test_nat.py revision ead1e536
1#!/usr/bin/env python3
2
3import socket
4import unittest
5import struct
6import random
7
8from framework import VppTestCase, VppTestRunner, running_extended_tests
9
10import scapy.compat
11from scapy.layers.inet import IP, TCP, UDP, ICMP
12from scapy.layers.inet import IPerror, TCPerror, UDPerror, ICMPerror
13from scapy.layers.inet6 import IPv6, ICMPv6EchoRequest, ICMPv6EchoReply, \
14    ICMPv6ND_NS, ICMPv6ND_NA, ICMPv6NDOptDstLLAddr, fragment6
15from scapy.layers.inet6 import ICMPv6DestUnreach, IPerror6, IPv6ExtHdrFragment
16from scapy.layers.l2 import Ether, ARP, GRE
17from scapy.data import IP_PROTOS
18from scapy.packet import bind_layers, Raw
19from util import ppp
20from ipfix import IPFIX, Set, Template, Data, IPFIXDecoder
21from time import sleep
22from util import ip4_range
23from vpp_papi import mac_pton
24from syslog_rfc5424_parser import SyslogMessage, ParseError
25from syslog_rfc5424_parser.constants import SyslogFacility, SyslogSeverity
26from io import BytesIO
27from vpp_papi import VppEnum
28from vpp_ip_route import VppIpRoute, VppRoutePath, FibPathType
29from vpp_neighbor import VppNeighbor
30from vpp_ip import VppIpAddress, VppIpPrefix
31from scapy.all import bind_layers, Packet, ByteEnumField, ShortField, \
32    IPField, IntField, LongField, XByteField, FlagsField, FieldLenField, \
33    PacketListField
34from ipaddress import IPv6Network
35
36
37# NAT HA protocol event data
38class Event(Packet):
39    name = "Event"
40    fields_desc = [ByteEnumField("event_type", None,
41                                 {1: "add", 2: "del", 3: "refresh"}),
42                   ByteEnumField("protocol", None,
43                                 {0: "udp", 1: "tcp", 2: "icmp"}),
44                   ShortField("flags", 0),
45                   IPField("in_addr", None),
46                   IPField("out_addr", None),
47                   ShortField("in_port", None),
48                   ShortField("out_port", None),
49                   IPField("eh_addr", None),
50                   IPField("ehn_addr", None),
51                   ShortField("eh_port", None),
52                   ShortField("ehn_port", None),
53                   IntField("fib_index", None),
54                   IntField("total_pkts", 0),
55                   LongField("total_bytes", 0)]
56
57    def extract_padding(self, s):
58        return "", s
59
60
61# NAT HA protocol header
62class HANATStateSync(Packet):
63    name = "HA NAT state sync"
64    fields_desc = [XByteField("version", 1),
65                   FlagsField("flags", 0, 8, ['ACK']),
66                   FieldLenField("count", None, count_of="events"),
67                   IntField("sequence_number", 1),
68                   IntField("thread_index", 0),
69                   PacketListField("events", [], Event,
70                                   count_from=lambda pkt: pkt.count)]
71
72
73class MethodHolder(VppTestCase):
74    """ NAT create capture and verify method holder """
75
76    @property
77    def config_flags(self):
78        return VppEnum.vl_api_nat_config_flags_t
79
80    @property
81    def SYSLOG_SEVERITY(self):
82        return VppEnum.vl_api_syslog_severity_t
83
84    def clear_nat44(self):
85        """
86        Clear NAT44 configuration.
87        """
88        if hasattr(self, 'pg7') and hasattr(self, 'pg8'):
89            if self.pg7.has_ip4_config:
90                self.pg7.unconfig_ip4()
91
92        self.vapi.nat44_forwarding_enable_disable(enable=0)
93
94        interfaces = self.vapi.nat44_interface_addr_dump()
95        for intf in interfaces:
96            self.vapi.nat44_add_del_interface_addr(
97                is_add=0,
98                sw_if_index=intf.sw_if_index,
99                flags=intf.flags)
100
101        self.vapi.nat_ipfix_enable_disable(domain_id=self.ipfix_domain_id,
102                                           src_port=self.ipfix_src_port,
103                                           enable=0)
104        self.ipfix_src_port = 4739
105        self.ipfix_domain_id = 1
106
107        self.vapi.syslog_set_filter(
108            self.SYSLOG_SEVERITY.SYSLOG_API_SEVERITY_EMERG)
109
110        self.vapi.nat_ha_set_listener(ip_address='0.0.0.0', port=0,
111                                      path_mtu=512)
112        self.vapi.nat_ha_set_failover(ip_address='0.0.0.0', port=0,
113                                      session_refresh_interval=10)
114
115        interfaces = self.vapi.nat44_interface_dump()
116        for intf in interfaces:
117            if intf.flags & self.config_flags.NAT_IS_INSIDE and \
118                    intf.flags & self.config_flags.NAT_IS_OUTSIDE:
119                self.vapi.nat44_interface_add_del_feature(
120                    sw_if_index=intf.sw_if_index)
121            self.vapi.nat44_interface_add_del_feature(
122                sw_if_index=intf.sw_if_index,
123                flags=intf.flags)
124
125        interfaces = self.vapi.nat44_interface_output_feature_dump()
126        for intf in interfaces:
127            self.vapi.nat44_interface_add_del_output_feature(
128                is_add=0,
129                flags=intf.flags,
130                sw_if_index=intf.sw_if_index)
131        static_mappings = self.vapi.nat44_static_mapping_dump()
132        for sm in static_mappings:
133            self.vapi.nat44_add_del_static_mapping(
134                is_add=0,
135                local_ip_address=sm.local_ip_address,
136                external_ip_address=sm.external_ip_address,
137                external_sw_if_index=sm.external_sw_if_index,
138                local_port=sm.local_port,
139                external_port=sm.external_port,
140                vrf_id=sm.vrf_id,
141                protocol=sm.protocol,
142                flags=sm.flags, tag=sm.tag)
143
144        lb_static_mappings = self.vapi.nat44_lb_static_mapping_dump()
145        for lb_sm in lb_static_mappings:
146            self.vapi.nat44_add_del_lb_static_mapping(
147                is_add=0,
148                flags=lb_sm.flags,
149                external_addr=lb_sm.external_addr,
150                external_port=lb_sm.external_port,
151                protocol=lb_sm.protocol,
152                local_num=0, locals=[],
153                tag=lb_sm.tag)
154
155        identity_mappings = self.vapi.nat44_identity_mapping_dump()
156        for id_m in identity_mappings:
157            self.vapi.nat44_add_del_identity_mapping(
158                ip_address=id_m.ip_address,
159                sw_if_index=id_m.sw_if_index,
160                port=id_m.port,
161                flags=id_m.flags,
162                vrf_id=id_m.vrf_id,
163                protocol=id_m.protocol)
164
165        addresses = self.vapi.nat44_address_dump()
166        for addr in addresses:
167            self.vapi.nat44_add_del_address_range(
168                first_ip_address=addr.ip_address,
169                last_ip_address=addr.ip_address,
170                vrf_id=0xFFFFFFFF, flags=addr.flags)
171
172        self.vapi.nat_set_reass(timeout=2, max_reass=1024, max_frag=5,
173                                drop_frag=0)
174        self.vapi.nat_set_reass(timeout=2, max_reass=1024, max_frag=5,
175                                drop_frag=0, is_ip6=1)
176        self.verify_no_nat44_user()
177        self.vapi.nat_set_timeouts(udp=300, tcp_established=7440,
178                                   tcp_transitory=240, icmp=60)
179        self.vapi.nat_set_addr_and_port_alloc_alg()
180        self.vapi.nat_set_mss_clamping(enable=0, mss_value=1500)
181
182    def nat44_add_static_mapping(self, local_ip, external_ip='0.0.0.0',
183                                 local_port=0, external_port=0, vrf_id=0,
184                                 is_add=1, external_sw_if_index=0xFFFFFFFF,
185                                 proto=0, tag="", flags=0):
186        """
187        Add/delete NAT44 static mapping
188
189        :param local_ip: Local IP address
190        :param external_ip: External IP address
191        :param local_port: Local port number (Optional)
192        :param external_port: External port number (Optional)
193        :param vrf_id: VRF ID (Default 0)
194        :param is_add: 1 if add, 0 if delete (Default add)
195        :param external_sw_if_index: External interface instead of IP address
196        :param proto: IP protocol (Mandatory if port specified)
197        :param tag: Opaque string tag
198        :param flags: NAT configuration flags
199        """
200
201        if not (local_port and external_port):
202            flags |= self.config_flags.NAT_IS_ADDR_ONLY
203
204        self.vapi.nat44_add_del_static_mapping(
205            is_add=is_add,
206            local_ip_address=local_ip,
207            external_ip_address=external_ip,
208            external_sw_if_index=external_sw_if_index,
209            local_port=local_port,
210            external_port=external_port,
211            vrf_id=vrf_id, protocol=proto,
212            flags=flags,
213            tag=tag)
214
215    def nat44_add_address(self, ip, is_add=1, vrf_id=0xFFFFFFFF, twice_nat=0):
216        """
217        Add/delete NAT44 address
218
219        :param ip: IP address
220        :param is_add: 1 if add, 0 if delete (Default add)
221        :param twice_nat: twice NAT address for external hosts
222        """
223        flags = self.config_flags.NAT_IS_TWICE_NAT if twice_nat else 0
224        self.vapi.nat44_add_del_address_range(first_ip_address=ip,
225                                              last_ip_address=ip,
226                                              vrf_id=vrf_id,
227                                              is_add=is_add,
228                                              flags=flags)
229
230    def create_stream_in(self, in_if, out_if, dst_ip=None, ttl=64):
231        """
232        Create packet stream for inside network
233
234        :param in_if: Inside interface
235        :param out_if: Outside interface
236        :param dst_ip: Destination address
237        :param ttl: TTL of generated packets
238        """
239        if dst_ip is None:
240            dst_ip = out_if.remote_ip4
241
242        pkts = []
243        # TCP
244        p = (Ether(dst=in_if.local_mac, src=in_if.remote_mac) /
245             IP(src=in_if.remote_ip4, dst=dst_ip, ttl=ttl) /
246             TCP(sport=self.tcp_port_in, dport=20))
247        pkts.extend([p, p])
248
249        # UDP
250        p = (Ether(dst=in_if.local_mac, src=in_if.remote_mac) /
251             IP(src=in_if.remote_ip4, dst=dst_ip, ttl=ttl) /
252             UDP(sport=self.udp_port_in, dport=20))
253        pkts.append(p)
254
255        # ICMP
256        p = (Ether(dst=in_if.local_mac, src=in_if.remote_mac) /
257             IP(src=in_if.remote_ip4, dst=dst_ip, ttl=ttl) /
258             ICMP(id=self.icmp_id_in, type='echo-request'))
259        pkts.append(p)
260
261        return pkts
262
263    def compose_ip6(self, ip4, pref, plen):
264        """
265        Compose IPv4-embedded IPv6 addresses
266
267        :param ip4: IPv4 address
268        :param pref: IPv6 prefix
269        :param plen: IPv6 prefix length
270        :returns: IPv4-embedded IPv6 addresses
271        """
272        pref_n = list(socket.inet_pton(socket.AF_INET6, pref))
273        ip4_n = list(socket.inet_pton(socket.AF_INET, ip4))
274        if plen == 32:
275            pref_n[4] = ip4_n[0]
276            pref_n[5] = ip4_n[1]
277            pref_n[6] = ip4_n[2]
278            pref_n[7] = ip4_n[3]
279        elif plen == 40:
280            pref_n[5] = ip4_n[0]
281            pref_n[6] = ip4_n[1]
282            pref_n[7] = ip4_n[2]
283            pref_n[9] = ip4_n[3]
284        elif plen == 48:
285            pref_n[6] = ip4_n[0]
286            pref_n[7] = ip4_n[1]
287            pref_n[9] = ip4_n[2]
288            pref_n[10] = ip4_n[3]
289        elif plen == 56:
290            pref_n[7] = ip4_n[0]
291            pref_n[9] = ip4_n[1]
292            pref_n[10] = ip4_n[2]
293            pref_n[11] = ip4_n[3]
294        elif plen == 64:
295            pref_n[9] = ip4_n[0]
296            pref_n[10] = ip4_n[1]
297            pref_n[11] = ip4_n[2]
298            pref_n[12] = ip4_n[3]
299        elif plen == 96:
300            pref_n[12] = ip4_n[0]
301            pref_n[13] = ip4_n[1]
302            pref_n[14] = ip4_n[2]
303            pref_n[15] = ip4_n[3]
304        packed_pref_n = b''.join([scapy.compat.chb(x) for x in pref_n])
305        return socket.inet_ntop(socket.AF_INET6, packed_pref_n)
306
307    def extract_ip4(self, ip6, plen):
308        """
309        Extract IPv4 address embedded in IPv6 addresses
310
311        :param ip6: IPv6 address
312        :param plen: IPv6 prefix length
313        :returns: extracted IPv4 address
314        """
315        ip6_n = list(socket.inet_pton(socket.AF_INET6, ip6))
316        ip4_n = [None] * 4
317        if plen == 32:
318            ip4_n[0] = ip6_n[4]
319            ip4_n[1] = ip6_n[5]
320            ip4_n[2] = ip6_n[6]
321            ip4_n[3] = ip6_n[7]
322        elif plen == 40:
323            ip4_n[0] = ip6_n[5]
324            ip4_n[1] = ip6_n[6]
325            ip4_n[2] = ip6_n[7]
326            ip4_n[3] = ip6_n[9]
327        elif plen == 48:
328            ip4_n[0] = ip6_n[6]
329            ip4_n[1] = ip6_n[7]
330            ip4_n[2] = ip6_n[9]
331            ip4_n[3] = ip6_n[10]
332        elif plen == 56:
333            ip4_n[0] = ip6_n[7]
334            ip4_n[1] = ip6_n[9]
335            ip4_n[2] = ip6_n[10]
336            ip4_n[3] = ip6_n[11]
337        elif plen == 64:
338            ip4_n[0] = ip6_n[9]
339            ip4_n[1] = ip6_n[10]
340            ip4_n[2] = ip6_n[11]
341            ip4_n[3] = ip6_n[12]
342        elif plen == 96:
343            ip4_n[0] = ip6_n[12]
344            ip4_n[1] = ip6_n[13]
345            ip4_n[2] = ip6_n[14]
346            ip4_n[3] = ip6_n[15]
347        return socket.inet_ntop(socket.AF_INET, ''.join(ip4_n))
348
349    def create_stream_in_ip6(self, in_if, out_if, hlim=64, pref=None, plen=0):
350        """
351        Create IPv6 packet stream for inside network
352
353        :param in_if: Inside interface
354        :param out_if: Outside interface
355        :param ttl: Hop Limit of generated packets
356        :param pref: NAT64 prefix
357        :param plen: NAT64 prefix length
358        """
359        pkts = []
360        if pref is None:
361            dst = ''.join(['64:ff9b::', out_if.remote_ip4])
362        else:
363            dst = self.compose_ip6(out_if.remote_ip4, pref, plen)
364
365        # TCP
366        p = (Ether(dst=in_if.local_mac, src=in_if.remote_mac) /
367             IPv6(src=in_if.remote_ip6, dst=dst, hlim=hlim) /
368             TCP(sport=self.tcp_port_in, dport=20))
369        pkts.append(p)
370
371        # UDP
372        p = (Ether(dst=in_if.local_mac, src=in_if.remote_mac) /
373             IPv6(src=in_if.remote_ip6, dst=dst, hlim=hlim) /
374             UDP(sport=self.udp_port_in, dport=20))
375        pkts.append(p)
376
377        # ICMP
378        p = (Ether(dst=in_if.local_mac, src=in_if.remote_mac) /
379             IPv6(src=in_if.remote_ip6, dst=dst, hlim=hlim) /
380             ICMPv6EchoRequest(id=self.icmp_id_in))
381        pkts.append(p)
382
383        return pkts
384
385    def create_stream_out(self, out_if, dst_ip=None, ttl=64,
386                          use_inside_ports=False):
387        """
388        Create packet stream for outside network
389
390        :param out_if: Outside interface
391        :param dst_ip: Destination IP address (Default use global NAT address)
392        :param ttl: TTL of generated packets
393        :param use_inside_ports: Use inside NAT ports as destination ports
394               instead of outside ports
395        """
396        if dst_ip is None:
397            dst_ip = self.nat_addr
398        if not use_inside_ports:
399            tcp_port = self.tcp_port_out
400            udp_port = self.udp_port_out
401            icmp_id = self.icmp_id_out
402        else:
403            tcp_port = self.tcp_port_in
404            udp_port = self.udp_port_in
405            icmp_id = self.icmp_id_in
406        pkts = []
407        # TCP
408        p = (Ether(dst=out_if.local_mac, src=out_if.remote_mac) /
409             IP(src=out_if.remote_ip4, dst=dst_ip, ttl=ttl) /
410             TCP(dport=tcp_port, sport=20))
411        pkts.extend([p, p])
412
413        # UDP
414        p = (Ether(dst=out_if.local_mac, src=out_if.remote_mac) /
415             IP(src=out_if.remote_ip4, dst=dst_ip, ttl=ttl) /
416             UDP(dport=udp_port, sport=20))
417        pkts.append(p)
418
419        # ICMP
420        p = (Ether(dst=out_if.local_mac, src=out_if.remote_mac) /
421             IP(src=out_if.remote_ip4, dst=dst_ip, ttl=ttl) /
422             ICMP(id=icmp_id, type='echo-reply'))
423        pkts.append(p)
424
425        return pkts
426
427    def create_stream_out_ip6(self, out_if, src_ip, dst_ip, hl=64):
428        """
429        Create packet stream for outside network
430
431        :param out_if: Outside interface
432        :param dst_ip: Destination IP address (Default use global NAT address)
433        :param hl: HL of generated packets
434        """
435        pkts = []
436        # TCP
437        p = (Ether(dst=out_if.local_mac, src=out_if.remote_mac) /
438             IPv6(src=src_ip, dst=dst_ip, hlim=hl) /
439             TCP(dport=self.tcp_port_out, sport=20))
440        pkts.append(p)
441
442        # UDP
443        p = (Ether(dst=out_if.local_mac, src=out_if.remote_mac) /
444             IPv6(src=src_ip, dst=dst_ip, hlim=hl) /
445             UDP(dport=self.udp_port_out, sport=20))
446        pkts.append(p)
447
448        # ICMP
449        p = (Ether(dst=out_if.local_mac, src=out_if.remote_mac) /
450             IPv6(src=src_ip, dst=dst_ip, hlim=hl) /
451             ICMPv6EchoReply(id=self.icmp_id_out))
452        pkts.append(p)
453
454        return pkts
455
456    def verify_capture_out(self, capture, nat_ip=None, same_port=False,
457                           dst_ip=None, is_ip6=False):
458        """
459        Verify captured packets on outside network
460
461        :param capture: Captured packets
462        :param nat_ip: Translated IP address (Default use global NAT address)
463        :param same_port: Source port number is not translated (Default False)
464        :param dst_ip: Destination IP address (Default do not verify)
465        :param is_ip6: If L3 protocol is IPv6 (Default False)
466        """
467        if is_ip6:
468            IP46 = IPv6
469            ICMP46 = ICMPv6EchoRequest
470        else:
471            IP46 = IP
472            ICMP46 = ICMP
473        if nat_ip is None:
474            nat_ip = self.nat_addr
475        for packet in capture:
476            try:
477                if not is_ip6:
478                    self.assert_packet_checksums_valid(packet)
479                self.assertEqual(packet[IP46].src, nat_ip)
480                if dst_ip is not None:
481                    self.assertEqual(packet[IP46].dst, dst_ip)
482                if packet.haslayer(TCP):
483                    if same_port:
484                        self.assertEqual(packet[TCP].sport, self.tcp_port_in)
485                    else:
486                        self.assertNotEqual(
487                            packet[TCP].sport, self.tcp_port_in)
488                    self.tcp_port_out = packet[TCP].sport
489                    self.assert_packet_checksums_valid(packet)
490                elif packet.haslayer(UDP):
491                    if same_port:
492                        self.assertEqual(packet[UDP].sport, self.udp_port_in)
493                    else:
494                        self.assertNotEqual(
495                            packet[UDP].sport, self.udp_port_in)
496                    self.udp_port_out = packet[UDP].sport
497                else:
498                    if same_port:
499                        self.assertEqual(packet[ICMP46].id, self.icmp_id_in)
500                    else:
501                        self.assertNotEqual(packet[ICMP46].id, self.icmp_id_in)
502                    self.icmp_id_out = packet[ICMP46].id
503                    self.assert_packet_checksums_valid(packet)
504            except:
505                self.logger.error(ppp("Unexpected or invalid packet "
506                                      "(outside network):", packet))
507                raise
508
509    def verify_capture_out_ip6(self, capture, nat_ip, same_port=False,
510                               dst_ip=None):
511        """
512        Verify captured packets on outside network
513
514        :param capture: Captured packets
515        :param nat_ip: Translated IP address
516        :param same_port: Source port number is not translated (Default False)
517        :param dst_ip: Destination IP address (Default do not verify)
518        """
519        return self.verify_capture_out(capture, nat_ip, same_port, dst_ip,
520                                       True)
521
522    def verify_capture_in(self, capture, in_if):
523        """
524        Verify captured packets on inside network
525
526        :param capture: Captured packets
527        :param in_if: Inside interface
528        """
529        for packet in capture:
530            try:
531                self.assert_packet_checksums_valid(packet)
532                self.assertEqual(packet[IP].dst, in_if.remote_ip4)
533                if packet.haslayer(TCP):
534                    self.assertEqual(packet[TCP].dport, self.tcp_port_in)
535                elif packet.haslayer(UDP):
536                    self.assertEqual(packet[UDP].dport, self.udp_port_in)
537                else:
538                    self.assertEqual(packet[ICMP].id, self.icmp_id_in)
539            except:
540                self.logger.error(ppp("Unexpected or invalid packet "
541                                      "(inside network):", packet))
542                raise
543
544    def verify_capture_in_ip6(self, capture, src_ip, dst_ip):
545        """
546        Verify captured IPv6 packets on inside network
547
548        :param capture: Captured packets
549        :param src_ip: Source IP
550        :param dst_ip: Destination IP address
551        """
552        for packet in capture:
553            try:
554                self.assertEqual(packet[IPv6].src, src_ip)
555                self.assertEqual(packet[IPv6].dst, dst_ip)
556                self.assert_packet_checksums_valid(packet)
557                if packet.haslayer(TCP):
558                    self.assertEqual(packet[TCP].dport, self.tcp_port_in)
559                elif packet.haslayer(UDP):
560                    self.assertEqual(packet[UDP].dport, self.udp_port_in)
561                else:
562                    self.assertEqual(packet[ICMPv6EchoReply].id,
563                                     self.icmp_id_in)
564            except:
565                self.logger.error(ppp("Unexpected or invalid packet "
566                                      "(inside network):", packet))
567                raise
568
569    def verify_capture_no_translation(self, capture, ingress_if, egress_if):
570        """
571        Verify captured packet that don't have to be translated
572
573        :param capture: Captured packets
574        :param ingress_if: Ingress interface
575        :param egress_if: Egress interface
576        """
577        for packet in capture:
578            try:
579                self.assertEqual(packet[IP].src, ingress_if.remote_ip4)
580                self.assertEqual(packet[IP].dst, egress_if.remote_ip4)
581                if packet.haslayer(TCP):
582                    self.assertEqual(packet[TCP].sport, self.tcp_port_in)
583                elif packet.haslayer(UDP):
584                    self.assertEqual(packet[UDP].sport, self.udp_port_in)
585                else:
586                    self.assertEqual(packet[ICMP].id, self.icmp_id_in)
587            except:
588                self.logger.error(ppp("Unexpected or invalid packet "
589                                      "(inside network):", packet))
590                raise
591
592    def verify_capture_out_with_icmp_errors(self, capture, src_ip=None,
593                                            icmp_type=11):
594        """
595        Verify captured packets with ICMP errors on outside network
596
597        :param capture: Captured packets
598        :param src_ip: Translated IP address or IP address of VPP
599                       (Default use global NAT address)
600        :param icmp_type: Type of error ICMP packet
601                          we are expecting (Default 11)
602        """
603        if src_ip is None:
604            src_ip = self.nat_addr
605        for packet in capture:
606            try:
607                self.assertEqual(packet[IP].src, src_ip)
608                self.assertEqual(packet.haslayer(ICMP), 1)
609                icmp = packet[ICMP]
610                self.assertEqual(icmp.type, icmp_type)
611                self.assertTrue(icmp.haslayer(IPerror))
612                inner_ip = icmp[IPerror]
613                if inner_ip.haslayer(TCPerror):
614                    self.assertEqual(inner_ip[TCPerror].dport,
615                                     self.tcp_port_out)
616                elif inner_ip.haslayer(UDPerror):
617                    self.assertEqual(inner_ip[UDPerror].dport,
618                                     self.udp_port_out)
619                else:
620                    self.assertEqual(inner_ip[ICMPerror].id, self.icmp_id_out)
621            except:
622                self.logger.error(ppp("Unexpected or invalid packet "
623                                      "(outside network):", packet))
624                raise
625
626    def verify_capture_in_with_icmp_errors(self, capture, in_if, icmp_type=11):
627        """
628        Verify captured packets with ICMP errors on inside network
629
630        :param capture: Captured packets
631        :param in_if: Inside interface
632        :param icmp_type: Type of error ICMP packet
633                          we are expecting (Default 11)
634        """
635        for packet in capture:
636            try:
637                self.assertEqual(packet[IP].dst, in_if.remote_ip4)
638                self.assertEqual(packet.haslayer(ICMP), 1)
639                icmp = packet[ICMP]
640                self.assertEqual(icmp.type, icmp_type)
641                self.assertTrue(icmp.haslayer(IPerror))
642                inner_ip = icmp[IPerror]
643                if inner_ip.haslayer(TCPerror):
644                    self.assertEqual(inner_ip[TCPerror].sport,
645                                     self.tcp_port_in)
646                elif inner_ip.haslayer(UDPerror):
647                    self.assertEqual(inner_ip[UDPerror].sport,
648                                     self.udp_port_in)
649                else:
650                    self.assertEqual(inner_ip[ICMPerror].id, self.icmp_id_in)
651            except:
652                self.logger.error(ppp("Unexpected or invalid packet "
653                                      "(inside network):", packet))
654                raise
655
656    def create_stream_frag(self, src_if, dst, sport, dport, data,
657                           proto=IP_PROTOS.tcp, echo_reply=False):
658        """
659        Create fragmented packet stream
660
661        :param src_if: Source interface
662        :param dst: Destination IPv4 address
663        :param sport: Source port
664        :param dport: Destination port
665        :param data: Payload data
666        :param proto: protocol (TCP, UDP, ICMP)
667        :param echo_reply: use echo_reply if protocol is ICMP
668        :returns: Fragments
669        """
670        if proto == IP_PROTOS.tcp:
671            p = (IP(src=src_if.remote_ip4, dst=dst) /
672                 TCP(sport=sport, dport=dport) /
673                 Raw(data))
674            p = p.__class__(scapy.compat.raw(p))
675            chksum = p[TCP].chksum
676            proto_header = TCP(sport=sport, dport=dport, chksum=chksum)
677        elif proto == IP_PROTOS.udp:
678            proto_header = UDP(sport=sport, dport=dport)
679        elif proto == IP_PROTOS.icmp:
680            if not echo_reply:
681                proto_header = ICMP(id=sport, type='echo-request')
682            else:
683                proto_header = ICMP(id=sport, type='echo-reply')
684        else:
685            raise Exception("Unsupported protocol")
686        id = random.randint(0, 65535)
687        pkts = []
688        if proto == IP_PROTOS.tcp:
689            raw = Raw(data[0:4])
690        else:
691            raw = Raw(data[0:16])
692        p = (Ether(src=src_if.remote_mac, dst=src_if.local_mac) /
693             IP(src=src_if.remote_ip4, dst=dst, flags="MF", frag=0, id=id) /
694             proto_header /
695             raw)
696        pkts.append(p)
697        if proto == IP_PROTOS.tcp:
698            raw = Raw(data[4:20])
699        else:
700            raw = Raw(data[16:32])
701        p = (Ether(src=src_if.remote_mac, dst=src_if.local_mac) /
702             IP(src=src_if.remote_ip4, dst=dst, flags="MF", frag=3, id=id,
703                proto=proto) /
704             raw)
705        pkts.append(p)
706        if proto == IP_PROTOS.tcp:
707            raw = Raw(data[20:])
708        else:
709            raw = Raw(data[32:])
710        p = (Ether(src=src_if.remote_mac, dst=src_if.local_mac) /
711             IP(src=src_if.remote_ip4, dst=dst, frag=5, proto=proto,
712                id=id) /
713             raw)
714        pkts.append(p)
715        return pkts
716
717    def create_stream_frag_ip6(self, src_if, dst, sport, dport, data,
718                               pref=None, plen=0, frag_size=128):
719        """
720        Create fragmented packet stream
721
722        :param src_if: Source interface
723        :param dst: Destination IPv4 address
724        :param sport: Source TCP port
725        :param dport: Destination TCP port
726        :param data: Payload data
727        :param pref: NAT64 prefix
728        :param plen: NAT64 prefix length
729        :param fragsize: size of fragments
730        :returns: Fragments
731        """
732        if pref is None:
733            dst_ip6 = ''.join(['64:ff9b::', dst])
734        else:
735            dst_ip6 = self.compose_ip6(dst, pref, plen)
736
737        p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
738             IPv6(src=src_if.remote_ip6, dst=dst_ip6) /
739             IPv6ExtHdrFragment(id=random.randint(0, 65535)) /
740             TCP(sport=sport, dport=dport) /
741             Raw(data))
742
743        return fragment6(p, frag_size)
744
745    def reass_frags_and_verify(self, frags, src, dst):
746        """
747        Reassemble and verify fragmented packet
748
749        :param frags: Captured fragments
750        :param src: Source IPv4 address to verify
751        :param dst: Destination IPv4 address to verify
752
753        :returns: Reassembled IPv4 packet
754        """
755        buffer = BytesIO()
756        for p in frags:
757            self.assertEqual(p[IP].src, src)
758            self.assertEqual(p[IP].dst, dst)
759            self.assert_ip_checksum_valid(p)
760            buffer.seek(p[IP].frag * 8)
761            buffer.write(bytes(p[IP].payload))
762        ip = IP(src=frags[0][IP].src, dst=frags[0][IP].dst,
763                proto=frags[0][IP].proto)
764        if ip.proto == IP_PROTOS.tcp:
765            p = (ip / TCP(buffer.getvalue()))
766            self.assert_tcp_checksum_valid(p)
767        elif ip.proto == IP_PROTOS.udp:
768            p = (ip / UDP(buffer.getvalue()[:8]) /
769                 Raw(buffer.getvalue()[8:]))
770        elif ip.proto == IP_PROTOS.icmp:
771            p = (ip / ICMP(buffer.getvalue()))
772        return p
773
774    def reass_frags_and_verify_ip6(self, frags, src, dst):
775        """
776        Reassemble and verify fragmented packet
777
778        :param frags: Captured fragments
779        :param src: Source IPv6 address to verify
780        :param dst: Destination IPv6 address to verify
781
782        :returns: Reassembled IPv6 packet
783        """
784        buffer = BytesIO()
785        for p in frags:
786            self.assertEqual(p[IPv6].src, src)
787            self.assertEqual(p[IPv6].dst, dst)
788            buffer.seek(p[IPv6ExtHdrFragment].offset * 8)
789            buffer.write(bytes(p[IPv6ExtHdrFragment].payload))
790        ip = IPv6(src=frags[0][IPv6].src, dst=frags[0][IPv6].dst,
791                  nh=frags[0][IPv6ExtHdrFragment].nh)
792        if ip.nh == IP_PROTOS.tcp:
793            p = (ip / TCP(buffer.getvalue()))
794        elif ip.nh == IP_PROTOS.udp:
795            p = (ip / UDP(buffer.getvalue()))
796        self.assert_packet_checksums_valid(p)
797        return p
798
799    def initiate_tcp_session(self, in_if, out_if):
800        """
801        Initiates TCP session
802
803        :param in_if: Inside interface
804        :param out_if: Outside interface
805        """
806        try:
807            # SYN packet in->out
808            p = (Ether(src=in_if.remote_mac, dst=in_if.local_mac) /
809                 IP(src=in_if.remote_ip4, dst=out_if.remote_ip4) /
810                 TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
811                     flags="S"))
812            in_if.add_stream(p)
813            self.pg_enable_capture(self.pg_interfaces)
814            self.pg_start()
815            capture = out_if.get_capture(1)
816            p = capture[0]
817            self.tcp_port_out = p[TCP].sport
818
819            # SYN + ACK packet out->in
820            p = (Ether(src=out_if.remote_mac, dst=out_if.local_mac) /
821                 IP(src=out_if.remote_ip4, dst=self.nat_addr) /
822                 TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
823                     flags="SA"))
824            out_if.add_stream(p)
825            self.pg_enable_capture(self.pg_interfaces)
826            self.pg_start()
827            in_if.get_capture(1)
828
829            # ACK packet in->out
830            p = (Ether(src=in_if.remote_mac, dst=in_if.local_mac) /
831                 IP(src=in_if.remote_ip4, dst=out_if.remote_ip4) /
832                 TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
833                     flags="A"))
834            in_if.add_stream(p)
835            self.pg_enable_capture(self.pg_interfaces)
836            self.pg_start()
837            out_if.get_capture(1)
838
839        except:
840            self.logger.error("TCP 3 way handshake failed")
841            raise
842
843    def verify_ipfix_nat44_ses(self, data):
844        """
845        Verify IPFIX NAT44 session create/delete event
846
847        :param data: Decoded IPFIX data records
848        """
849        nat44_ses_create_num = 0
850        nat44_ses_delete_num = 0
851        self.assertEqual(6, len(data))
852        for record in data:
853            # natEvent
854            self.assertIn(scapy.compat.orb(record[230]), [4, 5])
855            if scapy.compat.orb(record[230]) == 4:
856                nat44_ses_create_num += 1
857            else:
858                nat44_ses_delete_num += 1
859            # sourceIPv4Address
860            self.assertEqual(self.pg0.remote_ip4n, record[8])
861            # postNATSourceIPv4Address
862            self.assertEqual(socket.inet_pton(socket.AF_INET, self.nat_addr),
863                             record[225])
864            # ingressVRFID
865            self.assertEqual(struct.pack("!I", 0), record[234])
866            # protocolIdentifier/sourceTransportPort
867            # /postNAPTSourceTransportPort
868            if IP_PROTOS.icmp == scapy.compat.orb(record[4]):
869                self.assertEqual(struct.pack("!H", self.icmp_id_in), record[7])
870                self.assertEqual(struct.pack("!H", self.icmp_id_out),
871                                 record[227])
872            elif IP_PROTOS.tcp == scapy.compat.orb(record[4]):
873                self.assertEqual(struct.pack("!H", self.tcp_port_in),
874                                 record[7])
875                self.assertEqual(struct.pack("!H", self.tcp_port_out),
876                                 record[227])
877            elif IP_PROTOS.udp == scapy.compat.orb(record[4]):
878                self.assertEqual(struct.pack("!H", self.udp_port_in),
879                                 record[7])
880                self.assertEqual(struct.pack("!H", self.udp_port_out),
881                                 record[227])
882            else:
883                self.fail("Invalid protocol")
884        self.assertEqual(3, nat44_ses_create_num)
885        self.assertEqual(3, nat44_ses_delete_num)
886
887    def verify_ipfix_addr_exhausted(self, data):
888        """
889        Verify IPFIX NAT addresses event
890
891        :param data: Decoded IPFIX data records
892        """
893        self.assertEqual(1, len(data))
894        record = data[0]
895        # natEvent
896        self.assertEqual(scapy.compat.orb(record[230]), 3)
897        # natPoolID
898        self.assertEqual(struct.pack("!I", 0), record[283])
899
900    def verify_ipfix_max_sessions(self, data, limit):
901        """
902        Verify IPFIX maximum session entries exceeded event
903
904        :param data: Decoded IPFIX data records
905        :param limit: Number of maximum session entries that can be created.
906        """
907        self.assertEqual(1, len(data))
908        record = data[0]
909        # natEvent
910        self.assertEqual(scapy.compat.orb(record[230]), 13)
911        # natQuotaExceededEvent
912        self.assertEqual(struct.pack("I", 1), record[466])
913        # maxSessionEntries
914        self.assertEqual(struct.pack("I", limit), record[471])
915
916    def verify_ipfix_max_bibs(self, data, limit):
917        """
918        Verify IPFIX maximum BIB entries exceeded event
919
920        :param data: Decoded IPFIX data records
921        :param limit: Number of maximum BIB 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", 2), record[466])
929        # maxBIBEntries
930        self.assertEqual(struct.pack("I", limit), record[472])
931
932    def verify_ipfix_max_fragments_ip6(self, data, limit, src_addr):
933        """
934        Verify IPFIX maximum IPv6 fragments pending reassembly exceeded event
935
936        :param data: Decoded IPFIX data records
937        :param limit: Number of maximum fragments pending reassembly
938        :param src_addr: IPv6 source address
939        """
940        self.assertEqual(1, len(data))
941        record = data[0]
942        # natEvent
943        self.assertEqual(scapy.compat.orb(record[230]), 13)
944        # natQuotaExceededEvent
945        self.assertEqual(struct.pack("I", 5), record[466])
946        # maxFragmentsPendingReassembly
947        self.assertEqual(struct.pack("I", limit), record[475])
948        # sourceIPv6Address
949        self.assertEqual(src_addr, record[27])
950
951    def verify_ipfix_max_fragments_ip4(self, data, limit, src_addr):
952        """
953        Verify IPFIX maximum IPv4 fragments pending reassembly exceeded event
954
955        :param data: Decoded IPFIX data records
956        :param limit: Number of maximum fragments pending reassembly
957        :param src_addr: IPv4 source address
958        """
959        self.assertEqual(1, len(data))
960        record = data[0]
961        # natEvent
962        self.assertEqual(scapy.compat.orb(record[230]), 13)
963        # natQuotaExceededEvent
964        self.assertEqual(struct.pack("I", 5), record[466])
965        # maxFragmentsPendingReassembly
966        self.assertEqual(struct.pack("I", limit), record[475])
967        # sourceIPv4Address
968        self.assertEqual(src_addr, record[8])
969
970    def verify_ipfix_bib(self, data, is_create, src_addr):
971        """
972        Verify IPFIX NAT64 BIB create and delete events
973
974        :param data: Decoded IPFIX data records
975        :param is_create: Create event if nonzero value otherwise delete event
976        :param src_addr: IPv6 source address
977        """
978        self.assertEqual(1, len(data))
979        record = data[0]
980        # natEvent
981        if is_create:
982            self.assertEqual(scapy.compat.orb(record[230]), 10)
983        else:
984            self.assertEqual(scapy.compat.orb(record[230]), 11)
985        # sourceIPv6Address
986        self.assertEqual(src_addr, record[27])
987        # postNATSourceIPv4Address
988        self.assertEqual(self.nat_addr_n, record[225])
989        # protocolIdentifier
990        self.assertEqual(IP_PROTOS.tcp, scapy.compat.orb(record[4]))
991        # ingressVRFID
992        self.assertEqual(struct.pack("!I", 0), record[234])
993        # sourceTransportPort
994        self.assertEqual(struct.pack("!H", self.tcp_port_in), record[7])
995        # postNAPTSourceTransportPort
996        self.assertEqual(struct.pack("!H", self.tcp_port_out), record[227])
997
998    def verify_ipfix_nat64_ses(self, data, is_create, src_addr, dst_addr,
999                               dst_port):
1000        """
1001        Verify IPFIX NAT64 session create and delete events
1002
1003        :param data: Decoded IPFIX data records
1004        :param is_create: Create event if nonzero value otherwise delete event
1005        :param src_addr: IPv6 source address
1006        :param dst_addr: IPv4 destination address
1007        :param dst_port: destination TCP port
1008        """
1009        self.assertEqual(1, len(data))
1010        record = data[0]
1011        # natEvent
1012        if is_create:
1013            self.assertEqual(scapy.compat.orb(record[230]), 6)
1014        else:
1015            self.assertEqual(scapy.compat.orb(record[230]), 7)
1016        # sourceIPv6Address
1017        self.assertEqual(src_addr, record[27])
1018        # destinationIPv6Address
1019        self.assertEqual(socket.inet_pton(socket.AF_INET6,
1020                                          self.compose_ip6(dst_addr,
1021                                                           '64:ff9b::',
1022                                                           96)),
1023                         record[28])
1024        # postNATSourceIPv4Address
1025        self.assertEqual(self.nat_addr_n, record[225])
1026        # postNATDestinationIPv4Address
1027        self.assertEqual(socket.inet_pton(socket.AF_INET, dst_addr),
1028                         record[226])
1029        # protocolIdentifier
1030        self.assertEqual(IP_PROTOS.tcp, scapy.compat.orb(record[4]))
1031        # ingressVRFID
1032        self.assertEqual(struct.pack("!I", 0), record[234])
1033        # sourceTransportPort
1034        self.assertEqual(struct.pack("!H", self.tcp_port_in), record[7])
1035        # postNAPTSourceTransportPort
1036        self.assertEqual(struct.pack("!H", self.tcp_port_out), record[227])
1037        # destinationTransportPort
1038        self.assertEqual(struct.pack("!H", dst_port), record[11])
1039        # postNAPTDestinationTransportPort
1040        self.assertEqual(struct.pack("!H", dst_port), record[228])
1041
1042    def verify_no_nat44_user(self):
1043        """ Verify that there is no NAT44 user """
1044        users = self.vapi.nat44_user_dump()
1045        self.assertEqual(len(users), 0)
1046        users = self.statistics.get_counter('/nat44/total-users')
1047        self.assertEqual(users[0][0], 0)
1048        sessions = self.statistics.get_counter('/nat44/total-sessions')
1049        self.assertEqual(sessions[0][0], 0)
1050
1051    def verify_ipfix_max_entries_per_user(self, data, limit, src_addr):
1052        """
1053        Verify IPFIX maximum entries per user exceeded event
1054
1055        :param data: Decoded IPFIX data records
1056        :param limit: Number of maximum entries per user
1057        :param src_addr: IPv4 source address
1058        """
1059        self.assertEqual(1, len(data))
1060        record = data[0]
1061        # natEvent
1062        self.assertEqual(scapy.compat.orb(record[230]), 13)
1063        # natQuotaExceededEvent
1064        self.assertEqual(struct.pack("I", 3), record[466])
1065        # maxEntriesPerUser
1066        self.assertEqual(struct.pack("I", limit), record[473])
1067        # sourceIPv4Address
1068        self.assertEqual(socket.inet_pton(socket.AF_INET, src_addr), record[8])
1069
1070    def verify_syslog_apmap(self, data, is_add=True):
1071        message = data.decode('utf-8')
1072        try:
1073            message = SyslogMessage.parse(message)
1074        except ParseError as e:
1075            self.logger.error(e)
1076            raise
1077        else:
1078            self.assertEqual(message.severity, SyslogSeverity.info)
1079            self.assertEqual(message.appname, 'NAT')
1080            self.assertEqual(message.msgid, 'APMADD' if is_add else 'APMDEL')
1081            sd_params = message.sd.get('napmap')
1082            self.assertTrue(sd_params is not None)
1083            self.assertEqual(sd_params.get('IATYP'), 'IPv4')
1084            self.assertEqual(sd_params.get('ISADDR'), self.pg0.remote_ip4)
1085            self.assertEqual(sd_params.get('ISPORT'), "%d" % self.tcp_port_in)
1086            self.assertEqual(sd_params.get('XATYP'), 'IPv4')
1087            self.assertEqual(sd_params.get('XSADDR'), self.nat_addr)
1088            self.assertEqual(sd_params.get('XSPORT'), "%d" % self.tcp_port_out)
1089            self.assertEqual(sd_params.get('PROTO'), "%d" % IP_PROTOS.tcp)
1090            self.assertTrue(sd_params.get('SSUBIX') is not None)
1091            self.assertEqual(sd_params.get('SVLAN'), '0')
1092
1093    def verify_syslog_sess(self, data, is_add=True, is_ip6=False):
1094        message = data.decode('utf-8')
1095        try:
1096            message = SyslogMessage.parse(message)
1097        except ParseError as e:
1098            self.logger.error(e)
1099            raise
1100        else:
1101            self.assertEqual(message.severity, SyslogSeverity.info)
1102            self.assertEqual(message.appname, 'NAT')
1103            self.assertEqual(message.msgid, 'SADD' if is_add else 'SDEL')
1104            sd_params = message.sd.get('nsess')
1105            self.assertTrue(sd_params is not None)
1106            if is_ip6:
1107                self.assertEqual(sd_params.get('IATYP'), 'IPv6')
1108                self.assertEqual(sd_params.get('ISADDR'), self.pg0.remote_ip6)
1109            else:
1110                self.assertEqual(sd_params.get('IATYP'), 'IPv4')
1111                self.assertEqual(sd_params.get('ISADDR'), self.pg0.remote_ip4)
1112                self.assertTrue(sd_params.get('SSUBIX') is not None)
1113            self.assertEqual(sd_params.get('ISPORT'), "%d" % self.tcp_port_in)
1114            self.assertEqual(sd_params.get('XATYP'), 'IPv4')
1115            self.assertEqual(sd_params.get('XSADDR'), self.nat_addr)
1116            self.assertEqual(sd_params.get('XSPORT'), "%d" % self.tcp_port_out)
1117            self.assertEqual(sd_params.get('PROTO'), "%d" % IP_PROTOS.tcp)
1118            self.assertEqual(sd_params.get('SVLAN'), '0')
1119            self.assertEqual(sd_params.get('XDADDR'), self.pg1.remote_ip4)
1120            self.assertEqual(sd_params.get('XDPORT'),
1121                             "%d" % self.tcp_external_port)
1122
1123    def verify_mss_value(self, pkt, mss):
1124        """
1125        Verify TCP MSS value
1126
1127        :param pkt:
1128        :param mss:
1129        """
1130        if not pkt.haslayer(IP) or not pkt.haslayer(TCP):
1131            raise TypeError("Not a TCP/IP packet")
1132
1133        for option in pkt[TCP].options:
1134            if option[0] == 'MSS':
1135                self.assertEqual(option[1], mss)
1136                self.assert_tcp_checksum_valid(pkt)
1137
1138    @staticmethod
1139    def proto2layer(proto):
1140        if proto == IP_PROTOS.tcp:
1141            return TCP
1142        elif proto == IP_PROTOS.udp:
1143            return UDP
1144        elif proto == IP_PROTOS.icmp:
1145            return ICMP
1146        else:
1147            raise Exception("Unsupported protocol")
1148
1149    def frag_in_order(self, proto=IP_PROTOS.tcp, dont_translate=False):
1150        layer = self.proto2layer(proto)
1151
1152        if proto == IP_PROTOS.tcp:
1153            data = b"A" * 4 + b"B" * 16 + b"C" * 3
1154        else:
1155            data = b"A" * 16 + b"B" * 16 + b"C" * 3
1156        self.port_in = random.randint(1025, 65535)
1157
1158        reass = self.vapi.nat_reass_dump()
1159        reass_n_start = len(reass)
1160
1161        # in2out
1162        pkts = self.create_stream_frag(self.pg0,
1163                                       self.pg1.remote_ip4,
1164                                       self.port_in,
1165                                       20,
1166                                       data,
1167                                       proto)
1168        self.pg0.add_stream(pkts)
1169        self.pg_enable_capture(self.pg_interfaces)
1170        self.pg_start()
1171        frags = self.pg1.get_capture(len(pkts))
1172        if not dont_translate:
1173            p = self.reass_frags_and_verify(frags,
1174                                            self.nat_addr,
1175                                            self.pg1.remote_ip4)
1176        else:
1177            p = self.reass_frags_and_verify(frags,
1178                                            self.pg0.remote_ip4,
1179                                            self.pg1.remote_ip4)
1180        if proto != IP_PROTOS.icmp:
1181            if not dont_translate:
1182                self.assertEqual(p[layer].dport, 20)
1183                self.assertNotEqual(p[layer].sport, self.port_in)
1184            else:
1185                self.assertEqual(p[layer].sport, self.port_in)
1186        else:
1187            if not dont_translate:
1188                self.assertNotEqual(p[layer].id, self.port_in)
1189            else:
1190                self.assertEqual(p[layer].id, self.port_in)
1191        self.assertEqual(data, p[Raw].load)
1192
1193        # out2in
1194        if not dont_translate:
1195            dst_addr = self.nat_addr
1196        else:
1197            dst_addr = self.pg0.remote_ip4
1198        if proto != IP_PROTOS.icmp:
1199            sport = 20
1200            dport = p[layer].sport
1201        else:
1202            sport = p[layer].id
1203            dport = 0
1204        pkts = self.create_stream_frag(self.pg1,
1205                                       dst_addr,
1206                                       sport,
1207                                       dport,
1208                                       data,
1209                                       proto,
1210                                       echo_reply=True)
1211        self.pg1.add_stream(pkts)
1212        self.pg_enable_capture(self.pg_interfaces)
1213        self.pg_start()
1214        frags = self.pg0.get_capture(len(pkts))
1215        p = self.reass_frags_and_verify(frags,
1216                                        self.pg1.remote_ip4,
1217                                        self.pg0.remote_ip4)
1218        if proto != IP_PROTOS.icmp:
1219            self.assertEqual(p[layer].sport, 20)
1220            self.assertEqual(p[layer].dport, self.port_in)
1221        else:
1222            self.assertEqual(p[layer].id, self.port_in)
1223        self.assertEqual(data, p[Raw].load)
1224
1225        reass = self.vapi.nat_reass_dump()
1226        reass_n_end = len(reass)
1227
1228        self.assertEqual(reass_n_end - reass_n_start, 2)
1229
1230    def frag_in_order_in_plus_out(self, proto=IP_PROTOS.tcp):
1231        layer = self.proto2layer(proto)
1232
1233        if proto == IP_PROTOS.tcp:
1234            data = b"A" * 4 + b"B" * 16 + b"C" * 3
1235        else:
1236            data = b"A" * 16 + b"B" * 16 + b"C" * 3
1237        self.port_in = random.randint(1025, 65535)
1238
1239        for i in range(2):
1240            reass = self.vapi.nat_reass_dump()
1241            reass_n_start = len(reass)
1242
1243            # out2in
1244            pkts = self.create_stream_frag(self.pg0,
1245                                           self.server_out_addr,
1246                                           self.port_in,
1247                                           self.server_out_port,
1248                                           data,
1249                                           proto)
1250            self.pg0.add_stream(pkts)
1251            self.pg_enable_capture(self.pg_interfaces)
1252            self.pg_start()
1253            frags = self.pg1.get_capture(len(pkts))
1254            p = self.reass_frags_and_verify(frags,
1255                                            self.pg0.remote_ip4,
1256                                            self.server_in_addr)
1257            if proto != IP_PROTOS.icmp:
1258                self.assertEqual(p[layer].sport, self.port_in)
1259                self.assertEqual(p[layer].dport, self.server_in_port)
1260            else:
1261                self.assertEqual(p[layer].id, self.port_in)
1262            self.assertEqual(data, p[Raw].load)
1263
1264            # in2out
1265            if proto != IP_PROTOS.icmp:
1266                pkts = self.create_stream_frag(self.pg1,
1267                                               self.pg0.remote_ip4,
1268                                               self.server_in_port,
1269                                               p[layer].sport,
1270                                               data,
1271                                               proto)
1272            else:
1273                pkts = self.create_stream_frag(self.pg1,
1274                                               self.pg0.remote_ip4,
1275                                               p[layer].id,
1276                                               0,
1277                                               data,
1278                                               proto,
1279                                               echo_reply=True)
1280            self.pg1.add_stream(pkts)
1281            self.pg_enable_capture(self.pg_interfaces)
1282            self.pg_start()
1283            frags = self.pg0.get_capture(len(pkts))
1284            p = self.reass_frags_and_verify(frags,
1285                                            self.server_out_addr,
1286                                            self.pg0.remote_ip4)
1287            if proto != IP_PROTOS.icmp:
1288                self.assertEqual(p[layer].sport, self.server_out_port)
1289                self.assertEqual(p[layer].dport, self.port_in)
1290            else:
1291                self.assertEqual(p[layer].id, self.port_in)
1292            self.assertEqual(data, p[Raw].load)
1293
1294            reass = self.vapi.nat_reass_dump()
1295            reass_n_end = len(reass)
1296
1297            self.assertEqual(reass_n_end - reass_n_start, 2)
1298
1299    def reass_hairpinning(self, proto=IP_PROTOS.tcp):
1300        layer = self.proto2layer(proto)
1301
1302        if proto == IP_PROTOS.tcp:
1303            data = b"A" * 4 + b"B" * 16 + b"C" * 3
1304        else:
1305            data = b"A" * 16 + b"B" * 16 + b"C" * 3
1306
1307        # send packet from host to server
1308        pkts = self.create_stream_frag(self.pg0,
1309                                       self.nat_addr,
1310                                       self.host_in_port,
1311                                       self.server_out_port,
1312                                       data,
1313                                       proto)
1314        self.pg0.add_stream(pkts)
1315        self.pg_enable_capture(self.pg_interfaces)
1316        self.pg_start()
1317        frags = self.pg0.get_capture(len(pkts))
1318        p = self.reass_frags_and_verify(frags,
1319                                        self.nat_addr,
1320                                        self.server.ip4)
1321        if proto != IP_PROTOS.icmp:
1322            self.assertNotEqual(p[layer].sport, self.host_in_port)
1323            self.assertEqual(p[layer].dport, self.server_in_port)
1324        else:
1325            self.assertNotEqual(p[layer].id, self.host_in_port)
1326        self.assertEqual(data, p[Raw].load)
1327
1328    def frag_out_of_order(self, proto=IP_PROTOS.tcp, dont_translate=False):
1329        layer = self.proto2layer(proto)
1330
1331        if proto == IP_PROTOS.tcp:
1332            data = b"A" * 4 + b"B" * 16 + b"C" * 3
1333        else:
1334            data = b"A" * 16 + b"B" * 16 + b"C" * 3
1335        self.port_in = random.randint(1025, 65535)
1336
1337        for i in range(2):
1338            # in2out
1339            pkts = self.create_stream_frag(self.pg0,
1340                                           self.pg1.remote_ip4,
1341                                           self.port_in,
1342                                           20,
1343                                           data,
1344                                           proto)
1345            pkts.reverse()
1346            self.pg0.add_stream(pkts)
1347            self.pg_enable_capture(self.pg_interfaces)
1348            self.pg_start()
1349            frags = self.pg1.get_capture(len(pkts))
1350            if not dont_translate:
1351                p = self.reass_frags_and_verify(frags,
1352                                                self.nat_addr,
1353                                                self.pg1.remote_ip4)
1354            else:
1355                p = self.reass_frags_and_verify(frags,
1356                                                self.pg0.remote_ip4,
1357                                                self.pg1.remote_ip4)
1358            if proto != IP_PROTOS.icmp:
1359                if not dont_translate:
1360                    self.assertEqual(p[layer].dport, 20)
1361                    self.assertNotEqual(p[layer].sport, self.port_in)
1362                else:
1363                    self.assertEqual(p[layer].sport, self.port_in)
1364            else:
1365                if not dont_translate:
1366                    self.assertNotEqual(p[layer].id, self.port_in)
1367                else:
1368                    self.assertEqual(p[layer].id, self.port_in)
1369            self.assertEqual(data, p[Raw].load)
1370
1371            # out2in
1372            if not dont_translate:
1373                dst_addr = self.nat_addr
1374            else:
1375                dst_addr = self.pg0.remote_ip4
1376            if proto != IP_PROTOS.icmp:
1377                sport = 20
1378                dport = p[layer].sport
1379            else:
1380                sport = p[layer].id
1381                dport = 0
1382            pkts = self.create_stream_frag(self.pg1,
1383                                           dst_addr,
1384                                           sport,
1385                                           dport,
1386                                           data,
1387                                           proto,
1388                                           echo_reply=True)
1389            pkts.reverse()
1390            self.pg1.add_stream(pkts)
1391            self.pg_enable_capture(self.pg_interfaces)
1392            self.pg_start()
1393            frags = self.pg0.get_capture(len(pkts))
1394            p = self.reass_frags_and_verify(frags,
1395                                            self.pg1.remote_ip4,
1396                                            self.pg0.remote_ip4)
1397            if proto != IP_PROTOS.icmp:
1398                self.assertEqual(p[layer].sport, 20)
1399                self.assertEqual(p[layer].dport, self.port_in)
1400            else:
1401                self.assertEqual(p[layer].id, self.port_in)
1402            self.assertEqual(data, p[Raw].load)
1403
1404    def frag_out_of_order_in_plus_out(self, proto=IP_PROTOS.tcp):
1405        layer = self.proto2layer(proto)
1406
1407        if proto == IP_PROTOS.tcp:
1408            data = b"A" * 4 + b"B" * 16 + b"C" * 3
1409        else:
1410            data = b"A" * 16 + b"B" * 16 + b"C" * 3
1411        self.port_in = random.randint(1025, 65535)
1412
1413        for i in range(2):
1414            # out2in
1415            pkts = self.create_stream_frag(self.pg0,
1416                                           self.server_out_addr,
1417                                           self.port_in,
1418                                           self.server_out_port,
1419                                           data,
1420                                           proto)
1421            pkts.reverse()
1422            self.pg0.add_stream(pkts)
1423            self.pg_enable_capture(self.pg_interfaces)
1424            self.pg_start()
1425            frags = self.pg1.get_capture(len(pkts))
1426            p = self.reass_frags_and_verify(frags,
1427                                            self.pg0.remote_ip4,
1428                                            self.server_in_addr)
1429            if proto != IP_PROTOS.icmp:
1430                self.assertEqual(p[layer].dport, self.server_in_port)
1431                self.assertEqual(p[layer].sport, self.port_in)
1432                self.assertEqual(p[layer].dport, self.server_in_port)
1433            else:
1434                self.assertEqual(p[layer].id, self.port_in)
1435            self.assertEqual(data, p[Raw].load)
1436
1437            # in2out
1438            if proto != IP_PROTOS.icmp:
1439                pkts = self.create_stream_frag(self.pg1,
1440                                               self.pg0.remote_ip4,
1441                                               self.server_in_port,
1442                                               p[layer].sport,
1443                                               data,
1444                                               proto)
1445            else:
1446                pkts = self.create_stream_frag(self.pg1,
1447                                               self.pg0.remote_ip4,
1448                                               p[layer].id,
1449                                               0,
1450                                               data,
1451                                               proto,
1452                                               echo_reply=True)
1453            pkts.reverse()
1454            self.pg1.add_stream(pkts)
1455            self.pg_enable_capture(self.pg_interfaces)
1456            self.pg_start()
1457            frags = self.pg0.get_capture(len(pkts))
1458            p = self.reass_frags_and_verify(frags,
1459                                            self.server_out_addr,
1460                                            self.pg0.remote_ip4)
1461            if proto != IP_PROTOS.icmp:
1462                self.assertEqual(p[layer].sport, self.server_out_port)
1463                self.assertEqual(p[layer].dport, self.port_in)
1464            else:
1465                self.assertEqual(p[layer].id, self.port_in)
1466            self.assertEqual(data, p[Raw].load)
1467
1468
1469class TestNAT44(MethodHolder):
1470    """ NAT44 Test Cases """
1471
1472    @classmethod
1473    def setUpClass(cls):
1474        super(TestNAT44, cls).setUpClass()
1475        cls.vapi.cli("set log class nat level debug")
1476
1477        try:
1478            cls.tcp_port_in = 6303
1479            cls.tcp_port_out = 6303
1480            cls.udp_port_in = 6304
1481            cls.udp_port_out = 6304
1482            cls.icmp_id_in = 6305
1483            cls.icmp_id_out = 6305
1484            cls.nat_addr = '10.0.0.3'
1485            cls.ipfix_src_port = 4739
1486            cls.ipfix_domain_id = 1
1487            cls.tcp_external_port = 80
1488            cls.udp_external_port = 69
1489
1490            cls.create_pg_interfaces(range(10))
1491            cls.interfaces = list(cls.pg_interfaces[0:4])
1492
1493            for i in cls.interfaces:
1494                i.admin_up()
1495                i.config_ip4()
1496                i.resolve_arp()
1497
1498            cls.pg0.generate_remote_hosts(3)
1499            cls.pg0.configure_ipv4_neighbors()
1500
1501            cls.pg1.generate_remote_hosts(1)
1502            cls.pg1.configure_ipv4_neighbors()
1503
1504            cls.overlapping_interfaces = list(list(cls.pg_interfaces[4:7]))
1505            cls.vapi.ip_table_add_del(is_add=1, table_id=10)
1506            cls.vapi.ip_table_add_del(is_add=1, table_id=20)
1507
1508            cls.pg4._local_ip4 = VppIpPrefix("172.16.255.1",
1509                                             cls.pg4.local_ip4_prefix.len)
1510            cls.pg4._remote_hosts[0]._ip4 = "172.16.255.2"
1511            cls.pg4.set_table_ip4(10)
1512            cls.pg5._local_ip4 = VppIpPrefix("172.17.255.3",
1513                                             cls.pg5.local_ip4_prefix.len)
1514            cls.pg5._remote_hosts[0]._ip4 = "172.17.255.4"
1515            cls.pg5.set_table_ip4(10)
1516            cls.pg6._local_ip4 = VppIpPrefix("172.16.255.1",
1517                                             cls.pg6.local_ip4_prefix.len)
1518            cls.pg6._remote_hosts[0]._ip4 = "172.16.255.2"
1519            cls.pg6.set_table_ip4(20)
1520            for i in cls.overlapping_interfaces:
1521                i.config_ip4()
1522                i.admin_up()
1523                i.resolve_arp()
1524
1525            cls.pg7.admin_up()
1526            cls.pg8.admin_up()
1527
1528            cls.pg9.generate_remote_hosts(2)
1529            cls.pg9.config_ip4()
1530            cls.vapi.sw_interface_add_del_address(
1531                sw_if_index=cls.pg9.sw_if_index,
1532                prefix=VppIpPrefix("10.0.0.1", 24).encode())
1533
1534            cls.pg9.admin_up()
1535            cls.pg9.resolve_arp()
1536            cls.pg9._remote_hosts[1]._ip4 = cls.pg9._remote_hosts[0]._ip4
1537            cls.pg4._remote_ip4 = cls.pg9._remote_hosts[0]._ip4 = "10.0.0.2"
1538            cls.pg9.resolve_arp()
1539
1540        except Exception:
1541            super(TestNAT44, cls).tearDownClass()
1542            raise
1543
1544    @classmethod
1545    def tearDownClass(cls):
1546        super(TestNAT44, cls).tearDownClass()
1547
1548    def test_dynamic(self):
1549        """ NAT44 dynamic translation test """
1550        self.nat44_add_address(self.nat_addr)
1551        flags = self.config_flags.NAT_IS_INSIDE
1552        self.vapi.nat44_interface_add_del_feature(
1553            sw_if_index=self.pg0.sw_if_index,
1554            flags=flags, is_add=1)
1555        self.vapi.nat44_interface_add_del_feature(
1556            sw_if_index=self.pg1.sw_if_index,
1557            is_add=1)
1558
1559        # in2out
1560        tcpn = self.statistics.get_err_counter(
1561            '/err/nat44-in2out-slowpath/TCP packets')
1562        udpn = self.statistics.get_err_counter(
1563            '/err/nat44-in2out-slowpath/UDP packets')
1564        icmpn = self.statistics.get_err_counter(
1565            '/err/nat44-in2out-slowpath/ICMP packets')
1566        totaln = self.statistics.get_err_counter(
1567            '/err/nat44-in2out-slowpath/good in2out packets processed')
1568
1569        pkts = self.create_stream_in(self.pg0, self.pg1)
1570        self.pg0.add_stream(pkts)
1571        self.pg_enable_capture(self.pg_interfaces)
1572        self.pg_start()
1573        capture = self.pg1.get_capture(len(pkts))
1574        self.verify_capture_out(capture)
1575
1576        err = self.statistics.get_err_counter(
1577            '/err/nat44-in2out-slowpath/TCP packets')
1578        self.assertEqual(err - tcpn, 2)
1579        err = self.statistics.get_err_counter(
1580            '/err/nat44-in2out-slowpath/UDP packets')
1581        self.assertEqual(err - udpn, 1)
1582        err = self.statistics.get_err_counter(
1583            '/err/nat44-in2out-slowpath/ICMP packets')
1584        self.assertEqual(err - icmpn, 1)
1585        err = self.statistics.get_err_counter(
1586            '/err/nat44-in2out-slowpath/good in2out packets processed')
1587        self.assertEqual(err - totaln, 4)
1588
1589        # out2in
1590        tcpn = self.statistics.get_err_counter('/err/nat44-out2in/TCP packets')
1591        udpn = self.statistics.get_err_counter('/err/nat44-out2in/UDP packets')
1592        icmpn = self.statistics.get_err_counter(
1593            '/err/nat44-out2in/ICMP packets')
1594        totaln = self.statistics.get_err_counter(
1595            '/err/nat44-out2in/good out2in packets processed')
1596
1597        pkts = self.create_stream_out(self.pg1)
1598        self.pg1.add_stream(pkts)
1599        self.pg_enable_capture(self.pg_interfaces)
1600        self.pg_start()
1601        capture = self.pg0.get_capture(len(pkts))
1602        self.verify_capture_in(capture, self.pg0)
1603
1604        err = self.statistics.get_err_counter('/err/nat44-out2in/TCP packets')
1605        self.assertEqual(err - tcpn, 2)
1606        err = self.statistics.get_err_counter('/err/nat44-out2in/UDP packets')
1607        self.assertEqual(err - udpn, 1)
1608        err = self.statistics.get_err_counter('/err/nat44-out2in/ICMP packets')
1609        self.assertEqual(err - icmpn, 1)
1610        err = self.statistics.get_err_counter(
1611            '/err/nat44-out2in/good out2in packets processed')
1612        self.assertEqual(err - totaln, 4)
1613
1614        users = self.statistics.get_counter('/nat44/total-users')
1615        self.assertEqual(users[0][0], 1)
1616        sessions = self.statistics.get_counter('/nat44/total-sessions')
1617        self.assertEqual(sessions[0][0], 3)
1618
1619    def test_dynamic_icmp_errors_in2out_ttl_1(self):
1620        """ NAT44 handling of client packets with TTL=1 """
1621
1622        self.nat44_add_address(self.nat_addr)
1623        flags = self.config_flags.NAT_IS_INSIDE
1624        self.vapi.nat44_interface_add_del_feature(
1625            sw_if_index=self.pg0.sw_if_index,
1626            flags=flags, is_add=1)
1627        self.vapi.nat44_interface_add_del_feature(
1628            sw_if_index=self.pg1.sw_if_index,
1629            is_add=1)
1630
1631        # Client side - generate traffic
1632        pkts = self.create_stream_in(self.pg0, self.pg1, ttl=1)
1633        self.pg0.add_stream(pkts)
1634        self.pg_enable_capture(self.pg_interfaces)
1635        self.pg_start()
1636
1637        # Client side - verify ICMP type 11 packets
1638        capture = self.pg0.get_capture(len(pkts))
1639        self.verify_capture_in_with_icmp_errors(capture, self.pg0)
1640
1641    def test_dynamic_icmp_errors_out2in_ttl_1(self):
1642        """ NAT44 handling of server packets with TTL=1 """
1643
1644        self.nat44_add_address(self.nat_addr)
1645        flags = self.config_flags.NAT_IS_INSIDE
1646        self.vapi.nat44_interface_add_del_feature(
1647            sw_if_index=self.pg0.sw_if_index,
1648            flags=flags, is_add=1)
1649        self.vapi.nat44_interface_add_del_feature(
1650            sw_if_index=self.pg1.sw_if_index,
1651            is_add=1)
1652
1653        # Client side - create sessions
1654        pkts = self.create_stream_in(self.pg0, self.pg1)
1655        self.pg0.add_stream(pkts)
1656        self.pg_enable_capture(self.pg_interfaces)
1657        self.pg_start()
1658
1659        # Server side - generate traffic
1660        capture = self.pg1.get_capture(len(pkts))
1661        self.verify_capture_out(capture)
1662        pkts = self.create_stream_out(self.pg1, ttl=1)
1663        self.pg1.add_stream(pkts)
1664        self.pg_enable_capture(self.pg_interfaces)
1665        self.pg_start()
1666
1667        # Server side - verify ICMP type 11 packets
1668        capture = self.pg1.get_capture(len(pkts))
1669        self.verify_capture_out_with_icmp_errors(capture,
1670                                                 src_ip=self.pg1.local_ip4)
1671
1672    def test_dynamic_icmp_errors_in2out_ttl_2(self):
1673        """ NAT44 handling of error responses to client packets with TTL=2 """
1674
1675        self.nat44_add_address(self.nat_addr)
1676        flags = self.config_flags.NAT_IS_INSIDE
1677        self.vapi.nat44_interface_add_del_feature(
1678            sw_if_index=self.pg0.sw_if_index,
1679            flags=flags, is_add=1)
1680        self.vapi.nat44_interface_add_del_feature(
1681            sw_if_index=self.pg1.sw_if_index,
1682            is_add=1)
1683
1684        # Client side - generate traffic
1685        pkts = self.create_stream_in(self.pg0, self.pg1, ttl=2)
1686        self.pg0.add_stream(pkts)
1687        self.pg_enable_capture(self.pg_interfaces)
1688        self.pg_start()
1689
1690        # Server side - simulate ICMP type 11 response
1691        capture = self.pg1.get_capture(len(pkts))
1692        pkts = [Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
1693                IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
1694                ICMP(type=11) / packet[IP] for packet in capture]
1695        self.pg1.add_stream(pkts)
1696        self.pg_enable_capture(self.pg_interfaces)
1697        self.pg_start()
1698
1699        # Client side - verify ICMP type 11 packets
1700        capture = self.pg0.get_capture(len(pkts))
1701        self.verify_capture_in_with_icmp_errors(capture, self.pg0)
1702
1703    def test_dynamic_icmp_errors_out2in_ttl_2(self):
1704        """ NAT44 handling of error responses to server packets with TTL=2 """
1705
1706        self.nat44_add_address(self.nat_addr)
1707        flags = self.config_flags.NAT_IS_INSIDE
1708        self.vapi.nat44_interface_add_del_feature(
1709            sw_if_index=self.pg0.sw_if_index,
1710            flags=flags, is_add=1)
1711        self.vapi.nat44_interface_add_del_feature(
1712            sw_if_index=self.pg1.sw_if_index,
1713            is_add=1)
1714
1715        # Client side - create sessions
1716        pkts = self.create_stream_in(self.pg0, self.pg1)
1717        self.pg0.add_stream(pkts)
1718        self.pg_enable_capture(self.pg_interfaces)
1719        self.pg_start()
1720
1721        # Server side - generate traffic
1722        capture = self.pg1.get_capture(len(pkts))
1723        self.verify_capture_out(capture)
1724        pkts = self.create_stream_out(self.pg1, ttl=2)
1725        self.pg1.add_stream(pkts)
1726        self.pg_enable_capture(self.pg_interfaces)
1727        self.pg_start()
1728
1729        # Client side - simulate ICMP type 11 response
1730        capture = self.pg0.get_capture(len(pkts))
1731        pkts = [Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
1732                IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
1733                ICMP(type=11) / packet[IP] for packet in capture]
1734        self.pg0.add_stream(pkts)
1735        self.pg_enable_capture(self.pg_interfaces)
1736        self.pg_start()
1737
1738        # Server side - verify ICMP type 11 packets
1739        capture = self.pg1.get_capture(len(pkts))
1740        self.verify_capture_out_with_icmp_errors(capture)
1741
1742    def test_ping_out_interface_from_outside(self):
1743        """ Ping NAT44 out interface from outside network """
1744
1745        self.nat44_add_address(self.nat_addr)
1746        flags = self.config_flags.NAT_IS_INSIDE
1747        self.vapi.nat44_interface_add_del_feature(
1748            sw_if_index=self.pg0.sw_if_index,
1749            flags=flags, is_add=1)
1750        self.vapi.nat44_interface_add_del_feature(
1751            sw_if_index=self.pg1.sw_if_index,
1752            is_add=1)
1753
1754        p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
1755             IP(src=self.pg1.remote_ip4, dst=self.pg1.local_ip4) /
1756             ICMP(id=self.icmp_id_out, type='echo-request'))
1757        pkts = [p]
1758        self.pg1.add_stream(pkts)
1759        self.pg_enable_capture(self.pg_interfaces)
1760        self.pg_start()
1761        capture = self.pg1.get_capture(len(pkts))
1762        packet = capture[0]
1763        try:
1764            self.assertEqual(packet[IP].src, self.pg1.local_ip4)
1765            self.assertEqual(packet[IP].dst, self.pg1.remote_ip4)
1766            self.assertEqual(packet[ICMP].id, self.icmp_id_in)
1767            self.assertEqual(packet[ICMP].type, 0)  # echo reply
1768        except:
1769            self.logger.error(ppp("Unexpected or invalid packet "
1770                                  "(outside network):", packet))
1771            raise
1772
1773    def test_ping_internal_host_from_outside(self):
1774        """ Ping internal host from outside network """
1775
1776        self.nat44_add_static_mapping(self.pg0.remote_ip4, self.nat_addr)
1777        flags = self.config_flags.NAT_IS_INSIDE
1778        self.vapi.nat44_interface_add_del_feature(
1779            sw_if_index=self.pg0.sw_if_index,
1780            flags=flags, is_add=1)
1781        self.vapi.nat44_interface_add_del_feature(
1782            sw_if_index=self.pg1.sw_if_index,
1783            is_add=1)
1784
1785        # out2in
1786        pkt = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
1787               IP(src=self.pg1.remote_ip4, dst=self.nat_addr, ttl=64) /
1788               ICMP(id=self.icmp_id_out, type='echo-request'))
1789        self.pg1.add_stream(pkt)
1790        self.pg_enable_capture(self.pg_interfaces)
1791        self.pg_start()
1792        capture = self.pg0.get_capture(1)
1793        self.verify_capture_in(capture, self.pg0)
1794        self.assert_equal(capture[0][IP].proto, IP_PROTOS.icmp)
1795
1796        # in2out
1797        pkt = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
1798               IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4, ttl=64) /
1799               ICMP(id=self.icmp_id_in, type='echo-reply'))
1800        self.pg0.add_stream(pkt)
1801        self.pg_enable_capture(self.pg_interfaces)
1802        self.pg_start()
1803        capture = self.pg1.get_capture(1)
1804        self.verify_capture_out(capture, same_port=True)
1805        self.assert_equal(capture[0][IP].proto, IP_PROTOS.icmp)
1806
1807    def test_forwarding(self):
1808        """ NAT44 forwarding test """
1809
1810        flags = self.config_flags.NAT_IS_INSIDE
1811        self.vapi.nat44_interface_add_del_feature(
1812            sw_if_index=self.pg0.sw_if_index,
1813            flags=flags, is_add=1)
1814        self.vapi.nat44_interface_add_del_feature(
1815            sw_if_index=self.pg1.sw_if_index,
1816            is_add=1)
1817        self.vapi.nat44_forwarding_enable_disable(enable=1)
1818
1819        real_ip = self.pg0.remote_ip4
1820        alias_ip = self.nat_addr
1821        flags = self.config_flags.NAT_IS_ADDR_ONLY
1822        self.vapi.nat44_add_del_static_mapping(is_add=1,
1823                                               local_ip_address=real_ip,
1824                                               external_ip_address=alias_ip,
1825                                               external_sw_if_index=0xFFFFFFFF,
1826                                               flags=flags)
1827
1828        try:
1829            # static mapping match
1830
1831            pkts = self.create_stream_out(self.pg1)
1832            self.pg1.add_stream(pkts)
1833            self.pg_enable_capture(self.pg_interfaces)
1834            self.pg_start()
1835            capture = self.pg0.get_capture(len(pkts))
1836            self.verify_capture_in(capture, self.pg0)
1837
1838            pkts = self.create_stream_in(self.pg0, self.pg1)
1839            self.pg0.add_stream(pkts)
1840            self.pg_enable_capture(self.pg_interfaces)
1841            self.pg_start()
1842            capture = self.pg1.get_capture(len(pkts))
1843            self.verify_capture_out(capture, same_port=True)
1844
1845            # no static mapping match
1846
1847            host0 = self.pg0.remote_hosts[0]
1848            self.pg0.remote_hosts[0] = self.pg0.remote_hosts[1]
1849            try:
1850                pkts = self.create_stream_out(self.pg1,
1851                                              dst_ip=self.pg0.remote_ip4,
1852                                              use_inside_ports=True)
1853                self.pg1.add_stream(pkts)
1854                self.pg_enable_capture(self.pg_interfaces)
1855                self.pg_start()
1856                capture = self.pg0.get_capture(len(pkts))
1857                self.verify_capture_in(capture, self.pg0)
1858
1859                pkts = self.create_stream_in(self.pg0, self.pg1)
1860                self.pg0.add_stream(pkts)
1861                self.pg_enable_capture(self.pg_interfaces)
1862                self.pg_start()
1863                capture = self.pg1.get_capture(len(pkts))
1864                self.verify_capture_out(capture, nat_ip=self.pg0.remote_ip4,
1865                                        same_port=True)
1866            finally:
1867                self.pg0.remote_hosts[0] = host0
1868
1869        finally:
1870            self.vapi.nat44_forwarding_enable_disable(enable=0)
1871            flags = self.config_flags.NAT_IS_ADDR_ONLY
1872            self.vapi.nat44_add_del_static_mapping(
1873                is_add=0,
1874                local_ip_address=real_ip,
1875                external_ip_address=alias_ip,
1876                external_sw_if_index=0xFFFFFFFF,
1877                flags=flags)
1878
1879    def test_static_in(self):
1880        """ 1:1 NAT initialized from inside network """
1881
1882        nat_ip = "10.0.0.10"
1883        self.tcp_port_out = 6303
1884        self.udp_port_out = 6304
1885        self.icmp_id_out = 6305
1886
1887        self.nat44_add_static_mapping(self.pg0.remote_ip4, nat_ip)
1888        flags = self.config_flags.NAT_IS_INSIDE
1889        self.vapi.nat44_interface_add_del_feature(
1890            sw_if_index=self.pg0.sw_if_index,
1891            flags=flags, is_add=1)
1892        self.vapi.nat44_interface_add_del_feature(
1893            sw_if_index=self.pg1.sw_if_index,
1894            is_add=1)
1895        sm = self.vapi.nat44_static_mapping_dump()
1896        self.assertEqual(len(sm), 1)
1897        self.assertEqual(sm[0].tag, '')
1898        self.assertEqual(sm[0].protocol, 0)
1899        self.assertEqual(sm[0].local_port, 0)
1900        self.assertEqual(sm[0].external_port, 0)
1901
1902        # in2out
1903        pkts = self.create_stream_in(self.pg0, self.pg1)
1904        self.pg0.add_stream(pkts)
1905        self.pg_enable_capture(self.pg_interfaces)
1906        self.pg_start()
1907        capture = self.pg1.get_capture(len(pkts))
1908        self.verify_capture_out(capture, nat_ip, True)
1909
1910        # out2in
1911        pkts = self.create_stream_out(self.pg1, nat_ip)
1912        self.pg1.add_stream(pkts)
1913        self.pg_enable_capture(self.pg_interfaces)
1914        self.pg_start()
1915        capture = self.pg0.get_capture(len(pkts))
1916        self.verify_capture_in(capture, self.pg0)
1917
1918    def test_static_out(self):
1919        """ 1:1 NAT initialized from outside network """
1920
1921        nat_ip = "10.0.0.20"
1922        self.tcp_port_out = 6303
1923        self.udp_port_out = 6304
1924        self.icmp_id_out = 6305
1925        tag = "testTAG"
1926
1927        self.nat44_add_static_mapping(self.pg0.remote_ip4, nat_ip, tag=tag)
1928        flags = self.config_flags.NAT_IS_INSIDE
1929        self.vapi.nat44_interface_add_del_feature(
1930            sw_if_index=self.pg0.sw_if_index,
1931            flags=flags, is_add=1)
1932        self.vapi.nat44_interface_add_del_feature(
1933            sw_if_index=self.pg1.sw_if_index,
1934            is_add=1)
1935        sm = self.vapi.nat44_static_mapping_dump()
1936        self.assertEqual(len(sm), 1)
1937        self.assertEqual(sm[0].tag, tag)
1938
1939        # out2in
1940        pkts = self.create_stream_out(self.pg1, nat_ip)
1941        self.pg1.add_stream(pkts)
1942        self.pg_enable_capture(self.pg_interfaces)
1943        self.pg_start()
1944        capture = self.pg0.get_capture(len(pkts))
1945        self.verify_capture_in(capture, self.pg0)
1946
1947        # in2out
1948        pkts = self.create_stream_in(self.pg0, self.pg1)
1949        self.pg0.add_stream(pkts)
1950        self.pg_enable_capture(self.pg_interfaces)
1951        self.pg_start()
1952        capture = self.pg1.get_capture(len(pkts))
1953        self.verify_capture_out(capture, nat_ip, True)
1954
1955    def test_static_with_port_in(self):
1956        """ 1:1 NAPT initialized from inside network """
1957
1958        self.tcp_port_out = 3606
1959        self.udp_port_out = 3607
1960        self.icmp_id_out = 3608
1961
1962        self.nat44_add_address(self.nat_addr)
1963        self.nat44_add_static_mapping(self.pg0.remote_ip4, self.nat_addr,
1964                                      self.tcp_port_in, self.tcp_port_out,
1965                                      proto=IP_PROTOS.tcp)
1966        self.nat44_add_static_mapping(self.pg0.remote_ip4, self.nat_addr,
1967                                      self.udp_port_in, self.udp_port_out,
1968                                      proto=IP_PROTOS.udp)
1969        self.nat44_add_static_mapping(self.pg0.remote_ip4, self.nat_addr,
1970                                      self.icmp_id_in, self.icmp_id_out,
1971                                      proto=IP_PROTOS.icmp)
1972        flags = self.config_flags.NAT_IS_INSIDE
1973        self.vapi.nat44_interface_add_del_feature(
1974            sw_if_index=self.pg0.sw_if_index,
1975            flags=flags, is_add=1)
1976        self.vapi.nat44_interface_add_del_feature(
1977            sw_if_index=self.pg1.sw_if_index,
1978            is_add=1)
1979
1980        # in2out
1981        pkts = self.create_stream_in(self.pg0, self.pg1)
1982        self.pg0.add_stream(pkts)
1983        self.pg_enable_capture(self.pg_interfaces)
1984        self.pg_start()
1985        capture = self.pg1.get_capture(len(pkts))
1986        self.verify_capture_out(capture)
1987
1988        # out2in
1989        pkts = self.create_stream_out(self.pg1)
1990        self.pg1.add_stream(pkts)
1991        self.pg_enable_capture(self.pg_interfaces)
1992        self.pg_start()
1993        capture = self.pg0.get_capture(len(pkts))
1994        self.verify_capture_in(capture, self.pg0)
1995
1996    def test_static_with_port_out(self):
1997        """ 1:1 NAPT initialized from outside network """
1998
1999        self.tcp_port_out = 30606
2000        self.udp_port_out = 30607
2001        self.icmp_id_out = 30608
2002
2003        self.nat44_add_address(self.nat_addr)
2004        self.nat44_add_static_mapping(self.pg0.remote_ip4, self.nat_addr,
2005                                      self.tcp_port_in, self.tcp_port_out,
2006                                      proto=IP_PROTOS.tcp)
2007        self.nat44_add_static_mapping(self.pg0.remote_ip4, self.nat_addr,
2008                                      self.udp_port_in, self.udp_port_out,
2009                                      proto=IP_PROTOS.udp)
2010        self.nat44_add_static_mapping(self.pg0.remote_ip4, self.nat_addr,
2011                                      self.icmp_id_in, self.icmp_id_out,
2012                                      proto=IP_PROTOS.icmp)
2013        flags = self.config_flags.NAT_IS_INSIDE
2014        self.vapi.nat44_interface_add_del_feature(
2015            sw_if_index=self.pg0.sw_if_index,
2016            flags=flags, is_add=1)
2017        self.vapi.nat44_interface_add_del_feature(
2018            sw_if_index=self.pg1.sw_if_index,
2019            is_add=1)
2020
2021        # out2in
2022        pkts = self.create_stream_out(self.pg1)
2023        self.pg1.add_stream(pkts)
2024        self.pg_enable_capture(self.pg_interfaces)
2025        self.pg_start()
2026        capture = self.pg0.get_capture(len(pkts))
2027        self.verify_capture_in(capture, self.pg0)
2028
2029        # in2out
2030        pkts = self.create_stream_in(self.pg0, self.pg1)
2031        self.pg0.add_stream(pkts)
2032        self.pg_enable_capture(self.pg_interfaces)
2033        self.pg_start()
2034        capture = self.pg1.get_capture(len(pkts))
2035        self.verify_capture_out(capture)
2036
2037    def test_static_vrf_aware(self):
2038        """ 1:1 NAT VRF awareness """
2039
2040        nat_ip1 = "10.0.0.30"
2041        nat_ip2 = "10.0.0.40"
2042        self.tcp_port_out = 6303
2043        self.udp_port_out = 6304
2044        self.icmp_id_out = 6305
2045
2046        self.nat44_add_static_mapping(self.pg4.remote_ip4, nat_ip1,
2047                                      vrf_id=10)
2048        self.nat44_add_static_mapping(self.pg0.remote_ip4, nat_ip2,
2049                                      vrf_id=10)
2050        flags = self.config_flags.NAT_IS_INSIDE
2051        self.vapi.nat44_interface_add_del_feature(
2052            sw_if_index=self.pg3.sw_if_index,
2053            is_add=1)
2054        self.vapi.nat44_interface_add_del_feature(
2055            sw_if_index=self.pg0.sw_if_index,
2056            flags=flags, is_add=1)
2057        self.vapi.nat44_interface_add_del_feature(
2058            sw_if_index=self.pg4.sw_if_index,
2059            flags=flags, is_add=1)
2060
2061        # inside interface VRF match NAT44 static mapping VRF
2062        pkts = self.create_stream_in(self.pg4, self.pg3)
2063        self.pg4.add_stream(pkts)
2064        self.pg_enable_capture(self.pg_interfaces)
2065        self.pg_start()
2066        capture = self.pg3.get_capture(len(pkts))
2067        self.verify_capture_out(capture, nat_ip1, True)
2068
2069        # inside interface VRF don't match NAT44 static mapping VRF (packets
2070        # are dropped)
2071        pkts = self.create_stream_in(self.pg0, self.pg3)
2072        self.pg0.add_stream(pkts)
2073        self.pg_enable_capture(self.pg_interfaces)
2074        self.pg_start()
2075        self.pg3.assert_nothing_captured()
2076
2077    def test_dynamic_to_static(self):
2078        """ Switch from dynamic translation to 1:1NAT """
2079        nat_ip = "10.0.0.10"
2080        self.tcp_port_out = 6303
2081        self.udp_port_out = 6304
2082        self.icmp_id_out = 6305
2083
2084        self.nat44_add_address(self.nat_addr)
2085        flags = self.config_flags.NAT_IS_INSIDE
2086        self.vapi.nat44_interface_add_del_feature(
2087            sw_if_index=self.pg0.sw_if_index,
2088            flags=flags, is_add=1)
2089        self.vapi.nat44_interface_add_del_feature(
2090            sw_if_index=self.pg1.sw_if_index,
2091            is_add=1)
2092
2093        # dynamic
2094        pkts = self.create_stream_in(self.pg0, self.pg1)
2095        self.pg0.add_stream(pkts)
2096        self.pg_enable_capture(self.pg_interfaces)
2097        self.pg_start()
2098        capture = self.pg1.get_capture(len(pkts))
2099        self.verify_capture_out(capture)
2100
2101        # 1:1NAT
2102        self.nat44_add_static_mapping(self.pg0.remote_ip4, nat_ip)
2103        sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
2104        self.assertEqual(len(sessions), 0)
2105        pkts = self.create_stream_in(self.pg0, self.pg1)
2106        self.pg0.add_stream(pkts)
2107        self.pg_enable_capture(self.pg_interfaces)
2108        self.pg_start()
2109        capture = self.pg1.get_capture(len(pkts))
2110        self.verify_capture_out(capture, nat_ip, True)
2111
2112    def test_identity_nat(self):
2113        """ Identity NAT """
2114        flags = self.config_flags.NAT_IS_ADDR_ONLY
2115        self.vapi.nat44_add_del_identity_mapping(
2116            ip_address=self.pg0.remote_ip4, sw_if_index=0xFFFFFFFF,
2117            flags=flags, is_add=1)
2118        flags = self.config_flags.NAT_IS_INSIDE
2119        self.vapi.nat44_interface_add_del_feature(
2120            sw_if_index=self.pg0.sw_if_index,
2121            flags=flags, is_add=1)
2122        self.vapi.nat44_interface_add_del_feature(
2123            sw_if_index=self.pg1.sw_if_index,
2124            is_add=1)
2125
2126        p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
2127             IP(src=self.pg1.remote_ip4, dst=self.pg0.remote_ip4) /
2128             TCP(sport=12345, dport=56789))
2129        self.pg1.add_stream(p)
2130        self.pg_enable_capture(self.pg_interfaces)
2131        self.pg_start()
2132        capture = self.pg0.get_capture(1)
2133        p = capture[0]
2134        try:
2135            ip = p[IP]
2136            tcp = p[TCP]
2137            self.assertEqual(ip.dst, self.pg0.remote_ip4)
2138            self.assertEqual(ip.src, self.pg1.remote_ip4)
2139            self.assertEqual(tcp.dport, 56789)
2140            self.assertEqual(tcp.sport, 12345)
2141            self.assert_packet_checksums_valid(p)
2142        except:
2143            self.logger.error(ppp("Unexpected or invalid packet:", p))
2144            raise
2145
2146        sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
2147        self.assertEqual(len(sessions), 0)
2148        flags = self.config_flags.NAT_IS_ADDR_ONLY
2149        self.vapi.nat44_add_del_identity_mapping(
2150            ip_address=self.pg0.remote_ip4, sw_if_index=0xFFFFFFFF,
2151            flags=flags, vrf_id=1, is_add=1)
2152        identity_mappings = self.vapi.nat44_identity_mapping_dump()
2153        self.assertEqual(len(identity_mappings), 2)
2154
2155    def test_multiple_inside_interfaces(self):
2156        """ NAT44 multiple non-overlapping address space inside interfaces """
2157
2158        self.nat44_add_address(self.nat_addr)
2159        flags = self.config_flags.NAT_IS_INSIDE
2160        self.vapi.nat44_interface_add_del_feature(
2161            sw_if_index=self.pg0.sw_if_index,
2162            flags=flags, is_add=1)
2163        self.vapi.nat44_interface_add_del_feature(
2164            sw_if_index=self.pg1.sw_if_index,
2165            flags=flags, is_add=1)
2166        self.vapi.nat44_interface_add_del_feature(
2167            sw_if_index=self.pg3.sw_if_index,
2168            is_add=1)
2169
2170        # between two NAT44 inside interfaces (no translation)
2171        pkts = self.create_stream_in(self.pg0, self.pg1)
2172        self.pg0.add_stream(pkts)
2173        self.pg_enable_capture(self.pg_interfaces)
2174        self.pg_start()
2175        capture = self.pg1.get_capture(len(pkts))
2176        self.verify_capture_no_translation(capture, self.pg0, self.pg1)
2177
2178        # from NAT44 inside to interface without NAT44 feature (no translation)
2179        pkts = self.create_stream_in(self.pg0, self.pg2)
2180        self.pg0.add_stream(pkts)
2181        self.pg_enable_capture(self.pg_interfaces)
2182        self.pg_start()
2183        capture = self.pg2.get_capture(len(pkts))
2184        self.verify_capture_no_translation(capture, self.pg0, self.pg2)
2185
2186        # in2out 1st interface
2187        pkts = self.create_stream_in(self.pg0, self.pg3)
2188        self.pg0.add_stream(pkts)
2189        self.pg_enable_capture(self.pg_interfaces)
2190        self.pg_start()
2191        capture = self.pg3.get_capture(len(pkts))
2192        self.verify_capture_out(capture)
2193
2194        # out2in 1st interface
2195        pkts = self.create_stream_out(self.pg3)
2196        self.pg3.add_stream(pkts)
2197        self.pg_enable_capture(self.pg_interfaces)
2198        self.pg_start()
2199        capture = self.pg0.get_capture(len(pkts))
2200        self.verify_capture_in(capture, self.pg0)
2201
2202        # in2out 2nd interface
2203        pkts = self.create_stream_in(self.pg1, self.pg3)
2204        self.pg1.add_stream(pkts)
2205        self.pg_enable_capture(self.pg_interfaces)
2206        self.pg_start()
2207        capture = self.pg3.get_capture(len(pkts))
2208        self.verify_capture_out(capture)
2209
2210        # out2in 2nd interface
2211        pkts = self.create_stream_out(self.pg3)
2212        self.pg3.add_stream(pkts)
2213        self.pg_enable_capture(self.pg_interfaces)
2214        self.pg_start()
2215        capture = self.pg1.get_capture(len(pkts))
2216        self.verify_capture_in(capture, self.pg1)
2217
2218    def test_inside_overlapping_interfaces(self):
2219        """ NAT44 multiple inside interfaces with overlapping address space """
2220
2221        static_nat_ip = "10.0.0.10"
2222        self.nat44_add_address(self.nat_addr)
2223        flags = self.config_flags.NAT_IS_INSIDE
2224        self.vapi.nat44_interface_add_del_feature(
2225            sw_if_index=self.pg3.sw_if_index,
2226            is_add=1)
2227        self.vapi.nat44_interface_add_del_feature(
2228            sw_if_index=self.pg4.sw_if_index,
2229            flags=flags, is_add=1)
2230        self.vapi.nat44_interface_add_del_feature(
2231            sw_if_index=self.pg5.sw_if_index,
2232            flags=flags, is_add=1)
2233        self.vapi.nat44_interface_add_del_feature(
2234            sw_if_index=self.pg6.sw_if_index,
2235            flags=flags, is_add=1)
2236        self.nat44_add_static_mapping(self.pg6.remote_ip4, static_nat_ip,
2237                                      vrf_id=20)
2238
2239        # between NAT44 inside interfaces with same VRF (no translation)
2240        pkts = self.create_stream_in(self.pg4, self.pg5)
2241        self.pg4.add_stream(pkts)
2242        self.pg_enable_capture(self.pg_interfaces)
2243        self.pg_start()
2244        capture = self.pg5.get_capture(len(pkts))
2245        self.verify_capture_no_translation(capture, self.pg4, self.pg5)
2246
2247        # between NAT44 inside interfaces with different VRF (hairpinning)
2248        p = (Ether(src=self.pg4.remote_mac, dst=self.pg4.local_mac) /
2249             IP(src=self.pg4.remote_ip4, dst=static_nat_ip) /
2250             TCP(sport=1234, dport=5678))
2251        self.pg4.add_stream(p)
2252        self.pg_enable_capture(self.pg_interfaces)
2253        self.pg_start()
2254        capture = self.pg6.get_capture(1)
2255        p = capture[0]
2256        try:
2257            ip = p[IP]
2258            tcp = p[TCP]
2259            self.assertEqual(ip.src, self.nat_addr)
2260            self.assertEqual(ip.dst, self.pg6.remote_ip4)
2261            self.assertNotEqual(tcp.sport, 1234)
2262            self.assertEqual(tcp.dport, 5678)
2263        except:
2264            self.logger.error(ppp("Unexpected or invalid packet:", p))
2265            raise
2266
2267        # in2out 1st interface
2268        pkts = self.create_stream_in(self.pg4, self.pg3)
2269        self.pg4.add_stream(pkts)
2270        self.pg_enable_capture(self.pg_interfaces)
2271        self.pg_start()
2272        capture = self.pg3.get_capture(len(pkts))
2273        self.verify_capture_out(capture)
2274
2275        # out2in 1st interface
2276        pkts = self.create_stream_out(self.pg3)
2277        self.pg3.add_stream(pkts)
2278        self.pg_enable_capture(self.pg_interfaces)
2279        self.pg_start()
2280        capture = self.pg4.get_capture(len(pkts))
2281        self.verify_capture_in(capture, self.pg4)
2282
2283        # in2out 2nd interface
2284        pkts = self.create_stream_in(self.pg5, self.pg3)
2285        self.pg5.add_stream(pkts)
2286        self.pg_enable_capture(self.pg_interfaces)
2287        self.pg_start()
2288        capture = self.pg3.get_capture(len(pkts))
2289        self.verify_capture_out(capture)
2290
2291        # out2in 2nd interface
2292        pkts = self.create_stream_out(self.pg3)
2293        self.pg3.add_stream(pkts)
2294        self.pg_enable_capture(self.pg_interfaces)
2295        self.pg_start()
2296        capture = self.pg5.get_capture(len(pkts))
2297        self.verify_capture_in(capture, self.pg5)
2298
2299        # pg5 session dump
2300        addresses = self.vapi.nat44_address_dump()
2301        self.assertEqual(len(addresses), 1)
2302        sessions = self.vapi.nat44_user_session_dump(self.pg5.remote_ip4, 10)
2303        self.assertEqual(len(sessions), 3)
2304        for session in sessions:
2305            self.assertFalse(session.flags & self.config_flags.NAT_IS_STATIC)
2306            self.assertEqual(str(session.inside_ip_address),
2307                             self.pg5.remote_ip4)
2308            self.assertEqual(session.outside_ip_address,
2309                             addresses[0].ip_address)
2310        self.assertEqual(sessions[0].protocol, IP_PROTOS.tcp)
2311        self.assertEqual(sessions[1].protocol, IP_PROTOS.udp)
2312        self.assertEqual(sessions[2].protocol, IP_PROTOS.icmp)
2313        self.assertEqual(sessions[0].inside_port, self.tcp_port_in)
2314        self.assertEqual(sessions[1].inside_port, self.udp_port_in)
2315        self.assertEqual(sessions[2].inside_port, self.icmp_id_in)
2316        self.assertEqual(sessions[0].outside_port, self.tcp_port_out)
2317        self.assertEqual(sessions[1].outside_port, self.udp_port_out)
2318        self.assertEqual(sessions[2].outside_port, self.icmp_id_out)
2319
2320        # in2out 3rd interface
2321        pkts = self.create_stream_in(self.pg6, self.pg3)
2322        self.pg6.add_stream(pkts)
2323        self.pg_enable_capture(self.pg_interfaces)
2324        self.pg_start()
2325        capture = self.pg3.get_capture(len(pkts))
2326        self.verify_capture_out(capture, static_nat_ip, True)
2327
2328        # out2in 3rd interface
2329        pkts = self.create_stream_out(self.pg3, static_nat_ip)
2330        self.pg3.add_stream(pkts)
2331        self.pg_enable_capture(self.pg_interfaces)
2332        self.pg_start()
2333        capture = self.pg6.get_capture(len(pkts))
2334        self.verify_capture_in(capture, self.pg6)
2335
2336        # general user and session dump verifications
2337        users = self.vapi.nat44_user_dump()
2338        self.assertGreaterEqual(len(users), 3)
2339        addresses = self.vapi.nat44_address_dump()
2340        self.assertEqual(len(addresses), 1)
2341        for user in users:
2342            sessions = self.vapi.nat44_user_session_dump(user.ip_address,
2343                                                         user.vrf_id)
2344            for session in sessions:
2345                self.assertEqual(user.ip_address, session.inside_ip_address)
2346                self.assertTrue(session.total_bytes > session.total_pkts > 0)
2347                self.assertTrue(session.protocol in
2348                                [IP_PROTOS.tcp, IP_PROTOS.udp,
2349                                 IP_PROTOS.icmp])
2350                self.assertFalse(session.flags &
2351                                 self.config_flags.NAT_IS_EXT_HOST_VALID)
2352
2353        # pg4 session dump
2354        sessions = self.vapi.nat44_user_session_dump(self.pg4.remote_ip4, 10)
2355        self.assertGreaterEqual(len(sessions), 4)
2356        for session in sessions:
2357            self.assertFalse(session.flags & self.config_flags.NAT_IS_STATIC)
2358            self.assertEqual(str(session.inside_ip_address),
2359                             self.pg4.remote_ip4)
2360            self.assertEqual(session.outside_ip_address,
2361                             addresses[0].ip_address)
2362
2363        # pg6 session dump
2364        sessions = self.vapi.nat44_user_session_dump(self.pg6.remote_ip4, 20)
2365        self.assertGreaterEqual(len(sessions), 3)
2366        for session in sessions:
2367            self.assertTrue(session.flags & self.config_flags.NAT_IS_STATIC)
2368            self.assertEqual(str(session.inside_ip_address),
2369                             self.pg6.remote_ip4)
2370            self.assertEqual(str(session.outside_ip_address),
2371                             static_nat_ip)
2372            self.assertTrue(session.inside_port in
2373                            [self.tcp_port_in, self.udp_port_in,
2374                             self.icmp_id_in])
2375
2376    def test_hairpinning(self):
2377        """ NAT44 hairpinning - 1:1 NAPT """
2378
2379        host = self.pg0.remote_hosts[0]
2380        server = self.pg0.remote_hosts[1]
2381        host_in_port = 1234
2382        host_out_port = 0
2383        server_in_port = 5678
2384        server_out_port = 8765
2385
2386        self.nat44_add_address(self.nat_addr)
2387        flags = self.config_flags.NAT_IS_INSIDE
2388        self.vapi.nat44_interface_add_del_feature(
2389            sw_if_index=self.pg0.sw_if_index,
2390            flags=flags, is_add=1)
2391        self.vapi.nat44_interface_add_del_feature(
2392            sw_if_index=self.pg1.sw_if_index,
2393            is_add=1)
2394
2395        # add static mapping for server
2396        self.nat44_add_static_mapping(server.ip4, self.nat_addr,
2397                                      server_in_port, server_out_port,
2398                                      proto=IP_PROTOS.tcp)
2399
2400        # send packet from host to server
2401        p = (Ether(src=host.mac, dst=self.pg0.local_mac) /
2402             IP(src=host.ip4, dst=self.nat_addr) /
2403             TCP(sport=host_in_port, dport=server_out_port))
2404        self.pg0.add_stream(p)
2405        self.pg_enable_capture(self.pg_interfaces)
2406        self.pg_start()
2407        capture = self.pg0.get_capture(1)
2408        p = capture[0]
2409        try:
2410            ip = p[IP]
2411            tcp = p[TCP]
2412            self.assertEqual(ip.src, self.nat_addr)
2413            self.assertEqual(ip.dst, server.ip4)
2414            self.assertNotEqual(tcp.sport, host_in_port)
2415            self.assertEqual(tcp.dport, server_in_port)
2416            self.assert_packet_checksums_valid(p)
2417            host_out_port = tcp.sport
2418        except:
2419            self.logger.error(ppp("Unexpected or invalid packet:", p))
2420            raise
2421
2422        # send reply from server to host
2423        p = (Ether(src=server.mac, dst=self.pg0.local_mac) /
2424             IP(src=server.ip4, dst=self.nat_addr) /
2425             TCP(sport=server_in_port, dport=host_out_port))
2426        self.pg0.add_stream(p)
2427        self.pg_enable_capture(self.pg_interfaces)
2428        self.pg_start()
2429        capture = self.pg0.get_capture(1)
2430        p = capture[0]
2431        try:
2432            ip = p[IP]
2433            tcp = p[TCP]
2434            self.assertEqual(ip.src, self.nat_addr)
2435            self.assertEqual(ip.dst, host.ip4)
2436            self.assertEqual(tcp.sport, server_out_port)
2437            self.assertEqual(tcp.dport, host_in_port)
2438            self.assert_packet_checksums_valid(p)
2439        except:
2440            self.logger.error(ppp("Unexpected or invalid packet:", p))
2441            raise
2442
2443    def test_hairpinning2(self):
2444        """ NAT44 hairpinning - 1:1 NAT"""
2445
2446        server1_nat_ip = "10.0.0.10"
2447        server2_nat_ip = "10.0.0.11"
2448        host = self.pg0.remote_hosts[0]
2449        server1 = self.pg0.remote_hosts[1]
2450        server2 = self.pg0.remote_hosts[2]
2451        server_tcp_port = 22
2452        server_udp_port = 20
2453
2454        self.nat44_add_address(self.nat_addr)
2455        flags = self.config_flags.NAT_IS_INSIDE
2456        self.vapi.nat44_interface_add_del_feature(
2457            sw_if_index=self.pg0.sw_if_index,
2458            flags=flags, is_add=1)
2459        self.vapi.nat44_interface_add_del_feature(
2460            sw_if_index=self.pg1.sw_if_index,
2461            is_add=1)
2462
2463        # add static mapping for servers
2464        self.nat44_add_static_mapping(server1.ip4, server1_nat_ip)
2465        self.nat44_add_static_mapping(server2.ip4, server2_nat_ip)
2466
2467        # host to server1
2468        pkts = []
2469        p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2470             IP(src=host.ip4, dst=server1_nat_ip) /
2471             TCP(sport=self.tcp_port_in, dport=server_tcp_port))
2472        pkts.append(p)
2473        p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2474             IP(src=host.ip4, dst=server1_nat_ip) /
2475             UDP(sport=self.udp_port_in, dport=server_udp_port))
2476        pkts.append(p)
2477        p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2478             IP(src=host.ip4, dst=server1_nat_ip) /
2479             ICMP(id=self.icmp_id_in, type='echo-request'))
2480        pkts.append(p)
2481        self.pg0.add_stream(pkts)
2482        self.pg_enable_capture(self.pg_interfaces)
2483        self.pg_start()
2484        capture = self.pg0.get_capture(len(pkts))
2485        for packet in capture:
2486            try:
2487                self.assertEqual(packet[IP].src, self.nat_addr)
2488                self.assertEqual(packet[IP].dst, server1.ip4)
2489                if packet.haslayer(TCP):
2490                    self.assertNotEqual(packet[TCP].sport, self.tcp_port_in)
2491                    self.assertEqual(packet[TCP].dport, server_tcp_port)
2492                    self.tcp_port_out = packet[TCP].sport
2493                    self.assert_packet_checksums_valid(packet)
2494                elif packet.haslayer(UDP):
2495                    self.assertNotEqual(packet[UDP].sport, self.udp_port_in)
2496                    self.assertEqual(packet[UDP].dport, server_udp_port)
2497                    self.udp_port_out = packet[UDP].sport
2498                else:
2499                    self.assertNotEqual(packet[ICMP].id, self.icmp_id_in)
2500                    self.icmp_id_out = packet[ICMP].id
2501            except:
2502                self.logger.error(ppp("Unexpected or invalid packet:", packet))
2503                raise
2504
2505        # server1 to host
2506        pkts = []
2507        p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2508             IP(src=server1.ip4, dst=self.nat_addr) /
2509             TCP(sport=server_tcp_port, dport=self.tcp_port_out))
2510        pkts.append(p)
2511        p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2512             IP(src=server1.ip4, dst=self.nat_addr) /
2513             UDP(sport=server_udp_port, dport=self.udp_port_out))
2514        pkts.append(p)
2515        p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2516             IP(src=server1.ip4, dst=self.nat_addr) /
2517             ICMP(id=self.icmp_id_out, type='echo-reply'))
2518        pkts.append(p)
2519        self.pg0.add_stream(pkts)
2520        self.pg_enable_capture(self.pg_interfaces)
2521        self.pg_start()
2522        capture = self.pg0.get_capture(len(pkts))
2523        for packet in capture:
2524            try:
2525                self.assertEqual(packet[IP].src, server1_nat_ip)
2526                self.assertEqual(packet[IP].dst, host.ip4)
2527                if packet.haslayer(TCP):
2528                    self.assertEqual(packet[TCP].dport, self.tcp_port_in)
2529                    self.assertEqual(packet[TCP].sport, server_tcp_port)
2530                    self.assert_packet_checksums_valid(packet)
2531                elif packet.haslayer(UDP):
2532                    self.assertEqual(packet[UDP].dport, self.udp_port_in)
2533                    self.assertEqual(packet[UDP].sport, server_udp_port)
2534                else:
2535                    self.assertEqual(packet[ICMP].id, self.icmp_id_in)
2536            except:
2537                self.logger.error(ppp("Unexpected or invalid packet:", packet))
2538                raise
2539
2540        # server2 to server1
2541        pkts = []
2542        p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2543             IP(src=server2.ip4, dst=server1_nat_ip) /
2544             TCP(sport=self.tcp_port_in, dport=server_tcp_port))
2545        pkts.append(p)
2546        p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2547             IP(src=server2.ip4, dst=server1_nat_ip) /
2548             UDP(sport=self.udp_port_in, dport=server_udp_port))
2549        pkts.append(p)
2550        p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2551             IP(src=server2.ip4, dst=server1_nat_ip) /
2552             ICMP(id=self.icmp_id_in, type='echo-request'))
2553        pkts.append(p)
2554        self.pg0.add_stream(pkts)
2555        self.pg_enable_capture(self.pg_interfaces)
2556        self.pg_start()
2557        capture = self.pg0.get_capture(len(pkts))
2558        for packet in capture:
2559            try:
2560                self.assertEqual(packet[IP].src, server2_nat_ip)
2561                self.assertEqual(packet[IP].dst, server1.ip4)
2562                if packet.haslayer(TCP):
2563                    self.assertEqual(packet[TCP].sport, self.tcp_port_in)
2564                    self.assertEqual(packet[TCP].dport, server_tcp_port)
2565                    self.tcp_port_out = packet[TCP].sport
2566                    self.assert_packet_checksums_valid(packet)
2567                elif packet.haslayer(UDP):
2568                    self.assertEqual(packet[UDP].sport, self.udp_port_in)
2569                    self.assertEqual(packet[UDP].dport, server_udp_port)
2570                    self.udp_port_out = packet[UDP].sport
2571                else:
2572                    self.assertEqual(packet[ICMP].id, self.icmp_id_in)
2573                    self.icmp_id_out = packet[ICMP].id
2574            except:
2575                self.logger.error(ppp("Unexpected or invalid packet:", packet))
2576                raise
2577
2578        # server1 to server2
2579        pkts = []
2580        p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2581             IP(src=server1.ip4, dst=server2_nat_ip) /
2582             TCP(sport=server_tcp_port, dport=self.tcp_port_out))
2583        pkts.append(p)
2584        p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2585             IP(src=server1.ip4, dst=server2_nat_ip) /
2586             UDP(sport=server_udp_port, dport=self.udp_port_out))
2587        pkts.append(p)
2588        p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2589             IP(src=server1.ip4, dst=server2_nat_ip) /
2590             ICMP(id=self.icmp_id_out, type='echo-reply'))
2591        pkts.append(p)
2592        self.pg0.add_stream(pkts)
2593        self.pg_enable_capture(self.pg_interfaces)
2594        self.pg_start()
2595        capture = self.pg0.get_capture(len(pkts))
2596        for packet in capture:
2597            try:
2598                self.assertEqual(packet[IP].src, server1_nat_ip)
2599                self.assertEqual(packet[IP].dst, server2.ip4)
2600                if packet.haslayer(TCP):
2601                    self.assertEqual(packet[TCP].dport, self.tcp_port_in)
2602                    self.assertEqual(packet[TCP].sport, server_tcp_port)
2603                    self.assert_packet_checksums_valid(packet)
2604                elif packet.haslayer(UDP):
2605                    self.assertEqual(packet[UDP].dport, self.udp_port_in)
2606                    self.assertEqual(packet[UDP].sport, server_udp_port)
2607                else:
2608                    self.assertEqual(packet[ICMP].id, self.icmp_id_in)
2609            except:
2610                self.logger.error(ppp("Unexpected or invalid packet:", packet))
2611                raise
2612
2613    def test_max_translations_per_user(self):
2614        """ MAX translations per user - recycle the least recently used """
2615
2616        self.nat44_add_address(self.nat_addr)
2617        flags = self.config_flags.NAT_IS_INSIDE
2618        self.vapi.nat44_interface_add_del_feature(
2619            sw_if_index=self.pg0.sw_if_index,
2620            flags=flags, is_add=1)
2621        self.vapi.nat44_interface_add_del_feature(
2622            sw_if_index=self.pg1.sw_if_index,
2623            is_add=1)
2624
2625        # get maximum number of translations per user
2626        nat44_config = self.vapi.nat_show_config()
2627
2628        # send more than maximum number of translations per user packets
2629        pkts_num = nat44_config.max_translations_per_user + 5
2630        pkts = []
2631        for port in range(0, pkts_num):
2632            p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2633                 IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
2634                 TCP(sport=1025 + port))
2635            pkts.append(p)
2636        self.pg0.add_stream(pkts)
2637        self.pg_enable_capture(self.pg_interfaces)
2638        self.pg_start()
2639
2640        # verify number of translated packet
2641        self.pg1.get_capture(pkts_num)
2642
2643        users = self.vapi.nat44_user_dump()
2644        for user in users:
2645            if user.ip_address == self.pg0.remote_ip4:
2646                self.assertEqual(user.nsessions,
2647                                 nat44_config.max_translations_per_user)
2648                self.assertEqual(user.nstaticsessions, 0)
2649
2650        tcp_port = 22
2651        self.nat44_add_static_mapping(self.pg0.remote_ip4, self.nat_addr,
2652                                      tcp_port, tcp_port,
2653                                      proto=IP_PROTOS.tcp)
2654        p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2655             IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
2656             TCP(sport=tcp_port))
2657        self.pg0.add_stream(p)
2658        self.pg_enable_capture(self.pg_interfaces)
2659        self.pg_start()
2660        self.pg1.get_capture(1)
2661        users = self.vapi.nat44_user_dump()
2662        for user in users:
2663            if user.ip_address == self.pg0.remote_ip4:
2664                self.assertEqual(user.nsessions,
2665                                 nat44_config.max_translations_per_user - 1)
2666                self.assertEqual(user.nstaticsessions, 1)
2667
2668    def test_interface_addr(self):
2669        """ Acquire NAT44 addresses from interface """
2670        self.vapi.nat44_add_del_interface_addr(
2671            is_add=1,
2672            sw_if_index=self.pg7.sw_if_index)
2673
2674        # no address in NAT pool
2675        addresses = self.vapi.nat44_address_dump()
2676        self.assertEqual(0, len(addresses))
2677
2678        # configure interface address and check NAT address pool
2679        self.pg7.config_ip4()
2680        addresses = self.vapi.nat44_address_dump()
2681        self.assertEqual(1, len(addresses))
2682        self.assertEqual(str(addresses[0].ip_address), self.pg7.local_ip4)
2683
2684        # remove interface address and check NAT address pool
2685        self.pg7.unconfig_ip4()
2686        addresses = self.vapi.nat44_address_dump()
2687        self.assertEqual(0, len(addresses))
2688
2689    def test_interface_addr_static_mapping(self):
2690        """ Static mapping with addresses from interface """
2691        tag = "testTAG"
2692
2693        self.vapi.nat44_add_del_interface_addr(
2694            is_add=1,
2695            sw_if_index=self.pg7.sw_if_index)
2696        self.nat44_add_static_mapping(
2697            '1.2.3.4',
2698            external_sw_if_index=self.pg7.sw_if_index,
2699            tag=tag)
2700
2701        # static mappings with external interface
2702        static_mappings = self.vapi.nat44_static_mapping_dump()
2703        self.assertEqual(1, len(static_mappings))
2704        self.assertEqual(self.pg7.sw_if_index,
2705                         static_mappings[0].external_sw_if_index)
2706        self.assertEqual(static_mappings[0].tag, tag)
2707
2708        # configure interface address and check static mappings
2709        self.pg7.config_ip4()
2710        static_mappings = self.vapi.nat44_static_mapping_dump()
2711        self.assertEqual(2, len(static_mappings))
2712        resolved = False
2713        for sm in static_mappings:
2714            if sm.external_sw_if_index == 0xFFFFFFFF:
2715                self.assertEqual(str(sm.external_ip_address),
2716                                 self.pg7.local_ip4)
2717                self.assertEqual(sm.tag, tag)
2718                resolved = True
2719        self.assertTrue(resolved)
2720
2721        # remove interface address and check static mappings
2722        self.pg7.unconfig_ip4()
2723        static_mappings = self.vapi.nat44_static_mapping_dump()
2724        self.assertEqual(1, len(static_mappings))
2725        self.assertEqual(self.pg7.sw_if_index,
2726                         static_mappings[0].external_sw_if_index)
2727        self.assertEqual(static_mappings[0].tag, tag)
2728
2729        # configure interface address again and check static mappings
2730        self.pg7.config_ip4()
2731        static_mappings = self.vapi.nat44_static_mapping_dump()
2732        self.assertEqual(2, len(static_mappings))
2733        resolved = False
2734        for sm in static_mappings:
2735            if sm.external_sw_if_index == 0xFFFFFFFF:
2736                self.assertEqual(str(sm.external_ip_address),
2737                                 self.pg7.local_ip4)
2738                self.assertEqual(sm.tag, tag)
2739                resolved = True
2740        self.assertTrue(resolved)
2741
2742        # remove static mapping
2743        self.nat44_add_static_mapping(
2744            '1.2.3.4',
2745            external_sw_if_index=self.pg7.sw_if_index,
2746            tag=tag,
2747            is_add=0)
2748        static_mappings = self.vapi.nat44_static_mapping_dump()
2749        self.assertEqual(0, len(static_mappings))
2750
2751    def test_interface_addr_identity_nat(self):
2752        """ Identity NAT with addresses from interface """
2753
2754        port = 53053
2755        self.vapi.nat44_add_del_interface_addr(
2756            is_add=1,
2757            sw_if_index=self.pg7.sw_if_index)
2758        self.vapi.nat44_add_del_identity_mapping(
2759            ip_address=b'0',
2760            sw_if_index=self.pg7.sw_if_index,
2761            port=port,
2762            protocol=IP_PROTOS.tcp,
2763            is_add=1)
2764
2765        # identity mappings with external interface
2766        identity_mappings = self.vapi.nat44_identity_mapping_dump()
2767        self.assertEqual(1, len(identity_mappings))
2768        self.assertEqual(self.pg7.sw_if_index,
2769                         identity_mappings[0].sw_if_index)
2770
2771        # configure interface address and check identity mappings
2772        self.pg7.config_ip4()
2773        identity_mappings = self.vapi.nat44_identity_mapping_dump()
2774        resolved = False
2775        self.assertEqual(2, len(identity_mappings))
2776        for sm in identity_mappings:
2777            if sm.sw_if_index == 0xFFFFFFFF:
2778                self.assertEqual(str(identity_mappings[0].ip_address),
2779                                 self.pg7.local_ip4)
2780                self.assertEqual(port, identity_mappings[0].port)
2781                self.assertEqual(IP_PROTOS.tcp, identity_mappings[0].protocol)
2782                resolved = True
2783        self.assertTrue(resolved)
2784
2785        # remove interface address and check identity mappings
2786        self.pg7.unconfig_ip4()
2787        identity_mappings = self.vapi.nat44_identity_mapping_dump()
2788        self.assertEqual(1, len(identity_mappings))
2789        self.assertEqual(self.pg7.sw_if_index,
2790                         identity_mappings[0].sw_if_index)
2791
2792    def test_ipfix_nat44_sess(self):
2793        """ IPFIX logging NAT44 session created/deleted """
2794        self.ipfix_domain_id = 10
2795        self.ipfix_src_port = 20202
2796        collector_port = 30303
2797        bind_layers(UDP, IPFIX, dport=30303)
2798        self.nat44_add_address(self.nat_addr)
2799        flags = self.config_flags.NAT_IS_INSIDE
2800        self.vapi.nat44_interface_add_del_feature(
2801            sw_if_index=self.pg0.sw_if_index,
2802            flags=flags, is_add=1)
2803        self.vapi.nat44_interface_add_del_feature(
2804            sw_if_index=self.pg1.sw_if_index,
2805            is_add=1)
2806        self.vapi.set_ipfix_exporter(collector_address=self.pg3.remote_ip4,
2807                                     src_address=self.pg3.local_ip4,
2808                                     path_mtu=512,
2809                                     template_interval=10,
2810                                     collector_port=collector_port)
2811        self.vapi.nat_ipfix_enable_disable(domain_id=self.ipfix_domain_id,
2812                                           src_port=self.ipfix_src_port,
2813                                           enable=1)
2814
2815        pkts = self.create_stream_in(self.pg0, self.pg1)
2816        self.pg0.add_stream(pkts)
2817        self.pg_enable_capture(self.pg_interfaces)
2818        self.pg_start()
2819        capture = self.pg1.get_capture(len(pkts))
2820        self.verify_capture_out(capture)
2821        self.nat44_add_address(self.nat_addr, is_add=0)
2822        self.vapi.ipfix_flush()
2823        capture = self.pg3.get_capture(9)
2824        ipfix = IPFIXDecoder()
2825        # first load template
2826        for p in capture:
2827            self.assertTrue(p.haslayer(IPFIX))
2828            self.assertEqual(p[IP].src, self.pg3.local_ip4)
2829            self.assertEqual(p[IP].dst, self.pg3.remote_ip4)
2830            self.assertEqual(p[UDP].sport, self.ipfix_src_port)
2831            self.assertEqual(p[UDP].dport, collector_port)
2832            self.assertEqual(p[IPFIX].observationDomainID,
2833                             self.ipfix_domain_id)
2834            if p.haslayer(Template):
2835                ipfix.add_template(p.getlayer(Template))
2836        # verify events in data set
2837        for p in capture:
2838            if p.haslayer(Data):
2839                data = ipfix.decode_data_set(p.getlayer(Set))
2840                self.verify_ipfix_nat44_ses(data)
2841
2842    def test_ipfix_addr_exhausted(self):
2843        """ IPFIX logging NAT addresses exhausted """
2844        flags = self.config_flags.NAT_IS_INSIDE
2845        self.vapi.nat44_interface_add_del_feature(
2846            sw_if_index=self.pg0.sw_if_index,
2847            flags=flags, is_add=1)
2848        self.vapi.nat44_interface_add_del_feature(
2849            sw_if_index=self.pg1.sw_if_index,
2850            is_add=1)
2851        self.vapi.set_ipfix_exporter(collector_address=self.pg3.remote_ip4,
2852                                     src_address=self.pg3.local_ip4,
2853                                     path_mtu=512,
2854                                     template_interval=10)
2855        self.vapi.nat_ipfix_enable_disable(domain_id=self.ipfix_domain_id,
2856                                           src_port=self.ipfix_src_port,
2857                                           enable=1)
2858
2859        p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
2860             IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
2861             TCP(sport=3025))
2862        self.pg0.add_stream(p)
2863        self.pg_enable_capture(self.pg_interfaces)
2864        self.pg_start()
2865        self.pg1.assert_nothing_captured()
2866        sleep(1)
2867        self.vapi.ipfix_flush()
2868        capture = self.pg3.get_capture(9)
2869        ipfix = IPFIXDecoder()
2870        # first load template
2871        for p in capture:
2872            self.assertTrue(p.haslayer(IPFIX))
2873            self.assertEqual(p[IP].src, self.pg3.local_ip4)
2874            self.assertEqual(p[IP].dst, self.pg3.remote_ip4)
2875            self.assertEqual(p[UDP].sport, self.ipfix_src_port)
2876            self.assertEqual(p[UDP].dport, 4739)
2877            self.assertEqual(p[IPFIX].observationDomainID,
2878                             self.ipfix_domain_id)
2879            if p.haslayer(Template):
2880                ipfix.add_template(p.getlayer(Template))
2881        # verify events in data set
2882        for p in capture:
2883            if p.haslayer(Data):
2884                data = ipfix.decode_data_set(p.getlayer(Set))
2885                self.verify_ipfix_addr_exhausted(data)
2886
2887    @unittest.skipUnless(running_extended_tests, "part of extended tests")
2888    def test_ipfix_max_sessions(self):
2889        """ IPFIX logging maximum session entries exceeded """
2890        self.nat44_add_address(self.nat_addr)
2891        flags = self.config_flags.NAT_IS_INSIDE
2892        self.vapi.nat44_interface_add_del_feature(
2893            sw_if_index=self.pg0.sw_if_index,
2894            flags=flags, is_add=1)
2895        self.vapi.nat44_interface_add_del_feature(
2896            sw_if_index=self.pg1.sw_if_index,
2897            is_add=1)
2898
2899        nat44_config = self.vapi.nat_show_config()
2900        max_sessions = 10 * nat44_config.translation_buckets
2901
2902        pkts = []
2903        for i in range(0, max_sessions):
2904            src = "10.10.%u.%u" % ((i & 0xFF00) >> 8, i & 0xFF)
2905            p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2906                 IP(src=src, dst=self.pg1.remote_ip4) /
2907                 TCP(sport=1025))
2908            pkts.append(p)
2909        self.pg0.add_stream(pkts)
2910        self.pg_enable_capture(self.pg_interfaces)
2911        self.pg_start()
2912
2913        self.pg1.get_capture(max_sessions)
2914        self.vapi.set_ipfix_exporter(collector_address=self.pg3.remote_ip4,
2915                                     src_address=self.pg3.local_ip4,
2916                                     path_mtu=512,
2917                                     template_interval=10)
2918        self.vapi.nat_ipfix_enable_disable(domain_id=self.ipfix_domain_id,
2919                                           src_port=self.ipfix_src_port,
2920                                           enable=1)
2921
2922        p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2923             IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
2924             TCP(sport=1025))
2925        self.pg0.add_stream(p)
2926        self.pg_enable_capture(self.pg_interfaces)
2927        self.pg_start()
2928        self.pg1.assert_nothing_captured()
2929        sleep(1)
2930        self.vapi.ipfix_flush()
2931        capture = self.pg3.get_capture(9)
2932        ipfix = IPFIXDecoder()
2933        # first load template
2934        for p in capture:
2935            self.assertTrue(p.haslayer(IPFIX))
2936            self.assertEqual(p[IP].src, self.pg3.local_ip4)
2937            self.assertEqual(p[IP].dst, self.pg3.remote_ip4)
2938            self.assertEqual(p[UDP].sport, self.ipfix_src_port)
2939            self.assertEqual(p[UDP].dport, 4739)
2940            self.assertEqual(p[IPFIX].observationDomainID,
2941                             self.ipfix_domain_id)
2942            if p.haslayer(Template):
2943                ipfix.add_template(p.getlayer(Template))
2944        # verify events in data set
2945        for p in capture:
2946            if p.haslayer(Data):
2947                data = ipfix.decode_data_set(p.getlayer(Set))
2948                self.verify_ipfix_max_sessions(data, max_sessions)
2949
2950    def test_syslog_apmap(self):
2951        """ Test syslog address and port mapping creation and deletion """
2952        self.vapi.syslog_set_filter(
2953            self.SYSLOG_SEVERITY.SYSLOG_API_SEVERITY_INFO)
2954        self.vapi.syslog_set_sender(self.pg3.local_ip4, self.pg3.remote_ip4)
2955        self.nat44_add_address(self.nat_addr)
2956        flags = self.config_flags.NAT_IS_INSIDE
2957        self.vapi.nat44_interface_add_del_feature(
2958            sw_if_index=self.pg0.sw_if_index,
2959            flags=flags, is_add=1)
2960        self.vapi.nat44_interface_add_del_feature(
2961            sw_if_index=self.pg1.sw_if_index,
2962            is_add=1)
2963
2964        p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2965             IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
2966             TCP(sport=self.tcp_port_in, dport=20))
2967        self.pg0.add_stream(p)
2968        self.pg_enable_capture(self.pg_interfaces)
2969        self.pg_start()
2970        capture = self.pg1.get_capture(1)
2971        self.tcp_port_out = capture[0][TCP].sport
2972        capture = self.pg3.get_capture(1)
2973        self.verify_syslog_apmap(capture[0][Raw].load)
2974
2975        self.pg_enable_capture(self.pg_interfaces)
2976        self.pg_start()
2977        self.nat44_add_address(self.nat_addr, is_add=0)
2978        capture = self.pg3.get_capture(1)
2979        self.verify_syslog_apmap(capture[0][Raw].load, False)
2980
2981    def test_pool_addr_fib(self):
2982        """ NAT44 add pool addresses to FIB """
2983        static_addr = '10.0.0.10'
2984        self.nat44_add_address(self.nat_addr)
2985        flags = self.config_flags.NAT_IS_INSIDE
2986        self.vapi.nat44_interface_add_del_feature(
2987            sw_if_index=self.pg0.sw_if_index,
2988            flags=flags, is_add=1)
2989        self.vapi.nat44_interface_add_del_feature(
2990            sw_if_index=self.pg1.sw_if_index,
2991            is_add=1)
2992        self.nat44_add_static_mapping(self.pg0.remote_ip4, static_addr)
2993
2994        # NAT44 address
2995        p = (Ether(src=self.pg1.remote_mac, dst='ff:ff:ff:ff:ff:ff') /
2996             ARP(op=ARP.who_has, pdst=self.nat_addr,
2997                 psrc=self.pg1.remote_ip4, hwsrc=self.pg1.remote_mac))
2998        self.pg1.add_stream(p)
2999        self.pg_enable_capture(self.pg_interfaces)
3000        self.pg_start()
3001        capture = self.pg1.get_capture(1)
3002        self.assertTrue(capture[0].haslayer(ARP))
3003        self.assertTrue(capture[0][ARP].op, ARP.is_at)
3004
3005        # 1:1 NAT address
3006        p = (Ether(src=self.pg1.remote_mac, dst='ff:ff:ff:ff:ff:ff') /
3007             ARP(op=ARP.who_has, pdst=static_addr,
3008                 psrc=self.pg1.remote_ip4, hwsrc=self.pg1.remote_mac))
3009        self.pg1.add_stream(p)
3010        self.pg_enable_capture(self.pg_interfaces)
3011        self.pg_start()
3012        capture = self.pg1.get_capture(1)
3013        self.assertTrue(capture[0].haslayer(ARP))
3014        self.assertTrue(capture[0][ARP].op, ARP.is_at)
3015
3016        # send ARP to non-NAT44 interface
3017        p = (Ether(src=self.pg2.remote_mac, dst='ff:ff:ff:ff:ff:ff') /
3018             ARP(op=ARP.who_has, pdst=self.nat_addr,
3019                 psrc=self.pg2.remote_ip4, hwsrc=self.pg2.remote_mac))
3020        self.pg2.add_stream(p)
3021        self.pg_enable_capture(self.pg_interfaces)
3022        self.pg_start()
3023        self.pg1.assert_nothing_captured()
3024
3025        # remove addresses and verify
3026        self.nat44_add_address(self.nat_addr, is_add=0)
3027        self.nat44_add_static_mapping(self.pg0.remote_ip4, static_addr,
3028                                      is_add=0)
3029
3030        p = (Ether(src=self.pg1.remote_mac, dst='ff:ff:ff:ff:ff:ff') /
3031             ARP(op=ARP.who_has, pdst=self.nat_addr,
3032                 psrc=self.pg1.remote_ip4, hwsrc=self.pg1.remote_mac))
3033        self.pg1.add_stream(p)
3034        self.pg_enable_capture(self.pg_interfaces)
3035        self.pg_start()
3036        self.pg1.assert_nothing_captured()
3037
3038        p = (Ether(src=self.pg1.remote_mac, dst='ff:ff:ff:ff:ff:ff') /
3039             ARP(op=ARP.who_has, pdst=static_addr,
3040                 psrc=self.pg1.remote_ip4, hwsrc=self.pg1.remote_mac))
3041        self.pg1.add_stream(p)
3042        self.pg_enable_capture(self.pg_interfaces)
3043        self.pg_start()
3044        self.pg1.assert_nothing_captured()
3045
3046    def test_vrf_mode(self):
3047        """ NAT44 tenant VRF aware address pool mode """
3048
3049        vrf_id1 = 1
3050        vrf_id2 = 2
3051        nat_ip1 = "10.0.0.10"
3052        nat_ip2 = "10.0.0.11"
3053
3054        self.pg0.unconfig_ip4()
3055        self.pg1.unconfig_ip4()
3056        self.vapi.ip_table_add_del(is_add=1, table_id=vrf_id1)
3057        self.vapi.ip_table_add_del(is_add=1, table_id=vrf_id2)
3058        self.pg0.set_table_ip4(vrf_id1)
3059        self.pg1.set_table_ip4(vrf_id2)
3060        self.pg0.config_ip4()
3061        self.pg1.config_ip4()
3062        self.pg0.resolve_arp()
3063        self.pg1.resolve_arp()
3064
3065        self.nat44_add_address(nat_ip1, vrf_id=vrf_id1)
3066        self.nat44_add_address(nat_ip2, vrf_id=vrf_id2)
3067        flags = self.config_flags.NAT_IS_INSIDE
3068        self.vapi.nat44_interface_add_del_feature(
3069            sw_if_index=self.pg0.sw_if_index,
3070            flags=flags, is_add=1)
3071        self.vapi.nat44_interface_add_del_feature(
3072            sw_if_index=self.pg1.sw_if_index,
3073            flags=flags, is_add=1)
3074        self.vapi.nat44_interface_add_del_feature(
3075            sw_if_index=self.pg2.sw_if_index,
3076            is_add=1)
3077
3078        try:
3079            # first VRF
3080            pkts = self.create_stream_in(self.pg0, self.pg2)
3081            self.pg0.add_stream(pkts)
3082            self.pg_enable_capture(self.pg_interfaces)
3083            self.pg_start()
3084            capture = self.pg2.get_capture(len(pkts))
3085            self.verify_capture_out(capture, nat_ip1)
3086
3087            # second VRF
3088            pkts = self.create_stream_in(self.pg1, self.pg2)
3089            self.pg1.add_stream(pkts)
3090            self.pg_enable_capture(self.pg_interfaces)
3091            self.pg_start()
3092            capture = self.pg2.get_capture(len(pkts))
3093            self.verify_capture_out(capture, nat_ip2)
3094
3095        finally:
3096            self.pg0.unconfig_ip4()
3097            self.pg1.unconfig_ip4()
3098            self.pg0.set_table_ip4(0)
3099            self.pg1.set_table_ip4(0)
3100            self.pg0.config_ip4()
3101            self.pg1.config_ip4()
3102            self.pg0.resolve_arp()
3103            self.pg1.resolve_arp()
3104            self.vapi.ip_table_add_del(is_add=0, table_id=vrf_id1)
3105            self.vapi.ip_table_add_del(is_add=0, table_id=vrf_id2)
3106
3107    def test_vrf_feature_independent(self):
3108        """ NAT44 tenant VRF independent address pool mode """
3109
3110        nat_ip1 = "10.0.0.10"
3111        nat_ip2 = "10.0.0.11"
3112
3113        self.nat44_add_address(nat_ip1)
3114        self.nat44_add_address(nat_ip2, vrf_id=99)
3115        flags = self.config_flags.NAT_IS_INSIDE
3116        self.vapi.nat44_interface_add_del_feature(
3117            sw_if_index=self.pg0.sw_if_index,
3118            flags=flags, is_add=1)
3119        self.vapi.nat44_interface_add_del_feature(
3120            sw_if_index=self.pg1.sw_if_index,
3121            flags=flags, is_add=1)
3122        self.vapi.nat44_interface_add_del_feature(
3123            sw_if_index=self.pg2.sw_if_index,
3124            is_add=1)
3125
3126        # first VRF
3127        pkts = self.create_stream_in(self.pg0, self.pg2)
3128        self.pg0.add_stream(pkts)
3129        self.pg_enable_capture(self.pg_interfaces)
3130        self.pg_start()
3131        capture = self.pg2.get_capture(len(pkts))
3132        self.verify_capture_out(capture, nat_ip1)
3133
3134        # second VRF
3135        pkts = self.create_stream_in(self.pg1, self.pg2)
3136        self.pg1.add_stream(pkts)
3137        self.pg_enable_capture(self.pg_interfaces)
3138        self.pg_start()
3139        capture = self.pg2.get_capture(len(pkts))
3140        self.verify_capture_out(capture, nat_ip1)
3141
3142    def create_routes_and_neigbors(self):
3143        r1 = VppIpRoute(self, self.pg7.remote_ip4, 32,
3144                        [VppRoutePath(self.pg7.remote_ip4,
3145                                      self.pg7.sw_if_index)])
3146        r2 = VppIpRoute(self, self.pg8.remote_ip4, 32,
3147                        [VppRoutePath(self.pg8.remote_ip4,
3148                                      self.pg8.sw_if_index)])
3149        r1.add_vpp_config()
3150        r2.add_vpp_config()
3151
3152        n1 = VppNeighbor(self,
3153                         self.pg7.sw_if_index,
3154                         self.pg7.remote_mac,
3155                         self.pg7.remote_ip4,
3156                         is_static=1)
3157        n2 = VppNeighbor(self,
3158                         self.pg8.sw_if_index,
3159                         self.pg8.remote_mac,
3160                         self.pg8.remote_ip4,
3161                         is_static=1)
3162        n1.add_vpp_config()
3163        n2.add_vpp_config()
3164
3165    def test_dynamic_ipless_interfaces(self):
3166        """ NAT44 interfaces without configured IP address """
3167        self.create_routes_and_neigbors()
3168        self.nat44_add_address(self.nat_addr)
3169        flags = self.config_flags.NAT_IS_INSIDE
3170        self.vapi.nat44_interface_add_del_feature(
3171            sw_if_index=self.pg7.sw_if_index,
3172            flags=flags, is_add=1)
3173        self.vapi.nat44_interface_add_del_feature(
3174            sw_if_index=self.pg8.sw_if_index,
3175            is_add=1)
3176
3177        # in2out
3178        pkts = self.create_stream_in(self.pg7, self.pg8)
3179        self.pg7.add_stream(pkts)
3180        self.pg_enable_capture(self.pg_interfaces)
3181        self.pg_start()
3182        capture = self.pg8.get_capture(len(pkts))
3183        self.verify_capture_out(capture)
3184
3185        # out2in
3186        pkts = self.create_stream_out(self.pg8, self.nat_addr)
3187        self.pg8.add_stream(pkts)
3188        self.pg_enable_capture(self.pg_interfaces)
3189        self.pg_start()
3190        capture = self.pg7.get_capture(len(pkts))
3191        self.verify_capture_in(capture, self.pg7)
3192
3193    def test_static_ipless_interfaces(self):
3194        """ NAT44 interfaces without configured IP address - 1:1 NAT """
3195
3196        self.create_routes_and_neigbors()
3197        self.nat44_add_static_mapping(self.pg7.remote_ip4, self.nat_addr)
3198        flags = self.config_flags.NAT_IS_INSIDE
3199        self.vapi.nat44_interface_add_del_feature(
3200            sw_if_index=self.pg7.sw_if_index,
3201            flags=flags, is_add=1)
3202        self.vapi.nat44_interface_add_del_feature(
3203            sw_if_index=self.pg8.sw_if_index,
3204            is_add=1)
3205
3206        # out2in
3207        pkts = self.create_stream_out(self.pg8)
3208        self.pg8.add_stream(pkts)
3209        self.pg_enable_capture(self.pg_interfaces)
3210        self.pg_start()
3211        capture = self.pg7.get_capture(len(pkts))
3212        self.verify_capture_in(capture, self.pg7)
3213
3214        # in2out
3215        pkts = self.create_stream_in(self.pg7, self.pg8)
3216        self.pg7.add_stream(pkts)
3217        self.pg_enable_capture(self.pg_interfaces)
3218        self.pg_start()
3219        capture = self.pg8.get_capture(len(pkts))
3220        self.verify_capture_out(capture, self.nat_addr, True)
3221
3222    def test_static_with_port_ipless_interfaces(self):
3223        """ NAT44 interfaces without configured IP address - 1:1 NAPT """
3224
3225        self.tcp_port_out = 30606
3226        self.udp_port_out = 30607
3227        self.icmp_id_out = 30608
3228
3229        self.create_routes_and_neigbors()
3230        self.nat44_add_address(self.nat_addr)
3231        self.nat44_add_static_mapping(self.pg7.remote_ip4, self.nat_addr,
3232                                      self.tcp_port_in, self.tcp_port_out,
3233                                      proto=IP_PROTOS.tcp)
3234        self.nat44_add_static_mapping(self.pg7.remote_ip4, self.nat_addr,
3235                                      self.udp_port_in, self.udp_port_out,
3236                                      proto=IP_PROTOS.udp)
3237        self.nat44_add_static_mapping(self.pg7.remote_ip4, self.nat_addr,
3238                                      self.icmp_id_in, self.icmp_id_out,
3239                                      proto=IP_PROTOS.icmp)
3240        flags = self.config_flags.NAT_IS_INSIDE
3241        self.vapi.nat44_interface_add_del_feature(
3242            sw_if_index=self.pg7.sw_if_index,
3243            flags=flags, is_add=1)
3244        self.vapi.nat44_interface_add_del_feature(
3245            sw_if_index=self.pg8.sw_if_index,
3246            is_add=1)
3247
3248        # out2in
3249        pkts = self.create_stream_out(self.pg8)
3250        self.pg8.add_stream(pkts)
3251        self.pg_enable_capture(self.pg_interfaces)
3252        self.pg_start()
3253        capture = self.pg7.get_capture(len(pkts))
3254        self.verify_capture_in(capture, self.pg7)
3255
3256        # in2out
3257        pkts = self.create_stream_in(self.pg7, self.pg8)
3258        self.pg7.add_stream(pkts)
3259        self.pg_enable_capture(self.pg_interfaces)
3260        self.pg_start()
3261        capture = self.pg8.get_capture(len(pkts))
3262        self.verify_capture_out(capture)
3263
3264    def test_static_unknown_proto(self):
3265        """ 1:1 NAT translate packet with unknown protocol """
3266        nat_ip = "10.0.0.10"
3267        self.nat44_add_static_mapping(self.pg0.remote_ip4, nat_ip)
3268        flags = self.config_flags.NAT_IS_INSIDE
3269        self.vapi.nat44_interface_add_del_feature(
3270            sw_if_index=self.pg0.sw_if_index,
3271            flags=flags, is_add=1)
3272        self.vapi.nat44_interface_add_del_feature(
3273            sw_if_index=self.pg1.sw_if_index,
3274            is_add=1)
3275
3276        # in2out
3277        p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
3278             IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3279             GRE() /
3280             IP(src=self.pg2.remote_ip4, dst=self.pg3.remote_ip4) /
3281             TCP(sport=1234, dport=1234))
3282        self.pg0.add_stream(p)
3283        self.pg_enable_capture(self.pg_interfaces)
3284        self.pg_start()
3285        p = self.pg1.get_capture(1)
3286        packet = p[0]
3287        try:
3288            self.assertEqual(packet[IP].src, nat_ip)
3289            self.assertEqual(packet[IP].dst, self.pg1.remote_ip4)
3290            self.assertEqual(packet.haslayer(GRE), 1)
3291            self.assert_packet_checksums_valid(packet)
3292        except:
3293            self.logger.error(ppp("Unexpected or invalid packet:", packet))
3294            raise
3295
3296        # out2in
3297        p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
3298             IP(src=self.pg1.remote_ip4, dst=nat_ip) /
3299             GRE() /
3300             IP(src=self.pg3.remote_ip4, dst=self.pg2.remote_ip4) /
3301             TCP(sport=1234, dport=1234))
3302        self.pg1.add_stream(p)
3303        self.pg_enable_capture(self.pg_interfaces)
3304        self.pg_start()
3305        p = self.pg0.get_capture(1)
3306        packet = p[0]
3307        try:
3308            self.assertEqual(packet[IP].src, self.pg1.remote_ip4)
3309            self.assertEqual(packet[IP].dst, self.pg0.remote_ip4)
3310            self.assertEqual(packet.haslayer(GRE), 1)
3311            self.assert_packet_checksums_valid(packet)
3312        except:
3313            self.logger.error(ppp("Unexpected or invalid packet:", packet))
3314            raise
3315
3316    def test_hairpinning_static_unknown_proto(self):
3317        """ 1:1 NAT translate packet with unknown protocol - hairpinning """
3318
3319        host = self.pg0.remote_hosts[0]
3320        server = self.pg0.remote_hosts[1]
3321
3322        host_nat_ip = "10.0.0.10"
3323        server_nat_ip = "10.0.0.11"
3324
3325        self.nat44_add_static_mapping(host.ip4, host_nat_ip)
3326        self.nat44_add_static_mapping(server.ip4, server_nat_ip)
3327        flags = self.config_flags.NAT_IS_INSIDE
3328        self.vapi.nat44_interface_add_del_feature(
3329            sw_if_index=self.pg0.sw_if_index,
3330            flags=flags, is_add=1)
3331        self.vapi.nat44_interface_add_del_feature(
3332            sw_if_index=self.pg1.sw_if_index,
3333            is_add=1)
3334
3335        # host to server
3336        p = (Ether(dst=self.pg0.local_mac, src=host.mac) /
3337             IP(src=host.ip4, dst=server_nat_ip) /
3338             GRE() /
3339             IP(src=self.pg2.remote_ip4, dst=self.pg3.remote_ip4) /
3340             TCP(sport=1234, dport=1234))
3341        self.pg0.add_stream(p)
3342        self.pg_enable_capture(self.pg_interfaces)
3343        self.pg_start()
3344        p = self.pg0.get_capture(1)
3345        packet = p[0]
3346        try:
3347            self.assertEqual(packet[IP].src, host_nat_ip)
3348            self.assertEqual(packet[IP].dst, server.ip4)
3349            self.assertEqual(packet.haslayer(GRE), 1)
3350            self.assert_packet_checksums_valid(packet)
3351        except:
3352            self.logger.error(ppp("Unexpected or invalid packet:", packet))
3353            raise
3354
3355        # server to host
3356        p = (Ether(dst=self.pg0.local_mac, src=server.mac) /
3357             IP(src=server.ip4, dst=host_nat_ip) /
3358             GRE() /
3359             IP(src=self.pg3.remote_ip4, dst=self.pg2.remote_ip4) /
3360             TCP(sport=1234, dport=1234))
3361        self.pg0.add_stream(p)
3362        self.pg_enable_capture(self.pg_interfaces)
3363        self.pg_start()
3364        p = self.pg0.get_capture(1)
3365        packet = p[0]
3366        try:
3367            self.assertEqual(packet[IP].src, server_nat_ip)
3368            self.assertEqual(packet[IP].dst, host.ip4)
3369            self.assertEqual(packet.haslayer(GRE), 1)
3370            self.assert_packet_checksums_valid(packet)
3371        except:
3372            self.logger.error(ppp("Unexpected or invalid packet:", packet))
3373            raise
3374
3375    def test_output_feature(self):
3376        """ NAT44 interface output feature (in2out postrouting) """
3377        self.nat44_add_address(self.nat_addr)
3378        flags = self.config_flags.NAT_IS_INSIDE
3379        self.vapi.nat44_interface_add_del_output_feature(
3380            is_add=1, flags=flags,
3381            sw_if_index=self.pg0.sw_if_index)
3382        self.vapi.nat44_interface_add_del_output_feature(
3383            is_add=1, flags=flags,
3384            sw_if_index=self.pg1.sw_if_index)
3385        self.vapi.nat44_interface_add_del_output_feature(
3386            is_add=1,
3387            sw_if_index=self.pg3.sw_if_index)
3388
3389        # in2out
3390        pkts = self.create_stream_in(self.pg0, self.pg3)
3391        self.pg0.add_stream(pkts)
3392        self.pg_enable_capture(self.pg_interfaces)
3393        self.pg_start()
3394        capture = self.pg3.get_capture(len(pkts))
3395        self.verify_capture_out(capture)
3396
3397        # out2in
3398        pkts = self.create_stream_out(self.pg3)
3399        self.pg3.add_stream(pkts)
3400        self.pg_enable_capture(self.pg_interfaces)
3401        self.pg_start()
3402        capture = self.pg0.get_capture(len(pkts))
3403        self.verify_capture_in(capture, self.pg0)
3404
3405        # from non-NAT interface to NAT inside interface
3406        pkts = self.create_stream_in(self.pg2, self.pg0)
3407        self.pg2.add_stream(pkts)
3408        self.pg_enable_capture(self.pg_interfaces)
3409        self.pg_start()
3410        capture = self.pg0.get_capture(len(pkts))
3411        self.verify_capture_no_translation(capture, self.pg2, self.pg0)
3412
3413    def test_output_feature_vrf_aware(self):
3414        """ NAT44 interface output feature VRF aware (in2out postrouting) """
3415        nat_ip_vrf10 = "10.0.0.10"
3416        nat_ip_vrf20 = "10.0.0.20"
3417
3418        r1 = VppIpRoute(self, self.pg3.remote_ip4, 32,
3419                        [VppRoutePath(self.pg3.remote_ip4,
3420                                      self.pg3.sw_if_index)],
3421                        table_id=10)
3422        r2 = VppIpRoute(self, self.pg3.remote_ip4, 32,
3423                        [VppRoutePath(self.pg3.remote_ip4,
3424                                      self.pg3.sw_if_index)],
3425                        table_id=20)
3426        r1.add_vpp_config()
3427        r2.add_vpp_config()
3428
3429        self.nat44_add_address(nat_ip_vrf10, vrf_id=10)
3430        self.nat44_add_address(nat_ip_vrf20, vrf_id=20)
3431        flags = self.config_flags.NAT_IS_INSIDE
3432        self.vapi.nat44_interface_add_del_output_feature(
3433            is_add=1, flags=flags,
3434            sw_if_index=self.pg4.sw_if_index)
3435        self.vapi.nat44_interface_add_del_output_feature(
3436            is_add=1, flags=flags,
3437            sw_if_index=self.pg6.sw_if_index)
3438        self.vapi.nat44_interface_add_del_output_feature(
3439            is_add=1,
3440            sw_if_index=self.pg3.sw_if_index)
3441
3442        # in2out VRF 10
3443        pkts = self.create_stream_in(self.pg4, self.pg3)
3444        self.pg4.add_stream(pkts)
3445        self.pg_enable_capture(self.pg_interfaces)
3446        self.pg_start()
3447        capture = self.pg3.get_capture(len(pkts))
3448        self.verify_capture_out(capture, nat_ip=nat_ip_vrf10)
3449
3450        # out2in VRF 10
3451        pkts = self.create_stream_out(self.pg3, dst_ip=nat_ip_vrf10)
3452        self.pg3.add_stream(pkts)
3453        self.pg_enable_capture(self.pg_interfaces)
3454        self.pg_start()
3455        capture = self.pg4.get_capture(len(pkts))
3456        self.verify_capture_in(capture, self.pg4)
3457
3458        # in2out VRF 20
3459        pkts = self.create_stream_in(self.pg6, self.pg3)
3460        self.pg6.add_stream(pkts)
3461        self.pg_enable_capture(self.pg_interfaces)
3462        self.pg_start()
3463        capture = self.pg3.get_capture(len(pkts))
3464        self.verify_capture_out(capture, nat_ip=nat_ip_vrf20)
3465
3466        # out2in VRF 20
3467        pkts = self.create_stream_out(self.pg3, dst_ip=nat_ip_vrf20)
3468        self.pg3.add_stream(pkts)
3469        self.pg_enable_capture(self.pg_interfaces)
3470        self.pg_start()
3471        capture = self.pg6.get_capture(len(pkts))
3472        self.verify_capture_in(capture, self.pg6)
3473
3474    def test_output_feature_hairpinning(self):
3475        """ NAT44 interface output feature hairpinning (in2out postrouting) """
3476        host = self.pg0.remote_hosts[0]
3477        server = self.pg0.remote_hosts[1]
3478        host_in_port = 1234
3479        host_out_port = 0
3480        server_in_port = 5678
3481        server_out_port = 8765
3482
3483        self.nat44_add_address(self.nat_addr)
3484        flags = self.config_flags.NAT_IS_INSIDE
3485        self.vapi.nat44_interface_add_del_output_feature(
3486            is_add=1, flags=flags,
3487            sw_if_index=self.pg0.sw_if_index)
3488        self.vapi.nat44_interface_add_del_output_feature(
3489            is_add=1,
3490            sw_if_index=self.pg1.sw_if_index)
3491
3492        # add static mapping for server
3493        self.nat44_add_static_mapping(server.ip4, self.nat_addr,
3494                                      server_in_port, server_out_port,
3495                                      proto=IP_PROTOS.tcp)
3496
3497        # send packet from host to server
3498        p = (Ether(src=host.mac, dst=self.pg0.local_mac) /
3499             IP(src=host.ip4, dst=self.nat_addr) /
3500             TCP(sport=host_in_port, dport=server_out_port))
3501        self.pg0.add_stream(p)
3502        self.pg_enable_capture(self.pg_interfaces)
3503        self.pg_start()
3504        capture = self.pg0.get_capture(1)
3505        p = capture[0]
3506        try:
3507            ip = p[IP]
3508            tcp = p[TCP]
3509            self.assertEqual(ip.src, self.nat_addr)
3510            self.assertEqual(ip.dst, server.ip4)
3511            self.assertNotEqual(tcp.sport, host_in_port)
3512            self.assertEqual(tcp.dport, server_in_port)
3513            self.assert_packet_checksums_valid(p)
3514            host_out_port = tcp.sport
3515        except:
3516            self.logger.error(ppp("Unexpected or invalid packet:", p))
3517            raise
3518
3519        # send reply from server to host
3520        p = (Ether(src=server.mac, dst=self.pg0.local_mac) /
3521             IP(src=server.ip4, dst=self.nat_addr) /
3522             TCP(sport=server_in_port, dport=host_out_port))
3523        self.pg0.add_stream(p)
3524        self.pg_enable_capture(self.pg_interfaces)
3525        self.pg_start()
3526        capture = self.pg0.get_capture(1)
3527        p = capture[0]
3528        try:
3529            ip = p[IP]
3530            tcp = p[TCP]
3531            self.assertEqual(ip.src, self.nat_addr)
3532            self.assertEqual(ip.dst, host.ip4)
3533            self.assertEqual(tcp.sport, server_out_port)
3534            self.assertEqual(tcp.dport, host_in_port)
3535            self.assert_packet_checksums_valid(p)
3536        except:
3537            self.logger.error(ppp("Unexpected or invalid packet:", p))
3538            raise
3539
3540    def test_one_armed_nat44(self):
3541        """ One armed NAT44 """
3542        remote_host = self.pg9.remote_hosts[0]
3543        local_host = self.pg9.remote_hosts[1]
3544        external_port = 0
3545
3546        self.nat44_add_address(self.nat_addr)
3547        flags = self.config_flags.NAT_IS_INSIDE
3548        self.vapi.nat44_interface_add_del_feature(
3549            sw_if_index=self.pg9.sw_if_index,
3550            is_add=1)
3551        self.vapi.nat44_interface_add_del_feature(
3552            sw_if_index=self.pg9.sw_if_index,
3553            flags=flags, is_add=1)
3554
3555        # in2out
3556        p = (Ether(src=self.pg9.remote_mac, dst=self.pg9.local_mac) /
3557             IP(src=local_host.ip4, dst=remote_host.ip4) /
3558             TCP(sport=12345, dport=80))
3559        self.pg9.add_stream(p)
3560        self.pg_enable_capture(self.pg_interfaces)
3561        self.pg_start()
3562        capture = self.pg9.get_capture(1)
3563        p = capture[0]
3564        try:
3565            ip = p[IP]
3566            tcp = p[TCP]
3567            self.assertEqual(ip.src, self.nat_addr)
3568            self.assertEqual(ip.dst, remote_host.ip4)
3569            self.assertNotEqual(tcp.sport, 12345)
3570            external_port = tcp.sport
3571            self.assertEqual(tcp.dport, 80)
3572            self.assert_packet_checksums_valid(p)
3573        except:
3574            self.logger.error(ppp("Unexpected or invalid packet:", p))
3575            raise
3576
3577        # out2in
3578        p = (Ether(src=self.pg9.remote_mac, dst=self.pg9.local_mac) /
3579             IP(src=remote_host.ip4, dst=self.nat_addr) /
3580             TCP(sport=80, dport=external_port))
3581        self.pg9.add_stream(p)
3582        self.pg_enable_capture(self.pg_interfaces)
3583        self.pg_start()
3584        capture = self.pg9.get_capture(1)
3585        p = capture[0]
3586        try:
3587            ip = p[IP]
3588            tcp = p[TCP]
3589            self.assertEqual(ip.src, remote_host.ip4)
3590            self.assertEqual(ip.dst, local_host.ip4)
3591            self.assertEqual(tcp.sport, 80)
3592            self.assertEqual(tcp.dport, 12345)
3593            self.assert_packet_checksums_valid(p)
3594        except:
3595            self.logger.error(ppp("Unexpected or invalid packet:", p))
3596            raise
3597
3598        err = self.statistics.get_err_counter(
3599            '/err/nat44-classify/next in2out')
3600        self.assertEqual(err, 1)
3601        err = self.statistics.get_err_counter(
3602            '/err/nat44-classify/next out2in')
3603        self.assertEqual(err, 1)
3604
3605    def test_del_session(self):
3606        """ Delete NAT44 session """
3607        self.nat44_add_address(self.nat_addr)
3608        flags = self.config_flags.NAT_IS_INSIDE
3609        self.vapi.nat44_interface_add_del_feature(
3610            sw_if_index=self.pg0.sw_if_index,
3611            flags=flags, is_add=1)
3612        self.vapi.nat44_interface_add_del_feature(
3613            sw_if_index=self.pg1.sw_if_index,
3614            is_add=1)
3615
3616        pkts = self.create_stream_in(self.pg0, self.pg1)
3617        self.pg0.add_stream(pkts)
3618        self.pg_enable_capture(self.pg_interfaces)
3619        self.pg_start()
3620        self.pg1.get_capture(len(pkts))
3621
3622        sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
3623        nsessions = len(sessions)
3624
3625        self.vapi.nat44_del_session(address=sessions[0].inside_ip_address,
3626                                    port=sessions[0].inside_port,
3627                                    protocol=sessions[0].protocol,
3628                                    flags=self.config_flags.NAT_IS_INSIDE)
3629        self.vapi.nat44_del_session(address=sessions[1].outside_ip_address,
3630                                    port=sessions[1].outside_port,
3631                                    protocol=sessions[1].protocol)
3632
3633        sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
3634        self.assertEqual(nsessions - len(sessions), 2)
3635
3636        self.vapi.nat44_del_session(address=sessions[0].inside_ip_address,
3637                                    port=sessions[0].inside_port,
3638                                    protocol=sessions[0].protocol,
3639                                    flags=self.config_flags.NAT_IS_INSIDE)
3640
3641        self.verify_no_nat44_user()
3642
3643    def test_set_get_reass(self):
3644        """ NAT44 set/get virtual fragmentation reassembly """
3645        reas_cfg1 = self.vapi.nat_get_reass()
3646
3647        self.vapi.nat_set_reass(timeout=reas_cfg1.ip4_timeout + 5,
3648                                max_reass=reas_cfg1.ip4_max_reass * 2,
3649                                max_frag=reas_cfg1.ip4_max_frag * 2,
3650                                drop_frag=0)
3651
3652        reas_cfg2 = self.vapi.nat_get_reass()
3653
3654        self.assertEqual(reas_cfg1.ip4_timeout + 5, reas_cfg2.ip4_timeout)
3655        self.assertEqual(reas_cfg1.ip4_max_reass * 2, reas_cfg2.ip4_max_reass)
3656        self.assertEqual(reas_cfg1.ip4_max_frag * 2, reas_cfg2.ip4_max_frag)
3657
3658        self.vapi.nat_set_reass(timeout=2, max_reass=1024, max_frag=5,
3659                                drop_frag=1)
3660        self.assertTrue(self.vapi.nat_get_reass().ip4_drop_frag)
3661
3662    def test_frag_in_order(self):
3663        """ NAT44 translate fragments arriving in order """
3664
3665        self.nat44_add_address(self.nat_addr)
3666        flags = self.config_flags.NAT_IS_INSIDE
3667        self.vapi.nat44_interface_add_del_feature(
3668            sw_if_index=self.pg0.sw_if_index,
3669            flags=flags, is_add=1)
3670        self.vapi.nat44_interface_add_del_feature(
3671            sw_if_index=self.pg1.sw_if_index,
3672            is_add=1)
3673
3674        reas_cfg1 = self.vapi.nat_get_reass()
3675        # this test was intermittently failing in some cases
3676        # until we temporarily bump the reassembly timeouts
3677        self.vapi.nat_set_reass(timeout=20, max_reass=1024, max_frag=5,
3678                                drop_frag=0)
3679
3680        self.frag_in_order(proto=IP_PROTOS.tcp)
3681        self.frag_in_order(proto=IP_PROTOS.udp)
3682        self.frag_in_order(proto=IP_PROTOS.icmp)
3683
3684        # restore the reassembly timeouts
3685        self.vapi.nat_set_reass(timeout=reas_cfg1.ip4_timeout,
3686                                max_reass=reas_cfg1.ip4_max_reass,
3687                                max_frag=reas_cfg1.ip4_max_frag,
3688                                drop_frag=reas_cfg1.ip4_drop_frag)
3689
3690    def test_frag_forwarding(self):
3691        """ NAT44 forwarding fragment test """
3692        self.vapi.nat44_add_del_interface_addr(
3693            is_add=1,
3694            sw_if_index=self.pg1.sw_if_index)
3695        flags = self.config_flags.NAT_IS_INSIDE
3696        self.vapi.nat44_interface_add_del_feature(
3697            sw_if_index=self.pg0.sw_if_index,
3698            flags=flags, is_add=1)
3699        self.vapi.nat44_interface_add_del_feature(
3700            sw_if_index=self.pg1.sw_if_index,
3701            is_add=1)
3702        self.vapi.nat44_forwarding_enable_disable(enable=1)
3703
3704        data = b"A" * 16 + b"B" * 16 + b"C" * 3
3705        pkts = self.create_stream_frag(self.pg1,
3706                                       self.pg0.remote_ip4,
3707                                       4789,
3708                                       4789,
3709                                       data,
3710                                       proto=IP_PROTOS.udp)
3711        self.pg1.add_stream(pkts)
3712        self.pg_enable_capture(self.pg_interfaces)
3713        self.pg_start()
3714        frags = self.pg0.get_capture(len(pkts))
3715        p = self.reass_frags_and_verify(frags,
3716                                        self.pg1.remote_ip4,
3717                                        self.pg0.remote_ip4)
3718        self.assertEqual(p[UDP].sport, 4789)
3719        self.assertEqual(p[UDP].dport, 4789)
3720        self.assertEqual(data, p[Raw].load)
3721
3722    def test_reass_hairpinning(self):
3723        """ NAT44 fragments hairpinning """
3724
3725        self.server = self.pg0.remote_hosts[1]
3726        self.host_in_port = random.randint(1025, 65535)
3727        self.server_in_port = random.randint(1025, 65535)
3728        self.server_out_port = random.randint(1025, 65535)
3729
3730        self.nat44_add_address(self.nat_addr)
3731        flags = self.config_flags.NAT_IS_INSIDE
3732        self.vapi.nat44_interface_add_del_feature(
3733            sw_if_index=self.pg0.sw_if_index,
3734            flags=flags, is_add=1)
3735        self.vapi.nat44_interface_add_del_feature(
3736            sw_if_index=self.pg1.sw_if_index,
3737            is_add=1)
3738        # add static mapping for server
3739        self.nat44_add_static_mapping(self.server.ip4, self.nat_addr,
3740                                      self.server_in_port,
3741                                      self.server_out_port,
3742                                      proto=IP_PROTOS.tcp)
3743        self.nat44_add_static_mapping(self.server.ip4, self.nat_addr,
3744                                      self.server_in_port,
3745                                      self.server_out_port,
3746                                      proto=IP_PROTOS.udp)
3747        self.nat44_add_static_mapping(self.server.ip4, self.nat_addr)
3748
3749        self.reass_hairpinning(proto=IP_PROTOS.tcp)
3750        self.reass_hairpinning(proto=IP_PROTOS.udp)
3751        self.reass_hairpinning(proto=IP_PROTOS.icmp)
3752
3753    def test_frag_out_of_order(self):
3754        """ NAT44 translate fragments arriving out of order """
3755
3756        self.nat44_add_address(self.nat_addr)
3757        flags = self.config_flags.NAT_IS_INSIDE
3758        self.vapi.nat44_interface_add_del_feature(
3759            sw_if_index=self.pg0.sw_if_index,
3760            flags=flags, is_add=1)
3761        self.vapi.nat44_interface_add_del_feature(
3762            sw_if_index=self.pg1.sw_if_index,
3763            is_add=1)
3764
3765        self.frag_out_of_order(proto=IP_PROTOS.tcp)
3766        self.frag_out_of_order(proto=IP_PROTOS.udp)
3767        self.frag_out_of_order(proto=IP_PROTOS.icmp)
3768
3769    def test_port_restricted(self):
3770        """ Port restricted NAT44 (MAP-E CE) """
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        self.vapi.nat_set_addr_and_port_alloc_alg(alg=1,
3780                                                  psid_offset=6,
3781                                                  psid_length=6,
3782                                                  psid=10)
3783
3784        p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
3785             IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3786             TCP(sport=4567, dport=22))
3787        self.pg0.add_stream(p)
3788        self.pg_enable_capture(self.pg_interfaces)
3789        self.pg_start()
3790        capture = self.pg1.get_capture(1)
3791        p = capture[0]
3792        try:
3793            ip = p[IP]
3794            tcp = p[TCP]
3795            self.assertEqual(ip.dst, self.pg1.remote_ip4)
3796            self.assertEqual(ip.src, self.nat_addr)
3797            self.assertEqual(tcp.dport, 22)
3798            self.assertNotEqual(tcp.sport, 4567)
3799            self.assertEqual((tcp.sport >> 6) & 63, 10)
3800            self.assert_packet_checksums_valid(p)
3801        except:
3802            self.logger.error(ppp("Unexpected or invalid packet:", p))
3803            raise
3804
3805    def test_port_range(self):
3806        """ External address port range """
3807        self.nat44_add_address(self.nat_addr)
3808        flags = self.config_flags.NAT_IS_INSIDE
3809        self.vapi.nat44_interface_add_del_feature(
3810            sw_if_index=self.pg0.sw_if_index,
3811            flags=flags, is_add=1)
3812        self.vapi.nat44_interface_add_del_feature(
3813            sw_if_index=self.pg1.sw_if_index,
3814            is_add=1)
3815        self.vapi.nat_set_addr_and_port_alloc_alg(alg=2,
3816                                                  start_port=1025,
3817                                                  end_port=1027)
3818
3819        pkts = []
3820        for port in range(0, 5):
3821            p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
3822                 IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3823                 TCP(sport=1125 + port))
3824            pkts.append(p)
3825        self.pg0.add_stream(pkts)
3826        self.pg_enable_capture(self.pg_interfaces)
3827        self.pg_start()
3828        capture = self.pg1.get_capture(3)
3829        for p in capture:
3830            tcp = p[TCP]
3831            self.assertGreaterEqual(tcp.sport, 1025)
3832            self.assertLessEqual(tcp.sport, 1027)
3833
3834    def test_ipfix_max_frags(self):
3835        """ IPFIX logging maximum fragments pending reassembly exceeded """
3836        self.nat44_add_address(self.nat_addr)
3837        flags = self.config_flags.NAT_IS_INSIDE
3838        self.vapi.nat44_interface_add_del_feature(
3839            sw_if_index=self.pg0.sw_if_index,
3840            flags=flags, is_add=1)
3841        self.vapi.nat44_interface_add_del_feature(
3842            sw_if_index=self.pg1.sw_if_index,
3843            is_add=1)
3844        self.vapi.nat_set_reass(timeout=2, max_reass=1024, max_frag=1,
3845                                drop_frag=0)
3846        self.vapi.set_ipfix_exporter(collector_address=self.pg3.remote_ip4,
3847                                     src_address=self.pg3.local_ip4,
3848                                     path_mtu=512,
3849                                     template_interval=10)
3850        self.vapi.nat_ipfix_enable_disable(domain_id=self.ipfix_domain_id,
3851                                           src_port=self.ipfix_src_port,
3852                                           enable=1)
3853
3854        data = b"A" * 4 + b"B" * 16 + b"C" * 3
3855        self.tcp_port_in = random.randint(1025, 65535)
3856        pkts = self.create_stream_frag(self.pg0,
3857                                       self.pg1.remote_ip4,
3858                                       self.tcp_port_in,
3859                                       20,
3860                                       data)
3861        pkts.reverse()
3862        self.pg0.add_stream(pkts)
3863        self.pg_enable_capture(self.pg_interfaces)
3864        self.pg_start()
3865        self.pg1.assert_nothing_captured()
3866        sleep(1)
3867        self.vapi.ipfix_flush()
3868        capture = self.pg3.get_capture(9)
3869        ipfix = IPFIXDecoder()
3870        # first load template
3871        for p in capture:
3872            self.assertTrue(p.haslayer(IPFIX))
3873            self.assertEqual(p[IP].src, self.pg3.local_ip4)
3874            self.assertEqual(p[IP].dst, self.pg3.remote_ip4)
3875            self.assertEqual(p[UDP].sport, self.ipfix_src_port)
3876            self.assertEqual(p[UDP].dport, 4739)
3877            self.assertEqual(p[IPFIX].observationDomainID,
3878                             self.ipfix_domain_id)
3879            if p.haslayer(Template):
3880                ipfix.add_template(p.getlayer(Template))
3881        # verify events in data set
3882        for p in capture:
3883            if p.haslayer(Data):
3884                data = ipfix.decode_data_set(p.getlayer(Set))
3885                self.verify_ipfix_max_fragments_ip4(data, 1,
3886                                                    self.pg0.remote_ip4n)
3887
3888    def test_multiple_outside_vrf(self):
3889        """ Multiple outside VRF """
3890        vrf_id1 = 1
3891        vrf_id2 = 2
3892
3893        self.pg1.unconfig_ip4()
3894        self.pg2.unconfig_ip4()
3895        self.vapi.ip_table_add_del(is_add=1, table_id=vrf_id1)
3896        self.vapi.ip_table_add_del(is_add=1, table_id=vrf_id2)
3897        self.pg1.set_table_ip4(vrf_id1)
3898        self.pg2.set_table_ip4(vrf_id2)
3899        self.pg1.config_ip4()
3900        self.pg2.config_ip4()
3901        self.pg1.resolve_arp()
3902        self.pg2.resolve_arp()
3903
3904        self.nat44_add_address(self.nat_addr)
3905        flags = self.config_flags.NAT_IS_INSIDE
3906        self.vapi.nat44_interface_add_del_feature(
3907            sw_if_index=self.pg0.sw_if_index,
3908            flags=flags, is_add=1)
3909        self.vapi.nat44_interface_add_del_feature(
3910            sw_if_index=self.pg1.sw_if_index,
3911            is_add=1)
3912        self.vapi.nat44_interface_add_del_feature(
3913            sw_if_index=self.pg2.sw_if_index,
3914            is_add=1)
3915
3916        try:
3917            # first VRF
3918            pkts = self.create_stream_in(self.pg0, self.pg1)
3919            self.pg0.add_stream(pkts)
3920            self.pg_enable_capture(self.pg_interfaces)
3921            self.pg_start()
3922            capture = self.pg1.get_capture(len(pkts))
3923            self.verify_capture_out(capture, self.nat_addr)
3924
3925            pkts = self.create_stream_out(self.pg1, self.nat_addr)
3926            self.pg1.add_stream(pkts)
3927            self.pg_enable_capture(self.pg_interfaces)
3928            self.pg_start()
3929            capture = self.pg0.get_capture(len(pkts))
3930            self.verify_capture_in(capture, self.pg0)
3931
3932            self.tcp_port_in = 60303
3933            self.udp_port_in = 60304
3934            self.icmp_id_in = 60305
3935
3936            # second VRF
3937            pkts = self.create_stream_in(self.pg0, self.pg2)
3938            self.pg0.add_stream(pkts)
3939            self.pg_enable_capture(self.pg_interfaces)
3940            self.pg_start()
3941            capture = self.pg2.get_capture(len(pkts))
3942            self.verify_capture_out(capture, self.nat_addr)
3943
3944            pkts = self.create_stream_out(self.pg2, self.nat_addr)
3945            self.pg2.add_stream(pkts)
3946            self.pg_enable_capture(self.pg_interfaces)
3947            self.pg_start()
3948            capture = self.pg0.get_capture(len(pkts))
3949            self.verify_capture_in(capture, self.pg0)
3950
3951        finally:
3952            self.nat44_add_address(self.nat_addr, is_add=0)
3953            self.pg1.unconfig_ip4()
3954            self.pg2.unconfig_ip4()
3955            self.pg1.set_table_ip4(0)
3956            self.pg2.set_table_ip4(0)
3957            self.pg1.config_ip4()
3958            self.pg2.config_ip4()
3959            self.pg1.resolve_arp()
3960            self.pg2.resolve_arp()
3961
3962    @unittest.skipUnless(running_extended_tests, "part of extended tests")
3963    def test_session_timeout(self):
3964        """ NAT44 session timeouts """
3965        self.nat44_add_address(self.nat_addr)
3966        flags = self.config_flags.NAT_IS_INSIDE
3967        self.vapi.nat44_interface_add_del_feature(
3968            sw_if_index=self.pg0.sw_if_index,
3969            flags=flags, is_add=1)
3970        self.vapi.nat44_interface_add_del_feature(
3971            sw_if_index=self.pg1.sw_if_index,
3972            is_add=1)
3973        self.vapi.nat_set_timeouts(udp=5, tcp_established=7440,
3974                                   tcp_transitory=240, icmp=60)
3975
3976        max_sessions = 1000
3977        pkts = []
3978        for i in range(0, max_sessions):
3979            src = "10.10.%u.%u" % ((i & 0xFF00) >> 8, i & 0xFF)
3980            p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
3981                 IP(src=src, dst=self.pg1.remote_ip4) /
3982                 UDP(sport=1025, dport=53))
3983            pkts.append(p)
3984        self.pg0.add_stream(pkts)
3985        self.pg_enable_capture(self.pg_interfaces)
3986        self.pg_start()
3987        self.pg1.get_capture(max_sessions)
3988
3989        sleep(6)
3990
3991        pkts = []
3992        for i in range(0, max_sessions):
3993            src = "10.10.%u.%u" % ((i & 0xFF00) >> 8, i & 0xFF)
3994            p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
3995                 IP(src=src, dst=self.pg1.remote_ip4) /
3996                 UDP(sport=1026, dport=53))
3997            pkts.append(p)
3998        self.pg0.add_stream(pkts)
3999        self.pg_enable_capture(self.pg_interfaces)
4000        self.pg_start()
4001        self.pg1.get_capture(max_sessions)
4002
4003        nsessions = 0
4004        users = self.vapi.nat44_user_dump()
4005        for user in users:
4006            nsessions = nsessions + user.nsessions
4007        self.assertLess(nsessions, 2 * max_sessions)
4008
4009    def test_mss_clamping(self):
4010        """ TCP MSS clamping """
4011        self.nat44_add_address(self.nat_addr)
4012        flags = self.config_flags.NAT_IS_INSIDE
4013        self.vapi.nat44_interface_add_del_feature(
4014            sw_if_index=self.pg0.sw_if_index,
4015            flags=flags, is_add=1)
4016        self.vapi.nat44_interface_add_del_feature(
4017            sw_if_index=self.pg1.sw_if_index,
4018            is_add=1)
4019
4020        p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
4021             IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
4022             TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
4023                 flags="S", options=[('MSS', 1400)]))
4024
4025        self.vapi.nat_set_mss_clamping(enable=1, mss_value=1000)
4026        self.pg0.add_stream(p)
4027        self.pg_enable_capture(self.pg_interfaces)
4028        self.pg_start()
4029        capture = self.pg1.get_capture(1)
4030        # Negotiated MSS value greater than configured - changed
4031        self.verify_mss_value(capture[0], 1000)
4032
4033        self.vapi.nat_set_mss_clamping(enable=0, mss_value=1500)
4034        self.pg0.add_stream(p)
4035        self.pg_enable_capture(self.pg_interfaces)
4036        self.pg_start()
4037        capture = self.pg1.get_capture(1)
4038        # MSS clamping disabled - negotiated MSS unchanged
4039        self.verify_mss_value(capture[0], 1400)
4040
4041        self.vapi.nat_set_mss_clamping(enable=1, mss_value=1500)
4042        self.pg0.add_stream(p)
4043        self.pg_enable_capture(self.pg_interfaces)
4044        self.pg_start()
4045        capture = self.pg1.get_capture(1)
4046        # Negotiated MSS value smaller than configured - unchanged
4047        self.verify_mss_value(capture[0], 1400)
4048
4049    @unittest.skipUnless(running_extended_tests, "part of extended tests")
4050    def test_ha_send(self):
4051        """ Send HA session synchronization events (active) """
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        self.vapi.nat_ha_set_listener(ip_address=self.pg3.local_ip4,
4061                                      port=12345,
4062                                      path_mtu=512)
4063        self.vapi.nat_ha_set_failover(ip_address=self.pg3.remote_ip4,
4064                                      port=12346, session_refresh_interval=10)
4065        bind_layers(UDP, HANATStateSync, sport=12345)
4066
4067        # create sessions
4068        pkts = self.create_stream_in(self.pg0, self.pg1)
4069        self.pg0.add_stream(pkts)
4070        self.pg_enable_capture(self.pg_interfaces)
4071        self.pg_start()
4072        capture = self.pg1.get_capture(len(pkts))
4073        self.verify_capture_out(capture)
4074        # active send HA events
4075        self.vapi.nat_ha_flush()
4076        stats = self.statistics.get_counter('/nat44/ha/add-event-send')
4077        self.assertEqual(stats[0][0], 3)
4078        capture = self.pg3.get_capture(1)
4079        p = capture[0]
4080        self.assert_packet_checksums_valid(p)
4081        try:
4082            ip = p[IP]
4083            udp = p[UDP]
4084            hanat = p[HANATStateSync]
4085        except IndexError:
4086            self.logger.error(ppp("Invalid packet:", p))
4087            raise
4088        else:
4089            self.assertEqual(ip.src, self.pg3.local_ip4)
4090            self.assertEqual(ip.dst, self.pg3.remote_ip4)
4091            self.assertEqual(udp.sport, 12345)
4092            self.assertEqual(udp.dport, 12346)
4093            self.assertEqual(hanat.version, 1)
4094            self.assertEqual(hanat.thread_index, 0)
4095            self.assertEqual(hanat.count, 3)
4096            seq = hanat.sequence_number
4097            for event in hanat.events:
4098                self.assertEqual(event.event_type, 1)
4099                self.assertEqual(event.in_addr, self.pg0.remote_ip4)
4100                self.assertEqual(event.out_addr, self.nat_addr)
4101                self.assertEqual(event.fib_index, 0)
4102
4103        # ACK received events
4104        ack = (Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac) /
4105               IP(src=self.pg3.remote_ip4, dst=self.pg3.local_ip4) /
4106               UDP(sport=12346, dport=12345) /
4107               HANATStateSync(sequence_number=seq, flags='ACK'))
4108        self.pg3.add_stream(ack)
4109        self.pg_start()
4110        stats = self.statistics.get_counter('/nat44/ha/ack-recv')
4111        self.assertEqual(stats[0][0], 1)
4112
4113        # delete one session
4114        self.pg_enable_capture(self.pg_interfaces)
4115        self.vapi.nat44_del_session(address=self.pg0.remote_ip4,
4116                                    port=self.tcp_port_in,
4117                                    protocol=IP_PROTOS.tcp,
4118                                    flags=self.config_flags.NAT_IS_INSIDE)
4119        self.vapi.nat_ha_flush()
4120        stats = self.statistics.get_counter('/nat44/ha/del-event-send')
4121        self.assertEqual(stats[0][0], 1)
4122        capture = self.pg3.get_capture(1)
4123        p = capture[0]
4124        try:
4125            hanat = p[HANATStateSync]
4126        except IndexError:
4127            self.logger.error(ppp("Invalid packet:", p))
4128            raise
4129        else:
4130            self.assertGreater(hanat.sequence_number, seq)
4131
4132        # do not send ACK, active retry send HA event again
4133        self.pg_enable_capture(self.pg_interfaces)
4134        sleep(12)
4135        stats = self.statistics.get_counter('/nat44/ha/retry-count')
4136        self.assertEqual(stats[0][0], 3)
4137        stats = self.statistics.get_counter('/nat44/ha/missed-count')
4138        self.assertEqual(stats[0][0], 1)
4139        capture = self.pg3.get_capture(3)
4140        for packet in capture:
4141            self.assertEqual(packet, p)
4142
4143        # session counters refresh
4144        pkts = self.create_stream_out(self.pg1)
4145        self.pg1.add_stream(pkts)
4146        self.pg_enable_capture(self.pg_interfaces)
4147        self.pg_start()
4148        self.pg0.get_capture(2)
4149        self.vapi.nat_ha_flush()
4150        stats = self.statistics.get_counter('/nat44/ha/refresh-event-send')
4151        self.assertEqual(stats[0][0], 2)
4152        capture = self.pg3.get_capture(1)
4153        p = capture[0]
4154        self.assert_packet_checksums_valid(p)
4155        try:
4156            ip = p[IP]
4157            udp = p[UDP]
4158            hanat = p[HANATStateSync]
4159        except IndexError:
4160            self.logger.error(ppp("Invalid packet:", p))
4161            raise
4162        else:
4163            self.assertEqual(ip.src, self.pg3.local_ip4)
4164            self.assertEqual(ip.dst, self.pg3.remote_ip4)
4165            self.assertEqual(udp.sport, 12345)
4166            self.assertEqual(udp.dport, 12346)
4167            self.assertEqual(hanat.version, 1)
4168            self.assertEqual(hanat.count, 2)
4169            seq = hanat.sequence_number
4170            for event in hanat.events:
4171                self.assertEqual(event.event_type, 3)
4172                self.assertEqual(event.out_addr, self.nat_addr)
4173                self.assertEqual(event.fib_index, 0)
4174                self.assertEqual(event.total_pkts, 2)
4175                self.assertGreater(event.total_bytes, 0)
4176
4177        ack = (Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac) /
4178               IP(src=self.pg3.remote_ip4, dst=self.pg3.local_ip4) /
4179               UDP(sport=12346, dport=12345) /
4180               HANATStateSync(sequence_number=seq, flags='ACK'))
4181        self.pg3.add_stream(ack)
4182        self.pg_start()
4183        stats = self.statistics.get_counter('/nat44/ha/ack-recv')
4184        self.assertEqual(stats[0][0], 2)
4185
4186    def test_ha_recv(self):
4187        """ Receive HA session synchronization events (passive) """
4188        self.nat44_add_address(self.nat_addr)
4189        flags = self.config_flags.NAT_IS_INSIDE
4190        self.vapi.nat44_interface_add_del_feature(
4191            sw_if_index=self.pg0.sw_if_index,
4192            flags=flags, is_add=1)
4193        self.vapi.nat44_interface_add_del_feature(
4194            sw_if_index=self.pg1.sw_if_index,
4195            is_add=1)
4196        self.vapi.nat_ha_set_listener(ip_address=self.pg3.local_ip4,
4197                                      port=12345,
4198                                      path_mtu=512)
4199        bind_layers(UDP, HANATStateSync, sport=12345)
4200
4201        self.tcp_port_out = random.randint(1025, 65535)
4202        self.udp_port_out = random.randint(1025, 65535)
4203
4204        # send HA session add events to failover/passive
4205        p = (Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac) /
4206             IP(src=self.pg3.remote_ip4, dst=self.pg3.local_ip4) /
4207             UDP(sport=12346, dport=12345) /
4208             HANATStateSync(sequence_number=1, events=[
4209                 Event(event_type='add', protocol='tcp',
4210                       in_addr=self.pg0.remote_ip4, out_addr=self.nat_addr,
4211                       in_port=self.tcp_port_in, out_port=self.tcp_port_out,
4212                       eh_addr=self.pg1.remote_ip4,
4213                       ehn_addr=self.pg1.remote_ip4,
4214                       eh_port=self.tcp_external_port,
4215                       ehn_port=self.tcp_external_port, fib_index=0),
4216                 Event(event_type='add', protocol='udp',
4217                       in_addr=self.pg0.remote_ip4, out_addr=self.nat_addr,
4218                       in_port=self.udp_port_in, out_port=self.udp_port_out,
4219                       eh_addr=self.pg1.remote_ip4,
4220                       ehn_addr=self.pg1.remote_ip4,
4221                       eh_port=self.udp_external_port,
4222                       ehn_port=self.udp_external_port, fib_index=0)]))
4223
4224        self.pg3.add_stream(p)
4225        self.pg_enable_capture(self.pg_interfaces)
4226        self.pg_start()
4227        # receive ACK
4228        capture = self.pg3.get_capture(1)
4229        p = capture[0]
4230        try:
4231            hanat = p[HANATStateSync]
4232        except IndexError:
4233            self.logger.error(ppp("Invalid packet:", p))
4234            raise
4235        else:
4236            self.assertEqual(hanat.sequence_number, 1)
4237            self.assertEqual(hanat.flags, 'ACK')
4238            self.assertEqual(hanat.version, 1)
4239            self.assertEqual(hanat.thread_index, 0)
4240        stats = self.statistics.get_counter('/nat44/ha/ack-send')
4241        self.assertEqual(stats[0][0], 1)
4242        stats = self.statistics.get_counter('/nat44/ha/add-event-recv')
4243        self.assertEqual(stats[0][0], 2)
4244        users = self.statistics.get_counter('/nat44/total-users')
4245        self.assertEqual(users[0][0], 1)
4246        sessions = self.statistics.get_counter('/nat44/total-sessions')
4247        self.assertEqual(sessions[0][0], 2)
4248        users = self.vapi.nat44_user_dump()
4249        self.assertEqual(len(users), 1)
4250        self.assertEqual(str(users[0].ip_address),
4251                         self.pg0.remote_ip4)
4252        # there should be 2 sessions created by HA
4253        sessions = self.vapi.nat44_user_session_dump(users[0].ip_address,
4254                                                     users[0].vrf_id)
4255        self.assertEqual(len(sessions), 2)
4256        for session in sessions:
4257            self.assertEqual(str(session.inside_ip_address),
4258                             self.pg0.remote_ip4)
4259            self.assertEqual(str(session.outside_ip_address),
4260                             self.nat_addr)
4261            self.assertIn(session.inside_port,
4262                          [self.tcp_port_in, self.udp_port_in])
4263            self.assertIn(session.outside_port,
4264                          [self.tcp_port_out, self.udp_port_out])
4265            self.assertIn(session.protocol, [IP_PROTOS.tcp, IP_PROTOS.udp])
4266
4267        # send HA session delete event to failover/passive
4268        p = (Ether(dst=self.pg3.loca