0f4a737104816b4868827d71a7cd1fed1197f8cf
[vpp.git] / src / plugins / nat / test / test_nat44_ed.py
1 #!/usr/bin/env python3
2
3 import unittest
4 from io import BytesIO
5 from random import randint
6
7 import scapy.compat
8 from framework import VppTestCase, VppTestRunner
9 from scapy.data import IP_PROTOS
10 from scapy.layers.inet import IP, TCP, UDP, ICMP, GRE
11 from scapy.layers.inet import IPerror, TCPerror
12 from scapy.layers.l2 import Ether
13 from scapy.packet import Raw
14 from syslog_rfc5424_parser import SyslogMessage, ParseError
15 from syslog_rfc5424_parser.constants import SyslogSeverity
16 from util import ppp, ip4_range
17 from vpp_acl import AclRule, VppAcl, VppAclInterface
18 from vpp_ip_route import VppIpRoute, VppRoutePath
19 from vpp_papi import VppEnum
20
21
22 class NAT44EDTestCase(VppTestCase):
23
24     nat_addr = '10.0.0.3'
25
26     tcp_port_in = 6303
27     tcp_port_out = 6303
28
29     udp_port_in = 6304
30     udp_port_out = 6304
31
32     icmp_id_in = 6305
33     icmp_id_out = 6305
34
35     tcp_external_port = 80
36
37     max_sessions = 100
38
39     def setUp(self):
40         super(NAT44EDTestCase, self).setUp()
41         self.plugin_enable()
42
43     def tearDown(self):
44         super(NAT44EDTestCase, self).tearDown()
45         if not self.vpp_dead:
46             self.plugin_disable()
47
48     def plugin_enable(self):
49         self.vapi.nat44_plugin_enable_disable(
50             flags=self.nat44_config_flags.NAT44_IS_ENDPOINT_DEPENDENT,
51             sessions=self.max_sessions, enable=1)
52
53     def plugin_disable(self):
54         self.vapi.nat44_plugin_enable_disable(enable=0)
55
56     @property
57     def config_flags(self):
58         return VppEnum.vl_api_nat_config_flags_t
59
60     @property
61     def nat44_config_flags(self):
62         return VppEnum.vl_api_nat44_config_flags_t
63
64     @property
65     def syslog_severity(self):
66         return VppEnum.vl_api_syslog_severity_t
67
68     @property
69     def server_addr(self):
70         return self.pg1.remote_hosts[0].ip4
71
72     @staticmethod
73     def random_port():
74         return randint(1025, 65535)
75
76     @staticmethod
77     def proto2layer(proto):
78         if proto == IP_PROTOS.tcp:
79             return TCP
80         elif proto == IP_PROTOS.udp:
81             return UDP
82         elif proto == IP_PROTOS.icmp:
83             return ICMP
84         else:
85             raise Exception("Unsupported protocol")
86
87     @classmethod
88     def create_and_add_ip4_table(cls, i, table_id=0):
89         cls.vapi.ip_table_add_del(is_add=1, table={'table_id': table_id})
90         i.set_table_ip4(table_id)
91
92     @classmethod
93     def configure_ip4_interface(cls, i, hosts=0, table_id=None):
94         if table_id:
95             cls.create_and_add_ip4_table(i, table_id)
96
97         i.admin_up()
98         i.unconfig_ip4()
99         i.config_ip4()
100         i.resolve_arp()
101
102         if hosts:
103             i.generate_remote_hosts(hosts)
104             i.configure_ipv4_neighbors()
105
106     @classmethod
107     def nat_add_interface_address(cls, i):
108         cls.vapi.nat44_add_del_interface_addr(
109             sw_if_index=i.sw_if_index, is_add=1)
110
111     def nat_add_inside_interface(self, i):
112         self.vapi.nat44_interface_add_del_feature(
113             flags=self.config_flags.NAT_IS_INSIDE,
114             sw_if_index=i.sw_if_index, is_add=1)
115
116     def nat_add_outside_interface(self, i):
117         self.vapi.nat44_interface_add_del_feature(
118             flags=self.config_flags.NAT_IS_OUTSIDE,
119             sw_if_index=i.sw_if_index, is_add=1)
120
121     def nat_add_address(self, address, twice_nat=0,
122                         vrf_id=0xFFFFFFFF, is_add=1):
123         flags = self.config_flags.NAT_IS_TWICE_NAT if twice_nat else 0
124         self.vapi.nat44_add_del_address_range(first_ip_address=address,
125                                               last_ip_address=address,
126                                               vrf_id=vrf_id,
127                                               is_add=is_add,
128                                               flags=flags)
129
130     def nat_add_static_mapping(self, local_ip, external_ip='0.0.0.0',
131                                local_port=0, external_port=0, vrf_id=0,
132                                is_add=1, external_sw_if_index=0xFFFFFFFF,
133                                proto=0, tag="", flags=0):
134
135         if not (local_port and external_port):
136             flags |= self.config_flags.NAT_IS_ADDR_ONLY
137
138         self.vapi.nat44_add_del_static_mapping(
139             is_add=is_add,
140             local_ip_address=local_ip,
141             external_ip_address=external_ip,
142             external_sw_if_index=external_sw_if_index,
143             local_port=local_port,
144             external_port=external_port,
145             vrf_id=vrf_id, protocol=proto,
146             flags=flags,
147             tag=tag)
148
149     @classmethod
150     def setUpClass(cls):
151         super(NAT44EDTestCase, cls).setUpClass()
152         cls.vapi.cli("set log class nat level debug")
153
154         cls.create_pg_interfaces(range(12))
155         cls.interfaces = list(cls.pg_interfaces[:4])
156
157         cls.create_and_add_ip4_table(cls.pg2, 10)
158
159         for i in cls.interfaces:
160             cls.configure_ip4_interface(i, hosts=3)
161
162         # test specific (test-multiple-vrf)
163         cls.vapi.ip_table_add_del(is_add=1, table={'table_id': 1})
164
165         # test specific (test-one-armed-nat44-static)
166         cls.pg4.generate_remote_hosts(2)
167         cls.pg4.config_ip4()
168         cls.vapi.sw_interface_add_del_address(
169             sw_if_index=cls.pg4.sw_if_index,
170             prefix="10.0.0.1/24")
171         cls.pg4.admin_up()
172         cls.pg4.resolve_arp()
173         cls.pg4._remote_hosts[1]._ip4 = cls.pg4._remote_hosts[0]._ip4
174         cls.pg4.resolve_arp()
175
176         # test specific interface (pg5)
177         cls.pg5._local_ip4 = "10.1.1.1"
178         cls.pg5._remote_hosts[0]._ip4 = "10.1.1.2"
179         cls.pg5.set_table_ip4(1)
180         cls.pg5.config_ip4()
181         cls.pg5.admin_up()
182         cls.pg5.resolve_arp()
183
184         # test specific interface (pg6)
185         cls.pg6._local_ip4 = "10.1.2.1"
186         cls.pg6._remote_hosts[0]._ip4 = "10.1.2.2"
187         cls.pg6.set_table_ip4(1)
188         cls.pg6.config_ip4()
189         cls.pg6.admin_up()
190         cls.pg6.resolve_arp()
191
192         rl = list()
193
194         rl.append(VppIpRoute(cls, "0.0.0.0", 0,
195                              [VppRoutePath("0.0.0.0", 0xffffffff,
196                                            nh_table_id=0)],
197                              register=False, table_id=1))
198         rl.append(VppIpRoute(cls, "0.0.0.0", 0,
199                              [VppRoutePath(cls.pg1.local_ip4,
200                                            cls.pg1.sw_if_index)],
201                              register=False))
202         rl.append(VppIpRoute(cls, cls.pg5.remote_ip4, 32,
203                              [VppRoutePath("0.0.0.0",
204                                            cls.pg5.sw_if_index)],
205                              register=False, table_id=1))
206         rl.append(VppIpRoute(cls, cls.pg6.remote_ip4, 32,
207                              [VppRoutePath("0.0.0.0",
208                                            cls.pg6.sw_if_index)],
209                              register=False, table_id=1))
210         rl.append(VppIpRoute(cls, cls.pg6.remote_ip4, 16,
211                              [VppRoutePath("0.0.0.0", 0xffffffff,
212                                            nh_table_id=1)],
213                              register=False, table_id=0))
214
215         for r in rl:
216             r.add_vpp_config()
217
218     def get_err_counter(self, path):
219         return self.statistics.get_err_counter(path)
220
221     def get_stats_counter(self, path, worker=0):
222         return self.statistics.get_counter(path)[worker]
223
224     def reass_hairpinning(self, server_addr, server_in_port, server_out_port,
225                           host_in_port, proto=IP_PROTOS.tcp,
226                           ignore_port=False):
227         layer = self.proto2layer(proto)
228
229         if proto == IP_PROTOS.tcp:
230             data = b"A" * 4 + b"B" * 16 + b"C" * 3
231         else:
232             data = b"A" * 16 + b"B" * 16 + b"C" * 3
233
234         # send packet from host to server
235         pkts = self.create_stream_frag(self.pg0,
236                                        self.nat_addr,
237                                        host_in_port,
238                                        server_out_port,
239                                        data,
240                                        proto)
241         self.pg0.add_stream(pkts)
242         self.pg_enable_capture(self.pg_interfaces)
243         self.pg_start()
244         frags = self.pg0.get_capture(len(pkts))
245         p = self.reass_frags_and_verify(frags,
246                                         self.nat_addr,
247                                         server_addr)
248         if proto != IP_PROTOS.icmp:
249             if not ignore_port:
250                 self.assertNotEqual(p[layer].sport, host_in_port)
251             self.assertEqual(p[layer].dport, server_in_port)
252         else:
253             if not ignore_port:
254                 self.assertNotEqual(p[layer].id, host_in_port)
255         self.assertEqual(data, p[Raw].load)
256
257     def frag_out_of_order(self, proto=IP_PROTOS.tcp, dont_translate=False,
258                           ignore_port=False):
259         layer = self.proto2layer(proto)
260
261         if proto == IP_PROTOS.tcp:
262             data = b"A" * 4 + b"B" * 16 + b"C" * 3
263         else:
264             data = b"A" * 16 + b"B" * 16 + b"C" * 3
265         self.port_in = self.random_port()
266
267         for i in range(2):
268             # in2out
269             pkts = self.create_stream_frag(self.pg0, self.pg1.remote_ip4,
270                                            self.port_in, 20, data, proto)
271             pkts.reverse()
272             self.pg0.add_stream(pkts)
273             self.pg_enable_capture(self.pg_interfaces)
274             self.pg_start()
275             frags = self.pg1.get_capture(len(pkts))
276             if not dont_translate:
277                 p = self.reass_frags_and_verify(frags,
278                                                 self.nat_addr,
279                                                 self.pg1.remote_ip4)
280             else:
281                 p = self.reass_frags_and_verify(frags,
282                                                 self.pg0.remote_ip4,
283                                                 self.pg1.remote_ip4)
284             if proto != IP_PROTOS.icmp:
285                 if not dont_translate:
286                     self.assertEqual(p[layer].dport, 20)
287                     if not ignore_port:
288                         self.assertNotEqual(p[layer].sport, self.port_in)
289                 else:
290                     self.assertEqual(p[layer].sport, self.port_in)
291             else:
292                 if not ignore_port:
293                     if not dont_translate:
294                         self.assertNotEqual(p[layer].id, self.port_in)
295                     else:
296                         self.assertEqual(p[layer].id, self.port_in)
297             self.assertEqual(data, p[Raw].load)
298
299             # out2in
300             if not dont_translate:
301                 dst_addr = self.nat_addr
302             else:
303                 dst_addr = self.pg0.remote_ip4
304             if proto != IP_PROTOS.icmp:
305                 sport = 20
306                 dport = p[layer].sport
307             else:
308                 sport = p[layer].id
309                 dport = 0
310             pkts = self.create_stream_frag(self.pg1, dst_addr, sport, dport,
311                                            data, proto, echo_reply=True)
312             pkts.reverse()
313             self.pg1.add_stream(pkts)
314             self.pg_enable_capture(self.pg_interfaces)
315             self.pg_start()
316             frags = self.pg0.get_capture(len(pkts))
317             p = self.reass_frags_and_verify(frags,
318                                             self.pg1.remote_ip4,
319                                             self.pg0.remote_ip4)
320             if proto != IP_PROTOS.icmp:
321                 self.assertEqual(p[layer].sport, 20)
322                 self.assertEqual(p[layer].dport, self.port_in)
323             else:
324                 self.assertEqual(p[layer].id, self.port_in)
325             self.assertEqual(data, p[Raw].load)
326
327     def reass_frags_and_verify(self, frags, src, dst):
328         buffer = BytesIO()
329         for p in frags:
330             self.assertEqual(p[IP].src, src)
331             self.assertEqual(p[IP].dst, dst)
332             self.assert_ip_checksum_valid(p)
333             buffer.seek(p[IP].frag * 8)
334             buffer.write(bytes(p[IP].payload))
335         ip = IP(src=frags[0][IP].src, dst=frags[0][IP].dst,
336                 proto=frags[0][IP].proto)
337         if ip.proto == IP_PROTOS.tcp:
338             p = (ip / TCP(buffer.getvalue()))
339             self.logger.debug(ppp("Reassembled:", p))
340             self.assert_tcp_checksum_valid(p)
341         elif ip.proto == IP_PROTOS.udp:
342             p = (ip / UDP(buffer.getvalue()[:8]) /
343                  Raw(buffer.getvalue()[8:]))
344         elif ip.proto == IP_PROTOS.icmp:
345             p = (ip / ICMP(buffer.getvalue()))
346         return p
347
348     def frag_in_order(self, proto=IP_PROTOS.tcp, dont_translate=False,
349                       ignore_port=False):
350         layer = self.proto2layer(proto)
351
352         if proto == IP_PROTOS.tcp:
353             data = b"A" * 4 + b"B" * 16 + b"C" * 3
354         else:
355             data = b"A" * 16 + b"B" * 16 + b"C" * 3
356         self.port_in = self.random_port()
357
358         # in2out
359         pkts = self.create_stream_frag(self.pg0, self.pg1.remote_ip4,
360                                        self.port_in, 20, data, proto)
361         self.pg0.add_stream(pkts)
362         self.pg_enable_capture(self.pg_interfaces)
363         self.pg_start()
364         frags = self.pg1.get_capture(len(pkts))
365         if not dont_translate:
366             p = self.reass_frags_and_verify(frags,
367                                             self.nat_addr,
368                                             self.pg1.remote_ip4)
369         else:
370             p = self.reass_frags_and_verify(frags,
371                                             self.pg0.remote_ip4,
372                                             self.pg1.remote_ip4)
373         if proto != IP_PROTOS.icmp:
374             if not dont_translate:
375                 self.assertEqual(p[layer].dport, 20)
376                 if not ignore_port:
377                     self.assertNotEqual(p[layer].sport, self.port_in)
378             else:
379                 self.assertEqual(p[layer].sport, self.port_in)
380         else:
381             if not ignore_port:
382                 if not dont_translate:
383                     self.assertNotEqual(p[layer].id, self.port_in)
384                 else:
385                     self.assertEqual(p[layer].id, self.port_in)
386         self.assertEqual(data, p[Raw].load)
387
388         # out2in
389         if not dont_translate:
390             dst_addr = self.nat_addr
391         else:
392             dst_addr = self.pg0.remote_ip4
393         if proto != IP_PROTOS.icmp:
394             sport = 20
395             dport = p[layer].sport
396         else:
397             sport = p[layer].id
398             dport = 0
399         pkts = self.create_stream_frag(self.pg1, dst_addr, sport, dport, data,
400                                        proto, echo_reply=True)
401         self.pg1.add_stream(pkts)
402         self.pg_enable_capture(self.pg_interfaces)
403         self.pg_start()
404         frags = self.pg0.get_capture(len(pkts))
405         p = self.reass_frags_and_verify(frags,
406                                         self.pg1.remote_ip4,
407                                         self.pg0.remote_ip4)
408         if proto != IP_PROTOS.icmp:
409             self.assertEqual(p[layer].sport, 20)
410             self.assertEqual(p[layer].dport, self.port_in)
411         else:
412             self.assertEqual(p[layer].id, self.port_in)
413         self.assertEqual(data, p[Raw].load)
414
415     def verify_capture_out(self, capture, nat_ip=None, same_port=False,
416                            dst_ip=None, ignore_port=False):
417         if nat_ip is None:
418             nat_ip = self.nat_addr
419         for packet in capture:
420             try:
421                 self.assert_packet_checksums_valid(packet)
422                 self.assertEqual(packet[IP].src, nat_ip)
423                 if dst_ip is not None:
424                     self.assertEqual(packet[IP].dst, dst_ip)
425                 if packet.haslayer(TCP):
426                     if not ignore_port:
427                         if same_port:
428                             self.assertEqual(
429                                 packet[TCP].sport, self.tcp_port_in)
430                         else:
431                             self.assertNotEqual(
432                                 packet[TCP].sport, self.tcp_port_in)
433                     self.tcp_port_out = packet[TCP].sport
434                     self.assert_packet_checksums_valid(packet)
435                 elif packet.haslayer(UDP):
436                     if not ignore_port:
437                         if same_port:
438                             self.assertEqual(
439                                 packet[UDP].sport, self.udp_port_in)
440                         else:
441                             self.assertNotEqual(
442                                 packet[UDP].sport, self.udp_port_in)
443                     self.udp_port_out = packet[UDP].sport
444                 else:
445                     if not ignore_port:
446                         if same_port:
447                             self.assertEqual(
448                                 packet[ICMP].id, self.icmp_id_in)
449                         else:
450                             self.assertNotEqual(
451                                 packet[ICMP].id, self.icmp_id_in)
452                     self.icmp_id_out = packet[ICMP].id
453                     self.assert_packet_checksums_valid(packet)
454             except:
455                 self.logger.error(ppp("Unexpected or invalid packet "
456                                       "(outside network):", packet))
457                 raise
458
459     def verify_capture_in(self, capture, in_if):
460         for packet in capture:
461             try:
462                 self.assert_packet_checksums_valid(packet)
463                 self.assertEqual(packet[IP].dst, in_if.remote_ip4)
464                 if packet.haslayer(TCP):
465                     self.assertEqual(packet[TCP].dport, self.tcp_port_in)
466                 elif packet.haslayer(UDP):
467                     self.assertEqual(packet[UDP].dport, self.udp_port_in)
468                 else:
469                     self.assertEqual(packet[ICMP].id, self.icmp_id_in)
470             except:
471                 self.logger.error(ppp("Unexpected or invalid packet "
472                                       "(inside network):", packet))
473                 raise
474
475     def create_stream_in(self, in_if, out_if, dst_ip=None, ttl=64):
476         if dst_ip is None:
477             dst_ip = out_if.remote_ip4
478
479         pkts = []
480         # TCP
481         p = (Ether(dst=in_if.local_mac, src=in_if.remote_mac) /
482              IP(src=in_if.remote_ip4, dst=dst_ip, ttl=ttl) /
483              TCP(sport=self.tcp_port_in, dport=20))
484         pkts.extend([p, p])
485
486         # UDP
487         p = (Ether(dst=in_if.local_mac, src=in_if.remote_mac) /
488              IP(src=in_if.remote_ip4, dst=dst_ip, ttl=ttl) /
489              UDP(sport=self.udp_port_in, dport=20))
490         pkts.append(p)
491
492         # ICMP
493         p = (Ether(dst=in_if.local_mac, src=in_if.remote_mac) /
494              IP(src=in_if.remote_ip4, dst=dst_ip, ttl=ttl) /
495              ICMP(id=self.icmp_id_in, type='echo-request'))
496         pkts.append(p)
497
498         return pkts
499
500     def create_stream_out(self, out_if, dst_ip=None, ttl=64,
501                           use_inside_ports=False):
502         if dst_ip is None:
503             dst_ip = self.nat_addr
504         if not use_inside_ports:
505             tcp_port = self.tcp_port_out
506             udp_port = self.udp_port_out
507             icmp_id = self.icmp_id_out
508         else:
509             tcp_port = self.tcp_port_in
510             udp_port = self.udp_port_in
511             icmp_id = self.icmp_id_in
512         pkts = []
513         # TCP
514         p = (Ether(dst=out_if.local_mac, src=out_if.remote_mac) /
515              IP(src=out_if.remote_ip4, dst=dst_ip, ttl=ttl) /
516              TCP(dport=tcp_port, sport=20))
517         pkts.extend([p, p])
518
519         # UDP
520         p = (Ether(dst=out_if.local_mac, src=out_if.remote_mac) /
521              IP(src=out_if.remote_ip4, dst=dst_ip, ttl=ttl) /
522              UDP(dport=udp_port, sport=20))
523         pkts.append(p)
524
525         # ICMP
526         p = (Ether(dst=out_if.local_mac, src=out_if.remote_mac) /
527              IP(src=out_if.remote_ip4, dst=dst_ip, ttl=ttl) /
528              ICMP(id=icmp_id, type='echo-reply'))
529         pkts.append(p)
530
531         return pkts
532
533     def create_tcp_stream(self, in_if, out_if, count):
534         pkts = []
535         port = 6303
536
537         for i in range(count):
538             p = (Ether(dst=in_if.local_mac, src=in_if.remote_mac) /
539                  IP(src=in_if.remote_ip4, dst=out_if.remote_ip4, ttl=64) /
540                  TCP(sport=port + i, dport=20))
541             pkts.append(p)
542
543         return pkts
544
545     def create_stream_frag(self, src_if, dst, sport, dport, data,
546                            proto=IP_PROTOS.tcp, echo_reply=False):
547         if proto == IP_PROTOS.tcp:
548             p = (IP(src=src_if.remote_ip4, dst=dst) /
549                  TCP(sport=sport, dport=dport) /
550                  Raw(data))
551             p = p.__class__(scapy.compat.raw(p))
552             chksum = p[TCP].chksum
553             proto_header = TCP(sport=sport, dport=dport, chksum=chksum)
554         elif proto == IP_PROTOS.udp:
555             proto_header = UDP(sport=sport, dport=dport)
556         elif proto == IP_PROTOS.icmp:
557             if not echo_reply:
558                 proto_header = ICMP(id=sport, type='echo-request')
559             else:
560                 proto_header = ICMP(id=sport, type='echo-reply')
561         else:
562             raise Exception("Unsupported protocol")
563         id = self.random_port()
564         pkts = []
565         if proto == IP_PROTOS.tcp:
566             raw = Raw(data[0:4])
567         else:
568             raw = Raw(data[0:16])
569         p = (Ether(src=src_if.remote_mac, dst=src_if.local_mac) /
570              IP(src=src_if.remote_ip4, dst=dst, flags="MF", frag=0, id=id) /
571              proto_header /
572              raw)
573         pkts.append(p)
574         if proto == IP_PROTOS.tcp:
575             raw = Raw(data[4:20])
576         else:
577             raw = Raw(data[16:32])
578         p = (Ether(src=src_if.remote_mac, dst=src_if.local_mac) /
579              IP(src=src_if.remote_ip4, dst=dst, flags="MF", frag=3, id=id,
580                 proto=proto) /
581              raw)
582         pkts.append(p)
583         if proto == IP_PROTOS.tcp:
584             raw = Raw(data[20:])
585         else:
586             raw = Raw(data[32:])
587         p = (Ether(src=src_if.remote_mac, dst=src_if.local_mac) /
588              IP(src=src_if.remote_ip4, dst=dst, frag=5, proto=proto,
589                 id=id) /
590              raw)
591         pkts.append(p)
592         return pkts
593
594     def frag_in_order_in_plus_out(self, in_addr, out_addr, in_port, out_port,
595                                   proto=IP_PROTOS.tcp):
596
597         layer = self.proto2layer(proto)
598
599         if proto == IP_PROTOS.tcp:
600             data = b"A" * 4 + b"B" * 16 + b"C" * 3
601         else:
602             data = b"A" * 16 + b"B" * 16 + b"C" * 3
603         port_in = self.random_port()
604
605         for i in range(2):
606             # out2in
607             pkts = self.create_stream_frag(self.pg0, out_addr,
608                                            port_in, out_port,
609                                            data, proto)
610             self.pg0.add_stream(pkts)
611             self.pg_enable_capture(self.pg_interfaces)
612             self.pg_start()
613             frags = self.pg1.get_capture(len(pkts))
614             p = self.reass_frags_and_verify(frags,
615                                             self.pg0.remote_ip4,
616                                             in_addr)
617             if proto != IP_PROTOS.icmp:
618                 self.assertEqual(p[layer].sport, port_in)
619                 self.assertEqual(p[layer].dport, in_port)
620             else:
621                 self.assertEqual(p[layer].id, port_in)
622             self.assertEqual(data, p[Raw].load)
623
624             # in2out
625             if proto != IP_PROTOS.icmp:
626                 pkts = self.create_stream_frag(self.pg1, self.pg0.remote_ip4,
627                                                in_port,
628                                                p[layer].sport, data, proto)
629             else:
630                 pkts = self.create_stream_frag(self.pg1, self.pg0.remote_ip4,
631                                                p[layer].id, 0, data, proto,
632                                                echo_reply=True)
633             self.pg1.add_stream(pkts)
634             self.pg_enable_capture(self.pg_interfaces)
635             self.pg_start()
636             frags = self.pg0.get_capture(len(pkts))
637             p = self.reass_frags_and_verify(frags,
638                                             out_addr,
639                                             self.pg0.remote_ip4)
640             if proto != IP_PROTOS.icmp:
641                 self.assertEqual(p[layer].sport, out_port)
642                 self.assertEqual(p[layer].dport, port_in)
643             else:
644                 self.assertEqual(p[layer].id, port_in)
645             self.assertEqual(data, p[Raw].load)
646
647     def frag_out_of_order_in_plus_out(self, in_addr, out_addr, in_port,
648                                       out_port, proto=IP_PROTOS.tcp):
649
650         layer = self.proto2layer(proto)
651
652         if proto == IP_PROTOS.tcp:
653             data = b"A" * 4 + b"B" * 16 + b"C" * 3
654         else:
655             data = b"A" * 16 + b"B" * 16 + b"C" * 3
656         port_in = self.random_port()
657
658         for i in range(2):
659             # out2in
660             pkts = self.create_stream_frag(self.pg0, out_addr,
661                                            port_in, out_port,
662                                            data, proto)
663             pkts.reverse()
664             self.pg0.add_stream(pkts)
665             self.pg_enable_capture(self.pg_interfaces)
666             self.pg_start()
667             frags = self.pg1.get_capture(len(pkts))
668             p = self.reass_frags_and_verify(frags,
669                                             self.pg0.remote_ip4,
670                                             in_addr)
671             if proto != IP_PROTOS.icmp:
672                 self.assertEqual(p[layer].dport, in_port)
673                 self.assertEqual(p[layer].sport, port_in)
674                 self.assertEqual(p[layer].dport, in_port)
675             else:
676                 self.assertEqual(p[layer].id, port_in)
677             self.assertEqual(data, p[Raw].load)
678
679             # in2out
680             if proto != IP_PROTOS.icmp:
681                 pkts = self.create_stream_frag(self.pg1, self.pg0.remote_ip4,
682                                                in_port,
683                                                p[layer].sport, data, proto)
684             else:
685                 pkts = self.create_stream_frag(self.pg1, self.pg0.remote_ip4,
686                                                p[layer].id, 0, data, proto,
687                                                echo_reply=True)
688             pkts.reverse()
689             self.pg1.add_stream(pkts)
690             self.pg_enable_capture(self.pg_interfaces)
691             self.pg_start()
692             frags = self.pg0.get_capture(len(pkts))
693             p = self.reass_frags_and_verify(frags,
694                                             out_addr,
695                                             self.pg0.remote_ip4)
696             if proto != IP_PROTOS.icmp:
697                 self.assertEqual(p[layer].sport, out_port)
698                 self.assertEqual(p[layer].dport, port_in)
699             else:
700                 self.assertEqual(p[layer].id, port_in)
701             self.assertEqual(data, p[Raw].load)
702
703     def init_tcp_session(self, in_if, out_if, in_port, ext_port):
704         # SYN packet in->out
705         p = (Ether(src=in_if.remote_mac, dst=in_if.local_mac) /
706              IP(src=in_if.remote_ip4, dst=out_if.remote_ip4) /
707              TCP(sport=in_port, dport=ext_port, flags="S"))
708         in_if.add_stream(p)
709         self.pg_enable_capture(self.pg_interfaces)
710         self.pg_start()
711         capture = out_if.get_capture(1)
712         p = capture[0]
713         out_port = p[TCP].sport
714
715         # SYN + ACK packet out->in
716         p = (Ether(src=out_if.remote_mac, dst=out_if.local_mac) /
717              IP(src=out_if.remote_ip4, dst=self.nat_addr) /
718              TCP(sport=ext_port, dport=out_port, flags="SA"))
719         out_if.add_stream(p)
720         self.pg_enable_capture(self.pg_interfaces)
721         self.pg_start()
722         in_if.get_capture(1)
723
724         # ACK packet in->out
725         p = (Ether(src=in_if.remote_mac, dst=in_if.local_mac) /
726              IP(src=in_if.remote_ip4, dst=out_if.remote_ip4) /
727              TCP(sport=in_port, dport=ext_port, flags="A"))
728         in_if.add_stream(p)
729         self.pg_enable_capture(self.pg_interfaces)
730         self.pg_start()
731         out_if.get_capture(1)
732
733         return out_port
734
735     def twice_nat_common(self, self_twice_nat=False, same_pg=False, lb=False,
736                          client_id=None):
737         twice_nat_addr = '10.0.1.3'
738
739         port_in = 8080
740         if lb:
741             if not same_pg:
742                 port_in1 = port_in
743                 port_in2 = port_in
744             else:
745                 port_in1 = port_in + 1
746                 port_in2 = port_in + 2
747
748         port_out = 80
749         eh_port_out = 4567
750
751         server1 = self.pg0.remote_hosts[0]
752         server2 = self.pg0.remote_hosts[1]
753         if lb and same_pg:
754             server2 = server1
755         if not lb:
756             server = server1
757
758         pg0 = self.pg0
759         if same_pg:
760             pg1 = self.pg0
761         else:
762             pg1 = self.pg1
763
764         eh_translate = ((not self_twice_nat) or (not lb and same_pg) or
765                         client_id == 1)
766
767         self.nat_add_address(self.nat_addr)
768         self.nat_add_address(twice_nat_addr, twice_nat=1)
769
770         flags = 0
771         if self_twice_nat:
772             flags |= self.config_flags.NAT_IS_SELF_TWICE_NAT
773         else:
774             flags |= self.config_flags.NAT_IS_TWICE_NAT
775
776         if not lb:
777             self.nat_add_static_mapping(pg0.remote_ip4, self.nat_addr,
778                                         port_in, port_out,
779                                         proto=IP_PROTOS.tcp,
780                                         flags=flags)
781         else:
782             locals = [{'addr': server1.ip4,
783                        'port': port_in1,
784                        'probability': 50,
785                        'vrf_id': 0},
786                       {'addr': server2.ip4,
787                        'port': port_in2,
788                        'probability': 50,
789                        'vrf_id': 0}]
790             out_addr = self.nat_addr
791
792             self.vapi.nat44_add_del_lb_static_mapping(is_add=1, flags=flags,
793                                                       external_addr=out_addr,
794                                                       external_port=port_out,
795                                                       protocol=IP_PROTOS.tcp,
796                                                       local_num=len(locals),
797                                                       locals=locals)
798         self.nat_add_inside_interface(pg0)
799         self.nat_add_outside_interface(pg1)
800
801         if same_pg:
802             if not lb:
803                 client = server
804             else:
805                 assert client_id is not None
806                 if client_id == 1:
807                     client = self.pg0.remote_hosts[0]
808                 elif client_id == 2:
809                     client = self.pg0.remote_hosts[1]
810         else:
811             client = pg1.remote_hosts[0]
812         p = (Ether(src=pg1.remote_mac, dst=pg1.local_mac) /
813              IP(src=client.ip4, dst=self.nat_addr) /
814              TCP(sport=eh_port_out, dport=port_out))
815         pg1.add_stream(p)
816         self.pg_enable_capture(self.pg_interfaces)
817         self.pg_start()
818         capture = pg0.get_capture(1)
819         p = capture[0]
820         try:
821             ip = p[IP]
822             tcp = p[TCP]
823             if lb:
824                 if ip.dst == server1.ip4:
825                     server = server1
826                     port_in = port_in1
827                 else:
828                     server = server2
829                     port_in = port_in2
830             self.assertEqual(ip.dst, server.ip4)
831             if lb and same_pg:
832                 self.assertIn(tcp.dport, [port_in1, port_in2])
833             else:
834                 self.assertEqual(tcp.dport, port_in)
835             if eh_translate:
836                 self.assertEqual(ip.src, twice_nat_addr)
837                 self.assertNotEqual(tcp.sport, eh_port_out)
838             else:
839                 self.assertEqual(ip.src, client.ip4)
840                 self.assertEqual(tcp.sport, eh_port_out)
841             eh_addr_in = ip.src
842             eh_port_in = tcp.sport
843             saved_port_in = tcp.dport
844             self.assert_packet_checksums_valid(p)
845         except:
846             self.logger.error(ppp("Unexpected or invalid packet:", p))
847             raise
848
849         p = (Ether(src=server.mac, dst=pg0.local_mac) /
850              IP(src=server.ip4, dst=eh_addr_in) /
851              TCP(sport=saved_port_in, dport=eh_port_in))
852         pg0.add_stream(p)
853         self.pg_enable_capture(self.pg_interfaces)
854         self.pg_start()
855         capture = pg1.get_capture(1)
856         p = capture[0]
857         try:
858             ip = p[IP]
859             tcp = p[TCP]
860             self.assertEqual(ip.dst, client.ip4)
861             self.assertEqual(ip.src, self.nat_addr)
862             self.assertEqual(tcp.dport, eh_port_out)
863             self.assertEqual(tcp.sport, port_out)
864             self.assert_packet_checksums_valid(p)
865         except:
866             self.logger.error(ppp("Unexpected or invalid packet:", p))
867             raise
868
869         if eh_translate:
870             sessions = self.vapi.nat44_user_session_dump(server.ip4, 0)
871             self.assertEqual(len(sessions), 1)
872             self.assertTrue(sessions[0].flags &
873                             self.config_flags.NAT_IS_EXT_HOST_VALID)
874             self.assertTrue(sessions[0].flags &
875                             self.config_flags.NAT_IS_TWICE_NAT)
876             self.logger.info(self.vapi.cli("show nat44 sessions detail"))
877             self.vapi.nat44_del_session(
878                 address=sessions[0].inside_ip_address,
879                 port=sessions[0].inside_port,
880                 protocol=sessions[0].protocol,
881                 flags=(self.config_flags.NAT_IS_INSIDE |
882                        self.config_flags.NAT_IS_EXT_HOST_VALID),
883                 ext_host_address=sessions[0].ext_host_nat_address,
884                 ext_host_port=sessions[0].ext_host_nat_port)
885             sessions = self.vapi.nat44_user_session_dump(server.ip4, 0)
886             self.assertEqual(len(sessions), 0)
887
888     def verify_syslog_sess(self, data, is_add=True, is_ip6=False):
889         message = data.decode('utf-8')
890         try:
891             message = SyslogMessage.parse(message)
892         except ParseError as e:
893             self.logger.error(e)
894             raise
895         else:
896             self.assertEqual(message.severity, SyslogSeverity.info)
897             self.assertEqual(message.appname, 'NAT')
898             self.assertEqual(message.msgid, 'SADD' if is_add else 'SDEL')
899             sd_params = message.sd.get('nsess')
900             self.assertTrue(sd_params is not None)
901             if is_ip6:
902                 self.assertEqual(sd_params.get('IATYP'), 'IPv6')
903                 self.assertEqual(sd_params.get('ISADDR'), self.pg0.remote_ip6)
904             else:
905                 self.assertEqual(sd_params.get('IATYP'), 'IPv4')
906                 self.assertEqual(sd_params.get('ISADDR'), self.pg0.remote_ip4)
907                 self.assertTrue(sd_params.get('SSUBIX') is not None)
908             self.assertEqual(sd_params.get('ISPORT'), "%d" % self.tcp_port_in)
909             self.assertEqual(sd_params.get('XATYP'), 'IPv4')
910             self.assertEqual(sd_params.get('XSADDR'), self.nat_addr)
911             self.assertEqual(sd_params.get('XSPORT'), "%d" % self.tcp_port_out)
912             self.assertEqual(sd_params.get('PROTO'), "%d" % IP_PROTOS.tcp)
913             self.assertEqual(sd_params.get('SVLAN'), '0')
914             self.assertEqual(sd_params.get('XDADDR'), self.pg1.remote_ip4)
915             self.assertEqual(sd_params.get('XDPORT'),
916                              "%d" % self.tcp_external_port)
917
918
919 class TestNAT44ED(NAT44EDTestCase):
920     """ NAT44ED Test Case """
921
922     def test_users_dump(self):
923         """ NAT44ED API test - nat44_user_dump """
924
925         self.nat_add_address(self.nat_addr)
926         self.nat_add_inside_interface(self.pg0)
927         self.nat_add_outside_interface(self.pg1)
928
929         self.vapi.nat44_forwarding_enable_disable(enable=1)
930
931         local_ip = self.pg0.remote_ip4
932         external_ip = self.nat_addr
933         self.nat_add_static_mapping(local_ip, external_ip)
934
935         users = self.vapi.nat44_user_dump()
936         self.assertEqual(len(users), 0)
937
938         # in2out - static mapping match
939
940         pkts = self.create_stream_out(self.pg1)
941         self.pg1.add_stream(pkts)
942         self.pg_enable_capture(self.pg_interfaces)
943         self.pg_start()
944         capture = self.pg0.get_capture(len(pkts))
945         self.verify_capture_in(capture, self.pg0)
946
947         pkts = self.create_stream_in(self.pg0, self.pg1)
948         self.pg0.add_stream(pkts)
949         self.pg_enable_capture(self.pg_interfaces)
950         self.pg_start()
951         capture = self.pg1.get_capture(len(pkts))
952         self.verify_capture_out(capture, same_port=True)
953
954         users = self.vapi.nat44_user_dump()
955         self.assertEqual(len(users), 1)
956         static_user = users[0]
957         self.assertEqual(static_user.nstaticsessions, 3)
958         self.assertEqual(static_user.nsessions, 0)
959
960         # in2out - no static mapping match (forwarding test)
961
962         host0 = self.pg0.remote_hosts[0]
963         self.pg0.remote_hosts[0] = self.pg0.remote_hosts[1]
964         try:
965             pkts = self.create_stream_out(self.pg1,
966                                           dst_ip=self.pg0.remote_ip4,
967                                           use_inside_ports=True)
968             self.pg1.add_stream(pkts)
969             self.pg_enable_capture(self.pg_interfaces)
970             self.pg_start()
971             capture = self.pg0.get_capture(len(pkts))
972             self.verify_capture_in(capture, self.pg0)
973
974             pkts = self.create_stream_in(self.pg0, self.pg1)
975             self.pg0.add_stream(pkts)
976             self.pg_enable_capture(self.pg_interfaces)
977             self.pg_start()
978             capture = self.pg1.get_capture(len(pkts))
979             self.verify_capture_out(capture, nat_ip=self.pg0.remote_ip4,
980                                     same_port=True)
981         finally:
982             self.pg0.remote_hosts[0] = host0
983
984         users = self.vapi.nat44_user_dump()
985         self.assertEqual(len(users), 2)
986         if str(users[0].ip_address) == self.pg0.remote_hosts[0].ip4:
987             non_static_user = users[1]
988             static_user = users[0]
989         else:
990             non_static_user = users[0]
991             static_user = users[1]
992         self.assertEqual(static_user.nstaticsessions, 3)
993         self.assertEqual(static_user.nsessions, 0)
994         self.assertEqual(non_static_user.nstaticsessions, 0)
995         self.assertEqual(non_static_user.nsessions, 3)
996
997         users = self.vapi.nat44_user_dump()
998         self.assertEqual(len(users), 2)
999         if str(users[0].ip_address) == self.pg0.remote_hosts[0].ip4:
1000             non_static_user = users[1]
1001             static_user = users[0]
1002         else:
1003             non_static_user = users[0]
1004             static_user = users[1]
1005         self.assertEqual(static_user.nstaticsessions, 3)
1006         self.assertEqual(static_user.nsessions, 0)
1007         self.assertEqual(non_static_user.nstaticsessions, 0)
1008         self.assertEqual(non_static_user.nsessions, 3)
1009
1010     def test_frag_out_of_order_do_not_translate(self):
1011         """ NAT44ED don't translate fragments arriving out of order """
1012         self.nat_add_inside_interface(self.pg0)
1013         self.nat_add_outside_interface(self.pg1)
1014         self.vapi.nat44_forwarding_enable_disable(enable=True)
1015         self.frag_out_of_order(proto=IP_PROTOS.tcp, dont_translate=True)
1016
1017     def test_forwarding(self):
1018         """ NAT44ED forwarding test """
1019
1020         self.nat_add_inside_interface(self.pg0)
1021         self.nat_add_outside_interface(self.pg1)
1022         self.vapi.nat44_forwarding_enable_disable(enable=1)
1023
1024         real_ip = self.pg0.remote_ip4
1025         alias_ip = self.nat_addr
1026         flags = self.config_flags.NAT_IS_ADDR_ONLY
1027         self.vapi.nat44_add_del_static_mapping(is_add=1,
1028                                                local_ip_address=real_ip,
1029                                                external_ip_address=alias_ip,
1030                                                external_sw_if_index=0xFFFFFFFF,
1031                                                flags=flags)
1032
1033         try:
1034             # in2out - static mapping match
1035
1036             pkts = self.create_stream_out(self.pg1)
1037             self.pg1.add_stream(pkts)
1038             self.pg_enable_capture(self.pg_interfaces)
1039             self.pg_start()
1040             capture = self.pg0.get_capture(len(pkts))
1041             self.verify_capture_in(capture, self.pg0)
1042
1043             pkts = self.create_stream_in(self.pg0, self.pg1)
1044             self.pg0.add_stream(pkts)
1045             self.pg_enable_capture(self.pg_interfaces)
1046             self.pg_start()
1047             capture = self.pg1.get_capture(len(pkts))
1048             self.verify_capture_out(capture, same_port=True)
1049
1050             # in2out - no static mapping match
1051
1052             host0 = self.pg0.remote_hosts[0]
1053             self.pg0.remote_hosts[0] = self.pg0.remote_hosts[1]
1054             try:
1055                 pkts = self.create_stream_out(self.pg1,
1056                                               dst_ip=self.pg0.remote_ip4,
1057                                               use_inside_ports=True)
1058                 self.pg1.add_stream(pkts)
1059                 self.pg_enable_capture(self.pg_interfaces)
1060                 self.pg_start()
1061                 capture = self.pg0.get_capture(len(pkts))
1062                 self.verify_capture_in(capture, self.pg0)
1063
1064                 pkts = self.create_stream_in(self.pg0, self.pg1)
1065                 self.pg0.add_stream(pkts)
1066                 self.pg_enable_capture(self.pg_interfaces)
1067                 self.pg_start()
1068                 capture = self.pg1.get_capture(len(pkts))
1069                 self.verify_capture_out(capture, nat_ip=self.pg0.remote_ip4,
1070                                         same_port=True)
1071             finally:
1072                 self.pg0.remote_hosts[0] = host0
1073
1074             user = self.pg0.remote_hosts[1]
1075             sessions = self.vapi.nat44_user_session_dump(user.ip4, 0)
1076             self.assertEqual(len(sessions), 3)
1077             self.assertTrue(sessions[0].flags &
1078                             self.config_flags.NAT_IS_EXT_HOST_VALID)
1079             self.vapi.nat44_del_session(
1080                 address=sessions[0].inside_ip_address,
1081                 port=sessions[0].inside_port,
1082                 protocol=sessions[0].protocol,
1083                 flags=(self.config_flags.NAT_IS_INSIDE |
1084                        self.config_flags.NAT_IS_EXT_HOST_VALID),
1085                 ext_host_address=sessions[0].ext_host_address,
1086                 ext_host_port=sessions[0].ext_host_port)
1087             sessions = self.vapi.nat44_user_session_dump(user.ip4, 0)
1088             self.assertEqual(len(sessions), 2)
1089
1090         finally:
1091             self.vapi.nat44_forwarding_enable_disable(enable=0)
1092             flags = self.config_flags.NAT_IS_ADDR_ONLY
1093             self.vapi.nat44_add_del_static_mapping(
1094                 is_add=0,
1095                 local_ip_address=real_ip,
1096                 external_ip_address=alias_ip,
1097                 external_sw_if_index=0xFFFFFFFF,
1098                 flags=flags)
1099
1100     def test_output_feature_and_service2(self):
1101         """ NAT44ED interface output feature and service host direct access """
1102         self.vapi.nat44_forwarding_enable_disable(enable=1)
1103         self.nat_add_address(self.nat_addr)
1104
1105         self.vapi.nat44_interface_add_del_output_feature(
1106             sw_if_index=self.pg1.sw_if_index, is_add=1,)
1107
1108         # session initiated from service host - translate
1109         pkts = self.create_stream_in(self.pg0, self.pg1)
1110         self.pg0.add_stream(pkts)
1111         self.pg_enable_capture(self.pg_interfaces)
1112         self.pg_start()
1113         capture = self.pg1.get_capture(len(pkts))
1114         self.verify_capture_out(capture, ignore_port=True)
1115
1116         pkts = self.create_stream_out(self.pg1)
1117         self.pg1.add_stream(pkts)
1118         self.pg_enable_capture(self.pg_interfaces)
1119         self.pg_start()
1120         capture = self.pg0.get_capture(len(pkts))
1121         self.verify_capture_in(capture, self.pg0)
1122
1123         # session initiated from remote host - do not translate
1124         tcp_port_in = self.tcp_port_in
1125         udp_port_in = self.udp_port_in
1126         icmp_id_in = self.icmp_id_in
1127
1128         self.tcp_port_in = 60303
1129         self.udp_port_in = 60304
1130         self.icmp_id_in = 60305
1131
1132         try:
1133             pkts = self.create_stream_out(self.pg1,
1134                                           self.pg0.remote_ip4,
1135                                           use_inside_ports=True)
1136             self.pg1.add_stream(pkts)
1137             self.pg_enable_capture(self.pg_interfaces)
1138             self.pg_start()
1139             capture = self.pg0.get_capture(len(pkts))
1140             self.verify_capture_in(capture, self.pg0)
1141
1142             pkts = self.create_stream_in(self.pg0, self.pg1)
1143             self.pg0.add_stream(pkts)
1144             self.pg_enable_capture(self.pg_interfaces)
1145             self.pg_start()
1146             capture = self.pg1.get_capture(len(pkts))
1147             self.verify_capture_out(capture, nat_ip=self.pg0.remote_ip4,
1148                                     same_port=True)
1149         finally:
1150             self.tcp_port_in = tcp_port_in
1151             self.udp_port_in = udp_port_in
1152             self.icmp_id_in = icmp_id_in
1153
1154     def test_twice_nat(self):
1155         """ NAT44ED Twice NAT """
1156         self.twice_nat_common()
1157
1158     def test_self_twice_nat_positive(self):
1159         """ NAT44ED Self Twice NAT (positive test) """
1160         self.twice_nat_common(self_twice_nat=True, same_pg=True)
1161
1162     def test_self_twice_nat_lb_positive(self):
1163         """ NAT44ED Self Twice NAT local service load balancing (positive test)
1164         """
1165         self.twice_nat_common(lb=True, self_twice_nat=True, same_pg=True,
1166                               client_id=1)
1167
1168     def test_twice_nat_lb(self):
1169         """ NAT44ED Twice NAT local service load balancing """
1170         self.twice_nat_common(lb=True)
1171
1172     def test_output_feature(self):
1173         """ NAT44ED interface output feature (in2out postrouting) """
1174         self.vapi.nat44_forwarding_enable_disable(enable=1)
1175         self.nat_add_address(self.nat_addr)
1176
1177         self.nat_add_outside_interface(self.pg0)
1178         self.vapi.nat44_interface_add_del_output_feature(
1179             sw_if_index=self.pg1.sw_if_index, is_add=1)
1180
1181         # in2out
1182         pkts = self.create_stream_in(self.pg0, self.pg1)
1183         self.pg0.add_stream(pkts)
1184         self.pg_enable_capture(self.pg_interfaces)
1185         self.pg_start()
1186         capture = self.pg1.get_capture(len(pkts))
1187         self.verify_capture_out(capture, ignore_port=True)
1188
1189         # out2in
1190         pkts = self.create_stream_out(self.pg1)
1191         self.pg1.add_stream(pkts)
1192         self.pg_enable_capture(self.pg_interfaces)
1193         self.pg_start()
1194         capture = self.pg0.get_capture(len(pkts))
1195         self.verify_capture_in(capture, self.pg0)
1196
1197     def test_static_with_port_out2(self):
1198         """ NAT44ED 1:1 NAPT asymmetrical rule """
1199
1200         external_port = 80
1201         local_port = 8080
1202
1203         self.vapi.nat44_forwarding_enable_disable(enable=1)
1204         flags = self.config_flags.NAT_IS_OUT2IN_ONLY
1205         self.nat_add_static_mapping(self.pg0.remote_ip4, self.nat_addr,
1206                                     local_port, external_port,
1207                                     proto=IP_PROTOS.tcp, flags=flags)
1208
1209         self.nat_add_inside_interface(self.pg0)
1210         self.nat_add_outside_interface(self.pg1)
1211
1212         # from client to service
1213         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
1214              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
1215              TCP(sport=12345, dport=external_port))
1216         self.pg1.add_stream(p)
1217         self.pg_enable_capture(self.pg_interfaces)
1218         self.pg_start()
1219         capture = self.pg0.get_capture(1)
1220         p = capture[0]
1221         try:
1222             ip = p[IP]
1223             tcp = p[TCP]
1224             self.assertEqual(ip.dst, self.pg0.remote_ip4)
1225             self.assertEqual(tcp.dport, local_port)
1226             self.assert_packet_checksums_valid(p)
1227         except:
1228             self.logger.error(ppp("Unexpected or invalid packet:", p))
1229             raise
1230
1231         # ICMP error
1232         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
1233              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
1234              ICMP(type=11) / capture[0][IP])
1235         self.pg0.add_stream(p)
1236         self.pg_enable_capture(self.pg_interfaces)
1237         self.pg_start()
1238         capture = self.pg1.get_capture(1)
1239         p = capture[0]
1240         try:
1241             self.assertEqual(p[IP].src, self.nat_addr)
1242             inner = p[IPerror]
1243             self.assertEqual(inner.dst, self.nat_addr)
1244             self.assertEqual(inner[TCPerror].dport, external_port)
1245         except:
1246             self.logger.error(ppp("Unexpected or invalid packet:", p))
1247             raise
1248
1249         # from service back to client
1250         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
1251              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
1252              TCP(sport=local_port, dport=12345))
1253         self.pg0.add_stream(p)
1254         self.pg_enable_capture(self.pg_interfaces)
1255         self.pg_start()
1256         capture = self.pg1.get_capture(1)
1257         p = capture[0]
1258         try:
1259             ip = p[IP]
1260             tcp = p[TCP]
1261             self.assertEqual(ip.src, self.nat_addr)
1262             self.assertEqual(tcp.sport, external_port)
1263             self.assert_packet_checksums_valid(p)
1264         except:
1265             self.logger.error(ppp("Unexpected or invalid packet:", p))
1266             raise
1267
1268         # ICMP error
1269         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
1270              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
1271              ICMP(type=11) / capture[0][IP])
1272         self.pg1.add_stream(p)
1273         self.pg_enable_capture(self.pg_interfaces)
1274         self.pg_start()
1275         capture = self.pg0.get_capture(1)
1276         p = capture[0]
1277         try:
1278             self.assertEqual(p[IP].dst, self.pg0.remote_ip4)
1279             inner = p[IPerror]
1280             self.assertEqual(inner.src, self.pg0.remote_ip4)
1281             self.assertEqual(inner[TCPerror].sport, local_port)
1282         except:
1283             self.logger.error(ppp("Unexpected or invalid packet:", p))
1284             raise
1285
1286         # from client to server (no translation)
1287         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
1288              IP(src=self.pg1.remote_ip4, dst=self.pg0.remote_ip4) /
1289              TCP(sport=12346, dport=local_port))
1290         self.pg1.add_stream(p)
1291         self.pg_enable_capture(self.pg_interfaces)
1292         self.pg_start()
1293         capture = self.pg0.get_capture(1)
1294         p = capture[0]
1295         try:
1296             ip = p[IP]
1297             tcp = p[TCP]
1298             self.assertEqual(ip.dst, self.pg0.remote_ip4)
1299             self.assertEqual(tcp.dport, local_port)
1300             self.assert_packet_checksums_valid(p)
1301         except:
1302             self.logger.error(ppp("Unexpected or invalid packet:", p))
1303             raise
1304
1305         # from service back to client (no translation)
1306         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
1307              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
1308              TCP(sport=local_port, dport=12346))
1309         self.pg0.add_stream(p)
1310         self.pg_enable_capture(self.pg_interfaces)
1311         self.pg_start()
1312         capture = self.pg1.get_capture(1)
1313         p = capture[0]
1314         try:
1315             ip = p[IP]
1316             tcp = p[TCP]
1317             self.assertEqual(ip.src, self.pg0.remote_ip4)
1318             self.assertEqual(tcp.sport, local_port)
1319             self.assert_packet_checksums_valid(p)
1320         except:
1321             self.logger.error(ppp("Unexpected or invalid packet:", p))
1322             raise
1323
1324     def test_static_lb(self):
1325         """ NAT44ED local service load balancing """
1326         external_addr_n = self.nat_addr
1327         external_port = 80
1328         local_port = 8080
1329         server1 = self.pg0.remote_hosts[0]
1330         server2 = self.pg0.remote_hosts[1]
1331
1332         locals = [{'addr': server1.ip4,
1333                    'port': local_port,
1334                    'probability': 70,
1335                    'vrf_id': 0},
1336                   {'addr': server2.ip4,
1337                    'port': local_port,
1338                    'probability': 30,
1339                    'vrf_id': 0}]
1340
1341         self.nat_add_address(self.nat_addr)
1342         self.vapi.nat44_add_del_lb_static_mapping(
1343             is_add=1,
1344             external_addr=external_addr_n,
1345             external_port=external_port,
1346             protocol=IP_PROTOS.tcp,
1347             local_num=len(locals),
1348             locals=locals)
1349         flags = self.config_flags.NAT_IS_INSIDE
1350         self.vapi.nat44_interface_add_del_feature(
1351             sw_if_index=self.pg0.sw_if_index,
1352             flags=flags, is_add=1)
1353         self.vapi.nat44_interface_add_del_feature(
1354             sw_if_index=self.pg1.sw_if_index,
1355             is_add=1)
1356
1357         # from client to service
1358         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
1359              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
1360              TCP(sport=12345, dport=external_port))
1361         self.pg1.add_stream(p)
1362         self.pg_enable_capture(self.pg_interfaces)
1363         self.pg_start()
1364         capture = self.pg0.get_capture(1)
1365         p = capture[0]
1366         server = None
1367         try:
1368             ip = p[IP]
1369             tcp = p[TCP]
1370             self.assertIn(ip.dst, [server1.ip4, server2.ip4])
1371             if ip.dst == server1.ip4:
1372                 server = server1
1373             else:
1374                 server = server2
1375             self.assertEqual(tcp.dport, local_port)
1376             self.assert_packet_checksums_valid(p)
1377         except:
1378             self.logger.error(ppp("Unexpected or invalid packet:", p))
1379             raise
1380
1381         # from service back to client
1382         p = (Ether(src=server.mac, dst=self.pg0.local_mac) /
1383              IP(src=server.ip4, dst=self.pg1.remote_ip4) /
1384              TCP(sport=local_port, dport=12345))
1385         self.pg0.add_stream(p)
1386         self.pg_enable_capture(self.pg_interfaces)
1387         self.pg_start()
1388         capture = self.pg1.get_capture(1)
1389         p = capture[0]
1390         try:
1391             ip = p[IP]
1392             tcp = p[TCP]
1393             self.assertEqual(ip.src, self.nat_addr)
1394             self.assertEqual(tcp.sport, external_port)
1395             self.assert_packet_checksums_valid(p)
1396         except:
1397             self.logger.error(ppp("Unexpected or invalid packet:", p))
1398             raise
1399
1400         sessions = self.vapi.nat44_user_session_dump(server.ip4, 0)
1401         self.assertEqual(len(sessions), 1)
1402         self.assertTrue(sessions[0].flags &
1403                         self.config_flags.NAT_IS_EXT_HOST_VALID)
1404         self.vapi.nat44_del_session(
1405             address=sessions[0].inside_ip_address,
1406             port=sessions[0].inside_port,
1407             protocol=sessions[0].protocol,
1408             flags=(self.config_flags.NAT_IS_INSIDE |
1409                    self.config_flags.NAT_IS_EXT_HOST_VALID),
1410             ext_host_address=sessions[0].ext_host_address,
1411             ext_host_port=sessions[0].ext_host_port)
1412         sessions = self.vapi.nat44_user_session_dump(server.ip4, 0)
1413         self.assertEqual(len(sessions), 0)
1414
1415     def test_static_lb_2(self):
1416         """ NAT44ED local service load balancing (asymmetrical rule) """
1417         external_addr = self.nat_addr
1418         external_port = 80
1419         local_port = 8080
1420         server1 = self.pg0.remote_hosts[0]
1421         server2 = self.pg0.remote_hosts[1]
1422
1423         locals = [{'addr': server1.ip4,
1424                    'port': local_port,
1425                    'probability': 70,
1426                    'vrf_id': 0},
1427                   {'addr': server2.ip4,
1428                    'port': local_port,
1429                    'probability': 30,
1430                    'vrf_id': 0}]
1431
1432         self.vapi.nat44_forwarding_enable_disable(enable=1)
1433         flags = self.config_flags.NAT_IS_OUT2IN_ONLY
1434         self.vapi.nat44_add_del_lb_static_mapping(is_add=1, flags=flags,
1435                                                   external_addr=external_addr,
1436                                                   external_port=external_port,
1437                                                   protocol=IP_PROTOS.tcp,
1438                                                   local_num=len(locals),
1439                                                   locals=locals)
1440         flags = self.config_flags.NAT_IS_INSIDE
1441         self.vapi.nat44_interface_add_del_feature(
1442             sw_if_index=self.pg0.sw_if_index,
1443             flags=flags, is_add=1)
1444         self.vapi.nat44_interface_add_del_feature(
1445             sw_if_index=self.pg1.sw_if_index,
1446             is_add=1)
1447
1448         # from client to service
1449         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
1450              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
1451              TCP(sport=12345, dport=external_port))
1452         self.pg1.add_stream(p)
1453         self.pg_enable_capture(self.pg_interfaces)
1454         self.pg_start()
1455         capture = self.pg0.get_capture(1)
1456         p = capture[0]
1457         server = None
1458         try:
1459             ip = p[IP]
1460             tcp = p[TCP]
1461             self.assertIn(ip.dst, [server1.ip4, server2.ip4])
1462             if ip.dst == server1.ip4:
1463                 server = server1
1464             else:
1465                 server = server2
1466             self.assertEqual(tcp.dport, local_port)
1467             self.assert_packet_checksums_valid(p)
1468         except:
1469             self.logger.error(ppp("Unexpected or invalid packet:", p))
1470             raise
1471
1472         # from service back to client
1473         p = (Ether(src=server.mac, dst=self.pg0.local_mac) /
1474              IP(src=server.ip4, dst=self.pg1.remote_ip4) /
1475              TCP(sport=local_port, dport=12345))
1476         self.pg0.add_stream(p)
1477         self.pg_enable_capture(self.pg_interfaces)
1478         self.pg_start()
1479         capture = self.pg1.get_capture(1)
1480         p = capture[0]
1481         try:
1482             ip = p[IP]
1483             tcp = p[TCP]
1484             self.assertEqual(ip.src, self.nat_addr)
1485             self.assertEqual(tcp.sport, external_port)
1486             self.assert_packet_checksums_valid(p)
1487         except:
1488             self.logger.error(ppp("Unexpected or invalid packet:", p))
1489             raise
1490
1491         # from client to server (no translation)
1492         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
1493              IP(src=self.pg1.remote_ip4, dst=server1.ip4) /
1494              TCP(sport=12346, dport=local_port))
1495         self.pg1.add_stream(p)
1496         self.pg_enable_capture(self.pg_interfaces)
1497         self.pg_start()
1498         capture = self.pg0.get_capture(1)
1499         p = capture[0]
1500         server = None
1501         try:
1502             ip = p[IP]
1503             tcp = p[TCP]
1504             self.assertEqual(ip.dst, server1.ip4)
1505             self.assertEqual(tcp.dport, local_port)
1506             self.assert_packet_checksums_valid(p)
1507         except:
1508             self.logger.error(ppp("Unexpected or invalid packet:", p))
1509             raise
1510
1511         # from service back to client (no translation)
1512         p = (Ether(src=server1.mac, dst=self.pg0.local_mac) /
1513              IP(src=server1.ip4, dst=self.pg1.remote_ip4) /
1514              TCP(sport=local_port, dport=12346))
1515         self.pg0.add_stream(p)
1516         self.pg_enable_capture(self.pg_interfaces)
1517         self.pg_start()
1518         capture = self.pg1.get_capture(1)
1519         p = capture[0]
1520         try:
1521             ip = p[IP]
1522             tcp = p[TCP]
1523             self.assertEqual(ip.src, server1.ip4)
1524             self.assertEqual(tcp.sport, local_port)
1525             self.assert_packet_checksums_valid(p)
1526         except:
1527             self.logger.error(ppp("Unexpected or invalid packet:", p))
1528             raise
1529
1530     def test_lb_affinity(self):
1531         """ NAT44ED local service load balancing affinity """
1532         external_addr = self.nat_addr
1533         external_port = 80
1534         local_port = 8080
1535         server1 = self.pg0.remote_hosts[0]
1536         server2 = self.pg0.remote_hosts[1]
1537
1538         locals = [{'addr': server1.ip4,
1539                    'port': local_port,
1540                    'probability': 50,
1541                    'vrf_id': 0},
1542                   {'addr': server2.ip4,
1543                    'port': local_port,
1544                    'probability': 50,
1545                    'vrf_id': 0}]
1546
1547         self.nat_add_address(self.nat_addr)
1548         self.vapi.nat44_add_del_lb_static_mapping(is_add=1,
1549                                                   external_addr=external_addr,
1550                                                   external_port=external_port,
1551                                                   protocol=IP_PROTOS.tcp,
1552                                                   affinity=10800,
1553                                                   local_num=len(locals),
1554                                                   locals=locals)
1555         flags = self.config_flags.NAT_IS_INSIDE
1556         self.vapi.nat44_interface_add_del_feature(
1557             sw_if_index=self.pg0.sw_if_index,
1558             flags=flags, is_add=1)
1559         self.vapi.nat44_interface_add_del_feature(
1560             sw_if_index=self.pg1.sw_if_index,
1561             is_add=1)
1562
1563         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
1564              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
1565              TCP(sport=1025, dport=external_port))
1566         self.pg1.add_stream(p)
1567         self.pg_enable_capture(self.pg_interfaces)
1568         self.pg_start()
1569         capture = self.pg0.get_capture(1)
1570         backend = capture[0][IP].dst
1571
1572         sessions = self.vapi.nat44_user_session_dump(backend, 0)
1573         self.assertEqual(len(sessions), 1)
1574         self.assertTrue(sessions[0].flags &
1575                         self.config_flags.NAT_IS_EXT_HOST_VALID)
1576         self.vapi.nat44_del_session(
1577             address=sessions[0].inside_ip_address,
1578             port=sessions[0].inside_port,
1579             protocol=sessions[0].protocol,
1580             flags=(self.config_flags.NAT_IS_INSIDE |
1581                    self.config_flags.NAT_IS_EXT_HOST_VALID),
1582             ext_host_address=sessions[0].ext_host_address,
1583             ext_host_port=sessions[0].ext_host_port)
1584
1585         pkts = []
1586         for port in range(1030, 1100):
1587             p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
1588                  IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
1589                  TCP(sport=port, dport=external_port))
1590             pkts.append(p)
1591         self.pg1.add_stream(pkts)
1592         self.pg_enable_capture(self.pg_interfaces)
1593         self.pg_start()
1594         capture = self.pg0.get_capture(len(pkts))
1595         for p in capture:
1596             self.assertEqual(p[IP].dst, backend)
1597
1598     def test_multiple_vrf(self):
1599         """ NAT44ED Multiple VRF setup """
1600
1601         external_addr = '1.2.3.4'
1602         external_port = 80
1603         local_port = 8080
1604         port = 0
1605
1606         self.vapi.nat44_forwarding_enable_disable(enable=1)
1607         self.nat_add_address(self.nat_addr)
1608         flags = self.config_flags.NAT_IS_INSIDE
1609         self.vapi.nat44_interface_add_del_feature(
1610             sw_if_index=self.pg0.sw_if_index,
1611             is_add=1)
1612         self.vapi.nat44_interface_add_del_feature(
1613             sw_if_index=self.pg0.sw_if_index,
1614             is_add=1, flags=flags)
1615         self.vapi.nat44_interface_add_del_output_feature(
1616             sw_if_index=self.pg1.sw_if_index,
1617             is_add=1)
1618         self.vapi.nat44_interface_add_del_feature(
1619             sw_if_index=self.pg5.sw_if_index,
1620             is_add=1)
1621         self.vapi.nat44_interface_add_del_feature(
1622             sw_if_index=self.pg5.sw_if_index,
1623             is_add=1, flags=flags)
1624         self.vapi.nat44_interface_add_del_feature(
1625             sw_if_index=self.pg6.sw_if_index,
1626             is_add=1)
1627         flags = self.config_flags.NAT_IS_OUT2IN_ONLY
1628         self.nat_add_static_mapping(self.pg5.remote_ip4, external_addr,
1629                                     local_port, external_port, vrf_id=1,
1630                                     proto=IP_PROTOS.tcp, flags=flags)
1631         self.nat_add_static_mapping(
1632             self.pg0.remote_ip4,
1633             external_sw_if_index=self.pg0.sw_if_index,
1634             local_port=local_port,
1635             vrf_id=0,
1636             external_port=external_port,
1637             proto=IP_PROTOS.tcp,
1638             flags=flags
1639         )
1640
1641         # from client to service (both VRF1)
1642         p = (Ether(src=self.pg6.remote_mac, dst=self.pg6.local_mac) /
1643              IP(src=self.pg6.remote_ip4, dst=external_addr) /
1644              TCP(sport=12345, dport=external_port))
1645         self.pg6.add_stream(p)
1646         self.pg_enable_capture(self.pg_interfaces)
1647         self.pg_start()
1648         capture = self.pg5.get_capture(1)
1649         p = capture[0]
1650         try:
1651             ip = p[IP]
1652             tcp = p[TCP]
1653             self.assertEqual(ip.dst, self.pg5.remote_ip4)
1654             self.assertEqual(tcp.dport, local_port)
1655             self.assert_packet_checksums_valid(p)
1656         except:
1657             self.logger.error(ppp("Unexpected or invalid packet:", p))
1658             raise
1659
1660         # from service back to client (both VRF1)
1661         p = (Ether(src=self.pg5.remote_mac, dst=self.pg5.local_mac) /
1662              IP(src=self.pg5.remote_ip4, dst=self.pg6.remote_ip4) /
1663              TCP(sport=local_port, dport=12345))
1664         self.pg5.add_stream(p)
1665         self.pg_enable_capture(self.pg_interfaces)
1666         self.pg_start()
1667         capture = self.pg6.get_capture(1)
1668         p = capture[0]
1669         try:
1670             ip = p[IP]
1671             tcp = p[TCP]
1672             self.assertEqual(ip.src, external_addr)
1673             self.assertEqual(tcp.sport, external_port)
1674             self.assert_packet_checksums_valid(p)
1675         except:
1676             self.logger.error(ppp("Unexpected or invalid packet:", p))
1677             raise
1678
1679         # dynamic NAT from VRF1 to VRF0 (output-feature)
1680         p = (Ether(src=self.pg5.remote_mac, dst=self.pg5.local_mac) /
1681              IP(src=self.pg5.remote_ip4, dst=self.pg1.remote_ip4) /
1682              TCP(sport=2345, dport=22))
1683         self.pg5.add_stream(p)
1684         self.pg_enable_capture(self.pg_interfaces)
1685         self.pg_start()
1686         capture = self.pg1.get_capture(1)
1687         p = capture[0]
1688         try:
1689             ip = p[IP]
1690             tcp = p[TCP]
1691             self.assertEqual(ip.src, self.nat_addr)
1692             self.assert_packet_checksums_valid(p)
1693             port = tcp.sport
1694         except:
1695             self.logger.error(ppp("Unexpected or invalid packet:", p))
1696             raise
1697
1698         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
1699              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
1700              TCP(sport=22, dport=port))
1701         self.pg1.add_stream(p)
1702         self.pg_enable_capture(self.pg_interfaces)
1703         self.pg_start()
1704         capture = self.pg5.get_capture(1)
1705         p = capture[0]
1706         try:
1707             ip = p[IP]
1708             tcp = p[TCP]
1709             self.assertEqual(ip.dst, self.pg5.remote_ip4)
1710             self.assertEqual(tcp.dport, 2345)
1711             self.assert_packet_checksums_valid(p)
1712         except:
1713             self.logger.error(ppp("Unexpected or invalid packet:", p))
1714             raise
1715
1716         # from client VRF1 to service VRF0
1717         p = (Ether(src=self.pg6.remote_mac, dst=self.pg6.local_mac) /
1718              IP(src=self.pg6.remote_ip4, dst=self.pg0.local_ip4) /
1719              TCP(sport=12346, dport=external_port))
1720         self.pg6.add_stream(p)
1721         self.pg_enable_capture(self.pg_interfaces)
1722         self.pg_start()
1723         capture = self.pg0.get_capture(1)
1724         p = capture[0]
1725         try:
1726             ip = p[IP]
1727             tcp = p[TCP]
1728             self.assertEqual(ip.dst, self.pg0.remote_ip4)
1729             self.assertEqual(tcp.dport, local_port)
1730             self.assert_packet_checksums_valid(p)
1731         except:
1732             self.logger.error(ppp("Unexpected or invalid packet:", p))
1733             raise
1734
1735         # from service VRF0 back to client VRF1
1736         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
1737              IP(src=self.pg0.remote_ip4, dst=self.pg6.remote_ip4) /
1738              TCP(sport=local_port, dport=12346))
1739         self.pg0.add_stream(p)
1740         self.pg_enable_capture(self.pg_interfaces)
1741         self.pg_start()
1742         capture = self.pg6.get_capture(1)
1743         p = capture[0]
1744         try:
1745             ip = p[IP]
1746             tcp = p[TCP]
1747             self.assertEqual(ip.src, self.pg0.local_ip4)
1748             self.assertEqual(tcp.sport, external_port)
1749             self.assert_packet_checksums_valid(p)
1750         except:
1751             self.logger.error(ppp("Unexpected or invalid packet:", p))
1752             raise
1753
1754         # from client VRF0 to service VRF1
1755         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
1756              IP(src=self.pg0.remote_ip4, dst=external_addr) /
1757              TCP(sport=12347, dport=external_port))
1758         self.pg0.add_stream(p)
1759         self.pg_enable_capture(self.pg_interfaces)
1760         self.pg_start()
1761         capture = self.pg5.get_capture(1)
1762         p = capture[0]
1763         try:
1764             ip = p[IP]
1765             tcp = p[TCP]
1766             self.assertEqual(ip.dst, self.pg5.remote_ip4)
1767             self.assertEqual(tcp.dport, local_port)
1768             self.assert_packet_checksums_valid(p)
1769         except:
1770             self.logger.error(ppp("Unexpected or invalid packet:", p))
1771             raise
1772
1773         # from service VRF1 back to client VRF0
1774         p = (Ether(src=self.pg5.remote_mac, dst=self.pg5.local_mac) /
1775              IP(src=self.pg5.remote_ip4, dst=self.pg0.remote_ip4) /
1776              TCP(sport=local_port, dport=12347))
1777         self.pg5.add_stream(p)
1778         self.pg_enable_capture(self.pg_interfaces)
1779         self.pg_start()
1780         capture = self.pg0.get_capture(1)
1781         p = capture[0]
1782         try:
1783             ip = p[IP]
1784             tcp = p[TCP]
1785             self.assertEqual(ip.src, external_addr)
1786             self.assertEqual(tcp.sport, external_port)
1787             self.assert_packet_checksums_valid(p)
1788         except:
1789             self.logger.error(ppp("Unexpected or invalid packet:", p))
1790             raise
1791
1792         # from client to server (both VRF1, no translation)
1793         p = (Ether(src=self.pg6.remote_mac, dst=self.pg6.local_mac) /
1794              IP(src=self.pg6.remote_ip4, dst=self.pg5.remote_ip4) /
1795              TCP(sport=12348, dport=local_port))
1796         self.pg6.add_stream(p)
1797         self.pg_enable_capture(self.pg_interfaces)
1798         self.pg_start()
1799         capture = self.pg5.get_capture(1)
1800         p = capture[0]
1801         try:
1802             ip = p[IP]
1803             tcp = p[TCP]
1804             self.assertEqual(ip.dst, self.pg5.remote_ip4)
1805             self.assertEqual(tcp.dport, local_port)
1806             self.assert_packet_checksums_valid(p)
1807         except:
1808             self.logger.error(ppp("Unexpected or invalid packet:", p))
1809             raise
1810
1811         # from server back to client (both VRF1, no translation)
1812         p = (Ether(src=self.pg5.remote_mac, dst=self.pg5.local_mac) /
1813              IP(src=self.pg5.remote_ip4, dst=self.pg6.remote_ip4) /
1814              TCP(sport=local_port, dport=12348))
1815         self.pg5.add_stream(p)
1816         self.pg_enable_capture(self.pg_interfaces)
1817         self.pg_start()
1818         capture = self.pg6.get_capture(1)
1819         p = capture[0]
1820         try:
1821             ip = p[IP]
1822             tcp = p[TCP]
1823             self.assertEqual(ip.src, self.pg5.remote_ip4)
1824             self.assertEqual(tcp.sport, local_port)
1825             self.assert_packet_checksums_valid(p)
1826         except:
1827             self.logger.error(ppp("Unexpected or invalid packet:", p))
1828             raise
1829
1830         # from client VRF1 to server VRF0 (no translation)
1831         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
1832              IP(src=self.pg0.remote_ip4, dst=self.pg6.remote_ip4) /
1833              TCP(sport=local_port, dport=12349))
1834         self.pg0.add_stream(p)
1835         self.pg_enable_capture(self.pg_interfaces)
1836         self.pg_start()
1837         capture = self.pg6.get_capture(1)
1838         p = capture[0]
1839         try:
1840             ip = p[IP]
1841             tcp = p[TCP]
1842             self.assertEqual(ip.src, self.pg0.remote_ip4)
1843             self.assertEqual(tcp.sport, local_port)
1844             self.assert_packet_checksums_valid(p)
1845         except:
1846             self.logger.error(ppp("Unexpected or invalid packet:", p))
1847             raise
1848
1849         # from server VRF0 back to client VRF1 (no translation)
1850         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
1851              IP(src=self.pg0.remote_ip4, dst=self.pg6.remote_ip4) /
1852              TCP(sport=local_port, dport=12349))
1853         self.pg0.add_stream(p)
1854         self.pg_enable_capture(self.pg_interfaces)
1855         self.pg_start()
1856         capture = self.pg6.get_capture(1)
1857         p = capture[0]
1858         try:
1859             ip = p[IP]
1860             tcp = p[TCP]
1861             self.assertEqual(ip.src, self.pg0.remote_ip4)
1862             self.assertEqual(tcp.sport, local_port)
1863             self.assert_packet_checksums_valid(p)
1864         except:
1865             self.logger.error(ppp("Unexpected or invalid packet:", p))
1866             raise
1867
1868         # from client VRF0 to server VRF1 (no translation)
1869         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
1870              IP(src=self.pg0.remote_ip4, dst=self.pg5.remote_ip4) /
1871              TCP(sport=12344, dport=local_port))
1872         self.pg0.add_stream(p)
1873         self.pg_enable_capture(self.pg_interfaces)
1874         self.pg_start()
1875         capture = self.pg5.get_capture(1)
1876         p = capture[0]
1877         try:
1878             ip = p[IP]
1879             tcp = p[TCP]
1880             self.assertEqual(ip.dst, self.pg5.remote_ip4)
1881             self.assertEqual(tcp.dport, local_port)
1882             self.assert_packet_checksums_valid(p)
1883         except:
1884             self.logger.error(ppp("Unexpected or invalid packet:", p))
1885             raise
1886
1887         # from server VRF1 back to client VRF0 (no translation)
1888         p = (Ether(src=self.pg5.remote_mac, dst=self.pg5.local_mac) /
1889              IP(src=self.pg5.remote_ip4, dst=self.pg0.remote_ip4) /
1890              TCP(sport=local_port, dport=12344))
1891         self.pg5.add_stream(p)
1892         self.pg_enable_capture(self.pg_interfaces)
1893         self.pg_start()
1894         capture = self.pg0.get_capture(1)
1895         p = capture[0]
1896         try:
1897             ip = p[IP]
1898             tcp = p[TCP]
1899             self.assertEqual(ip.src, self.pg5.remote_ip4)
1900             self.assertEqual(tcp.sport, local_port)
1901             self.assert_packet_checksums_valid(p)
1902         except:
1903             self.logger.error(ppp("Unexpected or invalid packet:", p))
1904             raise
1905
1906
1907 class TestNAT44EDMW(TestNAT44ED):
1908     """ NAT44ED MW Test Case """
1909     worker_config = "workers 1"
1910
1911     def get_stats_counter(self, path, worker=1):
1912         return super(TestNAT44EDMW, self).get_stats_counter(path, worker)
1913
1914     @unittest.skip('MW fix required')
1915     def test_users_dump(self):
1916         """ NAT44ED API test - nat44_user_dump """
1917
1918     @unittest.skip('MW fix required')
1919     def test_frag_out_of_order_do_not_translate(self):
1920         """ NAT44ED don't translate fragments arriving out of order """
1921
1922     @unittest.skip('MW fix required')
1923     def test_forwarding(self):
1924         """ NAT44ED forwarding test """
1925
1926     @unittest.skip('MW fix required')
1927     def test_twice_nat(self):
1928         """ NAT44ED Twice NAT """
1929
1930     @unittest.skip('MW fix required')
1931     def test_twice_nat_lb(self):
1932         """ NAT44ED Twice NAT local service load balancing """
1933
1934     @unittest.skip('MW fix required')
1935     def test_output_feature(self):
1936         """ NAT44ED interface output feature (in2out postrouting) """
1937
1938     @unittest.skip('MW fix required')
1939     def test_static_with_port_out2(self):
1940         """ NAT44ED 1:1 NAPT asymmetrical rule """
1941
1942     @unittest.skip('MW fix required')
1943     def test_output_feature_and_service2(self):
1944         """ NAT44ED interface output feature and service host direct access """
1945
1946     @unittest.skip('MW fix required')
1947     def test_static_lb(self):
1948         """ NAT44ED local service load balancing """
1949
1950     @unittest.skip('MW fix required')
1951     def test_static_lb_2(self):
1952         """ NAT44ED local service load balancing (asymmetrical rule) """
1953
1954     @unittest.skip('MW fix required')
1955     def test_lb_affinity(self):
1956         """ NAT44ED local service load balancing affinity """
1957
1958     @unittest.skip('MW fix required')
1959     def test_multiple_vrf(self):
1960         """ NAT44ED Multiple VRF setup """
1961
1962     @unittest.skip('MW fix required')
1963     def test_self_twice_nat_positive(self):
1964         """ NAT44ED Self Twice NAT (positive test) """
1965
1966     @unittest.skip('MW fix required')
1967     def test_self_twice_nat_lb_positive(self):
1968         """ NAT44ED Self Twice NAT local service load balancing (positive test)
1969         """
1970
1971     def test_dynamic(self):
1972         """ NAT44ED dynamic translation test """
1973
1974         self.nat_add_address(self.nat_addr)
1975         self.nat_add_inside_interface(self.pg0)
1976         self.nat_add_outside_interface(self.pg1)
1977
1978         # in2out
1979         tc1 = self.get_stats_counter('/nat44/ed/in2out/slowpath/tcp')
1980         uc1 = self.get_stats_counter('/nat44/ed/in2out/slowpath/udp')
1981         ic1 = self.get_stats_counter('/nat44/ed/in2out/slowpath/icmp')
1982         dc1 = self.get_stats_counter('/nat44/ed/in2out/slowpath/drops')
1983
1984         pkts = self.create_stream_in(self.pg0, self.pg1)
1985         # TODO: specify worker=idx, also stats have to
1986         #       know from which worker to take capture
1987         self.pg0.add_stream(pkts)
1988         self.pg_enable_capture(self.pg_interfaces)
1989         self.pg_start()
1990         capture = self.pg1.get_capture(len(pkts))
1991         self.verify_capture_out(capture, ignore_port=True)
1992
1993         if_idx = self.pg0.sw_if_index
1994         tc2 = self.get_stats_counter('/nat44/ed/in2out/slowpath/tcp')
1995         uc2 = self.get_stats_counter('/nat44/ed/in2out/slowpath/udp')
1996         ic2 = self.get_stats_counter('/nat44/ed/in2out/slowpath/icmp')
1997         dc2 = self.get_stats_counter('/nat44/ed/in2out/slowpath/drops')
1998
1999         self.assertEqual(tc2[if_idx] - tc1[if_idx], 2)
2000         self.assertEqual(uc2[if_idx] - uc1[if_idx], 1)
2001         self.assertEqual(ic2[if_idx] - ic1[if_idx], 1)
2002         self.assertEqual(dc2[if_idx] - dc1[if_idx], 0)
2003
2004         # out2in
2005         tc1 = self.get_stats_counter('/nat44/ed/out2in/fastpath/tcp')
2006         uc1 = self.get_stats_counter('/nat44/ed/out2in/fastpath/udp')
2007         ic1 = self.get_stats_counter('/nat44/ed/out2in/slowpath/icmp')
2008         dc1 = self.get_stats_counter('/nat44/ed/out2in/fastpath/drops')
2009
2010         pkts = self.create_stream_out(self.pg1)
2011         self.pg1.add_stream(pkts)
2012         self.pg_enable_capture(self.pg_interfaces)
2013         self.pg_start()
2014         capture = self.pg0.get_capture(len(pkts))
2015         self.verify_capture_in(capture, self.pg0)
2016
2017         if_idx = self.pg1.sw_if_index
2018         tc2 = self.get_stats_counter('/nat44/ed/out2in/fastpath/tcp')
2019         uc2 = self.get_stats_counter('/nat44/ed/out2in/fastpath/udp')
2020         ic2 = self.get_stats_counter('/nat44/ed/out2in/slowpath/icmp')
2021         dc2 = self.get_stats_counter('/nat44/ed/out2in/fastpath/drops')
2022
2023         self.assertEqual(tc2[if_idx] - tc1[if_idx], 2)
2024         self.assertEqual(uc2[if_idx] - uc1[if_idx], 1)
2025         self.assertEqual(ic2[if_idx] - ic1[if_idx], 1)
2026         self.assertEqual(dc2[if_idx] - dc1[if_idx], 0)
2027
2028         sc = self.get_stats_counter('/nat44/total-sessions')
2029         self.assertEqual(sc[0], 3)
2030
2031     def test_frag_in_order(self):
2032         """ NAT44ED translate fragments arriving in order """
2033
2034         self.nat_add_address(self.nat_addr)
2035         self.nat_add_inside_interface(self.pg0)
2036         self.nat_add_outside_interface(self.pg1)
2037
2038         self.frag_in_order(proto=IP_PROTOS.tcp, ignore_port=True)
2039         self.frag_in_order(proto=IP_PROTOS.udp, ignore_port=True)
2040         self.frag_in_order(proto=IP_PROTOS.icmp, ignore_port=True)
2041
2042     def test_frag_in_order_do_not_translate(self):
2043         """ NAT44ED don't translate fragments arriving in order """
2044
2045         self.nat_add_address(self.nat_addr)
2046         self.nat_add_inside_interface(self.pg0)
2047         self.nat_add_outside_interface(self.pg1)
2048         self.vapi.nat44_forwarding_enable_disable(enable=True)
2049
2050         self.frag_in_order(proto=IP_PROTOS.tcp, dont_translate=True)
2051
2052     def test_frag_out_of_order(self):
2053         """ NAT44ED translate fragments arriving out of order """
2054
2055         self.nat_add_address(self.nat_addr)
2056         self.nat_add_inside_interface(self.pg0)
2057         self.nat_add_outside_interface(self.pg1)
2058
2059         self.frag_out_of_order(proto=IP_PROTOS.tcp, ignore_port=True)
2060         self.frag_out_of_order(proto=IP_PROTOS.udp, ignore_port=True)
2061         self.frag_out_of_order(proto=IP_PROTOS.icmp, ignore_port=True)
2062
2063     def test_frag_in_order_in_plus_out(self):
2064         """ NAT44ED in+out interface fragments in order """
2065
2066         in_port = self.random_port()
2067         out_port = self.random_port()
2068
2069         self.nat_add_address(self.nat_addr)
2070         self.nat_add_inside_interface(self.pg0)
2071         self.nat_add_outside_interface(self.pg0)
2072         self.nat_add_inside_interface(self.pg1)
2073         self.nat_add_outside_interface(self.pg1)
2074
2075         # add static mappings for server
2076         self.nat_add_static_mapping(self.server_addr,
2077                                     self.nat_addr,
2078                                     in_port,
2079                                     out_port,
2080                                     proto=IP_PROTOS.tcp)
2081         self.nat_add_static_mapping(self.server_addr,
2082                                     self.nat_addr,
2083                                     in_port,
2084                                     out_port,
2085                                     proto=IP_PROTOS.udp)
2086         self.nat_add_static_mapping(self.server_addr,
2087                                     self.nat_addr,
2088                                     proto=IP_PROTOS.icmp)
2089
2090         # run tests for each protocol
2091         self.frag_in_order_in_plus_out(self.server_addr,
2092                                        self.nat_addr,
2093                                        in_port,
2094                                        out_port,
2095                                        IP_PROTOS.tcp)
2096         self.frag_in_order_in_plus_out(self.server_addr,
2097                                        self.nat_addr,
2098                                        in_port,
2099                                        out_port,
2100                                        IP_PROTOS.udp)
2101         self.frag_in_order_in_plus_out(self.server_addr,
2102                                        self.nat_addr,
2103                                        in_port,
2104                                        out_port,
2105                                        IP_PROTOS.icmp)
2106
2107     def test_frag_out_of_order_in_plus_out(self):
2108         """ NAT44ED in+out interface fragments out of order """
2109
2110         in_port = self.random_port()
2111         out_port = self.random_port()
2112
2113         self.nat_add_address(self.nat_addr)
2114         self.nat_add_inside_interface(self.pg0)
2115         self.nat_add_outside_interface(self.pg0)
2116         self.nat_add_inside_interface(self.pg1)
2117         self.nat_add_outside_interface(self.pg1)
2118
2119         # add static mappings for server
2120         self.nat_add_static_mapping(self.server_addr,
2121                                     self.nat_addr,
2122                                     in_port,
2123                                     out_port,
2124                                     proto=IP_PROTOS.tcp)
2125         self.nat_add_static_mapping(self.server_addr,
2126                                     self.nat_addr,
2127                                     in_port,
2128                                     out_port,
2129                                     proto=IP_PROTOS.udp)
2130         self.nat_add_static_mapping(self.server_addr,
2131                                     self.nat_addr,
2132                                     proto=IP_PROTOS.icmp)
2133
2134         # run tests for each protocol
2135         self.frag_out_of_order_in_plus_out(self.server_addr,
2136                                            self.nat_addr,
2137                                            in_port,
2138                                            out_port,
2139                                            IP_PROTOS.tcp)
2140         self.frag_out_of_order_in_plus_out(self.server_addr,
2141                                            self.nat_addr,
2142                                            in_port,
2143                                            out_port,
2144                                            IP_PROTOS.udp)
2145         self.frag_out_of_order_in_plus_out(self.server_addr,
2146                                            self.nat_addr,
2147                                            in_port,
2148                                            out_port,
2149                                            IP_PROTOS.icmp)
2150
2151     def test_reass_hairpinning(self):
2152         """ NAT44ED fragments hairpinning """
2153
2154         server_addr = self.pg0.remote_hosts[1].ip4
2155
2156         host_in_port = self.random_port()
2157         server_in_port = self.random_port()
2158         server_out_port = self.random_port()
2159
2160         self.nat_add_address(self.nat_addr)
2161         self.nat_add_inside_interface(self.pg0)
2162         self.nat_add_outside_interface(self.pg1)
2163
2164         # add static mapping for server
2165         self.nat_add_static_mapping(server_addr, self.nat_addr,
2166                                     server_in_port, server_out_port,
2167                                     proto=IP_PROTOS.tcp)
2168         self.nat_add_static_mapping(server_addr, self.nat_addr,
2169                                     server_in_port, server_out_port,
2170                                     proto=IP_PROTOS.udp)
2171         self.nat_add_static_mapping(server_addr, self.nat_addr)
2172
2173         self.reass_hairpinning(server_addr, server_in_port, server_out_port,
2174                                host_in_port, proto=IP_PROTOS.tcp,
2175                                ignore_port=True)
2176         self.reass_hairpinning(server_addr, server_in_port, server_out_port,
2177                                host_in_port, proto=IP_PROTOS.udp,
2178                                ignore_port=True)
2179         self.reass_hairpinning(server_addr, server_in_port, server_out_port,
2180                                host_in_port, proto=IP_PROTOS.icmp,
2181                                ignore_port=True)
2182
2183     def test_session_limit_per_vrf(self):
2184         """ NAT44ED per vrf session limit """
2185
2186         inside = self.pg0
2187         inside_vrf10 = self.pg2
2188         outside = self.pg1
2189
2190         limit = 5
2191
2192         # 2 interfaces pg0, pg1 (vrf10, limit 1 tcp session)
2193         # non existing vrf_id makes process core dump
2194         self.vapi.nat44_set_session_limit(session_limit=limit, vrf_id=10)
2195
2196         self.nat_add_inside_interface(inside)
2197         self.nat_add_inside_interface(inside_vrf10)
2198         self.nat_add_outside_interface(outside)
2199
2200         # vrf independent
2201         self.nat_add_interface_address(outside)
2202
2203         # BUG: causing core dump - when bad vrf_id is specified
2204         # self.nat_add_address(outside.local_ip4, vrf_id=20)
2205
2206         stream = self.create_tcp_stream(inside_vrf10, outside, limit * 2)
2207         inside_vrf10.add_stream(stream)
2208
2209         self.pg_enable_capture(self.pg_interfaces)
2210         self.pg_start()
2211
2212         capture = outside.get_capture(limit)
2213
2214         stream = self.create_tcp_stream(inside, outside, limit * 2)
2215         inside.add_stream(stream)
2216
2217         self.pg_enable_capture(self.pg_interfaces)
2218         self.pg_start()
2219
2220         capture = outside.get_capture(len(stream))
2221
2222     def test_clear_sessions(self):
2223         """ NAT44ED session clearing test """
2224
2225         self.nat_add_address(self.nat_addr)
2226         self.nat_add_inside_interface(self.pg0)
2227         self.nat_add_outside_interface(self.pg1)
2228
2229         pkts = self.create_stream_in(self.pg0, self.pg1)
2230         self.pg0.add_stream(pkts)
2231         self.pg_enable_capture(self.pg_interfaces)
2232         self.pg_start()
2233         capture = self.pg1.get_capture(len(pkts))
2234         self.verify_capture_out(capture, ignore_port=True)
2235
2236         sessions = self.get_stats_counter('/nat44/total-sessions')
2237         self.assertTrue(sessions[0] > 0)
2238
2239         self.vapi.cli("clear nat44 sessions")
2240
2241         sessions = self.get_stats_counter('/nat44/total-sessions')
2242         self.assertEqual(sessions[0], 0)
2243
2244     def test_show_max_translations(self):
2245         """ NAT44ED API test - max translations per thread """
2246         nat_config = self.vapi.nat_show_config_2()
2247         self.assertEqual(self.max_sessions,
2248                          nat_config.max_translations_per_thread)
2249
2250     def test_lru_cleanup(self):
2251         """ NAT44ED LRU cleanup algorithm """
2252
2253         self.nat_add_address(self.nat_addr)
2254         self.nat_add_inside_interface(self.pg0)
2255         self.nat_add_outside_interface(self.pg1)
2256
2257         self.vapi.nat_set_timeouts(
2258             udp=1, tcp_established=7440, tcp_transitory=30, icmp=1)
2259
2260         tcp_port_out = self.init_tcp_session(self.pg0, self.pg1, 2000, 80)
2261         pkts = []
2262         for i in range(0, self.max_sessions - 1):
2263             p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2264                  IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4, ttl=64) /
2265                  UDP(sport=7000+i, dport=80))
2266             pkts.append(p)
2267
2268         self.pg0.add_stream(pkts)
2269         self.pg_enable_capture(self.pg_interfaces)
2270         self.pg_start()
2271         self.pg1.get_capture(len(pkts))
2272         self.sleep(1.5, "wait for timeouts")
2273
2274         pkts = []
2275         for i in range(0, self.max_sessions - 1):
2276             p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2277                  IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4, ttl=64) /
2278                  ICMP(id=8000+i, type='echo-request'))
2279             pkts.append(p)
2280
2281         self.pg0.add_stream(pkts)
2282         self.pg_enable_capture(self.pg_interfaces)
2283         self.pg_start()
2284         self.pg1.get_capture(len(pkts))
2285
2286     def test_session_rst_timeout(self):
2287         """ NAT44ED session RST timeouts """
2288
2289         self.nat_add_address(self.nat_addr)
2290         self.nat_add_inside_interface(self.pg0)
2291         self.nat_add_outside_interface(self.pg1)
2292
2293         self.vapi.nat_set_timeouts(udp=300, tcp_established=7440,
2294                                    tcp_transitory=5, icmp=60)
2295
2296         self.init_tcp_session(self.pg0, self.pg1, self.tcp_port_in,
2297                               self.tcp_external_port)
2298         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
2299              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
2300              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
2301                  flags="R"))
2302         self.pg0.add_stream(p)
2303         self.pg_enable_capture(self.pg_interfaces)
2304         self.pg_start()
2305         self.pg1.get_capture(1)
2306
2307         self.sleep(6)
2308
2309         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
2310              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
2311              TCP(sport=self.tcp_port_in + 1, dport=self.tcp_external_port + 1,
2312                  flags="S"))
2313         self.pg0.add_stream(p)
2314         self.pg_enable_capture(self.pg_interfaces)
2315         self.pg_start()
2316         self.pg1.get_capture(1)
2317
2318     def test_dynamic_out_of_ports(self):
2319         """ NAT44ED dynamic translation test: out of ports """
2320
2321         self.nat_add_inside_interface(self.pg0)
2322         self.nat_add_outside_interface(self.pg1)
2323
2324         # in2out and no NAT addresses added
2325         err_old = self.statistics.get_err_counter(
2326             '/err/nat44-ed-in2out-slowpath/out of ports')
2327
2328         pkts = self.create_stream_in(self.pg0, self.pg1)
2329         self.pg0.add_stream(pkts)
2330         self.pg_enable_capture(self.pg_interfaces)
2331         self.pg_start()
2332         self.pg1.get_capture(0, timeout=1)
2333
2334         err_new = self.statistics.get_err_counter(
2335             '/err/nat44-ed-in2out-slowpath/out of ports')
2336
2337         self.assertEqual(err_new - err_old, len(pkts))
2338
2339         # in2out after NAT addresses added
2340         self.nat_add_address(self.nat_addr)
2341
2342         err_old = self.statistics.get_err_counter(
2343             '/err/nat44-ed-in2out-slowpath/out of ports')
2344
2345         pkts = self.create_stream_in(self.pg0, self.pg1)
2346         self.pg0.add_stream(pkts)
2347         self.pg_enable_capture(self.pg_interfaces)
2348         self.pg_start()
2349         capture = self.pg1.get_capture(len(pkts))
2350         self.verify_capture_out(capture, ignore_port=True)
2351
2352         err_new = self.statistics.get_err_counter(
2353             '/err/nat44-ed-in2out-slowpath/out of ports')
2354
2355         self.assertEqual(err_new, err_old)
2356
2357     def test_unknown_proto(self):
2358         """ NAT44ED translate packet with unknown protocol """
2359
2360         self.nat_add_address(self.nat_addr)
2361         self.nat_add_inside_interface(self.pg0)
2362         self.nat_add_outside_interface(self.pg1)
2363
2364         # in2out
2365         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2366              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
2367              TCP(sport=self.tcp_port_in, dport=20))
2368         self.pg0.add_stream(p)
2369         self.pg_enable_capture(self.pg_interfaces)
2370         self.pg_start()
2371         p = self.pg1.get_capture(1)
2372
2373         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2374              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
2375              GRE() /
2376              IP(src=self.pg2.remote_ip4, dst=self.pg2.remote_ip4) /
2377              TCP(sport=1234, dport=1234))
2378         self.pg0.add_stream(p)
2379         self.pg_enable_capture(self.pg_interfaces)
2380         self.pg_start()
2381         p = self.pg1.get_capture(1)
2382         packet = p[0]
2383         try:
2384             self.assertEqual(packet[IP].src, self.nat_addr)
2385             self.assertEqual(packet[IP].dst, self.pg1.remote_ip4)
2386             self.assertEqual(packet.haslayer(GRE), 1)
2387             self.assert_packet_checksums_valid(packet)
2388         except:
2389             self.logger.error(ppp("Unexpected or invalid packet:", packet))
2390             raise
2391
2392         # out2in
2393         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
2394              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
2395              GRE() /
2396              IP(src=self.pg2.remote_ip4, dst=self.pg2.remote_ip4) /
2397              TCP(sport=1234, dport=1234))
2398         self.pg1.add_stream(p)
2399         self.pg_enable_capture(self.pg_interfaces)
2400         self.pg_start()
2401         p = self.pg0.get_capture(1)
2402         packet = p[0]
2403         try:
2404             self.assertEqual(packet[IP].src, self.pg1.remote_ip4)
2405             self.assertEqual(packet[IP].dst, self.pg0.remote_ip4)
2406             self.assertEqual(packet.haslayer(GRE), 1)
2407             self.assert_packet_checksums_valid(packet)
2408         except:
2409             self.logger.error(ppp("Unexpected or invalid packet:", packet))
2410             raise
2411
2412     def test_hairpinning_unknown_proto(self):
2413         """ NAT44ED translate packet with unknown protocol - hairpinning """
2414         host = self.pg0.remote_hosts[0]
2415         server = self.pg0.remote_hosts[1]
2416         host_in_port = 1234
2417         server_out_port = 8765
2418         server_nat_ip = "10.0.0.11"
2419
2420         self.nat_add_address(self.nat_addr)
2421         self.nat_add_inside_interface(self.pg0)
2422         self.nat_add_outside_interface(self.pg1)
2423
2424         # add static mapping for server
2425         self.nat_add_static_mapping(server.ip4, server_nat_ip)
2426
2427         # host to server
2428         p = (Ether(src=host.mac, dst=self.pg0.local_mac) /
2429              IP(src=host.ip4, dst=server_nat_ip) /
2430              TCP(sport=host_in_port, dport=server_out_port))
2431         self.pg0.add_stream(p)
2432         self.pg_enable_capture(self.pg_interfaces)
2433         self.pg_start()
2434         self.pg0.get_capture(1)
2435
2436         p = (Ether(dst=self.pg0.local_mac, src=host.mac) /
2437              IP(src=host.ip4, dst=server_nat_ip) /
2438              GRE() /
2439              IP(src=self.pg2.remote_ip4, dst=self.pg2.remote_ip4) /
2440              TCP(sport=1234, dport=1234))
2441         self.pg0.add_stream(p)
2442         self.pg_enable_capture(self.pg_interfaces)
2443         self.pg_start()
2444         p = self.pg0.get_capture(1)
2445         packet = p[0]
2446         try:
2447             self.assertEqual(packet[IP].src, self.nat_addr)
2448             self.assertEqual(packet[IP].dst, server.ip4)
2449             self.assertEqual(packet.haslayer(GRE), 1)
2450             self.assert_packet_checksums_valid(packet)
2451         except:
2452             self.logger.error(ppp("Unexpected or invalid packet:", packet))
2453             raise
2454
2455         # server to host
2456         p = (Ether(dst=self.pg0.local_mac, src=server.mac) /
2457              IP(src=server.ip4, dst=self.nat_addr) /
2458              GRE() /
2459              IP(src=self.pg2.remote_ip4, dst=self.pg2.remote_ip4) /
2460              TCP(sport=1234, dport=1234))
2461         self.pg0.add_stream(p)
2462         self.pg_enable_capture(self.pg_interfaces)
2463         self.pg_start()
2464         p = self.pg0.get_capture(1)
2465         packet = p[0]
2466         try:
2467             self.assertEqual(packet[IP].src, server_nat_ip)
2468             self.assertEqual(packet[IP].dst, host.ip4)
2469             self.assertEqual(packet.haslayer(GRE), 1)
2470             self.assert_packet_checksums_valid(packet)
2471         except:
2472             self.logger.error(ppp("Unexpected or invalid packet:", packet))
2473             raise
2474
2475     def test_output_feature_and_service(self):
2476         """ NAT44ED interface output feature and services """
2477         external_addr = '1.2.3.4'
2478         external_port = 80
2479         local_port = 8080
2480
2481         self.vapi.nat44_forwarding_enable_disable(enable=1)
2482         self.nat_add_address(self.nat_addr)
2483         flags = self.config_flags.NAT_IS_ADDR_ONLY
2484         self.vapi.nat44_add_del_identity_mapping(
2485             ip_address=self.pg1.remote_ip4, sw_if_index=0xFFFFFFFF,
2486             flags=flags, is_add=1)
2487         flags = self.config_flags.NAT_IS_OUT2IN_ONLY
2488         self.nat_add_static_mapping(self.pg0.remote_ip4, external_addr,
2489                                     local_port, external_port,
2490                                     proto=IP_PROTOS.tcp, flags=flags)
2491
2492         self.nat_add_inside_interface(self.pg0)
2493         self.nat_add_outside_interface(self.pg0)
2494         self.vapi.nat44_interface_add_del_output_feature(
2495             sw_if_index=self.pg1.sw_if_index, is_add=1)
2496
2497         # from client to service
2498         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
2499              IP(src=self.pg1.remote_ip4, dst=external_addr) /
2500              TCP(sport=12345, dport=external_port))
2501         self.pg1.add_stream(p)
2502         self.pg_enable_capture(self.pg_interfaces)
2503         self.pg_start()
2504         capture = self.pg0.get_capture(1)
2505         p = capture[0]
2506         try:
2507             ip = p[IP]
2508             tcp = p[TCP]
2509             self.assertEqual(ip.dst, self.pg0.remote_ip4)
2510             self.assertEqual(tcp.dport, local_port)
2511             self.assert_packet_checksums_valid(p)
2512         except:
2513             self.logger.error(ppp("Unexpected or invalid packet:", p))
2514             raise
2515
2516         # from service back to client
2517         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
2518              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
2519              TCP(sport=local_port, dport=12345))
2520         self.pg0.add_stream(p)
2521         self.pg_enable_capture(self.pg_interfaces)
2522         self.pg_start()
2523         capture = self.pg1.get_capture(1)
2524         p = capture[0]
2525         try:
2526             ip = p[IP]
2527             tcp = p[TCP]
2528             self.assertEqual(ip.src, external_addr)
2529             self.assertEqual(tcp.sport, external_port)
2530             self.assert_packet_checksums_valid(p)
2531         except:
2532             self.logger.error(ppp("Unexpected or invalid packet:", p))
2533             raise
2534
2535         # from local network host to external network
2536         pkts = self.create_stream_in(self.pg0, self.pg1)
2537         self.pg0.add_stream(pkts)
2538         self.pg_enable_capture(self.pg_interfaces)
2539         self.pg_start()
2540         capture = self.pg1.get_capture(len(pkts))
2541         self.verify_capture_out(capture, ignore_port=True)
2542         pkts = self.create_stream_in(self.pg0, self.pg1)
2543         self.pg0.add_stream(pkts)
2544         self.pg_enable_capture(self.pg_interfaces)
2545         self.pg_start()
2546         capture = self.pg1.get_capture(len(pkts))
2547         self.verify_capture_out(capture, ignore_port=True)
2548
2549         # from external network back to local network host
2550         pkts = self.create_stream_out(self.pg1)
2551         self.pg1.add_stream(pkts)
2552         self.pg_enable_capture(self.pg_interfaces)
2553         self.pg_start()
2554         capture = self.pg0.get_capture(len(pkts))
2555         self.verify_capture_in(capture, self.pg0)
2556
2557     def test_output_feature_and_service3(self):
2558         """ NAT44ED interface output feature and DST NAT """
2559         external_addr = '1.2.3.4'
2560         external_port = 80
2561         local_port = 8080
2562
2563         self.vapi.nat44_forwarding_enable_disable(enable=1)
2564         self.nat_add_address(self.nat_addr)
2565         flags = self.config_flags.NAT_IS_OUT2IN_ONLY
2566         self.nat_add_static_mapping(self.pg1.remote_ip4, external_addr,
2567                                     local_port, external_port,
2568                                     proto=IP_PROTOS.tcp, flags=flags)
2569
2570         self.nat_add_inside_interface(self.pg0)
2571         self.nat_add_outside_interface(self.pg0)
2572         self.vapi.nat44_interface_add_del_output_feature(
2573             sw_if_index=self.pg1.sw_if_index, is_add=1)
2574
2575         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
2576              IP(src=self.pg0.remote_ip4, dst=external_addr) /
2577              TCP(sport=12345, dport=external_port))
2578         self.pg0.add_stream(p)
2579         self.pg_enable_capture(self.pg_interfaces)
2580         self.pg_start()
2581         capture = self.pg1.get_capture(1)
2582         p = capture[0]
2583         try:
2584             ip = p[IP]
2585             tcp = p[TCP]
2586             self.assertEqual(ip.src, self.pg0.remote_ip4)
2587             self.assertEqual(tcp.sport, 12345)
2588             self.assertEqual(ip.dst, self.pg1.remote_ip4)
2589             self.assertEqual(tcp.dport, local_port)
2590             self.assert_packet_checksums_valid(p)
2591         except:
2592             self.logger.error(ppp("Unexpected or invalid packet:", p))
2593             raise
2594
2595         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
2596              IP(src=self.pg1.remote_ip4, dst=self.pg0.remote_ip4) /
2597              TCP(sport=local_port, dport=12345))
2598         self.pg1.add_stream(p)
2599         self.pg_enable_capture(self.pg_interfaces)
2600         self.pg_start()
2601         capture = self.pg0.get_capture(1)
2602         p = capture[0]
2603         try:
2604             ip = p[IP]
2605             tcp = p[TCP]
2606             self.assertEqual(ip.src, external_addr)
2607             self.assertEqual(tcp.sport, external_port)
2608             self.assertEqual(ip.dst, self.pg0.remote_ip4)
2609             self.assertEqual(tcp.dport, 12345)
2610             self.assert_packet_checksums_valid(p)
2611         except:
2612             self.logger.error(ppp("Unexpected or invalid packet:", p))
2613             raise
2614
2615     def test_self_twice_nat_lb_negative(self):
2616         """ NAT44ED Self Twice NAT local service load balancing (negative test)
2617         """
2618         self.twice_nat_common(lb=True, self_twice_nat=True, same_pg=True,
2619                               client_id=2)
2620
2621     def test_self_twice_nat_negative(self):
2622         """ NAT44ED Self Twice NAT (negative test) """
2623         self.twice_nat_common(self_twice_nat=True)
2624
2625     def test_static_lb_multi_clients(self):
2626         """ NAT44ED local service load balancing - multiple clients"""
2627
2628         external_addr = self.nat_addr
2629         external_port = 80
2630         local_port = 8080
2631         server1 = self.pg0.remote_hosts[0]
2632         server2 = self.pg0.remote_hosts[1]
2633         server3 = self.pg0.remote_hosts[2]
2634
2635         locals = [{'addr': server1.ip4,
2636                    'port': local_port,
2637                    'probability': 90,
2638                    'vrf_id': 0},
2639                   {'addr': server2.ip4,
2640                    'port': local_port,
2641                    'probability': 10,
2642                    'vrf_id': 0}]
2643
2644         flags = self.config_flags.NAT_IS_INSIDE
2645         self.vapi.nat44_interface_add_del_feature(
2646             sw_if_index=self.pg0.sw_if_index,
2647             flags=flags, is_add=1)
2648         self.vapi.nat44_interface_add_del_feature(
2649             sw_if_index=self.pg1.sw_if_index,
2650             is_add=1)
2651
2652         self.nat_add_address(self.nat_addr)
2653         self.vapi.nat44_add_del_lb_static_mapping(is_add=1,
2654                                                   external_addr=external_addr,
2655                                                   external_port=external_port,
2656                                                   protocol=IP_PROTOS.tcp,
2657                                                   local_num=len(locals),
2658                                                   locals=locals)
2659
2660         server1_n = 0
2661         server2_n = 0
2662         clients = ip4_range(self.pg1.remote_ip4, 10, 50)
2663         pkts = []
2664         for client in clients:
2665             p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
2666                  IP(src=client, dst=self.nat_addr) /
2667                  TCP(sport=12345, dport=external_port))
2668             pkts.append(p)
2669         self.pg1.add_stream(pkts)
2670         self.pg_enable_capture(self.pg_interfaces)
2671         self.pg_start()
2672         capture = self.pg0.get_capture(len(pkts))
2673         for p in capture:
2674             if p[IP].dst == server1.ip4:
2675                 server1_n += 1
2676             else:
2677                 server2_n += 1
2678         self.assertGreater(server1_n, server2_n)
2679
2680         local = {
2681             'addr': server3.ip4,
2682             'port': local_port,
2683             'probability': 20,
2684             'vrf_id': 0
2685         }
2686
2687         # add new back-end
2688         self.vapi.nat44_lb_static_mapping_add_del_local(
2689             is_add=1,
2690             external_addr=external_addr,
2691             external_port=external_port,
2692             local=local,
2693             protocol=IP_PROTOS.tcp)
2694         server1_n = 0
2695         server2_n = 0
2696         server3_n = 0
2697         clients = ip4_range(self.pg1.remote_ip4, 60, 110)
2698         pkts = []
2699         for client in clients:
2700             p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
2701                  IP(src=client, dst=self.nat_addr) /
2702                  TCP(sport=12346, dport=external_port))
2703             pkts.append(p)
2704         self.assertGreater(len(pkts), 0)
2705         self.pg1.add_stream(pkts)
2706         self.pg_enable_capture(self.pg_interfaces)
2707         self.pg_start()
2708         capture = self.pg0.get_capture(len(pkts))
2709         for p in capture:
2710             if p[IP].dst == server1.ip4:
2711                 server1_n += 1
2712             elif p[IP].dst == server2.ip4:
2713                 server2_n += 1
2714             else:
2715                 server3_n += 1
2716         self.assertGreater(server1_n, 0)
2717         self.assertGreater(server2_n, 0)
2718         self.assertGreater(server3_n, 0)
2719
2720         local = {
2721             'addr': server2.ip4,
2722             'port': local_port,
2723             'probability': 10,
2724             'vrf_id': 0
2725         }
2726
2727         # remove one back-end
2728         self.vapi.nat44_lb_static_mapping_add_del_local(
2729             is_add=0,
2730             external_addr=external_addr,
2731             external_port=external_port,
2732             local=local,
2733             protocol=IP_PROTOS.tcp)
2734         server1_n = 0
2735         server2_n = 0
2736         server3_n = 0
2737         self.pg1.add_stream(pkts)
2738         self.pg_enable_capture(self.pg_interfaces)
2739         self.pg_start()
2740         capture = self.pg0.get_capture(len(pkts))
2741         for p in capture:
2742             if p[IP].dst == server1.ip4:
2743                 server1_n += 1
2744             elif p[IP].dst == server2.ip4:
2745                 server2_n += 1
2746             else:
2747                 server3_n += 1
2748         self.assertGreater(server1_n, 0)
2749         self.assertEqual(server2_n, 0)
2750         self.assertGreater(server3_n, 0)
2751
2752     def test_syslog_sess(self):
2753         """ NAT44ED Test syslog session creation and deletion """
2754         self.vapi.syslog_set_filter(
2755             self.syslog_severity.SYSLOG_API_SEVERITY_INFO)
2756         self.vapi.syslog_set_sender(self.pg3.local_ip4, self.pg3.remote_ip4)
2757
2758         self.nat_add_address(self.nat_addr)
2759         self.nat_add_inside_interface(self.pg0)
2760         self.nat_add_outside_interface(self.pg1)
2761
2762         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2763              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
2764              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port))
2765         self.pg0.add_stream(p)
2766         self.pg_enable_capture(self.pg_interfaces)
2767         self.pg_start()
2768         capture = self.pg1.get_capture(1)
2769         self.tcp_port_out = capture[0][TCP].sport
2770         capture = self.pg3.get_capture(1)
2771         self.verify_syslog_sess(capture[0][Raw].load)
2772
2773         self.pg_enable_capture(self.pg_interfaces)
2774         self.pg_start()
2775         self.nat_add_address(self.nat_addr, is_add=0)
2776         capture = self.pg3.get_capture(1)
2777         self.verify_syslog_sess(capture[0][Raw].load, False)
2778
2779     def test_twice_nat_interface_addr(self):
2780         """ NAT44ED Acquire twice NAT addresses from interface """
2781         flags = self.config_flags.NAT_IS_TWICE_NAT
2782         self.vapi.nat44_add_del_interface_addr(
2783             sw_if_index=self.pg11.sw_if_index,
2784             flags=flags, is_add=1)
2785
2786         # no address in NAT pool
2787         adresses = self.vapi.nat44_address_dump()
2788         self.assertEqual(0, len(adresses))
2789
2790         # configure interface address and check NAT address pool
2791         self.pg11.config_ip4()
2792         adresses = self.vapi.nat44_address_dump()
2793         self.assertEqual(1, len(adresses))
2794         self.assertEqual(str(adresses[0].ip_address),
2795                          self.pg11.local_ip4)
2796         self.assertEqual(adresses[0].flags, flags)
2797
2798         # remove interface address and check NAT address pool
2799         self.pg11.unconfig_ip4()
2800         adresses = self.vapi.nat44_address_dump()
2801         self.assertEqual(0, len(adresses))
2802
2803     def test_output_feature_stateful_acl(self):
2804         """ NAT44ED output feature works with stateful ACL """
2805
2806         self.nat_add_address(self.nat_addr)
2807         self.vapi.nat44_interface_add_del_output_feature(
2808             sw_if_index=self.pg0.sw_if_index,
2809             flags=self.config_flags.NAT_IS_INSIDE, is_add=1)
2810         self.vapi.nat44_interface_add_del_output_feature(
2811             sw_if_index=self.pg1.sw_if_index,
2812             flags=self.config_flags.NAT_IS_OUTSIDE, is_add=1)
2813
2814         # First ensure that the NAT is working sans ACL
2815
2816         # send packets out2in, no sessions yet so packets should drop
2817         pkts_out2in = self.create_stream_out(self.pg1)
2818         self.send_and_assert_no_replies(self.pg1, pkts_out2in)
2819
2820         # send packets into inside intf, ensure received via outside intf
2821         pkts_in2out = self.create_stream_in(self.pg0, self.pg1)
2822         capture = self.send_and_expect(self.pg0, pkts_in2out, self.pg1,
2823                                        len(pkts_in2out))
2824         self.verify_capture_out(capture, ignore_port=True)
2825
2826         # send out2in again, with sessions created it should work now
2827         pkts_out2in = self.create_stream_out(self.pg1)
2828         capture = self.send_and_expect(self.pg1, pkts_out2in, self.pg0,
2829                                        len(pkts_out2in))
2830         self.verify_capture_in(capture, self.pg0)
2831
2832         # Create an ACL blocking everything
2833         out2in_deny_rule = AclRule(is_permit=0)
2834         out2in_acl = VppAcl(self, rules=[out2in_deny_rule])
2835         out2in_acl.add_vpp_config()
2836
2837         # create an ACL to permit/reflect everything
2838         in2out_reflect_rule = AclRule(is_permit=2)
2839         in2out_acl = VppAcl(self, rules=[in2out_reflect_rule])
2840         in2out_acl.add_vpp_config()
2841
2842         # apply as input acl on interface and confirm it blocks everything
2843         acl_if = VppAclInterface(self, sw_if_index=self.pg1.sw_if_index,
2844                                  n_input=1, acls=[out2in_acl])
2845         acl_if.add_vpp_config()
2846         self.send_and_assert_no_replies(self.pg1, pkts_out2in)
2847
2848         # apply output acl
2849         acl_if.acls = [out2in_acl, in2out_acl]
2850         acl_if.add_vpp_config()
2851         # send in2out to generate ACL state (NAT state was created earlier)
2852         capture = self.send_and_expect(self.pg0, pkts_in2out, self.pg1,
2853                                        len(pkts_in2out))
2854         self.verify_capture_out(capture, ignore_port=True)
2855
2856         # send out2in again. ACL state exists so it should work now.
2857         # TCP packets with the syn flag set also need the ack flag
2858         for p in pkts_out2in:
2859             if p.haslayer(TCP) and p[TCP].flags & 0x02:
2860                 p[TCP].flags |= 0x10
2861         capture = self.send_and_expect(self.pg1, pkts_out2in, self.pg0,
2862                                        len(pkts_out2in))
2863         self.verify_capture_in(capture, self.pg0)
2864         self.logger.info(self.vapi.cli("show trace"))
2865
2866     def test_tcp_close(self):
2867         """ NAT44ED Close TCP session from inside network - output feature """
2868         old_timeouts = self.vapi.nat_get_timeouts()
2869         new_transitory = 2
2870         self.vapi.nat_set_timeouts(
2871             udp=old_timeouts.udp,
2872             tcp_established=old_timeouts.tcp_established,
2873             icmp=old_timeouts.icmp,
2874             tcp_transitory=new_transitory)
2875
2876         self.vapi.nat44_forwarding_enable_disable(enable=1)
2877         self.nat_add_address(self.pg1.local_ip4)
2878         twice_nat_addr = '10.0.1.3'
2879         service_ip = '192.168.16.150'
2880         self.nat_add_address(twice_nat_addr, twice_nat=1)
2881
2882         flags = self.config_flags.NAT_IS_INSIDE
2883         self.vapi.nat44_interface_add_del_feature(
2884             sw_if_index=self.pg0.sw_if_index,
2885             is_add=1)
2886         self.vapi.nat44_interface_add_del_feature(
2887             sw_if_index=self.pg0.sw_if_index,
2888             flags=flags, is_add=1)
2889         self.vapi.nat44_interface_add_del_output_feature(
2890             is_add=1,
2891             sw_if_index=self.pg1.sw_if_index)
2892
2893         flags = (self.config_flags.NAT_IS_OUT2IN_ONLY |
2894                  self.config_flags.NAT_IS_TWICE_NAT)
2895         self.nat_add_static_mapping(self.pg0.remote_ip4,
2896                                     service_ip, 80, 80,
2897                                     proto=IP_PROTOS.tcp,
2898                                     flags=flags)
2899         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
2900         start_sessnum = len(sessions)
2901
2902         # SYN packet out->in
2903         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
2904              IP(src=self.pg1.remote_ip4, dst=service_ip) /
2905              TCP(sport=33898, dport=80, flags="S"))
2906         self.pg1.add_stream(p)
2907         self.pg_enable_capture(self.pg_interfaces)
2908         self.pg_start()
2909         capture = self.pg0.get_capture(1)
2910         p = capture[0]
2911         tcp_port = p[TCP].sport
2912
2913         # SYN + ACK packet in->out
2914         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
2915              IP(src=self.pg0.remote_ip4, dst=twice_nat_addr) /
2916              TCP(sport=80, dport=tcp_port, flags="SA"))
2917         self.pg0.add_stream(p)
2918         self.pg_enable_capture(self.pg_interfaces)
2919         self.pg_start()
2920         self.pg1.get_capture(1)
2921
2922         # ACK packet out->in
2923         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
2924              IP(src=self.pg1.remote_ip4, dst=service_ip) /
2925              TCP(sport=33898, dport=80, flags="A"))
2926         self.pg1.add_stream(p)
2927         self.pg_enable_capture(self.pg_interfaces)
2928         self.pg_start()
2929         self.pg0.get_capture(1)
2930
2931         # FIN packet in -> out
2932         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
2933              IP(src=self.pg0.remote_ip4, dst=twice_nat_addr) /
2934              TCP(sport=80, dport=tcp_port, flags="FA", seq=100, ack=300))
2935         self.pg0.add_stream(p)
2936         self.pg_enable_capture(self.pg_interfaces)
2937         self.pg_start()
2938         self.pg1.get_capture(1)
2939
2940         # FIN+ACK packet out -> in
2941         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
2942              IP(src=self.pg1.remote_ip4, dst=service_ip) /
2943              TCP(sport=33898, dport=80, flags="FA", seq=300, ack=101))
2944         self.pg1.add_stream(p)
2945         self.pg_enable_capture(self.pg_interfaces)
2946         self.pg_start()
2947         self.pg0.get_capture(1)
2948
2949         # ACK packet in -> out
2950         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
2951              IP(src=self.pg0.remote_ip4, dst=twice_nat_addr) /
2952              TCP(sport=80, dport=tcp_port, flags="A", seq=101, ack=301))
2953         self.pg0.add_stream(p)
2954         self.pg_enable_capture(self.pg_interfaces)
2955         self.pg_start()
2956         self.pg1.get_capture(1)
2957
2958         # session now in transitory timeout
2959         # try SYN packet out->in - should be dropped
2960         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
2961              IP(src=self.pg1.remote_ip4, dst=service_ip) /
2962              TCP(sport=33898, dport=80, flags="S"))
2963         self.pg1.add_stream(p)
2964         self.pg_enable_capture(self.pg_interfaces)
2965         self.pg_start()
2966
2967         self.sleep(new_transitory, "wait for transitory timeout")
2968         self.pg0.assert_nothing_captured(0)
2969
2970         # session should still exist
2971         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
2972         self.assertEqual(len(sessions) - start_sessnum, 1)
2973
2974         # send FIN+ACK packet out -> in - will cause session to be wiped
2975         # but won't create a new session
2976         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
2977              IP(src=self.pg1.remote_ip4, dst=service_ip) /
2978              TCP(sport=33898, dport=80, flags="FA", seq=300, ack=101))
2979         self.pg1.add_stream(p)
2980         self.pg_enable_capture(self.pg_interfaces)
2981         self.pg_start()
2982
2983         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
2984         self.assertEqual(len(sessions) - start_sessnum, 0)
2985         self.pg0.assert_nothing_captured(0)
2986
2987     def test_tcp_session_close_in(self):
2988         """ NAT44ED Close TCP session from inside network """
2989
2990         in_port = self.tcp_port_in
2991         out_port = 10505
2992         ext_port = self.tcp_external_port
2993
2994         self.nat_add_address(self.nat_addr)
2995         self.nat_add_inside_interface(self.pg0)
2996         self.nat_add_outside_interface(self.pg1)
2997         self.nat_add_static_mapping(self.pg0.remote_ip4, self.nat_addr,
2998                                     in_port, out_port, proto=IP_PROTOS.tcp,
2999                                     flags=self.config_flags.NAT_IS_TWICE_NAT)
3000
3001         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
3002         session_n = len(sessions)
3003
3004         self.vapi.nat_set_timeouts(udp=300, tcp_established=7440,
3005                                    tcp_transitory=2, icmp=5)
3006
3007         self.init_tcp_session(self.pg0, self.pg1, in_port, ext_port)
3008
3009         # FIN packet in -> out
3010         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
3011              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3012              TCP(sport=in_port, dport=ext_port,
3013                  flags="FA", seq=100, ack=300))
3014         self.pg0.add_stream(p)
3015         self.pg_enable_capture(self.pg_interfaces)
3016         self.pg_start()
3017         self.pg1.get_capture(1)
3018
3019         pkts = []
3020
3021         # ACK packet out -> in
3022         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
3023              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
3024              TCP(sport=ext_port, dport=out_port,
3025                  flags="A", seq=300, ack=101))
3026         pkts.append(p)
3027
3028         # FIN packet out -> in
3029         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
3030              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
3031              TCP(sport=ext_port, dport=out_port,
3032                  flags="FA", seq=300, ack=101))
3033         pkts.append(p)
3034
3035         self.pg1.add_stream(pkts)
3036         self.pg_enable_capture(self.pg_interfaces)
3037         self.pg_start()
3038         self.pg0.get_capture(2)
3039
3040         # ACK packet in -> out
3041         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
3042              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3043              TCP(sport=in_port, dport=ext_port,
3044                  flags="A", seq=101, ack=301))
3045         self.pg0.add_stream(p)
3046         self.pg_enable_capture(self.pg_interfaces)
3047         self.pg_start()
3048         self.pg1.get_capture(1)
3049
3050         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
3051         self.assertEqual(len(sessions) - session_n, 1)
3052
3053         out2in_drops = self.get_err_counter(
3054             '/err/nat44-ed-out2in/drops due to TCP in transitory timeout')
3055         in2out_drops = self.get_err_counter(
3056             '/err/nat44-ed-in2out/drops due to TCP in transitory timeout')
3057
3058         # extra FIN packet out -> in - this should be dropped
3059         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
3060              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
3061              TCP(sport=ext_port, dport=out_port,
3062                  flags="FA", seq=300, ack=101))
3063
3064         self.pg1.add_stream(p)
3065         self.pg_enable_capture(self.pg_interfaces)
3066         self.pg_start()
3067         self.pg0.assert_nothing_captured()
3068
3069         # extra ACK packet in -> out - this should be dropped
3070         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
3071              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3072              TCP(sport=in_port, dport=ext_port,
3073                  flags="A", seq=101, ack=301))
3074         self.pg0.add_stream(p)
3075         self.pg_enable_capture(self.pg_interfaces)
3076         self.pg_start()
3077         self.pg1.assert_nothing_captured()
3078
3079         stats = self.get_err_counter(
3080             '/err/nat44-ed-out2in/drops due to TCP in transitory timeout')
3081         self.assertEqual(stats - out2in_drops, 1)
3082         stats = self.get_err_counter(
3083             '/err/nat44-ed-in2out/drops due to TCP in transitory timeout')
3084         self.assertEqual(stats - in2out_drops, 1)
3085
3086         self.sleep(3)
3087         # extra ACK packet in -> out - this will cause session to be wiped
3088         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
3089              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3090              TCP(sport=in_port, dport=ext_port,
3091                  flags="A", seq=101, ack=301))
3092         self.pg0.add_stream(p)
3093         self.pg_enable_capture(self.pg_interfaces)
3094         self.pg_start()
3095         self.pg1.assert_nothing_captured()
3096         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
3097         self.assertEqual(len(sessions) - session_n, 0)
3098
3099     def test_tcp_session_close_out(self):
3100         """ NAT44ED Close TCP session from outside network """
3101
3102         in_port = self.tcp_port_in
3103         out_port = 10505
3104         ext_port = self.tcp_external_port
3105
3106         self.nat_add_address(self.nat_addr)
3107         self.nat_add_inside_interface(self.pg0)
3108         self.nat_add_outside_interface(self.pg1)
3109         self.nat_add_static_mapping(self.pg0.remote_ip4, self.nat_addr,
3110                                     in_port, out_port, proto=IP_PROTOS.tcp,
3111                                     flags=self.config_flags.NAT_IS_TWICE_NAT)
3112
3113         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
3114         session_n = len(sessions)
3115
3116         self.vapi.nat_set_timeouts(udp=300, tcp_established=7440,
3117                                    tcp_transitory=2, icmp=5)
3118
3119         _ = self.init_tcp_session(self.pg0, self.pg1, in_port, ext_port)
3120
3121         # FIN packet out -> in
3122         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
3123              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
3124              TCP(sport=ext_port, dport=out_port,
3125                  flags="FA", seq=100, ack=300))
3126         self.pg1.add_stream(p)
3127         self.pg_enable_capture(self.pg_interfaces)
3128         self.pg_start()
3129         self.pg0.get_capture(1)
3130
3131         # FIN+ACK packet in -> out
3132         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
3133              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3134              TCP(sport=in_port, dport=ext_port,
3135                  flags="FA", seq=300, ack=101))
3136
3137         self.pg0.add_stream(p)
3138         self.pg_enable_capture(self.pg_interfaces)
3139         self.pg_start()
3140         self.pg1.get_capture(1)
3141
3142         # ACK packet out -> in
3143         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
3144              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
3145              TCP(sport=ext_port, dport=out_port,
3146                  flags="A", seq=101, ack=301))
3147         self.pg1.add_stream(p)
3148         self.pg_enable_capture(self.pg_interfaces)
3149         self.pg_start()
3150         self.pg0.get_capture(1)
3151
3152         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
3153         self.assertEqual(len(sessions) - session_n, 1)
3154
3155         out2in_drops = self.get_err_counter(
3156             '/err/nat44-ed-out2in/drops due to TCP in transitory timeout')
3157         in2out_drops = self.get_err_counter(
3158             '/err/nat44-ed-in2out/drops due to TCP in transitory timeout')
3159
3160         # extra FIN packet out -> in - this should be dropped
3161         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
3162              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
3163              TCP(sport=ext_port, dport=out_port,
3164                  flags="FA", seq=300, ack=101))
3165
3166         self.pg1.add_stream(p)
3167         self.pg_enable_capture(self.pg_interfaces)
3168         self.pg_start()
3169         self.pg0.assert_nothing_captured()
3170
3171         # extra ACK packet in -> out - this should be dropped
3172         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
3173              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3174              TCP(sport=in_port, dport=ext_port,
3175                  flags="A", seq=101, ack=301))
3176         self.pg0.add_stream(p)
3177         self.pg_enable_capture(self.pg_interfaces)
3178         self.pg_start()
3179         self.pg1.assert_nothing_captured()
3180
3181         stats = self.get_err_counter(
3182             '/err/nat44-ed-out2in/drops due to TCP in transitory timeout')
3183         self.assertEqual(stats - out2in_drops, 1)
3184         stats = self.get_err_counter(
3185             '/err/nat44-ed-in2out/drops due to TCP in transitory timeout')
3186         self.assertEqual(stats - in2out_drops, 1)
3187
3188         self.sleep(3)
3189         # extra ACK packet in -> out - this will cause session to be wiped
3190         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
3191              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3192              TCP(sport=in_port, dport=ext_port,
3193                  flags="A", seq=101, ack=301))
3194         self.pg0.add_stream(p)
3195         self.pg_enable_capture(self.pg_interfaces)
3196         self.pg_start()
3197         self.pg1.assert_nothing_captured()
3198         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
3199         self.assertEqual(len(sessions) - session_n, 0)
3200
3201     def test_tcp_session_close_simultaneous(self):
3202         """ NAT44ED Close TCP session from inside network """
3203
3204         in_port = self.tcp_port_in
3205         ext_port = 10505
3206
3207         self.nat_add_address(self.nat_addr)
3208         self.nat_add_inside_interface(self.pg0)
3209         self.nat_add_outside_interface(self.pg1)
3210         self.nat_add_static_mapping(self.pg0.remote_ip4, self.nat_addr,
3211                                     in_port, ext_port, proto=IP_PROTOS.tcp,
3212                                     flags=self.config_flags.NAT_IS_TWICE_NAT)
3213
3214         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
3215         session_n = len(sessions)
3216
3217         self.vapi.nat_set_timeouts(udp=300, tcp_established=7440,
3218                                    tcp_transitory=2, icmp=5)
3219
3220         out_port = self.init_tcp_session(self.pg0, self.pg1, in_port, ext_port)
3221
3222         # FIN packet in -> out
3223         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
3224              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3225              TCP(sport=in_port, dport=ext_port,
3226                  flags="FA", seq=100, ack=300))
3227         self.pg0.add_stream(p)
3228         self.pg_enable_capture(self.pg_interfaces)
3229         self.pg_start()
3230         self.pg1.get_capture(1)
3231
3232         # FIN packet out -> in
3233         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
3234              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
3235              TCP(sport=ext_port, dport=out_port,
3236                  flags="FA", seq=300, ack=100))
3237         self.pg1.add_stream(p)
3238         self.pg_enable_capture(self.pg_interfaces)
3239         self.pg_start()
3240         self.pg0.get_capture(1)
3241
3242         # ACK packet in -> out
3243         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
3244              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3245              TCP(sport=in_port, dport=ext_port,
3246                  flags="A", seq=101, ack=301))
3247         self.pg0.add_stream(p)
3248         self.pg_enable_capture(self.pg_interfaces)
3249         self.pg_start()
3250         self.pg1.get_capture(1)
3251
3252         # ACK packet out -> in
3253         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
3254              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
3255              TCP(sport=ext_port, dport=out_port,
3256                  flags="A", seq=301, ack=101))
3257         self.pg1.add_stream(p)
3258         self.pg_enable_capture(self.pg_interfaces)
3259         self.pg_start()
3260         self.pg0.get_capture(1)
3261
3262         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
3263         self.assertEqual(len(sessions) - session_n, 1)
3264
3265         out2in_drops = self.get_err_counter(
3266             '/err/nat44-ed-out2in/drops due to TCP in transitory timeout')
3267         in2out_drops = self.get_err_counter(
3268             '/err/nat44-ed-in2out/drops due to TCP in transitory timeout')
3269
3270         # extra FIN packet out -> in - this should be dropped
3271         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
3272              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
3273              TCP(sport=ext_port, dport=out_port,
3274                  flags="FA", seq=300, ack=101))
3275
3276         self.pg1.add_stream(p)
3277         self.pg_enable_capture(self.pg_interfaces)
3278         self.pg_start()
3279         self.pg0.assert_nothing_captured()
3280
3281         # extra ACK packet in -> out - this should be dropped
3282         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
3283              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3284              TCP(sport=in_port, dport=ext_port,
3285                  flags="A", seq=101, ack=301))
3286         self.pg0.add_stream(p)
3287         self.pg_enable_capture(self.pg_interfaces)
3288         self.pg_start()
3289         self.pg1.assert_nothing_captured()
3290
3291         stats = self.get_err_counter(
3292             '/err/nat44-ed-out2in/drops due to TCP in transitory timeout')
3293         self.assertEqual(stats - out2in_drops, 1)
3294         stats = self.get_err_counter(
3295             '/err/nat44-ed-in2out/drops due to TCP in transitory timeout')
3296         self.assertEqual(stats - in2out_drops, 1)
3297
3298         self.sleep(3)
3299         # extra ACK packet in -> out - this will cause session to be wiped
3300         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
3301              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3302              TCP(sport=in_port, dport=ext_port,
3303                  flags="A", seq=101, ack=301))
3304         self.pg0.add_stream(p)
3305         self.pg_enable_capture(self.pg_interfaces)
3306         self.pg_start()
3307         self.pg1.assert_nothing_captured()
3308         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
3309         self.assertEqual(len(sessions) - session_n, 0)
3310
3311     def test_dynamic_output_feature_vrf(self):
3312         """ NAT44ED dynamic translation test: output-feature, VRF"""
3313
3314         # other then default (0)
3315         new_vrf_id = 22
3316
3317         self.nat_add_address(self.nat_addr)
3318         flags = self.config_flags.NAT_IS_INSIDE
3319         self.vapi.nat44_interface_add_del_output_feature(
3320             sw_if_index=self.pg7.sw_if_index,
3321             flags=flags, is_add=1)
3322         self.vapi.nat44_interface_add_del_output_feature(
3323             sw_if_index=self.pg8.sw_if_index,
3324             is_add=1)
3325
3326         try:
3327             self.configure_ip4_interface(self.pg7, table_id=new_vrf_id)
3328             self.configure_ip4_interface(self.pg8, table_id=new_vrf_id)
3329
3330             # in2out
3331             tcpn = self.get_stats_counter(
3332                 '/nat44/ed/in2out/slowpath/tcp')
3333             udpn = self.get_stats_counter(
3334                 '/nat44/ed/in2out/slowpath/udp')
3335             icmpn = self.get_stats_counter(
3336                 '/nat44/ed/in2out/slowpath/icmp')
3337             drops = self.get_stats_counter(
3338                 '/nat44/ed/in2out/slowpath/drops')
3339
3340             pkts = self.create_stream_in(self.pg7, self.pg8)
3341             self.pg7.add_stream(pkts)
3342             self.pg_enable_capture(self.pg_interfaces)
3343             self.pg_start()
3344             capture = self.pg8.get_capture(len(pkts))
3345             self.verify_capture_out(capture, ignore_port=True)
3346
3347             if_idx = self.pg7.sw_if_index
3348             cnt = self.get_stats_counter(
3349                 '/nat44/ed/in2out/slowpath/tcp')
3350             self.assertEqual(cnt[if_idx] - tcpn[if_idx], 2)
3351             cnt = self.get_stats_counter(
3352                 '/nat44/ed/in2out/slowpath/udp')
3353             self.assertEqual(cnt[if_idx] - udpn[if_idx], 1)
3354             cnt = self.get_stats_counter(
3355                 '/nat44/ed/in2out/slowpath/icmp')
3356             self.assertEqual(cnt[if_idx] - icmpn[if_idx], 1)
3357             cnt = self.get_stats_counter(
3358                 '/nat44/ed/in2out/slowpath/drops')
3359             self.assertEqual(cnt[if_idx] - drops[if_idx], 0)
3360
3361             # out2in
3362             tcpn = self.get_stats_counter(
3363                 '/nat44/ed/out2in/fastpath/tcp')
3364             udpn = self.get_stats_counter(
3365                 '/nat44/ed/out2in/fastpath/udp')
3366             icmpn = self.get_stats_counter(
3367                 '/nat44/ed/out2in/slowpath/icmp')
3368             drops = self.get_stats_counter(
3369                 '/nat44/ed/out2in/fastpath/drops')
3370
3371             pkts = self.create_stream_out(self.pg8)
3372             self.pg8.add_stream(pkts)
3373             self.pg_enable_capture(self.pg_interfaces)
3374             self.pg_start()
3375             capture = self.pg7.get_capture(len(pkts))
3376             self.verify_capture_in(capture, self.pg7)
3377
3378             if_idx = self.pg8.sw_if_index
3379             cnt = self.get_stats_counter(
3380                 '/nat44/ed/out2in/fastpath/tcp')
3381             self.assertEqual(cnt[if_idx] - tcpn[if_idx], 2)
3382             cnt = self.get_stats_counter(
3383                 '/nat44/ed/out2in/fastpath/udp')
3384             self.assertEqual(cnt[if_idx] - udpn[if_idx], 1)
3385             cnt = self.get_stats_counter(
3386                 '/nat44/ed/out2in/slowpath/icmp')
3387             self.assertEqual(cnt[if_idx] - icmpn[if_idx], 1)
3388             cnt = self.get_stats_counter(
3389                 '/nat44/ed/out2in/fastpath/drops')
3390             self.assertEqual(cnt[if_idx] - drops[if_idx], 0)
3391
3392             sessions = self.get_stats_counter('/nat44/total-sessions')
3393             self.assertEqual(sessions[0], 3)
3394
3395         finally:
3396             self.configure_ip4_interface(self.pg7, table_id=0)
3397             self.configure_ip4_interface(self.pg8, table_id=0)
3398
3399             self.vapi.ip_table_add_del(is_add=0,
3400                                        table={'table_id': new_vrf_id})
3401
3402     def test_next_src_nat(self):
3403         """ NAT44ED On way back forward packet to nat44-in2out node. """
3404
3405         twice_nat_addr = '10.0.1.3'
3406         external_port = 80
3407         local_port = 8080
3408         post_twice_nat_port = 0
3409
3410         self.vapi.nat44_forwarding_enable_disable(enable=1)
3411         self.nat_add_address(twice_nat_addr, twice_nat=1)
3412         flags = (self.config_flags.NAT_IS_OUT2IN_ONLY |
3413                  self.config_flags.NAT_IS_SELF_TWICE_NAT)
3414         self.nat_add_static_mapping(self.pg6.remote_ip4, self.pg1.remote_ip4,
3415                                     local_port, external_port,
3416                                     proto=IP_PROTOS.tcp, vrf_id=1,
3417                                     flags=flags)
3418         self.vapi.nat44_interface_add_del_feature(
3419             sw_if_index=self.pg6.sw_if_index,
3420             is_add=1)
3421
3422         p = (Ether(src=self.pg6.remote_mac, dst=self.pg6.local_mac) /
3423              IP(src=self.pg6.remote_ip4, dst=self.pg1.remote_ip4) /
3424              TCP(sport=12345, dport=external_port))
3425         self.pg6.add_stream(p)
3426         self.pg_enable_capture(self.pg_interfaces)
3427         self.pg_start()
3428         capture = self.pg6.get_capture(1)
3429         p = capture[0]
3430         try:
3431             ip = p[IP]
3432             tcp = p[TCP]
3433             self.assertEqual(ip.src, twice_nat_addr)
3434             self.assertNotEqual(tcp.sport, 12345)
3435             post_twice_nat_port = tcp.sport
3436             self.assertEqual(ip.dst, self.pg6.remote_ip4)
3437             self.assertEqual(tcp.dport, local_port)
3438             self.assert_packet_checksums_valid(p)
3439         except:
3440             self.logger.error(ppp("Unexpected or invalid packet:", p))
3441             raise
3442
3443         p = (Ether(src=self.pg6.remote_mac, dst=self.pg6.local_mac) /
3444              IP(src=self.pg6.remote_ip4, dst=twice_nat_addr) /
3445              TCP(sport=local_port, dport=post_twice_nat_port))
3446         self.pg6.add_stream(p)
3447         self.pg_enable_capture(self.pg_interfaces)
3448         self.pg_start()
3449         capture = self.pg6.get_capture(1)
3450         p = capture[0]
3451         try:
3452             ip = p[IP]
3453             tcp = p[TCP]
3454             self.assertEqual(ip.src, self.pg1.remote_ip4)
3455             self.assertEqual(tcp.sport, external_port)
3456             self.assertEqual(ip.dst, self.pg6.remote_ip4)
3457             self.assertEqual(tcp.dport, 12345)
3458             self.assert_packet_checksums_valid(p)
3459         except:
3460             self.logger.error(ppp("Unexpected or invalid packet:", p))
3461             raise
3462
3463     def test_one_armed_nat44_static(self):
3464         """ NAT44ED One armed NAT and 1:1 NAPT asymmetrical rule """
3465
3466         remote_host = self.pg4.remote_hosts[0]
3467         local_host = self.pg4.remote_hosts[1]
3468         external_port = 80
3469         local_port = 8080
3470         eh_port_in = 0
3471
3472         self.vapi.nat44_forwarding_enable_disable(enable=1)
3473         self.nat_add_address(self.nat_addr, twice_nat=1)
3474         flags = (self.config_flags.NAT_IS_OUT2IN_ONLY |
3475                  self.config_flags.NAT_IS_TWICE_NAT)
3476         self.nat_add_static_mapping(local_host.ip4, self.nat_addr,
3477                                     local_port, external_port,
3478                                     proto=IP_PROTOS.tcp, flags=flags)
3479         flags = self.config_flags.NAT_IS_INSIDE
3480         self.vapi.nat44_interface_add_del_feature(
3481             sw_if_index=self.pg4.sw_if_index,
3482             is_add=1)
3483         self.vapi.nat44_interface_add_del_feature(
3484             sw_if_index=self.pg4.sw_if_index,
3485             flags=flags, is_add=1)
3486
3487         # from client to service
3488         p = (Ether(src=self.pg4.remote_mac, dst=self.pg4.local_mac) /
3489              IP(src=remote_host.ip4, dst=self.nat_addr) /
3490              TCP(sport=12345, dport=external_port))
3491         self.pg4.add_stream(p)
3492         self.pg_enable_capture(self.pg_interfaces)
3493         self.pg_start()
3494         capture = self.pg4.get_capture(1)
3495         p = capture[0]
3496         try:
3497             ip = p[IP]
3498             tcp = p[TCP]
3499             self.assertEqual(ip.dst, local_host.ip4)
3500             self.assertEqual(ip.src, self.nat_addr)
3501             self.assertEqual(tcp.dport, local_port)
3502             self.assertNotEqual(tcp.sport, 12345)
3503             eh_port_in = tcp.sport
3504             self.assert_packet_checksums_valid(p)
3505         except:
3506             self.logger.error(ppp("Unexpected or invalid packet:", p))
3507             raise
3508
3509         # from service back to client
3510         p = (Ether(src=self.pg4.remote_mac, dst=self.pg4.local_mac) /
3511              IP(src=local_host.ip4, dst=self.nat_addr) /
3512              TCP(sport=local_port, dport=eh_port_in))
3513         self.pg4.add_stream(p)
3514         self.pg_enable_capture(self.pg_interfaces)
3515         self.pg_start()
3516         capture = self.pg4.get_capture(1)
3517         p = capture[0]
3518         try:
3519             ip = p[IP]
3520             tcp = p[TCP]
3521             self.assertEqual(ip.src, self.nat_addr)
3522             self.assertEqual(ip.dst, remote_host.ip4)
3523             self.assertEqual(tcp.sport, external_port)
3524             self.assertEqual(tcp.dport, 12345)
3525             self.assert_packet_checksums_valid(p)
3526         except:
3527             self.logger.error(ppp("Unexpected or invalid packet:", p))
3528             raise
3529
3530
3531 if __name__ == '__main__':
3532     unittest.main(testRunner=VppTestRunner)