nat: cleanup & reorganization
[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     @unittest.skipUnless(running_extended_tests, "part of extended tests")
2597     def test_ipfix_max_sessions(self):
2598         """ IPFIX logging maximum session entries exceeded """
2599         self.nat44_add_address(self.nat_addr)
2600         flags = self.config_flags.NAT_IS_INSIDE
2601         self.vapi.nat44_interface_add_del_feature(
2602             sw_if_index=self.pg0.sw_if_index,
2603             flags=flags, is_add=1)
2604         self.vapi.nat44_interface_add_del_feature(
2605             sw_if_index=self.pg1.sw_if_index,
2606             is_add=1)
2607
2608         max_sessions = self.max_translations
2609
2610         pkts = []
2611         for i in range(0, max_sessions):
2612             src = "10.10.%u.%u" % ((i & 0xFF00) >> 8, i & 0xFF)
2613             p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2614                  IP(src=src, dst=self.pg1.remote_ip4) /
2615                  TCP(sport=1025))
2616             pkts.append(p)
2617         self.pg0.add_stream(pkts)
2618         self.pg_enable_capture(self.pg_interfaces)
2619         self.pg_start()
2620
2621         self.pg1.get_capture(max_sessions)
2622         self.vapi.set_ipfix_exporter(collector_address=self.pg3.remote_ip4,
2623                                      src_address=self.pg3.local_ip4,
2624                                      path_mtu=512,
2625                                      template_interval=10)
2626         self.vapi.nat_ipfix_enable_disable(domain_id=self.ipfix_domain_id,
2627                                            src_port=self.ipfix_src_port,
2628                                            enable=1)
2629
2630         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2631              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
2632              TCP(sport=1025))
2633         self.pg0.add_stream(p)
2634         self.pg_enable_capture(self.pg_interfaces)
2635         self.pg_start()
2636         self.pg1.assert_nothing_captured()
2637         sleep(1)
2638         self.vapi.ipfix_flush()
2639         capture = self.pg3.get_capture(7)
2640         ipfix = IPFIXDecoder()
2641         # first load template
2642         for p in capture:
2643             self.assertTrue(p.haslayer(IPFIX))
2644             self.assertEqual(p[IP].src, self.pg3.local_ip4)
2645             self.assertEqual(p[IP].dst, self.pg3.remote_ip4)
2646             self.assertEqual(p[UDP].sport, self.ipfix_src_port)
2647             self.assertEqual(p[UDP].dport, 4739)
2648             self.assertEqual(p[IPFIX].observationDomainID,
2649                              self.ipfix_domain_id)
2650             if p.haslayer(Template):
2651                 ipfix.add_template(p.getlayer(Template))
2652         # verify events in data set
2653         for p in capture:
2654             if p.haslayer(Data):
2655                 data = ipfix.decode_data_set(p.getlayer(Set))
2656                 self.verify_ipfix_max_sessions(data, max_sessions)
2657
2658     def test_syslog_apmap(self):
2659         """ Test syslog address and port mapping creation and deletion """
2660         self.vapi.syslog_set_filter(
2661             self.SYSLOG_SEVERITY.SYSLOG_API_SEVERITY_INFO)
2662         self.vapi.syslog_set_sender(self.pg3.local_ip4, self.pg3.remote_ip4)
2663         self.nat44_add_address(self.nat_addr)
2664         flags = self.config_flags.NAT_IS_INSIDE
2665         self.vapi.nat44_interface_add_del_feature(
2666             sw_if_index=self.pg0.sw_if_index,
2667             flags=flags, is_add=1)
2668         self.vapi.nat44_interface_add_del_feature(
2669             sw_if_index=self.pg1.sw_if_index,
2670             is_add=1)
2671
2672         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2673              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
2674              TCP(sport=self.tcp_port_in, dport=20))
2675         self.pg0.add_stream(p)
2676         self.pg_enable_capture(self.pg_interfaces)
2677         self.pg_start()
2678         capture = self.pg1.get_capture(1)
2679         self.tcp_port_out = capture[0][TCP].sport
2680         capture = self.pg3.get_capture(1)
2681         self.verify_syslog_apmap(capture[0][Raw].load)
2682
2683         self.pg_enable_capture(self.pg_interfaces)
2684         self.pg_start()
2685         self.nat44_add_address(self.nat_addr, is_add=0)
2686         capture = self.pg3.get_capture(1)
2687         self.verify_syslog_apmap(capture[0][Raw].load, False)
2688
2689     def test_pool_addr_fib(self):
2690         """ NAT44 add pool addresses to FIB """
2691         static_addr = '10.0.0.10'
2692         self.nat44_add_address(self.nat_addr)
2693         flags = self.config_flags.NAT_IS_INSIDE
2694         self.vapi.nat44_interface_add_del_feature(
2695             sw_if_index=self.pg0.sw_if_index,
2696             flags=flags, is_add=1)
2697         self.vapi.nat44_interface_add_del_feature(
2698             sw_if_index=self.pg1.sw_if_index,
2699             is_add=1)
2700         self.nat44_add_static_mapping(self.pg0.remote_ip4, static_addr)
2701
2702         # NAT44 address
2703         p = (Ether(src=self.pg1.remote_mac, dst='ff:ff:ff:ff:ff:ff') /
2704              ARP(op=ARP.who_has, pdst=self.nat_addr,
2705                  psrc=self.pg1.remote_ip4, hwsrc=self.pg1.remote_mac))
2706         self.pg1.add_stream(p)
2707         self.pg_enable_capture(self.pg_interfaces)
2708         self.pg_start()
2709         capture = self.pg1.get_capture(1)
2710         self.assertTrue(capture[0].haslayer(ARP))
2711         self.assertTrue(capture[0][ARP].op, ARP.is_at)
2712
2713         # 1:1 NAT address
2714         p = (Ether(src=self.pg1.remote_mac, dst='ff:ff:ff:ff:ff:ff') /
2715              ARP(op=ARP.who_has, pdst=static_addr,
2716                  psrc=self.pg1.remote_ip4, hwsrc=self.pg1.remote_mac))
2717         self.pg1.add_stream(p)
2718         self.pg_enable_capture(self.pg_interfaces)
2719         self.pg_start()
2720         capture = self.pg1.get_capture(1)
2721         self.assertTrue(capture[0].haslayer(ARP))
2722         self.assertTrue(capture[0][ARP].op, ARP.is_at)
2723
2724         # send ARP to non-NAT44 interface
2725         p = (Ether(src=self.pg2.remote_mac, dst='ff:ff:ff:ff:ff:ff') /
2726              ARP(op=ARP.who_has, pdst=self.nat_addr,
2727                  psrc=self.pg2.remote_ip4, hwsrc=self.pg2.remote_mac))
2728         self.pg2.add_stream(p)
2729         self.pg_enable_capture(self.pg_interfaces)
2730         self.pg_start()
2731         self.pg1.assert_nothing_captured()
2732
2733         # remove addresses and verify
2734         self.nat44_add_address(self.nat_addr, is_add=0)
2735         self.nat44_add_static_mapping(self.pg0.remote_ip4, static_addr,
2736                                       is_add=0)
2737
2738         p = (Ether(src=self.pg1.remote_mac, dst='ff:ff:ff:ff:ff:ff') /
2739              ARP(op=ARP.who_has, pdst=self.nat_addr,
2740                  psrc=self.pg1.remote_ip4, hwsrc=self.pg1.remote_mac))
2741         self.pg1.add_stream(p)
2742         self.pg_enable_capture(self.pg_interfaces)
2743         self.pg_start()
2744         self.pg1.assert_nothing_captured()
2745
2746         p = (Ether(src=self.pg1.remote_mac, dst='ff:ff:ff:ff:ff:ff') /
2747              ARP(op=ARP.who_has, pdst=static_addr,
2748                  psrc=self.pg1.remote_ip4, hwsrc=self.pg1.remote_mac))
2749         self.pg1.add_stream(p)
2750         self.pg_enable_capture(self.pg_interfaces)
2751         self.pg_start()
2752         self.pg1.assert_nothing_captured()
2753
2754     def test_vrf_mode(self):
2755         """ NAT44 tenant VRF aware address pool mode """
2756
2757         vrf_id1 = 1
2758         vrf_id2 = 2
2759         nat_ip1 = "10.0.0.10"
2760         nat_ip2 = "10.0.0.11"
2761
2762         self.pg0.unconfig_ip4()
2763         self.pg1.unconfig_ip4()
2764         self.vapi.ip_table_add_del(is_add=1, table={'table_id': vrf_id1})
2765         self.vapi.ip_table_add_del(is_add=1, table={'table_id': vrf_id2})
2766         self.pg0.set_table_ip4(vrf_id1)
2767         self.pg1.set_table_ip4(vrf_id2)
2768         self.pg0.config_ip4()
2769         self.pg1.config_ip4()
2770         self.pg0.resolve_arp()
2771         self.pg1.resolve_arp()
2772
2773         self.nat44_add_address(nat_ip1, vrf_id=vrf_id1)
2774         self.nat44_add_address(nat_ip2, vrf_id=vrf_id2)
2775         flags = self.config_flags.NAT_IS_INSIDE
2776         self.vapi.nat44_interface_add_del_feature(
2777             sw_if_index=self.pg0.sw_if_index,
2778             flags=flags, is_add=1)
2779         self.vapi.nat44_interface_add_del_feature(
2780             sw_if_index=self.pg1.sw_if_index,
2781             flags=flags, is_add=1)
2782         self.vapi.nat44_interface_add_del_feature(
2783             sw_if_index=self.pg2.sw_if_index,
2784             is_add=1)
2785
2786         try:
2787             # first VRF
2788             pkts = self.create_stream_in(self.pg0, self.pg2)
2789             self.pg0.add_stream(pkts)
2790             self.pg_enable_capture(self.pg_interfaces)
2791             self.pg_start()
2792             capture = self.pg2.get_capture(len(pkts))
2793             self.verify_capture_out(capture, nat_ip1)
2794
2795             # second VRF
2796             pkts = self.create_stream_in(self.pg1, self.pg2)
2797             self.pg1.add_stream(pkts)
2798             self.pg_enable_capture(self.pg_interfaces)
2799             self.pg_start()
2800             capture = self.pg2.get_capture(len(pkts))
2801             self.verify_capture_out(capture, nat_ip2)
2802
2803         finally:
2804             self.pg0.unconfig_ip4()
2805             self.pg1.unconfig_ip4()
2806             self.pg0.set_table_ip4(0)
2807             self.pg1.set_table_ip4(0)
2808             self.pg0.config_ip4()
2809             self.pg1.config_ip4()
2810             self.pg0.resolve_arp()
2811             self.pg1.resolve_arp()
2812             self.vapi.ip_table_add_del(is_add=0, table={'table_id': vrf_id1})
2813             self.vapi.ip_table_add_del(is_add=0, table={'table_id': vrf_id2})
2814
2815     def test_vrf_feature_independent(self):
2816         """ NAT44 tenant VRF independent address pool mode """
2817
2818         nat_ip1 = "10.0.0.10"
2819         nat_ip2 = "10.0.0.11"
2820
2821         self.nat44_add_address(nat_ip1)
2822         self.nat44_add_address(nat_ip2, vrf_id=99)
2823         flags = self.config_flags.NAT_IS_INSIDE
2824         self.vapi.nat44_interface_add_del_feature(
2825             sw_if_index=self.pg0.sw_if_index,
2826             flags=flags, is_add=1)
2827         self.vapi.nat44_interface_add_del_feature(
2828             sw_if_index=self.pg1.sw_if_index,
2829             flags=flags, is_add=1)
2830         self.vapi.nat44_interface_add_del_feature(
2831             sw_if_index=self.pg2.sw_if_index,
2832             is_add=1)
2833
2834         # first VRF
2835         pkts = self.create_stream_in(self.pg0, self.pg2)
2836         self.pg0.add_stream(pkts)
2837         self.pg_enable_capture(self.pg_interfaces)
2838         self.pg_start()
2839         capture = self.pg2.get_capture(len(pkts))
2840         self.verify_capture_out(capture, nat_ip1)
2841
2842         # second VRF
2843         pkts = self.create_stream_in(self.pg1, self.pg2)
2844         self.pg1.add_stream(pkts)
2845         self.pg_enable_capture(self.pg_interfaces)
2846         self.pg_start()
2847         capture = self.pg2.get_capture(len(pkts))
2848         self.verify_capture_out(capture, nat_ip1)
2849
2850     def create_routes_and_neigbors(self):
2851         r1 = VppIpRoute(self, self.pg7.remote_ip4, 32,
2852                         [VppRoutePath(self.pg7.remote_ip4,
2853                                       self.pg7.sw_if_index)])
2854         r2 = VppIpRoute(self, self.pg8.remote_ip4, 32,
2855                         [VppRoutePath(self.pg8.remote_ip4,
2856                                       self.pg8.sw_if_index)])
2857         r1.add_vpp_config()
2858         r2.add_vpp_config()
2859
2860         n1 = VppNeighbor(self,
2861                          self.pg7.sw_if_index,
2862                          self.pg7.remote_mac,
2863                          self.pg7.remote_ip4,
2864                          is_static=1)
2865         n2 = VppNeighbor(self,
2866                          self.pg8.sw_if_index,
2867                          self.pg8.remote_mac,
2868                          self.pg8.remote_ip4,
2869                          is_static=1)
2870         n1.add_vpp_config()
2871         n2.add_vpp_config()
2872
2873     def test_dynamic_ipless_interfaces(self):
2874         """ NAT44 interfaces without configured IP address """
2875         self.create_routes_and_neigbors()
2876         self.nat44_add_address(self.nat_addr)
2877         flags = self.config_flags.NAT_IS_INSIDE
2878         self.vapi.nat44_interface_add_del_feature(
2879             sw_if_index=self.pg7.sw_if_index,
2880             flags=flags, is_add=1)
2881         self.vapi.nat44_interface_add_del_feature(
2882             sw_if_index=self.pg8.sw_if_index,
2883             is_add=1)
2884
2885         # in2out
2886         pkts = self.create_stream_in(self.pg7, self.pg8)
2887         self.pg7.add_stream(pkts)
2888         self.pg_enable_capture(self.pg_interfaces)
2889         self.pg_start()
2890         capture = self.pg8.get_capture(len(pkts))
2891         self.verify_capture_out(capture)
2892
2893         # out2in
2894         pkts = self.create_stream_out(self.pg8, self.nat_addr)
2895         self.pg8.add_stream(pkts)
2896         self.pg_enable_capture(self.pg_interfaces)
2897         self.pg_start()
2898         capture = self.pg7.get_capture(len(pkts))
2899         self.verify_capture_in(capture, self.pg7)
2900
2901     def test_static_ipless_interfaces(self):
2902         """ NAT44 interfaces without configured IP address - 1:1 NAT """
2903
2904         self.create_routes_and_neigbors()
2905         self.nat44_add_static_mapping(self.pg7.remote_ip4, self.nat_addr)
2906         flags = self.config_flags.NAT_IS_INSIDE
2907         self.vapi.nat44_interface_add_del_feature(
2908             sw_if_index=self.pg7.sw_if_index,
2909             flags=flags, is_add=1)
2910         self.vapi.nat44_interface_add_del_feature(
2911             sw_if_index=self.pg8.sw_if_index,
2912             is_add=1)
2913
2914         # out2in
2915         pkts = self.create_stream_out(self.pg8)
2916         self.pg8.add_stream(pkts)
2917         self.pg_enable_capture(self.pg_interfaces)
2918         self.pg_start()
2919         capture = self.pg7.get_capture(len(pkts))
2920         self.verify_capture_in(capture, self.pg7)
2921
2922         # in2out
2923         pkts = self.create_stream_in(self.pg7, self.pg8)
2924         self.pg7.add_stream(pkts)
2925         self.pg_enable_capture(self.pg_interfaces)
2926         self.pg_start()
2927         capture = self.pg8.get_capture(len(pkts))
2928         self.verify_capture_out(capture, self.nat_addr, True)
2929
2930     def test_static_with_port_ipless_interfaces(self):
2931         """ NAT44 interfaces without configured IP address - 1:1 NAPT """
2932
2933         self.tcp_port_out = 30606
2934         self.udp_port_out = 30607
2935         self.icmp_id_out = 30608
2936
2937         self.create_routes_and_neigbors()
2938         self.nat44_add_address(self.nat_addr)
2939         self.nat44_add_static_mapping(self.pg7.remote_ip4, self.nat_addr,
2940                                       self.tcp_port_in, self.tcp_port_out,
2941                                       proto=IP_PROTOS.tcp)
2942         self.nat44_add_static_mapping(self.pg7.remote_ip4, self.nat_addr,
2943                                       self.udp_port_in, self.udp_port_out,
2944                                       proto=IP_PROTOS.udp)
2945         self.nat44_add_static_mapping(self.pg7.remote_ip4, self.nat_addr,
2946                                       self.icmp_id_in, self.icmp_id_out,
2947                                       proto=IP_PROTOS.icmp)
2948         flags = self.config_flags.NAT_IS_INSIDE
2949         self.vapi.nat44_interface_add_del_feature(
2950             sw_if_index=self.pg7.sw_if_index,
2951             flags=flags, is_add=1)
2952         self.vapi.nat44_interface_add_del_feature(
2953             sw_if_index=self.pg8.sw_if_index,
2954             is_add=1)
2955
2956         # out2in
2957         pkts = self.create_stream_out(self.pg8)
2958         self.pg8.add_stream(pkts)
2959         self.pg_enable_capture(self.pg_interfaces)
2960         self.pg_start()
2961         capture = self.pg7.get_capture(len(pkts))
2962         self.verify_capture_in(capture, self.pg7)
2963
2964         # in2out
2965         pkts = self.create_stream_in(self.pg7, self.pg8)
2966         self.pg7.add_stream(pkts)
2967         self.pg_enable_capture(self.pg_interfaces)
2968         self.pg_start()
2969         capture = self.pg8.get_capture(len(pkts))
2970         self.verify_capture_out(capture)
2971
2972     def test_static_unknown_proto(self):
2973         """ 1:1 NAT translate packet with unknown protocol """
2974         nat_ip = "10.0.0.10"
2975         self.nat44_add_static_mapping(self.pg0.remote_ip4, nat_ip)
2976         flags = self.config_flags.NAT_IS_INSIDE
2977         self.vapi.nat44_interface_add_del_feature(
2978             sw_if_index=self.pg0.sw_if_index,
2979             flags=flags, is_add=1)
2980         self.vapi.nat44_interface_add_del_feature(
2981             sw_if_index=self.pg1.sw_if_index,
2982             is_add=1)
2983
2984         # in2out
2985         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2986              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
2987              GRE() /
2988              IP(src=self.pg2.remote_ip4, dst=self.pg3.remote_ip4) /
2989              TCP(sport=1234, dport=1234))
2990         self.pg0.add_stream(p)
2991         self.pg_enable_capture(self.pg_interfaces)
2992         self.pg_start()
2993         p = self.pg1.get_capture(1)
2994         packet = p[0]
2995         try:
2996             self.assertEqual(packet[IP].src, nat_ip)
2997             self.assertEqual(packet[IP].dst, self.pg1.remote_ip4)
2998             self.assertEqual(packet.haslayer(GRE), 1)
2999             self.assert_packet_checksums_valid(packet)
3000         except:
3001             self.logger.error(ppp("Unexpected or invalid packet:", packet))
3002             raise
3003
3004         # out2in
3005         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
3006              IP(src=self.pg1.remote_ip4, dst=nat_ip) /
3007              GRE() /
3008              IP(src=self.pg3.remote_ip4, dst=self.pg2.remote_ip4) /
3009              TCP(sport=1234, dport=1234))
3010         self.pg1.add_stream(p)
3011         self.pg_enable_capture(self.pg_interfaces)
3012         self.pg_start()
3013         p = self.pg0.get_capture(1)
3014         packet = p[0]
3015         try:
3016             self.assertEqual(packet[IP].src, self.pg1.remote_ip4)
3017             self.assertEqual(packet[IP].dst, self.pg0.remote_ip4)
3018             self.assertEqual(packet.haslayer(GRE), 1)
3019             self.assert_packet_checksums_valid(packet)
3020         except:
3021             self.logger.error(ppp("Unexpected or invalid packet:", packet))
3022             raise
3023
3024     def test_hairpinning_static_unknown_proto(self):
3025         """ 1:1 NAT translate packet with unknown protocol - hairpinning """
3026
3027         host = self.pg0.remote_hosts[0]
3028         server = self.pg0.remote_hosts[1]
3029
3030         host_nat_ip = "10.0.0.10"
3031         server_nat_ip = "10.0.0.11"
3032
3033         self.nat44_add_static_mapping(host.ip4, host_nat_ip)
3034         self.nat44_add_static_mapping(server.ip4, server_nat_ip)
3035         flags = self.config_flags.NAT_IS_INSIDE
3036         self.vapi.nat44_interface_add_del_feature(
3037             sw_if_index=self.pg0.sw_if_index,
3038             flags=flags, is_add=1)
3039         self.vapi.nat44_interface_add_del_feature(
3040             sw_if_index=self.pg1.sw_if_index,
3041             is_add=1)
3042
3043         # host to server
3044         p = (Ether(dst=self.pg0.local_mac, src=host.mac) /
3045              IP(src=host.ip4, dst=server_nat_ip) /
3046              GRE() /
3047              IP(src=self.pg2.remote_ip4, dst=self.pg3.remote_ip4) /
3048              TCP(sport=1234, dport=1234))
3049         self.pg0.add_stream(p)
3050         self.pg_enable_capture(self.pg_interfaces)
3051         self.pg_start()
3052         p = self.pg0.get_capture(1)
3053         packet = p[0]
3054         try:
3055             self.assertEqual(packet[IP].src, host_nat_ip)
3056             self.assertEqual(packet[IP].dst, server.ip4)
3057             self.assertEqual(packet.haslayer(GRE), 1)
3058             self.assert_packet_checksums_valid(packet)
3059         except:
3060             self.logger.error(ppp("Unexpected or invalid packet:", packet))
3061             raise
3062
3063         # server to host
3064         p = (Ether(dst=self.pg0.local_mac, src=server.mac) /
3065              IP(src=server.ip4, dst=host_nat_ip) /
3066              GRE() /
3067              IP(src=self.pg3.remote_ip4, dst=self.pg2.remote_ip4) /
3068              TCP(sport=1234, dport=1234))
3069         self.pg0.add_stream(p)
3070         self.pg_enable_capture(self.pg_interfaces)
3071         self.pg_start()
3072         p = self.pg0.get_capture(1)
3073         packet = p[0]
3074         try:
3075             self.assertEqual(packet[IP].src, server_nat_ip)
3076             self.assertEqual(packet[IP].dst, host.ip4)
3077             self.assertEqual(packet.haslayer(GRE), 1)
3078             self.assert_packet_checksums_valid(packet)
3079         except:
3080             self.logger.error(ppp("Unexpected or invalid packet:", packet))
3081             raise
3082
3083     def test_output_feature(self):
3084         """ NAT44 interface output feature (in2out postrouting) """
3085         self.nat44_add_address(self.nat_addr)
3086         flags = self.config_flags.NAT_IS_INSIDE
3087         self.vapi.nat44_interface_add_del_output_feature(
3088             is_add=1, flags=flags,
3089             sw_if_index=self.pg0.sw_if_index)
3090         self.vapi.nat44_interface_add_del_output_feature(
3091             is_add=1, flags=flags,
3092             sw_if_index=self.pg1.sw_if_index)
3093         self.vapi.nat44_interface_add_del_output_feature(
3094             is_add=1,
3095             sw_if_index=self.pg3.sw_if_index)
3096
3097         # in2out
3098         pkts = self.create_stream_in(self.pg0, self.pg3)
3099         self.pg0.add_stream(pkts)
3100         self.pg_enable_capture(self.pg_interfaces)
3101         self.pg_start()
3102         capture = self.pg3.get_capture(len(pkts))
3103         self.verify_capture_out(capture)
3104
3105         # out2in
3106         pkts = self.create_stream_out(self.pg3)
3107         self.pg3.add_stream(pkts)
3108         self.pg_enable_capture(self.pg_interfaces)
3109         self.pg_start()
3110         capture = self.pg0.get_capture(len(pkts))
3111         self.verify_capture_in(capture, self.pg0)
3112
3113         # from non-NAT interface to NAT inside interface
3114         pkts = self.create_stream_in(self.pg2, self.pg0)
3115         self.pg2.add_stream(pkts)
3116         self.pg_enable_capture(self.pg_interfaces)
3117         self.pg_start()
3118         capture = self.pg0.get_capture(len(pkts))
3119         self.verify_capture_no_translation(capture, self.pg2, self.pg0)
3120
3121     def test_output_feature_vrf_aware(self):
3122         """ NAT44 interface output feature VRF aware (in2out postrouting) """
3123         nat_ip_vrf10 = "10.0.0.10"
3124         nat_ip_vrf20 = "10.0.0.20"
3125
3126         r1 = VppIpRoute(self, self.pg3.remote_ip4, 32,
3127                         [VppRoutePath(self.pg3.remote_ip4,
3128                                       self.pg3.sw_if_index)],
3129                         table_id=10)
3130         r2 = VppIpRoute(self, self.pg3.remote_ip4, 32,
3131                         [VppRoutePath(self.pg3.remote_ip4,
3132                                       self.pg3.sw_if_index)],
3133                         table_id=20)
3134         r1.add_vpp_config()
3135         r2.add_vpp_config()
3136
3137         self.nat44_add_address(nat_ip_vrf10, vrf_id=10)
3138         self.nat44_add_address(nat_ip_vrf20, vrf_id=20)
3139         flags = self.config_flags.NAT_IS_INSIDE
3140         self.vapi.nat44_interface_add_del_output_feature(
3141             is_add=1, flags=flags,
3142             sw_if_index=self.pg4.sw_if_index)
3143         self.vapi.nat44_interface_add_del_output_feature(
3144             is_add=1, flags=flags,
3145             sw_if_index=self.pg6.sw_if_index)
3146         self.vapi.nat44_interface_add_del_output_feature(
3147             is_add=1,
3148             sw_if_index=self.pg3.sw_if_index)
3149
3150         # in2out VRF 10
3151         pkts = self.create_stream_in(self.pg4, self.pg3)
3152         self.pg4.add_stream(pkts)
3153         self.pg_enable_capture(self.pg_interfaces)
3154         self.pg_start()
3155         capture = self.pg3.get_capture(len(pkts))
3156         self.verify_capture_out(capture, nat_ip=nat_ip_vrf10)
3157
3158         # out2in VRF 10
3159         pkts = self.create_stream_out(self.pg3, dst_ip=nat_ip_vrf10)
3160         self.pg3.add_stream(pkts)
3161         self.pg_enable_capture(self.pg_interfaces)
3162         self.pg_start()
3163         capture = self.pg4.get_capture(len(pkts))
3164         self.verify_capture_in(capture, self.pg4)
3165
3166         # in2out VRF 20
3167         pkts = self.create_stream_in(self.pg6, self.pg3)
3168         self.pg6.add_stream(pkts)
3169         self.pg_enable_capture(self.pg_interfaces)
3170         self.pg_start()
3171         capture = self.pg3.get_capture(len(pkts))
3172         self.verify_capture_out(capture, nat_ip=nat_ip_vrf20)
3173
3174         # out2in VRF 20
3175         pkts = self.create_stream_out(self.pg3, dst_ip=nat_ip_vrf20)
3176         self.pg3.add_stream(pkts)
3177         self.pg_enable_capture(self.pg_interfaces)
3178         self.pg_start()
3179         capture = self.pg6.get_capture(len(pkts))
3180         self.verify_capture_in(capture, self.pg6)
3181
3182     def test_output_feature_hairpinning(self):
3183         """ NAT44 interface output feature hairpinning (in2out postrouting) """
3184         host = self.pg0.remote_hosts[0]
3185         server = self.pg0.remote_hosts[1]
3186         host_in_port = 1234
3187         host_out_port = 0
3188         server_in_port = 5678
3189         server_out_port = 8765
3190
3191         self.nat44_add_address(self.nat_addr)
3192         flags = self.config_flags.NAT_IS_INSIDE
3193         self.vapi.nat44_interface_add_del_output_feature(
3194             is_add=1, flags=flags,
3195             sw_if_index=self.pg0.sw_if_index)
3196         self.vapi.nat44_interface_add_del_output_feature(
3197             is_add=1,
3198             sw_if_index=self.pg1.sw_if_index)
3199
3200         # add static mapping for server
3201         self.nat44_add_static_mapping(server.ip4, self.nat_addr,
3202                                       server_in_port, server_out_port,
3203                                       proto=IP_PROTOS.tcp)
3204
3205         # send packet from host to server
3206         p = (Ether(src=host.mac, dst=self.pg0.local_mac) /
3207              IP(src=host.ip4, dst=self.nat_addr) /
3208              TCP(sport=host_in_port, dport=server_out_port))
3209         self.pg0.add_stream(p)
3210         self.pg_enable_capture(self.pg_interfaces)
3211         self.pg_start()
3212         capture = self.pg0.get_capture(1)
3213         p = capture[0]
3214         try:
3215             ip = p[IP]
3216             tcp = p[TCP]
3217             self.assertEqual(ip.src, self.nat_addr)
3218             self.assertEqual(ip.dst, server.ip4)
3219             self.assertNotEqual(tcp.sport, host_in_port)
3220             self.assertEqual(tcp.dport, server_in_port)
3221             self.assert_packet_checksums_valid(p)
3222             host_out_port = tcp.sport
3223         except:
3224             self.logger.error(ppp("Unexpected or invalid packet:", p))
3225             raise
3226
3227         # send reply from server to host
3228         p = (Ether(src=server.mac, dst=self.pg0.local_mac) /
3229              IP(src=server.ip4, dst=self.nat_addr) /
3230              TCP(sport=server_in_port, dport=host_out_port))
3231         self.pg0.add_stream(p)
3232         self.pg_enable_capture(self.pg_interfaces)
3233         self.pg_start()
3234         capture = self.pg0.get_capture(1)
3235         p = capture[0]
3236         try:
3237             ip = p[IP]
3238             tcp = p[TCP]
3239             self.assertEqual(ip.src, self.nat_addr)
3240             self.assertEqual(ip.dst, host.ip4)
3241             self.assertEqual(tcp.sport, server_out_port)
3242             self.assertEqual(tcp.dport, host_in_port)
3243             self.assert_packet_checksums_valid(p)
3244         except:
3245             self.logger.error(ppp("Unexpected or invalid packet:", p))
3246             raise
3247
3248     def test_one_armed_nat44(self):
3249         """ One armed NAT44 """
3250         remote_host = self.pg9.remote_hosts[0]
3251         local_host = self.pg9.remote_hosts[1]
3252         external_port = 0
3253
3254         self.nat44_add_address(self.nat_addr)
3255         flags = self.config_flags.NAT_IS_INSIDE
3256         self.vapi.nat44_interface_add_del_feature(
3257             sw_if_index=self.pg9.sw_if_index,
3258             is_add=1)
3259         self.vapi.nat44_interface_add_del_feature(
3260             sw_if_index=self.pg9.sw_if_index,
3261             flags=flags, is_add=1)
3262
3263         # in2out
3264         p = (Ether(src=self.pg9.remote_mac, dst=self.pg9.local_mac) /
3265              IP(src=local_host.ip4, dst=remote_host.ip4) /
3266              TCP(sport=12345, dport=80))
3267         self.pg9.add_stream(p)
3268         self.pg_enable_capture(self.pg_interfaces)
3269         self.pg_start()
3270         capture = self.pg9.get_capture(1)
3271         p = capture[0]
3272         try:
3273             ip = p[IP]
3274             tcp = p[TCP]
3275             self.assertEqual(ip.src, self.nat_addr)
3276             self.assertEqual(ip.dst, remote_host.ip4)
3277             self.assertNotEqual(tcp.sport, 12345)
3278             external_port = tcp.sport
3279             self.assertEqual(tcp.dport, 80)
3280             self.assert_packet_checksums_valid(p)
3281         except:
3282             self.logger.error(ppp("Unexpected or invalid packet:", p))
3283             raise
3284
3285         # out2in
3286         p = (Ether(src=self.pg9.remote_mac, dst=self.pg9.local_mac) /
3287              IP(src=remote_host.ip4, dst=self.nat_addr) /
3288              TCP(sport=80, dport=external_port))
3289         self.pg9.add_stream(p)
3290         self.pg_enable_capture(self.pg_interfaces)
3291         self.pg_start()
3292         capture = self.pg9.get_capture(1)
3293         p = capture[0]
3294         try:
3295             ip = p[IP]
3296             tcp = p[TCP]
3297             self.assertEqual(ip.src, remote_host.ip4)
3298             self.assertEqual(ip.dst, local_host.ip4)
3299             self.assertEqual(tcp.sport, 80)
3300             self.assertEqual(tcp.dport, 12345)
3301             self.assert_packet_checksums_valid(p)
3302         except:
3303             self.logger.error(ppp("Unexpected or invalid packet:", p))
3304             raise
3305
3306         err = self.statistics.get_err_counter(
3307             '/err/nat44-classify/next in2out')
3308         self.assertEqual(err, 1)
3309         err = self.statistics.get_err_counter(
3310             '/err/nat44-classify/next out2in')
3311         self.assertEqual(err, 1)
3312
3313     def test_del_session(self):
3314         """ Delete NAT44 session """
3315         self.nat44_add_address(self.nat_addr)
3316         flags = self.config_flags.NAT_IS_INSIDE
3317         self.vapi.nat44_interface_add_del_feature(
3318             sw_if_index=self.pg0.sw_if_index,
3319             flags=flags, is_add=1)
3320         self.vapi.nat44_interface_add_del_feature(
3321             sw_if_index=self.pg1.sw_if_index,
3322             is_add=1)
3323
3324         pkts = self.create_stream_in(self.pg0, self.pg1)
3325         self.pg0.add_stream(pkts)
3326         self.pg_enable_capture(self.pg_interfaces)
3327         self.pg_start()
3328         self.pg1.get_capture(len(pkts))
3329
3330         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
3331         nsessions = len(sessions)
3332
3333         self.vapi.nat44_del_session(address=sessions[0].inside_ip_address,
3334                                     port=sessions[0].inside_port,
3335                                     protocol=sessions[0].protocol,
3336                                     flags=self.config_flags.NAT_IS_INSIDE)
3337         self.vapi.nat44_del_session(address=sessions[1].outside_ip_address,
3338                                     port=sessions[1].outside_port,
3339                                     protocol=sessions[1].protocol)
3340
3341         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
3342         self.assertEqual(nsessions - len(sessions), 2)
3343
3344         self.vapi.nat44_del_session(address=sessions[0].inside_ip_address,
3345                                     port=sessions[0].inside_port,
3346                                     protocol=sessions[0].protocol,
3347                                     flags=self.config_flags.NAT_IS_INSIDE)
3348
3349         self.verify_no_nat44_user()
3350
3351     def test_frag_in_order(self):
3352         """ NAT44 translate fragments arriving in order """
3353
3354         self.nat44_add_address(self.nat_addr)
3355         flags = self.config_flags.NAT_IS_INSIDE
3356         self.vapi.nat44_interface_add_del_feature(
3357             sw_if_index=self.pg0.sw_if_index,
3358             flags=flags, is_add=1)
3359         self.vapi.nat44_interface_add_del_feature(
3360             sw_if_index=self.pg1.sw_if_index,
3361             is_add=1)
3362
3363         self.frag_in_order(proto=IP_PROTOS.tcp)
3364         self.frag_in_order(proto=IP_PROTOS.udp)
3365         self.frag_in_order(proto=IP_PROTOS.icmp)
3366
3367     def test_frag_forwarding(self):
3368         """ NAT44 forwarding fragment test """
3369         self.vapi.nat44_add_del_interface_addr(
3370             is_add=1,
3371             sw_if_index=self.pg1.sw_if_index)
3372         flags = self.config_flags.NAT_IS_INSIDE
3373         self.vapi.nat44_interface_add_del_feature(
3374             sw_if_index=self.pg0.sw_if_index,
3375             flags=flags, is_add=1)
3376         self.vapi.nat44_interface_add_del_feature(
3377             sw_if_index=self.pg1.sw_if_index,
3378             is_add=1)
3379         self.vapi.nat44_forwarding_enable_disable(enable=1)
3380
3381         data = b"A" * 16 + b"B" * 16 + b"C" * 3
3382         pkts = self.create_stream_frag(self.pg1,
3383                                        self.pg0.remote_ip4,
3384                                        4789,
3385                                        4789,
3386                                        data,
3387                                        proto=IP_PROTOS.udp)
3388         self.pg1.add_stream(pkts)
3389         self.pg_enable_capture(self.pg_interfaces)
3390         self.pg_start()
3391         frags = self.pg0.get_capture(len(pkts))
3392         p = self.reass_frags_and_verify(frags,
3393                                         self.pg1.remote_ip4,
3394                                         self.pg0.remote_ip4)
3395         self.assertEqual(p[UDP].sport, 4789)
3396         self.assertEqual(p[UDP].dport, 4789)
3397         self.assertEqual(data, p[Raw].load)
3398
3399     def test_reass_hairpinning(self):
3400         """ NAT44 fragments hairpinning """
3401
3402         self.server = self.pg0.remote_hosts[1]
3403         self.host_in_port = random.randint(1025, 65535)
3404         self.server_in_port = random.randint(1025, 65535)
3405         self.server_out_port = random.randint(1025, 65535)
3406
3407         self.nat44_add_address(self.nat_addr)
3408         flags = self.config_flags.NAT_IS_INSIDE
3409         self.vapi.nat44_interface_add_del_feature(
3410             sw_if_index=self.pg0.sw_if_index,
3411             flags=flags, is_add=1)
3412         self.vapi.nat44_interface_add_del_feature(
3413             sw_if_index=self.pg1.sw_if_index,
3414             is_add=1)
3415         # add static mapping for server
3416         self.nat44_add_static_mapping(self.server.ip4, self.nat_addr,
3417                                       self.server_in_port,
3418                                       self.server_out_port,
3419                                       proto=IP_PROTOS.tcp)
3420         self.nat44_add_static_mapping(self.server.ip4, self.nat_addr,
3421                                       self.server_in_port,
3422                                       self.server_out_port,
3423                                       proto=IP_PROTOS.udp)
3424         self.nat44_add_static_mapping(self.server.ip4, self.nat_addr)
3425
3426         self.reass_hairpinning(proto=IP_PROTOS.tcp)
3427         self.reass_hairpinning(proto=IP_PROTOS.udp)
3428         self.reass_hairpinning(proto=IP_PROTOS.icmp)
3429
3430     def test_frag_out_of_order(self):
3431         """ NAT44 translate fragments arriving out of order """
3432
3433         self.nat44_add_address(self.nat_addr)
3434         flags = self.config_flags.NAT_IS_INSIDE
3435         self.vapi.nat44_interface_add_del_feature(
3436             sw_if_index=self.pg0.sw_if_index,
3437             flags=flags, is_add=1)
3438         self.vapi.nat44_interface_add_del_feature(
3439             sw_if_index=self.pg1.sw_if_index,
3440             is_add=1)
3441
3442         self.frag_out_of_order(proto=IP_PROTOS.tcp)
3443         self.frag_out_of_order(proto=IP_PROTOS.udp)
3444         self.frag_out_of_order(proto=IP_PROTOS.icmp)
3445
3446     def test_port_restricted(self):
3447         """ Port restricted NAT44 (MAP-E CE) """
3448         self.nat44_add_address(self.nat_addr)
3449         flags = self.config_flags.NAT_IS_INSIDE
3450         self.vapi.nat44_interface_add_del_feature(
3451             sw_if_index=self.pg0.sw_if_index,
3452             flags=flags, is_add=1)
3453         self.vapi.nat44_interface_add_del_feature(
3454             sw_if_index=self.pg1.sw_if_index,
3455             is_add=1)
3456         self.vapi.nat_set_addr_and_port_alloc_alg(alg=1,
3457                                                   psid_offset=6,
3458                                                   psid_length=6,
3459                                                   psid=10)
3460
3461         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
3462              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3463              TCP(sport=4567, dport=22))
3464         self.pg0.add_stream(p)
3465         self.pg_enable_capture(self.pg_interfaces)
3466         self.pg_start()
3467         capture = self.pg1.get_capture(1)
3468         p = capture[0]
3469         try:
3470             ip = p[IP]
3471             tcp = p[TCP]
3472             self.assertEqual(ip.dst, self.pg1.remote_ip4)
3473             self.assertEqual(ip.src, self.nat_addr)
3474             self.assertEqual(tcp.dport, 22)
3475             self.assertNotEqual(tcp.sport, 4567)
3476             self.assertEqual((tcp.sport >> 6) & 63, 10)
3477             self.assert_packet_checksums_valid(p)
3478         except:
3479             self.logger.error(ppp("Unexpected or invalid packet:", p))
3480             raise
3481
3482     def test_port_range(self):
3483         """ External address port range """
3484         self.nat44_add_address(self.nat_addr)
3485         flags = self.config_flags.NAT_IS_INSIDE
3486         self.vapi.nat44_interface_add_del_feature(
3487             sw_if_index=self.pg0.sw_if_index,
3488             flags=flags, is_add=1)
3489         self.vapi.nat44_interface_add_del_feature(
3490             sw_if_index=self.pg1.sw_if_index,
3491             is_add=1)
3492         self.vapi.nat_set_addr_and_port_alloc_alg(alg=2,
3493                                                   start_port=1025,
3494                                                   end_port=1027)
3495
3496         pkts = []
3497         for port in range(0, 5):
3498             p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
3499                  IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3500                  TCP(sport=1125 + port))
3501             pkts.append(p)
3502         self.pg0.add_stream(pkts)
3503         self.pg_enable_capture(self.pg_interfaces)
3504         self.pg_start()
3505         capture = self.pg1.get_capture(3)
3506         for p in capture:
3507             tcp = p[TCP]
3508             self.assertGreaterEqual(tcp.sport, 1025)
3509             self.assertLessEqual(tcp.sport, 1027)
3510
3511     def test_multiple_outside_vrf(self):
3512         """ Multiple outside VRF """
3513         vrf_id1 = 1
3514         vrf_id2 = 2
3515
3516         self.pg1.unconfig_ip4()
3517         self.pg2.unconfig_ip4()
3518         self.vapi.ip_table_add_del(is_add=1, table={'table_id': vrf_id1})
3519         self.vapi.ip_table_add_del(is_add=1, table={'table_id': vrf_id2})
3520         self.pg1.set_table_ip4(vrf_id1)
3521         self.pg2.set_table_ip4(vrf_id2)
3522         self.pg1.config_ip4()
3523         self.pg2.config_ip4()
3524         self.pg1.resolve_arp()
3525         self.pg2.resolve_arp()
3526
3527         self.nat44_add_address(self.nat_addr)
3528         flags = self.config_flags.NAT_IS_INSIDE
3529         self.vapi.nat44_interface_add_del_feature(
3530             sw_if_index=self.pg0.sw_if_index,
3531             flags=flags, is_add=1)
3532         self.vapi.nat44_interface_add_del_feature(
3533             sw_if_index=self.pg1.sw_if_index,
3534             is_add=1)
3535         self.vapi.nat44_interface_add_del_feature(
3536             sw_if_index=self.pg2.sw_if_index,
3537             is_add=1)
3538
3539         try:
3540             # first VRF
3541             pkts = self.create_stream_in(self.pg0, self.pg1)
3542             self.pg0.add_stream(pkts)
3543             self.pg_enable_capture(self.pg_interfaces)
3544             self.pg_start()
3545             capture = self.pg1.get_capture(len(pkts))
3546             self.verify_capture_out(capture, self.nat_addr)
3547
3548             pkts = self.create_stream_out(self.pg1, self.nat_addr)
3549             self.pg1.add_stream(pkts)
3550             self.pg_enable_capture(self.pg_interfaces)
3551             self.pg_start()
3552             capture = self.pg0.get_capture(len(pkts))
3553             self.verify_capture_in(capture, self.pg0)
3554
3555             self.tcp_port_in = 60303
3556             self.udp_port_in = 60304
3557             self.icmp_id_in = 60305
3558
3559             # second VRF
3560             pkts = self.create_stream_in(self.pg0, self.pg2)
3561             self.pg0.add_stream(pkts)
3562             self.pg_enable_capture(self.pg_interfaces)
3563             self.pg_start()
3564             capture = self.pg2.get_capture(len(pkts))
3565             self.verify_capture_out(capture, self.nat_addr)
3566
3567             pkts = self.create_stream_out(self.pg2, self.nat_addr)
3568             self.pg2.add_stream(pkts)
3569             self.pg_enable_capture(self.pg_interfaces)
3570             self.pg_start()
3571             capture = self.pg0.get_capture(len(pkts))
3572             self.verify_capture_in(capture, self.pg0)
3573
3574         finally:
3575             self.nat44_add_address(self.nat_addr, is_add=0)
3576             self.pg1.unconfig_ip4()
3577             self.pg2.unconfig_ip4()
3578             self.pg1.set_table_ip4(0)
3579             self.pg2.set_table_ip4(0)
3580             self.pg1.config_ip4()
3581             self.pg2.config_ip4()
3582             self.pg1.resolve_arp()
3583             self.pg2.resolve_arp()
3584
3585     @unittest.skipUnless(running_extended_tests, "part of extended tests")
3586     def test_session_timeout(self):
3587         """ NAT44 session timeouts """
3588         self.nat44_add_address(self.nat_addr)
3589         flags = self.config_flags.NAT_IS_INSIDE
3590         self.vapi.nat44_interface_add_del_feature(
3591             sw_if_index=self.pg0.sw_if_index,
3592             flags=flags, is_add=1)
3593         self.vapi.nat44_interface_add_del_feature(
3594             sw_if_index=self.pg1.sw_if_index,
3595             is_add=1)
3596         self.vapi.nat_set_timeouts(udp=5, tcp_established=7440,
3597                                    tcp_transitory=240, icmp=60)
3598
3599         max_sessions = 1000
3600         pkts = []
3601         for i in range(0, max_sessions):
3602             src = "10.10.%u.%u" % ((i & 0xFF00) >> 8, i & 0xFF)
3603             p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
3604                  IP(src=src, dst=self.pg1.remote_ip4) /
3605                  UDP(sport=1025, dport=53))
3606             pkts.append(p)
3607         self.pg0.add_stream(pkts)
3608         self.pg_enable_capture(self.pg_interfaces)
3609         self.pg_start()
3610         self.pg1.get_capture(max_sessions)
3611
3612         sleep(6)
3613
3614         pkts = []
3615         for i in range(0, max_sessions):
3616             src = "10.10.%u.%u" % ((i & 0xFF00) >> 8, i & 0xFF)
3617             p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
3618                  IP(src=src, dst=self.pg1.remote_ip4) /
3619                  UDP(sport=1026, dport=53))
3620             pkts.append(p)
3621         self.pg0.add_stream(pkts)
3622         self.pg_enable_capture(self.pg_interfaces)
3623         self.pg_start()
3624         self.pg1.get_capture(max_sessions)
3625
3626         nsessions = 0
3627         users = self.vapi.nat44_user_dump()
3628         for user in users:
3629             nsessions = nsessions + user.nsessions
3630         self.assertLess(nsessions, 2 * max_sessions)
3631
3632     def test_mss_clamping(self):
3633         """ TCP MSS clamping """
3634         self.nat44_add_address(self.nat_addr)
3635         flags = self.config_flags.NAT_IS_INSIDE
3636         self.vapi.nat44_interface_add_del_feature(
3637             sw_if_index=self.pg0.sw_if_index,
3638             flags=flags, is_add=1)
3639         self.vapi.nat44_interface_add_del_feature(
3640             sw_if_index=self.pg1.sw_if_index,
3641             is_add=1)
3642
3643         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
3644              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3645              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
3646                  flags="S", options=[('MSS', 1400)]))
3647
3648         self.vapi.nat_set_mss_clamping(enable=1, mss_value=1000)
3649         self.pg0.add_stream(p)
3650         self.pg_enable_capture(self.pg_interfaces)
3651         self.pg_start()
3652         capture = self.pg1.get_capture(1)
3653         # Negotiated MSS value greater than configured - changed
3654         self.verify_mss_value(capture[0], 1000)
3655
3656         self.vapi.nat_set_mss_clamping(enable=0, mss_value=1500)
3657         self.pg0.add_stream(p)
3658         self.pg_enable_capture(self.pg_interfaces)
3659         self.pg_start()
3660         capture = self.pg1.get_capture(1)
3661         # MSS clamping disabled - negotiated MSS unchanged
3662         self.verify_mss_value(capture[0], 1400)
3663
3664         self.vapi.nat_set_mss_clamping(enable=1, mss_value=1500)
3665         self.pg0.add_stream(p)
3666         self.pg_enable_capture(self.pg_interfaces)
3667         self.pg_start()
3668         capture = self.pg1.get_capture(1)
3669         # Negotiated MSS value smaller than configured - unchanged
3670         self.verify_mss_value(capture[0], 1400)
3671
3672     @unittest.skipUnless(running_extended_tests, "part of extended tests")
3673     def test_ha_send(self):
3674         """ Send HA session synchronization events (active) """
3675         self.nat44_add_address(self.nat_addr)
3676         flags = self.config_flags.NAT_IS_INSIDE
3677         self.vapi.nat44_interface_add_del_feature(
3678             sw_if_index=self.pg0.sw_if_index,
3679             flags=flags, is_add=1)
3680         self.vapi.nat44_interface_add_del_feature(
3681             sw_if_index=self.pg1.sw_if_index,
3682             is_add=1)
3683         self.vapi.nat_ha_set_listener(ip_address=self.pg3.local_ip4,
3684                                       port=12345,
3685                                       path_mtu=512)
3686         self.vapi.nat_ha_set_failover(ip_address=self.pg3.remote_ip4,
3687                                       port=12346, session_refresh_interval=10)
3688         bind_layers(UDP, HANATStateSync, sport=12345)
3689
3690         # create sessions
3691         pkts = self.create_stream_in(self.pg0, self.pg1)
3692         self.pg0.add_stream(pkts)
3693         self.pg_enable_capture(self.pg_interfaces)
3694         self.pg_start()
3695         capture = self.pg1.get_capture(len(pkts))
3696         self.verify_capture_out(capture)
3697         # active send HA events
3698         self.vapi.nat_ha_flush()
3699         stats = self.statistics.get_counter('/nat44/ha/add-event-send')
3700         self.assertEqual(stats[0][0], 3)
3701         capture = self.pg3.get_capture(1)
3702         p = capture[0]
3703         self.assert_packet_checksums_valid(p)
3704         try:
3705             ip = p[IP]
3706             udp = p[UDP]
3707             hanat = p[HANATStateSync]
3708         except IndexError:
3709             self.logger.error(ppp("Invalid packet:", p))
3710             raise
3711         else:
3712             self.assertEqual(ip.src, self.pg3.local_ip4)
3713             self.assertEqual(ip.dst, self.pg3.remote_ip4)
3714             self.assertEqual(udp.sport, 12345)
3715             self.assertEqual(udp.dport, 12346)
3716             self.assertEqual(hanat.version, 1)
3717             self.assertEqual(hanat.thread_index, 0)
3718             self.assertEqual(hanat.count, 3)
3719             seq = hanat.sequence_number
3720             for event in hanat.events:
3721                 self.assertEqual(event.event_type, 1)
3722                 self.assertEqual(event.in_addr, self.pg0.remote_ip4)
3723                 self.assertEqual(event.out_addr, self.nat_addr)
3724                 self.assertEqual(event.fib_index, 0)
3725
3726         # ACK received events
3727         ack = (Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac) /
3728                IP(src=self.pg3.remote_ip4, dst=self.pg3.local_ip4) /
3729                UDP(sport=12346, dport=12345) /
3730                HANATStateSync(sequence_number=seq, flags='ACK'))
3731         self.pg3.add_stream(ack)
3732         self.pg_start()
3733         stats = self.statistics.get_counter('/nat44/ha/ack-recv')
3734         self.assertEqual(stats[0][0], 1)
3735
3736         # delete one session
3737         self.pg_enable_capture(self.pg_interfaces)
3738         self.vapi.nat44_del_session(address=self.pg0.remote_ip4,
3739                                     port=self.tcp_port_in,
3740                                     protocol=IP_PROTOS.tcp,
3741                                     flags=self.config_flags.NAT_IS_INSIDE)
3742         self.vapi.nat_ha_flush()
3743         stats = self.statistics.get_counter('/nat44/ha/del-event-send')
3744         self.assertEqual(stats[0][0], 1)
3745         capture = self.pg3.get_capture(1)
3746         p = capture[0]
3747         try:
3748             hanat = p[HANATStateSync]
3749         except IndexError:
3750             self.logger.error(ppp("Invalid packet:", p))
3751             raise
3752         else:
3753             self.assertGreater(hanat.sequence_number, seq)
3754
3755         # do not send ACK, active retry send HA event again
3756         self.pg_enable_capture(self.pg_interfaces)
3757         sleep(12)
3758         stats = self.statistics.get_counter('/nat44/ha/retry-count')
3759         self.assertEqual(stats[0][0], 3)
3760         stats = self.statistics.get_counter('/nat44/ha/missed-count')
3761         self.assertEqual(stats[0][0], 1)
3762         capture = self.pg3.get_capture(3)
3763         for packet in capture:
3764             self.assertEqual(packet, p)
3765
3766         # session counters refresh
3767         pkts = self.create_stream_out(self.pg1)
3768         self.pg1.add_stream(pkts)
3769         self.pg_enable_capture(self.pg_interfaces)
3770         self.pg_start()
3771         self.pg0.get_capture(2)
3772         self.vapi.nat_ha_flush()
3773         stats = self.statistics.get_counter('/nat44/ha/refresh-event-send')
3774         self.assertEqual(stats[0][0], 2)
3775         capture = self.pg3.get_capture(1)
3776         p = capture[0]
3777         self.assert_packet_checksums_valid(p)
3778         try:
3779             ip = p[IP]
3780             udp = p[UDP]
3781             hanat = p[HANATStateSync]
3782         except IndexError:
3783             self.logger.error(ppp("Invalid packet:", p))
3784             raise
3785         else:
3786             self.assertEqual(ip.src, self.pg3.local_ip4)
3787             self.assertEqual(ip.dst, self.pg3.remote_ip4)
3788             self.assertEqual(udp.sport, 12345)
3789             self.assertEqual(udp.dport, 12346)
3790             self.assertEqual(hanat.version, 1)
3791             self.assertEqual(hanat.count, 2)
3792             seq = hanat.sequence_number
3793             for event in hanat.events:
3794                 self.assertEqual(event.event_type, 3)
3795                 self.assertEqual(event.out_addr, self.nat_addr)
3796                 self.assertEqual(event.fib_index, 0)
3797                 self.assertEqual(event.total_pkts, 2)
3798                 self.assertGreater(event.total_bytes, 0)
3799
3800         ack = (Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac) /
3801                IP(src=self.pg3.remote_ip4, dst=self.pg3.local_ip4) /
3802                UDP(sport=12346, dport=12345) /
3803                HANATStateSync(sequence_number=seq, flags='ACK'))
3804         self.pg3.add_stream(ack)
3805         self.pg_start()
3806         stats = self.statistics.get_counter('/nat44/ha/ack-recv')
3807         self.assertEqual(stats[0][0], 2)
3808
3809     def test_ha_recv(self):
3810         """ Receive HA session synchronization events (passive) """
3811         self.nat44_add_address(self.nat_addr)
3812         flags = self.config_flags.NAT_IS_INSIDE
3813         self.vapi.nat44_interface_add_del_feature(
3814             sw_if_index=self.pg0.sw_if_index,
3815             flags=flags, is_add=1)
3816         self.vapi.nat44_interface_add_del_feature(
3817             sw_if_index=self.pg1.sw_if_index,
3818             is_add=1)
3819         self.vapi.nat_ha_set_listener(ip_address=self.pg3.local_ip4,
3820                                       port=12345,
3821                                       path_mtu=512)
3822         bind_layers(UDP, HANATStateSync, sport=12345)
3823
3824         self.tcp_port_out = random.randint(1025, 65535)
3825         self.udp_port_out = random.randint(1025, 65535)
3826
3827         # send HA session add events to failover/passive
3828         p = (Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac) /
3829              IP(src=self.pg3.remote_ip4, dst=self.pg3.local_ip4) /
3830              UDP(sport=12346, dport=12345) /
3831              HANATStateSync(sequence_number=1, events=[
3832                  Event(event_type='add', protocol='tcp',
3833                        in_addr=self.pg0.remote_ip4, out_addr=self.nat_addr,
3834                        in_port=self.tcp_port_in, out_port=self.tcp_port_out,
3835                        eh_addr=self.pg1.remote_ip4,
3836                        ehn_addr=self.pg1.remote_ip4,
3837                        eh_port=self.tcp_external_port,
3838                        ehn_port=self.tcp_external_port, fib_index=0),
3839                  Event(event_type='add', protocol='udp',
3840                        in_addr=self.pg0.remote_ip4, out_addr=self.nat_addr,
3841                        in_port=self.udp_port_in, out_port=self.udp_port_out,
3842                        eh_addr=self.pg1.remote_ip4,
3843                        ehn_addr=self.pg1.remote_ip4,
3844                        eh_port=self.udp_external_port,
3845                        ehn_port=self.udp_external_port, fib_index=0)]))
3846
3847         self.pg3.add_stream(p)
3848         self.pg_enable_capture(self.pg_interfaces)
3849         self.pg_start()
3850         # receive ACK
3851         capture = self.pg3.get_capture(1)
3852         p = capture[0]
3853         try:
3854             hanat = p[HANATStateSync]
3855         except IndexError:
3856             self.logger.error(ppp("Invalid packet:", p))
3857             raise
3858         else:
3859             self.assertEqual(hanat.sequence_number, 1)
3860             self.assertEqual(hanat.flags, 'ACK')
3861             self.assertEqual(hanat.version, 1)
3862             self.assertEqual(hanat.thread_index, 0)
3863         stats = self.statistics.get_counter('/nat44/ha/ack-send')
3864         self.assertEqual(stats[0][0], 1)
3865         stats = self.statistics.get_counter('/nat44/ha/add-event-recv')
3866         self.assertEqual(stats[0][0], 2)
3867         users = self.statistics.get_counter('/nat44/total-users')
3868         self.assertEqual(users[0][0], 1)
3869         sessions = self.statistics.get_counter('/nat44/total-sessions')
3870         self.assertEqual(sessions[0][0], 2)
3871         users = self.vapi.nat44_user_dump()
3872         self.assertEqual(len(users), 1)
3873         self.assertEqual(str(users[0].ip_address),
3874                          self.pg0.remote_ip4)
3875         # there should be 2 sessions created by HA
3876         sessions = self.vapi.nat44_user_session_dump(users[0].ip_address,
3877                                                      users[0].vrf_id)
3878         self.assertEqual(len(sessions), 2)
3879         for session in sessions:
3880             self.assertEqual(str(session.inside_ip_address),
3881                              self.pg0.remote_ip4)
3882             self.assertEqual(str(session.outside_ip_address),
3883                              self.nat_addr)
3884             self.assertIn(session.inside_port,
3885                           [self.tcp_port_in, self.udp_port_in])
3886             self.assertIn(session.outside_port,
3887                           [self.tcp_port_out, self.udp_port_out])
3888             self.assertIn(session.protocol, [IP_PROTOS.tcp, IP_PROTOS.udp])
3889
3890         # send HA session delete event to failover/passive
3891         p = (Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac) /
3892              IP(src=self.pg3.remote_ip4, dst=self.pg3.local_ip4) /
3893              UDP(sport=12346, dport=12345) /
3894              HANATStateSync(sequence_number=2, events=[
3895                  Event(event_type='del', protocol='udp',
3896                        in_addr=self.pg0.remote_ip4, out_addr=self.nat_addr,
3897                        in_port=self.udp_port_in, out_port=self.udp_port_out,
3898                        eh_addr=self.pg1.remote_ip4,
3899                        ehn_addr=self.pg1.remote_ip4,
3900                        eh_port=self.udp_external_port,
3901                        ehn_port=self.udp_external_port, fib_index=0)]))
3902
3903         self.pg3.add_stream(p)
3904         self.pg_enable_capture(self.pg_interfaces)
3905         self.pg_start()
3906         # receive ACK
3907         capture = self.pg3.get_capture(1)
3908         p = capture[0]
3909         try:
3910             hanat = p[HANATStateSync]
3911         except IndexError:
3912             self.logger.error(ppp("Invalid packet:", p))
3913             raise
3914         else:
3915             self.assertEqual(hanat.sequence_number, 2)
3916             self.assertEqual(hanat.flags, 'ACK')
3917             self.assertEqual(hanat.version, 1)
3918         users = self.vapi.nat44_user_dump()
3919         self.assertEqual(len(users), 1)
3920         self.assertEqual(str(users[0].ip_address),
3921                          self.pg0.remote_ip4)
3922         # now we should have only 1 session, 1 deleted by HA
3923         sessions = self.vapi.nat44_user_session_dump(users[0].ip_address,
3924                                                      users[0].vrf_id)
3925         self.assertEqual(len(sessions), 1)
3926         stats = self.statistics.get_counter('/nat44/ha/del-event-recv')
3927         self.assertEqual(stats[0][0], 1)
3928
3929         stats = self.statistics.get_err_counter('/err/nat-ha/pkts-processed')
3930         self.assertEqual(stats, 2)
3931
3932         # send HA session refresh event to failover/passive
3933         p = (Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac) /
3934              IP(src=self.pg3.remote_ip4, dst=self.pg3.local_ip4) /
3935              UDP(sport=12346, dport=12345) /
3936              HANATStateSync(sequence_number=3, events=[
3937                  Event(event_type='refresh', protocol='tcp',
3938                        in_addr=self.pg0.remote_ip4, out_addr=self.nat_addr,
3939                        in_port=self.tcp_port_in, out_port=self.tcp_port_out,
3940                        eh_addr=self.pg1.remote_ip4,
3941                        ehn_addr=self.pg1.remote_ip4,
3942                        eh_port=self.tcp_external_port,
3943                        ehn_port=self.tcp_external_port, fib_index=0,
3944                        total_bytes=1024, total_pkts=2)]))
3945         self.pg3.add_stream(p)
3946         self.pg_enable_capture(self.pg_interfaces)
3947         self.pg_start()
3948         # receive ACK
3949         capture = self.pg3.get_capture(1)
3950         p = capture[0]
3951         try:
3952             hanat = p[HANATStateSync]
3953         except IndexError:
3954             self.logger.error(ppp("Invalid packet:", p))
3955             raise
3956         else:
3957             self.assertEqual(hanat.sequence_number, 3)
3958             self.assertEqual(hanat.flags, 'ACK')
3959             self.assertEqual(hanat.version, 1)
3960         users = self.vapi.nat44_user_dump()
3961         self.assertEqual(len(users), 1)
3962         self.assertEqual(str(users[0].ip_address),
3963                          self.pg0.remote_ip4)
3964         sessions = self.vapi.nat44_user_session_dump(users[0].ip_address,
3965                                                      users[0].vrf_id)
3966         self.assertEqual(len(sessions), 1)
3967         session = sessions[0]
3968         self.assertEqual(session.total_bytes, 1024)
3969         self.assertEqual(session.total_pkts, 2)
3970         stats = self.statistics.get_counter('/nat44/ha/refresh-event-recv')
3971         self.assertEqual(stats[0][0], 1)
3972
3973         stats = self.statistics.get_err_counter('/err/nat-ha/pkts-processed')
3974         self.assertEqual(stats, 3)
3975
3976         # send packet to test session created by HA
3977         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
3978              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
3979              TCP(sport=self.tcp_external_port, dport=self.tcp_port_out))
3980         self.pg1.add_stream(p)
3981         self.pg_enable_capture(self.pg_interfaces)
3982         self.pg_start()
3983         capture = self.pg0.get_capture(1)
3984         p = capture[0]
3985         try:
3986             ip = p[IP]
3987             tcp = p[TCP]
3988         except IndexError:
3989             self.logger.error(ppp("Invalid packet:", p))
3990             raise
3991         else:
3992             self.assertEqual(ip.src, self.pg1.remote_ip4)
3993             self.assertEqual(ip.dst, self.pg0.remote_ip4)
3994             self.assertEqual(tcp.sport, self.tcp_external_port)
3995             self.assertEqual(tcp.dport, self.tcp_port_in)
3996
3997     def show_commands_at_teardown(self):
3998         self.logger.info(self.vapi.cli("show nat44 addresses"))
3999         self.logger.info(self.vapi.cli("show nat44 interfaces"))
4000         self.logger.info(self.vapi.cli("show nat44 static mappings"))
4001         self.logger.info(self.vapi.cli("show nat44 interface address"))
4002         self.logger.info(self.vapi.cli("show nat44 sessions detail"))
4003         self.logger.info(self.vapi.cli("show nat44 hash tables detail"))
4004         self.logger.info(self.vapi.cli("show nat timeouts"))
4005         self.logger.info(
4006             self.vapi.cli("show nat addr-port-assignment-alg"))
4007         self.logger.info(self.vapi.cli("show nat ha"))
4008
4009
4010 class TestNAT44EndpointDependent2(MethodHolder):
4011     """ Endpoint-Dependent mapping and filtering test cases """
4012
4013     @classmethod
4014     def tearDownClass(cls):
4015         super(TestNAT44EndpointDependent2, cls).tearDownClass()
4016
4017     def tearDown(self):
4018         super(TestNAT44EndpointDependent2, self).tearDown()
4019
4020     @classmethod
4021     def create_and_add_ip4_table(cls, i, table_id):
4022         cls.vapi.ip_table_add_del(is_add=1, table={'table_id': table_id})
4023         i.set_table_ip4(table_id)
4024
4025     @classmethod
4026     def setUpClass(cls):
4027         super(TestNAT44EndpointDependent2, cls).setUpClass()
4028
4029         cls.create_pg_interfaces(range(3))
4030         cls.interfaces = list(cls.pg_interfaces)
4031
4032         cls.create_and_add_ip4_table(cls.pg1, 10)
4033
4034         for i in cls.interfaces:
4035             i.admin_up()
4036             i.config_ip4()
4037             i.resolve_arp()
4038
4039             i.generate_remote_hosts(1)
4040             i.configure_ipv4_neighbors()
4041
4042     def setUp(self):
4043         super(TestNAT44EndpointDependent2, self).setUp()
4044         flags = self.nat44_config_flags.NAT44_IS_ENDPOINT_DEPENDENT
4045         self.vapi.nat44_plugin_enable_disable(enable=1, flags=flags)
4046
4047     def tearDown(self):
4048         super(TestNAT44EndpointDependent2, self).tearDown()
4049         if not self.vpp_dead:
4050             self.vapi.nat44_plugin_enable_disable(enable=0)
4051             self.vapi.cli("clear logging")
4052
4053     def nat_add_inside_interface(self, i):
4054         self.vapi.nat44_interface_add_del_feature(
4055             flags=self.config_flags.NAT_IS_INSIDE,
4056             sw_if_index=i.sw_if_index, is_add=1)
4057
4058     def nat_add_outside_interface(self, i):
4059         self.vapi.nat44_interface_add_del_feature(
4060             flags=self.config_flags.NAT_IS_OUTSIDE,
4061             sw_if_index=i.sw_if_index, is_add=1)
4062
4063     def nat_add_interface_address(self, i):
4064         self.nat_addr = i.local_ip4
4065         self.vapi.nat44_add_del_interface_addr(
4066             sw_if_index=i.sw_if_index, is_add=1)
4067
4068     def nat_add_address(self, address, vrf_id=0xFFFFFFFF):
4069         self.nat_addr = address
4070         self.nat44_add_address(address, vrf_id=vrf_id)
4071
4072     def cli(self, command):
4073         result = self.vapi.cli(command)
4074         self.logger.info(result)
4075         # print(result)
4076
4077     def show_configuration(self):
4078         self.cli("show interface")
4079         self.cli("show interface address")
4080         self.cli("show nat44 addresses")
4081         self.cli("show nat44 interfaces")
4082
4083     def create_tcp_stream(self, in_if, out_if, count):
4084         """
4085         Create tcp packet stream
4086
4087         :param in_if: Inside interface
4088         :param out_if: Outside interface
4089         :param count: count of packets to generate
4090         """
4091         pkts = []
4092         port = 6303
4093
4094         for i in range(count):
4095             p = (Ether(dst=in_if.local_mac, src=in_if.remote_mac) /
4096                  IP(src=in_if.remote_ip4, dst=out_if.remote_ip4, ttl=64) /
4097                  TCP(sport=port + i, dport=20))
4098             pkts.append(p)
4099
4100         return pkts
4101
4102     def test_session_limit_per_vrf(self):
4103
4104         inside = self.pg0
4105         inside_vrf10 = self.pg1
4106         outside = self.pg2
4107
4108         limit = 5
4109
4110         # 2 interfaces pg0, pg1 (vrf10, limit 1 tcp session)
4111         # non existing vrf_id makes process core dump
4112         self.vapi.nat44_set_session_limit(session_limit=limit, vrf_id=10)
4113
4114         self.nat_add_inside_interface(inside)
4115         self.nat_add_inside_interface(inside_vrf10)
4116         self.nat_add_outside_interface(outside)
4117
4118         # vrf independent
4119         self.nat_add_interface_address(outside)
4120
4121         # BUG: causing core dump - when bad vrf_id is specified
4122         # self.nat44_add_address(outside.local_ip4, vrf_id=20)
4123
4124         self.show_configuration()
4125
4126         stream = self.create_tcp_stream(inside_vrf10, outside, limit * 2)
4127         inside_vrf10.add_stream(stream)
4128
4129         self.pg_enable_capture(self.pg_interfaces)
4130         self.pg_start()
4131
4132         capture = outside.get_capture(limit)
4133
4134         stream = self.create_tcp_stream(inside, outside, limit * 2)
4135         inside.add_stream(stream)
4136
4137         self.pg_enable_capture(self.pg_interfaces)
4138         self.pg_start()
4139
4140         capture = outside.get_capture(len(stream))
4141
4142
4143 class TestNAT44EndpointDependent(MethodHolder):
4144     """ Endpoint-Dependent mapping and filtering test cases """
4145
4146     @classmethod
4147     def setUpClass(cls):
4148         super(TestNAT44EndpointDependent, cls).setUpClass()
4149         cls.vapi.cli("set log class nat level debug")
4150
4151         cls.tcp_port_in = 6303
4152         cls.tcp_port_out = 6303
4153         cls.udp_port_in = 6304
4154         cls.udp_port_out = 6304
4155         cls.icmp_id_in = 6305
4156         cls.icmp_id_out = 6305
4157         cls.nat_addr = '10.0.0.3'
4158         cls.ipfix_src_port = 4739
4159         cls.ipfix_domain_id = 1
4160         cls.tcp_external_port = 80
4161
4162         cls.create_pg_interfaces(range(9))
4163         cls.interfaces = list(cls.pg_interfaces[0:3])
4164
4165         for i in cls.interfaces:
4166             i.admin_up()
4167             i.config_ip4()
4168             i.resolve_arp()
4169
4170         cls.pg0.generate_remote_hosts(3)
4171         cls.pg0.configure_ipv4_neighbors()
4172
4173         cls.pg3.admin_up()
4174
4175         cls.pg4.generate_remote_hosts(2)
4176         cls.pg4.config_ip4()
4177         cls.vapi.sw_interface_add_del_address(
4178             sw_if_index=cls.pg4.sw_if_index,
4179             prefix="10.0.0.1/24")
4180
4181         cls.pg4.admin_up()
4182         cls.pg4.resolve_arp()
4183         cls.pg4._remote_hosts[1]._ip4 = cls.pg4._remote_hosts[0]._ip4
4184         cls.pg4.resolve_arp()
4185
4186         zero_ip4 = socket.inet_pton(socket.AF_INET, "0.0.0.0")
4187         cls.vapi.ip_table_add_del(is_add=1, table={'table_id': 1})
4188
4189         cls.pg5._local_ip4 = "10.1.1.1"
4190         cls.pg5._remote_hosts[0]._ip4 = "10.1.1.2"
4191         cls.pg5.set_table_ip4(1)
4192         cls.pg5.config_ip4()
4193         cls.pg5.admin_up()
4194         r1 = VppIpRoute(cls, cls.pg5.remote_ip4, 32,
4195                         [VppRoutePath("0.0.0.0",
4196                                       cls.pg5.sw_if_index)],
4197                         table_id=1,
4198                         register=False)
4199         r1.add_vpp_config()
4200
4201         cls.pg6._local_ip4 = "10.1.2.1"
4202         cls.pg6._remote_hosts[0]._ip4 = "10.1.2.2"
4203         cls.pg6.set_table_ip4(1)
4204         cls.pg6.config_ip4()
4205         cls.pg6.admin_up()
4206
4207         r2 = VppIpRoute(cls, cls.pg6.remote_ip4, 32,
4208                         [VppRoutePath("0.0.0.0",
4209                                       cls.pg6.sw_if_index)],
4210                         table_id=1,
4211                         register=False)
4212         r3 = VppIpRoute(cls, cls.pg6.remote_ip4, 16,
4213                         [VppRoutePath("0.0.0.0",
4214                                       0xffffffff,
4215                                       nh_table_id=1)],
4216                         table_id=0,
4217                         register=False)
4218         r4 = VppIpRoute(cls, "0.0.0.0", 0,
4219                         [VppRoutePath("0.0.0.0", 0xffffffff,
4220                                       nh_table_id=0)],
4221                         table_id=1,
4222                         register=False)
4223         r5 = VppIpRoute(cls, "0.0.0.0", 0,
4224                         [VppRoutePath(cls.pg1.local_ip4,
4225                                       cls.pg1.sw_if_index)],
4226                         register=False)
4227         r2.add_vpp_config()
4228         r3.add_vpp_config()
4229         r4.add_vpp_config()
4230         r5.add_vpp_config()
4231
4232         cls.pg5.resolve_arp()
4233         cls.pg6.resolve_arp()
4234
4235         cls.pg7.admin_up()
4236         cls.pg7.config_ip4()
4237         cls.pg7.resolve_arp()
4238         cls.pg7.generate_remote_hosts(3)
4239         cls.pg7.configure_ipv4_neighbors()
4240
4241         cls.pg8.admin_up()
4242         cls.pg8.config_ip4()
4243         cls.pg8.resolve_arp()
4244
4245     @classmethod
4246     def tearDownClass(cls):
4247         super(TestNAT44EndpointDependent, cls).tearDownClass()
4248
4249     def setUp(self):
4250         super(TestNAT44EndpointDependent, self).setUp()
4251         flags = self.nat44_config_flags.NAT44_IS_ENDPOINT_DEPENDENT
4252         self.vapi.nat44_plugin_enable_disable(enable=1, flags=flags)
4253         self.vapi.nat_set_timeouts(
4254             udp=300, tcp_established=7440,
4255             tcp_transitory=240, icmp=60)
4256
4257     def tearDown(self):
4258         super(TestNAT44EndpointDependent, self).tearDown()
4259         if not self.vpp_dead:
4260             self.vapi.nat44_plugin_enable_disable(enable=0)
4261             self.vapi.cli("clear logging")
4262
4263     def test_frag_in_order(self):
4264         """ NAT44 translate fragments arriving in order """
4265         self.nat44_add_address(self.nat_addr)
4266         flags = self.config_flags.NAT_IS_INSIDE
4267         self.vapi.nat44_interface_add_del_feature(
4268             sw_if_index=self.pg0.sw_if_index,
4269             flags=flags, is_add=1)
4270         self.vapi.nat44_interface_add_del_feature(
4271             sw_if_index=self.pg1.sw_if_index,
4272             is_add=1)
4273         self.frag_in_order(proto=IP_PROTOS.tcp, ignore_port=True)
4274         self.frag_in_order(proto=IP_PROTOS.udp, ignore_port=True)
4275         self.frag_in_order(proto=IP_PROTOS.icmp, ignore_port=True)
4276
4277     def test_frag_in_order_dont_translate(self):
4278         """ NAT44 don't translate fragments arriving in order """
4279         flags = self.config_flags.NAT_IS_INSIDE
4280         self.vapi.nat44_interface_add_del_feature(
4281             sw_if_index=self.pg0.sw_if_index,
4282             flags=flags, is_add=1)
4283         self.vapi.nat44_interface_add_del_feature(
4284             sw_if_index=self.pg1.sw_if_index,
4285             is_add=1)
4286         self.vapi.nat44_forwarding_enable_disable(enable=True)
4287         self.frag_in_order(proto=IP_PROTOS.tcp, dont_translate=True)
4288
4289     def test_frag_out_of_order(self):
4290         """ NAT44 translate fragments arriving out of order """
4291         self.nat44_add_address(self.nat_addr)
4292         flags = self.config_flags.NAT_IS_INSIDE
4293         self.vapi.nat44_interface_add_del_feature(
4294             sw_if_index=self.pg0.sw_if_index,
4295             flags=flags, is_add=1)
4296         self.vapi.nat44_interface_add_del_feature(
4297             sw_if_index=self.pg1.sw_if_index,
4298             is_add=1)
4299         self.frag_out_of_order(proto=IP_PROTOS.tcp, ignore_port=True)
4300         self.frag_out_of_order(proto=IP_PROTOS.udp, ignore_port=True)
4301         self.frag_out_of_order(proto=IP_PROTOS.icmp, ignore_port=True)
4302
4303     def test_frag_out_of_order_dont_translate(self):
4304         """ NAT44 don't translate fragments arriving out of order """
4305         flags = self.config_flags.NAT_IS_INSIDE
4306         self.vapi.nat44_interface_add_del_feature(
4307             sw_if_index=self.pg0.sw_if_index,
4308             flags=flags, is_add=1)
4309         self.vapi.nat44_interface_add_del_feature(
4310             sw_if_index=self.pg1.sw_if_index,
4311             is_add=1)
4312         self.vapi.nat44_forwarding_enable_disable(enable=True)
4313         self.frag_out_of_order(proto=IP_PROTOS.tcp, dont_translate=True)
4314
4315     def test_frag_in_order_in_plus_out(self):
4316         """ in+out interface fragments in order """
4317         flags = self.config_flags.NAT_IS_INSIDE
4318         self.vapi.nat44_interface_add_del_feature(
4319             sw_if_index=self.pg0.sw_if_index,
4320             is_add=1)
4321         self.vapi.nat44_interface_add_del_feature(
4322             sw_if_index=self.pg0.sw_if_index,
4323             flags=flags, is_add=1)
4324         self.vapi.nat44_interface_add_del_feature(
4325             sw_if_index=self.pg1.sw_if_index,
4326             is_add=1)
4327         self.vapi.nat44_interface_add_del_feature(
4328             sw_if_index=self.pg1.sw_if_index,
4329             flags=flags, is_add=1)
4330
4331         self.server = self.pg1.remote_hosts[0]
4332
4333         self.server_in_addr = self.server.ip4
4334         self.server_out_addr = '11.11.11.11'
4335         self.server_in_port = random.randint(1025, 65535)
4336         self.server_out_port = random.randint(1025, 65535)
4337
4338         self.nat44_add_address(self.server_out_addr)
4339
4340         # add static mappings for server
4341         self.nat44_add_static_mapping(self.server_in_addr,
4342                                       self.server_out_addr,
4343                                       self.server_in_port,
4344                                       self.server_out_port,
4345                                       proto=IP_PROTOS.tcp)
4346         self.nat44_add_static_mapping(self.server_in_addr,
4347                                       self.server_out_addr,
4348                                       self.server_in_port,
4349                                       self.server_out_port,
4350                                       proto=IP_PROTOS.udp)
4351         self.nat44_add_static_mapping(self.server_in_addr,
4352                                       self.server_out_addr,
4353                                       proto=IP_PROTOS.icmp)
4354
4355         self.frag_in_order_in_plus_out(proto=IP_PROTOS.tcp)
4356         self.frag_in_order_in_plus_out(proto=IP_PROTOS.udp)
4357         self.frag_in_order_in_plus_out(proto=IP_PROTOS.icmp)
4358
4359     def test_frag_out_of_order_in_plus_out(self):
4360         """ in+out interface fragments out of order """
4361         flags = self.config_flags.NAT_IS_INSIDE
4362         self.vapi.nat44_interface_add_del_feature(
4363             sw_if_index=self.pg0.sw_if_index,
4364             is_add=1)
4365         self.vapi.nat44_interface_add_del_feature(
4366             sw_if_index=self.pg0.sw_if_index,
4367             flags=flags, is_add=1)
4368         self.vapi.nat44_interface_add_del_feature(
4369             sw_if_index=self.pg1.sw_if_index,
4370             is_add=1)
4371         self.vapi.nat44_interface_add_del_feature(
4372             sw_if_index=self.pg1.sw_if_index,
4373             flags=flags, is_add=1)
4374
4375         self.server = self.pg1.remote_hosts[0]
4376
4377         self.server_in_addr = self.server.ip4
4378         self.server_out_addr = '11.11.11.11'
4379         self.server_in_port = random.randint(1025, 65535)
4380         self.server_out_port = random.randint(1025, 65535)
4381
4382         self.nat44_add_address(self.server_out_addr)
4383
4384         # add static mappings for server
4385         self.nat44_add_static_mapping(self.server_in_addr,
4386                                       self.server_out_addr,
4387                                       self.server_in_port,
4388                                       self.server_out_port,
4389                                       proto=IP_PROTOS.tcp)
4390         self.nat44_add_static_mapping(self.server_in_addr,
4391                                       self.server_out_addr,
4392                                       self.server_in_port,
4393                                       self.server_out_port,
4394                                       proto=IP_PROTOS.udp)
4395         self.nat44_add_static_mapping(self.server_in_addr,
4396                                       self.server_out_addr,
4397                                       proto=IP_PROTOS.icmp)
4398
4399         self.frag_out_of_order_in_plus_out(proto=IP_PROTOS.tcp)
4400         self.frag_out_of_order_in_plus_out(proto=IP_PROTOS.udp)
4401         self.frag_out_of_order_in_plus_out(proto=IP_PROTOS.icmp)
4402
4403     def test_reass_hairpinning(self):
4404         """ NAT44 fragments hairpinning """
4405         self.server = self.pg0.remote_hosts[1]
4406         self.host_in_port = random.randint(1025, 65535)
4407         self.server_in_port = random.randint(1025, 65535)
4408         self.server_out_port = random.randint(1025, 65535)
4409
4410         self.nat44_add_address(self.nat_addr)
4411         flags = self.config_flags.NAT_IS_INSIDE
4412         self.vapi.nat44_interface_add_del_feature(
4413             sw_if_index=self.pg0.sw_if_index,
4414             flags=flags, is_add=1)
4415         self.vapi.nat44_interface_add_del_feature(
4416             sw_if_index=self.pg1.sw_if_index,
4417             is_add=1)
4418         # add static mapping for server
4419         self.nat44_add_static_mapping(self.server.ip4, self.nat_addr,
4420                                       self.server_in_port,
4421                                       self.server_out_port,
4422                                       proto=IP_PROTOS.tcp)
4423         self.nat44_add_static_mapping(self.server.ip4, self.nat_addr,
4424                                       self.server_in_port,
4425                                       self.server_out_port,
4426                                       proto=IP_PROTOS.udp)
4427         self.nat44_add_static_mapping(self.server.ip4, self.nat_addr)
4428
4429         self.reass_hairpinning(proto=IP_PROTOS.tcp, ignore_port=True)
4430         self.reass_hairpinning(proto=IP_PROTOS.udp, ignore_port=True)
4431         self.reass_hairpinning(proto=IP_PROTOS.icmp, ignore_port=True)
4432
4433     def test_clear_sessions(self):
4434         """ NAT44 ED session clearing test """
4435
4436         self.nat44_add_address(self.nat_addr)
4437         flags = self.config_flags.NAT_IS_INSIDE
4438         self.vapi.nat44_interface_add_del_feature(
4439             sw_if_index=self.pg0.sw_if_index,
4440             flags=flags, is_add=1)
4441         self.vapi.nat44_interface_add_del_feature(
4442             sw_if_index=self.pg1.sw_if_index,
4443             is_add=1)
4444
4445         nat_config = self.vapi.nat_show_config()
4446         self.assertEqual(1, nat_config.endpoint_dependent)
4447
4448         pkts = self.create_stream_in(self.pg0, self.pg1)
4449         self.pg0.add_stream(pkts)
4450         self.pg_enable_capture(self.pg_interfaces)
4451         self.pg_start()
4452         capture = self.pg1.get_capture(len(pkts))
4453         self.verify_capture_out(capture, ignore_port=True)
4454
4455         sessions = self.statistics.get_counter('/nat44/total-sessions')
4456         self.assertTrue(sessions[0][0] > 0)
4457         self.logger.info("sessions before clearing: %s" % sessions[0][0])
4458
4459         # just for testing purposes
4460         self.logger.info(self.vapi.cli("show nat44 summary"))
4461
4462         self.vapi.cli("clear nat44 sessions")
4463
4464         self.logger.info(self.vapi.cli("show nat44 summary"))
4465
4466         sessions = self.statistics.get_counter('/nat44/total-sessions')
4467         self.assertEqual(sessions[0][0], 0)
4468         self.logger.info("sessions after clearing: %s" % sessions[0][0])
4469
4470     def test_dynamic(self):
4471         """ NAT44 dynamic translation test """
4472
4473         self.nat44_add_address(self.nat_addr)
4474         flags = self.config_flags.NAT_IS_INSIDE
4475         self.vapi.nat44_interface_add_del_feature(
4476             sw_if_index=self.pg0.sw_if_index,
4477             flags=flags, is_add=1)
4478         self.vapi.nat44_interface_add_del_feature(
4479             sw_if_index=self.pg1.sw_if_index,
4480             is_add=1)
4481
4482         nat_config = self.vapi.nat_show_config()
4483         self.assertEqual(1, nat_config.endpoint_dependent)
4484
4485         # in2out
4486         tcpn = self.statistics.get_counter('/nat44/ed/in2out/slowpath/tcp')[0]
4487         udpn = self.statistics.get_counter('/nat44/ed/in2out/slowpath/udp')[0]
4488         icmpn = self.statistics.get_counter(
4489             '/nat44/ed/in2out/slowpath/icmp')[0]
4490         drops = self.statistics.get_counter(
4491             '/nat44/ed/in2out/slowpath/drops')[0]
4492
4493         pkts = self.create_stream_in(self.pg0, self.pg1)
4494         self.pg0.add_stream(pkts)
4495         self.pg_enable_capture(self.pg_interfaces)
4496         self.pg_start()
4497         capture = self.pg1.get_capture(len(pkts))
4498         self.verify_capture_out(capture, ignore_port=True)
4499
4500         if_idx = self.pg0.sw_if_index
4501         cnt = self.statistics.get_counter('/nat44/ed/in2out/slowpath/tcp')[0]
4502         self.assertEqual(cnt[if_idx] - tcpn[if_idx], 2)
4503         cnt = self.statistics.get_counter('/nat44/ed/in2out/slowpath/udp')[0]
4504         self.assertEqual(cnt[if_idx] - udpn[if_idx], 1)
4505         cnt = self.statistics.get_counter('/nat44/ed/in2out/slowpath/icmp')[0]
4506         self.assertEqual(cnt[if_idx] - icmpn[if_idx], 1)
4507         cnt = self.statistics.get_counter('/nat44/ed/in2out/slowpath/drops')[0]
4508         self.assertEqual(cnt[if_idx] - drops[if_idx], 0)
4509
4510         # out2in
4511         tcpn = self.statistics.get_counter('/nat44/ed/out2in/fastpath/tcp')[0]
4512         udpn = self.statistics.get_counter('/nat44/ed/out2in/fastpath/udp')[0]
4513         icmpn = self.statistics.get_counter(
4514             '/nat44/ed/out2in/slowpath/icmp')[0]
4515         drops = self.statistics.get_counter(
4516             '/nat44/ed/out2in/fastpath/drops')[0]
4517
4518         pkts = self.create_stream_out(self.pg1)
4519         self.pg1.add_stream(pkts)
4520         self.pg_enable_capture(self.pg_interfaces)
4521         self.pg_start()
4522         capture = self.pg0.get_capture(len(pkts))
4523         self.verify_capture_in(capture, self.pg0)
4524
4525         if_idx = self.pg1.sw_if_index
4526         cnt = self.statistics.get_counter('/nat44/ed/out2in/fastpath/tcp')[0]
4527         self.assertEqual(cnt[if_idx] - tcpn[if_idx], 2)
4528         cnt = self.statistics.get_counter('/nat44/ed/out2in/fastpath/udp')[0]
4529         self.assertEqual(cnt[if_idx] - udpn[if_idx], 1)
4530         cnt = self.statistics.get_counter('/nat44/ed/out2in/slowpath/icmp')[0]
4531         self.assertEqual(cnt[if_idx] - icmpn[if_idx], 1)
4532         cnt = self.statistics.get_counter('/nat44/ed/out2in/fastpath/drops')[0]
4533         self.assertEqual(cnt[if_idx] - drops[if_idx], 0)
4534
4535         sessions = self.statistics.get_counter('/nat44/total-sessions')
4536         self.assertEqual(sessions[0][0], 3)
4537
4538     def test_dynamic_out_of_ports(self):
4539         """ NAT44 dynamic translation test: out of ports """
4540
4541         flags = self.config_flags.NAT_IS_INSIDE
4542         self.vapi.nat44_interface_add_del_feature(
4543             sw_if_index=self.pg0.sw_if_index,
4544             flags=flags, is_add=1)
4545         self.vapi.nat44_interface_add_del_feature(
4546             sw_if_index=self.pg1.sw_if_index,
4547             is_add=1)
4548
4549         nat_config = self.vapi.nat_show_config()
4550         self.assertEqual(1, nat_config.endpoint_dependent)
4551
4552         # in2out and no NAT addresses added
4553         err_old = self.statistics.get_err_counter(
4554             '/err/nat44-ed-in2out-slowpath/out of ports')
4555
4556         pkts = self.create_stream_in(self.pg0, self.pg1)
4557         self.pg0.add_stream(pkts)
4558         self.pg_enable_capture(self.pg_interfaces)
4559         self.pg_start()
4560         self.pg1.get_capture(0, timeout=1)
4561
4562         err_new = self.statistics.get_err_counter(
4563             '/err/nat44-ed-in2out-slowpath/out of ports')
4564
4565         self.assertEqual(err_new - err_old, len(pkts))
4566
4567         # in2out after NAT addresses added
4568         self.nat44_add_address(self.nat_addr)
4569
4570         err_old = self.statistics.get_err_counter(
4571             '/err/nat44-ed-in2out-slowpath/out of ports')
4572
4573         pkts = self.create_stream_in(self.pg0, self.pg1)
4574         self.pg0.add_stream(pkts)
4575         self.pg_enable_capture(self.pg_interfaces)
4576         self.pg_start()
4577         capture = self.pg1.get_capture(len(pkts))
4578         self.verify_capture_out(capture, ignore_port=True)
4579
4580         err_new = self.statistics.get_err_counter(
4581             '/err/nat44-ed-in2out-slowpath/out of ports')
4582
4583         self.assertEqual(err_new, err_old)
4584
4585     def test_dynamic_output_feature_vrf(self):
4586         """ NAT44 dynamic translation test: output-feature, VRF"""
4587
4588         # other then default (0)
4589         new_vrf_id = 22
4590
4591         self.nat44_add_address(self.nat_addr)
4592         flags = self.config_flags.NAT_IS_INSIDE
4593         self.vapi.nat44_interface_add_del_output_feature(
4594             sw_if_index=self.pg7.sw_if_index,
4595             flags=flags, is_add=1)
4596         self.vapi.nat44_interface_add_del_output_feature(
4597             sw_if_index=self.pg8.sw_if_index,
4598             is_add=1)
4599
4600         try:
4601             self.vapi.ip_table_add_del(is_add=1,
4602                                        table={'table_id': new_vrf_id})
4603
4604             self.pg7.unconfig_ip4()
4605             self.pg7.set_table_ip4(new_vrf_id)
4606             self.pg7.config_ip4()
4607             self.pg7.resolve_arp()
4608
4609             self.pg8.unconfig_ip4()
4610             self.pg8.set_table_ip4(new_vrf_id)
4611             self.pg8.config_ip4()
4612             self.pg8.resolve_arp()
4613
4614             nat_config = self.vapi.nat_show_config()
4615             self.assertEqual(1, nat_config.endpoint_dependent)
4616
4617             # in2out
4618             tcpn = self.statistics.get_counter(
4619                 '/nat44/ed/in2out/slowpath/tcp')[0]
4620             udpn = self.statistics.get_counter(
4621                 '/nat44/ed/in2out/slowpath/udp')[0]
4622             icmpn = self.statistics.get_counter(
4623                 '/nat44/ed/in2out/slowpath/icmp')[0]
4624             drops = self.statistics.get_counter(
4625                 '/nat44/ed/in2out/slowpath/drops')[0]
4626
4627             pkts = self.create_stream_in(self.pg7, self.pg8)
4628             self.pg7.add_stream(pkts)
4629             self.pg_enable_capture(self.pg_interfaces)
4630             self.pg_start()
4631             capture = self.pg8.get_capture(len(pkts))
4632             self.verify_capture_out(capture, ignore_port=True)
4633
4634             if_idx = self.pg7.sw_if_index
4635             cnt = self.statistics.get_counter(
4636                 '/nat44/ed/in2out/slowpath/tcp')[0]
4637             self.assertEqual(cnt[if_idx] - tcpn[if_idx], 2)
4638             cnt = self.statistics.get_counter(
4639                 '/nat44/ed/in2out/slowpath/udp')[0]
4640             self.assertEqual(cnt[if_idx] - udpn[if_idx], 1)
4641             cnt = self.statistics.get_counter(
4642                 '/nat44/ed/in2out/slowpath/icmp')[0]
4643             self.assertEqual(cnt[if_idx] - icmpn[if_idx], 1)
4644             cnt = self.statistics.get_counter(
4645                 '/nat44/ed/in2out/slowpath/drops')[0]
4646             self.assertEqual(cnt[if_idx] - drops[if_idx], 0)
4647
4648             # out2in
4649             tcpn = self.statistics.get_counter(
4650                 '/nat44/ed/out2in/fastpath/tcp')[0]
4651             udpn = self.statistics.get_counter(
4652                 '/nat44/ed/out2in/fastpath/udp')[0]
4653             icmpn = self.statistics.get_counter(
4654                 '/nat44/ed/out2in/slowpath/icmp')[0]
4655             drops = self.statistics.get_counter(
4656                 '/nat44/ed/out2in/fastpath/drops')[0]
4657
4658             pkts = self.create_stream_out(self.pg8)
4659             self.pg8.add_stream(pkts)
4660             self.pg_enable_capture(self.pg_interfaces)
4661             self.pg_start()
4662             capture = self.pg7.get_capture(len(pkts))
4663             self.verify_capture_in(capture, self.pg7)
4664
4665             if_idx = self.pg8.sw_if_index
4666             cnt = self.statistics.get_counter(
4667                 '/nat44/ed/out2in/fastpath/tcp')[0]
4668             self.assertEqual(cnt[if_idx] - tcpn[if_idx], 2)
4669             cnt = self.statistics.get_counter(
4670                 '/nat44/ed/out2in/fastpath/udp')[0]
4671             self.assertEqual(cnt[if_idx] - udpn[if_idx], 1)
4672             cnt = self.statistics.get_counter(
4673                 '/nat44/ed/out2in/slowpath/icmp')[0]
4674             self.assertEqual(cnt[if_idx] - icmpn[if_idx], 1)
4675             cnt = self.statistics.get_counter(
4676                 '/nat44/ed/out2in/fastpath/drops')[0]
4677             self.assertEqual(cnt[if_idx] - drops[if_idx], 0)
4678
4679             sessions = self.statistics.get_counter('/nat44/total-sessions')
4680             self.assertEqual(sessions[0][0], 3)
4681
4682         finally:
4683             self.pg7.unconfig_ip4()
4684             self.pg7.set_table_ip4(1)
4685             self.pg7.config_ip4()
4686             self.pg7.resolve_arp()
4687
4688             self.pg8.unconfig_ip4()
4689             self.pg8.set_table_ip4(1)
4690             self.pg8.config_ip4()
4691             self.pg8.resolve_arp()
4692
4693             self.vapi.ip_table_add_del(is_add=0,
4694                                        table={'table_id': new_vrf_id})
4695
4696     def test_forwarding(self):
4697         """ NAT44 forwarding test """
4698
4699         flags = self.config_flags.NAT_IS_INSIDE
4700         self.vapi.nat44_interface_add_del_feature(
4701             sw_if_index=self.pg0.sw_if_index,
4702             flags=flags, is_add=1)
4703         self.vapi.nat44_interface_add_del_feature(
4704             sw_if_index=self.pg1.sw_if_index,
4705             is_add=1)
4706         self.vapi.nat44_forwarding_enable_disable(enable=1)
4707
4708         real_ip = self.pg0.remote_ip4
4709         alias_ip = self.nat_addr
4710         flags = self.config_flags.NAT_IS_ADDR_ONLY
4711         self.vapi.nat44_add_del_static_mapping(is_add=1,
4712                                                local_ip_address=real_ip,
4713                                                external_ip_address=alias_ip,
4714                                                external_sw_if_index=0xFFFFFFFF,
4715                                                flags=flags)
4716
4717         try:
4718             # in2out - static mapping match
4719
4720             pkts = self.create_stream_out(self.pg1)
4721             self.pg1.add_stream(pkts)
4722             self.pg_enable_capture(self.pg_interfaces)
4723             self.pg_start()
4724             capture = self.pg0.get_capture(len(pkts))
4725             self.verify_capture_in(capture, self.pg0)
4726
4727             pkts = self.create_stream_in(self.pg0, self.pg1)
4728             self.pg0.add_stream(pkts)
4729             self.pg_enable_capture(self.pg_interfaces)
4730             self.pg_start()
4731             capture = self.pg1.get_capture(len(pkts))
4732             self.verify_capture_out(capture, same_port=True)
4733
4734             # in2out - no static mapping match
4735
4736             host0 = self.pg0.remote_hosts[0]
4737             self.pg0.remote_hosts[0] = self.pg0.remote_hosts[1]
4738             try:
4739                 pkts = self.create_stream_out(self.pg1,
4740                                               dst_ip=self.pg0.remote_ip4,
4741                                               use_inside_ports=True)
4742                 self.pg1.add_stream(pkts)
4743                 self.pg_enable_capture(self.pg_interfaces)
4744                 self.pg_start()
4745                 capture = self.pg0.get_capture(len(pkts))
4746                 self.verify_capture_in(capture, self.pg0)
4747
4748                 pkts = self.create_stream_in(self.pg0, self.pg1)
4749                 self.pg0.add_stream(pkts)
4750                 self.pg_enable_capture(self.pg_interfaces)
4751                 self.pg_start()
4752                 capture = self.pg1.get_capture(len(pkts))
4753                 self.verify_capture_out(capture, nat_ip=self.pg0.remote_ip4,
4754                                         same_port=True)
4755             finally:
4756                 self.pg0.remote_hosts[0] = host0
4757
4758             user = self.pg0.remote_hosts[1]
4759             sessions = self.vapi.nat44_user_session_dump(user.ip4, 0)
4760             self.assertEqual(len(sessions), 3)
4761             self.assertTrue(sessions[0].flags &
4762                             self.config_flags.NAT_IS_EXT_HOST_VALID)
4763             self.vapi.nat44_del_session(
4764                 address=sessions[0].inside_ip_address,
4765                 port=sessions[0].inside_port,
4766                 protocol=sessions[0].protocol,
4767                 flags=(self.config_flags.NAT_IS_INSIDE |
4768                        self.config_flags.NAT_IS_EXT_HOST_VALID),
4769                 ext_host_address=sessions[0].ext_host_address,
4770                 ext_host_port=sessions[0].ext_host_port)
4771             sessions = self.vapi.nat44_user_session_dump(user.ip4, 0)
4772             self.assertEqual(len(sessions), 2)
4773
4774         finally:
4775             self.vapi.nat44_forwarding_enable_disable(enable=0)
4776             flags = self.config_flags.NAT_IS_ADDR_ONLY
4777             self.vapi.nat44_add_del_static_mapping(
4778                 is_add=0,
4779                 local_ip_address=real_ip,
4780                 external_ip_address=alias_ip,
4781                 external_sw_if_index=0xFFFFFFFF,
4782                 flags=flags)
4783
4784     def test_static_lb(self):
4785         """ NAT44 local service load balancing """
4786         external_addr_n = self.nat_addr
4787         external_port = 80
4788         local_port = 8080
4789         server1 = self.pg0.remote_hosts[0]
4790         server2 = self.pg0.remote_hosts[1]
4791
4792         locals = [{'addr': server1.ip4,
4793                    'port': local_port,
4794                    'probability': 70,
4795                    'vrf_id': 0},
4796                   {'addr': server2.ip4,
4797                    'port': local_port,
4798                    'probability': 30,
4799                    'vrf_id': 0}]
4800
4801         self.nat44_add_address(self.nat_addr)
4802         self.vapi.nat44_add_del_lb_static_mapping(
4803             is_add=1,
4804             external_addr=external_addr_n,
4805             external_port=external_port,
4806             protocol=IP_PROTOS.tcp,
4807             local_num=len(locals),
4808             locals=locals)
4809         flags = self.config_flags.NAT_IS_INSIDE
4810         self.vapi.nat44_interface_add_del_feature(
4811             sw_if_index=self.pg0.sw_if_index,
4812             flags=flags, is_add=1)
4813         self.vapi.nat44_interface_add_del_feature(
4814             sw_if_index=self.pg1.sw_if_index,
4815             is_add=1)
4816
4817         # from client to service
4818         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
4819              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
4820              TCP(sport=12345, dport=external_port))
4821         self.pg1.add_stream(p)
4822         self.pg_enable_capture(self.pg_interfaces)
4823         self.pg_start()
4824         capture = self.pg0.get_capture(1)
4825         p = capture[0]
4826         server = None
4827         try:
4828             ip = p[IP]
4829             tcp = p[TCP]
4830             self.assertIn(ip.dst, [server1.ip4, server2.ip4])
4831             if ip.dst == server1.ip4:
4832                 server = server1
4833             else:
4834                 server = server2
4835             self.assertEqual(tcp.dport, local_port)
4836             self.assert_packet_checksums_valid(p)
4837         except:
4838             self.logger.error(ppp("Unexpected or invalid packet:", p))
4839             raise
4840
4841         # from service back to client
4842         p = (Ether(src=server.mac, dst=self.pg0.local_mac) /
4843              IP(src=server.ip4, dst=self.pg1.remote_ip4) /
4844              TCP(sport=local_port, dport=12345))
4845         self.pg0.add_stream(p)
4846         self.pg_enable_capture(self.pg_interfaces)
4847         self.pg_start()
4848         capture = self.pg1.get_capture(1)
4849         p = capture[0]
4850         try:
4851             ip = p[IP]
4852             tcp = p[TCP]
4853             self.assertEqual(ip.src, self.nat_addr)
4854             self.assertEqual(tcp.sport, external_port)
4855             self.assert_packet_checksums_valid(p)
4856         except:
4857             self.logger.error(ppp("Unexpected or invalid packet:", p))
4858             raise
4859
4860         sessions = self.vapi.nat44_user_session_dump(server.ip4, 0)
4861         self.assertEqual(len(sessions), 1)
4862         self.assertTrue(sessions[0].flags &
4863                         self.config_flags.NAT_IS_EXT_HOST_VALID)
4864         self.vapi.nat44_del_session(
4865             address=sessions[0].inside_ip_address,
4866             port=sessions[0].inside_port,
4867             protocol=sessions[0].protocol,
4868             flags=(self.config_flags.NAT_IS_INSIDE |
4869                    self.config_flags.NAT_IS_EXT_HOST_VALID),
4870             ext_host_address=sessions[0].ext_host_address,
4871             ext_host_port=sessions[0].ext_host_port)
4872         sessions = self.vapi.nat44_user_session_dump(server.ip4, 0)
4873         self.assertEqual(len(sessions), 0)
4874
4875     @unittest.skipUnless(running_extended_tests, "part of extended tests")
4876     def test_static_lb_multi_clients(self):
4877         """ NAT44 local service load balancing - multiple clients"""
4878
4879         external_addr = self.nat_addr
4880         external_port = 80
4881         local_port = 8080
4882         server1 = self.pg0.remote_hosts[0]
4883         server2 = self.pg0.remote_hosts[1]
4884         server3 = self.pg0.remote_hosts[2]
4885
4886         locals = [{'addr': server1.ip4,
4887                    'port': local_port,
4888                    'probability': 90,
4889                    'vrf_id': 0},
4890                   {'addr': server2.ip4,
4891                    'port': local_port,
4892                    'probability': 10,
4893                    'vrf_id': 0}]
4894
4895         self.nat44_add_address(self.nat_addr)
4896         self.vapi.nat44_add_del_lb_static_mapping(is_add=1,
4897                                                   external_addr=external_addr,
4898                                                   external_port=external_port,
4899                                                   protocol=IP_PROTOS.tcp,
4900                                                   local_num=len(locals),
4901                                                   locals=locals)
4902         flags = self.config_flags.NAT_IS_INSIDE
4903         self.vapi.nat44_interface_add_del_feature(
4904             sw_if_index=self.pg0.sw_if_index,
4905             flags=flags, is_add=1)
4906         self.vapi.nat44_interface_add_del_feature(
4907             sw_if_index=self.pg1.sw_if_index,
4908             is_add=1)
4909
4910         server1_n = 0
4911         server2_n = 0
4912         clients = ip4_range(self.pg1.remote_ip4, 10, 50)
4913         pkts = []
4914         for client in clients:
4915             p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
4916                  IP(src=client, dst=self.nat_addr) /
4917                  TCP(sport=12345, dport=external_port))
4918             pkts.append(p)
4919         self.pg1.add_stream(pkts)
4920         self.pg_enable_capture(self.pg_interfaces)
4921         self.pg_start()
4922         capture = self.pg0.get_capture(len(pkts))
4923         for p in capture:
4924             if p[IP].dst == server1.ip4:
4925                 server1_n += 1
4926             else:
4927                 server2_n += 1
4928         self.assertGreater(server1_n, server2_n)
4929
4930         local = {
4931             'addr': server3.ip4,
4932             'port': local_port,
4933             'probability': 20,
4934             'vrf_id': 0
4935         }
4936
4937         # add new back-end
4938         self.vapi.nat44_lb_static_mapping_add_del_local(
4939             is_add=1,
4940             external_addr=external_addr,
4941             external_port=external_port,
4942             local=local,
4943             protocol=IP_PROTOS.tcp)
4944         server1_n = 0
4945         server2_n = 0
4946         server3_n = 0
4947         clients = ip4_range(self.pg1.remote_ip4, 60, 110)
4948         pkts = []
4949         for client in clients:
4950             p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
4951                  IP(src=client, dst=self.nat_addr) /
4952                  TCP(sport=12346, dport=external_port))
4953             pkts.append(p)
4954         self.assertGreater(len(pkts), 0)
4955         self.pg1.add_stream(pkts)
4956         self.pg_enable_capture(self.pg_interfaces)
4957         self.pg_start()
4958         capture = self.pg0.get_capture(len(pkts))
4959         for p in capture:
4960             if p[IP].dst == server1.ip4:
4961                 server1_n += 1
4962             elif p[IP].dst == server2.ip4:
4963                 server2_n += 1
4964             else:
4965                 server3_n += 1
4966         self.assertGreater(server1_n, 0)
4967         self.assertGreater(server2_n, 0)
4968         self.assertGreater(server3_n, 0)
4969
4970         local = {
4971             'addr': server2.ip4,
4972             'port': local_port,
4973             'probability': 10,
4974             'vrf_id': 0
4975         }
4976
4977         # remove one back-end
4978         self.vapi.nat44_lb_static_mapping_add_del_local(
4979             is_add=0,
4980             external_addr=external_addr,
4981             external_port=external_port,
4982             local=local,
4983             protocol=IP_PROTOS.tcp)
4984         server1_n = 0
4985         server2_n = 0
4986         server3_n = 0
4987         self.pg1.add_stream(pkts)
4988         self.pg_enable_capture(self.pg_interfaces)
4989         self.pg_start()
4990         capture = self.pg0.get_capture(len(pkts))
4991         for p in capture:
4992             if p[IP].dst == server1.ip4:
4993                 server1_n += 1
4994             elif p[IP].dst == server2.ip4:
4995                 server2_n += 1
4996             else:
4997                 server3_n += 1
4998         self.assertGreater(server1_n, 0)
4999         self.assertEqual(server2_n, 0)
5000         self.assertGreater(server3_n, 0)
5001
5002     def test_static_lb_2(self):
5003         """ NAT44 local service load balancing (asymmetrical rule) """
5004         external_addr = self.nat_addr
5005         external_port = 80
5006         local_port = 8080
5007         server1 = self.pg0.remote_hosts[0]
5008         server2 = self.pg0.remote_hosts[1]
5009
5010         locals = [{'addr': server1.ip4,
5011                    'port': local_port,
5012                    'probability': 70,
5013                    'vrf_id': 0},
5014                   {'addr': server2.ip4,
5015                    'port': local_port,
5016                    'probability': 30,
5017                    'vrf_id': 0}]
5018
5019         self.vapi.nat44_forwarding_enable_disable(enable=1)
5020         flags = self.config_flags.NAT_IS_OUT2IN_ONLY
5021         self.vapi.nat44_add_del_lb_static_mapping(is_add=1, flags=flags,
5022                                                   external_addr=external_addr,
5023                                                   external_port=external_port,
5024                                                   protocol=IP_PROTOS.tcp,
5025                                                   local_num=len(locals),
5026                                                   locals=locals)
5027         flags = self.config_flags.NAT_IS_INSIDE
5028         self.vapi.nat44_interface_add_del_feature(
5029             sw_if_index=self.pg0.sw_if_index,
5030             flags=flags, is_add=1)
5031         self.vapi.nat44_interface_add_del_feature(
5032             sw_if_index=self.pg1.sw_if_index,
5033             is_add=1)
5034
5035         # from client to service
5036         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
5037              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
5038              TCP(sport=12345, dport=external_port))
5039         self.pg1.add_stream(p)
5040         self.pg_enable_capture(self.pg_interfaces)
5041         self.pg_start()
5042         capture = self.pg0.get_capture(1)
5043         p = capture[0]
5044         server = None
5045         try:
5046             ip = p[IP]
5047             tcp = p[TCP]
5048             self.assertIn(ip.dst, [server1.ip4, server2.ip4])
5049             if ip.dst == server1.ip4:
5050                 server = server1
5051             else:
5052                 server = server2
5053             self.assertEqual(tcp.dport, local_port)
5054             self.assert_packet_checksums_valid(p)
5055         except:
5056             self.logger.error(ppp("Unexpected or invalid packet:", p))
5057             raise
5058
5059         # from service back to client
5060         p = (Ether(src=server.mac, dst=self.pg0.local_mac) /
5061              IP(src=server.ip4, dst=self.pg1.remote_ip4) /
5062              TCP(sport=local_port, dport=12345))
5063         self.pg0.add_stream(p)
5064         self.pg_enable_capture(self.pg_interfaces)
5065         self.pg_start()
5066         capture = self.pg1.get_capture(1)
5067         p = capture[0]
5068         try:
5069             ip = p[IP]
5070             tcp = p[TCP]
5071             self.assertEqual(ip.src, self.nat_addr)
5072             self.assertEqual(tcp.sport, external_port)
5073             self.assert_packet_checksums_valid(p)
5074         except:
5075             self.logger.error(ppp("Unexpected or invalid packet:", p))
5076             raise
5077
5078         # from client to server (no translation)
5079         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
5080              IP(src=self.pg1.remote_ip4, dst=server1.ip4) /
5081              TCP(sport=12346, dport=local_port))
5082         self.pg1.add_stream(p)
5083         self.pg_enable_capture(self.pg_interfaces)
5084         self.pg_start()
5085         capture = self.pg0.get_capture(1)
5086         p = capture[0]
5087         server = None
5088         try:
5089             ip = p[IP]
5090             tcp = p[TCP]
5091             self.assertEqual(ip.dst, server1.ip4)
5092             self.assertEqual(tcp.dport, local_port)
5093             self.assert_packet_checksums_valid(p)
5094         except:
5095             self.logger.error(ppp("Unexpected or invalid packet:", p))
5096             raise
5097
5098         # from service back to client (no translation)
5099         p = (Ether(src=server1.mac, dst=self.pg0.local_mac) /
5100              IP(src=server1.ip4, dst=self.pg1.remote_ip4) /
5101              TCP(sport=local_port, dport=12346))
5102         self.pg0.add_stream(p)
5103         self.pg_enable_capture(self.pg_interfaces)
5104         self.pg_start()
5105         capture = self.pg1.get_capture(1)
5106         p = capture[0]
5107         try:
5108             ip = p[IP]
5109             tcp = p[TCP]
5110             self.assertEqual(ip.src, server1.ip4)
5111             self.assertEqual(tcp.sport, local_port)
5112             self.assert_packet_checksums_valid(p)
5113         except:
5114             self.logger.error(ppp("Unexpected or invalid packet:", p))
5115             raise
5116
5117     def test_lb_affinity(self):
5118         """ NAT44 local service load balancing affinity """
5119         external_addr = self.nat_addr
5120         external_port = 80
5121         local_port = 8080
5122         server1 = self.pg0.remote_hosts[0]
5123         server2 = self.pg0.remote_hosts[1]
5124
5125         locals = [{'addr': server1.ip4,
5126                    'port': local_port,
5127                    'probability': 50,
5128                    'vrf_id': 0},
5129                   {'addr': server2.ip4,
5130                    'port': local_port,
5131                    'probability': 50,
5132                    'vrf_id': 0}]
5133
5134         self.nat44_add_address(self.nat_addr)
5135         self.vapi.nat44_add_del_lb_static_mapping(is_add=1,
5136                                                   external_addr=external_addr,
5137                                                   external_port=external_port,
5138                                                   protocol=IP_PROTOS.tcp,
5139                                                   affinity=10800,
5140                                                   local_num=len(locals),
5141                                                   locals=locals)
5142         flags = self.config_flags.NAT_IS_INSIDE
5143         self.vapi.nat44_interface_add_del_feature(
5144             sw_if_index=self.pg0.sw_if_index,
5145             flags=flags, is_add=1)
5146         self.vapi.nat44_interface_add_del_feature(
5147             sw_if_index=self.pg1.sw_if_index,
5148             is_add=1)
5149
5150         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
5151              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
5152              TCP(sport=1025, dport=external_port))
5153         self.pg1.add_stream(p)
5154         self.pg_enable_capture(self.pg_interfaces)
5155         self.pg_start()
5156         capture = self.pg0.get_capture(1)
5157         backend = capture[0][IP].dst
5158
5159         sessions = self.vapi.nat44_user_session_dump(backend, 0)
5160         self.assertEqual(len(sessions), 1)
5161         self.assertTrue(sessions[0].flags &
5162                         self.config_flags.NAT_IS_EXT_HOST_VALID)
5163         self.vapi.nat44_del_session(
5164             address=sessions[0].inside_ip_address,
5165             port=sessions[0].inside_port,
5166             protocol=sessions[0].protocol,
5167             flags=(self.config_flags.NAT_IS_INSIDE |
5168                    self.config_flags.NAT_IS_EXT_HOST_VALID),
5169             ext_host_address=sessions[0].ext_host_address,
5170             ext_host_port=sessions[0].ext_host_port)
5171
5172         pkts = []
5173         for port in range(1030, 1100):
5174             p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
5175                  IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
5176                  TCP(sport=port, dport=external_port))
5177             pkts.append(p)
5178         self.pg1.add_stream(pkts)
5179         self.pg_enable_capture(self.pg_interfaces)
5180         self.pg_start()
5181         capture = self.pg0.get_capture(len(pkts))
5182         for p in capture:
5183             self.assertEqual(p[IP].dst, backend)
5184
5185     def test_unknown_proto(self):
5186         """ NAT44 translate packet with unknown protocol """
5187         self.nat44_add_address(self.nat_addr)
5188         flags = self.config_flags.NAT_IS_INSIDE
5189         self.vapi.nat44_interface_add_del_feature(
5190             sw_if_index=self.pg0.sw_if_index,
5191             flags=flags, is_add=1)
5192         self.vapi.nat44_interface_add_del_feature(
5193             sw_if_index=self.pg1.sw_if_index,
5194             is_add=1)
5195
5196         # in2out
5197         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
5198              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
5199              TCP(sport=self.tcp_port_in, dport=20))
5200         self.pg0.add_stream(p)
5201         self.pg_enable_capture(self.pg_interfaces)
5202         self.pg_start()
5203         p = self.pg1.get_capture(1)
5204
5205         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
5206              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
5207              GRE() /
5208              IP(src=self.pg2.remote_ip4, dst=self.pg2.remote_ip4) /
5209              TCP(sport=1234, dport=1234))
5210         self.pg0.add_stream(p)
5211         self.pg_enable_capture(self.pg_interfaces)
5212         self.pg_start()
5213         p = self.pg1.get_capture(1)
5214         packet = p[0]
5215         try:
5216             self.assertEqual(packet[IP].src, self.nat_addr)
5217             self.assertEqual(packet[IP].dst, self.pg1.remote_ip4)
5218             self.assertEqual(packet.haslayer(GRE), 1)
5219             self.assert_packet_checksums_valid(packet)
5220         except:
5221             self.logger.error(ppp("Unexpected or invalid packet:", packet))
5222             raise
5223
5224         # out2in
5225         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
5226              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
5227              GRE() /
5228              IP(src=self.pg2.remote_ip4, dst=self.pg2.remote_ip4) /
5229              TCP(sport=1234, dport=1234))
5230         self.pg1.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.pg1.remote_ip4)
5237             self.assertEqual(packet[IP].dst, self.pg0.remote_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     def test_hairpinning_unknown_proto(self):
5245         """ NAT44 translate packet with unknown protocol - hairpinning """
5246         host = self.pg0.remote_hosts[0]
5247         server = self.pg0.remote_hosts[1]
5248         host_in_port = 1234
5249         server_out_port = 8765
5250         server_nat_ip = "10.0.0.11"
5251
5252         self.nat44_add_address(self.nat_addr)
5253         flags = self.config_flags.NAT_IS_INSIDE
5254         self.vapi.nat44_interface_add_del_feature(
5255             sw_if_index=self.pg0.sw_if_index,
5256             flags=flags, is_add=1)
5257         self.vapi.nat44_interface_add_del_feature(
5258             sw_if_index=self.pg1.sw_if_index,
5259             is_add=1)
5260
5261         # add static mapping for server
5262         self.nat44_add_static_mapping(server.ip4, server_nat_ip)
5263
5264         # host to server
5265         p = (Ether(src=host.mac, dst=self.pg0.local_mac) /
5266              IP(src=host.ip4, dst=server_nat_ip) /
5267              TCP(sport=host_in_port, dport=server_out_port))
5268         self.pg0.add_stream(p)
5269         self.pg_enable_capture(self.pg_interfaces)
5270         self.pg_start()
5271         self.pg0.get_capture(1)
5272
5273         p = (Ether(dst=self.pg0.local_mac, src=host.mac) /
5274              IP(src=host.ip4, dst=server_nat_ip) /
5275              GRE() /
5276              IP(src=self.pg2.remote_ip4, dst=self.pg2.remote_ip4) /
5277              TCP(sport=1234, dport=1234))
5278         self.pg0.add_stream(p)
5279         self.pg_enable_capture(self.pg_interfaces)
5280         self.pg_start()
5281         p = self.pg0.get_capture(1)
5282         packet = p[0]
5283         try:
5284             self.assertEqual(packet[IP].src, self.nat_addr)
5285             self.assertEqual(packet[IP].dst, server.ip4)
5286             self.assertEqual(packet.haslayer(GRE), 1)
5287             self.assert_packet_checksums_valid(packet)
5288         except:
5289             self.logger.error(ppp("Unexpected or invalid packet:", packet))
5290             raise
5291
5292         # server to host
5293         p = (Ether(dst=self.pg0.local_mac, src=server.mac) /
5294              IP(src=server.ip4, dst=self.nat_addr) /
5295              GRE() /
5296              IP(src=self.pg2.remote_ip4, dst=self.pg2.remote_ip4) /
5297              TCP(sport=1234, dport=1234))
5298         self.pg0.add_stream(p)
5299         self.pg_enable_capture(self.pg_interfaces)
5300         self.pg_start()
5301         p = self.pg0.get_capture(1)
5302         packet = p[0]
5303         try:
5304             self.assertEqual(packet[IP].src, server_nat_ip)
5305             self.assertEqual(packet[IP].dst, host.ip4)
5306             self.assertEqual(packet.haslayer(GRE), 1)
5307             self.assert_packet_checksums_valid(packet)
5308         except:
5309             self.logger.error(ppp("Unexpected or invalid packet:", packet))
5310             raise
5311
5312     def test_output_feature_and_service(self):
5313         """ NAT44 interface output feature and services """
5314         external_addr = '1.2.3.4'
5315         external_port = 80
5316         local_port = 8080
5317
5318         self.vapi.nat44_forwarding_enable_disable(enable=1)
5319         self.nat44_add_address(self.nat_addr)
5320         flags = self.config_flags.NAT_IS_ADDR_ONLY
5321         self.vapi.nat44_add_del_identity_mapping(
5322             ip_address=self.pg1.remote_ip4, sw_if_index=0xFFFFFFFF,
5323             flags=flags, is_add=1)
5324         flags = self.config_flags.NAT_IS_OUT2IN_ONLY
5325         self.nat44_add_static_mapping(self.pg0.remote_ip4, external_addr,
5326                                       local_port, external_port,
5327                                       proto=IP_PROTOS.tcp, flags=flags)
5328         flags = self.config_flags.NAT_IS_INSIDE
5329         self.vapi.nat44_interface_add_del_feature(
5330             sw_if_index=self.pg0.sw_if_index,
5331             is_add=1)
5332         self.vapi.nat44_interface_add_del_feature(
5333             sw_if_index=self.pg0.sw_if_index,
5334             flags=flags, is_add=1)
5335         self.vapi.nat44_interface_add_del_output_feature(
5336             is_add=1,
5337             sw_if_index=self.pg1.sw_if_index)
5338
5339         # from client to service
5340         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
5341              IP(src=self.pg1.remote_ip4, dst=external_addr) /
5342              TCP(sport=12345, dport=external_port))
5343         self.pg1.add_stream(p)
5344         self.pg_enable_capture(self.pg_interfaces)
5345         self.pg_start()
5346         capture = self.pg0.get_capture(1)
5347         p = capture[0]
5348         try:
5349             ip = p[IP]
5350             tcp = p[TCP]
5351             self.assertEqual(ip.dst, self.pg0.remote_ip4)
5352             self.assertEqual(tcp.dport, local_port)
5353             self.assert_packet_checksums_valid(p)
5354         except:
5355             self.logger.error(ppp("Unexpected or invalid packet:", p))
5356             raise
5357
5358         # from service back to client
5359         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
5360              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
5361              TCP(sport=local_port, dport=12345))
5362         self.pg0.add_stream(p)
5363         self.pg_enable_capture(self.pg_interfaces)
5364         self.pg_start()
5365         capture = self.pg1.get_capture(1)
5366         p = capture[0]
5367         try:
5368             ip = p[IP]
5369             tcp = p[TCP]
5370             self.assertEqual(ip.src, external_addr)
5371             self.assertEqual(tcp.sport, external_port)
5372             self.assert_packet_checksums_valid(p)
5373         except:
5374             self.logger.error(ppp("Unexpected or invalid packet:", p))
5375             raise
5376
5377         # from local network host to external network
5378         pkts = self.create_stream_in(self.pg0, self.pg1)
5379         self.pg0.add_stream(pkts)
5380         self.pg_enable_capture(self.pg_interfaces)
5381         self.pg_start()
5382         capture = self.pg1.get_capture(len(pkts))
5383         self.verify_capture_out(capture, ignore_port=True)
5384         pkts = self.create_stream_in(self.pg0, self.pg1)
5385         self.pg0.add_stream(pkts)
5386         self.pg_enable_capture(self.pg_interfaces)
5387         self.pg_start()
5388         capture = self.pg1.get_capture(len(pkts))
5389         self.verify_capture_out(capture, ignore_port=True)
5390
5391         # from external network back to local network host
5392         pkts = self.create_stream_out(self.pg1)
5393         self.pg1.add_stream(pkts)
5394         self.pg_enable_capture(self.pg_interfaces)
5395         self.pg_start()
5396         capture = self.pg0.get_capture(len(pkts))
5397         self.verify_capture_in(capture, self.pg0)
5398
5399     def test_output_feature_and_service2(self):
5400         """ NAT44 interface output feature and service host direct access """
5401         self.vapi.nat44_forwarding_enable_disable(enable=1)
5402         self.nat44_add_address(self.nat_addr)
5403         self.vapi.nat44_interface_add_del_output_feature(
5404             is_add=1,
5405             sw_if_index=self.pg1.sw_if_index)
5406
5407         # session initiated from service host - translate
5408         pkts = self.create_stream_in(self.pg0, self.pg1)
5409         self.pg0.add_stream(pkts)
5410         self.pg_enable_capture(self.pg_interfaces)
5411         self.pg_start()
5412         capture = self.pg1.get_capture(len(pkts))
5413         self.verify_capture_out(capture, ignore_port=True)
5414
5415         pkts = self.create_stream_out(self.pg1)
5416         self.pg1.add_stream(pkts)
5417         self.pg_enable_capture(self.pg_interfaces)
5418         self.pg_start()
5419         capture = self.pg0.get_capture(len(pkts))
5420         self.verify_capture_in(capture, self.pg0)
5421
5422         # session initiated from remote host - do not translate
5423         self.tcp_port_in = 60303
5424         self.udp_port_in = 60304
5425         self.icmp_id_in = 60305
5426         pkts = self.create_stream_out(self.pg1,
5427                                       self.pg0.remote_ip4,
5428                                       use_inside_ports=True)
5429         self.pg1.add_stream(pkts)
5430         self.pg_enable_capture(self.pg_interfaces)
5431         self.pg_start()
5432         capture = self.pg0.get_capture(len(pkts))
5433         self.verify_capture_in(capture, self.pg0)
5434
5435         pkts = self.create_stream_in(self.pg0, self.pg1)
5436         self.pg0.add_stream(pkts)
5437         self.pg_enable_capture(self.pg_interfaces)
5438         self.pg_start()
5439         capture = self.pg1.get_capture(len(pkts))
5440         self.verify_capture_out(capture, nat_ip=self.pg0.remote_ip4,
5441                                 same_port=True)
5442
5443     def test_output_feature_and_service3(self):
5444         """ NAT44 interface output feature and DST NAT """
5445         external_addr = '1.2.3.4'
5446         external_port = 80
5447         local_port = 8080
5448
5449         self.vapi.nat44_forwarding_enable_disable(enable=1)
5450         self.nat44_add_address(self.nat_addr)
5451         flags = self.config_flags.NAT_IS_OUT2IN_ONLY
5452         self.nat44_add_static_mapping(self.pg1.remote_ip4, external_addr,
5453                                       local_port, external_port,
5454                                       proto=IP_PROTOS.tcp, flags=flags)
5455         flags = self.config_flags.NAT_IS_INSIDE
5456         self.vapi.nat44_interface_add_del_feature(
5457             sw_if_index=self.pg0.sw_if_index,
5458             is_add=1)
5459         self.vapi.nat44_interface_add_del_feature(
5460             sw_if_index=self.pg0.sw_if_index,
5461             flags=flags, is_add=1)
5462         self.vapi.nat44_interface_add_del_output_feature(
5463             is_add=1,
5464             sw_if_index=self.pg1.sw_if_index)
5465
5466         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
5467              IP(src=self.pg0.remote_ip4, dst=external_addr) /
5468              TCP(sport=12345, dport=external_port))
5469         self.pg0.add_stream(p)
5470         self.pg_enable_capture(self.pg_interfaces)
5471         self.pg_start()
5472         capture = self.pg1.get_capture(1)
5473         p = capture[0]
5474         try:
5475             ip = p[IP]
5476             tcp = p[TCP]
5477             self.assertEqual(ip.src, self.pg0.remote_ip4)
5478             self.assertEqual(tcp.sport, 12345)
5479             self.assertEqual(ip.dst, self.pg1.remote_ip4)
5480             self.assertEqual(tcp.dport, local_port)
5481             self.assert_packet_checksums_valid(p)
5482         except:
5483             self.logger.error(ppp("Unexpected or invalid packet:", p))
5484             raise
5485
5486         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
5487              IP(src=self.pg1.remote_ip4, dst=self.pg0.remote_ip4) /
5488              TCP(sport=local_port, dport=12345))
5489         self.pg1.add_stream(p)
5490         self.pg_enable_capture(self.pg_interfaces)
5491         self.pg_start()
5492         capture = self.pg0.get_capture(1)
5493         p = capture[0]
5494         try:
5495             ip = p[IP]
5496             tcp = p[TCP]
5497             self.assertEqual(ip.src, external_addr)
5498             self.assertEqual(tcp.sport, external_port)
5499             self.assertEqual(ip.dst, self.pg0.remote_ip4)
5500             self.assertEqual(tcp.dport, 12345)
5501             self.assert_packet_checksums_valid(p)
5502         except:
5503             self.logger.error(ppp("Unexpected or invalid packet:", p))
5504             raise
5505
5506     def test_next_src_nat(self):
5507         """ On way back forward packet to nat44-in2out node. """
5508         twice_nat_addr = '10.0.1.3'
5509         external_port = 80
5510         local_port = 8080
5511         post_twice_nat_port = 0
5512
5513         self.vapi.nat44_forwarding_enable_disable(enable=1)
5514         self.nat44_add_address(twice_nat_addr, twice_nat=1)
5515         flags = (self.config_flags.NAT_IS_OUT2IN_ONLY |
5516                  self.config_flags.NAT_IS_SELF_TWICE_NAT)
5517         self.nat44_add_static_mapping(self.pg6.remote_ip4, self.pg1.remote_ip4,
5518                                       local_port, external_port,
5519                                       proto=IP_PROTOS.tcp, vrf_id=1,
5520                                       flags=flags)
5521         self.vapi.nat44_interface_add_del_feature(
5522             sw_if_index=self.pg6.sw_if_index,
5523             is_add=1)
5524
5525         p = (Ether(src=self.pg6.remote_mac, dst=self.pg6.local_mac) /
5526              IP(src=self.pg6.remote_ip4, dst=self.pg1.remote_ip4) /
5527              TCP(sport=12345, dport=external_port))
5528         self.pg6.add_stream(p)
5529         self.pg_enable_capture(self.pg_interfaces)
5530         self.pg_start()
5531         capture = self.pg6.get_capture(1)
5532         p = capture[0]
5533         try:
5534             ip = p[IP]
5535             tcp = p[TCP]
5536             self.assertEqual(ip.src, twice_nat_addr)
5537             self.assertNotEqual(tcp.sport, 12345)
5538             post_twice_nat_port = tcp.sport
5539             self.assertEqual(ip.dst, self.pg6.remote_ip4)
5540             self.assertEqual(tcp.dport, local_port)
5541             self.assert_packet_checksums_valid(p)
5542         except:
5543             self.logger.error(ppp("Unexpected or invalid packet:", p))
5544             raise
5545
5546         p = (Ether(src=self.pg6.remote_mac, dst=self.pg6.local_mac) /
5547              IP(src=self.pg6.remote_ip4, dst=twice_nat_addr) /
5548              TCP(sport=local_port, dport=post_twice_nat_port))
5549         self.pg6.add_stream(p)
5550         self.pg_enable_capture(self.pg_interfaces)
5551         self.pg_start()
5552         capture = self.pg6.get_capture(1)
5553         p = capture[0]
5554         try:
5555             ip = p[IP]
5556             tcp = p[TCP]
5557             self.assertEqual(ip.src, self.pg1.remote_ip4)
5558             self.assertEqual(tcp.sport, external_port)
5559             self.assertEqual(ip.dst, self.pg6.remote_ip4)
5560             self.assertEqual(tcp.dport, 12345)
5561             self.assert_packet_checksums_valid(p)
5562         except:
5563             self.logger.error(ppp("Unexpected or invalid packet:", p))
5564             raise
5565
5566     def twice_nat_common(self, self_twice_nat=False, same_pg=False, lb=False,
5567                          client_id=None):
5568         twice_nat_addr = '10.0.1.3'
5569
5570         port_in = 8080
5571         if lb:
5572             if not same_pg:
5573                 port_in1 = port_in
5574                 port_in2 = port_in
5575             else:
5576                 port_in1 = port_in + 1
5577                 port_in2 = port_in + 2
5578
5579         port_out = 80
5580         eh_port_out = 4567
5581
5582         server1 = self.pg0.remote_hosts[0]
5583         server2 = self.pg0.remote_hosts[1]
5584         if lb and same_pg:
5585             server2 = server1
5586         if not lb:
5587             server = server1
5588
5589         pg0 = self.pg0
5590         if same_pg:
5591             pg1 = self.pg0
5592         else:
5593             pg1 = self.pg1
5594
5595         eh_translate = ((not self_twice_nat) or (not lb and same_pg) or
5596                         client_id == 1)
5597
5598         self.nat44_add_address(self.nat_addr)
5599         self.nat44_add_address(twice_nat_addr, twice_nat=1)
5600
5601         flags = 0
5602         if self_twice_nat:
5603             flags |= self.config_flags.NAT_IS_SELF_TWICE_NAT
5604         else:
5605             flags |= self.config_flags.NAT_IS_TWICE_NAT
5606
5607         if not lb:
5608             self.nat44_add_static_mapping(pg0.remote_ip4, self.nat_addr,
5609                                           port_in, port_out,
5610                                           proto=IP_PROTOS.tcp,
5611                                           flags=flags)
5612         else:
5613             locals = [{'addr': server1.ip4,
5614                        'port': port_in1,
5615                        'probability': 50,
5616                        'vrf_id': 0},
5617                       {'addr': server2.ip4,
5618                        'port': port_in2,
5619                        'probability': 50,
5620                        'vrf_id': 0}]
5621             out_addr = self.nat_addr
5622
5623             self.vapi.nat44_add_del_lb_static_mapping(is_add=1, flags=flags,
5624                                                       external_addr=out_addr,
5625                                                       external_port=port_out,
5626                                                       protocol=IP_PROTOS.tcp,
5627                                                       local_num=len(locals),
5628                                                       locals=locals)
5629         flags = self.config_flags.NAT_IS_INSIDE
5630         self.vapi.nat44_interface_add_del_feature(
5631             sw_if_index=pg0.sw_if_index,
5632             flags=flags, is_add=1)
5633         self.vapi.nat44_interface_add_del_feature(
5634             sw_if_index=pg1.sw_if_index,
5635             is_add=1)
5636
5637         if same_pg:
5638             if not lb:
5639                 client = server
5640             else:
5641                 assert client_id is not None
5642                 if client_id == 1:
5643                     client = self.pg0.remote_hosts[0]
5644                 elif client_id == 2:
5645                     client = self.pg0.remote_hosts[1]
5646         else:
5647             client = pg1.remote_hosts[0]
5648         p = (Ether(src=pg1.remote_mac, dst=pg1.local_mac) /
5649              IP(src=client.ip4, dst=self.nat_addr) /
5650              TCP(sport=eh_port_out, dport=port_out))
5651         pg1.add_stream(p)
5652         self.pg_enable_capture(self.pg_interfaces)
5653         self.pg_start()
5654         capture = pg0.get_capture(1)
5655         p = capture[0]
5656         try:
5657             ip = p[IP]
5658             tcp = p[TCP]
5659             if lb:
5660                 if ip.dst == server1.ip4:
5661                     server = server1
5662                     port_in = port_in1
5663                 else:
5664                     server = server2
5665                     port_in = port_in2
5666             self.assertEqual(ip.dst, server.ip4)
5667             if lb and same_pg:
5668                 self.assertIn(tcp.dport, [port_in1, port_in2])
5669             else:
5670                 self.assertEqual(tcp.dport, port_in)
5671             if eh_translate:
5672                 self.assertEqual(ip.src, twice_nat_addr)
5673                 self.assertNotEqual(tcp.sport, eh_port_out)
5674             else:
5675                 self.assertEqual(ip.src, client.ip4)
5676                 self.assertEqual(tcp.sport, eh_port_out)
5677             eh_addr_in = ip.src
5678             eh_port_in = tcp.sport
5679             saved_port_in = tcp.dport
5680             self.assert_packet_checksums_valid(p)
5681         except:
5682             self.logger.error(ppp("Unexpected or invalid packet:", p))
5683             raise
5684
5685         p = (Ether(src=server.mac, dst=pg0.local_mac) /
5686              IP(src=server.ip4, dst=eh_addr_in) /
5687              TCP(sport=saved_port_in, dport=eh_port_in))
5688         pg0.add_stream(p)
5689         self.pg_enable_capture(self.pg_interfaces)
5690         self.pg_start()
5691         capture = pg1.get_capture(1)
5692         p = capture[0]
5693         try:
5694             ip = p[IP]
5695             tcp = p[TCP]
5696             self.assertEqual(ip.dst, client.ip4)
5697             self.assertEqual(ip.src, self.nat_addr)
5698             self.assertEqual(tcp.dport, eh_port_out)
5699             self.assertEqual(tcp.sport, port_out)
5700             self.assert_packet_checksums_valid(p)
5701         except:
5702             self.logger.error(ppp("Unexpected or invalid packet:", p))
5703             raise
5704
5705         if eh_translate:
5706             sessions = self.vapi.nat44_user_session_dump(server.ip4, 0)
5707             self.assertEqual(len(sessions), 1)
5708             self.assertTrue(sessions[0].flags &
5709                             self.config_flags.NAT_IS_EXT_HOST_VALID)
5710             self.assertTrue(sessions[0].flags &
5711                             self.config_flags.NAT_IS_TWICE_NAT)
5712             self.logger.info(self.vapi.cli("show nat44 sessions detail"))
5713             self.vapi.nat44_del_session(
5714                 address=sessions[0].inside_ip_address,
5715                 port=sessions[0].inside_port,
5716                 protocol=sessions[0].protocol,
5717                 flags=(self.config_flags.NAT_IS_INSIDE |
5718                        self.config_flags.NAT_IS_EXT_HOST_VALID),
5719                 ext_host_address=sessions[0].ext_host_nat_address,
5720                 ext_host_port=sessions[0].ext_host_nat_port)
5721             sessions = self.vapi.nat44_user_session_dump(server.ip4, 0)
5722             self.assertEqual(len(sessions), 0)
5723
5724     def test_twice_nat(self):
5725         """ Twice NAT44 """
5726         self.twice_nat_common()
5727
5728     def test_self_twice_nat_positive(self):
5729         """ Self Twice NAT44 (positive test) """
5730         self.twice_nat_common(self_twice_nat=True, same_pg=True)
5731
5732     def test_self_twice_nat_negative(self):
5733         """ Self Twice NAT44 (negative test) """
5734         self.twice_nat_common(self_twice_nat=True)
5735
5736     def test_twice_nat_lb(self):
5737         """ Twice NAT44 local service load balancing """
5738         self.twice_nat_common(lb=True)
5739
5740     def test_self_twice_nat_lb_positive(self):
5741         """ Self Twice NAT44 local service load balancing (positive test) """
5742         self.twice_nat_common(lb=True, self_twice_nat=True, same_pg=True,
5743                               client_id=1)
5744
5745     def test_self_twice_nat_lb_negative(self):
5746         """ Self Twice NAT44 local service load balancing (negative test) """
5747         self.twice_nat_common(lb=True, self_twice_nat=True, same_pg=True,
5748                               client_id=2)
5749
5750     def test_twice_nat_interface_addr(self):
5751         """ Acquire twice NAT44 addresses from interface """
5752         flags = self.config_flags.NAT_IS_TWICE_NAT
5753         self.vapi.nat44_add_del_interface_addr(
5754             is_add=1,
5755             sw_if_index=self.pg3.sw_if_index,
5756             flags=flags)
5757
5758         # no address in NAT pool
5759         adresses = self.vapi.nat44_address_dump()
5760         self.assertEqual(0, len(adresses))
5761
5762         # configure interface address and check NAT address pool
5763         self.pg3.config_ip4()
5764         adresses = self.vapi.nat44_address_dump()
5765         self.assertEqual(1, len(adresses))
5766         self.assertEqual(str(adresses[0].ip_address),
5767                          self.pg3.local_ip4)
5768         self.assertEqual(adresses[0].flags, flags)
5769
5770         # remove interface address and check NAT address pool
5771         self.pg3.unconfig_ip4()
5772         adresses = self.vapi.nat44_address_dump()
5773         self.assertEqual(0, len(adresses))
5774
5775     def test_tcp_close(self):
5776         """ Close TCP session from inside network - output feature """
5777         self.vapi.nat44_forwarding_enable_disable(enable=1)
5778         self.nat44_add_address(self.pg1.local_ip4)
5779         twice_nat_addr = '10.0.1.3'
5780         service_ip = '192.168.16.150'
5781         self.nat44_add_address(twice_nat_addr, twice_nat=1)
5782         flags = self.config_flags.NAT_IS_INSIDE
5783         self.vapi.nat44_interface_add_del_feature(
5784             sw_if_index=self.pg0.sw_if_index,
5785             is_add=1)
5786         self.vapi.nat44_interface_add_del_feature(
5787             sw_if_index=self.pg0.sw_if_index,
5788             flags=flags, is_add=1)
5789         self.vapi.nat44_interface_add_del_output_feature(
5790             is_add=1,
5791             sw_if_index=self.pg1.sw_if_index)
5792         flags = (self.config_flags.NAT_IS_OUT2IN_ONLY |
5793                  self.config_flags.NAT_IS_TWICE_NAT)
5794         self.nat44_add_static_mapping(self.pg0.remote_ip4,
5795                                       service_ip,
5796                                       80,
5797                                       80,
5798                                       proto=IP_PROTOS.tcp,
5799                                       flags=flags)
5800         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
5801         start_sessnum = len(sessions)
5802
5803         # SYN packet out->in
5804         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
5805              IP(src=self.pg1.remote_ip4, dst=service_ip) /
5806              TCP(sport=33898, dport=80, flags="S"))
5807         self.pg1.add_stream(p)
5808         self.pg_enable_capture(self.pg_interfaces)
5809         self.pg_start()
5810         capture = self.pg0.get_capture(1)
5811         p = capture[0]
5812         tcp_port = p[TCP].sport
5813
5814         # SYN + ACK packet in->out
5815         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
5816              IP(src=self.pg0.remote_ip4, dst=twice_nat_addr) /
5817              TCP(sport=80, dport=tcp_port, flags="SA"))
5818         self.pg0.add_stream(p)
5819         self.pg_enable_capture(self.pg_interfaces)
5820         self.pg_start()
5821         self.pg1.get_capture(1)
5822
5823         # ACK packet out->in
5824         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
5825              IP(src=self.pg1.remote_ip4, dst=service_ip) /
5826              TCP(sport=33898, dport=80, flags="A"))
5827         self.pg1.add_stream(p)
5828         self.pg_enable_capture(self.pg_interfaces)
5829         self.pg_start()
5830         self.pg0.get_capture(1)
5831
5832         # FIN packet in -> out
5833         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
5834              IP(src=self.pg0.remote_ip4, dst=twice_nat_addr) /
5835              TCP(sport=80, dport=tcp_port, flags="FA", seq=100, ack=300))
5836         self.pg0.add_stream(p)
5837         self.pg_enable_capture(self.pg_interfaces)
5838         self.pg_start()
5839         self.pg1.get_capture(1)
5840
5841         # FIN+ACK packet out -> in
5842         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
5843              IP(src=self.pg1.remote_ip4, dst=service_ip) /
5844              TCP(sport=33898, dport=80, flags="FA", seq=300, ack=101))
5845         self.pg1.add_stream(p)
5846         self.pg_enable_capture(self.pg_interfaces)
5847         self.pg_start()
5848         self.pg0.get_capture(1)
5849
5850         # ACK packet in -> out
5851         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
5852              IP(src=self.pg0.remote_ip4, dst=twice_nat_addr) /
5853              TCP(sport=80, dport=tcp_port, flags="A", seq=101, ack=301))
5854         self.pg0.add_stream(p)
5855         self.pg_enable_capture(self.pg_interfaces)
5856         self.pg_start()
5857         self.pg1.get_capture(1)
5858
5859         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4,
5860                                                      0)
5861         self.assertEqual(len(sessions) - start_sessnum, 0)
5862
5863     def test_tcp_session_close_in(self):
5864         """ Close TCP session from inside network """
5865         self.tcp_port_out = 10505
5866         self.nat44_add_address(self.nat_addr)
5867         flags = self.config_flags.NAT_IS_TWICE_NAT
5868         self.nat44_add_static_mapping(self.pg0.remote_ip4,
5869                                       self.nat_addr,
5870                                       self.tcp_port_in,
5871                                       self.tcp_port_out,
5872                                       proto=IP_PROTOS.tcp,
5873                                       flags=flags)
5874         flags = self.config_flags.NAT_IS_INSIDE
5875         self.vapi.nat44_interface_add_del_feature(
5876             sw_if_index=self.pg0.sw_if_index,
5877             flags=flags, is_add=1)
5878         self.vapi.nat44_interface_add_del_feature(
5879             sw_if_index=self.pg1.sw_if_index,
5880             is_add=1)
5881
5882         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
5883         start_sessnum = len(sessions)
5884
5885         self.vapi.nat_set_timeouts(udp=300, tcp_established=7440,
5886                                    tcp_transitory=2, icmp=5)
5887
5888         self.initiate_tcp_session(self.pg0, self.pg1)
5889
5890         # FIN packet in -> out
5891         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
5892              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
5893              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
5894                  flags="FA", seq=100, ack=300))
5895         self.pg0.add_stream(p)
5896         self.pg_enable_capture(self.pg_interfaces)
5897         self.pg_start()
5898         self.pg1.get_capture(1)
5899
5900         pkts = []
5901
5902         # ACK packet out -> in
5903         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
5904              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
5905              TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
5906                  flags="A", seq=300, ack=101))
5907         pkts.append(p)
5908
5909         # FIN packet out -> in
5910         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
5911              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
5912              TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
5913                  flags="FA", seq=300, ack=101))
5914         pkts.append(p)
5915
5916         self.pg1.add_stream(pkts)
5917         self.pg_enable_capture(self.pg_interfaces)
5918         self.pg_start()
5919         self.pg0.get_capture(2)
5920
5921         # ACK packet in -> out
5922         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
5923              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
5924              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
5925                  flags="A", seq=101, ack=301))
5926         self.pg0.add_stream(p)
5927         self.pg_enable_capture(self.pg_interfaces)
5928         self.pg_start()
5929         self.pg1.get_capture(1)
5930
5931         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
5932         self.assertEqual(len(sessions) - start_sessnum, 1)
5933
5934         stats = self.statistics.get_counter(
5935             '/err/nat44-ed-out2in/drops due to TCP in transitory timeout')
5936         out2in_drops = stats[0]
5937         stats = self.statistics.get_counter(
5938             '/err/nat44-ed-in2out/drops due to TCP in transitory timeout')
5939         in2out_drops = stats[0]
5940
5941         # extra FIN packet out -> in - this should be dropped
5942         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
5943              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
5944              TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
5945                  flags="FA", seq=300, ack=101))
5946
5947         self.pg1.add_stream(p)
5948         self.pg_enable_capture(self.pg_interfaces)
5949         self.pg_start()
5950         self.pg0.assert_nothing_captured()
5951
5952         # extra ACK packet in -> out - this should be dropped
5953         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
5954              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
5955              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
5956                  flags="A", seq=101, ack=301))
5957         self.pg0.add_stream(p)
5958         self.pg_enable_capture(self.pg_interfaces)
5959         self.pg_start()
5960         self.pg1.assert_nothing_captured()
5961
5962         stats = self.statistics.get_counter(
5963             '/err/nat44-ed-out2in/drops due to TCP in transitory timeout')
5964         self.assertEqual(stats[0] - out2in_drops, 1)
5965         stats = self.statistics.get_counter(
5966             '/err/nat44-ed-in2out/drops due to TCP in transitory timeout')
5967         self.assertEqual(stats[0] - in2out_drops, 1)
5968
5969         self.sleep(3)
5970         # extra ACK packet in -> out - this will cause session to be wiped
5971         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
5972              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
5973              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
5974                  flags="A", seq=101, ack=301))
5975         self.pg0.add_stream(p)
5976         self.pg_enable_capture(self.pg_interfaces)
5977         self.pg_start()
5978         self.pg1.assert_nothing_captured()
5979         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
5980         self.assertEqual(len(sessions) - start_sessnum, 0)
5981
5982     def test_tcp_session_close_out(self):
5983         """ Close TCP session from outside network """
5984         self.tcp_port_out = 10505
5985         self.nat44_add_address(self.nat_addr)
5986         flags = self.config_flags.NAT_IS_TWICE_NAT
5987         self.nat44_add_static_mapping(self.pg0.remote_ip4,
5988                                       self.nat_addr,
5989                                       self.tcp_port_in,
5990                                       self.tcp_port_out,
5991                                       proto=IP_PROTOS.tcp,
5992                                       flags=flags)
5993         flags = self.config_flags.NAT_IS_INSIDE
5994         self.vapi.nat44_interface_add_del_feature(
5995             sw_if_index=self.pg0.sw_if_index,
5996             flags=flags, is_add=1)
5997         self.vapi.nat44_interface_add_del_feature(
5998             sw_if_index=self.pg1.sw_if_index,
5999             is_add=1)
6000
6001         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
6002         start_sessnum = len(sessions)
6003
6004         self.vapi.nat_set_timeouts(udp=300, tcp_established=7440,
6005                                    tcp_transitory=2, icmp=5)
6006
6007         self.initiate_tcp_session(self.pg0, self.pg1)
6008
6009         # FIN packet out -> in
6010         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
6011              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
6012              TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
6013                  flags="FA", seq=100, ack=300))
6014         self.pg1.add_stream(p)
6015         self.pg_enable_capture(self.pg_interfaces)
6016         self.pg_start()
6017         self.pg0.get_capture(1)
6018
6019         # FIN+ACK packet in -> out
6020         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6021              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6022              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
6023                  flags="FA", seq=300, ack=101))
6024
6025         self.pg0.add_stream(p)
6026         self.pg_enable_capture(self.pg_interfaces)
6027         self.pg_start()
6028         self.pg1.get_capture(1)
6029
6030         # ACK packet out -> in
6031         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
6032              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
6033              TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
6034                  flags="A", seq=101, ack=301))
6035         self.pg1.add_stream(p)
6036         self.pg_enable_capture(self.pg_interfaces)
6037         self.pg_start()
6038         self.pg0.get_capture(1)
6039
6040         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
6041         self.assertEqual(len(sessions) - start_sessnum, 1)
6042
6043         stats = self.statistics.get_counter(
6044             '/err/nat44-ed-out2in/drops due to TCP in transitory timeout')
6045         out2in_drops = stats[0]
6046         stats = self.statistics.get_counter(
6047             '/err/nat44-ed-in2out/drops due to TCP in transitory timeout')
6048         in2out_drops = stats[0]
6049
6050         # extra FIN packet out -> in - this should be dropped
6051         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
6052              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
6053              TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
6054                  flags="FA", seq=300, ack=101))
6055
6056         self.pg1.add_stream(p)
6057         self.pg_enable_capture(self.pg_interfaces)
6058         self.pg_start()
6059         self.pg0.assert_nothing_captured()
6060
6061         # extra ACK packet in -> out - this should be dropped
6062         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6063              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6064              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
6065                  flags="A", seq=101, ack=301))
6066         self.pg0.add_stream(p)
6067         self.pg_enable_capture(self.pg_interfaces)
6068         self.pg_start()
6069         self.pg1.assert_nothing_captured()
6070
6071         stats = self.statistics.get_counter(
6072             '/err/nat44-ed-out2in/drops due to TCP in transitory timeout')
6073         self.assertEqual(stats[0] - out2in_drops, 1)
6074         stats = self.statistics.get_counter(
6075             '/err/nat44-ed-in2out/drops due to TCP in transitory timeout')
6076         self.assertEqual(stats[0] - in2out_drops, 1)
6077
6078         self.sleep(3)
6079         # extra ACK packet in -> out - this will cause session to be wiped
6080         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6081              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6082              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
6083                  flags="A", seq=101, ack=301))
6084         self.pg0.add_stream(p)
6085         self.pg_enable_capture(self.pg_interfaces)
6086         self.pg_start()
6087         self.pg1.assert_nothing_captured()
6088         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
6089         self.assertEqual(len(sessions) - start_sessnum, 0)
6090
6091     def test_tcp_session_close_simultaneous(self):
6092         """ Close TCP session from inside network """
6093         self.tcp_port_out = 10505
6094         self.nat44_add_address(self.nat_addr)
6095         flags = self.config_flags.NAT_IS_TWICE_NAT
6096         self.nat44_add_static_mapping(self.pg0.remote_ip4,
6097                                       self.nat_addr,
6098                                       self.tcp_port_in,
6099                                       self.tcp_port_out,
6100                                       proto=IP_PROTOS.tcp,
6101                                       flags=flags)
6102         flags = self.config_flags.NAT_IS_INSIDE
6103         self.vapi.nat44_interface_add_del_feature(
6104             sw_if_index=self.pg0.sw_if_index,
6105             flags=flags, is_add=1)
6106         self.vapi.nat44_interface_add_del_feature(
6107             sw_if_index=self.pg1.sw_if_index,
6108             is_add=1)
6109
6110         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
6111         start_sessnum = len(sessions)
6112
6113         self.vapi.nat_set_timeouts(udp=300, tcp_established=7440,
6114                                    tcp_transitory=2, icmp=5)
6115
6116         self.initiate_tcp_session(self.pg0, self.pg1)
6117
6118         # FIN packet in -> out
6119         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6120              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6121              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
6122                  flags="FA", seq=100, ack=300))
6123         self.pg0.add_stream(p)
6124         self.pg_enable_capture(self.pg_interfaces)
6125         self.pg_start()
6126         self.pg1.get_capture(1)
6127
6128         # FIN packet out -> in
6129         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
6130              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
6131              TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
6132                  flags="FA", seq=300, ack=100))
6133         self.pg1.add_stream(p)
6134         self.pg_enable_capture(self.pg_interfaces)
6135         self.pg_start()
6136         self.pg0.get_capture(1)
6137
6138         # ACK packet in -> out
6139         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6140              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6141              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
6142                  flags="A", seq=101, ack=301))
6143         self.pg0.add_stream(p)
6144         self.pg_enable_capture(self.pg_interfaces)
6145         self.pg_start()
6146         self.pg1.get_capture(1)
6147
6148         # ACK packet out -> in
6149         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
6150              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
6151              TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
6152                  flags="A", seq=301, ack=101))
6153         self.pg1.add_stream(p)
6154         self.pg_enable_capture(self.pg_interfaces)
6155         self.pg_start()
6156         self.pg0.get_capture(1)
6157
6158         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
6159         self.assertEqual(len(sessions) - start_sessnum, 1)
6160
6161         stats = self.statistics.get_counter(
6162             '/err/nat44-ed-out2in/drops due to TCP in transitory timeout')
6163         out2in_drops = stats[0]
6164         stats = self.statistics.get_counter(
6165             '/err/nat44-ed-in2out/drops due to TCP in transitory timeout')
6166         in2out_drops = stats[0]
6167
6168         # extra FIN packet out -> in - this should be dropped
6169         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
6170              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
6171              TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
6172                  flags="FA", seq=300, ack=101))
6173
6174         self.pg1.add_stream(p)
6175         self.pg_enable_capture(self.pg_interfaces)
6176         self.pg_start()
6177         self.pg0.assert_nothing_captured()
6178
6179         # extra ACK packet in -> out - this should be dropped
6180         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6181              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6182              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
6183                  flags="A", seq=101, ack=301))
6184         self.pg0.add_stream(p)
6185         self.pg_enable_capture(self.pg_interfaces)
6186         self.pg_start()
6187         self.pg1.assert_nothing_captured()
6188
6189         stats = self.statistics.get_counter(
6190             '/err/nat44-ed-out2in/drops due to TCP in transitory timeout')
6191         self.assertEqual(stats[0] - out2in_drops, 1)
6192         stats = self.statistics.get_counter(
6193             '/err/nat44-ed-in2out/drops due to TCP in transitory timeout')
6194         self.assertEqual(stats[0] - in2out_drops, 1)
6195
6196         self.sleep(3)
6197         # extra ACK packet in -> out - this will cause session to be wiped
6198         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6199              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6200              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
6201                  flags="A", seq=101, ack=301))
6202         self.pg0.add_stream(p)
6203         self.pg_enable_capture(self.pg_interfaces)
6204         self.pg_start()
6205         self.pg1.assert_nothing_captured()
6206         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
6207         self.assertEqual(len(sessions) - start_sessnum, 0)
6208
6209     def test_one_armed_nat44_static(self):
6210         """ One armed NAT44 and 1:1 NAPT asymmetrical rule """
6211         remote_host = self.pg4.remote_hosts[0]
6212         local_host = self.pg4.remote_hosts[1]
6213         external_port = 80
6214         local_port = 8080
6215         eh_port_in = 0
6216
6217         self.vapi.nat44_forwarding_enable_disable(enable=1)
6218         self.nat44_add_address(self.nat_addr, twice_nat=1)
6219         flags = (self.config_flags.NAT_IS_OUT2IN_ONLY |
6220                  self.config_flags.NAT_IS_TWICE_NAT)
6221         self.nat44_add_static_mapping(local_host.ip4, self.nat_addr,
6222                                       local_port, external_port,
6223                                       proto=IP_PROTOS.tcp, flags=flags)
6224         flags = self.config_flags.NAT_IS_INSIDE
6225         self.vapi.nat44_interface_add_del_feature(
6226             sw_if_index=self.pg4.sw_if_index,
6227             is_add=1)
6228         self.vapi.nat44_interface_add_del_feature(
6229             sw_if_index=self.pg4.sw_if_index,
6230             flags=flags, is_add=1)
6231
6232         # from client to service
6233         p = (Ether(src=self.pg4.remote_mac, dst=self.pg4.local_mac) /
6234              IP(src=remote_host.ip4, dst=self.nat_addr) /
6235              TCP(sport=12345, dport=external_port))
6236         self.pg4.add_stream(p)
6237         self.pg_enable_capture(self.pg_interfaces)
6238         self.pg_start()
6239         capture = self.pg4.get_capture(1)
6240         p = capture[0]
6241         try:
6242             ip = p[IP]
6243             tcp = p[TCP]
6244             self.assertEqual(ip.dst, local_host.ip4)
6245             self.assertEqual(ip.src, self.nat_addr)
6246             self.assertEqual(tcp.dport, local_port)
6247             self.assertNotEqual(tcp.sport, 12345)
6248             eh_port_in = tcp.sport
6249             self.assert_packet_checksums_valid(p)
6250         except:
6251             self.logger.error(ppp("Unexpected or invalid packet:", p))
6252             raise
6253
6254         # from service back to client
6255         p = (Ether(src=self.pg4.remote_mac, dst=self.pg4.local_mac) /
6256              IP(src=local_host.ip4, dst=self.nat_addr) /
6257              TCP(sport=local_port, dport=eh_port_in))
6258         self.pg4.add_stream(p)
6259         self.pg_enable_capture(self.pg_interfaces)
6260         self.pg_start()
6261         capture = self.pg4.get_capture(1)
6262         p = capture[0]
6263         try:
6264             ip = p[IP]
6265             tcp = p[TCP]
6266             self.assertEqual(ip.src, self.nat_addr)
6267             self.assertEqual(ip.dst, remote_host.ip4)
6268             self.assertEqual(tcp.sport, external_port)
6269             self.assertEqual(tcp.dport, 12345)
6270             self.assert_packet_checksums_valid(p)
6271         except:
6272             self.logger.error(ppp("Unexpected or invalid packet:", p))
6273             raise
6274
6275     def test_static_with_port_out2(self):
6276         """ 1:1 NAPT asymmetrical rule """
6277
6278         external_port = 80
6279         local_port = 8080
6280
6281         self.vapi.nat44_forwarding_enable_disable(enable=1)
6282         flags = self.config_flags.NAT_IS_OUT2IN_ONLY
6283         self.nat44_add_static_mapping(self.pg0.remote_ip4, self.nat_addr,
6284                                       local_port, external_port,
6285                                       proto=IP_PROTOS.tcp, flags=flags)
6286         flags = self.config_flags.NAT_IS_INSIDE
6287         self.vapi.nat44_interface_add_del_feature(
6288             sw_if_index=self.pg0.sw_if_index,
6289             flags=flags, is_add=1)
6290         self.vapi.nat44_interface_add_del_feature(
6291             sw_if_index=self.pg1.sw_if_index,
6292             is_add=1)
6293
6294         # from client to service
6295         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
6296              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
6297              TCP(sport=12345, dport=external_port))
6298         self.pg1.add_stream(p)
6299         self.pg_enable_capture(self.pg_interfaces)
6300         self.pg_start()
6301         capture = self.pg0.get_capture(1)
6302         p = capture[0]
6303         try:
6304             ip = p[IP]
6305             tcp = p[TCP]
6306             self.assertEqual(ip.dst, self.pg0.remote_ip4)
6307             self.assertEqual(tcp.dport, local_port)
6308             self.assert_packet_checksums_valid(p)
6309         except:
6310             self.logger.error(ppp("Unexpected or invalid packet:", p))
6311             raise
6312
6313         # ICMP error
6314         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
6315              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6316              ICMP(type=11) / capture[0][IP])
6317         self.pg0.add_stream(p)
6318         self.pg_enable_capture(self.pg_interfaces)
6319         self.pg_start()
6320         capture = self.pg1.get_capture(1)
6321         p = capture[0]
6322         try:
6323             self.assertEqual(p[IP].src, self.nat_addr)
6324             inner = p[IPerror]
6325             self.assertEqual(inner.dst, self.nat_addr)
6326             self.assertEqual(inner[TCPerror].dport, external_port)
6327         except:
6328             self.logger.error(ppp("Unexpected or invalid packet:", p))
6329             raise
6330
6331         # from service back to client
6332         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6333              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6334              TCP(sport=local_port, dport=12345))
6335         self.pg0.add_stream(p)
6336         self.pg_enable_capture(self.pg_interfaces)
6337         self.pg_start()
6338         capture = self.pg1.get_capture(1)
6339         p = capture[0]
6340         try:
6341             ip = p[IP]
6342             tcp = p[TCP]
6343             self.assertEqual(ip.src, self.nat_addr)
6344             self.assertEqual(tcp.sport, external_port)
6345             self.assert_packet_checksums_valid(p)
6346         except:
6347             self.logger.error(ppp("Unexpected or invalid packet:", p))
6348             raise
6349
6350         # ICMP error
6351         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
6352              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
6353              ICMP(type=11) / capture[0][IP])
6354         self.pg1.add_stream(p)
6355         self.pg_enable_capture(self.pg_interfaces)
6356         self.pg_start()
6357         capture = self.pg0.get_capture(1)
6358         p = capture[0]
6359         try:
6360             self.assertEqual(p[IP].dst, self.pg0.remote_ip4)
6361             inner = p[IPerror]
6362             self.assertEqual(inner.src, self.pg0.remote_ip4)
6363             self.assertEqual(inner[TCPerror].sport, local_port)
6364         except:
6365             self.logger.error(ppp("Unexpected or invalid packet:", p))
6366             raise
6367
6368         # from client to server (no translation)
6369         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
6370              IP(src=self.pg1.remote_ip4, dst=self.pg0.remote_ip4) /
6371              TCP(sport=12346, dport=local_port))
6372         self.pg1.add_stream(p)
6373         self.pg_enable_capture(self.pg_interfaces)
6374         self.pg_start()
6375         capture = self.pg0.get_capture(1)
6376         p = capture[0]
6377         try:
6378             ip = p[IP]
6379             tcp = p[TCP]
6380             self.assertEqual(ip.dst, self.pg0.remote_ip4)
6381             self.assertEqual(tcp.dport, local_port)
6382             self.assert_packet_checksums_valid(p)
6383         except:
6384             self.logger.error(ppp("Unexpected or invalid packet:", p))
6385             raise
6386
6387         # from service back to client (no translation)
6388         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6389              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6390              TCP(sport=local_port, dport=12346))
6391         self.pg0.add_stream(p)
6392         self.pg_enable_capture(self.pg_interfaces)
6393         self.pg_start()
6394         capture = self.pg1.get_capture(1)
6395         p = capture[0]
6396         try:
6397             ip = p[IP]
6398             tcp = p[TCP]
6399             self.assertEqual(ip.src, self.pg0.remote_ip4)
6400             self.assertEqual(tcp.sport, local_port)
6401             self.assert_packet_checksums_valid(p)
6402         except:
6403             self.logger.error(ppp("Unexpected or invalid packet:", p))
6404             raise
6405
6406     def test_output_feature(self):
6407         """ NAT44 interface output feature (in2out postrouting) """
6408         self.vapi.nat44_forwarding_enable_disable(enable=1)
6409         self.nat44_add_address(self.nat_addr)
6410         self.vapi.nat44_interface_add_del_feature(
6411             sw_if_index=self.pg0.sw_if_index,
6412             is_add=1)
6413         self.vapi.nat44_interface_add_del_output_feature(
6414             is_add=1,
6415             sw_if_index=self.pg1.sw_if_index)
6416
6417         # in2out
6418         pkts = self.create_stream_in(self.pg0, self.pg1)
6419         self.pg0.add_stream(pkts)
6420         self.pg_enable_capture(self.pg_interfaces)
6421         self.pg_start()
6422         capture = self.pg1.get_capture(len(pkts))
6423         self.verify_capture_out(capture, ignore_port=True)
6424
6425         # out2in
6426         pkts = self.create_stream_out(self.pg1)
6427         self.pg1.add_stream(pkts)
6428         self.pg_enable_capture(self.pg_interfaces)
6429         self.pg_start()
6430         capture = self.pg0.get_capture(len(pkts))
6431         self.verify_capture_in(capture, self.pg0)
6432
6433     def test_output_feature_stateful_acl(self):
6434         """ NAT44 endpoint-dependent output feature works with stateful ACL """
6435         self.nat44_add_address(self.nat_addr)
6436         self.vapi.nat44_interface_add_del_output_feature(
6437             sw_if_index=self.pg0.sw_if_index,
6438             flags=self.config_flags.NAT_IS_INSIDE,
6439             is_add=1)
6440         self.vapi.nat44_interface_add_del_output_feature(
6441             sw_if_index=self.pg1.sw_if_index,
6442             flags=self.config_flags.NAT_IS_OUTSIDE,
6443             is_add=1)
6444
6445         # First ensure that the NAT is working sans ACL
6446
6447         # send packets out2in, no sessions yet so packets should drop
6448         pkts_out2in = self.create_stream_out(self.pg1)
6449         self.send_and_assert_no_replies(self.pg1, pkts_out2in)
6450
6451         # send packets into inside intf, ensure received via outside intf
6452         pkts_in2out = self.create_stream_in(self.pg0, self.pg1)
6453         capture = self.send_and_expect(self.pg0, pkts_in2out, self.pg1,
6454                                        len(pkts_in2out))
6455         self.verify_capture_out(capture, ignore_port=True)
6456
6457         # send out2in again, with sessions created it should work now
6458         pkts_out2in = self.create_stream_out(self.pg1)
6459         capture = self.send_and_expect(self.pg1, pkts_out2in, self.pg0,
6460                                        len(pkts_out2in))
6461         self.verify_capture_in(capture, self.pg0)
6462
6463         # Create an ACL blocking everything
6464         out2in_deny_rule = AclRule(is_permit=0)
6465         out2in_acl = VppAcl(self, rules=[out2in_deny_rule])
6466         out2in_acl.add_vpp_config()
6467
6468         # create an ACL to permit/reflect everything
6469         in2out_reflect_rule = AclRule(is_permit=2)
6470         in2out_acl = VppAcl(self, rules=[in2out_reflect_rule])
6471         in2out_acl.add_vpp_config()
6472
6473         # apply as input acl on interface and confirm it blocks everything
6474         acl_if = VppAclInterface(self, sw_if_index=self.pg1.sw_if_index,
6475                                  n_input=1, acls=[out2in_acl])
6476         acl_if.add_vpp_config()
6477         self.send_and_assert_no_replies(self.pg1, pkts_out2in)
6478
6479         # apply output acl
6480         acl_if.acls = [out2in_acl, in2out_acl]
6481         acl_if.add_vpp_config()
6482         # send in2out to generate ACL state (NAT state was created earlier)
6483         capture = self.send_and_expect(self.pg0, pkts_in2out, self.pg1,
6484                                        len(pkts_in2out))
6485         self.verify_capture_out(capture, ignore_port=True)
6486
6487         # send out2in again. ACL state exists so it should work now.
6488         # TCP packets with the syn flag set also need the ack flag
6489         for p in pkts_out2in:
6490             if p.haslayer(TCP) and p[TCP].flags & 0x02:
6491                 p[TCP].flags |= 0x10
6492         capture = self.send_and_expect(self.pg1, pkts_out2in, self.pg0,
6493                                        len(pkts_out2in))
6494         self.verify_capture_in(capture, self.pg0)
6495         self.logger.info(self.vapi.cli("show trace"))
6496
6497     def test_multiple_vrf(self):
6498         """ Multiple VRF setup """
6499         external_addr = '1.2.3.4'
6500         external_port = 80
6501         local_port = 8080
6502         port = 0
6503
6504         self.vapi.nat44_forwarding_enable_disable(enable=1)
6505         self.nat44_add_address(self.nat_addr)
6506         flags = self.config_flags.NAT_IS_INSIDE
6507         self.vapi.nat44_interface_add_del_feature(
6508             sw_if_index=self.pg0.sw_if_index,
6509             is_add=1)
6510         self.vapi.nat44_interface_add_del_feature(
6511             sw_if_index=self.pg0.sw_if_index,
6512             is_add=1, flags=flags)
6513         self.vapi.nat44_interface_add_del_output_feature(
6514             sw_if_index=self.pg1.sw_if_index,
6515             is_add=1)
6516         self.vapi.nat44_interface_add_del_feature(
6517             sw_if_index=self.pg5.sw_if_index,
6518             is_add=1)
6519         self.vapi.nat44_interface_add_del_feature(
6520             sw_if_index=self.pg5.sw_if_index,
6521             is_add=1, flags=flags)
6522         self.vapi.nat44_interface_add_del_feature(
6523             sw_if_index=self.pg6.sw_if_index,
6524             is_add=1)
6525         flags = self.config_flags.NAT_IS_OUT2IN_ONLY
6526         self.nat44_add_static_mapping(self.pg5.remote_ip4, external_addr,
6527                                       local_port, external_port, vrf_id=1,
6528                                       proto=IP_PROTOS.tcp, flags=flags)
6529         self.nat44_add_static_mapping(
6530             self.pg0.remote_ip4,
6531             external_sw_if_index=self.pg0.sw_if_index,
6532             local_port=local_port,
6533             vrf_id=0,
6534             external_port=external_port,
6535             proto=IP_PROTOS.tcp,
6536             flags=flags
6537         )
6538
6539         # from client to service (both VRF1)
6540         p = (Ether(src=self.pg6.remote_mac, dst=self.pg6.local_mac) /
6541              IP(src=self.pg6.remote_ip4, dst=external_addr) /
6542              TCP(sport=12345, dport=external_port))
6543         self.pg6.add_stream(p)
6544         self.pg_enable_capture(self.pg_interfaces)
6545         self.pg_start()
6546         capture = self.pg5.get_capture(1)
6547         p = capture[0]
6548         try:
6549             ip = p[IP]
6550             tcp = p[TCP]
6551             self.assertEqual(ip.dst, self.pg5.remote_ip4)
6552             self.assertEqual(tcp.dport, local_port)
6553             self.assert_packet_checksums_valid(p)
6554         except:
6555             self.logger.error(ppp("Unexpected or invalid packet:", p))
6556             raise
6557
6558         # from service back to client (both VRF1)
6559         p = (Ether(src=self.pg5.remote_mac, dst=self.pg5.local_mac) /
6560              IP(src=self.pg5.remote_ip4, dst=self.pg6.remote_ip4) /
6561              TCP(sport=local_port, dport=12345))
6562         self.pg5.add_stream(p)
6563         self.pg_enable_capture(self.pg_interfaces)
6564         self.pg_start()
6565         capture = self.pg6.get_capture(1)
6566         p = capture[0]
6567         try:
6568             ip = p[IP]
6569             tcp = p[TCP]
6570             self.assertEqual(ip.src, external_addr)
6571             self.assertEqual(tcp.sport, external_port)
6572             self.assert_packet_checksums_valid(p)
6573         except:
6574             self.logger.error(ppp("Unexpected or invalid packet:", p))
6575             raise
6576
6577         # dynamic NAT from VRF1 to VRF0 (output-feature)
6578         p = (Ether(src=self.pg5.remote_mac, dst=self.pg5.local_mac) /
6579              IP(src=self.pg5.remote_ip4, dst=self.pg1.remote_ip4) /
6580              TCP(sport=2345, dport=22))
6581         self.pg5.add_stream(p)
6582         self.pg_enable_capture(self.pg_interfaces)
6583         self.pg_start()
6584         capture = self.pg1.get_capture(1)
6585         p = capture[0]
6586         try:
6587             ip = p[IP]
6588             tcp = p[TCP]
6589             self.assertEqual(ip.src, self.nat_addr)
6590             self.assert_packet_checksums_valid(p)
6591             port = tcp.sport
6592         except:
6593             self.logger.error(ppp("Unexpected or invalid packet:", p))
6594             raise
6595
6596         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
6597              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
6598              TCP(sport=22, dport=port))
6599         self.pg1.add_stream(p)
6600         self.pg_enable_capture(self.pg_interfaces)
6601         self.pg_start()
6602         capture = self.pg5.get_capture(1)
6603         p = capture[0]
6604         try:
6605             ip = p[IP]
6606             tcp = p[TCP]
6607             self.assertEqual(ip.dst, self.pg5.remote_ip4)
6608             self.assertEqual(tcp.dport, 2345)
6609             self.assert_packet_checksums_valid(p)
6610         except:
6611             self.logger.error(ppp("Unexpected or invalid packet:", p))
6612             raise
6613
6614         # from client VRF1 to service VRF0
6615         p = (Ether(src=self.pg6.remote_mac, dst=self.pg6.local_mac) /
6616              IP(src=self.pg6.remote_ip4, dst=self.pg0.local_ip4) /
6617              TCP(sport=12346, dport=external_port))
6618         self.pg6.add_stream(p)
6619         self.pg_enable_capture(self.pg_interfaces)
6620         self.pg_start()
6621         capture = self.pg0.get_capture(1)
6622         p = capture[0]
6623         try:
6624             ip = p[IP]
6625             tcp = p[TCP]
6626             self.assertEqual(ip.dst, self.pg0.remote_ip4)
6627             self.assertEqual(tcp.dport, local_port)
6628             self.assert_packet_checksums_valid(p)
6629         except:
6630             self.logger.error(ppp("Unexpected or invalid packet:", p))
6631             raise
6632
6633         # from service VRF0 back to client VRF1
6634         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6635              IP(src=self.pg0.remote_ip4, dst=self.pg6.remote_ip4) /
6636              TCP(sport=local_port, dport=12346))
6637         self.pg0.add_stream(p)
6638         self.pg_enable_capture(self.pg_interfaces)
6639         self.pg_start()
6640         capture = self.pg6.get_capture(1)
6641         p = capture[0]
6642         try:
6643             ip = p[IP]
6644             tcp = p[TCP]
6645             self.assertEqual(ip.src, self.pg0.local_ip4)
6646             self.assertEqual(tcp.sport, external_port)
6647             self.assert_packet_checksums_valid(p)
6648         except:
6649             self.logger.error(ppp("Unexpected or invalid packet:", p))
6650             raise
6651
6652         # from client VRF0 to service VRF1
6653         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6654              IP(src=self.pg0.remote_ip4, dst=external_addr) /
6655              TCP(sport=12347, dport=external_port))
6656         self.pg0.add_stream(p)
6657         self.pg_enable_capture(self.pg_interfaces)
6658         self.pg_start()
6659         capture = self.pg5.get_capture(1)
6660         p = capture[0]
6661         try:
6662             ip = p[IP]
6663             tcp = p[TCP]
6664             self.assertEqual(ip.dst, self.pg5.remote_ip4)
6665             self.assertEqual(tcp.dport, local_port)
6666             self.assert_packet_checksums_valid(p)
6667         except:
6668             self.logger.error(ppp("Unexpected or invalid packet:", p))
6669             raise
6670
6671         # from service VRF1 back to client VRF0
6672         p = (Ether(src=self.pg5.remote_mac, dst=self.pg5.local_mac) /
6673              IP(src=self.pg5.remote_ip4, dst=self.pg0.remote_ip4) /
6674              TCP(sport=local_port, dport=12347))
6675         self.pg5.add_stream(p)
6676         self.pg_enable_capture(self.pg_interfaces)
6677         self.pg_start()
6678         capture = self.pg0.get_capture(1)
6679         p = capture[0]
6680         try:
6681             ip = p[IP]
6682             tcp = p[TCP]
6683             self.assertEqual(ip.src, external_addr)
6684             self.assertEqual(tcp.sport, external_port)
6685             self.assert_packet_checksums_valid(p)
6686         except:
6687             self.logger.error(ppp("Unexpected or invalid packet:", p))
6688             raise
6689
6690         # from client to server (both VRF1, no translation)
6691         p = (Ether(src=self.pg6.remote_mac, dst=self.pg6.local_mac) /
6692              IP(src=self.pg6.remote_ip4, dst=self.pg5.remote_ip4) /
6693              TCP(sport=12348, dport=local_port))
6694         self.pg6.add_stream(p)
6695         self.pg_enable_capture(self.pg_interfaces)
6696         self.pg_start()
6697         capture = self.pg5.get_capture(1)
6698         p = capture[0]
6699         try:
6700             ip = p[IP]
6701             tcp = p[TCP]
6702             self.assertEqual(ip.dst, self.pg5.remote_ip4)
6703             self.assertEqual(tcp.dport, local_port)
6704             self.assert_packet_checksums_valid(p)
6705         except:
6706             self.logger.error(ppp("Unexpected or invalid packet:", p))
6707             raise
6708
6709         # from server back to client (both VRF1, no translation)
6710         p = (Ether(src=self.pg5.remote_mac, dst=self.pg5.local_mac) /
6711              IP(src=self.pg5.remote_ip4, dst=self.pg6.remote_ip4) /
6712              TCP(sport=local_port, dport=12348))
6713         self.pg5.add_stream(p)
6714         self.pg_enable_capture(self.pg_interfaces)
6715         self.pg_start()
6716         capture = self.pg6.get_capture(1)
6717         p = capture[0]
6718         try:
6719             ip = p[IP]
6720             tcp = p[TCP]
6721             self.assertEqual(ip.src, self.pg5.remote_ip4)
6722             self.assertEqual(tcp.sport, local_port)
6723             self.assert_packet_checksums_valid(p)
6724         except:
6725             self.logger.error(ppp("Unexpected or invalid packet:", p))
6726             raise
6727
6728         # from client VRF1 to server VRF0 (no translation)
6729         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6730              IP(src=self.pg0.remote_ip4, dst=self.pg6.remote_ip4) /
6731              TCP(sport=local_port, dport=12349))
6732         self.pg0.add_stream(p)
6733         self.pg_enable_capture(self.pg_interfaces)
6734         self.pg_start()
6735         capture = self.pg6.get_capture(1)
6736         p = capture[0]
6737         try:
6738             ip = p[IP]
6739             tcp = p[TCP]
6740             self.assertEqual(ip.src, self.pg0.remote_ip4)
6741             self.assertEqual(tcp.sport, local_port)
6742             self.assert_packet_checksums_valid(p)
6743         except:
6744             self.logger.error(ppp("Unexpected or invalid packet:", p))
6745             raise
6746
6747         # from server VRF0 back to client VRF1 (no translation)
6748         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6749              IP(src=self.pg0.remote_ip4, dst=self.pg6.remote_ip4) /
6750              TCP(sport=local_port, dport=12349))
6751         self.pg0.add_stream(p)
6752         self.pg_enable_capture(self.pg_interfaces)
6753         self.pg_start()
6754         capture = self.pg6.get_capture(1)
6755         p = capture[0]
6756         try:
6757             ip = p[IP]
6758             tcp = p[TCP]
6759             self.assertEqual(ip.src, self.pg0.remote_ip4)
6760             self.assertEqual(tcp.sport, local_port)
6761             self.assert_packet_checksums_valid(p)
6762         except:
6763             self.logger.error(ppp("Unexpected or invalid packet:", p))
6764             raise
6765
6766         # from client VRF0 to server VRF1 (no translation)
6767         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6768              IP(src=self.pg0.remote_ip4, dst=self.pg5.remote_ip4) /
6769              TCP(sport=12344, dport=local_port))
6770         self.pg0.add_stream(p)
6771         self.pg_enable_capture(self.pg_interfaces)
6772         self.pg_start()
6773         capture = self.pg5.get_capture(1)
6774         p = capture[0]
6775         try:
6776             ip = p[IP]
6777             tcp = p[TCP]
6778             self.assertEqual(ip.dst, self.pg5.remote_ip4)
6779             self.assertEqual(tcp.dport, local_port)
6780             self.assert_packet_checksums_valid(p)
6781         except:
6782             self.logger.error(ppp("Unexpected or invalid packet:", p))
6783             raise
6784
6785         # from server VRF1 back to client VRF0 (no translation)
6786         p = (Ether(src=self.pg5.remote_mac, dst=self.pg5.local_mac) /
6787              IP(src=self.pg5.remote_ip4, dst=self.pg0.remote_ip4) /
6788              TCP(sport=local_port, dport=12344))
6789         self.pg5.add_stream(p)
6790         self.pg_enable_capture(self.pg_interfaces)
6791         self.pg_start()
6792         capture = self.pg0.get_capture(1)
6793         p = capture[0]
6794         try:
6795             ip = p[IP]
6796             tcp = p[TCP]
6797             self.assertEqual(ip.src, self.pg5.remote_ip4)
6798             self.assertEqual(tcp.sport, local_port)
6799             self.assert_packet_checksums_valid(p)
6800         except:
6801             self.logger.error(ppp("Unexpected or invalid packet:", p))
6802             raise
6803
6804     @unittest.skipUnless(running_extended_tests, "part of extended tests")
6805     def test_session_timeout(self):
6806         """ NAT44 session timeouts """
6807         self.nat44_add_address(self.nat_addr)
6808         flags = self.config_flags.NAT_IS_INSIDE
6809         self.vapi.nat44_interface_add_del_feature(
6810             sw_if_index=self.pg0.sw_if_index,
6811             flags=flags, is_add=1)
6812         self.vapi.nat44_interface_add_del_feature(
6813             sw_if_index=self.pg1.sw_if_index,
6814             is_add=1)
6815         self.vapi.nat_set_timeouts(udp=300, tcp_established=7440,
6816                                    tcp_transitory=240, icmp=5)
6817
6818         max_sessions = 1000
6819         pkts = []
6820         for i in range(0, max_sessions):
6821             src = "10.10.%u.%u" % ((i & 0xFF00) >> 8, i & 0xFF)
6822             p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
6823                  IP(src=src, dst=self.pg1.remote_ip4) /
6824                  ICMP(id=1025, type='echo-request'))
6825             pkts.append(p)
6826         self.pg0.add_stream(pkts)
6827         self.pg_enable_capture(self.pg_interfaces)
6828         self.pg_start()
6829         self.pg1.get_capture(max_sessions)
6830
6831         sleep(10)
6832
6833         pkts = []
6834         for i in range(0, max_sessions):
6835             src = "10.11.%u.%u" % ((i & 0xFF00) >> 8, i & 0xFF)
6836             p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
6837                  IP(src=src, dst=self.pg1.remote_ip4) /
6838                  ICMP(id=1026, type='echo-request'))
6839             pkts.append(p)
6840         self.pg0.add_stream(pkts)
6841         self.pg_enable_capture(self.pg_interfaces)
6842         self.pg_start()
6843         self.pg1.get_capture(max_sessions)
6844
6845         nsessions = 0
6846         users = self.vapi.nat44_user_dump()
6847         for user in users:
6848             nsessions = nsessions + user.nsessions
6849         self.assertLess(nsessions, 2 * max_sessions)
6850
6851     @unittest.skipUnless(running_extended_tests, "part of extended tests")
6852     def test_session_rst_timeout(self):
6853         """ NAT44 session RST timeouts """
6854         self.nat44_add_address(self.nat_addr)
6855         flags = self.config_flags.NAT_IS_INSIDE
6856         self.vapi.nat44_interface_add_del_feature(
6857             sw_if_index=self.pg0.sw_if_index,
6858             flags=flags, is_add=1)
6859         self.vapi.nat44_interface_add_del_feature(
6860             sw_if_index=self.pg1.sw_if_index,
6861             is_add=1)
6862         self.vapi.nat_set_timeouts(udp=300, tcp_established=7440,
6863                                    tcp_transitory=5, icmp=60)
6864
6865         self.initiate_tcp_session(self.pg0, self.pg1)
6866         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6867              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6868              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
6869                  flags="R"))
6870         self.pg0.add_stream(p)
6871         self.pg_enable_capture(self.pg_interfaces)
6872         self.pg_start()
6873         self.pg1.get_capture(1)
6874
6875         sleep(6)
6876
6877         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6878              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6879              TCP(sport=self.tcp_port_in + 1, dport=self.tcp_external_port + 1,
6880                  flags="S"))
6881         self.pg0.add_stream(p)
6882         self.pg_enable_capture(self.pg_interfaces)
6883         self.pg_start()
6884         self.pg1.get_capture(1)
6885
6886     def test_syslog_sess(self):
6887         """ Test syslog session creation and deletion """
6888         self.vapi.syslog_set_filter(
6889             self.SYSLOG_SEVERITY.SYSLOG_API_SEVERITY_INFO)
6890         self.vapi.syslog_set_sender(self.pg2.local_ip4, self.pg2.remote_ip4)
6891         self.nat44_add_address(self.nat_addr)
6892         flags = self.config_flags.NAT_IS_INSIDE
6893         self.vapi.nat44_interface_add_del_feature(
6894             sw_if_index=self.pg0.sw_if_index,
6895             flags=flags, is_add=1)
6896         self.vapi.nat44_interface_add_del_feature(
6897             sw_if_index=self.pg1.sw_if_index,
6898             is_add=1)
6899
6900         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
6901              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6902              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port))
6903         self.pg0.add_stream(p)
6904         self.pg_enable_capture(self.pg_interfaces)
6905         self.pg_start()
6906         capture = self.pg1.get_capture(1)
6907         self.tcp_port_out = capture[0][TCP].sport
6908         capture = self.pg2.get_capture(1)
6909         self.verify_syslog_sess(capture[0][Raw].load)
6910
6911         self.pg_enable_capture(self.pg_interfaces)
6912         self.pg_start()
6913         self.nat44_add_address(self.nat_addr, is_add=0)
6914         capture = self.pg2.get_capture(1)
6915         self.verify_syslog_sess(capture[0][Raw].load, False)
6916
6917     def test_ed_users_dump(self):
6918         """ API test - nat44_user_dump """
6919         flags = self.config_flags.NAT_IS_INSIDE
6920         self.vapi.nat44_interface_add_del_feature(
6921             sw_if_index=self.pg0.sw_if_index,
6922             flags=flags, is_add=1)
6923         self.vapi.nat44_interface_add_del_feature(
6924             sw_if_index=self.pg1.sw_if_index,
6925             is_add=1)
6926         self.vapi.nat44_forwarding_enable_disable(enable=1)
6927
6928         real_ip = self.pg0.remote_ip4
6929         alias_ip = self.nat_addr
6930         flags = self.config_flags.NAT_IS_ADDR_ONLY
6931         self.vapi.nat44_add_del_static_mapping(is_add=1,
6932                                                local_ip_address=real_ip,
6933                                                external_ip_address=alias_ip,
6934                                                external_sw_if_index=0xFFFFFFFF,
6935                                                flags=flags)
6936
6937         users = self.vapi.nat44_user_dump()
6938         self.assertEqual(len(users), 0)
6939         try:
6940             # in2out - static mapping match
6941
6942             pkts = self.create_stream_out(self.pg1)
6943             self.pg1.add_stream(pkts)
6944             self.pg_enable_capture(self.pg_interfaces)
6945             self.pg_start()
6946             capture = self.pg0.get_capture(len(pkts))
6947             self.verify_capture_in(capture, self.pg0)
6948
6949             pkts = self.create_stream_in(self.pg0, self.pg1)
6950             self.pg0.add_stream(pkts)
6951             self.pg_enable_capture(self.pg_interfaces)
6952             self.pg_start()
6953             capture = self.pg1.get_capture(len(pkts))
6954             self.verify_capture_out(capture, same_port=True)
6955
6956             users = self.vapi.nat44_user_dump()
6957             self.assertEqual(len(users), 1)
6958             static_user = users[0]
6959             self.assertEqual(static_user.nstaticsessions, 3)
6960             self.assertEqual(static_user.nsessions, 0)
6961
6962             # in2out - no static mapping match
6963
6964             host0 = self.pg0.remote_hosts[0]
6965             self.pg0.remote_hosts[0] = self.pg0.remote_hosts[1]
6966             try:
6967                 pkts = self.create_stream_out(self.pg1,
6968                                               dst_ip=self.pg0.remote_ip4,
6969                                               use_inside_ports=True)
6970                 self.pg1.add_stream(pkts)
6971                 self.pg_enable_capture(self.pg_interfaces)
6972                 self.pg_start()
6973                 capture = self.pg0.get_capture(len(pkts))
6974                 self.verify_capture_in(capture, self.pg0)
6975
6976                 pkts = self.create_stream_in(self.pg0, self.pg1)
6977                 self.pg0.add_stream(pkts)
6978                 self.pg_enable_capture(self.pg_interfaces)
6979                 self.pg_start()
6980                 capture = self.pg1.get_capture(len(pkts))
6981                 self.verify_capture_out(capture, nat_ip=self.pg0.remote_ip4,
6982                                         same_port=True)
6983             finally:
6984                 self.pg0.remote_hosts[0] = host0
6985
6986             users = self.vapi.nat44_user_dump()
6987             self.assertEqual(len(users), 2)
6988             if str(users[0].ip_address) == self.pg0.remote_hosts[0].ip4:
6989                 non_static_user = users[1]
6990                 static_user = users[0]
6991             else:
6992                 non_static_user = users[0]
6993                 static_user = users[1]
6994             self.assertEqual(static_user.nstaticsessions, 3)
6995             self.assertEqual(static_user.nsessions, 0)
6996             self.assertEqual(non_static_user.nstaticsessions, 0)
6997             self.assertEqual(non_static_user.nsessions, 3)
6998
6999             users = self.vapi.nat44_user_dump()
7000             self.assertEqual(len(users), 2)
7001             if str(users[0].ip_address) == self.pg0.remote_hosts[0].ip4:
7002                 non_static_user = users[1]
7003                 static_user = users[0]
7004             else:
7005                 non_static_user = users[0]
7006                 static_user = users[1]
7007             self.assertEqual(static_user.nstaticsessions, 3)
7008             self.assertEqual(static_user.nsessions, 0)
7009             self.assertEqual(non_static_user.nstaticsessions, 0)
7010             self.assertEqual(non_static_user.nsessions, 3)
7011
7012         finally:
7013             self.vapi.nat44_forwarding_enable_disable(enable=0)
7014             flags = self.config_flags.NAT_IS_ADDR_ONLY
7015             self.vapi.nat44_add_del_static_mapping(
7016                 is_add=0,
7017                 local_ip_address=real_ip,
7018                 external_ip_address=alias_ip,
7019                 external_sw_if_index=0xFFFFFFFF,
7020                 flags=flags)
7021
7022     def show_commands_at_teardown(self):
7023         self.logger.info(self.vapi.cli("show errors"))
7024         self.logger.info(self.vapi.cli("show nat44 addresses"))
7025         self.logger.info(self.vapi.cli("show nat44 interfaces"))
7026         self.logger.info(self.vapi.cli("show nat44 static mappings"))
7027         self.logger.info(self.vapi.cli("show nat44 interface address"))
7028         self.logger.info(self.vapi.cli("show nat44 sessions detail"))
7029         self.logger.info(self.vapi.cli("show nat44 hash tables detail"))
7030         self.logger.info(self.vapi.cli("show nat timeouts"))
7031         self.logger.info(self.vapi.cli("debug nat44 fib registration"))
7032
7033
7034 class TestNAT44EndpointDependent3(MethodHolder):
7035     """ Endpoint-Dependent mapping and filtering extra test cases """
7036
7037     max_translations = 50
7038
7039     @classmethod
7040     def setUpClass(cls):
7041         super(TestNAT44EndpointDependent3, cls).setUpClass()
7042         cls.vapi.cli("set log class nat level debug")
7043
7044         cls.nat_addr = '10.0.0.3'
7045
7046         cls.create_pg_interfaces(range(2))
7047
7048         for i in cls.pg_interfaces:
7049             i.admin_up()
7050             i.config_ip4()
7051             i.resolve_arp()
7052
7053     def setUp(self):
7054         super(TestNAT44EndpointDependent3, self).setUp()
7055         flags = self.nat44_config_flags.NAT44_IS_ENDPOINT_DEPENDENT
7056         self.vapi.nat44_plugin_enable_disable(
7057             sessions=self.max_translations,
7058             flags=flags, enable=1)
7059         self.vapi.nat_set_timeouts(
7060             udp=1, tcp_established=7440, tcp_transitory=30, icmp=1)
7061
7062         self.nat44_add_address(self.nat_addr)
7063         flags = self.config_flags.NAT_IS_INSIDE
7064         self.vapi.nat44_interface_add_del_feature(
7065             sw_if_index=self.pg0.sw_if_index, flags=flags, is_add=1)
7066         self.vapi.nat44_interface_add_del_feature(
7067             sw_if_index=self.pg1.sw_if_index, is_add=1)
7068
7069     @classmethod
7070     def tearDownClass(cls):
7071         super(TestNAT44EndpointDependent3, cls).tearDownClass()
7072
7073     def tearDown(self):
7074         super(TestNAT44EndpointDependent3, self).tearDown()
7075         if not self.vpp_dead:
7076             self.vapi.nat44_plugin_enable_disable(enable=0)
7077             self.vapi.cli("clear logging")
7078
7079     def init_tcp_session(self, in_if, out_if, sport, ext_dport):
7080         # SYN packet in->out
7081         p = (Ether(src=in_if.remote_mac, dst=in_if.local_mac) /
7082              IP(src=in_if.remote_ip4, dst=out_if.remote_ip4) /
7083              TCP(sport=sport, dport=ext_dport, flags="S"))
7084         in_if.add_stream(p)
7085         self.pg_enable_capture(self.pg_interfaces)
7086         self.pg_start()
7087         capture = out_if.get_capture(1)
7088         p = capture[0]
7089         tcp_port_out = p[TCP].sport
7090
7091         # SYN + ACK packet out->in
7092         p = (Ether(src=out_if.remote_mac, dst=out_if.local_mac) /
7093              IP(src=out_if.remote_ip4, dst=self.nat_addr) /
7094              TCP(sport=ext_dport, dport=tcp_port_out, flags="SA"))
7095         out_if.add_stream(p)
7096         self.pg_enable_capture(self.pg_interfaces)
7097         self.pg_start()
7098         in_if.get_capture(1)
7099
7100         # ACK packet in->out
7101         p = (Ether(src=in_if.remote_mac, dst=in_if.local_mac) /
7102              IP(src=in_if.remote_ip4, dst=out_if.remote_ip4) /
7103              TCP(sport=sport, dport=ext_dport, flags="A"))
7104         in_if.add_stream(p)
7105         self.pg_enable_capture(self.pg_interfaces)
7106         self.pg_start()
7107         out_if.get_capture(1)
7108
7109         return tcp_port_out
7110
7111     def test_lru_cleanup(self):
7112         """ LRU cleanup algorithm """
7113         tcp_port_out = self.init_tcp_session(self.pg0, self.pg1, 2000, 80)
7114         pkts = []
7115         for i in range(0, self.max_translations - 1):
7116             p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
7117                  IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4, ttl=64) /
7118                  UDP(sport=7000+i, dport=80))
7119             pkts.append(p)
7120
7121         self.pg0.add_stream(pkts)
7122         self.pg_enable_capture(self.pg_interfaces)
7123         self.pg_start()
7124         self.pg1.get_capture(len(pkts))
7125         self.sleep(1.5, "wait for timeouts")
7126
7127         pkts = []
7128         for i in range(0, self.max_translations - 1):
7129             p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
7130                  IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4, ttl=64) /
7131                  ICMP(id=8000+i, type='echo-request'))
7132             pkts.append(p)
7133
7134         self.pg0.add_stream(pkts)
7135         self.pg_enable_capture(self.pg_interfaces)
7136         self.pg_start()
7137         self.pg1.get_capture(len(pkts))
7138
7139
7140 class TestNAT44Out2InDPO(MethodHolder):
7141     """ NAT44 Test Cases using out2in DPO """
7142
7143     @classmethod
7144     def setUpClass(cls):
7145         super(TestNAT44Out2InDPO, cls).setUpClass()
7146         cls.vapi.cli("set log class nat level debug")
7147
7148         cls.tcp_port_in = 6303
7149         cls.tcp_port_out = 6303
7150         cls.udp_port_in = 6304
7151         cls.udp_port_out = 6304
7152         cls.icmp_id_in = 6305
7153         cls.icmp_id_out = 6305
7154         cls.nat_addr = '10.0.0.3'
7155         cls.dst_ip4 = '192.168.70.1'
7156
7157         cls.create_pg_interfaces(range(2))
7158
7159         cls.pg0.admin_up()
7160         cls.pg0.config_ip4()
7161         cls.pg0.resolve_arp()
7162
7163         cls.pg1.admin_up()
7164         cls.pg1.config_ip6()
7165         cls.pg1.resolve_ndp()
7166
7167         r1 = VppIpRoute(cls, "::", 0,
7168                         [VppRoutePath(cls.pg1.remote_ip6,
7169                                       cls.pg1.sw_if_index)],
7170                         register=False)
7171         r1.add_vpp_config()
7172
7173     @classmethod
7174     def tearDownClass(cls):
7175         super(TestNAT44Out2InDPO, cls).tearDownClass()
7176
7177     def setUp(self):
7178         super(TestNAT44Out2InDPO, self).setUp()
7179         flags = self.nat44_config_flags.NAT44_API_IS_OUT2IN_DPO
7180         self.vapi.nat44_plugin_enable_disable(enable=1, flags=flags)
7181
7182     def tearDown(self):
7183         super(TestNAT44Out2InDPO, self).tearDown()
7184         if not self.vpp_dead:
7185             self.vapi.nat44_plugin_enable_disable(enable=0)
7186             self.vapi.cli("clear logging")
7187
7188     def configure_xlat(self):
7189         self.dst_ip6_pfx = '1:2:3::'
7190         self.dst_ip6_pfx_n = socket.inet_pton(socket.AF_INET6,
7191                                               self.dst_ip6_pfx)
7192         self.dst_ip6_pfx_len = 96
7193         self.src_ip6_pfx = '4:5:6::'
7194         self.src_ip6_pfx_n = socket.inet_pton(socket.AF_INET6,
7195                                               self.src_ip6_pfx)
7196         self.src_ip6_pfx_len = 96
7197         self.vapi.map_add_domain(self.dst_ip6_pfx_n, self.dst_ip6_pfx_len,
7198                                  self.src_ip6_pfx_n, self.src_ip6_pfx_len,
7199                                  '\x00\x00\x00\x00', 0)
7200
7201     @unittest.skip('Temporary disabled')
7202     def test_464xlat_ce(self):
7203         """ Test 464XLAT CE with NAT44 """
7204
7205         nat_config = self.vapi.nat_show_config()
7206         self.assertEqual(1, nat_config.out2in_dpo)
7207
7208         self.configure_xlat()
7209
7210         flags = self.config_flags.NAT_IS_INSIDE
7211         self.vapi.nat44_interface_add_del_feature(
7212             sw_if_index=self.pg0.sw_if_index,
7213             flags=flags, is_add=1)
7214         self.vapi.nat44_add_del_address_range(first_ip_address=self.nat_addr_n,
7215                                               last_ip_address=self.nat_addr_n,
7216                                               vrf_id=0xFFFFFFFF, is_add=1)
7217
7218         out_src_ip6 = self.compose_ip6(self.dst_ip4, self.dst_ip6_pfx,
7219                                        self.dst_ip6_pfx_len)
7220         out_dst_ip6 = self.compose_ip6(self.nat_addr, self.src_ip6_pfx,
7221                                        self.src_ip6_pfx_len)
7222
7223         try:
7224             pkts = self.create_stream_in(self.pg0, self.pg1, self.dst_ip4)
7225             self.pg0.add_stream(pkts)
7226             self.pg_enable_capture(self.pg_interfaces)
7227             self.pg_start()
7228             capture = self.pg1.get_capture(len(pkts))
7229             self.verify_capture_out_ip6(capture, nat_ip=out_dst_ip6,
7230                                         dst_ip=out_src_ip6)
7231
7232             pkts = self.create_stream_out_ip6(self.pg1, out_src_ip6,
7233                                               out_dst_ip6)
7234             self.pg1.add_stream(pkts)
7235             self.pg_enable_capture(self.pg_interfaces)
7236             self.pg_start()
7237             capture = self.pg0.get_capture(len(pkts))
7238             self.verify_capture_in(capture, self.pg0)
7239         finally:
7240             self.vapi.nat44_interface_add_del_feature(
7241                 sw_if_index=self.pg0.sw_if_index,
7242                 flags=flags)
7243             self.vapi.nat44_add_del_address_range(
7244                 first_ip_address=self.nat_addr_n,
7245                 last_ip_address=self.nat_addr_n,
7246                 vrf_id=0xFFFFFFFF)
7247
7248     @unittest.skip('Temporary disabled')
7249     def test_464xlat_ce_no_nat(self):
7250         """ Test 464XLAT CE without NAT44 """
7251
7252         self.configure_xlat()
7253
7254         out_src_ip6 = self.compose_ip6(self.dst_ip4, self.dst_ip6_pfx,
7255                                        self.dst_ip6_pfx_len)
7256         out_dst_ip6 = self.compose_ip6(self.pg0.remote_ip4, self.src_ip6_pfx,
7257                                        self.src_ip6_pfx_len)
7258
7259         pkts = self.create_stream_in(self.pg0, self.pg1, self.dst_ip4)
7260         self.pg0.add_stream(pkts)
7261         self.pg_enable_capture(self.pg_interfaces)
7262         self.pg_start()
7263         capture = self.pg1.get_capture(len(pkts))
7264         self.verify_capture_out_ip6(capture, dst_ip=out_src_ip6,
7265                                     nat_ip=out_dst_ip6, same_port=True)
7266
7267         pkts = self.create_stream_out_ip6(self.pg1, out_src_ip6, out_dst_ip6)
7268         self.pg1.add_stream(pkts)
7269         self.pg_enable_capture(self.pg_interfaces)
7270         self.pg_start()
7271         capture = self.pg0.get_capture(len(pkts))
7272         self.verify_capture_in(capture, self.pg0)
7273
7274
7275 if __name__ == '__main__':
7276     unittest.main(testRunner=VppTestRunner)