make test: unify packet checksum verifications
[vpp.git] / test / test_nat.py
1 #!/usr/bin/env python
2
3 import socket
4 import unittest
5 import struct
6 import StringIO
7 import random
8
9 from framework import VppTestCase, VppTestRunner, running_extended_tests
10 from scapy.layers.inet import IP, TCP, UDP, ICMP
11 from scapy.layers.inet import IPerror, TCPerror, UDPerror, ICMPerror
12 from scapy.layers.inet6 import IPv6, ICMPv6EchoRequest, ICMPv6EchoReply
13 from scapy.layers.inet6 import ICMPv6DestUnreach, IPerror6, IPv6ExtHdrFragment
14 from scapy.layers.l2 import Ether, ARP, GRE
15 from scapy.data import IP_PROTOS
16 from scapy.packet import bind_layers, Raw
17 from scapy.all import fragment6
18 from util import ppp
19 from ipfix import IPFIX, Set, Template, Data, IPFIXDecoder
20 from time import sleep
21 from util import ip4_range
22 from util import mactobinary
23
24
25 class MethodHolder(VppTestCase):
26     """ NAT create capture and verify method holder """
27
28     def create_stream_in(self, in_if, out_if, dst_ip=None, ttl=64):
29         """
30         Create packet stream for inside network
31
32         :param in_if: Inside interface
33         :param out_if: Outside interface
34         :param dst_ip: Destination address
35         :param ttl: TTL of generated packets
36         """
37         if dst_ip is None:
38             dst_ip = out_if.remote_ip4
39
40         pkts = []
41         # TCP
42         p = (Ether(dst=in_if.local_mac, src=in_if.remote_mac) /
43              IP(src=in_if.remote_ip4, dst=dst_ip, ttl=ttl) /
44              TCP(sport=self.tcp_port_in, dport=20))
45         pkts.append(p)
46
47         # UDP
48         p = (Ether(dst=in_if.local_mac, src=in_if.remote_mac) /
49              IP(src=in_if.remote_ip4, dst=dst_ip, ttl=ttl) /
50              UDP(sport=self.udp_port_in, dport=20))
51         pkts.append(p)
52
53         # ICMP
54         p = (Ether(dst=in_if.local_mac, src=in_if.remote_mac) /
55              IP(src=in_if.remote_ip4, dst=dst_ip, ttl=ttl) /
56              ICMP(id=self.icmp_id_in, type='echo-request'))
57         pkts.append(p)
58
59         return pkts
60
61     def compose_ip6(self, ip4, pref, plen):
62         """
63         Compose IPv4-embedded IPv6 addresses
64
65         :param ip4: IPv4 address
66         :param pref: IPv6 prefix
67         :param plen: IPv6 prefix length
68         :returns: IPv4-embedded IPv6 addresses
69         """
70         pref_n = list(socket.inet_pton(socket.AF_INET6, pref))
71         ip4_n = list(socket.inet_pton(socket.AF_INET, ip4))
72         if plen == 32:
73             pref_n[4] = ip4_n[0]
74             pref_n[5] = ip4_n[1]
75             pref_n[6] = ip4_n[2]
76             pref_n[7] = ip4_n[3]
77         elif plen == 40:
78             pref_n[5] = ip4_n[0]
79             pref_n[6] = ip4_n[1]
80             pref_n[7] = ip4_n[2]
81             pref_n[9] = ip4_n[3]
82         elif plen == 48:
83             pref_n[6] = ip4_n[0]
84             pref_n[7] = ip4_n[1]
85             pref_n[9] = ip4_n[2]
86             pref_n[10] = ip4_n[3]
87         elif plen == 56:
88             pref_n[7] = ip4_n[0]
89             pref_n[9] = ip4_n[1]
90             pref_n[10] = ip4_n[2]
91             pref_n[11] = ip4_n[3]
92         elif plen == 64:
93             pref_n[9] = ip4_n[0]
94             pref_n[10] = ip4_n[1]
95             pref_n[11] = ip4_n[2]
96             pref_n[12] = ip4_n[3]
97         elif plen == 96:
98             pref_n[12] = ip4_n[0]
99             pref_n[13] = ip4_n[1]
100             pref_n[14] = ip4_n[2]
101             pref_n[15] = ip4_n[3]
102         return socket.inet_ntop(socket.AF_INET6, ''.join(pref_n))
103
104     def extract_ip4(self, ip6, plen):
105         """
106         Extract IPv4 address embedded in IPv6 addresses
107
108         :param ip6: IPv6 address
109         :param plen: IPv6 prefix length
110         :returns: extracted IPv4 address
111         """
112         ip6_n = list(socket.inet_pton(socket.AF_INET6, ip6))
113         ip4_n = [None] * 4
114         if plen == 32:
115             ip4_n[0] = ip6_n[4]
116             ip4_n[1] = ip6_n[5]
117             ip4_n[2] = ip6_n[6]
118             ip4_n[3] = ip6_n[7]
119         elif plen == 40:
120             ip4_n[0] = ip6_n[5]
121             ip4_n[1] = ip6_n[6]
122             ip4_n[2] = ip6_n[7]
123             ip4_n[3] = ip6_n[9]
124         elif plen == 48:
125             ip4_n[0] = ip6_n[6]
126             ip4_n[1] = ip6_n[7]
127             ip4_n[2] = ip6_n[9]
128             ip4_n[3] = ip6_n[10]
129         elif plen == 56:
130             ip4_n[0] = ip6_n[7]
131             ip4_n[1] = ip6_n[9]
132             ip4_n[2] = ip6_n[10]
133             ip4_n[3] = ip6_n[11]
134         elif plen == 64:
135             ip4_n[0] = ip6_n[9]
136             ip4_n[1] = ip6_n[10]
137             ip4_n[2] = ip6_n[11]
138             ip4_n[3] = ip6_n[12]
139         elif plen == 96:
140             ip4_n[0] = ip6_n[12]
141             ip4_n[1] = ip6_n[13]
142             ip4_n[2] = ip6_n[14]
143             ip4_n[3] = ip6_n[15]
144         return socket.inet_ntop(socket.AF_INET, ''.join(ip4_n))
145
146     def create_stream_in_ip6(self, in_if, out_if, hlim=64, pref=None, plen=0):
147         """
148         Create IPv6 packet stream for inside network
149
150         :param in_if: Inside interface
151         :param out_if: Outside interface
152         :param ttl: Hop Limit of generated packets
153         :param pref: NAT64 prefix
154         :param plen: NAT64 prefix length
155         """
156         pkts = []
157         if pref is None:
158             dst = ''.join(['64:ff9b::', out_if.remote_ip4])
159         else:
160             dst = self.compose_ip6(out_if.remote_ip4, pref, plen)
161
162         # TCP
163         p = (Ether(dst=in_if.local_mac, src=in_if.remote_mac) /
164              IPv6(src=in_if.remote_ip6, dst=dst, hlim=hlim) /
165              TCP(sport=self.tcp_port_in, dport=20))
166         pkts.append(p)
167
168         # UDP
169         p = (Ether(dst=in_if.local_mac, src=in_if.remote_mac) /
170              IPv6(src=in_if.remote_ip6, dst=dst, hlim=hlim) /
171              UDP(sport=self.udp_port_in, dport=20))
172         pkts.append(p)
173
174         # ICMP
175         p = (Ether(dst=in_if.local_mac, src=in_if.remote_mac) /
176              IPv6(src=in_if.remote_ip6, dst=dst, hlim=hlim) /
177              ICMPv6EchoRequest(id=self.icmp_id_in))
178         pkts.append(p)
179
180         return pkts
181
182     def create_stream_out(self, out_if, dst_ip=None, ttl=64,
183                           use_inside_ports=False):
184         """
185         Create packet stream for outside network
186
187         :param out_if: Outside interface
188         :param dst_ip: Destination IP address (Default use global NAT address)
189         :param ttl: TTL of generated packets
190         :param use_inside_ports: Use inside NAT ports as destination ports
191                instead of outside ports
192         """
193         if dst_ip is None:
194             dst_ip = self.nat_addr
195         if not use_inside_ports:
196             tcp_port = self.tcp_port_out
197             udp_port = self.udp_port_out
198             icmp_id = self.icmp_id_out
199         else:
200             tcp_port = self.tcp_port_in
201             udp_port = self.udp_port_in
202             icmp_id = self.icmp_id_in
203         pkts = []
204         # TCP
205         p = (Ether(dst=out_if.local_mac, src=out_if.remote_mac) /
206              IP(src=out_if.remote_ip4, dst=dst_ip, ttl=ttl) /
207              TCP(dport=tcp_port, sport=20))
208         pkts.append(p)
209
210         # UDP
211         p = (Ether(dst=out_if.local_mac, src=out_if.remote_mac) /
212              IP(src=out_if.remote_ip4, dst=dst_ip, ttl=ttl) /
213              UDP(dport=udp_port, sport=20))
214         pkts.append(p)
215
216         # ICMP
217         p = (Ether(dst=out_if.local_mac, src=out_if.remote_mac) /
218              IP(src=out_if.remote_ip4, dst=dst_ip, ttl=ttl) /
219              ICMP(id=icmp_id, type='echo-reply'))
220         pkts.append(p)
221
222         return pkts
223
224     def create_stream_out_ip6(self, out_if, src_ip, dst_ip, hl=64):
225         """
226         Create packet stream for outside network
227
228         :param out_if: Outside interface
229         :param dst_ip: Destination IP address (Default use global NAT address)
230         :param hl: HL of generated packets
231         """
232         pkts = []
233         # TCP
234         p = (Ether(dst=out_if.local_mac, src=out_if.remote_mac) /
235              IPv6(src=src_ip, dst=dst_ip, hlim=hl) /
236              TCP(dport=self.tcp_port_out, sport=20))
237         pkts.append(p)
238
239         # UDP
240         p = (Ether(dst=out_if.local_mac, src=out_if.remote_mac) /
241              IPv6(src=src_ip, dst=dst_ip, hlim=hl) /
242              UDP(dport=self.udp_port_out, sport=20))
243         pkts.append(p)
244
245         # ICMP
246         p = (Ether(dst=out_if.local_mac, src=out_if.remote_mac) /
247              IPv6(src=src_ip, dst=dst_ip, hlim=hl) /
248              ICMPv6EchoReply(id=self.icmp_id_out))
249         pkts.append(p)
250
251         return pkts
252
253     def verify_capture_out(self, capture, nat_ip=None, same_port=False,
254                            packet_num=3, dst_ip=None, is_ip6=False):
255         """
256         Verify captured packets on outside network
257
258         :param capture: Captured packets
259         :param nat_ip: Translated IP address (Default use global NAT address)
260         :param same_port: Sorce port number is not translated (Default False)
261         :param packet_num: Expected number of packets (Default 3)
262         :param dst_ip: Destination IP address (Default do not verify)
263         :param is_ip6: If L3 protocol is IPv6 (Default False)
264         """
265         if is_ip6:
266             IP46 = IPv6
267             ICMP46 = ICMPv6EchoRequest
268         else:
269             IP46 = IP
270             ICMP46 = ICMP
271         if nat_ip is None:
272             nat_ip = self.nat_addr
273         self.assertEqual(packet_num, len(capture))
274         for packet in capture:
275             try:
276                 if not is_ip6:
277                     self.assert_packet_checksums_valid(packet)
278                 self.assertEqual(packet[IP46].src, nat_ip)
279                 if dst_ip is not None:
280                     self.assertEqual(packet[IP46].dst, dst_ip)
281                 if packet.haslayer(TCP):
282                     if same_port:
283                         self.assertEqual(packet[TCP].sport, self.tcp_port_in)
284                     else:
285                         self.assertNotEqual(
286                             packet[TCP].sport, self.tcp_port_in)
287                     self.tcp_port_out = packet[TCP].sport
288                     self.assert_packet_checksums_valid(packet)
289                 elif packet.haslayer(UDP):
290                     if same_port:
291                         self.assertEqual(packet[UDP].sport, self.udp_port_in)
292                     else:
293                         self.assertNotEqual(
294                             packet[UDP].sport, self.udp_port_in)
295                     self.udp_port_out = packet[UDP].sport
296                 else:
297                     if same_port:
298                         self.assertEqual(packet[ICMP46].id, self.icmp_id_in)
299                     else:
300                         self.assertNotEqual(packet[ICMP46].id, self.icmp_id_in)
301                     self.icmp_id_out = packet[ICMP46].id
302                     self.assert_packet_checksums_valid(packet)
303             except:
304                 self.logger.error(ppp("Unexpected or invalid packet "
305                                       "(outside network):", packet))
306                 raise
307
308     def verify_capture_out_ip6(self, capture, nat_ip, same_port=False,
309                                packet_num=3, dst_ip=None):
310         """
311         Verify captured packets on outside network
312
313         :param capture: Captured packets
314         :param nat_ip: Translated IP address
315         :param same_port: Sorce port number is not translated (Default False)
316         :param packet_num: Expected number of packets (Default 3)
317         :param dst_ip: Destination IP address (Default do not verify)
318         """
319         return self.verify_capture_out(capture, nat_ip, same_port, packet_num,
320                                        dst_ip, True)
321
322     def verify_capture_in(self, capture, in_if, packet_num=3):
323         """
324         Verify captured packets on inside network
325
326         :param capture: Captured packets
327         :param in_if: Inside interface
328         :param packet_num: Expected number of packets (Default 3)
329         """
330         self.assertEqual(packet_num, len(capture))
331         for packet in capture:
332             try:
333                 self.assert_packet_checksums_valid(packet)
334                 self.assertEqual(packet[IP].dst, in_if.remote_ip4)
335                 if packet.haslayer(TCP):
336                     self.assertEqual(packet[TCP].dport, self.tcp_port_in)
337                 elif packet.haslayer(UDP):
338                     self.assertEqual(packet[UDP].dport, self.udp_port_in)
339                 else:
340                     self.assertEqual(packet[ICMP].id, self.icmp_id_in)
341             except:
342                 self.logger.error(ppp("Unexpected or invalid packet "
343                                       "(inside network):", packet))
344                 raise
345
346     def verify_capture_in_ip6(self, capture, src_ip, dst_ip, packet_num=3):
347         """
348         Verify captured IPv6 packets on inside network
349
350         :param capture: Captured packets
351         :param src_ip: Source IP
352         :param dst_ip: Destination IP address
353         :param packet_num: Expected number of packets (Default 3)
354         """
355         self.assertEqual(packet_num, len(capture))
356         for packet in capture:
357             try:
358                 self.assertEqual(packet[IPv6].src, src_ip)
359                 self.assertEqual(packet[IPv6].dst, dst_ip)
360                 self.assert_packet_checksums_valid(packet)
361                 if packet.haslayer(TCP):
362                     self.assertEqual(packet[TCP].dport, self.tcp_port_in)
363                 elif packet.haslayer(UDP):
364                     self.assertEqual(packet[UDP].dport, self.udp_port_in)
365                 else:
366                     self.assertEqual(packet[ICMPv6EchoReply].id,
367                                      self.icmp_id_in)
368             except:
369                 self.logger.error(ppp("Unexpected or invalid packet "
370                                       "(inside network):", packet))
371                 raise
372
373     def verify_capture_no_translation(self, capture, ingress_if, egress_if):
374         """
375         Verify captured packet that don't have to be translated
376
377         :param capture: Captured packets
378         :param ingress_if: Ingress interface
379         :param egress_if: Egress interface
380         """
381         for packet in capture:
382             try:
383                 self.assertEqual(packet[IP].src, ingress_if.remote_ip4)
384                 self.assertEqual(packet[IP].dst, egress_if.remote_ip4)
385                 if packet.haslayer(TCP):
386                     self.assertEqual(packet[TCP].sport, self.tcp_port_in)
387                 elif packet.haslayer(UDP):
388                     self.assertEqual(packet[UDP].sport, self.udp_port_in)
389                 else:
390                     self.assertEqual(packet[ICMP].id, self.icmp_id_in)
391             except:
392                 self.logger.error(ppp("Unexpected or invalid packet "
393                                       "(inside network):", packet))
394                 raise
395
396     def verify_capture_out_with_icmp_errors(self, capture, src_ip=None,
397                                             packet_num=3, icmp_type=11):
398         """
399         Verify captured packets with ICMP errors on outside network
400
401         :param capture: Captured packets
402         :param src_ip: Translated IP address or IP address of VPP
403                        (Default use global NAT address)
404         :param packet_num: Expected number of packets (Default 3)
405         :param icmp_type: Type of error ICMP packet
406                           we are expecting (Default 11)
407         """
408         if src_ip is None:
409             src_ip = self.nat_addr
410         self.assertEqual(packet_num, len(capture))
411         for packet in capture:
412             try:
413                 self.assertEqual(packet[IP].src, src_ip)
414                 self.assertTrue(packet.haslayer(ICMP))
415                 icmp = packet[ICMP]
416                 self.assertEqual(icmp.type, icmp_type)
417                 self.assertTrue(icmp.haslayer(IPerror))
418                 inner_ip = icmp[IPerror]
419                 if inner_ip.haslayer(TCPerror):
420                     self.assertEqual(inner_ip[TCPerror].dport,
421                                      self.tcp_port_out)
422                 elif inner_ip.haslayer(UDPerror):
423                     self.assertEqual(inner_ip[UDPerror].dport,
424                                      self.udp_port_out)
425                 else:
426                     self.assertEqual(inner_ip[ICMPerror].id, self.icmp_id_out)
427             except:
428                 self.logger.error(ppp("Unexpected or invalid packet "
429                                       "(outside network):", packet))
430                 raise
431
432     def verify_capture_in_with_icmp_errors(self, capture, in_if, packet_num=3,
433                                            icmp_type=11):
434         """
435         Verify captured packets with ICMP errors on inside network
436
437         :param capture: Captured packets
438         :param in_if: Inside interface
439         :param packet_num: Expected number of packets (Default 3)
440         :param icmp_type: Type of error ICMP packet
441                           we are expecting (Default 11)
442         """
443         self.assertEqual(packet_num, len(capture))
444         for packet in capture:
445             try:
446                 self.assertEqual(packet[IP].dst, in_if.remote_ip4)
447                 self.assertTrue(packet.haslayer(ICMP))
448                 icmp = packet[ICMP]
449                 self.assertEqual(icmp.type, icmp_type)
450                 self.assertTrue(icmp.haslayer(IPerror))
451                 inner_ip = icmp[IPerror]
452                 if inner_ip.haslayer(TCPerror):
453                     self.assertEqual(inner_ip[TCPerror].sport,
454                                      self.tcp_port_in)
455                 elif inner_ip.haslayer(UDPerror):
456                     self.assertEqual(inner_ip[UDPerror].sport,
457                                      self.udp_port_in)
458                 else:
459                     self.assertEqual(inner_ip[ICMPerror].id, self.icmp_id_in)
460             except:
461                 self.logger.error(ppp("Unexpected or invalid packet "
462                                       "(inside network):", packet))
463                 raise
464
465     def create_stream_frag(self, src_if, dst, sport, dport, data):
466         """
467         Create fragmented packet stream
468
469         :param src_if: Source interface
470         :param dst: Destination IPv4 address
471         :param sport: Source TCP port
472         :param dport: Destination TCP port
473         :param data: Payload data
474         :returns: Fragmets
475         """
476         id = random.randint(0, 65535)
477         p = (IP(src=src_if.remote_ip4, dst=dst) /
478              TCP(sport=sport, dport=dport) /
479              Raw(data))
480         p = p.__class__(str(p))
481         chksum = p['TCP'].chksum
482         pkts = []
483         p = (Ether(src=src_if.remote_mac, dst=src_if.local_mac) /
484              IP(src=src_if.remote_ip4, dst=dst, flags="MF", frag=0, id=id) /
485              TCP(sport=sport, dport=dport, chksum=chksum) /
486              Raw(data[0:4]))
487         pkts.append(p)
488         p = (Ether(src=src_if.remote_mac, dst=src_if.local_mac) /
489              IP(src=src_if.remote_ip4, dst=dst, flags="MF", frag=3, id=id,
490                 proto=IP_PROTOS.tcp) /
491              Raw(data[4:20]))
492         pkts.append(p)
493         p = (Ether(src=src_if.remote_mac, dst=src_if.local_mac) /
494              IP(src=src_if.remote_ip4, dst=dst, frag=5, proto=IP_PROTOS.tcp,
495                 id=id) /
496              Raw(data[20:]))
497         pkts.append(p)
498         return pkts
499
500     def create_stream_frag_ip6(self, src_if, dst, sport, dport, data,
501                                pref=None, plen=0, frag_size=128):
502         """
503         Create fragmented packet stream
504
505         :param src_if: Source interface
506         :param dst: Destination IPv4 address
507         :param sport: Source TCP port
508         :param dport: Destination TCP port
509         :param data: Payload data
510         :param pref: NAT64 prefix
511         :param plen: NAT64 prefix length
512         :param fragsize: size of fragments
513         :returns: Fragmets
514         """
515         if pref is None:
516             dst_ip6 = ''.join(['64:ff9b::', dst])
517         else:
518             dst_ip6 = self.compose_ip6(dst, pref, plen)
519
520         p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
521              IPv6(src=src_if.remote_ip6, dst=dst_ip6) /
522              IPv6ExtHdrFragment(id=random.randint(0, 65535)) /
523              TCP(sport=sport, dport=dport) /
524              Raw(data))
525
526         return fragment6(p, frag_size)
527
528     def reass_frags_and_verify(self, frags, src, dst):
529         """
530         Reassemble and verify fragmented packet
531
532         :param frags: Captured fragments
533         :param src: Source IPv4 address to verify
534         :param dst: Destination IPv4 address to verify
535
536         :returns: Reassembled IPv4 packet
537         """
538         buffer = StringIO.StringIO()
539         for p in frags:
540             self.assertEqual(p[IP].src, src)
541             self.assertEqual(p[IP].dst, dst)
542             self.assert_ip_checksum_valid(p)
543             buffer.seek(p[IP].frag * 8)
544             buffer.write(p[IP].payload)
545         ip = frags[0].getlayer(IP)
546         ip = IP(src=frags[0][IP].src, dst=frags[0][IP].dst,
547                 proto=frags[0][IP].proto)
548         if ip.proto == IP_PROTOS.tcp:
549             p = (ip / TCP(buffer.getvalue()))
550             self.assert_tcp_checksum_valid(p)
551         elif ip.proto == IP_PROTOS.udp:
552             p = (ip / UDP(buffer.getvalue()))
553         return p
554
555     def reass_frags_and_verify_ip6(self, frags, src, dst):
556         """
557         Reassemble and verify fragmented packet
558
559         :param frags: Captured fragments
560         :param src: Source IPv6 address to verify
561         :param dst: Destination IPv6 address to verify
562
563         :returns: Reassembled IPv6 packet
564         """
565         buffer = StringIO.StringIO()
566         for p in frags:
567             self.assertEqual(p[IPv6].src, src)
568             self.assertEqual(p[IPv6].dst, dst)
569             buffer.seek(p[IPv6ExtHdrFragment].offset * 8)
570             buffer.write(p[IPv6ExtHdrFragment].payload)
571         ip = IPv6(src=frags[0][IPv6].src, dst=frags[0][IPv6].dst,
572                   nh=frags[0][IPv6ExtHdrFragment].nh)
573         if ip.nh == IP_PROTOS.tcp:
574             p = (ip / TCP(buffer.getvalue()))
575         elif ip.nh == IP_PROTOS.udp:
576             p = (ip / UDP(buffer.getvalue()))
577         self.assert_packet_checksums_valid(p)
578         return p
579
580     def initiate_tcp_session(self, in_if, out_if):
581         """
582         Initiates TCP session
583
584         :param in_if: Inside interface
585         :param out_if: Outside interface
586         """
587         try:
588             # SYN packet in->out
589             p = (Ether(src=in_if.remote_mac, dst=in_if.local_mac) /
590                  IP(src=in_if.remote_ip4, dst=out_if.remote_ip4) /
591                  TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
592                      flags="S"))
593             in_if.add_stream(p)
594             self.pg_enable_capture(self.pg_interfaces)
595             self.pg_start()
596             capture = out_if.get_capture(1)
597             p = capture[0]
598             self.tcp_port_out = p[TCP].sport
599
600             # SYN + ACK packet out->in
601             p = (Ether(src=out_if.remote_mac, dst=out_if.local_mac) /
602                  IP(src=out_if.remote_ip4, dst=self.nat_addr) /
603                  TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
604                      flags="SA"))
605             out_if.add_stream(p)
606             self.pg_enable_capture(self.pg_interfaces)
607             self.pg_start()
608             in_if.get_capture(1)
609
610             # ACK packet in->out
611             p = (Ether(src=in_if.remote_mac, dst=in_if.local_mac) /
612                  IP(src=in_if.remote_ip4, dst=out_if.remote_ip4) /
613                  TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
614                      flags="A"))
615             in_if.add_stream(p)
616             self.pg_enable_capture(self.pg_interfaces)
617             self.pg_start()
618             out_if.get_capture(1)
619
620         except:
621             self.logger.error("TCP 3 way handshake failed")
622             raise
623
624     def verify_ipfix_nat44_ses(self, data):
625         """
626         Verify IPFIX NAT44 session create/delete event
627
628         :param data: Decoded IPFIX data records
629         """
630         nat44_ses_create_num = 0
631         nat44_ses_delete_num = 0
632         self.assertEqual(6, len(data))
633         for record in data:
634             # natEvent
635             self.assertIn(ord(record[230]), [4, 5])
636             if ord(record[230]) == 4:
637                 nat44_ses_create_num += 1
638             else:
639                 nat44_ses_delete_num += 1
640             # sourceIPv4Address
641             self.assertEqual(self.pg0.remote_ip4n, record[8])
642             # postNATSourceIPv4Address
643             self.assertEqual(socket.inet_pton(socket.AF_INET, self.nat_addr),
644                              record[225])
645             # ingressVRFID
646             self.assertEqual(struct.pack("!I", 0), record[234])
647             # protocolIdentifier/sourceTransportPort/postNAPTSourceTransportPort
648             if IP_PROTOS.icmp == ord(record[4]):
649                 self.assertEqual(struct.pack("!H", self.icmp_id_in), record[7])
650                 self.assertEqual(struct.pack("!H", self.icmp_id_out),
651                                  record[227])
652             elif IP_PROTOS.tcp == ord(record[4]):
653                 self.assertEqual(struct.pack("!H", self.tcp_port_in),
654                                  record[7])
655                 self.assertEqual(struct.pack("!H", self.tcp_port_out),
656                                  record[227])
657             elif IP_PROTOS.udp == ord(record[4]):
658                 self.assertEqual(struct.pack("!H", self.udp_port_in),
659                                  record[7])
660                 self.assertEqual(struct.pack("!H", self.udp_port_out),
661                                  record[227])
662             else:
663                 self.fail("Invalid protocol")
664         self.assertEqual(3, nat44_ses_create_num)
665         self.assertEqual(3, nat44_ses_delete_num)
666
667     def verify_ipfix_addr_exhausted(self, data):
668         """
669         Verify IPFIX NAT addresses event
670
671         :param data: Decoded IPFIX data records
672         """
673         self.assertEqual(1, len(data))
674         record = data[0]
675         # natEvent
676         self.assertEqual(ord(record[230]), 3)
677         # natPoolID
678         self.assertEqual(struct.pack("!I", 0), record[283])
679
680     def verify_ipfix_max_sessions(self, data, limit):
681         """
682         Verify IPFIX maximum session entries exceeded event
683
684         :param data: Decoded IPFIX data records
685         :param limit: Number of maximum session entries that can be created.
686         """
687         self.assertEqual(1, len(data))
688         record = data[0]
689         # natEvent
690         self.assertEqual(ord(record[230]), 13)
691         # natQuotaExceededEvent
692         self.assertEqual(struct.pack("I", 1), record[466])
693         # maxSessionEntries
694         self.assertEqual(struct.pack("I", limit), record[471])
695
696     def verify_ipfix_max_bibs(self, data, limit):
697         """
698         Verify IPFIX maximum BIB entries exceeded event
699
700         :param data: Decoded IPFIX data records
701         :param limit: Number of maximum BIB entries that can be created.
702         """
703         self.assertEqual(1, len(data))
704         record = data[0]
705         # natEvent
706         self.assertEqual(ord(record[230]), 13)
707         # natQuotaExceededEvent
708         self.assertEqual(struct.pack("I", 2), record[466])
709         # maxBIBEntries
710         self.assertEqual(struct.pack("I", limit), record[472])
711
712     def verify_ipfix_max_fragments_ip6(self, data, limit, src_addr):
713         """
714         Verify IPFIX maximum IPv6 fragments pending reassembly exceeded event
715
716         :param data: Decoded IPFIX data records
717         :param limit: Number of maximum fragments pending reassembly
718         :param src_addr: IPv6 source address
719         """
720         self.assertEqual(1, len(data))
721         record = data[0]
722         # natEvent
723         self.assertEqual(ord(record[230]), 13)
724         # natQuotaExceededEvent
725         self.assertEqual(struct.pack("I", 5), record[466])
726         # maxFragmentsPendingReassembly
727         self.assertEqual(struct.pack("I", limit), record[475])
728         # sourceIPv6Address
729         self.assertEqual(src_addr, record[27])
730
731     def verify_ipfix_max_fragments_ip4(self, data, limit, src_addr):
732         """
733         Verify IPFIX maximum IPv4 fragments pending reassembly exceeded event
734
735         :param data: Decoded IPFIX data records
736         :param limit: Number of maximum fragments pending reassembly
737         :param src_addr: IPv4 source address
738         """
739         self.assertEqual(1, len(data))
740         record = data[0]
741         # natEvent
742         self.assertEqual(ord(record[230]), 13)
743         # natQuotaExceededEvent
744         self.assertEqual(struct.pack("I", 5), record[466])
745         # maxFragmentsPendingReassembly
746         self.assertEqual(struct.pack("I", limit), record[475])
747         # sourceIPv4Address
748         self.assertEqual(src_addr, record[8])
749
750     def verify_ipfix_bib(self, data, is_create, src_addr):
751         """
752         Verify IPFIX NAT64 BIB create and delete events
753
754         :param data: Decoded IPFIX data records
755         :param is_create: Create event if nonzero value otherwise delete event
756         :param src_addr: IPv6 source address
757         """
758         self.assertEqual(1, len(data))
759         record = data[0]
760         # natEvent
761         if is_create:
762             self.assertEqual(ord(record[230]), 10)
763         else:
764             self.assertEqual(ord(record[230]), 11)
765         # sourceIPv6Address
766         self.assertEqual(src_addr, record[27])
767         # postNATSourceIPv4Address
768         self.assertEqual(self.nat_addr_n, record[225])
769         # protocolIdentifier
770         self.assertEqual(IP_PROTOS.tcp, ord(record[4]))
771         # ingressVRFID
772         self.assertEqual(struct.pack("!I", 0), record[234])
773         # sourceTransportPort
774         self.assertEqual(struct.pack("!H", self.tcp_port_in), record[7])
775         # postNAPTSourceTransportPort
776         self.assertEqual(struct.pack("!H", self.tcp_port_out), record[227])
777
778     def verify_ipfix_nat64_ses(self, data, is_create, src_addr, dst_addr,
779                                dst_port):
780         """
781         Verify IPFIX NAT64 session create and delete events
782
783         :param data: Decoded IPFIX data records
784         :param is_create: Create event if nonzero value otherwise delete event
785         :param src_addr: IPv6 source address
786         :param dst_addr: IPv4 destination address
787         :param dst_port: destination TCP port
788         """
789         self.assertEqual(1, len(data))
790         record = data[0]
791         # natEvent
792         if is_create:
793             self.assertEqual(ord(record[230]), 6)
794         else:
795             self.assertEqual(ord(record[230]), 7)
796         # sourceIPv6Address
797         self.assertEqual(src_addr, record[27])
798         # destinationIPv6Address
799         self.assertEqual(socket.inet_pton(socket.AF_INET6,
800                                           self.compose_ip6(dst_addr,
801                                                            '64:ff9b::',
802                                                            96)),
803                          record[28])
804         # postNATSourceIPv4Address
805         self.assertEqual(self.nat_addr_n, record[225])
806         # postNATDestinationIPv4Address
807         self.assertEqual(socket.inet_pton(socket.AF_INET, dst_addr),
808                          record[226])
809         # protocolIdentifier
810         self.assertEqual(IP_PROTOS.tcp, ord(record[4]))
811         # ingressVRFID
812         self.assertEqual(struct.pack("!I", 0), record[234])
813         # sourceTransportPort
814         self.assertEqual(struct.pack("!H", self.tcp_port_in), record[7])
815         # postNAPTSourceTransportPort
816         self.assertEqual(struct.pack("!H", self.tcp_port_out), record[227])
817         # destinationTransportPort
818         self.assertEqual(struct.pack("!H", dst_port), record[11])
819         # postNAPTDestinationTransportPort
820         self.assertEqual(struct.pack("!H", dst_port), record[228])
821
822
823 class TestNAT44(MethodHolder):
824     """ NAT44 Test Cases """
825
826     @classmethod
827     def setUpClass(cls):
828         super(TestNAT44, cls).setUpClass()
829
830         try:
831             cls.tcp_port_in = 6303
832             cls.tcp_port_out = 6303
833             cls.udp_port_in = 6304
834             cls.udp_port_out = 6304
835             cls.icmp_id_in = 6305
836             cls.icmp_id_out = 6305
837             cls.nat_addr = '10.0.0.3'
838             cls.nat_addr_n = socket.inet_pton(socket.AF_INET, cls.nat_addr)
839             cls.ipfix_src_port = 4739
840             cls.ipfix_domain_id = 1
841             cls.tcp_external_port = 80
842
843             cls.create_pg_interfaces(range(10))
844             cls.interfaces = list(cls.pg_interfaces[0:4])
845
846             for i in cls.interfaces:
847                 i.admin_up()
848                 i.config_ip4()
849                 i.resolve_arp()
850
851             cls.pg0.generate_remote_hosts(3)
852             cls.pg0.configure_ipv4_neighbors()
853
854             cls.pg1.generate_remote_hosts(1)
855             cls.pg1.configure_ipv4_neighbors()
856
857             cls.overlapping_interfaces = list(list(cls.pg_interfaces[4:7]))
858             cls.vapi.ip_table_add_del(10, is_add=1)
859             cls.vapi.ip_table_add_del(20, is_add=1)
860
861             cls.pg4._local_ip4 = "172.16.255.1"
862             cls.pg4._local_ip4n = socket.inet_pton(socket.AF_INET, i.local_ip4)
863             cls.pg4._remote_hosts[0]._ip4 = "172.16.255.2"
864             cls.pg4.set_table_ip4(10)
865             cls.pg5._local_ip4 = "172.17.255.3"
866             cls.pg5._local_ip4n = socket.inet_pton(socket.AF_INET, i.local_ip4)
867             cls.pg5._remote_hosts[0]._ip4 = "172.17.255.4"
868             cls.pg5.set_table_ip4(10)
869             cls.pg6._local_ip4 = "172.16.255.1"
870             cls.pg6._local_ip4n = socket.inet_pton(socket.AF_INET, i.local_ip4)
871             cls.pg6._remote_hosts[0]._ip4 = "172.16.255.2"
872             cls.pg6.set_table_ip4(20)
873             for i in cls.overlapping_interfaces:
874                 i.config_ip4()
875                 i.admin_up()
876                 i.resolve_arp()
877
878             cls.pg7.admin_up()
879             cls.pg8.admin_up()
880
881             cls.pg9.generate_remote_hosts(2)
882             cls.pg9.config_ip4()
883             ip_addr_n = socket.inet_pton(socket.AF_INET, "10.0.0.1")
884             cls.vapi.sw_interface_add_del_address(cls.pg9.sw_if_index,
885                                                   ip_addr_n,
886                                                   24)
887             cls.pg9.admin_up()
888             cls.pg9.resolve_arp()
889             cls.pg9._remote_hosts[1]._ip4 = cls.pg9._remote_hosts[0]._ip4
890             cls.pg4._remote_ip4 = cls.pg9._remote_hosts[0]._ip4 = "10.0.0.2"
891             cls.pg9.resolve_arp()
892
893         except Exception:
894             super(TestNAT44, cls).tearDownClass()
895             raise
896
897     def clear_nat44(self):
898         """
899         Clear NAT44 configuration.
900         """
901         # I found no elegant way to do this
902         self.vapi.ip_add_del_route(dst_address=self.pg7.remote_ip4n,
903                                    dst_address_length=32,
904                                    next_hop_address=self.pg7.remote_ip4n,
905                                    next_hop_sw_if_index=self.pg7.sw_if_index,
906                                    is_add=0)
907         self.vapi.ip_add_del_route(dst_address=self.pg8.remote_ip4n,
908                                    dst_address_length=32,
909                                    next_hop_address=self.pg8.remote_ip4n,
910                                    next_hop_sw_if_index=self.pg8.sw_if_index,
911                                    is_add=0)
912
913         for intf in [self.pg7, self.pg8]:
914             neighbors = self.vapi.ip_neighbor_dump(intf.sw_if_index)
915             for n in neighbors:
916                 self.vapi.ip_neighbor_add_del(intf.sw_if_index,
917                                               n.mac_address,
918                                               n.ip_address,
919                                               is_add=0)
920
921         if self.pg7.has_ip4_config:
922             self.pg7.unconfig_ip4()
923
924         self.vapi.nat44_forwarding_enable_disable(0)
925
926         interfaces = self.vapi.nat44_interface_addr_dump()
927         for intf in interfaces:
928             self.vapi.nat44_add_interface_addr(intf.sw_if_index,
929                                                twice_nat=intf.twice_nat,
930                                                is_add=0)
931
932         self.vapi.nat_ipfix(enable=0, src_port=self.ipfix_src_port,
933                             domain_id=self.ipfix_domain_id)
934         self.ipfix_src_port = 4739
935         self.ipfix_domain_id = 1
936
937         interfaces = self.vapi.nat44_interface_dump()
938         for intf in interfaces:
939             if intf.is_inside > 1:
940                 self.vapi.nat44_interface_add_del_feature(intf.sw_if_index,
941                                                           0,
942                                                           is_add=0)
943             self.vapi.nat44_interface_add_del_feature(intf.sw_if_index,
944                                                       intf.is_inside,
945                                                       is_add=0)
946
947         interfaces = self.vapi.nat44_interface_output_feature_dump()
948         for intf in interfaces:
949             self.vapi.nat44_interface_add_del_output_feature(intf.sw_if_index,
950                                                              intf.is_inside,
951                                                              is_add=0)
952
953         static_mappings = self.vapi.nat44_static_mapping_dump()
954         for sm in static_mappings:
955             self.vapi.nat44_add_del_static_mapping(
956                 sm.local_ip_address,
957                 sm.external_ip_address,
958                 local_port=sm.local_port,
959                 external_port=sm.external_port,
960                 addr_only=sm.addr_only,
961                 vrf_id=sm.vrf_id,
962                 protocol=sm.protocol,
963                 twice_nat=sm.twice_nat,
964                 self_twice_nat=sm.self_twice_nat,
965                 out2in_only=sm.out2in_only,
966                 tag=sm.tag,
967                 external_sw_if_index=sm.external_sw_if_index,
968                 is_add=0)
969
970         lb_static_mappings = self.vapi.nat44_lb_static_mapping_dump()
971         for lb_sm in lb_static_mappings:
972             self.vapi.nat44_add_del_lb_static_mapping(
973                 lb_sm.external_addr,
974                 lb_sm.external_port,
975                 lb_sm.protocol,
976                 vrf_id=lb_sm.vrf_id,
977                 twice_nat=lb_sm.twice_nat,
978                 self_twice_nat=lb_sm.self_twice_nat,
979                 out2in_only=lb_sm.out2in_only,
980                 tag=lb_sm.tag,
981                 is_add=0,
982                 local_num=0,
983                 locals=[])
984
985         identity_mappings = self.vapi.nat44_identity_mapping_dump()
986         for id_m in identity_mappings:
987             self.vapi.nat44_add_del_identity_mapping(
988                 addr_only=id_m.addr_only,
989                 ip=id_m.ip_address,
990                 port=id_m.port,
991                 sw_if_index=id_m.sw_if_index,
992                 vrf_id=id_m.vrf_id,
993                 protocol=id_m.protocol,
994                 is_add=0)
995
996         adresses = self.vapi.nat44_address_dump()
997         for addr in adresses:
998             self.vapi.nat44_add_del_address_range(addr.ip_address,
999                                                   addr.ip_address,
1000                                                   twice_nat=addr.twice_nat,
1001                                                   is_add=0)
1002
1003         self.vapi.nat_set_reass()
1004         self.vapi.nat_set_reass(is_ip6=1)
1005
1006     def nat44_add_static_mapping(self, local_ip, external_ip='0.0.0.0',
1007                                  local_port=0, external_port=0, vrf_id=0,
1008                                  is_add=1, external_sw_if_index=0xFFFFFFFF,
1009                                  proto=0, twice_nat=0, self_twice_nat=0,
1010                                  out2in_only=0, tag=""):
1011         """
1012         Add/delete NAT44 static mapping
1013
1014         :param local_ip: Local IP address
1015         :param external_ip: External IP address
1016         :param local_port: Local port number (Optional)
1017         :param external_port: External port number (Optional)
1018         :param vrf_id: VRF ID (Default 0)
1019         :param is_add: 1 if add, 0 if delete (Default add)
1020         :param external_sw_if_index: External interface instead of IP address
1021         :param proto: IP protocol (Mandatory if port specified)
1022         :param twice_nat: 1 if translate external host address and port
1023         :param self_twice_nat: 1 if translate external host address and port
1024                                whenever external host address equals
1025                                local address of internal host
1026         :param out2in_only: if 1 rule is matching only out2in direction
1027         :param tag: Opaque string tag
1028         """
1029         addr_only = 1
1030         if local_port and external_port:
1031             addr_only = 0
1032         l_ip = socket.inet_pton(socket.AF_INET, local_ip)
1033         e_ip = socket.inet_pton(socket.AF_INET, external_ip)
1034         self.vapi.nat44_add_del_static_mapping(
1035             l_ip,
1036             e_ip,
1037             external_sw_if_index,
1038             local_port,
1039             external_port,
1040             addr_only,
1041             vrf_id,
1042             proto,
1043             twice_nat,
1044             self_twice_nat,
1045             out2in_only,
1046             tag,
1047             is_add)
1048
1049     def nat44_add_address(self, ip, is_add=1, vrf_id=0xFFFFFFFF, twice_nat=0):
1050         """
1051         Add/delete NAT44 address
1052
1053         :param ip: IP address
1054         :param is_add: 1 if add, 0 if delete (Default add)
1055         :param twice_nat: twice NAT address for extenal hosts
1056         """
1057         nat_addr = socket.inet_pton(socket.AF_INET, ip)
1058         self.vapi.nat44_add_del_address_range(nat_addr, nat_addr, is_add,
1059                                               vrf_id=vrf_id,
1060                                               twice_nat=twice_nat)
1061
1062     def test_dynamic(self):
1063         """ NAT44 dynamic translation test """
1064
1065         self.nat44_add_address(self.nat_addr)
1066         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
1067         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
1068                                                   is_inside=0)
1069
1070         # in2out
1071         pkts = self.create_stream_in(self.pg0, self.pg1)
1072         self.pg0.add_stream(pkts)
1073         self.pg_enable_capture(self.pg_interfaces)
1074         self.pg_start()
1075         capture = self.pg1.get_capture(len(pkts))
1076         self.verify_capture_out(capture)
1077
1078         # out2in
1079         pkts = self.create_stream_out(self.pg1)
1080         self.pg1.add_stream(pkts)
1081         self.pg_enable_capture(self.pg_interfaces)
1082         self.pg_start()
1083         capture = self.pg0.get_capture(len(pkts))
1084         self.verify_capture_in(capture, self.pg0)
1085
1086     def test_dynamic_icmp_errors_in2out_ttl_1(self):
1087         """ NAT44 handling of client packets with TTL=1 """
1088
1089         self.nat44_add_address(self.nat_addr)
1090         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
1091         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
1092                                                   is_inside=0)
1093
1094         # Client side - generate traffic
1095         pkts = self.create_stream_in(self.pg0, self.pg1, ttl=1)
1096         self.pg0.add_stream(pkts)
1097         self.pg_enable_capture(self.pg_interfaces)
1098         self.pg_start()
1099
1100         # Client side - verify ICMP type 11 packets
1101         capture = self.pg0.get_capture(len(pkts))
1102         self.verify_capture_in_with_icmp_errors(capture, self.pg0)
1103
1104     def test_dynamic_icmp_errors_out2in_ttl_1(self):
1105         """ NAT44 handling of server packets with TTL=1 """
1106
1107         self.nat44_add_address(self.nat_addr)
1108         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
1109         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
1110                                                   is_inside=0)
1111
1112         # Client side - create sessions
1113         pkts = self.create_stream_in(self.pg0, self.pg1)
1114         self.pg0.add_stream(pkts)
1115         self.pg_enable_capture(self.pg_interfaces)
1116         self.pg_start()
1117
1118         # Server side - generate traffic
1119         capture = self.pg1.get_capture(len(pkts))
1120         self.verify_capture_out(capture)
1121         pkts = self.create_stream_out(self.pg1, ttl=1)
1122         self.pg1.add_stream(pkts)
1123         self.pg_enable_capture(self.pg_interfaces)
1124         self.pg_start()
1125
1126         # Server side - verify ICMP type 11 packets
1127         capture = self.pg1.get_capture(len(pkts))
1128         self.verify_capture_out_with_icmp_errors(capture,
1129                                                  src_ip=self.pg1.local_ip4)
1130
1131     def test_dynamic_icmp_errors_in2out_ttl_2(self):
1132         """ NAT44 handling of error responses to client packets with TTL=2 """
1133
1134         self.nat44_add_address(self.nat_addr)
1135         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
1136         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
1137                                                   is_inside=0)
1138
1139         # Client side - generate traffic
1140         pkts = self.create_stream_in(self.pg0, self.pg1, ttl=2)
1141         self.pg0.add_stream(pkts)
1142         self.pg_enable_capture(self.pg_interfaces)
1143         self.pg_start()
1144
1145         # Server side - simulate ICMP type 11 response
1146         capture = self.pg1.get_capture(len(pkts))
1147         pkts = [Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
1148                 IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
1149                 ICMP(type=11) / packet[IP] for packet in capture]
1150         self.pg1.add_stream(pkts)
1151         self.pg_enable_capture(self.pg_interfaces)
1152         self.pg_start()
1153
1154         # Client side - verify ICMP type 11 packets
1155         capture = self.pg0.get_capture(len(pkts))
1156         self.verify_capture_in_with_icmp_errors(capture, self.pg0)
1157
1158     def test_dynamic_icmp_errors_out2in_ttl_2(self):
1159         """ NAT44 handling of error responses to server packets with TTL=2 """
1160
1161         self.nat44_add_address(self.nat_addr)
1162         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
1163         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
1164                                                   is_inside=0)
1165
1166         # Client side - create sessions
1167         pkts = self.create_stream_in(self.pg0, self.pg1)
1168         self.pg0.add_stream(pkts)
1169         self.pg_enable_capture(self.pg_interfaces)
1170         self.pg_start()
1171
1172         # Server side - generate traffic
1173         capture = self.pg1.get_capture(len(pkts))
1174         self.verify_capture_out(capture)
1175         pkts = self.create_stream_out(self.pg1, ttl=2)
1176         self.pg1.add_stream(pkts)
1177         self.pg_enable_capture(self.pg_interfaces)
1178         self.pg_start()
1179
1180         # Client side - simulate ICMP type 11 response
1181         capture = self.pg0.get_capture(len(pkts))
1182         pkts = [Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
1183                 IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
1184                 ICMP(type=11) / packet[IP] for packet in capture]
1185         self.pg0.add_stream(pkts)
1186         self.pg_enable_capture(self.pg_interfaces)
1187         self.pg_start()
1188
1189         # Server side - verify ICMP type 11 packets
1190         capture = self.pg1.get_capture(len(pkts))
1191         self.verify_capture_out_with_icmp_errors(capture)
1192
1193     def test_ping_out_interface_from_outside(self):
1194         """ Ping NAT44 out interface from outside network """
1195
1196         self.nat44_add_address(self.nat_addr)
1197         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
1198         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
1199                                                   is_inside=0)
1200
1201         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
1202              IP(src=self.pg1.remote_ip4, dst=self.pg1.local_ip4) /
1203              ICMP(id=self.icmp_id_out, type='echo-request'))
1204         pkts = [p]
1205         self.pg1.add_stream(pkts)
1206         self.pg_enable_capture(self.pg_interfaces)
1207         self.pg_start()
1208         capture = self.pg1.get_capture(len(pkts))
1209         self.assertEqual(1, len(capture))
1210         packet = capture[0]
1211         try:
1212             self.assertEqual(packet[IP].src, self.pg1.local_ip4)
1213             self.assertEqual(packet[IP].dst, self.pg1.remote_ip4)
1214             self.assertEqual(packet[ICMP].id, self.icmp_id_in)
1215             self.assertEqual(packet[ICMP].type, 0)  # echo reply
1216         except:
1217             self.logger.error(ppp("Unexpected or invalid packet "
1218                                   "(outside network):", packet))
1219             raise
1220
1221     def test_ping_internal_host_from_outside(self):
1222         """ Ping internal host from outside network """
1223
1224         self.nat44_add_static_mapping(self.pg0.remote_ip4, self.nat_addr)
1225         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
1226         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
1227                                                   is_inside=0)
1228
1229         # out2in
1230         pkt = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
1231                IP(src=self.pg1.remote_ip4, dst=self.nat_addr, ttl=64) /
1232                ICMP(id=self.icmp_id_out, type='echo-request'))
1233         self.pg1.add_stream(pkt)
1234         self.pg_enable_capture(self.pg_interfaces)
1235         self.pg_start()
1236         capture = self.pg0.get_capture(1)
1237         self.verify_capture_in(capture, self.pg0, packet_num=1)
1238         self.assert_equal(capture[0][IP].proto, IP_PROTOS.icmp)
1239
1240         # in2out
1241         pkt = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
1242                IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4, ttl=64) /
1243                ICMP(id=self.icmp_id_in, type='echo-reply'))
1244         self.pg0.add_stream(pkt)
1245         self.pg_enable_capture(self.pg_interfaces)
1246         self.pg_start()
1247         capture = self.pg1.get_capture(1)
1248         self.verify_capture_out(capture, same_port=True, packet_num=1)
1249         self.assert_equal(capture[0][IP].proto, IP_PROTOS.icmp)
1250
1251     def test_forwarding(self):
1252         """ NAT44 forwarding test """
1253
1254         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
1255         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
1256                                                   is_inside=0)
1257         self.vapi.nat44_forwarding_enable_disable(1)
1258
1259         real_ip = self.pg0.remote_ip4n
1260         alias_ip = self.nat_addr_n
1261         self.vapi.nat44_add_del_static_mapping(local_ip=real_ip,
1262                                                external_ip=alias_ip)
1263
1264         try:
1265             # in2out - static mapping match
1266
1267             pkts = self.create_stream_out(self.pg1)
1268             self.pg1.add_stream(pkts)
1269             self.pg_enable_capture(self.pg_interfaces)
1270             self.pg_start()
1271             capture = self.pg0.get_capture(len(pkts))
1272             self.verify_capture_in(capture, self.pg0)
1273
1274             pkts = self.create_stream_in(self.pg0, self.pg1)
1275             self.pg0.add_stream(pkts)
1276             self.pg_enable_capture(self.pg_interfaces)
1277             self.pg_start()
1278             capture = self.pg1.get_capture(len(pkts))
1279             self.verify_capture_out(capture, same_port=True)
1280
1281             # in2out - no static mapping match
1282
1283             host0 = self.pg0.remote_hosts[0]
1284             self.pg0.remote_hosts[0] = self.pg0.remote_hosts[1]
1285             try:
1286                 pkts = self.create_stream_out(self.pg1,
1287                                               dst_ip=self.pg0.remote_ip4,
1288                                               use_inside_ports=True)
1289                 self.pg1.add_stream(pkts)
1290                 self.pg_enable_capture(self.pg_interfaces)
1291                 self.pg_start()
1292                 capture = self.pg0.get_capture(len(pkts))
1293                 self.verify_capture_in(capture, self.pg0)
1294
1295                 pkts = self.create_stream_in(self.pg0, self.pg1)
1296                 self.pg0.add_stream(pkts)
1297                 self.pg_enable_capture(self.pg_interfaces)
1298                 self.pg_start()
1299                 capture = self.pg1.get_capture(len(pkts))
1300                 self.verify_capture_out(capture, nat_ip=self.pg0.remote_ip4,
1301                                         same_port=True)
1302             finally:
1303                 self.pg0.remote_hosts[0] = host0
1304
1305         finally:
1306             self.vapi.nat44_forwarding_enable_disable(0)
1307             self.vapi.nat44_add_del_static_mapping(local_ip=real_ip,
1308                                                    external_ip=alias_ip,
1309                                                    is_add=0)
1310
1311     def test_static_in(self):
1312         """ 1:1 NAT initialized from inside network """
1313
1314         nat_ip = "10.0.0.10"
1315         self.tcp_port_out = 6303
1316         self.udp_port_out = 6304
1317         self.icmp_id_out = 6305
1318
1319         self.nat44_add_static_mapping(self.pg0.remote_ip4, nat_ip)
1320         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
1321         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
1322                                                   is_inside=0)
1323         sm = self.vapi.nat44_static_mapping_dump()
1324         self.assertEqual(len(sm), 1)
1325         self.assertEqual((sm[0].tag).split('\0', 1)[0], '')
1326         self.assertEqual(sm[0].protocol, 0)
1327         self.assertEqual(sm[0].local_port, 0)
1328         self.assertEqual(sm[0].external_port, 0)
1329
1330         # in2out
1331         pkts = self.create_stream_in(self.pg0, self.pg1)
1332         self.pg0.add_stream(pkts)
1333         self.pg_enable_capture(self.pg_interfaces)
1334         self.pg_start()
1335         capture = self.pg1.get_capture(len(pkts))
1336         self.verify_capture_out(capture, nat_ip, True)
1337
1338         # out2in
1339         pkts = self.create_stream_out(self.pg1, nat_ip)
1340         self.pg1.add_stream(pkts)
1341         self.pg_enable_capture(self.pg_interfaces)
1342         self.pg_start()
1343         capture = self.pg0.get_capture(len(pkts))
1344         self.verify_capture_in(capture, self.pg0)
1345
1346     def test_static_out(self):
1347         """ 1:1 NAT initialized from outside network """
1348
1349         nat_ip = "10.0.0.20"
1350         self.tcp_port_out = 6303
1351         self.udp_port_out = 6304
1352         self.icmp_id_out = 6305
1353         tag = "testTAG"
1354
1355         self.nat44_add_static_mapping(self.pg0.remote_ip4, nat_ip, tag=tag)
1356         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
1357         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
1358                                                   is_inside=0)
1359         sm = self.vapi.nat44_static_mapping_dump()
1360         self.assertEqual(len(sm), 1)
1361         self.assertEqual((sm[0].tag).split('\0', 1)[0], tag)
1362
1363         # out2in
1364         pkts = self.create_stream_out(self.pg1, nat_ip)
1365         self.pg1.add_stream(pkts)
1366         self.pg_enable_capture(self.pg_interfaces)
1367         self.pg_start()
1368         capture = self.pg0.get_capture(len(pkts))
1369         self.verify_capture_in(capture, self.pg0)
1370
1371         # in2out
1372         pkts = self.create_stream_in(self.pg0, self.pg1)
1373         self.pg0.add_stream(pkts)
1374         self.pg_enable_capture(self.pg_interfaces)
1375         self.pg_start()
1376         capture = self.pg1.get_capture(len(pkts))
1377         self.verify_capture_out(capture, nat_ip, True)
1378
1379     def test_static_with_port_in(self):
1380         """ 1:1 NAPT initialized from inside network """
1381
1382         self.tcp_port_out = 3606
1383         self.udp_port_out = 3607
1384         self.icmp_id_out = 3608
1385
1386         self.nat44_add_address(self.nat_addr)
1387         self.nat44_add_static_mapping(self.pg0.remote_ip4, self.nat_addr,
1388                                       self.tcp_port_in, self.tcp_port_out,
1389                                       proto=IP_PROTOS.tcp)
1390         self.nat44_add_static_mapping(self.pg0.remote_ip4, self.nat_addr,
1391                                       self.udp_port_in, self.udp_port_out,
1392                                       proto=IP_PROTOS.udp)
1393         self.nat44_add_static_mapping(self.pg0.remote_ip4, self.nat_addr,
1394                                       self.icmp_id_in, self.icmp_id_out,
1395                                       proto=IP_PROTOS.icmp)
1396         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
1397         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
1398                                                   is_inside=0)
1399
1400         # in2out
1401         pkts = self.create_stream_in(self.pg0, self.pg1)
1402         self.pg0.add_stream(pkts)
1403         self.pg_enable_capture(self.pg_interfaces)
1404         self.pg_start()
1405         capture = self.pg1.get_capture(len(pkts))
1406         self.verify_capture_out(capture)
1407
1408         # out2in
1409         pkts = self.create_stream_out(self.pg1)
1410         self.pg1.add_stream(pkts)
1411         self.pg_enable_capture(self.pg_interfaces)
1412         self.pg_start()
1413         capture = self.pg0.get_capture(len(pkts))
1414         self.verify_capture_in(capture, self.pg0)
1415
1416     def test_static_with_port_out(self):
1417         """ 1:1 NAPT initialized from outside network """
1418
1419         self.tcp_port_out = 30606
1420         self.udp_port_out = 30607
1421         self.icmp_id_out = 30608
1422
1423         self.nat44_add_address(self.nat_addr)
1424         self.nat44_add_static_mapping(self.pg0.remote_ip4, self.nat_addr,
1425                                       self.tcp_port_in, self.tcp_port_out,
1426                                       proto=IP_PROTOS.tcp)
1427         self.nat44_add_static_mapping(self.pg0.remote_ip4, self.nat_addr,
1428                                       self.udp_port_in, self.udp_port_out,
1429                                       proto=IP_PROTOS.udp)
1430         self.nat44_add_static_mapping(self.pg0.remote_ip4, self.nat_addr,
1431                                       self.icmp_id_in, self.icmp_id_out,
1432                                       proto=IP_PROTOS.icmp)
1433         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
1434         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
1435                                                   is_inside=0)
1436
1437         # out2in
1438         pkts = self.create_stream_out(self.pg1)
1439         self.pg1.add_stream(pkts)
1440         self.pg_enable_capture(self.pg_interfaces)
1441         self.pg_start()
1442         capture = self.pg0.get_capture(len(pkts))
1443         self.verify_capture_in(capture, self.pg0)
1444
1445         # in2out
1446         pkts = self.create_stream_in(self.pg0, self.pg1)
1447         self.pg0.add_stream(pkts)
1448         self.pg_enable_capture(self.pg_interfaces)
1449         self.pg_start()
1450         capture = self.pg1.get_capture(len(pkts))
1451         self.verify_capture_out(capture)
1452
1453     def test_static_with_port_out2(self):
1454         """ 1:1 NAPT symmetrical rule """
1455
1456         external_port = 80
1457         local_port = 8080
1458
1459         self.vapi.nat44_forwarding_enable_disable(1)
1460         self.nat44_add_static_mapping(self.pg0.remote_ip4, self.nat_addr,
1461                                       local_port, external_port,
1462                                       proto=IP_PROTOS.tcp, out2in_only=1)
1463         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
1464         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
1465                                                   is_inside=0)
1466
1467         # from client to service
1468         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
1469              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
1470              TCP(sport=12345, dport=external_port))
1471         self.pg1.add_stream(p)
1472         self.pg_enable_capture(self.pg_interfaces)
1473         self.pg_start()
1474         capture = self.pg0.get_capture(1)
1475         p = capture[0]
1476         try:
1477             ip = p[IP]
1478             tcp = p[TCP]
1479             self.assertEqual(ip.dst, self.pg0.remote_ip4)
1480             self.assertEqual(tcp.dport, local_port)
1481             self.assert_packet_checksums_valid(p)
1482         except:
1483             self.logger.error(ppp("Unexpected or invalid packet:", p))
1484             raise
1485
1486         # ICMP error
1487         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
1488              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
1489              ICMP(type=11) / capture[0][IP])
1490         self.pg0.add_stream(p)
1491         self.pg_enable_capture(self.pg_interfaces)
1492         self.pg_start()
1493         capture = self.pg1.get_capture(1)
1494         p = capture[0]
1495         try:
1496             self.assertEqual(p[IP].src, self.nat_addr)
1497             inner = p[IPerror]
1498             self.assertEqual(inner.dst, self.nat_addr)
1499             self.assertEqual(inner[TCPerror].dport, external_port)
1500         except:
1501             self.logger.error(ppp("Unexpected or invalid packet:", p))
1502             raise
1503
1504         # from service back to client
1505         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
1506              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
1507              TCP(sport=local_port, dport=12345))
1508         self.pg0.add_stream(p)
1509         self.pg_enable_capture(self.pg_interfaces)
1510         self.pg_start()
1511         capture = self.pg1.get_capture(1)
1512         p = capture[0]
1513         try:
1514             ip = p[IP]
1515             tcp = p[TCP]
1516             self.assertEqual(ip.src, self.nat_addr)
1517             self.assertEqual(tcp.sport, external_port)
1518             self.assert_packet_checksums_valid(p)
1519         except:
1520             self.logger.error(ppp("Unexpected or invalid packet:", p))
1521             raise
1522
1523         # ICMP error
1524         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
1525              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
1526              ICMP(type=11) / capture[0][IP])
1527         self.pg1.add_stream(p)
1528         self.pg_enable_capture(self.pg_interfaces)
1529         self.pg_start()
1530         capture = self.pg0.get_capture(1)
1531         p = capture[0]
1532         try:
1533             self.assertEqual(p[IP].dst, self.pg0.remote_ip4)
1534             inner = p[IPerror]
1535             self.assertEqual(inner.src, self.pg0.remote_ip4)
1536             self.assertEqual(inner[TCPerror].sport, local_port)
1537         except:
1538             self.logger.error(ppp("Unexpected or invalid packet:", p))
1539             raise
1540
1541         # from client to server (no translation)
1542         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
1543              IP(src=self.pg1.remote_ip4, dst=self.pg0.remote_ip4) /
1544              TCP(sport=12346, dport=local_port))
1545         self.pg1.add_stream(p)
1546         self.pg_enable_capture(self.pg_interfaces)
1547         self.pg_start()
1548         capture = self.pg0.get_capture(1)
1549         p = capture[0]
1550         try:
1551             ip = p[IP]
1552             tcp = p[TCP]
1553             self.assertEqual(ip.dst, self.pg0.remote_ip4)
1554             self.assertEqual(tcp.dport, local_port)
1555             self.assert_packet_checksums_valid(p)
1556         except:
1557             self.logger.error(ppp("Unexpected or invalid packet:", p))
1558             raise
1559
1560         # from service back to client (no translation)
1561         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
1562              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
1563              TCP(sport=local_port, dport=12346))
1564         self.pg0.add_stream(p)
1565         self.pg_enable_capture(self.pg_interfaces)
1566         self.pg_start()
1567         capture = self.pg1.get_capture(1)
1568         p = capture[0]
1569         try:
1570             ip = p[IP]
1571             tcp = p[TCP]
1572             self.assertEqual(ip.src, self.pg0.remote_ip4)
1573             self.assertEqual(tcp.sport, local_port)
1574             self.assert_packet_checksums_valid(p)
1575         except:
1576             self.logger.error(ppp("Unexpected or invalid packet:", p))
1577             raise
1578
1579     def test_static_vrf_aware(self):
1580         """ 1:1 NAT VRF awareness """
1581
1582         nat_ip1 = "10.0.0.30"
1583         nat_ip2 = "10.0.0.40"
1584         self.tcp_port_out = 6303
1585         self.udp_port_out = 6304
1586         self.icmp_id_out = 6305
1587
1588         self.nat44_add_static_mapping(self.pg4.remote_ip4, nat_ip1,
1589                                       vrf_id=10)
1590         self.nat44_add_static_mapping(self.pg0.remote_ip4, nat_ip2,
1591                                       vrf_id=10)
1592         self.vapi.nat44_interface_add_del_feature(self.pg3.sw_if_index,
1593                                                   is_inside=0)
1594         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
1595         self.vapi.nat44_interface_add_del_feature(self.pg4.sw_if_index)
1596
1597         # inside interface VRF match NAT44 static mapping VRF
1598         pkts = self.create_stream_in(self.pg4, self.pg3)
1599         self.pg4.add_stream(pkts)
1600         self.pg_enable_capture(self.pg_interfaces)
1601         self.pg_start()
1602         capture = self.pg3.get_capture(len(pkts))
1603         self.verify_capture_out(capture, nat_ip1, True)
1604
1605         # inside interface VRF don't match NAT44 static mapping VRF (packets
1606         # are dropped)
1607         pkts = self.create_stream_in(self.pg0, self.pg3)
1608         self.pg0.add_stream(pkts)
1609         self.pg_enable_capture(self.pg_interfaces)
1610         self.pg_start()
1611         self.pg3.assert_nothing_captured()
1612
1613     def test_dynamic_to_static(self):
1614         """ Switch from dynamic translation to 1:1NAT """
1615         nat_ip = "10.0.0.10"
1616         self.tcp_port_out = 6303
1617         self.udp_port_out = 6304
1618         self.icmp_id_out = 6305
1619
1620         self.nat44_add_address(self.nat_addr)
1621         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
1622         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
1623                                                   is_inside=0)
1624
1625         # dynamic
1626         pkts = self.create_stream_in(self.pg0, self.pg1)
1627         self.pg0.add_stream(pkts)
1628         self.pg_enable_capture(self.pg_interfaces)
1629         self.pg_start()
1630         capture = self.pg1.get_capture(len(pkts))
1631         self.verify_capture_out(capture)
1632
1633         # 1:1NAT
1634         self.nat44_add_static_mapping(self.pg0.remote_ip4, nat_ip)
1635         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4n, 0)
1636         self.assertEqual(len(sessions), 0)
1637         pkts = self.create_stream_in(self.pg0, self.pg1)
1638         self.pg0.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_out(capture, nat_ip, True)
1643
1644     def test_identity_nat(self):
1645         """ Identity NAT """
1646
1647         self.vapi.nat44_add_del_identity_mapping(ip=self.pg0.remote_ip4n)
1648         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
1649         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
1650                                                   is_inside=0)
1651
1652         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
1653              IP(src=self.pg1.remote_ip4, dst=self.pg0.remote_ip4) /
1654              TCP(sport=12345, dport=56789))
1655         self.pg1.add_stream(p)
1656         self.pg_enable_capture(self.pg_interfaces)
1657         self.pg_start()
1658         capture = self.pg0.get_capture(1)
1659         p = capture[0]
1660         try:
1661             ip = p[IP]
1662             tcp = p[TCP]
1663             self.assertEqual(ip.dst, self.pg0.remote_ip4)
1664             self.assertEqual(ip.src, self.pg1.remote_ip4)
1665             self.assertEqual(tcp.dport, 56789)
1666             self.assertEqual(tcp.sport, 12345)
1667             self.assert_packet_checksums_valid(p)
1668         except:
1669             self.logger.error(ppp("Unexpected or invalid packet:", p))
1670             raise
1671
1672     def test_static_lb(self):
1673         """ NAT44 local service load balancing """
1674         external_addr_n = socket.inet_pton(socket.AF_INET, self.nat_addr)
1675         external_port = 80
1676         local_port = 8080
1677         server1 = self.pg0.remote_hosts[0]
1678         server2 = self.pg0.remote_hosts[1]
1679
1680         locals = [{'addr': server1.ip4n,
1681                    'port': local_port,
1682                    'probability': 70},
1683                   {'addr': server2.ip4n,
1684                    'port': local_port,
1685                    'probability': 30}]
1686
1687         self.nat44_add_address(self.nat_addr)
1688         self.vapi.nat44_add_del_lb_static_mapping(external_addr_n,
1689                                                   external_port,
1690                                                   IP_PROTOS.tcp,
1691                                                   local_num=len(locals),
1692                                                   locals=locals)
1693         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
1694         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
1695                                                   is_inside=0)
1696
1697         # from client to service
1698         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
1699              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
1700              TCP(sport=12345, dport=external_port))
1701         self.pg1.add_stream(p)
1702         self.pg_enable_capture(self.pg_interfaces)
1703         self.pg_start()
1704         capture = self.pg0.get_capture(1)
1705         p = capture[0]
1706         server = None
1707         try:
1708             ip = p[IP]
1709             tcp = p[TCP]
1710             self.assertIn(ip.dst, [server1.ip4, server2.ip4])
1711             if ip.dst == server1.ip4:
1712                 server = server1
1713             else:
1714                 server = server2
1715             self.assertEqual(tcp.dport, local_port)
1716             self.assert_packet_checksums_valid(p)
1717         except:
1718             self.logger.error(ppp("Unexpected or invalid packet:", p))
1719             raise
1720
1721         # from service back to client
1722         p = (Ether(src=server.mac, dst=self.pg0.local_mac) /
1723              IP(src=server.ip4, dst=self.pg1.remote_ip4) /
1724              TCP(sport=local_port, dport=12345))
1725         self.pg0.add_stream(p)
1726         self.pg_enable_capture(self.pg_interfaces)
1727         self.pg_start()
1728         capture = self.pg1.get_capture(1)
1729         p = capture[0]
1730         try:
1731             ip = p[IP]
1732             tcp = p[TCP]
1733             self.assertEqual(ip.src, self.nat_addr)
1734             self.assertEqual(tcp.sport, external_port)
1735             self.assert_packet_checksums_valid(p)
1736         except:
1737             self.logger.error(ppp("Unexpected or invalid packet:", p))
1738             raise
1739
1740     @unittest.skipUnless(running_extended_tests(), "part of extended tests")
1741     def test_static_lb_multi_clients(self):
1742         """ NAT44 local service load balancing - multiple clients"""
1743
1744         external_addr_n = socket.inet_pton(socket.AF_INET, self.nat_addr)
1745         external_port = 80
1746         local_port = 8080
1747         server1 = self.pg0.remote_hosts[0]
1748         server2 = self.pg0.remote_hosts[1]
1749
1750         locals = [{'addr': server1.ip4n,
1751                    'port': local_port,
1752                    'probability': 90},
1753                   {'addr': server2.ip4n,
1754                    'port': local_port,
1755                    'probability': 10}]
1756
1757         self.nat44_add_address(self.nat_addr)
1758         self.vapi.nat44_add_del_lb_static_mapping(external_addr_n,
1759                                                   external_port,
1760                                                   IP_PROTOS.tcp,
1761                                                   local_num=len(locals),
1762                                                   locals=locals)
1763         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
1764         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
1765                                                   is_inside=0)
1766
1767         server1_n = 0
1768         server2_n = 0
1769         clients = ip4_range(self.pg1.remote_ip4, 10, 50)
1770         pkts = []
1771         for client in clients:
1772             p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
1773                  IP(src=client, dst=self.nat_addr) /
1774                  TCP(sport=12345, dport=external_port))
1775             pkts.append(p)
1776         self.pg1.add_stream(pkts)
1777         self.pg_enable_capture(self.pg_interfaces)
1778         self.pg_start()
1779         capture = self.pg0.get_capture(len(pkts))
1780         for p in capture:
1781             if p[IP].dst == server1.ip4:
1782                 server1_n += 1
1783             else:
1784                 server2_n += 1
1785         self.assertTrue(server1_n > server2_n)
1786
1787     def test_static_lb_2(self):
1788         """ NAT44 local service load balancing (asymmetrical rule) """
1789         external_addr_n = socket.inet_pton(socket.AF_INET, self.nat_addr)
1790         external_port = 80
1791         local_port = 8080
1792         server1 = self.pg0.remote_hosts[0]
1793         server2 = self.pg0.remote_hosts[1]
1794
1795         locals = [{'addr': server1.ip4n,
1796                    'port': local_port,
1797                    'probability': 70},
1798                   {'addr': server2.ip4n,
1799                    'port': local_port,
1800                    'probability': 30}]
1801
1802         self.vapi.nat44_forwarding_enable_disable(1)
1803         self.vapi.nat44_add_del_lb_static_mapping(external_addr_n,
1804                                                   external_port,
1805                                                   IP_PROTOS.tcp,
1806                                                   out2in_only=1,
1807                                                   local_num=len(locals),
1808                                                   locals=locals)
1809         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
1810         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
1811                                                   is_inside=0)
1812
1813         # from client to service
1814         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
1815              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
1816              TCP(sport=12345, dport=external_port))
1817         self.pg1.add_stream(p)
1818         self.pg_enable_capture(self.pg_interfaces)
1819         self.pg_start()
1820         capture = self.pg0.get_capture(1)
1821         p = capture[0]
1822         server = None
1823         try:
1824             ip = p[IP]
1825             tcp = p[TCP]
1826             self.assertIn(ip.dst, [server1.ip4, server2.ip4])
1827             if ip.dst == server1.ip4:
1828                 server = server1
1829             else:
1830                 server = server2
1831             self.assertEqual(tcp.dport, local_port)
1832             self.assert_packet_checksums_valid(p)
1833         except:
1834             self.logger.error(ppp("Unexpected or invalid packet:", p))
1835             raise
1836
1837         # from service back to client
1838         p = (Ether(src=server.mac, dst=self.pg0.local_mac) /
1839              IP(src=server.ip4, dst=self.pg1.remote_ip4) /
1840              TCP(sport=local_port, dport=12345))
1841         self.pg0.add_stream(p)
1842         self.pg_enable_capture(self.pg_interfaces)
1843         self.pg_start()
1844         capture = self.pg1.get_capture(1)
1845         p = capture[0]
1846         try:
1847             ip = p[IP]
1848             tcp = p[TCP]
1849             self.assertEqual(ip.src, self.nat_addr)
1850             self.assertEqual(tcp.sport, external_port)
1851             self.assert_packet_checksums_valid(p)
1852         except:
1853             self.logger.error(ppp("Unexpected or invalid packet:", p))
1854             raise
1855
1856         # from client to server (no translation)
1857         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
1858              IP(src=self.pg1.remote_ip4, dst=server1.ip4) /
1859              TCP(sport=12346, dport=local_port))
1860         self.pg1.add_stream(p)
1861         self.pg_enable_capture(self.pg_interfaces)
1862         self.pg_start()
1863         capture = self.pg0.get_capture(1)
1864         p = capture[0]
1865         server = None
1866         try:
1867             ip = p[IP]
1868             tcp = p[TCP]
1869             self.assertEqual(ip.dst, server1.ip4)
1870             self.assertEqual(tcp.dport, local_port)
1871             self.assert_packet_checksums_valid(p)
1872         except:
1873             self.logger.error(ppp("Unexpected or invalid packet:", p))
1874             raise
1875
1876         # from service back to client (no translation)
1877         p = (Ether(src=server1.mac, dst=self.pg0.local_mac) /
1878              IP(src=server1.ip4, dst=self.pg1.remote_ip4) /
1879              TCP(sport=local_port, dport=12346))
1880         self.pg0.add_stream(p)
1881         self.pg_enable_capture(self.pg_interfaces)
1882         self.pg_start()
1883         capture = self.pg1.get_capture(1)
1884         p = capture[0]
1885         try:
1886             ip = p[IP]
1887             tcp = p[TCP]
1888             self.assertEqual(ip.src, server1.ip4)
1889             self.assertEqual(tcp.sport, local_port)
1890             self.assert_packet_checksums_valid(p)
1891         except:
1892             self.logger.error(ppp("Unexpected or invalid packet:", p))
1893             raise
1894
1895     def test_multiple_inside_interfaces(self):
1896         """ NAT44 multiple non-overlapping address space inside interfaces """
1897
1898         self.nat44_add_address(self.nat_addr)
1899         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
1900         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index)
1901         self.vapi.nat44_interface_add_del_feature(self.pg3.sw_if_index,
1902                                                   is_inside=0)
1903
1904         # between two NAT44 inside interfaces (no translation)
1905         pkts = self.create_stream_in(self.pg0, self.pg1)
1906         self.pg0.add_stream(pkts)
1907         self.pg_enable_capture(self.pg_interfaces)
1908         self.pg_start()
1909         capture = self.pg1.get_capture(len(pkts))
1910         self.verify_capture_no_translation(capture, self.pg0, self.pg1)
1911
1912         # from NAT44 inside to interface without NAT44 feature (no translation)
1913         pkts = self.create_stream_in(self.pg0, self.pg2)
1914         self.pg0.add_stream(pkts)
1915         self.pg_enable_capture(self.pg_interfaces)
1916         self.pg_start()
1917         capture = self.pg2.get_capture(len(pkts))
1918         self.verify_capture_no_translation(capture, self.pg0, self.pg2)
1919
1920         # in2out 1st interface
1921         pkts = self.create_stream_in(self.pg0, self.pg3)
1922         self.pg0.add_stream(pkts)
1923         self.pg_enable_capture(self.pg_interfaces)
1924         self.pg_start()
1925         capture = self.pg3.get_capture(len(pkts))
1926         self.verify_capture_out(capture)
1927
1928         # out2in 1st interface
1929         pkts = self.create_stream_out(self.pg3)
1930         self.pg3.add_stream(pkts)
1931         self.pg_enable_capture(self.pg_interfaces)
1932         self.pg_start()
1933         capture = self.pg0.get_capture(len(pkts))
1934         self.verify_capture_in(capture, self.pg0)
1935
1936         # in2out 2nd interface
1937         pkts = self.create_stream_in(self.pg1, self.pg3)
1938         self.pg1.add_stream(pkts)
1939         self.pg_enable_capture(self.pg_interfaces)
1940         self.pg_start()
1941         capture = self.pg3.get_capture(len(pkts))
1942         self.verify_capture_out(capture)
1943
1944         # out2in 2nd interface
1945         pkts = self.create_stream_out(self.pg3)
1946         self.pg3.add_stream(pkts)
1947         self.pg_enable_capture(self.pg_interfaces)
1948         self.pg_start()
1949         capture = self.pg1.get_capture(len(pkts))
1950         self.verify_capture_in(capture, self.pg1)
1951
1952     def test_inside_overlapping_interfaces(self):
1953         """ NAT44 multiple inside interfaces with overlapping address space """
1954
1955         static_nat_ip = "10.0.0.10"
1956         self.nat44_add_address(self.nat_addr)
1957         self.vapi.nat44_interface_add_del_feature(self.pg3.sw_if_index,
1958                                                   is_inside=0)
1959         self.vapi.nat44_interface_add_del_feature(self.pg4.sw_if_index)
1960         self.vapi.nat44_interface_add_del_feature(self.pg5.sw_if_index)
1961         self.vapi.nat44_interface_add_del_feature(self.pg6.sw_if_index)
1962         self.nat44_add_static_mapping(self.pg6.remote_ip4, static_nat_ip,
1963                                       vrf_id=20)
1964
1965         # between NAT44 inside interfaces with same VRF (no translation)
1966         pkts = self.create_stream_in(self.pg4, self.pg5)
1967         self.pg4.add_stream(pkts)
1968         self.pg_enable_capture(self.pg_interfaces)
1969         self.pg_start()
1970         capture = self.pg5.get_capture(len(pkts))
1971         self.verify_capture_no_translation(capture, self.pg4, self.pg5)
1972
1973         # between NAT44 inside interfaces with different VRF (hairpinning)
1974         p = (Ether(src=self.pg4.remote_mac, dst=self.pg4.local_mac) /
1975              IP(src=self.pg4.remote_ip4, dst=static_nat_ip) /
1976              TCP(sport=1234, dport=5678))
1977         self.pg4.add_stream(p)
1978         self.pg_enable_capture(self.pg_interfaces)
1979         self.pg_start()
1980         capture = self.pg6.get_capture(1)
1981         p = capture[0]
1982         try:
1983             ip = p[IP]
1984             tcp = p[TCP]
1985             self.assertEqual(ip.src, self.nat_addr)
1986             self.assertEqual(ip.dst, self.pg6.remote_ip4)
1987             self.assertNotEqual(tcp.sport, 1234)
1988             self.assertEqual(tcp.dport, 5678)
1989         except:
1990             self.logger.error(ppp("Unexpected or invalid packet:", p))
1991             raise
1992
1993         # in2out 1st interface
1994         pkts = self.create_stream_in(self.pg4, self.pg3)
1995         self.pg4.add_stream(pkts)
1996         self.pg_enable_capture(self.pg_interfaces)
1997         self.pg_start()
1998         capture = self.pg3.get_capture(len(pkts))
1999         self.verify_capture_out(capture)
2000
2001         # out2in 1st interface
2002         pkts = self.create_stream_out(self.pg3)
2003         self.pg3.add_stream(pkts)
2004         self.pg_enable_capture(self.pg_interfaces)
2005         self.pg_start()
2006         capture = self.pg4.get_capture(len(pkts))
2007         self.verify_capture_in(capture, self.pg4)
2008
2009         # in2out 2nd interface
2010         pkts = self.create_stream_in(self.pg5, self.pg3)
2011         self.pg5.add_stream(pkts)
2012         self.pg_enable_capture(self.pg_interfaces)
2013         self.pg_start()
2014         capture = self.pg3.get_capture(len(pkts))
2015         self.verify_capture_out(capture)
2016
2017         # out2in 2nd interface
2018         pkts = self.create_stream_out(self.pg3)
2019         self.pg3.add_stream(pkts)
2020         self.pg_enable_capture(self.pg_interfaces)
2021         self.pg_start()
2022         capture = self.pg5.get_capture(len(pkts))
2023         self.verify_capture_in(capture, self.pg5)
2024
2025         # pg5 session dump
2026         addresses = self.vapi.nat44_address_dump()
2027         self.assertEqual(len(addresses), 1)
2028         sessions = self.vapi.nat44_user_session_dump(self.pg5.remote_ip4n, 10)
2029         self.assertEqual(len(sessions), 3)
2030         for session in sessions:
2031             self.assertFalse(session.is_static)
2032             self.assertEqual(session.inside_ip_address[0:4],
2033                              self.pg5.remote_ip4n)
2034             self.assertEqual(session.outside_ip_address,
2035                              addresses[0].ip_address)
2036         self.assertEqual(sessions[0].protocol, IP_PROTOS.tcp)
2037         self.assertEqual(sessions[1].protocol, IP_PROTOS.udp)
2038         self.assertEqual(sessions[2].protocol, IP_PROTOS.icmp)
2039         self.assertEqual(sessions[0].inside_port, self.tcp_port_in)
2040         self.assertEqual(sessions[1].inside_port, self.udp_port_in)
2041         self.assertEqual(sessions[2].inside_port, self.icmp_id_in)
2042         self.assertEqual(sessions[0].outside_port, self.tcp_port_out)
2043         self.assertEqual(sessions[1].outside_port, self.udp_port_out)
2044         self.assertEqual(sessions[2].outside_port, self.icmp_id_out)
2045
2046         # in2out 3rd interface
2047         pkts = self.create_stream_in(self.pg6, self.pg3)
2048         self.pg6.add_stream(pkts)
2049         self.pg_enable_capture(self.pg_interfaces)
2050         self.pg_start()
2051         capture = self.pg3.get_capture(len(pkts))
2052         self.verify_capture_out(capture, static_nat_ip, True)
2053
2054         # out2in 3rd interface
2055         pkts = self.create_stream_out(self.pg3, static_nat_ip)
2056         self.pg3.add_stream(pkts)
2057         self.pg_enable_capture(self.pg_interfaces)
2058         self.pg_start()
2059         capture = self.pg6.get_capture(len(pkts))
2060         self.verify_capture_in(capture, self.pg6)
2061
2062         # general user and session dump verifications
2063         users = self.vapi.nat44_user_dump()
2064         self.assertTrue(len(users) >= 3)
2065         addresses = self.vapi.nat44_address_dump()
2066         self.assertEqual(len(addresses), 1)
2067         for user in users:
2068             sessions = self.vapi.nat44_user_session_dump(user.ip_address,
2069                                                          user.vrf_id)
2070             for session in sessions:
2071                 self.assertEqual(user.ip_address, session.inside_ip_address)
2072                 self.assertTrue(session.total_bytes > session.total_pkts > 0)
2073                 self.assertTrue(session.protocol in
2074                                 [IP_PROTOS.tcp, IP_PROTOS.udp,
2075                                  IP_PROTOS.icmp])
2076
2077         # pg4 session dump
2078         sessions = self.vapi.nat44_user_session_dump(self.pg4.remote_ip4n, 10)
2079         self.assertTrue(len(sessions) >= 4)
2080         for session in sessions:
2081             self.assertFalse(session.is_static)
2082             self.assertEqual(session.inside_ip_address[0:4],
2083                              self.pg4.remote_ip4n)
2084             self.assertEqual(session.outside_ip_address,
2085                              addresses[0].ip_address)
2086
2087         # pg6 session dump
2088         sessions = self.vapi.nat44_user_session_dump(self.pg6.remote_ip4n, 20)
2089         self.assertTrue(len(sessions) >= 3)
2090         for session in sessions:
2091             self.assertTrue(session.is_static)
2092             self.assertEqual(session.inside_ip_address[0:4],
2093                              self.pg6.remote_ip4n)
2094             self.assertEqual(map(ord, session.outside_ip_address[0:4]),
2095                              map(int, static_nat_ip.split('.')))
2096             self.assertTrue(session.inside_port in
2097                             [self.tcp_port_in, self.udp_port_in,
2098                              self.icmp_id_in])
2099
2100     def test_hairpinning(self):
2101         """ NAT44 hairpinning - 1:1 NAPT """
2102
2103         host = self.pg0.remote_hosts[0]
2104         server = self.pg0.remote_hosts[1]
2105         host_in_port = 1234
2106         host_out_port = 0
2107         server_in_port = 5678
2108         server_out_port = 8765
2109
2110         self.nat44_add_address(self.nat_addr)
2111         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
2112         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
2113                                                   is_inside=0)
2114         # add static mapping for server
2115         self.nat44_add_static_mapping(server.ip4, self.nat_addr,
2116                                       server_in_port, server_out_port,
2117                                       proto=IP_PROTOS.tcp)
2118
2119         # send packet from host to server
2120         p = (Ether(src=host.mac, dst=self.pg0.local_mac) /
2121              IP(src=host.ip4, dst=self.nat_addr) /
2122              TCP(sport=host_in_port, dport=server_out_port))
2123         self.pg0.add_stream(p)
2124         self.pg_enable_capture(self.pg_interfaces)
2125         self.pg_start()
2126         capture = self.pg0.get_capture(1)
2127         p = capture[0]
2128         try:
2129             ip = p[IP]
2130             tcp = p[TCP]
2131             self.assertEqual(ip.src, self.nat_addr)
2132             self.assertEqual(ip.dst, server.ip4)
2133             self.assertNotEqual(tcp.sport, host_in_port)
2134             self.assertEqual(tcp.dport, server_in_port)
2135             self.assert_packet_checksums_valid(p)
2136             host_out_port = tcp.sport
2137         except:
2138             self.logger.error(ppp("Unexpected or invalid packet:", p))
2139             raise
2140
2141         # send reply from server to host
2142         p = (Ether(src=server.mac, dst=self.pg0.local_mac) /
2143              IP(src=server.ip4, dst=self.nat_addr) /
2144              TCP(sport=server_in_port, dport=host_out_port))
2145         self.pg0.add_stream(p)
2146         self.pg_enable_capture(self.pg_interfaces)
2147         self.pg_start()
2148         capture = self.pg0.get_capture(1)
2149         p = capture[0]
2150         try:
2151             ip = p[IP]
2152             tcp = p[TCP]
2153             self.assertEqual(ip.src, self.nat_addr)
2154             self.assertEqual(ip.dst, host.ip4)
2155             self.assertEqual(tcp.sport, server_out_port)
2156             self.assertEqual(tcp.dport, host_in_port)
2157             self.assert_packet_checksums_valid(p)
2158         except:
2159             self.logger.error(ppp("Unexpected or invalid packet:", p))
2160             raise
2161
2162     def test_hairpinning2(self):
2163         """ NAT44 hairpinning - 1:1 NAT"""
2164
2165         server1_nat_ip = "10.0.0.10"
2166         server2_nat_ip = "10.0.0.11"
2167         host = self.pg0.remote_hosts[0]
2168         server1 = self.pg0.remote_hosts[1]
2169         server2 = self.pg0.remote_hosts[2]
2170         server_tcp_port = 22
2171         server_udp_port = 20
2172
2173         self.nat44_add_address(self.nat_addr)
2174         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
2175         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
2176                                                   is_inside=0)
2177
2178         # add static mapping for servers
2179         self.nat44_add_static_mapping(server1.ip4, server1_nat_ip)
2180         self.nat44_add_static_mapping(server2.ip4, server2_nat_ip)
2181
2182         # host to server1
2183         pkts = []
2184         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2185              IP(src=host.ip4, dst=server1_nat_ip) /
2186              TCP(sport=self.tcp_port_in, dport=server_tcp_port))
2187         pkts.append(p)
2188         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2189              IP(src=host.ip4, dst=server1_nat_ip) /
2190              UDP(sport=self.udp_port_in, dport=server_udp_port))
2191         pkts.append(p)
2192         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2193              IP(src=host.ip4, dst=server1_nat_ip) /
2194              ICMP(id=self.icmp_id_in, type='echo-request'))
2195         pkts.append(p)
2196         self.pg0.add_stream(pkts)
2197         self.pg_enable_capture(self.pg_interfaces)
2198         self.pg_start()
2199         capture = self.pg0.get_capture(len(pkts))
2200         for packet in capture:
2201             try:
2202                 self.assertEqual(packet[IP].src, self.nat_addr)
2203                 self.assertEqual(packet[IP].dst, server1.ip4)
2204                 if packet.haslayer(TCP):
2205                     self.assertNotEqual(packet[TCP].sport, self.tcp_port_in)
2206                     self.assertEqual(packet[TCP].dport, server_tcp_port)
2207                     self.tcp_port_out = packet[TCP].sport
2208                     self.assert_packet_checksums_valid(packet)
2209                 elif packet.haslayer(UDP):
2210                     self.assertNotEqual(packet[UDP].sport, self.udp_port_in)
2211                     self.assertEqual(packet[UDP].dport, server_udp_port)
2212                     self.udp_port_out = packet[UDP].sport
2213                 else:
2214                     self.assertNotEqual(packet[ICMP].id, self.icmp_id_in)
2215                     self.icmp_id_out = packet[ICMP].id
2216             except:
2217                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
2218                 raise
2219
2220         # server1 to host
2221         pkts = []
2222         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2223              IP(src=server1.ip4, dst=self.nat_addr) /
2224              TCP(sport=server_tcp_port, dport=self.tcp_port_out))
2225         pkts.append(p)
2226         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2227              IP(src=server1.ip4, dst=self.nat_addr) /
2228              UDP(sport=server_udp_port, dport=self.udp_port_out))
2229         pkts.append(p)
2230         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2231              IP(src=server1.ip4, dst=self.nat_addr) /
2232              ICMP(id=self.icmp_id_out, type='echo-reply'))
2233         pkts.append(p)
2234         self.pg0.add_stream(pkts)
2235         self.pg_enable_capture(self.pg_interfaces)
2236         self.pg_start()
2237         capture = self.pg0.get_capture(len(pkts))
2238         for packet in capture:
2239             try:
2240                 self.assertEqual(packet[IP].src, server1_nat_ip)
2241                 self.assertEqual(packet[IP].dst, host.ip4)
2242                 if packet.haslayer(TCP):
2243                     self.assertEqual(packet[TCP].dport, self.tcp_port_in)
2244                     self.assertEqual(packet[TCP].sport, server_tcp_port)
2245                     self.assert_packet_checksums_valid(packet)
2246                 elif packet.haslayer(UDP):
2247                     self.assertEqual(packet[UDP].dport, self.udp_port_in)
2248                     self.assertEqual(packet[UDP].sport, server_udp_port)
2249                 else:
2250                     self.assertEqual(packet[ICMP].id, self.icmp_id_in)
2251             except:
2252                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
2253                 raise
2254
2255         # server2 to server1
2256         pkts = []
2257         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2258              IP(src=server2.ip4, dst=server1_nat_ip) /
2259              TCP(sport=self.tcp_port_in, dport=server_tcp_port))
2260         pkts.append(p)
2261         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2262              IP(src=server2.ip4, dst=server1_nat_ip) /
2263              UDP(sport=self.udp_port_in, dport=server_udp_port))
2264         pkts.append(p)
2265         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2266              IP(src=server2.ip4, dst=server1_nat_ip) /
2267              ICMP(id=self.icmp_id_in, type='echo-request'))
2268         pkts.append(p)
2269         self.pg0.add_stream(pkts)
2270         self.pg_enable_capture(self.pg_interfaces)
2271         self.pg_start()
2272         capture = self.pg0.get_capture(len(pkts))
2273         for packet in capture:
2274             try:
2275                 self.assertEqual(packet[IP].src, server2_nat_ip)
2276                 self.assertEqual(packet[IP].dst, server1.ip4)
2277                 if packet.haslayer(TCP):
2278                     self.assertEqual(packet[TCP].sport, self.tcp_port_in)
2279                     self.assertEqual(packet[TCP].dport, server_tcp_port)
2280                     self.tcp_port_out = packet[TCP].sport
2281                     self.assert_packet_checksums_valid(packet)
2282                 elif packet.haslayer(UDP):
2283                     self.assertEqual(packet[UDP].sport, self.udp_port_in)
2284                     self.assertEqual(packet[UDP].dport, server_udp_port)
2285                     self.udp_port_out = packet[UDP].sport
2286                 else:
2287                     self.assertEqual(packet[ICMP].id, self.icmp_id_in)
2288                     self.icmp_id_out = packet[ICMP].id
2289             except:
2290                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
2291                 raise
2292
2293         # server1 to server2
2294         pkts = []
2295         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2296              IP(src=server1.ip4, dst=server2_nat_ip) /
2297              TCP(sport=server_tcp_port, dport=self.tcp_port_out))
2298         pkts.append(p)
2299         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2300              IP(src=server1.ip4, dst=server2_nat_ip) /
2301              UDP(sport=server_udp_port, dport=self.udp_port_out))
2302         pkts.append(p)
2303         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2304              IP(src=server1.ip4, dst=server2_nat_ip) /
2305              ICMP(id=self.icmp_id_out, type='echo-reply'))
2306         pkts.append(p)
2307         self.pg0.add_stream(pkts)
2308         self.pg_enable_capture(self.pg_interfaces)
2309         self.pg_start()
2310         capture = self.pg0.get_capture(len(pkts))
2311         for packet in capture:
2312             try:
2313                 self.assertEqual(packet[IP].src, server1_nat_ip)
2314                 self.assertEqual(packet[IP].dst, server2.ip4)
2315                 if packet.haslayer(TCP):
2316                     self.assertEqual(packet[TCP].dport, self.tcp_port_in)
2317                     self.assertEqual(packet[TCP].sport, server_tcp_port)
2318                     self.assert_packet_checksums_valid(packet)
2319                 elif packet.haslayer(UDP):
2320                     self.assertEqual(packet[UDP].dport, self.udp_port_in)
2321                     self.assertEqual(packet[UDP].sport, server_udp_port)
2322                 else:
2323                     self.assertEqual(packet[ICMP].id, self.icmp_id_in)
2324             except:
2325                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
2326                 raise
2327
2328     def test_max_translations_per_user(self):
2329         """ MAX translations per user - recycle the least recently used """
2330
2331         self.nat44_add_address(self.nat_addr)
2332         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
2333         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
2334                                                   is_inside=0)
2335
2336         # get maximum number of translations per user
2337         nat44_config = self.vapi.nat_show_config()
2338
2339         # send more than maximum number of translations per user packets
2340         pkts_num = nat44_config.max_translations_per_user + 5
2341         pkts = []
2342         for port in range(0, pkts_num):
2343             p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2344                  IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
2345                  TCP(sport=1025 + port))
2346             pkts.append(p)
2347         self.pg0.add_stream(pkts)
2348         self.pg_enable_capture(self.pg_interfaces)
2349         self.pg_start()
2350
2351         # verify number of translated packet
2352         self.pg1.get_capture(pkts_num)
2353
2354         users = self.vapi.nat44_user_dump()
2355         for user in users:
2356             if user.ip_address == self.pg0.remote_ip4n:
2357                 self.assertEqual(user.nsessions,
2358                                  nat44_config.max_translations_per_user)
2359                 self.assertEqual(user.nstaticsessions, 0)
2360
2361         tcp_port = 22
2362         self.nat44_add_static_mapping(self.pg0.remote_ip4, self.nat_addr,
2363                                       tcp_port, tcp_port,
2364                                       proto=IP_PROTOS.tcp)
2365         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2366              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
2367              TCP(sport=tcp_port))
2368         self.pg0.add_stream(p)
2369         self.pg_enable_capture(self.pg_interfaces)
2370         self.pg_start()
2371         self.pg1.get_capture(1)
2372         users = self.vapi.nat44_user_dump()
2373         for user in users:
2374             if user.ip_address == self.pg0.remote_ip4n:
2375                 self.assertEqual(user.nsessions,
2376                                  nat44_config.max_translations_per_user - 1)
2377                 self.assertEqual(user.nstaticsessions, 1)
2378
2379     def test_interface_addr(self):
2380         """ Acquire NAT44 addresses from interface """
2381         self.vapi.nat44_add_interface_addr(self.pg7.sw_if_index)
2382
2383         # no address in NAT pool
2384         adresses = self.vapi.nat44_address_dump()
2385         self.assertEqual(0, len(adresses))
2386
2387         # configure interface address and check NAT address pool
2388         self.pg7.config_ip4()
2389         adresses = self.vapi.nat44_address_dump()
2390         self.assertEqual(1, len(adresses))
2391         self.assertEqual(adresses[0].ip_address[0:4], self.pg7.local_ip4n)
2392
2393         # remove interface address and check NAT address pool
2394         self.pg7.unconfig_ip4()
2395         adresses = self.vapi.nat44_address_dump()
2396         self.assertEqual(0, len(adresses))
2397
2398     def test_interface_addr_static_mapping(self):
2399         """ Static mapping with addresses from interface """
2400         tag = "testTAG"
2401
2402         self.vapi.nat44_add_interface_addr(self.pg7.sw_if_index)
2403         self.nat44_add_static_mapping(
2404             '1.2.3.4',
2405             external_sw_if_index=self.pg7.sw_if_index,
2406             tag=tag)
2407
2408         # static mappings with external interface
2409         static_mappings = self.vapi.nat44_static_mapping_dump()
2410         self.assertEqual(1, len(static_mappings))
2411         self.assertEqual(self.pg7.sw_if_index,
2412                          static_mappings[0].external_sw_if_index)
2413         self.assertEqual((static_mappings[0].tag).split('\0', 1)[0], tag)
2414
2415         # configure interface address and check static mappings
2416         self.pg7.config_ip4()
2417         static_mappings = self.vapi.nat44_static_mapping_dump()
2418         self.assertEqual(2, len(static_mappings))
2419         resolved = False
2420         for sm in static_mappings:
2421             if sm.external_sw_if_index == 0xFFFFFFFF:
2422                 self.assertEqual(sm.external_ip_address[0:4],
2423                                  self.pg7.local_ip4n)
2424                 self.assertEqual((sm.tag).split('\0', 1)[0], tag)
2425                 resolved = True
2426         self.assertTrue(resolved)
2427
2428         # remove interface address and check static mappings
2429         self.pg7.unconfig_ip4()
2430         static_mappings = self.vapi.nat44_static_mapping_dump()
2431         self.assertEqual(1, len(static_mappings))
2432         self.assertEqual(self.pg7.sw_if_index,
2433                          static_mappings[0].external_sw_if_index)
2434         self.assertEqual((static_mappings[0].tag).split('\0', 1)[0], tag)
2435
2436         # configure interface address again and check static mappings
2437         self.pg7.config_ip4()
2438         static_mappings = self.vapi.nat44_static_mapping_dump()
2439         self.assertEqual(2, len(static_mappings))
2440         resolved = False
2441         for sm in static_mappings:
2442             if sm.external_sw_if_index == 0xFFFFFFFF:
2443                 self.assertEqual(sm.external_ip_address[0:4],
2444                                  self.pg7.local_ip4n)
2445                 self.assertEqual((sm.tag).split('\0', 1)[0], tag)
2446                 resolved = True
2447         self.assertTrue(resolved)
2448
2449         # remove static mapping
2450         self.nat44_add_static_mapping(
2451             '1.2.3.4',
2452             external_sw_if_index=self.pg7.sw_if_index,
2453             tag=tag,
2454             is_add=0)
2455         static_mappings = self.vapi.nat44_static_mapping_dump()
2456         self.assertEqual(0, len(static_mappings))
2457
2458     def test_interface_addr_identity_nat(self):
2459         """ Identity NAT with addresses from interface """
2460
2461         port = 53053
2462         self.vapi.nat44_add_interface_addr(self.pg7.sw_if_index)
2463         self.vapi.nat44_add_del_identity_mapping(
2464             sw_if_index=self.pg7.sw_if_index,
2465             port=port,
2466             protocol=IP_PROTOS.tcp,
2467             addr_only=0)
2468
2469         # identity mappings with external interface
2470         identity_mappings = self.vapi.nat44_identity_mapping_dump()
2471         self.assertEqual(1, len(identity_mappings))
2472         self.assertEqual(self.pg7.sw_if_index,
2473                          identity_mappings[0].sw_if_index)
2474
2475         # configure interface address and check identity mappings
2476         self.pg7.config_ip4()
2477         identity_mappings = self.vapi.nat44_identity_mapping_dump()
2478         resolved = False
2479         self.assertEqual(2, len(identity_mappings))
2480         for sm in identity_mappings:
2481             if sm.sw_if_index == 0xFFFFFFFF:
2482                 self.assertEqual(identity_mappings[0].ip_address,
2483                                  self.pg7.local_ip4n)
2484                 self.assertEqual(port, identity_mappings[0].port)
2485                 self.assertEqual(IP_PROTOS.tcp, identity_mappings[0].protocol)
2486                 resolved = True
2487         self.assertTrue(resolved)
2488
2489         # remove interface address and check identity mappings
2490         self.pg7.unconfig_ip4()
2491         identity_mappings = self.vapi.nat44_identity_mapping_dump()
2492         self.assertEqual(1, len(identity_mappings))
2493         self.assertEqual(self.pg7.sw_if_index,
2494                          identity_mappings[0].sw_if_index)
2495
2496     def test_ipfix_nat44_sess(self):
2497         """ IPFIX logging NAT44 session created/delted """
2498         self.ipfix_domain_id = 10
2499         self.ipfix_src_port = 20202
2500         colector_port = 30303
2501         bind_layers(UDP, IPFIX, dport=30303)
2502         self.nat44_add_address(self.nat_addr)
2503         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
2504         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
2505                                                   is_inside=0)
2506         self.vapi.set_ipfix_exporter(collector_address=self.pg3.remote_ip4n,
2507                                      src_address=self.pg3.local_ip4n,
2508                                      path_mtu=512,
2509                                      template_interval=10,
2510                                      collector_port=colector_port)
2511         self.vapi.nat_ipfix(domain_id=self.ipfix_domain_id,
2512                             src_port=self.ipfix_src_port)
2513
2514         pkts = self.create_stream_in(self.pg0, self.pg1)
2515         self.pg0.add_stream(pkts)
2516         self.pg_enable_capture(self.pg_interfaces)
2517         self.pg_start()
2518         capture = self.pg1.get_capture(len(pkts))
2519         self.verify_capture_out(capture)
2520         self.nat44_add_address(self.nat_addr, is_add=0)
2521         self.vapi.cli("ipfix flush")  # FIXME this should be an API call
2522         capture = self.pg3.get_capture(9)
2523         ipfix = IPFIXDecoder()
2524         # first load template
2525         for p in capture:
2526             self.assertTrue(p.haslayer(IPFIX))
2527             self.assertEqual(p[IP].src, self.pg3.local_ip4)
2528             self.assertEqual(p[IP].dst, self.pg3.remote_ip4)
2529             self.assertEqual(p[UDP].sport, self.ipfix_src_port)
2530             self.assertEqual(p[UDP].dport, colector_port)
2531             self.assertEqual(p[IPFIX].observationDomainID,
2532                              self.ipfix_domain_id)
2533             if p.haslayer(Template):
2534                 ipfix.add_template(p.getlayer(Template))
2535         # verify events in data set
2536         for p in capture:
2537             if p.haslayer(Data):
2538                 data = ipfix.decode_data_set(p.getlayer(Set))
2539                 self.verify_ipfix_nat44_ses(data)
2540
2541     def test_ipfix_addr_exhausted(self):
2542         """ IPFIX logging NAT addresses exhausted """
2543         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
2544         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
2545                                                   is_inside=0)
2546         self.vapi.set_ipfix_exporter(collector_address=self.pg3.remote_ip4n,
2547                                      src_address=self.pg3.local_ip4n,
2548                                      path_mtu=512,
2549                                      template_interval=10)
2550         self.vapi.nat_ipfix(domain_id=self.ipfix_domain_id,
2551                             src_port=self.ipfix_src_port)
2552
2553         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
2554              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
2555              TCP(sport=3025))
2556         self.pg0.add_stream(p)
2557         self.pg_enable_capture(self.pg_interfaces)
2558         self.pg_start()
2559         capture = self.pg1.get_capture(0)
2560         self.vapi.cli("ipfix flush")  # FIXME this should be an API call
2561         capture = self.pg3.get_capture(9)
2562         ipfix = IPFIXDecoder()
2563         # first load template
2564         for p in capture:
2565             self.assertTrue(p.haslayer(IPFIX))
2566             self.assertEqual(p[IP].src, self.pg3.local_ip4)
2567             self.assertEqual(p[IP].dst, self.pg3.remote_ip4)
2568             self.assertEqual(p[UDP].sport, self.ipfix_src_port)
2569             self.assertEqual(p[UDP].dport, 4739)
2570             self.assertEqual(p[IPFIX].observationDomainID,
2571                              self.ipfix_domain_id)
2572             if p.haslayer(Template):
2573                 ipfix.add_template(p.getlayer(Template))
2574         # verify events in data set
2575         for p in capture:
2576             if p.haslayer(Data):
2577                 data = ipfix.decode_data_set(p.getlayer(Set))
2578                 self.verify_ipfix_addr_exhausted(data)
2579
2580     @unittest.skipUnless(running_extended_tests(), "part of extended tests")
2581     def test_ipfix_max_sessions(self):
2582         """ IPFIX logging maximum session entries exceeded """
2583         self.nat44_add_address(self.nat_addr)
2584         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
2585         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
2586                                                   is_inside=0)
2587
2588         nat44_config = self.vapi.nat_show_config()
2589         max_sessions = 10 * nat44_config.translation_buckets
2590
2591         pkts = []
2592         for i in range(0, max_sessions):
2593             src = "10.10.%u.%u" % ((i & 0xFF00) >> 8, i & 0xFF)
2594             p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2595                  IP(src=src, dst=self.pg1.remote_ip4) /
2596                  TCP(sport=1025))
2597             pkts.append(p)
2598         self.pg0.add_stream(pkts)
2599         self.pg_enable_capture(self.pg_interfaces)
2600         self.pg_start()
2601
2602         self.pg1.get_capture(max_sessions)
2603         self.vapi.set_ipfix_exporter(collector_address=self.pg3.remote_ip4n,
2604                                      src_address=self.pg3.local_ip4n,
2605                                      path_mtu=512,
2606                                      template_interval=10)
2607         self.vapi.nat_ipfix(domain_id=self.ipfix_domain_id,
2608                             src_port=self.ipfix_src_port)
2609
2610         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2611              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
2612              TCP(sport=1025))
2613         self.pg0.add_stream(p)
2614         self.pg_enable_capture(self.pg_interfaces)
2615         self.pg_start()
2616         self.pg1.get_capture(0)
2617         self.vapi.cli("ipfix flush")  # FIXME this should be an API call
2618         capture = self.pg3.get_capture(9)
2619         ipfix = IPFIXDecoder()
2620         # first load template
2621         for p in capture:
2622             self.assertTrue(p.haslayer(IPFIX))
2623             self.assertEqual(p[IP].src, self.pg3.local_ip4)
2624             self.assertEqual(p[IP].dst, self.pg3.remote_ip4)
2625             self.assertEqual(p[UDP].sport, self.ipfix_src_port)
2626             self.assertEqual(p[UDP].dport, 4739)
2627             self.assertEqual(p[IPFIX].observationDomainID,
2628                              self.ipfix_domain_id)
2629             if p.haslayer(Template):
2630                 ipfix.add_template(p.getlayer(Template))
2631         # verify events in data set
2632         for p in capture:
2633             if p.haslayer(Data):
2634                 data = ipfix.decode_data_set(p.getlayer(Set))
2635                 self.verify_ipfix_max_sessions(data, max_sessions)
2636
2637     def test_pool_addr_fib(self):
2638         """ NAT44 add pool addresses to FIB """
2639         static_addr = '10.0.0.10'
2640         self.nat44_add_address(self.nat_addr)
2641         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
2642         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
2643                                                   is_inside=0)
2644         self.nat44_add_static_mapping(self.pg0.remote_ip4, static_addr)
2645
2646         # NAT44 address
2647         p = (Ether(src=self.pg1.remote_mac, dst='ff:ff:ff:ff:ff:ff') /
2648              ARP(op=ARP.who_has, pdst=self.nat_addr,
2649                  psrc=self.pg1.remote_ip4, hwsrc=self.pg1.remote_mac))
2650         self.pg1.add_stream(p)
2651         self.pg_enable_capture(self.pg_interfaces)
2652         self.pg_start()
2653         capture = self.pg1.get_capture(1)
2654         self.assertTrue(capture[0].haslayer(ARP))
2655         self.assertTrue(capture[0][ARP].op, ARP.is_at)
2656
2657         # 1:1 NAT address
2658         p = (Ether(src=self.pg1.remote_mac, dst='ff:ff:ff:ff:ff:ff') /
2659              ARP(op=ARP.who_has, pdst=static_addr,
2660                  psrc=self.pg1.remote_ip4, hwsrc=self.pg1.remote_mac))
2661         self.pg1.add_stream(p)
2662         self.pg_enable_capture(self.pg_interfaces)
2663         self.pg_start()
2664         capture = self.pg1.get_capture(1)
2665         self.assertTrue(capture[0].haslayer(ARP))
2666         self.assertTrue(capture[0][ARP].op, ARP.is_at)
2667
2668         # send ARP to non-NAT44 interface
2669         p = (Ether(src=self.pg2.remote_mac, dst='ff:ff:ff:ff:ff:ff') /
2670              ARP(op=ARP.who_has, pdst=self.nat_addr,
2671                  psrc=self.pg2.remote_ip4, hwsrc=self.pg2.remote_mac))
2672         self.pg2.add_stream(p)
2673         self.pg_enable_capture(self.pg_interfaces)
2674         self.pg_start()
2675         capture = self.pg1.get_capture(0)
2676
2677         # remove addresses and verify
2678         self.nat44_add_address(self.nat_addr, is_add=0)
2679         self.nat44_add_static_mapping(self.pg0.remote_ip4, static_addr,
2680                                       is_add=0)
2681
2682         p = (Ether(src=self.pg1.remote_mac, dst='ff:ff:ff:ff:ff:ff') /
2683              ARP(op=ARP.who_has, pdst=self.nat_addr,
2684                  psrc=self.pg1.remote_ip4, hwsrc=self.pg1.remote_mac))
2685         self.pg1.add_stream(p)
2686         self.pg_enable_capture(self.pg_interfaces)
2687         self.pg_start()
2688         capture = self.pg1.get_capture(0)
2689
2690         p = (Ether(src=self.pg1.remote_mac, dst='ff:ff:ff:ff:ff:ff') /
2691              ARP(op=ARP.who_has, pdst=static_addr,
2692                  psrc=self.pg1.remote_ip4, hwsrc=self.pg1.remote_mac))
2693         self.pg1.add_stream(p)
2694         self.pg_enable_capture(self.pg_interfaces)
2695         self.pg_start()
2696         capture = self.pg1.get_capture(0)
2697
2698     def test_vrf_mode(self):
2699         """ NAT44 tenant VRF aware address pool mode """
2700
2701         vrf_id1 = 1
2702         vrf_id2 = 2
2703         nat_ip1 = "10.0.0.10"
2704         nat_ip2 = "10.0.0.11"
2705
2706         self.pg0.unconfig_ip4()
2707         self.pg1.unconfig_ip4()
2708         self.vapi.ip_table_add_del(vrf_id1, is_add=1)
2709         self.vapi.ip_table_add_del(vrf_id2, is_add=1)
2710         self.pg0.set_table_ip4(vrf_id1)
2711         self.pg1.set_table_ip4(vrf_id2)
2712         self.pg0.config_ip4()
2713         self.pg1.config_ip4()
2714
2715         self.nat44_add_address(nat_ip1, vrf_id=vrf_id1)
2716         self.nat44_add_address(nat_ip2, vrf_id=vrf_id2)
2717         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
2718         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index)
2719         self.vapi.nat44_interface_add_del_feature(self.pg2.sw_if_index,
2720                                                   is_inside=0)
2721
2722         # first VRF
2723         pkts = self.create_stream_in(self.pg0, self.pg2)
2724         self.pg0.add_stream(pkts)
2725         self.pg_enable_capture(self.pg_interfaces)
2726         self.pg_start()
2727         capture = self.pg2.get_capture(len(pkts))
2728         self.verify_capture_out(capture, nat_ip1)
2729
2730         # second VRF
2731         pkts = self.create_stream_in(self.pg1, self.pg2)
2732         self.pg1.add_stream(pkts)
2733         self.pg_enable_capture(self.pg_interfaces)
2734         self.pg_start()
2735         capture = self.pg2.get_capture(len(pkts))
2736         self.verify_capture_out(capture, nat_ip2)
2737
2738         self.pg0.unconfig_ip4()
2739         self.pg1.unconfig_ip4()
2740         self.pg0.set_table_ip4(0)
2741         self.pg1.set_table_ip4(0)
2742         self.vapi.ip_table_add_del(vrf_id1, is_add=0)
2743         self.vapi.ip_table_add_del(vrf_id2, is_add=0)
2744
2745     def test_vrf_feature_independent(self):
2746         """ NAT44 tenant VRF independent address pool mode """
2747
2748         nat_ip1 = "10.0.0.10"
2749         nat_ip2 = "10.0.0.11"
2750
2751         self.nat44_add_address(nat_ip1)
2752         self.nat44_add_address(nat_ip2, vrf_id=99)
2753         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
2754         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index)
2755         self.vapi.nat44_interface_add_del_feature(self.pg2.sw_if_index,
2756                                                   is_inside=0)
2757
2758         # first VRF
2759         pkts = self.create_stream_in(self.pg0, self.pg2)
2760         self.pg0.add_stream(pkts)
2761         self.pg_enable_capture(self.pg_interfaces)
2762         self.pg_start()
2763         capture = self.pg2.get_capture(len(pkts))
2764         self.verify_capture_out(capture, nat_ip1)
2765
2766         # second VRF
2767         pkts = self.create_stream_in(self.pg1, self.pg2)
2768         self.pg1.add_stream(pkts)
2769         self.pg_enable_capture(self.pg_interfaces)
2770         self.pg_start()
2771         capture = self.pg2.get_capture(len(pkts))
2772         self.verify_capture_out(capture, nat_ip1)
2773
2774     def test_dynamic_ipless_interfaces(self):
2775         """ NAT44 interfaces without configured IP address """
2776
2777         self.vapi.ip_neighbor_add_del(self.pg7.sw_if_index,
2778                                       mactobinary(self.pg7.remote_mac),
2779                                       self.pg7.remote_ip4n,
2780                                       is_static=1)
2781         self.vapi.ip_neighbor_add_del(self.pg8.sw_if_index,
2782                                       mactobinary(self.pg8.remote_mac),
2783                                       self.pg8.remote_ip4n,
2784                                       is_static=1)
2785
2786         self.vapi.ip_add_del_route(dst_address=self.pg7.remote_ip4n,
2787                                    dst_address_length=32,
2788                                    next_hop_address=self.pg7.remote_ip4n,
2789                                    next_hop_sw_if_index=self.pg7.sw_if_index)
2790         self.vapi.ip_add_del_route(dst_address=self.pg8.remote_ip4n,
2791                                    dst_address_length=32,
2792                                    next_hop_address=self.pg8.remote_ip4n,
2793                                    next_hop_sw_if_index=self.pg8.sw_if_index)
2794
2795         self.nat44_add_address(self.nat_addr)
2796         self.vapi.nat44_interface_add_del_feature(self.pg7.sw_if_index)
2797         self.vapi.nat44_interface_add_del_feature(self.pg8.sw_if_index,
2798                                                   is_inside=0)
2799
2800         # in2out
2801         pkts = self.create_stream_in(self.pg7, self.pg8)
2802         self.pg7.add_stream(pkts)
2803         self.pg_enable_capture(self.pg_interfaces)
2804         self.pg_start()
2805         capture = self.pg8.get_capture(len(pkts))
2806         self.verify_capture_out(capture)
2807
2808         # out2in
2809         pkts = self.create_stream_out(self.pg8, self.nat_addr)
2810         self.pg8.add_stream(pkts)
2811         self.pg_enable_capture(self.pg_interfaces)
2812         self.pg_start()
2813         capture = self.pg7.get_capture(len(pkts))
2814         self.verify_capture_in(capture, self.pg7)
2815
2816     def test_static_ipless_interfaces(self):
2817         """ NAT44 interfaces without configured IP address - 1:1 NAT """
2818
2819         self.vapi.ip_neighbor_add_del(self.pg7.sw_if_index,
2820                                       mactobinary(self.pg7.remote_mac),
2821                                       self.pg7.remote_ip4n,
2822                                       is_static=1)
2823         self.vapi.ip_neighbor_add_del(self.pg8.sw_if_index,
2824                                       mactobinary(self.pg8.remote_mac),
2825                                       self.pg8.remote_ip4n,
2826                                       is_static=1)
2827
2828         self.vapi.ip_add_del_route(dst_address=self.pg7.remote_ip4n,
2829                                    dst_address_length=32,
2830                                    next_hop_address=self.pg7.remote_ip4n,
2831                                    next_hop_sw_if_index=self.pg7.sw_if_index)
2832         self.vapi.ip_add_del_route(dst_address=self.pg8.remote_ip4n,
2833                                    dst_address_length=32,
2834                                    next_hop_address=self.pg8.remote_ip4n,
2835                                    next_hop_sw_if_index=self.pg8.sw_if_index)
2836
2837         self.nat44_add_static_mapping(self.pg7.remote_ip4, self.nat_addr)
2838         self.vapi.nat44_interface_add_del_feature(self.pg7.sw_if_index)
2839         self.vapi.nat44_interface_add_del_feature(self.pg8.sw_if_index,
2840                                                   is_inside=0)
2841
2842         # out2in
2843         pkts = self.create_stream_out(self.pg8)
2844         self.pg8.add_stream(pkts)
2845         self.pg_enable_capture(self.pg_interfaces)
2846         self.pg_start()
2847         capture = self.pg7.get_capture(len(pkts))
2848         self.verify_capture_in(capture, self.pg7)
2849
2850         # in2out
2851         pkts = self.create_stream_in(self.pg7, self.pg8)
2852         self.pg7.add_stream(pkts)
2853         self.pg_enable_capture(self.pg_interfaces)
2854         self.pg_start()
2855         capture = self.pg8.get_capture(len(pkts))
2856         self.verify_capture_out(capture, self.nat_addr, True)
2857
2858     def test_static_with_port_ipless_interfaces(self):
2859         """ NAT44 interfaces without configured IP address - 1:1 NAPT """
2860
2861         self.tcp_port_out = 30606
2862         self.udp_port_out = 30607
2863         self.icmp_id_out = 30608
2864
2865         self.vapi.ip_neighbor_add_del(self.pg7.sw_if_index,
2866                                       mactobinary(self.pg7.remote_mac),
2867                                       self.pg7.remote_ip4n,
2868                                       is_static=1)
2869         self.vapi.ip_neighbor_add_del(self.pg8.sw_if_index,
2870                                       mactobinary(self.pg8.remote_mac),
2871                                       self.pg8.remote_ip4n,
2872                                       is_static=1)
2873
2874         self.vapi.ip_add_del_route(dst_address=self.pg7.remote_ip4n,
2875                                    dst_address_length=32,
2876                                    next_hop_address=self.pg7.remote_ip4n,
2877                                    next_hop_sw_if_index=self.pg7.sw_if_index)
2878         self.vapi.ip_add_del_route(dst_address=self.pg8.remote_ip4n,
2879                                    dst_address_length=32,
2880                                    next_hop_address=self.pg8.remote_ip4n,
2881                                    next_hop_sw_if_index=self.pg8.sw_if_index)
2882
2883         self.nat44_add_address(self.nat_addr)
2884         self.nat44_add_static_mapping(self.pg7.remote_ip4, self.nat_addr,
2885                                       self.tcp_port_in, self.tcp_port_out,
2886                                       proto=IP_PROTOS.tcp)
2887         self.nat44_add_static_mapping(self.pg7.remote_ip4, self.nat_addr,
2888                                       self.udp_port_in, self.udp_port_out,
2889                                       proto=IP_PROTOS.udp)
2890         self.nat44_add_static_mapping(self.pg7.remote_ip4, self.nat_addr,
2891                                       self.icmp_id_in, self.icmp_id_out,
2892                                       proto=IP_PROTOS.icmp)
2893         self.vapi.nat44_interface_add_del_feature(self.pg7.sw_if_index)
2894         self.vapi.nat44_interface_add_del_feature(self.pg8.sw_if_index,
2895                                                   is_inside=0)
2896
2897         # out2in
2898         pkts = self.create_stream_out(self.pg8)
2899         self.pg8.add_stream(pkts)
2900         self.pg_enable_capture(self.pg_interfaces)
2901         self.pg_start()
2902         capture = self.pg7.get_capture(len(pkts))
2903         self.verify_capture_in(capture, self.pg7)
2904
2905         # in2out
2906         pkts = self.create_stream_in(self.pg7, self.pg8)
2907         self.pg7.add_stream(pkts)
2908         self.pg_enable_capture(self.pg_interfaces)
2909         self.pg_start()
2910         capture = self.pg8.get_capture(len(pkts))
2911         self.verify_capture_out(capture)
2912
2913     def test_static_unknown_proto(self):
2914         """ 1:1 NAT translate packet with unknown protocol """
2915         nat_ip = "10.0.0.10"
2916         self.nat44_add_static_mapping(self.pg0.remote_ip4, nat_ip)
2917         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
2918         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
2919                                                   is_inside=0)
2920
2921         # in2out
2922         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2923              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
2924              GRE() /
2925              IP(src=self.pg2.remote_ip4, dst=self.pg3.remote_ip4) /
2926              TCP(sport=1234, dport=1234))
2927         self.pg0.add_stream(p)
2928         self.pg_enable_capture(self.pg_interfaces)
2929         self.pg_start()
2930         p = self.pg1.get_capture(1)
2931         packet = p[0]
2932         try:
2933             self.assertEqual(packet[IP].src, nat_ip)
2934             self.assertEqual(packet[IP].dst, self.pg1.remote_ip4)
2935             self.assertTrue(packet.haslayer(GRE))
2936             self.assert_packet_checksums_valid(packet)
2937         except:
2938             self.logger.error(ppp("Unexpected or invalid packet:", packet))
2939             raise
2940
2941         # out2in
2942         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
2943              IP(src=self.pg1.remote_ip4, dst=nat_ip) /
2944              GRE() /
2945              IP(src=self.pg3.remote_ip4, dst=self.pg2.remote_ip4) /
2946              TCP(sport=1234, dport=1234))
2947         self.pg1.add_stream(p)
2948         self.pg_enable_capture(self.pg_interfaces)
2949         self.pg_start()
2950         p = self.pg0.get_capture(1)
2951         packet = p[0]
2952         try:
2953             self.assertEqual(packet[IP].src, self.pg1.remote_ip4)
2954             self.assertEqual(packet[IP].dst, self.pg0.remote_ip4)
2955             self.assertTrue(packet.haslayer(GRE))
2956             self.assert_packet_checksums_valid(packet)
2957         except:
2958             self.logger.error(ppp("Unexpected or invalid packet:", packet))
2959             raise
2960
2961     def test_hairpinning_static_unknown_proto(self):
2962         """ 1:1 NAT translate packet with unknown protocol - hairpinning """
2963
2964         host = self.pg0.remote_hosts[0]
2965         server = self.pg0.remote_hosts[1]
2966
2967         host_nat_ip = "10.0.0.10"
2968         server_nat_ip = "10.0.0.11"
2969
2970         self.nat44_add_static_mapping(host.ip4, host_nat_ip)
2971         self.nat44_add_static_mapping(server.ip4, server_nat_ip)
2972         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
2973         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
2974                                                   is_inside=0)
2975
2976         # host to server
2977         p = (Ether(dst=self.pg0.local_mac, src=host.mac) /
2978              IP(src=host.ip4, dst=server_nat_ip) /
2979              GRE() /
2980              IP(src=self.pg2.remote_ip4, dst=self.pg3.remote_ip4) /
2981              TCP(sport=1234, dport=1234))
2982         self.pg0.add_stream(p)
2983         self.pg_enable_capture(self.pg_interfaces)
2984         self.pg_start()
2985         p = self.pg0.get_capture(1)
2986         packet = p[0]
2987         try:
2988             self.assertEqual(packet[IP].src, host_nat_ip)
2989             self.assertEqual(packet[IP].dst, server.ip4)
2990             self.assertTrue(packet.haslayer(GRE))
2991             self.assert_packet_checksums_valid(packet)
2992         except:
2993             self.logger.error(ppp("Unexpected or invalid packet:", packet))
2994             raise
2995
2996         # server to host
2997         p = (Ether(dst=self.pg0.local_mac, src=server.mac) /
2998              IP(src=server.ip4, dst=host_nat_ip) /
2999              GRE() /
3000              IP(src=self.pg3.remote_ip4, dst=self.pg2.remote_ip4) /
3001              TCP(sport=1234, dport=1234))
3002         self.pg0.add_stream(p)
3003         self.pg_enable_capture(self.pg_interfaces)
3004         self.pg_start()
3005         p = self.pg0.get_capture(1)
3006         packet = p[0]
3007         try:
3008             self.assertEqual(packet[IP].src, server_nat_ip)
3009             self.assertEqual(packet[IP].dst, host.ip4)
3010             self.assertTrue(packet.haslayer(GRE))
3011             self.assert_packet_checksums_valid(packet)
3012         except:
3013             self.logger.error(ppp("Unexpected or invalid packet:", packet))
3014             raise
3015
3016     def test_unknown_proto(self):
3017         """ NAT44 translate packet with unknown protocol """
3018         self.nat44_add_address(self.nat_addr)
3019         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
3020         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
3021                                                   is_inside=0)
3022
3023         # in2out
3024         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
3025              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3026              TCP(sport=self.tcp_port_in, dport=20))
3027         self.pg0.add_stream(p)
3028         self.pg_enable_capture(self.pg_interfaces)
3029         self.pg_start()
3030         p = self.pg1.get_capture(1)
3031
3032         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
3033              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3034              GRE() /
3035              IP(src=self.pg2.remote_ip4, dst=self.pg3.remote_ip4) /
3036              TCP(sport=1234, dport=1234))
3037         self.pg0.add_stream(p)
3038         self.pg_enable_capture(self.pg_interfaces)
3039         self.pg_start()
3040         p = self.pg1.get_capture(1)
3041         packet = p[0]
3042         try:
3043             self.assertEqual(packet[IP].src, self.nat_addr)
3044             self.assertEqual(packet[IP].dst, self.pg1.remote_ip4)
3045             self.assertTrue(packet.haslayer(GRE))
3046             self.assert_packet_checksums_valid(packet)
3047         except:
3048             self.logger.error(ppp("Unexpected or invalid packet:", packet))
3049             raise
3050
3051         # out2in
3052         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
3053              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
3054              GRE() /
3055              IP(src=self.pg3.remote_ip4, dst=self.pg2.remote_ip4) /
3056              TCP(sport=1234, dport=1234))
3057         self.pg1.add_stream(p)
3058         self.pg_enable_capture(self.pg_interfaces)
3059         self.pg_start()
3060         p = self.pg0.get_capture(1)
3061         packet = p[0]
3062         try:
3063             self.assertEqual(packet[IP].src, self.pg1.remote_ip4)
3064             self.assertEqual(packet[IP].dst, self.pg0.remote_ip4)
3065             self.assertTrue(packet.haslayer(GRE))
3066             self.assert_packet_checksums_valid(packet)
3067         except:
3068             self.logger.error(ppp("Unexpected or invalid packet:", packet))
3069             raise
3070
3071     def test_hairpinning_unknown_proto(self):
3072         """ NAT44 translate packet with unknown protocol - hairpinning """
3073         host = self.pg0.remote_hosts[0]
3074         server = self.pg0.remote_hosts[1]
3075         host_in_port = 1234
3076         server_out_port = 8765
3077         server_nat_ip = "10.0.0.11"
3078
3079         self.nat44_add_address(self.nat_addr)
3080         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
3081         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
3082                                                   is_inside=0)
3083
3084         # add static mapping for server
3085         self.nat44_add_static_mapping(server.ip4, server_nat_ip)
3086
3087         # host to server
3088         p = (Ether(src=host.mac, dst=self.pg0.local_mac) /
3089              IP(src=host.ip4, dst=server_nat_ip) /
3090              TCP(sport=host_in_port, dport=server_out_port))
3091         self.pg0.add_stream(p)
3092         self.pg_enable_capture(self.pg_interfaces)
3093         self.pg_start()
3094         capture = self.pg0.get_capture(1)
3095
3096         p = (Ether(dst=self.pg0.local_mac, src=host.mac) /
3097              IP(src=host.ip4, dst=server_nat_ip) /
3098              GRE() /
3099              IP(src=self.pg2.remote_ip4, dst=self.pg3.remote_ip4) /
3100              TCP(sport=1234, dport=1234))
3101         self.pg0.add_stream(p)
3102         self.pg_enable_capture(self.pg_interfaces)
3103         self.pg_start()
3104         p = self.pg0.get_capture(1)
3105         packet = p[0]
3106         try:
3107             self.assertEqual(packet[IP].src, self.nat_addr)
3108             self.assertEqual(packet[IP].dst, server.ip4)
3109             self.assertTrue(packet.haslayer(GRE))
3110             self.assert_packet_checksums_valid(packet)
3111         except:
3112             self.logger.error(ppp("Unexpected or invalid packet:", packet))
3113             raise
3114
3115         # server to host
3116         p = (Ether(dst=self.pg0.local_mac, src=server.mac) /
3117              IP(src=server.ip4, dst=self.nat_addr) /
3118              GRE() /
3119              IP(src=self.pg3.remote_ip4, dst=self.pg2.remote_ip4) /
3120              TCP(sport=1234, dport=1234))
3121         self.pg0.add_stream(p)
3122         self.pg_enable_capture(self.pg_interfaces)
3123         self.pg_start()
3124         p = self.pg0.get_capture(1)
3125         packet = p[0]
3126         try:
3127             self.assertEqual(packet[IP].src, server_nat_ip)
3128             self.assertEqual(packet[IP].dst, host.ip4)
3129             self.assertTrue(packet.haslayer(GRE))
3130             self.assert_packet_checksums_valid(packet)
3131         except:
3132             self.logger.error(ppp("Unexpected or invalid packet:", packet))
3133             raise
3134
3135     def test_output_feature(self):
3136         """ NAT44 interface output feature (in2out postrouting) """
3137         self.nat44_add_address(self.nat_addr)
3138         self.vapi.nat44_interface_add_del_output_feature(self.pg0.sw_if_index)
3139         self.vapi.nat44_interface_add_del_output_feature(self.pg1.sw_if_index)
3140         self.vapi.nat44_interface_add_del_output_feature(self.pg3.sw_if_index,
3141                                                          is_inside=0)
3142
3143         # in2out
3144         pkts = self.create_stream_in(self.pg0, self.pg3)
3145         self.pg0.add_stream(pkts)
3146         self.pg_enable_capture(self.pg_interfaces)
3147         self.pg_start()
3148         capture = self.pg3.get_capture(len(pkts))
3149         self.verify_capture_out(capture)
3150
3151         # out2in
3152         pkts = self.create_stream_out(self.pg3)
3153         self.pg3.add_stream(pkts)
3154         self.pg_enable_capture(self.pg_interfaces)
3155         self.pg_start()
3156         capture = self.pg0.get_capture(len(pkts))
3157         self.verify_capture_in(capture, self.pg0)
3158
3159         # from non-NAT interface to NAT inside interface
3160         pkts = self.create_stream_in(self.pg2, self.pg0)
3161         self.pg2.add_stream(pkts)
3162         self.pg_enable_capture(self.pg_interfaces)
3163         self.pg_start()
3164         capture = self.pg0.get_capture(len(pkts))
3165         self.verify_capture_no_translation(capture, self.pg2, self.pg0)
3166
3167     def test_output_feature_vrf_aware(self):
3168         """ NAT44 interface output feature VRF aware (in2out postrouting) """
3169         nat_ip_vrf10 = "10.0.0.10"
3170         nat_ip_vrf20 = "10.0.0.20"
3171
3172         self.vapi.ip_add_del_route(dst_address=self.pg3.remote_ip4n,
3173                                    dst_address_length=32,
3174                                    next_hop_address=self.pg3.remote_ip4n,
3175                                    next_hop_sw_if_index=self.pg3.sw_if_index,
3176                                    table_id=10)
3177         self.vapi.ip_add_del_route(dst_address=self.pg3.remote_ip4n,
3178                                    dst_address_length=32,
3179                                    next_hop_address=self.pg3.remote_ip4n,
3180                                    next_hop_sw_if_index=self.pg3.sw_if_index,
3181                                    table_id=20)
3182
3183         self.nat44_add_address(nat_ip_vrf10, vrf_id=10)
3184         self.nat44_add_address(nat_ip_vrf20, vrf_id=20)
3185         self.vapi.nat44_interface_add_del_output_feature(self.pg4.sw_if_index)
3186         self.vapi.nat44_interface_add_del_output_feature(self.pg6.sw_if_index)
3187         self.vapi.nat44_interface_add_del_output_feature(self.pg3.sw_if_index,
3188                                                          is_inside=0)
3189
3190         # in2out VRF 10
3191         pkts = self.create_stream_in(self.pg4, self.pg3)
3192         self.pg4.add_stream(pkts)
3193         self.pg_enable_capture(self.pg_interfaces)
3194         self.pg_start()
3195         capture = self.pg3.get_capture(len(pkts))
3196         self.verify_capture_out(capture, nat_ip=nat_ip_vrf10)
3197
3198         # out2in VRF 10
3199         pkts = self.create_stream_out(self.pg3, dst_ip=nat_ip_vrf10)
3200         self.pg3.add_stream(pkts)
3201         self.pg_enable_capture(self.pg_interfaces)
3202         self.pg_start()
3203         capture = self.pg4.get_capture(len(pkts))
3204         self.verify_capture_in(capture, self.pg4)
3205
3206         # in2out VRF 20
3207         pkts = self.create_stream_in(self.pg6, self.pg3)
3208         self.pg6.add_stream(pkts)
3209         self.pg_enable_capture(self.pg_interfaces)
3210         self.pg_start()
3211         capture = self.pg3.get_capture(len(pkts))
3212         self.verify_capture_out(capture, nat_ip=nat_ip_vrf20)
3213
3214         # out2in VRF 20
3215         pkts = self.create_stream_out(self.pg3, dst_ip=nat_ip_vrf20)
3216         self.pg3.add_stream(pkts)
3217         self.pg_enable_capture(self.pg_interfaces)
3218         self.pg_start()
3219         capture = self.pg6.get_capture(len(pkts))
3220         self.verify_capture_in(capture, self.pg6)
3221
3222     def test_output_feature_hairpinning(self):
3223         """ NAT44 interface output feature hairpinning (in2out postrouting) """
3224         host = self.pg0.remote_hosts[0]
3225         server = self.pg0.remote_hosts[1]
3226         host_in_port = 1234
3227         host_out_port = 0
3228         server_in_port = 5678
3229         server_out_port = 8765
3230
3231         self.nat44_add_address(self.nat_addr)
3232         self.vapi.nat44_interface_add_del_output_feature(self.pg0.sw_if_index)
3233         self.vapi.nat44_interface_add_del_output_feature(self.pg1.sw_if_index,
3234                                                          is_inside=0)
3235
3236         # add static mapping for server
3237         self.nat44_add_static_mapping(server.ip4, self.nat_addr,
3238                                       server_in_port, server_out_port,
3239                                       proto=IP_PROTOS.tcp)
3240
3241         # send packet from host to server
3242         p = (Ether(src=host.mac, dst=self.pg0.local_mac) /
3243              IP(src=host.ip4, dst=self.nat_addr) /
3244              TCP(sport=host_in_port, dport=server_out_port))
3245         self.pg0.add_stream(p)
3246         self.pg_enable_capture(self.pg_interfaces)
3247         self.pg_start()
3248         capture = self.pg0.get_capture(1)
3249         p = capture[0]
3250         try:
3251             ip = p[IP]
3252             tcp = p[TCP]
3253             self.assertEqual(ip.src, self.nat_addr)
3254             self.assertEqual(ip.dst, server.ip4)
3255             self.assertNotEqual(tcp.sport, host_in_port)
3256             self.assertEqual(tcp.dport, server_in_port)
3257             self.assert_packet_checksums_valid(p)
3258             host_out_port = tcp.sport
3259         except:
3260             self.logger.error(ppp("Unexpected or invalid packet:", p))
3261             raise
3262
3263         # send reply from server to host
3264         p = (Ether(src=server.mac, dst=self.pg0.local_mac) /
3265              IP(src=server.ip4, dst=self.nat_addr) /
3266              TCP(sport=server_in_port, dport=host_out_port))
3267         self.pg0.add_stream(p)
3268         self.pg_enable_capture(self.pg_interfaces)
3269         self.pg_start()
3270         capture = self.pg0.get_capture(1)
3271         p = capture[0]
3272         try:
3273             ip = p[IP]
3274             tcp = p[TCP]
3275             self.assertEqual(ip.src, self.nat_addr)
3276             self.assertEqual(ip.dst, host.ip4)
3277             self.assertEqual(tcp.sport, server_out_port)
3278             self.assertEqual(tcp.dport, host_in_port)
3279             self.assert_packet_checksums_valid(p)
3280         except:
3281             self.logger.error(ppp("Unexpected or invalid packet:", p))
3282             raise
3283
3284     def test_output_feature_and_service(self):
3285         """ NAT44 interface output feature and services """
3286         external_addr = '1.2.3.4'
3287         external_port = 80
3288         local_port = 8080
3289
3290         self.vapi.nat44_forwarding_enable_disable(1)
3291         self.nat44_add_address(self.nat_addr)
3292         self.vapi.nat44_add_del_identity_mapping(ip=self.pg1.remote_ip4n)
3293         self.nat44_add_static_mapping(self.pg0.remote_ip4, external_addr,
3294                                       local_port, external_port,
3295                                       proto=IP_PROTOS.tcp, out2in_only=1)
3296         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
3297         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index,
3298                                                   is_inside=0)
3299         self.vapi.nat44_interface_add_del_output_feature(self.pg1.sw_if_index,
3300                                                          is_inside=0)
3301
3302         # from client to service
3303         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
3304              IP(src=self.pg1.remote_ip4, dst=external_addr) /
3305              TCP(sport=12345, dport=external_port))
3306         self.pg1.add_stream(p)
3307         self.pg_enable_capture(self.pg_interfaces)
3308         self.pg_start()
3309         capture = self.pg0.get_capture(1)
3310         p = capture[0]
3311         try:
3312             ip = p[IP]
3313             tcp = p[TCP]
3314             self.assertEqual(ip.dst, self.pg0.remote_ip4)
3315             self.assertEqual(tcp.dport, local_port)
3316             self.assert_packet_checksums_valid(p)
3317         except:
3318             self.logger.error(ppp("Unexpected or invalid packet:", p))
3319             raise
3320
3321         # from service back to client
3322         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
3323              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3324              TCP(sport=local_port, dport=12345))
3325         self.pg0.add_stream(p)
3326         self.pg_enable_capture(self.pg_interfaces)
3327         self.pg_start()
3328         capture = self.pg1.get_capture(1)
3329         p = capture[0]
3330         try:
3331             ip = p[IP]
3332             tcp = p[TCP]
3333             self.assertEqual(ip.src, external_addr)
3334             self.assertEqual(tcp.sport, external_port)
3335             self.assert_packet_checksums_valid(p)
3336         except:
3337             self.logger.error(ppp("Unexpected or invalid packet:", p))
3338             raise
3339
3340         # from local network host to external network
3341         pkts = self.create_stream_in(self.pg0, self.pg1)
3342         self.pg0.add_stream(pkts)
3343         self.pg_enable_capture(self.pg_interfaces)
3344         self.pg_start()
3345         capture = self.pg1.get_capture(len(pkts))
3346         self.verify_capture_out(capture)
3347         pkts = self.create_stream_in(self.pg0, self.pg1)
3348         self.pg0.add_stream(pkts)
3349         self.pg_enable_capture(self.pg_interfaces)
3350         self.pg_start()
3351         capture = self.pg1.get_capture(len(pkts))
3352         self.verify_capture_out(capture)
3353
3354         # from external network back to local network host
3355         pkts = self.create_stream_out(self.pg1)
3356         self.pg1.add_stream(pkts)
3357         self.pg_enable_capture(self.pg_interfaces)
3358         self.pg_start()
3359         capture = self.pg0.get_capture(len(pkts))
3360         self.verify_capture_in(capture, self.pg0)
3361
3362     def test_output_feature_and_service2(self):
3363         """ NAT44 interface output feature and service host direct access """
3364         self.vapi.nat44_forwarding_enable_disable(1)
3365         self.nat44_add_address(self.nat_addr)
3366         self.vapi.nat44_interface_add_del_output_feature(self.pg1.sw_if_index,
3367                                                          is_inside=0)
3368
3369         # session initiaded from service host - translate
3370         pkts = self.create_stream_in(self.pg0, self.pg1)
3371         self.pg0.add_stream(pkts)
3372         self.pg_enable_capture(self.pg_interfaces)
3373         self.pg_start()
3374         capture = self.pg1.get_capture(len(pkts))
3375         self.verify_capture_out(capture)
3376
3377         pkts = self.create_stream_out(self.pg1)
3378         self.pg1.add_stream(pkts)
3379         self.pg_enable_capture(self.pg_interfaces)
3380         self.pg_start()
3381         capture = self.pg0.get_capture(len(pkts))
3382         self.verify_capture_in(capture, self.pg0)
3383
3384         # session initiaded from remote host - do not translate
3385         pkts = self.create_stream_out(self.pg1,
3386                                       self.pg0.remote_ip4,
3387                                       use_inside_ports=True)
3388         self.pg1.add_stream(pkts)
3389         self.pg_enable_capture(self.pg_interfaces)
3390         self.pg_start()
3391         capture = self.pg0.get_capture(len(pkts))
3392         self.verify_capture_in(capture, self.pg0)
3393
3394         pkts = self.create_stream_in(self.pg0, self.pg1)
3395         self.pg0.add_stream(pkts)
3396         self.pg_enable_capture(self.pg_interfaces)
3397         self.pg_start()
3398         capture = self.pg1.get_capture(len(pkts))
3399         self.verify_capture_out(capture, nat_ip=self.pg0.remote_ip4,
3400                                 same_port=True)
3401
3402     def test_output_feature_and_service3(self):
3403         """ NAT44 interface output feature and DST NAT """
3404         external_addr = '1.2.3.4'
3405         external_port = 80
3406         local_port = 8080
3407
3408         self.vapi.nat44_forwarding_enable_disable(1)
3409         self.nat44_add_address(self.nat_addr)
3410         self.nat44_add_static_mapping(self.pg1.remote_ip4, external_addr,
3411                                       local_port, external_port,
3412                                       proto=IP_PROTOS.tcp, out2in_only=1)
3413         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
3414         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index,
3415                                                   is_inside=0)
3416         self.vapi.nat44_interface_add_del_output_feature(self.pg1.sw_if_index,
3417                                                          is_inside=0)
3418
3419         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
3420              IP(src=self.pg0.remote_ip4, dst=external_addr) /
3421              TCP(sport=12345, dport=external_port))
3422         self.pg0.add_stream(p)
3423         self.pg_enable_capture(self.pg_interfaces)
3424         self.pg_start()
3425         capture = self.pg1.get_capture(1)
3426         p = capture[0]
3427         try:
3428             ip = p[IP]
3429             tcp = p[TCP]
3430             self.assertEqual(ip.src, self.pg0.remote_ip4)
3431             self.assertEqual(tcp.sport, 12345)
3432             self.assertEqual(ip.dst, self.pg1.remote_ip4)
3433             self.assertEqual(tcp.dport, local_port)
3434             self.assert_packet_checksums_valid(p)
3435         except:
3436             self.logger.error(ppp("Unexpected or invalid packet:", p))
3437             raise
3438
3439         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
3440              IP(src=self.pg1.remote_ip4, dst=self.pg0.remote_ip4) /
3441              TCP(sport=local_port, dport=12345))
3442         self.pg1.add_stream(p)
3443         self.pg_enable_capture(self.pg_interfaces)
3444         self.pg_start()
3445         capture = self.pg0.get_capture(1)
3446         p = capture[0]
3447         try:
3448             ip = p[IP]
3449             tcp = p[TCP]
3450             self.assertEqual(ip.src, external_addr)
3451             self.assertEqual(tcp.sport, external_port)
3452             self.assertEqual(ip.dst, self.pg0.remote_ip4)
3453             self.assertEqual(tcp.dport, 12345)
3454             self.assert_packet_checksums_valid(p)
3455         except:
3456             self.logger.error(ppp("Unexpected or invalid packet:", p))
3457             raise
3458
3459     def test_one_armed_nat44(self):
3460         """ One armed NAT44 """
3461         remote_host = self.pg9.remote_hosts[0]
3462         local_host = self.pg9.remote_hosts[1]
3463         external_port = 0
3464
3465         self.nat44_add_address(self.nat_addr)
3466         self.vapi.nat44_interface_add_del_feature(self.pg9.sw_if_index)
3467         self.vapi.nat44_interface_add_del_feature(self.pg9.sw_if_index,
3468                                                   is_inside=0)
3469
3470         # in2out
3471         p = (Ether(src=self.pg9.remote_mac, dst=self.pg9.local_mac) /
3472              IP(src=local_host.ip4, dst=remote_host.ip4) /
3473              TCP(sport=12345, dport=80))
3474         self.pg9.add_stream(p)
3475         self.pg_enable_capture(self.pg_interfaces)
3476         self.pg_start()
3477         capture = self.pg9.get_capture(1)
3478         p = capture[0]
3479         try:
3480             ip = p[IP]
3481             tcp = p[TCP]
3482             self.assertEqual(ip.src, self.nat_addr)
3483             self.assertEqual(ip.dst, remote_host.ip4)
3484             self.assertNotEqual(tcp.sport, 12345)
3485             external_port = tcp.sport
3486             self.assertEqual(tcp.dport, 80)
3487             self.assert_packet_checksums_valid(p)
3488         except:
3489             self.logger.error(ppp("Unexpected or invalid packet:", p))
3490             raise
3491
3492         # out2in
3493         p = (Ether(src=self.pg9.remote_mac, dst=self.pg9.local_mac) /
3494              IP(src=remote_host.ip4, dst=self.nat_addr) /
3495              TCP(sport=80, dport=external_port))
3496         self.pg9.add_stream(p)
3497         self.pg_enable_capture(self.pg_interfaces)
3498         self.pg_start()
3499         capture = self.pg9.get_capture(1)
3500         p = capture[0]
3501         try:
3502             ip = p[IP]
3503             tcp = p[TCP]
3504             self.assertEqual(ip.src, remote_host.ip4)
3505             self.assertEqual(ip.dst, local_host.ip4)
3506             self.assertEqual(tcp.sport, 80)
3507             self.assertEqual(tcp.dport, 12345)
3508             self.assert_packet_checksums_valid(p)
3509         except:
3510             self.logger.error(ppp("Unexpected or invalid packet:", p))
3511             raise
3512
3513     def test_one_armed_nat44_static(self):
3514         """ One armed NAT44 and 1:1 NAPT symmetrical rule """
3515         remote_host = self.pg9.remote_hosts[0]
3516         local_host = self.pg9.remote_hosts[1]
3517         external_port = 80
3518         local_port = 8080
3519         eh_port_in = 0
3520
3521         self.vapi.nat44_forwarding_enable_disable(1)
3522         self.nat44_add_address(self.nat_addr, twice_nat=1)
3523         self.nat44_add_static_mapping(local_host.ip4, self.nat_addr,
3524                                       local_port, external_port,
3525                                       proto=IP_PROTOS.tcp, out2in_only=1,
3526                                       twice_nat=1)
3527         self.vapi.nat44_interface_add_del_feature(self.pg9.sw_if_index)
3528         self.vapi.nat44_interface_add_del_feature(self.pg9.sw_if_index,
3529                                                   is_inside=0)
3530
3531         # from client to service
3532         p = (Ether(src=self.pg9.remote_mac, dst=self.pg9.local_mac) /
3533              IP(src=remote_host.ip4, dst=self.nat_addr) /
3534              TCP(sport=12345, dport=external_port))
3535         self.pg9.add_stream(p)
3536         self.pg_enable_capture(self.pg_interfaces)
3537         self.pg_start()
3538         capture = self.pg9.get_capture(1)
3539         p = capture[0]
3540         try:
3541             ip = p[IP]
3542             tcp = p[TCP]
3543             self.assertEqual(ip.dst, local_host.ip4)
3544             self.assertEqual(ip.src, self.nat_addr)
3545             self.assertEqual(tcp.dport, local_port)
3546             self.assertNotEqual(tcp.sport, 12345)
3547             eh_port_in = tcp.sport
3548             self.assert_packet_checksums_valid(p)
3549         except:
3550             self.logger.error(ppp("Unexpected or invalid packet:", p))
3551             raise
3552
3553         # from service back to client
3554         p = (Ether(src=self.pg9.remote_mac, dst=self.pg9.local_mac) /
3555              IP(src=local_host.ip4, dst=self.nat_addr) /
3556              TCP(sport=local_port, dport=eh_port_in))
3557         self.pg9.add_stream(p)
3558         self.pg_enable_capture(self.pg_interfaces)
3559         self.pg_start()
3560         capture = self.pg9.get_capture(1)
3561         p = capture[0]
3562         try:
3563             ip = p[IP]
3564             tcp = p[TCP]
3565             self.assertEqual(ip.src, self.nat_addr)
3566             self.assertEqual(ip.dst, remote_host.ip4)
3567             self.assertEqual(tcp.sport, external_port)
3568             self.assertEqual(tcp.dport, 12345)
3569             self.assert_packet_checksums_valid(p)
3570         except:
3571             self.logger.error(ppp("Unexpected or invalid packet:", p))
3572             raise
3573
3574     def test_del_session(self):
3575         """ Delete NAT44 session """
3576         self.nat44_add_address(self.nat_addr)
3577         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
3578         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
3579                                                   is_inside=0)
3580
3581         pkts = self.create_stream_in(self.pg0, self.pg1)
3582         self.pg0.add_stream(pkts)
3583         self.pg_enable_capture(self.pg_interfaces)
3584         self.pg_start()
3585         capture = self.pg1.get_capture(len(pkts))
3586
3587         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4n, 0)
3588         nsessions = len(sessions)
3589
3590         self.vapi.nat44_del_session(sessions[0].inside_ip_address,
3591                                     sessions[0].inside_port,
3592                                     sessions[0].protocol)
3593         self.vapi.nat44_del_session(sessions[1].outside_ip_address,
3594                                     sessions[1].outside_port,
3595                                     sessions[1].protocol,
3596                                     is_in=0)
3597
3598         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4n, 0)
3599         self.assertEqual(nsessions - len(sessions), 2)
3600
3601     def test_set_get_reass(self):
3602         """ NAT44 set/get virtual fragmentation reassembly """
3603         reas_cfg1 = self.vapi.nat_get_reass()
3604
3605         self.vapi.nat_set_reass(timeout=reas_cfg1.ip4_timeout + 5,
3606                                 max_reass=reas_cfg1.ip4_max_reass * 2,
3607                                 max_frag=reas_cfg1.ip4_max_frag * 2)
3608
3609         reas_cfg2 = self.vapi.nat_get_reass()
3610
3611         self.assertEqual(reas_cfg1.ip4_timeout + 5, reas_cfg2.ip4_timeout)
3612         self.assertEqual(reas_cfg1.ip4_max_reass * 2, reas_cfg2.ip4_max_reass)
3613         self.assertEqual(reas_cfg1.ip4_max_frag * 2, reas_cfg2.ip4_max_frag)
3614
3615         self.vapi.nat_set_reass(drop_frag=1)
3616         self.assertTrue(self.vapi.nat_get_reass().ip4_drop_frag)
3617
3618     def test_frag_in_order(self):
3619         """ NAT44 translate fragments arriving in order """
3620         self.nat44_add_address(self.nat_addr)
3621         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
3622         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
3623                                                   is_inside=0)
3624
3625         data = "A" * 4 + "B" * 16 + "C" * 3
3626         self.tcp_port_in = random.randint(1025, 65535)
3627
3628         reass = self.vapi.nat_reass_dump()
3629         reass_n_start = len(reass)
3630
3631         # in2out
3632         pkts = self.create_stream_frag(self.pg0,
3633                                        self.pg1.remote_ip4,
3634                                        self.tcp_port_in,
3635                                        20,
3636                                        data)
3637         self.pg0.add_stream(pkts)
3638         self.pg_enable_capture(self.pg_interfaces)
3639         self.pg_start()
3640         frags = self.pg1.get_capture(len(pkts))
3641         p = self.reass_frags_and_verify(frags,
3642                                         self.nat_addr,
3643                                         self.pg1.remote_ip4)
3644         self.assertEqual(p[TCP].dport, 20)
3645         self.assertNotEqual(p[TCP].sport, self.tcp_port_in)
3646         self.tcp_port_out = p[TCP].sport
3647         self.assertEqual(data, p[Raw].load)
3648
3649         # out2in
3650         pkts = self.create_stream_frag(self.pg1,
3651                                        self.nat_addr,
3652                                        20,
3653                                        self.tcp_port_out,
3654                                        data)
3655         self.pg1.add_stream(pkts)
3656         self.pg_enable_capture(self.pg_interfaces)
3657         self.pg_start()
3658         frags = self.pg0.get_capture(len(pkts))
3659         p = self.reass_frags_and_verify(frags,
3660                                         self.pg1.remote_ip4,
3661                                         self.pg0.remote_ip4)
3662         self.assertEqual(p[TCP].sport, 20)
3663         self.assertEqual(p[TCP].dport, self.tcp_port_in)
3664         self.assertEqual(data, p[Raw].load)
3665
3666         reass = self.vapi.nat_reass_dump()
3667         reass_n_end = len(reass)
3668
3669         self.assertEqual(reass_n_end - reass_n_start, 2)
3670
3671     def test_reass_hairpinning(self):
3672         """ NAT44 fragments hairpinning """
3673         server = self.pg0.remote_hosts[1]
3674         host_in_port = random.randint(1025, 65535)
3675         server_in_port = random.randint(1025, 65535)
3676         server_out_port = random.randint(1025, 65535)
3677         data = "A" * 4 + "B" * 16 + "C" * 3
3678
3679         self.nat44_add_address(self.nat_addr)
3680         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
3681         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
3682                                                   is_inside=0)
3683         # add static mapping for server
3684         self.nat44_add_static_mapping(server.ip4, self.nat_addr,
3685                                       server_in_port, server_out_port,
3686                                       proto=IP_PROTOS.tcp)
3687
3688         # send packet from host to server
3689         pkts = self.create_stream_frag(self.pg0,
3690                                        self.nat_addr,
3691                                        host_in_port,
3692                                        server_out_port,
3693                                        data)
3694         self.pg0.add_stream(pkts)
3695         self.pg_enable_capture(self.pg_interfaces)
3696         self.pg_start()
3697         frags = self.pg0.get_capture(len(pkts))
3698         p = self.reass_frags_and_verify(frags,
3699                                         self.nat_addr,
3700                                         server.ip4)
3701         self.assertNotEqual(p[TCP].sport, host_in_port)
3702         self.assertEqual(p[TCP].dport, server_in_port)
3703         self.assertEqual(data, p[Raw].load)
3704
3705     def test_frag_out_of_order(self):
3706         """ NAT44 translate fragments arriving out of order """
3707         self.nat44_add_address(self.nat_addr)
3708         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
3709         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
3710                                                   is_inside=0)
3711
3712         data = "A" * 4 + "B" * 16 + "C" * 3
3713         random.randint(1025, 65535)
3714
3715         # in2out
3716         pkts = self.create_stream_frag(self.pg0,
3717                                        self.pg1.remote_ip4,
3718                                        self.tcp_port_in,
3719                                        20,
3720                                        data)
3721         pkts.reverse()
3722         self.pg0.add_stream(pkts)
3723         self.pg_enable_capture(self.pg_interfaces)
3724         self.pg_start()
3725         frags = self.pg1.get_capture(len(pkts))
3726         p = self.reass_frags_and_verify(frags,
3727                                         self.nat_addr,
3728                                         self.pg1.remote_ip4)
3729         self.assertEqual(p[TCP].dport, 20)
3730         self.assertNotEqual(p[TCP].sport, self.tcp_port_in)
3731         self.tcp_port_out = p[TCP].sport
3732         self.assertEqual(data, p[Raw].load)
3733
3734         # out2in
3735         pkts = self.create_stream_frag(self.pg1,
3736                                        self.nat_addr,
3737                                        20,
3738                                        self.tcp_port_out,
3739                                        data)
3740         pkts.reverse()
3741         self.pg1.add_stream(pkts)
3742         self.pg_enable_capture(self.pg_interfaces)
3743         self.pg_start()
3744         frags = self.pg0.get_capture(len(pkts))
3745         p = self.reass_frags_and_verify(frags,
3746                                         self.pg1.remote_ip4,
3747                                         self.pg0.remote_ip4)
3748         self.assertEqual(p[TCP].sport, 20)
3749         self.assertEqual(p[TCP].dport, self.tcp_port_in)
3750         self.assertEqual(data, p[Raw].load)
3751
3752     def test_port_restricted(self):
3753         """ Port restricted NAT44 (MAP-E CE) """
3754         self.nat44_add_address(self.nat_addr)
3755         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
3756         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
3757                                                   is_inside=0)
3758         self.vapi.cli("nat addr-port-assignment-alg map-e psid 10 "
3759                       "psid-offset 6 psid-len 6")
3760
3761         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
3762              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3763              TCP(sport=4567, dport=22))
3764         self.pg0.add_stream(p)
3765         self.pg_enable_capture(self.pg_interfaces)
3766         self.pg_start()
3767         capture = self.pg1.get_capture(1)
3768         p = capture[0]
3769         try:
3770             ip = p[IP]
3771             tcp = p[TCP]
3772             self.assertEqual(ip.dst, self.pg1.remote_ip4)
3773             self.assertEqual(ip.src, self.nat_addr)
3774             self.assertEqual(tcp.dport, 22)
3775             self.assertNotEqual(tcp.sport, 4567)
3776             self.assertEqual((tcp.sport >> 6) & 63, 10)
3777             self.assert_packet_checksums_valid(p)
3778         except:
3779             self.logger.error(ppp("Unexpected or invalid packet:", p))
3780             raise
3781
3782     def twice_nat_common(self, self_twice_nat=False, same_pg=False, lb=False,
3783                          client_id=None):
3784         twice_nat_addr = '10.0.1.3'
3785
3786         port_in = 8080
3787         if lb:
3788             if not same_pg:
3789                 port_in1 = port_in
3790                 port_in2 = port_in
3791             else:
3792                 port_in1 = port_in+1
3793                 port_in2 = port_in+2
3794
3795         port_out = 80
3796         eh_port_out = 4567
3797
3798         server1 = self.pg0.remote_hosts[0]
3799         server2 = self.pg0.remote_hosts[1]
3800         if lb and same_pg:
3801             server2 = server1
3802         if not lb:
3803             server = server1
3804
3805         pg0 = self.pg0
3806         if same_pg:
3807             pg1 = self.pg0
3808         else:
3809             pg1 = self.pg1
3810
3811         eh_translate = ((not self_twice_nat) or (not lb and same_pg) or
3812                         client_id == 1)
3813
3814         self.nat44_add_address(self.nat_addr)
3815         self.nat44_add_address(twice_nat_addr, twice_nat=1)
3816         if not lb:
3817             self.nat44_add_static_mapping(pg0.remote_ip4, self.nat_addr,
3818                                           port_in, port_out,
3819                                           proto=IP_PROTOS.tcp,
3820                                           twice_nat=int(not self_twice_nat),
3821                                           self_twice_nat=int(self_twice_nat))
3822         else:
3823             locals = [{'addr': server1.ip4n,
3824                        'port': port_in1,
3825                        'probability': 50},
3826                       {'addr': server2.ip4n,
3827                        'port': port_in2,
3828                        'probability': 50}]
3829             out_addr_n = socket.inet_pton(socket.AF_INET, self.nat_addr)
3830             self.vapi.nat44_add_del_lb_static_mapping(out_addr_n,
3831                                                       port_out,
3832                                                       IP_PROTOS.tcp,
3833                                                       twice_nat=int(
3834                                                           not self_twice_nat),
3835                                                       self_twice_nat=int(
3836                                                           self_twice_nat),
3837                                                       local_num=len(locals),
3838                                                       locals=locals)
3839         self.vapi.nat44_interface_add_del_feature(pg0.sw_if_index)
3840         self.vapi.nat44_interface_add_del_feature(pg1.sw_if_index,
3841                                                   is_inside=0)
3842
3843         if same_pg:
3844             if not lb:
3845                 client = server
3846             else:
3847                 assert client_id is not None
3848                 if client_id == 1:
3849                     client = self.pg0.remote_hosts[0]
3850                 elif client_id == 2:
3851                     client = self.pg0.remote_hosts[1]
3852         else:
3853             client = pg1.remote_hosts[0]
3854         p = (Ether(src=pg1.remote_mac, dst=pg1.local_mac) /
3855              IP(src=client.ip4, dst=self.nat_addr) /
3856              TCP(sport=eh_port_out, dport=port_out))
3857         pg1.add_stream(p)
3858         self.pg_enable_capture(self.pg_interfaces)
3859         self.pg_start()
3860         capture = pg0.get_capture(1)
3861         p = capture[0]
3862         try:
3863             ip = p[IP]
3864             tcp = p[TCP]
3865             if lb:
3866                 if ip.dst == server1.ip4:
3867                     server = server1
3868                     port_in = port_in1
3869                 else:
3870                     server = server2
3871                     port_in = port_in2
3872             self.assertEqual(ip.dst, server.ip4)
3873             if lb and same_pg:
3874                 self.assertIn(tcp.dport, [port_in1, port_in2])
3875             else:
3876                 self.assertEqual(tcp.dport, port_in)
3877             if eh_translate:
3878                 self.assertEqual(ip.src, twice_nat_addr)
3879                 self.assertNotEqual(tcp.sport, eh_port_out)
3880             else:
3881                 self.assertEqual(ip.src, client.ip4)
3882                 self.assertEqual(tcp.sport, eh_port_out)
3883             eh_addr_in = ip.src
3884             eh_port_in = tcp.sport
3885             saved_port_in = tcp.dport
3886             self.assert_packet_checksums_valid(p)
3887         except:
3888             self.logger.error(ppp("Unexpected or invalid packet:", p))
3889             raise
3890
3891         p = (Ether(src=server.mac, dst=pg0.local_mac) /
3892              IP(src=server.ip4, dst=eh_addr_in) /
3893              TCP(sport=saved_port_in, dport=eh_port_in))
3894         pg0.add_stream(p)
3895         self.pg_enable_capture(self.pg_interfaces)
3896         self.pg_start()
3897         capture = pg1.get_capture(1)
3898         p = capture[0]
3899         try:
3900             ip = p[IP]
3901             tcp = p[TCP]
3902             self.assertEqual(ip.dst, client.ip4)
3903             self.assertEqual(ip.src, self.nat_addr)
3904             self.assertEqual(tcp.dport, eh_port_out)
3905             self.assertEqual(tcp.sport, port_out)
3906             self.assert_packet_checksums_valid(p)
3907         except:
3908             self.logger.error(ppp("Unexpected or invalid packet:", p))
3909             raise
3910
3911     def test_twice_nat(self):
3912         """ Twice NAT44 """
3913         self.twice_nat_common()
3914
3915     def test_self_twice_nat_positive(self):
3916         """ Self Twice NAT44 (positive test) """
3917         self.twice_nat_common(self_twice_nat=True, same_pg=True)
3918
3919     def test_self_twice_nat_negative(self):
3920         """ Self Twice NAT44 (negative test) """
3921         self.twice_nat_common(self_twice_nat=True)
3922
3923     def test_twice_nat_lb(self):
3924         """ Twice NAT44 local service load balancing """
3925         self.twice_nat_common(lb=True)
3926
3927     def test_self_twice_nat_lb_positive(self):
3928         """ Self Twice NAT44 local service load balancing (positive test) """
3929         self.twice_nat_common(lb=True, self_twice_nat=True, same_pg=True,
3930                               client_id=1)
3931
3932     def test_self_twice_nat_lb_negative(self):
3933         """ Self Twice NAT44 local service load balancing (negative test) """
3934         self.twice_nat_common(lb=True, self_twice_nat=True, same_pg=True,
3935                               client_id=2)
3936
3937     def test_twice_nat_interface_addr(self):
3938         """ Acquire twice NAT44 addresses from interface """
3939         self.vapi.nat44_add_interface_addr(self.pg7.sw_if_index, twice_nat=1)
3940
3941         # no address in NAT pool
3942         adresses = self.vapi.nat44_address_dump()
3943         self.assertEqual(0, len(adresses))
3944
3945         # configure interface address and check NAT address pool
3946         self.pg7.config_ip4()
3947         adresses = self.vapi.nat44_address_dump()
3948         self.assertEqual(1, len(adresses))
3949         self.assertEqual(adresses[0].ip_address[0:4], self.pg7.local_ip4n)
3950         self.assertEqual(adresses[0].twice_nat, 1)
3951
3952         # remove interface address and check NAT address pool
3953         self.pg7.unconfig_ip4()
3954         adresses = self.vapi.nat44_address_dump()
3955         self.assertEqual(0, len(adresses))
3956
3957     def test_ipfix_max_frags(self):
3958         """ IPFIX logging maximum fragments pending reassembly exceeded """
3959         self.nat44_add_address(self.nat_addr)
3960         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
3961         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
3962                                                   is_inside=0)
3963         self.vapi.nat_set_reass(max_frag=0)
3964         self.vapi.set_ipfix_exporter(collector_address=self.pg3.remote_ip4n,
3965                                      src_address=self.pg3.local_ip4n,
3966                                      path_mtu=512,
3967                                      template_interval=10)
3968         self.vapi.nat_ipfix(domain_id=self.ipfix_domain_id,
3969                             src_port=self.ipfix_src_port)
3970
3971         data = "A" * 4 + "B" * 16 + "C" * 3
3972         self.tcp_port_in = random.randint(1025, 65535)
3973         pkts = self.create_stream_frag(self.pg0,
3974                                        self.pg1.remote_ip4,
3975                                        self.tcp_port_in,
3976                                        20,
3977                                        data)
3978         self.pg0.add_stream(pkts[-1])
3979         self.pg_enable_capture(self.pg_interfaces)
3980         self.pg_start()
3981         frags = self.pg1.get_capture(0)
3982         self.vapi.cli("ipfix flush")  # FIXME this should be an API call
3983         capture = self.pg3.get_capture(9)
3984         ipfix = IPFIXDecoder()
3985         # first load template
3986         for p in capture:
3987             self.assertTrue(p.haslayer(IPFIX))
3988             self.assertEqual(p[IP].src, self.pg3.local_ip4)
3989             self.assertEqual(p[IP].dst, self.pg3.remote_ip4)
3990             self.assertEqual(p[UDP].sport, self.ipfix_src_port)
3991             self.assertEqual(p[UDP].dport, 4739)
3992             self.assertEqual(p[IPFIX].observationDomainID,
3993                              self.ipfix_domain_id)
3994             if p.haslayer(Template):
3995                 ipfix.add_template(p.getlayer(Template))
3996         # verify events in data set
3997         for p in capture:
3998             if p.haslayer(Data):
3999                 data = ipfix.decode_data_set(p.getlayer(Set))
4000                 self.verify_ipfix_max_fragments_ip4(data, 0,
4001                                                     self.pg0.remote_ip4n)
4002
4003     def test_tcp_session_close_in(self):
4004         """ Close TCP session from inside network """
4005         self.nat44_add_address(self.nat_addr)
4006         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
4007         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
4008                                                   is_inside=0)
4009
4010         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4n, 0)
4011         start_sessnum = len(sessions)
4012
4013         self.initiate_tcp_session(self.pg0, self.pg1)
4014
4015         # close the session from inside
4016         try:
4017             # FIN packet in -> out
4018             p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
4019                  IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
4020                  TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
4021                      flags="FA"))
4022             self.pg0.add_stream(p)
4023             self.pg_enable_capture(self.pg_interfaces)
4024             self.pg_start()
4025             self.pg1.get_capture(1)
4026
4027             pkts = []
4028
4029             # ACK packet out -> in
4030             p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
4031                  IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
4032                  TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
4033                      flags="A"))
4034             pkts.append(p)
4035
4036             # FIN packet out -> in
4037             p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
4038                  IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
4039                  TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
4040                      flags="FA"))
4041             pkts.append(p)
4042
4043             self.pg1.add_stream(pkts)
4044             self.pg_enable_capture(self.pg_interfaces)
4045             self.pg_start()
4046             self.pg0.get_capture(2)
4047
4048             # ACK packet in -> out
4049             p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
4050                  IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
4051                  TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
4052                      flags="A"))
4053             self.pg0.add_stream(p)
4054             self.pg_enable_capture(self.pg_interfaces)
4055             self.pg_start()
4056             self.pg1.get_capture(1)
4057
4058             self.initiate_tcp_session(self.pg0, self.pg1)
4059             sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4n,
4060                                                          0)
4061             self.assertEqual(len(sessions) - start_sessnum, 1)
4062         except:
4063             self.logger.error("TCP session termination failed")
4064             raise
4065
4066     def test_tcp_session_close_out(self):
4067         """ Close TCP session from outside network """
4068         self.nat44_add_address(self.nat_addr)
4069         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
4070         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
4071                                                   is_inside=0)
4072
4073         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4n, 0)
4074         start_sessnum = len(sessions)
4075
4076         self.initiate_tcp_session(self.pg0, self.pg1)
4077
4078         # close the session from outside
4079         try:
4080             # FIN packet out -> in
4081             p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
4082                  IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
4083                  TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
4084                      flags="FA"))
4085             self.pg1.add_stream(p)
4086             self.pg_enable_capture(self.pg_interfaces)
4087             self.pg_start()
4088             self.pg0.get_capture(1)
4089
4090             pkts = []
4091
4092             # ACK packet in -> out
4093             p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
4094                  IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
4095                  TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
4096                      flags="A"))
4097             pkts.append(p)
4098
4099             # ACK packet in -> out
4100             p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
4101                  IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
4102                  TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
4103                      flags="FA"))
4104             pkts.append(p)
4105
4106             self.pg0.add_stream(pkts)
4107             self.pg_enable_capture(self.pg_interfaces)
4108             self.pg_start()
4109             self.pg1.get_capture(2)
4110
4111             # ACK packet out -> in
4112             p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
4113                  IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
4114                  TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
4115                      flags="A"))
4116             self.pg1.add_stream(p)
4117             self.pg_enable_capture(self.pg_interfaces)
4118             self.pg_start()
4119             self.pg0.get_capture(1)
4120
4121             self.initiate_tcp_session(self.pg0, self.pg1)
4122             sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4n,
4123                                                          0)
4124             self.assertEqual(len(sessions) - start_sessnum, 1)
4125         except:
4126             self.logger.error("TCP session termination failed")
4127             raise
4128
4129     def test_tcp_session_close_simultaneous(self):
4130         """ Close TCP session from inside network """
4131         self.nat44_add_address(self.nat_addr)
4132         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
4133         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
4134                                                   is_inside=0)
4135
4136         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4n, 0)
4137         start_sessnum = len(sessions)
4138
4139         self.initiate_tcp_session(self.pg0, self.pg1)
4140
4141         # close the session from inside
4142         try:
4143             # FIN packet in -> out
4144             p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
4145                  IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
4146                  TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
4147                      flags="FA"))
4148             self.pg0.add_stream(p)
4149             self.pg_enable_capture(self.pg_interfaces)
4150             self.pg_start()
4151             self.pg1.get_capture(1)
4152
4153             # FIN packet out -> in
4154             p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
4155                  IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
4156                  TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
4157                      flags="FA"))
4158             self.pg1.add_stream(p)
4159             self.pg_enable_capture(self.pg_interfaces)
4160             self.pg_start()
4161             self.pg0.get_capture(1)
4162
4163             # ACK packet in -> out
4164             p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
4165                  IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
4166                  TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
4167                      flags="A"))
4168             self.pg0.add_stream(p)
4169             self.pg_enable_capture(self.pg_interfaces)
4170             self.pg_start()
4171             self.pg1.get_capture(1)
4172
4173             # ACK packet out -> in
4174             p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
4175                  IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
4176                  TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
4177                      flags="A"))
4178             self.pg1.add_stream(p)
4179             self.pg_enable_capture(self.pg_interfaces)
4180             self.pg_start()
4181             self.pg0.get_capture(1)
4182
4183             self.initiate_tcp_session(self.pg0, self.pg1)
4184             sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4n,
4185                                                          0)
4186             self.assertEqual(len(sessions) - start_sessnum, 1)
4187         except:
4188             self.logger.error("TCP session termination failed")
4189             raise
4190
4191     def tearDown(self):
4192         super(TestNAT44, self).tearDown()
4193         if not self.vpp_dead:
4194             self.logger.info(self.vapi.cli("show nat44 addresses"))
4195             self.logger.info(self.vapi.cli("show nat44 interfaces"))
4196             self.logger.info(self.vapi.cli("show nat44 static mappings"))
4197             self.logger.info(self.vapi.cli("show nat44 interface address"))
4198             self.logger.info(self.vapi.cli("show nat44 sessions detail"))
4199             self.logger.info(self.vapi.cli("show nat virtual-reassembly"))
4200             self.vapi.cli("nat addr-port-assignment-alg default")
4201             self.clear_nat44()
4202
4203
4204 class TestNAT44Out2InDPO(MethodHolder):
4205     """ NAT44 Test Cases using out2in DPO """
4206
4207     @classmethod
4208     def setUpConstants(cls):
4209         super(TestNAT44Out2InDPO, cls).setUpConstants()
4210         cls.vpp_cmdline.extend(["nat", "{", "out2in dpo", "}"])
4211
4212     @classmethod
4213     def setUpClass(cls):
4214         super(TestNAT44Out2InDPO, cls).setUpClass()
4215
4216         try:
4217             cls.tcp_port_in = 6303
4218             cls.tcp_port_out = 6303
4219             cls.udp_port_in = 6304
4220             cls.udp_port_out = 6304
4221             cls.icmp_id_in = 6305
4222             cls.icmp_id_out = 6305
4223             cls.nat_addr = '10.0.0.3'
4224             cls.nat_addr_n = socket.inet_pton(socket.AF_INET, cls.nat_addr)
4225             cls.dst_ip4 = '192.168.70.1'
4226
4227             cls.create_pg_interfaces(range(2))
4228
4229             cls.pg0.admin_up()
4230             cls.pg0.config_ip4()
4231             cls.pg0.resolve_arp()
4232
4233             cls.pg1.admin_up()
4234             cls.pg1.config_ip6()
4235             cls.pg1.resolve_ndp()
4236
4237             cls.vapi.ip_add_del_route(is_ipv6=True, dst_address='\x00'*16,
4238                                       dst_address_length=0,
4239                                       next_hop_address=cls.pg1.remote_ip6n,
4240                                       next_hop_sw_if_index=cls.pg1.sw_if_index)
4241
4242         except Exception:
4243             super(TestNAT44Out2InDPO, cls).tearDownClass()
4244             raise
4245
4246     def configure_xlat(self):
4247         self.dst_ip6_pfx = '1:2:3::'
4248         self.dst_ip6_pfx_n = socket.inet_pton(socket.AF_INET6,
4249                                               self.dst_ip6_pfx)
4250         self.dst_ip6_pfx_len = 96
4251         self.src_ip6_pfx = '4:5:6::'
4252         self.src_ip6_pfx_n = socket.inet_pton(socket.AF_INET6,
4253                                               self.src_ip6_pfx)
4254         self.src_ip6_pfx_len = 96
4255         self.vapi.map_add_domain(self.dst_ip6_pfx_n, self.dst_ip6_pfx_len,
4256                                  self.src_ip6_pfx_n, self.src_ip6_pfx_len,
4257                                  '\x00\x00\x00\x00', 0, is_translation=1,
4258                                  is_rfc6052=1)
4259
4260     def test_464xlat_ce(self):
4261         """ Test 464XLAT CE with NAT44 """
4262
4263         self.configure_xlat()
4264
4265         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
4266         self.vapi.nat44_add_del_address_range(self.nat_addr_n, self.nat_addr_n)
4267
4268         out_src_ip6 = self.compose_ip6(self.dst_ip4, self.dst_ip6_pfx,
4269                                        self.dst_ip6_pfx_len)
4270         out_dst_ip6 = self.compose_ip6(self.nat_addr, self.src_ip6_pfx,
4271                                        self.src_ip6_pfx_len)
4272
4273         try:
4274             pkts = self.create_stream_in(self.pg0, self.pg1, self.dst_ip4)
4275             self.pg0.add_stream(pkts)
4276             self.pg_enable_capture(self.pg_interfaces)
4277             self.pg_start()
4278             capture = self.pg1.get_capture(len(pkts))
4279             self.verify_capture_out_ip6(capture, nat_ip=out_dst_ip6,
4280                                         dst_ip=out_src_ip6)
4281
4282             pkts = self.create_stream_out_ip6(self.pg1, out_src_ip6,
4283                                               out_dst_ip6)
4284             self.pg1.add_stream(pkts)
4285             self.pg_enable_capture(self.pg_interfaces)
4286             self.pg_start()
4287             capture = self.pg0.get_capture(len(pkts))
4288             self.verify_capture_in(capture, self.pg0)
4289         finally:
4290             self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index,
4291                                                       is_add=0)
4292             self.vapi.nat44_add_del_address_range(self.nat_addr_n,
4293                                                   self.nat_addr_n, is_add=0)
4294
4295     def test_464xlat_ce_no_nat(self):
4296         """ Test 464XLAT CE without NAT44 """
4297
4298         self.configure_xlat()
4299
4300         out_src_ip6 = self.compose_ip6(self.dst_ip4, self.dst_ip6_pfx,
4301                                        self.dst_ip6_pfx_len)
4302         out_dst_ip6 = self.compose_ip6(self.pg0.remote_ip4, self.src_ip6_pfx,
4303                                        self.src_ip6_pfx_len)
4304
4305         pkts = self.create_stream_in(self.pg0, self.pg1, self.dst_ip4)
4306         self.pg0.add_stream(pkts)
4307         self.pg_enable_capture(self.pg_interfaces)
4308         self.pg_start()
4309         capture = self.pg1.get_capture(len(pkts))
4310         self.verify_capture_out_ip6(capture, dst_ip=out_src_ip6,
4311                                     nat_ip=out_dst_ip6, same_port=True)
4312
4313         pkts = self.create_stream_out_ip6(self.pg1, out_src_ip6, out_dst_ip6)
4314         self.pg1.add_stream(pkts)
4315         self.pg_enable_capture(self.pg_interfaces)
4316         self.pg_start()
4317         capture = self.pg0.get_capture(len(pkts))
4318         self.verify_capture_in(capture, self.pg0)
4319
4320
4321 class TestDeterministicNAT(MethodHolder):
4322     """ Deterministic NAT Test Cases """
4323
4324     @classmethod
4325     def setUpConstants(cls):
4326         super(TestDeterministicNAT, cls).setUpConstants()
4327         cls.vpp_cmdline.extend(["nat", "{", "deterministic", "}"])
4328
4329     @classmethod
4330     def setUpClass(cls):
4331         super(TestDeterministicNAT, cls).setUpClass()
4332
4333         try:
4334             cls.tcp_port_in = 6303
4335             cls.tcp_external_port = 6303
4336             cls.udp_port_in = 6304
4337             cls.udp_external_port = 6304
4338             cls.icmp_id_in = 6305
4339             cls.nat_addr = '10.0.0.3'
4340
4341             cls.create_pg_interfaces(range(3))
4342             cls.interfaces = list(cls.pg_interfaces)
4343
4344             for i in cls.interfaces:
4345                 i.admin_up()
4346                 i.config_ip4()
4347                 i.resolve_arp()
4348
4349             cls.pg0.generate_remote_hosts(2)
4350             cls.pg0.configure_ipv4_neighbors()
4351
4352         except Exception:
4353             super(TestDeterministicNAT, cls).tearDownClass()
4354             raise
4355
4356     def create_stream_in(self, in_if, out_if, ttl=64):
4357         """
4358         Create packet stream for inside network
4359
4360         :param in_if: Inside interface
4361         :param out_if: Outside interface
4362         :param ttl: TTL of generated packets
4363         """
4364         pkts = []
4365         # TCP
4366         p = (Ether(dst=in_if.local_mac, src=in_if.remote_mac) /
4367              IP(src=in_if.remote_ip4, dst=out_if.remote_ip4, ttl=ttl) /
4368              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port))
4369         pkts.append(p)
4370
4371         # UDP
4372         p = (Ether(dst=in_if.local_mac, src=in_if.remote_mac) /
4373              IP(src=in_if.remote_ip4, dst=out_if.remote_ip4, ttl=ttl) /
4374              UDP(sport=self.udp_port_in, dport=self.udp_external_port))
4375         pkts.append(p)
4376
4377         # ICMP
4378         p = (Ether(dst=in_if.local_mac, src=in_if.remote_mac) /
4379              IP(src=in_if.remote_ip4, dst=out_if.remote_ip4, ttl=ttl) /
4380              ICMP(id=self.icmp_id_in, type='echo-request'))
4381         pkts.append(p)
4382
4383         return pkts
4384
4385     def create_stream_out(self, out_if, dst_ip=None, ttl=64):
4386         """
4387         Create packet stream for outside network
4388
4389         :param out_if: Outside interface
4390         :param dst_ip: Destination IP address (Default use global NAT address)
4391         :param ttl: TTL of generated packets
4392         """
4393         if dst_ip is None:
4394             dst_ip = self.nat_addr
4395         pkts = []
4396         # TCP
4397         p = (Ether(dst=out_if.local_mac, src=out_if.remote_mac) /
4398              IP(src=out_if.remote_ip4, dst=dst_ip, ttl=ttl) /
4399              TCP(dport=self.tcp_port_out, sport=self.tcp_external_port))
4400         pkts.append(p)
4401
4402         # UDP
4403         p = (Ether(dst=out_if.local_mac, src=out_if.remote_mac) /
4404              IP(src=out_if.remote_ip4, dst=dst_ip, ttl=ttl) /
4405              UDP(dport=self.udp_port_out, sport=self.udp_external_port))
4406         pkts.append(p)
4407
4408         # ICMP
4409         p = (Ether(dst=out_if.local_mac, src=out_if.remote_mac) /
4410              IP(src=out_if.remote_ip4, dst=dst_ip, ttl=ttl) /
4411              ICMP(id=self.icmp_external_id, type='echo-reply'))
4412         pkts.append(p)
4413
4414         return pkts
4415
4416     def verify_capture_out(self, capture, nat_ip=None, packet_num=3):
4417         """
4418         Verify captured packets on outside network
4419
4420         :param capture: Captured packets
4421         :param nat_ip: Translated IP address (Default use global NAT address)
4422         :param same_port: Sorce port number is not translated (Default False)
4423         :param packet_num: Expected number of packets (Default 3)
4424         """
4425         if nat_ip is None:
4426             nat_ip = self.nat_addr
4427         self.assertEqual(packet_num, len(capture))
4428         for packet in capture:
4429             try:
4430                 self.assertEqual(packet[IP].src, nat_ip)
4431                 if packet.haslayer(TCP):
4432                     self.tcp_port_out = packet[TCP].sport
4433                 elif packet.haslayer(UDP):
4434                     self.udp_port_out = packet[UDP].sport
4435                 else:
4436                     self.icmp_external_id = packet[ICMP].id
4437             except:
4438                 self.logger.error(ppp("Unexpected or invalid packet "
4439                                       "(outside network):", packet))
4440                 raise
4441
4442     def verify_ipfix_max_entries_per_user(self, data):
4443         """
4444         Verify IPFIX maximum entries per user exceeded event
4445
4446         :param data: Decoded IPFIX data records
4447         """
4448         self.assertEqual(1, len(data))
4449         record = data[0]
4450         # natEvent
4451         self.assertEqual(ord(record[230]), 13)
4452         # natQuotaExceededEvent
4453         self.assertEqual('\x03\x00\x00\x00', record[466])
4454         # maxEntriesPerUser
4455         self.assertEqual('\xe8\x03\x00\x00', record[473])
4456         # sourceIPv4Address
4457         self.assertEqual(self.pg0.remote_ip4n, record[8])
4458
4459     def test_deterministic_mode(self):
4460         """ NAT plugin run deterministic mode """
4461         in_addr = '172.16.255.0'
4462         out_addr = '172.17.255.50'
4463         in_addr_t = '172.16.255.20'
4464         in_addr_n = socket.inet_aton(in_addr)
4465         out_addr_n = socket.inet_aton(out_addr)
4466         in_addr_t_n = socket.inet_aton(in_addr_t)
4467         in_plen = 24
4468         out_plen = 32
4469
4470         nat_config = self.vapi.nat_show_config()
4471         self.assertEqual(1, nat_config.deterministic)
4472
4473         self.vapi.nat_det_add_del_map(in_addr_n, in_plen, out_addr_n, out_plen)
4474
4475         rep1 = self.vapi.nat_det_forward(in_addr_t_n)
4476         self.assertEqual(rep1.out_addr[:4], out_addr_n)
4477         rep2 = self.vapi.nat_det_reverse(out_addr_n, rep1.out_port_hi)
4478         self.assertEqual(rep2.in_addr[:4], in_addr_t_n)
4479
4480         deterministic_mappings = self.vapi.nat_det_map_dump()
4481         self.assertEqual(len(deterministic_mappings), 1)
4482         dsm = deterministic_mappings[0]
4483         self.assertEqual(in_addr_n, dsm.in_addr[:4])
4484         self.assertEqual(in_plen, dsm.in_plen)
4485         self.assertEqual(out_addr_n, dsm.out_addr[:4])
4486         self.assertEqual(out_plen, dsm.out_plen)
4487
4488         self.clear_nat_det()
4489         deterministic_mappings = self.vapi.nat_det_map_dump()
4490         self.assertEqual(len(deterministic_mappings), 0)
4491
4492     def test_set_timeouts(self):
4493         """ Set deterministic NAT timeouts """
4494         timeouts_before = self.vapi.nat_det_get_timeouts()
4495
4496         self.vapi.nat_det_set_timeouts(timeouts_before.udp + 10,
4497                                        timeouts_before.tcp_established + 10,
4498                                        timeouts_before.tcp_transitory + 10,
4499                                        timeouts_before.icmp + 10)
4500
4501         timeouts_after = self.vapi.nat_det_get_timeouts()
4502
4503         self.assertNotEqual(timeouts_before.udp, timeouts_after.udp)
4504         self.assertNotEqual(timeouts_before.icmp, timeouts_after.icmp)
4505         self.assertNotEqual(timeouts_before.tcp_established,
4506                             timeouts_after.tcp_established)
4507         self.assertNotEqual(timeouts_before.tcp_transitory,
4508                             timeouts_after.tcp_transitory)
4509
4510     def test_det_in(self):
4511         """ Deterministic NAT translation test (TCP, UDP, ICMP) """
4512
4513         nat_ip = "10.0.0.10"
4514
4515         self.vapi.nat_det_add_del_map(self.pg0.remote_ip4n,
4516                                       32,
4517                                       socket.inet_aton(nat_ip),
4518                                       32)
4519         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
4520         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
4521                                                   is_inside=0)
4522
4523         # in2out
4524         pkts = self.create_stream_in(self.pg0, self.pg1)
4525         self.pg0.add_stream(pkts)
4526         self.pg_enable_capture(self.pg_interfaces)
4527         self.pg_start()
4528         capture = self.pg1.get_capture(len(pkts))
4529         self.verify_capture_out(capture, nat_ip)
4530
4531         # out2in
4532         pkts = self.create_stream_out(self.pg1, nat_ip)
4533         self.pg1.add_stream(pkts)
4534         self.pg_enable_capture(self.pg_interfaces)
4535         self.pg_start()
4536         capture = self.pg0.get_capture(len(pkts))
4537         self.verify_capture_in(capture, self.pg0)
4538
4539         # session dump test
4540         sessions = self.vapi.nat_det_session_dump(self.pg0.remote_ip4n)
4541         self.assertEqual(len(sessions), 3)
4542
4543         # TCP session
4544         s = sessions[0]
4545         self.assertEqual(s.ext_addr[:4], self.pg1.remote_ip4n)
4546         self.assertEqual(s.in_port, self.tcp_port_in)
4547         self.assertEqual(s.out_port, self.tcp_port_out)
4548         self.assertEqual(s.ext_port, self.tcp_external_port)
4549
4550         # UDP session
4551         s = sessions[1]
4552         self.assertEqual(s.ext_addr[:4], self.pg1.remote_ip4n)
4553         self.assertEqual(s.in_port, self.udp_port_in)
4554         self.assertEqual(s.out_port, self.udp_port_out)
4555         self.assertEqual(s.ext_port, self.udp_external_port)
4556
4557         # ICMP session
4558         s = sessions[2]
4559         self.assertEqual(s.ext_addr[:4], self.pg1.remote_ip4n)
4560         self.assertEqual(s.in_port, self.icmp_id_in)
4561         self.assertEqual(s.out_port, self.icmp_external_id)
4562
4563     def test_multiple_users(self):
4564         """ Deterministic NAT multiple users """
4565
4566         nat_ip = "10.0.0.10"
4567         port_in = 80
4568         external_port = 6303
4569
4570         host0 = self.pg0.remote_hosts[0]
4571         host1 = self.pg0.remote_hosts[1]
4572
4573         self.vapi.nat_det_add_del_map(host0.ip4n,
4574                                       24,
4575                                       socket.inet_aton(nat_ip),
4576                                       32)
4577         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
4578         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
4579                                                   is_inside=0)
4580
4581         # host0 to out
4582         p = (Ether(src=host0.mac, dst=self.pg0.local_mac) /
4583              IP(src=host0.ip4, dst=self.pg1.remote_ip4) /
4584              TCP(sport=port_in, dport=external_port))
4585         self.pg0.add_stream(p)
4586         self.pg_enable_capture(self.pg_interfaces)
4587         self.pg_start()
4588         capture = self.pg1.get_capture(1)
4589         p = capture[0]
4590         try:
4591             ip = p[IP]
4592             tcp = p[TCP]
4593             self.assertEqual(ip.src, nat_ip)
4594             self.assertEqual(ip.dst, self.pg1.remote_ip4)
4595             self.assertEqual(tcp.dport, external_port)
4596             port_out0 = tcp.sport
4597         except:
4598             self.logger.error(ppp("Unexpected or invalid packet:", p))
4599             raise
4600
4601         # host1 to out
4602         p = (Ether(src=host1.mac, dst=self.pg0.local_mac) /
4603              IP(src=host1.ip4, dst=self.pg1.remote_ip4) /
4604              TCP(sport=port_in, dport=external_port))
4605         self.pg0.add_stream(p)
4606         self.pg_enable_capture(self.pg_interfaces)
4607         self.pg_start()
4608         capture = self.pg1.get_capture(1)
4609         p = capture[0]
4610         try:
4611             ip = p[IP]
4612             tcp = p[TCP]
4613             self.assertEqual(ip.src, nat_ip)
4614             self.assertEqual(ip.dst, self.pg1.remote_ip4)
4615             self.assertEqual(tcp.dport, external_port)
4616             port_out1 = tcp.sport
4617         except:
4618             self.logger.error(ppp("Unexpected or invalid packet:", p))
4619             raise
4620
4621         dms = self.vapi.nat_det_map_dump()
4622         self.assertEqual(1, len(dms))
4623         self.assertEqual(2, dms[0].ses_num)
4624
4625         # out to host0
4626         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
4627              IP(src=self.pg1.remote_ip4, dst=nat_ip) /
4628              TCP(sport=external_port, dport=port_out0))
4629         self.pg1.add_stream(p)
4630         self.pg_enable_capture(self.pg_interfaces)
4631         self.pg_start()
4632         capture = self.pg0.get_capture(1)
4633         p = capture[0]
4634         try:
4635             ip = p[IP]
4636             tcp = p[TCP]
4637             self.assertEqual(ip.src, self.pg1.remote_ip4)
4638             self.assertEqual(ip.dst, host0.ip4)
4639             self.assertEqual(tcp.dport, port_in)
4640             self.assertEqual(tcp.sport, external_port)
4641         except:
4642             self.logger.error(ppp("Unexpected or invalid packet:", p))
4643             raise
4644
4645         # out to host1
4646         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
4647              IP(src=self.pg1.remote_ip4, dst=nat_ip) /
4648              TCP(sport=external_port, dport=port_out1))
4649         self.pg1.add_stream(p)
4650         self.pg_enable_capture(self.pg_interfaces)
4651         self.pg_start()
4652         capture = self.pg0.get_capture(1)
4653         p = capture[0]
4654         try:
4655             ip = p[IP]
4656             tcp = p[TCP]
4657             self.assertEqual(ip.src, self.pg1.remote_ip4)
4658             self.assertEqual(ip.dst, host1.ip4)
4659             self.assertEqual(tcp.dport, port_in)
4660             self.assertEqual(tcp.sport, external_port)
4661         except:
4662             self.logger.error(ppp("Unexpected or invalid packet", p))
4663             raise
4664
4665         # session close api test
4666         self.vapi.nat_det_close_session_out(socket.inet_aton(nat_ip),
4667                                             port_out1,
4668                                             self.pg1.remote_ip4n,
4669                                             external_port)
4670         dms = self.vapi.nat_det_map_dump()
4671         self.assertEqual(dms[0].ses_num, 1)
4672
4673         self.vapi.nat_det_close_session_in(host0.ip4n,
4674                                            port_in,
4675                                            self.pg1.remote_ip4n,
4676                                            external_port)
4677         dms = self.vapi.nat_det_map_dump()
4678         self.assertEqual(dms[0].ses_num, 0)
4679
4680     def test_tcp_session_close_detection_in(self):
4681         """ Deterministic NAT TCP session close from inside network """
4682         self.vapi.nat_det_add_del_map(self.pg0.remote_ip4n,
4683                                       32,
4684                                       socket.inet_aton(self.nat_addr),
4685                                       32)
4686         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
4687         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
4688                                                   is_inside=0)
4689
4690         self.initiate_tcp_session(self.pg0, self.pg1)
4691
4692         # close the session from inside
4693         try:
4694             # FIN packet in -> out
4695             p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
4696                  IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
4697                  TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
4698                      flags="F"))
4699             self.pg0.add_stream(p)
4700             self.pg_enable_capture(self.pg_interfaces)
4701             self.pg_start()
4702             self.pg1.get_capture(1)
4703
4704             pkts = []
4705
4706             # ACK packet out -> in
4707             p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
4708                  IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
4709                  TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
4710                      flags="A"))
4711             pkts.append(p)
4712
4713             # FIN packet out -> in
4714             p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
4715                  IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
4716                  TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
4717                      flags="F"))
4718             pkts.append(p)
4719
4720             self.pg1.add_stream(pkts)
4721             self.pg_enable_capture(self.pg_interfaces)
4722             self.pg_start()
4723             self.pg0.get_capture(2)
4724
4725             # ACK packet in -> out
4726             p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
4727                  IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
4728                  TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
4729                      flags="A"))
4730             self.pg0.add_stream(p)
4731             self.pg_enable_capture(self.pg_interfaces)
4732             self.pg_start()
4733             self.pg1.get_capture(1)
4734
4735             # Check if deterministic NAT44 closed the session
4736             dms = self.vapi.nat_det_map_dump()
4737             self.assertEqual(0, dms[0].ses_num)
4738         except:
4739             self.logger.error("TCP session termination failed")
4740             raise
4741
4742     def test_tcp_session_close_detection_out(self):
4743         """ Deterministic NAT TCP session close from outside network """
4744         self.vapi.nat_det_add_del_map(self.pg0.remote_ip4n,
4745                                       32,
4746                                       socket.inet_aton(self.nat_addr),
4747                                       32)
4748         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
4749         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
4750                                                   is_inside=0)
4751
4752         self.initiate_tcp_session(self.pg0, self.pg1)
4753
4754         # close the session from outside
4755         try:
4756             # FIN packet out -> in
4757             p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
4758                  IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
4759                  TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
4760                      flags="F"))
4761             self.pg1.add_stream(p)
4762             self.pg_enable_capture(self.pg_interfaces)
4763             self.pg_start()
4764             self.pg0.get_capture(1)
4765
4766             pkts = []
4767
4768             # ACK packet in -> out
4769             p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
4770                  IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
4771                  TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
4772                      flags="A"))
4773             pkts.append(p)
4774
4775             # ACK packet in -> out
4776             p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
4777                  IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
4778                  TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
4779                      flags="F"))
4780             pkts.append(p)
4781
4782             self.pg0.add_stream(pkts)
4783             self.pg_enable_capture(self.pg_interfaces)
4784             self.pg_start()
4785             self.pg1.get_capture(2)
4786
4787             # ACK packet out -> in
4788             p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
4789                  IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
4790                  TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
4791                      flags="A"))
4792             self.pg1.add_stream(p)
4793             self.pg_enable_capture(self.pg_interfaces)
4794             self.pg_start()
4795             self.pg0.get_capture(1)
4796
4797             # Check if deterministic NAT44 closed the session
4798             dms = self.vapi.nat_det_map_dump()
4799             self.assertEqual(0, dms[0].ses_num)
4800         except:
4801             self.logger.error("TCP session termination failed")
4802             raise
4803
4804     @unittest.skipUnless(running_extended_tests(), "part of extended tests")
4805     def test_session_timeout(self):
4806         """ Deterministic NAT session timeouts """
4807         self.vapi.nat_det_add_del_map(self.pg0.remote_ip4n,
4808                                       32,
4809                                       socket.inet_aton(self.nat_addr),
4810                                       32)
4811         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
4812         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
4813                                                   is_inside=0)
4814
4815         self.initiate_tcp_session(self.pg0, self.pg1)
4816         self.vapi.nat_det_set_timeouts(5, 5, 5, 5)
4817         pkts = self.create_stream_in(self.pg0, self.pg1)
4818         self.pg0.add_stream(pkts)
4819         self.pg_enable_capture(self.pg_interfaces)
4820         self.pg_start()
4821         capture = self.pg1.get_capture(len(pkts))
4822         sleep(15)
4823
4824         dms = self.vapi.nat_det_map_dump()
4825         self.assertEqual(0, dms[0].ses_num)
4826
4827     @unittest.skipUnless(running_extended_tests(), "part of extended tests")
4828     def test_session_limit_per_user(self):
4829         """ Deterministic NAT maximum sessions per user limit """
4830         self.vapi.nat_det_add_del_map(self.pg0.remote_ip4n,
4831                                       32,
4832                                       socket.inet_aton(self.nat_addr),
4833                                       32)
4834         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
4835         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
4836                                                   is_inside=0)
4837         self.vapi.set_ipfix_exporter(collector_address=self.pg2.remote_ip4n,
4838                                      src_address=self.pg2.local_ip4n,
4839                                      path_mtu=512,
4840                                      template_interval=10)
4841         self.vapi.nat_ipfix()
4842
4843         pkts = []
4844         for port in range(1025, 2025):
4845             p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
4846                  IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
4847                  UDP(sport=port, dport=port))
4848             pkts.append(p)
4849
4850         self.pg0.add_stream(pkts)
4851         self.pg_enable_capture(self.pg_interfaces)
4852         self.pg_start()
4853         capture = self.pg1.get_capture(len(pkts))
4854
4855         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
4856              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
4857              UDP(sport=3001, dport=3002))
4858         self.pg0.add_stream(p)
4859         self.pg_enable_capture(self.pg_interfaces)
4860         self.pg_start()
4861         capture = self.pg1.assert_nothing_captured()
4862
4863         # verify ICMP error packet
4864         capture = self.pg0.get_capture(1)
4865         p = capture[0]
4866         self.assertTrue(p.haslayer(ICMP))
4867         icmp = p[ICMP]
4868         self.assertEqual(icmp.type, 3)
4869         self.assertEqual(icmp.code, 1)
4870         self.assertTrue(icmp.haslayer(IPerror))
4871         inner_ip = icmp[IPerror]
4872         self.assertEqual(inner_ip[UDPerror].sport, 3001)
4873         self.assertEqual(inner_ip[UDPerror].dport, 3002)
4874
4875         dms = self.vapi.nat_det_map_dump()
4876
4877         self.assertEqual(1000, dms[0].ses_num)
4878
4879         # verify IPFIX logging
4880         self.vapi.cli("ipfix flush")  # FIXME this should be an API call
4881         sleep(1)
4882         capture = self.pg2.get_capture(2)
4883         ipfix = IPFIXDecoder()
4884         # first load template
4885         for p in capture:
4886             self.assertTrue(p.haslayer(IPFIX))
4887             if p.haslayer(Template):
4888                 ipfix.add_template(p.getlayer(Template))
4889         # verify events in data set
4890         for p in capture:
4891             if p.haslayer(Data):
4892                 data = ipfix.decode_data_set(p.getlayer(Set))
4893                 self.verify_ipfix_max_entries_per_user(data)
4894
4895     def clear_nat_det(self):
4896         """
4897         Clear deterministic NAT configuration.
4898         """
4899         self.vapi.nat_ipfix(enable=0)
4900         self.vapi.nat_det_set_timeouts()
4901         deterministic_mappings = self.vapi.nat_det_map_dump()
4902         for dsm in deterministic_mappings:
4903             self.vapi.nat_det_add_del_map(dsm.in_addr,
4904                                           dsm.in_plen,
4905                                           dsm.out_addr,
4906                                           dsm.out_plen,
4907                                           is_add=0)
4908
4909         interfaces = self.vapi.nat44_interface_dump()
4910         for intf in interfaces:
4911             self.vapi.nat44_interface_add_del_feature(intf.sw_if_index,
4912                                                       intf.is_inside,
4913                                                       is_add=0)
4914
4915     def tearDown(self):
4916         super(TestDeterministicNAT, self).tearDown()
4917         if not self.vpp_dead:
4918             self.logger.info(self.vapi.cli("show nat44 interfaces"))
4919             self.logger.info(
4920                 self.vapi.cli("show nat44 deterministic mappings"))
4921             self.logger.info(
4922                 self.vapi.cli("show nat44 deterministic timeouts"))
4923             self.logger.info(
4924                 self.vapi.cli("show nat44 deterministic sessions"))
4925             self.clear_nat_det()
4926
4927
4928 class TestNAT64(MethodHolder):
4929     """ NAT64 Test Cases """
4930
4931     @classmethod
4932     def setUpConstants(cls):
4933         super(TestNAT64, cls).setUpConstants()
4934         cls.vpp_cmdline.extend(["nat", "{", "nat64 bib hash buckets 128",
4935                                 "nat64 st hash buckets 256", "}"])
4936
4937     @classmethod
4938     def setUpClass(cls):
4939         super(TestNAT64, cls).setUpClass()
4940
4941         try:
4942             cls.tcp_port_in = 6303
4943             cls.tcp_port_out = 6303
4944             cls.udp_port_in = 6304
4945             cls.udp_port_out = 6304
4946             cls.icmp_id_in = 6305
4947             cls.icmp_id_out = 6305
4948             cls.nat_addr = '10.0.0.3'
4949             cls.nat_addr_n = socket.inet_pton(socket.AF_INET, cls.nat_addr)
4950             cls.vrf1_id = 10
4951             cls.vrf1_nat_addr = '10.0.10.3'
4952             cls.vrf1_nat_addr_n = socket.inet_pton(socket.AF_INET,
4953                                                    cls.vrf1_nat_addr)
4954             cls.ipfix_src_port = 4739
4955             cls.ipfix_domain_id = 1
4956
4957             cls.create_pg_interfaces(range(5))
4958             cls.ip6_interfaces = list(cls.pg_interfaces[0:1])
4959             cls.ip6_interfaces.append(cls.pg_interfaces[2])
4960             cls.ip4_interfaces = list(cls.pg_interfaces[1:2])
4961
4962             cls.vapi.ip_table_add_del(cls.vrf1_id, is_add=1, is_ipv6=1)
4963
4964             cls.pg_interfaces[2].set_table_ip6(cls.vrf1_id)
4965
4966             cls.pg0.generate_remote_hosts(2)
4967
4968             for i in cls.ip6_interfaces:
4969                 i.admin_up()
4970                 i.config_ip6()
4971                 i.configure_ipv6_neighbors()
4972
4973             for i in cls.ip4_interfaces:
4974                 i.admin_up()
4975                 i.config_ip4()
4976                 i.resolve_arp()
4977
4978             cls.pg3.admin_up()
4979             cls.pg3.config_ip4()
4980             cls.pg3.resolve_arp()
4981             cls.pg3.config_ip6()
4982             cls.pg3.configure_ipv6_neighbors()
4983
4984         except Exception:
4985             super(TestNAT64, cls).tearDownClass()
4986             raise
4987
4988     def test_pool(self):
4989         """ Add/delete address to NAT64 pool """
4990         nat_addr = socket.inet_pton(socket.AF_INET, '1.2.3.4')
4991
4992         self.vapi.nat64_add_del_pool_addr_range(nat_addr, nat_addr)
4993
4994         addresses = self.vapi.nat64_pool_addr_dump()
4995         self.assertEqual(len(addresses), 1)
4996         self.assertEqual(addresses[0].address, nat_addr)
4997
4998         self.vapi.nat64_add_del_pool_addr_range(nat_addr, nat_addr, is_add=0)
4999
5000         addresses = self.vapi.nat64_pool_addr_dump()
5001         self.assertEqual(len(addresses), 0)
5002
5003     def test_interface(self):
5004         """ Enable/disable NAT64 feature on the interface """
5005         self.vapi.nat64_add_del_interface(self.pg0.sw_if_index)
5006         self.vapi.nat64_add_del_interface(self.pg1.sw_if_index, is_inside=0)
5007
5008         interfaces = self.vapi.nat64_interface_dump()
5009         self.assertEqual(len(interfaces), 2)
5010         pg0_found = False
5011         pg1_found = False
5012         for intf in interfaces:
5013             if intf.sw_if_index == self.pg0.sw_if_index:
5014                 self.assertEqual(intf.is_inside, 1)
5015                 pg0_found = True
5016             elif intf.sw_if_index == self.pg1.sw_if_index:
5017                 self.assertEqual(intf.is_inside, 0)
5018                 pg1_found = True
5019         self.assertTrue(pg0_found)
5020         self.assertTrue(pg1_found)
5021
5022         features = self.vapi.cli("show interface features pg0")
5023         self.assertNotEqual(features.find('nat64-in2out'), -1)
5024         features = self.vapi.cli("show interface features pg1")
5025         self.assertNotEqual(features.find('nat64-out2in'), -1)
5026
5027         self.vapi.nat64_add_del_interface(self.pg0.sw_if_index, is_add=0)
5028         self.vapi.nat64_add_del_interface(self.pg1.sw_if_index, is_add=0)
5029
5030         interfaces = self.vapi.nat64_interface_dump()
5031         self.assertEqual(len(interfaces), 0)
5032
5033     def test_static_bib(self):
5034         """ Add/delete static BIB entry """
5035         in_addr = socket.inet_pton(socket.AF_INET6,
5036                                    '2001:db8:85a3::8a2e:370:7334')
5037         out_addr = socket.inet_pton(socket.AF_INET, '10.1.1.3')
5038         in_port = 1234
5039         out_port = 5678
5040         proto = IP_PROTOS.tcp
5041
5042         self.vapi.nat64_add_del_static_bib(in_addr,
5043                                            out_addr,
5044                                            in_port,
5045                                            out_port,
5046                                            proto)
5047         bib = self.vapi.nat64_bib_dump(IP_PROTOS.tcp)
5048         static_bib_num = 0
5049         for bibe in bib:
5050             if bibe.is_static:
5051                 static_bib_num += 1
5052                 self.assertEqual(bibe.i_addr, in_addr)
5053                 self.assertEqual(bibe.o_addr, out_addr)
5054                 self.assertEqual(bibe.i_port, in_port)
5055                 self.assertEqual(bibe.o_port, out_port)
5056         self.assertEqual(static_bib_num, 1)
5057
5058         self.vapi.nat64_add_del_static_bib(in_addr,
5059                                            out_addr,
5060                                            in_port,
5061                                            out_port,
5062                                            proto,
5063                                            is_add=0)
5064         bib = self.vapi.nat64_bib_dump(IP_PROTOS.tcp)
5065         static_bib_num = 0
5066         for bibe in bib:
5067             if bibe.is_static:
5068                 static_bib_num += 1
5069         self.assertEqual(static_bib_num, 0)
5070
5071     def test_set_timeouts(self):
5072         """ Set NAT64 timeouts """
5073         # verify default values
5074         timeouts = self.vapi.nat64_get_timeouts()
5075         self.assertEqual(timeouts.udp, 300)
5076         self.assertEqual(timeouts.icmp, 60)
5077         self.assertEqual(timeouts.tcp_trans, 240)
5078         self.assertEqual(timeouts.tcp_est, 7440)
5079         self.assertEqual(timeouts.tcp_incoming_syn, 6)
5080
5081         # set and verify custom values
5082         self.vapi.nat64_set_timeouts(udp=200, icmp=30, tcp_trans=250,
5083                                      tcp_est=7450, tcp_incoming_syn=10)
5084         timeouts = self.vapi.nat64_get_timeouts()
5085         self.assertEqual(timeouts.udp, 200)
5086         self.assertEqual(timeouts.icmp, 30)
5087         self.assertEqual(timeouts.tcp_trans, 250)
5088         self.assertEqual(timeouts.tcp_est, 7450)
5089         self.assertEqual(timeouts.tcp_incoming_syn, 10)
5090
5091     def test_dynamic(self):
5092         """ NAT64 dynamic translation test """
5093         self.tcp_port_in = 6303
5094         self.udp_port_in = 6304
5095         self.icmp_id_in = 6305
5096
5097         ses_num_start = self.nat64_get_ses_num()
5098
5099         self.vapi.nat64_add_del_pool_addr_range(self.nat_addr_n,
5100                                                 self.nat_addr_n)
5101         self.vapi.nat64_add_del_interface(self.pg0.sw_if_index)
5102         self.vapi.nat64_add_del_interface(self.pg1.sw_if_index, is_inside=0)
5103
5104         # in2out
5105         pkts = self.create_stream_in_ip6(self.pg0, self.pg1)
5106         self.pg0.add_stream(pkts)
5107         self.pg_enable_capture(self.pg_interfaces)
5108         self.pg_start()
5109         capture = self.pg1.get_capture(len(pkts))
5110         self.verify_capture_out(capture, nat_ip=self.nat_addr,
5111                                 dst_ip=self.pg1.remote_ip4)
5112
5113         # out2in
5114         pkts = self.create_stream_out(self.pg1, dst_ip=self.nat_addr)
5115         self.pg1.add_stream(pkts)
5116         self.pg_enable_capture(self.pg_interfaces)
5117         self.pg_start()
5118         capture = self.pg0.get_capture(len(pkts))
5119         ip = IPv6(src=''.join(['64:ff9b::', self.pg1.remote_ip4]))
5120         self.verify_capture_in_ip6(capture, ip[IPv6].src, self.pg0.remote_ip6)
5121
5122         # in2out
5123         pkts = self.create_stream_in_ip6(self.pg0, self.pg1)
5124         self.pg0.add_stream(pkts)
5125         self.pg_enable_capture(self.pg_interfaces)
5126         self.pg_start()
5127         capture = self.pg1.get_capture(len(pkts))
5128         self.verify_capture_out(capture, nat_ip=self.nat_addr,
5129                                 dst_ip=self.pg1.remote_ip4)
5130
5131         # out2in
5132         pkts = self.create_stream_out(self.pg1, dst_ip=self.nat_addr)
5133         self.pg1.add_stream(pkts)
5134         self.pg_enable_capture(self.pg_interfaces)
5135         self.pg_start()
5136         capture = self.pg0.get_capture(len(pkts))
5137         self.verify_capture_in_ip6(capture, ip[IPv6].src, self.pg0.remote_ip6)
5138
5139         ses_num_end = self.nat64_get_ses_num()
5140
5141         self.assertEqual(ses_num_end - ses_num_start, 3)
5142
5143         # tenant with specific VRF
5144         self.vapi.nat64_add_del_pool_addr_range(self.vrf1_nat_addr_n,
5145                                                 self.vrf1_nat_addr_n,
5146                                                 vrf_id=self.vrf1_id)
5147         self.vapi.nat64_add_del_interface(self.pg2.sw_if_index)
5148
5149         pkts = self.create_stream_in_ip6(self.pg2, self.pg1)
5150         self.pg2.add_stream(pkts)
5151         self.pg_enable_capture(self.pg_interfaces)
5152         self.pg_start()
5153         capture = self.pg1.get_capture(len(pkts))
5154         self.verify_capture_out(capture, nat_ip=self.vrf1_nat_addr,
5155                                 dst_ip=self.pg1.remote_ip4)
5156
5157         pkts = self.create_stream_out(self.pg1, dst_ip=self.vrf1_nat_addr)
5158         self.pg1.add_stream(pkts)
5159         self.pg_enable_capture(self.pg_interfaces)
5160         self.pg_start()
5161         capture = self.pg2.get_capture(len(pkts))
5162         self.verify_capture_in_ip6(capture, ip[IPv6].src, self.pg2.remote_ip6)
5163
5164     def test_static(self):
5165         """ NAT64 static translation test """
5166         self.tcp_port_in = 60303
5167         self.udp_port_in = 60304
5168         self.icmp_id_in = 60305
5169         self.tcp_port_out = 60303
5170         self.udp_port_out = 60304
5171         self.icmp_id_out = 60305
5172
5173         ses_num_start = self.nat64_get_ses_num()
5174
5175         self.vapi.nat64_add_del_pool_addr_range(self.nat_addr_n,
5176                                                 self.nat_addr_n)
5177         self.vapi.nat64_add_del_interface(self.pg0.sw_if_index)
5178         self.vapi.nat64_add_del_interface(self.pg1.sw_if_index, is_inside=0)
5179
5180         self.vapi.nat64_add_del_static_bib(self.pg0.remote_ip6n,
5181                                            self.nat_addr_n,
5182                                            self.tcp_port_in,
5183                                            self.tcp_port_out,
5184                                            IP_PROTOS.tcp)
5185         self.vapi.nat64_add_del_static_bib(self.pg0.remote_ip6n,
5186                                            self.nat_addr_n,
5187                                            self.udp_port_in,
5188                                            self.udp_port_out,
5189                                            IP_PROTOS.udp)
5190         self.vapi.nat64_add_del_static_bib(self.pg0.remote_ip6n,
5191                                            self.nat_addr_n,
5192                                            self.icmp_id_in,
5193                                            self.icmp_id_out,
5194                                            IP_PROTOS.icmp)
5195
5196         # in2out
5197         pkts = self.create_stream_in_ip6(self.pg0, self.pg1)
5198         self.pg0.add_stream(pkts)
5199         self.pg_enable_capture(self.pg_interfaces)
5200         self.pg_start()
5201         capture = self.pg1.get_capture(len(pkts))
5202         self.verify_capture_out(capture, nat_ip=self.nat_addr,
5203                                 dst_ip=self.pg1.remote_ip4, same_port=True)
5204
5205         # out2in
5206         pkts = self.create_stream_out(self.pg1, dst_ip=self.nat_addr)
5207         self.pg1.add_stream(pkts)
5208         self.pg_enable_capture(self.pg_interfaces)
5209         self.pg_start()
5210         capture = self.pg0.get_capture(len(pkts))
5211         ip = IPv6(src=''.join(['64:ff9b::', self.pg1.remote_ip4]))
5212         self.verify_capture_in_ip6(capture, ip[IPv6].src, self.pg0.remote_ip6)
5213
5214         ses_num_end = self.nat64_get_ses_num()
5215
5216         self.assertEqual(ses_num_end - ses_num_start, 3)
5217
5218     @unittest.skipUnless(running_extended_tests(), "part of extended tests")
5219     def test_session_timeout(self):
5220         """ NAT64 session timeout """
5221         self.icmp_id_in = 1234
5222         self.vapi.nat64_add_del_pool_addr_range(self.nat_addr_n,
5223                                                 self.nat_addr_n)
5224         self.vapi.nat64_add_del_interface(self.pg0.sw_if_index)
5225         self.vapi.nat64_add_del_interface(self.pg1.sw_if_index, is_inside=0)
5226         self.vapi.nat64_set_timeouts(icmp=5)
5227
5228         pkts = self.create_stream_in_ip6(self.pg0, self.pg1)
5229         self.pg0.add_stream(pkts)
5230         self.pg_enable_capture(self.pg_interfaces)
5231         self.pg_start()
5232         capture = self.pg1.get_capture(len(pkts))
5233
5234         ses_num_before_timeout = self.nat64_get_ses_num()
5235
5236         sleep(15)
5237
5238         # ICMP session after timeout
5239         ses_num_after_timeout = self.nat64_get_ses_num()
5240         self.assertNotEqual(ses_num_before_timeout, ses_num_after_timeout)
5241
5242     def test_icmp_error(self):
5243         """ NAT64 ICMP Error message translation """
5244         self.tcp_port_in = 6303
5245         self.udp_port_in = 6304
5246         self.icmp_id_in = 6305
5247
5248         self.vapi.nat64_add_del_pool_addr_range(self.nat_addr_n,
5249                                                 self.nat_addr_n)
5250         self.vapi.nat64_add_del_interface(self.pg0.sw_if_index)
5251         self.vapi.nat64_add_del_interface(self.pg1.sw_if_index, is_inside=0)
5252
5253         # send some packets to create sessions
5254         pkts = self.create_stream_in_ip6(self.pg0, self.pg1)
5255         self.pg0.add_stream(pkts)
5256         self.pg_enable_capture(self.pg_interfaces)
5257         self.pg_start()
5258         capture_ip4 = self.pg1.get_capture(len(pkts))
5259         self.verify_capture_out(capture_ip4,
5260                                 nat_ip=self.nat_addr,
5261                                 dst_ip=self.pg1.remote_ip4)
5262
5263         pkts = self.create_stream_out(self.pg1, dst_ip=self.nat_addr)
5264         self.pg1.add_stream(pkts)
5265         self.pg_enable_capture(self.pg_interfaces)
5266         self.pg_start()
5267         capture_ip6 = self.pg0.get_capture(len(pkts))
5268         ip = IPv6(src=''.join(['64:ff9b::', self.pg1.remote_ip4]))
5269         self.verify_capture_in_ip6(capture_ip6, ip[IPv6].src,
5270                                    self.pg0.remote_ip6)
5271
5272         # in2out
5273         pkts = [Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
5274                 IPv6(src=self.pg0.remote_ip6, dst=ip[IPv6].src) /
5275                 ICMPv6DestUnreach(code=1) /
5276                 packet[IPv6] for packet in capture_ip6]
5277         self.pg0.add_stream(pkts)
5278         self.pg_enable_capture(self.pg_interfaces)
5279         self.pg_start()
5280         capture = self.pg1.get_capture(len(pkts))
5281         for packet in capture:
5282             try:
5283                 self.assertEqual(packet[IP].src, self.nat_addr)
5284                 self.assertEqual(packet[IP].dst, self.pg1.remote_ip4)
5285                 self.assertEqual(packet[ICMP].type, 3)
5286                 self.assertEqual(packet[ICMP].code, 13)
5287                 inner = packet[IPerror]
5288                 self.assertEqual(inner.src, self.pg1.remote_ip4)
5289                 self.assertEqual(inner.dst, self.nat_addr)
5290                 self.assert_packet_checksums_valid(packet)
5291                 if inner.haslayer(TCPerror):
5292                     self.assertEqual(inner[TCPerror].dport, self.tcp_port_out)
5293                 elif inner.haslayer(UDPerror):
5294                     self.assertEqual(inner[UDPerror].dport, self.udp_port_out)
5295                 else:
5296                     self.assertEqual(inner[ICMPerror].id, self.icmp_id_out)
5297             except:
5298                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
5299                 raise
5300
5301         # out2in
5302         pkts = [Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
5303                 IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
5304                 ICMP(type=3, code=13) /
5305                 packet[IP] for packet in capture_ip4]
5306         self.pg1.add_stream(pkts)
5307         self.pg_enable_capture(self.pg_interfaces)
5308         self.pg_start()
5309         capture = self.pg0.get_capture(len(pkts))
5310         for packet in capture:
5311             try:
5312                 self.assertEqual(packet[IPv6].src, ip.src)
5313                 self.assertEqual(packet[IPv6].dst, self.pg0.remote_ip6)
5314                 icmp = packet[ICMPv6DestUnreach]
5315                 self.assertEqual(icmp.code, 1)
5316                 inner = icmp[IPerror6]
5317                 self.assertEqual(inner.src, self.pg0.remote_ip6)
5318                 self.assertEqual(inner.dst, ip.src)
5319                 self.assert_icmpv6_checksum_valid(packet)
5320                 if inner.haslayer(TCPerror):
5321                     self.assertEqual(inner[TCPerror].sport, self.tcp_port_in)
5322                 elif inner.haslayer(UDPerror):
5323                     self.assertEqual(inner[UDPerror].sport, self.udp_port_in)
5324                 else:
5325                     self.assertEqual(inner[ICMPv6EchoRequest].id,
5326                                      self.icmp_id_in)
5327             except:
5328                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
5329                 raise
5330
5331     def test_hairpinning(self):
5332         """ NAT64 hairpinning """
5333
5334         client = self.pg0.remote_hosts[0]
5335         server = self.pg0.remote_hosts[1]
5336         server_tcp_in_port = 22
5337         server_tcp_out_port = 4022
5338         server_udp_in_port = 23
5339         server_udp_out_port = 4023
5340         client_tcp_in_port = 1234
5341         client_udp_in_port = 1235
5342         client_tcp_out_port = 0
5343         client_udp_out_port = 0
5344         ip = IPv6(src=''.join(['64:ff9b::', self.nat_addr]))
5345         nat_addr_ip6 = ip.src
5346
5347         self.vapi.nat64_add_del_pool_addr_range(self.nat_addr_n,
5348                                                 self.nat_addr_n)
5349         self.vapi.nat64_add_del_interface(self.pg0.sw_if_index)
5350         self.vapi.nat64_add_del_interface(self.pg1.sw_if_index, is_inside=0)
5351
5352         self.vapi.nat64_add_del_static_bib(server.ip6n,
5353                                            self.nat_addr_n,
5354                                            server_tcp_in_port,
5355                                            server_tcp_out_port,
5356                                            IP_PROTOS.tcp)
5357         self.vapi.nat64_add_del_static_bib(server.ip6n,
5358                                            self.nat_addr_n,
5359                                            server_udp_in_port,
5360                                            server_udp_out_port,
5361                                            IP_PROTOS.udp)
5362
5363         # client to server
5364         pkts = []
5365         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
5366              IPv6(src=client.ip6, dst=nat_addr_ip6) /
5367              TCP(sport=client_tcp_in_port, dport=server_tcp_out_port))
5368         pkts.append(p)
5369         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
5370              IPv6(src=client.ip6, dst=nat_addr_ip6) /
5371              UDP(sport=client_udp_in_port, dport=server_udp_out_port))
5372         pkts.append(p)
5373         self.pg0.add_stream(pkts)
5374         self.pg_enable_capture(self.pg_interfaces)
5375         self.pg_start()
5376         capture = self.pg0.get_capture(len(pkts))
5377         for packet in capture:
5378             try:
5379                 self.assertEqual(packet[IPv6].src, nat_addr_ip6)
5380                 self.assertEqual(packet[IPv6].dst, server.ip6)
5381                 self.assert_packet_checksums_valid(packet)
5382                 if packet.haslayer(TCP):
5383                     self.assertNotEqual(packet[TCP].sport, client_tcp_in_port)
5384                     self.assertEqual(packet[TCP].dport, server_tcp_in_port)
5385                     client_tcp_out_port = packet[TCP].sport
5386                 else:
5387                     self.assertNotEqual(packet[UDP].sport, client_udp_in_port)
5388                     self.assertEqual(packet[UDP].dport, server_udp_in_port)
5389                     client_udp_out_port = packet[UDP].sport
5390             except:
5391                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
5392                 raise
5393
5394         # server to client
5395         pkts = []
5396         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
5397              IPv6(src=server.ip6, dst=nat_addr_ip6) /
5398              TCP(sport=server_tcp_in_port, dport=client_tcp_out_port))
5399         pkts.append(p)
5400         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
5401              IPv6(src=server.ip6, dst=nat_addr_ip6) /
5402              UDP(sport=server_udp_in_port, dport=client_udp_out_port))
5403         pkts.append(p)
5404         self.pg0.add_stream(pkts)
5405         self.pg_enable_capture(self.pg_interfaces)
5406         self.pg_start()
5407         capture = self.pg0.get_capture(len(pkts))
5408         for packet in capture:
5409             try:
5410                 self.assertEqual(packet[IPv6].src, nat_addr_ip6)
5411                 self.assertEqual(packet[IPv6].dst, client.ip6)
5412                 self.assert_packet_checksums_valid(packet)
5413                 if packet.haslayer(TCP):
5414                     self.assertEqual(packet[TCP].sport, server_tcp_out_port)
5415                     self.assertEqual(packet[TCP].dport, client_tcp_in_port)
5416                 else:
5417                     self.assertEqual(packet[UDP].sport, server_udp_out_port)
5418                     self.assertEqual(packet[UDP].dport, client_udp_in_port)
5419             except:
5420                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
5421                 raise
5422
5423         # ICMP error
5424         pkts = []
5425         pkts = [Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
5426                 IPv6(src=client.ip6, dst=nat_addr_ip6) /
5427                 ICMPv6DestUnreach(code=1) /
5428                 packet[IPv6] for packet in capture]
5429         self.pg0.add_stream(pkts)
5430         self.pg_enable_capture(self.pg_interfaces)
5431         self.pg_start()
5432         capture = self.pg0.get_capture(len(pkts))
5433         for packet in capture:
5434             try:
5435                 self.assertEqual(packet[IPv6].src, nat_addr_ip6)
5436                 self.assertEqual(packet[IPv6].dst, server.ip6)
5437                 icmp = packet[ICMPv6DestUnreach]
5438                 self.assertEqual(icmp.code, 1)
5439                 inner = icmp[IPerror6]
5440                 self.assertEqual(inner.src, server.ip6)
5441                 self.assertEqual(inner.dst, nat_addr_ip6)
5442                 self.assert_packet_checksums_valid(packet)
5443                 if inner.haslayer(TCPerror):
5444                     self.assertEqual(inner[TCPerror].sport, server_tcp_in_port)
5445                     self.assertEqual(inner[TCPerror].dport,
5446                                      client_tcp_out_port)
5447                 else:
5448                     self.assertEqual(inner[UDPerror].sport, server_udp_in_port)
5449                     self.assertEqual(inner[UDPerror].dport,
5450                                      client_udp_out_port)
5451             except:
5452                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
5453                 raise
5454
5455     def test_prefix(self):
5456         """ NAT64 Network-Specific Prefix """
5457
5458         self.vapi.nat64_add_del_pool_addr_range(self.nat_addr_n,
5459                                                 self.nat_addr_n)
5460         self.vapi.nat64_add_del_interface(self.pg0.sw_if_index)
5461         self.vapi.nat64_add_del_interface(self.pg1.sw_if_index, is_inside=0)
5462         self.vapi.nat64_add_del_pool_addr_range(self.vrf1_nat_addr_n,
5463                                                 self.vrf1_nat_addr_n,
5464                                                 vrf_id=self.vrf1_id)
5465         self.vapi.nat64_add_del_interface(self.pg2.sw_if_index)
5466
5467         # Add global prefix
5468         global_pref64 = "2001:db8::"
5469         global_pref64_n = socket.inet_pton(socket.AF_INET6, global_pref64)
5470         global_pref64_len = 32
5471         self.vapi.nat64_add_del_prefix(global_pref64_n, global_pref64_len)
5472
5473         prefix = self.vapi.nat64_prefix_dump()
5474         self.assertEqual(len(prefix), 1)
5475         self.assertEqual(prefix[0].prefix, global_pref64_n)
5476         self.assertEqual(prefix[0].prefix_len, global_pref64_len)
5477         self.assertEqual(prefix[0].vrf_id, 0)
5478
5479         # Add tenant specific prefix
5480         vrf1_pref64 = "2001:db8:122:300::"
5481         vrf1_pref64_n = socket.inet_pton(socket.AF_INET6, vrf1_pref64)
5482         vrf1_pref64_len = 56
5483         self.vapi.nat64_add_del_prefix(vrf1_pref64_n,
5484                                        vrf1_pref64_len,
5485                                        vrf_id=self.vrf1_id)
5486         prefix = self.vapi.nat64_prefix_dump()
5487         self.assertEqual(len(prefix), 2)
5488
5489         # Global prefix
5490         pkts = self.create_stream_in_ip6(self.pg0,
5491                                          self.pg1,
5492                                          pref=global_pref64,
5493                                          plen=global_pref64_len)
5494         self.pg0.add_stream(pkts)
5495         self.pg_enable_capture(self.pg_interfaces)
5496         self.pg_start()
5497         capture = self.pg1.get_capture(len(pkts))
5498         self.verify_capture_out(capture, nat_ip=self.nat_addr,
5499                                 dst_ip=self.pg1.remote_ip4)
5500
5501         pkts = self.create_stream_out(self.pg1, dst_ip=self.nat_addr)
5502         self.pg1.add_stream(pkts)
5503         self.pg_enable_capture(self.pg_interfaces)
5504         self.pg_start()
5505         capture = self.pg0.get_capture(len(pkts))
5506         dst_ip = self.compose_ip6(self.pg1.remote_ip4,
5507                                   global_pref64,
5508                                   global_pref64_len)
5509         self.verify_capture_in_ip6(capture, dst_ip, self.pg0.remote_ip6)
5510
5511         # Tenant specific prefix
5512         pkts = self.create_stream_in_ip6(self.pg2,
5513                                          self.pg1,
5514                                          pref=vrf1_pref64,
5515                                          plen=vrf1_pref64_len)
5516         self.pg2.add_stream(pkts)
5517         self.pg_enable_capture(self.pg_interfaces)
5518         self.pg_start()
5519         capture = self.pg1.get_capture(len(pkts))
5520         self.verify_capture_out(capture, nat_ip=self.vrf1_nat_addr,
5521                                 dst_ip=self.pg1.remote_ip4)
5522
5523         pkts = self.create_stream_out(self.pg1, dst_ip=self.vrf1_nat_addr)
5524         self.pg1.add_stream(pkts)
5525         self.pg_enable_capture(self.pg_interfaces)
5526         self.pg_start()
5527         capture = self.pg2.get_capture(len(pkts))
5528         dst_ip = self.compose_ip6(self.pg1.remote_ip4,
5529                                   vrf1_pref64,
5530                                   vrf1_pref64_len)
5531         self.verify_capture_in_ip6(capture, dst_ip, self.pg2.remote_ip6)
5532
5533     def test_unknown_proto(self):
5534         """ NAT64 translate packet with unknown protocol """
5535
5536         self.vapi.nat64_add_del_pool_addr_range(self.nat_addr_n,
5537                                                 self.nat_addr_n)
5538         self.vapi.nat64_add_del_interface(self.pg0.sw_if_index)
5539         self.vapi.nat64_add_del_interface(self.pg1.sw_if_index, is_inside=0)
5540         remote_ip6 = self.compose_ip6(self.pg1.remote_ip4, '64:ff9b::', 96)
5541
5542         # in2out
5543         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
5544              IPv6(src=self.pg0.remote_ip6, dst=remote_ip6) /
5545              TCP(sport=self.tcp_port_in, dport=20))
5546         self.pg0.add_stream(p)
5547         self.pg_enable_capture(self.pg_interfaces)
5548         self.pg_start()
5549         p = self.pg1.get_capture(1)
5550
5551         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
5552              IPv6(src=self.pg0.remote_ip6, dst=remote_ip6, nh=47) /
5553              GRE() /
5554              IP(src=self.pg2.local_ip4, dst=self.pg2.remote_ip4) /
5555              TCP(sport=1234, dport=1234))
5556         self.pg0.add_stream(p)
5557         self.pg_enable_capture(self.pg_interfaces)
5558         self.pg_start()
5559         p = self.pg1.get_capture(1)
5560         packet = p[0]
5561         try:
5562             self.assertEqual(packet[IP].src, self.nat_addr)
5563             self.assertEqual(packet[IP].dst, self.pg1.remote_ip4)
5564             self.assertTrue(packet.haslayer(GRE))
5565             self.assert_packet_checksums_valid(packet)
5566         except:
5567             self.logger.error(ppp("Unexpected or invalid packet:", packet))
5568             raise
5569
5570         # out2in
5571         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
5572              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
5573              GRE() /
5574              IP(src=self.pg2.remote_ip4, dst=self.pg2.local_ip4) /
5575              TCP(sport=1234, dport=1234))
5576         self.pg1.add_stream(p)
5577         self.pg_enable_capture(self.pg_interfaces)
5578         self.pg_start()
5579         p = self.pg0.get_capture(1)
5580         packet = p[0]
5581         try:
5582             self.assertEqual(packet[IPv6].src, remote_ip6)
5583             self.assertEqual(packet[IPv6].dst, self.pg0.remote_ip6)
5584             self.assertEqual(packet[IPv6].nh, 47)
5585         except:
5586             self.logger.error(ppp("Unexpected or invalid packet:", packet))
5587             raise
5588
5589     def test_hairpinning_unknown_proto(self):
5590         """ NAT64 translate packet with unknown protocol - hairpinning """
5591
5592         client = self.pg0.remote_hosts[0]
5593         server = self.pg0.remote_hosts[1]
5594         server_tcp_in_port = 22
5595         server_tcp_out_port = 4022
5596         client_tcp_in_port = 1234
5597         client_tcp_out_port = 1235
5598         server_nat_ip = "10.0.0.100"
5599         client_nat_ip = "10.0.0.110"
5600         server_nat_ip_n = socket.inet_pton(socket.AF_INET, server_nat_ip)
5601         client_nat_ip_n = socket.inet_pton(socket.AF_INET, client_nat_ip)
5602         server_nat_ip6 = self.compose_ip6(server_nat_ip, '64:ff9b::', 96)
5603         client_nat_ip6 = self.compose_ip6(client_nat_ip, '64:ff9b::', 96)
5604
5605         self.vapi.nat64_add_del_pool_addr_range(server_nat_ip_n,
5606                                                 client_nat_ip_n)
5607         self.vapi.nat64_add_del_interface(self.pg0.sw_if_index)
5608         self.vapi.nat64_add_del_interface(self.pg1.sw_if_index, is_inside=0)
5609
5610         self.vapi.nat64_add_del_static_bib(server.ip6n,
5611                                            server_nat_ip_n,
5612                                            server_tcp_in_port,
5613                                            server_tcp_out_port,
5614                                            IP_PROTOS.tcp)
5615
5616         self.vapi.nat64_add_del_static_bib(server.ip6n,
5617                                            server_nat_ip_n,
5618                                            0,
5619                                            0,
5620                                            IP_PROTOS.gre)
5621
5622         self.vapi.nat64_add_del_static_bib(client.ip6n,
5623                                            client_nat_ip_n,
5624                                            client_tcp_in_port,
5625                                            client_tcp_out_port,
5626                                            IP_PROTOS.tcp)
5627
5628         # client to server
5629         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
5630              IPv6(src=client.ip6, dst=server_nat_ip6) /
5631              TCP(sport=client_tcp_in_port, dport=server_tcp_out_port))
5632         self.pg0.add_stream(p)
5633         self.pg_enable_capture(self.pg_interfaces)
5634         self.pg_start()
5635         p = self.pg0.get_capture(1)
5636
5637         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
5638              IPv6(src=client.ip6, dst=server_nat_ip6, nh=IP_PROTOS.gre) /
5639              GRE() /
5640              IP(src=self.pg2.local_ip4, dst=self.pg2.remote_ip4) /
5641              TCP(sport=1234, dport=1234))
5642         self.pg0.add_stream(p)
5643         self.pg_enable_capture(self.pg_interfaces)
5644         self.pg_start()
5645         p = self.pg0.get_capture(1)
5646         packet = p[0]
5647         try:
5648             self.assertEqual(packet[IPv6].src, client_nat_ip6)
5649             self.assertEqual(packet[IPv6].dst, server.ip6)
5650             self.assertEqual(packet[IPv6].nh, IP_PROTOS.gre)
5651         except:
5652             self.logger.error(ppp("Unexpected or invalid packet:", packet))
5653             raise
5654
5655         # server to client
5656         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
5657              IPv6(src=server.ip6, dst=client_nat_ip6, nh=IP_PROTOS.gre) /
5658              GRE() /
5659              IP(src=self.pg2.remote_ip4, dst=self.pg2.local_ip4) /
5660              TCP(sport=1234, dport=1234))
5661         self.pg0.add_stream(p)
5662         self.pg_enable_capture(self.pg_interfaces)
5663         self.pg_start()
5664         p = self.pg0.get_capture(1)
5665         packet = p[0]
5666         try:
5667             self.assertEqual(packet[IPv6].src, server_nat_ip6)
5668             self.assertEqual(packet[IPv6].dst, client.ip6)
5669             self.assertEqual(packet[IPv6].nh, IP_PROTOS.gre)
5670         except:
5671             self.logger.error(ppp("Unexpected or invalid packet:", packet))
5672             raise
5673
5674     def test_one_armed_nat64(self):
5675         """ One armed NAT64 """
5676         external_port = 0
5677         remote_host_ip6 = self.compose_ip6(self.pg3.remote_ip4,
5678                                            '64:ff9b::',
5679                                            96)
5680
5681         self.vapi.nat64_add_del_pool_addr_range(self.nat_addr_n,
5682                                                 self.nat_addr_n)
5683         self.vapi.nat64_add_del_interface(self.pg3.sw_if_index)
5684         self.vapi.nat64_add_del_interface(self.pg3.sw_if_index, is_inside=0)
5685
5686         # in2out
5687         p = (Ether(src=self.pg3.remote_mac, dst=self.pg3.local_mac) /
5688              IPv6(src=self.pg3.remote_ip6, dst=remote_host_ip6) /
5689              TCP(sport=12345, dport=80))
5690         self.pg3.add_stream(p)
5691         self.pg_enable_capture(self.pg_interfaces)
5692         self.pg_start()
5693         capture = self.pg3.get_capture(1)
5694         p = capture[0]
5695         try:
5696             ip = p[IP]
5697             tcp = p[TCP]
5698             self.assertEqual(ip.src, self.nat_addr)
5699             self.assertEqual(ip.dst, self.pg3.remote_ip4)
5700             self.assertNotEqual(tcp.sport, 12345)
5701             external_port = tcp.sport
5702             self.assertEqual(tcp.dport, 80)
5703             self.assert_packet_checksums_valid(p)
5704         except:
5705             self.logger.error(ppp("Unexpected or invalid packet:", p))
5706             raise
5707
5708         # out2in
5709         p = (Ether(src=self.pg3.remote_mac, dst=self.pg3.local_mac) /
5710              IP(src=self.pg3.remote_ip4, dst=self.nat_addr) /
5711              TCP(sport=80, dport=external_port))
5712         self.pg3.add_stream(p)
5713         self.pg_enable_capture(self.pg_interfaces)
5714         self.pg_start()
5715         capture = self.pg3.get_capture(1)
5716         p = capture[0]
5717         try:
5718             ip = p[IPv6]
5719             tcp = p[TCP]
5720             self.assertEqual(ip.src, remote_host_ip6)
5721             self.assertEqual(ip.dst, self.pg3.remote_ip6)
5722             self.assertEqual(tcp.sport, 80)
5723             self.assertEqual(tcp.dport, 12345)
5724             self.assert_packet_checksums_valid(p)
5725         except:
5726             self.logger.error(ppp("Unexpected or invalid packet:", p))
5727             raise
5728
5729     def test_frag_in_order(self):
5730         """ NAT64 translate fragments arriving in order """
5731         self.tcp_port_in = random.randint(1025, 65535)
5732
5733         self.vapi.nat64_add_del_pool_addr_range(self.nat_addr_n,
5734                                                 self.nat_addr_n)
5735         self.vapi.nat64_add_del_interface(self.pg0.sw_if_index)
5736         self.vapi.nat64_add_del_interface(self.pg1.sw_if_index, is_inside=0)
5737
5738         reass = self.vapi.nat_reass_dump()
5739         reass_n_start = len(reass)
5740
5741         # in2out
5742         data = 'a' * 200
5743         pkts = self.create_stream_frag_ip6(self.pg0, self.pg1.remote_ip4,
5744                                            self.tcp_port_in, 20, data)
5745         self.pg0.add_stream(pkts)
5746         self.pg_enable_capture(self.pg_interfaces)
5747         self.pg_start()
5748         frags = self.pg1.get_capture(len(pkts))
5749         p = self.reass_frags_and_verify(frags,
5750                                         self.nat_addr,
5751                                         self.pg1.remote_ip4)
5752         self.assertEqual(p[TCP].dport, 20)
5753         self.assertNotEqual(p[TCP].sport, self.tcp_port_in)
5754         self.tcp_port_out = p[TCP].sport
5755         self.assertEqual(data, p[Raw].load)
5756
5757         # out2in
5758         data = "A" * 4 + "b" * 16 + "C" * 3
5759         pkts = self.create_stream_frag(self.pg1,
5760                                        self.nat_addr,
5761                                        20,
5762                                        self.tcp_port_out,
5763                                        data)
5764         self.pg1.add_stream(pkts)
5765         self.pg_enable_capture(self.pg_interfaces)
5766         self.pg_start()
5767         frags = self.pg0.get_capture(len(pkts))
5768         src = self.compose_ip6(self.pg1.remote_ip4, '64:ff9b::', 96)
5769         p = self.reass_frags_and_verify_ip6(frags, src, self.pg0.remote_ip6)
5770         self.assertEqual(p[TCP].sport, 20)
5771         self.assertEqual(p[TCP].dport, self.tcp_port_in)
5772         self.assertEqual(data, p[Raw].load)
5773
5774         reass = self.vapi.nat_reass_dump()
5775         reass_n_end = len(reass)
5776
5777         self.assertEqual(reass_n_end - reass_n_start, 2)
5778
5779     def test_reass_hairpinning(self):
5780         """ NAT64 fragments hairpinning """
5781         data = 'a' * 200
5782         server = self.pg0.remote_hosts[1]
5783         server_in_port = random.randint(1025, 65535)
5784         server_out_port = random.randint(1025, 65535)
5785         client_in_port = random.randint(1025, 65535)
5786         ip = IPv6(src=''.join(['64:ff9b::', self.nat_addr]))
5787         nat_addr_ip6 = ip.src
5788
5789         self.vapi.nat64_add_del_pool_addr_range(self.nat_addr_n,
5790                                                 self.nat_addr_n)
5791         self.vapi.nat64_add_del_interface(self.pg0.sw_if_index)
5792         self.vapi.nat64_add_del_interface(self.pg1.sw_if_index, is_inside=0)
5793
5794         # add static BIB entry for server
5795         self.vapi.nat64_add_del_static_bib(server.ip6n,
5796                                            self.nat_addr_n,
5797                                            server_in_port,
5798                                            server_out_port,
5799                                            IP_PROTOS.tcp)
5800
5801         # send packet from host to server
5802         pkts = self.create_stream_frag_ip6(self.pg0,
5803                                            self.nat_addr,
5804                                            client_in_port,
5805                                            server_out_port,
5806                                            data)
5807         self.pg0.add_stream(pkts)
5808         self.pg_enable_capture(self.pg_interfaces)
5809         self.pg_start()
5810         frags = self.pg0.get_capture(len(pkts))
5811         p = self.reass_frags_and_verify_ip6(frags, nat_addr_ip6, server.ip6)
5812         self.assertNotEqual(p[TCP].sport, client_in_port)
5813         self.assertEqual(p[TCP].dport, server_in_port)
5814         self.assertEqual(data, p[Raw].load)
5815
5816     def test_frag_out_of_order(self):
5817         """ NAT64 translate fragments arriving out of order """
5818         self.tcp_port_in = random.randint(1025, 65535)
5819
5820         self.vapi.nat64_add_del_pool_addr_range(self.nat_addr_n,
5821                                                 self.nat_addr_n)
5822         self.vapi.nat64_add_del_interface(self.pg0.sw_if_index)
5823         self.vapi.nat64_add_del_interface(self.pg1.sw_if_index, is_inside=0)
5824
5825         # in2out
5826         data = 'a' * 200
5827         pkts = self.create_stream_frag_ip6(self.pg0, self.pg1.remote_ip4,
5828                                            self.tcp_port_in, 20, data)
5829         pkts.reverse()
5830         self.pg0.add_stream(pkts)
5831         self.pg_enable_capture(self.pg_interfaces)
5832         self.pg_start()
5833         frags = self.pg1.get_capture(len(pkts))
5834         p = self.reass_frags_and_verify(frags,
5835                                         self.nat_addr,
5836                                         self.pg1.remote_ip4)
5837         self.assertEqual(p[TCP].dport, 20)
5838         self.assertNotEqual(p[TCP].sport, self.tcp_port_in)
5839         self.tcp_port_out = p[TCP].sport
5840         self.assertEqual(data, p[Raw].load)
5841
5842         # out2in
5843         data = "A" * 4 + "B" * 16 + "C" * 3
5844         pkts = self.create_stream_frag(self.pg1,
5845                                        self.nat_addr,
5846                                        20,
5847                                        self.tcp_port_out,
5848                                        data)
5849         pkts.reverse()
5850         self.pg1.add_stream(pkts)
5851         self.pg_enable_capture(self.pg_interfaces)
5852         self.pg_start()
5853         frags = self.pg0.get_capture(len(pkts))
5854         src = self.compose_ip6(self.pg1.remote_ip4, '64:ff9b::', 96)
5855         p = self.reass_frags_and_verify_ip6(frags, src, self.pg0.remote_ip6)
5856         self.assertEqual(p[TCP].sport, 20)
5857         self.assertEqual(p[TCP].dport, self.tcp_port_in)
5858         self.assertEqual(data, p[Raw].load)
5859
5860     def test_interface_addr(self):
5861         """ Acquire NAT64 pool addresses from interface """
5862         self.vapi.nat64_add_interface_addr(self.pg4.sw_if_index)
5863
5864         # no address in NAT64 pool
5865         adresses = self.vapi.nat44_address_dump()
5866         self.assertEqual(0, len(adresses))
5867
5868         # configure interface address and check NAT64 address pool
5869         self.pg4.config_ip4()
5870         addresses = self.vapi.nat64_pool_addr_dump()
5871         self.assertEqual(len(addresses), 1)
5872         self.assertEqual(addresses[0].address, self.pg4.local_ip4n)
5873
5874         # remove interface address and check NAT64 address pool
5875         self.pg4.unconfig_ip4()
5876         addresses = self.vapi.nat64_pool_addr_dump()
5877         self.assertEqual(0, len(adresses))
5878
5879     @unittest.skipUnless(running_extended_tests(), "part of extended tests")
5880     def test_ipfix_max_bibs_sessions(self):
5881         """ IPFIX logging maximum session and BIB entries exceeded """
5882         max_bibs = 1280
5883         max_sessions = 2560
5884         remote_host_ip6 = self.compose_ip6(self.pg1.remote_ip4,
5885                                            '64:ff9b::',
5886                                            96)
5887
5888         self.vapi.nat64_add_del_pool_addr_range(self.nat_addr_n,
5889                                                 self.nat_addr_n)
5890         self.vapi.nat64_add_del_interface(self.pg0.sw_if_index)
5891         self.vapi.nat64_add_del_interface(self.pg1.sw_if_index, is_inside=0)
5892
5893         pkts = []
5894         src = ""
5895         for i in range(0, max_bibs):
5896             src = "fd01:aa::%x" % (i)
5897             p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
5898                  IPv6(src=src, dst=remote_host_ip6) /
5899                  TCP(sport=12345, dport=80))
5900             pkts.append(p)
5901             p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
5902                  IPv6(src=src, dst=remote_host_ip6) /
5903                  TCP(sport=12345, dport=22))
5904             pkts.append(p)
5905         self.pg0.add_stream(pkts)
5906         self.pg_enable_capture(self.pg_interfaces)
5907         self.pg_start()
5908         self.pg1.get_capture(max_sessions)
5909
5910         self.vapi.set_ipfix_exporter(collector_address=self.pg3.remote_ip4n,
5911                                      src_address=self.pg3.local_ip4n,
5912                                      path_mtu=512,
5913                                      template_interval=10)
5914         self.vapi.nat_ipfix(domain_id=self.ipfix_domain_id,
5915                             src_port=self.ipfix_src_port)
5916
5917         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
5918              IPv6(src=src, dst=remote_host_ip6) /
5919              TCP(sport=12345, dport=25))
5920         self.pg0.add_stream(p)
5921         self.pg_enable_capture(self.pg_interfaces)
5922         self.pg_start()
5923         self.pg1.get_capture(0)
5924         self.vapi.cli("ipfix flush")  # FIXME this should be an API call
5925         capture = self.pg3.get_capture(9)
5926         ipfix = IPFIXDecoder()
5927         # first load template
5928         for p in capture:
5929             self.assertTrue(p.haslayer(IPFIX))
5930             self.assertEqual(p[IP].src, self.pg3.local_ip4)
5931             self.assertEqual(p[IP].dst, self.pg3.remote_ip4)
5932             self.assertEqual(p[UDP].sport, self.ipfix_src_port)
5933             self.assertEqual(p[UDP].dport, 4739)
5934             self.assertEqual(p[IPFIX].observationDomainID,
5935                              self.ipfix_domain_id)
5936             if p.haslayer(Template):
5937                 ipfix.add_template(p.getlayer(Template))
5938         # verify events in data set
5939         for p in capture:
5940             if p.haslayer(Data):
5941                 data = ipfix.decode_data_set(p.getlayer(Set))
5942                 self.verify_ipfix_max_sessions(data, max_sessions)
5943
5944         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
5945              IPv6(src=self.pg0.remote_ip6, dst=remote_host_ip6) /
5946              TCP(sport=12345, dport=80))
5947         self.pg0.add_stream(p)
5948         self.pg_enable_capture(self.pg_interfaces)
5949         self.pg_start()
5950         self.pg1.get_capture(0)
5951         self.vapi.cli("ipfix flush")  # FIXME this should be an API call
5952         capture = self.pg3.get_capture(1)
5953         # verify events in data set
5954         for p in capture:
5955             self.assertTrue(p.haslayer(IPFIX))
5956             self.assertEqual(p[IP].src, self.pg3.local_ip4)
5957             self.assertEqual(p[IP].dst, self.pg3.remote_ip4)
5958             self.assertEqual(p[UDP].sport, self.ipfix_src_port)
5959             self.assertEqual(p[UDP].dport, 4739)
5960             self.assertEqual(p[IPFIX].observationDomainID,
5961                              self.ipfix_domain_id)
5962             if p.haslayer(Data):
5963                 data = ipfix.decode_data_set(p.getlayer(Set))
5964                 self.verify_ipfix_max_bibs(data, max_bibs)
5965
5966     def test_ipfix_max_frags(self):
5967         """ IPFIX logging maximum fragments pending reassembly exceeded """
5968         self.vapi.nat64_add_del_pool_addr_range(self.nat_addr_n,
5969                                                 self.nat_addr_n)
5970         self.vapi.nat64_add_del_interface(self.pg0.sw_if_index)
5971         self.vapi.nat64_add_del_interface(self.pg1.sw_if_index, is_inside=0)
5972         self.vapi.nat_set_reass(max_frag=0, is_ip6=1)
5973         self.vapi.set_ipfix_exporter(collector_address=self.pg3.remote_ip4n,
5974                                      src_address=self.pg3.local_ip4n,
5975                                      path_mtu=512,
5976                                      template_interval=10)
5977         self.vapi.nat_ipfix(domain_id=self.ipfix_domain_id,
5978                             src_port=self.ipfix_src_port)
5979
5980         data = 'a' * 200
5981         pkts = self.create_stream_frag_ip6(self.pg0, self.pg1.remote_ip4,
5982                                            self.tcp_port_in, 20, data)
5983         self.pg0.add_stream(pkts[-1])
5984         self.pg_enable_capture(self.pg_interfaces)
5985         self.pg_start()
5986         self.pg1.get_capture(0)
5987         self.vapi.cli("ipfix flush")  # FIXME this should be an API call
5988         capture = self.pg3.get_capture(9)
5989         ipfix = IPFIXDecoder()
5990         # first load template
5991         for p in capture:
5992             self.assertTrue(p.haslayer(IPFIX))
5993             self.assertEqual(p[IP].src, self.pg3.local_ip4)
5994             self.assertEqual(p[IP].dst, self.pg3.remote_ip4)
5995             self.assertEqual(p[UDP].sport, self.ipfix_src_port)
5996             self.assertEqual(p[UDP].dport, 4739)
5997             self.assertEqual(p[IPFIX].observationDomainID,
5998                              self.ipfix_domain_id)
5999             if p.haslayer(Template):
6000                 ipfix.add_template(p.getlayer(Template))
6001         # verify events in data set
6002         for p in capture:
6003             if p.haslayer(Data):
6004                 data = ipfix.decode_data_set(p.getlayer(Set))
6005                 self.verify_ipfix_max_fragments_ip6(data, 0,
6006                                                     self.pg0.remote_ip6n)
6007
6008     def test_ipfix_bib_ses(self):
6009         """ IPFIX logging NAT64 BIB/session create and delete events """
6010         self.tcp_port_in = random.randint(1025, 65535)
6011         remote_host_ip6 = self.compose_ip6(self.pg1.remote_ip4,
6012                                            '64:ff9b::',
6013                                            96)
6014
6015         self.vapi.nat64_add_del_pool_addr_range(self.nat_addr_n,
6016                                                 self.nat_addr_n)
6017         self.vapi.nat64_add_del_interface(self.pg0.sw_if_index)
6018         self.vapi.nat64_add_del_interface(self.pg1.sw_if_index, is_inside=0)
6019         self.vapi.set_ipfix_exporter(collector_address=self.pg3.remote_ip4n,
6020                                      src_address=self.pg3.local_ip4n,
6021                                      path_mtu=512,
6022                                      template_interval=10)
6023         self.vapi.nat_ipfix(domain_id=self.ipfix_domain_id,
6024                             src_port=self.ipfix_src_port)
6025
6026         # Create
6027         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6028              IPv6(src=self.pg0.remote_ip6, dst=remote_host_ip6) /
6029              TCP(sport=self.tcp_port_in, dport=25))
6030         self.pg0.add_stream(p)
6031         self.pg_enable_capture(self.pg_interfaces)
6032         self.pg_start()
6033         p = self.pg1.get_capture(1)
6034         self.tcp_port_out = p[0][TCP].sport
6035         self.vapi.cli("ipfix flush")  # FIXME this should be an API call
6036         capture = self.pg3.get_capture(10)
6037         ipfix = IPFIXDecoder()
6038         # first load template
6039         for p in capture:
6040             self.assertTrue(p.haslayer(IPFIX))
6041             self.assertEqual(p[IP].src, self.pg3.local_ip4)
6042             self.assertEqual(p[IP].dst, self.pg3.remote_ip4)
6043             self.assertEqual(p[UDP].sport, self.ipfix_src_port)
6044             self.assertEqual(p[UDP].dport, 4739)
6045             self.assertEqual(p[IPFIX].observationDomainID,
6046                              self.ipfix_domain_id)
6047             if p.haslayer(Template):
6048                 ipfix.add_template(p.getlayer(Template))
6049         # verify events in data set
6050         for p in capture:
6051             if p.haslayer(Data):
6052                 data = ipfix.decode_data_set(p.getlayer(Set))
6053                 if ord(data[0][230]) == 10:
6054                     self.verify_ipfix_bib(data, 1, self.pg0.remote_ip6n)
6055                 elif ord(data[0][230]) == 6:
6056                     self.verify_ipfix_nat64_ses(data,
6057                                                 1,
6058                                                 self.pg0.remote_ip6n,
6059                                                 self.pg1.remote_ip4,
6060                                                 25)
6061                 else:
6062                     self.logger.error(ppp("Unexpected or invalid packet: ", p))
6063
6064         # Delete
6065         self.pg_enable_capture(self.pg_interfaces)
6066         self.vapi.nat64_add_del_pool_addr_range(self.nat_addr_n,
6067                                                 self.nat_addr_n,
6068                                                 is_add=0)
6069         self.vapi.cli("ipfix flush")  # FIXME this should be an API call
6070         capture = self.pg3.get_capture(2)
6071         # verify events in data set
6072         for p in capture:
6073             self.assertTrue(p.haslayer(IPFIX))
6074             self.assertEqual(p[IP].src, self.pg3.local_ip4)
6075             self.assertEqual(p[IP].dst, self.pg3.remote_ip4)
6076             self.assertEqual(p[UDP].sport, self.ipfix_src_port)
6077             self.assertEqual(p[UDP].dport, 4739)
6078             self.assertEqual(p[IPFIX].observationDomainID,
6079                              self.ipfix_domain_id)
6080             if p.haslayer(Data):
6081                 data = ipfix.decode_data_set(p.getlayer(Set))
6082                 if ord(data[0][230]) == 11:
6083                     self.verify_ipfix_bib(data, 0, self.pg0.remote_ip6n)
6084                 elif ord(data[0][230]) == 7:
6085                     self.verify_ipfix_nat64_ses(data,
6086                                                 0,
6087                                                 self.pg0.remote_ip6n,
6088                                                 self.pg1.remote_ip4,
6089                                                 25)
6090                 else:
6091                     self.logger.error(ppp("Unexpected or invalid packet: ", p))
6092
6093     def nat64_get_ses_num(self):
6094         """
6095         Return number of active NAT64 sessions.
6096         """
6097         st = self.vapi.nat64_st_dump()
6098         return len(st)
6099
6100     def clear_nat64(self):
6101         """
6102         Clear NAT64 configuration.
6103         """
6104         self.vapi.nat_ipfix(enable=0, src_port=self.ipfix_src_port,
6105                             domain_id=self.ipfix_domain_id)
6106         self.ipfix_src_port = 4739
6107         self.ipfix_domain_id = 1
6108
6109         self.vapi.nat64_set_timeouts()
6110
6111         interfaces = self.vapi.nat64_interface_dump()
6112         for intf in interfaces:
6113             if intf.is_inside > 1:
6114                 self.vapi.nat64_add_del_interface(intf.sw_if_index,
6115                                                   0,
6116                                                   is_add=0)
6117             self.vapi.nat64_add_del_interface(intf.sw_if_index,
6118                                               intf.is_inside,
6119                                               is_add=0)
6120
6121         bib = self.vapi.nat64_bib_dump(255)
6122         for bibe in bib:
6123             if bibe.is_static:
6124                 self.vapi.nat64_add_del_static_bib(bibe.i_addr,
6125                                                    bibe.o_addr,
6126                                                    bibe.i_port,
6127                                                    bibe.o_port,
6128                                                    bibe.proto,
6129                                                    bibe.vrf_id,
6130                                                    is_add=0)
6131
6132         adresses = self.vapi.nat64_pool_addr_dump()
6133         for addr in adresses:
6134             self.vapi.nat64_add_del_pool_addr_range(addr.address,
6135                                                     addr.address,
6136                                                     vrf_id=addr.vrf_id,
6137                                                     is_add=0)
6138
6139         prefixes = self.vapi.nat64_prefix_dump()
6140         for prefix in prefixes:
6141             self.vapi.nat64_add_del_prefix(prefix.prefix,
6142                                            prefix.prefix_len,
6143                                            vrf_id=prefix.vrf_id,
6144                                            is_add=0)
6145
6146     def tearDown(self):
6147         super(TestNAT64, self).tearDown()
6148         if not self.vpp_dead:
6149             self.logger.info(self.vapi.cli("show nat64 pool"))
6150             self.logger.info(self.vapi.cli("show nat64 interfaces"))
6151             self.logger.info(self.vapi.cli("show nat64 prefix"))
6152             self.logger.info(self.vapi.cli("show nat64 bib all"))
6153             self.logger.info(self.vapi.cli("show nat64 session table all"))
6154             self.logger.info(self.vapi.cli("show nat virtual-reassembly"))
6155             self.clear_nat64()
6156
6157
6158 class TestDSlite(MethodHolder):
6159     """ DS-Lite Test Cases """
6160
6161     @classmethod
6162     def setUpClass(cls):
6163         super(TestDSlite, cls).setUpClass()
6164
6165         try:
6166             cls.nat_addr = '10.0.0.3'
6167             cls.nat_addr_n = socket.inet_pton(socket.AF_INET, cls.nat_addr)
6168
6169             cls.create_pg_interfaces(range(2))
6170             cls.pg0.admin_up()
6171             cls.pg0.config_ip4()
6172             cls.pg0.resolve_arp()
6173             cls.pg1.admin_up()
6174             cls.pg1.config_ip6()
6175             cls.pg1.generate_remote_hosts(2)
6176             cls.pg1.configure_ipv6_neighbors()
6177
6178         except Exception:
6179             super(TestDSlite, cls).tearDownClass()
6180             raise
6181
6182     def test_dslite(self):
6183         """ Test DS-Lite """
6184         self.vapi.dslite_add_del_pool_addr_range(self.nat_addr_n,
6185                                                  self.nat_addr_n)
6186         aftr_ip4 = '192.0.0.1'
6187         aftr_ip4_n = socket.inet_pton(socket.AF_INET, aftr_ip4)
6188         aftr_ip6 = '2001:db8:85a3::8a2e:370:1'
6189         aftr_ip6_n = socket.inet_pton(socket.AF_INET6, aftr_ip6)
6190         self.vapi.dslite_set_aftr_addr(aftr_ip6_n, aftr_ip4_n)
6191
6192         # UDP
6193         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
6194              IPv6(dst=aftr_ip6, src=self.pg1.remote_hosts[0].ip6) /
6195              IP(dst=self.pg0.remote_ip4, src='192.168.1.1') /
6196              UDP(sport=20000, dport=10000))
6197         self.pg1.add_stream(p)
6198         self.pg_enable_capture(self.pg_interfaces)
6199         self.pg_start()
6200         capture = self.pg0.get_capture(1)
6201         capture = capture[0]
6202         self.assertFalse(capture.haslayer(IPv6))
6203         self.assertEqual(capture[IP].src, self.nat_addr)
6204         self.assertEqual(capture[IP].dst, self.pg0.remote_ip4)
6205         self.assertNotEqual(capture[UDP].sport, 20000)
6206         self.assertEqual(capture[UDP].dport, 10000)
6207         self.assert_packet_checksums_valid(capture)
6208         out_port = capture[UDP].sport
6209
6210         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
6211              IP(dst=self.nat_addr, src=self.pg0.remote_ip4) /
6212              UDP(sport=10000, dport=out_port))
6213         self.pg0.add_stream(p)
6214         self.pg_enable_capture(self.pg_interfaces)
6215         self.pg_start()
6216         capture = self.pg1.get_capture(1)
6217         capture = capture[0]
6218         self.assertEqual(capture[IPv6].src, aftr_ip6)
6219         self.assertEqual(capture[IPv6].dst, self.pg1.remote_hosts[0].ip6)
6220         self.assertEqual(capture[IP].src, self.pg0.remote_ip4)
6221         self.assertEqual(capture[IP].dst, '192.168.1.1')
6222         self.assertEqual(capture[UDP].sport, 10000)
6223         self.assertEqual(capture[UDP].dport, 20000)
6224         self.assert_packet_checksums_valid(capture)
6225
6226         # TCP
6227         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
6228              IPv6(dst=aftr_ip6, src=self.pg1.remote_hosts[1].ip6) /
6229              IP(dst=self.pg0.remote_ip4, src='192.168.1.1') /
6230              TCP(sport=20001, dport=10001))
6231         self.pg1.add_stream(p)
6232         self.pg_enable_capture(self.pg_interfaces)
6233         self.pg_start()
6234         capture = self.pg0.get_capture(1)
6235         capture = capture[0]
6236         self.assertFalse(capture.haslayer(IPv6))
6237         self.assertEqual(capture[IP].src, self.nat_addr)
6238         self.assertEqual(capture[IP].dst, self.pg0.remote_ip4)
6239         self.assertNotEqual(capture[TCP].sport, 20001)
6240         self.assertEqual(capture[TCP].dport, 10001)
6241         self.assert_packet_checksums_valid(capture)
6242         out_port = capture[TCP].sport
6243
6244         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
6245              IP(dst=self.nat_addr, src=self.pg0.remote_ip4) /
6246              TCP(sport=10001, dport=out_port))
6247         self.pg0.add_stream(p)
6248         self.pg_enable_capture(self.pg_interfaces)
6249         self.pg_start()
6250         capture = self.pg1.get_capture(1)
6251         capture = capture[0]
6252         self.assertEqual(capture[IPv6].src, aftr_ip6)
6253         self.assertEqual(capture[IPv6].dst, self.pg1.remote_hosts[1].ip6)
6254         self.assertEqual(capture[IP].src, self.pg0.remote_ip4)
6255         self.assertEqual(capture[IP].dst, '192.168.1.1')
6256         self.assertEqual(capture[TCP].sport, 10001)
6257         self.assertEqual(capture[TCP].dport, 20001)
6258         self.assert_packet_checksums_valid(capture)
6259
6260         # ICMP
6261         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
6262              IPv6(dst=aftr_ip6, src=self.pg1.remote_hosts[1].ip6) /
6263              IP(dst=self.pg0.remote_ip4, src='192.168.1.1') /
6264              ICMP(id=4000, type='echo-request'))
6265         self.pg1.add_stream(p)
6266         self.pg_enable_capture(self.pg_interfaces)
6267         self.pg_start()
6268         capture = self.pg0.get_capture(1)
6269         capture = capture[0]
6270         self.assertFalse(capture.haslayer(IPv6))
6271         self.assertEqual(capture[IP].src, self.nat_addr)
6272         self.assertEqual(capture[IP].dst, self.pg0.remote_ip4)
6273         self.assertNotEqual(capture[ICMP].id, 4000)
6274         self.assert_packet_checksums_valid(capture)
6275         out_id = capture[ICMP].id
6276
6277         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
6278              IP(dst=self.nat_addr, src=self.pg0.remote_ip4) /
6279              ICMP(id=out_id, type='echo-reply'))
6280         self.pg0.add_stream(p)
6281         self.pg_enable_capture(self.pg_interfaces)
6282         self.pg_start()
6283         capture = self.pg1.get_capture(1)
6284         capture = capture[0]
6285         self.assertEqual(capture[IPv6].src, aftr_ip6)
6286         self.assertEqual(capture[IPv6].dst, self.pg1.remote_hosts[1].ip6)
6287         self.assertEqual(capture[IP].src, self.pg0.remote_ip4)
6288         self.assertEqual(capture[IP].dst, '192.168.1.1')
6289         self.assertEqual(capture[ICMP].id, 4000)
6290         self.assert_packet_checksums_valid(capture)
6291
6292         # ping DS-Lite AFTR tunnel endpoint address
6293         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
6294              IPv6(src=self.pg1.remote_hosts[1].ip6, dst=aftr_ip6) /
6295              ICMPv6EchoRequest())
6296         self.pg1.add_stream(p)
6297         self.pg_enable_capture(self.pg_interfaces)
6298         self.pg_start()
6299         capture = self.pg1.get_capture(1)
6300         self.assertEqual(1, len(capture))
6301         capture = capture[0]
6302         self.assertEqual(capture[IPv6].src, aftr_ip6)
6303         self.assertEqual(capture[IPv6].dst, self.pg1.remote_hosts[1].ip6)
6304         self.assertTrue(capture.haslayer(ICMPv6EchoReply))
6305
6306     def tearDown(self):
6307         super(TestDSlite, self).tearDown()
6308         if not self.vpp_dead:
6309             self.logger.info(self.vapi.cli("show dslite pool"))
6310             self.logger.info(
6311                 self.vapi.cli("show dslite aftr-tunnel-endpoint-address"))
6312             self.logger.info(self.vapi.cli("show dslite sessions"))
6313
6314
6315 class TestDSliteCE(MethodHolder):
6316     """ DS-Lite CE Test Cases """
6317
6318     @classmethod
6319     def setUpConstants(cls):
6320         super(TestDSliteCE, cls).setUpConstants()
6321         cls.vpp_cmdline.extend(["nat", "{", "dslite ce", "}"])
6322
6323     @classmethod
6324     def setUpClass(cls):
6325         super(TestDSliteCE, cls).setUpClass()
6326
6327         try:
6328             cls.create_pg_interfaces(range(2))
6329             cls.pg0.admin_up()
6330             cls.pg0.config_ip4()
6331             cls.pg0.resolve_arp()
6332             cls.pg1.admin_up()
6333             cls.pg1.config_ip6()
6334             cls.pg1.generate_remote_hosts(1)
6335             cls.pg1.configure_ipv6_neighbors()
6336
6337         except Exception:
6338             super(TestDSliteCE, cls).tearDownClass()
6339             raise
6340
6341     def test_dslite_ce(self):
6342         """ Test DS-Lite CE """
6343
6344         b4_ip4 = '192.0.0.2'
6345         b4_ip4_n = socket.inet_pton(socket.AF_INET, b4_ip4)
6346         b4_ip6 = '2001:db8:62aa::375e:f4c1:1'
6347         b4_ip6_n = socket.inet_pton(socket.AF_INET6, b4_ip6)
6348         self.vapi.dslite_set_b4_addr(b4_ip6_n, b4_ip4_n)
6349
6350         aftr_ip4 = '192.0.0.1'
6351         aftr_ip4_n = socket.inet_pton(socket.AF_INET, aftr_ip4)
6352         aftr_ip6 = '2001:db8:85a3::8a2e:370:1'
6353         aftr_ip6_n = socket.inet_pton(socket.AF_INET6, aftr_ip6)
6354         self.vapi.dslite_set_aftr_addr(aftr_ip6_n, aftr_ip4_n)
6355
6356         self.vapi.ip_add_del_route(dst_address=aftr_ip6_n,
6357                                    dst_address_length=128,
6358                                    next_hop_address=self.pg1.remote_ip6n,
6359                                    next_hop_sw_if_index=self.pg1.sw_if_index,
6360                                    is_ipv6=1)
6361
6362         # UDP encapsulation
6363         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
6364              IP(dst=self.pg1.remote_ip4, src=self.pg0.remote_ip4) /
6365              UDP(sport=10000, dport=20000))
6366         self.pg0.add_stream(p)
6367         self.pg_enable_capture(self.pg_interfaces)
6368         self.pg_start()
6369         capture = self.pg1.get_capture(1)
6370         capture = capture[0]
6371         self.assertEqual(capture[IPv6].src, b4_ip6)
6372         self.assertEqual(capture[IPv6].dst, aftr_ip6)
6373         self.assertEqual(capture[IP].src, self.pg0.remote_ip4)
6374         self.assertEqual(capture[IP].dst, self.pg1.remote_ip4)
6375         self.assertEqual(capture[UDP].sport, 10000)
6376         self.assertEqual(capture[UDP].dport, 20000)
6377         self.assert_packet_checksums_valid(capture)
6378
6379         # UDP decapsulation
6380         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
6381              IPv6(dst=b4_ip6, src=aftr_ip6) /
6382              IP(dst=self.pg0.remote_ip4, src=self.pg1.remote_ip4) /
6383              UDP(sport=20000, dport=10000))
6384         self.pg1.add_stream(p)
6385         self.pg_enable_capture(self.pg_interfaces)
6386         self.pg_start()
6387         capture = self.pg0.get_capture(1)
6388         capture = capture[0]
6389         self.assertFalse(capture.haslayer(IPv6))
6390         self.assertEqual(capture[IP].src, self.pg1.remote_ip4)
6391         self.assertEqual(capture[IP].dst, self.pg0.remote_ip4)
6392         self.assertEqual(capture[UDP].sport, 20000)
6393         self.assertEqual(capture[UDP].dport, 10000)
6394         self.assert_packet_checksums_valid(capture)
6395
6396         # ping DS-Lite B4 tunnel endpoint address
6397         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
6398              IPv6(src=self.pg1.remote_hosts[0].ip6, dst=b4_ip6) /
6399              ICMPv6EchoRequest())
6400         self.pg1.add_stream(p)
6401         self.pg_enable_capture(self.pg_interfaces)
6402         self.pg_start()
6403         capture = self.pg1.get_capture(1)
6404         self.assertEqual(1, len(capture))
6405         capture = capture[0]
6406         self.assertEqual(capture[IPv6].src, b4_ip6)
6407         self.assertEqual(capture[IPv6].dst, self.pg1.remote_hosts[0].ip6)
6408         self.assertTrue(capture.haslayer(ICMPv6EchoReply))
6409
6410     def tearDown(self):
6411         super(TestDSliteCE, self).tearDown()
6412         if not self.vpp_dead:
6413             self.logger.info(
6414                 self.vapi.cli("show dslite aftr-tunnel-endpoint-address"))
6415             self.logger.info(
6416                 self.vapi.cli("show dslite b4-tunnel-endpoint-address"))
6417
6418
6419 class TestNAT66(MethodHolder):
6420     """ NAT66 Test Cases """
6421
6422     @classmethod
6423     def setUpClass(cls):
6424         super(TestNAT66, cls).setUpClass()
6425
6426         try:
6427             cls.nat_addr = 'fd01:ff::2'
6428             cls.nat_addr_n = socket.inet_pton(socket.AF_INET6, cls.nat_addr)
6429
6430             cls.create_pg_interfaces(range(2))
6431             cls.interfaces = list(cls.pg_interfaces)
6432
6433             for i in cls.interfaces:
6434                 i.admin_up()
6435                 i.config_ip6()
6436                 i.configure_ipv6_neighbors()
6437
6438         except Exception:
6439             super(TestNAT66, cls).tearDownClass()
6440             raise
6441
6442     def test_static(self):
6443         """ 1:1 NAT66 test """
6444         self.vapi.nat66_add_del_interface(self.pg0.sw_if_index)
6445         self.vapi.nat66_add_del_interface(self.pg1.sw_if_index, is_inside=0)
6446         self.vapi.nat66_add_del_static_mapping(self.pg0.remote_ip6n,
6447                                                self.nat_addr_n)
6448
6449         # in2out
6450         pkts = []
6451         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
6452              IPv6(src=self.pg0.remote_ip6, dst=self.pg1.remote_ip6) /
6453              TCP())
6454         pkts.append(p)
6455         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
6456              IPv6(src=self.pg0.remote_ip6, dst=self.pg1.remote_ip6) /
6457              UDP())
6458         pkts.append(p)
6459         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
6460              IPv6(src=self.pg0.remote_ip6, dst=self.pg1.remote_ip6) /
6461              ICMPv6EchoRequest())
6462         pkts.append(p)
6463         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
6464              IPv6(src=self.pg0.remote_ip6, dst=self.pg1.remote_ip6) /
6465              GRE() / IP() / TCP())
6466         pkts.append(p)
6467         self.pg0.add_stream(pkts)
6468         self.pg_enable_capture(self.pg_interfaces)
6469         self.pg_start()
6470         capture = self.pg1.get_capture(len(pkts))
6471         for packet in capture:
6472             try:
6473                 self.assertEqual(packet[IPv6].src, self.nat_addr)
6474                 self.assertEqual(packet[IPv6].dst, self.pg1.remote_ip6)
6475                 self.assert_packet_checksums_valid(packet)
6476             except:
6477                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
6478                 raise
6479
6480         # out2in
6481         pkts = []
6482         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
6483              IPv6(src=self.pg1.remote_ip6, dst=self.nat_addr) /
6484              TCP())
6485         pkts.append(p)
6486         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
6487              IPv6(src=self.pg1.remote_ip6, dst=self.nat_addr) /
6488              UDP())
6489         pkts.append(p)
6490         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
6491              IPv6(src=self.pg1.remote_ip6, dst=self.nat_addr) /
6492              ICMPv6EchoReply())
6493         pkts.append(p)
6494         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
6495              IPv6(src=self.pg1.remote_ip6, dst=self.nat_addr) /
6496              GRE() / IP() / TCP())
6497         pkts.append(p)
6498         self.pg1.add_stream(pkts)
6499         self.pg_enable_capture(self.pg_interfaces)
6500         self.pg_start()
6501         capture = self.pg0.get_capture(len(pkts))
6502         for packet in capture:
6503             try:
6504                 self.assertEqual(packet[IPv6].src, self.pg1.remote_ip6)
6505                 self.assertEqual(packet[IPv6].dst, self.pg0.remote_ip6)
6506                 self.assert_packet_checksums_valid(packet)
6507             except:
6508                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
6509                 raise
6510
6511         sm = self.vapi.nat66_static_mapping_dump()
6512         self.assertEqual(len(sm), 1)
6513         self.assertEqual(sm[0].total_pkts, 8)
6514
6515     def test_check_no_translate(self):
6516         """ NAT66 translate only when egress interface is outside interface """
6517         self.vapi.nat66_add_del_interface(self.pg0.sw_if_index)
6518         self.vapi.nat66_add_del_interface(self.pg1.sw_if_index)
6519         self.vapi.nat66_add_del_static_mapping(self.pg0.remote_ip6n,
6520                                                self.nat_addr_n)
6521
6522         # in2out
6523         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
6524              IPv6(src=self.pg0.remote_ip6, dst=self.pg1.remote_ip6) /
6525              UDP())
6526         self.pg0.add_stream([p])
6527         self.pg_enable_capture(self.pg_interfaces)
6528         self.pg_start()
6529         capture = self.pg1.get_capture(1)
6530         packet = capture[0]
6531         try:
6532             self.assertEqual(packet[IPv6].src, self.pg0.remote_ip6)
6533             self.assertEqual(packet[IPv6].dst, self.pg1.remote_ip6)
6534         except:
6535             self.logger.error(ppp("Unexpected or invalid packet:", packet))
6536             raise
6537
6538     def clear_nat66(self):
6539         """
6540         Clear NAT66 configuration.
6541         """
6542         interfaces = self.vapi.nat66_interface_dump()
6543         for intf in interfaces:
6544             self.vapi.nat66_add_del_interface(intf.sw_if_index,
6545                                               intf.is_inside,
6546                                               is_add=0)
6547
6548         static_mappings = self.vapi.nat66_static_mapping_dump()
6549         for sm in static_mappings:
6550             self.vapi.nat66_add_del_static_mapping(sm.local_ip_address,
6551                                                    sm.external_ip_address,
6552                                                    sm.vrf_id,
6553                                                    is_add=0)
6554
6555     def tearDown(self):
6556         super(TestNAT66, self).tearDown()
6557         if not self.vpp_dead:
6558             self.logger.info(self.vapi.cli("show nat66 interfaces"))
6559             self.logger.info(self.vapi.cli("show nat66 static mappings"))
6560             self.clear_nat66()
6561
6562
6563 if __name__ == '__main__':
6564     unittest.main(testRunner=VppTestRunner)