nat: fix incorrect session removal case
[vpp.git] / src / plugins / nat / test / test_nat44.py
1 #!/usr/bin/env python3
2
3 import ipaddress
4 import random
5 import socket
6 import struct
7 import unittest
8 from io import BytesIO
9 from time import sleep
10
11 import scapy.compat
12 from framework import VppTestCase, VppTestRunner, running_extended_tests
13 from ipfix import IPFIX, Set, Template, Data, IPFIXDecoder
14 from scapy.all import bind_layers, Packet, ByteEnumField, ShortField, \
15     IPField, IntField, LongField, XByteField, FlagsField, FieldLenField, \
16     PacketListField
17 from scapy.data import IP_PROTOS
18 from scapy.layers.inet import IP, TCP, UDP, ICMP
19 from scapy.layers.inet import IPerror, TCPerror, UDPerror, ICMPerror
20 from scapy.layers.inet6 import ICMPv6DestUnreach, IPerror6, IPv6ExtHdrFragment
21 from scapy.layers.inet6 import IPv6, ICMPv6EchoRequest, ICMPv6EchoReply, \
22     ICMPv6ND_NS, ICMPv6ND_NA, ICMPv6NDOptDstLLAddr, fragment6
23 from scapy.layers.l2 import Ether, ARP, GRE
24 from scapy.packet import Raw
25 from syslog_rfc5424_parser import SyslogMessage, ParseError
26 from syslog_rfc5424_parser.constants import SyslogSeverity
27 from util import ip4_range
28 from util import ppc, ppp
29 from vpp_acl import AclRule, VppAcl, VppAclInterface
30 from vpp_ip_route import VppIpRoute, VppRoutePath
31 from vpp_neighbor import VppNeighbor
32 from vpp_papi import VppEnum
33
34
35 # NAT HA protocol event data
36 class Event(Packet):
37     name = "Event"
38     fields_desc = [ByteEnumField("event_type", None,
39                                  {1: "add", 2: "del", 3: "refresh"}),
40                    ByteEnumField("protocol", None,
41                                  {0: "other", 1: "udp", 2: "tcp", 3: "icmp"}),
42                    ShortField("flags", 0),
43                    IPField("in_addr", None),
44                    IPField("out_addr", None),
45                    ShortField("in_port", None),
46                    ShortField("out_port", None),
47                    IPField("eh_addr", None),
48                    IPField("ehn_addr", None),
49                    ShortField("eh_port", None),
50                    ShortField("ehn_port", None),
51                    IntField("fib_index", None),
52                    IntField("total_pkts", 0),
53                    LongField("total_bytes", 0)]
54
55     def extract_padding(self, s):
56         return "", s
57
58
59 # NAT HA protocol header
60 class HANATStateSync(Packet):
61     name = "HA NAT state sync"
62     fields_desc = [XByteField("version", 1),
63                    FlagsField("flags", 0, 8, ['ACK']),
64                    FieldLenField("count", None, count_of="events"),
65                    IntField("sequence_number", 1),
66                    IntField("thread_index", 0),
67                    PacketListField("events", [], Event,
68                                    count_from=lambda pkt: pkt.count)]
69
70
71 class MethodHolder(VppTestCase):
72     """ NAT create capture and verify method holder """
73
74     @property
75     def config_flags(self):
76         return VppEnum.vl_api_nat_config_flags_t
77
78     @property
79     def nat44_config_flags(self):
80         return VppEnum.vl_api_nat44_config_flags_t
81
82     @property
83     def SYSLOG_SEVERITY(self):
84         return VppEnum.vl_api_syslog_severity_t
85
86     def nat44_add_static_mapping(self, local_ip, external_ip='0.0.0.0',
87                                  local_port=0, external_port=0, vrf_id=0,
88                                  is_add=1, external_sw_if_index=0xFFFFFFFF,
89                                  proto=0, tag="", flags=0):
90         """
91         Add/delete NAT44 static mapping
92
93         :param local_ip: Local IP address
94         :param external_ip: External IP address
95         :param local_port: Local port number (Optional)
96         :param external_port: External port number (Optional)
97         :param vrf_id: VRF ID (Default 0)
98         :param is_add: 1 if add, 0 if delete (Default add)
99         :param external_sw_if_index: External interface instead of IP address
100         :param proto: IP protocol (Mandatory if port specified)
101         :param tag: Opaque string tag
102         :param flags: NAT configuration flags
103         """
104
105         if not (local_port and external_port):
106             flags |= self.config_flags.NAT_IS_ADDR_ONLY
107
108         self.vapi.nat44_add_del_static_mapping(
109             is_add=is_add,
110             local_ip_address=local_ip,
111             external_ip_address=external_ip,
112             external_sw_if_index=external_sw_if_index,
113             local_port=local_port,
114             external_port=external_port,
115             vrf_id=vrf_id, protocol=proto,
116             flags=flags,
117             tag=tag)
118
119     def nat44_add_address(self, ip, is_add=1, vrf_id=0xFFFFFFFF, twice_nat=0):
120         """
121         Add/delete NAT44 address
122
123         :param ip: IP address
124         :param is_add: 1 if add, 0 if delete (Default add)
125         :param twice_nat: twice NAT address for external hosts
126         """
127         flags = self.config_flags.NAT_IS_TWICE_NAT if twice_nat else 0
128         self.vapi.nat44_add_del_address_range(first_ip_address=ip,
129                                               last_ip_address=ip,
130                                               vrf_id=vrf_id,
131                                               is_add=is_add,
132                                               flags=flags)
133
134     def create_stream_in(self, in_if, out_if, dst_ip=None, ttl=64):
135         """
136         Create packet stream for inside network
137
138         :param in_if: Inside interface
139         :param out_if: Outside interface
140         :param dst_ip: Destination address
141         :param ttl: TTL of generated packets
142         """
143         if dst_ip is None:
144             dst_ip = out_if.remote_ip4
145
146         pkts = []
147         # TCP
148         p = (Ether(dst=in_if.local_mac, src=in_if.remote_mac) /
149              IP(src=in_if.remote_ip4, dst=dst_ip, ttl=ttl) /
150              TCP(sport=self.tcp_port_in, dport=20))
151         pkts.extend([p, p])
152
153         # UDP
154         p = (Ether(dst=in_if.local_mac, src=in_if.remote_mac) /
155              IP(src=in_if.remote_ip4, dst=dst_ip, ttl=ttl) /
156              UDP(sport=self.udp_port_in, dport=20))
157         pkts.append(p)
158
159         # ICMP
160         p = (Ether(dst=in_if.local_mac, src=in_if.remote_mac) /
161              IP(src=in_if.remote_ip4, dst=dst_ip, ttl=ttl) /
162              ICMP(id=self.icmp_id_in, type='echo-request'))
163         pkts.append(p)
164
165         return pkts
166
167     def compose_ip6(self, ip4, pref, plen):
168         """
169         Compose IPv4-embedded IPv6 addresses
170
171         :param ip4: IPv4 address
172         :param pref: IPv6 prefix
173         :param plen: IPv6 prefix length
174         :returns: IPv4-embedded IPv6 addresses
175         """
176         pref_n = list(socket.inet_pton(socket.AF_INET6, pref))
177         ip4_n = list(socket.inet_pton(socket.AF_INET, ip4))
178         if plen == 32:
179             pref_n[4] = ip4_n[0]
180             pref_n[5] = ip4_n[1]
181             pref_n[6] = ip4_n[2]
182             pref_n[7] = ip4_n[3]
183         elif plen == 40:
184             pref_n[5] = ip4_n[0]
185             pref_n[6] = ip4_n[1]
186             pref_n[7] = ip4_n[2]
187             pref_n[9] = ip4_n[3]
188         elif plen == 48:
189             pref_n[6] = ip4_n[0]
190             pref_n[7] = ip4_n[1]
191             pref_n[9] = ip4_n[2]
192             pref_n[10] = ip4_n[3]
193         elif plen == 56:
194             pref_n[7] = ip4_n[0]
195             pref_n[9] = ip4_n[1]
196             pref_n[10] = ip4_n[2]
197             pref_n[11] = ip4_n[3]
198         elif plen == 64:
199             pref_n[9] = ip4_n[0]
200             pref_n[10] = ip4_n[1]
201             pref_n[11] = ip4_n[2]
202             pref_n[12] = ip4_n[3]
203         elif plen == 96:
204             pref_n[12] = ip4_n[0]
205             pref_n[13] = ip4_n[1]
206             pref_n[14] = ip4_n[2]
207             pref_n[15] = ip4_n[3]
208         packed_pref_n = b''.join([scapy.compat.chb(x) for x in pref_n])
209         return socket.inet_ntop(socket.AF_INET6, packed_pref_n)
210
211     def extract_ip4(self, ip6, plen):
212         """
213         Extract IPv4 address embedded in IPv6 addresses
214
215         :param ip6: IPv6 address
216         :param plen: IPv6 prefix length
217         :returns: extracted IPv4 address
218         """
219         ip6_n = list(socket.inet_pton(socket.AF_INET6, ip6))
220         ip4_n = [None] * 4
221         if plen == 32:
222             ip4_n[0] = ip6_n[4]
223             ip4_n[1] = ip6_n[5]
224             ip4_n[2] = ip6_n[6]
225             ip4_n[3] = ip6_n[7]
226         elif plen == 40:
227             ip4_n[0] = ip6_n[5]
228             ip4_n[1] = ip6_n[6]
229             ip4_n[2] = ip6_n[7]
230             ip4_n[3] = ip6_n[9]
231         elif plen == 48:
232             ip4_n[0] = ip6_n[6]
233             ip4_n[1] = ip6_n[7]
234             ip4_n[2] = ip6_n[9]
235             ip4_n[3] = ip6_n[10]
236         elif plen == 56:
237             ip4_n[0] = ip6_n[7]
238             ip4_n[1] = ip6_n[9]
239             ip4_n[2] = ip6_n[10]
240             ip4_n[3] = ip6_n[11]
241         elif plen == 64:
242             ip4_n[0] = ip6_n[9]
243             ip4_n[1] = ip6_n[10]
244             ip4_n[2] = ip6_n[11]
245             ip4_n[3] = ip6_n[12]
246         elif plen == 96:
247             ip4_n[0] = ip6_n[12]
248             ip4_n[1] = ip6_n[13]
249             ip4_n[2] = ip6_n[14]
250             ip4_n[3] = ip6_n[15]
251         return socket.inet_ntop(socket.AF_INET, ''.join(ip4_n))
252
253     def create_stream_out(self, out_if, dst_ip=None, ttl=64,
254                           use_inside_ports=False):
255         """
256         Create packet stream for outside network
257
258         :param out_if: Outside interface
259         :param dst_ip: Destination IP address (Default use global NAT address)
260         :param ttl: TTL of generated packets
261         :param use_inside_ports: Use inside NAT ports as destination ports
262                instead of outside ports
263         """
264         if dst_ip is None:
265             dst_ip = self.nat_addr
266         if not use_inside_ports:
267             tcp_port = self.tcp_port_out
268             udp_port = self.udp_port_out
269             icmp_id = self.icmp_id_out
270         else:
271             tcp_port = self.tcp_port_in
272             udp_port = self.udp_port_in
273             icmp_id = self.icmp_id_in
274         pkts = []
275         # TCP
276         p = (Ether(dst=out_if.local_mac, src=out_if.remote_mac) /
277              IP(src=out_if.remote_ip4, dst=dst_ip, ttl=ttl) /
278              TCP(dport=tcp_port, sport=20))
279         pkts.extend([p, p])
280
281         # UDP
282         p = (Ether(dst=out_if.local_mac, src=out_if.remote_mac) /
283              IP(src=out_if.remote_ip4, dst=dst_ip, ttl=ttl) /
284              UDP(dport=udp_port, sport=20))
285         pkts.append(p)
286
287         # ICMP
288         p = (Ether(dst=out_if.local_mac, src=out_if.remote_mac) /
289              IP(src=out_if.remote_ip4, dst=dst_ip, ttl=ttl) /
290              ICMP(id=icmp_id, type='echo-reply'))
291         pkts.append(p)
292
293         return pkts
294
295     def create_stream_out_ip6(self, out_if, src_ip, dst_ip, hl=64):
296         """
297         Create packet stream for outside network
298
299         :param out_if: Outside interface
300         :param dst_ip: Destination IP address (Default use global NAT address)
301         :param hl: HL of generated packets
302         """
303         pkts = []
304         # TCP
305         p = (Ether(dst=out_if.local_mac, src=out_if.remote_mac) /
306              IPv6(src=src_ip, dst=dst_ip, hlim=hl) /
307              TCP(dport=self.tcp_port_out, sport=20))
308         pkts.append(p)
309
310         # UDP
311         p = (Ether(dst=out_if.local_mac, src=out_if.remote_mac) /
312              IPv6(src=src_ip, dst=dst_ip, hlim=hl) /
313              UDP(dport=self.udp_port_out, sport=20))
314         pkts.append(p)
315
316         # ICMP
317         p = (Ether(dst=out_if.local_mac, src=out_if.remote_mac) /
318              IPv6(src=src_ip, dst=dst_ip, hlim=hl) /
319              ICMPv6EchoReply(id=self.icmp_id_out))
320         pkts.append(p)
321
322         return pkts
323
324     def verify_capture_out(self, capture, nat_ip=None, same_port=False,
325                            dst_ip=None, is_ip6=False, ignore_port=False):
326         """
327         Verify captured packets on outside network
328
329         :param capture: Captured packets
330         :param nat_ip: Translated IP address (Default use global NAT address)
331         :param same_port: Source port number is not translated (Default False)
332         :param dst_ip: Destination IP address (Default do not verify)
333         :param is_ip6: If L3 protocol is IPv6 (Default False)
334         """
335         if is_ip6:
336             IP46 = IPv6
337             ICMP46 = ICMPv6EchoRequest
338         else:
339             IP46 = IP
340             ICMP46 = ICMP
341         if nat_ip is None:
342             nat_ip = self.nat_addr
343         for packet in capture:
344             try:
345                 if not is_ip6:
346                     self.assert_packet_checksums_valid(packet)
347                 self.assertEqual(packet[IP46].src, nat_ip)
348                 if dst_ip is not None:
349                     self.assertEqual(packet[IP46].dst, dst_ip)
350                 if packet.haslayer(TCP):
351                     if not ignore_port:
352                         if same_port:
353                             self.assertEqual(
354                                 packet[TCP].sport, self.tcp_port_in)
355                         else:
356                             self.assertNotEqual(
357                                 packet[TCP].sport, self.tcp_port_in)
358                     self.tcp_port_out = packet[TCP].sport
359                     self.assert_packet_checksums_valid(packet)
360                 elif packet.haslayer(UDP):
361                     if not ignore_port:
362                         if same_port:
363                             self.assertEqual(
364                                 packet[UDP].sport, self.udp_port_in)
365                         else:
366                             self.assertNotEqual(
367                                 packet[UDP].sport, self.udp_port_in)
368                     self.udp_port_out = packet[UDP].sport
369                 else:
370                     if not ignore_port:
371                         if same_port:
372                             self.assertEqual(
373                                 packet[ICMP46].id, self.icmp_id_in)
374                         else:
375                             self.assertNotEqual(
376                                 packet[ICMP46].id, self.icmp_id_in)
377                     self.icmp_id_out = packet[ICMP46].id
378                     self.assert_packet_checksums_valid(packet)
379             except:
380                 self.logger.error(ppp("Unexpected or invalid packet "
381                                       "(outside network):", packet))
382                 raise
383
384     def verify_capture_out_ip6(self, capture, nat_ip, same_port=False,
385                                dst_ip=None):
386         """
387         Verify captured packets on outside network
388
389         :param capture: Captured packets
390         :param nat_ip: Translated IP address
391         :param same_port: Source port number is not translated (Default False)
392         :param dst_ip: Destination IP address (Default do not verify)
393         """
394         return self.verify_capture_out(capture, nat_ip, same_port, dst_ip,
395                                        True)
396
397     def verify_capture_in(self, capture, in_if):
398         """
399         Verify captured packets on inside network
400
401         :param capture: Captured packets
402         :param in_if: Inside interface
403         """
404         for packet in capture:
405             try:
406                 self.assert_packet_checksums_valid(packet)
407                 self.assertEqual(packet[IP].dst, in_if.remote_ip4)
408                 if packet.haslayer(TCP):
409                     self.assertEqual(packet[TCP].dport, self.tcp_port_in)
410                 elif packet.haslayer(UDP):
411                     self.assertEqual(packet[UDP].dport, self.udp_port_in)
412                 else:
413                     self.assertEqual(packet[ICMP].id, self.icmp_id_in)
414             except:
415                 self.logger.error(ppp("Unexpected or invalid packet "
416                                       "(inside network):", packet))
417                 raise
418
419     def verify_capture_in_ip6(self, capture, src_ip, dst_ip):
420         """
421         Verify captured IPv6 packets on inside network
422
423         :param capture: Captured packets
424         :param src_ip: Source IP
425         :param dst_ip: Destination IP address
426         """
427         for packet in capture:
428             try:
429                 self.assertEqual(packet[IPv6].src, src_ip)
430                 self.assertEqual(packet[IPv6].dst, dst_ip)
431                 self.assert_packet_checksums_valid(packet)
432                 if packet.haslayer(TCP):
433                     self.assertEqual(packet[TCP].dport, self.tcp_port_in)
434                 elif packet.haslayer(UDP):
435                     self.assertEqual(packet[UDP].dport, self.udp_port_in)
436                 else:
437                     self.assertEqual(packet[ICMPv6EchoReply].id,
438                                      self.icmp_id_in)
439             except:
440                 self.logger.error(ppp("Unexpected or invalid packet "
441                                       "(inside network):", packet))
442                 raise
443
444     def verify_capture_no_translation(self, capture, ingress_if, egress_if):
445         """
446         Verify captured packet that don't have to be translated
447
448         :param capture: Captured packets
449         :param ingress_if: Ingress interface
450         :param egress_if: Egress interface
451         """
452         for packet in capture:
453             try:
454                 self.assertEqual(packet[IP].src, ingress_if.remote_ip4)
455                 self.assertEqual(packet[IP].dst, egress_if.remote_ip4)
456                 if packet.haslayer(TCP):
457                     self.assertEqual(packet[TCP].sport, self.tcp_port_in)
458                 elif packet.haslayer(UDP):
459                     self.assertEqual(packet[UDP].sport, self.udp_port_in)
460                 else:
461                     self.assertEqual(packet[ICMP].id, self.icmp_id_in)
462             except:
463                 self.logger.error(ppp("Unexpected or invalid packet "
464                                       "(inside network):", packet))
465                 raise
466
467     def verify_capture_out_with_icmp_errors(self, capture, src_ip=None,
468                                             icmp_type=11):
469         """
470         Verify captured packets with ICMP errors on outside network
471
472         :param capture: Captured packets
473         :param src_ip: Translated IP address or IP address of VPP
474                        (Default use global NAT address)
475         :param icmp_type: Type of error ICMP packet
476                           we are expecting (Default 11)
477         """
478         if src_ip is None:
479             src_ip = self.nat_addr
480         for packet in capture:
481             try:
482                 self.assertEqual(packet[IP].src, src_ip)
483                 self.assertEqual(packet.haslayer(ICMP), 1)
484                 icmp = packet[ICMP]
485                 self.assertEqual(icmp.type, icmp_type)
486                 self.assertTrue(icmp.haslayer(IPerror))
487                 inner_ip = icmp[IPerror]
488                 if inner_ip.haslayer(TCPerror):
489                     self.assertEqual(inner_ip[TCPerror].dport,
490                                      self.tcp_port_out)
491                 elif inner_ip.haslayer(UDPerror):
492                     self.assertEqual(inner_ip[UDPerror].dport,
493                                      self.udp_port_out)
494                 else:
495                     self.assertEqual(inner_ip[ICMPerror].id, self.icmp_id_out)
496             except:
497                 self.logger.error(ppp("Unexpected or invalid packet "
498                                       "(outside network):", packet))
499                 raise
500
501     def verify_capture_in_with_icmp_errors(self, capture, in_if, icmp_type=11):
502         """
503         Verify captured packets with ICMP errors on inside network
504
505         :param capture: Captured packets
506         :param in_if: Inside interface
507         :param icmp_type: Type of error ICMP packet
508                           we are expecting (Default 11)
509         """
510         for packet in capture:
511             try:
512                 self.assertEqual(packet[IP].dst, in_if.remote_ip4)
513                 self.assertEqual(packet.haslayer(ICMP), 1)
514                 icmp = packet[ICMP]
515                 self.assertEqual(icmp.type, icmp_type)
516                 self.assertTrue(icmp.haslayer(IPerror))
517                 inner_ip = icmp[IPerror]
518                 if inner_ip.haslayer(TCPerror):
519                     self.assertEqual(inner_ip[TCPerror].sport,
520                                      self.tcp_port_in)
521                 elif inner_ip.haslayer(UDPerror):
522                     self.assertEqual(inner_ip[UDPerror].sport,
523                                      self.udp_port_in)
524                 else:
525                     self.assertEqual(inner_ip[ICMPerror].id, self.icmp_id_in)
526             except:
527                 self.logger.error(ppp("Unexpected or invalid packet "
528                                       "(inside network):", packet))
529                 raise
530
531     def create_stream_frag(self, src_if, dst, sport, dport, data,
532                            proto=IP_PROTOS.tcp, echo_reply=False):
533         """
534         Create fragmented packet stream
535
536         :param src_if: Source interface
537         :param dst: Destination IPv4 address
538         :param sport: Source port
539         :param dport: Destination port
540         :param data: Payload data
541         :param proto: protocol (TCP, UDP, ICMP)
542         :param echo_reply: use echo_reply if protocol is ICMP
543         :returns: Fragments
544         """
545         if proto == IP_PROTOS.tcp:
546             p = (IP(src=src_if.remote_ip4, dst=dst) /
547                  TCP(sport=sport, dport=dport) /
548                  Raw(data))
549             p = p.__class__(scapy.compat.raw(p))
550             chksum = p[TCP].chksum
551             proto_header = TCP(sport=sport, dport=dport, chksum=chksum)
552         elif proto == IP_PROTOS.udp:
553             proto_header = UDP(sport=sport, dport=dport)
554         elif proto == IP_PROTOS.icmp:
555             if not echo_reply:
556                 proto_header = ICMP(id=sport, type='echo-request')
557             else:
558                 proto_header = ICMP(id=sport, type='echo-reply')
559         else:
560             raise Exception("Unsupported protocol")
561         id = random.randint(0, 65535)
562         pkts = []
563         if proto == IP_PROTOS.tcp:
564             raw = Raw(data[0:4])
565         else:
566             raw = Raw(data[0:16])
567         p = (Ether(src=src_if.remote_mac, dst=src_if.local_mac) /
568              IP(src=src_if.remote_ip4, dst=dst, flags="MF", frag=0, id=id) /
569              proto_header /
570              raw)
571         pkts.append(p)
572         if proto == IP_PROTOS.tcp:
573             raw = Raw(data[4:20])
574         else:
575             raw = Raw(data[16:32])
576         p = (Ether(src=src_if.remote_mac, dst=src_if.local_mac) /
577              IP(src=src_if.remote_ip4, dst=dst, flags="MF", frag=3, id=id,
578                 proto=proto) /
579              raw)
580         pkts.append(p)
581         if proto == IP_PROTOS.tcp:
582             raw = Raw(data[20:])
583         else:
584             raw = Raw(data[32:])
585         p = (Ether(src=src_if.remote_mac, dst=src_if.local_mac) /
586              IP(src=src_if.remote_ip4, dst=dst, frag=5, proto=proto,
587                 id=id) /
588              raw)
589         pkts.append(p)
590         return pkts
591
592     def reass_frags_and_verify(self, frags, src, dst):
593         """
594         Reassemble and verify fragmented packet
595
596         :param frags: Captured fragments
597         :param src: Source IPv4 address to verify
598         :param dst: Destination IPv4 address to verify
599
600         :returns: Reassembled IPv4 packet
601         """
602         buffer = BytesIO()
603         for p in frags:
604             self.assertEqual(p[IP].src, src)
605             self.assertEqual(p[IP].dst, dst)
606             self.assert_ip_checksum_valid(p)
607             buffer.seek(p[IP].frag * 8)
608             buffer.write(bytes(p[IP].payload))
609         ip = IP(src=frags[0][IP].src, dst=frags[0][IP].dst,
610                 proto=frags[0][IP].proto)
611         if ip.proto == IP_PROTOS.tcp:
612             p = (ip / TCP(buffer.getvalue()))
613             self.logger.debug(ppp("Reassembled:", p))
614             self.assert_tcp_checksum_valid(p)
615         elif ip.proto == IP_PROTOS.udp:
616             p = (ip / UDP(buffer.getvalue()[:8]) /
617                  Raw(buffer.getvalue()[8:]))
618         elif ip.proto == IP_PROTOS.icmp:
619             p = (ip / ICMP(buffer.getvalue()))
620         return p
621
622     def reass_frags_and_verify_ip6(self, frags, src, dst):
623         """
624         Reassemble and verify fragmented packet
625
626         :param frags: Captured fragments
627         :param src: Source IPv6 address to verify
628         :param dst: Destination IPv6 address to verify
629
630         :returns: Reassembled IPv6 packet
631         """
632         buffer = BytesIO()
633         for p in frags:
634             self.assertEqual(p[IPv6].src, src)
635             self.assertEqual(p[IPv6].dst, dst)
636             buffer.seek(p[IPv6ExtHdrFragment].offset * 8)
637             buffer.write(bytes(p[IPv6ExtHdrFragment].payload))
638         ip = IPv6(src=frags[0][IPv6].src, dst=frags[0][IPv6].dst,
639                   nh=frags[0][IPv6ExtHdrFragment].nh)
640         if ip.nh == IP_PROTOS.tcp:
641             p = (ip / TCP(buffer.getvalue()))
642         elif ip.nh == IP_PROTOS.udp:
643             p = (ip / UDP(buffer.getvalue()))
644         self.logger.debug(ppp("Reassembled:", p))
645         self.assert_packet_checksums_valid(p)
646         return p
647
648     def initiate_tcp_session(self, in_if, out_if):
649         """
650         Initiates TCP session
651
652         :param in_if: Inside interface
653         :param out_if: Outside interface
654         """
655         try:
656             # SYN packet in->out
657             p = (Ether(src=in_if.remote_mac, dst=in_if.local_mac) /
658                  IP(src=in_if.remote_ip4, dst=out_if.remote_ip4) /
659                  TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
660                      flags="S"))
661             in_if.add_stream(p)
662             self.pg_enable_capture(self.pg_interfaces)
663             self.pg_start()
664             capture = out_if.get_capture(1)
665             p = capture[0]
666             self.tcp_port_out = p[TCP].sport
667
668             # SYN + ACK packet out->in
669             p = (Ether(src=out_if.remote_mac, dst=out_if.local_mac) /
670                  IP(src=out_if.remote_ip4, dst=self.nat_addr) /
671                  TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
672                      flags="SA"))
673             out_if.add_stream(p)
674             self.pg_enable_capture(self.pg_interfaces)
675             self.pg_start()
676             in_if.get_capture(1)
677
678             # ACK packet in->out
679             p = (Ether(src=in_if.remote_mac, dst=in_if.local_mac) /
680                  IP(src=in_if.remote_ip4, dst=out_if.remote_ip4) /
681                  TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
682                      flags="A"))
683             in_if.add_stream(p)
684             self.pg_enable_capture(self.pg_interfaces)
685             self.pg_start()
686             out_if.get_capture(1)
687
688         except:
689             self.logger.error("TCP 3 way handshake failed")
690             raise
691
692     def verify_ipfix_nat44_ses(self, data):
693         """
694         Verify IPFIX NAT44 session create/delete event
695
696         :param data: Decoded IPFIX data records
697         """
698         nat44_ses_create_num = 0
699         nat44_ses_delete_num = 0
700         self.assertEqual(6, len(data))
701         for record in data:
702             # natEvent
703             self.assertIn(scapy.compat.orb(record[230]), [4, 5])
704             if scapy.compat.orb(record[230]) == 4:
705                 nat44_ses_create_num += 1
706             else:
707                 nat44_ses_delete_num += 1
708             # sourceIPv4Address
709             self.assertEqual(self.pg0.remote_ip4,
710                              str(ipaddress.IPv4Address(record[8])))
711             # postNATSourceIPv4Address
712             self.assertEqual(socket.inet_pton(socket.AF_INET, self.nat_addr),
713                              record[225])
714             # ingressVRFID
715             self.assertEqual(struct.pack("!I", 0), record[234])
716             # protocolIdentifier/sourceTransportPort
717             # /postNAPTSourceTransportPort
718             if IP_PROTOS.icmp == scapy.compat.orb(record[4]):
719                 self.assertEqual(struct.pack("!H", self.icmp_id_in), record[7])
720                 self.assertEqual(struct.pack("!H", self.icmp_id_out),
721                                  record[227])
722             elif IP_PROTOS.tcp == scapy.compat.orb(record[4]):
723                 self.assertEqual(struct.pack("!H", self.tcp_port_in),
724                                  record[7])
725                 self.assertEqual(struct.pack("!H", self.tcp_port_out),
726                                  record[227])
727             elif IP_PROTOS.udp == scapy.compat.orb(record[4]):
728                 self.assertEqual(struct.pack("!H", self.udp_port_in),
729                                  record[7])
730                 self.assertEqual(struct.pack("!H", self.udp_port_out),
731                                  record[227])
732             else:
733                 self.fail("Invalid protocol")
734         self.assertEqual(3, nat44_ses_create_num)
735         self.assertEqual(3, nat44_ses_delete_num)
736
737     def verify_ipfix_addr_exhausted(self, data):
738         """
739         Verify IPFIX NAT addresses event
740
741         :param data: Decoded IPFIX data records
742         """
743         self.assertEqual(1, len(data))
744         record = data[0]
745         # natEvent
746         self.assertEqual(scapy.compat.orb(record[230]), 3)
747         # natPoolID
748         self.assertEqual(struct.pack("!I", 0), record[283])
749
750     def verify_ipfix_max_sessions(self, data, limit):
751         """
752         Verify IPFIX maximum session entries exceeded event
753
754         :param data: Decoded IPFIX data records
755         :param limit: Number of maximum session entries that can be created.
756         """
757         self.assertEqual(1, len(data))
758         record = data[0]
759         # natEvent
760         self.assertEqual(scapy.compat.orb(record[230]), 13)
761         # natQuotaExceededEvent
762         self.assertEqual(struct.pack("I", 1), record[466])
763         # maxSessionEntries
764         self.assertEqual(struct.pack("I", limit), record[471])
765
766     def verify_ipfix_max_bibs(self, data, limit):
767         """
768         Verify IPFIX maximum BIB entries exceeded event
769
770         :param data: Decoded IPFIX data records
771         :param limit: Number of maximum BIB entries that can be created.
772         """
773         self.assertEqual(1, len(data))
774         record = data[0]
775         # natEvent
776         self.assertEqual(scapy.compat.orb(record[230]), 13)
777         # natQuotaExceededEvent
778         self.assertEqual(struct.pack("I", 2), record[466])
779         # maxBIBEntries
780         self.assertEqual(struct.pack("I", limit), record[472])
781
782     def verify_no_nat44_user(self):
783         """ Verify that there is no NAT44 user """
784         users = self.vapi.nat44_user_dump()
785         self.assertEqual(len(users), 0)
786         users = self.statistics.get_counter('/nat44/total-users')
787         self.assertEqual(users[0][0], 0)
788         sessions = self.statistics.get_counter('/nat44/total-sessions')
789         self.assertEqual(sessions[0][0], 0)
790
791     def verify_ipfix_max_entries_per_user(self, data, limit, src_addr):
792         """
793         Verify IPFIX maximum entries per user exceeded event
794
795         :param data: Decoded IPFIX data records
796         :param limit: Number of maximum entries per user
797         :param src_addr: IPv4 source address
798         """
799         self.assertEqual(1, len(data))
800         record = data[0]
801         # natEvent
802         self.assertEqual(scapy.compat.orb(record[230]), 13)
803         # natQuotaExceededEvent
804         self.assertEqual(struct.pack("I", 3), record[466])
805         # maxEntriesPerUser
806         self.assertEqual(struct.pack("I", limit), record[473])
807         # sourceIPv4Address
808         self.assertEqual(socket.inet_pton(socket.AF_INET, src_addr), record[8])
809
810     def verify_syslog_apmap(self, data, is_add=True):
811         message = data.decode('utf-8')
812         try:
813             message = SyslogMessage.parse(message)
814         except ParseError as e:
815             self.logger.error(e)
816             raise
817         else:
818             self.assertEqual(message.severity, SyslogSeverity.info)
819             self.assertEqual(message.appname, 'NAT')
820             self.assertEqual(message.msgid, 'APMADD' if is_add else 'APMDEL')
821             sd_params = message.sd.get('napmap')
822             self.assertTrue(sd_params is not None)
823             self.assertEqual(sd_params.get('IATYP'), 'IPv4')
824             self.assertEqual(sd_params.get('ISADDR'), self.pg0.remote_ip4)
825             self.assertEqual(sd_params.get('ISPORT'), "%d" % self.tcp_port_in)
826             self.assertEqual(sd_params.get('XATYP'), 'IPv4')
827             self.assertEqual(sd_params.get('XSADDR'), self.nat_addr)
828             self.assertEqual(sd_params.get('XSPORT'), "%d" % self.tcp_port_out)
829             self.assertEqual(sd_params.get('PROTO'), "%d" % IP_PROTOS.tcp)
830             self.assertTrue(sd_params.get('SSUBIX') is not None)
831             self.assertEqual(sd_params.get('SVLAN'), '0')
832
833     def verify_syslog_sess(self, data, is_add=True, is_ip6=False):
834         message = data.decode('utf-8')
835         try:
836             message = SyslogMessage.parse(message)
837         except ParseError as e:
838             self.logger.error(e)
839             raise
840         else:
841             self.assertEqual(message.severity, SyslogSeverity.info)
842             self.assertEqual(message.appname, 'NAT')
843             self.assertEqual(message.msgid, 'SADD' if is_add else 'SDEL')
844             sd_params = message.sd.get('nsess')
845             self.assertTrue(sd_params is not None)
846             if is_ip6:
847                 self.assertEqual(sd_params.get('IATYP'), 'IPv6')
848                 self.assertEqual(sd_params.get('ISADDR'), self.pg0.remote_ip6)
849             else:
850                 self.assertEqual(sd_params.get('IATYP'), 'IPv4')
851                 self.assertEqual(sd_params.get('ISADDR'), self.pg0.remote_ip4)
852                 self.assertTrue(sd_params.get('SSUBIX') is not None)
853             self.assertEqual(sd_params.get('ISPORT'), "%d" % self.tcp_port_in)
854             self.assertEqual(sd_params.get('XATYP'), 'IPv4')
855             self.assertEqual(sd_params.get('XSADDR'), self.nat_addr)
856             self.assertEqual(sd_params.get('XSPORT'), "%d" % self.tcp_port_out)
857             self.assertEqual(sd_params.get('PROTO'), "%d" % IP_PROTOS.tcp)
858             self.assertEqual(sd_params.get('SVLAN'), '0')
859             self.assertEqual(sd_params.get('XDADDR'), self.pg1.remote_ip4)
860             self.assertEqual(sd_params.get('XDPORT'),
861                              "%d" % self.tcp_external_port)
862
863     def verify_mss_value(self, pkt, mss):
864         """
865         Verify TCP MSS value
866
867         :param pkt:
868         :param mss:
869         """
870         if not pkt.haslayer(IP) or not pkt.haslayer(TCP):
871             raise TypeError("Not a TCP/IP packet")
872
873         for option in pkt[TCP].options:
874             if option[0] == 'MSS':
875                 self.assertEqual(option[1], mss)
876                 self.assert_tcp_checksum_valid(pkt)
877
878     @staticmethod
879     def proto2layer(proto):
880         if proto == IP_PROTOS.tcp:
881             return TCP
882         elif proto == IP_PROTOS.udp:
883             return UDP
884         elif proto == IP_PROTOS.icmp:
885             return ICMP
886         else:
887             raise Exception("Unsupported protocol")
888
889     def frag_in_order(self, proto=IP_PROTOS.tcp, dont_translate=False,
890                       ignore_port=False):
891         layer = self.proto2layer(proto)
892
893         if proto == IP_PROTOS.tcp:
894             data = b"A" * 4 + b"B" * 16 + b"C" * 3
895         else:
896             data = b"A" * 16 + b"B" * 16 + b"C" * 3
897         self.port_in = random.randint(1025, 65535)
898
899         # in2out
900         pkts = self.create_stream_frag(self.pg0, self.pg1.remote_ip4,
901                                        self.port_in, 20, data, proto)
902         self.pg0.add_stream(pkts)
903         self.pg_enable_capture(self.pg_interfaces)
904         self.pg_start()
905         frags = self.pg1.get_capture(len(pkts))
906         if not dont_translate:
907             p = self.reass_frags_and_verify(frags,
908                                             self.nat_addr,
909                                             self.pg1.remote_ip4)
910         else:
911             p = self.reass_frags_and_verify(frags,
912                                             self.pg0.remote_ip4,
913                                             self.pg1.remote_ip4)
914         if proto != IP_PROTOS.icmp:
915             if not dont_translate:
916                 self.assertEqual(p[layer].dport, 20)
917                 if not ignore_port:
918                     self.assertNotEqual(p[layer].sport, self.port_in)
919             else:
920                 self.assertEqual(p[layer].sport, self.port_in)
921         else:
922             if not ignore_port:
923                 if not dont_translate:
924                     self.assertNotEqual(p[layer].id, self.port_in)
925                 else:
926                     self.assertEqual(p[layer].id, self.port_in)
927         self.assertEqual(data, p[Raw].load)
928
929         # out2in
930         if not dont_translate:
931             dst_addr = self.nat_addr
932         else:
933             dst_addr = self.pg0.remote_ip4
934         if proto != IP_PROTOS.icmp:
935             sport = 20
936             dport = p[layer].sport
937         else:
938             sport = p[layer].id
939             dport = 0
940         pkts = self.create_stream_frag(self.pg1, dst_addr, sport, dport, data,
941                                        proto, echo_reply=True)
942         self.pg1.add_stream(pkts)
943         self.pg_enable_capture(self.pg_interfaces)
944         self.pg_start()
945         frags = self.pg0.get_capture(len(pkts))
946         p = self.reass_frags_and_verify(frags,
947                                         self.pg1.remote_ip4,
948                                         self.pg0.remote_ip4)
949         if proto != IP_PROTOS.icmp:
950             self.assertEqual(p[layer].sport, 20)
951             self.assertEqual(p[layer].dport, self.port_in)
952         else:
953             self.assertEqual(p[layer].id, self.port_in)
954         self.assertEqual(data, p[Raw].load)
955
956     def frag_in_order_in_plus_out(self, proto=IP_PROTOS.tcp):
957         layer = self.proto2layer(proto)
958
959         if proto == IP_PROTOS.tcp:
960             data = b"A" * 4 + b"B" * 16 + b"C" * 3
961         else:
962             data = b"A" * 16 + b"B" * 16 + b"C" * 3
963         self.port_in = random.randint(1025, 65535)
964
965         for i in range(2):
966             # out2in
967             pkts = self.create_stream_frag(self.pg0, self.server_out_addr,
968                                            self.port_in, self.server_out_port,
969                                            data, proto)
970             self.pg0.add_stream(pkts)
971             self.pg_enable_capture(self.pg_interfaces)
972             self.pg_start()
973             frags = self.pg1.get_capture(len(pkts))
974             p = self.reass_frags_and_verify(frags,
975                                             self.pg0.remote_ip4,
976                                             self.server_in_addr)
977             if proto != IP_PROTOS.icmp:
978                 self.assertEqual(p[layer].sport, self.port_in)
979                 self.assertEqual(p[layer].dport, self.server_in_port)
980             else:
981                 self.assertEqual(p[layer].id, self.port_in)
982             self.assertEqual(data, p[Raw].load)
983
984             # in2out
985             if proto != IP_PROTOS.icmp:
986                 pkts = self.create_stream_frag(self.pg1, self.pg0.remote_ip4,
987                                                self.server_in_port,
988                                                p[layer].sport, data, proto)
989             else:
990                 pkts = self.create_stream_frag(self.pg1, self.pg0.remote_ip4,
991                                                p[layer].id, 0, data, proto,
992                                                echo_reply=True)
993             self.pg1.add_stream(pkts)
994             self.pg_enable_capture(self.pg_interfaces)
995             self.pg_start()
996             frags = self.pg0.get_capture(len(pkts))
997             p = self.reass_frags_and_verify(frags,
998                                             self.server_out_addr,
999                                             self.pg0.remote_ip4)
1000             if proto != IP_PROTOS.icmp:
1001                 self.assertEqual(p[layer].sport, self.server_out_port)
1002                 self.assertEqual(p[layer].dport, self.port_in)
1003             else:
1004                 self.assertEqual(p[layer].id, self.port_in)
1005             self.assertEqual(data, p[Raw].load)
1006
1007     def reass_hairpinning(self, proto=IP_PROTOS.tcp, ignore_port=False):
1008         layer = self.proto2layer(proto)
1009
1010         if proto == IP_PROTOS.tcp:
1011             data = b"A" * 4 + b"B" * 16 + b"C" * 3
1012         else:
1013             data = b"A" * 16 + b"B" * 16 + b"C" * 3
1014
1015         # send packet from host to server
1016         pkts = self.create_stream_frag(self.pg0,
1017                                        self.nat_addr,
1018                                        self.host_in_port,
1019                                        self.server_out_port,
1020                                        data,
1021                                        proto)
1022         self.pg0.add_stream(pkts)
1023         self.pg_enable_capture(self.pg_interfaces)
1024         self.pg_start()
1025         frags = self.pg0.get_capture(len(pkts))
1026         p = self.reass_frags_and_verify(frags,
1027                                         self.nat_addr,
1028                                         self.server.ip4)
1029         if proto != IP_PROTOS.icmp:
1030             if not ignore_port:
1031                 self.assertNotEqual(p[layer].sport, self.host_in_port)
1032             self.assertEqual(p[layer].dport, self.server_in_port)
1033         else:
1034             if not ignore_port:
1035                 self.assertNotEqual(p[layer].id, self.host_in_port)
1036         self.assertEqual(data, p[Raw].load)
1037
1038     def frag_out_of_order(self, proto=IP_PROTOS.tcp, dont_translate=False,
1039                           ignore_port=False):
1040         layer = self.proto2layer(proto)
1041
1042         if proto == IP_PROTOS.tcp:
1043             data = b"A" * 4 + b"B" * 16 + b"C" * 3
1044         else:
1045             data = b"A" * 16 + b"B" * 16 + b"C" * 3
1046         self.port_in = random.randint(1025, 65535)
1047
1048         for i in range(2):
1049             # in2out
1050             pkts = self.create_stream_frag(self.pg0, self.pg1.remote_ip4,
1051                                            self.port_in, 20, data, proto)
1052             pkts.reverse()
1053             self.pg0.add_stream(pkts)
1054             self.pg_enable_capture(self.pg_interfaces)
1055             self.pg_start()
1056             frags = self.pg1.get_capture(len(pkts))
1057             if not dont_translate:
1058                 p = self.reass_frags_and_verify(frags,
1059                                                 self.nat_addr,
1060                                                 self.pg1.remote_ip4)
1061             else:
1062                 p = self.reass_frags_and_verify(frags,
1063                                                 self.pg0.remote_ip4,
1064                                                 self.pg1.remote_ip4)
1065             if proto != IP_PROTOS.icmp:
1066                 if not dont_translate:
1067                     self.assertEqual(p[layer].dport, 20)
1068                     if not ignore_port:
1069                         self.assertNotEqual(p[layer].sport, self.port_in)
1070                 else:
1071                     self.assertEqual(p[layer].sport, self.port_in)
1072             else:
1073                 if not ignore_port:
1074                     if not dont_translate:
1075                         self.assertNotEqual(p[layer].id, self.port_in)
1076                     else:
1077                         self.assertEqual(p[layer].id, self.port_in)
1078             self.assertEqual(data, p[Raw].load)
1079
1080             # out2in
1081             if not dont_translate:
1082                 dst_addr = self.nat_addr
1083             else:
1084                 dst_addr = self.pg0.remote_ip4
1085             if proto != IP_PROTOS.icmp:
1086                 sport = 20
1087                 dport = p[layer].sport
1088             else:
1089                 sport = p[layer].id
1090                 dport = 0
1091             pkts = self.create_stream_frag(self.pg1, dst_addr, sport, dport,
1092                                            data, proto, echo_reply=True)
1093             pkts.reverse()
1094             self.pg1.add_stream(pkts)
1095             self.pg_enable_capture(self.pg_interfaces)
1096             self.pg_start()
1097             frags = self.pg0.get_capture(len(pkts))
1098             p = self.reass_frags_and_verify(frags,
1099                                             self.pg1.remote_ip4,
1100                                             self.pg0.remote_ip4)
1101             if proto != IP_PROTOS.icmp:
1102                 self.assertEqual(p[layer].sport, 20)
1103                 self.assertEqual(p[layer].dport, self.port_in)
1104             else:
1105                 self.assertEqual(p[layer].id, self.port_in)
1106             self.assertEqual(data, p[Raw].load)
1107
1108     def frag_out_of_order_in_plus_out(self, proto=IP_PROTOS.tcp):
1109         layer = self.proto2layer(proto)
1110
1111         if proto == IP_PROTOS.tcp:
1112             data = b"A" * 4 + b"B" * 16 + b"C" * 3
1113         else:
1114             data = b"A" * 16 + b"B" * 16 + b"C" * 3
1115         self.port_in = random.randint(1025, 65535)
1116
1117         for i in range(2):
1118             # out2in
1119             pkts = self.create_stream_frag(self.pg0, self.server_out_addr,
1120                                            self.port_in, self.server_out_port,
1121                                            data, proto)
1122             pkts.reverse()
1123             self.pg0.add_stream(pkts)
1124             self.pg_enable_capture(self.pg_interfaces)
1125             self.pg_start()
1126             frags = self.pg1.get_capture(len(pkts))
1127             p = self.reass_frags_and_verify(frags,
1128                                             self.pg0.remote_ip4,
1129                                             self.server_in_addr)
1130             if proto != IP_PROTOS.icmp:
1131                 self.assertEqual(p[layer].dport, self.server_in_port)
1132                 self.assertEqual(p[layer].sport, self.port_in)
1133                 self.assertEqual(p[layer].dport, self.server_in_port)
1134             else:
1135                 self.assertEqual(p[layer].id, self.port_in)
1136             self.assertEqual(data, p[Raw].load)
1137
1138             # in2out
1139             if proto != IP_PROTOS.icmp:
1140                 pkts = self.create_stream_frag(self.pg1, self.pg0.remote_ip4,
1141                                                self.server_in_port,
1142                                                p[layer].sport, data, proto)
1143             else:
1144                 pkts = self.create_stream_frag(self.pg1, self.pg0.remote_ip4,
1145                                                p[layer].id, 0, data, proto,
1146                                                echo_reply=True)
1147             pkts.reverse()
1148             self.pg1.add_stream(pkts)
1149             self.pg_enable_capture(self.pg_interfaces)
1150             self.pg_start()
1151             frags = self.pg0.get_capture(len(pkts))
1152             p = self.reass_frags_and_verify(frags,
1153                                             self.server_out_addr,
1154                                             self.pg0.remote_ip4)
1155             if proto != IP_PROTOS.icmp:
1156                 self.assertEqual(p[layer].sport, self.server_out_port)
1157                 self.assertEqual(p[layer].dport, self.port_in)
1158             else:
1159                 self.assertEqual(p[layer].id, self.port_in)
1160             self.assertEqual(data, p[Raw].load)
1161
1162
1163 class TestNATMisc(MethodHolder):
1164     """ NAT misc Test Cases """
1165
1166     max_translations = 10240
1167     max_users = 10240
1168
1169     def setUp(self):
1170         super(TestNATMisc, self).setUp()
1171         self.vapi.nat44_plugin_enable_disable(
1172             sessions=self.max_translations,
1173             users=self.max_users, enable=1)
1174
1175     def tearDown(self):
1176         super(TestNATMisc, self).tearDown()
1177         if not self.vpp_dead:
1178             self.vapi.nat44_plugin_enable_disable(enable=0)
1179             self.vapi.cli("clear logging")
1180
1181     def test_show_max_translations(self):
1182         """ API test - max translations per thread """
1183         nat_config = self.vapi.nat_show_config_2()
1184         self.assertEqual(self.max_translations,
1185                          nat_config.max_translations_per_thread)
1186
1187
1188 class TestNAT44(MethodHolder):
1189     """ NAT44 Test Cases """
1190
1191     max_translations = 10240
1192     max_users = 10240
1193
1194     @classmethod
1195     def setUpClass(cls):
1196         super(TestNAT44, cls).setUpClass()
1197         cls.vapi.cli("set log class nat level debug")
1198
1199         cls.tcp_port_in = 6303
1200         cls.tcp_port_out = 6303
1201         cls.udp_port_in = 6304
1202         cls.udp_port_out = 6304
1203         cls.icmp_id_in = 6305
1204         cls.icmp_id_out = 6305
1205         cls.nat_addr = '10.0.0.3'
1206         cls.ipfix_src_port = 4739
1207         cls.ipfix_domain_id = 1
1208         cls.tcp_external_port = 80
1209         cls.udp_external_port = 69
1210
1211         cls.create_pg_interfaces(range(10))
1212         cls.interfaces = list(cls.pg_interfaces[0:4])
1213
1214         for i in cls.interfaces:
1215             i.admin_up()
1216             i.config_ip4()
1217             i.resolve_arp()
1218
1219         cls.pg0.generate_remote_hosts(3)
1220         cls.pg0.configure_ipv4_neighbors()
1221
1222         cls.pg1.generate_remote_hosts(1)
1223         cls.pg1.configure_ipv4_neighbors()
1224
1225         cls.overlapping_interfaces = list(list(cls.pg_interfaces[4:7]))
1226         cls.vapi.ip_table_add_del(is_add=1, table={'table_id': 10})
1227         cls.vapi.ip_table_add_del(is_add=1, table={'table_id': 20})
1228
1229         cls.pg4._local_ip4 = "172.16.255.1"
1230         cls.pg4._remote_hosts[0]._ip4 = "172.16.255.2"
1231         cls.pg4.set_table_ip4(10)
1232         cls.pg5._local_ip4 = "172.17.255.3"
1233         cls.pg5._remote_hosts[0]._ip4 = "172.17.255.4"
1234         cls.pg5.set_table_ip4(10)
1235         cls.pg6._local_ip4 = "172.16.255.1"
1236         cls.pg6._remote_hosts[0]._ip4 = "172.16.255.2"
1237         cls.pg6.set_table_ip4(20)
1238         for i in cls.overlapping_interfaces:
1239             i.config_ip4()
1240             i.admin_up()
1241             i.resolve_arp()
1242
1243         cls.pg7.admin_up()
1244         cls.pg8.admin_up()
1245
1246         cls.pg9.generate_remote_hosts(2)
1247         cls.pg9.config_ip4()
1248         cls.vapi.sw_interface_add_del_address(
1249             sw_if_index=cls.pg9.sw_if_index,
1250             prefix="10.0.0.1/24")
1251
1252         cls.pg9.admin_up()
1253         cls.pg9.resolve_arp()
1254         cls.pg9._remote_hosts[1]._ip4 = cls.pg9._remote_hosts[0]._ip4
1255         cls.pg4._remote_ip4 = cls.pg9._remote_hosts[0]._ip4 = "10.0.0.2"
1256         cls.pg9.resolve_arp()
1257
1258     def setUp(self):
1259         super(TestNAT44, self).setUp()
1260         self.vapi.nat44_plugin_enable_disable(
1261             sessions=self.max_translations,
1262             users=self.max_users, enable=1)
1263
1264     @classmethod
1265     def tearDownClass(cls):
1266         super(TestNAT44, cls).tearDownClass()
1267
1268     def tearDown(self):
1269         super(TestNAT44, self).tearDown()
1270         if not self.vpp_dead:
1271             self.vapi.nat_ipfix_enable_disable(domain_id=self.ipfix_domain_id,
1272                                                src_port=self.ipfix_src_port,
1273                                                enable=0)
1274             self.ipfix_src_port = 4739
1275             self.ipfix_domain_id = 1
1276
1277             self.vapi.nat44_plugin_enable_disable(enable=0)
1278             self.vapi.cli("clear logging")
1279
1280     def test_clear_sessions(self):
1281         """ NAT44 session clearing test """
1282
1283         self.nat44_add_address(self.nat_addr)
1284         flags = self.config_flags.NAT_IS_INSIDE
1285         self.vapi.nat44_interface_add_del_feature(
1286             sw_if_index=self.pg0.sw_if_index,
1287             flags=flags, is_add=1)
1288         self.vapi.nat44_interface_add_del_feature(
1289             sw_if_index=self.pg1.sw_if_index,
1290             is_add=1)
1291
1292         nat_config = self.vapi.nat_show_config()
1293         self.assertEqual(0, nat_config.endpoint_dependent)
1294
1295         pkts = self.create_stream_in(self.pg0, self.pg1)
1296         self.pg0.add_stream(pkts)
1297         self.pg_enable_capture(self.pg_interfaces)
1298         self.pg_start()
1299         capture = self.pg1.get_capture(len(pkts))
1300         self.verify_capture_out(capture)
1301
1302         sessions = self.statistics.get_counter('/nat44/total-sessions')
1303         self.assertTrue(sessions[0][0] > 0)
1304         self.logger.info("sessions before clearing: %s" % sessions[0][0])
1305
1306         self.vapi.cli("clear nat44 sessions")
1307
1308         sessions = self.statistics.get_counter('/nat44/total-sessions')
1309         self.assertEqual(sessions[0][0], 0)
1310         self.logger.info("sessions after clearing: %s" % sessions[0][0])
1311
1312     def test_dynamic(self):
1313         """ NAT44 dynamic translation test """
1314         self.nat44_add_address(self.nat_addr)
1315         flags = self.config_flags.NAT_IS_INSIDE
1316         self.vapi.nat44_interface_add_del_feature(
1317             sw_if_index=self.pg0.sw_if_index,
1318             flags=flags, is_add=1)
1319         self.vapi.nat44_interface_add_del_feature(
1320             sw_if_index=self.pg1.sw_if_index,
1321             is_add=1)
1322
1323         # in2out
1324         tcpn = self.statistics.get_counter('/nat44/in2out/slowpath/tcp')[0]
1325         udpn = self.statistics.get_counter('/nat44/in2out/slowpath/udp')[0]
1326         icmpn = self.statistics.get_counter('/nat44/in2out/slowpath/icmp')[0]
1327         drops = self.statistics.get_counter('/nat44/in2out/slowpath/drops')[0]
1328
1329         pkts = self.create_stream_in(self.pg0, self.pg1)
1330         self.pg0.add_stream(pkts)
1331         self.pg_enable_capture(self.pg_interfaces)
1332         self.pg_start()
1333         capture = self.pg1.get_capture(len(pkts))
1334         self.verify_capture_out(capture)
1335
1336         if_idx = self.pg0.sw_if_index
1337         cnt = self.statistics.get_counter('/nat44/in2out/slowpath/tcp')[0]
1338         self.assertEqual(cnt[if_idx] - tcpn[if_idx], 2)
1339         cnt = self.statistics.get_counter('/nat44/in2out/slowpath/udp')[0]
1340         self.assertEqual(cnt[if_idx] - udpn[if_idx], 1)
1341         cnt = self.statistics.get_counter('/nat44/in2out/slowpath/icmp')[0]
1342         self.assertEqual(cnt[if_idx] - icmpn[if_idx], 1)
1343         cnt = self.statistics.get_counter('/nat44/in2out/slowpath/drops')[0]
1344         self.assertEqual(cnt[if_idx] - drops[if_idx], 0)
1345
1346         # out2in
1347         tcpn = self.statistics.get_counter('/nat44/out2in/slowpath/tcp')[0]
1348         udpn = self.statistics.get_counter('/nat44/out2in/slowpath/udp')[0]
1349         icmpn = self.statistics.get_counter('/nat44/out2in/slowpath/icmp')[0]
1350         drops = self.statistics.get_counter('/nat44/out2in/slowpath/drops')[0]
1351
1352         pkts = self.create_stream_out(self.pg1)
1353         self.pg1.add_stream(pkts)
1354         self.pg_enable_capture(self.pg_interfaces)
1355         self.pg_start()
1356         capture = self.pg0.get_capture(len(pkts))
1357         self.verify_capture_in(capture, self.pg0)
1358
1359         if_idx = self.pg1.sw_if_index
1360         cnt = self.statistics.get_counter('/nat44/out2in/slowpath/tcp')[0]
1361         self.assertEqual(cnt[if_idx] - tcpn[if_idx], 2)
1362         cnt = self.statistics.get_counter('/nat44/out2in/slowpath/udp')[0]
1363         self.assertEqual(cnt[if_idx] - udpn[if_idx], 1)
1364         cnt = self.statistics.get_counter('/nat44/out2in/slowpath/icmp')[0]
1365         self.assertEqual(cnt[if_idx] - icmpn[if_idx], 1)
1366         cnt = self.statistics.get_counter('/nat44/out2in/slowpath/drops')[0]
1367         self.assertEqual(cnt[if_idx] - drops[if_idx], 0)
1368
1369         users = self.statistics.get_counter('/nat44/total-users')
1370         self.assertEqual(users[0][0], 1)
1371         sessions = self.statistics.get_counter('/nat44/total-sessions')
1372         self.assertEqual(sessions[0][0], 3)
1373
1374     def test_dynamic_icmp_errors_in2out_ttl_1(self):
1375         """ NAT44 handling of client packets with TTL=1 """
1376
1377         self.nat44_add_address(self.nat_addr)
1378         flags = self.config_flags.NAT_IS_INSIDE
1379         self.vapi.nat44_interface_add_del_feature(
1380             sw_if_index=self.pg0.sw_if_index,
1381             flags=flags, is_add=1)
1382         self.vapi.nat44_interface_add_del_feature(
1383             sw_if_index=self.pg1.sw_if_index,
1384             is_add=1)
1385
1386         # Client side - generate traffic
1387         pkts = self.create_stream_in(self.pg0, self.pg1, ttl=1)
1388         self.pg0.add_stream(pkts)
1389         self.pg_enable_capture(self.pg_interfaces)
1390         self.pg_start()
1391
1392         # Client side - verify ICMP type 11 packets
1393         capture = self.pg0.get_capture(len(pkts))
1394         self.verify_capture_in_with_icmp_errors(capture, self.pg0)
1395
1396     def test_dynamic_icmp_errors_out2in_ttl_1(self):
1397         """ NAT44 handling of server packets with TTL=1 """
1398
1399         self.nat44_add_address(self.nat_addr)
1400         flags = self.config_flags.NAT_IS_INSIDE
1401         self.vapi.nat44_interface_add_del_feature(
1402             sw_if_index=self.pg0.sw_if_index,
1403             flags=flags, is_add=1)
1404         self.vapi.nat44_interface_add_del_feature(
1405             sw_if_index=self.pg1.sw_if_index,
1406             is_add=1)
1407
1408         # Client side - create sessions
1409         pkts = self.create_stream_in(self.pg0, self.pg1)
1410         self.pg0.add_stream(pkts)
1411         self.pg_enable_capture(self.pg_interfaces)
1412         self.pg_start()
1413
1414         # Server side - generate traffic
1415         capture = self.pg1.get_capture(len(pkts))
1416         self.verify_capture_out(capture)
1417         pkts = self.create_stream_out(self.pg1, ttl=1)
1418         self.pg1.add_stream(pkts)
1419         self.pg_enable_capture(self.pg_interfaces)
1420         self.pg_start()
1421
1422         # Server side - verify ICMP type 11 packets
1423         capture = self.pg1.get_capture(len(pkts))
1424         self.verify_capture_out_with_icmp_errors(capture,
1425                                                  src_ip=self.pg1.local_ip4)
1426
1427     def test_dynamic_icmp_errors_in2out_ttl_2(self):
1428         """ NAT44 handling of error responses to client packets with TTL=2 """
1429
1430         self.nat44_add_address(self.nat_addr)
1431         flags = self.config_flags.NAT_IS_INSIDE
1432         self.vapi.nat44_interface_add_del_feature(
1433             sw_if_index=self.pg0.sw_if_index,
1434             flags=flags, is_add=1)
1435         self.vapi.nat44_interface_add_del_feature(
1436             sw_if_index=self.pg1.sw_if_index,
1437             is_add=1)
1438
1439         # Client side - generate traffic
1440         pkts = self.create_stream_in(self.pg0, self.pg1, ttl=2)
1441         self.pg0.add_stream(pkts)
1442         self.pg_enable_capture(self.pg_interfaces)
1443         self.pg_start()
1444
1445         # Server side - simulate ICMP type 11 response
1446         capture = self.pg1.get_capture(len(pkts))
1447         pkts = [Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
1448                 IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
1449                 ICMP(type=11) / packet[IP] for packet in capture]
1450         self.pg1.add_stream(pkts)
1451         self.pg_enable_capture(self.pg_interfaces)
1452         self.pg_start()
1453
1454         # Client side - verify ICMP type 11 packets
1455         capture = self.pg0.get_capture(len(pkts))
1456         self.verify_capture_in_with_icmp_errors(capture, self.pg0)
1457
1458     def test_dynamic_icmp_errors_out2in_ttl_2(self):
1459         """ NAT44 handling of error responses to server packets with TTL=2 """
1460
1461         self.nat44_add_address(self.nat_addr)
1462         flags = self.config_flags.NAT_IS_INSIDE
1463         self.vapi.nat44_interface_add_del_feature(
1464             sw_if_index=self.pg0.sw_if_index,
1465             flags=flags, is_add=1)
1466         self.vapi.nat44_interface_add_del_feature(
1467             sw_if_index=self.pg1.sw_if_index,
1468             is_add=1)
1469
1470         # Client side - create sessions
1471         pkts = self.create_stream_in(self.pg0, self.pg1)
1472         self.pg0.add_stream(pkts)
1473         self.pg_enable_capture(self.pg_interfaces)
1474         self.pg_start()
1475
1476         # Server side - generate traffic
1477         capture = self.pg1.get_capture(len(pkts))
1478         self.verify_capture_out(capture)
1479         pkts = self.create_stream_out(self.pg1, ttl=2)
1480         self.pg1.add_stream(pkts)
1481         self.pg_enable_capture(self.pg_interfaces)
1482         self.pg_start()
1483
1484         # Client side - simulate ICMP type 11 response
1485         capture = self.pg0.get_capture(len(pkts))
1486         pkts = [Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
1487                 IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
1488                 ICMP(type=11) / packet[IP] for packet in capture]
1489         self.pg0.add_stream(pkts)
1490         self.pg_enable_capture(self.pg_interfaces)
1491         self.pg_start()
1492
1493         # Server side - verify ICMP type 11 packets
1494         capture = self.pg1.get_capture(len(pkts))
1495         self.verify_capture_out_with_icmp_errors(capture)
1496
1497     def test_ping_out_interface_from_outside(self):
1498         """ Ping NAT44 out interface from outside network """
1499
1500         self.nat44_add_address(self.nat_addr)
1501         flags = self.config_flags.NAT_IS_INSIDE
1502         self.vapi.nat44_interface_add_del_feature(
1503             sw_if_index=self.pg0.sw_if_index,
1504             flags=flags, is_add=1)
1505         self.vapi.nat44_interface_add_del_feature(
1506             sw_if_index=self.pg1.sw_if_index,
1507             is_add=1)
1508
1509         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
1510              IP(src=self.pg1.remote_ip4, dst=self.pg1.local_ip4) /
1511              ICMP(id=self.icmp_id_out, type='echo-request'))
1512         pkts = [p]
1513         self.pg1.add_stream(pkts)
1514         self.pg_enable_capture(self.pg_interfaces)
1515         self.pg_start()
1516         capture = self.pg1.get_capture(len(pkts))
1517         packet = capture[0]
1518         try:
1519             self.assertEqual(packet[IP].src, self.pg1.local_ip4)
1520             self.assertEqual(packet[IP].dst, self.pg1.remote_ip4)
1521             self.assertEqual(packet[ICMP].id, self.icmp_id_in)
1522             self.assertEqual(packet[ICMP].type, 0)  # echo reply
1523         except:
1524             self.logger.error(ppp("Unexpected or invalid packet "
1525                                   "(outside network):", packet))
1526             raise
1527
1528     def test_ping_internal_host_from_outside(self):
1529         """ Ping internal host from outside network """
1530
1531         self.nat44_add_static_mapping(self.pg0.remote_ip4, self.nat_addr)
1532         flags = self.config_flags.NAT_IS_INSIDE
1533         self.vapi.nat44_interface_add_del_feature(
1534             sw_if_index=self.pg0.sw_if_index,
1535             flags=flags, is_add=1)
1536         self.vapi.nat44_interface_add_del_feature(
1537             sw_if_index=self.pg1.sw_if_index,
1538             is_add=1)
1539
1540         # out2in
1541         pkt = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
1542                IP(src=self.pg1.remote_ip4, dst=self.nat_addr, ttl=64) /
1543                ICMP(id=self.icmp_id_out, type='echo-request'))
1544         self.pg1.add_stream(pkt)
1545         self.pg_enable_capture(self.pg_interfaces)
1546         self.pg_start()
1547         capture = self.pg0.get_capture(1)
1548         self.verify_capture_in(capture, self.pg0)
1549         self.assert_equal(capture[0][IP].proto, IP_PROTOS.icmp)
1550
1551         # in2out
1552         pkt = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
1553                IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4, ttl=64) /
1554                ICMP(id=self.icmp_id_in, type='echo-reply'))
1555         self.pg0.add_stream(pkt)
1556         self.pg_enable_capture(self.pg_interfaces)
1557         self.pg_start()
1558         capture = self.pg1.get_capture(1)
1559         self.verify_capture_out(capture, same_port=True)
1560         self.assert_equal(capture[0][IP].proto, IP_PROTOS.icmp)
1561
1562     def test_forwarding(self):
1563         """ NAT44 forwarding test """
1564
1565         flags = self.config_flags.NAT_IS_INSIDE
1566         self.vapi.nat44_interface_add_del_feature(
1567             sw_if_index=self.pg0.sw_if_index,
1568             flags=flags, is_add=1)
1569         self.vapi.nat44_interface_add_del_feature(
1570             sw_if_index=self.pg1.sw_if_index,
1571             is_add=1)
1572         self.vapi.nat44_forwarding_enable_disable(enable=1)
1573
1574         real_ip = self.pg0.remote_ip4
1575         alias_ip = self.nat_addr
1576         flags = self.config_flags.NAT_IS_ADDR_ONLY
1577         self.vapi.nat44_add_del_static_mapping(is_add=1,
1578                                                local_ip_address=real_ip,
1579                                                external_ip_address=alias_ip,
1580                                                external_sw_if_index=0xFFFFFFFF,
1581                                                flags=flags)
1582
1583         try:
1584             # static mapping match
1585
1586             pkts = self.create_stream_out(self.pg1)
1587             self.pg1.add_stream(pkts)
1588             self.pg_enable_capture(self.pg_interfaces)
1589             self.pg_start()
1590             capture = self.pg0.get_capture(len(pkts))
1591             self.verify_capture_in(capture, self.pg0)
1592
1593             pkts = self.create_stream_in(self.pg0, self.pg1)
1594             self.pg0.add_stream(pkts)
1595             self.pg_enable_capture(self.pg_interfaces)
1596             self.pg_start()
1597             capture = self.pg1.get_capture(len(pkts))
1598             self.verify_capture_out(capture, same_port=True)
1599
1600             # no static mapping match
1601
1602             host0 = self.pg0.remote_hosts[0]
1603             self.pg0.remote_hosts[0] = self.pg0.remote_hosts[1]
1604             try:
1605                 pkts = self.create_stream_out(self.pg1,
1606                                               dst_ip=self.pg0.remote_ip4,
1607                                               use_inside_ports=True)
1608                 self.pg1.add_stream(pkts)
1609                 self.pg_enable_capture(self.pg_interfaces)
1610                 self.pg_start()
1611                 capture = self.pg0.get_capture(len(pkts))
1612                 self.verify_capture_in(capture, self.pg0)
1613
1614                 pkts = self.create_stream_in(self.pg0, self.pg1)
1615                 self.pg0.add_stream(pkts)
1616                 self.pg_enable_capture(self.pg_interfaces)
1617                 self.pg_start()
1618                 capture = self.pg1.get_capture(len(pkts))
1619                 self.verify_capture_out(capture, nat_ip=self.pg0.remote_ip4,
1620                                         same_port=True)
1621             finally:
1622                 self.pg0.remote_hosts[0] = host0
1623
1624         finally:
1625             self.vapi.nat44_forwarding_enable_disable(enable=0)
1626             flags = self.config_flags.NAT_IS_ADDR_ONLY
1627             self.vapi.nat44_add_del_static_mapping(
1628                 is_add=0,
1629                 local_ip_address=real_ip,
1630                 external_ip_address=alias_ip,
1631                 external_sw_if_index=0xFFFFFFFF,
1632                 flags=flags)
1633
1634     def test_static_in(self):
1635         """ 1:1 NAT initialized from inside network """
1636
1637         nat_ip = "10.0.0.10"
1638         self.tcp_port_out = 6303
1639         self.udp_port_out = 6304
1640         self.icmp_id_out = 6305
1641
1642         self.nat44_add_static_mapping(self.pg0.remote_ip4, nat_ip)
1643         flags = self.config_flags.NAT_IS_INSIDE
1644         self.vapi.nat44_interface_add_del_feature(
1645             sw_if_index=self.pg0.sw_if_index,
1646             flags=flags, is_add=1)
1647         self.vapi.nat44_interface_add_del_feature(
1648             sw_if_index=self.pg1.sw_if_index,
1649             is_add=1)
1650         sm = self.vapi.nat44_static_mapping_dump()
1651         self.assertEqual(len(sm), 1)
1652         self.assertEqual(sm[0].tag, '')
1653         self.assertEqual(sm[0].protocol, 0)
1654         self.assertEqual(sm[0].local_port, 0)
1655         self.assertEqual(sm[0].external_port, 0)
1656
1657         # in2out
1658         pkts = self.create_stream_in(self.pg0, self.pg1)
1659         self.pg0.add_stream(pkts)
1660         self.pg_enable_capture(self.pg_interfaces)
1661         self.pg_start()
1662         capture = self.pg1.get_capture(len(pkts))
1663         self.verify_capture_out(capture, nat_ip, True)
1664
1665         # out2in
1666         pkts = self.create_stream_out(self.pg1, nat_ip)
1667         self.pg1.add_stream(pkts)
1668         self.pg_enable_capture(self.pg_interfaces)
1669         self.pg_start()
1670         capture = self.pg0.get_capture(len(pkts))
1671         self.verify_capture_in(capture, self.pg0)
1672
1673     def test_static_out(self):
1674         """ 1:1 NAT initialized from outside network """
1675
1676         nat_ip = "10.0.0.20"
1677         self.tcp_port_out = 6303
1678         self.udp_port_out = 6304
1679         self.icmp_id_out = 6305
1680         tag = "testTAG"
1681
1682         self.nat44_add_static_mapping(self.pg0.remote_ip4, nat_ip, tag=tag)
1683         flags = self.config_flags.NAT_IS_INSIDE
1684         self.vapi.nat44_interface_add_del_feature(
1685             sw_if_index=self.pg0.sw_if_index,
1686             flags=flags, is_add=1)
1687         self.vapi.nat44_interface_add_del_feature(
1688             sw_if_index=self.pg1.sw_if_index,
1689             is_add=1)
1690         sm = self.vapi.nat44_static_mapping_dump()
1691         self.assertEqual(len(sm), 1)
1692         self.assertEqual(sm[0].tag, tag)
1693
1694         # out2in
1695         pkts = self.create_stream_out(self.pg1, nat_ip)
1696         self.pg1.add_stream(pkts)
1697         self.pg_enable_capture(self.pg_interfaces)
1698         self.pg_start()
1699         capture = self.pg0.get_capture(len(pkts))
1700         self.verify_capture_in(capture, self.pg0)
1701
1702         # in2out
1703         pkts = self.create_stream_in(self.pg0, self.pg1)
1704         self.pg0.add_stream(pkts)
1705         self.pg_enable_capture(self.pg_interfaces)
1706         self.pg_start()
1707         capture = self.pg1.get_capture(len(pkts))
1708         self.verify_capture_out(capture, nat_ip, True)
1709
1710     def test_static_with_port_in(self):
1711         """ 1:1 NAPT initialized from inside network """
1712
1713         self.tcp_port_out = 3606
1714         self.udp_port_out = 3607
1715         self.icmp_id_out = 3608
1716
1717         self.nat44_add_address(self.nat_addr)
1718         self.nat44_add_static_mapping(self.pg0.remote_ip4, self.nat_addr,
1719                                       self.tcp_port_in, self.tcp_port_out,
1720                                       proto=IP_PROTOS.tcp)
1721         self.nat44_add_static_mapping(self.pg0.remote_ip4, self.nat_addr,
1722                                       self.udp_port_in, self.udp_port_out,
1723                                       proto=IP_PROTOS.udp)
1724         self.nat44_add_static_mapping(self.pg0.remote_ip4, self.nat_addr,
1725                                       self.icmp_id_in, self.icmp_id_out,
1726                                       proto=IP_PROTOS.icmp)
1727         flags = self.config_flags.NAT_IS_INSIDE
1728         self.vapi.nat44_interface_add_del_feature(
1729             sw_if_index=self.pg0.sw_if_index,
1730             flags=flags, is_add=1)
1731         self.vapi.nat44_interface_add_del_feature(
1732             sw_if_index=self.pg1.sw_if_index,
1733             is_add=1)
1734
1735         # in2out
1736         pkts = self.create_stream_in(self.pg0, self.pg1)
1737         self.pg0.add_stream(pkts)
1738         self.pg_enable_capture(self.pg_interfaces)
1739         self.pg_start()
1740         capture = self.pg1.get_capture(len(pkts))
1741         self.verify_capture_out(capture)
1742
1743         # out2in
1744         pkts = self.create_stream_out(self.pg1)
1745         self.pg1.add_stream(pkts)
1746         self.pg_enable_capture(self.pg_interfaces)
1747         self.pg_start()
1748         capture = self.pg0.get_capture(len(pkts))
1749         self.verify_capture_in(capture, self.pg0)
1750
1751     def test_static_with_port_out(self):
1752         """ 1:1 NAPT initialized from outside network """
1753
1754         self.tcp_port_out = 30606
1755         self.udp_port_out = 30607
1756         self.icmp_id_out = 30608
1757
1758         self.nat44_add_address(self.nat_addr)
1759         self.nat44_add_static_mapping(self.pg0.remote_ip4, self.nat_addr,
1760                                       self.tcp_port_in, self.tcp_port_out,
1761                                       proto=IP_PROTOS.tcp)
1762         self.nat44_add_static_mapping(self.pg0.remote_ip4, self.nat_addr,
1763                                       self.udp_port_in, self.udp_port_out,
1764                                       proto=IP_PROTOS.udp)
1765         self.nat44_add_static_mapping(self.pg0.remote_ip4, self.nat_addr,
1766                                       self.icmp_id_in, self.icmp_id_out,
1767                                       proto=IP_PROTOS.icmp)
1768         flags = self.config_flags.NAT_IS_INSIDE
1769         self.vapi.nat44_interface_add_del_feature(
1770             sw_if_index=self.pg0.sw_if_index,
1771             flags=flags, is_add=1)
1772         self.vapi.nat44_interface_add_del_feature(
1773             sw_if_index=self.pg1.sw_if_index,
1774             is_add=1)
1775
1776         # out2in
1777         pkts = self.create_stream_out(self.pg1)
1778         self.pg1.add_stream(pkts)
1779         self.pg_enable_capture(self.pg_interfaces)
1780         self.pg_start()
1781         capture = self.pg0.get_capture(len(pkts))
1782         self.verify_capture_in(capture, self.pg0)
1783
1784         # in2out
1785         pkts = self.create_stream_in(self.pg0, self.pg1)
1786         self.pg0.add_stream(pkts)
1787         self.pg_enable_capture(self.pg_interfaces)
1788         self.pg_start()
1789         capture = self.pg1.get_capture(len(pkts))
1790         self.verify_capture_out(capture)
1791
1792     def test_static_vrf_aware(self):
1793         """ 1:1 NAT VRF awareness """
1794
1795         nat_ip1 = "10.0.0.30"
1796         nat_ip2 = "10.0.0.40"
1797         self.tcp_port_out = 6303
1798         self.udp_port_out = 6304
1799         self.icmp_id_out = 6305
1800
1801         self.nat44_add_static_mapping(self.pg4.remote_ip4, nat_ip1,
1802                                       vrf_id=10)
1803         self.nat44_add_static_mapping(self.pg0.remote_ip4, nat_ip2,
1804                                       vrf_id=10)
1805         flags = self.config_flags.NAT_IS_INSIDE
1806         self.vapi.nat44_interface_add_del_feature(
1807             sw_if_index=self.pg3.sw_if_index,
1808             is_add=1)
1809         self.vapi.nat44_interface_add_del_feature(
1810             sw_if_index=self.pg0.sw_if_index,
1811             flags=flags, is_add=1)
1812         self.vapi.nat44_interface_add_del_feature(
1813             sw_if_index=self.pg4.sw_if_index,
1814             flags=flags, is_add=1)
1815
1816         # inside interface VRF match NAT44 static mapping VRF
1817         pkts = self.create_stream_in(self.pg4, self.pg3)
1818         self.pg4.add_stream(pkts)
1819         self.pg_enable_capture(self.pg_interfaces)
1820         self.pg_start()
1821         capture = self.pg3.get_capture(len(pkts))
1822         self.verify_capture_out(capture, nat_ip1, True)
1823
1824         # inside interface VRF don't match NAT44 static mapping VRF (packets
1825         # are dropped)
1826         pkts = self.create_stream_in(self.pg0, self.pg3)
1827         self.pg0.add_stream(pkts)
1828         self.pg_enable_capture(self.pg_interfaces)
1829         self.pg_start()
1830         self.pg3.assert_nothing_captured()
1831
1832     def test_dynamic_to_static(self):
1833         """ Switch from dynamic translation to 1:1NAT """
1834         nat_ip = "10.0.0.10"
1835         self.tcp_port_out = 6303
1836         self.udp_port_out = 6304
1837         self.icmp_id_out = 6305
1838
1839         self.nat44_add_address(self.nat_addr)
1840         flags = self.config_flags.NAT_IS_INSIDE
1841         self.vapi.nat44_interface_add_del_feature(
1842             sw_if_index=self.pg0.sw_if_index,
1843             flags=flags, is_add=1)
1844         self.vapi.nat44_interface_add_del_feature(
1845             sw_if_index=self.pg1.sw_if_index,
1846             is_add=1)
1847
1848         # dynamic
1849         pkts = self.create_stream_in(self.pg0, self.pg1)
1850         self.pg0.add_stream(pkts)
1851         self.pg_enable_capture(self.pg_interfaces)
1852         self.pg_start()
1853         capture = self.pg1.get_capture(len(pkts))
1854         self.verify_capture_out(capture)
1855
1856         # 1:1NAT
1857         self.nat44_add_static_mapping(self.pg0.remote_ip4, nat_ip)
1858         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
1859         self.assertEqual(len(sessions), 0)
1860         pkts = self.create_stream_in(self.pg0, self.pg1)
1861         self.pg0.add_stream(pkts)
1862         self.pg_enable_capture(self.pg_interfaces)
1863         self.pg_start()
1864         capture = self.pg1.get_capture(len(pkts))
1865         self.verify_capture_out(capture, nat_ip, True)
1866
1867     def test_identity_nat(self):
1868         """ Identity NAT """
1869         flags = self.config_flags.NAT_IS_ADDR_ONLY
1870         self.vapi.nat44_add_del_identity_mapping(
1871             ip_address=self.pg0.remote_ip4, sw_if_index=0xFFFFFFFF,
1872             flags=flags, is_add=1)
1873         flags = self.config_flags.NAT_IS_INSIDE
1874         self.vapi.nat44_interface_add_del_feature(
1875             sw_if_index=self.pg0.sw_if_index,
1876             flags=flags, is_add=1)
1877         self.vapi.nat44_interface_add_del_feature(
1878             sw_if_index=self.pg1.sw_if_index,
1879             is_add=1)
1880
1881         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
1882              IP(src=self.pg1.remote_ip4, dst=self.pg0.remote_ip4) /
1883              TCP(sport=12345, dport=56789))
1884         self.pg1.add_stream(p)
1885         self.pg_enable_capture(self.pg_interfaces)
1886         self.pg_start()
1887         capture = self.pg0.get_capture(1)
1888         p = capture[0]
1889         try:
1890             ip = p[IP]
1891             tcp = p[TCP]
1892             self.assertEqual(ip.dst, self.pg0.remote_ip4)
1893             self.assertEqual(ip.src, self.pg1.remote_ip4)
1894             self.assertEqual(tcp.dport, 56789)
1895             self.assertEqual(tcp.sport, 12345)
1896             self.assert_packet_checksums_valid(p)
1897         except:
1898             self.logger.error(ppp("Unexpected or invalid packet:", p))
1899             raise
1900
1901         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
1902         self.assertEqual(len(sessions), 0)
1903         flags = self.config_flags.NAT_IS_ADDR_ONLY
1904         self.vapi.nat44_add_del_identity_mapping(
1905             ip_address=self.pg0.remote_ip4, sw_if_index=0xFFFFFFFF,
1906             flags=flags, vrf_id=1, is_add=1)
1907         identity_mappings = self.vapi.nat44_identity_mapping_dump()
1908         self.assertEqual(len(identity_mappings), 2)
1909
1910     def test_multiple_inside_interfaces(self):
1911         """ NAT44 multiple non-overlapping address space inside interfaces """
1912
1913         self.nat44_add_address(self.nat_addr)
1914         flags = self.config_flags.NAT_IS_INSIDE
1915         self.vapi.nat44_interface_add_del_feature(
1916             sw_if_index=self.pg0.sw_if_index,
1917             flags=flags, is_add=1)
1918         self.vapi.nat44_interface_add_del_feature(
1919             sw_if_index=self.pg1.sw_if_index,
1920             flags=flags, is_add=1)
1921         self.vapi.nat44_interface_add_del_feature(
1922             sw_if_index=self.pg3.sw_if_index,
1923             is_add=1)
1924
1925         # between two NAT44 inside interfaces (no translation)
1926         pkts = self.create_stream_in(self.pg0, self.pg1)
1927         self.pg0.add_stream(pkts)
1928         self.pg_enable_capture(self.pg_interfaces)
1929         self.pg_start()
1930         capture = self.pg1.get_capture(len(pkts))
1931         self.verify_capture_no_translation(capture, self.pg0, self.pg1)
1932
1933         # from NAT44 inside to interface without NAT44 feature (no translation)
1934         pkts = self.create_stream_in(self.pg0, self.pg2)
1935         self.pg0.add_stream(pkts)
1936         self.pg_enable_capture(self.pg_interfaces)
1937         self.pg_start()
1938         capture = self.pg2.get_capture(len(pkts))
1939         self.verify_capture_no_translation(capture, self.pg0, self.pg2)
1940
1941         # in2out 1st interface
1942         pkts = self.create_stream_in(self.pg0, self.pg3)
1943         self.pg0.add_stream(pkts)
1944         self.pg_enable_capture(self.pg_interfaces)
1945         self.pg_start()
1946         capture = self.pg3.get_capture(len(pkts))
1947         self.verify_capture_out(capture)
1948
1949         # out2in 1st interface
1950         pkts = self.create_stream_out(self.pg3)
1951         self.pg3.add_stream(pkts)
1952         self.pg_enable_capture(self.pg_interfaces)
1953         self.pg_start()
1954         capture = self.pg0.get_capture(len(pkts))
1955         self.verify_capture_in(capture, self.pg0)
1956
1957         # in2out 2nd interface
1958         pkts = self.create_stream_in(self.pg1, self.pg3)
1959         self.pg1.add_stream(pkts)
1960         self.pg_enable_capture(self.pg_interfaces)
1961         self.pg_start()
1962         capture = self.pg3.get_capture(len(pkts))
1963         self.verify_capture_out(capture)
1964
1965         # out2in 2nd interface
1966         pkts = self.create_stream_out(self.pg3)
1967         self.pg3.add_stream(pkts)
1968         self.pg_enable_capture(self.pg_interfaces)
1969         self.pg_start()
1970         capture = self.pg1.get_capture(len(pkts))
1971         self.verify_capture_in(capture, self.pg1)
1972
1973     def test_inside_overlapping_interfaces(self):
1974         """ NAT44 multiple inside interfaces with overlapping address space """
1975
1976         static_nat_ip = "10.0.0.10"
1977         self.nat44_add_address(self.nat_addr)
1978         flags = self.config_flags.NAT_IS_INSIDE
1979         self.vapi.nat44_interface_add_del_feature(
1980             sw_if_index=self.pg3.sw_if_index,
1981             is_add=1)
1982         self.vapi.nat44_interface_add_del_feature(
1983             sw_if_index=self.pg4.sw_if_index,
1984             flags=flags, is_add=1)
1985         self.vapi.nat44_interface_add_del_feature(
1986             sw_if_index=self.pg5.sw_if_index,
1987             flags=flags, is_add=1)
1988         self.vapi.nat44_interface_add_del_feature(
1989             sw_if_index=self.pg6.sw_if_index,
1990             flags=flags, is_add=1)
1991         self.nat44_add_static_mapping(self.pg6.remote_ip4, static_nat_ip,
1992                                       vrf_id=20)
1993
1994         # between NAT44 inside interfaces with same VRF (no translation)
1995         pkts = self.create_stream_in(self.pg4, self.pg5)
1996         self.pg4.add_stream(pkts)
1997         self.pg_enable_capture(self.pg_interfaces)
1998         self.pg_start()
1999         capture = self.pg5.get_capture(len(pkts))
2000         self.verify_capture_no_translation(capture, self.pg4, self.pg5)
2001
2002         # between NAT44 inside interfaces with different VRF (hairpinning)
2003         p = (Ether(src=self.pg4.remote_mac, dst=self.pg4.local_mac) /
2004              IP(src=self.pg4.remote_ip4, dst=static_nat_ip) /
2005              TCP(sport=1234, dport=5678))
2006         self.pg4.add_stream(p)
2007         self.pg_enable_capture(self.pg_interfaces)
2008         self.pg_start()
2009         capture = self.pg6.get_capture(1)
2010         p = capture[0]
2011         try:
2012             ip = p[IP]
2013             tcp = p[TCP]
2014             self.assertEqual(ip.src, self.nat_addr)
2015             self.assertEqual(ip.dst, self.pg6.remote_ip4)
2016             self.assertNotEqual(tcp.sport, 1234)
2017             self.assertEqual(tcp.dport, 5678)
2018         except:
2019             self.logger.error(ppp("Unexpected or invalid packet:", p))
2020             raise
2021
2022         # in2out 1st interface
2023         pkts = self.create_stream_in(self.pg4, self.pg3)
2024         self.pg4.add_stream(pkts)
2025         self.pg_enable_capture(self.pg_interfaces)
2026         self.pg_start()
2027         capture = self.pg3.get_capture(len(pkts))
2028         self.verify_capture_out(capture)
2029
2030         # out2in 1st interface
2031         pkts = self.create_stream_out(self.pg3)
2032         self.pg3.add_stream(pkts)
2033         self.pg_enable_capture(self.pg_interfaces)
2034         self.pg_start()
2035         capture = self.pg4.get_capture(len(pkts))
2036         self.verify_capture_in(capture, self.pg4)
2037
2038         # in2out 2nd interface
2039         pkts = self.create_stream_in(self.pg5, self.pg3)
2040         self.pg5.add_stream(pkts)
2041         self.pg_enable_capture(self.pg_interfaces)
2042         self.pg_start()
2043         capture = self.pg3.get_capture(len(pkts))
2044         self.verify_capture_out(capture)
2045
2046         # out2in 2nd interface
2047         pkts = self.create_stream_out(self.pg3)
2048         self.pg3.add_stream(pkts)
2049         self.pg_enable_capture(self.pg_interfaces)
2050         self.pg_start()
2051         capture = self.pg5.get_capture(len(pkts))
2052         self.verify_capture_in(capture, self.pg5)
2053
2054         # pg5 session dump
2055         addresses = self.vapi.nat44_address_dump()
2056         self.assertEqual(len(addresses), 1)
2057         sessions = self.vapi.nat44_user_session_dump(self.pg5.remote_ip4, 10)
2058         self.assertEqual(len(sessions), 3)
2059         for session in sessions:
2060             self.assertFalse(session.flags & self.config_flags.NAT_IS_STATIC)
2061             self.assertEqual(str(session.inside_ip_address),
2062                              self.pg5.remote_ip4)
2063             self.assertEqual(session.outside_ip_address,
2064                              addresses[0].ip_address)
2065         self.assertEqual(sessions[0].protocol, IP_PROTOS.tcp)
2066         self.assertEqual(sessions[1].protocol, IP_PROTOS.udp)
2067         self.assertEqual(sessions[2].protocol, IP_PROTOS.icmp)
2068         self.assertEqual(sessions[0].inside_port, self.tcp_port_in)
2069         self.assertEqual(sessions[1].inside_port, self.udp_port_in)
2070         self.assertEqual(sessions[2].inside_port, self.icmp_id_in)
2071         self.assertEqual(sessions[0].outside_port, self.tcp_port_out)
2072         self.assertEqual(sessions[1].outside_port, self.udp_port_out)
2073         self.assertEqual(sessions[2].outside_port, self.icmp_id_out)
2074
2075         # in2out 3rd interface
2076         pkts = self.create_stream_in(self.pg6, self.pg3)
2077         self.pg6.add_stream(pkts)
2078         self.pg_enable_capture(self.pg_interfaces)
2079         self.pg_start()
2080         capture = self.pg3.get_capture(len(pkts))
2081         self.verify_capture_out(capture, static_nat_ip, True)
2082
2083         # out2in 3rd interface
2084         pkts = self.create_stream_out(self.pg3, static_nat_ip)
2085         self.pg3.add_stream(pkts)
2086         self.pg_enable_capture(self.pg_interfaces)
2087         self.pg_start()
2088         capture = self.pg6.get_capture(len(pkts))
2089         self.verify_capture_in(capture, self.pg6)
2090
2091         # general user and session dump verifications
2092         users = self.vapi.nat44_user_dump()
2093         self.assertGreaterEqual(len(users), 3)
2094         addresses = self.vapi.nat44_address_dump()
2095         self.assertEqual(len(addresses), 1)
2096         for user in users:
2097             sessions = self.vapi.nat44_user_session_dump(user.ip_address,
2098                                                          user.vrf_id)
2099             for session in sessions:
2100                 self.assertEqual(user.ip_address, session.inside_ip_address)
2101                 self.assertTrue(session.total_bytes > session.total_pkts > 0)
2102                 self.assertTrue(session.protocol in
2103                                 [IP_PROTOS.tcp, IP_PROTOS.udp,
2104                                  IP_PROTOS.icmp])
2105                 self.assertFalse(session.flags &
2106                                  self.config_flags.NAT_IS_EXT_HOST_VALID)
2107
2108         # pg4 session dump
2109         sessions = self.vapi.nat44_user_session_dump(self.pg4.remote_ip4, 10)
2110         self.assertGreaterEqual(len(sessions), 4)
2111         for session in sessions:
2112             self.assertFalse(session.flags & self.config_flags.NAT_IS_STATIC)
2113             self.assertEqual(str(session.inside_ip_address),
2114                              self.pg4.remote_ip4)
2115             self.assertEqual(session.outside_ip_address,
2116                              addresses[0].ip_address)
2117
2118         # pg6 session dump
2119         sessions = self.vapi.nat44_user_session_dump(self.pg6.remote_ip4, 20)
2120         self.assertGreaterEqual(len(sessions), 3)
2121         for session in sessions:
2122             self.assertTrue(session.flags & self.config_flags.NAT_IS_STATIC)
2123             self.assertEqual(str(session.inside_ip_address),
2124                              self.pg6.remote_ip4)
2125             self.assertEqual(str(session.outside_ip_address),
2126                              static_nat_ip)
2127             self.assertTrue(session.inside_port in
2128                             [self.tcp_port_in, self.udp_port_in,
2129                              self.icmp_id_in])
2130
2131     def test_hairpinning(self):
2132         """ NAT44 hairpinning - 1:1 NAPT """
2133
2134         host = self.pg0.remote_hosts[0]
2135         server = self.pg0.remote_hosts[1]
2136         host_in_port = 1234
2137         host_out_port = 0
2138         server_in_port = 5678
2139         server_out_port = 8765
2140
2141         self.nat44_add_address(self.nat_addr)
2142         flags = self.config_flags.NAT_IS_INSIDE
2143         self.vapi.nat44_interface_add_del_feature(
2144             sw_if_index=self.pg0.sw_if_index,
2145             flags=flags, is_add=1)
2146         self.vapi.nat44_interface_add_del_feature(
2147             sw_if_index=self.pg1.sw_if_index,
2148             is_add=1)
2149
2150         # add static mapping for server
2151         self.nat44_add_static_mapping(server.ip4, self.nat_addr,
2152                                       server_in_port, server_out_port,
2153                                       proto=IP_PROTOS.tcp)
2154
2155         cnt = self.statistics.get_counter('/nat44/hairpinning')[0]
2156         # send packet from host to server
2157         p = (Ether(src=host.mac, dst=self.pg0.local_mac) /
2158              IP(src=host.ip4, dst=self.nat_addr) /
2159              TCP(sport=host_in_port, dport=server_out_port))
2160         self.pg0.add_stream(p)
2161         self.pg_enable_capture(self.pg_interfaces)
2162         self.pg_start()
2163         capture = self.pg0.get_capture(1)
2164         p = capture[0]
2165         try:
2166             ip = p[IP]
2167             tcp = p[TCP]
2168             self.assertEqual(ip.src, self.nat_addr)
2169             self.assertEqual(ip.dst, server.ip4)
2170             self.assertNotEqual(tcp.sport, host_in_port)
2171             self.assertEqual(tcp.dport, server_in_port)
2172             self.assert_packet_checksums_valid(p)
2173             host_out_port = tcp.sport
2174         except:
2175             self.logger.error(ppp("Unexpected or invalid packet:", p))
2176             raise
2177
2178         after = self.statistics.get_counter('/nat44/hairpinning')[0]
2179         if_idx = self.pg0.sw_if_index
2180         self.assertEqual(after[if_idx] - cnt[if_idx], 1)
2181
2182         # send reply from server to host
2183         p = (Ether(src=server.mac, dst=self.pg0.local_mac) /
2184              IP(src=server.ip4, dst=self.nat_addr) /
2185              TCP(sport=server_in_port, dport=host_out_port))
2186         self.pg0.add_stream(p)
2187         self.pg_enable_capture(self.pg_interfaces)
2188         self.pg_start()
2189         capture = self.pg0.get_capture(1)
2190         p = capture[0]
2191         try:
2192             ip = p[IP]
2193             tcp = p[TCP]
2194             self.assertEqual(ip.src, self.nat_addr)
2195             self.assertEqual(ip.dst, host.ip4)
2196             self.assertEqual(tcp.sport, server_out_port)
2197             self.assertEqual(tcp.dport, host_in_port)
2198             self.assert_packet_checksums_valid(p)
2199         except:
2200             self.logger.error(ppp("Unexpected or invalid packet:", p))
2201             raise
2202
2203         after = self.statistics.get_counter('/nat44/hairpinning')[0]
2204         if_idx = self.pg0.sw_if_index
2205         self.assertEqual(after[if_idx] - cnt[if_idx], 2)
2206
2207     def test_hairpinning2(self):
2208         """ NAT44 hairpinning - 1:1 NAT"""
2209
2210         server1_nat_ip = "10.0.0.10"
2211         server2_nat_ip = "10.0.0.11"
2212         host = self.pg0.remote_hosts[0]
2213         server1 = self.pg0.remote_hosts[1]
2214         server2 = self.pg0.remote_hosts[2]
2215         server_tcp_port = 22
2216         server_udp_port = 20
2217
2218         self.nat44_add_address(self.nat_addr)
2219         flags = self.config_flags.NAT_IS_INSIDE
2220         self.vapi.nat44_interface_add_del_feature(
2221             sw_if_index=self.pg0.sw_if_index,
2222             flags=flags, is_add=1)
2223         self.vapi.nat44_interface_add_del_feature(
2224             sw_if_index=self.pg1.sw_if_index,
2225             is_add=1)
2226
2227         # add static mapping for servers
2228         self.nat44_add_static_mapping(server1.ip4, server1_nat_ip)
2229         self.nat44_add_static_mapping(server2.ip4, server2_nat_ip)
2230
2231         # host to server1
2232         pkts = []
2233         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2234              IP(src=host.ip4, dst=server1_nat_ip) /
2235              TCP(sport=self.tcp_port_in, dport=server_tcp_port))
2236         pkts.append(p)
2237         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2238              IP(src=host.ip4, dst=server1_nat_ip) /
2239              UDP(sport=self.udp_port_in, dport=server_udp_port))
2240         pkts.append(p)
2241         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2242              IP(src=host.ip4, dst=server1_nat_ip) /
2243              ICMP(id=self.icmp_id_in, type='echo-request'))
2244         pkts.append(p)
2245         self.pg0.add_stream(pkts)
2246         self.pg_enable_capture(self.pg_interfaces)
2247         self.pg_start()
2248         capture = self.pg0.get_capture(len(pkts))
2249         for packet in capture:
2250             try:
2251                 self.assertEqual(packet[IP].src, self.nat_addr)
2252                 self.assertEqual(packet[IP].dst, server1.ip4)
2253                 if packet.haslayer(TCP):
2254                     self.assertNotEqual(packet[TCP].sport, self.tcp_port_in)
2255                     self.assertEqual(packet[TCP].dport, server_tcp_port)
2256                     self.tcp_port_out = packet[TCP].sport
2257                     self.assert_packet_checksums_valid(packet)
2258                 elif packet.haslayer(UDP):
2259                     self.assertNotEqual(packet[UDP].sport, self.udp_port_in)
2260                     self.assertEqual(packet[UDP].dport, server_udp_port)
2261                     self.udp_port_out = packet[UDP].sport
2262                 else:
2263                     self.assertNotEqual(packet[ICMP].id, self.icmp_id_in)
2264                     self.icmp_id_out = packet[ICMP].id
2265             except:
2266                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
2267                 raise
2268
2269         # server1 to host
2270         pkts = []
2271         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2272              IP(src=server1.ip4, dst=self.nat_addr) /
2273              TCP(sport=server_tcp_port, dport=self.tcp_port_out))
2274         pkts.append(p)
2275         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2276              IP(src=server1.ip4, dst=self.nat_addr) /
2277              UDP(sport=server_udp_port, dport=self.udp_port_out))
2278         pkts.append(p)
2279         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2280              IP(src=server1.ip4, dst=self.nat_addr) /
2281              ICMP(id=self.icmp_id_out, type='echo-reply'))
2282         pkts.append(p)
2283         self.pg0.add_stream(pkts)
2284         self.pg_enable_capture(self.pg_interfaces)
2285         self.pg_start()
2286         capture = self.pg0.get_capture(len(pkts))
2287         for packet in capture:
2288             try:
2289                 self.assertEqual(packet[IP].src, server1_nat_ip)
2290                 self.assertEqual(packet[IP].dst, host.ip4)
2291                 if packet.haslayer(TCP):
2292                     self.assertEqual(packet[TCP].dport, self.tcp_port_in)
2293                     self.assertEqual(packet[TCP].sport, server_tcp_port)
2294                     self.assert_packet_checksums_valid(packet)
2295                 elif packet.haslayer(UDP):
2296                     self.assertEqual(packet[UDP].dport, self.udp_port_in)
2297                     self.assertEqual(packet[UDP].sport, server_udp_port)
2298                 else:
2299                     self.assertEqual(packet[ICMP].id, self.icmp_id_in)
2300             except:
2301                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
2302                 raise
2303
2304         # server2 to server1
2305         pkts = []
2306         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2307              IP(src=server2.ip4, dst=server1_nat_ip) /
2308              TCP(sport=self.tcp_port_in, dport=server_tcp_port))
2309         pkts.append(p)
2310         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2311              IP(src=server2.ip4, dst=server1_nat_ip) /
2312              UDP(sport=self.udp_port_in, dport=server_udp_port))
2313         pkts.append(p)
2314         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2315              IP(src=server2.ip4, dst=server1_nat_ip) /
2316              ICMP(id=self.icmp_id_in, type='echo-request'))
2317         pkts.append(p)
2318         self.pg0.add_stream(pkts)
2319         self.pg_enable_capture(self.pg_interfaces)
2320         self.pg_start()
2321         capture = self.pg0.get_capture(len(pkts))
2322         for packet in capture:
2323             try:
2324                 self.assertEqual(packet[IP].src, server2_nat_ip)
2325                 self.assertEqual(packet[IP].dst, server1.ip4)
2326                 if packet.haslayer(TCP):
2327                     self.assertEqual(packet[TCP].sport, self.tcp_port_in)
2328                     self.assertEqual(packet[TCP].dport, server_tcp_port)
2329                     self.tcp_port_out = packet[TCP].sport
2330                     self.assert_packet_checksums_valid(packet)
2331                 elif packet.haslayer(UDP):
2332                     self.assertEqual(packet[UDP].sport, self.udp_port_in)
2333                     self.assertEqual(packet[UDP].dport, server_udp_port)
2334                     self.udp_port_out = packet[UDP].sport
2335                 else:
2336                     self.assertEqual(packet[ICMP].id, self.icmp_id_in)
2337                     self.icmp_id_out = packet[ICMP].id
2338             except:
2339                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
2340                 raise
2341
2342         # server1 to server2
2343         pkts = []
2344         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2345              IP(src=server1.ip4, dst=server2_nat_ip) /
2346              TCP(sport=server_tcp_port, dport=self.tcp_port_out))
2347         pkts.append(p)
2348         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2349              IP(src=server1.ip4, dst=server2_nat_ip) /
2350              UDP(sport=server_udp_port, dport=self.udp_port_out))
2351         pkts.append(p)
2352         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2353              IP(src=server1.ip4, dst=server2_nat_ip) /
2354              ICMP(id=self.icmp_id_out, type='echo-reply'))
2355         pkts.append(p)
2356         self.pg0.add_stream(pkts)
2357         self.pg_enable_capture(self.pg_interfaces)
2358         self.pg_start()
2359         capture = self.pg0.get_capture(len(pkts))
2360         for packet in capture:
2361             try:
2362                 self.assertEqual(packet[IP].src, server1_nat_ip)
2363                 self.assertEqual(packet[IP].dst, server2.ip4)
2364                 if packet.haslayer(TCP):
2365                     self.assertEqual(packet[TCP].dport, self.tcp_port_in)
2366                     self.assertEqual(packet[TCP].sport, server_tcp_port)
2367                     self.assert_packet_checksums_valid(packet)
2368                 elif packet.haslayer(UDP):
2369                     self.assertEqual(packet[UDP].dport, self.udp_port_in)
2370                     self.assertEqual(packet[UDP].sport, server_udp_port)
2371                 else:
2372                     self.assertEqual(packet[ICMP].id, self.icmp_id_in)
2373             except:
2374                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
2375                 raise
2376
2377     def test_interface_addr(self):
2378         """ Acquire NAT44 addresses from interface """
2379         self.vapi.nat44_add_del_interface_addr(
2380             is_add=1,
2381             sw_if_index=self.pg7.sw_if_index)
2382
2383         # no address in NAT pool
2384         addresses = self.vapi.nat44_address_dump()
2385         self.assertEqual(0, len(addresses))
2386
2387         # configure interface address and check NAT address pool
2388         self.pg7.config_ip4()
2389         addresses = self.vapi.nat44_address_dump()
2390         self.assertEqual(1, len(addresses))
2391         self.assertEqual(str(addresses[0].ip_address), self.pg7.local_ip4)
2392
2393         # remove interface address and check NAT address pool
2394         self.pg7.unconfig_ip4()
2395         addresses = self.vapi.nat44_address_dump()
2396         self.assertEqual(0, len(addresses))
2397
2398     def test_interface_addr_static_mapping(self):
2399         """ Static mapping with addresses from interface """
2400         tag = "testTAG"
2401
2402         self.vapi.nat44_add_del_interface_addr(
2403             is_add=1,
2404             sw_if_index=self.pg7.sw_if_index)
2405         self.nat44_add_static_mapping(
2406             '1.2.3.4',
2407             external_sw_if_index=self.pg7.sw_if_index,
2408             tag=tag)
2409
2410         # static mappings with external interface
2411         static_mappings = self.vapi.nat44_static_mapping_dump()
2412         self.assertEqual(1, len(static_mappings))
2413         self.assertEqual(self.pg7.sw_if_index,
2414                          static_mappings[0].external_sw_if_index)
2415         self.assertEqual(static_mappings[0].tag, tag)
2416
2417         # configure interface address and check static mappings
2418         self.pg7.config_ip4()
2419         static_mappings = self.vapi.nat44_static_mapping_dump()
2420         self.assertEqual(2, len(static_mappings))
2421         resolved = False
2422         for sm in static_mappings:
2423             if sm.external_sw_if_index == 0xFFFFFFFF:
2424                 self.assertEqual(str(sm.external_ip_address),
2425                                  self.pg7.local_ip4)
2426                 self.assertEqual(sm.tag, tag)
2427                 resolved = True
2428         self.assertTrue(resolved)
2429
2430         # remove interface address and check static mappings
2431         self.pg7.unconfig_ip4()
2432         static_mappings = self.vapi.nat44_static_mapping_dump()
2433         self.assertEqual(1, len(static_mappings))
2434         self.assertEqual(self.pg7.sw_if_index,
2435                          static_mappings[0].external_sw_if_index)
2436         self.assertEqual(static_mappings[0].tag, tag)
2437
2438         # configure interface address again and check static mappings
2439         self.pg7.config_ip4()
2440         static_mappings = self.vapi.nat44_static_mapping_dump()
2441         self.assertEqual(2, len(static_mappings))
2442         resolved = False
2443         for sm in static_mappings:
2444             if sm.external_sw_if_index == 0xFFFFFFFF:
2445                 self.assertEqual(str(sm.external_ip_address),
2446                                  self.pg7.local_ip4)
2447                 self.assertEqual(sm.tag, tag)
2448                 resolved = True
2449         self.assertTrue(resolved)
2450
2451         # remove static mapping
2452         self.nat44_add_static_mapping(
2453             '1.2.3.4',
2454             external_sw_if_index=self.pg7.sw_if_index,
2455             tag=tag,
2456             is_add=0)
2457         static_mappings = self.vapi.nat44_static_mapping_dump()
2458         self.assertEqual(0, len(static_mappings))
2459
2460     def test_interface_addr_identity_nat(self):
2461         """ Identity NAT with addresses from interface """
2462
2463         port = 53053
2464         self.vapi.nat44_add_del_interface_addr(
2465             is_add=1,
2466             sw_if_index=self.pg7.sw_if_index)
2467         self.vapi.nat44_add_del_identity_mapping(
2468             ip_address=b'0',
2469             sw_if_index=self.pg7.sw_if_index,
2470             port=port,
2471             protocol=IP_PROTOS.tcp,
2472             is_add=1)
2473
2474         # identity mappings with external interface
2475         identity_mappings = self.vapi.nat44_identity_mapping_dump()
2476         self.assertEqual(1, len(identity_mappings))
2477         self.assertEqual(self.pg7.sw_if_index,
2478                          identity_mappings[0].sw_if_index)
2479
2480         # configure interface address and check identity mappings
2481         self.pg7.config_ip4()
2482         identity_mappings = self.vapi.nat44_identity_mapping_dump()
2483         resolved = False
2484         self.assertEqual(2, len(identity_mappings))
2485         for sm in identity_mappings:
2486             if sm.sw_if_index == 0xFFFFFFFF:
2487                 self.assertEqual(str(identity_mappings[0].ip_address),
2488                                  self.pg7.local_ip4)
2489                 self.assertEqual(port, identity_mappings[0].port)
2490                 self.assertEqual(IP_PROTOS.tcp, identity_mappings[0].protocol)
2491                 resolved = True
2492         self.assertTrue(resolved)
2493
2494         # remove interface address and check identity mappings
2495         self.pg7.unconfig_ip4()
2496         identity_mappings = self.vapi.nat44_identity_mapping_dump()
2497         self.assertEqual(1, len(identity_mappings))
2498         self.assertEqual(self.pg7.sw_if_index,
2499                          identity_mappings[0].sw_if_index)
2500
2501     def test_ipfix_nat44_sess(self):
2502         """ IPFIX logging NAT44 session created/deleted """
2503         self.ipfix_domain_id = 10
2504         self.ipfix_src_port = 20202
2505         collector_port = 30303
2506         bind_layers(UDP, IPFIX, dport=30303)
2507         self.nat44_add_address(self.nat_addr)
2508         flags = self.config_flags.NAT_IS_INSIDE
2509         self.vapi.nat44_interface_add_del_feature(
2510             sw_if_index=self.pg0.sw_if_index,
2511             flags=flags, is_add=1)
2512         self.vapi.nat44_interface_add_del_feature(
2513             sw_if_index=self.pg1.sw_if_index,
2514             is_add=1)
2515         self.vapi.set_ipfix_exporter(collector_address=self.pg3.remote_ip4,
2516                                      src_address=self.pg3.local_ip4,
2517                                      path_mtu=512,
2518                                      template_interval=10,
2519                                      collector_port=collector_port)
2520         self.vapi.nat_ipfix_enable_disable(domain_id=self.ipfix_domain_id,
2521                                            src_port=self.ipfix_src_port,
2522                                            enable=1)
2523
2524         pkts = self.create_stream_in(self.pg0, self.pg1)
2525         self.pg0.add_stream(pkts)
2526         self.pg_enable_capture(self.pg_interfaces)
2527         self.pg_start()
2528         capture = self.pg1.get_capture(len(pkts))
2529         self.verify_capture_out(capture)
2530         self.nat44_add_address(self.nat_addr, is_add=0)
2531         self.vapi.ipfix_flush()
2532         capture = self.pg3.get_capture(7)
2533         ipfix = IPFIXDecoder()
2534         # first load template
2535         for p in capture:
2536             self.assertTrue(p.haslayer(IPFIX))
2537             self.assertEqual(p[IP].src, self.pg3.local_ip4)
2538             self.assertEqual(p[IP].dst, self.pg3.remote_ip4)
2539             self.assertEqual(p[UDP].sport, self.ipfix_src_port)
2540             self.assertEqual(p[UDP].dport, collector_port)
2541             self.assertEqual(p[IPFIX].observationDomainID,
2542                              self.ipfix_domain_id)
2543             if p.haslayer(Template):
2544                 ipfix.add_template(p.getlayer(Template))
2545         # verify events in data set
2546         for p in capture:
2547             if p.haslayer(Data):
2548                 data = ipfix.decode_data_set(p.getlayer(Set))
2549                 self.verify_ipfix_nat44_ses(data)
2550
2551     def test_ipfix_addr_exhausted(self):
2552         """ IPFIX logging NAT addresses exhausted """
2553         flags = self.config_flags.NAT_IS_INSIDE
2554         self.vapi.nat44_interface_add_del_feature(
2555             sw_if_index=self.pg0.sw_if_index,
2556             flags=flags, is_add=1)
2557         self.vapi.nat44_interface_add_del_feature(
2558             sw_if_index=self.pg1.sw_if_index,
2559             is_add=1)
2560         self.vapi.set_ipfix_exporter(collector_address=self.pg3.remote_ip4,
2561                                      src_address=self.pg3.local_ip4,
2562                                      path_mtu=512,
2563                                      template_interval=10)
2564         self.vapi.nat_ipfix_enable_disable(domain_id=self.ipfix_domain_id,
2565                                            src_port=self.ipfix_src_port,
2566                                            enable=1)
2567
2568         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
2569              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
2570              TCP(sport=3025))
2571         self.pg0.add_stream(p)
2572         self.pg_enable_capture(self.pg_interfaces)
2573         self.pg_start()
2574         self.pg1.assert_nothing_captured()
2575         sleep(1)
2576         self.vapi.ipfix_flush()
2577         capture = self.pg3.get_capture(7)
2578         ipfix = IPFIXDecoder()
2579         # first load template
2580         for p in capture:
2581             self.assertTrue(p.haslayer(IPFIX))
2582             self.assertEqual(p[IP].src, self.pg3.local_ip4)
2583             self.assertEqual(p[IP].dst, self.pg3.remote_ip4)
2584             self.assertEqual(p[UDP].sport, self.ipfix_src_port)
2585             self.assertEqual(p[UDP].dport, 4739)
2586             self.assertEqual(p[IPFIX].observationDomainID,
2587                              self.ipfix_domain_id)
2588             if p.haslayer(Template):
2589                 ipfix.add_template(p.getlayer(Template))
2590         # verify events in data set
2591         for p in capture:
2592             if p.haslayer(Data):
2593                 data = ipfix.decode_data_set(p.getlayer(Set))
2594                 self.verify_ipfix_addr_exhausted(data)
2595
2596     def test_ipfix_max_sessions(self):
2597         """ IPFIX logging maximum session entries exceeded """
2598         self.nat44_add_address(self.nat_addr)
2599         flags = self.config_flags.NAT_IS_INSIDE
2600         self.vapi.nat44_interface_add_del_feature(
2601             sw_if_index=self.pg0.sw_if_index,
2602             flags=flags, is_add=1)
2603         self.vapi.nat44_interface_add_del_feature(
2604             sw_if_index=self.pg1.sw_if_index,
2605             is_add=1)
2606
2607         max_sessions = self.max_translations
2608
2609         pkts = []
2610         for i in range(0, max_sessions):
2611             src = "10.10.%u.%u" % ((i & 0xFF00) >> 8, i & 0xFF)
2612             p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2613                  IP(src=src, dst=self.pg1.remote_ip4) /
2614                  TCP(sport=1025))
2615             pkts.append(p)
2616         self.pg0.add_stream(pkts)
2617         self.pg_enable_capture(self.pg_interfaces)
2618         self.pg_start()
2619
2620         self.pg1.get_capture(max_sessions)
2621         self.vapi.set_ipfix_exporter(collector_address=self.pg3.remote_ip4,
2622                                      src_address=self.pg3.local_ip4,
2623                                      path_mtu=512,
2624                                      template_interval=10)
2625         self.vapi.nat_ipfix_enable_disable(domain_id=self.ipfix_domain_id,
2626                                            src_port=self.ipfix_src_port,
2627                                            enable=1)
2628
2629         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2630              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
2631              TCP(sport=1025))
2632         self.pg0.add_stream(p)
2633         self.pg_enable_capture(self.pg_interfaces)
2634         self.pg_start()
2635         self.pg1.assert_nothing_captured()
2636         sleep(1)
2637         self.vapi.ipfix_flush()
2638         capture = self.pg3.get_capture(7)
2639         ipfix = IPFIXDecoder()
2640         # first load template
2641         for p in capture:
2642             self.assertTrue(p.haslayer(IPFIX))
2643             self.assertEqual(p[IP].src, self.pg3.local_ip4)
2644             self.assertEqual(p[IP].dst, self.pg3.remote_ip4)
2645             self.assertEqual(p[UDP].sport, self.ipfix_src_port)
2646             self.assertEqual(p[UDP].dport, 4739)
2647             self.assertEqual(p[IPFIX].observationDomainID,
2648                              self.ipfix_domain_id)
2649             if p.haslayer(Template):
2650                 ipfix.add_template(p.getlayer(Template))
2651         # verify events in data set
2652         for p in capture:
2653             if p.haslayer(Data):
2654                 data = ipfix.decode_data_set(p.getlayer(Set))
2655                 self.verify_ipfix_max_sessions(data, max_sessions)
2656
2657     def test_syslog_apmap(self):
2658         """ Test syslog address and port mapping creation and deletion """
2659         self.vapi.syslog_set_filter(
2660             self.SYSLOG_SEVERITY.SYSLOG_API_SEVERITY_INFO)
2661         self.vapi.syslog_set_sender(self.pg3.local_ip4, self.pg3.remote_ip4)
2662         self.nat44_add_address(self.nat_addr)
2663         flags = self.config_flags.NAT_IS_INSIDE
2664         self.vapi.nat44_interface_add_del_feature(
2665             sw_if_index=self.pg0.sw_if_index,
2666             flags=flags, is_add=1)
2667         self.vapi.nat44_interface_add_del_feature(
2668             sw_if_index=self.pg1.sw_if_index,
2669             is_add=1)
2670
2671         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2672              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
2673              TCP(sport=self.tcp_port_in, dport=20))
2674         self.pg0.add_stream(p)
2675         self.pg_enable_capture(self.pg_interfaces)
2676         self.pg_start()
2677         capture = self.pg1.get_capture(1)
2678         self.tcp_port_out = capture[0][TCP].sport
2679         capture = self.pg3.get_capture(1)
2680         self.verify_syslog_apmap(capture[0][Raw].load)
2681
2682         self.pg_enable_capture(self.pg_interfaces)
2683         self.pg_start()
2684         self.nat44_add_address(self.nat_addr, is_add=0)
2685         capture = self.pg3.get_capture(1)
2686         self.verify_syslog_apmap(capture[0][Raw].load, False)
2687
2688     def test_pool_addr_fib(self):
2689         """ NAT44 add pool addresses to FIB """
2690         static_addr = '10.0.0.10'
2691         self.nat44_add_address(self.nat_addr)
2692         flags = self.config_flags.NAT_IS_INSIDE
2693         self.vapi.nat44_interface_add_del_feature(
2694             sw_if_index=self.pg0.sw_if_index,
2695             flags=flags, is_add=1)
2696         self.vapi.nat44_interface_add_del_feature(
2697             sw_if_index=self.pg1.sw_if_index,
2698             is_add=1)
2699         self.nat44_add_static_mapping(self.pg0.remote_ip4, static_addr)
2700
2701         # NAT44 address
2702         p = (Ether(src=self.pg1.remote_mac, dst='ff:ff:ff:ff:ff:ff') /
2703              ARP(op=ARP.who_has, pdst=self.nat_addr,
2704                  psrc=self.pg1.remote_ip4, hwsrc=self.pg1.remote_mac))
2705         self.pg1.add_stream(p)
2706         self.pg_enable_capture(self.pg_interfaces)
2707         self.pg_start()
2708         capture = self.pg1.get_capture(1)
2709         self.assertTrue(capture[0].haslayer(ARP))
2710         self.assertTrue(capture[0][ARP].op, ARP.is_at)
2711
2712         # 1:1 NAT address
2713         p = (Ether(src=self.pg1.remote_mac, dst='ff:ff:ff:ff:ff:ff') /
2714              ARP(op=ARP.who_has, pdst=static_addr,
2715                  psrc=self.pg1.remote_ip4, hwsrc=self.pg1.remote_mac))
2716         self.pg1.add_stream(p)
2717         self.pg_enable_capture(self.pg_interfaces)
2718         self.pg_start()
2719         capture = self.pg1.get_capture(1)
2720         self.assertTrue(capture[0].haslayer(ARP))
2721         self.assertTrue(capture[0][ARP].op, ARP.is_at)
2722
2723         # send ARP to non-NAT44 interface
2724         p = (Ether(src=self.pg2.remote_mac, dst='ff:ff:ff:ff:ff:ff') /
2725              ARP(op=ARP.who_has, pdst=self.nat_addr,
2726                  psrc=self.pg2.remote_ip4, hwsrc=self.pg2.remote_mac))
2727         self.pg2.add_stream(p)
2728         self.pg_enable_capture(self.pg_interfaces)
2729         self.pg_start()
2730         self.pg1.assert_nothing_captured()
2731
2732         # remove addresses and verify
2733         self.nat44_add_address(self.nat_addr, is_add=0)
2734         self.nat44_add_static_mapping(self.pg0.remote_ip4, static_addr,
2735                                       is_add=0)
2736
2737         p = (Ether(src=self.pg1.remote_mac, dst='ff:ff:ff:ff:ff:ff') /
2738              ARP(op=ARP.who_has, pdst=self.nat_addr,
2739                  psrc=self.pg1.remote_ip4, hwsrc=self.pg1.remote_mac))
2740         self.pg1.add_stream(p)
2741         self.pg_enable_capture(self.pg_interfaces)
2742         self.pg_start()
2743         self.pg1.assert_nothing_captured()
2744
2745         p = (Ether(src=self.pg1.remote_mac, dst='ff:ff:ff:ff:ff:ff') /
2746              ARP(op=ARP.who_has, pdst=static_addr,
2747                  psrc=self.pg1.remote_ip4, hwsrc=self.pg1.remote_mac))
2748         self.pg1.add_stream(p)
2749         self.pg_enable_capture(self.pg_interfaces)
2750         self.pg_start()
2751         self.pg1.assert_nothing_captured()
2752
2753     def test_vrf_mode(self):
2754         """ NAT44 tenant VRF aware address pool mode """
2755
2756         vrf_id1 = 1
2757         vrf_id2 = 2
2758         nat_ip1 = "10.0.0.10"
2759         nat_ip2 = "10.0.0.11"
2760
2761         self.pg0.unconfig_ip4()
2762         self.pg1.unconfig_ip4()
2763         self.vapi.ip_table_add_del(is_add=1, table={'table_id': vrf_id1})
2764         self.vapi.ip_table_add_del(is_add=1, table={'table_id': vrf_id2})
2765         self.pg0.set_table_ip4(vrf_id1)
2766         self.pg1.set_table_ip4(vrf_id2)
2767         self.pg0.config_ip4()
2768         self.pg1.config_ip4()
2769         self.pg0.resolve_arp()
2770         self.pg1.resolve_arp()
2771
2772         self.nat44_add_address(nat_ip1, vrf_id=vrf_id1)
2773         self.nat44_add_address(nat_ip2, vrf_id=vrf_id2)
2774         flags = self.config_flags.NAT_IS_INSIDE
2775         self.vapi.nat44_interface_add_del_feature(
2776             sw_if_index=self.pg0.sw_if_index,
2777             flags=flags, is_add=1)
2778         self.vapi.nat44_interface_add_del_feature(
2779             sw_if_index=self.pg1.sw_if_index,
2780             flags=flags, is_add=1)
2781         self.vapi.nat44_interface_add_del_feature(
2782             sw_if_index=self.pg2.sw_if_index,
2783             is_add=1)
2784
2785         try:
2786             # first VRF
2787             pkts = self.create_stream_in(self.pg0, self.pg2)
2788             self.pg0.add_stream(pkts)
2789             self.pg_enable_capture(self.pg_interfaces)
2790             self.pg_start()
2791             capture = self.pg2.get_capture(len(pkts))
2792             self.verify_capture_out(capture, nat_ip1)
2793
2794             # second VRF
2795             pkts = self.create_stream_in(self.pg1, self.pg2)
2796             self.pg1.add_stream(pkts)
2797             self.pg_enable_capture(self.pg_interfaces)
2798             self.pg_start()
2799             capture = self.pg2.get_capture(len(pkts))
2800             self.verify_capture_out(capture, nat_ip2)
2801
2802         finally:
2803             self.pg0.unconfig_ip4()
2804             self.pg1.unconfig_ip4()
2805             self.pg0.set_table_ip4(0)
2806             self.pg1.set_table_ip4(0)
2807             self.pg0.config_ip4()
2808             self.pg1.config_ip4()
2809             self.pg0.resolve_arp()
2810             self.pg1.resolve_arp()
2811             self.vapi.ip_table_add_del(is_add=0, table={'table_id': vrf_id1})
2812             self.vapi.ip_table_add_del(is_add=0, table={'table_id': vrf_id2})
2813
2814     def test_vrf_feature_independent(self):
2815         """ NAT44 tenant VRF independent address pool mode """
2816
2817         nat_ip1 = "10.0.0.10"
2818         nat_ip2 = "10.0.0.11"
2819
2820         self.nat44_add_address(nat_ip1)
2821         self.nat44_add_address(nat_ip2, vrf_id=99)
2822         flags = self.config_flags.NAT_IS_INSIDE
2823         self.vapi.nat44_interface_add_del_feature(
2824             sw_if_index=self.pg0.sw_if_index,
2825             flags=flags, is_add=1)
2826         self.vapi.nat44_interface_add_del_feature(
2827             sw_if_index=self.pg1.sw_if_index,
2828             flags=flags, is_add=1)
2829         self.vapi.nat44_interface_add_del_feature(
2830             sw_if_index=self.pg2.sw_if_index,
2831             is_add=1)
2832
2833         # first VRF
2834         pkts = self.create_stream_in(self.pg0, self.pg2)
2835         self.pg0.add_stream(pkts)
2836         self.pg_enable_capture(self.pg_interfaces)
2837         self.pg_start()
2838         capture = self.pg2.get_capture(len(pkts))
2839         self.verify_capture_out(capture, nat_ip1)
2840
2841         # second VRF
2842         pkts = self.create_stream_in(self.pg1, self.pg2)
2843         self.pg1.add_stream(pkts)
2844         self.pg_enable_capture(self.pg_interfaces)
2845         self.pg_start()
2846         capture = self.pg2.get_capture(len(pkts))
2847         self.verify_capture_out(capture, nat_ip1)
2848
2849     def create_routes_and_neigbors(self):
2850         r1 = VppIpRoute(self, self.pg7.remote_ip4, 32,
2851                         [VppRoutePath(self.pg7.remote_ip4,
2852                                       self.pg7.sw_if_index)])
2853         r2 = VppIpRoute(self, self.pg8.remote_ip4, 32,
2854                         [VppRoutePath(self.pg8.remote_ip4,
2855                                       self.pg8.sw_if_index)])
2856         r1.add_vpp_config()
2857         r2.add_vpp_config()
2858
2859         n1 = VppNeighbor(self,
2860                          self.pg7.sw_if_index,
2861                          self.pg7.remote_mac,
2862                          self.pg7.remote_ip4,
2863                          is_static=1)
2864         n2 = VppNeighbor(self,
2865                          self.pg8.sw_if_index,
2866                          self.pg8.remote_mac,
2867                          self.pg8.remote_ip4,
2868                          is_static=1)
2869         n1.add_vpp_config()
2870         n2.add_vpp_config()
2871
2872     def test_dynamic_ipless_interfaces(self):
2873         """ NAT44 interfaces without configured IP address """
2874         self.create_routes_and_neigbors()
2875         self.nat44_add_address(self.nat_addr)
2876         flags = self.config_flags.NAT_IS_INSIDE
2877         self.vapi.nat44_interface_add_del_feature(
2878             sw_if_index=self.pg7.sw_if_index,
2879             flags=flags, is_add=1)
2880         self.vapi.nat44_interface_add_del_feature(
2881             sw_if_index=self.pg8.sw_if_index,
2882             is_add=1)
2883
2884         # in2out
2885         pkts = self.create_stream_in(self.pg7, self.pg8)
2886         self.pg7.add_stream(pkts)
2887         self.pg_enable_capture(self.pg_interfaces)
2888         self.pg_start()
2889         capture = self.pg8.get_capture(len(pkts))
2890         self.verify_capture_out(capture)
2891
2892         # out2in
2893         pkts = self.create_stream_out(self.pg8, self.nat_addr)
2894         self.pg8.add_stream(pkts)
2895         self.pg_enable_capture(self.pg_interfaces)
2896         self.pg_start()
2897         capture = self.pg7.get_capture(len(pkts))
2898         self.verify_capture_in(capture, self.pg7)
2899
2900     def test_static_ipless_interfaces(self):
2901         """ NAT44 interfaces without configured IP address - 1:1 NAT """
2902
2903         self.create_routes_and_neigbors()
2904         self.nat44_add_static_mapping(self.pg7.remote_ip4, self.nat_addr)
2905         flags = self.config_flags.NAT_IS_INSIDE
2906         self.vapi.nat44_interface_add_del_feature(
2907             sw_if_index=self.pg7.sw_if_index,
2908             flags=flags, is_add=1)
2909         self.vapi.nat44_interface_add_del_feature(
2910             sw_if_index=self.pg8.sw_if_index,
2911             is_add=1)
2912
2913         # out2in
2914         pkts = self.create_stream_out(self.pg8)
2915         self.pg8.add_stream(pkts)
2916         self.pg_enable_capture(self.pg_interfaces)
2917         self.pg_start()
2918         capture = self.pg7.get_capture(len(pkts))
2919         self.verify_capture_in(capture, self.pg7)
2920
2921         # in2out
2922         pkts = self.create_stream_in(self.pg7, self.pg8)
2923         self.pg7.add_stream(pkts)
2924         self.pg_enable_capture(self.pg_interfaces)
2925         self.pg_start()
2926         capture = self.pg8.get_capture(len(pkts))
2927         self.verify_capture_out(capture, self.nat_addr, True)
2928
2929     def test_static_with_port_ipless_interfaces(self):
2930         """ NAT44 interfaces without configured IP address - 1:1 NAPT """
2931
2932         self.tcp_port_out = 30606
2933         self.udp_port_out = 30607
2934         self.icmp_id_out = 30608
2935
2936         self.create_routes_and_neigbors()
2937         self.nat44_add_address(self.nat_addr)
2938         self.nat44_add_static_mapping(self.pg7.remote_ip4, self.nat_addr,
2939                                       self.tcp_port_in, self.tcp_port_out,
2940                                       proto=IP_PROTOS.tcp)
2941         self.nat44_add_static_mapping(self.pg7.remote_ip4, self.nat_addr,
2942                                       self.udp_port_in, self.udp_port_out,
2943                                       proto=IP_PROTOS.udp)
2944         self.nat44_add_static_mapping(self.pg7.remote_ip4, self.nat_addr,
2945                                       self.icmp_id_in, self.icmp_id_out,
2946                                       proto=IP_PROTOS.icmp)
2947         flags = self.config_flags.NAT_IS_INSIDE
2948         self.vapi.nat44_interface_add_del_feature(
2949             sw_if_index=self.pg7.sw_if_index,
2950             flags=flags, is_add=1)
2951         self.vapi.nat44_interface_add_del_feature(
2952             sw_if_index=self.pg8.sw_if_index,
2953             is_add=1)
2954
2955         # out2in
2956         pkts = self.create_stream_out(self.pg8)
2957         self.pg8.add_stream(pkts)
2958         self.pg_enable_capture(self.pg_interfaces)
2959         self.pg_start()
2960         capture = self.pg7.get_capture(len(pkts))
2961         self.verify_capture_in(capture, self.pg7)
2962
2963         # in2out
2964         pkts = self.create_stream_in(self.pg7, self.pg8)
2965         self.pg7.add_stream(pkts)
2966         self.pg_enable_capture(self.pg_interfaces)
2967         self.pg_start()
2968         capture = self.pg8.get_capture(len(pkts))
2969         self.verify_capture_out(capture)
2970
2971     def test_static_unknown_proto(self):
2972         """ 1:1 NAT translate packet with unknown protocol """
2973         nat_ip = "10.0.0.10"
2974         self.nat44_add_static_mapping(self.pg0.remote_ip4, nat_ip)
2975         flags = self.config_flags.NAT_IS_INSIDE
2976         self.vapi.nat44_interface_add_del_feature(
2977             sw_if_index=self.pg0.sw_if_index,
2978             flags=flags, is_add=1)
2979         self.vapi.nat44_interface_add_del_feature(
2980             sw_if_index=self.pg1.sw_if_index,
2981             is_add=1)
2982
2983         # in2out
2984         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2985              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
2986              GRE() /
2987              IP(src=self.pg2.remote_ip4, dst=self.pg3.remote_ip4) /
2988              TCP(sport=1234, dport=1234))
2989         self.pg0.add_stream(p)
2990         self.pg_enable_capture(self.pg_interfaces)
2991         self.pg_start()
2992         p = self.pg1.get_capture(1)
2993         packet = p[0]
2994         try:
2995             self.assertEqual(packet[IP].src, nat_ip)
2996             self.assertEqual(packet[IP].dst, self.pg1.remote_ip4)
2997             self.assertEqual(packet.haslayer(GRE), 1)
2998             self.assert_packet_checksums_valid(packet)
2999         except:
3000             self.logger.error(ppp("Unexpected or invalid packet:", packet))
3001             raise
3002
3003         # out2in
3004         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
3005              IP(src=self.pg1.remote_ip4, dst=nat_ip) /
3006              GRE() /
3007              IP(src=self.pg3.remote_ip4, dst=self.pg2.remote_ip4) /
3008              TCP(sport=1234, dport=1234))
3009         self.pg1.add_stream(p)
3010         self.pg_enable_capture(self.pg_interfaces)
3011         self.pg_start()
3012         p = self.pg0.get_capture(1)
3013         packet = p[0]
3014         try:
3015             self.assertEqual(packet[IP].src, self.pg1.remote_ip4)
3016             self.assertEqual(packet[IP].dst, self.pg0.remote_ip4)
3017             self.assertEqual(packet.haslayer(GRE), 1)
3018             self.assert_packet_checksums_valid(packet)
3019         except:
3020             self.logger.error(ppp("Unexpected or invalid packet:", packet))
3021             raise
3022
3023     def test_hairpinning_static_unknown_proto(self):
3024         """ 1:1 NAT translate packet with unknown protocol - hairpinning """
3025
3026         host = self.pg0.remote_hosts[0]
3027         server = self.pg0.remote_hosts[1]
3028
3029         host_nat_ip = "10.0.0.10"
3030         server_nat_ip = "10.0.0.11"
3031
3032         self.nat44_add_static_mapping(host.ip4, host_nat_ip)
3033         self.nat44_add_static_mapping(server.ip4, server_nat_ip)
3034         flags = self.config_flags.NAT_IS_INSIDE
3035         self.vapi.nat44_interface_add_del_feature(
3036             sw_if_index=self.pg0.sw_if_index,
3037             flags=flags, is_add=1)
3038         self.vapi.nat44_interface_add_del_feature(
3039             sw_if_index=self.pg1.sw_if_index,
3040             is_add=1)
3041
3042         # host to server
3043         p = (Ether(dst=self.pg0.local_mac, src=host.mac) /
3044              IP(src=host.ip4, dst=server_nat_ip) /
3045              GRE() /
3046              IP(src=self.pg2.remote_ip4, dst=self.pg3.remote_ip4) /
3047              TCP(sport=1234, dport=1234))
3048         self.pg0.add_stream(p)
3049         self.pg_enable_capture(self.pg_interfaces)
3050         self.pg_start()
3051         p = self.pg0.get_capture(1)
3052         packet = p[0]
3053         try:
3054             self.assertEqual(packet[IP].src, host_nat_ip)
3055             self.assertEqual(packet[IP].dst, server.ip4)
3056             self.assertEqual(packet.haslayer(GRE), 1)
3057             self.assert_packet_checksums_valid(packet)
3058         except:
3059             self.logger.error(ppp("Unexpected or invalid packet:", packet))
3060             raise
3061
3062         # server to host
3063         p = (Ether(dst=self.pg0.local_mac, src=server.mac) /
3064              IP(src=server.ip4, dst=host_nat_ip) /
3065              GRE() /
3066              IP(src=self.pg3.remote_ip4, dst=self.pg2.remote_ip4) /
3067              TCP(sport=1234, dport=1234))
3068         self.pg0.add_stream(p)
3069         self.pg_enable_capture(self.pg_interfaces)
3070         self.pg_start()
3071         p = self.pg0.get_capture(1)
3072         packet = p[0]
3073         try:
3074             self.assertEqual(packet[IP].src, server_nat_ip)
3075             self.assertEqual(packet[IP].dst, host.ip4)
3076             self.assertEqual(packet.haslayer(GRE), 1)
3077             self.assert_packet_checksums_valid(packet)
3078         except:
3079             self.logger.error(ppp("Unexpected or invalid packet:", packet))
3080             raise
3081
3082     def test_output_feature(self):
3083         """ NAT44 interface output feature (in2out postrouting) """
3084         self.nat44_add_address(self.nat_addr)
3085         flags = self.config_flags.NAT_IS_INSIDE
3086         self.vapi.nat44_interface_add_del_output_feature(
3087             is_add=1, flags=flags,
3088             sw_if_index=self.pg0.sw_if_index)
3089         self.vapi.nat44_interface_add_del_output_feature(
3090             is_add=1, flags=flags,
3091             sw_if_index=self.pg1.sw_if_index)
3092         self.vapi.nat44_interface_add_del_output_feature(
3093             is_add=1,
3094             sw_if_index=self.pg3.sw_if_index)
3095
3096         # in2out
3097         pkts = self.create_stream_in(self.pg0, self.pg3)
3098         self.pg0.add_stream(pkts)
3099         self.pg_enable_capture(self.pg_interfaces)
3100         self.pg_start()
3101         capture = self.pg3.get_capture(len(pkts))
3102         self.verify_capture_out(capture)
3103
3104         # out2in
3105         pkts = self.create_stream_out(self.pg3)
3106         self.pg3.add_stream(pkts)
3107         self.pg_enable_capture(self.pg_interfaces)
3108         self.pg_start()
3109         capture = self.pg0.get_capture(len(pkts))
3110         self.verify_capture_in(capture, self.pg0)
3111
3112         # from non-NAT interface to NAT inside interface
3113         pkts = self.create_stream_in(self.pg2, self.pg0)
3114         self.pg2.add_stream(pkts)
3115         self.pg_enable_capture(self.pg_interfaces)
3116         self.pg_start()
3117         capture = self.pg0.get_capture(len(pkts))
3118         self.verify_capture_no_translation(capture, self.pg2, self.pg0)
3119
3120     def test_output_feature_vrf_aware(self):
3121         """ NAT44 interface output feature VRF aware (in2out postrouting) """
3122         nat_ip_vrf10 = "10.0.0.10"
3123         nat_ip_vrf20 = "10.0.0.20"
3124
3125         r1 = VppIpRoute(self, self.pg3.remote_ip4, 32,
3126                         [VppRoutePath(self.pg3.remote_ip4,
3127                                       self.pg3.sw_if_index)],
3128                         table_id=10)
3129         r2 = VppIpRoute(self, self.pg3.remote_ip4, 32,
3130                         [VppRoutePath(self.pg3.remote_ip4,
3131                                       self.pg3.sw_if_index)],
3132                         table_id=20)
3133         r1.add_vpp_config()
3134         r2.add_vpp_config()
3135
3136         self.nat44_add_address(nat_ip_vrf10, vrf_id=10)
3137         self.nat44_add_address(nat_ip_vrf20, vrf_id=20)
3138         flags = self.config_flags.NAT_IS_INSIDE
3139         self.vapi.nat44_interface_add_del_output_feature(
3140             is_add=1, flags=flags,
3141             sw_if_index=self.pg4.sw_if_index)
3142         self.vapi.nat44_interface_add_del_output_feature(
3143             is_add=1, flags=flags,
3144             sw_if_index=self.pg6.sw_if_index)
3145         self.vapi.nat44_interface_add_del_output_feature(
3146             is_add=1,
3147             sw_if_index=self.pg3.sw_if_index)
3148
3149         # in2out VRF 10
3150         pkts = self.create_stream_in(self.pg4, self.pg3)
3151         self.pg4.add_stream(pkts)
3152         self.pg_enable_capture(self.pg_interfaces)
3153         self.pg_start()
3154         capture = self.pg3.get_capture(len(pkts))
3155         self.verify_capture_out(capture, nat_ip=nat_ip_vrf10)
3156
3157         # out2in VRF 10
3158         pkts = self.create_stream_out(self.pg3, dst_ip=nat_ip_vrf10)
3159         self.pg3.add_stream(pkts)
3160         self.pg_enable_capture(self.pg_interfaces)
3161         self.pg_start()
3162         capture = self.pg4.get_capture(len(pkts))
3163         self.verify_capture_in(capture, self.pg4)
3164
3165         # in2out VRF 20
3166         pkts = self.create_stream_in(self.pg6, self.pg3)
3167         self.pg6.add_stream(pkts)
3168         self.pg_enable_capture(self.pg_interfaces)
3169         self.pg_start()
3170         capture = self.pg3.get_capture(len(pkts))
3171         self.verify_capture_out(capture, nat_ip=nat_ip_vrf20)
3172
3173         # out2in VRF 20
3174         pkts = self.create_stream_out(self.pg3, dst_ip=nat_ip_vrf20)
3175         self.pg3.add_stream(pkts)
3176         self.pg_enable_capture(self.pg_interfaces)
3177         self.pg_start()
3178         capture = self.pg6.get_capture(len(pkts))
3179         self.verify_capture_in(capture, self.pg6)
3180
3181     def test_output_feature_hairpinning(self):
3182         """ NAT44 interface output feature hairpinning (in2out postrouting) """
3183         host = self.pg0.remote_hosts[0]
3184         server = self.pg0.remote_hosts[1]
3185         host_in_port = 1234
3186         host_out_port = 0
3187         server_in_port = 5678
3188         server_out_port = 8765
3189
3190         self.nat44_add_address(self.nat_addr)
3191         flags = self.config_flags.NAT_IS_INSIDE
3192         self.vapi.nat44_interface_add_del_output_feature(
3193             is_add=1, flags=flags,
3194             sw_if_index=self.pg0.sw_if_index)
3195         self.vapi.nat44_interface_add_del_output_feature(
3196             is_add=1,
3197             sw_if_index=self.pg1.sw_if_index)
3198
3199         # add static mapping for server
3200         self.nat44_add_static_mapping(server.ip4, self.nat_addr,
3201                                       server_in_port, server_out_port,
3202                                       proto=IP_PROTOS.tcp)
3203
3204         # send packet from host to server
3205         p = (Ether(src=host.mac, dst=self.pg0.local_mac) /
3206              IP(src=host.ip4, dst=self.nat_addr) /
3207              TCP(sport=host_in_port, dport=server_out_port))
3208         self.pg0.add_stream(p)
3209         self.pg_enable_capture(self.pg_interfaces)
3210         self.pg_start()
3211         capture = self.pg0.get_capture(1)
3212         p = capture[0]
3213         try:
3214             ip = p[IP]
3215             tcp = p[TCP]
3216             self.assertEqual(ip.src, self.nat_addr)
3217             self.assertEqual(ip.dst, server.ip4)
3218             self.assertNotEqual(tcp.sport, host_in_port)
3219             self.assertEqual(tcp.dport, server_in_port)
3220             self.assert_packet_checksums_valid(p)
3221             host_out_port = tcp.sport
3222         except:
3223             self.logger.error(ppp("Unexpected or invalid packet:", p))
3224             raise
3225
3226         # send reply from server to host
3227         p = (Ether(src=server.mac, dst=self.pg0.local_mac) /
3228              IP(src=server.ip4, dst=self.nat_addr) /
3229              TCP(sport=server_in_port, dport=host_out_port))
3230         self.pg0.add_stream(p)
3231         self.pg_enable_capture(self.pg_interfaces)
3232         self.pg_start()
3233         capture = self.pg0.get_capture(1)
3234         p = capture[0]
3235         try:
3236             ip = p[IP]
3237             tcp = p[TCP]
3238             self.assertEqual(ip.src, self.nat_addr)
3239             self.assertEqual(ip.dst, host.ip4)
3240             self.assertEqual(tcp.sport, server_out_port)
3241             self.assertEqual(tcp.dport, host_in_port)
3242             self.assert_packet_checksums_valid(p)
3243         except:
3244             self.logger.error(ppp("Unexpected or invalid packet:", p))
3245             raise
3246
3247     def test_one_armed_nat44(self):
3248         """ One armed NAT44 """
3249         remote_host = self.pg9.remote_hosts[0]
3250         local_host = self.pg9.remote_hosts[1]
3251         external_port = 0
3252
3253         self.nat44_add_address(self.nat_addr)
3254         flags = self.config_flags.NAT_IS_INSIDE
3255         self.vapi.nat44_interface_add_del_feature(
3256             sw_if_index=self.pg9.sw_if_index,
3257             is_add=1)
3258         self.vapi.nat44_interface_add_del_feature(
3259             sw_if_index=self.pg9.sw_if_index,
3260             flags=flags, is_add=1)
3261
3262         # in2out
3263         p = (Ether(src=self.pg9.remote_mac, dst=self.pg9.local_mac) /
3264              IP(src=local_host.ip4, dst=remote_host.ip4) /
3265              TCP(sport=12345, dport=80))
3266         self.pg9.add_stream(p)
3267         self.pg_enable_capture(self.pg_interfaces)
3268         self.pg_start()
3269         capture = self.pg9.get_capture(1)
3270         p = capture[0]
3271         try:
3272             ip = p[IP]
3273             tcp = p[TCP]
3274             self.assertEqual(ip.src, self.nat_addr)
3275             self.assertEqual(ip.dst, remote_host.ip4)
3276             self.assertNotEqual(tcp.sport, 12345)
3277             external_port = tcp.sport
3278             self.assertEqual(tcp.dport, 80)
3279             self.assert_packet_checksums_valid(p)
3280         except:
3281             self.logger.error(ppp("Unexpected or invalid packet:", p))
3282             raise
3283
3284         # out2in
3285         p = (Ether(src=self.pg9.remote_mac, dst=self.pg9.local_mac) /
3286              IP(src=remote_host.ip4, dst=self.nat_addr) /
3287              TCP(sport=80, dport=external_port))
3288         self.pg9.add_stream(p)
3289         self.pg_enable_capture(self.pg_interfaces)
3290         self.pg_start()
3291         capture = self.pg9.get_capture(1)
3292         p = capture[0]
3293         try:
3294             ip = p[IP]
3295             tcp = p[TCP]
3296             self.assertEqual(ip.src, remote_host.ip4)
3297             self.assertEqual(ip.dst, local_host.ip4)
3298             self.assertEqual(tcp.sport, 80)
3299             self.assertEqual(tcp.dport, 12345)
3300             self.assert_packet_checksums_valid(p)
3301         except:
3302             self.logger.error(ppp("Unexpected or invalid packet:", p))
3303             raise
3304
3305         err = self.statistics.get_err_counter(
3306             '/err/nat44-classify/next in2out')
3307         self.assertEqual(err, 1)
3308         err = self.statistics.get_err_counter(
3309             '/err/nat44-classify/next out2in')
3310         self.assertEqual(err, 1)
3311
3312     def test_del_session(self):
3313         """ Delete NAT44 session """
3314         self.nat44_add_address(self.nat_addr)
3315         flags = self.config_flags.NAT_IS_INSIDE
3316         self.vapi.nat44_interface_add_del_feature(
3317             sw_if_index=self.pg0.sw_if_index,
3318             flags=flags, is_add=1)
3319         self.vapi.nat44_interface_add_del_feature(
3320             sw_if_index=self.pg1.sw_if_index,
3321             is_add=1)
3322
3323         pkts = self.create_stream_in(self.pg0, self.pg1)
3324         self.pg0.add_stream(pkts)
3325         self.pg_enable_capture(self.pg_interfaces)
3326         self.pg_start()
3327         self.pg1.get_capture(len(pkts))
3328
3329         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
3330         nsessions = len(sessions)
3331
3332         self.vapi.nat44_del_session(address=sessions[0].inside_ip_address,
3333                                     port=sessions[0].inside_port,
3334                                     protocol=sessions[0].protocol,
3335                                     flags=self.config_flags.NAT_IS_INSIDE)
3336         self.vapi.nat44_del_session(address=sessions[1].outside_ip_address,
3337                                     port=sessions[1].outside_port,
3338                                     protocol=sessions[1].protocol)
3339
3340         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
3341         self.assertEqual(nsessions - len(sessions), 2)
3342
3343         self.vapi.nat44_del_session(address=sessions[0].inside_ip_address,
3344                                     port=sessions[0].inside_port,
3345                                     protocol=sessions[0].protocol,
3346                                     flags=self.config_flags.NAT_IS_INSIDE)
3347
3348         self.verify_no_nat44_user()
3349
3350     def test_frag_in_order(self):
3351         """ NAT44 translate fragments arriving in order """
3352
3353         self.nat44_add_address(self.nat_addr)
3354         flags = self.config_flags.NAT_IS_INSIDE
3355         self.vapi.nat44_interface_add_del_feature(
3356             sw_if_index=self.pg0.sw_if_index,
3357             flags=flags, is_add=1)
3358         self.vapi.nat44_interface_add_del_feature(
3359             sw_if_index=self.pg1.sw_if_index,
3360             is_add=1)
3361
3362         self.frag_in_order(proto=IP_PROTOS.tcp)
3363         self.frag_in_order(proto=IP_PROTOS.udp)
3364         self.frag_in_order(proto=IP_PROTOS.icmp)
3365
3366     def test_frag_forwarding(self):
3367         """ NAT44 forwarding fragment test """
3368         self.vapi.nat44_add_del_interface_addr(
3369             is_add=1,
3370             sw_if_index=self.pg1.sw_if_index)
3371         flags = self.config_flags.NAT_IS_INSIDE
3372         self.vapi.nat44_interface_add_del_feature(
3373             sw_if_index=self.pg0.sw_if_index,
3374             flags=flags, is_add=1)
3375         self.vapi.nat44_interface_add_del_feature(
3376             sw_if_index=self.pg1.sw_if_index,
3377             is_add=1)
3378         self.vapi.nat44_forwarding_enable_disable(enable=1)
3379
3380         data = b"A" * 16 + b"B" * 16 + b"C" * 3
3381         pkts = self.create_stream_frag(self.pg1,
3382                                        self.pg0.remote_ip4,
3383                                        4789,
3384                                        4789,
3385                                        data,
3386                                        proto=IP_PROTOS.udp)
3387         self.pg1.add_stream(pkts)
3388         self.pg_enable_capture(self.pg_interfaces)
3389         self.pg_start()
3390         frags = self.pg0.get_capture(len(pkts))
3391         p = self.reass_frags_and_verify(frags,
3392                                         self.pg1.remote_ip4,
3393                                         self.pg0.remote_ip4)
3394         self.assertEqual(p[UDP].sport, 4789)
3395         self.assertEqual(p[UDP].dport, 4789)
3396         self.assertEqual(data, p[Raw].load)
3397
3398     def test_reass_hairpinning(self):
3399         """ NAT44 fragments hairpinning """
3400
3401         self.server = self.pg0.remote_hosts[1]
3402         self.host_in_port = random.randint(1025, 65535)
3403         self.server_in_port = random.randint(1025, 65535)
3404         self.server_out_port = random.randint(1025, 65535)
3405
3406         self.nat44_add_address(self.nat_addr)
3407         flags = self.config_flags.NAT_IS_INSIDE
3408         self.vapi.nat44_interface_add_del_feature(
3409             sw_if_index=self.pg0.sw_if_index,
3410             flags=flags, is_add=1)
3411         self.vapi.nat44_interface_add_del_feature(
3412             sw_if_index=self.pg1.sw_if_index,
3413             is_add=1)
3414         # add static mapping for server
3415         self.nat44_add_static_mapping(self.server.ip4, self.nat_addr,
3416                                       self.server_in_port,
3417                                       self.server_out_port,
3418                                       proto=IP_PROTOS.tcp)
3419         self.nat44_add_static_mapping(self.server.ip4, self.nat_addr,
3420                                       self.server_in_port,
3421                                       self.server_out_port,
3422                                       proto=IP_PROTOS.udp)
3423         self.nat44_add_static_mapping(self.server.ip4, self.nat_addr)
3424
3425         self.reass_hairpinning(proto=IP_PROTOS.tcp)
3426         self.reass_hairpinning(proto=IP_PROTOS.udp)
3427         self.reass_hairpinning(proto=IP_PROTOS.icmp)
3428
3429     def test_frag_out_of_order(self):
3430         """ NAT44 translate fragments arriving out of order """
3431
3432         self.nat44_add_address(self.nat_addr)
3433         flags = self.config_flags.NAT_IS_INSIDE
3434         self.vapi.nat44_interface_add_del_feature(
3435             sw_if_index=self.pg0.sw_if_index,
3436             flags=flags, is_add=1)
3437         self.vapi.nat44_interface_add_del_feature(
3438             sw_if_index=self.pg1.sw_if_index,
3439             is_add=1)
3440
3441         self.frag_out_of_order(proto=IP_PROTOS.tcp)
3442         self.frag_out_of_order(proto=IP_PROTOS.udp)
3443         self.frag_out_of_order(proto=IP_PROTOS.icmp)
3444
3445     def test_port_restricted(self):
3446         """ Port restricted NAT44 (MAP-E CE) """
3447         self.nat44_add_address(self.nat_addr)
3448         flags = self.config_flags.NAT_IS_INSIDE
3449         self.vapi.nat44_interface_add_del_feature(
3450             sw_if_index=self.pg0.sw_if_index,
3451             flags=flags, is_add=1)
3452         self.vapi.nat44_interface_add_del_feature(
3453             sw_if_index=self.pg1.sw_if_index,
3454             is_add=1)
3455         self.vapi.nat_set_addr_and_port_alloc_alg(alg=1,
3456                                                   psid_offset=6,
3457                                                   psid_length=6,
3458                                                   psid=10)
3459
3460         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
3461              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3462              TCP(sport=4567, dport=22))
3463         self.pg0.add_stream(p)
3464         self.pg_enable_capture(self.pg_interfaces)
3465         self.pg_start()
3466         capture = self.pg1.get_capture(1)
3467         p = capture[0]
3468         try:
3469             ip = p[IP]
3470             tcp = p[TCP]
3471             self.assertEqual(ip.dst, self.pg1.remote_ip4)
3472             self.assertEqual(ip.src, self.nat_addr)
3473             self.assertEqual(tcp.dport, 22)
3474             self.assertNotEqual(tcp.sport, 4567)
3475             self.assertEqual((tcp.sport >> 6) & 63, 10)
3476             self.assert_packet_checksums_valid(p)
3477         except:
3478             self.logger.error(ppp("Unexpected or invalid packet:", p))
3479             raise
3480
3481     def test_port_range(self):
3482         """ External address port range """
3483         self.nat44_add_address(self.nat_addr)
3484         flags = self.config_flags.NAT_IS_INSIDE
3485         self.vapi.nat44_interface_add_del_feature(
3486             sw_if_index=self.pg0.sw_if_index,
3487             flags=flags, is_add=1)
3488         self.vapi.nat44_interface_add_del_feature(
3489             sw_if_index=self.pg1.sw_if_index,
3490             is_add=1)
3491         self.vapi.nat_set_addr_and_port_alloc_alg(alg=2,
3492                                                   start_port=1025,
3493                                                   end_port=1027)
3494
3495         pkts = []
3496         for port in range(0, 5):
3497             p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
3498                  IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3499                  TCP(sport=1125 + port))
3500             pkts.append(p)
3501         self.pg0.add_stream(pkts)
3502         self.pg_enable_capture(self.pg_interfaces)
3503         self.pg_start()
3504         capture = self.pg1.get_capture(3)
3505         for p in capture:
3506             tcp = p[TCP]
3507             self.assertGreaterEqual(tcp.sport, 1025)
3508             self.assertLessEqual(tcp.sport, 1027)
3509
3510     def test_multiple_outside_vrf(self):
3511         """ Multiple outside VRF """
3512         vrf_id1 = 1
3513         vrf_id2 = 2
3514
3515         self.pg1.unconfig_ip4()
3516         self.pg2.unconfig_ip4()
3517         self.vapi.ip_table_add_del(is_add=1, table={'table_id': vrf_id1})
3518         self.vapi.ip_table_add_del(is_add=1, table={'table_id': vrf_id2})
3519         self.pg1.set_table_ip4(vrf_id1)
3520         self.pg2.set_table_ip4(vrf_id2)
3521         self.pg1.config_ip4()
3522         self.pg2.config_ip4()
3523         self.pg1.resolve_arp()
3524         self.pg2.resolve_arp()
3525
3526         self.nat44_add_address(self.nat_addr)
3527         flags = self.config_flags.NAT_IS_INSIDE
3528         self.vapi.nat44_interface_add_del_feature(
3529             sw_if_index=self.pg0.sw_if_index,
3530             flags=flags, is_add=1)
3531         self.vapi.nat44_interface_add_del_feature(
3532             sw_if_index=self.pg1.sw_if_index,
3533             is_add=1)
3534         self.vapi.nat44_interface_add_del_feature(
3535             sw_if_index=self.pg2.sw_if_index,
3536             is_add=1)
3537
3538         try:
3539             # first VRF
3540             pkts = self.create_stream_in(self.pg0, self.pg1)
3541             self.pg0.add_stream(pkts)
3542             self.pg_enable_capture(self.pg_interfaces)
3543             self.pg_start()
3544             capture = self.pg1.get_capture(len(pkts))
3545             self.verify_capture_out(capture, self.nat_addr)
3546
3547             pkts = self.create_stream_out(self.pg1, self.nat_addr)
3548             self.pg1.add_stream(pkts)
3549             self.pg_enable_capture(self.pg_interfaces)
3550             self.pg_start()
3551             capture = self.pg0.get_capture(len(pkts))
3552             self.verify_capture_in(capture, self.pg0)
3553
3554             self.tcp_port_in = 60303
3555             self.udp_port_in = 60304
3556             self.icmp_id_in = 60305
3557
3558             # second VRF
3559             pkts = self.create_stream_in(self.pg0, self.pg2)
3560             self.pg0.add_stream(pkts)
3561             self.pg_enable_capture(self.pg_interfaces)
3562             self.pg_start()
3563             capture = self.pg2.get_capture(len(pkts))
3564             self.verify_capture_out(capture, self.nat_addr)
3565
3566             pkts = self.create_stream_out(self.pg2, self.nat_addr)
3567             self.pg2.add_stream(pkts)
3568             self.pg_enable_capture(self.pg_interfaces)
3569             self.pg_start()
3570             capture = self.pg0.get_capture(len(pkts))
3571             self.verify_capture_in(capture, self.pg0)
3572
3573         finally:
3574             self.nat44_add_address(self.nat_addr, is_add=0)
3575             self.pg1.unconfig_ip4()
3576             self.pg2.unconfig_ip4()
3577             self.pg1.set_table_ip4(0)
3578             self.pg2.set_table_ip4(0)
3579             self.pg1.config_ip4()
3580             self.pg2.config_ip4()
3581             self.pg1.resolve_arp()
3582             self.pg2.resolve_arp()
3583
3584     def test_mss_clamping(self):
3585         """ TCP MSS clamping """
3586         self.nat44_add_address(self.nat_addr)
3587         flags = self.config_flags.NAT_IS_INSIDE
3588         self.vapi.nat44_interface_add_del_feature(
3589             sw_if_index=self.pg0.sw_if_index,
3590             flags=flags, is_add=1)
3591         self.vapi.nat44_interface_add_del_feature(
3592             sw_if_index=self.pg1.sw_if_index,
3593             is_add=1)
3594
3595         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
3596              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3597              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
3598                  flags="S", options=[('MSS', 1400)]))
3599
3600         self.vapi.nat_set_mss_clamping(enable=1, mss_value=1000)
3601         self.pg0.add_stream(p)
3602         self.pg_enable_capture(self.pg_interfaces)
3603         self.pg_start()
3604         capture = self.pg1.get_capture(1)
3605         # Negotiated MSS value greater than configured - changed
3606         self.verify_mss_value(capture[0], 1000)
3607
3608         self.vapi.nat_set_mss_clamping(enable=0, mss_value=1500)
3609         self.pg0.add_stream(p)
3610         self.pg_enable_capture(self.pg_interfaces)
3611         self.pg_start()
3612         capture = self.pg1.get_capture(1)
3613         # MSS clamping disabled - negotiated MSS unchanged
3614         self.verify_mss_value(capture[0], 1400)
3615
3616         self.vapi.nat_set_mss_clamping(enable=1, mss_value=1500)
3617         self.pg0.add_stream(p)
3618         self.pg_enable_capture(self.pg_interfaces)
3619         self.pg_start()
3620         capture = self.pg1.get_capture(1)
3621         # Negotiated MSS value smaller than configured - unchanged
3622         self.verify_mss_value(capture[0], 1400)
3623
3624     def test_ha_send(self):
3625         """ Send HA session synchronization events (active) """
3626         flags = self.config_flags.NAT_IS_INSIDE
3627         self.vapi.nat44_interface_add_del_feature(
3628             sw_if_index=self.pg0.sw_if_index,
3629             flags=flags, is_add=1)
3630         self.vapi.nat44_interface_add_del_feature(
3631             sw_if_index=self.pg1.sw_if_index,
3632             is_add=1)
3633         self.nat44_add_address(self.nat_addr)
3634
3635         self.vapi.nat_ha_set_listener(ip_address=self.pg3.local_ip4,
3636                                       port=12345,
3637                                       path_mtu=512)
3638         self.vapi.nat_ha_set_failover(ip_address=self.pg3.remote_ip4,
3639                                       port=12346, session_refresh_interval=10)
3640         bind_layers(UDP, HANATStateSync, sport=12345)
3641
3642         # create sessions
3643         pkts = self.create_stream_in(self.pg0, self.pg1)
3644         self.pg0.add_stream(pkts)
3645         self.pg_enable_capture(self.pg_interfaces)
3646         self.pg_start()
3647         capture = self.pg1.get_capture(len(pkts))
3648         self.verify_capture_out(capture)
3649         # active send HA events
3650         self.vapi.nat_ha_flush()
3651         stats = self.statistics.get_counter('/nat44/ha/add-event-send')
3652         self.assertEqual(stats[0][0], 3)
3653         capture = self.pg3.get_capture(1)
3654         p = capture[0]
3655         self.assert_packet_checksums_valid(p)
3656         try:
3657             ip = p[IP]
3658             udp = p[UDP]
3659             hanat = p[HANATStateSync]
3660         except IndexError:
3661             self.logger.error(ppp("Invalid packet:", p))
3662             raise
3663         else:
3664             self.assertEqual(ip.src, self.pg3.local_ip4)
3665             self.assertEqual(ip.dst, self.pg3.remote_ip4)
3666             self.assertEqual(udp.sport, 12345)
3667             self.assertEqual(udp.dport, 12346)
3668             self.assertEqual(hanat.version, 1)
3669             self.assertEqual(hanat.thread_index, 0)
3670             self.assertEqual(hanat.count, 3)
3671             seq = hanat.sequence_number
3672             for event in hanat.events:
3673                 self.assertEqual(event.event_type, 1)
3674                 self.assertEqual(event.in_addr, self.pg0.remote_ip4)
3675                 self.assertEqual(event.out_addr, self.nat_addr)
3676                 self.assertEqual(event.fib_index, 0)
3677
3678         # ACK received events
3679         ack = (Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac) /
3680                IP(src=self.pg3.remote_ip4, dst=self.pg3.local_ip4) /
3681                UDP(sport=12346, dport=12345) /
3682                HANATStateSync(sequence_number=seq, flags='ACK'))
3683         self.pg3.add_stream(ack)
3684         self.pg_start()
3685         stats = self.statistics.get_counter('/nat44/ha/ack-recv')
3686         self.assertEqual(stats[0][0], 1)
3687
3688         # delete one session
3689         self.pg_enable_capture(self.pg_interfaces)
3690         self.vapi.nat44_del_session(address=self.pg0.remote_ip4,
3691                                     port=self.tcp_port_in,
3692                                     protocol=IP_PROTOS.tcp,
3693                                     flags=self.config_flags.NAT_IS_INSIDE)
3694         self.vapi.nat_ha_flush()
3695         stats = self.statistics.get_counter('/nat44/ha/del-event-send')
3696         self.assertEqual(stats[0][0], 1)
3697         capture = self.pg3.get_capture(1)
3698         p = capture[0]
3699         try:
3700             hanat = p[HANATStateSync]
3701         except IndexError:
3702             self.logger.error(ppp("Invalid packet:", p))
3703             raise
3704         else:
3705             self.assertGreater(hanat.sequence_number, seq)
3706
3707         # do not send ACK, active retry send HA event again
3708         self.pg_enable_capture(self.pg_interfaces)
3709         sleep(12)
3710         stats = self.statistics.get_counter('/nat44/ha/retry-count')
3711         self.assertEqual(stats[0][0], 3)
3712         stats = self.statistics.get_counter('/nat44/ha/missed-count')
3713         self.assertEqual(stats[0][0], 1)
3714         capture = self.pg3.get_capture(3)
3715         for packet in capture:
3716             self.assertEqual(packet, p)
3717
3718         # session counters refresh
3719         pkts = self.create_stream_out(self.pg1)
3720         self.pg1.add_stream(pkts)
3721         self.pg_enable_capture(self.pg_interfaces)
3722         self.pg_start()
3723         self.pg0.get_capture(2)
3724         self.vapi.nat_ha_flush()
3725         stats = self.statistics.get_counter('/nat44/ha/refresh-event-send')
3726         self.assertEqual(stats[0][0], 2)
3727         capture = self.pg3.get_capture(1)
3728         p = capture[0]
3729         self.assert_packet_checksums_valid(p)
3730         try:
3731             ip = p[IP]
3732             udp = p[UDP]
3733             hanat = p[HANATStateSync]
3734         except IndexError:
3735             self.logger.error(ppp("Invalid packet:", p))
3736             raise
3737         else:
3738             self.assertEqual(ip.src, self.pg3.local_ip4)
3739             self.assertEqual(ip.dst, self.pg3.remote_ip4)
3740             self.assertEqual(udp.sport, 12345)
3741             self.assertEqual(udp.dport, 12346)
3742             self.assertEqual(hanat.version, 1)
3743             self.assertEqual(hanat.count, 2)
3744             seq = hanat.sequence_number
3745             for event in hanat.events:
3746                 self.assertEqual(event.event_type, 3)
3747                 self.assertEqual(event.out_addr, self.nat_addr)
3748                 self.assertEqual(event.fib_index, 0)
3749                 self.assertEqual(event.total_pkts, 2)
3750                 self.assertGreater(event.total_bytes, 0)
3751
3752         ack = (Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac) /
3753                IP(src=self.pg3.remote_ip4, dst=self.pg3.local_ip4) /
3754                UDP(sport=12346, dport=12345) /
3755                HANATStateSync(sequence_number=seq, flags='ACK'))
3756         self.pg3.add_stream(ack)
3757         self.pg_start()
3758         stats = self.statistics.get_counter('/nat44/ha/ack-recv')
3759         self.assertEqual(stats[0][0], 2)
3760
3761     def test_ha_recv(self):
3762         """ Receive HA session synchronization events (passive) """
3763         self.nat44_add_address(self.nat_addr)
3764         flags = self.config_flags.NAT_IS_INSIDE
3765         self.vapi.nat44_interface_add_del_feature(
3766             sw_if_index=self.pg0.sw_if_index,
3767             flags=flags, is_add=1)
3768         self.vapi.nat44_interface_add_del_feature(
3769             sw_if_index=self.pg1.sw_if_index,
3770             is_add=1)
3771         self.vapi.nat_ha_set_listener(ip_address=self.pg3.local_ip4,
3772                                       port=12345,
3773                                       path_mtu=512)
3774         bind_layers(UDP, HANATStateSync, sport=12345)
3775
3776         self.tcp_port_out = random.randint(1025, 65535)
3777         self.udp_port_out = random.randint(1025, 65535)
3778
3779         # send HA session add events to failover/passive
3780         p = (Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac) /
3781              IP(src=self.pg3.remote_ip4, dst=self.pg3.local_ip4) /
3782              UDP(sport=12346, dport=12345) /
3783              HANATStateSync(sequence_number=1, events=[
3784                  Event(event_type='add', protocol='tcp',
3785                        in_addr=self.pg0.remote_ip4, out_addr=self.nat_addr,
3786                        in_port=self.tcp_port_in, out_port=self.tcp_port_out,
3787                        eh_addr=self.pg1.remote_ip4,
3788                        ehn_addr=self.pg1.remote_ip4,
3789                        eh_port=self.tcp_external_port,
3790                        ehn_port=self.tcp_external_port, fib_index=0),
3791                  Event(event_type='add', protocol='udp',
3792                        in_addr=self.pg0.remote_ip4, out_addr=self.nat_addr,
3793                        in_port=self.udp_port_in, out_port=self.udp_port_out,
3794                        eh_addr=self.pg1.remote_ip4,
3795                        ehn_addr=self.pg1.remote_ip4,
3796                        eh_port=self.udp_external_port,
3797                        ehn_port=self.udp_external_port, fib_index=0)]))
3798
3799         self.pg3.add_stream(p)
3800         self.pg_enable_capture(self.pg_interfaces)
3801         self.pg_start()
3802         # receive ACK
3803         capture = self.pg3.get_capture(1)
3804         p = capture[0]
3805         try:
3806             hanat = p[HANATStateSync]
3807         except IndexError:
3808             self.logger.error(ppp("Invalid packet:", p))
3809             raise
3810         else:
3811             self.assertEqual(hanat.sequence_number, 1)
3812             self.assertEqual(hanat.flags, 'ACK')
3813             self.assertEqual(hanat.version, 1)
3814             self.assertEqual(hanat.thread_index, 0)
3815         stats = self.statistics.get_counter('/nat44/ha/ack-send')
3816         self.assertEqual(stats[0][0], 1)
3817         stats = self.statistics.get_counter('/nat44/ha/add-event-recv')
3818         self.assertEqual(stats[0][0], 2)
3819         users = self.statistics.get_counter('/nat44/total-users')
3820         self.assertEqual(users[0][0], 1)
3821         sessions = self.statistics.get_counter('/nat44/total-sessions')
3822         self.assertEqual(sessions[0][0], 2)
3823         users = self.vapi.nat44_user_dump()
3824         self.assertEqual(len(users), 1)
3825         self.assertEqual(str(users[0].ip_address),
3826                          self.pg0.remote_ip4)
3827         # there should be 2 sessions created by HA
3828         sessions = self.vapi.nat44_user_session_dump(users[0].ip_address,
3829                                                      users[0].vrf_id)
3830         self.assertEqual(len(sessions), 2)
3831         for session in sessions:
3832             self.assertEqual(str(session.inside_ip_address),
3833                              self.pg0.remote_ip4)
3834             self.assertEqual(str(session.outside_ip_address),
3835                              self.nat_addr)
3836             self.assertIn(session.inside_port,
3837                           [self.tcp_port_in, self.udp_port_in])
3838             self.assertIn(session.outside_port,
3839                           [self.tcp_port_out, self.udp_port_out])
3840             self.assertIn(session.protocol, [IP_PROTOS.tcp, IP_PROTOS.udp])
3841
3842         # send HA session delete event to failover/passive
3843         p = (Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac) /
3844              IP(src=self.pg3.remote_ip4, dst=self.pg3.local_ip4) /
3845              UDP(sport=12346, dport=12345) /
3846              HANATStateSync(sequence_number=2, events=[
3847                  Event(event_type='del', protocol='udp',
3848                        in_addr=self.pg0.remote_ip4, out_addr=self.nat_addr,
3849                        in_port=self.udp_port_in, out_port=self.udp_port_out,
3850                        eh_addr=self.pg1.remote_ip4,
3851                        ehn_addr=self.pg1.remote_ip4,
3852                        eh_port=self.udp_external_port,
3853                        ehn_port=self.udp_external_port, fib_index=0)]))
3854
3855         self.pg3.add_stream(p)
3856         self.pg_enable_capture(self.pg_interfaces)
3857         self.pg_start()
3858         # receive ACK
3859         capture = self.pg3.get_capture(1)
3860         p = capture[0]
3861         try:
3862             hanat = p[HANATStateSync]
3863         except IndexError:
3864             self.logger.error(ppp("Invalid packet:", p))
3865             raise
3866         else:
3867             self.assertEqual(hanat.sequence_number, 2)
3868             self.assertEqual(hanat.flags, 'ACK')
3869             self.assertEqual(hanat.version, 1)
3870         users = self.vapi.nat44_user_dump()
3871         self.assertEqual(len(users), 1)
3872         self.assertEqual(str(users[0].ip_address),
3873                          self.pg0.remote_ip4)
3874         # now we should have only 1 session, 1 deleted by HA
3875         sessions = self.vapi.nat44_user_session_dump(users[0].ip_address,
3876                                                      users[0].vrf_id)
3877         self.assertEqual(len(sessions), 1)
3878         stats = self.statistics.get_counter('/nat44/ha/del-event-recv')
3879         self.assertEqual(stats[0][0], 1)
3880
3881         stats = self.statistics.get_err_counter('/err/nat-ha/pkts-processed')
3882         self.assertEqual(stats, 2)
3883
3884         # send HA session refresh event to failover/passive
3885         p = (Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac) /
3886              IP(src=self.pg3.remote_ip4, dst=self.pg3.local_ip4) /
3887              UDP(sport=12346, dport=12345) /
3888              HANATStateSync(sequence_number=3, events=[
3889                  Event(event_type='refresh', protocol='tcp',
3890                        in_addr=self.pg0.remote_ip4, out_addr=self.nat_addr,
3891                        in_port=self.tcp_port_in, out_port=self.tcp_port_out,
3892                        eh_addr=self.pg1.remote_ip4,
3893                        ehn_addr=self.pg1.remote_ip4,
3894                        eh_port=self.tcp_external_port,
3895                        ehn_port=self.tcp_external_port, fib_index=0,
3896                        total_bytes=1024, total_pkts=2)]))
3897         self.pg3.add_stream(p)
3898         self.pg_enable_capture(self.pg_interfaces)
3899         self.pg_start()
3900         # receive ACK
3901         capture = self.pg3.get_capture(1)
3902         p = capture[0]
3903         try:
3904             hanat = p[HANATStateSync]
3905         except IndexError:
3906             self.logger.error(ppp("Invalid packet:", p))
3907             raise
3908         else:
3909             self.assertEqual(hanat.sequence_number, 3)
3910             self.assertEqual(hanat.flags, 'ACK')
3911             self.assertEqual(hanat.version, 1)
3912         users = self.vapi.nat44_user_dump()
3913         self.assertEqual(len(users), 1)
3914         self.assertEqual(str(users[0].ip_address),
3915                          self.pg0.remote_ip4)
3916         sessions = self.vapi.nat44_user_session_dump(users[0].ip_address,
3917                                                      users[0].vrf_id)
3918         self.assertEqual(len(sessions), 1)
3919         session = sessions[0]
3920         self.assertEqual(session.total_bytes, 1024)
3921         self.assertEqual(session.total_pkts, 2)
3922         stats = self.statistics.get_counter('/nat44/ha/refresh-event-recv')
3923         self.assertEqual(stats[0][0], 1)
3924
3925         stats = self.statistics.get_err_counter('/err/nat-ha/pkts-processed')
3926         self.assertEqual(stats, 3)
3927
3928         # send packet to test session created by HA
3929         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
3930              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
3931              TCP(sport=self.tcp_external_port, dport=self.tcp_port_out))
3932         self.pg1.add_stream(p)
3933         self.pg_enable_capture(self.pg_interfaces)
3934         self.pg_start()
3935         capture = self.pg0.get_capture(1)
3936         p = capture[0]
3937         try:
3938             ip = p[IP]
3939             tcp = p[TCP]
3940         except IndexError:
3941             self.logger.error(ppp("Invalid packet:", p))
3942             raise
3943         else:
3944             self.assertEqual(ip.src, self.pg1.remote_ip4)
3945             self.assertEqual(ip.dst, self.pg0.remote_ip4)
3946             self.assertEqual(tcp.sport, self.tcp_external_port)
3947             self.assertEqual(tcp.dport, self.tcp_port_in)
3948
3949     def show_commands_at_teardown(self):
3950         self.logger.info(self.vapi.cli("show nat44 addresses"))
3951         self.logger.info(self.vapi.cli("show nat44 interfaces"))
3952         self.logger.info(self.vapi.cli("show nat44 static mappings"))
3953         self.logger.info(self.vapi.cli("show nat44 interface address"))
3954         self.logger.info(self.vapi.cli("show nat44 sessions detail"))
3955         self.logger.info(self.vapi.cli("show nat44 hash tables detail"))
3956         self.logger.info(self.vapi.cli("show nat timeouts"))
3957         self.logger.info(
3958             self.vapi.cli("show nat addr-port-assignment-alg"))
3959         self.logger.info(self.vapi.cli("show nat ha"))
3960
3961
3962 class TestNAT44EndpointDependent2(MethodHolder):
3963     """ Endpoint-Dependent mapping and filtering test cases """
3964
3965     @classmethod
3966     def tearDownClass(cls):
3967         super(TestNAT44EndpointDependent2, cls).tearDownClass()
3968
3969     def tearDown(self):
3970         super(TestNAT44EndpointDependent2, self).tearDown()
3971
3972     @classmethod
3973     def create_and_add_ip4_table(cls, i, table_id):
3974         cls.vapi.ip_table_add_del(is_add=1, table={'table_id': table_id})
3975         i.set_table_ip4(table_id)
3976
3977     @classmethod
3978     def setUpClass(cls):
3979         super(TestNAT44EndpointDependent2, cls).setUpClass()
3980
3981         cls.create_pg_interfaces(range(3))
3982         cls.interfaces = list(cls.pg_interfaces)
3983
3984         cls.create_and_add_ip4_table(cls.pg1, 10)
3985
3986         for i in cls.interfaces:
3987             i.admin_up()
3988             i.config_ip4()
3989             i.resolve_arp()
3990
3991             i.generate_remote_hosts(1)
3992             i.configure_ipv4_neighbors()
3993
3994     def setUp(self):
3995         super(TestNAT44EndpointDependent2, self).setUp()
3996         flags = self.nat44_config_flags.NAT44_IS_ENDPOINT_DEPENDENT
3997         self.vapi.nat44_plugin_enable_disable(enable=1, flags=flags)
3998
3999     def tearDown(self):
4000         super(TestNAT44EndpointDependent2, self).tearDown()
4001         if not self.vpp_dead:
4002             self.vapi.nat44_plugin_enable_disable(enable=0)
4003             self.vapi.cli("clear logging")
4004
4005     def nat_add_inside_interface(self, i):
4006         self.vapi.nat44_interface_add_del_feature(
4007             flags=self.config_flags.NAT_IS_INSIDE,
4008             sw_if_index=i.sw_if_index, is_add=1)
4009
4010     def nat_add_outside_interface(self, i):
4011         self.vapi.nat44_interface_add_del_feature(
4012             flags=self.config_flags.NAT_IS_OUTSIDE,
4013             sw_if_index=i.sw_if_index, is_add=1)
4014
4015     def nat_add_interface_address(self, i):
4016         self.nat_addr = i.local_ip4
4017         self.vapi.nat44_add_del_interface_addr(
4018             sw_if_index=i.sw_if_index, is_add=1)
4019
4020     def nat_add_address(self, address, vrf_id=0xFFFFFFFF):
4021         self.nat_addr = address
4022         self.nat44_add_address(address, vrf_id=vrf_id)
4023
4024     def cli(self, command):
4025         result = self.vapi.cli(command)
4026         self.logger.info(result)
4027         # print(result)
4028
4029     def show_configuration(self):
4030         self.cli("show interface")
4031         self.cli("show interface address")
4032         self.cli("show nat44 addresses")
4033         self.cli("show nat44 interfaces")
4034
4035     def create_tcp_stream(self, in_if, out_if, count):
4036         """
4037         Create tcp packet stream
4038
4039         :param in_if: Inside interface
4040         :param out_if: Outside interface
4041         :param count: count of packets to generate
4042         """
4043         pkts = []
4044         port = 6303
4045
4046         for i in range(count):
4047             p = (Ether(dst=in_if.local_mac, src=in_if.remote_mac) /
4048                  IP(src=in_if.remote_ip4, dst=out_if.remote_ip4, ttl=64) /
4049                  TCP(sport=port + i, dport=20))
4050             pkts.append(p)
4051
4052         return pkts
4053
4054     def test_session_limit_per_vrf(self):
4055
4056         inside = self.pg0
4057         inside_vrf10 = self.pg1
4058         outside = self.pg2
4059
4060         limit = 5
4061
4062         # 2 interfaces pg0, pg1 (vrf10, limit 1 tcp session)
4063         # non existing vrf_id makes process core dump
4064         self.vapi.nat44_set_session_limit(session_limit=limit, vrf_id=10)
4065
4066         self.nat_add_inside_interface(inside)
4067         self.nat_add_inside_interface(inside_vrf10)
4068         self.nat_add_outside_interface(outside)
4069
4070         # vrf independent
4071         self.nat_add_interface_address(outside)
4072
4073         # BUG: causing core dump - when bad vrf_id is specified
4074         # self.nat44_add_address(outside.local_ip4, vrf_id=20)
4075
4076         self.show_configuration()
4077
4078         stream = self.create_tcp_stream(inside_vrf10, outside, limit * 2)
4079         inside_vrf10.add_stream(stream)
4080
4081         self.pg_enable_capture(self.pg_interfaces)
4082         self.pg_start()
4083
4084         capture = outside.get_capture(limit)
4085
4086         stream = self.create_tcp_stream(inside, outside, limit * 2)
4087         inside.add_stream(stream)
4088
4089         self.pg_enable_capture(self.pg_interfaces)
4090         self.pg_start()
4091
4092         capture = outside.get_capture(len(stream))
4093
4094
4095 class TestNAT44EndpointDependent(MethodHolder):
4096     """ Endpoint-Dependent mapping and filtering test cases """
4097
4098     @classmethod
4099     def setUpClass(cls):
4100         super(TestNAT44EndpointDependent, cls).setUpClass()
4101         cls.vapi.cli("set log class nat level debug")
4102
4103         cls.tcp_port_in = 6303
4104         cls.tcp_port_out = 6303
4105         cls.udp_port_in = 6304
4106         cls.udp_port_out = 6304
4107         cls.icmp_id_in = 6305
4108         cls.icmp_id_out = 6305
4109         cls.nat_addr = '10.0.0.3'
4110         cls.ipfix_src_port = 4739
4111         cls.ipfix_domain_id = 1
4112         cls.tcp_external_port = 80
4113
4114         cls.create_pg_interfaces(range(9))
4115         cls.interfaces = list(cls.pg_interfaces[0:3])
4116
4117         for i in cls.interfaces:
4118             i.admin_up()
4119             i.config_ip4()
4120             i.resolve_arp()
4121
4122         cls.pg0.generate_remote_hosts(3)
4123         cls.pg0.configure_ipv4_neighbors()
4124
4125         cls.pg3.admin_up()
4126
4127         cls.pg4.generate_remote_hosts(2)
4128         cls.pg4.config_ip4()
4129         cls.vapi.sw_interface_add_del_address(
4130             sw_if_index=cls.pg4.sw_if_index,
4131             prefix="10.0.0.1/24")
4132
4133         cls.pg4.admin_up()
4134         cls.pg4.resolve_arp()
4135         cls.pg4._remote_hosts[1]._ip4 = cls.pg4._remote_hosts[0]._ip4
4136         cls.pg4.resolve_arp()
4137
4138         zero_ip4 = socket.inet_pton(socket.AF_INET, "0.0.0.0")
4139         cls.vapi.ip_table_add_del(is_add=1, table={'table_id': 1})
4140
4141         cls.pg5._local_ip4 = "10.1.1.1"
4142         cls.pg5._remote_hosts[0]._ip4 = "10.1.1.2"
4143         cls.pg5.set_table_ip4(1)
4144         cls.pg5.config_ip4()
4145         cls.pg5.admin_up()
4146         r1 = VppIpRoute(cls, cls.pg5.remote_ip4, 32,
4147                         [VppRoutePath("0.0.0.0",
4148                                       cls.pg5.sw_if_index)],
4149                         table_id=1,
4150                         register=False)
4151         r1.add_vpp_config()
4152
4153         cls.pg6._local_ip4 = "10.1.2.1"
4154         cls.pg6._remote_hosts[0]._ip4 = "10.1.2.2"
4155         cls.pg6.set_table_ip4(1)
4156         cls.pg6.config_ip4()
4157         cls.pg6.admin_up()
4158
4159         r2 = VppIpRoute(cls, cls.pg6.remote_ip4, 32,
4160                         [VppRoutePath("0.0.0.0",
4161                                       cls.pg6.sw_if_index)],
4162                         table_id=1,
4163                         register=False)
4164         r3 = VppIpRoute(cls, cls.pg6.remote_ip4, 16,
4165                         [VppRoutePath("0.0.0.0",
4166                                       0xffffffff,
4167                                       nh_table_id=1)],
4168                         table_id=0,
4169                         register=False)
4170         r4 = VppIpRoute(cls, "0.0.0.0", 0,
4171                         [VppRoutePath("0.0.0.0", 0xffffffff,
4172                                       nh_table_id=0)],
4173                         table_id=1,
4174                         register=False)
4175         r5 = VppIpRoute(cls, "0.0.0.0", 0,
4176                         [VppRoutePath(cls.pg1.local_ip4,
4177                                       cls.pg1.sw_if_index)],
4178                         register=False)
4179         r2.add_vpp_config()
4180         r3.add_vpp_config()
4181         r4.add_vpp_config()
4182         r5.add_vpp_config()
4183
4184         cls.pg5.resolve_arp()
4185         cls.pg6.resolve_arp()
4186
4187         cls.pg7.admin_up()
4188         cls.pg7.config_ip4()
4189         cls.pg7.resolve_arp()
4190         cls.pg7.generate_remote_hosts(3)
4191         cls.pg7.configure_ipv4_neighbors()
4192
4193         cls.pg8.admin_up()
4194         cls.pg8.config_ip4()
4195         cls.pg8.resolve_arp()
4196
4197     @classmethod
4198     def tearDownClass(cls):
4199         super(TestNAT44EndpointDependent, cls).tearDownClass()
4200
4201     def setUp(self):
4202         super(TestNAT44EndpointDependent, self).setUp()
4203         flags = self.nat44_config_flags.NAT44_IS_ENDPOINT_DEPENDENT
4204         self.vapi.nat44_plugin_enable_disable(enable=1, flags=flags)
4205         self.vapi.nat_set_timeouts(
4206             udp=300, tcp_established=7440,
4207             tcp_transitory=240, icmp=60)
4208
4209     def tearDown(self):
4210         super(TestNAT44EndpointDependent, self).tearDown()
4211         if not self.vpp_dead:
4212             self.vapi.nat44_plugin_enable_disable(enable=0)
4213             self.vapi.cli("clear logging")
4214
4215     def test_frag_in_order(self):
4216         """ NAT44 translate fragments arriving in order """
4217         self.nat44_add_address(self.nat_addr)
4218         flags = self.config_flags.NAT_IS_INSIDE
4219         self.vapi.nat44_interface_add_del_feature(
4220             sw_if_index=self.pg0.sw_if_index,
4221             flags=flags, is_add=1)
4222         self.vapi.nat44_interface_add_del_feature(
4223             sw_if_index=self.pg1.sw_if_index,
4224             is_add=1)
4225         self.frag_in_order(proto=IP_PROTOS.tcp, ignore_port=True)
4226         self.frag_in_order(proto=IP_PROTOS.udp, ignore_port=True)
4227         self.frag_in_order(proto=IP_PROTOS.icmp, ignore_port=True)
4228
4229     def test_frag_in_order_dont_translate(self):
4230         """ NAT44 don't translate fragments arriving in order """
4231         flags = self.config_flags.NAT_IS_INSIDE
4232         self.vapi.nat44_interface_add_del_feature(
4233             sw_if_index=self.pg0.sw_if_index,
4234             flags=flags, is_add=1)
4235         self.vapi.nat44_interface_add_del_feature(
4236             sw_if_index=self.pg1.sw_if_index,
4237             is_add=1)
4238         self.vapi.nat44_forwarding_enable_disable(enable=True)
4239         self.frag_in_order(proto=IP_PROTOS.tcp, dont_translate=True)
4240
4241     def test_frag_out_of_order(self):
4242         """ NAT44 translate fragments arriving out of order """
4243         self.nat44_add_address(self.nat_addr)
4244         flags = self.config_flags.NAT_IS_INSIDE
4245         self.vapi.nat44_interface_add_del_feature(
4246             sw_if_index=self.pg0.sw_if_index,
4247             flags=flags, is_add=1)
4248         self.vapi.nat44_interface_add_del_feature(
4249             sw_if_index=self.pg1.sw_if_index,
4250             is_add=1)
4251         self.frag_out_of_order(proto=IP_PROTOS.tcp, ignore_port=True)
4252         self.frag_out_of_order(proto=IP_PROTOS.udp, ignore_port=True)
4253         self.frag_out_of_order(proto=IP_PROTOS.icmp, ignore_port=True)
4254
4255     def test_frag_out_of_order_dont_translate(self):
4256         """ NAT44 don't translate fragments arriving out of order """
4257         flags = self.config_flags.NAT_IS_INSIDE
4258         self.vapi.nat44_interface_add_del_feature(
4259             sw_if_index=self.pg0.sw_if_index,
4260             flags=flags, is_add=1)
4261         self.vapi.nat44_interface_add_del_feature(
4262             sw_if_index=self.pg1.sw_if_index,
4263             is_add=1)
4264         self.vapi.nat44_forwarding_enable_disable(enable=True)
4265         self.frag_out_of_order(proto=IP_PROTOS.tcp, dont_translate=True)
4266
4267     def test_frag_in_order_in_plus_out(self):
4268         """ in+out interface fragments in order """
4269         flags = self.config_flags.NAT_IS_INSIDE
4270         self.vapi.nat44_interface_add_del_feature(
4271             sw_if_index=self.pg0.sw_if_index,
4272             is_add=1)
4273         self.vapi.nat44_interface_add_del_feature(
4274             sw_if_index=self.pg0.sw_if_index,
4275             flags=flags, is_add=1)
4276         self.vapi.nat44_interface_add_del_feature(
4277             sw_if_index=self.pg1.sw_if_index,
4278             is_add=1)
4279         self.vapi.nat44_interface_add_del_feature(
4280             sw_if_index=self.pg1.sw_if_index,
4281             flags=flags, is_add=1)
4282
4283         self.server = self.pg1.remote_hosts[0]
4284
4285         self.server_in_addr = self.server.ip4
4286         self.server_out_addr = '11.11.11.11'
4287         self.server_in_port = random.randint(1025, 65535)
4288         self.server_out_port = random.randint(1025, 65535)
4289
4290         self.nat44_add_address(self.server_out_addr)
4291
4292         # add static mappings for server
4293         self.nat44_add_static_mapping(self.server_in_addr,
4294                                       self.server_out_addr,
4295                                       self.server_in_port,
4296                                       self.server_out_port,
4297                                       proto=IP_PROTOS.tcp)
4298         self.nat44_add_static_mapping(self.server_in_addr,
4299                                       self.server_out_addr,
4300                                       self.server_in_port,
4301                                       self.server_out_port,
4302                                       proto=IP_PROTOS.udp)
4303         self.nat44_add_static_mapping(self.server_in_addr,
4304                                       self.server_out_addr,
4305                                       proto=IP_PROTOS.icmp)
4306
4307         self.frag_in_order_in_plus_out(proto=IP_PROTOS.tcp)
4308         self.frag_in_order_in_plus_out(proto=IP_PROTOS.udp)
4309         self.frag_in_order_in_plus_out(proto=IP_PROTOS.icmp)
4310
4311     def test_frag_out_of_order_in_plus_out(self):
4312         """ in+out interface fragments out of order """
4313         flags = self.config_flags.NAT_IS_INSIDE
4314         self.vapi.nat44_interface_add_del_feature(
4315             sw_if_index=self.pg0.sw_if_index,
4316             is_add=1)
4317         self.vapi.nat44_interface_add_del_feature(
4318             sw_if_index=self.pg0.sw_if_index,
4319             flags=flags, is_add=1)
4320         self.vapi.nat44_interface_add_del_feature(
4321             sw_if_index=self.pg1.sw_if_index,
4322             is_add=1)
4323         self.vapi.nat44_interface_add_del_feature(
4324             sw_if_index=self.pg1.sw_if_index,
4325             flags=flags, is_add=1)
4326
4327         self.server = self.pg1.remote_hosts[0]
4328
4329         self.server_in_addr = self.server.ip4
4330         self.server_out_addr = '11.11.11.11'
4331         self.server_in_port = random.randint(1025, 65535)
4332         self.server_out_port = random.randint(1025, 65535)
4333
4334         self.nat44_add_address(self.server_out_addr)
4335
4336         # add static mappings for server
4337         self.nat44_add_static_mapping(self.server_in_addr,
4338                                       self.server_out_addr,
4339                                       self.server_in_port,
4340                                       self.server_out_port,
4341                                       proto=IP_PROTOS.tcp)
4342         self.nat44_add_static_mapping(self.server_in_addr,
4343                                       self.server_out_addr,
4344                                       self.server_in_port,
4345                                       self.server_out_port,
4346                                       proto=IP_PROTOS.udp)
4347         self.nat44_add_static_mapping(self.server_in_addr,
4348                                       self.server_out_addr,
4349                                       proto=IP_PROTOS.icmp)
4350
4351         self.frag_out_of_order_in_plus_out(proto=IP_PROTOS.tcp)
4352         self.frag_out_of_order_in_plus_out(proto=IP_PROTOS.udp)
4353         self.frag_out_of_order_in_plus_out(proto=IP_PROTOS.icmp)
4354
4355     def test_reass_hairpinning(self):
4356         """ NAT44 fragments hairpinning """
4357         self.server = self.pg0.remote_hosts[1]
4358         self.host_in_port = random.randint(1025, 65535)
4359         self.server_in_port = random.randint(1025, 65535)
4360         self.server_out_port = random.randint(1025, 65535)
4361
4362         self.nat44_add_address(self.nat_addr)
4363         flags = self.config_flags.NAT_IS_INSIDE
4364         self.vapi.nat44_interface_add_del_feature(
4365             sw_if_index=self.pg0.sw_if_index,
4366             flags=flags, is_add=1)
4367         self.vapi.nat44_interface_add_del_feature(
4368             sw_if_index=self.pg1.sw_if_index,
4369             is_add=1)
4370         # add static mapping for server
4371         self.nat44_add_static_mapping(self.server.ip4, self.nat_addr,
4372                                       self.server_in_port,
4373                                       self.server_out_port,
4374                                       proto=IP_PROTOS.tcp)
4375         self.nat44_add_static_mapping(self.server.ip4, self.nat_addr,
4376                                       self.server_in_port,
4377                                       self.server_out_port,
4378                                       proto=IP_PROTOS.udp)
4379         self.nat44_add_static_mapping(self.server.ip4, self.nat_addr)
4380
4381         self.reass_hairpinning(proto=IP_PROTOS.tcp, ignore_port=True)
4382         self.reass_hairpinning(proto=IP_PROTOS.udp, ignore_port=True)
4383         self.reass_hairpinning(proto=IP_PROTOS.icmp, ignore_port=True)
4384
4385     def test_clear_sessions(self):
4386         """ NAT44 ED session clearing test """
4387
4388         self.nat44_add_address(self.nat_addr)
4389         flags = self.config_flags.NAT_IS_INSIDE
4390         self.vapi.nat44_interface_add_del_feature(
4391             sw_if_index=self.pg0.sw_if_index,
4392             flags=flags, is_add=1)
4393         self.vapi.nat44_interface_add_del_feature(
4394             sw_if_index=self.pg1.sw_if_index,
4395             is_add=1)
4396
4397         nat_config = self.vapi.nat_show_config()
4398         self.assertEqual(1, nat_config.endpoint_dependent)
4399
4400         pkts = self.create_stream_in(self.pg0, self.pg1)
4401         self.pg0.add_stream(pkts)
4402         self.pg_enable_capture(self.pg_interfaces)
4403         self.pg_start()
4404         capture = self.pg1.get_capture(len(pkts))
4405         self.verify_capture_out(capture, ignore_port=True)
4406
4407         sessions = self.statistics.get_counter('/nat44/total-sessions')
4408         self.assertTrue(sessions[0][0] > 0)
4409         self.logger.info("sessions before clearing: %s" % sessions[0][0])
4410
4411         # just for testing purposes
4412         self.logger.info(self.vapi.cli("show nat44 summary"))
4413
4414         self.vapi.cli("clear nat44 sessions")
4415
4416         self.logger.info(self.vapi.cli("show nat44 summary"))
4417
4418         sessions = self.statistics.get_counter('/nat44/total-sessions')
4419         self.assertEqual(sessions[0][0], 0)
4420         self.logger.info("sessions after clearing: %s" % sessions[0][0])
4421
4422     def test_dynamic(self):
4423         """ NAT44 dynamic translation test """
4424
4425         self.nat44_add_address(self.nat_addr)
4426         flags = self.config_flags.NAT_IS_INSIDE
4427         self.vapi.nat44_interface_add_del_feature(
4428             sw_if_index=self.pg0.sw_if_index,
4429             flags=flags, is_add=1)
4430         self.vapi.nat44_interface_add_del_feature(
4431             sw_if_index=self.pg1.sw_if_index,
4432             is_add=1)
4433
4434         nat_config = self.vapi.nat_show_config()
4435         self.assertEqual(1, nat_config.endpoint_dependent)
4436
4437         # in2out
4438         tcpn = self.statistics.get_counter('/nat44/ed/in2out/slowpath/tcp')[0]
4439         udpn = self.statistics.get_counter('/nat44/ed/in2out/slowpath/udp')[0]
4440         icmpn = self.statistics.get_counter(
4441             '/nat44/ed/in2out/slowpath/icmp')[0]
4442         drops = self.statistics.get_counter(
4443             '/nat44/ed/in2out/slowpath/drops')[0]
4444
4445         pkts = self.create_stream_in(self.pg0, self.pg1)
4446         self.pg0.add_stream(pkts)
4447         self.pg_enable_capture(self.pg_interfaces)
4448         self.pg_start()
4449         capture = self.pg1.get_capture(len(pkts))
4450         self.verify_capture_out(capture, ignore_port=True)
4451
4452         if_idx = self.pg0.sw_if_index
4453         cnt = self.statistics.get_counter('/nat44/ed/in2out/slowpath/tcp')[0]
4454         self.assertEqual(cnt[if_idx] - tcpn[if_idx], 2)
4455         cnt = self.statistics.get_counter('/nat44/ed/in2out/slowpath/udp')[0]
4456         self.assertEqual(cnt[if_idx] - udpn[if_idx], 1)
4457         cnt = self.statistics.get_counter('/nat44/ed/in2out/slowpath/icmp')[0]
4458         self.assertEqual(cnt[if_idx] - icmpn[if_idx], 1)
4459         cnt = self.statistics.get_counter('/nat44/ed/in2out/slowpath/drops')[0]
4460         self.assertEqual(cnt[if_idx] - drops[if_idx], 0)
4461
4462         # out2in
4463         tcpn = self.statistics.get_counter('/nat44/ed/out2in/fastpath/tcp')[0]
4464         udpn = self.statistics.get_counter('/nat44/ed/out2in/fastpath/udp')[0]
4465         icmpn = self.statistics.get_counter(
4466             '/nat44/ed/out2in/slowpath/icmp')[0]
4467         drops = self.statistics.get_counter(
4468             '/nat44/ed/out2in/fastpath/drops')[0]
4469
4470         pkts = self.create_stream_out(self.pg1)
4471         self.pg1.add_stream(pkts)
4472         self.pg_enable_capture(self.pg_interfaces)
4473         self.pg_start()
4474         capture = self.pg0.get_capture(len(pkts))
4475         self.verify_capture_in(capture, self.pg0)
4476
4477         if_idx = self.pg1.sw_if_index
4478         cnt = self.statistics.get_counter('/nat44/ed/out2in/fastpath/tcp')[0]
4479         self.assertEqual(cnt[if_idx] - tcpn[if_idx], 2)
4480         cnt = self.statistics.get_counter('/nat44/ed/out2in/fastpath/udp')[0]
4481         self.assertEqual(cnt[if_idx] - udpn[if_idx], 1)
4482         cnt = self.statistics.get_counter('/nat44/ed/out2in/slowpath/icmp')[0]
4483         self.assertEqual(cnt[if_idx] - icmpn[if_idx], 1)
4484         cnt = self.statistics.get_counter('/nat44/ed/out2in/fastpath/drops')[0]
4485         self.assertEqual(cnt[if_idx] - drops[if_idx], 0)
4486
4487         sessions = self.statistics.get_counter('/nat44/total-sessions')
4488         self.assertEqual(sessions[0][0], 3)
4489
4490     def test_dynamic_out_of_ports(self):
4491         """ NAT44 dynamic translation test: out of ports """
4492
4493         flags = self.config_flags.NAT_IS_INSIDE
4494         self.vapi.nat44_interface_add_del_feature(
4495             sw_if_index=self.pg0.sw_if_index,
4496             flags=flags, is_add=1)
4497         self.vapi.nat44_interface_add_del_feature(
4498             sw_if_index=self.pg1.sw_if_index,
4499             is_add=1)
4500
4501         nat_config = self.vapi.nat_show_config()
4502         self.assertEqual(1, nat_config.endpoint_dependent)
4503
4504         # in2out and no NAT addresses added
4505         err_old = self.statistics.get_err_counter(
4506             '/err/nat44-ed-in2out-slowpath/out of ports')
4507
4508         pkts = self.create_stream_in(self.pg0, self.pg1)
4509         self.pg0.add_stream(pkts)
4510         self.pg_enable_capture(self.pg_interfaces)
4511         self.pg_start()
4512         self.pg1.get_capture(0, timeout=1)
4513
4514         err_new = self.statistics.get_err_counter(
4515             '/err/nat44-ed-in2out-slowpath/out of ports')
4516
4517         self.assertEqual(err_new - err_old, len(pkts))
4518
4519         # in2out after NAT addresses added
4520         self.nat44_add_address(self.nat_addr)
4521
4522         err_old = self.statistics.get_err_counter(
4523             '/err/nat44-ed-in2out-slowpath/out of ports')
4524
4525         pkts = self.create_stream_in(self.pg0, self.pg1)
4526         self.pg0.add_stream(pkts)
4527         self.pg_enable_capture(self.pg_interfaces)
4528         self.pg_start()
4529         capture = self.pg1.get_capture(len(pkts))
4530         self.verify_capture_out(capture, ignore_port=True)
4531
4532         err_new = self.statistics.get_err_counter(
4533             '/err/nat44-ed-in2out-slowpath/out of ports')
4534
4535         self.assertEqual(err_new, err_old)
4536
4537     def test_dynamic_output_feature_vrf(self):
4538         """ NAT44 dynamic translation test: output-feature, VRF"""
4539
4540         # other then default (0)
4541         new_vrf_id = 22
4542
4543         self.nat44_add_address(self.nat_addr)
4544         flags = self.config_flags.NAT_IS_INSIDE
4545         self.vapi.nat44_interface_add_del_output_feature(
4546             sw_if_index=self.pg7.sw_if_index,
4547             flags=flags, is_add=1)
4548         self.vapi.nat44_interface_add_del_output_feature(
4549             sw_if_index=self.pg8.sw_if_index,
4550             is_add=1)
4551
4552         try:
4553             self.vapi.ip_table_add_del(is_add=1,
4554                                        table={'table_id': new_vrf_id})
4555
4556             self.pg7.unconfig_ip4()
4557             self.pg7.set_table_ip4(new_vrf_id)
4558             self.pg7.config_ip4()
4559             self.pg7.resolve_arp()
4560
4561             self.pg8.unconfig_ip4()
4562             self.pg8.set_table_ip4(new_vrf_id)
4563             self.pg8.config_ip4()
4564             self.pg8.resolve_arp()
4565
4566             nat_config = self.vapi.nat_show_config()
4567             self.assertEqual(1, nat_config.endpoint_dependent)
4568
4569             # in2out
4570             tcpn = self.statistics.get_counter(
4571                 '/nat44/ed/in2out/slowpath/tcp')[0]
4572             udpn = self.statistics.get_counter(
4573                 '/nat44/ed/in2out/slowpath/udp')[0]
4574             icmpn = self.statistics.get_counter(
4575                 '/nat44/ed/in2out/slowpath/icmp')[0]
4576             drops = self.statistics.get_counter(
4577                 '/nat44/ed/in2out/slowpath/drops')[0]
4578
4579             pkts = self.create_stream_in(self.pg7, self.pg8)
4580             self.pg7.add_stream(pkts)
4581             self.pg_enable_capture(self.pg_interfaces)
4582             self.pg_start()
4583             capture = self.pg8.get_capture(len(pkts))
4584             self.verify_capture_out(capture, ignore_port=True)
4585
4586             if_idx = self.pg7.sw_if_index
4587             cnt = self.statistics.get_counter(
4588                 '/nat44/ed/in2out/slowpath/tcp')[0]
4589             self.assertEqual(cnt[if_idx] - tcpn[if_idx], 2)
4590             cnt = self.statistics.get_counter(
4591                 '/nat44/ed/in2out/slowpath/udp')[0]
4592             self.assertEqual(cnt[if_idx] - udpn[if_idx], 1)
4593             cnt = self.statistics.get_counter(
4594                 '/nat44/ed/in2out/slowpath/icmp')[0]
4595             self.assertEqual(cnt[if_idx] - icmpn[if_idx], 1)
4596             cnt = self.statistics.get_counter(
4597                 '/nat44/ed/in2out/slowpath/drops')[0]
4598             self.assertEqual(cnt[if_idx] - drops[if_idx], 0)
4599
4600             # out2in
4601             tcpn = self.statistics.get_counter(
4602                 '/nat44/ed/out2in/fastpath/tcp')[0]
4603             udpn = self.statistics.get_counter(
4604                 '/nat44/ed/out2in/fastpath/udp')[0]
4605             icmpn = self.statistics.get_counter(
4606                 '/nat44/ed/out2in/slowpath/icmp')[0]
4607             drops = self.statistics.get_counter(
4608                 '/nat44/ed/out2in/fastpath/drops')[0]
4609
4610             pkts = self.create_stream_out(self.pg8)
4611             self.pg8.add_stream(pkts)
4612             self.pg_enable_capture(self.pg_interfaces)
4613             self.pg_start()
4614             capture = self.pg7.get_capture(len(pkts))
4615             self.verify_capture_in(capture, self.pg7)
4616
4617             if_idx = self.pg8.sw_if_index
4618             cnt = self.statistics.get_counter(
4619                 '/nat44/ed/out2in/fastpath/tcp')[0]
4620             self.assertEqual(cnt[if_idx] - tcpn[if_idx], 2)
4621             cnt = self.statistics.get_counter(
4622                 '/nat44/ed/out2in/fastpath/udp')[0]
4623             self.assertEqual(cnt[if_idx] - udpn[if_idx], 1)
4624             cnt = self.statistics.get_counter(
4625                 '/nat44/ed/out2in/slowpath/icmp')[0]
4626             self.assertEqual(cnt[if_idx] - icmpn[if_idx], 1)
4627             cnt = self.statistics.get_counter(
4628                 '/nat44/ed/out2in/fastpath/drops')[0]
4629             self.assertEqual(cnt[if_idx] - drops[if_idx], 0)
4630
4631             sessions = self.statistics.get_counter('/nat44/total-sessions')
4632             self.assertEqual(sessions[0][0], 3)
4633
4634         finally:
4635             self.pg7.unconfig_ip4()
4636             self.pg7.set_table_ip4(1)
4637             self.pg7.config_ip4()
4638             self.pg7.resolve_arp()
4639
4640             self.pg8.unconfig_ip4()
4641             self.pg8.set_table_ip4(1)
4642             self.pg8.config_ip4()
4643             self.pg8.resolve_arp()
4644
4645             self.vapi.ip_table_add_del(is_add=0,
4646                                        table={'table_id': new_vrf_id})
4647
4648     def test_forwarding(self):
4649         """ NAT44 forwarding test """
4650
4651         flags = self.config_flags.NAT_IS_INSIDE
4652         self.vapi.nat44_interface_add_del_feature(
4653             sw_if_index=self.pg0.sw_if_index,
4654             flags=flags, is_add=1)
4655         self.vapi.nat44_interface_add_del_feature(
4656             sw_if_index=self.pg1.sw_if_index,
4657             is_add=1)
4658         self.vapi.nat44_forwarding_enable_disable(enable=1)
4659
4660         real_ip = self.pg0.remote_ip4
4661         alias_ip = self.nat_addr
4662         flags = self.config_flags.NAT_IS_ADDR_ONLY
4663         self.vapi.nat44_add_del_static_mapping(is_add=1,
4664                                                local_ip_address=real_ip,
4665                                                external_ip_address=alias_ip,
4666                                                external_sw_if_index=0xFFFFFFFF,
4667                                                flags=flags)
4668
4669         try:
4670             # in2out - static mapping match
4671
4672             pkts = self.create_stream_out(self.pg1)
4673             self.pg1.add_stream(pkts)
4674             self.pg_enable_capture(self.pg_interfaces)
4675             self.pg_start()
4676             capture = self.pg0.get_capture(len(pkts))
4677             self.verify_capture_in(capture, self.pg0)
4678
4679             pkts = self.create_stream_in(self.pg0, self.pg1)
4680             self.pg0.add_stream(pkts)
4681             self.pg_enable_capture(self.pg_interfaces)
4682             self.pg_start()
4683             capture = self.pg1.get_capture(len(pkts))
4684             self.verify_capture_out(capture, same_port=True)
4685
4686             # in2out - no static mapping match
4687
4688             host0 = self.pg0.remote_hosts[0]
4689             self.pg0.remote_hosts[0] = self.pg0.remote_hosts[1]
4690             try:
4691                 pkts = self.create_stream_out(self.pg1,
4692                                               dst_ip=self.pg0.remote_ip4,
4693                                               use_inside_ports=True)
4694                 self.pg1.add_stream(pkts)
4695                 self.pg_enable_capture(self.pg_interfaces)
4696                 self.pg_start()
4697                 capture = self.pg0.get_capture(len(pkts))
4698                 self.verify_capture_in(capture, self.pg0)
4699
4700                 pkts = self.create_stream_in(self.pg0, self.pg1)
4701                 self.pg0.add_stream(pkts)
4702                 self.pg_enable_capture(self.pg_interfaces)
4703                 self.pg_start()
4704                 capture = self.pg1.get_capture(len(pkts))
4705                 self.verify_capture_out(capture, nat_ip=self.pg0.remote_ip4,
4706                                         same_port=True)
4707             finally:
4708                 self.pg0.remote_hosts[0] = host0
4709
4710             user = self.pg0.remote_hosts[1]
4711             sessions = self.vapi.nat44_user_session_dump(user.ip4, 0)
4712             self.assertEqual(len(sessions), 3)
4713             self.assertTrue(sessions[0].flags &
4714                             self.config_flags.NAT_IS_EXT_HOST_VALID)
4715             self.vapi.nat44_del_session(
4716                 address=sessions[0].inside_ip_address,
4717                 port=sessions[0].inside_port,
4718                 protocol=sessions[0].protocol,
4719                 flags=(self.config_flags.NAT_IS_INSIDE |
4720                        self.config_flags.NAT_IS_EXT_HOST_VALID),
4721                 ext_host_address=sessions[0].ext_host_address,
4722                 ext_host_port=sessions[0].ext_host_port)
4723             sessions = self.vapi.nat44_user_session_dump(user.ip4, 0)
4724             self.assertEqual(len(sessions), 2)
4725
4726         finally:
4727             self.vapi.nat44_forwarding_enable_disable(enable=0)
4728             flags = self.config_flags.NAT_IS_ADDR_ONLY
4729             self.vapi.nat44_add_del_static_mapping(
4730                 is_add=0,
4731                 local_ip_address=real_ip,
4732                 external_ip_address=alias_ip,
4733                 external_sw_if_index=0xFFFFFFFF,
4734                 flags=flags)
4735
4736     def test_static_lb(self):
4737         """ NAT44 local service load balancing """
4738         external_addr_n = self.nat_addr
4739         external_port = 80
4740         local_port = 8080
4741         server1 = self.pg0.remote_hosts[0]
4742         server2 = self.pg0.remote_hosts[1]
4743
4744         locals = [{'addr': server1.ip4,
4745                    'port': local_port,
4746                    'probability': 70,
4747                    'vrf_id': 0},
4748                   {'addr': server2.ip4,
4749                    'port': local_port,
4750                    'probability': 30,
4751                    'vrf_id': 0}]
4752
4753         self.nat44_add_address(self.nat_addr)
4754         self.vapi.nat44_add_del_lb_static_mapping(
4755             is_add=1,
4756             external_addr=external_addr_n,
4757             external_port=external_port,
4758             protocol=IP_PROTOS.tcp,
4759             local_num=len(locals),
4760             locals=locals)
4761         flags = self.config_flags.NAT_IS_INSIDE
4762         self.vapi.nat44_interface_add_del_feature(
4763             sw_if_index=self.pg0.sw_if_index,
4764             flags=flags, is_add=1)
4765         self.vapi.nat44_interface_add_del_feature(
4766             sw_if_index=self.pg1.sw_if_index,
4767             is_add=1)
4768
4769         # from client to service
4770         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
4771              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
4772              TCP(sport=12345, dport=external_port))
4773         self.pg1.add_stream(p)
4774         self.pg_enable_capture(self.pg_interfaces)
4775         self.pg_start()
4776         capture = self.pg0.get_capture(1)
4777         p = capture[0]
4778         server = None
4779         try:
4780             ip = p[IP]
4781             tcp = p[TCP]
4782             self.assertIn(ip.dst, [server1.ip4, server2.ip4])
4783             if ip.dst == server1.ip4:
4784                 server = server1
4785             else:
4786                 server = server2
4787             self.assertEqual(tcp.dport, local_port)
4788             self.assert_packet_checksums_valid(p)
4789         except:
4790             self.logger.error(ppp("Unexpected or invalid packet:", p))
4791             raise
4792
4793         # from service back to client
4794         p = (Ether(src=server.mac, dst=self.pg0.local_mac) /
4795              IP(src=server.ip4, dst=self.pg1.remote_ip4) /
4796              TCP(sport=local_port, dport=12345))
4797         self.pg0.add_stream(p)
4798         self.pg_enable_capture(self.pg_interfaces)
4799         self.pg_start()
4800         capture = self.pg1.get_capture(1)
4801         p = capture[0]
4802         try:
4803             ip = p[IP]
4804             tcp = p[TCP]
4805             self.assertEqual(ip.src, self.nat_addr)
4806             self.assertEqual(tcp.sport, external_port)
4807             self.assert_packet_checksums_valid(p)
4808         except:
4809             self.logger.error(ppp("Unexpected or invalid packet:", p))
4810             raise
4811
4812         sessions = self.vapi.nat44_user_session_dump(server.ip4, 0)
4813         self.assertEqual(len(sessions), 1)
4814         self.assertTrue(sessions[0].flags &
4815                         self.config_flags.NAT_IS_EXT_HOST_VALID)
4816         self.vapi.nat44_del_session(
4817             address=sessions[0].inside_ip_address,
4818             port=sessions[0].inside_port,
4819             protocol=sessions[0].protocol,
4820             flags=(self.config_flags.NAT_IS_INSIDE |
4821                    self.config_flags.NAT_IS_EXT_HOST_VALID),
4822             ext_host_address=sessions[0].ext_host_address,
4823             ext_host_port=sessions[0].ext_host_port)
4824         sessions = self.vapi.nat44_user_session_dump(server.ip4, 0)
4825         self.assertEqual(len(sessions), 0)
4826
4827     def test_static_lb_multi_clients(self):
4828         """ NAT44 local service load balancing - multiple clients"""
4829
4830         external_addr = self.nat_addr
4831         external_port = 80
4832         local_port = 8080
4833         server1 = self.pg0.remote_hosts[0]
4834         server2 = self.pg0.remote_hosts[1]
4835         server3 = self.pg0.remote_hosts[2]
4836
4837         locals = [{'addr': server1.ip4,
4838                    'port': local_port,
4839                    'probability': 90,
4840                    'vrf_id': 0},
4841                   {'addr': server2.ip4,
4842                    'port': local_port,
4843                    'probability': 10,
4844                    'vrf_id': 0}]
4845
4846         flags = self.config_flags.NAT_IS_INSIDE
4847         self.vapi.nat44_interface_add_del_feature(
4848             sw_if_index=self.pg0.sw_if_index,
4849             flags=flags, is_add=1)
4850         self.vapi.nat44_interface_add_del_feature(
4851             sw_if_index=self.pg1.sw_if_index,
4852             is_add=1)
4853
4854         self.nat44_add_address(self.nat_addr)
4855         self.vapi.nat44_add_del_lb_static_mapping(is_add=1,
4856                                                   external_addr=external_addr,
4857                                                   external_port=external_port,
4858                                                   protocol=IP_PROTOS.tcp,
4859                                                   local_num=len(locals),
4860                                                   locals=locals)
4861
4862         server1_n = 0
4863         server2_n = 0
4864         clients = ip4_range(self.pg1.remote_ip4, 10, 50)
4865         pkts = []
4866         for client in clients:
4867             p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
4868                  IP(src=client, dst=self.nat_addr) /
4869                  TCP(sport=12345, dport=external_port))
4870             pkts.append(p)
4871         self.pg1.add_stream(pkts)
4872         self.pg_enable_capture(self.pg_interfaces)
4873         self.pg_start()
4874         capture = self.pg0.get_capture(len(pkts))
4875         for p in capture:
4876             if p[IP].dst == server1.ip4:
4877                 server1_n += 1
4878             else:
4879                 server2_n += 1
4880         self.assertGreater(server1_n, server2_n)
4881
4882         local = {
4883             'addr': server3.ip4,
4884             'port': local_port,
4885             'probability': 20,
4886             'vrf_id': 0
4887         }
4888
4889         # add new back-end
4890         self.vapi.nat44_lb_static_mapping_add_del_local(
4891             is_add=1,
4892             external_addr=external_addr,
4893             external_port=external_port,
4894             local=local,
4895             protocol=IP_PROTOS.tcp)
4896         server1_n = 0
4897         server2_n = 0
4898         server3_n = 0
4899         clients = ip4_range(self.pg1.remote_ip4, 60, 110)
4900         pkts = []
4901         for client in clients:
4902             p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
4903                  IP(src=client, dst=self.nat_addr) /
4904                  TCP(sport=12346, dport=external_port))
4905             pkts.append(p)
4906         self.assertGreater(len(pkts), 0)
4907         self.pg1.add_stream(pkts)
4908         self.pg_enable_capture(self.pg_interfaces)
4909         self.pg_start()
4910         capture = self.pg0.get_capture(len(pkts))
4911         for p in capture:
4912             if p[IP].dst == server1.ip4:
4913                 server1_n += 1
4914             elif p[IP].dst == server2.ip4:
4915                 server2_n += 1
4916             else:
4917                 server3_n += 1
4918         self.assertGreater(server1_n, 0)
4919         self.assertGreater(server2_n, 0)
4920         self.assertGreater(server3_n, 0)
4921
4922         local = {
4923             'addr': server2.ip4,
4924             'port': local_port,
4925             'probability': 10,
4926             'vrf_id': 0
4927         }
4928
4929         # remove one back-end
4930         self.vapi.nat44_lb_static_mapping_add_del_local(
4931             is_add=0,
4932             external_addr=external_addr,
4933             external_port=external_port,
4934             local=local,
4935             protocol=IP_PROTOS.tcp)
4936         server1_n = 0
4937         server2_n = 0
4938         server3_n = 0
4939         self.pg1.add_stream(pkts)
4940         self.pg_enable_capture(self.pg_interfaces)
4941         self.pg_start()
4942         capture = self.pg0.get_capture(len(pkts))
4943         for p in capture:
4944             if p[IP].dst == server1.ip4:
4945                 server1_n += 1
4946             elif p[IP].dst == server2.ip4:
4947                 server2_n += 1
4948             else:
4949                 server3_n += 1
4950         self.assertGreater(server1_n, 0)
4951         self.assertEqual(server2_n, 0)
4952         self.assertGreater(server3_n, 0)
4953
4954     def test_static_lb_2(self):
4955         """ NAT44 local service load balancing (asymmetrical rule) """
4956         external_addr = self.nat_addr
4957         external_port = 80
4958         local_port = 8080
4959         server1 = self.pg0.remote_hosts[0]
4960         server2 = self.pg0.remote_hosts[1]
4961
4962         locals = [{'addr': server1.ip4,
4963                    'port': local_port,
4964                    'probability': 70,
4965                    'vrf_id': 0},
4966                   {'addr': server2.ip4,
4967                    'port': local_port,
4968                    'probability': 30,
4969                    'vrf_id': 0}]
4970
4971         self.vapi.nat44_forwarding_enable_disable(enable=1)
4972         flags = self.config_flags.NAT_IS_OUT2IN_ONLY
4973         self.vapi.nat44_add_del_lb_static_mapping(is_add=1, flags=flags,
4974                                                   external_addr=external_addr,
4975                                                   external_port=external_port,
4976                                                   protocol=IP_PROTOS.tcp,
4977                                                   local_num=len(locals),
4978                                                   locals=locals)
4979         flags = self.config_flags.NAT_IS_INSIDE
4980         self.vapi.nat44_interface_add_del_feature(
4981             sw_if_index=self.pg0.sw_if_index,
4982             flags=flags, is_add=1)
4983         self.vapi.nat44_interface_add_del_feature(
4984             sw_if_index=self.pg1.sw_if_index,
4985             is_add=1)
4986
4987         # from client to service
4988         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
4989              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
4990              TCP(sport=12345, dport=external_port))
4991         self.pg1.add_stream(p)
4992         self.pg_enable_capture(self.pg_interfaces)
4993         self.pg_start()
4994         capture = self.pg0.get_capture(1)
4995         p = capture[0]
4996         server = None
4997         try:
4998             ip = p[IP]
4999             tcp = p[TCP]
5000             self.assertIn(ip.dst, [server1.ip4, server2.ip4])
5001             if ip.dst == server1.ip4:
5002                 server = server1
5003             else:
5004                 server = server2
5005             self.assertEqual(tcp.dport, local_port)
5006             self.assert_packet_checksums_valid(p)
5007         except:
5008             self.logger.error(ppp("Unexpected or invalid packet:", p))
5009             raise
5010
5011         # from service back to client
5012         p = (Ether(src=server.mac, dst=self.pg0.local_mac) /
5013              IP(src=server.ip4, dst=self.pg1.remote_ip4) /
5014              TCP(sport=local_port, dport=12345))
5015         self.pg0.add_stream(p)
5016         self.pg_enable_capture(self.pg_interfaces)
5017         self.pg_start()
5018         capture = self.pg1.get_capture(1)
5019         p = capture[0]
5020         try:
5021             ip = p[IP]
5022             tcp = p[TCP]
5023             self.assertEqual(ip.src, self.nat_addr)
5024             self.assertEqual(tcp.sport, external_port)
5025             self.assert_packet_checksums_valid(p)
5026         except:
5027             self.logger.error(ppp("Unexpected or invalid packet:", p))
5028             raise
5029
5030         # from client to server (no translation)
5031         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
5032              IP(src=self.pg1.remote_ip4, dst=server1.ip4) /
5033              TCP(sport=12346, dport=local_port))
5034         self.pg1.add_stream(p)
5035         self.pg_enable_capture(self.pg_interfaces)
5036         self.pg_start()
5037         capture = self.pg0.get_capture(1)
5038         p = capture[0]
5039         server = None
5040         try:
5041             ip = p[IP]
5042             tcp = p[TCP]
5043             self.assertEqual(ip.dst, server1.ip4)
5044             self.assertEqual(tcp.dport, local_port)
5045             self.assert_packet_checksums_valid(p)
5046         except:
5047             self.logger.error(ppp("Unexpected or invalid packet:", p))
5048             raise
5049
5050         # from service back to client (no translation)
5051         p = (Ether(src=server1.mac, dst=self.pg0.local_mac) /
5052              IP(src=server1.ip4, dst=self.pg1.remote_ip4) /
5053              TCP(sport=local_port, dport=12346))
5054         self.pg0.add_stream(p)
5055         self.pg_enable_capture(self.pg_interfaces)
5056         self.pg_start()
5057         capture = self.pg1.get_capture(1)
5058         p = capture[0]
5059         try:
5060             ip = p[IP]
5061             tcp = p[TCP]
5062             self.assertEqual(ip.src, server1.ip4)
5063             self.assertEqual(tcp.sport, local_port)
5064             self.assert_packet_checksums_valid(p)
5065         except:
5066             self.logger.error(ppp("Unexpected or invalid packet:", p))
5067             raise
5068
5069     def test_lb_affinity(self):
5070         """ NAT44 local service load balancing affinity """
5071         external_addr = self.nat_addr
5072         external_port = 80
5073         local_port = 8080
5074         server1 = self.pg0.remote_hosts[0]
5075         server2 = self.pg0.remote_hosts[1]
5076
5077         locals = [{'addr': server1.ip4,
5078                    'port': local_port,
5079                    'probability': 50,
5080                    'vrf_id': 0},
5081                   {'addr': server2.ip4,
5082                    'port': local_port,
5083                    'probability': 50,
5084                    'vrf_id': 0}]
5085
5086         self.nat44_add_address(self.nat_addr)
5087         self.vapi.nat44_add_del_lb_static_mapping(is_add=1,
5088                                                   external_addr=external_addr,
5089                                                   external_port=external_port,
5090                                                   protocol=IP_PROTOS.tcp,
5091                                                   affinity=10800,
5092                                                   local_num=len(locals),
5093                                                   locals=locals)
5094         flags = self.config_flags.NAT_IS_INSIDE
5095         self.vapi.nat44_interface_add_del_feature(
5096             sw_if_index=self.pg0.sw_if_index,
5097             flags=flags, is_add=1)
5098         self.vapi.nat44_interface_add_del_feature(
5099             sw_if_index=self.pg1.sw_if_index,
5100             is_add=1)
5101
5102         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
5103              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
5104              TCP(sport=1025, dport=external_port))
5105         self.pg1.add_stream(p)
5106         self.pg_enable_capture(self.pg_interfaces)
5107         self.pg_start()
5108         capture = self.pg0.get_capture(1)
5109         backend = capture[0][IP].dst
5110
5111         sessions = self.vapi.nat44_user_session_dump(backend, 0)
5112         self.assertEqual(len(sessions), 1)
5113         self.assertTrue(sessions[0].flags &
5114                         self.config_flags.NAT_IS_EXT_HOST_VALID)
5115         self.vapi.nat44_del_session(
5116             address=sessions[0].inside_ip_address,
5117             port=sessions[0].inside_port,
5118             protocol=sessions[0].protocol,
5119             flags=(self.config_flags.NAT_IS_INSIDE |
5120                    self.config_flags.NAT_IS_EXT_HOST_VALID),
5121             ext_host_address=sessions[0].ext_host_address,
5122             ext_host_port=sessions[0].ext_host_port)
5123
5124         pkts = []
5125         for port in range(1030, 1100):
5126             p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
5127                  IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
5128                  TCP(sport=port, dport=external_port))
5129             pkts.append(p)
5130         self.pg1.add_stream(pkts)
5131         self.pg_enable_capture(self.pg_interfaces)
5132         self.pg_start()
5133         capture = self.pg0.get_capture(len(pkts))
5134         for p in capture:
5135             self.assertEqual(p[IP].dst, backend)
5136
5137     def test_unknown_proto(self):
5138         """ NAT44 translate packet with unknown protocol """
5139         self.nat44_add_address(self.nat_addr)
5140         flags = self.config_flags.NAT_IS_INSIDE
5141         self.vapi.nat44_interface_add_del_feature(
5142             sw_if_index=self.pg0.sw_if_index,
5143             flags=flags, is_add=1)
5144         self.vapi.nat44_interface_add_del_feature(
5145             sw_if_index=self.pg1.sw_if_index,
5146             is_add=1)
5147
5148         # in2out
5149         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
5150              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
5151              TCP(sport=self.tcp_port_in, dport=20))
5152         self.pg0.add_stream(p)
5153         self.pg_enable_capture(self.pg_interfaces)
5154         self.pg_start()
5155         p = self.pg1.get_capture(1)
5156
5157         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
5158              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
5159              GRE() /
5160              IP(src=self.pg2.remote_ip4, dst=self.pg2.remote_ip4) /
5161              TCP(sport=1234, dport=1234))
5162         self.pg0.add_stream(p)
5163         self.pg_enable_capture(self.pg_interfaces)
5164         self.pg_start()
5165         p = self.pg1.get_capture(1)
5166         packet = p[0]
5167         try:
5168             self.assertEqual(packet[IP].src, self.nat_addr)
5169             self.assertEqual(packet[IP].dst, self.pg1.remote_ip4)
5170             self.assertEqual(packet.haslayer(GRE), 1)
5171             self.assert_packet_checksums_valid(packet)
5172         except:
5173             self.logger.error(ppp("Unexpected or invalid packet:", packet))
5174             raise
5175
5176         # out2in
5177         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
5178              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
5179              GRE() /
5180              IP(src=self.pg2.remote_ip4, dst=self.pg2.remote_ip4) /
5181              TCP(sport=1234, dport=1234))
5182         self.pg1.add_stream(p)
5183         self.pg_enable_capture(self.pg_interfaces)
5184         self.pg_start()
5185         p = self.pg0.get_capture(1)
5186         packet = p[0]
5187         try:
5188             self.assertEqual(packet[IP].src, self.pg1.remote_ip4)
5189             self.assertEqual(packet[IP].dst, self.pg0.remote_ip4)
5190             self.assertEqual(packet.haslayer(GRE), 1)
5191             self.assert_packet_checksums_valid(packet)
5192         except:
5193             self.logger.error(ppp("Unexpected or invalid packet:", packet))
5194             raise
5195
5196     def test_hairpinning_unknown_proto(self):
5197         """ NAT44 translate packet with unknown protocol - hairpinning """
5198         host = self.pg0.remote_hosts[0]
5199         server = self.pg0.remote_hosts[1]
5200         host_in_port = 1234
5201         server_out_port = 8765
5202         server_nat_ip = "10.0.0.11"
5203
5204         self.nat44_add_address(self.nat_addr)
5205         flags = self.config_flags.NAT_IS_INSIDE
5206         self.vapi.nat44_interface_add_del_feature(
5207             sw_if_index=self.pg0.sw_if_index,
5208             flags=flags, is_add=1)
5209         self.vapi.nat44_interface_add_del_feature(
5210             sw_if_index=self.pg1.sw_if_index,
5211             is_add=1)
5212
5213         # add static mapping for server
5214         self.nat44_add_static_mapping(server.ip4, server_nat_ip)
5215
5216         # host to server
5217         p = (Ether(src=host.mac, dst=self.pg0.local_mac) /
5218              IP(src=host.ip4, dst=server_nat_ip) /
5219              TCP(sport=host_in_port, dport=server_out_port))
5220         self.pg0.add_stream(p)
5221         self.pg_enable_capture(self.pg_interfaces)
5222         self.pg_start()
5223         self.pg0.get_capture(1)
5224
5225         p = (Ether(dst=self.pg0.local_mac, src=host.mac) /
5226              IP(src=host.ip4, dst=server_nat_ip) /
5227              GRE() /
5228              IP(src=self.pg2.remote_ip4, dst=self.pg2.remote_ip4) /
5229              TCP(sport=1234, dport=1234))
5230         self.pg0.add_stream(p)
5231         self.pg_enable_capture(self.pg_interfaces)
5232         self.pg_start()
5233         p = self.pg0.get_capture(1)
5234         packet = p[0]
5235         try:
5236             self.assertEqual(packet[IP].src, self.nat_addr)
5237             self.assertEqual(packet[IP].dst, server.ip4)
5238             self.assertEqual(packet.haslayer(GRE), 1)
5239             self.assert_packet_checksums_valid(packet)
5240         except:
5241             self.logger.error(ppp("Unexpected or invalid packet:", packet))
5242             raise
5243
5244         # server to host
5245         p = (Ether(dst=self.pg0.local_mac, src=server.mac) /
5246              IP(src=server.ip4, dst=self.nat_addr) /
5247              GRE() /
5248              IP(src=self.pg2.remote_ip4, dst=self.pg2.remote_ip4) /
5249              TCP(sport=1234, dport=1234))
5250         self.pg0.add_stream(p)
5251         self.pg_enable_capture(self.pg_interfaces)
5252         self.pg_start()
5253         p = self.pg0.get_capture(1)
5254         packet = p[0]
5255         try:
5256             self.assertEqual(packet[IP].src, server_nat_ip)
5257             self.assertEqual(packet[IP].dst, host.ip4)
5258             self.assertEqual(packet.haslayer(GRE), 1)
5259             self.assert_packet_checksums_valid(packet)
5260         except:
5261             self.logger.error(ppp("Unexpected or invalid packet:", packet))
5262             raise
5263
5264     def test_output_feature_and_service(self):
5265         """ NAT44 interface output feature and services """
5266         external_addr = '1.2.3.4'
5267         external_port = 80
5268         local_port = 8080
5269
5270         self.vapi.nat44_forwarding_enable_disable(enable=1)
5271         self.nat44_add_address(self.nat_addr)
5272         flags = self.config_flags.NAT_IS_ADDR_ONLY
5273         self.vapi.nat44_add_del_identity_mapping(
5274             ip_address=self.pg1.remote_ip4, sw_if_index=0xFFFFFFFF,
5275             flags=flags, is_add=1)
5276         flags = self.config_flags.NAT_IS_OUT2IN_ONLY
5277         self.nat44_add_static_mapping(self.pg0.remote_ip4, external_addr,
5278                                       local_port, external_port,
5279                                       proto=IP_PROTOS.tcp, flags=flags)
5280         flags = self.config_flags.NAT_IS_INSIDE
5281         self.vapi.nat44_interface_add_del_feature(
5282             sw_if_index=self.pg0.sw_if_index,
5283             is_add=1)
5284         self.vapi.nat44_interface_add_del_feature(
5285             sw_if_index=self.pg0.sw_if_index,
5286             flags=flags, is_add=1)
5287         self.vapi.nat44_interface_add_del_output_feature(
5288             is_add=1,
5289             sw_if_index=self.pg1.sw_if_index)
5290
5291         # from client to service
5292         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
5293              IP(src=self.pg1.remote_ip4, dst=external_addr) /
5294              TCP(sport=12345, dport=external_port))
5295         self.pg1.add_stream(p)
5296         self.pg_enable_capture(self.pg_interfaces)
5297         self.pg_start()
5298         capture = self.pg0.get_capture(1)
5299         p = capture[0]
5300         try:
5301             ip = p[IP]
5302             tcp = p[TCP]
5303             self.assertEqual(ip.dst, self.pg0.remote_ip4)
5304             self.assertEqual(tcp.dport, local_port)
5305             self.assert_packet_checksums_valid(p)
5306         except:
5307             self.logger.error(ppp("Unexpected or invalid packet:", p))
5308             raise
5309
5310         # from service back to client
5311         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
5312              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
5313              TCP(sport=local_port, dport=12345))
5314         self.pg0.add_stream(p)
5315         self.pg_enable_capture(self.pg_interfaces)
5316         self.pg_start()
5317         capture = self.pg1.get_capture(1)
5318         p = capture[0]
5319         try:
5320             ip = p[IP]
5321             tcp = p[TCP]
5322             self.assertEqual(ip.src, external_addr)
5323             self.assertEqual(tcp.sport, external_port)
5324             self.assert_packet_checksums_valid(p)
5325         except:
5326             self.logger.error(ppp("Unexpected or invalid packet:", p))
5327             raise
5328
5329         # from local network host to external network
5330         pkts = self.create_stream_in(self.pg0, self.pg1)
5331         self.pg0.add_stream(pkts)
5332         self.pg_enable_capture(self.pg_interfaces)
5333         self.pg_start()
5334         capture = self.pg1.get_capture(len(pkts))
5335         self.verify_capture_out(capture, ignore_port=True)
5336         pkts = self.create_stream_in(self.pg0, self.pg1)
5337         self.pg0.add_stream(pkts)
5338         self.pg_enable_capture(self.pg_interfaces)
5339         self.pg_start()
5340         capture = self.pg1.get_capture(len(pkts))
5341         self.verify_capture_out(capture, ignore_port=True)
5342
5343         # from external network back to local network host
5344         pkts = self.create_stream_out(self.pg1)
5345         self.pg1.add_stream(pkts)
5346         self.pg_enable_capture(self.pg_interfaces)
5347         self.pg_start()
5348         capture = self.pg0.get_capture(len(pkts))
5349         self.verify_capture_in(capture, self.pg0)
5350
5351     def test_output_feature_and_service2(self):
5352         """ NAT44 interface output feature and service host direct access """
5353         self.vapi.nat44_forwarding_enable_disable(enable=1)
5354         self.nat44_add_address(self.nat_addr)
5355         self.vapi.nat44_interface_add_del_output_feature(
5356             is_add=1,
5357             sw_if_index=self.pg1.sw_if_index)
5358
5359         # session initiated from service host - translate
5360         pkts = self.create_stream_in(self.pg0, self.pg1)
5361         self.pg0.add_stream(pkts)
5362         self.pg_enable_capture(self.pg_interfaces)
5363         self.pg_start()
5364         capture = self.pg1.get_capture(len(pkts))
5365         self.verify_capture_out(capture, ignore_port=True)
5366
5367         pkts = self.create_stream_out(self.pg1)
5368         self.pg1.add_stream(pkts)
5369         self.pg_enable_capture(self.pg_interfaces)
5370         self.pg_start()
5371         capture = self.pg0.get_capture(len(pkts))
5372         self.verify_capture_in(capture, self.pg0)
5373
5374         # session initiated from remote host - do not translate
5375         self.tcp_port_in = 60303
5376         self.udp_port_in = 60304
5377         self.icmp_id_in = 60305
5378         pkts = self.create_stream_out(self.pg1,
5379                                       self.pg0.remote_ip4,
5380                                       use_inside_ports=True)
5381         self.pg1.add_stream(pkts)
5382         self.pg_enable_capture(self.pg_interfaces)
5383         self.pg_start()
5384         capture = self.pg0.get_capture(len(pkts))
5385         self.verify_capture_in(capture, self.pg0)
5386
5387         pkts = self.create_stream_in(self.pg0, self.pg1)
5388         self.pg0.add_stream(pkts)
5389         self.pg_enable_capture(self.pg_interfaces)
5390         self.pg_start()
5391         capture = self.pg1.get_capture(len(pkts))
5392         self.verify_capture_out(capture, nat_ip=self.pg0.remote_ip4,
5393                                 same_port=True)
5394
5395     def test_output_feature_and_service3(self):
5396         """ NAT44 interface output feature and DST NAT """
5397         external_addr = '1.2.3.4'
5398         external_port = 80
5399         local_port = 8080
5400
5401         self.vapi.nat44_forwarding_enable_disable(enable=1)
5402         self.nat44_add_address(self.nat_addr)
5403         flags = self.config_flags.NAT_IS_OUT2IN_ONLY
5404         self.nat44_add_static_mapping(self.pg1.remote_ip4, external_addr,
5405                                       local_port, external_port,
5406                                       proto=IP_PROTOS.tcp, flags=flags)
5407         flags = self.config_flags.NAT_IS_INSIDE
5408         self.vapi.nat44_interface_add_del_feature(
5409             sw_if_index=self.pg0.sw_if_index,
5410             is_add=1)
5411         self.vapi.nat44_interface_add_del_feature(
5412             sw_if_index=self.pg0.sw_if_index,
5413             flags=flags, is_add=1)
5414         self.vapi.nat44_interface_add_del_output_feature(
5415             is_add=1,
5416             sw_if_index=self.pg1.sw_if_index)
5417
5418         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
5419              IP(src=self.pg0.remote_ip4, dst=external_addr) /
5420              TCP(sport=12345, dport=external_port))
5421         self.pg0.add_stream(p)
5422         self.pg_enable_capture(self.pg_interfaces)
5423         self.pg_start()
5424         capture = self.pg1.get_capture(1)
5425         p = capture[0]
5426         try:
5427             ip = p[IP]
5428             tcp = p[TCP]
5429             self.assertEqual(ip.src, self.pg0.remote_ip4)
5430             self.assertEqual(tcp.sport, 12345)
5431             self.assertEqual(ip.dst, self.pg1.remote_ip4)
5432             self.assertEqual(tcp.dport, local_port)
5433             self.assert_packet_checksums_valid(p)
5434         except:
5435             self.logger.error(ppp("Unexpected or invalid packet:", p))
5436             raise
5437
5438         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
5439              IP(src=self.pg1.remote_ip4, dst=self.pg0.remote_ip4) /
5440              TCP(sport=local_port, dport=12345))
5441         self.pg1.add_stream(p)
5442         self.pg_enable_capture(self.pg_interfaces)
5443         self.pg_start()
5444         capture = self.pg0.get_capture(1)
5445         p = capture[0]
5446         try:
5447             ip = p[IP]
5448             tcp = p[TCP]
5449             self.assertEqual(ip.src, external_addr)
5450             self.assertEqual(tcp.sport, external_port)
5451             self.assertEqual(ip.dst, self.pg0.remote_ip4)
5452             self.assertEqual(tcp.dport, 12345)
5453             self.assert_packet_checksums_valid(p)
5454         except:
5455             self.logger.error(ppp("Unexpected or invalid packet:", p))
5456             raise
5457
5458     def test_next_src_nat(self):
5459         """ On way back forward packet to nat44-in2out node. """
5460         twice_nat_addr = '10.0.1.3'
5461         external_port = 80
5462         local_port = 8080
5463         post_twice_nat_port = 0
5464
5465         self.vapi.nat44_forwarding_enable_disable(enable=1)
5466         self.nat44_add_address(twice_nat_addr, twice_nat=1)
5467         flags = (self.config_flags.NAT_IS_OUT2IN_ONLY |
5468                  self.config_flags.NAT_IS_SELF_TWICE_NAT)
5469         self.nat44_add_static_mapping(self.pg6.remote_ip4, self.pg1.remote_ip4,
5470                                       local_port, external_port,
5471                                       proto=IP_PROTOS.tcp, vrf_id=1,
5472                                       flags=flags)
5473         self.vapi.nat44_interface_add_del_feature(
5474             sw_if_index=self.pg6.sw_if_index,
5475             is_add=1)
5476
5477         p = (Ether(src=self.pg6.remote_mac, dst=self.pg6.local_mac) /
5478              IP(src=self.pg6.remote_ip4, dst=self.pg1.remote_ip4) /
5479              TCP(sport=12345, dport=external_port))
5480         self.pg6.add_stream(p)
5481         self.pg_enable_capture(self.pg_interfaces)
5482         self.pg_start()
5483         capture = self.pg6.get_capture(1)
5484         p = capture[0]
5485         try:
5486             ip = p[IP]
5487             tcp = p[TCP]
5488             self.assertEqual(ip.src, twice_nat_addr)
5489             self.assertNotEqual(tcp.sport, 12345)
5490             post_twice_nat_port = tcp.sport
5491             self.assertEqual(ip.dst, self.pg6.remote_ip4)
5492             self.assertEqual(tcp.dport, local_port)
5493             self.assert_packet_checksums_valid(p)
5494         except:
5495             self.logger.error(ppp("Unexpected or invalid packet:", p))
5496             raise
5497
5498         p = (Ether(src=self.pg6.remote_mac, dst=self.pg6.local_mac) /
5499              IP(src=self.pg6.remote_ip4, dst=twice_nat_addr) /
5500              TCP(sport=local_port, dport=post_twice_nat_port))
5501         self.pg6.add_stream(p)
5502         self.pg_enable_capture(self.pg_interfaces)
5503         self.pg_start()
5504         capture = self.pg6.get_capture(1)
5505         p = capture[0]
5506         try:
5507             ip = p[IP]
5508             tcp = p[TCP]
5509             self.assertEqual(ip.src, self.pg1.remote_ip4)
5510             self.assertEqual(tcp.sport, external_port)
5511             self.assertEqual(ip.dst, self.pg6.remote_ip4)
5512             self.assertEqual(tcp.dport, 12345)
5513             self.assert_packet_checksums_valid(p)
5514         except:
5515             self.logger.error(ppp("Unexpected or invalid packet:", p))
5516             raise
5517
5518     def twice_nat_common(self, self_twice_nat=False, same_pg=False, lb=False,
5519                          client_id=None):
5520         twice_nat_addr = '10.0.1.3'
5521
5522         port_in = 8080
5523         if lb:
5524             if not same_pg:
5525                 port_in1 = port_in
5526                 port_in2 = port_in
5527             else:
5528                 port_in1 = port_in + 1
5529                 port_in2 = port_in + 2
5530
5531         port_out = 80
5532         eh_port_out = 4567
5533
5534         server1 = self.pg0.remote_hosts[0]
5535         server2 = self.pg0.remote_hosts[1]
5536         if lb and same_pg:
5537             server2 = server1
5538         if not lb:
5539             server = server1
5540
5541         pg0 = self.pg0
5542         if same_pg:
5543             pg1 = self.pg0
5544         else:
5545             pg1 = self.pg1
5546
5547         eh_translate = ((not self_twice_nat) or (not lb and same_pg) or
5548                         client_id == 1)
5549
5550         self.nat44_add_address(self.nat_addr)
5551         self.nat44_add_address(twice_nat_addr, twice_nat=1)
5552
5553         flags = 0
5554         if self_twice_nat:
5555             flags |= self.config_flags.NAT_IS_SELF_TWICE_NAT
5556         else:
5557             flags |= self.config_flags.NAT_IS_TWICE_NAT
5558
5559         if not lb:
5560             self.nat44_add_static_mapping(pg0.remote_ip4, self.nat_addr,
5561                                           port_in, port_out,
5562                                           proto=IP_PROTOS.tcp,
5563                                           flags=flags)
5564         else:
5565             locals = [{'addr': server1.ip4,
5566                        'port': port_in1,
5567                        'probability': 50,
5568                        'vrf_id': 0},
5569                       {'addr': server2.ip4,
5570                        'port': port_in2,
5571                        'probability': 50,
5572                        'vrf_id': 0}]
5573             out_addr = self.nat_addr
5574
5575             self.vapi.nat44_add_del_lb_static_mapping(is_add=1, flags=flags,
5576                                                       external_addr=out_addr,
5577                                                       external_port=port_out,
5578                                                       protocol=IP_PROTOS.tcp,
5579                                                       local_num=len(locals),
5580                                                       locals=locals)
5581         flags = self.config_flags.NAT_IS_INSIDE
5582         self.vapi.nat44_interface_add_del_feature(
5583             sw_if_index=pg0.sw_if_index,
5584             flags=flags, is_add=1)
5585         self.vapi.nat44_interface_add_del_feature(
5586             sw_if_index=pg1.sw_if_index,
5587             is_add=1)
5588
5589         if same_pg:
5590             if not lb:
5591                 client = server
5592             else:
5593                 assert client_id is not None
5594                 if client_id == 1:
5595                     client = self.pg0.remote_hosts[0]
5596                 elif client_id == 2:
5597                     client = self.pg0.remote_hosts[1]
5598         else:
5599             client = pg1.remote_hosts[0]
5600         p = (Ether(src=pg1.remote_mac, dst=pg1.local_mac) /
5601              IP(src=client.ip4, dst=self.nat_addr) /
5602              TCP(sport=eh_port_out, dport=port_out))
5603         pg1.add_stream(p)
5604         self.pg_enable_capture(self.pg_interfaces)
5605         self.pg_start()
5606         capture = pg0.get_capture(1)
5607         p = capture[0]
5608         try:
5609             ip = p[IP]
5610             tcp = p[TCP]
5611             if lb:
5612                 if ip.dst == server1.ip4:
5613                     server = server1
5614                     port_in = port_in1
5615                 else:
5616                     server = server2
5617                     port_in = port_in2
5618             self.assertEqual(ip.dst, server.ip4)
5619             if lb and same_pg:
5620                 self.assertIn(tcp.dport, [port_in1, port_in2])
5621             else:
5622                 self.assertEqual(tcp.dport, port_in)
5623             if eh_translate:
5624                 self.assertEqual(ip.src, twice_nat_addr)
5625                 self.assertNotEqual(tcp.sport, eh_port_out)
5626             else:
5627                 self.assertEqual(ip.src, client.ip4)
5628                 self.assertEqual(tcp.sport, eh_port_out)
5629             eh_addr_in = ip.src
5630             eh_port_in = tcp.sport
5631             saved_port_in = tcp.dport
5632             self.assert_packet_checksums_valid(p)
5633         except:
5634             self.logger.error(ppp("Unexpected or invalid packet:", p))
5635             raise
5636
5637         p = (Ether(src=server.mac, dst=pg0.local_mac) /
5638              IP(src=server.ip4, dst=eh_addr_in) /
5639              TCP(sport=saved_port_in, dport=eh_port_in))
5640         pg0.add_stream(p)
5641         self.pg_enable_capture(self.pg_interfaces)
5642         self.pg_start()
5643         capture = pg1.get_capture(1)
5644         p = capture[0]
5645         try:
5646             ip = p[IP]
5647             tcp = p[TCP]
5648             self.assertEqual(ip.dst, client.ip4)
5649             self.assertEqual(ip.src, self.nat_addr)
5650             self.assertEqual(tcp.dport, eh_port_out)
5651             self.assertEqual(tcp.sport, port_out)
5652             self.assert_packet_checksums_valid(p)
5653         except:
5654             self.logger.error(ppp("Unexpected or invalid packet:", p))
5655             raise
5656
5657         if eh_translate:
5658             sessions = self.vapi.nat44_user_session_dump(server.ip4, 0)
5659             self.assertEqual(len(sessions), 1)
5660             self.assertTrue(sessions[0].flags &
5661                             self.config_flags.NAT_IS_EXT_HOST_VALID)
5662             self.assertTrue(sessions[0].flags &
5663                             self.config_flags.NAT_IS_TWICE_NAT)
5664             self.logger.info(self.vapi.cli("show nat44 sessions detail"))
5665             self.vapi.nat44_del_session(
5666                 address=sessions[0].inside_ip_address,
5667                 port=sessions[0].inside_port,
5668                 protocol=sessions[0].protocol,
5669                 flags=(self.config_flags.NAT_IS_INSIDE |
5670                        self.config_flags.NAT_IS_EXT_HOST_VALID),
5671                 ext_host_address=sessions[0].ext_host_nat_address,
5672                 ext_host_port=sessions[0].ext_host_nat_port)
5673             sessions = self.vapi.nat44_user_session_dump(server.ip4, 0)
5674             self.assertEqual(len(sessions), 0)
5675
5676     def test_twice_nat(self):
5677         """ Twice NAT44 """
5678         self.twice_nat_common()
5679
5680     def test_self_twice_nat_positive(self):
5681         """ Self Twice NAT44 (positive test) """
5682         self.twice_nat_common(self_twice_nat=True, same_pg=True)
5683
5684     def test_self_twice_nat_negative(self):
5685         """ Self Twice NAT44 (negative test) """
5686         self.twice_nat_common(self_twice_nat=True)
5687
5688     def test_twice_nat_lb(self):
5689         """ Twice NAT44 local service load balancing """
5690         self.twice_nat_common(lb=True)
5691
5692     def test_self_twice_nat_lb_positive(self):
5693         """ Self Twice NAT44 local service load balancing (positive test) """
5694         self.twice_nat_common(lb=True, self_twice_nat=True, same_pg=True,
5695                               client_id=1)
5696
5697     def test_self_twice_nat_lb_negative(self):
5698         """ Self Twice NAT44 local service load balancing (negative test) """
5699         self.twice_nat_common(lb=True, self_twice_nat=True, same_pg=True,
5700                               client_id=2)
5701
5702     def test_twice_nat_interface_addr(self):
5703         """ Acquire twice NAT44 addresses from interface """
5704         flags = self.config_flags.NAT_IS_TWICE_NAT
5705         self.vapi.nat44_add_del_interface_addr(
5706             is_add=1,
5707             sw_if_index=self.pg3.sw_if_index,
5708             flags=flags)
5709
5710         # no address in NAT pool
5711         adresses = self.vapi.nat44_address_dump()
5712         self.assertEqual(0, len(adresses))
5713
5714         # configure interface address and check NAT address pool
5715         self.pg3.config_ip4()
5716         adresses = self.vapi.nat44_address_dump()
5717         self.assertEqual(1, len(adresses))
5718         self.assertEqual(str(adresses[0].ip_address),
5719                          self.pg3.local_ip4)
5720         self.assertEqual(adresses[0].flags, flags)
5721
5722         # remove interface address and check NAT address pool
5723         self.pg3.unconfig_ip4()
5724         adresses = self.vapi.nat44_address_dump()
5725         self.assertEqual(0, len(adresses))
5726
5727     def test_tcp_close(self):
5728         """ Close TCP session from inside network - output feature """
5729         old_timeouts = self.vapi.nat_get_timeouts()
5730         new_transitory = 2
5731         self.vapi.nat_set_timeouts(
5732                 udp=old_timeouts.udp,
5733                 tcp_established=old_timeouts.tcp_established,
5734                 icmp=old_timeouts.icmp,
5735                 tcp_transitory=new_transitory)
5736
5737         self.vapi.nat44_forwarding_enable_disable(enable=1)
5738         self.nat44_add_address(self.pg1.local_ip4)
5739         twice_nat_addr = '10.0.1.3'
5740         service_ip = '192.168.16.150'
5741         self.nat44_add_address(twice_nat_addr, twice_nat=1)
5742         flags = self.config_flags.NAT_IS_INSIDE
5743         self.vapi.nat44_interface_add_del_feature(
5744             sw_if_index=self.pg0.sw_if_index,
5745             is_add=1)
5746         self.vapi.nat44_interface_add_del_feature(
5747             sw_if_index=self.pg0.sw_if_index,
5748             flags=flags, is_add=1)
5749         self.vapi.nat44_interface_add_del_output_feature(
5750             is_add=1,
5751             sw_if_index=self.pg1.sw_if_index)
5752         flags = (self.config_flags.NAT_IS_OUT2IN_ONLY |
5753                  self.config_flags.NAT_IS_TWICE_NAT)
5754         self.nat44_add_static_mapping(self.pg0.remote_ip4,
5755                                       service_ip,
5756                                       80,
5757                                       80,
5758                                       proto=IP_PROTOS.tcp,
5759                                       flags=flags)
5760         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
5761         start_sessnum = len(sessions)
5762
5763         # SYN packet out->in
5764         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
5765              IP(src=self.pg1.remote_ip4, dst=service_ip) /
5766              TCP(sport=33898, dport=80, flags="S"))
5767         self.pg1.add_stream(p)
5768         self.pg_enable_capture(self.pg_interfaces)
5769         self.pg_start()
5770         capture = self.pg0.get_capture(1)
5771         p = capture[0]
5772         tcp_port = p[TCP].sport
5773
5774         # SYN + ACK packet in->out
5775         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
5776              IP(src=self.pg0.remote_ip4, dst=twice_nat_addr) /
5777              TCP(sport=80, dport=tcp_port, flags="SA"))
5778         self.pg0.add_stream(p)
5779         self.pg_enable_capture(self.pg_interfaces)
5780         self.pg_start()
5781         self.pg1.get_capture(1)
5782
5783         # ACK packet out->in
5784         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
5785              IP(src=self.pg1.remote_ip4, dst=service_ip) /
5786              TCP(sport=33898, dport=80, flags="A"))
5787         self.pg1.add_stream(p)
5788         self.pg_enable_capture(self.pg_interfaces)
5789         self.pg_start()
5790         self.pg0.get_capture(1)
5791
5792         # FIN packet in -> out
5793         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
5794              IP(src=self.pg0.remote_ip4, dst=twice_nat_addr) /
5795              TCP(sport=80, dport=tcp_port, flags="FA", seq=100, ack=300))
5796         self.pg0.add_stream(p)
5797         self.pg_enable_capture(self.pg_interfaces)
5798         self.pg_start()
5799         self.pg1.get_capture(1)
5800
5801         # FIN+ACK packet out -> in
5802         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
5803              IP(src=self.pg1.remote_ip4, dst=service_ip) /
5804              TCP(sport=33898, dport=80, flags="FA", seq=300, ack=101))
5805         self.pg1.add_stream(p)
5806         self.pg_enable_capture(self.pg_interfaces)
5807         self.pg_start()
5808         self.pg0.get_capture(1)
5809
5810         # ACK packet in -> out
5811         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
5812              IP(src=self.pg0.remote_ip4, dst=twice_nat_addr) /
5813              TCP(sport=80, dport=tcp_port, flags="A", seq=101, ack=301))
5814         self.pg0.add_stream(p)
5815         self.pg_enable_capture(self.pg_interfaces)
5816         self.pg_start()
5817         self.pg1.get_capture(1)
5818
5819         # session now in transitory timeout
5820         # try SYN packet out->in - should be dropped
5821         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
5822              IP(src=self.pg1.remote_ip4, dst=service_ip) /
5823              TCP(sport=33898, dport=80, flags="S"))
5824         self.pg1.add_stream(p)
5825         self.pg_enable_capture(self.pg_interfaces)
5826         self.pg_start()
5827
5828         self.sleep(new_transitory, "wait for transitory timeout")
5829         self.pg0.assert_nothing_captured(0)
5830
5831         # session should still exist
5832         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
5833         self.assertEqual(len(sessions) - start_sessnum, 1)
5834
5835         # send FIN+ACK packet out -> in - will cause session to be wiped
5836         # but won't create a new session
5837         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
5838              IP(src=self.pg1.remote_ip4, dst=service_ip) /
5839              TCP(sport=33898, dport=80, flags="FA", seq=300, ack=101))
5840         self.pg1.add_stream(p)
5841         self.pg_enable_capture(self.pg_interfaces)
5842         self.pg_start()
5843
5844         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
5845         self.assertEqual(len(sessions) - start_sessnum, 0)
5846         self.pg0.assert_nothing_captured(0)
5847
5848     def test_tcp_session_close_in(self):
5849         """ Close TCP session from inside network """
5850         self.tcp_port_out = 10505
5851         self.nat44_add_address(self.nat_addr)
5852         flags = self.config_flags.NAT_IS_TWICE_NAT
5853         self.nat44_add_static_mapping(self.pg0.remote_ip4,
5854                                       self.nat_addr,
5855                                       self.tcp_port_in,
5856                                       self.tcp_port_out,
5857                                       proto=IP_PROTOS.tcp,
5858                                       flags=flags)
5859         flags = self.config_flags.NAT_IS_INSIDE
5860         self.vapi.nat44_interface_add_del_feature(
5861             sw_if_index=self.pg0.sw_if_index,
5862             flags=flags, is_add=1)
5863         self.vapi.nat44_interface_add_del_feature(
5864             sw_if_index=self.pg1.sw_if_index,
5865             is_add=1)
5866
5867         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
5868         start_sessnum = len(sessions)
5869
5870         self.vapi.nat_set_timeouts(udp=300, tcp_established=7440,
5871                                    tcp_transitory=2, icmp=5)
5872
5873         self.initiate_tcp_session(self.pg0, self.pg1)
5874
5875         # FIN packet in -> out
5876         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
5877              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
5878              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
5879                  flags="FA", seq=100, ack=300))
5880         self.pg0.add_stream(p)
5881         self.pg_enable_capture(self.pg_interfaces)
5882         self.pg_start()
5883         self.pg1.get_capture(1)
5884
5885         pkts = []
5886
5887         # ACK packet out -> in
5888         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
5889              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
5890              TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
5891                  flags="A", seq=300, ack=101))
5892         pkts.append(p)
5893
5894         # FIN packet out -> in
5895         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
5896              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
5897              TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
5898                  flags="FA", seq=300, ack=101))
5899         pkts.append(p)
5900
5901         self.pg1.add_stream(pkts)
5902         self.pg_enable_capture(self.pg_interfaces)
5903         self.pg_start()
5904         self.pg0.get_capture(2)
5905
5906         # ACK packet in -> out
5907         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
5908              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
5909              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
5910                  flags="A", seq=101, ack=301))
5911         self.pg0.add_stream(p)
5912         self.pg_enable_capture(self.pg_interfaces)
5913         self.pg_start()
5914         self.pg1.get_capture(1)
5915
5916         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
5917         self.assertEqual(len(sessions) - start_sessnum, 1)
5918
5919         stats = self.statistics.get_counter(
5920             '/err/nat44-ed-out2in/drops due to TCP in transitory timeout')
5921         out2in_drops = stats[0]
5922         stats = self.statistics.get_counter(
5923             '/err/nat44-ed-in2out/drops due to TCP in transitory timeout')
5924         in2out_drops = stats[0]
5925
5926         # extra FIN packet out -> in - this should be dropped
5927         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
5928              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
5929              TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
5930                  flags="FA", seq=300, ack=101))
5931
5932         self.pg1.add_stream(p)
5933         self.pg_enable_capture(self.pg_interfaces)
5934         self.pg_start()
5935         self.pg0.assert_nothing_captured()
5936
5937         # extra ACK packet in -> out - this should be dropped
5938         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
5939              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
5940              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
5941                  flags="A", seq=101, ack=301))
5942         self.pg0.add_stream(p)
5943         self.pg_enable_capture(self.pg_interfaces)
5944         self.pg_start()
5945         self.pg1.assert_nothing_captured()
5946
5947         stats = self.statistics.get_counter(
5948             '/err/nat44-ed-out2in/drops due to TCP in transitory timeout')
5949         self.assertEqual(stats[0] - out2in_drops, 1)
5950         stats = self.statistics.get_counter(
5951             '/err/nat44-ed-in2out/drops due to TCP in transitory timeout')
5952         self.assertEqual(stats[0] - in2out_drops, 1)
5953
5954         self.sleep(3)
5955         # extra ACK packet in -> out - this will cause session to be wiped
5956         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
5957              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
5958              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
5959                  flags="A", seq=101, ack=301))
5960         self.pg0.add_stream(p)
5961         self.pg_enable_capture(self.pg_interfaces)
5962         self.pg_start()
5963         self.pg1.assert_nothing_captured()
5964         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
5965         self.assertEqual(len(sessions) - start_sessnum, 0)
5966
5967     def test_tcp_session_close_out(self):
5968         """ Close TCP session from outside network """
5969         self.tcp_port_out = 10505
5970         self.nat44_add_address(self.nat_addr)
5971         flags = self.config_flags.NAT_IS_TWICE_NAT
5972         self.nat44_add_static_mapping(self.pg0.remote_ip4,
5973                                       self.nat_addr,
5974                                       self.tcp_port_in,
5975                                       self.tcp_port_out,
5976                                       proto=IP_PROTOS.tcp,
5977                                       flags=flags)
5978         flags = self.config_flags.NAT_IS_INSIDE
5979         self.vapi.nat44_interface_add_del_feature(
5980             sw_if_index=self.pg0.sw_if_index,
5981             flags=flags, is_add=1)
5982         self.vapi.nat44_interface_add_del_feature(
5983             sw_if_index=self.pg1.sw_if_index,
5984             is_add=1)
5985
5986         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
5987         start_sessnum = len(sessions)
5988
5989         self.vapi.nat_set_timeouts(udp=300, tcp_established=7440,
5990                                    tcp_transitory=2, icmp=5)
5991
5992         self.initiate_tcp_session(self.pg0, self.pg1)
5993
5994         # FIN packet out -> in
5995         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
5996              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
5997              TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
5998                  flags="FA", seq=100, ack=300))
5999         self.pg1.add_stream(p)
6000         self.pg_enable_capture(self.pg_interfaces)
6001         self.pg_start()
6002         self.pg0.get_capture(1)
6003
6004         # FIN+ACK packet in -> out
6005         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6006              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6007              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
6008                  flags="FA", seq=300, ack=101))
6009
6010         self.pg0.add_stream(p)
6011         self.pg_enable_capture(self.pg_interfaces)
6012         self.pg_start()
6013         self.pg1.get_capture(1)
6014
6015         # ACK packet out -> in
6016         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
6017              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
6018              TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
6019                  flags="A", seq=101, ack=301))
6020         self.pg1.add_stream(p)
6021         self.pg_enable_capture(self.pg_interfaces)
6022         self.pg_start()
6023         self.pg0.get_capture(1)
6024
6025         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
6026         self.assertEqual(len(sessions) - start_sessnum, 1)
6027
6028         stats = self.statistics.get_counter(
6029             '/err/nat44-ed-out2in/drops due to TCP in transitory timeout')
6030         out2in_drops = stats[0]
6031         stats = self.statistics.get_counter(
6032             '/err/nat44-ed-in2out/drops due to TCP in transitory timeout')
6033         in2out_drops = stats[0]
6034
6035         # extra FIN packet out -> in - this should be dropped
6036         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
6037              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
6038              TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
6039                  flags="FA", seq=300, ack=101))
6040
6041         self.pg1.add_stream(p)
6042         self.pg_enable_capture(self.pg_interfaces)
6043         self.pg_start()
6044         self.pg0.assert_nothing_captured()
6045
6046         # extra ACK packet in -> out - this should be dropped
6047         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6048              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6049              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
6050                  flags="A", seq=101, ack=301))
6051         self.pg0.add_stream(p)
6052         self.pg_enable_capture(self.pg_interfaces)
6053         self.pg_start()
6054         self.pg1.assert_nothing_captured()
6055
6056         stats = self.statistics.get_counter(
6057             '/err/nat44-ed-out2in/drops due to TCP in transitory timeout')
6058         self.assertEqual(stats[0] - out2in_drops, 1)
6059         stats = self.statistics.get_counter(
6060             '/err/nat44-ed-in2out/drops due to TCP in transitory timeout')
6061         self.assertEqual(stats[0] - in2out_drops, 1)
6062
6063         self.sleep(3)
6064         # extra ACK packet in -> out - this will cause session to be wiped
6065         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6066              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6067              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
6068                  flags="A", seq=101, ack=301))
6069         self.pg0.add_stream(p)
6070         self.pg_enable_capture(self.pg_interfaces)
6071         self.pg_start()
6072         self.pg1.assert_nothing_captured()
6073         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
6074         self.assertEqual(len(sessions) - start_sessnum, 0)
6075
6076     def test_tcp_session_close_simultaneous(self):
6077         """ Close TCP session from inside network """
6078         self.tcp_port_out = 10505
6079         self.nat44_add_address(self.nat_addr)
6080         flags = self.config_flags.NAT_IS_TWICE_NAT
6081         self.nat44_add_static_mapping(self.pg0.remote_ip4,
6082                                       self.nat_addr,
6083                                       self.tcp_port_in,
6084                                       self.tcp_port_out,
6085                                       proto=IP_PROTOS.tcp,
6086                                       flags=flags)
6087         flags = self.config_flags.NAT_IS_INSIDE
6088         self.vapi.nat44_interface_add_del_feature(
6089             sw_if_index=self.pg0.sw_if_index,
6090             flags=flags, is_add=1)
6091         self.vapi.nat44_interface_add_del_feature(
6092             sw_if_index=self.pg1.sw_if_index,
6093             is_add=1)
6094
6095         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
6096         start_sessnum = len(sessions)
6097
6098         self.vapi.nat_set_timeouts(udp=300, tcp_established=7440,
6099                                    tcp_transitory=2, icmp=5)
6100
6101         self.initiate_tcp_session(self.pg0, self.pg1)
6102
6103         # FIN packet in -> out
6104         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6105              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6106              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
6107                  flags="FA", seq=100, ack=300))
6108         self.pg0.add_stream(p)
6109         self.pg_enable_capture(self.pg_interfaces)
6110         self.pg_start()
6111         self.pg1.get_capture(1)
6112
6113         # FIN packet out -> in
6114         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
6115              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
6116              TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
6117                  flags="FA", seq=300, ack=100))
6118         self.pg1.add_stream(p)
6119         self.pg_enable_capture(self.pg_interfaces)
6120         self.pg_start()
6121         self.pg0.get_capture(1)
6122
6123         # ACK packet in -> out
6124         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6125              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6126              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
6127                  flags="A", seq=101, ack=301))
6128         self.pg0.add_stream(p)
6129         self.pg_enable_capture(self.pg_interfaces)
6130         self.pg_start()
6131         self.pg1.get_capture(1)
6132
6133         # ACK packet out -> in
6134         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
6135              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
6136              TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
6137                  flags="A", seq=301, ack=101))
6138         self.pg1.add_stream(p)
6139         self.pg_enable_capture(self.pg_interfaces)
6140         self.pg_start()
6141         self.pg0.get_capture(1)
6142
6143         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
6144         self.assertEqual(len(sessions) - start_sessnum, 1)
6145
6146         stats = self.statistics.get_counter(
6147             '/err/nat44-ed-out2in/drops due to TCP in transitory timeout')
6148         out2in_drops = stats[0]
6149         stats = self.statistics.get_counter(
6150             '/err/nat44-ed-in2out/drops due to TCP in transitory timeout')
6151         in2out_drops = stats[0]
6152
6153         # extra FIN packet out -> in - this should be dropped
6154         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
6155              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
6156              TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
6157                  flags="FA", seq=300, ack=101))
6158
6159         self.pg1.add_stream(p)
6160         self.pg_enable_capture(self.pg_interfaces)
6161         self.pg_start()
6162         self.pg0.assert_nothing_captured()
6163
6164         # extra ACK packet in -> out - this should be dropped
6165         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6166              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6167              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
6168                  flags="A", seq=101, ack=301))
6169         self.pg0.add_stream(p)
6170         self.pg_enable_capture(self.pg_interfaces)
6171         self.pg_start()
6172         self.pg1.assert_nothing_captured()
6173
6174         stats = self.statistics.get_counter(
6175             '/err/nat44-ed-out2in/drops due to TCP in transitory timeout')
6176         self.assertEqual(stats[0] - out2in_drops, 1)
6177         stats = self.statistics.get_counter(
6178             '/err/nat44-ed-in2out/drops due to TCP in transitory timeout')
6179         self.assertEqual(stats[0] - in2out_drops, 1)
6180
6181         self.sleep(3)
6182         # extra ACK packet in -> out - this will cause session to be wiped
6183         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6184              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6185              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
6186                  flags="A", seq=101, ack=301))
6187         self.pg0.add_stream(p)
6188         self.pg_enable_capture(self.pg_interfaces)
6189         self.pg_start()
6190         self.pg1.assert_nothing_captured()
6191         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
6192         self.assertEqual(len(sessions) - start_sessnum, 0)
6193
6194     def test_one_armed_nat44_static(self):
6195         """ One armed NAT44 and 1:1 NAPT asymmetrical rule """
6196         remote_host = self.pg4.remote_hosts[0]
6197         local_host = self.pg4.remote_hosts[1]
6198         external_port = 80
6199         local_port = 8080
6200         eh_port_in = 0
6201
6202         self.vapi.nat44_forwarding_enable_disable(enable=1)
6203         self.nat44_add_address(self.nat_addr, twice_nat=1)
6204         flags = (self.config_flags.NAT_IS_OUT2IN_ONLY |
6205                  self.config_flags.NAT_IS_TWICE_NAT)
6206         self.nat44_add_static_mapping(local_host.ip4, self.nat_addr,
6207                                       local_port, external_port,
6208                                       proto=IP_PROTOS.tcp, flags=flags)
6209         flags = self.config_flags.NAT_IS_INSIDE
6210         self.vapi.nat44_interface_add_del_feature(
6211             sw_if_index=self.pg4.sw_if_index,
6212             is_add=1)
6213         self.vapi.nat44_interface_add_del_feature(
6214             sw_if_index=self.pg4.sw_if_index,
6215             flags=flags, is_add=1)
6216
6217         # from client to service
6218         p = (Ether(src=self.pg4.remote_mac, dst=self.pg4.local_mac) /
6219              IP(src=remote_host.ip4, dst=self.nat_addr) /
6220              TCP(sport=12345, dport=external_port))
6221         self.pg4.add_stream(p)
6222         self.pg_enable_capture(self.pg_interfaces)
6223         self.pg_start()
6224         capture = self.pg4.get_capture(1)
6225         p = capture[0]
6226         try:
6227             ip = p[IP]
6228             tcp = p[TCP]
6229             self.assertEqual(ip.dst, local_host.ip4)
6230             self.assertEqual(ip.src, self.nat_addr)
6231             self.assertEqual(tcp.dport, local_port)
6232             self.assertNotEqual(tcp.sport, 12345)
6233             eh_port_in = tcp.sport
6234             self.assert_packet_checksums_valid(p)
6235         except:
6236             self.logger.error(ppp("Unexpected or invalid packet:", p))
6237             raise
6238
6239         # from service back to client
6240         p = (Ether(src=self.pg4.remote_mac, dst=self.pg4.local_mac) /
6241              IP(src=local_host.ip4, dst=self.nat_addr) /
6242              TCP(sport=local_port, dport=eh_port_in))
6243         self.pg4.add_stream(p)
6244         self.pg_enable_capture(self.pg_interfaces)
6245         self.pg_start()
6246         capture = self.pg4.get_capture(1)
6247         p = capture[0]
6248         try:
6249             ip = p[IP]
6250             tcp = p[TCP]
6251             self.assertEqual(ip.src, self.nat_addr)
6252             self.assertEqual(ip.dst, remote_host.ip4)
6253             self.assertEqual(tcp.sport, external_port)
6254             self.assertEqual(tcp.dport, 12345)
6255             self.assert_packet_checksums_valid(p)
6256         except:
6257             self.logger.error(ppp("Unexpected or invalid packet:", p))
6258             raise
6259
6260     def test_static_with_port_out2(self):
6261         """ 1:1 NAPT asymmetrical rule """
6262
6263         external_port = 80
6264         local_port = 8080
6265
6266         self.vapi.nat44_forwarding_enable_disable(enable=1)
6267         flags = self.config_flags.NAT_IS_OUT2IN_ONLY
6268         self.nat44_add_static_mapping(self.pg0.remote_ip4, self.nat_addr,
6269                                       local_port, external_port,
6270                                       proto=IP_PROTOS.tcp, flags=flags)
6271         flags = self.config_flags.NAT_IS_INSIDE
6272         self.vapi.nat44_interface_add_del_feature(
6273             sw_if_index=self.pg0.sw_if_index,
6274             flags=flags, is_add=1)
6275         self.vapi.nat44_interface_add_del_feature(
6276             sw_if_index=self.pg1.sw_if_index,
6277             is_add=1)
6278
6279         # from client to service
6280         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
6281              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
6282              TCP(sport=12345, dport=external_port))
6283         self.pg1.add_stream(p)
6284         self.pg_enable_capture(self.pg_interfaces)
6285         self.pg_start()
6286         capture = self.pg0.get_capture(1)
6287         p = capture[0]
6288         try:
6289             ip = p[IP]
6290             tcp = p[TCP]
6291             self.assertEqual(ip.dst, self.pg0.remote_ip4)
6292             self.assertEqual(tcp.dport, local_port)
6293             self.assert_packet_checksums_valid(p)
6294         except:
6295             self.logger.error(ppp("Unexpected or invalid packet:", p))
6296             raise
6297
6298         # ICMP error
6299         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
6300              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6301              ICMP(type=11) / capture[0][IP])
6302         self.pg0.add_stream(p)
6303         self.pg_enable_capture(self.pg_interfaces)
6304         self.pg_start()
6305         capture = self.pg1.get_capture(1)
6306         p = capture[0]
6307         try:
6308             self.assertEqual(p[IP].src, self.nat_addr)
6309             inner = p[IPerror]
6310             self.assertEqual(inner.dst, self.nat_addr)
6311             self.assertEqual(inner[TCPerror].dport, external_port)
6312         except:
6313             self.logger.error(ppp("Unexpected or invalid packet:", p))
6314             raise
6315
6316         # from service back to client
6317         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6318              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6319              TCP(sport=local_port, dport=12345))
6320         self.pg0.add_stream(p)
6321         self.pg_enable_capture(self.pg_interfaces)
6322         self.pg_start()
6323         capture = self.pg1.get_capture(1)
6324         p = capture[0]
6325         try:
6326             ip = p[IP]
6327             tcp = p[TCP]
6328             self.assertEqual(ip.src, self.nat_addr)
6329             self.assertEqual(tcp.sport, external_port)
6330             self.assert_packet_checksums_valid(p)
6331         except:
6332             self.logger.error(ppp("Unexpected or invalid packet:", p))
6333             raise
6334
6335         # ICMP error
6336         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
6337              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
6338              ICMP(type=11) / capture[0][IP])
6339         self.pg1.add_stream(p)
6340         self.pg_enable_capture(self.pg_interfaces)
6341         self.pg_start()
6342         capture = self.pg0.get_capture(1)
6343         p = capture[0]
6344         try:
6345             self.assertEqual(p[IP].dst, self.pg0.remote_ip4)
6346             inner = p[IPerror]
6347             self.assertEqual(inner.src, self.pg0.remote_ip4)
6348             self.assertEqual(inner[TCPerror].sport, local_port)
6349         except:
6350             self.logger.error(ppp("Unexpected or invalid packet:", p))
6351             raise
6352
6353         # from client to server (no translation)
6354         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
6355              IP(src=self.pg1.remote_ip4, dst=self.pg0.remote_ip4) /
6356              TCP(sport=12346, dport=local_port))
6357         self.pg1.add_stream(p)
6358         self.pg_enable_capture(self.pg_interfaces)
6359         self.pg_start()
6360         capture = self.pg0.get_capture(1)
6361         p = capture[0]
6362         try:
6363             ip = p[IP]
6364             tcp = p[TCP]
6365             self.assertEqual(ip.dst, self.pg0.remote_ip4)
6366             self.assertEqual(tcp.dport, local_port)
6367             self.assert_packet_checksums_valid(p)
6368         except:
6369             self.logger.error(ppp("Unexpected or invalid packet:", p))
6370             raise
6371
6372         # from service back to client (no translation)
6373         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6374              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6375              TCP(sport=local_port, dport=12346))
6376         self.pg0.add_stream(p)
6377         self.pg_enable_capture(self.pg_interfaces)
6378         self.pg_start()
6379         capture = self.pg1.get_capture(1)
6380         p = capture[0]
6381         try:
6382             ip = p[IP]
6383             tcp = p[TCP]
6384             self.assertEqual(ip.src, self.pg0.remote_ip4)
6385             self.assertEqual(tcp.sport, local_port)
6386             self.assert_packet_checksums_valid(p)
6387         except:
6388             self.logger.error(ppp("Unexpected or invalid packet:", p))
6389             raise
6390
6391     def test_output_feature(self):
6392         """ NAT44 interface output feature (in2out postrouting) """
6393         self.vapi.nat44_forwarding_enable_disable(enable=1)
6394         self.nat44_add_address(self.nat_addr)
6395         self.vapi.nat44_interface_add_del_feature(
6396             sw_if_index=self.pg0.sw_if_index,
6397             is_add=1)
6398         self.vapi.nat44_interface_add_del_output_feature(
6399             is_add=1,
6400             sw_if_index=self.pg1.sw_if_index)
6401
6402         # in2out
6403         pkts = self.create_stream_in(self.pg0, self.pg1)
6404         self.pg0.add_stream(pkts)
6405         self.pg_enable_capture(self.pg_interfaces)
6406         self.pg_start()
6407         capture = self.pg1.get_capture(len(pkts))
6408         self.verify_capture_out(capture, ignore_port=True)
6409
6410         # out2in
6411         pkts = self.create_stream_out(self.pg1)
6412         self.pg1.add_stream(pkts)
6413         self.pg_enable_capture(self.pg_interfaces)
6414         self.pg_start()
6415         capture = self.pg0.get_capture(len(pkts))
6416         self.verify_capture_in(capture, self.pg0)
6417
6418     def test_output_feature_stateful_acl(self):
6419         """ NAT44 endpoint-dependent output feature works with stateful ACL """
6420         self.nat44_add_address(self.nat_addr)
6421         self.vapi.nat44_interface_add_del_output_feature(
6422             sw_if_index=self.pg0.sw_if_index,
6423             flags=self.config_flags.NAT_IS_INSIDE,
6424             is_add=1)
6425         self.vapi.nat44_interface_add_del_output_feature(
6426             sw_if_index=self.pg1.sw_if_index,
6427             flags=self.config_flags.NAT_IS_OUTSIDE,
6428             is_add=1)
6429
6430         # First ensure that the NAT is working sans ACL
6431
6432         # send packets out2in, no sessions yet so packets should drop
6433         pkts_out2in = self.create_stream_out(self.pg1)
6434         self.send_and_assert_no_replies(self.pg1, pkts_out2in)
6435
6436         # send packets into inside intf, ensure received via outside intf
6437         pkts_in2out = self.create_stream_in(self.pg0, self.pg1)
6438         capture = self.send_and_expect(self.pg0, pkts_in2out, self.pg1,
6439                                        len(pkts_in2out))
6440         self.verify_capture_out(capture, ignore_port=True)
6441
6442         # send out2in again, with sessions created it should work now
6443         pkts_out2in = self.create_stream_out(self.pg1)
6444         capture = self.send_and_expect(self.pg1, pkts_out2in, self.pg0,
6445                                        len(pkts_out2in))
6446         self.verify_capture_in(capture, self.pg0)
6447
6448         # Create an ACL blocking everything
6449         out2in_deny_rule = AclRule(is_permit=0)
6450         out2in_acl = VppAcl(self, rules=[out2in_deny_rule])
6451         out2in_acl.add_vpp_config()
6452
6453         # create an ACL to permit/reflect everything
6454         in2out_reflect_rule = AclRule(is_permit=2)
6455         in2out_acl = VppAcl(self, rules=[in2out_reflect_rule])
6456         in2out_acl.add_vpp_config()
6457
6458         # apply as input acl on interface and confirm it blocks everything
6459         acl_if = VppAclInterface(self, sw_if_index=self.pg1.sw_if_index,
6460                                  n_input=1, acls=[out2in_acl])
6461         acl_if.add_vpp_config()
6462         self.send_and_assert_no_replies(self.pg1, pkts_out2in)
6463
6464         # apply output acl
6465         acl_if.acls = [out2in_acl, in2out_acl]
6466         acl_if.add_vpp_config()
6467         # send in2out to generate ACL state (NAT state was created earlier)
6468         capture = self.send_and_expect(self.pg0, pkts_in2out, self.pg1,
6469                                        len(pkts_in2out))
6470         self.verify_capture_out(capture, ignore_port=True)
6471
6472         # send out2in again. ACL state exists so it should work now.
6473         # TCP packets with the syn flag set also need the ack flag
6474         for p in pkts_out2in:
6475             if p.haslayer(TCP) and p[TCP].flags & 0x02:
6476                 p[TCP].flags |= 0x10
6477         capture = self.send_and_expect(self.pg1, pkts_out2in, self.pg0,
6478                                        len(pkts_out2in))
6479         self.verify_capture_in(capture, self.pg0)
6480         self.logger.info(self.vapi.cli("show trace"))
6481
6482     def test_multiple_vrf(self):
6483         """ Multiple VRF setup """
6484         external_addr = '1.2.3.4'
6485         external_port = 80
6486         local_port = 8080
6487         port = 0
6488
6489         self.vapi.nat44_forwarding_enable_disable(enable=1)
6490         self.nat44_add_address(self.nat_addr)
6491         flags = self.config_flags.NAT_IS_INSIDE
6492         self.vapi.nat44_interface_add_del_feature(
6493             sw_if_index=self.pg0.sw_if_index,
6494             is_add=1)
6495         self.vapi.nat44_interface_add_del_feature(
6496             sw_if_index=self.pg0.sw_if_index,
6497             is_add=1, flags=flags)
6498         self.vapi.nat44_interface_add_del_output_feature(
6499             sw_if_index=self.pg1.sw_if_index,
6500             is_add=1)
6501         self.vapi.nat44_interface_add_del_feature(
6502             sw_if_index=self.pg5.sw_if_index,
6503             is_add=1)
6504         self.vapi.nat44_interface_add_del_feature(
6505             sw_if_index=self.pg5.sw_if_index,
6506             is_add=1, flags=flags)
6507         self.vapi.nat44_interface_add_del_feature(
6508             sw_if_index=self.pg6.sw_if_index,
6509             is_add=1)
6510         flags = self.config_flags.NAT_IS_OUT2IN_ONLY
6511         self.nat44_add_static_mapping(self.pg5.remote_ip4, external_addr,
6512                                       local_port, external_port, vrf_id=1,
6513                                       proto=IP_PROTOS.tcp, flags=flags)
6514         self.nat44_add_static_mapping(
6515             self.pg0.remote_ip4,
6516             external_sw_if_index=self.pg0.sw_if_index,
6517             local_port=local_port,
6518             vrf_id=0,
6519             external_port=external_port,
6520             proto=IP_PROTOS.tcp,
6521             flags=flags
6522         )
6523
6524         # from client to service (both VRF1)
6525         p = (Ether(src=self.pg6.remote_mac, dst=self.pg6.local_mac) /
6526              IP(src=self.pg6.remote_ip4, dst=external_addr) /
6527              TCP(sport=12345, dport=external_port))
6528         self.pg6.add_stream(p)
6529         self.pg_enable_capture(self.pg_interfaces)
6530         self.pg_start()
6531         capture = self.pg5.get_capture(1)
6532         p = capture[0]
6533         try:
6534             ip = p[IP]
6535             tcp = p[TCP]
6536             self.assertEqual(ip.dst, self.pg5.remote_ip4)
6537             self.assertEqual(tcp.dport, local_port)
6538             self.assert_packet_checksums_valid(p)
6539         except:
6540             self.logger.error(ppp("Unexpected or invalid packet:", p))
6541             raise
6542
6543         # from service back to client (both VRF1)
6544         p = (Ether(src=self.pg5.remote_mac, dst=self.pg5.local_mac) /
6545              IP(src=self.pg5.remote_ip4, dst=self.pg6.remote_ip4) /
6546              TCP(sport=local_port, dport=12345))
6547         self.pg5.add_stream(p)
6548         self.pg_enable_capture(self.pg_interfaces)
6549         self.pg_start()
6550         capture = self.pg6.get_capture(1)
6551         p = capture[0]
6552         try:
6553             ip = p[IP]
6554             tcp = p[TCP]
6555             self.assertEqual(ip.src, external_addr)
6556             self.assertEqual(tcp.sport, external_port)
6557             self.assert_packet_checksums_valid(p)
6558         except:
6559             self.logger.error(ppp("Unexpected or invalid packet:", p))
6560             raise
6561
6562         # dynamic NAT from VRF1 to VRF0 (output-feature)
6563         p = (Ether(src=self.pg5.remote_mac, dst=self.pg5.local_mac) /
6564              IP(src=self.pg5.remote_ip4, dst=self.pg1.remote_ip4) /
6565              TCP(sport=2345, dport=22))
6566         self.pg5.add_stream(p)
6567         self.pg_enable_capture(self.pg_interfaces)
6568         self.pg_start()
6569         capture = self.pg1.get_capture(1)
6570         p = capture[0]
6571         try:
6572             ip = p[IP]
6573             tcp = p[TCP]
6574             self.assertEqual(ip.src, self.nat_addr)
6575             self.assert_packet_checksums_valid(p)
6576             port = tcp.sport
6577         except:
6578             self.logger.error(ppp("Unexpected or invalid packet:", p))
6579             raise
6580
6581         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
6582              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
6583              TCP(sport=22, dport=port))
6584         self.pg1.add_stream(p)
6585         self.pg_enable_capture(self.pg_interfaces)
6586         self.pg_start()
6587         capture = self.pg5.get_capture(1)
6588         p = capture[0]
6589         try:
6590             ip = p[IP]
6591             tcp = p[TCP]
6592             self.assertEqual(ip.dst, self.pg5.remote_ip4)
6593             self.assertEqual(tcp.dport, 2345)
6594             self.assert_packet_checksums_valid(p)
6595         except:
6596             self.logger.error(ppp("Unexpected or invalid packet:", p))
6597             raise
6598
6599         # from client VRF1 to service VRF0
6600         p = (Ether(src=self.pg6.remote_mac, dst=self.pg6.local_mac) /
6601              IP(src=self.pg6.remote_ip4, dst=self.pg0.local_ip4) /
6602              TCP(sport=12346, dport=external_port))
6603         self.pg6.add_stream(p)
6604         self.pg_enable_capture(self.pg_interfaces)
6605         self.pg_start()
6606         capture = self.pg0.get_capture(1)
6607         p = capture[0]
6608         try:
6609             ip = p[IP]
6610             tcp = p[TCP]
6611             self.assertEqual(ip.dst, self.pg0.remote_ip4)
6612             self.assertEqual(tcp.dport, local_port)
6613             self.assert_packet_checksums_valid(p)
6614         except:
6615             self.logger.error(ppp("Unexpected or invalid packet:", p))
6616             raise
6617
6618         # from service VRF0 back to client VRF1
6619         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6620              IP(src=self.pg0.remote_ip4, dst=self.pg6.remote_ip4) /
6621              TCP(sport=local_port, dport=12346))
6622         self.pg0.add_stream(p)
6623         self.pg_enable_capture(self.pg_interfaces)
6624         self.pg_start()
6625         capture = self.pg6.get_capture(1)
6626         p = capture[0]
6627         try:
6628             ip = p[IP]
6629             tcp = p[TCP]
6630             self.assertEqual(ip.src, self.pg0.local_ip4)
6631             self.assertEqual(tcp.sport, external_port)
6632             self.assert_packet_checksums_valid(p)
6633         except:
6634             self.logger.error(ppp("Unexpected or invalid packet:", p))
6635             raise
6636
6637         # from client VRF0 to service VRF1
6638         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6639              IP(src=self.pg0.remote_ip4, dst=external_addr) /
6640              TCP(sport=12347, dport=external_port))
6641         self.pg0.add_stream(p)
6642         self.pg_enable_capture(self.pg_interfaces)
6643         self.pg_start()
6644         capture = self.pg5.get_capture(1)
6645         p = capture[0]
6646         try:
6647             ip = p[IP]
6648             tcp = p[TCP]
6649             self.assertEqual(ip.dst, self.pg5.remote_ip4)
6650             self.assertEqual(tcp.dport, local_port)
6651             self.assert_packet_checksums_valid(p)
6652         except:
6653             self.logger.error(ppp("Unexpected or invalid packet:", p))
6654             raise
6655
6656         # from service VRF1 back to client VRF0
6657         p = (Ether(src=self.pg5.remote_mac, dst=self.pg5.local_mac) /
6658              IP(src=self.pg5.remote_ip4, dst=self.pg0.remote_ip4) /
6659              TCP(sport=local_port, dport=12347))
6660         self.pg5.add_stream(p)
6661         self.pg_enable_capture(self.pg_interfaces)
6662         self.pg_start()
6663         capture = self.pg0.get_capture(1)
6664         p = capture[0]
6665         try:
6666             ip = p[IP]
6667             tcp = p[TCP]
6668             self.assertEqual(ip.src, external_addr)
6669             self.assertEqual(tcp.sport, external_port)
6670             self.assert_packet_checksums_valid(p)
6671         except:
6672             self.logger.error(ppp("Unexpected or invalid packet:", p))
6673             raise
6674
6675         # from client to server (both VRF1, no translation)
6676         p = (Ether(src=self.pg6.remote_mac, dst=self.pg6.local_mac) /
6677              IP(src=self.pg6.remote_ip4, dst=self.pg5.remote_ip4) /
6678              TCP(sport=12348, dport=local_port))
6679         self.pg6.add_stream(p)
6680         self.pg_enable_capture(self.pg_interfaces)
6681         self.pg_start()
6682         capture = self.pg5.get_capture(1)
6683         p = capture[0]
6684         try:
6685             ip = p[IP]
6686             tcp = p[TCP]
6687             self.assertEqual(ip.dst, self.pg5.remote_ip4)
6688             self.assertEqual(tcp.dport, local_port)
6689             self.assert_packet_checksums_valid(p)
6690         except:
6691             self.logger.error(ppp("Unexpected or invalid packet:", p))
6692             raise
6693
6694         # from server back to client (both VRF1, no translation)
6695         p = (Ether(src=self.pg5.remote_mac, dst=self.pg5.local_mac) /
6696              IP(src=self.pg5.remote_ip4, dst=self.pg6.remote_ip4) /
6697              TCP(sport=local_port, dport=12348))
6698         self.pg5.add_stream(p)
6699         self.pg_enable_capture(self.pg_interfaces)
6700         self.pg_start()
6701         capture = self.pg6.get_capture(1)
6702         p = capture[0]
6703         try:
6704             ip = p[IP]
6705             tcp = p[TCP]
6706             self.assertEqual(ip.src, self.pg5.remote_ip4)
6707             self.assertEqual(tcp.sport, local_port)
6708             self.assert_packet_checksums_valid(p)
6709         except:
6710             self.logger.error(ppp("Unexpected or invalid packet:", p))
6711             raise
6712
6713         # from client VRF1 to server VRF0 (no translation)
6714         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6715              IP(src=self.pg0.remote_ip4, dst=self.pg6.remote_ip4) /
6716              TCP(sport=local_port, dport=12349))
6717         self.pg0.add_stream(p)
6718         self.pg_enable_capture(self.pg_interfaces)
6719         self.pg_start()
6720         capture = self.pg6.get_capture(1)
6721         p = capture[0]
6722         try:
6723             ip = p[IP]
6724             tcp = p[TCP]
6725             self.assertEqual(ip.src, self.pg0.remote_ip4)
6726             self.assertEqual(tcp.sport, local_port)
6727             self.assert_packet_checksums_valid(p)
6728         except:
6729             self.logger.error(ppp("Unexpected or invalid packet:", p))
6730             raise
6731
6732         # from server VRF0 back to client VRF1 (no translation)
6733         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6734              IP(src=self.pg0.remote_ip4, dst=self.pg6.remote_ip4) /
6735              TCP(sport=local_port, dport=12349))
6736         self.pg0.add_stream(p)
6737         self.pg_enable_capture(self.pg_interfaces)
6738         self.pg_start()
6739         capture = self.pg6.get_capture(1)
6740         p = capture[0]
6741         try:
6742             ip = p[IP]
6743             tcp = p[TCP]
6744             self.assertEqual(ip.src, self.pg0.remote_ip4)
6745             self.assertEqual(tcp.sport, local_port)
6746             self.assert_packet_checksums_valid(p)
6747         except:
6748             self.logger.error(ppp("Unexpected or invalid packet:", p))
6749             raise
6750
6751         # from client VRF0 to server VRF1 (no translation)
6752         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6753              IP(src=self.pg0.remote_ip4, dst=self.pg5.remote_ip4) /
6754              TCP(sport=12344, dport=local_port))
6755         self.pg0.add_stream(p)
6756         self.pg_enable_capture(self.pg_interfaces)
6757         self.pg_start()
6758         capture = self.pg5.get_capture(1)
6759         p = capture[0]
6760         try:
6761             ip = p[IP]
6762             tcp = p[TCP]
6763             self.assertEqual(ip.dst, self.pg5.remote_ip4)
6764             self.assertEqual(tcp.dport, local_port)
6765             self.assert_packet_checksums_valid(p)
6766         except:
6767             self.logger.error(ppp("Unexpected or invalid packet:", p))
6768             raise
6769
6770         # from server VRF1 back to client VRF0 (no translation)
6771         p = (Ether(src=self.pg5.remote_mac, dst=self.pg5.local_mac) /
6772              IP(src=self.pg5.remote_ip4, dst=self.pg0.remote_ip4) /
6773              TCP(sport=local_port, dport=12344))
6774         self.pg5.add_stream(p)
6775         self.pg_enable_capture(self.pg_interfaces)
6776         self.pg_start()
6777         capture = self.pg0.get_capture(1)
6778         p = capture[0]
6779         try:
6780             ip = p[IP]
6781             tcp = p[TCP]
6782             self.assertEqual(ip.src, self.pg5.remote_ip4)
6783             self.assertEqual(tcp.sport, local_port)
6784             self.assert_packet_checksums_valid(p)
6785         except:
6786             self.logger.error(ppp("Unexpected or invalid packet:", p))
6787             raise
6788
6789     def test_session_rst_timeout(self):
6790         """ NAT44 session RST timeouts """
6791         self.nat44_add_address(self.nat_addr)
6792         flags = self.config_flags.NAT_IS_INSIDE
6793         self.vapi.nat44_interface_add_del_feature(
6794             sw_if_index=self.pg0.sw_if_index,
6795             flags=flags, is_add=1)
6796         self.vapi.nat44_interface_add_del_feature(
6797             sw_if_index=self.pg1.sw_if_index,
6798             is_add=1)
6799         self.vapi.nat_set_timeouts(udp=300, tcp_established=7440,
6800                                    tcp_transitory=5, icmp=60)
6801
6802         self.initiate_tcp_session(self.pg0, self.pg1)
6803         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6804              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6805              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
6806                  flags="R"))
6807         self.pg0.add_stream(p)
6808         self.pg_enable_capture(self.pg_interfaces)
6809         self.pg_start()
6810         self.pg1.get_capture(1)
6811
6812         sleep(6)
6813
6814         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6815              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6816              TCP(sport=self.tcp_port_in + 1, dport=self.tcp_external_port + 1,
6817                  flags="S"))
6818         self.pg0.add_stream(p)
6819         self.pg_enable_capture(self.pg_interfaces)
6820         self.pg_start()
6821         self.pg1.get_capture(1)
6822
6823     def test_syslog_sess(self):
6824         """ Test syslog session creation and deletion """
6825         self.vapi.syslog_set_filter(
6826             self.SYSLOG_SEVERITY.SYSLOG_API_SEVERITY_INFO)
6827         self.vapi.syslog_set_sender(self.pg2.local_ip4, self.pg2.remote_ip4)
6828         self.nat44_add_address(self.nat_addr)
6829         flags = self.config_flags.NAT_IS_INSIDE
6830         self.vapi.nat44_interface_add_del_feature(
6831             sw_if_index=self.pg0.sw_if_index,
6832             flags=flags, is_add=1)
6833         self.vapi.nat44_interface_add_del_feature(
6834             sw_if_index=self.pg1.sw_if_index,
6835             is_add=1)
6836
6837         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
6838              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6839              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port))
6840         self.pg0.add_stream(p)
6841         self.pg_enable_capture(self.pg_interfaces)
6842         self.pg_start()
6843         capture = self.pg1.get_capture(1)
6844         self.tcp_port_out = capture[0][TCP].sport
6845         capture = self.pg2.get_capture(1)
6846         self.verify_syslog_sess(capture[0][Raw].load)
6847
6848         self.pg_enable_capture(self.pg_interfaces)
6849         self.pg_start()
6850         self.nat44_add_address(self.nat_addr, is_add=0)
6851         capture = self.pg2.get_capture(1)
6852         self.verify_syslog_sess(capture[0][Raw].load, False)
6853
6854     def test_ed_users_dump(self):
6855         """ API test - nat44_user_dump """
6856         flags = self.config_flags.NAT_IS_INSIDE
6857         self.vapi.nat44_interface_add_del_feature(
6858             sw_if_index=self.pg0.sw_if_index,
6859             flags=flags, is_add=1)
6860         self.vapi.nat44_interface_add_del_feature(
6861             sw_if_index=self.pg1.sw_if_index,
6862             is_add=1)
6863         self.vapi.nat44_forwarding_enable_disable(enable=1)
6864
6865         real_ip = self.pg0.remote_ip4
6866         alias_ip = self.nat_addr
6867         flags = self.config_flags.NAT_IS_ADDR_ONLY
6868         self.vapi.nat44_add_del_static_mapping(is_add=1,
6869                                                local_ip_address=real_ip,
6870                                                external_ip_address=alias_ip,
6871                                                external_sw_if_index=0xFFFFFFFF,
6872                                                flags=flags)
6873
6874         users = self.vapi.nat44_user_dump()
6875         self.assertEqual(len(users), 0)
6876         try:
6877             # in2out - static mapping match
6878
6879             pkts = self.create_stream_out(self.pg1)
6880             self.pg1.add_stream(pkts)
6881             self.pg_enable_capture(self.pg_interfaces)
6882             self.pg_start()
6883             capture = self.pg0.get_capture(len(pkts))
6884             self.verify_capture_in(capture, self.pg0)
6885
6886             pkts = self.create_stream_in(self.pg0, self.pg1)
6887             self.pg0.add_stream(pkts)
6888             self.pg_enable_capture(self.pg_interfaces)
6889             self.pg_start()
6890             capture = self.pg1.get_capture(len(pkts))
6891             self.verify_capture_out(capture, same_port=True)
6892
6893             users = self.vapi.nat44_user_dump()
6894             self.assertEqual(len(users), 1)
6895             static_user = users[0]
6896             self.assertEqual(static_user.nstaticsessions, 3)
6897             self.assertEqual(static_user.nsessions, 0)
6898
6899             # in2out - no static mapping match
6900
6901             host0 = self.pg0.remote_hosts[0]
6902             self.pg0.remote_hosts[0] = self.pg0.remote_hosts[1]
6903             try:
6904                 pkts = self.create_stream_out(self.pg1,
6905                                               dst_ip=self.pg0.remote_ip4,
6906                                               use_inside_ports=True)
6907                 self.pg1.add_stream(pkts)
6908                 self.pg_enable_capture(self.pg_interfaces)
6909                 self.pg_start()
6910                 capture = self.pg0.get_capture(len(pkts))
6911                 self.verify_capture_in(capture, self.pg0)
6912
6913                 pkts = self.create_stream_in(self.pg0, self.pg1)
6914                 self.pg0.add_stream(pkts)
6915                 self.pg_enable_capture(self.pg_interfaces)
6916                 self.pg_start()
6917                 capture = self.pg1.get_capture(len(pkts))
6918                 self.verify_capture_out(capture, nat_ip=self.pg0.remote_ip4,
6919                                         same_port=True)
6920             finally:
6921                 self.pg0.remote_hosts[0] = host0
6922
6923             users = self.vapi.nat44_user_dump()
6924             self.assertEqual(len(users), 2)
6925             if str(users[0].ip_address) == self.pg0.remote_hosts[0].ip4:
6926                 non_static_user = users[1]
6927                 static_user = users[0]
6928             else:
6929                 non_static_user = users[0]
6930                 static_user = users[1]
6931             self.assertEqual(static_user.nstaticsessions, 3)
6932             self.assertEqual(static_user.nsessions, 0)
6933             self.assertEqual(non_static_user.nstaticsessions, 0)
6934             self.assertEqual(non_static_user.nsessions, 3)
6935
6936             users = self.vapi.nat44_user_dump()
6937             self.assertEqual(len(users), 2)
6938             if str(users[0].ip_address) == self.pg0.remote_hosts[0].ip4:
6939                 non_static_user = users[1]
6940                 static_user = users[0]
6941             else:
6942                 non_static_user = users[0]
6943                 static_user = users[1]
6944             self.assertEqual(static_user.nstaticsessions, 3)
6945             self.assertEqual(static_user.nsessions, 0)
6946             self.assertEqual(non_static_user.nstaticsessions, 0)
6947             self.assertEqual(non_static_user.nsessions, 3)
6948
6949         finally:
6950             self.vapi.nat44_forwarding_enable_disable(enable=0)
6951             flags = self.config_flags.NAT_IS_ADDR_ONLY
6952             self.vapi.nat44_add_del_static_mapping(
6953                 is_add=0,
6954                 local_ip_address=real_ip,
6955                 external_ip_address=alias_ip,
6956                 external_sw_if_index=0xFFFFFFFF,
6957                 flags=flags)
6958
6959     def show_commands_at_teardown(self):
6960         self.logger.info(self.vapi.cli("show errors"))
6961         self.logger.info(self.vapi.cli("show nat44 addresses"))
6962         self.logger.info(self.vapi.cli("show nat44 interfaces"))
6963         self.logger.info(self.vapi.cli("show nat44 static mappings"))
6964         self.logger.info(self.vapi.cli("show nat44 interface address"))
6965         self.logger.info(self.vapi.cli("show nat44 sessions detail"))
6966         self.logger.info(self.vapi.cli("show nat44 hash tables detail"))
6967         self.logger.info(self.vapi.cli("show nat timeouts"))
6968         self.logger.info(self.vapi.cli("debug nat44 fib registration"))
6969
6970
6971 class TestNAT44EndpointDependent3(MethodHolder):
6972     """ Endpoint-Dependent mapping and filtering extra test cases """
6973
6974     max_translations = 50
6975
6976     @classmethod
6977     def setUpClass(cls):
6978         super(TestNAT44EndpointDependent3, cls).setUpClass()
6979         cls.vapi.cli("set log class nat level debug")
6980
6981         cls.nat_addr = '10.0.0.3'
6982
6983         cls.create_pg_interfaces(range(2))
6984
6985         for i in cls.pg_interfaces:
6986             i.admin_up()
6987             i.config_ip4()
6988             i.resolve_arp()
6989
6990     def setUp(self):
6991         super(TestNAT44EndpointDependent3, self).setUp()
6992         flags = self.nat44_config_flags.NAT44_IS_ENDPOINT_DEPENDENT
6993         self.vapi.nat44_plugin_enable_disable(
6994             sessions=self.max_translations,
6995             flags=flags, enable=1)
6996         self.vapi.nat_set_timeouts(
6997             udp=1, tcp_established=7440, tcp_transitory=30, icmp=1)
6998
6999         self.nat44_add_address(self.nat_addr)
7000         flags = self.config_flags.NAT_IS_INSIDE
7001         self.vapi.nat44_interface_add_del_feature(
7002             sw_if_index=self.pg0.sw_if_index, flags=flags, is_add=1)
7003         self.vapi.nat44_interface_add_del_feature(
7004             sw_if_index=self.pg1.sw_if_index, is_add=1)
7005
7006     @classmethod
7007     def tearDownClass(cls):
7008         super(TestNAT44EndpointDependent3, cls).tearDownClass()
7009
7010     def tearDown(self):
7011         super(TestNAT44EndpointDependent3, self).tearDown()
7012         if not self.vpp_dead:
7013             self.vapi.nat44_plugin_enable_disable(enable=0)
7014             self.vapi.cli("clear logging")
7015
7016     def init_tcp_session(self, in_if, out_if, sport, ext_dport):
7017         # SYN packet in->out
7018         p = (Ether(src=in_if.remote_mac, dst=in_if.local_mac) /
7019              IP(src=in_if.remote_ip4, dst=out_if.remote_ip4) /
7020              TCP(sport=sport, dport=ext_dport, flags="S"))
7021         in_if.add_stream(p)
7022         self.pg_enable_capture(self.pg_interfaces)
7023         self.pg_start()
7024         capture = out_if.get_capture(1)
7025         p = capture[0]
7026         tcp_port_out = p[TCP].sport
7027
7028         # SYN + ACK packet out->in
7029         p = (Ether(src=out_if.remote_mac, dst=out_if.local_mac) /
7030              IP(src=out_if.remote_ip4, dst=self.nat_addr) /
7031              TCP(sport=ext_dport, dport=tcp_port_out, flags="SA"))
7032         out_if.add_stream(p)
7033         self.pg_enable_capture(self.pg_interfaces)
7034         self.pg_start()
7035         in_if.get_capture(1)
7036
7037         # ACK packet in->out
7038         p = (Ether(src=in_if.remote_mac, dst=in_if.local_mac) /
7039              IP(src=in_if.remote_ip4, dst=out_if.remote_ip4) /
7040              TCP(sport=sport, dport=ext_dport, flags="A"))
7041         in_if.add_stream(p)
7042         self.pg_enable_capture(self.pg_interfaces)
7043         self.pg_start()
7044         out_if.get_capture(1)
7045
7046         return tcp_port_out
7047
7048     def test_lru_cleanup(self):
7049         """ LRU cleanup algorithm """
7050         tcp_port_out = self.init_tcp_session(self.pg0, self.pg1, 2000, 80)
7051         pkts = []
7052         for i in range(0, self.max_translations - 1):
7053             p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
7054                  IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4, ttl=64) /
7055                  UDP(sport=7000+i, dport=80))
7056             pkts.append(p)
7057
7058         self.pg0.add_stream(pkts)
7059         self.pg_enable_capture(self.pg_interfaces)
7060         self.pg_start()
7061         self.pg1.get_capture(len(pkts))
7062         self.sleep(1.5, "wait for timeouts")
7063
7064         pkts = []
7065         for i in range(0, self.max_translations - 1):
7066             p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
7067                  IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4, ttl=64) /
7068                  ICMP(id=8000+i, type='echo-request'))
7069             pkts.append(p)
7070
7071         self.pg0.add_stream(pkts)
7072         self.pg_enable_capture(self.pg_interfaces)
7073         self.pg_start()
7074         self.pg1.get_capture(len(pkts))
7075
7076
7077 class TestNAT44Out2InDPO(MethodHolder):
7078     """ NAT44 Test Cases using out2in DPO """
7079
7080     @classmethod
7081     def setUpClass(cls):
7082         super(TestNAT44Out2InDPO, cls).setUpClass()
7083         cls.vapi.cli("set log class nat level debug")
7084
7085         cls.tcp_port_in = 6303
7086         cls.tcp_port_out = 6303
7087         cls.udp_port_in = 6304
7088         cls.udp_port_out = 6304
7089         cls.icmp_id_in = 6305
7090         cls.icmp_id_out = 6305
7091         cls.nat_addr = '10.0.0.3'
7092         cls.dst_ip4 = '192.168.70.1'
7093
7094         cls.create_pg_interfaces(range(2))
7095
7096         cls.pg0.admin_up()
7097         cls.pg0.config_ip4()
7098         cls.pg0.resolve_arp()
7099
7100         cls.pg1.admin_up()
7101         cls.pg1.config_ip6()
7102         cls.pg1.resolve_ndp()
7103
7104         r1 = VppIpRoute(cls, "::", 0,
7105                         [VppRoutePath(cls.pg1.remote_ip6,
7106                                       cls.pg1.sw_if_index)],
7107                         register=False)
7108         r1.add_vpp_config()
7109
7110     @classmethod
7111     def tearDownClass(cls):
7112         super(TestNAT44Out2InDPO, cls).tearDownClass()
7113
7114     def setUp(self):
7115         super(TestNAT44Out2InDPO, self).setUp()
7116         flags = self.nat44_config_flags.NAT44_API_IS_OUT2IN_DPO
7117         self.vapi.nat44_plugin_enable_disable(enable=1, flags=flags)
7118
7119     def tearDown(self):
7120         super(TestNAT44Out2InDPO, self).tearDown()
7121         if not self.vpp_dead:
7122             self.vapi.nat44_plugin_enable_disable(enable=0)
7123             self.vapi.cli("clear logging")
7124
7125     def configure_xlat(self):
7126         self.dst_ip6_pfx = '1:2:3::'
7127         self.dst_ip6_pfx_n = socket.inet_pton(socket.AF_INET6,
7128                                               self.dst_ip6_pfx)
7129         self.dst_ip6_pfx_len = 96
7130         self.src_ip6_pfx = '4:5:6::'
7131         self.src_ip6_pfx_n = socket.inet_pton(socket.AF_INET6,
7132                                               self.src_ip6_pfx)
7133         self.src_ip6_pfx_len = 96
7134         self.vapi.map_add_domain(self.dst_ip6_pfx_n, self.dst_ip6_pfx_len,
7135                                  self.src_ip6_pfx_n, self.src_ip6_pfx_len,
7136                                  '\x00\x00\x00\x00', 0)
7137
7138     @unittest.skip('Temporary disabled')
7139     def test_464xlat_ce(self):
7140         """ Test 464XLAT CE with NAT44 """
7141
7142         nat_config = self.vapi.nat_show_config()
7143         self.assertEqual(1, nat_config.out2in_dpo)
7144
7145         self.configure_xlat()
7146
7147         flags = self.config_flags.NAT_IS_INSIDE
7148         self.vapi.nat44_interface_add_del_feature(
7149             sw_if_index=self.pg0.sw_if_index,
7150             flags=flags, is_add=1)
7151         self.vapi.nat44_add_del_address_range(first_ip_address=self.nat_addr_n,
7152                                               last_ip_address=self.nat_addr_n,
7153                                               vrf_id=0xFFFFFFFF, is_add=1)
7154
7155         out_src_ip6 = self.compose_ip6(self.dst_ip4, self.dst_ip6_pfx,
7156                                        self.dst_ip6_pfx_len)
7157         out_dst_ip6 = self.compose_ip6(self.nat_addr, self.src_ip6_pfx,
7158                                        self.src_ip6_pfx_len)
7159
7160         try:
7161             pkts = self.create_stream_in(self.pg0, self.pg1, self.dst_ip4)
7162             self.pg0.add_stream(pkts)
7163             self.pg_enable_capture(self.pg_interfaces)
7164             self.pg_start()
7165             capture = self.pg1.get_capture(len(pkts))
7166             self.verify_capture_out_ip6(capture, nat_ip=out_dst_ip6,
7167                                         dst_ip=out_src_ip6)
7168
7169             pkts = self.create_stream_out_ip6(self.pg1, out_src_ip6,
7170                                               out_dst_ip6)
7171             self.pg1.add_stream(pkts)
7172             self.pg_enable_capture(self.pg_interfaces)
7173             self.pg_start()
7174             capture = self.pg0.get_capture(len(pkts))
7175             self.verify_capture_in(capture, self.pg0)
7176         finally:
7177             self.vapi.nat44_interface_add_del_feature(
7178                 sw_if_index=self.pg0.sw_if_index,
7179                 flags=flags)
7180             self.vapi.nat44_add_del_address_range(
7181                 first_ip_address=self.nat_addr_n,
7182                 last_ip_address=self.nat_addr_n,
7183                 vrf_id=0xFFFFFFFF)
7184
7185     @unittest.skip('Temporary disabled')
7186     def test_464xlat_ce_no_nat(self):
7187         """ Test 464XLAT CE without NAT44 """
7188
7189         self.configure_xlat()
7190
7191         out_src_ip6 = self.compose_ip6(self.dst_ip4, self.dst_ip6_pfx,
7192                                        self.dst_ip6_pfx_len)
7193         out_dst_ip6 = self.compose_ip6(self.pg0.remote_ip4, self.src_ip6_pfx,
7194                                        self.src_ip6_pfx_len)
7195
7196         pkts = self.create_stream_in(self.pg0, self.pg1, self.dst_ip4)
7197         self.pg0.add_stream(pkts)
7198         self.pg_enable_capture(self.pg_interfaces)
7199         self.pg_start()
7200         capture = self.pg1.get_capture(len(pkts))
7201         self.verify_capture_out_ip6(capture, dst_ip=out_src_ip6,
7202                                     nat_ip=out_dst_ip6, same_port=True)
7203
7204         pkts = self.create_stream_out_ip6(self.pg1, out_src_ip6, out_dst_ip6)
7205         self.pg1.add_stream(pkts)
7206         self.pg_enable_capture(self.pg_interfaces)
7207         self.pg_start()
7208         capture = self.pg0.get_capture(len(pkts))
7209         self.verify_capture_in(capture, self.pg0)
7210
7211
7212 if __name__ == '__main__':
7213     unittest.main(testRunner=VppTestRunner)