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