nat: remove non-error error counters
[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     max_translations = 10240
1393     max_users = 10240
1394
1395     @classmethod
1396     def setUpConstants(cls):
1397         super(TestNAT44, cls).setUpConstants()
1398         cls.vpp_cmdline.extend([
1399             "nat", "{",
1400             "max translations per thread %d" % cls.max_translations,
1401             "max users per thread %d" % cls.max_users,
1402             "}"
1403         ])
1404
1405     @classmethod
1406     def setUpClass(cls):
1407         super(TestNAT44, cls).setUpClass()
1408         cls.vapi.cli("set log class nat level debug")
1409
1410         cls.tcp_port_in = 6303
1411         cls.tcp_port_out = 6303
1412         cls.udp_port_in = 6304
1413         cls.udp_port_out = 6304
1414         cls.icmp_id_in = 6305
1415         cls.icmp_id_out = 6305
1416         cls.nat_addr = '10.0.0.3'
1417         cls.ipfix_src_port = 4739
1418         cls.ipfix_domain_id = 1
1419         cls.tcp_external_port = 80
1420         cls.udp_external_port = 69
1421
1422         cls.create_pg_interfaces(range(10))
1423         cls.interfaces = list(cls.pg_interfaces[0:4])
1424
1425         for i in cls.interfaces:
1426             i.admin_up()
1427             i.config_ip4()
1428             i.resolve_arp()
1429
1430         cls.pg0.generate_remote_hosts(3)
1431         cls.pg0.configure_ipv4_neighbors()
1432
1433         cls.pg1.generate_remote_hosts(1)
1434         cls.pg1.configure_ipv4_neighbors()
1435
1436         cls.overlapping_interfaces = list(list(cls.pg_interfaces[4:7]))
1437         cls.vapi.ip_table_add_del(is_add=1, table={'table_id': 10})
1438         cls.vapi.ip_table_add_del(is_add=1, table={'table_id': 20})
1439
1440         cls.pg4._local_ip4 = "172.16.255.1"
1441         cls.pg4._remote_hosts[0]._ip4 = "172.16.255.2"
1442         cls.pg4.set_table_ip4(10)
1443         cls.pg5._local_ip4 = "172.17.255.3"
1444         cls.pg5._remote_hosts[0]._ip4 = "172.17.255.4"
1445         cls.pg5.set_table_ip4(10)
1446         cls.pg6._local_ip4 = "172.16.255.1"
1447         cls.pg6._remote_hosts[0]._ip4 = "172.16.255.2"
1448         cls.pg6.set_table_ip4(20)
1449         for i in cls.overlapping_interfaces:
1450             i.config_ip4()
1451             i.admin_up()
1452             i.resolve_arp()
1453
1454         cls.pg7.admin_up()
1455         cls.pg8.admin_up()
1456
1457         cls.pg9.generate_remote_hosts(2)
1458         cls.pg9.config_ip4()
1459         cls.vapi.sw_interface_add_del_address(
1460             sw_if_index=cls.pg9.sw_if_index,
1461             prefix="10.0.0.1/24")
1462
1463         cls.pg9.admin_up()
1464         cls.pg9.resolve_arp()
1465         cls.pg9._remote_hosts[1]._ip4 = cls.pg9._remote_hosts[0]._ip4
1466         cls.pg4._remote_ip4 = cls.pg9._remote_hosts[0]._ip4 = "10.0.0.2"
1467         cls.pg9.resolve_arp()
1468
1469     @classmethod
1470     def tearDownClass(cls):
1471         super(TestNAT44, cls).tearDownClass()
1472
1473     def test_clear_sessions(self):
1474         """ NAT44 session clearing test """
1475
1476         self.nat44_add_address(self.nat_addr)
1477         flags = self.config_flags.NAT_IS_INSIDE
1478         self.vapi.nat44_interface_add_del_feature(
1479             sw_if_index=self.pg0.sw_if_index,
1480             flags=flags, is_add=1)
1481         self.vapi.nat44_interface_add_del_feature(
1482             sw_if_index=self.pg1.sw_if_index,
1483             is_add=1)
1484
1485         nat_config = self.vapi.nat_show_config()
1486         self.assertEqual(0, nat_config.endpoint_dependent)
1487
1488         pkts = self.create_stream_in(self.pg0, self.pg1)
1489         self.pg0.add_stream(pkts)
1490         self.pg_enable_capture(self.pg_interfaces)
1491         self.pg_start()
1492         capture = self.pg1.get_capture(len(pkts))
1493         self.verify_capture_out(capture)
1494
1495         sessions = self.statistics.get_counter('/nat44/total-sessions')
1496         self.assertTrue(sessions[0][0] > 0)
1497         self.logger.info("sessions before clearing: %s" % sessions[0][0])
1498
1499         self.vapi.cli("clear nat44 sessions")
1500
1501         sessions = self.statistics.get_counter('/nat44/total-sessions')
1502         self.assertEqual(sessions[0][0], 0)
1503         self.logger.info("sessions after clearing: %s" % sessions[0][0])
1504
1505     def test_dynamic(self):
1506         """ NAT44 dynamic translation test """
1507         self.nat44_add_address(self.nat_addr)
1508         flags = self.config_flags.NAT_IS_INSIDE
1509         self.vapi.nat44_interface_add_del_feature(
1510             sw_if_index=self.pg0.sw_if_index,
1511             flags=flags, is_add=1)
1512         self.vapi.nat44_interface_add_del_feature(
1513             sw_if_index=self.pg1.sw_if_index,
1514             is_add=1)
1515
1516         # in2out
1517         tcpn = self.statistics.get_counter('/nat44/in2out/slowpath/tcp')[0]
1518         udpn = self.statistics.get_counter('/nat44/in2out/slowpath/udp')[0]
1519         icmpn = self.statistics.get_counter('/nat44/in2out/slowpath/icmp')[0]
1520         drops = self.statistics.get_counter('/nat44/in2out/slowpath/drops')[0]
1521
1522         pkts = self.create_stream_in(self.pg0, self.pg1)
1523         self.pg0.add_stream(pkts)
1524         self.pg_enable_capture(self.pg_interfaces)
1525         self.pg_start()
1526         capture = self.pg1.get_capture(len(pkts))
1527         self.verify_capture_out(capture)
1528
1529         if_idx = self.pg0.sw_if_index
1530         cnt = self.statistics.get_counter('/nat44/in2out/slowpath/tcp')[0]
1531         self.assertEqual(cnt[if_idx] - tcpn[if_idx], 2)
1532         cnt = self.statistics.get_counter('/nat44/in2out/slowpath/udp')[0]
1533         self.assertEqual(cnt[if_idx] - udpn[if_idx], 1)
1534         cnt = self.statistics.get_counter('/nat44/in2out/slowpath/icmp')[0]
1535         self.assertEqual(cnt[if_idx] - icmpn[if_idx], 1)
1536         cnt = self.statistics.get_counter('/nat44/in2out/slowpath/drops')[0]
1537         self.assertEqual(cnt[if_idx] - drops[if_idx], 0)
1538
1539         # out2in
1540         tcpn = self.statistics.get_counter('/nat44/out2in/slowpath/tcp')[0]
1541         udpn = self.statistics.get_counter('/nat44/out2in/slowpath/udp')[0]
1542         icmpn = self.statistics.get_counter('/nat44/out2in/slowpath/icmp')[0]
1543         drops = self.statistics.get_counter('/nat44/out2in/slowpath/drops')[0]
1544
1545         pkts = self.create_stream_out(self.pg1)
1546         self.pg1.add_stream(pkts)
1547         self.pg_enable_capture(self.pg_interfaces)
1548         self.pg_start()
1549         capture = self.pg0.get_capture(len(pkts))
1550         self.verify_capture_in(capture, self.pg0)
1551
1552         if_idx = self.pg1.sw_if_index
1553         cnt = self.statistics.get_counter('/nat44/out2in/slowpath/tcp')[0]
1554         self.assertEqual(cnt[if_idx] - tcpn[if_idx], 2)
1555         cnt = self.statistics.get_counter('/nat44/out2in/slowpath/udp')[0]
1556         self.assertEqual(cnt[if_idx] - udpn[if_idx], 1)
1557         cnt = self.statistics.get_counter('/nat44/out2in/slowpath/icmp')[0]
1558         self.assertEqual(cnt[if_idx] - icmpn[if_idx], 1)
1559         cnt = self.statistics.get_counter('/nat44/out2in/slowpath/drops')[0]
1560         self.assertEqual(cnt[if_idx] - drops[if_idx], 0)
1561
1562         users = self.statistics.get_counter('/nat44/total-users')
1563         self.assertEqual(users[0][0], 1)
1564         sessions = self.statistics.get_counter('/nat44/total-sessions')
1565         self.assertEqual(sessions[0][0], 3)
1566
1567     def test_dynamic_icmp_errors_in2out_ttl_1(self):
1568         """ NAT44 handling of client packets with TTL=1 """
1569
1570         self.nat44_add_address(self.nat_addr)
1571         flags = self.config_flags.NAT_IS_INSIDE
1572         self.vapi.nat44_interface_add_del_feature(
1573             sw_if_index=self.pg0.sw_if_index,
1574             flags=flags, is_add=1)
1575         self.vapi.nat44_interface_add_del_feature(
1576             sw_if_index=self.pg1.sw_if_index,
1577             is_add=1)
1578
1579         # Client side - generate traffic
1580         pkts = self.create_stream_in(self.pg0, self.pg1, ttl=1)
1581         self.pg0.add_stream(pkts)
1582         self.pg_enable_capture(self.pg_interfaces)
1583         self.pg_start()
1584
1585         # Client side - verify ICMP type 11 packets
1586         capture = self.pg0.get_capture(len(pkts))
1587         self.verify_capture_in_with_icmp_errors(capture, self.pg0)
1588
1589     def test_dynamic_icmp_errors_out2in_ttl_1(self):
1590         """ NAT44 handling of server packets with TTL=1 """
1591
1592         self.nat44_add_address(self.nat_addr)
1593         flags = self.config_flags.NAT_IS_INSIDE
1594         self.vapi.nat44_interface_add_del_feature(
1595             sw_if_index=self.pg0.sw_if_index,
1596             flags=flags, is_add=1)
1597         self.vapi.nat44_interface_add_del_feature(
1598             sw_if_index=self.pg1.sw_if_index,
1599             is_add=1)
1600
1601         # Client side - create sessions
1602         pkts = self.create_stream_in(self.pg0, self.pg1)
1603         self.pg0.add_stream(pkts)
1604         self.pg_enable_capture(self.pg_interfaces)
1605         self.pg_start()
1606
1607         # Server side - generate traffic
1608         capture = self.pg1.get_capture(len(pkts))
1609         self.verify_capture_out(capture)
1610         pkts = self.create_stream_out(self.pg1, ttl=1)
1611         self.pg1.add_stream(pkts)
1612         self.pg_enable_capture(self.pg_interfaces)
1613         self.pg_start()
1614
1615         # Server side - verify ICMP type 11 packets
1616         capture = self.pg1.get_capture(len(pkts))
1617         self.verify_capture_out_with_icmp_errors(capture,
1618                                                  src_ip=self.pg1.local_ip4)
1619
1620     def test_dynamic_icmp_errors_in2out_ttl_2(self):
1621         """ NAT44 handling of error responses to client packets with TTL=2 """
1622
1623         self.nat44_add_address(self.nat_addr)
1624         flags = self.config_flags.NAT_IS_INSIDE
1625         self.vapi.nat44_interface_add_del_feature(
1626             sw_if_index=self.pg0.sw_if_index,
1627             flags=flags, is_add=1)
1628         self.vapi.nat44_interface_add_del_feature(
1629             sw_if_index=self.pg1.sw_if_index,
1630             is_add=1)
1631
1632         # Client side - generate traffic
1633         pkts = self.create_stream_in(self.pg0, self.pg1, ttl=2)
1634         self.pg0.add_stream(pkts)
1635         self.pg_enable_capture(self.pg_interfaces)
1636         self.pg_start()
1637
1638         # Server side - simulate ICMP type 11 response
1639         capture = self.pg1.get_capture(len(pkts))
1640         pkts = [Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
1641                 IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
1642                 ICMP(type=11) / packet[IP] for packet in capture]
1643         self.pg1.add_stream(pkts)
1644         self.pg_enable_capture(self.pg_interfaces)
1645         self.pg_start()
1646
1647         # Client side - verify ICMP type 11 packets
1648         capture = self.pg0.get_capture(len(pkts))
1649         self.verify_capture_in_with_icmp_errors(capture, self.pg0)
1650
1651     def test_dynamic_icmp_errors_out2in_ttl_2(self):
1652         """ NAT44 handling of error responses to server packets with TTL=2 """
1653
1654         self.nat44_add_address(self.nat_addr)
1655         flags = self.config_flags.NAT_IS_INSIDE
1656         self.vapi.nat44_interface_add_del_feature(
1657             sw_if_index=self.pg0.sw_if_index,
1658             flags=flags, is_add=1)
1659         self.vapi.nat44_interface_add_del_feature(
1660             sw_if_index=self.pg1.sw_if_index,
1661             is_add=1)
1662
1663         # Client side - create sessions
1664         pkts = self.create_stream_in(self.pg0, self.pg1)
1665         self.pg0.add_stream(pkts)
1666         self.pg_enable_capture(self.pg_interfaces)
1667         self.pg_start()
1668
1669         # Server side - generate traffic
1670         capture = self.pg1.get_capture(len(pkts))
1671         self.verify_capture_out(capture)
1672         pkts = self.create_stream_out(self.pg1, ttl=2)
1673         self.pg1.add_stream(pkts)
1674         self.pg_enable_capture(self.pg_interfaces)
1675         self.pg_start()
1676
1677         # Client side - simulate ICMP type 11 response
1678         capture = self.pg0.get_capture(len(pkts))
1679         pkts = [Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
1680                 IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
1681                 ICMP(type=11) / packet[IP] for packet in capture]
1682         self.pg0.add_stream(pkts)
1683         self.pg_enable_capture(self.pg_interfaces)
1684         self.pg_start()
1685
1686         # Server side - verify ICMP type 11 packets
1687         capture = self.pg1.get_capture(len(pkts))
1688         self.verify_capture_out_with_icmp_errors(capture)
1689
1690     def test_ping_out_interface_from_outside(self):
1691         """ Ping NAT44 out interface from outside network """
1692
1693         self.nat44_add_address(self.nat_addr)
1694         flags = self.config_flags.NAT_IS_INSIDE
1695         self.vapi.nat44_interface_add_del_feature(
1696             sw_if_index=self.pg0.sw_if_index,
1697             flags=flags, is_add=1)
1698         self.vapi.nat44_interface_add_del_feature(
1699             sw_if_index=self.pg1.sw_if_index,
1700             is_add=1)
1701
1702         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
1703              IP(src=self.pg1.remote_ip4, dst=self.pg1.local_ip4) /
1704              ICMP(id=self.icmp_id_out, type='echo-request'))
1705         pkts = [p]
1706         self.pg1.add_stream(pkts)
1707         self.pg_enable_capture(self.pg_interfaces)
1708         self.pg_start()
1709         capture = self.pg1.get_capture(len(pkts))
1710         packet = capture[0]
1711         try:
1712             self.assertEqual(packet[IP].src, self.pg1.local_ip4)
1713             self.assertEqual(packet[IP].dst, self.pg1.remote_ip4)
1714             self.assertEqual(packet[ICMP].id, self.icmp_id_in)
1715             self.assertEqual(packet[ICMP].type, 0)  # echo reply
1716         except:
1717             self.logger.error(ppp("Unexpected or invalid packet "
1718                                   "(outside network):", packet))
1719             raise
1720
1721     def test_ping_internal_host_from_outside(self):
1722         """ Ping internal host from outside network """
1723
1724         self.nat44_add_static_mapping(self.pg0.remote_ip4, self.nat_addr)
1725         flags = self.config_flags.NAT_IS_INSIDE
1726         self.vapi.nat44_interface_add_del_feature(
1727             sw_if_index=self.pg0.sw_if_index,
1728             flags=flags, is_add=1)
1729         self.vapi.nat44_interface_add_del_feature(
1730             sw_if_index=self.pg1.sw_if_index,
1731             is_add=1)
1732
1733         # out2in
1734         pkt = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
1735                IP(src=self.pg1.remote_ip4, dst=self.nat_addr, ttl=64) /
1736                ICMP(id=self.icmp_id_out, type='echo-request'))
1737         self.pg1.add_stream(pkt)
1738         self.pg_enable_capture(self.pg_interfaces)
1739         self.pg_start()
1740         capture = self.pg0.get_capture(1)
1741         self.verify_capture_in(capture, self.pg0)
1742         self.assert_equal(capture[0][IP].proto, IP_PROTOS.icmp)
1743
1744         # in2out
1745         pkt = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
1746                IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4, ttl=64) /
1747                ICMP(id=self.icmp_id_in, type='echo-reply'))
1748         self.pg0.add_stream(pkt)
1749         self.pg_enable_capture(self.pg_interfaces)
1750         self.pg_start()
1751         capture = self.pg1.get_capture(1)
1752         self.verify_capture_out(capture, same_port=True)
1753         self.assert_equal(capture[0][IP].proto, IP_PROTOS.icmp)
1754
1755     def test_forwarding(self):
1756         """ NAT44 forwarding test """
1757
1758         flags = self.config_flags.NAT_IS_INSIDE
1759         self.vapi.nat44_interface_add_del_feature(
1760             sw_if_index=self.pg0.sw_if_index,
1761             flags=flags, is_add=1)
1762         self.vapi.nat44_interface_add_del_feature(
1763             sw_if_index=self.pg1.sw_if_index,
1764             is_add=1)
1765         self.vapi.nat44_forwarding_enable_disable(enable=1)
1766
1767         real_ip = self.pg0.remote_ip4
1768         alias_ip = self.nat_addr
1769         flags = self.config_flags.NAT_IS_ADDR_ONLY
1770         self.vapi.nat44_add_del_static_mapping(is_add=1,
1771                                                local_ip_address=real_ip,
1772                                                external_ip_address=alias_ip,
1773                                                external_sw_if_index=0xFFFFFFFF,
1774                                                flags=flags)
1775
1776         try:
1777             # static mapping match
1778
1779             pkts = self.create_stream_out(self.pg1)
1780             self.pg1.add_stream(pkts)
1781             self.pg_enable_capture(self.pg_interfaces)
1782             self.pg_start()
1783             capture = self.pg0.get_capture(len(pkts))
1784             self.verify_capture_in(capture, self.pg0)
1785
1786             pkts = self.create_stream_in(self.pg0, self.pg1)
1787             self.pg0.add_stream(pkts)
1788             self.pg_enable_capture(self.pg_interfaces)
1789             self.pg_start()
1790             capture = self.pg1.get_capture(len(pkts))
1791             self.verify_capture_out(capture, same_port=True)
1792
1793             # no static mapping match
1794
1795             host0 = self.pg0.remote_hosts[0]
1796             self.pg0.remote_hosts[0] = self.pg0.remote_hosts[1]
1797             try:
1798                 pkts = self.create_stream_out(self.pg1,
1799                                               dst_ip=self.pg0.remote_ip4,
1800                                               use_inside_ports=True)
1801                 self.pg1.add_stream(pkts)
1802                 self.pg_enable_capture(self.pg_interfaces)
1803                 self.pg_start()
1804                 capture = self.pg0.get_capture(len(pkts))
1805                 self.verify_capture_in(capture, self.pg0)
1806
1807                 pkts = self.create_stream_in(self.pg0, self.pg1)
1808                 self.pg0.add_stream(pkts)
1809                 self.pg_enable_capture(self.pg_interfaces)
1810                 self.pg_start()
1811                 capture = self.pg1.get_capture(len(pkts))
1812                 self.verify_capture_out(capture, nat_ip=self.pg0.remote_ip4,
1813                                         same_port=True)
1814             finally:
1815                 self.pg0.remote_hosts[0] = host0
1816
1817         finally:
1818             self.vapi.nat44_forwarding_enable_disable(enable=0)
1819             flags = self.config_flags.NAT_IS_ADDR_ONLY
1820             self.vapi.nat44_add_del_static_mapping(
1821                 is_add=0,
1822                 local_ip_address=real_ip,
1823                 external_ip_address=alias_ip,
1824                 external_sw_if_index=0xFFFFFFFF,
1825                 flags=flags)
1826
1827     def test_static_in(self):
1828         """ 1:1 NAT initialized from inside network """
1829
1830         nat_ip = "10.0.0.10"
1831         self.tcp_port_out = 6303
1832         self.udp_port_out = 6304
1833         self.icmp_id_out = 6305
1834
1835         self.nat44_add_static_mapping(self.pg0.remote_ip4, nat_ip)
1836         flags = self.config_flags.NAT_IS_INSIDE
1837         self.vapi.nat44_interface_add_del_feature(
1838             sw_if_index=self.pg0.sw_if_index,
1839             flags=flags, is_add=1)
1840         self.vapi.nat44_interface_add_del_feature(
1841             sw_if_index=self.pg1.sw_if_index,
1842             is_add=1)
1843         sm = self.vapi.nat44_static_mapping_dump()
1844         self.assertEqual(len(sm), 1)
1845         self.assertEqual(sm[0].tag, '')
1846         self.assertEqual(sm[0].protocol, 0)
1847         self.assertEqual(sm[0].local_port, 0)
1848         self.assertEqual(sm[0].external_port, 0)
1849
1850         # in2out
1851         pkts = self.create_stream_in(self.pg0, self.pg1)
1852         self.pg0.add_stream(pkts)
1853         self.pg_enable_capture(self.pg_interfaces)
1854         self.pg_start()
1855         capture = self.pg1.get_capture(len(pkts))
1856         self.verify_capture_out(capture, nat_ip, True)
1857
1858         # out2in
1859         pkts = self.create_stream_out(self.pg1, nat_ip)
1860         self.pg1.add_stream(pkts)
1861         self.pg_enable_capture(self.pg_interfaces)
1862         self.pg_start()
1863         capture = self.pg0.get_capture(len(pkts))
1864         self.verify_capture_in(capture, self.pg0)
1865
1866     def test_static_out(self):
1867         """ 1:1 NAT initialized from outside network """
1868
1869         nat_ip = "10.0.0.20"
1870         self.tcp_port_out = 6303
1871         self.udp_port_out = 6304
1872         self.icmp_id_out = 6305
1873         tag = "testTAG"
1874
1875         self.nat44_add_static_mapping(self.pg0.remote_ip4, nat_ip, tag=tag)
1876         flags = self.config_flags.NAT_IS_INSIDE
1877         self.vapi.nat44_interface_add_del_feature(
1878             sw_if_index=self.pg0.sw_if_index,
1879             flags=flags, is_add=1)
1880         self.vapi.nat44_interface_add_del_feature(
1881             sw_if_index=self.pg1.sw_if_index,
1882             is_add=1)
1883         sm = self.vapi.nat44_static_mapping_dump()
1884         self.assertEqual(len(sm), 1)
1885         self.assertEqual(sm[0].tag, tag)
1886
1887         # out2in
1888         pkts = self.create_stream_out(self.pg1, nat_ip)
1889         self.pg1.add_stream(pkts)
1890         self.pg_enable_capture(self.pg_interfaces)
1891         self.pg_start()
1892         capture = self.pg0.get_capture(len(pkts))
1893         self.verify_capture_in(capture, self.pg0)
1894
1895         # in2out
1896         pkts = self.create_stream_in(self.pg0, self.pg1)
1897         self.pg0.add_stream(pkts)
1898         self.pg_enable_capture(self.pg_interfaces)
1899         self.pg_start()
1900         capture = self.pg1.get_capture(len(pkts))
1901         self.verify_capture_out(capture, nat_ip, True)
1902
1903     def test_static_with_port_in(self):
1904         """ 1:1 NAPT initialized from inside network """
1905
1906         self.tcp_port_out = 3606
1907         self.udp_port_out = 3607
1908         self.icmp_id_out = 3608
1909
1910         self.nat44_add_address(self.nat_addr)
1911         self.nat44_add_static_mapping(self.pg0.remote_ip4, self.nat_addr,
1912                                       self.tcp_port_in, self.tcp_port_out,
1913                                       proto=IP_PROTOS.tcp)
1914         self.nat44_add_static_mapping(self.pg0.remote_ip4, self.nat_addr,
1915                                       self.udp_port_in, self.udp_port_out,
1916                                       proto=IP_PROTOS.udp)
1917         self.nat44_add_static_mapping(self.pg0.remote_ip4, self.nat_addr,
1918                                       self.icmp_id_in, self.icmp_id_out,
1919                                       proto=IP_PROTOS.icmp)
1920         flags = self.config_flags.NAT_IS_INSIDE
1921         self.vapi.nat44_interface_add_del_feature(
1922             sw_if_index=self.pg0.sw_if_index,
1923             flags=flags, is_add=1)
1924         self.vapi.nat44_interface_add_del_feature(
1925             sw_if_index=self.pg1.sw_if_index,
1926             is_add=1)
1927
1928         # in2out
1929         pkts = self.create_stream_in(self.pg0, self.pg1)
1930         self.pg0.add_stream(pkts)
1931         self.pg_enable_capture(self.pg_interfaces)
1932         self.pg_start()
1933         capture = self.pg1.get_capture(len(pkts))
1934         self.verify_capture_out(capture)
1935
1936         # out2in
1937         pkts = self.create_stream_out(self.pg1)
1938         self.pg1.add_stream(pkts)
1939         self.pg_enable_capture(self.pg_interfaces)
1940         self.pg_start()
1941         capture = self.pg0.get_capture(len(pkts))
1942         self.verify_capture_in(capture, self.pg0)
1943
1944     def test_static_with_port_out(self):
1945         """ 1:1 NAPT initialized from outside network """
1946
1947         self.tcp_port_out = 30606
1948         self.udp_port_out = 30607
1949         self.icmp_id_out = 30608
1950
1951         self.nat44_add_address(self.nat_addr)
1952         self.nat44_add_static_mapping(self.pg0.remote_ip4, self.nat_addr,
1953                                       self.tcp_port_in, self.tcp_port_out,
1954                                       proto=IP_PROTOS.tcp)
1955         self.nat44_add_static_mapping(self.pg0.remote_ip4, self.nat_addr,
1956                                       self.udp_port_in, self.udp_port_out,
1957                                       proto=IP_PROTOS.udp)
1958         self.nat44_add_static_mapping(self.pg0.remote_ip4, self.nat_addr,
1959                                       self.icmp_id_in, self.icmp_id_out,
1960                                       proto=IP_PROTOS.icmp)
1961         flags = self.config_flags.NAT_IS_INSIDE
1962         self.vapi.nat44_interface_add_del_feature(
1963             sw_if_index=self.pg0.sw_if_index,
1964             flags=flags, is_add=1)
1965         self.vapi.nat44_interface_add_del_feature(
1966             sw_if_index=self.pg1.sw_if_index,
1967             is_add=1)
1968
1969         # out2in
1970         pkts = self.create_stream_out(self.pg1)
1971         self.pg1.add_stream(pkts)
1972         self.pg_enable_capture(self.pg_interfaces)
1973         self.pg_start()
1974         capture = self.pg0.get_capture(len(pkts))
1975         self.verify_capture_in(capture, self.pg0)
1976
1977         # in2out
1978         pkts = self.create_stream_in(self.pg0, self.pg1)
1979         self.pg0.add_stream(pkts)
1980         self.pg_enable_capture(self.pg_interfaces)
1981         self.pg_start()
1982         capture = self.pg1.get_capture(len(pkts))
1983         self.verify_capture_out(capture)
1984
1985     def test_static_vrf_aware(self):
1986         """ 1:1 NAT VRF awareness """
1987
1988         nat_ip1 = "10.0.0.30"
1989         nat_ip2 = "10.0.0.40"
1990         self.tcp_port_out = 6303
1991         self.udp_port_out = 6304
1992         self.icmp_id_out = 6305
1993
1994         self.nat44_add_static_mapping(self.pg4.remote_ip4, nat_ip1,
1995                                       vrf_id=10)
1996         self.nat44_add_static_mapping(self.pg0.remote_ip4, nat_ip2,
1997                                       vrf_id=10)
1998         flags = self.config_flags.NAT_IS_INSIDE
1999         self.vapi.nat44_interface_add_del_feature(
2000             sw_if_index=self.pg3.sw_if_index,
2001             is_add=1)
2002         self.vapi.nat44_interface_add_del_feature(
2003             sw_if_index=self.pg0.sw_if_index,
2004             flags=flags, is_add=1)
2005         self.vapi.nat44_interface_add_del_feature(
2006             sw_if_index=self.pg4.sw_if_index,
2007             flags=flags, is_add=1)
2008
2009         # inside interface VRF match NAT44 static mapping VRF
2010         pkts = self.create_stream_in(self.pg4, self.pg3)
2011         self.pg4.add_stream(pkts)
2012         self.pg_enable_capture(self.pg_interfaces)
2013         self.pg_start()
2014         capture = self.pg3.get_capture(len(pkts))
2015         self.verify_capture_out(capture, nat_ip1, True)
2016
2017         # inside interface VRF don't match NAT44 static mapping VRF (packets
2018         # are dropped)
2019         pkts = self.create_stream_in(self.pg0, self.pg3)
2020         self.pg0.add_stream(pkts)
2021         self.pg_enable_capture(self.pg_interfaces)
2022         self.pg_start()
2023         self.pg3.assert_nothing_captured()
2024
2025     def test_dynamic_to_static(self):
2026         """ Switch from dynamic translation to 1:1NAT """
2027         nat_ip = "10.0.0.10"
2028         self.tcp_port_out = 6303
2029         self.udp_port_out = 6304
2030         self.icmp_id_out = 6305
2031
2032         self.nat44_add_address(self.nat_addr)
2033         flags = self.config_flags.NAT_IS_INSIDE
2034         self.vapi.nat44_interface_add_del_feature(
2035             sw_if_index=self.pg0.sw_if_index,
2036             flags=flags, is_add=1)
2037         self.vapi.nat44_interface_add_del_feature(
2038             sw_if_index=self.pg1.sw_if_index,
2039             is_add=1)
2040
2041         # dynamic
2042         pkts = self.create_stream_in(self.pg0, self.pg1)
2043         self.pg0.add_stream(pkts)
2044         self.pg_enable_capture(self.pg_interfaces)
2045         self.pg_start()
2046         capture = self.pg1.get_capture(len(pkts))
2047         self.verify_capture_out(capture)
2048
2049         # 1:1NAT
2050         self.nat44_add_static_mapping(self.pg0.remote_ip4, nat_ip)
2051         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
2052         self.assertEqual(len(sessions), 0)
2053         pkts = self.create_stream_in(self.pg0, self.pg1)
2054         self.pg0.add_stream(pkts)
2055         self.pg_enable_capture(self.pg_interfaces)
2056         self.pg_start()
2057         capture = self.pg1.get_capture(len(pkts))
2058         self.verify_capture_out(capture, nat_ip, True)
2059
2060     def test_identity_nat(self):
2061         """ Identity NAT """
2062         flags = self.config_flags.NAT_IS_ADDR_ONLY
2063         self.vapi.nat44_add_del_identity_mapping(
2064             ip_address=self.pg0.remote_ip4, sw_if_index=0xFFFFFFFF,
2065             flags=flags, is_add=1)
2066         flags = self.config_flags.NAT_IS_INSIDE
2067         self.vapi.nat44_interface_add_del_feature(
2068             sw_if_index=self.pg0.sw_if_index,
2069             flags=flags, is_add=1)
2070         self.vapi.nat44_interface_add_del_feature(
2071             sw_if_index=self.pg1.sw_if_index,
2072             is_add=1)
2073
2074         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
2075              IP(src=self.pg1.remote_ip4, dst=self.pg0.remote_ip4) /
2076              TCP(sport=12345, dport=56789))
2077         self.pg1.add_stream(p)
2078         self.pg_enable_capture(self.pg_interfaces)
2079         self.pg_start()
2080         capture = self.pg0.get_capture(1)
2081         p = capture[0]
2082         try:
2083             ip = p[IP]
2084             tcp = p[TCP]
2085             self.assertEqual(ip.dst, self.pg0.remote_ip4)
2086             self.assertEqual(ip.src, self.pg1.remote_ip4)
2087             self.assertEqual(tcp.dport, 56789)
2088             self.assertEqual(tcp.sport, 12345)
2089             self.assert_packet_checksums_valid(p)
2090         except:
2091             self.logger.error(ppp("Unexpected or invalid packet:", p))
2092             raise
2093
2094         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
2095         self.assertEqual(len(sessions), 0)
2096         flags = self.config_flags.NAT_IS_ADDR_ONLY
2097         self.vapi.nat44_add_del_identity_mapping(
2098             ip_address=self.pg0.remote_ip4, sw_if_index=0xFFFFFFFF,
2099             flags=flags, vrf_id=1, is_add=1)
2100         identity_mappings = self.vapi.nat44_identity_mapping_dump()
2101         self.assertEqual(len(identity_mappings), 2)
2102
2103     def test_multiple_inside_interfaces(self):
2104         """ NAT44 multiple non-overlapping address space inside interfaces """
2105
2106         self.nat44_add_address(self.nat_addr)
2107         flags = self.config_flags.NAT_IS_INSIDE
2108         self.vapi.nat44_interface_add_del_feature(
2109             sw_if_index=self.pg0.sw_if_index,
2110             flags=flags, is_add=1)
2111         self.vapi.nat44_interface_add_del_feature(
2112             sw_if_index=self.pg1.sw_if_index,
2113             flags=flags, is_add=1)
2114         self.vapi.nat44_interface_add_del_feature(
2115             sw_if_index=self.pg3.sw_if_index,
2116             is_add=1)
2117
2118         # between two NAT44 inside interfaces (no translation)
2119         pkts = self.create_stream_in(self.pg0, self.pg1)
2120         self.pg0.add_stream(pkts)
2121         self.pg_enable_capture(self.pg_interfaces)
2122         self.pg_start()
2123         capture = self.pg1.get_capture(len(pkts))
2124         self.verify_capture_no_translation(capture, self.pg0, self.pg1)
2125
2126         # from NAT44 inside to interface without NAT44 feature (no translation)
2127         pkts = self.create_stream_in(self.pg0, self.pg2)
2128         self.pg0.add_stream(pkts)
2129         self.pg_enable_capture(self.pg_interfaces)
2130         self.pg_start()
2131         capture = self.pg2.get_capture(len(pkts))
2132         self.verify_capture_no_translation(capture, self.pg0, self.pg2)
2133
2134         # in2out 1st interface
2135         pkts = self.create_stream_in(self.pg0, self.pg3)
2136         self.pg0.add_stream(pkts)
2137         self.pg_enable_capture(self.pg_interfaces)
2138         self.pg_start()
2139         capture = self.pg3.get_capture(len(pkts))
2140         self.verify_capture_out(capture)
2141
2142         # out2in 1st interface
2143         pkts = self.create_stream_out(self.pg3)
2144         self.pg3.add_stream(pkts)
2145         self.pg_enable_capture(self.pg_interfaces)
2146         self.pg_start()
2147         capture = self.pg0.get_capture(len(pkts))
2148         self.verify_capture_in(capture, self.pg0)
2149
2150         # in2out 2nd interface
2151         pkts = self.create_stream_in(self.pg1, self.pg3)
2152         self.pg1.add_stream(pkts)
2153         self.pg_enable_capture(self.pg_interfaces)
2154         self.pg_start()
2155         capture = self.pg3.get_capture(len(pkts))
2156         self.verify_capture_out(capture)
2157
2158         # out2in 2nd interface
2159         pkts = self.create_stream_out(self.pg3)
2160         self.pg3.add_stream(pkts)
2161         self.pg_enable_capture(self.pg_interfaces)
2162         self.pg_start()
2163         capture = self.pg1.get_capture(len(pkts))
2164         self.verify_capture_in(capture, self.pg1)
2165
2166     def test_inside_overlapping_interfaces(self):
2167         """ NAT44 multiple inside interfaces with overlapping address space """
2168
2169         static_nat_ip = "10.0.0.10"
2170         self.nat44_add_address(self.nat_addr)
2171         flags = self.config_flags.NAT_IS_INSIDE
2172         self.vapi.nat44_interface_add_del_feature(
2173             sw_if_index=self.pg3.sw_if_index,
2174             is_add=1)
2175         self.vapi.nat44_interface_add_del_feature(
2176             sw_if_index=self.pg4.sw_if_index,
2177             flags=flags, is_add=1)
2178         self.vapi.nat44_interface_add_del_feature(
2179             sw_if_index=self.pg5.sw_if_index,
2180             flags=flags, is_add=1)
2181         self.vapi.nat44_interface_add_del_feature(
2182             sw_if_index=self.pg6.sw_if_index,
2183             flags=flags, is_add=1)
2184         self.nat44_add_static_mapping(self.pg6.remote_ip4, static_nat_ip,
2185                                       vrf_id=20)
2186
2187         # between NAT44 inside interfaces with same VRF (no translation)
2188         pkts = self.create_stream_in(self.pg4, self.pg5)
2189         self.pg4.add_stream(pkts)
2190         self.pg_enable_capture(self.pg_interfaces)
2191         self.pg_start()
2192         capture = self.pg5.get_capture(len(pkts))
2193         self.verify_capture_no_translation(capture, self.pg4, self.pg5)
2194
2195         # between NAT44 inside interfaces with different VRF (hairpinning)
2196         p = (Ether(src=self.pg4.remote_mac, dst=self.pg4.local_mac) /
2197              IP(src=self.pg4.remote_ip4, dst=static_nat_ip) /
2198              TCP(sport=1234, dport=5678))
2199         self.pg4.add_stream(p)
2200         self.pg_enable_capture(self.pg_interfaces)
2201         self.pg_start()
2202         capture = self.pg6.get_capture(1)
2203         p = capture[0]
2204         try:
2205             ip = p[IP]
2206             tcp = p[TCP]
2207             self.assertEqual(ip.src, self.nat_addr)
2208             self.assertEqual(ip.dst, self.pg6.remote_ip4)
2209             self.assertNotEqual(tcp.sport, 1234)
2210             self.assertEqual(tcp.dport, 5678)
2211         except:
2212             self.logger.error(ppp("Unexpected or invalid packet:", p))
2213             raise
2214
2215         # in2out 1st interface
2216         pkts = self.create_stream_in(self.pg4, self.pg3)
2217         self.pg4.add_stream(pkts)
2218         self.pg_enable_capture(self.pg_interfaces)
2219         self.pg_start()
2220         capture = self.pg3.get_capture(len(pkts))
2221         self.verify_capture_out(capture)
2222
2223         # out2in 1st interface
2224         pkts = self.create_stream_out(self.pg3)
2225         self.pg3.add_stream(pkts)
2226         self.pg_enable_capture(self.pg_interfaces)
2227         self.pg_start()
2228         capture = self.pg4.get_capture(len(pkts))
2229         self.verify_capture_in(capture, self.pg4)
2230
2231         # in2out 2nd interface
2232         pkts = self.create_stream_in(self.pg5, self.pg3)
2233         self.pg5.add_stream(pkts)
2234         self.pg_enable_capture(self.pg_interfaces)
2235         self.pg_start()
2236         capture = self.pg3.get_capture(len(pkts))
2237         self.verify_capture_out(capture)
2238
2239         # out2in 2nd interface
2240         pkts = self.create_stream_out(self.pg3)
2241         self.pg3.add_stream(pkts)
2242         self.pg_enable_capture(self.pg_interfaces)
2243         self.pg_start()
2244         capture = self.pg5.get_capture(len(pkts))
2245         self.verify_capture_in(capture, self.pg5)
2246
2247         # pg5 session dump
2248         addresses = self.vapi.nat44_address_dump()
2249         self.assertEqual(len(addresses), 1)
2250         sessions = self.vapi.nat44_user_session_dump(self.pg5.remote_ip4, 10)
2251         self.assertEqual(len(sessions), 3)
2252         for session in sessions:
2253             self.assertFalse(session.flags & self.config_flags.NAT_IS_STATIC)
2254             self.assertEqual(str(session.inside_ip_address),
2255                              self.pg5.remote_ip4)
2256             self.assertEqual(session.outside_ip_address,
2257                              addresses[0].ip_address)
2258         self.assertEqual(sessions[0].protocol, IP_PROTOS.tcp)
2259         self.assertEqual(sessions[1].protocol, IP_PROTOS.udp)
2260         self.assertEqual(sessions[2].protocol, IP_PROTOS.icmp)
2261         self.assertEqual(sessions[0].inside_port, self.tcp_port_in)
2262         self.assertEqual(sessions[1].inside_port, self.udp_port_in)
2263         self.assertEqual(sessions[2].inside_port, self.icmp_id_in)
2264         self.assertEqual(sessions[0].outside_port, self.tcp_port_out)
2265         self.assertEqual(sessions[1].outside_port, self.udp_port_out)
2266         self.assertEqual(sessions[2].outside_port, self.icmp_id_out)
2267
2268         # in2out 3rd interface
2269         pkts = self.create_stream_in(self.pg6, self.pg3)
2270         self.pg6.add_stream(pkts)
2271         self.pg_enable_capture(self.pg_interfaces)
2272         self.pg_start()
2273         capture = self.pg3.get_capture(len(pkts))
2274         self.verify_capture_out(capture, static_nat_ip, True)
2275
2276         # out2in 3rd interface
2277         pkts = self.create_stream_out(self.pg3, static_nat_ip)
2278         self.pg3.add_stream(pkts)
2279         self.pg_enable_capture(self.pg_interfaces)
2280         self.pg_start()
2281         capture = self.pg6.get_capture(len(pkts))
2282         self.verify_capture_in(capture, self.pg6)
2283
2284         # general user and session dump verifications
2285         users = self.vapi.nat44_user_dump()
2286         self.assertGreaterEqual(len(users), 3)
2287         addresses = self.vapi.nat44_address_dump()
2288         self.assertEqual(len(addresses), 1)
2289         for user in users:
2290             sessions = self.vapi.nat44_user_session_dump(user.ip_address,
2291                                                          user.vrf_id)
2292             for session in sessions:
2293                 self.assertEqual(user.ip_address, session.inside_ip_address)
2294                 self.assertTrue(session.total_bytes > session.total_pkts > 0)
2295                 self.assertTrue(session.protocol in
2296                                 [IP_PROTOS.tcp, IP_PROTOS.udp,
2297                                  IP_PROTOS.icmp])
2298                 self.assertFalse(session.flags &
2299                                  self.config_flags.NAT_IS_EXT_HOST_VALID)
2300
2301         # pg4 session dump
2302         sessions = self.vapi.nat44_user_session_dump(self.pg4.remote_ip4, 10)
2303         self.assertGreaterEqual(len(sessions), 4)
2304         for session in sessions:
2305             self.assertFalse(session.flags & self.config_flags.NAT_IS_STATIC)
2306             self.assertEqual(str(session.inside_ip_address),
2307                              self.pg4.remote_ip4)
2308             self.assertEqual(session.outside_ip_address,
2309                              addresses[0].ip_address)
2310
2311         # pg6 session dump
2312         sessions = self.vapi.nat44_user_session_dump(self.pg6.remote_ip4, 20)
2313         self.assertGreaterEqual(len(sessions), 3)
2314         for session in sessions:
2315             self.assertTrue(session.flags & self.config_flags.NAT_IS_STATIC)
2316             self.assertEqual(str(session.inside_ip_address),
2317                              self.pg6.remote_ip4)
2318             self.assertEqual(str(session.outside_ip_address),
2319                              static_nat_ip)
2320             self.assertTrue(session.inside_port in
2321                             [self.tcp_port_in, self.udp_port_in,
2322                              self.icmp_id_in])
2323
2324     def test_hairpinning(self):
2325         """ NAT44 hairpinning - 1:1 NAPT """
2326
2327         host = self.pg0.remote_hosts[0]
2328         server = self.pg0.remote_hosts[1]
2329         host_in_port = 1234
2330         host_out_port = 0
2331         server_in_port = 5678
2332         server_out_port = 8765
2333
2334         self.nat44_add_address(self.nat_addr)
2335         flags = self.config_flags.NAT_IS_INSIDE
2336         self.vapi.nat44_interface_add_del_feature(
2337             sw_if_index=self.pg0.sw_if_index,
2338             flags=flags, is_add=1)
2339         self.vapi.nat44_interface_add_del_feature(
2340             sw_if_index=self.pg1.sw_if_index,
2341             is_add=1)
2342
2343         # add static mapping for server
2344         self.nat44_add_static_mapping(server.ip4, self.nat_addr,
2345                                       server_in_port, server_out_port,
2346                                       proto=IP_PROTOS.tcp)
2347
2348         cnt = self.statistics.get_counter('/nat44/hairpinning')[0]
2349         # send packet from host to server
2350         p = (Ether(src=host.mac, dst=self.pg0.local_mac) /
2351              IP(src=host.ip4, dst=self.nat_addr) /
2352              TCP(sport=host_in_port, dport=server_out_port))
2353         self.pg0.add_stream(p)
2354         self.pg_enable_capture(self.pg_interfaces)
2355         self.pg_start()
2356         capture = self.pg0.get_capture(1)
2357         p = capture[0]
2358         try:
2359             ip = p[IP]
2360             tcp = p[TCP]
2361             self.assertEqual(ip.src, self.nat_addr)
2362             self.assertEqual(ip.dst, server.ip4)
2363             self.assertNotEqual(tcp.sport, host_in_port)
2364             self.assertEqual(tcp.dport, server_in_port)
2365             self.assert_packet_checksums_valid(p)
2366             host_out_port = tcp.sport
2367         except:
2368             self.logger.error(ppp("Unexpected or invalid packet:", p))
2369             raise
2370
2371         after = self.statistics.get_counter('/nat44/hairpinning')[0]
2372         if_idx = self.pg0.sw_if_index
2373         self.assertEqual(after[if_idx] - cnt[if_idx], 1)
2374
2375         # send reply from server to host
2376         p = (Ether(src=server.mac, dst=self.pg0.local_mac) /
2377              IP(src=server.ip4, dst=self.nat_addr) /
2378              TCP(sport=server_in_port, dport=host_out_port))
2379         self.pg0.add_stream(p)
2380         self.pg_enable_capture(self.pg_interfaces)
2381         self.pg_start()
2382         capture = self.pg0.get_capture(1)
2383         p = capture[0]
2384         try:
2385             ip = p[IP]
2386             tcp = p[TCP]
2387             self.assertEqual(ip.src, self.nat_addr)
2388             self.assertEqual(ip.dst, host.ip4)
2389             self.assertEqual(tcp.sport, server_out_port)
2390             self.assertEqual(tcp.dport, host_in_port)
2391             self.assert_packet_checksums_valid(p)
2392         except:
2393             self.logger.error(ppp("Unexpected or invalid packet:", p))
2394             raise
2395
2396         after = self.statistics.get_counter('/nat44/hairpinning')[0]
2397         if_idx = self.pg0.sw_if_index
2398         self.assertEqual(after[if_idx] - cnt[if_idx], 2)
2399
2400     def test_hairpinning2(self):
2401         """ NAT44 hairpinning - 1:1 NAT"""
2402
2403         server1_nat_ip = "10.0.0.10"
2404         server2_nat_ip = "10.0.0.11"
2405         host = self.pg0.remote_hosts[0]
2406         server1 = self.pg0.remote_hosts[1]
2407         server2 = self.pg0.remote_hosts[2]
2408         server_tcp_port = 22
2409         server_udp_port = 20
2410
2411         self.nat44_add_address(self.nat_addr)
2412         flags = self.config_flags.NAT_IS_INSIDE
2413         self.vapi.nat44_interface_add_del_feature(
2414             sw_if_index=self.pg0.sw_if_index,
2415             flags=flags, is_add=1)
2416         self.vapi.nat44_interface_add_del_feature(
2417             sw_if_index=self.pg1.sw_if_index,
2418             is_add=1)
2419
2420         # add static mapping for servers
2421         self.nat44_add_static_mapping(server1.ip4, server1_nat_ip)
2422         self.nat44_add_static_mapping(server2.ip4, server2_nat_ip)
2423
2424         # host to server1
2425         pkts = []
2426         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2427              IP(src=host.ip4, dst=server1_nat_ip) /
2428              TCP(sport=self.tcp_port_in, dport=server_tcp_port))
2429         pkts.append(p)
2430         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2431              IP(src=host.ip4, dst=server1_nat_ip) /
2432              UDP(sport=self.udp_port_in, dport=server_udp_port))
2433         pkts.append(p)
2434         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2435              IP(src=host.ip4, dst=server1_nat_ip) /
2436              ICMP(id=self.icmp_id_in, type='echo-request'))
2437         pkts.append(p)
2438         self.pg0.add_stream(pkts)
2439         self.pg_enable_capture(self.pg_interfaces)
2440         self.pg_start()
2441         capture = self.pg0.get_capture(len(pkts))
2442         for packet in capture:
2443             try:
2444                 self.assertEqual(packet[IP].src, self.nat_addr)
2445                 self.assertEqual(packet[IP].dst, server1.ip4)
2446                 if packet.haslayer(TCP):
2447                     self.assertNotEqual(packet[TCP].sport, self.tcp_port_in)
2448                     self.assertEqual(packet[TCP].dport, server_tcp_port)
2449                     self.tcp_port_out = packet[TCP].sport
2450                     self.assert_packet_checksums_valid(packet)
2451                 elif packet.haslayer(UDP):
2452                     self.assertNotEqual(packet[UDP].sport, self.udp_port_in)
2453                     self.assertEqual(packet[UDP].dport, server_udp_port)
2454                     self.udp_port_out = packet[UDP].sport
2455                 else:
2456                     self.assertNotEqual(packet[ICMP].id, self.icmp_id_in)
2457                     self.icmp_id_out = packet[ICMP].id
2458             except:
2459                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
2460                 raise
2461
2462         # server1 to host
2463         pkts = []
2464         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2465              IP(src=server1.ip4, dst=self.nat_addr) /
2466              TCP(sport=server_tcp_port, dport=self.tcp_port_out))
2467         pkts.append(p)
2468         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2469              IP(src=server1.ip4, dst=self.nat_addr) /
2470              UDP(sport=server_udp_port, dport=self.udp_port_out))
2471         pkts.append(p)
2472         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2473              IP(src=server1.ip4, dst=self.nat_addr) /
2474              ICMP(id=self.icmp_id_out, type='echo-reply'))
2475         pkts.append(p)
2476         self.pg0.add_stream(pkts)
2477         self.pg_enable_capture(self.pg_interfaces)
2478         self.pg_start()
2479         capture = self.pg0.get_capture(len(pkts))
2480         for packet in capture:
2481             try:
2482                 self.assertEqual(packet[IP].src, server1_nat_ip)
2483                 self.assertEqual(packet[IP].dst, host.ip4)
2484                 if packet.haslayer(TCP):
2485                     self.assertEqual(packet[TCP].dport, self.tcp_port_in)
2486                     self.assertEqual(packet[TCP].sport, server_tcp_port)
2487                     self.assert_packet_checksums_valid(packet)
2488                 elif packet.haslayer(UDP):
2489                     self.assertEqual(packet[UDP].dport, self.udp_port_in)
2490                     self.assertEqual(packet[UDP].sport, server_udp_port)
2491                 else:
2492                     self.assertEqual(packet[ICMP].id, self.icmp_id_in)
2493             except:
2494                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
2495                 raise
2496
2497         # server2 to server1
2498         pkts = []
2499         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2500              IP(src=server2.ip4, dst=server1_nat_ip) /
2501              TCP(sport=self.tcp_port_in, dport=server_tcp_port))
2502         pkts.append(p)
2503         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2504              IP(src=server2.ip4, dst=server1_nat_ip) /
2505              UDP(sport=self.udp_port_in, dport=server_udp_port))
2506         pkts.append(p)
2507         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2508              IP(src=server2.ip4, dst=server1_nat_ip) /
2509              ICMP(id=self.icmp_id_in, type='echo-request'))
2510         pkts.append(p)
2511         self.pg0.add_stream(pkts)
2512         self.pg_enable_capture(self.pg_interfaces)
2513         self.pg_start()
2514         capture = self.pg0.get_capture(len(pkts))
2515         for packet in capture:
2516             try:
2517                 self.assertEqual(packet[IP].src, server2_nat_ip)
2518                 self.assertEqual(packet[IP].dst, server1.ip4)
2519                 if packet.haslayer(TCP):
2520                     self.assertEqual(packet[TCP].sport, self.tcp_port_in)
2521                     self.assertEqual(packet[TCP].dport, server_tcp_port)
2522                     self.tcp_port_out = packet[TCP].sport
2523                     self.assert_packet_checksums_valid(packet)
2524                 elif packet.haslayer(UDP):
2525                     self.assertEqual(packet[UDP].sport, self.udp_port_in)
2526                     self.assertEqual(packet[UDP].dport, server_udp_port)
2527                     self.udp_port_out = packet[UDP].sport
2528                 else:
2529                     self.assertEqual(packet[ICMP].id, self.icmp_id_in)
2530                     self.icmp_id_out = packet[ICMP].id
2531             except:
2532                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
2533                 raise
2534
2535         # server1 to server2
2536         pkts = []
2537         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2538              IP(src=server1.ip4, dst=server2_nat_ip) /
2539              TCP(sport=server_tcp_port, dport=self.tcp_port_out))
2540         pkts.append(p)
2541         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2542              IP(src=server1.ip4, dst=server2_nat_ip) /
2543              UDP(sport=server_udp_port, dport=self.udp_port_out))
2544         pkts.append(p)
2545         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2546              IP(src=server1.ip4, dst=server2_nat_ip) /
2547              ICMP(id=self.icmp_id_out, type='echo-reply'))
2548         pkts.append(p)
2549         self.pg0.add_stream(pkts)
2550         self.pg_enable_capture(self.pg_interfaces)
2551         self.pg_start()
2552         capture = self.pg0.get_capture(len(pkts))
2553         for packet in capture:
2554             try:
2555                 self.assertEqual(packet[IP].src, server1_nat_ip)
2556                 self.assertEqual(packet[IP].dst, server2.ip4)
2557                 if packet.haslayer(TCP):
2558                     self.assertEqual(packet[TCP].dport, self.tcp_port_in)
2559                     self.assertEqual(packet[TCP].sport, server_tcp_port)
2560                     self.assert_packet_checksums_valid(packet)
2561                 elif packet.haslayer(UDP):
2562                     self.assertEqual(packet[UDP].dport, self.udp_port_in)
2563                     self.assertEqual(packet[UDP].sport, server_udp_port)
2564                 else:
2565                     self.assertEqual(packet[ICMP].id, self.icmp_id_in)
2566             except:
2567                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
2568                 raise
2569
2570     def test_interface_addr(self):
2571         """ Acquire NAT44 addresses from interface """
2572         self.vapi.nat44_add_del_interface_addr(
2573             is_add=1,
2574             sw_if_index=self.pg7.sw_if_index)
2575
2576         # no address in NAT pool
2577         addresses = self.vapi.nat44_address_dump()
2578         self.assertEqual(0, len(addresses))
2579
2580         # configure interface address and check NAT address pool
2581         self.pg7.config_ip4()
2582         addresses = self.vapi.nat44_address_dump()
2583         self.assertEqual(1, len(addresses))
2584         self.assertEqual(str(addresses[0].ip_address), self.pg7.local_ip4)
2585
2586         # remove interface address and check NAT address pool
2587         self.pg7.unconfig_ip4()
2588         addresses = self.vapi.nat44_address_dump()
2589         self.assertEqual(0, len(addresses))
2590
2591     def test_interface_addr_static_mapping(self):
2592         """ Static mapping with addresses from interface """
2593         tag = "testTAG"
2594
2595         self.vapi.nat44_add_del_interface_addr(
2596             is_add=1,
2597             sw_if_index=self.pg7.sw_if_index)
2598         self.nat44_add_static_mapping(
2599             '1.2.3.4',
2600             external_sw_if_index=self.pg7.sw_if_index,
2601             tag=tag)
2602
2603         # static mappings with external interface
2604         static_mappings = self.vapi.nat44_static_mapping_dump()
2605         self.assertEqual(1, len(static_mappings))
2606         self.assertEqual(self.pg7.sw_if_index,
2607                          static_mappings[0].external_sw_if_index)
2608         self.assertEqual(static_mappings[0].tag, tag)
2609
2610         # configure interface address and check static mappings
2611         self.pg7.config_ip4()
2612         static_mappings = self.vapi.nat44_static_mapping_dump()
2613         self.assertEqual(2, len(static_mappings))
2614         resolved = False
2615         for sm in static_mappings:
2616             if sm.external_sw_if_index == 0xFFFFFFFF:
2617                 self.assertEqual(str(sm.external_ip_address),
2618                                  self.pg7.local_ip4)
2619                 self.assertEqual(sm.tag, tag)
2620                 resolved = True
2621         self.assertTrue(resolved)
2622
2623         # remove interface address and check static mappings
2624         self.pg7.unconfig_ip4()
2625         static_mappings = self.vapi.nat44_static_mapping_dump()
2626         self.assertEqual(1, len(static_mappings))
2627         self.assertEqual(self.pg7.sw_if_index,
2628                          static_mappings[0].external_sw_if_index)
2629         self.assertEqual(static_mappings[0].tag, tag)
2630
2631         # configure interface address again and check static mappings
2632         self.pg7.config_ip4()
2633         static_mappings = self.vapi.nat44_static_mapping_dump()
2634         self.assertEqual(2, len(static_mappings))
2635         resolved = False
2636         for sm in static_mappings:
2637             if sm.external_sw_if_index == 0xFFFFFFFF:
2638                 self.assertEqual(str(sm.external_ip_address),
2639                                  self.pg7.local_ip4)
2640                 self.assertEqual(sm.tag, tag)
2641                 resolved = True
2642         self.assertTrue(resolved)
2643
2644         # remove static mapping
2645         self.nat44_add_static_mapping(
2646             '1.2.3.4',
2647             external_sw_if_index=self.pg7.sw_if_index,
2648             tag=tag,
2649             is_add=0)
2650         static_mappings = self.vapi.nat44_static_mapping_dump()
2651         self.assertEqual(0, len(static_mappings))
2652
2653     def test_interface_addr_identity_nat(self):
2654         """ Identity NAT with addresses from interface """
2655
2656         port = 53053
2657         self.vapi.nat44_add_del_interface_addr(
2658             is_add=1,
2659             sw_if_index=self.pg7.sw_if_index)
2660         self.vapi.nat44_add_del_identity_mapping(
2661             ip_address=b'0',
2662             sw_if_index=self.pg7.sw_if_index,
2663             port=port,
2664             protocol=IP_PROTOS.tcp,
2665             is_add=1)
2666
2667         # identity mappings with external interface
2668         identity_mappings = self.vapi.nat44_identity_mapping_dump()
2669         self.assertEqual(1, len(identity_mappings))
2670         self.assertEqual(self.pg7.sw_if_index,
2671                          identity_mappings[0].sw_if_index)
2672
2673         # configure interface address and check identity mappings
2674         self.pg7.config_ip4()
2675         identity_mappings = self.vapi.nat44_identity_mapping_dump()
2676         resolved = False
2677         self.assertEqual(2, len(identity_mappings))
2678         for sm in identity_mappings:
2679             if sm.sw_if_index == 0xFFFFFFFF:
2680                 self.assertEqual(str(identity_mappings[0].ip_address),
2681                                  self.pg7.local_ip4)
2682                 self.assertEqual(port, identity_mappings[0].port)
2683                 self.assertEqual(IP_PROTOS.tcp, identity_mappings[0].protocol)
2684                 resolved = True
2685         self.assertTrue(resolved)
2686
2687         # remove interface address and check identity mappings
2688         self.pg7.unconfig_ip4()
2689         identity_mappings = self.vapi.nat44_identity_mapping_dump()
2690         self.assertEqual(1, len(identity_mappings))
2691         self.assertEqual(self.pg7.sw_if_index,
2692                          identity_mappings[0].sw_if_index)
2693
2694     def test_ipfix_nat44_sess(self):
2695         """ IPFIX logging NAT44 session created/deleted """
2696         self.ipfix_domain_id = 10
2697         self.ipfix_src_port = 20202
2698         collector_port = 30303
2699         bind_layers(UDP, IPFIX, dport=30303)
2700         self.nat44_add_address(self.nat_addr)
2701         flags = self.config_flags.NAT_IS_INSIDE
2702         self.vapi.nat44_interface_add_del_feature(
2703             sw_if_index=self.pg0.sw_if_index,
2704             flags=flags, is_add=1)
2705         self.vapi.nat44_interface_add_del_feature(
2706             sw_if_index=self.pg1.sw_if_index,
2707             is_add=1)
2708         self.vapi.set_ipfix_exporter(collector_address=self.pg3.remote_ip4,
2709                                      src_address=self.pg3.local_ip4,
2710                                      path_mtu=512,
2711                                      template_interval=10,
2712                                      collector_port=collector_port)
2713         self.vapi.nat_ipfix_enable_disable(domain_id=self.ipfix_domain_id,
2714                                            src_port=self.ipfix_src_port,
2715                                            enable=1)
2716
2717         pkts = self.create_stream_in(self.pg0, self.pg1)
2718         self.pg0.add_stream(pkts)
2719         self.pg_enable_capture(self.pg_interfaces)
2720         self.pg_start()
2721         capture = self.pg1.get_capture(len(pkts))
2722         self.verify_capture_out(capture)
2723         self.nat44_add_address(self.nat_addr, is_add=0)
2724         self.vapi.ipfix_flush()
2725         capture = self.pg3.get_capture(7)
2726         ipfix = IPFIXDecoder()
2727         # first load template
2728         for p in capture:
2729             self.assertTrue(p.haslayer(IPFIX))
2730             self.assertEqual(p[IP].src, self.pg3.local_ip4)
2731             self.assertEqual(p[IP].dst, self.pg3.remote_ip4)
2732             self.assertEqual(p[UDP].sport, self.ipfix_src_port)
2733             self.assertEqual(p[UDP].dport, collector_port)
2734             self.assertEqual(p[IPFIX].observationDomainID,
2735                              self.ipfix_domain_id)
2736             if p.haslayer(Template):
2737                 ipfix.add_template(p.getlayer(Template))
2738         # verify events in data set
2739         for p in capture:
2740             if p.haslayer(Data):
2741                 data = ipfix.decode_data_set(p.getlayer(Set))
2742                 self.verify_ipfix_nat44_ses(data)
2743
2744     def test_ipfix_addr_exhausted(self):
2745         """ IPFIX logging NAT addresses exhausted """
2746         flags = self.config_flags.NAT_IS_INSIDE
2747         self.vapi.nat44_interface_add_del_feature(
2748             sw_if_index=self.pg0.sw_if_index,
2749             flags=flags, is_add=1)
2750         self.vapi.nat44_interface_add_del_feature(
2751             sw_if_index=self.pg1.sw_if_index,
2752             is_add=1)
2753         self.vapi.set_ipfix_exporter(collector_address=self.pg3.remote_ip4,
2754                                      src_address=self.pg3.local_ip4,
2755                                      path_mtu=512,
2756                                      template_interval=10)
2757         self.vapi.nat_ipfix_enable_disable(domain_id=self.ipfix_domain_id,
2758                                            src_port=self.ipfix_src_port,
2759                                            enable=1)
2760
2761         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
2762              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
2763              TCP(sport=3025))
2764         self.pg0.add_stream(p)
2765         self.pg_enable_capture(self.pg_interfaces)
2766         self.pg_start()
2767         self.pg1.assert_nothing_captured()
2768         sleep(1)
2769         self.vapi.ipfix_flush()
2770         capture = self.pg3.get_capture(7)
2771         ipfix = IPFIXDecoder()
2772         # first load template
2773         for p in capture:
2774             self.assertTrue(p.haslayer(IPFIX))
2775             self.assertEqual(p[IP].src, self.pg3.local_ip4)
2776             self.assertEqual(p[IP].dst, self.pg3.remote_ip4)
2777             self.assertEqual(p[UDP].sport, self.ipfix_src_port)
2778             self.assertEqual(p[UDP].dport, 4739)
2779             self.assertEqual(p[IPFIX].observationDomainID,
2780                              self.ipfix_domain_id)
2781             if p.haslayer(Template):
2782                 ipfix.add_template(p.getlayer(Template))
2783         # verify events in data set
2784         for p in capture:
2785             if p.haslayer(Data):
2786                 data = ipfix.decode_data_set(p.getlayer(Set))
2787                 self.verify_ipfix_addr_exhausted(data)
2788
2789     @unittest.skipUnless(running_extended_tests, "part of extended tests")
2790     def test_ipfix_max_sessions(self):
2791         """ IPFIX logging maximum session entries exceeded """
2792         self.nat44_add_address(self.nat_addr)
2793         flags = self.config_flags.NAT_IS_INSIDE
2794         self.vapi.nat44_interface_add_del_feature(
2795             sw_if_index=self.pg0.sw_if_index,
2796             flags=flags, is_add=1)
2797         self.vapi.nat44_interface_add_del_feature(
2798             sw_if_index=self.pg1.sw_if_index,
2799             is_add=1)
2800
2801         max_sessions = self.max_translations
2802
2803         pkts = []
2804         for i in range(0, max_sessions):
2805             src = "10.10.%u.%u" % ((i & 0xFF00) >> 8, i & 0xFF)
2806             p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2807                  IP(src=src, dst=self.pg1.remote_ip4) /
2808                  TCP(sport=1025))
2809             pkts.append(p)
2810         self.pg0.add_stream(pkts)
2811         self.pg_enable_capture(self.pg_interfaces)
2812         self.pg_start()
2813
2814         self.pg1.get_capture(max_sessions)
2815         self.vapi.set_ipfix_exporter(collector_address=self.pg3.remote_ip4,
2816                                      src_address=self.pg3.local_ip4,
2817                                      path_mtu=512,
2818                                      template_interval=10)
2819         self.vapi.nat_ipfix_enable_disable(domain_id=self.ipfix_domain_id,
2820                                            src_port=self.ipfix_src_port,
2821                                            enable=1)
2822
2823         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2824              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
2825              TCP(sport=1025))
2826         self.pg0.add_stream(p)
2827         self.pg_enable_capture(self.pg_interfaces)
2828         self.pg_start()
2829         self.pg1.assert_nothing_captured()
2830         sleep(1)
2831         self.vapi.ipfix_flush()
2832         capture = self.pg3.get_capture(7)
2833         ipfix = IPFIXDecoder()
2834         # first load template
2835         for p in capture:
2836             self.assertTrue(p.haslayer(IPFIX))
2837             self.assertEqual(p[IP].src, self.pg3.local_ip4)
2838             self.assertEqual(p[IP].dst, self.pg3.remote_ip4)
2839             self.assertEqual(p[UDP].sport, self.ipfix_src_port)
2840             self.assertEqual(p[UDP].dport, 4739)
2841             self.assertEqual(p[IPFIX].observationDomainID,
2842                              self.ipfix_domain_id)
2843             if p.haslayer(Template):
2844                 ipfix.add_template(p.getlayer(Template))
2845         # verify events in data set
2846         for p in capture:
2847             if p.haslayer(Data):
2848                 data = ipfix.decode_data_set(p.getlayer(Set))
2849                 self.verify_ipfix_max_sessions(data, max_sessions)
2850
2851     def test_syslog_apmap(self):
2852         """ Test syslog address and port mapping creation and deletion """
2853         self.vapi.syslog_set_filter(
2854             self.SYSLOG_SEVERITY.SYSLOG_API_SEVERITY_INFO)
2855         self.vapi.syslog_set_sender(self.pg3.local_ip4, self.pg3.remote_ip4)
2856         self.nat44_add_address(self.nat_addr)
2857         flags = self.config_flags.NAT_IS_INSIDE
2858         self.vapi.nat44_interface_add_del_feature(
2859             sw_if_index=self.pg0.sw_if_index,
2860             flags=flags, is_add=1)
2861         self.vapi.nat44_interface_add_del_feature(
2862             sw_if_index=self.pg1.sw_if_index,
2863             is_add=1)
2864
2865         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2866              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
2867              TCP(sport=self.tcp_port_in, dport=20))
2868         self.pg0.add_stream(p)
2869         self.pg_enable_capture(self.pg_interfaces)
2870         self.pg_start()
2871         capture = self.pg1.get_capture(1)
2872         self.tcp_port_out = capture[0][TCP].sport
2873         capture = self.pg3.get_capture(1)
2874         self.verify_syslog_apmap(capture[0][Raw].load)
2875
2876         self.pg_enable_capture(self.pg_interfaces)
2877         self.pg_start()
2878         self.nat44_add_address(self.nat_addr, is_add=0)
2879         capture = self.pg3.get_capture(1)
2880         self.verify_syslog_apmap(capture[0][Raw].load, False)
2881
2882     def test_pool_addr_fib(self):
2883         """ NAT44 add pool addresses to FIB """
2884         static_addr = '10.0.0.10'
2885         self.nat44_add_address(self.nat_addr)
2886         flags = self.config_flags.NAT_IS_INSIDE
2887         self.vapi.nat44_interface_add_del_feature(
2888             sw_if_index=self.pg0.sw_if_index,
2889             flags=flags, is_add=1)
2890         self.vapi.nat44_interface_add_del_feature(
2891             sw_if_index=self.pg1.sw_if_index,
2892             is_add=1)
2893         self.nat44_add_static_mapping(self.pg0.remote_ip4, static_addr)
2894
2895         # NAT44 address
2896         p = (Ether(src=self.pg1.remote_mac, dst='ff:ff:ff:ff:ff:ff') /
2897              ARP(op=ARP.who_has, pdst=self.nat_addr,
2898                  psrc=self.pg1.remote_ip4, hwsrc=self.pg1.remote_mac))
2899         self.pg1.add_stream(p)
2900         self.pg_enable_capture(self.pg_interfaces)
2901         self.pg_start()
2902         capture = self.pg1.get_capture(1)
2903         self.assertTrue(capture[0].haslayer(ARP))
2904         self.assertTrue(capture[0][ARP].op, ARP.is_at)
2905
2906         # 1:1 NAT address
2907         p = (Ether(src=self.pg1.remote_mac, dst='ff:ff:ff:ff:ff:ff') /
2908              ARP(op=ARP.who_has, pdst=static_addr,
2909                  psrc=self.pg1.remote_ip4, hwsrc=self.pg1.remote_mac))
2910         self.pg1.add_stream(p)
2911         self.pg_enable_capture(self.pg_interfaces)
2912         self.pg_start()
2913         capture = self.pg1.get_capture(1)
2914         self.assertTrue(capture[0].haslayer(ARP))
2915         self.assertTrue(capture[0][ARP].op, ARP.is_at)
2916
2917         # send ARP to non-NAT44 interface
2918         p = (Ether(src=self.pg2.remote_mac, dst='ff:ff:ff:ff:ff:ff') /
2919              ARP(op=ARP.who_has, pdst=self.nat_addr,
2920                  psrc=self.pg2.remote_ip4, hwsrc=self.pg2.remote_mac))
2921         self.pg2.add_stream(p)
2922         self.pg_enable_capture(self.pg_interfaces)
2923         self.pg_start()
2924         self.pg1.assert_nothing_captured()
2925
2926         # remove addresses and verify
2927         self.nat44_add_address(self.nat_addr, is_add=0)
2928         self.nat44_add_static_mapping(self.pg0.remote_ip4, static_addr,
2929                                       is_add=0)
2930
2931         p = (Ether(src=self.pg1.remote_mac, dst='ff:ff:ff:ff:ff:ff') /
2932              ARP(op=ARP.who_has, pdst=self.nat_addr,
2933                  psrc=self.pg1.remote_ip4, hwsrc=self.pg1.remote_mac))
2934         self.pg1.add_stream(p)
2935         self.pg_enable_capture(self.pg_interfaces)
2936         self.pg_start()
2937         self.pg1.assert_nothing_captured()
2938
2939         p = (Ether(src=self.pg1.remote_mac, dst='ff:ff:ff:ff:ff:ff') /
2940              ARP(op=ARP.who_has, pdst=static_addr,
2941                  psrc=self.pg1.remote_ip4, hwsrc=self.pg1.remote_mac))
2942         self.pg1.add_stream(p)
2943         self.pg_enable_capture(self.pg_interfaces)
2944         self.pg_start()
2945         self.pg1.assert_nothing_captured()
2946
2947     def test_vrf_mode(self):
2948         """ NAT44 tenant VRF aware address pool mode """
2949
2950         vrf_id1 = 1
2951         vrf_id2 = 2
2952         nat_ip1 = "10.0.0.10"
2953         nat_ip2 = "10.0.0.11"
2954
2955         self.pg0.unconfig_ip4()
2956         self.pg1.unconfig_ip4()
2957         self.vapi.ip_table_add_del(is_add=1, table={'table_id': vrf_id1})
2958         self.vapi.ip_table_add_del(is_add=1, table={'table_id': vrf_id2})
2959         self.pg0.set_table_ip4(vrf_id1)
2960         self.pg1.set_table_ip4(vrf_id2)
2961         self.pg0.config_ip4()
2962         self.pg1.config_ip4()
2963         self.pg0.resolve_arp()
2964         self.pg1.resolve_arp()
2965
2966         self.nat44_add_address(nat_ip1, vrf_id=vrf_id1)
2967         self.nat44_add_address(nat_ip2, vrf_id=vrf_id2)
2968         flags = self.config_flags.NAT_IS_INSIDE
2969         self.vapi.nat44_interface_add_del_feature(
2970             sw_if_index=self.pg0.sw_if_index,
2971             flags=flags, is_add=1)
2972         self.vapi.nat44_interface_add_del_feature(
2973             sw_if_index=self.pg1.sw_if_index,
2974             flags=flags, is_add=1)
2975         self.vapi.nat44_interface_add_del_feature(
2976             sw_if_index=self.pg2.sw_if_index,
2977             is_add=1)
2978
2979         try:
2980             # first VRF
2981             pkts = self.create_stream_in(self.pg0, self.pg2)
2982             self.pg0.add_stream(pkts)
2983             self.pg_enable_capture(self.pg_interfaces)
2984             self.pg_start()
2985             capture = self.pg2.get_capture(len(pkts))
2986             self.verify_capture_out(capture, nat_ip1)
2987
2988             # second VRF
2989             pkts = self.create_stream_in(self.pg1, self.pg2)
2990             self.pg1.add_stream(pkts)
2991             self.pg_enable_capture(self.pg_interfaces)
2992             self.pg_start()
2993             capture = self.pg2.get_capture(len(pkts))
2994             self.verify_capture_out(capture, nat_ip2)
2995
2996         finally:
2997             self.pg0.unconfig_ip4()
2998             self.pg1.unconfig_ip4()
2999             self.pg0.set_table_ip4(0)
3000             self.pg1.set_table_ip4(0)
3001             self.pg0.config_ip4()
3002             self.pg1.config_ip4()
3003             self.pg0.resolve_arp()
3004             self.pg1.resolve_arp()
3005             self.vapi.ip_table_add_del(is_add=0, table={'table_id': vrf_id1})
3006             self.vapi.ip_table_add_del(is_add=0, table={'table_id': vrf_id2})
3007
3008     def test_vrf_feature_independent(self):
3009         """ NAT44 tenant VRF independent address pool mode """
3010
3011         nat_ip1 = "10.0.0.10"
3012         nat_ip2 = "10.0.0.11"
3013
3014         self.nat44_add_address(nat_ip1)
3015         self.nat44_add_address(nat_ip2, vrf_id=99)
3016         flags = self.config_flags.NAT_IS_INSIDE
3017         self.vapi.nat44_interface_add_del_feature(
3018             sw_if_index=self.pg0.sw_if_index,
3019             flags=flags, is_add=1)
3020         self.vapi.nat44_interface_add_del_feature(
3021             sw_if_index=self.pg1.sw_if_index,
3022             flags=flags, is_add=1)
3023         self.vapi.nat44_interface_add_del_feature(
3024             sw_if_index=self.pg2.sw_if_index,
3025             is_add=1)
3026
3027         # first VRF
3028         pkts = self.create_stream_in(self.pg0, self.pg2)
3029         self.pg0.add_stream(pkts)
3030         self.pg_enable_capture(self.pg_interfaces)
3031         self.pg_start()
3032         capture = self.pg2.get_capture(len(pkts))
3033         self.verify_capture_out(capture, nat_ip1)
3034
3035         # second VRF
3036         pkts = self.create_stream_in(self.pg1, self.pg2)
3037         self.pg1.add_stream(pkts)
3038         self.pg_enable_capture(self.pg_interfaces)
3039         self.pg_start()
3040         capture = self.pg2.get_capture(len(pkts))
3041         self.verify_capture_out(capture, nat_ip1)
3042
3043     def create_routes_and_neigbors(self):
3044         r1 = VppIpRoute(self, self.pg7.remote_ip4, 32,
3045                         [VppRoutePath(self.pg7.remote_ip4,
3046                                       self.pg7.sw_if_index)])
3047         r2 = VppIpRoute(self, self.pg8.remote_ip4, 32,
3048                         [VppRoutePath(self.pg8.remote_ip4,
3049                                       self.pg8.sw_if_index)])
3050         r1.add_vpp_config()
3051         r2.add_vpp_config()
3052
3053         n1 = VppNeighbor(self,
3054                          self.pg7.sw_if_index,
3055                          self.pg7.remote_mac,
3056                          self.pg7.remote_ip4,
3057                          is_static=1)
3058         n2 = VppNeighbor(self,
3059                          self.pg8.sw_if_index,
3060                          self.pg8.remote_mac,
3061                          self.pg8.remote_ip4,
3062                          is_static=1)
3063         n1.add_vpp_config()
3064         n2.add_vpp_config()
3065
3066     def test_dynamic_ipless_interfaces(self):
3067         """ NAT44 interfaces without configured IP address """
3068         self.create_routes_and_neigbors()
3069         self.nat44_add_address(self.nat_addr)
3070         flags = self.config_flags.NAT_IS_INSIDE
3071         self.vapi.nat44_interface_add_del_feature(
3072             sw_if_index=self.pg7.sw_if_index,
3073             flags=flags, is_add=1)
3074         self.vapi.nat44_interface_add_del_feature(
3075             sw_if_index=self.pg8.sw_if_index,
3076             is_add=1)
3077
3078         # in2out
3079         pkts = self.create_stream_in(self.pg7, self.pg8)
3080         self.pg7.add_stream(pkts)
3081         self.pg_enable_capture(self.pg_interfaces)
3082         self.pg_start()
3083         capture = self.pg8.get_capture(len(pkts))
3084         self.verify_capture_out(capture)
3085
3086         # out2in
3087         pkts = self.create_stream_out(self.pg8, self.nat_addr)
3088         self.pg8.add_stream(pkts)
3089         self.pg_enable_capture(self.pg_interfaces)
3090         self.pg_start()
3091         capture = self.pg7.get_capture(len(pkts))
3092         self.verify_capture_in(capture, self.pg7)
3093
3094     def test_static_ipless_interfaces(self):
3095         """ NAT44 interfaces without configured IP address - 1:1 NAT """
3096
3097         self.create_routes_and_neigbors()
3098         self.nat44_add_static_mapping(self.pg7.remote_ip4, self.nat_addr)
3099         flags = self.config_flags.NAT_IS_INSIDE
3100         self.vapi.nat44_interface_add_del_feature(
3101             sw_if_index=self.pg7.sw_if_index,
3102             flags=flags, is_add=1)
3103         self.vapi.nat44_interface_add_del_feature(
3104             sw_if_index=self.pg8.sw_if_index,
3105             is_add=1)
3106
3107         # out2in
3108         pkts = self.create_stream_out(self.pg8)
3109         self.pg8.add_stream(pkts)
3110         self.pg_enable_capture(self.pg_interfaces)
3111         self.pg_start()
3112         capture = self.pg7.get_capture(len(pkts))
3113         self.verify_capture_in(capture, self.pg7)
3114
3115         # in2out
3116         pkts = self.create_stream_in(self.pg7, self.pg8)
3117         self.pg7.add_stream(pkts)
3118         self.pg_enable_capture(self.pg_interfaces)
3119         self.pg_start()
3120         capture = self.pg8.get_capture(len(pkts))
3121         self.verify_capture_out(capture, self.nat_addr, True)
3122
3123     def test_static_with_port_ipless_interfaces(self):
3124         """ NAT44 interfaces without configured IP address - 1:1 NAPT """
3125
3126         self.tcp_port_out = 30606
3127         self.udp_port_out = 30607
3128         self.icmp_id_out = 30608
3129
3130         self.create_routes_and_neigbors()
3131         self.nat44_add_address(self.nat_addr)
3132         self.nat44_add_static_mapping(self.pg7.remote_ip4, self.nat_addr,
3133                                       self.tcp_port_in, self.tcp_port_out,
3134                                       proto=IP_PROTOS.tcp)
3135         self.nat44_add_static_mapping(self.pg7.remote_ip4, self.nat_addr,
3136                                       self.udp_port_in, self.udp_port_out,
3137                                       proto=IP_PROTOS.udp)
3138         self.nat44_add_static_mapping(self.pg7.remote_ip4, self.nat_addr,
3139                                       self.icmp_id_in, self.icmp_id_out,
3140                                       proto=IP_PROTOS.icmp)
3141         flags = self.config_flags.NAT_IS_INSIDE
3142         self.vapi.nat44_interface_add_del_feature(
3143             sw_if_index=self.pg7.sw_if_index,
3144             flags=flags, is_add=1)
3145         self.vapi.nat44_interface_add_del_feature(
3146             sw_if_index=self.pg8.sw_if_index,
3147             is_add=1)
3148
3149         # out2in
3150         pkts = self.create_stream_out(self.pg8)
3151         self.pg8.add_stream(pkts)
3152         self.pg_enable_capture(self.pg_interfaces)
3153         self.pg_start()
3154         capture = self.pg7.get_capture(len(pkts))
3155         self.verify_capture_in(capture, self.pg7)
3156
3157         # in2out
3158         pkts = self.create_stream_in(self.pg7, self.pg8)
3159         self.pg7.add_stream(pkts)
3160         self.pg_enable_capture(self.pg_interfaces)
3161         self.pg_start()
3162         capture = self.pg8.get_capture(len(pkts))
3163         self.verify_capture_out(capture)
3164
3165     def test_static_unknown_proto(self):
3166         """ 1:1 NAT translate packet with unknown protocol """
3167         nat_ip = "10.0.0.10"
3168         self.nat44_add_static_mapping(self.pg0.remote_ip4, nat_ip)
3169         flags = self.config_flags.NAT_IS_INSIDE
3170         self.vapi.nat44_interface_add_del_feature(
3171             sw_if_index=self.pg0.sw_if_index,
3172             flags=flags, is_add=1)
3173         self.vapi.nat44_interface_add_del_feature(
3174             sw_if_index=self.pg1.sw_if_index,
3175             is_add=1)
3176
3177         # in2out
3178         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
3179              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3180              GRE() /
3181              IP(src=self.pg2.remote_ip4, dst=self.pg3.remote_ip4) /
3182              TCP(sport=1234, dport=1234))
3183         self.pg0.add_stream(p)
3184         self.pg_enable_capture(self.pg_interfaces)
3185         self.pg_start()
3186         p = self.pg1.get_capture(1)
3187         packet = p[0]
3188         try:
3189             self.assertEqual(packet[IP].src, nat_ip)
3190             self.assertEqual(packet[IP].dst, self.pg1.remote_ip4)
3191             self.assertEqual(packet.haslayer(GRE), 1)
3192             self.assert_packet_checksums_valid(packet)
3193         except:
3194             self.logger.error(ppp("Unexpected or invalid packet:", packet))
3195             raise
3196
3197         # out2in
3198         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
3199              IP(src=self.pg1.remote_ip4, dst=nat_ip) /
3200              GRE() /
3201              IP(src=self.pg3.remote_ip4, dst=self.pg2.remote_ip4) /
3202              TCP(sport=1234, dport=1234))
3203         self.pg1.add_stream(p)
3204         self.pg_enable_capture(self.pg_interfaces)
3205         self.pg_start()
3206         p = self.pg0.get_capture(1)
3207         packet = p[0]
3208         try:
3209             self.assertEqual(packet[IP].src, self.pg1.remote_ip4)
3210             self.assertEqual(packet[IP].dst, self.pg0.remote_ip4)
3211             self.assertEqual(packet.haslayer(GRE), 1)
3212             self.assert_packet_checksums_valid(packet)
3213         except:
3214             self.logger.error(ppp("Unexpected or invalid packet:", packet))
3215             raise
3216
3217     def test_hairpinning_static_unknown_proto(self):
3218         """ 1:1 NAT translate packet with unknown protocol - hairpinning """
3219
3220         host = self.pg0.remote_hosts[0]
3221         server = self.pg0.remote_hosts[1]
3222
3223         host_nat_ip = "10.0.0.10"
3224         server_nat_ip = "10.0.0.11"
3225
3226         self.nat44_add_static_mapping(host.ip4, host_nat_ip)
3227         self.nat44_add_static_mapping(server.ip4, server_nat_ip)
3228         flags = self.config_flags.NAT_IS_INSIDE
3229         self.vapi.nat44_interface_add_del_feature(
3230             sw_if_index=self.pg0.sw_if_index,
3231             flags=flags, is_add=1)
3232         self.vapi.nat44_interface_add_del_feature(
3233             sw_if_index=self.pg1.sw_if_index,
3234             is_add=1)
3235
3236         # host to server
3237         p = (Ether(dst=self.pg0.local_mac, src=host.mac) /
3238              IP(src=host.ip4, dst=server_nat_ip) /
3239              GRE() /
3240              IP(src=self.pg2.remote_ip4, dst=self.pg3.remote_ip4) /
3241              TCP(sport=1234, dport=1234))
3242         self.pg0.add_stream(p)
3243         self.pg_enable_capture(self.pg_interfaces)
3244         self.pg_start()
3245         p = self.pg0.get_capture(1)
3246         packet = p[0]
3247         try:
3248             self.assertEqual(packet[IP].src, host_nat_ip)
3249             self.assertEqual(packet[IP].dst, server.ip4)
3250             self.assertEqual(packet.haslayer(GRE), 1)
3251             self.assert_packet_checksums_valid(packet)
3252         except:
3253             self.logger.error(ppp("Unexpected or invalid packet:", packet))
3254             raise
3255
3256         # server to host
3257         p = (Ether(dst=self.pg0.local_mac, src=server.mac) /
3258              IP(src=server.ip4, dst=host_nat_ip) /
3259              GRE() /
3260              IP(src=self.pg3.remote_ip4, dst=self.pg2.remote_ip4) /
3261              TCP(sport=1234, dport=1234))
3262         self.pg0.add_stream(p)
3263         self.pg_enable_capture(self.pg_interfaces)
3264         self.pg_start()
3265         p = self.pg0.get_capture(1)
3266         packet = p[0]
3267         try:
3268             self.assertEqual(packet[IP].src, server_nat_ip)
3269             self.assertEqual(packet[IP].dst, host.ip4)
3270             self.assertEqual(packet.haslayer(GRE), 1)
3271             self.assert_packet_checksums_valid(packet)
3272         except:
3273             self.logger.error(ppp("Unexpected or invalid packet:", packet))
3274             raise
3275
3276     def test_output_feature(self):
3277         """ NAT44 interface output feature (in2out postrouting) """
3278         self.nat44_add_address(self.nat_addr)
3279         flags = self.config_flags.NAT_IS_INSIDE
3280         self.vapi.nat44_interface_add_del_output_feature(
3281             is_add=1, flags=flags,
3282             sw_if_index=self.pg0.sw_if_index)
3283         self.vapi.nat44_interface_add_del_output_feature(
3284             is_add=1, flags=flags,
3285             sw_if_index=self.pg1.sw_if_index)
3286         self.vapi.nat44_interface_add_del_output_feature(
3287             is_add=1,
3288             sw_if_index=self.pg3.sw_if_index)
3289
3290         # in2out
3291         pkts = self.create_stream_in(self.pg0, self.pg3)
3292         self.pg0.add_stream(pkts)
3293         self.pg_enable_capture(self.pg_interfaces)
3294         self.pg_start()
3295         capture = self.pg3.get_capture(len(pkts))
3296         self.verify_capture_out(capture)
3297
3298         # out2in
3299         pkts = self.create_stream_out(self.pg3)
3300         self.pg3.add_stream(pkts)
3301         self.pg_enable_capture(self.pg_interfaces)
3302         self.pg_start()
3303         capture = self.pg0.get_capture(len(pkts))
3304         self.verify_capture_in(capture, self.pg0)
3305
3306         # from non-NAT interface to NAT inside interface
3307         pkts = self.create_stream_in(self.pg2, self.pg0)
3308         self.pg2.add_stream(pkts)
3309         self.pg_enable_capture(self.pg_interfaces)
3310         self.pg_start()
3311         capture = self.pg0.get_capture(len(pkts))
3312         self.verify_capture_no_translation(capture, self.pg2, self.pg0)
3313
3314     def test_output_feature_vrf_aware(self):
3315         """ NAT44 interface output feature VRF aware (in2out postrouting) """
3316         nat_ip_vrf10 = "10.0.0.10"
3317         nat_ip_vrf20 = "10.0.0.20"
3318
3319         r1 = VppIpRoute(self, self.pg3.remote_ip4, 32,
3320                         [VppRoutePath(self.pg3.remote_ip4,
3321                                       self.pg3.sw_if_index)],
3322                         table_id=10)
3323         r2 = VppIpRoute(self, self.pg3.remote_ip4, 32,
3324                         [VppRoutePath(self.pg3.remote_ip4,
3325                                       self.pg3.sw_if_index)],
3326                         table_id=20)
3327         r1.add_vpp_config()
3328         r2.add_vpp_config()
3329
3330         self.nat44_add_address(nat_ip_vrf10, vrf_id=10)
3331         self.nat44_add_address(nat_ip_vrf20, vrf_id=20)
3332         flags = self.config_flags.NAT_IS_INSIDE
3333         self.vapi.nat44_interface_add_del_output_feature(
3334             is_add=1, flags=flags,
3335             sw_if_index=self.pg4.sw_if_index)
3336         self.vapi.nat44_interface_add_del_output_feature(
3337             is_add=1, flags=flags,
3338             sw_if_index=self.pg6.sw_if_index)
3339         self.vapi.nat44_interface_add_del_output_feature(
3340             is_add=1,
3341             sw_if_index=self.pg3.sw_if_index)
3342
3343         # in2out VRF 10
3344         pkts = self.create_stream_in(self.pg4, self.pg3)
3345         self.pg4.add_stream(pkts)
3346         self.pg_enable_capture(self.pg_interfaces)
3347         self.pg_start()
3348         capture = self.pg3.get_capture(len(pkts))
3349         self.verify_capture_out(capture, nat_ip=nat_ip_vrf10)
3350
3351         # out2in VRF 10
3352         pkts = self.create_stream_out(self.pg3, dst_ip=nat_ip_vrf10)
3353         self.pg3.add_stream(pkts)
3354         self.pg_enable_capture(self.pg_interfaces)
3355         self.pg_start()
3356         capture = self.pg4.get_capture(len(pkts))
3357         self.verify_capture_in(capture, self.pg4)
3358
3359         # in2out VRF 20
3360         pkts = self.create_stream_in(self.pg6, self.pg3)
3361         self.pg6.add_stream(pkts)
3362         self.pg_enable_capture(self.pg_interfaces)
3363         self.pg_start()
3364         capture = self.pg3.get_capture(len(pkts))
3365         self.verify_capture_out(capture, nat_ip=nat_ip_vrf20)
3366
3367         # out2in VRF 20
3368         pkts = self.create_stream_out(self.pg3, dst_ip=nat_ip_vrf20)
3369         self.pg3.add_stream(pkts)
3370         self.pg_enable_capture(self.pg_interfaces)
3371         self.pg_start()
3372         capture = self.pg6.get_capture(len(pkts))
3373         self.verify_capture_in(capture, self.pg6)
3374
3375     def test_output_feature_hairpinning(self):
3376         """ NAT44 interface output feature hairpinning (in2out postrouting) """
3377         host = self.pg0.remote_hosts[0]
3378         server = self.pg0.remote_hosts[1]
3379         host_in_port = 1234
3380         host_out_port = 0
3381         server_in_port = 5678
3382         server_out_port = 8765
3383
3384         self.nat44_add_address(self.nat_addr)
3385         flags = self.config_flags.NAT_IS_INSIDE
3386         self.vapi.nat44_interface_add_del_output_feature(
3387             is_add=1, flags=flags,
3388             sw_if_index=self.pg0.sw_if_index)
3389         self.vapi.nat44_interface_add_del_output_feature(
3390             is_add=1,
3391             sw_if_index=self.pg1.sw_if_index)
3392
3393         # add static mapping for server
3394         self.nat44_add_static_mapping(server.ip4, self.nat_addr,
3395                                       server_in_port, server_out_port,
3396                                       proto=IP_PROTOS.tcp)
3397
3398         # send packet from host to server
3399         p = (Ether(src=host.mac, dst=self.pg0.local_mac) /
3400              IP(src=host.ip4, dst=self.nat_addr) /
3401              TCP(sport=host_in_port, dport=server_out_port))
3402         self.pg0.add_stream(p)
3403         self.pg_enable_capture(self.pg_interfaces)
3404         self.pg_start()
3405         capture = self.pg0.get_capture(1)
3406         p = capture[0]
3407         try:
3408             ip = p[IP]
3409             tcp = p[TCP]
3410             self.assertEqual(ip.src, self.nat_addr)
3411             self.assertEqual(ip.dst, server.ip4)
3412             self.assertNotEqual(tcp.sport, host_in_port)
3413             self.assertEqual(tcp.dport, server_in_port)
3414             self.assert_packet_checksums_valid(p)
3415             host_out_port = tcp.sport
3416         except:
3417             self.logger.error(ppp("Unexpected or invalid packet:", p))
3418             raise
3419
3420         # send reply from server to host
3421         p = (Ether(src=server.mac, dst=self.pg0.local_mac) /
3422              IP(src=server.ip4, dst=self.nat_addr) /
3423              TCP(sport=server_in_port, dport=host_out_port))
3424         self.pg0.add_stream(p)
3425         self.pg_enable_capture(self.pg_interfaces)
3426         self.pg_start()
3427         capture = self.pg0.get_capture(1)
3428         p = capture[0]
3429         try:
3430             ip = p[IP]
3431             tcp = p[TCP]
3432             self.assertEqual(ip.src, self.nat_addr)
3433             self.assertEqual(ip.dst, host.ip4)
3434             self.assertEqual(tcp.sport, server_out_port)
3435             self.assertEqual(tcp.dport, host_in_port)
3436             self.assert_packet_checksums_valid(p)
3437         except:
3438             self.logger.error(ppp("Unexpected or invalid packet:", p))
3439             raise
3440
3441     def test_one_armed_nat44(self):
3442         """ One armed NAT44 """
3443         remote_host = self.pg9.remote_hosts[0]
3444         local_host = self.pg9.remote_hosts[1]
3445         external_port = 0
3446
3447         self.nat44_add_address(self.nat_addr)
3448         flags = self.config_flags.NAT_IS_INSIDE
3449         self.vapi.nat44_interface_add_del_feature(
3450             sw_if_index=self.pg9.sw_if_index,
3451             is_add=1)
3452         self.vapi.nat44_interface_add_del_feature(
3453             sw_if_index=self.pg9.sw_if_index,
3454             flags=flags, is_add=1)
3455
3456         # in2out
3457         p = (Ether(src=self.pg9.remote_mac, dst=self.pg9.local_mac) /
3458              IP(src=local_host.ip4, dst=remote_host.ip4) /
3459              TCP(sport=12345, dport=80))
3460         self.pg9.add_stream(p)
3461         self.pg_enable_capture(self.pg_interfaces)
3462         self.pg_start()
3463         capture = self.pg9.get_capture(1)
3464         p = capture[0]
3465         try:
3466             ip = p[IP]
3467             tcp = p[TCP]
3468             self.assertEqual(ip.src, self.nat_addr)
3469             self.assertEqual(ip.dst, remote_host.ip4)
3470             self.assertNotEqual(tcp.sport, 12345)
3471             external_port = tcp.sport
3472             self.assertEqual(tcp.dport, 80)
3473             self.assert_packet_checksums_valid(p)
3474         except:
3475             self.logger.error(ppp("Unexpected or invalid packet:", p))
3476             raise
3477
3478         # out2in
3479         p = (Ether(src=self.pg9.remote_mac, dst=self.pg9.local_mac) /
3480              IP(src=remote_host.ip4, dst=self.nat_addr) /
3481              TCP(sport=80, dport=external_port))
3482         self.pg9.add_stream(p)
3483         self.pg_enable_capture(self.pg_interfaces)
3484         self.pg_start()
3485         capture = self.pg9.get_capture(1)
3486         p = capture[0]
3487         try:
3488             ip = p[IP]
3489             tcp = p[TCP]
3490             self.assertEqual(ip.src, remote_host.ip4)
3491             self.assertEqual(ip.dst, local_host.ip4)
3492             self.assertEqual(tcp.sport, 80)
3493             self.assertEqual(tcp.dport, 12345)
3494             self.assert_packet_checksums_valid(p)
3495         except:
3496             self.logger.error(ppp("Unexpected or invalid packet:", p))
3497             raise
3498
3499         err = self.statistics.get_err_counter(
3500             '/err/nat44-classify/next in2out')
3501         self.assertEqual(err, 1)
3502         err = self.statistics.get_err_counter(
3503             '/err/nat44-classify/next out2in')
3504         self.assertEqual(err, 1)
3505
3506     def test_del_session(self):
3507         """ Delete NAT44 session """
3508         self.nat44_add_address(self.nat_addr)
3509         flags = self.config_flags.NAT_IS_INSIDE
3510         self.vapi.nat44_interface_add_del_feature(
3511             sw_if_index=self.pg0.sw_if_index,
3512             flags=flags, is_add=1)
3513         self.vapi.nat44_interface_add_del_feature(
3514             sw_if_index=self.pg1.sw_if_index,
3515             is_add=1)
3516
3517         pkts = self.create_stream_in(self.pg0, self.pg1)
3518         self.pg0.add_stream(pkts)
3519         self.pg_enable_capture(self.pg_interfaces)
3520         self.pg_start()
3521         self.pg1.get_capture(len(pkts))
3522
3523         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
3524         nsessions = len(sessions)
3525
3526         self.vapi.nat44_del_session(address=sessions[0].inside_ip_address,
3527                                     port=sessions[0].inside_port,
3528                                     protocol=sessions[0].protocol,
3529                                     flags=self.config_flags.NAT_IS_INSIDE)
3530         self.vapi.nat44_del_session(address=sessions[1].outside_ip_address,
3531                                     port=sessions[1].outside_port,
3532                                     protocol=sessions[1].protocol)
3533
3534         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
3535         self.assertEqual(nsessions - len(sessions), 2)
3536
3537         self.vapi.nat44_del_session(address=sessions[0].inside_ip_address,
3538                                     port=sessions[0].inside_port,
3539                                     protocol=sessions[0].protocol,
3540                                     flags=self.config_flags.NAT_IS_INSIDE)
3541
3542         self.verify_no_nat44_user()
3543
3544     def test_frag_in_order(self):
3545         """ NAT44 translate fragments arriving in order """
3546
3547         self.nat44_add_address(self.nat_addr)
3548         flags = self.config_flags.NAT_IS_INSIDE
3549         self.vapi.nat44_interface_add_del_feature(
3550             sw_if_index=self.pg0.sw_if_index,
3551             flags=flags, is_add=1)
3552         self.vapi.nat44_interface_add_del_feature(
3553             sw_if_index=self.pg1.sw_if_index,
3554             is_add=1)
3555
3556         self.frag_in_order(proto=IP_PROTOS.tcp)
3557         self.frag_in_order(proto=IP_PROTOS.udp)
3558         self.frag_in_order(proto=IP_PROTOS.icmp)
3559
3560     def test_frag_forwarding(self):
3561         """ NAT44 forwarding fragment test """
3562         self.vapi.nat44_add_del_interface_addr(
3563             is_add=1,
3564             sw_if_index=self.pg1.sw_if_index)
3565         flags = self.config_flags.NAT_IS_INSIDE
3566         self.vapi.nat44_interface_add_del_feature(
3567             sw_if_index=self.pg0.sw_if_index,
3568             flags=flags, is_add=1)
3569         self.vapi.nat44_interface_add_del_feature(
3570             sw_if_index=self.pg1.sw_if_index,
3571             is_add=1)
3572         self.vapi.nat44_forwarding_enable_disable(enable=1)
3573
3574         data = b"A" * 16 + b"B" * 16 + b"C" * 3
3575         pkts = self.create_stream_frag(self.pg1,
3576                                        self.pg0.remote_ip4,
3577                                        4789,
3578                                        4789,
3579                                        data,
3580                                        proto=IP_PROTOS.udp)
3581         self.pg1.add_stream(pkts)
3582         self.pg_enable_capture(self.pg_interfaces)
3583         self.pg_start()
3584         frags = self.pg0.get_capture(len(pkts))
3585         p = self.reass_frags_and_verify(frags,
3586                                         self.pg1.remote_ip4,
3587                                         self.pg0.remote_ip4)
3588         self.assertEqual(p[UDP].sport, 4789)
3589         self.assertEqual(p[UDP].dport, 4789)
3590         self.assertEqual(data, p[Raw].load)
3591
3592     def test_reass_hairpinning(self):
3593         """ NAT44 fragments hairpinning """
3594
3595         self.server = self.pg0.remote_hosts[1]
3596         self.host_in_port = random.randint(1025, 65535)
3597         self.server_in_port = random.randint(1025, 65535)
3598         self.server_out_port = random.randint(1025, 65535)
3599
3600         self.nat44_add_address(self.nat_addr)
3601         flags = self.config_flags.NAT_IS_INSIDE
3602         self.vapi.nat44_interface_add_del_feature(
3603             sw_if_index=self.pg0.sw_if_index,
3604             flags=flags, is_add=1)
3605         self.vapi.nat44_interface_add_del_feature(
3606             sw_if_index=self.pg1.sw_if_index,
3607             is_add=1)
3608         # add static mapping for server
3609         self.nat44_add_static_mapping(self.server.ip4, self.nat_addr,
3610                                       self.server_in_port,
3611                                       self.server_out_port,
3612                                       proto=IP_PROTOS.tcp)
3613         self.nat44_add_static_mapping(self.server.ip4, self.nat_addr,
3614                                       self.server_in_port,
3615                                       self.server_out_port,
3616                                       proto=IP_PROTOS.udp)
3617         self.nat44_add_static_mapping(self.server.ip4, self.nat_addr)
3618
3619         self.reass_hairpinning(proto=IP_PROTOS.tcp)
3620         self.reass_hairpinning(proto=IP_PROTOS.udp)
3621         self.reass_hairpinning(proto=IP_PROTOS.icmp)
3622
3623     def test_frag_out_of_order(self):
3624         """ NAT44 translate fragments arriving out of order """
3625
3626         self.nat44_add_address(self.nat_addr)
3627         flags = self.config_flags.NAT_IS_INSIDE
3628         self.vapi.nat44_interface_add_del_feature(
3629             sw_if_index=self.pg0.sw_if_index,
3630             flags=flags, is_add=1)
3631         self.vapi.nat44_interface_add_del_feature(
3632             sw_if_index=self.pg1.sw_if_index,
3633             is_add=1)
3634
3635         self.frag_out_of_order(proto=IP_PROTOS.tcp)
3636         self.frag_out_of_order(proto=IP_PROTOS.udp)
3637         self.frag_out_of_order(proto=IP_PROTOS.icmp)
3638
3639     def test_port_restricted(self):
3640         """ Port restricted NAT44 (MAP-E CE) """
3641         self.nat44_add_address(self.nat_addr)
3642         flags = self.config_flags.NAT_IS_INSIDE
3643         self.vapi.nat44_interface_add_del_feature(
3644             sw_if_index=self.pg0.sw_if_index,
3645             flags=flags, is_add=1)
3646         self.vapi.nat44_interface_add_del_feature(
3647             sw_if_index=self.pg1.sw_if_index,
3648             is_add=1)
3649         self.vapi.nat_set_addr_and_port_alloc_alg(alg=1,
3650                                                   psid_offset=6,
3651                                                   psid_length=6,
3652                                                   psid=10)
3653
3654         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
3655              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3656              TCP(sport=4567, dport=22))
3657         self.pg0.add_stream(p)
3658         self.pg_enable_capture(self.pg_interfaces)
3659         self.pg_start()
3660         capture = self.pg1.get_capture(1)
3661         p = capture[0]
3662         try:
3663             ip = p[IP]
3664             tcp = p[TCP]
3665             self.assertEqual(ip.dst, self.pg1.remote_ip4)
3666             self.assertEqual(ip.src, self.nat_addr)
3667             self.assertEqual(tcp.dport, 22)
3668             self.assertNotEqual(tcp.sport, 4567)
3669             self.assertEqual((tcp.sport >> 6) & 63, 10)
3670             self.assert_packet_checksums_valid(p)
3671         except:
3672             self.logger.error(ppp("Unexpected or invalid packet:", p))
3673             raise
3674
3675     def test_port_range(self):
3676         """ External address port range """
3677         self.nat44_add_address(self.nat_addr)
3678         flags = self.config_flags.NAT_IS_INSIDE
3679         self.vapi.nat44_interface_add_del_feature(
3680             sw_if_index=self.pg0.sw_if_index,
3681             flags=flags, is_add=1)
3682         self.vapi.nat44_interface_add_del_feature(
3683             sw_if_index=self.pg1.sw_if_index,
3684             is_add=1)
3685         self.vapi.nat_set_addr_and_port_alloc_alg(alg=2,
3686                                                   start_port=1025,
3687                                                   end_port=1027)
3688
3689         pkts = []
3690         for port in range(0, 5):
3691             p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
3692                  IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3693                  TCP(sport=1125 + port))
3694             pkts.append(p)
3695         self.pg0.add_stream(pkts)
3696         self.pg_enable_capture(self.pg_interfaces)
3697         self.pg_start()
3698         capture = self.pg1.get_capture(3)
3699         for p in capture:
3700             tcp = p[TCP]
3701             self.assertGreaterEqual(tcp.sport, 1025)
3702             self.assertLessEqual(tcp.sport, 1027)
3703
3704     def test_multiple_outside_vrf(self):
3705         """ Multiple outside VRF """
3706         vrf_id1 = 1
3707         vrf_id2 = 2
3708
3709         self.pg1.unconfig_ip4()
3710         self.pg2.unconfig_ip4()
3711         self.vapi.ip_table_add_del(is_add=1, table={'table_id': vrf_id1})
3712         self.vapi.ip_table_add_del(is_add=1, table={'table_id': vrf_id2})
3713         self.pg1.set_table_ip4(vrf_id1)
3714         self.pg2.set_table_ip4(vrf_id2)
3715         self.pg1.config_ip4()
3716         self.pg2.config_ip4()
3717         self.pg1.resolve_arp()
3718         self.pg2.resolve_arp()
3719
3720         self.nat44_add_address(self.nat_addr)
3721         flags = self.config_flags.NAT_IS_INSIDE
3722         self.vapi.nat44_interface_add_del_feature(
3723             sw_if_index=self.pg0.sw_if_index,
3724             flags=flags, is_add=1)
3725         self.vapi.nat44_interface_add_del_feature(
3726             sw_if_index=self.pg1.sw_if_index,
3727             is_add=1)
3728         self.vapi.nat44_interface_add_del_feature(
3729             sw_if_index=self.pg2.sw_if_index,
3730             is_add=1)
3731
3732         try:
3733             # first VRF
3734             pkts = self.create_stream_in(self.pg0, self.pg1)
3735             self.pg0.add_stream(pkts)
3736             self.pg_enable_capture(self.pg_interfaces)
3737             self.pg_start()
3738             capture = self.pg1.get_capture(len(pkts))
3739             self.verify_capture_out(capture, self.nat_addr)
3740
3741             pkts = self.create_stream_out(self.pg1, self.nat_addr)
3742             self.pg1.add_stream(pkts)
3743             self.pg_enable_capture(self.pg_interfaces)
3744             self.pg_start()
3745             capture = self.pg0.get_capture(len(pkts))
3746             self.verify_capture_in(capture, self.pg0)
3747
3748             self.tcp_port_in = 60303
3749             self.udp_port_in = 60304
3750             self.icmp_id_in = 60305
3751
3752             # second VRF
3753             pkts = self.create_stream_in(self.pg0, self.pg2)
3754             self.pg0.add_stream(pkts)
3755             self.pg_enable_capture(self.pg_interfaces)
3756             self.pg_start()
3757             capture = self.pg2.get_capture(len(pkts))
3758             self.verify_capture_out(capture, self.nat_addr)
3759
3760             pkts = self.create_stream_out(self.pg2, self.nat_addr)
3761             self.pg2.add_stream(pkts)
3762             self.pg_enable_capture(self.pg_interfaces)
3763             self.pg_start()
3764             capture = self.pg0.get_capture(len(pkts))
3765             self.verify_capture_in(capture, self.pg0)
3766
3767         finally:
3768             self.nat44_add_address(self.nat_addr, is_add=0)
3769             self.pg1.unconfig_ip4()
3770             self.pg2.unconfig_ip4()
3771             self.pg1.set_table_ip4(0)
3772             self.pg2.set_table_ip4(0)
3773             self.pg1.config_ip4()
3774             self.pg2.config_ip4()
3775             self.pg1.resolve_arp()
3776             self.pg2.resolve_arp()
3777
3778     @unittest.skipUnless(running_extended_tests, "part of extended tests")
3779     def test_session_timeout(self):
3780         """ NAT44 session timeouts """
3781         self.nat44_add_address(self.nat_addr)
3782         flags = self.config_flags.NAT_IS_INSIDE
3783         self.vapi.nat44_interface_add_del_feature(
3784             sw_if_index=self.pg0.sw_if_index,
3785             flags=flags, is_add=1)
3786         self.vapi.nat44_interface_add_del_feature(
3787             sw_if_index=self.pg1.sw_if_index,
3788             is_add=1)
3789         self.vapi.nat_set_timeouts(udp=5, tcp_established=7440,
3790                                    tcp_transitory=240, icmp=60)
3791
3792         max_sessions = 1000
3793         pkts = []
3794         for i in range(0, max_sessions):
3795             src = "10.10.%u.%u" % ((i & 0xFF00) >> 8, i & 0xFF)
3796             p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
3797                  IP(src=src, dst=self.pg1.remote_ip4) /
3798                  UDP(sport=1025, dport=53))
3799             pkts.append(p)
3800         self.pg0.add_stream(pkts)
3801         self.pg_enable_capture(self.pg_interfaces)
3802         self.pg_start()
3803         self.pg1.get_capture(max_sessions)
3804
3805         sleep(6)
3806
3807         pkts = []
3808         for i in range(0, max_sessions):
3809             src = "10.10.%u.%u" % ((i & 0xFF00) >> 8, i & 0xFF)
3810             p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
3811                  IP(src=src, dst=self.pg1.remote_ip4) /
3812                  UDP(sport=1026, dport=53))
3813             pkts.append(p)
3814         self.pg0.add_stream(pkts)
3815         self.pg_enable_capture(self.pg_interfaces)
3816         self.pg_start()
3817         self.pg1.get_capture(max_sessions)
3818
3819         nsessions = 0
3820         users = self.vapi.nat44_user_dump()
3821         for user in users:
3822             nsessions = nsessions + user.nsessions
3823         self.assertLess(nsessions, 2 * max_sessions)
3824
3825     def test_mss_clamping(self):
3826         """ TCP MSS clamping """
3827         self.nat44_add_address(self.nat_addr)
3828         flags = self.config_flags.NAT_IS_INSIDE
3829         self.vapi.nat44_interface_add_del_feature(
3830             sw_if_index=self.pg0.sw_if_index,
3831             flags=flags, is_add=1)
3832         self.vapi.nat44_interface_add_del_feature(
3833             sw_if_index=self.pg1.sw_if_index,
3834             is_add=1)
3835
3836         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
3837              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3838              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
3839                  flags="S", options=[('MSS', 1400)]))
3840
3841         self.vapi.nat_set_mss_clamping(enable=1, mss_value=1000)
3842         self.pg0.add_stream(p)
3843         self.pg_enable_capture(self.pg_interfaces)
3844         self.pg_start()
3845         capture = self.pg1.get_capture(1)
3846         # Negotiated MSS value greater than configured - changed
3847         self.verify_mss_value(capture[0], 1000)
3848
3849         self.vapi.nat_set_mss_clamping(enable=0, mss_value=1500)
3850         self.pg0.add_stream(p)
3851         self.pg_enable_capture(self.pg_interfaces)
3852         self.pg_start()
3853         capture = self.pg1.get_capture(1)
3854         # MSS clamping disabled - negotiated MSS unchanged
3855         self.verify_mss_value(capture[0], 1400)
3856
3857         self.vapi.nat_set_mss_clamping(enable=1, mss_value=1500)
3858         self.pg0.add_stream(p)
3859         self.pg_enable_capture(self.pg_interfaces)
3860         self.pg_start()
3861         capture = self.pg1.get_capture(1)
3862         # Negotiated MSS value smaller than configured - unchanged
3863         self.verify_mss_value(capture[0], 1400)
3864
3865     @unittest.skipUnless(running_extended_tests, "part of extended tests")
3866     def test_ha_send(self):
3867         """ Send HA session synchronization events (active) """
3868         self.nat44_add_address(self.nat_addr)
3869         flags = self.config_flags.NAT_IS_INSIDE
3870         self.vapi.nat44_interface_add_del_feature(
3871             sw_if_index=self.pg0.sw_if_index,
3872             flags=flags, is_add=1)
3873         self.vapi.nat44_interface_add_del_feature(
3874             sw_if_index=self.pg1.sw_if_index,
3875             is_add=1)
3876         self.vapi.nat_ha_set_listener(ip_address=self.pg3.local_ip4,
3877                                       port=12345,
3878                                       path_mtu=512)
3879         self.vapi.nat_ha_set_failover(ip_address=self.pg3.remote_ip4,
3880                                       port=12346, session_refresh_interval=10)
3881         bind_layers(UDP, HANATStateSync, sport=12345)
3882
3883         # create sessions
3884         pkts = self.create_stream_in(self.pg0, self.pg1)
3885         self.pg0.add_stream(pkts)
3886         self.pg_enable_capture(self.pg_interfaces)
3887         self.pg_start()
3888         capture = self.pg1.get_capture(len(pkts))
3889         self.verify_capture_out(capture)
3890         # active send HA events
3891         self.vapi.nat_ha_flush()
3892         stats = self.statistics.get_counter('/nat44/ha/add-event-send')
3893         self.assertEqual(stats[0][0], 3)
3894         capture = self.pg3.get_capture(1)
3895         p = capture[0]
3896         self.assert_packet_checksums_valid(p)
3897         try:
3898             ip = p[IP]
3899             udp = p[UDP]
3900             hanat = p[HANATStateSync]
3901         except IndexError:
3902             self.logger.error(ppp("Invalid packet:", p))
3903             raise
3904         else:
3905             self.assertEqual(ip.src, self.pg3.local_ip4)
3906             self.assertEqual(ip.dst, self.pg3.remote_ip4)
3907             self.assertEqual(udp.sport, 12345)
3908             self.assertEqual(udp.dport, 12346)
3909             self.assertEqual(hanat.version, 1)
3910             self.assertEqual(hanat.thread_index, 0)
3911             self.assertEqual(hanat.count, 3)
3912             seq = hanat.sequence_number
3913             for event in hanat.events:
3914                 self.assertEqual(event.event_type, 1)
3915                 self.assertEqual(event.in_addr, self.pg0.remote_ip4)
3916                 self.assertEqual(event.out_addr, self.nat_addr)
3917                 self.assertEqual(event.fib_index, 0)
3918
3919         # ACK received events
3920         ack = (Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac) /
3921                IP(src=self.pg3.remote_ip4, dst=self.pg3.local_ip4) /
3922                UDP(sport=12346, dport=12345) /
3923                HANATStateSync(sequence_number=seq, flags='ACK'))
3924         self.pg3.add_stream(ack)
3925         self.pg_start()
3926         stats = self.statistics.get_counter('/nat44/ha/ack-recv')
3927         self.assertEqual(stats[0][0], 1)
3928
3929         # delete one session
3930         self.pg_enable_capture(self.pg_interfaces)
3931         self.vapi.nat44_del_session(address=self.pg0.remote_ip4,
3932                                     port=self.tcp_port_in,
3933                                     protocol=IP_PROTOS.tcp,
3934                                     flags=self.config_flags.NAT_IS_INSIDE)
3935         self.vapi.nat_ha_flush()
3936         stats = self.statistics.get_counter('/nat44/ha/del-event-send')
3937         self.assertEqual(stats[0][0], 1)
3938         capture = self.pg3.get_capture(1)
3939         p = capture[0]
3940         try:
3941             hanat = p[HANATStateSync]
3942         except IndexError:
3943             self.logger.error(ppp("Invalid packet:", p))
3944             raise
3945         else:
3946             self.assertGreater(hanat.sequence_number, seq)
3947
3948         # do not send ACK, active retry send HA event again
3949         self.pg_enable_capture(self.pg_interfaces)
3950         sleep(12)
3951         stats = self.statistics.get_counter('/nat44/ha/retry-count')
3952         self.assertEqual(stats[0][0], 3)
3953         stats = self.statistics.get_counter('/nat44/ha/missed-count')
3954         self.assertEqual(stats[0][0], 1)
3955         capture = self.pg3.get_capture(3)
3956         for packet in capture:
3957             self.assertEqual(packet, p)
3958
3959         # session counters refresh
3960         pkts = self.create_stream_out(self.pg1)
3961         self.pg1.add_stream(pkts)
3962         self.pg_enable_capture(self.pg_interfaces)
3963         self.pg_start()
3964         self.pg0.get_capture(2)
3965         self.vapi.nat_ha_flush()
3966         stats = self.statistics.get_counter('/nat44/ha/refresh-event-send')
3967         self.assertEqual(stats[0][0], 2)
3968         capture = self.pg3.get_capture(1)
3969         p = capture[0]
3970         self.assert_packet_checksums_valid(p)
3971         try:
3972             ip = p[IP]
3973             udp = p[UDP]
3974             hanat = p[HANATStateSync]
3975         except IndexError:
3976             self.logger.error(ppp("Invalid packet:", p))
3977             raise
3978         else:
3979             self.assertEqual(ip.src, self.pg3.local_ip4)
3980             self.assertEqual(ip.dst, self.pg3.remote_ip4)
3981             self.assertEqual(udp.sport, 12345)
3982             self.assertEqual(udp.dport, 12346)
3983             self.assertEqual(hanat.version, 1)
3984             self.assertEqual(hanat.count, 2)
3985             seq = hanat.sequence_number
3986             for event in hanat.events:
3987                 self.assertEqual(event.event_type, 3)
3988                 self.assertEqual(event.out_addr, self.nat_addr)
3989                 self.assertEqual(event.fib_index, 0)
3990                 self.assertEqual(event.total_pkts, 2)
3991                 self.assertGreater(event.total_bytes, 0)
3992
3993         ack = (Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac) /
3994                IP(src=self.pg3.remote_ip4, dst=self.pg3.local_ip4) /
3995                UDP(sport=12346, dport=12345) /
3996                HANATStateSync(sequence_number=seq, flags='ACK'))
3997         self.pg3.add_stream(ack)
3998         self.pg_start()
3999         stats = self.statistics.get_counter('/nat44/ha/ack-recv')
4000         self.assertEqual(stats[0][0], 2)
4001
4002     def test_ha_recv(self):
4003         """ Receive HA session synchronization events (passive) """
4004         self.nat44_add_address(self.nat_addr)
4005         flags = self.config_flags.NAT_IS_INSIDE
4006         self.vapi.nat44_interface_add_del_feature(
4007             sw_if_index=self.pg0.sw_if_index,
4008             flags=flags, is_add=1)
4009         self.vapi.nat44_interface_add_del_feature(
4010             sw_if_index=self.pg1.sw_if_index,
4011             is_add=1)
4012         self.vapi.nat_ha_set_listener(ip_address=self.pg3.local_ip4,
4013                                       port=12345,
4014                                       path_mtu=512)
4015         bind_layers(UDP, HANATStateSync, sport=12345)
4016
4017         self.tcp_port_out = random.randint(1025, 65535)
4018         self.udp_port_out = random.randint(1025, 65535)
4019
4020         # send HA session add events to failover/passive
4021         p = (Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac) /
4022              IP(src=self.pg3.remote_ip4, dst=self.pg3.local_ip4) /
4023              UDP(sport=12346, dport=12345) /
4024              HANATStateSync(sequence_number=1, events=[
4025                  Event(event_type='add', protocol='tcp',
4026                        in_addr=self.pg0.remote_ip4, out_addr=self.nat_addr,
4027                        in_port=self.tcp_port_in, out_port=self.tcp_port_out,
4028                        eh_addr=self.pg1.remote_ip4,
4029                        ehn_addr=self.pg1.remote_ip4,
4030                        eh_port=self.tcp_external_port,
4031                        ehn_port=self.tcp_external_port, fib_index=0),
4032                  Event(event_type='add', protocol='udp',
4033                        in_addr=self.pg0.remote_ip4, out_addr=self.nat_addr,
4034                        in_port=self.udp_port_in, out_port=self.udp_port_out,
4035                        eh_addr=self.pg1.remote_ip4,
4036                        ehn_addr=self.pg1.remote_ip4,
4037                        eh_port=self.udp_external_port,
4038                        ehn_port=self.udp_external_port, fib_index=0)]))
4039
4040         self.pg3.add_stream(p)
4041         self.pg_enable_capture(self.pg_interfaces)
4042         self.pg_start()
4043         # receive ACK
4044         capture = self.pg3.get_capture(1)
4045         p = capture[0]
4046         try:
4047             hanat = p[HANATStateSync]
4048         except IndexError:
4049             self.logger.error(ppp("Invalid packet:", p))
4050             raise
4051         else:
4052             self.assertEqual(hanat.sequence_number, 1)
4053             self.assertEqual(hanat.flags, 'ACK')
4054             self.assertEqual(hanat.version, 1)
4055             self.assertEqual(hanat.thread_index, 0)
4056         stats = self.statistics.get_counter('/nat44/ha/ack-send')
4057         self.assertEqual(stats[0][0], 1)
4058         stats = self.statistics.get_counter('/nat44/ha/add-event-recv')
4059         self.assertEqual(stats[0][0], 2)
4060         users = self.statistics.get_counter('/nat44/total-users')
4061         self.assertEqual(users[0][0], 1)
4062         sessions = self.statistics.get_counter('/nat44/total-sessions')
4063         self.assertEqual(sessions[0][0], 2)
4064         users = self.vapi.nat44_user_dump()
4065         self.assertEqual(len(users), 1)
4066         self.assertEqual(str(users[0].ip_address),
4067                          self.pg0.remote_ip4)
4068         # there should be 2 sessions created by HA
4069         sessions = self.vapi.nat44_user_session_dump(users[0].ip_address,
4070                                                      users[0].vrf_id)
4071         self.assertEqual(len(sessions), 2)
4072         for session in sessions:
4073             self.assertEqual(str(session.inside_ip_address),
4074                              self.pg0.remote_ip4)
4075             self.assertEqual(str(session.outside_ip_address),
4076                              self.nat_addr)
4077             self.assertIn(session.inside_port,
4078                           [self.tcp_port_in, self.udp_port_in])
4079             self.assertIn(session.outside_port,
4080                           [self.tcp_port_out, self.udp_port_out])
4081             self.assertIn(session.protocol, [IP_PROTOS.tcp, IP_PROTOS.udp])
4082
4083         # send HA session delete event to failover/passive
4084         p = (Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac) /
4085              IP(src=self.pg3.remote_ip4, dst=self.pg3.local_ip4) /
4086              UDP(sport=12346, dport=12345) /
4087              HANATStateSync(sequence_number=2, events=[
4088                  Event(event_type='del', protocol='udp',
4089                        in_addr=self.pg0.remote_ip4, out_addr=self.nat_addr,
4090                        in_port=self.udp_port_in, out_port=self.udp_port_out,
4091                        eh_addr=self.pg1.remote_ip4,
4092                        ehn_addr=self.pg1.remote_ip4,
4093                        eh_port=self.udp_external_port,
4094                        ehn_port=self.udp_external_port, fib_index=0)]))
4095
4096         self.pg3.add_stream(p)
4097         self.pg_enable_capture(self.pg_interfaces)
4098         self.pg_start()
4099         # receive ACK
4100         capture = self.pg3.get_capture(1)
4101         p = capture[0]
4102         try:
4103             hanat = p[HANATStateSync]
4104         except IndexError:
4105             self.logger.error(ppp("Invalid packet:", p))
4106             raise
4107         else:
4108             self.assertEqual(hanat.sequence_number, 2)
4109             self.assertEqual(hanat.flags, 'ACK')
4110             self.assertEqual(hanat.version, 1)
4111         users = self.vapi.nat44_user_dump()
4112         self.assertEqual(len(users), 1)
4113         self.assertEqual(str(users[0].ip_address),
4114                          self.pg0.remote_ip4)
4115         # now we should have only 1 session, 1 deleted by HA
4116         sessions = self.vapi.nat44_user_session_dump(users[0].ip_address,
4117                                                      users[0].vrf_id)
4118         self.assertEqual(len(sessions), 1)
4119         stats = self.statistics.get_counter('/nat44/ha/del-event-recv')
4120         self.assertEqual(stats[0][0], 1)
4121
4122         stats = self.statistics.get_err_counter('/err/nat-ha/pkts-processed')
4123         self.assertEqual(stats, 2)
4124
4125         # send HA session refresh event to failover/passive
4126         p = (Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac) /
4127              IP(src=self.pg3.remote_ip4, dst=self.pg3.local_ip4) /
4128              UDP(sport=12346, dport=12345) /
4129              HANATStateSync(sequence_number=3, events=[
4130                  Event(event_type='refresh', protocol='tcp',
4131                        in_addr=self.pg0.remote_ip4, out_addr=self.nat_addr,
4132                        in_port=self.tcp_port_in, out_port=self.tcp_port_out,
4133                        eh_addr=self.pg1.remote_ip4,
4134                        ehn_addr=self.pg1.remote_ip4,
4135                        eh_port=self.tcp_external_port,
4136                        ehn_port=self.tcp_external_port, fib_index=0,
4137                        total_bytes=1024, total_pkts=2)]))
4138         self.pg3.add_stream(p)
4139         self.pg_enable_capture(self.pg_interfaces)
4140         self.pg_start()
4141         # receive ACK
4142         capture = self.pg3.get_capture(1)
4143         p = capture[0]
4144         try:
4145             hanat = p[HANATStateSync]
4146         except IndexError:
4147             self.logger.error(ppp("Invalid packet:", p))
4148             raise
4149         else:
4150             self.assertEqual(hanat.sequence_number, 3)
4151             self.assertEqual(hanat.flags, 'ACK')
4152             self.assertEqual(hanat.version, 1)
4153         users = self.vapi.nat44_user_dump()
4154         self.assertEqual(len(users), 1)
4155         self.assertEqual(str(users[0].ip_address),
4156                          self.pg0.remote_ip4)
4157         sessions = self.vapi.nat44_user_session_dump(users[0].ip_address,
4158                                                      users[0].vrf_id)
4159         self.assertEqual(len(sessions), 1)
4160         session = sessions[0]
4161         self.assertEqual(session.total_bytes, 1024)
4162         self.assertEqual(session.total_pkts, 2)
4163         stats = self.statistics.get_counter('/nat44/ha/refresh-event-recv')
4164         self.assertEqual(stats[0][0], 1)
4165
4166         stats = self.statistics.get_err_counter('/err/nat-ha/pkts-processed')
4167         self.assertEqual(stats, 3)
4168
4169         # send packet to test session created by HA
4170         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
4171              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
4172              TCP(sport=self.tcp_external_port, dport=self.tcp_port_out))
4173         self.pg1.add_stream(p)
4174         self.pg_enable_capture(self.pg_interfaces)
4175         self.pg_start()
4176         capture = self.pg0.get_capture(1)
4177         p = capture[0]
4178         try:
4179             ip = p[IP]
4180             tcp = p[TCP]
4181         except IndexError:
4182             self.logger.error(ppp("Invalid packet:", p))
4183             raise
4184         else:
4185             self.assertEqual(ip.src, self.pg1.remote_ip4)
4186             self.assertEqual(ip.dst, self.pg0.remote_ip4)
4187             self.assertEqual(tcp.sport, self.tcp_external_port)
4188             self.assertEqual(tcp.dport, self.tcp_port_in)
4189
4190     def tearDown(self):
4191         super(TestNAT44, self).tearDown()
4192         self.clear_nat44()
4193         self.vapi.cli("clear logging")
4194
4195     def show_commands_at_teardown(self):
4196         self.logger.info(self.vapi.cli("show nat44 addresses"))
4197         self.logger.info(self.vapi.cli("show nat44 interfaces"))
4198         self.logger.info(self.vapi.cli("show nat44 static mappings"))
4199         self.logger.info(self.vapi.cli("show nat44 interface address"))
4200         self.logger.info(self.vapi.cli("show nat44 sessions detail"))
4201         self.logger.info(self.vapi.cli("show nat44 hash tables detail"))
4202         self.logger.info(self.vapi.cli("show nat timeouts"))
4203         self.logger.info(
4204             self.vapi.cli("show nat addr-port-assignment-alg"))
4205         self.logger.info(self.vapi.cli("show nat ha"))
4206
4207
4208 class TestNAT44EndpointDependent2(MethodHolder):
4209     """ Endpoint-Dependent mapping and filtering test cases """
4210
4211     @classmethod
4212     def setUpConstants(cls):
4213         super(TestNAT44EndpointDependent2, cls).setUpConstants()
4214         cls.vpp_cmdline.extend(["nat", "{", "endpoint-dependent", "}"])
4215
4216     @classmethod
4217     def tearDownClass(cls):
4218         super(TestNAT44EndpointDependent2, cls).tearDownClass()
4219
4220     def tearDown(self):
4221         super(TestNAT44EndpointDependent2, self).tearDown()
4222
4223     @classmethod
4224     def create_and_add_ip4_table(cls, i, table_id):
4225         cls.vapi.ip_table_add_del(is_add=1, table={'table_id': table_id})
4226         i.set_table_ip4(table_id)
4227
4228     @classmethod
4229     def setUpClass(cls):
4230         super(TestNAT44EndpointDependent2, cls).setUpClass()
4231
4232         cls.create_pg_interfaces(range(3))
4233         cls.interfaces = list(cls.pg_interfaces)
4234
4235         cls.create_and_add_ip4_table(cls.pg1, 10)
4236
4237         for i in cls.interfaces:
4238             i.admin_up()
4239             i.config_ip4()
4240             i.resolve_arp()
4241
4242             i.generate_remote_hosts(1)
4243             i.configure_ipv4_neighbors()
4244
4245     def setUp(self):
4246         super(TestNAT44EndpointDependent2, self).setUp()
4247
4248         nat_config = self.vapi.nat_show_config()
4249         self.assertEqual(1, nat_config.endpoint_dependent)
4250
4251     def nat_add_inside_interface(self, i):
4252         self.vapi.nat44_interface_add_del_feature(
4253             flags=self.config_flags.NAT_IS_INSIDE,
4254             sw_if_index=i.sw_if_index, is_add=1)
4255
4256     def nat_add_outside_interface(self, i):
4257         self.vapi.nat44_interface_add_del_feature(
4258             flags=self.config_flags.NAT_IS_OUTSIDE,
4259             sw_if_index=i.sw_if_index, is_add=1)
4260
4261     def nat_add_interface_address(self, i):
4262         self.nat_addr = i.local_ip4
4263         self.vapi.nat44_add_del_interface_addr(
4264             sw_if_index=i.sw_if_index, is_add=1)
4265
4266     def nat_add_address(self, address, vrf_id=0xFFFFFFFF):
4267         self.nat_addr = address
4268         self.nat44_add_address(address, vrf_id=vrf_id)
4269
4270     def cli(self, command):
4271         result = self.vapi.cli(command)
4272         self.logger.info(result)
4273         # print(result)
4274
4275     def show_configuration(self):
4276         self.cli("show interface")
4277         self.cli("show interface address")
4278         self.cli("show nat44 addresses")
4279         self.cli("show nat44 interfaces")
4280
4281     def create_tcp_stream(self, in_if, out_if, count):
4282         """
4283         Create tcp packet stream
4284
4285         :param in_if: Inside interface
4286         :param out_if: Outside interface
4287         :param count: count of packets to generate
4288         """
4289         pkts = []
4290         port = 6303
4291
4292         for i in range(count):
4293             p = (Ether(dst=in_if.local_mac, src=in_if.remote_mac) /
4294                  IP(src=in_if.remote_ip4, dst=out_if.remote_ip4, ttl=64) /
4295                  TCP(sport=port + i, dport=20))
4296             pkts.append(p)
4297
4298         return pkts
4299
4300     def test_session_limit_per_vrf(self):
4301
4302         inside = self.pg0
4303         inside_vrf10 = self.pg1
4304         outside = self.pg2
4305
4306         limit = 5
4307
4308         # 2 interfaces pg0, pg1 (vrf10, limit 1 tcp session)
4309         # non existing vrf_id makes process core dump
4310         self.vapi.nat44_set_session_limit(session_limit=limit, vrf_id=10)
4311
4312         self.nat_add_inside_interface(inside)
4313         self.nat_add_inside_interface(inside_vrf10)
4314         self.nat_add_outside_interface(outside)
4315
4316         # vrf independent
4317         self.nat_add_interface_address(outside)
4318
4319         # BUG: causing core dump - when bad vrf_id is specified
4320         # self.nat44_add_address(outside.local_ip4, vrf_id=20)
4321
4322         self.show_configuration()
4323
4324         stream = self.create_tcp_stream(inside_vrf10, outside, limit * 2)
4325         inside_vrf10.add_stream(stream)
4326
4327         self.pg_enable_capture(self.pg_interfaces)
4328         self.pg_start()
4329
4330         capture = outside.get_capture(limit)
4331
4332         stream = self.create_tcp_stream(inside, outside, limit * 2)
4333         inside.add_stream(stream)
4334
4335         self.pg_enable_capture(self.pg_interfaces)
4336         self.pg_start()
4337
4338         capture = outside.get_capture(len(stream))
4339
4340
4341 class TestNAT44EndpointDependent(MethodHolder):
4342     """ Endpoint-Dependent mapping and filtering test cases """
4343
4344     @classmethod
4345     def setUpConstants(cls):
4346         super(TestNAT44EndpointDependent, cls).setUpConstants()
4347         cls.vpp_cmdline.extend(["nat", "{", "endpoint-dependent", "}"])
4348
4349     @classmethod
4350     def setUpClass(cls):
4351         super(TestNAT44EndpointDependent, cls).setUpClass()
4352         cls.vapi.cli("set log class nat level debug")
4353
4354         cls.tcp_port_in = 6303
4355         cls.tcp_port_out = 6303
4356         cls.udp_port_in = 6304
4357         cls.udp_port_out = 6304
4358         cls.icmp_id_in = 6305
4359         cls.icmp_id_out = 6305
4360         cls.nat_addr = '10.0.0.3'
4361         cls.ipfix_src_port = 4739
4362         cls.ipfix_domain_id = 1
4363         cls.tcp_external_port = 80
4364
4365         cls.create_pg_interfaces(range(9))
4366         cls.interfaces = list(cls.pg_interfaces[0:3])
4367
4368         for i in cls.interfaces:
4369             i.admin_up()
4370             i.config_ip4()
4371             i.resolve_arp()
4372
4373         cls.pg0.generate_remote_hosts(3)
4374         cls.pg0.configure_ipv4_neighbors()
4375
4376         cls.pg3.admin_up()
4377
4378         cls.pg4.generate_remote_hosts(2)
4379         cls.pg4.config_ip4()
4380         cls.vapi.sw_interface_add_del_address(
4381             sw_if_index=cls.pg4.sw_if_index,
4382             prefix="10.0.0.1/24")
4383
4384         cls.pg4.admin_up()
4385         cls.pg4.resolve_arp()
4386         cls.pg4._remote_hosts[1]._ip4 = cls.pg4._remote_hosts[0]._ip4
4387         cls.pg4.resolve_arp()
4388
4389         zero_ip4 = socket.inet_pton(socket.AF_INET, "0.0.0.0")
4390         cls.vapi.ip_table_add_del(is_add=1, table={'table_id': 1})
4391
4392         cls.pg5._local_ip4 = "10.1.1.1"
4393         cls.pg5._remote_hosts[0]._ip4 = "10.1.1.2"
4394         cls.pg5.set_table_ip4(1)
4395         cls.pg5.config_ip4()
4396         cls.pg5.admin_up()
4397         r1 = VppIpRoute(cls, cls.pg5.remote_ip4, 32,
4398                         [VppRoutePath("0.0.0.0",
4399                                       cls.pg5.sw_if_index)],
4400                         table_id=1,
4401                         register=False)
4402         r1.add_vpp_config()
4403
4404         cls.pg6._local_ip4 = "10.1.2.1"
4405         cls.pg6._remote_hosts[0]._ip4 = "10.1.2.2"
4406         cls.pg6.set_table_ip4(1)
4407         cls.pg6.config_ip4()
4408         cls.pg6.admin_up()
4409
4410         r2 = VppIpRoute(cls, cls.pg6.remote_ip4, 32,
4411                         [VppRoutePath("0.0.0.0",
4412                                       cls.pg6.sw_if_index)],
4413                         table_id=1,
4414                         register=False)
4415         r3 = VppIpRoute(cls, cls.pg6.remote_ip4, 16,
4416                         [VppRoutePath("0.0.0.0",
4417                                       0xffffffff,
4418                                       nh_table_id=1)],
4419                         table_id=0,
4420                         register=False)
4421         r4 = VppIpRoute(cls, "0.0.0.0", 0,
4422                         [VppRoutePath("0.0.0.0", 0xffffffff,
4423                                       nh_table_id=0)],
4424                         table_id=1,
4425                         register=False)
4426         r5 = VppIpRoute(cls, "0.0.0.0", 0,
4427                         [VppRoutePath(cls.pg1.local_ip4,
4428                                       cls.pg1.sw_if_index)],
4429                         register=False)
4430         r2.add_vpp_config()
4431         r3.add_vpp_config()
4432         r4.add_vpp_config()
4433         r5.add_vpp_config()
4434
4435         cls.pg5.resolve_arp()
4436         cls.pg6.resolve_arp()
4437
4438         cls.pg7.admin_up()
4439         cls.pg7.config_ip4()
4440         cls.pg7.resolve_arp()
4441         cls.pg7.generate_remote_hosts(3)
4442         cls.pg7.configure_ipv4_neighbors()
4443
4444         cls.pg8.admin_up()
4445         cls.pg8.config_ip4()
4446         cls.pg8.resolve_arp()
4447
4448     def setUp(self):
4449         super(TestNAT44EndpointDependent, self).setUp()
4450         self.vapi.nat_set_timeouts(
4451             udp=300, tcp_established=7440, tcp_transitory=240, icmp=60)
4452
4453     @classmethod
4454     def tearDownClass(cls):
4455         super(TestNAT44EndpointDependent, cls).tearDownClass()
4456
4457     def test_frag_in_order(self):
4458         """ NAT44 translate fragments arriving in order """
4459         self.nat44_add_address(self.nat_addr)
4460         flags = self.config_flags.NAT_IS_INSIDE
4461         self.vapi.nat44_interface_add_del_feature(
4462             sw_if_index=self.pg0.sw_if_index,
4463             flags=flags, is_add=1)
4464         self.vapi.nat44_interface_add_del_feature(
4465             sw_if_index=self.pg1.sw_if_index,
4466             is_add=1)
4467         self.frag_in_order(proto=IP_PROTOS.tcp, ignore_port=True)
4468         self.frag_in_order(proto=IP_PROTOS.udp, ignore_port=True)
4469         self.frag_in_order(proto=IP_PROTOS.icmp, ignore_port=True)
4470
4471     def test_frag_in_order_dont_translate(self):
4472         """ NAT44 don't translate fragments arriving in order """
4473         flags = self.config_flags.NAT_IS_INSIDE
4474         self.vapi.nat44_interface_add_del_feature(
4475             sw_if_index=self.pg0.sw_if_index,
4476             flags=flags, is_add=1)
4477         self.vapi.nat44_interface_add_del_feature(
4478             sw_if_index=self.pg1.sw_if_index,
4479             is_add=1)
4480         self.vapi.nat44_forwarding_enable_disable(enable=True)
4481         self.frag_in_order(proto=IP_PROTOS.tcp, dont_translate=True)
4482
4483     def test_frag_out_of_order(self):
4484         """ NAT44 translate fragments arriving out of order """
4485         self.nat44_add_address(self.nat_addr)
4486         flags = self.config_flags.NAT_IS_INSIDE
4487         self.vapi.nat44_interface_add_del_feature(
4488             sw_if_index=self.pg0.sw_if_index,
4489             flags=flags, is_add=1)
4490         self.vapi.nat44_interface_add_del_feature(
4491             sw_if_index=self.pg1.sw_if_index,
4492             is_add=1)
4493         self.frag_out_of_order(proto=IP_PROTOS.tcp, ignore_port=True)
4494         self.frag_out_of_order(proto=IP_PROTOS.udp, ignore_port=True)
4495         self.frag_out_of_order(proto=IP_PROTOS.icmp, ignore_port=True)
4496
4497     def test_frag_out_of_order_dont_translate(self):
4498         """ NAT44 don't translate fragments arriving out of 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             flags=flags, is_add=1)
4503         self.vapi.nat44_interface_add_del_feature(
4504             sw_if_index=self.pg1.sw_if_index,
4505             is_add=1)
4506         self.vapi.nat44_forwarding_enable_disable(enable=True)
4507         self.frag_out_of_order(proto=IP_PROTOS.tcp, dont_translate=True)
4508
4509     def test_frag_in_order_in_plus_out(self):
4510         """ in+out interface fragments in order """
4511         flags = self.config_flags.NAT_IS_INSIDE
4512         self.vapi.nat44_interface_add_del_feature(
4513             sw_if_index=self.pg0.sw_if_index,
4514             is_add=1)
4515         self.vapi.nat44_interface_add_del_feature(
4516             sw_if_index=self.pg0.sw_if_index,
4517             flags=flags, is_add=1)
4518         self.vapi.nat44_interface_add_del_feature(
4519             sw_if_index=self.pg1.sw_if_index,
4520             is_add=1)
4521         self.vapi.nat44_interface_add_del_feature(
4522             sw_if_index=self.pg1.sw_if_index,
4523             flags=flags, is_add=1)
4524
4525         self.server = self.pg1.remote_hosts[0]
4526
4527         self.server_in_addr = self.server.ip4
4528         self.server_out_addr = '11.11.11.11'
4529         self.server_in_port = random.randint(1025, 65535)
4530         self.server_out_port = random.randint(1025, 65535)
4531
4532         self.nat44_add_address(self.server_out_addr)
4533
4534         # add static mappings for server
4535         self.nat44_add_static_mapping(self.server_in_addr,
4536                                       self.server_out_addr,
4537                                       self.server_in_port,
4538                                       self.server_out_port,
4539                                       proto=IP_PROTOS.tcp)
4540         self.nat44_add_static_mapping(self.server_in_addr,
4541                                       self.server_out_addr,
4542                                       self.server_in_port,
4543                                       self.server_out_port,
4544                                       proto=IP_PROTOS.udp)
4545         self.nat44_add_static_mapping(self.server_in_addr,
4546                                       self.server_out_addr,
4547                                       proto=IP_PROTOS.icmp)
4548
4549         self.frag_in_order_in_plus_out(proto=IP_PROTOS.tcp)
4550         self.frag_in_order_in_plus_out(proto=IP_PROTOS.udp)
4551         self.frag_in_order_in_plus_out(proto=IP_PROTOS.icmp)
4552
4553     def test_frag_out_of_order_in_plus_out(self):
4554         """ in+out interface fragments out of order """
4555         flags = self.config_flags.NAT_IS_INSIDE
4556         self.vapi.nat44_interface_add_del_feature(
4557             sw_if_index=self.pg0.sw_if_index,
4558             is_add=1)
4559         self.vapi.nat44_interface_add_del_feature(
4560             sw_if_index=self.pg0.sw_if_index,
4561             flags=flags, is_add=1)
4562         self.vapi.nat44_interface_add_del_feature(
4563             sw_if_index=self.pg1.sw_if_index,
4564             is_add=1)
4565         self.vapi.nat44_interface_add_del_feature(
4566             sw_if_index=self.pg1.sw_if_index,
4567             flags=flags, is_add=1)
4568
4569         self.server = self.pg1.remote_hosts[0]
4570
4571         self.server_in_addr = self.server.ip4
4572         self.server_out_addr = '11.11.11.11'
4573         self.server_in_port = random.randint(1025, 65535)
4574         self.server_out_port = random.randint(1025, 65535)
4575
4576         self.nat44_add_address(self.server_out_addr)
4577
4578         # add static mappings for server
4579         self.nat44_add_static_mapping(self.server_in_addr,
4580                                       self.server_out_addr,
4581                                       self.server_in_port,
4582                                       self.server_out_port,
4583                                       proto=IP_PROTOS.tcp)
4584         self.nat44_add_static_mapping(self.server_in_addr,
4585                                       self.server_out_addr,
4586                                       self.server_in_port,
4587                                       self.server_out_port,
4588                                       proto=IP_PROTOS.udp)
4589         self.nat44_add_static_mapping(self.server_in_addr,
4590                                       self.server_out_addr,
4591                                       proto=IP_PROTOS.icmp)
4592
4593         self.frag_out_of_order_in_plus_out(proto=IP_PROTOS.tcp)
4594         self.frag_out_of_order_in_plus_out(proto=IP_PROTOS.udp)
4595         self.frag_out_of_order_in_plus_out(proto=IP_PROTOS.icmp)
4596
4597     def test_reass_hairpinning(self):
4598         """ NAT44 fragments hairpinning """
4599         self.server = self.pg0.remote_hosts[1]
4600         self.host_in_port = random.randint(1025, 65535)
4601         self.server_in_port = random.randint(1025, 65535)
4602         self.server_out_port = random.randint(1025, 65535)
4603
4604         self.nat44_add_address(self.nat_addr)
4605         flags = self.config_flags.NAT_IS_INSIDE
4606         self.vapi.nat44_interface_add_del_feature(
4607             sw_if_index=self.pg0.sw_if_index,
4608             flags=flags, is_add=1)
4609         self.vapi.nat44_interface_add_del_feature(
4610             sw_if_index=self.pg1.sw_if_index,
4611             is_add=1)
4612         # add static mapping for server
4613         self.nat44_add_static_mapping(self.server.ip4, self.nat_addr,
4614                                       self.server_in_port,
4615                                       self.server_out_port,
4616                                       proto=IP_PROTOS.tcp)
4617         self.nat44_add_static_mapping(self.server.ip4, self.nat_addr,
4618                                       self.server_in_port,
4619                                       self.server_out_port,
4620                                       proto=IP_PROTOS.udp)
4621         self.nat44_add_static_mapping(self.server.ip4, self.nat_addr)
4622
4623         self.reass_hairpinning(proto=IP_PROTOS.tcp, ignore_port=True)
4624         self.reass_hairpinning(proto=IP_PROTOS.udp, ignore_port=True)
4625         self.reass_hairpinning(proto=IP_PROTOS.icmp, ignore_port=True)
4626
4627     def test_clear_sessions(self):
4628         """ NAT44 ED session clearing test """
4629
4630         self.nat44_add_address(self.nat_addr)
4631         flags = self.config_flags.NAT_IS_INSIDE
4632         self.vapi.nat44_interface_add_del_feature(
4633             sw_if_index=self.pg0.sw_if_index,
4634             flags=flags, is_add=1)
4635         self.vapi.nat44_interface_add_del_feature(
4636             sw_if_index=self.pg1.sw_if_index,
4637             is_add=1)
4638
4639         nat_config = self.vapi.nat_show_config()
4640         self.assertEqual(1, nat_config.endpoint_dependent)
4641
4642         pkts = self.create_stream_in(self.pg0, self.pg1)
4643         self.pg0.add_stream(pkts)
4644         self.pg_enable_capture(self.pg_interfaces)
4645         self.pg_start()
4646         capture = self.pg1.get_capture(len(pkts))
4647         self.verify_capture_out(capture, ignore_port=True)
4648
4649         sessions = self.statistics.get_counter('/nat44/total-sessions')
4650         self.assertTrue(sessions[0][0] > 0)
4651         self.logger.info("sessions before clearing: %s" % sessions[0][0])
4652
4653         # just for testing purposes
4654         self.logger.info(self.vapi.cli("show nat44 summary"))
4655
4656         self.vapi.cli("clear nat44 sessions")
4657
4658         self.logger.info(self.vapi.cli("show nat44 summary"))
4659
4660         sessions = self.statistics.get_counter('/nat44/total-sessions')
4661         self.assertEqual(sessions[0][0], 0)
4662         self.logger.info("sessions after clearing: %s" % sessions[0][0])
4663
4664     def test_dynamic(self):
4665         """ NAT44 dynamic translation test """
4666
4667         self.nat44_add_address(self.nat_addr)
4668         flags = self.config_flags.NAT_IS_INSIDE
4669         self.vapi.nat44_interface_add_del_feature(
4670             sw_if_index=self.pg0.sw_if_index,
4671             flags=flags, is_add=1)
4672         self.vapi.nat44_interface_add_del_feature(
4673             sw_if_index=self.pg1.sw_if_index,
4674             is_add=1)
4675
4676         nat_config = self.vapi.nat_show_config()
4677         self.assertEqual(1, nat_config.endpoint_dependent)
4678
4679         # in2out
4680         tcpn = self.statistics.get_counter('/nat44/ed/in2out/slowpath/tcp')[0]
4681         udpn = self.statistics.get_counter('/nat44/ed/in2out/slowpath/udp')[0]
4682         icmpn = self.statistics.get_counter(
4683             '/nat44/ed/in2out/slowpath/icmp')[0]
4684         drops = self.statistics.get_counter(
4685             '/nat44/ed/in2out/slowpath/drops')[0]
4686
4687         pkts = self.create_stream_in(self.pg0, self.pg1)
4688         self.pg0.add_stream(pkts)
4689         self.pg_enable_capture(self.pg_interfaces)
4690         self.pg_start()
4691         capture = self.pg1.get_capture(len(pkts))
4692         self.verify_capture_out(capture, ignore_port=True)
4693
4694         if_idx = self.pg0.sw_if_index
4695         cnt = self.statistics.get_counter('/nat44/ed/in2out/slowpath/tcp')[0]
4696         self.assertEqual(cnt[if_idx] - tcpn[if_idx], 2)
4697         cnt = self.statistics.get_counter('/nat44/ed/in2out/slowpath/udp')[0]
4698         self.assertEqual(cnt[if_idx] - udpn[if_idx], 1)
4699         cnt = self.statistics.get_counter('/nat44/ed/in2out/slowpath/icmp')[0]
4700         self.assertEqual(cnt[if_idx] - icmpn[if_idx], 1)
4701         cnt = self.statistics.get_counter('/nat44/ed/in2out/slowpath/drops')[0]
4702         self.assertEqual(cnt[if_idx] - drops[if_idx], 0)
4703
4704         # out2in
4705         tcpn = self.statistics.get_counter('/nat44/ed/out2in/fastpath/tcp')[0]
4706         udpn = self.statistics.get_counter('/nat44/ed/out2in/fastpath/udp')[0]
4707         icmpn = self.statistics.get_counter(
4708             '/nat44/ed/out2in/slowpath/icmp')[0]
4709         drops = self.statistics.get_counter(
4710             '/nat44/ed/out2in/fastpath/drops')[0]
4711
4712         pkts = self.create_stream_out(self.pg1)
4713         self.pg1.add_stream(pkts)
4714         self.pg_enable_capture(self.pg_interfaces)
4715         self.pg_start()
4716         capture = self.pg0.get_capture(len(pkts))
4717         self.verify_capture_in(capture, self.pg0)
4718
4719         if_idx = self.pg1.sw_if_index
4720         cnt = self.statistics.get_counter('/nat44/ed/out2in/fastpath/tcp')[0]
4721         self.assertEqual(cnt[if_idx] - tcpn[if_idx], 2)
4722         cnt = self.statistics.get_counter('/nat44/ed/out2in/fastpath/udp')[0]
4723         self.assertEqual(cnt[if_idx] - udpn[if_idx], 1)
4724         cnt = self.statistics.get_counter('/nat44/ed/out2in/slowpath/icmp')[0]
4725         self.assertEqual(cnt[if_idx] - icmpn[if_idx], 1)
4726         cnt = self.statistics.get_counter('/nat44/ed/out2in/fastpath/drops')[0]
4727         self.assertEqual(cnt[if_idx] - drops[if_idx], 0)
4728
4729         sessions = self.statistics.get_counter('/nat44/total-sessions')
4730         self.assertEqual(sessions[0][0], 3)
4731
4732     def test_dynamic_out_of_ports(self):
4733         """ NAT44 dynamic translation test: out of ports """
4734
4735         flags = self.config_flags.NAT_IS_INSIDE
4736         self.vapi.nat44_interface_add_del_feature(
4737             sw_if_index=self.pg0.sw_if_index,
4738             flags=flags, is_add=1)
4739         self.vapi.nat44_interface_add_del_feature(
4740             sw_if_index=self.pg1.sw_if_index,
4741             is_add=1)
4742
4743         nat_config = self.vapi.nat_show_config()
4744         self.assertEqual(1, nat_config.endpoint_dependent)
4745
4746         # in2out and no NAT addresses added
4747         err_old = self.statistics.get_err_counter(
4748             '/err/nat44-ed-in2out-slowpath/out of ports')
4749
4750         pkts = self.create_stream_in(self.pg0, self.pg1)
4751         self.pg0.add_stream(pkts)
4752         self.pg_enable_capture(self.pg_interfaces)
4753         self.pg_start()
4754         self.pg1.get_capture(0, timeout=1)
4755
4756         err_new = self.statistics.get_err_counter(
4757             '/err/nat44-ed-in2out-slowpath/out of ports')
4758
4759         self.assertEqual(err_new - err_old, len(pkts))
4760
4761         # in2out after NAT addresses added
4762         self.nat44_add_address(self.nat_addr)
4763
4764         err_old = self.statistics.get_err_counter(
4765             '/err/nat44-ed-in2out-slowpath/out of ports')
4766
4767         pkts = self.create_stream_in(self.pg0, self.pg1)
4768         self.pg0.add_stream(pkts)
4769         self.pg_enable_capture(self.pg_interfaces)
4770         self.pg_start()
4771         capture = self.pg1.get_capture(len(pkts))
4772         self.verify_capture_out(capture, ignore_port=True)
4773
4774         err_new = self.statistics.get_err_counter(
4775             '/err/nat44-ed-in2out-slowpath/out of ports')
4776
4777         self.assertEqual(err_new, err_old)
4778
4779     def test_dynamic_output_feature_vrf(self):
4780         """ NAT44 dynamic translation test: output-feature, VRF"""
4781
4782         # other then default (0)
4783         new_vrf_id = 22
4784
4785         self.nat44_add_address(self.nat_addr)
4786         flags = self.config_flags.NAT_IS_INSIDE
4787         self.vapi.nat44_interface_add_del_output_feature(
4788             sw_if_index=self.pg7.sw_if_index,
4789             flags=flags, is_add=1)
4790         self.vapi.nat44_interface_add_del_output_feature(
4791             sw_if_index=self.pg8.sw_if_index,
4792             is_add=1)
4793
4794         try:
4795             self.vapi.ip_table_add_del(is_add=1,
4796                                        table={'table_id': new_vrf_id})
4797
4798             self.pg7.unconfig_ip4()
4799             self.pg7.set_table_ip4(new_vrf_id)
4800             self.pg7.config_ip4()
4801             self.pg7.resolve_arp()
4802
4803             self.pg8.unconfig_ip4()
4804             self.pg8.set_table_ip4(new_vrf_id)
4805             self.pg8.config_ip4()
4806             self.pg8.resolve_arp()
4807
4808             nat_config = self.vapi.nat_show_config()
4809             self.assertEqual(1, nat_config.endpoint_dependent)
4810
4811             # in2out
4812             tcpn = self.statistics.get_counter(
4813                 '/nat44/ed/in2out/slowpath/tcp')[0]
4814             udpn = self.statistics.get_counter(
4815                 '/nat44/ed/in2out/slowpath/udp')[0]
4816             icmpn = self.statistics.get_counter(
4817                 '/nat44/ed/in2out/slowpath/icmp')[0]
4818             drops = self.statistics.get_counter(
4819                 '/nat44/ed/in2out/slowpath/drops')[0]
4820
4821             pkts = self.create_stream_in(self.pg7, self.pg8)
4822             self.pg7.add_stream(pkts)
4823             self.pg_enable_capture(self.pg_interfaces)
4824             self.pg_start()
4825             capture = self.pg8.get_capture(len(pkts))
4826             self.verify_capture_out(capture, ignore_port=True)
4827
4828             if_idx = self.pg7.sw_if_index
4829             cnt = self.statistics.get_counter(
4830                 '/nat44/ed/in2out/slowpath/tcp')[0]
4831             self.assertEqual(cnt[if_idx] - tcpn[if_idx], 2)
4832             cnt = self.statistics.get_counter(
4833                 '/nat44/ed/in2out/slowpath/udp')[0]
4834             self.assertEqual(cnt[if_idx] - udpn[if_idx], 1)
4835             cnt = self.statistics.get_counter(
4836                 '/nat44/ed/in2out/slowpath/icmp')[0]
4837             self.assertEqual(cnt[if_idx] - icmpn[if_idx], 1)
4838             cnt = self.statistics.get_counter(
4839                 '/nat44/ed/in2out/slowpath/drops')[0]
4840             self.assertEqual(cnt[if_idx] - drops[if_idx], 0)
4841
4842             # out2in
4843             tcpn = self.statistics.get_counter(
4844                 '/nat44/ed/out2in/fastpath/tcp')[0]
4845             udpn = self.statistics.get_counter(
4846                 '/nat44/ed/out2in/fastpath/udp')[0]
4847             icmpn = self.statistics.get_counter(
4848                 '/nat44/ed/out2in/slowpath/icmp')[0]
4849             drops = self.statistics.get_counter(
4850                 '/nat44/ed/out2in/fastpath/drops')[0]
4851
4852             pkts = self.create_stream_out(self.pg8)
4853             self.pg8.add_stream(pkts)
4854             self.pg_enable_capture(self.pg_interfaces)
4855             self.pg_start()
4856             capture = self.pg7.get_capture(len(pkts))
4857             self.verify_capture_in(capture, self.pg7)
4858
4859             if_idx = self.pg8.sw_if_index
4860             cnt = self.statistics.get_counter(
4861                 '/nat44/ed/out2in/fastpath/tcp')[0]
4862             self.assertEqual(cnt[if_idx] - tcpn[if_idx], 2)
4863             cnt = self.statistics.get_counter(
4864                 '/nat44/ed/out2in/fastpath/udp')[0]
4865             self.assertEqual(cnt[if_idx] - udpn[if_idx], 1)
4866             cnt = self.statistics.get_counter(
4867                 '/nat44/ed/out2in/slowpath/icmp')[0]
4868             self.assertEqual(cnt[if_idx] - icmpn[if_idx], 1)
4869             cnt = self.statistics.get_counter(
4870                 '/nat44/ed/out2in/fastpath/drops')[0]
4871             self.assertEqual(cnt[if_idx] - drops[if_idx], 0)
4872
4873             sessions = self.statistics.get_counter('/nat44/total-sessions')
4874             self.assertEqual(sessions[0][0], 3)
4875
4876         finally:
4877             self.pg7.unconfig_ip4()
4878             self.pg7.set_table_ip4(1)
4879             self.pg7.config_ip4()
4880             self.pg7.resolve_arp()
4881
4882             self.pg8.unconfig_ip4()
4883             self.pg8.set_table_ip4(1)
4884             self.pg8.config_ip4()
4885             self.pg8.resolve_arp()
4886
4887             self.vapi.ip_table_add_del(is_add=0,
4888                                        table={'table_id': new_vrf_id})
4889
4890     def test_forwarding(self):
4891         """ NAT44 forwarding test """
4892
4893         flags = self.config_flags.NAT_IS_INSIDE
4894         self.vapi.nat44_interface_add_del_feature(
4895             sw_if_index=self.pg0.sw_if_index,
4896             flags=flags, is_add=1)
4897         self.vapi.nat44_interface_add_del_feature(
4898             sw_if_index=self.pg1.sw_if_index,
4899             is_add=1)
4900         self.vapi.nat44_forwarding_enable_disable(enable=1)
4901
4902         real_ip = self.pg0.remote_ip4
4903         alias_ip = self.nat_addr
4904         flags = self.config_flags.NAT_IS_ADDR_ONLY
4905         self.vapi.nat44_add_del_static_mapping(is_add=1,
4906                                                local_ip_address=real_ip,
4907                                                external_ip_address=alias_ip,
4908                                                external_sw_if_index=0xFFFFFFFF,
4909                                                flags=flags)
4910
4911         try:
4912             # in2out - static mapping match
4913
4914             pkts = self.create_stream_out(self.pg1)
4915             self.pg1.add_stream(pkts)
4916             self.pg_enable_capture(self.pg_interfaces)
4917             self.pg_start()
4918             capture = self.pg0.get_capture(len(pkts))
4919             self.verify_capture_in(capture, self.pg0)
4920
4921             pkts = self.create_stream_in(self.pg0, self.pg1)
4922             self.pg0.add_stream(pkts)
4923             self.pg_enable_capture(self.pg_interfaces)
4924             self.pg_start()
4925             capture = self.pg1.get_capture(len(pkts))
4926             self.verify_capture_out(capture, same_port=True)
4927
4928             # in2out - no static mapping match
4929
4930             host0 = self.pg0.remote_hosts[0]
4931             self.pg0.remote_hosts[0] = self.pg0.remote_hosts[1]
4932             try:
4933                 pkts = self.create_stream_out(self.pg1,
4934                                               dst_ip=self.pg0.remote_ip4,
4935                                               use_inside_ports=True)
4936                 self.pg1.add_stream(pkts)
4937                 self.pg_enable_capture(self.pg_interfaces)
4938                 self.pg_start()
4939                 capture = self.pg0.get_capture(len(pkts))
4940                 self.verify_capture_in(capture, self.pg0)
4941
4942                 pkts = self.create_stream_in(self.pg0, self.pg1)
4943                 self.pg0.add_stream(pkts)
4944                 self.pg_enable_capture(self.pg_interfaces)
4945                 self.pg_start()
4946                 capture = self.pg1.get_capture(len(pkts))
4947                 self.verify_capture_out(capture, nat_ip=self.pg0.remote_ip4,
4948                                         same_port=True)
4949             finally:
4950                 self.pg0.remote_hosts[0] = host0
4951
4952             user = self.pg0.remote_hosts[1]
4953             sessions = self.vapi.nat44_user_session_dump(user.ip4, 0)
4954             self.assertEqual(len(sessions), 3)
4955             self.assertTrue(sessions[0].flags &
4956                             self.config_flags.NAT_IS_EXT_HOST_VALID)
4957             self.vapi.nat44_del_session(
4958                 address=sessions[0].inside_ip_address,
4959                 port=sessions[0].inside_port,
4960                 protocol=sessions[0].protocol,
4961                 flags=(self.config_flags.NAT_IS_INSIDE |
4962                        self.config_flags.NAT_IS_EXT_HOST_VALID),
4963                 ext_host_address=sessions[0].ext_host_address,
4964                 ext_host_port=sessions[0].ext_host_port)
4965             sessions = self.vapi.nat44_user_session_dump(user.ip4, 0)
4966             self.assertEqual(len(sessions), 2)
4967
4968         finally:
4969             self.vapi.nat44_forwarding_enable_disable(enable=0)
4970             flags = self.config_flags.NAT_IS_ADDR_ONLY
4971             self.vapi.nat44_add_del_static_mapping(
4972                 is_add=0,
4973                 local_ip_address=real_ip,
4974                 external_ip_address=alias_ip,
4975                 external_sw_if_index=0xFFFFFFFF,
4976                 flags=flags)
4977
4978     def test_static_lb(self):
4979         """ NAT44 local service load balancing """
4980         external_addr_n = self.nat_addr
4981         external_port = 80
4982         local_port = 8080
4983         server1 = self.pg0.remote_hosts[0]
4984         server2 = self.pg0.remote_hosts[1]
4985
4986         locals = [{'addr': server1.ip4,
4987                    'port': local_port,
4988                    'probability': 70,
4989                    'vrf_id': 0},
4990                   {'addr': server2.ip4,
4991                    'port': local_port,
4992                    'probability': 30,
4993                    'vrf_id': 0}]
4994
4995         self.nat44_add_address(self.nat_addr)
4996         self.vapi.nat44_add_del_lb_static_mapping(
4997             is_add=1,
4998             external_addr=external_addr_n,
4999             external_port=external_port,
5000             protocol=IP_PROTOS.tcp,
5001             local_num=len(locals),
5002             locals=locals)
5003         flags = self.config_flags.NAT_IS_INSIDE
5004         self.vapi.nat44_interface_add_del_feature(
5005             sw_if_index=self.pg0.sw_if_index,
5006             flags=flags, is_add=1)
5007         self.vapi.nat44_interface_add_del_feature(
5008             sw_if_index=self.pg1.sw_if_index,
5009             is_add=1)
5010
5011         # from client to service
5012         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
5013              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
5014              TCP(sport=12345, dport=external_port))
5015         self.pg1.add_stream(p)
5016         self.pg_enable_capture(self.pg_interfaces)
5017         self.pg_start()
5018         capture = self.pg0.get_capture(1)
5019         p = capture[0]
5020         server = None
5021         try:
5022             ip = p[IP]
5023             tcp = p[TCP]
5024             self.assertIn(ip.dst, [server1.ip4, server2.ip4])
5025             if ip.dst == server1.ip4:
5026                 server = server1
5027             else:
5028                 server = server2
5029             self.assertEqual(tcp.dport, local_port)
5030             self.assert_packet_checksums_valid(p)
5031         except:
5032             self.logger.error(ppp("Unexpected or invalid packet:", p))
5033             raise
5034
5035         # from service back to client
5036         p = (Ether(src=server.mac, dst=self.pg0.local_mac) /
5037              IP(src=server.ip4, dst=self.pg1.remote_ip4) /
5038              TCP(sport=local_port, dport=12345))
5039         self.pg0.add_stream(p)
5040         self.pg_enable_capture(self.pg_interfaces)
5041         self.pg_start()
5042         capture = self.pg1.get_capture(1)
5043         p = capture[0]
5044         try:
5045             ip = p[IP]
5046             tcp = p[TCP]
5047             self.assertEqual(ip.src, self.nat_addr)
5048             self.assertEqual(tcp.sport, external_port)
5049             self.assert_packet_checksums_valid(p)
5050         except:
5051             self.logger.error(ppp("Unexpected or invalid packet:", p))
5052             raise
5053
5054         sessions = self.vapi.nat44_user_session_dump(server.ip4, 0)
5055         self.assertEqual(len(sessions), 1)
5056         self.assertTrue(sessions[0].flags &
5057                         self.config_flags.NAT_IS_EXT_HOST_VALID)
5058         self.vapi.nat44_del_session(
5059             address=sessions[0].inside_ip_address,
5060             port=sessions[0].inside_port,
5061             protocol=sessions[0].protocol,
5062             flags=(self.config_flags.NAT_IS_INSIDE |
5063                    self.config_flags.NAT_IS_EXT_HOST_VALID),
5064             ext_host_address=sessions[0].ext_host_address,
5065             ext_host_port=sessions[0].ext_host_port)
5066         sessions = self.vapi.nat44_user_session_dump(server.ip4, 0)
5067         self.assertEqual(len(sessions), 0)
5068
5069     @unittest.skipUnless(running_extended_tests, "part of extended tests")
5070     def test_static_lb_multi_clients(self):
5071         """ NAT44 local service load balancing - multiple clients"""
5072
5073         external_addr = self.nat_addr
5074         external_port = 80
5075         local_port = 8080
5076         server1 = self.pg0.remote_hosts[0]
5077         server2 = self.pg0.remote_hosts[1]
5078         server3 = self.pg0.remote_hosts[2]
5079
5080         locals = [{'addr': server1.ip4,
5081                    'port': local_port,
5082                    'probability': 90,
5083                    'vrf_id': 0},
5084                   {'addr': server2.ip4,
5085                    'port': local_port,
5086                    'probability': 10,
5087                    'vrf_id': 0}]
5088
5089         self.nat44_add_address(self.nat_addr)
5090         self.vapi.nat44_add_del_lb_static_mapping(is_add=1,
5091                                                   external_addr=external_addr,
5092                                                   external_port=external_port,
5093                                                   protocol=IP_PROTOS.tcp,
5094                                                   local_num=len(locals),
5095                                                   locals=locals)
5096         flags = self.config_flags.NAT_IS_INSIDE
5097         self.vapi.nat44_interface_add_del_feature(
5098             sw_if_index=self.pg0.sw_if_index,
5099             flags=flags, is_add=1)
5100         self.vapi.nat44_interface_add_del_feature(
5101             sw_if_index=self.pg1.sw_if_index,
5102             is_add=1)
5103
5104         server1_n = 0
5105         server2_n = 0
5106         clients = ip4_range(self.pg1.remote_ip4, 10, 50)
5107         pkts = []
5108         for client in clients:
5109             p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
5110                  IP(src=client, dst=self.nat_addr) /
5111                  TCP(sport=12345, dport=external_port))
5112             pkts.append(p)
5113         self.pg1.add_stream(pkts)
5114         self.pg_enable_capture(self.pg_interfaces)
5115         self.pg_start()
5116         capture = self.pg0.get_capture(len(pkts))
5117         for p in capture:
5118             if p[IP].dst == server1.ip4:
5119                 server1_n += 1
5120             else:
5121                 server2_n += 1
5122         self.assertGreater(server1_n, server2_n)
5123
5124         local = {
5125             'addr': server3.ip4,
5126             'port': local_port,
5127             'probability': 20,
5128             'vrf_id': 0
5129         }
5130
5131         # add new back-end
5132         self.vapi.nat44_lb_static_mapping_add_del_local(
5133             is_add=1,
5134             external_addr=external_addr,
5135             external_port=external_port,
5136             local=local,
5137             protocol=IP_PROTOS.tcp)
5138         server1_n = 0
5139         server2_n = 0
5140         server3_n = 0
5141         clients = ip4_range(self.pg1.remote_ip4, 60, 110)
5142         pkts = []
5143         for client in clients:
5144             p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
5145                  IP(src=client, dst=self.nat_addr) /
5146                  TCP(sport=12346, dport=external_port))
5147             pkts.append(p)
5148         self.assertGreater(len(pkts), 0)
5149         self.pg1.add_stream(pkts)
5150         self.pg_enable_capture(self.pg_interfaces)
5151         self.pg_start()
5152         capture = self.pg0.get_capture(len(pkts))
5153         for p in capture:
5154             if p[IP].dst == server1.ip4:
5155                 server1_n += 1
5156             elif p[IP].dst == server2.ip4:
5157                 server2_n += 1
5158             else:
5159                 server3_n += 1
5160         self.assertGreater(server1_n, 0)
5161         self.assertGreater(server2_n, 0)
5162         self.assertGreater(server3_n, 0)
5163
5164         local = {
5165             'addr': server2.ip4,
5166             'port': local_port,
5167             'probability': 10,
5168             'vrf_id': 0
5169         }
5170
5171         # remove one back-end
5172         self.vapi.nat44_lb_static_mapping_add_del_local(
5173             is_add=0,
5174             external_addr=external_addr,
5175             external_port=external_port,
5176             local=local,
5177             protocol=IP_PROTOS.tcp)
5178         server1_n = 0
5179         server2_n = 0
5180         server3_n = 0
5181         self.pg1.add_stream(pkts)
5182         self.pg_enable_capture(self.pg_interfaces)
5183         self.pg_start()
5184         capture = self.pg0.get_capture(len(pkts))
5185         for p in capture:
5186             if p[IP].dst == server1.ip4:
5187                 server1_n += 1
5188             elif p[IP].dst == server2.ip4:
5189                 server2_n += 1
5190             else:
5191                 server3_n += 1
5192         self.assertGreater(server1_n, 0)
5193         self.assertEqual(server2_n, 0)
5194         self.assertGreater(server3_n, 0)
5195
5196     def test_static_lb_2(self):
5197         """ NAT44 local service load balancing (asymmetrical rule) """
5198         external_addr = self.nat_addr
5199         external_port = 80
5200         local_port = 8080
5201         server1 = self.pg0.remote_hosts[0]
5202         server2 = self.pg0.remote_hosts[1]
5203
5204         locals = [{'addr': server1.ip4,
5205                    'port': local_port,
5206                    'probability': 70,
5207                    'vrf_id': 0},
5208                   {'addr': server2.ip4,
5209                    'port': local_port,
5210                    'probability': 30,
5211                    'vrf_id': 0}]
5212
5213         self.vapi.nat44_forwarding_enable_disable(enable=1)
5214         flags = self.config_flags.NAT_IS_OUT2IN_ONLY
5215         self.vapi.nat44_add_del_lb_static_mapping(is_add=1, flags=flags,
5216                                                   external_addr=external_addr,
5217                                                   external_port=external_port,
5218                                                   protocol=IP_PROTOS.tcp,
5219                                                   local_num=len(locals),
5220                                                   locals=locals)
5221         flags = self.config_flags.NAT_IS_INSIDE
5222         self.vapi.nat44_interface_add_del_feature(
5223             sw_if_index=self.pg0.sw_if_index,
5224             flags=flags, is_add=1)
5225         self.vapi.nat44_interface_add_del_feature(
5226             sw_if_index=self.pg1.sw_if_index,
5227             is_add=1)
5228
5229         # from client to service
5230         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
5231              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
5232              TCP(sport=12345, dport=external_port))
5233         self.pg1.add_stream(p)
5234         self.pg_enable_capture(self.pg_interfaces)
5235         self.pg_start()
5236         capture = self.pg0.get_capture(1)
5237         p = capture[0]
5238         server = None
5239         try:
5240             ip = p[IP]
5241             tcp = p[TCP]
5242             self.assertIn(ip.dst, [server1.ip4, server2.ip4])
5243             if ip.dst == server1.ip4:
5244                 server = server1
5245             else:
5246                 server = server2
5247             self.assertEqual(tcp.dport, local_port)
5248             self.assert_packet_checksums_valid(p)
5249         except:
5250             self.logger.error(ppp("Unexpected or invalid packet:", p))
5251             raise
5252
5253         # from service back to client
5254         p = (Ether(src=server.mac, dst=self.pg0.local_mac) /
5255              IP(src=server.ip4, dst=self.pg1.remote_ip4) /
5256              TCP(sport=local_port, dport=12345))
5257         self.pg0.add_stream(p)
5258         self.pg_enable_capture(self.pg_interfaces)
5259         self.pg_start()
5260         capture = self.pg1.get_capture(1)
5261         p = capture[0]
5262         try:
5263             ip = p[IP]
5264             tcp = p[TCP]
5265             self.assertEqual(ip.src, self.nat_addr)
5266             self.assertEqual(tcp.sport, external_port)
5267             self.assert_packet_checksums_valid(p)
5268         except:
5269             self.logger.error(ppp("Unexpected or invalid packet:", p))
5270             raise
5271
5272         # from client to server (no translation)
5273         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
5274              IP(src=self.pg1.remote_ip4, dst=server1.ip4) /
5275              TCP(sport=12346, dport=local_port))
5276         self.pg1.add_stream(p)
5277         self.pg_enable_capture(self.pg_interfaces)
5278         self.pg_start()
5279         capture = self.pg0.get_capture(1)
5280         p = capture[0]
5281         server = None
5282         try:
5283             ip = p[IP]
5284             tcp = p[TCP]
5285             self.assertEqual(ip.dst, server1.ip4)
5286             self.assertEqual(tcp.dport, local_port)
5287             self.assert_packet_checksums_valid(p)
5288         except:
5289             self.logger.error(ppp("Unexpected or invalid packet:", p))
5290             raise
5291
5292         # from service back to client (no translation)
5293         p = (Ether(src=server1.mac, dst=self.pg0.local_mac) /
5294              IP(src=server1.ip4, dst=self.pg1.remote_ip4) /
5295              TCP(sport=local_port, dport=12346))
5296         self.pg0.add_stream(p)
5297         self.pg_enable_capture(self.pg_interfaces)
5298         self.pg_start()
5299         capture = self.pg1.get_capture(1)
5300         p = capture[0]
5301         try:
5302             ip = p[IP]
5303             tcp = p[TCP]
5304             self.assertEqual(ip.src, server1.ip4)
5305             self.assertEqual(tcp.sport, local_port)
5306             self.assert_packet_checksums_valid(p)
5307         except:
5308             self.logger.error(ppp("Unexpected or invalid packet:", p))
5309             raise
5310
5311     def test_lb_affinity(self):
5312         """ NAT44 local service load balancing affinity """
5313         external_addr = self.nat_addr
5314         external_port = 80
5315         local_port = 8080
5316         server1 = self.pg0.remote_hosts[0]
5317         server2 = self.pg0.remote_hosts[1]
5318
5319         locals = [{'addr': server1.ip4,
5320                    'port': local_port,
5321                    'probability': 50,
5322                    'vrf_id': 0},
5323                   {'addr': server2.ip4,
5324                    'port': local_port,
5325                    'probability': 50,
5326                    'vrf_id': 0}]
5327
5328         self.nat44_add_address(self.nat_addr)
5329         self.vapi.nat44_add_del_lb_static_mapping(is_add=1,
5330                                                   external_addr=external_addr,
5331                                                   external_port=external_port,
5332                                                   protocol=IP_PROTOS.tcp,
5333                                                   affinity=10800,
5334                                                   local_num=len(locals),
5335                                                   locals=locals)
5336         flags = self.config_flags.NAT_IS_INSIDE
5337         self.vapi.nat44_interface_add_del_feature(
5338             sw_if_index=self.pg0.sw_if_index,
5339             flags=flags, is_add=1)
5340         self.vapi.nat44_interface_add_del_feature(
5341             sw_if_index=self.pg1.sw_if_index,
5342             is_add=1)
5343
5344         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
5345              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
5346              TCP(sport=1025, dport=external_port))
5347         self.pg1.add_stream(p)
5348         self.pg_enable_capture(self.pg_interfaces)
5349         self.pg_start()
5350         capture = self.pg0.get_capture(1)
5351         backend = capture[0][IP].dst
5352
5353         sessions = self.vapi.nat44_user_session_dump(backend, 0)
5354         self.assertEqual(len(sessions), 1)
5355         self.assertTrue(sessions[0].flags &
5356                         self.config_flags.NAT_IS_EXT_HOST_VALID)
5357         self.vapi.nat44_del_session(
5358             address=sessions[0].inside_ip_address,
5359             port=sessions[0].inside_port,
5360             protocol=sessions[0].protocol,
5361             flags=(self.config_flags.NAT_IS_INSIDE |
5362                    self.config_flags.NAT_IS_EXT_HOST_VALID),
5363             ext_host_address=sessions[0].ext_host_address,
5364             ext_host_port=sessions[0].ext_host_port)
5365
5366         pkts = []
5367         for port in range(1030, 1100):
5368             p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
5369                  IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
5370                  TCP(sport=port, dport=external_port))
5371             pkts.append(p)
5372         self.pg1.add_stream(pkts)
5373         self.pg_enable_capture(self.pg_interfaces)
5374         self.pg_start()
5375         capture = self.pg0.get_capture(len(pkts))
5376         for p in capture:
5377             self.assertEqual(p[IP].dst, backend)
5378
5379     def test_unknown_proto(self):
5380         """ NAT44 translate packet with unknown protocol """
5381         self.nat44_add_address(self.nat_addr)
5382         flags = self.config_flags.NAT_IS_INSIDE
5383         self.vapi.nat44_interface_add_del_feature(
5384             sw_if_index=self.pg0.sw_if_index,
5385             flags=flags, is_add=1)
5386         self.vapi.nat44_interface_add_del_feature(
5387             sw_if_index=self.pg1.sw_if_index,
5388             is_add=1)
5389
5390         # in2out
5391         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
5392              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
5393              TCP(sport=self.tcp_port_in, dport=20))
5394         self.pg0.add_stream(p)
5395         self.pg_enable_capture(self.pg_interfaces)
5396         self.pg_start()
5397         p = self.pg1.get_capture(1)
5398
5399         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
5400              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
5401              GRE() /
5402              IP(src=self.pg2.remote_ip4, dst=self.pg2.remote_ip4) /
5403              TCP(sport=1234, dport=1234))
5404         self.pg0.add_stream(p)
5405         self.pg_enable_capture(self.pg_interfaces)
5406         self.pg_start()
5407         p = self.pg1.get_capture(1)
5408         packet = p[0]
5409         try:
5410             self.assertEqual(packet[IP].src, self.nat_addr)
5411             self.assertEqual(packet[IP].dst, self.pg1.remote_ip4)
5412             self.assertEqual(packet.haslayer(GRE), 1)
5413             self.assert_packet_checksums_valid(packet)
5414         except:
5415             self.logger.error(ppp("Unexpected or invalid packet:", packet))
5416             raise
5417
5418         # out2in
5419         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
5420              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
5421              GRE() /
5422              IP(src=self.pg2.remote_ip4, dst=self.pg2.remote_ip4) /
5423              TCP(sport=1234, dport=1234))
5424         self.pg1.add_stream(p)
5425         self.pg_enable_capture(self.pg_interfaces)
5426         self.pg_start()
5427         p = self.pg0.get_capture(1)
5428         packet = p[0]
5429         try:
5430             self.assertEqual(packet[IP].src, self.pg1.remote_ip4)
5431             self.assertEqual(packet[IP].dst, self.pg0.remote_ip4)
5432             self.assertEqual(packet.haslayer(GRE), 1)
5433             self.assert_packet_checksums_valid(packet)
5434         except:
5435             self.logger.error(ppp("Unexpected or invalid packet:", packet))
5436             raise
5437
5438     def test_hairpinning_unknown_proto(self):
5439         """ NAT44 translate packet with unknown protocol - hairpinning """
5440         host = self.pg0.remote_hosts[0]
5441         server = self.pg0.remote_hosts[1]
5442         host_in_port = 1234
5443         server_out_port = 8765
5444         server_nat_ip = "10.0.0.11"
5445
5446         self.nat44_add_address(self.nat_addr)
5447         flags = self.config_flags.NAT_IS_INSIDE
5448         self.vapi.nat44_interface_add_del_feature(
5449             sw_if_index=self.pg0.sw_if_index,
5450             flags=flags, is_add=1)
5451         self.vapi.nat44_interface_add_del_feature(
5452             sw_if_index=self.pg1.sw_if_index,
5453             is_add=1)
5454
5455         # add static mapping for server
5456         self.nat44_add_static_mapping(server.ip4, server_nat_ip)
5457
5458         # host to server
5459         p = (Ether(src=host.mac, dst=self.pg0.local_mac) /
5460              IP(src=host.ip4, dst=server_nat_ip) /
5461              TCP(sport=host_in_port, dport=server_out_port))
5462         self.pg0.add_stream(p)
5463         self.pg_enable_capture(self.pg_interfaces)
5464         self.pg_start()
5465         self.pg0.get_capture(1)
5466
5467         p = (Ether(dst=self.pg0.local_mac, src=host.mac) /
5468              IP(src=host.ip4, dst=server_nat_ip) /
5469              GRE() /
5470              IP(src=self.pg2.remote_ip4, dst=self.pg2.remote_ip4) /
5471              TCP(sport=1234, dport=1234))
5472         self.pg0.add_stream(p)
5473         self.pg_enable_capture(self.pg_interfaces)
5474         self.pg_start()
5475         p = self.pg0.get_capture(1)
5476         packet = p[0]
5477         try:
5478             self.assertEqual(packet[IP].src, self.nat_addr)
5479             self.assertEqual(packet[IP].dst, server.ip4)
5480             self.assertEqual(packet.haslayer(GRE), 1)
5481             self.assert_packet_checksums_valid(packet)
5482         except:
5483             self.logger.error(ppp("Unexpected or invalid packet:", packet))
5484             raise
5485
5486         # server to host
5487         p = (Ether(dst=self.pg0.local_mac, src=server.mac) /
5488              IP(src=server.ip4, dst=self.nat_addr) /
5489              GRE() /
5490              IP(src=self.pg2.remote_ip4, dst=self.pg2.remote_ip4) /
5491              TCP(sport=1234, dport=1234))
5492         self.pg0.add_stream(p)
5493         self.pg_enable_capture(self.pg_interfaces)
5494         self.pg_start()
5495         p = self.pg0.get_capture(1)
5496         packet = p[0]
5497         try:
5498             self.assertEqual(packet[IP].src, server_nat_ip)
5499             self.assertEqual(packet[IP].dst, host.ip4)
5500             self.assertEqual(packet.haslayer(GRE), 1)
5501             self.assert_packet_checksums_valid(packet)
5502         except:
5503             self.logger.error(ppp("Unexpected or invalid packet:", packet))
5504             raise
5505
5506     def test_output_feature_and_service(self):
5507         """ NAT44 interface output feature and services """
5508         external_addr = '1.2.3.4'
5509         external_port = 80
5510         local_port = 8080
5511
5512         self.vapi.nat44_forwarding_enable_disable(enable=1)
5513         self.nat44_add_address(self.nat_addr)
5514         flags = self.config_flags.NAT_IS_ADDR_ONLY
5515         self.vapi.nat44_add_del_identity_mapping(
5516             ip_address=self.pg1.remote_ip4, sw_if_index=0xFFFFFFFF,
5517             flags=flags, is_add=1)
5518         flags = self.config_flags.NAT_IS_OUT2IN_ONLY
5519         self.nat44_add_static_mapping(self.pg0.remote_ip4, external_addr,
5520                                       local_port, external_port,
5521                                       proto=IP_PROTOS.tcp, flags=flags)
5522         flags = self.config_flags.NAT_IS_INSIDE
5523         self.vapi.nat44_interface_add_del_feature(
5524             sw_if_index=self.pg0.sw_if_index,
5525             is_add=1)
5526         self.vapi.nat44_interface_add_del_feature(
5527             sw_if_index=self.pg0.sw_if_index,
5528             flags=flags, is_add=1)
5529         self.vapi.nat44_interface_add_del_output_feature(
5530             is_add=1,
5531             sw_if_index=self.pg1.sw_if_index)
5532
5533         # from client to service
5534         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
5535              IP(src=self.pg1.remote_ip4, dst=external_addr) /
5536              TCP(sport=12345, dport=external_port))
5537         self.pg1.add_stream(p)
5538         self.pg_enable_capture(self.pg_interfaces)
5539         self.pg_start()
5540         capture = self.pg0.get_capture(1)
5541         p = capture[0]
5542         try:
5543             ip = p[IP]
5544             tcp = p[TCP]
5545             self.assertEqual(ip.dst, self.pg0.remote_ip4)
5546             self.assertEqual(tcp.dport, local_port)
5547             self.assert_packet_checksums_valid(p)
5548         except:
5549             self.logger.error(ppp("Unexpected or invalid packet:", p))
5550             raise
5551
5552         # from service back to client
5553         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
5554              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
5555              TCP(sport=local_port, dport=12345))
5556         self.pg0.add_stream(p)
5557         self.pg_enable_capture(self.pg_interfaces)
5558         self.pg_start()
5559         capture = self.pg1.get_capture(1)
5560         p = capture[0]
5561         try:
5562             ip = p[IP]
5563             tcp = p[TCP]
5564             self.assertEqual(ip.src, external_addr)
5565             self.assertEqual(tcp.sport, external_port)
5566             self.assert_packet_checksums_valid(p)
5567         except:
5568             self.logger.error(ppp("Unexpected or invalid packet:", p))
5569             raise
5570
5571         # from local network host to external network
5572         pkts = self.create_stream_in(self.pg0, self.pg1)
5573         self.pg0.add_stream(pkts)
5574         self.pg_enable_capture(self.pg_interfaces)
5575         self.pg_start()
5576         capture = self.pg1.get_capture(len(pkts))
5577         self.verify_capture_out(capture, ignore_port=True)
5578         pkts = self.create_stream_in(self.pg0, self.pg1)
5579         self.pg0.add_stream(pkts)
5580         self.pg_enable_capture(self.pg_interfaces)
5581         self.pg_start()
5582         capture = self.pg1.get_capture(len(pkts))
5583         self.verify_capture_out(capture, ignore_port=True)
5584
5585         # from external network back to local network host
5586         pkts = self.create_stream_out(self.pg1)
5587         self.pg1.add_stream(pkts)
5588         self.pg_enable_capture(self.pg_interfaces)
5589         self.pg_start()
5590         capture = self.pg0.get_capture(len(pkts))
5591         self.verify_capture_in(capture, self.pg0)
5592
5593     def test_output_feature_and_service2(self):
5594         """ NAT44 interface output feature and service host direct access """
5595         self.vapi.nat44_forwarding_enable_disable(enable=1)
5596         self.nat44_add_address(self.nat_addr)
5597         self.vapi.nat44_interface_add_del_output_feature(
5598             is_add=1,
5599             sw_if_index=self.pg1.sw_if_index)
5600
5601         # session initiated from service host - translate
5602         pkts = self.create_stream_in(self.pg0, self.pg1)
5603         self.pg0.add_stream(pkts)
5604         self.pg_enable_capture(self.pg_interfaces)
5605         self.pg_start()
5606         capture = self.pg1.get_capture(len(pkts))
5607         self.verify_capture_out(capture, ignore_port=True)
5608
5609         pkts = self.create_stream_out(self.pg1)
5610         self.pg1.add_stream(pkts)
5611         self.pg_enable_capture(self.pg_interfaces)
5612         self.pg_start()
5613         capture = self.pg0.get_capture(len(pkts))
5614         self.verify_capture_in(capture, self.pg0)
5615
5616         # session initiated from remote host - do not translate
5617         self.tcp_port_in = 60303
5618         self.udp_port_in = 60304
5619         self.icmp_id_in = 60305
5620         pkts = self.create_stream_out(self.pg1,
5621                                       self.pg0.remote_ip4,
5622                                       use_inside_ports=True)
5623         self.pg1.add_stream(pkts)
5624         self.pg_enable_capture(self.pg_interfaces)
5625         self.pg_start()
5626         capture = self.pg0.get_capture(len(pkts))
5627         self.verify_capture_in(capture, self.pg0)
5628
5629         pkts = self.create_stream_in(self.pg0, self.pg1)
5630         self.pg0.add_stream(pkts)
5631         self.pg_enable_capture(self.pg_interfaces)
5632         self.pg_start()
5633         capture = self.pg1.get_capture(len(pkts))
5634         self.verify_capture_out(capture, nat_ip=self.pg0.remote_ip4,
5635                                 same_port=True)
5636
5637     def test_output_feature_and_service3(self):
5638         """ NAT44 interface output feature and DST NAT """
5639         external_addr = '1.2.3.4'
5640         external_port = 80
5641         local_port = 8080
5642
5643         self.vapi.nat44_forwarding_enable_disable(enable=1)
5644         self.nat44_add_address(self.nat_addr)
5645         flags = self.config_flags.NAT_IS_OUT2IN_ONLY
5646         self.nat44_add_static_mapping(self.pg1.remote_ip4, external_addr,
5647                                       local_port, external_port,
5648                                       proto=IP_PROTOS.tcp, flags=flags)
5649         flags = self.config_flags.NAT_IS_INSIDE
5650         self.vapi.nat44_interface_add_del_feature(
5651             sw_if_index=self.pg0.sw_if_index,
5652             is_add=1)
5653         self.vapi.nat44_interface_add_del_feature(
5654             sw_if_index=self.pg0.sw_if_index,
5655             flags=flags, is_add=1)
5656         self.vapi.nat44_interface_add_del_output_feature(
5657             is_add=1,
5658             sw_if_index=self.pg1.sw_if_index)
5659
5660         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
5661              IP(src=self.pg0.remote_ip4, dst=external_addr) /
5662              TCP(sport=12345, dport=external_port))
5663         self.pg0.add_stream(p)
5664         self.pg_enable_capture(self.pg_interfaces)
5665         self.pg_start()
5666         capture = self.pg1.get_capture(1)
5667         p = capture[0]
5668         try:
5669             ip = p[IP]
5670             tcp = p[TCP]
5671             self.assertEqual(ip.src, self.pg0.remote_ip4)
5672             self.assertEqual(tcp.sport, 12345)
5673             self.assertEqual(ip.dst, self.pg1.remote_ip4)
5674             self.assertEqual(tcp.dport, local_port)
5675             self.assert_packet_checksums_valid(p)
5676         except:
5677             self.logger.error(ppp("Unexpected or invalid packet:", p))
5678             raise
5679
5680         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
5681              IP(src=self.pg1.remote_ip4, dst=self.pg0.remote_ip4) /
5682              TCP(sport=local_port, dport=12345))
5683         self.pg1.add_stream(p)
5684         self.pg_enable_capture(self.pg_interfaces)
5685         self.pg_start()
5686         capture = self.pg0.get_capture(1)
5687         p = capture[0]
5688         try:
5689             ip = p[IP]
5690             tcp = p[TCP]
5691             self.assertEqual(ip.src, external_addr)
5692             self.assertEqual(tcp.sport, external_port)
5693             self.assertEqual(ip.dst, self.pg0.remote_ip4)
5694             self.assertEqual(tcp.dport, 12345)
5695             self.assert_packet_checksums_valid(p)
5696         except:
5697             self.logger.error(ppp("Unexpected or invalid packet:", p))
5698             raise
5699
5700     def test_next_src_nat(self):
5701         """ On way back forward packet to nat44-in2out node. """
5702         twice_nat_addr = '10.0.1.3'
5703         external_port = 80
5704         local_port = 8080
5705         post_twice_nat_port = 0
5706
5707         self.vapi.nat44_forwarding_enable_disable(enable=1)
5708         self.nat44_add_address(twice_nat_addr, twice_nat=1)
5709         flags = (self.config_flags.NAT_IS_OUT2IN_ONLY |
5710                  self.config_flags.NAT_IS_SELF_TWICE_NAT)
5711         self.nat44_add_static_mapping(self.pg6.remote_ip4, self.pg1.remote_ip4,
5712                                       local_port, external_port,
5713                                       proto=IP_PROTOS.tcp, vrf_id=1,
5714                                       flags=flags)
5715         self.vapi.nat44_interface_add_del_feature(
5716             sw_if_index=self.pg6.sw_if_index,
5717             is_add=1)
5718
5719         p = (Ether(src=self.pg6.remote_mac, dst=self.pg6.local_mac) /
5720              IP(src=self.pg6.remote_ip4, dst=self.pg1.remote_ip4) /
5721              TCP(sport=12345, dport=external_port))
5722         self.pg6.add_stream(p)
5723         self.pg_enable_capture(self.pg_interfaces)
5724         self.pg_start()
5725         capture = self.pg6.get_capture(1)
5726         p = capture[0]
5727         try:
5728             ip = p[IP]
5729             tcp = p[TCP]
5730             self.assertEqual(ip.src, twice_nat_addr)
5731             self.assertNotEqual(tcp.sport, 12345)
5732             post_twice_nat_port = tcp.sport
5733             self.assertEqual(ip.dst, self.pg6.remote_ip4)
5734             self.assertEqual(tcp.dport, local_port)
5735             self.assert_packet_checksums_valid(p)
5736         except:
5737             self.logger.error(ppp("Unexpected or invalid packet:", p))
5738             raise
5739
5740         p = (Ether(src=self.pg6.remote_mac, dst=self.pg6.local_mac) /
5741              IP(src=self.pg6.remote_ip4, dst=twice_nat_addr) /
5742              TCP(sport=local_port, dport=post_twice_nat_port))
5743         self.pg6.add_stream(p)
5744         self.pg_enable_capture(self.pg_interfaces)
5745         self.pg_start()
5746         capture = self.pg6.get_capture(1)
5747         p = capture[0]
5748         try:
5749             ip = p[IP]
5750             tcp = p[TCP]
5751             self.assertEqual(ip.src, self.pg1.remote_ip4)
5752             self.assertEqual(tcp.sport, external_port)
5753             self.assertEqual(ip.dst, self.pg6.remote_ip4)
5754             self.assertEqual(tcp.dport, 12345)
5755             self.assert_packet_checksums_valid(p)
5756         except:
5757             self.logger.error(ppp("Unexpected or invalid packet:", p))
5758             raise
5759
5760     def twice_nat_common(self, self_twice_nat=False, same_pg=False, lb=False,
5761                          client_id=None):
5762         twice_nat_addr = '10.0.1.3'
5763
5764         port_in = 8080
5765         if lb:
5766             if not same_pg:
5767                 port_in1 = port_in
5768                 port_in2 = port_in
5769             else:
5770                 port_in1 = port_in + 1
5771                 port_in2 = port_in + 2
5772
5773         port_out = 80
5774         eh_port_out = 4567
5775
5776         server1 = self.pg0.remote_hosts[0]
5777         server2 = self.pg0.remote_hosts[1]
5778         if lb and same_pg:
5779             server2 = server1
5780         if not lb:
5781             server = server1
5782
5783         pg0 = self.pg0
5784         if same_pg:
5785             pg1 = self.pg0
5786         else:
5787             pg1 = self.pg1
5788
5789         eh_translate = ((not self_twice_nat) or (not lb and same_pg) or
5790                         client_id == 1)
5791
5792         self.nat44_add_address(self.nat_addr)
5793         self.nat44_add_address(twice_nat_addr, twice_nat=1)
5794
5795         flags = 0
5796         if self_twice_nat:
5797             flags |= self.config_flags.NAT_IS_SELF_TWICE_NAT
5798         else:
5799             flags |= self.config_flags.NAT_IS_TWICE_NAT
5800
5801         if not lb:
5802             self.nat44_add_static_mapping(pg0.remote_ip4, self.nat_addr,
5803                                           port_in, port_out,
5804                                           proto=IP_PROTOS.tcp,
5805                                           flags=flags)
5806         else:
5807             locals = [{'addr': server1.ip4,
5808                        'port': port_in1,
5809                        'probability': 50,
5810                        'vrf_id': 0},
5811                       {'addr': server2.ip4,
5812                        'port': port_in2,
5813                        'probability': 50,
5814                        'vrf_id': 0}]
5815             out_addr = self.nat_addr
5816
5817             self.vapi.nat44_add_del_lb_static_mapping(is_add=1, flags=flags,
5818                                                       external_addr=out_addr,
5819                                                       external_port=port_out,
5820                                                       protocol=IP_PROTOS.tcp,
5821                                                       local_num=len(locals),
5822                                                       locals=locals)
5823         flags = self.config_flags.NAT_IS_INSIDE
5824         self.vapi.nat44_interface_add_del_feature(
5825             sw_if_index=pg0.sw_if_index,
5826             flags=flags, is_add=1)
5827         self.vapi.nat44_interface_add_del_feature(
5828             sw_if_index=pg1.sw_if_index,
5829             is_add=1)
5830
5831         if same_pg:
5832             if not lb:
5833                 client = server
5834             else:
5835                 assert client_id is not None
5836                 if client_id == 1:
5837                     client = self.pg0.remote_hosts[0]
5838                 elif client_id == 2:
5839                     client = self.pg0.remote_hosts[1]
5840         else:
5841             client = pg1.remote_hosts[0]
5842         p = (Ether(src=pg1.remote_mac, dst=pg1.local_mac) /
5843              IP(src=client.ip4, dst=self.nat_addr) /
5844              TCP(sport=eh_port_out, dport=port_out))
5845         pg1.add_stream(p)
5846         self.pg_enable_capture(self.pg_interfaces)
5847         self.pg_start()
5848         capture = pg0.get_capture(1)
5849         p = capture[0]
5850         try:
5851             ip = p[IP]
5852             tcp = p[TCP]
5853             if lb:
5854                 if ip.dst == server1.ip4:
5855                     server = server1
5856                     port_in = port_in1
5857                 else:
5858                     server = server2
5859                     port_in = port_in2
5860             self.assertEqual(ip.dst, server.ip4)
5861             if lb and same_pg:
5862                 self.assertIn(tcp.dport, [port_in1, port_in2])
5863             else:
5864                 self.assertEqual(tcp.dport, port_in)
5865             if eh_translate:
5866                 self.assertEqual(ip.src, twice_nat_addr)
5867                 self.assertNotEqual(tcp.sport, eh_port_out)
5868             else:
5869                 self.assertEqual(ip.src, client.ip4)
5870                 self.assertEqual(tcp.sport, eh_port_out)
5871             eh_addr_in = ip.src
5872             eh_port_in = tcp.sport
5873             saved_port_in = tcp.dport
5874             self.assert_packet_checksums_valid(p)
5875         except:
5876             self.logger.error(ppp("Unexpected or invalid packet:", p))
5877             raise
5878
5879         p = (Ether(src=server.mac, dst=pg0.local_mac) /
5880              IP(src=server.ip4, dst=eh_addr_in) /
5881              TCP(sport=saved_port_in, dport=eh_port_in))
5882         pg0.add_stream(p)
5883         self.pg_enable_capture(self.pg_interfaces)
5884         self.pg_start()
5885         capture = pg1.get_capture(1)
5886         p = capture[0]
5887         try:
5888             ip = p[IP]
5889             tcp = p[TCP]
5890             self.assertEqual(ip.dst, client.ip4)
5891             self.assertEqual(ip.src, self.nat_addr)
5892             self.assertEqual(tcp.dport, eh_port_out)
5893             self.assertEqual(tcp.sport, port_out)
5894             self.assert_packet_checksums_valid(p)
5895         except:
5896             self.logger.error(ppp("Unexpected or invalid packet:", p))
5897             raise
5898
5899         if eh_translate:
5900             sessions = self.vapi.nat44_user_session_dump(server.ip4, 0)
5901             self.assertEqual(len(sessions), 1)
5902             self.assertTrue(sessions[0].flags &
5903                             self.config_flags.NAT_IS_EXT_HOST_VALID)
5904             self.assertTrue(sessions[0].flags &
5905                             self.config_flags.NAT_IS_TWICE_NAT)
5906             self.logger.info(self.vapi.cli("show nat44 sessions detail"))
5907             self.vapi.nat44_del_session(
5908                 address=sessions[0].inside_ip_address,
5909                 port=sessions[0].inside_port,
5910                 protocol=sessions[0].protocol,
5911                 flags=(self.config_flags.NAT_IS_INSIDE |
5912                        self.config_flags.NAT_IS_EXT_HOST_VALID),
5913                 ext_host_address=sessions[0].ext_host_nat_address,
5914                 ext_host_port=sessions[0].ext_host_nat_port)
5915             sessions = self.vapi.nat44_user_session_dump(server.ip4, 0)
5916             self.assertEqual(len(sessions), 0)
5917
5918     def test_twice_nat(self):
5919         """ Twice NAT44 """
5920         self.twice_nat_common()
5921
5922     def test_self_twice_nat_positive(self):
5923         """ Self Twice NAT44 (positive test) """
5924         self.twice_nat_common(self_twice_nat=True, same_pg=True)
5925
5926     def test_self_twice_nat_negative(self):
5927         """ Self Twice NAT44 (negative test) """
5928         self.twice_nat_common(self_twice_nat=True)
5929
5930     def test_twice_nat_lb(self):
5931         """ Twice NAT44 local service load balancing """
5932         self.twice_nat_common(lb=True)
5933
5934     def test_self_twice_nat_lb_positive(self):
5935         """ Self Twice NAT44 local service load balancing (positive test) """
5936         self.twice_nat_common(lb=True, self_twice_nat=True, same_pg=True,
5937                               client_id=1)
5938
5939     def test_self_twice_nat_lb_negative(self):
5940         """ Self Twice NAT44 local service load balancing (negative test) """
5941         self.twice_nat_common(lb=True, self_twice_nat=True, same_pg=True,
5942                               client_id=2)
5943
5944     def test_twice_nat_interface_addr(self):
5945         """ Acquire twice NAT44 addresses from interface """
5946         flags = self.config_flags.NAT_IS_TWICE_NAT
5947         self.vapi.nat44_add_del_interface_addr(
5948             is_add=1,
5949             sw_if_index=self.pg3.sw_if_index,
5950             flags=flags)
5951
5952         # no address in NAT pool
5953         adresses = self.vapi.nat44_address_dump()
5954         self.assertEqual(0, len(adresses))
5955
5956         # configure interface address and check NAT address pool
5957         self.pg3.config_ip4()
5958         adresses = self.vapi.nat44_address_dump()
5959         self.assertEqual(1, len(adresses))
5960         self.assertEqual(str(adresses[0].ip_address),
5961                          self.pg3.local_ip4)
5962         self.assertEqual(adresses[0].flags, flags)
5963
5964         # remove interface address and check NAT address pool
5965         self.pg3.unconfig_ip4()
5966         adresses = self.vapi.nat44_address_dump()
5967         self.assertEqual(0, len(adresses))
5968
5969     def test_tcp_close(self):
5970         """ Close TCP session from inside network - output feature """
5971         self.vapi.nat44_forwarding_enable_disable(enable=1)
5972         self.nat44_add_address(self.pg1.local_ip4)
5973         twice_nat_addr = '10.0.1.3'
5974         service_ip = '192.168.16.150'
5975         self.nat44_add_address(twice_nat_addr, twice_nat=1)
5976         flags = self.config_flags.NAT_IS_INSIDE
5977         self.vapi.nat44_interface_add_del_feature(
5978             sw_if_index=self.pg0.sw_if_index,
5979             is_add=1)
5980         self.vapi.nat44_interface_add_del_feature(
5981             sw_if_index=self.pg0.sw_if_index,
5982             flags=flags, is_add=1)
5983         self.vapi.nat44_interface_add_del_output_feature(
5984             is_add=1,
5985             sw_if_index=self.pg1.sw_if_index)
5986         flags = (self.config_flags.NAT_IS_OUT2IN_ONLY |
5987                  self.config_flags.NAT_IS_TWICE_NAT)
5988         self.nat44_add_static_mapping(self.pg0.remote_ip4,
5989                                       service_ip,
5990                                       80,
5991                                       80,
5992                                       proto=IP_PROTOS.tcp,
5993                                       flags=flags)
5994         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
5995         start_sessnum = len(sessions)
5996
5997         # SYN packet out->in
5998         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
5999              IP(src=self.pg1.remote_ip4, dst=service_ip) /
6000              TCP(sport=33898, dport=80, flags="S"))
6001         self.pg1.add_stream(p)
6002         self.pg_enable_capture(self.pg_interfaces)
6003         self.pg_start()
6004         capture = self.pg0.get_capture(1)
6005         p = capture[0]
6006         tcp_port = p[TCP].sport
6007
6008         # SYN + ACK packet in->out
6009         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6010              IP(src=self.pg0.remote_ip4, dst=twice_nat_addr) /
6011              TCP(sport=80, dport=tcp_port, flags="SA"))
6012         self.pg0.add_stream(p)
6013         self.pg_enable_capture(self.pg_interfaces)
6014         self.pg_start()
6015         self.pg1.get_capture(1)
6016
6017         # ACK packet out->in
6018         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
6019              IP(src=self.pg1.remote_ip4, dst=service_ip) /
6020              TCP(sport=33898, dport=80, flags="A"))
6021         self.pg1.add_stream(p)
6022         self.pg_enable_capture(self.pg_interfaces)
6023         self.pg_start()
6024         self.pg0.get_capture(1)
6025
6026         # FIN packet in -> out
6027         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6028              IP(src=self.pg0.remote_ip4, dst=twice_nat_addr) /
6029              TCP(sport=80, dport=tcp_port, flags="FA", seq=100, ack=300))
6030         self.pg0.add_stream(p)
6031         self.pg_enable_capture(self.pg_interfaces)
6032         self.pg_start()
6033         self.pg1.get_capture(1)
6034
6035         # FIN+ACK packet out -> in
6036         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
6037              IP(src=self.pg1.remote_ip4, dst=service_ip) /
6038              TCP(sport=33898, dport=80, flags="FA", seq=300, ack=101))
6039         self.pg1.add_stream(p)
6040         self.pg_enable_capture(self.pg_interfaces)
6041         self.pg_start()
6042         self.pg0.get_capture(1)
6043
6044         # ACK packet in -> out
6045         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6046              IP(src=self.pg0.remote_ip4, dst=twice_nat_addr) /
6047              TCP(sport=80, dport=tcp_port, flags="A", seq=101, ack=301))
6048         self.pg0.add_stream(p)
6049         self.pg_enable_capture(self.pg_interfaces)
6050         self.pg_start()
6051         self.pg1.get_capture(1)
6052
6053         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4,
6054                                                      0)
6055         self.assertEqual(len(sessions) - start_sessnum, 0)
6056
6057     def test_tcp_session_close_in(self):
6058         """ Close TCP session from inside network """
6059         self.tcp_port_out = 10505
6060         self.nat44_add_address(self.nat_addr)
6061         flags = self.config_flags.NAT_IS_TWICE_NAT
6062         self.nat44_add_static_mapping(self.pg0.remote_ip4,
6063                                       self.nat_addr,
6064                                       self.tcp_port_in,
6065                                       self.tcp_port_out,
6066                                       proto=IP_PROTOS.tcp,
6067                                       flags=flags)
6068         flags = self.config_flags.NAT_IS_INSIDE
6069         self.vapi.nat44_interface_add_del_feature(
6070             sw_if_index=self.pg0.sw_if_index,
6071             flags=flags, is_add=1)
6072         self.vapi.nat44_interface_add_del_feature(
6073             sw_if_index=self.pg1.sw_if_index,
6074             is_add=1)
6075
6076         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
6077         start_sessnum = len(sessions)
6078
6079         self.vapi.nat_set_timeouts(udp=300, tcp_established=7440,
6080                                    tcp_transitory=2, icmp=5)
6081
6082         self.initiate_tcp_session(self.pg0, self.pg1)
6083
6084         # FIN packet in -> out
6085         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6086              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6087              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
6088                  flags="FA", seq=100, ack=300))
6089         self.pg0.add_stream(p)
6090         self.pg_enable_capture(self.pg_interfaces)
6091         self.pg_start()
6092         self.pg1.get_capture(1)
6093
6094         pkts = []
6095
6096         # ACK packet out -> in
6097         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
6098              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
6099              TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
6100                  flags="A", seq=300, ack=101))
6101         pkts.append(p)
6102
6103         # FIN packet out -> in
6104         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
6105              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
6106              TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
6107                  flags="FA", seq=300, ack=101))
6108         pkts.append(p)
6109
6110         self.pg1.add_stream(pkts)
6111         self.pg_enable_capture(self.pg_interfaces)
6112         self.pg_start()
6113         self.pg0.get_capture(2)
6114
6115         # ACK packet in -> out
6116         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6117              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6118              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
6119                  flags="A", seq=101, ack=301))
6120         self.pg0.add_stream(p)
6121         self.pg_enable_capture(self.pg_interfaces)
6122         self.pg_start()
6123         self.pg1.get_capture(1)
6124
6125         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
6126         self.assertEqual(len(sessions) - start_sessnum, 1)
6127
6128         stats = self.statistics.get_counter(
6129             '/err/nat44-ed-out2in/drops due to TCP in transitory timeout')
6130         out2in_drops = stats[0]
6131         stats = self.statistics.get_counter(
6132             '/err/nat44-ed-in2out/drops due to TCP in transitory timeout')
6133         in2out_drops = stats[0]
6134
6135         # extra FIN packet out -> in - this should be dropped
6136         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
6137              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
6138              TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
6139                  flags="FA", seq=300, ack=101))
6140
6141         self.pg1.add_stream(p)
6142         self.pg_enable_capture(self.pg_interfaces)
6143         self.pg_start()
6144         self.pg0.assert_nothing_captured()
6145
6146         # extra ACK packet in -> out - this should be dropped
6147         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6148              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6149              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
6150                  flags="A", seq=101, ack=301))
6151         self.pg0.add_stream(p)
6152         self.pg_enable_capture(self.pg_interfaces)
6153         self.pg_start()
6154         self.pg1.assert_nothing_captured()
6155
6156         stats = self.statistics.get_counter(
6157             '/err/nat44-ed-out2in/drops due to TCP in transitory timeout')
6158         self.assertEqual(stats[0] - out2in_drops, 1)
6159         stats = self.statistics.get_counter(
6160             '/err/nat44-ed-in2out/drops due to TCP in transitory timeout')
6161         self.assertEqual(stats[0] - in2out_drops, 1)
6162
6163         self.sleep(3)
6164         # extra ACK packet in -> out - this will cause session to be wiped
6165         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6166              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6167              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
6168                  flags="A", seq=101, ack=301))
6169         self.pg0.add_stream(p)
6170         self.pg_enable_capture(self.pg_interfaces)
6171         self.pg_start()
6172         self.pg1.assert_nothing_captured()
6173         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
6174         self.assertEqual(len(sessions) - start_sessnum, 0)
6175
6176     def test_tcp_session_close_out(self):
6177         """ Close TCP session from outside network """
6178         self.tcp_port_out = 10505
6179         self.nat44_add_address(self.nat_addr)
6180         flags = self.config_flags.NAT_IS_TWICE_NAT
6181         self.nat44_add_static_mapping(self.pg0.remote_ip4,
6182                                       self.nat_addr,
6183                                       self.tcp_port_in,
6184                                       self.tcp_port_out,
6185                                       proto=IP_PROTOS.tcp,
6186                                       flags=flags)
6187         flags = self.config_flags.NAT_IS_INSIDE
6188         self.vapi.nat44_interface_add_del_feature(
6189             sw_if_index=self.pg0.sw_if_index,
6190             flags=flags, is_add=1)
6191         self.vapi.nat44_interface_add_del_feature(
6192             sw_if_index=self.pg1.sw_if_index,
6193             is_add=1)
6194
6195         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
6196         start_sessnum = len(sessions)
6197
6198         self.vapi.nat_set_timeouts(udp=300, tcp_established=7440,
6199                                    tcp_transitory=2, icmp=5)
6200
6201         self.initiate_tcp_session(self.pg0, self.pg1)
6202
6203         # FIN packet out -> in
6204         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
6205              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
6206              TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
6207                  flags="FA", seq=100, ack=300))
6208         self.pg1.add_stream(p)
6209         self.pg_enable_capture(self.pg_interfaces)
6210         self.pg_start()
6211         self.pg0.get_capture(1)
6212
6213         # FIN+ACK packet in -> out
6214         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6215              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6216              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
6217                  flags="FA", seq=300, ack=101))
6218
6219         self.pg0.add_stream(p)
6220         self.pg_enable_capture(self.pg_interfaces)
6221         self.pg_start()
6222         self.pg1.get_capture(1)
6223
6224         # ACK packet out -> in
6225         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
6226              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
6227              TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
6228                  flags="A", seq=101, ack=301))
6229         self.pg1.add_stream(p)
6230         self.pg_enable_capture(self.pg_interfaces)
6231         self.pg_start()
6232         self.pg0.get_capture(1)
6233
6234         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
6235         self.assertEqual(len(sessions) - start_sessnum, 1)
6236
6237         stats = self.statistics.get_counter(
6238             '/err/nat44-ed-out2in/drops due to TCP in transitory timeout')
6239         out2in_drops = stats[0]
6240         stats = self.statistics.get_counter(
6241             '/err/nat44-ed-in2out/drops due to TCP in transitory timeout')
6242         in2out_drops = stats[0]
6243
6244         # extra FIN packet out -> in - this should be dropped
6245         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
6246              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
6247              TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
6248                  flags="FA", seq=300, ack=101))
6249
6250         self.pg1.add_stream(p)
6251         self.pg_enable_capture(self.pg_interfaces)
6252         self.pg_start()
6253         self.pg0.assert_nothing_captured()
6254
6255         # extra ACK packet in -> out - this should be dropped
6256         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6257              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6258              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
6259                  flags="A", seq=101, ack=301))
6260         self.pg0.add_stream(p)
6261         self.pg_enable_capture(self.pg_interfaces)
6262         self.pg_start()
6263         self.pg1.assert_nothing_captured()
6264
6265         stats = self.statistics.get_counter(
6266             '/err/nat44-ed-out2in/drops due to TCP in transitory timeout')
6267         self.assertEqual(stats[0] - out2in_drops, 1)
6268         stats = self.statistics.get_counter(
6269             '/err/nat44-ed-in2out/drops due to TCP in transitory timeout')
6270         self.assertEqual(stats[0] - in2out_drops, 1)
6271
6272         self.sleep(3)
6273         # extra ACK packet in -> out - this will cause session to be wiped
6274         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6275              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6276              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
6277                  flags="A", seq=101, ack=301))
6278         self.pg0.add_stream(p)
6279         self.pg_enable_capture(self.pg_interfaces)
6280         self.pg_start()
6281         self.pg1.assert_nothing_captured()
6282         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
6283         self.assertEqual(len(sessions) - start_sessnum, 0)
6284
6285     def test_tcp_session_close_simultaneous(self):
6286         """ Close TCP session from inside network """
6287         self.tcp_port_out = 10505
6288         self.nat44_add_address(self.nat_addr)
6289         flags = self.config_flags.NAT_IS_TWICE_NAT
6290         self.nat44_add_static_mapping(self.pg0.remote_ip4,
6291                                       self.nat_addr,
6292                                       self.tcp_port_in,
6293                                       self.tcp_port_out,
6294                                       proto=IP_PROTOS.tcp,
6295                                       flags=flags)
6296         flags = self.config_flags.NAT_IS_INSIDE
6297         self.vapi.nat44_interface_add_del_feature(
6298             sw_if_index=self.pg0.sw_if_index,
6299             flags=flags, is_add=1)
6300         self.vapi.nat44_interface_add_del_feature(
6301             sw_if_index=self.pg1.sw_if_index,
6302             is_add=1)
6303
6304         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
6305         start_sessnum = len(sessions)
6306
6307         self.vapi.nat_set_timeouts(udp=300, tcp_established=7440,
6308                                    tcp_transitory=2, icmp=5)
6309
6310         self.initiate_tcp_session(self.pg0, self.pg1)
6311
6312         # FIN packet in -> out
6313         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6314              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6315              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
6316                  flags="FA", seq=100, ack=300))
6317         self.pg0.add_stream(p)
6318         self.pg_enable_capture(self.pg_interfaces)
6319         self.pg_start()
6320         self.pg1.get_capture(1)
6321
6322         # FIN packet out -> in
6323         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
6324              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
6325              TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
6326                  flags="FA", seq=300, ack=100))
6327         self.pg1.add_stream(p)
6328         self.pg_enable_capture(self.pg_interfaces)
6329         self.pg_start()
6330         self.pg0.get_capture(1)
6331
6332         # ACK packet in -> out
6333         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6334              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6335              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
6336                  flags="A", seq=101, ack=301))
6337         self.pg0.add_stream(p)
6338         self.pg_enable_capture(self.pg_interfaces)
6339         self.pg_start()
6340         self.pg1.get_capture(1)
6341
6342         # ACK packet out -> in
6343         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
6344              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
6345              TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
6346                  flags="A", seq=301, ack=101))
6347         self.pg1.add_stream(p)
6348         self.pg_enable_capture(self.pg_interfaces)
6349         self.pg_start()
6350         self.pg0.get_capture(1)
6351
6352         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
6353         self.assertEqual(len(sessions) - start_sessnum, 1)
6354
6355         stats = self.statistics.get_counter(
6356             '/err/nat44-ed-out2in/drops due to TCP in transitory timeout')
6357         out2in_drops = stats[0]
6358         stats = self.statistics.get_counter(
6359             '/err/nat44-ed-in2out/drops due to TCP in transitory timeout')
6360         in2out_drops = stats[0]
6361
6362         # extra FIN packet out -> in - this should be dropped
6363         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
6364              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
6365              TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
6366                  flags="FA", seq=300, ack=101))
6367
6368         self.pg1.add_stream(p)
6369         self.pg_enable_capture(self.pg_interfaces)
6370         self.pg_start()
6371         self.pg0.assert_nothing_captured()
6372
6373         # extra ACK packet in -> out - this should be dropped
6374         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6375              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6376              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
6377                  flags="A", seq=101, ack=301))
6378         self.pg0.add_stream(p)
6379         self.pg_enable_capture(self.pg_interfaces)
6380         self.pg_start()
6381         self.pg1.assert_nothing_captured()
6382
6383         stats = self.statistics.get_counter(
6384             '/err/nat44-ed-out2in/drops due to TCP in transitory timeout')
6385         self.assertEqual(stats[0] - out2in_drops, 1)
6386         stats = self.statistics.get_counter(
6387             '/err/nat44-ed-in2out/drops due to TCP in transitory timeout')
6388         self.assertEqual(stats[0] - in2out_drops, 1)
6389
6390         self.sleep(3)
6391         # extra ACK packet in -> out - this will cause session to be wiped
6392         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6393              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6394              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
6395                  flags="A", seq=101, ack=301))
6396         self.pg0.add_stream(p)
6397         self.pg_enable_capture(self.pg_interfaces)
6398         self.pg_start()
6399         self.pg1.assert_nothing_captured()
6400         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
6401         self.assertEqual(len(sessions) - start_sessnum, 0)
6402
6403     def test_one_armed_nat44_static(self):
6404         """ One armed NAT44 and 1:1 NAPT asymmetrical rule """
6405         remote_host = self.pg4.remote_hosts[0]
6406         local_host = self.pg4.remote_hosts[1]
6407         external_port = 80
6408         local_port = 8080
6409         eh_port_in = 0
6410
6411         self.vapi.nat44_forwarding_enable_disable(enable=1)
6412         self.nat44_add_address(self.nat_addr, twice_nat=1)
6413         flags = (self.config_flags.NAT_IS_OUT2IN_ONLY |
6414                  self.config_flags.NAT_IS_TWICE_NAT)
6415         self.nat44_add_static_mapping(local_host.ip4, self.nat_addr,
6416                                       local_port, external_port,
6417                                       proto=IP_PROTOS.tcp, flags=flags)
6418         flags = self.config_flags.NAT_IS_INSIDE
6419         self.vapi.nat44_interface_add_del_feature(
6420             sw_if_index=self.pg4.sw_if_index,
6421             is_add=1)
6422         self.vapi.nat44_interface_add_del_feature(
6423             sw_if_index=self.pg4.sw_if_index,
6424             flags=flags, is_add=1)
6425
6426         # from client to service
6427         p = (Ether(src=self.pg4.remote_mac, dst=self.pg4.local_mac) /
6428              IP(src=remote_host.ip4, dst=self.nat_addr) /
6429              TCP(sport=12345, dport=external_port))
6430         self.pg4.add_stream(p)
6431         self.pg_enable_capture(self.pg_interfaces)
6432         self.pg_start()
6433         capture = self.pg4.get_capture(1)
6434         p = capture[0]
6435         try:
6436             ip = p[IP]
6437             tcp = p[TCP]
6438             self.assertEqual(ip.dst, local_host.ip4)
6439             self.assertEqual(ip.src, self.nat_addr)
6440             self.assertEqual(tcp.dport, local_port)
6441             self.assertNotEqual(tcp.sport, 12345)
6442             eh_port_in = tcp.sport
6443             self.assert_packet_checksums_valid(p)
6444         except:
6445             self.logger.error(ppp("Unexpected or invalid packet:", p))
6446             raise
6447
6448         # from service back to client
6449         p = (Ether(src=self.pg4.remote_mac, dst=self.pg4.local_mac) /
6450              IP(src=local_host.ip4, dst=self.nat_addr) /
6451              TCP(sport=local_port, dport=eh_port_in))
6452         self.pg4.add_stream(p)
6453         self.pg_enable_capture(self.pg_interfaces)
6454         self.pg_start()
6455         capture = self.pg4.get_capture(1)
6456         p = capture[0]
6457         try:
6458             ip = p[IP]
6459             tcp = p[TCP]
6460             self.assertEqual(ip.src, self.nat_addr)
6461             self.assertEqual(ip.dst, remote_host.ip4)
6462             self.assertEqual(tcp.sport, external_port)
6463             self.assertEqual(tcp.dport, 12345)
6464             self.assert_packet_checksums_valid(p)
6465         except:
6466             self.logger.error(ppp("Unexpected or invalid packet:", p))
6467             raise
6468
6469     def test_static_with_port_out2(self):
6470         """ 1:1 NAPT asymmetrical rule """
6471
6472         external_port = 80
6473         local_port = 8080
6474
6475         self.vapi.nat44_forwarding_enable_disable(enable=1)
6476         flags = self.config_flags.NAT_IS_OUT2IN_ONLY
6477         self.nat44_add_static_mapping(self.pg0.remote_ip4, self.nat_addr,
6478                                       local_port, external_port,
6479                                       proto=IP_PROTOS.tcp, flags=flags)
6480         flags = self.config_flags.NAT_IS_INSIDE
6481         self.vapi.nat44_interface_add_del_feature(
6482             sw_if_index=self.pg0.sw_if_index,
6483             flags=flags, is_add=1)
6484         self.vapi.nat44_interface_add_del_feature(
6485             sw_if_index=self.pg1.sw_if_index,
6486             is_add=1)
6487
6488         # from client to service
6489         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
6490              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
6491              TCP(sport=12345, dport=external_port))
6492         self.pg1.add_stream(p)
6493         self.pg_enable_capture(self.pg_interfaces)
6494         self.pg_start()
6495         capture = self.pg0.get_capture(1)
6496         p = capture[0]
6497         try:
6498             ip = p[IP]
6499             tcp = p[TCP]
6500             self.assertEqual(ip.dst, self.pg0.remote_ip4)
6501             self.assertEqual(tcp.dport, local_port)
6502             self.assert_packet_checksums_valid(p)
6503         except:
6504             self.logger.error(ppp("Unexpected or invalid packet:", p))
6505             raise
6506
6507         # ICMP error
6508         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
6509              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6510              ICMP(type=11) / capture[0][IP])
6511         self.pg0.add_stream(p)
6512         self.pg_enable_capture(self.pg_interfaces)
6513         self.pg_start()
6514         capture = self.pg1.get_capture(1)
6515         p = capture[0]
6516         try:
6517             self.assertEqual(p[IP].src, self.nat_addr)
6518             inner = p[IPerror]
6519             self.assertEqual(inner.dst, self.nat_addr)
6520             self.assertEqual(inner[TCPerror].dport, external_port)
6521         except:
6522             self.logger.error(ppp("Unexpected or invalid packet:", p))
6523             raise
6524
6525         # from service back to client
6526         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6527              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6528              TCP(sport=local_port, dport=12345))
6529         self.pg0.add_stream(p)
6530         self.pg_enable_capture(self.pg_interfaces)
6531         self.pg_start()
6532         capture = self.pg1.get_capture(1)
6533         p = capture[0]
6534         try:
6535             ip = p[IP]
6536             tcp = p[TCP]
6537             self.assertEqual(ip.src, self.nat_addr)
6538             self.assertEqual(tcp.sport, external_port)
6539             self.assert_packet_checksums_valid(p)
6540         except:
6541             self.logger.error(ppp("Unexpected or invalid packet:", p))
6542             raise
6543
6544         # ICMP error
6545         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
6546              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
6547              ICMP(type=11) / capture[0][IP])
6548         self.pg1.add_stream(p)
6549         self.pg_enable_capture(self.pg_interfaces)
6550         self.pg_start()
6551         capture = self.pg0.get_capture(1)
6552         p = capture[0]
6553         try:
6554             self.assertEqual(p[IP].dst, self.pg0.remote_ip4)
6555             inner = p[IPerror]
6556             self.assertEqual(inner.src, self.pg0.remote_ip4)
6557             self.assertEqual(inner[TCPerror].sport, local_port)
6558         except:
6559             self.logger.error(ppp("Unexpected or invalid packet:", p))
6560             raise
6561
6562         # from client to server (no translation)
6563         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
6564              IP(src=self.pg1.remote_ip4, dst=self.pg0.remote_ip4) /
6565              TCP(sport=12346, dport=local_port))
6566         self.pg1.add_stream(p)
6567         self.pg_enable_capture(self.pg_interfaces)
6568         self.pg_start()
6569         capture = self.pg0.get_capture(1)
6570         p = capture[0]
6571         try:
6572             ip = p[IP]
6573             tcp = p[TCP]
6574             self.assertEqual(ip.dst, self.pg0.remote_ip4)
6575             self.assertEqual(tcp.dport, local_port)
6576             self.assert_packet_checksums_valid(p)
6577         except:
6578             self.logger.error(ppp("Unexpected or invalid packet:", p))
6579             raise
6580
6581         # from service back to client (no translation)
6582         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6583              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6584              TCP(sport=local_port, dport=12346))
6585         self.pg0.add_stream(p)
6586         self.pg_enable_capture(self.pg_interfaces)
6587         self.pg_start()
6588         capture = self.pg1.get_capture(1)
6589         p = capture[0]
6590         try:
6591             ip = p[IP]
6592             tcp = p[TCP]
6593             self.assertEqual(ip.src, self.pg0.remote_ip4)
6594             self.assertEqual(tcp.sport, local_port)
6595             self.assert_packet_checksums_valid(p)
6596         except:
6597             self.logger.error(ppp("Unexpected or invalid packet:", p))
6598             raise
6599
6600     def test_output_feature(self):
6601         """ NAT44 interface output feature (in2out postrouting) """
6602         self.vapi.nat44_forwarding_enable_disable(enable=1)
6603         self.nat44_add_address(self.nat_addr)
6604         self.vapi.nat44_interface_add_del_feature(
6605             sw_if_index=self.pg0.sw_if_index,
6606             is_add=1)
6607         self.vapi.nat44_interface_add_del_output_feature(
6608             is_add=1,
6609             sw_if_index=self.pg1.sw_if_index)
6610
6611         # in2out
6612         pkts = self.create_stream_in(self.pg0, self.pg1)
6613         self.pg0.add_stream(pkts)
6614         self.pg_enable_capture(self.pg_interfaces)
6615         self.pg_start()
6616         capture = self.pg1.get_capture(len(pkts))
6617         self.verify_capture_out(capture, ignore_port=True)
6618
6619         # out2in
6620         pkts = self.create_stream_out(self.pg1)
6621         self.pg1.add_stream(pkts)
6622         self.pg_enable_capture(self.pg_interfaces)
6623         self.pg_start()
6624         capture = self.pg0.get_capture(len(pkts))
6625         self.verify_capture_in(capture, self.pg0)
6626
6627     def test_output_feature_stateful_acl(self):
6628         """ NAT44 endpoint-dependent output feature works with stateful ACL """
6629         self.nat44_add_address(self.nat_addr)
6630         self.vapi.nat44_interface_add_del_output_feature(
6631             sw_if_index=self.pg0.sw_if_index,
6632             flags=self.config_flags.NAT_IS_INSIDE,
6633             is_add=1)
6634         self.vapi.nat44_interface_add_del_output_feature(
6635             sw_if_index=self.pg1.sw_if_index,
6636             flags=self.config_flags.NAT_IS_OUTSIDE,
6637             is_add=1)
6638
6639         # First ensure that the NAT is working sans ACL
6640
6641         # send packets out2in, no sessions yet so packets should drop
6642         pkts_out2in = self.create_stream_out(self.pg1)
6643         self.send_and_assert_no_replies(self.pg1, pkts_out2in)
6644
6645         # send packets into inside intf, ensure received via outside intf
6646         pkts_in2out = self.create_stream_in(self.pg0, self.pg1)
6647         capture = self.send_and_expect(self.pg0, pkts_in2out, self.pg1,
6648                                        len(pkts_in2out))
6649         self.verify_capture_out(capture, ignore_port=True)
6650
6651         # send out2in again, with sessions created it should work now
6652         pkts_out2in = self.create_stream_out(self.pg1)
6653         capture = self.send_and_expect(self.pg1, pkts_out2in, self.pg0,
6654                                        len(pkts_out2in))
6655         self.verify_capture_in(capture, self.pg0)
6656
6657         # Create an ACL blocking everything
6658         out2in_deny_rule = AclRule(is_permit=0)
6659         out2in_acl = VppAcl(self, rules=[out2in_deny_rule])
6660         out2in_acl.add_vpp_config()
6661
6662         # create an ACL to permit/reflect everything
6663         in2out_reflect_rule = AclRule(is_permit=2)
6664         in2out_acl = VppAcl(self, rules=[in2out_reflect_rule])
6665         in2out_acl.add_vpp_config()
6666
6667         # apply as input acl on interface and confirm it blocks everything
6668         acl_if = VppAclInterface(self, sw_if_index=self.pg1.sw_if_index,
6669                                  n_input=1, acls=[out2in_acl])
6670         acl_if.add_vpp_config()
6671         self.send_and_assert_no_replies(self.pg1, pkts_out2in)
6672
6673         # apply output acl
6674         acl_if.acls = [out2in_acl, in2out_acl]
6675         acl_if.add_vpp_config()
6676         # send in2out to generate ACL state (NAT state was created earlier)
6677         capture = self.send_and_expect(self.pg0, pkts_in2out, self.pg1,
6678                                        len(pkts_in2out))
6679         self.verify_capture_out(capture, ignore_port=True)
6680
6681         # send out2in again. ACL state exists so it should work now.
6682         # TCP packets with the syn flag set also need the ack flag
6683         for p in pkts_out2in:
6684             if p.haslayer(TCP) and p[TCP].flags & 0x02:
6685                 p[TCP].flags |= 0x10
6686         capture = self.send_and_expect(self.pg1, pkts_out2in, self.pg0,
6687                                        len(pkts_out2in))
6688         self.verify_capture_in(capture, self.pg0)
6689         self.logger.info(self.vapi.cli("show trace"))
6690
6691     def test_multiple_vrf(self):
6692         """ Multiple VRF setup """
6693         external_addr = '1.2.3.4'
6694         external_port = 80
6695         local_port = 8080
6696         port = 0
6697
6698         self.vapi.nat44_forwarding_enable_disable(enable=1)
6699         self.nat44_add_address(self.nat_addr)
6700         flags = self.config_flags.NAT_IS_INSIDE
6701         self.vapi.nat44_interface_add_del_feature(
6702             sw_if_index=self.pg0.sw_if_index,
6703             is_add=1)
6704         self.vapi.nat44_interface_add_del_feature(
6705             sw_if_index=self.pg0.sw_if_index,
6706             flags=flags, is_add=1)
6707         self.vapi.nat44_interface_add_del_output_feature(
6708             is_add=1,
6709             sw_if_index=self.pg1.sw_if_index)
6710         self.vapi.nat44_interface_add_del_feature(
6711             sw_if_index=self.pg5.sw_if_index,
6712             is_add=1)
6713         self.vapi.nat44_interface_add_del_feature(
6714             sw_if_index=self.pg5.sw_if_index,
6715             flags=flags, is_add=1)
6716         self.vapi.nat44_interface_add_del_feature(
6717             sw_if_index=self.pg6.sw_if_index,
6718             is_add=1)
6719         flags = self.config_flags.NAT_IS_OUT2IN_ONLY
6720         self.nat44_add_static_mapping(self.pg5.remote_ip4, external_addr,
6721                                       local_port, external_port, vrf_id=1,
6722                                       proto=IP_PROTOS.tcp, flags=flags)
6723         self.nat44_add_static_mapping(
6724             self.pg0.remote_ip4,
6725             external_sw_if_index=self.pg0.sw_if_index,
6726             local_port=local_port,
6727             vrf_id=0,
6728             external_port=external_port,
6729             proto=IP_PROTOS.tcp,
6730             flags=flags
6731         )
6732
6733         # from client to service (both VRF1)
6734         p = (Ether(src=self.pg6.remote_mac, dst=self.pg6.local_mac) /
6735              IP(src=self.pg6.remote_ip4, dst=external_addr) /
6736              TCP(sport=12345, dport=external_port))
6737         self.pg6.add_stream(p)
6738         self.pg_enable_capture(self.pg_interfaces)
6739         self.pg_start()
6740         capture = self.pg5.get_capture(1)
6741         p = capture[0]
6742         try:
6743             ip = p[IP]
6744             tcp = p[TCP]
6745             self.assertEqual(ip.dst, self.pg5.remote_ip4)
6746             self.assertEqual(tcp.dport, local_port)
6747             self.assert_packet_checksums_valid(p)
6748         except:
6749             self.logger.error(ppp("Unexpected or invalid packet:", p))
6750             raise
6751
6752         # from service back to client (both VRF1)
6753         p = (Ether(src=self.pg5.remote_mac, dst=self.pg5.local_mac) /
6754              IP(src=self.pg5.remote_ip4, dst=self.pg6.remote_ip4) /
6755              TCP(sport=local_port, dport=12345))
6756         self.pg5.add_stream(p)
6757         self.pg_enable_capture(self.pg_interfaces)
6758         self.pg_start()
6759         capture = self.pg6.get_capture(1)
6760         p = capture[0]
6761         try:
6762             ip = p[IP]
6763             tcp = p[TCP]
6764             self.assertEqual(ip.src, external_addr)
6765             self.assertEqual(tcp.sport, external_port)
6766             self.assert_packet_checksums_valid(p)
6767         except:
6768             self.logger.error(ppp("Unexpected or invalid packet:", p))
6769             raise
6770
6771         # dynamic NAT from VRF1 to VRF0 (output-feature)
6772         p = (Ether(src=self.pg5.remote_mac, dst=self.pg5.local_mac) /
6773              IP(src=self.pg5.remote_ip4, dst=self.pg1.remote_ip4) /
6774              TCP(sport=2345, dport=22))
6775         self.pg5.add_stream(p)
6776         self.pg_enable_capture(self.pg_interfaces)
6777         self.pg_start()
6778         capture = self.pg1.get_capture(1)
6779         p = capture[0]
6780         try:
6781             ip = p[IP]
6782             tcp = p[TCP]
6783             self.assertEqual(ip.src, self.nat_addr)
6784             self.assert_packet_checksums_valid(p)
6785             port = tcp.sport
6786         except:
6787             self.logger.error(ppp("Unexpected or invalid packet:", p))
6788             raise
6789
6790         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
6791              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
6792              TCP(sport=22, dport=port))
6793         self.pg1.add_stream(p)
6794         self.pg_enable_capture(self.pg_interfaces)
6795         self.pg_start()
6796         capture = self.pg5.get_capture(1)
6797         p = capture[0]
6798         try:
6799             ip = p[IP]
6800             tcp = p[TCP]
6801             self.assertEqual(ip.dst, self.pg5.remote_ip4)
6802             self.assertEqual(tcp.dport, 2345)
6803             self.assert_packet_checksums_valid(p)
6804         except:
6805             self.logger.error(ppp("Unexpected or invalid packet:", p))
6806             raise
6807
6808         # from client VRF1 to service VRF0
6809         p = (Ether(src=self.pg6.remote_mac, dst=self.pg6.local_mac) /
6810              IP(src=self.pg6.remote_ip4, dst=self.pg0.local_ip4) /
6811              TCP(sport=12346, dport=external_port))
6812         self.pg6.add_stream(p)
6813         self.pg_enable_capture(self.pg_interfaces)
6814         self.pg_start()
6815         capture = self.pg0.get_capture(1)
6816         p = capture[0]
6817         try:
6818             ip = p[IP]
6819             tcp = p[TCP]
6820             self.assertEqual(ip.dst, self.pg0.remote_ip4)
6821             self.assertEqual(tcp.dport, local_port)
6822             self.assert_packet_checksums_valid(p)
6823         except:
6824             self.logger.error(ppp("Unexpected or invalid packet:", p))
6825             raise
6826
6827         # from service VRF0 back to client VRF1
6828         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6829              IP(src=self.pg0.remote_ip4, dst=self.pg6.remote_ip4) /
6830              TCP(sport=local_port, dport=12346))
6831         self.pg0.add_stream(p)
6832         self.pg_enable_capture(self.pg_interfaces)
6833         self.pg_start()
6834         capture = self.pg6.get_capture(1)
6835         p = capture[0]
6836         try:
6837             ip = p[IP]
6838             tcp = p[TCP]
6839             self.assertEqual(ip.src, self.pg0.local_ip4)
6840             self.assertEqual(tcp.sport, external_port)
6841             self.assert_packet_checksums_valid(p)
6842         except:
6843             self.logger.error(ppp("Unexpected or invalid packet:", p))
6844             raise
6845
6846         # from client VRF0 to service VRF1
6847         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6848              IP(src=self.pg0.remote_ip4, dst=external_addr) /
6849              TCP(sport=12347, dport=external_port))
6850         self.pg0.add_stream(p)
6851         self.pg_enable_capture(self.pg_interfaces)
6852         self.pg_start()
6853         capture = self.pg5.get_capture(1)
6854         p = capture[0]
6855         try:
6856             ip = p[IP]
6857             tcp = p[TCP]
6858             self.assertEqual(ip.dst, self.pg5.remote_ip4)
6859             self.assertEqual(tcp.dport, local_port)
6860             self.assert_packet_checksums_valid(p)
6861         except:
6862             self.logger.error(ppp("Unexpected or invalid packet:", p))
6863             raise
6864
6865         # from service VRF1 back to client VRF0
6866         p = (Ether(src=self.pg5.remote_mac, dst=self.pg5.local_mac) /
6867              IP(src=self.pg5.remote_ip4, dst=self.pg0.remote_ip4) /
6868              TCP(sport=local_port, dport=12347))
6869         self.pg5.add_stream(p)
6870         self.pg_enable_capture(self.pg_interfaces)
6871         self.pg_start()
6872         capture = self.pg0.get_capture(1)
6873         p = capture[0]
6874         try:
6875             ip = p[IP]
6876             tcp = p[TCP]
6877             self.assertEqual(ip.src, external_addr)
6878             self.assertEqual(tcp.sport, external_port)
6879             self.assert_packet_checksums_valid(p)
6880         except:
6881             self.logger.error(ppp("Unexpected or invalid packet:", p))
6882             raise
6883
6884         # from client to server (both VRF1, no translation)
6885         p = (Ether(src=self.pg6.remote_mac, dst=self.pg6.local_mac) /
6886              IP(src=self.pg6.remote_ip4, dst=self.pg5.remote_ip4) /
6887              TCP(sport=12348, dport=local_port))
6888         self.pg6.add_stream(p)
6889         self.pg_enable_capture(self.pg_interfaces)
6890         self.pg_start()
6891         capture = self.pg5.get_capture(1)
6892         p = capture[0]
6893         try:
6894             ip = p[IP]
6895             tcp = p[TCP]
6896             self.assertEqual(ip.dst, self.pg5.remote_ip4)
6897             self.assertEqual(tcp.dport, local_port)
6898             self.assert_packet_checksums_valid(p)
6899         except:
6900             self.logger.error(ppp("Unexpected or invalid packet:", p))
6901             raise
6902
6903         # from server back to client (both VRF1, no translation)
6904         p = (Ether(src=self.pg5.remote_mac, dst=self.pg5.local_mac) /
6905              IP(src=self.pg5.remote_ip4, dst=self.pg6.remote_ip4) /
6906              TCP(sport=local_port, dport=12348))
6907         self.pg5.add_stream(p)
6908         self.pg_enable_capture(self.pg_interfaces)
6909         self.pg_start()
6910         capture = self.pg6.get_capture(1)
6911         p = capture[0]
6912         try:
6913             ip = p[IP]
6914             tcp = p[TCP]
6915             self.assertEqual(ip.src, self.pg5.remote_ip4)
6916             self.assertEqual(tcp.sport, local_port)
6917             self.assert_packet_checksums_valid(p)
6918         except:
6919             self.logger.error(ppp("Unexpected or invalid packet:", p))
6920             raise
6921
6922         # from client VRF1 to server VRF0 (no translation)
6923         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6924              IP(src=self.pg0.remote_ip4, dst=self.pg6.remote_ip4) /
6925              TCP(sport=local_port, dport=12349))
6926         self.pg0.add_stream(p)
6927         self.pg_enable_capture(self.pg_interfaces)
6928         self.pg_start()
6929         capture = self.pg6.get_capture(1)
6930         p = capture[0]
6931         try:
6932             ip = p[IP]
6933             tcp = p[TCP]
6934             self.assertEqual(ip.src, self.pg0.remote_ip4)
6935             self.assertEqual(tcp.sport, local_port)
6936             self.assert_packet_checksums_valid(p)
6937         except:
6938             self.logger.error(ppp("Unexpected or invalid packet:", p))
6939             raise
6940
6941         # from server VRF0 back to client VRF1 (no translation)
6942         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6943              IP(src=self.pg0.remote_ip4, dst=self.pg6.remote_ip4) /
6944              TCP(sport=local_port, dport=12349))
6945         self.pg0.add_stream(p)
6946         self.pg_enable_capture(self.pg_interfaces)
6947         self.pg_start()
6948         capture = self.pg6.get_capture(1)
6949         p = capture[0]
6950         try:
6951             ip = p[IP]
6952             tcp = p[TCP]
6953             self.assertEqual(ip.src, self.pg0.remote_ip4)
6954             self.assertEqual(tcp.sport, local_port)
6955             self.assert_packet_checksums_valid(p)
6956         except:
6957             self.logger.error(ppp("Unexpected or invalid packet:", p))
6958             raise
6959
6960         # from client VRF0 to server VRF1 (no translation)
6961         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6962              IP(src=self.pg0.remote_ip4, dst=self.pg5.remote_ip4) /
6963              TCP(sport=12344, dport=local_port))
6964         self.pg0.add_stream(p)
6965         self.pg_enable_capture(self.pg_interfaces)
6966         self.pg_start()
6967         capture = self.pg5.get_capture(1)
6968         p = capture[0]
6969         try:
6970             ip = p[IP]
6971             tcp = p[TCP]
6972             self.assertEqual(ip.dst, self.pg5.remote_ip4)
6973             self.assertEqual(tcp.dport, local_port)
6974             self.assert_packet_checksums_valid(p)
6975         except:
6976             self.logger.error(ppp("Unexpected or invalid packet:", p))
6977             raise
6978
6979         # from server VRF1 back to client VRF0 (no translation)
6980         p = (Ether(src=self.pg5.remote_mac, dst=self.pg5.local_mac) /
6981              IP(src=self.pg5.remote_ip4, dst=self.pg0.remote_ip4) /
6982              TCP(sport=local_port, dport=12344))
6983         self.pg5.add_stream(p)
6984         self.pg_enable_capture(self.pg_interfaces)
6985         self.pg_start()
6986         capture = self.pg0.get_capture(1)
6987         p = capture[0]
6988         try:
6989             ip = p[IP]
6990             tcp = p[TCP]
6991             self.assertEqual(ip.src, self.pg5.remote_ip4)
6992             self.assertEqual(tcp.sport, local_port)
6993             self.assert_packet_checksums_valid(p)
6994         except:
6995             self.logger.error(ppp("Unexpected or invalid packet:", p))
6996             raise
6997
6998     @unittest.skipUnless(running_extended_tests, "part of extended tests")
6999     def test_session_timeout(self):
7000         """ NAT44 session timeouts """
7001         self.nat44_add_address(self.nat_addr)
7002         flags = self.config_flags.NAT_IS_INSIDE
7003         self.vapi.nat44_interface_add_del_feature(
7004             sw_if_index=self.pg0.sw_if_index,
7005             flags=flags, is_add=1)
7006         self.vapi.nat44_interface_add_del_feature(
7007             sw_if_index=self.pg1.sw_if_index,
7008             is_add=1)
7009         self.vapi.nat_set_timeouts(udp=300, tcp_established=7440,
7010                                    tcp_transitory=240, icmp=5)
7011
7012         max_sessions = 1000
7013         pkts = []
7014         for i in range(0, max_sessions):
7015             src = "10.10.%u.%u" % ((i & 0xFF00) >> 8, i & 0xFF)
7016             p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
7017                  IP(src=src, dst=self.pg1.remote_ip4) /
7018                  ICMP(id=1025, type='echo-request'))
7019             pkts.append(p)
7020         self.pg0.add_stream(pkts)
7021         self.pg_enable_capture(self.pg_interfaces)
7022         self.pg_start()
7023         self.pg1.get_capture(max_sessions)
7024
7025         sleep(10)
7026
7027         pkts = []
7028         for i in range(0, max_sessions):
7029             src = "10.11.%u.%u" % ((i & 0xFF00) >> 8, i & 0xFF)
7030             p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
7031                  IP(src=src, dst=self.pg1.remote_ip4) /
7032                  ICMP(id=1026, type='echo-request'))
7033             pkts.append(p)
7034         self.pg0.add_stream(pkts)
7035         self.pg_enable_capture(self.pg_interfaces)
7036         self.pg_start()
7037         self.pg1.get_capture(max_sessions)
7038
7039         nsessions = 0
7040         users = self.vapi.nat44_user_dump()
7041         for user in users:
7042             nsessions = nsessions + user.nsessions
7043         self.assertLess(nsessions, 2 * max_sessions)
7044
7045     @unittest.skipUnless(running_extended_tests, "part of extended tests")
7046     def test_session_rst_timeout(self):
7047         """ NAT44 session RST timeouts """
7048         self.nat44_add_address(self.nat_addr)
7049         flags = self.config_flags.NAT_IS_INSIDE
7050         self.vapi.nat44_interface_add_del_feature(
7051             sw_if_index=self.pg0.sw_if_index,
7052             flags=flags, is_add=1)
7053         self.vapi.nat44_interface_add_del_feature(
7054             sw_if_index=self.pg1.sw_if_index,
7055             is_add=1)
7056         self.vapi.nat_set_timeouts(udp=300, tcp_established=7440,
7057                                    tcp_transitory=5, icmp=60)
7058
7059         self.initiate_tcp_session(self.pg0, self.pg1)
7060         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
7061              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
7062              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
7063                  flags="R"))
7064         self.pg0.add_stream(p)
7065         self.pg_enable_capture(self.pg_interfaces)
7066         self.pg_start()
7067         self.pg1.get_capture(1)
7068
7069         sleep(6)
7070
7071         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
7072              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
7073              TCP(sport=self.tcp_port_in + 1, dport=self.tcp_external_port + 1,
7074                  flags="S"))
7075         self.pg0.add_stream(p)
7076         self.pg_enable_capture(self.pg_interfaces)
7077         self.pg_start()
7078         self.pg1.get_capture(1)
7079
7080     def test_syslog_sess(self):
7081         """ Test syslog session creation and deletion """
7082         self.vapi.syslog_set_filter(
7083             self.SYSLOG_SEVERITY.SYSLOG_API_SEVERITY_INFO)
7084         self.vapi.syslog_set_sender(self.pg2.local_ip4, self.pg2.remote_ip4)
7085         self.nat44_add_address(self.nat_addr)
7086         flags = self.config_flags.NAT_IS_INSIDE
7087         self.vapi.nat44_interface_add_del_feature(
7088             sw_if_index=self.pg0.sw_if_index,
7089             flags=flags, is_add=1)
7090         self.vapi.nat44_interface_add_del_feature(
7091             sw_if_index=self.pg1.sw_if_index,
7092             is_add=1)
7093
7094         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
7095              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
7096              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port))
7097         self.pg0.add_stream(p)
7098         self.pg_enable_capture(self.pg_interfaces)
7099         self.pg_start()
7100         capture = self.pg1.get_capture(1)
7101         self.tcp_port_out = capture[0][TCP].sport
7102         capture = self.pg2.get_capture(1)
7103         self.verify_syslog_sess(capture[0][Raw].load)
7104
7105         self.pg_enable_capture(self.pg_interfaces)
7106         self.pg_start()
7107         self.nat44_add_address(self.nat_addr, is_add=0)
7108         capture = self.pg2.get_capture(1)
7109         self.verify_syslog_sess(capture[0][Raw].load, False)
7110
7111     def test_ed_users_dump(self):
7112         """ API test - nat44_user_dump """
7113         flags = self.config_flags.NAT_IS_INSIDE
7114         self.vapi.nat44_interface_add_del_feature(
7115             sw_if_index=self.pg0.sw_if_index,
7116             flags=flags, is_add=1)
7117         self.vapi.nat44_interface_add_del_feature(
7118             sw_if_index=self.pg1.sw_if_index,
7119             is_add=1)
7120         self.vapi.nat44_forwarding_enable_disable(enable=1)
7121
7122         real_ip = self.pg0.remote_ip4
7123         alias_ip = self.nat_addr
7124         flags = self.config_flags.NAT_IS_ADDR_ONLY
7125         self.vapi.nat44_add_del_static_mapping(is_add=1,
7126                                                local_ip_address=real_ip,
7127                                                external_ip_address=alias_ip,
7128                                                external_sw_if_index=0xFFFFFFFF,
7129                                                flags=flags)
7130
7131         users = self.vapi.nat44_user_dump()
7132         self.assertEqual(len(users), 0)
7133         try:
7134             # in2out - static mapping match
7135
7136             pkts = self.create_stream_out(self.pg1)
7137             self.pg1.add_stream(pkts)
7138             self.pg_enable_capture(self.pg_interfaces)
7139             self.pg_start()
7140             capture = self.pg0.get_capture(len(pkts))
7141             self.verify_capture_in(capture, self.pg0)
7142
7143             pkts = self.create_stream_in(self.pg0, self.pg1)
7144             self.pg0.add_stream(pkts)
7145             self.pg_enable_capture(self.pg_interfaces)
7146             self.pg_start()
7147             capture = self.pg1.get_capture(len(pkts))
7148             self.verify_capture_out(capture, same_port=True)
7149
7150             users = self.vapi.nat44_user_dump()
7151             self.assertEqual(len(users), 1)
7152             static_user = users[0]
7153             self.assertEqual(static_user.nstaticsessions, 3)
7154             self.assertEqual(static_user.nsessions, 0)
7155
7156             # in2out - no static mapping match
7157
7158             host0 = self.pg0.remote_hosts[0]
7159             self.pg0.remote_hosts[0] = self.pg0.remote_hosts[1]
7160             try:
7161                 pkts = self.create_stream_out(self.pg1,
7162                                               dst_ip=self.pg0.remote_ip4,
7163                                               use_inside_ports=True)
7164                 self.pg1.add_stream(pkts)
7165                 self.pg_enable_capture(self.pg_interfaces)
7166                 self.pg_start()
7167                 capture = self.pg0.get_capture(len(pkts))
7168                 self.verify_capture_in(capture, self.pg0)
7169
7170                 pkts = self.create_stream_in(self.pg0, self.pg1)
7171                 self.pg0.add_stream(pkts)
7172                 self.pg_enable_capture(self.pg_interfaces)
7173                 self.pg_start()
7174                 capture = self.pg1.get_capture(len(pkts))
7175                 self.verify_capture_out(capture, nat_ip=self.pg0.remote_ip4,
7176                                         same_port=True)
7177             finally:
7178                 self.pg0.remote_hosts[0] = host0
7179
7180             users = self.vapi.nat44_user_dump()
7181             self.assertEqual(len(users), 2)
7182             if str(users[0].ip_address) == self.pg0.remote_hosts[0].ip4:
7183                 non_static_user = users[1]
7184                 static_user = users[0]
7185             else:
7186                 non_static_user = users[0]
7187                 static_user = users[1]
7188             self.assertEqual(static_user.nstaticsessions, 3)
7189             self.assertEqual(static_user.nsessions, 0)
7190             self.assertEqual(non_static_user.nstaticsessions, 0)
7191             self.assertEqual(non_static_user.nsessions, 3)
7192
7193             users = self.vapi.nat44_user_dump()
7194             self.assertEqual(len(users), 2)
7195             if str(users[0].ip_address) == self.pg0.remote_hosts[0].ip4:
7196                 non_static_user = users[1]
7197                 static_user = users[0]
7198             else:
7199                 non_static_user = users[0]
7200                 static_user = users[1]
7201             self.assertEqual(static_user.nstaticsessions, 3)
7202             self.assertEqual(static_user.nsessions, 0)
7203             self.assertEqual(non_static_user.nstaticsessions, 0)
7204             self.assertEqual(non_static_user.nsessions, 3)
7205
7206         finally:
7207             self.vapi.nat44_forwarding_enable_disable(enable=0)
7208             flags = self.config_flags.NAT_IS_ADDR_ONLY
7209             self.vapi.nat44_add_del_static_mapping(
7210                 is_add=0,
7211                 local_ip_address=real_ip,
7212                 external_ip_address=alias_ip,
7213                 external_sw_if_index=0xFFFFFFFF,
7214                 flags=flags)
7215
7216     def tearDown(self):
7217         super(TestNAT44EndpointDependent, self).tearDown()
7218         if not self.vpp_dead:
7219             self.clear_nat44()
7220             self.vapi.cli("clear logging")
7221
7222     def show_commands_at_teardown(self):
7223         self.logger.info(self.vapi.cli("show nat44 addresses"))
7224         self.logger.info(self.vapi.cli("show nat44 interfaces"))
7225         self.logger.info(self.vapi.cli("show nat44 static mappings"))
7226         self.logger.info(self.vapi.cli("show nat44 interface address"))
7227         self.logger.info(self.vapi.cli("show nat44 sessions detail"))
7228         self.logger.info(self.vapi.cli("show nat44 hash tables detail"))
7229         self.logger.info(self.vapi.cli("show nat timeouts"))
7230
7231
7232 class TestNAT44EndpointDependent3(MethodHolder):
7233     """ Endpoint-Dependent mapping and filtering extra test cases """
7234
7235     max_translations = 50
7236
7237     @classmethod
7238     def setUpConstants(cls):
7239         super(TestNAT44EndpointDependent3, cls).setUpConstants()
7240         cls.vpp_cmdline.extend([
7241             "nat", "{", "endpoint-dependent",
7242             "max translations per thread %d" % cls.max_translations,
7243             "}"
7244         ])
7245
7246     @classmethod
7247     def setUpClass(cls):
7248         super(TestNAT44EndpointDependent3, cls).setUpClass()
7249         cls.vapi.cli("set log class nat level debug")
7250
7251         cls.nat_addr = '10.0.0.3'
7252
7253         cls.create_pg_interfaces(range(2))
7254
7255         for i in cls.pg_interfaces:
7256             i.admin_up()
7257             i.config_ip4()
7258             i.resolve_arp()
7259
7260     def setUp(self):
7261         super(TestNAT44EndpointDependent3, self).setUp()
7262         self.vapi.nat_set_timeouts(
7263             udp=1, tcp_established=7440, tcp_transitory=30, icmp=1)
7264         self.nat44_add_address(self.nat_addr)
7265         flags = self.config_flags.NAT_IS_INSIDE
7266         self.vapi.nat44_interface_add_del_feature(
7267             sw_if_index=self.pg0.sw_if_index, flags=flags, is_add=1)
7268         self.vapi.nat44_interface_add_del_feature(
7269             sw_if_index=self.pg1.sw_if_index, is_add=1)
7270
7271     @classmethod
7272     def tearDownClass(cls):
7273         super(TestNAT44EndpointDependent3, cls).tearDownClass()
7274
7275     def init_tcp_session(self, in_if, out_if, sport, ext_dport):
7276         # SYN packet in->out
7277         p = (Ether(src=in_if.remote_mac, dst=in_if.local_mac) /
7278              IP(src=in_if.remote_ip4, dst=out_if.remote_ip4) /
7279              TCP(sport=sport, dport=ext_dport, flags="S"))
7280         in_if.add_stream(p)
7281         self.pg_enable_capture(self.pg_interfaces)
7282         self.pg_start()
7283         capture = out_if.get_capture(1)
7284         p = capture[0]
7285         tcp_port_out = p[TCP].sport
7286
7287         # SYN + ACK packet out->in
7288         p = (Ether(src=out_if.remote_mac, dst=out_if.local_mac) /
7289              IP(src=out_if.remote_ip4, dst=self.nat_addr) /
7290              TCP(sport=ext_dport, dport=tcp_port_out, flags="SA"))
7291         out_if.add_stream(p)
7292         self.pg_enable_capture(self.pg_interfaces)
7293         self.pg_start()
7294         in_if.get_capture(1)
7295
7296         # ACK packet in->out
7297         p = (Ether(src=in_if.remote_mac, dst=in_if.local_mac) /
7298              IP(src=in_if.remote_ip4, dst=out_if.remote_ip4) /
7299              TCP(sport=sport, dport=ext_dport, flags="A"))
7300         in_if.add_stream(p)
7301         self.pg_enable_capture(self.pg_interfaces)
7302         self.pg_start()
7303         out_if.get_capture(1)
7304
7305         return tcp_port_out
7306
7307     def test_lru_cleanup(self):
7308         """ LRU cleanup algorithm """
7309         tcp_port_out = self.init_tcp_session(self.pg0, self.pg1, 2000, 80)
7310         pkts = []
7311         for i in range(0, self.max_translations - 1):
7312             p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
7313                  IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4, ttl=64) /
7314                  UDP(sport=7000+i, dport=80))
7315             pkts.append(p)
7316
7317         self.pg0.add_stream(pkts)
7318         self.pg_enable_capture(self.pg_interfaces)
7319         self.pg_start()
7320         self.pg1.get_capture(len(pkts))
7321         self.sleep(1.5, "wait for timeouts")
7322
7323         pkts = []
7324         for i in range(0, self.max_translations - 1):
7325             p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
7326                  IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4, ttl=64) /
7327                  ICMP(id=8000+i, type='echo-request'))
7328             pkts.append(p)
7329
7330         self.pg0.add_stream(pkts)
7331         self.pg_enable_capture(self.pg_interfaces)
7332         self.pg_start()
7333         self.pg1.get_capture(len(pkts))
7334
7335
7336 class TestNAT44Out2InDPO(MethodHolder):
7337     """ NAT44 Test Cases using out2in DPO """
7338
7339     @classmethod
7340     def setUpConstants(cls):
7341         super(TestNAT44Out2InDPO, cls).setUpConstants()
7342         cls.vpp_cmdline.extend(["nat", "{", "out2in dpo", "}"])
7343
7344     @classmethod
7345     def setUpClass(cls):
7346         super(TestNAT44Out2InDPO, cls).setUpClass()
7347         cls.vapi.cli("set log class nat level debug")
7348
7349         cls.tcp_port_in = 6303
7350         cls.tcp_port_out = 6303
7351         cls.udp_port_in = 6304
7352         cls.udp_port_out = 6304
7353         cls.icmp_id_in = 6305
7354         cls.icmp_id_out = 6305
7355         cls.nat_addr = '10.0.0.3'
7356         cls.dst_ip4 = '192.168.70.1'
7357
7358         cls.create_pg_interfaces(range(2))
7359
7360         cls.pg0.admin_up()
7361         cls.pg0.config_ip4()
7362         cls.pg0.resolve_arp()
7363
7364         cls.pg1.admin_up()
7365         cls.pg1.config_ip6()
7366         cls.pg1.resolve_ndp()
7367
7368         r1 = VppIpRoute(cls, "::", 0,
7369                         [VppRoutePath(cls.pg1.remote_ip6,
7370                                       cls.pg1.sw_if_index)],
7371                         register=False)
7372         r1.add_vpp_config()
7373
7374     @classmethod
7375     def tearDownClass(cls):
7376         super(TestNAT44Out2InDPO, cls).tearDownClass()
7377
7378     def configure_xlat(self):
7379         self.dst_ip6_pfx = '1:2:3::'
7380         self.dst_ip6_pfx_n = socket.inet_pton(socket.AF_INET6,
7381                                               self.dst_ip6_pfx)
7382         self.dst_ip6_pfx_len = 96
7383         self.src_ip6_pfx = '4:5:6::'
7384         self.src_ip6_pfx_n = socket.inet_pton(socket.AF_INET6,
7385                                               self.src_ip6_pfx)
7386         self.src_ip6_pfx_len = 96
7387         self.vapi.map_add_domain(self.dst_ip6_pfx_n, self.dst_ip6_pfx_len,
7388                                  self.src_ip6_pfx_n, self.src_ip6_pfx_len,
7389                                  '\x00\x00\x00\x00', 0)
7390
7391     @unittest.skip('Temporary disabled')
7392     def test_464xlat_ce(self):
7393         """ Test 464XLAT CE with NAT44 """
7394
7395         nat_config = self.vapi.nat_show_config()
7396         self.assertEqual(1, nat_config.out2in_dpo)
7397
7398         self.configure_xlat()
7399
7400         flags = self.config_flags.NAT_IS_INSIDE
7401         self.vapi.nat44_interface_add_del_feature(
7402             sw_if_index=self.pg0.sw_if_index,
7403             flags=flags, is_add=1)
7404         self.vapi.nat44_add_del_address_range(first_ip_address=self.nat_addr_n,
7405                                               last_ip_address=self.nat_addr_n,
7406                                               vrf_id=0xFFFFFFFF, is_add=1)
7407
7408         out_src_ip6 = self.compose_ip6(self.dst_ip4, self.dst_ip6_pfx,
7409                                        self.dst_ip6_pfx_len)
7410         out_dst_ip6 = self.compose_ip6(self.nat_addr, self.src_ip6_pfx,
7411                                        self.src_ip6_pfx_len)
7412
7413         try:
7414             pkts = self.create_stream_in(self.pg0, self.pg1, self.dst_ip4)
7415             self.pg0.add_stream(pkts)
7416             self.pg_enable_capture(self.pg_interfaces)
7417             self.pg_start()
7418             capture = self.pg1.get_capture(len(pkts))
7419             self.verify_capture_out_ip6(capture, nat_ip=out_dst_ip6,
7420                                         dst_ip=out_src_ip6)
7421
7422             pkts = self.create_stream_out_ip6(self.pg1, out_src_ip6,
7423                                               out_dst_ip6)
7424             self.pg1.add_stream(pkts)
7425             self.pg_enable_capture(self.pg_interfaces)
7426             self.pg_start()
7427             capture = self.pg0.get_capture(len(pkts))
7428             self.verify_capture_in(capture, self.pg0)
7429         finally:
7430             self.vapi.nat44_interface_add_del_feature(
7431                 sw_if_index=self.pg0.sw_if_index,
7432                 flags=flags)
7433             self.vapi.nat44_add_del_address_range(
7434                 first_ip_address=self.nat_addr_n,
7435                 last_ip_address=self.nat_addr_n,
7436                 vrf_id=0xFFFFFFFF)
7437
7438     @unittest.skip('Temporary disabled')
7439     def test_464xlat_ce_no_nat(self):
7440         """ Test 464XLAT CE without NAT44 """
7441
7442         self.configure_xlat()
7443
7444         out_src_ip6 = self.compose_ip6(self.dst_ip4, self.dst_ip6_pfx,
7445                                        self.dst_ip6_pfx_len)
7446         out_dst_ip6 = self.compose_ip6(self.pg0.remote_ip4, self.src_ip6_pfx,
7447                                        self.src_ip6_pfx_len)
7448
7449         pkts = self.create_stream_in(self.pg0, self.pg1, self.dst_ip4)
7450         self.pg0.add_stream(pkts)
7451         self.pg_enable_capture(self.pg_interfaces)
7452         self.pg_start()
7453         capture = self.pg1.get_capture(len(pkts))
7454         self.verify_capture_out_ip6(capture, dst_ip=out_src_ip6,
7455                                     nat_ip=out_dst_ip6, same_port=True)
7456
7457         pkts = self.create_stream_out_ip6(self.pg1, out_src_ip6, out_dst_ip6)
7458         self.pg1.add_stream(pkts)
7459         self.pg_enable_capture(self.pg_interfaces)
7460         self.pg_start()
7461         capture = self.pg0.get_capture(len(pkts))
7462         self.verify_capture_in(capture, self.pg0)
7463
7464
7465 class TestDeterministicNAT(MethodHolder):
7466     """ Deterministic NAT Test Cases """
7467
7468     @classmethod
7469     def setUpConstants(cls):
7470         super(TestDeterministicNAT, cls).setUpConstants()
7471         cls.vpp_cmdline.extend(["nat", "{", "deterministic", "}"])
7472
7473     @classmethod
7474     def setUpClass(cls):
7475         super(TestDeterministicNAT, cls).setUpClass()
7476         cls.vapi.cli("set log class nat level debug")
7477
7478         cls.tcp_port_in = 6303
7479         cls.tcp_external_port = 6303
7480         cls.udp_port_in = 6304
7481         cls.udp_external_port = 6304
7482         cls.icmp_id_in = 6305
7483         cls.nat_addr = '10.0.0.3'
7484
7485         cls.create_pg_interfaces(range(3))
7486         cls.interfaces = list(cls.pg_interfaces)
7487
7488         for i in cls.interfaces:
7489             i.admin_up()
7490             i.config_ip4()
7491             i.resolve_arp()
7492
7493         cls.pg0.generate_remote_hosts(2)
7494         cls.pg0.configure_ipv4_neighbors()
7495
7496     @classmethod
7497     def tearDownClass(cls):
7498         super(TestDeterministicNAT, cls).tearDownClass()
7499
7500     def create_stream_in(self, in_if, out_if, ttl=64):
7501         """
7502         Create packet stream for inside network
7503
7504         :param in_if: Inside interface
7505         :param out_if: Outside interface
7506         :param ttl: TTL of generated packets
7507         """
7508         pkts = []
7509         # TCP
7510         p = (Ether(dst=in_if.local_mac, src=in_if.remote_mac) /
7511              IP(src=in_if.remote_ip4, dst=out_if.remote_ip4, ttl=ttl) /
7512              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port))
7513         pkts.append(p)
7514
7515         # UDP
7516         p = (Ether(dst=in_if.local_mac, src=in_if.remote_mac) /
7517              IP(src=in_if.remote_ip4, dst=out_if.remote_ip4, ttl=ttl) /
7518              UDP(sport=self.udp_port_in, dport=self.udp_external_port))
7519         pkts.append(p)
7520
7521         # ICMP
7522         p = (Ether(dst=in_if.local_mac, src=in_if.remote_mac) /
7523              IP(src=in_if.remote_ip4, dst=out_if.remote_ip4, ttl=ttl) /
7524              ICMP(id=self.icmp_id_in, type='echo-request'))
7525         pkts.append(p)
7526
7527         return pkts
7528
7529     def create_stream_out(self, out_if, dst_ip=None, ttl=64):
7530         """
7531         Create packet stream for outside network
7532
7533         :param out_if: Outside interface
7534         :param dst_ip: Destination IP address (Default use global NAT address)
7535         :param ttl: TTL of generated packets
7536         """
7537         if dst_ip is None:
7538             dst_ip = self.nat_addr
7539         pkts = []
7540         # TCP
7541         p = (Ether(dst=out_if.local_mac, src=out_if.remote_mac) /
7542              IP(src=out_if.remote_ip4, dst=dst_ip, ttl=ttl) /
7543              TCP(dport=self.tcp_port_out, sport=self.tcp_external_port))
7544         pkts.append(p)
7545
7546         # UDP
7547         p = (Ether(dst=out_if.local_mac, src=out_if.remote_mac) /
7548              IP(src=out_if.remote_ip4, dst=dst_ip, ttl=ttl) /
7549              UDP(dport=self.udp_port_out, sport=self.udp_external_port))
7550         pkts.append(p)
7551
7552         # ICMP
7553         p = (Ether(dst=out_if.local_mac, src=out_if.remote_mac) /
7554              IP(src=out_if.remote_ip4, dst=dst_ip, ttl=ttl) /
7555              ICMP(id=self.icmp_external_id, type='echo-reply'))
7556         pkts.append(p)
7557
7558         return pkts
7559
7560     def verify_capture_out(self, capture, nat_ip=None):
7561         """
7562         Verify captured packets on outside network
7563
7564         :param capture: Captured packets
7565         :param nat_ip: Translated IP address (Default use global NAT address)
7566         :param same_port: Source port number is not translated (Default False)
7567         """
7568         if nat_ip is None:
7569             nat_ip = self.nat_addr
7570         for packet in capture:
7571             try:
7572                 self.assertEqual(packet[IP].src, nat_ip)
7573                 if packet.haslayer(TCP):
7574                     self.tcp_port_out = packet[TCP].sport
7575                 elif packet.haslayer(UDP):
7576                     self.udp_port_out = packet[UDP].sport
7577                 else:
7578                     self.icmp_external_id = packet[ICMP].id
7579             except:
7580                 self.logger.error(ppp("Unexpected or invalid packet "
7581                                       "(outside network):", packet))
7582                 raise
7583
7584     def test_deterministic_mode(self):
7585         """ NAT plugin run deterministic mode """
7586         in_addr = '172.16.255.0'
7587         out_addr = '172.17.255.50'
7588         in_addr_t = '172.16.255.20'
7589         in_plen = 24
7590         out_plen = 32
7591
7592         nat_config = self.vapi.nat_show_config()
7593         self.assertEqual(1, nat_config.deterministic)
7594
7595         self.vapi.nat_det_add_del_map(is_add=1, in_addr=in_addr,
7596                                       in_plen=in_plen, out_addr=out_addr,
7597                                       out_plen=out_plen)
7598
7599         rep1 = self.vapi.nat_det_forward(in_addr_t)
7600         self.assertEqual(str(rep1.out_addr), out_addr)
7601         rep2 = self.vapi.nat_det_reverse(rep1.out_port_hi, out_addr)
7602
7603         self.assertEqual(str(rep2.in_addr), in_addr_t)
7604
7605         deterministic_mappings = self.vapi.nat_det_map_dump()
7606         self.assertEqual(len(deterministic_mappings), 1)
7607         dsm = deterministic_mappings[0]
7608         self.assertEqual(in_addr, str(dsm.in_addr))
7609         self.assertEqual(in_plen, dsm.in_plen)
7610         self.assertEqual(out_addr, str(dsm.out_addr))
7611         self.assertEqual(out_plen, dsm.out_plen)
7612
7613         self.clear_nat_det()
7614         deterministic_mappings = self.vapi.nat_det_map_dump()
7615         self.assertEqual(len(deterministic_mappings), 0)
7616
7617     def test_set_timeouts(self):
7618         """ Set deterministic NAT timeouts """
7619         timeouts_before = self.vapi.nat_get_timeouts()
7620
7621         self.vapi.nat_set_timeouts(
7622             udp=timeouts_before.udp + 10,
7623             tcp_established=timeouts_before.tcp_established + 10,
7624             tcp_transitory=timeouts_before.tcp_transitory + 10,
7625             icmp=timeouts_before.icmp + 10)
7626
7627         timeouts_after = self.vapi.nat_get_timeouts()
7628
7629         self.assertNotEqual(timeouts_before.udp, timeouts_after.udp)
7630         self.assertNotEqual(timeouts_before.icmp, timeouts_after.icmp)
7631         self.assertNotEqual(timeouts_before.tcp_established,
7632                             timeouts_after.tcp_established)
7633         self.assertNotEqual(timeouts_before.tcp_transitory,
7634                             timeouts_after.tcp_transitory)
7635
7636     def test_det_in(self):
7637         """ Deterministic NAT translation test (TCP, UDP, ICMP) """
7638
7639         nat_ip = "10.0.0.10"
7640
7641         self.vapi.nat_det_add_del_map(is_add=1, in_addr=self.pg0.remote_ip4,
7642                                       in_plen=32,
7643                                       out_addr=socket.inet_aton(nat_ip),
7644                                       out_plen=32)
7645
7646         flags = self.config_flags.NAT_IS_INSIDE
7647         self.vapi.nat44_interface_add_del_feature(
7648             sw_if_index=self.pg0.sw_if_index,
7649             flags=flags, is_add=1)
7650         self.vapi.nat44_interface_add_del_feature(
7651             sw_if_index=self.pg1.sw_if_index,
7652             is_add=1)
7653
7654         # in2out
7655         pkts = self.create_stream_in(self.pg0, self.pg1)
7656         self.pg0.add_stream(pkts)
7657         self.pg_enable_capture(self.pg_interfaces)
7658         self.pg_start()
7659         capture = self.pg1.get_capture(len(pkts))
7660         self.verify_capture_out(capture, nat_ip)
7661
7662         # out2in
7663         pkts = self.create_stream_out(self.pg1, nat_ip)
7664         self.pg1.add_stream(pkts)
7665         self.pg_enable_capture(self.pg_interfaces)
7666         self.pg_start()
7667         capture = self.pg0.get_capture(len(pkts))
7668         self.verify_capture_in(capture, self.pg0)
7669
7670         # session dump test
7671         sessions = self.vapi.nat_det_session_dump(self.pg0.remote_ip4)
7672         self.assertEqual(len(sessions), 3)
7673
7674         # TCP session
7675         s = sessions[0]
7676         self.assertEqual(str(s.ext_addr), self.pg1.remote_ip4)
7677         self.assertEqual(s.in_port, self.tcp_port_in)
7678         self.assertEqual(s.out_port, self.tcp_port_out)
7679         self.assertEqual(s.ext_port, self.tcp_external_port)
7680
7681         # UDP session
7682         s = sessions[1]
7683         self.assertEqual(str(s.ext_addr), self.pg1.remote_ip4)
7684         self.assertEqual(s.in_port, self.udp_port_in)
7685         self.assertEqual(s.out_port, self.udp_port_out)
7686         self.assertEqual(s.ext_port, self.udp_external_port)
7687
7688         # ICMP session
7689         s = sessions[2]
7690         self.assertEqual(str(s.ext_addr), self.pg1.remote_ip4)
7691         self.assertEqual(s.in_port, self.icmp_id_in)
7692         self.assertEqual(s.out_port, self.icmp_external_id)
7693
7694     def test_multiple_users(self):
7695         """ Deterministic NAT multiple users """
7696
7697         nat_ip = "10.0.0.10"
7698         port_in = 80
7699         external_port = 6303
7700
7701         host0 = self.pg0.remote_hosts[0]
7702         host1 = self.pg0.remote_hosts[1]
7703
7704         self.vapi.nat_det_add_del_map(is_add=1, in_addr=host0.ip4, in_plen=24,
7705                                       out_addr=socket.inet_aton(nat_ip),
7706                                       out_plen=32)
7707         flags = self.config_flags.NAT_IS_INSIDE
7708         self.vapi.nat44_interface_add_del_feature(
7709             sw_if_index=self.pg0.sw_if_index,
7710             flags=flags, is_add=1)
7711         self.vapi.nat44_interface_add_del_feature(
7712             sw_if_index=self.pg1.sw_if_index,
7713             is_add=1)
7714
7715         # host0 to out
7716         p = (Ether(src=host0.mac, dst=self.pg0.local_mac) /
7717              IP(src=host0.ip4, dst=self.pg1.remote_ip4) /
7718              TCP(sport=port_in, dport=external_port))
7719         self.pg0.add_stream(p)
7720         self.pg_enable_capture(self.pg_interfaces)
7721         self.pg_start()
7722         capture = self.pg1.get_capture(1)
7723         p = capture[0]
7724         try:
7725             ip = p[IP]
7726             tcp = p[TCP]
7727             self.assertEqual(ip.src, nat_ip)
7728             self.assertEqual(ip.dst, self.pg1.remote_ip4)
7729             self.assertEqual(tcp.dport, external_port)
7730             port_out0 = tcp.sport
7731         except:
7732             self.logger.error(ppp("Unexpected or invalid packet:", p))
7733             raise
7734
7735         # host1 to out
7736         p = (Ether(src=host1.mac, dst=self.pg0.local_mac) /
7737              IP(src=host1.ip4, dst=self.pg1.remote_ip4) /
7738              TCP(sport=port_in, dport=external_port))
7739         self.pg0.add_stream(p)
7740         self.pg_enable_capture(self.pg_interfaces)
7741         self.pg_start()
7742         capture = self.pg1.get_capture(1)
7743         p = capture[0]
7744         try:
7745             ip = p[IP]
7746             tcp = p[TCP]
7747             self.assertEqual(ip.src, nat_ip)
7748             self.assertEqual(ip.dst, self.pg1.remote_ip4)
7749             self.assertEqual(tcp.dport, external_port)
7750             port_out1 = tcp.sport
7751         except:
7752             self.logger.error(ppp("Unexpected or invalid packet:", p))
7753             raise
7754
7755         dms = self.vapi.nat_det_map_dump()
7756         self.assertEqual(1, len(dms))
7757         self.assertEqual(2, dms[0].ses_num)
7758
7759         # out to host0
7760         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
7761              IP(src=self.pg1.remote_ip4, dst=nat_ip) /
7762              TCP(sport=external_port, dport=port_out0))
7763         self.pg1.add_stream(p)
7764         self.pg_enable_capture(self.pg_interfaces)
7765         self.pg_start()
7766         capture = self.pg0.get_capture(1)
7767         p = capture[0]
7768         try:
7769             ip = p[IP]
7770             tcp = p[TCP]
7771             self.assertEqual(ip.src, self.pg1.remote_ip4)
7772             self.assertEqual(ip.dst, host0.ip4)
7773             self.assertEqual(tcp.dport, port_in)
7774             self.assertEqual(tcp.sport, external_port)
7775         except:
7776             self.logger.error(ppp("Unexpected or invalid packet:", p))
7777             raise
7778
7779         # out to host1
7780         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
7781              IP(src=self.pg1.remote_ip4, dst=nat_ip) /
7782              TCP(sport=external_port, dport=port_out1))
7783         self.pg1.add_stream(p)
7784         self.pg_enable_capture(self.pg_interfaces)
7785         self.pg_start()
7786         capture = self.pg0.get_capture(1)
7787         p = capture[0]
7788         try:
7789             ip = p[IP]
7790             tcp = p[TCP]
7791             self.assertEqual(ip.src, self.pg1.remote_ip4)
7792             self.assertEqual(ip.dst, host1.ip4)
7793             self.assertEqual(tcp.dport, port_in)
7794             self.assertEqual(tcp.sport, external_port)
7795         except:
7796             self.logger.error(ppp("Unexpected or invalid packet", p))
7797             raise
7798
7799         # session close api test
7800         self.vapi.nat_det_close_session_out(socket.inet_aton(nat_ip),
7801                                             port_out1,
7802                                             self.pg1.remote_ip4,
7803                                             external_port)
7804         dms = self.vapi.nat_det_map_dump()
7805         self.assertEqual(dms[0].ses_num, 1)
7806
7807         self.vapi.nat_det_close_session_in(host0.ip4,
7808                                            port_in,
7809                                            self.pg1.remote_ip4,
7810                                            external_port)
7811         dms = self.vapi.nat_det_map_dump()
7812         self.assertEqual(dms[0].ses_num, 0)
7813
7814     def test_tcp_session_close_detection_in(self):
7815         """ Deterministic NAT TCP session close from inside network """
7816         self.vapi.nat_det_add_del_map(is_add=1, in_addr=self.pg0.remote_ip4,
7817                                       in_plen=32,
7818                                       out_addr=socket.inet_aton(self.nat_addr),
7819                                       out_plen=32)
7820         flags = self.config_flags.NAT_IS_INSIDE
7821         self.vapi.nat44_interface_add_del_feature(
7822             sw_if_index=self.pg0.sw_if_index,
7823             flags=flags, is_add=1)
7824         self.vapi.nat44_interface_add_del_feature(
7825             sw_if_index=self.pg1.sw_if_index,
7826             is_add=1)
7827
7828         self.initiate_tcp_session(self.pg0, self.pg1)
7829
7830         # close the session from inside
7831         try:
7832             # FIN packet in -> out
7833             p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
7834                  IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
7835                  TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
7836                      flags="F"))
7837             self.pg0.add_stream(p)
7838             self.pg_enable_capture(self.pg_interfaces)
7839             self.pg_start()
7840             self.pg1.get_capture(1)
7841
7842             pkts = []
7843
7844             # ACK packet out -> in
7845             p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
7846                  IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
7847                  TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
7848                      flags="A"))
7849             pkts.append(p)
7850
7851             # FIN packet out -> in
7852             p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
7853                  IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
7854                  TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
7855                      flags="F"))
7856             pkts.append(p)
7857
7858             self.pg1.add_stream(pkts)
7859             self.pg_enable_capture(self.pg_interfaces)
7860             self.pg_start()
7861             self.pg0.get_capture(2)
7862
7863             # ACK packet in -> out
7864             p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
7865                  IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
7866                  TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
7867                      flags="A"))
7868             self.pg0.add_stream(p)
7869             self.pg_enable_capture(self.pg_interfaces)
7870             self.pg_start()
7871             self.pg1.get_capture(1)
7872
7873             # Check if deterministic NAT44 closed the session
7874             dms = self.vapi.nat_det_map_dump()
7875             self.assertEqual(0, dms[0].ses_num)
7876         except:
7877             self.logger.error("TCP session termination failed")
7878             raise
7879
7880     def test_tcp_session_close_detection_out(self):
7881         """ Deterministic NAT TCP session close from outside network """
7882         self.vapi.nat_det_add_del_map(is_add=1, in_addr=self.pg0.remote_ip4,
7883                                       in_plen=32,
7884                                       out_addr=socket.inet_aton(self.nat_addr),
7885                                       out_plen=32)
7886         flags = self.config_flags.NAT_IS_INSIDE
7887         self.vapi.nat44_interface_add_del_feature(
7888             sw_if_index=self.pg0.sw_if_index,
7889             flags=flags, is_add=1)
7890         self.vapi.nat44_interface_add_del_feature(
7891             sw_if_index=self.pg1.sw_if_index,
7892             is_add=1)
7893
7894         self.initiate_tcp_session(self.pg0, self.pg1)
7895
7896         # close the session from outside
7897         try:
7898             # FIN packet out -> in
7899             p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
7900                  IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
7901                  TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
7902                      flags="F"))
7903             self.pg1.add_stream(p)
7904             self.pg_enable_capture(self.pg_interfaces)
7905             self.pg_start()
7906             self.pg0.get_capture(1)
7907
7908             pkts = []
7909
7910             # ACK packet in -> out
7911             p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
7912                  IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
7913                  TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
7914                      flags="A"))
7915             pkts.append(p)
7916
7917             # ACK packet in -> out
7918             p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
7919                  IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
7920                  TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
7921                      flags="F"))
7922             pkts.append(p)
7923
7924             self.pg0.add_stream(pkts)
7925             self.pg_enable_capture(self.pg_interfaces)
7926             self.pg_start()
7927             self.pg1.get_capture(2)
7928
7929             # ACK packet out -> in
7930             p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
7931                  IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
7932                  TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
7933                      flags="A"))
7934             self.pg1.add_stream(p)
7935             self.pg_enable_capture(self.pg_interfaces)
7936             self.pg_start()
7937             self.pg0.get_capture(1)
7938
7939             # Check if deterministic NAT44 closed the session
7940             dms = self.vapi.nat_det_map_dump()
7941             self.assertEqual(0, dms[0].ses_num)
7942         except:
7943             self.logger.error("TCP session termination failed")
7944             raise
7945
7946     @unittest.skipUnless(running_extended_tests, "part of extended tests")
7947     def test_session_timeout(self):
7948         """ Deterministic NAT session timeouts """
7949         self.vapi.nat_det_add_del_map(is_add=1, in_addr=self.pg0.remote_ip4,
7950                                       in_plen=32,
7951                                       out_addr=socket.inet_aton(self.nat_addr),
7952                                       out_plen=32)
7953         flags = self.config_flags.NAT_IS_INSIDE
7954         self.vapi.nat44_interface_add_del_feature(
7955             sw_if_index=self.pg0.sw_if_index,
7956             flags=flags, is_add=1)
7957         self.vapi.nat44_interface_add_del_feature(
7958             sw_if_index=self.pg1.sw_if_index,
7959             is_add=1)
7960
7961         self.initiate_tcp_session(self.pg0, self.pg1)
7962         self.vapi.nat_set_timeouts(udp=5, tcp_established=5, tcp_transitory=5,
7963                                    icmp=5)
7964         pkts = self.create_stream_in(self.pg0, self.pg1)
7965         self.pg0.add_stream(pkts)
7966         self.pg_enable_capture(self.pg_interfaces)
7967         self.pg_start()
7968         capture = self.pg1.get_capture(len(pkts))
7969         sleep(15)
7970
7971         dms = self.vapi.nat_det_map_dump()
7972         self.assertEqual(0, dms[0].ses_num)
7973
7974     @unittest.skipUnless(running_extended_tests, "part of extended tests")
7975     def test_session_limit_per_user(self):
7976         """ Deterministic NAT maximum sessions per user limit """
7977         self.vapi.nat_det_add_del_map(is_add=1, in_addr=self.pg0.remote_ip4,
7978                                       in_plen=32,
7979                                       out_addr=socket.inet_aton(self.nat_addr),
7980                                       out_plen=32)
7981         flags = self.config_flags.NAT_IS_INSIDE
7982         self.vapi.nat44_interface_add_del_feature(
7983             sw_if_index=self.pg0.sw_if_index,
7984             flags=flags, is_add=1)
7985         self.vapi.nat44_interface_add_del_feature(
7986             sw_if_index=self.pg1.sw_if_index,
7987             is_add=1)
7988         self.vapi.set_ipfix_exporter(collector_address=self.pg2.remote_ip4,
7989                                      src_address=self.pg2.local_ip4,
7990                                      path_mtu=512,
7991                                      template_interval=10)
7992         self.vapi.nat_ipfix_enable_disable(domain_id=1, src_port=4739,
7993                                            enable=1)
7994
7995         pkts = []
7996         for port in range(1025, 2025):
7997             p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
7998                  IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
7999                  UDP(sport=port, dport=port))
8000             pkts.append(p)
8001
8002         self.pg0.add_stream(pkts)
8003         self.pg_enable_capture(self.pg_interfaces)
8004         self.pg_start()
8005         capture = self.pg1.get_capture(len(pkts))
8006
8007         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
8008              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
8009              UDP(sport=3001, dport=3002))
8010         self.pg0.add_stream(p)
8011         self.pg_enable_capture(self.pg_interfaces)
8012         self.pg_start()
8013         capture = self.pg1.assert_nothing_captured()
8014
8015         # verify ICMP error packet
8016         capture = self.pg0.get_capture(1)
8017         p = capture[0]
8018         self.assertTrue(p.haslayer(ICMP))
8019         icmp = p[ICMP]
8020         self.assertEqual(icmp.type, 3)
8021         self.assertEqual(icmp.code, 1)
8022         self.assertTrue(icmp.haslayer(IPerror))
8023         inner_ip = icmp[IPerror]
8024         self.assertEqual(inner_ip[UDPerror].sport, 3001)
8025         self.assertEqual(inner_ip[UDPerror].dport, 3002)
8026
8027         dms = self.vapi.nat_det_map_dump()
8028
8029         self.assertEqual(1000, dms[0].ses_num)
8030
8031         # verify IPFIX logging
8032         self.vapi.ipfix_flush()
8033         sleep(1)
8034         capture = self.pg2.get_capture(2)
8035         ipfix = IPFIXDecoder()
8036         # first load template
8037         for p in capture:
8038             self.assertTrue(p.haslayer(IPFIX))
8039             if p.haslayer(Template):
8040                 ipfix.add_template(p.getlayer(Template))
8041         # verify events in data set
8042         for p in capture:
8043             if p.haslayer(Data):
8044                 data = ipfix.decode_data_set(p.getlayer(Set))
8045                 self.verify_ipfix_max_entries_per_user(data,
8046                                                        1000,
8047                                                        self.pg0.remote_ip4)
8048
8049     def clear_nat_det(self):
8050         """
8051         Clear deterministic NAT configuration.
8052         """
8053         self.vapi.nat_ipfix_enable_disable(domain_id=1, src_port=4739,
8054                                            enable=0)
8055         self.vapi.nat_set_timeouts(udp=300, tcp_established=7440,
8056                                    tcp_transitory=240, icmp=60)
8057         deterministic_mappings = self.vapi.nat_det_map_dump()
8058         for dsm in deterministic_mappings:
8059             self.vapi.nat_det_add_del_map(is_add=0, in_addr=dsm.in_addr,
8060                                           in_plen=dsm.in_plen,
8061                                           out_addr=dsm.out_addr,
8062                                           out_plen=dsm.out_plen)
8063
8064         interfaces = self.vapi.nat44_interface_dump()
8065         for intf in interfaces:
8066             self.vapi.nat44_interface_add_del_feature(
8067                 sw_if_index=intf.sw_if_index,
8068                 flags=intf.flags)
8069
8070     def tearDown(self):
8071         super(TestDeterministicNAT, self).tearDown()
8072         if not self.vpp_dead:
8073             self.clear_nat_det()
8074
8075     def show_commands_at_teardown(self):
8076         self.logger.info(self.vapi.cli("show nat44 interfaces"))
8077         self.logger.info(self.vapi.cli("show nat timeouts"))
8078         self.logger.info(
8079             self.vapi.cli("show nat44 deterministic mappings"))
8080         self.logger.info(
8081             self.vapi.cli("show nat44 deterministic sessions"))
8082
8083
8084 class TestNAT64(MethodHolder):
8085     """ NAT64 Test Cases """
8086
8087     @classmethod
8088     def setUpConstants(cls):
8089         super(TestNAT64, cls).setUpConstants()
8090         cls.vpp_cmdline.extend(["nat", "{", "nat64 bib hash buckets 128",
8091                                 "nat64 st hash buckets 256", "}"])
8092
8093     @classmethod
8094     def setUpClass(cls):
8095         super(TestNAT64, cls).setUpClass()
8096
8097         cls.tcp_port_in = 6303
8098         cls.tcp_port_out = 6303
8099         cls.udp_port_in = 6304
8100         cls.udp_port_out = 6304
8101         cls.icmp_id_in = 6305
8102         cls.icmp_id_out = 6305
8103         cls.tcp_external_port = 80
8104         cls.nat_addr = '10.0.0.3'
8105         cls.nat_addr_n = socket.inet_pton(socket.AF_INET, cls.nat_addr)
8106         cls.vrf1_id = 10
8107         cls.vrf1_nat_addr = '10.0.10.3'
8108         cls.ipfix_src_port = 4739
8109         cls.ipfix_domain_id = 1
8110
8111         cls.create_pg_interfaces(range(6))
8112         cls.ip6_interfaces = list(cls.pg_interfaces[0:1])
8113         cls.ip6_interfaces.append(cls.pg_interfaces[2])
8114         cls.ip4_interfaces = list(cls.pg_interfaces[1:2])
8115
8116         cls.vapi.ip_table_add_del(is_add=1,
8117                                   table={'table_id': cls.vrf1_id,
8118                                          'is_ip6': 1})
8119
8120         cls.pg_interfaces[2].set_table_ip6(cls.vrf1_id)
8121
8122         cls.pg0.generate_remote_hosts(2)
8123
8124         for i in cls.ip6_interfaces:
8125             i.admin_up()
8126             i.config_ip6()
8127             i.configure_ipv6_neighbors()
8128
8129         for i in cls.ip4_interfaces:
8130             i.admin_up()
8131             i.config_ip4()
8132             i.resolve_arp()
8133
8134         cls.pg3.admin_up()
8135         cls.pg3.config_ip4()
8136         cls.pg3.resolve_arp()
8137         cls.pg3.config_ip6()
8138         cls.pg3.configure_ipv6_neighbors()
8139
8140         cls.pg5.admin_up()
8141         cls.pg5.config_ip6()
8142
8143     @classmethod
8144     def tearDownClass(cls):
8145         super(TestNAT64, cls).tearDownClass()
8146
8147     def test_nat64_inside_interface_handles_neighbor_advertisement(self):
8148         """ NAT64 inside interface handles Neighbor Advertisement """
8149
8150         flags = self.config_flags.NAT_IS_INSIDE
8151         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
8152                                           sw_if_index=self.pg5.sw_if_index)
8153
8154         # Try to send ping
8155         ping = (Ether(dst=self.pg5.local_mac, src=self.pg5.remote_mac) /
8156                 IPv6(src=self.pg5.remote_ip6, dst=self.pg5.local_ip6) /
8157                 ICMPv6EchoRequest())
8158         pkts = [ping]
8159         self.pg5.add_stream(pkts)
8160         self.pg_enable_capture(self.pg_interfaces)
8161         self.pg_start()
8162
8163         # Wait for Neighbor Solicitation
8164         capture = self.pg5.get_capture(len(pkts))
8165         packet = capture[0]
8166         try:
8167             self.assertEqual(packet[IPv6].src, self.pg5.local_ip6)
8168             self.assertEqual(packet.haslayer(ICMPv6ND_NS), 1)
8169             tgt = packet[ICMPv6ND_NS].tgt
8170         except:
8171             self.logger.error(ppp("Unexpected or invalid packet:", packet))
8172             raise
8173
8174         # Send Neighbor Advertisement
8175         p = (Ether(dst=self.pg5.local_mac, src=self.pg5.remote_mac) /
8176              IPv6(src=self.pg5.remote_ip6, dst=self.pg5.local_ip6) /
8177              ICMPv6ND_NA(tgt=tgt) /
8178              ICMPv6NDOptDstLLAddr(lladdr=self.pg5.remote_mac))
8179         pkts = [p]
8180         self.pg5.add_stream(pkts)
8181         self.pg_enable_capture(self.pg_interfaces)
8182         self.pg_start()
8183
8184         # Try to send ping again
8185         pkts = [ping]
8186         self.pg5.add_stream(pkts)
8187         self.pg_enable_capture(self.pg_interfaces)
8188         self.pg_start()
8189
8190         # Wait for ping reply
8191         capture = self.pg5.get_capture(len(pkts))
8192         packet = capture[0]
8193         try:
8194             self.assertEqual(packet[IPv6].src, self.pg5.local_ip6)
8195             self.assertEqual(packet[IPv6].dst, self.pg5.remote_ip6)
8196             self.assertEqual(packet.haslayer(ICMPv6EchoReply), 1)
8197         except:
8198             self.logger.error(ppp("Unexpected or invalid packet:", packet))
8199             raise
8200
8201     def test_pool(self):
8202         """ Add/delete address to NAT64 pool """
8203         nat_addr = '1.2.3.4'
8204
8205         self.vapi.nat64_add_del_pool_addr_range(start_addr=nat_addr,
8206                                                 end_addr=nat_addr,
8207                                                 vrf_id=0xFFFFFFFF, is_add=1)
8208
8209         addresses = self.vapi.nat64_pool_addr_dump()
8210         self.assertEqual(len(addresses), 1)
8211         self.assertEqual(str(addresses[0].address), nat_addr)
8212
8213         self.vapi.nat64_add_del_pool_addr_range(start_addr=nat_addr,
8214                                                 end_addr=nat_addr,
8215                                                 vrf_id=0xFFFFFFFF, is_add=0)
8216
8217         addresses = self.vapi.nat64_pool_addr_dump()
8218         self.assertEqual(len(addresses), 0)
8219
8220     def test_interface(self):
8221         """ Enable/disable NAT64 feature on the interface """
8222         flags = self.config_flags.NAT_IS_INSIDE
8223         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
8224                                           sw_if_index=self.pg0.sw_if_index)
8225         self.vapi.nat64_add_del_interface(is_add=1, flags=0,
8226                                           sw_if_index=self.pg1.sw_if_index)
8227
8228         interfaces = self.vapi.nat64_interface_dump()
8229         self.assertEqual(len(interfaces), 2)
8230         pg0_found = False
8231         pg1_found = False
8232         for intf in interfaces:
8233             if intf.sw_if_index == self.pg0.sw_if_index:
8234                 self.assertEqual(intf.flags, self.config_flags.NAT_IS_INSIDE)
8235                 pg0_found = True
8236             elif intf.sw_if_index == self.pg1.sw_if_index:
8237                 self.assertEqual(intf.flags, self.config_flags.NAT_IS_OUTSIDE)
8238                 pg1_found = True
8239         self.assertTrue(pg0_found)
8240         self.assertTrue(pg1_found)
8241
8242         features = self.vapi.cli("show interface features pg0")
8243         self.assertIn('nat64-in2out', features)
8244         features = self.vapi.cli("show interface features pg1")
8245         self.assertIn('nat64-out2in', features)
8246
8247         self.vapi.nat64_add_del_interface(is_add=0, flags=flags,
8248                                           sw_if_index=self.pg0.sw_if_index)
8249         self.vapi.nat64_add_del_interface(is_add=0, flags=flags,
8250                                           sw_if_index=self.pg1.sw_if_index)
8251
8252         interfaces = self.vapi.nat64_interface_dump()
8253         self.assertEqual(len(interfaces), 0)
8254
8255     def test_static_bib(self):
8256         """ Add/delete static BIB entry """
8257         in_addr = '2001:db8:85a3::8a2e:370:7334'
8258         out_addr = '10.1.1.3'
8259         in_port = 1234
8260         out_port = 5678
8261         proto = IP_PROTOS.tcp
8262
8263         self.vapi.nat64_add_del_static_bib(i_addr=in_addr, o_addr=out_addr,
8264                                            i_port=in_port, o_port=out_port,
8265                                            proto=proto, vrf_id=0, is_add=1)
8266         bib = self.vapi.nat64_bib_dump(proto=IP_PROTOS.tcp)
8267         static_bib_num = 0
8268         for bibe in bib:
8269             if bibe.flags & self.config_flags.NAT_IS_STATIC:
8270                 static_bib_num += 1
8271                 self.assertEqual(str(bibe.i_addr), in_addr)
8272                 self.assertEqual(str(bibe.o_addr), out_addr)
8273                 self.assertEqual(bibe.i_port, in_port)
8274                 self.assertEqual(bibe.o_port, out_port)
8275         self.assertEqual(static_bib_num, 1)
8276         bibs = self.statistics.get_counter('/nat64/total-bibs')
8277         self.assertEqual(bibs[0][0], 1)
8278
8279         self.vapi.nat64_add_del_static_bib(i_addr=in_addr, o_addr=out_addr,
8280                                            i_port=in_port, o_port=out_port,
8281                                            proto=proto, vrf_id=0, is_add=0)
8282         bib = self.vapi.nat64_bib_dump(proto=IP_PROTOS.tcp)
8283         static_bib_num = 0
8284         for bibe in bib:
8285             if bibe.flags & self.config_flags.NAT_IS_STATIC:
8286                 static_bib_num += 1
8287         self.assertEqual(static_bib_num, 0)
8288         bibs = self.statistics.get_counter('/nat64/total-bibs')
8289         self.assertEqual(bibs[0][0], 0)
8290
8291     def test_set_timeouts(self):
8292         """ Set NAT64 timeouts """
8293         # verify default values
8294         timeouts = self.vapi.nat_get_timeouts()
8295         self.assertEqual(timeouts.udp, 300)
8296         self.assertEqual(timeouts.icmp, 60)
8297         self.assertEqual(timeouts.tcp_transitory, 240)
8298         self.assertEqual(timeouts.tcp_established, 7440)
8299
8300         # set and verify custom values
8301         self.vapi.nat_set_timeouts(udp=200, tcp_established=7450,
8302                                    tcp_transitory=250, icmp=30)
8303         timeouts = self.vapi.nat_get_timeouts()
8304         self.assertEqual(timeouts.udp, 200)
8305         self.assertEqual(timeouts.icmp, 30)
8306         self.assertEqual(timeouts.tcp_transitory, 250)
8307         self.assertEqual(timeouts.tcp_established, 7450)
8308
8309     def test_dynamic(self):
8310         """ NAT64 dynamic translation test """
8311         self.tcp_port_in = 6303
8312         self.udp_port_in = 6304
8313         self.icmp_id_in = 6305
8314
8315         ses_num_start = self.nat64_get_ses_num()
8316
8317         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr,
8318                                                 end_addr=self.nat_addr,
8319                                                 vrf_id=0xFFFFFFFF,
8320                                                 is_add=1)
8321         flags = self.config_flags.NAT_IS_INSIDE
8322         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
8323                                           sw_if_index=self.pg0.sw_if_index)
8324         self.vapi.nat64_add_del_interface(is_add=1, flags=0,
8325                                           sw_if_index=self.pg1.sw_if_index)
8326
8327         # in2out
8328         tcpn = self.statistics.get_counter('/nat64/in2out/tcp')[0]
8329         udpn = self.statistics.get_counter('/nat64/in2out/udp')[0]
8330         icmpn = self.statistics.get_counter('/nat64/in2out/icmp')[0]
8331         drops = self.statistics.get_counter('/nat64/in2out/drops')[0]
8332
8333         pkts = self.create_stream_in_ip6(self.pg0, self.pg1)
8334         self.pg0.add_stream(pkts)
8335         self.pg_enable_capture(self.pg_interfaces)
8336         self.pg_start()
8337         capture = self.pg1.get_capture(len(pkts))
8338         self.verify_capture_out(capture, nat_ip=self.nat_addr,
8339                                 dst_ip=self.pg1.remote_ip4)
8340
8341         if_idx = self.pg0.sw_if_index
8342         cnt = self.statistics.get_counter('/nat64/in2out/tcp')[0]
8343         self.assertEqual(cnt[if_idx] - tcpn[if_idx], 1)
8344         cnt = self.statistics.get_counter('/nat64/in2out/udp')[0]
8345         self.assertEqual(cnt[if_idx] - udpn[if_idx], 1)
8346         cnt = self.statistics.get_counter('/nat64/in2out/icmp')[0]
8347         self.assertEqual(cnt[if_idx] - icmpn[if_idx], 1)
8348         cnt = self.statistics.get_counter('/nat64/in2out/drops')[0]
8349         self.assertEqual(cnt[if_idx] - drops[if_idx], 0)
8350
8351         # out2in
8352         tcpn = self.statistics.get_counter('/nat64/out2in/tcp')[0]
8353         udpn = self.statistics.get_counter('/nat64/out2in/udp')[0]
8354         icmpn = self.statistics.get_counter('/nat64/out2in/icmp')[0]
8355         drops = self.statistics.get_counter('/nat64/out2in/drops')[0]
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         if_idx = self.pg1.sw_if_index
8366         cnt = self.statistics.get_counter('/nat64/out2in/tcp')[0]
8367         self.assertEqual(cnt[if_idx] - tcpn[if_idx], 2)
8368         cnt = self.statistics.get_counter('/nat64/out2in/udp')[0]
8369         self.assertEqual(cnt[if_idx] - udpn[if_idx], 1)
8370         cnt = self.statistics.get_counter('/nat64/out2in/icmp')[0]
8371         self.assertEqual(cnt[if_idx] - icmpn[if_idx], 1)
8372         cnt = self.statistics.get_counter('/nat64/out2in/drops')[0]
8373         self.assertEqual(cnt[if_idx] - drops[if_idx], 0)
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 if __name__ == '__main__':
9498     unittest.main(testRunner=VppTestRunner)