nat: simplify bihash buckets/mem config
[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_out_of_ports(self):
4716         """ NAT44 dynamic translation test: out of ports """
4717
4718         flags = self.config_flags.NAT_IS_INSIDE
4719         self.vapi.nat44_interface_add_del_feature(
4720             sw_if_index=self.pg0.sw_if_index,
4721             flags=flags, is_add=1)
4722         self.vapi.nat44_interface_add_del_feature(
4723             sw_if_index=self.pg1.sw_if_index,
4724             is_add=1)
4725
4726         nat_config = self.vapi.nat_show_config()
4727         self.assertEqual(1, nat_config.endpoint_dependent)
4728
4729         # in2out and no NAT addresses added
4730         err_old = self.statistics.get_err_counter(
4731             '/err/nat44-ed-in2out-slowpath/out of ports')
4732
4733         pkts = self.create_stream_in(self.pg0, self.pg1)
4734         self.pg0.add_stream(pkts)
4735         self.pg_enable_capture(self.pg_interfaces)
4736         self.pg_start()
4737         self.pg1.get_capture(0, timeout=1)
4738
4739         err_new = self.statistics.get_err_counter(
4740             '/err/nat44-ed-in2out-slowpath/out of ports')
4741
4742         self.assertEqual(err_new - err_old, len(pkts))
4743
4744         # in2out after NAT addresses added
4745         self.nat44_add_address(self.nat_addr)
4746
4747         err_old = self.statistics.get_err_counter(
4748             '/err/nat44-ed-in2out-slowpath/out of ports')
4749
4750         pkts = self.create_stream_in(self.pg0, self.pg1)
4751         self.pg0.add_stream(pkts)
4752         self.pg_enable_capture(self.pg_interfaces)
4753         self.pg_start()
4754         capture = self.pg1.get_capture(len(pkts))
4755         self.verify_capture_out(capture)
4756
4757         err_new = self.statistics.get_err_counter(
4758             '/err/nat44-ed-in2out-slowpath/out of ports')
4759
4760         self.assertEqual(err_new, err_old)
4761
4762     def test_dynamic_output_feature_vrf(self):
4763         """ NAT44 dynamic translation test: output-feature, VRF"""
4764
4765         # other then default (0)
4766         new_vrf_id = 22
4767
4768         self.nat44_add_address(self.nat_addr)
4769         flags = self.config_flags.NAT_IS_INSIDE
4770         self.vapi.nat44_interface_add_del_output_feature(
4771             sw_if_index=self.pg7.sw_if_index,
4772             flags=flags, is_add=1)
4773         self.vapi.nat44_interface_add_del_output_feature(
4774             sw_if_index=self.pg8.sw_if_index,
4775             is_add=1)
4776
4777         try:
4778             self.vapi.ip_table_add_del(is_add=1,
4779                                        table={'table_id': new_vrf_id})
4780
4781             self.pg7.unconfig_ip4()
4782             self.pg7.set_table_ip4(new_vrf_id)
4783             self.pg7.config_ip4()
4784             self.pg7.resolve_arp()
4785
4786             self.pg8.unconfig_ip4()
4787             self.pg8.set_table_ip4(new_vrf_id)
4788             self.pg8.config_ip4()
4789             self.pg8.resolve_arp()
4790
4791             nat_config = self.vapi.nat_show_config()
4792             self.assertEqual(1, nat_config.endpoint_dependent)
4793
4794             # in2out
4795             tcpn = self.statistics.get_err_counter(
4796                 '/err/nat44-ed-in2out-slowpath/TCP packets')
4797             udpn = self.statistics.get_err_counter(
4798                 '/err/nat44-ed-in2out-slowpath/UDP packets')
4799             icmpn = self.statistics.get_err_counter(
4800                 '/err/nat44-ed-in2out-slowpath/ICMP packets')
4801             totaln = self.statistics.get_err_counter(
4802                 '/err/nat44-ed-in2out-slowpath/good in2out packets processed')
4803
4804             pkts = self.create_stream_in(self.pg7, self.pg8)
4805             self.pg7.add_stream(pkts)
4806             self.pg_enable_capture(self.pg_interfaces)
4807             self.pg_start()
4808             capture = self.pg8.get_capture(len(pkts))
4809             self.verify_capture_out(capture)
4810
4811             err = self.statistics.get_err_counter(
4812                 '/err/nat44-ed-in2out-slowpath/TCP packets')
4813             self.assertEqual(err - tcpn, 2)
4814             err = self.statistics.get_err_counter(
4815                 '/err/nat44-ed-in2out-slowpath/UDP packets')
4816             self.assertEqual(err - udpn, 1)
4817             err = self.statistics.get_err_counter(
4818                 '/err/nat44-ed-in2out-slowpath/ICMP packets')
4819             self.assertEqual(err - icmpn, 1)
4820             err = self.statistics.get_err_counter(
4821                 '/err/nat44-ed-in2out-slowpath/good in2out packets processed')
4822             self.assertEqual(err - totaln, 4)
4823
4824             # out2in
4825             tcpn = self.statistics.get_err_counter(
4826                 '/err/nat44-ed-out2in/TCP packets')
4827             udpn = self.statistics.get_err_counter(
4828                 '/err/nat44-ed-out2in/UDP packets')
4829             icmpn = self.statistics.get_err_counter(
4830                 '/err/nat44-ed-out2in-slowpath/ICMP packets')
4831             totaln = self.statistics.get_err_counter(
4832                 '/err/nat44-ed-out2in/good out2in packets processed')
4833
4834             pkts = self.create_stream_out(self.pg8)
4835             self.pg8.add_stream(pkts)
4836             self.pg_enable_capture(self.pg_interfaces)
4837             self.pg_start()
4838             capture = self.pg7.get_capture(len(pkts))
4839             self.verify_capture_in(capture, self.pg7)
4840
4841             err = self.statistics.get_err_counter(
4842                 '/err/nat44-ed-out2in/TCP packets')
4843             self.assertEqual(err - tcpn, 2)
4844             err = self.statistics.get_err_counter(
4845                 '/err/nat44-ed-out2in/UDP packets')
4846             self.assertEqual(err - udpn, 1)
4847             err = self.statistics.get_err_counter(
4848                 '/err/nat44-ed-out2in-slowpath/ICMP packets')
4849             self.assertEqual(err - icmpn, 1)
4850             err = self.statistics.get_err_counter(
4851                 '/err/nat44-ed-out2in/good out2in packets processed')
4852             self.assertEqual(err - totaln, 3)
4853
4854             sessions = self.statistics.get_counter('/nat44/total-sessions')
4855             self.assertEqual(sessions[0][0], 3)
4856
4857         finally:
4858             self.pg7.unconfig_ip4()
4859             self.pg7.set_table_ip4(1)
4860             self.pg7.config_ip4()
4861             self.pg7.resolve_arp()
4862
4863             self.pg8.unconfig_ip4()
4864             self.pg8.set_table_ip4(1)
4865             self.pg8.config_ip4()
4866             self.pg8.resolve_arp()
4867
4868             self.vapi.ip_table_add_del(is_add=0,
4869                                        table={'table_id': new_vrf_id})
4870
4871     def test_forwarding(self):
4872         """ NAT44 forwarding test """
4873
4874         flags = self.config_flags.NAT_IS_INSIDE
4875         self.vapi.nat44_interface_add_del_feature(
4876             sw_if_index=self.pg0.sw_if_index,
4877             flags=flags, is_add=1)
4878         self.vapi.nat44_interface_add_del_feature(
4879             sw_if_index=self.pg1.sw_if_index,
4880             is_add=1)
4881         self.vapi.nat44_forwarding_enable_disable(enable=1)
4882
4883         real_ip = self.pg0.remote_ip4
4884         alias_ip = self.nat_addr
4885         flags = self.config_flags.NAT_IS_ADDR_ONLY
4886         self.vapi.nat44_add_del_static_mapping(is_add=1,
4887                                                local_ip_address=real_ip,
4888                                                external_ip_address=alias_ip,
4889                                                external_sw_if_index=0xFFFFFFFF,
4890                                                flags=flags)
4891
4892         try:
4893             # in2out - static mapping match
4894
4895             pkts = self.create_stream_out(self.pg1)
4896             self.pg1.add_stream(pkts)
4897             self.pg_enable_capture(self.pg_interfaces)
4898             self.pg_start()
4899             capture = self.pg0.get_capture(len(pkts))
4900             self.verify_capture_in(capture, self.pg0)
4901
4902             pkts = self.create_stream_in(self.pg0, self.pg1)
4903             self.pg0.add_stream(pkts)
4904             self.pg_enable_capture(self.pg_interfaces)
4905             self.pg_start()
4906             capture = self.pg1.get_capture(len(pkts))
4907             self.verify_capture_out(capture, same_port=True)
4908
4909             # in2out - no static mapping match
4910
4911             host0 = self.pg0.remote_hosts[0]
4912             self.pg0.remote_hosts[0] = self.pg0.remote_hosts[1]
4913             try:
4914                 pkts = self.create_stream_out(self.pg1,
4915                                               dst_ip=self.pg0.remote_ip4,
4916                                               use_inside_ports=True)
4917                 self.pg1.add_stream(pkts)
4918                 self.pg_enable_capture(self.pg_interfaces)
4919                 self.pg_start()
4920                 capture = self.pg0.get_capture(len(pkts))
4921                 self.verify_capture_in(capture, self.pg0)
4922
4923                 pkts = self.create_stream_in(self.pg0, self.pg1)
4924                 self.pg0.add_stream(pkts)
4925                 self.pg_enable_capture(self.pg_interfaces)
4926                 self.pg_start()
4927                 capture = self.pg1.get_capture(len(pkts))
4928                 self.verify_capture_out(capture, nat_ip=self.pg0.remote_ip4,
4929                                         same_port=True)
4930             finally:
4931                 self.pg0.remote_hosts[0] = host0
4932
4933             user = self.pg0.remote_hosts[1]
4934             sessions = self.vapi.nat44_user_session_dump(user.ip4, 0)
4935             self.assertEqual(len(sessions), 3)
4936             self.assertTrue(sessions[0].flags &
4937                             self.config_flags.NAT_IS_EXT_HOST_VALID)
4938             self.vapi.nat44_del_session(
4939                 address=sessions[0].inside_ip_address,
4940                 port=sessions[0].inside_port,
4941                 protocol=sessions[0].protocol,
4942                 flags=(self.config_flags.NAT_IS_INSIDE |
4943                        self.config_flags.NAT_IS_EXT_HOST_VALID),
4944                 ext_host_address=sessions[0].ext_host_address,
4945                 ext_host_port=sessions[0].ext_host_port)
4946             sessions = self.vapi.nat44_user_session_dump(user.ip4, 0)
4947             self.assertEqual(len(sessions), 2)
4948
4949         finally:
4950             self.vapi.nat44_forwarding_enable_disable(enable=0)
4951             flags = self.config_flags.NAT_IS_ADDR_ONLY
4952             self.vapi.nat44_add_del_static_mapping(
4953                 is_add=0,
4954                 local_ip_address=real_ip,
4955                 external_ip_address=alias_ip,
4956                 external_sw_if_index=0xFFFFFFFF,
4957                 flags=flags)
4958
4959     def test_static_lb(self):
4960         """ NAT44 local service load balancing """
4961         external_addr_n = self.nat_addr
4962         external_port = 80
4963         local_port = 8080
4964         server1 = self.pg0.remote_hosts[0]
4965         server2 = self.pg0.remote_hosts[1]
4966
4967         locals = [{'addr': server1.ip4,
4968                    'port': local_port,
4969                    'probability': 70,
4970                    'vrf_id': 0},
4971                   {'addr': server2.ip4,
4972                    'port': local_port,
4973                    'probability': 30,
4974                    'vrf_id': 0}]
4975
4976         self.nat44_add_address(self.nat_addr)
4977         self.vapi.nat44_add_del_lb_static_mapping(
4978             is_add=1,
4979             external_addr=external_addr_n,
4980             external_port=external_port,
4981             protocol=IP_PROTOS.tcp,
4982             local_num=len(locals),
4983             locals=locals)
4984         flags = self.config_flags.NAT_IS_INSIDE
4985         self.vapi.nat44_interface_add_del_feature(
4986             sw_if_index=self.pg0.sw_if_index,
4987             flags=flags, is_add=1)
4988         self.vapi.nat44_interface_add_del_feature(
4989             sw_if_index=self.pg1.sw_if_index,
4990             is_add=1)
4991
4992         # from client to service
4993         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
4994              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
4995              TCP(sport=12345, dport=external_port))
4996         self.pg1.add_stream(p)
4997         self.pg_enable_capture(self.pg_interfaces)
4998         self.pg_start()
4999         capture = self.pg0.get_capture(1)
5000         p = capture[0]
5001         server = None
5002         try:
5003             ip = p[IP]
5004             tcp = p[TCP]
5005             self.assertIn(ip.dst, [server1.ip4, server2.ip4])
5006             if ip.dst == server1.ip4:
5007                 server = server1
5008             else:
5009                 server = server2
5010             self.assertEqual(tcp.dport, local_port)
5011             self.assert_packet_checksums_valid(p)
5012         except:
5013             self.logger.error(ppp("Unexpected or invalid packet:", p))
5014             raise
5015
5016         # from service back to client
5017         p = (Ether(src=server.mac, dst=self.pg0.local_mac) /
5018              IP(src=server.ip4, dst=self.pg1.remote_ip4) /
5019              TCP(sport=local_port, dport=12345))
5020         self.pg0.add_stream(p)
5021         self.pg_enable_capture(self.pg_interfaces)
5022         self.pg_start()
5023         capture = self.pg1.get_capture(1)
5024         p = capture[0]
5025         try:
5026             ip = p[IP]
5027             tcp = p[TCP]
5028             self.assertEqual(ip.src, self.nat_addr)
5029             self.assertEqual(tcp.sport, external_port)
5030             self.assert_packet_checksums_valid(p)
5031         except:
5032             self.logger.error(ppp("Unexpected or invalid packet:", p))
5033             raise
5034
5035         sessions = self.vapi.nat44_user_session_dump(server.ip4, 0)
5036         self.assertEqual(len(sessions), 1)
5037         self.assertTrue(sessions[0].flags &
5038                         self.config_flags.NAT_IS_EXT_HOST_VALID)
5039         self.vapi.nat44_del_session(
5040             address=sessions[0].inside_ip_address,
5041             port=sessions[0].inside_port,
5042             protocol=sessions[0].protocol,
5043             flags=(self.config_flags.NAT_IS_INSIDE |
5044                    self.config_flags.NAT_IS_EXT_HOST_VALID),
5045             ext_host_address=sessions[0].ext_host_address,
5046             ext_host_port=sessions[0].ext_host_port)
5047         sessions = self.vapi.nat44_user_session_dump(server.ip4, 0)
5048         self.assertEqual(len(sessions), 0)
5049
5050     @unittest.skipUnless(running_extended_tests, "part of extended tests")
5051     def test_static_lb_multi_clients(self):
5052         """ NAT44 local service load balancing - multiple clients"""
5053
5054         external_addr = self.nat_addr
5055         external_port = 80
5056         local_port = 8080
5057         server1 = self.pg0.remote_hosts[0]
5058         server2 = self.pg0.remote_hosts[1]
5059         server3 = self.pg0.remote_hosts[2]
5060
5061         locals = [{'addr': server1.ip4,
5062                    'port': local_port,
5063                    'probability': 90,
5064                    'vrf_id': 0},
5065                   {'addr': server2.ip4,
5066                    'port': local_port,
5067                    'probability': 10,
5068                    'vrf_id': 0}]
5069
5070         self.nat44_add_address(self.nat_addr)
5071         self.vapi.nat44_add_del_lb_static_mapping(is_add=1,
5072                                                   external_addr=external_addr,
5073                                                   external_port=external_port,
5074                                                   protocol=IP_PROTOS.tcp,
5075                                                   local_num=len(locals),
5076                                                   locals=locals)
5077         flags = self.config_flags.NAT_IS_INSIDE
5078         self.vapi.nat44_interface_add_del_feature(
5079             sw_if_index=self.pg0.sw_if_index,
5080             flags=flags, is_add=1)
5081         self.vapi.nat44_interface_add_del_feature(
5082             sw_if_index=self.pg1.sw_if_index,
5083             is_add=1)
5084
5085         server1_n = 0
5086         server2_n = 0
5087         clients = ip4_range(self.pg1.remote_ip4, 10, 50)
5088         pkts = []
5089         for client in clients:
5090             p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
5091                  IP(src=client, dst=self.nat_addr) /
5092                  TCP(sport=12345, dport=external_port))
5093             pkts.append(p)
5094         self.pg1.add_stream(pkts)
5095         self.pg_enable_capture(self.pg_interfaces)
5096         self.pg_start()
5097         capture = self.pg0.get_capture(len(pkts))
5098         for p in capture:
5099             if p[IP].dst == server1.ip4:
5100                 server1_n += 1
5101             else:
5102                 server2_n += 1
5103         self.assertGreater(server1_n, server2_n)
5104
5105         local = {
5106             'addr': server3.ip4,
5107             'port': local_port,
5108             'probability': 20,
5109             'vrf_id': 0
5110         }
5111
5112         # add new back-end
5113         self.vapi.nat44_lb_static_mapping_add_del_local(
5114             is_add=1,
5115             external_addr=external_addr,
5116             external_port=external_port,
5117             local=local,
5118             protocol=IP_PROTOS.tcp)
5119         server1_n = 0
5120         server2_n = 0
5121         server3_n = 0
5122         clients = ip4_range(self.pg1.remote_ip4, 60, 110)
5123         pkts = []
5124         for client in clients:
5125             p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
5126                  IP(src=client, dst=self.nat_addr) /
5127                  TCP(sport=12346, dport=external_port))
5128             pkts.append(p)
5129         self.assertGreater(len(pkts), 0)
5130         self.pg1.add_stream(pkts)
5131         self.pg_enable_capture(self.pg_interfaces)
5132         self.pg_start()
5133         capture = self.pg0.get_capture(len(pkts))
5134         for p in capture:
5135             if p[IP].dst == server1.ip4:
5136                 server1_n += 1
5137             elif p[IP].dst == server2.ip4:
5138                 server2_n += 1
5139             else:
5140                 server3_n += 1
5141         self.assertGreater(server1_n, 0)
5142         self.assertGreater(server2_n, 0)
5143         self.assertGreater(server3_n, 0)
5144
5145         local = {
5146             'addr': server2.ip4,
5147             'port': local_port,
5148             'probability': 10,
5149             'vrf_id': 0
5150         }
5151
5152         # remove one back-end
5153         self.vapi.nat44_lb_static_mapping_add_del_local(
5154             is_add=0,
5155             external_addr=external_addr,
5156             external_port=external_port,
5157             local=local,
5158             protocol=IP_PROTOS.tcp)
5159         server1_n = 0
5160         server2_n = 0
5161         server3_n = 0
5162         self.pg1.add_stream(pkts)
5163         self.pg_enable_capture(self.pg_interfaces)
5164         self.pg_start()
5165         capture = self.pg0.get_capture(len(pkts))
5166         for p in capture:
5167             if p[IP].dst == server1.ip4:
5168                 server1_n += 1
5169             elif p[IP].dst == server2.ip4:
5170                 server2_n += 1
5171             else:
5172                 server3_n += 1
5173         self.assertGreater(server1_n, 0)
5174         self.assertEqual(server2_n, 0)
5175         self.assertGreater(server3_n, 0)
5176
5177     def test_static_lb_2(self):
5178         """ NAT44 local service load balancing (asymmetrical rule) """
5179         external_addr = self.nat_addr
5180         external_port = 80
5181         local_port = 8080
5182         server1 = self.pg0.remote_hosts[0]
5183         server2 = self.pg0.remote_hosts[1]
5184
5185         locals = [{'addr': server1.ip4,
5186                    'port': local_port,
5187                    'probability': 70,
5188                    'vrf_id': 0},
5189                   {'addr': server2.ip4,
5190                    'port': local_port,
5191                    'probability': 30,
5192                    'vrf_id': 0}]
5193
5194         self.vapi.nat44_forwarding_enable_disable(enable=1)
5195         flags = self.config_flags.NAT_IS_OUT2IN_ONLY
5196         self.vapi.nat44_add_del_lb_static_mapping(is_add=1, flags=flags,
5197                                                   external_addr=external_addr,
5198                                                   external_port=external_port,
5199                                                   protocol=IP_PROTOS.tcp,
5200                                                   local_num=len(locals),
5201                                                   locals=locals)
5202         flags = self.config_flags.NAT_IS_INSIDE
5203         self.vapi.nat44_interface_add_del_feature(
5204             sw_if_index=self.pg0.sw_if_index,
5205             flags=flags, is_add=1)
5206         self.vapi.nat44_interface_add_del_feature(
5207             sw_if_index=self.pg1.sw_if_index,
5208             is_add=1)
5209
5210         # from client to service
5211         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
5212              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
5213              TCP(sport=12345, dport=external_port))
5214         self.pg1.add_stream(p)
5215         self.pg_enable_capture(self.pg_interfaces)
5216         self.pg_start()
5217         capture = self.pg0.get_capture(1)
5218         p = capture[0]
5219         server = None
5220         try:
5221             ip = p[IP]
5222             tcp = p[TCP]
5223             self.assertIn(ip.dst, [server1.ip4, server2.ip4])
5224             if ip.dst == server1.ip4:
5225                 server = server1
5226             else:
5227                 server = server2
5228             self.assertEqual(tcp.dport, local_port)
5229             self.assert_packet_checksums_valid(p)
5230         except:
5231             self.logger.error(ppp("Unexpected or invalid packet:", p))
5232             raise
5233
5234         # from service back to client
5235         p = (Ether(src=server.mac, dst=self.pg0.local_mac) /
5236              IP(src=server.ip4, dst=self.pg1.remote_ip4) /
5237              TCP(sport=local_port, dport=12345))
5238         self.pg0.add_stream(p)
5239         self.pg_enable_capture(self.pg_interfaces)
5240         self.pg_start()
5241         capture = self.pg1.get_capture(1)
5242         p = capture[0]
5243         try:
5244             ip = p[IP]
5245             tcp = p[TCP]
5246             self.assertEqual(ip.src, self.nat_addr)
5247             self.assertEqual(tcp.sport, external_port)
5248             self.assert_packet_checksums_valid(p)
5249         except:
5250             self.logger.error(ppp("Unexpected or invalid packet:", p))
5251             raise
5252
5253         # from client to server (no translation)
5254         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
5255              IP(src=self.pg1.remote_ip4, dst=server1.ip4) /
5256              TCP(sport=12346, dport=local_port))
5257         self.pg1.add_stream(p)
5258         self.pg_enable_capture(self.pg_interfaces)
5259         self.pg_start()
5260         capture = self.pg0.get_capture(1)
5261         p = capture[0]
5262         server = None
5263         try:
5264             ip = p[IP]
5265             tcp = p[TCP]
5266             self.assertEqual(ip.dst, server1.ip4)
5267             self.assertEqual(tcp.dport, local_port)
5268             self.assert_packet_checksums_valid(p)
5269         except:
5270             self.logger.error(ppp("Unexpected or invalid packet:", p))
5271             raise
5272
5273         # from service back to client (no translation)
5274         p = (Ether(src=server1.mac, dst=self.pg0.local_mac) /
5275              IP(src=server1.ip4, dst=self.pg1.remote_ip4) /
5276              TCP(sport=local_port, dport=12346))
5277         self.pg0.add_stream(p)
5278         self.pg_enable_capture(self.pg_interfaces)
5279         self.pg_start()
5280         capture = self.pg1.get_capture(1)
5281         p = capture[0]
5282         try:
5283             ip = p[IP]
5284             tcp = p[TCP]
5285             self.assertEqual(ip.src, server1.ip4)
5286             self.assertEqual(tcp.sport, local_port)
5287             self.assert_packet_checksums_valid(p)
5288         except:
5289             self.logger.error(ppp("Unexpected or invalid packet:", p))
5290             raise
5291
5292     def test_lb_affinity(self):
5293         """ NAT44 local service load balancing affinity """
5294         external_addr = self.nat_addr
5295         external_port = 80
5296         local_port = 8080
5297         server1 = self.pg0.remote_hosts[0]
5298         server2 = self.pg0.remote_hosts[1]
5299
5300         locals = [{'addr': server1.ip4,
5301                    'port': local_port,
5302                    'probability': 50,
5303                    'vrf_id': 0},
5304                   {'addr': server2.ip4,
5305                    'port': local_port,
5306                    'probability': 50,
5307                    'vrf_id': 0}]
5308
5309         self.nat44_add_address(self.nat_addr)
5310         self.vapi.nat44_add_del_lb_static_mapping(is_add=1,
5311                                                   external_addr=external_addr,
5312                                                   external_port=external_port,
5313                                                   protocol=IP_PROTOS.tcp,
5314                                                   affinity=10800,
5315                                                   local_num=len(locals),
5316                                                   locals=locals)
5317         flags = self.config_flags.NAT_IS_INSIDE
5318         self.vapi.nat44_interface_add_del_feature(
5319             sw_if_index=self.pg0.sw_if_index,
5320             flags=flags, is_add=1)
5321         self.vapi.nat44_interface_add_del_feature(
5322             sw_if_index=self.pg1.sw_if_index,
5323             is_add=1)
5324
5325         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
5326              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
5327              TCP(sport=1025, dport=external_port))
5328         self.pg1.add_stream(p)
5329         self.pg_enable_capture(self.pg_interfaces)
5330         self.pg_start()
5331         capture = self.pg0.get_capture(1)
5332         backend = capture[0][IP].dst
5333
5334         sessions = self.vapi.nat44_user_session_dump(backend, 0)
5335         self.assertEqual(len(sessions), 1)
5336         self.assertTrue(sessions[0].flags &
5337                         self.config_flags.NAT_IS_EXT_HOST_VALID)
5338         self.vapi.nat44_del_session(
5339             address=sessions[0].inside_ip_address,
5340             port=sessions[0].inside_port,
5341             protocol=sessions[0].protocol,
5342             flags=(self.config_flags.NAT_IS_INSIDE |
5343                    self.config_flags.NAT_IS_EXT_HOST_VALID),
5344             ext_host_address=sessions[0].ext_host_address,
5345             ext_host_port=sessions[0].ext_host_port)
5346
5347         pkts = []
5348         for port in range(1030, 1100):
5349             p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
5350                  IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
5351                  TCP(sport=port, dport=external_port))
5352             pkts.append(p)
5353         self.pg1.add_stream(pkts)
5354         self.pg_enable_capture(self.pg_interfaces)
5355         self.pg_start()
5356         capture = self.pg0.get_capture(len(pkts))
5357         for p in capture:
5358             self.assertEqual(p[IP].dst, backend)
5359
5360     def test_unknown_proto(self):
5361         """ NAT44 translate packet with unknown protocol """
5362         self.nat44_add_address(self.nat_addr)
5363         flags = self.config_flags.NAT_IS_INSIDE
5364         self.vapi.nat44_interface_add_del_feature(
5365             sw_if_index=self.pg0.sw_if_index,
5366             flags=flags, is_add=1)
5367         self.vapi.nat44_interface_add_del_feature(
5368             sw_if_index=self.pg1.sw_if_index,
5369             is_add=1)
5370
5371         # in2out
5372         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
5373              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
5374              TCP(sport=self.tcp_port_in, dport=20))
5375         self.pg0.add_stream(p)
5376         self.pg_enable_capture(self.pg_interfaces)
5377         self.pg_start()
5378         p = self.pg1.get_capture(1)
5379
5380         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
5381              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
5382              GRE() /
5383              IP(src=self.pg2.remote_ip4, dst=self.pg2.remote_ip4) /
5384              TCP(sport=1234, dport=1234))
5385         self.pg0.add_stream(p)
5386         self.pg_enable_capture(self.pg_interfaces)
5387         self.pg_start()
5388         p = self.pg1.get_capture(1)
5389         packet = p[0]
5390         try:
5391             self.assertEqual(packet[IP].src, self.nat_addr)
5392             self.assertEqual(packet[IP].dst, self.pg1.remote_ip4)
5393             self.assertEqual(packet.haslayer(GRE), 1)
5394             self.assert_packet_checksums_valid(packet)
5395         except:
5396             self.logger.error(ppp("Unexpected or invalid packet:", packet))
5397             raise
5398
5399         # out2in
5400         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
5401              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
5402              GRE() /
5403              IP(src=self.pg2.remote_ip4, dst=self.pg2.remote_ip4) /
5404              TCP(sport=1234, dport=1234))
5405         self.pg1.add_stream(p)
5406         self.pg_enable_capture(self.pg_interfaces)
5407         self.pg_start()
5408         p = self.pg0.get_capture(1)
5409         packet = p[0]
5410         try:
5411             self.assertEqual(packet[IP].src, self.pg1.remote_ip4)
5412             self.assertEqual(packet[IP].dst, self.pg0.remote_ip4)
5413             self.assertEqual(packet.haslayer(GRE), 1)
5414             self.assert_packet_checksums_valid(packet)
5415         except:
5416             self.logger.error(ppp("Unexpected or invalid packet:", packet))
5417             raise
5418
5419     def test_hairpinning_unknown_proto(self):
5420         """ NAT44 translate packet with unknown protocol - hairpinning """
5421         host = self.pg0.remote_hosts[0]
5422         server = self.pg0.remote_hosts[1]
5423         host_in_port = 1234
5424         server_out_port = 8765
5425         server_nat_ip = "10.0.0.11"
5426
5427         self.nat44_add_address(self.nat_addr)
5428         flags = self.config_flags.NAT_IS_INSIDE
5429         self.vapi.nat44_interface_add_del_feature(
5430             sw_if_index=self.pg0.sw_if_index,
5431             flags=flags, is_add=1)
5432         self.vapi.nat44_interface_add_del_feature(
5433             sw_if_index=self.pg1.sw_if_index,
5434             is_add=1)
5435
5436         # add static mapping for server
5437         self.nat44_add_static_mapping(server.ip4, server_nat_ip)
5438
5439         # host to server
5440         p = (Ether(src=host.mac, dst=self.pg0.local_mac) /
5441              IP(src=host.ip4, dst=server_nat_ip) /
5442              TCP(sport=host_in_port, dport=server_out_port))
5443         self.pg0.add_stream(p)
5444         self.pg_enable_capture(self.pg_interfaces)
5445         self.pg_start()
5446         self.pg0.get_capture(1)
5447
5448         p = (Ether(dst=self.pg0.local_mac, src=host.mac) /
5449              IP(src=host.ip4, dst=server_nat_ip) /
5450              GRE() /
5451              IP(src=self.pg2.remote_ip4, dst=self.pg2.remote_ip4) /
5452              TCP(sport=1234, dport=1234))
5453         self.pg0.add_stream(p)
5454         self.pg_enable_capture(self.pg_interfaces)
5455         self.pg_start()
5456         p = self.pg0.get_capture(1)
5457         packet = p[0]
5458         try:
5459             self.assertEqual(packet[IP].src, self.nat_addr)
5460             self.assertEqual(packet[IP].dst, server.ip4)
5461             self.assertEqual(packet.haslayer(GRE), 1)
5462             self.assert_packet_checksums_valid(packet)
5463         except:
5464             self.logger.error(ppp("Unexpected or invalid packet:", packet))
5465             raise
5466
5467         # server to host
5468         p = (Ether(dst=self.pg0.local_mac, src=server.mac) /
5469              IP(src=server.ip4, dst=self.nat_addr) /
5470              GRE() /
5471              IP(src=self.pg2.remote_ip4, dst=self.pg2.remote_ip4) /
5472              TCP(sport=1234, dport=1234))
5473         self.pg0.add_stream(p)
5474         self.pg_enable_capture(self.pg_interfaces)
5475         self.pg_start()
5476         p = self.pg0.get_capture(1)
5477         packet = p[0]
5478         try:
5479             self.assertEqual(packet[IP].src, server_nat_ip)
5480             self.assertEqual(packet[IP].dst, host.ip4)
5481             self.assertEqual(packet.haslayer(GRE), 1)
5482             self.assert_packet_checksums_valid(packet)
5483         except:
5484             self.logger.error(ppp("Unexpected or invalid packet:", packet))
5485             raise
5486
5487     def test_output_feature_and_service(self):
5488         """ NAT44 interface output feature and services """
5489         external_addr = '1.2.3.4'
5490         external_port = 80
5491         local_port = 8080
5492
5493         self.vapi.nat44_forwarding_enable_disable(enable=1)
5494         self.nat44_add_address(self.nat_addr)
5495         flags = self.config_flags.NAT_IS_ADDR_ONLY
5496         self.vapi.nat44_add_del_identity_mapping(
5497             ip_address=self.pg1.remote_ip4, sw_if_index=0xFFFFFFFF,
5498             flags=flags, is_add=1)
5499         flags = self.config_flags.NAT_IS_OUT2IN_ONLY
5500         self.nat44_add_static_mapping(self.pg0.remote_ip4, external_addr,
5501                                       local_port, external_port,
5502                                       proto=IP_PROTOS.tcp, flags=flags)
5503         flags = self.config_flags.NAT_IS_INSIDE
5504         self.vapi.nat44_interface_add_del_feature(
5505             sw_if_index=self.pg0.sw_if_index,
5506             is_add=1)
5507         self.vapi.nat44_interface_add_del_feature(
5508             sw_if_index=self.pg0.sw_if_index,
5509             flags=flags, is_add=1)
5510         self.vapi.nat44_interface_add_del_output_feature(
5511             is_add=1,
5512             sw_if_index=self.pg1.sw_if_index)
5513
5514         # from client to service
5515         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
5516              IP(src=self.pg1.remote_ip4, dst=external_addr) /
5517              TCP(sport=12345, dport=external_port))
5518         self.pg1.add_stream(p)
5519         self.pg_enable_capture(self.pg_interfaces)
5520         self.pg_start()
5521         capture = self.pg0.get_capture(1)
5522         p = capture[0]
5523         try:
5524             ip = p[IP]
5525             tcp = p[TCP]
5526             self.assertEqual(ip.dst, self.pg0.remote_ip4)
5527             self.assertEqual(tcp.dport, local_port)
5528             self.assert_packet_checksums_valid(p)
5529         except:
5530             self.logger.error(ppp("Unexpected or invalid packet:", p))
5531             raise
5532
5533         # from service back to client
5534         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
5535              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
5536              TCP(sport=local_port, dport=12345))
5537         self.pg0.add_stream(p)
5538         self.pg_enable_capture(self.pg_interfaces)
5539         self.pg_start()
5540         capture = self.pg1.get_capture(1)
5541         p = capture[0]
5542         try:
5543             ip = p[IP]
5544             tcp = p[TCP]
5545             self.assertEqual(ip.src, external_addr)
5546             self.assertEqual(tcp.sport, external_port)
5547             self.assert_packet_checksums_valid(p)
5548         except:
5549             self.logger.error(ppp("Unexpected or invalid packet:", p))
5550             raise
5551
5552         # from local network host to external network
5553         pkts = self.create_stream_in(self.pg0, self.pg1)
5554         self.pg0.add_stream(pkts)
5555         self.pg_enable_capture(self.pg_interfaces)
5556         self.pg_start()
5557         capture = self.pg1.get_capture(len(pkts))
5558         self.verify_capture_out(capture)
5559         pkts = self.create_stream_in(self.pg0, self.pg1)
5560         self.pg0.add_stream(pkts)
5561         self.pg_enable_capture(self.pg_interfaces)
5562         self.pg_start()
5563         capture = self.pg1.get_capture(len(pkts))
5564         self.verify_capture_out(capture)
5565
5566         # from external network back to local network host
5567         pkts = self.create_stream_out(self.pg1)
5568         self.pg1.add_stream(pkts)
5569         self.pg_enable_capture(self.pg_interfaces)
5570         self.pg_start()
5571         capture = self.pg0.get_capture(len(pkts))
5572         self.verify_capture_in(capture, self.pg0)
5573
5574     def test_output_feature_and_service2(self):
5575         """ NAT44 interface output feature and service host direct access """
5576         self.vapi.nat44_forwarding_enable_disable(enable=1)
5577         self.nat44_add_address(self.nat_addr)
5578         self.vapi.nat44_interface_add_del_output_feature(
5579             is_add=1,
5580             sw_if_index=self.pg1.sw_if_index)
5581
5582         # session initiated from service host - translate
5583         pkts = self.create_stream_in(self.pg0, self.pg1)
5584         self.pg0.add_stream(pkts)
5585         self.pg_enable_capture(self.pg_interfaces)
5586         self.pg_start()
5587         capture = self.pg1.get_capture(len(pkts))
5588         self.verify_capture_out(capture)
5589
5590         pkts = self.create_stream_out(self.pg1)
5591         self.pg1.add_stream(pkts)
5592         self.pg_enable_capture(self.pg_interfaces)
5593         self.pg_start()
5594         capture = self.pg0.get_capture(len(pkts))
5595         self.verify_capture_in(capture, self.pg0)
5596
5597         # session initiated from remote host - do not translate
5598         self.tcp_port_in = 60303
5599         self.udp_port_in = 60304
5600         self.icmp_id_in = 60305
5601         pkts = self.create_stream_out(self.pg1,
5602                                       self.pg0.remote_ip4,
5603                                       use_inside_ports=True)
5604         self.pg1.add_stream(pkts)
5605         self.pg_enable_capture(self.pg_interfaces)
5606         self.pg_start()
5607         capture = self.pg0.get_capture(len(pkts))
5608         self.verify_capture_in(capture, self.pg0)
5609
5610         pkts = self.create_stream_in(self.pg0, self.pg1)
5611         self.pg0.add_stream(pkts)
5612         self.pg_enable_capture(self.pg_interfaces)
5613         self.pg_start()
5614         capture = self.pg1.get_capture(len(pkts))
5615         self.verify_capture_out(capture, nat_ip=self.pg0.remote_ip4,
5616                                 same_port=True)
5617
5618     def test_output_feature_and_service3(self):
5619         """ NAT44 interface output feature and DST NAT """
5620         external_addr = '1.2.3.4'
5621         external_port = 80
5622         local_port = 8080
5623
5624         self.vapi.nat44_forwarding_enable_disable(enable=1)
5625         self.nat44_add_address(self.nat_addr)
5626         flags = self.config_flags.NAT_IS_OUT2IN_ONLY
5627         self.nat44_add_static_mapping(self.pg1.remote_ip4, external_addr,
5628                                       local_port, external_port,
5629                                       proto=IP_PROTOS.tcp, flags=flags)
5630         flags = self.config_flags.NAT_IS_INSIDE
5631         self.vapi.nat44_interface_add_del_feature(
5632             sw_if_index=self.pg0.sw_if_index,
5633             is_add=1)
5634         self.vapi.nat44_interface_add_del_feature(
5635             sw_if_index=self.pg0.sw_if_index,
5636             flags=flags, is_add=1)
5637         self.vapi.nat44_interface_add_del_output_feature(
5638             is_add=1,
5639             sw_if_index=self.pg1.sw_if_index)
5640
5641         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
5642              IP(src=self.pg0.remote_ip4, dst=external_addr) /
5643              TCP(sport=12345, dport=external_port))
5644         self.pg0.add_stream(p)
5645         self.pg_enable_capture(self.pg_interfaces)
5646         self.pg_start()
5647         capture = self.pg1.get_capture(1)
5648         p = capture[0]
5649         try:
5650             ip = p[IP]
5651             tcp = p[TCP]
5652             self.assertEqual(ip.src, self.pg0.remote_ip4)
5653             self.assertEqual(tcp.sport, 12345)
5654             self.assertEqual(ip.dst, self.pg1.remote_ip4)
5655             self.assertEqual(tcp.dport, local_port)
5656             self.assert_packet_checksums_valid(p)
5657         except:
5658             self.logger.error(ppp("Unexpected or invalid packet:", p))
5659             raise
5660
5661         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
5662              IP(src=self.pg1.remote_ip4, dst=self.pg0.remote_ip4) /
5663              TCP(sport=local_port, dport=12345))
5664         self.pg1.add_stream(p)
5665         self.pg_enable_capture(self.pg_interfaces)
5666         self.pg_start()
5667         capture = self.pg0.get_capture(1)
5668         p = capture[0]
5669         try:
5670             ip = p[IP]
5671             tcp = p[TCP]
5672             self.assertEqual(ip.src, external_addr)
5673             self.assertEqual(tcp.sport, external_port)
5674             self.assertEqual(ip.dst, self.pg0.remote_ip4)
5675             self.assertEqual(tcp.dport, 12345)
5676             self.assert_packet_checksums_valid(p)
5677         except:
5678             self.logger.error(ppp("Unexpected or invalid packet:", p))
5679             raise
5680
5681     def test_next_src_nat(self):
5682         """ On way back forward packet to nat44-in2out node. """
5683         twice_nat_addr = '10.0.1.3'
5684         external_port = 80
5685         local_port = 8080
5686         post_twice_nat_port = 0
5687
5688         self.vapi.nat44_forwarding_enable_disable(enable=1)
5689         self.nat44_add_address(twice_nat_addr, twice_nat=1)
5690         flags = (self.config_flags.NAT_IS_OUT2IN_ONLY |
5691                  self.config_flags.NAT_IS_SELF_TWICE_NAT)
5692         self.nat44_add_static_mapping(self.pg6.remote_ip4, self.pg1.remote_ip4,
5693                                       local_port, external_port,
5694                                       proto=IP_PROTOS.tcp, vrf_id=1,
5695                                       flags=flags)
5696         self.vapi.nat44_interface_add_del_feature(
5697             sw_if_index=self.pg6.sw_if_index,
5698             is_add=1)
5699
5700         p = (Ether(src=self.pg6.remote_mac, dst=self.pg6.local_mac) /
5701              IP(src=self.pg6.remote_ip4, dst=self.pg1.remote_ip4) /
5702              TCP(sport=12345, dport=external_port))
5703         self.pg6.add_stream(p)
5704         self.pg_enable_capture(self.pg_interfaces)
5705         self.pg_start()
5706         capture = self.pg6.get_capture(1)
5707         p = capture[0]
5708         try:
5709             ip = p[IP]
5710             tcp = p[TCP]
5711             self.assertEqual(ip.src, twice_nat_addr)
5712             self.assertNotEqual(tcp.sport, 12345)
5713             post_twice_nat_port = tcp.sport
5714             self.assertEqual(ip.dst, self.pg6.remote_ip4)
5715             self.assertEqual(tcp.dport, local_port)
5716             self.assert_packet_checksums_valid(p)
5717         except:
5718             self.logger.error(ppp("Unexpected or invalid packet:", p))
5719             raise
5720
5721         p = (Ether(src=self.pg6.remote_mac, dst=self.pg6.local_mac) /
5722              IP(src=self.pg6.remote_ip4, dst=twice_nat_addr) /
5723              TCP(sport=local_port, dport=post_twice_nat_port))
5724         self.pg6.add_stream(p)
5725         self.pg_enable_capture(self.pg_interfaces)
5726         self.pg_start()
5727         capture = self.pg6.get_capture(1)
5728         p = capture[0]
5729         try:
5730             ip = p[IP]
5731             tcp = p[TCP]
5732             self.assertEqual(ip.src, self.pg1.remote_ip4)
5733             self.assertEqual(tcp.sport, external_port)
5734             self.assertEqual(ip.dst, self.pg6.remote_ip4)
5735             self.assertEqual(tcp.dport, 12345)
5736             self.assert_packet_checksums_valid(p)
5737         except:
5738             self.logger.error(ppp("Unexpected or invalid packet:", p))
5739             raise
5740
5741     def twice_nat_common(self, self_twice_nat=False, same_pg=False, lb=False,
5742                          client_id=None):
5743         twice_nat_addr = '10.0.1.3'
5744
5745         port_in = 8080
5746         if lb:
5747             if not same_pg:
5748                 port_in1 = port_in
5749                 port_in2 = port_in
5750             else:
5751                 port_in1 = port_in + 1
5752                 port_in2 = port_in + 2
5753
5754         port_out = 80
5755         eh_port_out = 4567
5756
5757         server1 = self.pg0.remote_hosts[0]
5758         server2 = self.pg0.remote_hosts[1]
5759         if lb and same_pg:
5760             server2 = server1
5761         if not lb:
5762             server = server1
5763
5764         pg0 = self.pg0
5765         if same_pg:
5766             pg1 = self.pg0
5767         else:
5768             pg1 = self.pg1
5769
5770         eh_translate = ((not self_twice_nat) or (not lb and same_pg) or
5771                         client_id == 1)
5772
5773         self.nat44_add_address(self.nat_addr)
5774         self.nat44_add_address(twice_nat_addr, twice_nat=1)
5775
5776         flags = 0
5777         if self_twice_nat:
5778             flags |= self.config_flags.NAT_IS_SELF_TWICE_NAT
5779         else:
5780             flags |= self.config_flags.NAT_IS_TWICE_NAT
5781
5782         if not lb:
5783             self.nat44_add_static_mapping(pg0.remote_ip4, self.nat_addr,
5784                                           port_in, port_out,
5785                                           proto=IP_PROTOS.tcp,
5786                                           flags=flags)
5787         else:
5788             locals = [{'addr': server1.ip4,
5789                        'port': port_in1,
5790                        'probability': 50,
5791                        'vrf_id': 0},
5792                       {'addr': server2.ip4,
5793                        'port': port_in2,
5794                        'probability': 50,
5795                        'vrf_id': 0}]
5796             out_addr = self.nat_addr
5797
5798             self.vapi.nat44_add_del_lb_static_mapping(is_add=1, flags=flags,
5799                                                       external_addr=out_addr,
5800                                                       external_port=port_out,
5801                                                       protocol=IP_PROTOS.tcp,
5802                                                       local_num=len(locals),
5803                                                       locals=locals)
5804         flags = self.config_flags.NAT_IS_INSIDE
5805         self.vapi.nat44_interface_add_del_feature(
5806             sw_if_index=pg0.sw_if_index,
5807             flags=flags, is_add=1)
5808         self.vapi.nat44_interface_add_del_feature(
5809             sw_if_index=pg1.sw_if_index,
5810             is_add=1)
5811
5812         if same_pg:
5813             if not lb:
5814                 client = server
5815             else:
5816                 assert client_id is not None
5817                 if client_id == 1:
5818                     client = self.pg0.remote_hosts[0]
5819                 elif client_id == 2:
5820                     client = self.pg0.remote_hosts[1]
5821         else:
5822             client = pg1.remote_hosts[0]
5823         p = (Ether(src=pg1.remote_mac, dst=pg1.local_mac) /
5824              IP(src=client.ip4, dst=self.nat_addr) /
5825              TCP(sport=eh_port_out, dport=port_out))
5826         pg1.add_stream(p)
5827         self.pg_enable_capture(self.pg_interfaces)
5828         self.pg_start()
5829         capture = pg0.get_capture(1)
5830         p = capture[0]
5831         try:
5832             ip = p[IP]
5833             tcp = p[TCP]
5834             if lb:
5835                 if ip.dst == server1.ip4:
5836                     server = server1
5837                     port_in = port_in1
5838                 else:
5839                     server = server2
5840                     port_in = port_in2
5841             self.assertEqual(ip.dst, server.ip4)
5842             if lb and same_pg:
5843                 self.assertIn(tcp.dport, [port_in1, port_in2])
5844             else:
5845                 self.assertEqual(tcp.dport, port_in)
5846             if eh_translate:
5847                 self.assertEqual(ip.src, twice_nat_addr)
5848                 self.assertNotEqual(tcp.sport, eh_port_out)
5849             else:
5850                 self.assertEqual(ip.src, client.ip4)
5851                 self.assertEqual(tcp.sport, eh_port_out)
5852             eh_addr_in = ip.src
5853             eh_port_in = tcp.sport
5854             saved_port_in = tcp.dport
5855             self.assert_packet_checksums_valid(p)
5856         except:
5857             self.logger.error(ppp("Unexpected or invalid packet:", p))
5858             raise
5859
5860         p = (Ether(src=server.mac, dst=pg0.local_mac) /
5861              IP(src=server.ip4, dst=eh_addr_in) /
5862              TCP(sport=saved_port_in, dport=eh_port_in))
5863         pg0.add_stream(p)
5864         self.pg_enable_capture(self.pg_interfaces)
5865         self.pg_start()
5866         capture = pg1.get_capture(1)
5867         p = capture[0]
5868         try:
5869             ip = p[IP]
5870             tcp = p[TCP]
5871             self.assertEqual(ip.dst, client.ip4)
5872             self.assertEqual(ip.src, self.nat_addr)
5873             self.assertEqual(tcp.dport, eh_port_out)
5874             self.assertEqual(tcp.sport, port_out)
5875             self.assert_packet_checksums_valid(p)
5876         except:
5877             self.logger.error(ppp("Unexpected or invalid packet:", p))
5878             raise
5879
5880         if eh_translate:
5881             sessions = self.vapi.nat44_user_session_dump(server.ip4, 0)
5882             self.assertEqual(len(sessions), 1)
5883             self.assertTrue(sessions[0].flags &
5884                             self.config_flags.NAT_IS_EXT_HOST_VALID)
5885             self.assertTrue(sessions[0].flags &
5886                             self.config_flags.NAT_IS_TWICE_NAT)
5887             self.logger.info(self.vapi.cli("show nat44 sessions detail"))
5888             self.vapi.nat44_del_session(
5889                 address=sessions[0].inside_ip_address,
5890                 port=sessions[0].inside_port,
5891                 protocol=sessions[0].protocol,
5892                 flags=(self.config_flags.NAT_IS_INSIDE |
5893                        self.config_flags.NAT_IS_EXT_HOST_VALID),
5894                 ext_host_address=sessions[0].ext_host_nat_address,
5895                 ext_host_port=sessions[0].ext_host_nat_port)
5896             sessions = self.vapi.nat44_user_session_dump(server.ip4, 0)
5897             self.assertEqual(len(sessions), 0)
5898
5899     def test_twice_nat(self):
5900         """ Twice NAT44 """
5901         self.twice_nat_common()
5902
5903     def test_self_twice_nat_positive(self):
5904         """ Self Twice NAT44 (positive test) """
5905         self.twice_nat_common(self_twice_nat=True, same_pg=True)
5906
5907     def test_self_twice_nat_negative(self):
5908         """ Self Twice NAT44 (negative test) """
5909         self.twice_nat_common(self_twice_nat=True)
5910
5911     def test_twice_nat_lb(self):
5912         """ Twice NAT44 local service load balancing """
5913         self.twice_nat_common(lb=True)
5914
5915     def test_self_twice_nat_lb_positive(self):
5916         """ Self Twice NAT44 local service load balancing (positive test) """
5917         self.twice_nat_common(lb=True, self_twice_nat=True, same_pg=True,
5918                               client_id=1)
5919
5920     def test_self_twice_nat_lb_negative(self):
5921         """ Self Twice NAT44 local service load balancing (negative test) """
5922         self.twice_nat_common(lb=True, self_twice_nat=True, same_pg=True,
5923                               client_id=2)
5924
5925     def test_twice_nat_interface_addr(self):
5926         """ Acquire twice NAT44 addresses from interface """
5927         flags = self.config_flags.NAT_IS_TWICE_NAT
5928         self.vapi.nat44_add_del_interface_addr(
5929             is_add=1,
5930             sw_if_index=self.pg3.sw_if_index,
5931             flags=flags)
5932
5933         # no address in NAT pool
5934         adresses = self.vapi.nat44_address_dump()
5935         self.assertEqual(0, len(adresses))
5936
5937         # configure interface address and check NAT address pool
5938         self.pg3.config_ip4()
5939         adresses = self.vapi.nat44_address_dump()
5940         self.assertEqual(1, len(adresses))
5941         self.assertEqual(str(adresses[0].ip_address),
5942                          self.pg3.local_ip4)
5943         self.assertEqual(adresses[0].flags, flags)
5944
5945         # remove interface address and check NAT address pool
5946         self.pg3.unconfig_ip4()
5947         adresses = self.vapi.nat44_address_dump()
5948         self.assertEqual(0, len(adresses))
5949
5950     def test_tcp_close(self):
5951         """ Close TCP session from inside network - output feature """
5952         self.vapi.nat44_forwarding_enable_disable(enable=1)
5953         self.nat44_add_address(self.pg1.local_ip4)
5954         twice_nat_addr = '10.0.1.3'
5955         service_ip = '192.168.16.150'
5956         self.nat44_add_address(twice_nat_addr, twice_nat=1)
5957         flags = self.config_flags.NAT_IS_INSIDE
5958         self.vapi.nat44_interface_add_del_feature(
5959             sw_if_index=self.pg0.sw_if_index,
5960             is_add=1)
5961         self.vapi.nat44_interface_add_del_feature(
5962             sw_if_index=self.pg0.sw_if_index,
5963             flags=flags, is_add=1)
5964         self.vapi.nat44_interface_add_del_output_feature(
5965             is_add=1,
5966             sw_if_index=self.pg1.sw_if_index)
5967         flags = (self.config_flags.NAT_IS_OUT2IN_ONLY |
5968                  self.config_flags.NAT_IS_TWICE_NAT)
5969         self.nat44_add_static_mapping(self.pg0.remote_ip4,
5970                                       service_ip,
5971                                       80,
5972                                       80,
5973                                       proto=IP_PROTOS.tcp,
5974                                       flags=flags)
5975         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
5976         start_sessnum = len(sessions)
5977
5978         # SYN packet out->in
5979         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
5980              IP(src=self.pg1.remote_ip4, dst=service_ip) /
5981              TCP(sport=33898, dport=80, flags="S"))
5982         self.pg1.add_stream(p)
5983         self.pg_enable_capture(self.pg_interfaces)
5984         self.pg_start()
5985         capture = self.pg0.get_capture(1)
5986         p = capture[0]
5987         tcp_port = p[TCP].sport
5988
5989         # SYN + ACK packet in->out
5990         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
5991              IP(src=self.pg0.remote_ip4, dst=twice_nat_addr) /
5992              TCP(sport=80, dport=tcp_port, flags="SA"))
5993         self.pg0.add_stream(p)
5994         self.pg_enable_capture(self.pg_interfaces)
5995         self.pg_start()
5996         self.pg1.get_capture(1)
5997
5998         # ACK packet out->in
5999         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
6000              IP(src=self.pg1.remote_ip4, dst=service_ip) /
6001              TCP(sport=33898, dport=80, flags="A"))
6002         self.pg1.add_stream(p)
6003         self.pg_enable_capture(self.pg_interfaces)
6004         self.pg_start()
6005         self.pg0.get_capture(1)
6006
6007         # FIN packet in -> out
6008         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6009              IP(src=self.pg0.remote_ip4, dst=twice_nat_addr) /
6010              TCP(sport=80, dport=tcp_port, flags="FA", seq=100, ack=300))
6011         self.pg0.add_stream(p)
6012         self.pg_enable_capture(self.pg_interfaces)
6013         self.pg_start()
6014         self.pg1.get_capture(1)
6015
6016         # FIN+ACK packet out -> in
6017         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
6018              IP(src=self.pg1.remote_ip4, dst=service_ip) /
6019              TCP(sport=33898, dport=80, flags="FA", seq=300, ack=101))
6020         self.pg1.add_stream(p)
6021         self.pg_enable_capture(self.pg_interfaces)
6022         self.pg_start()
6023         self.pg0.get_capture(1)
6024
6025         # ACK packet in -> out
6026         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6027              IP(src=self.pg0.remote_ip4, dst=twice_nat_addr) /
6028              TCP(sport=80, dport=tcp_port, flags="A", seq=101, ack=301))
6029         self.pg0.add_stream(p)
6030         self.pg_enable_capture(self.pg_interfaces)
6031         self.pg_start()
6032         self.pg1.get_capture(1)
6033
6034         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4,
6035                                                      0)
6036         self.assertEqual(len(sessions) - start_sessnum, 0)
6037
6038     def test_tcp_session_close_in(self):
6039         """ Close TCP session from inside network """
6040         self.tcp_port_out = 10505
6041         self.nat44_add_address(self.nat_addr)
6042         flags = self.config_flags.NAT_IS_TWICE_NAT
6043         self.nat44_add_static_mapping(self.pg0.remote_ip4,
6044                                       self.nat_addr,
6045                                       self.tcp_port_in,
6046                                       self.tcp_port_out,
6047                                       proto=IP_PROTOS.tcp,
6048                                       flags=flags)
6049         flags = self.config_flags.NAT_IS_INSIDE
6050         self.vapi.nat44_interface_add_del_feature(
6051             sw_if_index=self.pg0.sw_if_index,
6052             flags=flags, is_add=1)
6053         self.vapi.nat44_interface_add_del_feature(
6054             sw_if_index=self.pg1.sw_if_index,
6055             is_add=1)
6056
6057         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
6058         start_sessnum = len(sessions)
6059
6060         self.vapi.nat_set_timeouts(udp=300, tcp_established=7440,
6061                                    tcp_transitory=2, icmp=5)
6062
6063         self.initiate_tcp_session(self.pg0, self.pg1)
6064
6065         # FIN packet in -> out
6066         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6067              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6068              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
6069                  flags="FA", seq=100, ack=300))
6070         self.pg0.add_stream(p)
6071         self.pg_enable_capture(self.pg_interfaces)
6072         self.pg_start()
6073         self.pg1.get_capture(1)
6074
6075         pkts = []
6076
6077         # ACK packet out -> in
6078         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
6079              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
6080              TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
6081                  flags="A", seq=300, ack=101))
6082         pkts.append(p)
6083
6084         # FIN packet out -> in
6085         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
6086              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
6087              TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
6088                  flags="FA", seq=300, ack=101))
6089         pkts.append(p)
6090
6091         self.pg1.add_stream(pkts)
6092         self.pg_enable_capture(self.pg_interfaces)
6093         self.pg_start()
6094         self.pg0.get_capture(2)
6095
6096         # ACK packet in -> out
6097         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6098              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6099              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
6100                  flags="A", seq=101, ack=301))
6101         self.pg0.add_stream(p)
6102         self.pg_enable_capture(self.pg_interfaces)
6103         self.pg_start()
6104         self.pg1.get_capture(1)
6105
6106         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
6107         self.assertEqual(len(sessions) - start_sessnum, 1)
6108
6109         stats = self.statistics.get_counter(
6110             '/err/nat44-ed-out2in/drops due to TCP in transitory timeout')
6111         out2in_drops = stats[0]
6112         stats = self.statistics.get_counter(
6113             '/err/nat44-ed-in2out/drops due to TCP in transitory timeout')
6114         in2out_drops = stats[0]
6115
6116         # extra FIN packet out -> in - this should be dropped
6117         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
6118              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
6119              TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
6120                  flags="FA", seq=300, ack=101))
6121
6122         self.pg1.add_stream(p)
6123         self.pg_enable_capture(self.pg_interfaces)
6124         self.pg_start()
6125         self.pg0.assert_nothing_captured()
6126
6127         # extra ACK packet in -> out - this should be dropped
6128         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6129              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6130              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
6131                  flags="A", seq=101, ack=301))
6132         self.pg0.add_stream(p)
6133         self.pg_enable_capture(self.pg_interfaces)
6134         self.pg_start()
6135         self.pg1.assert_nothing_captured()
6136
6137         stats = self.statistics.get_counter(
6138             '/err/nat44-ed-out2in/drops due to TCP in transitory timeout')
6139         self.assertEqual(stats[0] - out2in_drops, 1)
6140         stats = self.statistics.get_counter(
6141             '/err/nat44-ed-in2out/drops due to TCP in transitory timeout')
6142         self.assertEqual(stats[0] - in2out_drops, 1)
6143
6144         self.sleep(3)
6145         # extra ACK packet in -> out - this will cause session to be wiped
6146         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6147              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6148              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
6149                  flags="A", seq=101, ack=301))
6150         self.pg0.add_stream(p)
6151         self.pg_enable_capture(self.pg_interfaces)
6152         self.pg_start()
6153         self.pg1.assert_nothing_captured()
6154         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
6155         self.assertEqual(len(sessions) - start_sessnum, 0)
6156
6157     def test_tcp_session_close_out(self):
6158         """ Close TCP session from outside network """
6159         self.tcp_port_out = 10505
6160         self.nat44_add_address(self.nat_addr)
6161         flags = self.config_flags.NAT_IS_TWICE_NAT
6162         self.nat44_add_static_mapping(self.pg0.remote_ip4,
6163                                       self.nat_addr,
6164                                       self.tcp_port_in,
6165                                       self.tcp_port_out,
6166                                       proto=IP_PROTOS.tcp,
6167                                       flags=flags)
6168         flags = self.config_flags.NAT_IS_INSIDE
6169         self.vapi.nat44_interface_add_del_feature(
6170             sw_if_index=self.pg0.sw_if_index,
6171             flags=flags, is_add=1)
6172         self.vapi.nat44_interface_add_del_feature(
6173             sw_if_index=self.pg1.sw_if_index,
6174             is_add=1)
6175
6176         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
6177         start_sessnum = len(sessions)
6178
6179         self.vapi.nat_set_timeouts(udp=300, tcp_established=7440,
6180                                    tcp_transitory=2, icmp=5)
6181
6182         self.initiate_tcp_session(self.pg0, self.pg1)
6183
6184         # FIN packet out -> in
6185         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
6186              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
6187              TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
6188                  flags="FA", seq=100, ack=300))
6189         self.pg1.add_stream(p)
6190         self.pg_enable_capture(self.pg_interfaces)
6191         self.pg_start()
6192         self.pg0.get_capture(1)
6193
6194         # FIN+ACK packet in -> out
6195         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6196              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6197              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
6198                  flags="FA", seq=300, ack=101))
6199
6200         self.pg0.add_stream(p)
6201         self.pg_enable_capture(self.pg_interfaces)
6202         self.pg_start()
6203         self.pg1.get_capture(1)
6204
6205         # ACK packet out -> in
6206         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
6207              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
6208              TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
6209                  flags="A", seq=101, ack=301))
6210         self.pg1.add_stream(p)
6211         self.pg_enable_capture(self.pg_interfaces)
6212         self.pg_start()
6213         self.pg0.get_capture(1)
6214
6215         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
6216         self.assertEqual(len(sessions) - start_sessnum, 1)
6217
6218         stats = self.statistics.get_counter(
6219             '/err/nat44-ed-out2in/drops due to TCP in transitory timeout')
6220         out2in_drops = stats[0]
6221         stats = self.statistics.get_counter(
6222             '/err/nat44-ed-in2out/drops due to TCP in transitory timeout')
6223         in2out_drops = stats[0]
6224
6225         # extra FIN packet out -> in - this should be dropped
6226         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
6227              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
6228              TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
6229                  flags="FA", seq=300, ack=101))
6230
6231         self.pg1.add_stream(p)
6232         self.pg_enable_capture(self.pg_interfaces)
6233         self.pg_start()
6234         self.pg0.assert_nothing_captured()
6235
6236         # extra ACK packet in -> out - this should be dropped
6237         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6238              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6239              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
6240                  flags="A", seq=101, ack=301))
6241         self.pg0.add_stream(p)
6242         self.pg_enable_capture(self.pg_interfaces)
6243         self.pg_start()
6244         self.pg1.assert_nothing_captured()
6245
6246         stats = self.statistics.get_counter(
6247             '/err/nat44-ed-out2in/drops due to TCP in transitory timeout')
6248         self.assertEqual(stats[0] - out2in_drops, 1)
6249         stats = self.statistics.get_counter(
6250             '/err/nat44-ed-in2out/drops due to TCP in transitory timeout')
6251         self.assertEqual(stats[0] - in2out_drops, 1)
6252
6253         self.sleep(3)
6254         # extra ACK packet in -> out - this will cause session to be wiped
6255         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6256              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6257              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
6258                  flags="A", seq=101, ack=301))
6259         self.pg0.add_stream(p)
6260         self.pg_enable_capture(self.pg_interfaces)
6261         self.pg_start()
6262         self.pg1.assert_nothing_captured()
6263         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
6264         self.assertEqual(len(sessions) - start_sessnum, 0)
6265
6266     def test_tcp_session_close_simultaneous(self):
6267         """ Close TCP session from inside network """
6268         self.tcp_port_out = 10505
6269         self.nat44_add_address(self.nat_addr)
6270         flags = self.config_flags.NAT_IS_TWICE_NAT
6271         self.nat44_add_static_mapping(self.pg0.remote_ip4,
6272                                       self.nat_addr,
6273                                       self.tcp_port_in,
6274                                       self.tcp_port_out,
6275                                       proto=IP_PROTOS.tcp,
6276                                       flags=flags)
6277         flags = self.config_flags.NAT_IS_INSIDE
6278         self.vapi.nat44_interface_add_del_feature(
6279             sw_if_index=self.pg0.sw_if_index,
6280             flags=flags, is_add=1)
6281         self.vapi.nat44_interface_add_del_feature(
6282             sw_if_index=self.pg1.sw_if_index,
6283             is_add=1)
6284
6285         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
6286         start_sessnum = len(sessions)
6287
6288         self.vapi.nat_set_timeouts(udp=300, tcp_established=7440,
6289                                    tcp_transitory=2, icmp=5)
6290
6291         self.initiate_tcp_session(self.pg0, self.pg1)
6292
6293         # FIN packet in -> out
6294         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6295              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6296              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
6297                  flags="FA", seq=100, ack=300))
6298         self.pg0.add_stream(p)
6299         self.pg_enable_capture(self.pg_interfaces)
6300         self.pg_start()
6301         self.pg1.get_capture(1)
6302
6303         # FIN packet out -> in
6304         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
6305              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
6306              TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
6307                  flags="FA", seq=300, ack=100))
6308         self.pg1.add_stream(p)
6309         self.pg_enable_capture(self.pg_interfaces)
6310         self.pg_start()
6311         self.pg0.get_capture(1)
6312
6313         # ACK packet in -> out
6314         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6315              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6316              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
6317                  flags="A", seq=101, ack=301))
6318         self.pg0.add_stream(p)
6319         self.pg_enable_capture(self.pg_interfaces)
6320         self.pg_start()
6321         self.pg1.get_capture(1)
6322
6323         # ACK packet out -> in
6324         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
6325              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
6326              TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
6327                  flags="A", seq=301, ack=101))
6328         self.pg1.add_stream(p)
6329         self.pg_enable_capture(self.pg_interfaces)
6330         self.pg_start()
6331         self.pg0.get_capture(1)
6332
6333         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
6334         self.assertEqual(len(sessions) - start_sessnum, 1)
6335
6336         stats = self.statistics.get_counter(
6337             '/err/nat44-ed-out2in/drops due to TCP in transitory timeout')
6338         out2in_drops = stats[0]
6339         stats = self.statistics.get_counter(
6340             '/err/nat44-ed-in2out/drops due to TCP in transitory timeout')
6341         in2out_drops = stats[0]
6342
6343         # extra FIN packet out -> in - this should be dropped
6344         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
6345              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
6346              TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
6347                  flags="FA", seq=300, ack=101))
6348
6349         self.pg1.add_stream(p)
6350         self.pg_enable_capture(self.pg_interfaces)
6351         self.pg_start()
6352         self.pg0.assert_nothing_captured()
6353
6354         # extra ACK packet in -> out - this should be dropped
6355         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6356              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6357              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
6358                  flags="A", seq=101, ack=301))
6359         self.pg0.add_stream(p)
6360         self.pg_enable_capture(self.pg_interfaces)
6361         self.pg_start()
6362         self.pg1.assert_nothing_captured()
6363
6364         stats = self.statistics.get_counter(
6365             '/err/nat44-ed-out2in/drops due to TCP in transitory timeout')
6366         self.assertEqual(stats[0] - out2in_drops, 1)
6367         stats = self.statistics.get_counter(
6368             '/err/nat44-ed-in2out/drops due to TCP in transitory timeout')
6369         self.assertEqual(stats[0] - in2out_drops, 1)
6370
6371         self.sleep(3)
6372         # extra ACK packet in -> out - this will cause session to be wiped
6373         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6374              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6375              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
6376                  flags="A", seq=101, ack=301))
6377         self.pg0.add_stream(p)
6378         self.pg_enable_capture(self.pg_interfaces)
6379         self.pg_start()
6380         self.pg1.assert_nothing_captured()
6381         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
6382         self.assertEqual(len(sessions) - start_sessnum, 0)
6383
6384     def test_one_armed_nat44_static(self):
6385         """ One armed NAT44 and 1:1 NAPT asymmetrical rule """
6386         remote_host = self.pg4.remote_hosts[0]
6387         local_host = self.pg4.remote_hosts[1]
6388         external_port = 80
6389         local_port = 8080
6390         eh_port_in = 0
6391
6392         self.vapi.nat44_forwarding_enable_disable(enable=1)
6393         self.nat44_add_address(self.nat_addr, twice_nat=1)
6394         flags = (self.config_flags.NAT_IS_OUT2IN_ONLY |
6395                  self.config_flags.NAT_IS_TWICE_NAT)
6396         self.nat44_add_static_mapping(local_host.ip4, self.nat_addr,
6397                                       local_port, external_port,
6398                                       proto=IP_PROTOS.tcp, flags=flags)
6399         flags = self.config_flags.NAT_IS_INSIDE
6400         self.vapi.nat44_interface_add_del_feature(
6401             sw_if_index=self.pg4.sw_if_index,
6402             is_add=1)
6403         self.vapi.nat44_interface_add_del_feature(
6404             sw_if_index=self.pg4.sw_if_index,
6405             flags=flags, is_add=1)
6406
6407         # from client to service
6408         p = (Ether(src=self.pg4.remote_mac, dst=self.pg4.local_mac) /
6409              IP(src=remote_host.ip4, dst=self.nat_addr) /
6410              TCP(sport=12345, dport=external_port))
6411         self.pg4.add_stream(p)
6412         self.pg_enable_capture(self.pg_interfaces)
6413         self.pg_start()
6414         capture = self.pg4.get_capture(1)
6415         p = capture[0]
6416         try:
6417             ip = p[IP]
6418             tcp = p[TCP]
6419             self.assertEqual(ip.dst, local_host.ip4)
6420             self.assertEqual(ip.src, self.nat_addr)
6421             self.assertEqual(tcp.dport, local_port)
6422             self.assertNotEqual(tcp.sport, 12345)
6423             eh_port_in = tcp.sport
6424             self.assert_packet_checksums_valid(p)
6425         except:
6426             self.logger.error(ppp("Unexpected or invalid packet:", p))
6427             raise
6428
6429         # from service back to client
6430         p = (Ether(src=self.pg4.remote_mac, dst=self.pg4.local_mac) /
6431              IP(src=local_host.ip4, dst=self.nat_addr) /
6432              TCP(sport=local_port, dport=eh_port_in))
6433         self.pg4.add_stream(p)
6434         self.pg_enable_capture(self.pg_interfaces)
6435         self.pg_start()
6436         capture = self.pg4.get_capture(1)
6437         p = capture[0]
6438         try:
6439             ip = p[IP]
6440             tcp = p[TCP]
6441             self.assertEqual(ip.src, self.nat_addr)
6442             self.assertEqual(ip.dst, remote_host.ip4)
6443             self.assertEqual(tcp.sport, external_port)
6444             self.assertEqual(tcp.dport, 12345)
6445             self.assert_packet_checksums_valid(p)
6446         except:
6447             self.logger.error(ppp("Unexpected or invalid packet:", p))
6448             raise
6449
6450     def test_static_with_port_out2(self):
6451         """ 1:1 NAPT asymmetrical rule """
6452
6453         external_port = 80
6454         local_port = 8080
6455
6456         self.vapi.nat44_forwarding_enable_disable(enable=1)
6457         flags = self.config_flags.NAT_IS_OUT2IN_ONLY
6458         self.nat44_add_static_mapping(self.pg0.remote_ip4, self.nat_addr,
6459                                       local_port, external_port,
6460                                       proto=IP_PROTOS.tcp, flags=flags)
6461         flags = self.config_flags.NAT_IS_INSIDE
6462         self.vapi.nat44_interface_add_del_feature(
6463             sw_if_index=self.pg0.sw_if_index,
6464             flags=flags, is_add=1)
6465         self.vapi.nat44_interface_add_del_feature(
6466             sw_if_index=self.pg1.sw_if_index,
6467             is_add=1)
6468
6469         # from client to service
6470         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
6471              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
6472              TCP(sport=12345, dport=external_port))
6473         self.pg1.add_stream(p)
6474         self.pg_enable_capture(self.pg_interfaces)
6475         self.pg_start()
6476         capture = self.pg0.get_capture(1)
6477         p = capture[0]
6478         try:
6479             ip = p[IP]
6480             tcp = p[TCP]
6481             self.assertEqual(ip.dst, self.pg0.remote_ip4)
6482             self.assertEqual(tcp.dport, local_port)
6483             self.assert_packet_checksums_valid(p)
6484         except:
6485             self.logger.error(ppp("Unexpected or invalid packet:", p))
6486             raise
6487
6488         # ICMP error
6489         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
6490              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6491              ICMP(type=11) / capture[0][IP])
6492         self.pg0.add_stream(p)
6493         self.pg_enable_capture(self.pg_interfaces)
6494         self.pg_start()
6495         capture = self.pg1.get_capture(1)
6496         p = capture[0]
6497         try:
6498             self.assertEqual(p[IP].src, self.nat_addr)
6499             inner = p[IPerror]
6500             self.assertEqual(inner.dst, self.nat_addr)
6501             self.assertEqual(inner[TCPerror].dport, external_port)
6502         except:
6503             self.logger.error(ppp("Unexpected or invalid packet:", p))
6504             raise
6505
6506         # from service back to client
6507         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6508              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6509              TCP(sport=local_port, dport=12345))
6510         self.pg0.add_stream(p)
6511         self.pg_enable_capture(self.pg_interfaces)
6512         self.pg_start()
6513         capture = self.pg1.get_capture(1)
6514         p = capture[0]
6515         try:
6516             ip = p[IP]
6517             tcp = p[TCP]
6518             self.assertEqual(ip.src, self.nat_addr)
6519             self.assertEqual(tcp.sport, external_port)
6520             self.assert_packet_checksums_valid(p)
6521         except:
6522             self.logger.error(ppp("Unexpected or invalid packet:", p))
6523             raise
6524
6525         # ICMP error
6526         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
6527              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
6528              ICMP(type=11) / capture[0][IP])
6529         self.pg1.add_stream(p)
6530         self.pg_enable_capture(self.pg_interfaces)
6531         self.pg_start()
6532         capture = self.pg0.get_capture(1)
6533         p = capture[0]
6534         try:
6535             self.assertEqual(p[IP].dst, self.pg0.remote_ip4)
6536             inner = p[IPerror]
6537             self.assertEqual(inner.src, self.pg0.remote_ip4)
6538             self.assertEqual(inner[TCPerror].sport, local_port)
6539         except:
6540             self.logger.error(ppp("Unexpected or invalid packet:", p))
6541             raise
6542
6543         # from client to server (no translation)
6544         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
6545              IP(src=self.pg1.remote_ip4, dst=self.pg0.remote_ip4) /
6546              TCP(sport=12346, dport=local_port))
6547         self.pg1.add_stream(p)
6548         self.pg_enable_capture(self.pg_interfaces)
6549         self.pg_start()
6550         capture = self.pg0.get_capture(1)
6551         p = capture[0]
6552         try:
6553             ip = p[IP]
6554             tcp = p[TCP]
6555             self.assertEqual(ip.dst, self.pg0.remote_ip4)
6556             self.assertEqual(tcp.dport, local_port)
6557             self.assert_packet_checksums_valid(p)
6558         except:
6559             self.logger.error(ppp("Unexpected or invalid packet:", p))
6560             raise
6561
6562         # from service back to client (no translation)
6563         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6564              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6565              TCP(sport=local_port, dport=12346))
6566         self.pg0.add_stream(p)
6567         self.pg_enable_capture(self.pg_interfaces)
6568         self.pg_start()
6569         capture = self.pg1.get_capture(1)
6570         p = capture[0]
6571         try:
6572             ip = p[IP]
6573             tcp = p[TCP]
6574             self.assertEqual(ip.src, self.pg0.remote_ip4)
6575             self.assertEqual(tcp.sport, local_port)
6576             self.assert_packet_checksums_valid(p)
6577         except:
6578             self.logger.error(ppp("Unexpected or invalid packet:", p))
6579             raise
6580
6581     def test_output_feature(self):
6582         """ NAT44 interface output feature (in2out postrouting) """
6583         self.vapi.nat44_forwarding_enable_disable(enable=1)
6584         self.nat44_add_address(self.nat_addr)
6585         self.vapi.nat44_interface_add_del_feature(
6586             sw_if_index=self.pg0.sw_if_index,
6587             is_add=1)
6588         self.vapi.nat44_interface_add_del_output_feature(
6589             is_add=1,
6590             sw_if_index=self.pg1.sw_if_index)
6591
6592         # in2out
6593         pkts = self.create_stream_in(self.pg0, self.pg1)
6594         self.pg0.add_stream(pkts)
6595         self.pg_enable_capture(self.pg_interfaces)
6596         self.pg_start()
6597         capture = self.pg1.get_capture(len(pkts))
6598         self.verify_capture_out(capture)
6599
6600         # out2in
6601         pkts = self.create_stream_out(self.pg1)
6602         self.pg1.add_stream(pkts)
6603         self.pg_enable_capture(self.pg_interfaces)
6604         self.pg_start()
6605         capture = self.pg0.get_capture(len(pkts))
6606         self.verify_capture_in(capture, self.pg0)
6607
6608     def test_output_feature_stateful_acl(self):
6609         """ NAT44 endpoint-dependent output feature works with stateful ACL """
6610         self.nat44_add_address(self.nat_addr)
6611         self.vapi.nat44_interface_add_del_output_feature(
6612             sw_if_index=self.pg0.sw_if_index,
6613             flags=self.config_flags.NAT_IS_INSIDE,
6614             is_add=1)
6615         self.vapi.nat44_interface_add_del_output_feature(
6616             sw_if_index=self.pg1.sw_if_index,
6617             flags=self.config_flags.NAT_IS_OUTSIDE,
6618             is_add=1)
6619
6620         # First ensure that the NAT is working sans ACL
6621
6622         # send packets out2in, no sessions yet so packets should drop
6623         pkts_out2in = self.create_stream_out(self.pg1)
6624         self.send_and_assert_no_replies(self.pg1, pkts_out2in)
6625
6626         # send packets into inside intf, ensure received via outside intf
6627         pkts_in2out = self.create_stream_in(self.pg0, self.pg1)
6628         capture = self.send_and_expect(self.pg0, pkts_in2out, self.pg1,
6629                                        len(pkts_in2out))
6630         self.verify_capture_out(capture)
6631
6632         # send out2in again, with sessions created it should work now
6633         pkts_out2in = self.create_stream_out(self.pg1)
6634         capture = self.send_and_expect(self.pg1, pkts_out2in, self.pg0,
6635                                        len(pkts_out2in))
6636         self.verify_capture_in(capture, self.pg0)
6637
6638         # Create an ACL blocking everything
6639         out2in_deny_rule = AclRule(is_permit=0)
6640         out2in_acl = VppAcl(self, rules=[out2in_deny_rule])
6641         out2in_acl.add_vpp_config()
6642
6643         # create an ACL to permit/reflect everything
6644         in2out_reflect_rule = AclRule(is_permit=2)
6645         in2out_acl = VppAcl(self, rules=[in2out_reflect_rule])
6646         in2out_acl.add_vpp_config()
6647
6648         # apply as input acl on interface and confirm it blocks everything
6649         acl_if = VppAclInterface(self, sw_if_index=self.pg1.sw_if_index,
6650                                  n_input=1, acls=[out2in_acl])
6651         acl_if.add_vpp_config()
6652         self.send_and_assert_no_replies(self.pg1, pkts_out2in)
6653
6654         # apply output acl
6655         acl_if.acls = [out2in_acl, in2out_acl]
6656         acl_if.add_vpp_config()
6657         # send in2out to generate ACL state (NAT state was created earlier)
6658         capture = self.send_and_expect(self.pg0, pkts_in2out, self.pg1,
6659                                        len(pkts_in2out))
6660         self.verify_capture_out(capture)
6661
6662         # send out2in again. ACL state exists so it should work now.
6663         # TCP packets with the syn flag set also need the ack flag
6664         for p in pkts_out2in:
6665             if p.haslayer(TCP) and p[TCP].flags & 0x02:
6666                 p[TCP].flags |= 0x10
6667         capture = self.send_and_expect(self.pg1, pkts_out2in, self.pg0,
6668                                        len(pkts_out2in))
6669         self.verify_capture_in(capture, self.pg0)
6670         self.logger.info(self.vapi.cli("show trace"))
6671
6672     def test_multiple_vrf(self):
6673         """ Multiple VRF setup """
6674         external_addr = '1.2.3.4'
6675         external_port = 80
6676         local_port = 8080
6677         port = 0
6678
6679         self.vapi.nat44_forwarding_enable_disable(enable=1)
6680         self.nat44_add_address(self.nat_addr)
6681         flags = self.config_flags.NAT_IS_INSIDE
6682         self.vapi.nat44_interface_add_del_feature(
6683             sw_if_index=self.pg0.sw_if_index,
6684             is_add=1)
6685         self.vapi.nat44_interface_add_del_feature(
6686             sw_if_index=self.pg0.sw_if_index,
6687             flags=flags, is_add=1)
6688         self.vapi.nat44_interface_add_del_output_feature(
6689             is_add=1,
6690             sw_if_index=self.pg1.sw_if_index)
6691         self.vapi.nat44_interface_add_del_feature(
6692             sw_if_index=self.pg5.sw_if_index,
6693             is_add=1)
6694         self.vapi.nat44_interface_add_del_feature(
6695             sw_if_index=self.pg5.sw_if_index,
6696             flags=flags, is_add=1)
6697         self.vapi.nat44_interface_add_del_feature(
6698             sw_if_index=self.pg6.sw_if_index,
6699             is_add=1)
6700         flags = self.config_flags.NAT_IS_OUT2IN_ONLY
6701         self.nat44_add_static_mapping(self.pg5.remote_ip4, external_addr,
6702                                       local_port, external_port, vrf_id=1,
6703                                       proto=IP_PROTOS.tcp, flags=flags)
6704         self.nat44_add_static_mapping(
6705             self.pg0.remote_ip4,
6706             external_sw_if_index=self.pg0.sw_if_index,
6707             local_port=local_port,
6708             vrf_id=0,
6709             external_port=external_port,
6710             proto=IP_PROTOS.tcp,
6711             flags=flags
6712         )
6713
6714         # from client to service (both VRF1)
6715         p = (Ether(src=self.pg6.remote_mac, dst=self.pg6.local_mac) /
6716              IP(src=self.pg6.remote_ip4, dst=external_addr) /
6717              TCP(sport=12345, dport=external_port))
6718         self.pg6.add_stream(p)
6719         self.pg_enable_capture(self.pg_interfaces)
6720         self.pg_start()
6721         capture = self.pg5.get_capture(1)
6722         p = capture[0]
6723         try:
6724             ip = p[IP]
6725             tcp = p[TCP]
6726             self.assertEqual(ip.dst, self.pg5.remote_ip4)
6727             self.assertEqual(tcp.dport, local_port)
6728             self.assert_packet_checksums_valid(p)
6729         except:
6730             self.logger.error(ppp("Unexpected or invalid packet:", p))
6731             raise
6732
6733         # from service back to client (both VRF1)
6734         p = (Ether(src=self.pg5.remote_mac, dst=self.pg5.local_mac) /
6735              IP(src=self.pg5.remote_ip4, dst=self.pg6.remote_ip4) /
6736              TCP(sport=local_port, dport=12345))
6737         self.pg5.add_stream(p)
6738         self.pg_enable_capture(self.pg_interfaces)
6739         self.pg_start()
6740         capture = self.pg6.get_capture(1)
6741         p = capture[0]
6742         try:
6743             ip = p[IP]
6744             tcp = p[TCP]
6745             self.assertEqual(ip.src, external_addr)
6746             self.assertEqual(tcp.sport, external_port)
6747             self.assert_packet_checksums_valid(p)
6748         except:
6749             self.logger.error(ppp("Unexpected or invalid packet:", p))
6750             raise
6751
6752         # dynamic NAT from VRF1 to VRF0 (output-feature)
6753         p = (Ether(src=self.pg5.remote_mac, dst=self.pg5.local_mac) /
6754              IP(src=self.pg5.remote_ip4, dst=self.pg1.remote_ip4) /
6755              TCP(sport=2345, dport=22))
6756         self.pg5.add_stream(p)
6757         self.pg_enable_capture(self.pg_interfaces)
6758         self.pg_start()
6759         capture = self.pg1.get_capture(1)
6760         p = capture[0]
6761         try:
6762             ip = p[IP]
6763             tcp = p[TCP]
6764             self.assertEqual(ip.src, self.nat_addr)
6765             self.assertNotEqual(tcp.sport, 2345)
6766             self.assert_packet_checksums_valid(p)
6767             port = tcp.sport
6768         except:
6769             self.logger.error(ppp("Unexpected or invalid packet:", p))
6770             raise
6771
6772         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
6773              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
6774              TCP(sport=22, dport=port))
6775         self.pg1.add_stream(p)
6776         self.pg_enable_capture(self.pg_interfaces)
6777         self.pg_start()
6778         capture = self.pg5.get_capture(1)
6779         p = capture[0]
6780         try:
6781             ip = p[IP]
6782             tcp = p[TCP]
6783             self.assertEqual(ip.dst, self.pg5.remote_ip4)
6784             self.assertEqual(tcp.dport, 2345)
6785             self.assert_packet_checksums_valid(p)
6786         except:
6787             self.logger.error(ppp("Unexpected or invalid packet:", p))
6788             raise
6789
6790         # from client VRF1 to service VRF0
6791         p = (Ether(src=self.pg6.remote_mac, dst=self.pg6.local_mac) /
6792              IP(src=self.pg6.remote_ip4, dst=self.pg0.local_ip4) /
6793              TCP(sport=12346, dport=external_port))
6794         self.pg6.add_stream(p)
6795         self.pg_enable_capture(self.pg_interfaces)
6796         self.pg_start()
6797         capture = self.pg0.get_capture(1)
6798         p = capture[0]
6799         try:
6800             ip = p[IP]
6801             tcp = p[TCP]
6802             self.assertEqual(ip.dst, self.pg0.remote_ip4)
6803             self.assertEqual(tcp.dport, local_port)
6804             self.assert_packet_checksums_valid(p)
6805         except:
6806             self.logger.error(ppp("Unexpected or invalid packet:", p))
6807             raise
6808
6809         # from service VRF0 back to client VRF1
6810         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6811              IP(src=self.pg0.remote_ip4, dst=self.pg6.remote_ip4) /
6812              TCP(sport=local_port, dport=12346))
6813         self.pg0.add_stream(p)
6814         self.pg_enable_capture(self.pg_interfaces)
6815         self.pg_start()
6816         capture = self.pg6.get_capture(1)
6817         p = capture[0]
6818         try:
6819             ip = p[IP]
6820             tcp = p[TCP]
6821             self.assertEqual(ip.src, self.pg0.local_ip4)
6822             self.assertEqual(tcp.sport, external_port)
6823             self.assert_packet_checksums_valid(p)
6824         except:
6825             self.logger.error(ppp("Unexpected or invalid packet:", p))
6826             raise
6827
6828         # from client VRF0 to service VRF1
6829         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6830              IP(src=self.pg0.remote_ip4, dst=external_addr) /
6831              TCP(sport=12347, dport=external_port))
6832         self.pg0.add_stream(p)
6833         self.pg_enable_capture(self.pg_interfaces)
6834         self.pg_start()
6835         capture = self.pg5.get_capture(1)
6836         p = capture[0]
6837         try:
6838             ip = p[IP]
6839             tcp = p[TCP]
6840             self.assertEqual(ip.dst, self.pg5.remote_ip4)
6841             self.assertEqual(tcp.dport, local_port)
6842             self.assert_packet_checksums_valid(p)
6843         except:
6844             self.logger.error(ppp("Unexpected or invalid packet:", p))
6845             raise
6846
6847         # from service VRF1 back to client VRF0
6848         p = (Ether(src=self.pg5.remote_mac, dst=self.pg5.local_mac) /
6849              IP(src=self.pg5.remote_ip4, dst=self.pg0.remote_ip4) /
6850              TCP(sport=local_port, dport=12347))
6851         self.pg5.add_stream(p)
6852         self.pg_enable_capture(self.pg_interfaces)
6853         self.pg_start()
6854         capture = self.pg0.get_capture(1)
6855         p = capture[0]
6856         try:
6857             ip = p[IP]
6858             tcp = p[TCP]
6859             self.assertEqual(ip.src, external_addr)
6860             self.assertEqual(tcp.sport, external_port)
6861             self.assert_packet_checksums_valid(p)
6862         except:
6863             self.logger.error(ppp("Unexpected or invalid packet:", p))
6864             raise
6865
6866         # from client to server (both VRF1, no translation)
6867         p = (Ether(src=self.pg6.remote_mac, dst=self.pg6.local_mac) /
6868              IP(src=self.pg6.remote_ip4, dst=self.pg5.remote_ip4) /
6869              TCP(sport=12348, dport=local_port))
6870         self.pg6.add_stream(p)
6871         self.pg_enable_capture(self.pg_interfaces)
6872         self.pg_start()
6873         capture = self.pg5.get_capture(1)
6874         p = capture[0]
6875         try:
6876             ip = p[IP]
6877             tcp = p[TCP]
6878             self.assertEqual(ip.dst, self.pg5.remote_ip4)
6879             self.assertEqual(tcp.dport, local_port)
6880             self.assert_packet_checksums_valid(p)
6881         except:
6882             self.logger.error(ppp("Unexpected or invalid packet:", p))
6883             raise
6884
6885         # from server back to client (both VRF1, no translation)
6886         p = (Ether(src=self.pg5.remote_mac, dst=self.pg5.local_mac) /
6887              IP(src=self.pg5.remote_ip4, dst=self.pg6.remote_ip4) /
6888              TCP(sport=local_port, dport=12348))
6889         self.pg5.add_stream(p)
6890         self.pg_enable_capture(self.pg_interfaces)
6891         self.pg_start()
6892         capture = self.pg6.get_capture(1)
6893         p = capture[0]
6894         try:
6895             ip = p[IP]
6896             tcp = p[TCP]
6897             self.assertEqual(ip.src, self.pg5.remote_ip4)
6898             self.assertEqual(tcp.sport, local_port)
6899             self.assert_packet_checksums_valid(p)
6900         except:
6901             self.logger.error(ppp("Unexpected or invalid packet:", p))
6902             raise
6903
6904         # from client VRF1 to server VRF0 (no translation)
6905         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6906              IP(src=self.pg0.remote_ip4, dst=self.pg6.remote_ip4) /
6907              TCP(sport=local_port, dport=12349))
6908         self.pg0.add_stream(p)
6909         self.pg_enable_capture(self.pg_interfaces)
6910         self.pg_start()
6911         capture = self.pg6.get_capture(1)
6912         p = capture[0]
6913         try:
6914             ip = p[IP]
6915             tcp = p[TCP]
6916             self.assertEqual(ip.src, self.pg0.remote_ip4)
6917             self.assertEqual(tcp.sport, local_port)
6918             self.assert_packet_checksums_valid(p)
6919         except:
6920             self.logger.error(ppp("Unexpected or invalid packet:", p))
6921             raise
6922
6923         # from server VRF0 back to client VRF1 (no translation)
6924         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6925              IP(src=self.pg0.remote_ip4, dst=self.pg6.remote_ip4) /
6926              TCP(sport=local_port, dport=12349))
6927         self.pg0.add_stream(p)
6928         self.pg_enable_capture(self.pg_interfaces)
6929         self.pg_start()
6930         capture = self.pg6.get_capture(1)
6931         p = capture[0]
6932         try:
6933             ip = p[IP]
6934             tcp = p[TCP]
6935             self.assertEqual(ip.src, self.pg0.remote_ip4)
6936             self.assertEqual(tcp.sport, local_port)
6937             self.assert_packet_checksums_valid(p)
6938         except:
6939             self.logger.error(ppp("Unexpected or invalid packet:", p))
6940             raise
6941
6942         # from client VRF0 to server VRF1 (no translation)
6943         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6944              IP(src=self.pg0.remote_ip4, dst=self.pg5.remote_ip4) /
6945              TCP(sport=12344, dport=local_port))
6946         self.pg0.add_stream(p)
6947         self.pg_enable_capture(self.pg_interfaces)
6948         self.pg_start()
6949         capture = self.pg5.get_capture(1)
6950         p = capture[0]
6951         try:
6952             ip = p[IP]
6953             tcp = p[TCP]
6954             self.assertEqual(ip.dst, self.pg5.remote_ip4)
6955             self.assertEqual(tcp.dport, local_port)
6956             self.assert_packet_checksums_valid(p)
6957         except:
6958             self.logger.error(ppp("Unexpected or invalid packet:", p))
6959             raise
6960
6961         # from server VRF1 back to client VRF0 (no translation)
6962         p = (Ether(src=self.pg5.remote_mac, dst=self.pg5.local_mac) /
6963              IP(src=self.pg5.remote_ip4, dst=self.pg0.remote_ip4) /
6964              TCP(sport=local_port, dport=12344))
6965         self.pg5.add_stream(p)
6966         self.pg_enable_capture(self.pg_interfaces)
6967         self.pg_start()
6968         capture = self.pg0.get_capture(1)
6969         p = capture[0]
6970         try:
6971             ip = p[IP]
6972             tcp = p[TCP]
6973             self.assertEqual(ip.src, self.pg5.remote_ip4)
6974             self.assertEqual(tcp.sport, local_port)
6975             self.assert_packet_checksums_valid(p)
6976         except:
6977             self.logger.error(ppp("Unexpected or invalid packet:", p))
6978             raise
6979
6980     @unittest.skipUnless(running_extended_tests, "part of extended tests")
6981     def test_session_timeout(self):
6982         """ NAT44 session 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=240, icmp=5)
6993
6994         max_sessions = 1000
6995         pkts = []
6996         for i in range(0, max_sessions):
6997             src = "10.10.%u.%u" % ((i & 0xFF00) >> 8, i & 0xFF)
6998             p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
6999                  IP(src=src, dst=self.pg1.remote_ip4) /
7000                  ICMP(id=1025, type='echo-request'))
7001             pkts.append(p)
7002         self.pg0.add_stream(pkts)
7003         self.pg_enable_capture(self.pg_interfaces)
7004         self.pg_start()
7005         self.pg1.get_capture(max_sessions)
7006
7007         sleep(10)
7008
7009         pkts = []
7010         for i in range(0, max_sessions):
7011             src = "10.11.%u.%u" % ((i & 0xFF00) >> 8, i & 0xFF)
7012             p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
7013                  IP(src=src, dst=self.pg1.remote_ip4) /
7014                  ICMP(id=1026, type='echo-request'))
7015             pkts.append(p)
7016         self.pg0.add_stream(pkts)
7017         self.pg_enable_capture(self.pg_interfaces)
7018         self.pg_start()
7019         self.pg1.get_capture(max_sessions)
7020
7021         nsessions = 0
7022         users = self.vapi.nat44_user_dump()
7023         for user in users:
7024             nsessions = nsessions + user.nsessions
7025         self.assertLess(nsessions, 2 * max_sessions)
7026
7027     @unittest.skipUnless(running_extended_tests, "part of extended tests")
7028     def test_session_rst_timeout(self):
7029         """ NAT44 session RST timeouts """
7030         self.nat44_add_address(self.nat_addr)
7031         flags = self.config_flags.NAT_IS_INSIDE
7032         self.vapi.nat44_interface_add_del_feature(
7033             sw_if_index=self.pg0.sw_if_index,
7034             flags=flags, is_add=1)
7035         self.vapi.nat44_interface_add_del_feature(
7036             sw_if_index=self.pg1.sw_if_index,
7037             is_add=1)
7038         self.vapi.nat_set_timeouts(udp=300, tcp_established=7440,
7039                                    tcp_transitory=5, icmp=60)
7040
7041         self.initiate_tcp_session(self.pg0, self.pg1)
7042         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
7043              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
7044              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
7045                  flags="R"))
7046         self.pg0.add_stream(p)
7047         self.pg_enable_capture(self.pg_interfaces)
7048         self.pg_start()
7049         self.pg1.get_capture(1)
7050
7051         sleep(6)
7052
7053         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
7054              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
7055              TCP(sport=self.tcp_port_in + 1, dport=self.tcp_external_port + 1,
7056                  flags="S"))
7057         self.pg0.add_stream(p)
7058         self.pg_enable_capture(self.pg_interfaces)
7059         self.pg_start()
7060         self.pg1.get_capture(1)
7061
7062     def test_syslog_sess(self):
7063         """ Test syslog session creation and deletion """
7064         self.vapi.syslog_set_filter(
7065             self.SYSLOG_SEVERITY.SYSLOG_API_SEVERITY_INFO)
7066         self.vapi.syslog_set_sender(self.pg2.local_ip4, self.pg2.remote_ip4)
7067         self.nat44_add_address(self.nat_addr)
7068         flags = self.config_flags.NAT_IS_INSIDE
7069         self.vapi.nat44_interface_add_del_feature(
7070             sw_if_index=self.pg0.sw_if_index,
7071             flags=flags, is_add=1)
7072         self.vapi.nat44_interface_add_del_feature(
7073             sw_if_index=self.pg1.sw_if_index,
7074             is_add=1)
7075
7076         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
7077              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
7078              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port))
7079         self.pg0.add_stream(p)
7080         self.pg_enable_capture(self.pg_interfaces)
7081         self.pg_start()
7082         capture = self.pg1.get_capture(1)
7083         self.tcp_port_out = capture[0][TCP].sport
7084         capture = self.pg2.get_capture(1)
7085         self.verify_syslog_sess(capture[0][Raw].load)
7086
7087         self.pg_enable_capture(self.pg_interfaces)
7088         self.pg_start()
7089         self.nat44_add_address(self.nat_addr, is_add=0)
7090         capture = self.pg2.get_capture(1)
7091         self.verify_syslog_sess(capture[0][Raw].load, False)
7092
7093     def test_ed_users_dump(self):
7094         """ API test - nat44_user_dump """
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,
7098             flags=flags, is_add=1)
7099         self.vapi.nat44_interface_add_del_feature(
7100             sw_if_index=self.pg1.sw_if_index,
7101             is_add=1)
7102         self.vapi.nat44_forwarding_enable_disable(enable=1)
7103
7104         real_ip = self.pg0.remote_ip4
7105         alias_ip = self.nat_addr
7106         flags = self.config_flags.NAT_IS_ADDR_ONLY
7107         self.vapi.nat44_add_del_static_mapping(is_add=1,
7108                                                local_ip_address=real_ip,
7109                                                external_ip_address=alias_ip,
7110                                                external_sw_if_index=0xFFFFFFFF,
7111                                                flags=flags)
7112
7113         users = self.vapi.nat44_user_dump()
7114         self.assertEqual(len(users), 0)
7115         try:
7116             # in2out - static mapping match
7117
7118             pkts = self.create_stream_out(self.pg1)
7119             self.pg1.add_stream(pkts)
7120             self.pg_enable_capture(self.pg_interfaces)
7121             self.pg_start()
7122             capture = self.pg0.get_capture(len(pkts))
7123             self.verify_capture_in(capture, self.pg0)
7124
7125             pkts = self.create_stream_in(self.pg0, self.pg1)
7126             self.pg0.add_stream(pkts)
7127             self.pg_enable_capture(self.pg_interfaces)
7128             self.pg_start()
7129             capture = self.pg1.get_capture(len(pkts))
7130             self.verify_capture_out(capture, same_port=True)
7131
7132             users = self.vapi.nat44_user_dump()
7133             self.assertEqual(len(users), 1)
7134             static_user = users[0]
7135             self.assertEqual(static_user.nstaticsessions, 3)
7136             self.assertEqual(static_user.nsessions, 0)
7137
7138             # in2out - no static mapping match
7139
7140             host0 = self.pg0.remote_hosts[0]
7141             self.pg0.remote_hosts[0] = self.pg0.remote_hosts[1]
7142             try:
7143                 pkts = self.create_stream_out(self.pg1,
7144                                               dst_ip=self.pg0.remote_ip4,
7145                                               use_inside_ports=True)
7146                 self.pg1.add_stream(pkts)
7147                 self.pg_enable_capture(self.pg_interfaces)
7148                 self.pg_start()
7149                 capture = self.pg0.get_capture(len(pkts))
7150                 self.verify_capture_in(capture, self.pg0)
7151
7152                 pkts = self.create_stream_in(self.pg0, self.pg1)
7153                 self.pg0.add_stream(pkts)
7154                 self.pg_enable_capture(self.pg_interfaces)
7155                 self.pg_start()
7156                 capture = self.pg1.get_capture(len(pkts))
7157                 self.verify_capture_out(capture, nat_ip=self.pg0.remote_ip4,
7158                                         same_port=True)
7159             finally:
7160                 self.pg0.remote_hosts[0] = host0
7161
7162             users = self.vapi.nat44_user_dump()
7163             self.assertEqual(len(users), 2)
7164             if str(users[0].ip_address) == self.pg0.remote_hosts[0].ip4:
7165                 non_static_user = users[1]
7166                 static_user = users[0]
7167             else:
7168                 non_static_user = users[0]
7169                 static_user = users[1]
7170             self.assertEqual(static_user.nstaticsessions, 3)
7171             self.assertEqual(static_user.nsessions, 0)
7172             self.assertEqual(non_static_user.nstaticsessions, 0)
7173             self.assertEqual(non_static_user.nsessions, 3)
7174
7175             users = self.vapi.nat44_user_dump()
7176             self.assertEqual(len(users), 2)
7177             if str(users[0].ip_address) == self.pg0.remote_hosts[0].ip4:
7178                 non_static_user = users[1]
7179                 static_user = users[0]
7180             else:
7181                 non_static_user = users[0]
7182                 static_user = users[1]
7183             self.assertEqual(static_user.nstaticsessions, 3)
7184             self.assertEqual(static_user.nsessions, 0)
7185             self.assertEqual(non_static_user.nstaticsessions, 0)
7186             self.assertEqual(non_static_user.nsessions, 3)
7187
7188         finally:
7189             self.vapi.nat44_forwarding_enable_disable(enable=0)
7190             flags = self.config_flags.NAT_IS_ADDR_ONLY
7191             self.vapi.nat44_add_del_static_mapping(
7192                 is_add=0,
7193                 local_ip_address=real_ip,
7194                 external_ip_address=alias_ip,
7195                 external_sw_if_index=0xFFFFFFFF,
7196                 flags=flags)
7197
7198     def tearDown(self):
7199         super(TestNAT44EndpointDependent, self).tearDown()
7200         if not self.vpp_dead:
7201             self.clear_nat44()
7202             self.vapi.cli("clear logging")
7203
7204     def show_commands_at_teardown(self):
7205         self.logger.info(self.vapi.cli("show nat44 addresses"))
7206         self.logger.info(self.vapi.cli("show nat44 interfaces"))
7207         self.logger.info(self.vapi.cli("show nat44 static mappings"))
7208         self.logger.info(self.vapi.cli("show nat44 interface address"))
7209         self.logger.info(self.vapi.cli("show nat44 sessions detail"))
7210         self.logger.info(self.vapi.cli("show nat44 hash tables detail"))
7211         self.logger.info(self.vapi.cli("show nat timeouts"))
7212
7213
7214 class TestNAT44EndpointDependent3(MethodHolder):
7215     """ Endpoint-Dependent mapping and filtering extra test cases """
7216
7217     max_translations = 50
7218
7219     @classmethod
7220     def setUpConstants(cls):
7221         super(TestNAT44EndpointDependent3, cls).setUpConstants()
7222         cls.vpp_cmdline.extend([
7223             "nat", "{", "endpoint-dependent",
7224             "max translations per thread %d" % cls.max_translations,
7225             "}"
7226         ])
7227
7228     @classmethod
7229     def setUpClass(cls):
7230         super(TestNAT44EndpointDependent3, cls).setUpClass()
7231         cls.vapi.cli("set log class nat level debug")
7232
7233         cls.nat_addr = '10.0.0.3'
7234
7235         cls.create_pg_interfaces(range(2))
7236
7237         for i in cls.pg_interfaces:
7238             i.admin_up()
7239             i.config_ip4()
7240             i.resolve_arp()
7241
7242     def setUp(self):
7243         super(TestNAT44EndpointDependent3, self).setUp()
7244         self.vapi.nat_set_timeouts(
7245             udp=1, tcp_established=7440, tcp_transitory=30, icmp=1)
7246         self.nat44_add_address(self.nat_addr)
7247         flags = self.config_flags.NAT_IS_INSIDE
7248         self.vapi.nat44_interface_add_del_feature(
7249             sw_if_index=self.pg0.sw_if_index, flags=flags, is_add=1)
7250         self.vapi.nat44_interface_add_del_feature(
7251             sw_if_index=self.pg1.sw_if_index, is_add=1)
7252
7253     @classmethod
7254     def tearDownClass(cls):
7255         super(TestNAT44EndpointDependent3, cls).tearDownClass()
7256
7257     def init_tcp_session(self, in_if, out_if, sport, ext_dport):
7258         # SYN packet in->out
7259         p = (Ether(src=in_if.remote_mac, dst=in_if.local_mac) /
7260              IP(src=in_if.remote_ip4, dst=out_if.remote_ip4) /
7261              TCP(sport=sport, dport=ext_dport, flags="S"))
7262         in_if.add_stream(p)
7263         self.pg_enable_capture(self.pg_interfaces)
7264         self.pg_start()
7265         capture = out_if.get_capture(1)
7266         p = capture[0]
7267         tcp_port_out = p[TCP].sport
7268
7269         # SYN + ACK packet out->in
7270         p = (Ether(src=out_if.remote_mac, dst=out_if.local_mac) /
7271              IP(src=out_if.remote_ip4, dst=self.nat_addr) /
7272              TCP(sport=ext_dport, dport=tcp_port_out, flags="SA"))
7273         out_if.add_stream(p)
7274         self.pg_enable_capture(self.pg_interfaces)
7275         self.pg_start()
7276         in_if.get_capture(1)
7277
7278         # ACK packet in->out
7279         p = (Ether(src=in_if.remote_mac, dst=in_if.local_mac) /
7280              IP(src=in_if.remote_ip4, dst=out_if.remote_ip4) /
7281              TCP(sport=sport, dport=ext_dport, flags="A"))
7282         in_if.add_stream(p)
7283         self.pg_enable_capture(self.pg_interfaces)
7284         self.pg_start()
7285         out_if.get_capture(1)
7286
7287         return tcp_port_out
7288
7289     def test_lru_cleanup(self):
7290         """ LRU cleanup algorithm """
7291         tcp_port_out = self.init_tcp_session(self.pg0, self.pg1, 2000, 80)
7292         pkts = []
7293         for i in range(0, self.max_translations - 1):
7294             p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
7295                  IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4, ttl=64) /
7296                  UDP(sport=7000+i, dport=80))
7297             pkts.append(p)
7298
7299         self.pg0.add_stream(pkts)
7300         self.pg_enable_capture(self.pg_interfaces)
7301         self.pg_start()
7302         self.pg1.get_capture(len(pkts))
7303         self.sleep(1.5, "wait for timeouts")
7304
7305         pkts = []
7306         for i in range(0, self.max_translations - 1):
7307             p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
7308                  IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4, ttl=64) /
7309                  ICMP(id=8000+i, type='echo-request'))
7310             pkts.append(p)
7311
7312         self.pg0.add_stream(pkts)
7313         self.pg_enable_capture(self.pg_interfaces)
7314         self.pg_start()
7315         self.pg1.get_capture(len(pkts))
7316
7317
7318 class TestNAT44Out2InDPO(MethodHolder):
7319     """ NAT44 Test Cases using out2in DPO """
7320
7321     @classmethod
7322     def setUpConstants(cls):
7323         super(TestNAT44Out2InDPO, cls).setUpConstants()
7324         cls.vpp_cmdline.extend(["nat", "{", "out2in dpo", "}"])
7325
7326     @classmethod
7327     def setUpClass(cls):
7328         super(TestNAT44Out2InDPO, cls).setUpClass()
7329         cls.vapi.cli("set log class nat level debug")
7330
7331         cls.tcp_port_in = 6303
7332         cls.tcp_port_out = 6303
7333         cls.udp_port_in = 6304
7334         cls.udp_port_out = 6304
7335         cls.icmp_id_in = 6305
7336         cls.icmp_id_out = 6305
7337         cls.nat_addr = '10.0.0.3'
7338         cls.dst_ip4 = '192.168.70.1'
7339
7340         cls.create_pg_interfaces(range(2))
7341
7342         cls.pg0.admin_up()
7343         cls.pg0.config_ip4()
7344         cls.pg0.resolve_arp()
7345
7346         cls.pg1.admin_up()
7347         cls.pg1.config_ip6()
7348         cls.pg1.resolve_ndp()
7349
7350         r1 = VppIpRoute(cls, "::", 0,
7351                         [VppRoutePath(cls.pg1.remote_ip6,
7352                                       cls.pg1.sw_if_index)],
7353                         register=False)
7354         r1.add_vpp_config()
7355
7356     @classmethod
7357     def tearDownClass(cls):
7358         super(TestNAT44Out2InDPO, cls).tearDownClass()
7359
7360     def configure_xlat(self):
7361         self.dst_ip6_pfx = '1:2:3::'
7362         self.dst_ip6_pfx_n = socket.inet_pton(socket.AF_INET6,
7363                                               self.dst_ip6_pfx)
7364         self.dst_ip6_pfx_len = 96
7365         self.src_ip6_pfx = '4:5:6::'
7366         self.src_ip6_pfx_n = socket.inet_pton(socket.AF_INET6,
7367                                               self.src_ip6_pfx)
7368         self.src_ip6_pfx_len = 96
7369         self.vapi.map_add_domain(self.dst_ip6_pfx_n, self.dst_ip6_pfx_len,
7370                                  self.src_ip6_pfx_n, self.src_ip6_pfx_len,
7371                                  '\x00\x00\x00\x00', 0)
7372
7373     @unittest.skip('Temporary disabled')
7374     def test_464xlat_ce(self):
7375         """ Test 464XLAT CE with NAT44 """
7376
7377         nat_config = self.vapi.nat_show_config()
7378         self.assertEqual(1, nat_config.out2in_dpo)
7379
7380         self.configure_xlat()
7381
7382         flags = self.config_flags.NAT_IS_INSIDE
7383         self.vapi.nat44_interface_add_del_feature(
7384             sw_if_index=self.pg0.sw_if_index,
7385             flags=flags, is_add=1)
7386         self.vapi.nat44_add_del_address_range(first_ip_address=self.nat_addr_n,
7387                                               last_ip_address=self.nat_addr_n,
7388                                               vrf_id=0xFFFFFFFF, is_add=1)
7389
7390         out_src_ip6 = self.compose_ip6(self.dst_ip4, self.dst_ip6_pfx,
7391                                        self.dst_ip6_pfx_len)
7392         out_dst_ip6 = self.compose_ip6(self.nat_addr, self.src_ip6_pfx,
7393                                        self.src_ip6_pfx_len)
7394
7395         try:
7396             pkts = self.create_stream_in(self.pg0, self.pg1, self.dst_ip4)
7397             self.pg0.add_stream(pkts)
7398             self.pg_enable_capture(self.pg_interfaces)
7399             self.pg_start()
7400             capture = self.pg1.get_capture(len(pkts))
7401             self.verify_capture_out_ip6(capture, nat_ip=out_dst_ip6,
7402                                         dst_ip=out_src_ip6)
7403
7404             pkts = self.create_stream_out_ip6(self.pg1, out_src_ip6,
7405                                               out_dst_ip6)
7406             self.pg1.add_stream(pkts)
7407             self.pg_enable_capture(self.pg_interfaces)
7408             self.pg_start()
7409             capture = self.pg0.get_capture(len(pkts))
7410             self.verify_capture_in(capture, self.pg0)
7411         finally:
7412             self.vapi.nat44_interface_add_del_feature(
7413                 sw_if_index=self.pg0.sw_if_index,
7414                 flags=flags)
7415             self.vapi.nat44_add_del_address_range(
7416                 first_ip_address=self.nat_addr_n,
7417                 last_ip_address=self.nat_addr_n,
7418                 vrf_id=0xFFFFFFFF)
7419
7420     @unittest.skip('Temporary disabled')
7421     def test_464xlat_ce_no_nat(self):
7422         """ Test 464XLAT CE without NAT44 """
7423
7424         self.configure_xlat()
7425
7426         out_src_ip6 = self.compose_ip6(self.dst_ip4, self.dst_ip6_pfx,
7427                                        self.dst_ip6_pfx_len)
7428         out_dst_ip6 = self.compose_ip6(self.pg0.remote_ip4, self.src_ip6_pfx,
7429                                        self.src_ip6_pfx_len)
7430
7431         pkts = self.create_stream_in(self.pg0, self.pg1, self.dst_ip4)
7432         self.pg0.add_stream(pkts)
7433         self.pg_enable_capture(self.pg_interfaces)
7434         self.pg_start()
7435         capture = self.pg1.get_capture(len(pkts))
7436         self.verify_capture_out_ip6(capture, dst_ip=out_src_ip6,
7437                                     nat_ip=out_dst_ip6, same_port=True)
7438
7439         pkts = self.create_stream_out_ip6(self.pg1, out_src_ip6, out_dst_ip6)
7440         self.pg1.add_stream(pkts)
7441         self.pg_enable_capture(self.pg_interfaces)
7442         self.pg_start()
7443         capture = self.pg0.get_capture(len(pkts))
7444         self.verify_capture_in(capture, self.pg0)
7445
7446
7447 class TestDeterministicNAT(MethodHolder):
7448     """ Deterministic NAT Test Cases """
7449
7450     @classmethod
7451     def setUpConstants(cls):
7452         super(TestDeterministicNAT, cls).setUpConstants()
7453         cls.vpp_cmdline.extend(["nat", "{", "deterministic", "}"])
7454
7455     @classmethod
7456     def setUpClass(cls):
7457         super(TestDeterministicNAT, cls).setUpClass()
7458         cls.vapi.cli("set log class nat level debug")
7459
7460         cls.tcp_port_in = 6303
7461         cls.tcp_external_port = 6303
7462         cls.udp_port_in = 6304
7463         cls.udp_external_port = 6304
7464         cls.icmp_id_in = 6305
7465         cls.nat_addr = '10.0.0.3'
7466
7467         cls.create_pg_interfaces(range(3))
7468         cls.interfaces = list(cls.pg_interfaces)
7469
7470         for i in cls.interfaces:
7471             i.admin_up()
7472             i.config_ip4()
7473             i.resolve_arp()
7474
7475         cls.pg0.generate_remote_hosts(2)
7476         cls.pg0.configure_ipv4_neighbors()
7477
7478     @classmethod
7479     def tearDownClass(cls):
7480         super(TestDeterministicNAT, cls).tearDownClass()
7481
7482     def create_stream_in(self, in_if, out_if, ttl=64):
7483         """
7484         Create packet stream for inside network
7485
7486         :param in_if: Inside interface
7487         :param out_if: Outside interface
7488         :param ttl: TTL of generated packets
7489         """
7490         pkts = []
7491         # TCP
7492         p = (Ether(dst=in_if.local_mac, src=in_if.remote_mac) /
7493              IP(src=in_if.remote_ip4, dst=out_if.remote_ip4, ttl=ttl) /
7494              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port))
7495         pkts.append(p)
7496
7497         # UDP
7498         p = (Ether(dst=in_if.local_mac, src=in_if.remote_mac) /
7499              IP(src=in_if.remote_ip4, dst=out_if.remote_ip4, ttl=ttl) /
7500              UDP(sport=self.udp_port_in, dport=self.udp_external_port))
7501         pkts.append(p)
7502
7503         # ICMP
7504         p = (Ether(dst=in_if.local_mac, src=in_if.remote_mac) /
7505              IP(src=in_if.remote_ip4, dst=out_if.remote_ip4, ttl=ttl) /
7506              ICMP(id=self.icmp_id_in, type='echo-request'))
7507         pkts.append(p)
7508
7509         return pkts
7510
7511     def create_stream_out(self, out_if, dst_ip=None, ttl=64):
7512         """
7513         Create packet stream for outside network
7514
7515         :param out_if: Outside interface
7516         :param dst_ip: Destination IP address (Default use global NAT address)
7517         :param ttl: TTL of generated packets
7518         """
7519         if dst_ip is None:
7520             dst_ip = self.nat_addr
7521         pkts = []
7522         # TCP
7523         p = (Ether(dst=out_if.local_mac, src=out_if.remote_mac) /
7524              IP(src=out_if.remote_ip4, dst=dst_ip, ttl=ttl) /
7525              TCP(dport=self.tcp_port_out, sport=self.tcp_external_port))
7526         pkts.append(p)
7527
7528         # UDP
7529         p = (Ether(dst=out_if.local_mac, src=out_if.remote_mac) /
7530              IP(src=out_if.remote_ip4, dst=dst_ip, ttl=ttl) /
7531              UDP(dport=self.udp_port_out, sport=self.udp_external_port))
7532         pkts.append(p)
7533
7534         # ICMP
7535         p = (Ether(dst=out_if.local_mac, src=out_if.remote_mac) /
7536              IP(src=out_if.remote_ip4, dst=dst_ip, ttl=ttl) /
7537              ICMP(id=self.icmp_external_id, type='echo-reply'))
7538         pkts.append(p)
7539
7540         return pkts
7541
7542     def verify_capture_out(self, capture, nat_ip=None):
7543         """
7544         Verify captured packets on outside network
7545
7546         :param capture: Captured packets
7547         :param nat_ip: Translated IP address (Default use global NAT address)
7548         :param same_port: Source port number is not translated (Default False)
7549         """
7550         if nat_ip is None:
7551             nat_ip = self.nat_addr
7552         for packet in capture:
7553             try:
7554                 self.assertEqual(packet[IP].src, nat_ip)
7555                 if packet.haslayer(TCP):
7556                     self.tcp_port_out = packet[TCP].sport
7557                 elif packet.haslayer(UDP):
7558                     self.udp_port_out = packet[UDP].sport
7559                 else:
7560                     self.icmp_external_id = packet[ICMP].id
7561             except:
7562                 self.logger.error(ppp("Unexpected or invalid packet "
7563                                       "(outside network):", packet))
7564                 raise
7565
7566     def test_deterministic_mode(self):
7567         """ NAT plugin run deterministic mode """
7568         in_addr = '172.16.255.0'
7569         out_addr = '172.17.255.50'
7570         in_addr_t = '172.16.255.20'
7571         in_plen = 24
7572         out_plen = 32
7573
7574         nat_config = self.vapi.nat_show_config()
7575         self.assertEqual(1, nat_config.deterministic)
7576
7577         self.vapi.nat_det_add_del_map(is_add=1, in_addr=in_addr,
7578                                       in_plen=in_plen, out_addr=out_addr,
7579                                       out_plen=out_plen)
7580
7581         rep1 = self.vapi.nat_det_forward(in_addr_t)
7582         self.assertEqual(str(rep1.out_addr), out_addr)
7583         rep2 = self.vapi.nat_det_reverse(rep1.out_port_hi, out_addr)
7584
7585         self.assertEqual(str(rep2.in_addr), in_addr_t)
7586
7587         deterministic_mappings = self.vapi.nat_det_map_dump()
7588         self.assertEqual(len(deterministic_mappings), 1)
7589         dsm = deterministic_mappings[0]
7590         self.assertEqual(in_addr, str(dsm.in_addr))
7591         self.assertEqual(in_plen, dsm.in_plen)
7592         self.assertEqual(out_addr, str(dsm.out_addr))
7593         self.assertEqual(out_plen, dsm.out_plen)
7594
7595         self.clear_nat_det()
7596         deterministic_mappings = self.vapi.nat_det_map_dump()
7597         self.assertEqual(len(deterministic_mappings), 0)
7598
7599     def test_set_timeouts(self):
7600         """ Set deterministic NAT timeouts """
7601         timeouts_before = self.vapi.nat_get_timeouts()
7602
7603         self.vapi.nat_set_timeouts(
7604             udp=timeouts_before.udp + 10,
7605             tcp_established=timeouts_before.tcp_established + 10,
7606             tcp_transitory=timeouts_before.tcp_transitory + 10,
7607             icmp=timeouts_before.icmp + 10)
7608
7609         timeouts_after = self.vapi.nat_get_timeouts()
7610
7611         self.assertNotEqual(timeouts_before.udp, timeouts_after.udp)
7612         self.assertNotEqual(timeouts_before.icmp, timeouts_after.icmp)
7613         self.assertNotEqual(timeouts_before.tcp_established,
7614                             timeouts_after.tcp_established)
7615         self.assertNotEqual(timeouts_before.tcp_transitory,
7616                             timeouts_after.tcp_transitory)
7617
7618     def test_det_in(self):
7619         """ Deterministic NAT translation test (TCP, UDP, ICMP) """
7620
7621         nat_ip = "10.0.0.10"
7622
7623         self.vapi.nat_det_add_del_map(is_add=1, in_addr=self.pg0.remote_ip4,
7624                                       in_plen=32,
7625                                       out_addr=socket.inet_aton(nat_ip),
7626                                       out_plen=32)
7627
7628         flags = self.config_flags.NAT_IS_INSIDE
7629         self.vapi.nat44_interface_add_del_feature(
7630             sw_if_index=self.pg0.sw_if_index,
7631             flags=flags, is_add=1)
7632         self.vapi.nat44_interface_add_del_feature(
7633             sw_if_index=self.pg1.sw_if_index,
7634             is_add=1)
7635
7636         # in2out
7637         pkts = self.create_stream_in(self.pg0, self.pg1)
7638         self.pg0.add_stream(pkts)
7639         self.pg_enable_capture(self.pg_interfaces)
7640         self.pg_start()
7641         capture = self.pg1.get_capture(len(pkts))
7642         self.verify_capture_out(capture, nat_ip)
7643
7644         # out2in
7645         pkts = self.create_stream_out(self.pg1, nat_ip)
7646         self.pg1.add_stream(pkts)
7647         self.pg_enable_capture(self.pg_interfaces)
7648         self.pg_start()
7649         capture = self.pg0.get_capture(len(pkts))
7650         self.verify_capture_in(capture, self.pg0)
7651
7652         # session dump test
7653         sessions = self.vapi.nat_det_session_dump(self.pg0.remote_ip4)
7654         self.assertEqual(len(sessions), 3)
7655
7656         # TCP session
7657         s = sessions[0]
7658         self.assertEqual(str(s.ext_addr), self.pg1.remote_ip4)
7659         self.assertEqual(s.in_port, self.tcp_port_in)
7660         self.assertEqual(s.out_port, self.tcp_port_out)
7661         self.assertEqual(s.ext_port, self.tcp_external_port)
7662
7663         # UDP session
7664         s = sessions[1]
7665         self.assertEqual(str(s.ext_addr), self.pg1.remote_ip4)
7666         self.assertEqual(s.in_port, self.udp_port_in)
7667         self.assertEqual(s.out_port, self.udp_port_out)
7668         self.assertEqual(s.ext_port, self.udp_external_port)
7669
7670         # ICMP session
7671         s = sessions[2]
7672         self.assertEqual(str(s.ext_addr), self.pg1.remote_ip4)
7673         self.assertEqual(s.in_port, self.icmp_id_in)
7674         self.assertEqual(s.out_port, self.icmp_external_id)
7675
7676     def test_multiple_users(self):
7677         """ Deterministic NAT multiple users """
7678
7679         nat_ip = "10.0.0.10"
7680         port_in = 80
7681         external_port = 6303
7682
7683         host0 = self.pg0.remote_hosts[0]
7684         host1 = self.pg0.remote_hosts[1]
7685
7686         self.vapi.nat_det_add_del_map(is_add=1, in_addr=host0.ip4, in_plen=24,
7687                                       out_addr=socket.inet_aton(nat_ip),
7688                                       out_plen=32)
7689         flags = self.config_flags.NAT_IS_INSIDE
7690         self.vapi.nat44_interface_add_del_feature(
7691             sw_if_index=self.pg0.sw_if_index,
7692             flags=flags, is_add=1)
7693         self.vapi.nat44_interface_add_del_feature(
7694             sw_if_index=self.pg1.sw_if_index,
7695             is_add=1)
7696
7697         # host0 to out
7698         p = (Ether(src=host0.mac, dst=self.pg0.local_mac) /
7699              IP(src=host0.ip4, dst=self.pg1.remote_ip4) /
7700              TCP(sport=port_in, dport=external_port))
7701         self.pg0.add_stream(p)
7702         self.pg_enable_capture(self.pg_interfaces)
7703         self.pg_start()
7704         capture = self.pg1.get_capture(1)
7705         p = capture[0]
7706         try:
7707             ip = p[IP]
7708             tcp = p[TCP]
7709             self.assertEqual(ip.src, nat_ip)
7710             self.assertEqual(ip.dst, self.pg1.remote_ip4)
7711             self.assertEqual(tcp.dport, external_port)
7712             port_out0 = tcp.sport
7713         except:
7714             self.logger.error(ppp("Unexpected or invalid packet:", p))
7715             raise
7716
7717         # host1 to out
7718         p = (Ether(src=host1.mac, dst=self.pg0.local_mac) /
7719              IP(src=host1.ip4, dst=self.pg1.remote_ip4) /
7720              TCP(sport=port_in, dport=external_port))
7721         self.pg0.add_stream(p)
7722         self.pg_enable_capture(self.pg_interfaces)
7723         self.pg_start()
7724         capture = self.pg1.get_capture(1)
7725         p = capture[0]
7726         try:
7727             ip = p[IP]
7728             tcp = p[TCP]
7729             self.assertEqual(ip.src, nat_ip)
7730             self.assertEqual(ip.dst, self.pg1.remote_ip4)
7731             self.assertEqual(tcp.dport, external_port)
7732             port_out1 = tcp.sport
7733         except:
7734             self.logger.error(ppp("Unexpected or invalid packet:", p))
7735             raise
7736
7737         dms = self.vapi.nat_det_map_dump()
7738         self.assertEqual(1, len(dms))
7739         self.assertEqual(2, dms[0].ses_num)
7740
7741         # out to host0
7742         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
7743              IP(src=self.pg1.remote_ip4, dst=nat_ip) /
7744              TCP(sport=external_port, dport=port_out0))
7745         self.pg1.add_stream(p)
7746         self.pg_enable_capture(self.pg_interfaces)
7747         self.pg_start()
7748         capture = self.pg0.get_capture(1)
7749         p = capture[0]
7750         try:
7751             ip = p[IP]
7752             tcp = p[TCP]
7753             self.assertEqual(ip.src, self.pg1.remote_ip4)
7754             self.assertEqual(ip.dst, host0.ip4)
7755             self.assertEqual(tcp.dport, port_in)
7756             self.assertEqual(tcp.sport, external_port)
7757         except:
7758             self.logger.error(ppp("Unexpected or invalid packet:", p))
7759             raise
7760
7761         # out to host1
7762         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
7763              IP(src=self.pg1.remote_ip4, dst=nat_ip) /
7764              TCP(sport=external_port, dport=port_out1))
7765         self.pg1.add_stream(p)
7766         self.pg_enable_capture(self.pg_interfaces)
7767         self.pg_start()
7768         capture = self.pg0.get_capture(1)
7769         p = capture[0]
7770         try:
7771             ip = p[IP]
7772             tcp = p[TCP]
7773             self.assertEqual(ip.src, self.pg1.remote_ip4)
7774             self.assertEqual(ip.dst, host1.ip4)
7775             self.assertEqual(tcp.dport, port_in)
7776             self.assertEqual(tcp.sport, external_port)
7777         except:
7778             self.logger.error(ppp("Unexpected or invalid packet", p))
7779             raise
7780
7781         # session close api test
7782         self.vapi.nat_det_close_session_out(socket.inet_aton(nat_ip),
7783                                             port_out1,
7784                                             self.pg1.remote_ip4,
7785                                             external_port)
7786         dms = self.vapi.nat_det_map_dump()
7787         self.assertEqual(dms[0].ses_num, 1)
7788
7789         self.vapi.nat_det_close_session_in(host0.ip4,
7790                                            port_in,
7791                                            self.pg1.remote_ip4,
7792                                            external_port)
7793         dms = self.vapi.nat_det_map_dump()
7794         self.assertEqual(dms[0].ses_num, 0)
7795
7796     def test_tcp_session_close_detection_in(self):
7797         """ Deterministic NAT TCP session close from inside network """
7798         self.vapi.nat_det_add_del_map(is_add=1, in_addr=self.pg0.remote_ip4,
7799                                       in_plen=32,
7800                                       out_addr=socket.inet_aton(self.nat_addr),
7801                                       out_plen=32)
7802         flags = self.config_flags.NAT_IS_INSIDE
7803         self.vapi.nat44_interface_add_del_feature(
7804             sw_if_index=self.pg0.sw_if_index,
7805             flags=flags, is_add=1)
7806         self.vapi.nat44_interface_add_del_feature(
7807             sw_if_index=self.pg1.sw_if_index,
7808             is_add=1)
7809
7810         self.initiate_tcp_session(self.pg0, self.pg1)
7811
7812         # close the session from inside
7813         try:
7814             # FIN packet in -> out
7815             p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
7816                  IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
7817                  TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
7818                      flags="F"))
7819             self.pg0.add_stream(p)
7820             self.pg_enable_capture(self.pg_interfaces)
7821             self.pg_start()
7822             self.pg1.get_capture(1)
7823
7824             pkts = []
7825
7826             # ACK packet out -> in
7827             p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
7828                  IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
7829                  TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
7830                      flags="A"))
7831             pkts.append(p)
7832
7833             # FIN packet out -> in
7834             p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
7835                  IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
7836                  TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
7837                      flags="F"))
7838             pkts.append(p)
7839
7840             self.pg1.add_stream(pkts)
7841             self.pg_enable_capture(self.pg_interfaces)
7842             self.pg_start()
7843             self.pg0.get_capture(2)
7844
7845             # ACK packet in -> out
7846             p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
7847                  IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
7848                  TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
7849                      flags="A"))
7850             self.pg0.add_stream(p)
7851             self.pg_enable_capture(self.pg_interfaces)
7852             self.pg_start()
7853             self.pg1.get_capture(1)
7854
7855             # Check if deterministic NAT44 closed the session
7856             dms = self.vapi.nat_det_map_dump()
7857             self.assertEqual(0, dms[0].ses_num)
7858         except:
7859             self.logger.error("TCP session termination failed")
7860             raise
7861
7862     def test_tcp_session_close_detection_out(self):
7863         """ Deterministic NAT TCP session close from outside network """
7864         self.vapi.nat_det_add_del_map(is_add=1, in_addr=self.pg0.remote_ip4,
7865                                       in_plen=32,
7866                                       out_addr=socket.inet_aton(self.nat_addr),
7867                                       out_plen=32)
7868         flags = self.config_flags.NAT_IS_INSIDE
7869         self.vapi.nat44_interface_add_del_feature(
7870             sw_if_index=self.pg0.sw_if_index,
7871             flags=flags, is_add=1)
7872         self.vapi.nat44_interface_add_del_feature(
7873             sw_if_index=self.pg1.sw_if_index,
7874             is_add=1)
7875
7876         self.initiate_tcp_session(self.pg0, self.pg1)
7877
7878         # close the session from outside
7879         try:
7880             # FIN packet out -> in
7881             p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
7882                  IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
7883                  TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
7884                      flags="F"))
7885             self.pg1.add_stream(p)
7886             self.pg_enable_capture(self.pg_interfaces)
7887             self.pg_start()
7888             self.pg0.get_capture(1)
7889
7890             pkts = []
7891
7892             # ACK packet in -> out
7893             p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
7894                  IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
7895                  TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
7896                      flags="A"))
7897             pkts.append(p)
7898
7899             # ACK packet in -> out
7900             p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
7901                  IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
7902                  TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
7903                      flags="F"))
7904             pkts.append(p)
7905
7906             self.pg0.add_stream(pkts)
7907             self.pg_enable_capture(self.pg_interfaces)
7908             self.pg_start()
7909             self.pg1.get_capture(2)
7910
7911             # ACK packet out -> in
7912             p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
7913                  IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
7914                  TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
7915                      flags="A"))
7916             self.pg1.add_stream(p)
7917             self.pg_enable_capture(self.pg_interfaces)
7918             self.pg_start()
7919             self.pg0.get_capture(1)
7920
7921             # Check if deterministic NAT44 closed the session
7922             dms = self.vapi.nat_det_map_dump()
7923             self.assertEqual(0, dms[0].ses_num)
7924         except:
7925             self.logger.error("TCP session termination failed")
7926             raise
7927
7928     @unittest.skipUnless(running_extended_tests, "part of extended tests")
7929     def test_session_timeout(self):
7930         """ Deterministic NAT session timeouts """
7931         self.vapi.nat_det_add_del_map(is_add=1, in_addr=self.pg0.remote_ip4,
7932                                       in_plen=32,
7933                                       out_addr=socket.inet_aton(self.nat_addr),
7934                                       out_plen=32)
7935         flags = self.config_flags.NAT_IS_INSIDE
7936         self.vapi.nat44_interface_add_del_feature(
7937             sw_if_index=self.pg0.sw_if_index,
7938             flags=flags, is_add=1)
7939         self.vapi.nat44_interface_add_del_feature(
7940             sw_if_index=self.pg1.sw_if_index,
7941             is_add=1)
7942
7943         self.initiate_tcp_session(self.pg0, self.pg1)
7944         self.vapi.nat_set_timeouts(udp=5, tcp_established=5, tcp_transitory=5,
7945                                    icmp=5)
7946         pkts = self.create_stream_in(self.pg0, self.pg1)
7947         self.pg0.add_stream(pkts)
7948         self.pg_enable_capture(self.pg_interfaces)
7949         self.pg_start()
7950         capture = self.pg1.get_capture(len(pkts))
7951         sleep(15)
7952
7953         dms = self.vapi.nat_det_map_dump()
7954         self.assertEqual(0, dms[0].ses_num)
7955
7956     @unittest.skipUnless(running_extended_tests, "part of extended tests")
7957     def test_session_limit_per_user(self):
7958         """ Deterministic NAT maximum sessions per user limit """
7959         self.vapi.nat_det_add_del_map(is_add=1, in_addr=self.pg0.remote_ip4,
7960                                       in_plen=32,
7961                                       out_addr=socket.inet_aton(self.nat_addr),
7962                                       out_plen=32)
7963         flags = self.config_flags.NAT_IS_INSIDE
7964         self.vapi.nat44_interface_add_del_feature(
7965             sw_if_index=self.pg0.sw_if_index,
7966             flags=flags, is_add=1)
7967         self.vapi.nat44_interface_add_del_feature(
7968             sw_if_index=self.pg1.sw_if_index,
7969             is_add=1)
7970         self.vapi.set_ipfix_exporter(collector_address=self.pg2.remote_ip4,
7971                                      src_address=self.pg2.local_ip4,
7972                                      path_mtu=512,
7973                                      template_interval=10)
7974         self.vapi.nat_ipfix_enable_disable(domain_id=1, src_port=4739,
7975                                            enable=1)
7976
7977         pkts = []
7978         for port in range(1025, 2025):
7979             p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
7980                  IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
7981                  UDP(sport=port, dport=port))
7982             pkts.append(p)
7983
7984         self.pg0.add_stream(pkts)
7985         self.pg_enable_capture(self.pg_interfaces)
7986         self.pg_start()
7987         capture = self.pg1.get_capture(len(pkts))
7988
7989         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
7990              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
7991              UDP(sport=3001, dport=3002))
7992         self.pg0.add_stream(p)
7993         self.pg_enable_capture(self.pg_interfaces)
7994         self.pg_start()
7995         capture = self.pg1.assert_nothing_captured()
7996
7997         # verify ICMP error packet
7998         capture = self.pg0.get_capture(1)
7999         p = capture[0]
8000         self.assertTrue(p.haslayer(ICMP))
8001         icmp = p[ICMP]
8002         self.assertEqual(icmp.type, 3)
8003         self.assertEqual(icmp.code, 1)
8004         self.assertTrue(icmp.haslayer(IPerror))
8005         inner_ip = icmp[IPerror]
8006         self.assertEqual(inner_ip[UDPerror].sport, 3001)
8007         self.assertEqual(inner_ip[UDPerror].dport, 3002)
8008
8009         dms = self.vapi.nat_det_map_dump()
8010
8011         self.assertEqual(1000, dms[0].ses_num)
8012
8013         # verify IPFIX logging
8014         self.vapi.ipfix_flush()
8015         sleep(1)
8016         capture = self.pg2.get_capture(2)
8017         ipfix = IPFIXDecoder()
8018         # first load template
8019         for p in capture:
8020             self.assertTrue(p.haslayer(IPFIX))
8021             if p.haslayer(Template):
8022                 ipfix.add_template(p.getlayer(Template))
8023         # verify events in data set
8024         for p in capture:
8025             if p.haslayer(Data):
8026                 data = ipfix.decode_data_set(p.getlayer(Set))
8027                 self.verify_ipfix_max_entries_per_user(data,
8028                                                        1000,
8029                                                        self.pg0.remote_ip4)
8030
8031     def clear_nat_det(self):
8032         """
8033         Clear deterministic NAT configuration.
8034         """
8035         self.vapi.nat_ipfix_enable_disable(domain_id=1, src_port=4739,
8036                                            enable=0)
8037         self.vapi.nat_set_timeouts(udp=300, tcp_established=7440,
8038                                    tcp_transitory=240, icmp=60)
8039         deterministic_mappings = self.vapi.nat_det_map_dump()
8040         for dsm in deterministic_mappings:
8041             self.vapi.nat_det_add_del_map(is_add=0, in_addr=dsm.in_addr,
8042                                           in_plen=dsm.in_plen,
8043                                           out_addr=dsm.out_addr,
8044                                           out_plen=dsm.out_plen)
8045
8046         interfaces = self.vapi.nat44_interface_dump()
8047         for intf in interfaces:
8048             self.vapi.nat44_interface_add_del_feature(
8049                 sw_if_index=intf.sw_if_index,
8050                 flags=intf.flags)
8051
8052     def tearDown(self):
8053         super(TestDeterministicNAT, self).tearDown()
8054         if not self.vpp_dead:
8055             self.clear_nat_det()
8056
8057     def show_commands_at_teardown(self):
8058         self.logger.info(self.vapi.cli("show nat44 interfaces"))
8059         self.logger.info(self.vapi.cli("show nat timeouts"))
8060         self.logger.info(
8061             self.vapi.cli("show nat44 deterministic mappings"))
8062         self.logger.info(
8063             self.vapi.cli("show nat44 deterministic sessions"))
8064
8065
8066 class TestNAT64(MethodHolder):
8067     """ NAT64 Test Cases """
8068
8069     @classmethod
8070     def setUpConstants(cls):
8071         super(TestNAT64, cls).setUpConstants()
8072         cls.vpp_cmdline.extend(["nat", "{", "nat64 bib hash buckets 128",
8073                                 "nat64 st hash buckets 256", "}"])
8074
8075     @classmethod
8076     def setUpClass(cls):
8077         super(TestNAT64, cls).setUpClass()
8078
8079         cls.tcp_port_in = 6303
8080         cls.tcp_port_out = 6303
8081         cls.udp_port_in = 6304
8082         cls.udp_port_out = 6304
8083         cls.icmp_id_in = 6305
8084         cls.icmp_id_out = 6305
8085         cls.tcp_external_port = 80
8086         cls.nat_addr = '10.0.0.3'
8087         cls.nat_addr_n = socket.inet_pton(socket.AF_INET, cls.nat_addr)
8088         cls.vrf1_id = 10
8089         cls.vrf1_nat_addr = '10.0.10.3'
8090         cls.ipfix_src_port = 4739
8091         cls.ipfix_domain_id = 1
8092
8093         cls.create_pg_interfaces(range(6))
8094         cls.ip6_interfaces = list(cls.pg_interfaces[0:1])
8095         cls.ip6_interfaces.append(cls.pg_interfaces[2])
8096         cls.ip4_interfaces = list(cls.pg_interfaces[1:2])
8097
8098         cls.vapi.ip_table_add_del(is_add=1,
8099                                   table={'table_id': cls.vrf1_id,
8100                                          'is_ip6': 1})
8101
8102         cls.pg_interfaces[2].set_table_ip6(cls.vrf1_id)
8103
8104         cls.pg0.generate_remote_hosts(2)
8105
8106         for i in cls.ip6_interfaces:
8107             i.admin_up()
8108             i.config_ip6()
8109             i.configure_ipv6_neighbors()
8110
8111         for i in cls.ip4_interfaces:
8112             i.admin_up()
8113             i.config_ip4()
8114             i.resolve_arp()
8115
8116         cls.pg3.admin_up()
8117         cls.pg3.config_ip4()
8118         cls.pg3.resolve_arp()
8119         cls.pg3.config_ip6()
8120         cls.pg3.configure_ipv6_neighbors()
8121
8122         cls.pg5.admin_up()
8123         cls.pg5.config_ip6()
8124
8125     @classmethod
8126     def tearDownClass(cls):
8127         super(TestNAT64, cls).tearDownClass()
8128
8129     def test_nat64_inside_interface_handles_neighbor_advertisement(self):
8130         """ NAT64 inside interface handles Neighbor Advertisement """
8131
8132         flags = self.config_flags.NAT_IS_INSIDE
8133         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
8134                                           sw_if_index=self.pg5.sw_if_index)
8135
8136         # Try to send ping
8137         ping = (Ether(dst=self.pg5.local_mac, src=self.pg5.remote_mac) /
8138                 IPv6(src=self.pg5.remote_ip6, dst=self.pg5.local_ip6) /
8139                 ICMPv6EchoRequest())
8140         pkts = [ping]
8141         self.pg5.add_stream(pkts)
8142         self.pg_enable_capture(self.pg_interfaces)
8143         self.pg_start()
8144
8145         # Wait for Neighbor Solicitation
8146         capture = self.pg5.get_capture(len(pkts))
8147         packet = capture[0]
8148         try:
8149             self.assertEqual(packet[IPv6].src, self.pg5.local_ip6)
8150             self.assertEqual(packet.haslayer(ICMPv6ND_NS), 1)
8151             tgt = packet[ICMPv6ND_NS].tgt
8152         except:
8153             self.logger.error(ppp("Unexpected or invalid packet:", packet))
8154             raise
8155
8156         # Send Neighbor Advertisement
8157         p = (Ether(dst=self.pg5.local_mac, src=self.pg5.remote_mac) /
8158              IPv6(src=self.pg5.remote_ip6, dst=self.pg5.local_ip6) /
8159              ICMPv6ND_NA(tgt=tgt) /
8160              ICMPv6NDOptDstLLAddr(lladdr=self.pg5.remote_mac))
8161         pkts = [p]
8162         self.pg5.add_stream(pkts)
8163         self.pg_enable_capture(self.pg_interfaces)
8164         self.pg_start()
8165
8166         # Try to send ping again
8167         pkts = [ping]
8168         self.pg5.add_stream(pkts)
8169         self.pg_enable_capture(self.pg_interfaces)
8170         self.pg_start()
8171
8172         # Wait for ping reply
8173         capture = self.pg5.get_capture(len(pkts))
8174         packet = capture[0]
8175         try:
8176             self.assertEqual(packet[IPv6].src, self.pg5.local_ip6)
8177             self.assertEqual(packet[IPv6].dst, self.pg5.remote_ip6)
8178             self.assertEqual(packet.haslayer(ICMPv6EchoReply), 1)
8179         except:
8180             self.logger.error(ppp("Unexpected or invalid packet:", packet))
8181             raise
8182
8183     def test_pool(self):
8184         """ Add/delete address to NAT64 pool """
8185         nat_addr = '1.2.3.4'
8186
8187         self.vapi.nat64_add_del_pool_addr_range(start_addr=nat_addr,
8188                                                 end_addr=nat_addr,
8189                                                 vrf_id=0xFFFFFFFF, is_add=1)
8190
8191         addresses = self.vapi.nat64_pool_addr_dump()
8192         self.assertEqual(len(addresses), 1)
8193         self.assertEqual(str(addresses[0].address), nat_addr)
8194
8195         self.vapi.nat64_add_del_pool_addr_range(start_addr=nat_addr,
8196                                                 end_addr=nat_addr,
8197                                                 vrf_id=0xFFFFFFFF, is_add=0)
8198
8199         addresses = self.vapi.nat64_pool_addr_dump()
8200         self.assertEqual(len(addresses), 0)
8201
8202     def test_interface(self):
8203         """ Enable/disable NAT64 feature on the interface """
8204         flags = self.config_flags.NAT_IS_INSIDE
8205         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
8206                                           sw_if_index=self.pg0.sw_if_index)
8207         self.vapi.nat64_add_del_interface(is_add=1, flags=0,
8208                                           sw_if_index=self.pg1.sw_if_index)
8209
8210         interfaces = self.vapi.nat64_interface_dump()
8211         self.assertEqual(len(interfaces), 2)
8212         pg0_found = False
8213         pg1_found = False
8214         for intf in interfaces:
8215             if intf.sw_if_index == self.pg0.sw_if_index:
8216                 self.assertEqual(intf.flags, self.config_flags.NAT_IS_INSIDE)
8217                 pg0_found = True
8218             elif intf.sw_if_index == self.pg1.sw_if_index:
8219                 self.assertEqual(intf.flags, self.config_flags.NAT_IS_OUTSIDE)
8220                 pg1_found = True
8221         self.assertTrue(pg0_found)
8222         self.assertTrue(pg1_found)
8223
8224         features = self.vapi.cli("show interface features pg0")
8225         self.assertIn('nat64-in2out', features)
8226         features = self.vapi.cli("show interface features pg1")
8227         self.assertIn('nat64-out2in', features)
8228
8229         self.vapi.nat64_add_del_interface(is_add=0, flags=flags,
8230                                           sw_if_index=self.pg0.sw_if_index)
8231         self.vapi.nat64_add_del_interface(is_add=0, flags=flags,
8232                                           sw_if_index=self.pg1.sw_if_index)
8233
8234         interfaces = self.vapi.nat64_interface_dump()
8235         self.assertEqual(len(interfaces), 0)
8236
8237     def test_static_bib(self):
8238         """ Add/delete static BIB entry """
8239         in_addr = '2001:db8:85a3::8a2e:370:7334'
8240         out_addr = '10.1.1.3'
8241         in_port = 1234
8242         out_port = 5678
8243         proto = IP_PROTOS.tcp
8244
8245         self.vapi.nat64_add_del_static_bib(i_addr=in_addr, o_addr=out_addr,
8246                                            i_port=in_port, o_port=out_port,
8247                                            proto=proto, vrf_id=0, is_add=1)
8248         bib = self.vapi.nat64_bib_dump(proto=IP_PROTOS.tcp)
8249         static_bib_num = 0
8250         for bibe in bib:
8251             if bibe.flags & self.config_flags.NAT_IS_STATIC:
8252                 static_bib_num += 1
8253                 self.assertEqual(str(bibe.i_addr), in_addr)
8254                 self.assertEqual(str(bibe.o_addr), out_addr)
8255                 self.assertEqual(bibe.i_port, in_port)
8256                 self.assertEqual(bibe.o_port, out_port)
8257         self.assertEqual(static_bib_num, 1)
8258         bibs = self.statistics.get_counter('/nat64/total-bibs')
8259         self.assertEqual(bibs[0][0], 1)
8260
8261         self.vapi.nat64_add_del_static_bib(i_addr=in_addr, o_addr=out_addr,
8262                                            i_port=in_port, o_port=out_port,
8263                                            proto=proto, vrf_id=0, is_add=0)
8264         bib = self.vapi.nat64_bib_dump(proto=IP_PROTOS.tcp)
8265         static_bib_num = 0
8266         for bibe in bib:
8267             if bibe.flags & self.config_flags.NAT_IS_STATIC:
8268                 static_bib_num += 1
8269         self.assertEqual(static_bib_num, 0)
8270         bibs = self.statistics.get_counter('/nat64/total-bibs')
8271         self.assertEqual(bibs[0][0], 0)
8272
8273     def test_set_timeouts(self):
8274         """ Set NAT64 timeouts """
8275         # verify default values
8276         timeouts = self.vapi.nat_get_timeouts()
8277         self.assertEqual(timeouts.udp, 300)
8278         self.assertEqual(timeouts.icmp, 60)
8279         self.assertEqual(timeouts.tcp_transitory, 240)
8280         self.assertEqual(timeouts.tcp_established, 7440)
8281
8282         # set and verify custom values
8283         self.vapi.nat_set_timeouts(udp=200, tcp_established=7450,
8284                                    tcp_transitory=250, icmp=30)
8285         timeouts = self.vapi.nat_get_timeouts()
8286         self.assertEqual(timeouts.udp, 200)
8287         self.assertEqual(timeouts.icmp, 30)
8288         self.assertEqual(timeouts.tcp_transitory, 250)
8289         self.assertEqual(timeouts.tcp_established, 7450)
8290
8291     def test_dynamic(self):
8292         """ NAT64 dynamic translation test """
8293         self.tcp_port_in = 6303
8294         self.udp_port_in = 6304
8295         self.icmp_id_in = 6305
8296
8297         ses_num_start = self.nat64_get_ses_num()
8298
8299         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr,
8300                                                 end_addr=self.nat_addr,
8301                                                 vrf_id=0xFFFFFFFF,
8302                                                 is_add=1)
8303         flags = self.config_flags.NAT_IS_INSIDE
8304         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
8305                                           sw_if_index=self.pg0.sw_if_index)
8306         self.vapi.nat64_add_del_interface(is_add=1, flags=0,
8307                                           sw_if_index=self.pg1.sw_if_index)
8308
8309         # in2out
8310         tcpn = self.statistics.get_err_counter('/err/nat64-in2out/TCP packets')
8311         udpn = self.statistics.get_err_counter('/err/nat64-in2out/UDP packets')
8312         icmpn = self.statistics.get_err_counter(
8313             '/err/nat64-in2out/ICMP packets')
8314         totaln = self.statistics.get_err_counter(
8315             '/err/nat64-in2out/good in2out packets processed')
8316
8317         pkts = self.create_stream_in_ip6(self.pg0, self.pg1)
8318         self.pg0.add_stream(pkts)
8319         self.pg_enable_capture(self.pg_interfaces)
8320         self.pg_start()
8321         capture = self.pg1.get_capture(len(pkts))
8322         self.verify_capture_out(capture, nat_ip=self.nat_addr,
8323                                 dst_ip=self.pg1.remote_ip4)
8324
8325         err = self.statistics.get_err_counter('/err/nat64-in2out/TCP packets')
8326         self.assertEqual(err - tcpn, 1)
8327         err = self.statistics.get_err_counter('/err/nat64-in2out/UDP packets')
8328         self.assertEqual(err - udpn, 1)
8329         err = self.statistics.get_err_counter('/err/nat64-in2out/ICMP packets')
8330         self.assertEqual(err - icmpn, 1)
8331         err = self.statistics.get_err_counter(
8332             '/err/nat64-in2out/good in2out packets processed')
8333         self.assertEqual(err - totaln, 3)
8334
8335         # out2in
8336         tcpn = self.statistics.get_err_counter('/err/nat64-out2in/TCP packets')
8337         udpn = self.statistics.get_err_counter('/err/nat64-out2in/UDP packets')
8338         icmpn = self.statistics.get_err_counter(
8339             '/err/nat64-out2in/ICMP packets')
8340         totaln = self.statistics.get_err_counter(
8341             '/err/nat64-out2in/good out2in packets processed')
8342
8343         pkts = self.create_stream_out(self.pg1, dst_ip=self.nat_addr)
8344         self.pg1.add_stream(pkts)
8345         self.pg_enable_capture(self.pg_interfaces)
8346         self.pg_start()
8347         capture = self.pg0.get_capture(len(pkts))
8348         ip = IPv6(src=''.join(['64:ff9b::', self.pg1.remote_ip4]))
8349         self.verify_capture_in_ip6(capture, ip[IPv6].src, self.pg0.remote_ip6)
8350
8351         err = self.statistics.get_err_counter('/err/nat64-out2in/TCP packets')
8352         self.assertEqual(err - tcpn, 2)
8353         err = self.statistics.get_err_counter('/err/nat64-out2in/UDP packets')
8354         self.assertEqual(err - udpn, 1)
8355         err = self.statistics.get_err_counter('/err/nat64-out2in/ICMP packets')
8356         self.assertEqual(err - icmpn, 1)
8357         err = self.statistics.get_err_counter(
8358             '/err/nat64-out2in/good out2in packets processed')
8359         self.assertEqual(err - totaln, 4)
8360
8361         bibs = self.statistics.get_counter('/nat64/total-bibs')
8362         self.assertEqual(bibs[0][0], 3)
8363         sessions = self.statistics.get_counter('/nat64/total-sessions')
8364         self.assertEqual(sessions[0][0], 3)
8365
8366         # in2out
8367         pkts = self.create_stream_in_ip6(self.pg0, self.pg1)
8368         self.pg0.add_stream(pkts)
8369         self.pg_enable_capture(self.pg_interfaces)
8370         self.pg_start()
8371         capture = self.pg1.get_capture(len(pkts))
8372         self.verify_capture_out(capture, nat_ip=self.nat_addr,
8373                                 dst_ip=self.pg1.remote_ip4)
8374
8375         # out2in
8376         pkts = self.create_stream_out(self.pg1, dst_ip=self.nat_addr)
8377         self.pg1.add_stream(pkts)
8378         self.pg_enable_capture(self.pg_interfaces)
8379         self.pg_start()
8380         capture = self.pg0.get_capture(len(pkts))
8381         self.verify_capture_in_ip6(capture, ip[IPv6].src, self.pg0.remote_ip6)
8382
8383         ses_num_end = self.nat64_get_ses_num()
8384
8385         self.assertEqual(ses_num_end - ses_num_start, 3)
8386
8387         # tenant with specific VRF
8388         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.vrf1_nat_addr,
8389                                                 end_addr=self.vrf1_nat_addr,
8390                                                 vrf_id=self.vrf1_id, is_add=1)
8391         flags = self.config_flags.NAT_IS_INSIDE
8392         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
8393                                           sw_if_index=self.pg2.sw_if_index)
8394
8395         pkts = self.create_stream_in_ip6(self.pg2, self.pg1)
8396         self.pg2.add_stream(pkts)
8397         self.pg_enable_capture(self.pg_interfaces)
8398         self.pg_start()
8399         capture = self.pg1.get_capture(len(pkts))
8400         self.verify_capture_out(capture, nat_ip=self.vrf1_nat_addr,
8401                                 dst_ip=self.pg1.remote_ip4)
8402
8403         pkts = self.create_stream_out(self.pg1, dst_ip=self.vrf1_nat_addr)
8404         self.pg1.add_stream(pkts)
8405         self.pg_enable_capture(self.pg_interfaces)
8406         self.pg_start()
8407         capture = self.pg2.get_capture(len(pkts))
8408         self.verify_capture_in_ip6(capture, ip[IPv6].src, self.pg2.remote_ip6)
8409
8410     def test_static(self):
8411         """ NAT64 static translation test """
8412         self.tcp_port_in = 60303
8413         self.udp_port_in = 60304
8414         self.icmp_id_in = 60305
8415         self.tcp_port_out = 60303
8416         self.udp_port_out = 60304
8417         self.icmp_id_out = 60305
8418
8419         ses_num_start = self.nat64_get_ses_num()
8420
8421         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr,
8422                                                 end_addr=self.nat_addr,
8423                                                 vrf_id=0xFFFFFFFF,
8424                                                 is_add=1)
8425         flags = self.config_flags.NAT_IS_INSIDE
8426         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
8427                                           sw_if_index=self.pg0.sw_if_index)
8428         self.vapi.nat64_add_del_interface(is_add=1, flags=0,
8429                                           sw_if_index=self.pg1.sw_if_index)
8430
8431         self.vapi.nat64_add_del_static_bib(i_addr=self.pg0.remote_ip6,
8432                                            o_addr=self.nat_addr,
8433                                            i_port=self.tcp_port_in,
8434                                            o_port=self.tcp_port_out,
8435                                            proto=IP_PROTOS.tcp, vrf_id=0,
8436                                            is_add=1)
8437         self.vapi.nat64_add_del_static_bib(i_addr=self.pg0.remote_ip6,
8438                                            o_addr=self.nat_addr,
8439                                            i_port=self.udp_port_in,
8440                                            o_port=self.udp_port_out,
8441                                            proto=IP_PROTOS.udp, vrf_id=0,
8442                                            is_add=1)
8443         self.vapi.nat64_add_del_static_bib(i_addr=self.pg0.remote_ip6,
8444                                            o_addr=self.nat_addr,
8445                                            i_port=self.icmp_id_in,
8446                                            o_port=self.icmp_id_out,
8447                                            proto=IP_PROTOS.icmp, vrf_id=0,
8448                                            is_add=1)
8449
8450         # in2out
8451         pkts = self.create_stream_in_ip6(self.pg0, self.pg1)
8452         self.pg0.add_stream(pkts)
8453         self.pg_enable_capture(self.pg_interfaces)
8454         self.pg_start()
8455         capture = self.pg1.get_capture(len(pkts))
8456         self.verify_capture_out(capture, nat_ip=self.nat_addr,
8457                                 dst_ip=self.pg1.remote_ip4, same_port=True)
8458
8459         # out2in
8460         pkts = self.create_stream_out(self.pg1, dst_ip=self.nat_addr)
8461         self.pg1.add_stream(pkts)
8462         self.pg_enable_capture(self.pg_interfaces)
8463         self.pg_start()
8464         capture = self.pg0.get_capture(len(pkts))
8465         ip = IPv6(src=''.join(['64:ff9b::', self.pg1.remote_ip4]))
8466         self.verify_capture_in_ip6(capture, ip[IPv6].src, self.pg0.remote_ip6)
8467
8468         ses_num_end = self.nat64_get_ses_num()
8469
8470         self.assertEqual(ses_num_end - ses_num_start, 3)
8471
8472     @unittest.skipUnless(running_extended_tests, "part of extended tests")
8473     def test_session_timeout(self):
8474         """ NAT64 session timeout """
8475         self.icmp_id_in = 1234
8476         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr,
8477                                                 end_addr=self.nat_addr,
8478                                                 vrf_id=0xFFFFFFFF,
8479                                                 is_add=1)
8480         flags = self.config_flags.NAT_IS_INSIDE
8481         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
8482                                           sw_if_index=self.pg0.sw_if_index)
8483         self.vapi.nat64_add_del_interface(is_add=1, flags=0,
8484                                           sw_if_index=self.pg1.sw_if_index)
8485         self.vapi.nat_set_timeouts(udp=300, tcp_established=5,
8486                                    tcp_transitory=5,
8487                                    icmp=5)
8488
8489         pkts = self.create_stream_in_ip6(self.pg0, self.pg1)
8490         self.pg0.add_stream(pkts)
8491         self.pg_enable_capture(self.pg_interfaces)
8492         self.pg_start()
8493         capture = self.pg1.get_capture(len(pkts))
8494
8495         ses_num_before_timeout = self.nat64_get_ses_num()
8496
8497         sleep(15)
8498
8499         # ICMP and TCP session after timeout
8500         ses_num_after_timeout = self.nat64_get_ses_num()
8501         self.assertEqual(ses_num_before_timeout - ses_num_after_timeout, 2)
8502
8503     def test_icmp_error(self):
8504         """ NAT64 ICMP Error message translation """
8505         self.tcp_port_in = 6303
8506         self.udp_port_in = 6304
8507         self.icmp_id_in = 6305
8508
8509         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr,
8510                                                 end_addr=self.nat_addr,
8511                                                 vrf_id=0xFFFFFFFF,
8512                                                 is_add=1)
8513         flags = self.config_flags.NAT_IS_INSIDE
8514         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
8515                                           sw_if_index=self.pg0.sw_if_index)
8516         self.vapi.nat64_add_del_interface(is_add=1, flags=0,
8517                                           sw_if_index=self.pg1.sw_if_index)
8518
8519         # send some packets to create sessions
8520         pkts = self.create_stream_in_ip6(self.pg0, self.pg1)
8521         self.pg0.add_stream(pkts)
8522         self.pg_enable_capture(self.pg_interfaces)
8523         self.pg_start()
8524         capture_ip4 = self.pg1.get_capture(len(pkts))
8525         self.verify_capture_out(capture_ip4,
8526                                 nat_ip=self.nat_addr,
8527                                 dst_ip=self.pg1.remote_ip4)
8528
8529         pkts = self.create_stream_out(self.pg1, dst_ip=self.nat_addr)
8530         self.pg1.add_stream(pkts)
8531         self.pg_enable_capture(self.pg_interfaces)
8532         self.pg_start()
8533         capture_ip6 = self.pg0.get_capture(len(pkts))
8534         ip = IPv6(src=''.join(['64:ff9b::', self.pg1.remote_ip4]))
8535         self.verify_capture_in_ip6(capture_ip6, ip[IPv6].src,
8536                                    self.pg0.remote_ip6)
8537
8538         # in2out
8539         pkts = [Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
8540                 IPv6(src=self.pg0.remote_ip6, dst=ip[IPv6].src) /
8541                 ICMPv6DestUnreach(code=1) /
8542                 packet[IPv6] for packet in capture_ip6]
8543         self.pg0.add_stream(pkts)
8544         self.pg_enable_capture(self.pg_interfaces)
8545         self.pg_start()
8546         capture = self.pg1.get_capture(len(pkts))
8547         for packet in capture:
8548             try:
8549                 self.assertEqual(packet[IP].src, self.nat_addr)
8550                 self.assertEqual(packet[IP].dst, self.pg1.remote_ip4)
8551                 self.assertEqual(packet[ICMP].type, 3)
8552                 self.assertEqual(packet[ICMP].code, 13)
8553                 inner = packet[IPerror]
8554                 self.assertEqual(inner.src, self.pg1.remote_ip4)
8555                 self.assertEqual(inner.dst, self.nat_addr)
8556                 self.assert_packet_checksums_valid(packet)
8557                 if inner.haslayer(TCPerror):
8558                     self.assertEqual(inner[TCPerror].dport, self.tcp_port_out)
8559                 elif inner.haslayer(UDPerror):
8560                     self.assertEqual(inner[UDPerror].dport, self.udp_port_out)
8561                 else:
8562                     self.assertEqual(inner[ICMPerror].id, self.icmp_id_out)
8563             except:
8564                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
8565                 raise
8566
8567         # out2in
8568         pkts = [Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
8569                 IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
8570                 ICMP(type=3, code=13) /
8571                 packet[IP] for packet in capture_ip4]
8572         self.pg1.add_stream(pkts)
8573         self.pg_enable_capture(self.pg_interfaces)
8574         self.pg_start()
8575         capture = self.pg0.get_capture(len(pkts))
8576         for packet in capture:
8577             try:
8578                 self.assertEqual(packet[IPv6].src, ip.src)
8579                 self.assertEqual(packet[IPv6].dst, self.pg0.remote_ip6)
8580                 icmp = packet[ICMPv6DestUnreach]
8581                 self.assertEqual(icmp.code, 1)
8582                 inner = icmp[IPerror6]
8583                 self.assertEqual(inner.src, self.pg0.remote_ip6)
8584                 self.assertEqual(inner.dst, ip.src)
8585                 self.assert_icmpv6_checksum_valid(packet)
8586                 if inner.haslayer(TCPerror):
8587                     self.assertEqual(inner[TCPerror].sport, self.tcp_port_in)
8588                 elif inner.haslayer(UDPerror):
8589                     self.assertEqual(inner[UDPerror].sport, self.udp_port_in)
8590                 else:
8591                     self.assertEqual(inner[ICMPv6EchoRequest].id,
8592                                      self.icmp_id_in)
8593             except:
8594                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
8595                 raise
8596
8597     def test_hairpinning(self):
8598         """ NAT64 hairpinning """
8599
8600         client = self.pg0.remote_hosts[0]
8601         server = self.pg0.remote_hosts[1]
8602         server_tcp_in_port = 22
8603         server_tcp_out_port = 4022
8604         server_udp_in_port = 23
8605         server_udp_out_port = 4023
8606         client_tcp_in_port = 1234
8607         client_udp_in_port = 1235
8608         client_tcp_out_port = 0
8609         client_udp_out_port = 0
8610         ip = IPv6(src=''.join(['64:ff9b::', self.nat_addr]))
8611         nat_addr_ip6 = ip.src
8612
8613         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr,
8614                                                 end_addr=self.nat_addr,
8615                                                 vrf_id=0xFFFFFFFF,
8616                                                 is_add=1)
8617         flags = self.config_flags.NAT_IS_INSIDE
8618         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
8619                                           sw_if_index=self.pg0.sw_if_index)
8620         self.vapi.nat64_add_del_interface(is_add=1, flags=0,
8621                                           sw_if_index=self.pg1.sw_if_index)
8622
8623         self.vapi.nat64_add_del_static_bib(i_addr=server.ip6n,
8624                                            o_addr=self.nat_addr,
8625                                            i_port=server_tcp_in_port,
8626                                            o_port=server_tcp_out_port,
8627                                            proto=IP_PROTOS.tcp, vrf_id=0,
8628                                            is_add=1)
8629         self.vapi.nat64_add_del_static_bib(i_addr=server.ip6n,
8630                                            o_addr=self.nat_addr,
8631                                            i_port=server_udp_in_port,
8632                                            o_port=server_udp_out_port,
8633                                            proto=IP_PROTOS.udp, vrf_id=0,
8634                                            is_add=1)
8635
8636         # client to server
8637         pkts = []
8638         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
8639              IPv6(src=client.ip6, dst=nat_addr_ip6) /
8640              TCP(sport=client_tcp_in_port, dport=server_tcp_out_port))
8641         pkts.append(p)
8642         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
8643              IPv6(src=client.ip6, dst=nat_addr_ip6) /
8644              UDP(sport=client_udp_in_port, dport=server_udp_out_port))
8645         pkts.append(p)
8646         self.pg0.add_stream(pkts)
8647         self.pg_enable_capture(self.pg_interfaces)
8648         self.pg_start()
8649         capture = self.pg0.get_capture(len(pkts))
8650         for packet in capture:
8651             try:
8652                 self.assertEqual(packet[IPv6].src, nat_addr_ip6)
8653                 self.assertEqual(packet[IPv6].dst, server.ip6)
8654                 self.assert_packet_checksums_valid(packet)
8655                 if packet.haslayer(TCP):
8656                     self.assertNotEqual(packet[TCP].sport, client_tcp_in_port)
8657                     self.assertEqual(packet[TCP].dport, server_tcp_in_port)
8658                     client_tcp_out_port = packet[TCP].sport
8659                 else:
8660                     self.assertNotEqual(packet[UDP].sport, client_udp_in_port)
8661                     self.assertEqual(packet[UDP].dport, server_udp_in_port)
8662                     client_udp_out_port = packet[UDP].sport
8663             except:
8664                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
8665                 raise
8666
8667         # server to client
8668         pkts = []
8669         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
8670              IPv6(src=server.ip6, dst=nat_addr_ip6) /
8671              TCP(sport=server_tcp_in_port, dport=client_tcp_out_port))
8672         pkts.append(p)
8673         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
8674              IPv6(src=server.ip6, dst=nat_addr_ip6) /
8675              UDP(sport=server_udp_in_port, dport=client_udp_out_port))
8676         pkts.append(p)
8677         self.pg0.add_stream(pkts)
8678         self.pg_enable_capture(self.pg_interfaces)
8679         self.pg_start()
8680         capture = self.pg0.get_capture(len(pkts))
8681         for packet in capture:
8682             try:
8683                 self.assertEqual(packet[IPv6].src, nat_addr_ip6)
8684                 self.assertEqual(packet[IPv6].dst, client.ip6)
8685                 self.assert_packet_checksums_valid(packet)
8686                 if packet.haslayer(TCP):
8687                     self.assertEqual(packet[TCP].sport, server_tcp_out_port)
8688                     self.assertEqual(packet[TCP].dport, client_tcp_in_port)
8689                 else:
8690                     self.assertEqual(packet[UDP].sport, server_udp_out_port)
8691                     self.assertEqual(packet[UDP].dport, client_udp_in_port)
8692             except:
8693                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
8694                 raise
8695
8696         # ICMP error
8697         pkts = []
8698         pkts = [Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
8699                 IPv6(src=client.ip6, dst=nat_addr_ip6) /
8700                 ICMPv6DestUnreach(code=1) /
8701                 packet[IPv6] for packet in capture]
8702         self.pg0.add_stream(pkts)
8703         self.pg_enable_capture(self.pg_interfaces)
8704         self.pg_start()
8705         capture = self.pg0.get_capture(len(pkts))
8706         for packet in capture:
8707             try:
8708                 self.assertEqual(packet[IPv6].src, nat_addr_ip6)
8709                 self.assertEqual(packet[IPv6].dst, server.ip6)
8710                 icmp = packet[ICMPv6DestUnreach]
8711                 self.assertEqual(icmp.code, 1)
8712                 inner = icmp[IPerror6]
8713                 self.assertEqual(inner.src, server.ip6)
8714                 self.assertEqual(inner.dst, nat_addr_ip6)
8715                 self.assert_packet_checksums_valid(packet)
8716                 if inner.haslayer(TCPerror):
8717                     self.assertEqual(inner[TCPerror].sport, server_tcp_in_port)
8718                     self.assertEqual(inner[TCPerror].dport,
8719                                      client_tcp_out_port)
8720                 else:
8721                     self.assertEqual(inner[UDPerror].sport, server_udp_in_port)
8722                     self.assertEqual(inner[UDPerror].dport,
8723                                      client_udp_out_port)
8724             except:
8725                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
8726                 raise
8727
8728     def test_prefix(self):
8729         """ NAT64 Network-Specific Prefix """
8730
8731         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr,
8732                                                 end_addr=self.nat_addr,
8733                                                 vrf_id=0xFFFFFFFF,
8734                                                 is_add=1)
8735         flags = self.config_flags.NAT_IS_INSIDE
8736         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
8737                                           sw_if_index=self.pg0.sw_if_index)
8738         self.vapi.nat64_add_del_interface(is_add=1, flags=0,
8739                                           sw_if_index=self.pg1.sw_if_index)
8740         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.vrf1_nat_addr,
8741                                                 end_addr=self.vrf1_nat_addr,
8742                                                 vrf_id=self.vrf1_id, is_add=1)
8743         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
8744                                           sw_if_index=self.pg2.sw_if_index)
8745
8746         # Add global prefix
8747         global_pref64 = "2001:db8::"
8748         global_pref64_len = 32
8749         global_pref64_str = "{}/{}".format(global_pref64, global_pref64_len)
8750         self.vapi.nat64_add_del_prefix(prefix=global_pref64_str, vrf_id=0,
8751                                        is_add=1)
8752
8753         prefix = self.vapi.nat64_prefix_dump()
8754         self.assertEqual(len(prefix), 1)
8755         self.assertEqual(str(prefix[0].prefix), global_pref64_str)
8756         self.assertEqual(prefix[0].vrf_id, 0)
8757
8758         # Add tenant specific prefix
8759         vrf1_pref64 = "2001:db8:122:300::"
8760         vrf1_pref64_len = 56
8761         vrf1_pref64_str = "{}/{}".format(vrf1_pref64, vrf1_pref64_len)
8762         self.vapi.nat64_add_del_prefix(prefix=vrf1_pref64_str,
8763                                        vrf_id=self.vrf1_id, is_add=1)
8764
8765         prefix = self.vapi.nat64_prefix_dump()
8766         self.assertEqual(len(prefix), 2)
8767
8768         # Global prefix
8769         pkts = self.create_stream_in_ip6(self.pg0,
8770                                          self.pg1,
8771                                          pref=global_pref64,
8772                                          plen=global_pref64_len)
8773         self.pg0.add_stream(pkts)
8774         self.pg_enable_capture(self.pg_interfaces)
8775         self.pg_start()
8776         capture = self.pg1.get_capture(len(pkts))
8777         self.verify_capture_out(capture, nat_ip=self.nat_addr,
8778                                 dst_ip=self.pg1.remote_ip4)
8779
8780         pkts = self.create_stream_out(self.pg1, dst_ip=self.nat_addr)
8781         self.pg1.add_stream(pkts)
8782         self.pg_enable_capture(self.pg_interfaces)
8783         self.pg_start()
8784         capture = self.pg0.get_capture(len(pkts))
8785         dst_ip = self.compose_ip6(self.pg1.remote_ip4,
8786                                   global_pref64,
8787                                   global_pref64_len)
8788         self.verify_capture_in_ip6(capture, dst_ip, self.pg0.remote_ip6)
8789
8790         # Tenant specific prefix
8791         pkts = self.create_stream_in_ip6(self.pg2,
8792                                          self.pg1,
8793                                          pref=vrf1_pref64,
8794                                          plen=vrf1_pref64_len)
8795         self.pg2.add_stream(pkts)
8796         self.pg_enable_capture(self.pg_interfaces)
8797         self.pg_start()
8798         capture = self.pg1.get_capture(len(pkts))
8799         self.verify_capture_out(capture, nat_ip=self.vrf1_nat_addr,
8800                                 dst_ip=self.pg1.remote_ip4)
8801
8802         pkts = self.create_stream_out(self.pg1, dst_ip=self.vrf1_nat_addr)
8803         self.pg1.add_stream(pkts)
8804         self.pg_enable_capture(self.pg_interfaces)
8805         self.pg_start()
8806         capture = self.pg2.get_capture(len(pkts))
8807         dst_ip = self.compose_ip6(self.pg1.remote_ip4,
8808                                   vrf1_pref64,
8809                                   vrf1_pref64_len)
8810         self.verify_capture_in_ip6(capture, dst_ip, self.pg2.remote_ip6)
8811
8812     def test_unknown_proto(self):
8813         """ NAT64 translate packet with unknown protocol """
8814
8815         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr,
8816                                                 end_addr=self.nat_addr,
8817                                                 vrf_id=0xFFFFFFFF,
8818                                                 is_add=1)
8819         flags = self.config_flags.NAT_IS_INSIDE
8820         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
8821                                           sw_if_index=self.pg0.sw_if_index)
8822         self.vapi.nat64_add_del_interface(is_add=1, flags=0,
8823                                           sw_if_index=self.pg1.sw_if_index)
8824         remote_ip6 = self.compose_ip6(self.pg1.remote_ip4, '64:ff9b::', 96)
8825
8826         # in2out
8827         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
8828              IPv6(src=self.pg0.remote_ip6, dst=remote_ip6) /
8829              TCP(sport=self.tcp_port_in, dport=20))
8830         self.pg0.add_stream(p)
8831         self.pg_enable_capture(self.pg_interfaces)
8832         self.pg_start()
8833         p = self.pg1.get_capture(1)
8834
8835         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
8836              IPv6(src=self.pg0.remote_ip6, dst=remote_ip6, nh=47) /
8837              GRE() /
8838              IP(src=self.pg2.local_ip4, dst=self.pg2.remote_ip4) /
8839              TCP(sport=1234, dport=1234))
8840         self.pg0.add_stream(p)
8841         self.pg_enable_capture(self.pg_interfaces)
8842         self.pg_start()
8843         p = self.pg1.get_capture(1)
8844         packet = p[0]
8845         try:
8846             self.assertEqual(packet[IP].src, self.nat_addr)
8847             self.assertEqual(packet[IP].dst, self.pg1.remote_ip4)
8848             self.assertEqual(packet.haslayer(GRE), 1)
8849             self.assert_packet_checksums_valid(packet)
8850         except:
8851             self.logger.error(ppp("Unexpected or invalid packet:", packet))
8852             raise
8853
8854         # out2in
8855         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
8856              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
8857              GRE() /
8858              IP(src=self.pg2.remote_ip4, dst=self.pg2.local_ip4) /
8859              TCP(sport=1234, dport=1234))
8860         self.pg1.add_stream(p)
8861         self.pg_enable_capture(self.pg_interfaces)
8862         self.pg_start()
8863         p = self.pg0.get_capture(1)
8864         packet = p[0]
8865         try:
8866             self.assertEqual(packet[IPv6].src, remote_ip6)
8867             self.assertEqual(packet[IPv6].dst, self.pg0.remote_ip6)
8868             self.assertEqual(packet[IPv6].nh, 47)
8869         except:
8870             self.logger.error(ppp("Unexpected or invalid packet:", packet))
8871             raise
8872
8873     def test_hairpinning_unknown_proto(self):
8874         """ NAT64 translate packet with unknown protocol - hairpinning """
8875
8876         client = self.pg0.remote_hosts[0]
8877         server = self.pg0.remote_hosts[1]
8878         server_tcp_in_port = 22
8879         server_tcp_out_port = 4022
8880         client_tcp_in_port = 1234
8881         client_tcp_out_port = 1235
8882         server_nat_ip = "10.0.0.100"
8883         client_nat_ip = "10.0.0.110"
8884         server_nat_ip6 = self.compose_ip6(server_nat_ip, '64:ff9b::', 96)
8885         client_nat_ip6 = self.compose_ip6(client_nat_ip, '64:ff9b::', 96)
8886
8887         self.vapi.nat64_add_del_pool_addr_range(start_addr=server_nat_ip,
8888                                                 end_addr=client_nat_ip,
8889                                                 vrf_id=0xFFFFFFFF,
8890                                                 is_add=1)
8891         flags = self.config_flags.NAT_IS_INSIDE
8892         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
8893                                           sw_if_index=self.pg0.sw_if_index)
8894         self.vapi.nat64_add_del_interface(is_add=1, flags=0,
8895                                           sw_if_index=self.pg1.sw_if_index)
8896
8897         self.vapi.nat64_add_del_static_bib(i_addr=server.ip6n,
8898                                            o_addr=server_nat_ip,
8899                                            i_port=server_tcp_in_port,
8900                                            o_port=server_tcp_out_port,
8901                                            proto=IP_PROTOS.tcp, vrf_id=0,
8902                                            is_add=1)
8903
8904         self.vapi.nat64_add_del_static_bib(i_addr=server.ip6n,
8905                                            o_addr=server_nat_ip, i_port=0,
8906                                            o_port=0,
8907                                            proto=IP_PROTOS.gre, vrf_id=0,
8908                                            is_add=1)
8909
8910         self.vapi.nat64_add_del_static_bib(i_addr=client.ip6n,
8911                                            o_addr=client_nat_ip,
8912                                            i_port=client_tcp_in_port,
8913                                            o_port=client_tcp_out_port,
8914                                            proto=IP_PROTOS.tcp, vrf_id=0,
8915                                            is_add=1)
8916
8917         # client to server
8918         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
8919              IPv6(src=client.ip6, dst=server_nat_ip6) /
8920              TCP(sport=client_tcp_in_port, dport=server_tcp_out_port))
8921         self.pg0.add_stream(p)
8922         self.pg_enable_capture(self.pg_interfaces)
8923         self.pg_start()
8924         p = self.pg0.get_capture(1)
8925
8926         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
8927              IPv6(src=client.ip6, dst=server_nat_ip6, nh=IP_PROTOS.gre) /
8928              GRE() /
8929              IP(src=self.pg2.local_ip4, dst=self.pg2.remote_ip4) /
8930              TCP(sport=1234, dport=1234))
8931         self.pg0.add_stream(p)
8932         self.pg_enable_capture(self.pg_interfaces)
8933         self.pg_start()
8934         p = self.pg0.get_capture(1)
8935         packet = p[0]
8936         try:
8937             self.assertEqual(packet[IPv6].src, client_nat_ip6)
8938             self.assertEqual(packet[IPv6].dst, server.ip6)
8939             self.assertEqual(packet[IPv6].nh, IP_PROTOS.gre)
8940         except:
8941             self.logger.error(ppp("Unexpected or invalid packet:", packet))
8942             raise
8943
8944         # server to client
8945         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
8946              IPv6(src=server.ip6, dst=client_nat_ip6, nh=IP_PROTOS.gre) /
8947              GRE() /
8948              IP(src=self.pg2.remote_ip4, dst=self.pg2.local_ip4) /
8949              TCP(sport=1234, dport=1234))
8950         self.pg0.add_stream(p)
8951         self.pg_enable_capture(self.pg_interfaces)
8952         self.pg_start()
8953         p = self.pg0.get_capture(1)
8954         packet = p[0]
8955         try:
8956             self.assertEqual(packet[IPv6].src, server_nat_ip6)
8957             self.assertEqual(packet[IPv6].dst, client.ip6)
8958             self.assertEqual(packet[IPv6].nh, IP_PROTOS.gre)
8959         except:
8960             self.logger.error(ppp("Unexpected or invalid packet:", packet))
8961             raise
8962
8963     def test_one_armed_nat64(self):
8964         """ One armed NAT64 """
8965         external_port = 0
8966         remote_host_ip6 = self.compose_ip6(self.pg3.remote_ip4,
8967                                            '64:ff9b::',
8968                                            96)
8969
8970         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr,
8971                                                 end_addr=self.nat_addr,
8972                                                 vrf_id=0xFFFFFFFF,
8973                                                 is_add=1)
8974         flags = self.config_flags.NAT_IS_INSIDE
8975         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
8976                                           sw_if_index=self.pg3.sw_if_index)
8977         self.vapi.nat64_add_del_interface(is_add=1, flags=0,
8978                                           sw_if_index=self.pg3.sw_if_index)
8979
8980         # in2out
8981         p = (Ether(src=self.pg3.remote_mac, dst=self.pg3.local_mac) /
8982              IPv6(src=self.pg3.remote_ip6, dst=remote_host_ip6) /
8983              TCP(sport=12345, dport=80))
8984         self.pg3.add_stream(p)
8985         self.pg_enable_capture(self.pg_interfaces)
8986         self.pg_start()
8987         capture = self.pg3.get_capture(1)
8988         p = capture[0]
8989         try:
8990             ip = p[IP]
8991             tcp = p[TCP]
8992             self.assertEqual(ip.src, self.nat_addr)
8993             self.assertEqual(ip.dst, self.pg3.remote_ip4)
8994             self.assertNotEqual(tcp.sport, 12345)
8995             external_port = tcp.sport
8996             self.assertEqual(tcp.dport, 80)
8997             self.assert_packet_checksums_valid(p)
8998         except:
8999             self.logger.error(ppp("Unexpected or invalid packet:", p))
9000             raise
9001
9002         # out2in
9003         p = (Ether(src=self.pg3.remote_mac, dst=self.pg3.local_mac) /
9004              IP(src=self.pg3.remote_ip4, dst=self.nat_addr) /
9005              TCP(sport=80, dport=external_port))
9006         self.pg3.add_stream(p)
9007         self.pg_enable_capture(self.pg_interfaces)
9008         self.pg_start()
9009         capture = self.pg3.get_capture(1)
9010         p = capture[0]
9011         try:
9012             ip = p[IPv6]
9013             tcp = p[TCP]
9014             self.assertEqual(ip.src, remote_host_ip6)
9015             self.assertEqual(ip.dst, self.pg3.remote_ip6)
9016             self.assertEqual(tcp.sport, 80)
9017             self.assertEqual(tcp.dport, 12345)
9018             self.assert_packet_checksums_valid(p)
9019         except:
9020             self.logger.error(ppp("Unexpected or invalid packet:", p))
9021             raise
9022
9023     def test_frag_in_order(self):
9024         """ NAT64 translate fragments arriving in order """
9025         self.tcp_port_in = random.randint(1025, 65535)
9026
9027         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr,
9028                                                 end_addr=self.nat_addr,
9029                                                 vrf_id=0xFFFFFFFF,
9030                                                 is_add=1)
9031         flags = self.config_flags.NAT_IS_INSIDE
9032         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
9033                                           sw_if_index=self.pg0.sw_if_index)
9034         self.vapi.nat64_add_del_interface(is_add=1, flags=0,
9035                                           sw_if_index=self.pg1.sw_if_index)
9036
9037         # in2out
9038         data = b'a' * 200
9039         pkts = self.create_stream_frag_ip6(self.pg0, self.pg1.remote_ip4,
9040                                            self.tcp_port_in, 20, data)
9041         self.pg0.add_stream(pkts)
9042         self.pg_enable_capture(self.pg_interfaces)
9043         self.pg_start()
9044         frags = self.pg1.get_capture(len(pkts))
9045         p = self.reass_frags_and_verify(frags,
9046                                         self.nat_addr,
9047                                         self.pg1.remote_ip4)
9048         self.assertEqual(p[TCP].dport, 20)
9049         self.assertNotEqual(p[TCP].sport, self.tcp_port_in)
9050         self.tcp_port_out = p[TCP].sport
9051         self.assertEqual(data, p[Raw].load)
9052
9053         # out2in
9054         data = b"A" * 4 + b"b" * 16 + b"C" * 3
9055         pkts = self.create_stream_frag(self.pg1,
9056                                        self.nat_addr,
9057                                        20,
9058                                        self.tcp_port_out,
9059                                        data)
9060         self.pg1.add_stream(pkts)
9061         self.pg_enable_capture(self.pg_interfaces)
9062         self.pg_start()
9063         frags = self.pg0.get_capture(len(pkts))
9064         self.logger.debug(ppc("Captured:", frags))
9065         src = self.compose_ip6(self.pg1.remote_ip4, '64:ff9b::', 96)
9066         p = self.reass_frags_and_verify_ip6(frags, src, self.pg0.remote_ip6)
9067         self.assertEqual(p[TCP].sport, 20)
9068         self.assertEqual(p[TCP].dport, self.tcp_port_in)
9069         self.assertEqual(data, p[Raw].load)
9070
9071     def test_reass_hairpinning(self):
9072         """ NAT64 fragments hairpinning """
9073         data = b'a' * 200
9074         server = self.pg0.remote_hosts[1]
9075         server_in_port = random.randint(1025, 65535)
9076         server_out_port = random.randint(1025, 65535)
9077         client_in_port = random.randint(1025, 65535)
9078         ip = IPv6(src=''.join(['64:ff9b::', self.nat_addr]))
9079         nat_addr_ip6 = ip.src
9080
9081         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr,
9082                                                 end_addr=self.nat_addr,
9083                                                 vrf_id=0xFFFFFFFF,
9084                                                 is_add=1)
9085         flags = self.config_flags.NAT_IS_INSIDE
9086         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
9087                                           sw_if_index=self.pg0.sw_if_index)
9088         self.vapi.nat64_add_del_interface(is_add=1, flags=0,
9089                                           sw_if_index=self.pg1.sw_if_index)
9090
9091         # add static BIB entry for server
9092         self.vapi.nat64_add_del_static_bib(i_addr=server.ip6n,
9093                                            o_addr=self.nat_addr,
9094                                            i_port=server_in_port,
9095                                            o_port=server_out_port,
9096                                            proto=IP_PROTOS.tcp, vrf_id=0,
9097                                            is_add=1)
9098
9099         # send packet from host to server
9100         pkts = self.create_stream_frag_ip6(self.pg0,
9101                                            self.nat_addr,
9102                                            client_in_port,
9103                                            server_out_port,
9104                                            data)
9105         self.pg0.add_stream(pkts)
9106         self.pg_enable_capture(self.pg_interfaces)
9107         self.pg_start()
9108         frags = self.pg0.get_capture(len(pkts))
9109         self.logger.debug(ppc("Captured:", frags))
9110         p = self.reass_frags_and_verify_ip6(frags, nat_addr_ip6, server.ip6)
9111         self.assertNotEqual(p[TCP].sport, client_in_port)
9112         self.assertEqual(p[TCP].dport, server_in_port)
9113         self.assertEqual(data, p[Raw].load)
9114
9115     def test_frag_out_of_order(self):
9116         """ NAT64 translate fragments arriving out of order """
9117         self.tcp_port_in = random.randint(1025, 65535)
9118
9119         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr,
9120                                                 end_addr=self.nat_addr,
9121                                                 vrf_id=0xFFFFFFFF,
9122                                                 is_add=1)
9123         flags = self.config_flags.NAT_IS_INSIDE
9124         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
9125                                           sw_if_index=self.pg0.sw_if_index)
9126         self.vapi.nat64_add_del_interface(is_add=1, flags=0,
9127                                           sw_if_index=self.pg1.sw_if_index)
9128
9129         # in2out
9130         data = b'a' * 200
9131         pkts = self.create_stream_frag_ip6(self.pg0, self.pg1.remote_ip4,
9132                                            self.tcp_port_in, 20, data)
9133         pkts.reverse()
9134         self.pg0.add_stream(pkts)
9135         self.pg_enable_capture(self.pg_interfaces)
9136         self.pg_start()
9137         frags = self.pg1.get_capture(len(pkts))
9138         p = self.reass_frags_and_verify(frags,
9139                                         self.nat_addr,
9140                                         self.pg1.remote_ip4)
9141         self.assertEqual(p[TCP].dport, 20)
9142         self.assertNotEqual(p[TCP].sport, self.tcp_port_in)
9143         self.tcp_port_out = p[TCP].sport
9144         self.assertEqual(data, p[Raw].load)
9145
9146         # out2in
9147         data = b"A" * 4 + b"B" * 16 + b"C" * 3
9148         pkts = self.create_stream_frag(self.pg1,
9149                                        self.nat_addr,
9150                                        20,
9151                                        self.tcp_port_out,
9152                                        data)
9153         pkts.reverse()
9154         self.pg1.add_stream(pkts)
9155         self.pg_enable_capture(self.pg_interfaces)
9156         self.pg_start()
9157         frags = self.pg0.get_capture(len(pkts))
9158         src = self.compose_ip6(self.pg1.remote_ip4, '64:ff9b::', 96)
9159         p = self.reass_frags_and_verify_ip6(frags, src, self.pg0.remote_ip6)
9160         self.assertEqual(p[TCP].sport, 20)
9161         self.assertEqual(p[TCP].dport, self.tcp_port_in)
9162         self.assertEqual(data, p[Raw].load)
9163
9164     def test_interface_addr(self):
9165         """ Acquire NAT64 pool addresses from interface """
9166         self.vapi.nat64_add_del_interface_addr(
9167             is_add=1,
9168             sw_if_index=self.pg4.sw_if_index)
9169
9170         # no address in NAT64 pool
9171         addresses = self.vapi.nat44_address_dump()
9172         self.assertEqual(0, len(addresses))
9173
9174         # configure interface address and check NAT64 address pool
9175         self.pg4.config_ip4()
9176         addresses = self.vapi.nat64_pool_addr_dump()
9177         self.assertEqual(len(addresses), 1)
9178
9179         self.assertEqual(str(addresses[0].address),
9180                          self.pg4.local_ip4)
9181
9182         # remove interface address and check NAT64 address pool
9183         self.pg4.unconfig_ip4()
9184         addresses = self.vapi.nat64_pool_addr_dump()
9185         self.assertEqual(0, len(addresses))
9186
9187     @unittest.skipUnless(running_extended_tests, "part of extended tests")
9188     def test_ipfix_max_bibs_sessions(self):
9189         """ IPFIX logging maximum session and BIB entries exceeded """
9190         max_bibs = 1280
9191         max_sessions = 2560
9192         remote_host_ip6 = self.compose_ip6(self.pg1.remote_ip4,
9193                                            '64:ff9b::',
9194                                            96)
9195
9196         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr,
9197                                                 end_addr=self.nat_addr,
9198                                                 vrf_id=0xFFFFFFFF,
9199                                                 is_add=1)
9200         flags = self.config_flags.NAT_IS_INSIDE
9201         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
9202                                           sw_if_index=self.pg0.sw_if_index)
9203         self.vapi.nat64_add_del_interface(is_add=1, flags=0,
9204                                           sw_if_index=self.pg1.sw_if_index)
9205
9206         pkts = []
9207         src = ""
9208         for i in range(0, max_bibs):
9209             src = "fd01:aa::%x" % (i)
9210             p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
9211                  IPv6(src=src, dst=remote_host_ip6) /
9212                  TCP(sport=12345, dport=80))
9213             pkts.append(p)
9214             p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
9215                  IPv6(src=src, dst=remote_host_ip6) /
9216                  TCP(sport=12345, dport=22))
9217             pkts.append(p)
9218         self.pg0.add_stream(pkts)
9219         self.pg_enable_capture(self.pg_interfaces)
9220         self.pg_start()
9221         self.pg1.get_capture(max_sessions)
9222
9223         self.vapi.set_ipfix_exporter(collector_address=self.pg3.remote_ip4,
9224                                      src_address=self.pg3.local_ip4,
9225                                      path_mtu=512,
9226                                      template_interval=10)
9227         self.vapi.nat_ipfix_enable_disable(domain_id=self.ipfix_domain_id,
9228                                            src_port=self.ipfix_src_port,
9229                                            enable=1)
9230
9231         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
9232              IPv6(src=src, dst=remote_host_ip6) /
9233              TCP(sport=12345, dport=25))
9234         self.pg0.add_stream(p)
9235         self.pg_enable_capture(self.pg_interfaces)
9236         self.pg_start()
9237         self.pg1.assert_nothing_captured()
9238         sleep(1)
9239         self.vapi.ipfix_flush()
9240         capture = self.pg3.get_capture(7)
9241         ipfix = IPFIXDecoder()
9242         # first load template
9243         for p in capture:
9244             self.assertTrue(p.haslayer(IPFIX))
9245             self.assertEqual(p[IP].src, self.pg3.local_ip4)
9246             self.assertEqual(p[IP].dst, self.pg3.remote_ip4)
9247             self.assertEqual(p[UDP].sport, self.ipfix_src_port)
9248             self.assertEqual(p[UDP].dport, 4739)
9249             self.assertEqual(p[IPFIX].observationDomainID,
9250                              self.ipfix_domain_id)
9251             if p.haslayer(Template):
9252                 ipfix.add_template(p.getlayer(Template))
9253         # verify events in data set
9254         for p in capture:
9255             if p.haslayer(Data):
9256                 data = ipfix.decode_data_set(p.getlayer(Set))
9257                 self.verify_ipfix_max_sessions(data, max_sessions)
9258
9259         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
9260              IPv6(src=self.pg0.remote_ip6, dst=remote_host_ip6) /
9261              TCP(sport=12345, dport=80))
9262         self.pg0.add_stream(p)
9263         self.pg_enable_capture(self.pg_interfaces)
9264         self.pg_start()
9265         self.pg1.assert_nothing_captured()
9266         sleep(1)
9267         self.vapi.ipfix_flush()
9268         capture = self.pg3.get_capture(1)
9269         # verify events in data set
9270         for p in capture:
9271             self.assertTrue(p.haslayer(IPFIX))
9272             self.assertEqual(p[IP].src, self.pg3.local_ip4)
9273             self.assertEqual(p[IP].dst, self.pg3.remote_ip4)
9274             self.assertEqual(p[UDP].sport, self.ipfix_src_port)
9275             self.assertEqual(p[UDP].dport, 4739)
9276             self.assertEqual(p[IPFIX].observationDomainID,
9277                              self.ipfix_domain_id)
9278             if p.haslayer(Data):
9279                 data = ipfix.decode_data_set(p.getlayer(Set))
9280                 self.verify_ipfix_max_bibs(data, max_bibs)
9281
9282     def test_ipfix_bib_ses(self):
9283         """ IPFIX logging NAT64 BIB/session create and delete events """
9284         self.tcp_port_in = random.randint(1025, 65535)
9285         remote_host_ip6 = self.compose_ip6(self.pg1.remote_ip4,
9286                                            '64:ff9b::',
9287                                            96)
9288
9289         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr,
9290                                                 end_addr=self.nat_addr,
9291                                                 vrf_id=0xFFFFFFFF,
9292                                                 is_add=1)
9293         flags = self.config_flags.NAT_IS_INSIDE
9294         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
9295                                           sw_if_index=self.pg0.sw_if_index)
9296         self.vapi.nat64_add_del_interface(is_add=1, flags=0,
9297                                           sw_if_index=self.pg1.sw_if_index)
9298         self.vapi.set_ipfix_exporter(collector_address=self.pg3.remote_ip4,
9299                                      src_address=self.pg3.local_ip4,
9300                                      path_mtu=512,
9301                                      template_interval=10)
9302         self.vapi.nat_ipfix_enable_disable(domain_id=self.ipfix_domain_id,
9303                                            src_port=self.ipfix_src_port,
9304                                            enable=1)
9305
9306         # Create
9307         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
9308              IPv6(src=self.pg0.remote_ip6, dst=remote_host_ip6) /
9309              TCP(sport=self.tcp_port_in, dport=25))
9310         self.pg0.add_stream(p)
9311         self.pg_enable_capture(self.pg_interfaces)
9312         self.pg_start()
9313         p = self.pg1.get_capture(1)
9314         self.tcp_port_out = p[0][TCP].sport
9315         self.vapi.ipfix_flush()
9316         capture = self.pg3.get_capture(8)
9317         ipfix = IPFIXDecoder()
9318         # first load template
9319         for p in capture:
9320             self.assertTrue(p.haslayer(IPFIX))
9321             self.assertEqual(p[IP].src, self.pg3.local_ip4)
9322             self.assertEqual(p[IP].dst, self.pg3.remote_ip4)
9323             self.assertEqual(p[UDP].sport, self.ipfix_src_port)
9324             self.assertEqual(p[UDP].dport, 4739)
9325             self.assertEqual(p[IPFIX].observationDomainID,
9326                              self.ipfix_domain_id)
9327             if p.haslayer(Template):
9328                 ipfix.add_template(p.getlayer(Template))
9329         # verify events in data set
9330         for p in capture:
9331             if p.haslayer(Data):
9332                 data = ipfix.decode_data_set(p.getlayer(Set))
9333                 if scapy.compat.orb(data[0][230]) == 10:
9334                     self.verify_ipfix_bib(data, 1, self.pg0.remote_ip6)
9335                 elif scapy.compat.orb(data[0][230]) == 6:
9336                     self.verify_ipfix_nat64_ses(data,
9337                                                 1,
9338                                                 self.pg0.remote_ip6,
9339                                                 self.pg1.remote_ip4,
9340                                                 25)
9341                 else:
9342                     self.logger.error(ppp("Unexpected or invalid packet: ", p))
9343
9344         # Delete
9345         self.pg_enable_capture(self.pg_interfaces)
9346         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr,
9347                                                 end_addr=self.nat_addr,
9348                                                 vrf_id=0xFFFFFFFF,
9349                                                 is_add=0)
9350         self.vapi.ipfix_flush()
9351         capture = self.pg3.get_capture(2)
9352         # verify events in data set
9353         for p in capture:
9354             self.assertTrue(p.haslayer(IPFIX))
9355             self.assertEqual(p[IP].src, self.pg3.local_ip4)
9356             self.assertEqual(p[IP].dst, self.pg3.remote_ip4)
9357             self.assertEqual(p[UDP].sport, self.ipfix_src_port)
9358             self.assertEqual(p[UDP].dport, 4739)
9359             self.assertEqual(p[IPFIX].observationDomainID,
9360                              self.ipfix_domain_id)
9361             if p.haslayer(Data):
9362                 data = ipfix.decode_data_set(p.getlayer(Set))
9363                 if scapy.compat.orb(data[0][230]) == 11:
9364                     self.verify_ipfix_bib(data, 0, self.pg0.remote_ip6)
9365                 elif scapy.compat.orb(data[0][230]) == 7:
9366                     self.verify_ipfix_nat64_ses(data,
9367                                                 0,
9368                                                 self.pg0.remote_ip6,
9369                                                 self.pg1.remote_ip4,
9370                                                 25)
9371                 else:
9372                     self.logger.error(ppp("Unexpected or invalid packet: ", p))
9373
9374     def test_syslog_sess(self):
9375         """ Test syslog session creation and deletion """
9376         self.tcp_port_in = random.randint(1025, 65535)
9377         remote_host_ip6 = self.compose_ip6(self.pg1.remote_ip4,
9378                                            '64:ff9b::',
9379                                            96)
9380
9381         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr,
9382                                                 end_addr=self.nat_addr,
9383                                                 vrf_id=0xFFFFFFFF,
9384                                                 is_add=1)
9385         flags = self.config_flags.NAT_IS_INSIDE
9386         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
9387                                           sw_if_index=self.pg0.sw_if_index)
9388         self.vapi.nat64_add_del_interface(is_add=1, flags=0,
9389                                           sw_if_index=self.pg1.sw_if_index)
9390         self.vapi.syslog_set_filter(
9391             self.SYSLOG_SEVERITY.SYSLOG_API_SEVERITY_INFO)
9392         self.vapi.syslog_set_sender(self.pg3.local_ip4, self.pg3.remote_ip4)
9393
9394         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
9395              IPv6(src=self.pg0.remote_ip6, dst=remote_host_ip6) /
9396              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port))
9397         self.pg0.add_stream(p)
9398         self.pg_enable_capture(self.pg_interfaces)
9399         self.pg_start()
9400         p = self.pg1.get_capture(1)
9401         self.tcp_port_out = p[0][TCP].sport
9402         capture = self.pg3.get_capture(1)
9403         self.verify_syslog_sess(capture[0][Raw].load, is_ip6=True)
9404
9405         self.pg_enable_capture(self.pg_interfaces)
9406         self.pg_start()
9407         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr,
9408                                                 end_addr=self.nat_addr,
9409                                                 vrf_id=0xFFFFFFFF,
9410                                                 is_add=0)
9411         capture = self.pg3.get_capture(1)
9412         self.verify_syslog_sess(capture[0][Raw].load, False, True)
9413
9414     def nat64_get_ses_num(self):
9415         """
9416         Return number of active NAT64 sessions.
9417         """
9418         st = self.vapi.nat64_st_dump(proto=255)
9419         return len(st)
9420
9421     def clear_nat64(self):
9422         """
9423         Clear NAT64 configuration.
9424         """
9425         self.vapi.nat_ipfix_enable_disable(domain_id=self.ipfix_domain_id,
9426                                            src_port=self.ipfix_src_port,
9427                                            enable=0)
9428         self.ipfix_src_port = 4739
9429         self.ipfix_domain_id = 1
9430
9431         self.vapi.syslog_set_filter(
9432             self.SYSLOG_SEVERITY.SYSLOG_API_SEVERITY_EMERG)
9433
9434         self.vapi.nat_set_timeouts(udp=300, tcp_established=7440,
9435                                    tcp_transitory=240, icmp=60)
9436
9437         interfaces = self.vapi.nat64_interface_dump()
9438         for intf in interfaces:
9439             self.vapi.nat64_add_del_interface(is_add=0, flags=intf.flags,
9440                                               sw_if_index=intf.sw_if_index)
9441
9442         bib = self.vapi.nat64_bib_dump(proto=255)
9443         for bibe in bib:
9444             if bibe.flags & self.config_flags.NAT_IS_STATIC:
9445                 self.vapi.nat64_add_del_static_bib(i_addr=bibe.i_addr,
9446                                                    o_addr=bibe.o_addr,
9447                                                    i_port=bibe.i_port,
9448                                                    o_port=bibe.o_port,
9449                                                    proto=bibe.proto,
9450                                                    vrf_id=bibe.vrf_id,
9451                                                    is_add=0)
9452
9453         adresses = self.vapi.nat64_pool_addr_dump()
9454         for addr in adresses:
9455             self.vapi.nat64_add_del_pool_addr_range(start_addr=addr.address,
9456                                                     end_addr=addr.address,
9457                                                     vrf_id=addr.vrf_id,
9458                                                     is_add=0)
9459
9460         prefixes = self.vapi.nat64_prefix_dump()
9461         for prefix in prefixes:
9462             self.vapi.nat64_add_del_prefix(prefix=str(prefix.prefix),
9463                                            vrf_id=prefix.vrf_id, is_add=0)
9464
9465         bibs = self.statistics.get_counter('/nat64/total-bibs')
9466         self.assertEqual(bibs[0][0], 0)
9467         sessions = self.statistics.get_counter('/nat64/total-sessions')
9468         self.assertEqual(sessions[0][0], 0)
9469
9470     def tearDown(self):
9471         super(TestNAT64, self).tearDown()
9472         if not self.vpp_dead:
9473             self.clear_nat64()
9474
9475     def show_commands_at_teardown(self):
9476         self.logger.info(self.vapi.cli("show nat64 pool"))
9477         self.logger.info(self.vapi.cli("show nat64 interfaces"))
9478         self.logger.info(self.vapi.cli("show nat64 prefix"))
9479         self.logger.info(self.vapi.cli("show nat64 bib all"))
9480         self.logger.info(self.vapi.cli("show nat64 session table all"))
9481
9482
9483 class TestNAT66(MethodHolder):
9484     """ NAT66 Test Cases """
9485
9486     @classmethod
9487     def setUpClass(cls):
9488         super(TestNAT66, cls).setUpClass()
9489
9490         cls.nat_addr = 'fd01:ff::2'
9491
9492         cls.create_pg_interfaces(range(2))
9493         cls.interfaces = list(cls.pg_interfaces)
9494
9495         for i in cls.interfaces:
9496             i.admin_up()
9497             i.config_ip6()
9498             i.configure_ipv6_neighbors()
9499
9500     @classmethod
9501     def tearDownClass(cls):
9502         super(TestNAT66, cls).tearDownClass()
9503
9504     def test_static(self):
9505         """ 1:1 NAT66 test """
9506         flags = self.config_flags.NAT_IS_INSIDE
9507         self.vapi.nat66_add_del_interface(is_add=1, flags=flags,
9508                                           sw_if_index=self.pg0.sw_if_index)
9509         self.vapi.nat66_add_del_interface(is_add=1,
9510                                           sw_if_index=self.pg1.sw_if_index)
9511         self.vapi.nat66_add_del_static_mapping(
9512             local_ip_address=self.pg0.remote_ip6,
9513             external_ip_address=self.nat_addr,
9514             is_add=1)
9515
9516         # in2out
9517         pkts = []
9518         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
9519              IPv6(src=self.pg0.remote_ip6, dst=self.pg1.remote_ip6) /
9520              TCP())
9521         pkts.append(p)
9522         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
9523              IPv6(src=self.pg0.remote_ip6, dst=self.pg1.remote_ip6) /
9524              UDP())
9525         pkts.append(p)
9526         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
9527              IPv6(src=self.pg0.remote_ip6, dst=self.pg1.remote_ip6) /
9528              ICMPv6EchoRequest())
9529         pkts.append(p)
9530         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
9531              IPv6(src=self.pg0.remote_ip6, dst=self.pg1.remote_ip6) /
9532              GRE() / IP() / TCP())
9533         pkts.append(p)
9534         self.pg0.add_stream(pkts)
9535         self.pg_enable_capture(self.pg_interfaces)
9536         self.pg_start()
9537         capture = self.pg1.get_capture(len(pkts))
9538
9539         for packet in capture:
9540             try:
9541                 self.assertEqual(packet[IPv6].src, self.nat_addr)
9542                 self.assertEqual(packet[IPv6].dst, self.pg1.remote_ip6)
9543                 self.assert_packet_checksums_valid(packet)
9544             except:
9545                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
9546                 raise
9547
9548         # out2in
9549         pkts = []
9550         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
9551              IPv6(src=self.pg1.remote_ip6, dst=self.nat_addr) /
9552              TCP())
9553         pkts.append(p)
9554         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
9555              IPv6(src=self.pg1.remote_ip6, dst=self.nat_addr) /
9556              UDP())
9557         pkts.append(p)
9558         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
9559              IPv6(src=self.pg1.remote_ip6, dst=self.nat_addr) /
9560              ICMPv6EchoReply())
9561         pkts.append(p)
9562         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
9563              IPv6(src=self.pg1.remote_ip6, dst=self.nat_addr) /
9564              GRE() / IP() / TCP())
9565         pkts.append(p)
9566         self.pg1.add_stream(pkts)
9567         self.pg_enable_capture(self.pg_interfaces)
9568         self.pg_start()
9569         capture = self.pg0.get_capture(len(pkts))
9570         for packet in capture:
9571             try:
9572                 self.assertEqual(packet[IPv6].src, self.pg1.remote_ip6)
9573                 self.assertEqual(packet[IPv6].dst, self.pg0.remote_ip6)
9574                 self.assert_packet_checksums_valid(packet)
9575             except:
9576                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
9577                 raise
9578
9579         sm = self.vapi.nat66_static_mapping_dump()
9580         self.assertEqual(len(sm), 1)
9581         self.assertEqual(sm[0].total_pkts, 8)
9582
9583     def test_check_no_translate(self):
9584         """ NAT66 translate only when egress interface is outside interface """
9585         flags = self.config_flags.NAT_IS_INSIDE
9586         self.vapi.nat66_add_del_interface(is_add=1, flags=flags,
9587                                           sw_if_index=self.pg0.sw_if_index)
9588         self.vapi.nat66_add_del_interface(is_add=1, flags=flags,
9589                                           sw_if_index=self.pg1.sw_if_index)
9590         self.vapi.nat66_add_del_static_mapping(
9591             local_ip_address=self.pg0.remote_ip6,
9592             external_ip_address=self.nat_addr,
9593             is_add=1)
9594
9595         # in2out
9596         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
9597              IPv6(src=self.pg0.remote_ip6, dst=self.pg1.remote_ip6) /
9598              UDP())
9599         self.pg0.add_stream([p])
9600         self.pg_enable_capture(self.pg_interfaces)
9601         self.pg_start()
9602         capture = self.pg1.get_capture(1)
9603         packet = capture[0]
9604         try:
9605             self.assertEqual(packet[IPv6].src, self.pg0.remote_ip6)
9606             self.assertEqual(packet[IPv6].dst, self.pg1.remote_ip6)
9607         except:
9608             self.logger.error(ppp("Unexpected or invalid packet:", packet))
9609             raise
9610
9611     def clear_nat66(self):
9612         """
9613         Clear NAT66 configuration.
9614         """
9615         interfaces = self.vapi.nat66_interface_dump()
9616         for intf in interfaces:
9617             self.vapi.nat66_add_del_interface(is_add=0, flags=intf.flags,
9618                                               sw_if_index=intf.sw_if_index)
9619
9620         static_mappings = self.vapi.nat66_static_mapping_dump()
9621         for sm in static_mappings:
9622             self.vapi.nat66_add_del_static_mapping(
9623                 local_ip_address=sm.local_ip_address,
9624                 external_ip_address=sm.external_ip_address, vrf_id=sm.vrf_id,
9625                 is_add=0)
9626
9627     def tearDown(self):
9628         super(TestNAT66, self).tearDown()
9629         self.clear_nat66()
9630
9631     def show_commands_at_teardown(self):
9632         self.logger.info(self.vapi.cli("show nat66 interfaces"))
9633         self.logger.info(self.vapi.cli("show nat66 static mappings"))
9634
9635
9636 if __name__ == '__main__':
9637     unittest.main(testRunner=VppTestRunner)