7 from framework import VppTestCase, VppTestRunner
8 from scapy.layers.inet import IP, TCP, UDP, ICMP
9 from scapy.layers.inet import IPerror, TCPerror, UDPerror, ICMPerror
10 from scapy.layers.l2 import Ether, ARP
11 from scapy.data import IP_PROTOS
13 from ipfix import IPFIX, Set, Template, Data, IPFIXDecoder
16 class TestSNAT(VppTestCase):
17 """ SNAT Test Cases """
21 super(TestSNAT, cls).setUpClass()
24 cls.tcp_port_in = 6303
25 cls.tcp_port_out = 6303
26 cls.udp_port_in = 6304
27 cls.udp_port_out = 6304
29 cls.icmp_id_out = 6305
30 cls.snat_addr = '10.0.0.3'
32 cls.create_pg_interfaces(range(8))
33 cls.interfaces = list(cls.pg_interfaces[0:4])
35 for i in cls.interfaces:
40 cls.pg0.generate_remote_hosts(2)
41 cls.pg0.configure_ipv4_neighbors()
43 cls.overlapping_interfaces = list(list(cls.pg_interfaces[4:7]))
45 cls.pg4._local_ip4 = "172.16.255.1"
46 cls.pg4._local_ip4n = socket.inet_pton(socket.AF_INET, i.local_ip4)
47 cls.pg4._remote_hosts[0]._ip4 = "172.16.255.2"
48 cls.pg4.set_table_ip4(10)
49 cls.pg5._local_ip4 = "172.16.255.3"
50 cls.pg5._local_ip4n = socket.inet_pton(socket.AF_INET, i.local_ip4)
51 cls.pg5._remote_hosts[0]._ip4 = "172.16.255.4"
52 cls.pg5.set_table_ip4(10)
53 cls.pg6._local_ip4 = "172.16.255.1"
54 cls.pg6._local_ip4n = socket.inet_pton(socket.AF_INET, i.local_ip4)
55 cls.pg6._remote_hosts[0]._ip4 = "172.16.255.2"
56 cls.pg6.set_table_ip4(20)
57 for i in cls.overlapping_interfaces:
65 super(TestSNAT, cls).tearDownClass()
68 def create_stream_in(self, in_if, out_if, ttl=64):
70 Create packet stream for inside network
72 :param in_if: Inside interface
73 :param out_if: Outside interface
74 :param ttl: TTL of generated packets
78 p = (Ether(dst=in_if.local_mac, src=in_if.remote_mac) /
79 IP(src=in_if.remote_ip4, dst=out_if.remote_ip4, ttl=ttl) /
80 TCP(sport=self.tcp_port_in))
84 p = (Ether(dst=in_if.local_mac, src=in_if.remote_mac) /
85 IP(src=in_if.remote_ip4, dst=out_if.remote_ip4, ttl=ttl) /
86 UDP(sport=self.udp_port_in))
90 p = (Ether(dst=in_if.local_mac, src=in_if.remote_mac) /
91 IP(src=in_if.remote_ip4, dst=out_if.remote_ip4, ttl=ttl) /
92 ICMP(id=self.icmp_id_in, type='echo-request'))
97 def create_stream_out(self, out_if, dst_ip=None, ttl=64):
99 Create packet stream for outside network
101 :param out_if: Outside interface
102 :param dst_ip: Destination IP address (Default use global SNAT address)
103 :param ttl: TTL of generated packets
106 dst_ip = self.snat_addr
109 p = (Ether(dst=out_if.local_mac, src=out_if.remote_mac) /
110 IP(src=out_if.remote_ip4, dst=dst_ip, ttl=ttl) /
111 TCP(dport=self.tcp_port_out))
115 p = (Ether(dst=out_if.local_mac, src=out_if.remote_mac) /
116 IP(src=out_if.remote_ip4, dst=dst_ip, ttl=ttl) /
117 UDP(dport=self.udp_port_out))
121 p = (Ether(dst=out_if.local_mac, src=out_if.remote_mac) /
122 IP(src=out_if.remote_ip4, dst=dst_ip, ttl=ttl) /
123 ICMP(id=self.icmp_id_out, type='echo-reply'))
128 def verify_capture_out(self, capture, nat_ip=None, same_port=False,
131 Verify captured packets on outside network
133 :param capture: Captured packets
134 :param nat_ip: Translated IP address (Default use global SNAT address)
135 :param same_port: Sorce port number is not translated (Default False)
136 :param packet_num: Expected number of packets (Default 3)
139 nat_ip = self.snat_addr
140 self.assertEqual(packet_num, len(capture))
141 for packet in capture:
143 self.assertEqual(packet[IP].src, nat_ip)
144 if packet.haslayer(TCP):
146 self.assertEqual(packet[TCP].sport, self.tcp_port_in)
149 packet[TCP].sport, self.tcp_port_in)
150 self.tcp_port_out = packet[TCP].sport
151 elif packet.haslayer(UDP):
153 self.assertEqual(packet[UDP].sport, self.udp_port_in)
156 packet[UDP].sport, self.udp_port_in)
157 self.udp_port_out = packet[UDP].sport
160 self.assertEqual(packet[ICMP].id, self.icmp_id_in)
162 self.assertNotEqual(packet[ICMP].id, self.icmp_id_in)
163 self.icmp_id_out = packet[ICMP].id
165 self.logger.error(ppp("Unexpected or invalid packet "
166 "(outside network):", packet))
169 def verify_capture_in(self, capture, in_if, packet_num=3):
171 Verify captured packets on inside network
173 :param capture: Captured packets
174 :param in_if: Inside interface
175 :param packet_num: Expected number of packets (Default 3)
177 self.assertEqual(packet_num, len(capture))
178 for packet in capture:
180 self.assertEqual(packet[IP].dst, in_if.remote_ip4)
181 if packet.haslayer(TCP):
182 self.assertEqual(packet[TCP].dport, self.tcp_port_in)
183 elif packet.haslayer(UDP):
184 self.assertEqual(packet[UDP].dport, self.udp_port_in)
186 self.assertEqual(packet[ICMP].id, self.icmp_id_in)
188 self.logger.error(ppp("Unexpected or invalid packet "
189 "(inside network):", packet))
192 def verify_capture_no_translation(self, capture, ingress_if, egress_if):
194 Verify captured packet that don't have to be translated
196 :param capture: Captured packets
197 :param ingress_if: Ingress interface
198 :param egress_if: Egress interface
200 for packet in capture:
202 self.assertEqual(packet[IP].src, ingress_if.remote_ip4)
203 self.assertEqual(packet[IP].dst, egress_if.remote_ip4)
204 if packet.haslayer(TCP):
205 self.assertEqual(packet[TCP].sport, self.tcp_port_in)
206 elif packet.haslayer(UDP):
207 self.assertEqual(packet[UDP].sport, self.udp_port_in)
209 self.assertEqual(packet[ICMP].id, self.icmp_id_in)
211 self.logger.error(ppp("Unexpected or invalid packet "
212 "(inside network):", packet))
215 def verify_capture_out_with_icmp_errors(self, capture, src_ip=None,
216 packet_num=3, icmp_type=11):
218 Verify captured packets with ICMP errors on outside network
220 :param capture: Captured packets
221 :param src_ip: Translated IP address or IP address of VPP
222 (Default use global SNAT address)
223 :param packet_num: Expected number of packets (Default 3)
224 :param icmp_type: Type of error ICMP packet
225 we are expecting (Default 11)
228 src_ip = self.snat_addr
229 self.assertEqual(packet_num, len(capture))
230 for packet in capture:
232 self.assertEqual(packet[IP].src, src_ip)
233 self.assertTrue(packet.haslayer(ICMP))
235 self.assertEqual(icmp.type, icmp_type)
236 self.assertTrue(icmp.haslayer(IPerror))
237 inner_ip = icmp[IPerror]
238 if inner_ip.haslayer(TCPerror):
239 self.assertEqual(inner_ip[TCPerror].dport,
241 elif inner_ip.haslayer(UDPerror):
242 self.assertEqual(inner_ip[UDPerror].dport,
245 self.assertEqual(inner_ip[ICMPerror].id, self.icmp_id_out)
247 self.logger.error(ppp("Unexpected or invalid packet "
248 "(outside network):", packet))
251 def verify_capture_in_with_icmp_errors(self, capture, in_if, packet_num=3,
254 Verify captured packets with ICMP errors on inside network
256 :param capture: Captured packets
257 :param in_if: Inside interface
258 :param packet_num: Expected number of packets (Default 3)
259 :param icmp_type: Type of error ICMP packet
260 we are expecting (Default 11)
262 self.assertEqual(packet_num, len(capture))
263 for packet in capture:
265 self.assertEqual(packet[IP].dst, in_if.remote_ip4)
266 self.assertTrue(packet.haslayer(ICMP))
268 self.assertEqual(icmp.type, icmp_type)
269 self.assertTrue(icmp.haslayer(IPerror))
270 inner_ip = icmp[IPerror]
271 if inner_ip.haslayer(TCPerror):
272 self.assertEqual(inner_ip[TCPerror].sport,
274 elif inner_ip.haslayer(UDPerror):
275 self.assertEqual(inner_ip[UDPerror].sport,
278 self.assertEqual(inner_ip[ICMPerror].id, self.icmp_id_in)
280 self.logger.error(ppp("Unexpected or invalid packet "
281 "(inside network):", packet))
284 def verify_ipfix_nat44_ses(self, data):
286 Verify IPFIX NAT44 session create/delete event
288 :param data: Decoded IPFIX data records
290 nat44_ses_create_num = 0
291 nat44_ses_delete_num = 0
292 self.assertEqual(6, len(data))
295 self.assertIn(ord(record[230]), [4, 5])
296 if ord(record[230]) == 4:
297 nat44_ses_create_num += 1
299 nat44_ses_delete_num += 1
301 self.assertEqual(self.pg0.remote_ip4n, record[8])
302 # postNATSourceIPv4Address
303 self.assertEqual(socket.inet_pton(socket.AF_INET, self.snat_addr),
306 self.assertEqual(struct.pack("!I", 0), record[234])
307 # protocolIdentifier/sourceTransportPort/postNAPTSourceTransportPort
308 if IP_PROTOS.icmp == ord(record[4]):
309 self.assertEqual(struct.pack("!H", self.icmp_id_in), record[7])
310 self.assertEqual(struct.pack("!H", self.icmp_id_out),
312 elif IP_PROTOS.tcp == ord(record[4]):
313 self.assertEqual(struct.pack("!H", self.tcp_port_in),
315 self.assertEqual(struct.pack("!H", self.tcp_port_out),
317 elif IP_PROTOS.udp == ord(record[4]):
318 self.assertEqual(struct.pack("!H", self.udp_port_in),
320 self.assertEqual(struct.pack("!H", self.udp_port_out),
323 self.fail("Invalid protocol")
324 self.assertEqual(3, nat44_ses_create_num)
325 self.assertEqual(3, nat44_ses_delete_num)
327 def verify_ipfix_addr_exhausted(self, data):
329 Verify IPFIX NAT addresses event
331 :param data: Decoded IPFIX data records
333 self.assertEqual(1, len(data))
336 self.assertEqual(ord(record[230]), 3)
338 self.assertEqual(struct.pack("!I", 0), record[283])
340 def clear_snat(self):
342 Clear SNAT configuration.
344 if self.pg7.has_ip4_config:
345 self.pg7.unconfig_ip4()
347 interfaces = self.vapi.snat_interface_addr_dump()
348 for intf in interfaces:
349 self.vapi.snat_add_interface_addr(intf.sw_if_index, is_add=0)
351 self.vapi.snat_ipfix(enable=0)
353 interfaces = self.vapi.snat_interface_dump()
354 for intf in interfaces:
355 self.vapi.snat_interface_add_del_feature(intf.sw_if_index,
359 static_mappings = self.vapi.snat_static_mapping_dump()
360 for sm in static_mappings:
361 self.vapi.snat_add_static_mapping(sm.local_ip_address,
362 sm.external_ip_address,
363 local_port=sm.local_port,
364 external_port=sm.external_port,
365 addr_only=sm.addr_only,
367 protocol=sm.protocol,
370 adresses = self.vapi.snat_address_dump()
371 for addr in adresses:
372 self.vapi.snat_add_address_range(addr.ip_address,
376 def snat_add_static_mapping(self, local_ip, external_ip='0.0.0.0',
377 local_port=0, external_port=0, vrf_id=0,
378 is_add=1, external_sw_if_index=0xFFFFFFFF,
381 Add/delete S-NAT static mapping
383 :param local_ip: Local IP address
384 :param external_ip: External IP address
385 :param local_port: Local port number (Optional)
386 :param external_port: External port number (Optional)
387 :param vrf_id: VRF ID (Default 0)
388 :param is_add: 1 if add, 0 if delete (Default add)
389 :param external_sw_if_index: External interface instead of IP address
390 :param proto: IP protocol (Mandatory if port specified)
393 if local_port and external_port:
395 l_ip = socket.inet_pton(socket.AF_INET, local_ip)
396 e_ip = socket.inet_pton(socket.AF_INET, external_ip)
397 self.vapi.snat_add_static_mapping(
400 external_sw_if_index,
408 def snat_add_address(self, ip, is_add=1):
410 Add/delete S-NAT address
412 :param ip: IP address
413 :param is_add: 1 if add, 0 if delete (Default add)
415 snat_addr = socket.inet_pton(socket.AF_INET, ip)
416 self.vapi.snat_add_address_range(snat_addr, snat_addr, is_add)
418 def test_dynamic(self):
419 """ SNAT dynamic translation test """
421 self.snat_add_address(self.snat_addr)
422 self.vapi.snat_interface_add_del_feature(self.pg0.sw_if_index)
423 self.vapi.snat_interface_add_del_feature(self.pg1.sw_if_index,
427 pkts = self.create_stream_in(self.pg0, self.pg1)
428 self.pg0.add_stream(pkts)
429 self.pg_enable_capture(self.pg_interfaces)
431 capture = self.pg1.get_capture(len(pkts))
432 self.verify_capture_out(capture)
435 pkts = self.create_stream_out(self.pg1)
436 self.pg1.add_stream(pkts)
437 self.pg_enable_capture(self.pg_interfaces)
439 capture = self.pg0.get_capture(len(pkts))
440 self.verify_capture_in(capture, self.pg0)
442 def test_dynamic_icmp_errors_in2out_ttl_1(self):
443 """ SNAT handling of client packets with TTL=1 """
445 self.snat_add_address(self.snat_addr)
446 self.vapi.snat_interface_add_del_feature(self.pg0.sw_if_index)
447 self.vapi.snat_interface_add_del_feature(self.pg1.sw_if_index,
450 # Client side - generate traffic
451 pkts = self.create_stream_in(self.pg0, self.pg1, ttl=1)
452 self.pg0.add_stream(pkts)
453 self.pg_enable_capture(self.pg_interfaces)
456 # Client side - verify ICMP type 11 packets
457 capture = self.pg0.get_capture(len(pkts))
458 self.verify_capture_in_with_icmp_errors(capture, self.pg0)
460 def test_dynamic_icmp_errors_out2in_ttl_1(self):
461 """ SNAT handling of server packets with TTL=1 """
463 self.snat_add_address(self.snat_addr)
464 self.vapi.snat_interface_add_del_feature(self.pg0.sw_if_index)
465 self.vapi.snat_interface_add_del_feature(self.pg1.sw_if_index,
468 # Client side - create sessions
469 pkts = self.create_stream_in(self.pg0, self.pg1)
470 self.pg0.add_stream(pkts)
471 self.pg_enable_capture(self.pg_interfaces)
474 # Server side - generate traffic
475 capture = self.pg1.get_capture(len(pkts))
476 self.verify_capture_out(capture)
477 pkts = self.create_stream_out(self.pg1, ttl=1)
478 self.pg1.add_stream(pkts)
479 self.pg_enable_capture(self.pg_interfaces)
482 # Server side - verify ICMP type 11 packets
483 capture = self.pg1.get_capture(len(pkts))
484 self.verify_capture_out_with_icmp_errors(capture,
485 src_ip=self.pg1.local_ip4)
487 def test_dynamic_icmp_errors_in2out_ttl_2(self):
488 """ SNAT handling of error respones to client packets with TTL=2 """
490 self.snat_add_address(self.snat_addr)
491 self.vapi.snat_interface_add_del_feature(self.pg0.sw_if_index)
492 self.vapi.snat_interface_add_del_feature(self.pg1.sw_if_index,
495 # Client side - generate traffic
496 pkts = self.create_stream_in(self.pg0, self.pg1, ttl=2)
497 self.pg0.add_stream(pkts)
498 self.pg_enable_capture(self.pg_interfaces)
501 # Server side - simulate ICMP type 11 response
502 capture = self.pg1.get_capture(len(pkts))
503 pkts = [Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
504 IP(src=self.pg1.remote_ip4, dst=self.snat_addr) /
505 ICMP(type=11) / packet[IP] for packet in capture]
506 self.pg1.add_stream(pkts)
507 self.pg_enable_capture(self.pg_interfaces)
510 # Client side - verify ICMP type 11 packets
511 capture = self.pg0.get_capture(len(pkts))
512 self.verify_capture_in_with_icmp_errors(capture, self.pg0)
514 def test_dynamic_icmp_errors_out2in_ttl_2(self):
515 """ SNAT handling of error respones to server packets with TTL=2 """
517 self.snat_add_address(self.snat_addr)
518 self.vapi.snat_interface_add_del_feature(self.pg0.sw_if_index)
519 self.vapi.snat_interface_add_del_feature(self.pg1.sw_if_index,
522 # Client side - create sessions
523 pkts = self.create_stream_in(self.pg0, self.pg1)
524 self.pg0.add_stream(pkts)
525 self.pg_enable_capture(self.pg_interfaces)
528 # Server side - generate traffic
529 capture = self.pg1.get_capture(len(pkts))
530 self.verify_capture_out(capture)
531 pkts = self.create_stream_out(self.pg1, ttl=2)
532 self.pg1.add_stream(pkts)
533 self.pg_enable_capture(self.pg_interfaces)
536 # Client side - simulate ICMP type 11 response
537 capture = self.pg0.get_capture(len(pkts))
538 pkts = [Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
539 IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
540 ICMP(type=11) / packet[IP] for packet in capture]
541 self.pg0.add_stream(pkts)
542 self.pg_enable_capture(self.pg_interfaces)
545 # Server side - verify ICMP type 11 packets
546 capture = self.pg1.get_capture(len(pkts))
547 self.verify_capture_out_with_icmp_errors(capture)
549 def test_static_in(self):
550 """ SNAT 1:1 NAT initialized from inside network """
553 self.tcp_port_out = 6303
554 self.udp_port_out = 6304
555 self.icmp_id_out = 6305
557 self.snat_add_static_mapping(self.pg0.remote_ip4, nat_ip)
558 self.vapi.snat_interface_add_del_feature(self.pg0.sw_if_index)
559 self.vapi.snat_interface_add_del_feature(self.pg1.sw_if_index,
563 pkts = self.create_stream_in(self.pg0, self.pg1)
564 self.pg0.add_stream(pkts)
565 self.pg_enable_capture(self.pg_interfaces)
567 capture = self.pg1.get_capture(len(pkts))
568 self.verify_capture_out(capture, nat_ip, True)
571 pkts = self.create_stream_out(self.pg1, nat_ip)
572 self.pg1.add_stream(pkts)
573 self.pg_enable_capture(self.pg_interfaces)
575 capture = self.pg0.get_capture(len(pkts))
576 self.verify_capture_in(capture, self.pg0)
578 def test_static_out(self):
579 """ SNAT 1:1 NAT initialized from outside network """
582 self.tcp_port_out = 6303
583 self.udp_port_out = 6304
584 self.icmp_id_out = 6305
586 self.snat_add_static_mapping(self.pg0.remote_ip4, nat_ip)
587 self.vapi.snat_interface_add_del_feature(self.pg0.sw_if_index)
588 self.vapi.snat_interface_add_del_feature(self.pg1.sw_if_index,
592 pkts = self.create_stream_out(self.pg1, nat_ip)
593 self.pg1.add_stream(pkts)
594 self.pg_enable_capture(self.pg_interfaces)
596 capture = self.pg0.get_capture(len(pkts))
597 self.verify_capture_in(capture, self.pg0)
600 pkts = self.create_stream_in(self.pg0, self.pg1)
601 self.pg0.add_stream(pkts)
602 self.pg_enable_capture(self.pg_interfaces)
604 capture = self.pg1.get_capture(len(pkts))
605 self.verify_capture_out(capture, nat_ip, True)
607 def test_static_with_port_in(self):
608 """ SNAT 1:1 NAT with port initialized from inside network """
610 self.tcp_port_out = 3606
611 self.udp_port_out = 3607
612 self.icmp_id_out = 3608
614 self.snat_add_address(self.snat_addr)
615 self.snat_add_static_mapping(self.pg0.remote_ip4, self.snat_addr,
616 self.tcp_port_in, self.tcp_port_out,
618 self.snat_add_static_mapping(self.pg0.remote_ip4, self.snat_addr,
619 self.udp_port_in, self.udp_port_out,
621 self.snat_add_static_mapping(self.pg0.remote_ip4, self.snat_addr,
622 self.icmp_id_in, self.icmp_id_out,
623 proto=IP_PROTOS.icmp)
624 self.vapi.snat_interface_add_del_feature(self.pg0.sw_if_index)
625 self.vapi.snat_interface_add_del_feature(self.pg1.sw_if_index,
629 pkts = self.create_stream_in(self.pg0, self.pg1)
630 self.pg0.add_stream(pkts)
631 self.pg_enable_capture(self.pg_interfaces)
633 capture = self.pg1.get_capture(len(pkts))
634 self.verify_capture_out(capture)
637 pkts = self.create_stream_out(self.pg1)
638 self.pg1.add_stream(pkts)
639 self.pg_enable_capture(self.pg_interfaces)
641 capture = self.pg0.get_capture(len(pkts))
642 self.verify_capture_in(capture, self.pg0)
644 def test_static_with_port_out(self):
645 """ SNAT 1:1 NAT with port initialized from outside network """
647 self.tcp_port_out = 30606
648 self.udp_port_out = 30607
649 self.icmp_id_out = 30608
651 self.snat_add_address(self.snat_addr)
652 self.snat_add_static_mapping(self.pg0.remote_ip4, self.snat_addr,
653 self.tcp_port_in, self.tcp_port_out,
655 self.snat_add_static_mapping(self.pg0.remote_ip4, self.snat_addr,
656 self.udp_port_in, self.udp_port_out,
658 self.snat_add_static_mapping(self.pg0.remote_ip4, self.snat_addr,
659 self.icmp_id_in, self.icmp_id_out,
660 proto=IP_PROTOS.icmp)
661 self.vapi.snat_interface_add_del_feature(self.pg0.sw_if_index)
662 self.vapi.snat_interface_add_del_feature(self.pg1.sw_if_index,
666 pkts = self.create_stream_out(self.pg1)
667 self.pg1.add_stream(pkts)
668 self.pg_enable_capture(self.pg_interfaces)
670 capture = self.pg0.get_capture(len(pkts))
671 self.verify_capture_in(capture, self.pg0)
674 pkts = self.create_stream_in(self.pg0, self.pg1)
675 self.pg0.add_stream(pkts)
676 self.pg_enable_capture(self.pg_interfaces)
678 capture = self.pg1.get_capture(len(pkts))
679 self.verify_capture_out(capture)
681 def test_static_vrf_aware(self):
682 """ SNAT 1:1 NAT VRF awareness """
684 nat_ip1 = "10.0.0.30"
685 nat_ip2 = "10.0.0.40"
686 self.tcp_port_out = 6303
687 self.udp_port_out = 6304
688 self.icmp_id_out = 6305
690 self.snat_add_static_mapping(self.pg4.remote_ip4, nat_ip1,
692 self.snat_add_static_mapping(self.pg0.remote_ip4, nat_ip2,
694 self.vapi.snat_interface_add_del_feature(self.pg3.sw_if_index,
696 self.vapi.snat_interface_add_del_feature(self.pg0.sw_if_index)
697 self.vapi.snat_interface_add_del_feature(self.pg4.sw_if_index)
699 # inside interface VRF match SNAT static mapping VRF
700 pkts = self.create_stream_in(self.pg4, self.pg3)
701 self.pg4.add_stream(pkts)
702 self.pg_enable_capture(self.pg_interfaces)
704 capture = self.pg3.get_capture(len(pkts))
705 self.verify_capture_out(capture, nat_ip1, True)
707 # inside interface VRF don't match SNAT static mapping VRF (packets
709 pkts = self.create_stream_in(self.pg0, self.pg3)
710 self.pg0.add_stream(pkts)
711 self.pg_enable_capture(self.pg_interfaces)
713 self.pg3.assert_nothing_captured()
715 def test_multiple_inside_interfaces(self):
716 """ SNAT multiple inside interfaces (non-overlapping address space) """
718 self.snat_add_address(self.snat_addr)
719 self.vapi.snat_interface_add_del_feature(self.pg0.sw_if_index)
720 self.vapi.snat_interface_add_del_feature(self.pg1.sw_if_index)
721 self.vapi.snat_interface_add_del_feature(self.pg3.sw_if_index,
724 # between two S-NAT inside interfaces (no translation)
725 pkts = self.create_stream_in(self.pg0, self.pg1)
726 self.pg0.add_stream(pkts)
727 self.pg_enable_capture(self.pg_interfaces)
729 capture = self.pg1.get_capture(len(pkts))
730 self.verify_capture_no_translation(capture, self.pg0, self.pg1)
732 # from S-NAT inside to interface without S-NAT feature (no translation)
733 pkts = self.create_stream_in(self.pg0, self.pg2)
734 self.pg0.add_stream(pkts)
735 self.pg_enable_capture(self.pg_interfaces)
737 capture = self.pg2.get_capture(len(pkts))
738 self.verify_capture_no_translation(capture, self.pg0, self.pg2)
740 # in2out 1st interface
741 pkts = self.create_stream_in(self.pg0, self.pg3)
742 self.pg0.add_stream(pkts)
743 self.pg_enable_capture(self.pg_interfaces)
745 capture = self.pg3.get_capture(len(pkts))
746 self.verify_capture_out(capture)
748 # out2in 1st interface
749 pkts = self.create_stream_out(self.pg3)
750 self.pg3.add_stream(pkts)
751 self.pg_enable_capture(self.pg_interfaces)
753 capture = self.pg0.get_capture(len(pkts))
754 self.verify_capture_in(capture, self.pg0)
756 # in2out 2nd interface
757 pkts = self.create_stream_in(self.pg1, self.pg3)
758 self.pg1.add_stream(pkts)
759 self.pg_enable_capture(self.pg_interfaces)
761 capture = self.pg3.get_capture(len(pkts))
762 self.verify_capture_out(capture)
764 # out2in 2nd interface
765 pkts = self.create_stream_out(self.pg3)
766 self.pg3.add_stream(pkts)
767 self.pg_enable_capture(self.pg_interfaces)
769 capture = self.pg1.get_capture(len(pkts))
770 self.verify_capture_in(capture, self.pg1)
772 def test_inside_overlapping_interfaces(self):
773 """ SNAT multiple inside interfaces with overlapping address space """
775 static_nat_ip = "10.0.0.10"
776 self.snat_add_address(self.snat_addr)
777 self.vapi.snat_interface_add_del_feature(self.pg3.sw_if_index,
779 self.vapi.snat_interface_add_del_feature(self.pg4.sw_if_index)
780 self.vapi.snat_interface_add_del_feature(self.pg5.sw_if_index)
781 self.vapi.snat_interface_add_del_feature(self.pg6.sw_if_index)
782 self.snat_add_static_mapping(self.pg6.remote_ip4, static_nat_ip,
785 # between S-NAT inside interfaces with same VRF (no translation)
786 pkts = self.create_stream_in(self.pg4, self.pg5)
787 self.pg4.add_stream(pkts)
788 self.pg_enable_capture(self.pg_interfaces)
790 capture = self.pg5.get_capture(len(pkts))
791 self.verify_capture_no_translation(capture, self.pg4, self.pg5)
793 # between S-NAT inside interfaces with different VRF (hairpinning)
794 p = (Ether(src=self.pg4.remote_mac, dst=self.pg4.local_mac) /
795 IP(src=self.pg4.remote_ip4, dst=static_nat_ip) /
796 TCP(sport=1234, dport=5678))
797 self.pg4.add_stream(p)
798 self.pg_enable_capture(self.pg_interfaces)
800 capture = self.pg6.get_capture(1)
805 self.assertEqual(ip.src, self.snat_addr)
806 self.assertEqual(ip.dst, self.pg6.remote_ip4)
807 self.assertNotEqual(tcp.sport, 1234)
808 self.assertEqual(tcp.dport, 5678)
810 self.logger.error(ppp("Unexpected or invalid packet:", p))
813 # in2out 1st interface
814 pkts = self.create_stream_in(self.pg4, self.pg3)
815 self.pg4.add_stream(pkts)
816 self.pg_enable_capture(self.pg_interfaces)
818 capture = self.pg3.get_capture(len(pkts))
819 self.verify_capture_out(capture)
821 # out2in 1st interface
822 pkts = self.create_stream_out(self.pg3)
823 self.pg3.add_stream(pkts)
824 self.pg_enable_capture(self.pg_interfaces)
826 capture = self.pg4.get_capture(len(pkts))
827 self.verify_capture_in(capture, self.pg4)
829 # in2out 2nd interface
830 pkts = self.create_stream_in(self.pg5, self.pg3)
831 self.pg5.add_stream(pkts)
832 self.pg_enable_capture(self.pg_interfaces)
834 capture = self.pg3.get_capture(len(pkts))
835 self.verify_capture_out(capture)
837 # out2in 2nd interface
838 pkts = self.create_stream_out(self.pg3)
839 self.pg3.add_stream(pkts)
840 self.pg_enable_capture(self.pg_interfaces)
842 capture = self.pg5.get_capture(len(pkts))
843 self.verify_capture_in(capture, self.pg5)
845 # in2out 3rd interface
846 pkts = self.create_stream_in(self.pg6, self.pg3)
847 self.pg6.add_stream(pkts)
848 self.pg_enable_capture(self.pg_interfaces)
850 capture = self.pg3.get_capture(len(pkts))
851 self.verify_capture_out(capture, static_nat_ip, True)
853 # out2in 3rd interface
854 pkts = self.create_stream_out(self.pg3, static_nat_ip)
855 self.pg3.add_stream(pkts)
856 self.pg_enable_capture(self.pg_interfaces)
858 capture = self.pg6.get_capture(len(pkts))
859 self.verify_capture_in(capture, self.pg6)
861 def test_hairpinning(self):
862 """ SNAT hairpinning """
864 host = self.pg0.remote_hosts[0]
865 server = self.pg0.remote_hosts[1]
868 server_in_port = 5678
869 server_out_port = 8765
871 self.snat_add_address(self.snat_addr)
872 self.vapi.snat_interface_add_del_feature(self.pg0.sw_if_index)
873 self.vapi.snat_interface_add_del_feature(self.pg1.sw_if_index,
875 # add static mapping for server
876 self.snat_add_static_mapping(server.ip4, self.snat_addr,
877 server_in_port, server_out_port,
880 # send packet from host to server
881 p = (Ether(src=host.mac, dst=self.pg0.local_mac) /
882 IP(src=host.ip4, dst=self.snat_addr) /
883 TCP(sport=host_in_port, dport=server_out_port))
884 self.pg0.add_stream(p)
885 self.pg_enable_capture(self.pg_interfaces)
887 capture = self.pg0.get_capture(1)
892 self.assertEqual(ip.src, self.snat_addr)
893 self.assertEqual(ip.dst, server.ip4)
894 self.assertNotEqual(tcp.sport, host_in_port)
895 self.assertEqual(tcp.dport, server_in_port)
896 host_out_port = tcp.sport
898 self.logger.error(ppp("Unexpected or invalid packet:", p))
901 # send reply from server to host
902 p = (Ether(src=server.mac, dst=self.pg0.local_mac) /
903 IP(src=server.ip4, dst=self.snat_addr) /
904 TCP(sport=server_in_port, dport=host_out_port))
905 self.pg0.add_stream(p)
906 self.pg_enable_capture(self.pg_interfaces)
908 capture = self.pg0.get_capture(1)
913 self.assertEqual(ip.src, self.snat_addr)
914 self.assertEqual(ip.dst, host.ip4)
915 self.assertEqual(tcp.sport, server_out_port)
916 self.assertEqual(tcp.dport, host_in_port)
918 self.logger.error(ppp("Unexpected or invalid packet:"), p)
921 def test_max_translations_per_user(self):
922 """ MAX translations per user - recycle the least recently used """
924 self.snat_add_address(self.snat_addr)
925 self.vapi.snat_interface_add_del_feature(self.pg0.sw_if_index)
926 self.vapi.snat_interface_add_del_feature(self.pg1.sw_if_index,
929 # get maximum number of translations per user
930 snat_config = self.vapi.snat_show_config()
932 # send more than maximum number of translations per user packets
933 pkts_num = snat_config.max_translations_per_user + 5
935 for port in range(0, pkts_num):
936 p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
937 IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
938 TCP(sport=1025 + port))
940 self.pg0.add_stream(pkts)
941 self.pg_enable_capture(self.pg_interfaces)
944 # verify number of translated packet
945 self.pg1.get_capture(pkts_num)
947 def test_interface_addr(self):
948 """ Acquire SNAT addresses from interface """
949 self.vapi.snat_add_interface_addr(self.pg7.sw_if_index)
951 # no address in NAT pool
952 adresses = self.vapi.snat_address_dump()
953 self.assertEqual(0, len(adresses))
955 # configure interface address and check NAT address pool
956 self.pg7.config_ip4()
957 adresses = self.vapi.snat_address_dump()
958 self.assertEqual(1, len(adresses))
959 self.assertEqual(adresses[0].ip_address[0:4], self.pg7.local_ip4n)
961 # remove interface address and check NAT address pool
962 self.pg7.unconfig_ip4()
963 adresses = self.vapi.snat_address_dump()
964 self.assertEqual(0, len(adresses))
966 def test_interface_addr_static_mapping(self):
967 """ Static mapping with addresses from interface """
968 self.vapi.snat_add_interface_addr(self.pg7.sw_if_index)
969 self.snat_add_static_mapping('1.2.3.4',
970 external_sw_if_index=self.pg7.sw_if_index)
972 # static mappings with external interface
973 static_mappings = self.vapi.snat_static_mapping_dump()
974 self.assertEqual(1, len(static_mappings))
975 self.assertEqual(self.pg7.sw_if_index,
976 static_mappings[0].external_sw_if_index)
978 # configure interface address and check static mappings
979 self.pg7.config_ip4()
980 static_mappings = self.vapi.snat_static_mapping_dump()
981 self.assertEqual(1, len(static_mappings))
982 self.assertEqual(static_mappings[0].external_ip_address[0:4],
984 self.assertEqual(0xFFFFFFFF, static_mappings[0].external_sw_if_index)
986 # remove interface address and check static mappings
987 self.pg7.unconfig_ip4()
988 static_mappings = self.vapi.snat_static_mapping_dump()
989 self.assertEqual(0, len(static_mappings))
991 def test_ipfix_nat44_sess(self):
992 """ S-NAT IPFIX logging NAT44 session created/delted """
993 self.snat_add_address(self.snat_addr)
994 self.vapi.snat_interface_add_del_feature(self.pg0.sw_if_index)
995 self.vapi.snat_interface_add_del_feature(self.pg1.sw_if_index,
997 self.vapi.set_ipfix_exporter(collector_address=self.pg3.remote_ip4n,
998 src_address=self.pg3.local_ip4n,
1000 template_interval=10)
1001 self.vapi.snat_ipfix()
1003 pkts = self.create_stream_in(self.pg0, self.pg1)
1004 self.pg0.add_stream(pkts)
1005 self.pg_enable_capture(self.pg_interfaces)
1007 capture = self.pg1.get_capture(len(pkts))
1008 self.verify_capture_out(capture)
1009 self.snat_add_address(self.snat_addr, is_add=0)
1010 self.vapi.cli("ipfix flush") # FIXME this should be an API call
1011 capture = self.pg3.get_capture(3)
1012 ipfix = IPFIXDecoder()
1013 # first load template
1015 self.assertTrue(p.haslayer(IPFIX))
1016 if p.haslayer(Template):
1017 ipfix.add_template(p.getlayer(Template))
1018 # verify events in data set
1020 if p.haslayer(Data):
1021 data = ipfix.decode_data_set(p.getlayer(Set))
1022 self.verify_ipfix_nat44_ses(data)
1024 def test_ipfix_addr_exhausted(self):
1025 """ S-NAT IPFIX logging NAT addresses exhausted """
1026 self.vapi.snat_interface_add_del_feature(self.pg0.sw_if_index)
1027 self.vapi.snat_interface_add_del_feature(self.pg1.sw_if_index,
1029 self.vapi.set_ipfix_exporter(collector_address=self.pg3.remote_ip4n,
1030 src_address=self.pg3.local_ip4n,
1032 template_interval=10)
1033 self.vapi.snat_ipfix()
1035 p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
1036 IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
1038 self.pg0.add_stream(p)
1039 self.pg_enable_capture(self.pg_interfaces)
1041 capture = self.pg1.get_capture(0)
1042 self.vapi.cli("ipfix flush") # FIXME this should be an API call
1043 capture = self.pg3.get_capture(3)
1044 ipfix = IPFIXDecoder()
1045 # first load template
1047 self.assertTrue(p.haslayer(IPFIX))
1048 if p.haslayer(Template):
1049 ipfix.add_template(p.getlayer(Template))
1050 # verify events in data set
1052 if p.haslayer(Data):
1053 data = ipfix.decode_data_set(p.getlayer(Set))
1054 self.verify_ipfix_addr_exhausted(data)
1056 def test_pool_addr_fib(self):
1057 """ S-NAT add pool addresses to FIB """
1058 static_addr = '10.0.0.10'
1059 self.snat_add_address(self.snat_addr)
1060 self.vapi.snat_interface_add_del_feature(self.pg0.sw_if_index)
1061 self.vapi.snat_interface_add_del_feature(self.pg1.sw_if_index,
1063 self.snat_add_static_mapping(self.pg0.remote_ip4, static_addr)
1066 p = (Ether(src=self.pg1.remote_mac, dst='ff:ff:ff:ff:ff:ff') /
1067 ARP(op=ARP.who_has, pdst=self.snat_addr,
1068 psrc=self.pg1.remote_ip4, hwsrc=self.pg1.remote_mac))
1069 self.pg1.add_stream(p)
1070 self.pg_enable_capture(self.pg_interfaces)
1072 capture = self.pg1.get_capture(1)
1073 self.assertTrue(capture[0].haslayer(ARP))
1074 self.assertTrue(capture[0][ARP].op, ARP.is_at)
1077 p = (Ether(src=self.pg1.remote_mac, dst='ff:ff:ff:ff:ff:ff') /
1078 ARP(op=ARP.who_has, pdst=static_addr,
1079 psrc=self.pg1.remote_ip4, hwsrc=self.pg1.remote_mac))
1080 self.pg1.add_stream(p)
1081 self.pg_enable_capture(self.pg_interfaces)
1083 capture = self.pg1.get_capture(1)
1084 self.assertTrue(capture[0].haslayer(ARP))
1085 self.assertTrue(capture[0][ARP].op, ARP.is_at)
1087 # send ARP to non-SNAT interface
1088 p = (Ether(src=self.pg2.remote_mac, dst='ff:ff:ff:ff:ff:ff') /
1089 ARP(op=ARP.who_has, pdst=self.snat_addr,
1090 psrc=self.pg2.remote_ip4, hwsrc=self.pg2.remote_mac))
1091 self.pg2.add_stream(p)
1092 self.pg_enable_capture(self.pg_interfaces)
1094 capture = self.pg1.get_capture(0)
1096 # remove addresses and verify
1097 self.snat_add_address(self.snat_addr, is_add=0)
1098 self.snat_add_static_mapping(self.pg0.remote_ip4, static_addr,
1101 p = (Ether(src=self.pg1.remote_mac, dst='ff:ff:ff:ff:ff:ff') /
1102 ARP(op=ARP.who_has, pdst=self.snat_addr,
1103 psrc=self.pg1.remote_ip4, hwsrc=self.pg1.remote_mac))
1104 self.pg1.add_stream(p)
1105 self.pg_enable_capture(self.pg_interfaces)
1107 capture = self.pg1.get_capture(0)
1109 p = (Ether(src=self.pg1.remote_mac, dst='ff:ff:ff:ff:ff:ff') /
1110 ARP(op=ARP.who_has, pdst=static_addr,
1111 psrc=self.pg1.remote_ip4, hwsrc=self.pg1.remote_mac))
1112 self.pg1.add_stream(p)
1113 self.pg_enable_capture(self.pg_interfaces)
1115 capture = self.pg1.get_capture(0)
1118 super(TestSNAT, self).tearDown()
1119 if not self.vpp_dead:
1120 self.logger.info(self.vapi.cli("show snat verbose"))
1124 if __name__ == '__main__':
1125 unittest.main(testRunner=VppTestRunner)