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