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