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