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