VPP-1508: Use scapy.compat to manage packet level library differences.
[vpp.git] / test / test_nat.py
1 #!/usr/bin/env python
2
3 import socket
4 import unittest
5 import struct
6 import random
7
8 from framework import VppTestCase, VppTestRunner, running_extended_tests
9
10 import scapy.compat
11 from scapy.layers.inet import IP, TCP, UDP, ICMP
12 from scapy.layers.inet import IPerror, TCPerror, UDPerror, ICMPerror
13 from scapy.layers.inet6 import IPv6, ICMPv6EchoRequest, ICMPv6EchoReply, \
14     ICMPv6ND_NS, ICMPv6ND_NA, ICMPv6NDOptDstLLAddr, fragment6
15 from scapy.layers.inet6 import ICMPv6DestUnreach, IPerror6, IPv6ExtHdrFragment
16 from scapy.layers.l2 import Ether, ARP, GRE
17 from scapy.data import IP_PROTOS
18 from scapy.packet import bind_layers, Raw
19 from util import ppp
20 from ipfix import IPFIX, Set, Template, Data, IPFIXDecoder
21 from time import sleep
22 from util import ip4_range
23 from vpp_papi import mac_pton
24 from syslog_rfc5424_parser import SyslogMessage, ParseError
25 from syslog_rfc5424_parser.constants import SyslogFacility, SyslogSeverity
26 from vpp_papi_provider import SYSLOG_SEVERITY
27 from io import BytesIO
28 from vpp_papi import VppEnum
29 from scapy.all import bind_layers, Packet, ByteEnumField, ShortField, \
30     IPField, IntField, LongField, XByteField, FlagsField, FieldLenField, \
31     PacketListField
32
33
34 # NAT HA protocol event data
35 class Event(Packet):
36     name = "Event"
37     fields_desc = [ByteEnumField("event_type", None,
38                                  {1: "add", 2: "del", 3: "refresh"}),
39                    ByteEnumField("protocol", None,
40                                  {0: "udp", 1: "tcp", 2: "icmp"}),
41                    ShortField("flags", 0),
42                    IPField("in_addr", None),
43                    IPField("out_addr", None),
44                    ShortField("in_port", None),
45                    ShortField("out_port", None),
46                    IPField("eh_addr", None),
47                    IPField("ehn_addr", None),
48                    ShortField("eh_port", None),
49                    ShortField("ehn_port", None),
50                    IntField("fib_index", None),
51                    IntField("total_pkts", 0),
52                    LongField("total_bytes", 0)]
53
54     def extract_padding(self, s):
55         return "", s
56
57
58 # NAT HA protocol header
59 class HANATStateSync(Packet):
60     name = "HA NAT state sync"
61     fields_desc = [XByteField("version", 1),
62                    FlagsField("flags", 0, 8, ['ACK']),
63                    FieldLenField("count", None, count_of="events"),
64                    IntField("sequence_number", 1),
65                    IntField("thread_index", 0),
66                    PacketListField("events", [], Event,
67                                    count_from=lambda pkt: pkt.count)]
68
69
70 class MethodHolder(VppTestCase):
71     """ NAT create capture and verify method holder """
72
73     def clear_nat44(self):
74         """
75         Clear NAT44 configuration.
76         """
77         if hasattr(self, 'pg7') and hasattr(self, 'pg8'):
78             # I found no elegant way to do this
79             self.vapi.ip_add_del_route(
80                 dst_address=self.pg7.remote_ip4n,
81                 dst_address_length=32,
82                 next_hop_address=self.pg7.remote_ip4n,
83                 next_hop_sw_if_index=self.pg7.sw_if_index,
84                 is_add=0)
85             self.vapi.ip_add_del_route(
86                 dst_address=self.pg8.remote_ip4n,
87                 dst_address_length=32,
88                 next_hop_address=self.pg8.remote_ip4n,
89                 next_hop_sw_if_index=self.pg8.sw_if_index,
90                 is_add=0)
91
92             for intf in [self.pg7, self.pg8]:
93                 self.vapi.ip_neighbor_add_del(
94                     intf.sw_if_index,
95                     intf.remote_mac,
96                     intf.remote_ip4,
97                     flags=(VppEnum.vl_api_ip_neighbor_flags_t.
98                            IP_API_NEIGHBOR_FLAG_STATIC),
99                     is_add=0)
100
101             if self.pg7.has_ip4_config:
102                 self.pg7.unconfig_ip4()
103
104         self.vapi.nat44_forwarding_enable_disable(0)
105
106         interfaces = self.vapi.nat44_interface_addr_dump()
107         for intf in interfaces:
108             self.vapi.nat44_add_del_interface_addr(intf.sw_if_index,
109                                                    twice_nat=intf.twice_nat,
110                                                    is_add=0)
111
112         self.vapi.nat_ipfix_enable_disable(enable=0,
113                                            src_port=self.ipfix_src_port,
114                                            domain_id=self.ipfix_domain_id)
115         self.ipfix_src_port = 4739
116         self.ipfix_domain_id = 1
117
118         self.vapi.syslog_set_filter(SYSLOG_SEVERITY.EMERG)
119
120         self.vapi.nat_ha_set_listener('0.0.0.0', 0)
121         self.vapi.nat_ha_set_failover('0.0.0.0', 0)
122
123         interfaces = self.vapi.nat44_interface_dump()
124         for intf in interfaces:
125             if intf.is_inside > 1:
126                 self.vapi.nat44_interface_add_del_feature(intf.sw_if_index,
127                                                           0,
128                                                           is_add=0)
129             self.vapi.nat44_interface_add_del_feature(intf.sw_if_index,
130                                                       intf.is_inside,
131                                                       is_add=0)
132
133         interfaces = self.vapi.nat44_interface_output_feature_dump()
134         for intf in interfaces:
135             self.vapi.nat44_interface_add_del_output_feature(intf.sw_if_index,
136                                                              intf.is_inside,
137                                                              is_add=0)
138
139         static_mappings = self.vapi.nat44_static_mapping_dump()
140         for sm in static_mappings:
141             self.vapi.nat44_add_del_static_mapping(
142                 sm.local_ip_address,
143                 sm.external_ip_address,
144                 local_port=sm.local_port,
145                 external_port=sm.external_port,
146                 addr_only=sm.addr_only,
147                 vrf_id=sm.vrf_id,
148                 protocol=sm.protocol,
149                 twice_nat=sm.twice_nat,
150                 self_twice_nat=sm.self_twice_nat,
151                 out2in_only=sm.out2in_only,
152                 tag=sm.tag,
153                 external_sw_if_index=sm.external_sw_if_index,
154                 is_add=0)
155
156         lb_static_mappings = self.vapi.nat44_lb_static_mapping_dump()
157         for lb_sm in lb_static_mappings:
158             self.vapi.nat44_add_del_lb_static_mapping(
159                 lb_sm.external_addr,
160                 lb_sm.external_port,
161                 lb_sm.protocol,
162                 twice_nat=lb_sm.twice_nat,
163                 self_twice_nat=lb_sm.self_twice_nat,
164                 out2in_only=lb_sm.out2in_only,
165                 tag=lb_sm.tag,
166                 is_add=0,
167                 local_num=0,
168                 locals=[])
169
170         identity_mappings = self.vapi.nat44_identity_mapping_dump()
171         for id_m in identity_mappings:
172             self.vapi.nat44_add_del_identity_mapping(
173                 addr_only=id_m.addr_only,
174                 ip=id_m.ip_address,
175                 port=id_m.port,
176                 sw_if_index=id_m.sw_if_index,
177                 vrf_id=id_m.vrf_id,
178                 protocol=id_m.protocol,
179                 is_add=0)
180
181         adresses = self.vapi.nat44_address_dump()
182         for addr in adresses:
183             self.vapi.nat44_add_del_address_range(addr.ip_address,
184                                                   addr.ip_address,
185                                                   twice_nat=addr.twice_nat,
186                                                   is_add=0)
187
188         self.vapi.nat_set_reass()
189         self.vapi.nat_set_reass(is_ip6=1)
190         self.verify_no_nat44_user()
191         self.vapi.nat_set_timeouts()
192         self.vapi.nat_set_addr_and_port_alloc_alg()
193         self.vapi.nat_set_mss_clamping()
194
195     def nat44_add_static_mapping(self, local_ip, external_ip='0.0.0.0',
196                                  local_port=0, external_port=0, vrf_id=0,
197                                  is_add=1, external_sw_if_index=0xFFFFFFFF,
198                                  proto=0, twice_nat=0, self_twice_nat=0,
199                                  out2in_only=0, tag=""):
200         """
201         Add/delete NAT44 static mapping
202
203         :param local_ip: Local IP address
204         :param external_ip: External IP address
205         :param local_port: Local port number (Optional)
206         :param external_port: External port number (Optional)
207         :param vrf_id: VRF ID (Default 0)
208         :param is_add: 1 if add, 0 if delete (Default add)
209         :param external_sw_if_index: External interface instead of IP address
210         :param proto: IP protocol (Mandatory if port specified)
211         :param twice_nat: 1 if translate external host address and port
212         :param self_twice_nat: 1 if translate external host address and port
213                                whenever external host address equals
214                                local address of internal host
215         :param out2in_only: if 1 rule is matching only out2in direction
216         :param tag: Opaque string tag
217         """
218         addr_only = 1
219         if local_port and external_port:
220             addr_only = 0
221         l_ip = socket.inet_pton(socket.AF_INET, local_ip)
222         e_ip = socket.inet_pton(socket.AF_INET, external_ip)
223         self.vapi.nat44_add_del_static_mapping(
224             l_ip,
225             e_ip,
226             external_sw_if_index,
227             local_port,
228             external_port,
229             addr_only,
230             vrf_id,
231             proto,
232             twice_nat,
233             self_twice_nat,
234             out2in_only,
235             tag,
236             is_add)
237
238     def nat44_add_address(self, ip, is_add=1, vrf_id=0xFFFFFFFF, twice_nat=0):
239         """
240         Add/delete NAT44 address
241
242         :param ip: IP address
243         :param is_add: 1 if add, 0 if delete (Default add)
244         :param twice_nat: twice NAT address for extenal hosts
245         """
246         nat_addr = socket.inet_pton(socket.AF_INET, ip)
247         self.vapi.nat44_add_del_address_range(nat_addr, nat_addr, is_add,
248                                               vrf_id=vrf_id,
249                                               twice_nat=twice_nat)
250
251     def create_stream_in(self, in_if, out_if, dst_ip=None, ttl=64):
252         """
253         Create packet stream for inside network
254
255         :param in_if: Inside interface
256         :param out_if: Outside interface
257         :param dst_ip: Destination address
258         :param ttl: TTL of generated packets
259         """
260         if dst_ip is None:
261             dst_ip = out_if.remote_ip4
262
263         pkts = []
264         # TCP
265         p = (Ether(dst=in_if.local_mac, src=in_if.remote_mac) /
266              IP(src=in_if.remote_ip4, dst=dst_ip, ttl=ttl) /
267              TCP(sport=self.tcp_port_in, dport=20))
268         pkts.append(p)
269
270         # UDP
271         p = (Ether(dst=in_if.local_mac, src=in_if.remote_mac) /
272              IP(src=in_if.remote_ip4, dst=dst_ip, ttl=ttl) /
273              UDP(sport=self.udp_port_in, dport=20))
274         pkts.append(p)
275
276         # ICMP
277         p = (Ether(dst=in_if.local_mac, src=in_if.remote_mac) /
278              IP(src=in_if.remote_ip4, dst=dst_ip, ttl=ttl) /
279              ICMP(id=self.icmp_id_in, type='echo-request'))
280         pkts.append(p)
281
282         return pkts
283
284     def compose_ip6(self, ip4, pref, plen):
285         """
286         Compose IPv4-embedded IPv6 addresses
287
288         :param ip4: IPv4 address
289         :param pref: IPv6 prefix
290         :param plen: IPv6 prefix length
291         :returns: IPv4-embedded IPv6 addresses
292         """
293         pref_n = list(socket.inet_pton(socket.AF_INET6, pref))
294         ip4_n = list(socket.inet_pton(socket.AF_INET, ip4))
295         if plen == 32:
296             pref_n[4] = ip4_n[0]
297             pref_n[5] = ip4_n[1]
298             pref_n[6] = ip4_n[2]
299             pref_n[7] = ip4_n[3]
300         elif plen == 40:
301             pref_n[5] = ip4_n[0]
302             pref_n[6] = ip4_n[1]
303             pref_n[7] = ip4_n[2]
304             pref_n[9] = ip4_n[3]
305         elif plen == 48:
306             pref_n[6] = ip4_n[0]
307             pref_n[7] = ip4_n[1]
308             pref_n[9] = ip4_n[2]
309             pref_n[10] = ip4_n[3]
310         elif plen == 56:
311             pref_n[7] = ip4_n[0]
312             pref_n[9] = ip4_n[1]
313             pref_n[10] = ip4_n[2]
314             pref_n[11] = ip4_n[3]
315         elif plen == 64:
316             pref_n[9] = ip4_n[0]
317             pref_n[10] = ip4_n[1]
318             pref_n[11] = ip4_n[2]
319             pref_n[12] = ip4_n[3]
320         elif plen == 96:
321             pref_n[12] = ip4_n[0]
322             pref_n[13] = ip4_n[1]
323             pref_n[14] = ip4_n[2]
324             pref_n[15] = ip4_n[3]
325         packed_pref_n = b''.join([scapy.compat.chb(x) for x in pref_n])
326         return socket.inet_ntop(socket.AF_INET6, packed_pref_n)
327
328     def extract_ip4(self, ip6, plen):
329         """
330         Extract IPv4 address embedded in IPv6 addresses
331
332         :param ip6: IPv6 address
333         :param plen: IPv6 prefix length
334         :returns: extracted IPv4 address
335         """
336         ip6_n = list(socket.inet_pton(socket.AF_INET6, ip6))
337         ip4_n = [None] * 4
338         if plen == 32:
339             ip4_n[0] = ip6_n[4]
340             ip4_n[1] = ip6_n[5]
341             ip4_n[2] = ip6_n[6]
342             ip4_n[3] = ip6_n[7]
343         elif plen == 40:
344             ip4_n[0] = ip6_n[5]
345             ip4_n[1] = ip6_n[6]
346             ip4_n[2] = ip6_n[7]
347             ip4_n[3] = ip6_n[9]
348         elif plen == 48:
349             ip4_n[0] = ip6_n[6]
350             ip4_n[1] = ip6_n[7]
351             ip4_n[2] = ip6_n[9]
352             ip4_n[3] = ip6_n[10]
353         elif plen == 56:
354             ip4_n[0] = ip6_n[7]
355             ip4_n[1] = ip6_n[9]
356             ip4_n[2] = ip6_n[10]
357             ip4_n[3] = ip6_n[11]
358         elif plen == 64:
359             ip4_n[0] = ip6_n[9]
360             ip4_n[1] = ip6_n[10]
361             ip4_n[2] = ip6_n[11]
362             ip4_n[3] = ip6_n[12]
363         elif plen == 96:
364             ip4_n[0] = ip6_n[12]
365             ip4_n[1] = ip6_n[13]
366             ip4_n[2] = ip6_n[14]
367             ip4_n[3] = ip6_n[15]
368         return socket.inet_ntop(socket.AF_INET, ''.join(ip4_n))
369
370     def create_stream_in_ip6(self, in_if, out_if, hlim=64, pref=None, plen=0):
371         """
372         Create IPv6 packet stream for inside network
373
374         :param in_if: Inside interface
375         :param out_if: Outside interface
376         :param ttl: Hop Limit of generated packets
377         :param pref: NAT64 prefix
378         :param plen: NAT64 prefix length
379         """
380         pkts = []
381         if pref is None:
382             dst = ''.join(['64:ff9b::', out_if.remote_ip4])
383         else:
384             dst = self.compose_ip6(out_if.remote_ip4, pref, plen)
385
386         # TCP
387         p = (Ether(dst=in_if.local_mac, src=in_if.remote_mac) /
388              IPv6(src=in_if.remote_ip6, dst=dst, hlim=hlim) /
389              TCP(sport=self.tcp_port_in, dport=20))
390         pkts.append(p)
391
392         # UDP
393         p = (Ether(dst=in_if.local_mac, src=in_if.remote_mac) /
394              IPv6(src=in_if.remote_ip6, dst=dst, hlim=hlim) /
395              UDP(sport=self.udp_port_in, dport=20))
396         pkts.append(p)
397
398         # ICMP
399         p = (Ether(dst=in_if.local_mac, src=in_if.remote_mac) /
400              IPv6(src=in_if.remote_ip6, dst=dst, hlim=hlim) /
401              ICMPv6EchoRequest(id=self.icmp_id_in))
402         pkts.append(p)
403
404         return pkts
405
406     def create_stream_out(self, out_if, dst_ip=None, ttl=64,
407                           use_inside_ports=False):
408         """
409         Create packet stream for outside network
410
411         :param out_if: Outside interface
412         :param dst_ip: Destination IP address (Default use global NAT address)
413         :param ttl: TTL of generated packets
414         :param use_inside_ports: Use inside NAT ports as destination ports
415                instead of outside ports
416         """
417         if dst_ip is None:
418             dst_ip = self.nat_addr
419         if not use_inside_ports:
420             tcp_port = self.tcp_port_out
421             udp_port = self.udp_port_out
422             icmp_id = self.icmp_id_out
423         else:
424             tcp_port = self.tcp_port_in
425             udp_port = self.udp_port_in
426             icmp_id = self.icmp_id_in
427         pkts = []
428         # TCP
429         p = (Ether(dst=out_if.local_mac, src=out_if.remote_mac) /
430              IP(src=out_if.remote_ip4, dst=dst_ip, ttl=ttl) /
431              TCP(dport=tcp_port, sport=20))
432         pkts.append(p)
433
434         # UDP
435         p = (Ether(dst=out_if.local_mac, src=out_if.remote_mac) /
436              IP(src=out_if.remote_ip4, dst=dst_ip, ttl=ttl) /
437              UDP(dport=udp_port, sport=20))
438         pkts.append(p)
439
440         # ICMP
441         p = (Ether(dst=out_if.local_mac, src=out_if.remote_mac) /
442              IP(src=out_if.remote_ip4, dst=dst_ip, ttl=ttl) /
443              ICMP(id=icmp_id, type='echo-reply'))
444         pkts.append(p)
445
446         return pkts
447
448     def create_stream_out_ip6(self, out_if, src_ip, dst_ip, hl=64):
449         """
450         Create packet stream for outside network
451
452         :param out_if: Outside interface
453         :param dst_ip: Destination IP address (Default use global NAT address)
454         :param hl: HL of generated packets
455         """
456         pkts = []
457         # TCP
458         p = (Ether(dst=out_if.local_mac, src=out_if.remote_mac) /
459              IPv6(src=src_ip, dst=dst_ip, hlim=hl) /
460              TCP(dport=self.tcp_port_out, sport=20))
461         pkts.append(p)
462
463         # UDP
464         p = (Ether(dst=out_if.local_mac, src=out_if.remote_mac) /
465              IPv6(src=src_ip, dst=dst_ip, hlim=hl) /
466              UDP(dport=self.udp_port_out, sport=20))
467         pkts.append(p)
468
469         # ICMP
470         p = (Ether(dst=out_if.local_mac, src=out_if.remote_mac) /
471              IPv6(src=src_ip, dst=dst_ip, hlim=hl) /
472              ICMPv6EchoReply(id=self.icmp_id_out))
473         pkts.append(p)
474
475         return pkts
476
477     def verify_capture_out(self, capture, nat_ip=None, same_port=False,
478                            dst_ip=None, is_ip6=False):
479         """
480         Verify captured packets on outside network
481
482         :param capture: Captured packets
483         :param nat_ip: Translated IP address (Default use global NAT address)
484         :param same_port: Sorce port number is not translated (Default False)
485         :param dst_ip: Destination IP address (Default do not verify)
486         :param is_ip6: If L3 protocol is IPv6 (Default False)
487         """
488         if is_ip6:
489             IP46 = IPv6
490             ICMP46 = ICMPv6EchoRequest
491         else:
492             IP46 = IP
493             ICMP46 = ICMP
494         if nat_ip is None:
495             nat_ip = self.nat_addr
496         for packet in capture:
497             try:
498                 if not is_ip6:
499                     self.assert_packet_checksums_valid(packet)
500                 self.assertEqual(packet[IP46].src, nat_ip)
501                 if dst_ip is not None:
502                     self.assertEqual(packet[IP46].dst, dst_ip)
503                 if packet.haslayer(TCP):
504                     if same_port:
505                         self.assertEqual(packet[TCP].sport, self.tcp_port_in)
506                     else:
507                         self.assertNotEqual(
508                             packet[TCP].sport, self.tcp_port_in)
509                     self.tcp_port_out = packet[TCP].sport
510                     self.assert_packet_checksums_valid(packet)
511                 elif packet.haslayer(UDP):
512                     if same_port:
513                         self.assertEqual(packet[UDP].sport, self.udp_port_in)
514                     else:
515                         self.assertNotEqual(
516                             packet[UDP].sport, self.udp_port_in)
517                     self.udp_port_out = packet[UDP].sport
518                 else:
519                     if same_port:
520                         self.assertEqual(packet[ICMP46].id, self.icmp_id_in)
521                     else:
522                         self.assertNotEqual(packet[ICMP46].id, self.icmp_id_in)
523                     self.icmp_id_out = packet[ICMP46].id
524                     self.assert_packet_checksums_valid(packet)
525             except:
526                 self.logger.error(ppp("Unexpected or invalid packet "
527                                       "(outside network):", packet))
528                 raise
529
530     def verify_capture_out_ip6(self, capture, nat_ip, same_port=False,
531                                dst_ip=None):
532         """
533         Verify captured packets on outside network
534
535         :param capture: Captured packets
536         :param nat_ip: Translated IP address
537         :param same_port: Sorce port number is not translated (Default False)
538         :param dst_ip: Destination IP address (Default do not verify)
539         """
540         return self.verify_capture_out(capture, nat_ip, same_port, dst_ip,
541                                        True)
542
543     def verify_capture_in(self, capture, in_if):
544         """
545         Verify captured packets on inside network
546
547         :param capture: Captured packets
548         :param in_if: Inside interface
549         """
550         for packet in capture:
551             try:
552                 self.assert_packet_checksums_valid(packet)
553                 self.assertEqual(packet[IP].dst, in_if.remote_ip4)
554                 if packet.haslayer(TCP):
555                     self.assertEqual(packet[TCP].dport, self.tcp_port_in)
556                 elif packet.haslayer(UDP):
557                     self.assertEqual(packet[UDP].dport, self.udp_port_in)
558                 else:
559                     self.assertEqual(packet[ICMP].id, self.icmp_id_in)
560             except:
561                 self.logger.error(ppp("Unexpected or invalid packet "
562                                       "(inside network):", packet))
563                 raise
564
565     def verify_capture_in_ip6(self, capture, src_ip, dst_ip):
566         """
567         Verify captured IPv6 packets on inside network
568
569         :param capture: Captured packets
570         :param src_ip: Source IP
571         :param dst_ip: Destination IP address
572         """
573         for packet in capture:
574             try:
575                 self.assertEqual(packet[IPv6].src, src_ip)
576                 self.assertEqual(packet[IPv6].dst, dst_ip)
577                 self.assert_packet_checksums_valid(packet)
578                 if packet.haslayer(TCP):
579                     self.assertEqual(packet[TCP].dport, self.tcp_port_in)
580                 elif packet.haslayer(UDP):
581                     self.assertEqual(packet[UDP].dport, self.udp_port_in)
582                 else:
583                     self.assertEqual(packet[ICMPv6EchoReply].id,
584                                      self.icmp_id_in)
585             except:
586                 self.logger.error(ppp("Unexpected or invalid packet "
587                                       "(inside network):", packet))
588                 raise
589
590     def verify_capture_no_translation(self, capture, ingress_if, egress_if):
591         """
592         Verify captured packet that don't have to be translated
593
594         :param capture: Captured packets
595         :param ingress_if: Ingress interface
596         :param egress_if: Egress interface
597         """
598         for packet in capture:
599             try:
600                 self.assertEqual(packet[IP].src, ingress_if.remote_ip4)
601                 self.assertEqual(packet[IP].dst, egress_if.remote_ip4)
602                 if packet.haslayer(TCP):
603                     self.assertEqual(packet[TCP].sport, self.tcp_port_in)
604                 elif packet.haslayer(UDP):
605                     self.assertEqual(packet[UDP].sport, self.udp_port_in)
606                 else:
607                     self.assertEqual(packet[ICMP].id, self.icmp_id_in)
608             except:
609                 self.logger.error(ppp("Unexpected or invalid packet "
610                                       "(inside network):", packet))
611                 raise
612
613     def verify_capture_out_with_icmp_errors(self, capture, src_ip=None,
614                                             icmp_type=11):
615         """
616         Verify captured packets with ICMP errors on outside network
617
618         :param capture: Captured packets
619         :param src_ip: Translated IP address or IP address of VPP
620                        (Default use global NAT address)
621         :param icmp_type: Type of error ICMP packet
622                           we are expecting (Default 11)
623         """
624         if src_ip is None:
625             src_ip = self.nat_addr
626         for packet in capture:
627             try:
628                 self.assertEqual(packet[IP].src, src_ip)
629                 self.assertEqual(packet.haslayer(ICMP), 1)
630                 icmp = packet[ICMP]
631                 self.assertEqual(icmp.type, icmp_type)
632                 self.assertTrue(icmp.haslayer(IPerror))
633                 inner_ip = icmp[IPerror]
634                 if inner_ip.haslayer(TCPerror):
635                     self.assertEqual(inner_ip[TCPerror].dport,
636                                      self.tcp_port_out)
637                 elif inner_ip.haslayer(UDPerror):
638                     self.assertEqual(inner_ip[UDPerror].dport,
639                                      self.udp_port_out)
640                 else:
641                     self.assertEqual(inner_ip[ICMPerror].id, self.icmp_id_out)
642             except:
643                 self.logger.error(ppp("Unexpected or invalid packet "
644                                       "(outside network):", packet))
645                 raise
646
647     def verify_capture_in_with_icmp_errors(self, capture, in_if, icmp_type=11):
648         """
649         Verify captured packets with ICMP errors on inside network
650
651         :param capture: Captured packets
652         :param in_if: Inside interface
653         :param icmp_type: Type of error ICMP packet
654                           we are expecting (Default 11)
655         """
656         for packet in capture:
657             try:
658                 self.assertEqual(packet[IP].dst, in_if.remote_ip4)
659                 self.assertEqual(packet.haslayer(ICMP), 1)
660                 icmp = packet[ICMP]
661                 self.assertEqual(icmp.type, icmp_type)
662                 self.assertTrue(icmp.haslayer(IPerror))
663                 inner_ip = icmp[IPerror]
664                 if inner_ip.haslayer(TCPerror):
665                     self.assertEqual(inner_ip[TCPerror].sport,
666                                      self.tcp_port_in)
667                 elif inner_ip.haslayer(UDPerror):
668                     self.assertEqual(inner_ip[UDPerror].sport,
669                                      self.udp_port_in)
670                 else:
671                     self.assertEqual(inner_ip[ICMPerror].id, self.icmp_id_in)
672             except:
673                 self.logger.error(ppp("Unexpected or invalid packet "
674                                       "(inside network):", packet))
675                 raise
676
677     def create_stream_frag(self, src_if, dst, sport, dport, data,
678                            proto=IP_PROTOS.tcp, echo_reply=False):
679         """
680         Create fragmented packet stream
681
682         :param src_if: Source interface
683         :param dst: Destination IPv4 address
684         :param sport: Source port
685         :param dport: Destination port
686         :param data: Payload data
687         :param proto: protocol (TCP, UDP, ICMP)
688         :param echo_reply: use echo_reply if protocol is ICMP
689         :returns: Fragmets
690         """
691         if proto == IP_PROTOS.tcp:
692             p = (IP(src=src_if.remote_ip4, dst=dst) /
693                  TCP(sport=sport, dport=dport) /
694                  Raw(data))
695             p = p.__class__(scapy.compat.raw(p))
696             chksum = p[TCP].chksum
697             proto_header = TCP(sport=sport, dport=dport, chksum=chksum)
698         elif proto == IP_PROTOS.udp:
699             proto_header = UDP(sport=sport, dport=dport)
700         elif proto == IP_PROTOS.icmp:
701             if not echo_reply:
702                 proto_header = ICMP(id=sport, type='echo-request')
703             else:
704                 proto_header = ICMP(id=sport, type='echo-reply')
705         else:
706             raise Exception("Unsupported protocol")
707         id = random.randint(0, 65535)
708         pkts = []
709         if proto == IP_PROTOS.tcp:
710             raw = Raw(data[0:4])
711         else:
712             raw = Raw(data[0:16])
713         p = (Ether(src=src_if.remote_mac, dst=src_if.local_mac) /
714              IP(src=src_if.remote_ip4, dst=dst, flags="MF", frag=0, id=id) /
715              proto_header /
716              raw)
717         pkts.append(p)
718         if proto == IP_PROTOS.tcp:
719             raw = Raw(data[4:20])
720         else:
721             raw = Raw(data[16:32])
722         p = (Ether(src=src_if.remote_mac, dst=src_if.local_mac) /
723              IP(src=src_if.remote_ip4, dst=dst, flags="MF", frag=3, id=id,
724                 proto=proto) /
725              raw)
726         pkts.append(p)
727         if proto == IP_PROTOS.tcp:
728             raw = Raw(data[20:])
729         else:
730             raw = Raw(data[32:])
731         p = (Ether(src=src_if.remote_mac, dst=src_if.local_mac) /
732              IP(src=src_if.remote_ip4, dst=dst, frag=5, proto=proto,
733                 id=id) /
734              raw)
735         pkts.append(p)
736         return pkts
737
738     def create_stream_frag_ip6(self, src_if, dst, sport, dport, data,
739                                pref=None, plen=0, frag_size=128):
740         """
741         Create fragmented packet stream
742
743         :param src_if: Source interface
744         :param dst: Destination IPv4 address
745         :param sport: Source TCP port
746         :param dport: Destination TCP port
747         :param data: Payload data
748         :param pref: NAT64 prefix
749         :param plen: NAT64 prefix length
750         :param fragsize: size of fragments
751         :returns: Fragmets
752         """
753         if pref is None:
754             dst_ip6 = ''.join(['64:ff9b::', dst])
755         else:
756             dst_ip6 = self.compose_ip6(dst, pref, plen)
757
758         p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
759              IPv6(src=src_if.remote_ip6, dst=dst_ip6) /
760              IPv6ExtHdrFragment(id=random.randint(0, 65535)) /
761              TCP(sport=sport, dport=dport) /
762              Raw(data))
763
764         return fragment6(p, frag_size)
765
766     def reass_frags_and_verify(self, frags, src, dst):
767         """
768         Reassemble and verify fragmented packet
769
770         :param frags: Captured fragments
771         :param src: Source IPv4 address to verify
772         :param dst: Destination IPv4 address to verify
773
774         :returns: Reassembled IPv4 packet
775         """
776         buffer = BytesIO()
777         for p in frags:
778             self.assertEqual(p[IP].src, src)
779             self.assertEqual(p[IP].dst, dst)
780             self.assert_ip_checksum_valid(p)
781             buffer.seek(p[IP].frag * 8)
782             buffer.write(bytes(p[IP].payload))
783         ip = IP(src=frags[0][IP].src, dst=frags[0][IP].dst,
784                 proto=frags[0][IP].proto)
785         if ip.proto == IP_PROTOS.tcp:
786             p = (ip / TCP(buffer.getvalue()))
787             self.assert_tcp_checksum_valid(p)
788         elif ip.proto == IP_PROTOS.udp:
789             p = (ip / UDP(buffer.getvalue()[:8]) /
790                  Raw(buffer.getvalue()[8:]))
791         elif ip.proto == IP_PROTOS.icmp:
792             p = (ip / ICMP(buffer.getvalue()))
793         return p
794
795     def reass_frags_and_verify_ip6(self, frags, src, dst):
796         """
797         Reassemble and verify fragmented packet
798
799         :param frags: Captured fragments
800         :param src: Source IPv6 address to verify
801         :param dst: Destination IPv6 address to verify
802
803         :returns: Reassembled IPv6 packet
804         """
805         buffer = BytesIO()
806         for p in frags:
807             self.assertEqual(p[IPv6].src, src)
808             self.assertEqual(p[IPv6].dst, dst)
809             buffer.seek(p[IPv6ExtHdrFragment].offset * 8)
810             buffer.write(bytes(p[IPv6ExtHdrFragment].payload))
811         ip = IPv6(src=frags[0][IPv6].src, dst=frags[0][IPv6].dst,
812                   nh=frags[0][IPv6ExtHdrFragment].nh)
813         if ip.nh == IP_PROTOS.tcp:
814             p = (ip / TCP(buffer.getvalue()))
815         elif ip.nh == IP_PROTOS.udp:
816             p = (ip / UDP(buffer.getvalue()))
817         self.assert_packet_checksums_valid(p)
818         return p
819
820     def initiate_tcp_session(self, in_if, out_if):
821         """
822         Initiates TCP session
823
824         :param in_if: Inside interface
825         :param out_if: Outside interface
826         """
827         try:
828             # SYN packet in->out
829             p = (Ether(src=in_if.remote_mac, dst=in_if.local_mac) /
830                  IP(src=in_if.remote_ip4, dst=out_if.remote_ip4) /
831                  TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
832                      flags="S"))
833             in_if.add_stream(p)
834             self.pg_enable_capture(self.pg_interfaces)
835             self.pg_start()
836             capture = out_if.get_capture(1)
837             p = capture[0]
838             self.tcp_port_out = p[TCP].sport
839
840             # SYN + ACK packet out->in
841             p = (Ether(src=out_if.remote_mac, dst=out_if.local_mac) /
842                  IP(src=out_if.remote_ip4, dst=self.nat_addr) /
843                  TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
844                      flags="SA"))
845             out_if.add_stream(p)
846             self.pg_enable_capture(self.pg_interfaces)
847             self.pg_start()
848             in_if.get_capture(1)
849
850             # ACK packet in->out
851             p = (Ether(src=in_if.remote_mac, dst=in_if.local_mac) /
852                  IP(src=in_if.remote_ip4, dst=out_if.remote_ip4) /
853                  TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
854                      flags="A"))
855             in_if.add_stream(p)
856             self.pg_enable_capture(self.pg_interfaces)
857             self.pg_start()
858             out_if.get_capture(1)
859
860         except:
861             self.logger.error("TCP 3 way handshake failed")
862             raise
863
864     def verify_ipfix_nat44_ses(self, data):
865         """
866         Verify IPFIX NAT44 session create/delete event
867
868         :param data: Decoded IPFIX data records
869         """
870         nat44_ses_create_num = 0
871         nat44_ses_delete_num = 0
872         self.assertEqual(6, len(data))
873         for record in data:
874             # natEvent
875             self.assertIn(scapy.compat.orb(record[230]), [4, 5])
876             if scapy.compat.orb(record[230]) == 4:
877                 nat44_ses_create_num += 1
878             else:
879                 nat44_ses_delete_num += 1
880             # sourceIPv4Address
881             self.assertEqual(self.pg0.remote_ip4n, record[8])
882             # postNATSourceIPv4Address
883             self.assertEqual(socket.inet_pton(socket.AF_INET, self.nat_addr),
884                              record[225])
885             # ingressVRFID
886             self.assertEqual(struct.pack("!I", 0), record[234])
887             # protocolIdentifier/sourceTransportPort/postNAPTSourceTransportPort
888             if IP_PROTOS.icmp == scapy.compat.orb(record[4]):
889                 self.assertEqual(struct.pack("!H", self.icmp_id_in), record[7])
890                 self.assertEqual(struct.pack("!H", self.icmp_id_out),
891                                  record[227])
892             elif IP_PROTOS.tcp == scapy.compat.orb(record[4]):
893                 self.assertEqual(struct.pack("!H", self.tcp_port_in),
894                                  record[7])
895                 self.assertEqual(struct.pack("!H", self.tcp_port_out),
896                                  record[227])
897             elif IP_PROTOS.udp == scapy.compat.orb(record[4]):
898                 self.assertEqual(struct.pack("!H", self.udp_port_in),
899                                  record[7])
900                 self.assertEqual(struct.pack("!H", self.udp_port_out),
901                                  record[227])
902             else:
903                 self.fail("Invalid protocol")
904         self.assertEqual(3, nat44_ses_create_num)
905         self.assertEqual(3, nat44_ses_delete_num)
906
907     def verify_ipfix_addr_exhausted(self, data):
908         """
909         Verify IPFIX NAT addresses event
910
911         :param data: Decoded IPFIX data records
912         """
913         self.assertEqual(1, len(data))
914         record = data[0]
915         # natEvent
916         self.assertEqual(scapy.compat.orb(record[230]), 3)
917         # natPoolID
918         self.assertEqual(struct.pack("!I", 0), record[283])
919
920     def verify_ipfix_max_sessions(self, data, limit):
921         """
922         Verify IPFIX maximum session entries exceeded event
923
924         :param data: Decoded IPFIX data records
925         :param limit: Number of maximum session entries that can be created.
926         """
927         self.assertEqual(1, len(data))
928         record = data[0]
929         # natEvent
930         self.assertEqual(scapy.compat.orb(record[230]), 13)
931         # natQuotaExceededEvent
932         self.assertEqual(struct.pack("I", 1), record[466])
933         # maxSessionEntries
934         self.assertEqual(struct.pack("I", limit), record[471])
935
936     def verify_ipfix_max_bibs(self, data, limit):
937         """
938         Verify IPFIX maximum BIB entries exceeded event
939
940         :param data: Decoded IPFIX data records
941         :param limit: Number of maximum BIB entries that can be created.
942         """
943         self.assertEqual(1, len(data))
944         record = data[0]
945         # natEvent
946         self.assertEqual(scapy.compat.orb(record[230]), 13)
947         # natQuotaExceededEvent
948         self.assertEqual(struct.pack("I", 2), record[466])
949         # maxBIBEntries
950         self.assertEqual(struct.pack("I", limit), record[472])
951
952     def verify_ipfix_max_fragments_ip6(self, data, limit, src_addr):
953         """
954         Verify IPFIX maximum IPv6 fragments pending reassembly exceeded event
955
956         :param data: Decoded IPFIX data records
957         :param limit: Number of maximum fragments pending reassembly
958         :param src_addr: IPv6 source address
959         """
960         self.assertEqual(1, len(data))
961         record = data[0]
962         # natEvent
963         self.assertEqual(scapy.compat.orb(record[230]), 13)
964         # natQuotaExceededEvent
965         self.assertEqual(struct.pack("I", 5), record[466])
966         # maxFragmentsPendingReassembly
967         self.assertEqual(struct.pack("I", limit), record[475])
968         # sourceIPv6Address
969         self.assertEqual(src_addr, record[27])
970
971     def verify_ipfix_max_fragments_ip4(self, data, limit, src_addr):
972         """
973         Verify IPFIX maximum IPv4 fragments pending reassembly exceeded event
974
975         :param data: Decoded IPFIX data records
976         :param limit: Number of maximum fragments pending reassembly
977         :param src_addr: IPv4 source address
978         """
979         self.assertEqual(1, len(data))
980         record = data[0]
981         # natEvent
982         self.assertEqual(scapy.compat.orb(record[230]), 13)
983         # natQuotaExceededEvent
984         self.assertEqual(struct.pack("I", 5), record[466])
985         # maxFragmentsPendingReassembly
986         self.assertEqual(struct.pack("I", limit), record[475])
987         # sourceIPv4Address
988         self.assertEqual(src_addr, record[8])
989
990     def verify_ipfix_bib(self, data, is_create, src_addr):
991         """
992         Verify IPFIX NAT64 BIB create and delete events
993
994         :param data: Decoded IPFIX data records
995         :param is_create: Create event if nonzero value otherwise delete event
996         :param src_addr: IPv6 source address
997         """
998         self.assertEqual(1, len(data))
999         record = data[0]
1000         # natEvent
1001         if is_create:
1002             self.assertEqual(scapy.compat.orb(record[230]), 10)
1003         else:
1004             self.assertEqual(scapy.compat.orb(record[230]), 11)
1005         # sourceIPv6Address
1006         self.assertEqual(src_addr, record[27])
1007         # postNATSourceIPv4Address
1008         self.assertEqual(self.nat_addr_n, record[225])
1009         # protocolIdentifier
1010         self.assertEqual(IP_PROTOS.tcp, scapy.compat.orb(record[4]))
1011         # ingressVRFID
1012         self.assertEqual(struct.pack("!I", 0), record[234])
1013         # sourceTransportPort
1014         self.assertEqual(struct.pack("!H", self.tcp_port_in), record[7])
1015         # postNAPTSourceTransportPort
1016         self.assertEqual(struct.pack("!H", self.tcp_port_out), record[227])
1017
1018     def verify_ipfix_nat64_ses(self, data, is_create, src_addr, dst_addr,
1019                                dst_port):
1020         """
1021         Verify IPFIX NAT64 session create and delete events
1022
1023         :param data: Decoded IPFIX data records
1024         :param is_create: Create event if nonzero value otherwise delete event
1025         :param src_addr: IPv6 source address
1026         :param dst_addr: IPv4 destination address
1027         :param dst_port: destination TCP port
1028         """
1029         self.assertEqual(1, len(data))
1030         record = data[0]
1031         # natEvent
1032         if is_create:
1033             self.assertEqual(scapy.compat.orb(record[230]), 6)
1034         else:
1035             self.assertEqual(scapy.compat.orb(record[230]), 7)
1036         # sourceIPv6Address
1037         self.assertEqual(src_addr, record[27])
1038         # destinationIPv6Address
1039         self.assertEqual(socket.inet_pton(socket.AF_INET6,
1040                                           self.compose_ip6(dst_addr,
1041                                                            '64:ff9b::',
1042                                                            96)),
1043                          record[28])
1044         # postNATSourceIPv4Address
1045         self.assertEqual(self.nat_addr_n, record[225])
1046         # postNATDestinationIPv4Address
1047         self.assertEqual(socket.inet_pton(socket.AF_INET, dst_addr),
1048                          record[226])
1049         # protocolIdentifier
1050         self.assertEqual(IP_PROTOS.tcp, scapy.compat.orb(record[4]))
1051         # ingressVRFID
1052         self.assertEqual(struct.pack("!I", 0), record[234])
1053         # sourceTransportPort
1054         self.assertEqual(struct.pack("!H", self.tcp_port_in), record[7])
1055         # postNAPTSourceTransportPort
1056         self.assertEqual(struct.pack("!H", self.tcp_port_out), record[227])
1057         # destinationTransportPort
1058         self.assertEqual(struct.pack("!H", dst_port), record[11])
1059         # postNAPTDestinationTransportPort
1060         self.assertEqual(struct.pack("!H", dst_port), record[228])
1061
1062     def verify_no_nat44_user(self):
1063         """ Verify that there is no NAT44 user """
1064         users = self.vapi.nat44_user_dump()
1065         self.assertEqual(len(users), 0)
1066         users = self.statistics.get_counter('/nat44/total-users')
1067         self.assertEqual(users[0][0], 0)
1068         sessions = self.statistics.get_counter('/nat44/total-sessions')
1069         self.assertEqual(sessions[0][0], 0)
1070
1071     def verify_ipfix_max_entries_per_user(self, data, limit, src_addr):
1072         """
1073         Verify IPFIX maximum entries per user exceeded event
1074
1075         :param data: Decoded IPFIX data records
1076         :param limit: Number of maximum entries per user
1077         :param src_addr: IPv4 source address
1078         """
1079         self.assertEqual(1, len(data))
1080         record = data[0]
1081         # natEvent
1082         self.assertEqual(scapy.compat.orb(record[230]), 13)
1083         # natQuotaExceededEvent
1084         self.assertEqual(struct.pack("I", 3), record[466])
1085         # maxEntriesPerUser
1086         self.assertEqual(struct.pack("I", limit), record[473])
1087         # sourceIPv4Address
1088         self.assertEqual(src_addr, record[8])
1089
1090     def verify_syslog_apmap(self, data, is_add=True):
1091         message = data.decode('utf-8')
1092         try:
1093             message = SyslogMessage.parse(message)
1094         except ParseError as e:
1095             self.logger.error(e)
1096             raise
1097         else:
1098             self.assertEqual(message.severity, SyslogSeverity.info)
1099             self.assertEqual(message.appname, 'NAT')
1100             self.assertEqual(message.msgid, 'APMADD' if is_add else 'APMDEL')
1101             sd_params = message.sd.get('napmap')
1102             self.assertTrue(sd_params is not None)
1103             self.assertEqual(sd_params.get('IATYP'), 'IPv4')
1104             self.assertEqual(sd_params.get('ISADDR'), self.pg0.remote_ip4)
1105             self.assertEqual(sd_params.get('ISPORT'), "%d" % self.tcp_port_in)
1106             self.assertEqual(sd_params.get('XATYP'), 'IPv4')
1107             self.assertEqual(sd_params.get('XSADDR'), self.nat_addr)
1108             self.assertEqual(sd_params.get('XSPORT'), "%d" % self.tcp_port_out)
1109             self.assertEqual(sd_params.get('PROTO'), "%d" % IP_PROTOS.tcp)
1110             self.assertTrue(sd_params.get('SSUBIX') is not None)
1111             self.assertEqual(sd_params.get('SVLAN'), '0')
1112
1113     def verify_syslog_sess(self, data, is_add=True, is_ip6=False):
1114         message = data.decode('utf-8')
1115         try:
1116             message = SyslogMessage.parse(message)
1117         except ParseError as e:
1118             self.logger.error(e)
1119             raise
1120         else:
1121             self.assertEqual(message.severity, SyslogSeverity.info)
1122             self.assertEqual(message.appname, 'NAT')
1123             self.assertEqual(message.msgid, 'SADD' if is_add else 'SDEL')
1124             sd_params = message.sd.get('nsess')
1125             self.assertTrue(sd_params is not None)
1126             if is_ip6:
1127                 self.assertEqual(sd_params.get('IATYP'), 'IPv6')
1128                 self.assertEqual(sd_params.get('ISADDR'), self.pg0.remote_ip6)
1129             else:
1130                 self.assertEqual(sd_params.get('IATYP'), 'IPv4')
1131                 self.assertEqual(sd_params.get('ISADDR'), self.pg0.remote_ip4)
1132                 self.assertTrue(sd_params.get('SSUBIX') is not None)
1133             self.assertEqual(sd_params.get('ISPORT'), "%d" % self.tcp_port_in)
1134             self.assertEqual(sd_params.get('XATYP'), 'IPv4')
1135             self.assertEqual(sd_params.get('XSADDR'), self.nat_addr)
1136             self.assertEqual(sd_params.get('XSPORT'), "%d" % self.tcp_port_out)
1137             self.assertEqual(sd_params.get('PROTO'), "%d" % IP_PROTOS.tcp)
1138             self.assertEqual(sd_params.get('SVLAN'), '0')
1139             self.assertEqual(sd_params.get('XDADDR'), self.pg1.remote_ip4)
1140             self.assertEqual(sd_params.get('XDPORT'),
1141                              "%d" % self.tcp_external_port)
1142
1143     def verify_mss_value(self, pkt, mss):
1144         """
1145         Verify TCP MSS value
1146
1147         :param pkt:
1148         :param mss:
1149         """
1150         if not pkt.haslayer(IP) or not pkt.haslayer(TCP):
1151             raise TypeError("Not a TCP/IP packet")
1152
1153         for option in pkt[TCP].options:
1154             if option[0] == 'MSS':
1155                 self.assertEqual(option[1], mss)
1156                 self.assert_tcp_checksum_valid(pkt)
1157
1158     @staticmethod
1159     def proto2layer(proto):
1160         if proto == IP_PROTOS.tcp:
1161             return TCP
1162         elif proto == IP_PROTOS.udp:
1163             return UDP
1164         elif proto == IP_PROTOS.icmp:
1165             return ICMP
1166         else:
1167             raise Exception("Unsupported protocol")
1168
1169     def frag_in_order(self, proto=IP_PROTOS.tcp, dont_translate=False):
1170         layer = self.proto2layer(proto)
1171
1172         if proto == IP_PROTOS.tcp:
1173             data = b"A" * 4 + b"B" * 16 + b"C" * 3
1174         else:
1175             data = b"A" * 16 + b"B" * 16 + b"C" * 3
1176         self.port_in = random.randint(1025, 65535)
1177
1178         reass = self.vapi.nat_reass_dump()
1179         reass_n_start = len(reass)
1180
1181         # in2out
1182         pkts = self.create_stream_frag(self.pg0,
1183                                        self.pg1.remote_ip4,
1184                                        self.port_in,
1185                                        20,
1186                                        data,
1187                                        proto)
1188         self.pg0.add_stream(pkts)
1189         self.pg_enable_capture(self.pg_interfaces)
1190         self.pg_start()
1191         frags = self.pg1.get_capture(len(pkts))
1192         if not dont_translate:
1193             p = self.reass_frags_and_verify(frags,
1194                                             self.nat_addr,
1195                                             self.pg1.remote_ip4)
1196         else:
1197             p = self.reass_frags_and_verify(frags,
1198                                             self.pg0.remote_ip4,
1199                                             self.pg1.remote_ip4)
1200         if proto != IP_PROTOS.icmp:
1201             if not dont_translate:
1202                 self.assertEqual(p[layer].dport, 20)
1203                 self.assertNotEqual(p[layer].sport, self.port_in)
1204             else:
1205                 self.assertEqual(p[layer].sport, self.port_in)
1206         else:
1207             if not dont_translate:
1208                 self.assertNotEqual(p[layer].id, self.port_in)
1209             else:
1210                 self.assertEqual(p[layer].id, self.port_in)
1211         self.assertEqual(data, p[Raw].load)
1212
1213         # out2in
1214         if not dont_translate:
1215             dst_addr = self.nat_addr
1216         else:
1217             dst_addr = self.pg0.remote_ip4
1218         if proto != IP_PROTOS.icmp:
1219             sport = 20
1220             dport = p[layer].sport
1221         else:
1222             sport = p[layer].id
1223             dport = 0
1224         pkts = self.create_stream_frag(self.pg1,
1225                                        dst_addr,
1226                                        sport,
1227                                        dport,
1228                                        data,
1229                                        proto,
1230                                        echo_reply=True)
1231         self.pg1.add_stream(pkts)
1232         self.pg_enable_capture(self.pg_interfaces)
1233         self.pg_start()
1234         frags = self.pg0.get_capture(len(pkts))
1235         p = self.reass_frags_and_verify(frags,
1236                                         self.pg1.remote_ip4,
1237                                         self.pg0.remote_ip4)
1238         if proto != IP_PROTOS.icmp:
1239             self.assertEqual(p[layer].sport, 20)
1240             self.assertEqual(p[layer].dport, self.port_in)
1241         else:
1242             self.assertEqual(p[layer].id, self.port_in)
1243         self.assertEqual(data, p[Raw].load)
1244
1245         reass = self.vapi.nat_reass_dump()
1246         reass_n_end = len(reass)
1247
1248         self.assertEqual(reass_n_end - reass_n_start, 2)
1249
1250     def frag_in_order_in_plus_out(self, proto=IP_PROTOS.tcp):
1251         layer = self.proto2layer(proto)
1252
1253         if proto == IP_PROTOS.tcp:
1254             data = b"A" * 4 + b"B" * 16 + b"C" * 3
1255         else:
1256             data = b"A" * 16 + b"B" * 16 + b"C" * 3
1257         self.port_in = random.randint(1025, 65535)
1258
1259         for i in range(2):
1260             reass = self.vapi.nat_reass_dump()
1261             reass_n_start = len(reass)
1262
1263             # out2in
1264             pkts = self.create_stream_frag(self.pg0,
1265                                            self.server_out_addr,
1266                                            self.port_in,
1267                                            self.server_out_port,
1268                                            data,
1269                                            proto)
1270             self.pg0.add_stream(pkts)
1271             self.pg_enable_capture(self.pg_interfaces)
1272             self.pg_start()
1273             frags = self.pg1.get_capture(len(pkts))
1274             p = self.reass_frags_and_verify(frags,
1275                                             self.pg0.remote_ip4,
1276                                             self.server_in_addr)
1277             if proto != IP_PROTOS.icmp:
1278                 self.assertEqual(p[layer].sport, self.port_in)
1279                 self.assertEqual(p[layer].dport, self.server_in_port)
1280             else:
1281                 self.assertEqual(p[layer].id, self.port_in)
1282             self.assertEqual(data, p[Raw].load)
1283
1284             # in2out
1285             if proto != IP_PROTOS.icmp:
1286                 pkts = self.create_stream_frag(self.pg1,
1287                                                self.pg0.remote_ip4,
1288                                                self.server_in_port,
1289                                                p[layer].sport,
1290                                                data,
1291                                                proto)
1292             else:
1293                 pkts = self.create_stream_frag(self.pg1,
1294                                                self.pg0.remote_ip4,
1295                                                p[layer].id,
1296                                                0,
1297                                                data,
1298                                                proto,
1299                                                echo_reply=True)
1300             self.pg1.add_stream(pkts)
1301             self.pg_enable_capture(self.pg_interfaces)
1302             self.pg_start()
1303             frags = self.pg0.get_capture(len(pkts))
1304             p = self.reass_frags_and_verify(frags,
1305                                             self.server_out_addr,
1306                                             self.pg0.remote_ip4)
1307             if proto != IP_PROTOS.icmp:
1308                 self.assertEqual(p[layer].sport, self.server_out_port)
1309                 self.assertEqual(p[layer].dport, self.port_in)
1310             else:
1311                 self.assertEqual(p[layer].id, self.port_in)
1312             self.assertEqual(data, p[Raw].load)
1313
1314             reass = self.vapi.nat_reass_dump()
1315             reass_n_end = len(reass)
1316
1317             self.assertEqual(reass_n_end - reass_n_start, 2)
1318
1319     def reass_hairpinning(self, proto=IP_PROTOS.tcp):
1320         layer = self.proto2layer(proto)
1321
1322         if proto == IP_PROTOS.tcp:
1323             data = b"A" * 4 + b"B" * 16 + b"C" * 3
1324         else:
1325             data = b"A" * 16 + b"B" * 16 + b"C" * 3
1326
1327         # send packet from host to server
1328         pkts = self.create_stream_frag(self.pg0,
1329                                        self.nat_addr,
1330                                        self.host_in_port,
1331                                        self.server_out_port,
1332                                        data,
1333                                        proto)
1334         self.pg0.add_stream(pkts)
1335         self.pg_enable_capture(self.pg_interfaces)
1336         self.pg_start()
1337         frags = self.pg0.get_capture(len(pkts))
1338         p = self.reass_frags_and_verify(frags,
1339                                         self.nat_addr,
1340                                         self.server.ip4)
1341         if proto != IP_PROTOS.icmp:
1342             self.assertNotEqual(p[layer].sport, self.host_in_port)
1343             self.assertEqual(p[layer].dport, self.server_in_port)
1344         else:
1345             self.assertNotEqual(p[layer].id, self.host_in_port)
1346         self.assertEqual(data, p[Raw].load)
1347
1348     def frag_out_of_order(self, proto=IP_PROTOS.tcp, dont_translate=False):
1349         layer = self.proto2layer(proto)
1350
1351         if proto == IP_PROTOS.tcp:
1352             data = b"A" * 4 + b"B" * 16 + b"C" * 3
1353         else:
1354             data = b"A" * 16 + b"B" * 16 + b"C" * 3
1355         self.port_in = random.randint(1025, 65535)
1356
1357         for i in range(2):
1358             # in2out
1359             pkts = self.create_stream_frag(self.pg0,
1360                                            self.pg1.remote_ip4,
1361                                            self.port_in,
1362                                            20,
1363                                            data,
1364                                            proto)
1365             pkts.reverse()
1366             self.pg0.add_stream(pkts)
1367             self.pg_enable_capture(self.pg_interfaces)
1368             self.pg_start()
1369             frags = self.pg1.get_capture(len(pkts))
1370             if not dont_translate:
1371                 p = self.reass_frags_and_verify(frags,
1372                                                 self.nat_addr,
1373                                                 self.pg1.remote_ip4)
1374             else:
1375                 p = self.reass_frags_and_verify(frags,
1376                                                 self.pg0.remote_ip4,
1377                                                 self.pg1.remote_ip4)
1378             if proto != IP_PROTOS.icmp:
1379                 if not dont_translate:
1380                     self.assertEqual(p[layer].dport, 20)
1381                     self.assertNotEqual(p[layer].sport, self.port_in)
1382                 else:
1383                     self.assertEqual(p[layer].sport, self.port_in)
1384             else:
1385                 if not dont_translate:
1386                     self.assertNotEqual(p[layer].id, self.port_in)
1387                 else:
1388                     self.assertEqual(p[layer].id, self.port_in)
1389             self.assertEqual(data, p[Raw].load)
1390
1391             # out2in
1392             if not dont_translate:
1393                 dst_addr = self.nat_addr
1394             else:
1395                 dst_addr = self.pg0.remote_ip4
1396             if proto != IP_PROTOS.icmp:
1397                 sport = 20
1398                 dport = p[layer].sport
1399             else:
1400                 sport = p[layer].id
1401                 dport = 0
1402             pkts = self.create_stream_frag(self.pg1,
1403                                            dst_addr,
1404                                            sport,
1405                                            dport,
1406                                            data,
1407                                            proto,
1408                                            echo_reply=True)
1409             pkts.reverse()
1410             self.pg1.add_stream(pkts)
1411             self.pg_enable_capture(self.pg_interfaces)
1412             self.pg_start()
1413             frags = self.pg0.get_capture(len(pkts))
1414             p = self.reass_frags_and_verify(frags,
1415                                             self.pg1.remote_ip4,
1416                                             self.pg0.remote_ip4)
1417             if proto != IP_PROTOS.icmp:
1418                 self.assertEqual(p[layer].sport, 20)
1419                 self.assertEqual(p[layer].dport, self.port_in)
1420             else:
1421                 self.assertEqual(p[layer].id, self.port_in)
1422             self.assertEqual(data, p[Raw].load)
1423
1424     def frag_out_of_order_in_plus_out(self, proto=IP_PROTOS.tcp):
1425         layer = self.proto2layer(proto)
1426
1427         if proto == IP_PROTOS.tcp:
1428             data = b"A" * 4 + b"B" * 16 + b"C" * 3
1429         else:
1430             data = b"A" * 16 + b"B" * 16 + b"C" * 3
1431         self.port_in = random.randint(1025, 65535)
1432
1433         for i in range(2):
1434             # out2in
1435             pkts = self.create_stream_frag(self.pg0,
1436                                            self.server_out_addr,
1437                                            self.port_in,
1438                                            self.server_out_port,
1439                                            data,
1440                                            proto)
1441             pkts.reverse()
1442             self.pg0.add_stream(pkts)
1443             self.pg_enable_capture(self.pg_interfaces)
1444             self.pg_start()
1445             frags = self.pg1.get_capture(len(pkts))
1446             p = self.reass_frags_and_verify(frags,
1447                                             self.pg0.remote_ip4,
1448                                             self.server_in_addr)
1449             if proto != IP_PROTOS.icmp:
1450                 self.assertEqual(p[layer].dport, self.server_in_port)
1451                 self.assertEqual(p[layer].sport, self.port_in)
1452                 self.assertEqual(p[layer].dport, self.server_in_port)
1453             else:
1454                 self.assertEqual(p[layer].id, self.port_in)
1455             self.assertEqual(data, p[Raw].load)
1456
1457             # in2out
1458             if proto != IP_PROTOS.icmp:
1459                 pkts = self.create_stream_frag(self.pg1,
1460                                                self.pg0.remote_ip4,
1461                                                self.server_in_port,
1462                                                p[layer].sport,
1463                                                data,
1464                                                proto)
1465             else:
1466                 pkts = self.create_stream_frag(self.pg1,
1467                                                self.pg0.remote_ip4,
1468                                                p[layer].id,
1469                                                0,
1470                                                data,
1471                                                proto,
1472                                                echo_reply=True)
1473             pkts.reverse()
1474             self.pg1.add_stream(pkts)
1475             self.pg_enable_capture(self.pg_interfaces)
1476             self.pg_start()
1477             frags = self.pg0.get_capture(len(pkts))
1478             p = self.reass_frags_and_verify(frags,
1479                                             self.server_out_addr,
1480                                             self.pg0.remote_ip4)
1481             if proto != IP_PROTOS.icmp:
1482                 self.assertEqual(p[layer].sport, self.server_out_port)
1483                 self.assertEqual(p[layer].dport, self.port_in)
1484             else:
1485                 self.assertEqual(p[layer].id, self.port_in)
1486             self.assertEqual(data, p[Raw].load)
1487
1488
1489 class TestNAT44(MethodHolder):
1490     """ NAT44 Test Cases """
1491
1492     @classmethod
1493     def setUpClass(cls):
1494         super(TestNAT44, cls).setUpClass()
1495         cls.vapi.cli("set log class nat level debug")
1496
1497         try:
1498             cls.tcp_port_in = 6303
1499             cls.tcp_port_out = 6303
1500             cls.udp_port_in = 6304
1501             cls.udp_port_out = 6304
1502             cls.icmp_id_in = 6305
1503             cls.icmp_id_out = 6305
1504             cls.nat_addr = '10.0.0.3'
1505             cls.nat_addr_n = socket.inet_pton(socket.AF_INET, cls.nat_addr)
1506             cls.ipfix_src_port = 4739
1507             cls.ipfix_domain_id = 1
1508             cls.tcp_external_port = 80
1509             cls.udp_external_port = 69
1510
1511             cls.create_pg_interfaces(range(10))
1512             cls.interfaces = list(cls.pg_interfaces[0:4])
1513
1514             for i in cls.interfaces:
1515                 i.admin_up()
1516                 i.config_ip4()
1517                 i.resolve_arp()
1518
1519             cls.pg0.generate_remote_hosts(3)
1520             cls.pg0.configure_ipv4_neighbors()
1521
1522             cls.pg1.generate_remote_hosts(1)
1523             cls.pg1.configure_ipv4_neighbors()
1524
1525             cls.overlapping_interfaces = list(list(cls.pg_interfaces[4:7]))
1526             cls.vapi.ip_table_add_del(is_add=1, table_id=10)
1527             cls.vapi.ip_table_add_del(is_add=1, table_id=20)
1528
1529             cls.pg4._local_ip4 = "172.16.255.1"
1530             cls.pg4._local_ip4n = socket.inet_pton(socket.AF_INET, i.local_ip4)
1531             cls.pg4._remote_hosts[0]._ip4 = "172.16.255.2"
1532             cls.pg4.set_table_ip4(10)
1533             cls.pg5._local_ip4 = "172.17.255.3"
1534             cls.pg5._local_ip4n = socket.inet_pton(socket.AF_INET, i.local_ip4)
1535             cls.pg5._remote_hosts[0]._ip4 = "172.17.255.4"
1536             cls.pg5.set_table_ip4(10)
1537             cls.pg6._local_ip4 = "172.16.255.1"
1538             cls.pg6._local_ip4n = socket.inet_pton(socket.AF_INET, i.local_ip4)
1539             cls.pg6._remote_hosts[0]._ip4 = "172.16.255.2"
1540             cls.pg6.set_table_ip4(20)
1541             for i in cls.overlapping_interfaces:
1542                 i.config_ip4()
1543                 i.admin_up()
1544                 i.resolve_arp()
1545
1546             cls.pg7.admin_up()
1547             cls.pg8.admin_up()
1548
1549             cls.pg9.generate_remote_hosts(2)
1550             cls.pg9.config_ip4()
1551             ip_addr_n = socket.inet_pton(socket.AF_INET, "10.0.0.1")
1552             cls.vapi.sw_interface_add_del_address(
1553                 sw_if_index=cls.pg9.sw_if_index, address=ip_addr_n,
1554                 address_length=24)
1555             cls.pg9.admin_up()
1556             cls.pg9.resolve_arp()
1557             cls.pg9._remote_hosts[1]._ip4 = cls.pg9._remote_hosts[0]._ip4
1558             cls.pg4._remote_ip4 = cls.pg9._remote_hosts[0]._ip4 = "10.0.0.2"
1559             cls.pg9.resolve_arp()
1560
1561         except Exception:
1562             super(TestNAT44, cls).tearDownClass()
1563             raise
1564
1565     def test_dynamic(self):
1566         """ NAT44 dynamic translation test """
1567         self.nat44_add_address(self.nat_addr)
1568         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
1569         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
1570                                                   is_inside=0)
1571
1572         # in2out
1573         tcpn = self.statistics.get_counter(
1574             '/err/nat44-in2out-slowpath/TCP packets')
1575         udpn = self.statistics.get_counter(
1576             '/err/nat44-in2out-slowpath/UDP packets')
1577         icmpn = self.statistics.get_counter(
1578             '/err/nat44-in2out-slowpath/ICMP packets')
1579         totaln = self.statistics.get_counter(
1580             '/err/nat44-in2out-slowpath/good in2out packets processed')
1581
1582         pkts = self.create_stream_in(self.pg0, self.pg1)
1583         self.pg0.add_stream(pkts)
1584         self.pg_enable_capture(self.pg_interfaces)
1585         self.pg_start()
1586         capture = self.pg1.get_capture(len(pkts))
1587         self.verify_capture_out(capture)
1588
1589         err = self.statistics.get_counter(
1590             '/err/nat44-in2out-slowpath/TCP packets')
1591         self.assertEqual(err - tcpn, 1)
1592         err = self.statistics.get_counter(
1593             '/err/nat44-in2out-slowpath/UDP packets')
1594         self.assertEqual(err - udpn, 1)
1595         err = self.statistics.get_counter(
1596             '/err/nat44-in2out-slowpath/ICMP packets')
1597         self.assertEqual(err - icmpn, 1)
1598         err = self.statistics.get_counter(
1599             '/err/nat44-in2out-slowpath/good in2out packets processed')
1600         self.assertEqual(err - totaln, 3)
1601
1602         # out2in
1603         tcpn = self.statistics.get_counter('/err/nat44-out2in/TCP packets')
1604         udpn = self.statistics.get_counter('/err/nat44-out2in/UDP packets')
1605         icmpn = self.statistics.get_counter('/err/nat44-out2in/ICMP packets')
1606         totaln = self.statistics.get_counter(
1607             '/err/nat44-out2in/good out2in packets processed')
1608
1609         pkts = self.create_stream_out(self.pg1)
1610         self.pg1.add_stream(pkts)
1611         self.pg_enable_capture(self.pg_interfaces)
1612         self.pg_start()
1613         capture = self.pg0.get_capture(len(pkts))
1614         self.verify_capture_in(capture, self.pg0)
1615
1616         err = self.statistics.get_counter('/err/nat44-out2in/TCP packets')
1617         self.assertEqual(err - tcpn, 1)
1618         err = self.statistics.get_counter('/err/nat44-out2in/UDP packets')
1619         self.assertEqual(err - udpn, 1)
1620         err = self.statistics.get_counter('/err/nat44-out2in/ICMP packets')
1621         self.assertEqual(err - icmpn, 1)
1622         err = self.statistics.get_counter(
1623             '/err/nat44-out2in/good out2in packets processed')
1624         self.assertEqual(err - totaln, 3)
1625
1626         users = self.statistics.get_counter('/nat44/total-users')
1627         self.assertEqual(users[0][0], 1)
1628         sessions = self.statistics.get_counter('/nat44/total-sessions')
1629         self.assertEqual(sessions[0][0], 3)
1630
1631     def test_dynamic_icmp_errors_in2out_ttl_1(self):
1632         """ NAT44 handling of client packets with TTL=1 """
1633
1634         self.nat44_add_address(self.nat_addr)
1635         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
1636         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
1637                                                   is_inside=0)
1638
1639         # Client side - generate traffic
1640         pkts = self.create_stream_in(self.pg0, self.pg1, ttl=1)
1641         self.pg0.add_stream(pkts)
1642         self.pg_enable_capture(self.pg_interfaces)
1643         self.pg_start()
1644
1645         # Client side - verify ICMP type 11 packets
1646         capture = self.pg0.get_capture(len(pkts))
1647         self.verify_capture_in_with_icmp_errors(capture, self.pg0)
1648
1649     def test_dynamic_icmp_errors_out2in_ttl_1(self):
1650         """ NAT44 handling of server packets with TTL=1 """
1651
1652         self.nat44_add_address(self.nat_addr)
1653         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
1654         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
1655                                                   is_inside=0)
1656
1657         # Client side - create sessions
1658         pkts = self.create_stream_in(self.pg0, self.pg1)
1659         self.pg0.add_stream(pkts)
1660         self.pg_enable_capture(self.pg_interfaces)
1661         self.pg_start()
1662
1663         # Server side - generate traffic
1664         capture = self.pg1.get_capture(len(pkts))
1665         self.verify_capture_out(capture)
1666         pkts = self.create_stream_out(self.pg1, ttl=1)
1667         self.pg1.add_stream(pkts)
1668         self.pg_enable_capture(self.pg_interfaces)
1669         self.pg_start()
1670
1671         # Server side - verify ICMP type 11 packets
1672         capture = self.pg1.get_capture(len(pkts))
1673         self.verify_capture_out_with_icmp_errors(capture,
1674                                                  src_ip=self.pg1.local_ip4)
1675
1676     def test_dynamic_icmp_errors_in2out_ttl_2(self):
1677         """ NAT44 handling of error responses to client packets with TTL=2 """
1678
1679         self.nat44_add_address(self.nat_addr)
1680         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
1681         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
1682                                                   is_inside=0)
1683
1684         # Client side - generate traffic
1685         pkts = self.create_stream_in(self.pg0, self.pg1, ttl=2)
1686         self.pg0.add_stream(pkts)
1687         self.pg_enable_capture(self.pg_interfaces)
1688         self.pg_start()
1689
1690         # Server side - simulate ICMP type 11 response
1691         capture = self.pg1.get_capture(len(pkts))
1692         pkts = [Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
1693                 IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
1694                 ICMP(type=11) / packet[IP] for packet in capture]
1695         self.pg1.add_stream(pkts)
1696         self.pg_enable_capture(self.pg_interfaces)
1697         self.pg_start()
1698
1699         # Client side - verify ICMP type 11 packets
1700         capture = self.pg0.get_capture(len(pkts))
1701         self.verify_capture_in_with_icmp_errors(capture, self.pg0)
1702
1703     def test_dynamic_icmp_errors_out2in_ttl_2(self):
1704         """ NAT44 handling of error responses to server packets with TTL=2 """
1705
1706         self.nat44_add_address(self.nat_addr)
1707         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
1708         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
1709                                                   is_inside=0)
1710
1711         # Client side - create sessions
1712         pkts = self.create_stream_in(self.pg0, self.pg1)
1713         self.pg0.add_stream(pkts)
1714         self.pg_enable_capture(self.pg_interfaces)
1715         self.pg_start()
1716
1717         # Server side - generate traffic
1718         capture = self.pg1.get_capture(len(pkts))
1719         self.verify_capture_out(capture)
1720         pkts = self.create_stream_out(self.pg1, ttl=2)
1721         self.pg1.add_stream(pkts)
1722         self.pg_enable_capture(self.pg_interfaces)
1723         self.pg_start()
1724
1725         # Client side - simulate ICMP type 11 response
1726         capture = self.pg0.get_capture(len(pkts))
1727         pkts = [Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
1728                 IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
1729                 ICMP(type=11) / packet[IP] for packet in capture]
1730         self.pg0.add_stream(pkts)
1731         self.pg_enable_capture(self.pg_interfaces)
1732         self.pg_start()
1733
1734         # Server side - verify ICMP type 11 packets
1735         capture = self.pg1.get_capture(len(pkts))
1736         self.verify_capture_out_with_icmp_errors(capture)
1737
1738     def test_ping_out_interface_from_outside(self):
1739         """ Ping NAT44 out interface from outside network """
1740
1741         self.nat44_add_address(self.nat_addr)
1742         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
1743         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
1744                                                   is_inside=0)
1745
1746         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
1747              IP(src=self.pg1.remote_ip4, dst=self.pg1.local_ip4) /
1748              ICMP(id=self.icmp_id_out, type='echo-request'))
1749         pkts = [p]
1750         self.pg1.add_stream(pkts)
1751         self.pg_enable_capture(self.pg_interfaces)
1752         self.pg_start()
1753         capture = self.pg1.get_capture(len(pkts))
1754         packet = capture[0]
1755         try:
1756             self.assertEqual(packet[IP].src, self.pg1.local_ip4)
1757             self.assertEqual(packet[IP].dst, self.pg1.remote_ip4)
1758             self.assertEqual(packet[ICMP].id, self.icmp_id_in)
1759             self.assertEqual(packet[ICMP].type, 0)  # echo reply
1760         except:
1761             self.logger.error(ppp("Unexpected or invalid packet "
1762                                   "(outside network):", packet))
1763             raise
1764
1765     def test_ping_internal_host_from_outside(self):
1766         """ Ping internal host from outside network """
1767
1768         self.nat44_add_static_mapping(self.pg0.remote_ip4, self.nat_addr)
1769         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
1770         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
1771                                                   is_inside=0)
1772
1773         # out2in
1774         pkt = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
1775                IP(src=self.pg1.remote_ip4, dst=self.nat_addr, ttl=64) /
1776                ICMP(id=self.icmp_id_out, type='echo-request'))
1777         self.pg1.add_stream(pkt)
1778         self.pg_enable_capture(self.pg_interfaces)
1779         self.pg_start()
1780         capture = self.pg0.get_capture(1)
1781         self.verify_capture_in(capture, self.pg0)
1782         self.assert_equal(capture[0][IP].proto, IP_PROTOS.icmp)
1783
1784         # in2out
1785         pkt = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
1786                IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4, ttl=64) /
1787                ICMP(id=self.icmp_id_in, type='echo-reply'))
1788         self.pg0.add_stream(pkt)
1789         self.pg_enable_capture(self.pg_interfaces)
1790         self.pg_start()
1791         capture = self.pg1.get_capture(1)
1792         self.verify_capture_out(capture, same_port=True)
1793         self.assert_equal(capture[0][IP].proto, IP_PROTOS.icmp)
1794
1795     def test_forwarding(self):
1796         """ NAT44 forwarding test """
1797
1798         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
1799         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
1800                                                   is_inside=0)
1801         self.vapi.nat44_forwarding_enable_disable(1)
1802
1803         real_ip = self.pg0.remote_ip4n
1804         alias_ip = self.nat_addr_n
1805         self.vapi.nat44_add_del_static_mapping(local_ip=real_ip,
1806                                                external_ip=alias_ip)
1807
1808         try:
1809             # static mapping match
1810
1811             pkts = self.create_stream_out(self.pg1)
1812             self.pg1.add_stream(pkts)
1813             self.pg_enable_capture(self.pg_interfaces)
1814             self.pg_start()
1815             capture = self.pg0.get_capture(len(pkts))
1816             self.verify_capture_in(capture, self.pg0)
1817
1818             pkts = self.create_stream_in(self.pg0, self.pg1)
1819             self.pg0.add_stream(pkts)
1820             self.pg_enable_capture(self.pg_interfaces)
1821             self.pg_start()
1822             capture = self.pg1.get_capture(len(pkts))
1823             self.verify_capture_out(capture, same_port=True)
1824
1825             # no static mapping match
1826
1827             host0 = self.pg0.remote_hosts[0]
1828             self.pg0.remote_hosts[0] = self.pg0.remote_hosts[1]
1829             try:
1830                 pkts = self.create_stream_out(self.pg1,
1831                                               dst_ip=self.pg0.remote_ip4,
1832                                               use_inside_ports=True)
1833                 self.pg1.add_stream(pkts)
1834                 self.pg_enable_capture(self.pg_interfaces)
1835                 self.pg_start()
1836                 capture = self.pg0.get_capture(len(pkts))
1837                 self.verify_capture_in(capture, self.pg0)
1838
1839                 pkts = self.create_stream_in(self.pg0, self.pg1)
1840                 self.pg0.add_stream(pkts)
1841                 self.pg_enable_capture(self.pg_interfaces)
1842                 self.pg_start()
1843                 capture = self.pg1.get_capture(len(pkts))
1844                 self.verify_capture_out(capture, nat_ip=self.pg0.remote_ip4,
1845                                         same_port=True)
1846             finally:
1847                 self.pg0.remote_hosts[0] = host0
1848
1849         finally:
1850             self.vapi.nat44_forwarding_enable_disable(0)
1851             self.vapi.nat44_add_del_static_mapping(local_ip=real_ip,
1852                                                    external_ip=alias_ip,
1853                                                    is_add=0)
1854
1855     def test_static_in(self):
1856         """ 1:1 NAT initialized from inside network """
1857
1858         nat_ip = "10.0.0.10"
1859         self.tcp_port_out = 6303
1860         self.udp_port_out = 6304
1861         self.icmp_id_out = 6305
1862
1863         self.nat44_add_static_mapping(self.pg0.remote_ip4, nat_ip)
1864         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
1865         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
1866                                                   is_inside=0)
1867         sm = self.vapi.nat44_static_mapping_dump()
1868         self.assertEqual(len(sm), 1)
1869         self.assertEqual((sm[0].tag).split('\0', 1)[0], '')
1870         self.assertEqual(sm[0].protocol, 0)
1871         self.assertEqual(sm[0].local_port, 0)
1872         self.assertEqual(sm[0].external_port, 0)
1873
1874         # in2out
1875         pkts = self.create_stream_in(self.pg0, self.pg1)
1876         self.pg0.add_stream(pkts)
1877         self.pg_enable_capture(self.pg_interfaces)
1878         self.pg_start()
1879         capture = self.pg1.get_capture(len(pkts))
1880         self.verify_capture_out(capture, nat_ip, True)
1881
1882         # out2in
1883         pkts = self.create_stream_out(self.pg1, nat_ip)
1884         self.pg1.add_stream(pkts)
1885         self.pg_enable_capture(self.pg_interfaces)
1886         self.pg_start()
1887         capture = self.pg0.get_capture(len(pkts))
1888         self.verify_capture_in(capture, self.pg0)
1889
1890     def test_static_out(self):
1891         """ 1:1 NAT initialized from outside network """
1892
1893         nat_ip = "10.0.0.20"
1894         self.tcp_port_out = 6303
1895         self.udp_port_out = 6304
1896         self.icmp_id_out = 6305
1897         tag = "testTAG"
1898
1899         self.nat44_add_static_mapping(self.pg0.remote_ip4, nat_ip, tag=tag)
1900         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
1901         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
1902                                                   is_inside=0)
1903         sm = self.vapi.nat44_static_mapping_dump()
1904         self.assertEqual(len(sm), 1)
1905         self.assertEqual((sm[0].tag).split('\0', 1)[0], tag)
1906
1907         # out2in
1908         pkts = self.create_stream_out(self.pg1, nat_ip)
1909         self.pg1.add_stream(pkts)
1910         self.pg_enable_capture(self.pg_interfaces)
1911         self.pg_start()
1912         capture = self.pg0.get_capture(len(pkts))
1913         self.verify_capture_in(capture, self.pg0)
1914
1915         # in2out
1916         pkts = self.create_stream_in(self.pg0, self.pg1)
1917         self.pg0.add_stream(pkts)
1918         self.pg_enable_capture(self.pg_interfaces)
1919         self.pg_start()
1920         capture = self.pg1.get_capture(len(pkts))
1921         self.verify_capture_out(capture, nat_ip, True)
1922
1923     def test_static_with_port_in(self):
1924         """ 1:1 NAPT initialized from inside network """
1925
1926         self.tcp_port_out = 3606
1927         self.udp_port_out = 3607
1928         self.icmp_id_out = 3608
1929
1930         self.nat44_add_address(self.nat_addr)
1931         self.nat44_add_static_mapping(self.pg0.remote_ip4, self.nat_addr,
1932                                       self.tcp_port_in, self.tcp_port_out,
1933                                       proto=IP_PROTOS.tcp)
1934         self.nat44_add_static_mapping(self.pg0.remote_ip4, self.nat_addr,
1935                                       self.udp_port_in, self.udp_port_out,
1936                                       proto=IP_PROTOS.udp)
1937         self.nat44_add_static_mapping(self.pg0.remote_ip4, self.nat_addr,
1938                                       self.icmp_id_in, self.icmp_id_out,
1939                                       proto=IP_PROTOS.icmp)
1940         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
1941         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
1942                                                   is_inside=0)
1943
1944         # in2out
1945         pkts = self.create_stream_in(self.pg0, self.pg1)
1946         self.pg0.add_stream(pkts)
1947         self.pg_enable_capture(self.pg_interfaces)
1948         self.pg_start()
1949         capture = self.pg1.get_capture(len(pkts))
1950         self.verify_capture_out(capture)
1951
1952         # out2in
1953         pkts = self.create_stream_out(self.pg1)
1954         self.pg1.add_stream(pkts)
1955         self.pg_enable_capture(self.pg_interfaces)
1956         self.pg_start()
1957         capture = self.pg0.get_capture(len(pkts))
1958         self.verify_capture_in(capture, self.pg0)
1959
1960     def test_static_with_port_out(self):
1961         """ 1:1 NAPT initialized from outside network """
1962
1963         self.tcp_port_out = 30606
1964         self.udp_port_out = 30607
1965         self.icmp_id_out = 30608
1966
1967         self.nat44_add_address(self.nat_addr)
1968         self.nat44_add_static_mapping(self.pg0.remote_ip4, self.nat_addr,
1969                                       self.tcp_port_in, self.tcp_port_out,
1970                                       proto=IP_PROTOS.tcp)
1971         self.nat44_add_static_mapping(self.pg0.remote_ip4, self.nat_addr,
1972                                       self.udp_port_in, self.udp_port_out,
1973                                       proto=IP_PROTOS.udp)
1974         self.nat44_add_static_mapping(self.pg0.remote_ip4, self.nat_addr,
1975                                       self.icmp_id_in, self.icmp_id_out,
1976                                       proto=IP_PROTOS.icmp)
1977         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
1978         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
1979                                                   is_inside=0)
1980
1981         # out2in
1982         pkts = self.create_stream_out(self.pg1)
1983         self.pg1.add_stream(pkts)
1984         self.pg_enable_capture(self.pg_interfaces)
1985         self.pg_start()
1986         capture = self.pg0.get_capture(len(pkts))
1987         self.verify_capture_in(capture, self.pg0)
1988
1989         # in2out
1990         pkts = self.create_stream_in(self.pg0, self.pg1)
1991         self.pg0.add_stream(pkts)
1992         self.pg_enable_capture(self.pg_interfaces)
1993         self.pg_start()
1994         capture = self.pg1.get_capture(len(pkts))
1995         self.verify_capture_out(capture)
1996
1997     def test_static_vrf_aware(self):
1998         """ 1:1 NAT VRF awareness """
1999
2000         nat_ip1 = "10.0.0.30"
2001         nat_ip2 = "10.0.0.40"
2002         self.tcp_port_out = 6303
2003         self.udp_port_out = 6304
2004         self.icmp_id_out = 6305
2005
2006         self.nat44_add_static_mapping(self.pg4.remote_ip4, nat_ip1,
2007                                       vrf_id=10)
2008         self.nat44_add_static_mapping(self.pg0.remote_ip4, nat_ip2,
2009                                       vrf_id=10)
2010         self.vapi.nat44_interface_add_del_feature(self.pg3.sw_if_index,
2011                                                   is_inside=0)
2012         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
2013         self.vapi.nat44_interface_add_del_feature(self.pg4.sw_if_index)
2014
2015         # inside interface VRF match NAT44 static mapping VRF
2016         pkts = self.create_stream_in(self.pg4, self.pg3)
2017         self.pg4.add_stream(pkts)
2018         self.pg_enable_capture(self.pg_interfaces)
2019         self.pg_start()
2020         capture = self.pg3.get_capture(len(pkts))
2021         self.verify_capture_out(capture, nat_ip1, True)
2022
2023         # inside interface VRF don't match NAT44 static mapping VRF (packets
2024         # are dropped)
2025         pkts = self.create_stream_in(self.pg0, self.pg3)
2026         self.pg0.add_stream(pkts)
2027         self.pg_enable_capture(self.pg_interfaces)
2028         self.pg_start()
2029         self.pg3.assert_nothing_captured()
2030
2031     def test_dynamic_to_static(self):
2032         """ Switch from dynamic translation to 1:1NAT """
2033         nat_ip = "10.0.0.10"
2034         self.tcp_port_out = 6303
2035         self.udp_port_out = 6304
2036         self.icmp_id_out = 6305
2037
2038         self.nat44_add_address(self.nat_addr)
2039         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
2040         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
2041                                                   is_inside=0)
2042
2043         # dynamic
2044         pkts = self.create_stream_in(self.pg0, self.pg1)
2045         self.pg0.add_stream(pkts)
2046         self.pg_enable_capture(self.pg_interfaces)
2047         self.pg_start()
2048         capture = self.pg1.get_capture(len(pkts))
2049         self.verify_capture_out(capture)
2050
2051         # 1:1NAT
2052         self.nat44_add_static_mapping(self.pg0.remote_ip4, nat_ip)
2053         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4n, 0)
2054         self.assertEqual(len(sessions), 0)
2055         pkts = self.create_stream_in(self.pg0, self.pg1)
2056         self.pg0.add_stream(pkts)
2057         self.pg_enable_capture(self.pg_interfaces)
2058         self.pg_start()
2059         capture = self.pg1.get_capture(len(pkts))
2060         self.verify_capture_out(capture, nat_ip, True)
2061
2062     def test_identity_nat(self):
2063         """ Identity NAT """
2064
2065         self.vapi.nat44_add_del_identity_mapping(ip=self.pg0.remote_ip4n)
2066         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
2067         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
2068                                                   is_inside=0)
2069
2070         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
2071              IP(src=self.pg1.remote_ip4, dst=self.pg0.remote_ip4) /
2072              TCP(sport=12345, dport=56789))
2073         self.pg1.add_stream(p)
2074         self.pg_enable_capture(self.pg_interfaces)
2075         self.pg_start()
2076         capture = self.pg0.get_capture(1)
2077         p = capture[0]
2078         try:
2079             ip = p[IP]
2080             tcp = p[TCP]
2081             self.assertEqual(ip.dst, self.pg0.remote_ip4)
2082             self.assertEqual(ip.src, self.pg1.remote_ip4)
2083             self.assertEqual(tcp.dport, 56789)
2084             self.assertEqual(tcp.sport, 12345)
2085             self.assert_packet_checksums_valid(p)
2086         except:
2087             self.logger.error(ppp("Unexpected or invalid packet:", p))
2088             raise
2089
2090         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4n, 0)
2091         self.assertEqual(len(sessions), 0)
2092         self.vapi.nat44_add_del_identity_mapping(ip=self.pg0.remote_ip4n,
2093                                                  vrf_id=1)
2094         identity_mappings = self.vapi.nat44_identity_mapping_dump()
2095         self.assertEqual(len(identity_mappings), 2)
2096
2097     def test_multiple_inside_interfaces(self):
2098         """ NAT44 multiple non-overlapping address space inside interfaces """
2099
2100         self.nat44_add_address(self.nat_addr)
2101         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
2102         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index)
2103         self.vapi.nat44_interface_add_del_feature(self.pg3.sw_if_index,
2104                                                   is_inside=0)
2105
2106         # between two NAT44 inside interfaces (no translation)
2107         pkts = self.create_stream_in(self.pg0, self.pg1)
2108         self.pg0.add_stream(pkts)
2109         self.pg_enable_capture(self.pg_interfaces)
2110         self.pg_start()
2111         capture = self.pg1.get_capture(len(pkts))
2112         self.verify_capture_no_translation(capture, self.pg0, self.pg1)
2113
2114         # from NAT44 inside to interface without NAT44 feature (no translation)
2115         pkts = self.create_stream_in(self.pg0, self.pg2)
2116         self.pg0.add_stream(pkts)
2117         self.pg_enable_capture(self.pg_interfaces)
2118         self.pg_start()
2119         capture = self.pg2.get_capture(len(pkts))
2120         self.verify_capture_no_translation(capture, self.pg0, self.pg2)
2121
2122         # in2out 1st interface
2123         pkts = self.create_stream_in(self.pg0, self.pg3)
2124         self.pg0.add_stream(pkts)
2125         self.pg_enable_capture(self.pg_interfaces)
2126         self.pg_start()
2127         capture = self.pg3.get_capture(len(pkts))
2128         self.verify_capture_out(capture)
2129
2130         # out2in 1st interface
2131         pkts = self.create_stream_out(self.pg3)
2132         self.pg3.add_stream(pkts)
2133         self.pg_enable_capture(self.pg_interfaces)
2134         self.pg_start()
2135         capture = self.pg0.get_capture(len(pkts))
2136         self.verify_capture_in(capture, self.pg0)
2137
2138         # in2out 2nd interface
2139         pkts = self.create_stream_in(self.pg1, self.pg3)
2140         self.pg1.add_stream(pkts)
2141         self.pg_enable_capture(self.pg_interfaces)
2142         self.pg_start()
2143         capture = self.pg3.get_capture(len(pkts))
2144         self.verify_capture_out(capture)
2145
2146         # out2in 2nd interface
2147         pkts = self.create_stream_out(self.pg3)
2148         self.pg3.add_stream(pkts)
2149         self.pg_enable_capture(self.pg_interfaces)
2150         self.pg_start()
2151         capture = self.pg1.get_capture(len(pkts))
2152         self.verify_capture_in(capture, self.pg1)
2153
2154     def test_inside_overlapping_interfaces(self):
2155         """ NAT44 multiple inside interfaces with overlapping address space """
2156
2157         static_nat_ip = "10.0.0.10"
2158         self.nat44_add_address(self.nat_addr)
2159         self.vapi.nat44_interface_add_del_feature(self.pg3.sw_if_index,
2160                                                   is_inside=0)
2161         self.vapi.nat44_interface_add_del_feature(self.pg4.sw_if_index)
2162         self.vapi.nat44_interface_add_del_feature(self.pg5.sw_if_index)
2163         self.vapi.nat44_interface_add_del_feature(self.pg6.sw_if_index)
2164         self.nat44_add_static_mapping(self.pg6.remote_ip4, static_nat_ip,
2165                                       vrf_id=20)
2166
2167         # between NAT44 inside interfaces with same VRF (no translation)
2168         pkts = self.create_stream_in(self.pg4, self.pg5)
2169         self.pg4.add_stream(pkts)
2170         self.pg_enable_capture(self.pg_interfaces)
2171         self.pg_start()
2172         capture = self.pg5.get_capture(len(pkts))
2173         self.verify_capture_no_translation(capture, self.pg4, self.pg5)
2174
2175         # between NAT44 inside interfaces with different VRF (hairpinning)
2176         p = (Ether(src=self.pg4.remote_mac, dst=self.pg4.local_mac) /
2177              IP(src=self.pg4.remote_ip4, dst=static_nat_ip) /
2178              TCP(sport=1234, dport=5678))
2179         self.pg4.add_stream(p)
2180         self.pg_enable_capture(self.pg_interfaces)
2181         self.pg_start()
2182         capture = self.pg6.get_capture(1)
2183         p = capture[0]
2184         try:
2185             ip = p[IP]
2186             tcp = p[TCP]
2187             self.assertEqual(ip.src, self.nat_addr)
2188             self.assertEqual(ip.dst, self.pg6.remote_ip4)
2189             self.assertNotEqual(tcp.sport, 1234)
2190             self.assertEqual(tcp.dport, 5678)
2191         except:
2192             self.logger.error(ppp("Unexpected or invalid packet:", p))
2193             raise
2194
2195         # in2out 1st interface
2196         pkts = self.create_stream_in(self.pg4, self.pg3)
2197         self.pg4.add_stream(pkts)
2198         self.pg_enable_capture(self.pg_interfaces)
2199         self.pg_start()
2200         capture = self.pg3.get_capture(len(pkts))
2201         self.verify_capture_out(capture)
2202
2203         # out2in 1st interface
2204         pkts = self.create_stream_out(self.pg3)
2205         self.pg3.add_stream(pkts)
2206         self.pg_enable_capture(self.pg_interfaces)
2207         self.pg_start()
2208         capture = self.pg4.get_capture(len(pkts))
2209         self.verify_capture_in(capture, self.pg4)
2210
2211         # in2out 2nd interface
2212         pkts = self.create_stream_in(self.pg5, self.pg3)
2213         self.pg5.add_stream(pkts)
2214         self.pg_enable_capture(self.pg_interfaces)
2215         self.pg_start()
2216         capture = self.pg3.get_capture(len(pkts))
2217         self.verify_capture_out(capture)
2218
2219         # out2in 2nd interface
2220         pkts = self.create_stream_out(self.pg3)
2221         self.pg3.add_stream(pkts)
2222         self.pg_enable_capture(self.pg_interfaces)
2223         self.pg_start()
2224         capture = self.pg5.get_capture(len(pkts))
2225         self.verify_capture_in(capture, self.pg5)
2226
2227         # pg5 session dump
2228         addresses = self.vapi.nat44_address_dump()
2229         self.assertEqual(len(addresses), 1)
2230         sessions = self.vapi.nat44_user_session_dump(self.pg5.remote_ip4n, 10)
2231         self.assertEqual(len(sessions), 3)
2232         for session in sessions:
2233             self.assertFalse(session.is_static)
2234             self.assertEqual(session.inside_ip_address[0:4],
2235                              self.pg5.remote_ip4n)
2236             self.assertEqual(session.outside_ip_address,
2237                              addresses[0].ip_address)
2238         self.assertEqual(sessions[0].protocol, IP_PROTOS.tcp)
2239         self.assertEqual(sessions[1].protocol, IP_PROTOS.udp)
2240         self.assertEqual(sessions[2].protocol, IP_PROTOS.icmp)
2241         self.assertEqual(sessions[0].inside_port, self.tcp_port_in)
2242         self.assertEqual(sessions[1].inside_port, self.udp_port_in)
2243         self.assertEqual(sessions[2].inside_port, self.icmp_id_in)
2244         self.assertEqual(sessions[0].outside_port, self.tcp_port_out)
2245         self.assertEqual(sessions[1].outside_port, self.udp_port_out)
2246         self.assertEqual(sessions[2].outside_port, self.icmp_id_out)
2247
2248         # in2out 3rd interface
2249         pkts = self.create_stream_in(self.pg6, self.pg3)
2250         self.pg6.add_stream(pkts)
2251         self.pg_enable_capture(self.pg_interfaces)
2252         self.pg_start()
2253         capture = self.pg3.get_capture(len(pkts))
2254         self.verify_capture_out(capture, static_nat_ip, True)
2255
2256         # out2in 3rd interface
2257         pkts = self.create_stream_out(self.pg3, static_nat_ip)
2258         self.pg3.add_stream(pkts)
2259         self.pg_enable_capture(self.pg_interfaces)
2260         self.pg_start()
2261         capture = self.pg6.get_capture(len(pkts))
2262         self.verify_capture_in(capture, self.pg6)
2263
2264         # general user and session dump verifications
2265         users = self.vapi.nat44_user_dump()
2266         self.assertGreaterEqual(len(users), 3)
2267         addresses = self.vapi.nat44_address_dump()
2268         self.assertEqual(len(addresses), 1)
2269         for user in users:
2270             sessions = self.vapi.nat44_user_session_dump(user.ip_address,
2271                                                          user.vrf_id)
2272             for session in sessions:
2273                 self.assertEqual(user.ip_address, session.inside_ip_address)
2274                 self.assertTrue(session.total_bytes > session.total_pkts > 0)
2275                 self.assertTrue(session.protocol in
2276                                 [IP_PROTOS.tcp, IP_PROTOS.udp,
2277                                  IP_PROTOS.icmp])
2278                 self.assertFalse(session.ext_host_valid)
2279
2280         # pg4 session dump
2281         sessions = self.vapi.nat44_user_session_dump(self.pg4.remote_ip4n, 10)
2282         self.assertGreaterEqual(len(sessions), 4)
2283         for session in sessions:
2284             self.assertFalse(session.is_static)
2285             self.assertEqual(session.inside_ip_address[0:4],
2286                              self.pg4.remote_ip4n)
2287             self.assertEqual(session.outside_ip_address,
2288                              addresses[0].ip_address)
2289
2290         # pg6 session dump
2291         sessions = self.vapi.nat44_user_session_dump(self.pg6.remote_ip4n, 20)
2292         self.assertGreaterEqual(len(sessions), 3)
2293         for session in sessions:
2294             self.assertTrue(session.is_static)
2295             self.assertEqual(session.inside_ip_address[0:4],
2296                              self.pg6.remote_ip4n)
2297             self.assertEqual(session.outside_ip_address,
2298                              socket.inet_pton(socket.AF_INET, static_nat_ip))
2299             self.assertTrue(session.inside_port in
2300                             [self.tcp_port_in, self.udp_port_in,
2301                              self.icmp_id_in])
2302
2303     def test_hairpinning(self):
2304         """ NAT44 hairpinning - 1:1 NAPT """
2305
2306         host = self.pg0.remote_hosts[0]
2307         server = self.pg0.remote_hosts[1]
2308         host_in_port = 1234
2309         host_out_port = 0
2310         server_in_port = 5678
2311         server_out_port = 8765
2312
2313         self.nat44_add_address(self.nat_addr)
2314         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
2315         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
2316                                                   is_inside=0)
2317         # add static mapping for server
2318         self.nat44_add_static_mapping(server.ip4, self.nat_addr,
2319                                       server_in_port, server_out_port,
2320                                       proto=IP_PROTOS.tcp)
2321
2322         # send packet from host to server
2323         p = (Ether(src=host.mac, dst=self.pg0.local_mac) /
2324              IP(src=host.ip4, dst=self.nat_addr) /
2325              TCP(sport=host_in_port, dport=server_out_port))
2326         self.pg0.add_stream(p)
2327         self.pg_enable_capture(self.pg_interfaces)
2328         self.pg_start()
2329         capture = self.pg0.get_capture(1)
2330         p = capture[0]
2331         try:
2332             ip = p[IP]
2333             tcp = p[TCP]
2334             self.assertEqual(ip.src, self.nat_addr)
2335             self.assertEqual(ip.dst, server.ip4)
2336             self.assertNotEqual(tcp.sport, host_in_port)
2337             self.assertEqual(tcp.dport, server_in_port)
2338             self.assert_packet_checksums_valid(p)
2339             host_out_port = tcp.sport
2340         except:
2341             self.logger.error(ppp("Unexpected or invalid packet:", p))
2342             raise
2343
2344         # send reply from server to host
2345         p = (Ether(src=server.mac, dst=self.pg0.local_mac) /
2346              IP(src=server.ip4, dst=self.nat_addr) /
2347              TCP(sport=server_in_port, dport=host_out_port))
2348         self.pg0.add_stream(p)
2349         self.pg_enable_capture(self.pg_interfaces)
2350         self.pg_start()
2351         capture = self.pg0.get_capture(1)
2352         p = capture[0]
2353         try:
2354             ip = p[IP]
2355             tcp = p[TCP]
2356             self.assertEqual(ip.src, self.nat_addr)
2357             self.assertEqual(ip.dst, host.ip4)
2358             self.assertEqual(tcp.sport, server_out_port)
2359             self.assertEqual(tcp.dport, host_in_port)
2360             self.assert_packet_checksums_valid(p)
2361         except:
2362             self.logger.error(ppp("Unexpected or invalid packet:", p))
2363             raise
2364
2365     def test_hairpinning2(self):
2366         """ NAT44 hairpinning - 1:1 NAT"""
2367
2368         server1_nat_ip = "10.0.0.10"
2369         server2_nat_ip = "10.0.0.11"
2370         host = self.pg0.remote_hosts[0]
2371         server1 = self.pg0.remote_hosts[1]
2372         server2 = self.pg0.remote_hosts[2]
2373         server_tcp_port = 22
2374         server_udp_port = 20
2375
2376         self.nat44_add_address(self.nat_addr)
2377         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
2378         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
2379                                                   is_inside=0)
2380
2381         # add static mapping for servers
2382         self.nat44_add_static_mapping(server1.ip4, server1_nat_ip)
2383         self.nat44_add_static_mapping(server2.ip4, server2_nat_ip)
2384
2385         # host to server1
2386         pkts = []
2387         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2388              IP(src=host.ip4, dst=server1_nat_ip) /
2389              TCP(sport=self.tcp_port_in, dport=server_tcp_port))
2390         pkts.append(p)
2391         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2392              IP(src=host.ip4, dst=server1_nat_ip) /
2393              UDP(sport=self.udp_port_in, dport=server_udp_port))
2394         pkts.append(p)
2395         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2396              IP(src=host.ip4, dst=server1_nat_ip) /
2397              ICMP(id=self.icmp_id_in, type='echo-request'))
2398         pkts.append(p)
2399         self.pg0.add_stream(pkts)
2400         self.pg_enable_capture(self.pg_interfaces)
2401         self.pg_start()
2402         capture = self.pg0.get_capture(len(pkts))
2403         for packet in capture:
2404             try:
2405                 self.assertEqual(packet[IP].src, self.nat_addr)
2406                 self.assertEqual(packet[IP].dst, server1.ip4)
2407                 if packet.haslayer(TCP):
2408                     self.assertNotEqual(packet[TCP].sport, self.tcp_port_in)
2409                     self.assertEqual(packet[TCP].dport, server_tcp_port)
2410                     self.tcp_port_out = packet[TCP].sport
2411                     self.assert_packet_checksums_valid(packet)
2412                 elif packet.haslayer(UDP):
2413                     self.assertNotEqual(packet[UDP].sport, self.udp_port_in)
2414                     self.assertEqual(packet[UDP].dport, server_udp_port)
2415                     self.udp_port_out = packet[UDP].sport
2416                 else:
2417                     self.assertNotEqual(packet[ICMP].id, self.icmp_id_in)
2418                     self.icmp_id_out = packet[ICMP].id
2419             except:
2420                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
2421                 raise
2422
2423         # server1 to host
2424         pkts = []
2425         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2426              IP(src=server1.ip4, dst=self.nat_addr) /
2427              TCP(sport=server_tcp_port, dport=self.tcp_port_out))
2428         pkts.append(p)
2429         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2430              IP(src=server1.ip4, dst=self.nat_addr) /
2431              UDP(sport=server_udp_port, dport=self.udp_port_out))
2432         pkts.append(p)
2433         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2434              IP(src=server1.ip4, dst=self.nat_addr) /
2435              ICMP(id=self.icmp_id_out, type='echo-reply'))
2436         pkts.append(p)
2437         self.pg0.add_stream(pkts)
2438         self.pg_enable_capture(self.pg_interfaces)
2439         self.pg_start()
2440         capture = self.pg0.get_capture(len(pkts))
2441         for packet in capture:
2442             try:
2443                 self.assertEqual(packet[IP].src, server1_nat_ip)
2444                 self.assertEqual(packet[IP].dst, host.ip4)
2445                 if packet.haslayer(TCP):
2446                     self.assertEqual(packet[TCP].dport, self.tcp_port_in)
2447                     self.assertEqual(packet[TCP].sport, server_tcp_port)
2448                     self.assert_packet_checksums_valid(packet)
2449                 elif packet.haslayer(UDP):
2450                     self.assertEqual(packet[UDP].dport, self.udp_port_in)
2451                     self.assertEqual(packet[UDP].sport, server_udp_port)
2452                 else:
2453                     self.assertEqual(packet[ICMP].id, self.icmp_id_in)
2454             except:
2455                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
2456                 raise
2457
2458         # server2 to server1
2459         pkts = []
2460         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2461              IP(src=server2.ip4, dst=server1_nat_ip) /
2462              TCP(sport=self.tcp_port_in, dport=server_tcp_port))
2463         pkts.append(p)
2464         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2465              IP(src=server2.ip4, dst=server1_nat_ip) /
2466              UDP(sport=self.udp_port_in, dport=server_udp_port))
2467         pkts.append(p)
2468         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2469              IP(src=server2.ip4, dst=server1_nat_ip) /
2470              ICMP(id=self.icmp_id_in, type='echo-request'))
2471         pkts.append(p)
2472         self.pg0.add_stream(pkts)
2473         self.pg_enable_capture(self.pg_interfaces)
2474         self.pg_start()
2475         capture = self.pg0.get_capture(len(pkts))
2476         for packet in capture:
2477             try:
2478                 self.assertEqual(packet[IP].src, server2_nat_ip)
2479                 self.assertEqual(packet[IP].dst, server1.ip4)
2480                 if packet.haslayer(TCP):
2481                     self.assertEqual(packet[TCP].sport, self.tcp_port_in)
2482                     self.assertEqual(packet[TCP].dport, server_tcp_port)
2483                     self.tcp_port_out = packet[TCP].sport
2484                     self.assert_packet_checksums_valid(packet)
2485                 elif packet.haslayer(UDP):
2486                     self.assertEqual(packet[UDP].sport, self.udp_port_in)
2487                     self.assertEqual(packet[UDP].dport, server_udp_port)
2488                     self.udp_port_out = packet[UDP].sport
2489                 else:
2490                     self.assertEqual(packet[ICMP].id, self.icmp_id_in)
2491                     self.icmp_id_out = packet[ICMP].id
2492             except:
2493                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
2494                 raise
2495
2496         # server1 to server2
2497         pkts = []
2498         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2499              IP(src=server1.ip4, dst=server2_nat_ip) /
2500              TCP(sport=server_tcp_port, dport=self.tcp_port_out))
2501         pkts.append(p)
2502         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2503              IP(src=server1.ip4, dst=server2_nat_ip) /
2504              UDP(sport=server_udp_port, dport=self.udp_port_out))
2505         pkts.append(p)
2506         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2507              IP(src=server1.ip4, dst=server2_nat_ip) /
2508              ICMP(id=self.icmp_id_out, type='echo-reply'))
2509         pkts.append(p)
2510         self.pg0.add_stream(pkts)
2511         self.pg_enable_capture(self.pg_interfaces)
2512         self.pg_start()
2513         capture = self.pg0.get_capture(len(pkts))
2514         for packet in capture:
2515             try:
2516                 self.assertEqual(packet[IP].src, server1_nat_ip)
2517                 self.assertEqual(packet[IP].dst, server2.ip4)
2518                 if packet.haslayer(TCP):
2519                     self.assertEqual(packet[TCP].dport, self.tcp_port_in)
2520                     self.assertEqual(packet[TCP].sport, server_tcp_port)
2521                     self.assert_packet_checksums_valid(packet)
2522                 elif packet.haslayer(UDP):
2523                     self.assertEqual(packet[UDP].dport, self.udp_port_in)
2524                     self.assertEqual(packet[UDP].sport, server_udp_port)
2525                 else:
2526                     self.assertEqual(packet[ICMP].id, self.icmp_id_in)
2527             except:
2528                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
2529                 raise
2530
2531     def test_max_translations_per_user(self):
2532         """ MAX translations per user - recycle the least recently used """
2533
2534         self.nat44_add_address(self.nat_addr)
2535         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
2536         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
2537                                                   is_inside=0)
2538
2539         # get maximum number of translations per user
2540         nat44_config = self.vapi.nat_show_config()
2541
2542         # send more than maximum number of translations per user packets
2543         pkts_num = nat44_config.max_translations_per_user + 5
2544         pkts = []
2545         for port in range(0, pkts_num):
2546             p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2547                  IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
2548                  TCP(sport=1025 + port))
2549             pkts.append(p)
2550         self.pg0.add_stream(pkts)
2551         self.pg_enable_capture(self.pg_interfaces)
2552         self.pg_start()
2553
2554         # verify number of translated packet
2555         self.pg1.get_capture(pkts_num)
2556
2557         users = self.vapi.nat44_user_dump()
2558         for user in users:
2559             if user.ip_address == self.pg0.remote_ip4n:
2560                 self.assertEqual(user.nsessions,
2561                                  nat44_config.max_translations_per_user)
2562                 self.assertEqual(user.nstaticsessions, 0)
2563
2564         tcp_port = 22
2565         self.nat44_add_static_mapping(self.pg0.remote_ip4, self.nat_addr,
2566                                       tcp_port, tcp_port,
2567                                       proto=IP_PROTOS.tcp)
2568         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2569              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
2570              TCP(sport=tcp_port))
2571         self.pg0.add_stream(p)
2572         self.pg_enable_capture(self.pg_interfaces)
2573         self.pg_start()
2574         self.pg1.get_capture(1)
2575         users = self.vapi.nat44_user_dump()
2576         for user in users:
2577             if user.ip_address == self.pg0.remote_ip4n:
2578                 self.assertEqual(user.nsessions,
2579                                  nat44_config.max_translations_per_user - 1)
2580                 self.assertEqual(user.nstaticsessions, 1)
2581
2582     def test_interface_addr(self):
2583         """ Acquire NAT44 addresses from interface """
2584         self.vapi.nat44_add_del_interface_addr(self.pg7.sw_if_index)
2585
2586         # no address in NAT pool
2587         adresses = self.vapi.nat44_address_dump()
2588         self.assertEqual(0, len(adresses))
2589
2590         # configure interface address and check NAT address pool
2591         self.pg7.config_ip4()
2592         adresses = self.vapi.nat44_address_dump()
2593         self.assertEqual(1, len(adresses))
2594         self.assertEqual(adresses[0].ip_address[0:4], self.pg7.local_ip4n)
2595
2596         # remove interface address and check NAT address pool
2597         self.pg7.unconfig_ip4()
2598         adresses = self.vapi.nat44_address_dump()
2599         self.assertEqual(0, len(adresses))
2600
2601     def test_interface_addr_static_mapping(self):
2602         """ Static mapping with addresses from interface """
2603         tag = "testTAG"
2604
2605         self.vapi.nat44_add_del_interface_addr(self.pg7.sw_if_index)
2606         self.nat44_add_static_mapping(
2607             '1.2.3.4',
2608             external_sw_if_index=self.pg7.sw_if_index,
2609             tag=tag)
2610
2611         # static mappings with external interface
2612         static_mappings = self.vapi.nat44_static_mapping_dump()
2613         self.assertEqual(1, len(static_mappings))
2614         self.assertEqual(self.pg7.sw_if_index,
2615                          static_mappings[0].external_sw_if_index)
2616         self.assertEqual((static_mappings[0].tag).split('\0', 1)[0], tag)
2617
2618         # configure interface address and check static mappings
2619         self.pg7.config_ip4()
2620         static_mappings = self.vapi.nat44_static_mapping_dump()
2621         self.assertEqual(2, len(static_mappings))
2622         resolved = False
2623         for sm in static_mappings:
2624             if sm.external_sw_if_index == 0xFFFFFFFF:
2625                 self.assertEqual(sm.external_ip_address[0:4],
2626                                  self.pg7.local_ip4n)
2627                 self.assertEqual((sm.tag).split('\0', 1)[0], tag)
2628                 resolved = True
2629         self.assertTrue(resolved)
2630
2631         # remove interface address and check static mappings
2632         self.pg7.unconfig_ip4()
2633         static_mappings = self.vapi.nat44_static_mapping_dump()
2634         self.assertEqual(1, len(static_mappings))
2635         self.assertEqual(self.pg7.sw_if_index,
2636                          static_mappings[0].external_sw_if_index)
2637         self.assertEqual((static_mappings[0].tag).split('\0', 1)[0], tag)
2638
2639         # configure interface address again and check static mappings
2640         self.pg7.config_ip4()
2641         static_mappings = self.vapi.nat44_static_mapping_dump()
2642         self.assertEqual(2, len(static_mappings))
2643         resolved = False
2644         for sm in static_mappings:
2645             if sm.external_sw_if_index == 0xFFFFFFFF:
2646                 self.assertEqual(sm.external_ip_address[0:4],
2647                                  self.pg7.local_ip4n)
2648                 self.assertEqual((sm.tag).split('\0', 1)[0], tag)
2649                 resolved = True
2650         self.assertTrue(resolved)
2651
2652         # remove static mapping
2653         self.nat44_add_static_mapping(
2654             '1.2.3.4',
2655             external_sw_if_index=self.pg7.sw_if_index,
2656             tag=tag,
2657             is_add=0)
2658         static_mappings = self.vapi.nat44_static_mapping_dump()
2659         self.assertEqual(0, len(static_mappings))
2660
2661     def test_interface_addr_identity_nat(self):
2662         """ Identity NAT with addresses from interface """
2663
2664         port = 53053
2665         self.vapi.nat44_add_del_interface_addr(self.pg7.sw_if_index)
2666         self.vapi.nat44_add_del_identity_mapping(
2667             sw_if_index=self.pg7.sw_if_index,
2668             port=port,
2669             protocol=IP_PROTOS.tcp,
2670             addr_only=0)
2671
2672         # identity mappings with external interface
2673         identity_mappings = self.vapi.nat44_identity_mapping_dump()
2674         self.assertEqual(1, len(identity_mappings))
2675         self.assertEqual(self.pg7.sw_if_index,
2676                          identity_mappings[0].sw_if_index)
2677
2678         # configure interface address and check identity mappings
2679         self.pg7.config_ip4()
2680         identity_mappings = self.vapi.nat44_identity_mapping_dump()
2681         resolved = False
2682         self.assertEqual(2, len(identity_mappings))
2683         for sm in identity_mappings:
2684             if sm.sw_if_index == 0xFFFFFFFF:
2685                 self.assertEqual(identity_mappings[0].ip_address,
2686                                  self.pg7.local_ip4n)
2687                 self.assertEqual(port, identity_mappings[0].port)
2688                 self.assertEqual(IP_PROTOS.tcp, identity_mappings[0].protocol)
2689                 resolved = True
2690         self.assertTrue(resolved)
2691
2692         # remove interface address and check identity mappings
2693         self.pg7.unconfig_ip4()
2694         identity_mappings = self.vapi.nat44_identity_mapping_dump()
2695         self.assertEqual(1, len(identity_mappings))
2696         self.assertEqual(self.pg7.sw_if_index,
2697                          identity_mappings[0].sw_if_index)
2698
2699     def test_ipfix_nat44_sess(self):
2700         """ IPFIX logging NAT44 session created/delted """
2701         self.ipfix_domain_id = 10
2702         self.ipfix_src_port = 20202
2703         colector_port = 30303
2704         bind_layers(UDP, IPFIX, dport=30303)
2705         self.nat44_add_address(self.nat_addr)
2706         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
2707         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
2708                                                   is_inside=0)
2709         self.vapi.set_ipfix_exporter(collector_address=self.pg3.remote_ip4n,
2710                                      src_address=self.pg3.local_ip4n,
2711                                      path_mtu=512,
2712                                      template_interval=10,
2713                                      collector_port=colector_port)
2714         self.vapi.nat_ipfix_enable_disable(domain_id=self.ipfix_domain_id,
2715                                            src_port=self.ipfix_src_port)
2716
2717         pkts = self.create_stream_in(self.pg0, self.pg1)
2718         self.pg0.add_stream(pkts)
2719         self.pg_enable_capture(self.pg_interfaces)
2720         self.pg_start()
2721         capture = self.pg1.get_capture(len(pkts))
2722         self.verify_capture_out(capture)
2723         self.nat44_add_address(self.nat_addr, is_add=0)
2724         self.vapi.cli("ipfix flush")  # FIXME this should be an API call
2725         capture = self.pg3.get_capture(9)
2726         ipfix = IPFIXDecoder()
2727         # first load template
2728         for p in capture:
2729             self.assertTrue(p.haslayer(IPFIX))
2730             self.assertEqual(p[IP].src, self.pg3.local_ip4)
2731             self.assertEqual(p[IP].dst, self.pg3.remote_ip4)
2732             self.assertEqual(p[UDP].sport, self.ipfix_src_port)
2733             self.assertEqual(p[UDP].dport, colector_port)
2734             self.assertEqual(p[IPFIX].observationDomainID,
2735                              self.ipfix_domain_id)
2736             if p.haslayer(Template):
2737                 ipfix.add_template(p.getlayer(Template))
2738         # verify events in data set
2739         for p in capture:
2740             if p.haslayer(Data):
2741                 data = ipfix.decode_data_set(p.getlayer(Set))
2742                 self.verify_ipfix_nat44_ses(data)
2743
2744     def test_ipfix_addr_exhausted(self):
2745         """ IPFIX logging NAT addresses exhausted """
2746         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
2747         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
2748                                                   is_inside=0)
2749         self.vapi.set_ipfix_exporter(collector_address=self.pg3.remote_ip4n,
2750                                      src_address=self.pg3.local_ip4n,
2751                                      path_mtu=512,
2752                                      template_interval=10)
2753         self.vapi.nat_ipfix_enable_disable(domain_id=self.ipfix_domain_id,
2754                                            src_port=self.ipfix_src_port)
2755
2756         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
2757              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
2758              TCP(sport=3025))
2759         self.pg0.add_stream(p)
2760         self.pg_enable_capture(self.pg_interfaces)
2761         self.pg_start()
2762         self.pg1.assert_nothing_captured()
2763         sleep(1)
2764         self.vapi.cli("ipfix flush")  # FIXME this should be an API call
2765         capture = self.pg3.get_capture(9)
2766         ipfix = IPFIXDecoder()
2767         # first load template
2768         for p in capture:
2769             self.assertTrue(p.haslayer(IPFIX))
2770             self.assertEqual(p[IP].src, self.pg3.local_ip4)
2771             self.assertEqual(p[IP].dst, self.pg3.remote_ip4)
2772             self.assertEqual(p[UDP].sport, self.ipfix_src_port)
2773             self.assertEqual(p[UDP].dport, 4739)
2774             self.assertEqual(p[IPFIX].observationDomainID,
2775                              self.ipfix_domain_id)
2776             if p.haslayer(Template):
2777                 ipfix.add_template(p.getlayer(Template))
2778         # verify events in data set
2779         for p in capture:
2780             if p.haslayer(Data):
2781                 data = ipfix.decode_data_set(p.getlayer(Set))
2782                 self.verify_ipfix_addr_exhausted(data)
2783
2784     @unittest.skipUnless(running_extended_tests, "part of extended tests")
2785     def test_ipfix_max_sessions(self):
2786         """ IPFIX logging maximum session entries exceeded """
2787         self.nat44_add_address(self.nat_addr)
2788         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
2789         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
2790                                                   is_inside=0)
2791
2792         nat44_config = self.vapi.nat_show_config()
2793         max_sessions = 10 * nat44_config.translation_buckets
2794
2795         pkts = []
2796         for i in range(0, max_sessions):
2797             src = "10.10.%u.%u" % ((i & 0xFF00) >> 8, i & 0xFF)
2798             p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2799                  IP(src=src, dst=self.pg1.remote_ip4) /
2800                  TCP(sport=1025))
2801             pkts.append(p)
2802         self.pg0.add_stream(pkts)
2803         self.pg_enable_capture(self.pg_interfaces)
2804         self.pg_start()
2805
2806         self.pg1.get_capture(max_sessions)
2807         self.vapi.set_ipfix_exporter(collector_address=self.pg3.remote_ip4n,
2808                                      src_address=self.pg3.local_ip4n,
2809                                      path_mtu=512,
2810                                      template_interval=10)
2811         self.vapi.nat_ipfix_enable_disable(domain_id=self.ipfix_domain_id,
2812                                            src_port=self.ipfix_src_port)
2813
2814         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2815              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
2816              TCP(sport=1025))
2817         self.pg0.add_stream(p)
2818         self.pg_enable_capture(self.pg_interfaces)
2819         self.pg_start()
2820         self.pg1.assert_nothing_captured()
2821         sleep(1)
2822         self.vapi.cli("ipfix flush")  # FIXME this should be an API call
2823         capture = self.pg3.get_capture(9)
2824         ipfix = IPFIXDecoder()
2825         # first load template
2826         for p in capture:
2827             self.assertTrue(p.haslayer(IPFIX))
2828             self.assertEqual(p[IP].src, self.pg3.local_ip4)
2829             self.assertEqual(p[IP].dst, self.pg3.remote_ip4)
2830             self.assertEqual(p[UDP].sport, self.ipfix_src_port)
2831             self.assertEqual(p[UDP].dport, 4739)
2832             self.assertEqual(p[IPFIX].observationDomainID,
2833                              self.ipfix_domain_id)
2834             if p.haslayer(Template):
2835                 ipfix.add_template(p.getlayer(Template))
2836         # verify events in data set
2837         for p in capture:
2838             if p.haslayer(Data):
2839                 data = ipfix.decode_data_set(p.getlayer(Set))
2840                 self.verify_ipfix_max_sessions(data, max_sessions)
2841
2842     def test_syslog_apmap(self):
2843         """ Test syslog address and port mapping creation and deletion """
2844         self.vapi.syslog_set_filter(SYSLOG_SEVERITY.INFO)
2845         self.vapi.syslog_set_sender(self.pg3.local_ip4n, self.pg3.remote_ip4n)
2846         self.nat44_add_address(self.nat_addr)
2847         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
2848         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
2849                                                   is_inside=0)
2850
2851         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
2852              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
2853              TCP(sport=self.tcp_port_in, dport=20))
2854         self.pg0.add_stream(p)
2855         self.pg_enable_capture(self.pg_interfaces)
2856         self.pg_start()
2857         capture = self.pg1.get_capture(1)
2858         self.tcp_port_out = capture[0][TCP].sport
2859         capture = self.pg3.get_capture(1)
2860         self.verify_syslog_apmap(capture[0][Raw].load)
2861
2862         self.pg_enable_capture(self.pg_interfaces)
2863         self.pg_start()
2864         self.nat44_add_address(self.nat_addr, is_add=0)
2865         capture = self.pg3.get_capture(1)
2866         self.verify_syslog_apmap(capture[0][Raw].load, False)
2867
2868     def test_pool_addr_fib(self):
2869         """ NAT44 add pool addresses to FIB """
2870         static_addr = '10.0.0.10'
2871         self.nat44_add_address(self.nat_addr)
2872         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
2873         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
2874                                                   is_inside=0)
2875         self.nat44_add_static_mapping(self.pg0.remote_ip4, static_addr)
2876
2877         # NAT44 address
2878         p = (Ether(src=self.pg1.remote_mac, dst='ff:ff:ff:ff:ff:ff') /
2879              ARP(op=ARP.who_has, pdst=self.nat_addr,
2880                  psrc=self.pg1.remote_ip4, hwsrc=self.pg1.remote_mac))
2881         self.pg1.add_stream(p)
2882         self.pg_enable_capture(self.pg_interfaces)
2883         self.pg_start()
2884         capture = self.pg1.get_capture(1)
2885         self.assertTrue(capture[0].haslayer(ARP))
2886         self.assertTrue(capture[0][ARP].op, ARP.is_at)
2887
2888         # 1:1 NAT address
2889         p = (Ether(src=self.pg1.remote_mac, dst='ff:ff:ff:ff:ff:ff') /
2890              ARP(op=ARP.who_has, pdst=static_addr,
2891                  psrc=self.pg1.remote_ip4, hwsrc=self.pg1.remote_mac))
2892         self.pg1.add_stream(p)
2893         self.pg_enable_capture(self.pg_interfaces)
2894         self.pg_start()
2895         capture = self.pg1.get_capture(1)
2896         self.assertTrue(capture[0].haslayer(ARP))
2897         self.assertTrue(capture[0][ARP].op, ARP.is_at)
2898
2899         # send ARP to non-NAT44 interface
2900         p = (Ether(src=self.pg2.remote_mac, dst='ff:ff:ff:ff:ff:ff') /
2901              ARP(op=ARP.who_has, pdst=self.nat_addr,
2902                  psrc=self.pg2.remote_ip4, hwsrc=self.pg2.remote_mac))
2903         self.pg2.add_stream(p)
2904         self.pg_enable_capture(self.pg_interfaces)
2905         self.pg_start()
2906         self.pg1.assert_nothing_captured()
2907
2908         # remove addresses and verify
2909         self.nat44_add_address(self.nat_addr, is_add=0)
2910         self.nat44_add_static_mapping(self.pg0.remote_ip4, static_addr,
2911                                       is_add=0)
2912
2913         p = (Ether(src=self.pg1.remote_mac, dst='ff:ff:ff:ff:ff:ff') /
2914              ARP(op=ARP.who_has, pdst=self.nat_addr,
2915                  psrc=self.pg1.remote_ip4, hwsrc=self.pg1.remote_mac))
2916         self.pg1.add_stream(p)
2917         self.pg_enable_capture(self.pg_interfaces)
2918         self.pg_start()
2919         self.pg1.assert_nothing_captured()
2920
2921         p = (Ether(src=self.pg1.remote_mac, dst='ff:ff:ff:ff:ff:ff') /
2922              ARP(op=ARP.who_has, pdst=static_addr,
2923                  psrc=self.pg1.remote_ip4, hwsrc=self.pg1.remote_mac))
2924         self.pg1.add_stream(p)
2925         self.pg_enable_capture(self.pg_interfaces)
2926         self.pg_start()
2927         self.pg1.assert_nothing_captured()
2928
2929     def test_vrf_mode(self):
2930         """ NAT44 tenant VRF aware address pool mode """
2931
2932         vrf_id1 = 1
2933         vrf_id2 = 2
2934         nat_ip1 = "10.0.0.10"
2935         nat_ip2 = "10.0.0.11"
2936
2937         self.pg0.unconfig_ip4()
2938         self.pg1.unconfig_ip4()
2939         self.vapi.ip_table_add_del(is_add=1, table_id=vrf_id1)
2940         self.vapi.ip_table_add_del(is_add=1, table_id=vrf_id2)
2941         self.pg0.set_table_ip4(vrf_id1)
2942         self.pg1.set_table_ip4(vrf_id2)
2943         self.pg0.config_ip4()
2944         self.pg1.config_ip4()
2945         self.pg0.resolve_arp()
2946         self.pg1.resolve_arp()
2947
2948         self.nat44_add_address(nat_ip1, vrf_id=vrf_id1)
2949         self.nat44_add_address(nat_ip2, vrf_id=vrf_id2)
2950         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
2951         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index)
2952         self.vapi.nat44_interface_add_del_feature(self.pg2.sw_if_index,
2953                                                   is_inside=0)
2954
2955         try:
2956             # first VRF
2957             pkts = self.create_stream_in(self.pg0, self.pg2)
2958             self.pg0.add_stream(pkts)
2959             self.pg_enable_capture(self.pg_interfaces)
2960             self.pg_start()
2961             capture = self.pg2.get_capture(len(pkts))
2962             self.verify_capture_out(capture, nat_ip1)
2963
2964             # second VRF
2965             pkts = self.create_stream_in(self.pg1, self.pg2)
2966             self.pg1.add_stream(pkts)
2967             self.pg_enable_capture(self.pg_interfaces)
2968             self.pg_start()
2969             capture = self.pg2.get_capture(len(pkts))
2970             self.verify_capture_out(capture, nat_ip2)
2971
2972         finally:
2973             self.pg0.unconfig_ip4()
2974             self.pg1.unconfig_ip4()
2975             self.pg0.set_table_ip4(0)
2976             self.pg1.set_table_ip4(0)
2977             self.pg0.config_ip4()
2978             self.pg1.config_ip4()
2979             self.pg0.resolve_arp()
2980             self.pg1.resolve_arp()
2981             self.vapi.ip_table_add_del(is_add=0, table_id=vrf_id1)
2982             self.vapi.ip_table_add_del(is_add=0, table_id=vrf_id2)
2983
2984     def test_vrf_feature_independent(self):
2985         """ NAT44 tenant VRF independent address pool mode """
2986
2987         nat_ip1 = "10.0.0.10"
2988         nat_ip2 = "10.0.0.11"
2989
2990         self.nat44_add_address(nat_ip1)
2991         self.nat44_add_address(nat_ip2, vrf_id=99)
2992         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
2993         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index)
2994         self.vapi.nat44_interface_add_del_feature(self.pg2.sw_if_index,
2995                                                   is_inside=0)
2996
2997         # first VRF
2998         pkts = self.create_stream_in(self.pg0, self.pg2)
2999         self.pg0.add_stream(pkts)
3000         self.pg_enable_capture(self.pg_interfaces)
3001         self.pg_start()
3002         capture = self.pg2.get_capture(len(pkts))
3003         self.verify_capture_out(capture, nat_ip1)
3004
3005         # second VRF
3006         pkts = self.create_stream_in(self.pg1, self.pg2)
3007         self.pg1.add_stream(pkts)
3008         self.pg_enable_capture(self.pg_interfaces)
3009         self.pg_start()
3010         capture = self.pg2.get_capture(len(pkts))
3011         self.verify_capture_out(capture, nat_ip1)
3012
3013     def test_dynamic_ipless_interfaces(self):
3014         """ NAT44 interfaces without configured IP address """
3015
3016         self.vapi.ip_neighbor_add_del(
3017             self.pg7.sw_if_index,
3018             self.pg7.remote_mac,
3019             self.pg7.remote_ip4,
3020             flags=(VppEnum.vl_api_ip_neighbor_flags_t.
3021                    IP_API_NEIGHBOR_FLAG_STATIC))
3022         self.vapi.ip_neighbor_add_del(
3023             self.pg8.sw_if_index,
3024             self.pg8.remote_mac,
3025             self.pg8.remote_ip4,
3026             flags=(VppEnum.vl_api_ip_neighbor_flags_t.
3027                    IP_API_NEIGHBOR_FLAG_STATIC))
3028
3029         self.vapi.ip_add_del_route(dst_address=self.pg7.remote_ip4n,
3030                                    dst_address_length=32,
3031                                    next_hop_address=self.pg7.remote_ip4n,
3032                                    next_hop_sw_if_index=self.pg7.sw_if_index)
3033         self.vapi.ip_add_del_route(dst_address=self.pg8.remote_ip4n,
3034                                    dst_address_length=32,
3035                                    next_hop_address=self.pg8.remote_ip4n,
3036                                    next_hop_sw_if_index=self.pg8.sw_if_index)
3037
3038         self.nat44_add_address(self.nat_addr)
3039         self.vapi.nat44_interface_add_del_feature(self.pg7.sw_if_index)
3040         self.vapi.nat44_interface_add_del_feature(self.pg8.sw_if_index,
3041                                                   is_inside=0)
3042
3043         # in2out
3044         pkts = self.create_stream_in(self.pg7, self.pg8)
3045         self.pg7.add_stream(pkts)
3046         self.pg_enable_capture(self.pg_interfaces)
3047         self.pg_start()
3048         capture = self.pg8.get_capture(len(pkts))
3049         self.verify_capture_out(capture)
3050
3051         # out2in
3052         pkts = self.create_stream_out(self.pg8, self.nat_addr)
3053         self.pg8.add_stream(pkts)
3054         self.pg_enable_capture(self.pg_interfaces)
3055         self.pg_start()
3056         capture = self.pg7.get_capture(len(pkts))
3057         self.verify_capture_in(capture, self.pg7)
3058
3059     def test_static_ipless_interfaces(self):
3060         """ NAT44 interfaces without configured IP address - 1:1 NAT """
3061
3062         self.vapi.ip_neighbor_add_del(
3063             self.pg7.sw_if_index,
3064             self.pg7.remote_mac,
3065             self.pg7.remote_ip4,
3066             flags=(VppEnum.vl_api_ip_neighbor_flags_t.
3067                    IP_API_NEIGHBOR_FLAG_STATIC))
3068         self.vapi.ip_neighbor_add_del(
3069             self.pg8.sw_if_index,
3070             self.pg8.remote_mac,
3071             self.pg8.remote_ip4,
3072             flags=(VppEnum.vl_api_ip_neighbor_flags_t.
3073                    IP_API_NEIGHBOR_FLAG_STATIC))
3074
3075         self.vapi.ip_add_del_route(dst_address=self.pg7.remote_ip4n,
3076                                    dst_address_length=32,
3077                                    next_hop_address=self.pg7.remote_ip4n,
3078                                    next_hop_sw_if_index=self.pg7.sw_if_index)
3079         self.vapi.ip_add_del_route(dst_address=self.pg8.remote_ip4n,
3080                                    dst_address_length=32,
3081                                    next_hop_address=self.pg8.remote_ip4n,
3082                                    next_hop_sw_if_index=self.pg8.sw_if_index)
3083
3084         self.nat44_add_static_mapping(self.pg7.remote_ip4, self.nat_addr)
3085         self.vapi.nat44_interface_add_del_feature(self.pg7.sw_if_index)
3086         self.vapi.nat44_interface_add_del_feature(self.pg8.sw_if_index,
3087                                                   is_inside=0)
3088
3089         # out2in
3090         pkts = self.create_stream_out(self.pg8)
3091         self.pg8.add_stream(pkts)
3092         self.pg_enable_capture(self.pg_interfaces)
3093         self.pg_start()
3094         capture = self.pg7.get_capture(len(pkts))
3095         self.verify_capture_in(capture, self.pg7)
3096
3097         # in2out
3098         pkts = self.create_stream_in(self.pg7, self.pg8)
3099         self.pg7.add_stream(pkts)
3100         self.pg_enable_capture(self.pg_interfaces)
3101         self.pg_start()
3102         capture = self.pg8.get_capture(len(pkts))
3103         self.verify_capture_out(capture, self.nat_addr, True)
3104
3105     def test_static_with_port_ipless_interfaces(self):
3106         """ NAT44 interfaces without configured IP address - 1:1 NAPT """
3107
3108         self.tcp_port_out = 30606
3109         self.udp_port_out = 30607
3110         self.icmp_id_out = 30608
3111
3112         self.vapi.ip_neighbor_add_del(
3113             self.pg7.sw_if_index,
3114             self.pg7.remote_mac,
3115             self.pg7.remote_ip4,
3116             flags=(VppEnum.vl_api_ip_neighbor_flags_t.
3117                    IP_API_NEIGHBOR_FLAG_STATIC))
3118         self.vapi.ip_neighbor_add_del(
3119             self.pg8.sw_if_index,
3120             self.pg8.remote_mac,
3121             self.pg8.remote_ip4,
3122             flags=(VppEnum.vl_api_ip_neighbor_flags_t.
3123                    IP_API_NEIGHBOR_FLAG_STATIC))
3124
3125         self.vapi.ip_add_del_route(dst_address=self.pg7.remote_ip4n,
3126                                    dst_address_length=32,
3127                                    next_hop_address=self.pg7.remote_ip4n,
3128                                    next_hop_sw_if_index=self.pg7.sw_if_index)
3129         self.vapi.ip_add_del_route(dst_address=self.pg8.remote_ip4n,
3130                                    dst_address_length=32,
3131                                    next_hop_address=self.pg8.remote_ip4n,
3132                                    next_hop_sw_if_index=self.pg8.sw_if_index)
3133
3134         self.nat44_add_address(self.nat_addr)
3135         self.nat44_add_static_mapping(self.pg7.remote_ip4, self.nat_addr,
3136                                       self.tcp_port_in, self.tcp_port_out,
3137                                       proto=IP_PROTOS.tcp)
3138         self.nat44_add_static_mapping(self.pg7.remote_ip4, self.nat_addr,
3139                                       self.udp_port_in, self.udp_port_out,
3140                                       proto=IP_PROTOS.udp)
3141         self.nat44_add_static_mapping(self.pg7.remote_ip4, self.nat_addr,
3142                                       self.icmp_id_in, self.icmp_id_out,
3143                                       proto=IP_PROTOS.icmp)
3144         self.vapi.nat44_interface_add_del_feature(self.pg7.sw_if_index)
3145         self.vapi.nat44_interface_add_del_feature(self.pg8.sw_if_index,
3146                                                   is_inside=0)
3147
3148         # out2in
3149         pkts = self.create_stream_out(self.pg8)
3150         self.pg8.add_stream(pkts)
3151         self.pg_enable_capture(self.pg_interfaces)
3152         self.pg_start()
3153         capture = self.pg7.get_capture(len(pkts))
3154         self.verify_capture_in(capture, self.pg7)
3155
3156         # in2out
3157         pkts = self.create_stream_in(self.pg7, self.pg8)
3158         self.pg7.add_stream(pkts)
3159         self.pg_enable_capture(self.pg_interfaces)
3160         self.pg_start()
3161         capture = self.pg8.get_capture(len(pkts))
3162         self.verify_capture_out(capture)
3163
3164     def test_static_unknown_proto(self):
3165         """ 1:1 NAT translate packet with unknown protocol """
3166         nat_ip = "10.0.0.10"
3167         self.nat44_add_static_mapping(self.pg0.remote_ip4, nat_ip)
3168         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
3169         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
3170                                                   is_inside=0)
3171
3172         # in2out
3173         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
3174              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3175              GRE() /
3176              IP(src=self.pg2.remote_ip4, dst=self.pg3.remote_ip4) /
3177              TCP(sport=1234, dport=1234))
3178         self.pg0.add_stream(p)
3179         self.pg_enable_capture(self.pg_interfaces)
3180         self.pg_start()
3181         p = self.pg1.get_capture(1)
3182         packet = p[0]
3183         try:
3184             self.assertEqual(packet[IP].src, nat_ip)
3185             self.assertEqual(packet[IP].dst, self.pg1.remote_ip4)
3186             self.assertEqual(packet.haslayer(GRE), 1)
3187             self.assert_packet_checksums_valid(packet)
3188         except:
3189             self.logger.error(ppp("Unexpected or invalid packet:", packet))
3190             raise
3191
3192         # out2in
3193         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
3194              IP(src=self.pg1.remote_ip4, dst=nat_ip) /
3195              GRE() /
3196              IP(src=self.pg3.remote_ip4, dst=self.pg2.remote_ip4) /
3197              TCP(sport=1234, dport=1234))
3198         self.pg1.add_stream(p)
3199         self.pg_enable_capture(self.pg_interfaces)
3200         self.pg_start()
3201         p = self.pg0.get_capture(1)
3202         packet = p[0]
3203         try:
3204             self.assertEqual(packet[IP].src, self.pg1.remote_ip4)
3205             self.assertEqual(packet[IP].dst, self.pg0.remote_ip4)
3206             self.assertEqual(packet.haslayer(GRE), 1)
3207             self.assert_packet_checksums_valid(packet)
3208         except:
3209             self.logger.error(ppp("Unexpected or invalid packet:", packet))
3210             raise
3211
3212     def test_hairpinning_static_unknown_proto(self):
3213         """ 1:1 NAT translate packet with unknown protocol - hairpinning """
3214
3215         host = self.pg0.remote_hosts[0]
3216         server = self.pg0.remote_hosts[1]
3217
3218         host_nat_ip = "10.0.0.10"
3219         server_nat_ip = "10.0.0.11"
3220
3221         self.nat44_add_static_mapping(host.ip4, host_nat_ip)
3222         self.nat44_add_static_mapping(server.ip4, server_nat_ip)
3223         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
3224         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
3225                                                   is_inside=0)
3226
3227         # host to server
3228         p = (Ether(dst=self.pg0.local_mac, src=host.mac) /
3229              IP(src=host.ip4, dst=server_nat_ip) /
3230              GRE() /
3231              IP(src=self.pg2.remote_ip4, dst=self.pg3.remote_ip4) /
3232              TCP(sport=1234, dport=1234))
3233         self.pg0.add_stream(p)
3234         self.pg_enable_capture(self.pg_interfaces)
3235         self.pg_start()
3236         p = self.pg0.get_capture(1)
3237         packet = p[0]
3238         try:
3239             self.assertEqual(packet[IP].src, host_nat_ip)
3240             self.assertEqual(packet[IP].dst, server.ip4)
3241             self.assertEqual(packet.haslayer(GRE), 1)
3242             self.assert_packet_checksums_valid(packet)
3243         except:
3244             self.logger.error(ppp("Unexpected or invalid packet:", packet))
3245             raise
3246
3247         # server to host
3248         p = (Ether(dst=self.pg0.local_mac, src=server.mac) /
3249              IP(src=server.ip4, dst=host_nat_ip) /
3250              GRE() /
3251              IP(src=self.pg3.remote_ip4, dst=self.pg2.remote_ip4) /
3252              TCP(sport=1234, dport=1234))
3253         self.pg0.add_stream(p)
3254         self.pg_enable_capture(self.pg_interfaces)
3255         self.pg_start()
3256         p = self.pg0.get_capture(1)
3257         packet = p[0]
3258         try:
3259             self.assertEqual(packet[IP].src, server_nat_ip)
3260             self.assertEqual(packet[IP].dst, host.ip4)
3261             self.assertEqual(packet.haslayer(GRE), 1)
3262             self.assert_packet_checksums_valid(packet)
3263         except:
3264             self.logger.error(ppp("Unexpected or invalid packet:", packet))
3265             raise
3266
3267     def test_output_feature(self):
3268         """ NAT44 interface output feature (in2out postrouting) """
3269         self.nat44_add_address(self.nat_addr)
3270         self.vapi.nat44_interface_add_del_output_feature(self.pg0.sw_if_index)
3271         self.vapi.nat44_interface_add_del_output_feature(self.pg1.sw_if_index)
3272         self.vapi.nat44_interface_add_del_output_feature(self.pg3.sw_if_index,
3273                                                          is_inside=0)
3274
3275         # in2out
3276         pkts = self.create_stream_in(self.pg0, self.pg3)
3277         self.pg0.add_stream(pkts)
3278         self.pg_enable_capture(self.pg_interfaces)
3279         self.pg_start()
3280         capture = self.pg3.get_capture(len(pkts))
3281         self.verify_capture_out(capture)
3282
3283         # out2in
3284         pkts = self.create_stream_out(self.pg3)
3285         self.pg3.add_stream(pkts)
3286         self.pg_enable_capture(self.pg_interfaces)
3287         self.pg_start()
3288         capture = self.pg0.get_capture(len(pkts))
3289         self.verify_capture_in(capture, self.pg0)
3290
3291         # from non-NAT interface to NAT inside interface
3292         pkts = self.create_stream_in(self.pg2, self.pg0)
3293         self.pg2.add_stream(pkts)
3294         self.pg_enable_capture(self.pg_interfaces)
3295         self.pg_start()
3296         capture = self.pg0.get_capture(len(pkts))
3297         self.verify_capture_no_translation(capture, self.pg2, self.pg0)
3298
3299     def test_output_feature_vrf_aware(self):
3300         """ NAT44 interface output feature VRF aware (in2out postrouting) """
3301         nat_ip_vrf10 = "10.0.0.10"
3302         nat_ip_vrf20 = "10.0.0.20"
3303
3304         self.vapi.ip_add_del_route(dst_address=self.pg3.remote_ip4n,
3305                                    dst_address_length=32,
3306                                    next_hop_address=self.pg3.remote_ip4n,
3307                                    next_hop_sw_if_index=self.pg3.sw_if_index,
3308                                    table_id=10)
3309         self.vapi.ip_add_del_route(dst_address=self.pg3.remote_ip4n,
3310                                    dst_address_length=32,
3311                                    next_hop_address=self.pg3.remote_ip4n,
3312                                    next_hop_sw_if_index=self.pg3.sw_if_index,
3313                                    table_id=20)
3314
3315         self.nat44_add_address(nat_ip_vrf10, vrf_id=10)
3316         self.nat44_add_address(nat_ip_vrf20, vrf_id=20)
3317         self.vapi.nat44_interface_add_del_output_feature(self.pg4.sw_if_index)
3318         self.vapi.nat44_interface_add_del_output_feature(self.pg6.sw_if_index)
3319         self.vapi.nat44_interface_add_del_output_feature(self.pg3.sw_if_index,
3320                                                          is_inside=0)
3321
3322         # in2out VRF 10
3323         pkts = self.create_stream_in(self.pg4, self.pg3)
3324         self.pg4.add_stream(pkts)
3325         self.pg_enable_capture(self.pg_interfaces)
3326         self.pg_start()
3327         capture = self.pg3.get_capture(len(pkts))
3328         self.verify_capture_out(capture, nat_ip=nat_ip_vrf10)
3329
3330         # out2in VRF 10
3331         pkts = self.create_stream_out(self.pg3, dst_ip=nat_ip_vrf10)
3332         self.pg3.add_stream(pkts)
3333         self.pg_enable_capture(self.pg_interfaces)
3334         self.pg_start()
3335         capture = self.pg4.get_capture(len(pkts))
3336         self.verify_capture_in(capture, self.pg4)
3337
3338         # in2out VRF 20
3339         pkts = self.create_stream_in(self.pg6, self.pg3)
3340         self.pg6.add_stream(pkts)
3341         self.pg_enable_capture(self.pg_interfaces)
3342         self.pg_start()
3343         capture = self.pg3.get_capture(len(pkts))
3344         self.verify_capture_out(capture, nat_ip=nat_ip_vrf20)
3345
3346         # out2in VRF 20
3347         pkts = self.create_stream_out(self.pg3, dst_ip=nat_ip_vrf20)
3348         self.pg3.add_stream(pkts)
3349         self.pg_enable_capture(self.pg_interfaces)
3350         self.pg_start()
3351         capture = self.pg6.get_capture(len(pkts))
3352         self.verify_capture_in(capture, self.pg6)
3353
3354     def test_output_feature_hairpinning(self):
3355         """ NAT44 interface output feature hairpinning (in2out postrouting) """
3356         host = self.pg0.remote_hosts[0]
3357         server = self.pg0.remote_hosts[1]
3358         host_in_port = 1234
3359         host_out_port = 0
3360         server_in_port = 5678
3361         server_out_port = 8765
3362
3363         self.nat44_add_address(self.nat_addr)
3364         self.vapi.nat44_interface_add_del_output_feature(self.pg0.sw_if_index)
3365         self.vapi.nat44_interface_add_del_output_feature(self.pg1.sw_if_index,
3366                                                          is_inside=0)
3367
3368         # add static mapping for server
3369         self.nat44_add_static_mapping(server.ip4, self.nat_addr,
3370                                       server_in_port, server_out_port,
3371                                       proto=IP_PROTOS.tcp)
3372
3373         # send packet from host to server
3374         p = (Ether(src=host.mac, dst=self.pg0.local_mac) /
3375              IP(src=host.ip4, dst=self.nat_addr) /
3376              TCP(sport=host_in_port, dport=server_out_port))
3377         self.pg0.add_stream(p)
3378         self.pg_enable_capture(self.pg_interfaces)
3379         self.pg_start()
3380         capture = self.pg0.get_capture(1)
3381         p = capture[0]
3382         try:
3383             ip = p[IP]
3384             tcp = p[TCP]
3385             self.assertEqual(ip.src, self.nat_addr)
3386             self.assertEqual(ip.dst, server.ip4)
3387             self.assertNotEqual(tcp.sport, host_in_port)
3388             self.assertEqual(tcp.dport, server_in_port)
3389             self.assert_packet_checksums_valid(p)
3390             host_out_port = tcp.sport
3391         except:
3392             self.logger.error(ppp("Unexpected or invalid packet:", p))
3393             raise
3394
3395         # send reply from server to host
3396         p = (Ether(src=server.mac, dst=self.pg0.local_mac) /
3397              IP(src=server.ip4, dst=self.nat_addr) /
3398              TCP(sport=server_in_port, dport=host_out_port))
3399         self.pg0.add_stream(p)
3400         self.pg_enable_capture(self.pg_interfaces)
3401         self.pg_start()
3402         capture = self.pg0.get_capture(1)
3403         p = capture[0]
3404         try:
3405             ip = p[IP]
3406             tcp = p[TCP]
3407             self.assertEqual(ip.src, self.nat_addr)
3408             self.assertEqual(ip.dst, host.ip4)
3409             self.assertEqual(tcp.sport, server_out_port)
3410             self.assertEqual(tcp.dport, host_in_port)
3411             self.assert_packet_checksums_valid(p)
3412         except:
3413             self.logger.error(ppp("Unexpected or invalid packet:", p))
3414             raise
3415
3416     def test_one_armed_nat44(self):
3417         """ One armed NAT44 """
3418         remote_host = self.pg9.remote_hosts[0]
3419         local_host = self.pg9.remote_hosts[1]
3420         external_port = 0
3421
3422         self.nat44_add_address(self.nat_addr)
3423         self.vapi.nat44_interface_add_del_feature(self.pg9.sw_if_index)
3424         self.vapi.nat44_interface_add_del_feature(self.pg9.sw_if_index,
3425                                                   is_inside=0)
3426
3427         # in2out
3428         p = (Ether(src=self.pg9.remote_mac, dst=self.pg9.local_mac) /
3429              IP(src=local_host.ip4, dst=remote_host.ip4) /
3430              TCP(sport=12345, dport=80))
3431         self.pg9.add_stream(p)
3432         self.pg_enable_capture(self.pg_interfaces)
3433         self.pg_start()
3434         capture = self.pg9.get_capture(1)
3435         p = capture[0]
3436         try:
3437             ip = p[IP]
3438             tcp = p[TCP]
3439             self.assertEqual(ip.src, self.nat_addr)
3440             self.assertEqual(ip.dst, remote_host.ip4)
3441             self.assertNotEqual(tcp.sport, 12345)
3442             external_port = tcp.sport
3443             self.assertEqual(tcp.dport, 80)
3444             self.assert_packet_checksums_valid(p)
3445         except:
3446             self.logger.error(ppp("Unexpected or invalid packet:", p))
3447             raise
3448
3449         # out2in
3450         p = (Ether(src=self.pg9.remote_mac, dst=self.pg9.local_mac) /
3451              IP(src=remote_host.ip4, dst=self.nat_addr) /
3452              TCP(sport=80, dport=external_port))
3453         self.pg9.add_stream(p)
3454         self.pg_enable_capture(self.pg_interfaces)
3455         self.pg_start()
3456         capture = self.pg9.get_capture(1)
3457         p = capture[0]
3458         try:
3459             ip = p[IP]
3460             tcp = p[TCP]
3461             self.assertEqual(ip.src, remote_host.ip4)
3462             self.assertEqual(ip.dst, local_host.ip4)
3463             self.assertEqual(tcp.sport, 80)
3464             self.assertEqual(tcp.dport, 12345)
3465             self.assert_packet_checksums_valid(p)
3466         except:
3467             self.logger.error(ppp("Unexpected or invalid packet:", p))
3468             raise
3469
3470         err = self.statistics.get_counter('/err/nat44-classify/next in2out')
3471         self.assertEqual(err, 1)
3472         err = self.statistics.get_counter('/err/nat44-classify/next out2in')
3473         self.assertEqual(err, 1)
3474
3475     def test_del_session(self):
3476         """ Delete NAT44 session """
3477         self.nat44_add_address(self.nat_addr)
3478         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
3479         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
3480                                                   is_inside=0)
3481
3482         pkts = self.create_stream_in(self.pg0, self.pg1)
3483         self.pg0.add_stream(pkts)
3484         self.pg_enable_capture(self.pg_interfaces)
3485         self.pg_start()
3486         self.pg1.get_capture(len(pkts))
3487
3488         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4n, 0)
3489         nsessions = len(sessions)
3490
3491         self.vapi.nat44_del_session(sessions[0].inside_ip_address,
3492                                     sessions[0].inside_port,
3493                                     sessions[0].protocol)
3494         self.vapi.nat44_del_session(sessions[1].outside_ip_address,
3495                                     sessions[1].outside_port,
3496                                     sessions[1].protocol,
3497                                     is_in=0)
3498
3499         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4n, 0)
3500         self.assertEqual(nsessions - len(sessions), 2)
3501
3502         self.vapi.nat44_del_session(sessions[0].inside_ip_address,
3503                                     sessions[0].inside_port,
3504                                     sessions[0].protocol)
3505
3506         self.verify_no_nat44_user()
3507
3508     def test_set_get_reass(self):
3509         """ NAT44 set/get virtual fragmentation reassembly """
3510         reas_cfg1 = self.vapi.nat_get_reass()
3511
3512         self.vapi.nat_set_reass(timeout=reas_cfg1.ip4_timeout + 5,
3513                                 max_reass=reas_cfg1.ip4_max_reass * 2,
3514                                 max_frag=reas_cfg1.ip4_max_frag * 2)
3515
3516         reas_cfg2 = self.vapi.nat_get_reass()
3517
3518         self.assertEqual(reas_cfg1.ip4_timeout + 5, reas_cfg2.ip4_timeout)
3519         self.assertEqual(reas_cfg1.ip4_max_reass * 2, reas_cfg2.ip4_max_reass)
3520         self.assertEqual(reas_cfg1.ip4_max_frag * 2, reas_cfg2.ip4_max_frag)
3521
3522         self.vapi.nat_set_reass(drop_frag=1)
3523         self.assertTrue(self.vapi.nat_get_reass().ip4_drop_frag)
3524
3525     def test_frag_in_order(self):
3526         """ NAT44 translate fragments arriving in order """
3527
3528         self.nat44_add_address(self.nat_addr)
3529         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
3530         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
3531                                                   is_inside=0)
3532
3533         self.frag_in_order(proto=IP_PROTOS.tcp)
3534         self.frag_in_order(proto=IP_PROTOS.udp)
3535         self.frag_in_order(proto=IP_PROTOS.icmp)
3536
3537     def test_frag_forwarding(self):
3538         """ NAT44 forwarding fragment test """
3539         self.vapi.nat44_add_del_interface_addr(self.pg1.sw_if_index)
3540         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
3541         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
3542                                                   is_inside=0)
3543         self.vapi.nat44_forwarding_enable_disable(1)
3544
3545         data = b"A" * 16 + b"B" * 16 + b"C" * 3
3546         pkts = self.create_stream_frag(self.pg1,
3547                                        self.pg0.remote_ip4,
3548                                        4789,
3549                                        4789,
3550                                        data,
3551                                        proto=IP_PROTOS.udp)
3552         self.pg1.add_stream(pkts)
3553         self.pg_enable_capture(self.pg_interfaces)
3554         self.pg_start()
3555         frags = self.pg0.get_capture(len(pkts))
3556         p = self.reass_frags_and_verify(frags,
3557                                         self.pg1.remote_ip4,
3558                                         self.pg0.remote_ip4)
3559         self.assertEqual(p[UDP].sport, 4789)
3560         self.assertEqual(p[UDP].dport, 4789)
3561         self.assertEqual(data, p[Raw].load)
3562
3563     def test_reass_hairpinning(self):
3564         """ NAT44 fragments hairpinning """
3565
3566         self.server = self.pg0.remote_hosts[1]
3567         self.host_in_port = random.randint(1025, 65535)
3568         self.server_in_port = random.randint(1025, 65535)
3569         self.server_out_port = random.randint(1025, 65535)
3570
3571         self.nat44_add_address(self.nat_addr)
3572         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
3573         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
3574                                                   is_inside=0)
3575         # add static mapping for server
3576         self.nat44_add_static_mapping(self.server.ip4, self.nat_addr,
3577                                       self.server_in_port,
3578                                       self.server_out_port,
3579                                       proto=IP_PROTOS.tcp)
3580         self.nat44_add_static_mapping(self.server.ip4, self.nat_addr,
3581                                       self.server_in_port,
3582                                       self.server_out_port,
3583                                       proto=IP_PROTOS.udp)
3584         self.nat44_add_static_mapping(self.server.ip4, self.nat_addr)
3585
3586         self.reass_hairpinning(proto=IP_PROTOS.tcp)
3587         self.reass_hairpinning(proto=IP_PROTOS.udp)
3588         self.reass_hairpinning(proto=IP_PROTOS.icmp)
3589
3590     def test_frag_out_of_order(self):
3591         """ NAT44 translate fragments arriving out of order """
3592
3593         self.nat44_add_address(self.nat_addr)
3594         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
3595         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
3596                                                   is_inside=0)
3597
3598         self.frag_out_of_order(proto=IP_PROTOS.tcp)
3599         self.frag_out_of_order(proto=IP_PROTOS.udp)
3600         self.frag_out_of_order(proto=IP_PROTOS.icmp)
3601
3602     def test_port_restricted(self):
3603         """ Port restricted NAT44 (MAP-E CE) """
3604         self.nat44_add_address(self.nat_addr)
3605         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
3606         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
3607                                                   is_inside=0)
3608         self.vapi.nat_set_addr_and_port_alloc_alg(alg=1,
3609                                                   psid_offset=6,
3610                                                   psid_length=6,
3611                                                   psid=10)
3612
3613         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
3614              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3615              TCP(sport=4567, dport=22))
3616         self.pg0.add_stream(p)
3617         self.pg_enable_capture(self.pg_interfaces)
3618         self.pg_start()
3619         capture = self.pg1.get_capture(1)
3620         p = capture[0]
3621         try:
3622             ip = p[IP]
3623             tcp = p[TCP]
3624             self.assertEqual(ip.dst, self.pg1.remote_ip4)
3625             self.assertEqual(ip.src, self.nat_addr)
3626             self.assertEqual(tcp.dport, 22)
3627             self.assertNotEqual(tcp.sport, 4567)
3628             self.assertEqual((tcp.sport >> 6) & 63, 10)
3629             self.assert_packet_checksums_valid(p)
3630         except:
3631             self.logger.error(ppp("Unexpected or invalid packet:", p))
3632             raise
3633
3634     def test_port_range(self):
3635         """ External address port range """
3636         self.nat44_add_address(self.nat_addr)
3637         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
3638         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
3639                                                   is_inside=0)
3640         self.vapi.nat_set_addr_and_port_alloc_alg(alg=2,
3641                                                   start_port=1025,
3642                                                   end_port=1027)
3643
3644         pkts = []
3645         for port in range(0, 5):
3646             p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
3647                  IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3648                  TCP(sport=1125 + port))
3649             pkts.append(p)
3650         self.pg0.add_stream(pkts)
3651         self.pg_enable_capture(self.pg_interfaces)
3652         self.pg_start()
3653         capture = self.pg1.get_capture(3)
3654         for p in capture:
3655             tcp = p[TCP]
3656             self.assertGreaterEqual(tcp.sport, 1025)
3657             self.assertLessEqual(tcp.sport, 1027)
3658
3659     def test_ipfix_max_frags(self):
3660         """ IPFIX logging maximum fragments pending reassembly exceeded """
3661         self.nat44_add_address(self.nat_addr)
3662         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
3663         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
3664                                                   is_inside=0)
3665         self.vapi.nat_set_reass(max_frag=1)
3666         self.vapi.set_ipfix_exporter(collector_address=self.pg3.remote_ip4n,
3667                                      src_address=self.pg3.local_ip4n,
3668                                      path_mtu=512,
3669                                      template_interval=10)
3670         self.vapi.nat_ipfix_enable_disable(domain_id=self.ipfix_domain_id,
3671                                            src_port=self.ipfix_src_port)
3672
3673         data = b"A" * 4 + b"B" * 16 + b"C" * 3
3674         self.tcp_port_in = random.randint(1025, 65535)
3675         pkts = self.create_stream_frag(self.pg0,
3676                                        self.pg1.remote_ip4,
3677                                        self.tcp_port_in,
3678                                        20,
3679                                        data)
3680         pkts.reverse()
3681         self.pg0.add_stream(pkts)
3682         self.pg_enable_capture(self.pg_interfaces)
3683         self.pg_start()
3684         self.pg1.assert_nothing_captured()
3685         sleep(1)
3686         self.vapi.cli("ipfix flush")  # FIXME this should be an API call
3687         capture = self.pg3.get_capture(9)
3688         ipfix = IPFIXDecoder()
3689         # first load template
3690         for p in capture:
3691             self.assertTrue(p.haslayer(IPFIX))
3692             self.assertEqual(p[IP].src, self.pg3.local_ip4)
3693             self.assertEqual(p[IP].dst, self.pg3.remote_ip4)
3694             self.assertEqual(p[UDP].sport, self.ipfix_src_port)
3695             self.assertEqual(p[UDP].dport, 4739)
3696             self.assertEqual(p[IPFIX].observationDomainID,
3697                              self.ipfix_domain_id)
3698             if p.haslayer(Template):
3699                 ipfix.add_template(p.getlayer(Template))
3700         # verify events in data set
3701         for p in capture:
3702             if p.haslayer(Data):
3703                 data = ipfix.decode_data_set(p.getlayer(Set))
3704                 self.verify_ipfix_max_fragments_ip4(data, 1,
3705                                                     self.pg0.remote_ip4n)
3706
3707     def test_multiple_outside_vrf(self):
3708         """ Multiple outside VRF """
3709         vrf_id1 = 1
3710         vrf_id2 = 2
3711
3712         self.pg1.unconfig_ip4()
3713         self.pg2.unconfig_ip4()
3714         self.vapi.ip_table_add_del(is_add=1, table_id=vrf_id1)
3715         self.vapi.ip_table_add_del(is_add=1, table_id=vrf_id2)
3716         self.pg1.set_table_ip4(vrf_id1)
3717         self.pg2.set_table_ip4(vrf_id2)
3718         self.pg1.config_ip4()
3719         self.pg2.config_ip4()
3720         self.pg1.resolve_arp()
3721         self.pg2.resolve_arp()
3722
3723         self.nat44_add_address(self.nat_addr)
3724         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
3725         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
3726                                                   is_inside=0)
3727         self.vapi.nat44_interface_add_del_feature(self.pg2.sw_if_index,
3728                                                   is_inside=0)
3729
3730         try:
3731             # first VRF
3732             pkts = self.create_stream_in(self.pg0, self.pg1)
3733             self.pg0.add_stream(pkts)
3734             self.pg_enable_capture(self.pg_interfaces)
3735             self.pg_start()
3736             capture = self.pg1.get_capture(len(pkts))
3737             self.verify_capture_out(capture, self.nat_addr)
3738
3739             pkts = self.create_stream_out(self.pg1, self.nat_addr)
3740             self.pg1.add_stream(pkts)
3741             self.pg_enable_capture(self.pg_interfaces)
3742             self.pg_start()
3743             capture = self.pg0.get_capture(len(pkts))
3744             self.verify_capture_in(capture, self.pg0)
3745
3746             self.tcp_port_in = 60303
3747             self.udp_port_in = 60304
3748             self.icmp_id_in = 60305
3749
3750             # second VRF
3751             pkts = self.create_stream_in(self.pg0, self.pg2)
3752             self.pg0.add_stream(pkts)
3753             self.pg_enable_capture(self.pg_interfaces)
3754             self.pg_start()
3755             capture = self.pg2.get_capture(len(pkts))
3756             self.verify_capture_out(capture, self.nat_addr)
3757
3758             pkts = self.create_stream_out(self.pg2, self.nat_addr)
3759             self.pg2.add_stream(pkts)
3760             self.pg_enable_capture(self.pg_interfaces)
3761             self.pg_start()
3762             capture = self.pg0.get_capture(len(pkts))
3763             self.verify_capture_in(capture, self.pg0)
3764
3765         finally:
3766             self.pg1.unconfig_ip4()
3767             self.pg2.unconfig_ip4()
3768             self.pg1.set_table_ip4(0)
3769             self.pg2.set_table_ip4(0)
3770             self.pg1.config_ip4()
3771             self.pg2.config_ip4()
3772             self.pg1.resolve_arp()
3773             self.pg2.resolve_arp()
3774
3775     @unittest.skipUnless(running_extended_tests, "part of extended tests")
3776     def test_session_timeout(self):
3777         """ NAT44 session timeouts """
3778         self.nat44_add_address(self.nat_addr)
3779         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
3780         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
3781                                                   is_inside=0)
3782         self.vapi.nat_set_timeouts(udp=5)
3783
3784         max_sessions = 1000
3785         pkts = []
3786         for i in range(0, max_sessions):
3787             src = "10.10.%u.%u" % ((i & 0xFF00) >> 8, i & 0xFF)
3788             p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
3789                  IP(src=src, dst=self.pg1.remote_ip4) /
3790                  UDP(sport=1025, dport=53))
3791             pkts.append(p)
3792         self.pg0.add_stream(pkts)
3793         self.pg_enable_capture(self.pg_interfaces)
3794         self.pg_start()
3795         self.pg1.get_capture(max_sessions)
3796
3797         sleep(6)
3798
3799         pkts = []
3800         for i in range(0, max_sessions):
3801             src = "10.10.%u.%u" % ((i & 0xFF00) >> 8, i & 0xFF)
3802             p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
3803                  IP(src=src, dst=self.pg1.remote_ip4) /
3804                  UDP(sport=1026, dport=53))
3805             pkts.append(p)
3806         self.pg0.add_stream(pkts)
3807         self.pg_enable_capture(self.pg_interfaces)
3808         self.pg_start()
3809         self.pg1.get_capture(max_sessions)
3810
3811         nsessions = 0
3812         users = self.vapi.nat44_user_dump()
3813         for user in users:
3814             nsessions = nsessions + user.nsessions
3815         self.assertLess(nsessions, 2 * max_sessions)
3816
3817     def test_mss_clamping(self):
3818         """ TCP MSS clamping """
3819         self.nat44_add_address(self.nat_addr)
3820         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
3821         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
3822                                                   is_inside=0)
3823
3824         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
3825              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
3826              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
3827                  flags="S", options=[('MSS', 1400)]))
3828
3829         self.vapi.nat_set_mss_clamping(enable=1, mss_value=1000)
3830         self.pg0.add_stream(p)
3831         self.pg_enable_capture(self.pg_interfaces)
3832         self.pg_start()
3833         capture = self.pg1.get_capture(1)
3834         # Negotiated MSS value greater than configured - changed
3835         self.verify_mss_value(capture[0], 1000)
3836
3837         self.vapi.nat_set_mss_clamping(enable=0)
3838         self.pg0.add_stream(p)
3839         self.pg_enable_capture(self.pg_interfaces)
3840         self.pg_start()
3841         capture = self.pg1.get_capture(1)
3842         # MSS clamping disabled - negotiated MSS unchanged
3843         self.verify_mss_value(capture[0], 1400)
3844
3845         self.vapi.nat_set_mss_clamping(enable=1, mss_value=1500)
3846         self.pg0.add_stream(p)
3847         self.pg_enable_capture(self.pg_interfaces)
3848         self.pg_start()
3849         capture = self.pg1.get_capture(1)
3850         # Negotiated MSS value smaller than configured - unchanged
3851         self.verify_mss_value(capture[0], 1400)
3852
3853     @unittest.skipUnless(running_extended_tests, "part of extended tests")
3854     def test_ha_send(self):
3855         """ Send HA session synchronization events (active) """
3856         self.nat44_add_address(self.nat_addr)
3857         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
3858         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
3859                                                   is_inside=0)
3860         self.vapi.nat_ha_set_listener(self.pg3.local_ip4, port=12345)
3861         self.vapi.nat_ha_set_failover(self.pg3.remote_ip4, port=12346)
3862         bind_layers(UDP, HANATStateSync, sport=12345)
3863
3864         # create sessions
3865         pkts = self.create_stream_in(self.pg0, self.pg1)
3866         self.pg0.add_stream(pkts)
3867         self.pg_enable_capture(self.pg_interfaces)
3868         self.pg_start()
3869         capture = self.pg1.get_capture(len(pkts))
3870         self.verify_capture_out(capture)
3871         # active send HA events
3872         self.vapi.nat_ha_flush()
3873         stats = self.statistics.get_counter('/nat44/ha/add-event-send')
3874         self.assertEqual(stats[0][0], 3)
3875         capture = self.pg3.get_capture(1)
3876         p = capture[0]
3877         self.assert_packet_checksums_valid(p)
3878         try:
3879             ip = p[IP]
3880             udp = p[UDP]
3881             hanat = p[HANATStateSync]
3882         except IndexError:
3883             self.logger.error(ppp("Invalid packet:", p))
3884             raise
3885         else:
3886             self.assertEqual(ip.src, self.pg3.local_ip4)
3887             self.assertEqual(ip.dst, self.pg3.remote_ip4)
3888             self.assertEqual(udp.sport, 12345)
3889             self.assertEqual(udp.dport, 12346)
3890             self.assertEqual(hanat.version, 1)
3891             self.assertEqual(hanat.thread_index, 0)
3892             self.assertEqual(hanat.count, 3)
3893             seq = hanat.sequence_number
3894             for event in hanat.events:
3895                 self.assertEqual(event.event_type, 1)
3896                 self.assertEqual(event.in_addr, self.pg0.remote_ip4)
3897                 self.assertEqual(event.out_addr, self.nat_addr)
3898                 self.assertEqual(event.fib_index, 0)
3899
3900         # ACK received events
3901         ack = (Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac) /
3902                IP(src=self.pg3.remote_ip4, dst=self.pg3.local_ip4) /
3903                UDP(sport=12346, dport=12345) /
3904                HANATStateSync(sequence_number=seq, flags='ACK'))
3905         self.pg3.add_stream(ack)
3906         self.pg_start()
3907         stats = self.statistics.get_counter('/nat44/ha/ack-recv')
3908         self.assertEqual(stats[0][0], 1)
3909
3910         # delete one session
3911         self.pg_enable_capture(self.pg_interfaces)
3912         self.vapi.nat44_del_session(self.pg0.remote_ip4n, self.tcp_port_in,
3913                                     IP_PROTOS.tcp)
3914         self.vapi.nat_ha_flush()
3915         stats = self.statistics.get_counter('/nat44/ha/del-event-send')
3916         self.assertEqual(stats[0][0], 1)
3917         capture = self.pg3.get_capture(1)
3918         p = capture[0]
3919         try:
3920             hanat = p[HANATStateSync]
3921         except IndexError:
3922             self.logger.error(ppp("Invalid packet:", p))
3923             raise
3924         else:
3925             self.assertGreater(hanat.sequence_number, seq)
3926
3927         # do not send ACK, active retry send HA event again
3928         self.pg_enable_capture(self.pg_interfaces)
3929         sleep(12)
3930         stats = self.statistics.get_counter('/nat44/ha/retry-count')
3931         self.assertEqual(stats[0][0], 3)
3932         stats = self.statistics.get_counter('/nat44/ha/missed-count')
3933         self.assertEqual(stats[0][0], 1)
3934         capture = self.pg3.get_capture(3)
3935         for packet in capture:
3936             self.assertEqual(packet, p)
3937
3938         # session counters refresh
3939         pkts = self.create_stream_out(self.pg1)
3940         self.pg1.add_stream(pkts)
3941         self.pg_enable_capture(self.pg_interfaces)
3942         self.pg_start()
3943         self.pg0.get_capture(2)
3944         self.vapi.nat_ha_flush()
3945         stats = self.statistics.get_counter('/nat44/ha/refresh-event-send')
3946         self.assertEqual(stats[0][0], 2)
3947         capture = self.pg3.get_capture(1)
3948         p = capture[0]
3949         self.assert_packet_checksums_valid(p)
3950         try:
3951             ip = p[IP]
3952             udp = p[UDP]
3953             hanat = p[HANATStateSync]
3954         except IndexError:
3955             self.logger.error(ppp("Invalid packet:", p))
3956             raise
3957         else:
3958             self.assertEqual(ip.src, self.pg3.local_ip4)
3959             self.assertEqual(ip.dst, self.pg3.remote_ip4)
3960             self.assertEqual(udp.sport, 12345)
3961             self.assertEqual(udp.dport, 12346)
3962             self.assertEqual(hanat.version, 1)
3963             self.assertEqual(hanat.count, 2)
3964             seq = hanat.sequence_number
3965             for event in hanat.events:
3966                 self.assertEqual(event.event_type, 3)
3967                 self.assertEqual(event.out_addr, self.nat_addr)
3968                 self.assertEqual(event.fib_index, 0)
3969                 self.assertEqual(event.total_pkts, 2)
3970                 self.assertGreater(event.total_bytes, 0)
3971
3972         ack = (Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac) /
3973                IP(src=self.pg3.remote_ip4, dst=self.pg3.local_ip4) /
3974                UDP(sport=12346, dport=12345) /
3975                HANATStateSync(sequence_number=seq, flags='ACK'))
3976         self.pg3.add_stream(ack)
3977         self.pg_start()
3978         stats = self.statistics.get_counter('/nat44/ha/ack-recv')
3979         self.assertEqual(stats[0][0], 2)
3980
3981     def test_ha_recv(self):
3982         """ Receive HA session synchronization events (passive) """
3983         self.nat44_add_address(self.nat_addr)
3984         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
3985         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
3986                                                   is_inside=0)
3987         self.vapi.nat_ha_set_listener(self.pg3.local_ip4, port=12345)
3988         bind_layers(UDP, HANATStateSync, sport=12345)
3989
3990         self.tcp_port_out = random.randint(1025, 65535)
3991         self.udp_port_out = random.randint(1025, 65535)
3992
3993         # send HA session add events to failover/passive
3994         p = (Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac) /
3995              IP(src=self.pg3.remote_ip4, dst=self.pg3.local_ip4) /
3996              UDP(sport=12346, dport=12345) /
3997              HANATStateSync(sequence_number=1, events=[
3998                  Event(event_type='add', protocol='tcp',
3999                        in_addr=self.pg0.remote_ip4, out_addr=self.nat_addr,
4000                        in_port=self.tcp_port_in, out_port=self.tcp_port_out,
4001                        eh_addr=self.pg1.remote_ip4,
4002                        ehn_addr=self.pg1.remote_ip4,
4003                        eh_port=self.tcp_external_port,
4004                        ehn_port=self.tcp_external_port, fib_index=0),
4005                  Event(event_type='add', protocol='udp',
4006                        in_addr=self.pg0.remote_ip4, out_addr=self.nat_addr,
4007                        in_port=self.udp_port_in, out_port=self.udp_port_out,
4008                        eh_addr=self.pg1.remote_ip4,
4009                        ehn_addr=self.pg1.remote_ip4,
4010                        eh_port=self.udp_external_port,
4011                        ehn_port=self.udp_external_port, fib_index=0)]))
4012
4013         self.pg3.add_stream(p)
4014         self.pg_enable_capture(self.pg_interfaces)
4015         self.pg_start()
4016         # receive ACK
4017         capture = self.pg3.get_capture(1)
4018         p = capture[0]
4019         try:
4020             hanat = p[HANATStateSync]
4021         except IndexError:
4022             self.logger.error(ppp("Invalid packet:", p))
4023             raise
4024         else:
4025             self.assertEqual(hanat.sequence_number, 1)
4026             self.assertEqual(hanat.flags, 'ACK')
4027             self.assertEqual(hanat.version, 1)
4028             self.assertEqual(hanat.thread_index, 0)
4029         stats = self.statistics.get_counter('/nat44/ha/ack-send')
4030         self.assertEqual(stats[0][0], 1)
4031         stats = self.statistics.get_counter('/nat44/ha/add-event-recv')
4032         self.assertEqual(stats[0][0], 2)
4033         users = self.statistics.get_counter('/nat44/total-users')
4034         self.assertEqual(users[0][0], 1)
4035         sessions = self.statistics.get_counter('/nat44/total-sessions')
4036         self.assertEqual(sessions[0][0], 2)
4037         users = self.vapi.nat44_user_dump()
4038         self.assertEqual(len(users), 1)
4039         self.assertEqual(users[0].ip_address, self.pg0.remote_ip4n)
4040         # there should be 2 sessions created by HA
4041         sessions = self.vapi.nat44_user_session_dump(users[0].ip_address,
4042                                                      users[0].vrf_id)
4043         self.assertEqual(len(sessions), 2)
4044         for session in sessions:
4045             self.assertEqual(session.inside_ip_address, self.pg0.remote_ip4n)
4046             self.assertEqual(session.outside_ip_address, self.nat_addr_n)
4047             self.assertIn(session.inside_port,
4048                           [self.tcp_port_in, self.udp_port_in])
4049             self.assertIn(session.outside_port,
4050                           [self.tcp_port_out, self.udp_port_out])
4051             self.assertIn(session.protocol, [IP_PROTOS.tcp, IP_PROTOS.udp])
4052
4053         # send HA session delete event to failover/passive
4054         p = (Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac) /
4055              IP(src=self.pg3.remote_ip4, dst=self.pg3.local_ip4) /
4056              UDP(sport=12346, dport=12345) /
4057              HANATStateSync(sequence_number=2, events=[
4058                  Event(event_type='del', protocol='udp',
4059                        in_addr=self.pg0.remote_ip4, out_addr=self.nat_addr,
4060                        in_port=self.udp_port_in, out_port=self.udp_port_out,
4061                        eh_addr=self.pg1.remote_ip4,
4062                        ehn_addr=self.pg1.remote_ip4,
4063                        eh_port=self.udp_external_port,
4064                        ehn_port=self.udp_external_port, fib_index=0)]))
4065
4066         self.pg3.add_stream(p)
4067         self.pg_enable_capture(self.pg_interfaces)
4068         self.pg_start()
4069         # receive ACK
4070         capture = self.pg3.get_capture(1)
4071         p = capture[0]
4072         try:
4073             hanat = p[HANATStateSync]
4074         except IndexError:
4075             self.logger.error(ppp("Invalid packet:", p))
4076             raise
4077         else:
4078             self.assertEqual(hanat.sequence_number, 2)
4079             self.assertEqual(hanat.flags, 'ACK')
4080             self.assertEqual(hanat.version, 1)
4081         users = self.vapi.nat44_user_dump()
4082         self.assertEqual(len(users), 1)
4083         self.assertEqual(users[0].ip_address, self.pg0.remote_ip4n)
4084         # now we should have only 1 session, 1 deleted by HA
4085         sessions = self.vapi.nat44_user_session_dump(users[0].ip_address,
4086                                                      users[0].vrf_id)
4087         self.assertEqual(len(sessions), 1)
4088         stats = self.statistics.get_counter('/nat44/ha/del-event-recv')
4089         self.assertEqual(stats[0][0], 1)
4090
4091         stats = self.statistics.get_counter('/err/nat-ha/pkts-processed')
4092         self.assertEqual(stats, 2)
4093
4094         # send HA session refresh event to failover/passive
4095         p = (Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac) /
4096              IP(src=self.pg3.remote_ip4, dst=self.pg3.local_ip4) /
4097              UDP(sport=12346, dport=12345) /
4098              HANATStateSync(sequence_number=3, events=[
4099                  Event(event_type='refresh', protocol='tcp',
4100                        in_addr=self.pg0.remote_ip4, out_addr=self.nat_addr,
4101                        in_port=self.tcp_port_in, out_port=self.tcp_port_out,
4102                        eh_addr=self.pg1.remote_ip4,
4103                        ehn_addr=self.pg1.remote_ip4,
4104                        eh_port=self.tcp_external_port,
4105                        ehn_port=self.tcp_external_port, fib_index=0,
4106                        total_bytes=1024, total_pkts=2)]))
4107         self.pg3.add_stream(p)
4108         self.pg_enable_capture(self.pg_interfaces)
4109         self.pg_start()
4110         # receive ACK
4111         capture = self.pg3.get_capture(1)
4112         p = capture[0]
4113         try:
4114             hanat = p[HANATStateSync]
4115         except IndexError:
4116             self.logger.error(ppp("Invalid packet:", p))
4117             raise
4118         else:
4119             self.assertEqual(hanat.sequence_number, 3)
4120             self.assertEqual(hanat.flags, 'ACK')
4121             self.assertEqual(hanat.version, 1)
4122         users = self.vapi.nat44_user_dump()
4123         self.assertEqual(len(users), 1)
4124         self.assertEqual(users[0].ip_address, self.pg0.remote_ip4n)
4125         sessions = self.vapi.nat44_user_session_dump(users[0].ip_address,
4126                                                      users[0].vrf_id)
4127         self.assertEqual(len(sessions), 1)
4128         session = sessions[0]
4129         self.assertEqual(session.total_bytes, 1024)
4130         self.assertEqual(session.total_pkts, 2)
4131         stats = self.statistics.get_counter('/nat44/ha/refresh-event-recv')
4132         self.assertEqual(stats[0][0], 1)
4133
4134         stats = self.statistics.get_counter('/err/nat-ha/pkts-processed')
4135         self.assertEqual(stats, 3)
4136
4137         # send packet to test session created by HA
4138         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
4139              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
4140              TCP(sport=self.tcp_external_port, dport=self.tcp_port_out))
4141         self.pg1.add_stream(p)
4142         self.pg_enable_capture(self.pg_interfaces)
4143         self.pg_start()
4144         capture = self.pg0.get_capture(1)
4145         p = capture[0]
4146         try:
4147             ip = p[IP]
4148             tcp = p[TCP]
4149         except IndexError:
4150             self.logger.error(ppp("Invalid packet:", p))
4151             raise
4152         else:
4153             self.assertEqual(ip.src, self.pg1.remote_ip4)
4154             self.assertEqual(ip.dst, self.pg0.remote_ip4)
4155             self.assertEqual(tcp.sport, self.tcp_external_port)
4156             self.assertEqual(tcp.dport, self.tcp_port_in)
4157
4158     def tearDown(self):
4159         super(TestNAT44, self).tearDown()
4160         if not self.vpp_dead:
4161             self.logger.info(self.vapi.cli("show nat44 addresses"))
4162             self.logger.info(self.vapi.cli("show nat44 interfaces"))
4163             self.logger.info(self.vapi.cli("show nat44 static mappings"))
4164             self.logger.info(self.vapi.cli("show nat44 interface address"))
4165             self.logger.info(self.vapi.cli("show nat44 sessions detail"))
4166             self.logger.info(self.vapi.cli("show nat virtual-reassembly"))
4167             self.logger.info(self.vapi.cli("show nat44 hash tables detail"))
4168             self.logger.info(self.vapi.cli("show nat timeouts"))
4169             self.logger.info(
4170                 self.vapi.cli("show nat addr-port-assignment-alg"))
4171             self.logger.info(self.vapi.cli("show nat ha"))
4172             self.clear_nat44()
4173             self.vapi.cli("clear logging")
4174
4175
4176 class TestNAT44EndpointDependent(MethodHolder):
4177     """ Endpoint-Dependent mapping and filtering test cases """
4178
4179     @classmethod
4180     def setUpConstants(cls):
4181         super(TestNAT44EndpointDependent, cls).setUpConstants()
4182         cls.vpp_cmdline.extend(["nat", "{", "endpoint-dependent", "}"])
4183
4184     @classmethod
4185     def setUpClass(cls):
4186         super(TestNAT44EndpointDependent, cls).setUpClass()
4187         cls.vapi.cli("set log class nat level debug")
4188         try:
4189             cls.tcp_port_in = 6303
4190             cls.tcp_port_out = 6303
4191             cls.udp_port_in = 6304
4192             cls.udp_port_out = 6304
4193             cls.icmp_id_in = 6305
4194             cls.icmp_id_out = 6305
4195             cls.nat_addr = '10.0.0.3'
4196             cls.nat_addr_n = socket.inet_pton(socket.AF_INET, cls.nat_addr)
4197             cls.ipfix_src_port = 4739
4198             cls.ipfix_domain_id = 1
4199             cls.tcp_external_port = 80
4200
4201             cls.create_pg_interfaces(range(7))
4202             cls.interfaces = list(cls.pg_interfaces[0:3])
4203
4204             for i in cls.interfaces:
4205                 i.admin_up()
4206                 i.config_ip4()
4207                 i.resolve_arp()
4208
4209             cls.pg0.generate_remote_hosts(3)
4210             cls.pg0.configure_ipv4_neighbors()
4211
4212             cls.pg3.admin_up()
4213
4214             cls.pg4.generate_remote_hosts(2)
4215             cls.pg4.config_ip4()
4216             ip_addr_n = socket.inet_pton(socket.AF_INET, "10.0.0.1")
4217             cls.vapi.sw_interface_add_del_address(
4218                 sw_if_index=cls.pg4.sw_if_index, address=ip_addr_n,
4219                 address_length=24)
4220             cls.pg4.admin_up()
4221             cls.pg4.resolve_arp()
4222             cls.pg4._remote_hosts[1]._ip4 = cls.pg4._remote_hosts[0]._ip4
4223             cls.pg4.resolve_arp()
4224
4225             zero_ip4n = socket.inet_pton(socket.AF_INET, "0.0.0.0")
4226             cls.vapi.ip_table_add_del(is_add=1, table_id=1)
4227
4228             cls.pg5._local_ip4 = "10.1.1.1"
4229             cls.pg5._local_ip4n = socket.inet_pton(socket.AF_INET,
4230                                                    cls.pg5.local_ip4)
4231             cls.pg5._remote_hosts[0]._ip4 = "10.1.1.2"
4232             cls.pg5._remote_hosts[0]._ip4n = socket.inet_pton(
4233                 socket.AF_INET, cls.pg5.remote_ip4)
4234             cls.pg5.set_table_ip4(1)
4235             cls.pg5.config_ip4()
4236             cls.pg5.admin_up()
4237             cls.vapi.ip_add_del_route(dst_address=cls.pg5.remote_ip4n,
4238                                       dst_address_length=32,
4239                                       table_id=1,
4240                                       next_hop_sw_if_index=cls.pg5.sw_if_index,
4241                                       next_hop_address=zero_ip4n)
4242
4243             cls.pg6._local_ip4 = "10.1.2.1"
4244             cls.pg6._local_ip4n = socket.inet_pton(socket.AF_INET,
4245                                                    cls.pg6.local_ip4)
4246             cls.pg6._remote_hosts[0]._ip4 = "10.1.2.2"
4247             cls.pg6._remote_hosts[0]._ip4n = socket.inet_pton(
4248                 socket.AF_INET, cls.pg6.remote_ip4)
4249             cls.pg6.set_table_ip4(1)
4250             cls.pg6.config_ip4()
4251             cls.pg6.admin_up()
4252             cls.vapi.ip_add_del_route(dst_address=cls.pg6.remote_ip4n,
4253                                       dst_address_length=32,
4254                                       table_id=1,
4255                                       next_hop_sw_if_index=cls.pg6.sw_if_index,
4256                                       next_hop_address=zero_ip4n)
4257
4258             cls.vapi.ip_add_del_route(dst_address=cls.pg6.remote_ip4n,
4259                                       dst_address_length=16,
4260                                       next_hop_address=zero_ip4n,
4261                                       table_id=0,
4262                                       next_hop_table_id=1)
4263             cls.vapi.ip_add_del_route(dst_address=zero_ip4n,
4264                                       dst_address_length=0,
4265                                       next_hop_address=zero_ip4n,
4266                                       table_id=1,
4267                                       next_hop_table_id=0)
4268             cls.vapi.ip_add_del_route(dst_address=zero_ip4n,
4269                                       dst_address_length=0,
4270                                       table_id=0,
4271                                       next_hop_sw_if_index=cls.pg1.sw_if_index,
4272                                       next_hop_address=cls.pg1.local_ip4n)
4273
4274             cls.pg5.resolve_arp()
4275             cls.pg6.resolve_arp()
4276
4277         except Exception:
4278             super(TestNAT44EndpointDependent, cls).tearDownClass()
4279             raise
4280
4281     def test_frag_in_order(self):
4282         """ NAT44 translate fragments arriving in order """
4283         self.nat44_add_address(self.nat_addr)
4284         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
4285         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
4286                                                   is_inside=0)
4287         self.frag_in_order(proto=IP_PROTOS.tcp)
4288         self.frag_in_order(proto=IP_PROTOS.udp)
4289         self.frag_in_order(proto=IP_PROTOS.icmp)
4290
4291     def test_frag_in_order_dont_translate(self):
4292         """ NAT44 don't translate fragments arriving in order """
4293         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
4294         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
4295                                                   is_inside=0)
4296         self.vapi.nat44_forwarding_enable_disable(enable=True)
4297         self.frag_in_order(proto=IP_PROTOS.tcp, dont_translate=True)
4298
4299     def test_frag_out_of_order(self):
4300         """ NAT44 translate fragments arriving out of order """
4301         self.nat44_add_address(self.nat_addr)
4302         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
4303         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
4304                                                   is_inside=0)
4305         self.frag_out_of_order(proto=IP_PROTOS.tcp)
4306         self.frag_out_of_order(proto=IP_PROTOS.udp)
4307         self.frag_out_of_order(proto=IP_PROTOS.icmp)
4308
4309     def test_frag_out_of_order_dont_translate(self):
4310         """ NAT44 don't translate fragments arriving out of order """
4311         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
4312         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
4313                                                   is_inside=0)
4314         self.vapi.nat44_forwarding_enable_disable(enable=True)
4315         self.frag_out_of_order(proto=IP_PROTOS.tcp, dont_translate=True)
4316
4317     def test_frag_in_order_in_plus_out(self):
4318         """ in+out interface fragments in order """
4319         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
4320         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index,
4321                                                   is_inside=0)
4322         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index)
4323         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
4324                                                   is_inside=0)
4325
4326         self.server = self.pg1.remote_hosts[0]
4327
4328         self.server_in_addr = self.server.ip4
4329         self.server_out_addr = '11.11.11.11'
4330         self.server_in_port = random.randint(1025, 65535)
4331         self.server_out_port = random.randint(1025, 65535)
4332
4333         self.nat44_add_address(self.server_out_addr)
4334
4335         # add static mappings for server
4336         self.nat44_add_static_mapping(self.server_in_addr,
4337                                       self.server_out_addr,
4338                                       self.server_in_port,
4339                                       self.server_out_port,
4340                                       proto=IP_PROTOS.tcp)
4341         self.nat44_add_static_mapping(self.server_in_addr,
4342                                       self.server_out_addr,
4343                                       self.server_in_port,
4344                                       self.server_out_port,
4345                                       proto=IP_PROTOS.udp)
4346         self.nat44_add_static_mapping(self.server_in_addr,
4347                                       self.server_out_addr,
4348                                       proto=IP_PROTOS.icmp)
4349
4350         self.vapi.nat_set_reass(timeout=10)
4351
4352         self.frag_in_order_in_plus_out(proto=IP_PROTOS.tcp)
4353         self.frag_in_order_in_plus_out(proto=IP_PROTOS.udp)
4354         self.frag_in_order_in_plus_out(proto=IP_PROTOS.icmp)
4355
4356     def test_frag_out_of_order_in_plus_out(self):
4357         """ in+out interface fragments out of order """
4358         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
4359         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index,
4360                                                   is_inside=0)
4361         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index)
4362         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
4363                                                   is_inside=0)
4364
4365         self.server = self.pg1.remote_hosts[0]
4366
4367         self.server_in_addr = self.server.ip4
4368         self.server_out_addr = '11.11.11.11'
4369         self.server_in_port = random.randint(1025, 65535)
4370         self.server_out_port = random.randint(1025, 65535)
4371
4372         self.nat44_add_address(self.server_out_addr)
4373
4374         # add static mappings for server
4375         self.nat44_add_static_mapping(self.server_in_addr,
4376                                       self.server_out_addr,
4377                                       self.server_in_port,
4378                                       self.server_out_port,
4379                                       proto=IP_PROTOS.tcp)
4380         self.nat44_add_static_mapping(self.server_in_addr,
4381                                       self.server_out_addr,
4382                                       self.server_in_port,
4383                                       self.server_out_port,
4384                                       proto=IP_PROTOS.udp)
4385         self.nat44_add_static_mapping(self.server_in_addr,
4386                                       self.server_out_addr,
4387                                       proto=IP_PROTOS.icmp)
4388
4389         self.vapi.nat_set_reass(timeout=10)
4390
4391         self.frag_out_of_order_in_plus_out(proto=IP_PROTOS.tcp)
4392         self.frag_out_of_order_in_plus_out(proto=IP_PROTOS.udp)
4393         self.frag_out_of_order_in_plus_out(proto=IP_PROTOS.icmp)
4394
4395     def test_reass_hairpinning(self):
4396         """ NAT44 fragments hairpinning """
4397         self.server = self.pg0.remote_hosts[1]
4398         self.host_in_port = random.randint(1025, 65535)
4399         self.server_in_port = random.randint(1025, 65535)
4400         self.server_out_port = random.randint(1025, 65535)
4401
4402         self.nat44_add_address(self.nat_addr)
4403         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
4404         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
4405                                                   is_inside=0)
4406         # add static mapping for server
4407         self.nat44_add_static_mapping(self.server.ip4, self.nat_addr,
4408                                       self.server_in_port,
4409                                       self.server_out_port,
4410                                       proto=IP_PROTOS.tcp)
4411         self.nat44_add_static_mapping(self.server.ip4, self.nat_addr,
4412                                       self.server_in_port,
4413                                       self.server_out_port,
4414                                       proto=IP_PROTOS.udp)
4415         self.nat44_add_static_mapping(self.server.ip4, self.nat_addr)
4416
4417         self.reass_hairpinning(proto=IP_PROTOS.tcp)
4418         self.reass_hairpinning(proto=IP_PROTOS.udp)
4419         self.reass_hairpinning(proto=IP_PROTOS.icmp)
4420
4421     def test_dynamic(self):
4422         """ NAT44 dynamic translation test """
4423
4424         self.nat44_add_address(self.nat_addr)
4425         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
4426         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
4427                                                   is_inside=0)
4428
4429         nat_config = self.vapi.nat_show_config()
4430         self.assertEqual(1, nat_config.endpoint_dependent)
4431
4432         # in2out
4433         tcpn = self.statistics.get_counter(
4434             '/err/nat44-ed-in2out-slowpath/TCP packets')
4435         udpn = self.statistics.get_counter(
4436             '/err/nat44-ed-in2out-slowpath/UDP packets')
4437         icmpn = self.statistics.get_counter(
4438             '/err/nat44-ed-in2out-slowpath/ICMP packets')
4439         totaln = self.statistics.get_counter(
4440             '/err/nat44-ed-in2out-slowpath/good in2out packets processed')
4441
4442         pkts = self.create_stream_in(self.pg0, self.pg1)
4443         self.pg0.add_stream(pkts)
4444         self.pg_enable_capture(self.pg_interfaces)
4445         self.pg_start()
4446         capture = self.pg1.get_capture(len(pkts))
4447         self.verify_capture_out(capture)
4448
4449         err = self.statistics.get_counter(
4450             '/err/nat44-ed-in2out-slowpath/TCP packets')
4451         self.assertEqual(err - tcpn, 1)
4452         err = self.statistics.get_counter(
4453             '/err/nat44-ed-in2out-slowpath/UDP packets')
4454         self.assertEqual(err - udpn, 1)
4455         err = self.statistics.get_counter(
4456             '/err/nat44-ed-in2out-slowpath/ICMP packets')
4457         self.assertEqual(err - icmpn, 1)
4458         err = self.statistics.get_counter(
4459             '/err/nat44-ed-in2out-slowpath/good in2out packets processed')
4460         self.assertEqual(err - totaln, 3)
4461
4462         # out2in
4463         tcpn = self.statistics.get_counter('/err/nat44-ed-out2in/TCP packets')
4464         udpn = self.statistics.get_counter('/err/nat44-ed-out2in/UDP packets')
4465         icmpn = self.statistics.get_counter(
4466             '/err/nat44-ed-out2in-slowpath/ICMP packets')
4467         totaln = self.statistics.get_counter(
4468             '/err/nat44-ed-out2in/good out2in packets processed')
4469
4470         pkts = self.create_stream_out(self.pg1)
4471         self.pg1.add_stream(pkts)
4472         self.pg_enable_capture(self.pg_interfaces)
4473         self.pg_start()
4474         capture = self.pg0.get_capture(len(pkts))
4475         self.verify_capture_in(capture, self.pg0)
4476
4477         err = self.statistics.get_counter('/err/nat44-ed-out2in/TCP packets')
4478         self.assertEqual(err - tcpn, 1)
4479         err = self.statistics.get_counter('/err/nat44-ed-out2in/UDP packets')
4480         self.assertEqual(err - udpn, 1)
4481         err = self.statistics.get_counter(
4482             '/err/nat44-ed-out2in-slowpath/ICMP packets')
4483         self.assertEqual(err - icmpn, 1)
4484         err = self.statistics.get_counter(
4485             '/err/nat44-ed-out2in/good out2in packets processed')
4486         self.assertEqual(err - totaln, 2)
4487
4488         users = self.statistics.get_counter('/nat44/total-users')
4489         self.assertEqual(users[0][0], 1)
4490         sessions = self.statistics.get_counter('/nat44/total-sessions')
4491         self.assertEqual(sessions[0][0], 3)
4492
4493     def test_forwarding(self):
4494         """ NAT44 forwarding test """
4495
4496         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
4497         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
4498                                                   is_inside=0)
4499         self.vapi.nat44_forwarding_enable_disable(1)
4500
4501         real_ip = self.pg0.remote_ip4n
4502         alias_ip = self.nat_addr_n
4503         self.vapi.nat44_add_del_static_mapping(local_ip=real_ip,
4504                                                external_ip=alias_ip)
4505
4506         try:
4507             # in2out - static mapping match
4508
4509             pkts = self.create_stream_out(self.pg1)
4510             self.pg1.add_stream(pkts)
4511             self.pg_enable_capture(self.pg_interfaces)
4512             self.pg_start()
4513             capture = self.pg0.get_capture(len(pkts))
4514             self.verify_capture_in(capture, self.pg0)
4515
4516             pkts = self.create_stream_in(self.pg0, self.pg1)
4517             self.pg0.add_stream(pkts)
4518             self.pg_enable_capture(self.pg_interfaces)
4519             self.pg_start()
4520             capture = self.pg1.get_capture(len(pkts))
4521             self.verify_capture_out(capture, same_port=True)
4522
4523             # in2out - no static mapping match
4524
4525             host0 = self.pg0.remote_hosts[0]
4526             self.pg0.remote_hosts[0] = self.pg0.remote_hosts[1]
4527             try:
4528                 pkts = self.create_stream_out(self.pg1,
4529                                               dst_ip=self.pg0.remote_ip4,
4530                                               use_inside_ports=True)
4531                 self.pg1.add_stream(pkts)
4532                 self.pg_enable_capture(self.pg_interfaces)
4533                 self.pg_start()
4534                 capture = self.pg0.get_capture(len(pkts))
4535                 self.verify_capture_in(capture, self.pg0)
4536
4537                 pkts = self.create_stream_in(self.pg0, self.pg1)
4538                 self.pg0.add_stream(pkts)
4539                 self.pg_enable_capture(self.pg_interfaces)
4540                 self.pg_start()
4541                 capture = self.pg1.get_capture(len(pkts))
4542                 self.verify_capture_out(capture, nat_ip=self.pg0.remote_ip4,
4543                                         same_port=True)
4544             finally:
4545                 self.pg0.remote_hosts[0] = host0
4546
4547             user = self.pg0.remote_hosts[1]
4548             sessions = self.vapi.nat44_user_session_dump(user.ip4n, 0)
4549             self.assertEqual(len(sessions), 3)
4550             self.assertTrue(sessions[0].ext_host_valid)
4551             self.vapi.nat44_del_session(
4552                 sessions[0].inside_ip_address,
4553                 sessions[0].inside_port,
4554                 sessions[0].protocol,
4555                 ext_host_address=sessions[0].ext_host_address,
4556                 ext_host_port=sessions[0].ext_host_port)
4557             sessions = self.vapi.nat44_user_session_dump(user.ip4n, 0)
4558             self.assertEqual(len(sessions), 2)
4559
4560         finally:
4561             self.vapi.nat44_forwarding_enable_disable(0)
4562             self.vapi.nat44_add_del_static_mapping(local_ip=real_ip,
4563                                                    external_ip=alias_ip,
4564                                                    is_add=0)
4565
4566     def test_static_lb(self):
4567         """ NAT44 local service load balancing """
4568         external_addr_n = socket.inet_pton(socket.AF_INET, self.nat_addr)
4569         external_port = 80
4570         local_port = 8080
4571         server1 = self.pg0.remote_hosts[0]
4572         server2 = self.pg0.remote_hosts[1]
4573
4574         locals = [{'addr': server1.ip4n,
4575                    'port': local_port,
4576                    'probability': 70,
4577                    'vrf_id': 0},
4578                   {'addr': server2.ip4n,
4579                    'port': local_port,
4580                    'probability': 30,
4581                    'vrf_id': 0}]
4582
4583         self.nat44_add_address(self.nat_addr)
4584         self.vapi.nat44_add_del_lb_static_mapping(external_addr_n,
4585                                                   external_port,
4586                                                   IP_PROTOS.tcp,
4587                                                   local_num=len(locals),
4588                                                   locals=locals)
4589         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
4590         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
4591                                                   is_inside=0)
4592
4593         # from client to service
4594         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
4595              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
4596              TCP(sport=12345, dport=external_port))
4597         self.pg1.add_stream(p)
4598         self.pg_enable_capture(self.pg_interfaces)
4599         self.pg_start()
4600         capture = self.pg0.get_capture(1)
4601         p = capture[0]
4602         server = None
4603         try:
4604             ip = p[IP]
4605             tcp = p[TCP]
4606             self.assertIn(ip.dst, [server1.ip4, server2.ip4])
4607             if ip.dst == server1.ip4:
4608                 server = server1
4609             else:
4610                 server = server2
4611             self.assertEqual(tcp.dport, local_port)
4612             self.assert_packet_checksums_valid(p)
4613         except:
4614             self.logger.error(ppp("Unexpected or invalid packet:", p))
4615             raise
4616
4617         # from service back to client
4618         p = (Ether(src=server.mac, dst=self.pg0.local_mac) /
4619              IP(src=server.ip4, dst=self.pg1.remote_ip4) /
4620              TCP(sport=local_port, dport=12345))
4621         self.pg0.add_stream(p)
4622         self.pg_enable_capture(self.pg_interfaces)
4623         self.pg_start()
4624         capture = self.pg1.get_capture(1)
4625         p = capture[0]
4626         try:
4627             ip = p[IP]
4628             tcp = p[TCP]
4629             self.assertEqual(ip.src, self.nat_addr)
4630             self.assertEqual(tcp.sport, external_port)
4631             self.assert_packet_checksums_valid(p)
4632         except:
4633             self.logger.error(ppp("Unexpected or invalid packet:", p))
4634             raise
4635
4636         sessions = self.vapi.nat44_user_session_dump(server.ip4n, 0)
4637         self.assertEqual(len(sessions), 1)
4638         self.assertTrue(sessions[0].ext_host_valid)
4639         self.vapi.nat44_del_session(
4640             sessions[0].inside_ip_address,
4641             sessions[0].inside_port,
4642             sessions[0].protocol,
4643             ext_host_address=sessions[0].ext_host_address,
4644             ext_host_port=sessions[0].ext_host_port)
4645         sessions = self.vapi.nat44_user_session_dump(server.ip4n, 0)
4646         self.assertEqual(len(sessions), 0)
4647
4648     @unittest.skipUnless(running_extended_tests, "part of extended tests")
4649     def test_static_lb_multi_clients(self):
4650         """ NAT44 local service load balancing - multiple clients"""
4651
4652         external_addr_n = socket.inet_pton(socket.AF_INET, self.nat_addr)
4653         external_port = 80
4654         local_port = 8080
4655         server1 = self.pg0.remote_hosts[0]
4656         server2 = self.pg0.remote_hosts[1]
4657         server3 = self.pg0.remote_hosts[2]
4658
4659         locals = [{'addr': server1.ip4n,
4660                    'port': local_port,
4661                    'probability': 90,
4662                    'vrf_id': 0},
4663                   {'addr': server2.ip4n,
4664                    'port': local_port,
4665                    'probability': 10,
4666                    'vrf_id': 0}]
4667
4668         self.nat44_add_address(self.nat_addr)
4669         self.vapi.nat44_add_del_lb_static_mapping(external_addr_n,
4670                                                   external_port,
4671                                                   IP_PROTOS.tcp,
4672                                                   local_num=len(locals),
4673                                                   locals=locals)
4674         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
4675         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
4676                                                   is_inside=0)
4677
4678         server1_n = 0
4679         server2_n = 0
4680         clients = ip4_range(self.pg1.remote_ip4, 10, 50)
4681         pkts = []
4682         for client in clients:
4683             p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
4684                  IP(src=client, dst=self.nat_addr) /
4685                  TCP(sport=12345, dport=external_port))
4686             pkts.append(p)
4687         self.pg1.add_stream(pkts)
4688         self.pg_enable_capture(self.pg_interfaces)
4689         self.pg_start()
4690         capture = self.pg0.get_capture(len(pkts))
4691         for p in capture:
4692             if p[IP].dst == server1.ip4:
4693                 server1_n += 1
4694             else:
4695                 server2_n += 1
4696         self.assertGreater(server1_n, server2_n)
4697
4698         # add new back-end
4699         self.vapi.nat44_lb_static_mapping_add_del_local(external_addr_n,
4700                                                         external_port,
4701                                                         server3.ip4n,
4702                                                         local_port,
4703                                                         IP_PROTOS.tcp,
4704                                                         20)
4705         server1_n = 0
4706         server2_n = 0
4707         server3_n = 0
4708         clients = ip4_range(self.pg1.remote_ip4, 60, 110)
4709         pkts = []
4710         for client in clients:
4711             p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
4712                  IP(src=client, dst=self.nat_addr) /
4713                  TCP(sport=12346, dport=external_port))
4714             pkts.append(p)
4715         self.assertGreater(len(pkts), 0)
4716         self.pg1.add_stream(pkts)
4717         self.pg_enable_capture(self.pg_interfaces)
4718         self.pg_start()
4719         capture = self.pg0.get_capture(len(pkts))
4720         for p in capture:
4721             if p[IP].dst == server1.ip4:
4722                 server1_n += 1
4723             elif p[IP].dst == server2.ip4:
4724                 server2_n += 1
4725             else:
4726                 server3_n += 1
4727         self.assertGreater(server1_n, 0)
4728         self.assertGreater(server2_n, 0)
4729         self.assertGreater(server3_n, 0)
4730
4731         # remove one back-end
4732         self.vapi.nat44_lb_static_mapping_add_del_local(external_addr_n,
4733                                                         external_port,
4734                                                         server2.ip4n,
4735                                                         local_port,
4736                                                         IP_PROTOS.tcp,
4737                                                         10,
4738                                                         is_add=0)
4739         server1_n = 0
4740         server2_n = 0
4741         server3_n = 0
4742         self.pg1.add_stream(pkts)
4743         self.pg_enable_capture(self.pg_interfaces)
4744         self.pg_start()
4745         capture = self.pg0.get_capture(len(pkts))
4746         for p in capture:
4747             if p[IP].dst == server1.ip4:
4748                 server1_n += 1
4749             elif p[IP].dst == server2.ip4:
4750                 server2_n += 1
4751             else:
4752                 server3_n += 1
4753         self.assertGreater(server1_n, 0)
4754         self.assertEqual(server2_n, 0)
4755         self.assertGreater(server3_n, 0)
4756
4757     def test_static_lb_2(self):
4758         """ NAT44 local service load balancing (asymmetrical rule) """
4759         external_addr_n = socket.inet_pton(socket.AF_INET, self.nat_addr)
4760         external_port = 80
4761         local_port = 8080
4762         server1 = self.pg0.remote_hosts[0]
4763         server2 = self.pg0.remote_hosts[1]
4764
4765         locals = [{'addr': server1.ip4n,
4766                    'port': local_port,
4767                    'probability': 70,
4768                    'vrf_id': 0},
4769                   {'addr': server2.ip4n,
4770                    'port': local_port,
4771                    'probability': 30,
4772                    'vrf_id': 0}]
4773
4774         self.vapi.nat44_forwarding_enable_disable(1)
4775         self.vapi.nat44_add_del_lb_static_mapping(external_addr_n,
4776                                                   external_port,
4777                                                   IP_PROTOS.tcp,
4778                                                   out2in_only=1,
4779                                                   local_num=len(locals),
4780                                                   locals=locals)
4781         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
4782         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
4783                                                   is_inside=0)
4784
4785         # from client to service
4786         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
4787              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
4788              TCP(sport=12345, dport=external_port))
4789         self.pg1.add_stream(p)
4790         self.pg_enable_capture(self.pg_interfaces)
4791         self.pg_start()
4792         capture = self.pg0.get_capture(1)
4793         p = capture[0]
4794         server = None
4795         try:
4796             ip = p[IP]
4797             tcp = p[TCP]
4798             self.assertIn(ip.dst, [server1.ip4, server2.ip4])
4799             if ip.dst == server1.ip4:
4800                 server = server1
4801             else:
4802                 server = server2
4803             self.assertEqual(tcp.dport, local_port)
4804             self.assert_packet_checksums_valid(p)
4805         except:
4806             self.logger.error(ppp("Unexpected or invalid packet:", p))
4807             raise
4808
4809         # from service back to client
4810         p = (Ether(src=server.mac, dst=self.pg0.local_mac) /
4811              IP(src=server.ip4, dst=self.pg1.remote_ip4) /
4812              TCP(sport=local_port, dport=12345))
4813         self.pg0.add_stream(p)
4814         self.pg_enable_capture(self.pg_interfaces)
4815         self.pg_start()
4816         capture = self.pg1.get_capture(1)
4817         p = capture[0]
4818         try:
4819             ip = p[IP]
4820             tcp = p[TCP]
4821             self.assertEqual(ip.src, self.nat_addr)
4822             self.assertEqual(tcp.sport, external_port)
4823             self.assert_packet_checksums_valid(p)
4824         except:
4825             self.logger.error(ppp("Unexpected or invalid packet:", p))
4826             raise
4827
4828         # from client to server (no translation)
4829         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
4830              IP(src=self.pg1.remote_ip4, dst=server1.ip4) /
4831              TCP(sport=12346, dport=local_port))
4832         self.pg1.add_stream(p)
4833         self.pg_enable_capture(self.pg_interfaces)
4834         self.pg_start()
4835         capture = self.pg0.get_capture(1)
4836         p = capture[0]
4837         server = None
4838         try:
4839             ip = p[IP]
4840             tcp = p[TCP]
4841             self.assertEqual(ip.dst, server1.ip4)
4842             self.assertEqual(tcp.dport, local_port)
4843             self.assert_packet_checksums_valid(p)
4844         except:
4845             self.logger.error(ppp("Unexpected or invalid packet:", p))
4846             raise
4847
4848         # from service back to client (no translation)
4849         p = (Ether(src=server1.mac, dst=self.pg0.local_mac) /
4850              IP(src=server1.ip4, dst=self.pg1.remote_ip4) /
4851              TCP(sport=local_port, dport=12346))
4852         self.pg0.add_stream(p)
4853         self.pg_enable_capture(self.pg_interfaces)
4854         self.pg_start()
4855         capture = self.pg1.get_capture(1)
4856         p = capture[0]
4857         try:
4858             ip = p[IP]
4859             tcp = p[TCP]
4860             self.assertEqual(ip.src, server1.ip4)
4861             self.assertEqual(tcp.sport, local_port)
4862             self.assert_packet_checksums_valid(p)
4863         except:
4864             self.logger.error(ppp("Unexpected or invalid packet:", p))
4865             raise
4866
4867     def test_lb_affinity(self):
4868         """ NAT44 local service load balancing affinity """
4869         external_addr_n = socket.inet_pton(socket.AF_INET, self.nat_addr)
4870         external_port = 80
4871         local_port = 8080
4872         server1 = self.pg0.remote_hosts[0]
4873         server2 = self.pg0.remote_hosts[1]
4874
4875         locals = [{'addr': server1.ip4n,
4876                    'port': local_port,
4877                    'probability': 50,
4878                    'vrf_id': 0},
4879                   {'addr': server2.ip4n,
4880                    'port': local_port,
4881                    'probability': 50,
4882                    'vrf_id': 0}]
4883
4884         self.nat44_add_address(self.nat_addr)
4885         self.vapi.nat44_add_del_lb_static_mapping(external_addr_n,
4886                                                   external_port,
4887                                                   IP_PROTOS.tcp,
4888                                                   affinity=10800,
4889                                                   local_num=len(locals),
4890                                                   locals=locals)
4891         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
4892         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
4893                                                   is_inside=0)
4894
4895         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
4896              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
4897              TCP(sport=1025, dport=external_port))
4898         self.pg1.add_stream(p)
4899         self.pg_enable_capture(self.pg_interfaces)
4900         self.pg_start()
4901         capture = self.pg0.get_capture(1)
4902         backend = capture[0][IP].dst
4903
4904         sessions = self.vapi.nat44_user_session_dump(
4905             socket.inet_pton(socket.AF_INET, backend), 0)
4906         self.assertEqual(len(sessions), 1)
4907         self.assertTrue(sessions[0].ext_host_valid)
4908         self.vapi.nat44_del_session(
4909             sessions[0].inside_ip_address,
4910             sessions[0].inside_port,
4911             sessions[0].protocol,
4912             ext_host_address=sessions[0].ext_host_address,
4913             ext_host_port=sessions[0].ext_host_port)
4914
4915         pkts = []
4916         for port in range(1030, 1100):
4917             p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
4918                  IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
4919                  TCP(sport=port, dport=external_port))
4920             pkts.append(p)
4921         self.pg1.add_stream(pkts)
4922         self.pg_enable_capture(self.pg_interfaces)
4923         self.pg_start()
4924         capture = self.pg0.get_capture(len(pkts))
4925         for p in capture:
4926             self.assertEqual(p[IP].dst, backend)
4927
4928     def test_unknown_proto(self):
4929         """ NAT44 translate packet with unknown protocol """
4930         self.nat44_add_address(self.nat_addr)
4931         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
4932         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
4933                                                   is_inside=0)
4934
4935         # in2out
4936         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
4937              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
4938              TCP(sport=self.tcp_port_in, dport=20))
4939         self.pg0.add_stream(p)
4940         self.pg_enable_capture(self.pg_interfaces)
4941         self.pg_start()
4942         p = self.pg1.get_capture(1)
4943
4944         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
4945              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
4946              GRE() /
4947              IP(src=self.pg2.remote_ip4, dst=self.pg2.remote_ip4) /
4948              TCP(sport=1234, dport=1234))
4949         self.pg0.add_stream(p)
4950         self.pg_enable_capture(self.pg_interfaces)
4951         self.pg_start()
4952         p = self.pg1.get_capture(1)
4953         packet = p[0]
4954         try:
4955             self.assertEqual(packet[IP].src, self.nat_addr)
4956             self.assertEqual(packet[IP].dst, self.pg1.remote_ip4)
4957             self.assertEqual(packet.haslayer(GRE), 1)
4958             self.assert_packet_checksums_valid(packet)
4959         except:
4960             self.logger.error(ppp("Unexpected or invalid packet:", packet))
4961             raise
4962
4963         # out2in
4964         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
4965              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
4966              GRE() /
4967              IP(src=self.pg2.remote_ip4, dst=self.pg2.remote_ip4) /
4968              TCP(sport=1234, dport=1234))
4969         self.pg1.add_stream(p)
4970         self.pg_enable_capture(self.pg_interfaces)
4971         self.pg_start()
4972         p = self.pg0.get_capture(1)
4973         packet = p[0]
4974         try:
4975             self.assertEqual(packet[IP].src, self.pg1.remote_ip4)
4976             self.assertEqual(packet[IP].dst, self.pg0.remote_ip4)
4977             self.assertEqual(packet.haslayer(GRE), 1)
4978             self.assert_packet_checksums_valid(packet)
4979         except:
4980             self.logger.error(ppp("Unexpected or invalid packet:", packet))
4981             raise
4982
4983     def test_hairpinning_unknown_proto(self):
4984         """ NAT44 translate packet with unknown protocol - hairpinning """
4985         host = self.pg0.remote_hosts[0]
4986         server = self.pg0.remote_hosts[1]
4987         host_in_port = 1234
4988         server_out_port = 8765
4989         server_nat_ip = "10.0.0.11"
4990
4991         self.nat44_add_address(self.nat_addr)
4992         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
4993         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
4994                                                   is_inside=0)
4995
4996         # add static mapping for server
4997         self.nat44_add_static_mapping(server.ip4, server_nat_ip)
4998
4999         # host to server
5000         p = (Ether(src=host.mac, dst=self.pg0.local_mac) /
5001              IP(src=host.ip4, dst=server_nat_ip) /
5002              TCP(sport=host_in_port, dport=server_out_port))
5003         self.pg0.add_stream(p)
5004         self.pg_enable_capture(self.pg_interfaces)
5005         self.pg_start()
5006         self.pg0.get_capture(1)
5007
5008         p = (Ether(dst=self.pg0.local_mac, src=host.mac) /
5009              IP(src=host.ip4, dst=server_nat_ip) /
5010              GRE() /
5011              IP(src=self.pg2.remote_ip4, dst=self.pg2.remote_ip4) /
5012              TCP(sport=1234, dport=1234))
5013         self.pg0.add_stream(p)
5014         self.pg_enable_capture(self.pg_interfaces)
5015         self.pg_start()
5016         p = self.pg0.get_capture(1)
5017         packet = p[0]
5018         try:
5019             self.assertEqual(packet[IP].src, self.nat_addr)
5020             self.assertEqual(packet[IP].dst, server.ip4)
5021             self.assertEqual(packet.haslayer(GRE), 1)
5022             self.assert_packet_checksums_valid(packet)
5023         except:
5024             self.logger.error(ppp("Unexpected or invalid packet:", packet))
5025             raise
5026
5027         # server to host
5028         p = (Ether(dst=self.pg0.local_mac, src=server.mac) /
5029              IP(src=server.ip4, dst=self.nat_addr) /
5030              GRE() /
5031              IP(src=self.pg2.remote_ip4, dst=self.pg2.remote_ip4) /
5032              TCP(sport=1234, dport=1234))
5033         self.pg0.add_stream(p)
5034         self.pg_enable_capture(self.pg_interfaces)
5035         self.pg_start()
5036         p = self.pg0.get_capture(1)
5037         packet = p[0]
5038         try:
5039             self.assertEqual(packet[IP].src, server_nat_ip)
5040             self.assertEqual(packet[IP].dst, host.ip4)
5041             self.assertEqual(packet.haslayer(GRE), 1)
5042             self.assert_packet_checksums_valid(packet)
5043         except:
5044             self.logger.error(ppp("Unexpected or invalid packet:", packet))
5045             raise
5046
5047     def test_output_feature_and_service(self):
5048         """ NAT44 interface output feature and services """
5049         external_addr = '1.2.3.4'
5050         external_port = 80
5051         local_port = 8080
5052
5053         self.vapi.nat44_forwarding_enable_disable(1)
5054         self.nat44_add_address(self.nat_addr)
5055         self.vapi.nat44_add_del_identity_mapping(ip=self.pg1.remote_ip4n)
5056         self.nat44_add_static_mapping(self.pg0.remote_ip4, external_addr,
5057                                       local_port, external_port,
5058                                       proto=IP_PROTOS.tcp, out2in_only=1)
5059         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
5060         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index,
5061                                                   is_inside=0)
5062         self.vapi.nat44_interface_add_del_output_feature(self.pg1.sw_if_index,
5063                                                          is_inside=0)
5064
5065         # from client to service
5066         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
5067              IP(src=self.pg1.remote_ip4, dst=external_addr) /
5068              TCP(sport=12345, dport=external_port))
5069         self.pg1.add_stream(p)
5070         self.pg_enable_capture(self.pg_interfaces)
5071         self.pg_start()
5072         capture = self.pg0.get_capture(1)
5073         p = capture[0]
5074         try:
5075             ip = p[IP]
5076             tcp = p[TCP]
5077             self.assertEqual(ip.dst, self.pg0.remote_ip4)
5078             self.assertEqual(tcp.dport, local_port)
5079             self.assert_packet_checksums_valid(p)
5080         except:
5081             self.logger.error(ppp("Unexpected or invalid packet:", p))
5082             raise
5083
5084         # from service back to client
5085         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
5086              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
5087              TCP(sport=local_port, dport=12345))
5088         self.pg0.add_stream(p)
5089         self.pg_enable_capture(self.pg_interfaces)
5090         self.pg_start()
5091         capture = self.pg1.get_capture(1)
5092         p = capture[0]
5093         try:
5094             ip = p[IP]
5095             tcp = p[TCP]
5096             self.assertEqual(ip.src, external_addr)
5097             self.assertEqual(tcp.sport, external_port)
5098             self.assert_packet_checksums_valid(p)
5099         except:
5100             self.logger.error(ppp("Unexpected or invalid packet:", p))
5101             raise
5102
5103         # from local network host to external network
5104         pkts = self.create_stream_in(self.pg0, self.pg1)
5105         self.pg0.add_stream(pkts)
5106         self.pg_enable_capture(self.pg_interfaces)
5107         self.pg_start()
5108         capture = self.pg1.get_capture(len(pkts))
5109         self.verify_capture_out(capture)
5110         pkts = self.create_stream_in(self.pg0, self.pg1)
5111         self.pg0.add_stream(pkts)
5112         self.pg_enable_capture(self.pg_interfaces)
5113         self.pg_start()
5114         capture = self.pg1.get_capture(len(pkts))
5115         self.verify_capture_out(capture)
5116
5117         # from external network back to local network host
5118         pkts = self.create_stream_out(self.pg1)
5119         self.pg1.add_stream(pkts)
5120         self.pg_enable_capture(self.pg_interfaces)
5121         self.pg_start()
5122         capture = self.pg0.get_capture(len(pkts))
5123         self.verify_capture_in(capture, self.pg0)
5124
5125     def test_output_feature_and_service2(self):
5126         """ NAT44 interface output feature and service host direct access """
5127         self.vapi.nat44_forwarding_enable_disable(1)
5128         self.nat44_add_address(self.nat_addr)
5129         self.vapi.nat44_interface_add_del_output_feature(self.pg1.sw_if_index,
5130                                                          is_inside=0)
5131
5132         # session initiaded from service host - translate
5133         pkts = self.create_stream_in(self.pg0, self.pg1)
5134         self.pg0.add_stream(pkts)
5135         self.pg_enable_capture(self.pg_interfaces)
5136         self.pg_start()
5137         capture = self.pg1.get_capture(len(pkts))
5138         self.verify_capture_out(capture)
5139
5140         pkts = self.create_stream_out(self.pg1)
5141         self.pg1.add_stream(pkts)
5142         self.pg_enable_capture(self.pg_interfaces)
5143         self.pg_start()
5144         capture = self.pg0.get_capture(len(pkts))
5145         self.verify_capture_in(capture, self.pg0)
5146
5147         # session initiaded from remote host - do not translate
5148         self.tcp_port_in = 60303
5149         self.udp_port_in = 60304
5150         self.icmp_id_in = 60305
5151         pkts = self.create_stream_out(self.pg1,
5152                                       self.pg0.remote_ip4,
5153                                       use_inside_ports=True)
5154         self.pg1.add_stream(pkts)
5155         self.pg_enable_capture(self.pg_interfaces)
5156         self.pg_start()
5157         capture = self.pg0.get_capture(len(pkts))
5158         self.verify_capture_in(capture, self.pg0)
5159
5160         pkts = self.create_stream_in(self.pg0, self.pg1)
5161         self.pg0.add_stream(pkts)
5162         self.pg_enable_capture(self.pg_interfaces)
5163         self.pg_start()
5164         capture = self.pg1.get_capture(len(pkts))
5165         self.verify_capture_out(capture, nat_ip=self.pg0.remote_ip4,
5166                                 same_port=True)
5167
5168     def test_output_feature_and_service3(self):
5169         """ NAT44 interface output feature and DST NAT """
5170         external_addr = '1.2.3.4'
5171         external_port = 80
5172         local_port = 8080
5173
5174         self.vapi.nat44_forwarding_enable_disable(1)
5175         self.nat44_add_address(self.nat_addr)
5176         self.nat44_add_static_mapping(self.pg1.remote_ip4, external_addr,
5177                                       local_port, external_port,
5178                                       proto=IP_PROTOS.tcp, out2in_only=1)
5179         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
5180         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index,
5181                                                   is_inside=0)
5182         self.vapi.nat44_interface_add_del_output_feature(self.pg1.sw_if_index,
5183                                                          is_inside=0)
5184
5185         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
5186              IP(src=self.pg0.remote_ip4, dst=external_addr) /
5187              TCP(sport=12345, dport=external_port))
5188         self.pg0.add_stream(p)
5189         self.pg_enable_capture(self.pg_interfaces)
5190         self.pg_start()
5191         capture = self.pg1.get_capture(1)
5192         p = capture[0]
5193         try:
5194             ip = p[IP]
5195             tcp = p[TCP]
5196             self.assertEqual(ip.src, self.pg0.remote_ip4)
5197             self.assertEqual(tcp.sport, 12345)
5198             self.assertEqual(ip.dst, self.pg1.remote_ip4)
5199             self.assertEqual(tcp.dport, local_port)
5200             self.assert_packet_checksums_valid(p)
5201         except:
5202             self.logger.error(ppp("Unexpected or invalid packet:", p))
5203             raise
5204
5205         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
5206              IP(src=self.pg1.remote_ip4, dst=self.pg0.remote_ip4) /
5207              TCP(sport=local_port, dport=12345))
5208         self.pg1.add_stream(p)
5209         self.pg_enable_capture(self.pg_interfaces)
5210         self.pg_start()
5211         capture = self.pg0.get_capture(1)
5212         p = capture[0]
5213         try:
5214             ip = p[IP]
5215             tcp = p[TCP]
5216             self.assertEqual(ip.src, external_addr)
5217             self.assertEqual(tcp.sport, external_port)
5218             self.assertEqual(ip.dst, self.pg0.remote_ip4)
5219             self.assertEqual(tcp.dport, 12345)
5220             self.assert_packet_checksums_valid(p)
5221         except:
5222             self.logger.error(ppp("Unexpected or invalid packet:", p))
5223             raise
5224
5225     def test_next_src_nat(self):
5226         """ On way back forward packet to nat44-in2out node. """
5227         twice_nat_addr = '10.0.1.3'
5228         external_port = 80
5229         local_port = 8080
5230         post_twice_nat_port = 0
5231
5232         self.vapi.nat44_forwarding_enable_disable(1)
5233         self.nat44_add_address(twice_nat_addr, twice_nat=1)
5234         self.nat44_add_static_mapping(self.pg6.remote_ip4, self.pg1.remote_ip4,
5235                                       local_port, external_port,
5236                                       proto=IP_PROTOS.tcp, out2in_only=1,
5237                                       self_twice_nat=1, vrf_id=1)
5238         self.vapi.nat44_interface_add_del_feature(self.pg6.sw_if_index,
5239                                                   is_inside=0)
5240
5241         p = (Ether(src=self.pg6.remote_mac, dst=self.pg6.local_mac) /
5242              IP(src=self.pg6.remote_ip4, dst=self.pg1.remote_ip4) /
5243              TCP(sport=12345, dport=external_port))
5244         self.pg6.add_stream(p)
5245         self.pg_enable_capture(self.pg_interfaces)
5246         self.pg_start()
5247         capture = self.pg6.get_capture(1)
5248         p = capture[0]
5249         try:
5250             ip = p[IP]
5251             tcp = p[TCP]
5252             self.assertEqual(ip.src, twice_nat_addr)
5253             self.assertNotEqual(tcp.sport, 12345)
5254             post_twice_nat_port = tcp.sport
5255             self.assertEqual(ip.dst, self.pg6.remote_ip4)
5256             self.assertEqual(tcp.dport, local_port)
5257             self.assert_packet_checksums_valid(p)
5258         except:
5259             self.logger.error(ppp("Unexpected or invalid packet:", p))
5260             raise
5261
5262         p = (Ether(src=self.pg6.remote_mac, dst=self.pg6.local_mac) /
5263              IP(src=self.pg6.remote_ip4, dst=twice_nat_addr) /
5264              TCP(sport=local_port, dport=post_twice_nat_port))
5265         self.pg6.add_stream(p)
5266         self.pg_enable_capture(self.pg_interfaces)
5267         self.pg_start()
5268         capture = self.pg6.get_capture(1)
5269         p = capture[0]
5270         try:
5271             ip = p[IP]
5272             tcp = p[TCP]
5273             self.assertEqual(ip.src, self.pg1.remote_ip4)
5274             self.assertEqual(tcp.sport, external_port)
5275             self.assertEqual(ip.dst, self.pg6.remote_ip4)
5276             self.assertEqual(tcp.dport, 12345)
5277             self.assert_packet_checksums_valid(p)
5278         except:
5279             self.logger.error(ppp("Unexpected or invalid packet:", p))
5280             raise
5281
5282     def twice_nat_common(self, self_twice_nat=False, same_pg=False, lb=False,
5283                          client_id=None):
5284         twice_nat_addr = '10.0.1.3'
5285
5286         port_in = 8080
5287         if lb:
5288             if not same_pg:
5289                 port_in1 = port_in
5290                 port_in2 = port_in
5291             else:
5292                 port_in1 = port_in + 1
5293                 port_in2 = port_in + 2
5294
5295         port_out = 80
5296         eh_port_out = 4567
5297
5298         server1 = self.pg0.remote_hosts[0]
5299         server2 = self.pg0.remote_hosts[1]
5300         if lb and same_pg:
5301             server2 = server1
5302         if not lb:
5303             server = server1
5304
5305         pg0 = self.pg0
5306         if same_pg:
5307             pg1 = self.pg0
5308         else:
5309             pg1 = self.pg1
5310
5311         eh_translate = ((not self_twice_nat) or (not lb and same_pg) or
5312                         client_id == 1)
5313
5314         self.nat44_add_address(self.nat_addr)
5315         self.nat44_add_address(twice_nat_addr, twice_nat=1)
5316         if not lb:
5317             self.nat44_add_static_mapping(pg0.remote_ip4, self.nat_addr,
5318                                           port_in, port_out,
5319                                           proto=IP_PROTOS.tcp,
5320                                           twice_nat=int(not self_twice_nat),
5321                                           self_twice_nat=int(self_twice_nat))
5322         else:
5323             locals = [{'addr': server1.ip4n,
5324                        'port': port_in1,
5325                        'probability': 50,
5326                        'vrf_id': 0},
5327                       {'addr': server2.ip4n,
5328                        'port': port_in2,
5329                        'probability': 50,
5330                        'vrf_id': 0}]
5331             out_addr_n = socket.inet_pton(socket.AF_INET, self.nat_addr)
5332             self.vapi.nat44_add_del_lb_static_mapping(out_addr_n,
5333                                                       port_out,
5334                                                       IP_PROTOS.tcp,
5335                                                       twice_nat=int(
5336                                                           not self_twice_nat),
5337                                                       self_twice_nat=int(
5338                                                           self_twice_nat),
5339                                                       local_num=len(locals),
5340                                                       locals=locals)
5341         self.vapi.nat44_interface_add_del_feature(pg0.sw_if_index)
5342         self.vapi.nat44_interface_add_del_feature(pg1.sw_if_index,
5343                                                   is_inside=0)
5344
5345         if same_pg:
5346             if not lb:
5347                 client = server
5348             else:
5349                 assert client_id is not None
5350                 if client_id == 1:
5351                     client = self.pg0.remote_hosts[0]
5352                 elif client_id == 2:
5353                     client = self.pg0.remote_hosts[1]
5354         else:
5355             client = pg1.remote_hosts[0]
5356         p = (Ether(src=pg1.remote_mac, dst=pg1.local_mac) /
5357              IP(src=client.ip4, dst=self.nat_addr) /
5358              TCP(sport=eh_port_out, dport=port_out))
5359         pg1.add_stream(p)
5360         self.pg_enable_capture(self.pg_interfaces)
5361         self.pg_start()
5362         capture = pg0.get_capture(1)
5363         p = capture[0]
5364         try:
5365             ip = p[IP]
5366             tcp = p[TCP]
5367             if lb:
5368                 if ip.dst == server1.ip4:
5369                     server = server1
5370                     port_in = port_in1
5371                 else:
5372                     server = server2
5373                     port_in = port_in2
5374             self.assertEqual(ip.dst, server.ip4)
5375             if lb and same_pg:
5376                 self.assertIn(tcp.dport, [port_in1, port_in2])
5377             else:
5378                 self.assertEqual(tcp.dport, port_in)
5379             if eh_translate:
5380                 self.assertEqual(ip.src, twice_nat_addr)
5381                 self.assertNotEqual(tcp.sport, eh_port_out)
5382             else:
5383                 self.assertEqual(ip.src, client.ip4)
5384                 self.assertEqual(tcp.sport, eh_port_out)
5385             eh_addr_in = ip.src
5386             eh_port_in = tcp.sport
5387             saved_port_in = tcp.dport
5388             self.assert_packet_checksums_valid(p)
5389         except:
5390             self.logger.error(ppp("Unexpected or invalid packet:", p))
5391             raise
5392
5393         p = (Ether(src=server.mac, dst=pg0.local_mac) /
5394              IP(src=server.ip4, dst=eh_addr_in) /
5395              TCP(sport=saved_port_in, dport=eh_port_in))
5396         pg0.add_stream(p)
5397         self.pg_enable_capture(self.pg_interfaces)
5398         self.pg_start()
5399         capture = pg1.get_capture(1)
5400         p = capture[0]
5401         try:
5402             ip = p[IP]
5403             tcp = p[TCP]
5404             self.assertEqual(ip.dst, client.ip4)
5405             self.assertEqual(ip.src, self.nat_addr)
5406             self.assertEqual(tcp.dport, eh_port_out)
5407             self.assertEqual(tcp.sport, port_out)
5408             self.assert_packet_checksums_valid(p)
5409         except:
5410             self.logger.error(ppp("Unexpected or invalid packet:", p))
5411             raise
5412
5413         if eh_translate:
5414             sessions = self.vapi.nat44_user_session_dump(server.ip4n, 0)
5415             self.assertEqual(len(sessions), 1)
5416             self.assertTrue(sessions[0].ext_host_valid)
5417             self.assertTrue(sessions[0].is_twicenat)
5418             self.vapi.nat44_del_session(
5419                 sessions[0].inside_ip_address,
5420                 sessions[0].inside_port,
5421                 sessions[0].protocol,
5422                 ext_host_address=sessions[0].ext_host_nat_address,
5423                 ext_host_port=sessions[0].ext_host_nat_port)
5424             sessions = self.vapi.nat44_user_session_dump(server.ip4n, 0)
5425             self.assertEqual(len(sessions), 0)
5426
5427     def test_twice_nat(self):
5428         """ Twice NAT44 """
5429         self.twice_nat_common()
5430
5431     def test_self_twice_nat_positive(self):
5432         """ Self Twice NAT44 (positive test) """
5433         self.twice_nat_common(self_twice_nat=True, same_pg=True)
5434
5435     def test_self_twice_nat_negative(self):
5436         """ Self Twice NAT44 (negative test) """
5437         self.twice_nat_common(self_twice_nat=True)
5438
5439     def test_twice_nat_lb(self):
5440         """ Twice NAT44 local service load balancing """
5441         self.twice_nat_common(lb=True)
5442
5443     def test_self_twice_nat_lb_positive(self):
5444         """ Self Twice NAT44 local service load balancing (positive test) """
5445         self.twice_nat_common(lb=True, self_twice_nat=True, same_pg=True,
5446                               client_id=1)
5447
5448     def test_self_twice_nat_lb_negative(self):
5449         """ Self Twice NAT44 local service load balancing (negative test) """
5450         self.twice_nat_common(lb=True, self_twice_nat=True, same_pg=True,
5451                               client_id=2)
5452
5453     def test_twice_nat_interface_addr(self):
5454         """ Acquire twice NAT44 addresses from interface """
5455         self.vapi.nat44_add_del_interface_addr(self.pg3.sw_if_index,
5456                                                twice_nat=1)
5457
5458         # no address in NAT pool
5459         adresses = self.vapi.nat44_address_dump()
5460         self.assertEqual(0, len(adresses))
5461
5462         # configure interface address and check NAT address pool
5463         self.pg3.config_ip4()
5464         adresses = self.vapi.nat44_address_dump()
5465         self.assertEqual(1, len(adresses))
5466         self.assertEqual(adresses[0].ip_address[0:4], self.pg3.local_ip4n)
5467         self.assertEqual(adresses[0].twice_nat, 1)
5468
5469         # remove interface address and check NAT address pool
5470         self.pg3.unconfig_ip4()
5471         adresses = self.vapi.nat44_address_dump()
5472         self.assertEqual(0, len(adresses))
5473
5474     def test_tcp_close(self):
5475         """ Close TCP session from inside network - output feature """
5476         self.vapi.nat44_forwarding_enable_disable(1)
5477         self.nat44_add_address(self.pg1.local_ip4)
5478         twice_nat_addr = '10.0.1.3'
5479         service_ip = '192.168.16.150'
5480         self.nat44_add_address(twice_nat_addr, twice_nat=1)
5481         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
5482         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index,
5483                                                   is_inside=0)
5484         self.vapi.nat44_interface_add_del_output_feature(self.pg1.sw_if_index,
5485                                                          is_inside=0)
5486         self.nat44_add_static_mapping(self.pg0.remote_ip4,
5487                                       service_ip,
5488                                       80,
5489                                       80,
5490                                       proto=IP_PROTOS.tcp,
5491                                       out2in_only=1,
5492                                       twice_nat=1)
5493         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4n, 0)
5494         start_sessnum = len(sessions)
5495
5496         # SYN packet out->in
5497         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
5498              IP(src=self.pg1.remote_ip4, dst=service_ip) /
5499              TCP(sport=33898, dport=80, flags="S"))
5500         self.pg1.add_stream(p)
5501         self.pg_enable_capture(self.pg_interfaces)
5502         self.pg_start()
5503         capture = self.pg0.get_capture(1)
5504         p = capture[0]
5505         tcp_port = p[TCP].sport
5506
5507         # SYN + ACK packet in->out
5508         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
5509              IP(src=self.pg0.remote_ip4, dst=twice_nat_addr) /
5510              TCP(sport=80, dport=tcp_port, flags="SA"))
5511         self.pg0.add_stream(p)
5512         self.pg_enable_capture(self.pg_interfaces)
5513         self.pg_start()
5514         self.pg1.get_capture(1)
5515
5516         # ACK packet out->in
5517         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
5518              IP(src=self.pg1.remote_ip4, dst=service_ip) /
5519              TCP(sport=33898, dport=80, flags="A"))
5520         self.pg1.add_stream(p)
5521         self.pg_enable_capture(self.pg_interfaces)
5522         self.pg_start()
5523         self.pg0.get_capture(1)
5524
5525         # FIN packet in -> out
5526         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
5527              IP(src=self.pg0.remote_ip4, dst=twice_nat_addr) /
5528              TCP(sport=80, dport=tcp_port, flags="FA", seq=100, ack=300))
5529         self.pg0.add_stream(p)
5530         self.pg_enable_capture(self.pg_interfaces)
5531         self.pg_start()
5532         self.pg1.get_capture(1)
5533
5534         # FIN+ACK packet out -> in
5535         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
5536              IP(src=self.pg1.remote_ip4, dst=service_ip) /
5537              TCP(sport=33898, dport=80, flags="FA", seq=300, ack=101))
5538         self.pg1.add_stream(p)
5539         self.pg_enable_capture(self.pg_interfaces)
5540         self.pg_start()
5541         self.pg0.get_capture(1)
5542
5543         # ACK packet in -> out
5544         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
5545              IP(src=self.pg0.remote_ip4, dst=twice_nat_addr) /
5546              TCP(sport=80, dport=tcp_port, flags="A", seq=101, ack=301))
5547         self.pg0.add_stream(p)
5548         self.pg_enable_capture(self.pg_interfaces)
5549         self.pg_start()
5550         self.pg1.get_capture(1)
5551
5552         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4n,
5553                                                      0)
5554         self.assertEqual(len(sessions) - start_sessnum, 0)
5555
5556     def test_tcp_session_close_in(self):
5557         """ Close TCP session from inside network """
5558         self.tcp_port_out = 10505
5559         self.nat44_add_address(self.nat_addr)
5560         self.nat44_add_static_mapping(self.pg0.remote_ip4,
5561                                       self.nat_addr,
5562                                       self.tcp_port_in,
5563                                       self.tcp_port_out,
5564                                       proto=IP_PROTOS.tcp,
5565                                       twice_nat=1)
5566         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
5567         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
5568                                                   is_inside=0)
5569
5570         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4n, 0)
5571         start_sessnum = len(sessions)
5572
5573         self.initiate_tcp_session(self.pg0, self.pg1)
5574
5575         # FIN packet in -> out
5576         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
5577              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
5578              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
5579                  flags="FA", seq=100, ack=300))
5580         self.pg0.add_stream(p)
5581         self.pg_enable_capture(self.pg_interfaces)
5582         self.pg_start()
5583         self.pg1.get_capture(1)
5584
5585         pkts = []
5586
5587         # ACK packet out -> in
5588         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
5589              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
5590              TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
5591                  flags="A", seq=300, ack=101))
5592         pkts.append(p)
5593
5594         # FIN packet out -> in
5595         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
5596              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
5597              TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
5598                  flags="FA", seq=300, ack=101))
5599         pkts.append(p)
5600
5601         self.pg1.add_stream(pkts)
5602         self.pg_enable_capture(self.pg_interfaces)
5603         self.pg_start()
5604         self.pg0.get_capture(2)
5605
5606         # ACK packet in -> out
5607         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
5608              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
5609              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
5610                  flags="A", seq=101, ack=301))
5611         self.pg0.add_stream(p)
5612         self.pg_enable_capture(self.pg_interfaces)
5613         self.pg_start()
5614         self.pg1.get_capture(1)
5615
5616         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4n,
5617                                                      0)
5618         self.assertEqual(len(sessions) - start_sessnum, 0)
5619
5620     def test_tcp_session_close_out(self):
5621         """ Close TCP session from outside network """
5622         self.tcp_port_out = 10505
5623         self.nat44_add_address(self.nat_addr)
5624         self.nat44_add_static_mapping(self.pg0.remote_ip4,
5625                                       self.nat_addr,
5626                                       self.tcp_port_in,
5627                                       self.tcp_port_out,
5628                                       proto=IP_PROTOS.tcp,
5629                                       twice_nat=1)
5630         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
5631         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
5632                                                   is_inside=0)
5633
5634         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4n, 0)
5635         start_sessnum = len(sessions)
5636
5637         self.initiate_tcp_session(self.pg0, self.pg1)
5638
5639         # FIN packet out -> in
5640         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
5641              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
5642              TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
5643                  flags="FA", seq=100, ack=300))
5644         self.pg1.add_stream(p)
5645         self.pg_enable_capture(self.pg_interfaces)
5646         self.pg_start()
5647         self.pg0.get_capture(1)
5648
5649         # FIN+ACK packet in -> out
5650         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
5651              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
5652              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
5653                  flags="FA", seq=300, ack=101))
5654
5655         self.pg0.add_stream(p)
5656         self.pg_enable_capture(self.pg_interfaces)
5657         self.pg_start()
5658         self.pg1.get_capture(1)
5659
5660         # ACK packet out -> in
5661         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
5662              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
5663              TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
5664                  flags="A", seq=101, ack=301))
5665         self.pg1.add_stream(p)
5666         self.pg_enable_capture(self.pg_interfaces)
5667         self.pg_start()
5668         self.pg0.get_capture(1)
5669
5670         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4n,
5671                                                      0)
5672         self.assertEqual(len(sessions) - start_sessnum, 0)
5673
5674     def test_tcp_session_close_simultaneous(self):
5675         """ Close TCP session from inside network """
5676         self.tcp_port_out = 10505
5677         self.nat44_add_address(self.nat_addr)
5678         self.nat44_add_static_mapping(self.pg0.remote_ip4,
5679                                       self.nat_addr,
5680                                       self.tcp_port_in,
5681                                       self.tcp_port_out,
5682                                       proto=IP_PROTOS.tcp,
5683                                       twice_nat=1)
5684         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
5685         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
5686                                                   is_inside=0)
5687
5688         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4n, 0)
5689         start_sessnum = len(sessions)
5690
5691         self.initiate_tcp_session(self.pg0, self.pg1)
5692
5693         # FIN packet in -> out
5694         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
5695              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
5696              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
5697                  flags="FA", seq=100, ack=300))
5698         self.pg0.add_stream(p)
5699         self.pg_enable_capture(self.pg_interfaces)
5700         self.pg_start()
5701         self.pg1.get_capture(1)
5702
5703         # FIN packet out -> in
5704         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
5705              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
5706              TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
5707                  flags="FA", seq=300, ack=100))
5708         self.pg1.add_stream(p)
5709         self.pg_enable_capture(self.pg_interfaces)
5710         self.pg_start()
5711         self.pg0.get_capture(1)
5712
5713         # ACK packet in -> out
5714         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
5715              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
5716              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
5717                  flags="A", seq=101, ack=301))
5718         self.pg0.add_stream(p)
5719         self.pg_enable_capture(self.pg_interfaces)
5720         self.pg_start()
5721         self.pg1.get_capture(1)
5722
5723         # ACK packet out -> in
5724         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
5725              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
5726              TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
5727                  flags="A", seq=301, ack=101))
5728         self.pg1.add_stream(p)
5729         self.pg_enable_capture(self.pg_interfaces)
5730         self.pg_start()
5731         self.pg0.get_capture(1)
5732
5733         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4n,
5734                                                      0)
5735         self.assertEqual(len(sessions) - start_sessnum, 0)
5736
5737     def test_one_armed_nat44_static(self):
5738         """ One armed NAT44 and 1:1 NAPT asymmetrical rule """
5739         remote_host = self.pg4.remote_hosts[0]
5740         local_host = self.pg4.remote_hosts[1]
5741         external_port = 80
5742         local_port = 8080
5743         eh_port_in = 0
5744
5745         self.vapi.nat44_forwarding_enable_disable(1)
5746         self.nat44_add_address(self.nat_addr, twice_nat=1)
5747         self.nat44_add_static_mapping(local_host.ip4, self.nat_addr,
5748                                       local_port, external_port,
5749                                       proto=IP_PROTOS.tcp, out2in_only=1,
5750                                       twice_nat=1)
5751         self.vapi.nat44_interface_add_del_feature(self.pg4.sw_if_index)
5752         self.vapi.nat44_interface_add_del_feature(self.pg4.sw_if_index,
5753                                                   is_inside=0)
5754
5755         # from client to service
5756         p = (Ether(src=self.pg4.remote_mac, dst=self.pg4.local_mac) /
5757              IP(src=remote_host.ip4, dst=self.nat_addr) /
5758              TCP(sport=12345, dport=external_port))
5759         self.pg4.add_stream(p)
5760         self.pg_enable_capture(self.pg_interfaces)
5761         self.pg_start()
5762         capture = self.pg4.get_capture(1)
5763         p = capture[0]
5764         try:
5765             ip = p[IP]
5766             tcp = p[TCP]
5767             self.assertEqual(ip.dst, local_host.ip4)
5768             self.assertEqual(ip.src, self.nat_addr)
5769             self.assertEqual(tcp.dport, local_port)
5770             self.assertNotEqual(tcp.sport, 12345)
5771             eh_port_in = tcp.sport
5772             self.assert_packet_checksums_valid(p)
5773         except:
5774             self.logger.error(ppp("Unexpected or invalid packet:", p))
5775             raise
5776
5777         # from service back to client
5778         p = (Ether(src=self.pg4.remote_mac, dst=self.pg4.local_mac) /
5779              IP(src=local_host.ip4, dst=self.nat_addr) /
5780              TCP(sport=local_port, dport=eh_port_in))
5781         self.pg4.add_stream(p)
5782         self.pg_enable_capture(self.pg_interfaces)
5783         self.pg_start()
5784         capture = self.pg4.get_capture(1)
5785         p = capture[0]
5786         try:
5787             ip = p[IP]
5788             tcp = p[TCP]
5789             self.assertEqual(ip.src, self.nat_addr)
5790             self.assertEqual(ip.dst, remote_host.ip4)
5791             self.assertEqual(tcp.sport, external_port)
5792             self.assertEqual(tcp.dport, 12345)
5793             self.assert_packet_checksums_valid(p)
5794         except:
5795             self.logger.error(ppp("Unexpected or invalid packet:", p))
5796             raise
5797
5798     def test_static_with_port_out2(self):
5799         """ 1:1 NAPT asymmetrical rule """
5800
5801         external_port = 80
5802         local_port = 8080
5803
5804         self.vapi.nat44_forwarding_enable_disable(1)
5805         self.nat44_add_static_mapping(self.pg0.remote_ip4, self.nat_addr,
5806                                       local_port, external_port,
5807                                       proto=IP_PROTOS.tcp, out2in_only=1)
5808         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
5809         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
5810                                                   is_inside=0)
5811
5812         # from client to service
5813         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
5814              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
5815              TCP(sport=12345, dport=external_port))
5816         self.pg1.add_stream(p)
5817         self.pg_enable_capture(self.pg_interfaces)
5818         self.pg_start()
5819         capture = self.pg0.get_capture(1)
5820         p = capture[0]
5821         try:
5822             ip = p[IP]
5823             tcp = p[TCP]
5824             self.assertEqual(ip.dst, self.pg0.remote_ip4)
5825             self.assertEqual(tcp.dport, local_port)
5826             self.assert_packet_checksums_valid(p)
5827         except:
5828             self.logger.error(ppp("Unexpected or invalid packet:", p))
5829             raise
5830
5831         # ICMP error
5832         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
5833              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
5834              ICMP(type=11) / capture[0][IP])
5835         self.pg0.add_stream(p)
5836         self.pg_enable_capture(self.pg_interfaces)
5837         self.pg_start()
5838         capture = self.pg1.get_capture(1)
5839         p = capture[0]
5840         try:
5841             self.assertEqual(p[IP].src, self.nat_addr)
5842             inner = p[IPerror]
5843             self.assertEqual(inner.dst, self.nat_addr)
5844             self.assertEqual(inner[TCPerror].dport, external_port)
5845         except:
5846             self.logger.error(ppp("Unexpected or invalid packet:", p))
5847             raise
5848
5849         # from service back to client
5850         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
5851              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
5852              TCP(sport=local_port, dport=12345))
5853         self.pg0.add_stream(p)
5854         self.pg_enable_capture(self.pg_interfaces)
5855         self.pg_start()
5856         capture = self.pg1.get_capture(1)
5857         p = capture[0]
5858         try:
5859             ip = p[IP]
5860             tcp = p[TCP]
5861             self.assertEqual(ip.src, self.nat_addr)
5862             self.assertEqual(tcp.sport, external_port)
5863             self.assert_packet_checksums_valid(p)
5864         except:
5865             self.logger.error(ppp("Unexpected or invalid packet:", p))
5866             raise
5867
5868         # ICMP error
5869         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
5870              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
5871              ICMP(type=11) / capture[0][IP])
5872         self.pg1.add_stream(p)
5873         self.pg_enable_capture(self.pg_interfaces)
5874         self.pg_start()
5875         capture = self.pg0.get_capture(1)
5876         p = capture[0]
5877         try:
5878             self.assertEqual(p[IP].dst, self.pg0.remote_ip4)
5879             inner = p[IPerror]
5880             self.assertEqual(inner.src, self.pg0.remote_ip4)
5881             self.assertEqual(inner[TCPerror].sport, local_port)
5882         except:
5883             self.logger.error(ppp("Unexpected or invalid packet:", p))
5884             raise
5885
5886         # from client to server (no translation)
5887         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
5888              IP(src=self.pg1.remote_ip4, dst=self.pg0.remote_ip4) /
5889              TCP(sport=12346, dport=local_port))
5890         self.pg1.add_stream(p)
5891         self.pg_enable_capture(self.pg_interfaces)
5892         self.pg_start()
5893         capture = self.pg0.get_capture(1)
5894         p = capture[0]
5895         try:
5896             ip = p[IP]
5897             tcp = p[TCP]
5898             self.assertEqual(ip.dst, self.pg0.remote_ip4)
5899             self.assertEqual(tcp.dport, local_port)
5900             self.assert_packet_checksums_valid(p)
5901         except:
5902             self.logger.error(ppp("Unexpected or invalid packet:", p))
5903             raise
5904
5905         # from service back to client (no translation)
5906         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
5907              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
5908              TCP(sport=local_port, dport=12346))
5909         self.pg0.add_stream(p)
5910         self.pg_enable_capture(self.pg_interfaces)
5911         self.pg_start()
5912         capture = self.pg1.get_capture(1)
5913         p = capture[0]
5914         try:
5915             ip = p[IP]
5916             tcp = p[TCP]
5917             self.assertEqual(ip.src, self.pg0.remote_ip4)
5918             self.assertEqual(tcp.sport, local_port)
5919             self.assert_packet_checksums_valid(p)
5920         except:
5921             self.logger.error(ppp("Unexpected or invalid packet:", p))
5922             raise
5923
5924     def test_output_feature(self):
5925         """ NAT44 interface output feature (in2out postrouting) """
5926         self.vapi.nat44_forwarding_enable_disable(1)
5927         self.nat44_add_address(self.nat_addr)
5928         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index,
5929                                                   is_inside=0)
5930         self.vapi.nat44_interface_add_del_output_feature(self.pg1.sw_if_index,
5931                                                          is_inside=0)
5932
5933         # in2out
5934         pkts = self.create_stream_in(self.pg0, self.pg1)
5935         self.pg0.add_stream(pkts)
5936         self.pg_enable_capture(self.pg_interfaces)
5937         self.pg_start()
5938         capture = self.pg1.get_capture(len(pkts))
5939         self.verify_capture_out(capture)
5940
5941         # out2in
5942         pkts = self.create_stream_out(self.pg1)
5943         self.pg1.add_stream(pkts)
5944         self.pg_enable_capture(self.pg_interfaces)
5945         self.pg_start()
5946         capture = self.pg0.get_capture(len(pkts))
5947         self.verify_capture_in(capture, self.pg0)
5948
5949     def test_multiple_vrf(self):
5950         """ Multiple VRF setup """
5951         external_addr = '1.2.3.4'
5952         external_port = 80
5953         local_port = 8080
5954         port = 0
5955
5956         self.vapi.nat44_forwarding_enable_disable(1)
5957         self.nat44_add_address(self.nat_addr)
5958         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
5959         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index,
5960                                                   is_inside=0)
5961         self.vapi.nat44_interface_add_del_output_feature(self.pg1.sw_if_index,
5962                                                          is_inside=0)
5963         self.vapi.nat44_interface_add_del_feature(self.pg5.sw_if_index)
5964         self.vapi.nat44_interface_add_del_feature(self.pg5.sw_if_index,
5965                                                   is_inside=0)
5966         self.vapi.nat44_interface_add_del_feature(self.pg6.sw_if_index,
5967                                                   is_inside=0)
5968         self.nat44_add_static_mapping(self.pg5.remote_ip4, external_addr,
5969                                       local_port, external_port, vrf_id=1,
5970                                       proto=IP_PROTOS.tcp, out2in_only=1)
5971         self.nat44_add_static_mapping(
5972             self.pg0.remote_ip4, external_sw_if_index=self.pg0.sw_if_index,
5973             local_port=local_port, vrf_id=0, external_port=external_port,
5974             proto=IP_PROTOS.tcp, out2in_only=1)
5975
5976         # from client to service (both VRF1)
5977         p = (Ether(src=self.pg6.remote_mac, dst=self.pg6.local_mac) /
5978              IP(src=self.pg6.remote_ip4, dst=external_addr) /
5979              TCP(sport=12345, dport=external_port))
5980         self.pg6.add_stream(p)
5981         self.pg_enable_capture(self.pg_interfaces)
5982         self.pg_start()
5983         capture = self.pg5.get_capture(1)
5984         p = capture[0]
5985         try:
5986             ip = p[IP]
5987             tcp = p[TCP]
5988             self.assertEqual(ip.dst, self.pg5.remote_ip4)
5989             self.assertEqual(tcp.dport, local_port)
5990             self.assert_packet_checksums_valid(p)
5991         except:
5992             self.logger.error(ppp("Unexpected or invalid packet:", p))
5993             raise
5994
5995         # from service back to client (both VRF1)
5996         p = (Ether(src=self.pg5.remote_mac, dst=self.pg5.local_mac) /
5997              IP(src=self.pg5.remote_ip4, dst=self.pg6.remote_ip4) /
5998              TCP(sport=local_port, dport=12345))
5999         self.pg5.add_stream(p)
6000         self.pg_enable_capture(self.pg_interfaces)
6001         self.pg_start()
6002         capture = self.pg6.get_capture(1)
6003         p = capture[0]
6004         try:
6005             ip = p[IP]
6006             tcp = p[TCP]
6007             self.assertEqual(ip.src, external_addr)
6008             self.assertEqual(tcp.sport, external_port)
6009             self.assert_packet_checksums_valid(p)
6010         except:
6011             self.logger.error(ppp("Unexpected or invalid packet:", p))
6012             raise
6013
6014         # dynamic NAT from VRF1 to VRF0 (output-feature)
6015         p = (Ether(src=self.pg5.remote_mac, dst=self.pg5.local_mac) /
6016              IP(src=self.pg5.remote_ip4, dst=self.pg1.remote_ip4) /
6017              TCP(sport=2345, dport=22))
6018         self.pg5.add_stream(p)
6019         self.pg_enable_capture(self.pg_interfaces)
6020         self.pg_start()
6021         capture = self.pg1.get_capture(1)
6022         p = capture[0]
6023         try:
6024             ip = p[IP]
6025             tcp = p[TCP]
6026             self.assertEqual(ip.src, self.nat_addr)
6027             self.assertNotEqual(tcp.sport, 2345)
6028             self.assert_packet_checksums_valid(p)
6029             port = tcp.sport
6030         except:
6031             self.logger.error(ppp("Unexpected or invalid packet:", p))
6032             raise
6033
6034         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
6035              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
6036              TCP(sport=22, dport=port))
6037         self.pg1.add_stream(p)
6038         self.pg_enable_capture(self.pg_interfaces)
6039         self.pg_start()
6040         capture = self.pg5.get_capture(1)
6041         p = capture[0]
6042         try:
6043             ip = p[IP]
6044             tcp = p[TCP]
6045             self.assertEqual(ip.dst, self.pg5.remote_ip4)
6046             self.assertEqual(tcp.dport, 2345)
6047             self.assert_packet_checksums_valid(p)
6048         except:
6049             self.logger.error(ppp("Unexpected or invalid packet:", p))
6050             raise
6051
6052         # from client VRF1 to service VRF0
6053         p = (Ether(src=self.pg6.remote_mac, dst=self.pg6.local_mac) /
6054              IP(src=self.pg6.remote_ip4, dst=self.pg0.local_ip4) /
6055              TCP(sport=12346, dport=external_port))
6056         self.pg6.add_stream(p)
6057         self.pg_enable_capture(self.pg_interfaces)
6058         self.pg_start()
6059         capture = self.pg0.get_capture(1)
6060         p = capture[0]
6061         try:
6062             ip = p[IP]
6063             tcp = p[TCP]
6064             self.assertEqual(ip.dst, self.pg0.remote_ip4)
6065             self.assertEqual(tcp.dport, local_port)
6066             self.assert_packet_checksums_valid(p)
6067         except:
6068             self.logger.error(ppp("Unexpected or invalid packet:", p))
6069             raise
6070
6071         # from service VRF0 back to client VRF1
6072         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6073              IP(src=self.pg0.remote_ip4, dst=self.pg6.remote_ip4) /
6074              TCP(sport=local_port, dport=12346))
6075         self.pg0.add_stream(p)
6076         self.pg_enable_capture(self.pg_interfaces)
6077         self.pg_start()
6078         capture = self.pg6.get_capture(1)
6079         p = capture[0]
6080         try:
6081             ip = p[IP]
6082             tcp = p[TCP]
6083             self.assertEqual(ip.src, self.pg0.local_ip4)
6084             self.assertEqual(tcp.sport, external_port)
6085             self.assert_packet_checksums_valid(p)
6086         except:
6087             self.logger.error(ppp("Unexpected or invalid packet:", p))
6088             raise
6089
6090         # from client VRF0 to service VRF1
6091         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6092              IP(src=self.pg0.remote_ip4, dst=external_addr) /
6093              TCP(sport=12347, dport=external_port))
6094         self.pg0.add_stream(p)
6095         self.pg_enable_capture(self.pg_interfaces)
6096         self.pg_start()
6097         capture = self.pg5.get_capture(1)
6098         p = capture[0]
6099         try:
6100             ip = p[IP]
6101             tcp = p[TCP]
6102             self.assertEqual(ip.dst, self.pg5.remote_ip4)
6103             self.assertEqual(tcp.dport, local_port)
6104             self.assert_packet_checksums_valid(p)
6105         except:
6106             self.logger.error(ppp("Unexpected or invalid packet:", p))
6107             raise
6108
6109         # from service VRF1 back to client VRF0
6110         p = (Ether(src=self.pg5.remote_mac, dst=self.pg5.local_mac) /
6111              IP(src=self.pg5.remote_ip4, dst=self.pg0.remote_ip4) /
6112              TCP(sport=local_port, dport=12347))
6113         self.pg5.add_stream(p)
6114         self.pg_enable_capture(self.pg_interfaces)
6115         self.pg_start()
6116         capture = self.pg0.get_capture(1)
6117         p = capture[0]
6118         try:
6119             ip = p[IP]
6120             tcp = p[TCP]
6121             self.assertEqual(ip.src, external_addr)
6122             self.assertEqual(tcp.sport, external_port)
6123             self.assert_packet_checksums_valid(p)
6124         except:
6125             self.logger.error(ppp("Unexpected or invalid packet:", p))
6126             raise
6127
6128         # from client to server (both VRF1, no translation)
6129         p = (Ether(src=self.pg6.remote_mac, dst=self.pg6.local_mac) /
6130              IP(src=self.pg6.remote_ip4, dst=self.pg5.remote_ip4) /
6131              TCP(sport=12348, dport=local_port))
6132         self.pg6.add_stream(p)
6133         self.pg_enable_capture(self.pg_interfaces)
6134         self.pg_start()
6135         capture = self.pg5.get_capture(1)
6136         p = capture[0]
6137         try:
6138             ip = p[IP]
6139             tcp = p[TCP]
6140             self.assertEqual(ip.dst, self.pg5.remote_ip4)
6141             self.assertEqual(tcp.dport, local_port)
6142             self.assert_packet_checksums_valid(p)
6143         except:
6144             self.logger.error(ppp("Unexpected or invalid packet:", p))
6145             raise
6146
6147         # from server back to client (both VRF1, no translation)
6148         p = (Ether(src=self.pg5.remote_mac, dst=self.pg5.local_mac) /
6149              IP(src=self.pg5.remote_ip4, dst=self.pg6.remote_ip4) /
6150              TCP(sport=local_port, dport=12348))
6151         self.pg5.add_stream(p)
6152         self.pg_enable_capture(self.pg_interfaces)
6153         self.pg_start()
6154         capture = self.pg6.get_capture(1)
6155         p = capture[0]
6156         try:
6157             ip = p[IP]
6158             tcp = p[TCP]
6159             self.assertEqual(ip.src, self.pg5.remote_ip4)
6160             self.assertEqual(tcp.sport, local_port)
6161             self.assert_packet_checksums_valid(p)
6162         except:
6163             self.logger.error(ppp("Unexpected or invalid packet:", p))
6164             raise
6165
6166         # from client VRF1 to server VRF0 (no translation)
6167         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6168              IP(src=self.pg0.remote_ip4, dst=self.pg6.remote_ip4) /
6169              TCP(sport=local_port, dport=12349))
6170         self.pg0.add_stream(p)
6171         self.pg_enable_capture(self.pg_interfaces)
6172         self.pg_start()
6173         capture = self.pg6.get_capture(1)
6174         p = capture[0]
6175         try:
6176             ip = p[IP]
6177             tcp = p[TCP]
6178             self.assertEqual(ip.src, self.pg0.remote_ip4)
6179             self.assertEqual(tcp.sport, local_port)
6180             self.assert_packet_checksums_valid(p)
6181         except:
6182             self.logger.error(ppp("Unexpected or invalid packet:", p))
6183             raise
6184
6185         # from server VRF0 back to client VRF1 (no translation)
6186         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6187              IP(src=self.pg0.remote_ip4, dst=self.pg6.remote_ip4) /
6188              TCP(sport=local_port, dport=12349))
6189         self.pg0.add_stream(p)
6190         self.pg_enable_capture(self.pg_interfaces)
6191         self.pg_start()
6192         capture = self.pg6.get_capture(1)
6193         p = capture[0]
6194         try:
6195             ip = p[IP]
6196             tcp = p[TCP]
6197             self.assertEqual(ip.src, self.pg0.remote_ip4)
6198             self.assertEqual(tcp.sport, local_port)
6199             self.assert_packet_checksums_valid(p)
6200         except:
6201             self.logger.error(ppp("Unexpected or invalid packet:", p))
6202             raise
6203
6204         # from client VRF0 to server VRF1 (no translation)
6205         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6206              IP(src=self.pg0.remote_ip4, dst=self.pg5.remote_ip4) /
6207              TCP(sport=12344, dport=local_port))
6208         self.pg0.add_stream(p)
6209         self.pg_enable_capture(self.pg_interfaces)
6210         self.pg_start()
6211         capture = self.pg5.get_capture(1)
6212         p = capture[0]
6213         try:
6214             ip = p[IP]
6215             tcp = p[TCP]
6216             self.assertEqual(ip.dst, self.pg5.remote_ip4)
6217             self.assertEqual(tcp.dport, local_port)
6218             self.assert_packet_checksums_valid(p)
6219         except:
6220             self.logger.error(ppp("Unexpected or invalid packet:", p))
6221             raise
6222
6223         # from server VRF1 back to client VRF0 (no translation)
6224         p = (Ether(src=self.pg5.remote_mac, dst=self.pg5.local_mac) /
6225              IP(src=self.pg5.remote_ip4, dst=self.pg0.remote_ip4) /
6226              TCP(sport=local_port, dport=12344))
6227         self.pg5.add_stream(p)
6228         self.pg_enable_capture(self.pg_interfaces)
6229         self.pg_start()
6230         capture = self.pg0.get_capture(1)
6231         p = capture[0]
6232         try:
6233             ip = p[IP]
6234             tcp = p[TCP]
6235             self.assertEqual(ip.src, self.pg5.remote_ip4)
6236             self.assertEqual(tcp.sport, local_port)
6237             self.assert_packet_checksums_valid(p)
6238         except:
6239             self.logger.error(ppp("Unexpected or invalid packet:", p))
6240             raise
6241
6242     @unittest.skipUnless(running_extended_tests, "part of extended tests")
6243     def test_session_timeout(self):
6244         """ NAT44 session timeouts """
6245         self.nat44_add_address(self.nat_addr)
6246         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
6247         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
6248                                                   is_inside=0)
6249         self.vapi.nat_set_timeouts(icmp=5)
6250
6251         max_sessions = 1000
6252         pkts = []
6253         for i in range(0, max_sessions):
6254             src = "10.10.%u.%u" % ((i & 0xFF00) >> 8, i & 0xFF)
6255             p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
6256                  IP(src=src, dst=self.pg1.remote_ip4) /
6257                  ICMP(id=1025, type='echo-request'))
6258             pkts.append(p)
6259         self.pg0.add_stream(pkts)
6260         self.pg_enable_capture(self.pg_interfaces)
6261         self.pg_start()
6262         self.pg1.get_capture(max_sessions)
6263
6264         sleep(10)
6265
6266         pkts = []
6267         for i in range(0, max_sessions):
6268             src = "10.11.%u.%u" % ((i & 0xFF00) >> 8, i & 0xFF)
6269             p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
6270                  IP(src=src, dst=self.pg1.remote_ip4) /
6271                  ICMP(id=1026, type='echo-request'))
6272             pkts.append(p)
6273         self.pg0.add_stream(pkts)
6274         self.pg_enable_capture(self.pg_interfaces)
6275         self.pg_start()
6276         self.pg1.get_capture(max_sessions)
6277
6278         nsessions = 0
6279         users = self.vapi.nat44_user_dump()
6280         for user in users:
6281             nsessions = nsessions + user.nsessions
6282         self.assertLess(nsessions, 2 * max_sessions)
6283
6284     @unittest.skipUnless(running_extended_tests, "part of extended tests")
6285     def test_session_rst_timeout(self):
6286         """ NAT44 session RST timeouts """
6287         self.nat44_add_address(self.nat_addr)
6288         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
6289         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
6290                                                   is_inside=0)
6291         self.vapi.nat_set_timeouts(tcp_transitory=5)
6292
6293         self.initiate_tcp_session(self.pg0, self.pg1)
6294         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6295              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6296              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
6297                  flags="R"))
6298         self.pg0.add_stream(p)
6299         self.pg_enable_capture(self.pg_interfaces)
6300         self.pg_start()
6301         self.pg1.get_capture(1)
6302
6303         sleep(6)
6304
6305         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6306              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6307              TCP(sport=self.tcp_port_in + 1, dport=self.tcp_external_port + 1,
6308                  flags="S"))
6309         self.pg0.add_stream(p)
6310         self.pg_enable_capture(self.pg_interfaces)
6311         self.pg_start()
6312         self.pg1.get_capture(1)
6313
6314         nsessions = 0
6315         users = self.vapi.nat44_user_dump()
6316         self.assertEqual(len(users), 1)
6317         self.assertEqual(users[0].ip_address, self.pg0.remote_ip4n)
6318         self.assertEqual(users[0].nsessions, 1)
6319
6320     @unittest.skipUnless(running_extended_tests, "part of extended tests")
6321     def test_session_limit_per_user(self):
6322         """ Maximum sessions per user limit """
6323         self.nat44_add_address(self.nat_addr)
6324         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
6325         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
6326                                                   is_inside=0)
6327         self.vapi.set_ipfix_exporter(collector_address=self.pg2.remote_ip4n,
6328                                      src_address=self.pg2.local_ip4n,
6329                                      path_mtu=512,
6330                                      template_interval=10)
6331         self.vapi.nat_set_timeouts(udp=5)
6332
6333         # get maximum number of translations per user
6334         nat44_config = self.vapi.nat_show_config()
6335
6336         pkts = []
6337         for port in range(0, nat44_config.max_translations_per_user):
6338             p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6339                  IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6340                  UDP(sport=1025 + port, dport=1025 + port))
6341             pkts.append(p)
6342
6343         self.pg0.add_stream(pkts)
6344         self.pg_enable_capture(self.pg_interfaces)
6345         self.pg_start()
6346         capture = self.pg1.get_capture(len(pkts))
6347
6348         self.vapi.nat_ipfix_enable_disable(domain_id=self.ipfix_domain_id,
6349                                            src_port=self.ipfix_src_port)
6350
6351         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6352              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6353              UDP(sport=3001, dport=3002))
6354         self.pg0.add_stream(p)
6355         self.pg_enable_capture(self.pg_interfaces)
6356         self.pg_start()
6357         capture = self.pg1.assert_nothing_captured()
6358
6359         # verify IPFIX logging
6360         self.vapi.cli("ipfix flush")  # FIXME this should be an API call
6361         sleep(1)
6362         capture = self.pg2.get_capture(10)
6363         ipfix = IPFIXDecoder()
6364         # first load template
6365         for p in capture:
6366             self.assertTrue(p.haslayer(IPFIX))
6367             if p.haslayer(Template):
6368                 ipfix.add_template(p.getlayer(Template))
6369         # verify events in data set
6370         for p in capture:
6371             if p.haslayer(Data):
6372                 data = ipfix.decode_data_set(p.getlayer(Set))
6373                 self.verify_ipfix_max_entries_per_user(
6374                     data,
6375                     nat44_config.max_translations_per_user,
6376                     self.pg0.remote_ip4n)
6377
6378         sleep(6)
6379         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6380              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6381              UDP(sport=3001, dport=3002))
6382         self.pg0.add_stream(p)
6383         self.pg_enable_capture(self.pg_interfaces)
6384         self.pg_start()
6385         self.pg1.get_capture(1)
6386
6387     def test_syslog_sess(self):
6388         """ Test syslog session creation and deletion """
6389         self.vapi.syslog_set_filter(SYSLOG_SEVERITY.INFO)
6390         self.vapi.syslog_set_sender(self.pg2.local_ip4n, self.pg2.remote_ip4n)
6391         self.nat44_add_address(self.nat_addr)
6392         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
6393         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
6394                                                   is_inside=0)
6395
6396         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
6397              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6398              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port))
6399         self.pg0.add_stream(p)
6400         self.pg_enable_capture(self.pg_interfaces)
6401         self.pg_start()
6402         capture = self.pg1.get_capture(1)
6403         self.tcp_port_out = capture[0][TCP].sport
6404         capture = self.pg2.get_capture(1)
6405         self.verify_syslog_sess(capture[0][Raw].load)
6406
6407         self.pg_enable_capture(self.pg_interfaces)
6408         self.pg_start()
6409         self.nat44_add_address(self.nat_addr, is_add=0)
6410         capture = self.pg2.get_capture(1)
6411         self.verify_syslog_sess(capture[0][Raw].load, False)
6412
6413     def tearDown(self):
6414         super(TestNAT44EndpointDependent, self).tearDown()
6415         if not self.vpp_dead:
6416             self.logger.info(self.vapi.cli("show nat44 addresses"))
6417             self.logger.info(self.vapi.cli("show nat44 interfaces"))
6418             self.logger.info(self.vapi.cli("show nat44 static mappings"))
6419             self.logger.info(self.vapi.cli("show nat44 interface address"))
6420             self.logger.info(self.vapi.cli("show nat44 sessions detail"))
6421             self.logger.info(self.vapi.cli("show nat44 hash tables detail"))
6422             self.logger.info(self.vapi.cli("show nat timeouts"))
6423             self.clear_nat44()
6424             self.vapi.cli("clear logging")
6425
6426
6427 class TestNAT44Out2InDPO(MethodHolder):
6428     """ NAT44 Test Cases using out2in DPO """
6429
6430     @classmethod
6431     def setUpConstants(cls):
6432         super(TestNAT44Out2InDPO, cls).setUpConstants()
6433         cls.vpp_cmdline.extend(["nat", "{", "out2in dpo", "}"])
6434
6435     @classmethod
6436     def setUpClass(cls):
6437         super(TestNAT44Out2InDPO, cls).setUpClass()
6438         cls.vapi.cli("set log class nat level debug")
6439
6440         try:
6441             cls.tcp_port_in = 6303
6442             cls.tcp_port_out = 6303
6443             cls.udp_port_in = 6304
6444             cls.udp_port_out = 6304
6445             cls.icmp_id_in = 6305
6446             cls.icmp_id_out = 6305
6447             cls.nat_addr = '10.0.0.3'
6448             cls.nat_addr_n = socket.inet_pton(socket.AF_INET, cls.nat_addr)
6449             cls.dst_ip4 = '192.168.70.1'
6450
6451             cls.create_pg_interfaces(range(2))
6452
6453             cls.pg0.admin_up()
6454             cls.pg0.config_ip4()
6455             cls.pg0.resolve_arp()
6456
6457             cls.pg1.admin_up()
6458             cls.pg1.config_ip6()
6459             cls.pg1.resolve_ndp()
6460
6461             cls.vapi.ip_add_del_route(is_ipv6=True, dst_address='\x00' * 16,
6462                                       dst_address_length=0,
6463                                       next_hop_address=cls.pg1.remote_ip6n,
6464                                       next_hop_sw_if_index=cls.pg1.sw_if_index)
6465
6466         except Exception:
6467             super(TestNAT44Out2InDPO, cls).tearDownClass()
6468             raise
6469
6470     def configure_xlat(self):
6471         self.dst_ip6_pfx = '1:2:3::'
6472         self.dst_ip6_pfx_n = socket.inet_pton(socket.AF_INET6,
6473                                               self.dst_ip6_pfx)
6474         self.dst_ip6_pfx_len = 96
6475         self.src_ip6_pfx = '4:5:6::'
6476         self.src_ip6_pfx_n = socket.inet_pton(socket.AF_INET6,
6477                                               self.src_ip6_pfx)
6478         self.src_ip6_pfx_len = 96
6479         self.vapi.map_add_domain(self.dst_ip6_pfx_n, self.dst_ip6_pfx_len,
6480                                  self.src_ip6_pfx_n, self.src_ip6_pfx_len,
6481                                  '\x00\x00\x00\x00', 0)
6482
6483     @unittest.skip('Temporary disabled')
6484     def test_464xlat_ce(self):
6485         """ Test 464XLAT CE with NAT44 """
6486
6487         nat_config = self.vapi.nat_show_config()
6488         self.assertEqual(1, nat_config.out2in_dpo)
6489
6490         self.configure_xlat()
6491
6492         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
6493         self.vapi.nat44_add_del_address_range(self.nat_addr_n, self.nat_addr_n)
6494
6495         out_src_ip6 = self.compose_ip6(self.dst_ip4, self.dst_ip6_pfx,
6496                                        self.dst_ip6_pfx_len)
6497         out_dst_ip6 = self.compose_ip6(self.nat_addr, self.src_ip6_pfx,
6498                                        self.src_ip6_pfx_len)
6499
6500         try:
6501             pkts = self.create_stream_in(self.pg0, self.pg1, self.dst_ip4)
6502             self.pg0.add_stream(pkts)
6503             self.pg_enable_capture(self.pg_interfaces)
6504             self.pg_start()
6505             capture = self.pg1.get_capture(len(pkts))
6506             self.verify_capture_out_ip6(capture, nat_ip=out_dst_ip6,
6507                                         dst_ip=out_src_ip6)
6508
6509             pkts = self.create_stream_out_ip6(self.pg1, out_src_ip6,
6510                                               out_dst_ip6)
6511             self.pg1.add_stream(pkts)
6512             self.pg_enable_capture(self.pg_interfaces)
6513             self.pg_start()
6514             capture = self.pg0.get_capture(len(pkts))
6515             self.verify_capture_in(capture, self.pg0)
6516         finally:
6517             self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index,
6518                                                       is_add=0)
6519             self.vapi.nat44_add_del_address_range(self.nat_addr_n,
6520                                                   self.nat_addr_n, is_add=0)
6521
6522     @unittest.skip('Temporary disabled')
6523     def test_464xlat_ce_no_nat(self):
6524         """ Test 464XLAT CE without NAT44 """
6525
6526         self.configure_xlat()
6527
6528         out_src_ip6 = self.compose_ip6(self.dst_ip4, self.dst_ip6_pfx,
6529                                        self.dst_ip6_pfx_len)
6530         out_dst_ip6 = self.compose_ip6(self.pg0.remote_ip4, self.src_ip6_pfx,
6531                                        self.src_ip6_pfx_len)
6532
6533         pkts = self.create_stream_in(self.pg0, self.pg1, self.dst_ip4)
6534         self.pg0.add_stream(pkts)
6535         self.pg_enable_capture(self.pg_interfaces)
6536         self.pg_start()
6537         capture = self.pg1.get_capture(len(pkts))
6538         self.verify_capture_out_ip6(capture, dst_ip=out_src_ip6,
6539                                     nat_ip=out_dst_ip6, same_port=True)
6540
6541         pkts = self.create_stream_out_ip6(self.pg1, out_src_ip6, out_dst_ip6)
6542         self.pg1.add_stream(pkts)
6543         self.pg_enable_capture(self.pg_interfaces)
6544         self.pg_start()
6545         capture = self.pg0.get_capture(len(pkts))
6546         self.verify_capture_in(capture, self.pg0)
6547
6548
6549 class TestDeterministicNAT(MethodHolder):
6550     """ Deterministic NAT Test Cases """
6551
6552     @classmethod
6553     def setUpConstants(cls):
6554         super(TestDeterministicNAT, cls).setUpConstants()
6555         cls.vpp_cmdline.extend(["nat", "{", "deterministic", "}"])
6556
6557     @classmethod
6558     def setUpClass(cls):
6559         super(TestDeterministicNAT, cls).setUpClass()
6560         cls.vapi.cli("set log class nat level debug")
6561
6562         try:
6563             cls.tcp_port_in = 6303
6564             cls.tcp_external_port = 6303
6565             cls.udp_port_in = 6304
6566             cls.udp_external_port = 6304
6567             cls.icmp_id_in = 6305
6568             cls.nat_addr = '10.0.0.3'
6569
6570             cls.create_pg_interfaces(range(3))
6571             cls.interfaces = list(cls.pg_interfaces)
6572
6573             for i in cls.interfaces:
6574                 i.admin_up()
6575                 i.config_ip4()
6576                 i.resolve_arp()
6577
6578             cls.pg0.generate_remote_hosts(2)
6579             cls.pg0.configure_ipv4_neighbors()
6580
6581         except Exception:
6582             super(TestDeterministicNAT, cls).tearDownClass()
6583             raise
6584
6585     def create_stream_in(self, in_if, out_if, ttl=64):
6586         """
6587         Create packet stream for inside network
6588
6589         :param in_if: Inside interface
6590         :param out_if: Outside interface
6591         :param ttl: TTL of generated packets
6592         """
6593         pkts = []
6594         # TCP
6595         p = (Ether(dst=in_if.local_mac, src=in_if.remote_mac) /
6596              IP(src=in_if.remote_ip4, dst=out_if.remote_ip4, ttl=ttl) /
6597              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port))
6598         pkts.append(p)
6599
6600         # UDP
6601         p = (Ether(dst=in_if.local_mac, src=in_if.remote_mac) /
6602              IP(src=in_if.remote_ip4, dst=out_if.remote_ip4, ttl=ttl) /
6603              UDP(sport=self.udp_port_in, dport=self.udp_external_port))
6604         pkts.append(p)
6605
6606         # ICMP
6607         p = (Ether(dst=in_if.local_mac, src=in_if.remote_mac) /
6608              IP(src=in_if.remote_ip4, dst=out_if.remote_ip4, ttl=ttl) /
6609              ICMP(id=self.icmp_id_in, type='echo-request'))
6610         pkts.append(p)
6611
6612         return pkts
6613
6614     def create_stream_out(self, out_if, dst_ip=None, ttl=64):
6615         """
6616         Create packet stream for outside network
6617
6618         :param out_if: Outside interface
6619         :param dst_ip: Destination IP address (Default use global NAT address)
6620         :param ttl: TTL of generated packets
6621         """
6622         if dst_ip is None:
6623             dst_ip = self.nat_addr
6624         pkts = []
6625         # TCP
6626         p = (Ether(dst=out_if.local_mac, src=out_if.remote_mac) /
6627              IP(src=out_if.remote_ip4, dst=dst_ip, ttl=ttl) /
6628              TCP(dport=self.tcp_port_out, sport=self.tcp_external_port))
6629         pkts.append(p)
6630
6631         # UDP
6632         p = (Ether(dst=out_if.local_mac, src=out_if.remote_mac) /
6633              IP(src=out_if.remote_ip4, dst=dst_ip, ttl=ttl) /
6634              UDP(dport=self.udp_port_out, sport=self.udp_external_port))
6635         pkts.append(p)
6636
6637         # ICMP
6638         p = (Ether(dst=out_if.local_mac, src=out_if.remote_mac) /
6639              IP(src=out_if.remote_ip4, dst=dst_ip, ttl=ttl) /
6640              ICMP(id=self.icmp_external_id, type='echo-reply'))
6641         pkts.append(p)
6642
6643         return pkts
6644
6645     def verify_capture_out(self, capture, nat_ip=None):
6646         """
6647         Verify captured packets on outside network
6648
6649         :param capture: Captured packets
6650         :param nat_ip: Translated IP address (Default use global NAT address)
6651         :param same_port: Sorce port number is not translated (Default False)
6652         """
6653         if nat_ip is None:
6654             nat_ip = self.nat_addr
6655         for packet in capture:
6656             try:
6657                 self.assertEqual(packet[IP].src, nat_ip)
6658                 if packet.haslayer(TCP):
6659                     self.tcp_port_out = packet[TCP].sport
6660                 elif packet.haslayer(UDP):
6661                     self.udp_port_out = packet[UDP].sport
6662                 else:
6663                     self.icmp_external_id = packet[ICMP].id
6664             except:
6665                 self.logger.error(ppp("Unexpected or invalid packet "
6666                                       "(outside network):", packet))
6667                 raise
6668
6669     def test_deterministic_mode(self):
6670         """ NAT plugin run deterministic mode """
6671         in_addr = '172.16.255.0'
6672         out_addr = '172.17.255.50'
6673         in_addr_t = '172.16.255.20'
6674         in_addr_n = socket.inet_aton(in_addr)
6675         out_addr_n = socket.inet_aton(out_addr)
6676         in_addr_t_n = socket.inet_aton(in_addr_t)
6677         in_plen = 24
6678         out_plen = 32
6679
6680         nat_config = self.vapi.nat_show_config()
6681         self.assertEqual(1, nat_config.deterministic)
6682
6683         self.vapi.nat_det_add_del_map(in_addr_n, in_plen, out_addr_n, out_plen)
6684
6685         rep1 = self.vapi.nat_det_forward(in_addr_t_n)
6686         self.assertEqual(rep1.out_addr[:4], out_addr_n)
6687         rep2 = self.vapi.nat_det_reverse(out_addr_n, rep1.out_port_hi)
6688         self.assertEqual(rep2.in_addr[:4], in_addr_t_n)
6689
6690         deterministic_mappings = self.vapi.nat_det_map_dump()
6691         self.assertEqual(len(deterministic_mappings), 1)
6692         dsm = deterministic_mappings[0]
6693         self.assertEqual(in_addr_n, dsm.in_addr[:4])
6694         self.assertEqual(in_plen, dsm.in_plen)
6695         self.assertEqual(out_addr_n, dsm.out_addr[:4])
6696         self.assertEqual(out_plen, dsm.out_plen)
6697
6698         self.clear_nat_det()
6699         deterministic_mappings = self.vapi.nat_det_map_dump()
6700         self.assertEqual(len(deterministic_mappings), 0)
6701
6702     def test_set_timeouts(self):
6703         """ Set deterministic NAT timeouts """
6704         timeouts_before = self.vapi.nat_get_timeouts()
6705
6706         self.vapi.nat_set_timeouts(timeouts_before.udp + 10,
6707                                    timeouts_before.tcp_established + 10,
6708                                    timeouts_before.tcp_transitory + 10,
6709                                    timeouts_before.icmp + 10)
6710
6711         timeouts_after = self.vapi.nat_get_timeouts()
6712
6713         self.assertNotEqual(timeouts_before.udp, timeouts_after.udp)
6714         self.assertNotEqual(timeouts_before.icmp, timeouts_after.icmp)
6715         self.assertNotEqual(timeouts_before.tcp_established,
6716                             timeouts_after.tcp_established)
6717         self.assertNotEqual(timeouts_before.tcp_transitory,
6718                             timeouts_after.tcp_transitory)
6719
6720     def test_det_in(self):
6721         """ Deterministic NAT translation test (TCP, UDP, ICMP) """
6722
6723         nat_ip = "10.0.0.10"
6724
6725         self.vapi.nat_det_add_del_map(self.pg0.remote_ip4n,
6726                                       32,
6727                                       socket.inet_aton(nat_ip),
6728                                       32)
6729         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
6730         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
6731                                                   is_inside=0)
6732
6733         # in2out
6734         pkts = self.create_stream_in(self.pg0, self.pg1)
6735         self.pg0.add_stream(pkts)
6736         self.pg_enable_capture(self.pg_interfaces)
6737         self.pg_start()
6738         capture = self.pg1.get_capture(len(pkts))
6739         self.verify_capture_out(capture, nat_ip)
6740
6741         # out2in
6742         pkts = self.create_stream_out(self.pg1, nat_ip)
6743         self.pg1.add_stream(pkts)
6744         self.pg_enable_capture(self.pg_interfaces)
6745         self.pg_start()
6746         capture = self.pg0.get_capture(len(pkts))
6747         self.verify_capture_in(capture, self.pg0)
6748
6749         # session dump test
6750         sessions = self.vapi.nat_det_session_dump(self.pg0.remote_ip4n)
6751         self.assertEqual(len(sessions), 3)
6752
6753         # TCP session
6754         s = sessions[0]
6755         self.assertEqual(s.ext_addr[:4], self.pg1.remote_ip4n)
6756         self.assertEqual(s.in_port, self.tcp_port_in)
6757         self.assertEqual(s.out_port, self.tcp_port_out)
6758         self.assertEqual(s.ext_port, self.tcp_external_port)
6759
6760         # UDP session
6761         s = sessions[1]
6762         self.assertEqual(s.ext_addr[:4], self.pg1.remote_ip4n)
6763         self.assertEqual(s.in_port, self.udp_port_in)
6764         self.assertEqual(s.out_port, self.udp_port_out)
6765         self.assertEqual(s.ext_port, self.udp_external_port)
6766
6767         # ICMP session
6768         s = sessions[2]
6769         self.assertEqual(s.ext_addr[:4], self.pg1.remote_ip4n)
6770         self.assertEqual(s.in_port, self.icmp_id_in)
6771         self.assertEqual(s.out_port, self.icmp_external_id)
6772
6773     def test_multiple_users(self):
6774         """ Deterministic NAT multiple users """
6775
6776         nat_ip = "10.0.0.10"
6777         port_in = 80
6778         external_port = 6303
6779
6780         host0 = self.pg0.remote_hosts[0]
6781         host1 = self.pg0.remote_hosts[1]
6782
6783         self.vapi.nat_det_add_del_map(host0.ip4n,
6784                                       24,
6785                                       socket.inet_aton(nat_ip),
6786                                       32)
6787         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
6788         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
6789                                                   is_inside=0)
6790
6791         # host0 to out
6792         p = (Ether(src=host0.mac, dst=self.pg0.local_mac) /
6793              IP(src=host0.ip4, dst=self.pg1.remote_ip4) /
6794              TCP(sport=port_in, dport=external_port))
6795         self.pg0.add_stream(p)
6796         self.pg_enable_capture(self.pg_interfaces)
6797         self.pg_start()
6798         capture = self.pg1.get_capture(1)
6799         p = capture[0]
6800         try:
6801             ip = p[IP]
6802             tcp = p[TCP]
6803             self.assertEqual(ip.src, nat_ip)
6804             self.assertEqual(ip.dst, self.pg1.remote_ip4)
6805             self.assertEqual(tcp.dport, external_port)
6806             port_out0 = tcp.sport
6807         except:
6808             self.logger.error(ppp("Unexpected or invalid packet:", p))
6809             raise
6810
6811         # host1 to out
6812         p = (Ether(src=host1.mac, dst=self.pg0.local_mac) /
6813              IP(src=host1.ip4, dst=self.pg1.remote_ip4) /
6814              TCP(sport=port_in, dport=external_port))
6815         self.pg0.add_stream(p)
6816         self.pg_enable_capture(self.pg_interfaces)
6817         self.pg_start()
6818         capture = self.pg1.get_capture(1)
6819         p = capture[0]
6820         try:
6821             ip = p[IP]
6822             tcp = p[TCP]
6823             self.assertEqual(ip.src, nat_ip)
6824             self.assertEqual(ip.dst, self.pg1.remote_ip4)
6825             self.assertEqual(tcp.dport, external_port)
6826             port_out1 = tcp.sport
6827         except:
6828             self.logger.error(ppp("Unexpected or invalid packet:", p))
6829             raise
6830
6831         dms = self.vapi.nat_det_map_dump()
6832         self.assertEqual(1, len(dms))
6833         self.assertEqual(2, dms[0].ses_num)
6834
6835         # out to host0
6836         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
6837              IP(src=self.pg1.remote_ip4, dst=nat_ip) /
6838              TCP(sport=external_port, dport=port_out0))
6839         self.pg1.add_stream(p)
6840         self.pg_enable_capture(self.pg_interfaces)
6841         self.pg_start()
6842         capture = self.pg0.get_capture(1)
6843         p = capture[0]
6844         try:
6845             ip = p[IP]
6846             tcp = p[TCP]
6847             self.assertEqual(ip.src, self.pg1.remote_ip4)
6848             self.assertEqual(ip.dst, host0.ip4)
6849             self.assertEqual(tcp.dport, port_in)
6850             self.assertEqual(tcp.sport, external_port)
6851         except:
6852             self.logger.error(ppp("Unexpected or invalid packet:", p))
6853             raise
6854
6855         # out to host1
6856         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
6857              IP(src=self.pg1.remote_ip4, dst=nat_ip) /
6858              TCP(sport=external_port, dport=port_out1))
6859         self.pg1.add_stream(p)
6860         self.pg_enable_capture(self.pg_interfaces)
6861         self.pg_start()
6862         capture = self.pg0.get_capture(1)
6863         p = capture[0]
6864         try:
6865             ip = p[IP]
6866             tcp = p[TCP]
6867             self.assertEqual(ip.src, self.pg1.remote_ip4)
6868             self.assertEqual(ip.dst, host1.ip4)
6869             self.assertEqual(tcp.dport, port_in)
6870             self.assertEqual(tcp.sport, external_port)
6871         except:
6872             self.logger.error(ppp("Unexpected or invalid packet", p))
6873             raise
6874
6875         # session close api test
6876         self.vapi.nat_det_close_session_out(socket.inet_aton(nat_ip),
6877                                             port_out1,
6878                                             self.pg1.remote_ip4n,
6879                                             external_port)
6880         dms = self.vapi.nat_det_map_dump()
6881         self.assertEqual(dms[0].ses_num, 1)
6882
6883         self.vapi.nat_det_close_session_in(host0.ip4n,
6884                                            port_in,
6885                                            self.pg1.remote_ip4n,
6886                                            external_port)
6887         dms = self.vapi.nat_det_map_dump()
6888         self.assertEqual(dms[0].ses_num, 0)
6889
6890     def test_tcp_session_close_detection_in(self):
6891         """ Deterministic NAT TCP session close from inside network """
6892         self.vapi.nat_det_add_del_map(self.pg0.remote_ip4n,
6893                                       32,
6894                                       socket.inet_aton(self.nat_addr),
6895                                       32)
6896         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
6897         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
6898                                                   is_inside=0)
6899
6900         self.initiate_tcp_session(self.pg0, self.pg1)
6901
6902         # close the session from inside
6903         try:
6904             # FIN packet in -> out
6905             p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6906                  IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6907                  TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
6908                      flags="F"))
6909             self.pg0.add_stream(p)
6910             self.pg_enable_capture(self.pg_interfaces)
6911             self.pg_start()
6912             self.pg1.get_capture(1)
6913
6914             pkts = []
6915
6916             # ACK packet out -> in
6917             p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
6918                  IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
6919                  TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
6920                      flags="A"))
6921             pkts.append(p)
6922
6923             # FIN packet out -> in
6924             p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
6925                  IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
6926                  TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
6927                      flags="F"))
6928             pkts.append(p)
6929
6930             self.pg1.add_stream(pkts)
6931             self.pg_enable_capture(self.pg_interfaces)
6932             self.pg_start()
6933             self.pg0.get_capture(2)
6934
6935             # ACK packet in -> out
6936             p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6937                  IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6938                  TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
6939                      flags="A"))
6940             self.pg0.add_stream(p)
6941             self.pg_enable_capture(self.pg_interfaces)
6942             self.pg_start()
6943             self.pg1.get_capture(1)
6944
6945             # Check if deterministic NAT44 closed the session
6946             dms = self.vapi.nat_det_map_dump()
6947             self.assertEqual(0, dms[0].ses_num)
6948         except:
6949             self.logger.error("TCP session termination failed")
6950             raise
6951
6952     def test_tcp_session_close_detection_out(self):
6953         """ Deterministic NAT TCP session close from outside network """
6954         self.vapi.nat_det_add_del_map(self.pg0.remote_ip4n,
6955                                       32,
6956                                       socket.inet_aton(self.nat_addr),
6957                                       32)
6958         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
6959         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
6960                                                   is_inside=0)
6961
6962         self.initiate_tcp_session(self.pg0, self.pg1)
6963
6964         # close the session from outside
6965         try:
6966             # FIN packet out -> in
6967             p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
6968                  IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
6969                  TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
6970                      flags="F"))
6971             self.pg1.add_stream(p)
6972             self.pg_enable_capture(self.pg_interfaces)
6973             self.pg_start()
6974             self.pg0.get_capture(1)
6975
6976             pkts = []
6977
6978             # ACK packet in -> out
6979             p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6980                  IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6981                  TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
6982                      flags="A"))
6983             pkts.append(p)
6984
6985             # ACK packet in -> out
6986             p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
6987                  IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
6988                  TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
6989                      flags="F"))
6990             pkts.append(p)
6991
6992             self.pg0.add_stream(pkts)
6993             self.pg_enable_capture(self.pg_interfaces)
6994             self.pg_start()
6995             self.pg1.get_capture(2)
6996
6997             # ACK packet out -> in
6998             p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
6999                  IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
7000                  TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
7001                      flags="A"))
7002             self.pg1.add_stream(p)
7003             self.pg_enable_capture(self.pg_interfaces)
7004             self.pg_start()
7005             self.pg0.get_capture(1)
7006
7007             # Check if deterministic NAT44 closed the session
7008             dms = self.vapi.nat_det_map_dump()
7009             self.assertEqual(0, dms[0].ses_num)
7010         except:
7011             self.logger.error("TCP session termination failed")
7012             raise
7013
7014     @unittest.skipUnless(running_extended_tests, "part of extended tests")
7015     def test_session_timeout(self):
7016         """ Deterministic NAT session timeouts """
7017         self.vapi.nat_det_add_del_map(self.pg0.remote_ip4n,
7018                                       32,
7019                                       socket.inet_aton(self.nat_addr),
7020                                       32)
7021         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
7022         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
7023                                                   is_inside=0)
7024
7025         self.initiate_tcp_session(self.pg0, self.pg1)
7026         self.vapi.nat_set_timeouts(5, 5, 5, 5)
7027         pkts = self.create_stream_in(self.pg0, self.pg1)
7028         self.pg0.add_stream(pkts)
7029         self.pg_enable_capture(self.pg_interfaces)
7030         self.pg_start()
7031         capture = self.pg1.get_capture(len(pkts))
7032         sleep(15)
7033
7034         dms = self.vapi.nat_det_map_dump()
7035         self.assertEqual(0, dms[0].ses_num)
7036
7037     @unittest.skipUnless(running_extended_tests, "part of extended tests")
7038     def test_session_limit_per_user(self):
7039         """ Deterministic NAT maximum sessions per user limit """
7040         self.vapi.nat_det_add_del_map(self.pg0.remote_ip4n,
7041                                       32,
7042                                       socket.inet_aton(self.nat_addr),
7043                                       32)
7044         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
7045         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
7046                                                   is_inside=0)
7047         self.vapi.set_ipfix_exporter(collector_address=self.pg2.remote_ip4n,
7048                                      src_address=self.pg2.local_ip4n,
7049                                      path_mtu=512,
7050                                      template_interval=10)
7051         self.vapi.nat_ipfix_enable_disable()
7052
7053         pkts = []
7054         for port in range(1025, 2025):
7055             p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
7056                  IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
7057                  UDP(sport=port, dport=port))
7058             pkts.append(p)
7059
7060         self.pg0.add_stream(pkts)
7061         self.pg_enable_capture(self.pg_interfaces)
7062         self.pg_start()
7063         capture = self.pg1.get_capture(len(pkts))
7064
7065         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
7066              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
7067              UDP(sport=3001, dport=3002))
7068         self.pg0.add_stream(p)
7069         self.pg_enable_capture(self.pg_interfaces)
7070         self.pg_start()
7071         capture = self.pg1.assert_nothing_captured()
7072
7073         # verify ICMP error packet
7074         capture = self.pg0.get_capture(1)
7075         p = capture[0]
7076         self.assertTrue(p.haslayer(ICMP))
7077         icmp = p[ICMP]
7078         self.assertEqual(icmp.type, 3)
7079         self.assertEqual(icmp.code, 1)
7080         self.assertTrue(icmp.haslayer(IPerror))
7081         inner_ip = icmp[IPerror]
7082         self.assertEqual(inner_ip[UDPerror].sport, 3001)
7083         self.assertEqual(inner_ip[UDPerror].dport, 3002)
7084
7085         dms = self.vapi.nat_det_map_dump()
7086
7087         self.assertEqual(1000, dms[0].ses_num)
7088
7089         # verify IPFIX logging
7090         self.vapi.cli("ipfix flush")  # FIXME this should be an API call
7091         sleep(1)
7092         capture = self.pg2.get_capture(2)
7093         ipfix = IPFIXDecoder()
7094         # first load template
7095         for p in capture:
7096             self.assertTrue(p.haslayer(IPFIX))
7097             if p.haslayer(Template):
7098                 ipfix.add_template(p.getlayer(Template))
7099         # verify events in data set
7100         for p in capture:
7101             if p.haslayer(Data):
7102                 data = ipfix.decode_data_set(p.getlayer(Set))
7103                 self.verify_ipfix_max_entries_per_user(data,
7104                                                        1000,
7105                                                        self.pg0.remote_ip4n)
7106
7107     def clear_nat_det(self):
7108         """
7109         Clear deterministic NAT configuration.
7110         """
7111         self.vapi.nat_ipfix_enable_disable(enable=0)
7112         self.vapi.nat_set_timeouts()
7113         deterministic_mappings = self.vapi.nat_det_map_dump()
7114         for dsm in deterministic_mappings:
7115             self.vapi.nat_det_add_del_map(dsm.in_addr,
7116                                           dsm.in_plen,
7117                                           dsm.out_addr,
7118                                           dsm.out_plen,
7119                                           is_add=0)
7120
7121         interfaces = self.vapi.nat44_interface_dump()
7122         for intf in interfaces:
7123             self.vapi.nat44_interface_add_del_feature(intf.sw_if_index,
7124                                                       intf.is_inside,
7125                                                       is_add=0)
7126
7127     def tearDown(self):
7128         super(TestDeterministicNAT, self).tearDown()
7129         if not self.vpp_dead:
7130             self.logger.info(self.vapi.cli("show nat44 interfaces"))
7131             self.logger.info(self.vapi.cli("show nat timeouts"))
7132             self.logger.info(
7133                 self.vapi.cli("show nat44 deterministic mappings"))
7134             self.logger.info(
7135                 self.vapi.cli("show nat44 deterministic sessions"))
7136             self.clear_nat_det()
7137
7138
7139 class TestNAT64(MethodHolder):
7140     """ NAT64 Test Cases """
7141
7142     @classmethod
7143     def setUpConstants(cls):
7144         super(TestNAT64, cls).setUpConstants()
7145         cls.vpp_cmdline.extend(["nat", "{", "nat64 bib hash buckets 128",
7146                                 "nat64 st hash buckets 256", "}"])
7147
7148     @classmethod
7149     def setUpClass(cls):
7150         super(TestNAT64, cls).setUpClass()
7151
7152         try:
7153             cls.tcp_port_in = 6303
7154             cls.tcp_port_out = 6303
7155             cls.udp_port_in = 6304
7156             cls.udp_port_out = 6304
7157             cls.icmp_id_in = 6305
7158             cls.icmp_id_out = 6305
7159             cls.tcp_external_port = 80
7160             cls.nat_addr = '10.0.0.3'
7161             cls.nat_addr_n = socket.inet_pton(socket.AF_INET, cls.nat_addr)
7162             cls.vrf1_id = 10
7163             cls.vrf1_nat_addr = '10.0.10.3'
7164             cls.vrf1_nat_addr_n = socket.inet_pton(socket.AF_INET,
7165                                                    cls.vrf1_nat_addr)
7166             cls.ipfix_src_port = 4739
7167             cls.ipfix_domain_id = 1
7168
7169             cls.create_pg_interfaces(range(6))
7170             cls.ip6_interfaces = list(cls.pg_interfaces[0:1])
7171             cls.ip6_interfaces.append(cls.pg_interfaces[2])
7172             cls.ip4_interfaces = list(cls.pg_interfaces[1:2])
7173
7174             cls.vapi.ip_table_add_del(is_ipv6=1, is_add=1,
7175                                       table_id=cls.vrf1_id)
7176
7177             cls.pg_interfaces[2].set_table_ip6(cls.vrf1_id)
7178
7179             cls.pg0.generate_remote_hosts(2)
7180
7181             for i in cls.ip6_interfaces:
7182                 i.admin_up()
7183                 i.config_ip6()
7184                 i.configure_ipv6_neighbors()
7185
7186             for i in cls.ip4_interfaces:
7187                 i.admin_up()
7188                 i.config_ip4()
7189                 i.resolve_arp()
7190
7191             cls.pg3.admin_up()
7192             cls.pg3.config_ip4()
7193             cls.pg3.resolve_arp()
7194             cls.pg3.config_ip6()
7195             cls.pg3.configure_ipv6_neighbors()
7196
7197             cls.pg5.admin_up()
7198             cls.pg5.config_ip6()
7199
7200         except Exception:
7201             super(TestNAT64, cls).tearDownClass()
7202             raise
7203
7204     def test_nat64_inside_interface_handles_neighbor_advertisement(self):
7205         """ NAT64 inside interface handles Neighbor Advertisement """
7206
7207         self.vapi.nat64_add_del_interface(self.pg5.sw_if_index)
7208
7209         # Try to send ping
7210         ping = (Ether(dst=self.pg5.local_mac, src=self.pg5.remote_mac) /
7211                 IPv6(src=self.pg5.remote_ip6, dst=self.pg5.local_ip6) /
7212                 ICMPv6EchoRequest())
7213         pkts = [ping]
7214         self.pg5.add_stream(pkts)
7215         self.pg_enable_capture(self.pg_interfaces)
7216         self.pg_start()
7217
7218         # Wait for Neighbor Solicitation
7219         capture = self.pg5.get_capture(len(pkts))
7220         packet = capture[0]
7221         try:
7222             self.assertEqual(packet[IPv6].src, self.pg5.local_ip6)
7223             self.assertEqual(packet.haslayer(ICMPv6ND_NS), 1)
7224             tgt = packet[ICMPv6ND_NS].tgt
7225         except:
7226             self.logger.error(ppp("Unexpected or invalid packet:", packet))
7227             raise
7228
7229         # Send Neighbor Advertisement
7230         p = (Ether(dst=self.pg5.local_mac, src=self.pg5.remote_mac) /
7231              IPv6(src=self.pg5.remote_ip6, dst=self.pg5.local_ip6) /
7232              ICMPv6ND_NA(tgt=tgt) /
7233              ICMPv6NDOptDstLLAddr(lladdr=self.pg5.remote_mac))
7234         pkts = [p]
7235         self.pg5.add_stream(pkts)
7236         self.pg_enable_capture(self.pg_interfaces)
7237         self.pg_start()
7238
7239         # Try to send ping again
7240         pkts = [ping]
7241         self.pg5.add_stream(pkts)
7242         self.pg_enable_capture(self.pg_interfaces)
7243         self.pg_start()
7244
7245         # Wait for ping reply
7246         capture = self.pg5.get_capture(len(pkts))
7247         packet = capture[0]
7248         try:
7249             self.assertEqual(packet[IPv6].src, self.pg5.local_ip6)
7250             self.assertEqual(packet[IPv6].dst, self.pg5.remote_ip6)
7251             self.assertEqual(packet.haslayer(ICMPv6EchoReply), 1)
7252         except:
7253             self.logger.error(ppp("Unexpected or invalid packet:", packet))
7254             raise
7255
7256     def test_pool(self):
7257         """ Add/delete address to NAT64 pool """
7258         nat_addr = socket.inet_pton(socket.AF_INET, '1.2.3.4')
7259
7260         self.vapi.nat64_add_del_pool_addr_range(nat_addr, nat_addr)
7261
7262         addresses = self.vapi.nat64_pool_addr_dump()
7263         self.assertEqual(len(addresses), 1)
7264         self.assertEqual(addresses[0].address, nat_addr)
7265
7266         self.vapi.nat64_add_del_pool_addr_range(nat_addr, nat_addr, is_add=0)
7267
7268         addresses = self.vapi.nat64_pool_addr_dump()
7269         self.assertEqual(len(addresses), 0)
7270
7271     def test_interface(self):
7272         """ Enable/disable NAT64 feature on the interface """
7273         self.vapi.nat64_add_del_interface(self.pg0.sw_if_index)
7274         self.vapi.nat64_add_del_interface(self.pg1.sw_if_index, is_inside=0)
7275
7276         interfaces = self.vapi.nat64_interface_dump()
7277         self.assertEqual(len(interfaces), 2)
7278         pg0_found = False
7279         pg1_found = False
7280         for intf in interfaces:
7281             if intf.sw_if_index == self.pg0.sw_if_index:
7282                 self.assertEqual(intf.is_inside, 1)
7283                 pg0_found = True
7284             elif intf.sw_if_index == self.pg1.sw_if_index:
7285                 self.assertEqual(intf.is_inside, 0)
7286                 pg1_found = True
7287         self.assertTrue(pg0_found)
7288         self.assertTrue(pg1_found)
7289
7290         features = self.vapi.cli("show interface features pg0")
7291         self.assertIn('nat64-in2out', features)
7292         features = self.vapi.cli("show interface features pg1")
7293         self.assertIn('nat64-out2in', features)
7294
7295         self.vapi.nat64_add_del_interface(self.pg0.sw_if_index, is_add=0)
7296         self.vapi.nat64_add_del_interface(self.pg1.sw_if_index, is_add=0)
7297
7298         interfaces = self.vapi.nat64_interface_dump()
7299         self.assertEqual(len(interfaces), 0)
7300
7301     def test_static_bib(self):
7302         """ Add/delete static BIB entry """
7303         in_addr = socket.inet_pton(socket.AF_INET6,
7304                                    '2001:db8:85a3::8a2e:370:7334')
7305         out_addr = socket.inet_pton(socket.AF_INET, '10.1.1.3')
7306         in_port = 1234
7307         out_port = 5678
7308         proto = IP_PROTOS.tcp
7309
7310         self.vapi.nat64_add_del_static_bib(in_addr,
7311                                            out_addr,
7312                                            in_port,
7313                                            out_port,
7314                                            proto)
7315         bib = self.vapi.nat64_bib_dump(IP_PROTOS.tcp)
7316         static_bib_num = 0
7317         for bibe in bib:
7318             if bibe.is_static:
7319                 static_bib_num += 1
7320                 self.assertEqual(bibe.i_addr, in_addr)
7321                 self.assertEqual(bibe.o_addr, out_addr)
7322                 self.assertEqual(bibe.i_port, in_port)
7323                 self.assertEqual(bibe.o_port, out_port)
7324         self.assertEqual(static_bib_num, 1)
7325         bibs = self.statistics.get_counter('/nat64/total-bibs')
7326         self.assertEqual(bibs[0][0], 1)
7327
7328         self.vapi.nat64_add_del_static_bib(in_addr,
7329                                            out_addr,
7330                                            in_port,
7331                                            out_port,
7332                                            proto,
7333                                            is_add=0)
7334         bib = self.vapi.nat64_bib_dump(IP_PROTOS.tcp)
7335         static_bib_num = 0
7336         for bibe in bib:
7337             if bibe.is_static:
7338                 static_bib_num += 1
7339         self.assertEqual(static_bib_num, 0)
7340         bibs = self.statistics.get_counter('/nat64/total-bibs')
7341         self.assertEqual(bibs[0][0], 0)
7342
7343     def test_set_timeouts(self):
7344         """ Set NAT64 timeouts """
7345         # verify default values
7346         timeouts = self.vapi.nat_get_timeouts()
7347         self.assertEqual(timeouts.udp, 300)
7348         self.assertEqual(timeouts.icmp, 60)
7349         self.assertEqual(timeouts.tcp_transitory, 240)
7350         self.assertEqual(timeouts.tcp_established, 7440)
7351
7352         # set and verify custom values
7353         self.vapi.nat_set_timeouts(udp=200, icmp=30, tcp_transitory=250,
7354                                    tcp_established=7450)
7355         timeouts = self.vapi.nat_get_timeouts()
7356         self.assertEqual(timeouts.udp, 200)
7357         self.assertEqual(timeouts.icmp, 30)
7358         self.assertEqual(timeouts.tcp_transitory, 250)
7359         self.assertEqual(timeouts.tcp_established, 7450)
7360
7361     def test_dynamic(self):
7362         """ NAT64 dynamic translation test """
7363         self.tcp_port_in = 6303
7364         self.udp_port_in = 6304
7365         self.icmp_id_in = 6305
7366
7367         ses_num_start = self.nat64_get_ses_num()
7368
7369         self.vapi.nat64_add_del_pool_addr_range(self.nat_addr_n,
7370                                                 self.nat_addr_n)
7371         self.vapi.nat64_add_del_interface(self.pg0.sw_if_index)
7372         self.vapi.nat64_add_del_interface(self.pg1.sw_if_index, is_inside=0)
7373
7374         # in2out
7375         tcpn = self.statistics.get_counter('/err/nat64-in2out/TCP packets')
7376         udpn = self.statistics.get_counter('/err/nat64-in2out/UDP packets')
7377         icmpn = self.statistics.get_counter('/err/nat64-in2out/ICMP packets')
7378         totaln = self.statistics.get_counter(
7379             '/err/nat64-in2out/good in2out packets processed')
7380
7381         pkts = self.create_stream_in_ip6(self.pg0, self.pg1)
7382         self.pg0.add_stream(pkts)
7383         self.pg_enable_capture(self.pg_interfaces)
7384         self.pg_start()
7385         capture = self.pg1.get_capture(len(pkts))
7386         self.verify_capture_out(capture, nat_ip=self.nat_addr,
7387                                 dst_ip=self.pg1.remote_ip4)
7388
7389         err = self.statistics.get_counter('/err/nat64-in2out/TCP packets')
7390         self.assertEqual(err - tcpn, 1)
7391         err = self.statistics.get_counter('/err/nat64-in2out/UDP packets')
7392         self.assertEqual(err - udpn, 1)
7393         err = self.statistics.get_counter('/err/nat64-in2out/ICMP packets')
7394         self.assertEqual(err - icmpn, 1)
7395         err = self.statistics.get_counter(
7396             '/err/nat64-in2out/good in2out packets processed')
7397         self.assertEqual(err - totaln, 3)
7398
7399         # out2in
7400         tcpn = self.statistics.get_counter('/err/nat64-out2in/TCP packets')
7401         udpn = self.statistics.get_counter('/err/nat64-out2in/UDP packets')
7402         icmpn = self.statistics.get_counter('/err/nat64-out2in/ICMP packets')
7403         totaln = self.statistics.get_counter(
7404             '/err/nat64-out2in/good out2in packets processed')
7405
7406         pkts = self.create_stream_out(self.pg1, dst_ip=self.nat_addr)
7407         self.pg1.add_stream(pkts)
7408         self.pg_enable_capture(self.pg_interfaces)
7409         self.pg_start()
7410         capture = self.pg0.get_capture(len(pkts))
7411         ip = IPv6(src=''.join(['64:ff9b::', self.pg1.remote_ip4]))
7412         self.verify_capture_in_ip6(capture, ip[IPv6].src, self.pg0.remote_ip6)
7413
7414         err = self.statistics.get_counter('/err/nat64-out2in/TCP packets')
7415         self.assertEqual(err - tcpn, 1)
7416         err = self.statistics.get_counter('/err/nat64-out2in/UDP packets')
7417         self.assertEqual(err - udpn, 1)
7418         err = self.statistics.get_counter('/err/nat64-out2in/ICMP packets')
7419         self.assertEqual(err - icmpn, 1)
7420         err = self.statistics.get_counter(
7421             '/err/nat64-out2in/good out2in packets processed')
7422         self.assertEqual(err - totaln, 3)
7423
7424         bibs = self.statistics.get_counter('/nat64/total-bibs')
7425         self.assertEqual(bibs[0][0], 3)
7426         sessions = self.statistics.get_counter('/nat64/total-sessions')
7427         self.assertEqual(sessions[0][0], 3)
7428
7429         # in2out
7430         pkts = self.create_stream_in_ip6(self.pg0, self.pg1)
7431         self.pg0.add_stream(pkts)
7432         self.pg_enable_capture(self.pg_interfaces)
7433         self.pg_start()
7434         capture = self.pg1.get_capture(len(pkts))
7435         self.verify_capture_out(capture, nat_ip=self.nat_addr,
7436                                 dst_ip=self.pg1.remote_ip4)
7437
7438         # out2in
7439         pkts = self.create_stream_out(self.pg1, dst_ip=self.nat_addr)
7440         self.pg1.add_stream(pkts)
7441         self.pg_enable_capture(self.pg_interfaces)
7442         self.pg_start()
7443         capture = self.pg0.get_capture(len(pkts))
7444         self.verify_capture_in_ip6(capture, ip[IPv6].src, self.pg0.remote_ip6)
7445
7446         ses_num_end = self.nat64_get_ses_num()
7447
7448         self.assertEqual(ses_num_end - ses_num_start, 3)
7449
7450         # tenant with specific VRF
7451         self.vapi.nat64_add_del_pool_addr_range(self.vrf1_nat_addr_n,
7452                                                 self.vrf1_nat_addr_n,
7453                                                 vrf_id=self.vrf1_id)
7454         self.vapi.nat64_add_del_interface(self.pg2.sw_if_index)
7455
7456         pkts = self.create_stream_in_ip6(self.pg2, self.pg1)
7457         self.pg2.add_stream(pkts)
7458         self.pg_enable_capture(self.pg_interfaces)
7459         self.pg_start()
7460         capture = self.pg1.get_capture(len(pkts))
7461         self.verify_capture_out(capture, nat_ip=self.vrf1_nat_addr,
7462                                 dst_ip=self.pg1.remote_ip4)
7463
7464         pkts = self.create_stream_out(self.pg1, dst_ip=self.vrf1_nat_addr)
7465         self.pg1.add_stream(pkts)
7466         self.pg_enable_capture(self.pg_interfaces)
7467         self.pg_start()
7468         capture = self.pg2.get_capture(len(pkts))
7469         self.verify_capture_in_ip6(capture, ip[IPv6].src, self.pg2.remote_ip6)
7470
7471     def test_static(self):
7472         """ NAT64 static translation test """
7473         self.tcp_port_in = 60303
7474         self.udp_port_in = 60304
7475         self.icmp_id_in = 60305
7476         self.tcp_port_out = 60303
7477         self.udp_port_out = 60304
7478         self.icmp_id_out = 60305
7479
7480         ses_num_start = self.nat64_get_ses_num()
7481
7482         self.vapi.nat64_add_del_pool_addr_range(self.nat_addr_n,
7483                                                 self.nat_addr_n)
7484         self.vapi.nat64_add_del_interface(self.pg0.sw_if_index)
7485         self.vapi.nat64_add_del_interface(self.pg1.sw_if_index, is_inside=0)
7486
7487         self.vapi.nat64_add_del_static_bib(self.pg0.remote_ip6n,
7488                                            self.nat_addr_n,
7489                                            self.tcp_port_in,
7490                                            self.tcp_port_out,
7491                                            IP_PROTOS.tcp)
7492         self.vapi.nat64_add_del_static_bib(self.pg0.remote_ip6n,
7493                                            self.nat_addr_n,
7494                                            self.udp_port_in,
7495                                            self.udp_port_out,
7496                                            IP_PROTOS.udp)
7497         self.vapi.nat64_add_del_static_bib(self.pg0.remote_ip6n,
7498                                            self.nat_addr_n,
7499                                            self.icmp_id_in,
7500                                            self.icmp_id_out,
7501                                            IP_PROTOS.icmp)
7502
7503         # in2out
7504         pkts = self.create_stream_in_ip6(self.pg0, self.pg1)
7505         self.pg0.add_stream(pkts)
7506         self.pg_enable_capture(self.pg_interfaces)
7507         self.pg_start()
7508         capture = self.pg1.get_capture(len(pkts))
7509         self.verify_capture_out(capture, nat_ip=self.nat_addr,
7510                                 dst_ip=self.pg1.remote_ip4, same_port=True)
7511
7512         # out2in
7513         pkts = self.create_stream_out(self.pg1, dst_ip=self.nat_addr)
7514         self.pg1.add_stream(pkts)
7515         self.pg_enable_capture(self.pg_interfaces)
7516         self.pg_start()
7517         capture = self.pg0.get_capture(len(pkts))
7518         ip = IPv6(src=''.join(['64:ff9b::', self.pg1.remote_ip4]))
7519         self.verify_capture_in_ip6(capture, ip[IPv6].src, self.pg0.remote_ip6)
7520
7521         ses_num_end = self.nat64_get_ses_num()
7522
7523         self.assertEqual(ses_num_end - ses_num_start, 3)
7524
7525     @unittest.skipUnless(running_extended_tests, "part of extended tests")
7526     def test_session_timeout(self):
7527         """ NAT64 session timeout """
7528         self.icmp_id_in = 1234
7529         self.vapi.nat64_add_del_pool_addr_range(self.nat_addr_n,
7530                                                 self.nat_addr_n)
7531         self.vapi.nat64_add_del_interface(self.pg0.sw_if_index)
7532         self.vapi.nat64_add_del_interface(self.pg1.sw_if_index, is_inside=0)
7533         self.vapi.nat_set_timeouts(icmp=5, tcp_transitory=5, tcp_established=5)
7534
7535         pkts = self.create_stream_in_ip6(self.pg0, self.pg1)
7536         self.pg0.add_stream(pkts)
7537         self.pg_enable_capture(self.pg_interfaces)
7538         self.pg_start()
7539         capture = self.pg1.get_capture(len(pkts))
7540
7541         ses_num_before_timeout = self.nat64_get_ses_num()
7542
7543         sleep(15)
7544
7545         # ICMP and TCP session after timeout
7546         ses_num_after_timeout = self.nat64_get_ses_num()
7547         self.assertEqual(ses_num_before_timeout - ses_num_after_timeout, 2)
7548
7549     def test_icmp_error(self):
7550         """ NAT64 ICMP Error message translation """
7551         self.tcp_port_in = 6303
7552         self.udp_port_in = 6304
7553         self.icmp_id_in = 6305
7554
7555         self.vapi.nat64_add_del_pool_addr_range(self.nat_addr_n,
7556                                                 self.nat_addr_n)
7557         self.vapi.nat64_add_del_interface(self.pg0.sw_if_index)
7558         self.vapi.nat64_add_del_interface(self.pg1.sw_if_index, is_inside=0)
7559
7560         # send some packets to create sessions
7561         pkts = self.create_stream_in_ip6(self.pg0, self.pg1)
7562         self.pg0.add_stream(pkts)
7563         self.pg_enable_capture(self.pg_interfaces)
7564         self.pg_start()
7565         capture_ip4 = self.pg1.get_capture(len(pkts))
7566         self.verify_capture_out(capture_ip4,
7567                                 nat_ip=self.nat_addr,
7568                                 dst_ip=self.pg1.remote_ip4)
7569
7570         pkts = self.create_stream_out(self.pg1, dst_ip=self.nat_addr)
7571         self.pg1.add_stream(pkts)
7572         self.pg_enable_capture(self.pg_interfaces)
7573         self.pg_start()
7574         capture_ip6 = self.pg0.get_capture(len(pkts))
7575         ip = IPv6(src=''.join(['64:ff9b::', self.pg1.remote_ip4]))
7576         self.verify_capture_in_ip6(capture_ip6, ip[IPv6].src,
7577                                    self.pg0.remote_ip6)
7578
7579         # in2out
7580         pkts = [Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
7581                 IPv6(src=self.pg0.remote_ip6, dst=ip[IPv6].src) /
7582                 ICMPv6DestUnreach(code=1) /
7583                 packet[IPv6] for packet in capture_ip6]
7584         self.pg0.add_stream(pkts)
7585         self.pg_enable_capture(self.pg_interfaces)
7586         self.pg_start()
7587         capture = self.pg1.get_capture(len(pkts))
7588         for packet in capture:
7589             try:
7590                 self.assertEqual(packet[IP].src, self.nat_addr)
7591                 self.assertEqual(packet[IP].dst, self.pg1.remote_ip4)
7592                 self.assertEqual(packet[ICMP].type, 3)
7593                 self.assertEqual(packet[ICMP].code, 13)
7594                 inner = packet[IPerror]
7595                 self.assertEqual(inner.src, self.pg1.remote_ip4)
7596                 self.assertEqual(inner.dst, self.nat_addr)
7597                 self.assert_packet_checksums_valid(packet)
7598                 if inner.haslayer(TCPerror):
7599                     self.assertEqual(inner[TCPerror].dport, self.tcp_port_out)
7600                 elif inner.haslayer(UDPerror):
7601                     self.assertEqual(inner[UDPerror].dport, self.udp_port_out)
7602                 else:
7603                     self.assertEqual(inner[ICMPerror].id, self.icmp_id_out)
7604             except:
7605                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
7606                 raise
7607
7608         # out2in
7609         pkts = [Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
7610                 IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
7611                 ICMP(type=3, code=13) /
7612                 packet[IP] for packet in capture_ip4]
7613         self.pg1.add_stream(pkts)
7614         self.pg_enable_capture(self.pg_interfaces)
7615         self.pg_start()
7616         capture = self.pg0.get_capture(len(pkts))
7617         for packet in capture:
7618             try:
7619                 self.assertEqual(packet[IPv6].src, ip.src)
7620                 self.assertEqual(packet[IPv6].dst, self.pg0.remote_ip6)
7621                 icmp = packet[ICMPv6DestUnreach]
7622                 self.assertEqual(icmp.code, 1)
7623                 inner = icmp[IPerror6]
7624                 self.assertEqual(inner.src, self.pg0.remote_ip6)
7625                 self.assertEqual(inner.dst, ip.src)
7626                 self.assert_icmpv6_checksum_valid(packet)
7627                 if inner.haslayer(TCPerror):
7628                     self.assertEqual(inner[TCPerror].sport, self.tcp_port_in)
7629                 elif inner.haslayer(UDPerror):
7630                     self.assertEqual(inner[UDPerror].sport, self.udp_port_in)
7631                 else:
7632                     self.assertEqual(inner[ICMPv6EchoRequest].id,
7633                                      self.icmp_id_in)
7634             except:
7635                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
7636                 raise
7637
7638     def test_hairpinning(self):
7639         """ NAT64 hairpinning """
7640
7641         client = self.pg0.remote_hosts[0]
7642         server = self.pg0.remote_hosts[1]
7643         server_tcp_in_port = 22
7644         server_tcp_out_port = 4022
7645         server_udp_in_port = 23
7646         server_udp_out_port = 4023
7647         client_tcp_in_port = 1234
7648         client_udp_in_port = 1235
7649         client_tcp_out_port = 0
7650         client_udp_out_port = 0
7651         ip = IPv6(src=''.join(['64:ff9b::', self.nat_addr]))
7652         nat_addr_ip6 = ip.src
7653
7654         self.vapi.nat64_add_del_pool_addr_range(self.nat_addr_n,
7655                                                 self.nat_addr_n)
7656         self.vapi.nat64_add_del_interface(self.pg0.sw_if_index)
7657         self.vapi.nat64_add_del_interface(self.pg1.sw_if_index, is_inside=0)
7658
7659         self.vapi.nat64_add_del_static_bib(server.ip6n,
7660                                            self.nat_addr_n,
7661                                            server_tcp_in_port,
7662                                            server_tcp_out_port,
7663                                            IP_PROTOS.tcp)
7664         self.vapi.nat64_add_del_static_bib(server.ip6n,
7665                                            self.nat_addr_n,
7666                                            server_udp_in_port,
7667                                            server_udp_out_port,
7668                                            IP_PROTOS.udp)
7669
7670         # client to server
7671         pkts = []
7672         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
7673              IPv6(src=client.ip6, dst=nat_addr_ip6) /
7674              TCP(sport=client_tcp_in_port, dport=server_tcp_out_port))
7675         pkts.append(p)
7676         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
7677              IPv6(src=client.ip6, dst=nat_addr_ip6) /
7678              UDP(sport=client_udp_in_port, dport=server_udp_out_port))
7679         pkts.append(p)
7680         self.pg0.add_stream(pkts)
7681         self.pg_enable_capture(self.pg_interfaces)
7682         self.pg_start()
7683         capture = self.pg0.get_capture(len(pkts))
7684         for packet in capture:
7685             try:
7686                 self.assertEqual(packet[IPv6].src, nat_addr_ip6)
7687                 self.assertEqual(packet[IPv6].dst, server.ip6)
7688                 self.assert_packet_checksums_valid(packet)
7689                 if packet.haslayer(TCP):
7690                     self.assertNotEqual(packet[TCP].sport, client_tcp_in_port)
7691                     self.assertEqual(packet[TCP].dport, server_tcp_in_port)
7692                     client_tcp_out_port = packet[TCP].sport
7693                 else:
7694                     self.assertNotEqual(packet[UDP].sport, client_udp_in_port)
7695                     self.assertEqual(packet[UDP].dport, server_udp_in_port)
7696                     client_udp_out_port = packet[UDP].sport
7697             except:
7698                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
7699                 raise
7700
7701         # server to client
7702         pkts = []
7703         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
7704              IPv6(src=server.ip6, dst=nat_addr_ip6) /
7705              TCP(sport=server_tcp_in_port, dport=client_tcp_out_port))
7706         pkts.append(p)
7707         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
7708              IPv6(src=server.ip6, dst=nat_addr_ip6) /
7709              UDP(sport=server_udp_in_port, dport=client_udp_out_port))
7710         pkts.append(p)
7711         self.pg0.add_stream(pkts)
7712         self.pg_enable_capture(self.pg_interfaces)
7713         self.pg_start()
7714         capture = self.pg0.get_capture(len(pkts))
7715         for packet in capture:
7716             try:
7717                 self.assertEqual(packet[IPv6].src, nat_addr_ip6)
7718                 self.assertEqual(packet[IPv6].dst, client.ip6)
7719                 self.assert_packet_checksums_valid(packet)
7720                 if packet.haslayer(TCP):
7721                     self.assertEqual(packet[TCP].sport, server_tcp_out_port)
7722                     self.assertEqual(packet[TCP].dport, client_tcp_in_port)
7723                 else:
7724                     self.assertEqual(packet[UDP].sport, server_udp_out_port)
7725                     self.assertEqual(packet[UDP].dport, client_udp_in_port)
7726             except:
7727                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
7728                 raise
7729
7730         # ICMP error
7731         pkts = []
7732         pkts = [Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
7733                 IPv6(src=client.ip6, dst=nat_addr_ip6) /
7734                 ICMPv6DestUnreach(code=1) /
7735                 packet[IPv6] for packet in capture]
7736         self.pg0.add_stream(pkts)
7737         self.pg_enable_capture(self.pg_interfaces)
7738         self.pg_start()
7739         capture = self.pg0.get_capture(len(pkts))
7740         for packet in capture:
7741             try:
7742                 self.assertEqual(packet[IPv6].src, nat_addr_ip6)
7743                 self.assertEqual(packet[IPv6].dst, server.ip6)
7744                 icmp = packet[ICMPv6DestUnreach]
7745                 self.assertEqual(icmp.code, 1)
7746                 inner = icmp[IPerror6]
7747                 self.assertEqual(inner.src, server.ip6)
7748                 self.assertEqual(inner.dst, nat_addr_ip6)
7749                 self.assert_packet_checksums_valid(packet)
7750                 if inner.haslayer(TCPerror):
7751                     self.assertEqual(inner[TCPerror].sport, server_tcp_in_port)
7752                     self.assertEqual(inner[TCPerror].dport,
7753                                      client_tcp_out_port)
7754                 else:
7755                     self.assertEqual(inner[UDPerror].sport, server_udp_in_port)
7756                     self.assertEqual(inner[UDPerror].dport,
7757                                      client_udp_out_port)
7758             except:
7759                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
7760                 raise
7761
7762     def test_prefix(self):
7763         """ NAT64 Network-Specific Prefix """
7764
7765         self.vapi.nat64_add_del_pool_addr_range(self.nat_addr_n,
7766                                                 self.nat_addr_n)
7767         self.vapi.nat64_add_del_interface(self.pg0.sw_if_index)
7768         self.vapi.nat64_add_del_interface(self.pg1.sw_if_index, is_inside=0)
7769         self.vapi.nat64_add_del_pool_addr_range(self.vrf1_nat_addr_n,
7770                                                 self.vrf1_nat_addr_n,
7771                                                 vrf_id=self.vrf1_id)
7772         self.vapi.nat64_add_del_interface(self.pg2.sw_if_index)
7773
7774         # Add global prefix
7775         global_pref64 = "2001:db8::"
7776         global_pref64_n = socket.inet_pton(socket.AF_INET6, global_pref64)
7777         global_pref64_len = 32
7778         self.vapi.nat64_add_del_prefix(global_pref64_n, global_pref64_len)
7779
7780         prefix = self.vapi.nat64_prefix_dump()
7781         self.assertEqual(len(prefix), 1)
7782         self.assertEqual(prefix[0].prefix, global_pref64_n)
7783         self.assertEqual(prefix[0].prefix_len, global_pref64_len)
7784         self.assertEqual(prefix[0].vrf_id, 0)
7785
7786         # Add tenant specific prefix
7787         vrf1_pref64 = "2001:db8:122:300::"
7788         vrf1_pref64_n = socket.inet_pton(socket.AF_INET6, vrf1_pref64)
7789         vrf1_pref64_len = 56
7790         self.vapi.nat64_add_del_prefix(vrf1_pref64_n,
7791                                        vrf1_pref64_len,
7792                                        vrf_id=self.vrf1_id)
7793         prefix = self.vapi.nat64_prefix_dump()
7794         self.assertEqual(len(prefix), 2)
7795
7796         # Global prefix
7797         pkts = self.create_stream_in_ip6(self.pg0,
7798                                          self.pg1,
7799                                          pref=global_pref64,
7800                                          plen=global_pref64_len)
7801         self.pg0.add_stream(pkts)
7802         self.pg_enable_capture(self.pg_interfaces)
7803         self.pg_start()
7804         capture = self.pg1.get_capture(len(pkts))
7805         self.verify_capture_out(capture, nat_ip=self.nat_addr,
7806                                 dst_ip=self.pg1.remote_ip4)
7807
7808         pkts = self.create_stream_out(self.pg1, dst_ip=self.nat_addr)
7809         self.pg1.add_stream(pkts)
7810         self.pg_enable_capture(self.pg_interfaces)
7811         self.pg_start()
7812         capture = self.pg0.get_capture(len(pkts))
7813         dst_ip = self.compose_ip6(self.pg1.remote_ip4,
7814                                   global_pref64,
7815                                   global_pref64_len)
7816         self.verify_capture_in_ip6(capture, dst_ip, self.pg0.remote_ip6)
7817
7818         # Tenant specific prefix
7819         pkts = self.create_stream_in_ip6(self.pg2,
7820                                          self.pg1,
7821                                          pref=vrf1_pref64,
7822                                          plen=vrf1_pref64_len)
7823         self.pg2.add_stream(pkts)
7824         self.pg_enable_capture(self.pg_interfaces)
7825         self.pg_start()
7826         capture = self.pg1.get_capture(len(pkts))
7827         self.verify_capture_out(capture, nat_ip=self.vrf1_nat_addr,
7828                                 dst_ip=self.pg1.remote_ip4)
7829
7830         pkts = self.create_stream_out(self.pg1, dst_ip=self.vrf1_nat_addr)
7831         self.pg1.add_stream(pkts)
7832         self.pg_enable_capture(self.pg_interfaces)
7833         self.pg_start()
7834         capture = self.pg2.get_capture(len(pkts))
7835         dst_ip = self.compose_ip6(self.pg1.remote_ip4,
7836                                   vrf1_pref64,
7837                                   vrf1_pref64_len)
7838         self.verify_capture_in_ip6(capture, dst_ip, self.pg2.remote_ip6)
7839
7840     def test_unknown_proto(self):
7841         """ NAT64 translate packet with unknown protocol """
7842
7843         self.vapi.nat64_add_del_pool_addr_range(self.nat_addr_n,
7844                                                 self.nat_addr_n)
7845         self.vapi.nat64_add_del_interface(self.pg0.sw_if_index)
7846         self.vapi.nat64_add_del_interface(self.pg1.sw_if_index, is_inside=0)
7847         remote_ip6 = self.compose_ip6(self.pg1.remote_ip4, '64:ff9b::', 96)
7848
7849         # in2out
7850         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
7851              IPv6(src=self.pg0.remote_ip6, dst=remote_ip6) /
7852              TCP(sport=self.tcp_port_in, dport=20))
7853         self.pg0.add_stream(p)
7854         self.pg_enable_capture(self.pg_interfaces)
7855         self.pg_start()
7856         p = self.pg1.get_capture(1)
7857
7858         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
7859              IPv6(src=self.pg0.remote_ip6, dst=remote_ip6, nh=47) /
7860              GRE() /
7861              IP(src=self.pg2.local_ip4, dst=self.pg2.remote_ip4) /
7862              TCP(sport=1234, dport=1234))
7863         self.pg0.add_stream(p)
7864         self.pg_enable_capture(self.pg_interfaces)
7865         self.pg_start()
7866         p = self.pg1.get_capture(1)
7867         packet = p[0]
7868         try:
7869             self.assertEqual(packet[IP].src, self.nat_addr)
7870             self.assertEqual(packet[IP].dst, self.pg1.remote_ip4)
7871             self.assertEqual(packet.haslayer(GRE), 1)
7872             self.assert_packet_checksums_valid(packet)
7873         except:
7874             self.logger.error(ppp("Unexpected or invalid packet:", packet))
7875             raise
7876
7877         # out2in
7878         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
7879              IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
7880              GRE() /
7881              IP(src=self.pg2.remote_ip4, dst=self.pg2.local_ip4) /
7882              TCP(sport=1234, dport=1234))
7883         self.pg1.add_stream(p)
7884         self.pg_enable_capture(self.pg_interfaces)
7885         self.pg_start()
7886         p = self.pg0.get_capture(1)
7887         packet = p[0]
7888         try:
7889             self.assertEqual(packet[IPv6].src, remote_ip6)
7890             self.assertEqual(packet[IPv6].dst, self.pg0.remote_ip6)
7891             self.assertEqual(packet[IPv6].nh, 47)
7892         except:
7893             self.logger.error(ppp("Unexpected or invalid packet:", packet))
7894             raise
7895
7896     def test_hairpinning_unknown_proto(self):
7897         """ NAT64 translate packet with unknown protocol - hairpinning """
7898
7899         client = self.pg0.remote_hosts[0]
7900         server = self.pg0.remote_hosts[1]
7901         server_tcp_in_port = 22
7902         server_tcp_out_port = 4022
7903         client_tcp_in_port = 1234
7904         client_tcp_out_port = 1235
7905         server_nat_ip = "10.0.0.100"
7906         client_nat_ip = "10.0.0.110"
7907         server_nat_ip_n = socket.inet_pton(socket.AF_INET, server_nat_ip)
7908         client_nat_ip_n = socket.inet_pton(socket.AF_INET, client_nat_ip)
7909         server_nat_ip6 = self.compose_ip6(server_nat_ip, '64:ff9b::', 96)
7910         client_nat_ip6 = self.compose_ip6(client_nat_ip, '64:ff9b::', 96)
7911
7912         self.vapi.nat64_add_del_pool_addr_range(server_nat_ip_n,
7913                                                 client_nat_ip_n)
7914         self.vapi.nat64_add_del_interface(self.pg0.sw_if_index)
7915         self.vapi.nat64_add_del_interface(self.pg1.sw_if_index, is_inside=0)
7916
7917         self.vapi.nat64_add_del_static_bib(server.ip6n,
7918                                            server_nat_ip_n,
7919                                            server_tcp_in_port,
7920                                            server_tcp_out_port,
7921                                            IP_PROTOS.tcp)
7922
7923         self.vapi.nat64_add_del_static_bib(server.ip6n,
7924                                            server_nat_ip_n,
7925                                            0,
7926                                            0,
7927                                            IP_PROTOS.gre)
7928
7929         self.vapi.nat64_add_del_static_bib(client.ip6n,
7930                                            client_nat_ip_n,
7931                                            client_tcp_in_port,
7932                                            client_tcp_out_port,
7933                                            IP_PROTOS.tcp)
7934
7935         # client to server
7936         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
7937              IPv6(src=client.ip6, dst=server_nat_ip6) /
7938              TCP(sport=client_tcp_in_port, dport=server_tcp_out_port))
7939         self.pg0.add_stream(p)
7940         self.pg_enable_capture(self.pg_interfaces)
7941         self.pg_start()
7942         p = self.pg0.get_capture(1)
7943
7944         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
7945              IPv6(src=client.ip6, dst=server_nat_ip6, nh=IP_PROTOS.gre) /
7946              GRE() /
7947              IP(src=self.pg2.local_ip4, dst=self.pg2.remote_ip4) /
7948              TCP(sport=1234, dport=1234))
7949         self.pg0.add_stream(p)
7950         self.pg_enable_capture(self.pg_interfaces)
7951         self.pg_start()
7952         p = self.pg0.get_capture(1)
7953         packet = p[0]
7954         try:
7955             self.assertEqual(packet[IPv6].src, client_nat_ip6)
7956             self.assertEqual(packet[IPv6].dst, server.ip6)
7957             self.assertEqual(packet[IPv6].nh, IP_PROTOS.gre)
7958         except:
7959             self.logger.error(ppp("Unexpected or invalid packet:", packet))
7960             raise
7961
7962         # server to client
7963         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
7964              IPv6(src=server.ip6, dst=client_nat_ip6, nh=IP_PROTOS.gre) /
7965              GRE() /
7966              IP(src=self.pg2.remote_ip4, dst=self.pg2.local_ip4) /
7967              TCP(sport=1234, dport=1234))
7968         self.pg0.add_stream(p)
7969         self.pg_enable_capture(self.pg_interfaces)
7970         self.pg_start()
7971         p = self.pg0.get_capture(1)
7972         packet = p[0]
7973         try:
7974             self.assertEqual(packet[IPv6].src, server_nat_ip6)
7975             self.assertEqual(packet[IPv6].dst, client.ip6)
7976             self.assertEqual(packet[IPv6].nh, IP_PROTOS.gre)
7977         except:
7978             self.logger.error(ppp("Unexpected or invalid packet:", packet))
7979             raise
7980
7981     def test_one_armed_nat64(self):
7982         """ One armed NAT64 """
7983         external_port = 0
7984         remote_host_ip6 = self.compose_ip6(self.pg3.remote_ip4,
7985                                            '64:ff9b::',
7986                                            96)
7987
7988         self.vapi.nat64_add_del_pool_addr_range(self.nat_addr_n,
7989                                                 self.nat_addr_n)
7990         self.vapi.nat64_add_del_interface(self.pg3.sw_if_index)
7991         self.vapi.nat64_add_del_interface(self.pg3.sw_if_index, is_inside=0)
7992
7993         # in2out
7994         p = (Ether(src=self.pg3.remote_mac, dst=self.pg3.local_mac) /
7995              IPv6(src=self.pg3.remote_ip6, dst=remote_host_ip6) /
7996              TCP(sport=12345, dport=80))
7997         self.pg3.add_stream(p)
7998         self.pg_enable_capture(self.pg_interfaces)
7999         self.pg_start()
8000         capture = self.pg3.get_capture(1)
8001         p = capture[0]
8002         try:
8003             ip = p[IP]
8004             tcp = p[TCP]
8005             self.assertEqual(ip.src, self.nat_addr)
8006             self.assertEqual(ip.dst, self.pg3.remote_ip4)
8007             self.assertNotEqual(tcp.sport, 12345)
8008             external_port = tcp.sport
8009             self.assertEqual(tcp.dport, 80)
8010             self.assert_packet_checksums_valid(p)
8011         except:
8012             self.logger.error(ppp("Unexpected or invalid packet:", p))
8013             raise
8014
8015         # out2in
8016         p = (Ether(src=self.pg3.remote_mac, dst=self.pg3.local_mac) /
8017              IP(src=self.pg3.remote_ip4, dst=self.nat_addr) /
8018              TCP(sport=80, dport=external_port))
8019         self.pg3.add_stream(p)
8020         self.pg_enable_capture(self.pg_interfaces)
8021         self.pg_start()
8022         capture = self.pg3.get_capture(1)
8023         p = capture[0]
8024         try:
8025             ip = p[IPv6]
8026             tcp = p[TCP]
8027             self.assertEqual(ip.src, remote_host_ip6)
8028             self.assertEqual(ip.dst, self.pg3.remote_ip6)
8029             self.assertEqual(tcp.sport, 80)
8030             self.assertEqual(tcp.dport, 12345)
8031             self.assert_packet_checksums_valid(p)
8032         except:
8033             self.logger.error(ppp("Unexpected or invalid packet:", p))
8034             raise
8035
8036     def test_frag_in_order(self):
8037         """ NAT64 translate fragments arriving in order """
8038         self.tcp_port_in = random.randint(1025, 65535)
8039
8040         self.vapi.nat64_add_del_pool_addr_range(self.nat_addr_n,
8041                                                 self.nat_addr_n)
8042         self.vapi.nat64_add_del_interface(self.pg0.sw_if_index)
8043         self.vapi.nat64_add_del_interface(self.pg1.sw_if_index, is_inside=0)
8044
8045         reass = self.vapi.nat_reass_dump()
8046         reass_n_start = len(reass)
8047
8048         # in2out
8049         data = b'a' * 200
8050         pkts = self.create_stream_frag_ip6(self.pg0, self.pg1.remote_ip4,
8051                                            self.tcp_port_in, 20, data)
8052         self.pg0.add_stream(pkts)
8053         self.pg_enable_capture(self.pg_interfaces)
8054         self.pg_start()
8055         frags = self.pg1.get_capture(len(pkts))
8056         p = self.reass_frags_and_verify(frags,
8057                                         self.nat_addr,
8058                                         self.pg1.remote_ip4)
8059         self.assertEqual(p[TCP].dport, 20)
8060         self.assertNotEqual(p[TCP].sport, self.tcp_port_in)
8061         self.tcp_port_out = p[TCP].sport
8062         self.assertEqual(data, p[Raw].load)
8063
8064         # out2in
8065         data = b"A" * 4 + b"b" * 16 + b"C" * 3
8066         pkts = self.create_stream_frag(self.pg1,
8067                                        self.nat_addr,
8068                                        20,
8069                                        self.tcp_port_out,
8070                                        data)
8071         self.pg1.add_stream(pkts)
8072         self.pg_enable_capture(self.pg_interfaces)
8073         self.pg_start()
8074         frags = self.pg0.get_capture(len(pkts))
8075         src = self.compose_ip6(self.pg1.remote_ip4, '64:ff9b::', 96)
8076         p = self.reass_frags_and_verify_ip6(frags, src, self.pg0.remote_ip6)
8077         self.assertEqual(p[TCP].sport, 20)
8078         self.assertEqual(p[TCP].dport, self.tcp_port_in)
8079         self.assertEqual(data, p[Raw].load)
8080
8081         reass = self.vapi.nat_reass_dump()
8082         reass_n_end = len(reass)
8083
8084         self.assertEqual(reass_n_end - reass_n_start, 2)
8085
8086     def test_reass_hairpinning(self):
8087         """ NAT64 fragments hairpinning """
8088         data = 'a' * 200
8089         server = self.pg0.remote_hosts[1]
8090         server_in_port = random.randint(1025, 65535)
8091         server_out_port = random.randint(1025, 65535)
8092         client_in_port = random.randint(1025, 65535)
8093         ip = IPv6(src=''.join(['64:ff9b::', self.nat_addr]))
8094         nat_addr_ip6 = ip.src
8095
8096         self.vapi.nat64_add_del_pool_addr_range(self.nat_addr_n,
8097                                                 self.nat_addr_n)
8098         self.vapi.nat64_add_del_interface(self.pg0.sw_if_index)
8099         self.vapi.nat64_add_del_interface(self.pg1.sw_if_index, is_inside=0)
8100
8101         # add static BIB entry for server
8102         self.vapi.nat64_add_del_static_bib(server.ip6n,
8103                                            self.nat_addr_n,
8104                                            server_in_port,
8105                                            server_out_port,
8106                                            IP_PROTOS.tcp)
8107
8108         # send packet from host to server
8109         pkts = self.create_stream_frag_ip6(self.pg0,
8110                                            self.nat_addr,
8111                                            client_in_port,
8112                                            server_out_port,
8113                                            data)
8114         self.pg0.add_stream(pkts)
8115         self.pg_enable_capture(self.pg_interfaces)
8116         self.pg_start()
8117         frags = self.pg0.get_capture(len(pkts))
8118         p = self.reass_frags_and_verify_ip6(frags, nat_addr_ip6, server.ip6)
8119         self.assertNotEqual(p[TCP].sport, client_in_port)
8120         self.assertEqual(p[TCP].dport, server_in_port)
8121         self.assertEqual(data, p[Raw].load)
8122
8123     def test_frag_out_of_order(self):
8124         """ NAT64 translate fragments arriving out of order """
8125         self.tcp_port_in = random.randint(1025, 65535)
8126
8127         self.vapi.nat64_add_del_pool_addr_range(self.nat_addr_n,
8128                                                 self.nat_addr_n)
8129         self.vapi.nat64_add_del_interface(self.pg0.sw_if_index)
8130         self.vapi.nat64_add_del_interface(self.pg1.sw_if_index, is_inside=0)
8131
8132         # in2out
8133         data = b'a' * 200
8134         pkts = self.create_stream_frag_ip6(self.pg0, self.pg1.remote_ip4,
8135                                            self.tcp_port_in, 20, data)
8136         pkts.reverse()
8137         self.pg0.add_stream(pkts)
8138         self.pg_enable_capture(self.pg_interfaces)
8139         self.pg_start()
8140         frags = self.pg1.get_capture(len(pkts))
8141         p = self.reass_frags_and_verify(frags,
8142                                         self.nat_addr,
8143                                         self.pg1.remote_ip4)
8144         self.assertEqual(p[TCP].dport, 20)
8145         self.assertNotEqual(p[TCP].sport, self.tcp_port_in)
8146         self.tcp_port_out = p[TCP].sport
8147         self.assertEqual(data, p[Raw].load)
8148
8149         # out2in
8150         data = b"A" * 4 + b"B" * 16 + b"C" * 3
8151         pkts = self.create_stream_frag(self.pg1,
8152                                        self.nat_addr,
8153                                        20,
8154                                        self.tcp_port_out,
8155                                        data)
8156         pkts.reverse()
8157         self.pg1.add_stream(pkts)
8158         self.pg_enable_capture(self.pg_interfaces)
8159         self.pg_start()
8160         frags = self.pg0.get_capture(len(pkts))
8161         src = self.compose_ip6(self.pg1.remote_ip4, '64:ff9b::', 96)
8162         p = self.reass_frags_and_verify_ip6(frags, src, self.pg0.remote_ip6)
8163         self.assertEqual(p[TCP].sport, 20)
8164         self.assertEqual(p[TCP].dport, self.tcp_port_in)
8165         self.assertEqual(data, p[Raw].load)
8166
8167     def test_interface_addr(self):
8168         """ Acquire NAT64 pool addresses from interface """
8169         self.vapi.nat64_add_del_interface_addr(self.pg4.sw_if_index)
8170
8171         # no address in NAT64 pool
8172         adresses = self.vapi.nat44_address_dump()
8173         self.assertEqual(0, len(adresses))
8174
8175         # configure interface address and check NAT64 address pool
8176         self.pg4.config_ip4()
8177         addresses = self.vapi.nat64_pool_addr_dump()
8178         self.assertEqual(len(addresses), 1)
8179         self.assertEqual(addresses[0].address, self.pg4.local_ip4n)
8180
8181         # remove interface address and check NAT64 address pool
8182         self.pg4.unconfig_ip4()
8183         addresses = self.vapi.nat64_pool_addr_dump()
8184         self.assertEqual(0, len(adresses))
8185
8186     @unittest.skipUnless(running_extended_tests, "part of extended tests")
8187     def test_ipfix_max_bibs_sessions(self):
8188         """ IPFIX logging maximum session and BIB entries exceeded """
8189         max_bibs = 1280
8190         max_sessions = 2560
8191         remote_host_ip6 = self.compose_ip6(self.pg1.remote_ip4,
8192                                            '64:ff9b::',
8193                                            96)
8194
8195         self.vapi.nat64_add_del_pool_addr_range(self.nat_addr_n,
8196                                                 self.nat_addr_n)
8197         self.vapi.nat64_add_del_interface(self.pg0.sw_if_index)
8198         self.vapi.nat64_add_del_interface(self.pg1.sw_if_index, is_inside=0)
8199
8200         pkts = []
8201         src = ""
8202         for i in range(0, max_bibs):
8203             src = "fd01:aa::%x" % (i)
8204             p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
8205                  IPv6(src=src, dst=remote_host_ip6) /
8206                  TCP(sport=12345, dport=80))
8207             pkts.append(p)
8208             p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
8209                  IPv6(src=src, dst=remote_host_ip6) /
8210                  TCP(sport=12345, dport=22))
8211             pkts.append(p)
8212         self.pg0.add_stream(pkts)
8213         self.pg_enable_capture(self.pg_interfaces)
8214         self.pg_start()
8215         self.pg1.get_capture(max_sessions)
8216
8217         self.vapi.set_ipfix_exporter(collector_address=self.pg3.remote_ip4n,
8218                                      src_address=self.pg3.local_ip4n,
8219                                      path_mtu=512,
8220                                      template_interval=10)
8221         self.vapi.nat_ipfix_enable_disable(domain_id=self.ipfix_domain_id,
8222                                            src_port=self.ipfix_src_port)
8223
8224         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
8225              IPv6(src=src, dst=remote_host_ip6) /
8226              TCP(sport=12345, dport=25))
8227         self.pg0.add_stream(p)
8228         self.pg_enable_capture(self.pg_interfaces)
8229         self.pg_start()
8230         self.pg1.assert_nothing_captured()
8231         sleep(1)
8232         self.vapi.cli("ipfix flush")  # FIXME this should be an API call
8233         capture = self.pg3.get_capture(9)
8234         ipfix = IPFIXDecoder()
8235         # first load template
8236         for p in capture:
8237             self.assertTrue(p.haslayer(IPFIX))
8238             self.assertEqual(p[IP].src, self.pg3.local_ip4)
8239             self.assertEqual(p[IP].dst, self.pg3.remote_ip4)
8240             self.assertEqual(p[UDP].sport, self.ipfix_src_port)
8241             self.assertEqual(p[UDP].dport, 4739)
8242             self.assertEqual(p[IPFIX].observationDomainID,
8243                              self.ipfix_domain_id)
8244             if p.haslayer(Template):
8245                 ipfix.add_template(p.getlayer(Template))
8246         # verify events in data set
8247         for p in capture:
8248             if p.haslayer(Data):
8249                 data = ipfix.decode_data_set(p.getlayer(Set))
8250                 self.verify_ipfix_max_sessions(data, max_sessions)
8251
8252         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
8253              IPv6(src=self.pg0.remote_ip6, dst=remote_host_ip6) /
8254              TCP(sport=12345, dport=80))
8255         self.pg0.add_stream(p)
8256         self.pg_enable_capture(self.pg_interfaces)
8257         self.pg_start()
8258         self.pg1.assert_nothing_captured()
8259         sleep(1)
8260         self.vapi.cli("ipfix flush")  # FIXME this should be an API call
8261         capture = self.pg3.get_capture(1)
8262         # verify events in data set
8263         for p in capture:
8264             self.assertTrue(p.haslayer(IPFIX))
8265             self.assertEqual(p[IP].src, self.pg3.local_ip4)
8266             self.assertEqual(p[IP].dst, self.pg3.remote_ip4)
8267             self.assertEqual(p[UDP].sport, self.ipfix_src_port)
8268             self.assertEqual(p[UDP].dport, 4739)
8269             self.assertEqual(p[IPFIX].observationDomainID,
8270                              self.ipfix_domain_id)
8271             if p.haslayer(Data):
8272                 data = ipfix.decode_data_set(p.getlayer(Set))
8273                 self.verify_ipfix_max_bibs(data, max_bibs)
8274
8275     def test_ipfix_max_frags(self):
8276         """ IPFIX logging maximum fragments pending reassembly exceeded """
8277         self.vapi.nat64_add_del_pool_addr_range(self.nat_addr_n,
8278                                                 self.nat_addr_n)
8279         self.vapi.nat64_add_del_interface(self.pg0.sw_if_index)
8280         self.vapi.nat64_add_del_interface(self.pg1.sw_if_index, is_inside=0)
8281         self.vapi.nat_set_reass(max_frag=1, is_ip6=1)
8282         self.vapi.set_ipfix_exporter(collector_address=self.pg3.remote_ip4n,
8283                                      src_address=self.pg3.local_ip4n,
8284                                      path_mtu=512,
8285                                      template_interval=10)
8286         self.vapi.nat_ipfix_enable_disable(domain_id=self.ipfix_domain_id,
8287                                            src_port=self.ipfix_src_port)
8288
8289         data = b'a' * 200
8290         pkts = self.create_stream_frag_ip6(self.pg0, self.pg1.remote_ip4,
8291                                            self.tcp_port_in, 20, data)
8292         pkts.reverse()
8293         self.pg0.add_stream(pkts)
8294         self.pg_enable_capture(self.pg_interfaces)
8295         self.pg_start()
8296         self.pg1.assert_nothing_captured()
8297         sleep(1)
8298         self.vapi.cli("ipfix flush")  # FIXME this should be an API call
8299         capture = self.pg3.get_capture(9)
8300         ipfix = IPFIXDecoder()
8301         # first load template
8302         for p in capture:
8303             self.assertTrue(p.haslayer(IPFIX))
8304             self.assertEqual(p[IP].src, self.pg3.local_ip4)
8305             self.assertEqual(p[IP].dst, self.pg3.remote_ip4)
8306             self.assertEqual(p[UDP].sport, self.ipfix_src_port)
8307             self.assertEqual(p[UDP].dport, 4739)
8308             self.assertEqual(p[IPFIX].observationDomainID,
8309                              self.ipfix_domain_id)
8310             if p.haslayer(Template):
8311                 ipfix.add_template(p.getlayer(Template))
8312         # verify events in data set
8313         for p in capture:
8314             if p.haslayer(Data):
8315                 data = ipfix.decode_data_set(p.getlayer(Set))
8316                 self.verify_ipfix_max_fragments_ip6(data, 1,
8317                                                     self.pg0.remote_ip6n)
8318
8319     def test_ipfix_bib_ses(self):
8320         """ IPFIX logging NAT64 BIB/session create and delete events """
8321         self.tcp_port_in = random.randint(1025, 65535)
8322         remote_host_ip6 = self.compose_ip6(self.pg1.remote_ip4,
8323                                            '64:ff9b::',
8324                                            96)
8325
8326         self.vapi.nat64_add_del_pool_addr_range(self.nat_addr_n,
8327                                                 self.nat_addr_n)
8328         self.vapi.nat64_add_del_interface(self.pg0.sw_if_index)
8329         self.vapi.nat64_add_del_interface(self.pg1.sw_if_index, is_inside=0)
8330         self.vapi.set_ipfix_exporter(collector_address=self.pg3.remote_ip4n,
8331                                      src_address=self.pg3.local_ip4n,
8332                                      path_mtu=512,
8333                                      template_interval=10)
8334         self.vapi.nat_ipfix_enable_disable(domain_id=self.ipfix_domain_id,
8335                                            src_port=self.ipfix_src_port)
8336
8337         # Create
8338         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
8339              IPv6(src=self.pg0.remote_ip6, dst=remote_host_ip6) /
8340              TCP(sport=self.tcp_port_in, dport=25))
8341         self.pg0.add_stream(p)
8342         self.pg_enable_capture(self.pg_interfaces)
8343         self.pg_start()
8344         p = self.pg1.get_capture(1)
8345         self.tcp_port_out = p[0][TCP].sport
8346         self.vapi.cli("ipfix flush")  # FIXME this should be an API call
8347         capture = self.pg3.get_capture(10)
8348         ipfix = IPFIXDecoder()
8349         # first load template
8350         for p in capture:
8351             self.assertTrue(p.haslayer(IPFIX))
8352             self.assertEqual(p[IP].src, self.pg3.local_ip4)
8353             self.assertEqual(p[IP].dst, self.pg3.remote_ip4)
8354             self.assertEqual(p[UDP].sport, self.ipfix_src_port)
8355             self.assertEqual(p[UDP].dport, 4739)
8356             self.assertEqual(p[IPFIX].observationDomainID,
8357                              self.ipfix_domain_id)
8358             if p.haslayer(Template):
8359                 ipfix.add_template(p.getlayer(Template))
8360         # verify events in data set
8361         for p in capture:
8362             if p.haslayer(Data):
8363                 data = ipfix.decode_data_set(p.getlayer(Set))
8364                 if scapy.compat.orb(data[0][230]) == 10:
8365                     self.verify_ipfix_bib(data, 1, self.pg0.remote_ip6n)
8366                 elif scapy.compat.orb(data[0][230]) == 6:
8367                     self.verify_ipfix_nat64_ses(data,
8368                                                 1,
8369                                                 self.pg0.remote_ip6n,
8370                                                 self.pg1.remote_ip4,
8371                                                 25)
8372                 else:
8373                     self.logger.error(ppp("Unexpected or invalid packet: ", p))
8374
8375         # Delete
8376         self.pg_enable_capture(self.pg_interfaces)
8377         self.vapi.nat64_add_del_pool_addr_range(self.nat_addr_n,
8378                                                 self.nat_addr_n,
8379                                                 is_add=0)
8380         self.vapi.cli("ipfix flush")  # FIXME this should be an API call
8381         capture = self.pg3.get_capture(2)
8382         # verify events in data set
8383         for p in capture:
8384             self.assertTrue(p.haslayer(IPFIX))
8385             self.assertEqual(p[IP].src, self.pg3.local_ip4)
8386             self.assertEqual(p[IP].dst, self.pg3.remote_ip4)
8387             self.assertEqual(p[UDP].sport, self.ipfix_src_port)
8388             self.assertEqual(p[UDP].dport, 4739)
8389             self.assertEqual(p[IPFIX].observationDomainID,
8390                              self.ipfix_domain_id)
8391             if p.haslayer(Data):
8392                 data = ipfix.decode_data_set(p.getlayer(Set))
8393                 if scapy.compat.orb(data[0][230]) == 11:
8394                     self.verify_ipfix_bib(data, 0, self.pg0.remote_ip6n)
8395                 elif scapy.compat.orb(data[0][230]) == 7:
8396                     self.verify_ipfix_nat64_ses(data,
8397                                                 0,
8398                                                 self.pg0.remote_ip6n,
8399                                                 self.pg1.remote_ip4,
8400                                                 25)
8401                 else:
8402                     self.logger.error(ppp("Unexpected or invalid packet: ", p))
8403
8404     def test_syslog_sess(self):
8405         """ Test syslog session creation and deletion """
8406         self.tcp_port_in = random.randint(1025, 65535)
8407         remote_host_ip6 = self.compose_ip6(self.pg1.remote_ip4,
8408                                            '64:ff9b::',
8409                                            96)
8410
8411         self.vapi.nat64_add_del_pool_addr_range(self.nat_addr_n,
8412                                                 self.nat_addr_n)
8413         self.vapi.nat64_add_del_interface(self.pg0.sw_if_index)
8414         self.vapi.nat64_add_del_interface(self.pg1.sw_if_index, is_inside=0)
8415         self.vapi.syslog_set_filter(SYSLOG_SEVERITY.INFO)
8416         self.vapi.syslog_set_sender(self.pg3.local_ip4n, self.pg3.remote_ip4n)
8417
8418         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
8419              IPv6(src=self.pg0.remote_ip6, dst=remote_host_ip6) /
8420              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port))
8421         self.pg0.add_stream(p)
8422         self.pg_enable_capture(self.pg_interfaces)
8423         self.pg_start()
8424         p = self.pg1.get_capture(1)
8425         self.tcp_port_out = p[0][TCP].sport
8426         capture = self.pg3.get_capture(1)
8427         self.verify_syslog_sess(capture[0][Raw].load, is_ip6=True)
8428
8429         self.pg_enable_capture(self.pg_interfaces)
8430         self.pg_start()
8431         self.vapi.nat64_add_del_pool_addr_range(self.nat_addr_n,
8432                                                 self.nat_addr_n,
8433                                                 is_add=0)
8434         capture = self.pg3.get_capture(1)
8435         self.verify_syslog_sess(capture[0][Raw].load, False, True)
8436
8437     def nat64_get_ses_num(self):
8438         """
8439         Return number of active NAT64 sessions.
8440         """
8441         st = self.vapi.nat64_st_dump()
8442         return len(st)
8443
8444     def clear_nat64(self):
8445         """
8446         Clear NAT64 configuration.
8447         """
8448         self.vapi.nat_ipfix_enable_disable(enable=0,
8449                                            src_port=self.ipfix_src_port,
8450                                            domain_id=self.ipfix_domain_id)
8451         self.ipfix_src_port = 4739
8452         self.ipfix_domain_id = 1
8453
8454         self.vapi.syslog_set_filter(SYSLOG_SEVERITY.EMERG)
8455
8456         self.vapi.nat_set_timeouts()
8457
8458         interfaces = self.vapi.nat64_interface_dump()
8459         for intf in interfaces:
8460             if intf.is_inside > 1:
8461                 self.vapi.nat64_add_del_interface(intf.sw_if_index,
8462                                                   0,
8463                                                   is_add=0)
8464             self.vapi.nat64_add_del_interface(intf.sw_if_index,
8465                                               intf.is_inside,
8466                                               is_add=0)
8467
8468         bib = self.vapi.nat64_bib_dump(255)
8469         for bibe in bib:
8470             if bibe.is_static:
8471                 self.vapi.nat64_add_del_static_bib(bibe.i_addr,
8472                                                    bibe.o_addr,
8473                                                    bibe.i_port,
8474                                                    bibe.o_port,
8475                                                    bibe.proto,
8476                                                    bibe.vrf_id,
8477                                                    is_add=0)
8478
8479         adresses = self.vapi.nat64_pool_addr_dump()
8480         for addr in adresses:
8481             self.vapi.nat64_add_del_pool_addr_range(addr.address,
8482                                                     addr.address,
8483                                                     vrf_id=addr.vrf_id,
8484                                                     is_add=0)
8485
8486         prefixes = self.vapi.nat64_prefix_dump()
8487         for prefix in prefixes:
8488             self.vapi.nat64_add_del_prefix(prefix.prefix,
8489                                            prefix.prefix_len,
8490                                            vrf_id=prefix.vrf_id,
8491                                            is_add=0)
8492
8493         bibs = self.statistics.get_counter('/nat64/total-bibs')
8494         self.assertEqual(bibs[0][0], 0)
8495         sessions = self.statistics.get_counter('/nat64/total-sessions')
8496         self.assertEqual(sessions[0][0], 0)
8497
8498     def tearDown(self):
8499         super(TestNAT64, self).tearDown()
8500         if not self.vpp_dead:
8501             self.logger.info(self.vapi.cli("show nat64 pool"))
8502             self.logger.info(self.vapi.cli("show nat64 interfaces"))
8503             self.logger.info(self.vapi.cli("show nat64 prefix"))
8504             self.logger.info(self.vapi.cli("show nat64 bib all"))
8505             self.logger.info(self.vapi.cli("show nat64 session table all"))
8506             self.logger.info(self.vapi.cli("show nat virtual-reassembly"))
8507             self.clear_nat64()
8508
8509
8510 class TestDSlite(MethodHolder):
8511     """ DS-Lite Test Cases """
8512
8513     @classmethod
8514     def setUpClass(cls):
8515         super(TestDSlite, cls).setUpClass()
8516
8517         try:
8518             cls.nat_addr = '10.0.0.3'
8519             cls.nat_addr_n = socket.inet_pton(socket.AF_INET, cls.nat_addr)
8520
8521             cls.create_pg_interfaces(range(3))
8522             cls.pg0.admin_up()
8523             cls.pg0.config_ip4()
8524             cls.pg0.resolve_arp()
8525             cls.pg1.admin_up()
8526             cls.pg1.config_ip6()
8527             cls.pg1.generate_remote_hosts(2)
8528             cls.pg1.configure_ipv6_neighbors()
8529             cls.pg2.admin_up()
8530             cls.pg2.config_ip4()
8531             cls.pg2.resolve_arp()
8532
8533         except Exception:
8534             super(TestDSlite, cls).tearDownClass()
8535             raise
8536
8537     def verify_syslog_apmadd(self, data, isaddr, isport, xsaddr, xsport,
8538                              sv6enc, proto):
8539         message = data.decode('utf-8')
8540         try:
8541             message = SyslogMessage.parse(message)
8542         except ParseError as e:
8543             self.logger.error(e)
8544         else:
8545             self.assertEqual(message.severity, SyslogSeverity.info)
8546             self.assertEqual(message.appname, 'NAT')
8547             self.assertEqual(message.msgid, 'APMADD')
8548             sd_params = message.sd.get('napmap')
8549             self.assertTrue(sd_params is not None)
8550             self.assertEqual(sd_params.get('IATYP'), 'IPv4')
8551             self.assertEqual(sd_params.get('ISADDR'), isaddr)
8552             self.assertEqual(sd_params.get('ISPORT'), "%d" % isport)
8553             self.assertEqual(sd_params.get('XATYP'), 'IPv4')
8554             self.assertEqual(sd_params.get('XSADDR'), xsaddr)
8555             self.assertEqual(sd_params.get('XSPORT'), "%d" % xsport)
8556             self.assertEqual(sd_params.get('PROTO'), "%d" % proto)
8557             self.assertTrue(sd_params.get('SSUBIX') is not None)
8558             self.assertEqual(sd_params.get('SV6ENC'), sv6enc)
8559
8560     def test_dslite(self):
8561         """ Test DS-Lite """
8562         nat_config = self.vapi.nat_show_config()
8563         self.assertEqual(0, nat_config.dslite_ce)
8564
8565         self.vapi.dslite_add_del_pool_addr_range(self.nat_addr_n,
8566                                                  self.nat_addr_n)
8567         aftr_ip4 = '192.0.0.1'
8568         aftr_ip4_n = socket.inet_pton(socket.AF_INET, aftr_ip4)
8569         aftr_ip6 = '2001:db8:85a3::8a2e:370:1'
8570         aftr_ip6_n = socket.inet_pton(socket.AF_INET6, aftr_ip6)
8571         self.vapi.dslite_set_aftr_addr(aftr_ip6_n, aftr_ip4_n)
8572         self.vapi.syslog_set_sender(self.pg2.local_ip4n, self.pg2.remote_ip4n)
8573
8574         # UDP
8575         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
8576              IPv6(dst=aftr_ip6, src=self.pg1.remote_hosts[0].ip6) /
8577              IP(dst=self.pg0.remote_ip4, src='192.168.1.1') /
8578              UDP(sport=20000, dport=10000))
8579         self.pg1.add_stream(p)
8580         self.pg_enable_capture(self.pg_interfaces)
8581         self.pg_start()
8582         capture = self.pg0.get_capture(1)
8583         capture = capture[0]
8584         self.assertFalse(capture.haslayer(IPv6))
8585         self.assertEqual(capture[IP].src, self.nat_addr)
8586         self.assertEqual(capture[IP].dst, self.pg0.remote_ip4)
8587         self.assertNotEqual(capture[UDP].sport, 20000)
8588         self.assertEqual(capture[UDP].dport, 10000)
8589         self.assert_packet_checksums_valid(capture)
8590         out_port = capture[UDP].sport
8591         capture = self.pg2.get_capture(1)
8592         self.verify_syslog_apmadd(capture[0][Raw].load, '192.168.1.1',
8593                                   20000, self.nat_addr, out_port,
8594                                   self.pg1.remote_hosts[0].ip6, IP_PROTOS.udp)
8595
8596         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
8597              IP(dst=self.nat_addr, src=self.pg0.remote_ip4) /
8598              UDP(sport=10000, dport=out_port))
8599         self.pg0.add_stream(p)
8600         self.pg_enable_capture(self.pg_interfaces)
8601         self.pg_start()
8602         capture = self.pg1.get_capture(1)
8603         capture = capture[0]
8604         self.assertEqual(capture[IPv6].src, aftr_ip6)
8605         self.assertEqual(capture[IPv6].dst, self.pg1.remote_hosts[0].ip6)
8606         self.assertEqual(capture[IP].src, self.pg0.remote_ip4)
8607         self.assertEqual(capture[IP].dst, '192.168.1.1')
8608         self.assertEqual(capture[UDP].sport, 10000)
8609         self.assertEqual(capture[UDP].dport, 20000)
8610         self.assert_packet_checksums_valid(capture)
8611
8612         # TCP
8613         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
8614              IPv6(dst=aftr_ip6, src=self.pg1.remote_hosts[1].ip6) /
8615              IP(dst=self.pg0.remote_ip4, src='192.168.1.1') /
8616              TCP(sport=20001, dport=10001))
8617         self.pg1.add_stream(p)
8618         self.pg_enable_capture(self.pg_interfaces)
8619         self.pg_start()
8620         capture = self.pg0.get_capture(1)
8621         capture = capture[0]
8622         self.assertFalse(capture.haslayer(IPv6))
8623         self.assertEqual(capture[IP].src, self.nat_addr)
8624         self.assertEqual(capture[IP].dst, self.pg0.remote_ip4)
8625         self.assertNotEqual(capture[TCP].sport, 20001)
8626         self.assertEqual(capture[TCP].dport, 10001)
8627         self.assert_packet_checksums_valid(capture)
8628         out_port = capture[TCP].sport
8629
8630         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
8631              IP(dst=self.nat_addr, src=self.pg0.remote_ip4) /
8632              TCP(sport=10001, dport=out_port))
8633         self.pg0.add_stream(p)
8634         self.pg_enable_capture(self.pg_interfaces)
8635         self.pg_start()
8636         capture = self.pg1.get_capture(1)
8637         capture = capture[0]
8638         self.assertEqual(capture[IPv6].src, aftr_ip6)
8639         self.assertEqual(capture[IPv6].dst, self.pg1.remote_hosts[1].ip6)
8640         self.assertEqual(capture[IP].src, self.pg0.remote_ip4)
8641         self.assertEqual(capture[IP].dst, '192.168.1.1')
8642         self.assertEqual(capture[TCP].sport, 10001)
8643         self.assertEqual(capture[TCP].dport, 20001)
8644         self.assert_packet_checksums_valid(capture)
8645
8646         # ICMP
8647         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
8648              IPv6(dst=aftr_ip6, src=self.pg1.remote_hosts[1].ip6) /
8649              IP(dst=self.pg0.remote_ip4, src='192.168.1.1') /
8650              ICMP(id=4000, type='echo-request'))
8651         self.pg1.add_stream(p)
8652         self.pg_enable_capture(self.pg_interfaces)
8653         self.pg_start()
8654         capture = self.pg0.get_capture(1)
8655         capture = capture[0]
8656         self.assertFalse(capture.haslayer(IPv6))
8657         self.assertEqual(capture[IP].src, self.nat_addr)
8658         self.assertEqual(capture[IP].dst, self.pg0.remote_ip4)
8659         self.assertNotEqual(capture[ICMP].id, 4000)
8660         self.assert_packet_checksums_valid(capture)
8661         out_id = capture[ICMP].id
8662
8663         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
8664              IP(dst=self.nat_addr, src=self.pg0.remote_ip4) /
8665              ICMP(id=out_id, type='echo-reply'))
8666         self.pg0.add_stream(p)
8667         self.pg_enable_capture(self.pg_interfaces)
8668         self.pg_start()
8669         capture = self.pg1.get_capture(1)
8670         capture = capture[0]
8671         self.assertEqual(capture[IPv6].src, aftr_ip6)
8672         self.assertEqual(capture[IPv6].dst, self.pg1.remote_hosts[1].ip6)
8673         self.assertEqual(capture[IP].src, self.pg0.remote_ip4)
8674         self.assertEqual(capture[IP].dst, '192.168.1.1')
8675         self.assertEqual(capture[ICMP].id, 4000)
8676         self.assert_packet_checksums_valid(capture)
8677
8678         # ping DS-Lite AFTR tunnel endpoint address
8679         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
8680              IPv6(src=self.pg1.remote_hosts[1].ip6, dst=aftr_ip6) /
8681              ICMPv6EchoRequest())
8682         self.pg1.add_stream(p)
8683         self.pg_enable_capture(self.pg_interfaces)
8684         self.pg_start()
8685         capture = self.pg1.get_capture(1)
8686         capture = capture[0]
8687         self.assertEqual(capture[IPv6].src, aftr_ip6)
8688         self.assertEqual(capture[IPv6].dst, self.pg1.remote_hosts[1].ip6)
8689         self.assertTrue(capture.haslayer(ICMPv6EchoReply))
8690
8691         b4s = self.statistics.get_counter('/dslite/total-b4s')
8692         self.assertEqual(b4s[0][0], 2)
8693         sessions = self.statistics.get_counter('/dslite/total-sessions')
8694         self.assertEqual(sessions[0][0], 3)
8695
8696     def tearDown(self):
8697         super(TestDSlite, self).tearDown()
8698         if not self.vpp_dead:
8699             self.logger.info(self.vapi.cli("show dslite pool"))
8700             self.logger.info(
8701                 self.vapi.cli("show dslite aftr-tunnel-endpoint-address"))
8702             self.logger.info(self.vapi.cli("show dslite sessions"))
8703
8704
8705 class TestDSliteCE(MethodHolder):
8706     """ DS-Lite CE Test Cases """
8707
8708     @classmethod
8709     def setUpConstants(cls):
8710         super(TestDSliteCE, cls).setUpConstants()
8711         cls.vpp_cmdline.extend(["nat", "{", "dslite ce", "}"])
8712
8713     @classmethod
8714     def setUpClass(cls):
8715         super(TestDSliteCE, cls).setUpClass()
8716
8717         try:
8718             cls.create_pg_interfaces(range(2))
8719             cls.pg0.admin_up()
8720             cls.pg0.config_ip4()
8721             cls.pg0.resolve_arp()
8722             cls.pg1.admin_up()
8723             cls.pg1.config_ip6()
8724             cls.pg1.generate_remote_hosts(1)
8725             cls.pg1.configure_ipv6_neighbors()
8726
8727         except Exception:
8728             super(TestDSliteCE, cls).tearDownClass()
8729             raise
8730
8731     def test_dslite_ce(self):
8732         """ Test DS-Lite CE """
8733
8734         nat_config = self.vapi.nat_show_config()
8735         self.assertEqual(1, nat_config.dslite_ce)
8736
8737         b4_ip4 = '192.0.0.2'
8738         b4_ip4_n = socket.inet_pton(socket.AF_INET, b4_ip4)
8739         b4_ip6 = '2001:db8:62aa::375e:f4c1:1'
8740         b4_ip6_n = socket.inet_pton(socket.AF_INET6, b4_ip6)
8741         self.vapi.dslite_set_b4_addr(b4_ip6_n, b4_ip4_n)
8742
8743         aftr_ip4 = '192.0.0.1'
8744         aftr_ip4_n = socket.inet_pton(socket.AF_INET, aftr_ip4)
8745         aftr_ip6 = '2001:db8:85a3::8a2e:370:1'
8746         aftr_ip6_n = socket.inet_pton(socket.AF_INET6, aftr_ip6)
8747         self.vapi.dslite_set_aftr_addr(aftr_ip6_n, aftr_ip4_n)
8748
8749         self.vapi.ip_add_del_route(dst_address=aftr_ip6_n,
8750                                    dst_address_length=128,
8751                                    next_hop_address=self.pg1.remote_ip6n,
8752                                    next_hop_sw_if_index=self.pg1.sw_if_index,
8753                                    is_ipv6=1)
8754
8755         # UDP encapsulation
8756         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
8757              IP(dst=self.pg1.remote_ip4, src=self.pg0.remote_ip4) /
8758              UDP(sport=10000, dport=20000))
8759         self.pg0.add_stream(p)
8760         self.pg_enable_capture(self.pg_interfaces)
8761         self.pg_start()
8762         capture = self.pg1.get_capture(1)
8763         capture = capture[0]
8764         self.assertEqual(capture[IPv6].src, b4_ip6)
8765         self.assertEqual(capture[IPv6].dst, aftr_ip6)
8766         self.assertEqual(capture[IP].src, self.pg0.remote_ip4)
8767         self.assertEqual(capture[IP].dst, self.pg1.remote_ip4)
8768         self.assertEqual(capture[UDP].sport, 10000)
8769         self.assertEqual(capture[UDP].dport, 20000)
8770         self.assert_packet_checksums_valid(capture)
8771
8772         # UDP decapsulation
8773         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
8774              IPv6(dst=b4_ip6, src=aftr_ip6) /
8775              IP(dst=self.pg0.remote_ip4, src=self.pg1.remote_ip4) /
8776              UDP(sport=20000, dport=10000))
8777         self.pg1.add_stream(p)
8778         self.pg_enable_capture(self.pg_interfaces)
8779         self.pg_start()
8780         capture = self.pg0.get_capture(1)
8781         capture = capture[0]
8782         self.assertFalse(capture.haslayer(IPv6))
8783         self.assertEqual(capture[IP].src, self.pg1.remote_ip4)
8784         self.assertEqual(capture[IP].dst, self.pg0.remote_ip4)
8785         self.assertEqual(capture[UDP].sport, 20000)
8786         self.assertEqual(capture[UDP].dport, 10000)
8787         self.assert_packet_checksums_valid(capture)
8788
8789         # ping DS-Lite B4 tunnel endpoint address
8790         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
8791              IPv6(src=self.pg1.remote_hosts[0].ip6, dst=b4_ip6) /
8792              ICMPv6EchoRequest())
8793         self.pg1.add_stream(p)
8794         self.pg_enable_capture(self.pg_interfaces)
8795         self.pg_start()
8796         capture = self.pg1.get_capture(1)
8797         capture = capture[0]
8798         self.assertEqual(capture[IPv6].src, b4_ip6)
8799         self.assertEqual(capture[IPv6].dst, self.pg1.remote_hosts[0].ip6)
8800         self.assertTrue(capture.haslayer(ICMPv6EchoReply))
8801
8802     def tearDown(self):
8803         super(TestDSliteCE, self).tearDown()
8804         if not self.vpp_dead:
8805             self.logger.info(
8806                 self.vapi.cli("show dslite aftr-tunnel-endpoint-address"))
8807             self.logger.info(
8808                 self.vapi.cli("show dslite b4-tunnel-endpoint-address"))
8809
8810
8811 class TestNAT66(MethodHolder):
8812     """ NAT66 Test Cases """
8813
8814     @classmethod
8815     def setUpClass(cls):
8816         super(TestNAT66, cls).setUpClass()
8817
8818         try:
8819             cls.nat_addr = 'fd01:ff::2'
8820             cls.nat_addr_n = socket.inet_pton(socket.AF_INET6, cls.nat_addr)
8821
8822             cls.create_pg_interfaces(range(2))
8823             cls.interfaces = list(cls.pg_interfaces)
8824
8825             for i in cls.interfaces:
8826                 i.admin_up()
8827                 i.config_ip6()
8828                 i.configure_ipv6_neighbors()
8829
8830         except Exception:
8831             super(TestNAT66, cls).tearDownClass()
8832             raise
8833
8834     def test_static(self):
8835         """ 1:1 NAT66 test """
8836         self.vapi.nat66_add_del_interface(self.pg0.sw_if_index)
8837         self.vapi.nat66_add_del_interface(self.pg1.sw_if_index, is_inside=0)
8838         self.vapi.nat66_add_del_static_mapping(self.pg0.remote_ip6n,
8839                                                self.nat_addr_n)
8840
8841         # in2out
8842         pkts = []
8843         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
8844              IPv6(src=self.pg0.remote_ip6, dst=self.pg1.remote_ip6) /
8845              TCP())
8846         pkts.append(p)
8847         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
8848              IPv6(src=self.pg0.remote_ip6, dst=self.pg1.remote_ip6) /
8849              UDP())
8850         pkts.append(p)
8851         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
8852              IPv6(src=self.pg0.remote_ip6, dst=self.pg1.remote_ip6) /
8853              ICMPv6EchoRequest())
8854         pkts.append(p)
8855         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
8856              IPv6(src=self.pg0.remote_ip6, dst=self.pg1.remote_ip6) /
8857              GRE() / IP() / TCP())
8858         pkts.append(p)
8859         self.pg0.add_stream(pkts)
8860         self.pg_enable_capture(self.pg_interfaces)
8861         self.pg_start()
8862         capture = self.pg1.get_capture(len(pkts))
8863         for packet in capture:
8864             try:
8865                 self.assertEqual(packet[IPv6].src, self.nat_addr)
8866                 self.assertEqual(packet[IPv6].dst, self.pg1.remote_ip6)
8867                 self.assert_packet_checksums_valid(packet)
8868             except:
8869                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
8870                 raise
8871
8872         # out2in
8873         pkts = []
8874         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
8875              IPv6(src=self.pg1.remote_ip6, dst=self.nat_addr) /
8876              TCP())
8877         pkts.append(p)
8878         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
8879              IPv6(src=self.pg1.remote_ip6, dst=self.nat_addr) /
8880              UDP())
8881         pkts.append(p)
8882         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
8883              IPv6(src=self.pg1.remote_ip6, dst=self.nat_addr) /
8884              ICMPv6EchoReply())
8885         pkts.append(p)
8886         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
8887              IPv6(src=self.pg1.remote_ip6, dst=self.nat_addr) /
8888              GRE() / IP() / TCP())
8889         pkts.append(p)
8890         self.pg1.add_stream(pkts)
8891         self.pg_enable_capture(self.pg_interfaces)
8892         self.pg_start()
8893         capture = self.pg0.get_capture(len(pkts))
8894         for packet in capture:
8895             try:
8896                 self.assertEqual(packet[IPv6].src, self.pg1.remote_ip6)
8897                 self.assertEqual(packet[IPv6].dst, self.pg0.remote_ip6)
8898                 self.assert_packet_checksums_valid(packet)
8899             except:
8900                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
8901                 raise
8902
8903         sm = self.vapi.nat66_static_mapping_dump()
8904         self.assertEqual(len(sm), 1)
8905         self.assertEqual(sm[0].total_pkts, 8)
8906
8907     def test_check_no_translate(self):
8908         """ NAT66 translate only when egress interface is outside interface """
8909         self.vapi.nat66_add_del_interface(self.pg0.sw_if_index)
8910         self.vapi.nat66_add_del_interface(self.pg1.sw_if_index)
8911         self.vapi.nat66_add_del_static_mapping(self.pg0.remote_ip6n,
8912                                                self.nat_addr_n)
8913
8914         # in2out
8915         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
8916              IPv6(src=self.pg0.remote_ip6, dst=self.pg1.remote_ip6) /
8917              UDP())
8918         self.pg0.add_stream([p])
8919         self.pg_enable_capture(self.pg_interfaces)
8920         self.pg_start()
8921         capture = self.pg1.get_capture(1)
8922         packet = capture[0]
8923         try:
8924             self.assertEqual(packet[IPv6].src, self.pg0.remote_ip6)
8925             self.assertEqual(packet[IPv6].dst, self.pg1.remote_ip6)
8926         except:
8927             self.logger.error(ppp("Unexpected or invalid packet:", packet))
8928             raise
8929
8930     def clear_nat66(self):
8931         """
8932         Clear NAT66 configuration.
8933         """
8934         interfaces = self.vapi.nat66_interface_dump()
8935         for intf in interfaces:
8936             self.vapi.nat66_add_del_interface(intf.sw_if_index,
8937                                               intf.is_inside,
8938                                               is_add=0)
8939
8940         static_mappings = self.vapi.nat66_static_mapping_dump()
8941         for sm in static_mappings:
8942             self.vapi.nat66_add_del_static_mapping(sm.local_ip_address,
8943                                                    sm.external_ip_address,
8944                                                    sm.vrf_id,
8945                                                    is_add=0)
8946
8947     def tearDown(self):
8948         super(TestNAT66, self).tearDown()
8949         if not self.vpp_dead:
8950             self.logger.info(self.vapi.cli("show nat66 interfaces"))
8951             self.logger.info(self.vapi.cli("show nat66 static mappings"))
8952             self.clear_nat66()
8953
8954
8955 if __name__ == '__main__':
8956     unittest.main(testRunner=VppTestRunner)