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