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