nat: nat44-ed cleanup & fixes
[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 keep it
2613         # established.
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 established, session should be still open 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="R"))
2634         self.send_and_expect(self.pg0, p, self.pg1)
2635
2636         # State is transitory, session should be closed after 6 seconds
2637         self.virtual_sleep(6)
2638
2639         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
2640              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
2641              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
2642                  flags="P"))
2643         self.send_and_assert_no_replies(self.pg0, p, self.pg1)
2644
2645     def test_dynamic_out_of_ports(self):
2646         """ NAT44ED dynamic translation test: out of ports """
2647
2648         self.nat_add_inside_interface(self.pg0)
2649         self.nat_add_outside_interface(self.pg1)
2650
2651         # in2out and no NAT addresses added
2652         pkts = self.create_stream_in(self.pg0, self.pg1)
2653
2654         self.send_and_assert_no_replies(
2655             self.pg0, pkts, msg="i2o pkts",
2656             stats_diff=self.no_diff | {
2657                 "err": {
2658                     '/err/nat44-ed-in2out-slowpath/out of ports': len(pkts),
2659                 },
2660                 self.pg0.sw_if_index: {
2661                     '/nat44-ed/in2out/slowpath/drops': len(pkts),
2662                 },
2663             }
2664         )
2665
2666         # in2out after NAT addresses added
2667         self.nat_add_address(self.nat_addr)
2668
2669         tcpn, udpn, icmpn = (sum(x) for x in
2670                              zip(*((TCP in p, UDP in p, ICMP in p)
2671                                  for p in pkts)))
2672
2673         self.send_and_expect(
2674             self.pg0, pkts, self.pg1, msg="i2o pkts",
2675             stats_diff=self.no_diff | {
2676                 "err": {
2677                     '/err/nat44-ed-in2out-slowpath/out of ports': 0,
2678                 },
2679                 self.pg0.sw_if_index: {
2680                     '/nat44-ed/in2out/slowpath/drops': 0,
2681                     '/nat44-ed/in2out/slowpath/tcp': tcpn,
2682                     '/nat44-ed/in2out/slowpath/udp': udpn,
2683                     '/nat44-ed/in2out/slowpath/icmp': icmpn,
2684                 },
2685             }
2686         )
2687
2688     def test_unknown_proto(self):
2689         """ NAT44ED translate packet with unknown protocol """
2690
2691         self.nat_add_address(self.nat_addr)
2692         self.nat_add_inside_interface(self.pg0)
2693         self.nat_add_outside_interface(self.pg1)
2694
2695         # in2out
2696         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2697              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
2698              TCP(sport=self.tcp_port_in, dport=20))
2699         self.pg0.add_stream(p)
2700         self.pg_enable_capture(self.pg_interfaces)
2701         self.pg_start()
2702         p = self.pg1.get_capture(1)
2703
2704         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2705              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
2706              GRE() /
2707              IP(src=self.pg2.remote_ip4, dst=self.pg2.remote_ip4) /
2708              TCP(sport=1234, dport=1234))
2709         self.pg0.add_stream(p)
2710         self.pg_enable_capture(self.pg_interfaces)
2711         self.pg_start()
2712         p = self.pg1.get_capture(1)
2713         packet = p[0]
2714         try:
2715             self.assertEqual(packet[IP].src, self.nat_addr)
2716             self.assertEqual(packet[IP].dst, self.pg1.remote_ip4)
2717             self.assertEqual(packet.haslayer(GRE), 1)
2718             self.assert_packet_checksums_valid(packet)
2719         except:
2720             self.logger.error(ppp("Unexpected or invalid packet:", packet))
2721             raise
2722
2723         # out2in
2724         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
2725              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
2726              GRE() /
2727              IP(src=self.pg2.remote_ip4, dst=self.pg2.remote_ip4) /
2728              TCP(sport=1234, dport=1234))
2729         self.pg1.add_stream(p)
2730         self.pg_enable_capture(self.pg_interfaces)
2731         self.pg_start()
2732         p = self.pg0.get_capture(1)
2733         packet = p[0]
2734         try:
2735             self.assertEqual(packet[IP].src, self.pg1.remote_ip4)
2736             self.assertEqual(packet[IP].dst, self.pg0.remote_ip4)
2737             self.assertEqual(packet.haslayer(GRE), 1)
2738             self.assert_packet_checksums_valid(packet)
2739         except:
2740             self.logger.error(ppp("Unexpected or invalid packet:", packet))
2741             raise
2742
2743     def test_hairpinning_unknown_proto(self):
2744         """ NAT44ED translate packet with unknown protocol - hairpinning """
2745         host = self.pg0.remote_hosts[0]
2746         server = self.pg0.remote_hosts[1]
2747         host_in_port = 1234
2748         server_out_port = 8765
2749         server_nat_ip = "10.0.0.11"
2750
2751         self.nat_add_address(self.nat_addr)
2752         self.nat_add_inside_interface(self.pg0)
2753         self.nat_add_outside_interface(self.pg1)
2754
2755         # add static mapping for server
2756         self.nat_add_static_mapping(server.ip4, server_nat_ip)
2757
2758         # host to server
2759         p = (Ether(src=host.mac, dst=self.pg0.local_mac) /
2760              IP(src=host.ip4, dst=server_nat_ip) /
2761              TCP(sport=host_in_port, dport=server_out_port))
2762         self.pg0.add_stream(p)
2763         self.pg_enable_capture(self.pg_interfaces)
2764         self.pg_start()
2765         self.pg0.get_capture(1)
2766
2767         p = (Ether(dst=self.pg0.local_mac, src=host.mac) /
2768              IP(src=host.ip4, dst=server_nat_ip) /
2769              GRE() /
2770              IP(src=self.pg2.remote_ip4, dst=self.pg2.remote_ip4) /
2771              TCP(sport=1234, dport=1234))
2772         self.pg0.add_stream(p)
2773         self.pg_enable_capture(self.pg_interfaces)
2774         self.pg_start()
2775         p = self.pg0.get_capture(1)
2776         packet = p[0]
2777         try:
2778             self.assertEqual(packet[IP].src, self.nat_addr)
2779             self.assertEqual(packet[IP].dst, server.ip4)
2780             self.assertEqual(packet.haslayer(GRE), 1)
2781             self.assert_packet_checksums_valid(packet)
2782         except:
2783             self.logger.error(ppp("Unexpected or invalid packet:", packet))
2784             raise
2785
2786         # server to host
2787         p = (Ether(dst=self.pg0.local_mac, src=server.mac) /
2788              IP(src=server.ip4, dst=self.nat_addr) /
2789              GRE() /
2790              IP(src=self.pg2.remote_ip4, dst=self.pg2.remote_ip4) /
2791              TCP(sport=1234, dport=1234))
2792         self.pg0.add_stream(p)
2793         self.pg_enable_capture(self.pg_interfaces)
2794         self.pg_start()
2795         p = self.pg0.get_capture(1)
2796         packet = p[0]
2797         try:
2798             self.assertEqual(packet[IP].src, server_nat_ip)
2799             self.assertEqual(packet[IP].dst, host.ip4)
2800             self.assertEqual(packet.haslayer(GRE), 1)
2801             self.assert_packet_checksums_valid(packet)
2802         except:
2803             self.logger.error(ppp("Unexpected or invalid packet:", packet))
2804             raise
2805
2806     def test_output_feature_and_service(self):
2807         """ NAT44ED interface output feature and services """
2808         external_addr = '1.2.3.4'
2809         external_port = 80
2810         local_port = 8080
2811
2812         self.vapi.nat44_forwarding_enable_disable(enable=1)
2813         self.nat_add_address(self.nat_addr)
2814         flags = self.config_flags.NAT_IS_ADDR_ONLY
2815         self.vapi.nat44_add_del_identity_mapping(
2816             ip_address=self.pg1.remote_ip4, sw_if_index=0xFFFFFFFF,
2817             flags=flags, is_add=1)
2818         flags = self.config_flags.NAT_IS_OUT2IN_ONLY
2819         self.nat_add_static_mapping(self.pg0.remote_ip4, external_addr,
2820                                     local_port, external_port,
2821                                     proto=IP_PROTOS.tcp, flags=flags)
2822
2823         self.nat_add_inside_interface(self.pg0)
2824         self.nat_add_outside_interface(self.pg0)
2825         self.vapi.nat44_ed_add_del_output_interface(
2826             sw_if_index=self.pg1.sw_if_index, is_add=1)
2827
2828         # from client to service
2829         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
2830              IP(src=self.pg1.remote_ip4, dst=external_addr) /
2831              TCP(sport=12345, dport=external_port))
2832         self.pg1.add_stream(p)
2833         self.pg_enable_capture(self.pg_interfaces)
2834         self.pg_start()
2835         capture = self.pg0.get_capture(1)
2836         p = capture[0]
2837         try:
2838             ip = p[IP]
2839             tcp = p[TCP]
2840             self.assertEqual(ip.dst, self.pg0.remote_ip4)
2841             self.assertEqual(tcp.dport, local_port)
2842             self.assert_packet_checksums_valid(p)
2843         except:
2844             self.logger.error(ppp("Unexpected or invalid packet:", p))
2845             raise
2846
2847         # from service back to client
2848         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
2849              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
2850              TCP(sport=local_port, dport=12345))
2851         self.pg0.add_stream(p)
2852         self.pg_enable_capture(self.pg_interfaces)
2853         self.pg_start()
2854         capture = self.pg1.get_capture(1)
2855         p = capture[0]
2856         try:
2857             ip = p[IP]
2858             tcp = p[TCP]
2859             self.assertEqual(ip.src, external_addr)
2860             self.assertEqual(tcp.sport, external_port)
2861             self.assert_packet_checksums_valid(p)
2862         except:
2863             self.logger.error(ppp("Unexpected or invalid packet:", p))
2864             raise
2865
2866         # from local network host to external network
2867         pkts = self.create_stream_in(self.pg0, self.pg1)
2868         self.pg0.add_stream(pkts)
2869         self.pg_enable_capture(self.pg_interfaces)
2870         self.pg_start()
2871         capture = self.pg1.get_capture(len(pkts))
2872         self.verify_capture_out(capture, ignore_port=True)
2873         pkts = self.create_stream_in(self.pg0, self.pg1)
2874         self.pg0.add_stream(pkts)
2875         self.pg_enable_capture(self.pg_interfaces)
2876         self.pg_start()
2877         capture = self.pg1.get_capture(len(pkts))
2878         self.verify_capture_out(capture, ignore_port=True)
2879
2880         # from external network back to local network host
2881         pkts = self.create_stream_out(self.pg1)
2882         self.pg1.add_stream(pkts)
2883         self.pg_enable_capture(self.pg_interfaces)
2884         self.pg_start()
2885         capture = self.pg0.get_capture(len(pkts))
2886         self.verify_capture_in(capture, self.pg0)
2887
2888     def test_output_feature_and_service3(self):
2889         """ NAT44ED interface output feature and DST NAT """
2890         external_addr = '1.2.3.4'
2891         external_port = 80
2892         local_port = 8080
2893
2894         self.vapi.nat44_forwarding_enable_disable(enable=1)
2895         self.nat_add_address(self.nat_addr)
2896         flags = self.config_flags.NAT_IS_OUT2IN_ONLY
2897         self.nat_add_static_mapping(self.pg1.remote_ip4, external_addr,
2898                                     local_port, external_port,
2899                                     proto=IP_PROTOS.tcp, flags=flags)
2900
2901         self.nat_add_inside_interface(self.pg0)
2902         self.nat_add_outside_interface(self.pg0)
2903         self.vapi.nat44_ed_add_del_output_interface(
2904             sw_if_index=self.pg1.sw_if_index, is_add=1)
2905
2906         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
2907              IP(src=self.pg0.remote_ip4, dst=external_addr) /
2908              TCP(sport=12345, dport=external_port))
2909         self.pg0.add_stream(p)
2910         self.pg_enable_capture(self.pg_interfaces)
2911         self.pg_start()
2912         capture = self.pg1.get_capture(1)
2913         p = capture[0]
2914         try:
2915             ip = p[IP]
2916             tcp = p[TCP]
2917             self.assertEqual(ip.src, self.pg0.remote_ip4)
2918             self.assertEqual(tcp.sport, 12345)
2919             self.assertEqual(ip.dst, self.pg1.remote_ip4)
2920             self.assertEqual(tcp.dport, local_port)
2921             self.assert_packet_checksums_valid(p)
2922         except:
2923             self.logger.error(ppp("Unexpected or invalid packet:", p))
2924             raise
2925
2926         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
2927              IP(src=self.pg1.remote_ip4, dst=self.pg0.remote_ip4) /
2928              TCP(sport=local_port, dport=12345))
2929         self.pg1.add_stream(p)
2930         self.pg_enable_capture(self.pg_interfaces)
2931         self.pg_start()
2932         capture = self.pg0.get_capture(1)
2933         p = capture[0]
2934         try:
2935             ip = p[IP]
2936             tcp = p[TCP]
2937             self.assertEqual(ip.src, external_addr)
2938             self.assertEqual(tcp.sport, external_port)
2939             self.assertEqual(ip.dst, self.pg0.remote_ip4)
2940             self.assertEqual(tcp.dport, 12345)
2941             self.assert_packet_checksums_valid(p)
2942         except:
2943             self.logger.error(ppp("Unexpected or invalid packet:", p))
2944             raise
2945
2946     def test_self_twice_nat_lb_negative(self):
2947         """ NAT44ED Self Twice NAT local service load balancing (negative test)
2948         """
2949         self.twice_nat_common(lb=True, self_twice_nat=True, same_pg=True,
2950                               client_id=2)
2951
2952     def test_self_twice_nat_negative(self):
2953         """ NAT44ED Self Twice NAT (negative test) """
2954         self.twice_nat_common(self_twice_nat=True)
2955
2956     def test_static_lb_multi_clients(self):
2957         """ NAT44ED local service load balancing - multiple clients"""
2958
2959         external_addr = self.nat_addr
2960         external_port = 80
2961         local_port = 8080
2962         server1 = self.pg0.remote_hosts[0]
2963         server2 = self.pg0.remote_hosts[1]
2964         server3 = self.pg0.remote_hosts[2]
2965
2966         locals = [{'addr': server1.ip4,
2967                    'port': local_port,
2968                    'probability': 90,
2969                    'vrf_id': 0},
2970                   {'addr': server2.ip4,
2971                    'port': local_port,
2972                    'probability': 10,
2973                    'vrf_id': 0}]
2974
2975         flags = self.config_flags.NAT_IS_INSIDE
2976         self.vapi.nat44_interface_add_del_feature(
2977             sw_if_index=self.pg0.sw_if_index,
2978             flags=flags, is_add=1)
2979         self.vapi.nat44_interface_add_del_feature(
2980             sw_if_index=self.pg1.sw_if_index,
2981             is_add=1)
2982
2983         self.nat_add_address(self.nat_addr)
2984         self.vapi.nat44_add_del_lb_static_mapping(is_add=1,
2985                                                   external_addr=external_addr,
2986                                                   external_port=external_port,
2987                                                   protocol=IP_PROTOS.tcp,
2988                                                   local_num=len(locals),
2989                                                   locals=locals)
2990
2991         server1_n = 0
2992         server2_n = 0
2993         clients = ip4_range(self.pg1.remote_ip4, 10, 50)
2994         pkts = []
2995         for client in clients:
2996             p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
2997                  IP(src=client, dst=self.nat_addr) /
2998                  TCP(sport=12345, dport=external_port))
2999             pkts.append(p)
3000         self.pg1.add_stream(pkts)
3001         self.pg_enable_capture(self.pg_interfaces)
3002         self.pg_start()
3003         capture = self.pg0.get_capture(len(pkts))
3004         for p in capture:
3005             if p[IP].dst == server1.ip4:
3006                 server1_n += 1
3007             else:
3008                 server2_n += 1
3009         self.assertGreaterEqual(server1_n, server2_n)
3010
3011         local = {
3012             'addr': server3.ip4,
3013             'port': local_port,
3014             'probability': 20,
3015             'vrf_id': 0
3016         }
3017
3018         # add new back-end
3019         self.vapi.nat44_lb_static_mapping_add_del_local(
3020             is_add=1,
3021             external_addr=external_addr,
3022             external_port=external_port,
3023             local=local,
3024             protocol=IP_PROTOS.tcp)
3025         server1_n = 0
3026         server2_n = 0
3027         server3_n = 0
3028         clients = ip4_range(self.pg1.remote_ip4, 60, 110)
3029         pkts = []
3030         for client in clients:
3031             p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
3032                  IP(src=client, dst=self.nat_addr) /
3033                  TCP(sport=12346, dport=external_port))
3034             pkts.append(p)
3035         self.assertGreater(len(pkts), 0)
3036         self.pg1.add_stream(pkts)
3037         self.pg_enable_capture(self.pg_interfaces)
3038         self.pg_start()
3039         capture = self.pg0.get_capture(len(pkts))
3040         for p in capture:
3041             if p[IP].dst == server1.ip4:
3042                 server1_n += 1
3043             elif p[IP].dst == server2.ip4:
3044                 server2_n += 1
3045             else:
3046                 server3_n += 1
3047         self.assertGreater(server1_n, 0)
3048         self.assertGreater(server2_n, 0)
3049         self.assertGreater(server3_n, 0)
3050
3051         local = {
3052             'addr': server2.ip4,
3053             'port': local_port,
3054             'probability': 10,
3055             'vrf_id': 0
3056         }
3057
3058         # remove one back-end
3059         self.vapi.nat44_lb_static_mapping_add_del_local(
3060             is_add=0,
3061             external_addr=external_addr,
3062             external_port=external_port,
3063             local=local,
3064             protocol=IP_PROTOS.tcp)
3065         server1_n = 0
3066         server2_n = 0
3067         server3_n = 0
3068         self.pg1.add_stream(pkts)
3069         self.pg_enable_capture(self.pg_interfaces)
3070         self.pg_start()
3071         capture = self.pg0.get_capture(len(pkts))
3072         for p in capture:
3073             if p[IP].dst == server1.ip4:
3074                 server1_n += 1
3075             elif p[IP].dst == server2.ip4:
3076                 server2_n += 1
3077             else:
3078                 server3_n += 1
3079         self.assertGreater(server1_n, 0)
3080         self.assertEqual(server2_n, 0)
3081         self.assertGreater(server3_n, 0)
3082
3083     # put zzz in front of syslog test name so that it runs as a last test
3084     # setting syslog sender cannot be undone and if it is set, it messes
3085     # with self.send_and_assert_no_replies functionality
3086     def test_zzz_syslog_sess(self):
3087         """ NAT44ED Test syslog session creation and deletion """
3088         self.vapi.syslog_set_filter(
3089             self.syslog_severity.SYSLOG_API_SEVERITY_INFO)
3090         self.vapi.syslog_set_sender(self.pg3.local_ip4, self.pg3.remote_ip4)
3091
3092         self.nat_add_address(self.nat_addr)
3093         self.nat_add_inside_interface(self.pg0)
3094         self.nat_add_outside_interface(self.pg1)
3095
3096         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
3097              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3098              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port))
3099         self.pg0.add_stream(p)
3100         self.pg_enable_capture(self.pg_interfaces)
3101         self.pg_start()
3102         capture = self.pg1.get_capture(1)
3103         self.tcp_port_out = capture[0][TCP].sport
3104         capture = self.pg3.get_capture(1)
3105         self.verify_syslog_sess(capture[0][Raw].load, 'SADD')
3106
3107         self.pg_enable_capture(self.pg_interfaces)
3108         self.pg_start()
3109         self.nat_add_address(self.nat_addr, is_add=0)
3110         capture = self.pg3.get_capture(1)
3111         self.verify_syslog_sess(capture[0][Raw].load, 'SDEL')
3112
3113     # put zzz in front of syslog test name so that it runs as a last test
3114     # setting syslog sender cannot be undone and if it is set, it messes
3115     # with self.send_and_assert_no_replies functionality
3116     def test_zzz_syslog_sess_reopen(self):
3117         """ Syslog events for session reopen """
3118         self.vapi.syslog_set_filter(
3119             self.syslog_severity.SYSLOG_API_SEVERITY_INFO)
3120         self.vapi.syslog_set_sender(self.pg3.local_ip4, self.pg3.remote_ip4)
3121
3122         self.nat_add_address(self.nat_addr)
3123         self.nat_add_inside_interface(self.pg0)
3124         self.nat_add_outside_interface(self.pg1)
3125
3126         # SYN in2out
3127         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
3128              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3129              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port))
3130         capture = self.send_and_expect(self.pg0, p, self.pg1)[0]
3131         self.tcp_port_out = capture[0][TCP].sport
3132         capture = self.pg3.get_capture(1)
3133         self.verify_syslog_sess(capture[0][Raw].load, 'SADD')
3134
3135         # SYN out2in
3136         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
3137              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
3138              TCP(sport=self.tcp_external_port, dport=self.tcp_port_out))
3139         self.send_and_expect(self.pg1, p, self.pg0)
3140
3141         # FIN in2out
3142         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
3143              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3144              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
3145                  flags="F"))
3146         self.send_and_expect(self.pg0, p, self.pg1)
3147
3148         # FIN out2in
3149         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
3150              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
3151              TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
3152                  flags="F"))
3153         self.send_and_expect(self.pg1, p, self.pg0)
3154
3155         # SYN in2out
3156         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
3157              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3158              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port))
3159         self.send_and_expect(self.pg0, p, self.pg1)
3160
3161         # SYN out2in
3162         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
3163              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
3164              TCP(sport=self.tcp_external_port, dport=self.tcp_port_out))
3165         self.send_and_expect(self.pg1, p, self.pg0)
3166
3167         # 2 records should be produced - first one del & add
3168         capture = self.pg3.get_capture(2)
3169         self.verify_syslog_sess(capture[0][Raw].load, 'SDEL')
3170         self.verify_syslog_sess(capture[1][Raw].load, 'SADD')
3171
3172     def test_twice_nat_interface_addr(self):
3173         """ NAT44ED Acquire twice NAT addresses from interface """
3174         flags = self.config_flags.NAT_IS_TWICE_NAT
3175         self.vapi.nat44_add_del_interface_addr(
3176             sw_if_index=self.pg11.sw_if_index,
3177             flags=flags, is_add=1)
3178
3179         # no address in NAT pool
3180         adresses = self.vapi.nat44_address_dump()
3181         self.assertEqual(0, len(adresses))
3182
3183         # configure interface address and check NAT address pool
3184         self.pg11.config_ip4()
3185         adresses = self.vapi.nat44_address_dump()
3186         self.assertEqual(1, len(adresses))
3187         self.assertEqual(str(adresses[0].ip_address),
3188                          self.pg11.local_ip4)
3189         self.assertEqual(adresses[0].flags, flags)
3190
3191         # remove interface address and check NAT address pool
3192         self.pg11.unconfig_ip4()
3193         adresses = self.vapi.nat44_address_dump()
3194         self.assertEqual(0, len(adresses))
3195
3196     def test_output_feature_stateful_acl(self):
3197         """ NAT44ED output feature works with stateful ACL """
3198
3199         self.nat_add_address(self.nat_addr)
3200         self.vapi.nat44_ed_add_del_output_interface(
3201             sw_if_index=self.pg1.sw_if_index, is_add=1)
3202
3203         # First ensure that the NAT is working sans ACL
3204
3205         # send packets out2in, no sessions yet so packets should drop
3206         pkts_out2in = self.create_stream_out(self.pg1)
3207         self.send_and_assert_no_replies(self.pg1, pkts_out2in)
3208
3209         # send packets into inside intf, ensure received via outside intf
3210         pkts_in2out = self.create_stream_in(self.pg0, self.pg1)
3211         capture = self.send_and_expect(self.pg0, pkts_in2out, self.pg1,
3212                                        len(pkts_in2out))
3213         self.verify_capture_out(capture, ignore_port=True)
3214
3215         # send out2in again, with sessions created it should work now
3216         pkts_out2in = self.create_stream_out(self.pg1)
3217         capture = self.send_and_expect(self.pg1, pkts_out2in, self.pg0,
3218                                        len(pkts_out2in))
3219         self.verify_capture_in(capture, self.pg0)
3220
3221         # Create an ACL blocking everything
3222         out2in_deny_rule = AclRule(is_permit=0)
3223         out2in_acl = VppAcl(self, rules=[out2in_deny_rule])
3224         out2in_acl.add_vpp_config()
3225
3226         # create an ACL to permit/reflect everything
3227         in2out_reflect_rule = AclRule(is_permit=2)
3228         in2out_acl = VppAcl(self, rules=[in2out_reflect_rule])
3229         in2out_acl.add_vpp_config()
3230
3231         # apply as input acl on interface and confirm it blocks everything
3232         acl_if = VppAclInterface(self, sw_if_index=self.pg1.sw_if_index,
3233                                  n_input=1, acls=[out2in_acl])
3234         acl_if.add_vpp_config()
3235         self.send_and_assert_no_replies(self.pg1, pkts_out2in)
3236
3237         # apply output acl
3238         acl_if.acls = [out2in_acl, in2out_acl]
3239         acl_if.add_vpp_config()
3240         # send in2out to generate ACL state (NAT state was created earlier)
3241         capture = self.send_and_expect(self.pg0, pkts_in2out, self.pg1,
3242                                        len(pkts_in2out))
3243         self.verify_capture_out(capture, ignore_port=True)
3244
3245         # send out2in again. ACL state exists so it should work now.
3246         # TCP packets with the syn flag set also need the ack flag
3247         for p in pkts_out2in:
3248             if p.haslayer(TCP) and p[TCP].flags & 0x02:
3249                 p[TCP].flags |= 0x10
3250         capture = self.send_and_expect(self.pg1, pkts_out2in, self.pg0,
3251                                        len(pkts_out2in))
3252         self.verify_capture_in(capture, self.pg0)
3253         self.logger.info(self.vapi.cli("show trace"))
3254
3255     def test_tcp_close(self):
3256         """ NAT44ED Close TCP session from inside network - output feature """
3257         config = self.vapi.nat44_show_running_config()
3258         old_timeouts = config.timeouts
3259         new_transitory = 2
3260         self.vapi.nat_set_timeouts(
3261             udp=old_timeouts.udp,
3262             tcp_established=old_timeouts.tcp_established,
3263             icmp=old_timeouts.icmp,
3264             tcp_transitory=new_transitory)
3265
3266         self.vapi.nat44_forwarding_enable_disable(enable=1)
3267         self.nat_add_address(self.pg1.local_ip4)
3268         twice_nat_addr = '10.0.1.3'
3269         service_ip = '192.168.16.150'
3270         self.nat_add_address(twice_nat_addr, twice_nat=1)
3271
3272         flags = self.config_flags.NAT_IS_INSIDE
3273         self.vapi.nat44_interface_add_del_feature(
3274             sw_if_index=self.pg0.sw_if_index,
3275             is_add=1)
3276         self.vapi.nat44_interface_add_del_feature(
3277             sw_if_index=self.pg0.sw_if_index,
3278             flags=flags, is_add=1)
3279         self.vapi.nat44_ed_add_del_output_interface(
3280             is_add=1,
3281             sw_if_index=self.pg1.sw_if_index)
3282
3283         flags = (self.config_flags.NAT_IS_OUT2IN_ONLY |
3284                  self.config_flags.NAT_IS_TWICE_NAT)
3285         self.nat_add_static_mapping(self.pg0.remote_ip4,
3286                                     service_ip, 80, 80,
3287                                     proto=IP_PROTOS.tcp,
3288                                     flags=flags)
3289         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
3290         start_sessnum = len(sessions)
3291
3292         # SYN packet out->in
3293         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
3294              IP(src=self.pg1.remote_ip4, dst=service_ip) /
3295              TCP(sport=33898, dport=80, flags="S"))
3296         capture = self.send_and_expect(self.pg1, p, self.pg0, n_rx=1)
3297         p = capture[0]
3298         tcp_port = p[TCP].sport
3299
3300         # SYN + ACK packet in->out
3301         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
3302              IP(src=self.pg0.remote_ip4, dst=twice_nat_addr) /
3303              TCP(sport=80, dport=tcp_port, flags="SA"))
3304         self.send_and_expect(self.pg0, p, self.pg1, n_rx=1)
3305
3306         # ACK packet out->in
3307         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
3308              IP(src=self.pg1.remote_ip4, dst=service_ip) /
3309              TCP(sport=33898, dport=80, flags="A"))
3310         self.send_and_expect(self.pg1, p, self.pg0, n_rx=1)
3311
3312         # FIN packet in -> out
3313         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
3314              IP(src=self.pg0.remote_ip4, dst=twice_nat_addr) /
3315              TCP(sport=80, dport=tcp_port, flags="FA", seq=100, ack=300))
3316         self.send_and_expect(self.pg0, p, self.pg1, n_rx=1)
3317
3318         # FIN+ACK packet out -> in
3319         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
3320              IP(src=self.pg1.remote_ip4, dst=service_ip) /
3321              TCP(sport=33898, dport=80, flags="FA", seq=300, ack=101))
3322         self.send_and_expect(self.pg1, p, self.pg0, n_rx=1)
3323
3324         # ACK packet in -> out
3325         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
3326              IP(src=self.pg0.remote_ip4, dst=twice_nat_addr) /
3327              TCP(sport=80, dport=tcp_port, flags="A", seq=101, ack=301))
3328         self.send_and_expect(self.pg0, p, self.pg1, n_rx=1)
3329
3330         # session now in transitory timeout, but traffic still flows
3331         # try FIN packet out->in
3332         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
3333              IP(src=self.pg1.remote_ip4, dst=service_ip) /
3334              TCP(sport=33898, dport=80, flags="F"))
3335         self.pg1.add_stream(p)
3336         self.pg_enable_capture(self.pg_interfaces)
3337         self.pg_start()
3338
3339         self.virtual_sleep(new_transitory, "wait for transitory timeout")
3340         self.pg0.get_capture(1)
3341
3342         # session should still exist
3343         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
3344         self.assertEqual(len(sessions) - start_sessnum, 1)
3345
3346         # send FIN+ACK packet out -> in - will cause session to be wiped
3347         # but won't create a new session
3348         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
3349              IP(src=self.pg1.remote_ip4, dst=service_ip) /
3350              TCP(sport=33898, dport=80, flags="FA", seq=300, ack=101))
3351         self.send_and_assert_no_replies(self.pg1, p)
3352         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
3353         self.assertEqual(len(sessions) - start_sessnum, 0)
3354
3355     def test_tcp_session_close_in(self):
3356         """ NAT44ED Close TCP session from inside network """
3357
3358         in_port = self.tcp_port_in
3359         out_port = 10505
3360         ext_port = self.tcp_external_port
3361
3362         self.nat_add_address(self.nat_addr)
3363         self.nat_add_inside_interface(self.pg0)
3364         self.nat_add_outside_interface(self.pg1)
3365         self.nat_add_static_mapping(self.pg0.remote_ip4, self.nat_addr,
3366                                     in_port, out_port, proto=IP_PROTOS.tcp,
3367                                     flags=self.config_flags.NAT_IS_TWICE_NAT)
3368
3369         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
3370         session_n = len(sessions)
3371
3372         self.vapi.nat_set_timeouts(udp=300, tcp_established=7440,
3373                                    tcp_transitory=2, icmp=5)
3374
3375         self.init_tcp_session(self.pg0, self.pg1, in_port, ext_port)
3376
3377         # FIN packet in -> out
3378         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
3379              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3380              TCP(sport=in_port, dport=ext_port,
3381                  flags="FA", seq=100, ack=300))
3382         self.send_and_expect(self.pg0, p, self.pg1)
3383         pkts = []
3384
3385         # ACK packet out -> in
3386         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
3387              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
3388              TCP(sport=ext_port, dport=out_port,
3389                  flags="A", seq=300, ack=101))
3390         pkts.append(p)
3391
3392         # FIN packet out -> in
3393         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
3394              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
3395              TCP(sport=ext_port, dport=out_port,
3396                  flags="FA", seq=300, ack=101))
3397         pkts.append(p)
3398
3399         self.send_and_expect(self.pg1, pkts, self.pg0)
3400
3401         # ACK packet in -> out
3402         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
3403              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3404              TCP(sport=in_port, dport=ext_port,
3405                  flags="A", seq=101, ack=301))
3406         self.send_and_expect(self.pg0, p, self.pg1)
3407
3408         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
3409         self.assertEqual(len(sessions) - session_n, 1)
3410
3411         # retransmit FIN packet out -> in
3412         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
3413              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
3414              TCP(sport=ext_port, dport=out_port,
3415                  flags="FA", seq=300, ack=101))
3416
3417         self.send_and_expect(self.pg1, p, self.pg0)
3418
3419         # retransmit ACK packet in -> out
3420         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
3421              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3422              TCP(sport=in_port, dport=ext_port,
3423                  flags="A", seq=101, ack=301))
3424         self.send_and_expect(self.pg0, p, self.pg1)
3425
3426         self.virtual_sleep(3)
3427         # retransmit ACK packet in -> out - this will cause session to be wiped
3428         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
3429              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3430              TCP(sport=in_port, dport=ext_port,
3431                  flags="A", seq=101, ack=301))
3432         self.send_and_assert_no_replies(self.pg0, p)
3433         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
3434         self.assertEqual(len(sessions) - session_n, 0)
3435
3436     def test_tcp_session_close_out(self):
3437         """ NAT44ED Close TCP session from outside network """
3438
3439         in_port = self.tcp_port_in
3440         out_port = 10505
3441         ext_port = self.tcp_external_port
3442
3443         self.nat_add_address(self.nat_addr)
3444         self.nat_add_inside_interface(self.pg0)
3445         self.nat_add_outside_interface(self.pg1)
3446         self.nat_add_static_mapping(self.pg0.remote_ip4, self.nat_addr,
3447                                     in_port, out_port, proto=IP_PROTOS.tcp,
3448                                     flags=self.config_flags.NAT_IS_TWICE_NAT)
3449
3450         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
3451         session_n = len(sessions)
3452
3453         self.vapi.nat_set_timeouts(udp=300, tcp_established=7440,
3454                                    tcp_transitory=2, icmp=5)
3455
3456         _ = self.init_tcp_session(self.pg0, self.pg1, in_port, ext_port)
3457
3458         # FIN packet out -> in
3459         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
3460              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
3461              TCP(sport=ext_port, dport=out_port,
3462                  flags="FA", seq=100, ack=300))
3463         self.pg1.add_stream(p)
3464         self.pg_enable_capture(self.pg_interfaces)
3465         self.pg_start()
3466         self.pg0.get_capture(1)
3467
3468         # FIN+ACK packet in -> out
3469         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
3470              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3471              TCP(sport=in_port, dport=ext_port,
3472                  flags="FA", seq=300, ack=101))
3473
3474         self.pg0.add_stream(p)
3475         self.pg_enable_capture(self.pg_interfaces)
3476         self.pg_start()
3477         self.pg1.get_capture(1)
3478
3479         # ACK packet out -> in
3480         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
3481              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
3482              TCP(sport=ext_port, dport=out_port,
3483                  flags="A", seq=101, ack=301))
3484         self.pg1.add_stream(p)
3485         self.pg_enable_capture(self.pg_interfaces)
3486         self.pg_start()
3487         self.pg0.get_capture(1)
3488
3489         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
3490         self.assertEqual(len(sessions) - session_n, 1)
3491
3492         # retransmit FIN packet out -> in
3493         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
3494              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
3495              TCP(sport=ext_port, dport=out_port,
3496                  flags="FA", seq=300, ack=101))
3497         self.send_and_expect(self.pg1, p, self.pg0)
3498
3499         # retransmit ACK packet in -> out
3500         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
3501              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3502              TCP(sport=in_port, dport=ext_port,
3503                  flags="A", seq=101, ack=301))
3504         self.send_and_expect(self.pg0, p, self.pg1)
3505
3506         self.virtual_sleep(3)
3507         # retransmit ACK packet in -> out - this will cause session to be wiped
3508         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
3509              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3510              TCP(sport=in_port, dport=ext_port,
3511                  flags="A", seq=101, ack=301))
3512         self.send_and_assert_no_replies(self.pg0, p)
3513         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
3514         self.assertEqual(len(sessions) - session_n, 0)
3515
3516     def test_tcp_session_close_simultaneous(self):
3517         """ Simultaneous TCP close from both sides """
3518
3519         in_port = self.tcp_port_in
3520         ext_port = 10505
3521
3522         self.nat_add_address(self.nat_addr)
3523         self.nat_add_inside_interface(self.pg0)
3524         self.nat_add_outside_interface(self.pg1)
3525         self.nat_add_static_mapping(self.pg0.remote_ip4, self.nat_addr,
3526                                     in_port, ext_port, proto=IP_PROTOS.tcp,
3527                                     flags=self.config_flags.NAT_IS_TWICE_NAT)
3528
3529         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
3530         session_n = len(sessions)
3531
3532         self.vapi.nat_set_timeouts(udp=300, tcp_established=7440,
3533                                    tcp_transitory=2, icmp=5)
3534
3535         out_port = self.init_tcp_session(self.pg0, self.pg1, in_port, ext_port)
3536
3537         # FIN packet in -> out
3538         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
3539              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3540              TCP(sport=in_port, dport=ext_port,
3541                  flags="FA", seq=100, ack=300))
3542         self.send_and_expect(self.pg0, p, self.pg1)
3543
3544         # FIN packet out -> in
3545         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
3546              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
3547              TCP(sport=ext_port, dport=out_port,
3548                  flags="FA", seq=300, ack=100))
3549         self.send_and_expect(self.pg1, p, self.pg0)
3550
3551         # ACK packet in -> out
3552         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
3553              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3554              TCP(sport=in_port, dport=ext_port,
3555                  flags="A", seq=101, ack=301))
3556         self.send_and_expect(self.pg0, p, self.pg1)
3557
3558         # ACK packet out -> in
3559         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
3560              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
3561              TCP(sport=ext_port, dport=out_port,
3562                  flags="A", seq=301, ack=101))
3563         self.send_and_expect(self.pg1, p, self.pg0)
3564
3565         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
3566         self.assertEqual(len(sessions) - session_n, 1)
3567
3568         # retransmit FIN packet out -> in
3569         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
3570              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
3571              TCP(sport=ext_port, dport=out_port,
3572                  flags="FA", seq=300, ack=101))
3573         self.send_and_expect(self.pg1, p, self.pg0)
3574
3575         # retransmit ACK packet in -> out
3576         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
3577              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3578              TCP(sport=in_port, dport=ext_port,
3579                  flags="A", seq=101, ack=301))
3580         self.send_and_expect(self.pg0, p, self.pg1)
3581
3582         self.virtual_sleep(3)
3583         # retransmit ACK packet in -> out - this will cause session to be wiped
3584         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
3585              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3586              TCP(sport=in_port, dport=ext_port,
3587                  flags="A", seq=101, ack=301))
3588         self.pg_send(self.pg0, p)
3589         self.send_and_assert_no_replies(self.pg0, p)
3590         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
3591         self.assertEqual(len(sessions) - session_n, 0)
3592
3593     def test_tcp_session_half_reopen_inside(self):
3594         """ TCP session in FIN/FIN state not reopened by in2out SYN only """
3595         in_port = self.tcp_port_in
3596         ext_port = 10505
3597
3598         self.nat_add_address(self.nat_addr)
3599         self.nat_add_inside_interface(self.pg0)
3600         self.nat_add_outside_interface(self.pg1)
3601         self.nat_add_static_mapping(self.pg0.remote_ip4, self.nat_addr,
3602                                     in_port, ext_port, proto=IP_PROTOS.tcp,
3603                                     flags=self.config_flags.NAT_IS_TWICE_NAT)
3604
3605         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
3606         session_n = len(sessions)
3607
3608         self.vapi.nat_set_timeouts(udp=300, tcp_established=7440,
3609                                    tcp_transitory=2, icmp=5)
3610
3611         out_port = self.init_tcp_session(self.pg0, self.pg1, in_port, ext_port)
3612
3613         # FIN packet in -> out
3614         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
3615              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3616              TCP(sport=in_port, dport=ext_port,
3617                  flags="FA", seq=100, ack=300))
3618         self.send_and_expect(self.pg0, p, self.pg1)
3619
3620         # FIN packet out -> in
3621         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
3622              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
3623              TCP(sport=ext_port, dport=out_port,
3624                  flags="FA", seq=300, ack=100))
3625         self.send_and_expect(self.pg1, p, self.pg0)
3626
3627         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
3628         self.assertEqual(len(sessions) - session_n, 1)
3629
3630         # send SYN packet in -> out
3631         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
3632              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3633              TCP(sport=in_port, dport=ext_port,
3634                  flags="S", seq=101, ack=301))
3635         self.send_and_expect(self.pg0, p, self.pg1)
3636
3637         self.virtual_sleep(3)
3638         # send ACK packet in -> out - session should be wiped
3639         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
3640              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3641              TCP(sport=in_port, dport=ext_port,
3642                  flags="A", seq=101, ack=301))
3643         self.send_and_assert_no_replies(self.pg0, p, self.pg1)
3644         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
3645         self.assertEqual(len(sessions) - session_n, 0)
3646
3647     def test_tcp_session_half_reopen_outside(self):
3648         """ TCP session in FIN/FIN state not reopened by out2in SYN only """
3649         in_port = self.tcp_port_in
3650         ext_port = 10505
3651
3652         self.nat_add_address(self.nat_addr)
3653         self.nat_add_inside_interface(self.pg0)
3654         self.nat_add_outside_interface(self.pg1)
3655         self.nat_add_static_mapping(self.pg0.remote_ip4, self.nat_addr,
3656                                     in_port, ext_port, proto=IP_PROTOS.tcp,
3657                                     flags=self.config_flags.NAT_IS_TWICE_NAT)
3658
3659         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
3660         session_n = len(sessions)
3661
3662         self.vapi.nat_set_timeouts(udp=300, tcp_established=7440,
3663                                    tcp_transitory=2, icmp=5)
3664
3665         out_port = self.init_tcp_session(self.pg0, self.pg1, in_port, ext_port)
3666
3667         # FIN packet in -> out
3668         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
3669              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3670              TCP(sport=in_port, dport=ext_port,
3671                  flags="FA", seq=100, ack=300))
3672         self.send_and_expect(self.pg0, p, self.pg1)
3673
3674         # FIN packet out -> in
3675         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
3676              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
3677              TCP(sport=ext_port, dport=out_port,
3678                  flags="FA", seq=300, ack=100))
3679         self.send_and_expect(self.pg1, p, self.pg0)
3680
3681         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
3682         self.assertEqual(len(sessions) - session_n, 1)
3683
3684         # send SYN packet out -> in
3685         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
3686              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
3687              TCP(sport=ext_port, dport=out_port,
3688                  flags="S", seq=300, ack=101))
3689         self.send_and_expect(self.pg1, p, self.pg0)
3690
3691         self.virtual_sleep(3)
3692         # send ACK packet in -> out - session should be wiped
3693         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
3694              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3695              TCP(sport=in_port, dport=ext_port,
3696                  flags="A", seq=101, ack=301))
3697         self.send_and_assert_no_replies(self.pg0, p, self.pg1)
3698         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
3699         self.assertEqual(len(sessions) - session_n, 0)
3700
3701     def test_tcp_session_reopen(self):
3702         """ TCP session in FIN/FIN state reopened by SYN from both sides """
3703         in_port = self.tcp_port_in
3704         ext_port = 10505
3705
3706         self.nat_add_address(self.nat_addr)
3707         self.nat_add_inside_interface(self.pg0)
3708         self.nat_add_outside_interface(self.pg1)
3709         self.nat_add_static_mapping(self.pg0.remote_ip4, self.nat_addr,
3710                                     in_port, ext_port, proto=IP_PROTOS.tcp,
3711                                     flags=self.config_flags.NAT_IS_TWICE_NAT)
3712
3713         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
3714         session_n = len(sessions)
3715
3716         self.vapi.nat_set_timeouts(udp=300, tcp_established=7440,
3717                                    tcp_transitory=2, icmp=5)
3718
3719         out_port = self.init_tcp_session(self.pg0, self.pg1, in_port, ext_port)
3720
3721         # FIN packet in -> out
3722         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
3723              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3724              TCP(sport=in_port, dport=ext_port,
3725                  flags="FA", seq=100, ack=300))
3726         self.send_and_expect(self.pg0, p, self.pg1)
3727
3728         # FIN packet out -> in
3729         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
3730              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
3731              TCP(sport=ext_port, dport=out_port,
3732                  flags="FA", seq=300, ack=100))
3733         self.send_and_expect(self.pg1, p, self.pg0)
3734
3735         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
3736         self.assertEqual(len(sessions) - session_n, 1)
3737
3738         # send SYN packet out -> in
3739         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
3740              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
3741              TCP(sport=ext_port, dport=out_port,
3742                  flags="S", seq=300, ack=101))
3743         self.send_and_expect(self.pg1, p, self.pg0)
3744
3745         # send SYN packet in -> out
3746         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
3747              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3748              TCP(sport=in_port, dport=ext_port,
3749                  flags="S", seq=101, ack=301))
3750         self.send_and_expect(self.pg0, p, self.pg1)
3751
3752         self.virtual_sleep(3)
3753         # send ACK packet in -> out - should be forwarded and session alive
3754         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
3755              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3756              TCP(sport=in_port, dport=ext_port,
3757                  flags="A", seq=101, ack=301))
3758         self.send_and_expect(self.pg0, p, self.pg1)
3759         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
3760         self.assertEqual(len(sessions) - session_n, 1)
3761
3762     def test_dynamic_vrf(self):
3763         """ NAT44ED dynamic translation test: different VRF"""
3764
3765         vrf_id_in = 33
3766         vrf_id_out = 34
3767
3768         self.nat_add_address(self.nat_addr, vrf_id=vrf_id_in)
3769
3770         try:
3771             self.configure_ip4_interface(self.pg7, table_id=vrf_id_in)
3772             self.configure_ip4_interface(self.pg8, table_id=vrf_id_out)
3773
3774             self.nat_add_inside_interface(self.pg7)
3775             self.nat_add_outside_interface(self.pg8)
3776
3777             # just basic stuff nothing special
3778             pkts = self.create_stream_in(self.pg7, self.pg8)
3779             self.pg7.add_stream(pkts)
3780             self.pg_enable_capture(self.pg_interfaces)
3781             self.pg_start()
3782             capture = self.pg8.get_capture(len(pkts))
3783             self.verify_capture_out(capture, ignore_port=True)
3784
3785             pkts = self.create_stream_out(self.pg8)
3786             self.pg8.add_stream(pkts)
3787             self.pg_enable_capture(self.pg_interfaces)
3788             self.pg_start()
3789             capture = self.pg7.get_capture(len(pkts))
3790             self.verify_capture_in(capture, self.pg7)
3791
3792         finally:
3793             self.pg7.unconfig()
3794             self.pg8.unconfig()
3795
3796             self.vapi.ip_table_add_del(is_add=0,
3797                                        table={'table_id': vrf_id_in})
3798             self.vapi.ip_table_add_del(is_add=0,
3799                                        table={'table_id': vrf_id_out})
3800
3801     def test_dynamic_output_feature_vrf(self):
3802         """ NAT44ED dynamic translation test: output-feature, VRF"""
3803
3804         # other then default (0)
3805         new_vrf_id = 22
3806
3807         self.nat_add_address(self.nat_addr)
3808         self.vapi.nat44_ed_add_del_output_interface(
3809             sw_if_index=self.pg8.sw_if_index,
3810             is_add=1)
3811         try:
3812             self.configure_ip4_interface(self.pg7, table_id=new_vrf_id)
3813             self.configure_ip4_interface(self.pg8, table_id=new_vrf_id)
3814
3815             # in2out
3816             tcpn = self.statistics['/nat44-ed/in2out/slowpath/tcp']
3817             udpn = self.statistics['/nat44-ed/in2out/slowpath/udp']
3818             icmpn = self.statistics['/nat44-ed/in2out/slowpath/icmp']
3819             drops = self.statistics['/nat44-ed/in2out/slowpath/drops']
3820
3821             pkts = self.create_stream_in(self.pg7, self.pg8)
3822             self.pg7.add_stream(pkts)
3823             self.pg_enable_capture(self.pg_interfaces)
3824             self.pg_start()
3825             capture = self.pg8.get_capture(len(pkts))
3826             self.verify_capture_out(capture, ignore_port=True)
3827
3828             if_idx = self.pg8.sw_if_index
3829             cnt = self.statistics['/nat44-ed/in2out/slowpath/tcp']
3830             self.assertEqual(cnt[:, if_idx].sum() - tcpn[:, if_idx].sum(), 2)
3831             cnt = self.statistics['/nat44-ed/in2out/slowpath/udp']
3832             self.assertEqual(cnt[:, if_idx].sum() - udpn[:, if_idx].sum(), 1)
3833             cnt = self.statistics['/nat44-ed/in2out/slowpath/icmp']
3834             self.assertEqual(cnt[:, if_idx].sum() - icmpn[:, if_idx].sum(), 1)
3835             cnt = self.statistics['/nat44-ed/in2out/slowpath/drops']
3836             self.assertEqual(cnt[:, if_idx].sum() - drops[:, if_idx].sum(), 0)
3837
3838             # out2in
3839             tcpn = self.statistics['/nat44-ed/out2in/fastpath/tcp']
3840             udpn = self.statistics['/nat44-ed/out2in/fastpath/udp']
3841             icmpn = self.statistics['/nat44-ed/out2in/fastpath/icmp']
3842             drops = self.statistics['/nat44-ed/out2in/fastpath/drops']
3843
3844             pkts = self.create_stream_out(self.pg8)
3845             self.pg8.add_stream(pkts)
3846             self.pg_enable_capture(self.pg_interfaces)
3847             self.pg_start()
3848             capture = self.pg7.get_capture(len(pkts))
3849             self.verify_capture_in(capture, self.pg7)
3850
3851             if_idx = self.pg8.sw_if_index
3852             cnt = self.statistics['/nat44-ed/out2in/fastpath/tcp']
3853             self.assertEqual(cnt[:, if_idx].sum() - tcpn[:, if_idx].sum(), 2)
3854             cnt = self.statistics['/nat44-ed/out2in/fastpath/udp']
3855             self.assertEqual(cnt[:, if_idx].sum() - udpn[:, if_idx].sum(), 1)
3856             cnt = self.statistics['/nat44-ed/out2in/fastpath/icmp']
3857             self.assertEqual(cnt[:, if_idx].sum() - icmpn[:, if_idx].sum(), 1)
3858             cnt = self.statistics['/nat44-ed/out2in/fastpath/drops']
3859             self.assertEqual(cnt[:, if_idx].sum() - drops[:, if_idx].sum(), 0)
3860
3861             sessions = self.statistics['/nat44-ed/total-sessions']
3862             self.assertEqual(sessions[:, 0].sum(), 3)
3863
3864         finally:
3865             self.pg7.unconfig()
3866             self.pg8.unconfig()
3867
3868             self.vapi.ip_table_add_del(is_add=0,
3869                                        table={'table_id': new_vrf_id})
3870
3871     def test_next_src_nat(self):
3872         """ NAT44ED On way back forward packet to nat44-in2out node. """
3873
3874         twice_nat_addr = '10.0.1.3'
3875         external_port = 80
3876         local_port = 8080
3877         post_twice_nat_port = 0
3878
3879         self.vapi.nat44_forwarding_enable_disable(enable=1)
3880         self.nat_add_address(twice_nat_addr, twice_nat=1)
3881         flags = (self.config_flags.NAT_IS_OUT2IN_ONLY |
3882                  self.config_flags.NAT_IS_SELF_TWICE_NAT)
3883         self.nat_add_static_mapping(self.pg6.remote_ip4, self.pg1.remote_ip4,
3884                                     local_port, external_port,
3885                                     proto=IP_PROTOS.tcp, vrf_id=1,
3886                                     flags=flags)
3887         self.vapi.nat44_interface_add_del_feature(
3888             sw_if_index=self.pg6.sw_if_index,
3889             is_add=1)
3890
3891         p = (Ether(src=self.pg6.remote_mac, dst=self.pg6.local_mac) /
3892              IP(src=self.pg6.remote_ip4, dst=self.pg1.remote_ip4) /
3893              TCP(sport=12345, dport=external_port))
3894         self.pg6.add_stream(p)
3895         self.pg_enable_capture(self.pg_interfaces)
3896         self.pg_start()
3897         capture = self.pg6.get_capture(1)
3898         p = capture[0]
3899         try:
3900             ip = p[IP]
3901             tcp = p[TCP]
3902             self.assertEqual(ip.src, twice_nat_addr)
3903             self.assertNotEqual(tcp.sport, 12345)
3904             post_twice_nat_port = tcp.sport
3905             self.assertEqual(ip.dst, self.pg6.remote_ip4)
3906             self.assertEqual(tcp.dport, local_port)
3907             self.assert_packet_checksums_valid(p)
3908         except:
3909             self.logger.error(ppp("Unexpected or invalid packet:", p))
3910             raise
3911
3912         p = (Ether(src=self.pg6.remote_mac, dst=self.pg6.local_mac) /
3913              IP(src=self.pg6.remote_ip4, dst=twice_nat_addr) /
3914              TCP(sport=local_port, dport=post_twice_nat_port))
3915         self.pg6.add_stream(p)
3916         self.pg_enable_capture(self.pg_interfaces)
3917         self.pg_start()
3918         capture = self.pg6.get_capture(1)
3919         p = capture[0]
3920         try:
3921             ip = p[IP]
3922             tcp = p[TCP]
3923             self.assertEqual(ip.src, self.pg1.remote_ip4)
3924             self.assertEqual(tcp.sport, external_port)
3925             self.assertEqual(ip.dst, self.pg6.remote_ip4)
3926             self.assertEqual(tcp.dport, 12345)
3927             self.assert_packet_checksums_valid(p)
3928         except:
3929             self.logger.error(ppp("Unexpected or invalid packet:", p))
3930             raise
3931
3932     def test_one_armed_nat44_static(self):
3933         """ NAT44ED One armed NAT and 1:1 NAPT asymmetrical rule """
3934
3935         remote_host = self.pg4.remote_hosts[0]
3936         local_host = self.pg4.remote_hosts[1]
3937         external_port = 80
3938         local_port = 8080
3939         eh_port_in = 0
3940
3941         self.vapi.nat44_forwarding_enable_disable(enable=1)
3942         self.nat_add_address(self.nat_addr, twice_nat=1)
3943         flags = (self.config_flags.NAT_IS_OUT2IN_ONLY |
3944                  self.config_flags.NAT_IS_TWICE_NAT)
3945         self.nat_add_static_mapping(local_host.ip4, self.nat_addr,
3946                                     local_port, external_port,
3947                                     proto=IP_PROTOS.tcp, flags=flags)
3948         flags = self.config_flags.NAT_IS_INSIDE
3949         self.vapi.nat44_interface_add_del_feature(
3950             sw_if_index=self.pg4.sw_if_index,
3951             is_add=1)
3952         self.vapi.nat44_interface_add_del_feature(
3953             sw_if_index=self.pg4.sw_if_index,
3954             flags=flags, is_add=1)
3955
3956         # from client to service
3957         p = (Ether(src=self.pg4.remote_mac, dst=self.pg4.local_mac) /
3958              IP(src=remote_host.ip4, dst=self.nat_addr) /
3959              TCP(sport=12345, dport=external_port))
3960         self.pg4.add_stream(p)
3961         self.pg_enable_capture(self.pg_interfaces)
3962         self.pg_start()
3963         capture = self.pg4.get_capture(1)
3964         p = capture[0]
3965         try:
3966             ip = p[IP]
3967             tcp = p[TCP]
3968             self.assertEqual(ip.dst, local_host.ip4)
3969             self.assertEqual(ip.src, self.nat_addr)
3970             self.assertEqual(tcp.dport, local_port)
3971             self.assertNotEqual(tcp.sport, 12345)
3972             eh_port_in = tcp.sport
3973             self.assert_packet_checksums_valid(p)
3974         except:
3975             self.logger.error(ppp("Unexpected or invalid packet:", p))
3976             raise
3977
3978         # from service back to client
3979         p = (Ether(src=self.pg4.remote_mac, dst=self.pg4.local_mac) /
3980              IP(src=local_host.ip4, dst=self.nat_addr) /
3981              TCP(sport=local_port, dport=eh_port_in))
3982         self.pg4.add_stream(p)
3983         self.pg_enable_capture(self.pg_interfaces)
3984         self.pg_start()
3985         capture = self.pg4.get_capture(1)
3986         p = capture[0]
3987         try:
3988             ip = p[IP]
3989             tcp = p[TCP]
3990             self.assertEqual(ip.src, self.nat_addr)
3991             self.assertEqual(ip.dst, remote_host.ip4)
3992             self.assertEqual(tcp.sport, external_port)
3993             self.assertEqual(tcp.dport, 12345)
3994             self.assert_packet_checksums_valid(p)
3995         except:
3996             self.logger.error(ppp("Unexpected or invalid packet:", p))
3997             raise
3998
3999     def test_icmp_error_fwd_outbound(self):
4000         """ NAT44ED ICMP error outbound with forwarding enabled """
4001
4002         # Ensure that an outbound ICMP error message is properly associated
4003         # with the inbound forward bypass session it is related to.
4004         payload = "H" * 10
4005
4006         self.nat_add_address(self.nat_addr)
4007         self.nat_add_inside_interface(self.pg0)
4008         self.nat_add_outside_interface(self.pg1)
4009
4010         # enable forwarding and initiate connection out2in
4011         self.vapi.nat44_forwarding_enable_disable(enable=1)
4012         p1 = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
4013               IP(src=self.pg1.remote_ip4, dst=self.pg0.remote_ip4) /
4014               UDP(sport=21, dport=20) / payload)
4015
4016         self.pg1.add_stream(p1)
4017         self.pg_enable_capture(self.pg_interfaces)
4018         self.pg_start()
4019         capture = self.pg0.get_capture(1)[0]
4020
4021         self.logger.info(self.vapi.cli("show nat44 sessions"))
4022
4023         # reply with ICMP error message in2out
4024         # We cannot reliably retrieve forward bypass sessions via the API.
4025         # session dumps for a user will only look on the worker that the
4026         # user is supposed to be mapped to in2out. The forward bypass session
4027         # is not necessarily created on that worker.
4028         p2 = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
4029               IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
4030               ICMP(type='dest-unreach', code='port-unreachable') /
4031               capture[IP:])
4032
4033         self.pg0.add_stream(p2)
4034         self.pg_enable_capture(self.pg_interfaces)
4035         self.pg_start()
4036         capture = self.pg1.get_capture(1)[0]
4037
4038         self.logger.info(self.vapi.cli("show nat44 sessions"))
4039
4040         self.logger.info(ppp("p1 packet:", p1))
4041         self.logger.info(ppp("p2 packet:", p2))
4042         self.logger.info(ppp("capture packet:", capture))
4043
4044     def test_tcp_session_open_retransmit1(self):
4045         """ NAT44ED Open TCP session with SYN,ACK retransmit 1
4046
4047             The client does not receive the [SYN,ACK] or the
4048             ACK from the client is lost. Therefore, the [SYN, ACK]
4049             is retransmitted by the server.
4050         """
4051
4052         in_port = self.tcp_port_in
4053         ext_port = self.tcp_external_port
4054         payload = "H" * 10
4055
4056         self.nat_add_address(self.nat_addr)
4057         self.nat_add_inside_interface(self.pg0)
4058         self.nat_add_outside_interface(self.pg1)
4059
4060         self.vapi.nat_set_timeouts(udp=300, tcp_established=7440,
4061                                    tcp_transitory=5, icmp=60)
4062         # SYN packet in->out
4063         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
4064              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
4065              TCP(sport=in_port, dport=ext_port, flags="S"))
4066         p = self.send_and_expect(self.pg0, p, self.pg1)[0]
4067         out_port = p[TCP].sport
4068
4069         # SYN + ACK packet out->in
4070         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
4071              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
4072              TCP(sport=ext_port, dport=out_port, flags="SA"))
4073         self.send_and_expect(self.pg1, p, self.pg0)
4074
4075         # ACK in->out does not arrive
4076
4077         # resent SYN + ACK packet out->in
4078         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
4079              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
4080              TCP(sport=ext_port, dport=out_port, flags="SA"))
4081         self.send_and_expect(self.pg1, p, self.pg0)
4082
4083         # ACK packet in->out
4084         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
4085              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
4086              TCP(sport=in_port, dport=ext_port, flags="A"))
4087         self.send_and_expect(self.pg0, p, self.pg1)
4088
4089         # Verify that the data can be transmitted after the transitory time
4090         self.virtual_sleep(6)
4091
4092         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
4093              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
4094              TCP(sport=in_port, dport=ext_port, flags="PA") /
4095              Raw(payload))
4096         self.send_and_expect(self.pg0, p, self.pg1)
4097
4098     def test_tcp_session_open_retransmit2(self):
4099         """ NAT44ED Open TCP session with SYN,ACK retransmit 2
4100
4101             The ACK is lost to the server after the TCP session is opened.
4102             Data is sent by the client, then the [SYN,ACK] is
4103             retransmitted by the server.
4104         """
4105
4106         in_port = self.tcp_port_in
4107         ext_port = self.tcp_external_port
4108         payload = "H" * 10
4109
4110         self.nat_add_address(self.nat_addr)
4111         self.nat_add_inside_interface(self.pg0)
4112         self.nat_add_outside_interface(self.pg1)
4113
4114         self.vapi.nat_set_timeouts(udp=300, tcp_established=7440,
4115                                    tcp_transitory=5, icmp=60)
4116         # SYN packet in->out
4117         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
4118              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
4119              TCP(sport=in_port, dport=ext_port, flags="S"))
4120         p = self.send_and_expect(self.pg0, p, self.pg1)[0]
4121         out_port = p[TCP].sport
4122
4123         # SYN + ACK packet out->in
4124         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
4125              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
4126              TCP(sport=ext_port, dport=out_port, flags="SA"))
4127         self.send_and_expect(self.pg1, p, self.pg0)
4128
4129         # ACK packet in->out -- not received by the server
4130         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
4131              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
4132              TCP(sport=in_port, dport=ext_port, flags="A"))
4133         self.send_and_expect(self.pg0, p, self.pg1)
4134
4135         # PUSH + ACK packet in->out
4136         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
4137              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
4138              TCP(sport=in_port, dport=ext_port, flags="PA") /
4139              Raw(payload))
4140         self.send_and_expect(self.pg0, p, self.pg1)
4141
4142         # resent SYN + ACK packet out->in
4143         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
4144              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
4145              TCP(sport=ext_port, dport=out_port, flags="SA"))
4146         self.send_and_expect(self.pg1, p, self.pg0)
4147
4148         # resent ACK packet in->out
4149         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
4150              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
4151              TCP(sport=in_port, dport=ext_port, flags="A"))
4152         self.send_and_expect(self.pg0, p, self.pg1)
4153
4154         # resent PUSH + ACK packet in->out
4155         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
4156              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
4157              TCP(sport=in_port, dport=ext_port, flags="PA") /
4158              Raw(payload))
4159         self.send_and_expect(self.pg0, p, self.pg1)
4160
4161         # ACK packet out->in
4162         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
4163              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
4164              TCP(sport=ext_port, dport=out_port, flags="A"))
4165         self.send_and_expect(self.pg1, p, self.pg0)
4166
4167         # Verify that the data can be transmitted after the transitory time
4168         self.virtual_sleep(6)
4169
4170         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
4171              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
4172              TCP(sport=in_port, dport=ext_port, flags="PA") /
4173              Raw(payload))
4174         self.send_and_expect(self.pg0, p, self.pg1)
4175
4176
4177 if __name__ == '__main__':
4178     unittest.main(testRunner=VppTestRunner)