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