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