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