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