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