fd011230b2bc2d697ad689716ced87fdf20600ce
[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_add_del_output_interface(
2835             sw_if_index=self.pg3.sw_if_index, is_add=1)
2836
2837         # in2out
2838         pkts = self.create_stream_in(self.pg0, self.pg3)
2839         self.pg0.add_stream(pkts)
2840         self.pg_enable_capture(self.pg_interfaces)
2841         self.pg_start()
2842         capture = self.pg3.get_capture(len(pkts))
2843         self.verify_capture_out(capture)
2844
2845         # out2in
2846         pkts = self.create_stream_out(self.pg3)
2847         self.pg3.add_stream(pkts)
2848         self.pg_enable_capture(self.pg_interfaces)
2849         self.pg_start()
2850         capture = self.pg0.get_capture(len(pkts))
2851         self.verify_capture_in(capture, self.pg0)
2852
2853         # from non-NAT interface to NAT inside interface
2854         pkts = self.create_stream_in(self.pg2, self.pg0)
2855         self.pg2.add_stream(pkts)
2856         self.pg_enable_capture(self.pg_interfaces)
2857         self.pg_start()
2858         capture = self.pg0.get_capture(len(pkts))
2859         self.verify_capture_no_translation(capture, self.pg2, self.pg0)
2860
2861     def test_output_feature_vrf_aware(self):
2862         """ NAT44EI output feature VRF aware (in2out postrouting) """
2863         nat_ip_vrf10 = "10.0.0.10"
2864         nat_ip_vrf20 = "10.0.0.20"
2865
2866         r1 = VppIpRoute(self, self.pg3.remote_ip4, 32,
2867                         [VppRoutePath(self.pg3.remote_ip4,
2868                                       self.pg3.sw_if_index)],
2869                         table_id=10)
2870         r2 = VppIpRoute(self, self.pg3.remote_ip4, 32,
2871                         [VppRoutePath(self.pg3.remote_ip4,
2872                                       self.pg3.sw_if_index)],
2873                         table_id=20)
2874         r1.add_vpp_config()
2875         r2.add_vpp_config()
2876
2877         self.nat44_add_address(nat_ip_vrf10, vrf_id=10)
2878         self.nat44_add_address(nat_ip_vrf20, vrf_id=20)
2879         self.vapi.nat44_ei_add_del_output_interface(
2880             sw_if_index=self.pg3.sw_if_index, is_add=1)
2881
2882         # in2out VRF 10
2883         pkts = self.create_stream_in(self.pg4, self.pg3)
2884         self.pg4.add_stream(pkts)
2885         self.pg_enable_capture(self.pg_interfaces)
2886         self.pg_start()
2887         capture = self.pg3.get_capture(len(pkts))
2888         self.verify_capture_out(capture, nat_ip=nat_ip_vrf10)
2889
2890         # out2in VRF 10
2891         pkts = self.create_stream_out(self.pg3, dst_ip=nat_ip_vrf10)
2892         self.pg3.add_stream(pkts)
2893         self.pg_enable_capture(self.pg_interfaces)
2894         self.pg_start()
2895         capture = self.pg4.get_capture(len(pkts))
2896         self.verify_capture_in(capture, self.pg4)
2897
2898         # in2out VRF 20
2899         pkts = self.create_stream_in(self.pg6, self.pg3)
2900         self.pg6.add_stream(pkts)
2901         self.pg_enable_capture(self.pg_interfaces)
2902         self.pg_start()
2903         capture = self.pg3.get_capture(len(pkts))
2904         self.verify_capture_out(capture, nat_ip=nat_ip_vrf20)
2905
2906         # out2in VRF 20
2907         pkts = self.create_stream_out(self.pg3, dst_ip=nat_ip_vrf20)
2908         self.pg3.add_stream(pkts)
2909         self.pg_enable_capture(self.pg_interfaces)
2910         self.pg_start()
2911         capture = self.pg6.get_capture(len(pkts))
2912         self.verify_capture_in(capture, self.pg6)
2913
2914     def test_output_feature_hairpinning(self):
2915         """ NAT44EI output feature hairpinning (in2out postrouting) """
2916         host = self.pg0.remote_hosts[0]
2917         server = self.pg0.remote_hosts[1]
2918         host_in_port = 1234
2919         host_out_port = 0
2920         server_in_port = 5678
2921         server_out_port = 8765
2922
2923         self.nat44_add_address(self.nat_addr)
2924         self.vapi.nat44_ei_add_del_output_interface(
2925             sw_if_index=self.pg0.sw_if_index, is_add=1)
2926         self.vapi.nat44_ei_add_del_output_interface(
2927             sw_if_index=self.pg1.sw_if_index, is_add=1)
2928
2929         # add static mapping for server
2930         self.nat44_add_static_mapping(server.ip4, self.nat_addr,
2931                                       server_in_port, server_out_port,
2932                                       proto=IP_PROTOS.tcp)
2933
2934         # send packet from host to server
2935         p = (Ether(src=host.mac, dst=self.pg0.local_mac) /
2936              IP(src=host.ip4, dst=self.nat_addr) /
2937              TCP(sport=host_in_port, dport=server_out_port))
2938         self.pg0.add_stream(p)
2939         self.pg_enable_capture(self.pg_interfaces)
2940         self.pg_start()
2941         capture = self.pg0.get_capture(1)
2942         p = capture[0]
2943         try:
2944             ip = p[IP]
2945             tcp = p[TCP]
2946             self.assertEqual(ip.src, self.nat_addr)
2947             self.assertEqual(ip.dst, server.ip4)
2948             self.assertNotEqual(tcp.sport, host_in_port)
2949             self.assertEqual(tcp.dport, server_in_port)
2950             self.assert_packet_checksums_valid(p)
2951             host_out_port = tcp.sport
2952         except:
2953             self.logger.error(ppp("Unexpected or invalid packet:", p))
2954             raise
2955
2956         # send reply from server to host
2957         p = (Ether(src=server.mac, dst=self.pg0.local_mac) /
2958              IP(src=server.ip4, dst=self.nat_addr) /
2959              TCP(sport=server_in_port, dport=host_out_port))
2960         self.pg0.add_stream(p)
2961         self.pg_enable_capture(self.pg_interfaces)
2962         self.pg_start()
2963         capture = self.pg0.get_capture(1)
2964         p = capture[0]
2965         try:
2966             ip = p[IP]
2967             tcp = p[TCP]
2968             self.assertEqual(ip.src, self.nat_addr)
2969             self.assertEqual(ip.dst, host.ip4)
2970             self.assertEqual(tcp.sport, server_out_port)
2971             self.assertEqual(tcp.dport, host_in_port)
2972             self.assert_packet_checksums_valid(p)
2973         except:
2974             self.logger.error(ppp("Unexpected or invalid packet:", p))
2975             raise
2976
2977     def test_one_armed_nat44(self):
2978         """ NAT44EI One armed NAT """
2979         remote_host = self.pg9.remote_hosts[0]
2980         local_host = self.pg9.remote_hosts[1]
2981         external_port = 0
2982
2983         self.nat44_add_address(self.nat_addr)
2984         flags = self.config_flags.NAT44_EI_IF_INSIDE
2985         self.vapi.nat44_ei_interface_add_del_feature(
2986             sw_if_index=self.pg9.sw_if_index,
2987             is_add=1)
2988         self.vapi.nat44_ei_interface_add_del_feature(
2989             sw_if_index=self.pg9.sw_if_index,
2990             flags=flags, is_add=1)
2991
2992         # in2out
2993         p = (Ether(src=self.pg9.remote_mac, dst=self.pg9.local_mac) /
2994              IP(src=local_host.ip4, dst=remote_host.ip4) /
2995              TCP(sport=12345, dport=80))
2996         self.pg9.add_stream(p)
2997         self.pg_enable_capture(self.pg_interfaces)
2998         self.pg_start()
2999         capture = self.pg9.get_capture(1)
3000         p = capture[0]
3001         try:
3002             ip = p[IP]
3003             tcp = p[TCP]
3004             self.assertEqual(ip.src, self.nat_addr)
3005             self.assertEqual(ip.dst, remote_host.ip4)
3006             self.assertNotEqual(tcp.sport, 12345)
3007             external_port = tcp.sport
3008             self.assertEqual(tcp.dport, 80)
3009             self.assert_packet_checksums_valid(p)
3010         except:
3011             self.logger.error(ppp("Unexpected or invalid packet:", p))
3012             raise
3013
3014         # out2in
3015         p = (Ether(src=self.pg9.remote_mac, dst=self.pg9.local_mac) /
3016              IP(src=remote_host.ip4, dst=self.nat_addr) /
3017              TCP(sport=80, dport=external_port))
3018         self.pg9.add_stream(p)
3019         self.pg_enable_capture(self.pg_interfaces)
3020         self.pg_start()
3021         capture = self.pg9.get_capture(1)
3022         p = capture[0]
3023         try:
3024             ip = p[IP]
3025             tcp = p[TCP]
3026             self.assertEqual(ip.src, remote_host.ip4)
3027             self.assertEqual(ip.dst, local_host.ip4)
3028             self.assertEqual(tcp.sport, 80)
3029             self.assertEqual(tcp.dport, 12345)
3030             self.assert_packet_checksums_valid(p)
3031         except:
3032             self.logger.error(ppp("Unexpected or invalid packet:", p))
3033             raise
3034
3035         if self.vpp_worker_count > 1:
3036             node = "nat44-ei-handoff-classify"
3037         else:
3038             node = "nat44-ei-classify"
3039
3040         err = self.statistics.get_err_counter('/err/%s/next in2out' % node)
3041         self.assertEqual(err, 1)
3042         err = self.statistics.get_err_counter('/err/%s/next out2in' % node)
3043         self.assertEqual(err, 1)
3044
3045     def test_del_session(self):
3046         """ NAT44EI delete session """
3047         self.nat44_add_address(self.nat_addr)
3048         flags = self.config_flags.NAT44_EI_IF_INSIDE
3049         self.vapi.nat44_ei_interface_add_del_feature(
3050             sw_if_index=self.pg0.sw_if_index,
3051             flags=flags, is_add=1)
3052         self.vapi.nat44_ei_interface_add_del_feature(
3053             sw_if_index=self.pg1.sw_if_index,
3054             is_add=1)
3055
3056         pkts = self.create_stream_in(self.pg0, self.pg1)
3057         self.pg0.add_stream(pkts)
3058         self.pg_enable_capture(self.pg_interfaces)
3059         self.pg_start()
3060         self.pg1.get_capture(len(pkts))
3061
3062         sessions = self.vapi.nat44_ei_user_session_dump(self.pg0.remote_ip4, 0)
3063         nsessions = len(sessions)
3064
3065         self.vapi.nat44_ei_del_session(
3066             address=sessions[0].inside_ip_address,
3067             port=sessions[0].inside_port,
3068             protocol=sessions[0].protocol,
3069             flags=self.config_flags.NAT44_EI_IF_INSIDE)
3070
3071         self.vapi.nat44_ei_del_session(
3072             address=sessions[1].outside_ip_address,
3073             port=sessions[1].outside_port,
3074             protocol=sessions[1].protocol)
3075
3076         sessions = self.vapi.nat44_ei_user_session_dump(self.pg0.remote_ip4, 0)
3077         self.assertEqual(nsessions - len(sessions), 2)
3078
3079         self.vapi.nat44_ei_del_session(
3080             address=sessions[0].inside_ip_address,
3081             port=sessions[0].inside_port,
3082             protocol=sessions[0].protocol,
3083             flags=self.config_flags.NAT44_EI_IF_INSIDE)
3084
3085         self.verify_no_nat44_user()
3086
3087     def test_frag_in_order(self):
3088         """ NAT44EI translate fragments arriving in order """
3089
3090         self.nat44_add_address(self.nat_addr)
3091         flags = self.config_flags.NAT44_EI_IF_INSIDE
3092         self.vapi.nat44_ei_interface_add_del_feature(
3093             sw_if_index=self.pg0.sw_if_index,
3094             flags=flags, is_add=1)
3095         self.vapi.nat44_ei_interface_add_del_feature(
3096             sw_if_index=self.pg1.sw_if_index,
3097             is_add=1)
3098
3099         self.frag_in_order(proto=IP_PROTOS.tcp)
3100         self.frag_in_order(proto=IP_PROTOS.udp)
3101         self.frag_in_order(proto=IP_PROTOS.icmp)
3102
3103     def test_frag_forwarding(self):
3104         """ NAT44EI forwarding fragment test """
3105         self.vapi.nat44_ei_add_del_interface_addr(
3106             is_add=1,
3107             sw_if_index=self.pg1.sw_if_index)
3108         flags = self.config_flags.NAT44_EI_IF_INSIDE
3109         self.vapi.nat44_ei_interface_add_del_feature(
3110             sw_if_index=self.pg0.sw_if_index,
3111             flags=flags, is_add=1)
3112         self.vapi.nat44_ei_interface_add_del_feature(
3113             sw_if_index=self.pg1.sw_if_index,
3114             is_add=1)
3115         self.vapi.nat44_ei_forwarding_enable_disable(enable=1)
3116
3117         data = b"A" * 16 + b"B" * 16 + b"C" * 3
3118         pkts = self.create_stream_frag(self.pg1,
3119                                        self.pg0.remote_ip4,
3120                                        4789,
3121                                        4789,
3122                                        data,
3123                                        proto=IP_PROTOS.udp)
3124         self.pg1.add_stream(pkts)
3125         self.pg_enable_capture(self.pg_interfaces)
3126         self.pg_start()
3127         frags = self.pg0.get_capture(len(pkts))
3128         p = self.reass_frags_and_verify(frags,
3129                                         self.pg1.remote_ip4,
3130                                         self.pg0.remote_ip4)
3131         self.assertEqual(p[UDP].sport, 4789)
3132         self.assertEqual(p[UDP].dport, 4789)
3133         self.assertEqual(data, p[Raw].load)
3134
3135     def test_reass_hairpinning(self):
3136         """ NAT44EI fragments hairpinning """
3137
3138         server_addr = self.pg0.remote_hosts[1].ip4
3139         host_in_port = random.randint(1025, 65535)
3140         server_in_port = random.randint(1025, 65535)
3141         server_out_port = random.randint(1025, 65535)
3142
3143         self.nat44_add_address(self.nat_addr)
3144         flags = self.config_flags.NAT44_EI_IF_INSIDE
3145         self.vapi.nat44_ei_interface_add_del_feature(
3146             sw_if_index=self.pg0.sw_if_index,
3147             flags=flags, is_add=1)
3148         self.vapi.nat44_ei_interface_add_del_feature(
3149             sw_if_index=self.pg1.sw_if_index,
3150             is_add=1)
3151         # add static mapping for server
3152         self.nat44_add_static_mapping(server_addr, self.nat_addr,
3153                                       server_in_port,
3154                                       server_out_port,
3155                                       proto=IP_PROTOS.tcp)
3156         self.nat44_add_static_mapping(server_addr, self.nat_addr,
3157                                       server_in_port,
3158                                       server_out_port,
3159                                       proto=IP_PROTOS.udp)
3160         self.nat44_add_static_mapping(server_addr, self.nat_addr)
3161
3162         self.reass_hairpinning(server_addr, server_in_port, server_out_port,
3163                                host_in_port, proto=IP_PROTOS.tcp)
3164         self.reass_hairpinning(server_addr, server_in_port, server_out_port,
3165                                host_in_port, proto=IP_PROTOS.udp)
3166         self.reass_hairpinning(server_addr, server_in_port, server_out_port,
3167                                host_in_port, proto=IP_PROTOS.icmp)
3168
3169     def test_frag_out_of_order(self):
3170         """ NAT44EI translate fragments arriving out of order """
3171
3172         self.nat44_add_address(self.nat_addr)
3173         flags = self.config_flags.NAT44_EI_IF_INSIDE
3174         self.vapi.nat44_ei_interface_add_del_feature(
3175             sw_if_index=self.pg0.sw_if_index,
3176             flags=flags, is_add=1)
3177         self.vapi.nat44_ei_interface_add_del_feature(
3178             sw_if_index=self.pg1.sw_if_index,
3179             is_add=1)
3180
3181         self.frag_out_of_order(proto=IP_PROTOS.tcp)
3182         self.frag_out_of_order(proto=IP_PROTOS.udp)
3183         self.frag_out_of_order(proto=IP_PROTOS.icmp)
3184
3185     def test_port_restricted(self):
3186         """ NAT44EI Port restricted NAT44EI (MAP-E CE) """
3187         self.nat44_add_address(self.nat_addr)
3188         flags = self.config_flags.NAT44_EI_IF_INSIDE
3189         self.vapi.nat44_ei_interface_add_del_feature(
3190             sw_if_index=self.pg0.sw_if_index,
3191             flags=flags, is_add=1)
3192         self.vapi.nat44_ei_interface_add_del_feature(
3193             sw_if_index=self.pg1.sw_if_index,
3194             is_add=1)
3195         self.vapi.nat44_ei_set_addr_and_port_alloc_alg(alg=1,
3196                                                        psid_offset=6,
3197                                                        psid_length=6,
3198                                                        psid=10)
3199
3200         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
3201              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3202              TCP(sport=4567, dport=22))
3203         self.pg0.add_stream(p)
3204         self.pg_enable_capture(self.pg_interfaces)
3205         self.pg_start()
3206         capture = self.pg1.get_capture(1)
3207         p = capture[0]
3208         try:
3209             ip = p[IP]
3210             tcp = p[TCP]
3211             self.assertEqual(ip.dst, self.pg1.remote_ip4)
3212             self.assertEqual(ip.src, self.nat_addr)
3213             self.assertEqual(tcp.dport, 22)
3214             self.assertNotEqual(tcp.sport, 4567)
3215             self.assertEqual((tcp.sport >> 6) & 63, 10)
3216             self.assert_packet_checksums_valid(p)
3217         except:
3218             self.logger.error(ppp("Unexpected or invalid packet:", p))
3219             raise
3220
3221     def test_port_range(self):
3222         """ NAT44EI External address port range """
3223         self.nat44_add_address(self.nat_addr)
3224         flags = self.config_flags.NAT44_EI_IF_INSIDE
3225         self.vapi.nat44_ei_interface_add_del_feature(
3226             sw_if_index=self.pg0.sw_if_index,
3227             flags=flags, is_add=1)
3228         self.vapi.nat44_ei_interface_add_del_feature(
3229             sw_if_index=self.pg1.sw_if_index,
3230             is_add=1)
3231         self.vapi.nat44_ei_set_addr_and_port_alloc_alg(alg=2,
3232                                                        start_port=1025,
3233                                                        end_port=1027)
3234
3235         pkts = []
3236         for port in range(0, 5):
3237             p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
3238                  IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3239                  TCP(sport=1125 + port))
3240             pkts.append(p)
3241         self.pg0.add_stream(pkts)
3242         self.pg_enable_capture(self.pg_interfaces)
3243         self.pg_start()
3244         capture = self.pg1.get_capture(3)
3245         for p in capture:
3246             tcp = p[TCP]
3247             self.assertGreaterEqual(tcp.sport, 1025)
3248             self.assertLessEqual(tcp.sport, 1027)
3249
3250     def test_multiple_outside_vrf(self):
3251         """ NAT44EI Multiple outside VRF """
3252         vrf_id1 = 1
3253         vrf_id2 = 2
3254
3255         self.pg1.unconfig_ip4()
3256         self.pg2.unconfig_ip4()
3257         self.vapi.ip_table_add_del(is_add=1, table={'table_id': vrf_id1})
3258         self.vapi.ip_table_add_del(is_add=1, table={'table_id': vrf_id2})
3259         self.pg1.set_table_ip4(vrf_id1)
3260         self.pg2.set_table_ip4(vrf_id2)
3261         self.pg1.config_ip4()
3262         self.pg2.config_ip4()
3263         self.pg1.resolve_arp()
3264         self.pg2.resolve_arp()
3265
3266         self.nat44_add_address(self.nat_addr)
3267         flags = self.config_flags.NAT44_EI_IF_INSIDE
3268         self.vapi.nat44_ei_interface_add_del_feature(
3269             sw_if_index=self.pg0.sw_if_index,
3270             flags=flags, is_add=1)
3271         self.vapi.nat44_ei_interface_add_del_feature(
3272             sw_if_index=self.pg1.sw_if_index,
3273             is_add=1)
3274         self.vapi.nat44_ei_interface_add_del_feature(
3275             sw_if_index=self.pg2.sw_if_index,
3276             is_add=1)
3277
3278         try:
3279             # first VRF
3280             pkts = self.create_stream_in(self.pg0, self.pg1)
3281             self.pg0.add_stream(pkts)
3282             self.pg_enable_capture(self.pg_interfaces)
3283             self.pg_start()
3284             capture = self.pg1.get_capture(len(pkts))
3285             self.verify_capture_out(capture, self.nat_addr)
3286
3287             pkts = self.create_stream_out(self.pg1, self.nat_addr)
3288             self.pg1.add_stream(pkts)
3289             self.pg_enable_capture(self.pg_interfaces)
3290             self.pg_start()
3291             capture = self.pg0.get_capture(len(pkts))
3292             self.verify_capture_in(capture, self.pg0)
3293
3294             self.tcp_port_in = 60303
3295             self.udp_port_in = 60304
3296             self.icmp_id_in = 60305
3297
3298             # second VRF
3299             pkts = self.create_stream_in(self.pg0, self.pg2)
3300             self.pg0.add_stream(pkts)
3301             self.pg_enable_capture(self.pg_interfaces)
3302             self.pg_start()
3303             capture = self.pg2.get_capture(len(pkts))
3304             self.verify_capture_out(capture, self.nat_addr)
3305
3306             pkts = self.create_stream_out(self.pg2, self.nat_addr)
3307             self.pg2.add_stream(pkts)
3308             self.pg_enable_capture(self.pg_interfaces)
3309             self.pg_start()
3310             capture = self.pg0.get_capture(len(pkts))
3311             self.verify_capture_in(capture, self.pg0)
3312
3313         finally:
3314             self.nat44_add_address(self.nat_addr, is_add=0)
3315             self.pg1.unconfig_ip4()
3316             self.pg2.unconfig_ip4()
3317             self.pg1.set_table_ip4(0)
3318             self.pg2.set_table_ip4(0)
3319             self.pg1.config_ip4()
3320             self.pg2.config_ip4()
3321             self.pg1.resolve_arp()
3322             self.pg2.resolve_arp()
3323
3324     def test_mss_clamping(self):
3325         """ NAT44EI TCP MSS clamping """
3326         self.nat44_add_address(self.nat_addr)
3327         flags = self.config_flags.NAT44_EI_IF_INSIDE
3328         self.vapi.nat44_ei_interface_add_del_feature(
3329             sw_if_index=self.pg0.sw_if_index,
3330             flags=flags, is_add=1)
3331         self.vapi.nat44_ei_interface_add_del_feature(
3332             sw_if_index=self.pg1.sw_if_index,
3333             is_add=1)
3334
3335         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
3336              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3337              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
3338                  flags="S", options=[('MSS', 1400)]))
3339
3340         self.vapi.nat44_ei_set_mss_clamping(enable=1, mss_value=1000)
3341         self.pg0.add_stream(p)
3342         self.pg_enable_capture(self.pg_interfaces)
3343         self.pg_start()
3344         capture = self.pg1.get_capture(1)
3345         # Negotiated MSS value greater than configured - changed
3346         self.verify_mss_value(capture[0], 1000)
3347
3348         self.vapi.nat44_ei_set_mss_clamping(enable=0, mss_value=1500)
3349         self.pg0.add_stream(p)
3350         self.pg_enable_capture(self.pg_interfaces)
3351         self.pg_start()
3352         capture = self.pg1.get_capture(1)
3353         # MSS clamping disabled - negotiated MSS unchanged
3354         self.verify_mss_value(capture[0], 1400)
3355
3356         self.vapi.nat44_ei_set_mss_clamping(enable=1, mss_value=1500)
3357         self.pg0.add_stream(p)
3358         self.pg_enable_capture(self.pg_interfaces)
3359         self.pg_start()
3360         capture = self.pg1.get_capture(1)
3361         # Negotiated MSS value smaller than configured - unchanged
3362         self.verify_mss_value(capture[0], 1400)
3363
3364     def test_ha_send(self):
3365         """ NAT44EI Send HA session synchronization events (active) """
3366         flags = self.config_flags.NAT44_EI_IF_INSIDE
3367         self.vapi.nat44_ei_interface_add_del_feature(
3368             sw_if_index=self.pg0.sw_if_index,
3369             flags=flags, is_add=1)
3370         self.vapi.nat44_ei_interface_add_del_feature(
3371             sw_if_index=self.pg1.sw_if_index,
3372             is_add=1)
3373         self.nat44_add_address(self.nat_addr)
3374
3375         self.vapi.nat44_ei_ha_set_listener(
3376             ip_address=self.pg3.local_ip4, port=12345, path_mtu=512)
3377         self.vapi.nat44_ei_ha_set_failover(
3378             ip_address=self.pg3.remote_ip4, port=12346,
3379             session_refresh_interval=10)
3380         bind_layers(UDP, HANATStateSync, sport=12345)
3381
3382         # create sessions
3383         pkts = self.create_stream_in(self.pg0, self.pg1)
3384         self.pg0.add_stream(pkts)
3385         self.pg_enable_capture(self.pg_interfaces)
3386         self.pg_start()
3387         capture = self.pg1.get_capture(len(pkts))
3388         self.verify_capture_out(capture)
3389         # active send HA events
3390         self.vapi.nat44_ei_ha_flush()
3391         stats = self.statistics['/nat44-ei/ha/add-event-send']
3392         self.assertEqual(stats[:, 0].sum(), 3)
3393         capture = self.pg3.get_capture(1)
3394         p = capture[0]
3395         self.assert_packet_checksums_valid(p)
3396         try:
3397             ip = p[IP]
3398             udp = p[UDP]
3399             hanat = p[HANATStateSync]
3400         except IndexError:
3401             self.logger.error(ppp("Invalid packet:", p))
3402             raise
3403         else:
3404             self.assertEqual(ip.src, self.pg3.local_ip4)
3405             self.assertEqual(ip.dst, self.pg3.remote_ip4)
3406             self.assertEqual(udp.sport, 12345)
3407             self.assertEqual(udp.dport, 12346)
3408             self.assertEqual(hanat.version, 1)
3409             # self.assertEqual(hanat.thread_index, 0)
3410             self.assertEqual(hanat.count, 3)
3411             seq = hanat.sequence_number
3412             for event in hanat.events:
3413                 self.assertEqual(event.event_type, 1)
3414                 self.assertEqual(event.in_addr, self.pg0.remote_ip4)
3415                 self.assertEqual(event.out_addr, self.nat_addr)
3416                 self.assertEqual(event.fib_index, 0)
3417
3418         # ACK received events
3419         ack = (Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac) /
3420                IP(src=self.pg3.remote_ip4, dst=self.pg3.local_ip4) /
3421                UDP(sport=12346, dport=12345) /
3422                HANATStateSync(sequence_number=seq, flags='ACK',
3423                               thread_index=hanat.thread_index))
3424         self.pg3.add_stream(ack)
3425         self.pg_start()
3426         stats = self.statistics['/nat44-ei/ha/ack-recv']
3427         self.assertEqual(stats[:, 0].sum(), 1)
3428
3429         # delete one session
3430         self.pg_enable_capture(self.pg_interfaces)
3431         self.vapi.nat44_ei_del_session(
3432             address=self.pg0.remote_ip4, port=self.tcp_port_in,
3433             protocol=IP_PROTOS.tcp, flags=self.config_flags.NAT44_EI_IF_INSIDE)
3434         self.vapi.nat44_ei_ha_flush()
3435         stats = self.statistics['/nat44-ei/ha/del-event-send']
3436         self.assertEqual(stats[:, 0].sum(), 1)
3437         capture = self.pg3.get_capture(1)
3438         p = capture[0]
3439         try:
3440             hanat = p[HANATStateSync]
3441         except IndexError:
3442             self.logger.error(ppp("Invalid packet:", p))
3443             raise
3444         else:
3445             self.assertGreater(hanat.sequence_number, seq)
3446
3447         # do not send ACK, active retry send HA event again
3448         self.pg_enable_capture(self.pg_interfaces)
3449         sleep(12)
3450         stats = self.statistics['/nat44-ei/ha/retry-count']
3451         self.assertEqual(stats[:, 0].sum(), 3)
3452         stats = self.statistics['/nat44-ei/ha/missed-count']
3453         self.assertEqual(stats[:, 0].sum(), 1)
3454         capture = self.pg3.get_capture(3)
3455         for packet in capture:
3456             self.assertEqual(packet, p)
3457
3458         # session counters refresh
3459         pkts = self.create_stream_out(self.pg1)
3460         self.pg1.add_stream(pkts)
3461         self.pg_enable_capture(self.pg_interfaces)
3462         self.pg_start()
3463         self.pg0.get_capture(2)
3464         self.vapi.nat44_ei_ha_flush()
3465         stats = self.statistics['/nat44-ei/ha/refresh-event-send']
3466         self.assertEqual(stats[:, 0].sum(), 2)
3467         capture = self.pg3.get_capture(1)
3468         p = capture[0]
3469         self.assert_packet_checksums_valid(p)
3470         try:
3471             ip = p[IP]
3472             udp = p[UDP]
3473             hanat = p[HANATStateSync]
3474         except IndexError:
3475             self.logger.error(ppp("Invalid packet:", p))
3476             raise
3477         else:
3478             self.assertEqual(ip.src, self.pg3.local_ip4)
3479             self.assertEqual(ip.dst, self.pg3.remote_ip4)
3480             self.assertEqual(udp.sport, 12345)
3481             self.assertEqual(udp.dport, 12346)
3482             self.assertEqual(hanat.version, 1)
3483             self.assertEqual(hanat.count, 2)
3484             seq = hanat.sequence_number
3485             for event in hanat.events:
3486                 self.assertEqual(event.event_type, 3)
3487                 self.assertEqual(event.out_addr, self.nat_addr)
3488                 self.assertEqual(event.fib_index, 0)
3489                 self.assertEqual(event.total_pkts, 2)
3490                 self.assertGreater(event.total_bytes, 0)
3491
3492         stats = self.statistics['/nat44-ei/ha/ack-recv']
3493         ack = (Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac) /
3494                IP(src=self.pg3.remote_ip4, dst=self.pg3.local_ip4) /
3495                UDP(sport=12346, dport=12345) /
3496                HANATStateSync(sequence_number=seq, flags='ACK',
3497                               thread_index=hanat.thread_index))
3498         self.pg3.add_stream(ack)
3499         self.pg_start()
3500         stats = self.statistics['/nat44-ei/ha/ack-recv']
3501         self.assertEqual(stats[:, 0].sum(), 2)
3502
3503     def test_ha_recv(self):
3504         """ NAT44EI Receive HA session synchronization events (passive) """
3505         self.nat44_add_address(self.nat_addr)
3506         flags = self.config_flags.NAT44_EI_IF_INSIDE
3507         self.vapi.nat44_ei_interface_add_del_feature(
3508             sw_if_index=self.pg0.sw_if_index,
3509             flags=flags, is_add=1)
3510         self.vapi.nat44_ei_interface_add_del_feature(
3511             sw_if_index=self.pg1.sw_if_index,
3512             is_add=1)
3513         self.vapi.nat44_ei_ha_set_listener(ip_address=self.pg3.local_ip4,
3514                                            port=12345, path_mtu=512)
3515         bind_layers(UDP, HANATStateSync, sport=12345)
3516
3517         # this is a bit tricky - HA dictates thread index due to how it's
3518         # designed, but once we use HA to create a session, we also want
3519         # to pass a packet through said session. so the session must end
3520         # up on the correct thread from both directions - in2out (based on
3521         # IP address) and out2in (based on outside port)
3522
3523         # first choose a thread index which is correct for IP
3524         thread_index = get_nat44_ei_in2out_worker_index(self.pg0.remote_ip4,
3525                                                         self.vpp_worker_count)
3526
3527         # now pick a port which is correct for given thread
3528         port_per_thread = int((0xffff-1024) / max(1, self.vpp_worker_count))
3529         self.tcp_port_out = 1024 + random.randint(1, port_per_thread)
3530         self.udp_port_out = 1024 + random.randint(1, port_per_thread)
3531         if self.vpp_worker_count > 0:
3532             self.tcp_port_out += port_per_thread * (thread_index - 1)
3533             self.udp_port_out += port_per_thread * (thread_index - 1)
3534
3535         # send HA session add events to failover/passive
3536         p = (Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac) /
3537              IP(src=self.pg3.remote_ip4, dst=self.pg3.local_ip4) /
3538              UDP(sport=12346, dport=12345) /
3539              HANATStateSync(sequence_number=1, events=[
3540                  Event(event_type='add', protocol='tcp',
3541                        in_addr=self.pg0.remote_ip4, out_addr=self.nat_addr,
3542                        in_port=self.tcp_port_in, out_port=self.tcp_port_out,
3543                        eh_addr=self.pg1.remote_ip4,
3544                        ehn_addr=self.pg1.remote_ip4,
3545                        eh_port=self.tcp_external_port,
3546                        ehn_port=self.tcp_external_port, fib_index=0),
3547                  Event(event_type='add', protocol='udp',
3548                        in_addr=self.pg0.remote_ip4, out_addr=self.nat_addr,
3549                        in_port=self.udp_port_in, out_port=self.udp_port_out,
3550                        eh_addr=self.pg1.remote_ip4,
3551                        ehn_addr=self.pg1.remote_ip4,
3552                        eh_port=self.udp_external_port,
3553                        ehn_port=self.udp_external_port, fib_index=0)],
3554                  thread_index=thread_index))
3555
3556         self.pg3.add_stream(p)
3557         self.pg_enable_capture(self.pg_interfaces)
3558         self.pg_start()
3559         # receive ACK
3560         capture = self.pg3.get_capture(1)
3561         p = capture[0]
3562         try:
3563             hanat = p[HANATStateSync]
3564         except IndexError:
3565             self.logger.error(ppp("Invalid packet:", p))
3566             raise
3567         else:
3568             self.assertEqual(hanat.sequence_number, 1)
3569             self.assertEqual(hanat.flags, 'ACK')
3570             self.assertEqual(hanat.version, 1)
3571             self.assertEqual(hanat.thread_index, thread_index)
3572         stats = self.statistics['/nat44-ei/ha/ack-send']
3573         self.assertEqual(stats[:, 0].sum(), 1)
3574         stats = self.statistics['/nat44-ei/ha/add-event-recv']
3575         self.assertEqual(stats[:, 0].sum(), 2)
3576         users = self.statistics['/nat44-ei/total-users']
3577         self.assertEqual(users[:, 0].sum(), 1)
3578         sessions = self.statistics['/nat44-ei/total-sessions']
3579         self.assertEqual(sessions[:, 0].sum(), 2)
3580         users = self.vapi.nat44_ei_user_dump()
3581         self.assertEqual(len(users), 1)
3582         self.assertEqual(str(users[0].ip_address),
3583                          self.pg0.remote_ip4)
3584         # there should be 2 sessions created by HA
3585         sessions = self.vapi.nat44_ei_user_session_dump(
3586             users[0].ip_address, users[0].vrf_id)
3587         self.assertEqual(len(sessions), 2)
3588         for session in sessions:
3589             self.assertEqual(str(session.inside_ip_address),
3590                              self.pg0.remote_ip4)
3591             self.assertEqual(str(session.outside_ip_address),
3592                              self.nat_addr)
3593             self.assertIn(session.inside_port,
3594                           [self.tcp_port_in, self.udp_port_in])
3595             self.assertIn(session.outside_port,
3596                           [self.tcp_port_out, self.udp_port_out])
3597             self.assertIn(session.protocol, [IP_PROTOS.tcp, IP_PROTOS.udp])
3598
3599         # send HA session delete event to failover/passive
3600         p = (Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac) /
3601              IP(src=self.pg3.remote_ip4, dst=self.pg3.local_ip4) /
3602              UDP(sport=12346, dport=12345) /
3603              HANATStateSync(sequence_number=2, events=[
3604                  Event(event_type='del', protocol='udp',
3605                        in_addr=self.pg0.remote_ip4, out_addr=self.nat_addr,
3606                        in_port=self.udp_port_in, out_port=self.udp_port_out,
3607                        eh_addr=self.pg1.remote_ip4,
3608                        ehn_addr=self.pg1.remote_ip4,
3609                        eh_port=self.udp_external_port,
3610                        ehn_port=self.udp_external_port, fib_index=0)],
3611                  thread_index=thread_index))
3612
3613         self.pg3.add_stream(p)
3614         self.pg_enable_capture(self.pg_interfaces)
3615         self.pg_start()
3616         # receive ACK
3617         capture = self.pg3.get_capture(1)
3618         p = capture[0]
3619         try:
3620             hanat = p[HANATStateSync]
3621         except IndexError:
3622             self.logger.error(ppp("Invalid packet:", p))
3623             raise
3624         else:
3625             self.assertEqual(hanat.sequence_number, 2)
3626             self.assertEqual(hanat.flags, 'ACK')
3627             self.assertEqual(hanat.version, 1)
3628         users = self.vapi.nat44_ei_user_dump()
3629         self.assertEqual(len(users), 1)
3630         self.assertEqual(str(users[0].ip_address),
3631                          self.pg0.remote_ip4)
3632         # now we should have only 1 session, 1 deleted by HA
3633         sessions = self.vapi.nat44_ei_user_session_dump(users[0].ip_address,
3634                                                         users[0].vrf_id)
3635         self.assertEqual(len(sessions), 1)
3636         stats = self.statistics['/nat44-ei/ha/del-event-recv']
3637         self.assertEqual(stats[:, 0].sum(), 1)
3638
3639         stats = self.statistics.get_err_counter(
3640             '/err/nat44-ei-ha/pkts-processed')
3641         self.assertEqual(stats, 2)
3642
3643         # send HA session refresh event to failover/passive
3644         p = (Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac) /
3645              IP(src=self.pg3.remote_ip4, dst=self.pg3.local_ip4) /
3646              UDP(sport=12346, dport=12345) /
3647              HANATStateSync(sequence_number=3, events=[
3648                  Event(event_type='refresh', protocol='tcp',
3649                        in_addr=self.pg0.remote_ip4, out_addr=self.nat_addr,
3650                        in_port=self.tcp_port_in, out_port=self.tcp_port_out,
3651                        eh_addr=self.pg1.remote_ip4,
3652                        ehn_addr=self.pg1.remote_ip4,
3653                        eh_port=self.tcp_external_port,
3654                        ehn_port=self.tcp_external_port, fib_index=0,
3655                        total_bytes=1024, total_pkts=2)],
3656                  thread_index=thread_index))
3657         self.pg3.add_stream(p)
3658         self.pg_enable_capture(self.pg_interfaces)
3659         self.pg_start()
3660         # receive ACK
3661         capture = self.pg3.get_capture(1)
3662         p = capture[0]
3663         try:
3664             hanat = p[HANATStateSync]
3665         except IndexError:
3666             self.logger.error(ppp("Invalid packet:", p))
3667             raise
3668         else:
3669             self.assertEqual(hanat.sequence_number, 3)
3670             self.assertEqual(hanat.flags, 'ACK')
3671             self.assertEqual(hanat.version, 1)
3672         users = self.vapi.nat44_ei_user_dump()
3673         self.assertEqual(len(users), 1)
3674         self.assertEqual(str(users[0].ip_address),
3675                          self.pg0.remote_ip4)
3676         sessions = self.vapi.nat44_ei_user_session_dump(
3677             users[0].ip_address, users[0].vrf_id)
3678         self.assertEqual(len(sessions), 1)
3679         session = sessions[0]
3680         self.assertEqual(session.total_bytes, 1024)
3681         self.assertEqual(session.total_pkts, 2)
3682         stats = self.statistics['/nat44-ei/ha/refresh-event-recv']
3683         self.assertEqual(stats[:, 0].sum(), 1)
3684
3685         stats = self.statistics.get_err_counter(
3686             '/err/nat44-ei-ha/pkts-processed')
3687         self.assertEqual(stats, 3)
3688
3689         # send packet to test session created by HA
3690         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
3691              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
3692              TCP(sport=self.tcp_external_port, dport=self.tcp_port_out))
3693         self.pg1.add_stream(p)
3694         self.pg_enable_capture(self.pg_interfaces)
3695         self.pg_start()
3696         capture = self.pg0.get_capture(1)
3697         p = capture[0]
3698         try:
3699             ip = p[IP]
3700             tcp = p[TCP]
3701         except IndexError:
3702             self.logger.error(ppp("Invalid packet:", p))
3703             raise
3704         else:
3705             self.assertEqual(ip.src, self.pg1.remote_ip4)
3706             self.assertEqual(ip.dst, self.pg0.remote_ip4)
3707             self.assertEqual(tcp.sport, self.tcp_external_port)
3708             self.assertEqual(tcp.dport, self.tcp_port_in)
3709
3710     def reconfigure_frame_queue_nelts(self, frame_queue_nelts):
3711         self.vapi.nat44_ei_plugin_enable_disable(enable=0)
3712         self.vapi.nat44_ei_set_fq_options(frame_queue_nelts=frame_queue_nelts)
3713         # keep plugin configuration persistent
3714         self.plugin_enable()
3715         return self.vapi.nat44_ei_show_fq_options().frame_queue_nelts
3716
3717     def test_set_frame_queue_nelts(self):
3718         """ NAT44 EI API test - worker handoff frame queue elements """
3719         self.assertEqual(self.reconfigure_frame_queue_nelts(512), 512)
3720
3721     def show_commands_at_teardown(self):
3722         self.logger.info(self.vapi.cli("show nat44 ei timeouts"))
3723         self.logger.info(self.vapi.cli("show nat44 ei addresses"))
3724         self.logger.info(self.vapi.cli("show nat44 ei interfaces"))
3725         self.logger.info(self.vapi.cli("show nat44 ei static mappings"))
3726         self.logger.info(self.vapi.cli("show nat44 ei interface address"))
3727         self.logger.info(self.vapi.cli("show nat44 ei sessions detail"))
3728         self.logger.info(self.vapi.cli("show nat44 ei hash tables detail"))
3729         self.logger.info(self.vapi.cli("show nat44 ei ha"))
3730         self.logger.info(
3731             self.vapi.cli("show nat44 ei addr-port-assignment-alg"))
3732
3733     def test_outside_address_distribution(self):
3734         """ Outside address distribution based on source address """
3735
3736         x = 100
3737         nat_addresses = []
3738
3739         for i in range(1, x):
3740             a = "10.0.0.%d" % i
3741             nat_addresses.append(a)
3742
3743         flags = self.config_flags.NAT44_EI_IF_INSIDE
3744         self.vapi.nat44_ei_interface_add_del_feature(
3745             sw_if_index=self.pg0.sw_if_index,
3746             flags=flags, is_add=1)
3747         self.vapi.nat44_ei_interface_add_del_feature(
3748             sw_if_index=self.pg1.sw_if_index,
3749             is_add=1)
3750
3751         self.vapi.nat44_ei_add_del_address_range(
3752             first_ip_address=nat_addresses[0],
3753             last_ip_address=nat_addresses[-1],
3754             vrf_id=0xFFFFFFFF, is_add=1)
3755
3756         self.pg0.generate_remote_hosts(x)
3757
3758         pkts = []
3759         for i in range(x):
3760             info = self.create_packet_info(self.pg0, self.pg1)
3761             payload = self.info_to_payload(info)
3762             p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
3763                  IP(src=self.pg0.remote_hosts[i].ip4,
3764                      dst=self.pg1.remote_ip4) /
3765                  UDP(sport=7000+i, dport=8000+i) /
3766                  Raw(payload))
3767             info.data = p
3768             pkts.append(p)
3769
3770         self.pg0.add_stream(pkts)
3771         self.pg_enable_capture(self.pg_interfaces)
3772         self.pg_start()
3773         recvd = self.pg1.get_capture(len(pkts))
3774         for p_recvd in recvd:
3775             payload_info = self.payload_to_info(p_recvd[Raw])
3776             packet_index = payload_info.index
3777             info = self._packet_infos[packet_index]
3778             self.assertTrue(info is not None)
3779             self.assertEqual(packet_index, info.index)
3780             p_sent = info.data
3781             packed = socket.inet_aton(p_sent[IP].src)
3782             numeric = struct.unpack("!L", packed)[0]
3783             numeric = socket.htonl(numeric)
3784             a = nat_addresses[(numeric-1) % len(nat_addresses)]
3785             self.assertEqual(
3786                 a, p_recvd[IP].src,
3787                 "Invalid packet (src IP %s translated to %s, but expected %s)"
3788                 % (p_sent[IP].src, p_recvd[IP].src, a))
3789
3790     def test_default_user_sessions(self):
3791         """ NAT44EI default per-user session limit is used and reported """
3792         nat44_ei_config = self.vapi.nat44_ei_show_running_config()
3793         # a nonzero default should be reported for user_sessions
3794         self.assertNotEqual(nat44_ei_config.user_sessions, 0)
3795
3796
3797 class TestNAT44Out2InDPO(MethodHolder):
3798     """ NAT44EI Test Cases using out2in DPO """
3799
3800     @classmethod
3801     def setUpClass(cls):
3802         super(TestNAT44Out2InDPO, cls).setUpClass()
3803         cls.vapi.cli("set log class nat44-ei level debug")
3804
3805         cls.tcp_port_in = 6303
3806         cls.tcp_port_out = 6303
3807         cls.udp_port_in = 6304
3808         cls.udp_port_out = 6304
3809         cls.icmp_id_in = 6305
3810         cls.icmp_id_out = 6305
3811         cls.nat_addr = '10.0.0.3'
3812         cls.dst_ip4 = '192.168.70.1'
3813
3814         cls.create_pg_interfaces(range(2))
3815
3816         cls.pg0.admin_up()
3817         cls.pg0.config_ip4()
3818         cls.pg0.resolve_arp()
3819
3820         cls.pg1.admin_up()
3821         cls.pg1.config_ip6()
3822         cls.pg1.resolve_ndp()
3823
3824         r1 = VppIpRoute(cls, "::", 0,
3825                         [VppRoutePath(cls.pg1.remote_ip6,
3826                                       cls.pg1.sw_if_index)],
3827                         register=False)
3828         r1.add_vpp_config()
3829
3830     def setUp(self):
3831         super(TestNAT44Out2InDPO, self).setUp()
3832         flags = self.config_flags.NAT44_EI_OUT2IN_DPO
3833         self.vapi.nat44_ei_plugin_enable_disable(enable=1, flags=flags)
3834
3835     def tearDown(self):
3836         super(TestNAT44Out2InDPO, self).tearDown()
3837         if not self.vpp_dead:
3838             self.vapi.nat44_ei_plugin_enable_disable(enable=0)
3839             self.vapi.cli("clear logging")
3840
3841     def configure_xlat(self):
3842         self.dst_ip6_pfx = '1:2:3::'
3843         self.dst_ip6_pfx_n = socket.inet_pton(socket.AF_INET6,
3844                                               self.dst_ip6_pfx)
3845         self.dst_ip6_pfx_len = 96
3846         self.src_ip6_pfx = '4:5:6::'
3847         self.src_ip6_pfx_n = socket.inet_pton(socket.AF_INET6,
3848                                               self.src_ip6_pfx)
3849         self.src_ip6_pfx_len = 96
3850         self.vapi.map_add_domain(self.dst_ip6_pfx_n, self.dst_ip6_pfx_len,
3851                                  self.src_ip6_pfx_n, self.src_ip6_pfx_len,
3852                                  '\x00\x00\x00\x00', 0)
3853
3854     @unittest.skip('Temporary disabled')
3855     def test_464xlat_ce(self):
3856         """ Test 464XLAT CE with NAT44EI """
3857
3858         self.configure_xlat()
3859
3860         flags = self.config_flags.NAT44_EI_IF_INSIDE
3861         self.vapi.nat44_ei_interface_add_del_feature(
3862             sw_if_index=self.pg0.sw_if_index,
3863             flags=flags, is_add=1)
3864         self.vapi.nat44_ei_add_del_address_range(
3865             first_ip_address=self.nat_addr_n,
3866             last_ip_address=self.nat_addr_n,
3867             vrf_id=0xFFFFFFFF, is_add=1)
3868
3869         out_src_ip6 = self.compose_ip6(self.dst_ip4, self.dst_ip6_pfx,
3870                                        self.dst_ip6_pfx_len)
3871         out_dst_ip6 = self.compose_ip6(self.nat_addr, self.src_ip6_pfx,
3872                                        self.src_ip6_pfx_len)
3873
3874         try:
3875             pkts = self.create_stream_in(self.pg0, self.pg1, self.dst_ip4)
3876             self.pg0.add_stream(pkts)
3877             self.pg_enable_capture(self.pg_interfaces)
3878             self.pg_start()
3879             capture = self.pg1.get_capture(len(pkts))
3880             self.verify_capture_out_ip6(capture, nat_ip=out_dst_ip6,
3881                                         dst_ip=out_src_ip6)
3882
3883             pkts = self.create_stream_out_ip6(self.pg1, out_src_ip6,
3884                                               out_dst_ip6)
3885             self.pg1.add_stream(pkts)
3886             self.pg_enable_capture(self.pg_interfaces)
3887             self.pg_start()
3888             capture = self.pg0.get_capture(len(pkts))
3889             self.verify_capture_in(capture, self.pg0)
3890         finally:
3891             self.vapi.nat44_ei_interface_add_del_feature(
3892                 sw_if_index=self.pg0.sw_if_index,
3893                 flags=flags)
3894             self.vapi.nat44_ei_add_del_address_range(
3895                 first_ip_address=self.nat_addr_n,
3896                 last_ip_address=self.nat_addr_n,
3897                 vrf_id=0xFFFFFFFF)
3898
3899     @unittest.skip('Temporary disabled')
3900     def test_464xlat_ce_no_nat(self):
3901         """ Test 464XLAT CE without NAT44EI """
3902
3903         self.configure_xlat()
3904
3905         out_src_ip6 = self.compose_ip6(self.dst_ip4, self.dst_ip6_pfx,
3906                                        self.dst_ip6_pfx_len)
3907         out_dst_ip6 = self.compose_ip6(self.pg0.remote_ip4, self.src_ip6_pfx,
3908                                        self.src_ip6_pfx_len)
3909
3910         pkts = self.create_stream_in(self.pg0, self.pg1, self.dst_ip4)
3911         self.pg0.add_stream(pkts)
3912         self.pg_enable_capture(self.pg_interfaces)
3913         self.pg_start()
3914         capture = self.pg1.get_capture(len(pkts))
3915         self.verify_capture_out_ip6(capture, dst_ip=out_src_ip6,
3916                                     nat_ip=out_dst_ip6, same_port=True)
3917
3918         pkts = self.create_stream_out_ip6(self.pg1, out_src_ip6, out_dst_ip6)
3919         self.pg1.add_stream(pkts)
3920         self.pg_enable_capture(self.pg_interfaces)
3921         self.pg_start()
3922         capture = self.pg0.get_capture(len(pkts))
3923         self.verify_capture_in(capture, self.pg0)
3924
3925
3926 class TestNAT44EIMW(MethodHolder):
3927     """ NAT44EI Test Cases (multiple workers) """
3928     vpp_worker_count = 2
3929     max_translations = 10240
3930     max_users = 10240
3931
3932     @classmethod
3933     def setUpClass(cls):
3934         super(TestNAT44EIMW, cls).setUpClass()
3935         cls.vapi.cli("set log class nat level debug")
3936
3937         cls.tcp_port_in = 6303
3938         cls.tcp_port_out = 6303
3939         cls.udp_port_in = 6304
3940         cls.udp_port_out = 6304
3941         cls.icmp_id_in = 6305
3942         cls.icmp_id_out = 6305
3943         cls.nat_addr = '10.0.0.3'
3944         cls.ipfix_src_port = 4739
3945         cls.ipfix_domain_id = 1
3946         cls.tcp_external_port = 80
3947         cls.udp_external_port = 69
3948
3949         cls.create_pg_interfaces(range(10))
3950         cls.interfaces = list(cls.pg_interfaces[0:4])
3951
3952         for i in cls.interfaces:
3953             i.admin_up()
3954             i.config_ip4()
3955             i.resolve_arp()
3956
3957         cls.pg0.generate_remote_hosts(3)
3958         cls.pg0.configure_ipv4_neighbors()
3959
3960         cls.pg1.generate_remote_hosts(1)
3961         cls.pg1.configure_ipv4_neighbors()
3962
3963         cls.overlapping_interfaces = list(list(cls.pg_interfaces[4:7]))
3964         cls.vapi.ip_table_add_del(is_add=1, table={'table_id': 10})
3965         cls.vapi.ip_table_add_del(is_add=1, table={'table_id': 20})
3966
3967         cls.pg4._local_ip4 = "172.16.255.1"
3968         cls.pg4._remote_hosts[0]._ip4 = "172.16.255.2"
3969         cls.pg4.set_table_ip4(10)
3970         cls.pg5._local_ip4 = "172.17.255.3"
3971         cls.pg5._remote_hosts[0]._ip4 = "172.17.255.4"
3972         cls.pg5.set_table_ip4(10)
3973         cls.pg6._local_ip4 = "172.16.255.1"
3974         cls.pg6._remote_hosts[0]._ip4 = "172.16.255.2"
3975         cls.pg6.set_table_ip4(20)
3976         for i in cls.overlapping_interfaces:
3977             i.config_ip4()
3978             i.admin_up()
3979             i.resolve_arp()
3980
3981         cls.pg7.admin_up()
3982         cls.pg8.admin_up()
3983
3984         cls.pg9.generate_remote_hosts(2)
3985         cls.pg9.config_ip4()
3986         cls.vapi.sw_interface_add_del_address(
3987             sw_if_index=cls.pg9.sw_if_index,
3988             prefix="10.0.0.1/24")
3989
3990         cls.pg9.admin_up()
3991         cls.pg9.resolve_arp()
3992         cls.pg9._remote_hosts[1]._ip4 = cls.pg9._remote_hosts[0]._ip4
3993         cls.pg4._remote_ip4 = cls.pg9._remote_hosts[0]._ip4 = "10.0.0.2"
3994         cls.pg9.resolve_arp()
3995
3996     def setUp(self):
3997         super(TestNAT44EIMW, self).setUp()
3998         self.vapi.nat44_ei_plugin_enable_disable(
3999             sessions=self.max_translations,
4000             users=self.max_users, enable=1)
4001
4002     def tearDown(self):
4003         super(TestNAT44EIMW, self).tearDown()
4004         if not self.vpp_dead:
4005             self.vapi.nat44_ei_ipfix_enable_disable(
4006                 domain_id=self.ipfix_domain_id,
4007                 src_port=self.ipfix_src_port,
4008                 enable=0)
4009             self.ipfix_src_port = 4739
4010             self.ipfix_domain_id = 1
4011
4012             self.vapi.nat44_ei_plugin_enable_disable(enable=0)
4013             self.vapi.cli("clear logging")
4014
4015     def test_hairpinning(self):
4016         """ NAT44EI hairpinning - 1:1 NAPT """
4017
4018         host = self.pg0.remote_hosts[0]
4019         server = self.pg0.remote_hosts[1]
4020         host_in_port = 1234
4021         host_out_port = 0
4022         server_in_port = 5678
4023         server_out_port = 8765
4024         worker_1 = 1
4025         worker_2 = 2
4026
4027         self.nat44_add_address(self.nat_addr)
4028         flags = self.config_flags.NAT44_EI_IF_INSIDE
4029         self.vapi.nat44_ei_interface_add_del_feature(
4030             sw_if_index=self.pg0.sw_if_index,
4031             flags=flags, is_add=1)
4032         self.vapi.nat44_ei_interface_add_del_feature(
4033             sw_if_index=self.pg1.sw_if_index,
4034             is_add=1)
4035
4036         # add static mapping for server
4037         self.nat44_add_static_mapping(server.ip4, self.nat_addr,
4038                                       server_in_port, server_out_port,
4039                                       proto=IP_PROTOS.tcp)
4040
4041         cnt = self.statistics['/nat44-ei/hairpinning']
4042         # send packet from host to server
4043         p = (Ether(src=host.mac, dst=self.pg0.local_mac) /
4044              IP(src=host.ip4, dst=self.nat_addr) /
4045              TCP(sport=host_in_port, dport=server_out_port))
4046         self.pg0.add_stream(p)
4047         self.pg_enable_capture(self.pg_interfaces)
4048         self.pg_start()
4049         capture = self.pg0.get_capture(1)
4050         p = capture[0]
4051         try:
4052             ip = p[IP]
4053             tcp = p[TCP]
4054             self.assertEqual(ip.src, self.nat_addr)
4055             self.assertEqual(ip.dst, server.ip4)
4056             self.assertNotEqual(tcp.sport, host_in_port)
4057             self.assertEqual(tcp.dport, server_in_port)
4058             self.assert_packet_checksums_valid(p)
4059             host_out_port = tcp.sport
4060         except:
4061             self.logger.error(ppp("Unexpected or invalid packet:", p))
4062             raise
4063
4064         after = self.statistics['/nat44-ei/hairpinning']
4065
4066         if_idx = self.pg0.sw_if_index
4067         self.assertEqual(after[worker_2][if_idx] - cnt[worker_1][if_idx], 1)
4068
4069         # send reply from server to host
4070         p = (Ether(src=server.mac, dst=self.pg0.local_mac) /
4071              IP(src=server.ip4, dst=self.nat_addr) /
4072              TCP(sport=server_in_port, dport=host_out_port))
4073         self.pg0.add_stream(p)
4074         self.pg_enable_capture(self.pg_interfaces)
4075         self.pg_start()
4076         capture = self.pg0.get_capture(1)
4077         p = capture[0]
4078         try:
4079             ip = p[IP]
4080             tcp = p[TCP]
4081             self.assertEqual(ip.src, self.nat_addr)
4082             self.assertEqual(ip.dst, host.ip4)
4083             self.assertEqual(tcp.sport, server_out_port)
4084             self.assertEqual(tcp.dport, host_in_port)
4085             self.assert_packet_checksums_valid(p)
4086         except:
4087             self.logger.error(ppp("Unexpected or invalid packet:", p))
4088             raise
4089
4090         after = self.statistics['/nat44-ei/hairpinning']
4091         if_idx = self.pg0.sw_if_index
4092         self.assertEqual(after[worker_1][if_idx] - cnt[worker_1][if_idx], 1)
4093         self.assertEqual(after[worker_2][if_idx] - cnt[worker_2][if_idx], 2)
4094
4095     def test_hairpinning2(self):
4096         """ NAT44EI hairpinning - 1:1 NAT"""
4097
4098         server1_nat_ip = "10.0.0.10"
4099         server2_nat_ip = "10.0.0.11"
4100         host = self.pg0.remote_hosts[0]
4101         server1 = self.pg0.remote_hosts[1]
4102         server2 = self.pg0.remote_hosts[2]
4103         server_tcp_port = 22
4104         server_udp_port = 20
4105
4106         self.nat44_add_address(self.nat_addr)
4107         flags = self.config_flags.NAT44_EI_IF_INSIDE
4108         self.vapi.nat44_ei_interface_add_del_feature(
4109             sw_if_index=self.pg0.sw_if_index,
4110             flags=flags, is_add=1)
4111         self.vapi.nat44_ei_interface_add_del_feature(
4112             sw_if_index=self.pg1.sw_if_index,
4113             is_add=1)
4114
4115         # add static mapping for servers
4116         self.nat44_add_static_mapping(server1.ip4, server1_nat_ip)
4117         self.nat44_add_static_mapping(server2.ip4, server2_nat_ip)
4118
4119         # host to server1
4120         pkts = []
4121         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
4122              IP(src=host.ip4, dst=server1_nat_ip) /
4123              TCP(sport=self.tcp_port_in, dport=server_tcp_port))
4124         pkts.append(p)
4125         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
4126              IP(src=host.ip4, dst=server1_nat_ip) /
4127              UDP(sport=self.udp_port_in, dport=server_udp_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              ICMP(id=self.icmp_id_in, type='echo-request'))
4132         pkts.append(p)
4133         self.pg0.add_stream(pkts)
4134         self.pg_enable_capture(self.pg_interfaces)
4135         self.pg_start()
4136         capture = self.pg0.get_capture(len(pkts))
4137         for packet in capture:
4138             try:
4139                 self.assertEqual(packet[IP].src, self.nat_addr)
4140                 self.assertEqual(packet[IP].dst, server1.ip4)
4141                 if packet.haslayer(TCP):
4142                     self.assertNotEqual(packet[TCP].sport, self.tcp_port_in)
4143                     self.assertEqual(packet[TCP].dport, server_tcp_port)
4144                     self.tcp_port_out = packet[TCP].sport
4145                     self.assert_packet_checksums_valid(packet)
4146                 elif packet.haslayer(UDP):
4147                     self.assertNotEqual(packet[UDP].sport, self.udp_port_in)
4148                     self.assertEqual(packet[UDP].dport, server_udp_port)
4149                     self.udp_port_out = packet[UDP].sport
4150                 else:
4151                     self.assertNotEqual(packet[ICMP].id, self.icmp_id_in)
4152                     self.icmp_id_out = packet[ICMP].id
4153             except:
4154                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
4155                 raise
4156
4157         # server1 to host
4158         pkts = []
4159         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
4160              IP(src=server1.ip4, dst=self.nat_addr) /
4161              TCP(sport=server_tcp_port, dport=self.tcp_port_out))
4162         pkts.append(p)
4163         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
4164              IP(src=server1.ip4, dst=self.nat_addr) /
4165              UDP(sport=server_udp_port, dport=self.udp_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              ICMP(id=self.icmp_id_out, type='echo-reply'))
4170         pkts.append(p)
4171         self.pg0.add_stream(pkts)
4172         self.pg_enable_capture(self.pg_interfaces)
4173         self.pg_start()
4174         capture = self.pg0.get_capture(len(pkts))
4175         for packet in capture:
4176             try:
4177                 self.assertEqual(packet[IP].src, server1_nat_ip)
4178                 self.assertEqual(packet[IP].dst, host.ip4)
4179                 if packet.haslayer(TCP):
4180                     self.assertEqual(packet[TCP].dport, self.tcp_port_in)
4181                     self.assertEqual(packet[TCP].sport, server_tcp_port)
4182                     self.assert_packet_checksums_valid(packet)
4183                 elif packet.haslayer(UDP):
4184                     self.assertEqual(packet[UDP].dport, self.udp_port_in)
4185                     self.assertEqual(packet[UDP].sport, server_udp_port)
4186                 else:
4187                     self.assertEqual(packet[ICMP].id, self.icmp_id_in)
4188             except:
4189                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
4190                 raise
4191
4192         # server2 to server1
4193         pkts = []
4194         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
4195              IP(src=server2.ip4, dst=server1_nat_ip) /
4196              TCP(sport=self.tcp_port_in, dport=server_tcp_port))
4197         pkts.append(p)
4198         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
4199              IP(src=server2.ip4, dst=server1_nat_ip) /
4200              UDP(sport=self.udp_port_in, dport=server_udp_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              ICMP(id=self.icmp_id_in, type='echo-request'))
4205         pkts.append(p)
4206         self.pg0.add_stream(pkts)
4207         self.pg_enable_capture(self.pg_interfaces)
4208         self.pg_start()
4209         capture = self.pg0.get_capture(len(pkts))
4210         for packet in capture:
4211             try:
4212                 self.assertEqual(packet[IP].src, server2_nat_ip)
4213                 self.assertEqual(packet[IP].dst, server1.ip4)
4214                 if packet.haslayer(TCP):
4215                     self.assertEqual(packet[TCP].sport, self.tcp_port_in)
4216                     self.assertEqual(packet[TCP].dport, server_tcp_port)
4217                     self.tcp_port_out = packet[TCP].sport
4218                     self.assert_packet_checksums_valid(packet)
4219                 elif packet.haslayer(UDP):
4220                     self.assertEqual(packet[UDP].sport, self.udp_port_in)
4221                     self.assertEqual(packet[UDP].dport, server_udp_port)
4222                     self.udp_port_out = packet[UDP].sport
4223                 else:
4224                     self.assertEqual(packet[ICMP].id, self.icmp_id_in)
4225                     self.icmp_id_out = packet[ICMP].id
4226             except:
4227                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
4228                 raise
4229
4230         # server1 to server2
4231         pkts = []
4232         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
4233              IP(src=server1.ip4, dst=server2_nat_ip) /
4234              TCP(sport=server_tcp_port, dport=self.tcp_port_out))
4235         pkts.append(p)
4236         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
4237              IP(src=server1.ip4, dst=server2_nat_ip) /
4238              UDP(sport=server_udp_port, dport=self.udp_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              ICMP(id=self.icmp_id_out, type='echo-reply'))
4243         pkts.append(p)
4244         self.pg0.add_stream(pkts)
4245         self.pg_enable_capture(self.pg_interfaces)
4246         self.pg_start()
4247         capture = self.pg0.get_capture(len(pkts))
4248         for packet in capture:
4249             try:
4250                 self.assertEqual(packet[IP].src, server1_nat_ip)
4251                 self.assertEqual(packet[IP].dst, server2.ip4)
4252                 if packet.haslayer(TCP):
4253                     self.assertEqual(packet[TCP].dport, self.tcp_port_in)
4254                     self.assertEqual(packet[TCP].sport, server_tcp_port)
4255                     self.assert_packet_checksums_valid(packet)
4256                 elif packet.haslayer(UDP):
4257                     self.assertEqual(packet[UDP].dport, self.udp_port_in)
4258                     self.assertEqual(packet[UDP].sport, server_udp_port)
4259                 else:
4260                     self.assertEqual(packet[ICMP].id, self.icmp_id_in)
4261             except:
4262                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
4263                 raise
4264
4265
4266 if __name__ == '__main__':
4267     unittest.main(testRunner=VppTestRunner)