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