X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=test%2Ftest_snat.py;h=b6cc1c9a17fbeb81f085d299fbbfa9c236de0499;hb=d2c97d988b2fbc28f0905d1826b428967d09348a;hp=5cc76f6c7da7f585713a588b7b295a8d9f60a635;hpb=f78a70d49486b8080941399f2473ef6ee6f5d0a3;p=vpp.git diff --git a/test/test_snat.py b/test/test_snat.py index 5cc76f6c7da..b6cc1c9a17f 100644 --- a/test/test_snat.py +++ b/test/test_snat.py @@ -2,12 +2,14 @@ import socket import unittest -from logging import * +import struct from framework import VppTestCase, VppTestRunner - from scapy.layers.inet import IP, TCP, UDP, ICMP from scapy.layers.l2 import Ether +from scapy.data import IP_PROTOS +from util import ppp +from ipfix import IPFIX, Set, Template, Data, IPFIXDecoder class TestSNAT(VppTestCase): @@ -26,7 +28,7 @@ class TestSNAT(VppTestCase): cls.icmp_id_out = 6305 cls.snat_addr = '10.0.0.3' - cls.create_pg_interfaces(range(7)) + cls.create_pg_interfaces(range(8)) cls.interfaces = list(cls.pg_interfaces[0:4]) for i in cls.interfaces: @@ -39,15 +41,25 @@ class TestSNAT(VppTestCase): cls.overlapping_interfaces = list(list(cls.pg_interfaces[4:7])) + cls.pg4._local_ip4 = "172.16.255.1" + cls.pg4._local_ip4n = socket.inet_pton(socket.AF_INET, i.local_ip4) + cls.pg4._remote_hosts[0]._ip4 = "172.16.255.2" + cls.pg4.set_table_ip4(10) + cls.pg5._local_ip4 = "172.16.255.3" + cls.pg5._local_ip4n = socket.inet_pton(socket.AF_INET, i.local_ip4) + cls.pg5._remote_hosts[0]._ip4 = "172.16.255.4" + cls.pg5.set_table_ip4(10) + cls.pg6._local_ip4 = "172.16.255.1" + cls.pg6._local_ip4n = socket.inet_pton(socket.AF_INET, i.local_ip4) + cls.pg6._remote_hosts[0]._ip4 = "172.16.255.2" + cls.pg6.set_table_ip4(20) for i in cls.overlapping_interfaces: - i._local_ip4 = "172.16.255.1" - i._local_ip4n = socket.inet_pton(socket.AF_INET, i.local_ip4) - i._remote_hosts[0]._ip4 = "172.16.255.2" - i.set_table_ip4(i.sw_if_index) i.config_ip4() i.admin_up() i.resolve_arp() + cls.pg7.admin_up() + except Exception: super(TestSNAT, cls).tearDownClass() raise @@ -88,7 +100,7 @@ class TestSNAT(VppTestCase): :param dst_ip: Destination IP address (Default use global SNAT address) """ if dst_ip is None: - dst_ip=self.snat_addr + dst_ip = self.snat_addr pkts = [] # TCP p = (Ether(dst=out_if.local_mac, src=out_if.remote_mac) / @@ -130,13 +142,15 @@ class TestSNAT(VppTestCase): if same_port: self.assertEqual(packet[TCP].sport, self.tcp_port_in) else: - self.assertNotEqual(packet[TCP].sport, self.tcp_port_in) + self.assertNotEqual( + packet[TCP].sport, self.tcp_port_in) self.tcp_port_out = packet[TCP].sport elif packet.haslayer(UDP): if same_port: self.assertEqual(packet[UDP].sport, self.udp_port_in) else: - self.assertNotEqual(packet[UDP].sport, self.udp_port_in) + self.assertNotEqual( + packet[UDP].sport, self.udp_port_in) self.udp_port_out = packet[UDP].sport else: if same_port: @@ -145,8 +159,8 @@ class TestSNAT(VppTestCase): self.assertNotEqual(packet[ICMP].id, self.icmp_id_in) self.icmp_id_out = packet[ICMP].id except: - error("Unexpected or invalid packet (outside network):") - error(packet.show()) + self.logger.error(ppp("Unexpected or invalid packet " + "(outside network):", packet)) raise def verify_capture_in(self, capture, in_if, packet_num=3): @@ -168,14 +182,102 @@ class TestSNAT(VppTestCase): else: self.assertEqual(packet[ICMP].id, self.icmp_id_in) except: - error("Unexpected or invalid packet (inside network):") - error(packet.show()) + self.logger.error(ppp("Unexpected or invalid packet " + "(inside network):", packet)) raise + def verify_capture_no_translation(self, capture, ingress_if, egress_if): + """ + Verify captured packet that don't have to be translated + + :param capture: Captured packets + :param ingress_if: Ingress interface + :param egress_if: Egress interface + """ + for packet in capture: + try: + self.assertEqual(packet[IP].src, ingress_if.remote_ip4) + self.assertEqual(packet[IP].dst, egress_if.remote_ip4) + if packet.haslayer(TCP): + self.assertEqual(packet[TCP].sport, self.tcp_port_in) + elif packet.haslayer(UDP): + self.assertEqual(packet[UDP].sport, self.udp_port_in) + else: + self.assertEqual(packet[ICMP].id, self.icmp_id_in) + except: + self.logger.error(ppp("Unexpected or invalid packet " + "(inside network):", packet)) + raise + + def verify_ipfix_nat44_ses(self, data): + """ + Verify IPFIX NAT44 session create/delete event + + :param data: Decoded IPFIX data records + """ + nat44_ses_create_num = 0 + nat44_ses_delete_num = 0 + self.assertEqual(6, len(data)) + for record in data: + # natEvent + self.assertIn(ord(record[230]), [4, 5]) + if ord(record[230]) == 4: + nat44_ses_create_num += 1 + else: + nat44_ses_delete_num += 1 + # sourceIPv4Address + self.assertEqual(self.pg0.remote_ip4n, record[8]) + # postNATSourceIPv4Address + self.assertEqual(socket.inet_pton(socket.AF_INET, self.snat_addr), + record[225]) + # ingressVRFID + self.assertEqual(struct.pack("!I", 0), record[234]) + # protocolIdentifier/sourceTransportPort/postNAPTSourceTransportPort + if IP_PROTOS.icmp == ord(record[4]): + self.assertEqual(struct.pack("!H", self.icmp_id_in), record[7]) + self.assertEqual(struct.pack("!H", self.icmp_id_out), + record[227]) + elif IP_PROTOS.tcp == ord(record[4]): + self.assertEqual(struct.pack("!H", self.tcp_port_in), + record[7]) + self.assertEqual(struct.pack("!H", self.tcp_port_out), + record[227]) + elif IP_PROTOS.udp == ord(record[4]): + self.assertEqual(struct.pack("!H", self.udp_port_in), + record[7]) + self.assertEqual(struct.pack("!H", self.udp_port_out), + record[227]) + else: + self.fail("Invalid protocol") + self.assertEqual(3, nat44_ses_create_num) + self.assertEqual(3, nat44_ses_delete_num) + + def verify_ipfix_addr_exhausted(self, data): + """ + Verify IPFIX NAT addresses event + + :param data: Decoded IPFIX data records + """ + self.assertEqual(1, len(data)) + record = data[0] + # natEvent + self.assertEqual(ord(record[230]), 3) + # natPoolID + self.assertEqual(struct.pack("!I", 0), record[283]) + def clear_snat(self): """ Clear SNAT configuration. """ + if self.pg7.has_ip4_config: + self.pg7.unconfig_ip4() + + interfaces = self.vapi.snat_interface_addr_dump() + for intf in interfaces: + self.vapi.snat_add_interface_addr(intf.sw_if_index, is_add=0) + + self.vapi.snat_ipfix(enable=0) + interfaces = self.vapi.snat_interface_dump() for intf in interfaces: self.vapi.snat_interface_add_del_feature(intf.sw_if_index, @@ -198,8 +300,9 @@ class TestSNAT(VppTestCase): addr.ip_address, is_add=0) - def snat_add_static_mapping(self, local_ip, external_ip, local_port=0, - external_port=0, vrf_id=0, is_add=1): + def snat_add_static_mapping(self, local_ip, external_ip='0.0.0.0', + local_port=0, external_port=0, vrf_id=0, + is_add=1, external_sw_if_index=0xFFFFFFFF): """ Add/delete S-NAT static mapping @@ -209,14 +312,22 @@ class TestSNAT(VppTestCase): :param external_port: External port number (Optional) :param vrf_id: VRF ID (Default 0) :param is_add: 1 if add, 0 if delete (Default add) + :param external_sw_if_index: External interface instead of IP address """ addr_only = 1 if local_port and external_port: addr_only = 0 l_ip = socket.inet_pton(socket.AF_INET, local_ip) e_ip = socket.inet_pton(socket.AF_INET, external_ip) - self.vapi.snat_add_static_mapping(l_ip, e_ip, local_port, external_port, - addr_only, vrf_id, is_add) + self.vapi.snat_add_static_mapping( + l_ip, + e_ip, + external_sw_if_index, + local_port, + external_port, + addr_only, + vrf_id, + is_add) def snat_add_address(self, ip, is_add=1): """ @@ -241,7 +352,7 @@ class TestSNAT(VppTestCase): self.pg0.add_stream(pkts) self.pg_enable_capture(self.pg_interfaces) self.pg_start() - capture = self.pg1.get_capture() + capture = self.pg1.get_capture(len(pkts)) self.verify_capture_out(capture) # out2in @@ -249,7 +360,7 @@ class TestSNAT(VppTestCase): self.pg1.add_stream(pkts) self.pg_enable_capture(self.pg_interfaces) self.pg_start() - capture = self.pg0.get_capture() + capture = self.pg0.get_capture(len(pkts)) self.verify_capture_in(capture, self.pg0) def test_static_in(self): @@ -270,7 +381,7 @@ class TestSNAT(VppTestCase): self.pg0.add_stream(pkts) self.pg_enable_capture(self.pg_interfaces) self.pg_start() - capture = self.pg1.get_capture() + capture = self.pg1.get_capture(len(pkts)) self.verify_capture_out(capture, nat_ip, True) # out2in @@ -278,7 +389,7 @@ class TestSNAT(VppTestCase): self.pg1.add_stream(pkts) self.pg_enable_capture(self.pg_interfaces) self.pg_start() - capture = self.pg0.get_capture() + capture = self.pg0.get_capture(len(pkts)) self.verify_capture_in(capture, self.pg0) def test_static_out(self): @@ -299,7 +410,7 @@ class TestSNAT(VppTestCase): self.pg1.add_stream(pkts) self.pg_enable_capture(self.pg_interfaces) self.pg_start() - capture = self.pg0.get_capture() + capture = self.pg0.get_capture(len(pkts)) self.verify_capture_in(capture, self.pg0) # in2out @@ -307,7 +418,7 @@ class TestSNAT(VppTestCase): self.pg0.add_stream(pkts) self.pg_enable_capture(self.pg_interfaces) self.pg_start() - capture = self.pg1.get_capture() + capture = self.pg1.get_capture(len(pkts)) self.verify_capture_out(capture, nat_ip, True) def test_static_with_port_in(self): @@ -333,7 +444,7 @@ class TestSNAT(VppTestCase): self.pg0.add_stream(pkts) self.pg_enable_capture(self.pg_interfaces) self.pg_start() - capture = self.pg1.get_capture() + capture = self.pg1.get_capture(len(pkts)) self.verify_capture_out(capture) # out2in @@ -341,7 +452,7 @@ class TestSNAT(VppTestCase): self.pg1.add_stream(pkts) self.pg_enable_capture(self.pg_interfaces) self.pg_start() - capture = self.pg0.get_capture() + capture = self.pg0.get_capture(len(pkts)) self.verify_capture_in(capture, self.pg0) def test_static_with_port_out(self): @@ -367,7 +478,7 @@ class TestSNAT(VppTestCase): self.pg1.add_stream(pkts) self.pg_enable_capture(self.pg_interfaces) self.pg_start() - capture = self.pg0.get_capture() + capture = self.pg0.get_capture(len(pkts)) self.verify_capture_in(capture, self.pg0) # in2out @@ -375,7 +486,7 @@ class TestSNAT(VppTestCase): self.pg0.add_stream(pkts) self.pg_enable_capture(self.pg_interfaces) self.pg_start() - capture = self.pg1.get_capture() + capture = self.pg1.get_capture(len(pkts)) self.verify_capture_out(capture) def test_static_vrf_aware(self): @@ -388,9 +499,9 @@ class TestSNAT(VppTestCase): self.icmp_id_out = 6305 self.snat_add_static_mapping(self.pg4.remote_ip4, nat_ip1, - vrf_id=self.pg4.sw_if_index) + vrf_id=10) self.snat_add_static_mapping(self.pg0.remote_ip4, nat_ip2, - vrf_id=self.pg4.sw_if_index) + vrf_id=10) self.vapi.snat_interface_add_del_feature(self.pg3.sw_if_index, is_inside=0) self.vapi.snat_interface_add_del_feature(self.pg0.sw_if_index) @@ -401,7 +512,7 @@ class TestSNAT(VppTestCase): self.pg4.add_stream(pkts) self.pg_enable_capture(self.pg_interfaces) self.pg_start() - capture = self.pg3.get_capture() + capture = self.pg3.get_capture(len(pkts)) self.verify_capture_out(capture, nat_ip1, True) # inside interface VRF don't match SNAT static mapping VRF (packets @@ -410,25 +521,41 @@ class TestSNAT(VppTestCase): self.pg0.add_stream(pkts) self.pg_enable_capture(self.pg_interfaces) self.pg_start() - capture = self.pg3.get_capture() - self.verify_capture_out(capture, packet_num=0) + self.pg3.assert_nothing_captured() def test_multiple_inside_interfaces(self): - """ SNAT multiple inside interfaces with non-overlapping address space """ + """ + SNAT multiple inside interfaces with non-overlapping address space + """ self.snat_add_address(self.snat_addr) self.vapi.snat_interface_add_del_feature(self.pg0.sw_if_index) self.vapi.snat_interface_add_del_feature(self.pg1.sw_if_index) - self.vapi.snat_interface_add_del_feature(self.pg2.sw_if_index) self.vapi.snat_interface_add_del_feature(self.pg3.sw_if_index, is_inside=0) + # between two S-NAT inside interfaces (no translation) + pkts = self.create_stream_in(self.pg0, self.pg1) + self.pg0.add_stream(pkts) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + capture = self.pg1.get_capture(len(pkts)) + self.verify_capture_no_translation(capture, self.pg0, self.pg1) + + # from S-NAT inside to interface without S-NAT feature (no translation) + pkts = self.create_stream_in(self.pg0, self.pg2) + self.pg0.add_stream(pkts) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + capture = self.pg2.get_capture(len(pkts)) + self.verify_capture_no_translation(capture, self.pg0, self.pg2) + # in2out 1st interface pkts = self.create_stream_in(self.pg0, self.pg3) self.pg0.add_stream(pkts) self.pg_enable_capture(self.pg_interfaces) self.pg_start() - capture = self.pg3.get_capture() + capture = self.pg3.get_capture(len(pkts)) self.verify_capture_out(capture) # out2in 1st interface @@ -436,7 +563,7 @@ class TestSNAT(VppTestCase): self.pg3.add_stream(pkts) self.pg_enable_capture(self.pg_interfaces) self.pg_start() - capture = self.pg0.get_capture() + capture = self.pg0.get_capture(len(pkts)) self.verify_capture_in(capture, self.pg0) # in2out 2nd interface @@ -444,7 +571,7 @@ class TestSNAT(VppTestCase): self.pg1.add_stream(pkts) self.pg_enable_capture(self.pg_interfaces) self.pg_start() - capture = self.pg3.get_capture() + capture = self.pg3.get_capture(len(pkts)) self.verify_capture_out(capture) # out2in 2nd interface @@ -452,41 +579,56 @@ class TestSNAT(VppTestCase): self.pg3.add_stream(pkts) self.pg_enable_capture(self.pg_interfaces) self.pg_start() - capture = self.pg1.get_capture() + capture = self.pg1.get_capture(len(pkts)) self.verify_capture_in(capture, self.pg1) - # in2out 3rd interface - pkts = self.create_stream_in(self.pg2, self.pg3) - self.pg2.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg3.get_capture() - self.verify_capture_out(capture) - - # out2in 3rd interface - pkts = self.create_stream_out(self.pg3) - self.pg3.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg2.get_capture() - self.verify_capture_in(capture, self.pg2) - def test_inside_overlapping_interfaces(self): """ SNAT multiple inside interfaces with overlapping address space """ + static_nat_ip = "10.0.0.10" self.snat_add_address(self.snat_addr) self.vapi.snat_interface_add_del_feature(self.pg3.sw_if_index, is_inside=0) self.vapi.snat_interface_add_del_feature(self.pg4.sw_if_index) self.vapi.snat_interface_add_del_feature(self.pg5.sw_if_index) self.vapi.snat_interface_add_del_feature(self.pg6.sw_if_index) + self.snat_add_static_mapping(self.pg6.remote_ip4, static_nat_ip, + vrf_id=20) + + # between S-NAT inside interfaces with same VRF (no translation) + pkts = self.create_stream_in(self.pg4, self.pg5) + self.pg4.add_stream(pkts) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + capture = self.pg5.get_capture(len(pkts)) + self.verify_capture_no_translation(capture, self.pg4, self.pg5) + + # between S-NAT inside interfaces with different VRF (hairpinning) + p = (Ether(src=self.pg4.remote_mac, dst=self.pg4.local_mac) / + IP(src=self.pg4.remote_ip4, dst=static_nat_ip) / + TCP(sport=1234, dport=5678)) + self.pg4.add_stream(p) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + capture = self.pg6.get_capture(1) + p = capture[0] + try: + ip = p[IP] + tcp = p[TCP] + self.assertEqual(ip.src, self.snat_addr) + self.assertEqual(ip.dst, self.pg6.remote_ip4) + self.assertNotEqual(tcp.sport, 1234) + self.assertEqual(tcp.dport, 5678) + except: + self.logger.error(ppp("Unexpected or invalid packet:", p)) + raise # in2out 1st interface pkts = self.create_stream_in(self.pg4, self.pg3) self.pg4.add_stream(pkts) self.pg_enable_capture(self.pg_interfaces) self.pg_start() - capture = self.pg3.get_capture() + capture = self.pg3.get_capture(len(pkts)) self.verify_capture_out(capture) # out2in 1st interface @@ -494,7 +636,7 @@ class TestSNAT(VppTestCase): self.pg3.add_stream(pkts) self.pg_enable_capture(self.pg_interfaces) self.pg_start() - capture = self.pg4.get_capture() + capture = self.pg4.get_capture(len(pkts)) self.verify_capture_in(capture, self.pg4) # in2out 2nd interface @@ -502,7 +644,7 @@ class TestSNAT(VppTestCase): self.pg5.add_stream(pkts) self.pg_enable_capture(self.pg_interfaces) self.pg_start() - capture = self.pg3.get_capture() + capture = self.pg3.get_capture(len(pkts)) self.verify_capture_out(capture) # out2in 2nd interface @@ -510,7 +652,7 @@ class TestSNAT(VppTestCase): self.pg3.add_stream(pkts) self.pg_enable_capture(self.pg_interfaces) self.pg_start() - capture = self.pg5.get_capture() + capture = self.pg5.get_capture(len(pkts)) self.verify_capture_in(capture, self.pg5) # in2out 3rd interface @@ -518,15 +660,15 @@ class TestSNAT(VppTestCase): self.pg6.add_stream(pkts) self.pg_enable_capture(self.pg_interfaces) self.pg_start() - capture = self.pg3.get_capture() - self.verify_capture_out(capture) + capture = self.pg3.get_capture(len(pkts)) + self.verify_capture_out(capture, static_nat_ip, True) # out2in 3rd interface - pkts = self.create_stream_out(self.pg3) + pkts = self.create_stream_out(self.pg3, static_nat_ip) self.pg3.add_stream(pkts) self.pg_enable_capture(self.pg_interfaces) self.pg_start() - capture = self.pg6.get_capture() + capture = self.pg6.get_capture(len(pkts)) self.verify_capture_in(capture, self.pg6) def test_hairpinning(self): @@ -554,8 +696,7 @@ class TestSNAT(VppTestCase): self.pg0.add_stream(p) self.pg_enable_capture(self.pg_interfaces) self.pg_start() - capture = self.pg0.get_capture() - self.assertEqual(1, len(capture)) + capture = self.pg0.get_capture(1) p = capture[0] try: ip = p[IP] @@ -566,8 +707,7 @@ class TestSNAT(VppTestCase): self.assertEqual(tcp.dport, server_in_port) host_out_port = tcp.sport except: - error("Unexpected or invalid packet:") - error(p.show()) + self.logger.error(ppp("Unexpected or invalid packet:", p)) raise # send reply from server to host @@ -577,8 +717,7 @@ class TestSNAT(VppTestCase): self.pg0.add_stream(p) self.pg_enable_capture(self.pg_interfaces) self.pg_start() - capture = self.pg0.get_capture() - self.assertEqual(1, len(capture)) + capture = self.pg0.get_capture(1) p = capture[0] try: ip = p[IP] @@ -588,10 +727,140 @@ class TestSNAT(VppTestCase): self.assertEqual(tcp.sport, server_out_port) self.assertEqual(tcp.dport, host_in_port) except: - error("Unexpected or invalid packet:") - error(p.show()) + self.logger.error(ppp("Unexpected or invalid packet:"), p) raise + def test_max_translations_per_user(self): + """ MAX translations per user - recycle the least recently used """ + + self.snat_add_address(self.snat_addr) + self.vapi.snat_interface_add_del_feature(self.pg0.sw_if_index) + self.vapi.snat_interface_add_del_feature(self.pg1.sw_if_index, + is_inside=0) + + # get maximum number of translations per user + snat_config = self.vapi.snat_show_config() + + # send more than maximum number of translations per user packets + pkts_num = snat_config.max_translations_per_user + 5 + pkts = [] + for port in range(0, pkts_num): + p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / + IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) / + TCP(sport=1025 + port)) + pkts.append(p) + self.pg0.add_stream(pkts) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + # verify number of translated packet + self.pg1.get_capture(pkts_num) + + def test_interface_addr(self): + """ Acquire SNAT addresses from interface """ + self.vapi.snat_add_interface_addr(self.pg7.sw_if_index) + + # no address in NAT pool + adresses = self.vapi.snat_address_dump() + self.assertEqual(0, len(adresses)) + + # configure interface address and check NAT address pool + self.pg7.config_ip4() + adresses = self.vapi.snat_address_dump() + self.assertEqual(1, len(adresses)) + self.assertEqual(adresses[0].ip_address[0:4], self.pg7.local_ip4n) + + # remove interface address and check NAT address pool + self.pg7.unconfig_ip4() + adresses = self.vapi.snat_address_dump() + self.assertEqual(0, len(adresses)) + + def test_interface_addr_static_mapping(self): + """ Static mapping with addresses from interface """ + self.vapi.snat_add_interface_addr(self.pg7.sw_if_index) + self.snat_add_static_mapping('1.2.3.4', + external_sw_if_index=self.pg7.sw_if_index) + + # no static mappings + static_mappings = self.vapi.snat_static_mapping_dump() + self.assertEqual(0, len(static_mappings)) + + # configure interface address and check static mappings + self.pg7.config_ip4() + static_mappings = self.vapi.snat_static_mapping_dump() + self.assertEqual(1, len(static_mappings)) + self.assertEqual(static_mappings[0].external_ip_address[0:4], + self.pg7.local_ip4n) + + # remove interface address and check static mappings + self.pg7.unconfig_ip4() + static_mappings = self.vapi.snat_static_mapping_dump() + self.assertEqual(0, len(static_mappings)) + + def test_ipfix_nat44_sess(self): + """ S-NAT IPFIX logging NAT44 session created/delted """ + self.snat_add_address(self.snat_addr) + self.vapi.snat_interface_add_del_feature(self.pg0.sw_if_index) + self.vapi.snat_interface_add_del_feature(self.pg1.sw_if_index, + is_inside=0) + self.vapi.set_ipfix_exporter(collector_address=self.pg3.remote_ip4n, + src_address=self.pg3.local_ip4n, + path_mtu=512, + template_interval=10) + self.vapi.snat_ipfix() + + pkts = self.create_stream_in(self.pg0, self.pg1) + self.pg0.add_stream(pkts) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + capture = self.pg1.get_capture(len(pkts)) + self.verify_capture_out(capture) + self.snat_add_address(self.snat_addr, is_add=0) + self.vapi.cli("ipfix flush") # FIXME this should be an API call + capture = self.pg3.get_capture(3) + ipfix = IPFIXDecoder() + # first load template + for p in capture: + self.assertTrue(p.haslayer(IPFIX)) + if p.haslayer(Template): + ipfix.add_template(p.getlayer(Template)) + # verify events in data set + for p in capture: + if p.haslayer(Data): + data = ipfix.decode_data_set(p.getlayer(Set)) + self.verify_ipfix_nat44_ses(data) + + def test_ipfix_addr_exhausted(self): + """ S-NAT IPFIX logging NAT addresses exhausted """ + self.vapi.snat_interface_add_del_feature(self.pg0.sw_if_index) + self.vapi.snat_interface_add_del_feature(self.pg1.sw_if_index, + is_inside=0) + self.vapi.set_ipfix_exporter(collector_address=self.pg3.remote_ip4n, + src_address=self.pg3.local_ip4n, + path_mtu=512, + template_interval=10) + self.vapi.snat_ipfix() + + p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / + IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) / + TCP(sport=3025)) + self.pg0.add_stream(p) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + capture = self.pg1.get_capture(0) + self.vapi.cli("ipfix flush") # FIXME this should be an API call + capture = self.pg3.get_capture(3) + ipfix = IPFIXDecoder() + # first load template + for p in capture: + self.assertTrue(p.haslayer(IPFIX)) + if p.haslayer(Template): + ipfix.add_template(p.getlayer(Template)) + # verify events in data set + for p in capture: + if p.haslayer(Data): + data = ipfix.decode_data_set(p.getlayer(Set)) + self.verify_ipfix_addr_exhausted(data) def tearDown(self): super(TestSNAT, self).tearDown() @@ -599,5 +868,6 @@ class TestSNAT(VppTestCase): self.logger.info(self.vapi.cli("show snat verbose")) self.clear_snat() + if __name__ == '__main__': unittest.main(testRunner=VppTestRunner)