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