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