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