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