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