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