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