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