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