97f473c95fdf02c559e359e21be7242ab64c5ba5
[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     translation_buckets = 5
7218
7219     @classmethod
7220     def setUpConstants(cls):
7221         super(TestNAT44EndpointDependent3, cls).setUpConstants()
7222         cls.vpp_cmdline.extend([
7223             "nat", "{", "endpoint-dependent",
7224             "translation hash buckets %d" % cls.translation_buckets,
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         max_translations = 10 * self.translation_buckets
7293         pkts = []
7294         for i in range(0, max_translations - 1):
7295             p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
7296                  IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4, ttl=64) /
7297                  UDP(sport=7000+i, dport=80))
7298             pkts.append(p)
7299
7300         self.pg0.add_stream(pkts)
7301         self.pg_enable_capture(self.pg_interfaces)
7302         self.pg_start()
7303         self.pg1.get_capture(len(pkts))
7304         self.sleep(1.5, "wait for timeouts")
7305
7306         pkts = []
7307         for i in range(0, max_translations - 1):
7308             p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
7309                  IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4, ttl=64) /
7310                  ICMP(id=8000+i, type='echo-request'))
7311             pkts.append(p)
7312
7313         self.pg0.add_stream(pkts)
7314         self.pg_enable_capture(self.pg_interfaces)
7315         self.pg_start()
7316         self.pg1.get_capture(len(pkts))
7317
7318
7319 class TestNAT44Out2InDPO(MethodHolder):
7320     """ NAT44 Test Cases using out2in DPO """
7321
7322     @classmethod
7323     def setUpConstants(cls):
7324         super(TestNAT44Out2InDPO, cls).setUpConstants()
7325         cls.vpp_cmdline.extend(["nat", "{", "out2in dpo", "}"])
7326
7327     @classmethod
7328     def setUpClass(cls):
7329         super(TestNAT44Out2InDPO, cls).setUpClass()
7330         cls.vapi.cli("set log class nat level debug")
7331
7332         cls.tcp_port_in = 6303
7333         cls.tcp_port_out = 6303
7334         cls.udp_port_in = 6304
7335         cls.udp_port_out = 6304
7336         cls.icmp_id_in = 6305
7337         cls.icmp_id_out = 6305
7338         cls.nat_addr = '10.0.0.3'
7339         cls.dst_ip4 = '192.168.70.1'
7340
7341         cls.create_pg_interfaces(range(2))
7342
7343         cls.pg0.admin_up()
7344         cls.pg0.config_ip4()
7345         cls.pg0.resolve_arp()
7346
7347         cls.pg1.admin_up()
7348         cls.pg1.config_ip6()
7349         cls.pg1.resolve_ndp()
7350
7351         r1 = VppIpRoute(cls, "::", 0,
7352                         [VppRoutePath(cls.pg1.remote_ip6,
7353                                       cls.pg1.sw_if_index)],
7354                         register=False)
7355         r1.add_vpp_config()
7356
7357     @classmethod
7358     def tearDownClass(cls):
7359         super(TestNAT44Out2InDPO, cls).tearDownClass()
7360
7361     def configure_xlat(self):
7362         self.dst_ip6_pfx = '1:2:3::'
7363         self.dst_ip6_pfx_n = socket.inet_pton(socket.AF_INET6,
7364                                               self.dst_ip6_pfx)
7365         self.dst_ip6_pfx_len = 96
7366         self.src_ip6_pfx = '4:5:6::'
7367         self.src_ip6_pfx_n = socket.inet_pton(socket.AF_INET6,
7368                                               self.src_ip6_pfx)
7369         self.src_ip6_pfx_len = 96
7370         self.vapi.map_add_domain(self.dst_ip6_pfx_n, self.dst_ip6_pfx_len,
7371                                  self.src_ip6_pfx_n, self.src_ip6_pfx_len,
7372                                  '\x00\x00\x00\x00', 0)
7373
7374     @unittest.skip('Temporary disabled')
7375     def test_464xlat_ce(self):
7376         """ Test 464XLAT CE with NAT44 """
7377
7378         nat_config = self.vapi.nat_show_config()
7379         self.assertEqual(1, nat_config.out2in_dpo)
7380
7381         self.configure_xlat()
7382
7383         flags = self.config_flags.NAT_IS_INSIDE
7384         self.vapi.nat44_interface_add_del_feature(
7385             sw_if_index=self.pg0.sw_if_index,
7386             flags=flags, is_add=1)
7387         self.vapi.nat44_add_del_address_range(first_ip_address=self.nat_addr_n,
7388                                               last_ip_address=self.nat_addr_n,
7389                                               vrf_id=0xFFFFFFFF, is_add=1)
7390
7391         out_src_ip6 = self.compose_ip6(self.dst_ip4, self.dst_ip6_pfx,
7392                                        self.dst_ip6_pfx_len)
7393         out_dst_ip6 = self.compose_ip6(self.nat_addr, self.src_ip6_pfx,
7394                                        self.src_ip6_pfx_len)
7395
7396         try:
7397             pkts = self.create_stream_in(self.pg0, self.pg1, self.dst_ip4)
7398             self.pg0.add_stream(pkts)
7399             self.pg_enable_capture(self.pg_interfaces)
7400             self.pg_start()
7401             capture = self.pg1.get_capture(len(pkts))
7402             self.verify_capture_out_ip6(capture, nat_ip=out_dst_ip6,
7403                                         dst_ip=out_src_ip6)
7404
7405             pkts = self.create_stream_out_ip6(self.pg1, out_src_ip6,
7406                                               out_dst_ip6)
7407             self.pg1.add_stream(pkts)
7408             self.pg_enable_capture(self.pg_interfaces)
7409             self.pg_start()
7410             capture = self.pg0.get_capture(len(pkts))
7411             self.verify_capture_in(capture, self.pg0)
7412         finally:
7413             self.vapi.nat44_interface_add_del_feature(
7414                 sw_if_index=self.pg0.sw_if_index,
7415                 flags=flags)
7416             self.vapi.nat44_add_del_address_range(
7417                 first_ip_address=self.nat_addr_n,
7418                 last_ip_address=self.nat_addr_n,
7419                 vrf_id=0xFFFFFFFF)
7420
7421     @unittest.skip('Temporary disabled')
7422     def test_464xlat_ce_no_nat(self):
7423         """ Test 464XLAT CE without NAT44 """
7424
7425         self.configure_xlat()
7426
7427         out_src_ip6 = self.compose_ip6(self.dst_ip4, self.dst_ip6_pfx,
7428                                        self.dst_ip6_pfx_len)
7429         out_dst_ip6 = self.compose_ip6(self.pg0.remote_ip4, self.src_ip6_pfx,
7430                                        self.src_ip6_pfx_len)
7431
7432         pkts = self.create_stream_in(self.pg0, self.pg1, self.dst_ip4)
7433         self.pg0.add_stream(pkts)
7434         self.pg_enable_capture(self.pg_interfaces)
7435         self.pg_start()
7436         capture = self.pg1.get_capture(len(pkts))
7437         self.verify_capture_out_ip6(capture, dst_ip=out_src_ip6,
7438                                     nat_ip=out_dst_ip6, same_port=True)
7439
7440         pkts = self.create_stream_out_ip6(self.pg1, out_src_ip6, out_dst_ip6)
7441         self.pg1.add_stream(pkts)
7442         self.pg_enable_capture(self.pg_interfaces)
7443         self.pg_start()
7444         capture = self.pg0.get_capture(len(pkts))
7445         self.verify_capture_in(capture, self.pg0)
7446
7447
7448 class TestDeterministicNAT(MethodHolder):
7449     """ Deterministic NAT Test Cases """
7450
7451     @classmethod
7452     def setUpConstants(cls):
7453         super(TestDeterministicNAT, cls).setUpConstants()
7454         cls.vpp_cmdline.extend(["nat", "{", "deterministic", "}"])
7455
7456     @classmethod
7457     def setUpClass(cls):
7458         super(TestDeterministicNAT, cls).setUpClass()
7459         cls.vapi.cli("set log class nat level debug")
7460
7461         cls.tcp_port_in = 6303
7462         cls.tcp_external_port = 6303
7463         cls.udp_port_in = 6304
7464         cls.udp_external_port = 6304
7465         cls.icmp_id_in = 6305
7466         cls.nat_addr = '10.0.0.3'
7467
7468         cls.create_pg_interfaces(range(3))
7469         cls.interfaces = list(cls.pg_interfaces)
7470
7471         for i in cls.interfaces:
7472             i.admin_up()
7473             i.config_ip4()
7474             i.resolve_arp()
7475
7476         cls.pg0.generate_remote_hosts(2)
7477         cls.pg0.configure_ipv4_neighbors()
7478
7479     @classmethod
7480     def tearDownClass(cls):
7481         super(TestDeterministicNAT, cls).tearDownClass()
7482
7483     def create_stream_in(self, in_if, out_if, ttl=64):
7484         """
7485         Create packet stream for inside network
7486
7487         :param in_if: Inside interface
7488         :param out_if: Outside interface
7489         :param ttl: TTL of generated packets
7490         """
7491         pkts = []
7492         # TCP
7493         p = (Ether(dst=in_if.local_mac, src=in_if.remote_mac) /
7494              IP(src=in_if.remote_ip4, dst=out_if.remote_ip4, ttl=ttl) /
7495              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port))
7496         pkts.append(p)
7497
7498         # UDP
7499         p = (Ether(dst=in_if.local_mac, src=in_if.remote_mac) /
7500              IP(src=in_if.remote_ip4, dst=out_if.remote_ip4, ttl=ttl) /
7501              UDP(sport=self.udp_port_in, dport=self.udp_external_port))
7502         pkts.append(p)
7503
7504         # ICMP
7505         p = (Ether(dst=in_if.local_mac, src=in_if.remote_mac) /
7506              IP(src=in_if.remote_ip4, dst=out_if.remote_ip4, ttl=ttl) /
7507              ICMP(id=self.icmp_id_in, type='echo-request'))
7508         pkts.append(p)
7509
7510         return pkts
7511
7512     def create_stream_out(self, out_if, dst_ip=None, ttl=64):
7513         """
7514         Create packet stream for outside network
7515
7516         :param out_if: Outside interface
7517         :param dst_ip: Destination IP address (Default use global NAT address)
7518         :param ttl: TTL of generated packets
7519         """
7520         if dst_ip is None:
7521             dst_ip = self.nat_addr
7522         pkts = []
7523         # TCP
7524         p = (Ether(dst=out_if.local_mac, src=out_if.remote_mac) /
7525              IP(src=out_if.remote_ip4, dst=dst_ip, ttl=ttl) /
7526              TCP(dport=self.tcp_port_out, sport=self.tcp_external_port))
7527         pkts.append(p)
7528
7529         # UDP
7530         p = (Ether(dst=out_if.local_mac, src=out_if.remote_mac) /
7531              IP(src=out_if.remote_ip4, dst=dst_ip, ttl=ttl) /
7532              UDP(dport=self.udp_port_out, sport=self.udp_external_port))
7533         pkts.append(p)
7534
7535         # ICMP
7536         p = (Ether(dst=out_if.local_mac, src=out_if.remote_mac) /
7537              IP(src=out_if.remote_ip4, dst=dst_ip, ttl=ttl) /
7538              ICMP(id=self.icmp_external_id, type='echo-reply'))
7539         pkts.append(p)
7540
7541         return pkts
7542
7543     def verify_capture_out(self, capture, nat_ip=None):
7544         """
7545         Verify captured packets on outside network
7546
7547         :param capture: Captured packets
7548         :param nat_ip: Translated IP address (Default use global NAT address)
7549         :param same_port: Source port number is not translated (Default False)
7550         """
7551         if nat_ip is None:
7552             nat_ip = self.nat_addr
7553         for packet in capture:
7554             try:
7555                 self.assertEqual(packet[IP].src, nat_ip)
7556                 if packet.haslayer(TCP):
7557                     self.tcp_port_out = packet[TCP].sport
7558                 elif packet.haslayer(UDP):
7559                     self.udp_port_out = packet[UDP].sport
7560                 else:
7561                     self.icmp_external_id = packet[ICMP].id
7562             except:
7563                 self.logger.error(ppp("Unexpected or invalid packet "
7564                                       "(outside network):", packet))
7565                 raise
7566
7567     def test_deterministic_mode(self):
7568         """ NAT plugin run deterministic mode """
7569         in_addr = '172.16.255.0'
7570         out_addr = '172.17.255.50'
7571         in_addr_t = '172.16.255.20'
7572         in_plen = 24
7573         out_plen = 32
7574
7575         nat_config = self.vapi.nat_show_config()
7576         self.assertEqual(1, nat_config.deterministic)
7577
7578         self.vapi.nat_det_add_del_map(is_add=1, in_addr=in_addr,
7579                                       in_plen=in_plen, out_addr=out_addr,
7580                                       out_plen=out_plen)
7581
7582         rep1 = self.vapi.nat_det_forward(in_addr_t)
7583         self.assertEqual(str(rep1.out_addr), out_addr)
7584         rep2 = self.vapi.nat_det_reverse(rep1.out_port_hi, out_addr)
7585
7586         self.assertEqual(str(rep2.in_addr), in_addr_t)
7587
7588         deterministic_mappings = self.vapi.nat_det_map_dump()
7589         self.assertEqual(len(deterministic_mappings), 1)
7590         dsm = deterministic_mappings[0]
7591         self.assertEqual(in_addr, str(dsm.in_addr))
7592         self.assertEqual(in_plen, dsm.in_plen)
7593         self.assertEqual(out_addr, str(dsm.out_addr))
7594         self.assertEqual(out_plen, dsm.out_plen)
7595
7596         self.clear_nat_det()
7597         deterministic_mappings = self.vapi.nat_det_map_dump()
7598         self.assertEqual(len(deterministic_mappings), 0)
7599
7600     def test_set_timeouts(self):
7601         """ Set deterministic NAT timeouts """
7602         timeouts_before = self.vapi.nat_get_timeouts()
7603
7604         self.vapi.nat_set_timeouts(
7605             udp=timeouts_before.udp + 10,
7606             tcp_established=timeouts_before.tcp_established + 10,
7607             tcp_transitory=timeouts_before.tcp_transitory + 10,
7608             icmp=timeouts_before.icmp + 10)
7609
7610         timeouts_after = self.vapi.nat_get_timeouts()
7611
7612         self.assertNotEqual(timeouts_before.udp, timeouts_after.udp)
7613         self.assertNotEqual(timeouts_before.icmp, timeouts_after.icmp)
7614         self.assertNotEqual(timeouts_before.tcp_established,
7615                             timeouts_after.tcp_established)
7616         self.assertNotEqual(timeouts_before.tcp_transitory,
7617                             timeouts_after.tcp_transitory)
7618
7619     def test_det_in(self):
7620         """ Deterministic NAT translation test (TCP, UDP, ICMP) """
7621
7622         nat_ip = "10.0.0.10"
7623
7624         self.vapi.nat_det_add_del_map(is_add=1, in_addr=self.pg0.remote_ip4,
7625                                       in_plen=32,
7626                                       out_addr=socket.inet_aton(nat_ip),
7627                                       out_plen=32)
7628
7629         flags = self.config_flags.NAT_IS_INSIDE
7630         self.vapi.nat44_interface_add_del_feature(
7631             sw_if_index=self.pg0.sw_if_index,
7632             flags=flags, is_add=1)
7633         self.vapi.nat44_interface_add_del_feature(
7634             sw_if_index=self.pg1.sw_if_index,
7635             is_add=1)
7636
7637         # in2out
7638         pkts = self.create_stream_in(self.pg0, self.pg1)
7639         self.pg0.add_stream(pkts)
7640         self.pg_enable_capture(self.pg_interfaces)
7641         self.pg_start()
7642         capture = self.pg1.get_capture(len(pkts))
7643         self.verify_capture_out(capture, nat_ip)
7644
7645         # out2in
7646         pkts = self.create_stream_out(self.pg1, nat_ip)
7647         self.pg1.add_stream(pkts)
7648         self.pg_enable_capture(self.pg_interfaces)
7649         self.pg_start()
7650         capture = self.pg0.get_capture(len(pkts))
7651         self.verify_capture_in(capture, self.pg0)
7652
7653         # session dump test
7654         sessions = self.vapi.nat_det_session_dump(self.pg0.remote_ip4)
7655         self.assertEqual(len(sessions), 3)
7656
7657         # TCP session
7658         s = sessions[0]
7659         self.assertEqual(str(s.ext_addr), self.pg1.remote_ip4)
7660         self.assertEqual(s.in_port, self.tcp_port_in)
7661         self.assertEqual(s.out_port, self.tcp_port_out)
7662         self.assertEqual(s.ext_port, self.tcp_external_port)
7663
7664         # UDP session
7665         s = sessions[1]
7666         self.assertEqual(str(s.ext_addr), self.pg1.remote_ip4)
7667         self.assertEqual(s.in_port, self.udp_port_in)
7668         self.assertEqual(s.out_port, self.udp_port_out)
7669         self.assertEqual(s.ext_port, self.udp_external_port)
7670
7671         # ICMP session
7672         s = sessions[2]
7673         self.assertEqual(str(s.ext_addr), self.pg1.remote_ip4)
7674         self.assertEqual(s.in_port, self.icmp_id_in)
7675         self.assertEqual(s.out_port, self.icmp_external_id)
7676
7677     def test_multiple_users(self):
7678         """ Deterministic NAT multiple users """
7679
7680         nat_ip = "10.0.0.10"
7681         port_in = 80
7682         external_port = 6303
7683
7684         host0 = self.pg0.remote_hosts[0]
7685         host1 = self.pg0.remote_hosts[1]
7686
7687         self.vapi.nat_det_add_del_map(is_add=1, in_addr=host0.ip4, in_plen=24,
7688                                       out_addr=socket.inet_aton(nat_ip),
7689                                       out_plen=32)
7690         flags = self.config_flags.NAT_IS_INSIDE
7691         self.vapi.nat44_interface_add_del_feature(
7692             sw_if_index=self.pg0.sw_if_index,
7693             flags=flags, is_add=1)
7694         self.vapi.nat44_interface_add_del_feature(
7695             sw_if_index=self.pg1.sw_if_index,
7696             is_add=1)
7697
7698         # host0 to out
7699         p = (Ether(src=host0.mac, dst=self.pg0.local_mac) /
7700              IP(src=host0.ip4, dst=self.pg1.remote_ip4) /
7701              TCP(sport=port_in, dport=external_port))
7702         self.pg0.add_stream(p)
7703         self.pg_enable_capture(self.pg_interfaces)
7704         self.pg_start()
7705         capture = self.pg1.get_capture(1)
7706         p = capture[0]
7707         try:
7708             ip = p[IP]
7709             tcp = p[TCP]
7710             self.assertEqual(ip.src, nat_ip)
7711             self.assertEqual(ip.dst, self.pg1.remote_ip4)
7712             self.assertEqual(tcp.dport, external_port)
7713             port_out0 = tcp.sport
7714         except:
7715             self.logger.error(ppp("Unexpected or invalid packet:", p))
7716             raise
7717
7718         # host1 to out
7719         p = (Ether(src=host1.mac, dst=self.pg0.local_mac) /
7720              IP(src=host1.ip4, dst=self.pg1.remote_ip4) /
7721              TCP(sport=port_in, dport=external_port))
7722         self.pg0.add_stream(p)
7723         self.pg_enable_capture(self.pg_interfaces)
7724         self.pg_start()
7725         capture = self.pg1.get_capture(1)
7726         p = capture[0]
7727         try:
7728             ip = p[IP]
7729             tcp = p[TCP]
7730             self.assertEqual(ip.src, nat_ip)
7731             self.assertEqual(ip.dst, self.pg1.remote_ip4)
7732             self.assertEqual(tcp.dport, external_port)
7733             port_out1 = tcp.sport
7734         except:
7735             self.logger.error(ppp("Unexpected or invalid packet:", p))
7736             raise
7737
7738         dms = self.vapi.nat_det_map_dump()
7739         self.assertEqual(1, len(dms))
7740         self.assertEqual(2, dms[0].ses_num)
7741
7742         # out to host0
7743         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
7744              IP(src=self.pg1.remote_ip4, dst=nat_ip) /
7745              TCP(sport=external_port, dport=port_out0))
7746         self.pg1.add_stream(p)
7747         self.pg_enable_capture(self.pg_interfaces)
7748         self.pg_start()
7749         capture = self.pg0.get_capture(1)
7750         p = capture[0]
7751         try:
7752             ip = p[IP]
7753             tcp = p[TCP]
7754             self.assertEqual(ip.src, self.pg1.remote_ip4)
7755             self.assertEqual(ip.dst, host0.ip4)
7756             self.assertEqual(tcp.dport, port_in)
7757             self.assertEqual(tcp.sport, external_port)
7758         except:
7759             self.logger.error(ppp("Unexpected or invalid packet:", p))
7760             raise
7761
7762         # out to host1
7763         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
7764              IP(src=self.pg1.remote_ip4, dst=nat_ip) /
7765              TCP(sport=external_port, dport=port_out1))
7766         self.pg1.add_stream(p)
7767         self.pg_enable_capture(self.pg_interfaces)
7768         self.pg_start()
7769         capture = self.pg0.get_capture(1)
7770         p = capture[0]
7771         try:
7772             ip = p[IP]
7773             tcp = p[TCP]
7774             self.assertEqual(ip.src, self.pg1.remote_ip4)
7775             self.assertEqual(ip.dst, host1.ip4)
7776             self.assertEqual(tcp.dport, port_in)
7777             self.assertEqual(tcp.sport, external_port)
7778         except:
7779             self.logger.error(ppp("Unexpected or invalid packet", p))
7780             raise
7781
7782         # session close api test
7783         self.vapi.nat_det_close_session_out(socket.inet_aton(nat_ip),
7784                                             port_out1,
7785                                             self.pg1.remote_ip4,
7786                                             external_port)
7787         dms = self.vapi.nat_det_map_dump()
7788         self.assertEqual(dms[0].ses_num, 1)
7789
7790         self.vapi.nat_det_close_session_in(host0.ip4,
7791                                            port_in,
7792                                            self.pg1.remote_ip4,
7793                                            external_port)
7794         dms = self.vapi.nat_det_map_dump()
7795         self.assertEqual(dms[0].ses_num, 0)
7796
7797     def test_tcp_session_close_detection_in(self):
7798         """ Deterministic NAT TCP session close from inside network """
7799         self.vapi.nat_det_add_del_map(is_add=1, in_addr=self.pg0.remote_ip4,
7800                                       in_plen=32,
7801                                       out_addr=socket.inet_aton(self.nat_addr),
7802                                       out_plen=32)
7803         flags = self.config_flags.NAT_IS_INSIDE
7804         self.vapi.nat44_interface_add_del_feature(
7805             sw_if_index=self.pg0.sw_if_index,
7806             flags=flags, is_add=1)
7807         self.vapi.nat44_interface_add_del_feature(
7808             sw_if_index=self.pg1.sw_if_index,
7809             is_add=1)
7810
7811         self.initiate_tcp_session(self.pg0, self.pg1)
7812
7813         # close the session from inside
7814         try:
7815             # FIN packet in -> out
7816             p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
7817                  IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
7818                  TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
7819                      flags="F"))
7820             self.pg0.add_stream(p)
7821             self.pg_enable_capture(self.pg_interfaces)
7822             self.pg_start()
7823             self.pg1.get_capture(1)
7824
7825             pkts = []
7826
7827             # ACK packet out -> in
7828             p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
7829                  IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
7830                  TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
7831                      flags="A"))
7832             pkts.append(p)
7833
7834             # FIN packet out -> in
7835             p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
7836                  IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
7837                  TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
7838                      flags="F"))
7839             pkts.append(p)
7840
7841             self.pg1.add_stream(pkts)
7842             self.pg_enable_capture(self.pg_interfaces)
7843             self.pg_start()
7844             self.pg0.get_capture(2)
7845
7846             # ACK packet in -> out
7847             p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
7848                  IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
7849                  TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
7850                      flags="A"))
7851             self.pg0.add_stream(p)
7852             self.pg_enable_capture(self.pg_interfaces)
7853             self.pg_start()
7854             self.pg1.get_capture(1)
7855
7856             # Check if deterministic NAT44 closed the session
7857             dms = self.vapi.nat_det_map_dump()
7858             self.assertEqual(0, dms[0].ses_num)
7859         except:
7860             self.logger.error("TCP session termination failed")
7861             raise
7862
7863     def test_tcp_session_close_detection_out(self):
7864         """ Deterministic NAT TCP session close from outside network """
7865         self.vapi.nat_det_add_del_map(is_add=1, in_addr=self.pg0.remote_ip4,
7866                                       in_plen=32,
7867                                       out_addr=socket.inet_aton(self.nat_addr),
7868                                       out_plen=32)
7869         flags = self.config_flags.NAT_IS_INSIDE
7870         self.vapi.nat44_interface_add_del_feature(
7871             sw_if_index=self.pg0.sw_if_index,
7872             flags=flags, is_add=1)
7873         self.vapi.nat44_interface_add_del_feature(
7874             sw_if_index=self.pg1.sw_if_index,
7875             is_add=1)
7876
7877         self.initiate_tcp_session(self.pg0, self.pg1)
7878
7879         # close the session from outside
7880         try:
7881             # FIN packet out -> in
7882             p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
7883                  IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
7884                  TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
7885                      flags="F"))
7886             self.pg1.add_stream(p)
7887             self.pg_enable_capture(self.pg_interfaces)
7888             self.pg_start()
7889             self.pg0.get_capture(1)
7890
7891             pkts = []
7892
7893             # ACK packet in -> out
7894             p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
7895                  IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
7896                  TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
7897                      flags="A"))
7898             pkts.append(p)
7899
7900             # ACK packet in -> out
7901             p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
7902                  IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
7903                  TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
7904                      flags="F"))
7905             pkts.append(p)
7906
7907             self.pg0.add_stream(pkts)
7908             self.pg_enable_capture(self.pg_interfaces)
7909             self.pg_start()
7910             self.pg1.get_capture(2)
7911
7912             # ACK packet out -> in
7913             p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
7914                  IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
7915                  TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
7916                      flags="A"))
7917             self.pg1.add_stream(p)
7918             self.pg_enable_capture(self.pg_interfaces)
7919             self.pg_start()
7920             self.pg0.get_capture(1)
7921
7922             # Check if deterministic NAT44 closed the session
7923             dms = self.vapi.nat_det_map_dump()
7924             self.assertEqual(0, dms[0].ses_num)
7925         except:
7926             self.logger.error("TCP session termination failed")
7927             raise
7928
7929     @unittest.skipUnless(running_extended_tests, "part of extended tests")
7930     def test_session_timeout(self):
7931         """ Deterministic NAT session timeouts """
7932         self.vapi.nat_det_add_del_map(is_add=1, in_addr=self.pg0.remote_ip4,
7933                                       in_plen=32,
7934                                       out_addr=socket.inet_aton(self.nat_addr),
7935                                       out_plen=32)
7936         flags = self.config_flags.NAT_IS_INSIDE
7937         self.vapi.nat44_interface_add_del_feature(
7938             sw_if_index=self.pg0.sw_if_index,
7939             flags=flags, is_add=1)
7940         self.vapi.nat44_interface_add_del_feature(
7941             sw_if_index=self.pg1.sw_if_index,
7942             is_add=1)
7943
7944         self.initiate_tcp_session(self.pg0, self.pg1)
7945         self.vapi.nat_set_timeouts(udp=5, tcp_established=5, tcp_transitory=5,
7946                                    icmp=5)
7947         pkts = self.create_stream_in(self.pg0, self.pg1)
7948         self.pg0.add_stream(pkts)
7949         self.pg_enable_capture(self.pg_interfaces)
7950         self.pg_start()
7951         capture = self.pg1.get_capture(len(pkts))
7952         sleep(15)
7953
7954         dms = self.vapi.nat_det_map_dump()
7955         self.assertEqual(0, dms[0].ses_num)
7956
7957     @unittest.skipUnless(running_extended_tests, "part of extended tests")
7958     def test_session_limit_per_user(self):
7959         """ Deterministic NAT maximum sessions per user limit """
7960         self.vapi.nat_det_add_del_map(is_add=1, in_addr=self.pg0.remote_ip4,
7961                                       in_plen=32,
7962                                       out_addr=socket.inet_aton(self.nat_addr),
7963                                       out_plen=32)
7964         flags = self.config_flags.NAT_IS_INSIDE
7965         self.vapi.nat44_interface_add_del_feature(
7966             sw_if_index=self.pg0.sw_if_index,
7967             flags=flags, is_add=1)
7968         self.vapi.nat44_interface_add_del_feature(
7969             sw_if_index=self.pg1.sw_if_index,
7970             is_add=1)
7971         self.vapi.set_ipfix_exporter(collector_address=self.pg2.remote_ip4,
7972                                      src_address=self.pg2.local_ip4,
7973                                      path_mtu=512,
7974                                      template_interval=10)
7975         self.vapi.nat_ipfix_enable_disable(domain_id=1, src_port=4739,
7976                                            enable=1)
7977
7978         pkts = []
7979         for port in range(1025, 2025):
7980             p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
7981                  IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
7982                  UDP(sport=port, dport=port))
7983             pkts.append(p)
7984
7985         self.pg0.add_stream(pkts)
7986         self.pg_enable_capture(self.pg_interfaces)
7987         self.pg_start()
7988         capture = self.pg1.get_capture(len(pkts))
7989
7990         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
7991              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
7992              UDP(sport=3001, dport=3002))
7993         self.pg0.add_stream(p)
7994         self.pg_enable_capture(self.pg_interfaces)
7995         self.pg_start()
7996         capture = self.pg1.assert_nothing_captured()
7997
7998         # verify ICMP error packet
7999         capture = self.pg0.get_capture(1)
8000         p = capture[0]
8001         self.assertTrue(p.haslayer(ICMP))
8002         icmp = p[ICMP]
8003         self.assertEqual(icmp.type, 3)
8004         self.assertEqual(icmp.code, 1)
8005         self.assertTrue(icmp.haslayer(IPerror))
8006         inner_ip = icmp[IPerror]
8007         self.assertEqual(inner_ip[UDPerror].sport, 3001)
8008         self.assertEqual(inner_ip[UDPerror].dport, 3002)
8009
8010         dms = self.vapi.nat_det_map_dump()
8011
8012         self.assertEqual(1000, dms[0].ses_num)
8013
8014         # verify IPFIX logging
8015         self.vapi.ipfix_flush()
8016         sleep(1)
8017         capture = self.pg2.get_capture(2)
8018         ipfix = IPFIXDecoder()
8019         # first load template
8020         for p in capture:
8021             self.assertTrue(p.haslayer(IPFIX))
8022             if p.haslayer(Template):
8023                 ipfix.add_template(p.getlayer(Template))
8024         # verify events in data set
8025         for p in capture:
8026             if p.haslayer(Data):
8027                 data = ipfix.decode_data_set(p.getlayer(Set))
8028                 self.verify_ipfix_max_entries_per_user(data,
8029                                                        1000,
8030                                                        self.pg0.remote_ip4)
8031
8032     def clear_nat_det(self):
8033         """
8034         Clear deterministic NAT configuration.
8035         """
8036         self.vapi.nat_ipfix_enable_disable(domain_id=1, src_port=4739,
8037                                            enable=0)
8038         self.vapi.nat_set_timeouts(udp=300, tcp_established=7440,
8039                                    tcp_transitory=240, icmp=60)
8040         deterministic_mappings = self.vapi.nat_det_map_dump()
8041         for dsm in deterministic_mappings:
8042             self.vapi.nat_det_add_del_map(is_add=0, in_addr=dsm.in_addr,
8043                                           in_plen=dsm.in_plen,
8044                                           out_addr=dsm.out_addr,
8045                                           out_plen=dsm.out_plen)
8046
8047         interfaces = self.vapi.nat44_interface_dump()
8048         for intf in interfaces:
8049             self.vapi.nat44_interface_add_del_feature(
8050                 sw_if_index=intf.sw_if_index,
8051                 flags=intf.flags)
8052
8053     def tearDown(self):
8054         super(TestDeterministicNAT, self).tearDown()
8055         if not self.vpp_dead:
8056             self.clear_nat_det()
8057
8058     def show_commands_at_teardown(self):
8059         self.logger.info(self.vapi.cli("show nat44 interfaces"))
8060         self.logger.info(self.vapi.cli("show nat timeouts"))
8061         self.logger.info(
8062             self.vapi.cli("show nat44 deterministic mappings"))
8063         self.logger.info(
8064             self.vapi.cli("show nat44 deterministic sessions"))
8065
8066
8067 class TestNAT64(MethodHolder):
8068     """ NAT64 Test Cases """
8069
8070     @classmethod
8071     def setUpConstants(cls):
8072         super(TestNAT64, cls).setUpConstants()
8073         cls.vpp_cmdline.extend(["nat", "{", "nat64 bib hash buckets 128",
8074                                 "nat64 st hash buckets 256", "}"])
8075
8076     @classmethod
8077     def setUpClass(cls):
8078         super(TestNAT64, cls).setUpClass()
8079
8080         cls.tcp_port_in = 6303
8081         cls.tcp_port_out = 6303
8082         cls.udp_port_in = 6304
8083         cls.udp_port_out = 6304
8084         cls.icmp_id_in = 6305
8085         cls.icmp_id_out = 6305
8086         cls.tcp_external_port = 80
8087         cls.nat_addr = '10.0.0.3'
8088         cls.nat_addr_n = socket.inet_pton(socket.AF_INET, cls.nat_addr)
8089         cls.vrf1_id = 10
8090         cls.vrf1_nat_addr = '10.0.10.3'
8091         cls.ipfix_src_port = 4739
8092         cls.ipfix_domain_id = 1
8093
8094         cls.create_pg_interfaces(range(6))
8095         cls.ip6_interfaces = list(cls.pg_interfaces[0:1])
8096         cls.ip6_interfaces.append(cls.pg_interfaces[2])
8097         cls.ip4_interfaces = list(cls.pg_interfaces[1:2])
8098
8099         cls.vapi.ip_table_add_del(is_add=1,
8100                                   table={'table_id': cls.vrf1_id,
8101                                          'is_ip6': 1})
8102
8103         cls.pg_interfaces[2].set_table_ip6(cls.vrf1_id)
8104
8105         cls.pg0.generate_remote_hosts(2)
8106
8107         for i in cls.ip6_interfaces:
8108             i.admin_up()
8109             i.config_ip6()
8110             i.configure_ipv6_neighbors()
8111
8112         for i in cls.ip4_interfaces:
8113             i.admin_up()
8114             i.config_ip4()
8115             i.resolve_arp()
8116
8117         cls.pg3.admin_up()
8118         cls.pg3.config_ip4()
8119         cls.pg3.resolve_arp()
8120         cls.pg3.config_ip6()
8121         cls.pg3.configure_ipv6_neighbors()
8122
8123         cls.pg5.admin_up()
8124         cls.pg5.config_ip6()
8125
8126     @classmethod
8127     def tearDownClass(cls):
8128         super(TestNAT64, cls).tearDownClass()
8129
8130     def test_nat64_inside_interface_handles_neighbor_advertisement(self):
8131         """ NAT64 inside interface handles Neighbor Advertisement """
8132
8133         flags = self.config_flags.NAT_IS_INSIDE
8134         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
8135                                           sw_if_index=self.pg5.sw_if_index)
8136
8137         # Try to send ping
8138         ping = (Ether(dst=self.pg5.local_mac, src=self.pg5.remote_mac) /
8139                 IPv6(src=self.pg5.remote_ip6, dst=self.pg5.local_ip6) /
8140                 ICMPv6EchoRequest())
8141         pkts = [ping]
8142         self.pg5.add_stream(pkts)
8143         self.pg_enable_capture(self.pg_interfaces)
8144         self.pg_start()
8145
8146         # Wait for Neighbor Solicitation
8147         capture = self.pg5.get_capture(len(pkts))
8148         packet = capture[0]
8149         try:
8150             self.assertEqual(packet[IPv6].src, self.pg5.local_ip6)
8151             self.assertEqual(packet.haslayer(ICMPv6ND_NS), 1)
8152             tgt = packet[ICMPv6ND_NS].tgt
8153         except:
8154             self.logger.error(ppp("Unexpected or invalid packet:", packet))
8155             raise
8156
8157         # Send Neighbor Advertisement
8158         p = (Ether(dst=self.pg5.local_mac, src=self.pg5.remote_mac) /
8159              IPv6(src=self.pg5.remote_ip6, dst=self.pg5.local_ip6) /
8160              ICMPv6ND_NA(tgt=tgt) /
8161              ICMPv6NDOptDstLLAddr(lladdr=self.pg5.remote_mac))
8162         pkts = [p]
8163         self.pg5.add_stream(pkts)
8164         self.pg_enable_capture(self.pg_interfaces)
8165         self.pg_start()
8166
8167         # Try to send ping again
8168         pkts = [ping]
8169         self.pg5.add_stream(pkts)
8170         self.pg_enable_capture(self.pg_interfaces)
8171         self.pg_start()
8172
8173         # Wait for ping reply
8174         capture = self.pg5.get_capture(len(pkts))
8175         packet = capture[0]
8176         try:
8177             self.assertEqual(packet[IPv6].src, self.pg5.local_ip6)
8178             self.assertEqual(packet[IPv6].dst, self.pg5.remote_ip6)
8179             self.assertEqual(packet.haslayer(ICMPv6EchoReply), 1)
8180         except:
8181             self.logger.error(ppp("Unexpected or invalid packet:", packet))
8182             raise
8183
8184     def test_pool(self):
8185         """ Add/delete address to NAT64 pool """
8186         nat_addr = '1.2.3.4'
8187
8188         self.vapi.nat64_add_del_pool_addr_range(start_addr=nat_addr,
8189                                                 end_addr=nat_addr,
8190                                                 vrf_id=0xFFFFFFFF, is_add=1)
8191
8192         addresses = self.vapi.nat64_pool_addr_dump()
8193         self.assertEqual(len(addresses), 1)
8194         self.assertEqual(str(addresses[0].address), nat_addr)
8195
8196         self.vapi.nat64_add_del_pool_addr_range(start_addr=nat_addr,
8197                                                 end_addr=nat_addr,
8198                                                 vrf_id=0xFFFFFFFF, is_add=0)
8199
8200         addresses = self.vapi.nat64_pool_addr_dump()
8201         self.assertEqual(len(addresses), 0)
8202
8203     def test_interface(self):
8204         """ Enable/disable NAT64 feature on the interface """
8205         flags = self.config_flags.NAT_IS_INSIDE
8206         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
8207                                           sw_if_index=self.pg0.sw_if_index)
8208         self.vapi.nat64_add_del_interface(is_add=1, flags=0,
8209                                           sw_if_index=self.pg1.sw_if_index)
8210
8211         interfaces = self.vapi.nat64_interface_dump()
8212         self.assertEqual(len(interfaces), 2)
8213         pg0_found = False
8214         pg1_found = False
8215         for intf in interfaces:
8216             if intf.sw_if_index == self.pg0.sw_if_index:
8217                 self.assertEqual(intf.flags, self.config_flags.NAT_IS_INSIDE)
8218                 pg0_found = True
8219             elif intf.sw_if_index == self.pg1.sw_if_index:
8220                 self.assertEqual(intf.flags, self.config_flags.NAT_IS_OUTSIDE)
8221                 pg1_found = True
8222         self.assertTrue(pg0_found)
8223         self.assertTrue(pg1_found)
8224
8225         features = self.vapi.cli("show interface features pg0")
8226         self.assertIn('nat64-in2out', features)
8227         features = self.vapi.cli("show interface features pg1")
8228         self.assertIn('nat64-out2in', features)
8229
8230         self.vapi.nat64_add_del_interface(is_add=0, flags=flags,
8231                                           sw_if_index=self.pg0.sw_if_index)
8232         self.vapi.nat64_add_del_interface(is_add=0, flags=flags,
8233                                           sw_if_index=self.pg1.sw_if_index)
8234
8235         interfaces = self.vapi.nat64_interface_dump()
8236         self.assertEqual(len(interfaces), 0)
8237
8238     def test_static_bib(self):
8239         """ Add/delete static BIB entry """
8240         in_addr = '2001:db8:85a3::8a2e:370:7334'
8241         out_addr = '10.1.1.3'
8242         in_port = 1234
8243         out_port = 5678
8244         proto = IP_PROTOS.tcp
8245
8246         self.vapi.nat64_add_del_static_bib(i_addr=in_addr, o_addr=out_addr,
8247                                            i_port=in_port, o_port=out_port,
8248                                            proto=proto, vrf_id=0, is_add=1)
8249         bib = self.vapi.nat64_bib_dump(proto=IP_PROTOS.tcp)
8250         static_bib_num = 0
8251         for bibe in bib:
8252             if bibe.flags & self.config_flags.NAT_IS_STATIC:
8253                 static_bib_num += 1
8254                 self.assertEqual(str(bibe.i_addr), in_addr)
8255                 self.assertEqual(str(bibe.o_addr), out_addr)
8256                 self.assertEqual(bibe.i_port, in_port)
8257                 self.assertEqual(bibe.o_port, out_port)
8258         self.assertEqual(static_bib_num, 1)
8259         bibs = self.statistics.get_counter('/nat64/total-bibs')
8260         self.assertEqual(bibs[0][0], 1)
8261
8262         self.vapi.nat64_add_del_static_bib(i_addr=in_addr, o_addr=out_addr,
8263                                            i_port=in_port, o_port=out_port,
8264                                            proto=proto, vrf_id=0, is_add=0)
8265         bib = self.vapi.nat64_bib_dump(proto=IP_PROTOS.tcp)
8266         static_bib_num = 0
8267         for bibe in bib:
8268             if bibe.flags & self.config_flags.NAT_IS_STATIC:
8269                 static_bib_num += 1
8270         self.assertEqual(static_bib_num, 0)
8271         bibs = self.statistics.get_counter('/nat64/total-bibs')
8272         self.assertEqual(bibs[0][0], 0)
8273
8274     def test_set_timeouts(self):
8275         """ Set NAT64 timeouts """
8276         # verify default values
8277         timeouts = self.vapi.nat_get_timeouts()
8278         self.assertEqual(timeouts.udp, 300)
8279         self.assertEqual(timeouts.icmp, 60)
8280         self.assertEqual(timeouts.tcp_transitory, 240)
8281         self.assertEqual(timeouts.tcp_established, 7440)
8282
8283         # set and verify custom values
8284         self.vapi.nat_set_timeouts(udp=200, tcp_established=7450,
8285                                    tcp_transitory=250, icmp=30)
8286         timeouts = self.vapi.nat_get_timeouts()
8287         self.assertEqual(timeouts.udp, 200)
8288         self.assertEqual(timeouts.icmp, 30)
8289         self.assertEqual(timeouts.tcp_transitory, 250)
8290         self.assertEqual(timeouts.tcp_established, 7450)
8291
8292     def test_dynamic(self):
8293         """ NAT64 dynamic translation test """
8294         self.tcp_port_in = 6303
8295         self.udp_port_in = 6304
8296         self.icmp_id_in = 6305
8297
8298         ses_num_start = self.nat64_get_ses_num()
8299
8300         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr,
8301                                                 end_addr=self.nat_addr,
8302                                                 vrf_id=0xFFFFFFFF,
8303                                                 is_add=1)
8304         flags = self.config_flags.NAT_IS_INSIDE
8305         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
8306                                           sw_if_index=self.pg0.sw_if_index)
8307         self.vapi.nat64_add_del_interface(is_add=1, flags=0,
8308                                           sw_if_index=self.pg1.sw_if_index)
8309
8310         # in2out
8311         tcpn = self.statistics.get_err_counter('/err/nat64-in2out/TCP packets')
8312         udpn = self.statistics.get_err_counter('/err/nat64-in2out/UDP packets')
8313         icmpn = self.statistics.get_err_counter(
8314             '/err/nat64-in2out/ICMP packets')
8315         totaln = self.statistics.get_err_counter(
8316             '/err/nat64-in2out/good in2out packets processed')
8317
8318         pkts = self.create_stream_in_ip6(self.pg0, self.pg1)
8319         self.pg0.add_stream(pkts)
8320         self.pg_enable_capture(self.pg_interfaces)
8321         self.pg_start()
8322         capture = self.pg1.get_capture(len(pkts))
8323         self.verify_capture_out(capture, nat_ip=self.nat_addr,
8324                                 dst_ip=self.pg1.remote_ip4)
8325
8326         err = self.statistics.get_err_counter('/err/nat64-in2out/TCP packets')
8327         self.assertEqual(err - tcpn, 1)
8328         err = self.statistics.get_err_counter('/err/nat64-in2out/UDP packets')
8329         self.assertEqual(err - udpn, 1)
8330         err = self.statistics.get_err_counter('/err/nat64-in2out/ICMP packets')
8331         self.assertEqual(err - icmpn, 1)
8332         err = self.statistics.get_err_counter(
8333             '/err/nat64-in2out/good in2out packets processed')
8334         self.assertEqual(err - totaln, 3)
8335
8336         # out2in
8337         tcpn = self.statistics.get_err_counter('/err/nat64-out2in/TCP packets')
8338         udpn = self.statistics.get_err_counter('/err/nat64-out2in/UDP packets')
8339         icmpn = self.statistics.get_err_counter(
8340             '/err/nat64-out2in/ICMP packets')
8341         totaln = self.statistics.get_err_counter(
8342             '/err/nat64-out2in/good out2in packets processed')
8343
8344         pkts = self.create_stream_out(self.pg1, dst_ip=self.nat_addr)
8345         self.pg1.add_stream(pkts)
8346         self.pg_enable_capture(self.pg_interfaces)
8347         self.pg_start()
8348         capture = self.pg0.get_capture(len(pkts))
8349         ip = IPv6(src=''.join(['64:ff9b::', self.pg1.remote_ip4]))
8350         self.verify_capture_in_ip6(capture, ip[IPv6].src, self.pg0.remote_ip6)
8351
8352         err = self.statistics.get_err_counter('/err/nat64-out2in/TCP packets')
8353         self.assertEqual(err - tcpn, 2)
8354         err = self.statistics.get_err_counter('/err/nat64-out2in/UDP packets')
8355         self.assertEqual(err - udpn, 1)
8356         err = self.statistics.get_err_counter('/err/nat64-out2in/ICMP packets')
8357         self.assertEqual(err - icmpn, 1)
8358         err = self.statistics.get_err_counter(
8359             '/err/nat64-out2in/good out2in packets processed')
8360         self.assertEqual(err - totaln, 4)
8361
8362         bibs = self.statistics.get_counter('/nat64/total-bibs')
8363         self.assertEqual(bibs[0][0], 3)
8364         sessions = self.statistics.get_counter('/nat64/total-sessions')
8365         self.assertEqual(sessions[0][0], 3)
8366
8367         # in2out
8368         pkts = self.create_stream_in_ip6(self.pg0, self.pg1)
8369         self.pg0.add_stream(pkts)
8370         self.pg_enable_capture(self.pg_interfaces)
8371         self.pg_start()
8372         capture = self.pg1.get_capture(len(pkts))
8373         self.verify_capture_out(capture, nat_ip=self.nat_addr,
8374                                 dst_ip=self.pg1.remote_ip4)
8375
8376         # out2in
8377         pkts = self.create_stream_out(self.pg1, dst_ip=self.nat_addr)
8378         self.pg1.add_stream(pkts)
8379         self.pg_enable_capture(self.pg_interfaces)
8380         self.pg_start()
8381         capture = self.pg0.get_capture(len(pkts))
8382         self.verify_capture_in_ip6(capture, ip[IPv6].src, self.pg0.remote_ip6)
8383
8384         ses_num_end = self.nat64_get_ses_num()
8385
8386         self.assertEqual(ses_num_end - ses_num_start, 3)
8387
8388         # tenant with specific VRF
8389         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.vrf1_nat_addr,
8390                                                 end_addr=self.vrf1_nat_addr,
8391                                                 vrf_id=self.vrf1_id, is_add=1)
8392         flags = self.config_flags.NAT_IS_INSIDE
8393         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
8394                                           sw_if_index=self.pg2.sw_if_index)
8395
8396         pkts = self.create_stream_in_ip6(self.pg2, self.pg1)
8397         self.pg2.add_stream(pkts)
8398         self.pg_enable_capture(self.pg_interfaces)
8399         self.pg_start()
8400         capture = self.pg1.get_capture(len(pkts))
8401         self.verify_capture_out(capture, nat_ip=self.vrf1_nat_addr,
8402                                 dst_ip=self.pg1.remote_ip4)
8403
8404         pkts = self.create_stream_out(self.pg1, dst_ip=self.vrf1_nat_addr)
8405         self.pg1.add_stream(pkts)
8406         self.pg_enable_capture(self.pg_interfaces)
8407         self.pg_start()
8408         capture = self.pg2.get_capture(len(pkts))
8409         self.verify_capture_in_ip6(capture, ip[IPv6].src, self.pg2.remote_ip6)
8410
8411     def test_static(self):
8412         """ NAT64 static translation test """
8413         self.tcp_port_in = 60303
8414         self.udp_port_in = 60304
8415         self.icmp_id_in = 60305
8416         self.tcp_port_out = 60303
8417         self.udp_port_out = 60304
8418         self.icmp_id_out = 60305
8419
8420         ses_num_start = self.nat64_get_ses_num()
8421
8422         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr,
8423                                                 end_addr=self.nat_addr,
8424                                                 vrf_id=0xFFFFFFFF,
8425                                                 is_add=1)
8426         flags = self.config_flags.NAT_IS_INSIDE
8427         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
8428                                           sw_if_index=self.pg0.sw_if_index)
8429         self.vapi.nat64_add_del_interface(is_add=1, flags=0,
8430                                           sw_if_index=self.pg1.sw_if_index)
8431
8432         self.vapi.nat64_add_del_static_bib(i_addr=self.pg0.remote_ip6,
8433                                            o_addr=self.nat_addr,
8434                                            i_port=self.tcp_port_in,
8435                                            o_port=self.tcp_port_out,
8436                                            proto=IP_PROTOS.tcp, vrf_id=0,
8437                                            is_add=1)
8438         self.vapi.nat64_add_del_static_bib(i_addr=self.pg0.remote_ip6,
8439                                            o_addr=self.nat_addr,
8440                                            i_port=self.udp_port_in,
8441                                            o_port=self.udp_port_out,
8442                                            proto=IP_PROTOS.udp, vrf_id=0,
8443                                            is_add=1)
8444         self.vapi.nat64_add_del_static_bib(i_addr=self.pg0.remote_ip6,
8445                                            o_addr=self.nat_addr,
8446                                            i_port=self.icmp_id_in,
8447                                            o_port=self.icmp_id_out,
8448                                            proto=IP_PROTOS.icmp, vrf_id=0,
8449                                            is_add=1)
8450
8451         # in2out
8452         pkts = self.create_stream_in_ip6(self.pg0, self.pg1)
8453         self.pg0.add_stream(pkts)
8454         self.pg_enable_capture(self.pg_interfaces)
8455         self.pg_start()
8456         capture = self.pg1.get_capture(len(pkts))
8457         self.verify_capture_out(capture, nat_ip=self.nat_addr,
8458                                 dst_ip=self.pg1.remote_ip4, same_port=True)
8459
8460         # out2in
8461         pkts = self.create_stream_out(self.pg1, dst_ip=self.nat_addr)
8462         self.pg1.add_stream(pkts)
8463         self.pg_enable_capture(self.pg_interfaces)
8464         self.pg_start()
8465         capture = self.pg0.get_capture(len(pkts))
8466         ip = IPv6(src=''.join(['64:ff9b::', self.pg1.remote_ip4]))
8467         self.verify_capture_in_ip6(capture, ip[IPv6].src, self.pg0.remote_ip6)
8468
8469         ses_num_end = self.nat64_get_ses_num()
8470
8471         self.assertEqual(ses_num_end - ses_num_start, 3)
8472
8473     @unittest.skipUnless(running_extended_tests, "part of extended tests")
8474     def test_session_timeout(self):
8475         """ NAT64 session timeout """
8476         self.icmp_id_in = 1234
8477         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr,
8478                                                 end_addr=self.nat_addr,
8479                                                 vrf_id=0xFFFFFFFF,
8480                                                 is_add=1)
8481         flags = self.config_flags.NAT_IS_INSIDE
8482         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
8483                                           sw_if_index=self.pg0.sw_if_index)
8484         self.vapi.nat64_add_del_interface(is_add=1, flags=0,
8485                                           sw_if_index=self.pg1.sw_if_index)
8486         self.vapi.nat_set_timeouts(udp=300, tcp_established=5,
8487                                    tcp_transitory=5,
8488                                    icmp=5)
8489
8490         pkts = self.create_stream_in_ip6(self.pg0, self.pg1)
8491         self.pg0.add_stream(pkts)
8492         self.pg_enable_capture(self.pg_interfaces)
8493         self.pg_start()
8494         capture = self.pg1.get_capture(len(pkts))
8495
8496         ses_num_before_timeout = self.nat64_get_ses_num()
8497
8498         sleep(15)
8499
8500         # ICMP and TCP session after timeout
8501         ses_num_after_timeout = self.nat64_get_ses_num()
8502         self.assertEqual(ses_num_before_timeout - ses_num_after_timeout, 2)
8503
8504     def test_icmp_error(self):
8505         """ NAT64 ICMP Error message translation """
8506         self.tcp_port_in = 6303
8507         self.udp_port_in = 6304
8508         self.icmp_id_in = 6305
8509
8510         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr,
8511                                                 end_addr=self.nat_addr,
8512                                                 vrf_id=0xFFFFFFFF,
8513                                                 is_add=1)
8514         flags = self.config_flags.NAT_IS_INSIDE
8515         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
8516                                           sw_if_index=self.pg0.sw_if_index)
8517         self.vapi.nat64_add_del_interface(is_add=1, flags=0,
8518                                           sw_if_index=self.pg1.sw_if_index)
8519
8520         # send some packets to create sessions
8521         pkts = self.create_stream_in_ip6(self.pg0, self.pg1)
8522         self.pg0.add_stream(pkts)
8523         self.pg_enable_capture(self.pg_interfaces)
8524         self.pg_start()
8525         capture_ip4 = self.pg1.get_capture(len(pkts))
8526         self.verify_capture_out(capture_ip4,
8527                                 nat_ip=self.nat_addr,
8528                                 dst_ip=self.pg1.remote_ip4)
8529
8530         pkts = self.create_stream_out(self.pg1, dst_ip=self.nat_addr)
8531         self.pg1.add_stream(pkts)
8532         self.pg_enable_capture(self.pg_interfaces)
8533         self.pg_start()
8534         capture_ip6 = self.pg0.get_capture(len(pkts))
8535         ip = IPv6(src=''.join(['64:ff9b::', self.pg1.remote_ip4]))
8536         self.verify_capture_in_ip6(capture_ip6, ip[IPv6].src,
8537                                    self.pg0.remote_ip6)
8538
8539         # in2out
8540         pkts = [Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
8541                 IPv6(src=self.pg0.remote_ip6, dst=ip[IPv6].src) /
8542                 ICMPv6DestUnreach(code=1) /
8543                 packet[IPv6] for packet in capture_ip6]
8544         self.pg0.add_stream(pkts)
8545         self.pg_enable_capture(self.pg_interfaces)
8546         self.pg_start()
8547         capture = self.pg1.get_capture(len(pkts))
8548         for packet in capture:
8549             try:
8550                 self.assertEqual(packet[IP].src, self.nat_addr)
8551                 self.assertEqual(packet[IP].dst, self.pg1.remote_ip4)
8552                 self.assertEqual(packet[ICMP].type, 3)
8553                 self.assertEqual(packet[ICMP].code, 13)
8554                 inner = packet[IPerror]
8555                 self.assertEqual(inner.src, self.pg1.remote_ip4)
8556                 self.assertEqual(inner.dst, self.nat_addr)
8557                 self.assert_packet_checksums_valid(packet)
8558                 if inner.haslayer(TCPerror):
8559                     self.assertEqual(inner[TCPerror].dport, self.tcp_port_out)
8560                 elif inner.haslayer(UDPerror):
8561                     self.assertEqual(inner[UDPerror].dport, self.udp_port_out)
8562                 else:
8563                     self.assertEqual(inner[ICMPerror].id, self.icmp_id_out)
8564             except:
8565                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
8566                 raise
8567
8568         # out2in
8569         pkts = [Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
8570                 IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
8571                 ICMP(type=3, code=13) /
8572                 packet[IP] for packet in capture_ip4]
8573         self.pg1.add_stream(pkts)
8574         self.pg_enable_capture(self.pg_interfaces)
8575         self.pg_start()
8576         capture = self.pg0.get_capture(len(pkts))
8577         for packet in capture:
8578             try:
8579                 self.assertEqual(packet[IPv6].src, ip.src)
8580                 self.assertEqual(packet[IPv6].dst, self.pg0.remote_ip6)
8581                 icmp = packet[ICMPv6DestUnreach]
8582                 self.assertEqual(icmp.code, 1)
8583                 inner = icmp[IPerror6]
8584                 self.assertEqual(inner.src, self.pg0.remote_ip6)
8585                 self.assertEqual(inner.dst, ip.src)
8586                 self.assert_icmpv6_checksum_valid(packet)
8587                 if inner.haslayer(TCPerror):
8588                     self.assertEqual(inner[TCPerror].sport, self.tcp_port_in)
8589                 elif inner.haslayer(UDPerror):
8590                     self.assertEqual(inner[UDPerror].sport, self.udp_port_in)
8591                 else:
8592                     self.assertEqual(inner[ICMPv6EchoRequest].id,
8593                                      self.icmp_id_in)
8594             except:
8595                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
8596                 raise
8597
8598     def test_hairpinning(self):
8599         """ NAT64 hairpinning """
8600
8601         client = self.pg0.remote_hosts[0]
8602         server = self.pg0.remote_hosts[1]
8603         server_tcp_in_port = 22
8604         server_tcp_out_port = 4022
8605         server_udp_in_port = 23
8606         server_udp_out_port = 4023
8607         client_tcp_in_port = 1234
8608         client_udp_in_port = 1235
8609         client_tcp_out_port = 0
8610         client_udp_out_port = 0
8611         ip = IPv6(src=''.join(['64:ff9b::', self.nat_addr]))
8612         nat_addr_ip6 = ip.src
8613
8614         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr,
8615                                                 end_addr=self.nat_addr,
8616                                                 vrf_id=0xFFFFFFFF,
8617                                                 is_add=1)
8618         flags = self.config_flags.NAT_IS_INSIDE
8619         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
8620                                           sw_if_index=self.pg0.sw_if_index)
8621         self.vapi.nat64_add_del_interface(is_add=1, flags=0,
8622                                           sw_if_index=self.pg1.sw_if_index)
8623
8624         self.vapi.nat64_add_del_static_bib(i_addr=server.ip6n,
8625                                            o_addr=self.nat_addr,
8626                                            i_port=server_tcp_in_port,
8627                                            o_port=server_tcp_out_port,
8628                                            proto=IP_PROTOS.tcp, vrf_id=0,
8629                                            is_add=1)
8630         self.vapi.nat64_add_del_static_bib(i_addr=server.ip6n,
8631                                            o_addr=self.nat_addr,
8632                                            i_port=server_udp_in_port,
8633                                            o_port=server_udp_out_port,
8634                                            proto=IP_PROTOS.udp, vrf_id=0,
8635                                            is_add=1)
8636
8637         # client to server
8638         pkts = []
8639         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
8640              IPv6(src=client.ip6, dst=nat_addr_ip6) /
8641              TCP(sport=client_tcp_in_port, dport=server_tcp_out_port))
8642         pkts.append(p)
8643         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
8644              IPv6(src=client.ip6, dst=nat_addr_ip6) /
8645              UDP(sport=client_udp_in_port, dport=server_udp_out_port))
8646         pkts.append(p)
8647         self.pg0.add_stream(pkts)
8648         self.pg_enable_capture(self.pg_interfaces)
8649         self.pg_start()
8650         capture = self.pg0.get_capture(len(pkts))
8651         for packet in capture:
8652             try:
8653                 self.assertEqual(packet[IPv6].src, nat_addr_ip6)
8654                 self.assertEqual(packet[IPv6].dst, server.ip6)
8655                 self.assert_packet_checksums_valid(packet)
8656                 if packet.haslayer(TCP):
8657                     self.assertNotEqual(packet[TCP].sport, client_tcp_in_port)
8658                     self.assertEqual(packet[TCP].dport, server_tcp_in_port)
8659                     client_tcp_out_port = packet[TCP].sport
8660                 else:
8661                     self.assertNotEqual(packet[UDP].sport, client_udp_in_port)
8662                     self.assertEqual(packet[UDP].dport, server_udp_in_port)
8663                     client_udp_out_port = packet[UDP].sport
8664             except:
8665                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
8666                 raise
8667
8668         # server to client
8669         pkts = []
8670         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
8671              IPv6(src=server.ip6, dst=nat_addr_ip6) /
8672              TCP(sport=server_tcp_in_port, dport=client_tcp_out_port))
8673         pkts.append(p)
8674         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
8675              IPv6(src=server.ip6, dst=nat_addr_ip6) /
8676              UDP(sport=server_udp_in_port, dport=client_udp_out_port))
8677         pkts.append(p)
8678         self.pg0.add_stream(pkts)
8679         self.pg_enable_capture(self.pg_interfaces)
8680         self.pg_start()
8681         capture = self.pg0.get_capture(len(pkts))
8682         for packet in capture:
8683             try:
8684                 self.assertEqual(packet[IPv6].src, nat_addr_ip6)
8685                 self.assertEqual(packet[IPv6].dst, client.ip6)
8686                 self.assert_packet_checksums_valid(packet)
8687                 if packet.haslayer(TCP):
8688                     self.assertEqual(packet[TCP].sport, server_tcp_out_port)
8689                     self.assertEqual(packet[TCP].dport, client_tcp_in_port)
8690                 else:
8691                     self.assertEqual(packet[UDP].sport, server_udp_out_port)
8692                     self.assertEqual(packet[UDP].dport, client_udp_in_port)
8693             except:
8694                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
8695                 raise
8696
8697         # ICMP error
8698         pkts = []
8699         pkts = [Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
8700                 IPv6(src=client.ip6, dst=nat_addr_ip6) /
8701                 ICMPv6DestUnreach(code=1) /
8702                 packet[IPv6] for packet in capture]
8703         self.pg0.add_stream(pkts)
8704         self.pg_enable_capture(self.pg_interfaces)
8705         self.pg_start()
8706         capture = self.pg0.get_capture(len(pkts))
8707         for packet in capture:
8708             try:
8709                 self.assertEqual(packet[IPv6].src, nat_addr_ip6)
8710                 self.assertEqual(packet[IPv6].dst, server.ip6)
8711                 icmp = packet[ICMPv6DestUnreach]
8712                 self.assertEqual(icmp.code, 1)
8713                 inner = icmp[IPerror6]
8714                 self.assertEqual(inner.src, server.ip6)
8715                 self.assertEqual(inner.dst, nat_addr_ip6)
8716                 self.assert_packet_checksums_valid(packet)
8717                 if inner.haslayer(TCPerror):
8718                     self.assertEqual(inner[TCPerror].sport, server_tcp_in_port)
8719                     self.assertEqual(inner[TCPerror].dport,
8720                                      client_tcp_out_port)
8721                 else:
8722                     self.assertEqual(inner[UDPerror].sport, server_udp_in_port)
8723                     self.assertEqual(inner[UDPerror].dport,
8724                                      client_udp_out_port)
8725             except:
8726                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
8727                 raise
8728
8729     def test_prefix(self):
8730         """ NAT64 Network-Specific Prefix """
8731
8732         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr,
8733                                                 end_addr=self.nat_addr,
8734                                                 vrf_id=0xFFFFFFFF,
8735                                                 is_add=1)
8736         flags = self.config_flags.NAT_IS_INSIDE
8737         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
8738                                           sw_if_index=self.pg0.sw_if_index)
8739         self.vapi.nat64_add_del_interface(is_add=1, flags=0,
8740                                           sw_if_index=self.pg1.sw_if_index)
8741         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.vrf1_nat_addr,
8742                                                 end_addr=self.vrf1_nat_addr,
8743                                                 vrf_id=self.vrf1_id, is_add=1)
8744         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
8745                                           sw_if_index=self.pg2.sw_if_index)
8746
8747         # Add global prefix
8748         global_pref64 = "2001:db8::"
8749         global_pref64_len = 32
8750         global_pref64_str = "{}/{}".format(global_pref64, global_pref64_len)
8751         self.vapi.nat64_add_del_prefix(prefix=global_pref64_str, vrf_id=0,
8752                                        is_add=1)
8753
8754         prefix = self.vapi.nat64_prefix_dump()
8755         self.assertEqual(len(prefix), 1)
8756         self.assertEqual(str(prefix[0].prefix), global_pref64_str)
8757         self.assertEqual(prefix[0].vrf_id, 0)
8758
8759         # Add tenant specific prefix
8760         vrf1_pref64 = "2001:db8:122:300::"
8761         vrf1_pref64_len = 56
8762         vrf1_pref64_str = "{}/{}".format(vrf1_pref64, vrf1_pref64_len)
8763         self.vapi.nat64_add_del_prefix(prefix=vrf1_pref64_str,
8764                                        vrf_id=self.vrf1_id, is_add=1)
8765
8766         prefix = self.vapi.nat64_prefix_dump()
8767         self.assertEqual(len(prefix), 2)
8768
8769         # Global prefix
8770         pkts = self.create_stream_in_ip6(self.pg0,
8771                                          self.pg1,
8772                                          pref=global_pref64,
8773                                          plen=global_pref64_len)
8774         self.pg0.add_stream(pkts)
8775         self.pg_enable_capture(self.pg_interfaces)
8776         self.pg_start()
8777         capture = self.pg1.get_capture(len(pkts))
8778         self.verify_capture_out(capture, nat_ip=self.nat_addr,
8779                                 dst_ip=self.pg1.remote_ip4)
8780
8781         pkts = self.create_stream_out(self.pg1, dst_ip=self.nat_addr)
8782         self.pg1.add_stream(pkts)
8783         self.pg_enable_capture(self.pg_interfaces)
8784         self.pg_start()
8785         capture = self.pg0.get_capture(len(pkts))
8786         dst_ip = self.compose_ip6(self.pg1.remote_ip4,
8787                                   global_pref64,
8788                                   global_pref64_len)
8789         self.verify_capture_in_ip6(capture, dst_ip, self.pg0.remote_ip6)
8790
8791         # Tenant specific prefix
8792         pkts = self.create_stream_in_ip6(self.pg2,
8793                                          self.pg1,
8794                                          pref=vrf1_pref64,
8795                                          plen=vrf1_pref64_len)
8796         self.pg2.add_stream(pkts)
8797         self.pg_enable_capture(self.pg_interfaces)
8798         self.pg_start()
8799         capture = self.pg1.get_capture(len(pkts))
8800         self.verify_capture_out(capture, nat_ip=self.vrf1_nat_addr,
8801                                 dst_ip=self.pg1.remote_ip4)
8802
8803         pkts = self.create_stream_out(self.pg1, dst_ip=self.vrf1_nat_addr)
8804         self.pg1.add_stream(pkts)
8805         self.pg_enable_capture(self.pg_interfaces)
8806         self.pg_start()
8807         capture = self.pg2.get_capture(len(pkts))
8808         dst_ip = self.compose_ip6(self.pg1.remote_ip4,
8809                                   vrf1_pref64,
8810                                   vrf1_pref64_len)
8811         self.verify_capture_in_ip6(capture, dst_ip, self.pg2.remote_ip6)
8812
8813     def test_unknown_proto(self):
8814         """ NAT64 translate packet with unknown protocol """
8815
8816         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr,
8817                                                 end_addr=self.nat_addr,
8818                                                 vrf_id=0xFFFFFFFF,
8819                                                 is_add=1)
8820         flags = self.config_flags.NAT_IS_INSIDE
8821         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
8822                                           sw_if_index=self.pg0.sw_if_index)
8823         self.vapi.nat64_add_del_interface(is_add=1, flags=0,
8824                                           sw_if_index=self.pg1.sw_if_index)
8825         remote_ip6 = self.compose_ip6(self.pg1.remote_ip4, '64:ff9b::', 96)
8826
8827         # in2out
8828         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
8829              IPv6(src=self.pg0.remote_ip6, dst=remote_ip6) /
8830              TCP(sport=self.tcp_port_in, dport=20))
8831         self.pg0.add_stream(p)
8832         self.pg_enable_capture(self.pg_interfaces)
8833         self.pg_start()
8834         p = self.pg1.get_capture(1)
8835
8836         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
8837              IPv6(src=self.pg0.remote_ip6, dst=remote_ip6, nh=47) /
8838              GRE() /
8839              IP(src=self.pg2.local_ip4, dst=self.pg2.remote_ip4) /
8840              TCP(sport=1234, dport=1234))
8841         self.pg0.add_stream(p)
8842         self.pg_enable_capture(self.pg_interfaces)
8843         self.pg_start()
8844         p = self.pg1.get_capture(1)
8845         packet = p[0]
8846         try:
8847             self.assertEqual(packet[IP].src, self.nat_addr)
8848             self.assertEqual(packet[IP].dst, self.pg1.remote_ip4)
8849             self.assertEqual(packet.haslayer(GRE), 1)
8850             self.assert_packet_checksums_valid(packet)
8851         except:
8852             self.logger.error(ppp("Unexpected or invalid packet:", packet))
8853             raise
8854
8855         # out2in
8856         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
8857              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
8858              GRE() /
8859              IP(src=self.pg2.remote_ip4, dst=self.pg2.local_ip4) /
8860              TCP(sport=1234, dport=1234))
8861         self.pg1.add_stream(p)
8862         self.pg_enable_capture(self.pg_interfaces)
8863         self.pg_start()
8864         p = self.pg0.get_capture(1)
8865         packet = p[0]
8866         try:
8867             self.assertEqual(packet[IPv6].src, remote_ip6)
8868             self.assertEqual(packet[IPv6].dst, self.pg0.remote_ip6)
8869             self.assertEqual(packet[IPv6].nh, 47)
8870         except:
8871             self.logger.error(ppp("Unexpected or invalid packet:", packet))
8872             raise
8873
8874     def test_hairpinning_unknown_proto(self):
8875         """ NAT64 translate packet with unknown protocol - hairpinning """
8876
8877         client = self.pg0.remote_hosts[0]
8878         server = self.pg0.remote_hosts[1]
8879         server_tcp_in_port = 22
8880         server_tcp_out_port = 4022
8881         client_tcp_in_port = 1234
8882         client_tcp_out_port = 1235
8883         server_nat_ip = "10.0.0.100"
8884         client_nat_ip = "10.0.0.110"
8885         server_nat_ip6 = self.compose_ip6(server_nat_ip, '64:ff9b::', 96)
8886         client_nat_ip6 = self.compose_ip6(client_nat_ip, '64:ff9b::', 96)
8887
8888         self.vapi.nat64_add_del_pool_addr_range(start_addr=server_nat_ip,
8889                                                 end_addr=client_nat_ip,
8890                                                 vrf_id=0xFFFFFFFF,
8891                                                 is_add=1)
8892         flags = self.config_flags.NAT_IS_INSIDE
8893         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
8894                                           sw_if_index=self.pg0.sw_if_index)
8895         self.vapi.nat64_add_del_interface(is_add=1, flags=0,
8896                                           sw_if_index=self.pg1.sw_if_index)
8897
8898         self.vapi.nat64_add_del_static_bib(i_addr=server.ip6n,
8899                                            o_addr=server_nat_ip,
8900                                            i_port=server_tcp_in_port,
8901                                            o_port=server_tcp_out_port,
8902                                            proto=IP_PROTOS.tcp, vrf_id=0,
8903                                            is_add=1)
8904
8905         self.vapi.nat64_add_del_static_bib(i_addr=server.ip6n,
8906                                            o_addr=server_nat_ip, i_port=0,
8907                                            o_port=0,
8908                                            proto=IP_PROTOS.gre, vrf_id=0,
8909                                            is_add=1)
8910
8911         self.vapi.nat64_add_del_static_bib(i_addr=client.ip6n,
8912                                            o_addr=client_nat_ip,
8913                                            i_port=client_tcp_in_port,
8914                                            o_port=client_tcp_out_port,
8915                                            proto=IP_PROTOS.tcp, vrf_id=0,
8916                                            is_add=1)
8917
8918         # client to server
8919         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
8920              IPv6(src=client.ip6, dst=server_nat_ip6) /
8921              TCP(sport=client_tcp_in_port, dport=server_tcp_out_port))
8922         self.pg0.add_stream(p)
8923         self.pg_enable_capture(self.pg_interfaces)
8924         self.pg_start()
8925         p = self.pg0.get_capture(1)
8926
8927         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
8928              IPv6(src=client.ip6, dst=server_nat_ip6, nh=IP_PROTOS.gre) /
8929              GRE() /
8930              IP(src=self.pg2.local_ip4, dst=self.pg2.remote_ip4) /
8931              TCP(sport=1234, dport=1234))
8932         self.pg0.add_stream(p)
8933         self.pg_enable_capture(self.pg_interfaces)
8934         self.pg_start()
8935         p = self.pg0.get_capture(1)
8936         packet = p[0]
8937         try:
8938             self.assertEqual(packet[IPv6].src, client_nat_ip6)
8939             self.assertEqual(packet[IPv6].dst, server.ip6)
8940             self.assertEqual(packet[IPv6].nh, IP_PROTOS.gre)
8941         except:
8942             self.logger.error(ppp("Unexpected or invalid packet:", packet))
8943             raise
8944
8945         # server to client
8946         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
8947              IPv6(src=server.ip6, dst=client_nat_ip6, nh=IP_PROTOS.gre) /
8948              GRE() /
8949              IP(src=self.pg2.remote_ip4, dst=self.pg2.local_ip4) /
8950              TCP(sport=1234, dport=1234))
8951         self.pg0.add_stream(p)
8952         self.pg_enable_capture(self.pg_interfaces)
8953         self.pg_start()
8954         p = self.pg0.get_capture(1)
8955         packet = p[0]
8956         try:
8957             self.assertEqual(packet[IPv6].src, server_nat_ip6)
8958             self.assertEqual(packet[IPv6].dst, client.ip6)
8959             self.assertEqual(packet[IPv6].nh, IP_PROTOS.gre)
8960         except:
8961             self.logger.error(ppp("Unexpected or invalid packet:", packet))
8962             raise
8963
8964     def test_one_armed_nat64(self):
8965         """ One armed NAT64 """
8966         external_port = 0
8967         remote_host_ip6 = self.compose_ip6(self.pg3.remote_ip4,
8968                                            '64:ff9b::',
8969                                            96)
8970
8971         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr,
8972                                                 end_addr=self.nat_addr,
8973                                                 vrf_id=0xFFFFFFFF,
8974                                                 is_add=1)
8975         flags = self.config_flags.NAT_IS_INSIDE
8976         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
8977                                           sw_if_index=self.pg3.sw_if_index)
8978         self.vapi.nat64_add_del_interface(is_add=1, flags=0,
8979                                           sw_if_index=self.pg3.sw_if_index)
8980
8981         # in2out
8982         p = (Ether(src=self.pg3.remote_mac, dst=self.pg3.local_mac) /
8983              IPv6(src=self.pg3.remote_ip6, dst=remote_host_ip6) /
8984              TCP(sport=12345, dport=80))
8985         self.pg3.add_stream(p)
8986         self.pg_enable_capture(self.pg_interfaces)
8987         self.pg_start()
8988         capture = self.pg3.get_capture(1)
8989         p = capture[0]
8990         try:
8991             ip = p[IP]
8992             tcp = p[TCP]
8993             self.assertEqual(ip.src, self.nat_addr)
8994             self.assertEqual(ip.dst, self.pg3.remote_ip4)
8995             self.assertNotEqual(tcp.sport, 12345)
8996             external_port = tcp.sport
8997             self.assertEqual(tcp.dport, 80)
8998             self.assert_packet_checksums_valid(p)
8999         except:
9000             self.logger.error(ppp("Unexpected or invalid packet:", p))
9001             raise
9002
9003         # out2in
9004         p = (Ether(src=self.pg3.remote_mac, dst=self.pg3.local_mac) /
9005              IP(src=self.pg3.remote_ip4, dst=self.nat_addr) /
9006              TCP(sport=80, dport=external_port))
9007         self.pg3.add_stream(p)
9008         self.pg_enable_capture(self.pg_interfaces)
9009         self.pg_start()
9010         capture = self.pg3.get_capture(1)
9011         p = capture[0]
9012         try:
9013             ip = p[IPv6]
9014             tcp = p[TCP]
9015             self.assertEqual(ip.src, remote_host_ip6)
9016             self.assertEqual(ip.dst, self.pg3.remote_ip6)
9017             self.assertEqual(tcp.sport, 80)
9018             self.assertEqual(tcp.dport, 12345)
9019             self.assert_packet_checksums_valid(p)
9020         except:
9021             self.logger.error(ppp("Unexpected or invalid packet:", p))
9022             raise
9023
9024     def test_frag_in_order(self):
9025         """ NAT64 translate fragments arriving in order """
9026         self.tcp_port_in = random.randint(1025, 65535)
9027
9028         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr,
9029                                                 end_addr=self.nat_addr,
9030                                                 vrf_id=0xFFFFFFFF,
9031                                                 is_add=1)
9032         flags = self.config_flags.NAT_IS_INSIDE
9033         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
9034                                           sw_if_index=self.pg0.sw_if_index)
9035         self.vapi.nat64_add_del_interface(is_add=1, flags=0,
9036                                           sw_if_index=self.pg1.sw_if_index)
9037
9038         # in2out
9039         data = b'a' * 200
9040         pkts = self.create_stream_frag_ip6(self.pg0, self.pg1.remote_ip4,
9041                                            self.tcp_port_in, 20, data)
9042         self.pg0.add_stream(pkts)
9043         self.pg_enable_capture(self.pg_interfaces)
9044         self.pg_start()
9045         frags = self.pg1.get_capture(len(pkts))
9046         p = self.reass_frags_and_verify(frags,
9047                                         self.nat_addr,
9048                                         self.pg1.remote_ip4)
9049         self.assertEqual(p[TCP].dport, 20)
9050         self.assertNotEqual(p[TCP].sport, self.tcp_port_in)
9051         self.tcp_port_out = p[TCP].sport
9052         self.assertEqual(data, p[Raw].load)
9053
9054         # out2in
9055         data = b"A" * 4 + b"b" * 16 + b"C" * 3
9056         pkts = self.create_stream_frag(self.pg1,
9057                                        self.nat_addr,
9058                                        20,
9059                                        self.tcp_port_out,
9060                                        data)
9061         self.pg1.add_stream(pkts)
9062         self.pg_enable_capture(self.pg_interfaces)
9063         self.pg_start()
9064         frags = self.pg0.get_capture(len(pkts))
9065         self.logger.debug(ppc("Captured:", frags))
9066         src = self.compose_ip6(self.pg1.remote_ip4, '64:ff9b::', 96)
9067         p = self.reass_frags_and_verify_ip6(frags, src, self.pg0.remote_ip6)
9068         self.assertEqual(p[TCP].sport, 20)
9069         self.assertEqual(p[TCP].dport, self.tcp_port_in)
9070         self.assertEqual(data, p[Raw].load)
9071
9072     def test_reass_hairpinning(self):
9073         """ NAT64 fragments hairpinning """
9074         data = b'a' * 200
9075         server = self.pg0.remote_hosts[1]
9076         server_in_port = random.randint(1025, 65535)
9077         server_out_port = random.randint(1025, 65535)
9078         client_in_port = random.randint(1025, 65535)
9079         ip = IPv6(src=''.join(['64:ff9b::', self.nat_addr]))
9080         nat_addr_ip6 = ip.src
9081
9082         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr,
9083                                                 end_addr=self.nat_addr,
9084                                                 vrf_id=0xFFFFFFFF,
9085                                                 is_add=1)
9086         flags = self.config_flags.NAT_IS_INSIDE
9087         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
9088                                           sw_if_index=self.pg0.sw_if_index)
9089         self.vapi.nat64_add_del_interface(is_add=1, flags=0,
9090                                           sw_if_index=self.pg1.sw_if_index)
9091
9092         # add static BIB entry for server
9093         self.vapi.nat64_add_del_static_bib(i_addr=server.ip6n,
9094                                            o_addr=self.nat_addr,
9095                                            i_port=server_in_port,
9096                                            o_port=server_out_port,
9097                                            proto=IP_PROTOS.tcp, vrf_id=0,
9098                                            is_add=1)
9099
9100         # send packet from host to server
9101         pkts = self.create_stream_frag_ip6(self.pg0,
9102                                            self.nat_addr,
9103                                            client_in_port,
9104                                            server_out_port,
9105                                            data)
9106         self.pg0.add_stream(pkts)
9107         self.pg_enable_capture(self.pg_interfaces)
9108         self.pg_start()
9109         frags = self.pg0.get_capture(len(pkts))
9110         self.logger.debug(ppc("Captured:", frags))
9111         p = self.reass_frags_and_verify_ip6(frags, nat_addr_ip6, server.ip6)
9112         self.assertNotEqual(p[TCP].sport, client_in_port)
9113         self.assertEqual(p[TCP].dport, server_in_port)
9114         self.assertEqual(data, p[Raw].load)
9115
9116     def test_frag_out_of_order(self):
9117         """ NAT64 translate fragments arriving out of order """
9118         self.tcp_port_in = random.randint(1025, 65535)
9119
9120         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr,
9121                                                 end_addr=self.nat_addr,
9122                                                 vrf_id=0xFFFFFFFF,
9123                                                 is_add=1)
9124         flags = self.config_flags.NAT_IS_INSIDE
9125         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
9126                                           sw_if_index=self.pg0.sw_if_index)
9127         self.vapi.nat64_add_del_interface(is_add=1, flags=0,
9128                                           sw_if_index=self.pg1.sw_if_index)
9129
9130         # in2out
9131         data = b'a' * 200
9132         pkts = self.create_stream_frag_ip6(self.pg0, self.pg1.remote_ip4,
9133                                            self.tcp_port_in, 20, data)
9134         pkts.reverse()
9135         self.pg0.add_stream(pkts)
9136         self.pg_enable_capture(self.pg_interfaces)
9137         self.pg_start()
9138         frags = self.pg1.get_capture(len(pkts))
9139         p = self.reass_frags_and_verify(frags,
9140                                         self.nat_addr,
9141                                         self.pg1.remote_ip4)
9142         self.assertEqual(p[TCP].dport, 20)
9143         self.assertNotEqual(p[TCP].sport, self.tcp_port_in)
9144         self.tcp_port_out = p[TCP].sport
9145         self.assertEqual(data, p[Raw].load)
9146
9147         # out2in
9148         data = b"A" * 4 + b"B" * 16 + b"C" * 3
9149         pkts = self.create_stream_frag(self.pg1,
9150                                        self.nat_addr,
9151                                        20,
9152                                        self.tcp_port_out,
9153                                        data)
9154         pkts.reverse()
9155         self.pg1.add_stream(pkts)
9156         self.pg_enable_capture(self.pg_interfaces)
9157         self.pg_start()
9158         frags = self.pg0.get_capture(len(pkts))
9159         src = self.compose_ip6(self.pg1.remote_ip4, '64:ff9b::', 96)
9160         p = self.reass_frags_and_verify_ip6(frags, src, self.pg0.remote_ip6)
9161         self.assertEqual(p[TCP].sport, 20)
9162         self.assertEqual(p[TCP].dport, self.tcp_port_in)
9163         self.assertEqual(data, p[Raw].load)
9164
9165     def test_interface_addr(self):
9166         """ Acquire NAT64 pool addresses from interface """
9167         self.vapi.nat64_add_del_interface_addr(
9168             is_add=1,
9169             sw_if_index=self.pg4.sw_if_index)
9170
9171         # no address in NAT64 pool
9172         addresses = self.vapi.nat44_address_dump()
9173         self.assertEqual(0, len(addresses))
9174
9175         # configure interface address and check NAT64 address pool
9176         self.pg4.config_ip4()
9177         addresses = self.vapi.nat64_pool_addr_dump()
9178         self.assertEqual(len(addresses), 1)
9179
9180         self.assertEqual(str(addresses[0].address),
9181                          self.pg4.local_ip4)
9182
9183         # remove interface address and check NAT64 address pool
9184         self.pg4.unconfig_ip4()
9185         addresses = self.vapi.nat64_pool_addr_dump()
9186         self.assertEqual(0, len(addresses))
9187
9188     @unittest.skipUnless(running_extended_tests, "part of extended tests")
9189     def test_ipfix_max_bibs_sessions(self):
9190         """ IPFIX logging maximum session and BIB entries exceeded """
9191         max_bibs = 1280
9192         max_sessions = 2560
9193         remote_host_ip6 = self.compose_ip6(self.pg1.remote_ip4,
9194                                            '64:ff9b::',
9195                                            96)
9196
9197         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr,
9198                                                 end_addr=self.nat_addr,
9199                                                 vrf_id=0xFFFFFFFF,
9200                                                 is_add=1)
9201         flags = self.config_flags.NAT_IS_INSIDE
9202         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
9203                                           sw_if_index=self.pg0.sw_if_index)
9204         self.vapi.nat64_add_del_interface(is_add=1, flags=0,
9205                                           sw_if_index=self.pg1.sw_if_index)
9206
9207         pkts = []
9208         src = ""
9209         for i in range(0, max_bibs):
9210             src = "fd01:aa::%x" % (i)
9211             p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
9212                  IPv6(src=src, dst=remote_host_ip6) /
9213                  TCP(sport=12345, dport=80))
9214             pkts.append(p)
9215             p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
9216                  IPv6(src=src, dst=remote_host_ip6) /
9217                  TCP(sport=12345, dport=22))
9218             pkts.append(p)
9219         self.pg0.add_stream(pkts)
9220         self.pg_enable_capture(self.pg_interfaces)
9221         self.pg_start()
9222         self.pg1.get_capture(max_sessions)
9223
9224         self.vapi.set_ipfix_exporter(collector_address=self.pg3.remote_ip4,
9225                                      src_address=self.pg3.local_ip4,
9226                                      path_mtu=512,
9227                                      template_interval=10)
9228         self.vapi.nat_ipfix_enable_disable(domain_id=self.ipfix_domain_id,
9229                                            src_port=self.ipfix_src_port,
9230                                            enable=1)
9231
9232         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
9233              IPv6(src=src, dst=remote_host_ip6) /
9234              TCP(sport=12345, dport=25))
9235         self.pg0.add_stream(p)
9236         self.pg_enable_capture(self.pg_interfaces)
9237         self.pg_start()
9238         self.pg1.assert_nothing_captured()
9239         sleep(1)
9240         self.vapi.ipfix_flush()
9241         capture = self.pg3.get_capture(7)
9242         ipfix = IPFIXDecoder()
9243         # first load template
9244         for p in capture:
9245             self.assertTrue(p.haslayer(IPFIX))
9246             self.assertEqual(p[IP].src, self.pg3.local_ip4)
9247             self.assertEqual(p[IP].dst, self.pg3.remote_ip4)
9248             self.assertEqual(p[UDP].sport, self.ipfix_src_port)
9249             self.assertEqual(p[UDP].dport, 4739)
9250             self.assertEqual(p[IPFIX].observationDomainID,
9251                              self.ipfix_domain_id)
9252             if p.haslayer(Template):
9253                 ipfix.add_template(p.getlayer(Template))
9254         # verify events in data set
9255         for p in capture:
9256             if p.haslayer(Data):
9257                 data = ipfix.decode_data_set(p.getlayer(Set))
9258                 self.verify_ipfix_max_sessions(data, max_sessions)
9259
9260         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
9261              IPv6(src=self.pg0.remote_ip6, dst=remote_host_ip6) /
9262              TCP(sport=12345, dport=80))
9263         self.pg0.add_stream(p)
9264         self.pg_enable_capture(self.pg_interfaces)
9265         self.pg_start()
9266         self.pg1.assert_nothing_captured()
9267         sleep(1)
9268         self.vapi.ipfix_flush()
9269         capture = self.pg3.get_capture(1)
9270         # verify events in data set
9271         for p in capture:
9272             self.assertTrue(p.haslayer(IPFIX))
9273             self.assertEqual(p[IP].src, self.pg3.local_ip4)
9274             self.assertEqual(p[IP].dst, self.pg3.remote_ip4)
9275             self.assertEqual(p[UDP].sport, self.ipfix_src_port)
9276             self.assertEqual(p[UDP].dport, 4739)
9277             self.assertEqual(p[IPFIX].observationDomainID,
9278                              self.ipfix_domain_id)
9279             if p.haslayer(Data):
9280                 data = ipfix.decode_data_set(p.getlayer(Set))
9281                 self.verify_ipfix_max_bibs(data, max_bibs)
9282
9283     def test_ipfix_bib_ses(self):
9284         """ IPFIX logging NAT64 BIB/session create and delete events """
9285         self.tcp_port_in = random.randint(1025, 65535)
9286         remote_host_ip6 = self.compose_ip6(self.pg1.remote_ip4,
9287                                            '64:ff9b::',
9288                                            96)
9289
9290         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr,
9291                                                 end_addr=self.nat_addr,
9292                                                 vrf_id=0xFFFFFFFF,
9293                                                 is_add=1)
9294         flags = self.config_flags.NAT_IS_INSIDE
9295         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
9296                                           sw_if_index=self.pg0.sw_if_index)
9297         self.vapi.nat64_add_del_interface(is_add=1, flags=0,
9298                                           sw_if_index=self.pg1.sw_if_index)
9299         self.vapi.set_ipfix_exporter(collector_address=self.pg3.remote_ip4,
9300                                      src_address=self.pg3.local_ip4,
9301                                      path_mtu=512,
9302                                      template_interval=10)
9303         self.vapi.nat_ipfix_enable_disable(domain_id=self.ipfix_domain_id,
9304                                            src_port=self.ipfix_src_port,
9305                                            enable=1)
9306
9307         # Create
9308         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
9309              IPv6(src=self.pg0.remote_ip6, dst=remote_host_ip6) /
9310              TCP(sport=self.tcp_port_in, dport=25))
9311         self.pg0.add_stream(p)
9312         self.pg_enable_capture(self.pg_interfaces)
9313         self.pg_start()
9314         p = self.pg1.get_capture(1)
9315         self.tcp_port_out = p[0][TCP].sport
9316         self.vapi.ipfix_flush()
9317         capture = self.pg3.get_capture(8)
9318         ipfix = IPFIXDecoder()
9319         # first load template
9320         for p in capture:
9321             self.assertTrue(p.haslayer(IPFIX))
9322             self.assertEqual(p[IP].src, self.pg3.local_ip4)
9323             self.assertEqual(p[IP].dst, self.pg3.remote_ip4)
9324             self.assertEqual(p[UDP].sport, self.ipfix_src_port)
9325             self.assertEqual(p[UDP].dport, 4739)
9326             self.assertEqual(p[IPFIX].observationDomainID,
9327                              self.ipfix_domain_id)
9328             if p.haslayer(Template):
9329                 ipfix.add_template(p.getlayer(Template))
9330         # verify events in data set
9331         for p in capture:
9332             if p.haslayer(Data):
9333                 data = ipfix.decode_data_set(p.getlayer(Set))
9334                 if scapy.compat.orb(data[0][230]) == 10:
9335                     self.verify_ipfix_bib(data, 1, self.pg0.remote_ip6)
9336                 elif scapy.compat.orb(data[0][230]) == 6:
9337                     self.verify_ipfix_nat64_ses(data,
9338                                                 1,
9339                                                 self.pg0.remote_ip6,
9340                                                 self.pg1.remote_ip4,
9341                                                 25)
9342                 else:
9343                     self.logger.error(ppp("Unexpected or invalid packet: ", p))
9344
9345         # Delete
9346         self.pg_enable_capture(self.pg_interfaces)
9347         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr,
9348                                                 end_addr=self.nat_addr,
9349                                                 vrf_id=0xFFFFFFFF,
9350                                                 is_add=0)
9351         self.vapi.ipfix_flush()
9352         capture = self.pg3.get_capture(2)
9353         # verify events in data set
9354         for p in capture:
9355             self.assertTrue(p.haslayer(IPFIX))
9356             self.assertEqual(p[IP].src, self.pg3.local_ip4)
9357             self.assertEqual(p[IP].dst, self.pg3.remote_ip4)
9358             self.assertEqual(p[UDP].sport, self.ipfix_src_port)
9359             self.assertEqual(p[UDP].dport, 4739)
9360             self.assertEqual(p[IPFIX].observationDomainID,
9361                              self.ipfix_domain_id)
9362             if p.haslayer(Data):
9363                 data = ipfix.decode_data_set(p.getlayer(Set))
9364                 if scapy.compat.orb(data[0][230]) == 11:
9365                     self.verify_ipfix_bib(data, 0, self.pg0.remote_ip6)
9366                 elif scapy.compat.orb(data[0][230]) == 7:
9367                     self.verify_ipfix_nat64_ses(data,
9368                                                 0,
9369                                                 self.pg0.remote_ip6,
9370                                                 self.pg1.remote_ip4,
9371                                                 25)
9372                 else:
9373                     self.logger.error(ppp("Unexpected or invalid packet: ", p))
9374
9375     def test_syslog_sess(self):
9376         """ Test syslog session creation and deletion """
9377         self.tcp_port_in = random.randint(1025, 65535)
9378         remote_host_ip6 = self.compose_ip6(self.pg1.remote_ip4,
9379                                            '64:ff9b::',
9380                                            96)
9381
9382         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr,
9383                                                 end_addr=self.nat_addr,
9384                                                 vrf_id=0xFFFFFFFF,
9385                                                 is_add=1)
9386         flags = self.config_flags.NAT_IS_INSIDE
9387         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
9388                                           sw_if_index=self.pg0.sw_if_index)
9389         self.vapi.nat64_add_del_interface(is_add=1, flags=0,
9390                                           sw_if_index=self.pg1.sw_if_index)
9391         self.vapi.syslog_set_filter(
9392             self.SYSLOG_SEVERITY.SYSLOG_API_SEVERITY_INFO)
9393         self.vapi.syslog_set_sender(self.pg3.local_ip4, self.pg3.remote_ip4)
9394
9395         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
9396              IPv6(src=self.pg0.remote_ip6, dst=remote_host_ip6) /
9397              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port))
9398         self.pg0.add_stream(p)
9399         self.pg_enable_capture(self.pg_interfaces)
9400         self.pg_start()
9401         p = self.pg1.get_capture(1)
9402         self.tcp_port_out = p[0][TCP].sport
9403         capture = self.pg3.get_capture(1)
9404         self.verify_syslog_sess(capture[0][Raw].load, is_ip6=True)
9405
9406         self.pg_enable_capture(self.pg_interfaces)
9407         self.pg_start()
9408         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr,
9409                                                 end_addr=self.nat_addr,
9410                                                 vrf_id=0xFFFFFFFF,
9411                                                 is_add=0)
9412         capture = self.pg3.get_capture(1)
9413         self.verify_syslog_sess(capture[0][Raw].load, False, True)
9414
9415     def nat64_get_ses_num(self):
9416         """
9417         Return number of active NAT64 sessions.
9418         """
9419         st = self.vapi.nat64_st_dump(proto=255)
9420         return len(st)
9421
9422     def clear_nat64(self):
9423         """
9424         Clear NAT64 configuration.
9425         """
9426         self.vapi.nat_ipfix_enable_disable(domain_id=self.ipfix_domain_id,
9427                                            src_port=self.ipfix_src_port,
9428                                            enable=0)
9429         self.ipfix_src_port = 4739
9430         self.ipfix_domain_id = 1
9431
9432         self.vapi.syslog_set_filter(
9433             self.SYSLOG_SEVERITY.SYSLOG_API_SEVERITY_EMERG)
9434
9435         self.vapi.nat_set_timeouts(udp=300, tcp_established=7440,
9436                                    tcp_transitory=240, icmp=60)
9437
9438         interfaces = self.vapi.nat64_interface_dump()
9439         for intf in interfaces:
9440             self.vapi.nat64_add_del_interface(is_add=0, flags=intf.flags,
9441                                               sw_if_index=intf.sw_if_index)
9442
9443         bib = self.vapi.nat64_bib_dump(proto=255)
9444         for bibe in bib:
9445             if bibe.flags & self.config_flags.NAT_IS_STATIC:
9446                 self.vapi.nat64_add_del_static_bib(i_addr=bibe.i_addr,
9447                                                    o_addr=bibe.o_addr,
9448                                                    i_port=bibe.i_port,
9449                                                    o_port=bibe.o_port,
9450                                                    proto=bibe.proto,
9451                                                    vrf_id=bibe.vrf_id,
9452                                                    is_add=0)
9453
9454         adresses = self.vapi.nat64_pool_addr_dump()
9455         for addr in adresses:
9456             self.vapi.nat64_add_del_pool_addr_range(start_addr=addr.address,
9457                                                     end_addr=addr.address,
9458                                                     vrf_id=addr.vrf_id,
9459                                                     is_add=0)
9460
9461         prefixes = self.vapi.nat64_prefix_dump()
9462         for prefix in prefixes:
9463             self.vapi.nat64_add_del_prefix(prefix=str(prefix.prefix),
9464                                            vrf_id=prefix.vrf_id, is_add=0)
9465
9466         bibs = self.statistics.get_counter('/nat64/total-bibs')
9467         self.assertEqual(bibs[0][0], 0)
9468         sessions = self.statistics.get_counter('/nat64/total-sessions')
9469         self.assertEqual(sessions[0][0], 0)
9470
9471     def tearDown(self):
9472         super(TestNAT64, self).tearDown()
9473         if not self.vpp_dead:
9474             self.clear_nat64()
9475
9476     def show_commands_at_teardown(self):
9477         self.logger.info(self.vapi.cli("show nat64 pool"))
9478         self.logger.info(self.vapi.cli("show nat64 interfaces"))
9479         self.logger.info(self.vapi.cli("show nat64 prefix"))
9480         self.logger.info(self.vapi.cli("show nat64 bib all"))
9481         self.logger.info(self.vapi.cli("show nat64 session table all"))
9482
9483
9484 class TestNAT66(MethodHolder):
9485     """ NAT66 Test Cases """
9486
9487     @classmethod
9488     def setUpClass(cls):
9489         super(TestNAT66, cls).setUpClass()
9490
9491         cls.nat_addr = 'fd01:ff::2'
9492
9493         cls.create_pg_interfaces(range(2))
9494         cls.interfaces = list(cls.pg_interfaces)
9495
9496         for i in cls.interfaces:
9497             i.admin_up()
9498             i.config_ip6()
9499             i.configure_ipv6_neighbors()
9500
9501     @classmethod
9502     def tearDownClass(cls):
9503         super(TestNAT66, cls).tearDownClass()
9504
9505     def test_static(self):
9506         """ 1:1 NAT66 test """
9507         flags = self.config_flags.NAT_IS_INSIDE
9508         self.vapi.nat66_add_del_interface(is_add=1, flags=flags,
9509                                           sw_if_index=self.pg0.sw_if_index)
9510         self.vapi.nat66_add_del_interface(is_add=1,
9511                                           sw_if_index=self.pg1.sw_if_index)
9512         self.vapi.nat66_add_del_static_mapping(
9513             local_ip_address=self.pg0.remote_ip6,
9514             external_ip_address=self.nat_addr,
9515             is_add=1)
9516
9517         # in2out
9518         pkts = []
9519         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
9520              IPv6(src=self.pg0.remote_ip6, dst=self.pg1.remote_ip6) /
9521              TCP())
9522         pkts.append(p)
9523         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
9524              IPv6(src=self.pg0.remote_ip6, dst=self.pg1.remote_ip6) /
9525              UDP())
9526         pkts.append(p)
9527         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
9528              IPv6(src=self.pg0.remote_ip6, dst=self.pg1.remote_ip6) /
9529              ICMPv6EchoRequest())
9530         pkts.append(p)
9531         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
9532              IPv6(src=self.pg0.remote_ip6, dst=self.pg1.remote_ip6) /
9533              GRE() / IP() / TCP())
9534         pkts.append(p)
9535         self.pg0.add_stream(pkts)
9536         self.pg_enable_capture(self.pg_interfaces)
9537         self.pg_start()
9538         capture = self.pg1.get_capture(len(pkts))
9539
9540         for packet in capture:
9541             try:
9542                 self.assertEqual(packet[IPv6].src, self.nat_addr)
9543                 self.assertEqual(packet[IPv6].dst, self.pg1.remote_ip6)
9544                 self.assert_packet_checksums_valid(packet)
9545             except:
9546                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
9547                 raise
9548
9549         # out2in
9550         pkts = []
9551         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
9552              IPv6(src=self.pg1.remote_ip6, dst=self.nat_addr) /
9553              TCP())
9554         pkts.append(p)
9555         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
9556              IPv6(src=self.pg1.remote_ip6, dst=self.nat_addr) /
9557              UDP())
9558         pkts.append(p)
9559         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
9560              IPv6(src=self.pg1.remote_ip6, dst=self.nat_addr) /
9561              ICMPv6EchoReply())
9562         pkts.append(p)
9563         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
9564              IPv6(src=self.pg1.remote_ip6, dst=self.nat_addr) /
9565              GRE() / IP() / TCP())
9566         pkts.append(p)
9567         self.pg1.add_stream(pkts)
9568         self.pg_enable_capture(self.pg_interfaces)
9569         self.pg_start()
9570         capture = self.pg0.get_capture(len(pkts))
9571         for packet in capture:
9572             try:
9573                 self.assertEqual(packet[IPv6].src, self.pg1.remote_ip6)
9574                 self.assertEqual(packet[IPv6].dst, self.pg0.remote_ip6)
9575                 self.assert_packet_checksums_valid(packet)
9576             except:
9577                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
9578                 raise
9579
9580         sm = self.vapi.nat66_static_mapping_dump()
9581         self.assertEqual(len(sm), 1)
9582         self.assertEqual(sm[0].total_pkts, 8)
9583
9584     def test_check_no_translate(self):
9585         """ NAT66 translate only when egress interface is outside interface """
9586         flags = self.config_flags.NAT_IS_INSIDE
9587         self.vapi.nat66_add_del_interface(is_add=1, flags=flags,
9588                                           sw_if_index=self.pg0.sw_if_index)
9589         self.vapi.nat66_add_del_interface(is_add=1, flags=flags,
9590                                           sw_if_index=self.pg1.sw_if_index)
9591         self.vapi.nat66_add_del_static_mapping(
9592             local_ip_address=self.pg0.remote_ip6,
9593             external_ip_address=self.nat_addr,
9594             is_add=1)
9595
9596         # in2out
9597         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
9598              IPv6(src=self.pg0.remote_ip6, dst=self.pg1.remote_ip6) /
9599              UDP())
9600         self.pg0.add_stream([p])
9601         self.pg_enable_capture(self.pg_interfaces)
9602         self.pg_start()
9603         capture = self.pg1.get_capture(1)
9604         packet = capture[0]
9605         try:
9606             self.assertEqual(packet[IPv6].src, self.pg0.remote_ip6)
9607             self.assertEqual(packet[IPv6].dst, self.pg1.remote_ip6)
9608         except:
9609             self.logger.error(ppp("Unexpected or invalid packet:", packet))
9610             raise
9611
9612     def clear_nat66(self):
9613         """
9614         Clear NAT66 configuration.
9615         """
9616         interfaces = self.vapi.nat66_interface_dump()
9617         for intf in interfaces:
9618             self.vapi.nat66_add_del_interface(is_add=0, flags=intf.flags,
9619                                               sw_if_index=intf.sw_if_index)
9620
9621         static_mappings = self.vapi.nat66_static_mapping_dump()
9622         for sm in static_mappings:
9623             self.vapi.nat66_add_del_static_mapping(
9624                 local_ip_address=sm.local_ip_address,
9625                 external_ip_address=sm.external_ip_address, vrf_id=sm.vrf_id,
9626                 is_add=0)
9627
9628     def tearDown(self):
9629         super(TestNAT66, self).tearDown()
9630         self.clear_nat66()
9631
9632     def show_commands_at_teardown(self):
9633         self.logger.info(self.vapi.cli("show nat66 interfaces"))
9634         self.logger.info(self.vapi.cli("show nat66 static mappings"))
9635
9636
9637 if __name__ == '__main__':
9638     unittest.main(testRunner=VppTestRunner)