nat: ignore user hash in ED NAT
[vpp.git] / src / plugins / nat / test / test_nat.py
1 #!/usr/bin/env python3
2
3 import socket
4 import unittest
5 import struct
6 import random
7
8 from framework import VppTestCase, VppTestRunner, running_extended_tests
9
10 import scapy.compat
11 from scapy.layers.inet import IP, TCP, UDP, ICMP
12 from scapy.layers.inet import IPerror, TCPerror, UDPerror, ICMPerror
13 from scapy.layers.inet6 import IPv6, ICMPv6EchoRequest, ICMPv6EchoReply, \
14     ICMPv6ND_NS, ICMPv6ND_NA, ICMPv6NDOptDstLLAddr, fragment6
15 from scapy.layers.inet6 import ICMPv6DestUnreach, IPerror6, IPv6ExtHdrFragment
16 from scapy.layers.l2 import Ether, ARP, GRE
17 from scapy.data import IP_PROTOS
18 from scapy.packet import bind_layers, Raw
19 from util import ppp
20 from ipfix import IPFIX, Set, Template, Data, IPFIXDecoder
21 from time import sleep
22 from util import ip4_range
23 from vpp_papi import mac_pton
24 from syslog_rfc5424_parser import SyslogMessage, ParseError
25 from syslog_rfc5424_parser.constants import SyslogFacility, SyslogSeverity
26 from io import BytesIO
27 from vpp_papi import VppEnum
28 from vpp_ip_route import VppIpRoute, VppRoutePath, FibPathType
29 from vpp_neighbor import VppNeighbor
30 from scapy.all import bind_layers, Packet, ByteEnumField, ShortField, \
31     IPField, IntField, LongField, XByteField, FlagsField, FieldLenField, \
32     PacketListField
33 from ipaddress import IPv6Network
34 from util import ppc, ppp
35 from socket import inet_pton, AF_INET
36 from vpp_acl import AclRule, VppAcl, VppAclInterface
37
38
39 # NAT HA protocol event data
40 class Event(Packet):
41     name = "Event"
42     fields_desc = [ByteEnumField("event_type", None,
43                                  {1: "add", 2: "del", 3: "refresh"}),
44                    ByteEnumField("protocol", None,
45                                  {0: "udp", 1: "tcp", 2: "icmp"}),
46                    ShortField("flags", 0),
47                    IPField("in_addr", None),
48                    IPField("out_addr", None),
49                    ShortField("in_port", None),
50                    ShortField("out_port", None),
51                    IPField("eh_addr", None),
52                    IPField("ehn_addr", None),
53                    ShortField("eh_port", None),
54                    ShortField("ehn_port", None),
55                    IntField("fib_index", None),
56                    IntField("total_pkts", 0),
57                    LongField("total_bytes", 0)]
58
59     def extract_padding(self, s):
60         return "", s
61
62
63 # NAT HA protocol header
64 class HANATStateSync(Packet):
65     name = "HA NAT state sync"
66     fields_desc = [XByteField("version", 1),
67                    FlagsField("flags", 0, 8, ['ACK']),
68                    FieldLenField("count", None, count_of="events"),
69                    IntField("sequence_number", 1),
70                    IntField("thread_index", 0),
71                    PacketListField("events", [], Event,
72                                    count_from=lambda pkt: pkt.count)]
73
74
75 class MethodHolder(VppTestCase):
76     """ NAT create capture and verify method holder """
77
78     @property
79     def config_flags(self):
80         return VppEnum.vl_api_nat_config_flags_t
81
82     @property
83     def SYSLOG_SEVERITY(self):
84         return VppEnum.vl_api_syslog_severity_t
85
86     def clear_nat44(self):
87         """
88         Clear NAT44 configuration.
89         """
90         if hasattr(self, 'pg7') and hasattr(self, 'pg8'):
91             if self.pg7.has_ip4_config:
92                 self.pg7.unconfig_ip4()
93
94         self.vapi.nat44_forwarding_enable_disable(enable=0)
95
96         interfaces = self.vapi.nat44_interface_addr_dump()
97         for intf in interfaces:
98             self.vapi.nat44_add_del_interface_addr(
99                 is_add=0,
100                 sw_if_index=intf.sw_if_index,
101                 flags=intf.flags)
102
103         self.vapi.nat_ipfix_enable_disable(domain_id=self.ipfix_domain_id,
104                                            src_port=self.ipfix_src_port,
105                                            enable=0)
106         self.ipfix_src_port = 4739
107         self.ipfix_domain_id = 1
108
109         self.vapi.syslog_set_filter(
110             self.SYSLOG_SEVERITY.SYSLOG_API_SEVERITY_EMERG)
111
112         self.vapi.nat_ha_set_listener(ip_address='0.0.0.0', port=0,
113                                       path_mtu=512)
114         self.vapi.nat_ha_set_failover(ip_address='0.0.0.0', port=0,
115                                       session_refresh_interval=10)
116
117         interfaces = self.vapi.nat44_interface_dump()
118         for intf in interfaces:
119             if intf.flags & self.config_flags.NAT_IS_INSIDE and \
120                     intf.flags & self.config_flags.NAT_IS_OUTSIDE:
121                 self.vapi.nat44_interface_add_del_feature(
122                     sw_if_index=intf.sw_if_index)
123             self.vapi.nat44_interface_add_del_feature(
124                 sw_if_index=intf.sw_if_index,
125                 flags=intf.flags)
126
127         interfaces = self.vapi.nat44_interface_output_feature_dump()
128         for intf in interfaces:
129             self.vapi.nat44_interface_add_del_output_feature(
130                 is_add=0,
131                 flags=intf.flags,
132                 sw_if_index=intf.sw_if_index)
133         static_mappings = self.vapi.nat44_static_mapping_dump()
134         for sm in static_mappings:
135             self.vapi.nat44_add_del_static_mapping(
136                 is_add=0,
137                 local_ip_address=sm.local_ip_address,
138                 external_ip_address=sm.external_ip_address,
139                 external_sw_if_index=sm.external_sw_if_index,
140                 local_port=sm.local_port,
141                 external_port=sm.external_port,
142                 vrf_id=sm.vrf_id,
143                 protocol=sm.protocol,
144                 flags=sm.flags, tag=sm.tag)
145
146         lb_static_mappings = self.vapi.nat44_lb_static_mapping_dump()
147         for lb_sm in lb_static_mappings:
148             self.vapi.nat44_add_del_lb_static_mapping(
149                 is_add=0,
150                 flags=lb_sm.flags,
151                 external_addr=lb_sm.external_addr,
152                 external_port=lb_sm.external_port,
153                 protocol=lb_sm.protocol,
154                 local_num=0, locals=[],
155                 tag=lb_sm.tag)
156
157         identity_mappings = self.vapi.nat44_identity_mapping_dump()
158         for id_m in identity_mappings:
159             self.vapi.nat44_add_del_identity_mapping(
160                 ip_address=id_m.ip_address,
161                 sw_if_index=id_m.sw_if_index,
162                 port=id_m.port,
163                 flags=id_m.flags,
164                 vrf_id=id_m.vrf_id,
165                 protocol=id_m.protocol)
166
167         addresses = self.vapi.nat44_address_dump()
168         for addr in addresses:
169             self.vapi.nat44_add_del_address_range(
170                 first_ip_address=addr.ip_address,
171                 last_ip_address=addr.ip_address,
172                 vrf_id=0xFFFFFFFF, flags=addr.flags)
173
174         self.verify_no_nat44_user()
175         self.vapi.nat_set_timeouts(udp=300, tcp_established=7440,
176                                    tcp_transitory=240, icmp=60)
177         self.vapi.nat_set_addr_and_port_alloc_alg()
178         self.vapi.nat_set_mss_clamping(enable=0, mss_value=1500)
179
180     def nat44_add_static_mapping(self, local_ip, external_ip='0.0.0.0',
181                                  local_port=0, external_port=0, vrf_id=0,
182                                  is_add=1, external_sw_if_index=0xFFFFFFFF,
183                                  proto=0, tag="", flags=0):
184         """
185         Add/delete NAT44 static mapping
186
187         :param local_ip: Local IP address
188         :param external_ip: External IP address
189         :param local_port: Local port number (Optional)
190         :param external_port: External port number (Optional)
191         :param vrf_id: VRF ID (Default 0)
192         :param is_add: 1 if add, 0 if delete (Default add)
193         :param external_sw_if_index: External interface instead of IP address
194         :param proto: IP protocol (Mandatory if port specified)
195         :param tag: Opaque string tag
196         :param flags: NAT configuration flags
197         """
198
199         if not (local_port and external_port):
200             flags |= self.config_flags.NAT_IS_ADDR_ONLY
201
202         self.vapi.nat44_add_del_static_mapping(
203             is_add=is_add,
204             local_ip_address=local_ip,
205             external_ip_address=external_ip,
206             external_sw_if_index=external_sw_if_index,
207             local_port=local_port,
208             external_port=external_port,
209             vrf_id=vrf_id, protocol=proto,
210             flags=flags,
211             tag=tag)
212
213     def nat44_add_address(self, ip, is_add=1, vrf_id=0xFFFFFFFF, twice_nat=0):
214         """
215         Add/delete NAT44 address
216
217         :param ip: IP address
218         :param is_add: 1 if add, 0 if delete (Default add)
219         :param twice_nat: twice NAT address for external hosts
220         """
221         flags = self.config_flags.NAT_IS_TWICE_NAT if twice_nat else 0
222         self.vapi.nat44_add_del_address_range(first_ip_address=ip,
223                                               last_ip_address=ip,
224                                               vrf_id=vrf_id,
225                                               is_add=is_add,
226                                               flags=flags)
227
228     def create_stream_in(self, in_if, out_if, dst_ip=None, ttl=64):
229         """
230         Create packet stream for inside network
231
232         :param in_if: Inside interface
233         :param out_if: Outside interface
234         :param dst_ip: Destination address
235         :param ttl: TTL of generated packets
236         """
237         if dst_ip is None:
238             dst_ip = out_if.remote_ip4
239
240         pkts = []
241         # TCP
242         p = (Ether(dst=in_if.local_mac, src=in_if.remote_mac) /
243              IP(src=in_if.remote_ip4, dst=dst_ip, ttl=ttl) /
244              TCP(sport=self.tcp_port_in, dport=20))
245         pkts.extend([p, p])
246
247         # UDP
248         p = (Ether(dst=in_if.local_mac, src=in_if.remote_mac) /
249              IP(src=in_if.remote_ip4, dst=dst_ip, ttl=ttl) /
250              UDP(sport=self.udp_port_in, dport=20))
251         pkts.append(p)
252
253         # ICMP
254         p = (Ether(dst=in_if.local_mac, src=in_if.remote_mac) /
255              IP(src=in_if.remote_ip4, dst=dst_ip, ttl=ttl) /
256              ICMP(id=self.icmp_id_in, type='echo-request'))
257         pkts.append(p)
258
259         return pkts
260
261     def compose_ip6(self, ip4, pref, plen):
262         """
263         Compose IPv4-embedded IPv6 addresses
264
265         :param ip4: IPv4 address
266         :param pref: IPv6 prefix
267         :param plen: IPv6 prefix length
268         :returns: IPv4-embedded IPv6 addresses
269         """
270         pref_n = list(socket.inet_pton(socket.AF_INET6, pref))
271         ip4_n = list(socket.inet_pton(socket.AF_INET, ip4))
272         if plen == 32:
273             pref_n[4] = ip4_n[0]
274             pref_n[5] = ip4_n[1]
275             pref_n[6] = ip4_n[2]
276             pref_n[7] = ip4_n[3]
277         elif plen == 40:
278             pref_n[5] = ip4_n[0]
279             pref_n[6] = ip4_n[1]
280             pref_n[7] = ip4_n[2]
281             pref_n[9] = ip4_n[3]
282         elif plen == 48:
283             pref_n[6] = ip4_n[0]
284             pref_n[7] = ip4_n[1]
285             pref_n[9] = ip4_n[2]
286             pref_n[10] = ip4_n[3]
287         elif plen == 56:
288             pref_n[7] = ip4_n[0]
289             pref_n[9] = ip4_n[1]
290             pref_n[10] = ip4_n[2]
291             pref_n[11] = ip4_n[3]
292         elif plen == 64:
293             pref_n[9] = ip4_n[0]
294             pref_n[10] = ip4_n[1]
295             pref_n[11] = ip4_n[2]
296             pref_n[12] = ip4_n[3]
297         elif plen == 96:
298             pref_n[12] = ip4_n[0]
299             pref_n[13] = ip4_n[1]
300             pref_n[14] = ip4_n[2]
301             pref_n[15] = ip4_n[3]
302         packed_pref_n = b''.join([scapy.compat.chb(x) for x in pref_n])
303         return socket.inet_ntop(socket.AF_INET6, packed_pref_n)
304
305     def extract_ip4(self, ip6, plen):
306         """
307         Extract IPv4 address embedded in IPv6 addresses
308
309         :param ip6: IPv6 address
310         :param plen: IPv6 prefix length
311         :returns: extracted IPv4 address
312         """
313         ip6_n = list(socket.inet_pton(socket.AF_INET6, ip6))
314         ip4_n = [None] * 4
315         if plen == 32:
316             ip4_n[0] = ip6_n[4]
317             ip4_n[1] = ip6_n[5]
318             ip4_n[2] = ip6_n[6]
319             ip4_n[3] = ip6_n[7]
320         elif plen == 40:
321             ip4_n[0] = ip6_n[5]
322             ip4_n[1] = ip6_n[6]
323             ip4_n[2] = ip6_n[7]
324             ip4_n[3] = ip6_n[9]
325         elif plen == 48:
326             ip4_n[0] = ip6_n[6]
327             ip4_n[1] = ip6_n[7]
328             ip4_n[2] = ip6_n[9]
329             ip4_n[3] = ip6_n[10]
330         elif plen == 56:
331             ip4_n[0] = ip6_n[7]
332             ip4_n[1] = ip6_n[9]
333             ip4_n[2] = ip6_n[10]
334             ip4_n[3] = ip6_n[11]
335         elif plen == 64:
336             ip4_n[0] = ip6_n[9]
337             ip4_n[1] = ip6_n[10]
338             ip4_n[2] = ip6_n[11]
339             ip4_n[3] = ip6_n[12]
340         elif plen == 96:
341             ip4_n[0] = ip6_n[12]
342             ip4_n[1] = ip6_n[13]
343             ip4_n[2] = ip6_n[14]
344             ip4_n[3] = ip6_n[15]
345         return socket.inet_ntop(socket.AF_INET, ''.join(ip4_n))
346
347     def create_stream_in_ip6(self, in_if, out_if, hlim=64, pref=None, plen=0):
348         """
349         Create IPv6 packet stream for inside network
350
351         :param in_if: Inside interface
352         :param out_if: Outside interface
353         :param ttl: Hop Limit of generated packets
354         :param pref: NAT64 prefix
355         :param plen: NAT64 prefix length
356         """
357         pkts = []
358         if pref is None:
359             dst = ''.join(['64:ff9b::', out_if.remote_ip4])
360         else:
361             dst = self.compose_ip6(out_if.remote_ip4, pref, plen)
362
363         # TCP
364         p = (Ether(dst=in_if.local_mac, src=in_if.remote_mac) /
365              IPv6(src=in_if.remote_ip6, dst=dst, hlim=hlim) /
366              TCP(sport=self.tcp_port_in, dport=20))
367         pkts.append(p)
368
369         # UDP
370         p = (Ether(dst=in_if.local_mac, src=in_if.remote_mac) /
371              IPv6(src=in_if.remote_ip6, dst=dst, hlim=hlim) /
372              UDP(sport=self.udp_port_in, dport=20))
373         pkts.append(p)
374
375         # ICMP
376         p = (Ether(dst=in_if.local_mac, src=in_if.remote_mac) /
377              IPv6(src=in_if.remote_ip6, dst=dst, hlim=hlim) /
378              ICMPv6EchoRequest(id=self.icmp_id_in))
379         pkts.append(p)
380
381         return pkts
382
383     def create_stream_out(self, out_if, dst_ip=None, ttl=64,
384                           use_inside_ports=False):
385         """
386         Create packet stream for outside network
387
388         :param out_if: Outside interface
389         :param dst_ip: Destination IP address (Default use global NAT address)
390         :param ttl: TTL of generated packets
391         :param use_inside_ports: Use inside NAT ports as destination ports
392                instead of outside ports
393         """
394         if dst_ip is None:
395             dst_ip = self.nat_addr
396         if not use_inside_ports:
397             tcp_port = self.tcp_port_out
398             udp_port = self.udp_port_out
399             icmp_id = self.icmp_id_out
400         else:
401             tcp_port = self.tcp_port_in
402             udp_port = self.udp_port_in
403             icmp_id = self.icmp_id_in
404         pkts = []
405         # TCP
406         p = (Ether(dst=out_if.local_mac, src=out_if.remote_mac) /
407              IP(src=out_if.remote_ip4, dst=dst_ip, ttl=ttl) /
408              TCP(dport=tcp_port, sport=20))
409         pkts.extend([p, p])
410
411         # UDP
412         p = (Ether(dst=out_if.local_mac, src=out_if.remote_mac) /
413              IP(src=out_if.remote_ip4, dst=dst_ip, ttl=ttl) /
414              UDP(dport=udp_port, sport=20))
415         pkts.append(p)
416
417         # ICMP
418         p = (Ether(dst=out_if.local_mac, src=out_if.remote_mac) /
419              IP(src=out_if.remote_ip4, dst=dst_ip, ttl=ttl) /
420              ICMP(id=icmp_id, type='echo-reply'))
421         pkts.append(p)
422
423         return pkts
424
425     def create_stream_out_ip6(self, out_if, src_ip, dst_ip, hl=64):
426         """
427         Create packet stream for outside network
428
429         :param out_if: Outside interface
430         :param dst_ip: Destination IP address (Default use global NAT address)
431         :param hl: HL of generated packets
432         """
433         pkts = []
434         # TCP
435         p = (Ether(dst=out_if.local_mac, src=out_if.remote_mac) /
436              IPv6(src=src_ip, dst=dst_ip, hlim=hl) /
437              TCP(dport=self.tcp_port_out, sport=20))
438         pkts.append(p)
439
440         # UDP
441         p = (Ether(dst=out_if.local_mac, src=out_if.remote_mac) /
442              IPv6(src=src_ip, dst=dst_ip, hlim=hl) /
443              UDP(dport=self.udp_port_out, sport=20))
444         pkts.append(p)
445
446         # ICMP
447         p = (Ether(dst=out_if.local_mac, src=out_if.remote_mac) /
448              IPv6(src=src_ip, dst=dst_ip, hlim=hl) /
449              ICMPv6EchoReply(id=self.icmp_id_out))
450         pkts.append(p)
451
452         return pkts
453
454     def verify_capture_out(self, capture, nat_ip=None, same_port=False,
455                            dst_ip=None, is_ip6=False):
456         """
457         Verify captured packets on outside network
458
459         :param capture: Captured packets
460         :param nat_ip: Translated IP address (Default use global NAT address)
461         :param same_port: Source port number is not translated (Default False)
462         :param dst_ip: Destination IP address (Default do not verify)
463         :param is_ip6: If L3 protocol is IPv6 (Default False)
464         """
465         if is_ip6:
466             IP46 = IPv6
467             ICMP46 = ICMPv6EchoRequest
468         else:
469             IP46 = IP
470             ICMP46 = ICMP
471         if nat_ip is None:
472             nat_ip = self.nat_addr
473         for packet in capture:
474             try:
475                 if not is_ip6:
476                     self.assert_packet_checksums_valid(packet)
477                 self.assertEqual(packet[IP46].src, nat_ip)
478                 if dst_ip is not None:
479                     self.assertEqual(packet[IP46].dst, dst_ip)
480                 if packet.haslayer(TCP):
481                     if same_port:
482                         self.assertEqual(packet[TCP].sport, self.tcp_port_in)
483                     else:
484                         self.assertNotEqual(
485                             packet[TCP].sport, self.tcp_port_in)
486                     self.tcp_port_out = packet[TCP].sport
487                     self.assert_packet_checksums_valid(packet)
488                 elif packet.haslayer(UDP):
489                     if same_port:
490                         self.assertEqual(packet[UDP].sport, self.udp_port_in)
491                     else:
492                         self.assertNotEqual(
493                             packet[UDP].sport, self.udp_port_in)
494                     self.udp_port_out = packet[UDP].sport
495                 else:
496                     if same_port:
497                         self.assertEqual(packet[ICMP46].id, self.icmp_id_in)
498                     else:
499                         self.assertNotEqual(packet[ICMP46].id, self.icmp_id_in)
500                     self.icmp_id_out = packet[ICMP46].id
501                     self.assert_packet_checksums_valid(packet)
502             except:
503                 self.logger.error(ppp("Unexpected or invalid packet "
504                                       "(outside network):", packet))
505                 raise
506
507     def verify_capture_out_ip6(self, capture, nat_ip, same_port=False,
508                                dst_ip=None):
509         """
510         Verify captured packets on outside network
511
512         :param capture: Captured packets
513         :param nat_ip: Translated IP address
514         :param same_port: Source port number is not translated (Default False)
515         :param dst_ip: Destination IP address (Default do not verify)
516         """
517         return self.verify_capture_out(capture, nat_ip, same_port, dst_ip,
518                                        True)
519
520     def verify_capture_in(self, capture, in_if):
521         """
522         Verify captured packets on inside network
523
524         :param capture: Captured packets
525         :param in_if: Inside interface
526         """
527         for packet in capture:
528             try:
529                 self.assert_packet_checksums_valid(packet)
530                 self.assertEqual(packet[IP].dst, in_if.remote_ip4)
531                 if packet.haslayer(TCP):
532                     self.assertEqual(packet[TCP].dport, self.tcp_port_in)
533                 elif packet.haslayer(UDP):
534                     self.assertEqual(packet[UDP].dport, self.udp_port_in)
535                 else:
536                     self.assertEqual(packet[ICMP].id, self.icmp_id_in)
537             except:
538                 self.logger.error(ppp("Unexpected or invalid packet "
539                                       "(inside network):", packet))
540                 raise
541
542     def verify_capture_in_ip6(self, capture, src_ip, dst_ip):
543         """
544         Verify captured IPv6 packets on inside network
545
546         :param capture: Captured packets
547         :param src_ip: Source IP
548         :param dst_ip: Destination IP address
549         """
550         for packet in capture:
551             try:
552                 self.assertEqual(packet[IPv6].src, src_ip)
553                 self.assertEqual(packet[IPv6].dst, dst_ip)
554                 self.assert_packet_checksums_valid(packet)
555                 if packet.haslayer(TCP):
556                     self.assertEqual(packet[TCP].dport, self.tcp_port_in)
557                 elif packet.haslayer(UDP):
558                     self.assertEqual(packet[UDP].dport, self.udp_port_in)
559                 else:
560                     self.assertEqual(packet[ICMPv6EchoReply].id,
561                                      self.icmp_id_in)
562             except:
563                 self.logger.error(ppp("Unexpected or invalid packet "
564                                       "(inside network):", packet))
565                 raise
566
567     def verify_capture_no_translation(self, capture, ingress_if, egress_if):
568         """
569         Verify captured packet that don't have to be translated
570
571         :param capture: Captured packets
572         :param ingress_if: Ingress interface
573         :param egress_if: Egress interface
574         """
575         for packet in capture:
576             try:
577                 self.assertEqual(packet[IP].src, ingress_if.remote_ip4)
578                 self.assertEqual(packet[IP].dst, egress_if.remote_ip4)
579                 if packet.haslayer(TCP):
580                     self.assertEqual(packet[TCP].sport, self.tcp_port_in)
581                 elif packet.haslayer(UDP):
582                     self.assertEqual(packet[UDP].sport, self.udp_port_in)
583                 else:
584                     self.assertEqual(packet[ICMP].id, self.icmp_id_in)
585             except:
586                 self.logger.error(ppp("Unexpected or invalid packet "
587                                       "(inside network):", packet))
588                 raise
589
590     def verify_capture_out_with_icmp_errors(self, capture, src_ip=None,
591                                             icmp_type=11):
592         """
593         Verify captured packets with ICMP errors on outside network
594
595         :param capture: Captured packets
596         :param src_ip: Translated IP address or IP address of VPP
597                        (Default use global NAT address)
598         :param icmp_type: Type of error ICMP packet
599                           we are expecting (Default 11)
600         """
601         if src_ip is None:
602             src_ip = self.nat_addr
603         for packet in capture:
604             try:
605                 self.assertEqual(packet[IP].src, src_ip)
606                 self.assertEqual(packet.haslayer(ICMP), 1)
607                 icmp = packet[ICMP]
608                 self.assertEqual(icmp.type, icmp_type)
609                 self.assertTrue(icmp.haslayer(IPerror))
610                 inner_ip = icmp[IPerror]
611                 if inner_ip.haslayer(TCPerror):
612                     self.assertEqual(inner_ip[TCPerror].dport,
613                                      self.tcp_port_out)
614                 elif inner_ip.haslayer(UDPerror):
615                     self.assertEqual(inner_ip[UDPerror].dport,
616                                      self.udp_port_out)
617                 else:
618                     self.assertEqual(inner_ip[ICMPerror].id, self.icmp_id_out)
619             except:
620                 self.logger.error(ppp("Unexpected or invalid packet "
621                                       "(outside network):", packet))
622                 raise
623
624     def verify_capture_in_with_icmp_errors(self, capture, in_if, icmp_type=11):
625         """
626         Verify captured packets with ICMP errors on inside network
627
628         :param capture: Captured packets
629         :param in_if: Inside interface
630         :param icmp_type: Type of error ICMP packet
631                           we are expecting (Default 11)
632         """
633         for packet in capture:
634             try:
635                 self.assertEqual(packet[IP].dst, in_if.remote_ip4)
636                 self.assertEqual(packet.haslayer(ICMP), 1)
637                 icmp = packet[ICMP]
638                 self.assertEqual(icmp.type, icmp_type)
639                 self.assertTrue(icmp.haslayer(IPerror))
640                 inner_ip = icmp[IPerror]
641                 if inner_ip.haslayer(TCPerror):
642                     self.assertEqual(inner_ip[TCPerror].sport,
643                                      self.tcp_port_in)
644                 elif inner_ip.haslayer(UDPerror):
645                     self.assertEqual(inner_ip[UDPerror].sport,
646                                      self.udp_port_in)
647                 else:
648                     self.assertEqual(inner_ip[ICMPerror].id, self.icmp_id_in)
649             except:
650                 self.logger.error(ppp("Unexpected or invalid packet "
651                                       "(inside network):", packet))
652                 raise
653
654     def create_stream_frag(self, src_if, dst, sport, dport, data,
655                            proto=IP_PROTOS.tcp, echo_reply=False):
656         """
657         Create fragmented packet stream
658
659         :param src_if: Source interface
660         :param dst: Destination IPv4 address
661         :param sport: Source port
662         :param dport: Destination port
663         :param data: Payload data
664         :param proto: protocol (TCP, UDP, ICMP)
665         :param echo_reply: use echo_reply if protocol is ICMP
666         :returns: Fragments
667         """
668         if proto == IP_PROTOS.tcp:
669             p = (IP(src=src_if.remote_ip4, dst=dst) /
670                  TCP(sport=sport, dport=dport) /
671                  Raw(data))
672             p = p.__class__(scapy.compat.raw(p))
673             chksum = p[TCP].chksum
674             proto_header = TCP(sport=sport, dport=dport, chksum=chksum)
675         elif proto == IP_PROTOS.udp:
676             proto_header = UDP(sport=sport, dport=dport)
677         elif proto == IP_PROTOS.icmp:
678             if not echo_reply:
679                 proto_header = ICMP(id=sport, type='echo-request')
680             else:
681                 proto_header = ICMP(id=sport, type='echo-reply')
682         else:
683             raise Exception("Unsupported protocol")
684         id = random.randint(0, 65535)
685         pkts = []
686         if proto == IP_PROTOS.tcp:
687             raw = Raw(data[0:4])
688         else:
689             raw = Raw(data[0:16])
690         p = (Ether(src=src_if.remote_mac, dst=src_if.local_mac) /
691              IP(src=src_if.remote_ip4, dst=dst, flags="MF", frag=0, id=id) /
692              proto_header /
693              raw)
694         pkts.append(p)
695         if proto == IP_PROTOS.tcp:
696             raw = Raw(data[4:20])
697         else:
698             raw = Raw(data[16:32])
699         p = (Ether(src=src_if.remote_mac, dst=src_if.local_mac) /
700              IP(src=src_if.remote_ip4, dst=dst, flags="MF", frag=3, id=id,
701                 proto=proto) /
702              raw)
703         pkts.append(p)
704         if proto == IP_PROTOS.tcp:
705             raw = Raw(data[20:])
706         else:
707             raw = Raw(data[32:])
708         p = (Ether(src=src_if.remote_mac, dst=src_if.local_mac) /
709              IP(src=src_if.remote_ip4, dst=dst, frag=5, proto=proto,
710                 id=id) /
711              raw)
712         pkts.append(p)
713         return pkts
714
715     def create_stream_frag_ip6(self, src_if, dst, sport, dport, data,
716                                pref=None, plen=0, frag_size=128):
717         """
718         Create fragmented packet stream
719
720         :param src_if: Source interface
721         :param dst: Destination IPv4 address
722         :param sport: Source TCP port
723         :param dport: Destination TCP port
724         :param data: Payload data
725         :param pref: NAT64 prefix
726         :param plen: NAT64 prefix length
727         :param fragsize: size of fragments
728         :returns: Fragments
729         """
730         if pref is None:
731             dst_ip6 = ''.join(['64:ff9b::', dst])
732         else:
733             dst_ip6 = self.compose_ip6(dst, pref, plen)
734
735         p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
736              IPv6(src=src_if.remote_ip6, dst=dst_ip6) /
737              IPv6ExtHdrFragment(id=random.randint(0, 65535)) /
738              TCP(sport=sport, dport=dport) /
739              Raw(data))
740
741         return fragment6(p, frag_size)
742
743     def reass_frags_and_verify(self, frags, src, dst):
744         """
745         Reassemble and verify fragmented packet
746
747         :param frags: Captured fragments
748         :param src: Source IPv4 address to verify
749         :param dst: Destination IPv4 address to verify
750
751         :returns: Reassembled IPv4 packet
752         """
753         buffer = BytesIO()
754         for p in frags:
755             self.assertEqual(p[IP].src, src)
756             self.assertEqual(p[IP].dst, dst)
757             self.assert_ip_checksum_valid(p)
758             buffer.seek(p[IP].frag * 8)
759             buffer.write(bytes(p[IP].payload))
760         ip = IP(src=frags[0][IP].src, dst=frags[0][IP].dst,
761                 proto=frags[0][IP].proto)
762         if ip.proto == IP_PROTOS.tcp:
763             p = (ip / TCP(buffer.getvalue()))
764             self.logger.debug(ppp("Reassembled:", p))
765             self.assert_tcp_checksum_valid(p)
766         elif ip.proto == IP_PROTOS.udp:
767             p = (ip / UDP(buffer.getvalue()[:8]) /
768                  Raw(buffer.getvalue()[8:]))
769         elif ip.proto == IP_PROTOS.icmp:
770             p = (ip / ICMP(buffer.getvalue()))
771         return p
772
773     def reass_frags_and_verify_ip6(self, frags, src, dst):
774         """
775         Reassemble and verify fragmented packet
776
777         :param frags: Captured fragments
778         :param src: Source IPv6 address to verify
779         :param dst: Destination IPv6 address to verify
780
781         :returns: Reassembled IPv6 packet
782         """
783         buffer = BytesIO()
784         for p in frags:
785             self.assertEqual(p[IPv6].src, src)
786             self.assertEqual(p[IPv6].dst, dst)
787             buffer.seek(p[IPv6ExtHdrFragment].offset * 8)
788             buffer.write(bytes(p[IPv6ExtHdrFragment].payload))
789         ip = IPv6(src=frags[0][IPv6].src, dst=frags[0][IPv6].dst,
790                   nh=frags[0][IPv6ExtHdrFragment].nh)
791         if ip.nh == IP_PROTOS.tcp:
792             p = (ip / TCP(buffer.getvalue()))
793         elif ip.nh == IP_PROTOS.udp:
794             p = (ip / UDP(buffer.getvalue()))
795         self.logger.debug(ppp("Reassembled:", p))
796         self.assert_packet_checksums_valid(p)
797         return p
798
799     def initiate_tcp_session(self, in_if, out_if):
800         """
801         Initiates TCP session
802
803         :param in_if: Inside interface
804         :param out_if: Outside interface
805         """
806         try:
807             # SYN packet in->out
808             p = (Ether(src=in_if.remote_mac, dst=in_if.local_mac) /
809                  IP(src=in_if.remote_ip4, dst=out_if.remote_ip4) /
810                  TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
811                      flags="S"))
812             in_if.add_stream(p)
813             self.pg_enable_capture(self.pg_interfaces)
814             self.pg_start()
815             capture = out_if.get_capture(1)
816             p = capture[0]
817             self.tcp_port_out = p[TCP].sport
818
819             # SYN + ACK packet out->in
820             p = (Ether(src=out_if.remote_mac, dst=out_if.local_mac) /
821                  IP(src=out_if.remote_ip4, dst=self.nat_addr) /
822                  TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
823                      flags="SA"))
824             out_if.add_stream(p)
825             self.pg_enable_capture(self.pg_interfaces)
826             self.pg_start()
827             in_if.get_capture(1)
828
829             # ACK packet in->out
830             p = (Ether(src=in_if.remote_mac, dst=in_if.local_mac) /
831                  IP(src=in_if.remote_ip4, dst=out_if.remote_ip4) /
832                  TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
833                      flags="A"))
834             in_if.add_stream(p)
835             self.pg_enable_capture(self.pg_interfaces)
836             self.pg_start()
837             out_if.get_capture(1)
838
839         except:
840             self.logger.error("TCP 3 way handshake failed")
841             raise
842
843     def verify_ipfix_nat44_ses(self, data):
844         """
845         Verify IPFIX NAT44 session create/delete event
846
847         :param data: Decoded IPFIX data records
848         """
849         nat44_ses_create_num = 0
850         nat44_ses_delete_num = 0
851         self.assertEqual(6, len(data))
852         for record in data:
853             # natEvent
854             self.assertIn(scapy.compat.orb(record[230]), [4, 5])
855             if scapy.compat.orb(record[230]) == 4:
856                 nat44_ses_create_num += 1
857             else:
858                 nat44_ses_delete_num += 1
859             # sourceIPv4Address
860             self.assertEqual(self.pg0.remote_ip4n, record[8])
861             # postNATSourceIPv4Address
862             self.assertEqual(socket.inet_pton(socket.AF_INET, self.nat_addr),
863                              record[225])
864             # ingressVRFID
865             self.assertEqual(struct.pack("!I", 0), record[234])
866             # protocolIdentifier/sourceTransportPort
867             # /postNAPTSourceTransportPort
868             if IP_PROTOS.icmp == scapy.compat.orb(record[4]):
869                 self.assertEqual(struct.pack("!H", self.icmp_id_in), record[7])
870                 self.assertEqual(struct.pack("!H", self.icmp_id_out),
871                                  record[227])
872             elif IP_PROTOS.tcp == scapy.compat.orb(record[4]):
873                 self.assertEqual(struct.pack("!H", self.tcp_port_in),
874                                  record[7])
875                 self.assertEqual(struct.pack("!H", self.tcp_port_out),
876                                  record[227])
877             elif IP_PROTOS.udp == scapy.compat.orb(record[4]):
878                 self.assertEqual(struct.pack("!H", self.udp_port_in),
879                                  record[7])
880                 self.assertEqual(struct.pack("!H", self.udp_port_out),
881                                  record[227])
882             else:
883                 self.fail("Invalid protocol")
884         self.assertEqual(3, nat44_ses_create_num)
885         self.assertEqual(3, nat44_ses_delete_num)
886
887     def verify_ipfix_addr_exhausted(self, data):
888         """
889         Verify IPFIX NAT addresses event
890
891         :param data: Decoded IPFIX data records
892         """
893         self.assertEqual(1, len(data))
894         record = data[0]
895         # natEvent
896         self.assertEqual(scapy.compat.orb(record[230]), 3)
897         # natPoolID
898         self.assertEqual(struct.pack("!I", 0), record[283])
899
900     def verify_ipfix_max_sessions(self, data, limit):
901         """
902         Verify IPFIX maximum session entries exceeded event
903
904         :param data: Decoded IPFIX data records
905         :param limit: Number of maximum session entries that can be created.
906         """
907         self.assertEqual(1, len(data))
908         record = data[0]
909         # natEvent
910         self.assertEqual(scapy.compat.orb(record[230]), 13)
911         # natQuotaExceededEvent
912         self.assertEqual(struct.pack("I", 1), record[466])
913         # maxSessionEntries
914         self.assertEqual(struct.pack("I", limit), record[471])
915
916     def verify_ipfix_max_bibs(self, data, limit):
917         """
918         Verify IPFIX maximum BIB entries exceeded event
919
920         :param data: Decoded IPFIX data records
921         :param limit: Number of maximum BIB entries that can be created.
922         """
923         self.assertEqual(1, len(data))
924         record = data[0]
925         # natEvent
926         self.assertEqual(scapy.compat.orb(record[230]), 13)
927         # natQuotaExceededEvent
928         self.assertEqual(struct.pack("I", 2), record[466])
929         # maxBIBEntries
930         self.assertEqual(struct.pack("I", limit), record[472])
931
932     def verify_ipfix_bib(self, data, is_create, src_addr):
933         """
934         Verify IPFIX NAT64 BIB create and delete events
935
936         :param data: Decoded IPFIX data records
937         :param is_create: Create event if nonzero value otherwise delete event
938         :param src_addr: IPv6 source address
939         """
940         self.assertEqual(1, len(data))
941         record = data[0]
942         # natEvent
943         if is_create:
944             self.assertEqual(scapy.compat.orb(record[230]), 10)
945         else:
946             self.assertEqual(scapy.compat.orb(record[230]), 11)
947         # sourceIPv6Address
948         self.assertEqual(src_addr, record[27])
949         # postNATSourceIPv4Address
950         self.assertEqual(self.nat_addr_n, record[225])
951         # protocolIdentifier
952         self.assertEqual(IP_PROTOS.tcp, scapy.compat.orb(record[4]))
953         # ingressVRFID
954         self.assertEqual(struct.pack("!I", 0), record[234])
955         # sourceTransportPort
956         self.assertEqual(struct.pack("!H", self.tcp_port_in), record[7])
957         # postNAPTSourceTransportPort
958         self.assertEqual(struct.pack("!H", self.tcp_port_out), record[227])
959
960     def verify_ipfix_nat64_ses(self, data, is_create, src_addr, dst_addr,
961                                dst_port):
962         """
963         Verify IPFIX NAT64 session create and delete events
964
965         :param data: Decoded IPFIX data records
966         :param is_create: Create event if nonzero value otherwise delete event
967         :param src_addr: IPv6 source address
968         :param dst_addr: IPv4 destination address
969         :param dst_port: destination TCP port
970         """
971         self.assertEqual(1, len(data))
972         record = data[0]
973         # natEvent
974         if is_create:
975             self.assertEqual(scapy.compat.orb(record[230]), 6)
976         else:
977             self.assertEqual(scapy.compat.orb(record[230]), 7)
978         # sourceIPv6Address
979         self.assertEqual(src_addr, record[27])
980         # destinationIPv6Address
981         self.assertEqual(socket.inet_pton(socket.AF_INET6,
982                                           self.compose_ip6(dst_addr,
983                                                            '64:ff9b::',
984                                                            96)),
985                          record[28])
986         # postNATSourceIPv4Address
987         self.assertEqual(self.nat_addr_n, record[225])
988         # postNATDestinationIPv4Address
989         self.assertEqual(socket.inet_pton(socket.AF_INET, dst_addr),
990                          record[226])
991         # protocolIdentifier
992         self.assertEqual(IP_PROTOS.tcp, scapy.compat.orb(record[4]))
993         # ingressVRFID
994         self.assertEqual(struct.pack("!I", 0), record[234])
995         # sourceTransportPort
996         self.assertEqual(struct.pack("!H", self.tcp_port_in), record[7])
997         # postNAPTSourceTransportPort
998         self.assertEqual(struct.pack("!H", self.tcp_port_out), record[227])
999         # destinationTransportPort
1000         self.assertEqual(struct.pack("!H", dst_port), record[11])
1001         # postNAPTDestinationTransportPort
1002         self.assertEqual(struct.pack("!H", dst_port), record[228])
1003
1004     def verify_no_nat44_user(self):
1005         """ Verify that there is no NAT44 user """
1006         users = self.vapi.nat44_user_dump()
1007         self.assertEqual(len(users), 0)
1008         users = self.statistics.get_counter('/nat44/total-users')
1009         self.assertEqual(users[0][0], 0)
1010         sessions = self.statistics.get_counter('/nat44/total-sessions')
1011         self.assertEqual(sessions[0][0], 0)
1012
1013     def verify_ipfix_max_entries_per_user(self, data, limit, src_addr):
1014         """
1015         Verify IPFIX maximum entries per user exceeded event
1016
1017         :param data: Decoded IPFIX data records
1018         :param limit: Number of maximum entries per user
1019         :param src_addr: IPv4 source address
1020         """
1021         self.assertEqual(1, len(data))
1022         record = data[0]
1023         # natEvent
1024         self.assertEqual(scapy.compat.orb(record[230]), 13)
1025         # natQuotaExceededEvent
1026         self.assertEqual(struct.pack("I", 3), record[466])
1027         # maxEntriesPerUser
1028         self.assertEqual(struct.pack("I", limit), record[473])
1029         # sourceIPv4Address
1030         self.assertEqual(socket.inet_pton(socket.AF_INET, src_addr), record[8])
1031
1032     def verify_syslog_apmap(self, data, is_add=True):
1033         message = data.decode('utf-8')
1034         try:
1035             message = SyslogMessage.parse(message)
1036         except ParseError as e:
1037             self.logger.error(e)
1038             raise
1039         else:
1040             self.assertEqual(message.severity, SyslogSeverity.info)
1041             self.assertEqual(message.appname, 'NAT')
1042             self.assertEqual(message.msgid, 'APMADD' if is_add else 'APMDEL')
1043             sd_params = message.sd.get('napmap')
1044             self.assertTrue(sd_params is not None)
1045             self.assertEqual(sd_params.get('IATYP'), 'IPv4')
1046             self.assertEqual(sd_params.get('ISADDR'), self.pg0.remote_ip4)
1047             self.assertEqual(sd_params.get('ISPORT'), "%d" % self.tcp_port_in)
1048             self.assertEqual(sd_params.get('XATYP'), 'IPv4')
1049             self.assertEqual(sd_params.get('XSADDR'), self.nat_addr)
1050             self.assertEqual(sd_params.get('XSPORT'), "%d" % self.tcp_port_out)
1051             self.assertEqual(sd_params.get('PROTO'), "%d" % IP_PROTOS.tcp)
1052             self.assertTrue(sd_params.get('SSUBIX') is not None)
1053             self.assertEqual(sd_params.get('SVLAN'), '0')
1054
1055     def verify_syslog_sess(self, data, is_add=True, is_ip6=False):
1056         message = data.decode('utf-8')
1057         try:
1058             message = SyslogMessage.parse(message)
1059         except ParseError as e:
1060             self.logger.error(e)
1061             raise
1062         else:
1063             self.assertEqual(message.severity, SyslogSeverity.info)
1064             self.assertEqual(message.appname, 'NAT')
1065             self.assertEqual(message.msgid, 'SADD' if is_add else 'SDEL')
1066             sd_params = message.sd.get('nsess')
1067             self.assertTrue(sd_params is not None)
1068             if is_ip6:
1069                 self.assertEqual(sd_params.get('IATYP'), 'IPv6')
1070                 self.assertEqual(sd_params.get('ISADDR'), self.pg0.remote_ip6)
1071             else:
1072                 self.assertEqual(sd_params.get('IATYP'), 'IPv4')
1073                 self.assertEqual(sd_params.get('ISADDR'), self.pg0.remote_ip4)
1074                 self.assertTrue(sd_params.get('SSUBIX') is not None)
1075             self.assertEqual(sd_params.get('ISPORT'), "%d" % self.tcp_port_in)
1076             self.assertEqual(sd_params.get('XATYP'), 'IPv4')
1077             self.assertEqual(sd_params.get('XSADDR'), self.nat_addr)
1078             self.assertEqual(sd_params.get('XSPORT'), "%d" % self.tcp_port_out)
1079             self.assertEqual(sd_params.get('PROTO'), "%d" % IP_PROTOS.tcp)
1080             self.assertEqual(sd_params.get('SVLAN'), '0')
1081             self.assertEqual(sd_params.get('XDADDR'), self.pg1.remote_ip4)
1082             self.assertEqual(sd_params.get('XDPORT'),
1083                              "%d" % self.tcp_external_port)
1084
1085     def verify_mss_value(self, pkt, mss):
1086         """
1087         Verify TCP MSS value
1088
1089         :param pkt:
1090         :param mss:
1091         """
1092         if not pkt.haslayer(IP) or not pkt.haslayer(TCP):
1093             raise TypeError("Not a TCP/IP packet")
1094
1095         for option in pkt[TCP].options:
1096             if option[0] == 'MSS':
1097                 self.assertEqual(option[1], mss)
1098                 self.assert_tcp_checksum_valid(pkt)
1099
1100     @staticmethod
1101     def proto2layer(proto):
1102         if proto == IP_PROTOS.tcp:
1103             return TCP
1104         elif proto == IP_PROTOS.udp:
1105             return UDP
1106         elif proto == IP_PROTOS.icmp:
1107             return ICMP
1108         else:
1109             raise Exception("Unsupported protocol")
1110
1111     def frag_in_order(self, proto=IP_PROTOS.tcp, dont_translate=False):
1112         layer = self.proto2layer(proto)
1113
1114         if proto == IP_PROTOS.tcp:
1115             data = b"A" * 4 + b"B" * 16 + b"C" * 3
1116         else:
1117             data = b"A" * 16 + b"B" * 16 + b"C" * 3
1118         self.port_in = random.randint(1025, 65535)
1119
1120         # in2out
1121         pkts = self.create_stream_frag(self.pg0, self.pg1.remote_ip4,
1122                                        self.port_in, 20, data, proto)
1123         self.pg0.add_stream(pkts)
1124         self.pg_enable_capture(self.pg_interfaces)
1125         self.pg_start()
1126         frags = self.pg1.get_capture(len(pkts))
1127         if not dont_translate:
1128             p = self.reass_frags_and_verify(frags,
1129                                             self.nat_addr,
1130                                             self.pg1.remote_ip4)
1131         else:
1132             p = self.reass_frags_and_verify(frags,
1133                                             self.pg0.remote_ip4,
1134                                             self.pg1.remote_ip4)
1135         if proto != IP_PROTOS.icmp:
1136             if not dont_translate:
1137                 self.assertEqual(p[layer].dport, 20)
1138                 self.assertNotEqual(p[layer].sport, self.port_in)
1139             else:
1140                 self.assertEqual(p[layer].sport, self.port_in)
1141         else:
1142             if not dont_translate:
1143                 self.assertNotEqual(p[layer].id, self.port_in)
1144             else:
1145                 self.assertEqual(p[layer].id, self.port_in)
1146         self.assertEqual(data, p[Raw].load)
1147
1148         # out2in
1149         if not dont_translate:
1150             dst_addr = self.nat_addr
1151         else:
1152             dst_addr = self.pg0.remote_ip4
1153         if proto != IP_PROTOS.icmp:
1154             sport = 20
1155             dport = p[layer].sport
1156         else:
1157             sport = p[layer].id
1158             dport = 0
1159         pkts = self.create_stream_frag(self.pg1, dst_addr, sport, dport, data,
1160                                        proto, echo_reply=True)
1161         self.pg1.add_stream(pkts)
1162         self.pg_enable_capture(self.pg_interfaces)
1163         self.pg_start()
1164         frags = self.pg0.get_capture(len(pkts))
1165         p = self.reass_frags_and_verify(frags,
1166                                         self.pg1.remote_ip4,
1167                                         self.pg0.remote_ip4)
1168         if proto != IP_PROTOS.icmp:
1169             self.assertEqual(p[layer].sport, 20)
1170             self.assertEqual(p[layer].dport, self.port_in)
1171         else:
1172             self.assertEqual(p[layer].id, self.port_in)
1173         self.assertEqual(data, p[Raw].load)
1174
1175     def frag_in_order_in_plus_out(self, proto=IP_PROTOS.tcp):
1176         layer = self.proto2layer(proto)
1177
1178         if proto == IP_PROTOS.tcp:
1179             data = b"A" * 4 + b"B" * 16 + b"C" * 3
1180         else:
1181             data = b"A" * 16 + b"B" * 16 + b"C" * 3
1182         self.port_in = random.randint(1025, 65535)
1183
1184         for i in range(2):
1185             # out2in
1186             pkts = self.create_stream_frag(self.pg0, self.server_out_addr,
1187                                            self.port_in, self.server_out_port,
1188                                            data, proto)
1189             self.pg0.add_stream(pkts)
1190             self.pg_enable_capture(self.pg_interfaces)
1191             self.pg_start()
1192             frags = self.pg1.get_capture(len(pkts))
1193             p = self.reass_frags_and_verify(frags,
1194                                             self.pg0.remote_ip4,
1195                                             self.server_in_addr)
1196             if proto != IP_PROTOS.icmp:
1197                 self.assertEqual(p[layer].sport, self.port_in)
1198                 self.assertEqual(p[layer].dport, self.server_in_port)
1199             else:
1200                 self.assertEqual(p[layer].id, self.port_in)
1201             self.assertEqual(data, p[Raw].load)
1202
1203             # in2out
1204             if proto != IP_PROTOS.icmp:
1205                 pkts = self.create_stream_frag(self.pg1, self.pg0.remote_ip4,
1206                                                self.server_in_port,
1207                                                p[layer].sport, data, proto)
1208             else:
1209                 pkts = self.create_stream_frag(self.pg1, self.pg0.remote_ip4,
1210                                                p[layer].id, 0, data, proto,
1211                                                echo_reply=True)
1212             self.pg1.add_stream(pkts)
1213             self.pg_enable_capture(self.pg_interfaces)
1214             self.pg_start()
1215             frags = self.pg0.get_capture(len(pkts))
1216             p = self.reass_frags_and_verify(frags,
1217                                             self.server_out_addr,
1218                                             self.pg0.remote_ip4)
1219             if proto != IP_PROTOS.icmp:
1220                 self.assertEqual(p[layer].sport, self.server_out_port)
1221                 self.assertEqual(p[layer].dport, self.port_in)
1222             else:
1223                 self.assertEqual(p[layer].id, self.port_in)
1224             self.assertEqual(data, p[Raw].load)
1225
1226     def reass_hairpinning(self, proto=IP_PROTOS.tcp):
1227         layer = self.proto2layer(proto)
1228
1229         if proto == IP_PROTOS.tcp:
1230             data = b"A" * 4 + b"B" * 16 + b"C" * 3
1231         else:
1232             data = b"A" * 16 + b"B" * 16 + b"C" * 3
1233
1234         # send packet from host to server
1235         pkts = self.create_stream_frag(self.pg0,
1236                                        self.nat_addr,
1237                                        self.host_in_port,
1238                                        self.server_out_port,
1239                                        data,
1240                                        proto)
1241         self.pg0.add_stream(pkts)
1242         self.pg_enable_capture(self.pg_interfaces)
1243         self.pg_start()
1244         frags = self.pg0.get_capture(len(pkts))
1245         p = self.reass_frags_and_verify(frags,
1246                                         self.nat_addr,
1247                                         self.server.ip4)
1248         if proto != IP_PROTOS.icmp:
1249             self.assertNotEqual(p[layer].sport, self.host_in_port)
1250             self.assertEqual(p[layer].dport, self.server_in_port)
1251         else:
1252             self.assertNotEqual(p[layer].id, self.host_in_port)
1253         self.assertEqual(data, p[Raw].load)
1254
1255     def frag_out_of_order(self, proto=IP_PROTOS.tcp, dont_translate=False):
1256         layer = self.proto2layer(proto)
1257
1258         if proto == IP_PROTOS.tcp:
1259             data = b"A" * 4 + b"B" * 16 + b"C" * 3
1260         else:
1261             data = b"A" * 16 + b"B" * 16 + b"C" * 3
1262         self.port_in = random.randint(1025, 65535)
1263
1264         for i in range(2):
1265             # in2out
1266             pkts = self.create_stream_frag(self.pg0, self.pg1.remote_ip4,
1267                                            self.port_in, 20, data, proto)
1268             pkts.reverse()
1269             self.pg0.add_stream(pkts)
1270             self.pg_enable_capture(self.pg_interfaces)
1271             self.pg_start()
1272             frags = self.pg1.get_capture(len(pkts))
1273             if not dont_translate:
1274                 p = self.reass_frags_and_verify(frags,
1275                                                 self.nat_addr,
1276                                                 self.pg1.remote_ip4)
1277             else:
1278                 p = self.reass_frags_and_verify(frags,
1279                                                 self.pg0.remote_ip4,
1280                                                 self.pg1.remote_ip4)
1281             if proto != IP_PROTOS.icmp:
1282                 if not dont_translate:
1283                     self.assertEqual(p[layer].dport, 20)
1284                     self.assertNotEqual(p[layer].sport, self.port_in)
1285                 else:
1286                     self.assertEqual(p[layer].sport, self.port_in)
1287             else:
1288                 if not dont_translate:
1289                     self.assertNotEqual(p[layer].id, self.port_in)
1290                 else:
1291                     self.assertEqual(p[layer].id, self.port_in)
1292             self.assertEqual(data, p[Raw].load)
1293
1294             # out2in
1295             if not dont_translate:
1296                 dst_addr = self.nat_addr
1297             else:
1298                 dst_addr = self.pg0.remote_ip4
1299             if proto != IP_PROTOS.icmp:
1300                 sport = 20
1301                 dport = p[layer].sport
1302             else:
1303                 sport = p[layer].id
1304                 dport = 0
1305             pkts = self.create_stream_frag(self.pg1, dst_addr, sport, dport,
1306                                            data, proto, echo_reply=True)
1307             pkts.reverse()
1308             self.pg1.add_stream(pkts)
1309             self.pg_enable_capture(self.pg_interfaces)
1310             self.pg_start()
1311             frags = self.pg0.get_capture(len(pkts))
1312             p = self.reass_frags_and_verify(frags,
1313                                             self.pg1.remote_ip4,
1314                                             self.pg0.remote_ip4)
1315             if proto != IP_PROTOS.icmp:
1316                 self.assertEqual(p[layer].sport, 20)
1317                 self.assertEqual(p[layer].dport, self.port_in)
1318             else:
1319                 self.assertEqual(p[layer].id, self.port_in)
1320             self.assertEqual(data, p[Raw].load)
1321
1322     def frag_out_of_order_in_plus_out(self, proto=IP_PROTOS.tcp):
1323         layer = self.proto2layer(proto)
1324
1325         if proto == IP_PROTOS.tcp:
1326             data = b"A" * 4 + b"B" * 16 + b"C" * 3
1327         else:
1328             data = b"A" * 16 + b"B" * 16 + b"C" * 3
1329         self.port_in = random.randint(1025, 65535)
1330
1331         for i in range(2):
1332             # out2in
1333             pkts = self.create_stream_frag(self.pg0, self.server_out_addr,
1334                                            self.port_in, self.server_out_port,
1335                                            data, proto)
1336             pkts.reverse()
1337             self.pg0.add_stream(pkts)
1338             self.pg_enable_capture(self.pg_interfaces)
1339             self.pg_start()
1340             frags = self.pg1.get_capture(len(pkts))
1341             p = self.reass_frags_and_verify(frags,
1342                                             self.pg0.remote_ip4,
1343                                             self.server_in_addr)
1344             if proto != IP_PROTOS.icmp:
1345                 self.assertEqual(p[layer].dport, self.server_in_port)
1346                 self.assertEqual(p[layer].sport, self.port_in)
1347                 self.assertEqual(p[layer].dport, self.server_in_port)
1348             else:
1349                 self.assertEqual(p[layer].id, self.port_in)
1350             self.assertEqual(data, p[Raw].load)
1351
1352             # in2out
1353             if proto != IP_PROTOS.icmp:
1354                 pkts = self.create_stream_frag(self.pg1, self.pg0.remote_ip4,
1355                                                self.server_in_port,
1356                                                p[layer].sport, data, proto)
1357             else:
1358                 pkts = self.create_stream_frag(self.pg1, self.pg0.remote_ip4,
1359                                                p[layer].id, 0, data, proto,
1360                                                echo_reply=True)
1361             pkts.reverse()
1362             self.pg1.add_stream(pkts)
1363             self.pg_enable_capture(self.pg_interfaces)
1364             self.pg_start()
1365             frags = self.pg0.get_capture(len(pkts))
1366             p = self.reass_frags_and_verify(frags,
1367                                             self.server_out_addr,
1368                                             self.pg0.remote_ip4)
1369             if proto != IP_PROTOS.icmp:
1370                 self.assertEqual(p[layer].sport, self.server_out_port)
1371                 self.assertEqual(p[layer].dport, self.port_in)
1372             else:
1373                 self.assertEqual(p[layer].id, self.port_in)
1374             self.assertEqual(data, p[Raw].load)
1375
1376
1377 class TestNAT44(MethodHolder):
1378     """ NAT44 Test Cases """
1379
1380     @classmethod
1381     def setUpClass(cls):
1382         super(TestNAT44, cls).setUpClass()
1383         cls.vapi.cli("set log class nat level debug")
1384
1385         cls.tcp_port_in = 6303
1386         cls.tcp_port_out = 6303
1387         cls.udp_port_in = 6304
1388         cls.udp_port_out = 6304
1389         cls.icmp_id_in = 6305
1390         cls.icmp_id_out = 6305
1391         cls.nat_addr = '10.0.0.3'
1392         cls.ipfix_src_port = 4739
1393         cls.ipfix_domain_id = 1
1394         cls.tcp_external_port = 80
1395         cls.udp_external_port = 69
1396
1397         cls.create_pg_interfaces(range(10))
1398         cls.interfaces = list(cls.pg_interfaces[0:4])
1399
1400         for i in cls.interfaces:
1401             i.admin_up()
1402             i.config_ip4()
1403             i.resolve_arp()
1404
1405         cls.pg0.generate_remote_hosts(3)
1406         cls.pg0.configure_ipv4_neighbors()
1407
1408         cls.pg1.generate_remote_hosts(1)
1409         cls.pg1.configure_ipv4_neighbors()
1410
1411         cls.overlapping_interfaces = list(list(cls.pg_interfaces[4:7]))
1412         cls.vapi.ip_table_add_del(is_add=1, table={'table_id': 10})
1413         cls.vapi.ip_table_add_del(is_add=1, table={'table_id': 20})
1414
1415         cls.pg4._local_ip4 = "172.16.255.1"
1416         cls.pg4._remote_hosts[0]._ip4 = "172.16.255.2"
1417         cls.pg4.set_table_ip4(10)
1418         cls.pg5._local_ip4 = "172.17.255.3"
1419         cls.pg5._remote_hosts[0]._ip4 = "172.17.255.4"
1420         cls.pg5.set_table_ip4(10)
1421         cls.pg6._local_ip4 = "172.16.255.1"
1422         cls.pg6._remote_hosts[0]._ip4 = "172.16.255.2"
1423         cls.pg6.set_table_ip4(20)
1424         for i in cls.overlapping_interfaces:
1425             i.config_ip4()
1426             i.admin_up()
1427             i.resolve_arp()
1428
1429         cls.pg7.admin_up()
1430         cls.pg8.admin_up()
1431
1432         cls.pg9.generate_remote_hosts(2)
1433         cls.pg9.config_ip4()
1434         cls.vapi.sw_interface_add_del_address(
1435             sw_if_index=cls.pg9.sw_if_index,
1436             prefix="10.0.0.1/24")
1437
1438         cls.pg9.admin_up()
1439         cls.pg9.resolve_arp()
1440         cls.pg9._remote_hosts[1]._ip4 = cls.pg9._remote_hosts[0]._ip4
1441         cls.pg4._remote_ip4 = cls.pg9._remote_hosts[0]._ip4 = "10.0.0.2"
1442         cls.pg9.resolve_arp()
1443
1444     @classmethod
1445     def tearDownClass(cls):
1446         super(TestNAT44, cls).tearDownClass()
1447
1448     def test_dynamic(self):
1449         """ NAT44 dynamic translation test """
1450         self.nat44_add_address(self.nat_addr)
1451         flags = self.config_flags.NAT_IS_INSIDE
1452         self.vapi.nat44_interface_add_del_feature(
1453             sw_if_index=self.pg0.sw_if_index,
1454             flags=flags, is_add=1)
1455         self.vapi.nat44_interface_add_del_feature(
1456             sw_if_index=self.pg1.sw_if_index,
1457             is_add=1)
1458
1459         # in2out
1460         tcpn = self.statistics.get_err_counter(
1461             '/err/nat44-in2out-slowpath/TCP packets')
1462         udpn = self.statistics.get_err_counter(
1463             '/err/nat44-in2out-slowpath/UDP packets')
1464         icmpn = self.statistics.get_err_counter(
1465             '/err/nat44-in2out-slowpath/ICMP packets')
1466         totaln = self.statistics.get_err_counter(
1467             '/err/nat44-in2out-slowpath/good in2out packets processed')
1468
1469         pkts = self.create_stream_in(self.pg0, self.pg1)
1470         self.pg0.add_stream(pkts)
1471         self.pg_enable_capture(self.pg_interfaces)
1472         self.pg_start()
1473         capture = self.pg1.get_capture(len(pkts))
1474         self.verify_capture_out(capture)
1475
1476         err = self.statistics.get_err_counter(
1477             '/err/nat44-in2out-slowpath/TCP packets')
1478         self.assertEqual(err - tcpn, 2)
1479         err = self.statistics.get_err_counter(
1480             '/err/nat44-in2out-slowpath/UDP packets')
1481         self.assertEqual(err - udpn, 1)
1482         err = self.statistics.get_err_counter(
1483             '/err/nat44-in2out-slowpath/ICMP packets')
1484         self.assertEqual(err - icmpn, 1)
1485         err = self.statistics.get_err_counter(
1486             '/err/nat44-in2out-slowpath/good in2out packets processed')
1487         self.assertEqual(err - totaln, 4)
1488
1489         # out2in
1490         tcpn = self.statistics.get_err_counter('/err/nat44-out2in/TCP packets')
1491         udpn = self.statistics.get_err_counter('/err/nat44-out2in/UDP packets')
1492         icmpn = self.statistics.get_err_counter(
1493             '/err/nat44-out2in/ICMP packets')
1494         totaln = self.statistics.get_err_counter(
1495             '/err/nat44-out2in/good out2in packets processed')
1496
1497         pkts = self.create_stream_out(self.pg1)
1498         self.pg1.add_stream(pkts)
1499         self.pg_enable_capture(self.pg_interfaces)
1500         self.pg_start()
1501         capture = self.pg0.get_capture(len(pkts))
1502         self.verify_capture_in(capture, self.pg0)
1503
1504         err = self.statistics.get_err_counter('/err/nat44-out2in/TCP packets')
1505         self.assertEqual(err - tcpn, 2)
1506         err = self.statistics.get_err_counter('/err/nat44-out2in/UDP packets')
1507         self.assertEqual(err - udpn, 1)
1508         err = self.statistics.get_err_counter('/err/nat44-out2in/ICMP packets')
1509         self.assertEqual(err - icmpn, 1)
1510         err = self.statistics.get_err_counter(
1511             '/err/nat44-out2in/good out2in packets processed')
1512         self.assertEqual(err - totaln, 4)
1513
1514         users = self.statistics.get_counter('/nat44/total-users')
1515         self.assertEqual(users[0][0], 1)
1516         sessions = self.statistics.get_counter('/nat44/total-sessions')
1517         self.assertEqual(sessions[0][0], 3)
1518
1519     def test_dynamic_icmp_errors_in2out_ttl_1(self):
1520         """ NAT44 handling of client packets with TTL=1 """
1521
1522         self.nat44_add_address(self.nat_addr)
1523         flags = self.config_flags.NAT_IS_INSIDE
1524         self.vapi.nat44_interface_add_del_feature(
1525             sw_if_index=self.pg0.sw_if_index,
1526             flags=flags, is_add=1)
1527         self.vapi.nat44_interface_add_del_feature(
1528             sw_if_index=self.pg1.sw_if_index,
1529             is_add=1)
1530
1531         # Client side - generate traffic
1532         pkts = self.create_stream_in(self.pg0, self.pg1, ttl=1)
1533         self.pg0.add_stream(pkts)
1534         self.pg_enable_capture(self.pg_interfaces)
1535         self.pg_start()
1536
1537         # Client side - verify ICMP type 11 packets
1538         capture = self.pg0.get_capture(len(pkts))
1539         self.verify_capture_in_with_icmp_errors(capture, self.pg0)
1540
1541     def test_dynamic_icmp_errors_out2in_ttl_1(self):
1542         """ NAT44 handling of server packets with TTL=1 """
1543
1544         self.nat44_add_address(self.nat_addr)
1545         flags = self.config_flags.NAT_IS_INSIDE
1546         self.vapi.nat44_interface_add_del_feature(
1547             sw_if_index=self.pg0.sw_if_index,
1548             flags=flags, is_add=1)
1549         self.vapi.nat44_interface_add_del_feature(
1550             sw_if_index=self.pg1.sw_if_index,
1551             is_add=1)
1552
1553         # Client side - create sessions
1554         pkts = self.create_stream_in(self.pg0, self.pg1)
1555         self.pg0.add_stream(pkts)
1556         self.pg_enable_capture(self.pg_interfaces)
1557         self.pg_start()
1558
1559         # Server side - generate traffic
1560         capture = self.pg1.get_capture(len(pkts))
1561         self.verify_capture_out(capture)
1562         pkts = self.create_stream_out(self.pg1, ttl=1)
1563         self.pg1.add_stream(pkts)
1564         self.pg_enable_capture(self.pg_interfaces)
1565         self.pg_start()
1566
1567         # Server side - verify ICMP type 11 packets
1568         capture = self.pg1.get_capture(len(pkts))
1569         self.verify_capture_out_with_icmp_errors(capture,
1570                                                  src_ip=self.pg1.local_ip4)
1571
1572     def test_dynamic_icmp_errors_in2out_ttl_2(self):
1573         """ NAT44 handling of error responses to client packets with TTL=2 """
1574
1575         self.nat44_add_address(self.nat_addr)
1576         flags = self.config_flags.NAT_IS_INSIDE
1577         self.vapi.nat44_interface_add_del_feature(
1578             sw_if_index=self.pg0.sw_if_index,
1579             flags=flags, is_add=1)
1580         self.vapi.nat44_interface_add_del_feature(
1581             sw_if_index=self.pg1.sw_if_index,
1582             is_add=1)
1583
1584         # Client side - generate traffic
1585         pkts = self.create_stream_in(self.pg0, self.pg1, ttl=2)
1586         self.pg0.add_stream(pkts)
1587         self.pg_enable_capture(self.pg_interfaces)
1588         self.pg_start()
1589
1590         # Server side - simulate ICMP type 11 response
1591         capture = self.pg1.get_capture(len(pkts))
1592         pkts = [Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
1593                 IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
1594                 ICMP(type=11) / packet[IP] for packet in capture]
1595         self.pg1.add_stream(pkts)
1596         self.pg_enable_capture(self.pg_interfaces)
1597         self.pg_start()
1598
1599         # Client side - verify ICMP type 11 packets
1600         capture = self.pg0.get_capture(len(pkts))
1601         self.verify_capture_in_with_icmp_errors(capture, self.pg0)
1602
1603     def test_dynamic_icmp_errors_out2in_ttl_2(self):
1604         """ NAT44 handling of error responses to server packets with TTL=2 """
1605
1606         self.nat44_add_address(self.nat_addr)
1607         flags = self.config_flags.NAT_IS_INSIDE
1608         self.vapi.nat44_interface_add_del_feature(
1609             sw_if_index=self.pg0.sw_if_index,
1610             flags=flags, is_add=1)
1611         self.vapi.nat44_interface_add_del_feature(
1612             sw_if_index=self.pg1.sw_if_index,
1613             is_add=1)
1614
1615         # Client side - create sessions
1616         pkts = self.create_stream_in(self.pg0, self.pg1)
1617         self.pg0.add_stream(pkts)
1618         self.pg_enable_capture(self.pg_interfaces)
1619         self.pg_start()
1620
1621         # Server side - generate traffic
1622         capture = self.pg1.get_capture(len(pkts))
1623         self.verify_capture_out(capture)
1624         pkts = self.create_stream_out(self.pg1, ttl=2)
1625         self.pg1.add_stream(pkts)
1626         self.pg_enable_capture(self.pg_interfaces)
1627         self.pg_start()
1628
1629         # Client side - simulate ICMP type 11 response
1630         capture = self.pg0.get_capture(len(pkts))
1631         pkts = [Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
1632                 IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
1633                 ICMP(type=11) / packet[IP] for packet in capture]
1634         self.pg0.add_stream(pkts)
1635         self.pg_enable_capture(self.pg_interfaces)
1636         self.pg_start()
1637
1638         # Server side - verify ICMP type 11 packets
1639         capture = self.pg1.get_capture(len(pkts))
1640         self.verify_capture_out_with_icmp_errors(capture)
1641
1642     def test_ping_out_interface_from_outside(self):
1643         """ Ping NAT44 out interface from outside network """
1644
1645         self.nat44_add_address(self.nat_addr)
1646         flags = self.config_flags.NAT_IS_INSIDE
1647         self.vapi.nat44_interface_add_del_feature(
1648             sw_if_index=self.pg0.sw_if_index,
1649             flags=flags, is_add=1)
1650         self.vapi.nat44_interface_add_del_feature(
1651             sw_if_index=self.pg1.sw_if_index,
1652             is_add=1)
1653
1654         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
1655              IP(src=self.pg1.remote_ip4, dst=self.pg1.local_ip4) /
1656              ICMP(id=self.icmp_id_out, type='echo-request'))
1657         pkts = [p]
1658         self.pg1.add_stream(pkts)
1659         self.pg_enable_capture(self.pg_interfaces)
1660         self.pg_start()
1661         capture = self.pg1.get_capture(len(pkts))
1662         packet = capture[0]
1663         try:
1664             self.assertEqual(packet[IP].src, self.pg1.local_ip4)
1665             self.assertEqual(packet[IP].dst, self.pg1.remote_ip4)
1666             self.assertEqual(packet[ICMP].id, self.icmp_id_in)
1667             self.assertEqual(packet[ICMP].type, 0)  # echo reply
1668         except:
1669             self.logger.error(ppp("Unexpected or invalid packet "
1670                                   "(outside network):", packet))
1671             raise
1672
1673     def test_ping_internal_host_from_outside(self):
1674         """ Ping internal host from outside network """
1675
1676         self.nat44_add_static_mapping(self.pg0.remote_ip4, self.nat_addr)
1677         flags = self.config_flags.NAT_IS_INSIDE
1678         self.vapi.nat44_interface_add_del_feature(
1679             sw_if_index=self.pg0.sw_if_index,
1680             flags=flags, is_add=1)
1681         self.vapi.nat44_interface_add_del_feature(
1682             sw_if_index=self.pg1.sw_if_index,
1683             is_add=1)
1684
1685         # out2in
1686         pkt = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
1687                IP(src=self.pg1.remote_ip4, dst=self.nat_addr, ttl=64) /
1688                ICMP(id=self.icmp_id_out, type='echo-request'))
1689         self.pg1.add_stream(pkt)
1690         self.pg_enable_capture(self.pg_interfaces)
1691         self.pg_start()
1692         capture = self.pg0.get_capture(1)
1693         self.verify_capture_in(capture, self.pg0)
1694         self.assert_equal(capture[0][IP].proto, IP_PROTOS.icmp)
1695
1696         # in2out
1697         pkt = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
1698                IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4, ttl=64) /
1699                ICMP(id=self.icmp_id_in, type='echo-reply'))
1700         self.pg0.add_stream(pkt)
1701         self.pg_enable_capture(self.pg_interfaces)
1702         self.pg_start()
1703         capture = self.pg1.get_capture(1)
1704         self.verify_capture_out(capture, same_port=True)
1705         self.assert_equal(capture[0][IP].proto, IP_PROTOS.icmp)
1706
1707     def test_forwarding(self):
1708         """ NAT44 forwarding test """
1709
1710         flags = self.config_flags.NAT_IS_INSIDE
1711         self.vapi.nat44_interface_add_del_feature(
1712             sw_if_index=self.pg0.sw_if_index,
1713             flags=flags, is_add=1)
1714         self.vapi.nat44_interface_add_del_feature(
1715             sw_if_index=self.pg1.sw_if_index,
1716             is_add=1)
1717         self.vapi.nat44_forwarding_enable_disable(enable=1)
1718
1719         real_ip = self.pg0.remote_ip4
1720         alias_ip = self.nat_addr
1721         flags = self.config_flags.NAT_IS_ADDR_ONLY
1722         self.vapi.nat44_add_del_static_mapping(is_add=1,
1723                                                local_ip_address=real_ip,
1724                                                external_ip_address=alias_ip,
1725                                                external_sw_if_index=0xFFFFFFFF,
1726                                                flags=flags)
1727
1728         try:
1729             # static mapping match
1730
1731             pkts = self.create_stream_out(self.pg1)
1732             self.pg1.add_stream(pkts)
1733             self.pg_enable_capture(self.pg_interfaces)
1734             self.pg_start()
1735             capture = self.pg0.get_capture(len(pkts))
1736             self.verify_capture_in(capture, self.pg0)
1737
1738             pkts = self.create_stream_in(self.pg0, self.pg1)
1739             self.pg0.add_stream(pkts)
1740             self.pg_enable_capture(self.pg_interfaces)
1741             self.pg_start()
1742             capture = self.pg1.get_capture(len(pkts))
1743             self.verify_capture_out(capture, same_port=True)
1744
1745             # no static mapping match
1746
1747             host0 = self.pg0.remote_hosts[0]
1748             self.pg0.remote_hosts[0] = self.pg0.remote_hosts[1]
1749             try:
1750                 pkts = self.create_stream_out(self.pg1,
1751                                               dst_ip=self.pg0.remote_ip4,
1752                                               use_inside_ports=True)
1753                 self.pg1.add_stream(pkts)
1754                 self.pg_enable_capture(self.pg_interfaces)
1755                 self.pg_start()
1756                 capture = self.pg0.get_capture(len(pkts))
1757                 self.verify_capture_in(capture, self.pg0)
1758
1759                 pkts = self.create_stream_in(self.pg0, self.pg1)
1760                 self.pg0.add_stream(pkts)
1761                 self.pg_enable_capture(self.pg_interfaces)
1762                 self.pg_start()
1763                 capture = self.pg1.get_capture(len(pkts))
1764                 self.verify_capture_out(capture, nat_ip=self.pg0.remote_ip4,
1765                                         same_port=True)
1766             finally:
1767                 self.pg0.remote_hosts[0] = host0
1768
1769         finally:
1770             self.vapi.nat44_forwarding_enable_disable(enable=0)
1771             flags = self.config_flags.NAT_IS_ADDR_ONLY
1772             self.vapi.nat44_add_del_static_mapping(
1773                 is_add=0,
1774                 local_ip_address=real_ip,
1775                 external_ip_address=alias_ip,
1776                 external_sw_if_index=0xFFFFFFFF,
1777                 flags=flags)
1778
1779     def test_static_in(self):
1780         """ 1:1 NAT initialized from inside network """
1781
1782         nat_ip = "10.0.0.10"
1783         self.tcp_port_out = 6303
1784         self.udp_port_out = 6304
1785         self.icmp_id_out = 6305
1786
1787         self.nat44_add_static_mapping(self.pg0.remote_ip4, nat_ip)
1788         flags = self.config_flags.NAT_IS_INSIDE
1789         self.vapi.nat44_interface_add_del_feature(
1790             sw_if_index=self.pg0.sw_if_index,
1791             flags=flags, is_add=1)
1792         self.vapi.nat44_interface_add_del_feature(
1793             sw_if_index=self.pg1.sw_if_index,
1794             is_add=1)
1795         sm = self.vapi.nat44_static_mapping_dump()
1796         self.assertEqual(len(sm), 1)
1797         self.assertEqual(sm[0].tag, '')
1798         self.assertEqual(sm[0].protocol, 0)
1799         self.assertEqual(sm[0].local_port, 0)
1800         self.assertEqual(sm[0].external_port, 0)
1801
1802         # in2out
1803         pkts = self.create_stream_in(self.pg0, self.pg1)
1804         self.pg0.add_stream(pkts)
1805         self.pg_enable_capture(self.pg_interfaces)
1806         self.pg_start()
1807         capture = self.pg1.get_capture(len(pkts))
1808         self.verify_capture_out(capture, nat_ip, True)
1809
1810         # out2in
1811         pkts = self.create_stream_out(self.pg1, nat_ip)
1812         self.pg1.add_stream(pkts)
1813         self.pg_enable_capture(self.pg_interfaces)
1814         self.pg_start()
1815         capture = self.pg0.get_capture(len(pkts))
1816         self.verify_capture_in(capture, self.pg0)
1817
1818     def test_static_out(self):
1819         """ 1:1 NAT initialized from outside network """
1820
1821         nat_ip = "10.0.0.20"
1822         self.tcp_port_out = 6303
1823         self.udp_port_out = 6304
1824         self.icmp_id_out = 6305
1825         tag = "testTAG"
1826
1827         self.nat44_add_static_mapping(self.pg0.remote_ip4, nat_ip, tag=tag)
1828         flags = self.config_flags.NAT_IS_INSIDE
1829         self.vapi.nat44_interface_add_del_feature(
1830             sw_if_index=self.pg0.sw_if_index,
1831             flags=flags, is_add=1)
1832         self.vapi.nat44_interface_add_del_feature(
1833             sw_if_index=self.pg1.sw_if_index,
1834             is_add=1)
1835         sm = self.vapi.nat44_static_mapping_dump()
1836         self.assertEqual(len(sm), 1)
1837         self.assertEqual(sm[0].tag, tag)
1838
1839         # out2in
1840         pkts = self.create_stream_out(self.pg1, nat_ip)
1841         self.pg1.add_stream(pkts)
1842         self.pg_enable_capture(self.pg_interfaces)
1843         self.pg_start()
1844         capture = self.pg0.get_capture(len(pkts))
1845         self.verify_capture_in(capture, self.pg0)
1846
1847         # in2out
1848         pkts = self.create_stream_in(self.pg0, self.pg1)
1849         self.pg0.add_stream(pkts)
1850         self.pg_enable_capture(self.pg_interfaces)
1851         self.pg_start()
1852         capture = self.pg1.get_capture(len(pkts))
1853         self.verify_capture_out(capture, nat_ip, True)
1854
1855     def test_static_with_port_in(self):
1856         """ 1:1 NAPT initialized from inside network """
1857
1858         self.tcp_port_out = 3606
1859         self.udp_port_out = 3607
1860         self.icmp_id_out = 3608
1861
1862         self.nat44_add_address(self.nat_addr)
1863         self.nat44_add_static_mapping(self.pg0.remote_ip4, self.nat_addr,
1864                                       self.tcp_port_in, self.tcp_port_out,
1865                                       proto=IP_PROTOS.tcp)
1866         self.nat44_add_static_mapping(self.pg0.remote_ip4, self.nat_addr,
1867                                       self.udp_port_in, self.udp_port_out,
1868                                       proto=IP_PROTOS.udp)
1869         self.nat44_add_static_mapping(self.pg0.remote_ip4, self.nat_addr,
1870                                       self.icmp_id_in, self.icmp_id_out,
1871                                       proto=IP_PROTOS.icmp)
1872         flags = self.config_flags.NAT_IS_INSIDE
1873         self.vapi.nat44_interface_add_del_feature(
1874             sw_if_index=self.pg0.sw_if_index,
1875             flags=flags, is_add=1)
1876         self.vapi.nat44_interface_add_del_feature(
1877             sw_if_index=self.pg1.sw_if_index,
1878             is_add=1)
1879
1880         # in2out
1881         pkts = self.create_stream_in(self.pg0, self.pg1)
1882         self.pg0.add_stream(pkts)
1883         self.pg_enable_capture(self.pg_interfaces)
1884         self.pg_start()
1885         capture = self.pg1.get_capture(len(pkts))
1886         self.verify_capture_out(capture)
1887
1888         # out2in
1889         pkts = self.create_stream_out(self.pg1)
1890         self.pg1.add_stream(pkts)
1891         self.pg_enable_capture(self.pg_interfaces)
1892         self.pg_start()
1893         capture = self.pg0.get_capture(len(pkts))
1894         self.verify_capture_in(capture, self.pg0)
1895
1896     def test_static_with_port_out(self):
1897         """ 1:1 NAPT initialized from outside network """
1898
1899         self.tcp_port_out = 30606
1900         self.udp_port_out = 30607
1901         self.icmp_id_out = 30608
1902
1903         self.nat44_add_address(self.nat_addr)
1904         self.nat44_add_static_mapping(self.pg0.remote_ip4, self.nat_addr,
1905                                       self.tcp_port_in, self.tcp_port_out,
1906                                       proto=IP_PROTOS.tcp)
1907         self.nat44_add_static_mapping(self.pg0.remote_ip4, self.nat_addr,
1908                                       self.udp_port_in, self.udp_port_out,
1909                                       proto=IP_PROTOS.udp)
1910         self.nat44_add_static_mapping(self.pg0.remote_ip4, self.nat_addr,
1911                                       self.icmp_id_in, self.icmp_id_out,
1912                                       proto=IP_PROTOS.icmp)
1913         flags = self.config_flags.NAT_IS_INSIDE
1914         self.vapi.nat44_interface_add_del_feature(
1915             sw_if_index=self.pg0.sw_if_index,
1916             flags=flags, is_add=1)
1917         self.vapi.nat44_interface_add_del_feature(
1918             sw_if_index=self.pg1.sw_if_index,
1919             is_add=1)
1920
1921         # out2in
1922         pkts = self.create_stream_out(self.pg1)
1923         self.pg1.add_stream(pkts)
1924         self.pg_enable_capture(self.pg_interfaces)
1925         self.pg_start()
1926         capture = self.pg0.get_capture(len(pkts))
1927         self.verify_capture_in(capture, self.pg0)
1928
1929         # in2out
1930         pkts = self.create_stream_in(self.pg0, self.pg1)
1931         self.pg0.add_stream(pkts)
1932         self.pg_enable_capture(self.pg_interfaces)
1933         self.pg_start()
1934         capture = self.pg1.get_capture(len(pkts))
1935         self.verify_capture_out(capture)
1936
1937     def test_static_vrf_aware(self):
1938         """ 1:1 NAT VRF awareness """
1939
1940         nat_ip1 = "10.0.0.30"
1941         nat_ip2 = "10.0.0.40"
1942         self.tcp_port_out = 6303
1943         self.udp_port_out = 6304
1944         self.icmp_id_out = 6305
1945
1946         self.nat44_add_static_mapping(self.pg4.remote_ip4, nat_ip1,
1947                                       vrf_id=10)
1948         self.nat44_add_static_mapping(self.pg0.remote_ip4, nat_ip2,
1949                                       vrf_id=10)
1950         flags = self.config_flags.NAT_IS_INSIDE
1951         self.vapi.nat44_interface_add_del_feature(
1952             sw_if_index=self.pg3.sw_if_index,
1953             is_add=1)
1954         self.vapi.nat44_interface_add_del_feature(
1955             sw_if_index=self.pg0.sw_if_index,
1956             flags=flags, is_add=1)
1957         self.vapi.nat44_interface_add_del_feature(
1958             sw_if_index=self.pg4.sw_if_index,
1959             flags=flags, is_add=1)
1960
1961         # inside interface VRF match NAT44 static mapping VRF
1962         pkts = self.create_stream_in(self.pg4, self.pg3)
1963         self.pg4.add_stream(pkts)
1964         self.pg_enable_capture(self.pg_interfaces)
1965         self.pg_start()
1966         capture = self.pg3.get_capture(len(pkts))
1967         self.verify_capture_out(capture, nat_ip1, True)
1968
1969         # inside interface VRF don't match NAT44 static mapping VRF (packets
1970         # are dropped)
1971         pkts = self.create_stream_in(self.pg0, self.pg3)
1972         self.pg0.add_stream(pkts)
1973         self.pg_enable_capture(self.pg_interfaces)
1974         self.pg_start()
1975         self.pg3.assert_nothing_captured()
1976
1977     def test_dynamic_to_static(self):
1978         """ Switch from dynamic translation to 1:1NAT """
1979         nat_ip = "10.0.0.10"
1980         self.tcp_port_out = 6303
1981         self.udp_port_out = 6304
1982         self.icmp_id_out = 6305
1983
1984         self.nat44_add_address(self.nat_addr)
1985         flags = self.config_flags.NAT_IS_INSIDE
1986         self.vapi.nat44_interface_add_del_feature(
1987             sw_if_index=self.pg0.sw_if_index,
1988             flags=flags, is_add=1)
1989         self.vapi.nat44_interface_add_del_feature(
1990             sw_if_index=self.pg1.sw_if_index,
1991             is_add=1)
1992
1993         # dynamic
1994         pkts = self.create_stream_in(self.pg0, self.pg1)
1995         self.pg0.add_stream(pkts)
1996         self.pg_enable_capture(self.pg_interfaces)
1997         self.pg_start()
1998         capture = self.pg1.get_capture(len(pkts))
1999         self.verify_capture_out(capture)
2000
2001         # 1:1NAT
2002         self.nat44_add_static_mapping(self.pg0.remote_ip4, nat_ip)
2003         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
2004         self.assertEqual(len(sessions), 0)
2005         pkts = self.create_stream_in(self.pg0, self.pg1)
2006         self.pg0.add_stream(pkts)
2007         self.pg_enable_capture(self.pg_interfaces)
2008         self.pg_start()
2009         capture = self.pg1.get_capture(len(pkts))
2010         self.verify_capture_out(capture, nat_ip, True)
2011
2012     def test_identity_nat(self):
2013         """ Identity NAT """
2014         flags = self.config_flags.NAT_IS_ADDR_ONLY
2015         self.vapi.nat44_add_del_identity_mapping(
2016             ip_address=self.pg0.remote_ip4, sw_if_index=0xFFFFFFFF,
2017             flags=flags, is_add=1)
2018         flags = self.config_flags.NAT_IS_INSIDE
2019         self.vapi.nat44_interface_add_del_feature(
2020             sw_if_index=self.pg0.sw_if_index,
2021             flags=flags, is_add=1)
2022         self.vapi.nat44_interface_add_del_feature(
2023             sw_if_index=self.pg1.sw_if_index,
2024             is_add=1)
2025
2026         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
2027              IP(src=self.pg1.remote_ip4, dst=self.pg0.remote_ip4) /
2028              TCP(sport=12345, dport=56789))
2029         self.pg1.add_stream(p)
2030         self.pg_enable_capture(self.pg_interfaces)
2031         self.pg_start()
2032         capture = self.pg0.get_capture(1)
2033         p = capture[0]
2034         try:
2035             ip = p[IP]
2036             tcp = p[TCP]
2037             self.assertEqual(ip.dst, self.pg0.remote_ip4)
2038             self.assertEqual(ip.src, self.pg1.remote_ip4)
2039             self.assertEqual(tcp.dport, 56789)
2040             self.assertEqual(tcp.sport, 12345)
2041             self.assert_packet_checksums_valid(p)
2042         except:
2043             self.logger.error(ppp("Unexpected or invalid packet:", p))
2044             raise
2045
2046         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
2047         self.assertEqual(len(sessions), 0)
2048         flags = self.config_flags.NAT_IS_ADDR_ONLY
2049         self.vapi.nat44_add_del_identity_mapping(
2050             ip_address=self.pg0.remote_ip4, sw_if_index=0xFFFFFFFF,
2051             flags=flags, vrf_id=1, is_add=1)
2052         identity_mappings = self.vapi.nat44_identity_mapping_dump()
2053         self.assertEqual(len(identity_mappings), 2)
2054
2055     def test_multiple_inside_interfaces(self):
2056         """ NAT44 multiple non-overlapping address space inside interfaces """
2057
2058         self.nat44_add_address(self.nat_addr)
2059         flags = self.config_flags.NAT_IS_INSIDE
2060         self.vapi.nat44_interface_add_del_feature(
2061             sw_if_index=self.pg0.sw_if_index,
2062             flags=flags, is_add=1)
2063         self.vapi.nat44_interface_add_del_feature(
2064             sw_if_index=self.pg1.sw_if_index,
2065             flags=flags, is_add=1)
2066         self.vapi.nat44_interface_add_del_feature(
2067             sw_if_index=self.pg3.sw_if_index,
2068             is_add=1)
2069
2070         # between two NAT44 inside interfaces (no translation)
2071         pkts = self.create_stream_in(self.pg0, self.pg1)
2072         self.pg0.add_stream(pkts)
2073         self.pg_enable_capture(self.pg_interfaces)
2074         self.pg_start()
2075         capture = self.pg1.get_capture(len(pkts))
2076         self.verify_capture_no_translation(capture, self.pg0, self.pg1)
2077
2078         # from NAT44 inside to interface without NAT44 feature (no translation)
2079         pkts = self.create_stream_in(self.pg0, self.pg2)
2080         self.pg0.add_stream(pkts)
2081         self.pg_enable_capture(self.pg_interfaces)
2082         self.pg_start()
2083         capture = self.pg2.get_capture(len(pkts))
2084         self.verify_capture_no_translation(capture, self.pg0, self.pg2)
2085
2086         # in2out 1st interface
2087         pkts = self.create_stream_in(self.pg0, self.pg3)
2088         self.pg0.add_stream(pkts)
2089         self.pg_enable_capture(self.pg_interfaces)
2090         self.pg_start()
2091         capture = self.pg3.get_capture(len(pkts))
2092         self.verify_capture_out(capture)
2093
2094         # out2in 1st interface
2095         pkts = self.create_stream_out(self.pg3)
2096         self.pg3.add_stream(pkts)
2097         self.pg_enable_capture(self.pg_interfaces)
2098         self.pg_start()
2099         capture = self.pg0.get_capture(len(pkts))
2100         self.verify_capture_in(capture, self.pg0)
2101
2102         # in2out 2nd interface
2103         pkts = self.create_stream_in(self.pg1, self.pg3)
2104         self.pg1.add_stream(pkts)
2105         self.pg_enable_capture(self.pg_interfaces)
2106         self.pg_start()
2107         capture = self.pg3.get_capture(len(pkts))
2108         self.verify_capture_out(capture)
2109
2110         # out2in 2nd interface
2111         pkts = self.create_stream_out(self.pg3)
2112         self.pg3.add_stream(pkts)
2113         self.pg_enable_capture(self.pg_interfaces)
2114         self.pg_start()
2115         capture = self.pg1.get_capture(len(pkts))
2116         self.verify_capture_in(capture, self.pg1)
2117
2118     def test_inside_overlapping_interfaces(self):
2119         """ NAT44 multiple inside interfaces with overlapping address space """
2120
2121         static_nat_ip = "10.0.0.10"
2122         self.nat44_add_address(self.nat_addr)
2123         flags = self.config_flags.NAT_IS_INSIDE
2124         self.vapi.nat44_interface_add_del_feature(
2125             sw_if_index=self.pg3.sw_if_index,
2126             is_add=1)
2127         self.vapi.nat44_interface_add_del_feature(
2128             sw_if_index=self.pg4.sw_if_index,
2129             flags=flags, is_add=1)
2130         self.vapi.nat44_interface_add_del_feature(
2131             sw_if_index=self.pg5.sw_if_index,
2132             flags=flags, is_add=1)
2133         self.vapi.nat44_interface_add_del_feature(
2134             sw_if_index=self.pg6.sw_if_index,
2135             flags=flags, is_add=1)
2136         self.nat44_add_static_mapping(self.pg6.remote_ip4, static_nat_ip,
2137                                       vrf_id=20)
2138
2139         # between NAT44 inside interfaces with same VRF (no translation)
2140         pkts = self.create_stream_in(self.pg4, self.pg5)
2141         self.pg4.add_stream(pkts)
2142         self.pg_enable_capture(self.pg_interfaces)
2143         self.pg_start()
2144         capture = self.pg5.get_capture(len(pkts))
2145         self.verify_capture_no_translation(capture, self.pg4, self.pg5)
2146
2147         # between NAT44 inside interfaces with different VRF (hairpinning)
2148         p = (Ether(src=self.pg4.remote_mac, dst=self.pg4.local_mac) /
2149              IP(src=self.pg4.remote_ip4, dst=static_nat_ip) /
2150              TCP(sport=1234, dport=5678))
2151         self.pg4.add_stream(p)
2152         self.pg_enable_capture(self.pg_interfaces)
2153         self.pg_start()
2154         capture = self.pg6.get_capture(1)
2155         p = capture[0]
2156         try:
2157             ip = p[IP]
2158             tcp = p[TCP]
2159             self.assertEqual(ip.src, self.nat_addr)
2160             self.assertEqual(ip.dst, self.pg6.remote_ip4)
2161             self.assertNotEqual(tcp.sport, 1234)
2162             self.assertEqual(tcp.dport, 5678)
2163         except:
2164             self.logger.error(ppp("Unexpected or invalid packet:", p))
2165             raise
2166
2167         # in2out 1st interface
2168         pkts = self.create_stream_in(self.pg4, self.pg3)
2169         self.pg4.add_stream(pkts)
2170         self.pg_enable_capture(self.pg_interfaces)
2171         self.pg_start()
2172         capture = self.pg3.get_capture(len(pkts))
2173         self.verify_capture_out(capture)
2174
2175         # out2in 1st interface
2176         pkts = self.create_stream_out(self.pg3)
2177         self.pg3.add_stream(pkts)
2178         self.pg_enable_capture(self.pg_interfaces)
2179         self.pg_start()
2180         capture = self.pg4.get_capture(len(pkts))
2181         self.verify_capture_in(capture, self.pg4)
2182
2183         # in2out 2nd interface
2184         pkts = self.create_stream_in(self.pg5, self.pg3)
2185         self.pg5.add_stream(pkts)
2186         self.pg_enable_capture(self.pg_interfaces)
2187         self.pg_start()
2188         capture = self.pg3.get_capture(len(pkts))
2189         self.verify_capture_out(capture)
2190
2191         # out2in 2nd interface
2192         pkts = self.create_stream_out(self.pg3)
2193         self.pg3.add_stream(pkts)
2194         self.pg_enable_capture(self.pg_interfaces)
2195         self.pg_start()
2196         capture = self.pg5.get_capture(len(pkts))
2197         self.verify_capture_in(capture, self.pg5)
2198
2199         # pg5 session dump
2200         addresses = self.vapi.nat44_address_dump()
2201         self.assertEqual(len(addresses), 1)
2202         sessions = self.vapi.nat44_user_session_dump(self.pg5.remote_ip4, 10)
2203         self.assertEqual(len(sessions), 3)
2204         for session in sessions:
2205             self.assertFalse(session.flags & self.config_flags.NAT_IS_STATIC)
2206             self.assertEqual(str(session.inside_ip_address),
2207                              self.pg5.remote_ip4)
2208             self.assertEqual(session.outside_ip_address,
2209                              addresses[0].ip_address)
2210         self.assertEqual(sessions[0].protocol, IP_PROTOS.tcp)
2211         self.assertEqual(sessions[1].protocol, IP_PROTOS.udp)
2212         self.assertEqual(sessions[2].protocol, IP_PROTOS.icmp)
2213         self.assertEqual(sessions[0].inside_port, self.tcp_port_in)
2214         self.assertEqual(sessions[1].inside_port, self.udp_port_in)
2215         self.assertEqual(sessions[2].inside_port, self.icmp_id_in)
2216         self.assertEqual(sessions[0].outside_port, self.tcp_port_out)
2217         self.assertEqual(sessions[1].outside_port, self.udp_port_out)
2218         self.assertEqual(sessions[2].outside_port, self.icmp_id_out)
2219
2220         # in2out 3rd interface
2221         pkts = self.create_stream_in(self.pg6, self.pg3)
2222         self.pg6.add_stream(pkts)
2223         self.pg_enable_capture(self.pg_interfaces)
2224         self.pg_start()
2225         capture = self.pg3.get_capture(len(pkts))
2226         self.verify_capture_out(capture, static_nat_ip, True)
2227
2228         # out2in 3rd interface
2229         pkts = self.create_stream_out(self.pg3, static_nat_ip)
2230         self.pg3.add_stream(pkts)
2231         self.pg_enable_capture(self.pg_interfaces)
2232         self.pg_start()
2233         capture = self.pg6.get_capture(len(pkts))
2234         self.verify_capture_in(capture, self.pg6)
2235
2236         # general user and session dump verifications
2237         users = self.vapi.nat44_user_dump()
2238         self.assertGreaterEqual(len(users), 3)
2239         addresses = self.vapi.nat44_address_dump()
2240         self.assertEqual(len(addresses), 1)
2241         for user in users:
2242             sessions = self.vapi.nat44_user_session_dump(user.ip_address,
2243                                                          user.vrf_id)
2244             for session in sessions:
2245                 self.assertEqual(user.ip_address, session.inside_ip_address)
2246                 self.assertTrue(session.total_bytes > session.total_pkts > 0)
2247                 self.assertTrue(session.protocol in
2248                                 [IP_PROTOS.tcp, IP_PROTOS.udp,
2249                                  IP_PROTOS.icmp])
2250                 self.assertFalse(session.flags &
2251                                  self.config_flags.NAT_IS_EXT_HOST_VALID)
2252
2253         # pg4 session dump
2254         sessions = self.vapi.nat44_user_session_dump(self.pg4.remote_ip4, 10)
2255         self.assertGreaterEqual(len(sessions), 4)
2256         for session in sessions:
2257             self.assertFalse(session.flags & self.config_flags.NAT_IS_STATIC)
2258             self.assertEqual(str(session.inside_ip_address),
2259                              self.pg4.remote_ip4)
2260             self.assertEqual(session.outside_ip_address,
2261                              addresses[0].ip_address)
2262
2263         # pg6 session dump
2264         sessions = self.vapi.nat44_user_session_dump(self.pg6.remote_ip4, 20)
2265         self.assertGreaterEqual(len(sessions), 3)
2266         for session in sessions:
2267             self.assertTrue(session.flags & self.config_flags.NAT_IS_STATIC)
2268             self.assertEqual(str(session.inside_ip_address),
2269                              self.pg6.remote_ip4)
2270             self.assertEqual(str(session.outside_ip_address),
2271                              static_nat_ip)
2272             self.assertTrue(session.inside_port in
2273                             [self.tcp_port_in, self.udp_port_in,
2274                              self.icmp_id_in])
2275
2276     def test_hairpinning(self):
2277         """ NAT44 hairpinning - 1:1 NAPT """
2278
2279         host = self.pg0.remote_hosts[0]
2280         server = self.pg0.remote_hosts[1]
2281         host_in_port = 1234
2282         host_out_port = 0
2283         server_in_port = 5678
2284         server_out_port = 8765
2285
2286         self.nat44_add_address(self.nat_addr)
2287         flags = self.config_flags.NAT_IS_INSIDE
2288         self.vapi.nat44_interface_add_del_feature(
2289             sw_if_index=self.pg0.sw_if_index,
2290             flags=flags, is_add=1)
2291         self.vapi.nat44_interface_add_del_feature(
2292             sw_if_index=self.pg1.sw_if_index,
2293             is_add=1)
2294
2295         # add static mapping for server
2296         self.nat44_add_static_mapping(server.ip4, self.nat_addr,
2297                                       server_in_port, server_out_port,
2298                                       proto=IP_PROTOS.tcp)
2299
2300         # send packet from host to server
2301         p = (Ether(src=host.mac, dst=self.pg0.local_mac) /
2302              IP(src=host.ip4, dst=self.nat_addr) /
2303              TCP(sport=host_in_port, dport=server_out_port))
2304         self.pg0.add_stream(p)
2305         self.pg_enable_capture(self.pg_interfaces)
2306         self.pg_start()
2307         capture = self.pg0.get_capture(1)
2308         p = capture[0]
2309         try:
2310             ip = p[IP]
2311             tcp = p[TCP]
2312             self.assertEqual(ip.src, self.nat_addr)
2313             self.assertEqual(ip.dst, server.ip4)
2314             self.assertNotEqual(tcp.sport, host_in_port)
2315             self.assertEqual(tcp.dport, server_in_port)
2316             self.assert_packet_checksums_valid(p)
2317             host_out_port = tcp.sport
2318         except:
2319             self.logger.error(ppp("Unexpected or invalid packet:", p))
2320             raise
2321
2322         # send reply from server to host
2323         p = (Ether(src=server.mac, dst=self.pg0.local_mac) /
2324              IP(src=server.ip4, dst=self.nat_addr) /
2325              TCP(sport=server_in_port, dport=host_out_port))
2326         self.pg0.add_stream(p)
2327         self.pg_enable_capture(self.pg_interfaces)
2328         self.pg_start()
2329         capture = self.pg0.get_capture(1)
2330         p = capture[0]
2331         try:
2332             ip = p[IP]
2333             tcp = p[TCP]
2334             self.assertEqual(ip.src, self.nat_addr)
2335             self.assertEqual(ip.dst, host.ip4)
2336             self.assertEqual(tcp.sport, server_out_port)
2337             self.assertEqual(tcp.dport, host_in_port)
2338             self.assert_packet_checksums_valid(p)
2339         except:
2340             self.logger.error(ppp("Unexpected or invalid packet:", p))
2341             raise
2342
2343     def test_hairpinning2(self):
2344         """ NAT44 hairpinning - 1:1 NAT"""
2345
2346         server1_nat_ip = "10.0.0.10"
2347         server2_nat_ip = "10.0.0.11"
2348         host = self.pg0.remote_hosts[0]
2349         server1 = self.pg0.remote_hosts[1]
2350         server2 = self.pg0.remote_hosts[2]
2351         server_tcp_port = 22
2352         server_udp_port = 20
2353
2354         self.nat44_add_address(self.nat_addr)
2355         flags = self.config_flags.NAT_IS_INSIDE
2356         self.vapi.nat44_interface_add_del_feature(
2357             sw_if_index=self.pg0.sw_if_index,
2358             flags=flags, is_add=1)
2359         self.vapi.nat44_interface_add_del_feature(
2360             sw_if_index=self.pg1.sw_if_index,
2361             is_add=1)
2362
2363         # add static mapping for servers
2364         self.nat44_add_static_mapping(server1.ip4, server1_nat_ip)
2365         self.nat44_add_static_mapping(server2.ip4, server2_nat_ip)
2366
2367         # host to server1
2368         pkts = []
2369         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2370              IP(src=host.ip4, dst=server1_nat_ip) /
2371              TCP(sport=self.tcp_port_in, dport=server_tcp_port))
2372         pkts.append(p)
2373         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2374              IP(src=host.ip4, dst=server1_nat_ip) /
2375              UDP(sport=self.udp_port_in, dport=server_udp_port))
2376         pkts.append(p)
2377         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2378              IP(src=host.ip4, dst=server1_nat_ip) /
2379              ICMP(id=self.icmp_id_in, type='echo-request'))
2380         pkts.append(p)
2381         self.pg0.add_stream(pkts)
2382         self.pg_enable_capture(self.pg_interfaces)
2383         self.pg_start()
2384         capture = self.pg0.get_capture(len(pkts))
2385         for packet in capture:
2386             try:
2387                 self.assertEqual(packet[IP].src, self.nat_addr)
2388                 self.assertEqual(packet[IP].dst, server1.ip4)
2389                 if packet.haslayer(TCP):
2390                     self.assertNotEqual(packet[TCP].sport, self.tcp_port_in)
2391                     self.assertEqual(packet[TCP].dport, server_tcp_port)
2392                     self.tcp_port_out = packet[TCP].sport
2393                     self.assert_packet_checksums_valid(packet)
2394                 elif packet.haslayer(UDP):
2395                     self.assertNotEqual(packet[UDP].sport, self.udp_port_in)
2396                     self.assertEqual(packet[UDP].dport, server_udp_port)
2397                     self.udp_port_out = packet[UDP].sport
2398                 else:
2399                     self.assertNotEqual(packet[ICMP].id, self.icmp_id_in)
2400                     self.icmp_id_out = packet[ICMP].id
2401             except:
2402                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
2403                 raise
2404
2405         # server1 to host
2406         pkts = []
2407         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2408              IP(src=server1.ip4, dst=self.nat_addr) /
2409              TCP(sport=server_tcp_port, dport=self.tcp_port_out))
2410         pkts.append(p)
2411         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2412              IP(src=server1.ip4, dst=self.nat_addr) /
2413              UDP(sport=server_udp_port, dport=self.udp_port_out))
2414         pkts.append(p)
2415         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2416              IP(src=server1.ip4, dst=self.nat_addr) /
2417              ICMP(id=self.icmp_id_out, type='echo-reply'))
2418         pkts.append(p)
2419         self.pg0.add_stream(pkts)
2420         self.pg_enable_capture(self.pg_interfaces)
2421         self.pg_start()
2422         capture = self.pg0.get_capture(len(pkts))
2423         for packet in capture:
2424             try:
2425                 self.assertEqual(packet[IP].src, server1_nat_ip)
2426                 self.assertEqual(packet[IP].dst, host.ip4)
2427                 if packet.haslayer(TCP):
2428                     self.assertEqual(packet[TCP].dport, self.tcp_port_in)
2429                     self.assertEqual(packet[TCP].sport, server_tcp_port)
2430                     self.assert_packet_checksums_valid(packet)
2431                 elif packet.haslayer(UDP):
2432                     self.assertEqual(packet[UDP].dport, self.udp_port_in)
2433                     self.assertEqual(packet[UDP].sport, server_udp_port)
2434                 else:
2435                     self.assertEqual(packet[ICMP].id, self.icmp_id_in)
2436             except:
2437                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
2438                 raise
2439
2440         # server2 to server1
2441         pkts = []
2442         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2443              IP(src=server2.ip4, dst=server1_nat_ip) /
2444              TCP(sport=self.tcp_port_in, dport=server_tcp_port))
2445         pkts.append(p)
2446         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2447              IP(src=server2.ip4, dst=server1_nat_ip) /
2448              UDP(sport=self.udp_port_in, dport=server_udp_port))
2449         pkts.append(p)
2450         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2451              IP(src=server2.ip4, dst=server1_nat_ip) /
2452              ICMP(id=self.icmp_id_in, type='echo-request'))
2453         pkts.append(p)
2454         self.pg0.add_stream(pkts)
2455         self.pg_enable_capture(self.pg_interfaces)
2456         self.pg_start()
2457         capture = self.pg0.get_capture(len(pkts))
2458         for packet in capture:
2459             try:
2460                 self.assertEqual(packet[IP].src, server2_nat_ip)
2461                 self.assertEqual(packet[IP].dst, server1.ip4)
2462                 if packet.haslayer(TCP):
2463                     self.assertEqual(packet[TCP].sport, self.tcp_port_in)
2464                     self.assertEqual(packet[TCP].dport, server_tcp_port)
2465                     self.tcp_port_out = packet[TCP].sport
2466                     self.assert_packet_checksums_valid(packet)
2467                 elif packet.haslayer(UDP):
2468                     self.assertEqual(packet[UDP].sport, self.udp_port_in)
2469                     self.assertEqual(packet[UDP].dport, server_udp_port)
2470                     self.udp_port_out = packet[UDP].sport
2471                 else:
2472                     self.assertEqual(packet[ICMP].id, self.icmp_id_in)
2473                     self.icmp_id_out = packet[ICMP].id
2474             except:
2475                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
2476                 raise
2477
2478         # server1 to server2
2479         pkts = []
2480         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2481              IP(src=server1.ip4, dst=server2_nat_ip) /
2482              TCP(sport=server_tcp_port, dport=self.tcp_port_out))
2483         pkts.append(p)
2484         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2485              IP(src=server1.ip4, dst=server2_nat_ip) /
2486              UDP(sport=server_udp_port, dport=self.udp_port_out))
2487         pkts.append(p)
2488         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2489              IP(src=server1.ip4, dst=server2_nat_ip) /
2490              ICMP(id=self.icmp_id_out, type='echo-reply'))
2491         pkts.append(p)
2492         self.pg0.add_stream(pkts)
2493         self.pg_enable_capture(self.pg_interfaces)
2494         self.pg_start()
2495         capture = self.pg0.get_capture(len(pkts))
2496         for packet in capture:
2497             try:
2498                 self.assertEqual(packet[IP].src, server1_nat_ip)
2499                 self.assertEqual(packet[IP].dst, server2.ip4)
2500                 if packet.haslayer(TCP):
2501                     self.assertEqual(packet[TCP].dport, self.tcp_port_in)
2502                     self.assertEqual(packet[TCP].sport, server_tcp_port)
2503                     self.assert_packet_checksums_valid(packet)
2504                 elif packet.haslayer(UDP):
2505                     self.assertEqual(packet[UDP].dport, self.udp_port_in)
2506                     self.assertEqual(packet[UDP].sport, server_udp_port)
2507                 else:
2508                     self.assertEqual(packet[ICMP].id, self.icmp_id_in)
2509             except:
2510                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
2511                 raise
2512
2513     def test_interface_addr(self):
2514         """ Acquire NAT44 addresses from interface """
2515         self.vapi.nat44_add_del_interface_addr(
2516             is_add=1,
2517             sw_if_index=self.pg7.sw_if_index)
2518
2519         # no address in NAT pool
2520         addresses = self.vapi.nat44_address_dump()
2521         self.assertEqual(0, len(addresses))
2522
2523         # configure interface address and check NAT address pool
2524         self.pg7.config_ip4()
2525         addresses = self.vapi.nat44_address_dump()
2526         self.assertEqual(1, len(addresses))
2527         self.assertEqual(str(addresses[0].ip_address), self.pg7.local_ip4)
2528
2529         # remove interface address and check NAT address pool
2530         self.pg7.unconfig_ip4()
2531         addresses = self.vapi.nat44_address_dump()
2532         self.assertEqual(0, len(addresses))
2533
2534     def test_interface_addr_static_mapping(self):
2535         """ Static mapping with addresses from interface """
2536         tag = "testTAG"
2537
2538         self.vapi.nat44_add_del_interface_addr(
2539             is_add=1,
2540             sw_if_index=self.pg7.sw_if_index)
2541         self.nat44_add_static_mapping(
2542             '1.2.3.4',
2543             external_sw_if_index=self.pg7.sw_if_index,
2544             tag=tag)
2545
2546         # static mappings with external interface
2547         static_mappings = self.vapi.nat44_static_mapping_dump()
2548         self.assertEqual(1, len(static_mappings))
2549         self.assertEqual(self.pg7.sw_if_index,
2550                          static_mappings[0].external_sw_if_index)
2551         self.assertEqual(static_mappings[0].tag, tag)
2552
2553         # configure interface address and check static mappings
2554         self.pg7.config_ip4()
2555         static_mappings = self.vapi.nat44_static_mapping_dump()
2556         self.assertEqual(2, len(static_mappings))
2557         resolved = False
2558         for sm in static_mappings:
2559             if sm.external_sw_if_index == 0xFFFFFFFF:
2560                 self.assertEqual(str(sm.external_ip_address),
2561                                  self.pg7.local_ip4)
2562                 self.assertEqual(sm.tag, tag)
2563                 resolved = True
2564         self.assertTrue(resolved)
2565
2566         # remove interface address and check static mappings
2567         self.pg7.unconfig_ip4()
2568         static_mappings = self.vapi.nat44_static_mapping_dump()
2569         self.assertEqual(1, len(static_mappings))
2570         self.assertEqual(self.pg7.sw_if_index,
2571                          static_mappings[0].external_sw_if_index)
2572         self.assertEqual(static_mappings[0].tag, tag)
2573
2574         # configure interface address again and check static mappings
2575         self.pg7.config_ip4()
2576         static_mappings = self.vapi.nat44_static_mapping_dump()
2577         self.assertEqual(2, len(static_mappings))
2578         resolved = False
2579         for sm in static_mappings:
2580             if sm.external_sw_if_index == 0xFFFFFFFF:
2581                 self.assertEqual(str(sm.external_ip_address),
2582                                  self.pg7.local_ip4)
2583                 self.assertEqual(sm.tag, tag)
2584                 resolved = True
2585         self.assertTrue(resolved)
2586
2587         # remove static mapping
2588         self.nat44_add_static_mapping(
2589             '1.2.3.4',
2590             external_sw_if_index=self.pg7.sw_if_index,
2591             tag=tag,
2592             is_add=0)
2593         static_mappings = self.vapi.nat44_static_mapping_dump()
2594         self.assertEqual(0, len(static_mappings))
2595
2596     def test_interface_addr_identity_nat(self):
2597         """ Identity NAT with addresses from interface """
2598
2599         port = 53053
2600         self.vapi.nat44_add_del_interface_addr(
2601             is_add=1,
2602             sw_if_index=self.pg7.sw_if_index)
2603         self.vapi.nat44_add_del_identity_mapping(
2604             ip_address=b'0',
2605             sw_if_index=self.pg7.sw_if_index,
2606             port=port,
2607             protocol=IP_PROTOS.tcp,
2608             is_add=1)
2609
2610         # identity mappings with external interface
2611         identity_mappings = self.vapi.nat44_identity_mapping_dump()
2612         self.assertEqual(1, len(identity_mappings))
2613         self.assertEqual(self.pg7.sw_if_index,
2614                          identity_mappings[0].sw_if_index)
2615
2616         # configure interface address and check identity mappings
2617         self.pg7.config_ip4()
2618         identity_mappings = self.vapi.nat44_identity_mapping_dump()
2619         resolved = False
2620         self.assertEqual(2, len(identity_mappings))
2621         for sm in identity_mappings:
2622             if sm.sw_if_index == 0xFFFFFFFF:
2623                 self.assertEqual(str(identity_mappings[0].ip_address),
2624                                  self.pg7.local_ip4)
2625                 self.assertEqual(port, identity_mappings[0].port)
2626                 self.assertEqual(IP_PROTOS.tcp, identity_mappings[0].protocol)
2627                 resolved = True
2628         self.assertTrue(resolved)
2629
2630         # remove interface address and check identity mappings
2631         self.pg7.unconfig_ip4()
2632         identity_mappings = self.vapi.nat44_identity_mapping_dump()
2633         self.assertEqual(1, len(identity_mappings))
2634         self.assertEqual(self.pg7.sw_if_index,
2635                          identity_mappings[0].sw_if_index)
2636
2637     def test_ipfix_nat44_sess(self):
2638         """ IPFIX logging NAT44 session created/deleted """
2639         self.ipfix_domain_id = 10
2640         self.ipfix_src_port = 20202
2641         collector_port = 30303
2642         bind_layers(UDP, IPFIX, dport=30303)
2643         self.nat44_add_address(self.nat_addr)
2644         flags = self.config_flags.NAT_IS_INSIDE
2645         self.vapi.nat44_interface_add_del_feature(
2646             sw_if_index=self.pg0.sw_if_index,
2647             flags=flags, is_add=1)
2648         self.vapi.nat44_interface_add_del_feature(
2649             sw_if_index=self.pg1.sw_if_index,
2650             is_add=1)
2651         self.vapi.set_ipfix_exporter(collector_address=self.pg3.remote_ip4,
2652                                      src_address=self.pg3.local_ip4,
2653                                      path_mtu=512,
2654                                      template_interval=10,
2655                                      collector_port=collector_port)
2656         self.vapi.nat_ipfix_enable_disable(domain_id=self.ipfix_domain_id,
2657                                            src_port=self.ipfix_src_port,
2658                                            enable=1)
2659
2660         pkts = self.create_stream_in(self.pg0, self.pg1)
2661         self.pg0.add_stream(pkts)
2662         self.pg_enable_capture(self.pg_interfaces)
2663         self.pg_start()
2664         capture = self.pg1.get_capture(len(pkts))
2665         self.verify_capture_out(capture)
2666         self.nat44_add_address(self.nat_addr, is_add=0)
2667         self.vapi.ipfix_flush()
2668         capture = self.pg3.get_capture(7)
2669         ipfix = IPFIXDecoder()
2670         # first load template
2671         for p in capture:
2672             self.assertTrue(p.haslayer(IPFIX))
2673             self.assertEqual(p[IP].src, self.pg3.local_ip4)
2674             self.assertEqual(p[IP].dst, self.pg3.remote_ip4)
2675             self.assertEqual(p[UDP].sport, self.ipfix_src_port)
2676             self.assertEqual(p[UDP].dport, collector_port)
2677             self.assertEqual(p[IPFIX].observationDomainID,
2678                              self.ipfix_domain_id)
2679             if p.haslayer(Template):
2680                 ipfix.add_template(p.getlayer(Template))
2681         # verify events in data set
2682         for p in capture:
2683             if p.haslayer(Data):
2684                 data = ipfix.decode_data_set(p.getlayer(Set))
2685                 self.verify_ipfix_nat44_ses(data)
2686
2687     def test_ipfix_addr_exhausted(self):
2688         """ IPFIX logging NAT addresses exhausted """
2689         flags = self.config_flags.NAT_IS_INSIDE
2690         self.vapi.nat44_interface_add_del_feature(
2691             sw_if_index=self.pg0.sw_if_index,
2692             flags=flags, is_add=1)
2693         self.vapi.nat44_interface_add_del_feature(
2694             sw_if_index=self.pg1.sw_if_index,
2695             is_add=1)
2696         self.vapi.set_ipfix_exporter(collector_address=self.pg3.remote_ip4,
2697                                      src_address=self.pg3.local_ip4,
2698                                      path_mtu=512,
2699                                      template_interval=10)
2700         self.vapi.nat_ipfix_enable_disable(domain_id=self.ipfix_domain_id,
2701                                            src_port=self.ipfix_src_port,
2702                                            enable=1)
2703
2704         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
2705              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
2706              TCP(sport=3025))
2707         self.pg0.add_stream(p)
2708         self.pg_enable_capture(self.pg_interfaces)
2709         self.pg_start()
2710         self.pg1.assert_nothing_captured()
2711         sleep(1)
2712         self.vapi.ipfix_flush()
2713         capture = self.pg3.get_capture(7)
2714         ipfix = IPFIXDecoder()
2715         # first load template
2716         for p in capture:
2717             self.assertTrue(p.haslayer(IPFIX))
2718             self.assertEqual(p[IP].src, self.pg3.local_ip4)
2719             self.assertEqual(p[IP].dst, self.pg3.remote_ip4)
2720             self.assertEqual(p[UDP].sport, self.ipfix_src_port)
2721             self.assertEqual(p[UDP].dport, 4739)
2722             self.assertEqual(p[IPFIX].observationDomainID,
2723                              self.ipfix_domain_id)
2724             if p.haslayer(Template):
2725                 ipfix.add_template(p.getlayer(Template))
2726         # verify events in data set
2727         for p in capture:
2728             if p.haslayer(Data):
2729                 data = ipfix.decode_data_set(p.getlayer(Set))
2730                 self.verify_ipfix_addr_exhausted(data)
2731
2732     @unittest.skipUnless(running_extended_tests, "part of extended tests")
2733     def test_ipfix_max_sessions(self):
2734         """ IPFIX logging maximum session entries exceeded """
2735         self.nat44_add_address(self.nat_addr)
2736         flags = self.config_flags.NAT_IS_INSIDE
2737         self.vapi.nat44_interface_add_del_feature(
2738             sw_if_index=self.pg0.sw_if_index,
2739             flags=flags, is_add=1)
2740         self.vapi.nat44_interface_add_del_feature(
2741             sw_if_index=self.pg1.sw_if_index,
2742             is_add=1)
2743
2744         nat44_config = self.vapi.nat_show_config()
2745         max_sessions = 10 * nat44_config.translation_buckets
2746
2747         pkts = []
2748         for i in range(0, max_sessions):
2749             src = "10.10.%u.%u" % ((i & 0xFF00) >> 8, i & 0xFF)
2750             p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2751                  IP(src=src, dst=self.pg1.remote_ip4) /
2752                  TCP(sport=1025))
2753             pkts.append(p)
2754         self.pg0.add_stream(pkts)
2755         self.pg_enable_capture(self.pg_interfaces)
2756         self.pg_start()
2757
2758         self.pg1.get_capture(max_sessions)
2759         self.vapi.set_ipfix_exporter(collector_address=self.pg3.remote_ip4,
2760                                      src_address=self.pg3.local_ip4,
2761                                      path_mtu=512,
2762                                      template_interval=10)
2763         self.vapi.nat_ipfix_enable_disable(domain_id=self.ipfix_domain_id,
2764                                            src_port=self.ipfix_src_port,
2765                                            enable=1)
2766
2767         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2768              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
2769              TCP(sport=1025))
2770         self.pg0.add_stream(p)
2771         self.pg_enable_capture(self.pg_interfaces)
2772         self.pg_start()
2773         self.pg1.assert_nothing_captured()
2774         sleep(1)
2775         self.vapi.ipfix_flush()
2776         capture = self.pg3.get_capture(7)
2777         ipfix = IPFIXDecoder()
2778         # first load template
2779         for p in capture:
2780             self.assertTrue(p.haslayer(IPFIX))
2781             self.assertEqual(p[IP].src, self.pg3.local_ip4)
2782             self.assertEqual(p[IP].dst, self.pg3.remote_ip4)
2783             self.assertEqual(p[UDP].sport, self.ipfix_src_port)
2784             self.assertEqual(p[UDP].dport, 4739)
2785             self.assertEqual(p[IPFIX].observationDomainID,
2786                              self.ipfix_domain_id)
2787             if p.haslayer(Template):
2788                 ipfix.add_template(p.getlayer(Template))
2789         # verify events in data set
2790         for p in capture:
2791             if p.haslayer(Data):
2792                 data = ipfix.decode_data_set(p.getlayer(Set))
2793                 self.verify_ipfix_max_sessions(data, max_sessions)
2794
2795     def test_syslog_apmap(self):
2796         """ Test syslog address and port mapping creation and deletion """
2797         self.vapi.syslog_set_filter(
2798             self.SYSLOG_SEVERITY.SYSLOG_API_SEVERITY_INFO)
2799         self.vapi.syslog_set_sender(self.pg3.local_ip4, self.pg3.remote_ip4)
2800         self.nat44_add_address(self.nat_addr)
2801         flags = self.config_flags.NAT_IS_INSIDE
2802         self.vapi.nat44_interface_add_del_feature(
2803             sw_if_index=self.pg0.sw_if_index,
2804             flags=flags, is_add=1)
2805         self.vapi.nat44_interface_add_del_feature(
2806             sw_if_index=self.pg1.sw_if_index,
2807             is_add=1)
2808
2809         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2810              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
2811              TCP(sport=self.tcp_port_in, dport=20))
2812         self.pg0.add_stream(p)
2813         self.pg_enable_capture(self.pg_interfaces)
2814         self.pg_start()
2815         capture = self.pg1.get_capture(1)
2816         self.tcp_port_out = capture[0][TCP].sport
2817         capture = self.pg3.get_capture(1)
2818         self.verify_syslog_apmap(capture[0][Raw].load)
2819
2820         self.pg_enable_capture(self.pg_interfaces)
2821         self.pg_start()
2822         self.nat44_add_address(self.nat_addr, is_add=0)
2823         capture = self.pg3.get_capture(1)
2824         self.verify_syslog_apmap(capture[0][Raw].load, False)
2825
2826     def test_pool_addr_fib(self):
2827         """ NAT44 add pool addresses to FIB """
2828         static_addr = '10.0.0.10'
2829         self.nat44_add_address(self.nat_addr)
2830         flags = self.config_flags.NAT_IS_INSIDE
2831         self.vapi.nat44_interface_add_del_feature(
2832             sw_if_index=self.pg0.sw_if_index,
2833             flags=flags, is_add=1)
2834         self.vapi.nat44_interface_add_del_feature(
2835             sw_if_index=self.pg1.sw_if_index,
2836             is_add=1)
2837         self.nat44_add_static_mapping(self.pg0.remote_ip4, static_addr)
2838
2839         # NAT44 address
2840         p = (Ether(src=self.pg1.remote_mac, dst='ff:ff:ff:ff:ff:ff') /
2841              ARP(op=ARP.who_has, pdst=self.nat_addr,
2842                  psrc=self.pg1.remote_ip4, hwsrc=self.pg1.remote_mac))
2843         self.pg1.add_stream(p)
2844         self.pg_enable_capture(self.pg_interfaces)
2845         self.pg_start()
2846         capture = self.pg1.get_capture(1)
2847         self.assertTrue(capture[0].haslayer(ARP))
2848         self.assertTrue(capture[0][ARP].op, ARP.is_at)
2849
2850         # 1:1 NAT address
2851         p = (Ether(src=self.pg1.remote_mac, dst='ff:ff:ff:ff:ff:ff') /
2852              ARP(op=ARP.who_has, pdst=static_addr,
2853                  psrc=self.pg1.remote_ip4, hwsrc=self.pg1.remote_mac))
2854         self.pg1.add_stream(p)
2855         self.pg_enable_capture(self.pg_interfaces)
2856         self.pg_start()
2857         capture = self.pg1.get_capture(1)
2858         self.assertTrue(capture[0].haslayer(ARP))
2859         self.assertTrue(capture[0][ARP].op, ARP.is_at)
2860
2861         # send ARP to non-NAT44 interface
2862         p = (Ether(src=self.pg2.remote_mac, dst='ff:ff:ff:ff:ff:ff') /
2863              ARP(op=ARP.who_has, pdst=self.nat_addr,
2864                  psrc=self.pg2.remote_ip4, hwsrc=self.pg2.remote_mac))
2865         self.pg2.add_stream(p)
2866         self.pg_enable_capture(self.pg_interfaces)
2867         self.pg_start()
2868         self.pg1.assert_nothing_captured()
2869
2870         # remove addresses and verify
2871         self.nat44_add_address(self.nat_addr, is_add=0)
2872         self.nat44_add_static_mapping(self.pg0.remote_ip4, static_addr,
2873                                       is_add=0)
2874
2875         p = (Ether(src=self.pg1.remote_mac, dst='ff:ff:ff:ff:ff:ff') /
2876              ARP(op=ARP.who_has, pdst=self.nat_addr,
2877                  psrc=self.pg1.remote_ip4, hwsrc=self.pg1.remote_mac))
2878         self.pg1.add_stream(p)
2879         self.pg_enable_capture(self.pg_interfaces)
2880         self.pg_start()
2881         self.pg1.assert_nothing_captured()
2882
2883         p = (Ether(src=self.pg1.remote_mac, dst='ff:ff:ff:ff:ff:ff') /
2884              ARP(op=ARP.who_has, pdst=static_addr,
2885                  psrc=self.pg1.remote_ip4, hwsrc=self.pg1.remote_mac))
2886         self.pg1.add_stream(p)
2887         self.pg_enable_capture(self.pg_interfaces)
2888         self.pg_start()
2889         self.pg1.assert_nothing_captured()
2890
2891     def test_vrf_mode(self):
2892         """ NAT44 tenant VRF aware address pool mode """
2893
2894         vrf_id1 = 1
2895         vrf_id2 = 2
2896         nat_ip1 = "10.0.0.10"
2897         nat_ip2 = "10.0.0.11"
2898
2899         self.pg0.unconfig_ip4()
2900         self.pg1.unconfig_ip4()
2901         self.vapi.ip_table_add_del(is_add=1, table={'table_id': vrf_id1})
2902         self.vapi.ip_table_add_del(is_add=1, table={'table_id': vrf_id2})
2903         self.pg0.set_table_ip4(vrf_id1)
2904         self.pg1.set_table_ip4(vrf_id2)
2905         self.pg0.config_ip4()
2906         self.pg1.config_ip4()
2907         self.pg0.resolve_arp()
2908         self.pg1.resolve_arp()
2909
2910         self.nat44_add_address(nat_ip1, vrf_id=vrf_id1)
2911         self.nat44_add_address(nat_ip2, vrf_id=vrf_id2)
2912         flags = self.config_flags.NAT_IS_INSIDE
2913         self.vapi.nat44_interface_add_del_feature(
2914             sw_if_index=self.pg0.sw_if_index,
2915             flags=flags, is_add=1)
2916         self.vapi.nat44_interface_add_del_feature(
2917             sw_if_index=self.pg1.sw_if_index,
2918             flags=flags, is_add=1)
2919         self.vapi.nat44_interface_add_del_feature(
2920             sw_if_index=self.pg2.sw_if_index,
2921             is_add=1)
2922
2923         try:
2924             # first VRF
2925             pkts = self.create_stream_in(self.pg0, self.pg2)
2926             self.pg0.add_stream(pkts)
2927             self.pg_enable_capture(self.pg_interfaces)
2928             self.pg_start()
2929             capture = self.pg2.get_capture(len(pkts))
2930             self.verify_capture_out(capture, nat_ip1)
2931
2932             # second VRF
2933             pkts = self.create_stream_in(self.pg1, self.pg2)
2934             self.pg1.add_stream(pkts)
2935             self.pg_enable_capture(self.pg_interfaces)
2936             self.pg_start()
2937             capture = self.pg2.get_capture(len(pkts))
2938             self.verify_capture_out(capture, nat_ip2)
2939
2940         finally:
2941             self.pg0.unconfig_ip4()
2942             self.pg1.unconfig_ip4()
2943             self.pg0.set_table_ip4(0)
2944             self.pg1.set_table_ip4(0)
2945             self.pg0.config_ip4()
2946             self.pg1.config_ip4()
2947             self.pg0.resolve_arp()
2948             self.pg1.resolve_arp()
2949             self.vapi.ip_table_add_del(is_add=0, table={'table_id': vrf_id1})
2950             self.vapi.ip_table_add_del(is_add=0, table={'table_id': vrf_id2})
2951
2952     def test_vrf_feature_independent(self):
2953         """ NAT44 tenant VRF independent address pool mode """
2954
2955         nat_ip1 = "10.0.0.10"
2956         nat_ip2 = "10.0.0.11"
2957
2958         self.nat44_add_address(nat_ip1)
2959         self.nat44_add_address(nat_ip2, vrf_id=99)
2960         flags = self.config_flags.NAT_IS_INSIDE
2961         self.vapi.nat44_interface_add_del_feature(
2962             sw_if_index=self.pg0.sw_if_index,
2963             flags=flags, is_add=1)
2964         self.vapi.nat44_interface_add_del_feature(
2965             sw_if_index=self.pg1.sw_if_index,
2966             flags=flags, is_add=1)
2967         self.vapi.nat44_interface_add_del_feature(
2968             sw_if_index=self.pg2.sw_if_index,
2969             is_add=1)
2970
2971         # first VRF
2972         pkts = self.create_stream_in(self.pg0, self.pg2)
2973         self.pg0.add_stream(pkts)
2974         self.pg_enable_capture(self.pg_interfaces)
2975         self.pg_start()
2976         capture = self.pg2.get_capture(len(pkts))
2977         self.verify_capture_out(capture, nat_ip1)
2978
2979         # second VRF
2980         pkts = self.create_stream_in(self.pg1, self.pg2)
2981         self.pg1.add_stream(pkts)
2982         self.pg_enable_capture(self.pg_interfaces)
2983         self.pg_start()
2984         capture = self.pg2.get_capture(len(pkts))
2985         self.verify_capture_out(capture, nat_ip1)
2986
2987     def create_routes_and_neigbors(self):
2988         r1 = VppIpRoute(self, self.pg7.remote_ip4, 32,
2989                         [VppRoutePath(self.pg7.remote_ip4,
2990                                       self.pg7.sw_if_index)])
2991         r2 = VppIpRoute(self, self.pg8.remote_ip4, 32,
2992                         [VppRoutePath(self.pg8.remote_ip4,
2993                                       self.pg8.sw_if_index)])
2994         r1.add_vpp_config()
2995         r2.add_vpp_config()
2996
2997         n1 = VppNeighbor(self,
2998                          self.pg7.sw_if_index,
2999                          self.pg7.remote_mac,
3000                          self.pg7.remote_ip4,
3001                          is_static=1)
3002         n2 = VppNeighbor(self,
3003                          self.pg8.sw_if_index,
3004                          self.pg8.remote_mac,
3005                          self.pg8.remote_ip4,
3006                          is_static=1)
3007         n1.add_vpp_config()
3008         n2.add_vpp_config()
3009
3010     def test_dynamic_ipless_interfaces(self):
3011         """ NAT44 interfaces without configured IP address """
3012         self.create_routes_and_neigbors()
3013         self.nat44_add_address(self.nat_addr)
3014         flags = self.config_flags.NAT_IS_INSIDE
3015         self.vapi.nat44_interface_add_del_feature(
3016             sw_if_index=self.pg7.sw_if_index,
3017             flags=flags, is_add=1)
3018         self.vapi.nat44_interface_add_del_feature(
3019             sw_if_index=self.pg8.sw_if_index,
3020             is_add=1)
3021
3022         # in2out
3023         pkts = self.create_stream_in(self.pg7, self.pg8)
3024         self.pg7.add_stream(pkts)
3025         self.pg_enable_capture(self.pg_interfaces)
3026         self.pg_start()
3027         capture = self.pg8.get_capture(len(pkts))
3028         self.verify_capture_out(capture)
3029
3030         # out2in
3031         pkts = self.create_stream_out(self.pg8, self.nat_addr)
3032         self.pg8.add_stream(pkts)
3033         self.pg_enable_capture(self.pg_interfaces)
3034         self.pg_start()
3035         capture = self.pg7.get_capture(len(pkts))
3036         self.verify_capture_in(capture, self.pg7)
3037
3038     def test_static_ipless_interfaces(self):
3039         """ NAT44 interfaces without configured IP address - 1:1 NAT """
3040
3041         self.create_routes_and_neigbors()
3042         self.nat44_add_static_mapping(self.pg7.remote_ip4, self.nat_addr)
3043         flags = self.config_flags.NAT_IS_INSIDE
3044         self.vapi.nat44_interface_add_del_feature(
3045             sw_if_index=self.pg7.sw_if_index,
3046             flags=flags, is_add=1)
3047         self.vapi.nat44_interface_add_del_feature(
3048             sw_if_index=self.pg8.sw_if_index,
3049             is_add=1)
3050
3051         # out2in
3052         pkts = self.create_stream_out(self.pg8)
3053         self.pg8.add_stream(pkts)
3054         self.pg_enable_capture(self.pg_interfaces)
3055         self.pg_start()
3056         capture = self.pg7.get_capture(len(pkts))
3057         self.verify_capture_in(capture, self.pg7)
3058
3059         # in2out
3060         pkts = self.create_stream_in(self.pg7, self.pg8)
3061         self.pg7.add_stream(pkts)
3062         self.pg_enable_capture(self.pg_interfaces)
3063         self.pg_start()
3064         capture = self.pg8.get_capture(len(pkts))
3065         self.verify_capture_out(capture, self.nat_addr, True)
3066
3067     def test_static_with_port_ipless_interfaces(self):
3068         """ NAT44 interfaces without configured IP address - 1:1 NAPT """
3069
3070         self.tcp_port_out = 30606
3071         self.udp_port_out = 30607
3072         self.icmp_id_out = 30608
3073
3074         self.create_routes_and_neigbors()
3075         self.nat44_add_address(self.nat_addr)
3076         self.nat44_add_static_mapping(self.pg7.remote_ip4, self.nat_addr,
3077                                       self.tcp_port_in, self.tcp_port_out,
3078                                       proto=IP_PROTOS.tcp)
3079         self.nat44_add_static_mapping(self.pg7.remote_ip4, self.nat_addr,
3080                                       self.udp_port_in, self.udp_port_out,
3081                                       proto=IP_PROTOS.udp)
3082         self.nat44_add_static_mapping(self.pg7.remote_ip4, self.nat_addr,
3083                                       self.icmp_id_in, self.icmp_id_out,
3084                                       proto=IP_PROTOS.icmp)
3085         flags = self.config_flags.NAT_IS_INSIDE
3086         self.vapi.nat44_interface_add_del_feature(
3087             sw_if_index=self.pg7.sw_if_index,
3088             flags=flags, is_add=1)
3089         self.vapi.nat44_interface_add_del_feature(
3090             sw_if_index=self.pg8.sw_if_index,
3091             is_add=1)
3092
3093         # out2in
3094         pkts = self.create_stream_out(self.pg8)
3095         self.pg8.add_stream(pkts)
3096         self.pg_enable_capture(self.pg_interfaces)
3097         self.pg_start()
3098         capture = self.pg7.get_capture(len(pkts))
3099         self.verify_capture_in(capture, self.pg7)
3100
3101         # in2out
3102         pkts = self.create_stream_in(self.pg7, self.pg8)
3103         self.pg7.add_stream(pkts)
3104         self.pg_enable_capture(self.pg_interfaces)
3105         self.pg_start()
3106         capture = self.pg8.get_capture(len(pkts))
3107         self.verify_capture_out(capture)
3108
3109     def test_static_unknown_proto(self):
3110         """ 1:1 NAT translate packet with unknown protocol """
3111         nat_ip = "10.0.0.10"
3112         self.nat44_add_static_mapping(self.pg0.remote_ip4, nat_ip)
3113         flags = self.config_flags.NAT_IS_INSIDE
3114         self.vapi.nat44_interface_add_del_feature(
3115             sw_if_index=self.pg0.sw_if_index,
3116             flags=flags, is_add=1)
3117         self.vapi.nat44_interface_add_del_feature(
3118             sw_if_index=self.pg1.sw_if_index,
3119             is_add=1)
3120
3121         # in2out
3122         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
3123              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3124              GRE() /
3125              IP(src=self.pg2.remote_ip4, dst=self.pg3.remote_ip4) /
3126              TCP(sport=1234, dport=1234))
3127         self.pg0.add_stream(p)
3128         self.pg_enable_capture(self.pg_interfaces)
3129         self.pg_start()
3130         p = self.pg1.get_capture(1)
3131         packet = p[0]
3132         try:
3133             self.assertEqual(packet[IP].src, nat_ip)
3134             self.assertEqual(packet[IP].dst, self.pg1.remote_ip4)
3135             self.assertEqual(packet.haslayer(GRE), 1)
3136             self.assert_packet_checksums_valid(packet)
3137         except:
3138             self.logger.error(ppp("Unexpected or invalid packet:", packet))
3139             raise
3140
3141         # out2in
3142         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
3143              IP(src=self.pg1.remote_ip4, dst=nat_ip) /
3144              GRE() /
3145              IP(src=self.pg3.remote_ip4, dst=self.pg2.remote_ip4) /
3146              TCP(sport=1234, dport=1234))
3147         self.pg1.add_stream(p)
3148         self.pg_enable_capture(self.pg_interfaces)
3149         self.pg_start()
3150         p = self.pg0.get_capture(1)
3151         packet = p[0]
3152         try:
3153             self.assertEqual(packet[IP].src, self.pg1.remote_ip4)
3154             self.assertEqual(packet[IP].dst, self.pg0.remote_ip4)
3155             self.assertEqual(packet.haslayer(GRE), 1)
3156             self.assert_packet_checksums_valid(packet)
3157         except:
3158             self.logger.error(ppp("Unexpected or invalid packet:", packet))
3159             raise
3160
3161     def test_hairpinning_static_unknown_proto(self):
3162         """ 1:1 NAT translate packet with unknown protocol - hairpinning """
3163
3164         host = self.pg0.remote_hosts[0]
3165         server = self.pg0.remote_hosts[1]
3166
3167         host_nat_ip = "10.0.0.10"
3168         server_nat_ip = "10.0.0.11"
3169
3170         self.nat44_add_static_mapping(host.ip4, host_nat_ip)
3171         self.nat44_add_static_mapping(server.ip4, server_nat_ip)
3172         flags = self.config_flags.NAT_IS_INSIDE
3173         self.vapi.nat44_interface_add_del_feature(
3174             sw_if_index=self.pg0.sw_if_index,
3175             flags=flags, is_add=1)
3176         self.vapi.nat44_interface_add_del_feature(
3177             sw_if_index=self.pg1.sw_if_index,
3178             is_add=1)
3179
3180         # host to server
3181         p = (Ether(dst=self.pg0.local_mac, src=host.mac) /
3182              IP(src=host.ip4, dst=server_nat_ip) /
3183              GRE() /
3184              IP(src=self.pg2.remote_ip4, dst=self.pg3.remote_ip4) /
3185              TCP(sport=1234, dport=1234))
3186         self.pg0.add_stream(p)
3187         self.pg_enable_capture(self.pg_interfaces)
3188         self.pg_start()
3189         p = self.pg0.get_capture(1)
3190         packet = p[0]
3191         try:
3192             self.assertEqual(packet[IP].src, host_nat_ip)
3193             self.assertEqual(packet[IP].dst, server.ip4)
3194             self.assertEqual(packet.haslayer(GRE), 1)
3195             self.assert_packet_checksums_valid(packet)
3196         except:
3197             self.logger.error(ppp("Unexpected or invalid packet:", packet))
3198             raise
3199
3200         # server to host
3201         p = (Ether(dst=self.pg0.local_mac, src=server.mac) /
3202              IP(src=server.ip4, dst=host_nat_ip) /
3203              GRE() /
3204              IP(src=self.pg3.remote_ip4, dst=self.pg2.remote_ip4) /
3205              TCP(sport=1234, dport=1234))
3206         self.pg0.add_stream(p)
3207         self.pg_enable_capture(self.pg_interfaces)
3208         self.pg_start()
3209         p = self.pg0.get_capture(1)
3210         packet = p[0]
3211         try:
3212             self.assertEqual(packet[IP].src, server_nat_ip)
3213             self.assertEqual(packet[IP].dst, host.ip4)
3214             self.assertEqual(packet.haslayer(GRE), 1)
3215             self.assert_packet_checksums_valid(packet)
3216         except:
3217             self.logger.error(ppp("Unexpected or invalid packet:", packet))
3218             raise
3219
3220     def test_output_feature(self):
3221         """ NAT44 interface output feature (in2out postrouting) """
3222         self.nat44_add_address(self.nat_addr)
3223         flags = self.config_flags.NAT_IS_INSIDE
3224         self.vapi.nat44_interface_add_del_output_feature(
3225             is_add=1, flags=flags,
3226             sw_if_index=self.pg0.sw_if_index)
3227         self.vapi.nat44_interface_add_del_output_feature(
3228             is_add=1, flags=flags,
3229             sw_if_index=self.pg1.sw_if_index)
3230         self.vapi.nat44_interface_add_del_output_feature(
3231             is_add=1,
3232             sw_if_index=self.pg3.sw_if_index)
3233
3234         # in2out
3235         pkts = self.create_stream_in(self.pg0, self.pg3)
3236         self.pg0.add_stream(pkts)
3237         self.pg_enable_capture(self.pg_interfaces)
3238         self.pg_start()
3239         capture = self.pg3.get_capture(len(pkts))
3240         self.verify_capture_out(capture)
3241
3242         # out2in
3243         pkts = self.create_stream_out(self.pg3)
3244         self.pg3.add_stream(pkts)
3245         self.pg_enable_capture(self.pg_interfaces)
3246         self.pg_start()
3247         capture = self.pg0.get_capture(len(pkts))
3248         self.verify_capture_in(capture, self.pg0)
3249
3250         # from non-NAT interface to NAT inside interface
3251         pkts = self.create_stream_in(self.pg2, self.pg0)
3252         self.pg2.add_stream(pkts)
3253         self.pg_enable_capture(self.pg_interfaces)
3254         self.pg_start()
3255         capture = self.pg0.get_capture(len(pkts))
3256         self.verify_capture_no_translation(capture, self.pg2, self.pg0)
3257
3258     def test_output_feature_vrf_aware(self):
3259         """ NAT44 interface output feature VRF aware (in2out postrouting) """
3260         nat_ip_vrf10 = "10.0.0.10"
3261         nat_ip_vrf20 = "10.0.0.20"
3262
3263         r1 = VppIpRoute(self, self.pg3.remote_ip4, 32,
3264                         [VppRoutePath(self.pg3.remote_ip4,
3265                                       self.pg3.sw_if_index)],
3266                         table_id=10)
3267         r2 = VppIpRoute(self, self.pg3.remote_ip4, 32,
3268                         [VppRoutePath(self.pg3.remote_ip4,
3269                                       self.pg3.sw_if_index)],
3270                         table_id=20)
3271         r1.add_vpp_config()
3272         r2.add_vpp_config()
3273
3274         self.nat44_add_address(nat_ip_vrf10, vrf_id=10)
3275         self.nat44_add_address(nat_ip_vrf20, vrf_id=20)
3276         flags = self.config_flags.NAT_IS_INSIDE
3277         self.vapi.nat44_interface_add_del_output_feature(
3278             is_add=1, flags=flags,
3279             sw_if_index=self.pg4.sw_if_index)
3280         self.vapi.nat44_interface_add_del_output_feature(
3281             is_add=1, flags=flags,
3282             sw_if_index=self.pg6.sw_if_index)
3283         self.vapi.nat44_interface_add_del_output_feature(
3284             is_add=1,
3285             sw_if_index=self.pg3.sw_if_index)
3286
3287         # in2out VRF 10
3288         pkts = self.create_stream_in(self.pg4, self.pg3)
3289         self.pg4.add_stream(pkts)
3290         self.pg_enable_capture(self.pg_interfaces)
3291         self.pg_start()
3292         capture = self.pg3.get_capture(len(pkts))
3293         self.verify_capture_out(capture, nat_ip=nat_ip_vrf10)
3294
3295         # out2in VRF 10
3296         pkts = self.create_stream_out(self.pg3, dst_ip=nat_ip_vrf10)
3297         self.pg3.add_stream(pkts)
3298         self.pg_enable_capture(self.pg_interfaces)
3299         self.pg_start()
3300         capture = self.pg4.get_capture(len(pkts))
3301         self.verify_capture_in(capture, self.pg4)
3302
3303         # in2out VRF 20
3304         pkts = self.create_stream_in(self.pg6, self.pg3)
3305         self.pg6.add_stream(pkts)
3306         self.pg_enable_capture(self.pg_interfaces)
3307         self.pg_start()
3308         capture = self.pg3.get_capture(len(pkts))
3309         self.verify_capture_out(capture, nat_ip=nat_ip_vrf20)
3310
3311         # out2in VRF 20
3312         pkts = self.create_stream_out(self.pg3, dst_ip=nat_ip_vrf20)
3313         self.pg3.add_stream(pkts)
3314         self.pg_enable_capture(self.pg_interfaces)
3315         self.pg_start()
3316         capture = self.pg6.get_capture(len(pkts))
3317         self.verify_capture_in(capture, self.pg6)
3318
3319     def test_output_feature_hairpinning(self):
3320         """ NAT44 interface output feature hairpinning (in2out postrouting) """
3321         host = self.pg0.remote_hosts[0]
3322         server = self.pg0.remote_hosts[1]
3323         host_in_port = 1234
3324         host_out_port = 0
3325         server_in_port = 5678
3326         server_out_port = 8765
3327
3328         self.nat44_add_address(self.nat_addr)
3329         flags = self.config_flags.NAT_IS_INSIDE
3330         self.vapi.nat44_interface_add_del_output_feature(
3331             is_add=1, flags=flags,
3332             sw_if_index=self.pg0.sw_if_index)
3333         self.vapi.nat44_interface_add_del_output_feature(
3334             is_add=1,
3335             sw_if_index=self.pg1.sw_if_index)
3336
3337         # add static mapping for server
3338         self.nat44_add_static_mapping(server.ip4, self.nat_addr,
3339                                       server_in_port, server_out_port,
3340                                       proto=IP_PROTOS.tcp)
3341
3342         # send packet from host to server
3343         p = (Ether(src=host.mac, dst=self.pg0.local_mac) /
3344              IP(src=host.ip4, dst=self.nat_addr) /
3345              TCP(sport=host_in_port, dport=server_out_port))
3346         self.pg0.add_stream(p)
3347         self.pg_enable_capture(self.pg_interfaces)
3348         self.pg_start()
3349         capture = self.pg0.get_capture(1)
3350         p = capture[0]
3351         try:
3352             ip = p[IP]
3353             tcp = p[TCP]
3354             self.assertEqual(ip.src, self.nat_addr)
3355             self.assertEqual(ip.dst, server.ip4)
3356             self.assertNotEqual(tcp.sport, host_in_port)
3357             self.assertEqual(tcp.dport, server_in_port)
3358             self.assert_packet_checksums_valid(p)
3359             host_out_port = tcp.sport
3360         except:
3361             self.logger.error(ppp("Unexpected or invalid packet:", p))
3362             raise
3363
3364         # send reply from server to host
3365         p = (Ether(src=server.mac, dst=self.pg0.local_mac) /
3366              IP(src=server.ip4, dst=self.nat_addr) /
3367              TCP(sport=server_in_port, dport=host_out_port))
3368         self.pg0.add_stream(p)
3369         self.pg_enable_capture(self.pg_interfaces)
3370         self.pg_start()
3371         capture = self.pg0.get_capture(1)
3372         p = capture[0]
3373         try:
3374             ip = p[IP]
3375             tcp = p[TCP]
3376             self.assertEqual(ip.src, self.nat_addr)
3377             self.assertEqual(ip.dst, host.ip4)
3378             self.assertEqual(tcp.sport, server_out_port)
3379             self.assertEqual(tcp.dport, host_in_port)
3380             self.assert_packet_checksums_valid(p)
3381         except:
3382             self.logger.error(ppp("Unexpected or invalid packet:", p))
3383             raise
3384
3385     def test_one_armed_nat44(self):
3386         """ One armed NAT44 """
3387         remote_host = self.pg9.remote_hosts[0]
3388         local_host = self.pg9.remote_hosts[1]
3389         external_port = 0
3390
3391         self.nat44_add_address(self.nat_addr)
3392         flags = self.config_flags.NAT_IS_INSIDE
3393         self.vapi.nat44_interface_add_del_feature(
3394             sw_if_index=self.pg9.sw_if_index,
3395             is_add=1)
3396         self.vapi.nat44_interface_add_del_feature(
3397             sw_if_index=self.pg9.sw_if_index,
3398             flags=flags, is_add=1)
3399
3400         # in2out
3401         p = (Ether(src=self.pg9.remote_mac, dst=self.pg9.local_mac) /
3402              IP(src=local_host.ip4, dst=remote_host.ip4) /
3403              TCP(sport=12345, dport=80))
3404         self.pg9.add_stream(p)
3405         self.pg_enable_capture(self.pg_interfaces)
3406         self.pg_start()
3407         capture = self.pg9.get_capture(1)
3408         p = capture[0]
3409         try:
3410             ip = p[IP]
3411             tcp = p[TCP]
3412             self.assertEqual(ip.src, self.nat_addr)
3413             self.assertEqual(ip.dst, remote_host.ip4)
3414             self.assertNotEqual(tcp.sport, 12345)
3415             external_port = tcp.sport
3416             self.assertEqual(tcp.dport, 80)
3417             self.assert_packet_checksums_valid(p)
3418         except:
3419             self.logger.error(ppp("Unexpected or invalid packet:", p))
3420             raise
3421
3422         # out2in
3423         p = (Ether(src=self.pg9.remote_mac, dst=self.pg9.local_mac) /
3424              IP(src=remote_host.ip4, dst=self.nat_addr) /
3425              TCP(sport=80, dport=external_port))
3426         self.pg9.add_stream(p)
3427         self.pg_enable_capture(self.pg_interfaces)
3428         self.pg_start()
3429         capture = self.pg9.get_capture(1)
3430         p = capture[0]
3431         try:
3432             ip = p[IP]
3433             tcp = p[TCP]
3434             self.assertEqual(ip.src, remote_host.ip4)
3435             self.assertEqual(ip.dst, local_host.ip4)
3436             self.assertEqual(tcp.sport, 80)
3437             self.assertEqual(tcp.dport, 12345)
3438             self.assert_packet_checksums_valid(p)
3439         except:
3440             self.logger.error(ppp("Unexpected or invalid packet:", p))
3441             raise
3442
3443         err = self.statistics.get_err_counter(
3444             '/err/nat44-classify/next in2out')
3445         self.assertEqual(err, 1)
3446         err = self.statistics.get_err_counter(
3447             '/err/nat44-classify/next out2in')
3448         self.assertEqual(err, 1)
3449
3450     def test_del_session(self):
3451         """ Delete NAT44 session """
3452         self.nat44_add_address(self.nat_addr)
3453         flags = self.config_flags.NAT_IS_INSIDE
3454         self.vapi.nat44_interface_add_del_feature(
3455             sw_if_index=self.pg0.sw_if_index,
3456             flags=flags, is_add=1)
3457         self.vapi.nat44_interface_add_del_feature(
3458             sw_if_index=self.pg1.sw_if_index,
3459             is_add=1)
3460
3461         pkts = self.create_stream_in(self.pg0, self.pg1)
3462         self.pg0.add_stream(pkts)
3463         self.pg_enable_capture(self.pg_interfaces)
3464         self.pg_start()
3465         self.pg1.get_capture(len(pkts))
3466
3467         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
3468         nsessions = len(sessions)
3469
3470         self.vapi.nat44_del_session(address=sessions[0].inside_ip_address,
3471                                     port=sessions[0].inside_port,
3472                                     protocol=sessions[0].protocol,
3473                                     flags=self.config_flags.NAT_IS_INSIDE)
3474         self.vapi.nat44_del_session(address=sessions[1].outside_ip_address,
3475                                     port=sessions[1].outside_port,
3476                                     protocol=sessions[1].protocol)
3477
3478         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
3479         self.assertEqual(nsessions - len(sessions), 2)
3480
3481         self.vapi.nat44_del_session(address=sessions[0].inside_ip_address,
3482                                     port=sessions[0].inside_port,
3483                                     protocol=sessions[0].protocol,
3484                                     flags=self.config_flags.NAT_IS_INSIDE)
3485
3486         self.verify_no_nat44_user()
3487
3488     def test_frag_in_order(self):
3489         """ NAT44 translate fragments arriving in order """
3490
3491         self.nat44_add_address(self.nat_addr)
3492         flags = self.config_flags.NAT_IS_INSIDE
3493         self.vapi.nat44_interface_add_del_feature(
3494             sw_if_index=self.pg0.sw_if_index,
3495             flags=flags, is_add=1)
3496         self.vapi.nat44_interface_add_del_feature(
3497             sw_if_index=self.pg1.sw_if_index,
3498             is_add=1)
3499
3500         self.frag_in_order(proto=IP_PROTOS.tcp)
3501         self.frag_in_order(proto=IP_PROTOS.udp)
3502         self.frag_in_order(proto=IP_PROTOS.icmp)
3503
3504     def test_frag_forwarding(self):
3505         """ NAT44 forwarding fragment test """
3506         self.vapi.nat44_add_del_interface_addr(
3507             is_add=1,
3508             sw_if_index=self.pg1.sw_if_index)
3509         flags = self.config_flags.NAT_IS_INSIDE
3510         self.vapi.nat44_interface_add_del_feature(
3511             sw_if_index=self.pg0.sw_if_index,
3512             flags=flags, is_add=1)
3513         self.vapi.nat44_interface_add_del_feature(
3514             sw_if_index=self.pg1.sw_if_index,
3515             is_add=1)
3516         self.vapi.nat44_forwarding_enable_disable(enable=1)
3517
3518         data = b"A" * 16 + b"B" * 16 + b"C" * 3
3519         pkts = self.create_stream_frag(self.pg1,
3520                                        self.pg0.remote_ip4,
3521                                        4789,
3522                                        4789,
3523                                        data,
3524                                        proto=IP_PROTOS.udp)
3525         self.pg1.add_stream(pkts)
3526         self.pg_enable_capture(self.pg_interfaces)
3527         self.pg_start()
3528         frags = self.pg0.get_capture(len(pkts))
3529         p = self.reass_frags_and_verify(frags,
3530                                         self.pg1.remote_ip4,
3531                                         self.pg0.remote_ip4)
3532         self.assertEqual(p[UDP].sport, 4789)
3533         self.assertEqual(p[UDP].dport, 4789)
3534         self.assertEqual(data, p[Raw].load)
3535
3536     def test_reass_hairpinning(self):
3537         """ NAT44 fragments hairpinning """
3538
3539         self.server = self.pg0.remote_hosts[1]
3540         self.host_in_port = random.randint(1025, 65535)
3541         self.server_in_port = random.randint(1025, 65535)
3542         self.server_out_port = random.randint(1025, 65535)
3543
3544         self.nat44_add_address(self.nat_addr)
3545         flags = self.config_flags.NAT_IS_INSIDE
3546         self.vapi.nat44_interface_add_del_feature(
3547             sw_if_index=self.pg0.sw_if_index,
3548             flags=flags, is_add=1)
3549         self.vapi.nat44_interface_add_del_feature(
3550             sw_if_index=self.pg1.sw_if_index,
3551             is_add=1)
3552         # add static mapping for server
3553         self.nat44_add_static_mapping(self.server.ip4, self.nat_addr,
3554                                       self.server_in_port,
3555                                       self.server_out_port,
3556                                       proto=IP_PROTOS.tcp)
3557         self.nat44_add_static_mapping(self.server.ip4, self.nat_addr,
3558                                       self.server_in_port,
3559                                       self.server_out_port,
3560                                       proto=IP_PROTOS.udp)
3561         self.nat44_add_static_mapping(self.server.ip4, self.nat_addr)
3562
3563         self.reass_hairpinning(proto=IP_PROTOS.tcp)
3564         self.reass_hairpinning(proto=IP_PROTOS.udp)
3565         self.reass_hairpinning(proto=IP_PROTOS.icmp)
3566
3567     def test_frag_out_of_order(self):
3568         """ NAT44 translate fragments arriving out of order """
3569
3570         self.nat44_add_address(self.nat_addr)
3571         flags = self.config_flags.NAT_IS_INSIDE
3572         self.vapi.nat44_interface_add_del_feature(
3573             sw_if_index=self.pg0.sw_if_index,
3574             flags=flags, is_add=1)
3575         self.vapi.nat44_interface_add_del_feature(
3576             sw_if_index=self.pg1.sw_if_index,
3577             is_add=1)
3578
3579         self.frag_out_of_order(proto=IP_PROTOS.tcp)
3580         self.frag_out_of_order(proto=IP_PROTOS.udp)
3581         self.frag_out_of_order(proto=IP_PROTOS.icmp)
3582
3583     def test_port_restricted(self):
3584         """ Port restricted NAT44 (MAP-E CE) """
3585         self.nat44_add_address(self.nat_addr)
3586         flags = self.config_flags.NAT_IS_INSIDE
3587         self.vapi.nat44_interface_add_del_feature(
3588             sw_if_index=self.pg0.sw_if_index,
3589             flags=flags, is_add=1)
3590         self.vapi.nat44_interface_add_del_feature(
3591             sw_if_index=self.pg1.sw_if_index,
3592             is_add=1)
3593         self.vapi.nat_set_addr_and_port_alloc_alg(alg=1,
3594                                                   psid_offset=6,
3595                                                   psid_length=6,
3596                                                   psid=10)
3597
3598         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
3599              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3600              TCP(sport=4567, dport=22))
3601         self.pg0.add_stream(p)
3602         self.pg_enable_capture(self.pg_interfaces)
3603         self.pg_start()
3604         capture = self.pg1.get_capture(1)
3605         p = capture[0]
3606         try:
3607             ip = p[IP]
3608             tcp = p[TCP]
3609             self.assertEqual(ip.dst, self.pg1.remote_ip4)
3610             self.assertEqual(ip.src, self.nat_addr)
3611             self.assertEqual(tcp.dport, 22)
3612             self.assertNotEqual(tcp.sport, 4567)
3613             self.assertEqual((tcp.sport >> 6) & 63, 10)
3614             self.assert_packet_checksums_valid(p)
3615         except:
3616             self.logger.error(ppp("Unexpected or invalid packet:", p))
3617             raise
3618
3619     def test_port_range(self):
3620         """ External address port range """
3621         self.nat44_add_address(self.nat_addr)
3622         flags = self.config_flags.NAT_IS_INSIDE
3623         self.vapi.nat44_interface_add_del_feature(
3624             sw_if_index=self.pg0.sw_if_index,
3625             flags=flags, is_add=1)
3626         self.vapi.nat44_interface_add_del_feature(
3627             sw_if_index=self.pg1.sw_if_index,
3628             is_add=1)
3629         self.vapi.nat_set_addr_and_port_alloc_alg(alg=2,
3630                                                   start_port=1025,
3631                                                   end_port=1027)
3632
3633         pkts = []
3634         for port in range(0, 5):
3635             p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
3636                  IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3637                  TCP(sport=1125 + port))
3638             pkts.append(p)
3639         self.pg0.add_stream(pkts)
3640         self.pg_enable_capture(self.pg_interfaces)
3641         self.pg_start()
3642         capture = self.pg1.get_capture(3)
3643         for p in capture:
3644             tcp = p[TCP]
3645             self.assertGreaterEqual(tcp.sport, 1025)
3646             self.assertLessEqual(tcp.sport, 1027)
3647
3648     def test_multiple_outside_vrf(self):
3649         """ Multiple outside VRF """
3650         vrf_id1 = 1
3651         vrf_id2 = 2
3652
3653         self.pg1.unconfig_ip4()
3654         self.pg2.unconfig_ip4()
3655         self.vapi.ip_table_add_del(is_add=1, table={'table_id': vrf_id1})
3656         self.vapi.ip_table_add_del(is_add=1, table={'table_id': vrf_id2})
3657         self.pg1.set_table_ip4(vrf_id1)
3658         self.pg2.set_table_ip4(vrf_id2)
3659         self.pg1.config_ip4()
3660         self.pg2.config_ip4()
3661         self.pg1.resolve_arp()
3662         self.pg2.resolve_arp()
3663
3664         self.nat44_add_address(self.nat_addr)
3665         flags = self.config_flags.NAT_IS_INSIDE
3666         self.vapi.nat44_interface_add_del_feature(
3667             sw_if_index=self.pg0.sw_if_index,
3668             flags=flags, is_add=1)
3669         self.vapi.nat44_interface_add_del_feature(
3670             sw_if_index=self.pg1.sw_if_index,
3671             is_add=1)
3672         self.vapi.nat44_interface_add_del_feature(
3673             sw_if_index=self.pg2.sw_if_index,
3674             is_add=1)
3675
3676         try:
3677             # first VRF
3678             pkts = self.create_stream_in(self.pg0, self.pg1)
3679             self.pg0.add_stream(pkts)
3680             self.pg_enable_capture(self.pg_interfaces)
3681             self.pg_start()
3682             capture = self.pg1.get_capture(len(pkts))
3683             self.verify_capture_out(capture, self.nat_addr)
3684
3685             pkts = self.create_stream_out(self.pg1, self.nat_addr)
3686             self.pg1.add_stream(pkts)
3687             self.pg_enable_capture(self.pg_interfaces)
3688             self.pg_start()
3689             capture = self.pg0.get_capture(len(pkts))
3690             self.verify_capture_in(capture, self.pg0)
3691
3692             self.tcp_port_in = 60303
3693             self.udp_port_in = 60304
3694             self.icmp_id_in = 60305
3695
3696             # second VRF
3697             pkts = self.create_stream_in(self.pg0, self.pg2)
3698             self.pg0.add_stream(pkts)
3699             self.pg_enable_capture(self.pg_interfaces)
3700             self.pg_start()
3701             capture = self.pg2.get_capture(len(pkts))
3702             self.verify_capture_out(capture, self.nat_addr)
3703
3704             pkts = self.create_stream_out(self.pg2, self.nat_addr)
3705             self.pg2.add_stream(pkts)
3706             self.pg_enable_capture(self.pg_interfaces)
3707             self.pg_start()
3708             capture = self.pg0.get_capture(len(pkts))
3709             self.verify_capture_in(capture, self.pg0)
3710
3711         finally:
3712             self.nat44_add_address(self.nat_addr, is_add=0)
3713             self.pg1.unconfig_ip4()
3714             self.pg2.unconfig_ip4()
3715             self.pg1.set_table_ip4(0)
3716             self.pg2.set_table_ip4(0)
3717             self.pg1.config_ip4()
3718             self.pg2.config_ip4()
3719             self.pg1.resolve_arp()
3720             self.pg2.resolve_arp()
3721
3722     @unittest.skipUnless(running_extended_tests, "part of extended tests")
3723     def test_session_timeout(self):
3724         """ NAT44 session timeouts """
3725         self.nat44_add_address(self.nat_addr)
3726         flags = self.config_flags.NAT_IS_INSIDE
3727         self.vapi.nat44_interface_add_del_feature(
3728             sw_if_index=self.pg0.sw_if_index,
3729             flags=flags, is_add=1)
3730         self.vapi.nat44_interface_add_del_feature(
3731             sw_if_index=self.pg1.sw_if_index,
3732             is_add=1)
3733         self.vapi.nat_set_timeouts(udp=5, tcp_established=7440,
3734                                    tcp_transitory=240, icmp=60)
3735
3736         max_sessions = 1000
3737         pkts = []
3738         for i in range(0, max_sessions):
3739             src = "10.10.%u.%u" % ((i & 0xFF00) >> 8, i & 0xFF)
3740             p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
3741                  IP(src=src, dst=self.pg1.remote_ip4) /
3742                  UDP(sport=1025, dport=53))
3743             pkts.append(p)
3744         self.pg0.add_stream(pkts)
3745         self.pg_enable_capture(self.pg_interfaces)
3746         self.pg_start()
3747         self.pg1.get_capture(max_sessions)
3748
3749         sleep(6)
3750
3751         pkts = []
3752         for i in range(0, max_sessions):
3753             src = "10.10.%u.%u" % ((i & 0xFF00) >> 8, i & 0xFF)
3754             p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
3755                  IP(src=src, dst=self.pg1.remote_ip4) /
3756                  UDP(sport=1026, dport=53))
3757             pkts.append(p)
3758         self.pg0.add_stream(pkts)
3759         self.pg_enable_capture(self.pg_interfaces)
3760         self.pg_start()
3761         self.pg1.get_capture(max_sessions)
3762
3763         nsessions = 0
3764         users = self.vapi.nat44_user_dump()
3765         for user in users:
3766             nsessions = nsessions + user.nsessions
3767         self.assertLess(nsessions, 2 * max_sessions)
3768
3769     def test_mss_clamping(self):
3770         """ TCP MSS clamping """
3771         self.nat44_add_address(self.nat_addr)
3772         flags = self.config_flags.NAT_IS_INSIDE
3773         self.vapi.nat44_interface_add_del_feature(
3774             sw_if_index=self.pg0.sw_if_index,
3775             flags=flags, is_add=1)
3776         self.vapi.nat44_interface_add_del_feature(
3777             sw_if_index=self.pg1.sw_if_index,
3778             is_add=1)
3779
3780         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
3781              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3782              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
3783                  flags="S", options=[('MSS', 1400)]))
3784
3785         self.vapi.nat_set_mss_clamping(enable=1, mss_value=1000)
3786         self.pg0.add_stream(p)
3787         self.pg_enable_capture(self.pg_interfaces)
3788         self.pg_start()
3789         capture = self.pg1.get_capture(1)
3790         # Negotiated MSS value greater than configured - changed
3791         self.verify_mss_value(capture[0], 1000)
3792
3793         self.vapi.nat_set_mss_clamping(enable=0, mss_value=1500)
3794         self.pg0.add_stream(p)
3795         self.pg_enable_capture(self.pg_interfaces)
3796         self.pg_start()
3797         capture = self.pg1.get_capture(1)
3798         # MSS clamping disabled - negotiated MSS unchanged
3799         self.verify_mss_value(capture[0], 1400)
3800
3801         self.vapi.nat_set_mss_clamping(enable=1, mss_value=1500)
3802         self.pg0.add_stream(p)
3803         self.pg_enable_capture(self.pg_interfaces)
3804         self.pg_start()
3805         capture = self.pg1.get_capture(1)
3806         # Negotiated MSS value smaller than configured - unchanged
3807         self.verify_mss_value(capture[0], 1400)
3808
3809     @unittest.skipUnless(running_extended_tests, "part of extended tests")
3810     def test_ha_send(self):
3811         """ Send HA session synchronization events (active) """
3812         self.nat44_add_address(self.nat_addr)
3813         flags = self.config_flags.NAT_IS_INSIDE
3814         self.vapi.nat44_interface_add_del_feature(
3815             sw_if_index=self.pg0.sw_if_index,
3816             flags=flags, is_add=1)
3817         self.vapi.nat44_interface_add_del_feature(
3818             sw_if_index=self.pg1.sw_if_index,
3819             is_add=1)
3820         self.vapi.nat_ha_set_listener(ip_address=self.pg3.local_ip4,
3821                                       port=12345,
3822                                       path_mtu=512)
3823         self.vapi.nat_ha_set_failover(ip_address=self.pg3.remote_ip4,
3824                                       port=12346, session_refresh_interval=10)
3825         bind_layers(UDP, HANATStateSync, sport=12345)
3826
3827         # create sessions
3828         pkts = self.create_stream_in(self.pg0, self.pg1)
3829         self.pg0.add_stream(pkts)
3830         self.pg_enable_capture(self.pg_interfaces)
3831         self.pg_start()
3832         capture = self.pg1.get_capture(len(pkts))
3833         self.verify_capture_out(capture)
3834         # active send HA events
3835         self.vapi.nat_ha_flush()
3836         stats = self.statistics.get_counter('/nat44/ha/add-event-send')
3837         self.assertEqual(stats[0][0], 3)
3838         capture = self.pg3.get_capture(1)
3839         p = capture[0]
3840         self.assert_packet_checksums_valid(p)
3841         try:
3842             ip = p[IP]
3843             udp = p[UDP]
3844             hanat = p[HANATStateSync]
3845         except IndexError:
3846             self.logger.error(ppp("Invalid packet:", p))
3847             raise
3848         else:
3849             self.assertEqual(ip.src, self.pg3.local_ip4)
3850             self.assertEqual(ip.dst, self.pg3.remote_ip4)
3851             self.assertEqual(udp.sport, 12345)
3852             self.assertEqual(udp.dport, 12346)
3853             self.assertEqual(hanat.version, 1)
3854             self.assertEqual(hanat.thread_index, 0)
3855             self.assertEqual(hanat.count, 3)
3856             seq = hanat.sequence_number
3857             for event in hanat.events:
3858                 self.assertEqual(event.event_type, 1)
3859                 self.assertEqual(event.in_addr, self.pg0.remote_ip4)
3860                 self.assertEqual(event.out_addr, self.nat_addr)
3861                 self.assertEqual(event.fib_index, 0)
3862
3863         # ACK received events
3864         ack = (Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac) /
3865                IP(src=self.pg3.remote_ip4, dst=self.pg3.local_ip4) /
3866                UDP(sport=12346, dport=12345) /
3867                HANATStateSync(sequence_number=seq, flags='ACK'))
3868         self.pg3.add_stream(ack)
3869         self.pg_start()
3870         stats = self.statistics.get_counter('/nat44/ha/ack-recv')
3871         self.assertEqual(stats[0][0], 1)
3872
3873         # delete one session
3874         self.pg_enable_capture(self.pg_interfaces)
3875         self.vapi.nat44_del_session(address=self.pg0.remote_ip4,
3876                                     port=self.tcp_port_in,
3877                                     protocol=IP_PROTOS.tcp,
3878                                     flags=self.config_flags.NAT_IS_INSIDE)
3879         self.vapi.nat_ha_flush()
3880         stats = self.statistics.get_counter('/nat44/ha/del-event-send')
3881         self.assertEqual(stats[0][0], 1)
3882         capture = self.pg3.get_capture(1)
3883         p = capture[0]
3884         try:
3885             hanat = p[HANATStateSync]
3886         except IndexError:
3887             self.logger.error(ppp("Invalid packet:", p))
3888             raise
3889         else:
3890             self.assertGreater(hanat.sequence_number, seq)
3891
3892         # do not send ACK, active retry send HA event again
3893         self.pg_enable_capture(self.pg_interfaces)
3894         sleep(12)
3895         stats = self.statistics.get_counter('/nat44/ha/retry-count')
3896         self.assertEqual(stats[0][0], 3)
3897         stats = self.statistics.get_counter('/nat44/ha/missed-count')
3898         self.assertEqual(stats[0][0], 1)
3899         capture = self.pg3.get_capture(3)
3900         for packet in capture:
3901             self.assertEqual(packet, p)
3902
3903         # session counters refresh
3904         pkts = self.create_stream_out(self.pg1)
3905         self.pg1.add_stream(pkts)
3906         self.pg_enable_capture(self.pg_interfaces)
3907         self.pg_start()
3908         self.pg0.get_capture(2)
3909         self.vapi.nat_ha_flush()
3910         stats = self.statistics.get_counter('/nat44/ha/refresh-event-send')
3911         self.assertEqual(stats[0][0], 2)
3912         capture = self.pg3.get_capture(1)
3913         p = capture[0]
3914         self.assert_packet_checksums_valid(p)
3915         try:
3916             ip = p[IP]
3917             udp = p[UDP]
3918             hanat = p[HANATStateSync]
3919         except IndexError:
3920             self.logger.error(ppp("Invalid packet:", p))
3921             raise
3922         else:
3923             self.assertEqual(ip.src, self.pg3.local_ip4)
3924             self.assertEqual(ip.dst, self.pg3.remote_ip4)
3925             self.assertEqual(udp.sport, 12345)
3926             self.assertEqual(udp.dport, 12346)
3927             self.assertEqual(hanat.version, 1)
3928             self.assertEqual(hanat.count, 2)
3929             seq = hanat.sequence_number
3930             for event in hanat.events:
3931                 self.assertEqual(event.event_type, 3)
3932                 self.assertEqual(event.out_addr, self.nat_addr)
3933                 self.assertEqual(event.fib_index, 0)
3934                 self.assertEqual(event.total_pkts, 2)
3935                 self.assertGreater(event.total_bytes, 0)
3936
3937         ack = (Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac) /
3938                IP(src=self.pg3.remote_ip4, dst=self.pg3.local_ip4) /
3939                UDP(sport=12346, dport=12345) /
3940                HANATStateSync(sequence_number=seq, flags='ACK'))
3941         self.pg3.add_stream(ack)
3942         self.pg_start()
3943         stats = self.statistics.get_counter('/nat44/ha/ack-recv')
3944         self.assertEqual(stats[0][0], 2)
3945
3946     def test_ha_recv(self):
3947         """ Receive HA session synchronization events (passive) """
3948         self.nat44_add_address(self.nat_addr)
3949         flags = self.config_flags.NAT_IS_INSIDE
3950         self.vapi.nat44_interface_add_del_feature(
3951             sw_if_index=self.pg0.sw_if_index,
3952             flags=flags, is_add=1)
3953         self.vapi.nat44_interface_add_del_feature(
3954             sw_if_index=self.pg1.sw_if_index,
3955             is_add=1)
3956         self.vapi.nat_ha_set_listener(ip_address=self.pg3.local_ip4,
3957                                       port=12345,
3958                                       path_mtu=512)
3959         bind_layers(UDP, HANATStateSync, sport=12345)
3960
3961         self.tcp_port_out = random.randint(1025, 65535)
3962         self.udp_port_out = random.randint(1025, 65535)
3963
3964         # send HA session add events to failover/passive
3965         p = (Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac) /
3966              IP(src=self.pg3.remote_ip4, dst=self.pg3.local_ip4) /
3967              UDP(sport=12346, dport=12345) /
3968              HANATStateSync(sequence_number=1, events=[
3969                  Event(event_type='add', protocol='tcp',
3970                        in_addr=self.pg0.remote_ip4, out_addr=self.nat_addr,
3971                        in_port=self.tcp_port_in, out_port=self.tcp_port_out,
3972                        eh_addr=self.pg1.remote_ip4,
3973                        ehn_addr=self.pg1.remote_ip4,
3974                        eh_port=self.tcp_external_port,
3975                        ehn_port=self.tcp_external_port, fib_index=0),
3976                  Event(event_type='add', protocol='udp',
3977                        in_addr=self.pg0.remote_ip4, out_addr=self.nat_addr,
3978                        in_port=self.udp_port_in, out_port=self.udp_port_out,
3979                        eh_addr=self.pg1.remote_ip4,
3980                        ehn_addr=self.pg1.remote_ip4,
3981                        eh_port=self.udp_external_port,
3982                        ehn_port=self.udp_external_port, fib_index=0)]))
3983
3984         self.pg3.add_stream(p)
3985         self.pg_enable_capture(self.pg_interfaces)
3986         self.pg_start()
3987         # receive ACK
3988         capture = self.pg3.get_capture(1)
3989         p = capture[0]
3990         try:
3991             hanat = p[HANATStateSync]
3992         except IndexError:
3993             self.logger.error(ppp("Invalid packet:", p))
3994             raise
3995         else:
3996             self.assertEqual(hanat.sequence_number, 1)
3997             self.assertEqual(hanat.flags, 'ACK')
3998             self.assertEqual(hanat.version, 1)
3999             self.assertEqual(hanat.thread_index, 0)
4000         stats = self.statistics.get_counter('/nat44/ha/ack-send')
4001         self.assertEqual(stats[0][0], 1)
4002         stats = self.statistics.get_counter('/nat44/ha/add-event-recv')
4003         self.assertEqual(stats[0][0], 2)
4004         users = self.statistics.get_counter('/nat44/total-users')
4005         self.assertEqual(users[0][0], 1)
4006         sessions = self.statistics.get_counter('/nat44/total-sessions')
4007         self.assertEqual(sessions[0][0], 2)
4008         users = self.vapi.nat44_user_dump()
4009         self.assertEqual(len(users), 1)
4010         self.assertEqual(str(users[0].ip_address),
4011                          self.pg0.remote_ip4)
4012         # there should be 2 sessions created by HA
4013         sessions = self.vapi.nat44_user_session_dump(users[0].ip_address,
4014                                                      users[0].vrf_id)
4015         self.assertEqual(len(sessions), 2)
4016         for session in sessions:
4017             self.assertEqual(str(session.inside_ip_address),
4018                              self.pg0.remote_ip4)
4019             self.assertEqual(str(session.outside_ip_address),
4020                              self.nat_addr)
4021             self.assertIn(session.inside_port,
4022                           [self.tcp_port_in, self.udp_port_in])
4023             self.assertIn(session.outside_port,
4024                           [self.tcp_port_out, self.udp_port_out])
4025             self.assertIn(session.protocol, [IP_PROTOS.tcp, IP_PROTOS.udp])
4026
4027         # send HA session delete event to failover/passive
4028         p = (Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac) /
4029              IP(src=self.pg3.remote_ip4, dst=self.pg3.local_ip4) /
4030              UDP(sport=12346, dport=12345) /
4031              HANATStateSync(sequence_number=2, events=[
4032                  Event(event_type='del', protocol='udp',
4033                        in_addr=self.pg0.remote_ip4, out_addr=self.nat_addr,
4034                        in_port=self.udp_port_in, out_port=self.udp_port_out,
4035                        eh_addr=self.pg1.remote_ip4,
4036                        ehn_addr=self.pg1.remote_ip4,
4037                        eh_port=self.udp_external_port,
4038                        ehn_port=self.udp_external_port, fib_index=0)]))
4039
4040         self.pg3.add_stream(p)
4041         self.pg_enable_capture(self.pg_interfaces)
4042         self.pg_start()
4043         # receive ACK
4044         capture = self.pg3.get_capture(1)
4045         p = capture[0]
4046         try:
4047             hanat = p[HANATStateSync]
4048         except IndexError:
4049             self.logger.error(ppp("Invalid packet:", p))
4050             raise
4051         else:
4052             self.assertEqual(hanat.sequence_number, 2)
4053             self.assertEqual(hanat.flags, 'ACK')
4054             self.assertEqual(hanat.version, 1)
4055         users = self.vapi.nat44_user_dump()
4056         self.assertEqual(len(users), 1)
4057         self.assertEqual(str(users[0].ip_address),
4058                          self.pg0.remote_ip4)
4059         # now we should have only 1 session, 1 deleted by HA
4060         sessions = self.vapi.nat44_user_session_dump(users[0].ip_address,
4061                                                      users[0].vrf_id)
4062         self.assertEqual(len(sessions), 1)
4063         stats = self.statistics.get_counter('/nat44/ha/del-event-recv')
4064         self.assertEqual(stats[0][0], 1)
4065
4066         stats = self.statistics.get_err_counter('/err/nat-ha/pkts-processed')
4067         self.assertEqual(stats, 2)
4068
4069         # send HA session refresh event to failover/passive
4070         p = (Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac) /
4071              IP(src=self.pg3.remote_ip4, dst=self.pg3.local_ip4) /
4072              UDP(sport=12346, dport=12345) /
4073              HANATStateSync(sequence_number=3, events=[
4074                  Event(event_type='refresh', protocol='tcp',
4075                        in_addr=self.pg0.remote_ip4, out_addr=self.nat_addr,
4076                        in_port=self.tcp_port_in, out_port=self.tcp_port_out,
4077                        eh_addr=self.pg1.remote_ip4,
4078                        ehn_addr=self.pg1.remote_ip4,
4079                        eh_port=self.tcp_external_port,
4080                        ehn_port=self.tcp_external_port, fib_index=0,
4081                        total_bytes=1024, total_pkts=2)]))
4082         self.pg3.add_stream(p)
4083         self.pg_enable_capture(self.pg_interfaces)
4084         self.pg_start()
4085         # receive ACK
4086         capture = self.pg3.get_capture(1)
4087         p = capture[0]
4088         try:
4089             hanat = p[HANATStateSync]
4090         except IndexError:
4091             self.logger.error(ppp("Invalid packet:", p))
4092             raise
4093         else:
4094             self.assertEqual(hanat.sequence_number, 3)
4095             self.assertEqual(hanat.flags, 'ACK')
4096             self.assertEqual(hanat.version, 1)
4097         users = self.vapi.nat44_user_dump()
4098         self.assertEqual(len(users), 1)
4099         self.assertEqual(str(users[0].ip_address),
4100                          self.pg0.remote_ip4)
4101         sessions = self.vapi.nat44_user_session_dump(users[0].ip_address,
4102                                                      users[0].vrf_id)
4103         self.assertEqual(len(sessions), 1)
4104         session = sessions[0]
4105         self.assertEqual(session.total_bytes, 1024)
4106         self.assertEqual(session.total_pkts, 2)
4107         stats = self.statistics.get_counter('/nat44/ha/refresh-event-recv')
4108         self.assertEqual(stats[0][0], 1)
4109
4110         stats = self.statistics.get_err_counter('/err/nat-ha/pkts-processed')
4111         self.assertEqual(stats, 3)
4112
4113         # send packet to test session created by HA
4114         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
4115              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
4116              TCP(sport=self.tcp_external_port, dport=self.tcp_port_out))
4117         self.pg1.add_stream(p)
4118         self.pg_enable_capture(self.pg_interfaces)
4119         self.pg_start()
4120         capture = self.pg0.get_capture(1)
4121         p = capture[0]
4122         try:
4123             ip = p[IP]
4124             tcp = p[TCP]
4125         except IndexError:
4126             self.logger.error(ppp("Invalid packet:", p))
4127             raise
4128         else:
4129             self.assertEqual(ip.src, self.pg1.remote_ip4)
4130             self.assertEqual(ip.dst, self.pg0.remote_ip4)
4131             self.assertEqual(tcp.sport, self.tcp_external_port)
4132             self.assertEqual(tcp.dport, self.tcp_port_in)
4133
4134     def tearDown(self):
4135         super(TestNAT44, self).tearDown()
4136         self.clear_nat44()
4137         self.vapi.cli("clear logging")
4138
4139     def show_commands_at_teardown(self):
4140         self.logger.info(self.vapi.cli("show nat44 addresses"))
4141         self.logger.info(self.vapi.cli("show nat44 interfaces"))
4142         self.logger.info(self.vapi.cli("show nat44 static mappings"))
4143         self.logger.info(self.vapi.cli("show nat44 interface address"))
4144         self.logger.info(self.vapi.cli("show nat44 sessions detail"))
4145         self.logger.info(self.vapi.cli("show nat44 hash tables detail"))
4146         self.logger.info(self.vapi.cli("show nat timeouts"))
4147         self.logger.info(
4148             self.vapi.cli("show nat addr-port-assignment-alg"))
4149         self.logger.info(self.vapi.cli("show nat ha"))
4150
4151
4152 class TestNAT44EndpointDependent(MethodHolder):
4153     """ Endpoint-Dependent mapping and filtering test cases """
4154
4155     @classmethod
4156     def setUpConstants(cls):
4157         super(TestNAT44EndpointDependent, cls).setUpConstants()
4158         cls.vpp_cmdline.extend(["nat", "{", "endpoint-dependent", "}"])
4159
4160     @classmethod
4161     def setUpClass(cls):
4162         super(TestNAT44EndpointDependent, cls).setUpClass()
4163         cls.vapi.cli("set log class nat level debug")
4164
4165         cls.tcp_port_in = 6303
4166         cls.tcp_port_out = 6303
4167         cls.udp_port_in = 6304
4168         cls.udp_port_out = 6304
4169         cls.icmp_id_in = 6305
4170         cls.icmp_id_out = 6305
4171         cls.nat_addr = '10.0.0.3'
4172         cls.ipfix_src_port = 4739
4173         cls.ipfix_domain_id = 1
4174         cls.tcp_external_port = 80
4175
4176         cls.create_pg_interfaces(range(9))
4177         cls.interfaces = list(cls.pg_interfaces[0:3])
4178
4179         for i in cls.interfaces:
4180             i.admin_up()
4181             i.config_ip4()
4182             i.resolve_arp()
4183
4184         cls.pg0.generate_remote_hosts(3)
4185         cls.pg0.configure_ipv4_neighbors()
4186
4187         cls.pg3.admin_up()
4188
4189         cls.pg4.generate_remote_hosts(2)
4190         cls.pg4.config_ip4()
4191         cls.vapi.sw_interface_add_del_address(
4192             sw_if_index=cls.pg4.sw_if_index,
4193             prefix="10.0.0.1/24")
4194
4195         cls.pg4.admin_up()
4196         cls.pg4.resolve_arp()
4197         cls.pg4._remote_hosts[1]._ip4 = cls.pg4._remote_hosts[0]._ip4
4198         cls.pg4.resolve_arp()
4199
4200         zero_ip4 = socket.inet_pton(socket.AF_INET, "0.0.0.0")
4201         cls.vapi.ip_table_add_del(is_add=1, table={'table_id': 1})
4202
4203         cls.pg5._local_ip4 = "10.1.1.1"
4204         cls.pg5._remote_hosts[0]._ip4 = "10.1.1.2"
4205         cls.pg5.set_table_ip4(1)
4206         cls.pg5.config_ip4()
4207         cls.pg5.admin_up()
4208         r1 = VppIpRoute(cls, cls.pg5.remote_ip4, 32,
4209                         [VppRoutePath("0.0.0.0",
4210                                       cls.pg5.sw_if_index)],
4211                         table_id=1,
4212                         register=False)
4213         r1.add_vpp_config()
4214
4215         cls.pg6._local_ip4 = "10.1.2.1"
4216         cls.pg6._remote_hosts[0]._ip4 = "10.1.2.2"
4217         cls.pg6.set_table_ip4(1)
4218         cls.pg6.config_ip4()
4219         cls.pg6.admin_up()
4220
4221         r2 = VppIpRoute(cls, cls.pg6.remote_ip4, 32,
4222                         [VppRoutePath("0.0.0.0",
4223                                       cls.pg6.sw_if_index)],
4224                         table_id=1,
4225                         register=False)
4226         r3 = VppIpRoute(cls, cls.pg6.remote_ip4, 16,
4227                         [VppRoutePath("0.0.0.0",
4228                                       0xffffffff,
4229                                       nh_table_id=1)],
4230                         table_id=0,
4231                         register=False)
4232         r4 = VppIpRoute(cls, "0.0.0.0", 0,
4233                         [VppRoutePath("0.0.0.0", 0xffffffff,
4234                                       nh_table_id=0)],
4235                         table_id=1,
4236                         register=False)
4237         r5 = VppIpRoute(cls, "0.0.0.0", 0,
4238                         [VppRoutePath(cls.pg1.local_ip4,
4239                                       cls.pg1.sw_if_index)],
4240                         register=False)
4241         r2.add_vpp_config()
4242         r3.add_vpp_config()
4243         r4.add_vpp_config()
4244         r5.add_vpp_config()
4245
4246         cls.pg5.resolve_arp()
4247         cls.pg6.resolve_arp()
4248
4249         cls.pg7.admin_up()
4250         cls.pg7.config_ip4()
4251         cls.pg7.resolve_arp()
4252         cls.pg7.generate_remote_hosts(3)
4253         cls.pg7.configure_ipv4_neighbors()
4254
4255         cls.pg8.admin_up()
4256         cls.pg8.config_ip4()
4257         cls.pg8.resolve_arp()
4258
4259     def setUp(self):
4260         super(TestNAT44EndpointDependent, self).setUp()
4261         self.vapi.nat_set_timeouts(
4262             udp=300, tcp_established=7440, tcp_transitory=240, icmp=60)
4263
4264     @classmethod
4265     def tearDownClass(cls):
4266         super(TestNAT44EndpointDependent, cls).tearDownClass()
4267
4268     def test_frag_in_order(self):
4269         """ NAT44 translate fragments arriving in order """
4270         self.nat44_add_address(self.nat_addr)
4271         flags = self.config_flags.NAT_IS_INSIDE
4272         self.vapi.nat44_interface_add_del_feature(
4273             sw_if_index=self.pg0.sw_if_index,
4274             flags=flags, is_add=1)
4275         self.vapi.nat44_interface_add_del_feature(
4276             sw_if_index=self.pg1.sw_if_index,
4277             is_add=1)
4278         self.frag_in_order(proto=IP_PROTOS.tcp)
4279         self.frag_in_order(proto=IP_PROTOS.udp)
4280         self.frag_in_order(proto=IP_PROTOS.icmp)
4281
4282     def test_frag_in_order_dont_translate(self):
4283         """ NAT44 don't translate fragments arriving in order """
4284         flags = self.config_flags.NAT_IS_INSIDE
4285         self.vapi.nat44_interface_add_del_feature(
4286             sw_if_index=self.pg0.sw_if_index,
4287             flags=flags, is_add=1)
4288         self.vapi.nat44_interface_add_del_feature(
4289             sw_if_index=self.pg1.sw_if_index,
4290             is_add=1)
4291         self.vapi.nat44_forwarding_enable_disable(enable=True)
4292         self.frag_in_order(proto=IP_PROTOS.tcp, dont_translate=True)
4293
4294     def test_frag_out_of_order(self):
4295         """ NAT44 translate fragments arriving out of order """
4296         self.nat44_add_address(self.nat_addr)
4297         flags = self.config_flags.NAT_IS_INSIDE
4298         self.vapi.nat44_interface_add_del_feature(
4299             sw_if_index=self.pg0.sw_if_index,
4300             flags=flags, is_add=1)
4301         self.vapi.nat44_interface_add_del_feature(
4302             sw_if_index=self.pg1.sw_if_index,
4303             is_add=1)
4304         self.frag_out_of_order(proto=IP_PROTOS.tcp)
4305         self.frag_out_of_order(proto=IP_PROTOS.udp)
4306         self.frag_out_of_order(proto=IP_PROTOS.icmp)
4307
4308     def test_frag_out_of_order_dont_translate(self):
4309         """ NAT44 don't translate fragments arriving out of order """
4310         flags = self.config_flags.NAT_IS_INSIDE
4311         self.vapi.nat44_interface_add_del_feature(
4312             sw_if_index=self.pg0.sw_if_index,
4313             flags=flags, is_add=1)
4314         self.vapi.nat44_interface_add_del_feature(
4315             sw_if_index=self.pg1.sw_if_index,
4316             is_add=1)
4317         self.vapi.nat44_forwarding_enable_disable(enable=True)
4318         self.frag_out_of_order(proto=IP_PROTOS.tcp, dont_translate=True)
4319
4320     def test_frag_in_order_in_plus_out(self):
4321         """ in+out interface fragments in order """
4322         flags = self.config_flags.NAT_IS_INSIDE
4323         self.vapi.nat44_interface_add_del_feature(
4324             sw_if_index=self.pg0.sw_if_index,
4325             is_add=1)
4326         self.vapi.nat44_interface_add_del_feature(
4327             sw_if_index=self.pg0.sw_if_index,
4328             flags=flags, is_add=1)
4329         self.vapi.nat44_interface_add_del_feature(
4330             sw_if_index=self.pg1.sw_if_index,
4331             is_add=1)
4332         self.vapi.nat44_interface_add_del_feature(
4333             sw_if_index=self.pg1.sw_if_index,
4334             flags=flags, is_add=1)
4335
4336         self.server = self.pg1.remote_hosts[0]
4337
4338         self.server_in_addr = self.server.ip4
4339         self.server_out_addr = '11.11.11.11'
4340         self.server_in_port = random.randint(1025, 65535)
4341         self.server_out_port = random.randint(1025, 65535)
4342
4343         self.nat44_add_address(self.server_out_addr)
4344
4345         # add static mappings for server
4346         self.nat44_add_static_mapping(self.server_in_addr,
4347                                       self.server_out_addr,
4348                                       self.server_in_port,
4349                                       self.server_out_port,
4350                                       proto=IP_PROTOS.tcp)
4351         self.nat44_add_static_mapping(self.server_in_addr,
4352                                       self.server_out_addr,
4353                                       self.server_in_port,
4354                                       self.server_out_port,
4355                                       proto=IP_PROTOS.udp)
4356         self.nat44_add_static_mapping(self.server_in_addr,
4357                                       self.server_out_addr,
4358                                       proto=IP_PROTOS.icmp)
4359
4360         self.frag_in_order_in_plus_out(proto=IP_PROTOS.tcp)
4361         self.frag_in_order_in_plus_out(proto=IP_PROTOS.udp)
4362         self.frag_in_order_in_plus_out(proto=IP_PROTOS.icmp)
4363
4364     def test_frag_out_of_order_in_plus_out(self):
4365         """ in+out interface fragments out of order """
4366         flags = self.config_flags.NAT_IS_INSIDE
4367         self.vapi.nat44_interface_add_del_feature(
4368             sw_if_index=self.pg0.sw_if_index,
4369             is_add=1)
4370         self.vapi.nat44_interface_add_del_feature(
4371             sw_if_index=self.pg0.sw_if_index,
4372             flags=flags, is_add=1)
4373         self.vapi.nat44_interface_add_del_feature(
4374             sw_if_index=self.pg1.sw_if_index,
4375             is_add=1)
4376         self.vapi.nat44_interface_add_del_feature(
4377             sw_if_index=self.pg1.sw_if_index,
4378             flags=flags, is_add=1)
4379
4380         self.server = self.pg1.remote_hosts[0]
4381
4382         self.server_in_addr = self.server.ip4
4383         self.server_out_addr = '11.11.11.11'
4384         self.server_in_port = random.randint(1025, 65535)
4385         self.server_out_port = random.randint(1025, 65535)
4386
4387         self.nat44_add_address(self.server_out_addr)
4388
4389         # add static mappings for server
4390         self.nat44_add_static_mapping(self.server_in_addr,
4391                                       self.server_out_addr,
4392                                       self.server_in_port,
4393                                       self.server_out_port,
4394                                       proto=IP_PROTOS.tcp)
4395         self.nat44_add_static_mapping(self.server_in_addr,
4396                                       self.server_out_addr,
4397                                       self.server_in_port,
4398                                       self.server_out_port,
4399                                       proto=IP_PROTOS.udp)
4400         self.nat44_add_static_mapping(self.server_in_addr,
4401                                       self.server_out_addr,
4402                                       proto=IP_PROTOS.icmp)
4403
4404         self.frag_out_of_order_in_plus_out(proto=IP_PROTOS.tcp)
4405         self.frag_out_of_order_in_plus_out(proto=IP_PROTOS.udp)
4406         self.frag_out_of_order_in_plus_out(proto=IP_PROTOS.icmp)
4407
4408     def test_reass_hairpinning(self):
4409         """ NAT44 fragments hairpinning """
4410         self.server = self.pg0.remote_hosts[1]
4411         self.host_in_port = random.randint(1025, 65535)
4412         self.server_in_port = random.randint(1025, 65535)
4413         self.server_out_port = random.randint(1025, 65535)
4414
4415         self.nat44_add_address(self.nat_addr)
4416         flags = self.config_flags.NAT_IS_INSIDE
4417         self.vapi.nat44_interface_add_del_feature(
4418             sw_if_index=self.pg0.sw_if_index,
4419             flags=flags, is_add=1)
4420         self.vapi.nat44_interface_add_del_feature(
4421             sw_if_index=self.pg1.sw_if_index,
4422             is_add=1)
4423         # add static mapping for server
4424         self.nat44_add_static_mapping(self.server.ip4, self.nat_addr,
4425                                       self.server_in_port,
4426                                       self.server_out_port,
4427                                       proto=IP_PROTOS.tcp)
4428         self.nat44_add_static_mapping(self.server.ip4, self.nat_addr,
4429                                       self.server_in_port,
4430                                       self.server_out_port,
4431                                       proto=IP_PROTOS.udp)
4432         self.nat44_add_static_mapping(self.server.ip4, self.nat_addr)
4433
4434         self.reass_hairpinning(proto=IP_PROTOS.tcp)
4435         self.reass_hairpinning(proto=IP_PROTOS.udp)
4436         self.reass_hairpinning(proto=IP_PROTOS.icmp)
4437
4438     def test_dynamic(self):
4439         """ NAT44 dynamic translation test """
4440
4441         self.nat44_add_address(self.nat_addr)
4442         flags = self.config_flags.NAT_IS_INSIDE
4443         self.vapi.nat44_interface_add_del_feature(
4444             sw_if_index=self.pg0.sw_if_index,
4445             flags=flags, is_add=1)
4446         self.vapi.nat44_interface_add_del_feature(
4447             sw_if_index=self.pg1.sw_if_index,
4448             is_add=1)
4449
4450         nat_config = self.vapi.nat_show_config()
4451         self.assertEqual(1, nat_config.endpoint_dependent)
4452
4453         # in2out
4454         tcpn = self.statistics.get_err_counter(
4455             '/err/nat44-ed-in2out-slowpath/TCP packets')
4456         udpn = self.statistics.get_err_counter(
4457             '/err/nat44-ed-in2out-slowpath/UDP packets')
4458         icmpn = self.statistics.get_err_counter(
4459             '/err/nat44-ed-in2out-slowpath/ICMP packets')
4460         totaln = self.statistics.get_err_counter(
4461             '/err/nat44-ed-in2out-slowpath/good in2out packets processed')
4462
4463         pkts = self.create_stream_in(self.pg0, self.pg1)
4464         self.pg0.add_stream(pkts)
4465         self.pg_enable_capture(self.pg_interfaces)
4466         self.pg_start()
4467         capture = self.pg1.get_capture(len(pkts))
4468         self.verify_capture_out(capture)
4469
4470         err = self.statistics.get_err_counter(
4471             '/err/nat44-ed-in2out-slowpath/TCP packets')
4472         self.assertEqual(err - tcpn, 2)
4473         err = self.statistics.get_err_counter(
4474             '/err/nat44-ed-in2out-slowpath/UDP packets')
4475         self.assertEqual(err - udpn, 1)
4476         err = self.statistics.get_err_counter(
4477             '/err/nat44-ed-in2out-slowpath/ICMP packets')
4478         self.assertEqual(err - icmpn, 1)
4479         err = self.statistics.get_err_counter(
4480             '/err/nat44-ed-in2out-slowpath/good in2out packets processed')
4481         self.assertEqual(err - totaln, 4)
4482
4483         # out2in
4484         tcpn = self.statistics.get_err_counter(
4485             '/err/nat44-ed-out2in/TCP packets')
4486         udpn = self.statistics.get_err_counter(
4487             '/err/nat44-ed-out2in/UDP packets')
4488         icmpn = self.statistics.get_err_counter(
4489             '/err/nat44-ed-out2in-slowpath/ICMP packets')
4490         totaln = self.statistics.get_err_counter(
4491             '/err/nat44-ed-out2in/good out2in packets processed')
4492
4493         pkts = self.create_stream_out(self.pg1)
4494         self.pg1.add_stream(pkts)
4495         self.pg_enable_capture(self.pg_interfaces)
4496         self.pg_start()
4497         capture = self.pg0.get_capture(len(pkts))
4498         self.verify_capture_in(capture, self.pg0)
4499
4500         err = self.statistics.get_err_counter(
4501             '/err/nat44-ed-out2in/TCP packets')
4502         self.assertEqual(err - tcpn, 2)
4503         err = self.statistics.get_err_counter(
4504             '/err/nat44-ed-out2in/UDP packets')
4505         self.assertEqual(err - udpn, 1)
4506         err = self.statistics.get_err_counter(
4507             '/err/nat44-ed-out2in-slowpath/ICMP packets')
4508         self.assertEqual(err - icmpn, 1)
4509         err = self.statistics.get_err_counter(
4510             '/err/nat44-ed-out2in/good out2in packets processed')
4511         self.assertEqual(err - totaln, 3)
4512
4513         sessions = self.statistics.get_counter('/nat44/total-sessions')
4514         self.assertEqual(sessions[0][0], 3)
4515
4516     def test_dynamic_output_feature_vrf(self):
4517         """ NAT44 dynamic translation test: output-feature, VRF"""
4518
4519         # other then default (0)
4520         new_vrf_id = 22
4521
4522         self.nat44_add_address(self.nat_addr)
4523         flags = self.config_flags.NAT_IS_INSIDE
4524         self.vapi.nat44_interface_add_del_output_feature(
4525             sw_if_index=self.pg7.sw_if_index,
4526             flags=flags, is_add=1)
4527         self.vapi.nat44_interface_add_del_output_feature(
4528             sw_if_index=self.pg8.sw_if_index,
4529             is_add=1)
4530
4531         try:
4532             self.vapi.ip_table_add_del(is_add=1,
4533                                        table={'table_id': new_vrf_id})
4534
4535             self.pg7.unconfig_ip4()
4536             self.pg7.set_table_ip4(new_vrf_id)
4537             self.pg7.config_ip4()
4538             self.pg7.resolve_arp()
4539
4540             self.pg8.unconfig_ip4()
4541             self.pg8.set_table_ip4(new_vrf_id)
4542             self.pg8.config_ip4()
4543             self.pg8.resolve_arp()
4544
4545             nat_config = self.vapi.nat_show_config()
4546             self.assertEqual(1, nat_config.endpoint_dependent)
4547
4548             # in2out
4549             tcpn = self.statistics.get_err_counter(
4550                 '/err/nat44-ed-in2out-slowpath/TCP packets')
4551             udpn = self.statistics.get_err_counter(
4552                 '/err/nat44-ed-in2out-slowpath/UDP packets')
4553             icmpn = self.statistics.get_err_counter(
4554                 '/err/nat44-ed-in2out-slowpath/ICMP packets')
4555             totaln = self.statistics.get_err_counter(
4556                 '/err/nat44-ed-in2out-slowpath/good in2out packets processed')
4557
4558             pkts = self.create_stream_in(self.pg7, self.pg8)
4559             self.pg7.add_stream(pkts)
4560             self.pg_enable_capture(self.pg_interfaces)
4561             self.pg_start()
4562             capture = self.pg8.get_capture(len(pkts))
4563             self.verify_capture_out(capture)
4564
4565             err = self.statistics.get_err_counter(
4566                 '/err/nat44-ed-in2out-slowpath/TCP packets')
4567             self.assertEqual(err - tcpn, 2)
4568             err = self.statistics.get_err_counter(
4569                 '/err/nat44-ed-in2out-slowpath/UDP packets')
4570             self.assertEqual(err - udpn, 1)
4571             err = self.statistics.get_err_counter(
4572                 '/err/nat44-ed-in2out-slowpath/ICMP packets')
4573             self.assertEqual(err - icmpn, 1)
4574             err = self.statistics.get_err_counter(
4575                 '/err/nat44-ed-in2out-slowpath/good in2out packets processed')
4576             self.assertEqual(err - totaln, 4)
4577
4578             # out2in
4579             tcpn = self.statistics.get_err_counter(
4580                 '/err/nat44-ed-out2in/TCP packets')
4581             udpn = self.statistics.get_err_counter(
4582                 '/err/nat44-ed-out2in/UDP packets')
4583             icmpn = self.statistics.get_err_counter(
4584                 '/err/nat44-ed-out2in-slowpath/ICMP packets')
4585             totaln = self.statistics.get_err_counter(
4586                 '/err/nat44-ed-out2in/good out2in packets processed')
4587
4588             pkts = self.create_stream_out(self.pg8)
4589             self.pg8.add_stream(pkts)
4590             self.pg_enable_capture(self.pg_interfaces)
4591             self.pg_start()
4592             capture = self.pg7.get_capture(len(pkts))
4593             self.verify_capture_in(capture, self.pg7)
4594
4595             err = self.statistics.get_err_counter(
4596                 '/err/nat44-ed-out2in/TCP packets')
4597             self.assertEqual(err - tcpn, 2)
4598             err = self.statistics.get_err_counter(
4599                 '/err/nat44-ed-out2in/UDP packets')
4600             self.assertEqual(err - udpn, 1)
4601             err = self.statistics.get_err_counter(
4602                 '/err/nat44-ed-out2in-slowpath/ICMP packets')
4603             self.assertEqual(err - icmpn, 1)
4604             err = self.statistics.get_err_counter(
4605                 '/err/nat44-ed-out2in/good out2in packets processed')
4606             self.assertEqual(err - totaln, 3)
4607
4608             sessions = self.statistics.get_counter('/nat44/total-sessions')
4609             self.assertEqual(sessions[0][0], 3)
4610
4611         finally:
4612             self.pg7.unconfig_ip4()
4613             self.pg7.set_table_ip4(1)
4614             self.pg7.config_ip4()
4615             self.pg7.resolve_arp()
4616
4617             self.pg8.unconfig_ip4()
4618             self.pg8.set_table_ip4(1)
4619             self.pg8.config_ip4()
4620             self.pg8.resolve_arp()
4621
4622             self.vapi.ip_table_add_del(is_add=0,
4623                                        table={'table_id': new_vrf_id})
4624
4625     def test_forwarding(self):
4626         """ NAT44 forwarding test """
4627
4628         flags = self.config_flags.NAT_IS_INSIDE
4629         self.vapi.nat44_interface_add_del_feature(
4630             sw_if_index=self.pg0.sw_if_index,
4631             flags=flags, is_add=1)
4632         self.vapi.nat44_interface_add_del_feature(
4633             sw_if_index=self.pg1.sw_if_index,
4634             is_add=1)
4635         self.vapi.nat44_forwarding_enable_disable(enable=1)
4636
4637         real_ip = self.pg0.remote_ip4
4638         alias_ip = self.nat_addr
4639         flags = self.config_flags.NAT_IS_ADDR_ONLY
4640         self.vapi.nat44_add_del_static_mapping(is_add=1,
4641                                                local_ip_address=real_ip,
4642                                                external_ip_address=alias_ip,
4643                                                external_sw_if_index=0xFFFFFFFF,
4644                                                flags=flags)
4645
4646         try:
4647             # in2out - static mapping match
4648
4649             pkts = self.create_stream_out(self.pg1)
4650             self.pg1.add_stream(pkts)
4651             self.pg_enable_capture(self.pg_interfaces)
4652             self.pg_start()
4653             capture = self.pg0.get_capture(len(pkts))
4654             self.verify_capture_in(capture, self.pg0)
4655
4656             pkts = self.create_stream_in(self.pg0, self.pg1)
4657             self.pg0.add_stream(pkts)
4658             self.pg_enable_capture(self.pg_interfaces)
4659             self.pg_start()
4660             capture = self.pg1.get_capture(len(pkts))
4661             self.verify_capture_out(capture, same_port=True)
4662
4663             # in2out - no static mapping match
4664
4665             host0 = self.pg0.remote_hosts[0]
4666             self.pg0.remote_hosts[0] = self.pg0.remote_hosts[1]
4667             try:
4668                 pkts = self.create_stream_out(self.pg1,
4669                                               dst_ip=self.pg0.remote_ip4,
4670                                               use_inside_ports=True)
4671                 self.pg1.add_stream(pkts)
4672                 self.pg_enable_capture(self.pg_interfaces)
4673                 self.pg_start()
4674                 capture = self.pg0.get_capture(len(pkts))
4675                 self.verify_capture_in(capture, self.pg0)
4676
4677                 pkts = self.create_stream_in(self.pg0, self.pg1)
4678                 self.pg0.add_stream(pkts)
4679                 self.pg_enable_capture(self.pg_interfaces)
4680                 self.pg_start()
4681                 capture = self.pg1.get_capture(len(pkts))
4682                 self.verify_capture_out(capture, nat_ip=self.pg0.remote_ip4,
4683                                         same_port=True)
4684             finally:
4685                 self.pg0.remote_hosts[0] = host0
4686
4687             user = self.pg0.remote_hosts[1]
4688             sessions = self.vapi.nat44_user_session_dump(user.ip4, 0)
4689             self.assertEqual(len(sessions), 3)
4690             self.assertTrue(sessions[0].flags &
4691                             self.config_flags.NAT_IS_EXT_HOST_VALID)
4692             self.vapi.nat44_del_session(
4693                 address=sessions[0].inside_ip_address,
4694                 port=sessions[0].inside_port,
4695                 protocol=sessions[0].protocol,
4696                 flags=(self.config_flags.NAT_IS_INSIDE |
4697                        self.config_flags.NAT_IS_EXT_HOST_VALID),
4698                 ext_host_address=sessions[0].ext_host_address,
4699                 ext_host_port=sessions[0].ext_host_port)
4700             sessions = self.vapi.nat44_user_session_dump(user.ip4, 0)
4701             self.assertEqual(len(sessions), 2)
4702
4703         finally:
4704             self.vapi.nat44_forwarding_enable_disable(enable=0)
4705             flags = self.config_flags.NAT_IS_ADDR_ONLY
4706             self.vapi.nat44_add_del_static_mapping(
4707                 is_add=0,
4708                 local_ip_address=real_ip,
4709                 external_ip_address=alias_ip,
4710                 external_sw_if_index=0xFFFFFFFF,
4711                 flags=flags)
4712
4713     def test_static_lb(self):
4714         """ NAT44 local service load balancing """
4715         external_addr_n = self.nat_addr
4716         external_port = 80
4717         local_port = 8080
4718         server1 = self.pg0.remote_hosts[0]
4719         server2 = self.pg0.remote_hosts[1]
4720
4721         locals = [{'addr': server1.ip4,
4722                    'port': local_port,
4723                    'probability': 70,
4724                    'vrf_id': 0},
4725                   {'addr': server2.ip4,
4726                    'port': local_port,
4727                    'probability': 30,
4728                    'vrf_id': 0}]
4729
4730         self.nat44_add_address(self.nat_addr)
4731         self.vapi.nat44_add_del_lb_static_mapping(
4732             is_add=1,
4733             external_addr=external_addr_n,
4734             external_port=external_port,
4735             protocol=IP_PROTOS.tcp,
4736             local_num=len(locals),
4737             locals=locals)
4738         flags = self.config_flags.NAT_IS_INSIDE
4739         self.vapi.nat44_interface_add_del_feature(
4740             sw_if_index=self.pg0.sw_if_index,
4741             flags=flags, is_add=1)
4742         self.vapi.nat44_interface_add_del_feature(
4743             sw_if_index=self.pg1.sw_if_index,
4744             is_add=1)
4745
4746         # from client to service
4747         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
4748              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
4749              TCP(sport=12345, dport=external_port))
4750         self.pg1.add_stream(p)
4751         self.pg_enable_capture(self.pg_interfaces)
4752         self.pg_start()
4753         capture = self.pg0.get_capture(1)
4754         p = capture[0]
4755         server = None
4756         try:
4757             ip = p[IP]
4758             tcp = p[TCP]
4759             self.assertIn(ip.dst, [server1.ip4, server2.ip4])
4760             if ip.dst == server1.ip4:
4761                 server = server1
4762             else:
4763                 server = server2
4764             self.assertEqual(tcp.dport, local_port)
4765             self.assert_packet_checksums_valid(p)
4766         except:
4767             self.logger.error(ppp("Unexpected or invalid packet:", p))
4768             raise
4769
4770         # from service back to client
4771         p = (Ether(src=server.mac, dst=self.pg0.local_mac) /
4772              IP(src=server.ip4, dst=self.pg1.remote_ip4) /
4773              TCP(sport=local_port, dport=12345))
4774         self.pg0.add_stream(p)
4775         self.pg_enable_capture(self.pg_interfaces)
4776         self.pg_start()
4777         capture = self.pg1.get_capture(1)
4778         p = capture[0]
4779         try:
4780             ip = p[IP]
4781             tcp = p[TCP]
4782             self.assertEqual(ip.src, self.nat_addr)
4783             self.assertEqual(tcp.sport, external_port)
4784             self.assert_packet_checksums_valid(p)
4785         except:
4786             self.logger.error(ppp("Unexpected or invalid packet:", p))
4787             raise
4788
4789         sessions = self.vapi.nat44_user_session_dump(server.ip4, 0)
4790         self.assertEqual(len(sessions), 1)
4791         self.assertTrue(sessions[0].flags &
4792                         self.config_flags.NAT_IS_EXT_HOST_VALID)
4793         self.vapi.nat44_del_session(
4794             address=sessions[0].inside_ip_address,
4795             port=sessions[0].inside_port,
4796             protocol=sessions[0].protocol,
4797             flags=(self.config_flags.NAT_IS_INSIDE |
4798                    self.config_flags.NAT_IS_EXT_HOST_VALID),
4799             ext_host_address=sessions[0].ext_host_address,
4800             ext_host_port=sessions[0].ext_host_port)
4801         sessions = self.vapi.nat44_user_session_dump(server.ip4, 0)
4802         self.assertEqual(len(sessions), 0)
4803
4804     @unittest.skipUnless(running_extended_tests, "part of extended tests")
4805     def test_static_lb_multi_clients(self):
4806         """ NAT44 local service load balancing - multiple clients"""
4807
4808         external_addr = self.nat_addr
4809         external_port = 80
4810         local_port = 8080
4811         server1 = self.pg0.remote_hosts[0]
4812         server2 = self.pg0.remote_hosts[1]
4813         server3 = self.pg0.remote_hosts[2]
4814
4815         locals = [{'addr': server1.ip4,
4816                    'port': local_port,
4817                    'probability': 90,
4818                    'vrf_id': 0},
4819                   {'addr': server2.ip4,
4820                    'port': local_port,
4821                    'probability': 10,
4822                    'vrf_id': 0}]
4823
4824         self.nat44_add_address(self.nat_addr)
4825         self.vapi.nat44_add_del_lb_static_mapping(is_add=1,
4826                                                   external_addr=external_addr,
4827                                                   external_port=external_port,
4828                                                   protocol=IP_PROTOS.tcp,
4829                                                   local_num=len(locals),
4830                                                   locals=locals)
4831         flags = self.config_flags.NAT_IS_INSIDE
4832         self.vapi.nat44_interface_add_del_feature(
4833             sw_if_index=self.pg0.sw_if_index,
4834             flags=flags, is_add=1)
4835         self.vapi.nat44_interface_add_del_feature(
4836             sw_if_index=self.pg1.sw_if_index,
4837             is_add=1)
4838
4839         server1_n = 0
4840         server2_n = 0
4841         clients = ip4_range(self.pg1.remote_ip4, 10, 50)
4842         pkts = []
4843         for client in clients:
4844             p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
4845                  IP(src=client, dst=self.nat_addr) /
4846                  TCP(sport=12345, dport=external_port))
4847             pkts.append(p)
4848         self.pg1.add_stream(pkts)
4849         self.pg_enable_capture(self.pg_interfaces)
4850         self.pg_start()
4851         capture = self.pg0.get_capture(len(pkts))
4852         for p in capture:
4853             if p[IP].dst == server1.ip4:
4854                 server1_n += 1
4855             else:
4856                 server2_n += 1
4857         self.assertGreater(server1_n, server2_n)
4858
4859         local = {
4860             'addr': server3.ip4,
4861             'port': local_port,
4862             'probability': 20,
4863             'vrf_id': 0
4864         }
4865
4866         # add new back-end
4867         self.vapi.nat44_lb_static_mapping_add_del_local(
4868             is_add=1,
4869             external_addr=external_addr,
4870             external_port=external_port,
4871             local=local,
4872             protocol=IP_PROTOS.tcp)
4873         server1_n = 0
4874         server2_n = 0
4875         server3_n = 0
4876         clients = ip4_range(self.pg1.remote_ip4, 60, 110)
4877         pkts = []
4878         for client in clients:
4879             p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
4880                  IP(src=client, dst=self.nat_addr) /
4881                  TCP(sport=12346, dport=external_port))
4882             pkts.append(p)
4883         self.assertGreater(len(pkts), 0)
4884         self.pg1.add_stream(pkts)
4885         self.pg_enable_capture(self.pg_interfaces)
4886         self.pg_start()
4887         capture = self.pg0.get_capture(len(pkts))
4888         for p in capture:
4889             if p[IP].dst == server1.ip4:
4890                 server1_n += 1
4891             elif p[IP].dst == server2.ip4:
4892                 server2_n += 1
4893             else:
4894                 server3_n += 1
4895         self.assertGreater(server1_n, 0)
4896         self.assertGreater(server2_n, 0)
4897         self.assertGreater(server3_n, 0)
4898
4899         local = {
4900             'addr': server2.ip4,
4901             'port': local_port,
4902             'probability': 10,
4903             'vrf_id': 0
4904         }
4905
4906         # remove one back-end
4907         self.vapi.nat44_lb_static_mapping_add_del_local(
4908             is_add=0,
4909             external_addr=external_addr,
4910             external_port=external_port,
4911             local=local,
4912             protocol=IP_PROTOS.tcp)
4913         server1_n = 0
4914         server2_n = 0
4915         server3_n = 0
4916         self.pg1.add_stream(pkts)
4917         self.pg_enable_capture(self.pg_interfaces)
4918         self.pg_start()
4919         capture = self.pg0.get_capture(len(pkts))
4920         for p in capture:
4921             if p[IP].dst == server1.ip4:
4922                 server1_n += 1
4923             elif p[IP].dst == server2.ip4:
4924                 server2_n += 1
4925             else:
4926                 server3_n += 1
4927         self.assertGreater(server1_n, 0)
4928         self.assertEqual(server2_n, 0)
4929         self.assertGreater(server3_n, 0)
4930
4931     def test_static_lb_2(self):
4932         """ NAT44 local service load balancing (asymmetrical rule) """
4933         external_addr = self.nat_addr
4934         external_port = 80
4935         local_port = 8080
4936         server1 = self.pg0.remote_hosts[0]
4937         server2 = self.pg0.remote_hosts[1]
4938
4939         locals = [{'addr': server1.ip4,
4940                    'port': local_port,
4941                    'probability': 70,
4942                    'vrf_id': 0},
4943                   {'addr': server2.ip4,
4944                    'port': local_port,
4945                    'probability': 30,
4946                    'vrf_id': 0}]
4947
4948         self.vapi.nat44_forwarding_enable_disable(enable=1)
4949         flags = self.config_flags.NAT_IS_OUT2IN_ONLY
4950         self.vapi.nat44_add_del_lb_static_mapping(is_add=1, flags=flags,
4951                                                   external_addr=external_addr,
4952                                                   external_port=external_port,
4953                                                   protocol=IP_PROTOS.tcp,
4954                                                   local_num=len(locals),
4955                                                   locals=locals)
4956         flags = self.config_flags.NAT_IS_INSIDE
4957         self.vapi.nat44_interface_add_del_feature(
4958             sw_if_index=self.pg0.sw_if_index,
4959             flags=flags, is_add=1)
4960         self.vapi.nat44_interface_add_del_feature(
4961             sw_if_index=self.pg1.sw_if_index,
4962             is_add=1)
4963
4964         # from client to service
4965         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
4966              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
4967              TCP(sport=12345, dport=external_port))
4968         self.pg1.add_stream(p)
4969         self.pg_enable_capture(self.pg_interfaces)
4970         self.pg_start()
4971         capture = self.pg0.get_capture(1)
4972         p = capture[0]
4973         server = None
4974         try:
4975             ip = p[IP]
4976             tcp = p[TCP]
4977             self.assertIn(ip.dst, [server1.ip4, server2.ip4])
4978             if ip.dst == server1.ip4:
4979                 server = server1
4980             else:
4981                 server = server2
4982             self.assertEqual(tcp.dport, local_port)
4983             self.assert_packet_checksums_valid(p)
4984         except:
4985             self.logger.error(ppp("Unexpected or invalid packet:", p))
4986             raise
4987
4988         # from service back to client
4989         p = (Ether(src=server.mac, dst=self.pg0.local_mac) /
4990              IP(src=server.ip4, dst=self.pg1.remote_ip4) /
4991              TCP(sport=local_port, dport=12345))
4992         self.pg0.add_stream(p)
4993         self.pg_enable_capture(self.pg_interfaces)
4994         self.pg_start()
4995         capture = self.pg1.get_capture(1)
4996         p = capture[0]
4997         try:
4998             ip = p[IP]
4999             tcp = p[TCP]
5000             self.assertEqual(ip.src, self.nat_addr)
5001             self.assertEqual(tcp.sport, external_port)
5002             self.assert_packet_checksums_valid(p)
5003         except:
5004             self.logger.error(ppp("Unexpected or invalid packet:", p))
5005             raise
5006
5007         # from client to server (no translation)
5008         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
5009              IP(src=self.pg1.remote_ip4, dst=server1.ip4) /
5010              TCP(sport=12346, dport=local_port))
5011         self.pg1.add_stream(p)
5012         self.pg_enable_capture(self.pg_interfaces)
5013         self.pg_start()
5014         capture = self.pg0.get_capture(1)
5015         p = capture[0]
5016         server = None
5017         try:
5018             ip = p[IP]
5019             tcp = p[TCP]
5020             self.assertEqual(ip.dst, server1.ip4)
5021             self.assertEqual(tcp.dport, local_port)
5022             self.assert_packet_checksums_valid(p)
5023         except:
5024             self.logger.error(ppp("Unexpected or invalid packet:", p))
5025             raise
5026
5027         # from service back to client (no translation)
5028         p = (Ether(src=server1.mac, dst=self.pg0.local_mac) /
5029              IP(src=server1.ip4, dst=self.pg1.remote_ip4) /
5030              TCP(sport=local_port, dport=12346))
5031         self.pg0.add_stream(p)
5032         self.pg_enable_capture(self.pg_interfaces)
5033         self.pg_start()
5034         capture = self.pg1.get_capture(1)
5035         p = capture[0]
5036         try:
5037             ip = p[IP]
5038             tcp = p[TCP]
5039             self.assertEqual(ip.src, server1.ip4)
5040             self.assertEqual(tcp.sport, local_port)
5041             self.assert_packet_checksums_valid(p)
5042         except:
5043             self.logger.error(ppp("Unexpected or invalid packet:", p))
5044             raise
5045
5046     def test_lb_affinity(self):
5047         """ NAT44 local service load balancing affinity """
5048         external_addr = self.nat_addr
5049         external_port = 80
5050         local_port = 8080
5051         server1 = self.pg0.remote_hosts[0]
5052         server2 = self.pg0.remote_hosts[1]
5053
5054         locals = [{'addr': server1.ip4,
5055                    'port': local_port,
5056                    'probability': 50,
5057                    'vrf_id': 0},
5058                   {'addr': server2.ip4,
5059                    'port': local_port,
5060                    'probability': 50,
5061                    'vrf_id': 0}]
5062
5063         self.nat44_add_address(self.nat_addr)
5064         self.vapi.nat44_add_del_lb_static_mapping(is_add=1,
5065                                                   external_addr=external_addr,
5066                                                   external_port=external_port,
5067                                                   protocol=IP_PROTOS.tcp,
5068                                                   affinity=10800,
5069                                                   local_num=len(locals),
5070                                                   locals=locals)
5071         flags = self.config_flags.NAT_IS_INSIDE
5072         self.vapi.nat44_interface_add_del_feature(
5073             sw_if_index=self.pg0.sw_if_index,
5074             flags=flags, is_add=1)
5075         self.vapi.nat44_interface_add_del_feature(
5076             sw_if_index=self.pg1.sw_if_index,
5077             is_add=1)
5078
5079         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
5080              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
5081              TCP(sport=1025, dport=external_port))
5082         self.pg1.add_stream(p)
5083         self.pg_enable_capture(self.pg_interfaces)
5084         self.pg_start()
5085         capture = self.pg0.get_capture(1)
5086         backend = capture[0][IP].dst
5087
5088         sessions = self.vapi.nat44_user_session_dump(backend, 0)
5089         self.assertEqual(len(sessions), 1)
5090         self.assertTrue(sessions[0].flags &
5091                         self.config_flags.NAT_IS_EXT_HOST_VALID)
5092         self.vapi.nat44_del_session(
5093             address=sessions[0].inside_ip_address,
5094             port=sessions[0].inside_port,
5095             protocol=sessions[0].protocol,
5096             flags=(self.config_flags.NAT_IS_INSIDE |
5097                    self.config_flags.NAT_IS_EXT_HOST_VALID),
5098             ext_host_address=sessions[0].ext_host_address,
5099             ext_host_port=sessions[0].ext_host_port)
5100
5101         pkts = []
5102         for port in range(1030, 1100):
5103             p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
5104                  IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
5105                  TCP(sport=port, dport=external_port))
5106             pkts.append(p)
5107         self.pg1.add_stream(pkts)
5108         self.pg_enable_capture(self.pg_interfaces)
5109         self.pg_start()
5110         capture = self.pg0.get_capture(len(pkts))
5111         for p in capture:
5112             self.assertEqual(p[IP].dst, backend)
5113
5114     def test_unknown_proto(self):
5115         """ NAT44 translate packet with unknown protocol """
5116         self.nat44_add_address(self.nat_addr)
5117         flags = self.config_flags.NAT_IS_INSIDE
5118         self.vapi.nat44_interface_add_del_feature(
5119             sw_if_index=self.pg0.sw_if_index,
5120             flags=flags, is_add=1)
5121         self.vapi.nat44_interface_add_del_feature(
5122             sw_if_index=self.pg1.sw_if_index,
5123             is_add=1)
5124
5125         # in2out
5126         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
5127              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
5128              TCP(sport=self.tcp_port_in, dport=20))
5129         self.pg0.add_stream(p)
5130         self.pg_enable_capture(self.pg_interfaces)
5131         self.pg_start()
5132         p = self.pg1.get_capture(1)
5133
5134         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
5135              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
5136              GRE() /
5137              IP(src=self.pg2.remote_ip4, dst=self.pg2.remote_ip4) /
5138              TCP(sport=1234, dport=1234))
5139         self.pg0.add_stream(p)
5140         self.pg_enable_capture(self.pg_interfaces)
5141         self.pg_start()
5142         p = self.pg1.get_capture(1)
5143         packet = p[0]
5144         try:
5145             self.assertEqual(packet[IP].src, self.nat_addr)
5146             self.assertEqual(packet[IP].dst, self.pg1.remote_ip4)
5147             self.assertEqual(packet.haslayer(GRE), 1)
5148             self.assert_packet_checksums_valid(packet)
5149         except:
5150             self.logger.error(ppp("Unexpected or invalid packet:", packet))
5151             raise
5152
5153         # out2in
5154         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
5155              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
5156              GRE() /
5157              IP(src=self.pg2.remote_ip4, dst=self.pg2.remote_ip4) /
5158              TCP(sport=1234, dport=1234))
5159         self.pg1.add_stream(p)
5160         self.pg_enable_capture(self.pg_interfaces)
5161         self.pg_start()
5162         p = self.pg0.get_capture(1)
5163         packet = p[0]
5164         try:
5165             self.assertEqual(packet[IP].src, self.pg1.remote_ip4)
5166             self.assertEqual(packet[IP].dst, self.pg0.remote_ip4)
5167             self.assertEqual(packet.haslayer(GRE), 1)
5168             self.assert_packet_checksums_valid(packet)
5169         except:
5170             self.logger.error(ppp("Unexpected or invalid packet:", packet))
5171             raise
5172
5173     def test_hairpinning_unknown_proto(self):
5174         """ NAT44 translate packet with unknown protocol - hairpinning """
5175         host = self.pg0.remote_hosts[0]
5176         server = self.pg0.remote_hosts[1]
5177         host_in_port = 1234
5178         server_out_port = 8765
5179         server_nat_ip = "10.0.0.11"
5180
5181         self.nat44_add_address(self.nat_addr)
5182         flags = self.config_flags.NAT_IS_INSIDE
5183         self.vapi.nat44_interface_add_del_feature(
5184             sw_if_index=self.pg0.sw_if_index,
5185             flags=flags, is_add=1)
5186         self.vapi.nat44_interface_add_del_feature(
5187             sw_if_index=self.pg1.sw_if_index,
5188             is_add=1)
5189
5190         # add static mapping for server
5191         self.nat44_add_static_mapping(server.ip4, server_nat_ip)
5192
5193         # host to server
5194         p = (Ether(src=host.mac, dst=self.pg0.local_mac) /
5195              IP(src=host.ip4, dst=server_nat_ip) /
5196              TCP(sport=host_in_port, dport=server_out_port))
5197         self.pg0.add_stream(p)
5198         self.pg_enable_capture(self.pg_interfaces)
5199         self.pg_start()
5200         self.pg0.get_capture(1)
5201
5202         p = (Ether(dst=self.pg0.local_mac, src=host.mac) /
5203              IP(src=host.ip4, dst=server_nat_ip) /
5204              GRE() /
5205              IP(src=self.pg2.remote_ip4, dst=self.pg2.remote_ip4) /
5206              TCP(sport=1234, dport=1234))
5207         self.pg0.add_stream(p)
5208         self.pg_enable_capture(self.pg_interfaces)
5209         self.pg_start()
5210         p = self.pg0.get_capture(1)
5211         packet = p[0]
5212         try:
5213             self.assertEqual(packet[IP].src, self.nat_addr)
5214             self.assertEqual(packet[IP].dst, server.ip4)
5215             self.assertEqual(packet.haslayer(GRE), 1)
5216             self.assert_packet_checksums_valid(packet)
5217         except:
5218             self.logger.error(ppp("Unexpected or invalid packet:", packet))
5219             raise
5220
5221         # server to host
5222         p = (Ether(dst=self.pg0.local_mac, src=server.mac) /
5223              IP(src=server.ip4, dst=self.nat_addr) /
5224              GRE() /
5225              IP(src=self.pg2.remote_ip4, dst=self.pg2.remote_ip4) /
5226              TCP(sport=1234, dport=1234))
5227         self.pg0.add_stream(p)
5228         self.pg_enable_capture(self.pg_interfaces)
5229         self.pg_start()
5230         p = self.pg0.get_capture(1)
5231         packet = p[0]
5232         try:
5233             self.assertEqual(packet[IP].src, server_nat_ip)
5234             self.assertEqual(packet[IP].dst, host.ip4)
5235             self.assertEqual(packet.haslayer(GRE), 1)
5236             self.assert_packet_checksums_valid(packet)
5237         except:
5238             self.logger.error(ppp("Unexpected or invalid packet:", packet))
5239             raise
5240
5241     def test_output_feature_and_service(self):
5242         """ NAT44 interface output feature and services """
5243         external_addr = '1.2.3.4'
5244         external_port = 80
5245         local_port = 8080
5246
5247         self.vapi.nat44_forwarding_enable_disable(enable=1)
5248         self.nat44_add_address(self.nat_addr)
5249         flags = self.config_flags.NAT_IS_ADDR_ONLY
5250         self.vapi.nat44_add_del_identity_mapping(
5251             ip_address=self.pg1.remote_ip4, sw_if_index=0xFFFFFFFF,
5252             flags=flags, is_add=1)
5253         flags = self.config_flags.NAT_IS_OUT2IN_ONLY
5254         self.nat44_add_static_mapping(self.pg0.remote_ip4, external_addr,
5255                                       local_port, external_port,
5256                                       proto=IP_PROTOS.tcp, flags=flags)
5257         flags = self.config_flags.NAT_IS_INSIDE
5258         self.vapi.nat44_interface_add_del_feature(
5259             sw_if_index=self.pg0.sw_if_index,
5260             is_add=1)
5261         self.vapi.nat44_interface_add_del_feature(
5262             sw_if_index=self.pg0.sw_if_index,
5263             flags=flags, is_add=1)
5264         self.vapi.nat44_interface_add_del_output_feature(
5265             is_add=1,
5266             sw_if_index=self.pg1.sw_if_index)
5267
5268         # from client to service
5269         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
5270              IP(src=self.pg1.remote_ip4, dst=external_addr) /
5271              TCP(sport=12345, dport=external_port))
5272         self.pg1.add_stream(p)
5273         self.pg_enable_capture(self.pg_interfaces)
5274         self.pg_start()
5275         capture = self.pg0.get_capture(1)
5276         p = capture[0]
5277         try:
5278             ip = p[IP]
5279             tcp = p[TCP]
5280             self.assertEqual(ip.dst, self.pg0.remote_ip4)
5281             self.assertEqual(tcp.dport, local_port)
5282             self.assert_packet_checksums_valid(p)
5283         except:
5284             self.logger.error(ppp("Unexpected or invalid packet:", p))
5285             raise
5286
5287         # from service back to client
5288         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
5289              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
5290              TCP(sport=local_port, dport=12345))
5291         self.pg0.add_stream(p)
5292         self.pg_enable_capture(self.pg_interfaces)
5293         self.pg_start()
5294         capture = self.pg1.get_capture(1)
5295         p = capture[0]
5296         try:
5297             ip = p[IP]
5298             tcp = p[TCP]
5299             self.assertEqual(ip.src, external_addr)
5300             self.assertEqual(tcp.sport, external_port)
5301             self.assert_packet_checksums_valid(p)
5302         except:
5303             self.logger.error(ppp("Unexpected or invalid packet:", p))
5304             raise
5305
5306         # from local network host to external network
5307         pkts = self.create_stream_in(self.pg0, self.pg1)
5308         self.pg0.add_stream(pkts)
5309         self.pg_enable_capture(self.pg_interfaces)
5310         self.pg_start()
5311         capture = self.pg1.get_capture(len(pkts))
5312         self.verify_capture_out(capture)
5313         pkts = self.create_stream_in(self.pg0, self.pg1)
5314         self.pg0.add_stream(pkts)
5315         self.pg_enable_capture(self.pg_interfaces)
5316         self.pg_start()
5317         capture = self.pg1.get_capture(len(pkts))
5318         self.verify_capture_out(capture)
5319
5320         # from external network back to local network host
5321         pkts = self.create_stream_out(self.pg1)
5322         self.pg1.add_stream(pkts)
5323         self.pg_enable_capture(self.pg_interfaces)
5324         self.pg_start()
5325         capture = self.pg0.get_capture(len(pkts))
5326         self.verify_capture_in(capture, self.pg0)
5327
5328     def test_output_feature_and_service2(self):
5329         """ NAT44 interface output feature and service host direct access """
5330         self.vapi.nat44_forwarding_enable_disable(enable=1)
5331         self.nat44_add_address(self.nat_addr)
5332         self.vapi.nat44_interface_add_del_output_feature(
5333             is_add=1,
5334             sw_if_index=self.pg1.sw_if_index)
5335
5336         # session initiated from service host - translate
5337         pkts = self.create_stream_in(self.pg0, self.pg1)
5338         self.pg0.add_stream(pkts)
5339         self.pg_enable_capture(self.pg_interfaces)
5340         self.pg_start()
5341         capture = self.pg1.get_capture(len(pkts))
5342         self.verify_capture_out(capture)
5343
5344         pkts = self.create_stream_out(self.pg1)
5345         self.pg1.add_stream(pkts)
5346         self.pg_enable_capture(self.pg_interfaces)
5347         self.pg_start()
5348         capture = self.pg0.get_capture(len(pkts))
5349         self.verify_capture_in(capture, self.pg0)
5350
5351         # session initiated from remote host - do not translate
5352         self.tcp_port_in = 60303
5353         self.udp_port_in = 60304
5354         self.icmp_id_in = 60305
5355         pkts = self.create_stream_out(self.pg1,
5356                                       self.pg0.remote_ip4,
5357                                       use_inside_ports=True)
5358         self.pg1.add_stream(pkts)
5359         self.pg_enable_capture(self.pg_interfaces)
5360         self.pg_start()
5361         capture = self.pg0.get_capture(len(pkts))
5362         self.verify_capture_in(capture, self.pg0)
5363
5364         pkts = self.create_stream_in(self.pg0, self.pg1)
5365         self.pg0.add_stream(pkts)
5366         self.pg_enable_capture(self.pg_interfaces)
5367         self.pg_start()
5368         capture = self.pg1.get_capture(len(pkts))
5369         self.verify_capture_out(capture, nat_ip=self.pg0.remote_ip4,
5370                                 same_port=True)
5371
5372     def test_output_feature_and_service3(self):
5373         """ NAT44 interface output feature and DST NAT """
5374         external_addr = '1.2.3.4'
5375         external_port = 80
5376         local_port = 8080
5377
5378         self.vapi.nat44_forwarding_enable_disable(enable=1)
5379         self.nat44_add_address(self.nat_addr)
5380         flags = self.config_flags.NAT_IS_OUT2IN_ONLY
5381         self.nat44_add_static_mapping(self.pg1.remote_ip4, external_addr,
5382                                       local_port, external_port,
5383                                       proto=IP_PROTOS.tcp, flags=flags)
5384         flags = self.config_flags.NAT_IS_INSIDE
5385         self.vapi.nat44_interface_add_del_feature(
5386             sw_if_index=self.pg0.sw_if_index,
5387             is_add=1)
5388         self.vapi.nat44_interface_add_del_feature(
5389             sw_if_index=self.pg0.sw_if_index,
5390             flags=flags, is_add=1)
5391         self.vapi.nat44_interface_add_del_output_feature(
5392             is_add=1,
5393             sw_if_index=self.pg1.sw_if_index)
5394
5395         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
5396              IP(src=self.pg0.remote_ip4, dst=external_addr) /
5397              TCP(sport=12345, dport=external_port))
5398         self.pg0.add_stream(p)
5399         self.pg_enable_capture(self.pg_interfaces)
5400         self.pg_start()
5401         capture = self.pg1.get_capture(1)
5402         p = capture[0]
5403         try:
5404             ip = p[IP]
5405             tcp = p[TCP]
5406             self.assertEqual(ip.src, self.pg0.remote_ip4)
5407             self.assertEqual(tcp.sport, 12345)
5408             self.assertEqual(ip.dst, self.pg1.remote_ip4)
5409             self.assertEqual(tcp.dport, local_port)
5410             self.assert_packet_checksums_valid(p)
5411         except:
5412             self.logger.error(ppp("Unexpected or invalid packet:", p))
5413             raise
5414
5415         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
5416              IP(src=self.pg1.remote_ip4, dst=self.pg0.remote_ip4) /
5417              TCP(sport=local_port, dport=12345))
5418         self.pg1.add_stream(p)
5419         self.pg_enable_capture(self.pg_interfaces)
5420         self.pg_start()
5421         capture = self.pg0.get_capture(1)
5422         p = capture[0]
5423         try:
5424             ip = p[IP]
5425             tcp = p[TCP]
5426             self.assertEqual(ip.src, external_addr)
5427             self.assertEqual(tcp.sport, external_port)
5428             self.assertEqual(ip.dst, self.pg0.remote_ip4)
5429             self.assertEqual(tcp.dport, 12345)
5430             self.assert_packet_checksums_valid(p)
5431         except:
5432             self.logger.error(ppp("Unexpected or invalid packet:", p))
5433             raise
5434
5435     def test_next_src_nat(self):
5436         """ On way back forward packet to nat44-in2out node. """
5437         twice_nat_addr = '10.0.1.3'
5438         external_port = 80
5439         local_port = 8080
5440         post_twice_nat_port = 0
5441
5442         self.vapi.nat44_forwarding_enable_disable(enable=1)
5443         self.nat44_add_address(twice_nat_addr, twice_nat=1)
5444         flags = (self.config_flags.NAT_IS_OUT2IN_ONLY |
5445                  self.config_flags.NAT_IS_SELF_TWICE_NAT)
5446         self.nat44_add_static_mapping(self.pg6.remote_ip4, self.pg1.remote_ip4,
5447                                       local_port, external_port,
5448                                       proto=IP_PROTOS.tcp, vrf_id=1,
5449                                       flags=flags)
5450         self.vapi.nat44_interface_add_del_feature(
5451             sw_if_index=self.pg6.sw_if_index,
5452             is_add=1)
5453
5454         p = (Ether(src=self.pg6.remote_mac, dst=self.pg6.local_mac) /
5455              IP(src=self.pg6.remote_ip4, dst=self.pg1.remote_ip4) /
5456              TCP(sport=12345, dport=external_port))
5457         self.pg6.add_stream(p)
5458         self.pg_enable_capture(self.pg_interfaces)
5459         self.pg_start()
5460         capture = self.pg6.get_capture(1)
5461         p = capture[0]
5462         try:
5463             ip = p[IP]
5464             tcp = p[TCP]
5465             self.assertEqual(ip.src, twice_nat_addr)
5466             self.assertNotEqual(tcp.sport, 12345)
5467             post_twice_nat_port = tcp.sport
5468             self.assertEqual(ip.dst, self.pg6.remote_ip4)
5469             self.assertEqual(tcp.dport, local_port)
5470             self.assert_packet_checksums_valid(p)
5471         except:
5472             self.logger.error(ppp("Unexpected or invalid packet:", p))
5473             raise
5474
5475         p = (Ether(src=self.pg6.remote_mac, dst=self.pg6.local_mac) /
5476              IP(src=self.pg6.remote_ip4, dst=twice_nat_addr) /
5477              TCP(sport=local_port, dport=post_twice_nat_port))
5478         self.pg6.add_stream(p)
5479         self.pg_enable_capture(self.pg_interfaces)
5480         self.pg_start()
5481         capture = self.pg6.get_capture(1)
5482         p = capture[0]
5483         try:
5484             ip = p[IP]
5485             tcp = p[TCP]
5486             self.assertEqual(ip.src, self.pg1.remote_ip4)
5487             self.assertEqual(tcp.sport, external_port)
5488             self.assertEqual(ip.dst, self.pg6.remote_ip4)
5489             self.assertEqual(tcp.dport, 12345)
5490             self.assert_packet_checksums_valid(p)
5491         except:
5492             self.logger.error(ppp("Unexpected or invalid packet:", p))
5493             raise
5494
5495     def twice_nat_common(self, self_twice_nat=False, same_pg=False, lb=False,
5496                          client_id=None):
5497         twice_nat_addr = '10.0.1.3'
5498
5499         port_in = 8080
5500         if lb:
5501             if not same_pg:
5502                 port_in1 = port_in
5503                 port_in2 = port_in
5504             else:
5505                 port_in1 = port_in + 1
5506                 port_in2 = port_in + 2
5507
5508         port_out = 80
5509         eh_port_out = 4567
5510
5511         server1 = self.pg0.remote_hosts[0]
5512         server2 = self.pg0.remote_hosts[1]
5513         if lb and same_pg:
5514             server2 = server1
5515         if not lb:
5516             server = server1
5517
5518         pg0 = self.pg0
5519         if same_pg:
5520             pg1 = self.pg0
5521         else:
5522             pg1 = self.pg1
5523
5524         eh_translate = ((not self_twice_nat) or (not lb and same_pg) or
5525                         client_id == 1)
5526
5527         self.nat44_add_address(self.nat_addr)
5528         self.nat44_add_address(twice_nat_addr, twice_nat=1)
5529
5530         flags = 0
5531         if self_twice_nat:
5532             flags |= self.config_flags.NAT_IS_SELF_TWICE_NAT
5533         else:
5534             flags |= self.config_flags.NAT_IS_TWICE_NAT
5535
5536         if not lb:
5537             self.nat44_add_static_mapping(pg0.remote_ip4, self.nat_addr,
5538                                           port_in, port_out,
5539                                           proto=IP_PROTOS.tcp,
5540                                           flags=flags)
5541         else:
5542             locals = [{'addr': server1.ip4,
5543                        'port': port_in1,
5544                        'probability': 50,
5545                        'vrf_id': 0},
5546                       {'addr': server2.ip4,
5547                        'port': port_in2,
5548                        'probability': 50,
5549                        'vrf_id': 0}]
5550             out_addr = self.nat_addr
5551
5552             self.vapi.nat44_add_del_lb_static_mapping(is_add=1, flags=flags,
5553                                                       external_addr=out_addr,
5554                                                       external_port=port_out,
5555                                                       protocol=IP_PROTOS.tcp,
5556                                                       local_num=len(locals),
5557                                                       locals=locals)
5558         flags = self.config_flags.NAT_IS_INSIDE
5559         self.vapi.nat44_interface_add_del_feature(
5560             sw_if_index=pg0.sw_if_index,
5561             flags=flags, is_add=1)
5562         self.vapi.nat44_interface_add_del_feature(
5563             sw_if_index=pg1.sw_if_index,
5564             is_add=1)
5565
5566         if same_pg:
5567             if not lb:
5568                 client = server
5569             else:
5570                 assert client_id is not None
5571                 if client_id == 1:
5572                     client = self.pg0.remote_hosts[0]
5573                 elif client_id == 2:
5574                     client = self.pg0.remote_hosts[1]
5575         else:
5576             client = pg1.remote_hosts[0]
5577         p = (Ether(src=pg1.remote_mac, dst=pg1.local_mac) /
5578              IP(src=client.ip4, dst=self.nat_addr) /
5579              TCP(sport=eh_port_out, dport=port_out))
5580         pg1.add_stream(p)
5581         self.pg_enable_capture(self.pg_interfaces)
5582         self.pg_start()
5583         capture = pg0.get_capture(1)
5584         p = capture[0]
5585         try:
5586             ip = p[IP]
5587             tcp = p[TCP]
5588             if lb:
5589                 if ip.dst == server1.ip4:
5590                     server = server1
5591                     port_in = port_in1
5592                 else:
5593                     server = server2
5594                     port_in = port_in2
5595             self.assertEqual(ip.dst, server.ip4)
5596             if lb and same_pg:
5597                 self.assertIn(tcp.dport, [port_in1, port_in2])
5598             else:
5599                 self.assertEqual(tcp.dport, port_in)
5600             if eh_translate:
5601                 self.assertEqual(ip.src, twice_nat_addr)
5602                 self.assertNotEqual(tcp.sport, eh_port_out)
5603             else:
5604                 self.assertEqual(ip.src, client.ip4)
5605                 self.assertEqual(tcp.sport, eh_port_out)
5606             eh_addr_in = ip.src
5607             eh_port_in = tcp.sport
5608             saved_port_in = tcp.dport
5609             self.assert_packet_checksums_valid(p)
5610         except:
5611             self.logger.error(ppp("Unexpected or invalid packet:", p))
5612             raise
5613
5614         p = (Ether(src=server.mac, dst=pg0.local_mac) /
5615              IP(src=server.ip4, dst=eh_addr_in) /
5616              TCP(sport=saved_port_in, dport=eh_port_in))
5617         pg0.add_stream(p)
5618         self.pg_enable_capture(self.pg_interfaces)
5619         self.pg_start()
5620         capture = pg1.get_capture(1)
5621         p = capture[0]
5622         try:
5623             ip = p[IP]
5624             tcp = p[TCP]
5625             self.assertEqual(ip.dst, client.ip4)
5626             self.assertEqual(ip.src, self.nat_addr)
5627             self.assertEqual(tcp.dport, eh_port_out)
5628             self.assertEqual(tcp.sport, port_out)
5629             self.assert_packet_checksums_valid(p)
5630         except:
5631             self.logger.error(ppp("Unexpected or invalid packet:", p))
5632             raise
5633
5634         if eh_translate:
5635             sessions = self.vapi.nat44_user_session_dump(server.ip4, 0)
5636             self.assertEqual(len(sessions), 1)
5637             self.assertTrue(sessions[0].flags &
5638                             self.config_flags.NAT_IS_EXT_HOST_VALID)
5639             self.assertTrue(sessions[0].flags &
5640                             self.config_flags.NAT_IS_TWICE_NAT)
5641             self.logger.info(self.vapi.cli("show nat44 sessions detail"))
5642             self.vapi.nat44_del_session(
5643                 address=sessions[0].inside_ip_address,
5644                 port=sessions[0].inside_port,
5645                 protocol=sessions[0].protocol,
5646                 flags=(self.config_flags.NAT_IS_INSIDE |
5647                        self.config_flags.NAT_IS_EXT_HOST_VALID),
5648                 ext_host_address=sessions[0].ext_host_nat_address,
5649                 ext_host_port=sessions[0].ext_host_nat_port)
5650             sessions = self.vapi.nat44_user_session_dump(server.ip4, 0)
5651             self.assertEqual(len(sessions), 0)
5652
5653     def test_twice_nat(self):
5654         """ Twice NAT44 """
5655         self.twice_nat_common()
5656
5657     def test_self_twice_nat_positive(self):
5658         """ Self Twice NAT44 (positive test) """
5659         self.twice_nat_common(self_twice_nat=True, same_pg=True)
5660
5661     def test_self_twice_nat_negative(self):
5662         """ Self Twice NAT44 (negative test) """
5663         self.twice_nat_common(self_twice_nat=True)
5664
5665     def test_twice_nat_lb(self):
5666         """ Twice NAT44 local service load balancing """
5667         self.twice_nat_common(lb=True)
5668
5669     def test_self_twice_nat_lb_positive(self):
5670         """ Self Twice NAT44 local service load balancing (positive test) """
5671         self.twice_nat_common(lb=True, self_twice_nat=True, same_pg=True,
5672                               client_id=1)
5673
5674     def test_self_twice_nat_lb_negative(self):
5675         """ Self Twice NAT44 local service load balancing (negative test) """
5676         self.twice_nat_common(lb=True, self_twice_nat=True, same_pg=True,
5677                               client_id=2)
5678
5679     def test_twice_nat_interface_addr(self):
5680         """ Acquire twice NAT44 addresses from interface """
5681         flags = self.config_flags.NAT_IS_TWICE_NAT
5682         self.vapi.nat44_add_del_interface_addr(
5683             is_add=1,
5684             sw_if_index=self.pg3.sw_if_index,
5685             flags=flags)
5686
5687         # no address in NAT pool
5688         adresses = self.vapi.nat44_address_dump()
5689         self.assertEqual(0, len(adresses))
5690
5691         # configure interface address and check NAT address pool
5692         self.pg3.config_ip4()
5693         adresses = self.vapi.nat44_address_dump()
5694         self.assertEqual(1, len(adresses))
5695         self.assertEqual(str(adresses[0].ip_address),
5696                          self.pg3.local_ip4)
5697         self.assertEqual(adresses[0].flags, flags)
5698
5699         # remove interface address and check NAT address pool
5700         self.pg3.unconfig_ip4()
5701         adresses = self.vapi.nat44_address_dump()
5702         self.assertEqual(0, len(adresses))
5703
5704     def test_tcp_close(self):
5705         """ Close TCP session from inside network - output feature """
5706         self.vapi.nat44_forwarding_enable_disable(enable=1)
5707         self.nat44_add_address(self.pg1.local_ip4)
5708         twice_nat_addr = '10.0.1.3'
5709         service_ip = '192.168.16.150'
5710         self.nat44_add_address(twice_nat_addr, twice_nat=1)
5711         flags = self.config_flags.NAT_IS_INSIDE
5712         self.vapi.nat44_interface_add_del_feature(
5713             sw_if_index=self.pg0.sw_if_index,
5714             is_add=1)
5715         self.vapi.nat44_interface_add_del_feature(
5716             sw_if_index=self.pg0.sw_if_index,
5717             flags=flags, is_add=1)
5718         self.vapi.nat44_interface_add_del_output_feature(
5719             is_add=1,
5720             sw_if_index=self.pg1.sw_if_index)
5721         flags = (self.config_flags.NAT_IS_OUT2IN_ONLY |
5722                  self.config_flags.NAT_IS_TWICE_NAT)
5723         self.nat44_add_static_mapping(self.pg0.remote_ip4,
5724                                       service_ip,
5725                                       80,
5726                                       80,
5727                                       proto=IP_PROTOS.tcp,
5728                                       flags=flags)
5729         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
5730         start_sessnum = len(sessions)
5731
5732         # SYN packet out->in
5733         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
5734              IP(src=self.pg1.remote_ip4, dst=service_ip) /
5735              TCP(sport=33898, dport=80, flags="S"))
5736         self.pg1.add_stream(p)
5737         self.pg_enable_capture(self.pg_interfaces)
5738         self.pg_start()
5739         capture = self.pg0.get_capture(1)
5740         p = capture[0]
5741         tcp_port = p[TCP].sport
5742
5743         # SYN + ACK packet in->out
5744         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
5745              IP(src=self.pg0.remote_ip4, dst=twice_nat_addr) /
5746              TCP(sport=80, dport=tcp_port, flags="SA"))
5747         self.pg0.add_stream(p)
5748         self.pg_enable_capture(self.pg_interfaces)
5749         self.pg_start()
5750         self.pg1.get_capture(1)
5751
5752         # ACK packet out->in
5753         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
5754              IP(src=self.pg1.remote_ip4, dst=service_ip) /
5755              TCP(sport=33898, dport=80, flags="A"))
5756         self.pg1.add_stream(p)
5757         self.pg_enable_capture(self.pg_interfaces)
5758         self.pg_start()
5759         self.pg0.get_capture(1)
5760
5761         # FIN packet in -> out
5762         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
5763              IP(src=self.pg0.remote_ip4, dst=twice_nat_addr) /
5764              TCP(sport=80, dport=tcp_port, flags="FA", seq=100, ack=300))
5765         self.pg0.add_stream(p)
5766         self.pg_enable_capture(self.pg_interfaces)
5767         self.pg_start()
5768         self.pg1.get_capture(1)
5769
5770         # FIN+ACK packet out -> in
5771         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
5772              IP(src=self.pg1.remote_ip4, dst=service_ip) /
5773              TCP(sport=33898, dport=80, flags="FA", seq=300, ack=101))
5774         self.pg1.add_stream(p)
5775         self.pg_enable_capture(self.pg_interfaces)
5776         self.pg_start()
5777         self.pg0.get_capture(1)
5778
5779         # ACK packet in -> out
5780         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
5781              IP(src=self.pg0.remote_ip4, dst=twice_nat_addr) /
5782              TCP(sport=80, dport=tcp_port, flags="A", seq=101, ack=301))
5783         self.pg0.add_stream(p)
5784         self.pg_enable_capture(self.pg_interfaces)
5785         self.pg_start()
5786         self.pg1.get_capture(1)
5787
5788         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4,
5789                                                      0)
5790         self.assertEqual(len(sessions) - start_sessnum, 0)
5791
5792     def test_tcp_session_close_in(self):
5793         """ Close TCP session from inside network """
5794         self.tcp_port_out = 10505
5795         self.nat44_add_address(self.nat_addr)
5796         flags = self.config_flags.NAT_IS_TWICE_NAT
5797         self.nat44_add_static_mapping(self.pg0.remote_ip4,
5798                                       self.nat_addr,
5799                                       self.tcp_port_in,
5800                                       self.tcp_port_out,
5801                                       proto=IP_PROTOS.tcp,
5802                                       flags=flags)
5803         flags = self.config_flags.NAT_IS_INSIDE
5804         self.vapi.nat44_interface_add_del_feature(
5805             sw_if_index=self.pg0.sw_if_index,
5806             flags=flags, is_add=1)
5807         self.vapi.nat44_interface_add_del_feature(
5808             sw_if_index=self.pg1.sw_if_index,
5809             is_add=1)
5810
5811         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
5812         start_sessnum = len(sessions)
5813
5814         self.vapi.nat_set_timeouts(udp=300, tcp_established=7440,
5815                                    tcp_transitory=2, icmp=5)
5816
5817         self.initiate_tcp_session(self.pg0, self.pg1)
5818
5819         # FIN packet in -> out
5820         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
5821              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
5822              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
5823                  flags="FA", seq=100, ack=300))
5824         self.pg0.add_stream(p)
5825         self.pg_enable_capture(self.pg_interfaces)
5826         self.pg_start()
5827         self.pg1.get_capture(1)
5828
5829         pkts = []
5830
5831         # ACK packet out -> in
5832         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
5833              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
5834              TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
5835                  flags="A", seq=300, ack=101))
5836         pkts.append(p)
5837
5838         # FIN packet out -> in
5839         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
5840              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
5841              TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
5842                  flags="FA", seq=300, ack=101))
5843         pkts.append(p)
5844
5845         self.pg1.add_stream(pkts)
5846         self.pg_enable_capture(self.pg_interfaces)
5847         self.pg_start()
5848         self.pg0.get_capture(2)
5849
5850         # ACK packet in -> out
5851         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
5852              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
5853              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
5854                  flags="A", seq=101, ack=301))
5855         self.pg0.add_stream(p)
5856         self.pg_enable_capture(self.pg_interfaces)
5857         self.pg_start()
5858         self.pg1.get_capture(1)
5859
5860         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
5861         self.assertEqual(len(sessions) - start_sessnum, 1)
5862
5863         stats = self.statistics.get_counter(
5864             '/err/nat44-ed-out2in/drops due to TCP in transitory timeout')
5865         out2in_drops = stats[0]
5866         stats = self.statistics.get_counter(
5867             '/err/nat44-ed-in2out/drops due to TCP in transitory timeout')
5868         in2out_drops = stats[0]
5869
5870         # extra FIN packet out -> in - this should be dropped
5871         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
5872              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
5873              TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
5874                  flags="FA", seq=300, ack=101))
5875
5876         self.pg1.add_stream(p)
5877         self.pg_enable_capture(self.pg_interfaces)
5878         self.pg_start()
5879         self.pg0.assert_nothing_captured()
5880
5881         # extra ACK packet in -> out - this should be dropped
5882         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
5883              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
5884              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
5885                  flags="A", seq=101, ack=301))
5886         self.pg0.add_stream(p)
5887         self.pg_enable_capture(self.pg_interfaces)
5888         self.pg_start()
5889         self.pg1.assert_nothing_captured()
5890
5891         stats = self.statistics.get_counter(
5892             '/err/nat44-ed-out2in/drops due to TCP in transitory timeout')
5893         self.assertEqual(stats[0] - out2in_drops, 1)
5894         stats = self.statistics.get_counter(
5895             '/err/nat44-ed-in2out/drops due to TCP in transitory timeout')
5896         self.assertEqual(stats[0] - in2out_drops, 1)
5897
5898         self.sleep(3)
5899         # extra ACK packet in -> out - this will cause session to be wiped
5900         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
5901              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
5902              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
5903                  flags="A", seq=101, ack=301))
5904         self.pg0.add_stream(p)
5905         self.pg_enable_capture(self.pg_interfaces)
5906         self.pg_start()
5907         self.pg1.assert_nothing_captured()
5908         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
5909         self.assertEqual(len(sessions) - start_sessnum, 0)
5910
5911     def test_tcp_session_close_out(self):
5912         """ Close TCP session from outside network """
5913         self.tcp_port_out = 10505
5914         self.nat44_add_address(self.nat_addr)
5915         flags = self.config_flags.NAT_IS_TWICE_NAT
5916         self.nat44_add_static_mapping(self.pg0.remote_ip4,
5917                                       self.nat_addr,
5918                                       self.tcp_port_in,
5919                                       self.tcp_port_out,
5920                                       proto=IP_PROTOS.tcp,
5921                                       flags=flags)
5922         flags = self.config_flags.NAT_IS_INSIDE
5923         self.vapi.nat44_interface_add_del_feature(
5924             sw_if_index=self.pg0.sw_if_index,
5925             flags=flags, is_add=1)
5926         self.vapi.nat44_interface_add_del_feature(
5927             sw_if_index=self.pg1.sw_if_index,
5928             is_add=1)
5929
5930         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
5931         start_sessnum = len(sessions)
5932
5933         self.vapi.nat_set_timeouts(udp=300, tcp_established=7440,
5934                                    tcp_transitory=2, icmp=5)
5935
5936         self.initiate_tcp_session(self.pg0, self.pg1)
5937
5938         # FIN packet out -> in
5939         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
5940              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
5941              TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
5942                  flags="FA", seq=100, ack=300))
5943         self.pg1.add_stream(p)
5944         self.pg_enable_capture(self.pg_interfaces)
5945         self.pg_start()
5946         self.pg0.get_capture(1)
5947
5948         # FIN+ACK packet in -> out
5949         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
5950              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
5951              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
5952                  flags="FA", seq=300, ack=101))
5953
5954         self.pg0.add_stream(p)
5955         self.pg_enable_capture(self.pg_interfaces)
5956         self.pg_start()
5957         self.pg1.get_capture(1)
5958
5959         # ACK packet out -> in
5960         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
5961              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
5962              TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
5963                  flags="A", seq=101, ack=301))
5964         self.pg1.add_stream(p)
5965         self.pg_enable_capture(self.pg_interfaces)
5966         self.pg_start()
5967         self.pg0.get_capture(1)
5968
5969         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
5970         self.assertEqual(len(sessions) - start_sessnum, 1)
5971
5972         stats = self.statistics.get_counter(
5973             '/err/nat44-ed-out2in/drops due to TCP in transitory timeout')
5974         out2in_drops = stats[0]
5975         stats = self.statistics.get_counter(
5976             '/err/nat44-ed-in2out/drops due to TCP in transitory timeout')
5977         in2out_drops = stats[0]
5978
5979         # extra FIN packet out -> in - this should be dropped
5980         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
5981              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
5982              TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
5983                  flags="FA", seq=300, ack=101))
5984
5985         self.pg1.add_stream(p)
5986         self.pg_enable_capture(self.pg_interfaces)
5987         self.pg_start()
5988         self.pg0.assert_nothing_captured()
5989
5990         # extra ACK packet in -> out - this should be dropped
5991         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
5992              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
5993              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
5994                  flags="A", seq=101, ack=301))
5995         self.pg0.add_stream(p)
5996         self.pg_enable_capture(self.pg_interfaces)
5997         self.pg_start()
5998         self.pg1.assert_nothing_captured()
5999
6000         stats = self.statistics.get_counter(
6001             '/err/nat44-ed-out2in/drops due to TCP in transitory timeout')
6002         self.assertEqual(stats[0] - out2in_drops, 1)
6003         stats = self.statistics.get_counter(
6004             '/err/nat44-ed-in2out/drops due to TCP in transitory timeout')
6005         self.assertEqual(stats[0] - in2out_drops, 1)
6006
6007         self.sleep(3)
6008         # extra ACK packet in -> out - this will cause session to be wiped
6009         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6010              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6011              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
6012                  flags="A", seq=101, ack=301))
6013         self.pg0.add_stream(p)
6014         self.pg_enable_capture(self.pg_interfaces)
6015         self.pg_start()
6016         self.pg1.assert_nothing_captured()
6017         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
6018         self.assertEqual(len(sessions) - start_sessnum, 0)
6019
6020     def test_tcp_session_close_simultaneous(self):
6021         """ Close TCP session from inside network """
6022         self.tcp_port_out = 10505
6023         self.nat44_add_address(self.nat_addr)
6024         flags = self.config_flags.NAT_IS_TWICE_NAT
6025         self.nat44_add_static_mapping(self.pg0.remote_ip4,
6026                                       self.nat_addr,
6027                                       self.tcp_port_in,
6028                                       self.tcp_port_out,
6029                                       proto=IP_PROTOS.tcp,
6030                                       flags=flags)
6031         flags = self.config_flags.NAT_IS_INSIDE
6032         self.vapi.nat44_interface_add_del_feature(
6033             sw_if_index=self.pg0.sw_if_index,
6034             flags=flags, is_add=1)
6035         self.vapi.nat44_interface_add_del_feature(
6036             sw_if_index=self.pg1.sw_if_index,
6037             is_add=1)
6038
6039         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
6040         start_sessnum = len(sessions)
6041
6042         self.vapi.nat_set_timeouts(udp=300, tcp_established=7440,
6043                                    tcp_transitory=2, icmp=5)
6044
6045         self.initiate_tcp_session(self.pg0, self.pg1)
6046
6047         # FIN packet in -> out
6048         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6049              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6050              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
6051                  flags="FA", seq=100, ack=300))
6052         self.pg0.add_stream(p)
6053         self.pg_enable_capture(self.pg_interfaces)
6054         self.pg_start()
6055         self.pg1.get_capture(1)
6056
6057         # FIN packet out -> in
6058         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
6059              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
6060              TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
6061                  flags="FA", seq=300, ack=100))
6062         self.pg1.add_stream(p)
6063         self.pg_enable_capture(self.pg_interfaces)
6064         self.pg_start()
6065         self.pg0.get_capture(1)
6066
6067         # ACK packet in -> out
6068         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6069              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6070              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
6071                  flags="A", seq=101, ack=301))
6072         self.pg0.add_stream(p)
6073         self.pg_enable_capture(self.pg_interfaces)
6074         self.pg_start()
6075         self.pg1.get_capture(1)
6076
6077         # ACK packet out -> in
6078         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
6079              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
6080              TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
6081                  flags="A", seq=301, ack=101))
6082         self.pg1.add_stream(p)
6083         self.pg_enable_capture(self.pg_interfaces)
6084         self.pg_start()
6085         self.pg0.get_capture(1)
6086
6087         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
6088         self.assertEqual(len(sessions) - start_sessnum, 1)
6089
6090         stats = self.statistics.get_counter(
6091             '/err/nat44-ed-out2in/drops due to TCP in transitory timeout')
6092         out2in_drops = stats[0]
6093         stats = self.statistics.get_counter(
6094             '/err/nat44-ed-in2out/drops due to TCP in transitory timeout')
6095         in2out_drops = stats[0]
6096
6097         # extra FIN packet out -> in - this should be dropped
6098         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
6099              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
6100              TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
6101                  flags="FA", seq=300, ack=101))
6102
6103         self.pg1.add_stream(p)
6104         self.pg_enable_capture(self.pg_interfaces)
6105         self.pg_start()
6106         self.pg0.assert_nothing_captured()
6107
6108         # extra ACK packet in -> out - this should be dropped
6109         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6110              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6111              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
6112                  flags="A", seq=101, ack=301))
6113         self.pg0.add_stream(p)
6114         self.pg_enable_capture(self.pg_interfaces)
6115         self.pg_start()
6116         self.pg1.assert_nothing_captured()
6117
6118         stats = self.statistics.get_counter(
6119             '/err/nat44-ed-out2in/drops due to TCP in transitory timeout')
6120         self.assertEqual(stats[0] - out2in_drops, 1)
6121         stats = self.statistics.get_counter(
6122             '/err/nat44-ed-in2out/drops due to TCP in transitory timeout')
6123         self.assertEqual(stats[0] - in2out_drops, 1)
6124
6125         self.sleep(3)
6126         # extra ACK packet in -> out - this will cause session to be wiped
6127         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6128              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6129              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
6130                  flags="A", seq=101, ack=301))
6131         self.pg0.add_stream(p)
6132         self.pg_enable_capture(self.pg_interfaces)
6133         self.pg_start()
6134         self.pg1.assert_nothing_captured()
6135         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
6136         self.assertEqual(len(sessions) - start_sessnum, 0)
6137
6138     def test_one_armed_nat44_static(self):
6139         """ One armed NAT44 and 1:1 NAPT asymmetrical rule """
6140         remote_host = self.pg4.remote_hosts[0]
6141         local_host = self.pg4.remote_hosts[1]
6142         external_port = 80
6143         local_port = 8080
6144         eh_port_in = 0
6145
6146         self.vapi.nat44_forwarding_enable_disable(enable=1)
6147         self.nat44_add_address(self.nat_addr, twice_nat=1)
6148         flags = (self.config_flags.NAT_IS_OUT2IN_ONLY |
6149                  self.config_flags.NAT_IS_TWICE_NAT)
6150         self.nat44_add_static_mapping(local_host.ip4, self.nat_addr,
6151                                       local_port, external_port,
6152                                       proto=IP_PROTOS.tcp, flags=flags)
6153         flags = self.config_flags.NAT_IS_INSIDE
6154         self.vapi.nat44_interface_add_del_feature(
6155             sw_if_index=self.pg4.sw_if_index,
6156             is_add=1)
6157         self.vapi.nat44_interface_add_del_feature(
6158             sw_if_index=self.pg4.sw_if_index,
6159             flags=flags, is_add=1)
6160
6161         # from client to service
6162         p = (Ether(src=self.pg4.remote_mac, dst=self.pg4.local_mac) /
6163              IP(src=remote_host.ip4, dst=self.nat_addr) /
6164              TCP(sport=12345, dport=external_port))
6165         self.pg4.add_stream(p)
6166         self.pg_enable_capture(self.pg_interfaces)
6167         self.pg_start()
6168         capture = self.pg4.get_capture(1)
6169         p = capture[0]
6170         try:
6171             ip = p[IP]
6172             tcp = p[TCP]
6173             self.assertEqual(ip.dst, local_host.ip4)
6174             self.assertEqual(ip.src, self.nat_addr)
6175             self.assertEqual(tcp.dport, local_port)
6176             self.assertNotEqual(tcp.sport, 12345)
6177             eh_port_in = tcp.sport
6178             self.assert_packet_checksums_valid(p)
6179         except:
6180             self.logger.error(ppp("Unexpected or invalid packet:", p))
6181             raise
6182
6183         # from service back to client
6184         p = (Ether(src=self.pg4.remote_mac, dst=self.pg4.local_mac) /
6185              IP(src=local_host.ip4, dst=self.nat_addr) /
6186              TCP(sport=local_port, dport=eh_port_in))
6187         self.pg4.add_stream(p)
6188         self.pg_enable_capture(self.pg_interfaces)
6189         self.pg_start()
6190         capture = self.pg4.get_capture(1)
6191         p = capture[0]
6192         try:
6193             ip = p[IP]
6194             tcp = p[TCP]
6195             self.assertEqual(ip.src, self.nat_addr)
6196             self.assertEqual(ip.dst, remote_host.ip4)
6197             self.assertEqual(tcp.sport, external_port)
6198             self.assertEqual(tcp.dport, 12345)
6199             self.assert_packet_checksums_valid(p)
6200         except:
6201             self.logger.error(ppp("Unexpected or invalid packet:", p))
6202             raise
6203
6204     def test_static_with_port_out2(self):
6205         """ 1:1 NAPT asymmetrical rule """
6206
6207         external_port = 80
6208         local_port = 8080
6209
6210         self.vapi.nat44_forwarding_enable_disable(enable=1)
6211         flags = self.config_flags.NAT_IS_OUT2IN_ONLY
6212         self.nat44_add_static_mapping(self.pg0.remote_ip4, self.nat_addr,
6213                                       local_port, external_port,
6214                                       proto=IP_PROTOS.tcp, flags=flags)
6215         flags = self.config_flags.NAT_IS_INSIDE
6216         self.vapi.nat44_interface_add_del_feature(
6217             sw_if_index=self.pg0.sw_if_index,
6218             flags=flags, is_add=1)
6219         self.vapi.nat44_interface_add_del_feature(
6220             sw_if_index=self.pg1.sw_if_index,
6221             is_add=1)
6222
6223         # from client to service
6224         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
6225              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
6226              TCP(sport=12345, dport=external_port))
6227         self.pg1.add_stream(p)
6228         self.pg_enable_capture(self.pg_interfaces)
6229         self.pg_start()
6230         capture = self.pg0.get_capture(1)
6231         p = capture[0]
6232         try:
6233             ip = p[IP]
6234             tcp = p[TCP]
6235             self.assertEqual(ip.dst, self.pg0.remote_ip4)
6236             self.assertEqual(tcp.dport, local_port)
6237             self.assert_packet_checksums_valid(p)
6238         except:
6239             self.logger.error(ppp("Unexpected or invalid packet:", p))
6240             raise
6241
6242         # ICMP error
6243         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
6244              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6245              ICMP(type=11) / capture[0][IP])
6246         self.pg0.add_stream(p)
6247         self.pg_enable_capture(self.pg_interfaces)
6248         self.pg_start()
6249         capture = self.pg1.get_capture(1)
6250         p = capture[0]
6251         try:
6252             self.assertEqual(p[IP].src, self.nat_addr)
6253             inner = p[IPerror]
6254             self.assertEqual(inner.dst, self.nat_addr)
6255             self.assertEqual(inner[TCPerror].dport, external_port)
6256         except:
6257             self.logger.error(ppp("Unexpected or invalid packet:", p))
6258             raise
6259
6260         # from service back to client
6261         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6262              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6263              TCP(sport=local_port, dport=12345))
6264         self.pg0.add_stream(p)
6265         self.pg_enable_capture(self.pg_interfaces)
6266         self.pg_start()
6267         capture = self.pg1.get_capture(1)
6268         p = capture[0]
6269         try:
6270             ip = p[IP]
6271             tcp = p[TCP]
6272             self.assertEqual(ip.src, self.nat_addr)
6273             self.assertEqual(tcp.sport, external_port)
6274             self.assert_packet_checksums_valid(p)
6275         except:
6276             self.logger.error(ppp("Unexpected or invalid packet:", p))
6277             raise
6278
6279         # ICMP error
6280         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
6281              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
6282              ICMP(type=11) / capture[0][IP])
6283         self.pg1.add_stream(p)
6284         self.pg_enable_capture(self.pg_interfaces)
6285         self.pg_start()
6286         capture = self.pg0.get_capture(1)
6287         p = capture[0]
6288         try:
6289             self.assertEqual(p[IP].dst, self.pg0.remote_ip4)
6290             inner = p[IPerror]
6291             self.assertEqual(inner.src, self.pg0.remote_ip4)
6292             self.assertEqual(inner[TCPerror].sport, local_port)
6293         except:
6294             self.logger.error(ppp("Unexpected or invalid packet:", p))
6295             raise
6296
6297         # from client to server (no translation)
6298         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
6299              IP(src=self.pg1.remote_ip4, dst=self.pg0.remote_ip4) /
6300              TCP(sport=12346, dport=local_port))
6301         self.pg1.add_stream(p)
6302         self.pg_enable_capture(self.pg_interfaces)
6303         self.pg_start()
6304         capture = self.pg0.get_capture(1)
6305         p = capture[0]
6306         try:
6307             ip = p[IP]
6308             tcp = p[TCP]
6309             self.assertEqual(ip.dst, self.pg0.remote_ip4)
6310             self.assertEqual(tcp.dport, local_port)
6311             self.assert_packet_checksums_valid(p)
6312         except:
6313             self.logger.error(ppp("Unexpected or invalid packet:", p))
6314             raise
6315
6316         # from service back to client (no translation)
6317         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6318              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6319              TCP(sport=local_port, dport=12346))
6320         self.pg0.add_stream(p)
6321         self.pg_enable_capture(self.pg_interfaces)
6322         self.pg_start()
6323         capture = self.pg1.get_capture(1)
6324         p = capture[0]
6325         try:
6326             ip = p[IP]
6327             tcp = p[TCP]
6328             self.assertEqual(ip.src, self.pg0.remote_ip4)
6329             self.assertEqual(tcp.sport, local_port)
6330             self.assert_packet_checksums_valid(p)
6331         except:
6332             self.logger.error(ppp("Unexpected or invalid packet:", p))
6333             raise
6334
6335     def test_output_feature(self):
6336         """ NAT44 interface output feature (in2out postrouting) """
6337         self.vapi.nat44_forwarding_enable_disable(enable=1)
6338         self.nat44_add_address(self.nat_addr)
6339         self.vapi.nat44_interface_add_del_feature(
6340             sw_if_index=self.pg0.sw_if_index,
6341             is_add=1)
6342         self.vapi.nat44_interface_add_del_output_feature(
6343             is_add=1,
6344             sw_if_index=self.pg1.sw_if_index)
6345
6346         # in2out
6347         pkts = self.create_stream_in(self.pg0, self.pg1)
6348         self.pg0.add_stream(pkts)
6349         self.pg_enable_capture(self.pg_interfaces)
6350         self.pg_start()
6351         capture = self.pg1.get_capture(len(pkts))
6352         self.verify_capture_out(capture)
6353
6354         # out2in
6355         pkts = self.create_stream_out(self.pg1)
6356         self.pg1.add_stream(pkts)
6357         self.pg_enable_capture(self.pg_interfaces)
6358         self.pg_start()
6359         capture = self.pg0.get_capture(len(pkts))
6360         self.verify_capture_in(capture, self.pg0)
6361
6362     def test_output_feature_stateful_acl(self):
6363         """ NAT44 endpoint-dependent output feature works with stateful ACL """
6364         self.nat44_add_address(self.nat_addr)
6365         self.vapi.nat44_interface_add_del_output_feature(
6366             sw_if_index=self.pg0.sw_if_index,
6367             flags=self.config_flags.NAT_IS_INSIDE,
6368             is_add=1)
6369         self.vapi.nat44_interface_add_del_output_feature(
6370             sw_if_index=self.pg1.sw_if_index,
6371             flags=self.config_flags.NAT_IS_OUTSIDE,
6372             is_add=1)
6373
6374         # First ensure that the NAT is working sans ACL
6375
6376         # send packets out2in, no sessions yet so packets should drop
6377         pkts_out2in = self.create_stream_out(self.pg1)
6378         self.send_and_assert_no_replies(self.pg1, pkts_out2in)
6379
6380         # send packets into inside intf, ensure received via outside intf
6381         pkts_in2out = self.create_stream_in(self.pg0, self.pg1)
6382         capture = self.send_and_expect(self.pg0, pkts_in2out, self.pg1,
6383                                        len(pkts_in2out))
6384         self.verify_capture_out(capture)
6385
6386         # send out2in again, with sessions created it should work now
6387         pkts_out2in = self.create_stream_out(self.pg1)
6388         capture = self.send_and_expect(self.pg1, pkts_out2in, self.pg0,
6389                                        len(pkts_out2in))
6390         self.verify_capture_in(capture, self.pg0)
6391
6392         # Create an ACL blocking everything
6393         out2in_deny_rule = AclRule(is_permit=0)
6394         out2in_acl = VppAcl(self, rules=[out2in_deny_rule])
6395         out2in_acl.add_vpp_config()
6396
6397         # create an ACL to permit/reflect everything
6398         in2out_reflect_rule = AclRule(is_permit=2)
6399         in2out_acl = VppAcl(self, rules=[in2out_reflect_rule])
6400         in2out_acl.add_vpp_config()
6401
6402         # apply as input acl on interface and confirm it blocks everything
6403         acl_if = VppAclInterface(self, sw_if_index=self.pg1.sw_if_index,
6404                                  n_input=1, acls=[out2in_acl])
6405         acl_if.add_vpp_config()
6406         self.send_and_assert_no_replies(self.pg1, pkts_out2in)
6407
6408         # apply output acl
6409         acl_if.acls = [out2in_acl, in2out_acl]
6410         acl_if.add_vpp_config()
6411         # send in2out to generate ACL state (NAT state was created earlier)
6412         capture = self.send_and_expect(self.pg0, pkts_in2out, self.pg1,
6413                                        len(pkts_in2out))
6414         self.verify_capture_out(capture)
6415
6416         # send out2in again. ACL state exists so it should work now.
6417         # TCP packets with the syn flag set also need the ack flag
6418         for p in pkts_out2in:
6419             if p.haslayer(TCP) and p[TCP].flags & 0x02:
6420                 p[TCP].flags |= 0x10
6421         capture = self.send_and_expect(self.pg1, pkts_out2in, self.pg0,
6422                                        len(pkts_out2in))
6423         self.verify_capture_in(capture, self.pg0)
6424         self.logger.info(self.vapi.cli("show trace"))
6425
6426     def test_multiple_vrf(self):
6427         """ Multiple VRF setup """
6428         external_addr = '1.2.3.4'
6429         external_port = 80
6430         local_port = 8080
6431         port = 0
6432
6433         self.vapi.nat44_forwarding_enable_disable(enable=1)
6434         self.nat44_add_address(self.nat_addr)
6435         flags = self.config_flags.NAT_IS_INSIDE
6436         self.vapi.nat44_interface_add_del_feature(
6437             sw_if_index=self.pg0.sw_if_index,
6438             is_add=1)
6439         self.vapi.nat44_interface_add_del_feature(
6440             sw_if_index=self.pg0.sw_if_index,
6441             flags=flags, is_add=1)
6442         self.vapi.nat44_interface_add_del_output_feature(
6443             is_add=1,
6444             sw_if_index=self.pg1.sw_if_index)
6445         self.vapi.nat44_interface_add_del_feature(
6446             sw_if_index=self.pg5.sw_if_index,
6447             is_add=1)
6448         self.vapi.nat44_interface_add_del_feature(
6449             sw_if_index=self.pg5.sw_if_index,
6450             flags=flags, is_add=1)
6451         self.vapi.nat44_interface_add_del_feature(
6452             sw_if_index=self.pg6.sw_if_index,
6453             is_add=1)
6454         flags = self.config_flags.NAT_IS_OUT2IN_ONLY
6455         self.nat44_add_static_mapping(self.pg5.remote_ip4, external_addr,
6456                                       local_port, external_port, vrf_id=1,
6457                                       proto=IP_PROTOS.tcp, flags=flags)
6458         self.nat44_add_static_mapping(
6459             self.pg0.remote_ip4,
6460             external_sw_if_index=self.pg0.sw_if_index,
6461             local_port=local_port,
6462             vrf_id=0,
6463             external_port=external_port,
6464             proto=IP_PROTOS.tcp,
6465             flags=flags
6466         )
6467
6468         # from client to service (both VRF1)
6469         p = (Ether(src=self.pg6.remote_mac, dst=self.pg6.local_mac) /
6470              IP(src=self.pg6.remote_ip4, dst=external_addr) /
6471              TCP(sport=12345, dport=external_port))
6472         self.pg6.add_stream(p)
6473         self.pg_enable_capture(self.pg_interfaces)
6474         self.pg_start()
6475         capture = self.pg5.get_capture(1)
6476         p = capture[0]
6477         try:
6478             ip = p[IP]
6479             tcp = p[TCP]
6480             self.assertEqual(ip.dst, self.pg5.remote_ip4)
6481             self.assertEqual(tcp.dport, local_port)
6482             self.assert_packet_checksums_valid(p)
6483         except:
6484             self.logger.error(ppp("Unexpected or invalid packet:", p))
6485             raise
6486
6487         # from service back to client (both VRF1)
6488         p = (Ether(src=self.pg5.remote_mac, dst=self.pg5.local_mac) /
6489              IP(src=self.pg5.remote_ip4, dst=self.pg6.remote_ip4) /
6490              TCP(sport=local_port, dport=12345))
6491         self.pg5.add_stream(p)
6492         self.pg_enable_capture(self.pg_interfaces)
6493         self.pg_start()
6494         capture = self.pg6.get_capture(1)
6495         p = capture[0]
6496         try:
6497             ip = p[IP]
6498             tcp = p[TCP]
6499             self.assertEqual(ip.src, external_addr)
6500             self.assertEqual(tcp.sport, external_port)
6501             self.assert_packet_checksums_valid(p)
6502         except:
6503             self.logger.error(ppp("Unexpected or invalid packet:", p))
6504             raise
6505
6506         # dynamic NAT from VRF1 to VRF0 (output-feature)
6507         p = (Ether(src=self.pg5.remote_mac, dst=self.pg5.local_mac) /
6508              IP(src=self.pg5.remote_ip4, dst=self.pg1.remote_ip4) /
6509              TCP(sport=2345, dport=22))
6510         self.pg5.add_stream(p)
6511         self.pg_enable_capture(self.pg_interfaces)
6512         self.pg_start()
6513         capture = self.pg1.get_capture(1)
6514         p = capture[0]
6515         try:
6516             ip = p[IP]
6517             tcp = p[TCP]
6518             self.assertEqual(ip.src, self.nat_addr)
6519             self.assertNotEqual(tcp.sport, 2345)
6520             self.assert_packet_checksums_valid(p)
6521             port = tcp.sport
6522         except:
6523             self.logger.error(ppp("Unexpected or invalid packet:", p))
6524             raise
6525
6526         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
6527              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
6528              TCP(sport=22, dport=port))
6529         self.pg1.add_stream(p)
6530         self.pg_enable_capture(self.pg_interfaces)
6531         self.pg_start()
6532         capture = self.pg5.get_capture(1)
6533         p = capture[0]
6534         try:
6535             ip = p[IP]
6536             tcp = p[TCP]
6537             self.assertEqual(ip.dst, self.pg5.remote_ip4)
6538             self.assertEqual(tcp.dport, 2345)
6539             self.assert_packet_checksums_valid(p)
6540         except:
6541             self.logger.error(ppp("Unexpected or invalid packet:", p))
6542             raise
6543
6544         # from client VRF1 to service VRF0
6545         p = (Ether(src=self.pg6.remote_mac, dst=self.pg6.local_mac) /
6546              IP(src=self.pg6.remote_ip4, dst=self.pg0.local_ip4) /
6547              TCP(sport=12346, dport=external_port))
6548         self.pg6.add_stream(p)
6549         self.pg_enable_capture(self.pg_interfaces)
6550         self.pg_start()
6551         capture = self.pg0.get_capture(1)
6552         p = capture[0]
6553         try:
6554             ip = p[IP]
6555             tcp = p[TCP]
6556             self.assertEqual(ip.dst, self.pg0.remote_ip4)
6557             self.assertEqual(tcp.dport, local_port)
6558             self.assert_packet_checksums_valid(p)
6559         except:
6560             self.logger.error(ppp("Unexpected or invalid packet:", p))
6561             raise
6562
6563         # from service VRF0 back to client VRF1
6564         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6565              IP(src=self.pg0.remote_ip4, dst=self.pg6.remote_ip4) /
6566              TCP(sport=local_port, dport=12346))
6567         self.pg0.add_stream(p)
6568         self.pg_enable_capture(self.pg_interfaces)
6569         self.pg_start()
6570         capture = self.pg6.get_capture(1)
6571         p = capture[0]
6572         try:
6573             ip = p[IP]
6574             tcp = p[TCP]
6575             self.assertEqual(ip.src, self.pg0.local_ip4)
6576             self.assertEqual(tcp.sport, external_port)
6577             self.assert_packet_checksums_valid(p)
6578         except:
6579             self.logger.error(ppp("Unexpected or invalid packet:", p))
6580             raise
6581
6582         # from client VRF0 to service VRF1
6583         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6584              IP(src=self.pg0.remote_ip4, dst=external_addr) /
6585              TCP(sport=12347, dport=external_port))
6586         self.pg0.add_stream(p)
6587         self.pg_enable_capture(self.pg_interfaces)
6588         self.pg_start()
6589         capture = self.pg5.get_capture(1)
6590         p = capture[0]
6591         try:
6592             ip = p[IP]
6593             tcp = p[TCP]
6594             self.assertEqual(ip.dst, self.pg5.remote_ip4)
6595             self.assertEqual(tcp.dport, local_port)
6596             self.assert_packet_checksums_valid(p)
6597         except:
6598             self.logger.error(ppp("Unexpected or invalid packet:", p))
6599             raise
6600
6601         # from service VRF1 back to client VRF0
6602         p = (Ether(src=self.pg5.remote_mac, dst=self.pg5.local_mac) /
6603              IP(src=self.pg5.remote_ip4, dst=self.pg0.remote_ip4) /
6604              TCP(sport=local_port, dport=12347))
6605         self.pg5.add_stream(p)
6606         self.pg_enable_capture(self.pg_interfaces)
6607         self.pg_start()
6608         capture = self.pg0.get_capture(1)
6609         p = capture[0]
6610         try:
6611             ip = p[IP]
6612             tcp = p[TCP]
6613             self.assertEqual(ip.src, external_addr)
6614             self.assertEqual(tcp.sport, external_port)
6615             self.assert_packet_checksums_valid(p)
6616         except:
6617             self.logger.error(ppp("Unexpected or invalid packet:", p))
6618             raise
6619
6620         # from client to server (both VRF1, no translation)
6621         p = (Ether(src=self.pg6.remote_mac, dst=self.pg6.local_mac) /
6622              IP(src=self.pg6.remote_ip4, dst=self.pg5.remote_ip4) /
6623              TCP(sport=12348, dport=local_port))
6624         self.pg6.add_stream(p)
6625         self.pg_enable_capture(self.pg_interfaces)
6626         self.pg_start()
6627         capture = self.pg5.get_capture(1)
6628         p = capture[0]
6629         try:
6630             ip = p[IP]
6631             tcp = p[TCP]
6632             self.assertEqual(ip.dst, self.pg5.remote_ip4)
6633             self.assertEqual(tcp.dport, local_port)
6634             self.assert_packet_checksums_valid(p)
6635         except:
6636             self.logger.error(ppp("Unexpected or invalid packet:", p))
6637             raise
6638
6639         # from server back to client (both VRF1, no translation)
6640         p = (Ether(src=self.pg5.remote_mac, dst=self.pg5.local_mac) /
6641              IP(src=self.pg5.remote_ip4, dst=self.pg6.remote_ip4) /
6642              TCP(sport=local_port, dport=12348))
6643         self.pg5.add_stream(p)
6644         self.pg_enable_capture(self.pg_interfaces)
6645         self.pg_start()
6646         capture = self.pg6.get_capture(1)
6647         p = capture[0]
6648         try:
6649             ip = p[IP]
6650             tcp = p[TCP]
6651             self.assertEqual(ip.src, self.pg5.remote_ip4)
6652             self.assertEqual(tcp.sport, local_port)
6653             self.assert_packet_checksums_valid(p)
6654         except:
6655             self.logger.error(ppp("Unexpected or invalid packet:", p))
6656             raise
6657
6658         # from client VRF1 to server VRF0 (no translation)
6659         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6660              IP(src=self.pg0.remote_ip4, dst=self.pg6.remote_ip4) /
6661              TCP(sport=local_port, dport=12349))
6662         self.pg0.add_stream(p)
6663         self.pg_enable_capture(self.pg_interfaces)
6664         self.pg_start()
6665         capture = self.pg6.get_capture(1)
6666         p = capture[0]
6667         try:
6668             ip = p[IP]
6669             tcp = p[TCP]
6670             self.assertEqual(ip.src, self.pg0.remote_ip4)
6671             self.assertEqual(tcp.sport, local_port)
6672             self.assert_packet_checksums_valid(p)
6673         except:
6674             self.logger.error(ppp("Unexpected or invalid packet:", p))
6675             raise
6676
6677         # from server VRF0 back to client VRF1 (no translation)
6678         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6679              IP(src=self.pg0.remote_ip4, dst=self.pg6.remote_ip4) /
6680              TCP(sport=local_port, dport=12349))
6681         self.pg0.add_stream(p)
6682         self.pg_enable_capture(self.pg_interfaces)
6683         self.pg_start()
6684         capture = self.pg6.get_capture(1)
6685         p = capture[0]
6686         try:
6687             ip = p[IP]
6688             tcp = p[TCP]
6689             self.assertEqual(ip.src, self.pg0.remote_ip4)
6690             self.assertEqual(tcp.sport, local_port)
6691             self.assert_packet_checksums_valid(p)
6692         except:
6693             self.logger.error(ppp("Unexpected or invalid packet:", p))
6694             raise
6695
6696         # from client VRF0 to server VRF1 (no translation)
6697         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6698              IP(src=self.pg0.remote_ip4, dst=self.pg5.remote_ip4) /
6699              TCP(sport=12344, dport=local_port))
6700         self.pg0.add_stream(p)
6701         self.pg_enable_capture(self.pg_interfaces)
6702         self.pg_start()
6703         capture = self.pg5.get_capture(1)
6704         p = capture[0]
6705         try:
6706             ip = p[IP]
6707             tcp = p[TCP]
6708             self.assertEqual(ip.dst, self.pg5.remote_ip4)
6709             self.assertEqual(tcp.dport, local_port)
6710             self.assert_packet_checksums_valid(p)
6711         except:
6712             self.logger.error(ppp("Unexpected or invalid packet:", p))
6713             raise
6714
6715         # from server VRF1 back to client VRF0 (no translation)
6716         p = (Ether(src=self.pg5.remote_mac, dst=self.pg5.local_mac) /
6717              IP(src=self.pg5.remote_ip4, dst=self.pg0.remote_ip4) /
6718              TCP(sport=local_port, dport=12344))
6719         self.pg5.add_stream(p)
6720         self.pg_enable_capture(self.pg_interfaces)
6721         self.pg_start()
6722         capture = self.pg0.get_capture(1)
6723         p = capture[0]
6724         try:
6725             ip = p[IP]
6726             tcp = p[TCP]
6727             self.assertEqual(ip.src, self.pg5.remote_ip4)
6728             self.assertEqual(tcp.sport, local_port)
6729             self.assert_packet_checksums_valid(p)
6730         except:
6731             self.logger.error(ppp("Unexpected or invalid packet:", p))
6732             raise
6733
6734     @unittest.skipUnless(running_extended_tests, "part of extended tests")
6735     def test_session_timeout(self):
6736         """ NAT44 session timeouts """
6737         self.nat44_add_address(self.nat_addr)
6738         flags = self.config_flags.NAT_IS_INSIDE
6739         self.vapi.nat44_interface_add_del_feature(
6740             sw_if_index=self.pg0.sw_if_index,
6741             flags=flags, is_add=1)
6742         self.vapi.nat44_interface_add_del_feature(
6743             sw_if_index=self.pg1.sw_if_index,
6744             is_add=1)
6745         self.vapi.nat_set_timeouts(udp=300, tcp_established=7440,
6746                                    tcp_transitory=240, icmp=5)
6747
6748         max_sessions = 1000
6749         pkts = []
6750         for i in range(0, max_sessions):
6751             src = "10.10.%u.%u" % ((i & 0xFF00) >> 8, i & 0xFF)
6752             p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
6753                  IP(src=src, dst=self.pg1.remote_ip4) /
6754                  ICMP(id=1025, type='echo-request'))
6755             pkts.append(p)
6756         self.pg0.add_stream(pkts)
6757         self.pg_enable_capture(self.pg_interfaces)
6758         self.pg_start()
6759         self.pg1.get_capture(max_sessions)
6760
6761         sleep(10)
6762
6763         pkts = []
6764         for i in range(0, max_sessions):
6765             src = "10.11.%u.%u" % ((i & 0xFF00) >> 8, i & 0xFF)
6766             p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
6767                  IP(src=src, dst=self.pg1.remote_ip4) /
6768                  ICMP(id=1026, type='echo-request'))
6769             pkts.append(p)
6770         self.pg0.add_stream(pkts)
6771         self.pg_enable_capture(self.pg_interfaces)
6772         self.pg_start()
6773         self.pg1.get_capture(max_sessions)
6774
6775         nsessions = 0
6776         users = self.vapi.nat44_user_dump()
6777         for user in users:
6778             nsessions = nsessions + user.nsessions
6779         self.assertLess(nsessions, 2 * max_sessions)
6780
6781     @unittest.skipUnless(running_extended_tests, "part of extended tests")
6782     def test_session_rst_timeout(self):
6783         """ NAT44 session RST timeouts """
6784         self.nat44_add_address(self.nat_addr)
6785         flags = self.config_flags.NAT_IS_INSIDE
6786         self.vapi.nat44_interface_add_del_feature(
6787             sw_if_index=self.pg0.sw_if_index,
6788             flags=flags, is_add=1)
6789         self.vapi.nat44_interface_add_del_feature(
6790             sw_if_index=self.pg1.sw_if_index,
6791             is_add=1)
6792         self.vapi.nat_set_timeouts(udp=300, tcp_established=7440,
6793                                    tcp_transitory=5, icmp=60)
6794
6795         self.initiate_tcp_session(self.pg0, self.pg1)
6796         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6797              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6798              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
6799                  flags="R"))
6800         self.pg0.add_stream(p)
6801         self.pg_enable_capture(self.pg_interfaces)
6802         self.pg_start()
6803         self.pg1.get_capture(1)
6804
6805         sleep(6)
6806
6807         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6808              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6809              TCP(sport=self.tcp_port_in + 1, dport=self.tcp_external_port + 1,
6810                  flags="S"))
6811         self.pg0.add_stream(p)
6812         self.pg_enable_capture(self.pg_interfaces)
6813         self.pg_start()
6814         self.pg1.get_capture(1)
6815
6816     def test_syslog_sess(self):
6817         """ Test syslog session creation and deletion """
6818         self.vapi.syslog_set_filter(
6819             self.SYSLOG_SEVERITY.SYSLOG_API_SEVERITY_INFO)
6820         self.vapi.syslog_set_sender(self.pg2.local_ip4, self.pg2.remote_ip4)
6821         self.nat44_add_address(self.nat_addr)
6822         flags = self.config_flags.NAT_IS_INSIDE
6823         self.vapi.nat44_interface_add_del_feature(
6824             sw_if_index=self.pg0.sw_if_index,
6825             flags=flags, is_add=1)
6826         self.vapi.nat44_interface_add_del_feature(
6827             sw_if_index=self.pg1.sw_if_index,
6828             is_add=1)
6829
6830         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
6831              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6832              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port))
6833         self.pg0.add_stream(p)
6834         self.pg_enable_capture(self.pg_interfaces)
6835         self.pg_start()
6836         capture = self.pg1.get_capture(1)
6837         self.tcp_port_out = capture[0][TCP].sport
6838         capture = self.pg2.get_capture(1)
6839         self.verify_syslog_sess(capture[0][Raw].load)
6840
6841         self.pg_enable_capture(self.pg_interfaces)
6842         self.pg_start()
6843         self.nat44_add_address(self.nat_addr, is_add=0)
6844         capture = self.pg2.get_capture(1)
6845         self.verify_syslog_sess(capture[0][Raw].load, False)
6846
6847     def tearDown(self):
6848         super(TestNAT44EndpointDependent, self).tearDown()
6849         if not self.vpp_dead:
6850             self.clear_nat44()
6851             self.vapi.cli("clear logging")
6852
6853     def show_commands_at_teardown(self):
6854         self.logger.info(self.vapi.cli("show nat44 addresses"))
6855         self.logger.info(self.vapi.cli("show nat44 interfaces"))
6856         self.logger.info(self.vapi.cli("show nat44 static mappings"))
6857         self.logger.info(self.vapi.cli("show nat44 interface address"))
6858         self.logger.info(self.vapi.cli("show nat44 sessions detail"))
6859         self.logger.info(self.vapi.cli("show nat44 hash tables detail"))
6860         self.logger.info(self.vapi.cli("show nat timeouts"))
6861
6862
6863 class TestNAT44Out2InDPO(MethodHolder):
6864     """ NAT44 Test Cases using out2in DPO """
6865
6866     @classmethod
6867     def setUpConstants(cls):
6868         super(TestNAT44Out2InDPO, cls).setUpConstants()
6869         cls.vpp_cmdline.extend(["nat", "{", "out2in dpo", "}"])
6870
6871     @classmethod
6872     def setUpClass(cls):
6873         super(TestNAT44Out2InDPO, cls).setUpClass()
6874         cls.vapi.cli("set log class nat level debug")
6875
6876         cls.tcp_port_in = 6303
6877         cls.tcp_port_out = 6303
6878         cls.udp_port_in = 6304
6879         cls.udp_port_out = 6304
6880         cls.icmp_id_in = 6305
6881         cls.icmp_id_out = 6305
6882         cls.nat_addr = '10.0.0.3'
6883         cls.dst_ip4 = '192.168.70.1'
6884
6885         cls.create_pg_interfaces(range(2))
6886
6887         cls.pg0.admin_up()
6888         cls.pg0.config_ip4()
6889         cls.pg0.resolve_arp()
6890
6891         cls.pg1.admin_up()
6892         cls.pg1.config_ip6()
6893         cls.pg1.resolve_ndp()
6894
6895         r1 = VppIpRoute(cls, "::", 0,
6896                         [VppRoutePath(cls.pg1.remote_ip6,
6897                                       cls.pg1.sw_if_index)],
6898                         register=False)
6899         r1.add_vpp_config()
6900
6901     @classmethod
6902     def tearDownClass(cls):
6903         super(TestNAT44Out2InDPO, cls).tearDownClass()
6904
6905     def configure_xlat(self):
6906         self.dst_ip6_pfx = '1:2:3::'
6907         self.dst_ip6_pfx_n = socket.inet_pton(socket.AF_INET6,
6908                                               self.dst_ip6_pfx)
6909         self.dst_ip6_pfx_len = 96
6910         self.src_ip6_pfx = '4:5:6::'
6911         self.src_ip6_pfx_n = socket.inet_pton(socket.AF_INET6,
6912                                               self.src_ip6_pfx)
6913         self.src_ip6_pfx_len = 96
6914         self.vapi.map_add_domain(self.dst_ip6_pfx_n, self.dst_ip6_pfx_len,
6915                                  self.src_ip6_pfx_n, self.src_ip6_pfx_len,
6916                                  '\x00\x00\x00\x00', 0)
6917
6918     @unittest.skip('Temporary disabled')
6919     def test_464xlat_ce(self):
6920         """ Test 464XLAT CE with NAT44 """
6921
6922         nat_config = self.vapi.nat_show_config()
6923         self.assertEqual(1, nat_config.out2in_dpo)
6924
6925         self.configure_xlat()
6926
6927         flags = self.config_flags.NAT_IS_INSIDE
6928         self.vapi.nat44_interface_add_del_feature(
6929             sw_if_index=self.pg0.sw_if_index,
6930             flags=flags, is_add=1)
6931         self.vapi.nat44_add_del_address_range(first_ip_address=self.nat_addr_n,
6932                                               last_ip_address=self.nat_addr_n,
6933                                               vrf_id=0xFFFFFFFF, is_add=1)
6934
6935         out_src_ip6 = self.compose_ip6(self.dst_ip4, self.dst_ip6_pfx,
6936                                        self.dst_ip6_pfx_len)
6937         out_dst_ip6 = self.compose_ip6(self.nat_addr, self.src_ip6_pfx,
6938                                        self.src_ip6_pfx_len)
6939
6940         try:
6941             pkts = self.create_stream_in(self.pg0, self.pg1, self.dst_ip4)
6942             self.pg0.add_stream(pkts)
6943             self.pg_enable_capture(self.pg_interfaces)
6944             self.pg_start()
6945             capture = self.pg1.get_capture(len(pkts))
6946             self.verify_capture_out_ip6(capture, nat_ip=out_dst_ip6,
6947                                         dst_ip=out_src_ip6)
6948
6949             pkts = self.create_stream_out_ip6(self.pg1, out_src_ip6,
6950                                               out_dst_ip6)
6951             self.pg1.add_stream(pkts)
6952             self.pg_enable_capture(self.pg_interfaces)
6953             self.pg_start()
6954             capture = self.pg0.get_capture(len(pkts))
6955             self.verify_capture_in(capture, self.pg0)
6956         finally:
6957             self.vapi.nat44_interface_add_del_feature(
6958                 sw_if_index=self.pg0.sw_if_index,
6959                 flags=flags)
6960             self.vapi.nat44_add_del_address_range(
6961                 first_ip_address=self.nat_addr_n,
6962                 last_ip_address=self.nat_addr_n,
6963                 vrf_id=0xFFFFFFFF)
6964
6965     @unittest.skip('Temporary disabled')
6966     def test_464xlat_ce_no_nat(self):
6967         """ Test 464XLAT CE without NAT44 """
6968
6969         self.configure_xlat()
6970
6971         out_src_ip6 = self.compose_ip6(self.dst_ip4, self.dst_ip6_pfx,
6972                                        self.dst_ip6_pfx_len)
6973         out_dst_ip6 = self.compose_ip6(self.pg0.remote_ip4, self.src_ip6_pfx,
6974                                        self.src_ip6_pfx_len)
6975
6976         pkts = self.create_stream_in(self.pg0, self.pg1, self.dst_ip4)
6977         self.pg0.add_stream(pkts)
6978         self.pg_enable_capture(self.pg_interfaces)
6979         self.pg_start()
6980         capture = self.pg1.get_capture(len(pkts))
6981         self.verify_capture_out_ip6(capture, dst_ip=out_src_ip6,
6982                                     nat_ip=out_dst_ip6, same_port=True)
6983
6984         pkts = self.create_stream_out_ip6(self.pg1, out_src_ip6, out_dst_ip6)
6985         self.pg1.add_stream(pkts)
6986         self.pg_enable_capture(self.pg_interfaces)
6987         self.pg_start()
6988         capture = self.pg0.get_capture(len(pkts))
6989         self.verify_capture_in(capture, self.pg0)
6990
6991
6992 class TestDeterministicNAT(MethodHolder):
6993     """ Deterministic NAT Test Cases """
6994
6995     @classmethod
6996     def setUpConstants(cls):
6997         super(TestDeterministicNAT, cls).setUpConstants()
6998         cls.vpp_cmdline.extend(["nat", "{", "deterministic", "}"])
6999
7000     @classmethod
7001     def setUpClass(cls):
7002         super(TestDeterministicNAT, cls).setUpClass()
7003         cls.vapi.cli("set log class nat level debug")
7004
7005         cls.tcp_port_in = 6303
7006         cls.tcp_external_port = 6303
7007         cls.udp_port_in = 6304
7008         cls.udp_external_port = 6304
7009         cls.icmp_id_in = 6305
7010         cls.nat_addr = '10.0.0.3'
7011
7012         cls.create_pg_interfaces(range(3))
7013         cls.interfaces = list(cls.pg_interfaces)
7014
7015         for i in cls.interfaces:
7016             i.admin_up()
7017             i.config_ip4()
7018             i.resolve_arp()
7019
7020         cls.pg0.generate_remote_hosts(2)
7021         cls.pg0.configure_ipv4_neighbors()
7022
7023     @classmethod
7024     def tearDownClass(cls):
7025         super(TestDeterministicNAT, cls).tearDownClass()
7026
7027     def create_stream_in(self, in_if, out_if, ttl=64):
7028         """
7029         Create packet stream for inside network
7030
7031         :param in_if: Inside interface
7032         :param out_if: Outside interface
7033         :param ttl: TTL of generated packets
7034         """
7035         pkts = []
7036         # TCP
7037         p = (Ether(dst=in_if.local_mac, src=in_if.remote_mac) /
7038              IP(src=in_if.remote_ip4, dst=out_if.remote_ip4, ttl=ttl) /
7039              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port))
7040         pkts.append(p)
7041
7042         # UDP
7043         p = (Ether(dst=in_if.local_mac, src=in_if.remote_mac) /
7044              IP(src=in_if.remote_ip4, dst=out_if.remote_ip4, ttl=ttl) /
7045              UDP(sport=self.udp_port_in, dport=self.udp_external_port))
7046         pkts.append(p)
7047
7048         # ICMP
7049         p = (Ether(dst=in_if.local_mac, src=in_if.remote_mac) /
7050              IP(src=in_if.remote_ip4, dst=out_if.remote_ip4, ttl=ttl) /
7051              ICMP(id=self.icmp_id_in, type='echo-request'))
7052         pkts.append(p)
7053
7054         return pkts
7055
7056     def create_stream_out(self, out_if, dst_ip=None, ttl=64):
7057         """
7058         Create packet stream for outside network
7059
7060         :param out_if: Outside interface
7061         :param dst_ip: Destination IP address (Default use global NAT address)
7062         :param ttl: TTL of generated packets
7063         """
7064         if dst_ip is None:
7065             dst_ip = self.nat_addr
7066         pkts = []
7067         # TCP
7068         p = (Ether(dst=out_if.local_mac, src=out_if.remote_mac) /
7069              IP(src=out_if.remote_ip4, dst=dst_ip, ttl=ttl) /
7070              TCP(dport=self.tcp_port_out, sport=self.tcp_external_port))
7071         pkts.append(p)
7072
7073         # UDP
7074         p = (Ether(dst=out_if.local_mac, src=out_if.remote_mac) /
7075              IP(src=out_if.remote_ip4, dst=dst_ip, ttl=ttl) /
7076              UDP(dport=self.udp_port_out, sport=self.udp_external_port))
7077         pkts.append(p)
7078
7079         # ICMP
7080         p = (Ether(dst=out_if.local_mac, src=out_if.remote_mac) /
7081              IP(src=out_if.remote_ip4, dst=dst_ip, ttl=ttl) /
7082              ICMP(id=self.icmp_external_id, type='echo-reply'))
7083         pkts.append(p)
7084
7085         return pkts
7086
7087     def verify_capture_out(self, capture, nat_ip=None):
7088         """
7089         Verify captured packets on outside network
7090
7091         :param capture: Captured packets
7092         :param nat_ip: Translated IP address (Default use global NAT address)
7093         :param same_port: Source port number is not translated (Default False)
7094         """
7095         if nat_ip is None:
7096             nat_ip = self.nat_addr
7097         for packet in capture:
7098             try:
7099                 self.assertEqual(packet[IP].src, nat_ip)
7100                 if packet.haslayer(TCP):
7101                     self.tcp_port_out = packet[TCP].sport
7102                 elif packet.haslayer(UDP):
7103                     self.udp_port_out = packet[UDP].sport
7104                 else:
7105                     self.icmp_external_id = packet[ICMP].id
7106             except:
7107                 self.logger.error(ppp("Unexpected or invalid packet "
7108                                       "(outside network):", packet))
7109                 raise
7110
7111     def test_deterministic_mode(self):
7112         """ NAT plugin run deterministic mode """
7113         in_addr = '172.16.255.0'
7114         out_addr = '172.17.255.50'
7115         in_addr_t = '172.16.255.20'
7116         in_plen = 24
7117         out_plen = 32
7118
7119         nat_config = self.vapi.nat_show_config()
7120         self.assertEqual(1, nat_config.deterministic)
7121
7122         self.vapi.nat_det_add_del_map(is_add=1, in_addr=in_addr,
7123                                       in_plen=in_plen, out_addr=out_addr,
7124                                       out_plen=out_plen)
7125
7126         rep1 = self.vapi.nat_det_forward(in_addr_t)
7127         self.assertEqual(str(rep1.out_addr), out_addr)
7128         rep2 = self.vapi.nat_det_reverse(rep1.out_port_hi, out_addr)
7129
7130         self.assertEqual(str(rep2.in_addr), in_addr_t)
7131
7132         deterministic_mappings = self.vapi.nat_det_map_dump()
7133         self.assertEqual(len(deterministic_mappings), 1)
7134         dsm = deterministic_mappings[0]
7135         self.assertEqual(in_addr, str(dsm.in_addr))
7136         self.assertEqual(in_plen, dsm.in_plen)
7137         self.assertEqual(out_addr, str(dsm.out_addr))
7138         self.assertEqual(out_plen, dsm.out_plen)
7139
7140         self.clear_nat_det()
7141         deterministic_mappings = self.vapi.nat_det_map_dump()
7142         self.assertEqual(len(deterministic_mappings), 0)
7143
7144     def test_set_timeouts(self):
7145         """ Set deterministic NAT timeouts """
7146         timeouts_before = self.vapi.nat_get_timeouts()
7147
7148         self.vapi.nat_set_timeouts(
7149             udp=timeouts_before.udp + 10,
7150             tcp_established=timeouts_before.tcp_established + 10,
7151             tcp_transitory=timeouts_before.tcp_transitory + 10,
7152             icmp=timeouts_before.icmp + 10)
7153
7154         timeouts_after = self.vapi.nat_get_timeouts()
7155
7156         self.assertNotEqual(timeouts_before.udp, timeouts_after.udp)
7157         self.assertNotEqual(timeouts_before.icmp, timeouts_after.icmp)
7158         self.assertNotEqual(timeouts_before.tcp_established,
7159                             timeouts_after.tcp_established)
7160         self.assertNotEqual(timeouts_before.tcp_transitory,
7161                             timeouts_after.tcp_transitory)
7162
7163     def test_det_in(self):
7164         """ Deterministic NAT translation test (TCP, UDP, ICMP) """
7165
7166         nat_ip = "10.0.0.10"
7167
7168         self.vapi.nat_det_add_del_map(is_add=1, in_addr=self.pg0.remote_ip4,
7169                                       in_plen=32,
7170                                       out_addr=socket.inet_aton(nat_ip),
7171                                       out_plen=32)
7172
7173         flags = self.config_flags.NAT_IS_INSIDE
7174         self.vapi.nat44_interface_add_del_feature(
7175             sw_if_index=self.pg0.sw_if_index,
7176             flags=flags, is_add=1)
7177         self.vapi.nat44_interface_add_del_feature(
7178             sw_if_index=self.pg1.sw_if_index,
7179             is_add=1)
7180
7181         # in2out
7182         pkts = self.create_stream_in(self.pg0, self.pg1)
7183         self.pg0.add_stream(pkts)
7184         self.pg_enable_capture(self.pg_interfaces)
7185         self.pg_start()
7186         capture = self.pg1.get_capture(len(pkts))
7187         self.verify_capture_out(capture, nat_ip)
7188
7189         # out2in
7190         pkts = self.create_stream_out(self.pg1, nat_ip)
7191         self.pg1.add_stream(pkts)
7192         self.pg_enable_capture(self.pg_interfaces)
7193         self.pg_start()
7194         capture = self.pg0.get_capture(len(pkts))
7195         self.verify_capture_in(capture, self.pg0)
7196
7197         # session dump test
7198         sessions = self.vapi.nat_det_session_dump(self.pg0.remote_ip4)
7199         self.assertEqual(len(sessions), 3)
7200
7201         # TCP session
7202         s = sessions[0]
7203         self.assertEqual(str(s.ext_addr), self.pg1.remote_ip4)
7204         self.assertEqual(s.in_port, self.tcp_port_in)
7205         self.assertEqual(s.out_port, self.tcp_port_out)
7206         self.assertEqual(s.ext_port, self.tcp_external_port)
7207
7208         # UDP session
7209         s = sessions[1]
7210         self.assertEqual(str(s.ext_addr), self.pg1.remote_ip4)
7211         self.assertEqual(s.in_port, self.udp_port_in)
7212         self.assertEqual(s.out_port, self.udp_port_out)
7213         self.assertEqual(s.ext_port, self.udp_external_port)
7214
7215         # ICMP session
7216         s = sessions[2]
7217         self.assertEqual(str(s.ext_addr), self.pg1.remote_ip4)
7218         self.assertEqual(s.in_port, self.icmp_id_in)
7219         self.assertEqual(s.out_port, self.icmp_external_id)
7220
7221     def test_multiple_users(self):
7222         """ Deterministic NAT multiple users """
7223
7224         nat_ip = "10.0.0.10"
7225         port_in = 80
7226         external_port = 6303
7227
7228         host0 = self.pg0.remote_hosts[0]
7229         host1 = self.pg0.remote_hosts[1]
7230
7231         self.vapi.nat_det_add_del_map(is_add=1, in_addr=host0.ip4, in_plen=24,
7232                                       out_addr=socket.inet_aton(nat_ip),
7233                                       out_plen=32)
7234         flags = self.config_flags.NAT_IS_INSIDE
7235         self.vapi.nat44_interface_add_del_feature(
7236             sw_if_index=self.pg0.sw_if_index,
7237             flags=flags, is_add=1)
7238         self.vapi.nat44_interface_add_del_feature(
7239             sw_if_index=self.pg1.sw_if_index,
7240             is_add=1)
7241
7242         # host0 to out
7243         p = (Ether(src=host0.mac, dst=self.pg0.local_mac) /
7244              IP(src=host0.ip4, dst=self.pg1.remote_ip4) /
7245              TCP(sport=port_in, dport=external_port))
7246         self.pg0.add_stream(p)
7247         self.pg_enable_capture(self.pg_interfaces)
7248         self.pg_start()
7249         capture = self.pg1.get_capture(1)
7250         p = capture[0]
7251         try:
7252             ip = p[IP]
7253             tcp = p[TCP]
7254             self.assertEqual(ip.src, nat_ip)
7255             self.assertEqual(ip.dst, self.pg1.remote_ip4)
7256             self.assertEqual(tcp.dport, external_port)
7257             port_out0 = tcp.sport
7258         except:
7259             self.logger.error(ppp("Unexpected or invalid packet:", p))
7260             raise
7261
7262         # host1 to out
7263         p = (Ether(src=host1.mac, dst=self.pg0.local_mac) /
7264              IP(src=host1.ip4, dst=self.pg1.remote_ip4) /
7265              TCP(sport=port_in, dport=external_port))
7266         self.pg0.add_stream(p)
7267         self.pg_enable_capture(self.pg_interfaces)
7268         self.pg_start()
7269         capture = self.pg1.get_capture(1)
7270         p = capture[0]
7271         try:
7272             ip = p[IP]
7273             tcp = p[TCP]
7274             self.assertEqual(ip.src, nat_ip)
7275             self.assertEqual(ip.dst, self.pg1.remote_ip4)
7276             self.assertEqual(tcp.dport, external_port)
7277             port_out1 = tcp.sport
7278         except:
7279             self.logger.error(ppp("Unexpected or invalid packet:", p))
7280             raise
7281
7282         dms = self.vapi.nat_det_map_dump()
7283         self.assertEqual(1, len(dms))
7284         self.assertEqual(2, dms[0].ses_num)
7285
7286         # out to host0
7287         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
7288              IP(src=self.pg1.remote_ip4, dst=nat_ip) /
7289              TCP(sport=external_port, dport=port_out0))
7290         self.pg1.add_stream(p)
7291         self.pg_enable_capture(self.pg_interfaces)
7292         self.pg_start()
7293         capture = self.pg0.get_capture(1)
7294         p = capture[0]
7295         try:
7296             ip = p[IP]
7297             tcp = p[TCP]
7298             self.assertEqual(ip.src, self.pg1.remote_ip4)
7299             self.assertEqual(ip.dst, host0.ip4)
7300             self.assertEqual(tcp.dport, port_in)
7301             self.assertEqual(tcp.sport, external_port)
7302         except:
7303             self.logger.error(ppp("Unexpected or invalid packet:", p))
7304             raise
7305
7306         # out to host1
7307         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
7308              IP(src=self.pg1.remote_ip4, dst=nat_ip) /
7309              TCP(sport=external_port, dport=port_out1))
7310         self.pg1.add_stream(p)
7311         self.pg_enable_capture(self.pg_interfaces)
7312         self.pg_start()
7313         capture = self.pg0.get_capture(1)
7314         p = capture[0]
7315         try:
7316             ip = p[IP]
7317             tcp = p[TCP]
7318             self.assertEqual(ip.src, self.pg1.remote_ip4)
7319             self.assertEqual(ip.dst, host1.ip4)
7320             self.assertEqual(tcp.dport, port_in)
7321             self.assertEqual(tcp.sport, external_port)
7322         except:
7323             self.logger.error(ppp("Unexpected or invalid packet", p))
7324             raise
7325
7326         # session close api test
7327         self.vapi.nat_det_close_session_out(socket.inet_aton(nat_ip),
7328                                             port_out1,
7329                                             self.pg1.remote_ip4,
7330                                             external_port)
7331         dms = self.vapi.nat_det_map_dump()
7332         self.assertEqual(dms[0].ses_num, 1)
7333
7334         self.vapi.nat_det_close_session_in(host0.ip4,
7335                                            port_in,
7336                                            self.pg1.remote_ip4,
7337                                            external_port)
7338         dms = self.vapi.nat_det_map_dump()
7339         self.assertEqual(dms[0].ses_num, 0)
7340
7341     def test_tcp_session_close_detection_in(self):
7342         """ Deterministic NAT TCP session close from inside network """
7343         self.vapi.nat_det_add_del_map(is_add=1, in_addr=self.pg0.remote_ip4,
7344                                       in_plen=32,
7345                                       out_addr=socket.inet_aton(self.nat_addr),
7346                                       out_plen=32)
7347         flags = self.config_flags.NAT_IS_INSIDE
7348         self.vapi.nat44_interface_add_del_feature(
7349             sw_if_index=self.pg0.sw_if_index,
7350             flags=flags, is_add=1)
7351         self.vapi.nat44_interface_add_del_feature(
7352             sw_if_index=self.pg1.sw_if_index,
7353             is_add=1)
7354
7355         self.initiate_tcp_session(self.pg0, self.pg1)
7356
7357         # close the session from inside
7358         try:
7359             # FIN packet in -> out
7360             p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
7361                  IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
7362                  TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
7363                      flags="F"))
7364             self.pg0.add_stream(p)
7365             self.pg_enable_capture(self.pg_interfaces)
7366             self.pg_start()
7367             self.pg1.get_capture(1)
7368
7369             pkts = []
7370
7371             # ACK packet out -> in
7372             p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
7373                  IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
7374                  TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
7375                      flags="A"))
7376             pkts.append(p)
7377
7378             # FIN packet out -> in
7379             p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
7380                  IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
7381                  TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
7382                      flags="F"))
7383             pkts.append(p)
7384
7385             self.pg1.add_stream(pkts)
7386             self.pg_enable_capture(self.pg_interfaces)
7387             self.pg_start()
7388             self.pg0.get_capture(2)
7389
7390             # ACK packet in -> out
7391             p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
7392                  IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
7393                  TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
7394                      flags="A"))
7395             self.pg0.add_stream(p)
7396             self.pg_enable_capture(self.pg_interfaces)
7397             self.pg_start()
7398             self.pg1.get_capture(1)
7399
7400             # Check if deterministic NAT44 closed the session
7401             dms = self.vapi.nat_det_map_dump()
7402             self.assertEqual(0, dms[0].ses_num)
7403         except:
7404             self.logger.error("TCP session termination failed")
7405             raise
7406
7407     def test_tcp_session_close_detection_out(self):
7408         """ Deterministic NAT TCP session close from outside network """
7409         self.vapi.nat_det_add_del_map(is_add=1, in_addr=self.pg0.remote_ip4,
7410                                       in_plen=32,
7411                                       out_addr=socket.inet_aton(self.nat_addr),
7412                                       out_plen=32)
7413         flags = self.config_flags.NAT_IS_INSIDE
7414         self.vapi.nat44_interface_add_del_feature(
7415             sw_if_index=self.pg0.sw_if_index,
7416             flags=flags, is_add=1)
7417         self.vapi.nat44_interface_add_del_feature(
7418             sw_if_index=self.pg1.sw_if_index,
7419             is_add=1)
7420
7421         self.initiate_tcp_session(self.pg0, self.pg1)
7422
7423         # close the session from outside
7424         try:
7425             # FIN packet out -> in
7426             p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
7427                  IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
7428                  TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
7429                      flags="F"))
7430             self.pg1.add_stream(p)
7431             self.pg_enable_capture(self.pg_interfaces)
7432             self.pg_start()
7433             self.pg0.get_capture(1)
7434
7435             pkts = []
7436
7437             # ACK packet in -> out
7438             p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
7439                  IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
7440                  TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
7441                      flags="A"))
7442             pkts.append(p)
7443
7444             # ACK packet in -> out
7445             p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
7446                  IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
7447                  TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
7448                      flags="F"))
7449             pkts.append(p)
7450
7451             self.pg0.add_stream(pkts)
7452             self.pg_enable_capture(self.pg_interfaces)
7453             self.pg_start()
7454             self.pg1.get_capture(2)
7455
7456             # ACK packet out -> in
7457             p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
7458                  IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
7459                  TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
7460                      flags="A"))
7461             self.pg1.add_stream(p)
7462             self.pg_enable_capture(self.pg_interfaces)
7463             self.pg_start()
7464             self.pg0.get_capture(1)
7465
7466             # Check if deterministic NAT44 closed the session
7467             dms = self.vapi.nat_det_map_dump()
7468             self.assertEqual(0, dms[0].ses_num)
7469         except:
7470             self.logger.error("TCP session termination failed")
7471             raise
7472
7473     @unittest.skipUnless(running_extended_tests, "part of extended tests")
7474     def test_session_timeout(self):
7475         """ Deterministic NAT session timeouts """
7476         self.vapi.nat_det_add_del_map(is_add=1, in_addr=self.pg0.remote_ip4,
7477                                       in_plen=32,
7478                                       out_addr=socket.inet_aton(self.nat_addr),
7479                                       out_plen=32)
7480         flags = self.config_flags.NAT_IS_INSIDE
7481         self.vapi.nat44_interface_add_del_feature(
7482             sw_if_index=self.pg0.sw_if_index,
7483             flags=flags, is_add=1)
7484         self.vapi.nat44_interface_add_del_feature(
7485             sw_if_index=self.pg1.sw_if_index,
7486             is_add=1)
7487
7488         self.initiate_tcp_session(self.pg0, self.pg1)
7489         self.vapi.nat_set_timeouts(udp=5, tcp_established=5, tcp_transitory=5,
7490                                    icmp=5)
7491         pkts = self.create_stream_in(self.pg0, self.pg1)
7492         self.pg0.add_stream(pkts)
7493         self.pg_enable_capture(self.pg_interfaces)
7494         self.pg_start()
7495         capture = self.pg1.get_capture(len(pkts))
7496         sleep(15)
7497
7498         dms = self.vapi.nat_det_map_dump()
7499         self.assertEqual(0, dms[0].ses_num)
7500
7501     @unittest.skipUnless(running_extended_tests, "part of extended tests")
7502     def test_session_limit_per_user(self):
7503         """ Deterministic NAT maximum sessions per user limit """
7504         self.vapi.nat_det_add_del_map(is_add=1, in_addr=self.pg0.remote_ip4,
7505                                       in_plen=32,
7506                                       out_addr=socket.inet_aton(self.nat_addr),
7507                                       out_plen=32)
7508         flags = self.config_flags.NAT_IS_INSIDE
7509         self.vapi.nat44_interface_add_del_feature(
7510             sw_if_index=self.pg0.sw_if_index,
7511             flags=flags, is_add=1)
7512         self.vapi.nat44_interface_add_del_feature(
7513             sw_if_index=self.pg1.sw_if_index,
7514             is_add=1)
7515         self.vapi.set_ipfix_exporter(collector_address=self.pg2.remote_ip4,
7516                                      src_address=self.pg2.local_ip4,
7517                                      path_mtu=512,
7518                                      template_interval=10)
7519         self.vapi.nat_ipfix_enable_disable(domain_id=1, src_port=4739,
7520                                            enable=1)
7521
7522         pkts = []
7523         for port in range(1025, 2025):
7524             p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
7525                  IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
7526                  UDP(sport=port, dport=port))
7527             pkts.append(p)
7528
7529         self.pg0.add_stream(pkts)
7530         self.pg_enable_capture(self.pg_interfaces)
7531         self.pg_start()
7532         capture = self.pg1.get_capture(len(pkts))
7533
7534         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
7535              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
7536              UDP(sport=3001, dport=3002))
7537         self.pg0.add_stream(p)
7538         self.pg_enable_capture(self.pg_interfaces)
7539         self.pg_start()
7540         capture = self.pg1.assert_nothing_captured()
7541
7542         # verify ICMP error packet
7543         capture = self.pg0.get_capture(1)
7544         p = capture[0]
7545         self.assertTrue(p.haslayer(ICMP))
7546         icmp = p[ICMP]
7547         self.assertEqual(icmp.type, 3)
7548         self.assertEqual(icmp.code, 1)
7549         self.assertTrue(icmp.haslayer(IPerror))
7550         inner_ip = icmp[IPerror]
7551         self.assertEqual(inner_ip[UDPerror].sport, 3001)
7552         self.assertEqual(inner_ip[UDPerror].dport, 3002)
7553
7554         dms = self.vapi.nat_det_map_dump()
7555
7556         self.assertEqual(1000, dms[0].ses_num)
7557
7558         # verify IPFIX logging
7559         self.vapi.ipfix_flush()
7560         sleep(1)
7561         capture = self.pg2.get_capture(2)
7562         ipfix = IPFIXDecoder()
7563         # first load template
7564         for p in capture:
7565             self.assertTrue(p.haslayer(IPFIX))
7566             if p.haslayer(Template):
7567                 ipfix.add_template(p.getlayer(Template))
7568         # verify events in data set
7569         for p in capture:
7570             if p.haslayer(Data):
7571                 data = ipfix.decode_data_set(p.getlayer(Set))
7572                 self.verify_ipfix_max_entries_per_user(data,
7573                                                        1000,
7574                                                        self.pg0.remote_ip4)
7575
7576     def clear_nat_det(self):
7577         """
7578         Clear deterministic NAT configuration.
7579         """
7580         self.vapi.nat_ipfix_enable_disable(domain_id=1, src_port=4739,
7581                                            enable=0)
7582         self.vapi.nat_set_timeouts(udp=300, tcp_established=7440,
7583                                    tcp_transitory=240, icmp=60)
7584         deterministic_mappings = self.vapi.nat_det_map_dump()
7585         for dsm in deterministic_mappings:
7586             self.vapi.nat_det_add_del_map(is_add=0, in_addr=dsm.in_addr,
7587                                           in_plen=dsm.in_plen,
7588                                           out_addr=dsm.out_addr,
7589                                           out_plen=dsm.out_plen)
7590
7591         interfaces = self.vapi.nat44_interface_dump()
7592         for intf in interfaces:
7593             self.vapi.nat44_interface_add_del_feature(
7594                 sw_if_index=intf.sw_if_index,
7595                 flags=intf.flags)
7596
7597     def tearDown(self):
7598         super(TestDeterministicNAT, self).tearDown()
7599         if not self.vpp_dead:
7600             self.clear_nat_det()
7601
7602     def show_commands_at_teardown(self):
7603         self.logger.info(self.vapi.cli("show nat44 interfaces"))
7604         self.logger.info(self.vapi.cli("show nat timeouts"))
7605         self.logger.info(
7606             self.vapi.cli("show nat44 deterministic mappings"))
7607         self.logger.info(
7608             self.vapi.cli("show nat44 deterministic sessions"))
7609
7610
7611 class TestNAT64(MethodHolder):
7612     """ NAT64 Test Cases """
7613
7614     @classmethod
7615     def setUpConstants(cls):
7616         super(TestNAT64, cls).setUpConstants()
7617         cls.vpp_cmdline.extend(["nat", "{", "nat64 bib hash buckets 128",
7618                                 "nat64 st hash buckets 256", "}"])
7619
7620     @classmethod
7621     def setUpClass(cls):
7622         super(TestNAT64, cls).setUpClass()
7623
7624         cls.tcp_port_in = 6303
7625         cls.tcp_port_out = 6303
7626         cls.udp_port_in = 6304
7627         cls.udp_port_out = 6304
7628         cls.icmp_id_in = 6305
7629         cls.icmp_id_out = 6305
7630         cls.tcp_external_port = 80
7631         cls.nat_addr = '10.0.0.3'
7632         cls.nat_addr_n = socket.inet_pton(socket.AF_INET, cls.nat_addr)
7633         cls.vrf1_id = 10
7634         cls.vrf1_nat_addr = '10.0.10.3'
7635         cls.ipfix_src_port = 4739
7636         cls.ipfix_domain_id = 1
7637
7638         cls.create_pg_interfaces(range(6))
7639         cls.ip6_interfaces = list(cls.pg_interfaces[0:1])
7640         cls.ip6_interfaces.append(cls.pg_interfaces[2])
7641         cls.ip4_interfaces = list(cls.pg_interfaces[1:2])
7642
7643         cls.vapi.ip_table_add_del(is_add=1,
7644                                   table={'table_id': cls.vrf1_id,
7645                                          'is_ip6': 1})
7646
7647         cls.pg_interfaces[2].set_table_ip6(cls.vrf1_id)
7648
7649         cls.pg0.generate_remote_hosts(2)
7650
7651         for i in cls.ip6_interfaces:
7652             i.admin_up()
7653             i.config_ip6()
7654             i.configure_ipv6_neighbors()
7655
7656         for i in cls.ip4_interfaces:
7657             i.admin_up()
7658             i.config_ip4()
7659             i.resolve_arp()
7660
7661         cls.pg3.admin_up()
7662         cls.pg3.config_ip4()
7663         cls.pg3.resolve_arp()
7664         cls.pg3.config_ip6()
7665         cls.pg3.configure_ipv6_neighbors()
7666
7667         cls.pg5.admin_up()
7668         cls.pg5.config_ip6()
7669
7670     @classmethod
7671     def tearDownClass(cls):
7672         super(TestNAT64, cls).tearDownClass()
7673
7674     def test_nat64_inside_interface_handles_neighbor_advertisement(self):
7675         """ NAT64 inside interface handles Neighbor Advertisement """
7676
7677         flags = self.config_flags.NAT_IS_INSIDE
7678         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
7679                                           sw_if_index=self.pg5.sw_if_index)
7680
7681         # Try to send ping
7682         ping = (Ether(dst=self.pg5.local_mac, src=self.pg5.remote_mac) /
7683                 IPv6(src=self.pg5.remote_ip6, dst=self.pg5.local_ip6) /
7684                 ICMPv6EchoRequest())
7685         pkts = [ping]
7686         self.pg5.add_stream(pkts)
7687         self.pg_enable_capture(self.pg_interfaces)
7688         self.pg_start()
7689
7690         # Wait for Neighbor Solicitation
7691         capture = self.pg5.get_capture(len(pkts))
7692         packet = capture[0]
7693         try:
7694             self.assertEqual(packet[IPv6].src, self.pg5.local_ip6)
7695             self.assertEqual(packet.haslayer(ICMPv6ND_NS), 1)
7696             tgt = packet[ICMPv6ND_NS].tgt
7697         except:
7698             self.logger.error(ppp("Unexpected or invalid packet:", packet))
7699             raise
7700
7701         # Send Neighbor Advertisement
7702         p = (Ether(dst=self.pg5.local_mac, src=self.pg5.remote_mac) /
7703              IPv6(src=self.pg5.remote_ip6, dst=self.pg5.local_ip6) /
7704              ICMPv6ND_NA(tgt=tgt) /
7705              ICMPv6NDOptDstLLAddr(lladdr=self.pg5.remote_mac))
7706         pkts = [p]
7707         self.pg5.add_stream(pkts)
7708         self.pg_enable_capture(self.pg_interfaces)
7709         self.pg_start()
7710
7711         # Try to send ping again
7712         pkts = [ping]
7713         self.pg5.add_stream(pkts)
7714         self.pg_enable_capture(self.pg_interfaces)
7715         self.pg_start()
7716
7717         # Wait for ping reply
7718         capture = self.pg5.get_capture(len(pkts))
7719         packet = capture[0]
7720         try:
7721             self.assertEqual(packet[IPv6].src, self.pg5.local_ip6)
7722             self.assertEqual(packet[IPv6].dst, self.pg5.remote_ip6)
7723             self.assertEqual(packet.haslayer(ICMPv6EchoReply), 1)
7724         except:
7725             self.logger.error(ppp("Unexpected or invalid packet:", packet))
7726             raise
7727
7728     def test_pool(self):
7729         """ Add/delete address to NAT64 pool """
7730         nat_addr = '1.2.3.4'
7731
7732         self.vapi.nat64_add_del_pool_addr_range(start_addr=nat_addr,
7733                                                 end_addr=nat_addr,
7734                                                 vrf_id=0xFFFFFFFF, is_add=1)
7735
7736         addresses = self.vapi.nat64_pool_addr_dump()
7737         self.assertEqual(len(addresses), 1)
7738         self.assertEqual(str(addresses[0].address), nat_addr)
7739
7740         self.vapi.nat64_add_del_pool_addr_range(start_addr=nat_addr,
7741                                                 end_addr=nat_addr,
7742                                                 vrf_id=0xFFFFFFFF, is_add=0)
7743
7744         addresses = self.vapi.nat64_pool_addr_dump()
7745         self.assertEqual(len(addresses), 0)
7746
7747     def test_interface(self):
7748         """ Enable/disable NAT64 feature on the interface """
7749         flags = self.config_flags.NAT_IS_INSIDE
7750         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
7751                                           sw_if_index=self.pg0.sw_if_index)
7752         self.vapi.nat64_add_del_interface(is_add=1, flags=0,
7753                                           sw_if_index=self.pg1.sw_if_index)
7754
7755         interfaces = self.vapi.nat64_interface_dump()
7756         self.assertEqual(len(interfaces), 2)
7757         pg0_found = False
7758         pg1_found = False
7759         for intf in interfaces:
7760             if intf.sw_if_index == self.pg0.sw_if_index:
7761                 self.assertEqual(intf.flags, self.config_flags.NAT_IS_INSIDE)
7762                 pg0_found = True
7763             elif intf.sw_if_index == self.pg1.sw_if_index:
7764                 self.assertEqual(intf.flags, self.config_flags.NAT_IS_OUTSIDE)
7765                 pg1_found = True
7766         self.assertTrue(pg0_found)
7767         self.assertTrue(pg1_found)
7768
7769         features = self.vapi.cli("show interface features pg0")
7770         self.assertIn('nat64-in2out', features)
7771         features = self.vapi.cli("show interface features pg1")
7772         self.assertIn('nat64-out2in', features)
7773
7774         self.vapi.nat64_add_del_interface(is_add=0, flags=flags,
7775                                           sw_if_index=self.pg0.sw_if_index)
7776         self.vapi.nat64_add_del_interface(is_add=0, flags=flags,
7777                                           sw_if_index=self.pg1.sw_if_index)
7778
7779         interfaces = self.vapi.nat64_interface_dump()
7780         self.assertEqual(len(interfaces), 0)
7781
7782     def test_static_bib(self):
7783         """ Add/delete static BIB entry """
7784         in_addr = '2001:db8:85a3::8a2e:370:7334'
7785         out_addr = '10.1.1.3'
7786         in_port = 1234
7787         out_port = 5678
7788         proto = IP_PROTOS.tcp
7789
7790         self.vapi.nat64_add_del_static_bib(i_addr=in_addr, o_addr=out_addr,
7791                                            i_port=in_port, o_port=out_port,
7792                                            proto=proto, vrf_id=0, is_add=1)
7793         bib = self.vapi.nat64_bib_dump(proto=IP_PROTOS.tcp)
7794         static_bib_num = 0
7795         for bibe in bib:
7796             if bibe.flags & self.config_flags.NAT_IS_STATIC:
7797                 static_bib_num += 1
7798                 self.assertEqual(str(bibe.i_addr), in_addr)
7799                 self.assertEqual(str(bibe.o_addr), out_addr)
7800                 self.assertEqual(bibe.i_port, in_port)
7801                 self.assertEqual(bibe.o_port, out_port)
7802         self.assertEqual(static_bib_num, 1)
7803         bibs = self.statistics.get_counter('/nat64/total-bibs')
7804         self.assertEqual(bibs[0][0], 1)
7805
7806         self.vapi.nat64_add_del_static_bib(i_addr=in_addr, o_addr=out_addr,
7807                                            i_port=in_port, o_port=out_port,
7808                                            proto=proto, vrf_id=0, is_add=0)
7809         bib = self.vapi.nat64_bib_dump(proto=IP_PROTOS.tcp)
7810         static_bib_num = 0
7811         for bibe in bib:
7812             if bibe.flags & self.config_flags.NAT_IS_STATIC:
7813                 static_bib_num += 1
7814         self.assertEqual(static_bib_num, 0)
7815         bibs = self.statistics.get_counter('/nat64/total-bibs')
7816         self.assertEqual(bibs[0][0], 0)
7817
7818     def test_set_timeouts(self):
7819         """ Set NAT64 timeouts """
7820         # verify default values
7821         timeouts = self.vapi.nat_get_timeouts()
7822         self.assertEqual(timeouts.udp, 300)
7823         self.assertEqual(timeouts.icmp, 60)
7824         self.assertEqual(timeouts.tcp_transitory, 240)
7825         self.assertEqual(timeouts.tcp_established, 7440)
7826
7827         # set and verify custom values
7828         self.vapi.nat_set_timeouts(udp=200, tcp_established=7450,
7829                                    tcp_transitory=250, icmp=30)
7830         timeouts = self.vapi.nat_get_timeouts()
7831         self.assertEqual(timeouts.udp, 200)
7832         self.assertEqual(timeouts.icmp, 30)
7833         self.assertEqual(timeouts.tcp_transitory, 250)
7834         self.assertEqual(timeouts.tcp_established, 7450)
7835
7836     def test_dynamic(self):
7837         """ NAT64 dynamic translation test """
7838         self.tcp_port_in = 6303
7839         self.udp_port_in = 6304
7840         self.icmp_id_in = 6305
7841
7842         ses_num_start = self.nat64_get_ses_num()
7843
7844         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr,
7845                                                 end_addr=self.nat_addr,
7846                                                 vrf_id=0xFFFFFFFF,
7847                                                 is_add=1)
7848         flags = self.config_flags.NAT_IS_INSIDE
7849         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
7850                                           sw_if_index=self.pg0.sw_if_index)
7851         self.vapi.nat64_add_del_interface(is_add=1, flags=0,
7852                                           sw_if_index=self.pg1.sw_if_index)
7853
7854         # in2out
7855         tcpn = self.statistics.get_err_counter('/err/nat64-in2out/TCP packets')
7856         udpn = self.statistics.get_err_counter('/err/nat64-in2out/UDP packets')
7857         icmpn = self.statistics.get_err_counter(
7858             '/err/nat64-in2out/ICMP packets')
7859         totaln = self.statistics.get_err_counter(
7860             '/err/nat64-in2out/good in2out packets processed')
7861
7862         pkts = self.create_stream_in_ip6(self.pg0, self.pg1)
7863         self.pg0.add_stream(pkts)
7864         self.pg_enable_capture(self.pg_interfaces)
7865         self.pg_start()
7866         capture = self.pg1.get_capture(len(pkts))
7867         self.verify_capture_out(capture, nat_ip=self.nat_addr,
7868                                 dst_ip=self.pg1.remote_ip4)
7869
7870         err = self.statistics.get_err_counter('/err/nat64-in2out/TCP packets')
7871         self.assertEqual(err - tcpn, 1)
7872         err = self.statistics.get_err_counter('/err/nat64-in2out/UDP packets')
7873         self.assertEqual(err - udpn, 1)
7874         err = self.statistics.get_err_counter('/err/nat64-in2out/ICMP packets')
7875         self.assertEqual(err - icmpn, 1)
7876         err = self.statistics.get_err_counter(
7877             '/err/nat64-in2out/good in2out packets processed')
7878         self.assertEqual(err - totaln, 3)
7879
7880         # out2in
7881         tcpn = self.statistics.get_err_counter('/err/nat64-out2in/TCP packets')
7882         udpn = self.statistics.get_err_counter('/err/nat64-out2in/UDP packets')
7883         icmpn = self.statistics.get_err_counter(
7884             '/err/nat64-out2in/ICMP packets')
7885         totaln = self.statistics.get_err_counter(
7886             '/err/nat64-out2in/good out2in packets processed')
7887
7888         pkts = self.create_stream_out(self.pg1, dst_ip=self.nat_addr)
7889         self.pg1.add_stream(pkts)
7890         self.pg_enable_capture(self.pg_interfaces)
7891         self.pg_start()
7892         capture = self.pg0.get_capture(len(pkts))
7893         ip = IPv6(src=''.join(['64:ff9b::', self.pg1.remote_ip4]))
7894         self.verify_capture_in_ip6(capture, ip[IPv6].src, self.pg0.remote_ip6)
7895
7896         err = self.statistics.get_err_counter('/err/nat64-out2in/TCP packets')
7897         self.assertEqual(err - tcpn, 2)
7898         err = self.statistics.get_err_counter('/err/nat64-out2in/UDP packets')
7899         self.assertEqual(err - udpn, 1)
7900         err = self.statistics.get_err_counter('/err/nat64-out2in/ICMP packets')
7901         self.assertEqual(err - icmpn, 1)
7902         err = self.statistics.get_err_counter(
7903             '/err/nat64-out2in/good out2in packets processed')
7904         self.assertEqual(err - totaln, 4)
7905
7906         bibs = self.statistics.get_counter('/nat64/total-bibs')
7907         self.assertEqual(bibs[0][0], 3)
7908         sessions = self.statistics.get_counter('/nat64/total-sessions')
7909         self.assertEqual(sessions[0][0], 3)
7910
7911         # in2out
7912         pkts = self.create_stream_in_ip6(self.pg0, self.pg1)
7913         self.pg0.add_stream(pkts)
7914         self.pg_enable_capture(self.pg_interfaces)
7915         self.pg_start()
7916         capture = self.pg1.get_capture(len(pkts))
7917         self.verify_capture_out(capture, nat_ip=self.nat_addr,
7918                                 dst_ip=self.pg1.remote_ip4)
7919
7920         # out2in
7921         pkts = self.create_stream_out(self.pg1, dst_ip=self.nat_addr)
7922         self.pg1.add_stream(pkts)
7923         self.pg_enable_capture(self.pg_interfaces)
7924         self.pg_start()
7925         capture = self.pg0.get_capture(len(pkts))
7926         self.verify_capture_in_ip6(capture, ip[IPv6].src, self.pg0.remote_ip6)
7927
7928         ses_num_end = self.nat64_get_ses_num()
7929
7930         self.assertEqual(ses_num_end - ses_num_start, 3)
7931
7932         # tenant with specific VRF
7933         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.vrf1_nat_addr,
7934                                                 end_addr=self.vrf1_nat_addr,
7935                                                 vrf_id=self.vrf1_id, is_add=1)
7936         flags = self.config_flags.NAT_IS_INSIDE
7937         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
7938                                           sw_if_index=self.pg2.sw_if_index)
7939
7940         pkts = self.create_stream_in_ip6(self.pg2, self.pg1)
7941         self.pg2.add_stream(pkts)
7942         self.pg_enable_capture(self.pg_interfaces)
7943         self.pg_start()
7944         capture = self.pg1.get_capture(len(pkts))
7945         self.verify_capture_out(capture, nat_ip=self.vrf1_nat_addr,
7946                                 dst_ip=self.pg1.remote_ip4)
7947
7948         pkts = self.create_stream_out(self.pg1, dst_ip=self.vrf1_nat_addr)
7949         self.pg1.add_stream(pkts)
7950         self.pg_enable_capture(self.pg_interfaces)
7951         self.pg_start()
7952         capture = self.pg2.get_capture(len(pkts))
7953         self.verify_capture_in_ip6(capture, ip[IPv6].src, self.pg2.remote_ip6)
7954
7955     def test_static(self):
7956         """ NAT64 static translation test """
7957         self.tcp_port_in = 60303
7958         self.udp_port_in = 60304
7959         self.icmp_id_in = 60305
7960         self.tcp_port_out = 60303
7961         self.udp_port_out = 60304
7962         self.icmp_id_out = 60305
7963
7964         ses_num_start = self.nat64_get_ses_num()
7965
7966         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr,
7967                                                 end_addr=self.nat_addr,
7968                                                 vrf_id=0xFFFFFFFF,
7969                                                 is_add=1)
7970         flags = self.config_flags.NAT_IS_INSIDE
7971         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
7972                                           sw_if_index=self.pg0.sw_if_index)
7973         self.vapi.nat64_add_del_interface(is_add=1, flags=0,
7974                                           sw_if_index=self.pg1.sw_if_index)
7975
7976         self.vapi.nat64_add_del_static_bib(i_addr=self.pg0.remote_ip6n,
7977                                            o_addr=self.nat_addr,
7978                                            i_port=self.tcp_port_in,
7979                                            o_port=self.tcp_port_out,
7980                                            proto=IP_PROTOS.tcp, vrf_id=0,
7981                                            is_add=1)
7982         self.vapi.nat64_add_del_static_bib(i_addr=self.pg0.remote_ip6n,
7983                                            o_addr=self.nat_addr,
7984                                            i_port=self.udp_port_in,
7985                                            o_port=self.udp_port_out,
7986                                            proto=IP_PROTOS.udp, vrf_id=0,
7987                                            is_add=1)
7988         self.vapi.nat64_add_del_static_bib(i_addr=self.pg0.remote_ip6n,
7989                                            o_addr=self.nat_addr,
7990                                            i_port=self.icmp_id_in,
7991                                            o_port=self.icmp_id_out,
7992                                            proto=IP_PROTOS.icmp, vrf_id=0,
7993                                            is_add=1)
7994
7995         # in2out
7996         pkts = self.create_stream_in_ip6(self.pg0, self.pg1)
7997         self.pg0.add_stream(pkts)
7998         self.pg_enable_capture(self.pg_interfaces)
7999         self.pg_start()
8000         capture = self.pg1.get_capture(len(pkts))
8001         self.verify_capture_out(capture, nat_ip=self.nat_addr,
8002                                 dst_ip=self.pg1.remote_ip4, same_port=True)
8003
8004         # out2in
8005         pkts = self.create_stream_out(self.pg1, dst_ip=self.nat_addr)
8006         self.pg1.add_stream(pkts)
8007         self.pg_enable_capture(self.pg_interfaces)
8008         self.pg_start()
8009         capture = self.pg0.get_capture(len(pkts))
8010         ip = IPv6(src=''.join(['64:ff9b::', self.pg1.remote_ip4]))
8011         self.verify_capture_in_ip6(capture, ip[IPv6].src, self.pg0.remote_ip6)
8012
8013         ses_num_end = self.nat64_get_ses_num()
8014
8015         self.assertEqual(ses_num_end - ses_num_start, 3)
8016
8017     @unittest.skipUnless(running_extended_tests, "part of extended tests")
8018     def test_session_timeout(self):
8019         """ NAT64 session timeout """
8020         self.icmp_id_in = 1234
8021         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr,
8022                                                 end_addr=self.nat_addr,
8023                                                 vrf_id=0xFFFFFFFF,
8024                                                 is_add=1)
8025         flags = self.config_flags.NAT_IS_INSIDE
8026         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
8027                                           sw_if_index=self.pg0.sw_if_index)
8028         self.vapi.nat64_add_del_interface(is_add=1, flags=0,
8029                                           sw_if_index=self.pg1.sw_if_index)
8030         self.vapi.nat_set_timeouts(udp=300, tcp_established=5,
8031                                    tcp_transitory=5,
8032                                    icmp=5)
8033
8034         pkts = self.create_stream_in_ip6(self.pg0, self.pg1)
8035         self.pg0.add_stream(pkts)
8036         self.pg_enable_capture(self.pg_interfaces)
8037         self.pg_start()
8038         capture = self.pg1.get_capture(len(pkts))
8039
8040         ses_num_before_timeout = self.nat64_get_ses_num()
8041
8042         sleep(15)
8043
8044         # ICMP and TCP session after timeout
8045         ses_num_after_timeout = self.nat64_get_ses_num()
8046         self.assertEqual(ses_num_before_timeout - ses_num_after_timeout, 2)
8047
8048     def test_icmp_error(self):
8049         """ NAT64 ICMP Error message translation """
8050         self.tcp_port_in = 6303
8051         self.udp_port_in = 6304
8052         self.icmp_id_in = 6305
8053
8054         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr,
8055                                                 end_addr=self.nat_addr,
8056                                                 vrf_id=0xFFFFFFFF,
8057                                                 is_add=1)
8058         flags = self.config_flags.NAT_IS_INSIDE
8059         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
8060                                           sw_if_index=self.pg0.sw_if_index)
8061         self.vapi.nat64_add_del_interface(is_add=1, flags=0,
8062                                           sw_if_index=self.pg1.sw_if_index)
8063
8064         # send some packets to create sessions
8065         pkts = self.create_stream_in_ip6(self.pg0, self.pg1)
8066         self.pg0.add_stream(pkts)
8067         self.pg_enable_capture(self.pg_interfaces)
8068         self.pg_start()
8069         capture_ip4 = self.pg1.get_capture(len(pkts))
8070         self.verify_capture_out(capture_ip4,
8071                                 nat_ip=self.nat_addr,
8072                                 dst_ip=self.pg1.remote_ip4)
8073
8074         pkts = self.create_stream_out(self.pg1, dst_ip=self.nat_addr)
8075         self.pg1.add_stream(pkts)
8076         self.pg_enable_capture(self.pg_interfaces)
8077         self.pg_start()
8078         capture_ip6 = self.pg0.get_capture(len(pkts))
8079         ip = IPv6(src=''.join(['64:ff9b::', self.pg1.remote_ip4]))
8080         self.verify_capture_in_ip6(capture_ip6, ip[IPv6].src,
8081                                    self.pg0.remote_ip6)
8082
8083         # in2out
8084         pkts = [Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
8085                 IPv6(src=self.pg0.remote_ip6, dst=ip[IPv6].src) /
8086                 ICMPv6DestUnreach(code=1) /
8087                 packet[IPv6] for packet in capture_ip6]
8088         self.pg0.add_stream(pkts)
8089         self.pg_enable_capture(self.pg_interfaces)
8090         self.pg_start()
8091         capture = self.pg1.get_capture(len(pkts))
8092         for packet in capture:
8093             try:
8094                 self.assertEqual(packet[IP].src, self.nat_addr)
8095                 self.assertEqual(packet[IP].dst, self.pg1.remote_ip4)
8096                 self.assertEqual(packet[ICMP].type, 3)
8097                 self.assertEqual(packet[ICMP].code, 13)
8098                 inner = packet[IPerror]
8099                 self.assertEqual(inner.src, self.pg1.remote_ip4)
8100                 self.assertEqual(inner.dst, self.nat_addr)
8101                 self.assert_packet_checksums_valid(packet)
8102                 if inner.haslayer(TCPerror):
8103                     self.assertEqual(inner[TCPerror].dport, self.tcp_port_out)
8104                 elif inner.haslayer(UDPerror):
8105                     self.assertEqual(inner[UDPerror].dport, self.udp_port_out)
8106                 else:
8107                     self.assertEqual(inner[ICMPerror].id, self.icmp_id_out)
8108             except:
8109                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
8110                 raise
8111
8112         # out2in
8113         pkts = [Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
8114                 IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
8115                 ICMP(type=3, code=13) /
8116                 packet[IP] for packet in capture_ip4]
8117         self.pg1.add_stream(pkts)
8118         self.pg_enable_capture(self.pg_interfaces)
8119         self.pg_start()
8120         capture = self.pg0.get_capture(len(pkts))
8121         for packet in capture:
8122             try:
8123                 self.assertEqual(packet[IPv6].src, ip.src)
8124                 self.assertEqual(packet[IPv6].dst, self.pg0.remote_ip6)
8125                 icmp = packet[ICMPv6DestUnreach]
8126                 self.assertEqual(icmp.code, 1)
8127                 inner = icmp[IPerror6]
8128                 self.assertEqual(inner.src, self.pg0.remote_ip6)
8129                 self.assertEqual(inner.dst, ip.src)
8130                 self.assert_icmpv6_checksum_valid(packet)
8131                 if inner.haslayer(TCPerror):
8132                     self.assertEqual(inner[TCPerror].sport, self.tcp_port_in)
8133                 elif inner.haslayer(UDPerror):
8134                     self.assertEqual(inner[UDPerror].sport, self.udp_port_in)
8135                 else:
8136                     self.assertEqual(inner[ICMPv6EchoRequest].id,
8137                                      self.icmp_id_in)
8138             except:
8139                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
8140                 raise
8141
8142     def test_hairpinning(self):
8143         """ NAT64 hairpinning """
8144
8145         client = self.pg0.remote_hosts[0]
8146         server = self.pg0.remote_hosts[1]
8147         server_tcp_in_port = 22
8148         server_tcp_out_port = 4022
8149         server_udp_in_port = 23
8150         server_udp_out_port = 4023
8151         client_tcp_in_port = 1234
8152         client_udp_in_port = 1235
8153         client_tcp_out_port = 0
8154         client_udp_out_port = 0
8155         ip = IPv6(src=''.join(['64:ff9b::', self.nat_addr]))
8156         nat_addr_ip6 = ip.src
8157
8158         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr,
8159                                                 end_addr=self.nat_addr,
8160                                                 vrf_id=0xFFFFFFFF,
8161                                                 is_add=1)
8162         flags = self.config_flags.NAT_IS_INSIDE
8163         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
8164                                           sw_if_index=self.pg0.sw_if_index)
8165         self.vapi.nat64_add_del_interface(is_add=1, flags=0,
8166                                           sw_if_index=self.pg1.sw_if_index)
8167
8168         self.vapi.nat64_add_del_static_bib(i_addr=server.ip6n,
8169                                            o_addr=self.nat_addr,
8170                                            i_port=server_tcp_in_port,
8171                                            o_port=server_tcp_out_port,
8172                                            proto=IP_PROTOS.tcp, vrf_id=0,
8173                                            is_add=1)
8174         self.vapi.nat64_add_del_static_bib(i_addr=server.ip6n,
8175                                            o_addr=self.nat_addr,
8176                                            i_port=server_udp_in_port,
8177                                            o_port=server_udp_out_port,
8178                                            proto=IP_PROTOS.udp, vrf_id=0,
8179                                            is_add=1)
8180
8181         # client to server
8182         pkts = []
8183         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
8184              IPv6(src=client.ip6, dst=nat_addr_ip6) /
8185              TCP(sport=client_tcp_in_port, dport=server_tcp_out_port))
8186         pkts.append(p)
8187         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
8188              IPv6(src=client.ip6, dst=nat_addr_ip6) /
8189              UDP(sport=client_udp_in_port, dport=server_udp_out_port))
8190         pkts.append(p)
8191         self.pg0.add_stream(pkts)
8192         self.pg_enable_capture(self.pg_interfaces)
8193         self.pg_start()
8194         capture = self.pg0.get_capture(len(pkts))
8195         for packet in capture:
8196             try:
8197                 self.assertEqual(packet[IPv6].src, nat_addr_ip6)
8198                 self.assertEqual(packet[IPv6].dst, server.ip6)
8199                 self.assert_packet_checksums_valid(packet)
8200                 if packet.haslayer(TCP):
8201                     self.assertNotEqual(packet[TCP].sport, client_tcp_in_port)
8202                     self.assertEqual(packet[TCP].dport, server_tcp_in_port)
8203                     client_tcp_out_port = packet[TCP].sport
8204                 else:
8205                     self.assertNotEqual(packet[UDP].sport, client_udp_in_port)
8206                     self.assertEqual(packet[UDP].dport, server_udp_in_port)
8207                     client_udp_out_port = packet[UDP].sport
8208             except:
8209                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
8210                 raise
8211
8212         # server to client
8213         pkts = []
8214         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
8215              IPv6(src=server.ip6, dst=nat_addr_ip6) /
8216              TCP(sport=server_tcp_in_port, dport=client_tcp_out_port))
8217         pkts.append(p)
8218         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
8219              IPv6(src=server.ip6, dst=nat_addr_ip6) /
8220              UDP(sport=server_udp_in_port, dport=client_udp_out_port))
8221         pkts.append(p)
8222         self.pg0.add_stream(pkts)
8223         self.pg_enable_capture(self.pg_interfaces)
8224         self.pg_start()
8225         capture = self.pg0.get_capture(len(pkts))
8226         for packet in capture:
8227             try:
8228                 self.assertEqual(packet[IPv6].src, nat_addr_ip6)
8229                 self.assertEqual(packet[IPv6].dst, client.ip6)
8230                 self.assert_packet_checksums_valid(packet)
8231                 if packet.haslayer(TCP):
8232                     self.assertEqual(packet[TCP].sport, server_tcp_out_port)
8233                     self.assertEqual(packet[TCP].dport, client_tcp_in_port)
8234                 else:
8235                     self.assertEqual(packet[UDP].sport, server_udp_out_port)
8236                     self.assertEqual(packet[UDP].dport, client_udp_in_port)
8237             except:
8238                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
8239                 raise
8240
8241         # ICMP error
8242         pkts = []
8243         pkts = [Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
8244                 IPv6(src=client.ip6, dst=nat_addr_ip6) /
8245                 ICMPv6DestUnreach(code=1) /
8246                 packet[IPv6] for packet in capture]
8247         self.pg0.add_stream(pkts)
8248         self.pg_enable_capture(self.pg_interfaces)
8249         self.pg_start()
8250         capture = self.pg0.get_capture(len(pkts))
8251         for packet in capture:
8252             try:
8253                 self.assertEqual(packet[IPv6].src, nat_addr_ip6)
8254                 self.assertEqual(packet[IPv6].dst, server.ip6)
8255                 icmp = packet[ICMPv6DestUnreach]
8256                 self.assertEqual(icmp.code, 1)
8257                 inner = icmp[IPerror6]
8258                 self.assertEqual(inner.src, server.ip6)
8259                 self.assertEqual(inner.dst, nat_addr_ip6)
8260                 self.assert_packet_checksums_valid(packet)
8261                 if inner.haslayer(TCPerror):
8262                     self.assertEqual(inner[TCPerror].sport, server_tcp_in_port)
8263                     self.assertEqual(inner[TCPerror].dport,
8264                                      client_tcp_out_port)
8265                 else:
8266                     self.assertEqual(inner[UDPerror].sport, server_udp_in_port)
8267                     self.assertEqual(inner[UDPerror].dport,
8268                                      client_udp_out_port)
8269             except:
8270                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
8271                 raise
8272
8273     def test_prefix(self):
8274         """ NAT64 Network-Specific Prefix """
8275
8276         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr,
8277                                                 end_addr=self.nat_addr,
8278                                                 vrf_id=0xFFFFFFFF,
8279                                                 is_add=1)
8280         flags = self.config_flags.NAT_IS_INSIDE
8281         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
8282                                           sw_if_index=self.pg0.sw_if_index)
8283         self.vapi.nat64_add_del_interface(is_add=1, flags=0,
8284                                           sw_if_index=self.pg1.sw_if_index)
8285         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.vrf1_nat_addr,
8286                                                 end_addr=self.vrf1_nat_addr,
8287                                                 vrf_id=self.vrf1_id, is_add=1)
8288         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
8289                                           sw_if_index=self.pg2.sw_if_index)
8290
8291         # Add global prefix
8292         global_pref64 = "2001:db8::"
8293         global_pref64_len = 32
8294         global_pref64_str = "{}/{}".format(global_pref64, global_pref64_len)
8295         self.vapi.nat64_add_del_prefix(prefix=global_pref64_str, vrf_id=0,
8296                                        is_add=1)
8297
8298         prefix = self.vapi.nat64_prefix_dump()
8299         self.assertEqual(len(prefix), 1)
8300         self.assertEqual(str(prefix[0].prefix), global_pref64_str)
8301         self.assertEqual(prefix[0].vrf_id, 0)
8302
8303         # Add tenant specific prefix
8304         vrf1_pref64 = "2001:db8:122:300::"
8305         vrf1_pref64_len = 56
8306         vrf1_pref64_str = "{}/{}".format(vrf1_pref64, vrf1_pref64_len)
8307         self.vapi.nat64_add_del_prefix(prefix=vrf1_pref64_str,
8308                                        vrf_id=self.vrf1_id, is_add=1)
8309
8310         prefix = self.vapi.nat64_prefix_dump()
8311         self.assertEqual(len(prefix), 2)
8312
8313         # Global prefix
8314         pkts = self.create_stream_in_ip6(self.pg0,
8315                                          self.pg1,
8316                                          pref=global_pref64,
8317                                          plen=global_pref64_len)
8318         self.pg0.add_stream(pkts)
8319         self.pg_enable_capture(self.pg_interfaces)
8320         self.pg_start()
8321         capture = self.pg1.get_capture(len(pkts))
8322         self.verify_capture_out(capture, nat_ip=self.nat_addr,
8323                                 dst_ip=self.pg1.remote_ip4)
8324
8325         pkts = self.create_stream_out(self.pg1, dst_ip=self.nat_addr)
8326         self.pg1.add_stream(pkts)
8327         self.pg_enable_capture(self.pg_interfaces)
8328         self.pg_start()
8329         capture = self.pg0.get_capture(len(pkts))
8330         dst_ip = self.compose_ip6(self.pg1.remote_ip4,
8331                                   global_pref64,
8332                                   global_pref64_len)
8333         self.verify_capture_in_ip6(capture, dst_ip, self.pg0.remote_ip6)
8334
8335         # Tenant specific prefix
8336         pkts = self.create_stream_in_ip6(self.pg2,
8337                                          self.pg1,
8338                                          pref=vrf1_pref64,
8339                                          plen=vrf1_pref64_len)
8340         self.pg2.add_stream(pkts)
8341         self.pg_enable_capture(self.pg_interfaces)
8342         self.pg_start()
8343         capture = self.pg1.get_capture(len(pkts))
8344         self.verify_capture_out(capture, nat_ip=self.vrf1_nat_addr,
8345                                 dst_ip=self.pg1.remote_ip4)
8346
8347         pkts = self.create_stream_out(self.pg1, dst_ip=self.vrf1_nat_addr)
8348         self.pg1.add_stream(pkts)
8349         self.pg_enable_capture(self.pg_interfaces)
8350         self.pg_start()
8351         capture = self.pg2.get_capture(len(pkts))
8352         dst_ip = self.compose_ip6(self.pg1.remote_ip4,
8353                                   vrf1_pref64,
8354                                   vrf1_pref64_len)
8355         self.verify_capture_in_ip6(capture, dst_ip, self.pg2.remote_ip6)
8356
8357     def test_unknown_proto(self):
8358         """ NAT64 translate packet with unknown protocol """
8359
8360         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr,
8361                                                 end_addr=self.nat_addr,
8362                                                 vrf_id=0xFFFFFFFF,
8363                                                 is_add=1)
8364         flags = self.config_flags.NAT_IS_INSIDE
8365         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
8366                                           sw_if_index=self.pg0.sw_if_index)
8367         self.vapi.nat64_add_del_interface(is_add=1, flags=0,
8368                                           sw_if_index=self.pg1.sw_if_index)
8369         remote_ip6 = self.compose_ip6(self.pg1.remote_ip4, '64:ff9b::', 96)
8370
8371         # in2out
8372         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
8373              IPv6(src=self.pg0.remote_ip6, dst=remote_ip6) /
8374              TCP(sport=self.tcp_port_in, dport=20))
8375         self.pg0.add_stream(p)
8376         self.pg_enable_capture(self.pg_interfaces)
8377         self.pg_start()
8378         p = self.pg1.get_capture(1)
8379
8380         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
8381              IPv6(src=self.pg0.remote_ip6, dst=remote_ip6, nh=47) /
8382              GRE() /
8383              IP(src=self.pg2.local_ip4, dst=self.pg2.remote_ip4) /
8384              TCP(sport=1234, dport=1234))
8385         self.pg0.add_stream(p)
8386         self.pg_enable_capture(self.pg_interfaces)
8387         self.pg_start()
8388         p = self.pg1.get_capture(1)
8389         packet = p[0]
8390         try:
8391             self.assertEqual(packet[IP].src, self.nat_addr)
8392             self.assertEqual(packet[IP].dst, self.pg1.remote_ip4)
8393             self.assertEqual(packet.haslayer(GRE), 1)
8394             self.assert_packet_checksums_valid(packet)
8395         except:
8396             self.logger.error(ppp("Unexpected or invalid packet:", packet))
8397             raise
8398
8399         # out2in
8400         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
8401              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
8402              GRE() /
8403              IP(src=self.pg2.remote_ip4, dst=self.pg2.local_ip4) /
8404              TCP(sport=1234, dport=1234))
8405         self.pg1.add_stream(p)
8406         self.pg_enable_capture(self.pg_interfaces)
8407         self.pg_start()
8408         p = self.pg0.get_capture(1)
8409         packet = p[0]
8410         try:
8411             self.assertEqual(packet[IPv6].src, remote_ip6)
8412             self.assertEqual(packet[IPv6].dst, self.pg0.remote_ip6)
8413             self.assertEqual(packet[IPv6].nh, 47)
8414         except:
8415             self.logger.error(ppp("Unexpected or invalid packet:", packet))
8416             raise
8417
8418     def test_hairpinning_unknown_proto(self):
8419         """ NAT64 translate packet with unknown protocol - hairpinning """
8420
8421         client = self.pg0.remote_hosts[0]
8422         server = self.pg0.remote_hosts[1]
8423         server_tcp_in_port = 22
8424         server_tcp_out_port = 4022
8425         client_tcp_in_port = 1234
8426         client_tcp_out_port = 1235
8427         server_nat_ip = "10.0.0.100"
8428         client_nat_ip = "10.0.0.110"
8429         server_nat_ip6 = self.compose_ip6(server_nat_ip, '64:ff9b::', 96)
8430         client_nat_ip6 = self.compose_ip6(client_nat_ip, '64:ff9b::', 96)
8431
8432         self.vapi.nat64_add_del_pool_addr_range(start_addr=server_nat_ip,
8433                                                 end_addr=client_nat_ip,
8434                                                 vrf_id=0xFFFFFFFF,
8435                                                 is_add=1)
8436         flags = self.config_flags.NAT_IS_INSIDE
8437         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
8438                                           sw_if_index=self.pg0.sw_if_index)
8439         self.vapi.nat64_add_del_interface(is_add=1, flags=0,
8440                                           sw_if_index=self.pg1.sw_if_index)
8441
8442         self.vapi.nat64_add_del_static_bib(i_addr=server.ip6n,
8443                                            o_addr=server_nat_ip,
8444                                            i_port=server_tcp_in_port,
8445                                            o_port=server_tcp_out_port,
8446                                            proto=IP_PROTOS.tcp, vrf_id=0,
8447                                            is_add=1)
8448
8449         self.vapi.nat64_add_del_static_bib(i_addr=server.ip6n,
8450                                            o_addr=server_nat_ip, i_port=0,
8451                                            o_port=0,
8452                                            proto=IP_PROTOS.gre, vrf_id=0,
8453                                            is_add=1)
8454
8455         self.vapi.nat64_add_del_static_bib(i_addr=client.ip6n,
8456                                            o_addr=client_nat_ip,
8457                                            i_port=client_tcp_in_port,
8458                                            o_port=client_tcp_out_port,
8459                                            proto=IP_PROTOS.tcp, vrf_id=0,
8460                                            is_add=1)
8461
8462         # client to server
8463         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
8464              IPv6(src=client.ip6, dst=server_nat_ip6) /
8465              TCP(sport=client_tcp_in_port, dport=server_tcp_out_port))
8466         self.pg0.add_stream(p)
8467         self.pg_enable_capture(self.pg_interfaces)
8468         self.pg_start()
8469         p = self.pg0.get_capture(1)
8470
8471         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
8472              IPv6(src=client.ip6, dst=server_nat_ip6, nh=IP_PROTOS.gre) /
8473              GRE() /
8474              IP(src=self.pg2.local_ip4, dst=self.pg2.remote_ip4) /
8475              TCP(sport=1234, dport=1234))
8476         self.pg0.add_stream(p)
8477         self.pg_enable_capture(self.pg_interfaces)
8478         self.pg_start()
8479         p = self.pg0.get_capture(1)
8480         packet = p[0]
8481         try:
8482             self.assertEqual(packet[IPv6].src, client_nat_ip6)
8483             self.assertEqual(packet[IPv6].dst, server.ip6)
8484             self.assertEqual(packet[IPv6].nh, IP_PROTOS.gre)
8485         except:
8486             self.logger.error(ppp("Unexpected or invalid packet:", packet))
8487             raise
8488
8489         # server to client
8490         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
8491              IPv6(src=server.ip6, dst=client_nat_ip6, nh=IP_PROTOS.gre) /
8492              GRE() /
8493              IP(src=self.pg2.remote_ip4, dst=self.pg2.local_ip4) /
8494              TCP(sport=1234, dport=1234))
8495         self.pg0.add_stream(p)
8496         self.pg_enable_capture(self.pg_interfaces)
8497         self.pg_start()
8498         p = self.pg0.get_capture(1)
8499         packet = p[0]
8500         try:
8501             self.assertEqual(packet[IPv6].src, server_nat_ip6)
8502             self.assertEqual(packet[IPv6].dst, client.ip6)
8503             self.assertEqual(packet[IPv6].nh, IP_PROTOS.gre)
8504         except:
8505             self.logger.error(ppp("Unexpected or invalid packet:", packet))
8506             raise
8507
8508     def test_one_armed_nat64(self):
8509         """ One armed NAT64 """
8510         external_port = 0
8511         remote_host_ip6 = self.compose_ip6(self.pg3.remote_ip4,
8512                                            '64:ff9b::',
8513                                            96)
8514
8515         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr,
8516                                                 end_addr=self.nat_addr,
8517                                                 vrf_id=0xFFFFFFFF,
8518                                                 is_add=1)
8519         flags = self.config_flags.NAT_IS_INSIDE
8520         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
8521                                           sw_if_index=self.pg3.sw_if_index)
8522         self.vapi.nat64_add_del_interface(is_add=1, flags=0,
8523                                           sw_if_index=self.pg3.sw_if_index)
8524
8525         # in2out
8526         p = (Ether(src=self.pg3.remote_mac, dst=self.pg3.local_mac) /
8527              IPv6(src=self.pg3.remote_ip6, dst=remote_host_ip6) /
8528              TCP(sport=12345, dport=80))
8529         self.pg3.add_stream(p)
8530         self.pg_enable_capture(self.pg_interfaces)
8531         self.pg_start()
8532         capture = self.pg3.get_capture(1)
8533         p = capture[0]
8534         try:
8535             ip = p[IP]
8536             tcp = p[TCP]
8537             self.assertEqual(ip.src, self.nat_addr)
8538             self.assertEqual(ip.dst, self.pg3.remote_ip4)
8539             self.assertNotEqual(tcp.sport, 12345)
8540             external_port = tcp.sport
8541             self.assertEqual(tcp.dport, 80)
8542             self.assert_packet_checksums_valid(p)
8543         except:
8544             self.logger.error(ppp("Unexpected or invalid packet:", p))
8545             raise
8546
8547         # out2in
8548         p = (Ether(src=self.pg3.remote_mac, dst=self.pg3.local_mac) /
8549              IP(src=self.pg3.remote_ip4, dst=self.nat_addr) /
8550              TCP(sport=80, dport=external_port))
8551         self.pg3.add_stream(p)
8552         self.pg_enable_capture(self.pg_interfaces)
8553         self.pg_start()
8554         capture = self.pg3.get_capture(1)
8555         p = capture[0]
8556         try:
8557             ip = p[IPv6]
8558             tcp = p[TCP]
8559             self.assertEqual(ip.src, remote_host_ip6)
8560             self.assertEqual(ip.dst, self.pg3.remote_ip6)
8561             self.assertEqual(tcp.sport, 80)
8562             self.assertEqual(tcp.dport, 12345)
8563             self.assert_packet_checksums_valid(p)
8564         except:
8565             self.logger.error(ppp("Unexpected or invalid packet:", p))
8566             raise
8567
8568     def test_frag_in_order(self):
8569         """ NAT64 translate fragments arriving in order """
8570         self.tcp_port_in = random.randint(1025, 65535)
8571
8572         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr,
8573                                                 end_addr=self.nat_addr,
8574                                                 vrf_id=0xFFFFFFFF,
8575                                                 is_add=1)
8576         flags = self.config_flags.NAT_IS_INSIDE
8577         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
8578                                           sw_if_index=self.pg0.sw_if_index)
8579         self.vapi.nat64_add_del_interface(is_add=1, flags=0,
8580                                           sw_if_index=self.pg1.sw_if_index)
8581
8582         # in2out
8583         data = b'a' * 200
8584         pkts = self.create_stream_frag_ip6(self.pg0, self.pg1.remote_ip4,
8585                                            self.tcp_port_in, 20, data)
8586         self.pg0.add_stream(pkts)
8587         self.pg_enable_capture(self.pg_interfaces)
8588         self.pg_start()
8589         frags = self.pg1.get_capture(len(pkts))
8590         p = self.reass_frags_and_verify(frags,
8591                                         self.nat_addr,
8592                                         self.pg1.remote_ip4)
8593         self.assertEqual(p[TCP].dport, 20)
8594         self.assertNotEqual(p[TCP].sport, self.tcp_port_in)
8595         self.tcp_port_out = p[TCP].sport
8596         self.assertEqual(data, p[Raw].load)
8597
8598         # out2in
8599         data = b"A" * 4 + b"b" * 16 + b"C" * 3
8600         pkts = self.create_stream_frag(self.pg1,
8601                                        self.nat_addr,
8602                                        20,
8603                                        self.tcp_port_out,
8604                                        data)
8605         self.pg1.add_stream(pkts)
8606         self.pg_enable_capture(self.pg_interfaces)
8607         self.pg_start()
8608         frags = self.pg0.get_capture(len(pkts))
8609         self.logger.debug(ppc("Captured:", frags))
8610         src = self.compose_ip6(self.pg1.remote_ip4, '64:ff9b::', 96)
8611         p = self.reass_frags_and_verify_ip6(frags, src, self.pg0.remote_ip6)
8612         self.assertEqual(p[TCP].sport, 20)
8613         self.assertEqual(p[TCP].dport, self.tcp_port_in)
8614         self.assertEqual(data, p[Raw].load)
8615
8616     def test_reass_hairpinning(self):
8617         """ NAT64 fragments hairpinning """
8618         data = b'a' * 200
8619         server = self.pg0.remote_hosts[1]
8620         server_in_port = random.randint(1025, 65535)
8621         server_out_port = random.randint(1025, 65535)
8622         client_in_port = random.randint(1025, 65535)
8623         ip = IPv6(src=''.join(['64:ff9b::', self.nat_addr]))
8624         nat_addr_ip6 = ip.src
8625
8626         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr,
8627                                                 end_addr=self.nat_addr,
8628                                                 vrf_id=0xFFFFFFFF,
8629                                                 is_add=1)
8630         flags = self.config_flags.NAT_IS_INSIDE
8631         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
8632                                           sw_if_index=self.pg0.sw_if_index)
8633         self.vapi.nat64_add_del_interface(is_add=1, flags=0,
8634                                           sw_if_index=self.pg1.sw_if_index)
8635
8636         # add static BIB entry for server
8637         self.vapi.nat64_add_del_static_bib(i_addr=server.ip6n,
8638                                            o_addr=self.nat_addr,
8639                                            i_port=server_in_port,
8640                                            o_port=server_out_port,
8641                                            proto=IP_PROTOS.tcp, vrf_id=0,
8642                                            is_add=1)
8643
8644         # send packet from host to server
8645         pkts = self.create_stream_frag_ip6(self.pg0,
8646                                            self.nat_addr,
8647                                            client_in_port,
8648                                            server_out_port,
8649                                            data)
8650         self.pg0.add_stream(pkts)
8651         self.pg_enable_capture(self.pg_interfaces)
8652         self.pg_start()
8653         frags = self.pg0.get_capture(len(pkts))
8654         self.logger.debug(ppc("Captured:", frags))
8655         p = self.reass_frags_and_verify_ip6(frags, nat_addr_ip6, server.ip6)
8656         self.assertNotEqual(p[TCP].sport, client_in_port)
8657         self.assertEqual(p[TCP].dport, server_in_port)
8658         self.assertEqual(data, p[Raw].load)
8659
8660     def test_frag_out_of_order(self):
8661         """ NAT64 translate fragments arriving out of order """
8662         self.tcp_port_in = random.randint(1025, 65535)
8663
8664         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr,
8665                                                 end_addr=self.nat_addr,
8666                                                 vrf_id=0xFFFFFFFF,
8667                                                 is_add=1)
8668         flags = self.config_flags.NAT_IS_INSIDE
8669         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
8670                                           sw_if_index=self.pg0.sw_if_index)
8671         self.vapi.nat64_add_del_interface(is_add=1, flags=0,
8672                                           sw_if_index=self.pg1.sw_if_index)
8673
8674         # in2out
8675         data = b'a' * 200
8676         pkts = self.create_stream_frag_ip6(self.pg0, self.pg1.remote_ip4,
8677                                            self.tcp_port_in, 20, data)
8678         pkts.reverse()
8679         self.pg0.add_stream(pkts)
8680         self.pg_enable_capture(self.pg_interfaces)
8681         self.pg_start()
8682         frags = self.pg1.get_capture(len(pkts))
8683         p = self.reass_frags_and_verify(frags,
8684                                         self.nat_addr,
8685                                         self.pg1.remote_ip4)
8686         self.assertEqual(p[TCP].dport, 20)
8687         self.assertNotEqual(p[TCP].sport, self.tcp_port_in)
8688         self.tcp_port_out = p[TCP].sport
8689         self.assertEqual(data, p[Raw].load)
8690
8691         # out2in
8692         data = b"A" * 4 + b"B" * 16 + b"C" * 3
8693         pkts = self.create_stream_frag(self.pg1,
8694                                        self.nat_addr,
8695                                        20,
8696                                        self.tcp_port_out,
8697                                        data)
8698         pkts.reverse()
8699         self.pg1.add_stream(pkts)
8700         self.pg_enable_capture(self.pg_interfaces)
8701         self.pg_start()
8702         frags = self.pg0.get_capture(len(pkts))
8703         src = self.compose_ip6(self.pg1.remote_ip4, '64:ff9b::', 96)
8704         p = self.reass_frags_and_verify_ip6(frags, src, self.pg0.remote_ip6)
8705         self.assertEqual(p[TCP].sport, 20)
8706         self.assertEqual(p[TCP].dport, self.tcp_port_in)
8707         self.assertEqual(data, p[Raw].load)
8708
8709     def test_interface_addr(self):
8710         """ Acquire NAT64 pool addresses from interface """
8711         self.vapi.nat64_add_del_interface_addr(
8712             is_add=1,
8713             sw_if_index=self.pg4.sw_if_index)
8714
8715         # no address in NAT64 pool
8716         addresses = self.vapi.nat44_address_dump()
8717         self.assertEqual(0, len(addresses))
8718
8719         # configure interface address and check NAT64 address pool
8720         self.pg4.config_ip4()
8721         addresses = self.vapi.nat64_pool_addr_dump()
8722         self.assertEqual(len(addresses), 1)
8723
8724         self.assertEqual(str(addresses[0].address),
8725                          self.pg4.local_ip4)
8726
8727         # remove interface address and check NAT64 address pool
8728         self.pg4.unconfig_ip4()
8729         addresses = self.vapi.nat64_pool_addr_dump()
8730         self.assertEqual(0, len(addresses))
8731
8732     @unittest.skipUnless(running_extended_tests, "part of extended tests")
8733     def test_ipfix_max_bibs_sessions(self):
8734         """ IPFIX logging maximum session and BIB entries exceeded """
8735         max_bibs = 1280
8736         max_sessions = 2560
8737         remote_host_ip6 = self.compose_ip6(self.pg1.remote_ip4,
8738                                            '64:ff9b::',
8739                                            96)
8740
8741         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr,
8742                                                 end_addr=self.nat_addr,
8743                                                 vrf_id=0xFFFFFFFF,
8744                                                 is_add=1)
8745         flags = self.config_flags.NAT_IS_INSIDE
8746         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
8747                                           sw_if_index=self.pg0.sw_if_index)
8748         self.vapi.nat64_add_del_interface(is_add=1, flags=0,
8749                                           sw_if_index=self.pg1.sw_if_index)
8750
8751         pkts = []
8752         src = ""
8753         for i in range(0, max_bibs):
8754             src = "fd01:aa::%x" % (i)
8755             p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
8756                  IPv6(src=src, dst=remote_host_ip6) /
8757                  TCP(sport=12345, dport=80))
8758             pkts.append(p)
8759             p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
8760                  IPv6(src=src, dst=remote_host_ip6) /
8761                  TCP(sport=12345, dport=22))
8762             pkts.append(p)
8763         self.pg0.add_stream(pkts)
8764         self.pg_enable_capture(self.pg_interfaces)
8765         self.pg_start()
8766         self.pg1.get_capture(max_sessions)
8767
8768         self.vapi.set_ipfix_exporter(collector_address=self.pg3.remote_ip4,
8769                                      src_address=self.pg3.local_ip4,
8770                                      path_mtu=512,
8771                                      template_interval=10)
8772         self.vapi.nat_ipfix_enable_disable(domain_id=self.ipfix_domain_id,
8773                                            src_port=self.ipfix_src_port,
8774                                            enable=1)
8775
8776         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
8777              IPv6(src=src, dst=remote_host_ip6) /
8778              TCP(sport=12345, dport=25))
8779         self.pg0.add_stream(p)
8780         self.pg_enable_capture(self.pg_interfaces)
8781         self.pg_start()
8782         self.pg1.assert_nothing_captured()
8783         sleep(1)
8784         self.vapi.ipfix_flush()
8785         capture = self.pg3.get_capture(7)
8786         ipfix = IPFIXDecoder()
8787         # first load template
8788         for p in capture:
8789             self.assertTrue(p.haslayer(IPFIX))
8790             self.assertEqual(p[IP].src, self.pg3.local_ip4)
8791             self.assertEqual(p[IP].dst, self.pg3.remote_ip4)
8792             self.assertEqual(p[UDP].sport, self.ipfix_src_port)
8793             self.assertEqual(p[UDP].dport, 4739)
8794             self.assertEqual(p[IPFIX].observationDomainID,
8795                              self.ipfix_domain_id)
8796             if p.haslayer(Template):
8797                 ipfix.add_template(p.getlayer(Template))
8798         # verify events in data set
8799         for p in capture:
8800             if p.haslayer(Data):
8801                 data = ipfix.decode_data_set(p.getlayer(Set))
8802                 self.verify_ipfix_max_sessions(data, max_sessions)
8803
8804         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
8805              IPv6(src=self.pg0.remote_ip6, dst=remote_host_ip6) /
8806              TCP(sport=12345, dport=80))
8807         self.pg0.add_stream(p)
8808         self.pg_enable_capture(self.pg_interfaces)
8809         self.pg_start()
8810         self.pg1.assert_nothing_captured()
8811         sleep(1)
8812         self.vapi.ipfix_flush()
8813         capture = self.pg3.get_capture(1)
8814         # verify events in data set
8815         for p in capture:
8816             self.assertTrue(p.haslayer(IPFIX))
8817             self.assertEqual(p[IP].src, self.pg3.local_ip4)
8818             self.assertEqual(p[IP].dst, self.pg3.remote_ip4)
8819             self.assertEqual(p[UDP].sport, self.ipfix_src_port)
8820             self.assertEqual(p[UDP].dport, 4739)
8821             self.assertEqual(p[IPFIX].observationDomainID,
8822                              self.ipfix_domain_id)
8823             if p.haslayer(Data):
8824                 data = ipfix.decode_data_set(p.getlayer(Set))
8825                 self.verify_ipfix_max_bibs(data, max_bibs)
8826
8827     def test_ipfix_bib_ses(self):
8828         """ IPFIX logging NAT64 BIB/session create and delete events """
8829         self.tcp_port_in = random.randint(1025, 65535)
8830         remote_host_ip6 = self.compose_ip6(self.pg1.remote_ip4,
8831                                            '64:ff9b::',
8832                                            96)
8833
8834         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr,
8835                                                 end_addr=self.nat_addr,
8836                                                 vrf_id=0xFFFFFFFF,
8837                                                 is_add=1)
8838         flags = self.config_flags.NAT_IS_INSIDE
8839         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
8840                                           sw_if_index=self.pg0.sw_if_index)
8841         self.vapi.nat64_add_del_interface(is_add=1, flags=0,
8842                                           sw_if_index=self.pg1.sw_if_index)
8843         self.vapi.set_ipfix_exporter(collector_address=self.pg3.remote_ip4,
8844                                      src_address=self.pg3.local_ip4,
8845                                      path_mtu=512,
8846                                      template_interval=10)
8847         self.vapi.nat_ipfix_enable_disable(domain_id=self.ipfix_domain_id,
8848                                            src_port=self.ipfix_src_port,
8849                                            enable=1)
8850
8851         # Create
8852         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
8853              IPv6(src=self.pg0.remote_ip6, dst=remote_host_ip6) /
8854              TCP(sport=self.tcp_port_in, dport=25))
8855         self.pg0.add_stream(p)
8856         self.pg_enable_capture(self.pg_interfaces)
8857         self.pg_start()
8858         p = self.pg1.get_capture(1)
8859         self.tcp_port_out = p[0][TCP].sport
8860         self.vapi.ipfix_flush()
8861         capture = self.pg3.get_capture(8)
8862         ipfix = IPFIXDecoder()
8863         # first load template
8864         for p in capture:
8865             self.assertTrue(p.haslayer(IPFIX))
8866             self.assertEqual(p[IP].src, self.pg3.local_ip4)
8867             self.assertEqual(p[IP].dst, self.pg3.remote_ip4)
8868             self.assertEqual(p[UDP].sport, self.ipfix_src_port)
8869             self.assertEqual(p[UDP].dport, 4739)
8870             self.assertEqual(p[IPFIX].observationDomainID,
8871                              self.ipfix_domain_id)
8872             if p.haslayer(Template):
8873                 ipfix.add_template(p.getlayer(Template))
8874         # verify events in data set
8875         for p in capture:
8876             if p.haslayer(Data):
8877                 data = ipfix.decode_data_set(p.getlayer(Set))
8878                 if scapy.compat.orb(data[0][230]) == 10:
8879                     self.verify_ipfix_bib(data, 1, self.pg0.remote_ip6n)
8880                 elif scapy.compat.orb(data[0][230]) == 6:
8881                     self.verify_ipfix_nat64_ses(data,
8882                                                 1,
8883                                                 self.pg0.remote_ip6n,
8884                                                 self.pg1.remote_ip4,
8885                                                 25)
8886                 else:
8887                     self.logger.error(ppp("Unexpected or invalid packet: ", p))
8888
8889         # Delete
8890         self.pg_enable_capture(self.pg_interfaces)
8891         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr,
8892                                                 end_addr=self.nat_addr,
8893                                                 vrf_id=0xFFFFFFFF,
8894                                                 is_add=0)
8895         self.vapi.ipfix_flush()
8896         capture = self.pg3.get_capture(2)
8897         # verify events in data set
8898         for p in capture:
8899             self.assertTrue(p.haslayer(IPFIX))
8900             self.assertEqual(p[IP].src, self.pg3.local_ip4)
8901             self.assertEqual(p[IP].dst, self.pg3.remote_ip4)
8902             self.assertEqual(p[UDP].sport, self.ipfix_src_port)
8903             self.assertEqual(p[UDP].dport, 4739)
8904             self.assertEqual(p[IPFIX].observationDomainID,
8905                              self.ipfix_domain_id)
8906             if p.haslayer(Data):
8907                 data = ipfix.decode_data_set(p.getlayer(Set))
8908                 if scapy.compat.orb(data[0][230]) == 11:
8909                     self.verify_ipfix_bib(data, 0, self.pg0.remote_ip6n)
8910                 elif scapy.compat.orb(data[0][230]) == 7:
8911                     self.verify_ipfix_nat64_ses(data,
8912                                                 0,
8913                                                 self.pg0.remote_ip6n,
8914                                                 self.pg1.remote_ip4,
8915                                                 25)
8916                 else:
8917                     self.logger.error(ppp("Unexpected or invalid packet: ", p))
8918
8919     def test_syslog_sess(self):
8920         """ Test syslog session creation and deletion """
8921         self.tcp_port_in = random.randint(1025, 65535)
8922         remote_host_ip6 = self.compose_ip6(self.pg1.remote_ip4,
8923                                            '64:ff9b::',
8924                                            96)
8925
8926         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr,
8927                                                 end_addr=self.nat_addr,
8928                                                 vrf_id=0xFFFFFFFF,
8929                                                 is_add=1)
8930         flags = self.config_flags.NAT_IS_INSIDE
8931         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
8932                                           sw_if_index=self.pg0.sw_if_index)
8933         self.vapi.nat64_add_del_interface(is_add=1, flags=0,
8934                                           sw_if_index=self.pg1.sw_if_index)
8935         self.vapi.syslog_set_filter(
8936             self.SYSLOG_SEVERITY.SYSLOG_API_SEVERITY_INFO)
8937         self.vapi.syslog_set_sender(self.pg3.local_ip4, self.pg3.remote_ip4)
8938
8939         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
8940              IPv6(src=self.pg0.remote_ip6, dst=remote_host_ip6) /
8941              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port))
8942         self.pg0.add_stream(p)
8943         self.pg_enable_capture(self.pg_interfaces)
8944         self.pg_start()
8945         p = self.pg1.get_capture(1)
8946         self.tcp_port_out = p[0][TCP].sport
8947         capture = self.pg3.get_capture(1)
8948         self.verify_syslog_sess(capture[0][Raw].load, is_ip6=True)
8949
8950         self.pg_enable_capture(self.pg_interfaces)
8951         self.pg_start()
8952         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr,
8953                                                 end_addr=self.nat_addr,
8954                                                 vrf_id=0xFFFFFFFF,
8955                                                 is_add=0)
8956         capture = self.pg3.get_capture(1)
8957         self.verify_syslog_sess(capture[0][Raw].load, False, True)
8958
8959     def nat64_get_ses_num(self):
8960         """
8961         Return number of active NAT64 sessions.
8962         """
8963         st = self.vapi.nat64_st_dump(proto=255)
8964         return len(st)
8965
8966     def clear_nat64(self):
8967         """
8968         Clear NAT64 configuration.
8969         """
8970         self.vapi.nat_ipfix_enable_disable(domain_id=self.ipfix_domain_id,
8971                                            src_port=self.ipfix_src_port,
8972                                            enable=0)
8973         self.ipfix_src_port = 4739
8974         self.ipfix_domain_id = 1
8975
8976         self.vapi.syslog_set_filter(
8977             self.SYSLOG_SEVERITY.SYSLOG_API_SEVERITY_EMERG)
8978
8979         self.vapi.nat_set_timeouts(udp=300, tcp_established=7440,
8980                                    tcp_transitory=240, icmp=60)
8981
8982         interfaces = self.vapi.nat64_interface_dump()
8983         for intf in interfaces:
8984             self.vapi.nat64_add_del_interface(is_add=0, flags=intf.flags,
8985                                               sw_if_index=intf.sw_if_index)
8986
8987         bib = self.vapi.nat64_bib_dump(proto=255)
8988         for bibe in bib:
8989             if bibe.flags & self.config_flags.NAT_IS_STATIC:
8990                 self.vapi.nat64_add_del_static_bib(i_addr=bibe.i_addr,
8991                                                    o_addr=bibe.o_addr,
8992                                                    i_port=bibe.i_port,
8993                                                    o_port=bibe.o_port,
8994                                                    proto=bibe.proto,
8995                                                    vrf_id=bibe.vrf_id,
8996                                                    is_add=0)
8997
8998         adresses = self.vapi.nat64_pool_addr_dump()
8999         for addr in adresses:
9000             self.vapi.nat64_add_del_pool_addr_range(start_addr=addr.address,
9001                                                     end_addr=addr.address,
9002                                                     vrf_id=addr.vrf_id,
9003                                                     is_add=0)
9004
9005         prefixes = self.vapi.nat64_prefix_dump()
9006         for prefix in prefixes:
9007             self.vapi.nat64_add_del_prefix(prefix=str(prefix.prefix),
9008                                            vrf_id=prefix.vrf_id, is_add=0)
9009
9010         bibs = self.statistics.get_counter('/nat64/total-bibs')
9011         self.assertEqual(bibs[0][0], 0)
9012         sessions = self.statistics.get_counter('/nat64/total-sessions')
9013         self.assertEqual(sessions[0][0], 0)
9014
9015     def tearDown(self):
9016         super(TestNAT64, self).tearDown()
9017         if not self.vpp_dead:
9018             self.clear_nat64()
9019
9020     def show_commands_at_teardown(self):
9021         self.logger.info(self.vapi.cli("show nat64 pool"))
9022         self.logger.info(self.vapi.cli("show nat64 interfaces"))
9023         self.logger.info(self.vapi.cli("show nat64 prefix"))
9024         self.logger.info(self.vapi.cli("show nat64 bib all"))
9025         self.logger.info(self.vapi.cli("show nat64 session table all"))
9026
9027
9028 class TestNAT66(MethodHolder):
9029     """ NAT66 Test Cases """
9030
9031     @classmethod
9032     def setUpClass(cls):
9033         super(TestNAT66, cls).setUpClass()
9034
9035         cls.nat_addr = 'fd01:ff::2'
9036
9037         cls.create_pg_interfaces(range(2))
9038         cls.interfaces = list(cls.pg_interfaces)
9039
9040         for i in cls.interfaces:
9041             i.admin_up()
9042             i.config_ip6()
9043             i.configure_ipv6_neighbors()
9044
9045     @classmethod
9046     def tearDownClass(cls):
9047         super(TestNAT66, cls).tearDownClass()
9048
9049     def test_static(self):
9050         """ 1:1 NAT66 test """
9051         flags = self.config_flags.NAT_IS_INSIDE
9052         self.vapi.nat66_add_del_interface(is_add=1, flags=flags,
9053                                           sw_if_index=self.pg0.sw_if_index)
9054         self.vapi.nat66_add_del_interface(is_add=1,
9055                                           sw_if_index=self.pg1.sw_if_index)
9056         self.vapi.nat66_add_del_static_mapping(
9057             local_ip_address=self.pg0.remote_ip6n,
9058             external_ip_address=self.nat_addr,
9059             is_add=1)
9060
9061         # in2out
9062         pkts = []
9063         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
9064              IPv6(src=self.pg0.remote_ip6, dst=self.pg1.remote_ip6) /
9065              TCP())
9066         pkts.append(p)
9067         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
9068              IPv6(src=self.pg0.remote_ip6, dst=self.pg1.remote_ip6) /
9069              UDP())
9070         pkts.append(p)
9071         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
9072              IPv6(src=self.pg0.remote_ip6, dst=self.pg1.remote_ip6) /
9073              ICMPv6EchoRequest())
9074         pkts.append(p)
9075         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
9076              IPv6(src=self.pg0.remote_ip6, dst=self.pg1.remote_ip6) /
9077              GRE() / IP() / TCP())
9078         pkts.append(p)
9079         self.pg0.add_stream(pkts)
9080         self.pg_enable_capture(self.pg_interfaces)
9081         self.pg_start()
9082         capture = self.pg1.get_capture(len(pkts))
9083
9084         for packet in capture:
9085             try:
9086                 self.assertEqual(packet[IPv6].src, self.nat_addr)
9087                 self.assertEqual(packet[IPv6].dst, self.pg1.remote_ip6)
9088                 self.assert_packet_checksums_valid(packet)
9089             except:
9090                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
9091                 raise
9092
9093         # out2in
9094         pkts = []
9095         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
9096              IPv6(src=self.pg1.remote_ip6, dst=self.nat_addr) /
9097              TCP())
9098         pkts.append(p)
9099         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
9100              IPv6(src=self.pg1.remote_ip6, dst=self.nat_addr) /
9101              UDP())
9102         pkts.append(p)
9103         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
9104              IPv6(src=self.pg1.remote_ip6, dst=self.nat_addr) /
9105              ICMPv6EchoReply())
9106         pkts.append(p)
9107         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
9108              IPv6(src=self.pg1.remote_ip6, dst=self.nat_addr) /
9109              GRE() / IP() / TCP())
9110         pkts.append(p)
9111         self.pg1.add_stream(pkts)
9112         self.pg_enable_capture(self.pg_interfaces)
9113         self.pg_start()
9114         capture = self.pg0.get_capture(len(pkts))
9115         for packet in capture:
9116             try:
9117                 self.assertEqual(packet[IPv6].src, self.pg1.remote_ip6)
9118                 self.assertEqual(packet[IPv6].dst, self.pg0.remote_ip6)
9119                 self.assert_packet_checksums_valid(packet)
9120             except:
9121                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
9122                 raise
9123
9124         sm = self.vapi.nat66_static_mapping_dump()
9125         self.assertEqual(len(sm), 1)
9126         self.assertEqual(sm[0].total_pkts, 8)
9127
9128     def test_check_no_translate(self):
9129         """ NAT66 translate only when egress interface is outside interface """
9130         flags = self.config_flags.NAT_IS_INSIDE
9131         self.vapi.nat66_add_del_interface(is_add=1, flags=flags,
9132                                           sw_if_index=self.pg0.sw_if_index)
9133         self.vapi.nat66_add_del_interface(is_add=1, flags=flags,
9134                                           sw_if_index=self.pg1.sw_if_index)
9135         self.vapi.nat66_add_del_static_mapping(
9136             local_ip_address=self.pg0.remote_ip6n,
9137             external_ip_address=self.nat_addr,
9138             is_add=1)
9139
9140         # in2out
9141         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
9142              IPv6(src=self.pg0.remote_ip6, dst=self.pg1.remote_ip6) /
9143              UDP())
9144         self.pg0.add_stream([p])
9145         self.pg_enable_capture(self.pg_interfaces)
9146         self.pg_start()
9147         capture = self.pg1.get_capture(1)
9148         packet = capture[0]
9149         try:
9150             self.assertEqual(packet[IPv6].src, self.pg0.remote_ip6)
9151             self.assertEqual(packet[IPv6].dst, self.pg1.remote_ip6)
9152         except:
9153             self.logger.error(ppp("Unexpected or invalid packet:", packet))
9154             raise
9155
9156     def clear_nat66(self):
9157         """
9158         Clear NAT66 configuration.
9159         """
9160         interfaces = self.vapi.nat66_interface_dump()
9161         for intf in interfaces:
9162             self.vapi.nat66_add_del_interface(is_add=0, flags=intf.flags,
9163                                               sw_if_index=intf.sw_if_index)
9164
9165         static_mappings = self.vapi.nat66_static_mapping_dump()
9166         for sm in static_mappings:
9167             self.vapi.nat66_add_del_static_mapping(
9168                 local_ip_address=sm.local_ip_address,
9169                 external_ip_address=sm.external_ip_address, vrf_id=sm.vrf_id,
9170                 is_add=0)
9171
9172     def tearDown(self):
9173         super(TestNAT66, self).tearDown()
9174         self.clear_nat66()
9175
9176     def show_commands_at_teardown(self):
9177         self.logger.info(self.vapi.cli("show nat66 interfaces"))
9178         self.logger.info(self.vapi.cli("show nat66 static mappings"))
9179
9180
9181 if __name__ == '__main__':
9182     unittest.main(testRunner=VppTestRunner)