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