tests: refactor. Replace literal constant w/ named constant.
[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.nat44_add_address(self.nat_addr, is_add=0)
3994             self.pg1.unconfig_ip4()
3995             self.pg2.unconfig_ip4()
3996             self.pg1.set_table_ip4(0)
3997             self.pg2.set_table_ip4(0)
3998             self.pg1.config_ip4()
3999             self.pg2.config_ip4()
4000             self.pg1.resolve_arp()
4001             self.pg2.resolve_arp()
4002
4003     @unittest.skipUnless(running_extended_tests, "part of extended tests")
4004     def test_session_timeout(self):
4005         """ NAT44 session timeouts """
4006         self.nat44_add_address(self.nat_addr)
4007         flags = self.config_flags.NAT_IS_INSIDE
4008         self.vapi.nat44_interface_add_del_feature(
4009             sw_if_index=self.pg0.sw_if_index,
4010             flags=flags, is_add=1)
4011         self.vapi.nat44_interface_add_del_feature(
4012             sw_if_index=self.pg1.sw_if_index,
4013             is_add=1)
4014         self.vapi.nat_set_timeouts(udp=5, tcp_established=7440,
4015                                    tcp_transitory=240, icmp=60)
4016
4017         max_sessions = 1000
4018         pkts = []
4019         for i in range(0, max_sessions):
4020             src = "10.10.%u.%u" % ((i & 0xFF00) >> 8, i & 0xFF)
4021             p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
4022                  IP(src=src, dst=self.pg1.remote_ip4) /
4023                  UDP(sport=1025, dport=53))
4024             pkts.append(p)
4025         self.pg0.add_stream(pkts)
4026         self.pg_enable_capture(self.pg_interfaces)
4027         self.pg_start()
4028         self.pg1.get_capture(max_sessions)
4029
4030         sleep(6)
4031
4032         pkts = []
4033         for i in range(0, max_sessions):
4034             src = "10.10.%u.%u" % ((i & 0xFF00) >> 8, i & 0xFF)
4035             p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
4036                  IP(src=src, dst=self.pg1.remote_ip4) /
4037                  UDP(sport=1026, dport=53))
4038             pkts.append(p)
4039         self.pg0.add_stream(pkts)
4040         self.pg_enable_capture(self.pg_interfaces)
4041         self.pg_start()
4042         self.pg1.get_capture(max_sessions)
4043
4044         nsessions = 0
4045         users = self.vapi.nat44_user_dump()
4046         for user in users:
4047             nsessions = nsessions + user.nsessions
4048         self.assertLess(nsessions, 2 * max_sessions)
4049
4050     def test_mss_clamping(self):
4051         """ TCP MSS clamping """
4052         self.nat44_add_address(self.nat_addr)
4053         flags = self.config_flags.NAT_IS_INSIDE
4054         self.vapi.nat44_interface_add_del_feature(
4055             sw_if_index=self.pg0.sw_if_index,
4056             flags=flags, is_add=1)
4057         self.vapi.nat44_interface_add_del_feature(
4058             sw_if_index=self.pg1.sw_if_index,
4059             is_add=1)
4060
4061         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
4062              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
4063              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
4064                  flags="S", options=[('MSS', 1400)]))
4065
4066         self.vapi.nat_set_mss_clamping(enable=1, mss_value=1000)
4067         self.pg0.add_stream(p)
4068         self.pg_enable_capture(self.pg_interfaces)
4069         self.pg_start()
4070         capture = self.pg1.get_capture(1)
4071         # Negotiated MSS value greater than configured - changed
4072         self.verify_mss_value(capture[0], 1000)
4073
4074         self.vapi.nat_set_mss_clamping(enable=0, mss_value=1500)
4075         self.pg0.add_stream(p)
4076         self.pg_enable_capture(self.pg_interfaces)
4077         self.pg_start()
4078         capture = self.pg1.get_capture(1)
4079         # MSS clamping disabled - negotiated MSS unchanged
4080         self.verify_mss_value(capture[0], 1400)
4081
4082         self.vapi.nat_set_mss_clamping(enable=1, mss_value=1500)
4083         self.pg0.add_stream(p)
4084         self.pg_enable_capture(self.pg_interfaces)
4085         self.pg_start()
4086         capture = self.pg1.get_capture(1)
4087         # Negotiated MSS value smaller than configured - unchanged
4088         self.verify_mss_value(capture[0], 1400)
4089
4090     @unittest.skipUnless(running_extended_tests, "part of extended tests")
4091     def test_ha_send(self):
4092         """ Send HA session synchronization events (active) """
4093         self.nat44_add_address(self.nat_addr)
4094         flags = self.config_flags.NAT_IS_INSIDE
4095         self.vapi.nat44_interface_add_del_feature(
4096             sw_if_index=self.pg0.sw_if_index,
4097             flags=flags, is_add=1)
4098         self.vapi.nat44_interface_add_del_feature(
4099             sw_if_index=self.pg1.sw_if_index,
4100             is_add=1)
4101         self.vapi.nat_ha_set_listener(ip_address=self.pg3.local_ip4,
4102                                       port=12345,
4103                                       path_mtu=512)
4104         self.vapi.nat_ha_set_failover(ip_address=self.pg3.remote_ip4,
4105                                       port=12346, session_refresh_interval=10)
4106         bind_layers(UDP, HANATStateSync, sport=12345)
4107
4108         # create sessions
4109         pkts = self.create_stream_in(self.pg0, self.pg1)
4110         self.pg0.add_stream(pkts)
4111         self.pg_enable_capture(self.pg_interfaces)
4112         self.pg_start()
4113         capture = self.pg1.get_capture(len(pkts))
4114         self.verify_capture_out(capture)
4115         # active send HA events
4116         self.vapi.nat_ha_flush()
4117         stats = self.statistics.get_counter('/nat44/ha/add-event-send')
4118         self.assertEqual(stats[0][0], 3)
4119         capture = self.pg3.get_capture(1)
4120         p = capture[0]
4121         self.assert_packet_checksums_valid(p)
4122         try:
4123             ip = p[IP]
4124             udp = p[UDP]
4125             hanat = p[HANATStateSync]
4126         except IndexError:
4127             self.logger.error(ppp("Invalid packet:", p))
4128             raise
4129         else:
4130             self.assertEqual(ip.src, self.pg3.local_ip4)
4131             self.assertEqual(ip.dst, self.pg3.remote_ip4)
4132             self.assertEqual(udp.sport, 12345)
4133             self.assertEqual(udp.dport, 12346)
4134             self.assertEqual(hanat.version, 1)
4135             self.assertEqual(hanat.thread_index, 0)
4136             self.assertEqual(hanat.count, 3)
4137             seq = hanat.sequence_number
4138             for event in hanat.events:
4139                 self.assertEqual(event.event_type, 1)
4140                 self.assertEqual(event.in_addr, self.pg0.remote_ip4)
4141                 self.assertEqual(event.out_addr, self.nat_addr)
4142                 self.assertEqual(event.fib_index, 0)
4143
4144         # ACK received events
4145         ack = (Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac) /
4146                IP(src=self.pg3.remote_ip4, dst=self.pg3.local_ip4) /
4147                UDP(sport=12346, dport=12345) /
4148                HANATStateSync(sequence_number=seq, flags='ACK'))
4149         self.pg3.add_stream(ack)
4150         self.pg_start()
4151         stats = self.statistics.get_counter('/nat44/ha/ack-recv')
4152         self.assertEqual(stats[0][0], 1)
4153
4154         # delete one session
4155         self.pg_enable_capture(self.pg_interfaces)
4156         self.vapi.nat44_del_session(address=self.pg0.remote_ip4n,
4157                                     port=self.tcp_port_in,
4158                                     protocol=IP_PROTOS.tcp,
4159                                     flags=self.config_flags.NAT_IS_INSIDE)
4160         self.vapi.nat_ha_flush()
4161         stats = self.statistics.get_counter('/nat44/ha/del-event-send')
4162         self.assertEqual(stats[0][0], 1)
4163         capture = self.pg3.get_capture(1)
4164         p = capture[0]
4165         try:
4166             hanat = p[HANATStateSync]
4167         except IndexError:
4168             self.logger.error(ppp("Invalid packet:", p))
4169             raise
4170         else:
4171             self.assertGreater(hanat.sequence_number, seq)
4172
4173         # do not send ACK, active retry send HA event again
4174         self.pg_enable_capture(self.pg_interfaces)
4175         sleep(12)
4176         stats = self.statistics.get_counter('/nat44/ha/retry-count')
4177         self.assertEqual(stats[0][0], 3)
4178         stats = self.statistics.get_counter('/nat44/ha/missed-count')
4179         self.assertEqual(stats[0][0], 1)
4180         capture = self.pg3.get_capture(3)
4181         for packet in capture:
4182             self.assertEqual(packet, p)
4183
4184         # session counters refresh
4185         pkts = self.create_stream_out(self.pg1)
4186         self.pg1.add_stream(pkts)
4187         self.pg_enable_capture(self.pg_interfaces)
4188         self.pg_start()
4189         self.pg0.get_capture(2)
4190         self.vapi.nat_ha_flush()
4191         stats = self.statistics.get_counter('/nat44/ha/refresh-event-send')
4192         self.assertEqual(stats[0][0], 2)
4193         capture = self.pg3.get_capture(1)
4194         p = capture[0]
4195         self.assert_packet_checksums_valid(p)
4196         try:
4197             ip = p[IP]
4198             udp = p[UDP]
4199             hanat = p[HANATStateSync]
4200         except IndexError:
4201             self.logger.error(ppp("Invalid packet:", p))
4202             raise
4203         else:
4204             self.assertEqual(ip.src, self.pg3.local_ip4)
4205             self.assertEqual(ip.dst, self.pg3.remote_ip4)
4206             self.assertEqual(udp.sport, 12345)
4207             self.assertEqual(udp.dport, 12346)
4208             self.assertEqual(hanat.version, 1)
4209             self.assertEqual(hanat.count, 2)
4210             seq = hanat.sequence_number
4211             for event in hanat.events:
4212                 self.assertEqual(event.event_type, 3)
4213                 self.assertEqual(event.out_addr, self.nat_addr)
4214                 self.assertEqual(event.fib_index, 0)
4215                 self.assertEqual(event.total_pkts, 2)
4216                 self.assertGreater(event.total_bytes, 0)
4217
4218         ack = (Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac) /
4219                IP(src=self.pg3.remote_ip4, dst=self.pg3.local_ip4) /
4220                UDP(sport=12346, dport=12345) /
4221                HANATStateSync(sequence_number=seq, flags='ACK'))
4222         self.pg3.add_stream(ack)
4223         self.pg_start()
4224         stats = self.statistics.get_counter('/nat44/ha/ack-recv')
4225         self.assertEqual(stats[0][0], 2)
4226
4227     def test_ha_recv(self):
4228         """ Receive HA session synchronization events (passive) """
4229         self.nat44_add_address(self.nat_addr)
4230         flags = self.config_flags.NAT_IS_INSIDE
4231         self.vapi.nat44_interface_add_del_feature(
4232             sw_if_index=self.pg0.sw_if_index,
4233             flags=flags, is_add=1)
4234         self.vapi.nat44_interface_add_del_feature(
4235             sw_if_index=self.pg1.sw_if_index,
4236             is_add=1)
4237         self.vapi.nat_ha_set_listener(ip_address=self.pg3.local_ip4,
4238                                       port=12345,
4239                                       path_mtu=512)
4240         bind_layers(UDP, HANATStateSync, sport=12345)
4241
4242         self.tcp_port_out = random.randint(1025, 65535)
4243         self.udp_port_out = random.randint(1025, 65535)
4244
4245         # send HA session add events to failover/passive
4246         p = (Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac) /
4247              IP(src=self.pg3.remote_ip4, dst=self.pg3.local_ip4) /
4248              UDP(sport=12346, dport=12345) /
4249              HANATStateSync(sequence_number=1, events=[
4250                  Event(event_type='add', protocol='tcp',
4251                        in_addr=self.pg0.remote_ip4, out_addr=self.nat_addr,
4252                        in_port=self.tcp_port_in, out_port=self.tcp_port_out,
4253                        eh_addr=self.pg1.remote_ip4,
4254                        ehn_addr=self.pg1.remote_ip4,
4255                        eh_port=self.tcp_external_port,
4256                        ehn_port=self.tcp_external_port, fib_index=0),
4257                  Event(event_type='add', protocol='udp',
4258                        in_addr=self.pg0.remote_ip4, out_addr=self.nat_addr,
4259                        in_port=self.udp_port_in, out_port=self.udp_port_out,
4260                        eh_addr=self.pg1.remote_ip4,
4261                        ehn_addr=self.pg1.remote_ip4,
4262                        eh_port=self.udp_external_port,
4263                        ehn_port=self.udp_external_port, fib_index=0)]))
4264
4265         self.pg3.add_stream(p)
4266         self.pg_enable_capture(self.pg_interfaces)
4267         self.pg_start()
4268         # receive ACK
4269         capture = self.pg3.get_capture(1)
4270         p = capture[0]
4271         try:
4272             hanat = p[HANATStateSync]
4273         except IndexError:
4274             self.logger.error(ppp("Invalid packet:", p))
4275             raise
4276         else:
4277             self.assertEqual(hanat.sequence_number, 1)
4278             self.assertEqual(hanat.flags, 'ACK')
4279             self.assertEqual(hanat.version, 1)
4280             self.assertEqual(hanat.thread_index, 0)
4281         stats = self.statistics.get_counter('/nat44/ha/ack-send')
4282         self.assertEqual(stats[0][0], 1)
4283         stats = self.statistics.get_counter('/nat44/ha/add-event-recv')
4284         self.assertEqual(stats[0][0], 2)
4285         users = self.statistics.get_counter('/nat44/total-users')
4286         self.assertEqual(users[0][0], 1)
4287         sessions = self.statistics.get_counter('/nat44/total-sessions')
4288         self.assertEqual(sessions[0][0], 2)
4289         users = self.vapi.nat44_user_dump()
4290         self.assertEqual(len(users), 1)
4291         self.assertEqual(str(users[0].ip_address),
4292                          self.pg0.remote_ip4)
4293         # there should be 2 sessions created by HA
4294         sessions = self.vapi.nat44_user_session_dump(users[0].ip_address,
4295                                                      users[0].vrf_id)
4296         self.assertEqual(len(sessions), 2)
4297         for session in sessions:
4298             self.assertEqual(str(session.inside_ip_address),
4299                              self.pg0.remote_ip4)
4300             self.assertEqual(str(session.outside_ip_address),
4301                              self.nat_addr)
4302             self.assertIn(session.inside_port,
4303                           [self.tcp_port_in, self.udp_port_in])
4304             self.assertIn(session.outside_port,
4305                           [self.tcp_port_out, self.udp_port_out])
4306             self.assertIn(session.protocol, [IP_PROTOS.tcp, IP_PROTOS.udp])
4307
4308         # send HA session delete event to failover/passive
4309         p = (Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac) /
4310              IP(src=self.pg3.remote_ip4, dst=self.pg3.local_ip4) /
4311              UDP(sport=12346, dport=12345) /
4312              HANATStateSync(sequence_number=2, events=[
4313                  Event(event_type='del', protocol='udp',
4314                        in_addr=self.pg0.remote_ip4, out_addr=self.nat_addr,
4315                        in_port=self.udp_port_in, out_port=self.udp_port_out,
4316                        eh_addr=self.pg1.remote_ip4,
4317                        ehn_addr=self.pg1.remote_ip4,
4318                        eh_port=self.udp_external_port,
4319                        ehn_port=self.udp_external_port, fib_index=0)]))
4320
4321         self.pg3.add_stream(p)
4322         self.pg_enable_capture(self.pg_interfaces)
4323         self.pg_start()
4324         # receive ACK
4325         capture = self.pg3.get_capture(1)
4326         p = capture[0]
4327         try:
4328             hanat = p[HANATStateSync]
4329         except IndexError:
4330             self.logger.error(ppp("Invalid packet:", p))
4331             raise
4332         else:
4333             self.assertEqual(hanat.sequence_number, 2)
4334             self.assertEqual(hanat.flags, 'ACK')
4335             self.assertEqual(hanat.version, 1)
4336         users = self.vapi.nat44_user_dump()
4337         self.assertEqual(len(users), 1)
4338         self.assertEqual(str(users[0].ip_address),
4339                          self.pg0.remote_ip4)
4340         # now we should have only 1 session, 1 deleted by HA
4341         sessions = self.vapi.nat44_user_session_dump(users[0].ip_address,
4342                                                      users[0].vrf_id)
4343         self.assertEqual(len(sessions), 1)
4344         stats = self.statistics.get_counter('/nat44/ha/del-event-recv')
4345         self.assertEqual(stats[0][0], 1)
4346
4347         stats = self.statistics.get_counter('/err/nat-ha/pkts-processed')
4348         self.assertEqual(stats, 2)
4349
4350         # send HA session refresh event to failover/passive
4351         p = (Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac) /
4352              IP(src=self.pg3.remote_ip4, dst=self.pg3.local_ip4) /
4353              UDP(sport=12346, dport=12345) /
4354              HANATStateSync(sequence_number=3, events=[
4355                  Event(event_type='refresh', protocol='tcp',
4356                        in_addr=self.pg0.remote_ip4, out_addr=self.nat_addr,
4357                        in_port=self.tcp_port_in, out_port=self.tcp_port_out,
4358                        eh_addr=self.pg1.remote_ip4,
4359                        ehn_addr=self.pg1.remote_ip4,
4360                        eh_port=self.tcp_external_port,
4361                        ehn_port=self.tcp_external_port, fib_index=0,
4362                        total_bytes=1024, total_pkts=2)]))
4363         self.pg3.add_stream(p)
4364         self.pg_enable_capture(self.pg_interfaces)
4365         self.pg_start()
4366         # receive ACK
4367         capture = self.pg3.get_capture(1)
4368         p = capture[0]
4369         try:
4370             hanat = p[HANATStateSync]
4371         except IndexError:
4372             self.logger.error(ppp("Invalid packet:", p))
4373             raise
4374         else:
4375             self.assertEqual(hanat.sequence_number, 3)
4376             self.assertEqual(hanat.flags, 'ACK')
4377             self.assertEqual(hanat.version, 1)
4378         users = self.vapi.nat44_user_dump()
4379         self.assertEqual(len(users), 1)
4380         self.assertEqual(str(users[0].ip_address),
4381                          self.pg0.remote_ip4)
4382         sessions = self.vapi.nat44_user_session_dump(users[0].ip_address,
4383                                                      users[0].vrf_id)
4384         self.assertEqual(len(sessions), 1)
4385         session = sessions[0]
4386         self.assertEqual(session.total_bytes, 1024)
4387         self.assertEqual(session.total_pkts, 2)
4388         stats = self.statistics.get_counter('/nat44/ha/refresh-event-recv')
4389         self.assertEqual(stats[0][0], 1)
4390
4391         stats = self.statistics.get_counter('/err/nat-ha/pkts-processed')
4392         self.assertEqual(stats, 3)
4393
4394         # send packet to test session created by HA
4395         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
4396              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
4397              TCP(sport=self.tcp_external_port, dport=self.tcp_port_out))
4398         self.pg1.add_stream(p)
4399         self.pg_enable_capture(self.pg_interfaces)
4400         self.pg_start()
4401         capture = self.pg0.get_capture(1)
4402         p = capture[0]
4403         try:
4404             ip = p[IP]
4405             tcp = p[TCP]
4406         except IndexError:
4407             self.logger.error(ppp("Invalid packet:", p))
4408             raise
4409         else:
4410             self.assertEqual(ip.src, self.pg1.remote_ip4)
4411             self.assertEqual(ip.dst, self.pg0.remote_ip4)
4412             self.assertEqual(tcp.sport, self.tcp_external_port)
4413             self.assertEqual(tcp.dport, self.tcp_port_in)
4414
4415     def tearDown(self):
4416         super(TestNAT44, self).tearDown()
4417         self.clear_nat44()
4418         self.vapi.cli("clear logging")
4419
4420     def show_commands_at_teardown(self):
4421         self.logger.info(self.vapi.cli("show nat44 addresses"))
4422         self.logger.info(self.vapi.cli("show nat44 interfaces"))
4423         self.logger.info(self.vapi.cli("show nat44 static mappings"))
4424         self.logger.info(self.vapi.cli("show nat44 interface address"))
4425         self.logger.info(self.vapi.cli("show nat44 sessions detail"))
4426         self.logger.info(self.vapi.cli("show nat virtual-reassembly"))
4427         self.logger.info(self.vapi.cli("show nat44 hash tables detail"))
4428         self.logger.info(self.vapi.cli("show nat timeouts"))
4429         self.logger.info(
4430             self.vapi.cli("show nat addr-port-assignment-alg"))
4431         self.logger.info(self.vapi.cli("show nat ha"))
4432
4433
4434 class TestNAT44EndpointDependent(MethodHolder):
4435     """ Endpoint-Dependent mapping and filtering test cases """
4436
4437     @classmethod
4438     def setUpConstants(cls):
4439         super(TestNAT44EndpointDependent, cls).setUpConstants()
4440         cls.vpp_cmdline.extend(["nat", "{", "endpoint-dependent", "}"])
4441
4442     @classmethod
4443     def setUpClass(cls):
4444         super(TestNAT44EndpointDependent, cls).setUpClass()
4445         cls.vapi.cli("set log class nat level debug")
4446         try:
4447             cls.tcp_port_in = 6303
4448             cls.tcp_port_out = 6303
4449             cls.udp_port_in = 6304
4450             cls.udp_port_out = 6304
4451             cls.icmp_id_in = 6305
4452             cls.icmp_id_out = 6305
4453             cls.nat_addr = '10.0.0.3'
4454             cls.ipfix_src_port = 4739
4455             cls.ipfix_domain_id = 1
4456             cls.tcp_external_port = 80
4457
4458             cls.create_pg_interfaces(range(7))
4459             cls.interfaces = list(cls.pg_interfaces[0:3])
4460
4461             for i in cls.interfaces:
4462                 i.admin_up()
4463                 i.config_ip4()
4464                 i.resolve_arp()
4465
4466             cls.pg0.generate_remote_hosts(3)
4467             cls.pg0.configure_ipv4_neighbors()
4468
4469             cls.pg3.admin_up()
4470
4471             cls.pg4.generate_remote_hosts(2)
4472             cls.pg4.config_ip4()
4473             ip_addr_n = socket.inet_pton(socket.AF_INET, "10.0.0.1")
4474             cls.vapi.sw_interface_add_del_address(
4475                 sw_if_index=cls.pg4.sw_if_index, address=ip_addr_n,
4476                 address_length=24)
4477             cls.pg4.admin_up()
4478             cls.pg4.resolve_arp()
4479             cls.pg4._remote_hosts[1]._ip4 = cls.pg4._remote_hosts[0]._ip4
4480             cls.pg4.resolve_arp()
4481
4482             zero_ip4n = socket.inet_pton(socket.AF_INET, "0.0.0.0")
4483             cls.vapi.ip_table_add_del(is_add=1, table_id=1)
4484
4485             cls.pg5._local_ip4 = "10.1.1.1"
4486             cls.pg5._local_ip4n = socket.inet_pton(socket.AF_INET,
4487                                                    cls.pg5.local_ip4)
4488             cls.pg5._remote_hosts[0]._ip4 = "10.1.1.2"
4489             cls.pg5._remote_hosts[0]._ip4n = socket.inet_pton(
4490                 socket.AF_INET, cls.pg5.remote_ip4)
4491             cls.pg5.set_table_ip4(1)
4492             cls.pg5.config_ip4()
4493             cls.pg5.admin_up()
4494             cls.vapi.ip_add_del_route(dst_address=cls.pg5.remote_ip4n,
4495                                       dst_address_length=32,
4496                                       next_hop_address=zero_ip4n,
4497                                       next_hop_sw_if_index=cls.pg5.sw_if_index,
4498                                       table_id=1)
4499
4500             cls.pg6._local_ip4 = "10.1.2.1"
4501             cls.pg6._local_ip4n = socket.inet_pton(socket.AF_INET,
4502                                                    cls.pg6.local_ip4)
4503             cls.pg6._remote_hosts[0]._ip4 = "10.1.2.2"
4504             cls.pg6._remote_hosts[0]._ip4n = socket.inet_pton(
4505                 socket.AF_INET, cls.pg6.remote_ip4)
4506             cls.pg6.set_table_ip4(1)
4507             cls.pg6.config_ip4()
4508             cls.pg6.admin_up()
4509             cls.vapi.ip_add_del_route(dst_address=cls.pg6.remote_ip4n,
4510                                       dst_address_length=32,
4511                                       next_hop_address=zero_ip4n,
4512                                       next_hop_sw_if_index=cls.pg6.sw_if_index,
4513                                       table_id=1)
4514
4515             cls.vapi.ip_add_del_route(dst_address=cls.pg6.remote_ip4n,
4516                                       dst_address_length=16,
4517                                       next_hop_address=zero_ip4n, table_id=0,
4518                                       next_hop_table_id=1)
4519             cls.vapi.ip_add_del_route(dst_address=zero_ip4n,
4520                                       dst_address_length=0,
4521                                       next_hop_address=zero_ip4n, table_id=1,
4522                                       next_hop_table_id=0)
4523             cls.vapi.ip_add_del_route(dst_address=zero_ip4n,
4524                                       dst_address_length=0,
4525                                       next_hop_address=cls.pg1.local_ip4n,
4526                                       next_hop_sw_if_index=cls.pg1.sw_if_index,
4527                                       table_id=0)
4528
4529             cls.pg5.resolve_arp()
4530             cls.pg6.resolve_arp()
4531
4532         except Exception:
4533             super(TestNAT44EndpointDependent, cls).tearDownClass()
4534             raise
4535
4536     @classmethod
4537     def tearDownClass(cls):
4538         super(TestNAT44EndpointDependent, cls).tearDownClass()
4539
4540     def test_frag_in_order(self):
4541         """ NAT44 translate fragments arriving in order """
4542         self.nat44_add_address(self.nat_addr)
4543         flags = self.config_flags.NAT_IS_INSIDE
4544         self.vapi.nat44_interface_add_del_feature(
4545             sw_if_index=self.pg0.sw_if_index,
4546             flags=flags, is_add=1)
4547         self.vapi.nat44_interface_add_del_feature(
4548             sw_if_index=self.pg1.sw_if_index,
4549             is_add=1)
4550         self.frag_in_order(proto=IP_PROTOS.tcp)
4551         self.frag_in_order(proto=IP_PROTOS.udp)
4552         self.frag_in_order(proto=IP_PROTOS.icmp)
4553
4554     def test_frag_in_order_dont_translate(self):
4555         """ NAT44 don't translate fragments arriving in order """
4556         flags = self.config_flags.NAT_IS_INSIDE
4557         self.vapi.nat44_interface_add_del_feature(
4558             sw_if_index=self.pg0.sw_if_index,
4559             flags=flags, is_add=1)
4560         self.vapi.nat44_interface_add_del_feature(
4561             sw_if_index=self.pg1.sw_if_index,
4562             is_add=1)
4563         self.vapi.nat44_forwarding_enable_disable(enable=True)
4564         self.frag_in_order(proto=IP_PROTOS.tcp, dont_translate=True)
4565
4566     def test_frag_out_of_order(self):
4567         """ NAT44 translate fragments arriving out of order """
4568         self.nat44_add_address(self.nat_addr)
4569         flags = self.config_flags.NAT_IS_INSIDE
4570         self.vapi.nat44_interface_add_del_feature(
4571             sw_if_index=self.pg0.sw_if_index,
4572             flags=flags, is_add=1)
4573         self.vapi.nat44_interface_add_del_feature(
4574             sw_if_index=self.pg1.sw_if_index,
4575             is_add=1)
4576         self.frag_out_of_order(proto=IP_PROTOS.tcp)
4577         self.frag_out_of_order(proto=IP_PROTOS.udp)
4578         self.frag_out_of_order(proto=IP_PROTOS.icmp)
4579
4580     def test_frag_out_of_order_dont_translate(self):
4581         """ NAT44 don't translate fragments arriving out of order """
4582         flags = self.config_flags.NAT_IS_INSIDE
4583         self.vapi.nat44_interface_add_del_feature(
4584             sw_if_index=self.pg0.sw_if_index,
4585             flags=flags, is_add=1)
4586         self.vapi.nat44_interface_add_del_feature(
4587             sw_if_index=self.pg1.sw_if_index,
4588             is_add=1)
4589         self.vapi.nat44_forwarding_enable_disable(enable=True)
4590         self.frag_out_of_order(proto=IP_PROTOS.tcp, dont_translate=True)
4591
4592     def test_frag_in_order_in_plus_out(self):
4593         """ in+out interface fragments in order """
4594         flags = self.config_flags.NAT_IS_INSIDE
4595         self.vapi.nat44_interface_add_del_feature(
4596             sw_if_index=self.pg0.sw_if_index,
4597             is_add=1)
4598         self.vapi.nat44_interface_add_del_feature(
4599             sw_if_index=self.pg0.sw_if_index,
4600             flags=flags, is_add=1)
4601         self.vapi.nat44_interface_add_del_feature(
4602             sw_if_index=self.pg1.sw_if_index,
4603             is_add=1)
4604         self.vapi.nat44_interface_add_del_feature(
4605             sw_if_index=self.pg1.sw_if_index,
4606             flags=flags, is_add=1)
4607
4608         self.server = self.pg1.remote_hosts[0]
4609
4610         self.server_in_addr = self.server.ip4
4611         self.server_out_addr = '11.11.11.11'
4612         self.server_in_port = random.randint(1025, 65535)
4613         self.server_out_port = random.randint(1025, 65535)
4614
4615         self.nat44_add_address(self.server_out_addr)
4616
4617         # add static mappings for server
4618         self.nat44_add_static_mapping(self.server_in_addr,
4619                                       self.server_out_addr,
4620                                       self.server_in_port,
4621                                       self.server_out_port,
4622                                       proto=IP_PROTOS.tcp)
4623         self.nat44_add_static_mapping(self.server_in_addr,
4624                                       self.server_out_addr,
4625                                       self.server_in_port,
4626                                       self.server_out_port,
4627                                       proto=IP_PROTOS.udp)
4628         self.nat44_add_static_mapping(self.server_in_addr,
4629                                       self.server_out_addr,
4630                                       proto=IP_PROTOS.icmp)
4631
4632         self.vapi.nat_set_reass(timeout=10, max_reass=1024, max_frag=5,
4633                                 drop_frag=0)
4634
4635         self.frag_in_order_in_plus_out(proto=IP_PROTOS.tcp)
4636         self.frag_in_order_in_plus_out(proto=IP_PROTOS.udp)
4637         self.frag_in_order_in_plus_out(proto=IP_PROTOS.icmp)
4638
4639     def test_frag_out_of_order_in_plus_out(self):
4640         """ in+out interface fragments out of order """
4641         flags = self.config_flags.NAT_IS_INSIDE
4642         self.vapi.nat44_interface_add_del_feature(
4643             sw_if_index=self.pg0.sw_if_index,
4644             is_add=1)
4645         self.vapi.nat44_interface_add_del_feature(
4646             sw_if_index=self.pg0.sw_if_index,
4647             flags=flags, is_add=1)
4648         self.vapi.nat44_interface_add_del_feature(
4649             sw_if_index=self.pg1.sw_if_index,
4650             is_add=1)
4651         self.vapi.nat44_interface_add_del_feature(
4652             sw_if_index=self.pg1.sw_if_index,
4653             flags=flags, is_add=1)
4654
4655         self.server = self.pg1.remote_hosts[0]
4656
4657         self.server_in_addr = self.server.ip4
4658         self.server_out_addr = '11.11.11.11'
4659         self.server_in_port = random.randint(1025, 65535)
4660         self.server_out_port = random.randint(1025, 65535)
4661
4662         self.nat44_add_address(self.server_out_addr)
4663
4664         # add static mappings for server
4665         self.nat44_add_static_mapping(self.server_in_addr,
4666                                       self.server_out_addr,
4667                                       self.server_in_port,
4668                                       self.server_out_port,
4669                                       proto=IP_PROTOS.tcp)
4670         self.nat44_add_static_mapping(self.server_in_addr,
4671                                       self.server_out_addr,
4672                                       self.server_in_port,
4673                                       self.server_out_port,
4674                                       proto=IP_PROTOS.udp)
4675         self.nat44_add_static_mapping(self.server_in_addr,
4676                                       self.server_out_addr,
4677                                       proto=IP_PROTOS.icmp)
4678
4679         self.vapi.nat_set_reass(timeout=10, max_reass=1024, max_frag=5,
4680                                 drop_frag=0)
4681
4682         self.frag_out_of_order_in_plus_out(proto=IP_PROTOS.tcp)
4683         self.frag_out_of_order_in_plus_out(proto=IP_PROTOS.udp)
4684         self.frag_out_of_order_in_plus_out(proto=IP_PROTOS.icmp)
4685
4686     def test_reass_hairpinning(self):
4687         """ NAT44 fragments hairpinning """
4688         self.server = self.pg0.remote_hosts[1]
4689         self.host_in_port = random.randint(1025, 65535)
4690         self.server_in_port = random.randint(1025, 65535)
4691         self.server_out_port = random.randint(1025, 65535)
4692
4693         self.nat44_add_address(self.nat_addr)
4694         flags = self.config_flags.NAT_IS_INSIDE
4695         self.vapi.nat44_interface_add_del_feature(
4696             sw_if_index=self.pg0.sw_if_index,
4697             flags=flags, is_add=1)
4698         self.vapi.nat44_interface_add_del_feature(
4699             sw_if_index=self.pg1.sw_if_index,
4700             is_add=1)
4701         # add static mapping for server
4702         self.nat44_add_static_mapping(self.server.ip4, self.nat_addr,
4703                                       self.server_in_port,
4704                                       self.server_out_port,
4705                                       proto=IP_PROTOS.tcp)
4706         self.nat44_add_static_mapping(self.server.ip4, self.nat_addr,
4707                                       self.server_in_port,
4708                                       self.server_out_port,
4709                                       proto=IP_PROTOS.udp)
4710         self.nat44_add_static_mapping(self.server.ip4, self.nat_addr)
4711
4712         self.reass_hairpinning(proto=IP_PROTOS.tcp)
4713         self.reass_hairpinning(proto=IP_PROTOS.udp)
4714         self.reass_hairpinning(proto=IP_PROTOS.icmp)
4715
4716     def test_dynamic(self):
4717         """ NAT44 dynamic translation test """
4718
4719         self.nat44_add_address(self.nat_addr)
4720         flags = self.config_flags.NAT_IS_INSIDE
4721         self.vapi.nat44_interface_add_del_feature(
4722             sw_if_index=self.pg0.sw_if_index,
4723             flags=flags, is_add=1)
4724         self.vapi.nat44_interface_add_del_feature(
4725             sw_if_index=self.pg1.sw_if_index,
4726             is_add=1)
4727
4728         nat_config = self.vapi.nat_show_config()
4729         self.assertEqual(1, nat_config.endpoint_dependent)
4730
4731         # in2out
4732         tcpn = self.statistics.get_counter(
4733             '/err/nat44-ed-in2out-slowpath/TCP packets')
4734         udpn = self.statistics.get_counter(
4735             '/err/nat44-ed-in2out-slowpath/UDP packets')
4736         icmpn = self.statistics.get_counter(
4737             '/err/nat44-ed-in2out-slowpath/ICMP packets')
4738         totaln = self.statistics.get_counter(
4739             '/err/nat44-ed-in2out-slowpath/good in2out packets processed')
4740
4741         pkts = self.create_stream_in(self.pg0, self.pg1)
4742         self.pg0.add_stream(pkts)
4743         self.pg_enable_capture(self.pg_interfaces)
4744         self.pg_start()
4745         capture = self.pg1.get_capture(len(pkts))
4746         self.verify_capture_out(capture)
4747
4748         err = self.statistics.get_counter(
4749             '/err/nat44-ed-in2out-slowpath/TCP packets')
4750         self.assertEqual(err - tcpn, 1)
4751         err = self.statistics.get_counter(
4752             '/err/nat44-ed-in2out-slowpath/UDP packets')
4753         self.assertEqual(err - udpn, 1)
4754         err = self.statistics.get_counter(
4755             '/err/nat44-ed-in2out-slowpath/ICMP packets')
4756         self.assertEqual(err - icmpn, 1)
4757         err = self.statistics.get_counter(
4758             '/err/nat44-ed-in2out-slowpath/good in2out packets processed')
4759         self.assertEqual(err - totaln, 3)
4760
4761         # out2in
4762         tcpn = self.statistics.get_counter('/err/nat44-ed-out2in/TCP packets')
4763         udpn = self.statistics.get_counter('/err/nat44-ed-out2in/UDP packets')
4764         icmpn = self.statistics.get_counter(
4765             '/err/nat44-ed-out2in-slowpath/ICMP packets')
4766         totaln = self.statistics.get_counter(
4767             '/err/nat44-ed-out2in/good out2in packets processed')
4768
4769         pkts = self.create_stream_out(self.pg1)
4770         self.pg1.add_stream(pkts)
4771         self.pg_enable_capture(self.pg_interfaces)
4772         self.pg_start()
4773         capture = self.pg0.get_capture(len(pkts))
4774         self.verify_capture_in(capture, self.pg0)
4775
4776         err = self.statistics.get_counter('/err/nat44-ed-out2in/TCP packets')
4777         self.assertEqual(err - tcpn, 1)
4778         err = self.statistics.get_counter('/err/nat44-ed-out2in/UDP packets')
4779         self.assertEqual(err - udpn, 1)
4780         err = self.statistics.get_counter(
4781             '/err/nat44-ed-out2in-slowpath/ICMP packets')
4782         self.assertEqual(err - icmpn, 1)
4783         err = self.statistics.get_counter(
4784             '/err/nat44-ed-out2in/good out2in packets processed')
4785         self.assertEqual(err - totaln, 2)
4786
4787         users = self.statistics.get_counter('/nat44/total-users')
4788         self.assertEqual(users[0][0], 1)
4789         sessions = self.statistics.get_counter('/nat44/total-sessions')
4790         self.assertEqual(sessions[0][0], 3)
4791
4792     def test_forwarding(self):
4793         """ NAT44 forwarding test """
4794
4795         flags = self.config_flags.NAT_IS_INSIDE
4796         self.vapi.nat44_interface_add_del_feature(
4797             sw_if_index=self.pg0.sw_if_index,
4798             flags=flags, is_add=1)
4799         self.vapi.nat44_interface_add_del_feature(
4800             sw_if_index=self.pg1.sw_if_index,
4801             is_add=1)
4802         self.vapi.nat44_forwarding_enable_disable(enable=1)
4803
4804         real_ip = self.pg0.remote_ip4
4805         alias_ip = self.nat_addr
4806         flags = self.config_flags.NAT_IS_ADDR_ONLY
4807         self.vapi.nat44_add_del_static_mapping(is_add=1,
4808                                                local_ip_address=real_ip,
4809                                                external_ip_address=alias_ip,
4810                                                external_sw_if_index=0xFFFFFFFF,
4811                                                flags=flags)
4812
4813         try:
4814             # in2out - static mapping match
4815
4816             pkts = self.create_stream_out(self.pg1)
4817             self.pg1.add_stream(pkts)
4818             self.pg_enable_capture(self.pg_interfaces)
4819             self.pg_start()
4820             capture = self.pg0.get_capture(len(pkts))
4821             self.verify_capture_in(capture, self.pg0)
4822
4823             pkts = self.create_stream_in(self.pg0, self.pg1)
4824             self.pg0.add_stream(pkts)
4825             self.pg_enable_capture(self.pg_interfaces)
4826             self.pg_start()
4827             capture = self.pg1.get_capture(len(pkts))
4828             self.verify_capture_out(capture, same_port=True)
4829
4830             # in2out - no static mapping match
4831
4832             host0 = self.pg0.remote_hosts[0]
4833             self.pg0.remote_hosts[0] = self.pg0.remote_hosts[1]
4834             try:
4835                 pkts = self.create_stream_out(self.pg1,
4836                                               dst_ip=self.pg0.remote_ip4,
4837                                               use_inside_ports=True)
4838                 self.pg1.add_stream(pkts)
4839                 self.pg_enable_capture(self.pg_interfaces)
4840                 self.pg_start()
4841                 capture = self.pg0.get_capture(len(pkts))
4842                 self.verify_capture_in(capture, self.pg0)
4843
4844                 pkts = self.create_stream_in(self.pg0, self.pg1)
4845                 self.pg0.add_stream(pkts)
4846                 self.pg_enable_capture(self.pg_interfaces)
4847                 self.pg_start()
4848                 capture = self.pg1.get_capture(len(pkts))
4849                 self.verify_capture_out(capture, nat_ip=self.pg0.remote_ip4,
4850                                         same_port=True)
4851             finally:
4852                 self.pg0.remote_hosts[0] = host0
4853
4854             user = self.pg0.remote_hosts[1]
4855             sessions = self.vapi.nat44_user_session_dump(user.ip4n, 0)
4856             self.assertEqual(len(sessions), 3)
4857             self.assertTrue(sessions[0].flags &
4858                             self.config_flags.NAT_IS_EXT_HOST_VALID)
4859             self.vapi.nat44_del_session(
4860                 address=sessions[0].inside_ip_address,
4861                 port=sessions[0].inside_port,
4862                 protocol=sessions[0].protocol,
4863                 flags=(self.config_flags.NAT_IS_INSIDE |
4864                        self.config_flags.NAT_IS_EXT_HOST_VALID),
4865                 ext_host_address=sessions[0].ext_host_address,
4866                 ext_host_port=sessions[0].ext_host_port)
4867             sessions = self.vapi.nat44_user_session_dump(user.ip4n, 0)
4868             self.assertEqual(len(sessions), 2)
4869
4870         finally:
4871             self.vapi.nat44_forwarding_enable_disable(enable=0)
4872             flags = self.config_flags.NAT_IS_ADDR_ONLY
4873             self.vapi.nat44_add_del_static_mapping(
4874                 is_add=0,
4875                 local_ip_address=real_ip,
4876                 external_ip_address=alias_ip,
4877                 external_sw_if_index=0xFFFFFFFF,
4878                 flags=flags)
4879
4880     def test_static_lb(self):
4881         """ NAT44 local service load balancing """
4882         external_addr_n = self.nat_addr
4883         external_port = 80
4884         local_port = 8080
4885         server1 = self.pg0.remote_hosts[0]
4886         server2 = self.pg0.remote_hosts[1]
4887
4888         locals = [{'addr': server1.ip4n,
4889                    'port': local_port,
4890                    'probability': 70,
4891                    'vrf_id': 0},
4892                   {'addr': server2.ip4n,
4893                    'port': local_port,
4894                    'probability': 30,
4895                    'vrf_id': 0}]
4896
4897         self.nat44_add_address(self.nat_addr)
4898         self.vapi.nat44_add_del_lb_static_mapping(
4899             is_add=1,
4900             external_addr=external_addr_n,
4901             external_port=external_port,
4902             protocol=IP_PROTOS.tcp,
4903             local_num=len(locals),
4904             locals=locals)
4905         flags = self.config_flags.NAT_IS_INSIDE
4906         self.vapi.nat44_interface_add_del_feature(
4907             sw_if_index=self.pg0.sw_if_index,
4908             flags=flags, is_add=1)
4909         self.vapi.nat44_interface_add_del_feature(
4910             sw_if_index=self.pg1.sw_if_index,
4911             is_add=1)
4912
4913         # from client to service
4914         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
4915              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
4916              TCP(sport=12345, dport=external_port))
4917         self.pg1.add_stream(p)
4918         self.pg_enable_capture(self.pg_interfaces)
4919         self.pg_start()
4920         capture = self.pg0.get_capture(1)
4921         p = capture[0]
4922         server = None
4923         try:
4924             ip = p[IP]
4925             tcp = p[TCP]
4926             self.assertIn(ip.dst, [server1.ip4, server2.ip4])
4927             if ip.dst == server1.ip4:
4928                 server = server1
4929             else:
4930                 server = server2
4931             self.assertEqual(tcp.dport, local_port)
4932             self.assert_packet_checksums_valid(p)
4933         except:
4934             self.logger.error(ppp("Unexpected or invalid packet:", p))
4935             raise
4936
4937         # from service back to client
4938         p = (Ether(src=server.mac, dst=self.pg0.local_mac) /
4939              IP(src=server.ip4, dst=self.pg1.remote_ip4) /
4940              TCP(sport=local_port, dport=12345))
4941         self.pg0.add_stream(p)
4942         self.pg_enable_capture(self.pg_interfaces)
4943         self.pg_start()
4944         capture = self.pg1.get_capture(1)
4945         p = capture[0]
4946         try:
4947             ip = p[IP]
4948             tcp = p[TCP]
4949             self.assertEqual(ip.src, self.nat_addr)
4950             self.assertEqual(tcp.sport, external_port)
4951             self.assert_packet_checksums_valid(p)
4952         except:
4953             self.logger.error(ppp("Unexpected or invalid packet:", p))
4954             raise
4955
4956         sessions = self.vapi.nat44_user_session_dump(server.ip4n, 0)
4957         self.assertEqual(len(sessions), 1)
4958         self.assertTrue(sessions[0].flags &
4959                         self.config_flags.NAT_IS_EXT_HOST_VALID)
4960         self.vapi.nat44_del_session(
4961             address=sessions[0].inside_ip_address,
4962             port=sessions[0].inside_port,
4963             protocol=sessions[0].protocol,
4964             flags=(self.config_flags.NAT_IS_INSIDE |
4965                    self.config_flags.NAT_IS_EXT_HOST_VALID),
4966             ext_host_address=sessions[0].ext_host_address,
4967             ext_host_port=sessions[0].ext_host_port)
4968         sessions = self.vapi.nat44_user_session_dump(server.ip4n, 0)
4969         self.assertEqual(len(sessions), 0)
4970
4971     @unittest.skipUnless(running_extended_tests, "part of extended tests")
4972     def test_static_lb_multi_clients(self):
4973         """ NAT44 local service load balancing - multiple clients"""
4974
4975         external_addr = self.nat_addr
4976         external_port = 80
4977         local_port = 8080
4978         server1 = self.pg0.remote_hosts[0]
4979         server2 = self.pg0.remote_hosts[1]
4980         server3 = self.pg0.remote_hosts[2]
4981
4982         locals = [{'addr': server1.ip4n,
4983                    'port': local_port,
4984                    'probability': 90,
4985                    'vrf_id': 0},
4986                   {'addr': server2.ip4n,
4987                    'port': local_port,
4988                    'probability': 10,
4989                    'vrf_id': 0}]
4990
4991         self.nat44_add_address(self.nat_addr)
4992         self.vapi.nat44_add_del_lb_static_mapping(is_add=1,
4993                                                   external_addr=external_addr,
4994                                                   external_port=external_port,
4995                                                   protocol=IP_PROTOS.tcp,
4996                                                   local_num=len(locals),
4997                                                   locals=locals)
4998         flags = self.config_flags.NAT_IS_INSIDE
4999         self.vapi.nat44_interface_add_del_feature(
5000             sw_if_index=self.pg0.sw_if_index,
5001             flags=flags, is_add=1)
5002         self.vapi.nat44_interface_add_del_feature(
5003             sw_if_index=self.pg1.sw_if_index,
5004             is_add=1)
5005
5006         server1_n = 0
5007         server2_n = 0
5008         clients = ip4_range(self.pg1.remote_ip4, 10, 50)
5009         pkts = []
5010         for client in clients:
5011             p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
5012                  IP(src=client, dst=self.nat_addr) /
5013                  TCP(sport=12345, dport=external_port))
5014             pkts.append(p)
5015         self.pg1.add_stream(pkts)
5016         self.pg_enable_capture(self.pg_interfaces)
5017         self.pg_start()
5018         capture = self.pg0.get_capture(len(pkts))
5019         for p in capture:
5020             if p[IP].dst == server1.ip4:
5021                 server1_n += 1
5022             else:
5023                 server2_n += 1
5024         self.assertGreater(server1_n, server2_n)
5025
5026         local = {
5027             'addr': server3.ip4n,
5028             'port': local_port,
5029             'probability': 20,
5030             'vrf_id': 0
5031         }
5032
5033         # add new back-end
5034         self.vapi.nat44_lb_static_mapping_add_del_local(
5035             is_add=1,
5036             external_addr=external_addr,
5037             external_port=external_port,
5038             local=local,
5039             protocol=IP_PROTOS.tcp)
5040         server1_n = 0
5041         server2_n = 0
5042         server3_n = 0
5043         clients = ip4_range(self.pg1.remote_ip4, 60, 110)
5044         pkts = []
5045         for client in clients:
5046             p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
5047                  IP(src=client, dst=self.nat_addr) /
5048                  TCP(sport=12346, dport=external_port))
5049             pkts.append(p)
5050         self.assertGreater(len(pkts), 0)
5051         self.pg1.add_stream(pkts)
5052         self.pg_enable_capture(self.pg_interfaces)
5053         self.pg_start()
5054         capture = self.pg0.get_capture(len(pkts))
5055         for p in capture:
5056             if p[IP].dst == server1.ip4:
5057                 server1_n += 1
5058             elif p[IP].dst == server2.ip4:
5059                 server2_n += 1
5060             else:
5061                 server3_n += 1
5062         self.assertGreater(server1_n, 0)
5063         self.assertGreater(server2_n, 0)
5064         self.assertGreater(server3_n, 0)
5065
5066         local = {
5067             'addr': server2.ip4n,
5068             'port': local_port,
5069             'probability': 10,
5070             'vrf_id': 0
5071         }
5072
5073         # remove one back-end
5074         self.vapi.nat44_lb_static_mapping_add_del_local(
5075             is_add=0,
5076             external_addr=external_addr,
5077             external_port=external_port,
5078             local=local,
5079             protocol=IP_PROTOS.tcp)
5080         server1_n = 0
5081         server2_n = 0
5082         server3_n = 0
5083         self.pg1.add_stream(pkts)
5084         self.pg_enable_capture(self.pg_interfaces)
5085         self.pg_start()
5086         capture = self.pg0.get_capture(len(pkts))
5087         for p in capture:
5088             if p[IP].dst == server1.ip4:
5089                 server1_n += 1
5090             elif p[IP].dst == server2.ip4:
5091                 server2_n += 1
5092             else:
5093                 server3_n += 1
5094         self.assertGreater(server1_n, 0)
5095         self.assertEqual(server2_n, 0)
5096         self.assertGreater(server3_n, 0)
5097
5098     def test_static_lb_2(self):
5099         """ NAT44 local service load balancing (asymmetrical rule) """
5100         external_addr = self.nat_addr
5101         external_port = 80
5102         local_port = 8080
5103         server1 = self.pg0.remote_hosts[0]
5104         server2 = self.pg0.remote_hosts[1]
5105
5106         locals = [{'addr': server1.ip4n,
5107                    'port': local_port,
5108                    'probability': 70,
5109                    'vrf_id': 0},
5110                   {'addr': server2.ip4n,
5111                    'port': local_port,
5112                    'probability': 30,
5113                    'vrf_id': 0}]
5114
5115         self.vapi.nat44_forwarding_enable_disable(enable=1)
5116         flags = self.config_flags.NAT_IS_OUT2IN_ONLY
5117         self.vapi.nat44_add_del_lb_static_mapping(is_add=1, flags=flags,
5118                                                   external_addr=external_addr,
5119                                                   external_port=external_port,
5120                                                   protocol=IP_PROTOS.tcp,
5121                                                   local_num=len(locals),
5122                                                   locals=locals)
5123         flags = self.config_flags.NAT_IS_INSIDE
5124         self.vapi.nat44_interface_add_del_feature(
5125             sw_if_index=self.pg0.sw_if_index,
5126             flags=flags, is_add=1)
5127         self.vapi.nat44_interface_add_del_feature(
5128             sw_if_index=self.pg1.sw_if_index,
5129             is_add=1)
5130
5131         # from client to service
5132         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
5133              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
5134              TCP(sport=12345, dport=external_port))
5135         self.pg1.add_stream(p)
5136         self.pg_enable_capture(self.pg_interfaces)
5137         self.pg_start()
5138         capture = self.pg0.get_capture(1)
5139         p = capture[0]
5140         server = None
5141         try:
5142             ip = p[IP]
5143             tcp = p[TCP]
5144             self.assertIn(ip.dst, [server1.ip4, server2.ip4])
5145             if ip.dst == server1.ip4:
5146                 server = server1
5147             else:
5148                 server = server2
5149             self.assertEqual(tcp.dport, local_port)
5150             self.assert_packet_checksums_valid(p)
5151         except:
5152             self.logger.error(ppp("Unexpected or invalid packet:", p))
5153             raise
5154
5155         # from service back to client
5156         p = (Ether(src=server.mac, dst=self.pg0.local_mac) /
5157              IP(src=server.ip4, dst=self.pg1.remote_ip4) /
5158              TCP(sport=local_port, dport=12345))
5159         self.pg0.add_stream(p)
5160         self.pg_enable_capture(self.pg_interfaces)
5161         self.pg_start()
5162         capture = self.pg1.get_capture(1)
5163         p = capture[0]
5164         try:
5165             ip = p[IP]
5166             tcp = p[TCP]
5167             self.assertEqual(ip.src, self.nat_addr)
5168             self.assertEqual(tcp.sport, external_port)
5169             self.assert_packet_checksums_valid(p)
5170         except:
5171             self.logger.error(ppp("Unexpected or invalid packet:", p))
5172             raise
5173
5174         # from client to server (no translation)
5175         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
5176              IP(src=self.pg1.remote_ip4, dst=server1.ip4) /
5177              TCP(sport=12346, dport=local_port))
5178         self.pg1.add_stream(p)
5179         self.pg_enable_capture(self.pg_interfaces)
5180         self.pg_start()
5181         capture = self.pg0.get_capture(1)
5182         p = capture[0]
5183         server = None
5184         try:
5185             ip = p[IP]
5186             tcp = p[TCP]
5187             self.assertEqual(ip.dst, server1.ip4)
5188             self.assertEqual(tcp.dport, local_port)
5189             self.assert_packet_checksums_valid(p)
5190         except:
5191             self.logger.error(ppp("Unexpected or invalid packet:", p))
5192             raise
5193
5194         # from service back to client (no translation)
5195         p = (Ether(src=server1.mac, dst=self.pg0.local_mac) /
5196              IP(src=server1.ip4, dst=self.pg1.remote_ip4) /
5197              TCP(sport=local_port, dport=12346))
5198         self.pg0.add_stream(p)
5199         self.pg_enable_capture(self.pg_interfaces)
5200         self.pg_start()
5201         capture = self.pg1.get_capture(1)
5202         p = capture[0]
5203         try:
5204             ip = p[IP]
5205             tcp = p[TCP]
5206             self.assertEqual(ip.src, server1.ip4)
5207             self.assertEqual(tcp.sport, local_port)
5208             self.assert_packet_checksums_valid(p)
5209         except:
5210             self.logger.error(ppp("Unexpected or invalid packet:", p))
5211             raise
5212
5213     def test_lb_affinity(self):
5214         """ NAT44 local service load balancing affinity """
5215         external_addr = self.nat_addr
5216         external_port = 80
5217         local_port = 8080
5218         server1 = self.pg0.remote_hosts[0]
5219         server2 = self.pg0.remote_hosts[1]
5220
5221         locals = [{'addr': server1.ip4n,
5222                    'port': local_port,
5223                    'probability': 50,
5224                    'vrf_id': 0},
5225                   {'addr': server2.ip4n,
5226                    'port': local_port,
5227                    'probability': 50,
5228                    'vrf_id': 0}]
5229
5230         self.nat44_add_address(self.nat_addr)
5231         self.vapi.nat44_add_del_lb_static_mapping(is_add=1,
5232                                                   external_addr=external_addr,
5233                                                   external_port=external_port,
5234                                                   protocol=IP_PROTOS.tcp,
5235                                                   affinity=10800,
5236                                                   local_num=len(locals),
5237                                                   locals=locals)
5238         flags = self.config_flags.NAT_IS_INSIDE
5239         self.vapi.nat44_interface_add_del_feature(
5240             sw_if_index=self.pg0.sw_if_index,
5241             flags=flags, is_add=1)
5242         self.vapi.nat44_interface_add_del_feature(
5243             sw_if_index=self.pg1.sw_if_index,
5244             is_add=1)
5245
5246         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
5247              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
5248              TCP(sport=1025, dport=external_port))
5249         self.pg1.add_stream(p)
5250         self.pg_enable_capture(self.pg_interfaces)
5251         self.pg_start()
5252         capture = self.pg0.get_capture(1)
5253         backend = capture[0][IP].dst
5254
5255         sessions = self.vapi.nat44_user_session_dump(backend, 0)
5256         self.assertEqual(len(sessions), 1)
5257         self.assertTrue(sessions[0].flags &
5258                         self.config_flags.NAT_IS_EXT_HOST_VALID)
5259         self.vapi.nat44_del_session(
5260             address=sessions[0].inside_ip_address,
5261             port=sessions[0].inside_port,
5262             protocol=sessions[0].protocol,
5263             flags=(self.config_flags.NAT_IS_INSIDE |
5264                    self.config_flags.NAT_IS_EXT_HOST_VALID),
5265             ext_host_address=sessions[0].ext_host_address,
5266             ext_host_port=sessions[0].ext_host_port)
5267
5268         pkts = []
5269         for port in range(1030, 1100):
5270             p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
5271                  IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
5272                  TCP(sport=port, dport=external_port))
5273             pkts.append(p)
5274         self.pg1.add_stream(pkts)
5275         self.pg_enable_capture(self.pg_interfaces)
5276         self.pg_start()
5277         capture = self.pg0.get_capture(len(pkts))
5278         for p in capture:
5279             self.assertEqual(p[IP].dst, backend)
5280
5281     def test_unknown_proto(self):
5282         """ NAT44 translate packet with unknown protocol """
5283         self.nat44_add_address(self.nat_addr)
5284         flags = self.config_flags.NAT_IS_INSIDE
5285         self.vapi.nat44_interface_add_del_feature(
5286             sw_if_index=self.pg0.sw_if_index,
5287             flags=flags, is_add=1)
5288         self.vapi.nat44_interface_add_del_feature(
5289             sw_if_index=self.pg1.sw_if_index,
5290             is_add=1)
5291
5292         # in2out
5293         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
5294              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
5295              TCP(sport=self.tcp_port_in, dport=20))
5296         self.pg0.add_stream(p)
5297         self.pg_enable_capture(self.pg_interfaces)
5298         self.pg_start()
5299         p = self.pg1.get_capture(1)
5300
5301         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
5302              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
5303              GRE() /
5304              IP(src=self.pg2.remote_ip4, dst=self.pg2.remote_ip4) /
5305              TCP(sport=1234, dport=1234))
5306         self.pg0.add_stream(p)
5307         self.pg_enable_capture(self.pg_interfaces)
5308         self.pg_start()
5309         p = self.pg1.get_capture(1)
5310         packet = p[0]
5311         try:
5312             self.assertEqual(packet[IP].src, self.nat_addr)
5313             self.assertEqual(packet[IP].dst, self.pg1.remote_ip4)
5314             self.assertEqual(packet.haslayer(GRE), 1)
5315             self.assert_packet_checksums_valid(packet)
5316         except:
5317             self.logger.error(ppp("Unexpected or invalid packet:", packet))
5318             raise
5319
5320         # out2in
5321         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
5322              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
5323              GRE() /
5324              IP(src=self.pg2.remote_ip4, dst=self.pg2.remote_ip4) /
5325              TCP(sport=1234, dport=1234))
5326         self.pg1.add_stream(p)
5327         self.pg_enable_capture(self.pg_interfaces)
5328         self.pg_start()
5329         p = self.pg0.get_capture(1)
5330         packet = p[0]
5331         try:
5332             self.assertEqual(packet[IP].src, self.pg1.remote_ip4)
5333             self.assertEqual(packet[IP].dst, self.pg0.remote_ip4)
5334             self.assertEqual(packet.haslayer(GRE), 1)
5335             self.assert_packet_checksums_valid(packet)
5336         except:
5337             self.logger.error(ppp("Unexpected or invalid packet:", packet))
5338             raise
5339
5340     def test_hairpinning_unknown_proto(self):
5341         """ NAT44 translate packet with unknown protocol - hairpinning """
5342         host = self.pg0.remote_hosts[0]
5343         server = self.pg0.remote_hosts[1]
5344         host_in_port = 1234
5345         server_out_port = 8765
5346         server_nat_ip = "10.0.0.11"
5347
5348         self.nat44_add_address(self.nat_addr)
5349         flags = self.config_flags.NAT_IS_INSIDE
5350         self.vapi.nat44_interface_add_del_feature(
5351             sw_if_index=self.pg0.sw_if_index,
5352             flags=flags, is_add=1)
5353         self.vapi.nat44_interface_add_del_feature(
5354             sw_if_index=self.pg1.sw_if_index,
5355             is_add=1)
5356
5357         # add static mapping for server
5358         self.nat44_add_static_mapping(server.ip4, server_nat_ip)
5359
5360         # host to server
5361         p = (Ether(src=host.mac, dst=self.pg0.local_mac) /
5362              IP(src=host.ip4, dst=server_nat_ip) /
5363              TCP(sport=host_in_port, dport=server_out_port))
5364         self.pg0.add_stream(p)
5365         self.pg_enable_capture(self.pg_interfaces)
5366         self.pg_start()
5367         self.pg0.get_capture(1)
5368
5369         p = (Ether(dst=self.pg0.local_mac, src=host.mac) /
5370              IP(src=host.ip4, dst=server_nat_ip) /
5371              GRE() /
5372              IP(src=self.pg2.remote_ip4, dst=self.pg2.remote_ip4) /
5373              TCP(sport=1234, dport=1234))
5374         self.pg0.add_stream(p)
5375         self.pg_enable_capture(self.pg_interfaces)
5376         self.pg_start()
5377         p = self.pg0.get_capture(1)
5378         packet = p[0]
5379         try:
5380             self.assertEqual(packet[IP].src, self.nat_addr)
5381             self.assertEqual(packet[IP].dst, server.ip4)
5382             self.assertEqual(packet.haslayer(GRE), 1)
5383             self.assert_packet_checksums_valid(packet)
5384         except:
5385             self.logger.error(ppp("Unexpected or invalid packet:", packet))
5386             raise
5387
5388         # server to host
5389         p = (Ether(dst=self.pg0.local_mac, src=server.mac) /
5390              IP(src=server.ip4, dst=self.nat_addr) /
5391              GRE() /
5392              IP(src=self.pg2.remote_ip4, dst=self.pg2.remote_ip4) /
5393              TCP(sport=1234, dport=1234))
5394         self.pg0.add_stream(p)
5395         self.pg_enable_capture(self.pg_interfaces)
5396         self.pg_start()
5397         p = self.pg0.get_capture(1)
5398         packet = p[0]
5399         try:
5400             self.assertEqual(packet[IP].src, server_nat_ip)
5401             self.assertEqual(packet[IP].dst, host.ip4)
5402             self.assertEqual(packet.haslayer(GRE), 1)
5403             self.assert_packet_checksums_valid(packet)
5404         except:
5405             self.logger.error(ppp("Unexpected or invalid packet:", packet))
5406             raise
5407
5408     def test_output_feature_and_service(self):
5409         """ NAT44 interface output feature and services """
5410         external_addr = '1.2.3.4'
5411         external_port = 80
5412         local_port = 8080
5413
5414         self.vapi.nat44_forwarding_enable_disable(enable=1)
5415         self.nat44_add_address(self.nat_addr)
5416         flags = self.config_flags.NAT_IS_ADDR_ONLY
5417         self.vapi.nat44_add_del_identity_mapping(
5418             ip_address=self.pg1.remote_ip4n, sw_if_index=0xFFFFFFFF,
5419             flags=flags, is_add=1)
5420         flags = self.config_flags.NAT_IS_OUT2IN_ONLY
5421         self.nat44_add_static_mapping(self.pg0.remote_ip4, external_addr,
5422                                       local_port, external_port,
5423                                       proto=IP_PROTOS.tcp, flags=flags)
5424         flags = self.config_flags.NAT_IS_INSIDE
5425         self.vapi.nat44_interface_add_del_feature(
5426             sw_if_index=self.pg0.sw_if_index,
5427             is_add=1)
5428         self.vapi.nat44_interface_add_del_feature(
5429             sw_if_index=self.pg0.sw_if_index,
5430             flags=flags, is_add=1)
5431         self.vapi.nat44_interface_add_del_output_feature(
5432             is_add=1,
5433             sw_if_index=self.pg1.sw_if_index)
5434
5435         # from client to service
5436         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
5437              IP(src=self.pg1.remote_ip4, dst=external_addr) /
5438              TCP(sport=12345, dport=external_port))
5439         self.pg1.add_stream(p)
5440         self.pg_enable_capture(self.pg_interfaces)
5441         self.pg_start()
5442         capture = self.pg0.get_capture(1)
5443         p = capture[0]
5444         try:
5445             ip = p[IP]
5446             tcp = p[TCP]
5447             self.assertEqual(ip.dst, self.pg0.remote_ip4)
5448             self.assertEqual(tcp.dport, local_port)
5449             self.assert_packet_checksums_valid(p)
5450         except:
5451             self.logger.error(ppp("Unexpected or invalid packet:", p))
5452             raise
5453
5454         # from service back to client
5455         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
5456              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
5457              TCP(sport=local_port, dport=12345))
5458         self.pg0.add_stream(p)
5459         self.pg_enable_capture(self.pg_interfaces)
5460         self.pg_start()
5461         capture = self.pg1.get_capture(1)
5462         p = capture[0]
5463         try:
5464             ip = p[IP]
5465             tcp = p[TCP]
5466             self.assertEqual(ip.src, external_addr)
5467             self.assertEqual(tcp.sport, external_port)
5468             self.assert_packet_checksums_valid(p)
5469         except:
5470             self.logger.error(ppp("Unexpected or invalid packet:", p))
5471             raise
5472
5473         # from local network host to external network
5474         pkts = self.create_stream_in(self.pg0, self.pg1)
5475         self.pg0.add_stream(pkts)
5476         self.pg_enable_capture(self.pg_interfaces)
5477         self.pg_start()
5478         capture = self.pg1.get_capture(len(pkts))
5479         self.verify_capture_out(capture)
5480         pkts = self.create_stream_in(self.pg0, self.pg1)
5481         self.pg0.add_stream(pkts)
5482         self.pg_enable_capture(self.pg_interfaces)
5483         self.pg_start()
5484         capture = self.pg1.get_capture(len(pkts))
5485         self.verify_capture_out(capture)
5486
5487         # from external network back to local network host
5488         pkts = self.create_stream_out(self.pg1)
5489         self.pg1.add_stream(pkts)
5490         self.pg_enable_capture(self.pg_interfaces)
5491         self.pg_start()
5492         capture = self.pg0.get_capture(len(pkts))
5493         self.verify_capture_in(capture, self.pg0)
5494
5495     def test_output_feature_and_service2(self):
5496         """ NAT44 interface output feature and service host direct access """
5497         self.vapi.nat44_forwarding_enable_disable(enable=1)
5498         self.nat44_add_address(self.nat_addr)
5499         self.vapi.nat44_interface_add_del_output_feature(
5500             is_add=1,
5501             sw_if_index=self.pg1.sw_if_index)
5502
5503         # session initiated from service host - translate
5504         pkts = self.create_stream_in(self.pg0, self.pg1)
5505         self.pg0.add_stream(pkts)
5506         self.pg_enable_capture(self.pg_interfaces)
5507         self.pg_start()
5508         capture = self.pg1.get_capture(len(pkts))
5509         self.verify_capture_out(capture)
5510
5511         pkts = self.create_stream_out(self.pg1)
5512         self.pg1.add_stream(pkts)
5513         self.pg_enable_capture(self.pg_interfaces)
5514         self.pg_start()
5515         capture = self.pg0.get_capture(len(pkts))
5516         self.verify_capture_in(capture, self.pg0)
5517
5518         # session initiated from remote host - do not translate
5519         self.tcp_port_in = 60303
5520         self.udp_port_in = 60304
5521         self.icmp_id_in = 60305
5522         pkts = self.create_stream_out(self.pg1,
5523                                       self.pg0.remote_ip4,
5524                                       use_inside_ports=True)
5525         self.pg1.add_stream(pkts)
5526         self.pg_enable_capture(self.pg_interfaces)
5527         self.pg_start()
5528         capture = self.pg0.get_capture(len(pkts))
5529         self.verify_capture_in(capture, self.pg0)
5530
5531         pkts = self.create_stream_in(self.pg0, self.pg1)
5532         self.pg0.add_stream(pkts)
5533         self.pg_enable_capture(self.pg_interfaces)
5534         self.pg_start()
5535         capture = self.pg1.get_capture(len(pkts))
5536         self.verify_capture_out(capture, nat_ip=self.pg0.remote_ip4,
5537                                 same_port=True)
5538
5539     def test_output_feature_and_service3(self):
5540         """ NAT44 interface output feature and DST NAT """
5541         external_addr = '1.2.3.4'
5542         external_port = 80
5543         local_port = 8080
5544
5545         self.vapi.nat44_forwarding_enable_disable(enable=1)
5546         self.nat44_add_address(self.nat_addr)
5547         flags = self.config_flags.NAT_IS_OUT2IN_ONLY
5548         self.nat44_add_static_mapping(self.pg1.remote_ip4, external_addr,
5549                                       local_port, external_port,
5550                                       proto=IP_PROTOS.tcp, flags=flags)
5551         flags = self.config_flags.NAT_IS_INSIDE
5552         self.vapi.nat44_interface_add_del_feature(
5553             sw_if_index=self.pg0.sw_if_index,
5554             is_add=1)
5555         self.vapi.nat44_interface_add_del_feature(
5556             sw_if_index=self.pg0.sw_if_index,
5557             flags=flags, is_add=1)
5558         self.vapi.nat44_interface_add_del_output_feature(
5559             is_add=1,
5560             sw_if_index=self.pg1.sw_if_index)
5561
5562         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
5563              IP(src=self.pg0.remote_ip4, dst=external_addr) /
5564              TCP(sport=12345, dport=external_port))
5565         self.pg0.add_stream(p)
5566         self.pg_enable_capture(self.pg_interfaces)
5567         self.pg_start()
5568         capture = self.pg1.get_capture(1)
5569         p = capture[0]
5570         try:
5571             ip = p[IP]
5572             tcp = p[TCP]
5573             self.assertEqual(ip.src, self.pg0.remote_ip4)
5574             self.assertEqual(tcp.sport, 12345)
5575             self.assertEqual(ip.dst, self.pg1.remote_ip4)
5576             self.assertEqual(tcp.dport, local_port)
5577             self.assert_packet_checksums_valid(p)
5578         except:
5579             self.logger.error(ppp("Unexpected or invalid packet:", p))
5580             raise
5581
5582         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
5583              IP(src=self.pg1.remote_ip4, dst=self.pg0.remote_ip4) /
5584              TCP(sport=local_port, dport=12345))
5585         self.pg1.add_stream(p)
5586         self.pg_enable_capture(self.pg_interfaces)
5587         self.pg_start()
5588         capture = self.pg0.get_capture(1)
5589         p = capture[0]
5590         try:
5591             ip = p[IP]
5592             tcp = p[TCP]
5593             self.assertEqual(ip.src, external_addr)
5594             self.assertEqual(tcp.sport, external_port)
5595             self.assertEqual(ip.dst, self.pg0.remote_ip4)
5596             self.assertEqual(tcp.dport, 12345)
5597             self.assert_packet_checksums_valid(p)
5598         except:
5599             self.logger.error(ppp("Unexpected or invalid packet:", p))
5600             raise
5601
5602     def test_next_src_nat(self):
5603         """ On way back forward packet to nat44-in2out node. """
5604         twice_nat_addr = '10.0.1.3'
5605         external_port = 80
5606         local_port = 8080
5607         post_twice_nat_port = 0
5608
5609         self.vapi.nat44_forwarding_enable_disable(enable=1)
5610         self.nat44_add_address(twice_nat_addr, twice_nat=1)
5611         flags = (self.config_flags.NAT_IS_OUT2IN_ONLY |
5612                  self.config_flags.NAT_IS_SELF_TWICE_NAT)
5613         self.nat44_add_static_mapping(self.pg6.remote_ip4, self.pg1.remote_ip4,
5614                                       local_port, external_port,
5615                                       proto=IP_PROTOS.tcp, vrf_id=1,
5616                                       flags=flags)
5617         self.vapi.nat44_interface_add_del_feature(
5618             sw_if_index=self.pg6.sw_if_index,
5619             is_add=1)
5620
5621         p = (Ether(src=self.pg6.remote_mac, dst=self.pg6.local_mac) /
5622              IP(src=self.pg6.remote_ip4, dst=self.pg1.remote_ip4) /
5623              TCP(sport=12345, dport=external_port))
5624         self.pg6.add_stream(p)
5625         self.pg_enable_capture(self.pg_interfaces)
5626         self.pg_start()
5627         capture = self.pg6.get_capture(1)
5628         p = capture[0]
5629         try:
5630             ip = p[IP]
5631             tcp = p[TCP]
5632             self.assertEqual(ip.src, twice_nat_addr)
5633             self.assertNotEqual(tcp.sport, 12345)
5634             post_twice_nat_port = tcp.sport
5635             self.assertEqual(ip.dst, self.pg6.remote_ip4)
5636             self.assertEqual(tcp.dport, local_port)
5637             self.assert_packet_checksums_valid(p)
5638         except:
5639             self.logger.error(ppp("Unexpected or invalid packet:", p))
5640             raise
5641
5642         p = (Ether(src=self.pg6.remote_mac, dst=self.pg6.local_mac) /
5643              IP(src=self.pg6.remote_ip4, dst=twice_nat_addr) /
5644              TCP(sport=local_port, dport=post_twice_nat_port))
5645         self.pg6.add_stream(p)
5646         self.pg_enable_capture(self.pg_interfaces)
5647         self.pg_start()
5648         capture = self.pg6.get_capture(1)
5649         p = capture[0]
5650         try:
5651             ip = p[IP]
5652             tcp = p[TCP]
5653             self.assertEqual(ip.src, self.pg1.remote_ip4)
5654             self.assertEqual(tcp.sport, external_port)
5655             self.assertEqual(ip.dst, self.pg6.remote_ip4)
5656             self.assertEqual(tcp.dport, 12345)
5657             self.assert_packet_checksums_valid(p)
5658         except:
5659             self.logger.error(ppp("Unexpected or invalid packet:", p))
5660             raise
5661
5662     def twice_nat_common(self, self_twice_nat=False, same_pg=False, lb=False,
5663                          client_id=None):
5664         twice_nat_addr = '10.0.1.3'
5665
5666         port_in = 8080
5667         if lb:
5668             if not same_pg:
5669                 port_in1 = port_in
5670                 port_in2 = port_in
5671             else:
5672                 port_in1 = port_in + 1
5673                 port_in2 = port_in + 2
5674
5675         port_out = 80
5676         eh_port_out = 4567
5677
5678         server1 = self.pg0.remote_hosts[0]
5679         server2 = self.pg0.remote_hosts[1]
5680         if lb and same_pg:
5681             server2 = server1
5682         if not lb:
5683             server = server1
5684
5685         pg0 = self.pg0
5686         if same_pg:
5687             pg1 = self.pg0
5688         else:
5689             pg1 = self.pg1
5690
5691         eh_translate = ((not self_twice_nat) or (not lb and same_pg) or
5692                         client_id == 1)
5693
5694         self.nat44_add_address(self.nat_addr)
5695         self.nat44_add_address(twice_nat_addr, twice_nat=1)
5696
5697         flags = 0
5698         if self_twice_nat:
5699             flags |= self.config_flags.NAT_IS_SELF_TWICE_NAT
5700         else:
5701             flags |= self.config_flags.NAT_IS_TWICE_NAT
5702
5703         if not lb:
5704             self.nat44_add_static_mapping(pg0.remote_ip4, self.nat_addr,
5705                                           port_in, port_out,
5706                                           proto=IP_PROTOS.tcp,
5707                                           flags=flags)
5708         else:
5709             locals = [{'addr': server1.ip4n,
5710                        'port': port_in1,
5711                        'probability': 50,
5712                        'vrf_id': 0},
5713                       {'addr': server2.ip4n,
5714                        'port': port_in2,
5715                        'probability': 50,
5716                        'vrf_id': 0}]
5717             out_addr = self.nat_addr
5718
5719             self.vapi.nat44_add_del_lb_static_mapping(is_add=1, flags=flags,
5720                                                       external_addr=out_addr,
5721                                                       external_port=port_out,
5722                                                       protocol=IP_PROTOS.tcp,
5723                                                       local_num=len(locals),
5724                                                       locals=locals)
5725         flags = self.config_flags.NAT_IS_INSIDE
5726         self.vapi.nat44_interface_add_del_feature(
5727             sw_if_index=pg0.sw_if_index,
5728             flags=flags, is_add=1)
5729         self.vapi.nat44_interface_add_del_feature(
5730             sw_if_index=pg1.sw_if_index,
5731             is_add=1)
5732
5733         if same_pg:
5734             if not lb:
5735                 client = server
5736             else:
5737                 assert client_id is not None
5738                 if client_id == 1:
5739                     client = self.pg0.remote_hosts[0]
5740                 elif client_id == 2:
5741                     client = self.pg0.remote_hosts[1]
5742         else:
5743             client = pg1.remote_hosts[0]
5744         p = (Ether(src=pg1.remote_mac, dst=pg1.local_mac) /
5745              IP(src=client.ip4, dst=self.nat_addr) /
5746              TCP(sport=eh_port_out, dport=port_out))
5747         pg1.add_stream(p)
5748         self.pg_enable_capture(self.pg_interfaces)
5749         self.pg_start()
5750         capture = pg0.get_capture(1)
5751         p = capture[0]
5752         try:
5753             ip = p[IP]
5754             tcp = p[TCP]
5755             if lb:
5756                 if ip.dst == server1.ip4:
5757                     server = server1
5758                     port_in = port_in1
5759                 else:
5760                     server = server2
5761                     port_in = port_in2
5762             self.assertEqual(ip.dst, server.ip4)
5763             if lb and same_pg:
5764                 self.assertIn(tcp.dport, [port_in1, port_in2])
5765             else:
5766                 self.assertEqual(tcp.dport, port_in)
5767             if eh_translate:
5768                 self.assertEqual(ip.src, twice_nat_addr)
5769                 self.assertNotEqual(tcp.sport, eh_port_out)
5770             else:
5771                 self.assertEqual(ip.src, client.ip4)
5772                 self.assertEqual(tcp.sport, eh_port_out)
5773             eh_addr_in = ip.src
5774             eh_port_in = tcp.sport
5775             saved_port_in = tcp.dport
5776             self.assert_packet_checksums_valid(p)
5777         except:
5778             self.logger.error(ppp("Unexpected or invalid packet:", p))
5779             raise
5780
5781         p = (Ether(src=server.mac, dst=pg0.local_mac) /
5782              IP(src=server.ip4, dst=eh_addr_in) /
5783              TCP(sport=saved_port_in, dport=eh_port_in))
5784         pg0.add_stream(p)
5785         self.pg_enable_capture(self.pg_interfaces)
5786         self.pg_start()
5787         capture = pg1.get_capture(1)
5788         p = capture[0]
5789         try:
5790             ip = p[IP]
5791             tcp = p[TCP]
5792             self.assertEqual(ip.dst, client.ip4)
5793             self.assertEqual(ip.src, self.nat_addr)
5794             self.assertEqual(tcp.dport, eh_port_out)
5795             self.assertEqual(tcp.sport, port_out)
5796             self.assert_packet_checksums_valid(p)
5797         except:
5798             self.logger.error(ppp("Unexpected or invalid packet:", p))
5799             raise
5800
5801         if eh_translate:
5802             sessions = self.vapi.nat44_user_session_dump(server.ip4n, 0)
5803             self.assertEqual(len(sessions), 1)
5804             self.assertTrue(sessions[0].flags &
5805                             self.config_flags.NAT_IS_EXT_HOST_VALID)
5806             self.assertTrue(sessions[0].flags &
5807                             self.config_flags.NAT_IS_TWICE_NAT)
5808             self.logger.error(self.vapi.cli("show nat44 sessions detail"))
5809             self.vapi.nat44_del_session(
5810                 address=sessions[0].inside_ip_address,
5811                 port=sessions[0].inside_port,
5812                 protocol=sessions[0].protocol,
5813                 flags=(self.config_flags.NAT_IS_INSIDE |
5814                        self.config_flags.NAT_IS_EXT_HOST_VALID),
5815                 ext_host_address=sessions[0].ext_host_nat_address,
5816                 ext_host_port=sessions[0].ext_host_nat_port)
5817             sessions = self.vapi.nat44_user_session_dump(server.ip4n, 0)
5818             self.assertEqual(len(sessions), 0)
5819
5820     def test_twice_nat(self):
5821         """ Twice NAT44 """
5822         self.twice_nat_common()
5823
5824     def test_self_twice_nat_positive(self):
5825         """ Self Twice NAT44 (positive test) """
5826         self.twice_nat_common(self_twice_nat=True, same_pg=True)
5827
5828     def test_self_twice_nat_negative(self):
5829         """ Self Twice NAT44 (negative test) """
5830         self.twice_nat_common(self_twice_nat=True)
5831
5832     def test_twice_nat_lb(self):
5833         """ Twice NAT44 local service load balancing """
5834         self.twice_nat_common(lb=True)
5835
5836     def test_self_twice_nat_lb_positive(self):
5837         """ Self Twice NAT44 local service load balancing (positive test) """
5838         self.twice_nat_common(lb=True, self_twice_nat=True, same_pg=True,
5839                               client_id=1)
5840
5841     def test_self_twice_nat_lb_negative(self):
5842         """ Self Twice NAT44 local service load balancing (negative test) """
5843         self.twice_nat_common(lb=True, self_twice_nat=True, same_pg=True,
5844                               client_id=2)
5845
5846     def test_twice_nat_interface_addr(self):
5847         """ Acquire twice NAT44 addresses from interface """
5848         flags = self.config_flags.NAT_IS_TWICE_NAT
5849         self.vapi.nat44_add_del_interface_addr(
5850             is_add=1,
5851             sw_if_index=self.pg3.sw_if_index,
5852             flags=flags)
5853
5854         # no address in NAT pool
5855         adresses = self.vapi.nat44_address_dump()
5856         self.assertEqual(0, len(adresses))
5857
5858         # configure interface address and check NAT address pool
5859         self.pg3.config_ip4()
5860         adresses = self.vapi.nat44_address_dump()
5861         self.assertEqual(1, len(adresses))
5862         self.assertEqual(str(adresses[0].ip_address),
5863                          self.pg3.local_ip4)
5864         self.assertEqual(adresses[0].flags, flags)
5865
5866         # remove interface address and check NAT address pool
5867         self.pg3.unconfig_ip4()
5868         adresses = self.vapi.nat44_address_dump()
5869         self.assertEqual(0, len(adresses))
5870
5871     def test_tcp_close(self):
5872         """ Close TCP session from inside network - output feature """
5873         self.vapi.nat44_forwarding_enable_disable(enable=1)
5874         self.nat44_add_address(self.pg1.local_ip4)
5875         twice_nat_addr = '10.0.1.3'
5876         service_ip = '192.168.16.150'
5877         self.nat44_add_address(twice_nat_addr, twice_nat=1)
5878         flags = self.config_flags.NAT_IS_INSIDE
5879         self.vapi.nat44_interface_add_del_feature(
5880             sw_if_index=self.pg0.sw_if_index,
5881             is_add=1)
5882         self.vapi.nat44_interface_add_del_feature(
5883             sw_if_index=self.pg0.sw_if_index,
5884             flags=flags, is_add=1)
5885         self.vapi.nat44_interface_add_del_output_feature(
5886             is_add=1,
5887             sw_if_index=self.pg1.sw_if_index)
5888         flags = (self.config_flags.NAT_IS_OUT2IN_ONLY |
5889                  self.config_flags.NAT_IS_TWICE_NAT)
5890         self.nat44_add_static_mapping(self.pg0.remote_ip4,
5891                                       service_ip,
5892                                       80,
5893                                       80,
5894                                       proto=IP_PROTOS.tcp,
5895                                       flags=flags)
5896         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4n, 0)
5897         start_sessnum = len(sessions)
5898
5899         # SYN packet out->in
5900         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
5901              IP(src=self.pg1.remote_ip4, dst=service_ip) /
5902              TCP(sport=33898, dport=80, flags="S"))
5903         self.pg1.add_stream(p)
5904         self.pg_enable_capture(self.pg_interfaces)
5905         self.pg_start()
5906         capture = self.pg0.get_capture(1)
5907         p = capture[0]
5908         tcp_port = p[TCP].sport
5909
5910         # SYN + ACK packet in->out
5911         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
5912              IP(src=self.pg0.remote_ip4, dst=twice_nat_addr) /
5913              TCP(sport=80, dport=tcp_port, flags="SA"))
5914         self.pg0.add_stream(p)
5915         self.pg_enable_capture(self.pg_interfaces)
5916         self.pg_start()
5917         self.pg1.get_capture(1)
5918
5919         # ACK packet out->in
5920         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
5921              IP(src=self.pg1.remote_ip4, dst=service_ip) /
5922              TCP(sport=33898, dport=80, flags="A"))
5923         self.pg1.add_stream(p)
5924         self.pg_enable_capture(self.pg_interfaces)
5925         self.pg_start()
5926         self.pg0.get_capture(1)
5927
5928         # FIN packet in -> out
5929         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
5930              IP(src=self.pg0.remote_ip4, dst=twice_nat_addr) /
5931              TCP(sport=80, dport=tcp_port, flags="FA", seq=100, ack=300))
5932         self.pg0.add_stream(p)
5933         self.pg_enable_capture(self.pg_interfaces)
5934         self.pg_start()
5935         self.pg1.get_capture(1)
5936
5937         # FIN+ACK packet out -> in
5938         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
5939              IP(src=self.pg1.remote_ip4, dst=service_ip) /
5940              TCP(sport=33898, dport=80, flags="FA", seq=300, ack=101))
5941         self.pg1.add_stream(p)
5942         self.pg_enable_capture(self.pg_interfaces)
5943         self.pg_start()
5944         self.pg0.get_capture(1)
5945
5946         # ACK packet in -> out
5947         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
5948              IP(src=self.pg0.remote_ip4, dst=twice_nat_addr) /
5949              TCP(sport=80, dport=tcp_port, flags="A", seq=101, ack=301))
5950         self.pg0.add_stream(p)
5951         self.pg_enable_capture(self.pg_interfaces)
5952         self.pg_start()
5953         self.pg1.get_capture(1)
5954
5955         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4n,
5956                                                      0)
5957         self.assertEqual(len(sessions) - start_sessnum, 0)
5958
5959     def test_tcp_session_close_in(self):
5960         """ Close TCP session from inside network """
5961         self.tcp_port_out = 10505
5962         self.nat44_add_address(self.nat_addr)
5963         flags = self.config_flags.NAT_IS_TWICE_NAT
5964         self.nat44_add_static_mapping(self.pg0.remote_ip4,
5965                                       self.nat_addr,
5966                                       self.tcp_port_in,
5967                                       self.tcp_port_out,
5968                                       proto=IP_PROTOS.tcp,
5969                                       flags=flags)
5970         flags = self.config_flags.NAT_IS_INSIDE
5971         self.vapi.nat44_interface_add_del_feature(
5972             sw_if_index=self.pg0.sw_if_index,
5973             flags=flags, is_add=1)
5974         self.vapi.nat44_interface_add_del_feature(
5975             sw_if_index=self.pg1.sw_if_index,
5976             is_add=1)
5977
5978         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4n, 0)
5979         start_sessnum = len(sessions)
5980
5981         self.initiate_tcp_session(self.pg0, self.pg1)
5982
5983         # FIN packet in -> out
5984         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
5985              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
5986              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
5987                  flags="FA", seq=100, ack=300))
5988         self.pg0.add_stream(p)
5989         self.pg_enable_capture(self.pg_interfaces)
5990         self.pg_start()
5991         self.pg1.get_capture(1)
5992
5993         pkts = []
5994
5995         # ACK packet out -> in
5996         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
5997              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
5998              TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
5999                  flags="A", seq=300, ack=101))
6000         pkts.append(p)
6001
6002         # FIN packet out -> in
6003         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
6004              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
6005              TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
6006                  flags="FA", seq=300, ack=101))
6007         pkts.append(p)
6008
6009         self.pg1.add_stream(pkts)
6010         self.pg_enable_capture(self.pg_interfaces)
6011         self.pg_start()
6012         self.pg0.get_capture(2)
6013
6014         # ACK packet in -> out
6015         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6016              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6017              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
6018                  flags="A", seq=101, ack=301))
6019         self.pg0.add_stream(p)
6020         self.pg_enable_capture(self.pg_interfaces)
6021         self.pg_start()
6022         self.pg1.get_capture(1)
6023
6024         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4n,
6025                                                      0)
6026         self.assertEqual(len(sessions) - start_sessnum, 0)
6027
6028     def test_tcp_session_close_out(self):
6029         """ Close TCP session from outside network """
6030         self.tcp_port_out = 10505
6031         self.nat44_add_address(self.nat_addr)
6032         flags = self.config_flags.NAT_IS_TWICE_NAT
6033         self.nat44_add_static_mapping(self.pg0.remote_ip4,
6034                                       self.nat_addr,
6035                                       self.tcp_port_in,
6036                                       self.tcp_port_out,
6037                                       proto=IP_PROTOS.tcp,
6038                                       flags=flags)
6039         flags = self.config_flags.NAT_IS_INSIDE
6040         self.vapi.nat44_interface_add_del_feature(
6041             sw_if_index=self.pg0.sw_if_index,
6042             flags=flags, is_add=1)
6043         self.vapi.nat44_interface_add_del_feature(
6044             sw_if_index=self.pg1.sw_if_index,
6045             is_add=1)
6046
6047         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4n, 0)
6048         start_sessnum = len(sessions)
6049
6050         self.initiate_tcp_session(self.pg0, self.pg1)
6051
6052         # FIN packet out -> in
6053         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
6054              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
6055              TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
6056                  flags="FA", seq=100, ack=300))
6057         self.pg1.add_stream(p)
6058         self.pg_enable_capture(self.pg_interfaces)
6059         self.pg_start()
6060         self.pg0.get_capture(1)
6061
6062         # FIN+ACK packet in -> out
6063         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6064              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6065              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
6066                  flags="FA", seq=300, ack=101))
6067
6068         self.pg0.add_stream(p)
6069         self.pg_enable_capture(self.pg_interfaces)
6070         self.pg_start()
6071         self.pg1.get_capture(1)
6072
6073         # ACK packet out -> in
6074         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
6075              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
6076              TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
6077                  flags="A", seq=101, ack=301))
6078         self.pg1.add_stream(p)
6079         self.pg_enable_capture(self.pg_interfaces)
6080         self.pg_start()
6081         self.pg0.get_capture(1)
6082
6083         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4n,
6084                                                      0)
6085         self.assertEqual(len(sessions) - start_sessnum, 0)
6086
6087     def test_tcp_session_close_simultaneous(self):
6088         """ Close TCP session from inside network """
6089         self.tcp_port_out = 10505
6090         self.nat44_add_address(self.nat_addr)
6091         flags = self.config_flags.NAT_IS_TWICE_NAT
6092         self.nat44_add_static_mapping(self.pg0.remote_ip4,
6093                                       self.nat_addr,
6094                                       self.tcp_port_in,
6095                                       self.tcp_port_out,
6096                                       proto=IP_PROTOS.tcp,
6097                                       flags=flags)
6098         flags = self.config_flags.NAT_IS_INSIDE
6099         self.vapi.nat44_interface_add_del_feature(
6100             sw_if_index=self.pg0.sw_if_index,
6101             flags=flags, is_add=1)
6102         self.vapi.nat44_interface_add_del_feature(
6103             sw_if_index=self.pg1.sw_if_index,
6104             is_add=1)
6105
6106         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4n, 0)
6107         start_sessnum = len(sessions)
6108
6109         self.initiate_tcp_session(self.pg0, self.pg1)
6110
6111         # FIN packet in -> out
6112         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6113              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6114              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
6115                  flags="FA", seq=100, ack=300))
6116         self.pg0.add_stream(p)
6117         self.pg_enable_capture(self.pg_interfaces)
6118         self.pg_start()
6119         self.pg1.get_capture(1)
6120
6121         # FIN packet out -> in
6122         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
6123              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
6124              TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
6125                  flags="FA", seq=300, ack=100))
6126         self.pg1.add_stream(p)
6127         self.pg_enable_capture(self.pg_interfaces)
6128         self.pg_start()
6129         self.pg0.get_capture(1)
6130
6131         # ACK packet in -> out
6132         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6133              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6134              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
6135                  flags="A", seq=101, ack=301))
6136         self.pg0.add_stream(p)
6137         self.pg_enable_capture(self.pg_interfaces)
6138         self.pg_start()
6139         self.pg1.get_capture(1)
6140
6141         # ACK packet out -> in
6142         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
6143              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
6144              TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
6145                  flags="A", seq=301, ack=101))
6146         self.pg1.add_stream(p)
6147         self.pg_enable_capture(self.pg_interfaces)
6148         self.pg_start()
6149         self.pg0.get_capture(1)
6150
6151         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4n,
6152                                                      0)
6153         self.assertEqual(len(sessions) - start_sessnum, 0)
6154
6155     def test_one_armed_nat44_static(self):
6156         """ One armed NAT44 and 1:1 NAPT asymmetrical rule """
6157         remote_host = self.pg4.remote_hosts[0]
6158         local_host = self.pg4.remote_hosts[1]
6159         external_port = 80
6160         local_port = 8080
6161         eh_port_in = 0
6162
6163         self.vapi.nat44_forwarding_enable_disable(enable=1)
6164         self.nat44_add_address(self.nat_addr, twice_nat=1)
6165         flags = (self.config_flags.NAT_IS_OUT2IN_ONLY |
6166                  self.config_flags.NAT_IS_TWICE_NAT)
6167         self.nat44_add_static_mapping(local_host.ip4, self.nat_addr,
6168                                       local_port, external_port,
6169                                       proto=IP_PROTOS.tcp, flags=flags)
6170         flags = self.config_flags.NAT_IS_INSIDE
6171         self.vapi.nat44_interface_add_del_feature(
6172             sw_if_index=self.pg4.sw_if_index,
6173             is_add=1)
6174         self.vapi.nat44_interface_add_del_feature(
6175             sw_if_index=self.pg4.sw_if_index,
6176             flags=flags, is_add=1)
6177
6178         # from client to service
6179         p = (Ether(src=self.pg4.remote_mac, dst=self.pg4.local_mac) /
6180              IP(src=remote_host.ip4, dst=self.nat_addr) /
6181              TCP(sport=12345, dport=external_port))
6182         self.pg4.add_stream(p)
6183         self.pg_enable_capture(self.pg_interfaces)
6184         self.pg_start()
6185         capture = self.pg4.get_capture(1)
6186         p = capture[0]
6187         try:
6188             ip = p[IP]
6189             tcp = p[TCP]
6190             self.assertEqual(ip.dst, local_host.ip4)
6191             self.assertEqual(ip.src, self.nat_addr)
6192             self.assertEqual(tcp.dport, local_port)
6193             self.assertNotEqual(tcp.sport, 12345)
6194             eh_port_in = tcp.sport
6195             self.assert_packet_checksums_valid(p)
6196         except:
6197             self.logger.error(ppp("Unexpected or invalid packet:", p))
6198             raise
6199
6200         # from service back to client
6201         p = (Ether(src=self.pg4.remote_mac, dst=self.pg4.local_mac) /
6202              IP(src=local_host.ip4, dst=self.nat_addr) /
6203              TCP(sport=local_port, dport=eh_port_in))
6204         self.pg4.add_stream(p)
6205         self.pg_enable_capture(self.pg_interfaces)
6206         self.pg_start()
6207         capture = self.pg4.get_capture(1)
6208         p = capture[0]
6209         try:
6210             ip = p[IP]
6211             tcp = p[TCP]
6212             self.assertEqual(ip.src, self.nat_addr)
6213             self.assertEqual(ip.dst, remote_host.ip4)
6214             self.assertEqual(tcp.sport, external_port)
6215             self.assertEqual(tcp.dport, 12345)
6216             self.assert_packet_checksums_valid(p)
6217         except:
6218             self.logger.error(ppp("Unexpected or invalid packet:", p))
6219             raise
6220
6221     def test_static_with_port_out2(self):
6222         """ 1:1 NAPT asymmetrical rule """
6223
6224         external_port = 80
6225         local_port = 8080
6226
6227         self.vapi.nat44_forwarding_enable_disable(enable=1)
6228         flags = self.config_flags.NAT_IS_OUT2IN_ONLY
6229         self.nat44_add_static_mapping(self.pg0.remote_ip4, self.nat_addr,
6230                                       local_port, external_port,
6231                                       proto=IP_PROTOS.tcp, flags=flags)
6232         flags = self.config_flags.NAT_IS_INSIDE
6233         self.vapi.nat44_interface_add_del_feature(
6234             sw_if_index=self.pg0.sw_if_index,
6235             flags=flags, is_add=1)
6236         self.vapi.nat44_interface_add_del_feature(
6237             sw_if_index=self.pg1.sw_if_index,
6238             is_add=1)
6239
6240         # from client to service
6241         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
6242              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
6243              TCP(sport=12345, dport=external_port))
6244         self.pg1.add_stream(p)
6245         self.pg_enable_capture(self.pg_interfaces)
6246         self.pg_start()
6247         capture = self.pg0.get_capture(1)
6248         p = capture[0]
6249         try:
6250             ip = p[IP]
6251             tcp = p[TCP]
6252             self.assertEqual(ip.dst, self.pg0.remote_ip4)
6253             self.assertEqual(tcp.dport, local_port)
6254             self.assert_packet_checksums_valid(p)
6255         except:
6256             self.logger.error(ppp("Unexpected or invalid packet:", p))
6257             raise
6258
6259         # ICMP error
6260         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
6261              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6262              ICMP(type=11) / capture[0][IP])
6263         self.pg0.add_stream(p)
6264         self.pg_enable_capture(self.pg_interfaces)
6265         self.pg_start()
6266         capture = self.pg1.get_capture(1)
6267         p = capture[0]
6268         try:
6269             self.assertEqual(p[IP].src, self.nat_addr)
6270             inner = p[IPerror]
6271             self.assertEqual(inner.dst, self.nat_addr)
6272             self.assertEqual(inner[TCPerror].dport, external_port)
6273         except:
6274             self.logger.error(ppp("Unexpected or invalid packet:", p))
6275             raise
6276
6277         # from service back to client
6278         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6279              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6280              TCP(sport=local_port, dport=12345))
6281         self.pg0.add_stream(p)
6282         self.pg_enable_capture(self.pg_interfaces)
6283         self.pg_start()
6284         capture = self.pg1.get_capture(1)
6285         p = capture[0]
6286         try:
6287             ip = p[IP]
6288             tcp = p[TCP]
6289             self.assertEqual(ip.src, self.nat_addr)
6290             self.assertEqual(tcp.sport, external_port)
6291             self.assert_packet_checksums_valid(p)
6292         except:
6293             self.logger.error(ppp("Unexpected or invalid packet:", p))
6294             raise
6295
6296         # ICMP error
6297         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
6298              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
6299              ICMP(type=11) / capture[0][IP])
6300         self.pg1.add_stream(p)
6301         self.pg_enable_capture(self.pg_interfaces)
6302         self.pg_start()
6303         capture = self.pg0.get_capture(1)
6304         p = capture[0]
6305         try:
6306             self.assertEqual(p[IP].dst, self.pg0.remote_ip4)
6307             inner = p[IPerror]
6308             self.assertEqual(inner.src, self.pg0.remote_ip4)
6309             self.assertEqual(inner[TCPerror].sport, local_port)
6310         except:
6311             self.logger.error(ppp("Unexpected or invalid packet:", p))
6312             raise
6313
6314         # from client to server (no translation)
6315         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
6316              IP(src=self.pg1.remote_ip4, dst=self.pg0.remote_ip4) /
6317              TCP(sport=12346, dport=local_port))
6318         self.pg1.add_stream(p)
6319         self.pg_enable_capture(self.pg_interfaces)
6320         self.pg_start()
6321         capture = self.pg0.get_capture(1)
6322         p = capture[0]
6323         try:
6324             ip = p[IP]
6325             tcp = p[TCP]
6326             self.assertEqual(ip.dst, self.pg0.remote_ip4)
6327             self.assertEqual(tcp.dport, local_port)
6328             self.assert_packet_checksums_valid(p)
6329         except:
6330             self.logger.error(ppp("Unexpected or invalid packet:", p))
6331             raise
6332
6333         # from service back to client (no translation)
6334         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6335              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6336              TCP(sport=local_port, dport=12346))
6337         self.pg0.add_stream(p)
6338         self.pg_enable_capture(self.pg_interfaces)
6339         self.pg_start()
6340         capture = self.pg1.get_capture(1)
6341         p = capture[0]
6342         try:
6343             ip = p[IP]
6344             tcp = p[TCP]
6345             self.assertEqual(ip.src, self.pg0.remote_ip4)
6346             self.assertEqual(tcp.sport, local_port)
6347             self.assert_packet_checksums_valid(p)
6348         except:
6349             self.logger.error(ppp("Unexpected or invalid packet:", p))
6350             raise
6351
6352     def test_output_feature(self):
6353         """ NAT44 interface output feature (in2out postrouting) """
6354         self.vapi.nat44_forwarding_enable_disable(enable=1)
6355         self.nat44_add_address(self.nat_addr)
6356         self.vapi.nat44_interface_add_del_feature(
6357             sw_if_index=self.pg0.sw_if_index,
6358             is_add=1)
6359         self.vapi.nat44_interface_add_del_output_feature(
6360             is_add=1,
6361             sw_if_index=self.pg1.sw_if_index)
6362
6363         # in2out
6364         pkts = self.create_stream_in(self.pg0, self.pg1)
6365         self.pg0.add_stream(pkts)
6366         self.pg_enable_capture(self.pg_interfaces)
6367         self.pg_start()
6368         capture = self.pg1.get_capture(len(pkts))
6369         self.verify_capture_out(capture)
6370
6371         # out2in
6372         pkts = self.create_stream_out(self.pg1)
6373         self.pg1.add_stream(pkts)
6374         self.pg_enable_capture(self.pg_interfaces)
6375         self.pg_start()
6376         capture = self.pg0.get_capture(len(pkts))
6377         self.verify_capture_in(capture, self.pg0)
6378
6379     def test_multiple_vrf(self):
6380         """ Multiple VRF setup """
6381         external_addr = '1.2.3.4'
6382         external_port = 80
6383         local_port = 8080
6384         port = 0
6385
6386         self.vapi.nat44_forwarding_enable_disable(enable=1)
6387         self.nat44_add_address(self.nat_addr)
6388         flags = self.config_flags.NAT_IS_INSIDE
6389         self.vapi.nat44_interface_add_del_feature(
6390             sw_if_index=self.pg0.sw_if_index,
6391             is_add=1)
6392         self.vapi.nat44_interface_add_del_feature(
6393             sw_if_index=self.pg0.sw_if_index,
6394             flags=flags, is_add=1)
6395         self.vapi.nat44_interface_add_del_output_feature(
6396             is_add=1,
6397             sw_if_index=self.pg1.sw_if_index)
6398         self.vapi.nat44_interface_add_del_feature(
6399             sw_if_index=self.pg5.sw_if_index,
6400             is_add=1)
6401         self.vapi.nat44_interface_add_del_feature(
6402             sw_if_index=self.pg5.sw_if_index,
6403             flags=flags, is_add=1)
6404         self.vapi.nat44_interface_add_del_feature(
6405             sw_if_index=self.pg6.sw_if_index,
6406             is_add=1)
6407         flags = self.config_flags.NAT_IS_OUT2IN_ONLY
6408         self.nat44_add_static_mapping(self.pg5.remote_ip4, external_addr,
6409                                       local_port, external_port, vrf_id=1,
6410                                       proto=IP_PROTOS.tcp, flags=flags)
6411         self.nat44_add_static_mapping(
6412             self.pg0.remote_ip4,
6413             external_sw_if_index=self.pg0.sw_if_index,
6414             local_port=local_port,
6415             vrf_id=0,
6416             external_port=external_port,
6417             proto=IP_PROTOS.tcp,
6418             flags=flags
6419         )
6420
6421         # from client to service (both VRF1)
6422         p = (Ether(src=self.pg6.remote_mac, dst=self.pg6.local_mac) /
6423              IP(src=self.pg6.remote_ip4, dst=external_addr) /
6424              TCP(sport=12345, dport=external_port))
6425         self.pg6.add_stream(p)
6426         self.pg_enable_capture(self.pg_interfaces)
6427         self.pg_start()
6428         capture = self.pg5.get_capture(1)
6429         p = capture[0]
6430         try:
6431             ip = p[IP]
6432             tcp = p[TCP]
6433             self.assertEqual(ip.dst, self.pg5.remote_ip4)
6434             self.assertEqual(tcp.dport, local_port)
6435             self.assert_packet_checksums_valid(p)
6436         except:
6437             self.logger.error(ppp("Unexpected or invalid packet:", p))
6438             raise
6439
6440         # from service back to client (both VRF1)
6441         p = (Ether(src=self.pg5.remote_mac, dst=self.pg5.local_mac) /
6442              IP(src=self.pg5.remote_ip4, dst=self.pg6.remote_ip4) /
6443              TCP(sport=local_port, dport=12345))
6444         self.pg5.add_stream(p)
6445         self.pg_enable_capture(self.pg_interfaces)
6446         self.pg_start()
6447         capture = self.pg6.get_capture(1)
6448         p = capture[0]
6449         try:
6450             ip = p[IP]
6451             tcp = p[TCP]
6452             self.assertEqual(ip.src, external_addr)
6453             self.assertEqual(tcp.sport, external_port)
6454             self.assert_packet_checksums_valid(p)
6455         except:
6456             self.logger.error(ppp("Unexpected or invalid packet:", p))
6457             raise
6458
6459         # dynamic NAT from VRF1 to VRF0 (output-feature)
6460         p = (Ether(src=self.pg5.remote_mac, dst=self.pg5.local_mac) /
6461              IP(src=self.pg5.remote_ip4, dst=self.pg1.remote_ip4) /
6462              TCP(sport=2345, dport=22))
6463         self.pg5.add_stream(p)
6464         self.pg_enable_capture(self.pg_interfaces)
6465         self.pg_start()
6466         capture = self.pg1.get_capture(1)
6467         p = capture[0]
6468         try:
6469             ip = p[IP]
6470             tcp = p[TCP]
6471             self.assertEqual(ip.src, self.nat_addr)
6472             self.assertNotEqual(tcp.sport, 2345)
6473             self.assert_packet_checksums_valid(p)
6474             port = tcp.sport
6475         except:
6476             self.logger.error(ppp("Unexpected or invalid packet:", p))
6477             raise
6478
6479         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
6480              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
6481              TCP(sport=22, dport=port))
6482         self.pg1.add_stream(p)
6483         self.pg_enable_capture(self.pg_interfaces)
6484         self.pg_start()
6485         capture = self.pg5.get_capture(1)
6486         p = capture[0]
6487         try:
6488             ip = p[IP]
6489             tcp = p[TCP]
6490             self.assertEqual(ip.dst, self.pg5.remote_ip4)
6491             self.assertEqual(tcp.dport, 2345)
6492             self.assert_packet_checksums_valid(p)
6493         except:
6494             self.logger.error(ppp("Unexpected or invalid packet:", p))
6495             raise
6496
6497         # from client VRF1 to service VRF0
6498         p = (Ether(src=self.pg6.remote_mac, dst=self.pg6.local_mac) /
6499              IP(src=self.pg6.remote_ip4, dst=self.pg0.local_ip4) /
6500              TCP(sport=12346, dport=external_port))
6501         self.pg6.add_stream(p)
6502         self.pg_enable_capture(self.pg_interfaces)
6503         self.pg_start()
6504         capture = self.pg0.get_capture(1)
6505         p = capture[0]
6506         try:
6507             ip = p[IP]
6508             tcp = p[TCP]
6509             self.assertEqual(ip.dst, self.pg0.remote_ip4)
6510             self.assertEqual(tcp.dport, local_port)
6511             self.assert_packet_checksums_valid(p)
6512         except:
6513             self.logger.error(ppp("Unexpected or invalid packet:", p))
6514             raise
6515
6516         # from service VRF0 back to client VRF1
6517         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6518              IP(src=self.pg0.remote_ip4, dst=self.pg6.remote_ip4) /
6519              TCP(sport=local_port, dport=12346))
6520         self.pg0.add_stream(p)
6521         self.pg_enable_capture(self.pg_interfaces)
6522         self.pg_start()
6523         capture = self.pg6.get_capture(1)
6524         p = capture[0]
6525         try:
6526             ip = p[IP]
6527             tcp = p[TCP]
6528             self.assertEqual(ip.src, self.pg0.local_ip4)
6529             self.assertEqual(tcp.sport, external_port)
6530             self.assert_packet_checksums_valid(p)
6531         except:
6532             self.logger.error(ppp("Unexpected or invalid packet:", p))
6533             raise
6534
6535         # from client VRF0 to service VRF1
6536         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6537              IP(src=self.pg0.remote_ip4, dst=external_addr) /
6538              TCP(sport=12347, dport=external_port))
6539         self.pg0.add_stream(p)
6540         self.pg_enable_capture(self.pg_interfaces)
6541         self.pg_start()
6542         capture = self.pg5.get_capture(1)
6543         p = capture[0]
6544         try:
6545             ip = p[IP]
6546             tcp = p[TCP]
6547             self.assertEqual(ip.dst, self.pg5.remote_ip4)
6548             self.assertEqual(tcp.dport, local_port)
6549             self.assert_packet_checksums_valid(p)
6550         except:
6551             self.logger.error(ppp("Unexpected or invalid packet:", p))
6552             raise
6553
6554         # from service VRF1 back to client VRF0
6555         p = (Ether(src=self.pg5.remote_mac, dst=self.pg5.local_mac) /
6556              IP(src=self.pg5.remote_ip4, dst=self.pg0.remote_ip4) /
6557              TCP(sport=local_port, dport=12347))
6558         self.pg5.add_stream(p)
6559         self.pg_enable_capture(self.pg_interfaces)
6560         self.pg_start()
6561         capture = self.pg0.get_capture(1)
6562         p = capture[0]
6563         try:
6564             ip = p[IP]
6565             tcp = p[TCP]
6566             self.assertEqual(ip.src, external_addr)
6567             self.assertEqual(tcp.sport, external_port)
6568             self.assert_packet_checksums_valid(p)
6569         except:
6570             self.logger.error(ppp("Unexpected or invalid packet:", p))
6571             raise
6572
6573         # from client to server (both VRF1, no translation)
6574         p = (Ether(src=self.pg6.remote_mac, dst=self.pg6.local_mac) /
6575              IP(src=self.pg6.remote_ip4, dst=self.pg5.remote_ip4) /
6576              TCP(sport=12348, dport=local_port))
6577         self.pg6.add_stream(p)
6578         self.pg_enable_capture(self.pg_interfaces)
6579         self.pg_start()
6580         capture = self.pg5.get_capture(1)
6581         p = capture[0]
6582         try:
6583             ip = p[IP]
6584             tcp = p[TCP]
6585             self.assertEqual(ip.dst, self.pg5.remote_ip4)
6586             self.assertEqual(tcp.dport, local_port)
6587             self.assert_packet_checksums_valid(p)
6588         except:
6589             self.logger.error(ppp("Unexpected or invalid packet:", p))
6590             raise
6591
6592         # from server back to client (both VRF1, no translation)
6593         p = (Ether(src=self.pg5.remote_mac, dst=self.pg5.local_mac) /
6594              IP(src=self.pg5.remote_ip4, dst=self.pg6.remote_ip4) /
6595              TCP(sport=local_port, dport=12348))
6596         self.pg5.add_stream(p)
6597         self.pg_enable_capture(self.pg_interfaces)
6598         self.pg_start()
6599         capture = self.pg6.get_capture(1)
6600         p = capture[0]
6601         try:
6602             ip = p[IP]
6603             tcp = p[TCP]
6604             self.assertEqual(ip.src, self.pg5.remote_ip4)
6605             self.assertEqual(tcp.sport, local_port)
6606             self.assert_packet_checksums_valid(p)
6607         except:
6608             self.logger.error(ppp("Unexpected or invalid packet:", p))
6609             raise
6610
6611         # from client VRF1 to server VRF0 (no translation)
6612         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6613              IP(src=self.pg0.remote_ip4, dst=self.pg6.remote_ip4) /
6614              TCP(sport=local_port, dport=12349))
6615         self.pg0.add_stream(p)
6616         self.pg_enable_capture(self.pg_interfaces)
6617         self.pg_start()
6618         capture = self.pg6.get_capture(1)
6619         p = capture[0]
6620         try:
6621             ip = p[IP]
6622             tcp = p[TCP]
6623             self.assertEqual(ip.src, self.pg0.remote_ip4)
6624             self.assertEqual(tcp.sport, local_port)
6625             self.assert_packet_checksums_valid(p)
6626         except:
6627             self.logger.error(ppp("Unexpected or invalid packet:", p))
6628             raise
6629
6630         # from server VRF0 back to client VRF1 (no translation)
6631         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6632              IP(src=self.pg0.remote_ip4, dst=self.pg6.remote_ip4) /
6633              TCP(sport=local_port, dport=12349))
6634         self.pg0.add_stream(p)
6635         self.pg_enable_capture(self.pg_interfaces)
6636         self.pg_start()
6637         capture = self.pg6.get_capture(1)
6638         p = capture[0]
6639         try:
6640             ip = p[IP]
6641             tcp = p[TCP]
6642             self.assertEqual(ip.src, self.pg0.remote_ip4)
6643             self.assertEqual(tcp.sport, local_port)
6644             self.assert_packet_checksums_valid(p)
6645         except:
6646             self.logger.error(ppp("Unexpected or invalid packet:", p))
6647             raise
6648
6649         # from client VRF0 to server VRF1 (no translation)
6650         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6651              IP(src=self.pg0.remote_ip4, dst=self.pg5.remote_ip4) /
6652              TCP(sport=12344, dport=local_port))
6653         self.pg0.add_stream(p)
6654         self.pg_enable_capture(self.pg_interfaces)
6655         self.pg_start()
6656         capture = self.pg5.get_capture(1)
6657         p = capture[0]
6658         try:
6659             ip = p[IP]
6660             tcp = p[TCP]
6661             self.assertEqual(ip.dst, self.pg5.remote_ip4)
6662             self.assertEqual(tcp.dport, local_port)
6663             self.assert_packet_checksums_valid(p)
6664         except:
6665             self.logger.error(ppp("Unexpected or invalid packet:", p))
6666             raise
6667
6668         # from server VRF1 back to client VRF0 (no translation)
6669         p = (Ether(src=self.pg5.remote_mac, dst=self.pg5.local_mac) /
6670              IP(src=self.pg5.remote_ip4, dst=self.pg0.remote_ip4) /
6671              TCP(sport=local_port, dport=12344))
6672         self.pg5.add_stream(p)
6673         self.pg_enable_capture(self.pg_interfaces)
6674         self.pg_start()
6675         capture = self.pg0.get_capture(1)
6676         p = capture[0]
6677         try:
6678             ip = p[IP]
6679             tcp = p[TCP]
6680             self.assertEqual(ip.src, self.pg5.remote_ip4)
6681             self.assertEqual(tcp.sport, local_port)
6682             self.assert_packet_checksums_valid(p)
6683         except:
6684             self.logger.error(ppp("Unexpected or invalid packet:", p))
6685             raise
6686
6687     @unittest.skipUnless(running_extended_tests, "part of extended tests")
6688     def test_session_timeout(self):
6689         """ NAT44 session timeouts """
6690         self.nat44_add_address(self.nat_addr)
6691         flags = self.config_flags.NAT_IS_INSIDE
6692         self.vapi.nat44_interface_add_del_feature(
6693             sw_if_index=self.pg0.sw_if_index,
6694             flags=flags, is_add=1)
6695         self.vapi.nat44_interface_add_del_feature(
6696             sw_if_index=self.pg1.sw_if_index,
6697             is_add=1)
6698         self.vapi.nat_set_timeouts(udp=300, tcp_established=7440,
6699                                    tcp_transitory=240, icmp=5)
6700
6701         max_sessions = 1000
6702         pkts = []
6703         for i in range(0, max_sessions):
6704             src = "10.10.%u.%u" % ((i & 0xFF00) >> 8, i & 0xFF)
6705             p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
6706                  IP(src=src, dst=self.pg1.remote_ip4) /
6707                  ICMP(id=1025, type='echo-request'))
6708             pkts.append(p)
6709         self.pg0.add_stream(pkts)
6710         self.pg_enable_capture(self.pg_interfaces)
6711         self.pg_start()
6712         self.pg1.get_capture(max_sessions)
6713
6714         sleep(10)
6715
6716         pkts = []
6717         for i in range(0, max_sessions):
6718             src = "10.11.%u.%u" % ((i & 0xFF00) >> 8, i & 0xFF)
6719             p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
6720                  IP(src=src, dst=self.pg1.remote_ip4) /
6721                  ICMP(id=1026, type='echo-request'))
6722             pkts.append(p)
6723         self.pg0.add_stream(pkts)
6724         self.pg_enable_capture(self.pg_interfaces)
6725         self.pg_start()
6726         self.pg1.get_capture(max_sessions)
6727
6728         nsessions = 0
6729         users = self.vapi.nat44_user_dump()
6730         for user in users:
6731             nsessions = nsessions + user.nsessions
6732         self.assertLess(nsessions, 2 * max_sessions)
6733
6734     @unittest.skipUnless(running_extended_tests, "part of extended tests")
6735     def test_session_rst_timeout(self):
6736         """ NAT44 session RST timeouts """
6737         self.nat44_add_address(self.nat_addr)
6738         flags = self.config_flags.NAT_IS_INSIDE
6739         self.vapi.nat44_interface_add_del_feature(
6740             sw_if_index=self.pg0.sw_if_index,
6741             flags=flags, is_add=1)
6742         self.vapi.nat44_interface_add_del_feature(
6743             sw_if_index=self.pg1.sw_if_index,
6744             is_add=1)
6745         self.vapi.nat_set_timeouts(udp=300, tcp_established=7440,
6746                                    tcp_transitory=5, icmp=60)
6747
6748         self.initiate_tcp_session(self.pg0, self.pg1)
6749         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6750              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6751              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
6752                  flags="R"))
6753         self.pg0.add_stream(p)
6754         self.pg_enable_capture(self.pg_interfaces)
6755         self.pg_start()
6756         self.pg1.get_capture(1)
6757
6758         sleep(6)
6759
6760         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6761              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6762              TCP(sport=self.tcp_port_in + 1, dport=self.tcp_external_port + 1,
6763                  flags="S"))
6764         self.pg0.add_stream(p)
6765         self.pg_enable_capture(self.pg_interfaces)
6766         self.pg_start()
6767         self.pg1.get_capture(1)
6768
6769         nsessions = 0
6770         users = self.vapi.nat44_user_dump()
6771         self.assertEqual(len(users), 1)
6772         self.assertEqual(str(users[0].ip_address),
6773                          self.pg0.remote_ip4)
6774         self.assertEqual(users[0].nsessions, 1)
6775
6776     @unittest.skipUnless(running_extended_tests, "part of extended tests")
6777     def test_session_limit_per_user(self):
6778         """ Maximum sessions per user limit """
6779         self.nat44_add_address(self.nat_addr)
6780         flags = self.config_flags.NAT_IS_INSIDE
6781         self.vapi.nat44_interface_add_del_feature(
6782             sw_if_index=self.pg0.sw_if_index,
6783             flags=flags, is_add=1)
6784         self.vapi.nat44_interface_add_del_feature(
6785             sw_if_index=self.pg1.sw_if_index,
6786             is_add=1)
6787         self.vapi.set_ipfix_exporter(collector_address=self.pg2.remote_ip4n,
6788                                      src_address=self.pg2.local_ip4n,
6789                                      path_mtu=512,
6790                                      template_interval=10)
6791         self.vapi.nat_set_timeouts(udp=5, tcp_established=7440,
6792                                    tcp_transitory=240, icmp=60)
6793
6794         # get maximum number of translations per user
6795         nat44_config = self.vapi.nat_show_config()
6796
6797         pkts = []
6798         for port in range(0, nat44_config.max_translations_per_user):
6799             p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6800                  IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6801                  UDP(sport=1025 + port, dport=1025 + port))
6802             pkts.append(p)
6803
6804         self.pg0.add_stream(pkts)
6805         self.pg_enable_capture(self.pg_interfaces)
6806         self.pg_start()
6807         capture = self.pg1.get_capture(len(pkts))
6808
6809         self.vapi.nat_ipfix_enable_disable(domain_id=self.ipfix_domain_id,
6810                                            src_port=self.ipfix_src_port,
6811                                            enable=1)
6812
6813         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6814              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6815              UDP(sport=3001, dport=3002))
6816         self.pg0.add_stream(p)
6817         self.pg_enable_capture(self.pg_interfaces)
6818         self.pg_start()
6819         capture = self.pg1.assert_nothing_captured()
6820
6821         # verify IPFIX logging
6822         self.vapi.cli("ipfix flush")  # FIXME this should be an API call
6823         sleep(1)
6824         capture = self.pg2.get_capture(10)
6825         ipfix = IPFIXDecoder()
6826         # first load template
6827         for p in capture:
6828             self.assertTrue(p.haslayer(IPFIX))
6829             if p.haslayer(Template):
6830                 ipfix.add_template(p.getlayer(Template))
6831         # verify events in data set
6832         for p in capture:
6833             if p.haslayer(Data):
6834                 data = ipfix.decode_data_set(p.getlayer(Set))
6835                 self.verify_ipfix_max_entries_per_user(
6836                     data,
6837                     nat44_config.max_translations_per_user,
6838                     self.pg0.remote_ip4n)
6839
6840         sleep(6)
6841         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6842              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6843              UDP(sport=3001, dport=3002))
6844         self.pg0.add_stream(p)
6845         self.pg_enable_capture(self.pg_interfaces)
6846         self.pg_start()
6847         self.pg1.get_capture(1)
6848
6849     def test_syslog_sess(self):
6850         """ Test syslog session creation and deletion """
6851         self.vapi.syslog_set_filter(SYSLOG_SEVERITY.INFO)
6852         self.vapi.syslog_set_sender(self.pg2.local_ip4n, self.pg2.remote_ip4n)
6853         self.nat44_add_address(self.nat_addr)
6854         flags = self.config_flags.NAT_IS_INSIDE
6855         self.vapi.nat44_interface_add_del_feature(
6856             sw_if_index=self.pg0.sw_if_index,
6857             flags=flags, is_add=1)
6858         self.vapi.nat44_interface_add_del_feature(
6859             sw_if_index=self.pg1.sw_if_index,
6860             is_add=1)
6861
6862         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
6863              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6864              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port))
6865         self.pg0.add_stream(p)
6866         self.pg_enable_capture(self.pg_interfaces)
6867         self.pg_start()
6868         capture = self.pg1.get_capture(1)
6869         self.tcp_port_out = capture[0][TCP].sport
6870         capture = self.pg2.get_capture(1)
6871         self.verify_syslog_sess(capture[0][Raw].load)
6872
6873         self.pg_enable_capture(self.pg_interfaces)
6874         self.pg_start()
6875         self.nat44_add_address(self.nat_addr, is_add=0)
6876         capture = self.pg2.get_capture(1)
6877         self.verify_syslog_sess(capture[0][Raw].load, False)
6878
6879     def tearDown(self):
6880         super(TestNAT44EndpointDependent, self).tearDown()
6881         if not self.vpp_dead:
6882             self.clear_nat44()
6883             self.vapi.cli("clear logging")
6884
6885     def show_commands_at_teardown(self):
6886         self.logger.info(self.vapi.cli("show nat44 addresses"))
6887         self.logger.info(self.vapi.cli("show nat44 interfaces"))
6888         self.logger.info(self.vapi.cli("show nat44 static mappings"))
6889         self.logger.info(self.vapi.cli("show nat44 interface address"))
6890         self.logger.info(self.vapi.cli("show nat44 sessions detail"))
6891         self.logger.info(self.vapi.cli("show nat44 hash tables detail"))
6892         self.logger.info(self.vapi.cli("show nat timeouts"))
6893
6894
6895 class TestNAT44Out2InDPO(MethodHolder):
6896     """ NAT44 Test Cases using out2in DPO """
6897
6898     @classmethod
6899     def setUpConstants(cls):
6900         super(TestNAT44Out2InDPO, cls).setUpConstants()
6901         cls.vpp_cmdline.extend(["nat", "{", "out2in dpo", "}"])
6902
6903     @classmethod
6904     def setUpClass(cls):
6905         super(TestNAT44Out2InDPO, cls).setUpClass()
6906         cls.vapi.cli("set log class nat level debug")
6907
6908         try:
6909             cls.tcp_port_in = 6303
6910             cls.tcp_port_out = 6303
6911             cls.udp_port_in = 6304
6912             cls.udp_port_out = 6304
6913             cls.icmp_id_in = 6305
6914             cls.icmp_id_out = 6305
6915             cls.nat_addr = '10.0.0.3'
6916             cls.dst_ip4 = '192.168.70.1'
6917
6918             cls.create_pg_interfaces(range(2))
6919
6920             cls.pg0.admin_up()
6921             cls.pg0.config_ip4()
6922             cls.pg0.resolve_arp()
6923
6924             cls.pg1.admin_up()
6925             cls.pg1.config_ip6()
6926             cls.pg1.resolve_ndp()
6927
6928             cls.vapi.ip_add_del_route(dst_address=b'\x00' * 16,
6929                                       dst_address_length=0,
6930                                       next_hop_address=cls.pg1.remote_ip6n,
6931                                       next_hop_sw_if_index=cls.pg1.sw_if_index,
6932                                       is_ipv6=True)
6933
6934         except Exception:
6935             super(TestNAT44Out2InDPO, cls).tearDownClass()
6936             raise
6937
6938     @classmethod
6939     def tearDownClass(cls):
6940         super(TestNAT44Out2InDPO, cls).tearDownClass()
6941
6942     def configure_xlat(self):
6943         self.dst_ip6_pfx = '1:2:3::'
6944         self.dst_ip6_pfx_n = socket.inet_pton(socket.AF_INET6,
6945                                               self.dst_ip6_pfx)
6946         self.dst_ip6_pfx_len = 96
6947         self.src_ip6_pfx = '4:5:6::'
6948         self.src_ip6_pfx_n = socket.inet_pton(socket.AF_INET6,
6949                                               self.src_ip6_pfx)
6950         self.src_ip6_pfx_len = 96
6951         self.vapi.map_add_domain(self.dst_ip6_pfx_n, self.dst_ip6_pfx_len,
6952                                  self.src_ip6_pfx_n, self.src_ip6_pfx_len,
6953                                  '\x00\x00\x00\x00', 0)
6954
6955     @unittest.skip('Temporary disabled')
6956     def test_464xlat_ce(self):
6957         """ Test 464XLAT CE with NAT44 """
6958
6959         nat_config = self.vapi.nat_show_config()
6960         self.assertEqual(1, nat_config.out2in_dpo)
6961
6962         self.configure_xlat()
6963
6964         flags = self.config_flags.NAT_IS_INSIDE
6965         self.vapi.nat44_interface_add_del_feature(
6966             sw_if_index=self.pg0.sw_if_index,
6967             flags=flags, is_add=1)
6968         self.vapi.nat44_add_del_address_range(first_ip_address=self.nat_addr_n,
6969                                               last_ip_address=self.nat_addr_n,
6970                                               vrf_id=0xFFFFFFFF, is_add=1)
6971
6972         out_src_ip6 = self.compose_ip6(self.dst_ip4, self.dst_ip6_pfx,
6973                                        self.dst_ip6_pfx_len)
6974         out_dst_ip6 = self.compose_ip6(self.nat_addr, self.src_ip6_pfx,
6975                                        self.src_ip6_pfx_len)
6976
6977         try:
6978             pkts = self.create_stream_in(self.pg0, self.pg1, self.dst_ip4)
6979             self.pg0.add_stream(pkts)
6980             self.pg_enable_capture(self.pg_interfaces)
6981             self.pg_start()
6982             capture = self.pg1.get_capture(len(pkts))
6983             self.verify_capture_out_ip6(capture, nat_ip=out_dst_ip6,
6984                                         dst_ip=out_src_ip6)
6985
6986             pkts = self.create_stream_out_ip6(self.pg1, out_src_ip6,
6987                                               out_dst_ip6)
6988             self.pg1.add_stream(pkts)
6989             self.pg_enable_capture(self.pg_interfaces)
6990             self.pg_start()
6991             capture = self.pg0.get_capture(len(pkts))
6992             self.verify_capture_in(capture, self.pg0)
6993         finally:
6994             self.vapi.nat44_interface_add_del_feature(
6995                 sw_if_index=self.pg0.sw_if_index,
6996                 flags=flags)
6997             self.vapi.nat44_add_del_address_range(
6998                 first_ip_address=self.nat_addr_n,
6999                 last_ip_address=self.nat_addr_n,
7000                 vrf_id=0xFFFFFFFF)
7001
7002     @unittest.skip('Temporary disabled')
7003     def test_464xlat_ce_no_nat(self):
7004         """ Test 464XLAT CE without NAT44 """
7005
7006         self.configure_xlat()
7007
7008         out_src_ip6 = self.compose_ip6(self.dst_ip4, self.dst_ip6_pfx,
7009                                        self.dst_ip6_pfx_len)
7010         out_dst_ip6 = self.compose_ip6(self.pg0.remote_ip4, self.src_ip6_pfx,
7011                                        self.src_ip6_pfx_len)
7012
7013         pkts = self.create_stream_in(self.pg0, self.pg1, self.dst_ip4)
7014         self.pg0.add_stream(pkts)
7015         self.pg_enable_capture(self.pg_interfaces)
7016         self.pg_start()
7017         capture = self.pg1.get_capture(len(pkts))
7018         self.verify_capture_out_ip6(capture, dst_ip=out_src_ip6,
7019                                     nat_ip=out_dst_ip6, same_port=True)
7020
7021         pkts = self.create_stream_out_ip6(self.pg1, out_src_ip6, out_dst_ip6)
7022         self.pg1.add_stream(pkts)
7023         self.pg_enable_capture(self.pg_interfaces)
7024         self.pg_start()
7025         capture = self.pg0.get_capture(len(pkts))
7026         self.verify_capture_in(capture, self.pg0)
7027
7028
7029 class TestDeterministicNAT(MethodHolder):
7030     """ Deterministic NAT Test Cases """
7031
7032     @classmethod
7033     def setUpConstants(cls):
7034         super(TestDeterministicNAT, cls).setUpConstants()
7035         cls.vpp_cmdline.extend(["nat", "{", "deterministic", "}"])
7036
7037     @classmethod
7038     def setUpClass(cls):
7039         super(TestDeterministicNAT, cls).setUpClass()
7040         cls.vapi.cli("set log class nat level debug")
7041
7042         try:
7043             cls.tcp_port_in = 6303
7044             cls.tcp_external_port = 6303
7045             cls.udp_port_in = 6304
7046             cls.udp_external_port = 6304
7047             cls.icmp_id_in = 6305
7048             cls.nat_addr = '10.0.0.3'
7049
7050             cls.create_pg_interfaces(range(3))
7051             cls.interfaces = list(cls.pg_interfaces)
7052
7053             for i in cls.interfaces:
7054                 i.admin_up()
7055                 i.config_ip4()
7056                 i.resolve_arp()
7057
7058             cls.pg0.generate_remote_hosts(2)
7059             cls.pg0.configure_ipv4_neighbors()
7060
7061         except Exception:
7062             super(TestDeterministicNAT, cls).tearDownClass()
7063             raise
7064
7065     @classmethod
7066     def tearDownClass(cls):
7067         super(TestDeterministicNAT, cls).tearDownClass()
7068
7069     def create_stream_in(self, in_if, out_if, ttl=64):
7070         """
7071         Create packet stream for inside network
7072
7073         :param in_if: Inside interface
7074         :param out_if: Outside interface
7075         :param ttl: TTL of generated packets
7076         """
7077         pkts = []
7078         # TCP
7079         p = (Ether(dst=in_if.local_mac, src=in_if.remote_mac) /
7080              IP(src=in_if.remote_ip4, dst=out_if.remote_ip4, ttl=ttl) /
7081              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port))
7082         pkts.append(p)
7083
7084         # UDP
7085         p = (Ether(dst=in_if.local_mac, src=in_if.remote_mac) /
7086              IP(src=in_if.remote_ip4, dst=out_if.remote_ip4, ttl=ttl) /
7087              UDP(sport=self.udp_port_in, dport=self.udp_external_port))
7088         pkts.append(p)
7089
7090         # ICMP
7091         p = (Ether(dst=in_if.local_mac, src=in_if.remote_mac) /
7092              IP(src=in_if.remote_ip4, dst=out_if.remote_ip4, ttl=ttl) /
7093              ICMP(id=self.icmp_id_in, type='echo-request'))
7094         pkts.append(p)
7095
7096         return pkts
7097
7098     def create_stream_out(self, out_if, dst_ip=None, ttl=64):
7099         """
7100         Create packet stream for outside network
7101
7102         :param out_if: Outside interface
7103         :param dst_ip: Destination IP address (Default use global NAT address)
7104         :param ttl: TTL of generated packets
7105         """
7106         if dst_ip is None:
7107             dst_ip = self.nat_addr
7108         pkts = []
7109         # TCP
7110         p = (Ether(dst=out_if.local_mac, src=out_if.remote_mac) /
7111              IP(src=out_if.remote_ip4, dst=dst_ip, ttl=ttl) /
7112              TCP(dport=self.tcp_port_out, sport=self.tcp_external_port))
7113         pkts.append(p)
7114
7115         # UDP
7116         p = (Ether(dst=out_if.local_mac, src=out_if.remote_mac) /
7117              IP(src=out_if.remote_ip4, dst=dst_ip, ttl=ttl) /
7118              UDP(dport=self.udp_port_out, sport=self.udp_external_port))
7119         pkts.append(p)
7120
7121         # ICMP
7122         p = (Ether(dst=out_if.local_mac, src=out_if.remote_mac) /
7123              IP(src=out_if.remote_ip4, dst=dst_ip, ttl=ttl) /
7124              ICMP(id=self.icmp_external_id, type='echo-reply'))
7125         pkts.append(p)
7126
7127         return pkts
7128
7129     def verify_capture_out(self, capture, nat_ip=None):
7130         """
7131         Verify captured packets on outside network
7132
7133         :param capture: Captured packets
7134         :param nat_ip: Translated IP address (Default use global NAT address)
7135         :param same_port: Source port number is not translated (Default False)
7136         """
7137         if nat_ip is None:
7138             nat_ip = self.nat_addr
7139         for packet in capture:
7140             try:
7141                 self.assertEqual(packet[IP].src, nat_ip)
7142                 if packet.haslayer(TCP):
7143                     self.tcp_port_out = packet[TCP].sport
7144                 elif packet.haslayer(UDP):
7145                     self.udp_port_out = packet[UDP].sport
7146                 else:
7147                     self.icmp_external_id = packet[ICMP].id
7148             except:
7149                 self.logger.error(ppp("Unexpected or invalid packet "
7150                                       "(outside network):", packet))
7151                 raise
7152
7153     def test_deterministic_mode(self):
7154         """ NAT plugin run deterministic mode """
7155         in_addr = '172.16.255.0'
7156         out_addr = '172.17.255.50'
7157         in_addr_t = '172.16.255.20'
7158         in_plen = 24
7159         out_plen = 32
7160
7161         nat_config = self.vapi.nat_show_config()
7162         self.assertEqual(1, nat_config.deterministic)
7163
7164         self.vapi.nat_det_add_del_map(is_add=1, in_addr=in_addr,
7165                                       in_plen=in_plen, out_addr=out_addr,
7166                                       out_plen=out_plen)
7167
7168         rep1 = self.vapi.nat_det_forward(in_addr_t)
7169         self.assertEqual(str(rep1.out_addr), out_addr)
7170         rep2 = self.vapi.nat_det_reverse(rep1.out_port_hi, out_addr)
7171
7172         self.assertEqual(str(rep2.in_addr), in_addr_t)
7173
7174         deterministic_mappings = self.vapi.nat_det_map_dump()
7175         self.assertEqual(len(deterministic_mappings), 1)
7176         dsm = deterministic_mappings[0]
7177         self.assertEqual(in_addr, str(dsm.in_addr))
7178         self.assertEqual(in_plen, dsm.in_plen)
7179         self.assertEqual(out_addr, str(dsm.out_addr))
7180         self.assertEqual(out_plen, dsm.out_plen)
7181
7182         self.clear_nat_det()
7183         deterministic_mappings = self.vapi.nat_det_map_dump()
7184         self.assertEqual(len(deterministic_mappings), 0)
7185
7186     def test_set_timeouts(self):
7187         """ Set deterministic NAT timeouts """
7188         timeouts_before = self.vapi.nat_get_timeouts()
7189
7190         self.vapi.nat_set_timeouts(
7191             udp=timeouts_before.udp + 10,
7192             tcp_established=timeouts_before.tcp_established + 10,
7193             tcp_transitory=timeouts_before.tcp_transitory + 10,
7194             icmp=timeouts_before.icmp + 10)
7195
7196         timeouts_after = self.vapi.nat_get_timeouts()
7197
7198         self.assertNotEqual(timeouts_before.udp, timeouts_after.udp)
7199         self.assertNotEqual(timeouts_before.icmp, timeouts_after.icmp)
7200         self.assertNotEqual(timeouts_before.tcp_established,
7201                             timeouts_after.tcp_established)
7202         self.assertNotEqual(timeouts_before.tcp_transitory,
7203                             timeouts_after.tcp_transitory)
7204
7205     def test_det_in(self):
7206         """ Deterministic NAT translation test (TCP, UDP, ICMP) """
7207
7208         nat_ip = "10.0.0.10"
7209
7210         self.vapi.nat_det_add_del_map(is_add=1, in_addr=self.pg0.remote_ip4n,
7211                                       in_plen=32,
7212                                       out_addr=socket.inet_aton(nat_ip),
7213                                       out_plen=32)
7214
7215         flags = self.config_flags.NAT_IS_INSIDE
7216         self.vapi.nat44_interface_add_del_feature(
7217             sw_if_index=self.pg0.sw_if_index,
7218             flags=flags, is_add=1)
7219         self.vapi.nat44_interface_add_del_feature(
7220             sw_if_index=self.pg1.sw_if_index,
7221             is_add=1)
7222
7223         # in2out
7224         pkts = self.create_stream_in(self.pg0, self.pg1)
7225         self.pg0.add_stream(pkts)
7226         self.pg_enable_capture(self.pg_interfaces)
7227         self.pg_start()
7228         capture = self.pg1.get_capture(len(pkts))
7229         self.verify_capture_out(capture, nat_ip)
7230
7231         # out2in
7232         pkts = self.create_stream_out(self.pg1, nat_ip)
7233         self.pg1.add_stream(pkts)
7234         self.pg_enable_capture(self.pg_interfaces)
7235         self.pg_start()
7236         capture = self.pg0.get_capture(len(pkts))
7237         self.verify_capture_in(capture, self.pg0)
7238
7239         # session dump test
7240         sessions = self.vapi.nat_det_session_dump(self.pg0.remote_ip4n)
7241         self.assertEqual(len(sessions), 3)
7242
7243         # TCP session
7244         s = sessions[0]
7245         self.assertEqual(str(s.ext_addr), self.pg1.remote_ip4)
7246         self.assertEqual(s.in_port, self.tcp_port_in)
7247         self.assertEqual(s.out_port, self.tcp_port_out)
7248         self.assertEqual(s.ext_port, self.tcp_external_port)
7249
7250         # UDP session
7251         s = sessions[1]
7252         self.assertEqual(str(s.ext_addr), self.pg1.remote_ip4)
7253         self.assertEqual(s.in_port, self.udp_port_in)
7254         self.assertEqual(s.out_port, self.udp_port_out)
7255         self.assertEqual(s.ext_port, self.udp_external_port)
7256
7257         # ICMP session
7258         s = sessions[2]
7259         self.assertEqual(str(s.ext_addr), self.pg1.remote_ip4)
7260         self.assertEqual(s.in_port, self.icmp_id_in)
7261         self.assertEqual(s.out_port, self.icmp_external_id)
7262
7263     def test_multiple_users(self):
7264         """ Deterministic NAT multiple users """
7265
7266         nat_ip = "10.0.0.10"
7267         port_in = 80
7268         external_port = 6303
7269
7270         host0 = self.pg0.remote_hosts[0]
7271         host1 = self.pg0.remote_hosts[1]
7272
7273         self.vapi.nat_det_add_del_map(is_add=1, in_addr=host0.ip4n, in_plen=24,
7274                                       out_addr=socket.inet_aton(nat_ip),
7275                                       out_plen=32)
7276         flags = self.config_flags.NAT_IS_INSIDE
7277         self.vapi.nat44_interface_add_del_feature(
7278             sw_if_index=self.pg0.sw_if_index,
7279             flags=flags, is_add=1)
7280         self.vapi.nat44_interface_add_del_feature(
7281             sw_if_index=self.pg1.sw_if_index,
7282             is_add=1)
7283
7284         # host0 to out
7285         p = (Ether(src=host0.mac, dst=self.pg0.local_mac) /
7286              IP(src=host0.ip4, dst=self.pg1.remote_ip4) /
7287              TCP(sport=port_in, dport=external_port))
7288         self.pg0.add_stream(p)
7289         self.pg_enable_capture(self.pg_interfaces)
7290         self.pg_start()
7291         capture = self.pg1.get_capture(1)
7292         p = capture[0]
7293         try:
7294             ip = p[IP]
7295             tcp = p[TCP]
7296             self.assertEqual(ip.src, nat_ip)
7297             self.assertEqual(ip.dst, self.pg1.remote_ip4)
7298             self.assertEqual(tcp.dport, external_port)
7299             port_out0 = tcp.sport
7300         except:
7301             self.logger.error(ppp("Unexpected or invalid packet:", p))
7302             raise
7303
7304         # host1 to out
7305         p = (Ether(src=host1.mac, dst=self.pg0.local_mac) /
7306              IP(src=host1.ip4, dst=self.pg1.remote_ip4) /
7307              TCP(sport=port_in, dport=external_port))
7308         self.pg0.add_stream(p)
7309         self.pg_enable_capture(self.pg_interfaces)
7310         self.pg_start()
7311         capture = self.pg1.get_capture(1)
7312         p = capture[0]
7313         try:
7314             ip = p[IP]
7315             tcp = p[TCP]
7316             self.assertEqual(ip.src, nat_ip)
7317             self.assertEqual(ip.dst, self.pg1.remote_ip4)
7318             self.assertEqual(tcp.dport, external_port)
7319             port_out1 = tcp.sport
7320         except:
7321             self.logger.error(ppp("Unexpected or invalid packet:", p))
7322             raise
7323
7324         dms = self.vapi.nat_det_map_dump()
7325         self.assertEqual(1, len(dms))
7326         self.assertEqual(2, dms[0].ses_num)
7327
7328         # out to host0
7329         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
7330              IP(src=self.pg1.remote_ip4, dst=nat_ip) /
7331              TCP(sport=external_port, dport=port_out0))
7332         self.pg1.add_stream(p)
7333         self.pg_enable_capture(self.pg_interfaces)
7334         self.pg_start()
7335         capture = self.pg0.get_capture(1)
7336         p = capture[0]
7337         try:
7338             ip = p[IP]
7339             tcp = p[TCP]
7340             self.assertEqual(ip.src, self.pg1.remote_ip4)
7341             self.assertEqual(ip.dst, host0.ip4)
7342             self.assertEqual(tcp.dport, port_in)
7343             self.assertEqual(tcp.sport, external_port)
7344         except:
7345             self.logger.error(ppp("Unexpected or invalid packet:", p))
7346             raise
7347
7348         # out to host1
7349         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
7350              IP(src=self.pg1.remote_ip4, dst=nat_ip) /
7351              TCP(sport=external_port, dport=port_out1))
7352         self.pg1.add_stream(p)
7353         self.pg_enable_capture(self.pg_interfaces)
7354         self.pg_start()
7355         capture = self.pg0.get_capture(1)
7356         p = capture[0]
7357         try:
7358             ip = p[IP]
7359             tcp = p[TCP]
7360             self.assertEqual(ip.src, self.pg1.remote_ip4)
7361             self.assertEqual(ip.dst, host1.ip4)
7362             self.assertEqual(tcp.dport, port_in)
7363             self.assertEqual(tcp.sport, external_port)
7364         except:
7365             self.logger.error(ppp("Unexpected or invalid packet", p))
7366             raise
7367
7368         # session close api test
7369         self.vapi.nat_det_close_session_out(socket.inet_aton(nat_ip),
7370                                             port_out1,
7371                                             self.pg1.remote_ip4n,
7372                                             external_port)
7373         dms = self.vapi.nat_det_map_dump()
7374         self.assertEqual(dms[0].ses_num, 1)
7375
7376         self.vapi.nat_det_close_session_in(host0.ip4n,
7377                                            port_in,
7378                                            self.pg1.remote_ip4n,
7379                                            external_port)
7380         dms = self.vapi.nat_det_map_dump()
7381         self.assertEqual(dms[0].ses_num, 0)
7382
7383     def test_tcp_session_close_detection_in(self):
7384         """ Deterministic NAT TCP session close from inside network """
7385         self.vapi.nat_det_add_del_map(is_add=1, in_addr=self.pg0.remote_ip4n,
7386                                       in_plen=32,
7387                                       out_addr=socket.inet_aton(self.nat_addr),
7388                                       out_plen=32)
7389         flags = self.config_flags.NAT_IS_INSIDE
7390         self.vapi.nat44_interface_add_del_feature(
7391             sw_if_index=self.pg0.sw_if_index,
7392             flags=flags, is_add=1)
7393         self.vapi.nat44_interface_add_del_feature(
7394             sw_if_index=self.pg1.sw_if_index,
7395             is_add=1)
7396
7397         self.initiate_tcp_session(self.pg0, self.pg1)
7398
7399         # close the session from inside
7400         try:
7401             # FIN packet in -> out
7402             p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
7403                  IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
7404                  TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
7405                      flags="F"))
7406             self.pg0.add_stream(p)
7407             self.pg_enable_capture(self.pg_interfaces)
7408             self.pg_start()
7409             self.pg1.get_capture(1)
7410
7411             pkts = []
7412
7413             # ACK packet out -> in
7414             p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
7415                  IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
7416                  TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
7417                      flags="A"))
7418             pkts.append(p)
7419
7420             # FIN packet out -> in
7421             p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
7422                  IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
7423                  TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
7424                      flags="F"))
7425             pkts.append(p)
7426
7427             self.pg1.add_stream(pkts)
7428             self.pg_enable_capture(self.pg_interfaces)
7429             self.pg_start()
7430             self.pg0.get_capture(2)
7431
7432             # ACK packet in -> out
7433             p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
7434                  IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
7435                  TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
7436                      flags="A"))
7437             self.pg0.add_stream(p)
7438             self.pg_enable_capture(self.pg_interfaces)
7439             self.pg_start()
7440             self.pg1.get_capture(1)
7441
7442             # Check if deterministic NAT44 closed the session
7443             dms = self.vapi.nat_det_map_dump()
7444             self.assertEqual(0, dms[0].ses_num)
7445         except:
7446             self.logger.error("TCP session termination failed")
7447             raise
7448
7449     def test_tcp_session_close_detection_out(self):
7450         """ Deterministic NAT TCP session close from outside network """
7451         self.vapi.nat_det_add_del_map(is_add=1, in_addr=self.pg0.remote_ip4n,
7452                                       in_plen=32,
7453                                       out_addr=socket.inet_aton(self.nat_addr),
7454                                       out_plen=32)
7455         flags = self.config_flags.NAT_IS_INSIDE
7456         self.vapi.nat44_interface_add_del_feature(
7457             sw_if_index=self.pg0.sw_if_index,
7458             flags=flags, is_add=1)
7459         self.vapi.nat44_interface_add_del_feature(
7460             sw_if_index=self.pg1.sw_if_index,
7461             is_add=1)
7462
7463         self.initiate_tcp_session(self.pg0, self.pg1)
7464
7465         # close the session from outside
7466         try:
7467             # FIN packet out -> in
7468             p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
7469                  IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
7470                  TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
7471                      flags="F"))
7472             self.pg1.add_stream(p)
7473             self.pg_enable_capture(self.pg_interfaces)
7474             self.pg_start()
7475             self.pg0.get_capture(1)
7476
7477             pkts = []
7478
7479             # ACK packet in -> out
7480             p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
7481                  IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
7482                  TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
7483                      flags="A"))
7484             pkts.append(p)
7485
7486             # ACK packet in -> out
7487             p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
7488                  IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
7489                  TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
7490                      flags="F"))
7491             pkts.append(p)
7492
7493             self.pg0.add_stream(pkts)
7494             self.pg_enable_capture(self.pg_interfaces)
7495             self.pg_start()
7496             self.pg1.get_capture(2)
7497
7498             # ACK packet out -> in
7499             p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
7500                  IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
7501                  TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
7502                      flags="A"))
7503             self.pg1.add_stream(p)
7504             self.pg_enable_capture(self.pg_interfaces)
7505             self.pg_start()
7506             self.pg0.get_capture(1)
7507
7508             # Check if deterministic NAT44 closed the session
7509             dms = self.vapi.nat_det_map_dump()
7510             self.assertEqual(0, dms[0].ses_num)
7511         except:
7512             self.logger.error("TCP session termination failed")
7513             raise
7514
7515     @unittest.skipUnless(running_extended_tests, "part of extended tests")
7516     def test_session_timeout(self):
7517         """ Deterministic NAT session timeouts """
7518         self.vapi.nat_det_add_del_map(is_add=1, in_addr=self.pg0.remote_ip4n,
7519                                       in_plen=32,
7520                                       out_addr=socket.inet_aton(self.nat_addr),
7521                                       out_plen=32)
7522         flags = self.config_flags.NAT_IS_INSIDE
7523         self.vapi.nat44_interface_add_del_feature(
7524             sw_if_index=self.pg0.sw_if_index,
7525             flags=flags, is_add=1)
7526         self.vapi.nat44_interface_add_del_feature(
7527             sw_if_index=self.pg1.sw_if_index,
7528             is_add=1)
7529
7530         self.initiate_tcp_session(self.pg0, self.pg1)
7531         self.vapi.nat_set_timeouts(udp=5, tcp_established=5, tcp_transitory=5,
7532                                    icmp=5)
7533         pkts = self.create_stream_in(self.pg0, self.pg1)
7534         self.pg0.add_stream(pkts)
7535         self.pg_enable_capture(self.pg_interfaces)
7536         self.pg_start()
7537         capture = self.pg1.get_capture(len(pkts))
7538         sleep(15)
7539
7540         dms = self.vapi.nat_det_map_dump()
7541         self.assertEqual(0, dms[0].ses_num)
7542
7543     @unittest.skipUnless(running_extended_tests, "part of extended tests")
7544     def test_session_limit_per_user(self):
7545         """ Deterministic NAT maximum sessions per user limit """
7546         self.vapi.nat_det_add_del_map(is_add=1, in_addr=self.pg0.remote_ip4n,
7547                                       in_plen=32,
7548                                       out_addr=socket.inet_aton(self.nat_addr),
7549                                       out_plen=32)
7550         flags = self.config_flags.NAT_IS_INSIDE
7551         self.vapi.nat44_interface_add_del_feature(
7552             sw_if_index=self.pg0.sw_if_index,
7553             flags=flags, is_add=1)
7554         self.vapi.nat44_interface_add_del_feature(
7555             sw_if_index=self.pg1.sw_if_index,
7556             is_add=1)
7557         self.vapi.set_ipfix_exporter(collector_address=self.pg2.remote_ip4n,
7558                                      src_address=self.pg2.local_ip4n,
7559                                      path_mtu=512,
7560                                      template_interval=10)
7561         self.vapi.nat_ipfix_enable_disable(domain_id=1, src_port=4739,
7562                                            enable=1)
7563
7564         pkts = []
7565         for port in range(1025, 2025):
7566             p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
7567                  IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
7568                  UDP(sport=port, dport=port))
7569             pkts.append(p)
7570
7571         self.pg0.add_stream(pkts)
7572         self.pg_enable_capture(self.pg_interfaces)
7573         self.pg_start()
7574         capture = self.pg1.get_capture(len(pkts))
7575
7576         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
7577              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
7578              UDP(sport=3001, dport=3002))
7579         self.pg0.add_stream(p)
7580         self.pg_enable_capture(self.pg_interfaces)
7581         self.pg_start()
7582         capture = self.pg1.assert_nothing_captured()
7583
7584         # verify ICMP error packet
7585         capture = self.pg0.get_capture(1)
7586         p = capture[0]
7587         self.assertTrue(p.haslayer(ICMP))
7588         icmp = p[ICMP]
7589         self.assertEqual(icmp.type, 3)
7590         self.assertEqual(icmp.code, 1)
7591         self.assertTrue(icmp.haslayer(IPerror))
7592         inner_ip = icmp[IPerror]
7593         self.assertEqual(inner_ip[UDPerror].sport, 3001)
7594         self.assertEqual(inner_ip[UDPerror].dport, 3002)
7595
7596         dms = self.vapi.nat_det_map_dump()
7597
7598         self.assertEqual(1000, dms[0].ses_num)
7599
7600         # verify IPFIX logging
7601         self.vapi.cli("ipfix flush")  # FIXME this should be an API call
7602         sleep(1)
7603         capture = self.pg2.get_capture(2)
7604         ipfix = IPFIXDecoder()
7605         # first load template
7606         for p in capture:
7607             self.assertTrue(p.haslayer(IPFIX))
7608             if p.haslayer(Template):
7609                 ipfix.add_template(p.getlayer(Template))
7610         # verify events in data set
7611         for p in capture:
7612             if p.haslayer(Data):
7613                 data = ipfix.decode_data_set(p.getlayer(Set))
7614                 self.verify_ipfix_max_entries_per_user(data,
7615                                                        1000,
7616                                                        self.pg0.remote_ip4n)
7617
7618     def clear_nat_det(self):
7619         """
7620         Clear deterministic NAT configuration.
7621         """
7622         self.vapi.nat_ipfix_enable_disable(domain_id=1, src_port=4739,
7623                                            enable=0)
7624         self.vapi.nat_set_timeouts(udp=300, tcp_established=7440,
7625                                    tcp_transitory=240, icmp=60)
7626         deterministic_mappings = self.vapi.nat_det_map_dump()
7627         for dsm in deterministic_mappings:
7628             self.vapi.nat_det_add_del_map(is_add=0, in_addr=dsm.in_addr,
7629                                           in_plen=dsm.in_plen,
7630                                           out_addr=dsm.out_addr,
7631                                           out_plen=dsm.out_plen)
7632
7633         interfaces = self.vapi.nat44_interface_dump()
7634         for intf in interfaces:
7635             self.vapi.nat44_interface_add_del_feature(
7636                 sw_if_index=intf.sw_if_index,
7637                 flags=intf.flags)
7638
7639     def tearDown(self):
7640         super(TestDeterministicNAT, self).tearDown()
7641         if not self.vpp_dead:
7642             self.clear_nat_det()
7643
7644     def show_commands_at_teardown(self):
7645         self.logger.info(self.vapi.cli("show nat44 interfaces"))
7646         self.logger.info(self.vapi.cli("show nat timeouts"))
7647         self.logger.info(
7648             self.vapi.cli("show nat44 deterministic mappings"))
7649         self.logger.info(
7650             self.vapi.cli("show nat44 deterministic sessions"))
7651
7652
7653 class TestNAT64(MethodHolder):
7654     """ NAT64 Test Cases """
7655
7656     @classmethod
7657     def setUpConstants(cls):
7658         super(TestNAT64, cls).setUpConstants()
7659         cls.vpp_cmdline.extend(["nat", "{", "nat64 bib hash buckets 128",
7660                                 "nat64 st hash buckets 256", "}"])
7661
7662     @classmethod
7663     def setUpClass(cls):
7664         super(TestNAT64, cls).setUpClass()
7665
7666         try:
7667             cls.tcp_port_in = 6303
7668             cls.tcp_port_out = 6303
7669             cls.udp_port_in = 6304
7670             cls.udp_port_out = 6304
7671             cls.icmp_id_in = 6305
7672             cls.icmp_id_out = 6305
7673             cls.tcp_external_port = 80
7674             cls.nat_addr = '10.0.0.3'
7675             cls.nat_addr_n = socket.inet_pton(socket.AF_INET, cls.nat_addr)
7676             cls.vrf1_id = 10
7677             cls.vrf1_nat_addr = '10.0.10.3'
7678             cls.ipfix_src_port = 4739
7679             cls.ipfix_domain_id = 1
7680
7681             cls.create_pg_interfaces(range(6))
7682             cls.ip6_interfaces = list(cls.pg_interfaces[0:1])
7683             cls.ip6_interfaces.append(cls.pg_interfaces[2])
7684             cls.ip4_interfaces = list(cls.pg_interfaces[1:2])
7685
7686             cls.vapi.ip_table_add_del(is_ipv6=1, is_add=1,
7687                                       table_id=cls.vrf1_id)
7688
7689             cls.pg_interfaces[2].set_table_ip6(cls.vrf1_id)
7690
7691             cls.pg0.generate_remote_hosts(2)
7692
7693             for i in cls.ip6_interfaces:
7694                 i.admin_up()
7695                 i.config_ip6()
7696                 i.configure_ipv6_neighbors()
7697
7698             for i in cls.ip4_interfaces:
7699                 i.admin_up()
7700                 i.config_ip4()
7701                 i.resolve_arp()
7702
7703             cls.pg3.admin_up()
7704             cls.pg3.config_ip4()
7705             cls.pg3.resolve_arp()
7706             cls.pg3.config_ip6()
7707             cls.pg3.configure_ipv6_neighbors()
7708
7709             cls.pg5.admin_up()
7710             cls.pg5.config_ip6()
7711
7712         except Exception:
7713             super(TestNAT64, cls).tearDownClass()
7714             raise
7715
7716     @classmethod
7717     def tearDownClass(cls):
7718         super(TestNAT64, cls).tearDownClass()
7719
7720     def test_nat64_inside_interface_handles_neighbor_advertisement(self):
7721         """ NAT64 inside interface handles Neighbor Advertisement """
7722
7723         flags = self.config_flags.NAT_IS_INSIDE
7724         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
7725                                           sw_if_index=self.pg5.sw_if_index)
7726
7727         # Try to send ping
7728         ping = (Ether(dst=self.pg5.local_mac, src=self.pg5.remote_mac) /
7729                 IPv6(src=self.pg5.remote_ip6, dst=self.pg5.local_ip6) /
7730                 ICMPv6EchoRequest())
7731         pkts = [ping]
7732         self.pg5.add_stream(pkts)
7733         self.pg_enable_capture(self.pg_interfaces)
7734         self.pg_start()
7735
7736         # Wait for Neighbor Solicitation
7737         capture = self.pg5.get_capture(len(pkts))
7738         packet = capture[0]
7739         try:
7740             self.assertEqual(packet[IPv6].src, self.pg5.local_ip6)
7741             self.assertEqual(packet.haslayer(ICMPv6ND_NS), 1)
7742             tgt = packet[ICMPv6ND_NS].tgt
7743         except:
7744             self.logger.error(ppp("Unexpected or invalid packet:", packet))
7745             raise
7746
7747         # Send Neighbor Advertisement
7748         p = (Ether(dst=self.pg5.local_mac, src=self.pg5.remote_mac) /
7749              IPv6(src=self.pg5.remote_ip6, dst=self.pg5.local_ip6) /
7750              ICMPv6ND_NA(tgt=tgt) /
7751              ICMPv6NDOptDstLLAddr(lladdr=self.pg5.remote_mac))
7752         pkts = [p]
7753         self.pg5.add_stream(pkts)
7754         self.pg_enable_capture(self.pg_interfaces)
7755         self.pg_start()
7756
7757         # Try to send ping again
7758         pkts = [ping]
7759         self.pg5.add_stream(pkts)
7760         self.pg_enable_capture(self.pg_interfaces)
7761         self.pg_start()
7762
7763         # Wait for ping reply
7764         capture = self.pg5.get_capture(len(pkts))
7765         packet = capture[0]
7766         try:
7767             self.assertEqual(packet[IPv6].src, self.pg5.local_ip6)
7768             self.assertEqual(packet[IPv6].dst, self.pg5.remote_ip6)
7769             self.assertEqual(packet.haslayer(ICMPv6EchoReply), 1)
7770         except:
7771             self.logger.error(ppp("Unexpected or invalid packet:", packet))
7772             raise
7773
7774     def test_pool(self):
7775         """ Add/delete address to NAT64 pool """
7776         nat_addr = '1.2.3.4'
7777
7778         self.vapi.nat64_add_del_pool_addr_range(start_addr=nat_addr,
7779                                                 end_addr=nat_addr,
7780                                                 vrf_id=0xFFFFFFFF, is_add=1)
7781
7782         addresses = self.vapi.nat64_pool_addr_dump()
7783         self.assertEqual(len(addresses), 1)
7784         self.assertEqual(str(addresses[0].address), nat_addr)
7785
7786         self.vapi.nat64_add_del_pool_addr_range(start_addr=nat_addr,
7787                                                 end_addr=nat_addr,
7788                                                 vrf_id=0xFFFFFFFF, is_add=0)
7789
7790         addresses = self.vapi.nat64_pool_addr_dump()
7791         self.assertEqual(len(addresses), 0)
7792
7793     def test_interface(self):
7794         """ Enable/disable NAT64 feature on the interface """
7795         flags = self.config_flags.NAT_IS_INSIDE
7796         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
7797                                           sw_if_index=self.pg0.sw_if_index)
7798         self.vapi.nat64_add_del_interface(is_add=1, flags=0,
7799                                           sw_if_index=self.pg1.sw_if_index)
7800
7801         interfaces = self.vapi.nat64_interface_dump()
7802         self.assertEqual(len(interfaces), 2)
7803         pg0_found = False
7804         pg1_found = False
7805         for intf in interfaces:
7806             if intf.sw_if_index == self.pg0.sw_if_index:
7807                 self.assertEqual(intf.flags, self.config_flags.NAT_IS_INSIDE)
7808                 pg0_found = True
7809             elif intf.sw_if_index == self.pg1.sw_if_index:
7810                 self.assertEqual(intf.flags, self.config_flags.NAT_IS_OUTSIDE)
7811                 pg1_found = True
7812         self.assertTrue(pg0_found)
7813         self.assertTrue(pg1_found)
7814
7815         features = self.vapi.cli("show interface features pg0")
7816         self.assertIn('nat64-in2out', features)
7817         features = self.vapi.cli("show interface features pg1")
7818         self.assertIn('nat64-out2in', features)
7819
7820         self.vapi.nat64_add_del_interface(is_add=0, flags=flags,
7821                                           sw_if_index=self.pg0.sw_if_index)
7822         self.vapi.nat64_add_del_interface(is_add=0, flags=flags,
7823                                           sw_if_index=self.pg1.sw_if_index)
7824
7825         interfaces = self.vapi.nat64_interface_dump()
7826         self.assertEqual(len(interfaces), 0)
7827
7828     def test_static_bib(self):
7829         """ Add/delete static BIB entry """
7830         in_addr = '2001:db8:85a3::8a2e:370:7334'
7831         out_addr = '10.1.1.3'
7832         in_port = 1234
7833         out_port = 5678
7834         proto = IP_PROTOS.tcp
7835
7836         self.vapi.nat64_add_del_static_bib(i_addr=in_addr, o_addr=out_addr,
7837                                            i_port=in_port, o_port=out_port,
7838                                            proto=proto, vrf_id=0, is_add=1)
7839         bib = self.vapi.nat64_bib_dump(proto=IP_PROTOS.tcp)
7840         static_bib_num = 0
7841         for bibe in bib:
7842             if bibe.flags & self.config_flags.NAT_IS_STATIC:
7843                 static_bib_num += 1
7844                 self.assertEqual(str(bibe.i_addr), in_addr)
7845                 self.assertEqual(str(bibe.o_addr), out_addr)
7846                 self.assertEqual(bibe.i_port, in_port)
7847                 self.assertEqual(bibe.o_port, out_port)
7848         self.assertEqual(static_bib_num, 1)
7849         bibs = self.statistics.get_counter('/nat64/total-bibs')
7850         self.assertEqual(bibs[0][0], 1)
7851
7852         self.vapi.nat64_add_del_static_bib(i_addr=in_addr, o_addr=out_addr,
7853                                            i_port=in_port, o_port=out_port,
7854                                            proto=proto, vrf_id=0, is_add=0)
7855         bib = self.vapi.nat64_bib_dump(proto=IP_PROTOS.tcp)
7856         static_bib_num = 0
7857         for bibe in bib:
7858             if bibe.flags & self.config_flags.NAT_IS_STATIC:
7859                 static_bib_num += 1
7860         self.assertEqual(static_bib_num, 0)
7861         bibs = self.statistics.get_counter('/nat64/total-bibs')
7862         self.assertEqual(bibs[0][0], 0)
7863
7864     def test_set_timeouts(self):
7865         """ Set NAT64 timeouts """
7866         # verify default values
7867         timeouts = self.vapi.nat_get_timeouts()
7868         self.assertEqual(timeouts.udp, 300)
7869         self.assertEqual(timeouts.icmp, 60)
7870         self.assertEqual(timeouts.tcp_transitory, 240)
7871         self.assertEqual(timeouts.tcp_established, 7440)
7872
7873         # set and verify custom values
7874         self.vapi.nat_set_timeouts(udp=200, tcp_established=7450,
7875                                    tcp_transitory=250, icmp=30)
7876         timeouts = self.vapi.nat_get_timeouts()
7877         self.assertEqual(timeouts.udp, 200)
7878         self.assertEqual(timeouts.icmp, 30)
7879         self.assertEqual(timeouts.tcp_transitory, 250)
7880         self.assertEqual(timeouts.tcp_established, 7450)
7881
7882     def test_dynamic(self):
7883         """ NAT64 dynamic translation test """
7884         self.tcp_port_in = 6303
7885         self.udp_port_in = 6304
7886         self.icmp_id_in = 6305
7887
7888         ses_num_start = self.nat64_get_ses_num()
7889
7890         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr,
7891                                                 end_addr=self.nat_addr,
7892                                                 vrf_id=0xFFFFFFFF,
7893                                                 is_add=1)
7894         flags = self.config_flags.NAT_IS_INSIDE
7895         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
7896                                           sw_if_index=self.pg0.sw_if_index)
7897         self.vapi.nat64_add_del_interface(is_add=1, flags=0,
7898                                           sw_if_index=self.pg1.sw_if_index)
7899
7900         # in2out
7901         tcpn = self.statistics.get_counter('/err/nat64-in2out/TCP packets')
7902         udpn = self.statistics.get_counter('/err/nat64-in2out/UDP packets')
7903         icmpn = self.statistics.get_counter('/err/nat64-in2out/ICMP packets')
7904         totaln = self.statistics.get_counter(
7905             '/err/nat64-in2out/good in2out packets processed')
7906
7907         pkts = self.create_stream_in_ip6(self.pg0, self.pg1)
7908         self.pg0.add_stream(pkts)
7909         self.pg_enable_capture(self.pg_interfaces)
7910         self.pg_start()
7911         capture = self.pg1.get_capture(len(pkts))
7912         self.verify_capture_out(capture, nat_ip=self.nat_addr,
7913                                 dst_ip=self.pg1.remote_ip4)
7914
7915         err = self.statistics.get_counter('/err/nat64-in2out/TCP packets')
7916         self.assertEqual(err - tcpn, 1)
7917         err = self.statistics.get_counter('/err/nat64-in2out/UDP packets')
7918         self.assertEqual(err - udpn, 1)
7919         err = self.statistics.get_counter('/err/nat64-in2out/ICMP packets')
7920         self.assertEqual(err - icmpn, 1)
7921         err = self.statistics.get_counter(
7922             '/err/nat64-in2out/good in2out packets processed')
7923         self.assertEqual(err - totaln, 3)
7924
7925         # out2in
7926         tcpn = self.statistics.get_counter('/err/nat64-out2in/TCP packets')
7927         udpn = self.statistics.get_counter('/err/nat64-out2in/UDP packets')
7928         icmpn = self.statistics.get_counter('/err/nat64-out2in/ICMP packets')
7929         totaln = self.statistics.get_counter(
7930             '/err/nat64-out2in/good out2in packets processed')
7931
7932         pkts = self.create_stream_out(self.pg1, dst_ip=self.nat_addr)
7933         self.pg1.add_stream(pkts)
7934         self.pg_enable_capture(self.pg_interfaces)
7935         self.pg_start()
7936         capture = self.pg0.get_capture(len(pkts))
7937         ip = IPv6(src=''.join(['64:ff9b::', self.pg1.remote_ip4]))
7938         self.verify_capture_in_ip6(capture, ip[IPv6].src, self.pg0.remote_ip6)
7939
7940         err = self.statistics.get_counter('/err/nat64-out2in/TCP packets')
7941         self.assertEqual(err - tcpn, 1)
7942         err = self.statistics.get_counter('/err/nat64-out2in/UDP packets')
7943         self.assertEqual(err - udpn, 1)
7944         err = self.statistics.get_counter('/err/nat64-out2in/ICMP packets')
7945         self.assertEqual(err - icmpn, 1)
7946         err = self.statistics.get_counter(
7947             '/err/nat64-out2in/good out2in packets processed')
7948         self.assertEqual(err - totaln, 3)
7949
7950         bibs = self.statistics.get_counter('/nat64/total-bibs')
7951         self.assertEqual(bibs[0][0], 3)
7952         sessions = self.statistics.get_counter('/nat64/total-sessions')
7953         self.assertEqual(sessions[0][0], 3)
7954
7955         # in2out
7956         pkts = self.create_stream_in_ip6(self.pg0, self.pg1)
7957         self.pg0.add_stream(pkts)
7958         self.pg_enable_capture(self.pg_interfaces)
7959         self.pg_start()
7960         capture = self.pg1.get_capture(len(pkts))
7961         self.verify_capture_out(capture, nat_ip=self.nat_addr,
7962                                 dst_ip=self.pg1.remote_ip4)
7963
7964         # out2in
7965         pkts = self.create_stream_out(self.pg1, dst_ip=self.nat_addr)
7966         self.pg1.add_stream(pkts)
7967         self.pg_enable_capture(self.pg_interfaces)
7968         self.pg_start()
7969         capture = self.pg0.get_capture(len(pkts))
7970         self.verify_capture_in_ip6(capture, ip[IPv6].src, self.pg0.remote_ip6)
7971
7972         ses_num_end = self.nat64_get_ses_num()
7973
7974         self.assertEqual(ses_num_end - ses_num_start, 3)
7975
7976         # tenant with specific VRF
7977         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.vrf1_nat_addr,
7978                                                 end_addr=self.vrf1_nat_addr,
7979                                                 vrf_id=self.vrf1_id, is_add=1)
7980         flags = self.config_flags.NAT_IS_INSIDE
7981         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
7982                                           sw_if_index=self.pg2.sw_if_index)
7983
7984         pkts = self.create_stream_in_ip6(self.pg2, self.pg1)
7985         self.pg2.add_stream(pkts)
7986         self.pg_enable_capture(self.pg_interfaces)
7987         self.pg_start()
7988         capture = self.pg1.get_capture(len(pkts))
7989         self.verify_capture_out(capture, nat_ip=self.vrf1_nat_addr,
7990                                 dst_ip=self.pg1.remote_ip4)
7991
7992         pkts = self.create_stream_out(self.pg1, dst_ip=self.vrf1_nat_addr)
7993         self.pg1.add_stream(pkts)
7994         self.pg_enable_capture(self.pg_interfaces)
7995         self.pg_start()
7996         capture = self.pg2.get_capture(len(pkts))
7997         self.verify_capture_in_ip6(capture, ip[IPv6].src, self.pg2.remote_ip6)
7998
7999     def test_static(self):
8000         """ NAT64 static translation test """
8001         self.tcp_port_in = 60303
8002         self.udp_port_in = 60304
8003         self.icmp_id_in = 60305
8004         self.tcp_port_out = 60303
8005         self.udp_port_out = 60304
8006         self.icmp_id_out = 60305
8007
8008         ses_num_start = self.nat64_get_ses_num()
8009
8010         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr,
8011                                                 end_addr=self.nat_addr,
8012                                                 vrf_id=0xFFFFFFFF,
8013                                                 is_add=1)
8014         flags = self.config_flags.NAT_IS_INSIDE
8015         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
8016                                           sw_if_index=self.pg0.sw_if_index)
8017         self.vapi.nat64_add_del_interface(is_add=1, flags=0,
8018                                           sw_if_index=self.pg1.sw_if_index)
8019
8020         self.vapi.nat64_add_del_static_bib(i_addr=self.pg0.remote_ip6n,
8021                                            o_addr=self.nat_addr,
8022                                            i_port=self.tcp_port_in,
8023                                            o_port=self.tcp_port_out,
8024                                            proto=IP_PROTOS.tcp, vrf_id=0,
8025                                            is_add=1)
8026         self.vapi.nat64_add_del_static_bib(i_addr=self.pg0.remote_ip6n,
8027                                            o_addr=self.nat_addr,
8028                                            i_port=self.udp_port_in,
8029                                            o_port=self.udp_port_out,
8030                                            proto=IP_PROTOS.udp, vrf_id=0,
8031                                            is_add=1)
8032         self.vapi.nat64_add_del_static_bib(i_addr=self.pg0.remote_ip6n,
8033                                            o_addr=self.nat_addr,
8034                                            i_port=self.icmp_id_in,
8035                                            o_port=self.icmp_id_out,
8036                                            proto=IP_PROTOS.icmp, vrf_id=0,
8037                                            is_add=1)
8038
8039         # in2out
8040         pkts = self.create_stream_in_ip6(self.pg0, self.pg1)
8041         self.pg0.add_stream(pkts)
8042         self.pg_enable_capture(self.pg_interfaces)
8043         self.pg_start()
8044         capture = self.pg1.get_capture(len(pkts))
8045         self.verify_capture_out(capture, nat_ip=self.nat_addr,
8046                                 dst_ip=self.pg1.remote_ip4, same_port=True)
8047
8048         # out2in
8049         pkts = self.create_stream_out(self.pg1, dst_ip=self.nat_addr)
8050         self.pg1.add_stream(pkts)
8051         self.pg_enable_capture(self.pg_interfaces)
8052         self.pg_start()
8053         capture = self.pg0.get_capture(len(pkts))
8054         ip = IPv6(src=''.join(['64:ff9b::', self.pg1.remote_ip4]))
8055         self.verify_capture_in_ip6(capture, ip[IPv6].src, self.pg0.remote_ip6)
8056
8057         ses_num_end = self.nat64_get_ses_num()
8058
8059         self.assertEqual(ses_num_end - ses_num_start, 3)
8060
8061     @unittest.skipUnless(running_extended_tests, "part of extended tests")
8062     def test_session_timeout(self):
8063         """ NAT64 session timeout """
8064         self.icmp_id_in = 1234
8065         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr,
8066                                                 end_addr=self.nat_addr,
8067                                                 vrf_id=0xFFFFFFFF,
8068                                                 is_add=1)
8069         flags = self.config_flags.NAT_IS_INSIDE
8070         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
8071                                           sw_if_index=self.pg0.sw_if_index)
8072         self.vapi.nat64_add_del_interface(is_add=1, flags=0,
8073                                           sw_if_index=self.pg1.sw_if_index)
8074         self.vapi.nat_set_timeouts(udp=300, tcp_established=5,
8075                                    tcp_transitory=5,
8076                                    icmp=5)
8077
8078         pkts = self.create_stream_in_ip6(self.pg0, self.pg1)
8079         self.pg0.add_stream(pkts)
8080         self.pg_enable_capture(self.pg_interfaces)
8081         self.pg_start()
8082         capture = self.pg1.get_capture(len(pkts))
8083
8084         ses_num_before_timeout = self.nat64_get_ses_num()
8085
8086         sleep(15)
8087
8088         # ICMP and TCP session after timeout
8089         ses_num_after_timeout = self.nat64_get_ses_num()
8090         self.assertEqual(ses_num_before_timeout - ses_num_after_timeout, 2)
8091
8092     def test_icmp_error(self):
8093         """ NAT64 ICMP Error message translation """
8094         self.tcp_port_in = 6303
8095         self.udp_port_in = 6304
8096         self.icmp_id_in = 6305
8097
8098         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr,
8099                                                 end_addr=self.nat_addr,
8100                                                 vrf_id=0xFFFFFFFF,
8101                                                 is_add=1)
8102         flags = self.config_flags.NAT_IS_INSIDE
8103         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
8104                                           sw_if_index=self.pg0.sw_if_index)
8105         self.vapi.nat64_add_del_interface(is_add=1, flags=0,
8106                                           sw_if_index=self.pg1.sw_if_index)
8107
8108         # send some packets to create sessions
8109         pkts = self.create_stream_in_ip6(self.pg0, self.pg1)
8110         self.pg0.add_stream(pkts)
8111         self.pg_enable_capture(self.pg_interfaces)
8112         self.pg_start()
8113         capture_ip4 = self.pg1.get_capture(len(pkts))
8114         self.verify_capture_out(capture_ip4,
8115                                 nat_ip=self.nat_addr,
8116                                 dst_ip=self.pg1.remote_ip4)
8117
8118         pkts = self.create_stream_out(self.pg1, dst_ip=self.nat_addr)
8119         self.pg1.add_stream(pkts)
8120         self.pg_enable_capture(self.pg_interfaces)
8121         self.pg_start()
8122         capture_ip6 = self.pg0.get_capture(len(pkts))
8123         ip = IPv6(src=''.join(['64:ff9b::', self.pg1.remote_ip4]))
8124         self.verify_capture_in_ip6(capture_ip6, ip[IPv6].src,
8125                                    self.pg0.remote_ip6)
8126
8127         # in2out
8128         pkts = [Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
8129                 IPv6(src=self.pg0.remote_ip6, dst=ip[IPv6].src) /
8130                 ICMPv6DestUnreach(code=1) /
8131                 packet[IPv6] for packet in capture_ip6]
8132         self.pg0.add_stream(pkts)
8133         self.pg_enable_capture(self.pg_interfaces)
8134         self.pg_start()
8135         capture = self.pg1.get_capture(len(pkts))
8136         for packet in capture:
8137             try:
8138                 self.assertEqual(packet[IP].src, self.nat_addr)
8139                 self.assertEqual(packet[IP].dst, self.pg1.remote_ip4)
8140                 self.assertEqual(packet[ICMP].type, 3)
8141                 self.assertEqual(packet[ICMP].code, 13)
8142                 inner = packet[IPerror]
8143                 self.assertEqual(inner.src, self.pg1.remote_ip4)
8144                 self.assertEqual(inner.dst, self.nat_addr)
8145                 self.assert_packet_checksums_valid(packet)
8146                 if inner.haslayer(TCPerror):
8147                     self.assertEqual(inner[TCPerror].dport, self.tcp_port_out)
8148                 elif inner.haslayer(UDPerror):
8149                     self.assertEqual(inner[UDPerror].dport, self.udp_port_out)
8150                 else:
8151                     self.assertEqual(inner[ICMPerror].id, self.icmp_id_out)
8152             except:
8153                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
8154                 raise
8155
8156         # out2in
8157         pkts = [Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
8158                 IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
8159                 ICMP(type=3, code=13) /
8160                 packet[IP] for packet in capture_ip4]
8161         self.pg1.add_stream(pkts)
8162         self.pg_enable_capture(self.pg_interfaces)
8163         self.pg_start()
8164         capture = self.pg0.get_capture(len(pkts))
8165         for packet in capture:
8166             try:
8167                 self.assertEqual(packet[IPv6].src, ip.src)
8168                 self.assertEqual(packet[IPv6].dst, self.pg0.remote_ip6)
8169                 icmp = packet[ICMPv6DestUnreach]
8170                 self.assertEqual(icmp.code, 1)
8171                 inner = icmp[IPerror6]
8172                 self.assertEqual(inner.src, self.pg0.remote_ip6)
8173                 self.assertEqual(inner.dst, ip.src)
8174                 self.assert_icmpv6_checksum_valid(packet)
8175                 if inner.haslayer(TCPerror):
8176                     self.assertEqual(inner[TCPerror].sport, self.tcp_port_in)
8177                 elif inner.haslayer(UDPerror):
8178                     self.assertEqual(inner[UDPerror].sport, self.udp_port_in)
8179                 else:
8180                     self.assertEqual(inner[ICMPv6EchoRequest].id,
8181                                      self.icmp_id_in)
8182             except:
8183                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
8184                 raise
8185
8186     def test_hairpinning(self):
8187         """ NAT64 hairpinning """
8188
8189         client = self.pg0.remote_hosts[0]
8190         server = self.pg0.remote_hosts[1]
8191         server_tcp_in_port = 22
8192         server_tcp_out_port = 4022
8193         server_udp_in_port = 23
8194         server_udp_out_port = 4023
8195         client_tcp_in_port = 1234
8196         client_udp_in_port = 1235
8197         client_tcp_out_port = 0
8198         client_udp_out_port = 0
8199         ip = IPv6(src=''.join(['64:ff9b::', self.nat_addr]))
8200         nat_addr_ip6 = ip.src
8201
8202         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr,
8203                                                 end_addr=self.nat_addr,
8204                                                 vrf_id=0xFFFFFFFF,
8205                                                 is_add=1)
8206         flags = self.config_flags.NAT_IS_INSIDE
8207         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
8208                                           sw_if_index=self.pg0.sw_if_index)
8209         self.vapi.nat64_add_del_interface(is_add=1, flags=0,
8210                                           sw_if_index=self.pg1.sw_if_index)
8211
8212         self.vapi.nat64_add_del_static_bib(i_addr=server.ip6n,
8213                                            o_addr=self.nat_addr,
8214                                            i_port=server_tcp_in_port,
8215                                            o_port=server_tcp_out_port,
8216                                            proto=IP_PROTOS.tcp, vrf_id=0,
8217                                            is_add=1)
8218         self.vapi.nat64_add_del_static_bib(i_addr=server.ip6n,
8219                                            o_addr=self.nat_addr,
8220                                            i_port=server_udp_in_port,
8221                                            o_port=server_udp_out_port,
8222                                            proto=IP_PROTOS.udp, vrf_id=0,
8223                                            is_add=1)
8224
8225         # client to server
8226         pkts = []
8227         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
8228              IPv6(src=client.ip6, dst=nat_addr_ip6) /
8229              TCP(sport=client_tcp_in_port, dport=server_tcp_out_port))
8230         pkts.append(p)
8231         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
8232              IPv6(src=client.ip6, dst=nat_addr_ip6) /
8233              UDP(sport=client_udp_in_port, dport=server_udp_out_port))
8234         pkts.append(p)
8235         self.pg0.add_stream(pkts)
8236         self.pg_enable_capture(self.pg_interfaces)
8237         self.pg_start()
8238         capture = self.pg0.get_capture(len(pkts))
8239         for packet in capture:
8240             try:
8241                 self.assertEqual(packet[IPv6].src, nat_addr_ip6)
8242                 self.assertEqual(packet[IPv6].dst, server.ip6)
8243                 self.assert_packet_checksums_valid(packet)
8244                 if packet.haslayer(TCP):
8245                     self.assertNotEqual(packet[TCP].sport, client_tcp_in_port)
8246                     self.assertEqual(packet[TCP].dport, server_tcp_in_port)
8247                     client_tcp_out_port = packet[TCP].sport
8248                 else:
8249                     self.assertNotEqual(packet[UDP].sport, client_udp_in_port)
8250                     self.assertEqual(packet[UDP].dport, server_udp_in_port)
8251                     client_udp_out_port = packet[UDP].sport
8252             except:
8253                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
8254                 raise
8255
8256         # server to client
8257         pkts = []
8258         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
8259              IPv6(src=server.ip6, dst=nat_addr_ip6) /
8260              TCP(sport=server_tcp_in_port, dport=client_tcp_out_port))
8261         pkts.append(p)
8262         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
8263              IPv6(src=server.ip6, dst=nat_addr_ip6) /
8264              UDP(sport=server_udp_in_port, dport=client_udp_out_port))
8265         pkts.append(p)
8266         self.pg0.add_stream(pkts)
8267         self.pg_enable_capture(self.pg_interfaces)
8268         self.pg_start()
8269         capture = self.pg0.get_capture(len(pkts))
8270         for packet in capture:
8271             try:
8272                 self.assertEqual(packet[IPv6].src, nat_addr_ip6)
8273                 self.assertEqual(packet[IPv6].dst, client.ip6)
8274                 self.assert_packet_checksums_valid(packet)
8275                 if packet.haslayer(TCP):
8276                     self.assertEqual(packet[TCP].sport, server_tcp_out_port)
8277                     self.assertEqual(packet[TCP].dport, client_tcp_in_port)
8278                 else:
8279                     self.assertEqual(packet[UDP].sport, server_udp_out_port)
8280                     self.assertEqual(packet[UDP].dport, client_udp_in_port)
8281             except:
8282                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
8283                 raise
8284
8285         # ICMP error
8286         pkts = []
8287         pkts = [Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
8288                 IPv6(src=client.ip6, dst=nat_addr_ip6) /
8289                 ICMPv6DestUnreach(code=1) /
8290                 packet[IPv6] for packet in capture]
8291         self.pg0.add_stream(pkts)
8292         self.pg_enable_capture(self.pg_interfaces)
8293         self.pg_start()
8294         capture = self.pg0.get_capture(len(pkts))
8295         for packet in capture:
8296             try:
8297                 self.assertEqual(packet[IPv6].src, nat_addr_ip6)
8298                 self.assertEqual(packet[IPv6].dst, server.ip6)
8299                 icmp = packet[ICMPv6DestUnreach]
8300                 self.assertEqual(icmp.code, 1)
8301                 inner = icmp[IPerror6]
8302                 self.assertEqual(inner.src, server.ip6)
8303                 self.assertEqual(inner.dst, nat_addr_ip6)
8304                 self.assert_packet_checksums_valid(packet)
8305                 if inner.haslayer(TCPerror):
8306                     self.assertEqual(inner[TCPerror].sport, server_tcp_in_port)
8307                     self.assertEqual(inner[TCPerror].dport,
8308                                      client_tcp_out_port)
8309                 else:
8310                     self.assertEqual(inner[UDPerror].sport, server_udp_in_port)
8311                     self.assertEqual(inner[UDPerror].dport,
8312                                      client_udp_out_port)
8313             except:
8314                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
8315                 raise
8316
8317     def test_prefix(self):
8318         """ NAT64 Network-Specific Prefix """
8319
8320         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr,
8321                                                 end_addr=self.nat_addr,
8322                                                 vrf_id=0xFFFFFFFF,
8323                                                 is_add=1)
8324         flags = self.config_flags.NAT_IS_INSIDE
8325         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
8326                                           sw_if_index=self.pg0.sw_if_index)
8327         self.vapi.nat64_add_del_interface(is_add=1, flags=0,
8328                                           sw_if_index=self.pg1.sw_if_index)
8329         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.vrf1_nat_addr,
8330                                                 end_addr=self.vrf1_nat_addr,
8331                                                 vrf_id=self.vrf1_id, is_add=1)
8332         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
8333                                           sw_if_index=self.pg2.sw_if_index)
8334
8335         # Add global prefix
8336         global_pref64 = "2001:db8::"
8337         global_pref64_len = 32
8338         global_pref64_str = "{}/{}".format(global_pref64, global_pref64_len)
8339         self.vapi.nat64_add_del_prefix(prefix=global_pref64_str, vrf_id=0,
8340                                        is_add=1)
8341
8342         prefix = self.vapi.nat64_prefix_dump()
8343         self.assertEqual(len(prefix), 1)
8344         self.assertEqual(prefix[0].prefix,
8345                          IPv6Network(unicode(global_pref64_str)))
8346         self.assertEqual(prefix[0].vrf_id, 0)
8347
8348         # Add tenant specific prefix
8349         vrf1_pref64 = "2001:db8:122:300::"
8350         vrf1_pref64_len = 56
8351         vrf1_pref64_str = "{}/{}".format(vrf1_pref64, vrf1_pref64_len)
8352         self.vapi.nat64_add_del_prefix(prefix=vrf1_pref64_str,
8353                                        vrf_id=self.vrf1_id, is_add=1)
8354
8355         prefix = self.vapi.nat64_prefix_dump()
8356         self.assertEqual(len(prefix), 2)
8357
8358         # Global prefix
8359         pkts = self.create_stream_in_ip6(self.pg0,
8360                                          self.pg1,
8361                                          pref=global_pref64,
8362                                          plen=global_pref64_len)
8363         self.pg0.add_stream(pkts)
8364         self.pg_enable_capture(self.pg_interfaces)
8365         self.pg_start()
8366         capture = self.pg1.get_capture(len(pkts))
8367         self.verify_capture_out(capture, nat_ip=self.nat_addr,
8368                                 dst_ip=self.pg1.remote_ip4)
8369
8370         pkts = self.create_stream_out(self.pg1, dst_ip=self.nat_addr)
8371         self.pg1.add_stream(pkts)
8372         self.pg_enable_capture(self.pg_interfaces)
8373         self.pg_start()
8374         capture = self.pg0.get_capture(len(pkts))
8375         dst_ip = self.compose_ip6(self.pg1.remote_ip4,
8376                                   global_pref64,
8377                                   global_pref64_len)
8378         self.verify_capture_in_ip6(capture, dst_ip, self.pg0.remote_ip6)
8379
8380         # Tenant specific prefix
8381         pkts = self.create_stream_in_ip6(self.pg2,
8382                                          self.pg1,
8383                                          pref=vrf1_pref64,
8384                                          plen=vrf1_pref64_len)
8385         self.pg2.add_stream(pkts)
8386         self.pg_enable_capture(self.pg_interfaces)
8387         self.pg_start()
8388         capture = self.pg1.get_capture(len(pkts))
8389         self.verify_capture_out(capture, nat_ip=self.vrf1_nat_addr,
8390                                 dst_ip=self.pg1.remote_ip4)
8391
8392         pkts = self.create_stream_out(self.pg1, dst_ip=self.vrf1_nat_addr)
8393         self.pg1.add_stream(pkts)
8394         self.pg_enable_capture(self.pg_interfaces)
8395         self.pg_start()
8396         capture = self.pg2.get_capture(len(pkts))
8397         dst_ip = self.compose_ip6(self.pg1.remote_ip4,
8398                                   vrf1_pref64,
8399                                   vrf1_pref64_len)
8400         self.verify_capture_in_ip6(capture, dst_ip, self.pg2.remote_ip6)
8401
8402     def test_unknown_proto(self):
8403         """ NAT64 translate packet with unknown protocol """
8404
8405         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr,
8406                                                 end_addr=self.nat_addr,
8407                                                 vrf_id=0xFFFFFFFF,
8408                                                 is_add=1)
8409         flags = self.config_flags.NAT_IS_INSIDE
8410         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
8411                                           sw_if_index=self.pg0.sw_if_index)
8412         self.vapi.nat64_add_del_interface(is_add=1, flags=0,
8413                                           sw_if_index=self.pg1.sw_if_index)
8414         remote_ip6 = self.compose_ip6(self.pg1.remote_ip4, '64:ff9b::', 96)
8415
8416         # in2out
8417         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
8418              IPv6(src=self.pg0.remote_ip6, dst=remote_ip6) /
8419              TCP(sport=self.tcp_port_in, dport=20))
8420         self.pg0.add_stream(p)
8421         self.pg_enable_capture(self.pg_interfaces)
8422         self.pg_start()
8423         p = self.pg1.get_capture(1)
8424
8425         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
8426              IPv6(src=self.pg0.remote_ip6, dst=remote_ip6, nh=47) /
8427              GRE() /
8428              IP(src=self.pg2.local_ip4, dst=self.pg2.remote_ip4) /
8429              TCP(sport=1234, dport=1234))
8430         self.pg0.add_stream(p)
8431         self.pg_enable_capture(self.pg_interfaces)
8432         self.pg_start()
8433         p = self.pg1.get_capture(1)
8434         packet = p[0]
8435         try:
8436             self.assertEqual(packet[IP].src, self.nat_addr)
8437             self.assertEqual(packet[IP].dst, self.pg1.remote_ip4)
8438             self.assertEqual(packet.haslayer(GRE), 1)
8439             self.assert_packet_checksums_valid(packet)
8440         except:
8441             self.logger.error(ppp("Unexpected or invalid packet:", packet))
8442             raise
8443
8444         # out2in
8445         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
8446              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
8447              GRE() /
8448              IP(src=self.pg2.remote_ip4, dst=self.pg2.local_ip4) /
8449              TCP(sport=1234, dport=1234))
8450         self.pg1.add_stream(p)
8451         self.pg_enable_capture(self.pg_interfaces)
8452         self.pg_start()
8453         p = self.pg0.get_capture(1)
8454         packet = p[0]
8455         try:
8456             self.assertEqual(packet[IPv6].src, remote_ip6)
8457             self.assertEqual(packet[IPv6].dst, self.pg0.remote_ip6)
8458             self.assertEqual(packet[IPv6].nh, 47)
8459         except:
8460             self.logger.error(ppp("Unexpected or invalid packet:", packet))
8461             raise
8462
8463     def test_hairpinning_unknown_proto(self):
8464         """ NAT64 translate packet with unknown protocol - hairpinning """
8465
8466         client = self.pg0.remote_hosts[0]
8467         server = self.pg0.remote_hosts[1]
8468         server_tcp_in_port = 22
8469         server_tcp_out_port = 4022
8470         client_tcp_in_port = 1234
8471         client_tcp_out_port = 1235
8472         server_nat_ip = "10.0.0.100"
8473         client_nat_ip = "10.0.0.110"
8474         server_nat_ip6 = self.compose_ip6(server_nat_ip, '64:ff9b::', 96)
8475         client_nat_ip6 = self.compose_ip6(client_nat_ip, '64:ff9b::', 96)
8476
8477         self.vapi.nat64_add_del_pool_addr_range(start_addr=server_nat_ip,
8478                                                 end_addr=client_nat_ip,
8479                                                 vrf_id=0xFFFFFFFF,
8480                                                 is_add=1)
8481         flags = self.config_flags.NAT_IS_INSIDE
8482         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
8483                                           sw_if_index=self.pg0.sw_if_index)
8484         self.vapi.nat64_add_del_interface(is_add=1, flags=0,
8485                                           sw_if_index=self.pg1.sw_if_index)
8486
8487         self.vapi.nat64_add_del_static_bib(i_addr=server.ip6n,
8488                                            o_addr=server_nat_ip,
8489                                            i_port=server_tcp_in_port,
8490                                            o_port=server_tcp_out_port,
8491                                            proto=IP_PROTOS.tcp, vrf_id=0,
8492                                            is_add=1)
8493
8494         self.vapi.nat64_add_del_static_bib(i_addr=server.ip6n,
8495                                            o_addr=server_nat_ip, i_port=0,
8496                                            o_port=0,
8497                                            proto=IP_PROTOS.gre, vrf_id=0,
8498                                            is_add=1)
8499
8500         self.vapi.nat64_add_del_static_bib(i_addr=client.ip6n,
8501                                            o_addr=client_nat_ip,
8502                                            i_port=client_tcp_in_port,
8503                                            o_port=client_tcp_out_port,
8504                                            proto=IP_PROTOS.tcp, vrf_id=0,
8505                                            is_add=1)
8506
8507         # client to server
8508         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
8509              IPv6(src=client.ip6, dst=server_nat_ip6) /
8510              TCP(sport=client_tcp_in_port, dport=server_tcp_out_port))
8511         self.pg0.add_stream(p)
8512         self.pg_enable_capture(self.pg_interfaces)
8513         self.pg_start()
8514         p = self.pg0.get_capture(1)
8515
8516         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
8517              IPv6(src=client.ip6, dst=server_nat_ip6, nh=IP_PROTOS.gre) /
8518              GRE() /
8519              IP(src=self.pg2.local_ip4, dst=self.pg2.remote_ip4) /
8520              TCP(sport=1234, dport=1234))
8521         self.pg0.add_stream(p)
8522         self.pg_enable_capture(self.pg_interfaces)
8523         self.pg_start()
8524         p = self.pg0.get_capture(1)
8525         packet = p[0]
8526         try:
8527             self.assertEqual(packet[IPv6].src, client_nat_ip6)
8528             self.assertEqual(packet[IPv6].dst, server.ip6)
8529             self.assertEqual(packet[IPv6].nh, IP_PROTOS.gre)
8530         except:
8531             self.logger.error(ppp("Unexpected or invalid packet:", packet))
8532             raise
8533
8534         # server to client
8535         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
8536              IPv6(src=server.ip6, dst=client_nat_ip6, nh=IP_PROTOS.gre) /
8537              GRE() /
8538              IP(src=self.pg2.remote_ip4, dst=self.pg2.local_ip4) /
8539              TCP(sport=1234, dport=1234))
8540         self.pg0.add_stream(p)
8541         self.pg_enable_capture(self.pg_interfaces)
8542         self.pg_start()
8543         p = self.pg0.get_capture(1)
8544         packet = p[0]
8545         try:
8546             self.assertEqual(packet[IPv6].src, server_nat_ip6)
8547             self.assertEqual(packet[IPv6].dst, client.ip6)
8548             self.assertEqual(packet[IPv6].nh, IP_PROTOS.gre)
8549         except:
8550             self.logger.error(ppp("Unexpected or invalid packet:", packet))
8551             raise
8552
8553     def test_one_armed_nat64(self):
8554         """ One armed NAT64 """
8555         external_port = 0
8556         remote_host_ip6 = self.compose_ip6(self.pg3.remote_ip4,
8557                                            '64:ff9b::',
8558                                            96)
8559
8560         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr,
8561                                                 end_addr=self.nat_addr,
8562                                                 vrf_id=0xFFFFFFFF,
8563                                                 is_add=1)
8564         flags = self.config_flags.NAT_IS_INSIDE
8565         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
8566                                           sw_if_index=self.pg3.sw_if_index)
8567         self.vapi.nat64_add_del_interface(is_add=1, flags=0,
8568                                           sw_if_index=self.pg3.sw_if_index)
8569
8570         # in2out
8571         p = (Ether(src=self.pg3.remote_mac, dst=self.pg3.local_mac) /
8572              IPv6(src=self.pg3.remote_ip6, dst=remote_host_ip6) /
8573              TCP(sport=12345, dport=80))
8574         self.pg3.add_stream(p)
8575         self.pg_enable_capture(self.pg_interfaces)
8576         self.pg_start()
8577         capture = self.pg3.get_capture(1)
8578         p = capture[0]
8579         try:
8580             ip = p[IP]
8581             tcp = p[TCP]
8582             self.assertEqual(ip.src, self.nat_addr)
8583             self.assertEqual(ip.dst, self.pg3.remote_ip4)
8584             self.assertNotEqual(tcp.sport, 12345)
8585             external_port = tcp.sport
8586             self.assertEqual(tcp.dport, 80)
8587             self.assert_packet_checksums_valid(p)
8588         except:
8589             self.logger.error(ppp("Unexpected or invalid packet:", p))
8590             raise
8591
8592         # out2in
8593         p = (Ether(src=self.pg3.remote_mac, dst=self.pg3.local_mac) /
8594              IP(src=self.pg3.remote_ip4, dst=self.nat_addr) /
8595              TCP(sport=80, dport=external_port))
8596         self.pg3.add_stream(p)
8597         self.pg_enable_capture(self.pg_interfaces)
8598         self.pg_start()
8599         capture = self.pg3.get_capture(1)
8600         p = capture[0]
8601         try:
8602             ip = p[IPv6]
8603             tcp = p[TCP]
8604             self.assertEqual(ip.src, remote_host_ip6)
8605             self.assertEqual(ip.dst, self.pg3.remote_ip6)
8606             self.assertEqual(tcp.sport, 80)
8607             self.assertEqual(tcp.dport, 12345)
8608             self.assert_packet_checksums_valid(p)
8609         except:
8610             self.logger.error(ppp("Unexpected or invalid packet:", p))
8611             raise
8612
8613     def test_frag_in_order(self):
8614         """ NAT64 translate fragments arriving in order """
8615         self.tcp_port_in = random.randint(1025, 65535)
8616
8617         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr,
8618                                                 end_addr=self.nat_addr,
8619                                                 vrf_id=0xFFFFFFFF,
8620                                                 is_add=1)
8621         flags = self.config_flags.NAT_IS_INSIDE
8622         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
8623                                           sw_if_index=self.pg0.sw_if_index)
8624         self.vapi.nat64_add_del_interface(is_add=1, flags=0,
8625                                           sw_if_index=self.pg1.sw_if_index)
8626
8627         reass = self.vapi.nat_reass_dump()
8628         reass_n_start = len(reass)
8629
8630         # in2out
8631         data = b'a' * 200
8632         pkts = self.create_stream_frag_ip6(self.pg0, self.pg1.remote_ip4,
8633                                            self.tcp_port_in, 20, data)
8634         self.pg0.add_stream(pkts)
8635         self.pg_enable_capture(self.pg_interfaces)
8636         self.pg_start()
8637         frags = self.pg1.get_capture(len(pkts))
8638         p = self.reass_frags_and_verify(frags,
8639                                         self.nat_addr,
8640                                         self.pg1.remote_ip4)
8641         self.assertEqual(p[TCP].dport, 20)
8642         self.assertNotEqual(p[TCP].sport, self.tcp_port_in)
8643         self.tcp_port_out = p[TCP].sport
8644         self.assertEqual(data, p[Raw].load)
8645
8646         # out2in
8647         data = b"A" * 4 + b"b" * 16 + b"C" * 3
8648         pkts = self.create_stream_frag(self.pg1,
8649                                        self.nat_addr,
8650                                        20,
8651                                        self.tcp_port_out,
8652                                        data)
8653         self.pg1.add_stream(pkts)
8654         self.pg_enable_capture(self.pg_interfaces)
8655         self.pg_start()
8656         frags = self.pg0.get_capture(len(pkts))
8657         src = self.compose_ip6(self.pg1.remote_ip4, '64:ff9b::', 96)
8658         p = self.reass_frags_and_verify_ip6(frags, src, self.pg0.remote_ip6)
8659         self.assertEqual(p[TCP].sport, 20)
8660         self.assertEqual(p[TCP].dport, self.tcp_port_in)
8661         self.assertEqual(data, p[Raw].load)
8662
8663         reass = self.vapi.nat_reass_dump()
8664         reass_n_end = len(reass)
8665
8666         self.assertEqual(reass_n_end - reass_n_start, 2)
8667
8668     def test_reass_hairpinning(self):
8669         """ NAT64 fragments hairpinning """
8670         data = 'a' * 200
8671         server = self.pg0.remote_hosts[1]
8672         server_in_port = random.randint(1025, 65535)
8673         server_out_port = random.randint(1025, 65535)
8674         client_in_port = random.randint(1025, 65535)
8675         ip = IPv6(src=''.join(['64:ff9b::', self.nat_addr]))
8676         nat_addr_ip6 = ip.src
8677
8678         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr,
8679                                                 end_addr=self.nat_addr,
8680                                                 vrf_id=0xFFFFFFFF,
8681                                                 is_add=1)
8682         flags = self.config_flags.NAT_IS_INSIDE
8683         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
8684                                           sw_if_index=self.pg0.sw_if_index)
8685         self.vapi.nat64_add_del_interface(is_add=1, flags=0,
8686                                           sw_if_index=self.pg1.sw_if_index)
8687
8688         # add static BIB entry for server
8689         self.vapi.nat64_add_del_static_bib(i_addr=server.ip6n,
8690                                            o_addr=self.nat_addr,
8691                                            i_port=server_in_port,
8692                                            o_port=server_out_port,
8693                                            proto=IP_PROTOS.tcp, vrf_id=0,
8694                                            is_add=1)
8695
8696         # send packet from host to server
8697         pkts = self.create_stream_frag_ip6(self.pg0,
8698                                            self.nat_addr,
8699                                            client_in_port,
8700                                            server_out_port,
8701                                            data)
8702         self.pg0.add_stream(pkts)
8703         self.pg_enable_capture(self.pg_interfaces)
8704         self.pg_start()
8705         frags = self.pg0.get_capture(len(pkts))
8706         p = self.reass_frags_and_verify_ip6(frags, nat_addr_ip6, server.ip6)
8707         self.assertNotEqual(p[TCP].sport, client_in_port)
8708         self.assertEqual(p[TCP].dport, server_in_port)
8709         self.assertEqual(data, p[Raw].load)
8710
8711     def test_frag_out_of_order(self):
8712         """ NAT64 translate fragments arriving out of order """
8713         self.tcp_port_in = random.randint(1025, 65535)
8714
8715         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr,
8716                                                 end_addr=self.nat_addr,
8717                                                 vrf_id=0xFFFFFFFF,
8718                                                 is_add=1)
8719         flags = self.config_flags.NAT_IS_INSIDE
8720         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
8721                                           sw_if_index=self.pg0.sw_if_index)
8722         self.vapi.nat64_add_del_interface(is_add=1, flags=0,
8723                                           sw_if_index=self.pg1.sw_if_index)
8724
8725         # in2out
8726         data = b'a' * 200
8727         pkts = self.create_stream_frag_ip6(self.pg0, self.pg1.remote_ip4,
8728                                            self.tcp_port_in, 20, data)
8729         pkts.reverse()
8730         self.pg0.add_stream(pkts)
8731         self.pg_enable_capture(self.pg_interfaces)
8732         self.pg_start()
8733         frags = self.pg1.get_capture(len(pkts))
8734         p = self.reass_frags_and_verify(frags,
8735                                         self.nat_addr,
8736                                         self.pg1.remote_ip4)
8737         self.assertEqual(p[TCP].dport, 20)
8738         self.assertNotEqual(p[TCP].sport, self.tcp_port_in)
8739         self.tcp_port_out = p[TCP].sport
8740         self.assertEqual(data, p[Raw].load)
8741
8742         # out2in
8743         data = b"A" * 4 + b"B" * 16 + b"C" * 3
8744         pkts = self.create_stream_frag(self.pg1,
8745                                        self.nat_addr,
8746                                        20,
8747                                        self.tcp_port_out,
8748                                        data)
8749         pkts.reverse()
8750         self.pg1.add_stream(pkts)
8751         self.pg_enable_capture(self.pg_interfaces)
8752         self.pg_start()
8753         frags = self.pg0.get_capture(len(pkts))
8754         src = self.compose_ip6(self.pg1.remote_ip4, '64:ff9b::', 96)
8755         p = self.reass_frags_and_verify_ip6(frags, src, self.pg0.remote_ip6)
8756         self.assertEqual(p[TCP].sport, 20)
8757         self.assertEqual(p[TCP].dport, self.tcp_port_in)
8758         self.assertEqual(data, p[Raw].load)
8759
8760     def test_interface_addr(self):
8761         """ Acquire NAT64 pool addresses from interface """
8762         self.vapi.nat64_add_del_interface_addr(
8763             is_add=1,
8764             sw_if_index=self.pg4.sw_if_index)
8765
8766         # no address in NAT64 pool
8767         addresses = self.vapi.nat44_address_dump()
8768         self.assertEqual(0, len(addresses))
8769
8770         # configure interface address and check NAT64 address pool
8771         self.pg4.config_ip4()
8772         addresses = self.vapi.nat64_pool_addr_dump()
8773         self.assertEqual(len(addresses), 1)
8774
8775         self.assertEqual(str(addresses[0].address),
8776                          self.pg4.local_ip4)
8777
8778         # remove interface address and check NAT64 address pool
8779         self.pg4.unconfig_ip4()
8780         addresses = self.vapi.nat64_pool_addr_dump()
8781         self.assertEqual(0, len(addresses))
8782
8783     @unittest.skipUnless(running_extended_tests, "part of extended tests")
8784     def test_ipfix_max_bibs_sessions(self):
8785         """ IPFIX logging maximum session and BIB entries exceeded """
8786         max_bibs = 1280
8787         max_sessions = 2560
8788         remote_host_ip6 = self.compose_ip6(self.pg1.remote_ip4,
8789                                            '64:ff9b::',
8790                                            96)
8791
8792         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr,
8793                                                 end_addr=self.nat_addr,
8794                                                 vrf_id=0xFFFFFFFF,
8795                                                 is_add=1)
8796         flags = self.config_flags.NAT_IS_INSIDE
8797         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
8798                                           sw_if_index=self.pg0.sw_if_index)
8799         self.vapi.nat64_add_del_interface(is_add=1, flags=0,
8800                                           sw_if_index=self.pg1.sw_if_index)
8801
8802         pkts = []
8803         src = ""
8804         for i in range(0, max_bibs):
8805             src = "fd01:aa::%x" % (i)
8806             p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
8807                  IPv6(src=src, dst=remote_host_ip6) /
8808                  TCP(sport=12345, dport=80))
8809             pkts.append(p)
8810             p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
8811                  IPv6(src=src, dst=remote_host_ip6) /
8812                  TCP(sport=12345, dport=22))
8813             pkts.append(p)
8814         self.pg0.add_stream(pkts)
8815         self.pg_enable_capture(self.pg_interfaces)
8816         self.pg_start()
8817         self.pg1.get_capture(max_sessions)
8818
8819         self.vapi.set_ipfix_exporter(collector_address=self.pg3.remote_ip4n,
8820                                      src_address=self.pg3.local_ip4n,
8821                                      path_mtu=512,
8822                                      template_interval=10)
8823         self.vapi.nat_ipfix_enable_disable(domain_id=self.ipfix_domain_id,
8824                                            src_port=self.ipfix_src_port,
8825                                            enable=1)
8826
8827         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
8828              IPv6(src=src, dst=remote_host_ip6) /
8829              TCP(sport=12345, dport=25))
8830         self.pg0.add_stream(p)
8831         self.pg_enable_capture(self.pg_interfaces)
8832         self.pg_start()
8833         self.pg1.assert_nothing_captured()
8834         sleep(1)
8835         self.vapi.cli("ipfix flush")  # FIXME this should be an API call
8836         capture = self.pg3.get_capture(9)
8837         ipfix = IPFIXDecoder()
8838         # first load template
8839         for p in capture:
8840             self.assertTrue(p.haslayer(IPFIX))
8841             self.assertEqual(p[IP].src, self.pg3.local_ip4)
8842             self.assertEqual(p[IP].dst, self.pg3.remote_ip4)
8843             self.assertEqual(p[UDP].sport, self.ipfix_src_port)
8844             self.assertEqual(p[UDP].dport, 4739)
8845             self.assertEqual(p[IPFIX].observationDomainID,
8846                              self.ipfix_domain_id)
8847             if p.haslayer(Template):
8848                 ipfix.add_template(p.getlayer(Template))
8849         # verify events in data set
8850         for p in capture:
8851             if p.haslayer(Data):
8852                 data = ipfix.decode_data_set(p.getlayer(Set))
8853                 self.verify_ipfix_max_sessions(data, max_sessions)
8854
8855         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
8856              IPv6(src=self.pg0.remote_ip6, dst=remote_host_ip6) /
8857              TCP(sport=12345, dport=80))
8858         self.pg0.add_stream(p)
8859         self.pg_enable_capture(self.pg_interfaces)
8860         self.pg_start()
8861         self.pg1.assert_nothing_captured()
8862         sleep(1)
8863         self.vapi.cli("ipfix flush")  # FIXME this should be an API call
8864         capture = self.pg3.get_capture(1)
8865         # verify events in data set
8866         for p in capture:
8867             self.assertTrue(p.haslayer(IPFIX))
8868             self.assertEqual(p[IP].src, self.pg3.local_ip4)
8869             self.assertEqual(p[IP].dst, self.pg3.remote_ip4)
8870             self.assertEqual(p[UDP].sport, self.ipfix_src_port)
8871             self.assertEqual(p[UDP].dport, 4739)
8872             self.assertEqual(p[IPFIX].observationDomainID,
8873                              self.ipfix_domain_id)
8874             if p.haslayer(Data):
8875                 data = ipfix.decode_data_set(p.getlayer(Set))
8876                 self.verify_ipfix_max_bibs(data, max_bibs)
8877
8878     def test_ipfix_max_frags(self):
8879         """ IPFIX logging maximum fragments pending reassembly exceeded """
8880         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr,
8881                                                 end_addr=self.nat_addr,
8882                                                 vrf_id=0xFFFFFFFF,
8883                                                 is_add=1)
8884         flags = self.config_flags.NAT_IS_INSIDE
8885         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
8886                                           sw_if_index=self.pg0.sw_if_index)
8887         self.vapi.nat64_add_del_interface(is_add=1, flags=0,
8888                                           sw_if_index=self.pg1.sw_if_index)
8889         self.vapi.nat_set_reass(timeout=2, max_reass=1024, max_frag=1,
8890                                 drop_frag=0, is_ip6=1)
8891         self.vapi.set_ipfix_exporter(collector_address=self.pg3.remote_ip4n,
8892                                      src_address=self.pg3.local_ip4n,
8893                                      path_mtu=512,
8894                                      template_interval=10)
8895         self.vapi.nat_ipfix_enable_disable(domain_id=self.ipfix_domain_id,
8896                                            src_port=self.ipfix_src_port,
8897                                            enable=1)
8898
8899         data = b'a' * 200
8900         pkts = self.create_stream_frag_ip6(self.pg0, self.pg1.remote_ip4,
8901                                            self.tcp_port_in, 20, data)
8902         pkts.reverse()
8903         self.pg0.add_stream(pkts)
8904         self.pg_enable_capture(self.pg_interfaces)
8905         self.pg_start()
8906         self.pg1.assert_nothing_captured()
8907         sleep(1)
8908         self.vapi.cli("ipfix flush")  # FIXME this should be an API call
8909         capture = self.pg3.get_capture(9)
8910         ipfix = IPFIXDecoder()
8911         # first load template
8912         for p in capture:
8913             self.assertTrue(p.haslayer(IPFIX))
8914             self.assertEqual(p[IP].src, self.pg3.local_ip4)
8915             self.assertEqual(p[IP].dst, self.pg3.remote_ip4)
8916             self.assertEqual(p[UDP].sport, self.ipfix_src_port)
8917             self.assertEqual(p[UDP].dport, 4739)
8918             self.assertEqual(p[IPFIX].observationDomainID,
8919                              self.ipfix_domain_id)
8920             if p.haslayer(Template):
8921                 ipfix.add_template(p.getlayer(Template))
8922         # verify events in data set
8923         for p in capture:
8924             if p.haslayer(Data):
8925                 data = ipfix.decode_data_set(p.getlayer(Set))
8926                 self.verify_ipfix_max_fragments_ip6(data, 1,
8927                                                     self.pg0.remote_ip6n)
8928
8929     def test_ipfix_bib_ses(self):
8930         """ IPFIX logging NAT64 BIB/session create and delete events """
8931         self.tcp_port_in = random.randint(1025, 65535)
8932         remote_host_ip6 = self.compose_ip6(self.pg1.remote_ip4,
8933                                            '64:ff9b::',
8934                                            96)
8935
8936         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr,
8937                                                 end_addr=self.nat_addr,
8938                                                 vrf_id=0xFFFFFFFF,
8939                                                 is_add=1)
8940         flags = self.config_flags.NAT_IS_INSIDE
8941         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
8942                                           sw_if_index=self.pg0.sw_if_index)
8943         self.vapi.nat64_add_del_interface(is_add=1, flags=0,
8944                                           sw_if_index=self.pg1.sw_if_index)
8945         self.vapi.set_ipfix_exporter(collector_address=self.pg3.remote_ip4n,
8946                                      src_address=self.pg3.local_ip4n,
8947                                      path_mtu=512,
8948                                      template_interval=10)
8949         self.vapi.nat_ipfix_enable_disable(domain_id=self.ipfix_domain_id,
8950                                            src_port=self.ipfix_src_port,
8951                                            enable=1)
8952
8953         # Create
8954         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
8955              IPv6(src=self.pg0.remote_ip6, dst=remote_host_ip6) /
8956              TCP(sport=self.tcp_port_in, dport=25))
8957         self.pg0.add_stream(p)
8958         self.pg_enable_capture(self.pg_interfaces)
8959         self.pg_start()
8960         p = self.pg1.get_capture(1)
8961         self.tcp_port_out = p[0][TCP].sport
8962         self.vapi.cli("ipfix flush")  # FIXME this should be an API call
8963         capture = self.pg3.get_capture(10)
8964         ipfix = IPFIXDecoder()
8965         # first load template
8966         for p in capture:
8967             self.assertTrue(p.haslayer(IPFIX))
8968             self.assertEqual(p[IP].src, self.pg3.local_ip4)
8969             self.assertEqual(p[IP].dst, self.pg3.remote_ip4)
8970             self.assertEqual(p[UDP].sport, self.ipfix_src_port)
8971             self.assertEqual(p[UDP].dport, 4739)
8972             self.assertEqual(p[IPFIX].observationDomainID,
8973                              self.ipfix_domain_id)
8974             if p.haslayer(Template):
8975                 ipfix.add_template(p.getlayer(Template))
8976         # verify events in data set
8977         for p in capture:
8978             if p.haslayer(Data):
8979                 data = ipfix.decode_data_set(p.getlayer(Set))
8980                 if scapy.compat.orb(data[0][230]) == 10:
8981                     self.verify_ipfix_bib(data, 1, self.pg0.remote_ip6n)
8982                 elif scapy.compat.orb(data[0][230]) == 6:
8983                     self.verify_ipfix_nat64_ses(data,
8984                                                 1,
8985                                                 self.pg0.remote_ip6n,
8986                                                 self.pg1.remote_ip4,
8987                                                 25)
8988                 else:
8989                     self.logger.error(ppp("Unexpected or invalid packet: ", p))
8990
8991         # Delete
8992         self.pg_enable_capture(self.pg_interfaces)
8993         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr,
8994                                                 end_addr=self.nat_addr,
8995                                                 vrf_id=0xFFFFFFFF,
8996                                                 is_add=0)
8997         self.vapi.cli("ipfix flush")  # FIXME this should be an API call
8998         capture = self.pg3.get_capture(2)
8999         # verify events in data set
9000         for p in capture:
9001             self.assertTrue(p.haslayer(IPFIX))
9002             self.assertEqual(p[IP].src, self.pg3.local_ip4)
9003             self.assertEqual(p[IP].dst, self.pg3.remote_ip4)
9004             self.assertEqual(p[UDP].sport, self.ipfix_src_port)
9005             self.assertEqual(p[UDP].dport, 4739)
9006             self.assertEqual(p[IPFIX].observationDomainID,
9007                              self.ipfix_domain_id)
9008             if p.haslayer(Data):
9009                 data = ipfix.decode_data_set(p.getlayer(Set))
9010                 if scapy.compat.orb(data[0][230]) == 11:
9011                     self.verify_ipfix_bib(data, 0, self.pg0.remote_ip6n)
9012                 elif scapy.compat.orb(data[0][230]) == 7:
9013                     self.verify_ipfix_nat64_ses(data,
9014                                                 0,
9015                                                 self.pg0.remote_ip6n,
9016                                                 self.pg1.remote_ip4,
9017                                                 25)
9018                 else:
9019                     self.logger.error(ppp("Unexpected or invalid packet: ", p))
9020
9021     def test_syslog_sess(self):
9022         """ Test syslog session creation and deletion """
9023         self.tcp_port_in = random.randint(1025, 65535)
9024         remote_host_ip6 = self.compose_ip6(self.pg1.remote_ip4,
9025                                            '64:ff9b::',
9026                                            96)
9027
9028         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr,
9029                                                 end_addr=self.nat_addr,
9030                                                 vrf_id=0xFFFFFFFF,
9031                                                 is_add=1)
9032         flags = self.config_flags.NAT_IS_INSIDE
9033         self.vapi.nat64_add_del_interface(is_add=1, flags=flags,
9034                                           sw_if_index=self.pg0.sw_if_index)
9035         self.vapi.nat64_add_del_interface(is_add=1, flags=0,
9036                                           sw_if_index=self.pg1.sw_if_index)
9037         self.vapi.syslog_set_filter(SYSLOG_SEVERITY.INFO)
9038         self.vapi.syslog_set_sender(self.pg3.local_ip4n, self.pg3.remote_ip4n)
9039
9040         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
9041              IPv6(src=self.pg0.remote_ip6, dst=remote_host_ip6) /
9042              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port))
9043         self.pg0.add_stream(p)
9044         self.pg_enable_capture(self.pg_interfaces)
9045         self.pg_start()
9046         p = self.pg1.get_capture(1)
9047         self.tcp_port_out = p[0][TCP].sport
9048         capture = self.pg3.get_capture(1)
9049         self.verify_syslog_sess(capture[0][Raw].load, is_ip6=True)
9050
9051         self.pg_enable_capture(self.pg_interfaces)
9052         self.pg_start()
9053         self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr,
9054                                                 end_addr=self.nat_addr,
9055                                                 vrf_id=0xFFFFFFFF,
9056                                                 is_add=0)
9057         capture = self.pg3.get_capture(1)
9058         self.verify_syslog_sess(capture[0][Raw].load, False, True)
9059
9060     def nat64_get_ses_num(self):
9061         """
9062         Return number of active NAT64 sessions.
9063         """
9064         st = self.vapi.nat64_st_dump(proto=255)
9065         return len(st)
9066
9067     def clear_nat64(self):
9068         """
9069         Clear NAT64 configuration.
9070         """
9071         self.vapi.nat_ipfix_enable_disable(domain_id=self.ipfix_domain_id,
9072                                            src_port=self.ipfix_src_port,
9073                                            enable=0)
9074         self.ipfix_src_port = 4739
9075         self.ipfix_domain_id = 1
9076
9077         self.vapi.syslog_set_filter(SYSLOG_SEVERITY.EMERG)
9078
9079         self.vapi.nat_set_timeouts(udp=300, tcp_established=7440,
9080                                    tcp_transitory=240, icmp=60)
9081
9082         interfaces = self.vapi.nat64_interface_dump()
9083         for intf in interfaces:
9084             self.vapi.nat64_add_del_interface(is_add=0, flags=intf.flags,
9085                                               sw_if_index=intf.sw_if_index)
9086
9087         bib = self.vapi.nat64_bib_dump(proto=255)
9088         for bibe in bib:
9089             if bibe.flags & self.config_flags.NAT_IS_STATIC:
9090                 self.vapi.nat64_add_del_static_bib(i_addr=bibe.i_addr,
9091                                                    o_addr=bibe.o_addr,
9092                                                    i_port=bibe.i_port,
9093                                                    o_port=bibe.o_port,
9094                                                    proto=bibe.proto,
9095                                                    vrf_id=bibe.vrf_id,
9096                                                    is_add=0)
9097
9098         adresses = self.vapi.nat64_pool_addr_dump()
9099         for addr in adresses:
9100             self.vapi.nat64_add_del_pool_addr_range(start_addr=addr.address,
9101                                                     end_addr=addr.address,
9102                                                     vrf_id=addr.vrf_id,
9103                                                     is_add=0)
9104
9105         prefixes = self.vapi.nat64_prefix_dump()
9106         for prefix in prefixes:
9107             self.vapi.nat64_add_del_prefix(prefix=str(prefix.prefix),
9108                                            vrf_id=prefix.vrf_id, is_add=0)
9109
9110         bibs = self.statistics.get_counter('/nat64/total-bibs')
9111         self.assertEqual(bibs[0][0], 0)
9112         sessions = self.statistics.get_counter('/nat64/total-sessions')
9113         self.assertEqual(sessions[0][0], 0)
9114
9115     def tearDown(self):
9116         super(TestNAT64, self).tearDown()
9117         if not self.vpp_dead:
9118             self.clear_nat64()
9119
9120     def show_commands_at_teardown(self):
9121         self.logger.info(self.vapi.cli("show nat64 pool"))
9122         self.logger.info(self.vapi.cli("show nat64 interfaces"))
9123         self.logger.info(self.vapi.cli("show nat64 prefix"))
9124         self.logger.info(self.vapi.cli("show nat64 bib all"))
9125         self.logger.info(self.vapi.cli("show nat64 session table all"))
9126         self.logger.info(self.vapi.cli("show nat virtual-reassembly"))
9127
9128
9129 class TestDSlite(MethodHolder):
9130     """ DS-Lite Test Cases """
9131
9132     @classmethod
9133     def setUpClass(cls):
9134         super(TestDSlite, cls).setUpClass()
9135
9136         try:
9137             cls.nat_addr = '10.0.0.3'
9138
9139             cls.create_pg_interfaces(range(3))
9140             cls.pg0.admin_up()
9141             cls.pg0.config_ip4()
9142             cls.pg0.resolve_arp()
9143             cls.pg1.admin_up()
9144             cls.pg1.config_ip6()
9145             cls.pg1.generate_remote_hosts(2)
9146             cls.pg1.configure_ipv6_neighbors()
9147             cls.pg2.admin_up()
9148             cls.pg2.config_ip4()
9149             cls.pg2.resolve_arp()
9150
9151         except Exception:
9152             super(TestDSlite, cls).tearDownClass()
9153             raise
9154
9155     @classmethod
9156     def tearDownClass(cls):
9157         super(TestDSlite, cls).tearDownClass()
9158
9159     def verify_syslog_apmadd(self, data, isaddr, isport, xsaddr, xsport,
9160                              sv6enc, proto):
9161         message = data.decode('utf-8')
9162         try:
9163             message = SyslogMessage.parse(message)
9164         except ParseError as e:
9165             self.logger.error(e)
9166         else:
9167             self.assertEqual(message.severity, SyslogSeverity.info)
9168             self.assertEqual(message.appname, 'NAT')
9169             self.assertEqual(message.msgid, 'APMADD')
9170             sd_params = message.sd.get('napmap')
9171             self.assertTrue(sd_params is not None)
9172             self.assertEqual(sd_params.get('IATYP'), 'IPv4')
9173             self.assertEqual(sd_params.get('ISADDR'), isaddr)
9174             self.assertEqual(sd_params.get('ISPORT'), "%d" % isport)
9175             self.assertEqual(sd_params.get('XATYP'), 'IPv4')
9176             self.assertEqual(sd_params.get('XSADDR'), xsaddr)
9177             self.assertEqual(sd_params.get('XSPORT'), "%d" % xsport)
9178             self.assertEqual(sd_params.get('PROTO'), "%d" % proto)
9179             self.assertTrue(sd_params.get('SSUBIX') is not None)
9180             self.assertEqual(sd_params.get('SV6ENC'), sv6enc)
9181
9182     def test_dslite(self):
9183         """ Test DS-Lite """
9184         nat_config = self.vapi.nat_show_config()
9185         self.assertEqual(0, nat_config.dslite_ce)
9186
9187         self.vapi.dslite_add_del_pool_addr_range(start_addr=self.nat_addr,
9188                                                  end_addr=self.nat_addr,
9189                                                  is_add=1)
9190         aftr_ip4 = '192.0.0.1'
9191         aftr_ip6 = '2001:db8:85a3::8a2e:370:1'
9192         self.vapi.dslite_set_aftr_addr(ip4_addr=aftr_ip4, ip6_addr=aftr_ip6)
9193         self.vapi.syslog_set_sender(self.pg2.local_ip4n, self.pg2.remote_ip4n)
9194
9195         # UDP
9196         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
9197              IPv6(dst=aftr_ip6, src=self.pg1.remote_hosts[0].ip6) /
9198              IP(dst=self.pg0.remote_ip4, src='192.168.1.1') /
9199              UDP(sport=20000, dport=10000))
9200         self.pg1.add_stream(p)
9201         self.pg_enable_capture(self.pg_interfaces)
9202         self.pg_start()
9203         capture = self.pg0.get_capture(1)
9204         capture = capture[0]
9205         self.assertFalse(capture.haslayer(IPv6))
9206         self.assertEqual(capture[IP].src, self.nat_addr)
9207         self.assertEqual(capture[IP].dst, self.pg0.remote_ip4)
9208         self.assertNotEqual(capture[UDP].sport, 20000)
9209         self.assertEqual(capture[UDP].dport, 10000)
9210         self.assert_packet_checksums_valid(capture)
9211         out_port = capture[UDP].sport
9212         capture = self.pg2.get_capture(1)
9213         self.verify_syslog_apmadd(capture[0][Raw].load, '192.168.1.1',
9214                                   20000, self.nat_addr, out_port,
9215                                   self.pg1.remote_hosts[0].ip6, IP_PROTOS.udp)
9216
9217         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
9218              IP(dst=self.nat_addr, src=self.pg0.remote_ip4) /
9219              UDP(sport=10000, dport=out_port))
9220         self.pg0.add_stream(p)
9221         self.pg_enable_capture(self.pg_interfaces)
9222         self.pg_start()
9223         capture = self.pg1.get_capture(1)
9224         capture = capture[0]
9225         self.assertEqual(capture[IPv6].src, aftr_ip6)
9226         self.assertEqual(capture[IPv6].dst, self.pg1.remote_hosts[0].ip6)
9227         self.assertEqual(capture[IP].src, self.pg0.remote_ip4)
9228         self.assertEqual(capture[IP].dst, '192.168.1.1')
9229         self.assertEqual(capture[UDP].sport, 10000)
9230         self.assertEqual(capture[UDP].dport, 20000)
9231         self.assert_packet_checksums_valid(capture)
9232
9233         # TCP
9234         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
9235              IPv6(dst=aftr_ip6, src=self.pg1.remote_hosts[1].ip6) /
9236              IP(dst=self.pg0.remote_ip4, src='192.168.1.1') /
9237              TCP(sport=20001, dport=10001))
9238         self.pg1.add_stream(p)
9239         self.pg_enable_capture(self.pg_interfaces)
9240         self.pg_start()
9241         capture = self.pg0.get_capture(1)
9242         capture = capture[0]
9243         self.assertFalse(capture.haslayer(IPv6))
9244         self.assertEqual(capture[IP].src, self.nat_addr)
9245         self.assertEqual(capture[IP].dst, self.pg0.remote_ip4)
9246         self.assertNotEqual(capture[TCP].sport, 20001)
9247         self.assertEqual(capture[TCP].dport, 10001)
9248         self.assert_packet_checksums_valid(capture)
9249         out_port = capture[TCP].sport
9250
9251         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
9252              IP(dst=self.nat_addr, src=self.pg0.remote_ip4) /
9253              TCP(sport=10001, dport=out_port))
9254         self.pg0.add_stream(p)
9255         self.pg_enable_capture(self.pg_interfaces)
9256         self.pg_start()
9257         capture = self.pg1.get_capture(1)
9258         capture = capture[0]
9259         self.assertEqual(capture[IPv6].src, aftr_ip6)
9260         self.assertEqual(capture[IPv6].dst, self.pg1.remote_hosts[1].ip6)
9261         self.assertEqual(capture[IP].src, self.pg0.remote_ip4)
9262         self.assertEqual(capture[IP].dst, '192.168.1.1')
9263         self.assertEqual(capture[TCP].sport, 10001)
9264         self.assertEqual(capture[TCP].dport, 20001)
9265         self.assert_packet_checksums_valid(capture)
9266
9267         # ICMP
9268         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
9269              IPv6(dst=aftr_ip6, src=self.pg1.remote_hosts[1].ip6) /
9270              IP(dst=self.pg0.remote_ip4, src='192.168.1.1') /
9271              ICMP(id=4000, type='echo-request'))
9272         self.pg1.add_stream(p)
9273         self.pg_enable_capture(self.pg_interfaces)
9274         self.pg_start()
9275         capture = self.pg0.get_capture(1)
9276         capture = capture[0]
9277         self.assertFalse(capture.haslayer(IPv6))
9278         self.assertEqual(capture[IP].src, self.nat_addr)
9279         self.assertEqual(capture[IP].dst, self.pg0.remote_ip4)
9280         self.assertNotEqual(capture[ICMP].id, 4000)
9281         self.assert_packet_checksums_valid(capture)
9282         out_id = capture[ICMP].id
9283
9284         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
9285              IP(dst=self.nat_addr, src=self.pg0.remote_ip4) /
9286              ICMP(id=out_id, type='echo-reply'))
9287         self.pg0.add_stream(p)
9288         self.pg_enable_capture(self.pg_interfaces)
9289         self.pg_start()
9290         capture = self.pg1.get_capture(1)
9291         capture = capture[0]
9292         self.assertEqual(capture[IPv6].src, aftr_ip6)
9293         self.assertEqual(capture[IPv6].dst, self.pg1.remote_hosts[1].ip6)
9294         self.assertEqual(capture[IP].src, self.pg0.remote_ip4)
9295         self.assertEqual(capture[IP].dst, '192.168.1.1')
9296         self.assertEqual(capture[ICMP].id, 4000)
9297         self.assert_packet_checksums_valid(capture)
9298
9299         # ping DS-Lite AFTR tunnel endpoint address
9300         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
9301              IPv6(src=self.pg1.remote_hosts[1].ip6, dst=aftr_ip6) /
9302              ICMPv6EchoRequest())
9303         self.pg1.add_stream(p)
9304         self.pg_enable_capture(self.pg_interfaces)
9305         self.pg_start()
9306         capture = self.pg1.get_capture(1)
9307         capture = capture[0]
9308         self.assertEqual(capture[IPv6].src, aftr_ip6)
9309         self.assertEqual(capture[IPv6].dst, self.pg1.remote_hosts[1].ip6)
9310         self.assertTrue(capture.haslayer(ICMPv6EchoReply))
9311
9312         b4s = self.statistics.get_counter('/dslite/total-b4s')
9313         self.assertEqual(b4s[0][0], 2)
9314         sessions = self.statistics.get_counter('/dslite/total-sessions')
9315         self.assertEqual(sessions[0][0], 3)
9316
9317     def tearDown(self):
9318         super(TestDSlite, self).tearDown()
9319
9320     def show_commands_at_teardown(self):
9321         self.logger.info(self.vapi.cli("show dslite pool"))
9322         self.logger.info(
9323             self.vapi.cli("show dslite aftr-tunnel-endpoint-address"))
9324         self.logger.info(self.vapi.cli("show dslite sessions"))
9325
9326
9327 class TestDSliteCE(MethodHolder):
9328     """ DS-Lite CE Test Cases """
9329
9330     @classmethod
9331     def setUpConstants(cls):
9332         super(TestDSliteCE, cls).setUpConstants()
9333         cls.vpp_cmdline.extend(["nat", "{", "dslite ce", "}"])
9334
9335     @classmethod
9336     def setUpClass(cls):
9337         super(TestDSliteCE, cls).setUpClass()
9338
9339         try:
9340             cls.create_pg_interfaces(range(2))
9341             cls.pg0.admin_up()
9342             cls.pg0.config_ip4()
9343             cls.pg0.resolve_arp()
9344             cls.pg1.admin_up()
9345             cls.pg1.config_ip6()
9346             cls.pg1.generate_remote_hosts(1)
9347             cls.pg1.configure_ipv6_neighbors()
9348
9349         except Exception:
9350             super(TestDSliteCE, cls).tearDownClass()
9351             raise
9352
9353     @classmethod
9354     def tearDownClass(cls):
9355         super(TestDSliteCE, cls).tearDownClass()
9356
9357     def test_dslite_ce(self):
9358         """ Test DS-Lite CE """
9359
9360         nat_config = self.vapi.nat_show_config()
9361         self.assertEqual(1, nat_config.dslite_ce)
9362
9363         b4_ip4 = '192.0.0.2'
9364         b4_ip6 = '2001:db8:62aa::375e:f4c1:1'
9365         self.vapi.dslite_set_b4_addr(ip4_addr=b4_ip4, ip6_addr=b4_ip6)
9366
9367         aftr_ip4 = '192.0.0.1'
9368         aftr_ip6 = '2001:db8:85a3::8a2e:370:1'
9369         aftr_ip6_n = socket.inet_pton(socket.AF_INET6, aftr_ip6)
9370         self.vapi.dslite_set_aftr_addr(ip4_addr=aftr_ip4, ip6_addr=aftr_ip6)
9371
9372         self.vapi.ip_add_del_route(dst_address=aftr_ip6_n,
9373                                    dst_address_length=128,
9374                                    next_hop_address=self.pg1.remote_ip6n,
9375                                    next_hop_sw_if_index=self.pg1.sw_if_index,
9376                                    is_ipv6=1)
9377
9378         # UDP encapsulation
9379         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
9380              IP(dst=self.pg1.remote_ip4, src=self.pg0.remote_ip4) /
9381              UDP(sport=10000, dport=20000))
9382         self.pg0.add_stream(p)
9383         self.pg_enable_capture(self.pg_interfaces)
9384         self.pg_start()
9385         capture = self.pg1.get_capture(1)
9386         capture = capture[0]
9387         self.assertEqual(capture[IPv6].src, b4_ip6)
9388         self.assertEqual(capture[IPv6].dst, aftr_ip6)
9389         self.assertEqual(capture[IP].src, self.pg0.remote_ip4)
9390         self.assertEqual(capture[IP].dst, self.pg1.remote_ip4)
9391         self.assertEqual(capture[UDP].sport, 10000)
9392         self.assertEqual(capture[UDP].dport, 20000)
9393         self.assert_packet_checksums_valid(capture)
9394
9395         # UDP decapsulation
9396         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
9397              IPv6(dst=b4_ip6, src=aftr_ip6) /
9398              IP(dst=self.pg0.remote_ip4, src=self.pg1.remote_ip4) /
9399              UDP(sport=20000, dport=10000))
9400         self.pg1.add_stream(p)
9401         self.pg_enable_capture(self.pg_interfaces)
9402         self.pg_start()
9403         capture = self.pg0.get_capture(1)
9404         capture = capture[0]
9405         self.assertFalse(capture.haslayer(IPv6))
9406         self.assertEqual(capture[IP].src, self.pg1.remote_ip4)
9407         self.assertEqual(capture[IP].dst, self.pg0.remote_ip4)
9408         self.assertEqual(capture[UDP].sport, 20000)
9409         self.assertEqual(capture[UDP].dport, 10000)
9410         self.assert_packet_checksums_valid(capture)
9411
9412         # ping DS-Lite B4 tunnel endpoint address
9413         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
9414              IPv6(src=self.pg1.remote_hosts[0].ip6, dst=b4_ip6) /
9415              ICMPv6EchoRequest())
9416         self.pg1.add_stream(p)
9417         self.pg_enable_capture(self.pg_interfaces)
9418         self.pg_start()
9419         capture = self.pg1.get_capture(1)
9420         capture = capture[0]
9421         self.assertEqual(capture[IPv6].src, b4_ip6)
9422         self.assertEqual(capture[IPv6].dst, self.pg1.remote_hosts[0].ip6)
9423         self.assertTrue(capture.haslayer(ICMPv6EchoReply))
9424
9425     def tearDown(self):
9426         super(TestDSliteCE, self).tearDown()
9427
9428     def show_commands_at_teardown(self):
9429         self.logger.info(
9430             self.vapi.cli("show dslite aftr-tunnel-endpoint-address"))
9431         self.logger.info(
9432             self.vapi.cli("show dslite b4-tunnel-endpoint-address"))
9433
9434
9435 class TestNAT66(MethodHolder):
9436     """ NAT66 Test Cases """
9437
9438     @classmethod
9439     def setUpClass(cls):
9440         super(TestNAT66, cls).setUpClass()
9441
9442         try:
9443             cls.nat_addr = 'fd01:ff::2'
9444
9445             cls.create_pg_interfaces(range(2))
9446             cls.interfaces = list(cls.pg_interfaces)
9447
9448             for i in cls.interfaces:
9449                 i.admin_up()
9450                 i.config_ip6()
9451                 i.configure_ipv6_neighbors()
9452
9453         except Exception:
9454             super(TestNAT66, cls).tearDownClass()
9455             raise
9456
9457     @classmethod
9458     def tearDownClass(cls):
9459         super(TestNAT66, cls).tearDownClass()
9460
9461     def test_static(self):
9462         """ 1:1 NAT66 test """
9463         flags = self.config_flags.NAT_IS_INSIDE
9464         self.vapi.nat66_add_del_interface(is_add=1, flags=flags,
9465                                           sw_if_index=self.pg0.sw_if_index)
9466         self.vapi.nat66_add_del_interface(is_add=1,
9467                                           sw_if_index=self.pg1.sw_if_index)
9468         self.vapi.nat66_add_del_static_mapping(
9469             local_ip_address=self.pg0.remote_ip6n,
9470             external_ip_address=self.nat_addr,
9471             is_add=1)
9472
9473         # in2out
9474         pkts = []
9475         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
9476              IPv6(src=self.pg0.remote_ip6, dst=self.pg1.remote_ip6) /
9477              TCP())
9478         pkts.append(p)
9479         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
9480              IPv6(src=self.pg0.remote_ip6, dst=self.pg1.remote_ip6) /
9481              UDP())
9482         pkts.append(p)
9483         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
9484              IPv6(src=self.pg0.remote_ip6, dst=self.pg1.remote_ip6) /
9485              ICMPv6EchoRequest())
9486         pkts.append(p)
9487         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
9488              IPv6(src=self.pg0.remote_ip6, dst=self.pg1.remote_ip6) /
9489              GRE() / IP() / TCP())
9490         pkts.append(p)
9491         self.pg0.add_stream(pkts)
9492         self.pg_enable_capture(self.pg_interfaces)
9493         self.pg_start()
9494         capture = self.pg1.get_capture(len(pkts))
9495         for packet in capture:
9496             try:
9497                 self.assertEqual(packet[IPv6].src, self.nat_addr)
9498                 self.assertEqual(packet[IPv6].dst, self.pg1.remote_ip6)
9499                 self.assert_packet_checksums_valid(packet)
9500             except:
9501                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
9502                 raise
9503
9504         # out2in
9505         pkts = []
9506         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
9507              IPv6(src=self.pg1.remote_ip6, dst=self.nat_addr) /
9508              TCP())
9509         pkts.append(p)
9510         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
9511              IPv6(src=self.pg1.remote_ip6, dst=self.nat_addr) /
9512              UDP())
9513         pkts.append(p)
9514         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
9515              IPv6(src=self.pg1.remote_ip6, dst=self.nat_addr) /
9516              ICMPv6EchoReply())
9517         pkts.append(p)
9518         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
9519              IPv6(src=self.pg1.remote_ip6, dst=self.nat_addr) /
9520              GRE() / IP() / TCP())
9521         pkts.append(p)
9522         self.pg1.add_stream(pkts)
9523         self.pg_enable_capture(self.pg_interfaces)
9524         self.pg_start()
9525         capture = self.pg0.get_capture(len(pkts))
9526         for packet in capture:
9527             try:
9528                 self.assertEqual(packet[IPv6].src, self.pg1.remote_ip6)
9529                 self.assertEqual(packet[IPv6].dst, self.pg0.remote_ip6)
9530                 self.assert_packet_checksums_valid(packet)
9531             except:
9532                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
9533                 raise
9534
9535         sm = self.vapi.nat66_static_mapping_dump()
9536         self.assertEqual(len(sm), 1)
9537         self.assertEqual(sm[0].total_pkts, 8)
9538
9539     def test_check_no_translate(self):
9540         """ NAT66 translate only when egress interface is outside interface """
9541         flags = self.config_flags.NAT_IS_INSIDE
9542         self.vapi.nat66_add_del_interface(is_add=1, flags=flags,
9543                                           sw_if_index=self.pg0.sw_if_index)
9544         self.vapi.nat66_add_del_interface(is_add=1, flags=flags,
9545                                           sw_if_index=self.pg1.sw_if_index)
9546         self.vapi.nat66_add_del_static_mapping(
9547             local_ip_address=self.pg0.remote_ip6n,
9548             external_ip_address=self.nat_addr,
9549             is_add=1)
9550
9551         # in2out
9552         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
9553              IPv6(src=self.pg0.remote_ip6, dst=self.pg1.remote_ip6) /
9554              UDP())
9555         self.pg0.add_stream([p])
9556         self.pg_enable_capture(self.pg_interfaces)
9557         self.pg_start()
9558         capture = self.pg1.get_capture(1)
9559         packet = capture[0]
9560         try:
9561             self.assertEqual(packet[IPv6].src, self.pg0.remote_ip6)
9562             self.assertEqual(packet[IPv6].dst, self.pg1.remote_ip6)
9563         except:
9564             self.logger.error(ppp("Unexpected or invalid packet:", packet))
9565             raise
9566
9567     def clear_nat66(self):
9568         """
9569         Clear NAT66 configuration.
9570         """
9571         interfaces = self.vapi.nat66_interface_dump()
9572         for intf in interfaces:
9573             self.vapi.nat66_add_del_interface(is_add=0, flags=intf.flags,
9574                                               sw_if_index=intf.sw_if_index)
9575
9576         static_mappings = self.vapi.nat66_static_mapping_dump()
9577         for sm in static_mappings:
9578             self.vapi.nat66_add_del_static_mapping(
9579                 local_ip_address=sm.local_ip_address,
9580                 external_ip_address=sm.external_ip_address, vrf_id=sm.vrf_id,
9581                 is_add=0)
9582
9583     def tearDown(self):
9584         super(TestNAT66, self).tearDown()
9585         self.clear_nat66()
9586
9587     def show_commands_at_teardown(self):
9588         self.logger.info(self.vapi.cli("show nat66 interfaces"))
9589         self.logger.info(self.vapi.cli("show nat66 static mappings"))
9590
9591
9592 if __name__ == '__main__':
9593     unittest.main(testRunner=VppTestRunner)