2fa70fa8957ceaf73e7bcfaab749ac4bcaf8f555
[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, 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
951         self.pg0.add_stream(p1)
952         self.pg_enable_capture(self.pg_interfaces)
953         self.pg_start()
954         capture = self.pg1.get_capture(1)[0]
955
956         # out2in (send error message)
957         p2 = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
958               IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
959               ICMP(type='dest-unreach', code='port-unreachable') /
960               capture[IP:])
961
962         self.pg1.add_stream(p2)
963         self.pg_enable_capture(self.pg_interfaces)
964         self.pg_start()
965
966         capture = self.pg0.get_capture(1)[0]
967
968         self.logger.info(ppp("p1 packet:", p1))
969         self.logger.info(ppp("p2 packet:", p2))
970         self.logger.info(ppp("capture packet:", capture))
971
972     def test_icmp_echo_reply_trailer(self):
973         """ ICMP echo reply with ethernet trailer"""
974
975         self.nat_add_address(self.nat_addr)
976         self.nat_add_inside_interface(self.pg0)
977         self.nat_add_outside_interface(self.pg1)
978
979         # in2out
980         p1 = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
981               IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
982               ICMP(type=8, id=0xabcd, seq=0))
983
984         self.pg0.add_stream(p1)
985         self.pg_enable_capture(self.pg_interfaces)
986         self.pg_start()
987         c = self.pg1.get_capture(1)[0]
988
989         self.logger.debug(self.vapi.cli("show trace"))
990
991         # out2in
992         p2 = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
993               IP(src=self.pg1.remote_ip4, dst=self.nat_addr, id=0xee59) /
994               ICMP(type=0, id=c[ICMP].id, seq=0))
995
996         # force checksum calculation
997         p2 = p2.__class__(bytes(p2))
998
999         self.logger.debug(ppp("Packet before modification:", p2))
1000
1001         # hex representation of vss monitoring ethernet trailer
1002         # this seems to be just added to end of packet without modifying
1003         # IP or ICMP lengths / checksums
1004         p2 = p2 / Raw("\x00\x00\x52\x54\x00\x46\xab\x04\x84\x18")
1005         # change it so that IP/ICMP is unaffected
1006         p2[IP].len = 28
1007
1008         self.logger.debug(ppp("Packet with added trailer:", p2))
1009
1010         self.pg1.add_stream(p2)
1011         self.pg_enable_capture(self.pg_interfaces)
1012         self.pg_start()
1013
1014         self.pg0.get_capture(1)
1015
1016     def test_users_dump(self):
1017         """ NAT44ED API test - nat44_user_dump """
1018
1019         self.nat_add_address(self.nat_addr)
1020         self.nat_add_inside_interface(self.pg0)
1021         self.nat_add_outside_interface(self.pg1)
1022
1023         self.vapi.nat44_forwarding_enable_disable(enable=1)
1024
1025         local_ip = self.pg0.remote_ip4
1026         external_ip = self.nat_addr
1027         self.nat_add_static_mapping(local_ip, external_ip)
1028
1029         users = self.vapi.nat44_user_dump()
1030         self.assertEqual(len(users), 0)
1031
1032         # in2out - static mapping match
1033
1034         pkts = self.create_stream_out(self.pg1)
1035         self.pg1.add_stream(pkts)
1036         self.pg_enable_capture(self.pg_interfaces)
1037         self.pg_start()
1038         capture = self.pg0.get_capture(len(pkts))
1039         self.verify_capture_in(capture, self.pg0)
1040
1041         pkts = self.create_stream_in(self.pg0, self.pg1)
1042         self.pg0.add_stream(pkts)
1043         self.pg_enable_capture(self.pg_interfaces)
1044         self.pg_start()
1045         capture = self.pg1.get_capture(len(pkts))
1046         self.verify_capture_out(capture, same_port=True)
1047
1048         users = self.vapi.nat44_user_dump()
1049         self.assertEqual(len(users), 1)
1050         static_user = users[0]
1051         self.assertEqual(static_user.nstaticsessions, 3)
1052         self.assertEqual(static_user.nsessions, 0)
1053
1054         # in2out - no static mapping match (forwarding test)
1055
1056         host0 = self.pg0.remote_hosts[0]
1057         self.pg0.remote_hosts[0] = self.pg0.remote_hosts[1]
1058         try:
1059             pkts = self.create_stream_out(self.pg1,
1060                                           dst_ip=self.pg0.remote_ip4,
1061                                           use_inside_ports=True)
1062             self.pg1.add_stream(pkts)
1063             self.pg_enable_capture(self.pg_interfaces)
1064             self.pg_start()
1065             capture = self.pg0.get_capture(len(pkts))
1066             self.verify_capture_in(capture, self.pg0)
1067
1068             pkts = self.create_stream_in(self.pg0, self.pg1)
1069             self.pg0.add_stream(pkts)
1070             self.pg_enable_capture(self.pg_interfaces)
1071             self.pg_start()
1072             capture = self.pg1.get_capture(len(pkts))
1073             self.verify_capture_out(capture, nat_ip=self.pg0.remote_ip4,
1074                                     same_port=True)
1075         finally:
1076             self.pg0.remote_hosts[0] = host0
1077
1078         users = self.vapi.nat44_user_dump()
1079         self.assertEqual(len(users), 2)
1080         if str(users[0].ip_address) == self.pg0.remote_hosts[0].ip4:
1081             non_static_user = users[1]
1082             static_user = users[0]
1083         else:
1084             non_static_user = users[0]
1085             static_user = users[1]
1086         self.assertEqual(static_user.nstaticsessions, 3)
1087         self.assertEqual(static_user.nsessions, 0)
1088         self.assertEqual(non_static_user.nstaticsessions, 0)
1089         self.assertEqual(non_static_user.nsessions, 3)
1090
1091         users = self.vapi.nat44_user_dump()
1092         self.assertEqual(len(users), 2)
1093         if str(users[0].ip_address) == self.pg0.remote_hosts[0].ip4:
1094             non_static_user = users[1]
1095             static_user = users[0]
1096         else:
1097             non_static_user = users[0]
1098             static_user = users[1]
1099         self.assertEqual(static_user.nstaticsessions, 3)
1100         self.assertEqual(static_user.nsessions, 0)
1101         self.assertEqual(non_static_user.nstaticsessions, 0)
1102         self.assertEqual(non_static_user.nsessions, 3)
1103
1104     def test_frag_out_of_order_do_not_translate(self):
1105         """ NAT44ED don't translate fragments arriving out of order """
1106         self.nat_add_inside_interface(self.pg0)
1107         self.nat_add_outside_interface(self.pg1)
1108         self.vapi.nat44_forwarding_enable_disable(enable=True)
1109         self.frag_out_of_order(proto=IP_PROTOS.tcp, dont_translate=True)
1110
1111     def test_forwarding(self):
1112         """ NAT44ED forwarding test """
1113
1114         self.nat_add_inside_interface(self.pg0)
1115         self.nat_add_outside_interface(self.pg1)
1116         self.vapi.nat44_forwarding_enable_disable(enable=1)
1117
1118         real_ip = self.pg0.remote_ip4
1119         alias_ip = self.nat_addr
1120         flags = self.config_flags.NAT_IS_ADDR_ONLY
1121         self.vapi.nat44_add_del_static_mapping(is_add=1,
1122                                                local_ip_address=real_ip,
1123                                                external_ip_address=alias_ip,
1124                                                external_sw_if_index=0xFFFFFFFF,
1125                                                flags=flags)
1126
1127         try:
1128             # in2out - static mapping match
1129
1130             pkts = self.create_stream_out(self.pg1)
1131             self.pg1.add_stream(pkts)
1132             self.pg_enable_capture(self.pg_interfaces)
1133             self.pg_start()
1134             capture = self.pg0.get_capture(len(pkts))
1135             self.verify_capture_in(capture, self.pg0)
1136
1137             pkts = self.create_stream_in(self.pg0, self.pg1)
1138             self.pg0.add_stream(pkts)
1139             self.pg_enable_capture(self.pg_interfaces)
1140             self.pg_start()
1141             capture = self.pg1.get_capture(len(pkts))
1142             self.verify_capture_out(capture, same_port=True)
1143
1144             # in2out - no static mapping match
1145
1146             host0 = self.pg0.remote_hosts[0]
1147             self.pg0.remote_hosts[0] = self.pg0.remote_hosts[1]
1148             try:
1149                 pkts = self.create_stream_out(self.pg1,
1150                                               dst_ip=self.pg0.remote_ip4,
1151                                               use_inside_ports=True)
1152                 self.pg1.add_stream(pkts)
1153                 self.pg_enable_capture(self.pg_interfaces)
1154                 self.pg_start()
1155                 capture = self.pg0.get_capture(len(pkts))
1156                 self.verify_capture_in(capture, self.pg0)
1157
1158                 pkts = self.create_stream_in(self.pg0, self.pg1)
1159                 self.pg0.add_stream(pkts)
1160                 self.pg_enable_capture(self.pg_interfaces)
1161                 self.pg_start()
1162                 capture = self.pg1.get_capture(len(pkts))
1163                 self.verify_capture_out(capture, nat_ip=self.pg0.remote_ip4,
1164                                         same_port=True)
1165             finally:
1166                 self.pg0.remote_hosts[0] = host0
1167
1168             user = self.pg0.remote_hosts[1]
1169             sessions = self.vapi.nat44_user_session_dump(user.ip4, 0)
1170             self.assertEqual(len(sessions), 3)
1171             self.assertTrue(sessions[0].flags &
1172                             self.config_flags.NAT_IS_EXT_HOST_VALID)
1173             self.vapi.nat44_del_session(
1174                 address=sessions[0].inside_ip_address,
1175                 port=sessions[0].inside_port,
1176                 protocol=sessions[0].protocol,
1177                 flags=(self.config_flags.NAT_IS_INSIDE |
1178                        self.config_flags.NAT_IS_EXT_HOST_VALID),
1179                 ext_host_address=sessions[0].ext_host_address,
1180                 ext_host_port=sessions[0].ext_host_port)
1181             sessions = self.vapi.nat44_user_session_dump(user.ip4, 0)
1182             self.assertEqual(len(sessions), 2)
1183
1184         finally:
1185             self.vapi.nat44_forwarding_enable_disable(enable=0)
1186             flags = self.config_flags.NAT_IS_ADDR_ONLY
1187             self.vapi.nat44_add_del_static_mapping(
1188                 is_add=0,
1189                 local_ip_address=real_ip,
1190                 external_ip_address=alias_ip,
1191                 external_sw_if_index=0xFFFFFFFF,
1192                 flags=flags)
1193
1194     def test_output_feature_and_service2(self):
1195         """ NAT44ED interface output feature and service host direct access """
1196         self.vapi.nat44_forwarding_enable_disable(enable=1)
1197         self.nat_add_address(self.nat_addr)
1198
1199         self.vapi.nat44_interface_add_del_output_feature(
1200             sw_if_index=self.pg1.sw_if_index, is_add=1,)
1201
1202         # session initiated from service host - translate
1203         pkts = self.create_stream_in(self.pg0, self.pg1)
1204         self.pg0.add_stream(pkts)
1205         self.pg_enable_capture(self.pg_interfaces)
1206         self.pg_start()
1207         capture = self.pg1.get_capture(len(pkts))
1208         self.verify_capture_out(capture, ignore_port=True)
1209
1210         pkts = self.create_stream_out(self.pg1)
1211         self.pg1.add_stream(pkts)
1212         self.pg_enable_capture(self.pg_interfaces)
1213         self.pg_start()
1214         capture = self.pg0.get_capture(len(pkts))
1215         self.verify_capture_in(capture, self.pg0)
1216
1217         # session initiated from remote host - do not translate
1218         tcp_port_in = self.tcp_port_in
1219         udp_port_in = self.udp_port_in
1220         icmp_id_in = self.icmp_id_in
1221
1222         self.tcp_port_in = 60303
1223         self.udp_port_in = 60304
1224         self.icmp_id_in = 60305
1225
1226         try:
1227             pkts = self.create_stream_out(self.pg1,
1228                                           self.pg0.remote_ip4,
1229                                           use_inside_ports=True)
1230             self.pg1.add_stream(pkts)
1231             self.pg_enable_capture(self.pg_interfaces)
1232             self.pg_start()
1233             capture = self.pg0.get_capture(len(pkts))
1234             self.verify_capture_in(capture, self.pg0)
1235
1236             pkts = self.create_stream_in(self.pg0, self.pg1)
1237             self.pg0.add_stream(pkts)
1238             self.pg_enable_capture(self.pg_interfaces)
1239             self.pg_start()
1240             capture = self.pg1.get_capture(len(pkts))
1241             self.verify_capture_out(capture, nat_ip=self.pg0.remote_ip4,
1242                                     same_port=True)
1243         finally:
1244             self.tcp_port_in = tcp_port_in
1245             self.udp_port_in = udp_port_in
1246             self.icmp_id_in = icmp_id_in
1247
1248     def test_twice_nat(self):
1249         """ NAT44ED Twice NAT """
1250         self.twice_nat_common()
1251
1252     def test_self_twice_nat_positive(self):
1253         """ NAT44ED Self Twice NAT (positive test) """
1254         self.twice_nat_common(self_twice_nat=True, same_pg=True)
1255
1256     def test_self_twice_nat_lb_positive(self):
1257         """ NAT44ED Self Twice NAT local service load balancing (positive test)
1258         """
1259         self.twice_nat_common(lb=True, self_twice_nat=True, same_pg=True,
1260                               client_id=1)
1261
1262     def test_twice_nat_lb(self):
1263         """ NAT44ED Twice NAT local service load balancing """
1264         self.twice_nat_common(lb=True)
1265
1266     def test_output_feature(self):
1267         """ NAT44ED interface output feature (in2out postrouting) """
1268         self.vapi.nat44_forwarding_enable_disable(enable=1)
1269         self.nat_add_address(self.nat_addr)
1270
1271         self.nat_add_outside_interface(self.pg0)
1272         self.vapi.nat44_interface_add_del_output_feature(
1273             sw_if_index=self.pg1.sw_if_index, is_add=1)
1274
1275         # in2out
1276         pkts = self.create_stream_in(self.pg0, self.pg1)
1277         self.pg0.add_stream(pkts)
1278         self.pg_enable_capture(self.pg_interfaces)
1279         self.pg_start()
1280         capture = self.pg1.get_capture(len(pkts))
1281         self.verify_capture_out(capture, ignore_port=True)
1282         self.logger.debug(self.vapi.cli("show trace"))
1283
1284         # out2in
1285         pkts = self.create_stream_out(self.pg1)
1286         self.pg1.add_stream(pkts)
1287         self.pg_enable_capture(self.pg_interfaces)
1288         self.pg_start()
1289         capture = self.pg0.get_capture(len(pkts))
1290         self.verify_capture_in(capture, self.pg0)
1291         self.logger.debug(self.vapi.cli("show trace"))
1292
1293         # in2out
1294         pkts = self.create_stream_in(self.pg0, self.pg1, ttl=2)
1295         self.pg0.add_stream(pkts)
1296         self.pg_enable_capture(self.pg_interfaces)
1297         self.pg_start()
1298         capture = self.pg1.get_capture(len(pkts))
1299         self.verify_capture_out(capture, ignore_port=True)
1300         self.logger.debug(self.vapi.cli("show trace"))
1301
1302         # out2in
1303         pkts = self.create_stream_out(self.pg1, ttl=2)
1304         self.pg1.add_stream(pkts)
1305         self.pg_enable_capture(self.pg_interfaces)
1306         self.pg_start()
1307         capture = self.pg0.get_capture(len(pkts))
1308         self.verify_capture_in(capture, self.pg0)
1309         self.logger.debug(self.vapi.cli("show trace"))
1310
1311         # in2out
1312         pkts = self.create_stream_in(self.pg0, self.pg1, ttl=1)
1313         capture = self.send_and_expect_some(self.pg0, pkts, self.pg0)
1314         for p in capture:
1315             self.assertIn(ICMP, p)
1316             self.assertEqual(p[ICMP].type, 11)  # 11 == time-exceeded
1317
1318     def test_static_with_port_out2(self):
1319         """ NAT44ED 1:1 NAPT asymmetrical rule """
1320
1321         external_port = 80
1322         local_port = 8080
1323
1324         self.vapi.nat44_forwarding_enable_disable(enable=1)
1325         flags = self.config_flags.NAT_IS_OUT2IN_ONLY
1326         self.nat_add_static_mapping(self.pg0.remote_ip4, self.nat_addr,
1327                                     local_port, external_port,
1328                                     proto=IP_PROTOS.tcp, flags=flags)
1329
1330         self.nat_add_inside_interface(self.pg0)
1331         self.nat_add_outside_interface(self.pg1)
1332
1333         # from client to service
1334         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
1335              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
1336              TCP(sport=12345, dport=external_port))
1337         self.pg1.add_stream(p)
1338         self.pg_enable_capture(self.pg_interfaces)
1339         self.pg_start()
1340         capture = self.pg0.get_capture(1)
1341         p = capture[0]
1342         try:
1343             ip = p[IP]
1344             tcp = p[TCP]
1345             self.assertEqual(ip.dst, self.pg0.remote_ip4)
1346             self.assertEqual(tcp.dport, local_port)
1347             self.assert_packet_checksums_valid(p)
1348         except:
1349             self.logger.error(ppp("Unexpected or invalid packet:", p))
1350             raise
1351
1352         # ICMP error
1353         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
1354              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
1355              ICMP(type=11) / capture[0][IP])
1356         self.pg0.add_stream(p)
1357         self.pg_enable_capture(self.pg_interfaces)
1358         self.pg_start()
1359         capture = self.pg1.get_capture(1)
1360         p = capture[0]
1361         try:
1362             self.assertEqual(p[IP].src, self.nat_addr)
1363             inner = p[IPerror]
1364             self.assertEqual(inner.dst, self.nat_addr)
1365             self.assertEqual(inner[TCPerror].dport, external_port)
1366         except:
1367             self.logger.error(ppp("Unexpected or invalid packet:", p))
1368             raise
1369
1370         # from service back to client
1371         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
1372              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
1373              TCP(sport=local_port, dport=12345))
1374         self.pg0.add_stream(p)
1375         self.pg_enable_capture(self.pg_interfaces)
1376         self.pg_start()
1377         capture = self.pg1.get_capture(1)
1378         p = capture[0]
1379         try:
1380             ip = p[IP]
1381             tcp = p[TCP]
1382             self.assertEqual(ip.src, self.nat_addr)
1383             self.assertEqual(tcp.sport, external_port)
1384             self.assert_packet_checksums_valid(p)
1385         except:
1386             self.logger.error(ppp("Unexpected or invalid packet:", p))
1387             raise
1388
1389         # ICMP error
1390         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
1391              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
1392              ICMP(type=11) / capture[0][IP])
1393         self.pg1.add_stream(p)
1394         self.pg_enable_capture(self.pg_interfaces)
1395         self.pg_start()
1396         capture = self.pg0.get_capture(1)
1397         p = capture[0]
1398         try:
1399             self.assertEqual(p[IP].dst, self.pg0.remote_ip4)
1400             inner = p[IPerror]
1401             self.assertEqual(inner.src, self.pg0.remote_ip4)
1402             self.assertEqual(inner[TCPerror].sport, local_port)
1403         except:
1404             self.logger.error(ppp("Unexpected or invalid packet:", p))
1405             raise
1406
1407         # from client to server (no translation)
1408         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
1409              IP(src=self.pg1.remote_ip4, dst=self.pg0.remote_ip4) /
1410              TCP(sport=12346, dport=local_port))
1411         self.pg1.add_stream(p)
1412         self.pg_enable_capture(self.pg_interfaces)
1413         self.pg_start()
1414         capture = self.pg0.get_capture(1)
1415         p = capture[0]
1416         try:
1417             ip = p[IP]
1418             tcp = p[TCP]
1419             self.assertEqual(ip.dst, self.pg0.remote_ip4)
1420             self.assertEqual(tcp.dport, local_port)
1421             self.assert_packet_checksums_valid(p)
1422         except:
1423             self.logger.error(ppp("Unexpected or invalid packet:", p))
1424             raise
1425
1426         # from service back to client (no translation)
1427         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
1428              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
1429              TCP(sport=local_port, dport=12346))
1430         self.pg0.add_stream(p)
1431         self.pg_enable_capture(self.pg_interfaces)
1432         self.pg_start()
1433         capture = self.pg1.get_capture(1)
1434         p = capture[0]
1435         try:
1436             ip = p[IP]
1437             tcp = p[TCP]
1438             self.assertEqual(ip.src, self.pg0.remote_ip4)
1439             self.assertEqual(tcp.sport, local_port)
1440             self.assert_packet_checksums_valid(p)
1441         except:
1442             self.logger.error(ppp("Unexpected or invalid packet:", p))
1443             raise
1444
1445     def test_static_lb(self):
1446         """ NAT44ED local service load balancing """
1447         external_addr_n = self.nat_addr
1448         external_port = 80
1449         local_port = 8080
1450         server1 = self.pg0.remote_hosts[0]
1451         server2 = self.pg0.remote_hosts[1]
1452
1453         locals = [{'addr': server1.ip4,
1454                    'port': local_port,
1455                    'probability': 70,
1456                    'vrf_id': 0},
1457                   {'addr': server2.ip4,
1458                    'port': local_port,
1459                    'probability': 30,
1460                    'vrf_id': 0}]
1461
1462         self.nat_add_address(self.nat_addr)
1463         self.vapi.nat44_add_del_lb_static_mapping(
1464             is_add=1,
1465             external_addr=external_addr_n,
1466             external_port=external_port,
1467             protocol=IP_PROTOS.tcp,
1468             local_num=len(locals),
1469             locals=locals)
1470         flags = self.config_flags.NAT_IS_INSIDE
1471         self.vapi.nat44_interface_add_del_feature(
1472             sw_if_index=self.pg0.sw_if_index,
1473             flags=flags, is_add=1)
1474         self.vapi.nat44_interface_add_del_feature(
1475             sw_if_index=self.pg1.sw_if_index,
1476             is_add=1)
1477
1478         # from client to service
1479         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
1480              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
1481              TCP(sport=12345, dport=external_port))
1482         self.pg1.add_stream(p)
1483         self.pg_enable_capture(self.pg_interfaces)
1484         self.pg_start()
1485         capture = self.pg0.get_capture(1)
1486         p = capture[0]
1487         server = None
1488         try:
1489             ip = p[IP]
1490             tcp = p[TCP]
1491             self.assertIn(ip.dst, [server1.ip4, server2.ip4])
1492             if ip.dst == server1.ip4:
1493                 server = server1
1494             else:
1495                 server = server2
1496             self.assertEqual(tcp.dport, local_port)
1497             self.assert_packet_checksums_valid(p)
1498         except:
1499             self.logger.error(ppp("Unexpected or invalid packet:", p))
1500             raise
1501
1502         # from service back to client
1503         p = (Ether(src=server.mac, dst=self.pg0.local_mac) /
1504              IP(src=server.ip4, dst=self.pg1.remote_ip4) /
1505              TCP(sport=local_port, dport=12345))
1506         self.pg0.add_stream(p)
1507         self.pg_enable_capture(self.pg_interfaces)
1508         self.pg_start()
1509         capture = self.pg1.get_capture(1)
1510         p = capture[0]
1511         try:
1512             ip = p[IP]
1513             tcp = p[TCP]
1514             self.assertEqual(ip.src, self.nat_addr)
1515             self.assertEqual(tcp.sport, external_port)
1516             self.assert_packet_checksums_valid(p)
1517         except:
1518             self.logger.error(ppp("Unexpected or invalid packet:", p))
1519             raise
1520
1521         sessions = self.vapi.nat44_user_session_dump(server.ip4, 0)
1522         self.assertEqual(len(sessions), 1)
1523         self.assertTrue(sessions[0].flags &
1524                         self.config_flags.NAT_IS_EXT_HOST_VALID)
1525         self.vapi.nat44_del_session(
1526             address=sessions[0].inside_ip_address,
1527             port=sessions[0].inside_port,
1528             protocol=sessions[0].protocol,
1529             flags=(self.config_flags.NAT_IS_INSIDE |
1530                    self.config_flags.NAT_IS_EXT_HOST_VALID),
1531             ext_host_address=sessions[0].ext_host_address,
1532             ext_host_port=sessions[0].ext_host_port)
1533         sessions = self.vapi.nat44_user_session_dump(server.ip4, 0)
1534         self.assertEqual(len(sessions), 0)
1535
1536     def test_static_lb_2(self):
1537         """ NAT44ED local service load balancing (asymmetrical rule) """
1538         external_addr = self.nat_addr
1539         external_port = 80
1540         local_port = 8080
1541         server1 = self.pg0.remote_hosts[0]
1542         server2 = self.pg0.remote_hosts[1]
1543
1544         locals = [{'addr': server1.ip4,
1545                    'port': local_port,
1546                    'probability': 70,
1547                    'vrf_id': 0},
1548                   {'addr': server2.ip4,
1549                    'port': local_port,
1550                    'probability': 30,
1551                    'vrf_id': 0}]
1552
1553         self.vapi.nat44_forwarding_enable_disable(enable=1)
1554         flags = self.config_flags.NAT_IS_OUT2IN_ONLY
1555         self.vapi.nat44_add_del_lb_static_mapping(is_add=1, flags=flags,
1556                                                   external_addr=external_addr,
1557                                                   external_port=external_port,
1558                                                   protocol=IP_PROTOS.tcp,
1559                                                   local_num=len(locals),
1560                                                   locals=locals)
1561         flags = self.config_flags.NAT_IS_INSIDE
1562         self.vapi.nat44_interface_add_del_feature(
1563             sw_if_index=self.pg0.sw_if_index,
1564             flags=flags, is_add=1)
1565         self.vapi.nat44_interface_add_del_feature(
1566             sw_if_index=self.pg1.sw_if_index,
1567             is_add=1)
1568
1569         # from client to service
1570         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
1571              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
1572              TCP(sport=12345, dport=external_port))
1573         self.pg1.add_stream(p)
1574         self.pg_enable_capture(self.pg_interfaces)
1575         self.pg_start()
1576         capture = self.pg0.get_capture(1)
1577         p = capture[0]
1578         server = None
1579         try:
1580             ip = p[IP]
1581             tcp = p[TCP]
1582             self.assertIn(ip.dst, [server1.ip4, server2.ip4])
1583             if ip.dst == server1.ip4:
1584                 server = server1
1585             else:
1586                 server = server2
1587             self.assertEqual(tcp.dport, local_port)
1588             self.assert_packet_checksums_valid(p)
1589         except:
1590             self.logger.error(ppp("Unexpected or invalid packet:", p))
1591             raise
1592
1593         # from service back to client
1594         p = (Ether(src=server.mac, dst=self.pg0.local_mac) /
1595              IP(src=server.ip4, dst=self.pg1.remote_ip4) /
1596              TCP(sport=local_port, dport=12345))
1597         self.pg0.add_stream(p)
1598         self.pg_enable_capture(self.pg_interfaces)
1599         self.pg_start()
1600         capture = self.pg1.get_capture(1)
1601         p = capture[0]
1602         try:
1603             ip = p[IP]
1604             tcp = p[TCP]
1605             self.assertEqual(ip.src, self.nat_addr)
1606             self.assertEqual(tcp.sport, external_port)
1607             self.assert_packet_checksums_valid(p)
1608         except:
1609             self.logger.error(ppp("Unexpected or invalid packet:", p))
1610             raise
1611
1612         # from client to server (no translation)
1613         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
1614              IP(src=self.pg1.remote_ip4, dst=server1.ip4) /
1615              TCP(sport=12346, dport=local_port))
1616         self.pg1.add_stream(p)
1617         self.pg_enable_capture(self.pg_interfaces)
1618         self.pg_start()
1619         capture = self.pg0.get_capture(1)
1620         p = capture[0]
1621         server = None
1622         try:
1623             ip = p[IP]
1624             tcp = p[TCP]
1625             self.assertEqual(ip.dst, server1.ip4)
1626             self.assertEqual(tcp.dport, local_port)
1627             self.assert_packet_checksums_valid(p)
1628         except:
1629             self.logger.error(ppp("Unexpected or invalid packet:", p))
1630             raise
1631
1632         # from service back to client (no translation)
1633         p = (Ether(src=server1.mac, dst=self.pg0.local_mac) /
1634              IP(src=server1.ip4, dst=self.pg1.remote_ip4) /
1635              TCP(sport=local_port, dport=12346))
1636         self.pg0.add_stream(p)
1637         self.pg_enable_capture(self.pg_interfaces)
1638         self.pg_start()
1639         capture = self.pg1.get_capture(1)
1640         p = capture[0]
1641         try:
1642             ip = p[IP]
1643             tcp = p[TCP]
1644             self.assertEqual(ip.src, server1.ip4)
1645             self.assertEqual(tcp.sport, local_port)
1646             self.assert_packet_checksums_valid(p)
1647         except:
1648             self.logger.error(ppp("Unexpected or invalid packet:", p))
1649             raise
1650
1651     def test_lb_affinity(self):
1652         """ NAT44ED local service load balancing affinity """
1653         external_addr = self.nat_addr
1654         external_port = 80
1655         local_port = 8080
1656         server1 = self.pg0.remote_hosts[0]
1657         server2 = self.pg0.remote_hosts[1]
1658
1659         locals = [{'addr': server1.ip4,
1660                    'port': local_port,
1661                    'probability': 50,
1662                    'vrf_id': 0},
1663                   {'addr': server2.ip4,
1664                    'port': local_port,
1665                    'probability': 50,
1666                    'vrf_id': 0}]
1667
1668         self.nat_add_address(self.nat_addr)
1669         self.vapi.nat44_add_del_lb_static_mapping(is_add=1,
1670                                                   external_addr=external_addr,
1671                                                   external_port=external_port,
1672                                                   protocol=IP_PROTOS.tcp,
1673                                                   affinity=10800,
1674                                                   local_num=len(locals),
1675                                                   locals=locals)
1676         flags = self.config_flags.NAT_IS_INSIDE
1677         self.vapi.nat44_interface_add_del_feature(
1678             sw_if_index=self.pg0.sw_if_index,
1679             flags=flags, is_add=1)
1680         self.vapi.nat44_interface_add_del_feature(
1681             sw_if_index=self.pg1.sw_if_index,
1682             is_add=1)
1683
1684         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
1685              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
1686              TCP(sport=1025, dport=external_port))
1687         self.pg1.add_stream(p)
1688         self.pg_enable_capture(self.pg_interfaces)
1689         self.pg_start()
1690         capture = self.pg0.get_capture(1)
1691         backend = capture[0][IP].dst
1692
1693         sessions = self.vapi.nat44_user_session_dump(backend, 0)
1694         self.assertEqual(len(sessions), 1)
1695         self.assertTrue(sessions[0].flags &
1696                         self.config_flags.NAT_IS_EXT_HOST_VALID)
1697         self.vapi.nat44_del_session(
1698             address=sessions[0].inside_ip_address,
1699             port=sessions[0].inside_port,
1700             protocol=sessions[0].protocol,
1701             flags=(self.config_flags.NAT_IS_INSIDE |
1702                    self.config_flags.NAT_IS_EXT_HOST_VALID),
1703             ext_host_address=sessions[0].ext_host_address,
1704             ext_host_port=sessions[0].ext_host_port)
1705
1706         pkts = []
1707         for port in range(1030, 1100):
1708             p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
1709                  IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
1710                  TCP(sport=port, dport=external_port))
1711             pkts.append(p)
1712         self.pg1.add_stream(pkts)
1713         self.pg_enable_capture(self.pg_interfaces)
1714         self.pg_start()
1715         capture = self.pg0.get_capture(len(pkts))
1716         for p in capture:
1717             self.assertEqual(p[IP].dst, backend)
1718
1719     def test_multiple_vrf_1(self):
1720         """ Multiple VRF - both client & service in VRF1 """
1721
1722         external_addr = '1.2.3.4'
1723         external_port = 80
1724         local_port = 8080
1725         port = 0
1726
1727         flags = self.config_flags.NAT_IS_INSIDE
1728         self.vapi.nat44_interface_add_del_feature(
1729             sw_if_index=self.pg5.sw_if_index,
1730             is_add=1)
1731         self.vapi.nat44_interface_add_del_feature(
1732             sw_if_index=self.pg5.sw_if_index,
1733             is_add=1, flags=flags)
1734         self.vapi.nat44_interface_add_del_feature(
1735             sw_if_index=self.pg6.sw_if_index,
1736             is_add=1)
1737         flags = self.config_flags.NAT_IS_OUT2IN_ONLY
1738         self.nat_add_static_mapping(self.pg5.remote_ip4, external_addr,
1739                                     local_port, external_port, vrf_id=1,
1740                                     proto=IP_PROTOS.tcp, flags=flags)
1741
1742         p = (Ether(src=self.pg6.remote_mac, dst=self.pg6.local_mac) /
1743              IP(src=self.pg6.remote_ip4, dst=external_addr) /
1744              TCP(sport=12345, dport=external_port))
1745         self.pg6.add_stream(p)
1746         self.pg_enable_capture(self.pg_interfaces)
1747         self.pg_start()
1748         capture = self.pg5.get_capture(1)
1749         p = capture[0]
1750         try:
1751             ip = p[IP]
1752             tcp = p[TCP]
1753             self.assertEqual(ip.dst, self.pg5.remote_ip4)
1754             self.assertEqual(tcp.dport, local_port)
1755             self.assert_packet_checksums_valid(p)
1756         except:
1757             self.logger.error(ppp("Unexpected or invalid packet:", p))
1758             raise
1759
1760         p = (Ether(src=self.pg5.remote_mac, dst=self.pg5.local_mac) /
1761              IP(src=self.pg5.remote_ip4, dst=self.pg6.remote_ip4) /
1762              TCP(sport=local_port, dport=12345))
1763         self.pg5.add_stream(p)
1764         self.pg_enable_capture(self.pg_interfaces)
1765         self.pg_start()
1766         capture = self.pg6.get_capture(1)
1767         p = capture[0]
1768         try:
1769             ip = p[IP]
1770             tcp = p[TCP]
1771             self.assertEqual(ip.src, external_addr)
1772             self.assertEqual(tcp.sport, external_port)
1773             self.assert_packet_checksums_valid(p)
1774         except:
1775             self.logger.error(ppp("Unexpected or invalid packet:", p))
1776             raise
1777
1778     def test_multiple_vrf_2(self):
1779         """ Multiple VRF - dynamic NAT from VRF1 to VRF0 (output-feature) """
1780
1781         external_addr = '1.2.3.4'
1782         external_port = 80
1783         local_port = 8080
1784         port = 0
1785
1786         self.nat_add_address(self.nat_addr)
1787         flags = self.config_flags.NAT_IS_INSIDE
1788         self.vapi.nat44_interface_add_del_output_feature(
1789             sw_if_index=self.pg1.sw_if_index,
1790             is_add=1)
1791         self.vapi.nat44_interface_add_del_feature(
1792             sw_if_index=self.pg5.sw_if_index,
1793             is_add=1)
1794         self.vapi.nat44_interface_add_del_feature(
1795             sw_if_index=self.pg5.sw_if_index,
1796             is_add=1, flags=flags)
1797         flags = self.config_flags.NAT_IS_OUT2IN_ONLY
1798         self.nat_add_static_mapping(self.pg5.remote_ip4, external_addr,
1799                                     local_port, external_port, vrf_id=1,
1800                                     proto=IP_PROTOS.tcp, flags=flags)
1801
1802         p = (Ether(src=self.pg5.remote_mac, dst=self.pg5.local_mac) /
1803              IP(src=self.pg5.remote_ip4, dst=self.pg1.remote_ip4) /
1804              TCP(sport=2345, dport=22))
1805         self.pg5.add_stream(p)
1806         self.pg_enable_capture(self.pg_interfaces)
1807         self.pg_start()
1808         capture = self.pg1.get_capture(1)
1809         p = capture[0]
1810         try:
1811             ip = p[IP]
1812             tcp = p[TCP]
1813             self.assertEqual(ip.src, self.nat_addr)
1814             self.assert_packet_checksums_valid(p)
1815             port = tcp.sport
1816         except:
1817             self.logger.error(ppp("Unexpected or invalid packet:", p))
1818             raise
1819
1820         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
1821              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
1822              TCP(sport=22, dport=port))
1823         self.pg1.add_stream(p)
1824         self.pg_enable_capture(self.pg_interfaces)
1825         self.pg_start()
1826         capture = self.pg5.get_capture(1)
1827         p = capture[0]
1828         try:
1829             ip = p[IP]
1830             tcp = p[TCP]
1831             self.assertEqual(ip.dst, self.pg5.remote_ip4)
1832             self.assertEqual(tcp.dport, 2345)
1833             self.assert_packet_checksums_valid(p)
1834         except:
1835             self.logger.error(ppp("Unexpected or invalid packet:", p))
1836             raise
1837
1838     def test_multiple_vrf_3(self):
1839         """ Multiple VRF - client in VRF1, service in VRF0 """
1840
1841         external_addr = '1.2.3.4'
1842         external_port = 80
1843         local_port = 8080
1844         port = 0
1845
1846         flags = self.config_flags.NAT_IS_INSIDE
1847         self.vapi.nat44_interface_add_del_feature(
1848             sw_if_index=self.pg0.sw_if_index,
1849             is_add=1)
1850         self.vapi.nat44_interface_add_del_feature(
1851             sw_if_index=self.pg0.sw_if_index,
1852             is_add=1, flags=flags)
1853         self.vapi.nat44_interface_add_del_feature(
1854             sw_if_index=self.pg6.sw_if_index,
1855             is_add=1)
1856         flags = self.config_flags.NAT_IS_OUT2IN_ONLY
1857         self.nat_add_static_mapping(
1858             self.pg0.remote_ip4,
1859             external_sw_if_index=self.pg0.sw_if_index,
1860             local_port=local_port,
1861             vrf_id=0,
1862             external_port=external_port,
1863             proto=IP_PROTOS.tcp,
1864             flags=flags
1865         )
1866
1867         # from client VRF1 to service VRF0
1868         p = (Ether(src=self.pg6.remote_mac, dst=self.pg6.local_mac) /
1869              IP(src=self.pg6.remote_ip4, dst=self.pg0.local_ip4) /
1870              TCP(sport=12346, dport=external_port))
1871         self.pg6.add_stream(p)
1872         self.pg_enable_capture(self.pg_interfaces)
1873         self.pg_start()
1874         capture = self.pg0.get_capture(1)
1875         p = capture[0]
1876         try:
1877             ip = p[IP]
1878             tcp = p[TCP]
1879             self.assertEqual(ip.dst, self.pg0.remote_ip4)
1880             self.assertEqual(tcp.dport, local_port)
1881             self.assert_packet_checksums_valid(p)
1882         except:
1883             self.logger.error(ppp("Unexpected or invalid packet:", p))
1884             raise
1885
1886         # from service VRF0 back to client VRF1
1887         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
1888              IP(src=self.pg0.remote_ip4, dst=self.pg6.remote_ip4) /
1889              TCP(sport=local_port, dport=12346))
1890         self.pg0.add_stream(p)
1891         self.pg_enable_capture(self.pg_interfaces)
1892         self.pg_start()
1893         capture = self.pg6.get_capture(1)
1894         p = capture[0]
1895         try:
1896             ip = p[IP]
1897             tcp = p[TCP]
1898             self.assertEqual(ip.src, self.pg0.local_ip4)
1899             self.assertEqual(tcp.sport, external_port)
1900             self.assert_packet_checksums_valid(p)
1901         except:
1902             self.logger.error(ppp("Unexpected or invalid packet:", p))
1903             raise
1904
1905     def test_multiple_vrf_4(self):
1906         """ Multiple VRF - client in VRF0, service in VRF1 """
1907
1908         external_addr = '1.2.3.4'
1909         external_port = 80
1910         local_port = 8080
1911         port = 0
1912
1913         flags = self.config_flags.NAT_IS_INSIDE
1914         self.vapi.nat44_interface_add_del_feature(
1915             sw_if_index=self.pg0.sw_if_index,
1916             is_add=1)
1917         self.vapi.nat44_interface_add_del_feature(
1918             sw_if_index=self.pg0.sw_if_index,
1919             is_add=1, flags=flags)
1920         self.vapi.nat44_interface_add_del_feature(
1921             sw_if_index=self.pg5.sw_if_index,
1922             is_add=1)
1923         self.vapi.nat44_interface_add_del_feature(
1924             sw_if_index=self.pg5.sw_if_index,
1925             is_add=1, flags=flags)
1926         flags = self.config_flags.NAT_IS_OUT2IN_ONLY
1927         self.nat_add_static_mapping(self.pg5.remote_ip4, external_addr,
1928                                     local_port, external_port, vrf_id=1,
1929                                     proto=IP_PROTOS.tcp, flags=flags)
1930
1931         # from client VRF0 to service VRF1
1932         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
1933              IP(src=self.pg0.remote_ip4, dst=external_addr) /
1934              TCP(sport=12347, dport=external_port))
1935         self.pg0.add_stream(p)
1936         self.pg_enable_capture(self.pg_interfaces)
1937         self.pg_start()
1938         capture = self.pg5.get_capture(1)
1939         p = capture[0]
1940         try:
1941             ip = p[IP]
1942             tcp = p[TCP]
1943             self.assertEqual(ip.dst, self.pg5.remote_ip4)
1944             self.assertEqual(tcp.dport, local_port)
1945             self.assert_packet_checksums_valid(p)
1946         except:
1947             self.logger.error(ppp("Unexpected or invalid packet:", p))
1948             raise
1949
1950         # from service VRF1 back to client VRF0
1951         p = (Ether(src=self.pg5.remote_mac, dst=self.pg5.local_mac) /
1952              IP(src=self.pg5.remote_ip4, dst=self.pg0.remote_ip4) /
1953              TCP(sport=local_port, dport=12347))
1954         self.pg5.add_stream(p)
1955         self.pg_enable_capture(self.pg_interfaces)
1956         self.pg_start()
1957         capture = self.pg0.get_capture(1)
1958         p = capture[0]
1959         try:
1960             ip = p[IP]
1961             tcp = p[TCP]
1962             self.assertEqual(ip.src, external_addr)
1963             self.assertEqual(tcp.sport, external_port)
1964             self.assert_packet_checksums_valid(p)
1965         except:
1966             self.logger.error(ppp("Unexpected or invalid packet:", p))
1967             raise
1968
1969     def test_multiple_vrf_5(self):
1970         """ Multiple VRF - forwarding - no translation """
1971
1972         external_addr = '1.2.3.4'
1973         external_port = 80
1974         local_port = 8080
1975         port = 0
1976
1977         self.vapi.nat44_forwarding_enable_disable(enable=1)
1978         flags = self.config_flags.NAT_IS_INSIDE
1979         self.vapi.nat44_interface_add_del_feature(
1980             sw_if_index=self.pg0.sw_if_index,
1981             is_add=1)
1982         self.vapi.nat44_interface_add_del_feature(
1983             sw_if_index=self.pg0.sw_if_index,
1984             is_add=1, flags=flags)
1985         self.vapi.nat44_interface_add_del_feature(
1986             sw_if_index=self.pg5.sw_if_index,
1987             is_add=1)
1988         self.vapi.nat44_interface_add_del_feature(
1989             sw_if_index=self.pg5.sw_if_index,
1990             is_add=1, flags=flags)
1991         self.vapi.nat44_interface_add_del_feature(
1992             sw_if_index=self.pg6.sw_if_index,
1993             is_add=1)
1994         flags = self.config_flags.NAT_IS_OUT2IN_ONLY
1995         self.nat_add_static_mapping(self.pg5.remote_ip4, external_addr,
1996                                     local_port, external_port, vrf_id=1,
1997                                     proto=IP_PROTOS.tcp, flags=flags)
1998         self.nat_add_static_mapping(
1999             self.pg0.remote_ip4,
2000             external_sw_if_index=self.pg0.sw_if_index,
2001             local_port=local_port,
2002             vrf_id=0,
2003             external_port=external_port,
2004             proto=IP_PROTOS.tcp,
2005             flags=flags
2006         )
2007
2008         # from client to server (both VRF1, no translation)
2009         p = (Ether(src=self.pg6.remote_mac, dst=self.pg6.local_mac) /
2010              IP(src=self.pg6.remote_ip4, dst=self.pg5.remote_ip4) /
2011              TCP(sport=12348, dport=local_port))
2012         self.pg6.add_stream(p)
2013         self.pg_enable_capture(self.pg_interfaces)
2014         self.pg_start()
2015         capture = self.pg5.get_capture(1)
2016         p = capture[0]
2017         try:
2018             ip = p[IP]
2019             tcp = p[TCP]
2020             self.assertEqual(ip.dst, self.pg5.remote_ip4)
2021             self.assertEqual(tcp.dport, local_port)
2022             self.assert_packet_checksums_valid(p)
2023         except:
2024             self.logger.error(ppp("Unexpected or invalid packet:", p))
2025             raise
2026
2027         # from server back to client (both VRF1, no translation)
2028         p = (Ether(src=self.pg5.remote_mac, dst=self.pg5.local_mac) /
2029              IP(src=self.pg5.remote_ip4, dst=self.pg6.remote_ip4) /
2030              TCP(sport=local_port, dport=12348))
2031         self.pg5.add_stream(p)
2032         self.pg_enable_capture(self.pg_interfaces)
2033         self.pg_start()
2034         capture = self.pg6.get_capture(1)
2035         p = capture[0]
2036         try:
2037             ip = p[IP]
2038             tcp = p[TCP]
2039             self.assertEqual(ip.src, self.pg5.remote_ip4)
2040             self.assertEqual(tcp.sport, local_port)
2041             self.assert_packet_checksums_valid(p)
2042         except:
2043             self.logger.error(ppp("Unexpected or invalid packet:", p))
2044             raise
2045
2046         # from client VRF1 to server VRF0 (no translation)
2047         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
2048              IP(src=self.pg0.remote_ip4, dst=self.pg6.remote_ip4) /
2049              TCP(sport=local_port, dport=12349))
2050         self.pg0.add_stream(p)
2051         self.pg_enable_capture(self.pg_interfaces)
2052         self.pg_start()
2053         capture = self.pg6.get_capture(1)
2054         p = capture[0]
2055         try:
2056             ip = p[IP]
2057             tcp = p[TCP]
2058             self.assertEqual(ip.src, self.pg0.remote_ip4)
2059             self.assertEqual(tcp.sport, local_port)
2060             self.assert_packet_checksums_valid(p)
2061         except:
2062             self.logger.error(ppp("Unexpected or invalid packet:", p))
2063             raise
2064
2065         # from server VRF0 back to client VRF1 (no translation)
2066         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
2067              IP(src=self.pg0.remote_ip4, dst=self.pg6.remote_ip4) /
2068              TCP(sport=local_port, dport=12349))
2069         self.pg0.add_stream(p)
2070         self.pg_enable_capture(self.pg_interfaces)
2071         self.pg_start()
2072         capture = self.pg6.get_capture(1)
2073         p = capture[0]
2074         try:
2075             ip = p[IP]
2076             tcp = p[TCP]
2077             self.assertEqual(ip.src, self.pg0.remote_ip4)
2078             self.assertEqual(tcp.sport, local_port)
2079             self.assert_packet_checksums_valid(p)
2080         except:
2081             self.logger.error(ppp("Unexpected or invalid packet:", p))
2082             raise
2083
2084         # from client VRF0 to server VRF1 (no translation)
2085         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
2086              IP(src=self.pg0.remote_ip4, dst=self.pg5.remote_ip4) /
2087              TCP(sport=12344, dport=local_port))
2088         self.pg0.add_stream(p)
2089         self.pg_enable_capture(self.pg_interfaces)
2090         self.pg_start()
2091         capture = self.pg5.get_capture(1)
2092         p = capture[0]
2093         try:
2094             ip = p[IP]
2095             tcp = p[TCP]
2096             self.assertEqual(ip.dst, self.pg5.remote_ip4)
2097             self.assertEqual(tcp.dport, local_port)
2098             self.assert_packet_checksums_valid(p)
2099         except:
2100             self.logger.error(ppp("Unexpected or invalid packet:", p))
2101             raise
2102
2103         # from server VRF1 back to client VRF0 (no translation)
2104         p = (Ether(src=self.pg5.remote_mac, dst=self.pg5.local_mac) /
2105              IP(src=self.pg5.remote_ip4, dst=self.pg0.remote_ip4) /
2106              TCP(sport=local_port, dport=12344))
2107         self.pg5.add_stream(p)
2108         self.pg_enable_capture(self.pg_interfaces)
2109         self.pg_start()
2110         capture = self.pg0.get_capture(1)
2111         p = capture[0]
2112         try:
2113             ip = p[IP]
2114             tcp = p[TCP]
2115             self.assertEqual(ip.src, self.pg5.remote_ip4)
2116             self.assertEqual(tcp.sport, local_port)
2117             self.assert_packet_checksums_valid(p)
2118         except:
2119             self.logger.error(ppp("Unexpected or invalid packet:", p))
2120             raise
2121
2122     def test_outside_address_distribution(self):
2123         """ Outside address distribution based on source address """
2124
2125         x = 100
2126         nat_addresses = []
2127
2128         for i in range(1, x):
2129             a = "10.0.0.%d" % i
2130             nat_addresses.append(a)
2131
2132         self.nat_add_inside_interface(self.pg0)
2133         self.nat_add_outside_interface(self.pg1)
2134
2135         self.vapi.nat44_add_del_address_range(
2136             first_ip_address=nat_addresses[0],
2137             last_ip_address=nat_addresses[-1],
2138             vrf_id=0xFFFFFFFF, is_add=1, flags=0)
2139
2140         self.pg0.generate_remote_hosts(x)
2141
2142         pkts = []
2143         for i in range(x):
2144             info = self.create_packet_info(self.pg0, self.pg1)
2145             payload = self.info_to_payload(info)
2146             p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2147                  IP(src=self.pg0.remote_hosts[i].ip4,
2148                      dst=self.pg1.remote_ip4) /
2149                  UDP(sport=7000+i, dport=8000+i) /
2150                  Raw(payload))
2151             info.data = p
2152             pkts.append(p)
2153
2154         self.pg0.add_stream(pkts)
2155         self.pg_enable_capture(self.pg_interfaces)
2156         self.pg_start()
2157         recvd = self.pg1.get_capture(len(pkts))
2158         for p_recvd in recvd:
2159             payload_info = self.payload_to_info(p_recvd[Raw])
2160             packet_index = payload_info.index
2161             info = self._packet_infos[packet_index]
2162             self.assertTrue(info is not None)
2163             self.assertEqual(packet_index, info.index)
2164             p_sent = info.data
2165             packed = socket.inet_aton(p_sent[IP].src)
2166             numeric = struct.unpack("!L", packed)[0]
2167             numeric = socket.htonl(numeric)
2168             a = nat_addresses[(numeric-1) % len(nat_addresses)]
2169             self.assertEqual(
2170                 a, p_recvd[IP].src,
2171                 "Invalid packet (src IP %s translated to %s, but expected %s)"
2172                 % (p_sent[IP].src, p_recvd[IP].src, a))
2173
2174
2175 class TestNAT44EDMW(TestNAT44ED):
2176     """ NAT44ED MW Test Case """
2177     vpp_worker_count = 4
2178     max_sessions = 5000
2179
2180     def test_dynamic(self):
2181         """ NAT44ED dynamic translation test """
2182         pkt_count = 1500
2183         tcp_port_offset = 20
2184         udp_port_offset = 20
2185         icmp_id_offset = 20
2186
2187         self.nat_add_address(self.nat_addr)
2188         self.nat_add_inside_interface(self.pg0)
2189         self.nat_add_outside_interface(self.pg1)
2190
2191         # in2out
2192         tc1 = self.statistics['/nat44-ed/in2out/slowpath/tcp']
2193         uc1 = self.statistics['/nat44-ed/in2out/slowpath/udp']
2194         ic1 = self.statistics['/nat44-ed/in2out/slowpath/icmp']
2195         dc1 = self.statistics['/nat44-ed/in2out/slowpath/drops']
2196
2197         i2o_pkts = [[] for x in range(0, self.vpp_worker_count)]
2198
2199         for i in range(pkt_count):
2200             p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2201                  IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
2202                  TCP(sport=tcp_port_offset + i, dport=20))
2203             i2o_pkts[p[TCP].sport % self.vpp_worker_count].append(p)
2204
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                  UDP(sport=udp_port_offset + i, dport=20))
2208             i2o_pkts[p[UDP].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                  ICMP(id=icmp_id_offset + i, type='echo-request'))
2213             i2o_pkts[p[ICMP].id % self.vpp_worker_count].append(p)
2214
2215         for i in range(0, self.vpp_worker_count):
2216             if len(i2o_pkts[i]) > 0:
2217                 self.pg0.add_stream(i2o_pkts[i], worker=i)
2218
2219         self.pg_enable_capture(self.pg_interfaces)
2220         self.pg_start()
2221         capture = self.pg1.get_capture(pkt_count * 3, timeout=5)
2222
2223         if_idx = self.pg0.sw_if_index
2224         tc2 = self.statistics['/nat44-ed/in2out/slowpath/tcp']
2225         uc2 = self.statistics['/nat44-ed/in2out/slowpath/udp']
2226         ic2 = self.statistics['/nat44-ed/in2out/slowpath/icmp']
2227         dc2 = self.statistics['/nat44-ed/in2out/slowpath/drops']
2228
2229         self.assertEqual(
2230             tc2[:, if_idx].sum() - tc1[:, if_idx].sum(), pkt_count)
2231         self.assertEqual(
2232             uc2[:, if_idx].sum() - uc1[:, if_idx].sum(), pkt_count)
2233         self.assertEqual(
2234             ic2[:, if_idx].sum() - ic1[:, if_idx].sum(), pkt_count)
2235         self.assertEqual(dc2[:, if_idx].sum() - dc1[:, if_idx].sum(), 0)
2236
2237         self.logger.info(self.vapi.cli("show trace"))
2238
2239         # out2in
2240         tc1 = self.statistics['/nat44-ed/out2in/fastpath/tcp']
2241         uc1 = self.statistics['/nat44-ed/out2in/fastpath/udp']
2242         ic1 = self.statistics['/nat44-ed/out2in/fastpath/icmp']
2243         dc1 = self.statistics['/nat44-ed/out2in/fastpath/drops']
2244
2245         recvd_tcp_ports = set()
2246         recvd_udp_ports = set()
2247         recvd_icmp_ids = set()
2248
2249         for p in capture:
2250             if TCP in p:
2251                 recvd_tcp_ports.add(p[TCP].sport)
2252             if UDP in p:
2253                 recvd_udp_ports.add(p[UDP].sport)
2254             if ICMP in p:
2255                 recvd_icmp_ids.add(p[ICMP].id)
2256
2257         recvd_tcp_ports = list(recvd_tcp_ports)
2258         recvd_udp_ports = list(recvd_udp_ports)
2259         recvd_icmp_ids = list(recvd_icmp_ids)
2260
2261         o2i_pkts = [[] for x in range(0, self.vpp_worker_count)]
2262         for i in range(pkt_count):
2263             p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
2264                  IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
2265                  TCP(dport=choice(recvd_tcp_ports), sport=20))
2266             o2i_pkts[p[TCP].dport % self.vpp_worker_count].append(p)
2267
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                  UDP(dport=choice(recvd_udp_ports), sport=20))
2271             o2i_pkts[p[UDP].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                  ICMP(id=choice(recvd_icmp_ids), type='echo-reply'))
2276             o2i_pkts[p[ICMP].id % self.vpp_worker_count].append(p)
2277
2278         for i in range(0, self.vpp_worker_count):
2279             if len(o2i_pkts[i]) > 0:
2280                 self.pg1.add_stream(o2i_pkts[i], worker=i)
2281
2282         self.pg_enable_capture(self.pg_interfaces)
2283         self.pg_start()
2284         capture = self.pg0.get_capture(pkt_count * 3)
2285         for packet in capture:
2286             try:
2287                 self.assert_packet_checksums_valid(packet)
2288                 self.assertEqual(packet[IP].dst, self.pg0.remote_ip4)
2289                 if packet.haslayer(TCP):
2290                     self.assert_in_range(
2291                         packet[TCP].dport, tcp_port_offset,
2292                         tcp_port_offset + pkt_count, "dst TCP port")
2293                 elif packet.haslayer(UDP):
2294                     self.assert_in_range(
2295                         packet[UDP].dport, udp_port_offset,
2296                         udp_port_offset + pkt_count, "dst UDP port")
2297                 else:
2298                     self.assert_in_range(
2299                         packet[ICMP].id, icmp_id_offset,
2300                         icmp_id_offset + pkt_count, "ICMP id")
2301             except:
2302                 self.logger.error(ppp("Unexpected or invalid packet "
2303                                       "(inside network):", packet))
2304                 raise
2305
2306         if_idx = self.pg1.sw_if_index
2307         tc2 = self.statistics['/nat44-ed/out2in/fastpath/tcp']
2308         uc2 = self.statistics['/nat44-ed/out2in/fastpath/udp']
2309         ic2 = self.statistics['/nat44-ed/out2in/fastpath/icmp']
2310         dc2 = self.statistics['/nat44-ed/out2in/fastpath/drops']
2311
2312         self.assertEqual(
2313             tc2[:, if_idx].sum() - tc1[:, if_idx].sum(), pkt_count)
2314         self.assertEqual(
2315             uc2[:, if_idx].sum() - uc1[:, if_idx].sum(), pkt_count)
2316         self.assertEqual(
2317             ic2[:, if_idx].sum() - ic1[:, if_idx].sum(), pkt_count)
2318         self.assertEqual(dc2[:, if_idx].sum() - dc1[:, if_idx].sum(), 0)
2319
2320         sc = self.statistics['/nat44-ed/total-sessions']
2321         self.assertEqual(sc[:, 0].sum(), len(recvd_tcp_ports) +
2322                          len(recvd_udp_ports) + len(recvd_icmp_ids))
2323
2324     def test_frag_in_order(self):
2325         """ NAT44ED translate fragments arriving in order """
2326
2327         self.nat_add_address(self.nat_addr)
2328         self.nat_add_inside_interface(self.pg0)
2329         self.nat_add_outside_interface(self.pg1)
2330
2331         self.frag_in_order(proto=IP_PROTOS.tcp, ignore_port=True)
2332         self.frag_in_order(proto=IP_PROTOS.udp, ignore_port=True)
2333         self.frag_in_order(proto=IP_PROTOS.icmp, ignore_port=True)
2334
2335     def test_frag_in_order_do_not_translate(self):
2336         """ NAT44ED don't translate fragments arriving in order """
2337
2338         self.nat_add_address(self.nat_addr)
2339         self.nat_add_inside_interface(self.pg0)
2340         self.nat_add_outside_interface(self.pg1)
2341         self.vapi.nat44_forwarding_enable_disable(enable=True)
2342
2343         self.frag_in_order(proto=IP_PROTOS.tcp, dont_translate=True)
2344
2345     def test_frag_out_of_order(self):
2346         """ NAT44ED translate fragments arriving out of order """
2347
2348         self.nat_add_address(self.nat_addr)
2349         self.nat_add_inside_interface(self.pg0)
2350         self.nat_add_outside_interface(self.pg1)
2351
2352         self.frag_out_of_order(proto=IP_PROTOS.tcp, ignore_port=True)
2353         self.frag_out_of_order(proto=IP_PROTOS.udp, ignore_port=True)
2354         self.frag_out_of_order(proto=IP_PROTOS.icmp, ignore_port=True)
2355
2356     def test_frag_in_order_in_plus_out(self):
2357         """ NAT44ED in+out interface fragments in order """
2358
2359         in_port = self.random_port()
2360         out_port = self.random_port()
2361
2362         self.nat_add_address(self.nat_addr)
2363         self.nat_add_inside_interface(self.pg0)
2364         self.nat_add_outside_interface(self.pg0)
2365         self.nat_add_inside_interface(self.pg1)
2366         self.nat_add_outside_interface(self.pg1)
2367
2368         # add static mappings for server
2369         self.nat_add_static_mapping(self.server_addr,
2370                                     self.nat_addr,
2371                                     in_port,
2372                                     out_port,
2373                                     proto=IP_PROTOS.tcp)
2374         self.nat_add_static_mapping(self.server_addr,
2375                                     self.nat_addr,
2376                                     in_port,
2377                                     out_port,
2378                                     proto=IP_PROTOS.udp)
2379         self.nat_add_static_mapping(self.server_addr,
2380                                     self.nat_addr,
2381                                     proto=IP_PROTOS.icmp)
2382
2383         # run tests for each protocol
2384         self.frag_in_order_in_plus_out(self.server_addr,
2385                                        self.nat_addr,
2386                                        in_port,
2387                                        out_port,
2388                                        IP_PROTOS.tcp)
2389         self.frag_in_order_in_plus_out(self.server_addr,
2390                                        self.nat_addr,
2391                                        in_port,
2392                                        out_port,
2393                                        IP_PROTOS.udp)
2394         self.frag_in_order_in_plus_out(self.server_addr,
2395                                        self.nat_addr,
2396                                        in_port,
2397                                        out_port,
2398                                        IP_PROTOS.icmp)
2399
2400     def test_frag_out_of_order_in_plus_out(self):
2401         """ NAT44ED in+out interface fragments out of order """
2402
2403         in_port = self.random_port()
2404         out_port = self.random_port()
2405
2406         self.nat_add_address(self.nat_addr)
2407         self.nat_add_inside_interface(self.pg0)
2408         self.nat_add_outside_interface(self.pg0)
2409         self.nat_add_inside_interface(self.pg1)
2410         self.nat_add_outside_interface(self.pg1)
2411
2412         # add static mappings for server
2413         self.nat_add_static_mapping(self.server_addr,
2414                                     self.nat_addr,
2415                                     in_port,
2416                                     out_port,
2417                                     proto=IP_PROTOS.tcp)
2418         self.nat_add_static_mapping(self.server_addr,
2419                                     self.nat_addr,
2420                                     in_port,
2421                                     out_port,
2422                                     proto=IP_PROTOS.udp)
2423         self.nat_add_static_mapping(self.server_addr,
2424                                     self.nat_addr,
2425                                     proto=IP_PROTOS.icmp)
2426
2427         # run tests for each protocol
2428         self.frag_out_of_order_in_plus_out(self.server_addr,
2429                                            self.nat_addr,
2430                                            in_port,
2431                                            out_port,
2432                                            IP_PROTOS.tcp)
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.udp)
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.icmp)
2443
2444     def test_reass_hairpinning(self):
2445         """ NAT44ED fragments hairpinning """
2446
2447         server_addr = self.pg0.remote_hosts[1].ip4
2448
2449         host_in_port = self.random_port()
2450         server_in_port = self.random_port()
2451         server_out_port = self.random_port()
2452
2453         self.nat_add_address(self.nat_addr)
2454         self.nat_add_inside_interface(self.pg0)
2455         self.nat_add_outside_interface(self.pg1)
2456
2457         # add static mapping for server
2458         self.nat_add_static_mapping(server_addr, self.nat_addr,
2459                                     server_in_port, server_out_port,
2460                                     proto=IP_PROTOS.tcp)
2461         self.nat_add_static_mapping(server_addr, self.nat_addr,
2462                                     server_in_port, server_out_port,
2463                                     proto=IP_PROTOS.udp)
2464         self.nat_add_static_mapping(server_addr, self.nat_addr)
2465
2466         self.reass_hairpinning(server_addr, server_in_port, server_out_port,
2467                                host_in_port, proto=IP_PROTOS.tcp,
2468                                ignore_port=True)
2469         self.reass_hairpinning(server_addr, server_in_port, server_out_port,
2470                                host_in_port, proto=IP_PROTOS.udp,
2471                                ignore_port=True)
2472         self.reass_hairpinning(server_addr, server_in_port, server_out_port,
2473                                host_in_port, proto=IP_PROTOS.icmp,
2474                                ignore_port=True)
2475
2476     def test_session_limit_per_vrf(self):
2477         """ NAT44ED per vrf session limit """
2478
2479         inside = self.pg0
2480         inside_vrf10 = self.pg2
2481         outside = self.pg1
2482
2483         limit = 5
2484
2485         # 2 interfaces pg0, pg1 (vrf10, limit 1 tcp session)
2486         # non existing vrf_id makes process core dump
2487         self.vapi.nat44_set_session_limit(session_limit=limit, vrf_id=10)
2488
2489         self.nat_add_inside_interface(inside)
2490         self.nat_add_inside_interface(inside_vrf10)
2491         self.nat_add_outside_interface(outside)
2492
2493         # vrf independent
2494         self.nat_add_interface_address(outside)
2495
2496         # BUG: causing core dump - when bad vrf_id is specified
2497         # self.nat_add_address(outside.local_ip4, vrf_id=20)
2498
2499         stream = self.create_tcp_stream(inside_vrf10, outside, limit * 2)
2500         inside_vrf10.add_stream(stream)
2501
2502         self.pg_enable_capture(self.pg_interfaces)
2503         self.pg_start()
2504
2505         capture = outside.get_capture(limit)
2506
2507         stream = self.create_tcp_stream(inside, outside, limit * 2)
2508         inside.add_stream(stream)
2509
2510         self.pg_enable_capture(self.pg_interfaces)
2511         self.pg_start()
2512
2513         capture = outside.get_capture(len(stream))
2514
2515     def test_show_max_translations(self):
2516         """ NAT44ED API test - max translations per thread """
2517         nat_config = self.vapi.nat_show_config_2()
2518         self.assertEqual(self.max_sessions,
2519                          nat_config.max_translations_per_thread)
2520
2521     def test_lru_cleanup(self):
2522         """ NAT44ED LRU cleanup algorithm """
2523
2524         self.nat_add_address(self.nat_addr)
2525         self.nat_add_inside_interface(self.pg0)
2526         self.nat_add_outside_interface(self.pg1)
2527
2528         self.vapi.nat_set_timeouts(
2529             udp=1, tcp_established=7440, tcp_transitory=30, icmp=1)
2530
2531         tcp_port_out = self.init_tcp_session(self.pg0, self.pg1, 2000, 80)
2532         pkts = []
2533         for i in range(0, self.max_sessions - 1):
2534             p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2535                  IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4, ttl=64) /
2536                  UDP(sport=7000+i, dport=80))
2537             pkts.append(p)
2538
2539         self.pg0.add_stream(pkts)
2540         self.pg_enable_capture(self.pg_interfaces)
2541         self.pg_start()
2542         self.pg1.get_capture(len(pkts))
2543         self.virtual_sleep(1.5, "wait for timeouts")
2544
2545         pkts = []
2546         for i in range(0, self.max_sessions - 1):
2547             p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2548                  IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4, ttl=64) /
2549                  ICMP(id=8000+i, type='echo-request'))
2550             pkts.append(p)
2551
2552         self.pg0.add_stream(pkts)
2553         self.pg_enable_capture(self.pg_interfaces)
2554         self.pg_start()
2555         self.pg1.get_capture(len(pkts))
2556
2557     def test_session_rst_timeout(self):
2558         """ NAT44ED session RST timeouts """
2559
2560         self.nat_add_address(self.nat_addr)
2561         self.nat_add_inside_interface(self.pg0)
2562         self.nat_add_outside_interface(self.pg1)
2563
2564         self.vapi.nat_set_timeouts(udp=300, tcp_established=7440,
2565                                    tcp_transitory=5, icmp=60)
2566
2567         self.init_tcp_session(self.pg0, self.pg1, self.tcp_port_in,
2568                               self.tcp_external_port)
2569         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
2570              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
2571              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
2572                  flags="R"))
2573         self.send_and_expect(self.pg0, p, self.pg1)
2574
2575         self.virtual_sleep(6)
2576
2577         # The session is already closed
2578         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
2579              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
2580              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
2581                  flags="P"))
2582         self.send_and_assert_no_replies(self.pg0, p, self.pg1)
2583
2584         # The session can be re-opened
2585         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
2586              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
2587              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
2588                  flags="S"))
2589         self.send_and_expect(self.pg0, p, self.pg1)
2590
2591     def test_session_rst_established_timeout(self):
2592         """ NAT44ED session RST timeouts """
2593
2594         self.nat_add_address(self.nat_addr)
2595         self.nat_add_inside_interface(self.pg0)
2596         self.nat_add_outside_interface(self.pg1)
2597
2598         self.vapi.nat_set_timeouts(udp=300, tcp_established=7440,
2599                                    tcp_transitory=5, icmp=60)
2600
2601         self.init_tcp_session(self.pg0, self.pg1, self.tcp_port_in,
2602                               self.tcp_external_port)
2603
2604         # Wait at least the transitory time, the session is in established
2605         # state anyway. RST followed by a data packet should keep it
2606         # established.
2607         self.virtual_sleep(6)
2608         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
2609              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
2610              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
2611                  flags="R"))
2612         self.send_and_expect(self.pg0, p, self.pg1)
2613
2614         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
2615              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
2616              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
2617                  flags="P"))
2618         self.send_and_expect(self.pg0, p, self.pg1)
2619
2620         # State is established, session should be still open after 6 seconds
2621         self.virtual_sleep(6)
2622
2623         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
2624              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
2625              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
2626                  flags="R"))
2627         self.send_and_expect(self.pg0, p, self.pg1)
2628
2629         # State is transitory, session should be closed after 6 seconds
2630         self.virtual_sleep(6)
2631
2632         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
2633              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
2634              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
2635                  flags="P"))
2636         self.send_and_assert_no_replies(self.pg0, p, self.pg1)
2637
2638     def test_dynamic_out_of_ports(self):
2639         """ NAT44ED dynamic translation test: out of ports """
2640
2641         self.nat_add_inside_interface(self.pg0)
2642         self.nat_add_outside_interface(self.pg1)
2643
2644         # in2out and no NAT addresses added
2645         pkts = self.create_stream_in(self.pg0, self.pg1)
2646
2647         self.send_and_assert_no_replies(
2648             self.pg0, pkts, msg="i2o pkts",
2649             stats_diff=self.no_diff | {
2650                 "err": {
2651                     '/err/nat44-ed-in2out-slowpath/out of ports': len(pkts),
2652                 },
2653                 self.pg0.sw_if_index: {
2654                     '/nat44-ed/in2out/slowpath/drops': len(pkts),
2655                 },
2656             }
2657         )
2658
2659         # in2out after NAT addresses added
2660         self.nat_add_address(self.nat_addr)
2661
2662         tcpn, udpn, icmpn = (sum(x) for x in
2663                              zip(*((TCP in p, UDP in p, ICMP in p)
2664                                  for p in pkts)))
2665
2666         self.send_and_expect(
2667             self.pg0, pkts, self.pg1, msg="i2o pkts",
2668             stats_diff=self.no_diff | {
2669                 "err": {
2670                     '/err/nat44-ed-in2out-slowpath/out of ports': 0,
2671                 },
2672                 self.pg0.sw_if_index: {
2673                     '/nat44-ed/in2out/slowpath/drops': 0,
2674                     '/nat44-ed/in2out/slowpath/tcp': tcpn,
2675                     '/nat44-ed/in2out/slowpath/udp': udpn,
2676                     '/nat44-ed/in2out/slowpath/icmp': icmpn,
2677                 },
2678             }
2679         )
2680
2681     def test_unknown_proto(self):
2682         """ NAT44ED translate packet with unknown protocol """
2683
2684         self.nat_add_address(self.nat_addr)
2685         self.nat_add_inside_interface(self.pg0)
2686         self.nat_add_outside_interface(self.pg1)
2687
2688         # in2out
2689         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2690              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
2691              TCP(sport=self.tcp_port_in, dport=20))
2692         self.pg0.add_stream(p)
2693         self.pg_enable_capture(self.pg_interfaces)
2694         self.pg_start()
2695         p = self.pg1.get_capture(1)
2696
2697         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2698              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
2699              GRE() /
2700              IP(src=self.pg2.remote_ip4, dst=self.pg2.remote_ip4) /
2701              TCP(sport=1234, dport=1234))
2702         self.pg0.add_stream(p)
2703         self.pg_enable_capture(self.pg_interfaces)
2704         self.pg_start()
2705         p = self.pg1.get_capture(1)
2706         packet = p[0]
2707         try:
2708             self.assertEqual(packet[IP].src, self.nat_addr)
2709             self.assertEqual(packet[IP].dst, self.pg1.remote_ip4)
2710             self.assertEqual(packet.haslayer(GRE), 1)
2711             self.assert_packet_checksums_valid(packet)
2712         except:
2713             self.logger.error(ppp("Unexpected or invalid packet:", packet))
2714             raise
2715
2716         # out2in
2717         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
2718              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
2719              GRE() /
2720              IP(src=self.pg2.remote_ip4, dst=self.pg2.remote_ip4) /
2721              TCP(sport=1234, dport=1234))
2722         self.pg1.add_stream(p)
2723         self.pg_enable_capture(self.pg_interfaces)
2724         self.pg_start()
2725         p = self.pg0.get_capture(1)
2726         packet = p[0]
2727         try:
2728             self.assertEqual(packet[IP].src, self.pg1.remote_ip4)
2729             self.assertEqual(packet[IP].dst, self.pg0.remote_ip4)
2730             self.assertEqual(packet.haslayer(GRE), 1)
2731             self.assert_packet_checksums_valid(packet)
2732         except:
2733             self.logger.error(ppp("Unexpected or invalid packet:", packet))
2734             raise
2735
2736     def test_hairpinning_unknown_proto(self):
2737         """ NAT44ED translate packet with unknown protocol - hairpinning """
2738         host = self.pg0.remote_hosts[0]
2739         server = self.pg0.remote_hosts[1]
2740         host_in_port = 1234
2741         server_out_port = 8765
2742         server_nat_ip = "10.0.0.11"
2743
2744         self.nat_add_address(self.nat_addr)
2745         self.nat_add_inside_interface(self.pg0)
2746         self.nat_add_outside_interface(self.pg1)
2747
2748         # add static mapping for server
2749         self.nat_add_static_mapping(server.ip4, server_nat_ip)
2750
2751         # host to server
2752         p = (Ether(src=host.mac, dst=self.pg0.local_mac) /
2753              IP(src=host.ip4, dst=server_nat_ip) /
2754              TCP(sport=host_in_port, dport=server_out_port))
2755         self.pg0.add_stream(p)
2756         self.pg_enable_capture(self.pg_interfaces)
2757         self.pg_start()
2758         self.pg0.get_capture(1)
2759
2760         p = (Ether(dst=self.pg0.local_mac, src=host.mac) /
2761              IP(src=host.ip4, dst=server_nat_ip) /
2762              GRE() /
2763              IP(src=self.pg2.remote_ip4, dst=self.pg2.remote_ip4) /
2764              TCP(sport=1234, dport=1234))
2765         self.pg0.add_stream(p)
2766         self.pg_enable_capture(self.pg_interfaces)
2767         self.pg_start()
2768         p = self.pg0.get_capture(1)
2769         packet = p[0]
2770         try:
2771             self.assertEqual(packet[IP].src, self.nat_addr)
2772             self.assertEqual(packet[IP].dst, server.ip4)
2773             self.assertEqual(packet.haslayer(GRE), 1)
2774             self.assert_packet_checksums_valid(packet)
2775         except:
2776             self.logger.error(ppp("Unexpected or invalid packet:", packet))
2777             raise
2778
2779         # server to host
2780         p = (Ether(dst=self.pg0.local_mac, src=server.mac) /
2781              IP(src=server.ip4, dst=self.nat_addr) /
2782              GRE() /
2783              IP(src=self.pg2.remote_ip4, dst=self.pg2.remote_ip4) /
2784              TCP(sport=1234, dport=1234))
2785         self.pg0.add_stream(p)
2786         self.pg_enable_capture(self.pg_interfaces)
2787         self.pg_start()
2788         p = self.pg0.get_capture(1)
2789         packet = p[0]
2790         try:
2791             self.assertEqual(packet[IP].src, server_nat_ip)
2792             self.assertEqual(packet[IP].dst, host.ip4)
2793             self.assertEqual(packet.haslayer(GRE), 1)
2794             self.assert_packet_checksums_valid(packet)
2795         except:
2796             self.logger.error(ppp("Unexpected or invalid packet:", packet))
2797             raise
2798
2799     def test_output_feature_and_service(self):
2800         """ NAT44ED interface output feature and services """
2801         external_addr = '1.2.3.4'
2802         external_port = 80
2803         local_port = 8080
2804
2805         self.vapi.nat44_forwarding_enable_disable(enable=1)
2806         self.nat_add_address(self.nat_addr)
2807         flags = self.config_flags.NAT_IS_ADDR_ONLY
2808         self.vapi.nat44_add_del_identity_mapping(
2809             ip_address=self.pg1.remote_ip4, sw_if_index=0xFFFFFFFF,
2810             flags=flags, is_add=1)
2811         flags = self.config_flags.NAT_IS_OUT2IN_ONLY
2812         self.nat_add_static_mapping(self.pg0.remote_ip4, external_addr,
2813                                     local_port, external_port,
2814                                     proto=IP_PROTOS.tcp, flags=flags)
2815
2816         self.nat_add_inside_interface(self.pg0)
2817         self.nat_add_outside_interface(self.pg0)
2818         self.vapi.nat44_ed_add_del_output_interface(
2819             sw_if_index=self.pg1.sw_if_index, is_add=1)
2820
2821         # from client to service
2822         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
2823              IP(src=self.pg1.remote_ip4, dst=external_addr) /
2824              TCP(sport=12345, dport=external_port))
2825         self.pg1.add_stream(p)
2826         self.pg_enable_capture(self.pg_interfaces)
2827         self.pg_start()
2828         capture = self.pg0.get_capture(1)
2829         p = capture[0]
2830         try:
2831             ip = p[IP]
2832             tcp = p[TCP]
2833             self.assertEqual(ip.dst, self.pg0.remote_ip4)
2834             self.assertEqual(tcp.dport, local_port)
2835             self.assert_packet_checksums_valid(p)
2836         except:
2837             self.logger.error(ppp("Unexpected or invalid packet:", p))
2838             raise
2839
2840         # from service back to client
2841         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
2842              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
2843              TCP(sport=local_port, dport=12345))
2844         self.pg0.add_stream(p)
2845         self.pg_enable_capture(self.pg_interfaces)
2846         self.pg_start()
2847         capture = self.pg1.get_capture(1)
2848         p = capture[0]
2849         try:
2850             ip = p[IP]
2851             tcp = p[TCP]
2852             self.assertEqual(ip.src, external_addr)
2853             self.assertEqual(tcp.sport, external_port)
2854             self.assert_packet_checksums_valid(p)
2855         except:
2856             self.logger.error(ppp("Unexpected or invalid packet:", p))
2857             raise
2858
2859         # from local network host to external network
2860         pkts = self.create_stream_in(self.pg0, self.pg1)
2861         self.pg0.add_stream(pkts)
2862         self.pg_enable_capture(self.pg_interfaces)
2863         self.pg_start()
2864         capture = self.pg1.get_capture(len(pkts))
2865         self.verify_capture_out(capture, ignore_port=True)
2866         pkts = self.create_stream_in(self.pg0, self.pg1)
2867         self.pg0.add_stream(pkts)
2868         self.pg_enable_capture(self.pg_interfaces)
2869         self.pg_start()
2870         capture = self.pg1.get_capture(len(pkts))
2871         self.verify_capture_out(capture, ignore_port=True)
2872
2873         # from external network back to local network host
2874         pkts = self.create_stream_out(self.pg1)
2875         self.pg1.add_stream(pkts)
2876         self.pg_enable_capture(self.pg_interfaces)
2877         self.pg_start()
2878         capture = self.pg0.get_capture(len(pkts))
2879         self.verify_capture_in(capture, self.pg0)
2880
2881     def test_output_feature_and_service3(self):
2882         """ NAT44ED interface output feature and DST NAT """
2883         external_addr = '1.2.3.4'
2884         external_port = 80
2885         local_port = 8080
2886
2887         self.vapi.nat44_forwarding_enable_disable(enable=1)
2888         self.nat_add_address(self.nat_addr)
2889         flags = self.config_flags.NAT_IS_OUT2IN_ONLY
2890         self.nat_add_static_mapping(self.pg1.remote_ip4, external_addr,
2891                                     local_port, external_port,
2892                                     proto=IP_PROTOS.tcp, flags=flags)
2893
2894         self.nat_add_inside_interface(self.pg0)
2895         self.nat_add_outside_interface(self.pg0)
2896         self.vapi.nat44_ed_add_del_output_interface(
2897             sw_if_index=self.pg1.sw_if_index, is_add=1)
2898
2899         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
2900              IP(src=self.pg0.remote_ip4, dst=external_addr) /
2901              TCP(sport=12345, dport=external_port))
2902         self.pg0.add_stream(p)
2903         self.pg_enable_capture(self.pg_interfaces)
2904         self.pg_start()
2905         capture = self.pg1.get_capture(1)
2906         p = capture[0]
2907         try:
2908             ip = p[IP]
2909             tcp = p[TCP]
2910             self.assertEqual(ip.src, self.pg0.remote_ip4)
2911             self.assertEqual(tcp.sport, 12345)
2912             self.assertEqual(ip.dst, self.pg1.remote_ip4)
2913             self.assertEqual(tcp.dport, local_port)
2914             self.assert_packet_checksums_valid(p)
2915         except:
2916             self.logger.error(ppp("Unexpected or invalid packet:", p))
2917             raise
2918
2919         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
2920              IP(src=self.pg1.remote_ip4, dst=self.pg0.remote_ip4) /
2921              TCP(sport=local_port, dport=12345))
2922         self.pg1.add_stream(p)
2923         self.pg_enable_capture(self.pg_interfaces)
2924         self.pg_start()
2925         capture = self.pg0.get_capture(1)
2926         p = capture[0]
2927         try:
2928             ip = p[IP]
2929             tcp = p[TCP]
2930             self.assertEqual(ip.src, external_addr)
2931             self.assertEqual(tcp.sport, external_port)
2932             self.assertEqual(ip.dst, self.pg0.remote_ip4)
2933             self.assertEqual(tcp.dport, 12345)
2934             self.assert_packet_checksums_valid(p)
2935         except:
2936             self.logger.error(ppp("Unexpected or invalid packet:", p))
2937             raise
2938
2939     def test_self_twice_nat_lb_negative(self):
2940         """ NAT44ED Self Twice NAT local service load balancing (negative test)
2941         """
2942         self.twice_nat_common(lb=True, self_twice_nat=True, same_pg=True,
2943                               client_id=2)
2944
2945     def test_self_twice_nat_negative(self):
2946         """ NAT44ED Self Twice NAT (negative test) """
2947         self.twice_nat_common(self_twice_nat=True)
2948
2949     def test_static_lb_multi_clients(self):
2950         """ NAT44ED local service load balancing - multiple clients"""
2951
2952         external_addr = self.nat_addr
2953         external_port = 80
2954         local_port = 8080
2955         server1 = self.pg0.remote_hosts[0]
2956         server2 = self.pg0.remote_hosts[1]
2957         server3 = self.pg0.remote_hosts[2]
2958
2959         locals = [{'addr': server1.ip4,
2960                    'port': local_port,
2961                    'probability': 90,
2962                    'vrf_id': 0},
2963                   {'addr': server2.ip4,
2964                    'port': local_port,
2965                    'probability': 10,
2966                    'vrf_id': 0}]
2967
2968         flags = self.config_flags.NAT_IS_INSIDE
2969         self.vapi.nat44_interface_add_del_feature(
2970             sw_if_index=self.pg0.sw_if_index,
2971             flags=flags, is_add=1)
2972         self.vapi.nat44_interface_add_del_feature(
2973             sw_if_index=self.pg1.sw_if_index,
2974             is_add=1)
2975
2976         self.nat_add_address(self.nat_addr)
2977         self.vapi.nat44_add_del_lb_static_mapping(is_add=1,
2978                                                   external_addr=external_addr,
2979                                                   external_port=external_port,
2980                                                   protocol=IP_PROTOS.tcp,
2981                                                   local_num=len(locals),
2982                                                   locals=locals)
2983
2984         server1_n = 0
2985         server2_n = 0
2986         clients = ip4_range(self.pg1.remote_ip4, 10, 50)
2987         pkts = []
2988         for client in clients:
2989             p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
2990                  IP(src=client, dst=self.nat_addr) /
2991                  TCP(sport=12345, dport=external_port))
2992             pkts.append(p)
2993         self.pg1.add_stream(pkts)
2994         self.pg_enable_capture(self.pg_interfaces)
2995         self.pg_start()
2996         capture = self.pg0.get_capture(len(pkts))
2997         for p in capture:
2998             if p[IP].dst == server1.ip4:
2999                 server1_n += 1
3000             else:
3001                 server2_n += 1
3002         self.assertGreaterEqual(server1_n, server2_n)
3003
3004         local = {
3005             'addr': server3.ip4,
3006             'port': local_port,
3007             'probability': 20,
3008             'vrf_id': 0
3009         }
3010
3011         # add new back-end
3012         self.vapi.nat44_lb_static_mapping_add_del_local(
3013             is_add=1,
3014             external_addr=external_addr,
3015             external_port=external_port,
3016             local=local,
3017             protocol=IP_PROTOS.tcp)
3018         server1_n = 0
3019         server2_n = 0
3020         server3_n = 0
3021         clients = ip4_range(self.pg1.remote_ip4, 60, 110)
3022         pkts = []
3023         for client in clients:
3024             p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
3025                  IP(src=client, dst=self.nat_addr) /
3026                  TCP(sport=12346, dport=external_port))
3027             pkts.append(p)
3028         self.assertGreater(len(pkts), 0)
3029         self.pg1.add_stream(pkts)
3030         self.pg_enable_capture(self.pg_interfaces)
3031         self.pg_start()
3032         capture = self.pg0.get_capture(len(pkts))
3033         for p in capture:
3034             if p[IP].dst == server1.ip4:
3035                 server1_n += 1
3036             elif p[IP].dst == server2.ip4:
3037                 server2_n += 1
3038             else:
3039                 server3_n += 1
3040         self.assertGreater(server1_n, 0)
3041         self.assertGreater(server2_n, 0)
3042         self.assertGreater(server3_n, 0)
3043
3044         local = {
3045             'addr': server2.ip4,
3046             'port': local_port,
3047             'probability': 10,
3048             'vrf_id': 0
3049         }
3050
3051         # remove one back-end
3052         self.vapi.nat44_lb_static_mapping_add_del_local(
3053             is_add=0,
3054             external_addr=external_addr,
3055             external_port=external_port,
3056             local=local,
3057             protocol=IP_PROTOS.tcp)
3058         server1_n = 0
3059         server2_n = 0
3060         server3_n = 0
3061         self.pg1.add_stream(pkts)
3062         self.pg_enable_capture(self.pg_interfaces)
3063         self.pg_start()
3064         capture = self.pg0.get_capture(len(pkts))
3065         for p in capture:
3066             if p[IP].dst == server1.ip4:
3067                 server1_n += 1
3068             elif p[IP].dst == server2.ip4:
3069                 server2_n += 1
3070             else:
3071                 server3_n += 1
3072         self.assertGreater(server1_n, 0)
3073         self.assertEqual(server2_n, 0)
3074         self.assertGreater(server3_n, 0)
3075
3076     # put zzz in front of syslog test name so that it runs as a last test
3077     # setting syslog sender cannot be undone and if it is set, it messes
3078     # with self.send_and_assert_no_replies functionality
3079     def test_zzz_syslog_sess(self):
3080         """ NAT44ED Test syslog session creation and deletion """
3081         self.vapi.syslog_set_filter(
3082             self.syslog_severity.SYSLOG_API_SEVERITY_INFO)
3083         self.vapi.syslog_set_sender(self.pg3.local_ip4, self.pg3.remote_ip4)
3084
3085         self.nat_add_address(self.nat_addr)
3086         self.nat_add_inside_interface(self.pg0)
3087         self.nat_add_outside_interface(self.pg1)
3088
3089         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
3090              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3091              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port))
3092         self.pg0.add_stream(p)
3093         self.pg_enable_capture(self.pg_interfaces)
3094         self.pg_start()
3095         capture = self.pg1.get_capture(1)
3096         self.tcp_port_out = capture[0][TCP].sport
3097         capture = self.pg3.get_capture(1)
3098         self.verify_syslog_sess(capture[0][Raw].load, 'SADD')
3099
3100         self.pg_enable_capture(self.pg_interfaces)
3101         self.pg_start()
3102         self.nat_add_address(self.nat_addr, is_add=0)
3103         capture = self.pg3.get_capture(1)
3104         self.verify_syslog_sess(capture[0][Raw].load, 'SDEL')
3105
3106     # put zzz in front of syslog test name so that it runs as a last test
3107     # setting syslog sender cannot be undone and if it is set, it messes
3108     # with self.send_and_assert_no_replies functionality
3109     def test_zzz_syslog_sess_reopen(self):
3110         """ Syslog events for session reopen """
3111         self.vapi.syslog_set_filter(
3112             self.syslog_severity.SYSLOG_API_SEVERITY_INFO)
3113         self.vapi.syslog_set_sender(self.pg3.local_ip4, self.pg3.remote_ip4)
3114
3115         self.nat_add_address(self.nat_addr)
3116         self.nat_add_inside_interface(self.pg0)
3117         self.nat_add_outside_interface(self.pg1)
3118
3119         # SYN in2out
3120         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
3121              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3122              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port))
3123         capture = self.send_and_expect(self.pg0, p, self.pg1)[0]
3124         self.tcp_port_out = capture[0][TCP].sport
3125         capture = self.pg3.get_capture(1)
3126         self.verify_syslog_sess(capture[0][Raw].load, 'SADD')
3127
3128         # SYN out2in
3129         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
3130              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
3131              TCP(sport=self.tcp_external_port, dport=self.tcp_port_out))
3132         self.send_and_expect(self.pg1, p, self.pg0)
3133
3134         # FIN in2out
3135         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
3136              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3137              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
3138                  flags="F"))
3139         self.send_and_expect(self.pg0, p, self.pg1)
3140
3141         # FIN out2in
3142         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
3143              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
3144              TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
3145                  flags="F"))
3146         self.send_and_expect(self.pg1, p, self.pg0)
3147
3148         # SYN in2out
3149         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
3150              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3151              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port))
3152         self.send_and_expect(self.pg0, p, self.pg1)
3153
3154         # SYN out2in
3155         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
3156              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
3157              TCP(sport=self.tcp_external_port, dport=self.tcp_port_out))
3158         self.send_and_expect(self.pg1, p, self.pg0)
3159
3160         # 2 records should be produced - first one del & add
3161         capture = self.pg3.get_capture(2)
3162         self.verify_syslog_sess(capture[0][Raw].load, 'SDEL')
3163         self.verify_syslog_sess(capture[1][Raw].load, 'SADD')
3164
3165     def test_twice_nat_interface_addr(self):
3166         """ NAT44ED Acquire twice NAT addresses from interface """
3167         flags = self.config_flags.NAT_IS_TWICE_NAT
3168         self.vapi.nat44_add_del_interface_addr(
3169             sw_if_index=self.pg11.sw_if_index,
3170             flags=flags, is_add=1)
3171
3172         # no address in NAT pool
3173         adresses = self.vapi.nat44_address_dump()
3174         self.assertEqual(0, len(adresses))
3175
3176         # configure interface address and check NAT address pool
3177         self.pg11.config_ip4()
3178         adresses = self.vapi.nat44_address_dump()
3179         self.assertEqual(1, len(adresses))
3180         self.assertEqual(str(adresses[0].ip_address),
3181                          self.pg11.local_ip4)
3182         self.assertEqual(adresses[0].flags, flags)
3183
3184         # remove interface address and check NAT address pool
3185         self.pg11.unconfig_ip4()
3186         adresses = self.vapi.nat44_address_dump()
3187         self.assertEqual(0, len(adresses))
3188
3189     def test_output_feature_stateful_acl(self):
3190         """ NAT44ED output feature works with stateful ACL """
3191
3192         self.nat_add_address(self.nat_addr)
3193         self.vapi.nat44_ed_add_del_output_interface(
3194             sw_if_index=self.pg1.sw_if_index, is_add=1)
3195
3196         # First ensure that the NAT is working sans ACL
3197
3198         # send packets out2in, no sessions yet so packets should drop
3199         pkts_out2in = self.create_stream_out(self.pg1)
3200         self.send_and_assert_no_replies(self.pg1, pkts_out2in)
3201
3202         # send packets into inside intf, ensure received via outside intf
3203         pkts_in2out = self.create_stream_in(self.pg0, self.pg1)
3204         capture = self.send_and_expect(self.pg0, pkts_in2out, self.pg1,
3205                                        len(pkts_in2out))
3206         self.verify_capture_out(capture, ignore_port=True)
3207
3208         # send out2in again, with sessions created it should work now
3209         pkts_out2in = self.create_stream_out(self.pg1)
3210         capture = self.send_and_expect(self.pg1, pkts_out2in, self.pg0,
3211                                        len(pkts_out2in))
3212         self.verify_capture_in(capture, self.pg0)
3213
3214         # Create an ACL blocking everything
3215         out2in_deny_rule = AclRule(is_permit=0)
3216         out2in_acl = VppAcl(self, rules=[out2in_deny_rule])
3217         out2in_acl.add_vpp_config()
3218
3219         # create an ACL to permit/reflect everything
3220         in2out_reflect_rule = AclRule(is_permit=2)
3221         in2out_acl = VppAcl(self, rules=[in2out_reflect_rule])
3222         in2out_acl.add_vpp_config()
3223
3224         # apply as input acl on interface and confirm it blocks everything
3225         acl_if = VppAclInterface(self, sw_if_index=self.pg1.sw_if_index,
3226                                  n_input=1, acls=[out2in_acl])
3227         acl_if.add_vpp_config()
3228         self.send_and_assert_no_replies(self.pg1, pkts_out2in)
3229
3230         # apply output acl
3231         acl_if.acls = [out2in_acl, in2out_acl]
3232         acl_if.add_vpp_config()
3233         # send in2out to generate ACL state (NAT state was created earlier)
3234         capture = self.send_and_expect(self.pg0, pkts_in2out, self.pg1,
3235                                        len(pkts_in2out))
3236         self.verify_capture_out(capture, ignore_port=True)
3237
3238         # send out2in again. ACL state exists so it should work now.
3239         # TCP packets with the syn flag set also need the ack flag
3240         for p in pkts_out2in:
3241             if p.haslayer(TCP) and p[TCP].flags & 0x02:
3242                 p[TCP].flags |= 0x10
3243         capture = self.send_and_expect(self.pg1, pkts_out2in, self.pg0,
3244                                        len(pkts_out2in))
3245         self.verify_capture_in(capture, self.pg0)
3246         self.logger.info(self.vapi.cli("show trace"))
3247
3248     def test_tcp_close(self):
3249         """ NAT44ED Close TCP session from inside network - output feature """
3250         old_timeouts = self.vapi.nat_get_timeouts()
3251         new_transitory = 2
3252         self.vapi.nat_set_timeouts(
3253             udp=old_timeouts.udp,
3254             tcp_established=old_timeouts.tcp_established,
3255             icmp=old_timeouts.icmp,
3256             tcp_transitory=new_transitory)
3257
3258         self.vapi.nat44_forwarding_enable_disable(enable=1)
3259         self.nat_add_address(self.pg1.local_ip4)
3260         twice_nat_addr = '10.0.1.3'
3261         service_ip = '192.168.16.150'
3262         self.nat_add_address(twice_nat_addr, twice_nat=1)
3263
3264         flags = self.config_flags.NAT_IS_INSIDE
3265         self.vapi.nat44_interface_add_del_feature(
3266             sw_if_index=self.pg0.sw_if_index,
3267             is_add=1)
3268         self.vapi.nat44_interface_add_del_feature(
3269             sw_if_index=self.pg0.sw_if_index,
3270             flags=flags, is_add=1)
3271         self.vapi.nat44_ed_add_del_output_interface(
3272             is_add=1,
3273             sw_if_index=self.pg1.sw_if_index)
3274
3275         flags = (self.config_flags.NAT_IS_OUT2IN_ONLY |
3276                  self.config_flags.NAT_IS_TWICE_NAT)
3277         self.nat_add_static_mapping(self.pg0.remote_ip4,
3278                                     service_ip, 80, 80,
3279                                     proto=IP_PROTOS.tcp,
3280                                     flags=flags)
3281         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
3282         start_sessnum = len(sessions)
3283
3284         # SYN packet out->in
3285         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
3286              IP(src=self.pg1.remote_ip4, dst=service_ip) /
3287              TCP(sport=33898, dport=80, flags="S"))
3288         capture = self.send_and_expect(self.pg1, p, self.pg0, n_rx=1)
3289         p = capture[0]
3290         tcp_port = p[TCP].sport
3291
3292         # SYN + ACK packet in->out
3293         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
3294              IP(src=self.pg0.remote_ip4, dst=twice_nat_addr) /
3295              TCP(sport=80, dport=tcp_port, flags="SA"))
3296         self.send_and_expect(self.pg0, p, self.pg1, n_rx=1)
3297
3298         # ACK packet out->in
3299         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
3300              IP(src=self.pg1.remote_ip4, dst=service_ip) /
3301              TCP(sport=33898, dport=80, flags="A"))
3302         self.send_and_expect(self.pg1, p, self.pg0, n_rx=1)
3303
3304         # FIN packet in -> out
3305         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
3306              IP(src=self.pg0.remote_ip4, dst=twice_nat_addr) /
3307              TCP(sport=80, dport=tcp_port, flags="FA", seq=100, ack=300))
3308         self.send_and_expect(self.pg0, p, self.pg1, n_rx=1)
3309
3310         # FIN+ACK packet out -> in
3311         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
3312              IP(src=self.pg1.remote_ip4, dst=service_ip) /
3313              TCP(sport=33898, dport=80, flags="FA", seq=300, ack=101))
3314         self.send_and_expect(self.pg1, p, self.pg0, n_rx=1)
3315
3316         # ACK packet in -> out
3317         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
3318              IP(src=self.pg0.remote_ip4, dst=twice_nat_addr) /
3319              TCP(sport=80, dport=tcp_port, flags="A", seq=101, ack=301))
3320         self.send_and_expect(self.pg0, p, self.pg1, n_rx=1)
3321
3322         # session now in transitory timeout, but traffic still flows
3323         # try FIN packet out->in
3324         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
3325              IP(src=self.pg1.remote_ip4, dst=service_ip) /
3326              TCP(sport=33898, dport=80, flags="F"))
3327         self.pg1.add_stream(p)
3328         self.pg_enable_capture(self.pg_interfaces)
3329         self.pg_start()
3330
3331         self.virtual_sleep(new_transitory, "wait for transitory timeout")
3332         self.pg0.get_capture(1)
3333
3334         # session should still exist
3335         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
3336         self.assertEqual(len(sessions) - start_sessnum, 1)
3337
3338         # send FIN+ACK packet out -> in - will cause session to be wiped
3339         # but won't create a new session
3340         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
3341              IP(src=self.pg1.remote_ip4, dst=service_ip) /
3342              TCP(sport=33898, dport=80, flags="FA", seq=300, ack=101))
3343         self.send_and_assert_no_replies(self.pg1, p)
3344         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
3345         self.assertEqual(len(sessions) - start_sessnum, 0)
3346
3347     def test_tcp_session_close_in(self):
3348         """ NAT44ED Close TCP session from inside network """
3349
3350         in_port = self.tcp_port_in
3351         out_port = 10505
3352         ext_port = self.tcp_external_port
3353
3354         self.nat_add_address(self.nat_addr)
3355         self.nat_add_inside_interface(self.pg0)
3356         self.nat_add_outside_interface(self.pg1)
3357         self.nat_add_static_mapping(self.pg0.remote_ip4, self.nat_addr,
3358                                     in_port, out_port, proto=IP_PROTOS.tcp,
3359                                     flags=self.config_flags.NAT_IS_TWICE_NAT)
3360
3361         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
3362         session_n = len(sessions)
3363
3364         self.vapi.nat_set_timeouts(udp=300, tcp_established=7440,
3365                                    tcp_transitory=2, icmp=5)
3366
3367         self.init_tcp_session(self.pg0, self.pg1, in_port, ext_port)
3368
3369         # FIN packet in -> out
3370         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
3371              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3372              TCP(sport=in_port, dport=ext_port,
3373                  flags="FA", seq=100, ack=300))
3374         self.send_and_expect(self.pg0, p, self.pg1)
3375         pkts = []
3376
3377         # ACK packet out -> in
3378         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
3379              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
3380              TCP(sport=ext_port, dport=out_port,
3381                  flags="A", seq=300, ack=101))
3382         pkts.append(p)
3383
3384         # FIN packet out -> in
3385         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
3386              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
3387              TCP(sport=ext_port, dport=out_port,
3388                  flags="FA", seq=300, ack=101))
3389         pkts.append(p)
3390
3391         self.send_and_expect(self.pg1, pkts, self.pg0)
3392
3393         # ACK packet in -> out
3394         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
3395              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3396              TCP(sport=in_port, dport=ext_port,
3397                  flags="A", seq=101, ack=301))
3398         self.send_and_expect(self.pg0, p, self.pg1)
3399
3400         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
3401         self.assertEqual(len(sessions) - session_n, 1)
3402
3403         # retransmit FIN packet out -> in
3404         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
3405              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
3406              TCP(sport=ext_port, dport=out_port,
3407                  flags="FA", seq=300, ack=101))
3408
3409         self.send_and_expect(self.pg1, p, self.pg0)
3410
3411         # retransmit ACK packet in -> out
3412         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
3413              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3414              TCP(sport=in_port, dport=ext_port,
3415                  flags="A", seq=101, ack=301))
3416         self.send_and_expect(self.pg0, p, self.pg1)
3417
3418         self.virtual_sleep(3)
3419         # retransmit ACK packet in -> out - this will cause session to be wiped
3420         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
3421              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3422              TCP(sport=in_port, dport=ext_port,
3423                  flags="A", seq=101, ack=301))
3424         self.send_and_assert_no_replies(self.pg0, p)
3425         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
3426         self.assertEqual(len(sessions) - session_n, 0)
3427
3428     def test_tcp_session_close_out(self):
3429         """ NAT44ED Close TCP session from outside network """
3430
3431         in_port = self.tcp_port_in
3432         out_port = 10505
3433         ext_port = self.tcp_external_port
3434
3435         self.nat_add_address(self.nat_addr)
3436         self.nat_add_inside_interface(self.pg0)
3437         self.nat_add_outside_interface(self.pg1)
3438         self.nat_add_static_mapping(self.pg0.remote_ip4, self.nat_addr,
3439                                     in_port, out_port, proto=IP_PROTOS.tcp,
3440                                     flags=self.config_flags.NAT_IS_TWICE_NAT)
3441
3442         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
3443         session_n = len(sessions)
3444
3445         self.vapi.nat_set_timeouts(udp=300, tcp_established=7440,
3446                                    tcp_transitory=2, icmp=5)
3447
3448         _ = self.init_tcp_session(self.pg0, self.pg1, in_port, ext_port)
3449
3450         # FIN packet out -> in
3451         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
3452              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
3453              TCP(sport=ext_port, dport=out_port,
3454                  flags="FA", seq=100, ack=300))
3455         self.pg1.add_stream(p)
3456         self.pg_enable_capture(self.pg_interfaces)
3457         self.pg_start()
3458         self.pg0.get_capture(1)
3459
3460         # FIN+ACK packet in -> out
3461         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
3462              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3463              TCP(sport=in_port, dport=ext_port,
3464                  flags="FA", seq=300, ack=101))
3465
3466         self.pg0.add_stream(p)
3467         self.pg_enable_capture(self.pg_interfaces)
3468         self.pg_start()
3469         self.pg1.get_capture(1)
3470
3471         # ACK packet out -> in
3472         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
3473              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
3474              TCP(sport=ext_port, dport=out_port,
3475                  flags="A", seq=101, ack=301))
3476         self.pg1.add_stream(p)
3477         self.pg_enable_capture(self.pg_interfaces)
3478         self.pg_start()
3479         self.pg0.get_capture(1)
3480
3481         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
3482         self.assertEqual(len(sessions) - session_n, 1)
3483
3484         # retransmit FIN packet out -> in
3485         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
3486              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
3487              TCP(sport=ext_port, dport=out_port,
3488                  flags="FA", seq=300, ack=101))
3489         self.send_and_expect(self.pg1, p, self.pg0)
3490
3491         # retransmit ACK packet in -> out
3492         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
3493              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3494              TCP(sport=in_port, dport=ext_port,
3495                  flags="A", seq=101, ack=301))
3496         self.send_and_expect(self.pg0, p, self.pg1)
3497
3498         self.virtual_sleep(3)
3499         # retransmit ACK packet in -> out - this will cause session to be wiped
3500         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
3501              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3502              TCP(sport=in_port, dport=ext_port,
3503                  flags="A", seq=101, ack=301))
3504         self.send_and_assert_no_replies(self.pg0, p)
3505         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
3506         self.assertEqual(len(sessions) - session_n, 0)
3507
3508     def test_tcp_session_close_simultaneous(self):
3509         """ Simultaneous TCP close from both sides """
3510
3511         in_port = self.tcp_port_in
3512         ext_port = 10505
3513
3514         self.nat_add_address(self.nat_addr)
3515         self.nat_add_inside_interface(self.pg0)
3516         self.nat_add_outside_interface(self.pg1)
3517         self.nat_add_static_mapping(self.pg0.remote_ip4, self.nat_addr,
3518                                     in_port, ext_port, proto=IP_PROTOS.tcp,
3519                                     flags=self.config_flags.NAT_IS_TWICE_NAT)
3520
3521         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
3522         session_n = len(sessions)
3523
3524         self.vapi.nat_set_timeouts(udp=300, tcp_established=7440,
3525                                    tcp_transitory=2, icmp=5)
3526
3527         out_port = self.init_tcp_session(self.pg0, self.pg1, in_port, ext_port)
3528
3529         # FIN packet in -> out
3530         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
3531              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3532              TCP(sport=in_port, dport=ext_port,
3533                  flags="FA", seq=100, ack=300))
3534         self.send_and_expect(self.pg0, p, self.pg1)
3535
3536         # FIN packet out -> in
3537         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
3538              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
3539              TCP(sport=ext_port, dport=out_port,
3540                  flags="FA", seq=300, ack=100))
3541         self.send_and_expect(self.pg1, p, self.pg0)
3542
3543         # ACK packet in -> out
3544         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
3545              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3546              TCP(sport=in_port, dport=ext_port,
3547                  flags="A", seq=101, ack=301))
3548         self.send_and_expect(self.pg0, p, self.pg1)
3549
3550         # ACK packet out -> in
3551         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
3552              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
3553              TCP(sport=ext_port, dport=out_port,
3554                  flags="A", seq=301, ack=101))
3555         self.send_and_expect(self.pg1, p, self.pg0)
3556
3557         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
3558         self.assertEqual(len(sessions) - session_n, 1)
3559
3560         # retransmit FIN packet out -> in
3561         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
3562              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
3563              TCP(sport=ext_port, dport=out_port,
3564                  flags="FA", seq=300, ack=101))
3565         self.send_and_expect(self.pg1, p, self.pg0)
3566
3567         # retransmit ACK packet in -> out
3568         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
3569              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3570              TCP(sport=in_port, dport=ext_port,
3571                  flags="A", seq=101, ack=301))
3572         self.send_and_expect(self.pg0, p, self.pg1)
3573
3574         self.virtual_sleep(3)
3575         # retransmit ACK packet in -> out - this will cause session to be wiped
3576         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
3577              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3578              TCP(sport=in_port, dport=ext_port,
3579                  flags="A", seq=101, ack=301))
3580         self.pg_send(self.pg0, p)
3581         self.send_and_assert_no_replies(self.pg0, p)
3582         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
3583         self.assertEqual(len(sessions) - session_n, 0)
3584
3585     def test_tcp_session_half_reopen_inside(self):
3586         """ TCP session in FIN/FIN state not reopened by in2out SYN only """
3587         in_port = self.tcp_port_in
3588         ext_port = 10505
3589
3590         self.nat_add_address(self.nat_addr)
3591         self.nat_add_inside_interface(self.pg0)
3592         self.nat_add_outside_interface(self.pg1)
3593         self.nat_add_static_mapping(self.pg0.remote_ip4, self.nat_addr,
3594                                     in_port, ext_port, proto=IP_PROTOS.tcp,
3595                                     flags=self.config_flags.NAT_IS_TWICE_NAT)
3596
3597         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
3598         session_n = len(sessions)
3599
3600         self.vapi.nat_set_timeouts(udp=300, tcp_established=7440,
3601                                    tcp_transitory=2, icmp=5)
3602
3603         out_port = self.init_tcp_session(self.pg0, self.pg1, in_port, ext_port)
3604
3605         # FIN packet in -> out
3606         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
3607              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3608              TCP(sport=in_port, dport=ext_port,
3609                  flags="FA", seq=100, ack=300))
3610         self.send_and_expect(self.pg0, p, self.pg1)
3611
3612         # FIN packet out -> in
3613         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
3614              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
3615              TCP(sport=ext_port, dport=out_port,
3616                  flags="FA", seq=300, ack=100))
3617         self.send_and_expect(self.pg1, p, self.pg0)
3618
3619         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
3620         self.assertEqual(len(sessions) - session_n, 1)
3621
3622         # send SYN packet in -> out
3623         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
3624              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3625              TCP(sport=in_port, dport=ext_port,
3626                  flags="S", seq=101, ack=301))
3627         self.send_and_expect(self.pg0, p, self.pg1)
3628
3629         self.virtual_sleep(3)
3630         # send ACK packet in -> out - session should be wiped
3631         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
3632              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3633              TCP(sport=in_port, dport=ext_port,
3634                  flags="A", seq=101, ack=301))
3635         self.send_and_assert_no_replies(self.pg0, p, self.pg1)
3636         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
3637         self.assertEqual(len(sessions) - session_n, 0)
3638
3639     def test_tcp_session_half_reopen_outside(self):
3640         """ TCP session in FIN/FIN state not reopened by out2in SYN only """
3641         in_port = self.tcp_port_in
3642         ext_port = 10505
3643
3644         self.nat_add_address(self.nat_addr)
3645         self.nat_add_inside_interface(self.pg0)
3646         self.nat_add_outside_interface(self.pg1)
3647         self.nat_add_static_mapping(self.pg0.remote_ip4, self.nat_addr,
3648                                     in_port, ext_port, proto=IP_PROTOS.tcp,
3649                                     flags=self.config_flags.NAT_IS_TWICE_NAT)
3650
3651         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
3652         session_n = len(sessions)
3653
3654         self.vapi.nat_set_timeouts(udp=300, tcp_established=7440,
3655                                    tcp_transitory=2, icmp=5)
3656
3657         out_port = self.init_tcp_session(self.pg0, self.pg1, in_port, ext_port)
3658
3659         # FIN packet in -> out
3660         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
3661              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3662              TCP(sport=in_port, dport=ext_port,
3663                  flags="FA", seq=100, ack=300))
3664         self.send_and_expect(self.pg0, p, self.pg1)
3665
3666         # FIN packet out -> in
3667         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
3668              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
3669              TCP(sport=ext_port, dport=out_port,
3670                  flags="FA", seq=300, ack=100))
3671         self.send_and_expect(self.pg1, p, self.pg0)
3672
3673         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
3674         self.assertEqual(len(sessions) - session_n, 1)
3675
3676         # send SYN packet out -> in
3677         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
3678              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
3679              TCP(sport=ext_port, dport=out_port,
3680                  flags="S", seq=300, ack=101))
3681         self.send_and_expect(self.pg1, p, self.pg0)
3682
3683         self.virtual_sleep(3)
3684         # send ACK packet in -> out - session should be wiped
3685         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
3686              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3687              TCP(sport=in_port, dport=ext_port,
3688                  flags="A", seq=101, ack=301))
3689         self.send_and_assert_no_replies(self.pg0, p, self.pg1)
3690         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
3691         self.assertEqual(len(sessions) - session_n, 0)
3692
3693     def test_tcp_session_reopen(self):
3694         """ TCP session in FIN/FIN state reopened by SYN from both sides """
3695         in_port = self.tcp_port_in
3696         ext_port = 10505
3697
3698         self.nat_add_address(self.nat_addr)
3699         self.nat_add_inside_interface(self.pg0)
3700         self.nat_add_outside_interface(self.pg1)
3701         self.nat_add_static_mapping(self.pg0.remote_ip4, self.nat_addr,
3702                                     in_port, ext_port, proto=IP_PROTOS.tcp,
3703                                     flags=self.config_flags.NAT_IS_TWICE_NAT)
3704
3705         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
3706         session_n = len(sessions)
3707
3708         self.vapi.nat_set_timeouts(udp=300, tcp_established=7440,
3709                                    tcp_transitory=2, icmp=5)
3710
3711         out_port = self.init_tcp_session(self.pg0, self.pg1, in_port, ext_port)
3712
3713         # FIN packet in -> out
3714         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
3715              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3716              TCP(sport=in_port, dport=ext_port,
3717                  flags="FA", seq=100, ack=300))
3718         self.send_and_expect(self.pg0, p, self.pg1)
3719
3720         # FIN packet out -> in
3721         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
3722              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
3723              TCP(sport=ext_port, dport=out_port,
3724                  flags="FA", seq=300, ack=100))
3725         self.send_and_expect(self.pg1, p, self.pg0)
3726
3727         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
3728         self.assertEqual(len(sessions) - session_n, 1)
3729
3730         # send SYN packet out -> in
3731         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
3732              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
3733              TCP(sport=ext_port, dport=out_port,
3734                  flags="S", seq=300, ack=101))
3735         self.send_and_expect(self.pg1, p, self.pg0)
3736
3737         # send SYN packet in -> out
3738         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
3739              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3740              TCP(sport=in_port, dport=ext_port,
3741                  flags="S", seq=101, ack=301))
3742         self.send_and_expect(self.pg0, p, self.pg1)
3743
3744         self.virtual_sleep(3)
3745         # send ACK packet in -> out - should be forwarded and session alive
3746         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
3747              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3748              TCP(sport=in_port, dport=ext_port,
3749                  flags="A", seq=101, ack=301))
3750         self.send_and_expect(self.pg0, p, self.pg1)
3751         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
3752         self.assertEqual(len(sessions) - session_n, 1)
3753
3754     def test_dynamic_vrf(self):
3755         """ NAT44ED dynamic translation test: different VRF"""
3756
3757         vrf_id_in = 33
3758         vrf_id_out = 34
3759
3760         self.nat_add_address(self.nat_addr, vrf_id=vrf_id_in)
3761
3762         try:
3763             self.configure_ip4_interface(self.pg7, table_id=vrf_id_in)
3764             self.configure_ip4_interface(self.pg8, table_id=vrf_id_out)
3765
3766             self.nat_add_inside_interface(self.pg7)
3767             self.nat_add_outside_interface(self.pg8)
3768
3769             # just basic stuff nothing special
3770             pkts = self.create_stream_in(self.pg7, self.pg8)
3771             self.pg7.add_stream(pkts)
3772             self.pg_enable_capture(self.pg_interfaces)
3773             self.pg_start()
3774             capture = self.pg8.get_capture(len(pkts))
3775             self.verify_capture_out(capture, ignore_port=True)
3776
3777             pkts = self.create_stream_out(self.pg8)
3778             self.pg8.add_stream(pkts)
3779             self.pg_enable_capture(self.pg_interfaces)
3780             self.pg_start()
3781             capture = self.pg7.get_capture(len(pkts))
3782             self.verify_capture_in(capture, self.pg7)
3783
3784         finally:
3785             self.pg7.unconfig()
3786             self.pg8.unconfig()
3787
3788             self.vapi.ip_table_add_del(is_add=0,
3789                                        table={'table_id': vrf_id_in})
3790             self.vapi.ip_table_add_del(is_add=0,
3791                                        table={'table_id': vrf_id_out})
3792
3793     def test_dynamic_output_feature_vrf(self):
3794         """ NAT44ED dynamic translation test: output-feature, VRF"""
3795
3796         # other then default (0)
3797         new_vrf_id = 22
3798
3799         self.nat_add_address(self.nat_addr)
3800         self.vapi.nat44_interface_add_del_output_feature(
3801             sw_if_index=self.pg8.sw_if_index, is_add=1)
3802
3803         try:
3804             self.configure_ip4_interface(self.pg7, table_id=new_vrf_id)
3805             self.configure_ip4_interface(self.pg8, table_id=new_vrf_id)
3806
3807             # in2out
3808             tcpn = self.statistics['/nat44-ed/in2out/slowpath/tcp']
3809             udpn = self.statistics['/nat44-ed/in2out/slowpath/udp']
3810             icmpn = self.statistics['/nat44-ed/in2out/slowpath/icmp']
3811             drops = self.statistics['/nat44-ed/in2out/slowpath/drops']
3812
3813             pkts = self.create_stream_in(self.pg7, self.pg8)
3814             self.pg7.add_stream(pkts)
3815             self.pg_enable_capture(self.pg_interfaces)
3816             self.pg_start()
3817             capture = self.pg8.get_capture(len(pkts))
3818             self.verify_capture_out(capture, ignore_port=True)
3819
3820             if_idx = self.pg8.sw_if_index
3821             cnt = self.statistics['/nat44-ed/in2out/slowpath/tcp']
3822             self.assertEqual(cnt[:, if_idx].sum() - tcpn[:, if_idx].sum(), 2)
3823             cnt = self.statistics['/nat44-ed/in2out/slowpath/udp']
3824             self.assertEqual(cnt[:, if_idx].sum() - udpn[:, if_idx].sum(), 1)
3825             cnt = self.statistics['/nat44-ed/in2out/slowpath/icmp']
3826             self.assertEqual(cnt[:, if_idx].sum() - icmpn[:, if_idx].sum(), 1)
3827             cnt = self.statistics['/nat44-ed/in2out/slowpath/drops']
3828             self.assertEqual(cnt[:, if_idx].sum() - drops[:, if_idx].sum(), 0)
3829
3830             # out2in
3831             tcpn = self.statistics['/nat44-ed/out2in/fastpath/tcp']
3832             udpn = self.statistics['/nat44-ed/out2in/fastpath/udp']
3833             icmpn = self.statistics['/nat44-ed/out2in/fastpath/icmp']
3834             drops = self.statistics['/nat44-ed/out2in/fastpath/drops']
3835
3836             pkts = self.create_stream_out(self.pg8)
3837             self.pg8.add_stream(pkts)
3838             self.pg_enable_capture(self.pg_interfaces)
3839             self.pg_start()
3840             capture = self.pg7.get_capture(len(pkts))
3841             self.verify_capture_in(capture, self.pg7)
3842
3843             if_idx = self.pg8.sw_if_index
3844             cnt = self.statistics['/nat44-ed/out2in/fastpath/tcp']
3845             self.assertEqual(cnt[:, if_idx].sum() - tcpn[:, if_idx].sum(), 2)
3846             cnt = self.statistics['/nat44-ed/out2in/fastpath/udp']
3847             self.assertEqual(cnt[:, if_idx].sum() - udpn[:, if_idx].sum(), 1)
3848             cnt = self.statistics['/nat44-ed/out2in/fastpath/icmp']
3849             self.assertEqual(cnt[:, if_idx].sum() - icmpn[:, if_idx].sum(), 1)
3850             cnt = self.statistics['/nat44-ed/out2in/fastpath/drops']
3851             self.assertEqual(cnt[:, if_idx].sum() - drops[:, if_idx].sum(), 0)
3852
3853             sessions = self.statistics['/nat44-ed/total-sessions']
3854             self.assertEqual(sessions[:, 0].sum(), 3)
3855
3856         finally:
3857             self.pg7.unconfig()
3858             self.pg8.unconfig()
3859
3860             self.vapi.ip_table_add_del(is_add=0,
3861                                        table={'table_id': new_vrf_id})
3862
3863     def test_next_src_nat(self):
3864         """ NAT44ED On way back forward packet to nat44-in2out node. """
3865
3866         twice_nat_addr = '10.0.1.3'
3867         external_port = 80
3868         local_port = 8080
3869         post_twice_nat_port = 0
3870
3871         self.vapi.nat44_forwarding_enable_disable(enable=1)
3872         self.nat_add_address(twice_nat_addr, twice_nat=1)
3873         flags = (self.config_flags.NAT_IS_OUT2IN_ONLY |
3874                  self.config_flags.NAT_IS_SELF_TWICE_NAT)
3875         self.nat_add_static_mapping(self.pg6.remote_ip4, self.pg1.remote_ip4,
3876                                     local_port, external_port,
3877                                     proto=IP_PROTOS.tcp, vrf_id=1,
3878                                     flags=flags)
3879         self.vapi.nat44_interface_add_del_feature(
3880             sw_if_index=self.pg6.sw_if_index,
3881             is_add=1)
3882
3883         p = (Ether(src=self.pg6.remote_mac, dst=self.pg6.local_mac) /
3884              IP(src=self.pg6.remote_ip4, dst=self.pg1.remote_ip4) /
3885              TCP(sport=12345, dport=external_port))
3886         self.pg6.add_stream(p)
3887         self.pg_enable_capture(self.pg_interfaces)
3888         self.pg_start()
3889         capture = self.pg6.get_capture(1)
3890         p = capture[0]
3891         try:
3892             ip = p[IP]
3893             tcp = p[TCP]
3894             self.assertEqual(ip.src, twice_nat_addr)
3895             self.assertNotEqual(tcp.sport, 12345)
3896             post_twice_nat_port = tcp.sport
3897             self.assertEqual(ip.dst, self.pg6.remote_ip4)
3898             self.assertEqual(tcp.dport, local_port)
3899             self.assert_packet_checksums_valid(p)
3900         except:
3901             self.logger.error(ppp("Unexpected or invalid packet:", p))
3902             raise
3903
3904         p = (Ether(src=self.pg6.remote_mac, dst=self.pg6.local_mac) /
3905              IP(src=self.pg6.remote_ip4, dst=twice_nat_addr) /
3906              TCP(sport=local_port, dport=post_twice_nat_port))
3907         self.pg6.add_stream(p)
3908         self.pg_enable_capture(self.pg_interfaces)
3909         self.pg_start()
3910         capture = self.pg6.get_capture(1)
3911         p = capture[0]
3912         try:
3913             ip = p[IP]
3914             tcp = p[TCP]
3915             self.assertEqual(ip.src, self.pg1.remote_ip4)
3916             self.assertEqual(tcp.sport, external_port)
3917             self.assertEqual(ip.dst, self.pg6.remote_ip4)
3918             self.assertEqual(tcp.dport, 12345)
3919             self.assert_packet_checksums_valid(p)
3920         except:
3921             self.logger.error(ppp("Unexpected or invalid packet:", p))
3922             raise
3923
3924     def test_one_armed_nat44_static(self):
3925         """ NAT44ED One armed NAT and 1:1 NAPT asymmetrical rule """
3926
3927         remote_host = self.pg4.remote_hosts[0]
3928         local_host = self.pg4.remote_hosts[1]
3929         external_port = 80
3930         local_port = 8080
3931         eh_port_in = 0
3932
3933         self.vapi.nat44_forwarding_enable_disable(enable=1)
3934         self.nat_add_address(self.nat_addr, twice_nat=1)
3935         flags = (self.config_flags.NAT_IS_OUT2IN_ONLY |
3936                  self.config_flags.NAT_IS_TWICE_NAT)
3937         self.nat_add_static_mapping(local_host.ip4, self.nat_addr,
3938                                     local_port, external_port,
3939                                     proto=IP_PROTOS.tcp, flags=flags)
3940         flags = self.config_flags.NAT_IS_INSIDE
3941         self.vapi.nat44_interface_add_del_feature(
3942             sw_if_index=self.pg4.sw_if_index,
3943             is_add=1)
3944         self.vapi.nat44_interface_add_del_feature(
3945             sw_if_index=self.pg4.sw_if_index,
3946             flags=flags, is_add=1)
3947
3948         # from client to service
3949         p = (Ether(src=self.pg4.remote_mac, dst=self.pg4.local_mac) /
3950              IP(src=remote_host.ip4, dst=self.nat_addr) /
3951              TCP(sport=12345, dport=external_port))
3952         self.pg4.add_stream(p)
3953         self.pg_enable_capture(self.pg_interfaces)
3954         self.pg_start()
3955         capture = self.pg4.get_capture(1)
3956         p = capture[0]
3957         try:
3958             ip = p[IP]
3959             tcp = p[TCP]
3960             self.assertEqual(ip.dst, local_host.ip4)
3961             self.assertEqual(ip.src, self.nat_addr)
3962             self.assertEqual(tcp.dport, local_port)
3963             self.assertNotEqual(tcp.sport, 12345)
3964             eh_port_in = tcp.sport
3965             self.assert_packet_checksums_valid(p)
3966         except:
3967             self.logger.error(ppp("Unexpected or invalid packet:", p))
3968             raise
3969
3970         # from service back to client
3971         p = (Ether(src=self.pg4.remote_mac, dst=self.pg4.local_mac) /
3972              IP(src=local_host.ip4, dst=self.nat_addr) /
3973              TCP(sport=local_port, dport=eh_port_in))
3974         self.pg4.add_stream(p)
3975         self.pg_enable_capture(self.pg_interfaces)
3976         self.pg_start()
3977         capture = self.pg4.get_capture(1)
3978         p = capture[0]
3979         try:
3980             ip = p[IP]
3981             tcp = p[TCP]
3982             self.assertEqual(ip.src, self.nat_addr)
3983             self.assertEqual(ip.dst, remote_host.ip4)
3984             self.assertEqual(tcp.sport, external_port)
3985             self.assertEqual(tcp.dport, 12345)
3986             self.assert_packet_checksums_valid(p)
3987         except:
3988             self.logger.error(ppp("Unexpected or invalid packet:", p))
3989             raise
3990
3991     def test_icmp_error_fwd_outbound(self):
3992         """ NAT44ED ICMP error outbound with forwarding enabled """
3993
3994         # Ensure that an outbound ICMP error message is properly associated
3995         # with the inbound forward bypass session it is related to.
3996         payload = "H" * 10
3997
3998         self.nat_add_address(self.nat_addr)
3999         self.nat_add_inside_interface(self.pg0)
4000         self.nat_add_outside_interface(self.pg1)
4001
4002         # enable forwarding and initiate connection out2in
4003         self.vapi.nat44_forwarding_enable_disable(enable=1)
4004         p1 = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
4005               IP(src=self.pg1.remote_ip4, dst=self.pg0.remote_ip4) /
4006               UDP(sport=21, dport=20) / payload)
4007
4008         self.pg1.add_stream(p1)
4009         self.pg_enable_capture(self.pg_interfaces)
4010         self.pg_start()
4011         capture = self.pg0.get_capture(1)[0]
4012
4013         self.logger.info(self.vapi.cli("show nat44 sessions"))
4014
4015         # reply with ICMP error message in2out
4016         # We cannot reliably retrieve forward bypass sessions via the API.
4017         # session dumps for a user will only look on the worker that the
4018         # user is supposed to be mapped to in2out. The forward bypass session
4019         # is not necessarily created on that worker.
4020         p2 = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
4021               IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
4022               ICMP(type='dest-unreach', code='port-unreachable') /
4023               capture[IP:])
4024
4025         self.pg0.add_stream(p2)
4026         self.pg_enable_capture(self.pg_interfaces)
4027         self.pg_start()
4028         capture = self.pg1.get_capture(1)[0]
4029
4030         self.logger.info(self.vapi.cli("show nat44 sessions"))
4031
4032         self.logger.info(ppp("p1 packet:", p1))
4033         self.logger.info(ppp("p2 packet:", p2))
4034         self.logger.info(ppp("capture packet:", capture))
4035
4036     def test_tcp_session_open_retransmit1(self):
4037         """ NAT44ED Open TCP session with SYN,ACK retransmit 1
4038
4039             The client does not receive the [SYN,ACK] or the
4040             ACK from the client is lost. Therefore, the [SYN, ACK]
4041             is retransmitted by the server.
4042         """
4043
4044         in_port = self.tcp_port_in
4045         ext_port = self.tcp_external_port
4046         payload = "H" * 10
4047
4048         self.nat_add_address(self.nat_addr)
4049         self.nat_add_inside_interface(self.pg0)
4050         self.nat_add_outside_interface(self.pg1)
4051
4052         self.vapi.nat_set_timeouts(udp=300, tcp_established=7440,
4053                                    tcp_transitory=5, icmp=60)
4054         # SYN packet in->out
4055         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
4056              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
4057              TCP(sport=in_port, dport=ext_port, flags="S"))
4058         p = self.send_and_expect(self.pg0, p, self.pg1)[0]
4059         out_port = p[TCP].sport
4060
4061         # SYN + ACK packet out->in
4062         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
4063              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
4064              TCP(sport=ext_port, dport=out_port, flags="SA"))
4065         self.send_and_expect(self.pg1, p, self.pg0)
4066
4067         # ACK in->out does not arrive
4068
4069         # resent SYN + ACK packet out->in
4070         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
4071              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
4072              TCP(sport=ext_port, dport=out_port, flags="SA"))
4073         self.send_and_expect(self.pg1, p, self.pg0)
4074
4075         # ACK packet in->out
4076         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
4077              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
4078              TCP(sport=in_port, dport=ext_port, flags="A"))
4079         self.send_and_expect(self.pg0, p, self.pg1)
4080
4081         # Verify that the data can be transmitted after the transitory time
4082         self.virtual_sleep(6)
4083
4084         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
4085              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
4086              TCP(sport=in_port, dport=ext_port, flags="PA") /
4087              Raw(payload))
4088         self.send_and_expect(self.pg0, p, self.pg1)
4089
4090     def test_tcp_session_open_retransmit2(self):
4091         """ NAT44ED Open TCP session with SYN,ACK retransmit 2
4092
4093             The ACK is lost to the server after the TCP session is opened.
4094             Data is sent by the client, then the [SYN,ACK] is
4095             retransmitted by the server.
4096         """
4097
4098         in_port = self.tcp_port_in
4099         ext_port = self.tcp_external_port
4100         payload = "H" * 10
4101
4102         self.nat_add_address(self.nat_addr)
4103         self.nat_add_inside_interface(self.pg0)
4104         self.nat_add_outside_interface(self.pg1)
4105
4106         self.vapi.nat_set_timeouts(udp=300, tcp_established=7440,
4107                                    tcp_transitory=5, icmp=60)
4108         # SYN packet in->out
4109         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
4110              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
4111              TCP(sport=in_port, dport=ext_port, flags="S"))
4112         p = self.send_and_expect(self.pg0, p, self.pg1)[0]
4113         out_port = p[TCP].sport
4114
4115         # SYN + ACK packet out->in
4116         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
4117              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
4118              TCP(sport=ext_port, dport=out_port, flags="SA"))
4119         self.send_and_expect(self.pg1, p, self.pg0)
4120
4121         # ACK packet in->out -- not received by the server
4122         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
4123              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
4124              TCP(sport=in_port, dport=ext_port, flags="A"))
4125         self.send_and_expect(self.pg0, p, self.pg1)
4126
4127         # PUSH + ACK packet in->out
4128         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
4129              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
4130              TCP(sport=in_port, dport=ext_port, flags="PA") /
4131              Raw(payload))
4132         self.send_and_expect(self.pg0, p, self.pg1)
4133
4134         # resent SYN + ACK packet out->in
4135         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
4136              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
4137              TCP(sport=ext_port, dport=out_port, flags="SA"))
4138         self.send_and_expect(self.pg1, p, self.pg0)
4139
4140         # resent ACK packet in->out
4141         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
4142              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
4143              TCP(sport=in_port, dport=ext_port, flags="A"))
4144         self.send_and_expect(self.pg0, p, self.pg1)
4145
4146         # resent PUSH + ACK packet in->out
4147         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
4148              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
4149              TCP(sport=in_port, dport=ext_port, flags="PA") /
4150              Raw(payload))
4151         self.send_and_expect(self.pg0, p, self.pg1)
4152
4153         # ACK packet out->in
4154         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
4155              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
4156              TCP(sport=ext_port, dport=out_port, flags="A"))
4157         self.send_and_expect(self.pg1, p, self.pg0)
4158
4159         # Verify that the data can be transmitted after the transitory time
4160         self.virtual_sleep(6)
4161
4162         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
4163              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
4164              TCP(sport=in_port, dport=ext_port, flags="PA") /
4165              Raw(payload))
4166         self.send_and_expect(self.pg0, p, self.pg1)
4167
4168
4169 if __name__ == '__main__':
4170     unittest.main(testRunner=VppTestRunner)