diff options
author | Dave Wallace <dwallacelf@gmail.com> | 2019-08-22 00:32:29 +0000 |
---|---|---|
committer | Dave Barach <openvpp@barachs.net> | 2019-08-22 15:33:59 +0000 |
commit | a43c93f8554ad7418e31be3791b3fb71232f60ac (patch) | |
tree | 50382fdf248809eac59580d8901ff7aef02a8f17 /test | |
parent | 34af0ccf5cf27d8a72119626d2d009222e4ff0a6 (diff) |
tests: move plugin tests to src/plugins/*/test
- Relocate plugin tests for 'make test' into
src/plugins/*/test so that plugin test cases
are co-located with the plugin source code.
Type: refactor
Signed-off-by: Dave Wallace <dwallacelf@gmail.com>
Change-Id: I503e6a43528e14981799b735fa65674155713f67
Signed-off-by: Dave Wallace <dwallacelf@gmail.com>
Diffstat (limited to 'test')
32 files changed, 8 insertions, 30163 deletions
diff --git a/test/Makefile b/test/Makefile index 3a92f1413b5..66c8f8a9bb7 100644 --- a/test/Makefile +++ b/test/Makefile @@ -135,8 +135,15 @@ refresh-deps: clean-deps $(PYTHON_DEPENDS) clean-deps: @rm -f $(PYTHON_DEPENDS) +ifneq ($(EXTERN_PLUGIN_SRC_DIR),) +PLUGIN_SRC_DIR=$(EXTERN_PLUGIN_SRC_DIR) +else +PLUGIN_SRC_DIR=$(WS_ROOT)/src/plugins +endif +PLUGIN_TEST_DIRS=$(shell find $(PLUGIN_SRC_DIR) -type d -name test -exec echo -n " -d {}" \;) + define retest-func -@env FORCE_FOREGROUND=$(FORCE_FOREGROUND) FAILED_DIR=$(FAILED_DIR) VENV_PATH=$(VENV_PATH) scripts/setsid_wrapper.sh $(FORCE_FOREGROUND) $(VENV_PATH)/bin/activate $(PYTHON_INTERP) $(PYTHON_PROFILE_OPTS) run_tests.py -d $(TEST_DIR) $(UNITTEST_EXTRA_OPTS) || env FAILED_DIR=$(FAILED_DIR) COMPRESS_FAILED_TEST_LOGS=$(COMPRESS_FAILED_TEST_LOGS) scripts/compress_failed.sh +@env FORCE_FOREGROUND=$(FORCE_FOREGROUND) FAILED_DIR=$(FAILED_DIR) VENV_PATH=$(VENV_PATH) scripts/setsid_wrapper.sh $(FORCE_FOREGROUND) $(VENV_PATH)/bin/activate $(PYTHON_INTERP) $(PYTHON_PROFILE_OPTS) run_tests.py -d $(TEST_DIR)$(PLUGIN_TEST_DIRS) $(UNITTEST_EXTRA_OPTS) || env FAILED_DIR=$(FAILED_DIR) COMPRESS_FAILED_TEST_LOGS=$(COMPRESS_FAILED_TEST_LOGS) scripts/compress_failed.sh endef .PHONY: sanity diff --git a/test/test_abf.py b/test/test_abf.py deleted file mode 100644 index 221a793fed3..00000000000 --- a/test/test_abf.py +++ /dev/null @@ -1,344 +0,0 @@ -#!/usr/bin/env python - -from socket import inet_pton, inet_ntop, AF_INET, AF_INET6 -import unittest - -from framework import VppTestCase, VppTestRunner -from vpp_ip import DpoProto -from vpp_ip_route import VppIpRoute, VppRoutePath, VppMplsLabel, \ - VppIpTable, FibPathProto - -from scapy.packet import Raw -from scapy.layers.l2 import Ether -from scapy.layers.inet import IP, UDP -from scapy.layers.inet6 import IPv6 - -from vpp_object import VppObject - -NUM_PKTS = 67 - - -def find_abf_policy(test, id): - policies = test.vapi.abf_policy_dump() - for p in policies: - if id == p.policy.policy_id: - return True - return False - - -def find_abf_itf_attach(test, id, sw_if_index): - attachs = test.vapi.abf_itf_attach_dump() - for a in attachs: - if id == a.attach.policy_id and \ - sw_if_index == a.attach.sw_if_index: - return True - return False - - -class VppAbfPolicy(VppObject): - - def __init__(self, - test, - policy_id, - acl, - paths): - self._test = test - self.policy_id = policy_id - self.acl = acl - self.paths = paths - self.encoded_paths = [] - for path in self.paths: - self.encoded_paths.append(path.encode()) - - def add_vpp_config(self): - self._test.vapi.abf_policy_add_del( - 1, - {'policy_id': self.policy_id, - 'acl_index': self.acl.acl_index, - 'n_paths': len(self.paths), - 'paths': self.encoded_paths}) - self._test.registry.register(self, self._test.logger) - - def remove_vpp_config(self): - self._test.vapi.abf_policy_add_del( - 0, - {'policy_id': self.policy_id, - 'acl_index': self.acl.acl_index, - 'n_paths': len(self.paths), - 'paths': self.encoded_paths}) - - def query_vpp_config(self): - return find_abf_policy(self._test, self.policy_id) - - def object_id(self): - return ("abf-policy-%d" % self.policy_id) - - -class VppAbfAttach(VppObject): - - def __init__(self, - test, - policy_id, - sw_if_index, - priority, - is_ipv6=0): - self._test = test - self.policy_id = policy_id - self.sw_if_index = sw_if_index - self.priority = priority - self.is_ipv6 = is_ipv6 - - def add_vpp_config(self): - self._test.vapi.abf_itf_attach_add_del( - 1, - {'policy_id': self.policy_id, - 'sw_if_index': self.sw_if_index, - 'priority': self.priority, - 'is_ipv6': self.is_ipv6}) - self._test.registry.register(self, self._test.logger) - - def remove_vpp_config(self): - self._test.vapi.abf_itf_attach_add_del( - 0, - {'policy_id': self.policy_id, - 'sw_if_index': self.sw_if_index, - 'priority': self.priority, - 'is_ipv6': self.is_ipv6}) - - def query_vpp_config(self): - return find_abf_itf_attach(self._test, - self.policy_id, - self.sw_if_index) - - def object_id(self): - return ("abf-attach-%d-%d" % (self.policy_id, self.sw_if_index)) - - -class TestAbf(VppTestCase): - """ ABF Test Case """ - - @classmethod - def setUpClass(cls): - super(TestAbf, cls).setUpClass() - - @classmethod - def tearDownClass(cls): - super(TestAbf, cls).tearDownClass() - - def setUp(self): - super(TestAbf, self).setUp() - - self.create_pg_interfaces(range(5)) - - for i in self.pg_interfaces[:4]: - i.admin_up() - i.config_ip4() - i.resolve_arp() - i.config_ip6() - i.resolve_ndp() - - def tearDown(self): - for i in self.pg_interfaces: - i.unconfig_ip4() - i.unconfig_ip6() - i.ip6_disable() - i.admin_down() - super(TestAbf, self).tearDown() - - def test_abf4(self): - """ IPv4 ACL Based Forwarding - """ - - # - # We are not testing the various matching capabilities - # of ACLs, that's done elsewhere. Here ware are testing - # the application of ACLs to a forwarding path to achieve - # ABF - # So we construct just a few ACLs to ensure the ABF policies - # are correctly constructed and used. And a few path types - # to test the API path decoding. - # - - # - # Rule 1 - # - rule_1 = ({'is_permit': 1, - 'is_ipv6': 0, - 'proto': 17, - 'srcport_or_icmptype_first': 1234, - 'srcport_or_icmptype_last': 1234, - 'src_ip_prefix_len': 32, - 'src_ip_addr': inet_pton(AF_INET, "1.1.1.1"), - 'dstport_or_icmpcode_first': 1234, - 'dstport_or_icmpcode_last': 1234, - 'dst_ip_prefix_len': 32, - 'dst_ip_addr': inet_pton(AF_INET, "1.1.1.2")}) - acl_1 = self.vapi.acl_add_replace(acl_index=4294967295, r=[rule_1]) - - # - # ABF policy for ACL 1 - path via interface 1 - # - abf_1 = VppAbfPolicy(self, 10, acl_1, - [VppRoutePath(self.pg1.remote_ip4, - self.pg1.sw_if_index)]) - abf_1.add_vpp_config() - - # - # Attach the policy to input interface Pg0 - # - attach_1 = VppAbfAttach(self, 10, self.pg0.sw_if_index, 50) - attach_1.add_vpp_config() - - # - # fire in packet matching the ACL src,dst. If it's forwarded - # then the ABF was successful, since default routing will drop it - # - p_1 = (Ether(src=self.pg0.remote_mac, - dst=self.pg0.local_mac) / - IP(src="1.1.1.1", dst="1.1.1.2") / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - self.send_and_expect(self.pg0, p_1*NUM_PKTS, self.pg1) - - # - # Attach a 'better' priority policy to the same interface - # - abf_2 = VppAbfPolicy(self, 11, acl_1, - [VppRoutePath(self.pg2.remote_ip4, - self.pg2.sw_if_index)]) - abf_2.add_vpp_config() - attach_2 = VppAbfAttach(self, 11, self.pg0.sw_if_index, 40) - attach_2.add_vpp_config() - - self.send_and_expect(self.pg0, p_1*NUM_PKTS, self.pg2) - - # - # Attach a policy with priority in the middle - # - abf_3 = VppAbfPolicy(self, 12, acl_1, - [VppRoutePath(self.pg3.remote_ip4, - self.pg3.sw_if_index)]) - abf_3.add_vpp_config() - attach_3 = VppAbfAttach(self, 12, self.pg0.sw_if_index, 45) - attach_3.add_vpp_config() - - self.send_and_expect(self.pg0, p_1*NUM_PKTS, self.pg2) - - # - # remove the best priority - # - attach_2.remove_vpp_config() - self.send_and_expect(self.pg0, p_1*NUM_PKTS, self.pg3) - - # - # Attach one of the same policies to Pg1 - # - attach_4 = VppAbfAttach(self, 12, self.pg1.sw_if_index, 45) - attach_4.add_vpp_config() - - p_2 = (Ether(src=self.pg1.remote_mac, - dst=self.pg1.local_mac) / - IP(src="1.1.1.1", dst="1.1.1.2") / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - self.send_and_expect(self.pg1, p_2 * NUM_PKTS, self.pg3) - - # - # detach the policy from PG1, now expect traffic to be dropped - # - attach_4.remove_vpp_config() - - self.send_and_assert_no_replies(self.pg1, p_2 * NUM_PKTS, "Detached") - - # - # Swap to route via a next-hop in the non-default table - # - table_20 = VppIpTable(self, 20) - table_20.add_vpp_config() - - self.pg4.set_table_ip4(table_20.table_id) - self.pg4.admin_up() - self.pg4.config_ip4() - self.pg4.resolve_arp() - - abf_13 = VppAbfPolicy(self, 13, acl_1, - [VppRoutePath(self.pg4.remote_ip4, - 0xffffffff, - nh_table_id=table_20.table_id)]) - abf_13.add_vpp_config() - attach_5 = VppAbfAttach(self, 13, self.pg0.sw_if_index, 30) - attach_5.add_vpp_config() - - self.send_and_expect(self.pg0, p_1*NUM_PKTS, self.pg4) - - self.pg4.unconfig_ip4() - self.pg4.set_table_ip4(0) - - def test_abf6(self): - """ IPv6 ACL Based Forwarding - """ - - # - # Simple test for matching IPv6 packets - # - - # - # Rule 1 - # - rule_1 = ({'is_permit': 1, - 'is_ipv6': 1, - 'proto': 17, - 'srcport_or_icmptype_first': 1234, - 'srcport_or_icmptype_last': 1234, - 'src_ip_prefix_len': 128, - 'src_ip_addr': inet_pton(AF_INET6, "2001::2"), - 'dstport_or_icmpcode_first': 1234, - 'dstport_or_icmpcode_last': 1234, - 'dst_ip_prefix_len': 128, - 'dst_ip_addr': inet_pton(AF_INET6, "2001::1")}) - acl_1 = self.vapi.acl_add_replace(acl_index=4294967295, - r=[rule_1]) - - # - # ABF policy for ACL 1 - path via interface 1 - # - abf_1 = VppAbfPolicy(self, 10, acl_1, - [VppRoutePath("3001::1", - 0xffffffff)]) - abf_1.add_vpp_config() - - attach_1 = VppAbfAttach(self, 10, self.pg0.sw_if_index, - 45, is_ipv6=True) - attach_1.add_vpp_config() - - # - # a packet matching the rule - # - p = (Ether(src=self.pg0.remote_mac, - dst=self.pg0.local_mac) / - IPv6(src="2001::2", dst="2001::1") / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - - # - # packets are dropped because there is no route to the policy's - # next hop - # - self.send_and_assert_no_replies(self.pg1, p * NUM_PKTS, "no route") - - # - # add a route resolving the next-hop - # - route = VppIpRoute(self, "3001::1", 32, - [VppRoutePath(self.pg1.remote_ip6, - self.pg1.sw_if_index)]) - route.add_vpp_config() - - # - # now expect packets forwarded. - # - self.send_and_expect(self.pg0, p * NUM_PKTS, self.pg1) - - -if __name__ == '__main__': - unittest.main(testRunner=VppTestRunner) diff --git a/test/test_acl_plugin.py b/test/test_acl_plugin.py deleted file mode 100644 index eca02316bf6..00000000000 --- a/test/test_acl_plugin.py +++ /dev/null @@ -1,1519 +0,0 @@ -#!/usr/bin/env python -"""ACL plugin Test Case HLD: -""" - -import unittest -import random - -from scapy.packet import Raw -from scapy.layers.l2 import Ether -from scapy.layers.inet import IP, TCP, UDP, ICMP -from scapy.layers.inet6 import IPv6, ICMPv6EchoRequest -from scapy.layers.inet6 import IPv6ExtHdrFragment -from framework import VppTestCase, VppTestRunner -from util import Host, ppp - -from vpp_lo_interface import VppLoInterface - - -class TestACLplugin(VppTestCase): - """ ACL plugin Test Case """ - - # traffic types - IP = 0 - ICMP = 1 - - # IP version - IPRANDOM = -1 - IPV4 = 0 - IPV6 = 1 - - # rule types - DENY = 0 - PERMIT = 1 - - # supported protocols - proto = [[6, 17], [1, 58]] - proto_map = {1: 'ICMP', 58: 'ICMPv6EchoRequest', 6: 'TCP', 17: 'UDP'} - ICMPv4 = 0 - ICMPv6 = 1 - TCP = 0 - UDP = 1 - PROTO_ALL = 0 - - # port ranges - PORTS_ALL = -1 - PORTS_RANGE = 0 - PORTS_RANGE_2 = 1 - udp_sport_from = 10 - udp_sport_to = udp_sport_from + 5 - udp_dport_from = 20000 - udp_dport_to = udp_dport_from + 5000 - tcp_sport_from = 30 - tcp_sport_to = tcp_sport_from + 5 - tcp_dport_from = 40000 - tcp_dport_to = tcp_dport_from + 5000 - - udp_sport_from_2 = 90 - udp_sport_to_2 = udp_sport_from_2 + 5 - udp_dport_from_2 = 30000 - udp_dport_to_2 = udp_dport_from_2 + 5000 - tcp_sport_from_2 = 130 - tcp_sport_to_2 = tcp_sport_from_2 + 5 - tcp_dport_from_2 = 20000 - tcp_dport_to_2 = tcp_dport_from_2 + 5000 - - icmp4_type = 8 # echo request - icmp4_code = 3 - icmp6_type = 128 # echo request - icmp6_code = 3 - - icmp4_type_2 = 8 - icmp4_code_from_2 = 5 - icmp4_code_to_2 = 20 - icmp6_type_2 = 128 - icmp6_code_from_2 = 8 - icmp6_code_to_2 = 42 - - # Test variables - bd_id = 1 - - @classmethod - def setUpClass(cls): - """ - Perform standard class setup (defined by class method setUpClass in - class VppTestCase) before running the test case, set test case related - variables and configure VPP. - """ - super(TestACLplugin, cls).setUpClass() - - try: - # Create 2 pg interfaces - cls.create_pg_interfaces(range(2)) - - # Packet flows mapping pg0 -> pg1, pg2 etc. - cls.flows = dict() - cls.flows[cls.pg0] = [cls.pg1] - - # Packet sizes - cls.pg_if_packet_sizes = [64, 512, 1518, 9018] - - # Create BD with MAC learning and unknown unicast flooding disabled - # and put interfaces to this BD - cls.vapi.bridge_domain_add_del(bd_id=cls.bd_id, uu_flood=1, - learn=1) - for pg_if in cls.pg_interfaces: - cls.vapi.sw_interface_set_l2_bridge( - rx_sw_if_index=pg_if.sw_if_index, bd_id=cls.bd_id) - - # Set up all interfaces - for i in cls.pg_interfaces: - i.admin_up() - - # Mapping between packet-generator index and lists of test hosts - cls.hosts_by_pg_idx = dict() - for pg_if in cls.pg_interfaces: - cls.hosts_by_pg_idx[pg_if.sw_if_index] = [] - - # Create list of deleted hosts - cls.deleted_hosts_by_pg_idx = dict() - for pg_if in cls.pg_interfaces: - cls.deleted_hosts_by_pg_idx[pg_if.sw_if_index] = [] - - # warm-up the mac address tables - # self.warmup_test() - count = 16 - start = 0 - n_int = len(cls.pg_interfaces) - macs_per_if = count / n_int - i = -1 - for pg_if in cls.pg_interfaces: - i += 1 - start_nr = macs_per_if * i + start - end_nr = count + start if i == (n_int - 1) \ - else macs_per_if * (i + 1) + start - hosts = cls.hosts_by_pg_idx[pg_if.sw_if_index] - for j in range(start_nr, end_nr): - host = Host( - "00:00:00:ff:%02x:%02x" % (pg_if.sw_if_index, j), - "172.17.1%02x.%u" % (pg_if.sw_if_index, j), - "2017:dead:%02x::%u" % (pg_if.sw_if_index, j)) - hosts.append(host) - - except Exception: - super(TestACLplugin, cls).tearDownClass() - raise - - @classmethod - def tearDownClass(cls): - super(TestACLplugin, cls).tearDownClass() - - def setUp(self): - super(TestACLplugin, self).setUp() - self.reset_packet_infos() - - def tearDown(self): - """ - Show various debug prints after each test. - """ - super(TestACLplugin, self).tearDown() - - def show_commands_at_teardown(self): - cli = "show vlib graph l2-input-feat-arc" - self.logger.info(self.vapi.ppcli(cli)) - cli = "show vlib graph l2-input-feat-arc-end" - self.logger.info(self.vapi.ppcli(cli)) - cli = "show vlib graph l2-output-feat-arc" - self.logger.info(self.vapi.ppcli(cli)) - cli = "show vlib graph l2-output-feat-arc-end" - self.logger.info(self.vapi.ppcli(cli)) - self.logger.info(self.vapi.ppcli("show l2fib verbose")) - self.logger.info(self.vapi.ppcli("show acl-plugin acl")) - self.logger.info(self.vapi.ppcli("show acl-plugin interface")) - self.logger.info(self.vapi.ppcli("show acl-plugin tables")) - self.logger.info(self.vapi.ppcli("show bridge-domain %s detail" - % self.bd_id)) - - def create_rule(self, ip=0, permit_deny=0, ports=PORTS_ALL, proto=-1, - s_prefix=0, s_ip='\x00\x00\x00\x00', - d_prefix=0, d_ip='\x00\x00\x00\x00'): - if proto == -1: - return - if ports == self.PORTS_ALL: - sport_from = 0 - dport_from = 0 - sport_to = 65535 if proto != 1 and proto != 58 else 255 - dport_to = sport_to - elif ports == self.PORTS_RANGE: - if proto == 1: - sport_from = self.icmp4_type - sport_to = self.icmp4_type - dport_from = self.icmp4_code - dport_to = self.icmp4_code - elif proto == 58: - sport_from = self.icmp6_type - sport_to = self.icmp6_type - dport_from = self.icmp6_code - dport_to = self.icmp6_code - elif proto == self.proto[self.IP][self.TCP]: - sport_from = self.tcp_sport_from - sport_to = self.tcp_sport_to - dport_from = self.tcp_dport_from - dport_to = self.tcp_dport_to - elif proto == self.proto[self.IP][self.UDP]: - sport_from = self.udp_sport_from - sport_to = self.udp_sport_to - dport_from = self.udp_dport_from - dport_to = self.udp_dport_to - elif ports == self.PORTS_RANGE_2: - if proto == 1: - sport_from = self.icmp4_type_2 - sport_to = self.icmp4_type_2 - dport_from = self.icmp4_code_from_2 - dport_to = self.icmp4_code_to_2 - elif proto == 58: - sport_from = self.icmp6_type_2 - sport_to = self.icmp6_type_2 - dport_from = self.icmp6_code_from_2 - dport_to = self.icmp6_code_to_2 - elif proto == self.proto[self.IP][self.TCP]: - sport_from = self.tcp_sport_from_2 - sport_to = self.tcp_sport_to_2 - dport_from = self.tcp_dport_from_2 - dport_to = self.tcp_dport_to_2 - elif proto == self.proto[self.IP][self.UDP]: - sport_from = self.udp_sport_from_2 - sport_to = self.udp_sport_to_2 - dport_from = self.udp_dport_from_2 - dport_to = self.udp_dport_to_2 - else: - sport_from = ports - sport_to = ports - dport_from = ports - dport_to = ports - - rule = ({'is_permit': permit_deny, 'is_ipv6': ip, 'proto': proto, - 'srcport_or_icmptype_first': sport_from, - 'srcport_or_icmptype_last': sport_to, - 'src_ip_prefix_len': s_prefix, - 'src_ip_addr': s_ip, - 'dstport_or_icmpcode_first': dport_from, - 'dstport_or_icmpcode_last': dport_to, - 'dst_ip_prefix_len': d_prefix, - 'dst_ip_addr': d_ip}) - return rule - - def apply_rules(self, rules, tag=b''): - reply = self.vapi.acl_add_replace(acl_index=4294967295, r=rules, - tag=tag) - self.logger.info("Dumped ACL: " + str( - self.vapi.acl_dump(reply.acl_index))) - # Apply a ACL on the interface as inbound - for i in self.pg_interfaces: - self.vapi.acl_interface_set_acl_list(sw_if_index=i.sw_if_index, - n_input=1, - acls=[reply.acl_index]) - return reply.acl_index - - def apply_rules_to(self, rules, tag=b'', sw_if_index=0xFFFFFFFF): - reply = self.vapi.acl_add_replace(acl_index=4294967295, r=rules, - tag=tag) - self.logger.info("Dumped ACL: " + str( - self.vapi.acl_dump(reply.acl_index))) - # Apply a ACL on the interface as inbound - self.vapi.acl_interface_set_acl_list(sw_if_index=sw_if_index, - n_input=1, - acls=[reply.acl_index]) - return reply.acl_index - - def etype_whitelist(self, whitelist, n_input): - # Apply whitelists on all the interfaces - for i in self.pg_interfaces: - # checkstyle can't read long names. Help them. - fun = self.vapi.acl_interface_set_etype_whitelist - fun(sw_if_index=i.sw_if_index, n_input=n_input, - whitelist=whitelist) - return - - def create_upper_layer(self, packet_index, proto, ports=0): - p = self.proto_map[proto] - if p == 'UDP': - if ports == 0: - return UDP(sport=random.randint(self.udp_sport_from, - self.udp_sport_to), - dport=random.randint(self.udp_dport_from, - self.udp_dport_to)) - else: - return UDP(sport=ports, dport=ports) - elif p == 'TCP': - if ports == 0: - return TCP(sport=random.randint(self.tcp_sport_from, - self.tcp_sport_to), - dport=random.randint(self.tcp_dport_from, - self.tcp_dport_to)) - else: - return TCP(sport=ports, dport=ports) - return '' - - def create_stream(self, src_if, packet_sizes, traffic_type=0, ipv6=0, - proto=-1, ports=0, fragments=False, - pkt_raw=True, etype=-1): - """ - Create input packet stream for defined interface using hosts or - deleted_hosts list. - - :param object src_if: Interface to create packet stream for. - :param list packet_sizes: List of required packet sizes. - :param traffic_type: 1: ICMP packet, 2: IPv6 with EH, 0: otherwise. - :return: Stream of packets. - """ - pkts = [] - if self.flows.__contains__(src_if): - src_hosts = self.hosts_by_pg_idx[src_if.sw_if_index] - for dst_if in self.flows[src_if]: - dst_hosts = self.hosts_by_pg_idx[dst_if.sw_if_index] - n_int = len(dst_hosts) * len(src_hosts) - for i in range(0, n_int): - dst_host = dst_hosts[i / len(src_hosts)] - src_host = src_hosts[i % len(src_hosts)] - pkt_info = self.create_packet_info(src_if, dst_if) - if ipv6 == 1: - pkt_info.ip = 1 - elif ipv6 == 0: - pkt_info.ip = 0 - else: - pkt_info.ip = random.choice([0, 1]) - if proto == -1: - pkt_info.proto = random.choice(self.proto[self.IP]) - else: - pkt_info.proto = proto - payload = self.info_to_payload(pkt_info) - p = Ether(dst=dst_host.mac, src=src_host.mac) - if etype > 0: - p = Ether(dst=dst_host.mac, - src=src_host.mac, - type=etype) - if pkt_info.ip: - p /= IPv6(dst=dst_host.ip6, src=src_host.ip6) - if fragments: - p /= IPv6ExtHdrFragment(offset=64, m=1) - else: - if fragments: - p /= IP(src=src_host.ip4, dst=dst_host.ip4, - flags=1, frag=64) - else: - p /= IP(src=src_host.ip4, dst=dst_host.ip4) - if traffic_type == self.ICMP: - if pkt_info.ip: - p /= ICMPv6EchoRequest(type=self.icmp6_type, - code=self.icmp6_code) - else: - p /= ICMP(type=self.icmp4_type, - code=self.icmp4_code) - else: - p /= self.create_upper_layer(i, pkt_info.proto, ports) - if pkt_raw: - p /= Raw(payload) - pkt_info.data = p.copy() - if pkt_raw: - size = random.choice(packet_sizes) - self.extend_packet(p, size) - pkts.append(p) - return pkts - - def verify_capture(self, pg_if, capture, - traffic_type=0, ip_type=0, etype=-1): - """ - Verify captured input packet stream for defined interface. - - :param object pg_if: Interface to verify captured packet stream for. - :param list capture: Captured packet stream. - :param traffic_type: 1: ICMP packet, 2: IPv6 with EH, 0: otherwise. - """ - last_info = dict() - for i in self.pg_interfaces: - last_info[i.sw_if_index] = None - dst_sw_if_index = pg_if.sw_if_index - for packet in capture: - if etype > 0: - if packet[Ether].type != etype: - self.logger.error(ppp("Unexpected ethertype in packet:", - packet)) - else: - continue - try: - # Raw data for ICMPv6 are stored in ICMPv6EchoRequest.data - if traffic_type == self.ICMP and ip_type == self.IPV6: - payload_info = self.payload_to_info( - packet[ICMPv6EchoRequest], 'data') - payload = packet[ICMPv6EchoRequest] - else: - payload_info = self.payload_to_info(packet[Raw]) - payload = packet[self.proto_map[payload_info.proto]] - except: - self.logger.error(ppp("Unexpected or invalid packet " - "(outside network):", packet)) - raise - - if ip_type != 0: - self.assertEqual(payload_info.ip, ip_type) - if traffic_type == self.ICMP: - try: - if payload_info.ip == 0: - self.assertEqual(payload.type, self.icmp4_type) - self.assertEqual(payload.code, self.icmp4_code) - else: - self.assertEqual(payload.type, self.icmp6_type) - self.assertEqual(payload.code, self.icmp6_code) - except: - self.logger.error(ppp("Unexpected or invalid packet " - "(outside network):", packet)) - raise - else: - try: - ip_version = IPv6 if payload_info.ip == 1 else IP - - ip = packet[ip_version] - packet_index = payload_info.index - - self.assertEqual(payload_info.dst, dst_sw_if_index) - self.logger.debug("Got packet on port %s: src=%u (id=%u)" % - (pg_if.name, payload_info.src, - packet_index)) - next_info = self.get_next_packet_info_for_interface2( - payload_info.src, dst_sw_if_index, - last_info[payload_info.src]) - last_info[payload_info.src] = next_info - self.assertTrue(next_info is not None) - self.assertEqual(packet_index, next_info.index) - saved_packet = next_info.data - # Check standard fields - self.assertEqual(ip.src, saved_packet[ip_version].src) - self.assertEqual(ip.dst, saved_packet[ip_version].dst) - p = self.proto_map[payload_info.proto] - if p == 'TCP': - tcp = packet[TCP] - self.assertEqual(tcp.sport, saved_packet[ - TCP].sport) - self.assertEqual(tcp.dport, saved_packet[ - TCP].dport) - elif p == 'UDP': - udp = packet[UDP] - self.assertEqual(udp.sport, saved_packet[ - UDP].sport) - self.assertEqual(udp.dport, saved_packet[ - UDP].dport) - except: - self.logger.error(ppp("Unexpected or invalid packet:", - packet)) - raise - for i in self.pg_interfaces: - remaining_packet = self.get_next_packet_info_for_interface2( - i, dst_sw_if_index, last_info[i.sw_if_index]) - self.assertTrue( - remaining_packet is None, - "Port %u: Packet expected from source %u didn't arrive" % - (dst_sw_if_index, i.sw_if_index)) - - def run_traffic_no_check(self): - # Test - # Create incoming packet streams for packet-generator interfaces - for i in self.pg_interfaces: - if self.flows.__contains__(i): - pkts = self.create_stream(i, self.pg_if_packet_sizes) - if len(pkts) > 0: - i.add_stream(pkts) - - # Enable packet capture and start packet sending - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - - def run_verify_test(self, traffic_type=0, ip_type=0, proto=-1, ports=0, - frags=False, pkt_raw=True, etype=-1): - # Test - # Create incoming packet streams for packet-generator interfaces - pkts_cnt = 0 - for i in self.pg_interfaces: - if self.flows.__contains__(i): - pkts = self.create_stream(i, self.pg_if_packet_sizes, - traffic_type, ip_type, proto, ports, - frags, pkt_raw, etype) - if len(pkts) > 0: - i.add_stream(pkts) - pkts_cnt += len(pkts) - - # Enable packet capture and start packet sendingself.IPV - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - self.logger.info("sent packets count: %d" % pkts_cnt) - - # Verify - # Verify outgoing packet streams per packet-generator interface - for src_if in self.pg_interfaces: - if self.flows.__contains__(src_if): - for dst_if in self.flows[src_if]: - capture = dst_if.get_capture(pkts_cnt) - self.logger.info("Verifying capture on interface %s" % - dst_if.name) - self.verify_capture(dst_if, capture, - traffic_type, ip_type, etype) - - def run_verify_negat_test(self, traffic_type=0, ip_type=0, proto=-1, - ports=0, frags=False, etype=-1): - # Test - pkts_cnt = 0 - self.reset_packet_infos() - for i in self.pg_interfaces: - if self.flows.__contains__(i): - pkts = self.create_stream(i, self.pg_if_packet_sizes, - traffic_type, ip_type, proto, ports, - frags, True, etype) - if len(pkts) > 0: - i.add_stream(pkts) - pkts_cnt += len(pkts) - - # Enable packet capture and start packet sending - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - self.logger.info("sent packets count: %d" % pkts_cnt) - - # Verify - # Verify outgoing packet streams per packet-generator interface - for src_if in self.pg_interfaces: - if self.flows.__contains__(src_if): - for dst_if in self.flows[src_if]: - self.logger.info("Verifying capture on interface %s" % - dst_if.name) - capture = dst_if.get_capture(0) - self.assertEqual(len(capture), 0) - - def test_0000_warmup_test(self): - """ ACL plugin version check; learn MACs - """ - reply = self.vapi.papi.acl_plugin_get_version() - self.assertEqual(reply.major, 1) - self.logger.info("Working with ACL plugin version: %d.%d" % ( - reply.major, reply.minor)) - # minor version changes are non breaking - # self.assertEqual(reply.minor, 0) - - def test_0001_acl_create(self): - """ ACL create/delete test - """ - - self.logger.info("ACLP_TEST_START_0001") - # Add an ACL - r = [{'is_permit': 1, 'is_ipv6': 0, 'proto': 17, - 'srcport_or_icmptype_first': 1234, - 'srcport_or_icmptype_last': 1235, - 'src_ip_prefix_len': 0, - 'src_ip_addr': b'\x00\x00\x00\x00', - 'dstport_or_icmpcode_first': 1234, - 'dstport_or_icmpcode_last': 1234, - 'dst_ip_addr': b'\x00\x00\x00\x00', - 'dst_ip_prefix_len': 0}] - # Test 1: add a new ACL - reply = self.vapi.acl_add_replace(acl_index=4294967295, r=r, - tag=b"permit 1234") - self.assertEqual(reply.retval, 0) - # The very first ACL gets #0 - self.assertEqual(reply.acl_index, 0) - first_acl = reply.acl_index - rr = self.vapi.acl_dump(reply.acl_index) - self.logger.info("Dumped ACL: " + str(rr)) - self.assertEqual(len(rr), 1) - # We should have the same number of ACL entries as we had asked - self.assertEqual(len(rr[0].r), len(r)) - # The rules should be the same. But because the submitted and returned - # are different types, we need to iterate over rules and keys to get - # to basic values. - for i_rule in range(0, len(r) - 1): - for rule_key in r[i_rule]: - self.assertEqual(rr[0].r[i_rule][rule_key], - r[i_rule][rule_key]) - - # Add a deny-1234 ACL - r_deny = [{'is_permit': 0, 'is_ipv6': 0, 'proto': 17, - 'srcport_or_icmptype_first': 1234, - 'srcport_or_icmptype_last': 1235, - 'src_ip_prefix_len': 0, - 'src_ip_addr': b'\x00\x00\x00\x00', - 'dstport_or_icmpcode_first': 1234, - 'dstport_or_icmpcode_last': 1234, - 'dst_ip_addr': b'\x00\x00\x00\x00', - 'dst_ip_prefix_len': 0}, - {'is_permit': 1, 'is_ipv6': 0, 'proto': 17, - 'srcport_or_icmptype_first': 0, - 'srcport_or_icmptype_last': 0, - 'src_ip_prefix_len': 0, - 'src_ip_addr': b'\x00\x00\x00\x00', - 'dstport_or_icmpcode_first': 0, - 'dstport_or_icmpcode_last': 0, - 'dst_ip_addr': b'\x00\x00\x00\x00', - 'dst_ip_prefix_len': 0}] - - reply = self.vapi.acl_add_replace(acl_index=4294967295, r=r_deny, - tag=b"deny 1234;permit all") - self.assertEqual(reply.retval, 0) - # The second ACL gets #1 - self.assertEqual(reply.acl_index, 1) - second_acl = reply.acl_index - - # Test 2: try to modify a nonexistent ACL - reply = self.vapi.acl_add_replace(acl_index=432, r=r, - tag=b"FFFF:FFFF", expected_retval=-6) - self.assertEqual(reply.retval, -6) - # The ACL number should pass through - self.assertEqual(reply.acl_index, 432) - # apply an ACL on an interface inbound, try to delete ACL, must fail - self.vapi.acl_interface_set_acl_list(sw_if_index=self.pg0.sw_if_index, - n_input=1, - acls=[first_acl]) - reply = self.vapi.acl_del(acl_index=first_acl, expected_retval=-142) - # Unapply an ACL and then try to delete it - must be ok - self.vapi.acl_interface_set_acl_list(sw_if_index=self.pg0.sw_if_index, - n_input=0, - acls=[]) - reply = self.vapi.acl_del(acl_index=first_acl, expected_retval=0) - - # apply an ACL on an interface outbound, try to delete ACL, must fail - self.vapi.acl_interface_set_acl_list(sw_if_index=self.pg0.sw_if_index, - n_input=0, - acls=[second_acl]) - reply = self.vapi.acl_del(acl_index=second_acl, expected_retval=-143) - # Unapply the ACL and then try to delete it - must be ok - self.vapi.acl_interface_set_acl_list(sw_if_index=self.pg0.sw_if_index, - n_input=0, - acls=[]) - reply = self.vapi.acl_del(acl_index=second_acl, expected_retval=0) - - # try to apply a nonexistent ACL - must fail - self.vapi.acl_interface_set_acl_list(sw_if_index=self.pg0.sw_if_index, - n_input=1, - acls=[first_acl], - expected_retval=-6) - - self.logger.info("ACLP_TEST_FINISH_0001") - - def test_0002_acl_permit_apply(self): - """ permit ACL apply test - """ - self.logger.info("ACLP_TEST_START_0002") - - rules = [] - rules.append(self.create_rule(self.IPV4, self.PERMIT, - 0, self.proto[self.IP][self.UDP])) - rules.append(self.create_rule(self.IPV4, self.PERMIT, - 0, self.proto[self.IP][self.TCP])) - - # Apply rules - acl_idx = self.apply_rules(rules, b"permit per-flow") - - # enable counters - reply = self.vapi.papi.acl_stats_intf_counters_enable(enable=1) - - # Traffic should still pass - self.run_verify_test(self.IP, self.IPV4, -1) - - matches = self.statistics.get_counter('/acl/%d/matches' % acl_idx) - self.logger.info("stat segment counters: %s" % repr(matches)) - cli = "show acl-plugin acl" - self.logger.info(self.vapi.ppcli(cli)) - cli = "show acl-plugin tables" - self.logger.info(self.vapi.ppcli(cli)) - - total_hits = matches[0][0]['packets'] + matches[0][1]['packets'] - self.assertEqual(total_hits, 64) - - # disable counters - reply = self.vapi.papi.acl_stats_intf_counters_enable(enable=0) - - self.logger.info("ACLP_TEST_FINISH_0002") - - def test_0003_acl_deny_apply(self): - """ deny ACL apply test - """ - self.logger.info("ACLP_TEST_START_0003") - # Add a deny-flows ACL - rules = [] - rules.append(self.create_rule(self.IPV4, self.DENY, - self.PORTS_ALL, self.proto[self.IP][self.UDP])) - # Permit ip any any in the end - rules.append(self.create_rule(self.IPV4, self.PERMIT, - self.PORTS_ALL, 0)) - - # Apply rules - acl_idx = self.apply_rules(rules, b"deny per-flow;permit all") - - # enable counters - reply = self.vapi.papi.acl_stats_intf_counters_enable(enable=1) - - # Traffic should not pass - self.run_verify_negat_test(self.IP, self.IPV4, - self.proto[self.IP][self.UDP]) - - matches = self.statistics.get_counter('/acl/%d/matches' % acl_idx) - self.logger.info("stat segment counters: %s" % repr(matches)) - cli = "show acl-plugin acl" - self.logger.info(self.vapi.ppcli(cli)) - cli = "show acl-plugin tables" - self.logger.info(self.vapi.ppcli(cli)) - self.assertEqual(matches[0][0]['packets'], 64) - # disable counters - reply = self.vapi.papi.acl_stats_intf_counters_enable(enable=0) - self.logger.info("ACLP_TEST_FINISH_0003") - # self.assertEqual(, 0) - - def test_0004_vpp624_permit_icmpv4(self): - """ VPP_624 permit ICMPv4 - """ - self.logger.info("ACLP_TEST_START_0004") - - # Add an ACL - rules = [] - rules.append(self.create_rule(self.IPV4, self.PERMIT, self.PORTS_RANGE, - self.proto[self.ICMP][self.ICMPv4])) - # deny ip any any in the end - rules.append(self.create_rule(self.IPV4, self.DENY, self.PORTS_ALL, 0)) - - # Apply rules - self.apply_rules(rules, b"permit icmpv4") - - # Traffic should still pass - self.run_verify_test(self.ICMP, self.IPV4, - self.proto[self.ICMP][self.ICMPv4]) - - self.logger.info("ACLP_TEST_FINISH_0004") - - def test_0005_vpp624_permit_icmpv6(self): - """ VPP_624 permit ICMPv6 - """ - self.logger.info("ACLP_TEST_START_0005") - - # Add an ACL - rules = [] - rules.append(self.create_rule(self.IPV6, self.PERMIT, self.PORTS_RANGE, - self.proto[self.ICMP][self.ICMPv6])) - # deny ip any any in the end - rules.append(self.create_rule(self.IPV6, self.DENY, self.PORTS_ALL, 0)) - - # Apply rules - self.apply_rules(rules, b"permit icmpv6") - - # Traffic should still pass - self.run_verify_test(self.ICMP, self.IPV6, - self.proto[self.ICMP][self.ICMPv6]) - - self.logger.info("ACLP_TEST_FINISH_0005") - - def test_0006_vpp624_deny_icmpv4(self): - """ VPP_624 deny ICMPv4 - """ - self.logger.info("ACLP_TEST_START_0006") - # Add an ACL - rules = [] - rules.append(self.create_rule(self.IPV4, self.DENY, self.PORTS_RANGE, - self.proto[self.ICMP][self.ICMPv4])) - # permit ip any any in the end - rules.append(self.create_rule(self.IPV4, self.PERMIT, - self.PORTS_ALL, 0)) - - # Apply rules - self.apply_rules(rules, b"deny icmpv4") - - # Traffic should not pass - self.run_verify_negat_test(self.ICMP, self.IPV4, 0) - - self.logger.info("ACLP_TEST_FINISH_0006") - - def test_0007_vpp624_deny_icmpv6(self): - """ VPP_624 deny ICMPv6 - """ - self.logger.info("ACLP_TEST_START_0007") - # Add an ACL - rules = [] - rules.append(self.create_rule(self.IPV6, self.DENY, self.PORTS_RANGE, - self.proto[self.ICMP][self.ICMPv6])) - # deny ip any any in the end - rules.append(self.create_rule(self.IPV6, self.PERMIT, - self.PORTS_ALL, 0)) - - # Apply rules - self.apply_rules(rules, b"deny icmpv6") - - # Traffic should not pass - self.run_verify_negat_test(self.ICMP, self.IPV6, 0) - - self.logger.info("ACLP_TEST_FINISH_0007") - - def test_0008_tcp_permit_v4(self): - """ permit TCPv4 - """ - self.logger.info("ACLP_TEST_START_0008") - - # Add an ACL - rules = [] - rules.append(self.create_rule(self.IPV4, self.PERMIT, self.PORTS_RANGE, - self.proto[self.IP][self.TCP])) - # deny ip any any in the end - rules.append(self.create_rule(self.IPV4, self.DENY, self.PORTS_ALL, 0)) - - # Apply rules - self.apply_rules(rules, b"permit ipv4 tcp") - - # Traffic should still pass - self.run_verify_test(self.IP, self.IPV4, self.proto[self.IP][self.TCP]) - - self.logger.info("ACLP_TEST_FINISH_0008") - - def test_0009_tcp_permit_v6(self): - """ permit TCPv6 - """ - self.logger.info("ACLP_TEST_START_0009") - - # Add an ACL - rules = [] - rules.append(self.create_rule(self.IPV6, self.PERMIT, self.PORTS_RANGE, - self.proto[self.IP][self.TCP])) - # deny ip any any in the end - rules.append(self.create_rule(self.IPV6, self.DENY, self.PORTS_ALL, 0)) - - # Apply rules - self.apply_rules(rules, b"permit ip6 tcp") - - # Traffic should still pass - self.run_verify_test(self.IP, self.IPV6, self.proto[self.IP][self.TCP]) - - self.logger.info("ACLP_TEST_FINISH_0008") - - def test_0010_udp_permit_v4(self): - """ permit UDPv4 - """ - self.logger.info("ACLP_TEST_START_0010") - - # Add an ACL - rules = [] - rules.append(self.create_rule(self.IPV4, self.PERMIT, self.PORTS_RANGE, - self.proto[self.IP][self.UDP])) - # deny ip any any in the end - rules.append(self.create_rule(self.IPV4, self.DENY, self.PORTS_ALL, 0)) - - # Apply rules - self.apply_rules(rules, b"permit ipv udp") - - # Traffic should still pass - self.run_verify_test(self.IP, self.IPV4, self.proto[self.IP][self.UDP]) - - self.logger.info("ACLP_TEST_FINISH_0010") - - def test_0011_udp_permit_v6(self): - """ permit UDPv6 - """ - self.logger.info("ACLP_TEST_START_0011") - - # Add an ACL - rules = [] - rules.append(self.create_rule(self.IPV6, self.PERMIT, self.PORTS_RANGE, - self.proto[self.IP][self.UDP])) - # deny ip any any in the end - rules.append(self.create_rule(self.IPV6, self.DENY, self.PORTS_ALL, 0)) - - # Apply rules - self.apply_rules(rules, b"permit ip6 udp") - - # Traffic should still pass - self.run_verify_test(self.IP, self.IPV6, self.proto[self.IP][self.UDP]) - - self.logger.info("ACLP_TEST_FINISH_0011") - - def test_0012_tcp_deny(self): - """ deny TCPv4/v6 - """ - self.logger.info("ACLP_TEST_START_0012") - - # Add an ACL - rules = [] - rules.append(self.create_rule(self.IPV4, self.DENY, self.PORTS_RANGE, - self.proto[self.IP][self.TCP])) - rules.append(self.create_rule(self.IPV6, self.DENY, self.PORTS_RANGE, - self.proto[self.IP][self.TCP])) - # permit ip any any in the end - rules.append(self.create_rule(self.IPV4, self.PERMIT, - self.PORTS_ALL, 0)) - rules.append(self.create_rule(self.IPV6, self.PERMIT, - self.PORTS_ALL, 0)) - - # Apply rules - self.apply_rules(rules, b"deny ip4/ip6 tcp") - - # Traffic should not pass - self.run_verify_negat_test(self.IP, self.IPRANDOM, - self.proto[self.IP][self.TCP]) - - self.logger.info("ACLP_TEST_FINISH_0012") - - def test_0013_udp_deny(self): - """ deny UDPv4/v6 - """ - self.logger.info("ACLP_TEST_START_0013") - - # Add an ACL - rules = [] - rules.append(self.create_rule(self.IPV4, self.DENY, self.PORTS_RANGE, - self.proto[self.IP][self.UDP])) - rules.append(self.create_rule(self.IPV6, self.DENY, self.PORTS_RANGE, - self.proto[self.IP][self.UDP])) - # permit ip any any in the end - rules.append(self.create_rule(self.IPV4, self.PERMIT, - self.PORTS_ALL, 0)) - rules.append(self.create_rule(self.IPV6, self.PERMIT, - self.PORTS_ALL, 0)) - - # Apply rules - self.apply_rules(rules, b"deny ip4/ip6 udp") - - # Traffic should not pass - self.run_verify_negat_test(self.IP, self.IPRANDOM, - self.proto[self.IP][self.UDP]) - - self.logger.info("ACLP_TEST_FINISH_0013") - - def test_0014_acl_dump(self): - """ verify add/dump acls - """ - self.logger.info("ACLP_TEST_START_0014") - - r = [[self.IPV4, self.PERMIT, 1234, self.proto[self.IP][self.TCP]], - [self.IPV4, self.PERMIT, 2345, self.proto[self.IP][self.UDP]], - [self.IPV4, self.PERMIT, 0, self.proto[self.IP][self.TCP]], - [self.IPV4, self.PERMIT, 0, self.proto[self.IP][self.UDP]], - [self.IPV4, self.PERMIT, 5, self.proto[self.ICMP][self.ICMPv4]], - [self.IPV6, self.PERMIT, 4321, self.proto[self.IP][self.TCP]], - [self.IPV6, self.PERMIT, 5432, self.proto[self.IP][self.UDP]], - [self.IPV6, self.PERMIT, 0, self.proto[self.IP][self.TCP]], - [self.IPV6, self.PERMIT, 0, self.proto[self.IP][self.UDP]], - [self.IPV6, self.PERMIT, 6, self.proto[self.ICMP][self.ICMPv6]], - [self.IPV4, self.DENY, self.PORTS_ALL, 0], - [self.IPV4, self.DENY, 1234, self.proto[self.IP][self.TCP]], - [self.IPV4, self.DENY, 2345, self.proto[self.IP][self.UDP]], - [self.IPV4, self.DENY, 5, self.proto[self.ICMP][self.ICMPv4]], - [self.IPV6, self.DENY, 4321, self.proto[self.IP][self.TCP]], - [self.IPV6, self.DENY, 5432, self.proto[self.IP][self.UDP]], - [self.IPV6, self.DENY, 6, self.proto[self.ICMP][self.ICMPv6]], - [self.IPV6, self.DENY, self.PORTS_ALL, 0] - ] - - # Add and verify new ACLs - rules = [] - for i in range(len(r)): - rules.append(self.create_rule(r[i][0], r[i][1], r[i][2], r[i][3])) - - reply = self.vapi.acl_add_replace(acl_index=4294967295, r=rules) - result = self.vapi.acl_dump(reply.acl_index) - - i = 0 - for drules in result: - for dr in drules.r: - self.assertEqual(dr.is_ipv6, r[i][0]) - self.assertEqual(dr.is_permit, r[i][1]) - self.assertEqual(dr.proto, r[i][3]) - - if r[i][2] > 0: - self.assertEqual(dr.srcport_or_icmptype_first, r[i][2]) - else: - if r[i][2] < 0: - self.assertEqual(dr.srcport_or_icmptype_first, 0) - self.assertEqual(dr.srcport_or_icmptype_last, 65535) - else: - if dr.proto == self.proto[self.IP][self.TCP]: - self.assertGreater(dr.srcport_or_icmptype_first, - self.tcp_sport_from-1) - self.assertLess(dr.srcport_or_icmptype_first, - self.tcp_sport_to+1) - self.assertGreater(dr.dstport_or_icmpcode_last, - self.tcp_dport_from-1) - self.assertLess(dr.dstport_or_icmpcode_last, - self.tcp_dport_to+1) - elif dr.proto == self.proto[self.IP][self.UDP]: - self.assertGreater(dr.srcport_or_icmptype_first, - self.udp_sport_from-1) - self.assertLess(dr.srcport_or_icmptype_first, - self.udp_sport_to+1) - self.assertGreater(dr.dstport_or_icmpcode_last, - self.udp_dport_from-1) - self.assertLess(dr.dstport_or_icmpcode_last, - self.udp_dport_to+1) - i += 1 - - self.logger.info("ACLP_TEST_FINISH_0014") - - def test_0015_tcp_permit_port_v4(self): - """ permit single TCPv4 - """ - self.logger.info("ACLP_TEST_START_0015") - - port = random.randint(0, 65535) - # Add an ACL - rules = [] - rules.append(self.create_rule(self.IPV4, self.PERMIT, port, - self.proto[self.IP][self.TCP])) - # deny ip any any in the end - rules.append(self.create_rule(self.IPV4, self.DENY, self.PORTS_ALL, 0)) - - # Apply rules - self.apply_rules(rules, b"permit ip4 tcp %d" % port) - - # Traffic should still pass - self.run_verify_test(self.IP, self.IPV4, - self.proto[self.IP][self.TCP], port) - - self.logger.info("ACLP_TEST_FINISH_0015") - - def test_0016_udp_permit_port_v4(self): - """ permit single UDPv4 - """ - self.logger.info("ACLP_TEST_START_0016") - - port = random.randint(0, 65535) - # Add an ACL - rules = [] - rules.append(self.create_rule(self.IPV4, self.PERMIT, port, - self.proto[self.IP][self.UDP])) - # deny ip any any in the end - rules.append(self.create_rule(self.IPV4, self.DENY, self.PORTS_ALL, 0)) - - # Apply rules - self.apply_rules(rules, b"permit ip4 tcp %d" % port) - - # Traffic should still pass - self.run_verify_test(self.IP, self.IPV4, - self.proto[self.IP][self.UDP], port) - - self.logger.info("ACLP_TEST_FINISH_0016") - - def test_0017_tcp_permit_port_v6(self): - """ permit single TCPv6 - """ - self.logger.info("ACLP_TEST_START_0017") - - port = random.randint(0, 65535) - # Add an ACL - rules = [] - rules.append(self.create_rule(self.IPV6, self.PERMIT, port, - self.proto[self.IP][self.TCP])) - # deny ip any any in the end - rules.append(self.create_rule(self.IPV6, self.DENY, self.PORTS_ALL, 0)) - - # Apply rules - self.apply_rules(rules, b"permit ip4 tcp %d" % port) - - # Traffic should still pass - self.run_verify_test(self.IP, self.IPV6, - self.proto[self.IP][self.TCP], port) - - self.logger.info("ACLP_TEST_FINISH_0017") - - def test_0018_udp_permit_port_v6(self): - """ permit single UPPv6 - """ - self.logger.info("ACLP_TEST_START_0018") - - port = random.randint(0, 65535) - # Add an ACL - rules = [] - rules.append(self.create_rule(self.IPV6, self.PERMIT, port, - self.proto[self.IP][self.UDP])) - # deny ip any any in the end - rules.append(self.create_rule(self.IPV6, self.DENY, - self.PORTS_ALL, 0)) - - # Apply rules - self.apply_rules(rules, b"permit ip4 tcp %d" % port) - - # Traffic should still pass - self.run_verify_test(self.IP, self.IPV6, - self.proto[self.IP][self.UDP], port) - - self.logger.info("ACLP_TEST_FINISH_0018") - - def test_0019_udp_deny_port(self): - """ deny single TCPv4/v6 - """ - self.logger.info("ACLP_TEST_START_0019") - - port = random.randint(0, 65535) - # Add an ACL - rules = [] - rules.append(self.create_rule(self.IPV4, self.DENY, port, - self.proto[self.IP][self.TCP])) - rules.append(self.create_rule(self.IPV6, self.DENY, port, - self.proto[self.IP][self.TCP])) - # Permit ip any any in the end - rules.append(self.create_rule(self.IPV4, self.PERMIT, - self.PORTS_ALL, 0)) - rules.append(self.create_rule(self.IPV6, self.PERMIT, - self.PORTS_ALL, 0)) - - # Apply rules - self.apply_rules(rules, b"deny ip4/ip6 udp %d" % port) - - # Traffic should not pass - self.run_verify_negat_test(self.IP, self.IPRANDOM, - self.proto[self.IP][self.TCP], port) - - self.logger.info("ACLP_TEST_FINISH_0019") - - def test_0020_udp_deny_port(self): - """ deny single UDPv4/v6 - """ - self.logger.info("ACLP_TEST_START_0020") - - port = random.randint(0, 65535) - # Add an ACL - rules = [] - rules.append(self.create_rule(self.IPV4, self.DENY, port, - self.proto[self.IP][self.UDP])) - rules.append(self.create_rule(self.IPV6, self.DENY, port, - self.proto[self.IP][self.UDP])) - # Permit ip any any in the end - rules.append(self.create_rule(self.IPV4, self.PERMIT, - self.PORTS_ALL, 0)) - rules.append(self.create_rule(self.IPV6, self.PERMIT, - self.PORTS_ALL, 0)) - - # Apply rules - self.apply_rules(rules, b"deny ip4/ip6 udp %d" % port) - - # Traffic should not pass - self.run_verify_negat_test(self.IP, self.IPRANDOM, - self.proto[self.IP][self.UDP], port) - - self.logger.info("ACLP_TEST_FINISH_0020") - - def test_0021_udp_deny_port_verify_fragment_deny(self): - """ deny single UDPv4/v6, permit ip any, verify non-initial fragment - blocked - """ - self.logger.info("ACLP_TEST_START_0021") - - port = random.randint(0, 65535) - # Add an ACL - rules = [] - rules.append(self.create_rule(self.IPV4, self.DENY, port, - self.proto[self.IP][self.UDP])) - rules.append(self.create_rule(self.IPV6, self.DENY, port, - self.proto[self.IP][self.UDP])) - # deny ip any any in the end - rules.append(self.create_rule(self.IPV4, self.PERMIT, - self.PORTS_ALL, 0)) - rules.append(self.create_rule(self.IPV6, self.PERMIT, - self.PORTS_ALL, 0)) - - # Apply rules - self.apply_rules(rules, b"deny ip4/ip6 udp %d" % port) - - # Traffic should not pass - self.run_verify_negat_test(self.IP, self.IPRANDOM, - self.proto[self.IP][self.UDP], port, True) - - self.logger.info("ACLP_TEST_FINISH_0021") - - def test_0022_zero_length_udp_ipv4(self): - """ VPP-687 zero length udp ipv4 packet""" - self.logger.info("ACLP_TEST_START_0022") - - port = random.randint(0, 65535) - # Add an ACL - rules = [] - rules.append(self.create_rule(self.IPV4, self.PERMIT, port, - self.proto[self.IP][self.UDP])) - # deny ip any any in the end - rules.append( - self.create_rule(self.IPV4, self.DENY, self.PORTS_ALL, 0)) - - # Apply rules - self.apply_rules(rules, b"permit empty udp ip4 %d" % port) - - # Traffic should still pass - # Create incoming packet streams for packet-generator interfaces - pkts_cnt = 0 - pkts = self.create_stream(self.pg0, self.pg_if_packet_sizes, - self.IP, self.IPV4, - self.proto[self.IP][self.UDP], port, - False, False) - if len(pkts) > 0: - self.pg0.add_stream(pkts) - pkts_cnt += len(pkts) - - # Enable packet capture and start packet sendingself.IPV - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - - self.pg1.get_capture(pkts_cnt) - - self.logger.info("ACLP_TEST_FINISH_0022") - - def test_0023_zero_length_udp_ipv6(self): - """ VPP-687 zero length udp ipv6 packet""" - self.logger.info("ACLP_TEST_START_0023") - - port = random.randint(0, 65535) - # Add an ACL - rules = [] - rules.append(self.create_rule(self.IPV6, self.PERMIT, port, - self.proto[self.IP][self.UDP])) - # deny ip any any in the end - rules.append(self.create_rule(self.IPV6, self.DENY, self.PORTS_ALL, 0)) - - # Apply rules - self.apply_rules(rules, b"permit empty udp ip6 %d" % port) - - # Traffic should still pass - # Create incoming packet streams for packet-generator interfaces - pkts_cnt = 0 - pkts = self.create_stream(self.pg0, self.pg_if_packet_sizes, - self.IP, self.IPV6, - self.proto[self.IP][self.UDP], port, - False, False) - if len(pkts) > 0: - self.pg0.add_stream(pkts) - pkts_cnt += len(pkts) - - # Enable packet capture and start packet sendingself.IPV - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - - # Verify outgoing packet streams per packet-generator interface - self.pg1.get_capture(pkts_cnt) - - self.logger.info("ACLP_TEST_FINISH_0023") - - def test_0108_tcp_permit_v4(self): - """ permit TCPv4 + non-match range - """ - self.logger.info("ACLP_TEST_START_0108") - - # Add an ACL - rules = [] - rules.append(self.create_rule(self.IPV4, self.DENY, self.PORTS_RANGE_2, - self.proto[self.IP][self.TCP])) - rules.append(self.create_rule(self.IPV4, self.PERMIT, self.PORTS_RANGE, - self.proto[self.IP][self.TCP])) - # deny ip any any in the end - rules.append(self.create_rule(self.IPV4, self.DENY, self.PORTS_ALL, 0)) - - # Apply rules - self.apply_rules(rules, b"permit ipv4 tcp") - - # Traffic should still pass - self.run_verify_test(self.IP, self.IPV4, self.proto[self.IP][self.TCP]) - - self.logger.info("ACLP_TEST_FINISH_0108") - - def test_0109_tcp_permit_v6(self): - """ permit TCPv6 + non-match range - """ - self.logger.info("ACLP_TEST_START_0109") - - # Add an ACL - rules = [] - rules.append(self.create_rule(self.IPV6, self.DENY, self.PORTS_RANGE_2, - self.proto[self.IP][self.TCP])) - rules.append(self.create_rule(self.IPV6, self.PERMIT, self.PORTS_RANGE, - self.proto[self.IP][self.TCP])) - # deny ip any any in the end - rules.append(self.create_rule(self.IPV6, self.DENY, self.PORTS_ALL, 0)) - - # Apply rules - self.apply_rules(rules, b"permit ip6 tcp") - - # Traffic should still pass - self.run_verify_test(self.IP, self.IPV6, self.proto[self.IP][self.TCP]) - - self.logger.info("ACLP_TEST_FINISH_0109") - - def test_0110_udp_permit_v4(self): - """ permit UDPv4 + non-match range - """ - self.logger.info("ACLP_TEST_START_0110") - - # Add an ACL - rules = [] - rules.append(self.create_rule(self.IPV4, self.DENY, self.PORTS_RANGE_2, - self.proto[self.IP][self.UDP])) - rules.append(self.create_rule(self.IPV4, self.PERMIT, self.PORTS_RANGE, - self.proto[self.IP][self.UDP])) - # deny ip any any in the end - rules.append(self.create_rule(self.IPV4, self.DENY, self.PORTS_ALL, 0)) - - # Apply rules - self.apply_rules(rules, b"permit ipv4 udp") - - # Traffic should still pass - self.run_verify_test(self.IP, self.IPV4, self.proto[self.IP][self.UDP]) - - self.logger.info("ACLP_TEST_FINISH_0110") - - def test_0111_udp_permit_v6(self): - """ permit UDPv6 + non-match range - """ - self.logger.info("ACLP_TEST_START_0111") - - # Add an ACL - rules = [] - rules.append(self.create_rule(self.IPV6, self.DENY, self.PORTS_RANGE_2, - self.proto[self.IP][self.UDP])) - rules.append(self.create_rule(self.IPV6, self.PERMIT, self.PORTS_RANGE, - self.proto[self.IP][self.UDP])) - # deny ip any any in the end - rules.append(self.create_rule(self.IPV6, self.DENY, self.PORTS_ALL, 0)) - - # Apply rules - self.apply_rules(rules, b"permit ip6 udp") - - # Traffic should still pass - self.run_verify_test(self.IP, self.IPV6, self.proto[self.IP][self.UDP]) - - self.logger.info("ACLP_TEST_FINISH_0111") - - def test_0112_tcp_deny(self): - """ deny TCPv4/v6 + non-match range - """ - self.logger.info("ACLP_TEST_START_0112") - - # Add an ACL - rules = [] - rules.append(self.create_rule(self.IPV4, self.PERMIT, - self.PORTS_RANGE_2, - self.proto[self.IP][self.TCP])) - rules.append(self.create_rule(self.IPV6, self.PERMIT, - self.PORTS_RANGE_2, - self.proto[self.IP][self.TCP])) - rules.append(self.create_rule(self.IPV4, self.DENY, self.PORTS_RANGE, - self.proto[self.IP][self.TCP])) - rules.append(self.create_rule(self.IPV6, self.DENY, self.PORTS_RANGE, - self.proto[self.IP][self.TCP])) - # permit ip any any in the end - rules.append(self.create_rule(self.IPV4, self.PERMIT, - self.PORTS_ALL, 0)) - rules.append(self.create_rule(self.IPV6, self.PERMIT, - self.PORTS_ALL, 0)) - - # Apply rules - self.apply_rules(rules, b"deny ip4/ip6 tcp") - - # Traffic should not pass - self.run_verify_negat_test(self.IP, self.IPRANDOM, - self.proto[self.IP][self.TCP]) - - self.logger.info("ACLP_TEST_FINISH_0112") - - def test_0113_udp_deny(self): - """ deny UDPv4/v6 + non-match range - """ - self.logger.info("ACLP_TEST_START_0113") - - # Add an ACL - rules = [] - rules.append(self.create_rule(self.IPV4, self.PERMIT, - self.PORTS_RANGE_2, - self.proto[self.IP][self.UDP])) - rules.append(self.create_rule(self.IPV6, self.PERMIT, - self.PORTS_RANGE_2, - self.proto[self.IP][self.UDP])) - rules.append(self.create_rule(self.IPV4, self.DENY, self.PORTS_RANGE, - self.proto[self.IP][self.UDP])) - rules.append(self.create_rule(self.IPV6, self.DENY, self.PORTS_RANGE, - self.proto[self.IP][self.UDP])) - # permit ip any any in the end - rules.append(self.create_rule(self.IPV4, self.PERMIT, - self.PORTS_ALL, 0)) - rules.append(self.create_rule(self.IPV6, self.PERMIT, - self.PORTS_ALL, 0)) - - # Apply rules - self.apply_rules(rules, b"deny ip4/ip6 udp") - - # Traffic should not pass - self.run_verify_negat_test(self.IP, self.IPRANDOM, - self.proto[self.IP][self.UDP]) - - self.logger.info("ACLP_TEST_FINISH_0113") - - def test_0300_tcp_permit_v4_etype_aaaa(self): - """ permit TCPv4, send 0xAAAA etype - """ - self.logger.info("ACLP_TEST_START_0300") - - # Add an ACL - rules = [] - rules.append(self.create_rule(self.IPV4, self.DENY, self.PORTS_RANGE_2, - self.proto[self.IP][self.TCP])) - rules.append(self.create_rule(self.IPV4, self.PERMIT, self.PORTS_RANGE, - self.proto[self.IP][self.TCP])) - # deny ip any any in the end - rules.append(self.create_rule(self.IPV4, self.DENY, self.PORTS_ALL, 0)) - - # Apply rules - self.apply_rules(rules, b"permit ipv4 tcp") - - # Traffic should still pass also for an odd ethertype - self.run_verify_test(self.IP, self.IPV4, self.proto[self.IP][self.TCP], - 0, False, True, 0xaaaa) - self.logger.info("ACLP_TEST_FINISH_0300") - - def test_0305_tcp_permit_v4_etype_blacklist_aaaa(self): - """ permit TCPv4, whitelist 0x0BBB ethertype, send 0xAAAA-blocked - """ - self.logger.info("ACLP_TEST_START_0305") - - # Add an ACL - rules = [] - rules.append(self.create_rule(self.IPV4, self.DENY, self.PORTS_RANGE_2, - self.proto[self.IP][self.TCP])) - rules.append(self.create_rule(self.IPV4, self.PERMIT, self.PORTS_RANGE, - self.proto[self.IP][self.TCP])) - # deny ip any any in the end - rules.append(self.create_rule(self.IPV4, self.DENY, self.PORTS_ALL, 0)) - - # Apply rules - self.apply_rules(rules, b"permit ipv4 tcp") - - # whitelist the 0xbbbb etype - so the 0xaaaa should be blocked - self.etype_whitelist([0xbbb], 1) - - # The oddball ethertype should be blocked - self.run_verify_negat_test(self.IP, self.IPV4, - self.proto[self.IP][self.TCP], - 0, False, 0xaaaa) - - # remove the whitelist - self.etype_whitelist([], 0) - - self.logger.info("ACLP_TEST_FINISH_0305") - - def test_0306_tcp_permit_v4_etype_blacklist_aaaa(self): - """ permit TCPv4, whitelist 0x0BBB ethertype, send 0x0BBB - pass - """ - self.logger.info("ACLP_TEST_START_0306") - - # Add an ACL - rules = [] - rules.append(self.create_rule(self.IPV4, self.DENY, self.PORTS_RANGE_2, - self.proto[self.IP][self.TCP])) - rules.append(self.create_rule(self.IPV4, self.PERMIT, self.PORTS_RANGE, - self.proto[self.IP][self.TCP])) - # deny ip any any in the end - rules.append(self.create_rule(self.IPV4, self.DENY, self.PORTS_ALL, 0)) - - # Apply rules - self.apply_rules(rules, b"permit ipv4 tcp") - - # whitelist the 0xbbbb etype - so the 0xaaaa should be blocked - self.etype_whitelist([0xbbb], 1) - - # The whitelisted traffic, should pass - self.run_verify_test(self.IP, self.IPV4, self.proto[self.IP][self.TCP], - 0, False, True, 0x0bbb) - - # remove the whitelist, the previously blocked 0xAAAA should pass now - self.etype_whitelist([], 0) - - self.logger.info("ACLP_TEST_FINISH_0306") - - def test_0307_tcp_permit_v4_etype_blacklist_aaaa(self): - """ permit TCPv4, whitelist 0x0BBB, remove, send 0xAAAA - pass - """ - self.logger.info("ACLP_TEST_START_0307") - - # Add an ACL - rules = [] - rules.append(self.create_rule(self.IPV4, self.DENY, self.PORTS_RANGE_2, - self.proto[self.IP][self.TCP])) - rules.append(self.create_rule(self.IPV4, self.PERMIT, self.PORTS_RANGE, - self.proto[self.IP][self.TCP])) - # deny ip any any in the end - rules.append(self.create_rule(self.IPV4, self.DENY, self.PORTS_ALL, 0)) - - # Apply rules - self.apply_rules(rules, b"permit ipv4 tcp") - - # whitelist the 0xbbbb etype - so the 0xaaaa should be blocked - self.etype_whitelist([0xbbb], 1) - # remove the whitelist, the previously blocked 0xAAAA should pass now - self.etype_whitelist([], 0) - - # The whitelisted traffic, should pass - self.run_verify_test(self.IP, self.IPV4, self.proto[self.IP][self.TCP], - 0, False, True, 0xaaaa) - - self.logger.info("ACLP_TEST_FINISH_0306") - - def test_0315_del_intf(self): - """ apply an acl and delete the interface - """ - self.logger.info("ACLP_TEST_START_0315") - - # Add an ACL - rules = [] - rules.append(self.create_rule(self.IPV4, self.DENY, self.PORTS_RANGE_2, - self.proto[self.IP][self.TCP])) - rules.append(self.create_rule(self.IPV4, self.PERMIT, self.PORTS_RANGE, - self.proto[self.IP][self.TCP])) - # deny ip any any in the end - rules.append(self.create_rule(self.IPV4, self.DENY, self.PORTS_ALL, 0)) - - # create an interface - intf = [] - intf.append(VppLoInterface(self)) - - # Apply rules - self.apply_rules_to(rules, b"permit ipv4 tcp", intf[0].sw_if_index) - - # Remove the interface - intf[0].remove_vpp_config() - - self.logger.info("ACLP_TEST_FINISH_0315") - -if __name__ == '__main__': - unittest.main(testRunner=VppTestRunner) diff --git a/test/test_acl_plugin_conns.py b/test/test_acl_plugin_conns.py deleted file mode 100644 index 58c44e68262..00000000000 --- a/test/test_acl_plugin_conns.py +++ /dev/null @@ -1,411 +0,0 @@ -#!/usr/bin/env python -""" ACL plugin extended stateful tests """ - -import unittest -from framework import VppTestCase, VppTestRunner, running_extended_tests -from scapy.layers.l2 import Ether -from scapy.packet import Raw -from scapy.layers.inet import IP, UDP, TCP -from scapy.packet import Packet -from socket import inet_pton, AF_INET, AF_INET6 -from scapy.layers.inet6 import IPv6, ICMPv6Unknown, ICMPv6EchoRequest -from scapy.layers.inet6 import ICMPv6EchoReply, IPv6ExtHdrRouting -from scapy.layers.inet6 import IPv6ExtHdrFragment -from pprint import pprint -from random import randint -from util import L4_Conn - - -def to_acl_rule(self, is_permit, wildcard_sport=False): - p = self - rule_family = AF_INET6 if p.haslayer(IPv6) else AF_INET - rule_prefix_len = 128 if p.haslayer(IPv6) else 32 - rule_l3_layer = IPv6 if p.haslayer(IPv6) else IP - rule_l4_sport = p.sport - rule_l4_dport = p.dport - if p.haslayer(IPv6): - rule_l4_proto = p[IPv6].nh - else: - rule_l4_proto = p[IP].proto - - if wildcard_sport: - rule_l4_sport_first = 0 - rule_l4_sport_last = 65535 - else: - rule_l4_sport_first = rule_l4_sport - rule_l4_sport_last = rule_l4_sport - - new_rule = { - 'is_permit': is_permit, - 'is_ipv6': p.haslayer(IPv6), - 'src_ip_addr': inet_pton(rule_family, - p[rule_l3_layer].src), - 'src_ip_prefix_len': rule_prefix_len, - 'dst_ip_addr': inet_pton(rule_family, - p[rule_l3_layer].dst), - 'dst_ip_prefix_len': rule_prefix_len, - 'srcport_or_icmptype_first': rule_l4_sport_first, - 'srcport_or_icmptype_last': rule_l4_sport_last, - 'dstport_or_icmpcode_first': rule_l4_dport, - 'dstport_or_icmpcode_last': rule_l4_dport, - 'proto': rule_l4_proto, - } - return new_rule - -Packet.to_acl_rule = to_acl_rule - - -class IterateWithSleep(): - def __init__(self, testcase, n_iters, description, sleep_sec): - self.curr = 0 - self.testcase = testcase - self.n_iters = n_iters - self.sleep_sec = sleep_sec - self.description = description - - def __iter__(self): - for x in range(0, self.n_iters): - yield x - self.testcase.sleep(self.sleep_sec) - - -class Conn(L4_Conn): - def apply_acls(self, reflect_side, acl_side): - pkts = [] - pkts.append(self.pkt(0)) - pkts.append(self.pkt(1)) - pkt = pkts[reflect_side] - - r = [] - r.append(pkt.to_acl_rule(2, wildcard_sport=True)) - r.append(self.wildcard_rule(0)) - res = self.testcase.vapi.acl_add_replace(0xffffffff, r) - self.testcase.assert_equal(res.retval, 0, "error adding ACL") - reflect_acl_index = res.acl_index - - r = [] - r.append(self.wildcard_rule(0)) - res = self.testcase.vapi.acl_add_replace(0xffffffff, r) - self.testcase.assert_equal(res.retval, 0, "error adding deny ACL") - deny_acl_index = res.acl_index - - if reflect_side == acl_side: - self.testcase.vapi.acl_interface_set_acl_list( - self.ifs[acl_side].sw_if_index, 1, - [reflect_acl_index, - deny_acl_index]) - self.testcase.vapi.acl_interface_set_acl_list( - self.ifs[1-acl_side].sw_if_index, 0, []) - else: - self.testcase.vapi.acl_interface_set_acl_list( - self.ifs[acl_side].sw_if_index, 1, - [deny_acl_index, - reflect_acl_index]) - self.testcase.vapi.acl_interface_set_acl_list( - self.ifs[1-acl_side].sw_if_index, 0, []) - - def wildcard_rule(self, is_permit): - any_addr = ["0.0.0.0", "::"] - rule_family = self.address_family - is_ip6 = 1 if rule_family == AF_INET6 else 0 - new_rule = { - 'is_permit': is_permit, - 'is_ipv6': is_ip6, - 'src_ip_addr': inet_pton(rule_family, any_addr[is_ip6]), - 'src_ip_prefix_len': 0, - 'dst_ip_addr': inet_pton(rule_family, any_addr[is_ip6]), - 'dst_ip_prefix_len': 0, - 'srcport_or_icmptype_first': 0, - 'srcport_or_icmptype_last': 65535, - 'dstport_or_icmpcode_first': 0, - 'dstport_or_icmpcode_last': 65535, - 'proto': 0, - } - return new_rule - - -@unittest.skipUnless(running_extended_tests, "part of extended tests") -class ACLPluginConnTestCase(VppTestCase): - """ ACL plugin connection-oriented extended testcases """ - - @classmethod - def setUpClass(cls): - super(ACLPluginConnTestCase, cls).setUpClass() - # create pg0 and pg1 - cls.create_pg_interfaces(range(2)) - cmd = "set acl-plugin session table event-trace 1" - cls.logger.info(cls.vapi.cli(cmd)) - for i in cls.pg_interfaces: - i.admin_up() - i.config_ip4() - i.config_ip6() - i.resolve_arp() - i.resolve_ndp() - - @classmethod - def tearDownClass(cls): - super(ACLPluginConnTestCase, cls).tearDownClass() - - def tearDown(self): - """Run standard test teardown and log various show commands - """ - super(ACLPluginConnTestCase, self).tearDown() - - def show_commands_at_teardown(self): - self.logger.info(self.vapi.cli("show ip arp")) - self.logger.info(self.vapi.cli("show ip6 neighbors")) - self.logger.info(self.vapi.cli("show acl-plugin sessions")) - self.logger.info(self.vapi.cli("show acl-plugin acl")) - self.logger.info(self.vapi.cli("show acl-plugin interface")) - self.logger.info(self.vapi.cli("show acl-plugin tables")) - self.logger.info(self.vapi.cli("show event-logger all")) - - def run_basic_conn_test(self, af, acl_side): - """ Basic conn timeout test """ - conn1 = Conn(self, self.pg0, self.pg1, af, UDP, 42001, 4242) - conn1.apply_acls(0, acl_side) - conn1.send_through(0) - # the return packets should pass - conn1.send_through(1) - # send some packets on conn1, ensure it doesn't go away - for i in IterateWithSleep(self, 20, "Keep conn active", 0.3): - conn1.send_through(1) - # allow the conn to time out - for i in IterateWithSleep(self, 30, "Wait for timeout", 0.1): - pass - # now try to send a packet on the reflected side - try: - p2 = conn1.send_through(1).command() - except: - # If we asserted while waiting, it's good. - # the conn should have timed out. - p2 = None - self.assert_equal(p2, None, "packet on long-idle conn") - - def run_active_conn_test(self, af, acl_side): - """ Idle connection behind active connection test """ - base = 10000 + 1000*acl_side - conn1 = Conn(self, self.pg0, self.pg1, af, UDP, base + 1, 2323) - conn2 = Conn(self, self.pg0, self.pg1, af, UDP, base + 2, 2323) - conn3 = Conn(self, self.pg0, self.pg1, af, UDP, base + 3, 2323) - conn1.apply_acls(0, acl_side) - conn1.send(0) - conn1.recv(1) - # create and check that the conn2/3 work - self.sleep(0.1) - conn2.send_pingpong(0) - self.sleep(0.1) - conn3.send_pingpong(0) - # send some packets on conn1, keep conn2/3 idle - for i in IterateWithSleep(self, 20, "Keep conn active", 0.2): - conn1.send_through(1) - try: - p2 = conn2.send_through(1).command() - except: - # If we asserted while waiting, it's good. - # the conn should have timed out. - p2 = None - # We should have not received the packet on a long-idle - # connection, because it should have timed out - # If it didn't - it is a problem - self.assert_equal(p2, None, "packet on long-idle conn") - - def run_clear_conn_test(self, af, acl_side): - """ Clear the connections via CLI """ - conn1 = Conn(self, self.pg0, self.pg1, af, UDP, 42001, 4242) - conn1.apply_acls(0, acl_side) - conn1.send_through(0) - # the return packets should pass - conn1.send_through(1) - # send some packets on conn1, ensure it doesn't go away - for i in IterateWithSleep(self, 20, "Keep conn active", 0.3): - conn1.send_through(1) - # clear all connections - self.vapi.ppcli("clear acl-plugin sessions") - # now try to send a packet on the reflected side - try: - p2 = conn1.send_through(1).command() - except: - # If we asserted while waiting, it's good. - # the conn should have timed out. - p2 = None - self.assert_equal(p2, None, "packet on supposedly deleted conn") - - def run_tcp_transient_setup_conn_test(self, af, acl_side): - conn1 = Conn(self, self.pg0, self.pg1, af, TCP, 53001, 5151) - conn1.apply_acls(0, acl_side) - conn1.send_through(0, 'S') - # the return packets should pass - conn1.send_through(1, 'SA') - # allow the conn to time out - for i in IterateWithSleep(self, 30, "Wait for timeout", 0.1): - pass - # ensure conn times out - try: - p2 = conn1.send_through(1).command() - except: - # If we asserted while waiting, it's good. - # the conn should have timed out. - p2 = None - self.assert_equal(p2, None, "packet on supposedly deleted conn") - - def run_tcp_established_conn_test(self, af, acl_side): - conn1 = Conn(self, self.pg0, self.pg1, af, TCP, 53002, 5052) - conn1.apply_acls(0, acl_side) - conn1.send_through(0, 'S') - # the return packets should pass - conn1.send_through(1, 'SA') - # complete the threeway handshake - # (NB: sequence numbers not tracked, so not set!) - conn1.send_through(0, 'A') - # allow the conn to time out if it's in embryonic timer - for i in IterateWithSleep(self, 30, "Wait for transient timeout", 0.1): - pass - # Try to send the packet from the "forbidden" side - it must pass - conn1.send_through(1, 'A') - # ensure conn times out for real - for i in IterateWithSleep(self, 130, "Wait for timeout", 0.1): - pass - try: - p2 = conn1.send_through(1).command() - except: - # If we asserted while waiting, it's good. - # the conn should have timed out. - p2 = None - self.assert_equal(p2, None, "packet on supposedly deleted conn") - - def run_tcp_transient_teardown_conn_test(self, af, acl_side): - conn1 = Conn(self, self.pg0, self.pg1, af, TCP, 53002, 5052) - conn1.apply_acls(0, acl_side) - conn1.send_through(0, 'S') - # the return packets should pass - conn1.send_through(1, 'SA') - # complete the threeway handshake - # (NB: sequence numbers not tracked, so not set!) - conn1.send_through(0, 'A') - # allow the conn to time out if it's in embryonic timer - for i in IterateWithSleep(self, 30, "Wait for transient timeout", 0.1): - pass - # Try to send the packet from the "forbidden" side - it must pass - conn1.send_through(1, 'A') - # Send the FIN to bounce the session out of established - conn1.send_through(1, 'FA') - # If conn landed on transient timer it will time out here - for i in IterateWithSleep(self, 30, "Wait for transient timeout", 0.1): - pass - # Now it should have timed out already - try: - p2 = conn1.send_through(1).command() - except: - # If we asserted while waiting, it's good. - # the conn should have timed out. - p2 = None - self.assert_equal(p2, None, "packet on supposedly deleted conn") - - def test_0000_conn_prepare_test(self): - """ Prepare the settings """ - self.vapi.ppcli("set acl-plugin session timeout udp idle 1") - - def test_0001_basic_conn_test(self): - """ IPv4: Basic conn timeout test reflect on ingress """ - self.run_basic_conn_test(AF_INET, 0) - - def test_0002_basic_conn_test(self): - """ IPv4: Basic conn timeout test reflect on egress """ - self.run_basic_conn_test(AF_INET, 1) - - def test_0005_clear_conn_test(self): - """ IPv4: reflect egress, clear conn """ - self.run_clear_conn_test(AF_INET, 1) - - def test_0006_clear_conn_test(self): - """ IPv4: reflect ingress, clear conn """ - self.run_clear_conn_test(AF_INET, 0) - - def test_0011_active_conn_test(self): - """ IPv4: Idle conn behind active conn, reflect on ingress """ - self.run_active_conn_test(AF_INET, 0) - - def test_0012_active_conn_test(self): - """ IPv4: Idle conn behind active conn, reflect on egress """ - self.run_active_conn_test(AF_INET, 1) - - def test_1001_basic_conn_test(self): - """ IPv6: Basic conn timeout test reflect on ingress """ - self.run_basic_conn_test(AF_INET6, 0) - - def test_1002_basic_conn_test(self): - """ IPv6: Basic conn timeout test reflect on egress """ - self.run_basic_conn_test(AF_INET6, 1) - - def test_1005_clear_conn_test(self): - """ IPv6: reflect egress, clear conn """ - self.run_clear_conn_test(AF_INET6, 1) - - def test_1006_clear_conn_test(self): - """ IPv6: reflect ingress, clear conn """ - self.run_clear_conn_test(AF_INET6, 0) - - def test_1011_active_conn_test(self): - """ IPv6: Idle conn behind active conn, reflect on ingress """ - self.run_active_conn_test(AF_INET6, 0) - - def test_1012_active_conn_test(self): - """ IPv6: Idle conn behind active conn, reflect on egress """ - self.run_active_conn_test(AF_INET6, 1) - - def test_2000_prepare_for_tcp_test(self): - """ Prepare for TCP session tests """ - # ensure the session hangs on if it gets treated as UDP - self.vapi.ppcli("set acl-plugin session timeout udp idle 200") - # let the TCP connection time out at 5 seconds - self.vapi.ppcli("set acl-plugin session timeout tcp idle 10") - self.vapi.ppcli("set acl-plugin session timeout tcp transient 1") - - def test_2001_tcp_transient_conn_test(self): - """ IPv4: transient TCP session (incomplete 3WHS), ref. on ingress """ - self.run_tcp_transient_setup_conn_test(AF_INET, 0) - - def test_2002_tcp_transient_conn_test(self): - """ IPv4: transient TCP session (incomplete 3WHS), ref. on egress """ - self.run_tcp_transient_setup_conn_test(AF_INET, 1) - - def test_2003_tcp_transient_conn_test(self): - """ IPv4: established TCP session (complete 3WHS), ref. on ingress """ - self.run_tcp_established_conn_test(AF_INET, 0) - - def test_2004_tcp_transient_conn_test(self): - """ IPv4: established TCP session (complete 3WHS), ref. on egress """ - self.run_tcp_established_conn_test(AF_INET, 1) - - def test_2005_tcp_transient_teardown_conn_test(self): - """ IPv4: transient TCP session (3WHS,ACK,FINACK), ref. on ingress """ - self.run_tcp_transient_teardown_conn_test(AF_INET, 0) - - def test_2006_tcp_transient_teardown_conn_test(self): - """ IPv4: transient TCP session (3WHS,ACK,FINACK), ref. on egress """ - self.run_tcp_transient_teardown_conn_test(AF_INET, 1) - - def test_3001_tcp_transient_conn_test(self): - """ IPv6: transient TCP session (incomplete 3WHS), ref. on ingress """ - self.run_tcp_transient_setup_conn_test(AF_INET6, 0) - - def test_3002_tcp_transient_conn_test(self): - """ IPv6: transient TCP session (incomplete 3WHS), ref. on egress """ - self.run_tcp_transient_setup_conn_test(AF_INET6, 1) - - def test_3003_tcp_transient_conn_test(self): - """ IPv6: established TCP session (complete 3WHS), ref. on ingress """ - self.run_tcp_established_conn_test(AF_INET6, 0) - - def test_3004_tcp_transient_conn_test(self): - """ IPv6: established TCP session (complete 3WHS), ref. on egress """ - self.run_tcp_established_conn_test(AF_INET6, 1) - - def test_3005_tcp_transient_teardown_conn_test(self): - """ IPv6: transient TCP session (3WHS,ACK,FINACK), ref. on ingress """ - self.run_tcp_transient_teardown_conn_test(AF_INET6, 0) - - def test_3006_tcp_transient_teardown_conn_test(self): - """ IPv6: transient TCP session (3WHS,ACK,FINACK), ref. on egress """ - self.run_tcp_transient_teardown_conn_test(AF_INET6, 1) diff --git a/test/test_acl_plugin_l2l3.py b/test/test_acl_plugin_l2l3.py deleted file mode 100644 index 31b4058fc69..00000000000 --- a/test/test_acl_plugin_l2l3.py +++ /dev/null @@ -1,871 +0,0 @@ -#!/usr/bin/env python -"""ACL IRB Test Case HLD: - -**config** - - L2 MAC learning enabled in l2bd - - 2 routed interfaces untagged, bvi (Bridge Virtual Interface) - - 2 bridged interfaces in l2bd with bvi - -**test** - - sending ip4 eth pkts between routed interfaces - - 2 routed interfaces - - 2 bridged interfaces - - - 64B, 512B, 1518B, 9200B (ether_size) - - - burst of pkts per interface - - 257pkts per burst - - routed pkts hitting different FIB entries - - bridged pkts hitting different MAC entries - -**verify** - - all packets received correctly - -""" - -import unittest -from socket import inet_pton, AF_INET, AF_INET6 -from random import choice, shuffle -from pprint import pprint - -import scapy.compat -from scapy.packet import Raw -from scapy.layers.l2 import Ether -from scapy.layers.inet import IP, UDP, ICMP, TCP -from scapy.layers.inet6 import IPv6, ICMPv6Unknown, ICMPv6EchoRequest -from scapy.layers.inet6 import ICMPv6EchoReply, IPv6ExtHdrRouting -from scapy.layers.inet6 import IPv6ExtHdrFragment - -from framework import VppTestCase, VppTestRunner -from vpp_l2 import L2_PORT_TYPE -import time - - -class TestACLpluginL2L3(VppTestCase): - """TestACLpluginL2L3 Test Case""" - - @classmethod - def setUpClass(cls): - """ - #. Create BD with MAC learning enabled and put interfaces to this BD. - #. Configure IPv4 addresses on loopback interface and routed interface. - #. Configure MAC address binding to IPv4 neighbors on loop0. - #. Configure MAC address on pg2. - #. Loopback BVI interface has remote hosts, one half of hosts are - behind pg0 second behind pg1. - """ - super(TestACLpluginL2L3, cls).setUpClass() - - cls.pg_if_packet_sizes = [64, 512, 1518, 9018] # packet sizes - cls.bd_id = 10 - cls.remote_hosts_count = 250 - - # create 3 pg interfaces, 1 loopback interface - cls.create_pg_interfaces(range(3)) - cls.create_loopback_interfaces(1) - - cls.interfaces = list(cls.pg_interfaces) - cls.interfaces.extend(cls.lo_interfaces) - - for i in cls.interfaces: - i.admin_up() - - # Create BD with MAC learning enabled and put interfaces to this BD - cls.vapi.sw_interface_set_l2_bridge( - rx_sw_if_index=cls.loop0.sw_if_index, bd_id=cls.bd_id, - port_type=L2_PORT_TYPE.BVI) - cls.vapi.sw_interface_set_l2_bridge(rx_sw_if_index=cls.pg0.sw_if_index, - bd_id=cls.bd_id) - cls.vapi.sw_interface_set_l2_bridge(rx_sw_if_index=cls.pg1.sw_if_index, - bd_id=cls.bd_id) - - # Configure IPv4 addresses on loopback interface and routed interface - cls.loop0.config_ip4() - cls.loop0.config_ip6() - cls.pg2.config_ip4() - cls.pg2.config_ip6() - - # Configure MAC address binding to IPv4 neighbors on loop0 - cls.loop0.generate_remote_hosts(cls.remote_hosts_count) - cls.loop0.configure_ipv4_neighbors() - cls.loop0.configure_ipv6_neighbors() - # configure MAC address on pg2 - cls.pg2.resolve_arp() - cls.pg2.resolve_ndp() - - cls.WITHOUT_EH = False - cls.WITH_EH = True - cls.STATELESS_ICMP = False - cls.STATEFUL_ICMP = True - - # Loopback BVI interface has remote hosts, one half of hosts are behind - # pg0 second behind pg1 - half = cls.remote_hosts_count // 2 - cls.pg0.remote_hosts = cls.loop0.remote_hosts[:half] - cls.pg1.remote_hosts = cls.loop0.remote_hosts[half:] - reply = cls.vapi.papi.acl_stats_intf_counters_enable(enable=1) - - @classmethod - def tearDownClass(cls): - reply = cls.vapi.papi.acl_stats_intf_counters_enable(enable=0) - super(TestACLpluginL2L3, cls).tearDownClass() - - def tearDown(self): - """Run standard test teardown and log ``show l2patch``, - ``show l2fib verbose``,``show bridge-domain <bd_id> detail``, - ``show ip arp``. - """ - super(TestACLpluginL2L3, self).tearDown() - - def show_commands_at_teardown(self): - self.logger.info(self.vapi.cli("show l2patch")) - self.logger.info(self.vapi.cli("show classify tables")) - self.logger.info(self.vapi.cli("show l2fib verbose")) - self.logger.info(self.vapi.cli("show bridge-domain %s detail" % - self.bd_id)) - self.logger.info(self.vapi.cli("show ip arp")) - self.logger.info(self.vapi.cli("show ip6 neighbors")) - cmd = "show acl-plugin sessions verbose 1" - self.logger.info(self.vapi.cli(cmd)) - self.logger.info(self.vapi.cli("show acl-plugin acl")) - self.logger.info(self.vapi.cli("show acl-plugin interface")) - self.logger.info(self.vapi.cli("show acl-plugin tables")) - - def create_stream(self, src_ip_if, dst_ip_if, reverse, packet_sizes, - is_ip6, expect_blocked, expect_established, - add_extension_header, icmp_stateful=False): - pkts = [] - rules = [] - permit_rules = [] - permit_and_reflect_rules = [] - total_packet_count = 8 - for i in range(0, total_packet_count): - modulo = (i//2) % 2 - icmp_type_delta = i % 2 - icmp_code = i - is_udp_packet = (modulo == 0) - if is_udp_packet and icmp_stateful: - continue - is_reflectable_icmp = (icmp_stateful and icmp_type_delta == 0 and - not is_udp_packet) - is_reflected_icmp = is_reflectable_icmp and expect_established - can_reflect_this_packet = is_udp_packet or is_reflectable_icmp - is_permit = i % 2 - remote_dst_index = i % len(dst_ip_if.remote_hosts) - remote_dst_host = dst_ip_if.remote_hosts[remote_dst_index] - if is_permit == 1: - info = self.create_packet_info(src_ip_if, dst_ip_if) - payload = self.info_to_payload(info) - else: - to_be_blocked = False - if (expect_blocked and not expect_established): - to_be_blocked = True - if (not can_reflect_this_packet): - to_be_blocked = True - if to_be_blocked: - payload = "to be blocked" - else: - info = self.create_packet_info(src_ip_if, dst_ip_if) - payload = self.info_to_payload(info) - if reverse: - dst_mac = 'de:ad:00:00:00:00' - src_mac = remote_dst_host._mac - dst_ip6 = src_ip_if.remote_ip6 - src_ip6 = remote_dst_host.ip6 - dst_ip4 = src_ip_if.remote_ip4 - src_ip4 = remote_dst_host.ip4 - dst_l4 = 1234 + i - src_l4 = 4321 + i - else: - dst_mac = src_ip_if.local_mac - src_mac = src_ip_if.remote_mac - src_ip6 = src_ip_if.remote_ip6 - dst_ip6 = remote_dst_host.ip6 - src_ip4 = src_ip_if.remote_ip4 - dst_ip4 = remote_dst_host.ip4 - src_l4 = 1234 + i - dst_l4 = 4321 + i - if is_reflected_icmp: - icmp_type_delta = 1 - - # default ULP should be something we do not use in tests - ulp_l4 = TCP(sport=src_l4, dport=dst_l4) - # potentially a chain of protocols leading to ULP - ulp = ulp_l4 - - if is_udp_packet: - if is_ip6: - ulp_l4 = UDP(sport=src_l4, dport=dst_l4) - if add_extension_header: - # prepend some extension headers - ulp = (IPv6ExtHdrRouting() / IPv6ExtHdrRouting() / - IPv6ExtHdrFragment(offset=0, m=1) / ulp_l4) - # uncomment below to test invalid ones - # ulp = IPv6ExtHdrRouting(len = 200) / ulp_l4 - else: - ulp = ulp_l4 - p = (Ether(dst=dst_mac, src=src_mac) / - IPv6(src=src_ip6, dst=dst_ip6) / - ulp / - Raw(payload)) - else: - ulp_l4 = UDP(sport=src_l4, dport=dst_l4) - # IPv4 does not allow extension headers, - # but we rather make it a first fragment - flags = 1 if add_extension_header else 0 - ulp = ulp_l4 - p = (Ether(dst=dst_mac, src=src_mac) / - IP(src=src_ip4, dst=dst_ip4, frag=0, flags=flags) / - ulp / - Raw(payload)) - elif modulo == 1: - if is_ip6: - ulp_l4 = ICMPv6Unknown(type=128 + icmp_type_delta, - code=icmp_code) - ulp = ulp_l4 - p = (Ether(dst=dst_mac, src=src_mac) / - IPv6(src=src_ip6, dst=dst_ip6) / - ulp / - Raw(payload)) - else: - ulp_l4 = ICMP(type=8 - 8*icmp_type_delta, code=icmp_code) - ulp = ulp_l4 - p = (Ether(dst=dst_mac, src=src_mac) / - IP(src=src_ip4, dst=dst_ip4) / - ulp / - Raw(payload)) - - if i % 2 == 1: - info.data = p.copy() - size = packet_sizes[(i // 2) % len(packet_sizes)] - self.extend_packet(p, size) - pkts.append(p) - - rule_family = AF_INET6 if p.haslayer(IPv6) else AF_INET - rule_prefix_len = 128 if p.haslayer(IPv6) else 32 - rule_l3_layer = IPv6 if p.haslayer(IPv6) else IP - - if p.haslayer(UDP): - rule_l4_sport = p[UDP].sport - rule_l4_dport = p[UDP].dport - else: - if p.haslayer(ICMP): - rule_l4_sport = p[ICMP].type - rule_l4_dport = p[ICMP].code - else: - rule_l4_sport = p[ICMPv6Unknown].type - rule_l4_dport = p[ICMPv6Unknown].code - if p.haslayer(IPv6): - rule_l4_proto = ulp_l4.overload_fields[IPv6]['nh'] - else: - rule_l4_proto = p[IP].proto - - new_rule = { - 'is_permit': is_permit, - 'is_ipv6': p.haslayer(IPv6), - 'src_ip_addr': inet_pton(rule_family, - p[rule_l3_layer].src), - 'src_ip_prefix_len': rule_prefix_len, - 'dst_ip_addr': inet_pton(rule_family, - p[rule_l3_layer].dst), - 'dst_ip_prefix_len': rule_prefix_len, - 'srcport_or_icmptype_first': rule_l4_sport, - 'srcport_or_icmptype_last': rule_l4_sport, - 'dstport_or_icmpcode_first': rule_l4_dport, - 'dstport_or_icmpcode_last': rule_l4_dport, - 'proto': rule_l4_proto, - } - rules.append(new_rule) - new_rule_permit = new_rule.copy() - new_rule_permit['is_permit'] = 1 - permit_rules.append(new_rule_permit) - - new_rule_permit_and_reflect = new_rule.copy() - if can_reflect_this_packet: - new_rule_permit_and_reflect['is_permit'] = 2 - else: - new_rule_permit_and_reflect['is_permit'] = is_permit - - permit_and_reflect_rules.append(new_rule_permit_and_reflect) - self.logger.info("create_stream pkt#%d: %s" % (i, payload)) - - return {'stream': pkts, - 'rules': rules, - 'permit_rules': permit_rules, - 'permit_and_reflect_rules': permit_and_reflect_rules} - - def verify_capture(self, dst_ip_if, src_ip_if, capture, reverse): - last_info = dict() - for i in self.interfaces: - last_info[i.sw_if_index] = None - - dst_ip_sw_if_index = dst_ip_if.sw_if_index - - for packet in capture: - l3 = IP if packet.haslayer(IP) else IPv6 - ip = packet[l3] - if packet.haslayer(UDP): - l4 = UDP - else: - if packet.haslayer(ICMP): - l4 = ICMP - else: - l4 = ICMPv6Unknown - - # Scapy IPv6 stuff is too smart for its own good. - # So we do this and coerce the ICMP into unknown type - if packet.haslayer(UDP): - data = scapy.compat.raw(packet[UDP][Raw]) - else: - if l3 == IP: - data = scapy.compat.raw(ICMP( - scapy.compat.raw(packet[l3].payload))[Raw]) - else: - data = scapy.compat.raw(ICMPv6Unknown( - scapy.compat.raw(packet[l3].payload)).msgbody) - udp_or_icmp = packet[l3].payload - data_obj = Raw(data) - # FIXME: make framework believe we are on object - payload_info = self.payload_to_info(data_obj) - packet_index = payload_info.index - - self.assertEqual(payload_info.dst, dst_ip_sw_if_index) - - next_info = self.get_next_packet_info_for_interface2( - payload_info.src, dst_ip_sw_if_index, - last_info[payload_info.src]) - last_info[payload_info.src] = next_info - self.assertTrue(next_info is not None) - self.assertEqual(packet_index, next_info.index) - saved_packet = next_info.data - self.assertTrue(next_info is not None) - - # MAC: src, dst - if not reverse: - self.assertEqual(packet.src, dst_ip_if.local_mac) - host = dst_ip_if.host_by_mac(packet.dst) - - # IP: src, dst - # self.assertEqual(ip.src, src_ip_if.remote_ip4) - if saved_packet is not None: - self.assertEqual(ip.src, saved_packet[l3].src) - self.assertEqual(ip.dst, saved_packet[l3].dst) - if l4 == UDP: - self.assertEqual(udp_or_icmp.sport, saved_packet[l4].sport) - self.assertEqual(udp_or_icmp.dport, saved_packet[l4].dport) - # self.assertEqual(ip.dst, host.ip4) - - # UDP: - - def applied_acl_shuffle(self, sw_if_index): - # first collect what ACLs are applied and what they look like - r = self.vapi.acl_interface_list_dump(sw_if_index=sw_if_index) - orig_applied_acls = r[0] - - # we will collect these just to save and generate additional rulesets - orig_acls = [] - for acl_num in orig_applied_acls.acls: - rr = self.vapi.acl_dump(acl_num) - orig_acls.append(rr[0]) - - # now create a list of all the rules in all ACLs - all_rules = [] - for old_acl in orig_acls: - for rule in old_acl.r: - all_rules.append(dict(rule._asdict())) - - # Add a few ACLs made from shuffled rules - shuffle(all_rules) - reply = self.vapi.acl_add_replace(acl_index=4294967295, - r=all_rules[::2], - tag=b"shuffle 1. acl") - shuffle_acl_1 = reply.acl_index - shuffle(all_rules) - reply = self.vapi.acl_add_replace(acl_index=4294967295, - r=all_rules[::3], - tag=b"shuffle 2. acl") - shuffle_acl_2 = reply.acl_index - shuffle(all_rules) - reply = self.vapi.acl_add_replace(acl_index=4294967295, - r=all_rules[::2], - tag=b"shuffle 3. acl") - shuffle_acl_3 = reply.acl_index - - # apply the shuffle ACLs in front - input_acls = [shuffle_acl_1, shuffle_acl_2] - output_acls = [shuffle_acl_1, shuffle_acl_2] - - # add the currently applied ACLs - n_input = orig_applied_acls.n_input - input_acls.extend(orig_applied_acls.acls[:n_input]) - output_acls.extend(orig_applied_acls.acls[n_input:]) - - # and the trailing shuffle ACL(s) - input_acls.extend([shuffle_acl_3]) - output_acls.extend([shuffle_acl_3]) - - # set the interface ACL list to the result - self.vapi.acl_interface_set_acl_list(sw_if_index=sw_if_index, - n_input=len(input_acls), - acls=input_acls + output_acls) - # change the ACLs a few times - for i in range(1, 10): - shuffle(all_rules) - reply = self.vapi.acl_add_replace(acl_index=shuffle_acl_1, - r=all_rules[::1+(i % 2)], - tag=b"shuffle 1. acl") - shuffle(all_rules) - reply = self.vapi.acl_add_replace(acl_index=shuffle_acl_2, - r=all_rules[::1+(i % 3)], - tag=b"shuffle 2. acl") - shuffle(all_rules) - reply = self.vapi.acl_add_replace(acl_index=shuffle_acl_2, - r=all_rules[::1+(i % 5)], - tag=b"shuffle 3. acl") - - # restore to how it was before and clean up - self.vapi.acl_interface_set_acl_list(sw_if_index=sw_if_index, - n_input=orig_applied_acls.n_input, - acls=orig_applied_acls.acls) - reply = self.vapi.acl_del(acl_index=shuffle_acl_1) - reply = self.vapi.acl_del(acl_index=shuffle_acl_2) - reply = self.vapi.acl_del(acl_index=shuffle_acl_3) - - def create_acls_for_a_stream(self, stream_dict, - test_l2_action, is_reflect): - r = stream_dict['rules'] - r_permit = stream_dict['permit_rules'] - r_permit_reflect = stream_dict['permit_and_reflect_rules'] - r_action = r_permit_reflect if is_reflect else r - reply = self.vapi.acl_add_replace(acl_index=4294967295, r=r_action, - tag=b"act. acl") - action_acl_index = reply.acl_index - reply = self.vapi.acl_add_replace(acl_index=4294967295, r=r_permit, - tag=b"perm. acl") - permit_acl_index = reply.acl_index - return {'L2': action_acl_index if test_l2_action else permit_acl_index, - 'L3': permit_acl_index if test_l2_action else action_acl_index, - 'permit': permit_acl_index, 'action': action_acl_index} - - def apply_acl_ip46_x_to_y(self, bridged_to_routed, test_l2_deny, - is_ip6, is_reflect, add_eh): - """ Apply the ACLs - """ - self.reset_packet_infos() - stream_dict = self.create_stream( - self.pg2, self.loop0, - bridged_to_routed, - self.pg_if_packet_sizes, is_ip6, - not is_reflect, False, add_eh) - stream = stream_dict['stream'] - acl_idx = self.create_acls_for_a_stream(stream_dict, test_l2_deny, - is_reflect) - n_input_l3 = 0 if bridged_to_routed else 1 - n_input_l2 = 1 if bridged_to_routed else 0 - self.vapi.acl_interface_set_acl_list(sw_if_index=self.pg2.sw_if_index, - n_input=n_input_l3, - acls=[acl_idx['L3']]) - self.vapi.acl_interface_set_acl_list(sw_if_index=self.pg0.sw_if_index, - n_input=n_input_l2, - acls=[acl_idx['L2']]) - self.vapi.acl_interface_set_acl_list(sw_if_index=self.pg1.sw_if_index, - n_input=n_input_l2, - acls=[acl_idx['L2']]) - self.applied_acl_shuffle(self.pg0.sw_if_index) - self.applied_acl_shuffle(self.pg2.sw_if_index) - return {'L2': acl_idx['L2'], 'L3': acl_idx['L3']} - - def apply_acl_ip46_both_directions_reflect(self, - primary_is_bridged_to_routed, - reflect_on_l2, is_ip6, add_eh, - stateful_icmp): - primary_is_routed_to_bridged = not primary_is_bridged_to_routed - self.reset_packet_infos() - stream_dict_fwd = self.create_stream(self.pg2, self.loop0, - primary_is_bridged_to_routed, - self.pg_if_packet_sizes, is_ip6, - False, False, add_eh, - stateful_icmp) - acl_idx_fwd = self.create_acls_for_a_stream(stream_dict_fwd, - reflect_on_l2, True) - - stream_dict_rev = self.create_stream(self.pg2, self.loop0, - not primary_is_bridged_to_routed, - self.pg_if_packet_sizes, is_ip6, - True, True, add_eh, stateful_icmp) - # We want the primary action to be "deny" rather than reflect - acl_idx_rev = self.create_acls_for_a_stream(stream_dict_rev, - reflect_on_l2, False) - - if primary_is_bridged_to_routed: - inbound_l2_acl = acl_idx_fwd['L2'] - else: - inbound_l2_acl = acl_idx_rev['L2'] - - if primary_is_routed_to_bridged: - outbound_l2_acl = acl_idx_fwd['L2'] - else: - outbound_l2_acl = acl_idx_rev['L2'] - - if primary_is_routed_to_bridged: - inbound_l3_acl = acl_idx_fwd['L3'] - else: - inbound_l3_acl = acl_idx_rev['L3'] - - if primary_is_bridged_to_routed: - outbound_l3_acl = acl_idx_fwd['L3'] - else: - outbound_l3_acl = acl_idx_rev['L3'] - - self.vapi.acl_interface_set_acl_list(sw_if_index=self.pg2.sw_if_index, - n_input=1, - acls=[inbound_l3_acl, - outbound_l3_acl]) - self.vapi.acl_interface_set_acl_list(sw_if_index=self.pg0.sw_if_index, - n_input=1, - acls=[inbound_l2_acl, - outbound_l2_acl]) - self.vapi.acl_interface_set_acl_list(sw_if_index=self.pg1.sw_if_index, - n_input=1, - acls=[inbound_l2_acl, - outbound_l2_acl]) - self.applied_acl_shuffle(self.pg0.sw_if_index) - self.applied_acl_shuffle(self.pg2.sw_if_index) - - def apply_acl_ip46_routed_to_bridged(self, test_l2_deny, is_ip6, - is_reflect, add_eh): - return self.apply_acl_ip46_x_to_y(False, test_l2_deny, is_ip6, - is_reflect, add_eh) - - def apply_acl_ip46_bridged_to_routed(self, test_l2_deny, is_ip6, - is_reflect, add_eh): - return self.apply_acl_ip46_x_to_y(True, test_l2_deny, is_ip6, - is_reflect, add_eh) - - def verify_acl_packet_count(self, acl_idx, packet_count): - matches = self.statistics.get_counter('/acl/%d/matches' % acl_idx) - self.logger.info("stat seg for ACL %d: %s" % (acl_idx, repr(matches))) - total_count = 0 - for p in matches[0]: - total_count = total_count + p['packets'] - self.assertEqual(total_count, packet_count) - - def run_traffic_ip46_x_to_y(self, bridged_to_routed, - test_l2_deny, is_ip6, - is_reflect, is_established, add_eh, - stateful_icmp=False): - self.reset_packet_infos() - stream_dict = self.create_stream(self.pg2, self.loop0, - bridged_to_routed, - self.pg_if_packet_sizes, is_ip6, - not is_reflect, is_established, - add_eh, stateful_icmp) - stream = stream_dict['stream'] - - tx_if = self.pg0 if bridged_to_routed else self.pg2 - rx_if = self.pg2 if bridged_to_routed else self.pg0 - - tx_if.add_stream(stream) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - packet_count = self.get_packet_count_for_if_idx(self.loop0.sw_if_index) - rcvd1 = rx_if.get_capture(packet_count) - self.verify_capture(self.loop0, self.pg2, rcvd1, bridged_to_routed) - return len(stream) - - def run_traffic_ip46_routed_to_bridged(self, test_l2_deny, is_ip6, - is_reflect, is_established, add_eh, - stateful_icmp=False): - return self.run_traffic_ip46_x_to_y(False, test_l2_deny, is_ip6, - is_reflect, is_established, add_eh, - stateful_icmp) - - def run_traffic_ip46_bridged_to_routed(self, test_l2_deny, is_ip6, - is_reflect, is_established, add_eh, - stateful_icmp=False): - return self.run_traffic_ip46_x_to_y(True, test_l2_deny, is_ip6, - is_reflect, is_established, add_eh, - stateful_icmp) - - def run_test_ip46_routed_to_bridged(self, test_l2_deny, - is_ip6, is_reflect, add_eh): - acls = self.apply_acl_ip46_routed_to_bridged(test_l2_deny, - is_ip6, is_reflect, - add_eh) - pkts = self.run_traffic_ip46_routed_to_bridged(test_l2_deny, is_ip6, - is_reflect, False, - add_eh) - self.verify_acl_packet_count(acls['L3'], pkts) - - def run_test_ip46_bridged_to_routed(self, test_l2_deny, - is_ip6, is_reflect, add_eh): - acls = self.apply_acl_ip46_bridged_to_routed(test_l2_deny, - is_ip6, is_reflect, - add_eh) - pkts = self.run_traffic_ip46_bridged_to_routed(test_l2_deny, is_ip6, - is_reflect, False, - add_eh) - self.verify_acl_packet_count(acls['L2'], pkts) - - def run_test_ip46_routed_to_bridged_and_back(self, test_l2_action, - is_ip6, add_eh, - stateful_icmp=False): - self.apply_acl_ip46_both_directions_reflect(False, test_l2_action, - is_ip6, add_eh, - stateful_icmp) - self.run_traffic_ip46_routed_to_bridged(test_l2_action, is_ip6, - True, False, add_eh, - stateful_icmp) - self.run_traffic_ip46_bridged_to_routed(test_l2_action, is_ip6, - False, True, add_eh, - stateful_icmp) - - def run_test_ip46_bridged_to_routed_and_back(self, test_l2_action, - is_ip6, add_eh, - stateful_icmp=False): - self.apply_acl_ip46_both_directions_reflect(True, test_l2_action, - is_ip6, add_eh, - stateful_icmp) - self.run_traffic_ip46_bridged_to_routed(test_l2_action, is_ip6, - True, False, add_eh, - stateful_icmp) - self.run_traffic_ip46_routed_to_bridged(test_l2_action, is_ip6, - False, True, add_eh, - stateful_icmp) - - def test_0000_ip6_irb_1(self): - """ ACL plugin prepare""" - if not self.vpp_dead: - cmd = "set acl-plugin session timeout udp idle 2000" - self.logger.info(self.vapi.ppcli(cmd)) - # uncomment to not skip past the routing header - # and watch the EH tests fail - # self.logger.info(self.vapi.ppcli( - # "set acl-plugin skip-ipv6-extension-header 43 0")) - # uncomment to test the session limit (stateful tests will fail) - # self.logger.info(self.vapi.ppcli( - # "set acl-plugin session table max-entries 1")) - # new datapath is the default, but just in case - # self.logger.info(self.vapi.ppcli( - # "set acl-plugin l2-datapath new")) - # If you want to see some tests fail, uncomment the next line - # self.logger.info(self.vapi.ppcli( - # "set acl-plugin l2-datapath old")) - - def test_0001_ip6_irb_1(self): - """ ACL IPv6 routed -> bridged, L2 ACL deny""" - self.run_test_ip46_routed_to_bridged(True, True, False, - self.WITHOUT_EH) - - def test_0002_ip6_irb_1(self): - """ ACL IPv6 routed -> bridged, L3 ACL deny""" - self.run_test_ip46_routed_to_bridged(False, True, False, - self.WITHOUT_EH) - - def test_0003_ip4_irb_1(self): - """ ACL IPv4 routed -> bridged, L2 ACL deny""" - self.run_test_ip46_routed_to_bridged(True, False, False, - self.WITHOUT_EH) - - def test_0004_ip4_irb_1(self): - """ ACL IPv4 routed -> bridged, L3 ACL deny""" - self.run_test_ip46_routed_to_bridged(False, False, False, - self.WITHOUT_EH) - - def test_0005_ip6_irb_1(self): - """ ACL IPv6 bridged -> routed, L2 ACL deny """ - self.run_test_ip46_bridged_to_routed(True, True, False, - self.WITHOUT_EH) - - def test_0006_ip6_irb_1(self): - """ ACL IPv6 bridged -> routed, L3 ACL deny """ - self.run_test_ip46_bridged_to_routed(False, True, False, - self.WITHOUT_EH) - - def test_0007_ip6_irb_1(self): - """ ACL IPv4 bridged -> routed, L2 ACL deny """ - self.run_test_ip46_bridged_to_routed(True, False, False, - self.WITHOUT_EH) - - def test_0008_ip6_irb_1(self): - """ ACL IPv4 bridged -> routed, L3 ACL deny """ - self.run_test_ip46_bridged_to_routed(False, False, False, - self.WITHOUT_EH) - - # Stateful ACL tests - def test_0101_ip6_irb_1(self): - """ ACL IPv6 routed -> bridged, L2 ACL permit+reflect""" - self.run_test_ip46_routed_to_bridged_and_back(True, True, - self.WITHOUT_EH) - - def test_0102_ip6_irb_1(self): - """ ACL IPv6 bridged -> routed, L2 ACL permit+reflect""" - self.run_test_ip46_bridged_to_routed_and_back(True, True, - self.WITHOUT_EH) - - def test_0103_ip6_irb_1(self): - """ ACL IPv4 routed -> bridged, L2 ACL permit+reflect""" - self.run_test_ip46_routed_to_bridged_and_back(True, False, - self.WITHOUT_EH) - - def test_0104_ip6_irb_1(self): - """ ACL IPv4 bridged -> routed, L2 ACL permit+reflect""" - self.run_test_ip46_bridged_to_routed_and_back(True, False, - self.WITHOUT_EH) - - def test_0111_ip6_irb_1(self): - """ ACL IPv6 routed -> bridged, L3 ACL permit+reflect""" - self.run_test_ip46_routed_to_bridged_and_back(False, True, - self.WITHOUT_EH) - - def test_0112_ip6_irb_1(self): - """ ACL IPv6 bridged -> routed, L3 ACL permit+reflect""" - self.run_test_ip46_bridged_to_routed_and_back(False, True, - self.WITHOUT_EH) - - def test_0113_ip6_irb_1(self): - """ ACL IPv4 routed -> bridged, L3 ACL permit+reflect""" - self.run_test_ip46_routed_to_bridged_and_back(False, False, - self.WITHOUT_EH) - - def test_0114_ip6_irb_1(self): - """ ACL IPv4 bridged -> routed, L3 ACL permit+reflect""" - self.run_test_ip46_bridged_to_routed_and_back(False, False, - self.WITHOUT_EH) - - # A block of tests with extension headers - - def test_1001_ip6_irb_1(self): - """ ACL IPv6+EH routed -> bridged, L2 ACL deny""" - self.run_test_ip46_routed_to_bridged(True, True, False, - self.WITH_EH) - - def test_1002_ip6_irb_1(self): - """ ACL IPv6+EH routed -> bridged, L3 ACL deny""" - self.run_test_ip46_routed_to_bridged(False, True, False, - self.WITH_EH) - - def test_1005_ip6_irb_1(self): - """ ACL IPv6+EH bridged -> routed, L2 ACL deny """ - self.run_test_ip46_bridged_to_routed(True, True, False, - self.WITH_EH) - - def test_1006_ip6_irb_1(self): - """ ACL IPv6+EH bridged -> routed, L3 ACL deny """ - self.run_test_ip46_bridged_to_routed(False, True, False, - self.WITH_EH) - - def test_1101_ip6_irb_1(self): - """ ACL IPv6+EH routed -> bridged, L2 ACL permit+reflect""" - self.run_test_ip46_routed_to_bridged_and_back(True, True, - self.WITH_EH) - - def test_1102_ip6_irb_1(self): - """ ACL IPv6+EH bridged -> routed, L2 ACL permit+reflect""" - self.run_test_ip46_bridged_to_routed_and_back(True, True, - self.WITH_EH) - - def test_1111_ip6_irb_1(self): - """ ACL IPv6+EH routed -> bridged, L3 ACL permit+reflect""" - self.run_test_ip46_routed_to_bridged_and_back(False, True, - self.WITH_EH) - - def test_1112_ip6_irb_1(self): - """ ACL IPv6+EH bridged -> routed, L3 ACL permit+reflect""" - self.run_test_ip46_bridged_to_routed_and_back(False, True, - self.WITH_EH) - - # IPv4 with "MF" bit set - - def test_1201_ip6_irb_1(self): - """ ACL IPv4+MF routed -> bridged, L2 ACL deny""" - self.run_test_ip46_routed_to_bridged(True, False, False, - self.WITH_EH) - - def test_1202_ip6_irb_1(self): - """ ACL IPv4+MF routed -> bridged, L3 ACL deny""" - self.run_test_ip46_routed_to_bridged(False, False, False, - self.WITH_EH) - - def test_1205_ip6_irb_1(self): - """ ACL IPv4+MF bridged -> routed, L2 ACL deny """ - self.run_test_ip46_bridged_to_routed(True, False, False, - self.WITH_EH) - - def test_1206_ip6_irb_1(self): - """ ACL IPv4+MF bridged -> routed, L3 ACL deny """ - self.run_test_ip46_bridged_to_routed(False, False, False, - self.WITH_EH) - - def test_1301_ip6_irb_1(self): - """ ACL IPv4+MF routed -> bridged, L2 ACL permit+reflect""" - self.run_test_ip46_routed_to_bridged_and_back(True, False, - self.WITH_EH) - - def test_1302_ip6_irb_1(self): - """ ACL IPv4+MF bridged -> routed, L2 ACL permit+reflect""" - self.run_test_ip46_bridged_to_routed_and_back(True, False, - self.WITH_EH) - - def test_1311_ip6_irb_1(self): - """ ACL IPv4+MF routed -> bridged, L3 ACL permit+reflect""" - self.run_test_ip46_routed_to_bridged_and_back(False, False, - self.WITH_EH) - - def test_1312_ip6_irb_1(self): - """ ACL IPv4+MF bridged -> routed, L3 ACL permit+reflect""" - self.run_test_ip46_bridged_to_routed_and_back(False, False, - self.WITH_EH) - # Stateful ACL tests with stateful ICMP - - def test_1401_ip6_irb_1(self): - """ IPv6 routed -> bridged, L2 ACL permit+reflect, ICMP reflect""" - self.run_test_ip46_routed_to_bridged_and_back(True, True, - self.WITHOUT_EH, - self.STATEFUL_ICMP) - - def test_1402_ip6_irb_1(self): - """ IPv6 bridged -> routed, L2 ACL permit+reflect, ICMP reflect""" - self.run_test_ip46_bridged_to_routed_and_back(True, True, - self.WITHOUT_EH, - self.STATEFUL_ICMP) - - def test_1403_ip4_irb_1(self): - """ IPv4 routed -> bridged, L2 ACL permit+reflect, ICMP reflect""" - self.run_test_ip46_routed_to_bridged_and_back(True, False, - self.WITHOUT_EH, - self.STATEFUL_ICMP) - - def test_1404_ip4_irb_1(self): - """ IPv4 bridged -> routed, L2 ACL permit+reflect, ICMP reflect""" - self.run_test_ip46_bridged_to_routed_and_back(True, False, - self.WITHOUT_EH, - self.STATEFUL_ICMP) - - def test_1411_ip6_irb_1(self): - """ IPv6 routed -> bridged, L3 ACL permit+reflect, ICMP reflect""" - self.run_test_ip46_routed_to_bridged_and_back(False, True, - self.WITHOUT_EH, - self.STATEFUL_ICMP) - - def test_1412_ip6_irb_1(self): - """ IPv6 bridged -> routed, L3 ACL permit+reflect, ICMP reflect""" - self.run_test_ip46_bridged_to_routed_and_back(False, True, - self.WITHOUT_EH, - self.STATEFUL_ICMP) - - def test_1413_ip4_irb_1(self): - """ IPv4 routed -> bridged, L3 ACL permit+reflect, ICMP reflect""" - self.run_test_ip46_routed_to_bridged_and_back(False, False, - self.WITHOUT_EH, - self.STATEFUL_ICMP) - - def test_1414_ip4_irb_1(self): - """ IPv4 bridged -> routed, L3 ACL permit+reflect, ICMP reflect""" - self.run_test_ip46_bridged_to_routed_and_back(False, False, - self.WITHOUT_EH, - self.STATEFUL_ICMP) - - -if __name__ == '__main__': - unittest.main(testRunner=VppTestRunner) diff --git a/test/test_acl_plugin_macip.py b/test/test_acl_plugin_macip.py deleted file mode 100644 index 41735251792..00000000000 --- a/test/test_acl_plugin_macip.py +++ /dev/null @@ -1,1295 +0,0 @@ -#!/usr/bin/env python -from __future__ import print_function -"""ACL plugin - MACIP tests -""" -import binascii -import ipaddress -import random -from socket import inet_ntop, inet_pton, AF_INET, AF_INET6 -from struct import pack, unpack -import re -import unittest - -import scapy.compat -from scapy.packet import Raw -from scapy.layers.l2 import Ether -from scapy.layers.inet import IP, UDP -from scapy.layers.inet6 import IPv6 - -from framework import VppTestCase, VppTestRunner, running_extended_tests -from vpp_lo_interface import VppLoInterface -from vpp_l2 import L2_PORT_TYPE -from vpp_sub_interface import L2_VTR_OP, VppSubInterface, VppDot1QSubint, \ - VppDot1ADSubint - - -class MethodHolder(VppTestCase): - DEBUG = False - - BRIDGED = True - ROUTED = False - - IS_IP4 = False - IS_IP6 = True - - DOT1AD = "dot1ad" - DOT1Q = "dot1q" - PERMIT_TAGS = True - DENY_TAGS = False - - # rule types - DENY = 0 - PERMIT = 1 - - # ACL types - EXACT_IP = 1 - SUBNET_IP = 2 - WILD_IP = 3 - - EXACT_MAC = 1 - WILD_MAC = 2 - OUI_MAC = 3 - - ACLS = [] - - @classmethod - def setUpClass(cls): - """ - Perform standard class setup (defined by class method setUpClass in - class VppTestCase) before running the test case, set test case related - variables and configure VPP. - """ - super(MethodHolder, cls).setUpClass() - - cls.pg_if_packet_sizes = [64, 512, 1518, 9018] # packet sizes - cls.bd_id = 111 - cls.remote_hosts_count = 200 - - try: - # create 4 pg interfaces, 1 loopback interface - cls.create_pg_interfaces(range(4)) - cls.create_loopback_interfaces(1) - - # create 2 subinterfaces - cls.subifs = [ - VppDot1QSubint(cls, cls.pg1, 10), - VppDot1ADSubint(cls, cls.pg2, 20, 300, 400), - VppDot1QSubint(cls, cls.pg3, 30), - VppDot1ADSubint(cls, cls.pg3, 40, 600, 700)] - - cls.subifs[0].set_vtr(L2_VTR_OP.L2_POP_1, - inner=10, push1q=1) - cls.subifs[1].set_vtr(L2_VTR_OP.L2_POP_2, - outer=300, inner=400, push1q=1) - cls.subifs[2].set_vtr(L2_VTR_OP.L2_POP_1, - inner=30, push1q=1) - cls.subifs[3].set_vtr(L2_VTR_OP.L2_POP_2, - outer=600, inner=700, push1q=1) - - cls.interfaces = list(cls.pg_interfaces) - cls.interfaces.extend(cls.lo_interfaces) - cls.interfaces.extend(cls.subifs) - - for i in cls.interfaces: - i.admin_up() - - # Create BD with MAC learning enabled and put interfaces to this BD - cls.vapi.sw_interface_set_l2_bridge( - rx_sw_if_index=cls.loop0.sw_if_index, bd_id=cls.bd_id, - port_type=L2_PORT_TYPE.BVI) - cls.vapi.sw_interface_set_l2_bridge( - rx_sw_if_index=cls.pg0.sw_if_index, bd_id=cls.bd_id) - cls.vapi.sw_interface_set_l2_bridge( - rx_sw_if_index=cls.pg1.sw_if_index, bd_id=cls.bd_id) - cls.vapi.sw_interface_set_l2_bridge( - rx_sw_if_index=cls.subifs[0].sw_if_index, bd_id=cls.bd_id) - cls.vapi.sw_interface_set_l2_bridge( - rx_sw_if_index=cls.subifs[1].sw_if_index, bd_id=cls.bd_id) - - # Configure IPv4/6 addresses on loop interface and routed interface - cls.loop0.config_ip4() - cls.loop0.config_ip6() - cls.pg2.config_ip4() - cls.pg2.config_ip6() - cls.pg3.config_ip4() - cls.pg3.config_ip6() - - # Configure MAC address binding to IPv4 neighbors on loop0 - cls.loop0.generate_remote_hosts(cls.remote_hosts_count) - # Modify host mac addresses to have different OUI parts - for i in range(2, cls.remote_hosts_count + 2): - mac = cls.loop0.remote_hosts[i-2]._mac.split(':') - mac[2] = format(int(mac[2], 16) + i, "02x") - cls.loop0.remote_hosts[i - 2]._mac = ":".join(mac) - - cls.loop0.configure_ipv4_neighbors() - cls.loop0.configure_ipv6_neighbors() - - # configure MAC address on pg3 - cls.pg3.resolve_arp() - cls.pg3.resolve_ndp() - - # configure MAC address on subifs - for i in cls.subifs: - i.config_ip4() - i.resolve_arp() - i.config_ip6() - - # configure MAC address on pg2 - cls.pg2.resolve_arp() - cls.pg2.resolve_ndp() - - # Loopback BVI interface has remote hosts - # one half of hosts are behind pg0 second behind pg1,pg2,pg3 subifs - cls.pg0.remote_hosts = cls.loop0.remote_hosts[:100] - cls.subifs[0].remote_hosts = cls.loop0.remote_hosts[100:125] - cls.subifs[1].remote_hosts = cls.loop0.remote_hosts[125:150] - cls.subifs[2].remote_hosts = cls.loop0.remote_hosts[150:175] - cls.subifs[3].remote_hosts = cls.loop0.remote_hosts[175:] - - except Exception: - super(MethodHolder, cls).tearDownClass() - raise - - @classmethod - def tearDownClass(cls): - super(MethodHolder, cls).tearDownClass() - - def setUp(self): - super(MethodHolder, self).setUp() - self.reset_packet_infos() - del self.ACLS[:] - - def tearDown(self): - super(MethodHolder, self).tearDown() - self.delete_acls() - - def show_commands_at_teardown(self): - self.logger.info(self.vapi.ppcli("show interface address")) - self.logger.info(self.vapi.ppcli("show hardware")) - self.logger.info(self.vapi.ppcli("sh acl-plugin macip acl")) - self.logger.info(self.vapi.ppcli("sh acl-plugin macip interface")) - self.logger.info(self.vapi.ppcli("sh classify tables verbose")) - self.logger.info(self.vapi.ppcli("sh acl-plugin acl")) - self.logger.info(self.vapi.ppcli("sh acl-plugin interface")) - self.logger.info(self.vapi.ppcli("sh acl-plugin tables")) - # print(self.vapi.ppcli("show interface address")) - # print(self.vapi.ppcli("show hardware")) - # print(self.vapi.ppcli("sh acl-plugin macip interface")) - # print(self.vapi.ppcli("sh acl-plugin macip acl")) - - def macip_acl_dump_debug(self): - acls = self.vapi.macip_acl_dump() - if self.DEBUG: - for acl in acls: - print("ACL #"+str(acl.acl_index)) - for r in acl.r: - rule = "ACTION" - if r.is_permit == 1: - rule = "PERMIT" - elif r.is_permit == 0: - rule = "DENY " - print(" IP6" if r.is_ipv6 else " IP4", - rule, - binascii.hexlify(r.src_mac), - binascii.hexlify(r.src_mac_mask), - unpack('<16B', r.src_ip_addr), - r.src_ip_prefix_len) - return acls - - def create_rules(self, mac_type=EXACT_MAC, ip_type=EXACT_IP, - acl_count=1, rules_count=None): - acls = [] - if rules_count is None: - rules_count = [1] - src_mac = int("220000dead00", 16) - for acl in range(2, (acl_count+1) * 2): - rules = [] - host = random.choice(self.loop0.remote_hosts) - is_ip6 = acl % 2 - ip4 = host.ip4.split('.') - ip6 = list(unpack('<16B', inet_pton(AF_INET6, host.ip6))) - - if ip_type == self.EXACT_IP: - prefix_len4 = 32 - prefix_len6 = 128 - elif ip_type == self.WILD_IP: - ip4 = [0, 0, 0, 0] - ip6 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] - prefix_len4 = 0 - prefix_len6 = 0 - rules_count[(acl / 2) - 1] = 1 - else: - prefix_len4 = 24 - prefix_len6 = 64 - - if mac_type == self.EXACT_MAC: - mask = "ff:ff:ff:ff:ff:ff" - elif mac_type == self.WILD_MAC: - mask = "00:00:00:00:00:00" - elif mac_type == self.OUI_MAC: - mask = "ff:ff:ff:00:00:00" - else: - mask = "ff:ff:ff:ff:ff:00" - - ip = ip6 if is_ip6 else ip4 - ip_len = prefix_len6 if is_ip6 else prefix_len4 - - for i in range(0, rules_count[(acl / 2) - 1]): - src_mac += 16777217 - if mac_type == self.WILD_MAC: - mac = "00:00:00:00:00:00" - elif mac_type == self.OUI_MAC: - mac = ':'.join(re.findall('..', '{:02x}'.format( - src_mac))[:3])+":00:00:00" - else: - mac = ':'.join(re.findall( - '..', '{:02x}'.format(src_mac))) - - if ip_type == self.EXACT_IP: - ip4[3] = random.randint(100, 200) - ip6[15] = random.randint(100, 200) - elif ip_type == self.SUBNET_IP: - ip4[2] = random.randint(100, 200) - ip4[3] = 0 - ip6[8] = random.randint(100, 200) - ip6[15] = 0 - ip_pack = b'' - for j in range(0, len(ip)): - ip_pack += pack('<B', int(ip[j])) - - rule = ({'is_permit': self.PERMIT, - 'is_ipv6': is_ip6, - 'src_ip_addr': ip_pack, - 'src_ip_prefix_len': ip_len, - 'src_mac': binascii.unhexlify(mac.replace(':', '')), - 'src_mac_mask': binascii.unhexlify( - mask.replace(':', ''))}) - rules.append(rule) - if ip_type == self.WILD_IP: - break - - acls.append(rules) - src_mac += 1099511627776 - return acls - - def apply_macip_rules(self, acls): - for acl in acls: - reply = self.vapi.macip_acl_add(acl) - self.assertEqual(reply.retval, 0) - self.ACLS.append(reply.acl_index) - - def verify_macip_acls(self, acl_count, rules_count, expected_count=2): - reply = self.macip_acl_dump_debug() - for acl in range(2, (acl_count+1) * 2): - self.assertEqual(reply[acl - 2].count, rules_count[acl//2-1]) - - self.vapi.macip_acl_interface_get() - - self.vapi.macip_acl_interface_add_del(sw_if_index=0, acl_index=0) - self.vapi.macip_acl_interface_add_del(sw_if_index=1, acl_index=1) - - reply = self.vapi.macip_acl_interface_get() - self.assertEqual(reply.count, expected_count) - - def delete_acls(self): - for acl in range(len(self.ACLS)-1, -1, -1): - self.vapi.macip_acl_del(self.ACLS[acl]) - - reply = self.vapi.macip_acl_dump() - self.assertEqual(len(reply), 0) - - intf_acls = self.vapi.acl_interface_list_dump() - for i_a in intf_acls: - sw_if_index = i_a.sw_if_index - for acl_index in i_a.acls: - self.vapi.acl_interface_add_del(sw_if_index, acl_index, 0) - self.vapi.acl_del(acl_index) - - def create_stream(self, mac_type, ip_type, packet_count, - src_if, dst_if, traffic, is_ip6, tags=PERMIT_TAGS): - # exact MAC and exact IP - # exact MAC and subnet of IPs - # exact MAC and wildcard IP - # wildcard MAC and exact IP - # wildcard MAC and subnet of IPs - # wildcard MAC and wildcard IP - # OUI restricted MAC and exact IP - # OUI restricted MAC and subnet of IPs - # OUI restricted MAC and wildcard IP - - packets = [] - macip_rules = [] - acl_rules = [] - ip_permit = "" - mac_permit = "" - dst_mac = "" - mac_rule = "00:00:00:00:00:00" - mac_mask = "00:00:00:00:00:00" - for p in range(0, packet_count): - remote_dst_index = p % len(dst_if.remote_hosts) - remote_dst_host = dst_if.remote_hosts[remote_dst_index] - - dst_port = 1234 + p - src_port = 4321 + p - is_permit = self.PERMIT if p % 3 == 0 else self.DENY - denyMAC = True if not is_permit and p % 3 == 1 else False - denyIP = True if not is_permit and p % 3 == 2 else False - if not is_permit and ip_type == self.WILD_IP: - denyMAC = True - if not is_permit and mac_type == self.WILD_MAC: - denyIP = True - - if traffic == self.BRIDGED: - if is_permit: - src_mac = remote_dst_host._mac - dst_mac = 'de:ad:00:00:00:00' - src_ip4 = remote_dst_host.ip4 - dst_ip4 = src_if.remote_ip4 - src_ip6 = remote_dst_host.ip6 - dst_ip6 = src_if.remote_ip6 - ip_permit = src_ip6 if is_ip6 else src_ip4 - mac_permit = src_mac - if denyMAC: - mac = src_mac.split(':') - mac[0] = format(int(mac[0], 16)+1, "02x") - src_mac = ":".join(mac) - if is_ip6: - src_ip6 = ip_permit - else: - src_ip4 = ip_permit - if denyIP: - if ip_type != self.WILD_IP: - src_mac = mac_permit - src_ip4 = remote_dst_host.ip4 - dst_ip4 = src_if.remote_ip4 - src_ip6 = remote_dst_host.ip6 - dst_ip6 = src_if.remote_ip6 - else: - if is_permit: - src_mac = remote_dst_host._mac - dst_mac = src_if.local_mac - src_ip4 = src_if.remote_ip4 - dst_ip4 = remote_dst_host.ip4 - src_ip6 = src_if.remote_ip6 - dst_ip6 = remote_dst_host.ip6 - ip_permit = src_ip6 if is_ip6 else src_ip4 - mac_permit = src_mac - if denyMAC: - mac = src_mac.split(':') - mac[0] = format(int(mac[0], 16) + 1, "02x") - src_mac = ":".join(mac) - if is_ip6: - src_ip6 = ip_permit - else: - src_ip4 = ip_permit - if denyIP: - src_mac = remote_dst_host._mac - if ip_type != self.WILD_IP: - src_mac = mac_permit - src_ip4 = remote_dst_host.ip4 - dst_ip4 = src_if.remote_ip4 - src_ip6 = remote_dst_host.ip6 - dst_ip6 = src_if.remote_ip6 - - if is_permit: - info = self.create_packet_info(src_if, dst_if) - payload = self.info_to_payload(info) - else: - payload = "to be blocked" - - if mac_type == self.WILD_MAC: - mac = src_mac.split(':') - for i in range(1, 5): - mac[i] = format(random.randint(0, 255), "02x") - src_mac = ":".join(mac) - - # create packet - packet = Ether(src=src_mac, dst=dst_mac) - ip_rule = src_ip6 if is_ip6 else src_ip4 - if is_ip6: - if ip_type != self.EXACT_IP: - sub_ip = list(unpack('<16B', inet_pton(AF_INET6, ip_rule))) - if ip_type == self.WILD_IP: - sub_ip[0] = random.randint(240, 254) - sub_ip[1] = random.randint(230, 239) - sub_ip[14] = random.randint(100, 199) - sub_ip[15] = random.randint(200, 255) - elif ip_type == self.SUBNET_IP: - if denyIP: - sub_ip[2] = int(sub_ip[2]) + 1 - sub_ip[14] = random.randint(100, 199) - sub_ip[15] = random.randint(200, 255) - packed_src_ip6 = b''.join( - [scapy.compat.chb(x) for x in sub_ip]) - src_ip6 = inet_ntop(AF_INET6, packed_src_ip6) - packet /= IPv6(src=src_ip6, dst=dst_ip6) - else: - if ip_type != self.EXACT_IP: - sub_ip = ip_rule.split('.') - if ip_type == self.WILD_IP: - sub_ip[0] = random.randint(1, 49) - sub_ip[1] = random.randint(50, 99) - sub_ip[2] = random.randint(100, 199) - sub_ip[3] = random.randint(200, 255) - elif ip_type == self.SUBNET_IP: - if denyIP: - sub_ip[1] = int(sub_ip[1])+1 - sub_ip[2] = random.randint(100, 199) - sub_ip[3] = random.randint(200, 255) - src_ip4 = '.'.join(['{!s}'.format(x) for x in sub_ip]) - packet /= IP(src=src_ip4, dst=dst_ip4, frag=0, flags=0) - - packet /= UDP(sport=src_port, dport=dst_port)/Raw(payload) - - packet[Raw].load += b" mac:%s" % scapy.compat.raw(src_mac) - - size = self.pg_if_packet_sizes[p % len(self.pg_if_packet_sizes)] - if isinstance(src_if, VppSubInterface): - size = size + 4 - if isinstance(src_if, VppDot1QSubint): - if src_if is self.subifs[0]: - if tags == self.PERMIT_TAGS: - packet = src_if.add_dot1q_layer(packet, 10) - else: - packet = src_if.add_dot1q_layer(packet, 11) - else: - if tags == self.PERMIT_TAGS: - packet = src_if.add_dot1q_layer(packet, 30) - else: - packet = src_if.add_dot1q_layer(packet, 33) - elif isinstance(src_if, VppDot1ADSubint): - if src_if is self.subifs[1]: - if tags == self.PERMIT_TAGS: - packet = src_if.add_dot1ad_layer(packet, 300, 400) - else: - packet = src_if.add_dot1ad_layer(packet, 333, 444) - else: - if tags == self.PERMIT_TAGS: - packet = src_if.add_dot1ad_layer(packet, 600, 700) - else: - packet = src_if.add_dot1ad_layer(packet, 666, 777) - self.extend_packet(packet, size) - packets.append(packet) - - # create suitable MACIP rule - if mac_type == self.EXACT_MAC: - mac_rule = src_mac - mac_mask = "ff:ff:ff:ff:ff:ff" - elif mac_type == self.WILD_MAC: - mac_rule = "00:00:00:00:00:00" - mac_mask = "00:00:00:00:00:00" - elif mac_type == self.OUI_MAC: - mac = src_mac.split(':') - mac[3] = mac[4] = mac[5] = '00' - mac_rule = ":".join(mac) - mac_mask = "ff:ff:ff:00:00:00" - - if is_ip6: - if ip_type == self.WILD_IP: - ip = "0::0" - else: - ip = src_ip6 - if ip_type == self.SUBNET_IP: - sub_ip = list(unpack('<16B', inet_pton(AF_INET6, ip))) - for i in range(8, 16): - sub_ip[i] = 0 - packed_ip = b''.join( - [scapy.compat.chb(x) for x in sub_ip]) - ip = inet_ntop(AF_INET6, packed_ip) - else: - if ip_type == self.WILD_IP: - ip = "0.0.0.0" - else: - ip = src_ip4 - if ip_type == self.SUBNET_IP: - sub_ip = ip.split('.') - sub_ip[2] = sub_ip[3] = '0' - ip = ".".join(sub_ip) - - prefix_len = 128 if is_ip6 else 32 - if ip_type == self.WILD_IP: - prefix_len = 0 - elif ip_type == self.SUBNET_IP: - prefix_len = 64 if is_ip6 else 16 - ip_rule = inet_pton(AF_INET6 if is_ip6 else AF_INET, ip) - - # create suitable ACL rule - if is_permit: - rule_l4_sport = packet[UDP].sport - rule_l4_dport = packet[UDP].dport - rule_family = AF_INET6 if packet.haslayer(IPv6) else AF_INET - rule_prefix_len = 128 if packet.haslayer(IPv6) else 32 - rule_l3_layer = IPv6 if packet.haslayer(IPv6) else IP - if packet.haslayer(IPv6): - rule_l4_proto = packet[UDP].overload_fields[IPv6]['nh'] - else: - rule_l4_proto = packet[IP].proto - - acl_rule = { - 'is_permit': is_permit, - 'is_ipv6': is_ip6, - 'src_ip_addr': inet_pton(rule_family, - packet[rule_l3_layer].src), - 'src_ip_prefix_len': rule_prefix_len, - 'dst_ip_addr': inet_pton(rule_family, - packet[rule_l3_layer].dst), - 'dst_ip_prefix_len': rule_prefix_len, - 'srcport_or_icmptype_first': rule_l4_sport, - 'srcport_or_icmptype_last': rule_l4_sport, - 'dstport_or_icmpcode_first': rule_l4_dport, - 'dstport_or_icmpcode_last': rule_l4_dport, - 'proto': rule_l4_proto} - acl_rules.append(acl_rule) - - if mac_type == self.WILD_MAC and ip_type == self.WILD_IP and p > 0: - continue - - if is_permit: - macip_rule = ({ - 'is_permit': is_permit, - 'is_ipv6': is_ip6, - 'src_ip_addr': ip_rule, - 'src_ip_prefix_len': prefix_len, - 'src_mac': binascii.unhexlify(mac_rule.replace(':', '')), - 'src_mac_mask': binascii.unhexlify( - mac_mask.replace(':', ''))}) - macip_rules.append(macip_rule) - - # deny all other packets - if not (mac_type == self.WILD_MAC and ip_type == self.WILD_IP): - macip_rule = ({'is_permit': 0, - 'is_ipv6': is_ip6, - 'src_ip_addr': "", - 'src_ip_prefix_len': 0, - 'src_mac': "", - 'src_mac_mask': ""}) - macip_rules.append(macip_rule) - - acl_rule = {'is_permit': 0, - 'is_ipv6': is_ip6} - acl_rules.append(acl_rule) - return {'stream': packets, - 'macip_rules': macip_rules, - 'acl_rules': acl_rules} - - def verify_capture(self, stream, capture, is_ip6): - """ - :param stream: - :param capture: - :param is_ip6: - :return: - """ - # p_l3 = IPv6 if is_ip6 else IP - # if self.DEBUG: - # for p in stream: - # print(p[Ether].src, p[Ether].dst, p[p_l3].src, p[p_l3].dst) - # - # acls = self.macip_acl_dump_debug() - - # TODO : verify - # for acl in acls: - # for r in acl.r: - # print(binascii.hexlify(r.src_mac), \ - # binascii.hexlify(r.src_mac_mask),\ - # unpack('<16B', r.src_ip_addr), \ - # r.src_ip_prefix_len) - # - # for p in capture: - # print(p[Ether].src, p[Ether].dst, p[p_l3].src, p[p_l3].dst - # data = p[Raw].load.split(':',1)[1]) - # print(p[p_l3].src, data) - - def run_traffic(self, mac_type, ip_type, traffic, is_ip6, packets, - do_not_expected_capture=False, tags=None, - apply_rules=True, isMACIP=True, permit_tags=PERMIT_TAGS, - try_replace=False): - self.reset_packet_infos() - - if tags is None: - tx_if = self.pg0 if traffic == self.BRIDGED else self.pg3 - rx_if = self.pg3 if traffic == self.BRIDGED else self.pg0 - src_if = self.pg3 - dst_if = self.loop0 - else: - if tags == self.DOT1Q: - if traffic == self.BRIDGED: - tx_if = self.subifs[0] - rx_if = self.pg0 - src_if = self.subifs[0] - dst_if = self.loop0 - else: - tx_if = self.subifs[2] - rx_if = self.pg0 - src_if = self.subifs[2] - dst_if = self.loop0 - elif tags == self.DOT1AD: - if traffic == self.BRIDGED: - tx_if = self.subifs[1] - rx_if = self.pg0 - src_if = self.subifs[1] - dst_if = self.loop0 - else: - tx_if = self.subifs[3] - rx_if = self.pg0 - src_if = self.subifs[3] - dst_if = self.loop0 - else: - return - - test_dict = self.create_stream(mac_type, ip_type, packets, - src_if, dst_if, - traffic, is_ip6, - tags=permit_tags) - - if apply_rules: - if isMACIP: - reply = self.vapi.macip_acl_add(test_dict['macip_rules']) - else: - reply = self.vapi.acl_add_replace(acl_index=4294967295, - r=test_dict['acl_rules']) - self.assertEqual(reply.retval, 0) - acl_index = reply.acl_index - - if isMACIP: - self.vapi.macip_acl_interface_add_del( - sw_if_index=tx_if.sw_if_index, - acl_index=acl_index) - reply = self.vapi.macip_acl_interface_get() - self.assertEqual(reply.acls[tx_if.sw_if_index], acl_index) - self.ACLS.append(reply.acls[tx_if.sw_if_index]) - else: - self.vapi.acl_interface_add_del( - sw_if_index=tx_if.sw_if_index, acl_index=acl_index) - else: - self.vapi.macip_acl_interface_add_del( - sw_if_index=tx_if.sw_if_index, - acl_index=0) - if try_replace: - if isMACIP: - reply = self.vapi.macip_acl_add_replace( - test_dict['macip_rules'], - acl_index) - else: - reply = self.vapi.acl_add_replace(acl_index=acl_index, - r=test_dict['acl_rules']) - self.assertEqual(reply.retval, 0) - - if not isinstance(src_if, VppSubInterface): - tx_if.add_stream(test_dict['stream']) - else: - tx_if.parent.add_stream(test_dict['stream']) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - - if do_not_expected_capture: - rx_if.get_capture(0) - else: - if traffic == self.BRIDGED and mac_type == self.WILD_MAC and \ - ip_type == self.WILD_IP: - capture = rx_if.get_capture(packets) - else: - capture = rx_if.get_capture( - self.get_packet_count_for_if_idx(dst_if.sw_if_index)) - self.verify_capture(test_dict['stream'], capture, is_ip6) - if not isMACIP: - self.vapi.acl_interface_add_del(sw_if_index=tx_if.sw_if_index, - acl_index=acl_index, is_add=0) - self.vapi.acl_del(acl_index) - - def run_test_acls(self, mac_type, ip_type, acl_count, - rules_count, traffic=None, ip=None): - self.apply_macip_rules(self.create_rules(mac_type, ip_type, acl_count, - rules_count)) - self.verify_macip_acls(acl_count, rules_count) - - if traffic is not None: - self.run_traffic(self.EXACT_MAC, self.EXACT_IP, traffic, ip, 9) - - -class TestMACIP_IP4(MethodHolder): - """MACIP with IP4 traffic""" - - @classmethod - def setUpClass(cls): - super(TestMACIP_IP4, cls).setUpClass() - - @classmethod - def tearDownClass(cls): - super(TestMACIP_IP4, cls).tearDownClass() - - def test_acl_bridged_ip4_exactMAC_exactIP(self): - """ IP4 MACIP exactMAC|exactIP ACL bridged traffic - """ - self.run_traffic(self.EXACT_MAC, self.EXACT_IP, - self.BRIDGED, self.IS_IP4, 9) - - def test_acl_bridged_ip4_exactMAC_subnetIP(self): - """ IP4 MACIP exactMAC|subnetIP ACL bridged traffic - """ - - self.run_traffic(self.EXACT_MAC, self.SUBNET_IP, - self.BRIDGED, self.IS_IP4, 9) - - def test_acl_bridged_ip4_exactMAC_wildIP(self): - """ IP4 MACIP exactMAC|wildIP ACL bridged traffic - """ - - self.run_traffic(self.EXACT_MAC, self.WILD_IP, - self.BRIDGED, self.IS_IP4, 9) - - def test_acl_bridged_ip4_ouiMAC_exactIP(self): - """ IP4 MACIP ouiMAC|exactIP ACL bridged traffic - """ - - self.run_traffic(self.OUI_MAC, self.EXACT_IP, - self.BRIDGED, self.IS_IP4, 3) - - def test_acl_bridged_ip4_ouiMAC_subnetIP(self): - """ IP4 MACIP ouiMAC|subnetIP ACL bridged traffic - """ - - self.run_traffic(self.OUI_MAC, self.SUBNET_IP, - self.BRIDGED, self.IS_IP4, 9) - - def test_acl_bridged_ip4_ouiMAC_wildIP(self): - """ IP4 MACIP ouiMAC|wildIP ACL bridged traffic - """ - - self.run_traffic(self.OUI_MAC, self.WILD_IP, - self.BRIDGED, self.IS_IP4, 9) - - def test_ac_bridgedl_ip4_wildMAC_exactIP(self): - """ IP4 MACIP wildcardMAC|exactIP ACL bridged traffic - """ - - self.run_traffic(self.WILD_MAC, self.EXACT_IP, - self.BRIDGED, self.IS_IP4, 9) - - def test_acl_bridged_ip4_wildMAC_subnetIP(self): - """ IP4 MACIP wildcardMAC|subnetIP ACL bridged traffic - """ - - self.run_traffic(self.WILD_MAC, self.SUBNET_IP, - self.BRIDGED, self.IS_IP4, 9) - - def test_acl_bridged_ip4_wildMAC_wildIP(self): - """ IP4 MACIP wildcardMAC|wildIP ACL bridged traffic - """ - - self.run_traffic(self.WILD_MAC, self.WILD_IP, - self.BRIDGED, self.IS_IP4, 9) - - def test_acl_routed_ip4_exactMAC_exactIP(self): - """ IP4 MACIP exactMAC|exactIP ACL routed traffic - """ - self.run_traffic(self.EXACT_MAC, self.EXACT_IP, - self.ROUTED, self.IS_IP4, 9) - - def test_acl_routed_ip4_exactMAC_subnetIP(self): - """ IP4 MACIP exactMAC|subnetIP ACL routed traffic - """ - self.run_traffic(self.EXACT_MAC, self.SUBNET_IP, - self.ROUTED, self.IS_IP4, 9) - - def test_acl_routed_ip4_exactMAC_wildIP(self): - """ IP4 MACIP exactMAC|wildIP ACL routed traffic - """ - self.run_traffic(self.EXACT_MAC, self.WILD_IP, - self.ROUTED, self.IS_IP4, 9) - - def test_acl_routed_ip4_ouiMAC_exactIP(self): - """ IP4 MACIP ouiMAC|exactIP ACL routed traffic - """ - - self.run_traffic(self.OUI_MAC, self.EXACT_IP, - self.ROUTED, self.IS_IP4, 9) - - def test_acl_routed_ip4_ouiMAC_subnetIP(self): - """ IP4 MACIP ouiMAC|subnetIP ACL routed traffic - """ - - self.run_traffic(self.OUI_MAC, self.SUBNET_IP, - self.ROUTED, self.IS_IP4, 9) - - def test_acl_routed_ip4_ouiMAC_wildIP(self): - """ IP4 MACIP ouiMAC|wildIP ACL routed traffic - """ - - self.run_traffic(self.OUI_MAC, self.WILD_IP, - self.ROUTED, self.IS_IP4, 9) - - def test_acl_routed_ip4_wildMAC_exactIP(self): - """ IP4 MACIP wildcardMAC|exactIP ACL routed traffic - """ - - self.run_traffic(self.WILD_MAC, self.EXACT_IP, - self.ROUTED, self.IS_IP4, 9) - - def test_acl_routed_ip4_wildMAC_subnetIP(self): - """ IP4 MACIP wildcardMAC|subnetIP ACL routed traffic - """ - - self.run_traffic(self.WILD_MAC, self.SUBNET_IP, - self.ROUTED, self.IS_IP4, 9) - - def test_acl_routed_ip4_wildMAC_wildIP(self): - """ IP4 MACIP wildcardMAC|wildIP ACL - """ - - self.run_traffic(self.WILD_MAC, self.WILD_IP, - self.ROUTED, self.IS_IP4, 9) - - def test_acl_replace_traffic_ip4(self): - """ MACIP replace ACL with IP4 traffic - """ - self.run_traffic(self.OUI_MAC, self.SUBNET_IP, - self.BRIDGED, self.IS_IP4, 9, try_replace=True) - self.run_traffic(self.EXACT_MAC, self.EXACT_IP, - self.BRIDGED, self.IS_IP4, 9, try_replace=True) - - -class TestMACIP_IP6(MethodHolder): - """MACIP with IP6 traffic""" - - @classmethod - def setUpClass(cls): - super(TestMACIP_IP6, cls).setUpClass() - - @classmethod - def tearDownClass(cls): - super(TestMACIP_IP6, cls).tearDownClass() - - def test_acl_bridged_ip6_exactMAC_exactIP(self): - """ IP6 MACIP exactMAC|exactIP ACL bridged traffic - """ - - self.run_traffic(self.EXACT_MAC, self.EXACT_IP, - self.BRIDGED, self.IS_IP6, 9) - - def test_acl_bridged_ip6_exactMAC_subnetIP(self): - """ IP6 MACIP exactMAC|subnetIP ACL bridged traffic - """ - - self.run_traffic(self.EXACT_MAC, self.SUBNET_IP, - self.BRIDGED, self.IS_IP6, 9) - - def test_acl_bridged_ip6_exactMAC_wildIP(self): - """ IP6 MACIP exactMAC|wildIP ACL bridged traffic - """ - - self.run_traffic(self.EXACT_MAC, self.WILD_IP, - self.BRIDGED, self.IS_IP6, 9) - - def test_acl_bridged_ip6_ouiMAC_exactIP(self): - """ IP6 MACIP oui_MAC|exactIP ACL bridged traffic - """ - - self.run_traffic(self.OUI_MAC, self.EXACT_IP, - self.BRIDGED, self.IS_IP6, 9) - - def test_acl_bridged_ip6_ouiMAC_subnetIP(self): - """ IP6 MACIP ouiMAC|subnetIP ACL bridged traffic - """ - - self.run_traffic(self.OUI_MAC, self.SUBNET_IP, - self.BRIDGED, self.IS_IP6, 9) - - def test_acl_bridged_ip6_ouiMAC_wildIP(self): - """ IP6 MACIP ouiMAC|wildIP ACL bridged traffic - """ - - self.run_traffic(self.OUI_MAC, self.WILD_IP, - self.BRIDGED, self.IS_IP6, 9) - - def test_acl_bridged_ip6_wildMAC_exactIP(self): - """ IP6 MACIP wildcardMAC|exactIP ACL bridged traffic - """ - - self.run_traffic(self.WILD_MAC, self.EXACT_IP, - self.BRIDGED, self.IS_IP6, 9) - - def test_acl_bridged_ip6_wildMAC_subnetIP(self): - """ IP6 MACIP wildcardMAC|subnetIP ACL bridged traffic - """ - - self.run_traffic(self.WILD_MAC, self.SUBNET_IP, - self.BRIDGED, self.IS_IP6, 9) - - def test_acl_bridged_ip6_wildMAC_wildIP(self): - """ IP6 MACIP wildcardMAC|wildIP ACL bridged traffic - """ - - self.run_traffic(self.WILD_MAC, self.WILD_IP, - self.BRIDGED, self.IS_IP6, 9) - - def test_acl_routed_ip6_exactMAC_exactIP(self): - """ IP6 MACIP exactMAC|exactIP ACL routed traffic - """ - - self.run_traffic(self.EXACT_MAC, self.EXACT_IP, - self.ROUTED, self.IS_IP6, 9) - - def test_acl_routed_ip6_exactMAC_subnetIP(self): - """ IP6 MACIP exactMAC|subnetIP ACL routed traffic - """ - - self.run_traffic(self.EXACT_MAC, self.SUBNET_IP, - self.ROUTED, self.IS_IP6, 9) - - def test_acl_routed_ip6_exactMAC_wildIP(self): - """ IP6 MACIP exactMAC|wildIP ACL routed traffic - """ - - self.run_traffic(self.EXACT_MAC, self.WILD_IP, - self.ROUTED, self.IS_IP6, 9) - - def test_acl_routed_ip6_ouiMAC_exactIP(self): - """ IP6 MACIP ouiMAC|exactIP ACL routed traffic - """ - - self.run_traffic(self.OUI_MAC, self.EXACT_IP, - self.ROUTED, self.IS_IP6, 9) - - def test_acl_routed_ip6_ouiMAC_subnetIP(self): - """ IP6 MACIP ouiMAC|subnetIP ACL routed traffic - """ - - self.run_traffic(self.OUI_MAC, self.SUBNET_IP, - self.ROUTED, self.IS_IP6, 9) - - def test_acl_routed_ip6_ouiMAC_wildIP(self): - """ IP6 MACIP ouiMAC|wildIP ACL routed traffic - """ - - self.run_traffic(self.OUI_MAC, self.WILD_IP, - self.ROUTED, self.IS_IP6, 9) - - def test_acl_routed_ip6_wildMAC_exactIP(self): - """ IP6 MACIP wildcardMAC|exactIP ACL routed traffic - """ - - self.run_traffic(self.WILD_MAC, self.EXACT_IP, - self.ROUTED, self.IS_IP6, 9) - - def test_acl_routed_ip6_wildMAC_subnetIP(self): - """ IP6 MACIP wildcardMAC|subnetIP ACL routed traffic - """ - - self.run_traffic(self.WILD_MAC, self.SUBNET_IP, - self.ROUTED, self.IS_IP6, 9) - - def test_acl_routed_ip6_wildMAC_wildIP(self): - """ IP6 MACIP wildcardMAC|wildIP ACL - """ - - self.run_traffic(self.WILD_MAC, self.WILD_IP, - self.ROUTED, self.IS_IP6, 9) - - def test_acl_replace_traffic_ip6(self): - """ MACIP replace ACL with IP6 traffic - """ - self.run_traffic(self.OUI_MAC, self.SUBNET_IP, - self.BRIDGED, self.IS_IP6, 9, try_replace=True) - self.run_traffic(self.EXACT_MAC, self.EXACT_IP, - self.BRIDGED, self.IS_IP6, 9, try_replace=True) - - -class TestMACIP(MethodHolder): - """MACIP Tests""" - - @classmethod - def setUpClass(cls): - super(TestMACIP, cls).setUpClass() - - @classmethod - def tearDownClass(cls): - super(TestMACIP, cls).tearDownClass() - - def test_acl_1_2(self): - """ MACIP ACL with 2 entries - """ - - self.run_test_acls(self.EXACT_MAC, self.WILD_IP, 1, [2]) - - def test_acl_1_5(self): - """ MACIP ACL with 5 entries - """ - - self.run_test_acls(self.EXACT_MAC, self.SUBNET_IP, 1, [5]) - - def test_acl_1_10(self): - """ MACIP ACL with 10 entries - """ - - self.run_test_acls(self.EXACT_MAC, self.EXACT_IP, 1, [10]) - - def test_acl_1_20(self): - """ MACIP ACL with 20 entries - """ - - self.run_test_acls(self.OUI_MAC, self.WILD_IP, 1, [20]) - - def test_acl_1_50(self): - """ MACIP ACL with 50 entries - """ - - self.run_test_acls(self.OUI_MAC, self.SUBNET_IP, 1, [50]) - - def test_acl_1_100(self): - """ MACIP ACL with 100 entries - """ - - self.run_test_acls(self.OUI_MAC, self.EXACT_IP, 1, [100]) - - def test_acl_2_X(self): - """ MACIP 2 ACLs each with 100+ entries - """ - - self.run_test_acls(self.OUI_MAC, self.SUBNET_IP, 2, [100, 200]) - - def test_acl_10_X(self): - """ MACIP 10 ACLs each with 100+ entries - """ - - self.run_test_acls(self.EXACT_MAC, self.EXACT_IP, 10, - [100, 120, 140, 160, 180, 200, 210, 220, 230, 240]) - - def test_acl_10_X_traffic_ip4(self): - """ MACIP 10 ACLs each with 100+ entries with IP4 traffic - """ - - self.run_test_acls(self.EXACT_MAC, self.EXACT_IP, 10, - [100, 120, 140, 160, 180, 200, 210, 220, 230, 240], - self.BRIDGED, self.IS_IP4) - - def test_acl_10_X_traffic_ip6(self): - """ MACIP 10 ACLs each with 100+ entries with IP6 traffic - """ - - self.run_test_acls(self.EXACT_MAC, self.EXACT_IP, 10, - [100, 120, 140, 160, 180, 200, 210, 220, 230, 240], - self.BRIDGED, self.IS_IP6) - - def test_acl_replace(self): - """ MACIP replace ACL - """ - - r1 = self.create_rules(acl_count=3, rules_count=[2, 2, 2]) - r2 = self.create_rules(mac_type=self.OUI_MAC, ip_type=self.SUBNET_IP) - self.apply_macip_rules(r1) - - acls_before = self.macip_acl_dump_debug() - - # replace acls #2, #3 with new - reply = self.vapi.macip_acl_add_replace(r2[0], 2) - self.assertEqual(reply.retval, 0) - self.assertEqual(reply.acl_index, 2) - reply = self.vapi.macip_acl_add_replace(r2[1], 3) - self.assertEqual(reply.retval, 0) - self.assertEqual(reply.acl_index, 3) - - acls_after = self.macip_acl_dump_debug() - - # verify changes - self.assertEqual(len(acls_before), len(acls_after)) - for acl1, acl2 in zip( - acls_before[:2]+acls_before[4:], - acls_after[:2]+acls_after[4:]): - self.assertEqual(len(acl1), len(acl2)) - - self.assertEqual(len(acl1.r), len(acl2.r)) - for r1, r2 in zip(acl1.r, acl2.r): - self.assertEqual(len(acl1.r), len(acl2.r)) - self.assertEqual(acl1.r, acl2.r) - for acl1, acl2 in zip( - acls_before[2:4], - acls_after[2:4]): - self.assertEqual(len(acl1), len(acl2)) - - self.assertNotEqual(len(acl1.r), len(acl2.r)) - for r1, r2 in zip(acl1.r, acl2.r): - self.assertNotEqual(len(acl1.r), len(acl2.r)) - self.assertNotEqual(acl1.r, acl2.r) - - def test_delete_intf(self): - """ MACIP ACL delete intf with acl - """ - - intf_count = len(self.interfaces)+1 - intf = [] - self.apply_macip_rules(self.create_rules(acl_count=3, - rules_count=[3, 5, 4])) - - intf.append(VppLoInterface(self)) - intf.append(VppLoInterface(self)) - - sw_if_index0 = intf[0].sw_if_index - self.vapi.macip_acl_interface_add_del(sw_if_index0, 1) - - reply = self.vapi.macip_acl_interface_get() - self.assertEqual(reply.count, intf_count+1) - self.assertEqual(reply.acls[sw_if_index0], 1) - - sw_if_index1 = intf[1].sw_if_index - self.vapi.macip_acl_interface_add_del(sw_if_index1, 0) - - reply = self.vapi.macip_acl_interface_get() - self.assertEqual(reply.count, intf_count+2) - self.assertEqual(reply.acls[sw_if_index1], 0) - - intf[0].remove_vpp_config() - reply = self.vapi.macip_acl_interface_get() - self.assertEqual(reply.count, intf_count+2) - self.assertEqual(reply.acls[sw_if_index0], 4294967295) - self.assertEqual(reply.acls[sw_if_index1], 0) - - intf.append(VppLoInterface(self)) - intf.append(VppLoInterface(self)) - sw_if_index2 = intf[2].sw_if_index - sw_if_index3 = intf[3].sw_if_index - self.vapi.macip_acl_interface_add_del(sw_if_index2, 1) - self.vapi.macip_acl_interface_add_del(sw_if_index3, 1) - - reply = self.vapi.macip_acl_interface_get() - self.assertEqual(reply.count, intf_count+3) - self.assertEqual(reply.acls[sw_if_index1], 0) - self.assertEqual(reply.acls[sw_if_index2], 1) - self.assertEqual(reply.acls[sw_if_index3], 1) - self.logger.info("MACIP ACL on multiple interfaces:") - self.logger.info(self.vapi.ppcli("sh acl-plugin macip acl")) - self.logger.info(self.vapi.ppcli("sh acl-plugin macip acl index 1234")) - self.logger.info(self.vapi.ppcli("sh acl-plugin macip acl index 1")) - self.logger.info(self.vapi.ppcli("sh acl-plugin macip acl index 0")) - self.logger.info(self.vapi.ppcli("sh acl-plugin macip interface")) - - intf[2].remove_vpp_config() - intf[1].remove_vpp_config() - - reply = self.vapi.macip_acl_interface_get() - self.assertEqual(reply.count, intf_count+3) - self.assertEqual(reply.acls[sw_if_index0], 4294967295) - self.assertEqual(reply.acls[sw_if_index1], 4294967295) - self.assertEqual(reply.acls[sw_if_index2], 4294967295) - self.assertEqual(reply.acls[sw_if_index3], 1) - - intf[3].remove_vpp_config() - reply = self.vapi.macip_acl_interface_get() - - self.assertEqual(len([x for x in reply.acls if x != 4294967295]), 0) - - -class TestACL_dot1q_bridged(MethodHolder): - """ACL on dot1q bridged subinterfaces Tests""" - - @classmethod - def setUpClass(cls): - super(TestACL_dot1q_bridged, cls).setUpClass() - - @classmethod - def tearDownClass(cls): - super(TestACL_dot1q_bridged, cls).tearDownClass() - - def test_acl_bridged_ip4_subif_dot1q(self): - """ IP4 ACL SubIf Dot1Q bridged traffic""" - self.run_traffic(self.EXACT_MAC, self.EXACT_IP, self.BRIDGED, - self.IS_IP4, 9, tags=self.DOT1Q, isMACIP=False) - - def test_acl_bridged_ip6_subif_dot1q(self): - """ IP6 ACL SubIf Dot1Q bridged traffic""" - self.run_traffic(self.EXACT_MAC, self.EXACT_IP, self.BRIDGED, - self.IS_IP6, 9, tags=self.DOT1Q, isMACIP=False) - - -class TestACL_dot1ad_bridged(MethodHolder): - """ACL on dot1ad bridged subinterfaces Tests""" - - @classmethod - def setUpClass(cls): - super(TestACL_dot1ad_bridged, cls).setUpClass() - - @classmethod - def tearDownClass(cls): - super(TestACL_dot1ad_bridged, cls).tearDownClass() - - def test_acl_bridged_ip4_subif_dot1ad(self): - """ IP4 ACL SubIf Dot1AD bridged traffic""" - self.run_traffic(self.EXACT_MAC, self.EXACT_IP, self.BRIDGED, - self.IS_IP4, 9, tags=self.DOT1AD, isMACIP=False) - - def test_acl_bridged_ip6_subif_dot1ad(self): - """ IP6 ACL SubIf Dot1AD bridged traffic""" - self.run_traffic(self.EXACT_MAC, self.EXACT_IP, self.BRIDGED, - self.IS_IP6, 9, tags=self.DOT1AD, isMACIP=False) - - -class TestACL_dot1q_routed(MethodHolder): - """ACL on dot1q routed subinterfaces Tests""" - - @classmethod - def setUpClass(cls): - super(TestACL_dot1q_routed, cls).setUpClass() - - @classmethod - def tearDownClass(cls): - super(TestACL_dot1q_routed, cls).tearDownClass() - - def test_acl_routed_ip4_subif_dot1q(self): - """ IP4 ACL SubIf Dot1Q routed traffic""" - self.run_traffic(self.EXACT_MAC, self.EXACT_IP, self.ROUTED, - self.IS_IP4, 9, tags=self.DOT1Q, isMACIP=False) - - def test_acl_routed_ip6_subif_dot1q(self): - """ IP6 ACL SubIf Dot1Q routed traffic""" - self.run_traffic(self.EXACT_MAC, self.EXACT_IP, self.ROUTED, - self.IS_IP6, 9, tags=self.DOT1Q, isMACIP=False) - - def test_acl_routed_ip4_subif_dot1q_deny_by_tags(self): - """ IP4 ACL SubIf wrong tags Dot1Q routed traffic""" - self.run_traffic(self.EXACT_MAC, self.EXACT_IP, self.ROUTED, - self.IS_IP4, 9, True, tags=self.DOT1Q, isMACIP=False, - permit_tags=self.DENY_TAGS) - - def test_acl_routed_ip6_subif_dot1q_deny_by_tags(self): - """ IP6 ACL SubIf wrong tags Dot1Q routed traffic""" - self.run_traffic(self.EXACT_MAC, self.EXACT_IP, self.ROUTED, - self.IS_IP6, 9, True, tags=self.DOT1Q, isMACIP=False, - permit_tags=self.DENY_TAGS) - - -class TestACL_dot1ad_routed(MethodHolder): - """ACL on dot1ad routed subinterfaces Tests""" - - @classmethod - def setUpClass(cls): - super(TestACL_dot1ad_routed, cls).setUpClass() - - @classmethod - def tearDownClass(cls): - super(TestACL_dot1ad_routed, cls).tearDownClass() - - def test_acl_routed_ip6_subif_dot1ad(self): - """ IP6 ACL SubIf Dot1AD routed traffic""" - self.run_traffic(self.EXACT_MAC, self.EXACT_IP, self.ROUTED, - self.IS_IP6, 9, tags=self.DOT1AD, isMACIP=False) - - def test_acl_routed_ip4_subif_dot1ad(self): - """ IP4 ACL SubIf Dot1AD routed traffic""" - self.run_traffic(self.EXACT_MAC, self.EXACT_IP, self.ROUTED, - self.IS_IP4, 9, tags=self.DOT1AD, isMACIP=False) - - def test_acl_routed_ip6_subif_dot1ad_deny_by_tags(self): - """ IP6 ACL SubIf wrong tags Dot1AD routed traffic""" - self.run_traffic(self.EXACT_MAC, self.EXACT_IP, self.ROUTED, - self.IS_IP6, 9, True, tags=self.DOT1AD, isMACIP=False, - permit_tags=self.DENY_TAGS) - - def test_acl_routed_ip4_subif_dot1ad_deny_by_tags(self): - """ IP4 ACL SubIf wrong tags Dot1AD routed traffic""" - self.run_traffic(self.EXACT_MAC, self.EXACT_IP, self.ROUTED, - self.IS_IP4, 9, True, tags=self.DOT1AD, isMACIP=False, - permit_tags=self.DENY_TAGS) - - -if __name__ == '__main__': - unittest.main(testRunner=VppTestRunner) diff --git a/test/test_cdp.py b/test/test_cdp.py deleted file mode 100644 index 7f77b4bbb01..00000000000 --- a/test/test_cdp.py +++ /dev/null @@ -1,171 +0,0 @@ -#!/usr/bin/env python -""" CDP tests """ - -from scapy.packet import Packet -from scapy.all import ShortField, StrField -from scapy.layers.l2 import Dot3, LLC, SNAP -from scapy.contrib.cdp import CDPMsgDeviceID, CDPMsgSoftwareVersion, \ - CDPMsgPlatform, CDPMsgPortID, CDPv2_HDR - -from framework import VppTestCase -from scapy.all import raw -from re import compile -from time import sleep -from util import ppp -import platform - - -""" TestCDP is a subclass of VPPTestCase classes. - -CDP test. - -""" - - -class CustomTLV(Packet): - """ Custom TLV protocol layer for scapy """ - - fields_desc = [ - ShortField("type", 0), - ShortField("length", 4), - StrField("value", "") - - ] - - -class TestCDP(VppTestCase): - """ CDP Test Case """ - - nen_ptr = compile(r"not enabled") - cdp_ptr = compile(r"^([-\.\w]+)\s+([-\.\w]+)\s+([-\.\w]+)\s+([-\.\w]+)$") - err_ptr = compile(r"^([\d]+)\s+([-\w]+)\s+([ -\.\w)(]+)$") - - @property - def device_id(self): - return platform.node() - - @property - def version(self): - return platform.release() - - @property - def port_id(self): - return self.interface.name - - @property - def platform(self): - return platform.system() - - @classmethod - def setUpClass(cls): - super(TestCDP, cls).setUpClass() - try: - cls.create_pg_interfaces(range(1)) - cls.interface = cls.pg_interfaces[0] - - cls.interface.admin_up() - cls.interface.config_ip4() - cls.interface.resolve_arp() - - except Exception: - super(TestCDP, cls).tearDownClass() - raise - - @classmethod - def tearDownClass(cls): - super(TestCDP, cls).tearDownClass() - - def test_enable_cdp(self): - self.logger.info(self.vapi.cdp_enable_disable(enable_disable=1)) - ret = self.vapi.cli("show cdp") - self.logger.info(ret) - not_enabled = self.nen_ptr.search(ret) - self.assertFalse(not_enabled, "CDP isn't enabled") - - def test_send_cdp_packet(self): - self.logger.info(self.vapi.cdp_enable_disable(enable_disable=1)) - self.send_packet(self.create_packet()) - - neighbors = list(self.show_cdp()) - self.assertTrue(neighbors, "CDP didn't register neighbor") - - port, system = neighbors[0] - length = min(len(system), len(self.device_id)) - - self.assert_equal(port, self.port_id, "CDP received invalid port id") - self.assert_equal(system[:length], self.device_id[:length], - "CDP received invalid device id") - - def test_cdp_underflow_tlv(self): - self.send_bad_packet(3, ".") - - def test_cdp_overflow_tlv(self): - self.send_bad_packet(8, ".") - - def send_bad_packet(self, l, v): - self.logger.info(self.vapi.cdp_enable_disable(enable_disable=1)) - self.send_packet(self.create_bad_packet(l, v)) - - errors = list(self.show_errors()) - self.assertTrue(errors) - - expected_errors = False - for count, node, reason in errors: - if (node == u'cdp-input' and - reason == u'cdp packets with bad TLVs' and - int(count) >= 1): - - expected_errors = True - break - self.assertTrue(expected_errors, "CDP didn't drop bad packet") - - def send_packet(self, packet): - self.logger.debug(ppp("Sending packet:", packet)) - self.interface.add_stream(packet) - self.pg_start() - - def create_base_packet(self): - packet = (Dot3(src=self.interface.remote_mac, - dst="01:00:0c:cc:cc:cc") / - LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03) / - SNAP()/CDPv2_HDR()) - return packet - - def create_packet(self): - packet = (self.create_base_packet() / - CDPMsgDeviceID(val=self.device_id) / - CDPMsgSoftwareVersion(val=self.version) / - CDPMsgPortID(iface=self.port_id) / - CDPMsgPlatform(val=self.platform)) - return packet - - def create_bad_packet(self, tl=4, tv=""): - packet = (self.create_base_packet() / - CustomTLV(type=1, - length=tl, - value=tv)) - return packet - - def process_cli(self, exp, ptr): - for line in self.vapi.cli(exp).split('\n')[1:]: - m = ptr.match(line.strip()) - if m: - yield m.groups() - - def show_cdp(self): - for pack in self.process_cli("show cdp", self.cdp_ptr): - try: - port, system, _, _ = pack - except ValueError: - pass - else: - yield port, system - - def show_errors(self): - for pack in self.process_cli("show errors", self.err_ptr): - try: - count, node, reason = pack - except ValueError: - pass - else: - yield count, node, reason diff --git a/test/test_classify_l2_acl.py b/test/test_classify_l2_acl.py deleted file mode 100644 index 8ba7181aef1..00000000000 --- a/test/test_classify_l2_acl.py +++ /dev/null @@ -1,689 +0,0 @@ -#!/usr/bin/env python -""" Classifier-based L2 ACL Test Case HLD: -""" - -import unittest -import random -import binascii -import socket - - -from scapy.packet import Raw -from scapy.data import ETH_P_IP -from scapy.layers.l2 import Ether -from scapy.layers.inet import IP, TCP, UDP, ICMP -from scapy.layers.inet6 import IPv6, ICMPv6EchoRequest -from scapy.layers.inet6 import IPv6ExtHdrFragment -from framework import VppTestCase, VppTestRunner -from util import Host, ppp - - -class TestClassifyAcl(VppTestCase): - """ Classifier-based L2 input and output ACL Test Case """ - - # traffic types - IP = 0 - ICMP = 1 - - # IP version - IPRANDOM = -1 - IPV4 = 0 - IPV6 = 1 - - # rule types - DENY = 0 - PERMIT = 1 - - # supported protocols - proto = [[6, 17], [1, 58]] - proto_map = {1: 'ICMP', 58: 'ICMPv6EchoRequest', 6: 'TCP', 17: 'UDP'} - ICMPv4 = 0 - ICMPv6 = 1 - TCP = 0 - UDP = 1 - PROTO_ALL = 0 - - # port ranges - PORTS_ALL = -1 - PORTS_RANGE = 0 - PORTS_RANGE_2 = 1 - udp_sport_from = 10 - udp_sport_to = udp_sport_from + 5 - udp_dport_from = 20000 - udp_dport_to = udp_dport_from + 5000 - tcp_sport_from = 30 - tcp_sport_to = tcp_sport_from + 5 - tcp_dport_from = 40000 - tcp_dport_to = tcp_dport_from + 5000 - - udp_sport_from_2 = 90 - udp_sport_to_2 = udp_sport_from_2 + 5 - udp_dport_from_2 = 30000 - udp_dport_to_2 = udp_dport_from_2 + 5000 - tcp_sport_from_2 = 130 - tcp_sport_to_2 = tcp_sport_from_2 + 5 - tcp_dport_from_2 = 20000 - tcp_dport_to_2 = tcp_dport_from_2 + 5000 - - icmp4_type = 8 # echo request - icmp4_code = 3 - icmp6_type = 128 # echo request - icmp6_code = 3 - - icmp4_type_2 = 8 - icmp4_code_from_2 = 5 - icmp4_code_to_2 = 20 - icmp6_type_2 = 128 - icmp6_code_from_2 = 8 - icmp6_code_to_2 = 42 - - # Test variables - bd_id = 1 - - @classmethod - def setUpClass(cls): - """ - Perform standard class setup (defined by class method setUpClass in - class VppTestCase) before running the test case, set test case related - variables and configure VPP. - """ - super(TestClassifyAcl, cls).setUpClass() - - try: - # Create 2 pg interfaces - cls.create_pg_interfaces(range(2)) - - # Packet flows mapping pg0 -> pg1, pg2 etc. - cls.flows = dict() - cls.flows[cls.pg0] = [cls.pg1] - - # Packet sizes - cls.pg_if_packet_sizes = [64, 512, 1518, 9018] - - # Create BD with MAC learning and unknown unicast flooding disabled - # and put interfaces to this BD - cls.vapi.bridge_domain_add_del(bd_id=cls.bd_id, uu_flood=1, - learn=1) - for pg_if in cls.pg_interfaces: - cls.vapi.sw_interface_set_l2_bridge( - rx_sw_if_index=pg_if.sw_if_index, bd_id=cls.bd_id) - - # Set up all interfaces - for i in cls.pg_interfaces: - i.admin_up() - - # Mapping between packet-generator index and lists of test hosts - cls.hosts_by_pg_idx = dict() - for pg_if in cls.pg_interfaces: - cls.hosts_by_pg_idx[pg_if.sw_if_index] = [] - - # Create list of deleted hosts - cls.deleted_hosts_by_pg_idx = dict() - for pg_if in cls.pg_interfaces: - cls.deleted_hosts_by_pg_idx[pg_if.sw_if_index] = [] - - # warm-up the mac address tables - # self.warmup_test() - - # Holder of the active classify table key - cls.acl_active_table = '' - - except Exception: - super(TestClassifyAcl, cls).tearDownClass() - raise - - @classmethod - def tearDownClass(cls): - super(TestClassifyAcl, cls).tearDownClass() - - def setUp(self): - super(TestClassifyAcl, self).setUp() - - self.acl_tbl_idx = {} - self.reset_packet_infos() - - def tearDown(self): - """ - Show various debug prints after each test. - """ - if not self.vpp_dead: - if self.acl_active_table == 'mac_inout': - self.output_acl_set_interface( - self.pg1, self.acl_tbl_idx.get(self.acl_active_table), 0) - self.input_acl_set_interface( - self.pg0, self.acl_tbl_idx.get(self.acl_active_table), 0) - self.acl_active_table = '' - elif self.acl_active_table == 'mac_out': - self.output_acl_set_interface( - self.pg1, self.acl_tbl_idx.get(self.acl_active_table), 0) - self.acl_active_table = '' - elif self.acl_active_table == 'mac_in': - self.input_acl_set_interface( - self.pg0, self.acl_tbl_idx.get(self.acl_active_table), 0) - self.acl_active_table = '' - - super(TestClassifyAcl, self).tearDown() - - def show_commands_at_teardown(self): - self.logger.info(self.vapi.ppcli("show inacl type l2")) - self.logger.info(self.vapi.ppcli("show outacl type l2")) - self.logger.info(self.vapi.ppcli("show classify tables verbose")) - self.logger.info(self.vapi.ppcli("show bridge-domain %s detail" - % self.bd_id)) - - @staticmethod - def build_mac_mask(dst_mac='', src_mac='', ether_type=''): - """Build MAC ACL mask data with hexstring format - - :param str dst_mac: source MAC address <0-ffffffffffff> - :param str src_mac: destination MAC address <0-ffffffffffff> - :param str ether_type: ethernet type <0-ffff> - """ - - return ('{!s:0>12}{!s:0>12}{!s:0>4}'.format( - dst_mac, src_mac, ether_type)).rstrip('0') - - @staticmethod - def build_mac_match(dst_mac='', src_mac='', ether_type=''): - """Build MAC ACL match data with hexstring format - - :param str dst_mac: source MAC address <x:x:x:x:x:x> - :param str src_mac: destination MAC address <x:x:x:x:x:x> - :param str ether_type: ethernet type <0-ffff> - """ - if dst_mac: - dst_mac = dst_mac.replace(':', '') - if src_mac: - src_mac = src_mac.replace(':', '') - - return ('{!s:0>12}{!s:0>12}{!s:0>4}'.format( - dst_mac, src_mac, ether_type)).rstrip('0') - - def create_classify_table(self, key, mask, data_offset=0, is_add=1): - """Create Classify Table - - :param str key: key for classify table (ex, ACL name). - :param str mask: mask value for interested traffic. - :param int match_n_vectors: - :param int is_add: option to configure classify table. - - create(1) or delete(0) - """ - r = self.vapi.classify_add_del_table( - is_add, - binascii.unhexlify(mask), - match_n_vectors=(len(mask) - 1) // 32 + 1, - miss_next_index=0, - current_data_flag=1, - current_data_offset=data_offset) - self.assertIsNotNone(r, 'No response msg for add_del_table') - self.acl_tbl_idx[key] = r.new_table_index - - def create_classify_session(self, intf, table_index, match, - hit_next_index=0xffffffff, is_add=1): - """Create Classify Session - - :param VppInterface intf: Interface to apply classify session. - :param int table_index: table index to identify classify table. - :param str match: matched value for interested traffic. - :param int pbr_action: enable/disable PBR feature. - :param int vrfid: VRF id. - :param int is_add: option to configure classify session. - - create(1) or delete(0) - """ - r = self.vapi.classify_add_del_session( - is_add, - table_index, - binascii.unhexlify(match), - hit_next_index=hit_next_index) - self.assertIsNotNone(r, 'No response msg for add_del_session') - - def input_acl_set_interface(self, intf, table_index, is_add=1): - """Configure Input ACL interface - - :param VppInterface intf: Interface to apply Input ACL feature. - :param int table_index: table index to identify classify table. - :param int is_add: option to configure classify session. - - enable(1) or disable(0) - """ - r = self.vapi.input_acl_set_interface( - is_add, - intf.sw_if_index, - l2_table_index=table_index) - self.assertIsNotNone(r, 'No response msg for acl_set_interface') - - def output_acl_set_interface(self, intf, table_index, is_add=1): - """Configure Output ACL interface - - :param VppInterface intf: Interface to apply Output ACL feature. - :param int table_index: table index to identify classify table. - :param int is_add: option to configure classify session. - - enable(1) or disable(0) - """ - r = self.vapi.output_acl_set_interface( - is_add, - intf.sw_if_index, - l2_table_index=table_index) - self.assertIsNotNone(r, 'No response msg for acl_set_interface') - - def create_hosts(self, count, start=0): - """ - Create required number of host MAC addresses and distribute them among - interfaces. Create host IPv4 address for every host MAC address. - - :param int count: Number of hosts to create MAC/IPv4 addresses for. - :param int start: Number to start numbering from. - """ - n_int = len(self.pg_interfaces) - macs_per_if = count / n_int - i = -1 - for pg_if in self.pg_interfaces: - i += 1 - start_nr = macs_per_if * i + start - end_nr = count + start if i == (n_int - 1) \ - else macs_per_if * (i + 1) + start - hosts = self.hosts_by_pg_idx[pg_if.sw_if_index] - for j in range(start_nr, end_nr): - host = Host( - "00:00:00:ff:%02x:%02x" % (pg_if.sw_if_index, j), - "172.17.1%02x.%u" % (pg_if.sw_if_index, j), - "2017:dead:%02x::%u" % (pg_if.sw_if_index, j)) - hosts.append(host) - - def create_upper_layer(self, packet_index, proto, ports=0): - p = self.proto_map[proto] - if p == 'UDP': - if ports == 0: - return UDP(sport=random.randint(self.udp_sport_from, - self.udp_sport_to), - dport=random.randint(self.udp_dport_from, - self.udp_dport_to)) - else: - return UDP(sport=ports, dport=ports) - elif p == 'TCP': - if ports == 0: - return TCP(sport=random.randint(self.tcp_sport_from, - self.tcp_sport_to), - dport=random.randint(self.tcp_dport_from, - self.tcp_dport_to)) - else: - return TCP(sport=ports, dport=ports) - return '' - - def create_stream(self, src_if, packet_sizes, traffic_type=0, ipv6=0, - proto=-1, ports=0, fragments=False, - pkt_raw=True, etype=-1): - """ - Create input packet stream for defined interface using hosts or - deleted_hosts list. - - :param object src_if: Interface to create packet stream for. - :param list packet_sizes: List of required packet sizes. - :param traffic_type: 1: ICMP packet, 2: IPv6 with EH, 0: otherwise. - :return: Stream of packets. - """ - pkts = [] - if self.flows.__contains__(src_if): - src_hosts = self.hosts_by_pg_idx[src_if.sw_if_index] - for dst_if in self.flows[src_if]: - dst_hosts = self.hosts_by_pg_idx[dst_if.sw_if_index] - n_int = len(dst_hosts) * len(src_hosts) - for i in range(0, n_int): - dst_host = dst_hosts[i / len(src_hosts)] - src_host = src_hosts[i % len(src_hosts)] - pkt_info = self.create_packet_info(src_if, dst_if) - if ipv6 == 1: - pkt_info.ip = 1 - elif ipv6 == 0: - pkt_info.ip = 0 - else: - pkt_info.ip = random.choice([0, 1]) - if proto == -1: - pkt_info.proto = random.choice(self.proto[self.IP]) - else: - pkt_info.proto = proto - payload = self.info_to_payload(pkt_info) - p = Ether(dst=dst_host.mac, src=src_host.mac) - if etype > 0: - p = Ether(dst=dst_host.mac, - src=src_host.mac, - type=etype) - if pkt_info.ip: - p /= IPv6(dst=dst_host.ip6, src=src_host.ip6) - if fragments: - p /= IPv6ExtHdrFragment(offset=64, m=1) - else: - if fragments: - p /= IP(src=src_host.ip4, dst=dst_host.ip4, - flags=1, frag=64) - else: - p /= IP(src=src_host.ip4, dst=dst_host.ip4) - if traffic_type == self.ICMP: - if pkt_info.ip: - p /= ICMPv6EchoRequest(type=self.icmp6_type, - code=self.icmp6_code) - else: - p /= ICMP(type=self.icmp4_type, - code=self.icmp4_code) - else: - p /= self.create_upper_layer(i, pkt_info.proto, ports) - if pkt_raw: - p /= Raw(payload) - pkt_info.data = p.copy() - if pkt_raw: - size = random.choice(packet_sizes) - self.extend_packet(p, size) - pkts.append(p) - return pkts - - def verify_capture(self, pg_if, capture, - traffic_type=0, ip_type=0, etype=-1): - """ - Verify captured input packet stream for defined interface. - - :param object pg_if: Interface to verify captured packet stream for. - :param list capture: Captured packet stream. - :param traffic_type: 1: ICMP packet, 2: IPv6 with EH, 0: otherwise. - """ - last_info = dict() - for i in self.pg_interfaces: - last_info[i.sw_if_index] = None - dst_sw_if_index = pg_if.sw_if_index - for packet in capture: - if etype > 0: - if packet[Ether].type != etype: - self.logger.error(ppp("Unexpected ethertype in packet:", - packet)) - else: - continue - try: - # Raw data for ICMPv6 are stored in ICMPv6EchoRequest.data - if traffic_type == self.ICMP and ip_type == self.IPV6: - payload_info = self.payload_to_info( - packet[ICMPv6EchoRequest].data) - payload = packet[ICMPv6EchoRequest] - else: - payload_info = self.payload_to_info(packet[Raw]) - payload = packet[self.proto_map[payload_info.proto]] - except: - self.logger.error(ppp("Unexpected or invalid packet " - "(outside network):", packet)) - raise - - if ip_type != 0: - self.assertEqual(payload_info.ip, ip_type) - if traffic_type == self.ICMP: - try: - if payload_info.ip == 0: - self.assertEqual(payload.type, self.icmp4_type) - self.assertEqual(payload.code, self.icmp4_code) - else: - self.assertEqual(payload.type, self.icmp6_type) - self.assertEqual(payload.code, self.icmp6_code) - except: - self.logger.error(ppp("Unexpected or invalid packet " - "(outside network):", packet)) - raise - else: - try: - ip_version = IPv6 if payload_info.ip == 1 else IP - - ip = packet[ip_version] - packet_index = payload_info.index - - self.assertEqual(payload_info.dst, dst_sw_if_index) - self.logger.debug("Got packet on port %s: src=%u (id=%u)" % - (pg_if.name, payload_info.src, - packet_index)) - next_info = self.get_next_packet_info_for_interface2( - payload_info.src, dst_sw_if_index, - last_info[payload_info.src]) - last_info[payload_info.src] = next_info - self.assertTrue(next_info is not None) - self.assertEqual(packet_index, next_info.index) - saved_packet = next_info.data - # Check standard fields - self.assertEqual(ip.src, saved_packet[ip_version].src) - self.assertEqual(ip.dst, saved_packet[ip_version].dst) - p = self.proto_map[payload_info.proto] - if p == 'TCP': - tcp = packet[TCP] - self.assertEqual(tcp.sport, saved_packet[ - TCP].sport) - self.assertEqual(tcp.dport, saved_packet[ - TCP].dport) - elif p == 'UDP': - udp = packet[UDP] - self.assertEqual(udp.sport, saved_packet[ - UDP].sport) - self.assertEqual(udp.dport, saved_packet[ - UDP].dport) - except: - self.logger.error(ppp("Unexpected or invalid packet:", - packet)) - raise - for i in self.pg_interfaces: - remaining_packet = self.get_next_packet_info_for_interface2( - i, dst_sw_if_index, last_info[i.sw_if_index]) - self.assertTrue( - remaining_packet is None, - "Port %u: Packet expected from source %u didn't arrive" % - (dst_sw_if_index, i.sw_if_index)) - - def run_traffic_no_check(self): - # Test - # Create incoming packet streams for packet-generator interfaces - for i in self.pg_interfaces: - if self.flows.__contains__(i): - pkts = self.create_stream(i, self.pg_if_packet_sizes) - if len(pkts) > 0: - i.add_stream(pkts) - - # Enable packet capture and start packet sending - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - - def run_verify_test(self, traffic_type=0, ip_type=0, proto=-1, ports=0, - frags=False, pkt_raw=True, etype=-1): - # Test - # Create incoming packet streams for packet-generator interfaces - pkts_cnt = 0 - for i in self.pg_interfaces: - if self.flows.__contains__(i): - pkts = self.create_stream(i, self.pg_if_packet_sizes, - traffic_type, ip_type, proto, ports, - frags, pkt_raw, etype) - if len(pkts) > 0: - i.add_stream(pkts) - pkts_cnt += len(pkts) - - # Enable packet capture and start packet sendingself.IPV - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - - # Verify - # Verify outgoing packet streams per packet-generator interface - for src_if in self.pg_interfaces: - if self.flows.__contains__(src_if): - for dst_if in self.flows[src_if]: - capture = dst_if.get_capture(pkts_cnt) - self.logger.info("Verifying capture on interface %s" % - dst_if.name) - self.verify_capture(dst_if, capture, - traffic_type, ip_type, etype) - - def run_verify_negat_test(self, traffic_type=0, ip_type=0, proto=-1, - ports=0, frags=False, etype=-1): - # Test - self.reset_packet_infos() - for i in self.pg_interfaces: - if self.flows.__contains__(i): - pkts = self.create_stream(i, self.pg_if_packet_sizes, - traffic_type, ip_type, proto, ports, - frags, True, etype) - if len(pkts) > 0: - i.add_stream(pkts) - - # Enable packet capture and start packet sending - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - - # Verify - # Verify outgoing packet streams per packet-generator interface - for src_if in self.pg_interfaces: - if self.flows.__contains__(src_if): - for dst_if in self.flows[src_if]: - self.logger.info("Verifying capture on interface %s" % - dst_if.name) - capture = dst_if.get_capture(0) - self.assertEqual(len(capture), 0) - - def build_classify_table(self, src_mac='', dst_mac='', ether_type='', - etype='', key='mac', hit_next_index=0xffffffff): - # Basic ACL testing - a_mask = self.build_mac_mask(src_mac=src_mac, dst_mac=dst_mac, - ether_type=ether_type) - self.create_classify_table(key, a_mask) - for host in self.hosts_by_pg_idx[self.pg0.sw_if_index]: - s_mac = host.mac if src_mac else '' - if dst_mac: - for dst_if in self.flows[self.pg0]: - for dst_host in self.hosts_by_pg_idx[dst_if.sw_if_index]: - self.create_classify_session( - self.pg0, self.acl_tbl_idx.get(key), - self.build_mac_match(src_mac=s_mac, - dst_mac=dst_host.mac, - ether_type=etype), - hit_next_index=hit_next_index) - else: - self.create_classify_session( - self.pg0, self.acl_tbl_idx.get(key), - self.build_mac_match(src_mac=s_mac, dst_mac='', - ether_type=etype), - hit_next_index=hit_next_index) - - def test_0000_warmup_test(self): - """ Learn the MAC addresses - """ - self.create_hosts(2) - self.run_traffic_no_check() - - def test_0010_inacl_permit_src_mac(self): - """ Input L2 ACL test - permit source MAC - - Test scenario for basic IP ACL with source IP - - Create IPv4 stream for pg0 -> pg1 interface. - - Create ACL with source MAC address. - - Send and verify received packets on pg1 interface. - """ - key = 'mac_in' - self.build_classify_table(src_mac='ffffffffffff', key=key) - self.input_acl_set_interface(self.pg0, self.acl_tbl_idx.get(key)) - self.acl_active_table = key - self.run_verify_test(self.IP, self.IPV4, -1) - - def test_0011_inacl_permit_dst_mac(self): - """ Input L2 ACL test - permit destination MAC - - Test scenario for basic IP ACL with source IP - - Create IPv4 stream for pg0 -> pg1 interface. - - Create ACL with destination MAC address. - - Send and verify received packets on pg1 interface. - """ - key = 'mac_in' - self.build_classify_table(dst_mac='ffffffffffff', key=key) - self.input_acl_set_interface(self.pg0, self.acl_tbl_idx.get(key)) - self.acl_active_table = key - self.run_verify_test(self.IP, self.IPV4, -1) - - def test_0012_inacl_permit_src_dst_mac(self): - """ Input L2 ACL test - permit source and destination MAC - - Test scenario for basic IP ACL with source IP - - Create IPv4 stream for pg0 -> pg1 interface. - - Create ACL with source and destination MAC addresses. - - Send and verify received packets on pg1 interface. - """ - key = 'mac_in' - self.build_classify_table( - src_mac='ffffffffffff', dst_mac='ffffffffffff', key=key) - self.input_acl_set_interface(self.pg0, self.acl_tbl_idx.get(key)) - self.acl_active_table = key - self.run_verify_test(self.IP, self.IPV4, -1) - - def test_0013_inacl_permit_ether_type(self): - """ Input L2 ACL test - permit ether_type - - Test scenario for basic IP ACL with source IP - - Create IPv4 stream for pg0 -> pg1 interface. - - Create ACL with destination MAC address. - - Send and verify received packets on pg1 interface. - """ - key = 'mac_in' - self.build_classify_table( - ether_type='ffff', etype=hex(ETH_P_IP)[2:], key=key) - self.input_acl_set_interface(self.pg0, self.acl_tbl_idx.get(key)) - self.acl_active_table = key - self.run_verify_test(self.IP, self.IPV4, -1) - - def test_0015_inacl_deny(self): - """ Input L2 ACL test - deny - - Test scenario for basic IP ACL with source IP - - Create IPv4 stream for pg0 -> pg1 interface. - - - Create ACL with source MAC address. - - Send and verify no received packets on pg1 interface. - """ - key = 'mac_in' - self.build_classify_table( - src_mac='ffffffffffff', hit_next_index=0, key=key) - self.input_acl_set_interface(self.pg0, self.acl_tbl_idx.get(key)) - self.acl_active_table = key - self.run_verify_negat_test(self.IP, self.IPV4, -1) - - def test_0020_outacl_permit(self): - """ Output L2 ACL test - permit - - Test scenario for basic IP ACL with source IP - - Create IPv4 stream for pg0 -> pg1 interface. - - Create ACL with source MAC address. - - Send and verify received packets on pg1 interface. - """ - key = 'mac_out' - self.build_classify_table(src_mac='ffffffffffff', key=key) - self.output_acl_set_interface(self.pg1, self.acl_tbl_idx.get(key)) - self.acl_active_table = key - self.run_verify_test(self.IP, self.IPV4, -1) - - def test_0025_outacl_deny(self): - """ Output L2 ACL test - deny - - Test scenario for basic IP ACL with source IP - - Create IPv4 stream for pg0 -> pg1 interface. - - Create ACL with source MAC address. - - Send and verify no received packets on pg1 interface. - """ - key = 'mac_out' - self.build_classify_table( - src_mac='ffffffffffff', hit_next_index=0, key=key) - self.output_acl_set_interface(self.pg1, self.acl_tbl_idx.get(key)) - self.acl_active_table = key - self.run_verify_negat_test(self.IP, self.IPV4, -1) - - def test_0030_inoutacl_permit(self): - """ Input+Output L2 ACL test - permit - - Test scenario for basic IP ACL with source IP - - Create IPv4 stream for pg0 -> pg1 interface. - - Create ACLs with source MAC address. - - Send and verify received packets on pg1 interface. - """ - key = 'mac_inout' - self.build_classify_table(src_mac='ffffffffffff', key=key) - self.output_acl_set_interface(self.pg1, self.acl_tbl_idx.get(key)) - self.input_acl_set_interface(self.pg0, self.acl_tbl_idx.get(key)) - self.acl_active_table = key - self.run_verify_test(self.IP, self.IPV4, -1) - -if __name__ == '__main__': - unittest.main(testRunner=VppTestRunner) diff --git a/test/test_flowprobe.py b/test/test_flowprobe.py deleted file mode 100644 index 9ffe84b8c2c..00000000000 --- a/test/test_flowprobe.py +++ /dev/null @@ -1,1082 +0,0 @@ -#!/usr/bin/env python -from __future__ import print_function -import binascii -import random -import socket -import unittest -import time -import re - -from scapy.packet import Raw -from scapy.layers.l2 import Ether -from scapy.layers.inet import IP, TCP, UDP -from scapy.layers.inet6 import IPv6 - -from framework import VppTestCase, VppTestRunner, running_extended_tests -from vpp_object import VppObject -from vpp_pg_interface import CaptureTimeoutError -from util import ppp -from ipfix import IPFIX, Set, Template, Data, IPFIXDecoder -from vpp_ip_route import VppIpRoute, VppRoutePath - - -class VppCFLOW(VppObject): - """CFLOW object for IPFIX exporter and Flowprobe feature""" - - def __init__(self, test, intf='pg2', active=0, passive=0, timeout=100, - mtu=1024, datapath='l2', layer='l2 l3 l4'): - self._test = test - self._intf = intf - self._active = active - if passive == 0 or passive < active: - self._passive = active+1 - else: - self._passive = passive - self._datapath = datapath # l2 ip4 ip6 - self._collect = layer # l2 l3 l4 - self._timeout = timeout - self._mtu = mtu - self._configured = False - - def add_vpp_config(self): - self.enable_exporter() - self._test.vapi.flowprobe_params( - record_l2=1 if 'l2' in self._collect.lower() else 0, - record_l3=1 if 'l3' in self._collect.lower() else 0, - record_l4=1 if 'l4' in self._collect.lower() else 0, - active_timer=self._active, passive_timer=self._passive) - self.enable_flowprobe_feature() - self._test.vapi.cli("ipfix flush") - self._configured = True - - def remove_vpp_config(self): - self.disable_exporter() - self.disable_flowprobe_feature() - self._test.vapi.cli("ipfix flush") - self._configured = False - - def enable_exporter(self): - self._test.vapi.set_ipfix_exporter( - collector_address=self._test.pg0.remote_ip4n, - src_address=self._test.pg0.local_ip4n, - path_mtu=self._mtu, - template_interval=self._timeout) - - def enable_flowprobe_feature(self): - self._test.vapi.ppcli("flowprobe feature add-del %s %s" % - (self._intf, self._datapath)) - - def disable_exporter(self): - self._test.vapi.cli("set ipfix exporter collector 0.0.0.0") - - def disable_flowprobe_feature(self): - self._test.vapi.cli("flowprobe feature add-del %s %s disable" % - (self._intf, self._datapath)) - - def object_id(self): - return "ipfix-collector-%s-%s" % (self._src, self.dst) - - def query_vpp_config(self): - return self._configured - - def verify_templates(self, decoder=None, timeout=1, count=3): - templates = [] - p = self._test.wait_for_cflow_packet(self._test.collector, 2, timeout) - self._test.assertTrue(p.haslayer(IPFIX)) - if decoder is not None and p.haslayer(Template): - templates.append(p[Template].templateID) - decoder.add_template(p.getlayer(Template)) - if count > 1: - p = self._test.wait_for_cflow_packet(self._test.collector, 2) - self._test.assertTrue(p.haslayer(IPFIX)) - if decoder is not None and p.haslayer(Template): - templates.append(p[Template].templateID) - decoder.add_template(p.getlayer(Template)) - if count > 2: - p = self._test.wait_for_cflow_packet(self._test.collector, 2) - self._test.assertTrue(p.haslayer(IPFIX)) - if decoder is not None and p.haslayer(Template): - templates.append(p[Template].templateID) - decoder.add_template(p.getlayer(Template)) - return templates - - -class MethodHolder(VppTestCase): - """ Flow-per-packet plugin: test L2, IP4, IP6 reporting """ - - # Test variables - debug_print = False - max_number_of_packets = 10 - pkts = [] - - @classmethod - def setUpClass(cls): - """ - Perform standard class setup (defined by class method setUpClass in - class VppTestCase) before running the test case, set test case related - variables and configure VPP. - """ - super(MethodHolder, cls).setUpClass() - try: - # Create pg interfaces - cls.create_pg_interfaces(range(9)) - - # Packet sizes - cls.pg_if_packet_sizes = [64, 512, 1518, 9018] - - # Create BD with MAC learning and unknown unicast flooding disabled - # and put interfaces to this BD - cls.vapi.bridge_domain_add_del(bd_id=1, uu_flood=1, learn=1) - cls.vapi.sw_interface_set_l2_bridge( - rx_sw_if_index=cls.pg1._sw_if_index, bd_id=1) - cls.vapi.sw_interface_set_l2_bridge( - rx_sw_if_index=cls.pg2._sw_if_index, bd_id=1) - - # Set up all interfaces - for i in cls.pg_interfaces: - i.admin_up() - - cls.pg0.config_ip4() - cls.pg0.configure_ipv4_neighbors() - cls.collector = cls.pg0 - - cls.pg1.config_ip4() - cls.pg1.resolve_arp() - cls.pg2.config_ip4() - cls.pg2.resolve_arp() - cls.pg3.config_ip4() - cls.pg3.resolve_arp() - cls.pg4.config_ip4() - cls.pg4.resolve_arp() - cls.pg7.config_ip4() - cls.pg8.config_ip4() - cls.pg8.configure_ipv4_neighbors() - - cls.pg5.config_ip6() - cls.pg5.resolve_ndp() - cls.pg5.disable_ipv6_ra() - cls.pg6.config_ip6() - cls.pg6.resolve_ndp() - cls.pg6.disable_ipv6_ra() - except Exception: - super(MethodHolder, cls).tearDownClass() - raise - - @classmethod - def tearDownClass(cls): - super(MethodHolder, cls).tearDownClass() - - def create_stream(self, src_if=None, dst_if=None, packets=None, - size=None, ip_ver='v4'): - """Create a packet stream to tickle the plugin - - :param VppInterface src_if: Source interface for packet stream - :param VppInterface src_if: Dst interface for packet stream - """ - if src_if is None: - src_if = self.pg1 - if dst_if is None: - dst_if = self.pg2 - self.pkts = [] - if packets is None: - packets = random.randint(1, self.max_number_of_packets) - pkt_size = size - for p in range(0, packets): - if size is None: - pkt_size = random.choice(self.pg_if_packet_sizes) - info = self.create_packet_info(src_if, dst_if) - payload = self.info_to_payload(info) - p = Ether(src=src_if.remote_mac, dst=src_if.local_mac) - if ip_ver == 'v4': - p /= IP(src=src_if.remote_ip4, dst=dst_if.remote_ip4) - else: - p /= IPv6(src=src_if.remote_ip6, dst=dst_if.remote_ip6) - p /= UDP(sport=1234, dport=4321) - p /= Raw(payload) - info.data = p.copy() - self.extend_packet(p, pkt_size) - self.pkts.append(p) - - def verify_cflow_data(self, decoder, capture, cflow): - octets = 0 - packets = 0 - for p in capture: - octets += p[IP].len - packets += 1 - if cflow.haslayer(Data): - data = decoder.decode_data_set(cflow.getlayer(Set)) - for record in data: - self.assertEqual(int(binascii.hexlify(record[1]), 16), octets) - self.assertEqual(int(binascii.hexlify(record[2]), 16), packets) - - def send_packets(self, src_if=None, dst_if=None): - if src_if is None: - src_if = self.pg1 - if dst_if is None: - dst_if = self.pg2 - self.pg_enable_capture([dst_if]) - src_if.add_stream(self.pkts) - self.pg_start() - return dst_if.get_capture(len(self.pkts)) - - def verify_cflow_data_detail(self, decoder, capture, cflow, - data_set={1: 'octets', 2: 'packets'}, - ip_ver='v4'): - if self.debug_print: - print(capture[0].show()) - if cflow.haslayer(Data): - data = decoder.decode_data_set(cflow.getlayer(Set)) - if self.debug_print: - print(data) - if ip_ver == 'v4': - ip_layer = capture[0][IP] - else: - ip_layer = capture[0][IPv6] - if data_set is not None: - for record in data: - # skip flow if ingress/egress interface is 0 - if int(binascii.hexlify(record[10]), 16) == 0: - continue - if int(binascii.hexlify(record[14]), 16) == 0: - continue - - for field in data_set: - if field not in record.keys(): - continue - value = data_set[field] - if value == 'octets': - value = ip_layer.len - if ip_ver == 'v6': - value += 40 # ??? is this correct - elif value == 'packets': - value = 1 - elif value == 'src_ip': - if ip_ver == 'v4': - ip = socket.inet_pton(socket.AF_INET, - ip_layer.src) - else: - ip = socket.inet_pton(socket.AF_INET6, - ip_layer.src) - value = int(binascii.hexlify(ip), 16) - elif value == 'dst_ip': - if ip_ver == 'v4': - ip = socket.inet_pton(socket.AF_INET, - ip_layer.dst) - else: - ip = socket.inet_pton(socket.AF_INET6, - ip_layer.dst) - value = int(binascii.hexlify(ip), 16) - elif value == 'sport': - value = int(capture[0][UDP].sport) - elif value == 'dport': - value = int(capture[0][UDP].dport) - self.assertEqual(int(binascii.hexlify( - record[field]), 16), - value) - - def verify_cflow_data_notimer(self, decoder, capture, cflows): - idx = 0 - for cflow in cflows: - if cflow.haslayer(Data): - data = decoder.decode_data_set(cflow.getlayer(Set)) - else: - raise Exception("No CFLOW data") - - for rec in data: - p = capture[idx] - idx += 1 - self.assertEqual(p[IP].len, int( - binascii.hexlify(rec[1]), 16)) - self.assertEqual(1, int( - binascii.hexlify(rec[2]), 16)) - self.assertEqual(len(capture), idx) - - def wait_for_cflow_packet(self, collector_intf, set_id=2, timeout=1, - expected=True): - """ wait for CFLOW packet and verify its correctness - - :param timeout: how long to wait - - :returns: tuple (packet, time spent waiting for packet) - """ - self.logger.info("IPFIX: Waiting for CFLOW packet") - deadline = time.time() + timeout - counter = 0 - # self.logger.debug(self.vapi.ppcli("show flow table")) - while True: - counter += 1 - # sanity check - self.assert_in_range(counter, 0, 100, "number of packets ignored") - time_left = deadline - time.time() - try: - if time_left < 0 and expected: - # self.logger.debug(self.vapi.ppcli("show flow table")) - raise CaptureTimeoutError( - "Packet did not arrive within timeout") - p = collector_intf.wait_for_packet(timeout=time_left) - except CaptureTimeoutError: - if expected: - # self.logger.debug(self.vapi.ppcli("show flow table")) - raise CaptureTimeoutError( - "Packet did not arrive within timeout") - else: - return - if not expected: - raise CaptureTimeoutError("Packet arrived even not expected") - self.assertEqual(p[Set].setID, set_id) - # self.logger.debug(self.vapi.ppcli("show flow table")) - self.logger.debug(ppp("IPFIX: Got packet:", p)) - break - return p - - -class Flowprobe(MethodHolder): - """Template verification, timer tests""" - - @classmethod - def setUpClass(cls): - super(Flowprobe, cls).setUpClass() - - @classmethod - def tearDownClass(cls): - super(Flowprobe, cls).tearDownClass() - - def test_0001(self): - """ timer less than template timeout""" - self.logger.info("FFP_TEST_START_0001") - self.pg_enable_capture(self.pg_interfaces) - self.pkts = [] - - ipfix = VppCFLOW(test=self, active=2) - ipfix.add_vpp_config() - - ipfix_decoder = IPFIXDecoder() - # template packet should arrive immediately - templates = ipfix.verify_templates(ipfix_decoder) - - self.create_stream(packets=1) - self.send_packets() - capture = self.pg2.get_capture(1) - - # make sure the one packet we expect actually showed up - cflow = self.wait_for_cflow_packet(self.collector, templates[1], 15) - self.verify_cflow_data(ipfix_decoder, capture, cflow) - - ipfix.remove_vpp_config() - self.logger.info("FFP_TEST_FINISH_0001") - - def test_0002(self): - """ timer greater than template timeout""" - self.logger.info("FFP_TEST_START_0002") - self.pg_enable_capture(self.pg_interfaces) - self.pkts = [] - - ipfix = VppCFLOW(test=self, timeout=3, active=4) - ipfix.add_vpp_config() - - ipfix_decoder = IPFIXDecoder() - # template packet should arrive immediately - ipfix.verify_templates() - - self.create_stream(packets=2) - self.send_packets() - capture = self.pg2.get_capture(2) - - # next set of template packet should arrive after 20 seconds - # template packet should arrive within 20 s - templates = ipfix.verify_templates(ipfix_decoder, timeout=5) - - # make sure the one packet we expect actually showed up - cflow = self.wait_for_cflow_packet(self.collector, templates[1], 15) - self.verify_cflow_data(ipfix_decoder, capture, cflow) - - ipfix.remove_vpp_config() - self.logger.info("FFP_TEST_FINISH_0002") - - def test_cflow_packet(self): - """verify cflow packet fields""" - self.logger.info("FFP_TEST_START_0000") - self.pg_enable_capture(self.pg_interfaces) - self.pkts = [] - - ipfix = VppCFLOW(test=self, intf='pg8', datapath="ip4", - layer='l2 l3 l4', active=2) - ipfix.add_vpp_config() - - route_9001 = VppIpRoute(self, "9.0.0.0", 24, - [VppRoutePath(self.pg8._remote_hosts[0].ip4, - self.pg8.sw_if_index)]) - route_9001.add_vpp_config() - - ipfix_decoder = IPFIXDecoder() - templates = ipfix.verify_templates(ipfix_decoder, count=1) - - self.pkts = [(Ether(dst=self.pg7.local_mac, - src=self.pg7.remote_mac) / - IP(src=self.pg7.remote_ip4, dst="9.0.0.100") / - TCP(sport=1234, dport=4321, flags=80) / - Raw('\xa5' * 100))] - - nowUTC = int(time.time()) - nowUNIX = nowUTC+2208988800 - self.send_packets(src_if=self.pg7, dst_if=self.pg8) - - cflow = self.wait_for_cflow_packet(self.collector, templates[0], 10) - self.collector.get_capture(2) - - if cflow[0].haslayer(IPFIX): - self.assertEqual(cflow[IPFIX].version, 10) - self.assertEqual(cflow[IPFIX].observationDomainID, 1) - self.assertEqual(cflow[IPFIX].sequenceNumber, 0) - self.assertAlmostEqual(cflow[IPFIX].exportTime, nowUTC, delta=5) - if cflow.haslayer(Data): - record = ipfix_decoder.decode_data_set(cflow[0].getlayer(Set))[0] - # ingress interface - self.assertEqual(int(binascii.hexlify(record[10]), 16), 8) - # egress interface - self.assertEqual(int(binascii.hexlify(record[14]), 16), 9) - # packets - self.assertEqual(int(binascii.hexlify(record[2]), 16), 1) - # src mac - self.assertEqual(':'.join(re.findall('..', record[56].encode( - 'hex'))), self.pg8.local_mac) - # dst mac - self.assertEqual(':'.join(re.findall('..', record[80].encode( - 'hex'))), self.pg8.remote_mac) - flowTimestamp = int(binascii.hexlify(record[156]), 16) >> 32 - # flow start timestamp - self.assertAlmostEqual(flowTimestamp, nowUNIX, delta=1) - flowTimestamp = int(binascii.hexlify(record[157]), 16) >> 32 - # flow end timestamp - self.assertAlmostEqual(flowTimestamp, nowUNIX, delta=1) - # ethernet type - self.assertEqual(int(binascii.hexlify(record[256]), 16), 8) - # src ip - self.assertEqual('.'.join(re.findall('..', record[8].encode( - 'hex'))), - '.'.join('{:02x}'.format(int(n)) for n in - self.pg7.remote_ip4.split('.'))) - # dst ip - self.assertEqual('.'.join(re.findall('..', record[12].encode( - 'hex'))), - '.'.join('{:02x}'.format(int(n)) for n in - "9.0.0.100".split('.'))) - # protocol (TCP) - self.assertEqual(int(binascii.hexlify(record[4]), 16), 6) - # src port - self.assertEqual(int(binascii.hexlify(record[7]), 16), 1234) - # dst port - self.assertEqual(int(binascii.hexlify(record[11]), 16), 4321) - # tcp flags - self.assertEqual(int(binascii.hexlify(record[6]), 16), 80) - - ipfix.remove_vpp_config() - self.logger.info("FFP_TEST_FINISH_0000") - - -class Datapath(MethodHolder): - """collect information on Ethernet, IP4 and IP6 datapath (no timers)""" - - @classmethod - def setUpClass(cls): - super(Datapath, cls).setUpClass() - - @classmethod - def tearDownClass(cls): - super(Datapath, cls).tearDownClass() - - def test_templatesL2(self): - """ verify template on L2 datapath""" - self.logger.info("FFP_TEST_START_0000") - self.pg_enable_capture(self.pg_interfaces) - - ipfix = VppCFLOW(test=self, layer='l2') - ipfix.add_vpp_config() - - # template packet should arrive immediately - self.vapi.ipfix_flush() - ipfix.verify_templates(timeout=3, count=1) - self.collector.get_capture(1) - - ipfix.remove_vpp_config() - self.logger.info("FFP_TEST_FINISH_0000") - - def test_L2onL2(self): - """ L2 data on L2 datapath""" - self.logger.info("FFP_TEST_START_0001") - self.pg_enable_capture(self.pg_interfaces) - self.pkts = [] - - ipfix = VppCFLOW(test=self, layer='l2') - ipfix.add_vpp_config() - - ipfix_decoder = IPFIXDecoder() - # template packet should arrive immediately - templates = ipfix.verify_templates(ipfix_decoder, count=1) - - self.create_stream(packets=1) - capture = self.send_packets() - - # make sure the one packet we expect actually showed up - self.vapi.ipfix_flush() - cflow = self.wait_for_cflow_packet(self.collector, templates[0]) - self.verify_cflow_data_detail(ipfix_decoder, capture, cflow, - {2: 'packets', 256: 8}) - self.collector.get_capture(2) - - ipfix.remove_vpp_config() - self.logger.info("FFP_TEST_FINISH_0001") - - def test_L3onL2(self): - """ L3 data on L2 datapath""" - self.logger.info("FFP_TEST_START_0002") - self.pg_enable_capture(self.pg_interfaces) - self.pkts = [] - - ipfix = VppCFLOW(test=self, layer='l3') - ipfix.add_vpp_config() - - ipfix_decoder = IPFIXDecoder() - # template packet should arrive immediately - templates = ipfix.verify_templates(ipfix_decoder, count=2) - - self.create_stream(packets=1) - capture = self.send_packets() - - # make sure the one packet we expect actually showed up - self.vapi.ipfix_flush() - cflow = self.wait_for_cflow_packet(self.collector, templates[0]) - self.verify_cflow_data_detail(ipfix_decoder, capture, cflow, - {2: 'packets', 4: 17, - 8: 'src_ip', 12: 'dst_ip'}) - - self.collector.get_capture(3) - - ipfix.remove_vpp_config() - self.logger.info("FFP_TEST_FINISH_0002") - - def test_L4onL2(self): - """ L4 data on L2 datapath""" - self.logger.info("FFP_TEST_START_0003") - self.pg_enable_capture(self.pg_interfaces) - self.pkts = [] - - ipfix = VppCFLOW(test=self, layer='l4') - ipfix.add_vpp_config() - - ipfix_decoder = IPFIXDecoder() - # template packet should arrive immediately - templates = ipfix.verify_templates(ipfix_decoder, count=2) - - self.create_stream(packets=1) - capture = self.send_packets() - - # make sure the one packet we expect actually showed up - self.vapi.ipfix_flush() - cflow = self.wait_for_cflow_packet(self.collector, templates[0]) - self.verify_cflow_data_detail(ipfix_decoder, capture, cflow, - {2: 'packets', 7: 'sport', 11: 'dport'}) - - self.collector.get_capture(3) - - ipfix.remove_vpp_config() - self.logger.info("FFP_TEST_FINISH_0003") - - def test_templatesIp4(self): - """ verify templates on IP4 datapath""" - self.logger.info("FFP_TEST_START_0000") - - self.pg_enable_capture(self.pg_interfaces) - - ipfix = VppCFLOW(test=self, datapath='ip4') - ipfix.add_vpp_config() - - # template packet should arrive immediately - self.vapi.ipfix_flush() - ipfix.verify_templates(timeout=3, count=1) - self.collector.get_capture(1) - - ipfix.remove_vpp_config() - - self.logger.info("FFP_TEST_FINISH_0000") - - def test_L2onIP4(self): - """ L2 data on IP4 datapath""" - self.logger.info("FFP_TEST_START_0001") - self.pg_enable_capture(self.pg_interfaces) - self.pkts = [] - - ipfix = VppCFLOW(test=self, intf='pg4', layer='l2', datapath='ip4') - ipfix.add_vpp_config() - - ipfix_decoder = IPFIXDecoder() - # template packet should arrive immediately - templates = ipfix.verify_templates(ipfix_decoder, count=1) - - self.create_stream(src_if=self.pg3, dst_if=self.pg4, packets=1) - capture = self.send_packets(src_if=self.pg3, dst_if=self.pg4) - - # make sure the one packet we expect actually showed up - self.vapi.ipfix_flush() - cflow = self.wait_for_cflow_packet(self.collector, templates[0]) - self.verify_cflow_data_detail(ipfix_decoder, capture, cflow, - {2: 'packets', 256: 8}) - - # expected two templates and one cflow packet - self.collector.get_capture(2) - - ipfix.remove_vpp_config() - self.logger.info("FFP_TEST_FINISH_0001") - - def test_L3onIP4(self): - """ L3 data on IP4 datapath""" - self.logger.info("FFP_TEST_START_0002") - self.pg_enable_capture(self.pg_interfaces) - self.pkts = [] - - ipfix = VppCFLOW(test=self, intf='pg4', layer='l3', datapath='ip4') - ipfix.add_vpp_config() - - ipfix_decoder = IPFIXDecoder() - # template packet should arrive immediately - templates = ipfix.verify_templates(ipfix_decoder, count=1) - - self.create_stream(src_if=self.pg3, dst_if=self.pg4, packets=1) - capture = self.send_packets(src_if=self.pg3, dst_if=self.pg4) - - # make sure the one packet we expect actually showed up - self.vapi.ipfix_flush() - cflow = self.wait_for_cflow_packet(self.collector, templates[0]) - self.verify_cflow_data_detail(ipfix_decoder, capture, cflow, - {1: 'octets', 2: 'packets', - 8: 'src_ip', 12: 'dst_ip'}) - - # expected two templates and one cflow packet - self.collector.get_capture(2) - - ipfix.remove_vpp_config() - self.logger.info("FFP_TEST_FINISH_0002") - - def test_L4onIP4(self): - """ L4 data on IP4 datapath""" - self.logger.info("FFP_TEST_START_0003") - self.pg_enable_capture(self.pg_interfaces) - self.pkts = [] - - ipfix = VppCFLOW(test=self, intf='pg4', layer='l4', datapath='ip4') - ipfix.add_vpp_config() - - ipfix_decoder = IPFIXDecoder() - # template packet should arrive immediately - templates = ipfix.verify_templates(ipfix_decoder, count=1) - - self.create_stream(src_if=self.pg3, dst_if=self.pg4, packets=1) - capture = self.send_packets(src_if=self.pg3, dst_if=self.pg4) - - # make sure the one packet we expect actually showed up - self.vapi.ipfix_flush() - cflow = self.wait_for_cflow_packet(self.collector, templates[0]) - self.verify_cflow_data_detail(ipfix_decoder, capture, cflow, - {2: 'packets', 7: 'sport', 11: 'dport'}) - - # expected two templates and one cflow packet - self.collector.get_capture(2) - - ipfix.remove_vpp_config() - self.logger.info("FFP_TEST_FINISH_0003") - - def test_templatesIP6(self): - """ verify templates on IP6 datapath""" - self.logger.info("FFP_TEST_START_0000") - self.pg_enable_capture(self.pg_interfaces) - - ipfix = VppCFLOW(test=self, datapath='ip6') - ipfix.add_vpp_config() - - # template packet should arrive immediately - ipfix.verify_templates(count=1) - self.collector.get_capture(1) - - ipfix.remove_vpp_config() - - self.logger.info("FFP_TEST_FINISH_0000") - - def test_L2onIP6(self): - """ L2 data on IP6 datapath""" - self.logger.info("FFP_TEST_START_0001") - self.pg_enable_capture(self.pg_interfaces) - self.pkts = [] - - ipfix = VppCFLOW(test=self, intf='pg6', layer='l2', datapath='ip6') - ipfix.add_vpp_config() - - ipfix_decoder = IPFIXDecoder() - # template packet should arrive immediately - templates = ipfix.verify_templates(ipfix_decoder, count=1) - - self.create_stream(src_if=self.pg5, dst_if=self.pg6, packets=1, - ip_ver='IPv6') - capture = self.send_packets(src_if=self.pg5, dst_if=self.pg6) - - # make sure the one packet we expect actually showed up - self.vapi.ipfix_flush() - cflow = self.wait_for_cflow_packet(self.collector, templates[0]) - self.verify_cflow_data_detail(ipfix_decoder, capture, cflow, - {2: 'packets', 256: 56710}, - ip_ver='v6') - - # expected two templates and one cflow packet - self.collector.get_capture(2) - - ipfix.remove_vpp_config() - self.logger.info("FFP_TEST_FINISH_0001") - - def test_L3onIP6(self): - """ L3 data on IP6 datapath""" - self.logger.info("FFP_TEST_START_0002") - self.pg_enable_capture(self.pg_interfaces) - self.pkts = [] - - ipfix = VppCFLOW(test=self, intf='pg6', layer='l3', datapath='ip6') - ipfix.add_vpp_config() - - ipfix_decoder = IPFIXDecoder() - # template packet should arrive immediately - templates = ipfix.verify_templates(ipfix_decoder, count=1) - - self.create_stream(src_if=self.pg5, dst_if=self.pg6, packets=1, - ip_ver='IPv6') - capture = self.send_packets(src_if=self.pg5, dst_if=self.pg6) - - # make sure the one packet we expect actually showed up - self.vapi.ipfix_flush() - cflow = self.wait_for_cflow_packet(self.collector, templates[0]) - self.verify_cflow_data_detail(ipfix_decoder, capture, cflow, - {2: 'packets', - 27: 'src_ip', 28: 'dst_ip'}, - ip_ver='v6') - - # expected two templates and one cflow packet - self.collector.get_capture(2) - - ipfix.remove_vpp_config() - self.logger.info("FFP_TEST_FINISH_0002") - - def test_L4onIP6(self): - """ L4 data on IP6 datapath""" - self.logger.info("FFP_TEST_START_0003") - self.pg_enable_capture(self.pg_interfaces) - self.pkts = [] - - ipfix = VppCFLOW(test=self, intf='pg6', layer='l4', datapath='ip6') - ipfix.add_vpp_config() - - ipfix_decoder = IPFIXDecoder() - # template packet should arrive immediately - templates = ipfix.verify_templates(ipfix_decoder, count=1) - - self.create_stream(src_if=self.pg5, dst_if=self.pg6, packets=1, - ip_ver='IPv6') - capture = self.send_packets(src_if=self.pg5, dst_if=self.pg6) - - # make sure the one packet we expect actually showed up - self.vapi.ipfix_flush() - cflow = self.wait_for_cflow_packet(self.collector, templates[0]) - self.verify_cflow_data_detail(ipfix_decoder, capture, cflow, - {2: 'packets', 7: 'sport', 11: 'dport'}, - ip_ver='v6') - - # expected two templates and one cflow packet - self.collector.get_capture(2) - - ipfix.remove_vpp_config() - self.logger.info("FFP_TEST_FINISH_0003") - - def test_0001(self): - """ no timers, one CFLOW packet, 9 Flows inside""" - self.logger.info("FFP_TEST_START_0001") - self.pg_enable_capture(self.pg_interfaces) - self.pkts = [] - - ipfix = VppCFLOW(test=self) - ipfix.add_vpp_config() - - ipfix_decoder = IPFIXDecoder() - # template packet should arrive immediately - templates = ipfix.verify_templates(ipfix_decoder) - - self.create_stream(packets=9) - capture = self.send_packets() - - # make sure the one packet we expect actually showed up - self.vapi.ipfix_flush() - cflow = self.wait_for_cflow_packet(self.collector, templates[1]) - self.verify_cflow_data_notimer(ipfix_decoder, capture, [cflow]) - self.collector.get_capture(4) - - ipfix.remove_vpp_config() - self.logger.info("FFP_TEST_FINISH_0001") - - def test_0002(self): - """ no timers, two CFLOW packets (mtu=256), 3 Flows in each""" - self.logger.info("FFP_TEST_START_0002") - self.pg_enable_capture(self.pg_interfaces) - self.pkts = [] - - ipfix = VppCFLOW(test=self, mtu=256) - ipfix.add_vpp_config() - - ipfix_decoder = IPFIXDecoder() - # template packet should arrive immediately - self.vapi.ipfix_flush() - templates = ipfix.verify_templates(ipfix_decoder) - - self.create_stream(packets=6) - capture = self.send_packets() - - # make sure the one packet we expect actually showed up - cflows = [] - self.vapi.ipfix_flush() - cflows.append(self.wait_for_cflow_packet(self.collector, - templates[1])) - cflows.append(self.wait_for_cflow_packet(self.collector, - templates[1])) - self.verify_cflow_data_notimer(ipfix_decoder, capture, cflows) - self.collector.get_capture(5) - - ipfix.remove_vpp_config() - self.logger.info("FFP_TEST_FINISH_0002") - - -@unittest.skipUnless(running_extended_tests, "part of extended tests") -class DisableIPFIX(MethodHolder): - """Disable IPFIX""" - - @classmethod - def setUpClass(cls): - super(DisableIPFIX, cls).setUpClass() - - @classmethod - def tearDownClass(cls): - super(DisableIPFIX, cls).tearDownClass() - - def test_0001(self): - """ disable IPFIX after first packets""" - self.logger.info("FFP_TEST_START_0001") - self.pg_enable_capture(self.pg_interfaces) - self.pkts = [] - - ipfix = VppCFLOW(test=self) - ipfix.add_vpp_config() - - ipfix_decoder = IPFIXDecoder() - # template packet should arrive immediately - templates = ipfix.verify_templates(ipfix_decoder) - - self.create_stream() - self.send_packets() - - # make sure the one packet we expect actually showed up - self.vapi.ipfix_flush() - self.wait_for_cflow_packet(self.collector, templates[1]) - self.collector.get_capture(4) - - # disable IPFIX - ipfix.disable_exporter() - self.pg_enable_capture([self.collector]) - - self.send_packets() - - # make sure no one packet arrived in 1 minute - self.vapi.ipfix_flush() - self.wait_for_cflow_packet(self.collector, templates[1], - expected=False) - self.collector.get_capture(0) - - ipfix.remove_vpp_config() - self.logger.info("FFP_TEST_FINISH_0001") - - -@unittest.skipUnless(running_extended_tests, "part of extended tests") -class ReenableIPFIX(MethodHolder): - """Re-enable IPFIX""" - - @classmethod - def setUpClass(cls): - super(ReenableIPFIX, cls).setUpClass() - - @classmethod - def tearDownClass(cls): - super(ReenableIPFIX, cls).tearDownClass() - - def test_0011(self): - """ disable IPFIX after first packets and re-enable after few packets - """ - self.logger.info("FFP_TEST_START_0001") - self.pg_enable_capture(self.pg_interfaces) - self.pkts = [] - - ipfix = VppCFLOW(test=self) - ipfix.add_vpp_config() - - ipfix_decoder = IPFIXDecoder() - # template packet should arrive immediately - templates = ipfix.verify_templates(ipfix_decoder) - - self.create_stream(packets=5) - self.send_packets() - - # make sure the one packet we expect actually showed up - self.vapi.ipfix_flush() - self.wait_for_cflow_packet(self.collector, templates[1]) - self.collector.get_capture(4) - - # disable IPFIX - ipfix.disable_exporter() - self.vapi.ipfix_flush() - self.pg_enable_capture([self.collector]) - - self.send_packets() - - # make sure no one packet arrived in active timer span - self.vapi.ipfix_flush() - self.wait_for_cflow_packet(self.collector, templates[1], - expected=False) - self.collector.get_capture(0) - self.pg2.get_capture(5) - - # enable IPFIX - ipfix.enable_exporter() - - capture = self.collector.get_capture(4) - nr_templates = 0 - nr_data = 0 - for p in capture: - self.assertTrue(p.haslayer(IPFIX)) - if p.haslayer(Template): - nr_templates += 1 - self.assertTrue(nr_templates, 3) - for p in capture: - self.assertTrue(p.haslayer(IPFIX)) - if p.haslayer(Data): - nr_data += 1 - self.assertTrue(nr_templates, 1) - - ipfix.remove_vpp_config() - self.logger.info("FFP_TEST_FINISH_0001") - - -@unittest.skipUnless(running_extended_tests, "part of extended tests") -class DisableFP(MethodHolder): - """Disable Flowprobe feature""" - - @classmethod - def setUpClass(cls): - super(DisableFP, cls).setUpClass() - - @classmethod - def tearDownClass(cls): - super(DisableFP, cls).tearDownClass() - - def test_0001(self): - """ disable flowprobe feature after first packets""" - self.logger.info("FFP_TEST_START_0001") - self.pg_enable_capture(self.pg_interfaces) - self.pkts = [] - ipfix = VppCFLOW(test=self) - ipfix.add_vpp_config() - - ipfix_decoder = IPFIXDecoder() - # template packet should arrive immediately - templates = ipfix.verify_templates(ipfix_decoder) - - self.create_stream() - self.send_packets() - - # make sure the one packet we expect actually showed up - self.vapi.ipfix_flush() - self.wait_for_cflow_packet(self.collector, templates[1]) - self.collector.get_capture(4) - - # disable IPFIX - ipfix.disable_flowprobe_feature() - self.pg_enable_capture([self.collector]) - - self.send_packets() - - # make sure no one packet arrived in active timer span - self.vapi.ipfix_flush() - self.wait_for_cflow_packet(self.collector, templates[1], - expected=False) - self.collector.get_capture(0) - - ipfix.remove_vpp_config() - self.logger.info("FFP_TEST_FINISH_0001") - - -@unittest.skipUnless(running_extended_tests, "part of extended tests") -class ReenableFP(MethodHolder): - """Re-enable Flowprobe feature""" - - @classmethod - def setUpClass(cls): - super(ReenableFP, cls).setUpClass() - - @classmethod - def tearDownClass(cls): - super(ReenableFP, cls).tearDownClass() - - def test_0001(self): - """ disable flowprobe feature after first packets and re-enable - after few packets """ - self.logger.info("FFP_TEST_START_0001") - self.pg_enable_capture(self.pg_interfaces) - self.pkts = [] - - ipfix = VppCFLOW(test=self) - ipfix.add_vpp_config() - - ipfix_decoder = IPFIXDecoder() - # template packet should arrive immediately - self.vapi.ipfix_flush() - templates = ipfix.verify_templates(ipfix_decoder, timeout=3) - - self.create_stream() - self.send_packets() - - # make sure the one packet we expect actually showed up - self.vapi.ipfix_flush() - self.wait_for_cflow_packet(self.collector, templates[1], 5) - self.collector.get_capture(4) - - # disable FPP feature - ipfix.disable_flowprobe_feature() - self.pg_enable_capture([self.collector]) - - self.send_packets() - - # make sure no one packet arrived in active timer span - self.vapi.ipfix_flush() - self.wait_for_cflow_packet(self.collector, templates[1], 5, - expected=False) - self.collector.get_capture(0) - - # enable FPP feature - ipfix.enable_flowprobe_feature() - self.vapi.ipfix_flush() - templates = ipfix.verify_templates(ipfix_decoder, timeout=3) - - self.send_packets() - - # make sure the next packets (templates and data) we expect actually - # showed up - self.vapi.ipfix_flush() - self.wait_for_cflow_packet(self.collector, templates[1], 5) - self.collector.get_capture(4) - - ipfix.remove_vpp_config() - self.logger.info("FFP_TEST_FINISH_0001") - - -if __name__ == '__main__': - unittest.main(testRunner=VppTestRunner) diff --git a/test/test_gbp.py b/test/test_gbp.py deleted file mode 100644 index 2d7fa459440..00000000000 --- a/test/test_gbp.py +++ /dev/null @@ -1,5425 +0,0 @@ -#!/usr/bin/env python - -from socket import AF_INET, AF_INET6 -import unittest - -from scapy.packet import Raw -from scapy.layers.l2 import Ether, ARP, Dot1Q -from scapy.layers.inet import IP, UDP, ICMP -from scapy.layers.inet6 import IPv6, ICMPv6ND_NS, ICMPv6NDOptSrcLLAddr, \ - ICMPv6ND_NA, ICMPv6EchoRequest -from scapy.utils6 import in6_getnsma, in6_getnsmac -from scapy.layers.vxlan import VXLAN -from scapy.data import ETH_P_IP, ETH_P_IPV6, ETH_P_ARP -from scapy.utils import inet_pton, inet_ntop - -from framework import VppTestCase, VppTestRunner -from vpp_object import VppObject -from vpp_interface import VppInterface -from vpp_ip_route import VppIpRoute, VppRoutePath, VppIpTable, \ - VppIpInterfaceAddress, VppIpInterfaceBind, find_route, FibPathProto, \ - FibPathType -from vpp_l2 import VppBridgeDomain, VppBridgeDomainPort, \ - VppBridgeDomainArpEntry, VppL2FibEntry, find_bridge_domain_port, VppL2Vtr -from vpp_sub_interface import L2_VTR_OP, VppDot1QSubint -from vpp_ip import VppIpAddress, VppIpPrefix, DpoProto -from vpp_papi import VppEnum, MACAddress -from vpp_vxlan_gbp_tunnel import find_vxlan_gbp_tunnel, INDEX_INVALID, \ - VppVxlanGbpTunnel -from vpp_neighbor import VppNeighbor -try: - text_type = unicode -except NameError: - text_type = str - -NUM_PKTS = 67 - - -def find_gbp_endpoint(test, sw_if_index=None, ip=None, mac=None, - tep=None, sclass=None): - if ip: - vip = VppIpAddress(ip) - if mac: - vmac = MACAddress(mac) - - eps = test.vapi.gbp_endpoint_dump() - - for ep in eps: - if tep: - src = VppIpAddress(tep[0]) - dst = VppIpAddress(tep[1]) - if src != ep.endpoint.tun.src or dst != ep.endpoint.tun.dst: - continue - if sw_if_index: - if ep.endpoint.sw_if_index != sw_if_index: - continue - if sclass: - if ep.endpoint.sclass != sclass: - continue - if ip: - for eip in ep.endpoint.ips: - if vip == eip: - return True - if mac: - if vmac.packed == ep.endpoint.mac: - return True - - return False - - -def find_gbp_vxlan(test, vni): - ts = test.vapi.gbp_vxlan_tunnel_dump() - for t in ts: - if t.tunnel.vni == vni: - return True - return False - - -class VppGbpEndpoint(VppObject): - """ - GBP Endpoint - """ - - @property - def mac(self): - return str(self.vmac) - - @property - def ip4(self): - return self._ip4 - - @property - def fip4(self): - return self._fip4 - - @property - def ip6(self): - return self._ip6 - - @property - def fip6(self): - return self._fip6 - - @property - def ips(self): - return [self.ip4, self.ip6] - - @property - def fips(self): - return [self.fip4, self.fip6] - - def __init__(self, test, itf, epg, recirc, ip4, fip4, ip6, fip6, - flags=0, - tun_src="0.0.0.0", - tun_dst="0.0.0.0", - mac=True): - self._test = test - self.itf = itf - self.epg = epg - self.recirc = recirc - - self._ip4 = VppIpAddress(ip4) - self._fip4 = VppIpAddress(fip4) - self._ip6 = VppIpAddress(ip6) - self._fip6 = VppIpAddress(fip6) - - if mac: - self.vmac = MACAddress(self.itf.remote_mac) - else: - self.vmac = MACAddress("00:00:00:00:00:00") - - self.flags = flags - self.tun_src = VppIpAddress(tun_src) - self.tun_dst = VppIpAddress(tun_dst) - - def add_vpp_config(self): - res = self._test.vapi.gbp_endpoint_add( - self.itf.sw_if_index, - [self.ip4.encode(), self.ip6.encode()], - self.vmac.packed, - self.epg.sclass, - self.flags, - self.tun_src.encode(), - self.tun_dst.encode()) - self.handle = res.handle - self._test.registry.register(self, self._test.logger) - - def remove_vpp_config(self): - self._test.vapi.gbp_endpoint_del(self.handle) - - def object_id(self): - return "gbp-endpoint:[%d==%d:%s:%d]" % (self.handle, - self.itf.sw_if_index, - self.ip4.address, - self.epg.sclass) - - def query_vpp_config(self): - return find_gbp_endpoint(self._test, - self.itf.sw_if_index, - self.ip4.address) - - -class VppGbpRecirc(VppObject): - """ - GBP Recirculation Interface - """ - - def __init__(self, test, epg, recirc, is_ext=False): - self._test = test - self.recirc = recirc - self.epg = epg - self.is_ext = is_ext - - def add_vpp_config(self): - self._test.vapi.gbp_recirc_add_del( - 1, - self.recirc.sw_if_index, - self.epg.sclass, - self.is_ext) - self._test.registry.register(self, self._test.logger) - - def remove_vpp_config(self): - self._test.vapi.gbp_recirc_add_del( - 0, - self.recirc.sw_if_index, - self.epg.sclass, - self.is_ext) - - def object_id(self): - return "gbp-recirc:[%d]" % (self.recirc.sw_if_index) - - def query_vpp_config(self): - rs = self._test.vapi.gbp_recirc_dump() - for r in rs: - if r.recirc.sw_if_index == self.recirc.sw_if_index: - return True - return False - - -class VppGbpExtItf(VppObject): - """ - GBP ExtItfulation Interface - """ - - def __init__(self, test, itf, bd, rd, anon=False): - self._test = test - self.itf = itf - self.bd = bd - self.rd = rd - self.flags = 1 if anon else 0 - - def add_vpp_config(self): - self._test.vapi.gbp_ext_itf_add_del( - 1, self.itf.sw_if_index, self.bd.bd_id, self.rd.rd_id, self.flags) - self._test.registry.register(self, self._test.logger) - - def remove_vpp_config(self): - self._test.vapi.gbp_ext_itf_add_del( - 0, self.itf.sw_if_index, self.bd.bd_id, self.rd.rd_id, self.flags) - - def object_id(self): - return "gbp-ext-itf:[%d]%s" % (self.itf.sw_if_index, - " [anon]" if self.flags else "") - - def query_vpp_config(self): - rs = self._test.vapi.gbp_ext_itf_dump() - for r in rs: - if r.ext_itf.sw_if_index == self.itf.sw_if_index: - return True - return False - - -class VppGbpSubnet(VppObject): - """ - GBP Subnet - """ - - def __init__(self, test, rd, address, address_len, - type, sw_if_index=None, sclass=None): - self._test = test - self.rd_id = rd.rd_id - self.prefix = VppIpPrefix(address, address_len) - self.type = type - self.sw_if_index = sw_if_index - self.sclass = sclass - - def add_vpp_config(self): - self._test.vapi.gbp_subnet_add_del( - 1, - self.rd_id, - self.prefix.encode(), - self.type, - sw_if_index=self.sw_if_index if self.sw_if_index else 0xffffffff, - sclass=self.sclass if self.sclass else 0xffff) - self._test.registry.register(self, self._test.logger) - - def remove_vpp_config(self): - self._test.vapi.gbp_subnet_add_del( - 0, - self.rd_id, - self.prefix.encode(), - self.type) - - def object_id(self): - return "gbp-subnet:[%d-%s]" % (self.rd_id, self.prefix) - - def query_vpp_config(self): - ss = self._test.vapi.gbp_subnet_dump() - for s in ss: - if s.subnet.rd_id == self.rd_id and \ - s.subnet.type == self.type and \ - s.subnet.prefix == self.prefix: - return True - return False - - -class VppGbpEndpointRetention(object): - def __init__(self, remote_ep_timeout=0xffffffff): - self.remote_ep_timeout = remote_ep_timeout - - def encode(self): - return {'remote_ep_timeout': self.remote_ep_timeout} - - -class VppGbpEndpointGroup(VppObject): - """ - GBP Endpoint Group - """ - - def __init__(self, test, vnid, sclass, rd, bd, uplink, - bvi, bvi_ip4, bvi_ip6=None, - retention=VppGbpEndpointRetention()): - self._test = test - self.uplink = uplink - self.bvi = bvi - self.bvi_ip4 = VppIpAddress(bvi_ip4) - self.bvi_ip6 = VppIpAddress(bvi_ip6) - self.vnid = vnid - self.bd = bd - self.rd = rd - self.sclass = sclass - if 0 == self.sclass: - self.sclass = 0xffff - self.retention = retention - - def add_vpp_config(self): - self._test.vapi.gbp_endpoint_group_add( - self.vnid, - self.sclass, - self.bd.bd.bd_id, - self.rd.rd_id, - self.uplink.sw_if_index if self.uplink else INDEX_INVALID, - self.retention.encode()) - self._test.registry.register(self, self._test.logger) - - def remove_vpp_config(self): - self._test.vapi.gbp_endpoint_group_del(self.sclass) - - def object_id(self): - return "gbp-endpoint-group:[%d]" % (self.vnid) - - def query_vpp_config(self): - epgs = self._test.vapi.gbp_endpoint_group_dump() - for epg in epgs: - if epg.epg.vnid == self.vnid: - return True - return False - - -class VppGbpBridgeDomain(VppObject): - """ - GBP Bridge Domain - """ - - def __init__(self, test, bd, rd, bvi, uu_fwd=None, - bm_flood=None, learn=True, - uu_drop=False, bm_drop=False, - ucast_arp=False): - self._test = test - self.bvi = bvi - self.uu_fwd = uu_fwd - self.bm_flood = bm_flood - self.bd = bd - self.rd = rd - - e = VppEnum.vl_api_gbp_bridge_domain_flags_t - - self.flags = e.GBP_BD_API_FLAG_NONE - if not learn: - self.flags |= e.GBP_BD_API_FLAG_DO_NOT_LEARN - if uu_drop: - self.flags |= e.GBP_BD_API_FLAG_UU_FWD_DROP - if bm_drop: - self.flags |= e.GBP_BD_API_FLAG_MCAST_DROP - if ucast_arp: - self.flags |= e.GBP_BD_API_FLAG_UCAST_ARP - - def add_vpp_config(self): - self._test.vapi.gbp_bridge_domain_add( - self.bd.bd_id, - self.rd.rd_id, - self.flags, - self.bvi.sw_if_index, - self.uu_fwd.sw_if_index if self.uu_fwd else INDEX_INVALID, - self.bm_flood.sw_if_index if self.bm_flood else INDEX_INVALID) - self._test.registry.register(self, self._test.logger) - - def remove_vpp_config(self): - self._test.vapi.gbp_bridge_domain_del(self.bd.bd_id) - - def object_id(self): - return "gbp-bridge-domain:[%d]" % (self.bd.bd_id) - - def query_vpp_config(self): - bds = self._test.vapi.gbp_bridge_domain_dump() - for bd in bds: - if bd.bd.bd_id == self.bd.bd_id: - return True - return False - - -class VppGbpRouteDomain(VppObject): - """ - GBP Route Domain - """ - - def __init__(self, test, rd_id, scope, t4, t6, ip4_uu=None, ip6_uu=None): - self._test = test - self.rd_id = rd_id - self.scope = scope - self.t4 = t4 - self.t6 = t6 - self.ip4_uu = ip4_uu - self.ip6_uu = ip6_uu - - def add_vpp_config(self): - self._test.vapi.gbp_route_domain_add( - self.rd_id, - self.scope, - self.t4.table_id, - self.t6.table_id, - self.ip4_uu.sw_if_index if self.ip4_uu else INDEX_INVALID, - self.ip6_uu.sw_if_index if self.ip6_uu else INDEX_INVALID) - self._test.registry.register(self, self._test.logger) - - def remove_vpp_config(self): - self._test.vapi.gbp_route_domain_del(self.rd_id) - - def object_id(self): - return "gbp-route-domain:[%d]" % (self.rd_id) - - def query_vpp_config(self): - rds = self._test.vapi.gbp_route_domain_dump() - for rd in rds: - if rd.rd.rd_id == self.rd_id: - return True - return False - - -class VppGbpContractNextHop(): - def __init__(self, mac, bd, ip, rd): - self.mac = mac - self.ip = ip - self.bd = bd - self.rd = rd - - def encode(self): - return {'ip': self.ip.encode(), - 'mac': self.mac.packed, - 'bd_id': self.bd.bd.bd_id, - 'rd_id': self.rd.rd_id} - - -class VppGbpContractRule(): - def __init__(self, action, hash_mode, nhs=None): - self.action = action - self.hash_mode = hash_mode - self.nhs = [] if nhs is None else nhs - - def encode(self): - nhs = [] - for nh in self.nhs: - nhs.append(nh.encode()) - while len(nhs) < 8: - nhs.append({}) - return {'action': self.action, - 'nh_set': { - 'hash_mode': self.hash_mode, - 'n_nhs': len(self.nhs), - 'nhs': nhs}} - - def __repr__(self): - return '<VppGbpContractRule action=%s, hash_mode=%s>' % ( - self.action, self.hash_mode) - - -class VppGbpContract(VppObject): - """ - GBP Contract - """ - - def __init__(self, test, scope, sclass, dclass, acl_index, - rules, allowed_ethertypes): - self._test = test - if not isinstance(rules, list): - raise ValueError("'rules' must be a list.") - if not isinstance(allowed_ethertypes, list): - raise ValueError("'allowed_ethertypes' must be a list.") - self.scope = scope - self.acl_index = acl_index - self.sclass = sclass - self.dclass = dclass - self.rules = rules - self.allowed_ethertypes = allowed_ethertypes - while (len(self.allowed_ethertypes) < 16): - self.allowed_ethertypes.append(0) - - def add_vpp_config(self): - rules = [] - for r in self.rules: - rules.append(r.encode()) - r = self._test.vapi.gbp_contract_add_del( - is_add=1, - contract={ - 'acl_index': self.acl_index, - 'scope': self.scope, - 'sclass': self.sclass, - 'dclass': self.dclass, - 'n_rules': len(rules), - 'rules': rules, - 'n_ether_types': len(self.allowed_ethertypes), - 'allowed_ethertypes': self.allowed_ethertypes}) - self.stats_index = r.stats_index - self._test.registry.register(self, self._test.logger) - - def remove_vpp_config(self): - self._test.vapi.gbp_contract_add_del( - is_add=0, - contract={ - 'acl_index': self.acl_index, - 'scope': self.scope, - 'sclass': self.sclass, - 'dclass': self.dclass, - 'n_rules': 0, - 'rules': [], - 'n_ether_types': len(self.allowed_ethertypes), - 'allowed_ethertypes': self.allowed_ethertypes}) - - def object_id(self): - return "gbp-contract:[%d:%d:%d:%d]" % (self.scope, - self.sclass, - self.dclass, - self.acl_index) - - def query_vpp_config(self): - cs = self._test.vapi.gbp_contract_dump() - for c in cs: - if c.contract.scope == self.scope \ - and c.contract.sclass == self.sclass \ - and c.contract.dclass == self.dclass: - return True - return False - - def get_drop_stats(self): - c = self._test.statistics.get_counter("/net/gbp/contract/drop") - return c[0][self.stats_index] - - def get_permit_stats(self): - c = self._test.statistics.get_counter("/net/gbp/contract/permit") - return c[0][self.stats_index] - - -class VppGbpVxlanTunnel(VppInterface): - """ - GBP VXLAN tunnel - """ - - def __init__(self, test, vni, bd_rd_id, mode, src): - super(VppGbpVxlanTunnel, self).__init__(test) - self._test = test - self.vni = vni - self.bd_rd_id = bd_rd_id - self.mode = mode - self.src = src - - def add_vpp_config(self): - r = self._test.vapi.gbp_vxlan_tunnel_add( - self.vni, - self.bd_rd_id, - self.mode, - self.src) - self.set_sw_if_index(r.sw_if_index) - self._test.registry.register(self, self._test.logger) - - def remove_vpp_config(self): - self._test.vapi.gbp_vxlan_tunnel_del(self.vni) - - def object_id(self): - return "gbp-vxlan:%d" % (self.sw_if_index) - - def query_vpp_config(self): - return find_gbp_vxlan(self._test, self.vni) - - -class VppGbpAcl(VppObject): - """ - GBP Acl - """ - - def __init__(self, test): - self._test = test - self.acl_index = 4294967295 - - def create_rule(self, is_ipv6=0, permit_deny=0, proto=-1, - s_prefix=0, s_ip=b'\x00\x00\x00\x00', sport_from=0, - sport_to=65535, d_prefix=0, d_ip=b'\x00\x00\x00\x00', - dport_from=0, dport_to=65535): - if proto == -1 or proto == 0: - sport_to = 0 - dport_to = sport_to - elif proto == 1 or proto == 58: - sport_to = 255 - dport_to = sport_to - rule = ({'is_permit': permit_deny, 'is_ipv6': is_ipv6, 'proto': proto, - 'srcport_or_icmptype_first': sport_from, - 'srcport_or_icmptype_last': sport_to, - 'src_ip_prefix_len': s_prefix, - 'src_ip_addr': s_ip, - 'dstport_or_icmpcode_first': dport_from, - 'dstport_or_icmpcode_last': dport_to, - 'dst_ip_prefix_len': d_prefix, - 'dst_ip_addr': d_ip}) - return rule - - def add_vpp_config(self, rules): - - reply = self._test.vapi.acl_add_replace(acl_index=self.acl_index, - r=rules, - tag=b'GBPTest') - self.acl_index = reply.acl_index - return self.acl_index - - def remove_vpp_config(self): - self._test.vapi.acl_del(self.acl_index) - - def object_id(self): - return "gbp-acl:[%d]" % (self.acl_index) - - def query_vpp_config(self): - cs = self._test.vapi.acl_dump() - for c in cs: - if c.acl_index == self.acl_index: - return True - return False - - -class TestGBP(VppTestCase): - """ GBP Test Case """ - - @property - def config_flags(self): - return VppEnum.vl_api_nat_config_flags_t - - @classmethod - def setUpClass(cls): - super(TestGBP, cls).setUpClass() - - @classmethod - def tearDownClass(cls): - super(TestGBP, cls).tearDownClass() - - def setUp(self): - super(TestGBP, self).setUp() - - self.create_pg_interfaces(range(9)) - self.create_loopback_interfaces(8) - - self.router_mac = MACAddress("00:11:22:33:44:55") - - for i in self.pg_interfaces: - i.admin_up() - for i in self.lo_interfaces: - i.admin_up() - - self.vlan_100 = VppDot1QSubint(self, self.pg0, 100) - self.vlan_100.admin_up() - self.vlan_101 = VppDot1QSubint(self, self.pg0, 101) - self.vlan_101.admin_up() - self.vlan_102 = VppDot1QSubint(self, self.pg0, 102) - self.vlan_102.admin_up() - - def tearDown(self): - for i in self.pg_interfaces: - i.admin_down() - super(TestGBP, self).tearDown() - self.vlan_102.remove_vpp_config() - self.vlan_101.remove_vpp_config() - self.vlan_100.remove_vpp_config() - - def send_and_expect_bridged(self, src, tx, dst): - rx = self.send_and_expect(src, tx, dst) - - for r in rx: - self.assertEqual(r[Ether].src, tx[0][Ether].src) - self.assertEqual(r[Ether].dst, tx[0][Ether].dst) - self.assertEqual(r[IP].src, tx[0][IP].src) - self.assertEqual(r[IP].dst, tx[0][IP].dst) - return rx - - def send_and_expect_bridged6(self, src, tx, dst): - rx = self.send_and_expect(src, tx, dst) - - for r in rx: - self.assertEqual(r[Ether].src, tx[0][Ether].src) - self.assertEqual(r[Ether].dst, tx[0][Ether].dst) - self.assertEqual(r[IPv6].src, tx[0][IPv6].src) - self.assertEqual(r[IPv6].dst, tx[0][IPv6].dst) - return rx - - def send_and_expect_routed(self, src, tx, dst, src_mac): - rx = self.send_and_expect(src, tx, dst) - - for r in rx: - self.assertEqual(r[Ether].src, src_mac) - self.assertEqual(r[Ether].dst, dst.remote_mac) - self.assertEqual(r[IP].src, tx[0][IP].src) - self.assertEqual(r[IP].dst, tx[0][IP].dst) - return rx - - def send_and_expect_routed6(self, src, tx, dst, src_mac): - rx = self.send_and_expect(src, tx, dst) - - for r in rx: - self.assertEqual(r[Ether].src, src_mac) - self.assertEqual(r[Ether].dst, dst.remote_mac) - self.assertEqual(r[IPv6].src, tx[0][IPv6].src) - self.assertEqual(r[IPv6].dst, tx[0][IPv6].dst) - return rx - - def send_and_expect_natted(self, src, tx, dst, src_ip): - rx = self.send_and_expect(src, tx, dst) - - for r in rx: - self.assertEqual(r[Ether].src, tx[0][Ether].src) - self.assertEqual(r[Ether].dst, tx[0][Ether].dst) - self.assertEqual(r[IP].src, src_ip) - self.assertEqual(r[IP].dst, tx[0][IP].dst) - return rx - - def send_and_expect_natted6(self, src, tx, dst, src_ip): - rx = self.send_and_expect(src, tx, dst) - - for r in rx: - self.assertEqual(r[Ether].src, tx[0][Ether].src) - self.assertEqual(r[Ether].dst, tx[0][Ether].dst) - self.assertEqual(r[IPv6].src, src_ip) - self.assertEqual(r[IPv6].dst, tx[0][IPv6].dst) - return rx - - def send_and_expect_unnatted(self, src, tx, dst, dst_ip): - rx = self.send_and_expect(src, tx, dst) - - for r in rx: - self.assertEqual(r[Ether].src, tx[0][Ether].src) - self.assertEqual(r[Ether].dst, tx[0][Ether].dst) - self.assertEqual(r[IP].dst, dst_ip) - self.assertEqual(r[IP].src, tx[0][IP].src) - return rx - - def send_and_expect_unnatted6(self, src, tx, dst, dst_ip): - rx = self.send_and_expect(src, tx, dst) - - for r in rx: - self.assertEqual(r[Ether].src, tx[0][Ether].src) - self.assertEqual(r[Ether].dst, tx[0][Ether].dst) - self.assertEqual(r[IPv6].dst, dst_ip) - self.assertEqual(r[IPv6].src, tx[0][IPv6].src) - return rx - - def send_and_expect_double_natted(self, src, tx, dst, src_ip, dst_ip): - rx = self.send_and_expect(src, tx, dst) - - for r in rx: - self.assertEqual(r[Ether].src, str(self.router_mac)) - self.assertEqual(r[Ether].dst, dst.remote_mac) - self.assertEqual(r[IP].dst, dst_ip) - self.assertEqual(r[IP].src, src_ip) - return rx - - def send_and_expect_double_natted6(self, src, tx, dst, src_ip, dst_ip): - rx = self.send_and_expect(src, tx, dst) - - for r in rx: - self.assertEqual(r[Ether].src, str(self.router_mac)) - self.assertEqual(r[Ether].dst, dst.remote_mac) - self.assertEqual(r[IPv6].dst, dst_ip) - self.assertEqual(r[IPv6].src, src_ip) - return rx - - def send_and_expect_no_arp(self, src, tx, dst): - self.pg_send(src, tx) - dst.get_capture(0, timeout=1) - dst.assert_nothing_captured(remark="") - timeout = 0.1 - - def send_and_expect_arp(self, src, tx, dst): - rx = self.send_and_expect(src, tx, dst) - - for r in rx: - self.assertEqual(r[Ether].src, tx[0][Ether].src) - self.assertEqual(r[Ether].dst, tx[0][Ether].dst) - self.assertEqual(r[ARP].psrc, tx[0][ARP].psrc) - self.assertEqual(r[ARP].pdst, tx[0][ARP].pdst) - self.assertEqual(r[ARP].hwsrc, tx[0][ARP].hwsrc) - self.assertEqual(r[ARP].hwdst, tx[0][ARP].hwdst) - return rx - - def test_gbp(self): - """ Group Based Policy """ - - ep_flags = VppEnum.vl_api_gbp_endpoint_flags_t - - # - # Route Domains - # - gt4 = VppIpTable(self, 0) - gt4.add_vpp_config() - gt6 = VppIpTable(self, 0, is_ip6=True) - gt6.add_vpp_config() - nt4 = VppIpTable(self, 20) - nt4.add_vpp_config() - nt6 = VppIpTable(self, 20, is_ip6=True) - nt6.add_vpp_config() - - rd0 = VppGbpRouteDomain(self, 0, 400, gt4, gt6, None, None) - rd20 = VppGbpRouteDomain(self, 20, 420, nt4, nt6, None, None) - - rd0.add_vpp_config() - rd20.add_vpp_config() - - # - # Bridge Domains - # - bd1 = VppBridgeDomain(self, 1) - bd2 = VppBridgeDomain(self, 2) - bd20 = VppBridgeDomain(self, 20) - - bd1.add_vpp_config() - bd2.add_vpp_config() - bd20.add_vpp_config() - - gbd1 = VppGbpBridgeDomain(self, bd1, rd0, self.loop0) - gbd2 = VppGbpBridgeDomain(self, bd2, rd0, self.loop1) - gbd20 = VppGbpBridgeDomain(self, bd20, rd20, self.loop2) - - gbd1.add_vpp_config() - gbd2.add_vpp_config() - gbd20.add_vpp_config() - - # - # 3 EPGs, 2 of which share a BD. - # 2 NAT EPGs, one for floating-IP subnets, the other for internet - # - epgs = [VppGbpEndpointGroup(self, 220, 1220, rd0, gbd1, - self.pg4, self.loop0, - "10.0.0.128", "2001:10::128"), - VppGbpEndpointGroup(self, 221, 1221, rd0, gbd1, - self.pg5, self.loop0, - "10.0.1.128", "2001:10:1::128"), - VppGbpEndpointGroup(self, 222, 1222, rd0, gbd2, - self.pg6, self.loop1, - "10.0.2.128", "2001:10:2::128"), - VppGbpEndpointGroup(self, 333, 1333, rd20, gbd20, - self.pg7, self.loop2, - "11.0.0.128", "3001::128"), - VppGbpEndpointGroup(self, 444, 1444, rd20, gbd20, - self.pg8, self.loop2, - "11.0.0.129", "3001::129")] - recircs = [VppGbpRecirc(self, epgs[0], self.loop3), - VppGbpRecirc(self, epgs[1], self.loop4), - VppGbpRecirc(self, epgs[2], self.loop5), - VppGbpRecirc(self, epgs[3], self.loop6, is_ext=True), - VppGbpRecirc(self, epgs[4], self.loop7, is_ext=True)] - - epg_nat = epgs[3] - recirc_nat = recircs[3] - - # - # 4 end-points, 2 in the same subnet, 3 in the same BD - # - eps = [VppGbpEndpoint(self, self.pg0, - epgs[0], recircs[0], - "10.0.0.1", "11.0.0.1", - "2001:10::1", "3001::1"), - VppGbpEndpoint(self, self.pg1, - epgs[0], recircs[0], - "10.0.0.2", "11.0.0.2", - "2001:10::2", "3001::2"), - VppGbpEndpoint(self, self.pg2, - epgs[1], recircs[1], - "10.0.1.1", "11.0.0.3", - "2001:10:1::1", "3001::3"), - VppGbpEndpoint(self, self.pg3, - epgs[2], recircs[2], - "10.0.2.1", "11.0.0.4", - "2001:10:2::1", "3001::4")] - - # - # Config related to each of the EPGs - # - for epg in epgs: - # IP config on the BVI interfaces - if epg != epgs[1] and epg != epgs[4]: - VppIpInterfaceBind(self, epg.bvi, epg.rd.t4).add_vpp_config() - VppIpInterfaceBind(self, epg.bvi, epg.rd.t6).add_vpp_config() - self.vapi.sw_interface_set_mac_address( - epg.bvi.sw_if_index, - self.router_mac.packed) - - # The BVIs are NAT inside interfaces - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=epg.bvi.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat66_add_del_interface( - is_add=1, flags=flags, - sw_if_index=epg.bvi.sw_if_index) - - if_ip4 = VppIpInterfaceAddress(self, epg.bvi, epg.bvi_ip4, 32) - if_ip6 = VppIpInterfaceAddress(self, epg.bvi, epg.bvi_ip6, 128) - if_ip4.add_vpp_config() - if_ip6.add_vpp_config() - - # EPG uplink interfaces in the RD - VppIpInterfaceBind(self, epg.uplink, epg.rd.t4).add_vpp_config() - VppIpInterfaceBind(self, epg.uplink, epg.rd.t6).add_vpp_config() - - # add the BD ARP termination entry for BVI IP - epg.bd_arp_ip4 = VppBridgeDomainArpEntry(self, epg.bd.bd, - str(self.router_mac), - epg.bvi_ip4.address) - epg.bd_arp_ip6 = VppBridgeDomainArpEntry(self, epg.bd.bd, - str(self.router_mac), - epg.bvi_ip6.address) - epg.bd_arp_ip4.add_vpp_config() - epg.bd_arp_ip6.add_vpp_config() - - # EPG in VPP - epg.add_vpp_config() - - for recirc in recircs: - # EPG's ingress recirculation interface maps to its RD - VppIpInterfaceBind(self, recirc.recirc, - recirc.epg.rd.t4).add_vpp_config() - VppIpInterfaceBind(self, recirc.recirc, - recirc.epg.rd.t6).add_vpp_config() - - self.vapi.nat44_interface_add_del_feature( - sw_if_index=recirc.recirc.sw_if_index, is_add=1) - self.vapi.nat66_add_del_interface( - is_add=1, - sw_if_index=recirc.recirc.sw_if_index) - - recirc.add_vpp_config() - - for recirc in recircs: - self.assertTrue(find_bridge_domain_port(self, - recirc.epg.bd.bd.bd_id, - recirc.recirc.sw_if_index)) - - for ep in eps: - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - # - # routes to the endpoints. We need these since there are no - # adj-fibs due to the fact the the BVI address has /32 and - # the subnet is not attached. - # - for (ip, fip) in zip(ep.ips, ep.fips): - # Add static mappings for each EP from the 10/8 to 11/8 network - if ip.af == AF_INET: - flags = self.config_flags.NAT_IS_ADDR_ONLY - self.vapi.nat44_add_del_static_mapping( - is_add=1, - local_ip_address=ip.bytes, - external_ip_address=fip.bytes, - external_sw_if_index=0xFFFFFFFF, - vrf_id=0, - flags=flags) - else: - self.vapi.nat66_add_del_static_mapping( - local_ip_address=ip.bytes, - external_ip_address=fip.bytes, - vrf_id=0, is_add=1) - - # VPP EP create ... - ep.add_vpp_config() - - self.logger.info(self.vapi.cli("sh gbp endpoint")) - - # ... results in a Gratuitous ARP/ND on the EPG's uplink - rx = ep.epg.uplink.get_capture(len(ep.ips), timeout=0.2) - - for ii, ip in enumerate(ep.ips): - p = rx[ii] - - if ip.is_ip6: - self.assertTrue(p.haslayer(ICMPv6ND_NA)) - self.assertEqual(p[ICMPv6ND_NA].tgt, ip.address) - else: - self.assertTrue(p.haslayer(ARP)) - self.assertEqual(p[ARP].psrc, ip.address) - self.assertEqual(p[ARP].pdst, ip.address) - - # add the BD ARP termination entry for floating IP - for fip in ep.fips: - ba = VppBridgeDomainArpEntry(self, epg_nat.bd.bd, ep.mac, - fip.address) - ba.add_vpp_config() - - # floating IPs route via EPG recirc - r = VppIpRoute( - self, fip.address, fip.length, - [VppRoutePath(fip.address, - ep.recirc.recirc.sw_if_index, - type=FibPathType.FIB_PATH_TYPE_DVR, - proto=fip.dpo_proto)], - table_id=20) - r.add_vpp_config() - - # L2 FIB entries in the NAT EPG BD to bridge the packets from - # the outside direct to the internal EPG - lf = VppL2FibEntry(self, epg_nat.bd.bd, ep.mac, - ep.recirc.recirc, bvi_mac=0) - lf.add_vpp_config() - - # - # ARP packets for unknown IP are sent to the EPG uplink - # - pkt_arp = (Ether(dst="ff:ff:ff:ff:ff:ff", - src=self.pg0.remote_mac) / - ARP(op="who-has", - hwdst="ff:ff:ff:ff:ff:ff", - hwsrc=self.pg0.remote_mac, - pdst="10.0.0.88", - psrc="10.0.0.99")) - - self.vapi.cli("clear trace") - self.pg0.add_stream(pkt_arp) - - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - - rxd = epgs[0].uplink.get_capture(1) - - # - # ARP/ND packets get a response - # - pkt_arp = (Ether(dst="ff:ff:ff:ff:ff:ff", - src=self.pg0.remote_mac) / - ARP(op="who-has", - hwdst="ff:ff:ff:ff:ff:ff", - hwsrc=self.pg0.remote_mac, - pdst=epgs[0].bvi_ip4.address, - psrc=eps[0].ip4.address)) - - self.send_and_expect(self.pg0, [pkt_arp], self.pg0) - - nsma = in6_getnsma(inet_pton(AF_INET6, eps[0].ip6.address)) - d = inet_ntop(AF_INET6, nsma) - pkt_nd = (Ether(dst=in6_getnsmac(nsma), - src=self.pg0.remote_mac) / - IPv6(dst=d, src=eps[0].ip6.address) / - ICMPv6ND_NS(tgt=epgs[0].bvi_ip6.address) / - ICMPv6NDOptSrcLLAddr(lladdr=self.pg0.remote_mac)) - self.send_and_expect(self.pg0, [pkt_nd], self.pg0) - - # - # broadcast packets are flooded - # - pkt_bcast = (Ether(dst="ff:ff:ff:ff:ff:ff", - src=self.pg0.remote_mac) / - IP(src=eps[0].ip4.address, dst="232.1.1.1") / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - - self.vapi.cli("clear trace") - self.pg0.add_stream(pkt_bcast) - - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - - rxd = eps[1].itf.get_capture(1) - self.assertEqual(rxd[0][Ether].dst, pkt_bcast[Ether].dst) - rxd = epgs[0].uplink.get_capture(1) - self.assertEqual(rxd[0][Ether].dst, pkt_bcast[Ether].dst) - - # - # packets to non-local L3 destinations dropped - # - pkt_intra_epg_220_ip4 = (Ether(src=self.pg0.remote_mac, - dst=str(self.router_mac)) / - IP(src=eps[0].ip4.address, - dst="10.0.0.99") / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - pkt_inter_epg_222_ip4 = (Ether(src=self.pg0.remote_mac, - dst=str(self.router_mac)) / - IP(src=eps[0].ip4.address, - dst="10.0.1.99") / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - - self.send_and_assert_no_replies(self.pg0, - pkt_intra_epg_220_ip4 * NUM_PKTS) - - pkt_inter_epg_222_ip6 = (Ether(src=self.pg0.remote_mac, - dst=str(self.router_mac)) / - IPv6(src=eps[0].ip6.address, - dst="2001:10::99") / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - self.send_and_assert_no_replies(self.pg0, - pkt_inter_epg_222_ip6 * NUM_PKTS) - - # - # Add the subnet routes - # - s41 = VppGbpSubnet( - self, rd0, "10.0.0.0", 24, - VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_INTERNAL) - s42 = VppGbpSubnet( - self, rd0, "10.0.1.0", 24, - VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_INTERNAL) - s43 = VppGbpSubnet( - self, rd0, "10.0.2.0", 24, - VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_INTERNAL) - s61 = VppGbpSubnet( - self, rd0, "2001:10::1", 64, - VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_INTERNAL) - s62 = VppGbpSubnet( - self, rd0, "2001:10:1::1", 64, - VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_INTERNAL) - s63 = VppGbpSubnet( - self, rd0, "2001:10:2::1", 64, - VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_INTERNAL) - s41.add_vpp_config() - s42.add_vpp_config() - s43.add_vpp_config() - s61.add_vpp_config() - s62.add_vpp_config() - s63.add_vpp_config() - - self.send_and_expect_bridged(eps[0].itf, - pkt_intra_epg_220_ip4 * NUM_PKTS, - eps[0].epg.uplink) - self.send_and_expect_bridged(eps[0].itf, - pkt_inter_epg_222_ip4 * NUM_PKTS, - eps[0].epg.uplink) - self.send_and_expect_bridged6(eps[0].itf, - pkt_inter_epg_222_ip6 * NUM_PKTS, - eps[0].epg.uplink) - - self.logger.info(self.vapi.cli("sh ip fib 11.0.0.2")) - self.logger.info(self.vapi.cli("sh gbp endpoint-group")) - self.logger.info(self.vapi.cli("sh gbp endpoint")) - self.logger.info(self.vapi.cli("sh gbp recirc")) - self.logger.info(self.vapi.cli("sh int")) - self.logger.info(self.vapi.cli("sh int addr")) - self.logger.info(self.vapi.cli("sh int feat loop6")) - self.logger.info(self.vapi.cli("sh vlib graph ip4-gbp-src-classify")) - self.logger.info(self.vapi.cli("sh int feat loop3")) - self.logger.info(self.vapi.cli("sh int feat pg0")) - - # - # Packet destined to unknown unicast is sent on the epg uplink ... - # - pkt_intra_epg_220_to_uplink = (Ether(src=self.pg0.remote_mac, - dst="00:00:00:33:44:55") / - IP(src=eps[0].ip4.address, - dst="10.0.0.99") / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - - self.send_and_expect_bridged(eps[0].itf, - pkt_intra_epg_220_to_uplink * NUM_PKTS, - eps[0].epg.uplink) - # ... and nowhere else - self.pg1.get_capture(0, timeout=0.1) - self.pg1.assert_nothing_captured(remark="Flood onto other VMS") - - pkt_intra_epg_221_to_uplink = (Ether(src=self.pg2.remote_mac, - dst="00:00:00:33:44:66") / - IP(src=eps[0].ip4.address, - dst="10.0.0.99") / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - - self.send_and_expect_bridged(eps[2].itf, - pkt_intra_epg_221_to_uplink * NUM_PKTS, - eps[2].epg.uplink) - - # - # Packets from the uplink are forwarded in the absence of a contract - # - pkt_intra_epg_220_from_uplink = (Ether(src="00:00:00:33:44:55", - dst=self.pg0.remote_mac) / - IP(src=eps[0].ip4.address, - dst="10.0.0.99") / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - - self.send_and_expect_bridged(self.pg4, - pkt_intra_epg_220_from_uplink * NUM_PKTS, - self.pg0) - - # - # in the absence of policy, endpoints in the same EPG - # can communicate - # - pkt_intra_epg = (Ether(src=self.pg0.remote_mac, - dst=self.pg1.remote_mac) / - IP(src=eps[0].ip4.address, - dst=eps[1].ip4.address) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - - self.send_and_expect_bridged(self.pg0, - pkt_intra_epg * NUM_PKTS, - self.pg1) - - # - # in the absence of policy, endpoints in the different EPG - # cannot communicate - # - pkt_inter_epg_220_to_221 = (Ether(src=self.pg0.remote_mac, - dst=self.pg2.remote_mac) / - IP(src=eps[0].ip4.address, - dst=eps[2].ip4.address) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - pkt_inter_epg_221_to_220 = (Ether(src=self.pg2.remote_mac, - dst=self.pg0.remote_mac) / - IP(src=eps[2].ip4.address, - dst=eps[0].ip4.address) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - pkt_inter_epg_220_to_222 = (Ether(src=self.pg0.remote_mac, - dst=str(self.router_mac)) / - IP(src=eps[0].ip4.address, - dst=eps[3].ip4.address) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - - self.send_and_assert_no_replies(eps[0].itf, - pkt_inter_epg_220_to_221 * NUM_PKTS) - self.send_and_assert_no_replies(eps[0].itf, - pkt_inter_epg_220_to_222 * NUM_PKTS) - - # - # A uni-directional contract from EPG 220 -> 221 - # - acl = VppGbpAcl(self) - rule = acl.create_rule(permit_deny=1, proto=17) - rule2 = acl.create_rule(is_ipv6=1, permit_deny=1, proto=17) - acl_index = acl.add_vpp_config([rule, rule2]) - c1 = VppGbpContract( - self, 400, epgs[0].sclass, epgs[1].sclass, acl_index, - [VppGbpContractRule( - VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT, - VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP, - []), - VppGbpContractRule( - VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT, - VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP, - [])], - [ETH_P_IP, ETH_P_IPV6]) - c1.add_vpp_config() - - self.send_and_expect_bridged(eps[0].itf, - pkt_inter_epg_220_to_221 * NUM_PKTS, - eps[2].itf) - self.send_and_assert_no_replies(eps[0].itf, - pkt_inter_epg_220_to_222 * NUM_PKTS) - - # - # contract for the return direction - # - c2 = VppGbpContract( - self, 400, epgs[1].sclass, epgs[0].sclass, acl_index, - [VppGbpContractRule( - VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT, - VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP, - []), - VppGbpContractRule( - VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT, - VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP, - [])], - [ETH_P_IP, ETH_P_IPV6]) - c2.add_vpp_config() - - self.send_and_expect_bridged(eps[0].itf, - pkt_inter_epg_220_to_221 * NUM_PKTS, - eps[2].itf) - self.send_and_expect_bridged(eps[2].itf, - pkt_inter_epg_221_to_220 * NUM_PKTS, - eps[0].itf) - - ds = c2.get_drop_stats() - self.assertEqual(ds['packets'], 0) - ps = c2.get_permit_stats() - self.assertEqual(ps['packets'], NUM_PKTS) - - # - # the contract does not allow non-IP - # - pkt_non_ip_inter_epg_220_to_221 = (Ether(src=self.pg0.remote_mac, - dst=self.pg2.remote_mac) / - ARP()) - self.send_and_assert_no_replies(eps[0].itf, - pkt_non_ip_inter_epg_220_to_221 * 17) - - # - # check that inter group is still disabled for the groups - # not in the contract. - # - self.send_and_assert_no_replies(eps[0].itf, - pkt_inter_epg_220_to_222 * NUM_PKTS) - - # - # A uni-directional contract from EPG 220 -> 222 'L3 routed' - # - c3 = VppGbpContract( - self, 400, epgs[0].sclass, epgs[2].sclass, acl_index, - [VppGbpContractRule( - VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT, - VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP, - []), - VppGbpContractRule( - VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT, - VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP, - [])], - [ETH_P_IP, ETH_P_IPV6]) - c3.add_vpp_config() - - self.logger.info(self.vapi.cli("sh gbp contract")) - - self.send_and_expect_routed(eps[0].itf, - pkt_inter_epg_220_to_222 * NUM_PKTS, - eps[3].itf, - str(self.router_mac)) - - # - # remove both contracts, traffic stops in both directions - # - c2.remove_vpp_config() - c1.remove_vpp_config() - c3.remove_vpp_config() - acl.remove_vpp_config() - - self.send_and_assert_no_replies(eps[2].itf, - pkt_inter_epg_221_to_220 * NUM_PKTS) - self.send_and_assert_no_replies(eps[0].itf, - pkt_inter_epg_220_to_221 * NUM_PKTS) - self.send_and_expect_bridged(eps[0].itf, - pkt_intra_epg * NUM_PKTS, - eps[1].itf) - - # - # EPs to the outside world - # - - # in the EP's RD an external subnet via the NAT EPG's recirc - se1 = VppGbpSubnet( - self, rd0, "0.0.0.0", 0, - VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_EXTERNAL, - sw_if_index=recirc_nat.recirc.sw_if_index, - sclass=epg_nat.sclass) - se2 = VppGbpSubnet( - self, rd0, "11.0.0.0", 8, - VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_EXTERNAL, - sw_if_index=recirc_nat.recirc.sw_if_index, - sclass=epg_nat.sclass) - se16 = VppGbpSubnet( - self, rd0, "::", 0, - VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_EXTERNAL, - sw_if_index=recirc_nat.recirc.sw_if_index, - sclass=epg_nat.sclass) - # in the NAT RD an external subnet via the NAT EPG's uplink - se3 = VppGbpSubnet( - self, rd20, "0.0.0.0", 0, - VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_EXTERNAL, - sw_if_index=epg_nat.uplink.sw_if_index, - sclass=epg_nat.sclass) - se36 = VppGbpSubnet( - self, rd20, "::", 0, - VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_EXTERNAL, - sw_if_index=epg_nat.uplink.sw_if_index, - sclass=epg_nat.sclass) - se4 = VppGbpSubnet( - self, rd20, "11.0.0.0", 8, - VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_EXTERNAL, - sw_if_index=epg_nat.uplink.sw_if_index, - sclass=epg_nat.sclass) - se1.add_vpp_config() - se2.add_vpp_config() - se16.add_vpp_config() - se3.add_vpp_config() - se36.add_vpp_config() - se4.add_vpp_config() - - self.logger.info(self.vapi.cli("sh ip fib 0.0.0.0/0")) - self.logger.info(self.vapi.cli("sh ip fib 11.0.0.1")) - self.logger.info(self.vapi.cli("sh ip6 fib ::/0")) - self.logger.info(self.vapi.cli("sh ip6 fib %s" % - eps[0].fip6)) - - # - # From an EP to an outside address: IN2OUT - # - pkt_inter_epg_220_to_global = (Ether(src=self.pg0.remote_mac, - dst=str(self.router_mac)) / - IP(src=eps[0].ip4.address, - dst="1.1.1.1") / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - - # no policy yet - self.send_and_assert_no_replies(eps[0].itf, - pkt_inter_epg_220_to_global * NUM_PKTS) - - acl2 = VppGbpAcl(self) - rule = acl2.create_rule(permit_deny=1, proto=17, sport_from=1234, - sport_to=1234, dport_from=1234, dport_to=1234) - rule2 = acl2.create_rule(is_ipv6=1, permit_deny=1, proto=17, - sport_from=1234, sport_to=1234, - dport_from=1234, dport_to=1234) - - acl_index2 = acl2.add_vpp_config([rule, rule2]) - c4 = VppGbpContract( - self, 400, epgs[0].sclass, epgs[3].sclass, acl_index2, - [VppGbpContractRule( - VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT, - VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP, - []), - VppGbpContractRule( - VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT, - VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP, - [])], - [ETH_P_IP, ETH_P_IPV6]) - c4.add_vpp_config() - - self.send_and_expect_natted(eps[0].itf, - pkt_inter_epg_220_to_global * NUM_PKTS, - self.pg7, - eps[0].fip4.address) - - pkt_inter_epg_220_to_global = (Ether(src=self.pg0.remote_mac, - dst=str(self.router_mac)) / - IPv6(src=eps[0].ip6.address, - dst="6001::1") / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - - self.send_and_expect_natted6(self.pg0, - pkt_inter_epg_220_to_global * NUM_PKTS, - self.pg7, - eps[0].fip6.address) - - # - # From a global address to an EP: OUT2IN - # - pkt_inter_epg_220_from_global = (Ether(src=str(self.router_mac), - dst=self.pg0.remote_mac) / - IP(dst=eps[0].fip4.address, - src="1.1.1.1") / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - - self.send_and_assert_no_replies( - self.pg7, pkt_inter_epg_220_from_global * NUM_PKTS) - - c5 = VppGbpContract( - self, 400, epgs[3].sclass, epgs[0].sclass, acl_index2, - [VppGbpContractRule( - VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT, - VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP, - []), - VppGbpContractRule( - VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT, - VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP, - [])], - [ETH_P_IP, ETH_P_IPV6]) - c5.add_vpp_config() - - self.send_and_expect_unnatted(self.pg7, - pkt_inter_epg_220_from_global * NUM_PKTS, - eps[0].itf, - eps[0].ip4.address) - - pkt_inter_epg_220_from_global = (Ether(src=str(self.router_mac), - dst=self.pg0.remote_mac) / - IPv6(dst=eps[0].fip6.address, - src="6001::1") / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - - self.send_and_expect_unnatted6( - self.pg7, - pkt_inter_epg_220_from_global * NUM_PKTS, - eps[0].itf, - eps[0].ip6.address) - - # - # From a local VM to another local VM using resp. public addresses: - # IN2OUT2IN - # - pkt_intra_epg_220_global = (Ether(src=self.pg0.remote_mac, - dst=str(self.router_mac)) / - IP(src=eps[0].ip4.address, - dst=eps[1].fip4.address) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - - self.send_and_expect_double_natted(eps[0].itf, - pkt_intra_epg_220_global * NUM_PKTS, - eps[1].itf, - eps[0].fip4.address, - eps[1].ip4.address) - - pkt_intra_epg_220_global = (Ether(src=self.pg0.remote_mac, - dst=str(self.router_mac)) / - IPv6(src=eps[0].ip6.address, - dst=eps[1].fip6.address) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - - self.send_and_expect_double_natted6( - eps[0].itf, - pkt_intra_epg_220_global * NUM_PKTS, - eps[1].itf, - eps[0].fip6.address, - eps[1].ip6.address) - - # - # cleanup - # - for ep in eps: - # del static mappings for each EP from the 10/8 to 11/8 network - flags = self.config_flags.NAT_IS_ADDR_ONLY - self.vapi.nat44_add_del_static_mapping( - is_add=0, - local_ip_address=ep.ip4.bytes, - external_ip_address=ep.fip4.bytes, - external_sw_if_index=0xFFFFFFFF, - vrf_id=0, - flags=flags) - self.vapi.nat66_add_del_static_mapping( - local_ip_address=ep.ip6.bytes, - external_ip_address=ep.fip6.bytes, - vrf_id=0, is_add=0) - - for epg in epgs: - # IP config on the BVI interfaces - if epg != epgs[0] and epg != epgs[3]: - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=epg.bvi.sw_if_index, - flags=flags, - is_add=0) - self.vapi.nat66_add_del_interface( - is_add=0, flags=flags, - sw_if_index=epg.bvi.sw_if_index) - - for recirc in recircs: - self.vapi.nat44_interface_add_del_feature( - sw_if_index=recirc.recirc.sw_if_index, - is_add=0) - self.vapi.nat66_add_del_interface( - is_add=0, - sw_if_index=recirc.recirc.sw_if_index) - - def wait_for_ep_timeout(self, sw_if_index=None, ip=None, mac=None, - tep=None, n_tries=100, s_time=1): - while (n_tries): - if not find_gbp_endpoint(self, sw_if_index, ip, mac, tep=tep): - return True - n_tries = n_tries - 1 - self.sleep(s_time) - self.assertFalse(find_gbp_endpoint(self, sw_if_index, ip, mac)) - return False - - def test_gbp_learn_l2(self): - """ GBP L2 Endpoint Learning """ - - drop_no_contract = self.statistics.get_err_counter( - '/err/gbp-policy-port/drop-no-contract') - allow_intra_class = self.statistics.get_err_counter( - '/err/gbp-policy-port/allow-intra-sclass') - - ep_flags = VppEnum.vl_api_gbp_endpoint_flags_t - learnt = [{'mac': '00:00:11:11:11:01', - 'ip': '10.0.0.1', - 'ip6': '2001:10::2'}, - {'mac': '00:00:11:11:11:02', - 'ip': '10.0.0.2', - 'ip6': '2001:10::3'}] - - # - # IP tables - # - gt4 = VppIpTable(self, 1) - gt4.add_vpp_config() - gt6 = VppIpTable(self, 1, is_ip6=True) - gt6.add_vpp_config() - - rd1 = VppGbpRouteDomain(self, 1, 401, gt4, gt6) - rd1.add_vpp_config() - - # - # Pg2 hosts the vxlan tunnel, hosts on pg2 to act as TEPs - # Pg3 hosts the IP4 UU-flood VXLAN tunnel - # Pg4 hosts the IP6 UU-flood VXLAN tunnel - # - self.pg2.config_ip4() - self.pg2.resolve_arp() - self.pg2.generate_remote_hosts(4) - self.pg2.configure_ipv4_neighbors() - self.pg3.config_ip4() - self.pg3.resolve_arp() - self.pg4.config_ip4() - self.pg4.resolve_arp() - - # - # Add a mcast destination VXLAN-GBP tunnel for B&M traffic - # - tun_bm = VppVxlanGbpTunnel(self, self.pg4.local_ip4, - "239.1.1.1", 88, - mcast_itf=self.pg4) - tun_bm.add_vpp_config() - - # - # a GBP bridge domain with a BVI and a UU-flood interface - # - bd1 = VppBridgeDomain(self, 1) - bd1.add_vpp_config() - gbd1 = VppGbpBridgeDomain(self, bd1, rd1, self.loop0, - self.pg3, tun_bm) - gbd1.add_vpp_config() - - self.logger.info(self.vapi.cli("sh bridge 1 detail")) - self.logger.info(self.vapi.cli("sh gbp bridge")) - - # ... and has a /32 applied - ip_addr = VppIpInterfaceAddress(self, gbd1.bvi, "10.0.0.128", 32) - ip_addr.add_vpp_config() - - # - # The Endpoint-group in which we are learning endpoints - # - epg_220 = VppGbpEndpointGroup(self, 220, 112, rd1, gbd1, - None, self.loop0, - "10.0.0.128", - "2001:10::128", - VppGbpEndpointRetention(2)) - epg_220.add_vpp_config() - epg_330 = VppGbpEndpointGroup(self, 330, 113, rd1, gbd1, - None, self.loop1, - "10.0.1.128", - "2001:11::128", - VppGbpEndpointRetention(2)) - epg_330.add_vpp_config() - - # - # The VXLAN GBP tunnel is a bridge-port and has L2 endpoint - # learning enabled - # - vx_tun_l2_1 = VppGbpVxlanTunnel( - self, 99, bd1.bd_id, - VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L2, - self.pg2.local_ip4) - vx_tun_l2_1.add_vpp_config() - - # - # A static endpoint that the learnt endpoints are trying to - # talk to - # - ep = VppGbpEndpoint(self, self.pg0, - epg_220, None, - "10.0.0.127", "11.0.0.127", - "2001:10::1", "3001::1") - ep.add_vpp_config() - - self.assertTrue(find_route(self, ep.ip4.address, 32, table_id=1)) - - # a packet with an sclass from an unknown EPG - p = (Ether(src=self.pg2.remote_mac, - dst=self.pg2.local_mac) / - IP(src=self.pg2.remote_hosts[0].ip4, - dst=self.pg2.local_ip4) / - UDP(sport=1234, dport=48879) / - VXLAN(vni=99, gpid=88, flags=0x88) / - Ether(src=learnt[0]["mac"], dst=ep.mac) / - IP(src=learnt[0]["ip"], dst=ep.ip4.address) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - - self.send_and_assert_no_replies(self.pg2, p) - - self.logger.info(self.vapi.cli("sh error")) - self.assert_error_counter_equal( - '/err/gbp-policy-port/drop-no-contract', - drop_no_contract + 1) - - # - # we should not have learnt a new tunnel endpoint, since - # the EPG was not learnt. - # - self.assertEqual(INDEX_INVALID, - find_vxlan_gbp_tunnel(self, - self.pg2.local_ip4, - self.pg2.remote_hosts[0].ip4, - 99)) - - # ep is not learnt, because the EPG is unknown - self.assertEqual(len(self.vapi.gbp_endpoint_dump()), 1) - - # - # Learn new EPs from IP packets - # - for ii, l in enumerate(learnt): - # a packet with an sclass from a known EPG - # arriving on an unknown TEP - p = (Ether(src=self.pg2.remote_mac, - dst=self.pg2.local_mac) / - IP(src=self.pg2.remote_hosts[1].ip4, - dst=self.pg2.local_ip4) / - UDP(sport=1234, dport=48879) / - VXLAN(vni=99, gpid=112, flags=0x88) / - Ether(src=l['mac'], dst=ep.mac) / - IP(src=l['ip'], dst=ep.ip4.address) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - - rx = self.send_and_expect(self.pg2, [p], self.pg0) - - # the new TEP - tep1_sw_if_index = find_vxlan_gbp_tunnel( - self, - self.pg2.local_ip4, - self.pg2.remote_hosts[1].ip4, - 99) - self.assertNotEqual(INDEX_INVALID, tep1_sw_if_index) - - # - # the EP is learnt via the learnt TEP - # both from its MAC and its IP - # - self.assertTrue(find_gbp_endpoint(self, - vx_tun_l2_1.sw_if_index, - mac=l['mac'])) - self.assertTrue(find_gbp_endpoint(self, - vx_tun_l2_1.sw_if_index, - ip=l['ip'])) - - self.assert_error_counter_equal( - '/err/gbp-policy-port/allow-intra-sclass', - allow_intra_class + 2) - - self.logger.info(self.vapi.cli("show gbp endpoint")) - self.logger.info(self.vapi.cli("show gbp vxlan")) - self.logger.info(self.vapi.cli("show ip mfib")) - - # - # If we sleep for the threshold time, the learnt endpoints should - # age out - # - for l in learnt: - self.wait_for_ep_timeout(vx_tun_l2_1.sw_if_index, - mac=l['mac']) - - # - # Learn new EPs from GARP packets received on the BD's mcast tunnel - # - for ii, l in enumerate(learnt): - # add some junk in the reserved field of the vxlan-header - # next to the VNI. we should accept since reserved bits are - # ignored on rx. - p = (Ether(src=self.pg2.remote_mac, - dst=self.pg2.local_mac) / - IP(src=self.pg2.remote_hosts[1].ip4, - dst="239.1.1.1") / - UDP(sport=1234, dport=48879) / - VXLAN(vni=88, reserved2=0x80, gpid=112, flags=0x88) / - Ether(src=l['mac'], dst="ff:ff:ff:ff:ff:ff") / - ARP(op="who-has", - psrc=l['ip'], pdst=l['ip'], - hwsrc=l['mac'], hwdst="ff:ff:ff:ff:ff:ff")) - - rx = self.send_and_expect(self.pg4, [p], self.pg0) - - # the new TEP - tep1_sw_if_index = find_vxlan_gbp_tunnel( - self, - self.pg2.local_ip4, - self.pg2.remote_hosts[1].ip4, - 99) - self.assertNotEqual(INDEX_INVALID, tep1_sw_if_index) - - # - # the EP is learnt via the learnt TEP - # both from its MAC and its IP - # - self.assertTrue(find_gbp_endpoint(self, - vx_tun_l2_1.sw_if_index, - mac=l['mac'])) - self.assertTrue(find_gbp_endpoint(self, - vx_tun_l2_1.sw_if_index, - ip=l['ip'])) - - # - # wait for the learnt endpoints to age out - # - for l in learnt: - self.wait_for_ep_timeout(vx_tun_l2_1.sw_if_index, - mac=l['mac']) - - # - # Learn new EPs from L2 packets - # - for ii, l in enumerate(learnt): - # a packet with an sclass from a known EPG - # arriving on an unknown TEP - p = (Ether(src=self.pg2.remote_mac, - dst=self.pg2.local_mac) / - IP(src=self.pg2.remote_hosts[1].ip4, - dst=self.pg2.local_ip4) / - UDP(sport=1234, dport=48879) / - VXLAN(vni=99, gpid=112, flags=0x88) / - Ether(src=l['mac'], dst=ep.mac) / - Raw('\xa5' * 100)) - - rx = self.send_and_expect(self.pg2, [p], self.pg0) - - # the new TEP - tep1_sw_if_index = find_vxlan_gbp_tunnel( - self, - self.pg2.local_ip4, - self.pg2.remote_hosts[1].ip4, - 99) - self.assertNotEqual(INDEX_INVALID, tep1_sw_if_index) - - # - # the EP is learnt via the learnt TEP - # both from its MAC and its IP - # - self.assertTrue(find_gbp_endpoint(self, - vx_tun_l2_1.sw_if_index, - mac=l['mac'])) - - self.logger.info(self.vapi.cli("show gbp endpoint")) - self.logger.info(self.vapi.cli("show gbp vxlan")) - self.logger.info(self.vapi.cli("show vxlan-gbp tunnel")) - - # - # wait for the learnt endpoints to age out - # - for l in learnt: - self.wait_for_ep_timeout(vx_tun_l2_1.sw_if_index, - mac=l['mac']) - - # - # repeat. the do not learn bit is set so the EPs are not learnt - # - for l in learnt: - # a packet with an sclass from a known EPG - p = (Ether(src=self.pg2.remote_mac, - dst=self.pg2.local_mac) / - IP(src=self.pg2.remote_hosts[1].ip4, - dst=self.pg2.local_ip4) / - UDP(sport=1234, dport=48879) / - VXLAN(vni=99, gpid=112, flags=0x88, gpflags="D") / - Ether(src=l['mac'], dst=ep.mac) / - IP(src=l['ip'], dst=ep.ip4.address) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - - rx = self.send_and_expect(self.pg2, p * NUM_PKTS, self.pg0) - - for l in learnt: - self.assertFalse(find_gbp_endpoint(self, - vx_tun_l2_1.sw_if_index, - mac=l['mac'])) - - # - # repeat - # - for l in learnt: - # a packet with an sclass from a known EPG - # set a reserved bit in addition to the G and I - # reserved bits should not be checked on rx. - p = (Ether(src=self.pg2.remote_mac, - dst=self.pg2.local_mac) / - IP(src=self.pg2.remote_hosts[1].ip4, - dst=self.pg2.local_ip4) / - UDP(sport=1234, dport=48879) / - VXLAN(vni=99, gpid=112, flags=0xc8) / - Ether(src=l['mac'], dst=ep.mac) / - IP(src=l['ip'], dst=ep.ip4.address) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - - rx = self.send_and_expect(self.pg2, p * NUM_PKTS, self.pg0) - - self.assertTrue(find_gbp_endpoint(self, - vx_tun_l2_1.sw_if_index, - mac=l['mac'])) - - # - # Static EP replies to dynamics - # - self.logger.info(self.vapi.cli("sh l2fib bd_id 1")) - for l in learnt: - p = (Ether(src=ep.mac, dst=l['mac']) / - IP(dst=l['ip'], src=ep.ip4.address) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - - rxs = self.send_and_expect(self.pg0, p * 17, self.pg2) - - for rx in rxs: - self.assertEqual(rx[IP].src, self.pg2.local_ip4) - self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[1].ip4) - self.assertEqual(rx[UDP].dport, 48879) - # the UDP source port is a random value for hashing - self.assertEqual(rx[VXLAN].gpid, 112) - self.assertEqual(rx[VXLAN].vni, 99) - self.assertTrue(rx[VXLAN].flags.G) - self.assertTrue(rx[VXLAN].flags.Instance) - self.assertTrue(rx[VXLAN].gpflags.A) - self.assertFalse(rx[VXLAN].gpflags.D) - - for l in learnt: - self.wait_for_ep_timeout(vx_tun_l2_1.sw_if_index, - mac=l['mac']) - - # - # repeat in the other EPG - # there's no contract between 220 and 330, but the A-bit is set - # so the packet is cleared for delivery - # - for l in learnt: - # a packet with an sclass from a known EPG - p = (Ether(src=self.pg2.remote_mac, - dst=self.pg2.local_mac) / - IP(src=self.pg2.remote_hosts[1].ip4, - dst=self.pg2.local_ip4) / - UDP(sport=1234, dport=48879) / - VXLAN(vni=99, gpid=113, flags=0x88, gpflags='A') / - Ether(src=l['mac'], dst=ep.mac) / - IP(src=l['ip'], dst=ep.ip4.address) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - - rx = self.send_and_expect(self.pg2, p * NUM_PKTS, self.pg0) - - self.assertTrue(find_gbp_endpoint(self, - vx_tun_l2_1.sw_if_index, - mac=l['mac'])) - - # - # static EP cannot reach the learnt EPs since there is no contract - # only test 1 EP as the others could timeout - # - p = (Ether(src=ep.mac, dst=l['mac']) / - IP(dst=learnt[0]['ip'], src=ep.ip4.address) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - - self.send_and_assert_no_replies(self.pg0, [p]) - - # - # refresh the entries after the check for no replies above - # - for l in learnt: - # a packet with an sclass from a known EPG - p = (Ether(src=self.pg2.remote_mac, - dst=self.pg2.local_mac) / - IP(src=self.pg2.remote_hosts[1].ip4, - dst=self.pg2.local_ip4) / - UDP(sport=1234, dport=48879) / - VXLAN(vni=99, gpid=113, flags=0x88, gpflags='A') / - Ether(src=l['mac'], dst=ep.mac) / - IP(src=l['ip'], dst=ep.ip4.address) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - - rx = self.send_and_expect(self.pg2, p * NUM_PKTS, self.pg0) - - self.assertTrue(find_gbp_endpoint(self, - vx_tun_l2_1.sw_if_index, - mac=l['mac'])) - - # - # Add the contract so they can talk - # - acl = VppGbpAcl(self) - rule = acl.create_rule(permit_deny=1, proto=17) - rule2 = acl.create_rule(is_ipv6=1, permit_deny=1, proto=17) - acl_index = acl.add_vpp_config([rule, rule2]) - c1 = VppGbpContract( - self, 401, epg_220.sclass, epg_330.sclass, acl_index, - [VppGbpContractRule( - VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT, - VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP, - []), - VppGbpContractRule( - VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT, - VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP, - [])], - [ETH_P_IP, ETH_P_IPV6]) - c1.add_vpp_config() - - for l in learnt: - p = (Ether(src=ep.mac, dst=l['mac']) / - IP(dst=l['ip'], src=ep.ip4.address) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - - self.send_and_expect(self.pg0, [p], self.pg2) - - # - # send UU packets from the local EP - # - self.logger.info(self.vapi.cli("sh gbp bridge")) - self.logger.info(self.vapi.cli("sh bridge-domain 1 detail")) - p_uu = (Ether(src=ep.mac, dst="00:11:11:11:11:11") / - IP(dst="10.0.0.133", src=ep.ip4.address) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - rxs = self.send_and_expect(ep.itf, [p_uu], gbd1.uu_fwd) - - self.logger.info(self.vapi.cli("sh bridge 1 detail")) - - p_bm = (Ether(src=ep.mac, dst="ff:ff:ff:ff:ff:ff") / - IP(dst="10.0.0.133", src=ep.ip4.address) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - rxs = self.send_and_expect_only(ep.itf, [p_bm], tun_bm.mcast_itf) - - for rx in rxs: - self.assertEqual(rx[IP].src, self.pg4.local_ip4) - self.assertEqual(rx[IP].dst, "239.1.1.1") - self.assertEqual(rx[UDP].dport, 48879) - # the UDP source port is a random value for hashing - self.assertEqual(rx[VXLAN].gpid, 112) - self.assertEqual(rx[VXLAN].vni, 88) - self.assertTrue(rx[VXLAN].flags.G) - self.assertTrue(rx[VXLAN].flags.Instance) - self.assertFalse(rx[VXLAN].gpflags.A) - self.assertFalse(rx[VXLAN].gpflags.D) - - acl = VppGbpAcl(self) - rule = acl.create_rule(permit_deny=1, proto=17) - rule2 = acl.create_rule(is_ipv6=1, permit_deny=1, proto=17) - acl_index = acl.add_vpp_config([rule, rule2]) - c2 = VppGbpContract( - self, 401, epg_330.sclass, epg_220.sclass, acl_index, - [VppGbpContractRule( - VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT, - VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP, - []), - VppGbpContractRule( - VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT, - VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP, - [])], - [ETH_P_IP, ETH_P_IPV6]) - c2.add_vpp_config() - - for l in learnt: - self.wait_for_ep_timeout(vx_tun_l2_1.sw_if_index, - mac=l['mac']) - # - # Check v6 Endpoints learning - # - for l in learnt: - # a packet with an sclass from a known EPG - p = (Ether(src=self.pg2.remote_mac, - dst=self.pg2.local_mac) / - IP(src=self.pg2.remote_hosts[1].ip4, - dst=self.pg2.local_ip4) / - UDP(sport=1234, dport=48879) / - VXLAN(vni=99, gpid=113, flags=0x88) / - Ether(src=l['mac'], dst=ep.mac) / - IPv6(src=l['ip6'], dst=ep.ip6.address) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - - rx = self.send_and_expect(self.pg2, p * NUM_PKTS, self.pg0) - rx = self.send_and_expect(self.pg2, p * NUM_PKTS, self.pg0) - - self.assertTrue(find_gbp_endpoint( - self, - vx_tun_l2_1.sw_if_index, - ip=l['ip6'], - tep=[self.pg2.local_ip4, - self.pg2.remote_hosts[1].ip4])) - - self.logger.info(self.vapi.cli("sh int")) - self.logger.info(self.vapi.cli("sh vxlan-gbp tunnel")) - self.logger.info(self.vapi.cli("sh gbp vxlan")) - self.logger.info(self.vapi.cli("sh gbp endpoint")) - self.logger.info(self.vapi.cli("sh gbp interface")) - - # - # EP moves to a different TEP - # - for l in learnt: - # a packet with an sclass from a known EPG - p = (Ether(src=self.pg2.remote_mac, - dst=self.pg2.local_mac) / - IP(src=self.pg2.remote_hosts[2].ip4, - dst=self.pg2.local_ip4) / - UDP(sport=1234, dport=48879) / - VXLAN(vni=99, gpid=113, flags=0x88) / - Ether(src=l['mac'], dst=ep.mac) / - IPv6(src=l['ip6'], dst=ep.ip6.address) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - - rx = self.send_and_expect(self.pg2, p * 1, self.pg0) - rx = self.send_and_expect(self.pg2, p * NUM_PKTS, self.pg0) - - self.assertTrue(find_gbp_endpoint( - self, - vx_tun_l2_1.sw_if_index, - sclass=113, - mac=l['mac'], - tep=[self.pg2.local_ip4, - self.pg2.remote_hosts[2].ip4])) - - # - # v6 remote EP reachability - # - for l in learnt: - p = (Ether(src=ep.mac, dst=l['mac']) / - IPv6(dst=l['ip6'], src=ep.ip6.address) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - - rxs = self.send_and_expect(self.pg0, p * NUM_PKTS, self.pg2) - - for rx in rxs: - self.assertEqual(rx[IP].src, self.pg2.local_ip4) - self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[2].ip4) - self.assertEqual(rx[UDP].dport, 48879) - # the UDP source port is a random value for hashing - self.assertEqual(rx[VXLAN].gpid, 112) - self.assertEqual(rx[VXLAN].vni, 99) - self.assertTrue(rx[VXLAN].flags.G) - self.assertTrue(rx[VXLAN].flags.Instance) - self.assertTrue(rx[VXLAN].gpflags.A) - self.assertFalse(rx[VXLAN].gpflags.D) - self.assertEqual(rx[IPv6].dst, l['ip6']) - - # - # EP changes sclass - # - for l in learnt: - # a packet with an sclass from a known EPG - p = (Ether(src=self.pg2.remote_mac, - dst=self.pg2.local_mac) / - IP(src=self.pg2.remote_hosts[2].ip4, - dst=self.pg2.local_ip4) / - UDP(sport=1234, dport=48879) / - VXLAN(vni=99, gpid=112, flags=0x88) / - Ether(src=l['mac'], dst=ep.mac) / - IPv6(src=l['ip6'], dst=ep.ip6.address) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - - rx = self.send_and_expect(self.pg2, p * 1, self.pg0) - rx = self.send_and_expect(self.pg2, p * NUM_PKTS, self.pg0) - - self.assertTrue(find_gbp_endpoint( - self, - vx_tun_l2_1.sw_if_index, - mac=l['mac'], - sclass=112, - tep=[self.pg2.local_ip4, - self.pg2.remote_hosts[2].ip4])) - - # - # check reachability and contract intra-epg - # - allow_intra_class = self.statistics.get_err_counter( - '/err/gbp-policy-mac/allow-intra-sclass') - - for l in learnt: - p = (Ether(src=ep.mac, dst=l['mac']) / - IPv6(dst=l['ip6'], src=ep.ip6.address) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - - rxs = self.send_and_expect(self.pg0, p * NUM_PKTS, self.pg2) - - for rx in rxs: - self.assertEqual(rx[IP].src, self.pg2.local_ip4) - self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[2].ip4) - self.assertEqual(rx[UDP].dport, 48879) - self.assertEqual(rx[VXLAN].gpid, 112) - self.assertEqual(rx[VXLAN].vni, 99) - self.assertTrue(rx[VXLAN].flags.G) - self.assertTrue(rx[VXLAN].flags.Instance) - self.assertTrue(rx[VXLAN].gpflags.A) - self.assertFalse(rx[VXLAN].gpflags.D) - self.assertEqual(rx[IPv6].dst, l['ip6']) - - allow_intra_class += NUM_PKTS - - self.assert_error_counter_equal( - '/err/gbp-policy-mac/allow-intra-sclass', - allow_intra_class) - - # - # clean up - # - for l in learnt: - self.wait_for_ep_timeout(vx_tun_l2_1.sw_if_index, - mac=l['mac']) - self.pg2.unconfig_ip4() - self.pg3.unconfig_ip4() - self.pg4.unconfig_ip4() - - def test_gbp_contract(self): - """ GBP Contracts """ - - # - # Route Domains - # - gt4 = VppIpTable(self, 0) - gt4.add_vpp_config() - gt6 = VppIpTable(self, 0, is_ip6=True) - gt6.add_vpp_config() - - rd0 = VppGbpRouteDomain(self, 0, 400, gt4, gt6, None, None) - - rd0.add_vpp_config() - - # - # Bridge Domains - # - bd1 = VppBridgeDomain(self, 1, arp_term=0) - bd2 = VppBridgeDomain(self, 2, arp_term=0) - - bd1.add_vpp_config() - bd2.add_vpp_config() - - gbd1 = VppGbpBridgeDomain(self, bd1, rd0, self.loop0) - gbd2 = VppGbpBridgeDomain(self, bd2, rd0, self.loop1) - - gbd1.add_vpp_config() - gbd2.add_vpp_config() - - # - # 3 EPGs, 2 of which share a BD. - # - epgs = [VppGbpEndpointGroup(self, 220, 1220, rd0, gbd1, - None, self.loop0, - "10.0.0.128", "2001:10::128"), - VppGbpEndpointGroup(self, 221, 1221, rd0, gbd1, - None, self.loop0, - "10.0.1.128", "2001:10:1::128"), - VppGbpEndpointGroup(self, 222, 1222, rd0, gbd2, - None, self.loop1, - "10.0.2.128", "2001:10:2::128")] - # - # 4 end-points, 2 in the same subnet, 3 in the same BD - # - eps = [VppGbpEndpoint(self, self.pg0, - epgs[0], None, - "10.0.0.1", "11.0.0.1", - "2001:10::1", "3001::1"), - VppGbpEndpoint(self, self.pg1, - epgs[0], None, - "10.0.0.2", "11.0.0.2", - "2001:10::2", "3001::2"), - VppGbpEndpoint(self, self.pg2, - epgs[1], None, - "10.0.1.1", "11.0.0.3", - "2001:10:1::1", "3001::3"), - VppGbpEndpoint(self, self.pg3, - epgs[2], None, - "10.0.2.1", "11.0.0.4", - "2001:10:2::1", "3001::4")] - - # - # Config related to each of the EPGs - # - for epg in epgs: - # IP config on the BVI interfaces - if epg != epgs[1]: - VppIpInterfaceBind(self, epg.bvi, epg.rd.t4).add_vpp_config() - VppIpInterfaceBind(self, epg.bvi, epg.rd.t6).add_vpp_config() - self.vapi.sw_interface_set_mac_address( - epg.bvi.sw_if_index, - self.router_mac.packed) - - if_ip4 = VppIpInterfaceAddress(self, epg.bvi, epg.bvi_ip4, 32) - if_ip6 = VppIpInterfaceAddress(self, epg.bvi, epg.bvi_ip6, 128) - if_ip4.add_vpp_config() - if_ip6.add_vpp_config() - - # add the BD ARP termination entry for BVI IP - epg.bd_arp_ip4 = VppBridgeDomainArpEntry(self, epg.bd.bd, - str(self.router_mac), - epg.bvi_ip4.address) - epg.bd_arp_ip4.add_vpp_config() - - # EPG in VPP - epg.add_vpp_config() - - # - # config ep - # - for ep in eps: - ep.add_vpp_config() - - self.logger.info(self.vapi.cli("show gbp endpoint")) - self.logger.info(self.vapi.cli("show interface")) - self.logger.info(self.vapi.cli("show br")) - - # - # Intra epg allowed without contract - # - pkt_intra_epg_220_to_220 = (Ether(src=self.pg0.remote_mac, - dst=self.pg1.remote_mac) / - IP(src=eps[0].ip4.address, - dst=eps[1].ip4.address) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - - self.send_and_expect_bridged(self.pg0, - pkt_intra_epg_220_to_220 * 65, - self.pg1) - - pkt_intra_epg_220_to_220 = (Ether(src=self.pg0.remote_mac, - dst=self.pg1.remote_mac) / - IPv6(src=eps[0].ip6.address, - dst=eps[1].ip6.address) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - - self.send_and_expect_bridged6(self.pg0, - pkt_intra_epg_220_to_220 * 65, - self.pg1) - - # - # Inter epg denied without contract - # - pkt_inter_epg_220_to_221 = (Ether(src=self.pg0.remote_mac, - dst=self.pg2.remote_mac) / - IP(src=eps[0].ip4.address, - dst=eps[2].ip4.address) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - - self.send_and_assert_no_replies(self.pg0, pkt_inter_epg_220_to_221) - - # - # A uni-directional contract from EPG 220 -> 221 - # - acl = VppGbpAcl(self) - rule = acl.create_rule(permit_deny=1, proto=17) - rule2 = acl.create_rule(is_ipv6=1, permit_deny=1, proto=17) - rule3 = acl.create_rule(permit_deny=1, proto=1) - acl_index = acl.add_vpp_config([rule, rule2, rule3]) - c1 = VppGbpContract( - self, 400, epgs[0].sclass, epgs[1].sclass, acl_index, - [VppGbpContractRule( - VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT, - VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP, - []), - VppGbpContractRule( - VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT, - VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP, - []), - VppGbpContractRule( - VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT, - VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP, - [])], - [ETH_P_IP, ETH_P_IPV6]) - c1.add_vpp_config() - - self.send_and_expect_bridged(eps[0].itf, - pkt_inter_epg_220_to_221 * 65, - eps[2].itf) - - pkt_inter_epg_220_to_222 = (Ether(src=self.pg0.remote_mac, - dst=str(self.router_mac)) / - IP(src=eps[0].ip4.address, - dst=eps[3].ip4.address) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - self.send_and_assert_no_replies(eps[0].itf, - pkt_inter_epg_220_to_222 * 65) - - # - # ping router IP in different BD - # - pkt_router_ping_220_to_221 = (Ether(src=self.pg0.remote_mac, - dst=str(self.router_mac)) / - IP(src=eps[0].ip4.address, - dst=epgs[1].bvi_ip4.address) / - ICMP(type='echo-request')) - - self.send_and_expect(self.pg0, [pkt_router_ping_220_to_221], self.pg0) - - pkt_router_ping_220_to_221 = (Ether(src=self.pg0.remote_mac, - dst=str(self.router_mac)) / - IPv6(src=eps[0].ip6.address, - dst=epgs[1].bvi_ip6.address) / - ICMPv6EchoRequest()) - - self.send_and_expect(self.pg0, [pkt_router_ping_220_to_221], self.pg0) - - # - # contract for the return direction - # - c2 = VppGbpContract( - self, 400, epgs[1].sclass, epgs[0].sclass, acl_index, - [VppGbpContractRule( - VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT, - VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP, - []), - VppGbpContractRule( - VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT, - VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP, - [])], - [ETH_P_IP, ETH_P_IPV6]) - c2.add_vpp_config() - - self.send_and_expect_bridged(eps[0].itf, - pkt_inter_epg_220_to_221 * 65, - eps[2].itf) - pkt_inter_epg_221_to_220 = (Ether(src=self.pg2.remote_mac, - dst=self.pg0.remote_mac) / - IP(src=eps[2].ip4.address, - dst=eps[0].ip4.address) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - self.send_and_expect_bridged(eps[2].itf, - pkt_inter_epg_221_to_220 * 65, - eps[0].itf) - pkt_inter_epg_221_to_220 = (Ether(src=self.pg2.remote_mac, - dst=str(self.router_mac)) / - IP(src=eps[2].ip4.address, - dst=eps[0].ip4.address) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - self.send_and_expect_routed(eps[2].itf, - pkt_inter_epg_221_to_220 * 65, - eps[0].itf, - str(self.router_mac)) - pkt_inter_epg_221_to_220 = (Ether(src=self.pg2.remote_mac, - dst=str(self.router_mac)) / - IPv6(src=eps[2].ip6.address, - dst=eps[0].ip6.address) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - self.send_and_expect_routed6(eps[2].itf, - pkt_inter_epg_221_to_220 * 65, - eps[0].itf, - str(self.router_mac)) - - # - # contract between 220 and 222 uni-direction - # - c3 = VppGbpContract( - self, 400, epgs[0].sclass, epgs[2].sclass, acl_index, - [VppGbpContractRule( - VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT, - VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP, - []), - VppGbpContractRule( - VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT, - VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP, - [])], - [ETH_P_IP, ETH_P_IPV6]) - c3.add_vpp_config() - - self.send_and_expect(eps[0].itf, - pkt_inter_epg_220_to_222 * 65, - eps[3].itf) - - c3.remove_vpp_config() - c1.remove_vpp_config() - c2.remove_vpp_config() - acl.remove_vpp_config() - - def test_gbp_bd_drop_flags(self): - """ GBP BD drop flags """ - - # - # IP tables - # - gt4 = VppIpTable(self, 1) - gt4.add_vpp_config() - gt6 = VppIpTable(self, 1, is_ip6=True) - gt6.add_vpp_config() - - rd1 = VppGbpRouteDomain(self, 1, 401, gt4, gt6) - rd1.add_vpp_config() - - # - # a GBP bridge domain with a BVI only - # - bd1 = VppBridgeDomain(self, 1) - bd1.add_vpp_config() - - gbd1 = VppGbpBridgeDomain(self, bd1, rd1, self.loop0, - None, None, - uu_drop=True, bm_drop=True) - gbd1.add_vpp_config() - - self.logger.info(self.vapi.cli("sh bridge 1 detail")) - self.logger.info(self.vapi.cli("sh gbp bridge")) - - # ... and has a /32 applied - ip_addr = VppIpInterfaceAddress(self, gbd1.bvi, "10.0.0.128", 32) - ip_addr.add_vpp_config() - - # - # The Endpoint-group - # - epg_220 = VppGbpEndpointGroup(self, 220, 112, rd1, gbd1, - None, self.loop0, - "10.0.0.128", - "2001:10::128", - VppGbpEndpointRetention(2)) - epg_220.add_vpp_config() - - ep = VppGbpEndpoint(self, self.pg0, - epg_220, None, - "10.0.0.127", "11.0.0.127", - "2001:10::1", "3001::1") - ep.add_vpp_config() - - # - # send UU/BM packet from the local EP with UU drop and BM drop enabled - # in bd - # - self.logger.info(self.vapi.cli("sh bridge 1 detail")) - self.logger.info(self.vapi.cli("sh gbp bridge")) - p_uu = (Ether(src=ep.mac, dst="00:11:11:11:11:11") / - IP(dst="10.0.0.133", src=ep.ip4.address) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - self.send_and_assert_no_replies(ep.itf, [p_uu]) - - p_bm = (Ether(src=ep.mac, dst="ff:ff:ff:ff:ff:ff") / - IP(dst="10.0.0.133", src=ep.ip4.address) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - self.send_and_assert_no_replies(ep.itf, [p_bm]) - - self.pg3.unconfig_ip4() - - self.logger.info(self.vapi.cli("sh int")) - - def test_gbp_bd_arp_flags(self): - """ GBP BD arp flags """ - - # - # IP tables - # - gt4 = VppIpTable(self, 1) - gt4.add_vpp_config() - gt6 = VppIpTable(self, 1, is_ip6=True) - gt6.add_vpp_config() - - rd1 = VppGbpRouteDomain(self, 1, 401, gt4, gt6) - rd1.add_vpp_config() - - # - # Pg4 hosts the IP6 UU-flood VXLAN tunnel - # - self.pg4.config_ip4() - self.pg4.resolve_arp() - - # - # Add a mcast destination VXLAN-GBP tunnel for B&M traffic - # - tun_uu = VppVxlanGbpTunnel(self, self.pg4.local_ip4, - "239.1.1.1", 88, - mcast_itf=self.pg4) - tun_uu.add_vpp_config() - - # - # a GBP bridge domain with a BVI and a UU-flood interface - # - bd1 = VppBridgeDomain(self, 1) - bd1.add_vpp_config() - - gbd1 = VppGbpBridgeDomain(self, bd1, rd1, self.loop0, - tun_uu, None, - ucast_arp=True) - gbd1.add_vpp_config() - - # ... and has a /32 applied - ip_addr = VppIpInterfaceAddress(self, gbd1.bvi, "10.0.0.128", 32) - ip_addr.add_vpp_config() - - # - # The Endpoint-group - # - epg_220 = VppGbpEndpointGroup(self, 220, 112, rd1, gbd1, - None, self.loop0, - "10.0.0.128", - "2001:10::128", - VppGbpEndpointRetention(2)) - epg_220.add_vpp_config() - - ep = VppGbpEndpoint(self, self.pg0, - epg_220, None, - "10.0.0.127", "11.0.0.127", - "2001:10::1", "3001::1") - ep.add_vpp_config() - - # - # send ARP packet from the local EP expect it on the uu interface - # - self.logger.info(self.vapi.cli("sh bridge 1 detail")) - self.logger.info(self.vapi.cli("sh gbp bridge")) - p_arp = (Ether(src=ep.mac, dst="ff:ff:ff:ff:ff:ff") / - ARP(op="who-has", - psrc=ep.ip4.address, pdst="10.0.0.99", - hwsrc=ep.mac, - hwdst="ff:ff:ff:ff:ff:ff")) - self.send_and_expect(ep.itf, [p_arp], self.pg4) - - self.pg4.unconfig_ip4() - - def test_gbp_learn_vlan_l2(self): - """ GBP L2 Endpoint w/ VLANs""" - - ep_flags = VppEnum.vl_api_gbp_endpoint_flags_t - learnt = [{'mac': '00:00:11:11:11:01', - 'ip': '10.0.0.1', - 'ip6': '2001:10::2'}, - {'mac': '00:00:11:11:11:02', - 'ip': '10.0.0.2', - 'ip6': '2001:10::3'}] - - # - # IP tables - # - gt4 = VppIpTable(self, 1) - gt4.add_vpp_config() - gt6 = VppIpTable(self, 1, is_ip6=True) - gt6.add_vpp_config() - - rd1 = VppGbpRouteDomain(self, 1, 401, gt4, gt6) - rd1.add_vpp_config() - - # - # Pg2 hosts the vxlan tunnel, hosts on pg2 to act as TEPs - # - self.pg2.config_ip4() - self.pg2.resolve_arp() - self.pg2.generate_remote_hosts(4) - self.pg2.configure_ipv4_neighbors() - self.pg3.config_ip4() - self.pg3.resolve_arp() - - # - # The EP will be on a vlan sub-interface - # - vlan_11 = VppDot1QSubint(self, self.pg0, 11) - vlan_11.admin_up() - self.vapi.l2_interface_vlan_tag_rewrite( - sw_if_index=vlan_11.sw_if_index, vtr_op=L2_VTR_OP.L2_POP_1, - push_dot1q=11) - - bd_uu_fwd = VppVxlanGbpTunnel(self, self.pg3.local_ip4, - self.pg3.remote_ip4, 116) - bd_uu_fwd.add_vpp_config() - - # - # a GBP bridge domain with a BVI and a UU-flood interface - # The BD is marked as do not learn, so no endpoints are ever - # learnt in this BD. - # - bd1 = VppBridgeDomain(self, 1) - bd1.add_vpp_config() - gbd1 = VppGbpBridgeDomain(self, bd1, rd1, self.loop0, bd_uu_fwd, - learn=False) - gbd1.add_vpp_config() - - self.logger.info(self.vapi.cli("sh bridge 1 detail")) - self.logger.info(self.vapi.cli("sh gbp bridge")) - - # ... and has a /32 applied - ip_addr = VppIpInterfaceAddress(self, gbd1.bvi, "10.0.0.128", 32) - ip_addr.add_vpp_config() - - # - # The Endpoint-group in which we are learning endpoints - # - epg_220 = VppGbpEndpointGroup(self, 220, 441, rd1, gbd1, - None, self.loop0, - "10.0.0.128", - "2001:10::128", - VppGbpEndpointRetention(2)) - epg_220.add_vpp_config() - - # - # The VXLAN GBP tunnel is a bridge-port and has L2 endpoint - # learning enabled - # - vx_tun_l2_1 = VppGbpVxlanTunnel( - self, 99, bd1.bd_id, - VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L2, - self.pg2.local_ip4) - vx_tun_l2_1.add_vpp_config() - - # - # A static endpoint that the learnt endpoints are trying to - # talk to - # - ep = VppGbpEndpoint(self, vlan_11, - epg_220, None, - "10.0.0.127", "11.0.0.127", - "2001:10::1", "3001::1") - ep.add_vpp_config() - - self.assertTrue(find_route(self, ep.ip4.address, 32, table_id=1)) - - # - # Send to the static EP - # - for ii, l in enumerate(learnt): - # a packet with an sclass from a known EPG - # arriving on an unknown TEP - p = (Ether(src=self.pg2.remote_mac, - dst=self.pg2.local_mac) / - IP(src=self.pg2.remote_hosts[1].ip4, - dst=self.pg2.local_ip4) / - UDP(sport=1234, dport=48879) / - VXLAN(vni=99, gpid=441, flags=0x88) / - Ether(src=l['mac'], dst=ep.mac) / - IP(src=l['ip'], dst=ep.ip4.address) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - - rxs = self.send_and_expect(self.pg2, [p], self.pg0) - - # - # packet to EP has the EP's vlan tag - # - for rx in rxs: - self.assertEqual(rx[Dot1Q].vlan, 11) - - # - # the EP is not learnt since the BD setting prevents it - # also no TEP too - # - self.assertFalse(find_gbp_endpoint(self, - vx_tun_l2_1.sw_if_index, - mac=l['mac'])) - self.assertEqual(INDEX_INVALID, - find_vxlan_gbp_tunnel( - self, - self.pg2.local_ip4, - self.pg2.remote_hosts[1].ip4, - 99)) - - self.assertEqual(len(self.vapi.gbp_endpoint_dump()), 1) - - # - # static to remotes - # we didn't learn the remotes so they are sent to the UU-fwd - # - for l in learnt: - p = (Ether(src=ep.mac, dst=l['mac']) / - Dot1Q(vlan=11) / - IP(dst=l['ip'], src=ep.ip4.address) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - - rxs = self.send_and_expect(self.pg0, p * 17, self.pg3) - - for rx in rxs: - self.assertEqual(rx[IP].src, self.pg3.local_ip4) - self.assertEqual(rx[IP].dst, self.pg3.remote_ip4) - self.assertEqual(rx[UDP].dport, 48879) - # the UDP source port is a random value for hashing - self.assertEqual(rx[VXLAN].gpid, 441) - self.assertEqual(rx[VXLAN].vni, 116) - self.assertTrue(rx[VXLAN].flags.G) - self.assertTrue(rx[VXLAN].flags.Instance) - self.assertFalse(rx[VXLAN].gpflags.A) - self.assertFalse(rx[VXLAN].gpflags.D) - - self.pg2.unconfig_ip4() - self.pg3.unconfig_ip4() - - def test_gbp_learn_l3(self): - """ GBP L3 Endpoint Learning """ - - self.vapi.cli("set logging class gbp level debug") - - ep_flags = VppEnum.vl_api_gbp_endpoint_flags_t - routed_dst_mac = "00:0c:0c:0c:0c:0c" - routed_src_mac = "00:22:bd:f8:19:ff" - - learnt = [{'mac': '00:00:11:11:11:02', - 'ip': '10.0.1.2', - 'ip6': '2001:10::2'}, - {'mac': '00:00:11:11:11:03', - 'ip': '10.0.1.3', - 'ip6': '2001:10::3'}] - - # - # IP tables - # - t4 = VppIpTable(self, 1) - t4.add_vpp_config() - t6 = VppIpTable(self, 1, True) - t6.add_vpp_config() - - tun_ip4_uu = VppVxlanGbpTunnel(self, self.pg4.local_ip4, - self.pg4.remote_ip4, 114) - tun_ip6_uu = VppVxlanGbpTunnel(self, self.pg4.local_ip4, - self.pg4.remote_ip4, 116) - tun_ip4_uu.add_vpp_config() - tun_ip6_uu.add_vpp_config() - - rd1 = VppGbpRouteDomain(self, 2, 401, t4, t6, tun_ip4_uu, tun_ip6_uu) - rd1.add_vpp_config() - - self.loop0.set_mac(self.router_mac) - - # - # Bind the BVI to the RD - # - VppIpInterfaceBind(self, self.loop0, t4).add_vpp_config() - VppIpInterfaceBind(self, self.loop0, t6).add_vpp_config() - - # - # Pg2 hosts the vxlan tunnel - # hosts on pg2 to act as TEPs - # pg3 is BD uu-fwd - # pg4 is RD uu-fwd - # - self.pg2.config_ip4() - self.pg2.resolve_arp() - self.pg2.generate_remote_hosts(4) - self.pg2.configure_ipv4_neighbors() - self.pg3.config_ip4() - self.pg3.resolve_arp() - self.pg4.config_ip4() - self.pg4.resolve_arp() - - # - # a GBP bridge domain with a BVI and a UU-flood interface - # - bd1 = VppBridgeDomain(self, 1) - bd1.add_vpp_config() - gbd1 = VppGbpBridgeDomain(self, bd1, rd1, self.loop0, self.pg3) - gbd1.add_vpp_config() - - self.logger.info(self.vapi.cli("sh bridge 1 detail")) - self.logger.info(self.vapi.cli("sh gbp bridge")) - self.logger.info(self.vapi.cli("sh gbp route")) - - # ... and has a /32 and /128 applied - ip4_addr = VppIpInterfaceAddress(self, gbd1.bvi, "10.0.0.128", 32) - ip4_addr.add_vpp_config() - ip6_addr = VppIpInterfaceAddress(self, gbd1.bvi, "2001:10::128", 128) - ip6_addr.add_vpp_config() - - # - # The Endpoint-group in which we are learning endpoints - # - epg_220 = VppGbpEndpointGroup(self, 220, 441, rd1, gbd1, - None, self.loop0, - "10.0.0.128", - "2001:10::128", - VppGbpEndpointRetention(2)) - epg_220.add_vpp_config() - - # - # The VXLAN GBP tunnel is in L3 mode with learning enabled - # - vx_tun_l3 = VppGbpVxlanTunnel( - self, 101, rd1.rd_id, - VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L3, - self.pg2.local_ip4) - vx_tun_l3.add_vpp_config() - - # - # A static endpoint that the learnt endpoints are trying to - # talk to - # - ep = VppGbpEndpoint(self, self.pg0, - epg_220, None, - "10.0.0.127", "11.0.0.127", - "2001:10::1", "3001::1") - ep.add_vpp_config() - - # - # learn some remote IPv4 EPs - # - for ii, l in enumerate(learnt): - # a packet with an sclass from a known EPG - # arriving on an unknown TEP - p = (Ether(src=self.pg2.remote_mac, - dst=self.pg2.local_mac) / - IP(src=self.pg2.remote_hosts[1].ip4, - dst=self.pg2.local_ip4) / - UDP(sport=1234, dport=48879) / - VXLAN(vni=101, gpid=441, flags=0x88) / - Ether(src=l['mac'], dst="00:00:00:11:11:11") / - IP(src=l['ip'], dst=ep.ip4.address) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - - rx = self.send_and_expect(self.pg2, [p], self.pg0) - - # the new TEP - tep1_sw_if_index = find_vxlan_gbp_tunnel( - self, - self.pg2.local_ip4, - self.pg2.remote_hosts[1].ip4, - vx_tun_l3.vni) - self.assertNotEqual(INDEX_INVALID, tep1_sw_if_index) - - # endpoint learnt via the parent GBP-vxlan interface - self.assertTrue(find_gbp_endpoint(self, - vx_tun_l3._sw_if_index, - ip=l['ip'])) - - # - # Static IPv4 EP replies to learnt - # - for l in learnt: - p = (Ether(src=ep.mac, dst=self.loop0.local_mac) / - IP(dst=l['ip'], src=ep.ip4.address) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - - rxs = self.send_and_expect(self.pg0, p * 1, self.pg2) - - for rx in rxs: - self.assertEqual(rx[IP].src, self.pg2.local_ip4) - self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[1].ip4) - self.assertEqual(rx[UDP].dport, 48879) - # the UDP source port is a random value for hashing - self.assertEqual(rx[VXLAN].gpid, 441) - self.assertEqual(rx[VXLAN].vni, 101) - self.assertTrue(rx[VXLAN].flags.G) - self.assertTrue(rx[VXLAN].flags.Instance) - self.assertTrue(rx[VXLAN].gpflags.A) - self.assertFalse(rx[VXLAN].gpflags.D) - - inner = rx[VXLAN].payload - - self.assertEqual(inner[Ether].src, routed_src_mac) - self.assertEqual(inner[Ether].dst, routed_dst_mac) - self.assertEqual(inner[IP].src, ep.ip4.address) - self.assertEqual(inner[IP].dst, l['ip']) - - for l in learnt: - self.assertFalse(find_gbp_endpoint(self, - tep1_sw_if_index, - ip=l['ip'])) - - # - # learn some remote IPv6 EPs - # - for ii, l in enumerate(learnt): - # a packet with an sclass from a known EPG - # arriving on an unknown TEP - p = (Ether(src=self.pg2.remote_mac, - dst=self.pg2.local_mac) / - IP(src=self.pg2.remote_hosts[1].ip4, - dst=self.pg2.local_ip4) / - UDP(sport=1234, dport=48879) / - VXLAN(vni=101, gpid=441, flags=0x88) / - Ether(src=l['mac'], dst="00:00:00:11:11:11") / - IPv6(src=l['ip6'], dst=ep.ip6.address) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - - rx = self.send_and_expect(self.pg2, [p], self.pg0) - - # the new TEP - tep1_sw_if_index = find_vxlan_gbp_tunnel( - self, - self.pg2.local_ip4, - self.pg2.remote_hosts[1].ip4, - vx_tun_l3.vni) - self.assertNotEqual(INDEX_INVALID, tep1_sw_if_index) - - self.logger.info(self.vapi.cli("show gbp bridge")) - self.logger.info(self.vapi.cli("show vxlan-gbp tunnel")) - self.logger.info(self.vapi.cli("show gbp vxlan")) - self.logger.info(self.vapi.cli("show int addr")) - - # endpoint learnt via the TEP - self.assertTrue(find_gbp_endpoint(self, ip=l['ip6'])) - - self.logger.info(self.vapi.cli("show gbp endpoint")) - self.logger.info(self.vapi.cli("show ip fib index 1 %s" % l['ip'])) - - # - # Static EP replies to learnt - # - for l in learnt: - p = (Ether(src=ep.mac, dst=self.loop0.local_mac) / - IPv6(dst=l['ip6'], src=ep.ip6.address) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - - rxs = self.send_and_expect(self.pg0, p * NUM_PKTS, self.pg2) - - for rx in rxs: - self.assertEqual(rx[IP].src, self.pg2.local_ip4) - self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[1].ip4) - self.assertEqual(rx[UDP].dport, 48879) - # the UDP source port is a random value for hashing - self.assertEqual(rx[VXLAN].gpid, 441) - self.assertEqual(rx[VXLAN].vni, 101) - self.assertTrue(rx[VXLAN].flags.G) - self.assertTrue(rx[VXLAN].flags.Instance) - self.assertTrue(rx[VXLAN].gpflags.A) - self.assertFalse(rx[VXLAN].gpflags.D) - - inner = rx[VXLAN].payload - - self.assertEqual(inner[Ether].src, routed_src_mac) - self.assertEqual(inner[Ether].dst, routed_dst_mac) - self.assertEqual(inner[IPv6].src, ep.ip6.address) - self.assertEqual(inner[IPv6].dst, l['ip6']) - - self.logger.info(self.vapi.cli("sh gbp endpoint")) - for l in learnt: - self.wait_for_ep_timeout(ip=l['ip']) - - # - # Static sends to unknown EP with no route - # - p = (Ether(src=ep.mac, dst=self.loop0.local_mac) / - IP(dst="10.0.0.99", src=ep.ip4.address) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - - self.send_and_assert_no_replies(self.pg0, [p]) - - # - # Add a route to static EP's v4 and v6 subnet - # - se_10_24 = VppGbpSubnet( - self, rd1, "10.0.0.0", 24, - VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_TRANSPORT) - se_10_24.add_vpp_config() - - # - # static pings router - # - p = (Ether(src=ep.mac, dst=self.loop0.local_mac) / - IP(dst=epg_220.bvi_ip4.address, src=ep.ip4.address) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - - self.send_and_expect(self.pg0, p * NUM_PKTS, self.pg0) - - p = (Ether(src=ep.mac, dst=self.loop0.local_mac) / - IPv6(dst=epg_220.bvi_ip6.address, src=ep.ip6.address) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - - self.send_and_expect(self.pg0, p * NUM_PKTS, self.pg0) - - # - # packets to address in the subnet are sent on the uu-fwd - # - p = (Ether(src=ep.mac, dst=self.loop0.local_mac) / - IP(dst="10.0.0.99", src=ep.ip4.address) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - - rxs = self.send_and_expect(self.pg0, [p], self.pg4) - for rx in rxs: - self.assertEqual(rx[IP].src, self.pg4.local_ip4) - self.assertEqual(rx[IP].dst, self.pg4.remote_ip4) - self.assertEqual(rx[UDP].dport, 48879) - # the UDP source port is a random value for hashing - self.assertEqual(rx[VXLAN].gpid, 441) - self.assertEqual(rx[VXLAN].vni, 114) - self.assertTrue(rx[VXLAN].flags.G) - self.assertTrue(rx[VXLAN].flags.Instance) - # policy is not applied to packets sent to the uu-fwd interfaces - self.assertFalse(rx[VXLAN].gpflags.A) - self.assertFalse(rx[VXLAN].gpflags.D) - - # - # learn some remote IPv4 EPs - # - for ii, l in enumerate(learnt): - # a packet with an sclass from a known EPG - # arriving on an unknown TEP - p = (Ether(src=self.pg2.remote_mac, - dst=self.pg2.local_mac) / - IP(src=self.pg2.remote_hosts[2].ip4, - dst=self.pg2.local_ip4) / - UDP(sport=1234, dport=48879) / - VXLAN(vni=101, gpid=441, flags=0x88) / - Ether(src=l['mac'], dst="00:00:00:11:11:11") / - IP(src=l['ip'], dst=ep.ip4.address) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - - rx = self.send_and_expect(self.pg2, [p], self.pg0) - - # the new TEP - tep1_sw_if_index = find_vxlan_gbp_tunnel( - self, - self.pg2.local_ip4, - self.pg2.remote_hosts[2].ip4, - vx_tun_l3.vni) - self.assertNotEqual(INDEX_INVALID, tep1_sw_if_index) - - # endpoint learnt via the parent GBP-vxlan interface - self.assertTrue(find_gbp_endpoint(self, - vx_tun_l3._sw_if_index, - ip=l['ip'])) - - # - # Add a remote endpoint from the API - # - rep_88 = VppGbpEndpoint(self, vx_tun_l3, - epg_220, None, - "10.0.0.88", "11.0.0.88", - "2001:10::88", "3001::88", - ep_flags.GBP_API_ENDPOINT_FLAG_REMOTE, - self.pg2.local_ip4, - self.pg2.remote_hosts[2].ip4, - mac=None) - rep_88.add_vpp_config() - - # - # Add a remote endpoint from the API that matches an existing one - # this is a lower priority, hence the packet is sent to the DP leanrt - # TEP - # - rep_2 = VppGbpEndpoint(self, vx_tun_l3, - epg_220, None, - learnt[0]['ip'], "11.0.0.101", - learnt[0]['ip6'], "3001::101", - ep_flags.GBP_API_ENDPOINT_FLAG_REMOTE, - self.pg2.local_ip4, - self.pg2.remote_hosts[1].ip4, - mac=None) - rep_2.add_vpp_config() - - # - # Add a route to the learned EP's v4 subnet - # packets should be send on the v4/v6 uu=fwd interface resp. - # - se_10_1_24 = VppGbpSubnet( - self, rd1, "10.0.1.0", 24, - VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_TRANSPORT) - se_10_1_24.add_vpp_config() - - self.logger.info(self.vapi.cli("show gbp endpoint")) - - ips = ["10.0.0.88", learnt[0]['ip']] - for ip in ips: - p = (Ether(src=ep.mac, dst=self.loop0.local_mac) / - IP(dst=ip, src=ep.ip4.address) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - - rxs = self.send_and_expect(self.pg0, p * NUM_PKTS, self.pg2) - - for rx in rxs: - self.assertEqual(rx[IP].src, self.pg2.local_ip4) - self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[2].ip4) - self.assertEqual(rx[UDP].dport, 48879) - # the UDP source port is a random value for hashing - self.assertEqual(rx[VXLAN].gpid, 441) - self.assertEqual(rx[VXLAN].vni, 101) - self.assertTrue(rx[VXLAN].flags.G) - self.assertTrue(rx[VXLAN].flags.Instance) - self.assertTrue(rx[VXLAN].gpflags.A) - self.assertFalse(rx[VXLAN].gpflags.D) - - inner = rx[VXLAN].payload - - self.assertEqual(inner[Ether].src, routed_src_mac) - self.assertEqual(inner[Ether].dst, routed_dst_mac) - self.assertEqual(inner[IP].src, ep.ip4.address) - self.assertEqual(inner[IP].dst, ip) - - # - # remove the API remote EPs, only API sourced is gone, the DP - # learnt one remains - # - rep_88.remove_vpp_config() - rep_2.remove_vpp_config() - - self.assertTrue(find_gbp_endpoint(self, ip=rep_2.ip4.address)) - - p = (Ether(src=ep.mac, dst=self.loop0.local_mac) / - IP(src=ep.ip4.address, dst=rep_2.ip4.address) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - rxs = self.send_and_expect(self.pg0, [p], self.pg2) - - self.assertFalse(find_gbp_endpoint(self, ip=rep_88.ip4.address)) - - p = (Ether(src=ep.mac, dst=self.loop0.local_mac) / - IP(src=ep.ip4.address, dst=rep_88.ip4.address) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - rxs = self.send_and_expect(self.pg0, [p], self.pg4) - - # - # to appease the testcase we cannot have the registered EP still - # present (because it's DP learnt) when the TC ends so wait until - # it is removed - # - self.wait_for_ep_timeout(ip=rep_88.ip4.address) - self.wait_for_ep_timeout(ip=rep_2.ip4.address) - - # - # Same as above, learn a remote EP via CP and DP - # this time remove the DP one first. expect the CP data to remain - # - rep_3 = VppGbpEndpoint(self, vx_tun_l3, - epg_220, None, - "10.0.1.4", "11.0.0.103", - "2001::10:3", "3001::103", - ep_flags.GBP_API_ENDPOINT_FLAG_REMOTE, - self.pg2.local_ip4, - self.pg2.remote_hosts[1].ip4, - mac=None) - rep_3.add_vpp_config() - - p = (Ether(src=self.pg2.remote_mac, - dst=self.pg2.local_mac) / - IP(src=self.pg2.remote_hosts[2].ip4, - dst=self.pg2.local_ip4) / - UDP(sport=1234, dport=48879) / - VXLAN(vni=101, gpid=441, flags=0x88) / - Ether(src=l['mac'], dst="00:00:00:11:11:11") / - IP(src="10.0.1.4", dst=ep.ip4.address) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - rxs = self.send_and_expect(self.pg2, p * NUM_PKTS, self.pg0) - - self.assertTrue(find_gbp_endpoint(self, - vx_tun_l3._sw_if_index, - ip=rep_3.ip4.address, - tep=[self.pg2.local_ip4, - self.pg2.remote_hosts[2].ip4])) - - p = (Ether(src=ep.mac, dst=self.loop0.local_mac) / - IP(dst="10.0.1.4", src=ep.ip4.address) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - rxs = self.send_and_expect(self.pg0, p * NUM_PKTS, self.pg2) - - # host 2 is the DP learned TEP - for rx in rxs: - self.assertEqual(rx[IP].src, self.pg2.local_ip4) - self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[2].ip4) - - self.wait_for_ep_timeout(ip=rep_3.ip4.address, - tep=[self.pg2.local_ip4, - self.pg2.remote_hosts[2].ip4]) - - rxs = self.send_and_expect(self.pg0, p * NUM_PKTS, self.pg2) - - # host 1 is the CP learned TEP - for rx in rxs: - self.assertEqual(rx[IP].src, self.pg2.local_ip4) - self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[1].ip4) - - # - # shutdown with learnt endpoint present - # - p = (Ether(src=self.pg2.remote_mac, - dst=self.pg2.local_mac) / - IP(src=self.pg2.remote_hosts[1].ip4, - dst=self.pg2.local_ip4) / - UDP(sport=1234, dport=48879) / - VXLAN(vni=101, gpid=441, flags=0x88) / - Ether(src=l['mac'], dst="00:00:00:11:11:11") / - IP(src=learnt[1]['ip'], dst=ep.ip4.address) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - - rx = self.send_and_expect(self.pg2, [p], self.pg0) - - # endpoint learnt via the parent GBP-vxlan interface - self.assertTrue(find_gbp_endpoint(self, - vx_tun_l3._sw_if_index, - ip=l['ip'])) - - # - # TODO - # remote endpoint becomes local - # - self.pg2.unconfig_ip4() - self.pg3.unconfig_ip4() - self.pg4.unconfig_ip4() - - def test_gbp_redirect(self): - """ GBP Endpoint Redirect """ - - self.vapi.cli("set logging class gbp level debug") - - ep_flags = VppEnum.vl_api_gbp_endpoint_flags_t - routed_dst_mac = "00:0c:0c:0c:0c:0c" - routed_src_mac = "00:22:bd:f8:19:ff" - - learnt = [{'mac': '00:00:11:11:11:02', - 'ip': '10.0.1.2', - 'ip6': '2001:10::2'}, - {'mac': '00:00:11:11:11:03', - 'ip': '10.0.1.3', - 'ip6': '2001:10::3'}] - - # - # IP tables - # - t4 = VppIpTable(self, 1) - t4.add_vpp_config() - t6 = VppIpTable(self, 1, True) - t6.add_vpp_config() - - rd1 = VppGbpRouteDomain(self, 2, 402, t4, t6) - rd1.add_vpp_config() - - self.loop0.set_mac(self.router_mac) - - # - # Bind the BVI to the RD - # - VppIpInterfaceBind(self, self.loop0, t4).add_vpp_config() - VppIpInterfaceBind(self, self.loop0, t6).add_vpp_config() - - # - # Pg7 hosts a BD's UU-fwd - # - self.pg7.config_ip4() - self.pg7.resolve_arp() - - # - # a GBP bridge domains for the EPs - # - bd1 = VppBridgeDomain(self, 1) - bd1.add_vpp_config() - gbd1 = VppGbpBridgeDomain(self, bd1, rd1, self.loop0) - gbd1.add_vpp_config() - - bd2 = VppBridgeDomain(self, 2) - bd2.add_vpp_config() - gbd2 = VppGbpBridgeDomain(self, bd2, rd1, self.loop1) - gbd2.add_vpp_config() - - # ... and has a /32 and /128 applied - ip4_addr = VppIpInterfaceAddress(self, gbd1.bvi, "10.0.0.128", 32) - ip4_addr.add_vpp_config() - ip6_addr = VppIpInterfaceAddress(self, gbd1.bvi, "2001:10::128", 128) - ip6_addr.add_vpp_config() - ip4_addr = VppIpInterfaceAddress(self, gbd2.bvi, "10.0.1.128", 32) - ip4_addr.add_vpp_config() - ip6_addr = VppIpInterfaceAddress(self, gbd2.bvi, "2001:11::128", 128) - ip6_addr.add_vpp_config() - - # - # The Endpoint-groups in which we are learning endpoints - # - epg_220 = VppGbpEndpointGroup(self, 220, 440, rd1, gbd1, - None, gbd1.bvi, - "10.0.0.128", - "2001:10::128", - VppGbpEndpointRetention(2)) - epg_220.add_vpp_config() - epg_221 = VppGbpEndpointGroup(self, 221, 441, rd1, gbd2, - None, gbd2.bvi, - "10.0.1.128", - "2001:11::128", - VppGbpEndpointRetention(2)) - epg_221.add_vpp_config() - epg_222 = VppGbpEndpointGroup(self, 222, 442, rd1, gbd1, - None, gbd1.bvi, - "10.0.2.128", - "2001:12::128", - VppGbpEndpointRetention(2)) - epg_222.add_vpp_config() - - # - # a GBP bridge domains for the SEPs - # - bd_uu1 = VppVxlanGbpTunnel(self, self.pg7.local_ip4, - self.pg7.remote_ip4, 116) - bd_uu1.add_vpp_config() - bd_uu2 = VppVxlanGbpTunnel(self, self.pg7.local_ip4, - self.pg7.remote_ip4, 117) - bd_uu2.add_vpp_config() - - bd3 = VppBridgeDomain(self, 3) - bd3.add_vpp_config() - gbd3 = VppGbpBridgeDomain(self, bd3, rd1, self.loop2, - bd_uu1, learn=False) - gbd3.add_vpp_config() - bd4 = VppBridgeDomain(self, 4) - bd4.add_vpp_config() - gbd4 = VppGbpBridgeDomain(self, bd4, rd1, self.loop3, - bd_uu2, learn=False) - gbd4.add_vpp_config() - - # - # EPGs in which the service endpoints exist - # - epg_320 = VppGbpEndpointGroup(self, 320, 550, rd1, gbd3, - None, gbd1.bvi, - "12.0.0.128", - "4001:10::128", - VppGbpEndpointRetention(2)) - epg_320.add_vpp_config() - epg_321 = VppGbpEndpointGroup(self, 321, 551, rd1, gbd4, - None, gbd2.bvi, - "12.0.1.128", - "4001:11::128", - VppGbpEndpointRetention(2)) - epg_321.add_vpp_config() - - # - # three local endpoints - # - ep1 = VppGbpEndpoint(self, self.pg0, - epg_220, None, - "10.0.0.1", "11.0.0.1", - "2001:10::1", "3001:10::1") - ep1.add_vpp_config() - ep2 = VppGbpEndpoint(self, self.pg1, - epg_221, None, - "10.0.1.1", "11.0.1.1", - "2001:11::1", "3001:11::1") - ep2.add_vpp_config() - ep3 = VppGbpEndpoint(self, self.pg2, - epg_222, None, - "10.0.2.2", "11.0.2.2", - "2001:12::1", "3001:12::1") - ep3.add_vpp_config() - - # - # service endpoints - # - sep1 = VppGbpEndpoint(self, self.pg3, - epg_320, None, - "12.0.0.1", "13.0.0.1", - "4001:10::1", "5001:10::1") - sep1.add_vpp_config() - sep2 = VppGbpEndpoint(self, self.pg4, - epg_320, None, - "12.0.0.2", "13.0.0.2", - "4001:10::2", "5001:10::2") - sep2.add_vpp_config() - sep3 = VppGbpEndpoint(self, self.pg5, - epg_321, None, - "12.0.1.1", "13.0.1.1", - "4001:11::1", "5001:11::1") - sep3.add_vpp_config() - # this EP is not installed immediately - sep4 = VppGbpEndpoint(self, self.pg6, - epg_321, None, - "12.0.1.2", "13.0.1.2", - "4001:11::2", "5001:11::2") - - # - # an L2 switch packet between local EPs in different EPGs - # different dest ports on each so the are LB hashed differently - # - p4 = [(Ether(src=ep1.mac, dst=ep3.mac) / - IP(src=ep1.ip4.address, dst=ep3.ip4.address) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)), - (Ether(src=ep3.mac, dst=ep1.mac) / - IP(src=ep3.ip4.address, dst=ep1.ip4.address) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100))] - p6 = [(Ether(src=ep1.mac, dst=ep3.mac) / - IPv6(src=ep1.ip6.address, dst=ep3.ip6.address) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)), - (Ether(src=ep3.mac, dst=ep1.mac) / - IPv6(src=ep3.ip6.address, dst=ep1.ip6.address) / - UDP(sport=1234, dport=1230) / - Raw('\xa5' * 100))] - - # should be dropped since no contract yet - self.send_and_assert_no_replies(self.pg0, [p4[0]]) - self.send_and_assert_no_replies(self.pg0, [p6[0]]) - - # - # Add a contract with a rule to load-balance redirect via SEP1 and SEP2 - # one of the next-hops is via an EP that is not known - # - acl = VppGbpAcl(self) - rule4 = acl.create_rule(permit_deny=1, proto=17) - rule6 = acl.create_rule(is_ipv6=1, permit_deny=1, proto=17) - acl_index = acl.add_vpp_config([rule4, rule6]) - - # - # test the src-ip hash mode - # - c1 = VppGbpContract( - self, 402, epg_220.sclass, epg_222.sclass, acl_index, - [VppGbpContractRule( - VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT, - VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP, - [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd, - sep1.ip4, sep1.epg.rd), - VppGbpContractNextHop(sep2.vmac, sep2.epg.bd, - sep2.ip4, sep2.epg.rd)]), - VppGbpContractRule( - VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT, - VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP, - [VppGbpContractNextHop(sep3.vmac, sep3.epg.bd, - sep3.ip6, sep3.epg.rd), - VppGbpContractNextHop(sep4.vmac, sep4.epg.bd, - sep4.ip6, sep4.epg.rd)])], - [ETH_P_IP, ETH_P_IPV6]) - c1.add_vpp_config() - - c2 = VppGbpContract( - self, 402, epg_222.sclass, epg_220.sclass, acl_index, - [VppGbpContractRule( - VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT, - VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP, - [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd, - sep1.ip4, sep1.epg.rd), - VppGbpContractNextHop(sep2.vmac, sep2.epg.bd, - sep2.ip4, sep2.epg.rd)]), - VppGbpContractRule( - VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT, - VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP, - [VppGbpContractNextHop(sep3.vmac, sep3.epg.bd, - sep3.ip6, sep3.epg.rd), - VppGbpContractNextHop(sep4.vmac, sep4.epg.bd, - sep4.ip6, sep4.epg.rd)])], - [ETH_P_IP, ETH_P_IPV6]) - c2.add_vpp_config() - - # - # send again with the contract preset, now packets arrive - # at SEP1 or SEP2 depending on the hashing - # - rxs = self.send_and_expect(self.pg0, p4[0] * 17, sep1.itf) - - for rx in rxs: - self.assertEqual(rx[Ether].src, routed_src_mac) - self.assertEqual(rx[Ether].dst, sep1.mac) - self.assertEqual(rx[IP].src, ep1.ip4.address) - self.assertEqual(rx[IP].dst, ep3.ip4.address) - - rxs = self.send_and_expect(self.pg2, p4[1] * 17, sep2.itf) - - for rx in rxs: - self.assertEqual(rx[Ether].src, routed_src_mac) - self.assertEqual(rx[Ether].dst, sep2.mac) - self.assertEqual(rx[IP].src, ep3.ip4.address) - self.assertEqual(rx[IP].dst, ep1.ip4.address) - - rxs = self.send_and_expect(self.pg0, p6[0] * 17, self.pg7) - - for rx in rxs: - self.assertEqual(rx[Ether].src, self.pg7.local_mac) - self.assertEqual(rx[Ether].dst, self.pg7.remote_mac) - self.assertEqual(rx[IP].src, self.pg7.local_ip4) - self.assertEqual(rx[IP].dst, self.pg7.remote_ip4) - self.assertEqual(rx[VXLAN].vni, 117) - self.assertTrue(rx[VXLAN].flags.G) - self.assertTrue(rx[VXLAN].flags.Instance) - # redirect policy has been applied - self.assertTrue(rx[VXLAN].gpflags.A) - self.assertFalse(rx[VXLAN].gpflags.D) - - inner = rx[VXLAN].payload - - self.assertEqual(inner[Ether].src, routed_src_mac) - self.assertEqual(inner[Ether].dst, sep4.mac) - self.assertEqual(inner[IPv6].src, ep1.ip6.address) - self.assertEqual(inner[IPv6].dst, ep3.ip6.address) - - rxs = self.send_and_expect(self.pg2, p6[1] * 17, sep3.itf) - - for rx in rxs: - self.assertEqual(rx[Ether].src, routed_src_mac) - self.assertEqual(rx[Ether].dst, sep3.mac) - self.assertEqual(rx[IPv6].src, ep3.ip6.address) - self.assertEqual(rx[IPv6].dst, ep1.ip6.address) - - # - # programme the unknown EP - # - sep4.add_vpp_config() - - rxs = self.send_and_expect(self.pg0, p6[0] * 17, sep4.itf) - - for rx in rxs: - self.assertEqual(rx[Ether].src, routed_src_mac) - self.assertEqual(rx[Ether].dst, sep4.mac) - self.assertEqual(rx[IPv6].src, ep1.ip6.address) - self.assertEqual(rx[IPv6].dst, ep3.ip6.address) - - # - # and revert back to unprogrammed - # - sep4.remove_vpp_config() - - rxs = self.send_and_expect(self.pg0, p6[0] * 17, self.pg7) - - for rx in rxs: - self.assertEqual(rx[Ether].src, self.pg7.local_mac) - self.assertEqual(rx[Ether].dst, self.pg7.remote_mac) - self.assertEqual(rx[IP].src, self.pg7.local_ip4) - self.assertEqual(rx[IP].dst, self.pg7.remote_ip4) - self.assertEqual(rx[VXLAN].vni, 117) - self.assertTrue(rx[VXLAN].flags.G) - self.assertTrue(rx[VXLAN].flags.Instance) - # redirect policy has been applied - self.assertTrue(rx[VXLAN].gpflags.A) - self.assertFalse(rx[VXLAN].gpflags.D) - - inner = rx[VXLAN].payload - - self.assertEqual(inner[Ether].src, routed_src_mac) - self.assertEqual(inner[Ether].dst, sep4.mac) - self.assertEqual(inner[IPv6].src, ep1.ip6.address) - self.assertEqual(inner[IPv6].dst, ep3.ip6.address) - - c1.remove_vpp_config() - c2.remove_vpp_config() - - # - # test the symmetric hash mode - # - c1 = VppGbpContract( - self, 402, epg_220.sclass, epg_222.sclass, acl_index, - [VppGbpContractRule( - VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT, - VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SYMMETRIC, - [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd, - sep1.ip4, sep1.epg.rd), - VppGbpContractNextHop(sep2.vmac, sep2.epg.bd, - sep2.ip4, sep2.epg.rd)]), - VppGbpContractRule( - VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT, - VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SYMMETRIC, - [VppGbpContractNextHop(sep3.vmac, sep3.epg.bd, - sep3.ip6, sep3.epg.rd), - VppGbpContractNextHop(sep4.vmac, sep4.epg.bd, - sep4.ip6, sep4.epg.rd)])], - [ETH_P_IP, ETH_P_IPV6]) - c1.add_vpp_config() - - c2 = VppGbpContract( - self, 402, epg_222.sclass, epg_220.sclass, acl_index, - [VppGbpContractRule( - VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT, - VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SYMMETRIC, - [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd, - sep1.ip4, sep1.epg.rd), - VppGbpContractNextHop(sep2.vmac, sep2.epg.bd, - sep2.ip4, sep2.epg.rd)]), - VppGbpContractRule( - VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT, - VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SYMMETRIC, - [VppGbpContractNextHop(sep3.vmac, sep3.epg.bd, - sep3.ip6, sep3.epg.rd), - VppGbpContractNextHop(sep4.vmac, sep4.epg.bd, - sep4.ip6, sep4.epg.rd)])], - [ETH_P_IP, ETH_P_IPV6]) - c2.add_vpp_config() - - # - # send again with the contract preset, now packets arrive - # at SEP1 for both directions - # - rxs = self.send_and_expect(self.pg0, p4[0] * 17, sep1.itf) - - for rx in rxs: - self.assertEqual(rx[Ether].src, routed_src_mac) - self.assertEqual(rx[Ether].dst, sep1.mac) - self.assertEqual(rx[IP].src, ep1.ip4.address) - self.assertEqual(rx[IP].dst, ep3.ip4.address) - - rxs = self.send_and_expect(self.pg2, p4[1] * 17, sep1.itf) - - for rx in rxs: - self.assertEqual(rx[Ether].src, routed_src_mac) - self.assertEqual(rx[Ether].dst, sep1.mac) - self.assertEqual(rx[IP].src, ep3.ip4.address) - self.assertEqual(rx[IP].dst, ep1.ip4.address) - - # - # programme the unknown EP for the L3 tests - # - sep4.add_vpp_config() - - # - # an L3 switch packet between local EPs in different EPGs - # different dest ports on each so the are LB hashed differently - # - p4 = [(Ether(src=ep1.mac, dst=str(self.router_mac)) / - IP(src=ep1.ip4.address, dst=ep2.ip4.address) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)), - (Ether(src=ep2.mac, dst=str(self.router_mac)) / - IP(src=ep2.ip4.address, dst=ep1.ip4.address) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100))] - p6 = [(Ether(src=ep1.mac, dst=str(self.router_mac)) / - IPv6(src=ep1.ip6.address, dst=ep2.ip6.address) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)), - (Ether(src=ep2.mac, dst=str(self.router_mac)) / - IPv6(src=ep2.ip6.address, dst=ep1.ip6.address) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100))] - - c3 = VppGbpContract( - self, 402, epg_220.sclass, epg_221.sclass, acl_index, - [VppGbpContractRule( - VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT, - VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SYMMETRIC, - [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd, - sep1.ip4, sep1.epg.rd), - VppGbpContractNextHop(sep2.vmac, sep2.epg.bd, - sep2.ip4, sep2.epg.rd)]), - VppGbpContractRule( - VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT, - VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SYMMETRIC, - [VppGbpContractNextHop(sep3.vmac, sep3.epg.bd, - sep3.ip6, sep3.epg.rd), - VppGbpContractNextHop(sep4.vmac, sep4.epg.bd, - sep4.ip6, sep4.epg.rd)])], - [ETH_P_IP, ETH_P_IPV6]) - c3.add_vpp_config() - - rxs = self.send_and_expect(self.pg0, p4[0] * 17, sep1.itf) - - for rx in rxs: - self.assertEqual(rx[Ether].src, routed_src_mac) - self.assertEqual(rx[Ether].dst, sep1.mac) - self.assertEqual(rx[IP].src, ep1.ip4.address) - self.assertEqual(rx[IP].dst, ep2.ip4.address) - - # - # learn a remote EP in EPG 221 - # packets coming from unknown remote EPs will be leant & redirected - # - vx_tun_l3 = VppGbpVxlanTunnel( - self, 444, rd1.rd_id, - VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L3, - self.pg2.local_ip4) - vx_tun_l3.add_vpp_config() - - c4 = VppGbpContract( - self, 402, epg_221.sclass, epg_220.sclass, acl_index, - [VppGbpContractRule( - VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT, - VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP, - [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd, - sep1.ip4, sep1.epg.rd), - VppGbpContractNextHop(sep2.vmac, sep2.epg.bd, - sep2.ip4, sep2.epg.rd)]), - VppGbpContractRule( - VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT, - VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP, - [VppGbpContractNextHop(sep3.vmac, sep3.epg.bd, - sep3.ip6, sep3.epg.rd), - VppGbpContractNextHop(sep4.vmac, sep4.epg.bd, - sep4.ip6, sep4.epg.rd)])], - [ETH_P_IP, ETH_P_IPV6]) - c4.add_vpp_config() - - p = (Ether(src=self.pg7.remote_mac, - dst=self.pg7.local_mac) / - IP(src=self.pg7.remote_ip4, - dst=self.pg7.local_ip4) / - UDP(sport=1234, dport=48879) / - VXLAN(vni=444, gpid=441, flags=0x88) / - Ether(src="00:22:22:22:22:33", dst=str(self.router_mac)) / - IP(src="10.0.0.88", dst=ep1.ip4.address) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - - # unknown remote EP to local EP redirected - rxs = self.send_and_expect(self.pg7, [p], sep1.itf) - - for rx in rxs: - self.assertEqual(rx[Ether].src, routed_src_mac) - self.assertEqual(rx[Ether].dst, sep1.mac) - self.assertEqual(rx[IP].src, "10.0.0.88") - self.assertEqual(rx[IP].dst, ep1.ip4.address) - - # endpoint learnt via the parent GBP-vxlan interface - self.assertTrue(find_gbp_endpoint(self, - vx_tun_l3._sw_if_index, - ip="10.0.0.88")) - - p = (Ether(src=self.pg7.remote_mac, - dst=self.pg7.local_mac) / - IP(src=self.pg7.remote_ip4, - dst=self.pg7.local_ip4) / - UDP(sport=1234, dport=48879) / - VXLAN(vni=444, gpid=441, flags=0x88) / - Ether(src="00:22:22:22:22:33", dst=str(self.router_mac)) / - IPv6(src="2001:10::88", dst=ep1.ip6.address) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - - # unknown remote EP to local EP redirected (ipv6) - rxs = self.send_and_expect(self.pg7, [p], sep3.itf) - - for rx in rxs: - self.assertEqual(rx[Ether].src, routed_src_mac) - self.assertEqual(rx[Ether].dst, sep3.mac) - self.assertEqual(rx[IPv6].src, "2001:10::88") - self.assertEqual(rx[IPv6].dst, ep1.ip6.address) - - # endpoint learnt via the parent GBP-vxlan interface - self.assertTrue(find_gbp_endpoint(self, - vx_tun_l3._sw_if_index, - ip="2001:10::88")) - - # - # L3 switch from local to remote EP - # - p4 = [(Ether(src=ep1.mac, dst=str(self.router_mac)) / - IP(src=ep1.ip4.address, dst="10.0.0.88") / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100))] - p6 = [(Ether(src=ep1.mac, dst=str(self.router_mac)) / - IPv6(src=ep1.ip6.address, dst="2001:10::88") / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100))] - - rxs = self.send_and_expect(self.pg0, p4[0] * 17, sep1.itf) - - for rx in rxs: - self.assertEqual(rx[Ether].src, routed_src_mac) - self.assertEqual(rx[Ether].dst, sep1.mac) - self.assertEqual(rx[IP].src, ep1.ip4.address) - self.assertEqual(rx[IP].dst, "10.0.0.88") - - rxs = self.send_and_expect(self.pg0, p6[0] * 17, sep4.itf) - - for rx in rxs: - self.assertEqual(rx[Ether].src, routed_src_mac) - self.assertEqual(rx[Ether].dst, sep4.mac) - self.assertEqual(rx[IPv6].src, ep1.ip6.address) - self.assertEqual(rx[IPv6].dst, "2001:10::88") - - # - # test the dst-ip hash mode - # - c5 = VppGbpContract( - self, 402, epg_220.sclass, epg_221.sclass, acl_index, - [VppGbpContractRule( - VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT, - VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_DST_IP, - [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd, - sep1.ip4, sep1.epg.rd), - VppGbpContractNextHop(sep2.vmac, sep2.epg.bd, - sep2.ip4, sep2.epg.rd)]), - VppGbpContractRule( - VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT, - VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_DST_IP, - [VppGbpContractNextHop(sep3.vmac, sep3.epg.bd, - sep3.ip6, sep3.epg.rd), - VppGbpContractNextHop(sep4.vmac, sep4.epg.bd, - sep4.ip6, sep4.epg.rd)])], - [ETH_P_IP, ETH_P_IPV6]) - c5.add_vpp_config() - - rxs = self.send_and_expect(self.pg0, p4[0] * 17, sep1.itf) - - for rx in rxs: - self.assertEqual(rx[Ether].src, routed_src_mac) - self.assertEqual(rx[Ether].dst, sep1.mac) - self.assertEqual(rx[IP].src, ep1.ip4.address) - self.assertEqual(rx[IP].dst, "10.0.0.88") - - rxs = self.send_and_expect(self.pg0, p6[0] * 17, sep3.itf) - - for rx in rxs: - self.assertEqual(rx[Ether].src, routed_src_mac) - self.assertEqual(rx[Ether].dst, sep3.mac) - self.assertEqual(rx[IPv6].src, ep1.ip6.address) - self.assertEqual(rx[IPv6].dst, "2001:10::88") - - # - # a programmed remote SEP in EPG 320 - # - - # gbp vxlan tunnel for the remote SEP - vx_tun_l3_sep = VppGbpVxlanTunnel( - self, 555, rd1.rd_id, - VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L3, - self.pg2.local_ip4) - vx_tun_l3_sep.add_vpp_config() - - # remote SEP - sep5 = VppGbpEndpoint(self, vx_tun_l3_sep, - epg_320, None, - "12.0.0.10", "13.0.0.10", - "4001:10::10", "5001:10::10", - ep_flags.GBP_API_ENDPOINT_FLAG_REMOTE, - self.pg7.local_ip4, - self.pg7.remote_ip4, - mac=None) - sep5.add_vpp_config() - - # - # local l3out redirect tests - # - - # add local l3out - # the external bd - self.loop4.set_mac(self.router_mac) - VppIpInterfaceBind(self, self.loop4, t4).add_vpp_config() - VppIpInterfaceBind(self, self.loop4, t6).add_vpp_config() - ebd = VppBridgeDomain(self, 100) - ebd.add_vpp_config() - gebd = VppGbpBridgeDomain(self, ebd, rd1, self.loop4, None, None) - gebd.add_vpp_config() - # the external epg - eepg = VppGbpEndpointGroup(self, 888, 765, rd1, gebd, - None, gebd.bvi, - "10.1.0.128", - "2001:10:1::128", - VppGbpEndpointRetention(2)) - eepg.add_vpp_config() - # add subnets to BVI - VppIpInterfaceAddress( - self, - gebd.bvi, - "10.1.0.128", - 24).add_vpp_config() - VppIpInterfaceAddress( - self, - gebd.bvi, - "2001:10:1::128", - 64).add_vpp_config() - # ... which are L3-out subnets - VppGbpSubnet(self, rd1, "10.1.0.0", 24, - VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT, - sclass=765).add_vpp_config() - VppGbpSubnet(self, rd1, "2001:10:1::128", 64, - VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT, - sclass=765).add_vpp_config() - # external endpoints - VppL2Vtr(self, self.vlan_100, L2_VTR_OP.L2_POP_1).add_vpp_config() - eep1 = VppGbpEndpoint(self, self.vlan_100, eepg, None, "10.1.0.1", - "11.1.0.1", "2001:10:1::1", "3001:10:1::1", - ep_flags.GBP_API_ENDPOINT_FLAG_EXTERNAL) - eep1.add_vpp_config() - VppL2Vtr(self, self.vlan_101, L2_VTR_OP.L2_POP_1).add_vpp_config() - eep2 = VppGbpEndpoint(self, self.vlan_101, eepg, None, "10.1.0.2", - "11.1.0.2", "2001:10:1::2", "3001:10:1::2", - ep_flags.GBP_API_ENDPOINT_FLAG_EXTERNAL) - eep2.add_vpp_config() - - # external subnets reachable though eep1 and eep2 respectively - VppIpRoute(self, "10.220.0.0", 24, - [VppRoutePath(eep1.ip4.address, eep1.epg.bvi.sw_if_index)], - table_id=t4.table_id).add_vpp_config() - VppGbpSubnet(self, rd1, "10.220.0.0", 24, - VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT, - sclass=4220).add_vpp_config() - VppIpRoute(self, "10:220::", 64, - [VppRoutePath(eep1.ip6.address, eep1.epg.bvi.sw_if_index)], - table_id=t6.table_id).add_vpp_config() - VppGbpSubnet(self, rd1, "10:220::", 64, - VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT, - sclass=4220).add_vpp_config() - VppIpRoute(self, "10.221.0.0", 24, - [VppRoutePath(eep2.ip4.address, eep2.epg.bvi.sw_if_index)], - table_id=t4.table_id).add_vpp_config() - VppGbpSubnet(self, rd1, "10.221.0.0", 24, - VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT, - sclass=4221).add_vpp_config() - VppIpRoute(self, "10:221::", 64, - [VppRoutePath(eep2.ip6.address, eep2.epg.bvi.sw_if_index)], - table_id=t6.table_id).add_vpp_config() - VppGbpSubnet(self, rd1, "10:221::", 64, - VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT, - sclass=4221).add_vpp_config() - - # - # l3out redirect to remote (known, then unknown) SEP - # - - # packets from 1 external subnet to the other - p = [(Ether(src=eep1.mac, dst=self.router_mac) / - Dot1Q(vlan=100) / - IP(src="10.220.0.17", dst="10.221.0.65") / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)), - (Ether(src=eep1.mac, dst=self.router_mac) / - Dot1Q(vlan=100) / - IPv6(src="10:220::17", dst="10:221::65") / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100))] - - # packets should be dropped in absence of contract - self.send_and_assert_no_replies(self.pg0, p) - - # contract redirecting to sep5 - VppGbpContract( - self, 402, 4220, 4221, acl_index, - [VppGbpContractRule( - VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT, - VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_DST_IP, - [VppGbpContractNextHop(sep5.vmac, sep5.epg.bd, - sep5.ip4, sep5.epg.rd)]), - VppGbpContractRule( - VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT, - VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_DST_IP, - [VppGbpContractNextHop(sep5.vmac, sep5.epg.bd, - sep5.ip6, sep5.epg.rd)])], - [ETH_P_IP, ETH_P_IPV6]).add_vpp_config() - - rxs = self.send_and_expect(self.pg0, p, self.pg7) - - for rx, tx in zip(rxs, p): - self.assertEqual(rx[Ether].src, self.pg7.local_mac) - self.assertEqual(rx[Ether].dst, self.pg7.remote_mac) - self.assertEqual(rx[IP].src, self.pg7.local_ip4) - self.assertEqual(rx[IP].dst, self.pg7.remote_ip4) - # this should use the programmed remote leaf TEP - self.assertEqual(rx[VXLAN].vni, 555) - self.assertEqual(rx[VXLAN].gpid, 4220) - self.assertTrue(rx[VXLAN].flags.G) - self.assertTrue(rx[VXLAN].flags.Instance) - # redirect policy has been applied - self.assertTrue(rx[VXLAN].gpflags.A) - self.assertTrue(rx[VXLAN].gpflags.D) - rxip = rx[VXLAN][Ether].payload - txip = tx[Dot1Q].payload - self.assertEqual(rxip.src, txip.src) - self.assertEqual(rxip.dst, txip.dst) - - # remote SEP: it is now an unknown remote SEP and should go - # to spine proxy - sep5.remove_vpp_config() - - rxs = self.send_and_expect(self.pg0, p, self.pg7) - - for rx, tx in zip(rxs, p): - self.assertEqual(rx[Ether].src, self.pg7.local_mac) - self.assertEqual(rx[Ether].dst, self.pg7.remote_mac) - self.assertEqual(rx[IP].src, self.pg7.local_ip4) - self.assertEqual(rx[IP].dst, self.pg7.remote_ip4) - # this should use the spine proxy TEP - self.assertEqual(rx[VXLAN].vni, epg_320.bd.uu_fwd.vni) - self.assertEqual(rx[VXLAN].gpid, 4220) - self.assertTrue(rx[VXLAN].flags.G) - self.assertTrue(rx[VXLAN].flags.Instance) - # redirect policy has been applied - self.assertTrue(rx[VXLAN].gpflags.A) - self.assertTrue(rx[VXLAN].gpflags.D) - rxip = rx[VXLAN][Ether].payload - txip = tx[Dot1Q].payload - self.assertEqual(rxip.src, txip.src) - self.assertEqual(rxip.dst, txip.dst) - - # - # l3out redirect to local SEP - # - - # change the contract between l3out to redirect to local SEPs - # instead of remote SEP - VppGbpContract( - self, 402, 4220, 4221, acl_index, - [VppGbpContractRule( - VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT, - VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_DST_IP, - [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd, - sep1.ip4, sep1.epg.rd)]), - VppGbpContractRule( - VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT, - VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_DST_IP, - [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd, - sep1.ip6, sep1.epg.rd)])], - [ETH_P_IP, ETH_P_IPV6]).add_vpp_config() - - rxs = self.send_and_expect(self.pg0, p, sep1.itf) - for rx, tx in zip(rxs, p): - self.assertEqual(rx[Ether].src, routed_src_mac) - self.assertEqual(rx[Ether].dst, sep1.mac) - rxip = rx[Ether].payload - txip = tx[Ether].payload - self.assertEqual(rxip.src, txip.src) - self.assertEqual(rxip.dst, txip.dst) - - # - # redirect remote EP to remote (known then unknown) SEP - # - - # remote SEP known again - sep5.add_vpp_config() - - # contract to redirect to learnt SEP - VppGbpContract( - self, 402, epg_221.sclass, epg_222.sclass, acl_index, - [VppGbpContractRule( - VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT, - VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_DST_IP, - [VppGbpContractNextHop(sep5.vmac, sep5.epg.bd, - sep5.ip4, sep5.epg.rd)]), - VppGbpContractRule( - VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT, - VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_DST_IP, - [VppGbpContractNextHop(sep5.vmac, sep5.epg.bd, - sep5.ip6, sep5.epg.rd)])], - [ETH_P_IP, ETH_P_IPV6]).add_vpp_config() - - # packets from unknown EP 221 to known EP in EPG 222 - # should be redirected to known remote SEP - base = (Ether(src=self.pg7.remote_mac, dst=self.pg7.local_mac) / - IP(src=self.pg7.remote_ip4, dst=self.pg7.local_ip4) / - UDP(sport=1234, dport=48879) / - VXLAN(vni=444, gpid=441, flags=0x88) / - Ether(src="00:22:22:22:22:44", dst=str(self.router_mac))) - p = [(base / - IP(src="10.0.1.100", dst=ep3.ip4.address) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)), - (base / - IPv6(src="2001:10::100", dst=ep3.ip6.address) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100))] - - # unknown remote EP to local EP redirected to known remote SEP - rxs = self.send_and_expect(self.pg7, p, self.pg7) - - for rx, tx in zip(rxs, p): - self.assertEqual(rx[Ether].src, self.pg7.local_mac) - self.assertEqual(rx[Ether].dst, self.pg7.remote_mac) - self.assertEqual(rx[IP].src, self.pg7.local_ip4) - self.assertEqual(rx[IP].dst, self.pg7.remote_ip4) - # this should use the programmed remote leaf TEP - self.assertEqual(rx[VXLAN].vni, 555) - self.assertEqual(rx[VXLAN].gpid, epg_221.sclass) - self.assertTrue(rx[VXLAN].flags.G) - self.assertTrue(rx[VXLAN].flags.Instance) - # redirect policy has been applied - self.assertTrue(rx[VXLAN].gpflags.A) - self.assertFalse(rx[VXLAN].gpflags.D) - rxip = rx[VXLAN][Ether].payload - txip = tx[VXLAN][Ether].payload - self.assertEqual(rxip.src, txip.src) - self.assertEqual(rxip.dst, txip.dst) - - # endpoint learnt via the parent GBP-vxlan interface - self.assertTrue(find_gbp_endpoint(self, - vx_tun_l3._sw_if_index, - ip="10.0.1.100")) - self.assertTrue(find_gbp_endpoint(self, - vx_tun_l3._sw_if_index, - ip="2001:10::100")) - - # remote SEP: it is now an unknown remote SEP and should go - # to spine proxy - sep5.remove_vpp_config() - - # remote EP (coming from spine proxy) to local EP redirected to - # known remote SEP - rxs = self.send_and_expect(self.pg7, p, self.pg7) - - for rx, tx in zip(rxs, p): - self.assertEqual(rx[Ether].src, self.pg7.local_mac) - self.assertEqual(rx[Ether].dst, self.pg7.remote_mac) - self.assertEqual(rx[IP].src, self.pg7.local_ip4) - self.assertEqual(rx[IP].dst, self.pg7.remote_ip4) - # this should use the spine proxy TEP - self.assertEqual(rx[VXLAN].vni, epg_320.bd.uu_fwd.vni) - self.assertEqual(rx[VXLAN].gpid, epg_221.sclass) - self.assertTrue(rx[VXLAN].flags.G) - self.assertTrue(rx[VXLAN].flags.Instance) - # redirect policy has been applied - self.assertTrue(rx[VXLAN].gpflags.A) - self.assertFalse(rx[VXLAN].gpflags.D) - rxip = rx[VXLAN][Ether].payload - txip = tx[VXLAN][Ether].payload - self.assertEqual(rxip.src, txip.src) - self.assertEqual(rxip.dst, txip.dst) - - # - # cleanup - # - self.pg7.unconfig_ip4() - - def test_gbp_l3_out(self): - """ GBP L3 Out """ - - ep_flags = VppEnum.vl_api_gbp_endpoint_flags_t - self.vapi.cli("set logging class gbp level debug") - - routed_dst_mac = "00:0c:0c:0c:0c:0c" - routed_src_mac = "00:22:bd:f8:19:ff" - - # - # IP tables - # - t4 = VppIpTable(self, 1) - t4.add_vpp_config() - t6 = VppIpTable(self, 1, True) - t6.add_vpp_config() - - rd1 = VppGbpRouteDomain(self, 2, 55, t4, t6) - rd1.add_vpp_config() - - self.loop0.set_mac(self.router_mac) - - # - # Bind the BVI to the RD - # - VppIpInterfaceBind(self, self.loop0, t4).add_vpp_config() - VppIpInterfaceBind(self, self.loop0, t6).add_vpp_config() - - # - # Pg7 hosts a BD's BUM - # Pg1 some other l3 interface - # - self.pg7.config_ip4() - self.pg7.resolve_arp() - - # - # a multicast vxlan-gbp tunnel for broadcast in the BD - # - tun_bm = VppVxlanGbpTunnel(self, self.pg7.local_ip4, - "239.1.1.1", 88, - mcast_itf=self.pg7) - tun_bm.add_vpp_config() - - # - # a GBP external bridge domains for the EPs - # - bd1 = VppBridgeDomain(self, 1) - bd1.add_vpp_config() - gbd1 = VppGbpBridgeDomain(self, bd1, rd1, self.loop0, None, tun_bm) - gbd1.add_vpp_config() - - # - # The Endpoint-groups in which the external endpoints exist - # - epg_220 = VppGbpEndpointGroup(self, 220, 113, rd1, gbd1, - None, gbd1.bvi, - "10.0.0.128", - "2001:10::128", - VppGbpEndpointRetention(2)) - epg_220.add_vpp_config() - - # the BVIs have the subnets applied ... - ip4_addr = VppIpInterfaceAddress(self, gbd1.bvi, "10.0.0.128", 24) - ip4_addr.add_vpp_config() - ip6_addr = VppIpInterfaceAddress(self, gbd1.bvi, "2001:10::128", 64) - ip6_addr.add_vpp_config() - - # ... which are L3-out subnets - l3o_1 = VppGbpSubnet( - self, rd1, "10.0.0.0", 24, - VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT, - sclass=113) - l3o_1.add_vpp_config() - - # - # an external interface attached to the outside world and the - # external BD - # - VppL2Vtr(self, self.vlan_100, L2_VTR_OP.L2_POP_1).add_vpp_config() - VppL2Vtr(self, self.vlan_101, L2_VTR_OP.L2_POP_1).add_vpp_config() - vlan_144 = VppDot1QSubint(self, self.pg0, 144) - vlan_144.admin_up() - # vlan_102 is not poped - - # - # an unicast vxlan-gbp for inter-RD traffic - # - vx_tun_l3 = VppGbpVxlanTunnel( - self, 444, rd1.rd_id, - VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L3, - self.pg2.local_ip4) - vx_tun_l3.add_vpp_config() - - # - # External Endpoints - # - eep1 = VppGbpEndpoint(self, self.vlan_100, - epg_220, None, - "10.0.0.1", "11.0.0.1", - "2001:10::1", "3001::1", - ep_flags.GBP_API_ENDPOINT_FLAG_EXTERNAL) - eep1.add_vpp_config() - eep2 = VppGbpEndpoint(self, self.vlan_101, - epg_220, None, - "10.0.0.2", "11.0.0.2", - "2001:10::2", "3001::2", - ep_flags.GBP_API_ENDPOINT_FLAG_EXTERNAL) - eep2.add_vpp_config() - eep3 = VppGbpEndpoint(self, self.vlan_102, - epg_220, None, - "10.0.0.3", "11.0.0.3", - "2001:10::3", "3001::3", - ep_flags.GBP_API_ENDPOINT_FLAG_EXTERNAL) - eep3.add_vpp_config() - - # - # A remote external endpoint - # - rep = VppGbpEndpoint(self, vx_tun_l3, - epg_220, None, - "10.0.0.101", "11.0.0.101", - "2001:10::101", "3001::101", - ep_flags.GBP_API_ENDPOINT_FLAG_REMOTE, - self.pg7.local_ip4, - self.pg7.remote_ip4, - mac=None) - rep.add_vpp_config() - - # - # EP1 impersonating EP3 is dropped - # - p = (Ether(src=eep1.mac, dst="ff:ff:ff:ff:ff:ff") / - Dot1Q(vlan=100) / - ARP(op="who-has", - psrc="10.0.0.3", pdst="10.0.0.128", - hwsrc=eep1.mac, hwdst="ff:ff:ff:ff:ff:ff")) - self.send_and_assert_no_replies(self.pg0, p) - - # - # ARP packet from External EPs are accepted and replied to - # - p_arp = (Ether(src=eep1.mac, dst="ff:ff:ff:ff:ff:ff") / - Dot1Q(vlan=100) / - ARP(op="who-has", - psrc=eep1.ip4.address, pdst="10.0.0.128", - hwsrc=eep1.mac, hwdst="ff:ff:ff:ff:ff:ff")) - rxs = self.send_and_expect(self.pg0, p_arp * 1, self.pg0) - - # - # ARP packet from host in remote subnet are accepted and replied to - # - p_arp = (Ether(src=eep3.mac, dst="ff:ff:ff:ff:ff:ff") / - Dot1Q(vlan=102) / - ARP(op="who-has", - psrc=eep3.ip4.address, pdst="10.0.0.128", - hwsrc=eep3.mac, hwdst="ff:ff:ff:ff:ff:ff")) - rxs = self.send_and_expect(self.pg0, p_arp * 1, self.pg0) - - # - # packets destined to unknown addresses in the BVI's subnet - # are ARP'd for - # - p4 = (Ether(src=eep1.mac, dst=str(self.router_mac)) / - Dot1Q(vlan=100) / - IP(src="10.0.0.1", dst="10.0.0.88") / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - p6 = (Ether(src=eep1.mac, dst=str(self.router_mac)) / - Dot1Q(vlan=100) / - IPv6(src="2001:10::1", dst="2001:10::88") / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - - rxs = self.send_and_expect(self.pg0, p4 * 1, self.pg7) - - for rx in rxs: - self.assertEqual(rx[Ether].src, self.pg7.local_mac) - # self.assertEqual(rx[Ether].dst, self.pg7.remote_mac) - self.assertEqual(rx[IP].src, self.pg7.local_ip4) - self.assertEqual(rx[IP].dst, "239.1.1.1") - self.assertEqual(rx[VXLAN].vni, 88) - self.assertTrue(rx[VXLAN].flags.G) - self.assertTrue(rx[VXLAN].flags.Instance) - # policy was applied to the original IP packet - self.assertEqual(rx[VXLAN].gpid, 113) - self.assertTrue(rx[VXLAN].gpflags.A) - self.assertFalse(rx[VXLAN].gpflags.D) - - inner = rx[VXLAN].payload - - self.assertTrue(inner.haslayer(ARP)) - - # - # remote to external - # - p = (Ether(src=self.pg7.remote_mac, - dst=self.pg7.local_mac) / - IP(src=self.pg7.remote_ip4, - dst=self.pg7.local_ip4) / - UDP(sport=1234, dport=48879) / - VXLAN(vni=444, gpid=113, flags=0x88) / - Ether(src=self.pg0.remote_mac, dst=str(self.router_mac)) / - IP(src="10.0.0.101", dst="10.0.0.1") / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - - rxs = self.send_and_expect(self.pg7, p * 1, self.pg0) - - # - # local EP pings router - # - p = (Ether(src=eep1.mac, dst=str(self.router_mac)) / - Dot1Q(vlan=100) / - IP(src=eep1.ip4.address, dst="10.0.0.128") / - ICMP(type='echo-request')) - - rxs = self.send_and_expect(self.pg0, p * 1, self.pg0) - - for rx in rxs: - self.assertEqual(rx[Ether].src, str(self.router_mac)) - self.assertEqual(rx[Ether].dst, eep1.mac) - self.assertEqual(rx[Dot1Q].vlan, 100) - - # - # local EP pings other local EP - # - p = (Ether(src=eep1.mac, dst=eep2.mac) / - Dot1Q(vlan=100) / - IP(src=eep1.ip4.address, dst=eep2.ip4.address) / - ICMP(type='echo-request')) - - rxs = self.send_and_expect(self.pg0, p * 1, self.pg0) - - for rx in rxs: - self.assertEqual(rx[Ether].src, eep1.mac) - self.assertEqual(rx[Ether].dst, eep2.mac) - self.assertEqual(rx[Dot1Q].vlan, 101) - - # - # local EP pings router w/o vlan tag poped - # - p = (Ether(src=eep3.mac, dst=str(self.router_mac)) / - Dot1Q(vlan=102) / - IP(src=eep3.ip4.address, dst="10.0.0.128") / - ICMP(type='echo-request')) - - rxs = self.send_and_expect(self.pg0, p * 1, self.pg0) - - for rx in rxs: - self.assertEqual(rx[Ether].src, str(self.router_mac)) - self.assertEqual(rx[Ether].dst, self.vlan_102.remote_mac) - - # - # A ip4 subnet reachable through the external EP1 - # - ip_220 = VppIpRoute(self, "10.220.0.0", 24, - [VppRoutePath(eep1.ip4.address, - eep1.epg.bvi.sw_if_index)], - table_id=t4.table_id) - ip_220.add_vpp_config() - - l3o_220 = VppGbpSubnet( - self, rd1, "10.220.0.0", 24, - VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT, - sclass=4220) - l3o_220.add_vpp_config() - - # - # An ip6 subnet reachable through the external EP1 - # - ip6_220 = VppIpRoute(self, "10:220::", 64, - [VppRoutePath(eep1.ip6.address, - eep1.epg.bvi.sw_if_index)], - table_id=t6.table_id) - ip6_220.add_vpp_config() - - l3o6_220 = VppGbpSubnet( - self, rd1, "10:220::", 64, - VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT, - sclass=4220) - l3o6_220.add_vpp_config() - - # - # A subnet reachable through the external EP2 - # - ip_221 = VppIpRoute(self, "10.221.0.0", 24, - [VppRoutePath(eep2.ip4.address, - eep2.epg.bvi.sw_if_index)], - table_id=t4.table_id) - ip_221.add_vpp_config() - - l3o_221 = VppGbpSubnet( - self, rd1, "10.221.0.0", 24, - VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT, - sclass=4221) - l3o_221.add_vpp_config() - - # - # ping between hosts in remote subnets - # dropped without a contract - # - p = (Ether(src=eep1.mac, dst=str(self.router_mac)) / - Dot1Q(vlan=100) / - IP(src="10.220.0.1", dst="10.221.0.1") / - ICMP(type='echo-request')) - - self.send_and_assert_no_replies(self.pg0, p * 1) - - # - # contract for the external nets to communicate - # - acl = VppGbpAcl(self) - rule4 = acl.create_rule(permit_deny=1, proto=17) - rule6 = acl.create_rule(is_ipv6=1, permit_deny=1, proto=17) - acl_index = acl.add_vpp_config([rule4, rule6]) - - # - # A contract with the wrong scope is not matched - # - c_44 = VppGbpContract( - self, 44, 4220, 4221, acl_index, - [VppGbpContractRule( - VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT, - []), - VppGbpContractRule( - VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT, - [])], - [ETH_P_IP, ETH_P_IPV6]) - c_44.add_vpp_config() - self.send_and_assert_no_replies(self.pg0, p * 1) - - c1 = VppGbpContract( - self, 55, 4220, 4221, acl_index, - [VppGbpContractRule( - VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT, - VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP, - []), - VppGbpContractRule( - VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT, - VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP, - [])], - [ETH_P_IP, ETH_P_IPV6]) - c1.add_vpp_config() - - # - # Contracts allowing ext-net 200 to talk with external EPs - # - c2 = VppGbpContract( - self, 55, 4220, 113, acl_index, - [VppGbpContractRule( - VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT, - VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP, - []), - VppGbpContractRule( - VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT, - VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP, - [])], - [ETH_P_IP, ETH_P_IPV6]) - c2.add_vpp_config() - c3 = VppGbpContract( - self, 55, 113, 4220, acl_index, - [VppGbpContractRule( - VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT, - VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP, - []), - VppGbpContractRule( - VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT, - VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP, - [])], - [ETH_P_IP, ETH_P_IPV6]) - c3.add_vpp_config() - - # - # ping between hosts in remote subnets - # - p = (Ether(src=eep1.mac, dst=str(self.router_mac)) / - Dot1Q(vlan=100) / - IP(src="10.220.0.1", dst="10.221.0.1") / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - - rxs = self.send_and_expect(self.pg0, p * 1, self.pg0) - - for rx in rxs: - self.assertEqual(rx[Ether].src, str(self.router_mac)) - self.assertEqual(rx[Ether].dst, eep2.mac) - self.assertEqual(rx[Dot1Q].vlan, 101) - - # we did not learn these external hosts - self.assertFalse(find_gbp_endpoint(self, ip="10.220.0.1")) - self.assertFalse(find_gbp_endpoint(self, ip="10.221.0.1")) - - # - # from remote external EP to local external EP - # - p = (Ether(src=self.pg7.remote_mac, - dst=self.pg7.local_mac) / - IP(src=self.pg7.remote_ip4, - dst=self.pg7.local_ip4) / - UDP(sport=1234, dport=48879) / - VXLAN(vni=444, gpid=113, flags=0x88) / - Ether(src=self.pg0.remote_mac, dst=str(self.router_mac)) / - IP(src="10.0.0.101", dst="10.220.0.1") / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - - rxs = self.send_and_expect(self.pg7, p * 1, self.pg0) - - # - # ping from an external host to the remote external EP - # - p = (Ether(src=eep1.mac, dst=str(self.router_mac)) / - Dot1Q(vlan=100) / - IP(src="10.220.0.1", dst=rep.ip4.address) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - - rxs = self.send_and_expect(self.pg0, p * 1, self.pg7) - - for rx in rxs: - self.assertEqual(rx[Ether].src, self.pg7.local_mac) - # self.assertEqual(rx[Ether].dst, self.pg7.remote_mac) - self.assertEqual(rx[IP].src, self.pg7.local_ip4) - self.assertEqual(rx[IP].dst, self.pg7.remote_ip4) - self.assertEqual(rx[VXLAN].vni, 444) - self.assertTrue(rx[VXLAN].flags.G) - self.assertTrue(rx[VXLAN].flags.Instance) - # the sclass of the ext-net the packet came from - self.assertEqual(rx[VXLAN].gpid, 4220) - # policy was applied to the original IP packet - self.assertTrue(rx[VXLAN].gpflags.A) - # since it's an external host the reciever should not learn it - self.assertTrue(rx[VXLAN].gpflags.D) - inner = rx[VXLAN].payload - self.assertEqual(inner[IP].src, "10.220.0.1") - self.assertEqual(inner[IP].dst, rep.ip4.address) - - # - # An external subnet reachable via the remote external EP - # - - # - # first the VXLAN-GBP tunnel over which it is reached - # - vx_tun_r1 = VppVxlanGbpTunnel( - self, self.pg7.local_ip4, - self.pg7.remote_ip4, 445, - mode=(VppEnum.vl_api_vxlan_gbp_api_tunnel_mode_t. - VXLAN_GBP_API_TUNNEL_MODE_L3)) - vx_tun_r1.add_vpp_config() - VppIpInterfaceBind(self, vx_tun_r1, t4).add_vpp_config() - - self.logger.info(self.vapi.cli("sh vxlan-gbp tunnel")) - - # - # then the special adj to resolve through on that tunnel - # - n1 = VppNeighbor(self, - vx_tun_r1.sw_if_index, - "00:0c:0c:0c:0c:0c", - self.pg7.remote_ip4) - n1.add_vpp_config() - - # - # the route via the adj above - # - ip_222 = VppIpRoute(self, "10.222.0.0", 24, - [VppRoutePath(self.pg7.remote_ip4, - vx_tun_r1.sw_if_index)], - table_id=t4.table_id) - ip_222.add_vpp_config() - - l3o_222 = VppGbpSubnet( - self, rd1, "10.222.0.0", 24, - VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT, - sclass=4222) - l3o_222.add_vpp_config() - - # - # ping between hosts in local and remote external subnets - # dropped without a contract - # - p = (Ether(src=eep1.mac, dst=str(self.router_mac)) / - Dot1Q(vlan=100) / - IP(src="10.220.0.1", dst="10.222.0.1") / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - - rxs = self.send_and_assert_no_replies(self.pg0, p * 1) - - # - # Add contracts ext-nets for 220 -> 222 - # - c4 = VppGbpContract( - self, 55, 4220, 4222, acl_index, - [VppGbpContractRule( - VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT, - VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP, - []), - VppGbpContractRule( - VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT, - VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP, - [])], - [ETH_P_IP, ETH_P_IPV6]) - c4.add_vpp_config() - - # - # ping from host in local to remote external subnets - # - p = (Ether(src=eep1.mac, dst=str(self.router_mac)) / - Dot1Q(vlan=100) / - IP(src="10.220.0.1", dst="10.222.0.1") / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - - rxs = self.send_and_expect(self.pg0, p * 3, self.pg7) - - for rx in rxs: - self.assertEqual(rx[Ether].src, self.pg7.local_mac) - self.assertEqual(rx[Ether].dst, self.pg7.remote_mac) - self.assertEqual(rx[IP].src, self.pg7.local_ip4) - self.assertEqual(rx[IP].dst, self.pg7.remote_ip4) - self.assertEqual(rx[VXLAN].vni, 445) - self.assertTrue(rx[VXLAN].flags.G) - self.assertTrue(rx[VXLAN].flags.Instance) - # the sclass of the ext-net the packet came from - self.assertEqual(rx[VXLAN].gpid, 4220) - # policy was applied to the original IP packet - self.assertTrue(rx[VXLAN].gpflags.A) - # since it's an external host the reciever should not learn it - self.assertTrue(rx[VXLAN].gpflags.D) - inner = rx[VXLAN].payload - self.assertEqual(inner[Ether].dst, "00:0c:0c:0c:0c:0c") - self.assertEqual(inner[IP].src, "10.220.0.1") - self.assertEqual(inner[IP].dst, "10.222.0.1") - - # - # make the external subnet ECMP - # - vx_tun_r2 = VppVxlanGbpTunnel( - self, self.pg7.local_ip4, - self.pg7.remote_ip4, 446, - mode=(VppEnum.vl_api_vxlan_gbp_api_tunnel_mode_t. - VXLAN_GBP_API_TUNNEL_MODE_L3)) - vx_tun_r2.add_vpp_config() - VppIpInterfaceBind(self, vx_tun_r2, t4).add_vpp_config() - - self.logger.info(self.vapi.cli("sh vxlan-gbp tunnel")) - - n2 = VppNeighbor(self, - vx_tun_r2.sw_if_index, - "00:0c:0c:0c:0c:0c", - self.pg7.remote_ip4) - n2.add_vpp_config() - - ip_222.modify([VppRoutePath(self.pg7.remote_ip4, - vx_tun_r1.sw_if_index), - VppRoutePath(self.pg7.remote_ip4, - vx_tun_r2.sw_if_index)]) - - # - # now expect load-balance - # - p = [(Ether(src=eep1.mac, dst=str(self.router_mac)) / - Dot1Q(vlan=100) / - IP(src="10.220.0.1", dst="10.222.0.1") / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)), - (Ether(src=eep1.mac, dst=str(self.router_mac)) / - Dot1Q(vlan=100) / - IP(src="10.220.0.1", dst="10.222.0.1") / - UDP(sport=1222, dport=1235) / - Raw('\xa5' * 100))] - - rxs = self.send_and_expect(self.pg0, p, self.pg7) - - self.assertEqual(rxs[0][VXLAN].vni, 445) - self.assertEqual(rxs[1][VXLAN].vni, 446) - - # - # Same LB test for v6 - # - n3 = VppNeighbor(self, - vx_tun_r1.sw_if_index, - "00:0c:0c:0c:0c:0c", - self.pg7.remote_ip6) - n3.add_vpp_config() - n4 = VppNeighbor(self, - vx_tun_r2.sw_if_index, - "00:0c:0c:0c:0c:0c", - self.pg7.remote_ip6) - n4.add_vpp_config() - - ip_222_6 = VppIpRoute(self, "10:222::", 64, - [VppRoutePath(self.pg7.remote_ip6, - vx_tun_r1.sw_if_index), - VppRoutePath(self.pg7.remote_ip6, - vx_tun_r2.sw_if_index)], - table_id=t6.table_id) - ip_222_6.add_vpp_config() - - l3o_222_6 = VppGbpSubnet( - self, rd1, "10:222::", 64, - VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT, - sclass=4222) - l3o_222_6.add_vpp_config() - - p = [(Ether(src=eep1.mac, dst=str(self.router_mac)) / - Dot1Q(vlan=100) / - IPv6(src="10:220::1", dst="10:222::1") / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)), - (Ether(src=eep1.mac, dst=str(self.router_mac)) / - Dot1Q(vlan=100) / - IPv6(src="10:220::1", dst="10:222::1") / - UDP(sport=7777, dport=8881) / - Raw('\xa5' * 100))] - - self.logger.info(self.vapi.cli("sh ip6 fib 10:222::1")) - rxs = self.send_and_expect(self.pg0, p, self.pg7) - - self.assertEqual(rxs[0][VXLAN].vni, 445) - self.assertEqual(rxs[1][VXLAN].vni, 446) - - # - # ping from host in remote to local external subnets - # there's no contract for this, but the A bit is set. - # - p = (Ether(src=self.pg7.remote_mac, dst=self.pg7.local_mac) / - IP(src=self.pg7.remote_ip4, dst=self.pg7.local_ip4) / - UDP(sport=1234, dport=48879) / - VXLAN(vni=445, gpid=4222, flags=0x88, gpflags='A') / - Ether(src=self.pg0.remote_mac, dst=str(self.router_mac)) / - IP(src="10.222.0.1", dst="10.220.0.1") / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - - rxs = self.send_and_expect(self.pg7, p * 3, self.pg0) - self.assertFalse(find_gbp_endpoint(self, ip="10.222.0.1")) - - # - # ping from host in remote to remote external subnets - # this is dropped by reflection check. - # - p = (Ether(src=self.pg7.remote_mac, dst=self.pg7.local_mac) / - IP(src=self.pg7.remote_ip4, dst=self.pg7.local_ip4) / - UDP(sport=1234, dport=48879) / - VXLAN(vni=445, gpid=4222, flags=0x88, gpflags='A') / - Ether(src=self.pg0.remote_mac, dst=str(self.router_mac)) / - IP(src="10.222.0.1", dst="10.222.0.2") / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - - rxs = self.send_and_assert_no_replies(self.pg7, p * 3) - - p = (Ether(src=self.pg7.remote_mac, dst=self.pg7.local_mac) / - IP(src=self.pg7.remote_ip4, dst=self.pg7.local_ip4) / - UDP(sport=1234, dport=48879) / - VXLAN(vni=445, gpid=4222, flags=0x88, gpflags='A') / - Ether(src=self.pg0.remote_mac, dst=str(self.router_mac)) / - IPv6(src="10:222::1", dst="10:222::2") / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - - rxs = self.send_and_assert_no_replies(self.pg7, p * 3) - - # - # local EP - # - lep1 = VppGbpEndpoint(self, vlan_144, - epg_220, None, - "10.0.0.44", "11.0.0.44", - "2001:10::44", "3001::44") - lep1.add_vpp_config() - - # - # local EP to local ip4 external subnet - # - p = (Ether(src=lep1.mac, dst=str(self.router_mac)) / - Dot1Q(vlan=144) / - IP(src=lep1.ip4.address, dst="10.220.0.1") / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - - rxs = self.send_and_expect(self.pg0, p * 1, self.pg0) - - for rx in rxs: - self.assertEqual(rx[Ether].src, str(self.router_mac)) - self.assertEqual(rx[Ether].dst, eep1.mac) - self.assertEqual(rx[Dot1Q].vlan, 100) - - # - # local EP to local ip6 external subnet - # - p = (Ether(src=lep1.mac, dst=str(self.router_mac)) / - Dot1Q(vlan=144) / - IPv6(src=lep1.ip6.address, dst="10:220::1") / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - - rxs = self.send_and_expect(self.pg0, p * 1, self.pg0) - - for rx in rxs: - self.assertEqual(rx[Ether].src, str(self.router_mac)) - self.assertEqual(rx[Ether].dst, eep1.mac) - self.assertEqual(rx[Dot1Q].vlan, 100) - - # - # ip4 and ip6 subnets that load-balance - # - ip_20 = VppIpRoute(self, "10.20.0.0", 24, - [VppRoutePath(eep1.ip4.address, - eep1.epg.bvi.sw_if_index), - VppRoutePath(eep2.ip4.address, - eep2.epg.bvi.sw_if_index)], - table_id=t4.table_id) - ip_20.add_vpp_config() - - l3o_20 = VppGbpSubnet( - self, rd1, "10.20.0.0", 24, - VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT, - sclass=4220) - l3o_20.add_vpp_config() - - ip6_20 = VppIpRoute(self, "10:20::", 64, - [VppRoutePath(eep1.ip6.address, - eep1.epg.bvi.sw_if_index), - VppRoutePath(eep2.ip6.address, - eep2.epg.bvi.sw_if_index)], - table_id=t6.table_id) - ip6_20.add_vpp_config() - - l3o6_20 = VppGbpSubnet( - self, rd1, "10:20::", 64, - VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT, - sclass=4220) - l3o6_20.add_vpp_config() - - self.logger.info(self.vapi.cli("sh ip fib 10.20.0.1")) - self.logger.info(self.vapi.cli("sh ip6 fib 10:20::1")) - - # two ip6 packets whose port are chosen so they load-balance - p = [(Ether(src=lep1.mac, dst=str(self.router_mac)) / - Dot1Q(vlan=144) / - IPv6(src=lep1.ip6.address, dst="10:20::1") / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)), - (Ether(src=lep1.mac, dst=str(self.router_mac)) / - Dot1Q(vlan=144) / - IPv6(src=lep1.ip6.address, dst="10:20::1") / - UDP(sport=124, dport=1230) / - Raw('\xa5' * 100))] - - rxs = self.send_and_expect(self.pg0, p, self.pg0, 2) - - self.assertEqual(rxs[0][Dot1Q].vlan, 101) - self.assertEqual(rxs[1][Dot1Q].vlan, 100) - - # two ip4 packets whose port are chosen so they load-balance - p = [(Ether(src=lep1.mac, dst=str(self.router_mac)) / - Dot1Q(vlan=144) / - IP(src=lep1.ip4.address, dst="10.20.0.1") / - UDP(sport=1235, dport=1235) / - Raw('\xa5' * 100)), - (Ether(src=lep1.mac, dst=str(self.router_mac)) / - Dot1Q(vlan=144) / - IP(src=lep1.ip4.address, dst="10.20.0.1") / - UDP(sport=124, dport=1230) / - Raw('\xa5' * 100))] - - rxs = self.send_and_expect(self.pg0, p, self.pg0, 2) - - self.assertEqual(rxs[0][Dot1Q].vlan, 101) - self.assertEqual(rxs[1][Dot1Q].vlan, 100) - - # - # cleanup - # - ip_222.remove_vpp_config() - self.pg7.unconfig_ip4() - self.vlan_101.set_vtr(L2_VTR_OP.L2_DISABLED) - self.vlan_100.set_vtr(L2_VTR_OP.L2_DISABLED) - - def test_gbp_anon_l3_out(self): - """ GBP Anonymous L3 Out """ - - ep_flags = VppEnum.vl_api_gbp_endpoint_flags_t - self.vapi.cli("set logging class gbp level debug") - - routed_dst_mac = "00:0c:0c:0c:0c:0c" - routed_src_mac = "00:22:bd:f8:19:ff" - - # - # IP tables - # - t4 = VppIpTable(self, 1) - t4.add_vpp_config() - t6 = VppIpTable(self, 1, True) - t6.add_vpp_config() - - rd1 = VppGbpRouteDomain(self, 2, 55, t4, t6) - rd1.add_vpp_config() - - self.loop0.set_mac(self.router_mac) - - # - # Bind the BVI to the RD - # - VppIpInterfaceBind(self, self.loop0, t4).add_vpp_config() - VppIpInterfaceBind(self, self.loop0, t6).add_vpp_config() - - # - # Pg7 hosts a BD's BUM - # Pg1 some other l3 interface - # - self.pg7.config_ip4() - self.pg7.resolve_arp() - - # - # a GBP external bridge domains for the EPs - # - bd1 = VppBridgeDomain(self, 1) - bd1.add_vpp_config() - gbd1 = VppGbpBridgeDomain(self, bd1, rd1, self.loop0, None, None) - gbd1.add_vpp_config() - - # - # The Endpoint-groups in which the external endpoints exist - # - epg_220 = VppGbpEndpointGroup(self, 220, 113, rd1, gbd1, - None, gbd1.bvi, - "10.0.0.128", - "2001:10::128", - VppGbpEndpointRetention(2)) - epg_220.add_vpp_config() - - # the BVIs have the subnet applied ... - ip4_addr = VppIpInterfaceAddress(self, gbd1.bvi, "10.0.0.128", 24) - ip4_addr.add_vpp_config() - - # ... which is an Anonymous L3-out subnets - l3o_1 = VppGbpSubnet( - self, rd1, "10.0.0.0", 24, - VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_ANON_L3_OUT, - sclass=113) - l3o_1.add_vpp_config() - - # - # an external interface attached to the outside world and the - # external BD - # - VppL2Vtr(self, self.vlan_100, L2_VTR_OP.L2_POP_1).add_vpp_config() - VppL2Vtr(self, self.vlan_101, L2_VTR_OP.L2_POP_1).add_vpp_config() - - # - # vlan_100 and vlan_101 are anonymous l3-out interfaces - # - ext_itf = VppGbpExtItf(self, self.vlan_100, bd1, rd1, anon=True) - ext_itf.add_vpp_config() - ext_itf = VppGbpExtItf(self, self.vlan_101, bd1, rd1, anon=True) - ext_itf.add_vpp_config() - - # - # an unicast vxlan-gbp for inter-RD traffic - # - vx_tun_l3 = VppGbpVxlanTunnel( - self, 444, rd1.rd_id, - VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L3, - self.pg2.local_ip4) - vx_tun_l3.add_vpp_config() - - # - # A remote external endpoint - # - rep = VppGbpEndpoint(self, vx_tun_l3, - epg_220, None, - "10.0.0.201", "11.0.0.201", - "2001:10::201", "3001::101", - ep_flags.GBP_API_ENDPOINT_FLAG_REMOTE, - self.pg7.local_ip4, - self.pg7.remote_ip4, - mac=None) - rep.add_vpp_config() - - # - # ARP packet from host in external subnet are accepted, flooded and - # replied to. We expect 2 packets: - # - APR request flooded over the other vlan subif - # - ARP reply from BVI - # - p_arp = (Ether(src=self.vlan_100.remote_mac, - dst="ff:ff:ff:ff:ff:ff") / - Dot1Q(vlan=100) / - ARP(op="who-has", - psrc="10.0.0.100", - pdst="10.0.0.128", - hwsrc=self.vlan_100.remote_mac, - hwdst="ff:ff:ff:ff:ff:ff")) - rxs = self.send_and_expect(self.pg0, p_arp * 1, self.pg0, n_rx=2) - - p_arp = (Ether(src=self.vlan_101.remote_mac, - dst="ff:ff:ff:ff:ff:ff") / - Dot1Q(vlan=101) / - ARP(op="who-has", - psrc='10.0.0.101', - pdst="10.0.0.128", - hwsrc=self.vlan_101.remote_mac, - hwdst="ff:ff:ff:ff:ff:ff")) - rxs = self.send_and_expect(self.pg0, p_arp * 1, self.pg0, n_rx=2) - - # - # remote to external - # - p = (Ether(src=self.pg7.remote_mac, - dst=self.pg7.local_mac) / - IP(src=self.pg7.remote_ip4, - dst=self.pg7.local_ip4) / - UDP(sport=1234, dport=48879) / - VXLAN(vni=vx_tun_l3.vni, gpid=epg_220.sclass, flags=0x88) / - Ether(src=self.pg0.remote_mac, dst=str(self.router_mac)) / - IP(src=str(rep.ip4), dst="10.0.0.100") / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - rxs = self.send_and_expect(self.pg7, p * 1, self.pg0) - - # - # local EP pings router - # - p = (Ether(src=self.vlan_100.remote_mac, dst=str(self.router_mac)) / - Dot1Q(vlan=100) / - IP(src="10.0.0.100", dst="10.0.0.128") / - ICMP(type='echo-request')) - rxs = self.send_and_expect(self.pg0, p * 1, self.pg0) - - for rx in rxs: - self.assertEqual(rx[Ether].src, str(self.router_mac)) - self.assertEqual(rx[Ether].dst, self.vlan_100.remote_mac) - self.assertEqual(rx[Dot1Q].vlan, 100) - - # - # local EP pings other local EP - # - p = (Ether(src=self.vlan_100.remote_mac, - dst=self.vlan_101.remote_mac) / - Dot1Q(vlan=100) / - IP(src="10.0.0.100", dst="10.0.0.101") / - ICMP(type='echo-request')) - rxs = self.send_and_expect(self.pg0, p * 1, self.pg0) - - for rx in rxs: - self.assertEqual(rx[Ether].src, self.vlan_100.remote_mac) - self.assertEqual(rx[Ether].dst, self.vlan_101.remote_mac) - self.assertEqual(rx[Dot1Q].vlan, 101) - - # - # A subnet reachable through an external router on vlan 100 - # - ip_220 = VppIpRoute(self, "10.220.0.0", 24, - [VppRoutePath("10.0.0.100", - epg_220.bvi.sw_if_index)], - table_id=t4.table_id) - ip_220.add_vpp_config() - - l3o_220 = VppGbpSubnet( - self, rd1, "10.220.0.0", 24, - # note: this a "regular" L3 out subnet (not connected) - VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT, - sclass=4220) - l3o_220.add_vpp_config() - - # - # A subnet reachable through an external router on vlan 101 - # - ip_221 = VppIpRoute(self, "10.221.0.0", 24, - [VppRoutePath("10.0.0.101", - epg_220.bvi.sw_if_index)], - table_id=t4.table_id) - ip_221.add_vpp_config() - - l3o_221 = VppGbpSubnet( - self, rd1, "10.221.0.0", 24, - # note: this a "regular" L3 out subnet (not connected) - VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT, - sclass=4221) - l3o_221.add_vpp_config() - - # - # ping between hosts in remote subnets - # dropped without a contract - # - p = (Ether(src=self.vlan_100.remote_mac, dst=str(self.router_mac)) / - Dot1Q(vlan=100) / - IP(src="10.220.0.1", dst="10.221.0.1") / - ICMP(type='echo-request')) - - rxs = self.send_and_assert_no_replies(self.pg0, p * 1) - - # - # contract for the external nets to communicate - # - acl = VppGbpAcl(self) - rule4 = acl.create_rule(permit_deny=1, proto=17) - rule6 = acl.create_rule(is_ipv6=1, permit_deny=1, proto=17) - acl_index = acl.add_vpp_config([rule4, rule6]) - - c1 = VppGbpContract( - self, 55, 4220, 4221, acl_index, - [VppGbpContractRule( - VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT, - VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP, - []), - VppGbpContractRule( - VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT, - VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP, - [])], - [ETH_P_IP, ETH_P_IPV6]) - c1.add_vpp_config() - - # - # Contracts allowing ext-net 200 to talk with external EPs - # - c2 = VppGbpContract( - self, 55, 4220, 113, acl_index, - [VppGbpContractRule( - VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT, - VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP, - []), - VppGbpContractRule( - VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT, - VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP, - [])], - [ETH_P_IP, ETH_P_IPV6]) - c2.add_vpp_config() - c3 = VppGbpContract( - self, 55, 113, 4220, acl_index, - [VppGbpContractRule( - VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT, - VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP, - []), - VppGbpContractRule( - VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT, - VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP, - [])], - [ETH_P_IP, ETH_P_IPV6]) - c3.add_vpp_config() - - # - # ping between hosts in remote subnets - # - p = (Ether(src=self.vlan_100.remote_mac, dst=str(self.router_mac)) / - Dot1Q(vlan=100) / - IP(src="10.220.0.1", dst="10.221.0.1") / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - - rxs = self.send_and_expect(self.pg0, p * 1, self.pg0) - - for rx in rxs: - self.assertEqual(rx[Ether].src, str(self.router_mac)) - self.assertEqual(rx[Ether].dst, self.vlan_101.remote_mac) - self.assertEqual(rx[Dot1Q].vlan, 101) - - # we did not learn these external hosts - self.assertFalse(find_gbp_endpoint(self, ip="10.220.0.1")) - self.assertFalse(find_gbp_endpoint(self, ip="10.221.0.1")) - - # - # from remote external EP to local external EP - # - p = (Ether(src=self.pg7.remote_mac, - dst=self.pg7.local_mac) / - IP(src=self.pg7.remote_ip4, - dst=self.pg7.local_ip4) / - UDP(sport=1234, dport=48879) / - VXLAN(vni=444, gpid=113, flags=0x88) / - Ether(src=self.pg0.remote_mac, dst=str(self.router_mac)) / - IP(src=rep.ip4.address, dst="10.220.0.1") / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - - rxs = self.send_and_expect(self.pg7, p * 1, self.pg0) - - # - # ping from an external host to the remote external EP - # - p = (Ether(src=self.vlan_100.remote_mac, dst=str(self.router_mac)) / - Dot1Q(vlan=100) / - IP(src="10.220.0.1", dst=rep.ip4.address) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - - rxs = self.send_and_expect(self.pg0, p * 1, self.pg7) - - for rx in rxs: - self.assertEqual(rx[Ether].src, self.pg7.local_mac) - # self.assertEqual(rx[Ether].dst, self.pg7.remote_mac) - self.assertEqual(rx[IP].src, self.pg7.local_ip4) - self.assertEqual(rx[IP].dst, self.pg7.remote_ip4) - self.assertEqual(rx[VXLAN].vni, 444) - self.assertTrue(rx[VXLAN].flags.G) - self.assertTrue(rx[VXLAN].flags.Instance) - # the sclass of the ext-net the packet came from - self.assertEqual(rx[VXLAN].gpid, 4220) - # policy was applied to the original IP packet - self.assertTrue(rx[VXLAN].gpflags.A) - # since it's an external host the reciever should not learn it - self.assertTrue(rx[VXLAN].gpflags.D) - inner = rx[VXLAN].payload - self.assertEqual(inner[IP].src, "10.220.0.1") - self.assertEqual(inner[IP].dst, rep.ip4.address) - - # - # An external subnet reachable via the remote external EP - # - - # - # first the VXLAN-GBP tunnel over which it is reached - # - vx_tun_r = VppVxlanGbpTunnel( - self, self.pg7.local_ip4, - self.pg7.remote_ip4, 445, - mode=(VppEnum.vl_api_vxlan_gbp_api_tunnel_mode_t. - VXLAN_GBP_API_TUNNEL_MODE_L3)) - vx_tun_r.add_vpp_config() - VppIpInterfaceBind(self, vx_tun_r, t4).add_vpp_config() - - self.logger.info(self.vapi.cli("sh vxlan-gbp tunnel")) - - # - # then the special adj to resolve through on that tunnel - # - n1 = VppNeighbor(self, - vx_tun_r.sw_if_index, - "00:0c:0c:0c:0c:0c", - self.pg7.remote_ip4) - n1.add_vpp_config() - - # - # the route via the adj above - # - ip_222 = VppIpRoute(self, "10.222.0.0", 24, - [VppRoutePath(self.pg7.remote_ip4, - vx_tun_r.sw_if_index)], - table_id=t4.table_id) - ip_222.add_vpp_config() - - l3o_222 = VppGbpSubnet( - self, rd1, "10.222.0.0", 24, - # note: this a "regular" l3out subnet (not connected) - VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT, - sclass=4222) - l3o_222.add_vpp_config() - - # - # ping between hosts in local and remote external subnets - # dropped without a contract - # - p = (Ether(src=self.vlan_100.remote_mac, dst=str(self.router_mac)) / - Dot1Q(vlan=100) / - IP(src="10.220.0.1", dst="10.222.0.1") / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - - rxs = self.send_and_assert_no_replies(self.pg0, p * 1) - - # - # Add contracts ext-nets for 220 -> 222 - # - c4 = VppGbpContract( - self, 55, 4220, 4222, acl_index, - [VppGbpContractRule( - VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT, - VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP, - []), - VppGbpContractRule( - VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT, - VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP, - [])], - [ETH_P_IP, ETH_P_IPV6]) - c4.add_vpp_config() - - # - # ping from host in local to remote external subnets - # - p = (Ether(src=self.vlan_100.remote_mac, dst=str(self.router_mac)) / - Dot1Q(vlan=100) / - IP(src="10.220.0.1", dst="10.222.0.1") / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - - rxs = self.send_and_expect(self.pg0, p * 3, self.pg7) - - for rx in rxs: - self.assertEqual(rx[Ether].src, self.pg7.local_mac) - self.assertEqual(rx[Ether].dst, self.pg7.remote_mac) - self.assertEqual(rx[IP].src, self.pg7.local_ip4) - self.assertEqual(rx[IP].dst, self.pg7.remote_ip4) - self.assertEqual(rx[VXLAN].vni, 445) - self.assertTrue(rx[VXLAN].flags.G) - self.assertTrue(rx[VXLAN].flags.Instance) - # the sclass of the ext-net the packet came from - self.assertEqual(rx[VXLAN].gpid, 4220) - # policy was applied to the original IP packet - self.assertTrue(rx[VXLAN].gpflags.A) - # since it's an external host the reciever should not learn it - self.assertTrue(rx[VXLAN].gpflags.D) - inner = rx[VXLAN].payload - self.assertEqual(inner[Ether].dst, "00:0c:0c:0c:0c:0c") - self.assertEqual(inner[IP].src, "10.220.0.1") - self.assertEqual(inner[IP].dst, "10.222.0.1") - - # - # ping from host in remote to local external subnets - # there's no contract for this, but the A bit is set. - # - p = (Ether(src=self.pg7.remote_mac, dst=self.pg7.local_mac) / - IP(src=self.pg7.remote_ip4, dst=self.pg7.local_ip4) / - UDP(sport=1234, dport=48879) / - VXLAN(vni=445, gpid=4222, flags=0x88, gpflags='A') / - Ether(src=self.pg0.remote_mac, dst=str(self.router_mac)) / - IP(src="10.222.0.1", dst="10.220.0.1") / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - - rxs = self.send_and_expect(self.pg7, p * 3, self.pg0) - self.assertFalse(find_gbp_endpoint(self, ip="10.222.0.1")) - - # - # ping from host in remote to remote external subnets - # this is dropped by reflection check. - # - p = (Ether(src=self.pg7.remote_mac, dst=self.pg7.local_mac) / - IP(src=self.pg7.remote_ip4, dst=self.pg7.local_ip4) / - UDP(sport=1234, dport=48879) / - VXLAN(vni=445, gpid=4222, flags=0x88, gpflags='A') / - Ether(src=self.pg0.remote_mac, dst=str(self.router_mac)) / - IP(src="10.222.0.1", dst="10.222.0.2") / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - - rxs = self.send_and_assert_no_replies(self.pg7, p * 3) - - # - # cleanup - # - self.vlan_101.set_vtr(L2_VTR_OP.L2_DISABLED) - self.vlan_100.set_vtr(L2_VTR_OP.L2_DISABLED) - self.pg7.unconfig_ip4() - - -if __name__ == '__main__': - unittest.main(testRunner=VppTestRunner) diff --git a/test/test_gtpu.py b/test/test_gtpu.py deleted file mode 100644 index 957181a71e4..00000000000 --- a/test/test_gtpu.py +++ /dev/null @@ -1,393 +0,0 @@ -#!/usr/bin/env python - -import socket -from util import ip4n_range, ip4_range -import unittest -from framework import VppTestCase, VppTestRunner -from template_bd import BridgeDomain - -from scapy.layers.l2 import Ether, Raw -from scapy.layers.inet import IP, UDP -from scapy.layers.inet6 import IPv6 -from scapy.contrib.gtp import GTP_U_Header -from scapy.utils import atol -from vpp_ip_route import VppIpRoute, VppRoutePath -from vpp_ip import INVALID_INDEX - - -class TestGtpuUDP(VppTestCase): - """ GTPU UDP ports Test Case """ - - def setUp(self): - super(TestGtpuUDP, self).setUp() - - self.dport = 2152 - - self.ip4_err = 0 - self.ip6_err = 0 - - self.create_pg_interfaces(range(1)) - for pg in self.pg_interfaces: - pg.admin_up() - self.pg0.config_ip4() - self.pg0.config_ip6() - - def _check_udp_port_ip4(self, enabled=True): - - pkt = (Ether(src=self.pg0.local_mac, dst=self.pg0.remote_mac) / - IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) / - UDP(sport=self.dport, dport=self.dport, chksum=0)) - - self.pg0.add_stream(pkt) - self.pg_start() - - err = self.statistics.get_counter( - '/err/ip4-udp-lookup/no listener for dst port')[0] - - if enabled: - self.assertEqual(err, self.ip4_err) - else: - self.assertEqual(err, self.ip4_err + 1) - - self.ip4_err = err - - def _check_udp_port_ip6(self, enabled=True): - - pkt = (Ether(src=self.pg0.local_mac, dst=self.pg0.remote_mac) / - IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6) / - UDP(sport=self.dport, dport=self.dport, chksum=0)) - - self.pg0.add_stream(pkt) - self.pg_start() - - err = self.statistics.get_counter( - '/err/ip6-udp-lookup/no listener for dst port')[0] - - if enabled: - self.assertEqual(err, self.ip6_err) - else: - self.assertEqual(err, self.ip6_err + 1) - - self.ip6_err = err - - def test_udp_port(self): - """ test UDP ports - Check if there are no udp listeners before gtpu is enabled - """ - - # UDP ports should be disabled unless a tunnel is configured - self._check_udp_port_ip4(False) - self._check_udp_port_ip6(False) - - r = self.vapi.gtpu_add_del_tunnel(src_addr=self.pg0.local_ip4n, - dst_addr=self.pg0.remote_ip4n) - - # UDP port 2152 enabled for ip4 - self._check_udp_port_ip4() - - r = self.vapi.gtpu_add_del_tunnel(is_ipv6=1, - src_addr=self.pg0.local_ip6n, - dst_addr=self.pg0.remote_ip6n) - - # UDP port 2152 enabled for ip6 - self._check_udp_port_ip6() - - r = self.vapi.gtpu_add_del_tunnel(is_add=0, - src_addr=self.pg0.local_ip4n, - dst_addr=self.pg0.remote_ip4n) - - r = self.vapi.gtpu_add_del_tunnel(is_add=0, is_ipv6=1, - src_addr=self.pg0.local_ip6n, - dst_addr=self.pg0.remote_ip6n) - - -class TestGtpu(BridgeDomain, VppTestCase): - """ GTPU Test Case """ - - def __init__(self, *args): - BridgeDomain.__init__(self) - VppTestCase.__init__(self, *args) - - def encapsulate(self, pkt, vni): - """ - Encapsulate the original payload frame by adding GTPU header with its - UDP, IP and Ethernet fields - """ - return (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / - IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) / - UDP(sport=self.dport, dport=self.dport, chksum=0) / - GTP_U_Header(teid=vni, gtp_type=self.gtp_type, length=150) / - pkt) - - def ip_range(self, start, end): - """ range of remote ip's """ - return ip4_range(self.pg0.remote_ip4, start, end) - - def encap_mcast(self, pkt, src_ip, src_mac, vni): - """ - Encapsulate the original payload frame by adding GTPU header with its - UDP, IP and Ethernet fields - """ - return (Ether(src=src_mac, dst=self.mcast_mac) / - IP(src=src_ip, dst=self.mcast_ip4) / - UDP(sport=self.dport, dport=self.dport, chksum=0) / - GTP_U_Header(teid=vni, gtp_type=self.gtp_type, length=150) / - pkt) - - def decapsulate(self, pkt): - """ - Decapsulate the original payload frame by removing GTPU header - """ - return pkt[GTP_U_Header].payload - - # Method for checking GTPU encapsulation. - # - def check_encapsulation(self, pkt, vni, local_only=False, mcast_pkt=False): - # Verify source MAC is VPP_MAC and destination MAC is MY_MAC resolved - # by VPP using ARP. - self.assertEqual(pkt[Ether].src, self.pg0.local_mac) - if not local_only: - if not mcast_pkt: - self.assertEqual(pkt[Ether].dst, self.pg0.remote_mac) - else: - self.assertEqual(pkt[Ether].dst, type(self).mcast_mac) - # Verify GTPU tunnel source IP is VPP_IP and destination IP is MY_IP. - self.assertEqual(pkt[IP].src, self.pg0.local_ip4) - if not local_only: - if not mcast_pkt: - self.assertEqual(pkt[IP].dst, self.pg0.remote_ip4) - else: - self.assertEqual(pkt[IP].dst, type(self).mcast_ip4) - # Verify UDP destination port is GTPU 2152, source UDP port could be - # arbitrary. - self.assertEqual(pkt[UDP].dport, type(self).dport) - # Verify teid - self.assertEqual(pkt[GTP_U_Header].teid, vni) - - def test_encap(self): - """ Encapsulation test - Send frames from pg1 - Verify receipt of encapsulated frames on pg0 - """ - self.pg1.add_stream([self.frame_reply]) - - self.pg0.enable_capture() - - self.pg_start() - - # Pick first received frame and check if it's correctly encapsulated. - out = self.pg0.get_capture(1) - pkt = out[0] - self.check_encapsulation(pkt, self.single_tunnel_bd) - - # payload = self.decapsulate(pkt) - # self.assert_eq_pkts(payload, self.frame_reply) - - def test_ucast_flood(self): - """ Unicast flood test - Send frames from pg3 - Verify receipt of encapsulated frames on pg0 - """ - self.pg3.add_stream([self.frame_reply]) - - self.pg0.enable_capture() - - self.pg_start() - - # Get packet from each tunnel and assert it's correctly encapsulated. - out = self.pg0.get_capture(self.n_ucast_tunnels) - for pkt in out: - self.check_encapsulation(pkt, self.ucast_flood_bd, True) - # payload = self.decapsulate(pkt) - # self.assert_eq_pkts(payload, self.frame_reply) - - def test_mcast_flood(self): - """ Multicast flood test - Send frames from pg2 - Verify receipt of encapsulated frames on pg0 - """ - self.pg2.add_stream([self.frame_reply]) - - self.pg0.enable_capture() - - self.pg_start() - - # Pick first received frame and check if it's correctly encapsulated. - out = self.pg0.get_capture(1) - pkt = out[0] - self.check_encapsulation(pkt, self.mcast_flood_bd, - local_only=False, mcast_pkt=True) - - # payload = self.decapsulate(pkt) - # self.assert_eq_pkts(payload, self.frame_reply) - - @classmethod - def create_gtpu_flood_test_bd(cls, teid, n_ucast_tunnels): - # Create 10 ucast gtpu tunnels under bd - ip_range_start = 10 - ip_range_end = ip_range_start + n_ucast_tunnels - next_hop_address = cls.pg0.remote_ip4 - for dest_ip4 in ip4_range(next_hop_address, ip_range_start, - ip_range_end): - # add host route so dest_ip4n will not be resolved - rip = VppIpRoute(cls, dest_ip4, 32, - [VppRoutePath(next_hop_address, - INVALID_INDEX)], - register=False) - rip.add_vpp_config() - dest_ip4n = socket.inet_pton(socket.AF_INET, dest_ip4) - r = cls.vapi.gtpu_add_del_tunnel( - src_addr=cls.pg0.local_ip4n, - dst_addr=dest_ip4n, - teid=teid) - cls.vapi.sw_interface_set_l2_bridge(rx_sw_if_index=r.sw_if_index, - bd_id=teid) - - @classmethod - def add_del_shared_mcast_dst_load(cls, is_add): - """ - add or del tunnels sharing the same mcast dst - to test gtpu ref_count mechanism - """ - n_shared_dst_tunnels = 20 - teid_start = 1000 - teid_end = teid_start + n_shared_dst_tunnels - for teid in range(teid_start, teid_end): - r = cls.vapi.gtpu_add_del_tunnel( - src_addr=cls.pg0.local_ip4n, - dst_addr=cls.mcast_ip4n, - mcast_sw_if_index=1, - teid=teid, - is_add=is_add) - if r.sw_if_index == 0xffffffff: - raise ValueError("bad sw_if_index: ~0") - - @classmethod - def add_shared_mcast_dst_load(cls): - cls.add_del_shared_mcast_dst_load(is_add=1) - - @classmethod - def del_shared_mcast_dst_load(cls): - cls.add_del_shared_mcast_dst_load(is_add=0) - - @classmethod - def add_del_mcast_tunnels_load(cls, is_add): - """ - add or del tunnels to test gtpu stability - """ - n_distinct_dst_tunnels = 20 - ip_range_start = 10 - ip_range_end = ip_range_start + n_distinct_dst_tunnels - for dest_ip4n in ip4n_range(cls.mcast_ip4n, ip_range_start, - ip_range_end): - teid = bytearray(dest_ip4n)[3] - cls.vapi.gtpu_add_del_tunnel( - src_addr=cls.pg0.local_ip4n, - dst_addr=dest_ip4n, - mcast_sw_if_index=1, - teid=teid, - is_add=is_add) - - @classmethod - def add_mcast_tunnels_load(cls): - cls.add_del_mcast_tunnels_load(is_add=1) - - @classmethod - def del_mcast_tunnels_load(cls): - cls.add_del_mcast_tunnels_load(is_add=0) - - # Class method to start the GTPU test case. - # Overrides setUpClass method in VppTestCase class. - # Python try..except statement is used to ensure that the tear down of - # the class will be executed even if exception is raised. - # @param cls The class pointer. - @classmethod - def setUpClass(cls): - super(TestGtpu, cls).setUpClass() - - try: - cls.dport = 2152 - cls.gtp_type = 0xff - - # Create 2 pg interfaces. - cls.create_pg_interfaces(range(4)) - for pg in cls.pg_interfaces: - pg.admin_up() - - # Configure IPv4 addresses on VPP pg0. - cls.pg0.config_ip4() - - # Resolve MAC address for VPP's IP address on pg0. - cls.pg0.resolve_arp() - - # Our Multicast address - cls.mcast_ip4 = '239.1.1.1' - cls.mcast_ip4n = socket.inet_pton(socket.AF_INET, cls.mcast_ip4) - iplong = atol(cls.mcast_ip4) - cls.mcast_mac = "01:00:5e:%02x:%02x:%02x" % ( - (iplong >> 16) & 0x7F, (iplong >> 8) & 0xFF, iplong & 0xFF) - - # Create GTPU VTEP on VPP pg0, and put gtpu_tunnel0 and pg1 - # into BD. - cls.single_tunnel_bd = 11 - r = cls.vapi.gtpu_add_del_tunnel( - src_addr=cls.pg0.local_ip4n, - dst_addr=cls.pg0.remote_ip4n, - teid=cls.single_tunnel_bd) - cls.vapi.sw_interface_set_l2_bridge(rx_sw_if_index=r.sw_if_index, - bd_id=cls.single_tunnel_bd) - cls.vapi.sw_interface_set_l2_bridge( - rx_sw_if_index=cls.pg1.sw_if_index, bd_id=cls.single_tunnel_bd) - - # Setup teid 2 to test multicast flooding - cls.n_ucast_tunnels = 10 - cls.mcast_flood_bd = 12 - cls.create_gtpu_flood_test_bd(cls.mcast_flood_bd, - cls.n_ucast_tunnels) - r = cls.vapi.gtpu_add_del_tunnel( - src_addr=cls.pg0.local_ip4n, - dst_addr=cls.mcast_ip4n, - mcast_sw_if_index=1, - teid=cls.mcast_flood_bd) - cls.vapi.sw_interface_set_l2_bridge(rx_sw_if_index=r.sw_if_index, - bd_id=cls.mcast_flood_bd) - cls.vapi.sw_interface_set_l2_bridge( - rx_sw_if_index=cls.pg2.sw_if_index, bd_id=cls.mcast_flood_bd) - - # Add and delete mcast tunnels to check stability - cls.add_shared_mcast_dst_load() - cls.add_mcast_tunnels_load() - cls.del_shared_mcast_dst_load() - cls.del_mcast_tunnels_load() - - # Setup teid 3 to test unicast flooding - cls.ucast_flood_bd = 13 - cls.create_gtpu_flood_test_bd(cls.ucast_flood_bd, - cls.n_ucast_tunnels) - cls.vapi.sw_interface_set_l2_bridge( - rx_sw_if_index=cls.pg3.sw_if_index, bd_id=cls.ucast_flood_bd) - except Exception: - super(TestGtpu, cls).tearDownClass() - raise - - @classmethod - def tearDownClass(cls): - super(TestGtpu, cls).tearDownClass() - - # Method to define VPP actions before tear down of the test case. - # Overrides tearDown method in VppTestCase class. - # @param self The object pointer. - def tearDown(self): - super(TestGtpu, self).tearDown() - - def show_commands_at_teardown(self): - self.logger.info(self.vapi.cli("show bridge-domain 11 detail")) - self.logger.info(self.vapi.cli("show bridge-domain 12 detail")) - self.logger.info(self.vapi.cli("show bridge-domain 13 detail")) - self.logger.info(self.vapi.cli("show int")) - self.logger.info(self.vapi.cli("show gtpu tunnel")) - self.logger.info(self.vapi.cli("show trace")) - - -if __name__ == '__main__': - unittest.main(testRunner=VppTestRunner) diff --git a/test/test_igmp.py b/test/test_igmp.py deleted file mode 100644 index f1c49acba4c..00000000000 --- a/test/test_igmp.py +++ /dev/null @@ -1,834 +0,0 @@ -#!/usr/bin/env python - -import unittest - -from scapy.layers.l2 import Ether, Raw -from scapy.layers.inet import IP, IPOption -from scapy.contrib.igmpv3 import IGMPv3, IGMPv3gr, IGMPv3mq, IGMPv3mr - -from framework import VppTestCase, VppTestRunner, running_extended_tests -from vpp_igmp import find_igmp_state, IGMP_FILTER, IgmpRecord, IGMP_MODE, \ - IgmpSG, VppHostState, wait_for_igmp_event -from vpp_ip_route import find_mroute, VppIpTable - - -class IgmpMode: - HOST = 1 - ROUTER = 0 - - -class TestIgmp(VppTestCase): - """ IGMP Test Case """ - - @classmethod - def setUpClass(cls): - super(TestIgmp, cls).setUpClass() - - @classmethod - def tearDownClass(cls): - super(TestIgmp, cls).tearDownClass() - - def setUp(self): - super(TestIgmp, self).setUp() - - self.create_pg_interfaces(range(4)) - self.sg_list = [] - self.config_list = [] - - self.ip_addr = [] - self.ip_table = VppIpTable(self, 1) - self.ip_table.add_vpp_config() - - for pg in self.pg_interfaces[2:]: - pg.set_table_ip4(1) - for pg in self.pg_interfaces: - pg.admin_up() - pg.config_ip4() - pg.resolve_arp() - - def tearDown(self): - for pg in self.pg_interfaces: - self.vapi.igmp_clear_interface(pg.sw_if_index) - pg.unconfig_ip4() - pg.set_table_ip4(0) - pg.admin_down() - super(TestIgmp, self).tearDown() - - def send(self, ti, pkts): - ti.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - - def test_igmp_flush(self): - """ IGMP Link Up/down and Flush """ - - # - # FIX THIS. Link down. - # - - def test_igmp_enable(self): - """ IGMP enable/disable on an interface - - check for the addition/removal of the IGMP mroutes """ - - self.vapi.igmp_enable_disable(self.pg0.sw_if_index, 1, IGMP_MODE.HOST) - self.vapi.igmp_enable_disable(self.pg1.sw_if_index, 1, IGMP_MODE.HOST) - - self.assertTrue(find_mroute(self, "224.0.0.1", "0.0.0.0", 32)) - self.assertTrue(find_mroute(self, "224.0.0.22", "0.0.0.0", 32)) - - self.vapi.igmp_enable_disable(self.pg2.sw_if_index, 1, IGMP_MODE.HOST) - self.vapi.igmp_enable_disable(self.pg3.sw_if_index, 1, IGMP_MODE.HOST) - - self.assertTrue(find_mroute(self, "224.0.0.1", "0.0.0.0", 32, - table_id=1)) - self.assertTrue(find_mroute(self, "224.0.0.22", "0.0.0.0", 32, - table_id=1)) - self.vapi.igmp_enable_disable(self.pg0.sw_if_index, 0, IGMP_MODE.HOST) - self.vapi.igmp_enable_disable(self.pg1.sw_if_index, 0, IGMP_MODE.HOST) - self.vapi.igmp_enable_disable(self.pg2.sw_if_index, 0, IGMP_MODE.HOST) - self.vapi.igmp_enable_disable(self.pg3.sw_if_index, 0, IGMP_MODE.HOST) - - self.assertFalse(find_mroute(self, "224.0.0.1", "0.0.0.0", 32)) - self.assertFalse(find_mroute(self, "224.0.0.22", "0.0.0.0", 32)) - self.assertFalse(find_mroute(self, "224.0.0.1", "0.0.0.0", 32, - table_id=1)) - self.assertFalse(find_mroute(self, "224.0.0.22", "0.0.0.0", 32, - table_id=1)) - - def verify_general_query(self, p): - ip = p[IP] - self.assertEqual(len(ip.options), 1) - self.assertEqual(ip.options[0].option, 20) - self.assertEqual(ip.dst, "224.0.0.1") - self.assertEqual(ip.proto, 2) - igmp = p[IGMPv3] - self.assertEqual(igmp.type, 0x11) - self.assertEqual(igmp.gaddr, "0.0.0.0") - - def verify_group_query(self, p, grp, srcs): - ip = p[IP] - self.assertEqual(ip.dst, grp) - self.assertEqual(ip.proto, 2) - self.assertEqual(len(ip.options), 1) - self.assertEqual(ip.options[0].option, 20) - self.assertEqual(ip.proto, 2) - igmp = p[IGMPv3] - self.assertEqual(igmp.type, 0x11) - self.assertEqual(igmp.gaddr, grp) - - def verify_report(self, rx, records): - ip = rx[IP] - self.assertEqual(rx[IP].dst, "224.0.0.22") - self.assertEqual(len(ip.options), 1) - self.assertEqual(ip.options[0].option, 20) - self.assertEqual(ip.proto, 2) - self.assertEqual(IGMPv3.igmpv3types[rx[IGMPv3].type], - "Version 3 Membership Report") - self.assertEqual(rx[IGMPv3mr].numgrp, len(records)) - - received = rx[IGMPv3mr].records - - for ii in range(len(records)): - gr = received[ii] - r = records[ii] - self.assertEqual(IGMPv3gr.igmpv3grtypes[gr.rtype], r.type) - self.assertEqual(gr.numsrc, len(r.sg.saddrs)) - self.assertEqual(gr.maddr, r.sg.gaddr) - self.assertEqual(len(gr.srcaddrs), len(r.sg.saddrs)) - - self.assertEqual(sorted(gr.srcaddrs), - sorted(r.sg.saddrs)) - - def add_group(self, itf, sg, n_pkts=2): - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - - hs = VppHostState(self, - IGMP_FILTER.INCLUDE, - itf.sw_if_index, - sg) - hs.add_vpp_config() - - capture = itf.get_capture(n_pkts, timeout=10) - - # reports are transmitted twice due to default rebostness value=2 - self.verify_report(capture[0], - [IgmpRecord(sg, "Allow New Sources")]), - self.verify_report(capture[1], - [IgmpRecord(sg, "Allow New Sources")]), - - return hs - - def remove_group(self, hs): - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - hs.remove_vpp_config() - - capture = self.pg0.get_capture(1, timeout=10) - - self.verify_report(capture[0], - [IgmpRecord(hs.sg, "Block Old Sources")]) - - def test_igmp_host(self): - """ IGMP Host functions """ - - # - # Enable interface for host functions - # - self.vapi.igmp_enable_disable(self.pg0.sw_if_index, - 1, - IGMP_MODE.HOST) - - # - # Add one S,G of state and expect a state-change event report - # indicating the addition of the S,G - # - h1 = self.add_group(self.pg0, IgmpSG("239.1.1.1", ["1.1.1.1"])) - - # search for the corresponding state created in VPP - dump = self.vapi.igmp_dump(self.pg0.sw_if_index) - self.assertEqual(len(dump), 1) - self.assertTrue(find_igmp_state(dump, self.pg0, - "239.1.1.1", "1.1.1.1")) - - # - # Send a general query (to the all router's address) - # expect VPP to respond with a membership report. - # Pad the query with 0 - some devices in the big wild - # internet are prone to this. - # - p_g = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IP(src=self.pg0.remote_ip4, dst='224.0.0.1', tos=0xc0) / - IGMPv3(type="Membership Query", mrcode=100) / - IGMPv3mq(gaddr="0.0.0.0") / - Raw('\x00' * 10)) - - self.send(self.pg0, p_g) - - capture = self.pg0.get_capture(1, timeout=10) - self.verify_report(capture[0], - [IgmpRecord(h1.sg, "Mode Is Include")]) - - # - # Group specific query - # - p_gs = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IP(src=self.pg0.remote_ip4, dst='239.1.1.1', tos=0xc0, - options=[IPOption(copy_flag=1, optclass="control", - option="router_alert")]) / - IGMPv3(type="Membership Query", mrcode=100) / - IGMPv3mq(gaddr="239.1.1.1")) - - self.send(self.pg0, p_gs) - - capture = self.pg0.get_capture(1, timeout=10) - self.verify_report(capture[0], - [IgmpRecord(h1.sg, "Mode Is Include")]) - - # - # A group and source specific query, with the source matching - # the source VPP has - # - p_gs1 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IP(src=self.pg0.remote_ip4, dst='239.1.1.1', tos=0xc0, - options=[IPOption(copy_flag=1, optclass="control", - option="router_alert")]) / - IGMPv3(type="Membership Query", mrcode=100) / - IGMPv3mq(gaddr="239.1.1.1", srcaddrs=["1.1.1.1"])) - - self.send(self.pg0, p_gs1) - - capture = self.pg0.get_capture(1, timeout=10) - self.verify_report(capture[0], - [IgmpRecord(h1.sg, "Mode Is Include")]) - - # - # A group and source specific query that reports more sources - # than the packet actually has. - # - p_gs2 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IP(src=self.pg0.remote_ip4, dst='239.1.1.1', tos=0xc0, - options=[IPOption(copy_flag=1, optclass="control", - option="router_alert")]) / - IGMPv3(type="Membership Query", mrcode=100) / - IGMPv3mq(gaddr="239.1.1.1", numsrc=4, srcaddrs=["1.1.1.1"])) - - self.send_and_assert_no_replies(self.pg0, p_gs2, timeout=10) - - # - # A group and source specific query, with the source NOT matching - # the source VPP has. There should be no response. - # - p_gs2 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IP(src=self.pg0.remote_ip4, dst='239.1.1.1', tos=0xc0, - options=[IPOption(copy_flag=1, optclass="control", - option="router_alert")]) / - IGMPv3(type="Membership Query", mrcode=100) / - IGMPv3mq(gaddr="239.1.1.1", srcaddrs=["1.1.1.2"])) - - self.send_and_assert_no_replies(self.pg0, p_gs2, timeout=10) - - # - # A group and source specific query, with the multiple sources - # one of which matches the source VPP has. - # The report should contain only the source VPP has. - # - p_gs3 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IP(src=self.pg0.remote_ip4, dst='239.1.1.1', tos=0xc0, - options=[IPOption(copy_flag=1, optclass="control", - option="router_alert")]) / - IGMPv3(type="Membership Query", mrcode=100) / - IGMPv3mq(gaddr="239.1.1.1", - srcaddrs=["1.1.1.1", "1.1.1.2", "1.1.1.3"])) - - self.send(self.pg0, p_gs3) - - capture = self.pg0.get_capture(1, timeout=10) - self.verify_report(capture[0], - [IgmpRecord(h1.sg, "Mode Is Include")]) - - # - # Two source and group specific queries in quick succession, the - # first does not have VPPs source the second does. then vice-versa - # - self.send(self.pg0, [p_gs2, p_gs1]) - capture = self.pg0.get_capture(1, timeout=10) - self.verify_report(capture[0], - [IgmpRecord(h1.sg, "Mode Is Include")]) - - self.send(self.pg0, [p_gs1, p_gs2]) - capture = self.pg0.get_capture(1, timeout=10) - self.verify_report(capture[0], - [IgmpRecord(h1.sg, "Mode Is Include")]) - - # - # remove state, expect the report for the removal - # - self.remove_group(h1) - - dump = self.vapi.igmp_dump() - self.assertFalse(dump) - - # - # A group with multiple sources - # - h2 = self.add_group(self.pg0, - IgmpSG("239.1.1.1", - ["1.1.1.1", "1.1.1.2", "1.1.1.3"])) - - # search for the corresponding state created in VPP - dump = self.vapi.igmp_dump(self.pg0.sw_if_index) - self.assertEqual(len(dump), 3) - for s in h2.sg.saddrs: - self.assertTrue(find_igmp_state(dump, self.pg0, - "239.1.1.1", s)) - # - # Send a general query (to the all router's address) - # expect VPP to respond with a membership report will all sources - # - self.send(self.pg0, p_g) - - capture = self.pg0.get_capture(1, timeout=10) - self.verify_report(capture[0], - [IgmpRecord(h2.sg, "Mode Is Include")]) - - # - # Group and source specific query; some present some not - # - p_gs = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IP(src=self.pg0.remote_ip4, dst='239.1.1.1', tos=0xc0, - options=[IPOption(copy_flag=1, optclass="control", - option="router_alert")]) / - IGMPv3(type="Membership Query", mrcode=100) / - IGMPv3mq(gaddr="239.1.1.1", - srcaddrs=["1.1.1.1", "1.1.1.2", "1.1.1.4"])) - - self.send(self.pg0, p_gs) - - capture = self.pg0.get_capture(1, timeout=10) - self.verify_report(capture[0], - [IgmpRecord( - IgmpSG('239.1.1.1', ["1.1.1.1", "1.1.1.2"]), - "Mode Is Include")]) - - # - # add loads more groups - # - h3 = self.add_group(self.pg0, - IgmpSG("239.1.1.2", - ["2.1.1.1", "2.1.1.2", "2.1.1.3"])) - h4 = self.add_group(self.pg0, - IgmpSG("239.1.1.3", - ["3.1.1.1", "3.1.1.2", "3.1.1.3"])) - h5 = self.add_group(self.pg0, - IgmpSG("239.1.1.4", - ["4.1.1.1", "4.1.1.2", "4.1.1.3"])) - h6 = self.add_group(self.pg0, - IgmpSG("239.1.1.5", - ["5.1.1.1", "5.1.1.2", "5.1.1.3"])) - h7 = self.add_group(self.pg0, - IgmpSG("239.1.1.6", - ["6.1.1.1", "6.1.1.2", - "6.1.1.3", "6.1.1.4", - "6.1.1.5", "6.1.1.6", - "6.1.1.7", "6.1.1.8", - "6.1.1.9", "6.1.1.10", - "6.1.1.11", "6.1.1.12", - "6.1.1.13", "6.1.1.14", - "6.1.1.15", "6.1.1.16"])) - - # - # general query. - # the order the groups come in is not important, so what is - # checked for is what VPP is sending today. - # - self.send(self.pg0, p_g) - - capture = self.pg0.get_capture(1, timeout=10) - - self.verify_report(capture[0], - [IgmpRecord(h3.sg, "Mode Is Include"), - IgmpRecord(h2.sg, "Mode Is Include"), - IgmpRecord(h6.sg, "Mode Is Include"), - IgmpRecord(h4.sg, "Mode Is Include"), - IgmpRecord(h5.sg, "Mode Is Include"), - IgmpRecord(h7.sg, "Mode Is Include")]) - - # - # modify a group to add and remove some sources - # - h7.sg = IgmpSG("239.1.1.6", - ["6.1.1.1", "6.1.1.2", - "6.1.1.5", "6.1.1.6", - "6.1.1.7", "6.1.1.8", - "6.1.1.9", "6.1.1.10", - "6.1.1.11", "6.1.1.12", - "6.1.1.13", "6.1.1.14", - "6.1.1.15", "6.1.1.16", - "6.1.1.17", "6.1.1.18"]) - - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - h7.add_vpp_config() - - capture = self.pg0.get_capture(1, timeout=10) - self.verify_report(capture[0], - [IgmpRecord(IgmpSG("239.1.1.6", - ["6.1.1.17", "6.1.1.18"]), - "Allow New Sources"), - IgmpRecord(IgmpSG("239.1.1.6", - ["6.1.1.3", "6.1.1.4"]), - "Block Old Sources")]) - - # - # add an additional groups with many sources so that each group - # consumes the link MTU. We should therefore see multiple state - # state reports when queried. - # - self.vapi.sw_interface_set_mtu(self.pg0.sw_if_index, [560, 0, 0, 0]) - - src_list = [] - for i in range(128): - src_list.append("10.1.1.%d" % i) - - h8 = self.add_group(self.pg0, - IgmpSG("238.1.1.1", src_list)) - h9 = self.add_group(self.pg0, - IgmpSG("238.1.1.2", src_list)) - - self.send(self.pg0, p_g) - - capture = self.pg0.get_capture(4, timeout=10) - - self.verify_report(capture[0], - [IgmpRecord(h3.sg, "Mode Is Include"), - IgmpRecord(h2.sg, "Mode Is Include"), - IgmpRecord(h6.sg, "Mode Is Include"), - IgmpRecord(h4.sg, "Mode Is Include"), - IgmpRecord(h5.sg, "Mode Is Include")]) - self.verify_report(capture[1], - [IgmpRecord(h8.sg, "Mode Is Include")]) - self.verify_report(capture[2], - [IgmpRecord(h7.sg, "Mode Is Include")]) - self.verify_report(capture[3], - [IgmpRecord(h9.sg, "Mode Is Include")]) - - # - # drop the MTU further (so a 128 sized group won't fit) - # - self.vapi.sw_interface_set_mtu(self.pg0.sw_if_index, [512, 0, 0, 0]) - - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - - h10 = VppHostState(self, - IGMP_FILTER.INCLUDE, - self.pg0.sw_if_index, - IgmpSG("238.1.1.3", src_list)) - h10.add_vpp_config() - - capture = self.pg0.get_capture(2, timeout=10) - # wait for a little bit - self.sleep(1) - - # - # remove state, expect the report for the removal - # the dump should be empty - # - self.vapi.sw_interface_set_mtu(self.pg0.sw_if_index, [600, 0, 0, 0]) - self.remove_group(h8) - self.remove_group(h9) - self.remove_group(h2) - self.remove_group(h3) - self.remove_group(h4) - self.remove_group(h5) - self.remove_group(h6) - self.remove_group(h7) - self.remove_group(h10) - - self.logger.info(self.vapi.cli("sh igmp config")) - self.assertFalse(self.vapi.igmp_dump()) - - # - # TODO - # ADD STATE ON MORE INTERFACES - # - - self.vapi.igmp_enable_disable(self.pg0.sw_if_index, - 0, - IGMP_MODE.HOST) - - def test_igmp_router(self): - """ IGMP Router Functions """ - - # - # Drop reports when not enabled - # - p_j = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IP(src=self.pg0.remote_ip4, dst="224.0.0.22", tos=0xc0, ttl=1, - options=[IPOption(copy_flag=1, optclass="control", - option="router_alert")]) / - IGMPv3(type="Version 3 Membership Report") / - IGMPv3mr(numgrp=1) / - IGMPv3gr(rtype="Allow New Sources", - maddr="239.1.1.1", srcaddrs=["10.1.1.1", "10.1.1.2"])) - p_l = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IP(src=self.pg0.remote_ip4, dst="224.0.0.22", tos=0xc0, - options=[IPOption(copy_flag=1, optclass="control", - option="router_alert")]) / - IGMPv3(type="Version 3 Membership Report") / - IGMPv3mr(numgrp=1) / - IGMPv3gr(rtype="Block Old Sources", - maddr="239.1.1.1", srcaddrs=["10.1.1.1", "10.1.1.2"])) - - self.send(self.pg0, p_j) - self.assertFalse(self.vapi.igmp_dump()) - - # - # drop the default timer values so these tests execute in a - # reasonable time frame - # - self.vapi.cli("test igmp timers query 1 src 3 leave 1") - - # - # enable router functions on the interface - # - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - self.vapi.igmp_enable_disable(self.pg0.sw_if_index, - 1, - IGMP_MODE.ROUTER) - self.vapi.want_igmp_events(1) - - # - # wait for router to send general query - # - for ii in range(3): - capture = self.pg0.get_capture(1, timeout=2) - self.verify_general_query(capture[0]) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - - # - # re-send the report. VPP should now hold state for the new group - # VPP sends a notification that a new group has been joined - # - self.send(self.pg0, p_j) - - self.assertTrue(wait_for_igmp_event(self, 1, self.pg0, - "239.1.1.1", "10.1.1.1", 1)) - self.assertTrue(wait_for_igmp_event(self, 1, self.pg0, - "239.1.1.1", "10.1.1.2", 1)) - dump = self.vapi.igmp_dump(self.pg0.sw_if_index) - self.assertEqual(len(dump), 2) - self.assertTrue(find_igmp_state(dump, self.pg0, - "239.1.1.1", "10.1.1.1")) - self.assertTrue(find_igmp_state(dump, self.pg0, - "239.1.1.1", "10.1.1.2")) - - # - # wait for the per-source timer to expire - # the state should be reaped - # VPP sends a notification that the group has been left - # - self.assertTrue(wait_for_igmp_event(self, 4, self.pg0, - "239.1.1.1", "10.1.1.1", 0)) - self.assertTrue(wait_for_igmp_event(self, 1, self.pg0, - "239.1.1.1", "10.1.1.2", 0)) - self.assertFalse(self.vapi.igmp_dump()) - - # - # resend the join. wait for two queries and then send a current-state - # record to include all sources. this should reset the expiry time - # on the sources and thus they will still be present in 2 seconds time. - # If the source timer was not refreshed, then the state would have - # expired in 3 seconds. - # - self.send(self.pg0, p_j) - self.assertTrue(wait_for_igmp_event(self, 1, self.pg0, - "239.1.1.1", "10.1.1.1", 1)) - self.assertTrue(wait_for_igmp_event(self, 1, self.pg0, - "239.1.1.1", "10.1.1.2", 1)) - dump = self.vapi.igmp_dump(self.pg0.sw_if_index) - self.assertEqual(len(dump), 2) - - capture = self.pg0.get_capture(2, timeout=3) - self.verify_general_query(capture[0]) - self.verify_general_query(capture[1]) - - p_cs = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IP(src=self.pg0.remote_ip4, dst="224.0.0.22", tos=0xc0, - options=[IPOption(copy_flag=1, optclass="control", - option="router_alert")]) / - IGMPv3(type="Version 3 Membership Report") / - IGMPv3mr(numgrp=1) / - IGMPv3gr(rtype="Mode Is Include", - maddr="239.1.1.1", srcaddrs=["10.1.1.1", "10.1.1.2"])) - - self.send(self.pg0, p_cs) - - self.sleep(2) - dump = self.vapi.igmp_dump(self.pg0.sw_if_index) - self.assertEqual(len(dump), 2) - self.assertTrue(find_igmp_state(dump, self.pg0, - "239.1.1.1", "10.1.1.1")) - self.assertTrue(find_igmp_state(dump, self.pg0, - "239.1.1.1", "10.1.1.2")) - - # - # wait for the per-source timer to expire - # the state should be reaped - # - self.assertTrue(wait_for_igmp_event(self, 4, self.pg0, - "239.1.1.1", "10.1.1.1", 0)) - self.assertTrue(wait_for_igmp_event(self, 1, self.pg0, - "239.1.1.1", "10.1.1.2", 0)) - self.assertFalse(self.vapi.igmp_dump()) - - # - # resend the join, then a leave. Router sends a group+source - # specific query containing both sources - # - self.send(self.pg0, p_j) - - self.assertTrue(wait_for_igmp_event(self, 1, self.pg0, - "239.1.1.1", "10.1.1.1", 1)) - self.assertTrue(wait_for_igmp_event(self, 1, self.pg0, - "239.1.1.1", "10.1.1.2", 1)) - dump = self.vapi.igmp_dump(self.pg0.sw_if_index) - self.assertEqual(len(dump), 2) - - self.send(self.pg0, p_l) - capture = self.pg0.get_capture(1, timeout=3) - self.verify_group_query(capture[0], "239.1.1.1", - ["10.1.1.1", "10.1.1.2"]) - - # - # the group specific query drops the timeout to leave (=1) seconds - # - self.assertTrue(wait_for_igmp_event(self, 2, self.pg0, - "239.1.1.1", "10.1.1.1", 0)) - self.assertTrue(wait_for_igmp_event(self, 1, self.pg0, - "239.1.1.1", "10.1.1.2", 0)) - self.assertFalse(self.vapi.igmp_dump()) - self.assertFalse(self.vapi.igmp_dump()) - - # - # a TO_EX({}) / IN_EX({}) is treated like a (*,G) join - # - p_j = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IP(src=self.pg0.remote_ip4, dst="224.0.0.22", tos=0xc0, ttl=1, - options=[IPOption(copy_flag=1, optclass="control", - option="router_alert")]) / - IGMPv3(type="Version 3 Membership Report") / - IGMPv3mr(numgrp=1) / - IGMPv3gr(rtype="Change To Exclude Mode", maddr="239.1.1.2")) - - self.send(self.pg0, p_j) - - self.assertTrue(wait_for_igmp_event(self, 1, self.pg0, - "239.1.1.2", "0.0.0.0", 1)) - - p_j = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IP(src=self.pg0.remote_ip4, dst="224.0.0.22", tos=0xc0, ttl=1, - options=[IPOption(copy_flag=1, optclass="control", - option="router_alert")]) / - IGMPv3(type="Version 3 Membership Report") / - IGMPv3mr(numgrp=1) / - IGMPv3gr(rtype="Mode Is Exclude", maddr="239.1.1.3")) - - self.send(self.pg0, p_j) - - self.assertTrue(wait_for_igmp_event(self, 1, self.pg0, - "239.1.1.3", "0.0.0.0", 1)) - - # - # A 'allow sources' for {} should be ignored as it should - # never be sent. - # - p_j = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IP(src=self.pg0.remote_ip4, dst="224.0.0.22", tos=0xc0, ttl=1, - options=[IPOption(copy_flag=1, optclass="control", - option="router_alert")]) / - IGMPv3(type="Version 3 Membership Report") / - IGMPv3mr(numgrp=1) / - IGMPv3gr(rtype="Allow New Sources", maddr="239.1.1.4")) - - self.send(self.pg0, p_j) - - dump = self.vapi.igmp_dump(self.pg0.sw_if_index) - self.assertTrue(find_igmp_state(dump, self.pg0, - "239.1.1.2", "0.0.0.0")) - self.assertTrue(find_igmp_state(dump, self.pg0, - "239.1.1.3", "0.0.0.0")) - self.assertFalse(find_igmp_state(dump, self.pg0, - "239.1.1.4", "0.0.0.0")) - - # - # a TO_IN({}) and IS_IN({}) are treated like a (*,G) leave - # - self.vapi.cli("set logging class igmp level debug") - p_l = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IP(src=self.pg0.remote_ip4, dst="224.0.0.22", tos=0xc0, ttl=1, - options=[IPOption(copy_flag=1, optclass="control", - option="router_alert")]) / - IGMPv3(type="Version 3 Membership Report") / - IGMPv3mr(numgrp=1) / - IGMPv3gr(rtype="Change To Include Mode", maddr="239.1.1.2")) - - self.send(self.pg0, p_l) - self.assertTrue(wait_for_igmp_event(self, 2, self.pg0, - "239.1.1.2", "0.0.0.0", 0)) - - p_l = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IP(src=self.pg0.remote_ip4, dst="224.0.0.22", tos=0xc0, ttl=1, - options=[IPOption(copy_flag=1, optclass="control", - option="router_alert")]) / - IGMPv3(type="Version 3 Membership Report") / - IGMPv3mr(numgrp=1) / - IGMPv3gr(rtype="Mode Is Include", maddr="239.1.1.3")) - - self.send(self.pg0, p_l) - - self.assertTrue(wait_for_igmp_event(self, 2, self.pg0, - "239.1.1.3", "0.0.0.0", 0)) - self.assertFalse(self.vapi.igmp_dump(self.pg0.sw_if_index)) - - # - # disable router config - # - self.vapi.igmp_enable_disable(self.pg0.sw_if_index, - 0, - IGMP_MODE.ROUTER) - - def _create_igmpv3_pck(self, itf, rtype, maddr, srcaddrs): - p = (Ether(dst=itf.local_mac, src=itf.remote_mac) / - IP(src=itf.remote_ip4, dst="224.0.0.22", tos=0xc0, ttl=1, - options=[IPOption(copy_flag=1, optclass="control", - option="router_alert")]) / - IGMPv3(type="Version 3 Membership Report") / - IGMPv3mr(numgrp=1) / - IGMPv3gr(rtype=rtype, - maddr=maddr, srcaddrs=srcaddrs)) - return p - - def test_igmp_proxy_device(self): - """ IGMP proxy device """ - self.pg2.admin_down() - self.pg2.unconfig_ip4() - self.pg2.set_table_ip4(0) - self.pg2.config_ip4() - self.pg2.admin_up() - - self.vapi.cli('test igmp timers query 10 src 3 leave 1') - - # enable IGMP - self.vapi.igmp_enable_disable(self.pg0.sw_if_index, 1, IGMP_MODE.HOST) - self.vapi.igmp_enable_disable(self.pg1.sw_if_index, 1, - IGMP_MODE.ROUTER) - self.vapi.igmp_enable_disable(self.pg2.sw_if_index, 1, - IGMP_MODE.ROUTER) - - # create IGMP proxy device - self.vapi.igmp_proxy_device_add_del(0, self.pg0.sw_if_index, 1) - self.vapi.igmp_proxy_device_add_del_interface(0, - self.pg1.sw_if_index, 1) - self.vapi.igmp_proxy_device_add_del_interface(0, - self.pg2.sw_if_index, 1) - - # send join on pg1. join should be proxied by pg0 - p_j = self._create_igmpv3_pck(self.pg1, "Allow New Sources", - "239.1.1.1", ["10.1.1.1", "10.1.1.2"]) - self.send(self.pg1, p_j) - - capture = self.pg0.get_capture(1, timeout=1) - self.verify_report(capture[0], [IgmpRecord(IgmpSG("239.1.1.1", - ["10.1.1.1", "10.1.1.2"]), "Allow New Sources")]) - self.assertTrue(find_mroute(self, "239.1.1.1", "0.0.0.0", 32)) - - # send join on pg2. join should be proxied by pg0. - # the group should contain only 10.1.1.3 as - # 10.1.1.1 was already reported - p_j = self._create_igmpv3_pck(self.pg2, "Allow New Sources", - "239.1.1.1", ["10.1.1.1", "10.1.1.3"]) - self.send(self.pg2, p_j) - - capture = self.pg0.get_capture(1, timeout=1) - self.verify_report(capture[0], [IgmpRecord(IgmpSG("239.1.1.1", - ["10.1.1.3"]), "Allow New Sources")]) - self.assertTrue(find_mroute(self, "239.1.1.1", "0.0.0.0", 32)) - - # send leave on pg2. leave for 10.1.1.3 should be proxyed - # as pg2 was the only interface interested in 10.1.1.3 - p_l = self._create_igmpv3_pck(self.pg2, "Block Old Sources", - "239.1.1.1", ["10.1.1.3"]) - self.send(self.pg2, p_l) - - capture = self.pg0.get_capture(1, timeout=2) - self.verify_report(capture[0], [IgmpRecord(IgmpSG("239.1.1.1", - ["10.1.1.3"]), "Block Old Sources")]) - self.assertTrue(find_mroute(self, "239.1.1.1", "0.0.0.0", 32)) - - # disable igmp on pg1 (also removes interface from proxy device) - # proxy leave for 10.1.1.2. pg2 is still interested in 10.1.1.1 - self.pg_enable_capture(self.pg_interfaces) - self.vapi.igmp_enable_disable(self.pg1.sw_if_index, 0, - IGMP_MODE.ROUTER) - - capture = self.pg0.get_capture(1, timeout=1) - self.verify_report(capture[0], [IgmpRecord(IgmpSG("239.1.1.1", - ["10.1.1.2"]), "Block Old Sources")]) - self.assertTrue(find_mroute(self, "239.1.1.1", "0.0.0.0", 32)) - - # disable IGMP on pg0 and pg1. - # disabling IGMP on pg0 (proxy device upstream interface) - # removes this proxy device - self.vapi.igmp_enable_disable(self.pg0.sw_if_index, 0, IGMP_MODE.HOST) - self.vapi.igmp_enable_disable(self.pg2.sw_if_index, 0, - IGMP_MODE.ROUTER) - self.assertFalse(find_mroute(self, "239.1.1.1", "0.0.0.0", 32)) - - -if __name__ == '__main__': - unittest.main(testRunner=VppTestRunner) diff --git a/test/test_ipsec_nat.py b/test/test_ipsec_nat.py deleted file mode 100644 index 07670d71b03..00000000000 --- a/test/test_ipsec_nat.py +++ /dev/null @@ -1,271 +0,0 @@ -#!/usr/bin/env python - -import socket - -import scapy.compat -from scapy.layers.l2 import Ether -from scapy.layers.inet import ICMP, IP, TCP, UDP -from scapy.layers.ipsec import SecurityAssociation, ESP - -from util import ppp, ppc -from template_ipsec import TemplateIpsec -from vpp_ipsec import VppIpsecSA, VppIpsecSpd, VppIpsecSpdEntry,\ - VppIpsecSpdItfBinding -from vpp_ip_route import VppIpRoute, VppRoutePath -from vpp_ip import DpoProto -from vpp_papi import VppEnum - - -class IPSecNATTestCase(TemplateIpsec): - """ IPSec/NAT - TUNNEL MODE: - - - public network | private network - --- encrypt --- plain --- - |pg0| <------- |VPP| <------ |pg1| - --- --- --- - - --- decrypt --- plain --- - |pg0| -------> |VPP| ------> |pg1| - --- --- --- - """ - - tcp_port_in = 6303 - tcp_port_out = 6303 - udp_port_in = 6304 - udp_port_out = 6304 - icmp_id_in = 6305 - icmp_id_out = 6305 - - @classmethod - def setUpClass(cls): - super(IPSecNATTestCase, cls).setUpClass() - - @classmethod - def tearDownClass(cls): - super(IPSecNATTestCase, cls).tearDownClass() - - def setUp(self): - super(IPSecNATTestCase, self).setUp() - self.tun_if = self.pg0 - - self.tun_spd = VppIpsecSpd(self, self.tun_spd_id) - self.tun_spd.add_vpp_config() - VppIpsecSpdItfBinding(self, self.tun_spd, - self.tun_if).add_vpp_config() - - p = self.ipv4_params - self.config_esp_tun(p) - self.logger.info(self.vapi.ppcli("show ipsec all")) - - d = DpoProto.DPO_PROTO_IP6 if p.is_ipv6 else DpoProto.DPO_PROTO_IP4 - VppIpRoute(self, p.remote_tun_if_host, p.addr_len, - [VppRoutePath(self.tun_if.remote_addr[p.addr_type], - 0xffffffff, - proto=d)]).add_vpp_config() - - def tearDown(self): - super(IPSecNATTestCase, self).tearDown() - - def create_stream_plain(self, src_mac, dst_mac, src_ip, dst_ip): - return [ - # TCP - Ether(src=src_mac, dst=dst_mac) / - IP(src=src_ip, dst=dst_ip) / - TCP(sport=self.tcp_port_in, dport=20), - # UDP - Ether(src=src_mac, dst=dst_mac) / - IP(src=src_ip, dst=dst_ip) / - UDP(sport=self.udp_port_in, dport=20), - # ICMP - Ether(src=src_mac, dst=dst_mac) / - IP(src=src_ip, dst=dst_ip) / - ICMP(id=self.icmp_id_in, type='echo-request') - ] - - def create_stream_encrypted(self, src_mac, dst_mac, src_ip, dst_ip, sa): - return [ - # TCP - Ether(src=src_mac, dst=dst_mac) / - sa.encrypt(IP(src=src_ip, dst=dst_ip) / - TCP(dport=self.tcp_port_out, sport=20)), - # UDP - Ether(src=src_mac, dst=dst_mac) / - sa.encrypt(IP(src=src_ip, dst=dst_ip) / - UDP(dport=self.udp_port_out, sport=20)), - # ICMP - Ether(src=src_mac, dst=dst_mac) / - sa.encrypt(IP(src=src_ip, dst=dst_ip) / - ICMP(id=self.icmp_id_out, type='echo-request')) - ] - - def verify_capture_plain(self, capture): - for packet in capture: - try: - self.assert_packet_checksums_valid(packet) - self.assert_equal(packet[IP].src, self.tun_if.remote_ip4, - "decrypted packet source address") - self.assert_equal(packet[IP].dst, self.pg1.remote_ip4, - "decrypted packet destination address") - if packet.haslayer(TCP): - self.assertFalse( - packet.haslayer(UDP), - "unexpected UDP header in decrypted packet") - self.assert_equal(packet[TCP].dport, self.tcp_port_in, - "decrypted packet TCP destination port") - elif packet.haslayer(UDP): - if packet[UDP].payload: - self.assertFalse( - packet[UDP][1].haslayer(UDP), - "unexpected UDP header in decrypted packet") - self.assert_equal(packet[UDP].dport, self.udp_port_in, - "decrypted packet UDP destination port") - else: - self.assertFalse( - packet.haslayer(UDP), - "unexpected UDP header in decrypted packet") - self.assert_equal(packet[ICMP].id, self.icmp_id_in, - "decrypted packet ICMP ID") - except Exception: - self.logger.error( - ppp("Unexpected or invalid plain packet:", packet)) - raise - - def verify_capture_encrypted(self, capture, sa): - for packet in capture: - try: - copy = packet.__class__(scapy.compat.raw(packet)) - del copy[UDP].len - copy = packet.__class__(scapy.compat.raw(copy)) - self.assert_equal(packet[UDP].len, copy[UDP].len, - "UDP header length") - self.assert_packet_checksums_valid(packet) - self.assertIn(ESP, packet[IP]) - decrypt_pkt = sa.decrypt(packet[IP]) - self.assert_packet_checksums_valid(decrypt_pkt) - self.assert_equal(decrypt_pkt[IP].src, self.pg1.remote_ip4, - "encrypted packet source address") - self.assert_equal(decrypt_pkt[IP].dst, self.tun_if.remote_ip4, - "encrypted packet destination address") - except Exception: - self.logger.error( - ppp("Unexpected or invalid encrypted packet:", packet)) - raise - - def config_esp_tun(self, params): - addr_type = params.addr_type - scapy_tun_sa_id = params.scapy_tun_sa_id - scapy_tun_spi = params.scapy_tun_spi - vpp_tun_sa_id = params.vpp_tun_sa_id - vpp_tun_spi = params.vpp_tun_spi - auth_algo_vpp_id = params.auth_algo_vpp_id - auth_key = params.auth_key - crypt_algo_vpp_id = params.crypt_algo_vpp_id - crypt_key = params.crypt_key - addr_any = params.addr_any - addr_bcast = params.addr_bcast - flags = (VppEnum.vl_api_ipsec_sad_flags_t. - IPSEC_API_SAD_FLAG_UDP_ENCAP) - e = VppEnum.vl_api_ipsec_spd_action_t - - VppIpsecSA(self, scapy_tun_sa_id, scapy_tun_spi, - auth_algo_vpp_id, auth_key, - crypt_algo_vpp_id, crypt_key, - self.vpp_esp_protocol, - self.pg1.remote_addr[addr_type], - self.tun_if.remote_addr[addr_type], - flags=flags).add_vpp_config() - VppIpsecSA(self, vpp_tun_sa_id, vpp_tun_spi, - auth_algo_vpp_id, auth_key, - crypt_algo_vpp_id, crypt_key, - self.vpp_esp_protocol, - self.tun_if.remote_addr[addr_type], - self.pg1.remote_addr[addr_type], - flags=flags).add_vpp_config() - - VppIpsecSpdEntry(self, self.tun_spd, scapy_tun_sa_id, - addr_any, addr_bcast, - addr_any, addr_bcast, - socket.IPPROTO_ESP).add_vpp_config() - VppIpsecSpdEntry(self, self.tun_spd, scapy_tun_sa_id, - addr_any, addr_bcast, - addr_any, addr_bcast, - socket.IPPROTO_ESP, - is_outbound=0).add_vpp_config() - VppIpsecSpdEntry(self, self.tun_spd, scapy_tun_sa_id, - addr_any, addr_bcast, - addr_any, addr_bcast, - socket.IPPROTO_UDP, - remote_port_start=4500, - remote_port_stop=4500).add_vpp_config() - VppIpsecSpdEntry(self, self.tun_spd, scapy_tun_sa_id, - addr_any, addr_bcast, - addr_any, addr_bcast, - socket.IPPROTO_UDP, - remote_port_start=4500, - remote_port_stop=4500, - is_outbound=0).add_vpp_config() - VppIpsecSpdEntry(self, self.tun_spd, vpp_tun_sa_id, - self.tun_if.remote_addr[addr_type], - self.tun_if.remote_addr[addr_type], - self.pg1.remote_addr[addr_type], - self.pg1.remote_addr[addr_type], - 0, priority=10, - policy=e.IPSEC_API_SPD_ACTION_PROTECT, - is_outbound=0).add_vpp_config() - VppIpsecSpdEntry(self, self.tun_spd, scapy_tun_sa_id, - self.pg1.remote_addr[addr_type], - self.pg1.remote_addr[addr_type], - self.tun_if.remote_addr[addr_type], - self.tun_if.remote_addr[addr_type], - 0, policy=e.IPSEC_API_SPD_ACTION_PROTECT, - priority=10).add_vpp_config() - - def test_ipsec_nat_tun(self): - """ IPSec/NAT tunnel test case """ - p = self.ipv4_params - scapy_tun_sa = SecurityAssociation(ESP, spi=p.scapy_tun_spi, - crypt_algo=p.crypt_algo, - crypt_key=p.crypt_key, - auth_algo=p.auth_algo, - auth_key=p.auth_key, - tunnel_header=IP( - src=self.pg1.remote_ip4, - dst=self.tun_if.remote_ip4), - nat_t_header=UDP( - sport=4500, - dport=4500)) - # in2out - from private network to public - pkts = self.create_stream_plain( - self.pg1.remote_mac, self.pg1.local_mac, - self.pg1.remote_ip4, self.tun_if.remote_ip4) - self.pg1.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.tun_if.get_capture(len(pkts)) - self.verify_capture_encrypted(capture, scapy_tun_sa) - - vpp_tun_sa = SecurityAssociation(ESP, - spi=p.vpp_tun_spi, - crypt_algo=p.crypt_algo, - crypt_key=p.crypt_key, - auth_algo=p.auth_algo, - auth_key=p.auth_key, - tunnel_header=IP( - src=self.tun_if.remote_ip4, - dst=self.pg1.remote_ip4), - nat_t_header=UDP( - sport=4500, - dport=4500)) - - # out2in - from public network to private - pkts = self.create_stream_encrypted( - self.tun_if.remote_mac, self.tun_if.local_mac, - self.tun_if.remote_ip4, self.pg1.remote_ip4, vpp_tun_sa) - self.logger.info(ppc("Sending packets:", pkts)) - self.tun_if.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg1.get_capture(len(pkts)) - self.verify_capture_plain(capture) diff --git a/test/test_l3xc.py b/test/test_l3xc.py deleted file mode 100644 index 696e23507ac..00000000000 --- a/test/test_l3xc.py +++ /dev/null @@ -1,153 +0,0 @@ -#!/usr/bin/env python - -from socket import inet_pton, inet_ntop, AF_INET, AF_INET6 -import unittest - -from framework import VppTestCase, VppTestRunner -from vpp_ip import DpoProto -from vpp_ip_route import VppIpRoute, VppRoutePath, VppMplsLabel, VppIpTable - -from scapy.packet import Raw -from scapy.layers.l2 import Ether -from scapy.layers.inet import IP, UDP -from scapy.layers.inet6 import IPv6 - -from vpp_object import VppObject - -NUM_PKTS = 67 - - -def find_l3xc(test, sw_if_index, dump_sw_if_index=None): - if not dump_sw_if_index: - dump_sw_if_index = sw_if_index - xcs = test.vapi.l3xc_dump(dump_sw_if_index) - for xc in xcs: - if sw_if_index == xc.l3xc.sw_if_index: - return True - return False - - -class VppL3xc(VppObject): - - def __init__(self, test, intf, paths, is_ip6=False): - self._test = test - self.intf = intf - self.is_ip6 = is_ip6 - self.paths = paths - self.encoded_paths = [] - for path in self.paths: - self.encoded_paths.append(path.encode()) - - def add_vpp_config(self): - self._test.vapi.l3xc_update( - l3xc={ - 'is_ip6': self.is_ip6, - 'sw_if_index': self.intf.sw_if_index, - 'n_paths': len(self.paths), - 'paths': self.encoded_paths - }) - self._test.registry.register(self, self._test.logger) - - def remove_vpp_config(self): - self._test.vapi.l3xc_del( - is_ip6=self.is_ip6, - sw_if_index=self.intf.sw_if_index) - - def query_vpp_config(self): - return find_l3xc(self._test, self.intf.sw_if_index) - - def object_id(self): - return ("l3xc-%d" % self.intf.sw_if_index) - - -class TestL3xc(VppTestCase): - """ L3XC Test Case """ - - @classmethod - def setUpClass(cls): - super(TestL3xc, cls).setUpClass() - - @classmethod - def tearDownClass(cls): - super(TestL3xc, cls).tearDownClass() - - def setUp(self): - super(TestL3xc, self).setUp() - - self.create_pg_interfaces(range(6)) - - for i in self.pg_interfaces: - i.admin_up() - i.config_ip4() - i.resolve_arp() - i.config_ip6() - i.resolve_ndp() - - def tearDown(self): - for i in self.pg_interfaces: - i.unconfig_ip4() - i.unconfig_ip6() - i.ip6_disable() - i.admin_down() - super(TestL3xc, self).tearDown() - - def send_and_expect_load_balancing(self, input, pkts, outputs): - self.pg_send(input, pkts) - rxs = [] - for oo in outputs: - rx = oo._get_capture(1) - self.assertNotEqual(0, len(rx)) - for r in rx: - rxs.append(r) - return rxs - - def test_l3xc4(self): - """ IPv4 X-Connect """ - - # - # x-connect pg0 to pg1 and pg2 to pg3->5 - # - l3xc_1 = VppL3xc(self, self.pg0, - [VppRoutePath(self.pg1.remote_ip4, - self.pg1.sw_if_index)]) - l3xc_1.add_vpp_config() - l3xc_2 = VppL3xc(self, self.pg2, - [VppRoutePath(self.pg3.remote_ip4, - self.pg3.sw_if_index), - VppRoutePath(self.pg4.remote_ip4, - self.pg4.sw_if_index), - VppRoutePath(self.pg5.remote_ip4, - self.pg5.sw_if_index)]) - l3xc_2.add_vpp_config() - - self.assertTrue(find_l3xc(self, self.pg2.sw_if_index, 0xffffffff)) - - self.logger.info(self.vapi.cli("sh l3xc")) - - # - # fire in packets. If it's forwarded then the L3XC was successful, - # since default routing will drop it - # - p_1 = (Ether(src=self.pg0.remote_mac, - dst=self.pg0.local_mac) / - IP(src="1.1.1.1", dst="1.1.1.2") / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - # self.send_and_expect(self.pg0, p_1*NUM_PKTS, self.pg1) - - p_2 = [] - for ii in range(NUM_PKTS): - p_2.append(Ether(src=self.pg0.remote_mac, - dst=self.pg0.local_mac) / - IP(src="1.1.1.1", dst="1.1.1.2") / - UDP(sport=1000 + ii, dport=1234) / - Raw('\xa5' * 100)) - self.send_and_expect_load_balancing(self.pg2, p_2, - [self.pg3, self.pg4, self.pg5]) - - l3xc_2.remove_vpp_config() - self.send_and_assert_no_replies(self.pg2, p_2) - - -if __name__ == '__main__': - unittest.main(testRunner=VppTestRunner) diff --git a/test/test_lb.py b/test/test_lb.py deleted file mode 100644 index 4603bd10db8..00000000000 --- a/test/test_lb.py +++ /dev/null @@ -1,502 +0,0 @@ -import socket - -import scapy.compat -from scapy.layers.inet import IP, UDP -from scapy.layers.inet6 import IPv6 -from scapy.layers.l2 import Ether, GRE -from scapy.packet import Raw -from scapy.data import IP_PROTOS - -from framework import VppTestCase -from util import ppp -from vpp_ip_route import VppIpRoute, VppRoutePath -from vpp_ip import INVALID_INDEX - -""" TestLB is a subclass of VPPTestCase classes. - - TestLB class defines Load Balancer test cases for: - - IP4 to GRE4 encap on per-port vip case - - IP4 to GRE6 encap on per-port vip case - - IP6 to GRE4 encap on per-port vip case - - IP6 to GRE6 encap on per-port vip case - - IP4 to L3DSR encap on vip case - - IP4 to L3DSR encap on per-port vip case - - IP4 to NAT4 encap on per-port vip case - - IP6 to NAT6 encap on per-port vip case - - As stated in comments below, GRE has issues with IPv6. - All test cases involving IPv6 are executed, but - received packets are not parsed and checked. - -""" - - -class TestLB(VppTestCase): - """ Load Balancer Test Case """ - - @classmethod - def setUpClass(cls): - super(TestLB, cls).setUpClass() - - cls.ass = range(5) - cls.packets = range(1) - - try: - cls.create_pg_interfaces(range(2)) - cls.interfaces = list(cls.pg_interfaces) - - for i in cls.interfaces: - i.admin_up() - i.config_ip4() - i.config_ip6() - i.disable_ipv6_ra() - i.resolve_arp() - i.resolve_ndp() - - dst4 = VppIpRoute(cls, "10.0.0.0", 24, - [VppRoutePath(cls.pg1.remote_ip4, - INVALID_INDEX)], - register=False) - dst4.add_vpp_config() - dst6 = VppIpRoute(cls, "2002::", 16, - [VppRoutePath(cls.pg1.remote_ip6, - INVALID_INDEX)], - register=False) - dst6.add_vpp_config() - cls.vapi.lb_conf(ip4_src_address="39.40.41.42", - ip6_src_address="2004::1") - except Exception: - super(TestLB, cls).tearDownClass() - raise - - @classmethod - def tearDownClass(cls): - super(TestLB, cls).tearDownClass() - - def tearDown(self): - super(TestLB, self).tearDown() - - def show_commands_at_teardown(self): - self.logger.info(self.vapi.cli("show lb vip verbose")) - - def getIPv4Flow(self, id): - return (IP(dst="90.0.%u.%u" % (id / 255, id % 255), - src="40.0.%u.%u" % (id / 255, id % 255)) / - UDP(sport=10000 + id, dport=20000)) - - def getIPv6Flow(self, id): - return (IPv6(dst="2001::%u" % (id), src="fd00:f00d:ffff::%u" % (id)) / - UDP(sport=10000 + id, dport=20000)) - - def generatePackets(self, src_if, isv4): - self.reset_packet_infos() - pkts = [] - for pktid in self.packets: - info = self.create_packet_info(src_if, self.pg1) - payload = self.info_to_payload(info) - ip = self.getIPv4Flow(pktid) if isv4 else self.getIPv6Flow(pktid) - packet = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) / - ip / - Raw(payload)) - self.extend_packet(packet, 128) - info.data = packet.copy() - pkts.append(packet) - return pkts - - def checkInner(self, gre, isv4): - IPver = IP if isv4 else IPv6 - self.assertEqual(gre.proto, 0x0800 if isv4 else 0x86DD) - self.assertEqual(gre.flags, 0) - self.assertEqual(gre.version, 0) - inner = IPver(scapy.compat.raw(gre.payload)) - payload_info = self.payload_to_info(inner[Raw]) - self.info = self.packet_infos[payload_info.index] - self.assertEqual(payload_info.src, self.pg0.sw_if_index) - self.assertEqual(scapy.compat.raw(inner), - scapy.compat.raw(self.info.data[IPver])) - - def checkCapture(self, encap, isv4): - self.pg0.assert_nothing_captured() - out = self.pg1.get_capture(len(self.packets)) - - load = [0] * len(self.ass) - self.info = None - for p in out: - try: - asid = 0 - gre = None - if (encap == 'gre4'): - ip = p[IP] - asid = int(ip.dst.split(".")[3]) - self.assertEqual(ip.version, 4) - self.assertEqual(ip.flags, 0) - self.assertEqual(ip.src, "39.40.41.42") - self.assertEqual(ip.dst, "10.0.0.%u" % asid) - self.assertEqual(ip.proto, 47) - self.assertEqual(len(ip.options), 0) - gre = p[GRE] - self.checkInner(gre, isv4) - elif (encap == 'gre6'): - ip = p[IPv6] - asid = ip.dst.split(":") - asid = asid[len(asid) - 1] - asid = 0 if asid == "" else int(asid) - self.assertEqual(ip.version, 6) - self.assertEqual(ip.tc, 0) - self.assertEqual(ip.fl, 0) - self.assertEqual(ip.src, "2004::1") - self.assertEqual( - socket.inet_pton(socket.AF_INET6, ip.dst), - socket.inet_pton(socket.AF_INET6, "2002::%u" % asid) - ) - self.assertEqual(ip.nh, 47) - # self.assertEqual(len(ip.options), 0) - gre = GRE(scapy.compat.raw(p[IPv6].payload)) - self.checkInner(gre, isv4) - elif (encap == 'l3dsr'): - ip = p[IP] - asid = int(ip.dst.split(".")[3]) - self.assertEqual(ip.version, 4) - self.assertEqual(ip.flags, 0) - self.assertEqual(ip.dst, "10.0.0.%u" % asid) - self.assertEqual(ip.tos, 0x1c) - self.assertEqual(len(ip.options), 0) - self.assert_ip_checksum_valid(p) - if ip.proto == IP_PROTOS.tcp: - self.assert_tcp_checksum_valid(p) - elif ip.proto == IP_PROTOS.udp: - self.assert_udp_checksum_valid(p) - elif (encap == 'nat4'): - ip = p[IP] - asid = int(ip.dst.split(".")[3]) - self.assertEqual(ip.version, 4) - self.assertEqual(ip.flags, 0) - self.assertEqual(ip.dst, "10.0.0.%u" % asid) - self.assertEqual(ip.proto, 17) - self.assertEqual(len(ip.options), 0) - udp = p[UDP] - self.assertEqual(udp.dport, 3307) - elif (encap == 'nat6'): - ip = p[IPv6] - asid = ip.dst.split(":") - asid = asid[len(asid) - 1] - asid = 0 if asid == "" else int(asid) - self.assertEqual(ip.version, 6) - self.assertEqual(ip.tc, 0) - self.assertEqual(ip.fl, 0) - self.assertEqual( - socket.inet_pton(socket.AF_INET6, ip.dst), - socket.inet_pton(socket.AF_INET6, "2002::%u" % asid) - ) - self.assertEqual(ip.nh, 17) - self.assertGreaterEqual(ip.hlim, 63) - udp = UDP(scapy.compat.raw(p[IPv6].payload)) - self.assertEqual(udp.dport, 3307) - load[asid] += 1 - except: - self.logger.error(ppp("Unexpected or invalid packet:", p)) - raise - - # This is just to roughly check that the balancing algorithm - # is not completely biased. - for asid in self.ass: - if load[asid] < len(self.packets) / (len(self.ass) * 2): - self.logger.error( - "ASS is not balanced: load[%d] = %d" % (asid, load[asid])) - raise Exception("Load Balancer algorithm is biased") - - def test_lb_ip4_gre4(self): - """ Load Balancer IP4 GRE4 on vip case """ - try: - self.vapi.cli( - "lb vip 90.0.0.0/8 encap gre4") - for asid in self.ass: - self.vapi.cli( - "lb as 90.0.0.0/8 10.0.0.%u" - % (asid)) - - self.pg0.add_stream(self.generatePackets(self.pg0, isv4=True)) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - self.checkCapture(encap='gre4', isv4=True) - - finally: - for asid in self.ass: - self.vapi.cli( - "lb as 90.0.0.0/8 10.0.0.%u del" - % (asid)) - self.vapi.cli( - "lb vip 90.0.0.0/8 encap gre4 del") - self.vapi.cli("test lb flowtable flush") - - def test_lb_ip6_gre4(self): - """ Load Balancer IP6 GRE4 on vip case """ - - try: - self.vapi.cli( - "lb vip 2001::/16 encap gre4") - for asid in self.ass: - self.vapi.cli( - "lb as 2001::/16 10.0.0.%u" - % (asid)) - - self.pg0.add_stream(self.generatePackets(self.pg0, isv4=False)) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - - self.checkCapture(encap='gre4', isv4=False) - finally: - for asid in self.ass: - self.vapi.cli( - "lb as 2001::/16 10.0.0.%u del" - % (asid)) - self.vapi.cli( - "lb vip 2001::/16 encap gre4 del") - self.vapi.cli("test lb flowtable flush") - - def test_lb_ip4_gre6(self): - """ Load Balancer IP4 GRE6 on vip case """ - try: - self.vapi.cli( - "lb vip 90.0.0.0/8 encap gre6") - for asid in self.ass: - self.vapi.cli( - "lb as 90.0.0.0/8 2002::%u" - % (asid)) - - self.pg0.add_stream(self.generatePackets(self.pg0, isv4=True)) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - - self.checkCapture(encap='gre6', isv4=True) - finally: - for asid in self.ass: - self.vapi.cli( - "lb as 90.0.0.0/8 2002::%u del" - % (asid)) - self.vapi.cli( - "lb vip 90.0.0.0/8 encap gre6 del") - self.vapi.cli("test lb flowtable flush") - - def test_lb_ip6_gre6(self): - """ Load Balancer IP6 GRE6 on vip case """ - try: - self.vapi.cli( - "lb vip 2001::/16 encap gre6") - for asid in self.ass: - self.vapi.cli( - "lb as 2001::/16 2002::%u" - % (asid)) - - self.pg0.add_stream(self.generatePackets(self.pg0, isv4=False)) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - - self.checkCapture(encap='gre6', isv4=False) - finally: - for asid in self.ass: - self.vapi.cli( - "lb as 2001::/16 2002::%u del" - % (asid)) - self.vapi.cli( - "lb vip 2001::/16 encap gre6 del") - self.vapi.cli("test lb flowtable flush") - - def test_lb_ip4_gre4_port(self): - """ Load Balancer IP4 GRE4 on per-port-vip case """ - try: - self.vapi.cli( - "lb vip 90.0.0.0/8 protocol udp port 20000 encap gre4") - for asid in self.ass: - self.vapi.cli( - "lb as 90.0.0.0/8 protocol udp port 20000 10.0.0.%u" - % (asid)) - - self.pg0.add_stream(self.generatePackets(self.pg0, isv4=True)) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - self.checkCapture(encap='gre4', isv4=True) - - finally: - for asid in self.ass: - self.vapi.cli( - "lb as 90.0.0.0/8 protocol udp port 20000 10.0.0.%u del" - % (asid)) - self.vapi.cli( - "lb vip 90.0.0.0/8 protocol udp port 20000 encap gre4 del") - self.vapi.cli("test lb flowtable flush") - - def test_lb_ip6_gre4_port(self): - """ Load Balancer IP6 GRE4 on per-port-vip case """ - - try: - self.vapi.cli( - "lb vip 2001::/16 protocol udp port 20000 encap gre4") - for asid in self.ass: - self.vapi.cli( - "lb as 2001::/16 protocol udp port 20000 10.0.0.%u" - % (asid)) - - self.pg0.add_stream(self.generatePackets(self.pg0, isv4=False)) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - - self.checkCapture(encap='gre4', isv4=False) - finally: - for asid in self.ass: - self.vapi.cli( - "lb as 2001::/16 protocol udp port 20000 10.0.0.%u del" - % (asid)) - self.vapi.cli( - "lb vip 2001::/16 protocol udp port 20000 encap gre4 del") - self.vapi.cli("test lb flowtable flush") - - def test_lb_ip4_gre6_port(self): - """ Load Balancer IP4 GRE6 on per-port-vip case """ - try: - self.vapi.cli( - "lb vip 90.0.0.0/8 protocol udp port 20000 encap gre6") - for asid in self.ass: - self.vapi.cli( - "lb as 90.0.0.0/8 protocol udp port 20000 2002::%u" - % (asid)) - - self.pg0.add_stream(self.generatePackets(self.pg0, isv4=True)) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - - self.checkCapture(encap='gre6', isv4=True) - finally: - for asid in self.ass: - self.vapi.cli( - "lb as 90.0.0.0/8 protocol udp port 20000 2002::%u del" - % (asid)) - self.vapi.cli( - "lb vip 90.0.0.0/8 protocol udp port 20000 encap gre6 del") - self.vapi.cli("test lb flowtable flush") - - def test_lb_ip6_gre6_port(self): - """ Load Balancer IP6 GRE6 on per-port-vip case """ - try: - self.vapi.cli( - "lb vip 2001::/16 protocol udp port 20000 encap gre6") - for asid in self.ass: - self.vapi.cli( - "lb as 2001::/16 protocol udp port 20000 2002::%u" - % (asid)) - - self.pg0.add_stream(self.generatePackets(self.pg0, isv4=False)) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - - self.checkCapture(encap='gre6', isv4=False) - finally: - for asid in self.ass: - self.vapi.cli( - "lb as 2001::/16 protocol udp port 20000 2002::%u del" - % (asid)) - self.vapi.cli( - "lb vip 2001::/16 protocol udp port 20000 encap gre6 del") - self.vapi.cli("test lb flowtable flush") - - def test_lb_ip4_l3dsr(self): - """ Load Balancer IP4 L3DSR on vip case """ - try: - self.vapi.cli( - "lb vip 90.0.0.0/8 encap l3dsr dscp 7") - for asid in self.ass: - self.vapi.cli( - "lb as 90.0.0.0/8 10.0.0.%u" - % (asid)) - - self.pg0.add_stream(self.generatePackets(self.pg0, isv4=True)) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - self.checkCapture(encap='l3dsr', isv4=True) - - finally: - for asid in self.ass: - self.vapi.cli( - "lb as 90.0.0.0/8 10.0.0.%u del" - % (asid)) - self.vapi.cli( - "lb vip 90.0.0.0/8 encap l3dsr" - " dscp 7 del") - self.vapi.cli("test lb flowtable flush") - - def test_lb_ip4_l3dsr_port(self): - """ Load Balancer IP4 L3DSR on per-port-vip case """ - try: - self.vapi.cli( - "lb vip 90.0.0.0/8 protocol udp port 20000 encap l3dsr dscp 7") - for asid in self.ass: - self.vapi.cli( - "lb as 90.0.0.0/8 protocol udp port 20000 10.0.0.%u" - % (asid)) - - self.pg0.add_stream(self.generatePackets(self.pg0, isv4=True)) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - self.checkCapture(encap='l3dsr', isv4=True) - - finally: - for asid in self.ass: - self.vapi.cli( - "lb as 90.0.0.0/8 protocol udp port 20000 10.0.0.%u del" - % (asid)) - self.vapi.cli( - "lb vip 90.0.0.0/8 protocol udp port 20000 encap l3dsr" - " dscp 7 del") - self.vapi.cli("test lb flowtable flush") - - def test_lb_ip4_nat4_port(self): - """ Load Balancer IP4 NAT4 on per-port-vip case """ - try: - self.vapi.cli( - "lb vip 90.0.0.0/8 protocol udp port 20000 encap nat4" - " type clusterip target_port 3307") - for asid in self.ass: - self.vapi.cli( - "lb as 90.0.0.0/8 protocol udp port 20000 10.0.0.%u" - % (asid)) - - self.pg0.add_stream(self.generatePackets(self.pg0, isv4=True)) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - self.checkCapture(encap='nat4', isv4=True) - - finally: - for asid in self.ass: - self.vapi.cli( - "lb as 90.0.0.0/8 protocol udp port 20000 10.0.0.%u del" - % (asid)) - self.vapi.cli( - "lb vip 90.0.0.0/8 protocol udp port 20000 encap nat4" - " type clusterip target_port 3307 del") - self.vapi.cli("test lb flowtable flush") - - def test_lb_ip6_nat6_port(self): - """ Load Balancer IP6 NAT6 on per-port-vip case """ - try: - self.vapi.cli( - "lb vip 2001::/16 protocol udp port 20000 encap nat6" - " type clusterip target_port 3307") - for asid in self.ass: - self.vapi.cli( - "lb as 2001::/16 protocol udp port 20000 2002::%u" - % (asid)) - - self.pg0.add_stream(self.generatePackets(self.pg0, isv4=False)) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - self.checkCapture(encap='nat6', isv4=False) - - finally: - for asid in self.ass: - self.vapi.cli( - "lb as 2001::/16 protocol udp port 20000 2002::%u del" - % (asid)) - self.vapi.cli( - "lb vip 2001::/16 protocol udp port 20000 encap nat6" - " type clusterip target_port 3307 del") - self.vapi.cli("test lb flowtable flush") diff --git a/test/test_lb_api.py b/test/test_lb_api.py deleted file mode 100644 index 70d41d432a7..00000000000 --- a/test/test_lb_api.py +++ /dev/null @@ -1,76 +0,0 @@ -# Copyright (c) 2019. Vinci Consulting Corp. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import framework -import ipaddress - -DEFAULT_VIP = "lb_vip_details(_0=978, context=12, vip=vl_api_lb_ip_addr_t(pfx=IPv6Network(u'::/0'), protocol=<vl_api_ip_proto_t.IP_API_PROTO_RESERVED: 255>, port=0), encap=<vl_api_lb_encap_type_t.LB_API_ENCAP_TYPE_GRE4: 0>, dscp=<vl_api_ip_dscp_t.IP_API_DSCP_CS0: 0>, srv_type=<vl_api_lb_srv_type_t.LB_API_SRV_TYPE_CLUSTERIP: 0>, target_port=0, flow_table_length=0)" # noqa - - -class TestLbEmptyApi(framework.VppTestCase): - """TestLbEmptyApi """ - - def test_lb_empty_vip_dump(self): - - # no records should normally return [], but - # lb initializes with a default VIP - rv = self.vapi.lb_vip_dump() - # print(rv) - self.assertEqual(rv, [], 'Expected: [] Received: %r.' % rv) - - def test_lb_empty_as_dump(self): - - # no records should return [] - rv = self.vapi.lb_as_dump() - # print(rv) - self.assertEqual(rv, [], 'Expected: [] Received: %r.' % rv) - - -class TestLbApi(framework.VppTestCase): - """TestLbApi """ - - def test_lb_vip_dump(self): - # add some vips - # rv = self.vapi.lb_add_del_vip(pfx=ipaddress.IPv4Network(u'1.2.3.0/24'), # noqa - # protocol=17, - # encap=0) - # print(rv) - self.vapi.cli("lb vip 2001::/16 encap gre6") - rv = self.vapi.lb_vip_dump() - # print(rv) - self.assertEqual(str(rv[-1].vip.pfx), "2001::/16", - 'Expected: 2001::/16 Received: %r.' % rv[-1].vip.pfx) - - self.vapi.cli("lb vip 2001::/16 del") - - -class TestLbAsApi(framework.VppTestCase): - """TestLbAsApi """ - - def test_lb_as_dump(self): - # add some vips - self.vapi.cli("lb vip 2001::/16 encap gre6") - self.vapi.cli("lb as 2001::/16 2000::1") - # add some as's for the vips - # rv = self.vapi.lb_add_del_as( - # pfx=ipaddress.IPv4Network(u"10.0.0.0/24"), - # as_address=ipaddress.IPv4Address(u"192.168.1.1")) - - # print(rv) - rv = self.vapi.lb_as_dump() - # print(rv) - self.assertEqual(str(rv[0].vip.pfx), "2001::/16", - 'Expected: "2001::/16" Received: %r.' % rv[0].vip.pfx) - self.assertEqual(str(rv[0].app_srv), "2000::1", - 'Expected: "2000::1" Received: %r.' % rv[0].app_srv) diff --git a/test/test_mactime.py b/test/test_mactime.py deleted file mode 100644 index ab3d5371815..00000000000 --- a/test/test_mactime.py +++ /dev/null @@ -1,155 +0,0 @@ -#!/usr/bin/env python - -import unittest - -from framework import VppTestCase, VppTestRunner, running_extended_tests -from vpp_ip_route import VppIpTable, VppIpRoute, VppRoutePath - - -class TestMactime(VppTestCase): - """ Mactime Unit Test Cases """ - - @classmethod - def setUpClass(cls): - super(TestMactime, cls).setUpClass() - - @classmethod - def tearDownClass(cls): - super(TestMactime, cls).tearDownClass() - - def setUp(self): - super(TestMactime, self).setUp() - - def tearDown(self): - super(TestMactime, self).tearDown() - - def test_mactime_range_unittest(self): - """ Time Range Test """ - error = self.vapi.cli("test time-range") - - if error: - self.logger.critical(error) - self.assertNotIn('FAILED', error) - - @unittest.skipUnless(running_extended_tests, "part of extended tests") - def test_mactime_unittest(self): - """ Mactime Plugin Code Coverage Test """ - cmds = ["loopback create", - "mactime enable-disable disable", - "mactime enable-disable loop0", - "mactime enable-disable loop0 disable", - "mactime enable-disable sw_if_index 9999", - "bin mactime_enable_disable loop0", - "bin mactime_enable_disable loop0 disable", - "bin mactime_enable_disable sw_if_index 1", - "set interface state loop0 up", - "clear mactime", - "set ip arp loop0 192.168.1.1 00:d0:2d:5e:86:85", - "bin mactime_add_del_range name sallow " - "mac 00:d0:2d:5e:86:85 allow-static del", - "bin mactime_add_del_range name sallow " - "mac 00:d0:2d:5e:86:85 allow-static", - "bin mactime_add_del_range name sallow " - "mac 00:d0:2d:5e:86:85 allow-static del", - "bin mactime_add_del_range name sallow " - "mac 00:d0:2d:5e:86:85 allow-static", - "bin mactime_add_del_range name sblock " - "mac 01:00:5e:7f:ff:fa drop-static", - "bin mactime_add_del_range name ddrop " - "mac c8:bc:c8:5a:ba:f3 drop-range Sun - Sat " - "00:00 - 23:59", - "bin mactime_add_del_range name dallow " - "mac c8:bc:c8:5a:ba:f4 allow-range Sun - Sat " - "00:00 - 23:59", - "bin mactime_add_del_range name multi " - "mac c8:bc:c8:f0:f0:f0 allow-range Sun - Mon " - "00:00 - 23:59 Tue - Sat 00:00 - 23:59", - "bin mactime_add_del_range bogus", - "bin mactime_add_del_range mac 01:00:5e:7f:f0:f0 allow-static", - "bin mactime_add_del_range " - "name tooloooooooooooooooooooooooooooooooooooooooooooooooo" - "nnnnnnnnnnnnnnnnnnnnnnnnnnnng mac 00:00:de:ad:be:ef " - "allow-static", - "packet-generator new {\n" - " name allow\n" - " limit 15\n" - " size 128-128\n" - " interface loop0\n" - " node ethernet-input\n" - " data {\n" - " IP6: 00:d0:2d:5e:86:85 -> 00:0d:ea:d0:00:00\n" - " ICMP: db00::1 -> db00::2\n" - " incrementing 30\n" - " }\n", - "}\n", - "packet-generator new {\n" - " name deny\n" - " limit 15\n" - " size 128-128\n" - " interface loop0\n" - " node ethernet-input\n" - " data {\n" - " IP6: 01:00:5e:7f:ff:fa -> 00:0d:ea:d0:00:00\n" - " ICMP: db00::1 -> db00::2\n" - " incrementing 30\n" - " }\n", - "}\n", - "packet-generator new {\n" - " name ddrop\n" - " limit 15\n" - " size 128-128\n" - " interface loop0\n" - " node ethernet-input\n" - " data {\n" - " IP6: c8:bc:c8:5a:ba:f3 -> 00:0d:ea:d0:00:00\n" - " ICMP: db00::1 -> db00::2\n" - " incrementing 30\n" - " }\n", - "}\n", - "packet-generator new {\n" - " name dallow\n" - " limit 15\n" - " size 128-128\n" - " interface loop0\n" - " node ethernet-input\n" - " data {\n" - " IP6: c8:bc:c8:5a:ba:f4 -> 00:0d:ea:d0:00:00\n" - " ICMP: db00::1 -> db00::2\n" - " incrementing 30\n" - " }\n" - "}\n" - "packet-generator new {\n" - " name makeentry\n" - " limit 15\n" - " size 128-128\n" - " interface loop0\n" - " node ethernet-input\n" - " data {\n" - " IP6: c8:bc:c8:5a:b0:0b -> 00:0d:ea:d0:00:00\n" - " ICMP: db00::1 -> db00::2\n" - " incrementing 30\n" - " }\n" - "}\n" - "packet-generator new {\n" - " name tx\n" - " limit 15\n" - " size 128-128\n" - " interface local0\n" - " tx-interface loop0\n" - " node loop0-output\n" - " data {\n" - " hex 0x01005e7ffffa000dead000000800" - "0102030405060708090a0b0c0d0e0f0102030405\n" - " }\n" - "}\n" - "trace add pg-input 2", - "pa en", - "show mactime verbose 2", - "show trace", - "show error"] - - for cmd in cmds: - self.logger.info(self.vapi.cli(cmd)) - -if __name__ == '__main__': - unittest.main(testRunner=VppTestRunner) diff --git a/test/test_map.py b/test/test_map.py deleted file mode 100644 index f1388b39c65..00000000000 --- a/test/test_map.py +++ /dev/null @@ -1,437 +0,0 @@ -#!/usr/bin/env python - -import ipaddress -import unittest -from ipaddress import IPv6Network, IPv4Network - -from framework import VppTestCase, VppTestRunner -from vpp_ip import DpoProto -from vpp_ip_route import VppIpRoute, VppRoutePath - -import scapy.compat -from scapy.layers.l2 import Ether, Raw -from scapy.layers.inet import IP, UDP, ICMP, TCP, fragment -from scapy.layers.inet6 import IPv6, ICMPv6TimeExceeded - - -class TestMAP(VppTestCase): - """ MAP Test Case """ - - @classmethod - def setUpClass(cls): - super(TestMAP, cls).setUpClass() - - @classmethod - def tearDownClass(cls): - super(TestMAP, cls).tearDownClass() - - def setUp(self): - super(TestMAP, self).setUp() - - # create 2 pg interfaces - self.create_pg_interfaces(range(4)) - - # pg0 is 'inside' IPv4 - self.pg0.admin_up() - self.pg0.config_ip4() - self.pg0.resolve_arp() - - # pg1 is 'outside' IPv6 - self.pg1.admin_up() - self.pg1.config_ip6() - self.pg1.generate_remote_hosts(4) - self.pg1.configure_ipv6_neighbors() - - def tearDown(self): - super(TestMAP, self).tearDown() - for i in self.pg_interfaces: - i.unconfig_ip4() - i.unconfig_ip6() - i.admin_down() - - def send_and_assert_encapped(self, tx, ip6_src, ip6_dst, dmac=None): - if not dmac: - dmac = self.pg1.remote_mac - - self.pg0.add_stream(tx) - - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - - rx = self.pg1.get_capture(1) - rx = rx[0] - - self.assertEqual(rx[Ether].dst, dmac) - self.assertEqual(rx[IP].src, tx[IP].src) - self.assertEqual(rx[IPv6].src, ip6_src) - self.assertEqual(rx[IPv6].dst, ip6_dst) - - def test_api_map_domain_dump(self): - map_dst = '2001::/64' - map_src = '3000::1/128' - client_pfx = '192.168.0.0/16' - tag = 'MAP-E tag.' - index = self.vapi.map_add_domain(ip4_prefix=client_pfx, - ip6_prefix=map_dst, - ip6_src=map_src, - tag=tag).index - - rv = self.vapi.map_domain_dump() - - # restore the state early so as to not impact subsequent tests. - # If an assert fails, we will not get the chance to do it at the end. - self.vapi.map_del_domain(index=index) - - self.assertGreater(len(rv), 0, - "Expected output from 'map_domain_dump'") - - # typedefs are returned as ipaddress objects. - # wrap results in str() ugh! to avoid the need to call unicode. - self.assertEqual(str(rv[0].ip4_prefix), client_pfx) - self.assertEqual(str(rv[0].ip6_prefix), map_dst) - self.assertEqual(str(rv[0].ip6_src), map_src) - - self.assertEqual(rv[0].tag, tag, - "output produced incorrect tag value.") - - def test_map_e(self): - """ MAP-E """ - - # - # Add a route to the MAP-BR - # - map_br_pfx = "2001::" - map_br_pfx_len = 64 - map_route = VppIpRoute(self, - map_br_pfx, - map_br_pfx_len, - [VppRoutePath(self.pg1.remote_ip6, - self.pg1.sw_if_index)]) - map_route.add_vpp_config() - - # - # Add a domain that maps from pg0 to pg1 - # - map_dst = '2001::/64' - map_src = '3000::1/128' - client_pfx = '192.168.0.0/16' - tag = 'MAP-E tag.' - self.vapi.map_add_domain(ip4_prefix=client_pfx, - ip6_prefix=map_dst, - ip6_src=map_src, - tag=tag) - - # Enable MAP on interface. - self.vapi.map_if_enable_disable(is_enable=1, - sw_if_index=self.pg0.sw_if_index, - is_translation=0) - - # Ensure MAP doesn't steal all packets! - v4 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IP(src=self.pg0.remote_ip4, dst=self.pg0.remote_ip4) / - UDP(sport=20000, dport=10000) / - Raw('\xa5' * 100)) - rx = self.send_and_expect(self.pg0, v4*1, self.pg0) - v4_reply = v4[1] - v4_reply.ttl -= 1 - for p in rx: - self.validate(p[1], v4_reply) - - # - # Fire in a v4 packet that will be encapped to the BR - # - v4 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IP(src=self.pg0.remote_ip4, dst='192.168.1.1') / - UDP(sport=20000, dport=10000) / - Raw('\xa5' * 100)) - - self.send_and_assert_encapped(v4, "3000::1", "2001::c0a8:0:0") - - # Enable MAP on interface. - self.vapi.map_if_enable_disable(is_enable=1, - sw_if_index=self.pg1.sw_if_index, - is_translation=0) - - # Ensure MAP doesn't steal all packets - v6 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / - IPv6(src=self.pg1.remote_ip6, dst=self.pg1.remote_ip6) / - UDP(sport=20000, dport=10000) / - Raw('\xa5' * 100)) - rx = self.send_and_expect(self.pg1, v6*1, self.pg1) - v6_reply = v6[1] - v6_reply.hlim -= 1 - for p in rx: - self.validate(p[1], v6_reply) - - # - # Fire in a V6 encapped packet. - # expect a decapped packet on the inside ip4 link - # - p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / - IPv6(dst='3000::1', src="2001::1") / - IP(dst=self.pg0.remote_ip4, src='192.168.1.1') / - UDP(sport=20000, dport=10000) / - Raw('\xa5' * 100)) - - self.pg1.add_stream(p) - - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - - rx = self.pg0.get_capture(1) - rx = rx[0] - - self.assertFalse(rx.haslayer(IPv6)) - self.assertEqual(rx[IP].src, p[IP].src) - self.assertEqual(rx[IP].dst, p[IP].dst) - - # - # Pre-resolve. No API for this!! - # - self.vapi.ppcli("map params pre-resolve ip6-nh 4001::1") - - self.send_and_assert_no_replies(self.pg0, v4, - "resolved via default route") - - # - # Add a route to 4001::1. Expect the encapped traffic to be - # sent via that routes next-hop - # - pre_res_route = VppIpRoute(self, "4001::1", 128, - [VppRoutePath(self.pg1.remote_hosts[2].ip6, - self.pg1.sw_if_index)]) - pre_res_route.add_vpp_config() - - self.send_and_assert_encapped(v4, "3000::1", - "2001::c0a8:0:0", - dmac=self.pg1.remote_hosts[2].mac) - - # - # change the route to the pre-solved next-hop - # - pre_res_route.modify([VppRoutePath(self.pg1.remote_hosts[3].ip6, - self.pg1.sw_if_index)]) - pre_res_route.add_vpp_config() - - self.send_and_assert_encapped(v4, "3000::1", - "2001::c0a8:0:0", - dmac=self.pg1.remote_hosts[3].mac) - - # - # cleanup. The test infra's object registry will ensure - # the route is really gone and thus that the unresolve worked. - # - pre_res_route.remove_vpp_config() - self.vapi.ppcli("map params pre-resolve del ip6-nh 4001::1") - - def validate(self, rx, expected): - self.assertEqual(rx, expected.__class__(scapy.compat.raw(expected))) - - def payload(self, len): - return 'x' * len - - def test_map_t(self): - """ MAP-T """ - - # - # Add a domain that maps from pg0 to pg1 - # - map_dst = '2001:db8::/32' - map_src = '1234:5678:90ab:cdef::/64' - ip4_pfx = '192.168.0.0/24' - tag = 'MAP-T Tag.' - - self.vapi.map_add_domain(ip6_prefix=map_dst, - ip4_prefix=ip4_pfx, - ip6_src=map_src, - ea_bits_len=16, - psid_offset=6, - psid_length=4, - mtu=1500, - tag=tag) - - # Enable MAP-T on interfaces. - self.vapi.map_if_enable_disable(is_enable=1, - sw_if_index=self.pg0.sw_if_index, - is_translation=1) - self.vapi.map_if_enable_disable(is_enable=1, - sw_if_index=self.pg1.sw_if_index, - is_translation=1) - - # Ensure MAP doesn't steal all packets! - v4 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IP(src=self.pg0.remote_ip4, dst=self.pg0.remote_ip4) / - UDP(sport=20000, dport=10000) / - Raw('\xa5' * 100)) - rx = self.send_and_expect(self.pg0, v4*1, self.pg0) - v4_reply = v4[1] - v4_reply.ttl -= 1 - for p in rx: - self.validate(p[1], v4_reply) - # Ensure MAP doesn't steal all packets - v6 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / - IPv6(src=self.pg1.remote_ip6, dst=self.pg1.remote_ip6) / - UDP(sport=20000, dport=10000) / - Raw('\xa5' * 100)) - rx = self.send_and_expect(self.pg1, v6*1, self.pg1) - v6_reply = v6[1] - v6_reply.hlim -= 1 - for p in rx: - self.validate(p[1], v6_reply) - - map_route = VppIpRoute(self, - "2001:db8::", - 32, - [VppRoutePath(self.pg1.remote_ip6, - self.pg1.sw_if_index, - proto=DpoProto.DPO_PROTO_IP6)]) - map_route.add_vpp_config() - - # - # Send a v4 packet that will be translated - # - p_ether = Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) - p_ip4 = IP(src=self.pg0.remote_ip4, dst='192.168.0.1') - payload = TCP(sport=0xabcd, dport=0xabcd) - - p4 = (p_ether / p_ip4 / payload) - p6_translated = (IPv6(src="1234:5678:90ab:cdef:ac:1001:200:0", - dst="2001:db8:1f0::c0a8:1:f") / payload) - p6_translated.hlim -= 1 - rx = self.send_and_expect(self.pg0, p4*1, self.pg1) - for p in rx: - self.validate(p[1], p6_translated) - - # Send back an IPv6 packet that will be "untranslated" - p_ether6 = Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) - p_ip6 = IPv6(src='2001:db8:1f0::c0a8:1:f', - dst='1234:5678:90ab:cdef:ac:1001:200:0') - p6 = (p_ether6 / p_ip6 / payload) - p4_translated = (IP(src='192.168.0.1', - dst=self.pg0.remote_ip4) / payload) - p4_translated.id = 0 - p4_translated.ttl -= 1 - rx = self.send_and_expect(self.pg1, p6*1, self.pg0) - for p in rx: - self.validate(p[1], p4_translated) - - # IPv4 TTL - ip4_ttl_expired = IP(src=self.pg0.remote_ip4, dst='192.168.0.1', ttl=0) - p4 = (p_ether / ip4_ttl_expired / payload) - - icmp4_reply = (IP(id=0, ttl=254, src=self.pg0.local_ip4, - dst=self.pg0.remote_ip4) / - ICMP(type='time-exceeded', - code='ttl-zero-during-transit') / - IP(src=self.pg0.remote_ip4, - dst='192.168.0.1', ttl=0) / payload) - rx = self.send_and_expect(self.pg0, p4*1, self.pg0) - for p in rx: - self.validate(p[1], icmp4_reply) - - ''' - This one is broken, cause it would require hairpinning... - # IPv4 TTL TTL1 - ip4_ttl_expired = IP(src=self.pg0.remote_ip4, dst='192.168.0.1', ttl=1) - p4 = (p_ether / ip4_ttl_expired / payload) - - icmp4_reply = IP(id=0, ttl=254, src=self.pg0.local_ip4, - dst=self.pg0.remote_ip4) / \ - ICMP(type='time-exceeded', code='ttl-zero-during-transit' ) / \ - IP(src=self.pg0.remote_ip4, dst='192.168.0.1', ttl=0) / payload - rx = self.send_and_expect(self.pg0, p4*1, self.pg0) - for p in rx: - self.validate(p[1], icmp4_reply) - ''' - - # IPv6 Hop limit - ip6_hlim_expired = IPv6(hlim=0, src='2001:db8:1ab::c0a8:1:ab', - dst='1234:5678:90ab:cdef:ac:1001:200:0') - p6 = (p_ether6 / ip6_hlim_expired / payload) - - icmp6_reply = (IPv6(hlim=255, src=self.pg1.local_ip6, - dst="2001:db8:1ab::c0a8:1:ab") / - ICMPv6TimeExceeded(code=0) / - IPv6(src="2001:db8:1ab::c0a8:1:ab", - dst='1234:5678:90ab:cdef:ac:1001:200:0', - hlim=0) / payload) - rx = self.send_and_expect(self.pg1, p6*1, self.pg1) - for p in rx: - self.validate(p[1], icmp6_reply) - - # IPv4 Well-known port - p_ip4 = IP(src=self.pg0.remote_ip4, dst='192.168.0.1') - payload = UDP(sport=200, dport=200) - p4 = (p_ether / p_ip4 / payload) - self.send_and_assert_no_replies(self.pg0, p4*1) - - # IPv6 Well-known port - payload = UDP(sport=200, dport=200) - p6 = (p_ether6 / p_ip6 / payload) - self.send_and_assert_no_replies(self.pg1, p6*1) - - # Packet fragmentation - payload = UDP(sport=40000, dport=4000) / self.payload(1453) - p4 = (p_ether / p_ip4 / payload) - self.pg_enable_capture() - self.pg0.add_stream(p4) - self.pg_start() - rx = self.pg1.get_capture(2) - for p in rx: - pass - # TODO: Manual validation - # self.validate(p[1], icmp4_reply) - - # Packet fragmentation send fragments - payload = UDP(sport=40000, dport=4000) / self.payload(1453) - p4 = (p_ether / p_ip4 / payload) - frags = fragment(p4, fragsize=1000) - self.pg_enable_capture() - self.pg0.add_stream(frags) - self.pg_start() - rx = self.pg1.get_capture(2) - for p in rx: - pass - # p.show2() - # reass_pkt = reassemble(rx) - # p4_reply.ttl -= 1 - # p4_reply.id = 256 - # self.validate(reass_pkt, p4_reply) - - # TCP MSS clamping - self.vapi.map_param_set_tcp(1300) - - # - # Send a v4 TCP SYN packet that will be translated and MSS clamped - # - p_ether = Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) - p_ip4 = IP(src=self.pg0.remote_ip4, dst='192.168.0.1') - payload = TCP(sport=0xabcd, dport=0xabcd, flags="S", - options=[('MSS', 1460)]) - - p4 = (p_ether / p_ip4 / payload) - p6_translated = (IPv6(src="1234:5678:90ab:cdef:ac:1001:200:0", - dst="2001:db8:1f0::c0a8:1:f") / payload) - p6_translated.hlim -= 1 - p6_translated[TCP].options = [('MSS', 1300)] - rx = self.send_and_expect(self.pg0, p4*1, self.pg1) - for p in rx: - self.validate(p[1], p6_translated) - - # Send back an IPv6 packet that will be "untranslated" - p_ether6 = Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) - p_ip6 = IPv6(src='2001:db8:1f0::c0a8:1:f', - dst='1234:5678:90ab:cdef:ac:1001:200:0') - p6 = (p_ether6 / p_ip6 / payload) - p4_translated = (IP(src='192.168.0.1', - dst=self.pg0.remote_ip4) / payload) - p4_translated.id = 0 - p4_translated.ttl -= 1 - p4_translated[TCP].options = [('MSS', 1300)] - rx = self.send_and_expect(self.pg1, p6*1, self.pg0) - for p in rx: - self.validate(p[1], p4_translated) - - -if __name__ == '__main__': - unittest.main(testRunner=VppTestRunner) diff --git a/test/test_memif.py b/test/test_memif.py deleted file mode 100644 index 6413cfdbf20..00000000000 --- a/test/test_memif.py +++ /dev/null @@ -1,275 +0,0 @@ -import socket -import unittest - -from scapy.layers.l2 import Ether -from scapy.layers.inet import IP, ICMP -import six - -from framework import VppTestCase, VppTestRunner, running_extended_tests -from remote_test import RemoteClass, RemoteVppTestCase -from vpp_memif import MEMIF_MODE, MEMIF_ROLE, remove_all_memif_vpp_config, \ - VppSocketFilename, VppMemif -from vpp_ip_route import VppIpRoute, VppRoutePath - - -class TestMemif(VppTestCase): - """ Memif Test Case """ - - @classmethod - def setUpClass(cls): - # fork new process before client connects to VPP - cls.remote_test = RemoteClass(RemoteVppTestCase) - cls.remote_test.start_remote() - cls.remote_test.set_request_timeout(10) - super(TestMemif, cls).setUpClass() - cls.remote_test.setUpClass(cls.tempdir) - cls.create_pg_interfaces(range(1)) - for pg in cls.pg_interfaces: - pg.config_ip4() - pg.admin_up() - pg.resolve_arp() - - @classmethod - def tearDownClass(cls): - cls.remote_test.tearDownClass() - cls.remote_test.quit_remote() - for pg in cls.pg_interfaces: - pg.unconfig_ip4() - pg.set_table_ip4(0) - pg.admin_down() - super(TestMemif, cls).tearDownClass() - - def tearDown(self): - remove_all_memif_vpp_config(self) - remove_all_memif_vpp_config(self.remote_test) - super(TestMemif, self).tearDown() - - def _check_socket_filename(self, dump, socket_id, filename): - for d in dump: - if (d.socket_id == socket_id) and ( - d.socket_filename.rstrip(b"\0") == filename): - return True - return False - - def test_memif_socket_filename_add_del(self): - """ Memif socket filename add/del """ - - # dump default socket filename - dump = self.vapi.memif_socket_filename_dump() - self.assertTrue( - self._check_socket_filename( - dump, 0, b"%s/memif.sock" % six.ensure_binary( - self.tempdir, encoding='utf-8'))) - - memif_sockets = [] - # existing path - memif_sockets.append( - VppSocketFilename( - self, 1, b"%s/memif1.sock" % six.ensure_binary( - self.tempdir, encoding='utf-8'))) - # default path (test tempdir) - memif_sockets.append( - VppSocketFilename( - self, - 2, - b"memif2.sock", - add_default_folder=True)) - # create new folder in default folder - memif_sockets.append( - VppSocketFilename( - self, - 3, - b"sock/memif3.sock", - add_default_folder=True)) - - for sock in memif_sockets: - sock.add_vpp_config() - dump = sock.query_vpp_config() - self.assertTrue( - self._check_socket_filename( - dump, - sock.socket_id, - sock.socket_filename)) - - for sock in memif_sockets: - sock.remove_vpp_config() - - dump = self.vapi.memif_socket_filename_dump() - self.assertTrue( - self._check_socket_filename( - dump, 0, b"%s/memif.sock" % six.ensure_binary( - self.tempdir, encoding='utf-8'))) - - def _create_delete_test_one_interface(self, memif): - memif.add_vpp_config() - - dump = memif.query_vpp_config() - - self.assertTrue(dump) - self.assertEqual(dump.sw_if_index, memif.sw_if_index) - self.assertEqual(dump.role, memif.role) - self.assertEqual(dump.mode, memif.mode) - if (memif.socket_id is not None): - self.assertEqual(dump.socket_id, memif.socket_id) - - memif.remove_vpp_config() - - dump = memif.query_vpp_config() - - self.assertFalse(dump) - - def _connect_test_one_interface(self, memif): - self.assertTrue(memif.wait_for_link_up(5)) - dump = memif.query_vpp_config() - - if memif.role == MEMIF_ROLE.SLAVE: - self.assertEqual(dump.ring_size, memif.ring_size) - self.assertEqual(dump.buffer_size, memif.buffer_size) - else: - self.assertEqual(dump.ring_size, 1) - self.assertEqual(dump.buffer_size, 0) - - def _connect_test_interface_pair(self, memif0, memif1): - memif0.add_vpp_config() - memif1.add_vpp_config() - - memif0.admin_up() - memif1.admin_up() - - self._connect_test_one_interface(memif0) - self._connect_test_one_interface(memif1) - - memif0.remove_vpp_config() - memif1.remove_vpp_config() - - def test_memif_create_delete(self): - """ Memif create/delete interface """ - - memif = VppMemif(self, MEMIF_ROLE.SLAVE, MEMIF_MODE.ETHERNET) - self._create_delete_test_one_interface(memif) - memif.role = MEMIF_ROLE.MASTER - self._create_delete_test_one_interface(memif) - - def test_memif_create_custom_socket(self): - """ Memif create with non-default socket filename """ - - memif_sockets = [] - # existing path - memif_sockets.append( - VppSocketFilename( - self, 1, b"%s/memif1.sock" % six.ensure_binary( - self.tempdir, encoding='utf-8'))) - # default path (test tempdir) - memif_sockets.append( - VppSocketFilename( - self, - 2, - b"memif2.sock", - add_default_folder=True)) - # create new folder in default folder - memif_sockets.append( - VppSocketFilename( - self, - 3, - b"sock/memif3.sock", - add_default_folder=True)) - - memif = VppMemif(self, MEMIF_ROLE.SLAVE, MEMIF_MODE.ETHERNET) - - for sock in memif_sockets: - sock.add_vpp_config() - memif.socket_id = sock.socket_id - memif.role = MEMIF_ROLE.SLAVE - self._create_delete_test_one_interface(memif) - memif.role = MEMIF_ROLE.MASTER - self._create_delete_test_one_interface(memif) - - def test_memif_connect(self): - """ Memif connect """ - memif = VppMemif(self, MEMIF_ROLE.SLAVE, MEMIF_MODE.ETHERNET, - ring_size=1024, buffer_size=2048) - - remote_socket = VppSocketFilename(self.remote_test, 1, - b"%s/memif.sock" % six.ensure_binary( - self.tempdir, encoding='utf-8')) - remote_socket.add_vpp_config() - - remote_memif = VppMemif(self.remote_test, MEMIF_ROLE.MASTER, - MEMIF_MODE.ETHERNET, socket_id=1, - ring_size=1024, buffer_size=2048) - - self._connect_test_interface_pair(memif, remote_memif) - - memif.role = MEMIF_ROLE.MASTER - remote_memif.role = MEMIF_ROLE.SLAVE - - self._connect_test_interface_pair(memif, remote_memif) - - def _create_icmp(self, pg, memif, num): - pkts = [] - for i in range(num): - pkt = (Ether(dst=pg.local_mac, src=pg.remote_mac) / - IP(src=pg.remote_ip4, dst=memif.ip_prefix.address) / - ICMP(id=memif.if_id, type='echo-request', seq=i)) - pkts.append(pkt) - return pkts - - def _verify_icmp(self, pg, memif, rx, seq): - ip = rx[IP] - self.assertEqual(ip.src, memif.ip_prefix.address) - self.assertEqual(ip.dst, pg.remote_ip4) - self.assertEqual(ip.proto, 1) - icmp = rx[ICMP] - self.assertEqual(icmp.type, 0) # echo-reply - self.assertEqual(icmp.id, memif.if_id) - self.assertEqual(icmp.seq, seq) - - def test_memif_ping(self): - """ Memif ping """ - - memif = VppMemif(self, MEMIF_ROLE.SLAVE, MEMIF_MODE.ETHERNET) - - remote_socket = VppSocketFilename(self.remote_test, 1, - b"%s/memif.sock" % six.ensure_binary( - self.tempdir, encoding='utf-8')) - remote_socket.add_vpp_config() - - remote_memif = VppMemif(self.remote_test, MEMIF_ROLE.MASTER, - MEMIF_MODE.ETHERNET, socket_id=1) - - memif.add_vpp_config() - memif.config_ip4() - memif.admin_up() - - remote_memif.add_vpp_config() - remote_memif.config_ip4() - remote_memif.admin_up() - - self.assertTrue(memif.wait_for_link_up(5)) - self.assertTrue(remote_memif.wait_for_link_up(5)) - - # add routing to remote vpp - route = VppIpRoute(self.remote_test, self.pg0._local_ip4_subnet, 24, - [VppRoutePath(memif.ip_prefix.address, 0xffffffff)], - register=False) - - route.add_vpp_config() - - # create ICMP echo-request from local pg to remote memif - packet_num = 10 - pkts = self._create_icmp(self.pg0, remote_memif, packet_num) - - self.pg0.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg0.get_capture(packet_num, timeout=2) - seq = 0 - for c in capture: - self._verify_icmp(self.pg0, remote_memif, c, seq) - seq += 1 - - route.remove_vpp_config() - - -if __name__ == '__main__': - unittest.main(testRunner=VppTestRunner) diff --git a/test/test_nat.py b/test/test_nat.py deleted file mode 100644 index a64b5709c72..00000000000 --- a/test/test_nat.py +++ /dev/null @@ -1,9575 +0,0 @@ -#!/usr/bin/env python - -import socket -import unittest -import struct -import random - -from framework import VppTestCase, VppTestRunner, running_extended_tests - -import scapy.compat -from scapy.layers.inet import IP, TCP, UDP, ICMP -from scapy.layers.inet import IPerror, TCPerror, UDPerror, ICMPerror -from scapy.layers.inet6 import IPv6, ICMPv6EchoRequest, ICMPv6EchoReply, \ - ICMPv6ND_NS, ICMPv6ND_NA, ICMPv6NDOptDstLLAddr, fragment6 -from scapy.layers.inet6 import ICMPv6DestUnreach, IPerror6, IPv6ExtHdrFragment -from scapy.layers.l2 import Ether, ARP, GRE -from scapy.data import IP_PROTOS -from scapy.packet import bind_layers, Raw -from util import ppp -from ipfix import IPFIX, Set, Template, Data, IPFIXDecoder -from time import sleep -from util import ip4_range -from vpp_papi import mac_pton -from syslog_rfc5424_parser import SyslogMessage, ParseError -from syslog_rfc5424_parser.constants import SyslogFacility, SyslogSeverity -from io import BytesIO -from vpp_papi import VppEnum -from vpp_ip_route import VppIpRoute, VppRoutePath, FibPathType -from vpp_neighbor import VppNeighbor -from vpp_ip import VppIpAddress, VppIpPrefix -from scapy.all import bind_layers, Packet, ByteEnumField, ShortField, \ - IPField, IntField, LongField, XByteField, FlagsField, FieldLenField, \ - PacketListField -from ipaddress import IPv6Network - - -# NAT HA protocol event data -class Event(Packet): - name = "Event" - fields_desc = [ByteEnumField("event_type", None, - {1: "add", 2: "del", 3: "refresh"}), - ByteEnumField("protocol", None, - {0: "udp", 1: "tcp", 2: "icmp"}), - ShortField("flags", 0), - IPField("in_addr", None), - IPField("out_addr", None), - ShortField("in_port", None), - ShortField("out_port", None), - IPField("eh_addr", None), - IPField("ehn_addr", None), - ShortField("eh_port", None), - ShortField("ehn_port", None), - IntField("fib_index", None), - IntField("total_pkts", 0), - LongField("total_bytes", 0)] - - def extract_padding(self, s): - return "", s - - -# NAT HA protocol header -class HANATStateSync(Packet): - name = "HA NAT state sync" - fields_desc = [XByteField("version", 1), - FlagsField("flags", 0, 8, ['ACK']), - FieldLenField("count", None, count_of="events"), - IntField("sequence_number", 1), - IntField("thread_index", 0), - PacketListField("events", [], Event, - count_from=lambda pkt: pkt.count)] - - -class MethodHolder(VppTestCase): - """ NAT create capture and verify method holder """ - - @property - def config_flags(self): - return VppEnum.vl_api_nat_config_flags_t - - @property - def SYSLOG_SEVERITY(self): - return VppEnum.vl_api_syslog_severity_t - - def clear_nat44(self): - """ - Clear NAT44 configuration. - """ - if hasattr(self, 'pg7') and hasattr(self, 'pg8'): - if self.pg7.has_ip4_config: - self.pg7.unconfig_ip4() - - self.vapi.nat44_forwarding_enable_disable(enable=0) - - interfaces = self.vapi.nat44_interface_addr_dump() - for intf in interfaces: - self.vapi.nat44_add_del_interface_addr( - is_add=0, - sw_if_index=intf.sw_if_index, - flags=intf.flags) - - self.vapi.nat_ipfix_enable_disable(domain_id=self.ipfix_domain_id, - src_port=self.ipfix_src_port, - enable=0) - self.ipfix_src_port = 4739 - self.ipfix_domain_id = 1 - - self.vapi.syslog_set_filter( - self.SYSLOG_SEVERITY.SYSLOG_API_SEVERITY_EMERG) - - self.vapi.nat_ha_set_listener(ip_address='0.0.0.0', port=0, - path_mtu=512) - self.vapi.nat_ha_set_failover(ip_address='0.0.0.0', port=0, - session_refresh_interval=10) - - interfaces = self.vapi.nat44_interface_dump() - for intf in interfaces: - if intf.flags & self.config_flags.NAT_IS_INSIDE and \ - intf.flags & self.config_flags.NAT_IS_OUTSIDE: - self.vapi.nat44_interface_add_del_feature( - sw_if_index=intf.sw_if_index) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=intf.sw_if_index, - flags=intf.flags) - - interfaces = self.vapi.nat44_interface_output_feature_dump() - for intf in interfaces: - self.vapi.nat44_interface_add_del_output_feature( - is_add=0, - flags=intf.flags, - sw_if_index=intf.sw_if_index) - static_mappings = self.vapi.nat44_static_mapping_dump() - for sm in static_mappings: - self.vapi.nat44_add_del_static_mapping( - is_add=0, - local_ip_address=sm.local_ip_address, - external_ip_address=sm.external_ip_address, - external_sw_if_index=sm.external_sw_if_index, - local_port=sm.local_port, - external_port=sm.external_port, - vrf_id=sm.vrf_id, - protocol=sm.protocol, - flags=sm.flags, tag=sm.tag) - - lb_static_mappings = self.vapi.nat44_lb_static_mapping_dump() - for lb_sm in lb_static_mappings: - self.vapi.nat44_add_del_lb_static_mapping( - is_add=0, - flags=lb_sm.flags, - external_addr=lb_sm.external_addr, - external_port=lb_sm.external_port, - protocol=lb_sm.protocol, - local_num=0, locals=[], - tag=lb_sm.tag) - - identity_mappings = self.vapi.nat44_identity_mapping_dump() - for id_m in identity_mappings: - self.vapi.nat44_add_del_identity_mapping( - ip_address=id_m.ip_address, - sw_if_index=id_m.sw_if_index, - port=id_m.port, - flags=id_m.flags, - vrf_id=id_m.vrf_id, - protocol=id_m.protocol) - - addresses = self.vapi.nat44_address_dump() - for addr in addresses: - self.vapi.nat44_add_del_address_range( - first_ip_address=addr.ip_address, - last_ip_address=addr.ip_address, - vrf_id=0xFFFFFFFF, flags=addr.flags) - - self.vapi.nat_set_reass(timeout=2, max_reass=1024, max_frag=5, - drop_frag=0) - self.vapi.nat_set_reass(timeout=2, max_reass=1024, max_frag=5, - drop_frag=0, is_ip6=1) - self.verify_no_nat44_user() - self.vapi.nat_set_timeouts(udp=300, tcp_established=7440, - tcp_transitory=240, icmp=60) - self.vapi.nat_set_addr_and_port_alloc_alg() - self.vapi.nat_set_mss_clamping(enable=0, mss_value=1500) - - def nat44_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, - proto=0, tag="", flags=0): - """ - Add/delete NAT44 static mapping - - :param local_ip: Local IP address - :param external_ip: External IP address - :param local_port: Local port number (Optional) - :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 - :param proto: IP protocol (Mandatory if port specified) - :param tag: Opaque string tag - :param flags: NAT configuration flags - """ - - if not (local_port and external_port): - flags |= self.config_flags.NAT_IS_ADDR_ONLY - - self.vapi.nat44_add_del_static_mapping( - is_add=is_add, - local_ip_address=local_ip, - external_ip_address=external_ip, - external_sw_if_index=external_sw_if_index, - local_port=local_port, - external_port=external_port, - vrf_id=vrf_id, protocol=proto, - flags=flags, - tag=tag) - - def nat44_add_address(self, ip, is_add=1, vrf_id=0xFFFFFFFF, twice_nat=0): - """ - Add/delete NAT44 address - - :param ip: IP address - :param is_add: 1 if add, 0 if delete (Default add) - :param twice_nat: twice NAT address for external hosts - """ - flags = self.config_flags.NAT_IS_TWICE_NAT if twice_nat else 0 - self.vapi.nat44_add_del_address_range(first_ip_address=ip, - last_ip_address=ip, - vrf_id=vrf_id, - is_add=is_add, - flags=flags) - - def create_stream_in(self, in_if, out_if, dst_ip=None, ttl=64): - """ - Create packet stream for inside network - - :param in_if: Inside interface - :param out_if: Outside interface - :param dst_ip: Destination address - :param ttl: TTL of generated packets - """ - if dst_ip is None: - dst_ip = out_if.remote_ip4 - - pkts = [] - # TCP - p = (Ether(dst=in_if.local_mac, src=in_if.remote_mac) / - IP(src=in_if.remote_ip4, dst=dst_ip, ttl=ttl) / - TCP(sport=self.tcp_port_in, dport=20)) - pkts.append(p) - - # UDP - p = (Ether(dst=in_if.local_mac, src=in_if.remote_mac) / - IP(src=in_if.remote_ip4, dst=dst_ip, ttl=ttl) / - UDP(sport=self.udp_port_in, dport=20)) - pkts.append(p) - - # ICMP - p = (Ether(dst=in_if.local_mac, src=in_if.remote_mac) / - IP(src=in_if.remote_ip4, dst=dst_ip, ttl=ttl) / - ICMP(id=self.icmp_id_in, type='echo-request')) - pkts.append(p) - - return pkts - - def compose_ip6(self, ip4, pref, plen): - """ - Compose IPv4-embedded IPv6 addresses - - :param ip4: IPv4 address - :param pref: IPv6 prefix - :param plen: IPv6 prefix length - :returns: IPv4-embedded IPv6 addresses - """ - pref_n = list(socket.inet_pton(socket.AF_INET6, pref)) - ip4_n = list(socket.inet_pton(socket.AF_INET, ip4)) - if plen == 32: - pref_n[4] = ip4_n[0] - pref_n[5] = ip4_n[1] - pref_n[6] = ip4_n[2] - pref_n[7] = ip4_n[3] - elif plen == 40: - pref_n[5] = ip4_n[0] - pref_n[6] = ip4_n[1] - pref_n[7] = ip4_n[2] - pref_n[9] = ip4_n[3] - elif plen == 48: - pref_n[6] = ip4_n[0] - pref_n[7] = ip4_n[1] - pref_n[9] = ip4_n[2] - pref_n[10] = ip4_n[3] - elif plen == 56: - pref_n[7] = ip4_n[0] - pref_n[9] = ip4_n[1] - pref_n[10] = ip4_n[2] - pref_n[11] = ip4_n[3] - elif plen == 64: - pref_n[9] = ip4_n[0] - pref_n[10] = ip4_n[1] - pref_n[11] = ip4_n[2] - pref_n[12] = ip4_n[3] - elif plen == 96: - pref_n[12] = ip4_n[0] - pref_n[13] = ip4_n[1] - pref_n[14] = ip4_n[2] - pref_n[15] = ip4_n[3] - packed_pref_n = b''.join([scapy.compat.chb(x) for x in pref_n]) - return socket.inet_ntop(socket.AF_INET6, packed_pref_n) - - def extract_ip4(self, ip6, plen): - """ - Extract IPv4 address embedded in IPv6 addresses - - :param ip6: IPv6 address - :param plen: IPv6 prefix length - :returns: extracted IPv4 address - """ - ip6_n = list(socket.inet_pton(socket.AF_INET6, ip6)) - ip4_n = [None] * 4 - if plen == 32: - ip4_n[0] = ip6_n[4] - ip4_n[1] = ip6_n[5] - ip4_n[2] = ip6_n[6] - ip4_n[3] = ip6_n[7] - elif plen == 40: - ip4_n[0] = ip6_n[5] - ip4_n[1] = ip6_n[6] - ip4_n[2] = ip6_n[7] - ip4_n[3] = ip6_n[9] - elif plen == 48: - ip4_n[0] = ip6_n[6] - ip4_n[1] = ip6_n[7] - ip4_n[2] = ip6_n[9] - ip4_n[3] = ip6_n[10] - elif plen == 56: - ip4_n[0] = ip6_n[7] - ip4_n[1] = ip6_n[9] - ip4_n[2] = ip6_n[10] - ip4_n[3] = ip6_n[11] - elif plen == 64: - ip4_n[0] = ip6_n[9] - ip4_n[1] = ip6_n[10] - ip4_n[2] = ip6_n[11] - ip4_n[3] = ip6_n[12] - elif plen == 96: - ip4_n[0] = ip6_n[12] - ip4_n[1] = ip6_n[13] - ip4_n[2] = ip6_n[14] - ip4_n[3] = ip6_n[15] - return socket.inet_ntop(socket.AF_INET, ''.join(ip4_n)) - - def create_stream_in_ip6(self, in_if, out_if, hlim=64, pref=None, plen=0): - """ - Create IPv6 packet stream for inside network - - :param in_if: Inside interface - :param out_if: Outside interface - :param ttl: Hop Limit of generated packets - :param pref: NAT64 prefix - :param plen: NAT64 prefix length - """ - pkts = [] - if pref is None: - dst = ''.join(['64:ff9b::', out_if.remote_ip4]) - else: - dst = self.compose_ip6(out_if.remote_ip4, pref, plen) - - # TCP - p = (Ether(dst=in_if.local_mac, src=in_if.remote_mac) / - IPv6(src=in_if.remote_ip6, dst=dst, hlim=hlim) / - TCP(sport=self.tcp_port_in, dport=20)) - pkts.append(p) - - # UDP - p = (Ether(dst=in_if.local_mac, src=in_if.remote_mac) / - IPv6(src=in_if.remote_ip6, dst=dst, hlim=hlim) / - UDP(sport=self.udp_port_in, dport=20)) - pkts.append(p) - - # ICMP - p = (Ether(dst=in_if.local_mac, src=in_if.remote_mac) / - IPv6(src=in_if.remote_ip6, dst=dst, hlim=hlim) / - ICMPv6EchoRequest(id=self.icmp_id_in)) - pkts.append(p) - - return pkts - - def create_stream_out(self, out_if, dst_ip=None, ttl=64, - use_inside_ports=False): - """ - Create packet stream for outside network - - :param out_if: Outside interface - :param dst_ip: Destination IP address (Default use global NAT address) - :param ttl: TTL of generated packets - :param use_inside_ports: Use inside NAT ports as destination ports - instead of outside ports - """ - if dst_ip is None: - dst_ip = self.nat_addr - if not use_inside_ports: - tcp_port = self.tcp_port_out - udp_port = self.udp_port_out - icmp_id = self.icmp_id_out - else: - tcp_port = self.tcp_port_in - udp_port = self.udp_port_in - icmp_id = self.icmp_id_in - pkts = [] - # TCP - p = (Ether(dst=out_if.local_mac, src=out_if.remote_mac) / - IP(src=out_if.remote_ip4, dst=dst_ip, ttl=ttl) / - TCP(dport=tcp_port, sport=20)) - pkts.append(p) - - # UDP - p = (Ether(dst=out_if.local_mac, src=out_if.remote_mac) / - IP(src=out_if.remote_ip4, dst=dst_ip, ttl=ttl) / - UDP(dport=udp_port, sport=20)) - pkts.append(p) - - # ICMP - p = (Ether(dst=out_if.local_mac, src=out_if.remote_mac) / - IP(src=out_if.remote_ip4, dst=dst_ip, ttl=ttl) / - ICMP(id=icmp_id, type='echo-reply')) - pkts.append(p) - - return pkts - - def create_stream_out_ip6(self, out_if, src_ip, dst_ip, hl=64): - """ - Create packet stream for outside network - - :param out_if: Outside interface - :param dst_ip: Destination IP address (Default use global NAT address) - :param hl: HL of generated packets - """ - pkts = [] - # TCP - p = (Ether(dst=out_if.local_mac, src=out_if.remote_mac) / - IPv6(src=src_ip, dst=dst_ip, hlim=hl) / - TCP(dport=self.tcp_port_out, sport=20)) - pkts.append(p) - - # UDP - p = (Ether(dst=out_if.local_mac, src=out_if.remote_mac) / - IPv6(src=src_ip, dst=dst_ip, hlim=hl) / - UDP(dport=self.udp_port_out, sport=20)) - pkts.append(p) - - # ICMP - p = (Ether(dst=out_if.local_mac, src=out_if.remote_mac) / - IPv6(src=src_ip, dst=dst_ip, hlim=hl) / - ICMPv6EchoReply(id=self.icmp_id_out)) - pkts.append(p) - - return pkts - - def verify_capture_out(self, capture, nat_ip=None, same_port=False, - dst_ip=None, is_ip6=False): - """ - Verify captured packets on outside network - - :param capture: Captured packets - :param nat_ip: Translated IP address (Default use global NAT address) - :param same_port: Source port number is not translated (Default False) - :param dst_ip: Destination IP address (Default do not verify) - :param is_ip6: If L3 protocol is IPv6 (Default False) - """ - if is_ip6: - IP46 = IPv6 - ICMP46 = ICMPv6EchoRequest - else: - IP46 = IP - ICMP46 = ICMP - if nat_ip is None: - nat_ip = self.nat_addr - for packet in capture: - try: - if not is_ip6: - self.assert_packet_checksums_valid(packet) - self.assertEqual(packet[IP46].src, nat_ip) - if dst_ip is not None: - self.assertEqual(packet[IP46].dst, dst_ip) - if packet.haslayer(TCP): - if same_port: - self.assertEqual(packet[TCP].sport, self.tcp_port_in) - else: - self.assertNotEqual( - packet[TCP].sport, self.tcp_port_in) - self.tcp_port_out = packet[TCP].sport - self.assert_packet_checksums_valid(packet) - 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.udp_port_out = packet[UDP].sport - else: - if same_port: - self.assertEqual(packet[ICMP46].id, self.icmp_id_in) - else: - self.assertNotEqual(packet[ICMP46].id, self.icmp_id_in) - self.icmp_id_out = packet[ICMP46].id - self.assert_packet_checksums_valid(packet) - except: - self.logger.error(ppp("Unexpected or invalid packet " - "(outside network):", packet)) - raise - - def verify_capture_out_ip6(self, capture, nat_ip, same_port=False, - dst_ip=None): - """ - Verify captured packets on outside network - - :param capture: Captured packets - :param nat_ip: Translated IP address - :param same_port: Source port number is not translated (Default False) - :param dst_ip: Destination IP address (Default do not verify) - """ - return self.verify_capture_out(capture, nat_ip, same_port, dst_ip, - True) - - def verify_capture_in(self, capture, in_if): - """ - Verify captured packets on inside network - - :param capture: Captured packets - :param in_if: Inside interface - """ - for packet in capture: - try: - self.assert_packet_checksums_valid(packet) - self.assertEqual(packet[IP].dst, in_if.remote_ip4) - if packet.haslayer(TCP): - self.assertEqual(packet[TCP].dport, self.tcp_port_in) - elif packet.haslayer(UDP): - self.assertEqual(packet[UDP].dport, 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_capture_in_ip6(self, capture, src_ip, dst_ip): - """ - Verify captured IPv6 packets on inside network - - :param capture: Captured packets - :param src_ip: Source IP - :param dst_ip: Destination IP address - """ - for packet in capture: - try: - self.assertEqual(packet[IPv6].src, src_ip) - self.assertEqual(packet[IPv6].dst, dst_ip) - self.assert_packet_checksums_valid(packet) - if packet.haslayer(TCP): - self.assertEqual(packet[TCP].dport, self.tcp_port_in) - elif packet.haslayer(UDP): - self.assertEqual(packet[UDP].dport, self.udp_port_in) - else: - self.assertEqual(packet[ICMPv6EchoReply].id, - self.icmp_id_in) - except: - 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_capture_out_with_icmp_errors(self, capture, src_ip=None, - icmp_type=11): - """ - Verify captured packets with ICMP errors on outside network - - :param capture: Captured packets - :param src_ip: Translated IP address or IP address of VPP - (Default use global NAT address) - :param icmp_type: Type of error ICMP packet - we are expecting (Default 11) - """ - if src_ip is None: - src_ip = self.nat_addr - for packet in capture: - try: - self.assertEqual(packet[IP].src, src_ip) - self.assertEqual(packet.haslayer(ICMP), 1) - icmp = packet[ICMP] - self.assertEqual(icmp.type, icmp_type) - self.assertTrue(icmp.haslayer(IPerror)) - inner_ip = icmp[IPerror] - if inner_ip.haslayer(TCPerror): - self.assertEqual(inner_ip[TCPerror].dport, - self.tcp_port_out) - elif inner_ip.haslayer(UDPerror): - self.assertEqual(inner_ip[UDPerror].dport, - self.udp_port_out) - else: - self.assertEqual(inner_ip[ICMPerror].id, self.icmp_id_out) - except: - self.logger.error(ppp("Unexpected or invalid packet " - "(outside network):", packet)) - raise - - def verify_capture_in_with_icmp_errors(self, capture, in_if, icmp_type=11): - """ - Verify captured packets with ICMP errors on inside network - - :param capture: Captured packets - :param in_if: Inside interface - :param icmp_type: Type of error ICMP packet - we are expecting (Default 11) - """ - for packet in capture: - try: - self.assertEqual(packet[IP].dst, in_if.remote_ip4) - self.assertEqual(packet.haslayer(ICMP), 1) - icmp = packet[ICMP] - self.assertEqual(icmp.type, icmp_type) - self.assertTrue(icmp.haslayer(IPerror)) - inner_ip = icmp[IPerror] - if inner_ip.haslayer(TCPerror): - self.assertEqual(inner_ip[TCPerror].sport, - self.tcp_port_in) - elif inner_ip.haslayer(UDPerror): - self.assertEqual(inner_ip[UDPerror].sport, - self.udp_port_in) - else: - self.assertEqual(inner_ip[ICMPerror].id, self.icmp_id_in) - except: - self.logger.error(ppp("Unexpected or invalid packet " - "(inside network):", packet)) - raise - - def create_stream_frag(self, src_if, dst, sport, dport, data, - proto=IP_PROTOS.tcp, echo_reply=False): - """ - Create fragmented packet stream - - :param src_if: Source interface - :param dst: Destination IPv4 address - :param sport: Source port - :param dport: Destination port - :param data: Payload data - :param proto: protocol (TCP, UDP, ICMP) - :param echo_reply: use echo_reply if protocol is ICMP - :returns: Fragments - """ - if proto == IP_PROTOS.tcp: - p = (IP(src=src_if.remote_ip4, dst=dst) / - TCP(sport=sport, dport=dport) / - Raw(data)) - p = p.__class__(scapy.compat.raw(p)) - chksum = p[TCP].chksum - proto_header = TCP(sport=sport, dport=dport, chksum=chksum) - elif proto == IP_PROTOS.udp: - proto_header = UDP(sport=sport, dport=dport) - elif proto == IP_PROTOS.icmp: - if not echo_reply: - proto_header = ICMP(id=sport, type='echo-request') - else: - proto_header = ICMP(id=sport, type='echo-reply') - else: - raise Exception("Unsupported protocol") - id = random.randint(0, 65535) - pkts = [] - if proto == IP_PROTOS.tcp: - raw = Raw(data[0:4]) - else: - raw = Raw(data[0:16]) - p = (Ether(src=src_if.remote_mac, dst=src_if.local_mac) / - IP(src=src_if.remote_ip4, dst=dst, flags="MF", frag=0, id=id) / - proto_header / - raw) - pkts.append(p) - if proto == IP_PROTOS.tcp: - raw = Raw(data[4:20]) - else: - raw = Raw(data[16:32]) - p = (Ether(src=src_if.remote_mac, dst=src_if.local_mac) / - IP(src=src_if.remote_ip4, dst=dst, flags="MF", frag=3, id=id, - proto=proto) / - raw) - pkts.append(p) - if proto == IP_PROTOS.tcp: - raw = Raw(data[20:]) - else: - raw = Raw(data[32:]) - p = (Ether(src=src_if.remote_mac, dst=src_if.local_mac) / - IP(src=src_if.remote_ip4, dst=dst, frag=5, proto=proto, - id=id) / - raw) - pkts.append(p) - return pkts - - def create_stream_frag_ip6(self, src_if, dst, sport, dport, data, - pref=None, plen=0, frag_size=128): - """ - Create fragmented packet stream - - :param src_if: Source interface - :param dst: Destination IPv4 address - :param sport: Source TCP port - :param dport: Destination TCP port - :param data: Payload data - :param pref: NAT64 prefix - :param plen: NAT64 prefix length - :param fragsize: size of fragments - :returns: Fragments - """ - if pref is None: - dst_ip6 = ''.join(['64:ff9b::', dst]) - else: - dst_ip6 = self.compose_ip6(dst, pref, plen) - - p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) / - IPv6(src=src_if.remote_ip6, dst=dst_ip6) / - IPv6ExtHdrFragment(id=random.randint(0, 65535)) / - TCP(sport=sport, dport=dport) / - Raw(data)) - - return fragment6(p, frag_size) - - def reass_frags_and_verify(self, frags, src, dst): - """ - Reassemble and verify fragmented packet - - :param frags: Captured fragments - :param src: Source IPv4 address to verify - :param dst: Destination IPv4 address to verify - - :returns: Reassembled IPv4 packet - """ - buffer = BytesIO() - for p in frags: - self.assertEqual(p[IP].src, src) - self.assertEqual(p[IP].dst, dst) - self.assert_ip_checksum_valid(p) - buffer.seek(p[IP].frag * 8) - buffer.write(bytes(p[IP].payload)) - ip = IP(src=frags[0][IP].src, dst=frags[0][IP].dst, - proto=frags[0][IP].proto) - if ip.proto == IP_PROTOS.tcp: - p = (ip / TCP(buffer.getvalue())) - self.assert_tcp_checksum_valid(p) - elif ip.proto == IP_PROTOS.udp: - p = (ip / UDP(buffer.getvalue()[:8]) / - Raw(buffer.getvalue()[8:])) - elif ip.proto == IP_PROTOS.icmp: - p = (ip / ICMP(buffer.getvalue())) - return p - - def reass_frags_and_verify_ip6(self, frags, src, dst): - """ - Reassemble and verify fragmented packet - - :param frags: Captured fragments - :param src: Source IPv6 address to verify - :param dst: Destination IPv6 address to verify - - :returns: Reassembled IPv6 packet - """ - buffer = BytesIO() - for p in frags: - self.assertEqual(p[IPv6].src, src) - self.assertEqual(p[IPv6].dst, dst) - buffer.seek(p[IPv6ExtHdrFragment].offset * 8) - buffer.write(bytes(p[IPv6ExtHdrFragment].payload)) - ip = IPv6(src=frags[0][IPv6].src, dst=frags[0][IPv6].dst, - nh=frags[0][IPv6ExtHdrFragment].nh) - if ip.nh == IP_PROTOS.tcp: - p = (ip / TCP(buffer.getvalue())) - elif ip.nh == IP_PROTOS.udp: - p = (ip / UDP(buffer.getvalue())) - self.assert_packet_checksums_valid(p) - return p - - def initiate_tcp_session(self, in_if, out_if): - """ - Initiates TCP session - - :param in_if: Inside interface - :param out_if: Outside interface - """ - try: - # SYN packet in->out - p = (Ether(src=in_if.remote_mac, dst=in_if.local_mac) / - IP(src=in_if.remote_ip4, dst=out_if.remote_ip4) / - TCP(sport=self.tcp_port_in, dport=self.tcp_external_port, - flags="S")) - in_if.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = out_if.get_capture(1) - p = capture[0] - self.tcp_port_out = p[TCP].sport - - # SYN + ACK packet out->in - p = (Ether(src=out_if.remote_mac, dst=out_if.local_mac) / - IP(src=out_if.remote_ip4, dst=self.nat_addr) / - TCP(sport=self.tcp_external_port, dport=self.tcp_port_out, - flags="SA")) - out_if.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - in_if.get_capture(1) - - # ACK packet in->out - p = (Ether(src=in_if.remote_mac, dst=in_if.local_mac) / - IP(src=in_if.remote_ip4, dst=out_if.remote_ip4) / - TCP(sport=self.tcp_port_in, dport=self.tcp_external_port, - flags="A")) - in_if.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - out_if.get_capture(1) - - except: - self.logger.error("TCP 3 way handshake failed") - 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(scapy.compat.orb(record[230]), [4, 5]) - if scapy.compat.orb(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.nat_addr), - record[225]) - # ingressVRFID - self.assertEqual(struct.pack("!I", 0), record[234]) - # protocolIdentifier/sourceTransportPort - # /postNAPTSourceTransportPort - if IP_PROTOS.icmp == scapy.compat.orb(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 == scapy.compat.orb(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 == scapy.compat.orb(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(scapy.compat.orb(record[230]), 3) - # natPoolID - self.assertEqual(struct.pack("!I", 0), record[283]) - - def verify_ipfix_max_sessions(self, data, limit): - """ - Verify IPFIX maximum session entries exceeded event - - :param data: Decoded IPFIX data records - :param limit: Number of maximum session entries that can be created. - """ - self.assertEqual(1, len(data)) - record = data[0] - # natEvent - self.assertEqual(scapy.compat.orb(record[230]), 13) - # natQuotaExceededEvent - self.assertEqual(struct.pack("I", 1), record[466]) - # maxSessionEntries - self.assertEqual(struct.pack("I", limit), record[471]) - - def verify_ipfix_max_bibs(self, data, limit): - """ - Verify IPFIX maximum BIB entries exceeded event - - :param data: Decoded IPFIX data records - :param limit: Number of maximum BIB entries that can be created. - """ - self.assertEqual(1, len(data)) - record = data[0] - # natEvent - self.assertEqual(scapy.compat.orb(record[230]), 13) - # natQuotaExceededEvent - self.assertEqual(struct.pack("I", 2), record[466]) - # maxBIBEntries - self.assertEqual(struct.pack("I", limit), record[472]) - - def verify_ipfix_max_fragments_ip6(self, data, limit, src_addr): - """ - Verify IPFIX maximum IPv6 fragments pending reassembly exceeded event - - :param data: Decoded IPFIX data records - :param limit: Number of maximum fragments pending reassembly - :param src_addr: IPv6 source address - """ - self.assertEqual(1, len(data)) - record = data[0] - # natEvent - self.assertEqual(scapy.compat.orb(record[230]), 13) - # natQuotaExceededEvent - self.assertEqual(struct.pack("I", 5), record[466]) - # maxFragmentsPendingReassembly - self.assertEqual(struct.pack("I", limit), record[475]) - # sourceIPv6Address - self.assertEqual(src_addr, record[27]) - - def verify_ipfix_max_fragments_ip4(self, data, limit, src_addr): - """ - Verify IPFIX maximum IPv4 fragments pending reassembly exceeded event - - :param data: Decoded IPFIX data records - :param limit: Number of maximum fragments pending reassembly - :param src_addr: IPv4 source address - """ - self.assertEqual(1, len(data)) - record = data[0] - # natEvent - self.assertEqual(scapy.compat.orb(record[230]), 13) - # natQuotaExceededEvent - self.assertEqual(struct.pack("I", 5), record[466]) - # maxFragmentsPendingReassembly - self.assertEqual(struct.pack("I", limit), record[475]) - # sourceIPv4Address - self.assertEqual(src_addr, record[8]) - - def verify_ipfix_bib(self, data, is_create, src_addr): - """ - Verify IPFIX NAT64 BIB create and delete events - - :param data: Decoded IPFIX data records - :param is_create: Create event if nonzero value otherwise delete event - :param src_addr: IPv6 source address - """ - self.assertEqual(1, len(data)) - record = data[0] - # natEvent - if is_create: - self.assertEqual(scapy.compat.orb(record[230]), 10) - else: - self.assertEqual(scapy.compat.orb(record[230]), 11) - # sourceIPv6Address - self.assertEqual(src_addr, record[27]) - # postNATSourceIPv4Address - self.assertEqual(self.nat_addr_n, record[225]) - # protocolIdentifier - self.assertEqual(IP_PROTOS.tcp, scapy.compat.orb(record[4])) - # ingressVRFID - self.assertEqual(struct.pack("!I", 0), record[234]) - # sourceTransportPort - self.assertEqual(struct.pack("!H", self.tcp_port_in), record[7]) - # postNAPTSourceTransportPort - self.assertEqual(struct.pack("!H", self.tcp_port_out), record[227]) - - def verify_ipfix_nat64_ses(self, data, is_create, src_addr, dst_addr, - dst_port): - """ - Verify IPFIX NAT64 session create and delete events - - :param data: Decoded IPFIX data records - :param is_create: Create event if nonzero value otherwise delete event - :param src_addr: IPv6 source address - :param dst_addr: IPv4 destination address - :param dst_port: destination TCP port - """ - self.assertEqual(1, len(data)) - record = data[0] - # natEvent - if is_create: - self.assertEqual(scapy.compat.orb(record[230]), 6) - else: - self.assertEqual(scapy.compat.orb(record[230]), 7) - # sourceIPv6Address - self.assertEqual(src_addr, record[27]) - # destinationIPv6Address - self.assertEqual(socket.inet_pton(socket.AF_INET6, - self.compose_ip6(dst_addr, - '64:ff9b::', - 96)), - record[28]) - # postNATSourceIPv4Address - self.assertEqual(self.nat_addr_n, record[225]) - # postNATDestinationIPv4Address - self.assertEqual(socket.inet_pton(socket.AF_INET, dst_addr), - record[226]) - # protocolIdentifier - self.assertEqual(IP_PROTOS.tcp, scapy.compat.orb(record[4])) - # ingressVRFID - self.assertEqual(struct.pack("!I", 0), record[234]) - # sourceTransportPort - self.assertEqual(struct.pack("!H", self.tcp_port_in), record[7]) - # postNAPTSourceTransportPort - self.assertEqual(struct.pack("!H", self.tcp_port_out), record[227]) - # destinationTransportPort - self.assertEqual(struct.pack("!H", dst_port), record[11]) - # postNAPTDestinationTransportPort - self.assertEqual(struct.pack("!H", dst_port), record[228]) - - def verify_no_nat44_user(self): - """ Verify that there is no NAT44 user """ - users = self.vapi.nat44_user_dump() - self.assertEqual(len(users), 0) - users = self.statistics.get_counter('/nat44/total-users') - self.assertEqual(users[0][0], 0) - sessions = self.statistics.get_counter('/nat44/total-sessions') - self.assertEqual(sessions[0][0], 0) - - def verify_ipfix_max_entries_per_user(self, data, limit, src_addr): - """ - Verify IPFIX maximum entries per user exceeded event - - :param data: Decoded IPFIX data records - :param limit: Number of maximum entries per user - :param src_addr: IPv4 source address - """ - self.assertEqual(1, len(data)) - record = data[0] - # natEvent - self.assertEqual(scapy.compat.orb(record[230]), 13) - # natQuotaExceededEvent - self.assertEqual(struct.pack("I", 3), record[466]) - # maxEntriesPerUser - self.assertEqual(struct.pack("I", limit), record[473]) - # sourceIPv4Address - self.assertEqual(src_addr, record[8]) - - def verify_syslog_apmap(self, data, is_add=True): - message = data.decode('utf-8') - try: - message = SyslogMessage.parse(message) - except ParseError as e: - self.logger.error(e) - raise - else: - self.assertEqual(message.severity, SyslogSeverity.info) - self.assertEqual(message.appname, 'NAT') - self.assertEqual(message.msgid, 'APMADD' if is_add else 'APMDEL') - sd_params = message.sd.get('napmap') - self.assertTrue(sd_params is not None) - self.assertEqual(sd_params.get('IATYP'), 'IPv4') - self.assertEqual(sd_params.get('ISADDR'), self.pg0.remote_ip4) - self.assertEqual(sd_params.get('ISPORT'), "%d" % self.tcp_port_in) - self.assertEqual(sd_params.get('XATYP'), 'IPv4') - self.assertEqual(sd_params.get('XSADDR'), self.nat_addr) - self.assertEqual(sd_params.get('XSPORT'), "%d" % self.tcp_port_out) - self.assertEqual(sd_params.get('PROTO'), "%d" % IP_PROTOS.tcp) - self.assertTrue(sd_params.get('SSUBIX') is not None) - self.assertEqual(sd_params.get('SVLAN'), '0') - - def verify_syslog_sess(self, data, is_add=True, is_ip6=False): - message = data.decode('utf-8') - try: - message = SyslogMessage.parse(message) - except ParseError as e: - self.logger.error(e) - raise - else: - self.assertEqual(message.severity, SyslogSeverity.info) - self.assertEqual(message.appname, 'NAT') - self.assertEqual(message.msgid, 'SADD' if is_add else 'SDEL') - sd_params = message.sd.get('nsess') - self.assertTrue(sd_params is not None) - if is_ip6: - self.assertEqual(sd_params.get('IATYP'), 'IPv6') - self.assertEqual(sd_params.get('ISADDR'), self.pg0.remote_ip6) - else: - self.assertEqual(sd_params.get('IATYP'), 'IPv4') - self.assertEqual(sd_params.get('ISADDR'), self.pg0.remote_ip4) - self.assertTrue(sd_params.get('SSUBIX') is not None) - self.assertEqual(sd_params.get('ISPORT'), "%d" % self.tcp_port_in) - self.assertEqual(sd_params.get('XATYP'), 'IPv4') - self.assertEqual(sd_params.get('XSADDR'), self.nat_addr) - self.assertEqual(sd_params.get('XSPORT'), "%d" % self.tcp_port_out) - self.assertEqual(sd_params.get('PROTO'), "%d" % IP_PROTOS.tcp) - self.assertEqual(sd_params.get('SVLAN'), '0') - self.assertEqual(sd_params.get('XDADDR'), self.pg1.remote_ip4) - self.assertEqual(sd_params.get('XDPORT'), - "%d" % self.tcp_external_port) - - def verify_mss_value(self, pkt, mss): - """ - Verify TCP MSS value - - :param pkt: - :param mss: - """ - if not pkt.haslayer(IP) or not pkt.haslayer(TCP): - raise TypeError("Not a TCP/IP packet") - - for option in pkt[TCP].options: - if option[0] == 'MSS': - self.assertEqual(option[1], mss) - self.assert_tcp_checksum_valid(pkt) - - @staticmethod - def proto2layer(proto): - if proto == IP_PROTOS.tcp: - return TCP - elif proto == IP_PROTOS.udp: - return UDP - elif proto == IP_PROTOS.icmp: - return ICMP - else: - raise Exception("Unsupported protocol") - - def frag_in_order(self, proto=IP_PROTOS.tcp, dont_translate=False): - layer = self.proto2layer(proto) - - if proto == IP_PROTOS.tcp: - data = b"A" * 4 + b"B" * 16 + b"C" * 3 - else: - data = b"A" * 16 + b"B" * 16 + b"C" * 3 - self.port_in = random.randint(1025, 65535) - - reass = self.vapi.nat_reass_dump() - reass_n_start = len(reass) - - # in2out - pkts = self.create_stream_frag(self.pg0, - self.pg1.remote_ip4, - self.port_in, - 20, - data, - proto) - self.pg0.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - frags = self.pg1.get_capture(len(pkts)) - if not dont_translate: - p = self.reass_frags_and_verify(frags, - self.nat_addr, - self.pg1.remote_ip4) - else: - p = self.reass_frags_and_verify(frags, - self.pg0.remote_ip4, - self.pg1.remote_ip4) - if proto != IP_PROTOS.icmp: - if not dont_translate: - self.assertEqual(p[layer].dport, 20) - self.assertNotEqual(p[layer].sport, self.port_in) - else: - self.assertEqual(p[layer].sport, self.port_in) - else: - if not dont_translate: - self.assertNotEqual(p[layer].id, self.port_in) - else: - self.assertEqual(p[layer].id, self.port_in) - self.assertEqual(data, p[Raw].load) - - # out2in - if not dont_translate: - dst_addr = self.nat_addr - else: - dst_addr = self.pg0.remote_ip4 - if proto != IP_PROTOS.icmp: - sport = 20 - dport = p[layer].sport - else: - sport = p[layer].id - dport = 0 - pkts = self.create_stream_frag(self.pg1, - dst_addr, - sport, - dport, - data, - proto, - echo_reply=True) - self.pg1.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - frags = self.pg0.get_capture(len(pkts)) - p = self.reass_frags_and_verify(frags, - self.pg1.remote_ip4, - self.pg0.remote_ip4) - if proto != IP_PROTOS.icmp: - self.assertEqual(p[layer].sport, 20) - self.assertEqual(p[layer].dport, self.port_in) - else: - self.assertEqual(p[layer].id, self.port_in) - self.assertEqual(data, p[Raw].load) - - reass = self.vapi.nat_reass_dump() - reass_n_end = len(reass) - - self.assertEqual(reass_n_end - reass_n_start, 2) - - def frag_in_order_in_plus_out(self, proto=IP_PROTOS.tcp): - layer = self.proto2layer(proto) - - if proto == IP_PROTOS.tcp: - data = b"A" * 4 + b"B" * 16 + b"C" * 3 - else: - data = b"A" * 16 + b"B" * 16 + b"C" * 3 - self.port_in = random.randint(1025, 65535) - - for i in range(2): - reass = self.vapi.nat_reass_dump() - reass_n_start = len(reass) - - # out2in - pkts = self.create_stream_frag(self.pg0, - self.server_out_addr, - self.port_in, - self.server_out_port, - data, - proto) - self.pg0.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - frags = self.pg1.get_capture(len(pkts)) - p = self.reass_frags_and_verify(frags, - self.pg0.remote_ip4, - self.server_in_addr) - if proto != IP_PROTOS.icmp: - self.assertEqual(p[layer].sport, self.port_in) - self.assertEqual(p[layer].dport, self.server_in_port) - else: - self.assertEqual(p[layer].id, self.port_in) - self.assertEqual(data, p[Raw].load) - - # in2out - if proto != IP_PROTOS.icmp: - pkts = self.create_stream_frag(self.pg1, - self.pg0.remote_ip4, - self.server_in_port, - p[layer].sport, - data, - proto) - else: - pkts = self.create_stream_frag(self.pg1, - self.pg0.remote_ip4, - p[layer].id, - 0, - data, - proto, - echo_reply=True) - self.pg1.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - frags = self.pg0.get_capture(len(pkts)) - p = self.reass_frags_and_verify(frags, - self.server_out_addr, - self.pg0.remote_ip4) - if proto != IP_PROTOS.icmp: - self.assertEqual(p[layer].sport, self.server_out_port) - self.assertEqual(p[layer].dport, self.port_in) - else: - self.assertEqual(p[layer].id, self.port_in) - self.assertEqual(data, p[Raw].load) - - reass = self.vapi.nat_reass_dump() - reass_n_end = len(reass) - - self.assertEqual(reass_n_end - reass_n_start, 2) - - def reass_hairpinning(self, proto=IP_PROTOS.tcp): - layer = self.proto2layer(proto) - - if proto == IP_PROTOS.tcp: - data = b"A" * 4 + b"B" * 16 + b"C" * 3 - else: - data = b"A" * 16 + b"B" * 16 + b"C" * 3 - - # send packet from host to server - pkts = self.create_stream_frag(self.pg0, - self.nat_addr, - self.host_in_port, - self.server_out_port, - data, - proto) - self.pg0.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - frags = self.pg0.get_capture(len(pkts)) - p = self.reass_frags_and_verify(frags, - self.nat_addr, - self.server.ip4) - if proto != IP_PROTOS.icmp: - self.assertNotEqual(p[layer].sport, self.host_in_port) - self.assertEqual(p[layer].dport, self.server_in_port) - else: - self.assertNotEqual(p[layer].id, self.host_in_port) - self.assertEqual(data, p[Raw].load) - - def frag_out_of_order(self, proto=IP_PROTOS.tcp, dont_translate=False): - layer = self.proto2layer(proto) - - if proto == IP_PROTOS.tcp: - data = b"A" * 4 + b"B" * 16 + b"C" * 3 - else: - data = b"A" * 16 + b"B" * 16 + b"C" * 3 - self.port_in = random.randint(1025, 65535) - - for i in range(2): - # in2out - pkts = self.create_stream_frag(self.pg0, - self.pg1.remote_ip4, - self.port_in, - 20, - data, - proto) - pkts.reverse() - self.pg0.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - frags = self.pg1.get_capture(len(pkts)) - if not dont_translate: - p = self.reass_frags_and_verify(frags, - self.nat_addr, - self.pg1.remote_ip4) - else: - p = self.reass_frags_and_verify(frags, - self.pg0.remote_ip4, - self.pg1.remote_ip4) - if proto != IP_PROTOS.icmp: - if not dont_translate: - self.assertEqual(p[layer].dport, 20) - self.assertNotEqual(p[layer].sport, self.port_in) - else: - self.assertEqual(p[layer].sport, self.port_in) - else: - if not dont_translate: - self.assertNotEqual(p[layer].id, self.port_in) - else: - self.assertEqual(p[layer].id, self.port_in) - self.assertEqual(data, p[Raw].load) - - # out2in - if not dont_translate: - dst_addr = self.nat_addr - else: - dst_addr = self.pg0.remote_ip4 - if proto != IP_PROTOS.icmp: - sport = 20 - dport = p[layer].sport - else: - sport = p[layer].id - dport = 0 - pkts = self.create_stream_frag(self.pg1, - dst_addr, - sport, - dport, - data, - proto, - echo_reply=True) - pkts.reverse() - self.pg1.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - frags = self.pg0.get_capture(len(pkts)) - p = self.reass_frags_and_verify(frags, - self.pg1.remote_ip4, - self.pg0.remote_ip4) - if proto != IP_PROTOS.icmp: - self.assertEqual(p[layer].sport, 20) - self.assertEqual(p[layer].dport, self.port_in) - else: - self.assertEqual(p[layer].id, self.port_in) - self.assertEqual(data, p[Raw].load) - - def frag_out_of_order_in_plus_out(self, proto=IP_PROTOS.tcp): - layer = self.proto2layer(proto) - - if proto == IP_PROTOS.tcp: - data = b"A" * 4 + b"B" * 16 + b"C" * 3 - else: - data = b"A" * 16 + b"B" * 16 + b"C" * 3 - self.port_in = random.randint(1025, 65535) - - for i in range(2): - # out2in - pkts = self.create_stream_frag(self.pg0, - self.server_out_addr, - self.port_in, - self.server_out_port, - data, - proto) - pkts.reverse() - self.pg0.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - frags = self.pg1.get_capture(len(pkts)) - p = self.reass_frags_and_verify(frags, - self.pg0.remote_ip4, - self.server_in_addr) - if proto != IP_PROTOS.icmp: - self.assertEqual(p[layer].dport, self.server_in_port) - self.assertEqual(p[layer].sport, self.port_in) - self.assertEqual(p[layer].dport, self.server_in_port) - else: - self.assertEqual(p[layer].id, self.port_in) - self.assertEqual(data, p[Raw].load) - - # in2out - if proto != IP_PROTOS.icmp: - pkts = self.create_stream_frag(self.pg1, - self.pg0.remote_ip4, - self.server_in_port, - p[layer].sport, - data, - proto) - else: - pkts = self.create_stream_frag(self.pg1, - self.pg0.remote_ip4, - p[layer].id, - 0, - data, - proto, - echo_reply=True) - pkts.reverse() - self.pg1.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - frags = self.pg0.get_capture(len(pkts)) - p = self.reass_frags_and_verify(frags, - self.server_out_addr, - self.pg0.remote_ip4) - if proto != IP_PROTOS.icmp: - self.assertEqual(p[layer].sport, self.server_out_port) - self.assertEqual(p[layer].dport, self.port_in) - else: - self.assertEqual(p[layer].id, self.port_in) - self.assertEqual(data, p[Raw].load) - - -class TestNAT44(MethodHolder): - """ NAT44 Test Cases """ - - @classmethod - def setUpClass(cls): - super(TestNAT44, cls).setUpClass() - cls.vapi.cli("set log class nat level debug") - - try: - cls.tcp_port_in = 6303 - cls.tcp_port_out = 6303 - cls.udp_port_in = 6304 - cls.udp_port_out = 6304 - cls.icmp_id_in = 6305 - cls.icmp_id_out = 6305 - cls.nat_addr = '10.0.0.3' - cls.ipfix_src_port = 4739 - cls.ipfix_domain_id = 1 - cls.tcp_external_port = 80 - cls.udp_external_port = 69 - - cls.create_pg_interfaces(range(10)) - cls.interfaces = list(cls.pg_interfaces[0:4]) - - for i in cls.interfaces: - i.admin_up() - i.config_ip4() - i.resolve_arp() - - cls.pg0.generate_remote_hosts(3) - cls.pg0.configure_ipv4_neighbors() - - cls.pg1.generate_remote_hosts(1) - cls.pg1.configure_ipv4_neighbors() - - cls.overlapping_interfaces = list(list(cls.pg_interfaces[4:7])) - cls.vapi.ip_table_add_del(is_add=1, table_id=10) - cls.vapi.ip_table_add_del(is_add=1, table_id=20) - - cls.pg4._local_ip4 = VppIpPrefix("172.16.255.1", - cls.pg4.local_ip4_prefix.len) - cls.pg4._remote_hosts[0]._ip4 = "172.16.255.2" - cls.pg4.set_table_ip4(10) - cls.pg5._local_ip4 = VppIpPrefix("172.17.255.3", - cls.pg5.local_ip4_prefix.len) - cls.pg5._remote_hosts[0]._ip4 = "172.17.255.4" - cls.pg5.set_table_ip4(10) - cls.pg6._local_ip4 = VppIpPrefix("172.16.255.1", - cls.pg6.local_ip4_prefix.len) - cls.pg6._remote_hosts[0]._ip4 = "172.16.255.2" - cls.pg6.set_table_ip4(20) - for i in cls.overlapping_interfaces: - i.config_ip4() - i.admin_up() - i.resolve_arp() - - cls.pg7.admin_up() - cls.pg8.admin_up() - - cls.pg9.generate_remote_hosts(2) - cls.pg9.config_ip4() - cls.vapi.sw_interface_add_del_address( - sw_if_index=cls.pg9.sw_if_index, - prefix=VppIpPrefix("10.0.0.1", 24).encode()) - - cls.pg9.admin_up() - cls.pg9.resolve_arp() - cls.pg9._remote_hosts[1]._ip4 = cls.pg9._remote_hosts[0]._ip4 - cls.pg4._remote_ip4 = cls.pg9._remote_hosts[0]._ip4 = "10.0.0.2" - cls.pg9.resolve_arp() - - except Exception: - super(TestNAT44, cls).tearDownClass() - raise - - @classmethod - def tearDownClass(cls): - super(TestNAT44, cls).tearDownClass() - - def test_dynamic(self): - """ NAT44 dynamic translation test """ - self.nat44_add_address(self.nat_addr) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg1.sw_if_index, - is_add=1) - - # in2out - tcpn = self.statistics.get_err_counter( - '/err/nat44-in2out-slowpath/TCP packets') - udpn = self.statistics.get_err_counter( - '/err/nat44-in2out-slowpath/UDP packets') - icmpn = self.statistics.get_err_counter( - '/err/nat44-in2out-slowpath/ICMP packets') - totaln = self.statistics.get_err_counter( - '/err/nat44-in2out-slowpath/good in2out packets processed') - - 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) - - err = self.statistics.get_err_counter( - '/err/nat44-in2out-slowpath/TCP packets') - self.assertEqual(err - tcpn, 1) - err = self.statistics.get_err_counter( - '/err/nat44-in2out-slowpath/UDP packets') - self.assertEqual(err - udpn, 1) - err = self.statistics.get_err_counter( - '/err/nat44-in2out-slowpath/ICMP packets') - self.assertEqual(err - icmpn, 1) - err = self.statistics.get_err_counter( - '/err/nat44-in2out-slowpath/good in2out packets processed') - self.assertEqual(err - totaln, 3) - - # out2in - tcpn = self.statistics.get_err_counter('/err/nat44-out2in/TCP packets') - udpn = self.statistics.get_err_counter('/err/nat44-out2in/UDP packets') - icmpn = self.statistics.get_err_counter( - '/err/nat44-out2in/ICMP packets') - totaln = self.statistics.get_err_counter( - '/err/nat44-out2in/good out2in packets processed') - - pkts = self.create_stream_out(self.pg1) - self.pg1.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg0.get_capture(len(pkts)) - self.verify_capture_in(capture, self.pg0) - - err = self.statistics.get_err_counter('/err/nat44-out2in/TCP packets') - self.assertEqual(err - tcpn, 1) - err = self.statistics.get_err_counter('/err/nat44-out2in/UDP packets') - self.assertEqual(err - udpn, 1) - err = self.statistics.get_err_counter('/err/nat44-out2in/ICMP packets') - self.assertEqual(err - icmpn, 1) - err = self.statistics.get_err_counter( - '/err/nat44-out2in/good out2in packets processed') - self.assertEqual(err - totaln, 3) - - users = self.statistics.get_counter('/nat44/total-users') - self.assertEqual(users[0][0], 1) - sessions = self.statistics.get_counter('/nat44/total-sessions') - self.assertEqual(sessions[0][0], 3) - - def test_dynamic_icmp_errors_in2out_ttl_1(self): - """ NAT44 handling of client packets with TTL=1 """ - - self.nat44_add_address(self.nat_addr) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg1.sw_if_index, - is_add=1) - - # Client side - generate traffic - pkts = self.create_stream_in(self.pg0, self.pg1, ttl=1) - self.pg0.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - - # Client side - verify ICMP type 11 packets - capture = self.pg0.get_capture(len(pkts)) - self.verify_capture_in_with_icmp_errors(capture, self.pg0) - - def test_dynamic_icmp_errors_out2in_ttl_1(self): - """ NAT44 handling of server packets with TTL=1 """ - - self.nat44_add_address(self.nat_addr) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg1.sw_if_index, - is_add=1) - - # Client side - create sessions - pkts = self.create_stream_in(self.pg0, self.pg1) - self.pg0.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - - # Server side - generate traffic - capture = self.pg1.get_capture(len(pkts)) - self.verify_capture_out(capture) - pkts = self.create_stream_out(self.pg1, ttl=1) - self.pg1.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - - # Server side - verify ICMP type 11 packets - capture = self.pg1.get_capture(len(pkts)) - self.verify_capture_out_with_icmp_errors(capture, - src_ip=self.pg1.local_ip4) - - def test_dynamic_icmp_errors_in2out_ttl_2(self): - """ NAT44 handling of error responses to client packets with TTL=2 """ - - self.nat44_add_address(self.nat_addr) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg1.sw_if_index, - is_add=1) - - # Client side - generate traffic - pkts = self.create_stream_in(self.pg0, self.pg1, ttl=2) - self.pg0.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - - # Server side - simulate ICMP type 11 response - capture = self.pg1.get_capture(len(pkts)) - pkts = [Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / - IP(src=self.pg1.remote_ip4, dst=self.nat_addr) / - ICMP(type=11) / packet[IP] for packet in capture] - self.pg1.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - - # Client side - verify ICMP type 11 packets - capture = self.pg0.get_capture(len(pkts)) - self.verify_capture_in_with_icmp_errors(capture, self.pg0) - - def test_dynamic_icmp_errors_out2in_ttl_2(self): - """ NAT44 handling of error responses to server packets with TTL=2 """ - - self.nat44_add_address(self.nat_addr) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg1.sw_if_index, - is_add=1) - - # Client side - create sessions - pkts = self.create_stream_in(self.pg0, self.pg1) - self.pg0.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - - # Server side - generate traffic - capture = self.pg1.get_capture(len(pkts)) - self.verify_capture_out(capture) - pkts = self.create_stream_out(self.pg1, ttl=2) - self.pg1.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - - # Client side - simulate ICMP type 11 response - capture = self.pg0.get_capture(len(pkts)) - pkts = [Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) / - ICMP(type=11) / packet[IP] for packet in capture] - self.pg0.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - - # Server side - verify ICMP type 11 packets - capture = self.pg1.get_capture(len(pkts)) - self.verify_capture_out_with_icmp_errors(capture) - - def test_ping_out_interface_from_outside(self): - """ Ping NAT44 out interface from outside network """ - - self.nat44_add_address(self.nat_addr) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg1.sw_if_index, - is_add=1) - - p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / - IP(src=self.pg1.remote_ip4, dst=self.pg1.local_ip4) / - ICMP(id=self.icmp_id_out, type='echo-request')) - pkts = [p] - self.pg1.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg1.get_capture(len(pkts)) - packet = capture[0] - try: - self.assertEqual(packet[IP].src, self.pg1.local_ip4) - self.assertEqual(packet[IP].dst, self.pg1.remote_ip4) - self.assertEqual(packet[ICMP].id, self.icmp_id_in) - self.assertEqual(packet[ICMP].type, 0) # echo reply - except: - self.logger.error(ppp("Unexpected or invalid packet " - "(outside network):", packet)) - raise - - def test_ping_internal_host_from_outside(self): - """ Ping internal host from outside network """ - - self.nat44_add_static_mapping(self.pg0.remote_ip4, self.nat_addr) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg1.sw_if_index, - is_add=1) - - # out2in - pkt = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / - IP(src=self.pg1.remote_ip4, dst=self.nat_addr, ttl=64) / - ICMP(id=self.icmp_id_out, type='echo-request')) - self.pg1.add_stream(pkt) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg0.get_capture(1) - self.verify_capture_in(capture, self.pg0) - self.assert_equal(capture[0][IP].proto, IP_PROTOS.icmp) - - # in2out - pkt = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4, ttl=64) / - ICMP(id=self.icmp_id_in, type='echo-reply')) - self.pg0.add_stream(pkt) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg1.get_capture(1) - self.verify_capture_out(capture, same_port=True) - self.assert_equal(capture[0][IP].proto, IP_PROTOS.icmp) - - def test_forwarding(self): - """ NAT44 forwarding test """ - - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg1.sw_if_index, - is_add=1) - self.vapi.nat44_forwarding_enable_disable(enable=1) - - real_ip = self.pg0.remote_ip4n - alias_ip = self.nat_addr - flags = self.config_flags.NAT_IS_ADDR_ONLY - self.vapi.nat44_add_del_static_mapping(is_add=1, - local_ip_address=real_ip, - external_ip_address=alias_ip, - external_sw_if_index=0xFFFFFFFF, - flags=flags) - - try: - # static mapping match - - pkts = self.create_stream_out(self.pg1) - self.pg1.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg0.get_capture(len(pkts)) - self.verify_capture_in(capture, self.pg0) - - 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, same_port=True) - - # no static mapping match - - host0 = self.pg0.remote_hosts[0] - self.pg0.remote_hosts[0] = self.pg0.remote_hosts[1] - try: - pkts = self.create_stream_out(self.pg1, - dst_ip=self.pg0.remote_ip4, - use_inside_ports=True) - self.pg1.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg0.get_capture(len(pkts)) - self.verify_capture_in(capture, self.pg0) - - 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, nat_ip=self.pg0.remote_ip4, - same_port=True) - finally: - self.pg0.remote_hosts[0] = host0 - - finally: - self.vapi.nat44_forwarding_enable_disable(enable=0) - flags = self.config_flags.NAT_IS_ADDR_ONLY - self.vapi.nat44_add_del_static_mapping( - is_add=0, - local_ip_address=real_ip, - external_ip_address=alias_ip, - external_sw_if_index=0xFFFFFFFF, - flags=flags) - - def test_static_in(self): - """ 1:1 NAT initialized from inside network """ - - nat_ip = "10.0.0.10" - self.tcp_port_out = 6303 - self.udp_port_out = 6304 - self.icmp_id_out = 6305 - - self.nat44_add_static_mapping(self.pg0.remote_ip4, nat_ip) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg1.sw_if_index, - is_add=1) - sm = self.vapi.nat44_static_mapping_dump() - self.assertEqual(len(sm), 1) - self.assertEqual((sm[0].tag).split(b'\0', 1)[0], b'') - self.assertEqual(sm[0].protocol, 0) - self.assertEqual(sm[0].local_port, 0) - self.assertEqual(sm[0].external_port, 0) - - # in2out - 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, nat_ip, True) - - # out2in - pkts = self.create_stream_out(self.pg1, nat_ip) - self.pg1.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg0.get_capture(len(pkts)) - self.verify_capture_in(capture, self.pg0) - - def test_static_out(self): - """ 1:1 NAT initialized from outside network """ - - nat_ip = "10.0.0.20" - self.tcp_port_out = 6303 - self.udp_port_out = 6304 - self.icmp_id_out = 6305 - tag = b"testTAG" - - self.nat44_add_static_mapping(self.pg0.remote_ip4, nat_ip, tag=tag) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg1.sw_if_index, - is_add=1) - sm = self.vapi.nat44_static_mapping_dump() - self.assertEqual(len(sm), 1) - self.assertEqual((sm[0].tag).split(b'\0', 1)[0], tag) - - # out2in - pkts = self.create_stream_out(self.pg1, nat_ip) - self.pg1.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg0.get_capture(len(pkts)) - self.verify_capture_in(capture, self.pg0) - - # in2out - 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, nat_ip, True) - - def test_static_with_port_in(self): - """ 1:1 NAPT initialized from inside network """ - - self.tcp_port_out = 3606 - self.udp_port_out = 3607 - self.icmp_id_out = 3608 - - self.nat44_add_address(self.nat_addr) - self.nat44_add_static_mapping(self.pg0.remote_ip4, self.nat_addr, - self.tcp_port_in, self.tcp_port_out, - proto=IP_PROTOS.tcp) - self.nat44_add_static_mapping(self.pg0.remote_ip4, self.nat_addr, - self.udp_port_in, self.udp_port_out, - proto=IP_PROTOS.udp) - self.nat44_add_static_mapping(self.pg0.remote_ip4, self.nat_addr, - self.icmp_id_in, self.icmp_id_out, - proto=IP_PROTOS.icmp) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg1.sw_if_index, - is_add=1) - - # in2out - 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) - - # out2in - pkts = self.create_stream_out(self.pg1) - self.pg1.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg0.get_capture(len(pkts)) - self.verify_capture_in(capture, self.pg0) - - def test_static_with_port_out(self): - """ 1:1 NAPT initialized from outside network """ - - self.tcp_port_out = 30606 - self.udp_port_out = 30607 - self.icmp_id_out = 30608 - - self.nat44_add_address(self.nat_addr) - self.nat44_add_static_mapping(self.pg0.remote_ip4, self.nat_addr, - self.tcp_port_in, self.tcp_port_out, - proto=IP_PROTOS.tcp) - self.nat44_add_static_mapping(self.pg0.remote_ip4, self.nat_addr, - self.udp_port_in, self.udp_port_out, - proto=IP_PROTOS.udp) - self.nat44_add_static_mapping(self.pg0.remote_ip4, self.nat_addr, - self.icmp_id_in, self.icmp_id_out, - proto=IP_PROTOS.icmp) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg1.sw_if_index, - is_add=1) - - # out2in - pkts = self.create_stream_out(self.pg1) - self.pg1.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg0.get_capture(len(pkts)) - self.verify_capture_in(capture, self.pg0) - - # in2out - 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) - - def test_static_vrf_aware(self): - """ 1:1 NAT VRF awareness """ - - nat_ip1 = "10.0.0.30" - nat_ip2 = "10.0.0.40" - self.tcp_port_out = 6303 - self.udp_port_out = 6304 - self.icmp_id_out = 6305 - - self.nat44_add_static_mapping(self.pg4.remote_ip4, nat_ip1, - vrf_id=10) - self.nat44_add_static_mapping(self.pg0.remote_ip4, nat_ip2, - vrf_id=10) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg3.sw_if_index, - is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg4.sw_if_index, - flags=flags, is_add=1) - - # inside interface VRF match NAT44 static mapping VRF - 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(len(pkts)) - self.verify_capture_out(capture, nat_ip1, True) - - # inside interface VRF don't match NAT44 static mapping VRF (packets - # are dropped) - pkts = self.create_stream_in(self.pg0, self.pg3) - self.pg0.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - self.pg3.assert_nothing_captured() - - def test_dynamic_to_static(self): - """ Switch from dynamic translation to 1:1NAT """ - nat_ip = "10.0.0.10" - self.tcp_port_out = 6303 - self.udp_port_out = 6304 - self.icmp_id_out = 6305 - - self.nat44_add_address(self.nat_addr) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg1.sw_if_index, - is_add=1) - - # dynamic - 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) - - # 1:1NAT - self.nat44_add_static_mapping(self.pg0.remote_ip4, nat_ip) - sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4n, 0) - self.assertEqual(len(sessions), 0) - 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, nat_ip, True) - - def test_identity_nat(self): - """ Identity NAT """ - flags = self.config_flags.NAT_IS_ADDR_ONLY - self.vapi.nat44_add_del_identity_mapping( - ip_address=self.pg0.remote_ip4n, sw_if_index=0xFFFFFFFF, - flags=flags, is_add=1) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg1.sw_if_index, - is_add=1) - - p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / - IP(src=self.pg1.remote_ip4, dst=self.pg0.remote_ip4) / - TCP(sport=12345, dport=56789)) - self.pg1.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg0.get_capture(1) - p = capture[0] - try: - ip = p[IP] - tcp = p[TCP] - self.assertEqual(ip.dst, self.pg0.remote_ip4) - self.assertEqual(ip.src, self.pg1.remote_ip4) - self.assertEqual(tcp.dport, 56789) - self.assertEqual(tcp.sport, 12345) - self.assert_packet_checksums_valid(p) - except: - self.logger.error(ppp("Unexpected or invalid packet:", p)) - raise - - sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4n, 0) - self.assertEqual(len(sessions), 0) - flags = self.config_flags.NAT_IS_ADDR_ONLY - self.vapi.nat44_add_del_identity_mapping( - ip_address=self.pg0.remote_ip4n, sw_if_index=0xFFFFFFFF, - flags=flags, vrf_id=1, is_add=1) - identity_mappings = self.vapi.nat44_identity_mapping_dump() - self.assertEqual(len(identity_mappings), 2) - - def test_multiple_inside_interfaces(self): - """ NAT44 multiple non-overlapping address space inside interfaces """ - - self.nat44_add_address(self.nat_addr) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg1.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg3.sw_if_index, - is_add=1) - - # between two NAT44 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 NAT44 inside to interface without NAT44 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(len(pkts)) - self.verify_capture_out(capture) - - # out2in 1st 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.pg0.get_capture(len(pkts)) - self.verify_capture_in(capture, self.pg0) - - # in2out 2nd interface - pkts = self.create_stream_in(self.pg1, self.pg3) - self.pg1.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg3.get_capture(len(pkts)) - self.verify_capture_out(capture) - - # out2in 2nd 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.pg1.get_capture(len(pkts)) - self.verify_capture_in(capture, self.pg1) - - def test_inside_overlapping_interfaces(self): - """ NAT44 multiple inside interfaces with overlapping address space """ - - static_nat_ip = "10.0.0.10" - self.nat44_add_address(self.nat_addr) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg3.sw_if_index, - is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg4.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg5.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg6.sw_if_index, - flags=flags, is_add=1) - self.nat44_add_static_mapping(self.pg6.remote_ip4, static_nat_ip, - vrf_id=20) - - # between NAT44 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 NAT44 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.nat_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(len(pkts)) - self.verify_capture_out(capture) - - # out2in 1st 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.pg4.get_capture(len(pkts)) - self.verify_capture_in(capture, self.pg4) - - # in2out 2nd interface - pkts = self.create_stream_in(self.pg5, self.pg3) - self.pg5.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg3.get_capture(len(pkts)) - self.verify_capture_out(capture) - - # out2in 2nd 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.pg5.get_capture(len(pkts)) - self.verify_capture_in(capture, self.pg5) - - # pg5 session dump - addresses = self.vapi.nat44_address_dump() - self.assertEqual(len(addresses), 1) - sessions = self.vapi.nat44_user_session_dump(self.pg5.remote_ip4n, 10) - self.assertEqual(len(sessions), 3) - for session in sessions: - self.assertFalse(session.flags & self.config_flags.NAT_IS_STATIC) - self.assertEqual(str(session.inside_ip_address), - self.pg5.remote_ip4) - self.assertEqual(session.outside_ip_address, - addresses[0].ip_address) - self.assertEqual(sessions[0].protocol, IP_PROTOS.tcp) - self.assertEqual(sessions[1].protocol, IP_PROTOS.udp) - self.assertEqual(sessions[2].protocol, IP_PROTOS.icmp) - self.assertEqual(sessions[0].inside_port, self.tcp_port_in) - self.assertEqual(sessions[1].inside_port, self.udp_port_in) - self.assertEqual(sessions[2].inside_port, self.icmp_id_in) - self.assertEqual(sessions[0].outside_port, self.tcp_port_out) - self.assertEqual(sessions[1].outside_port, self.udp_port_out) - self.assertEqual(sessions[2].outside_port, self.icmp_id_out) - - # in2out 3rd interface - pkts = self.create_stream_in(self.pg6, self.pg3) - self.pg6.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - 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, static_nat_ip) - self.pg3.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg6.get_capture(len(pkts)) - self.verify_capture_in(capture, self.pg6) - - # general user and session dump verifications - users = self.vapi.nat44_user_dump() - self.assertGreaterEqual(len(users), 3) - addresses = self.vapi.nat44_address_dump() - self.assertEqual(len(addresses), 1) - for user in users: - sessions = self.vapi.nat44_user_session_dump(user.ip_address, - user.vrf_id) - for session in sessions: - self.assertEqual(user.ip_address, session.inside_ip_address) - self.assertTrue(session.total_bytes > session.total_pkts > 0) - self.assertTrue(session.protocol in - [IP_PROTOS.tcp, IP_PROTOS.udp, - IP_PROTOS.icmp]) - self.assertFalse(session.flags & - self.config_flags.NAT_IS_EXT_HOST_VALID) - - # pg4 session dump - sessions = self.vapi.nat44_user_session_dump(self.pg4.remote_ip4n, 10) - self.assertGreaterEqual(len(sessions), 4) - for session in sessions: - self.assertFalse(session.flags & self.config_flags.NAT_IS_STATIC) - self.assertEqual(str(session.inside_ip_address), - self.pg4.remote_ip4) - self.assertEqual(session.outside_ip_address, - addresses[0].ip_address) - - # pg6 session dump - sessions = self.vapi.nat44_user_session_dump(self.pg6.remote_ip4n, 20) - self.assertGreaterEqual(len(sessions), 3) - for session in sessions: - self.assertTrue(session.flags & self.config_flags.NAT_IS_STATIC) - self.assertEqual(str(session.inside_ip_address), - self.pg6.remote_ip4) - self.assertEqual(str(session.outside_ip_address), - static_nat_ip) - self.assertTrue(session.inside_port in - [self.tcp_port_in, self.udp_port_in, - self.icmp_id_in]) - - def test_hairpinning(self): - """ NAT44 hairpinning - 1:1 NAPT """ - - host = self.pg0.remote_hosts[0] - server = self.pg0.remote_hosts[1] - host_in_port = 1234 - host_out_port = 0 - server_in_port = 5678 - server_out_port = 8765 - - self.nat44_add_address(self.nat_addr) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg1.sw_if_index, - is_add=1) - - # add static mapping for server - self.nat44_add_static_mapping(server.ip4, self.nat_addr, - server_in_port, server_out_port, - proto=IP_PROTOS.tcp) - - # send packet from host to server - p = (Ether(src=host.mac, dst=self.pg0.local_mac) / - IP(src=host.ip4, dst=self.nat_addr) / - TCP(sport=host_in_port, dport=server_out_port)) - self.pg0.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg0.get_capture(1) - p = capture[0] - try: - ip = p[IP] - tcp = p[TCP] - self.assertEqual(ip.src, self.nat_addr) - self.assertEqual(ip.dst, server.ip4) - self.assertNotEqual(tcp.sport, host_in_port) - self.assertEqual(tcp.dport, server_in_port) - self.assert_packet_checksums_valid(p) - host_out_port = tcp.sport - except: - self.logger.error(ppp("Unexpected or invalid packet:", p)) - raise - - # send reply from server to host - p = (Ether(src=server.mac, dst=self.pg0.local_mac) / - IP(src=server.ip4, dst=self.nat_addr) / - TCP(sport=server_in_port, dport=host_out_port)) - self.pg0.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg0.get_capture(1) - p = capture[0] - try: - ip = p[IP] - tcp = p[TCP] - self.assertEqual(ip.src, self.nat_addr) - self.assertEqual(ip.dst, host.ip4) - self.assertEqual(tcp.sport, server_out_port) - self.assertEqual(tcp.dport, host_in_port) - self.assert_packet_checksums_valid(p) - except: - self.logger.error(ppp("Unexpected or invalid packet:", p)) - raise - - def test_hairpinning2(self): - """ NAT44 hairpinning - 1:1 NAT""" - - server1_nat_ip = "10.0.0.10" - server2_nat_ip = "10.0.0.11" - host = self.pg0.remote_hosts[0] - server1 = self.pg0.remote_hosts[1] - server2 = self.pg0.remote_hosts[2] - server_tcp_port = 22 - server_udp_port = 20 - - self.nat44_add_address(self.nat_addr) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg1.sw_if_index, - is_add=1) - - # add static mapping for servers - self.nat44_add_static_mapping(server1.ip4, server1_nat_ip) - self.nat44_add_static_mapping(server2.ip4, server2_nat_ip) - - # host to server1 - pkts = [] - p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IP(src=host.ip4, dst=server1_nat_ip) / - TCP(sport=self.tcp_port_in, dport=server_tcp_port)) - pkts.append(p) - p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IP(src=host.ip4, dst=server1_nat_ip) / - UDP(sport=self.udp_port_in, dport=server_udp_port)) - pkts.append(p) - p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IP(src=host.ip4, dst=server1_nat_ip) / - ICMP(id=self.icmp_id_in, type='echo-request')) - pkts.append(p) - self.pg0.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg0.get_capture(len(pkts)) - for packet in capture: - try: - self.assertEqual(packet[IP].src, self.nat_addr) - self.assertEqual(packet[IP].dst, server1.ip4) - if packet.haslayer(TCP): - self.assertNotEqual(packet[TCP].sport, self.tcp_port_in) - self.assertEqual(packet[TCP].dport, server_tcp_port) - self.tcp_port_out = packet[TCP].sport - self.assert_packet_checksums_valid(packet) - elif packet.haslayer(UDP): - self.assertNotEqual(packet[UDP].sport, self.udp_port_in) - self.assertEqual(packet[UDP].dport, server_udp_port) - self.udp_port_out = packet[UDP].sport - else: - self.assertNotEqual(packet[ICMP].id, self.icmp_id_in) - self.icmp_id_out = packet[ICMP].id - except: - self.logger.error(ppp("Unexpected or invalid packet:", packet)) - raise - - # server1 to host - pkts = [] - p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IP(src=server1.ip4, dst=self.nat_addr) / - TCP(sport=server_tcp_port, dport=self.tcp_port_out)) - pkts.append(p) - p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IP(src=server1.ip4, dst=self.nat_addr) / - UDP(sport=server_udp_port, dport=self.udp_port_out)) - pkts.append(p) - p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IP(src=server1.ip4, dst=self.nat_addr) / - ICMP(id=self.icmp_id_out, type='echo-reply')) - pkts.append(p) - self.pg0.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg0.get_capture(len(pkts)) - for packet in capture: - try: - self.assertEqual(packet[IP].src, server1_nat_ip) - self.assertEqual(packet[IP].dst, host.ip4) - if packet.haslayer(TCP): - self.assertEqual(packet[TCP].dport, self.tcp_port_in) - self.assertEqual(packet[TCP].sport, server_tcp_port) - self.assert_packet_checksums_valid(packet) - elif packet.haslayer(UDP): - self.assertEqual(packet[UDP].dport, self.udp_port_in) - self.assertEqual(packet[UDP].sport, server_udp_port) - else: - self.assertEqual(packet[ICMP].id, self.icmp_id_in) - except: - self.logger.error(ppp("Unexpected or invalid packet:", packet)) - raise - - # server2 to server1 - pkts = [] - p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IP(src=server2.ip4, dst=server1_nat_ip) / - TCP(sport=self.tcp_port_in, dport=server_tcp_port)) - pkts.append(p) - p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IP(src=server2.ip4, dst=server1_nat_ip) / - UDP(sport=self.udp_port_in, dport=server_udp_port)) - pkts.append(p) - p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IP(src=server2.ip4, dst=server1_nat_ip) / - ICMP(id=self.icmp_id_in, type='echo-request')) - pkts.append(p) - self.pg0.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg0.get_capture(len(pkts)) - for packet in capture: - try: - self.assertEqual(packet[IP].src, server2_nat_ip) - self.assertEqual(packet[IP].dst, server1.ip4) - if packet.haslayer(TCP): - self.assertEqual(packet[TCP].sport, self.tcp_port_in) - self.assertEqual(packet[TCP].dport, server_tcp_port) - self.tcp_port_out = packet[TCP].sport - self.assert_packet_checksums_valid(packet) - elif packet.haslayer(UDP): - self.assertEqual(packet[UDP].sport, self.udp_port_in) - self.assertEqual(packet[UDP].dport, server_udp_port) - self.udp_port_out = packet[UDP].sport - else: - self.assertEqual(packet[ICMP].id, self.icmp_id_in) - self.icmp_id_out = packet[ICMP].id - except: - self.logger.error(ppp("Unexpected or invalid packet:", packet)) - raise - - # server1 to server2 - pkts = [] - p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IP(src=server1.ip4, dst=server2_nat_ip) / - TCP(sport=server_tcp_port, dport=self.tcp_port_out)) - pkts.append(p) - p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IP(src=server1.ip4, dst=server2_nat_ip) / - UDP(sport=server_udp_port, dport=self.udp_port_out)) - pkts.append(p) - p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IP(src=server1.ip4, dst=server2_nat_ip) / - ICMP(id=self.icmp_id_out, type='echo-reply')) - pkts.append(p) - self.pg0.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg0.get_capture(len(pkts)) - for packet in capture: - try: - self.assertEqual(packet[IP].src, server1_nat_ip) - self.assertEqual(packet[IP].dst, server2.ip4) - if packet.haslayer(TCP): - self.assertEqual(packet[TCP].dport, self.tcp_port_in) - self.assertEqual(packet[TCP].sport, server_tcp_port) - self.assert_packet_checksums_valid(packet) - elif packet.haslayer(UDP): - self.assertEqual(packet[UDP].dport, self.udp_port_in) - self.assertEqual(packet[UDP].sport, server_udp_port) - else: - self.assertEqual(packet[ICMP].id, self.icmp_id_in) - except: - self.logger.error(ppp("Unexpected or invalid packet:", packet)) - raise - - def test_max_translations_per_user(self): - """ MAX translations per user - recycle the least recently used """ - - self.nat44_add_address(self.nat_addr) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg1.sw_if_index, - is_add=1) - - # get maximum number of translations per user - nat44_config = self.vapi.nat_show_config() - - # send more than maximum number of translations per user packets - pkts_num = nat44_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) - - users = self.vapi.nat44_user_dump() - for user in users: - if user.ip_address == self.pg0.remote_ip4n: - self.assertEqual(user.nsessions, - nat44_config.max_translations_per_user) - self.assertEqual(user.nstaticsessions, 0) - - tcp_port = 22 - self.nat44_add_static_mapping(self.pg0.remote_ip4, self.nat_addr, - tcp_port, tcp_port, - proto=IP_PROTOS.tcp) - 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=tcp_port)) - self.pg0.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - self.pg1.get_capture(1) - users = self.vapi.nat44_user_dump() - for user in users: - if user.ip_address == self.pg0.remote_ip4n: - self.assertEqual(user.nsessions, - nat44_config.max_translations_per_user - 1) - self.assertEqual(user.nstaticsessions, 1) - - def test_interface_addr(self): - """ Acquire NAT44 addresses from interface """ - self.vapi.nat44_add_del_interface_addr( - is_add=1, - sw_if_index=self.pg7.sw_if_index) - - # no address in NAT pool - addresses = self.vapi.nat44_address_dump() - self.assertEqual(0, len(addresses)) - - # configure interface address and check NAT address pool - self.pg7.config_ip4() - addresses = self.vapi.nat44_address_dump() - self.assertEqual(1, len(addresses)) - self.assertEqual(str(addresses[0].ip_address), self.pg7.local_ip4) - - # remove interface address and check NAT address pool - self.pg7.unconfig_ip4() - addresses = self.vapi.nat44_address_dump() - self.assertEqual(0, len(addresses)) - - def test_interface_addr_static_mapping(self): - """ Static mapping with addresses from interface """ - tag = b"testTAG" - - self.vapi.nat44_add_del_interface_addr( - is_add=1, - sw_if_index=self.pg7.sw_if_index) - self.nat44_add_static_mapping( - '1.2.3.4', - external_sw_if_index=self.pg7.sw_if_index, - tag=tag) - - # static mappings with external interface - static_mappings = self.vapi.nat44_static_mapping_dump() - self.assertEqual(1, len(static_mappings)) - self.assertEqual(self.pg7.sw_if_index, - static_mappings[0].external_sw_if_index) - self.assertEqual((static_mappings[0].tag).split(b'\0', 1)[0], tag) - - # configure interface address and check static mappings - self.pg7.config_ip4() - static_mappings = self.vapi.nat44_static_mapping_dump() - self.assertEqual(2, len(static_mappings)) - resolved = False - for sm in static_mappings: - if sm.external_sw_if_index == 0xFFFFFFFF: - self.assertEqual(str(sm.external_ip_address), - self.pg7.local_ip4) - self.assertEqual((sm.tag).split(b'\0', 1)[0], tag) - resolved = True - self.assertTrue(resolved) - - # remove interface address and check static mappings - self.pg7.unconfig_ip4() - static_mappings = self.vapi.nat44_static_mapping_dump() - self.assertEqual(1, len(static_mappings)) - self.assertEqual(self.pg7.sw_if_index, - static_mappings[0].external_sw_if_index) - self.assertEqual((static_mappings[0].tag).split(b'\0', 1)[0], tag) - - # configure interface address again and check static mappings - self.pg7.config_ip4() - static_mappings = self.vapi.nat44_static_mapping_dump() - self.assertEqual(2, len(static_mappings)) - resolved = False - for sm in static_mappings: - if sm.external_sw_if_index == 0xFFFFFFFF: - self.assertEqual(str(sm.external_ip_address), - self.pg7.local_ip4) - self.assertEqual((sm.tag).split(b'\0', 1)[0], tag) - resolved = True - self.assertTrue(resolved) - - # remove static mapping - self.nat44_add_static_mapping( - '1.2.3.4', - external_sw_if_index=self.pg7.sw_if_index, - tag=tag, - is_add=0) - static_mappings = self.vapi.nat44_static_mapping_dump() - self.assertEqual(0, len(static_mappings)) - - def test_interface_addr_identity_nat(self): - """ Identity NAT with addresses from interface """ - - port = 53053 - self.vapi.nat44_add_del_interface_addr( - is_add=1, - sw_if_index=self.pg7.sw_if_index) - self.vapi.nat44_add_del_identity_mapping( - ip_address=b'0', - sw_if_index=self.pg7.sw_if_index, - port=port, - protocol=IP_PROTOS.tcp, - is_add=1) - - # identity mappings with external interface - identity_mappings = self.vapi.nat44_identity_mapping_dump() - self.assertEqual(1, len(identity_mappings)) - self.assertEqual(self.pg7.sw_if_index, - identity_mappings[0].sw_if_index) - - # configure interface address and check identity mappings - self.pg7.config_ip4() - identity_mappings = self.vapi.nat44_identity_mapping_dump() - resolved = False - self.assertEqual(2, len(identity_mappings)) - for sm in identity_mappings: - if sm.sw_if_index == 0xFFFFFFFF: - self.assertEqual(str(identity_mappings[0].ip_address), - self.pg7.local_ip4) - self.assertEqual(port, identity_mappings[0].port) - self.assertEqual(IP_PROTOS.tcp, identity_mappings[0].protocol) - resolved = True - self.assertTrue(resolved) - - # remove interface address and check identity mappings - self.pg7.unconfig_ip4() - identity_mappings = self.vapi.nat44_identity_mapping_dump() - self.assertEqual(1, len(identity_mappings)) - self.assertEqual(self.pg7.sw_if_index, - identity_mappings[0].sw_if_index) - - def test_ipfix_nat44_sess(self): - """ IPFIX logging NAT44 session created/deleted """ - self.ipfix_domain_id = 10 - self.ipfix_src_port = 20202 - collector_port = 30303 - bind_layers(UDP, IPFIX, dport=30303) - self.nat44_add_address(self.nat_addr) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg1.sw_if_index, - is_add=1) - self.vapi.set_ipfix_exporter(collector_address=self.pg3.remote_ip4n, - src_address=self.pg3.local_ip4n, - path_mtu=512, - template_interval=10, - collector_port=collector_port) - self.vapi.nat_ipfix_enable_disable(domain_id=self.ipfix_domain_id, - src_port=self.ipfix_src_port, - enable=1) - - 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.nat44_add_address(self.nat_addr, is_add=0) - self.vapi.ipfix_flush() - capture = self.pg3.get_capture(9) - ipfix = IPFIXDecoder() - # first load template - for p in capture: - self.assertTrue(p.haslayer(IPFIX)) - self.assertEqual(p[IP].src, self.pg3.local_ip4) - self.assertEqual(p[IP].dst, self.pg3.remote_ip4) - self.assertEqual(p[UDP].sport, self.ipfix_src_port) - self.assertEqual(p[UDP].dport, collector_port) - self.assertEqual(p[IPFIX].observationDomainID, - self.ipfix_domain_id) - 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): - """ IPFIX logging NAT addresses exhausted """ - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg1.sw_if_index, - is_add=1) - 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.nat_ipfix_enable_disable(domain_id=self.ipfix_domain_id, - src_port=self.ipfix_src_port, - enable=1) - - 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() - self.pg1.assert_nothing_captured() - sleep(1) - self.vapi.ipfix_flush() - capture = self.pg3.get_capture(9) - ipfix = IPFIXDecoder() - # first load template - for p in capture: - self.assertTrue(p.haslayer(IPFIX)) - self.assertEqual(p[IP].src, self.pg3.local_ip4) - self.assertEqual(p[IP].dst, self.pg3.remote_ip4) - self.assertEqual(p[UDP].sport, self.ipfix_src_port) - self.assertEqual(p[UDP].dport, 4739) - self.assertEqual(p[IPFIX].observationDomainID, - self.ipfix_domain_id) - 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) - - @unittest.skipUnless(running_extended_tests, "part of extended tests") - def test_ipfix_max_sessions(self): - """ IPFIX logging maximum session entries exceeded """ - self.nat44_add_address(self.nat_addr) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg1.sw_if_index, - is_add=1) - - nat44_config = self.vapi.nat_show_config() - max_sessions = 10 * nat44_config.translation_buckets - - pkts = [] - for i in range(0, max_sessions): - src = "10.10.%u.%u" % ((i & 0xFF00) >> 8, i & 0xFF) - p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IP(src=src, dst=self.pg1.remote_ip4) / - TCP(sport=1025)) - pkts.append(p) - self.pg0.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - - self.pg1.get_capture(max_sessions) - 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.nat_ipfix_enable_disable(domain_id=self.ipfix_domain_id, - src_port=self.ipfix_src_port, - enable=1) - - 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)) - self.pg0.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - self.pg1.assert_nothing_captured() - sleep(1) - self.vapi.ipfix_flush() - capture = self.pg3.get_capture(9) - ipfix = IPFIXDecoder() - # first load template - for p in capture: - self.assertTrue(p.haslayer(IPFIX)) - self.assertEqual(p[IP].src, self.pg3.local_ip4) - self.assertEqual(p[IP].dst, self.pg3.remote_ip4) - self.assertEqual(p[UDP].sport, self.ipfix_src_port) - self.assertEqual(p[UDP].dport, 4739) - self.assertEqual(p[IPFIX].observationDomainID, - self.ipfix_domain_id) - 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_max_sessions(data, max_sessions) - - def test_syslog_apmap(self): - """ Test syslog address and port mapping creation and deletion """ - self.vapi.syslog_set_filter( - self.SYSLOG_SEVERITY.SYSLOG_API_SEVERITY_INFO) - self.vapi.syslog_set_sender(self.pg3.local_ip4n, self.pg3.remote_ip4n) - self.nat44_add_address(self.nat_addr) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg1.sw_if_index, - is_add=1) - - 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=self.tcp_port_in, dport=20)) - self.pg0.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg1.get_capture(1) - self.tcp_port_out = capture[0][TCP].sport - capture = self.pg3.get_capture(1) - self.verify_syslog_apmap(capture[0][Raw].load) - - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - self.nat44_add_address(self.nat_addr, is_add=0) - capture = self.pg3.get_capture(1) - self.verify_syslog_apmap(capture[0][Raw].load, False) - - def test_pool_addr_fib(self): - """ NAT44 add pool addresses to FIB """ - static_addr = '10.0.0.10' - self.nat44_add_address(self.nat_addr) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg1.sw_if_index, - is_add=1) - self.nat44_add_static_mapping(self.pg0.remote_ip4, static_addr) - - # NAT44 address - p = (Ether(src=self.pg1.remote_mac, dst='ff:ff:ff:ff:ff:ff') / - ARP(op=ARP.who_has, pdst=self.nat_addr, - psrc=self.pg1.remote_ip4, hwsrc=self.pg1.remote_mac)) - self.pg1.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg1.get_capture(1) - self.assertTrue(capture[0].haslayer(ARP)) - self.assertTrue(capture[0][ARP].op, ARP.is_at) - - # 1:1 NAT address - p = (Ether(src=self.pg1.remote_mac, dst='ff:ff:ff:ff:ff:ff') / - ARP(op=ARP.who_has, pdst=static_addr, - psrc=self.pg1.remote_ip4, hwsrc=self.pg1.remote_mac)) - self.pg1.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg1.get_capture(1) - self.assertTrue(capture[0].haslayer(ARP)) - self.assertTrue(capture[0][ARP].op, ARP.is_at) - - # send ARP to non-NAT44 interface - p = (Ether(src=self.pg2.remote_mac, dst='ff:ff:ff:ff:ff:ff') / - ARP(op=ARP.who_has, pdst=self.nat_addr, - psrc=self.pg2.remote_ip4, hwsrc=self.pg2.remote_mac)) - self.pg2.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - self.pg1.assert_nothing_captured() - - # remove addresses and verify - self.nat44_add_address(self.nat_addr, is_add=0) - self.nat44_add_static_mapping(self.pg0.remote_ip4, static_addr, - is_add=0) - - p = (Ether(src=self.pg1.remote_mac, dst='ff:ff:ff:ff:ff:ff') / - ARP(op=ARP.who_has, pdst=self.nat_addr, - psrc=self.pg1.remote_ip4, hwsrc=self.pg1.remote_mac)) - self.pg1.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - self.pg1.assert_nothing_captured() - - p = (Ether(src=self.pg1.remote_mac, dst='ff:ff:ff:ff:ff:ff') / - ARP(op=ARP.who_has, pdst=static_addr, - psrc=self.pg1.remote_ip4, hwsrc=self.pg1.remote_mac)) - self.pg1.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - self.pg1.assert_nothing_captured() - - def test_vrf_mode(self): - """ NAT44 tenant VRF aware address pool mode """ - - vrf_id1 = 1 - vrf_id2 = 2 - nat_ip1 = "10.0.0.10" - nat_ip2 = "10.0.0.11" - - self.pg0.unconfig_ip4() - self.pg1.unconfig_ip4() - self.vapi.ip_table_add_del(is_add=1, table_id=vrf_id1) - self.vapi.ip_table_add_del(is_add=1, table_id=vrf_id2) - self.pg0.set_table_ip4(vrf_id1) - self.pg1.set_table_ip4(vrf_id2) - self.pg0.config_ip4() - self.pg1.config_ip4() - self.pg0.resolve_arp() - self.pg1.resolve_arp() - - self.nat44_add_address(nat_ip1, vrf_id=vrf_id1) - self.nat44_add_address(nat_ip2, vrf_id=vrf_id2) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg1.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg2.sw_if_index, - is_add=1) - - try: - # first VRF - 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_out(capture, nat_ip1) - - # second VRF - pkts = self.create_stream_in(self.pg1, self.pg2) - self.pg1.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg2.get_capture(len(pkts)) - self.verify_capture_out(capture, nat_ip2) - - finally: - self.pg0.unconfig_ip4() - self.pg1.unconfig_ip4() - self.pg0.set_table_ip4(0) - self.pg1.set_table_ip4(0) - self.pg0.config_ip4() - self.pg1.config_ip4() - self.pg0.resolve_arp() - self.pg1.resolve_arp() - self.vapi.ip_table_add_del(is_add=0, table_id=vrf_id1) - self.vapi.ip_table_add_del(is_add=0, table_id=vrf_id2) - - def test_vrf_feature_independent(self): - """ NAT44 tenant VRF independent address pool mode """ - - nat_ip1 = "10.0.0.10" - nat_ip2 = "10.0.0.11" - - self.nat44_add_address(nat_ip1) - self.nat44_add_address(nat_ip2, vrf_id=99) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg1.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg2.sw_if_index, - is_add=1) - - # first VRF - 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_out(capture, nat_ip1) - - # second VRF - pkts = self.create_stream_in(self.pg1, self.pg2) - self.pg1.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg2.get_capture(len(pkts)) - self.verify_capture_out(capture, nat_ip1) - - def create_routes_and_neigbors(self): - r1 = VppIpRoute(self, self.pg7.remote_ip4, 32, - [VppRoutePath(self.pg7.remote_ip4, - self.pg7.sw_if_index)]) - r2 = VppIpRoute(self, self.pg8.remote_ip4, 32, - [VppRoutePath(self.pg8.remote_ip4, - self.pg8.sw_if_index)]) - r1.add_vpp_config() - r2.add_vpp_config() - - n1 = VppNeighbor(self, - self.pg7.sw_if_index, - self.pg7.remote_mac, - self.pg7.remote_ip4, - is_static=1) - n2 = VppNeighbor(self, - self.pg8.sw_if_index, - self.pg8.remote_mac, - self.pg8.remote_ip4, - is_static=1) - n1.add_vpp_config() - n2.add_vpp_config() - - def test_dynamic_ipless_interfaces(self): - """ NAT44 interfaces without configured IP address """ - self.create_routes_and_neigbors() - self.nat44_add_address(self.nat_addr) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg7.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg8.sw_if_index, - is_add=1) - - # in2out - pkts = self.create_stream_in(self.pg7, self.pg8) - self.pg7.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg8.get_capture(len(pkts)) - self.verify_capture_out(capture) - - # out2in - pkts = self.create_stream_out(self.pg8, self.nat_addr) - self.pg8.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg7.get_capture(len(pkts)) - self.verify_capture_in(capture, self.pg7) - - def test_static_ipless_interfaces(self): - """ NAT44 interfaces without configured IP address - 1:1 NAT """ - - self.create_routes_and_neigbors() - self.nat44_add_static_mapping(self.pg7.remote_ip4, self.nat_addr) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg7.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg8.sw_if_index, - is_add=1) - - # out2in - pkts = self.create_stream_out(self.pg8) - self.pg8.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg7.get_capture(len(pkts)) - self.verify_capture_in(capture, self.pg7) - - # in2out - pkts = self.create_stream_in(self.pg7, self.pg8) - self.pg7.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg8.get_capture(len(pkts)) - self.verify_capture_out(capture, self.nat_addr, True) - - def test_static_with_port_ipless_interfaces(self): - """ NAT44 interfaces without configured IP address - 1:1 NAPT """ - - self.tcp_port_out = 30606 - self.udp_port_out = 30607 - self.icmp_id_out = 30608 - - self.create_routes_and_neigbors() - self.nat44_add_address(self.nat_addr) - self.nat44_add_static_mapping(self.pg7.remote_ip4, self.nat_addr, - self.tcp_port_in, self.tcp_port_out, - proto=IP_PROTOS.tcp) - self.nat44_add_static_mapping(self.pg7.remote_ip4, self.nat_addr, - self.udp_port_in, self.udp_port_out, - proto=IP_PROTOS.udp) - self.nat44_add_static_mapping(self.pg7.remote_ip4, self.nat_addr, - self.icmp_id_in, self.icmp_id_out, - proto=IP_PROTOS.icmp) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg7.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg8.sw_if_index, - is_add=1) - - # out2in - pkts = self.create_stream_out(self.pg8) - self.pg8.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg7.get_capture(len(pkts)) - self.verify_capture_in(capture, self.pg7) - - # in2out - pkts = self.create_stream_in(self.pg7, self.pg8) - self.pg7.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg8.get_capture(len(pkts)) - self.verify_capture_out(capture) - - def test_static_unknown_proto(self): - """ 1:1 NAT translate packet with unknown protocol """ - nat_ip = "10.0.0.10" - self.nat44_add_static_mapping(self.pg0.remote_ip4, nat_ip) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg1.sw_if_index, - is_add=1) - - # in2out - p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) / - GRE() / - IP(src=self.pg2.remote_ip4, dst=self.pg3.remote_ip4) / - TCP(sport=1234, dport=1234)) - self.pg0.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - p = self.pg1.get_capture(1) - packet = p[0] - try: - self.assertEqual(packet[IP].src, nat_ip) - self.assertEqual(packet[IP].dst, self.pg1.remote_ip4) - self.assertEqual(packet.haslayer(GRE), 1) - self.assert_packet_checksums_valid(packet) - except: - self.logger.error(ppp("Unexpected or invalid packet:", packet)) - raise - - # out2in - p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / - IP(src=self.pg1.remote_ip4, dst=nat_ip) / - GRE() / - IP(src=self.pg3.remote_ip4, dst=self.pg2.remote_ip4) / - TCP(sport=1234, dport=1234)) - self.pg1.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - p = self.pg0.get_capture(1) - packet = p[0] - try: - self.assertEqual(packet[IP].src, self.pg1.remote_ip4) - self.assertEqual(packet[IP].dst, self.pg0.remote_ip4) - self.assertEqual(packet.haslayer(GRE), 1) - self.assert_packet_checksums_valid(packet) - except: - self.logger.error(ppp("Unexpected or invalid packet:", packet)) - raise - - def test_hairpinning_static_unknown_proto(self): - """ 1:1 NAT translate packet with unknown protocol - hairpinning """ - - host = self.pg0.remote_hosts[0] - server = self.pg0.remote_hosts[1] - - host_nat_ip = "10.0.0.10" - server_nat_ip = "10.0.0.11" - - self.nat44_add_static_mapping(host.ip4, host_nat_ip) - self.nat44_add_static_mapping(server.ip4, server_nat_ip) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg1.sw_if_index, - is_add=1) - - # host to server - p = (Ether(dst=self.pg0.local_mac, src=host.mac) / - IP(src=host.ip4, dst=server_nat_ip) / - GRE() / - IP(src=self.pg2.remote_ip4, dst=self.pg3.remote_ip4) / - TCP(sport=1234, dport=1234)) - self.pg0.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - p = self.pg0.get_capture(1) - packet = p[0] - try: - self.assertEqual(packet[IP].src, host_nat_ip) - self.assertEqual(packet[IP].dst, server.ip4) - self.assertEqual(packet.haslayer(GRE), 1) - self.assert_packet_checksums_valid(packet) - except: - self.logger.error(ppp("Unexpected or invalid packet:", packet)) - raise - - # server to host - p = (Ether(dst=self.pg0.local_mac, src=server.mac) / - IP(src=server.ip4, dst=host_nat_ip) / - GRE() / - IP(src=self.pg3.remote_ip4, dst=self.pg2.remote_ip4) / - TCP(sport=1234, dport=1234)) - self.pg0.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - p = self.pg0.get_capture(1) - packet = p[0] - try: - self.assertEqual(packet[IP].src, server_nat_ip) - self.assertEqual(packet[IP].dst, host.ip4) - self.assertEqual(packet.haslayer(GRE), 1) - self.assert_packet_checksums_valid(packet) - except: - self.logger.error(ppp("Unexpected or invalid packet:", packet)) - raise - - def test_output_feature(self): - """ NAT44 interface output feature (in2out postrouting) """ - self.nat44_add_address(self.nat_addr) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_output_feature( - is_add=1, flags=flags, - sw_if_index=self.pg0.sw_if_index) - self.vapi.nat44_interface_add_del_output_feature( - is_add=1, flags=flags, - sw_if_index=self.pg1.sw_if_index) - self.vapi.nat44_interface_add_del_output_feature( - is_add=1, - sw_if_index=self.pg3.sw_if_index) - - # in2out - 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(len(pkts)) - self.verify_capture_out(capture) - - # out2in - pkts = self.create_stream_out(self.pg3) - self.pg3.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg0.get_capture(len(pkts)) - self.verify_capture_in(capture, self.pg0) - - # from non-NAT interface to NAT inside interface - pkts = self.create_stream_in(self.pg2, self.pg0) - self.pg2.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg0.get_capture(len(pkts)) - self.verify_capture_no_translation(capture, self.pg2, self.pg0) - - def test_output_feature_vrf_aware(self): - """ NAT44 interface output feature VRF aware (in2out postrouting) """ - nat_ip_vrf10 = "10.0.0.10" - nat_ip_vrf20 = "10.0.0.20" - - r1 = VppIpRoute(self, self.pg3.remote_ip4, 32, - [VppRoutePath(self.pg3.remote_ip4, - self.pg3.sw_if_index)], - table_id=10) - r2 = VppIpRoute(self, self.pg3.remote_ip4, 32, - [VppRoutePath(self.pg3.remote_ip4, - self.pg3.sw_if_index)], - table_id=20) - r1.add_vpp_config() - r2.add_vpp_config() - - self.nat44_add_address(nat_ip_vrf10, vrf_id=10) - self.nat44_add_address(nat_ip_vrf20, vrf_id=20) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_output_feature( - is_add=1, flags=flags, - sw_if_index=self.pg4.sw_if_index) - self.vapi.nat44_interface_add_del_output_feature( - is_add=1, flags=flags, - sw_if_index=self.pg6.sw_if_index) - self.vapi.nat44_interface_add_del_output_feature( - is_add=1, - sw_if_index=self.pg3.sw_if_index) - - # in2out VRF 10 - 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(len(pkts)) - self.verify_capture_out(capture, nat_ip=nat_ip_vrf10) - - # out2in VRF 10 - pkts = self.create_stream_out(self.pg3, dst_ip=nat_ip_vrf10) - self.pg3.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg4.get_capture(len(pkts)) - self.verify_capture_in(capture, self.pg4) - - # in2out VRF 20 - pkts = self.create_stream_in(self.pg6, self.pg3) - self.pg6.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg3.get_capture(len(pkts)) - self.verify_capture_out(capture, nat_ip=nat_ip_vrf20) - - # out2in VRF 20 - pkts = self.create_stream_out(self.pg3, dst_ip=nat_ip_vrf20) - self.pg3.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg6.get_capture(len(pkts)) - self.verify_capture_in(capture, self.pg6) - - def test_output_feature_hairpinning(self): - """ NAT44 interface output feature hairpinning (in2out postrouting) """ - host = self.pg0.remote_hosts[0] - server = self.pg0.remote_hosts[1] - host_in_port = 1234 - host_out_port = 0 - server_in_port = 5678 - server_out_port = 8765 - - self.nat44_add_address(self.nat_addr) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_output_feature( - is_add=1, flags=flags, - sw_if_index=self.pg0.sw_if_index) - self.vapi.nat44_interface_add_del_output_feature( - is_add=1, - sw_if_index=self.pg1.sw_if_index) - - # add static mapping for server - self.nat44_add_static_mapping(server.ip4, self.nat_addr, - server_in_port, server_out_port, - proto=IP_PROTOS.tcp) - - # send packet from host to server - p = (Ether(src=host.mac, dst=self.pg0.local_mac) / - IP(src=host.ip4, dst=self.nat_addr) / - TCP(sport=host_in_port, dport=server_out_port)) - self.pg0.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg0.get_capture(1) - p = capture[0] - try: - ip = p[IP] - tcp = p[TCP] - self.assertEqual(ip.src, self.nat_addr) - self.assertEqual(ip.dst, server.ip4) - self.assertNotEqual(tcp.sport, host_in_port) - self.assertEqual(tcp.dport, server_in_port) - self.assert_packet_checksums_valid(p) - host_out_port = tcp.sport - except: - self.logger.error(ppp("Unexpected or invalid packet:", p)) - raise - - # send reply from server to host - p = (Ether(src=server.mac, dst=self.pg0.local_mac) / - IP(src=server.ip4, dst=self.nat_addr) / - TCP(sport=server_in_port, dport=host_out_port)) - self.pg0.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg0.get_capture(1) - p = capture[0] - try: - ip = p[IP] - tcp = p[TCP] - self.assertEqual(ip.src, self.nat_addr) - self.assertEqual(ip.dst, host.ip4) - self.assertEqual(tcp.sport, server_out_port) - self.assertEqual(tcp.dport, host_in_port) - self.assert_packet_checksums_valid(p) - except: - self.logger.error(ppp("Unexpected or invalid packet:", p)) - raise - - def test_one_armed_nat44(self): - """ One armed NAT44 """ - remote_host = self.pg9.remote_hosts[0] - local_host = self.pg9.remote_hosts[1] - external_port = 0 - - self.nat44_add_address(self.nat_addr) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg9.sw_if_index, - is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg9.sw_if_index, - flags=flags, is_add=1) - - # in2out - p = (Ether(src=self.pg9.remote_mac, dst=self.pg9.local_mac) / - IP(src=local_host.ip4, dst=remote_host.ip4) / - TCP(sport=12345, dport=80)) - self.pg9.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg9.get_capture(1) - p = capture[0] - try: - ip = p[IP] - tcp = p[TCP] - self.assertEqual(ip.src, self.nat_addr) - self.assertEqual(ip.dst, remote_host.ip4) - self.assertNotEqual(tcp.sport, 12345) - external_port = tcp.sport - self.assertEqual(tcp.dport, 80) - self.assert_packet_checksums_valid(p) - except: - self.logger.error(ppp("Unexpected or invalid packet:", p)) - raise - - # out2in - p = (Ether(src=self.pg9.remote_mac, dst=self.pg9.local_mac) / - IP(src=remote_host.ip4, dst=self.nat_addr) / - TCP(sport=80, dport=external_port)) - self.pg9.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg9.get_capture(1) - p = capture[0] - try: - ip = p[IP] - tcp = p[TCP] - self.assertEqual(ip.src, remote_host.ip4) - self.assertEqual(ip.dst, local_host.ip4) - self.assertEqual(tcp.sport, 80) - self.assertEqual(tcp.dport, 12345) - self.assert_packet_checksums_valid(p) - except: - self.logger.error(ppp("Unexpected or invalid packet:", p)) - raise - - err = self.statistics.get_err_counter( - '/err/nat44-classify/next in2out') - self.assertEqual(err, 1) - err = self.statistics.get_err_counter( - '/err/nat44-classify/next out2in') - self.assertEqual(err, 1) - - def test_del_session(self): - """ Delete NAT44 session """ - self.nat44_add_address(self.nat_addr) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg1.sw_if_index, - is_add=1) - - pkts = self.create_stream_in(self.pg0, self.pg1) - self.pg0.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - self.pg1.get_capture(len(pkts)) - - sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4n, 0) - nsessions = len(sessions) - - self.vapi.nat44_del_session(address=sessions[0].inside_ip_address, - port=sessions[0].inside_port, - protocol=sessions[0].protocol, - flags=self.config_flags.NAT_IS_INSIDE) - self.vapi.nat44_del_session(address=sessions[1].outside_ip_address, - port=sessions[1].outside_port, - protocol=sessions[1].protocol) - - sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4n, 0) - self.assertEqual(nsessions - len(sessions), 2) - - self.vapi.nat44_del_session(address=sessions[0].inside_ip_address, - port=sessions[0].inside_port, - protocol=sessions[0].protocol, - flags=self.config_flags.NAT_IS_INSIDE) - - self.verify_no_nat44_user() - - def test_set_get_reass(self): - """ NAT44 set/get virtual fragmentation reassembly """ - reas_cfg1 = self.vapi.nat_get_reass() - - self.vapi.nat_set_reass(timeout=reas_cfg1.ip4_timeout + 5, - max_reass=reas_cfg1.ip4_max_reass * 2, - max_frag=reas_cfg1.ip4_max_frag * 2, - drop_frag=0) - - reas_cfg2 = self.vapi.nat_get_reass() - - self.assertEqual(reas_cfg1.ip4_timeout + 5, reas_cfg2.ip4_timeout) - self.assertEqual(reas_cfg1.ip4_max_reass * 2, reas_cfg2.ip4_max_reass) - self.assertEqual(reas_cfg1.ip4_max_frag * 2, reas_cfg2.ip4_max_frag) - - self.vapi.nat_set_reass(timeout=2, max_reass=1024, max_frag=5, - drop_frag=1) - self.assertTrue(self.vapi.nat_get_reass().ip4_drop_frag) - - def test_frag_in_order(self): - """ NAT44 translate fragments arriving in order """ - - self.nat44_add_address(self.nat_addr) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg1.sw_if_index, - is_add=1) - - reas_cfg1 = self.vapi.nat_get_reass() - # this test was intermittently failing in some cases - # until we temporarily bump the reassembly timeouts - self.vapi.nat_set_reass(timeout=20, max_reass=1024, max_frag=5, - drop_frag=0) - - self.frag_in_order(proto=IP_PROTOS.tcp) - self.frag_in_order(proto=IP_PROTOS.udp) - self.frag_in_order(proto=IP_PROTOS.icmp) - - # restore the reassembly timeouts - self.vapi.nat_set_reass(timeout=reas_cfg1.ip4_timeout, - max_reass=reas_cfg1.ip4_max_reass, - max_frag=reas_cfg1.ip4_max_frag, - drop_frag=reas_cfg1.ip4_drop_frag) - - def test_frag_forwarding(self): - """ NAT44 forwarding fragment test """ - self.vapi.nat44_add_del_interface_addr( - is_add=1, - sw_if_index=self.pg1.sw_if_index) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg1.sw_if_index, - is_add=1) - self.vapi.nat44_forwarding_enable_disable(enable=1) - - data = b"A" * 16 + b"B" * 16 + b"C" * 3 - pkts = self.create_stream_frag(self.pg1, - self.pg0.remote_ip4, - 4789, - 4789, - data, - proto=IP_PROTOS.udp) - self.pg1.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - frags = self.pg0.get_capture(len(pkts)) - p = self.reass_frags_and_verify(frags, - self.pg1.remote_ip4, - self.pg0.remote_ip4) - self.assertEqual(p[UDP].sport, 4789) - self.assertEqual(p[UDP].dport, 4789) - self.assertEqual(data, p[Raw].load) - - def test_reass_hairpinning(self): - """ NAT44 fragments hairpinning """ - - self.server = self.pg0.remote_hosts[1] - self.host_in_port = random.randint(1025, 65535) - self.server_in_port = random.randint(1025, 65535) - self.server_out_port = random.randint(1025, 65535) - - self.nat44_add_address(self.nat_addr) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg1.sw_if_index, - is_add=1) - # add static mapping for server - self.nat44_add_static_mapping(self.server.ip4, self.nat_addr, - self.server_in_port, - self.server_out_port, - proto=IP_PROTOS.tcp) - self.nat44_add_static_mapping(self.server.ip4, self.nat_addr, - self.server_in_port, - self.server_out_port, - proto=IP_PROTOS.udp) - self.nat44_add_static_mapping(self.server.ip4, self.nat_addr) - - self.reass_hairpinning(proto=IP_PROTOS.tcp) - self.reass_hairpinning(proto=IP_PROTOS.udp) - self.reass_hairpinning(proto=IP_PROTOS.icmp) - - def test_frag_out_of_order(self): - """ NAT44 translate fragments arriving out of order """ - - self.nat44_add_address(self.nat_addr) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg1.sw_if_index, - is_add=1) - - self.frag_out_of_order(proto=IP_PROTOS.tcp) - self.frag_out_of_order(proto=IP_PROTOS.udp) - self.frag_out_of_order(proto=IP_PROTOS.icmp) - - def test_port_restricted(self): - """ Port restricted NAT44 (MAP-E CE) """ - self.nat44_add_address(self.nat_addr) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg1.sw_if_index, - is_add=1) - self.vapi.nat_set_addr_and_port_alloc_alg(alg=1, - psid_offset=6, - psid_length=6, - psid=10) - - 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=4567, dport=22)) - self.pg0.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg1.get_capture(1) - p = capture[0] - try: - ip = p[IP] - tcp = p[TCP] - self.assertEqual(ip.dst, self.pg1.remote_ip4) - self.assertEqual(ip.src, self.nat_addr) - self.assertEqual(tcp.dport, 22) - self.assertNotEqual(tcp.sport, 4567) - self.assertEqual((tcp.sport >> 6) & 63, 10) - self.assert_packet_checksums_valid(p) - except: - self.logger.error(ppp("Unexpected or invalid packet:", p)) - raise - - def test_port_range(self): - """ External address port range """ - self.nat44_add_address(self.nat_addr) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg1.sw_if_index, - is_add=1) - self.vapi.nat_set_addr_and_port_alloc_alg(alg=2, - start_port=1025, - end_port=1027) - - pkts = [] - for port in range(0, 5): - 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=1125 + port)) - pkts.append(p) - self.pg0.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg1.get_capture(3) - for p in capture: - tcp = p[TCP] - self.assertGreaterEqual(tcp.sport, 1025) - self.assertLessEqual(tcp.sport, 1027) - - def test_ipfix_max_frags(self): - """ IPFIX logging maximum fragments pending reassembly exceeded """ - self.nat44_add_address(self.nat_addr) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg1.sw_if_index, - is_add=1) - self.vapi.nat_set_reass(timeout=2, max_reass=1024, max_frag=1, - drop_frag=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.nat_ipfix_enable_disable(domain_id=self.ipfix_domain_id, - src_port=self.ipfix_src_port, - enable=1) - - data = b"A" * 4 + b"B" * 16 + b"C" * 3 - self.tcp_port_in = random.randint(1025, 65535) - pkts = self.create_stream_frag(self.pg0, - self.pg1.remote_ip4, - self.tcp_port_in, - 20, - data) - pkts.reverse() - self.pg0.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - self.pg1.assert_nothing_captured() - sleep(1) - self.vapi.ipfix_flush() - capture = self.pg3.get_capture(9) - ipfix = IPFIXDecoder() - # first load template - for p in capture: - self.assertTrue(p.haslayer(IPFIX)) - self.assertEqual(p[IP].src, self.pg3.local_ip4) - self.assertEqual(p[IP].dst, self.pg3.remote_ip4) - self.assertEqual(p[UDP].sport, self.ipfix_src_port) - self.assertEqual(p[UDP].dport, 4739) - self.assertEqual(p[IPFIX].observationDomainID, - self.ipfix_domain_id) - 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_max_fragments_ip4(data, 1, - self.pg0.remote_ip4n) - - def test_multiple_outside_vrf(self): - """ Multiple outside VRF """ - vrf_id1 = 1 - vrf_id2 = 2 - - self.pg1.unconfig_ip4() - self.pg2.unconfig_ip4() - self.vapi.ip_table_add_del(is_add=1, table_id=vrf_id1) - self.vapi.ip_table_add_del(is_add=1, table_id=vrf_id2) - self.pg1.set_table_ip4(vrf_id1) - self.pg2.set_table_ip4(vrf_id2) - self.pg1.config_ip4() - self.pg2.config_ip4() - self.pg1.resolve_arp() - self.pg2.resolve_arp() - - self.nat44_add_address(self.nat_addr) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg1.sw_if_index, - is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg2.sw_if_index, - is_add=1) - - try: - # first VRF - 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.nat_addr) - - pkts = self.create_stream_out(self.pg1, self.nat_addr) - self.pg1.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg0.get_capture(len(pkts)) - self.verify_capture_in(capture, self.pg0) - - self.tcp_port_in = 60303 - self.udp_port_in = 60304 - self.icmp_id_in = 60305 - - # second VRF - 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_out(capture, self.nat_addr) - - pkts = self.create_stream_out(self.pg2, self.nat_addr) - self.pg2.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg0.get_capture(len(pkts)) - self.verify_capture_in(capture, self.pg0) - - finally: - self.nat44_add_address(self.nat_addr, is_add=0) - self.pg1.unconfig_ip4() - self.pg2.unconfig_ip4() - self.pg1.set_table_ip4(0) - self.pg2.set_table_ip4(0) - self.pg1.config_ip4() - self.pg2.config_ip4() - self.pg1.resolve_arp() - self.pg2.resolve_arp() - - @unittest.skipUnless(running_extended_tests, "part of extended tests") - def test_session_timeout(self): - """ NAT44 session timeouts """ - self.nat44_add_address(self.nat_addr) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg1.sw_if_index, - is_add=1) - self.vapi.nat_set_timeouts(udp=5, tcp_established=7440, - tcp_transitory=240, icmp=60) - - max_sessions = 1000 - pkts = [] - for i in range(0, max_sessions): - src = "10.10.%u.%u" % ((i & 0xFF00) >> 8, i & 0xFF) - p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IP(src=src, dst=self.pg1.remote_ip4) / - UDP(sport=1025, dport=53)) - pkts.append(p) - self.pg0.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - self.pg1.get_capture(max_sessions) - - sleep(6) - - pkts = [] - for i in range(0, max_sessions): - src = "10.10.%u.%u" % ((i & 0xFF00) >> 8, i & 0xFF) - p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IP(src=src, dst=self.pg1.remote_ip4) / - UDP(sport=1026, dport=53)) - pkts.append(p) - self.pg0.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - self.pg1.get_capture(max_sessions) - - nsessions = 0 - users = self.vapi.nat44_user_dump() - for user in users: - nsessions = nsessions + user.nsessions - self.assertLess(nsessions, 2 * max_sessions) - - def test_mss_clamping(self): - """ TCP MSS clamping """ - self.nat44_add_address(self.nat_addr) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg1.sw_if_index, - is_add=1) - - 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=self.tcp_port_in, dport=self.tcp_external_port, - flags="S", options=[('MSS', 1400)])) - - self.vapi.nat_set_mss_clamping(enable=1, mss_value=1000) - self.pg0.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg1.get_capture(1) - # Negotiated MSS value greater than configured - changed - self.verify_mss_value(capture[0], 1000) - - self.vapi.nat_set_mss_clamping(enable=0, mss_value=1500) - self.pg0.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg1.get_capture(1) - # MSS clamping disabled - negotiated MSS unchanged - self.verify_mss_value(capture[0], 1400) - - self.vapi.nat_set_mss_clamping(enable=1, mss_value=1500) - self.pg0.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg1.get_capture(1) - # Negotiated MSS value smaller than configured - unchanged - self.verify_mss_value(capture[0], 1400) - - @unittest.skipUnless(running_extended_tests, "part of extended tests") - def test_ha_send(self): - """ Send HA session synchronization events (active) """ - self.nat44_add_address(self.nat_addr) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg1.sw_if_index, - is_add=1) - self.vapi.nat_ha_set_listener(ip_address=self.pg3.local_ip4, - port=12345, - path_mtu=512) - self.vapi.nat_ha_set_failover(ip_address=self.pg3.remote_ip4, - port=12346, session_refresh_interval=10) - bind_layers(UDP, HANATStateSync, sport=12345) - - # create sessions - 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) - # active send HA events - self.vapi.nat_ha_flush() - stats = self.statistics.get_counter('/nat44/ha/add-event-send') - self.assertEqual(stats[0][0], 3) - capture = self.pg3.get_capture(1) - p = capture[0] - self.assert_packet_checksums_valid(p) - try: - ip = p[IP] - udp = p[UDP] - hanat = p[HANATStateSync] - except IndexError: - self.logger.error(ppp("Invalid packet:", p)) - raise - else: - self.assertEqual(ip.src, self.pg3.local_ip4) - self.assertEqual(ip.dst, self.pg3.remote_ip4) - self.assertEqual(udp.sport, 12345) - self.assertEqual(udp.dport, 12346) - self.assertEqual(hanat.version, 1) - self.assertEqual(hanat.thread_index, 0) - self.assertEqual(hanat.count, 3) - seq = hanat.sequence_number - for event in hanat.events: - self.assertEqual(event.event_type, 1) - self.assertEqual(event.in_addr, self.pg0.remote_ip4) - self.assertEqual(event.out_addr, self.nat_addr) - self.assertEqual(event.fib_index, 0) - - # ACK received events - ack = (Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac) / - IP(src=self.pg3.remote_ip4, dst=self.pg3.local_ip4) / - UDP(sport=12346, dport=12345) / - HANATStateSync(sequence_number=seq, flags='ACK')) - self.pg3.add_stream(ack) - self.pg_start() - stats = self.statistics.get_counter('/nat44/ha/ack-recv') - self.assertEqual(stats[0][0], 1) - - # delete one session - self.pg_enable_capture(self.pg_interfaces) - self.vapi.nat44_del_session(address=self.pg0.remote_ip4n, - port=self.tcp_port_in, - protocol=IP_PROTOS.tcp, - flags=self.config_flags.NAT_IS_INSIDE) - self.vapi.nat_ha_flush() - stats = self.statistics.get_counter('/nat44/ha/del-event-send') - self.assertEqual(stats[0][0], 1) - capture = self.pg3.get_capture(1) - p = capture[0] - try: - hanat = p[HANATStateSync] - except IndexError: - self.logger.error(ppp("Invalid packet:", p)) - raise - else: - self.assertGreater(hanat.sequence_number, seq) - - # do not send ACK, active retry send HA event again - self.pg_enable_capture(self.pg_interfaces) - sleep(12) - stats = self.statistics.get_counter('/nat44/ha/retry-count') - self.assertEqual(stats[0][0], 3) - stats = self.statistics.get_counter('/nat44/ha/missed-count') - self.assertEqual(stats[0][0], 1) - capture = self.pg3.get_capture(3) - for packet in capture: - self.assertEqual(packet, p) - - # session counters refresh - pkts = self.create_stream_out(self.pg1) - self.pg1.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - self.pg0.get_capture(2) - self.vapi.nat_ha_flush() - stats = self.statistics.get_counter('/nat44/ha/refresh-event-send') - self.assertEqual(stats[0][0], 2) - capture = self.pg3.get_capture(1) - p = capture[0] - self.assert_packet_checksums_valid(p) - try: - ip = p[IP] - udp = p[UDP] - hanat = p[HANATStateSync] - except IndexError: - self.logger.error(ppp("Invalid packet:", p)) - raise - else: - self.assertEqual(ip.src, self.pg3.local_ip4) - self.assertEqual(ip.dst, self.pg3.remote_ip4) - self.assertEqual(udp.sport, 12345) - self.assertEqual(udp.dport, 12346) - self.assertEqual(hanat.version, 1) - self.assertEqual(hanat.count, 2) - seq = hanat.sequence_number - for event in hanat.events: - self.assertEqual(event.event_type, 3) - self.assertEqual(event.out_addr, self.nat_addr) - self.assertEqual(event.fib_index, 0) - self.assertEqual(event.total_pkts, 2) - self.assertGreater(event.total_bytes, 0) - - ack = (Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac) / - IP(src=self.pg3.remote_ip4, dst=self.pg3.local_ip4) / - UDP(sport=12346, dport=12345) / - HANATStateSync(sequence_number=seq, flags='ACK')) - self.pg3.add_stream(ack) - self.pg_start() - stats = self.statistics.get_counter('/nat44/ha/ack-recv') - self.assertEqual(stats[0][0], 2) - - def test_ha_recv(self): - """ Receive HA session synchronization events (passive) """ - self.nat44_add_address(self.nat_addr) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg1.sw_if_index, - is_add=1) - self.vapi.nat_ha_set_listener(ip_address=self.pg3.local_ip4, - port=12345, - path_mtu=512) - bind_layers(UDP, HANATStateSync, sport=12345) - - self.tcp_port_out = random.randint(1025, 65535) - self.udp_port_out = random.randint(1025, 65535) - - # send HA session add events to failover/passive - p = (Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac) / - IP(src=self.pg3.remote_ip4, dst=self.pg3.local_ip4) / - UDP(sport=12346, dport=12345) / - HANATStateSync(sequence_number=1, events=[ - Event(event_type='add', protocol='tcp', - in_addr=self.pg0.remote_ip4, out_addr=self.nat_addr, - in_port=self.tcp_port_in, out_port=self.tcp_port_out, - eh_addr=self.pg1.remote_ip4, - ehn_addr=self.pg1.remote_ip4, - eh_port=self.tcp_external_port, - ehn_port=self.tcp_external_port, fib_index=0), - Event(event_type='add', protocol='udp', - in_addr=self.pg0.remote_ip4, out_addr=self.nat_addr, - in_port=self.udp_port_in, out_port=self.udp_port_out, - eh_addr=self.pg1.remote_ip4, - ehn_addr=self.pg1.remote_ip4, - eh_port=self.udp_external_port, - ehn_port=self.udp_external_port, fib_index=0)])) - - self.pg3.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - # receive ACK - capture = self.pg3.get_capture(1) - p = capture[0] - try: - hanat = p[HANATStateSync] - except IndexError: - self.logger.error(ppp("Invalid packet:", p)) - raise - else: - self.assertEqual(hanat.sequence_number, 1) - self.assertEqual(hanat.flags, 'ACK') - self.assertEqual(hanat.version, 1) - self.assertEqual(hanat.thread_index, 0) - stats = self.statistics.get_counter('/nat44/ha/ack-send') - self.assertEqual(stats[0][0], 1) - stats = self.statistics.get_counter('/nat44/ha/add-event-recv') - self.assertEqual(stats[0][0], 2) - users = self.statistics.get_counter('/nat44/total-users') - self.assertEqual(users[0][0], 1) - sessions = self.statistics.get_counter('/nat44/total-sessions') - self.assertEqual(sessions[0][0], 2) - users = self.vapi.nat44_user_dump() - self.assertEqual(len(users), 1) - self.assertEqual(str(users[0].ip_address), - self.pg0.remote_ip4) - # there should be 2 sessions created by HA - sessions = self.vapi.nat44_user_session_dump(users[0].ip_address, - users[0].vrf_id) - self.assertEqual(len(sessions), 2) - for session in sessions: - self.assertEqual(str(session.inside_ip_address), - self.pg0.remote_ip4) - self.assertEqual(str(session.outside_ip_address), - self.nat_addr) - self.assertIn(session.inside_port, - [self.tcp_port_in, self.udp_port_in]) - self.assertIn(session.outside_port, - [self.tcp_port_out, self.udp_port_out]) - self.assertIn(session.protocol, [IP_PROTOS.tcp, IP_PROTOS.udp]) - - # send HA session delete event to failover/passive - p = (Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac) / - IP(src=self.pg3.remote_ip4, dst=self.pg3.local_ip4) / - UDP(sport=12346, dport=12345) / - HANATStateSync(sequence_number=2, events=[ - Event(event_type='del', protocol='udp', - in_addr=self.pg0.remote_ip4, out_addr=self.nat_addr, - in_port=self.udp_port_in, out_port=self.udp_port_out, - eh_addr=self.pg1.remote_ip4, - ehn_addr=self.pg1.remote_ip4, - eh_port=self.udp_external_port, - ehn_port=self.udp_external_port, fib_index=0)])) - - self.pg3.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - # receive ACK - capture = self.pg3.get_capture(1) - p = capture[0] - try: - hanat = p[HANATStateSync] - except IndexError: - self.logger.error(ppp("Invalid packet:", p)) - raise - else: - self.assertEqual(hanat.sequence_number, 2) - self.assertEqual(hanat.flags, 'ACK') - self.assertEqual(hanat.version, 1) - users = self.vapi.nat44_user_dump() - self.assertEqual(len(users), 1) - self.assertEqual(str(users[0].ip_address), - self.pg0.remote_ip4) - # now we should have only 1 session, 1 deleted by HA - sessions = self.vapi.nat44_user_session_dump(users[0].ip_address, - users[0].vrf_id) - self.assertEqual(len(sessions), 1) - stats = self.statistics.get_counter('/nat44/ha/del-event-recv') - self.assertEqual(stats[0][0], 1) - - stats = self.statistics.get_err_counter('/err/nat-ha/pkts-processed') - self.assertEqual(stats, 2) - - # send HA session refresh event to failover/passive - p = (Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac) / - IP(src=self.pg3.remote_ip4, dst=self.pg3.local_ip4) / - UDP(sport=12346, dport=12345) / - HANATStateSync(sequence_number=3, events=[ - Event(event_type='refresh', protocol='tcp', - in_addr=self.pg0.remote_ip4, out_addr=self.nat_addr, - in_port=self.tcp_port_in, out_port=self.tcp_port_out, - eh_addr=self.pg1.remote_ip4, - ehn_addr=self.pg1.remote_ip4, - eh_port=self.tcp_external_port, - ehn_port=self.tcp_external_port, fib_index=0, - total_bytes=1024, total_pkts=2)])) - self.pg3.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - # receive ACK - capture = self.pg3.get_capture(1) - p = capture[0] - try: - hanat = p[HANATStateSync] - except IndexError: - self.logger.error(ppp("Invalid packet:", p)) - raise - else: - self.assertEqual(hanat.sequence_number, 3) - self.assertEqual(hanat.flags, 'ACK') - self.assertEqual(hanat.version, 1) - users = self.vapi.nat44_user_dump() - self.assertEqual(len(users), 1) - self.assertEqual(str(users[0].ip_address), - self.pg0.remote_ip4) - sessions = self.vapi.nat44_user_session_dump(users[0].ip_address, - users[0].vrf_id) - self.assertEqual(len(sessions), 1) - session = sessions[0] - self.assertEqual(session.total_bytes, 1024) - self.assertEqual(session.total_pkts, 2) - stats = self.statistics.get_counter('/nat44/ha/refresh-event-recv') - self.assertEqual(stats[0][0], 1) - - stats = self.statistics.get_err_counter('/err/nat-ha/pkts-processed') - self.assertEqual(stats, 3) - - # send packet to test session created by HA - p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / - IP(src=self.pg1.remote_ip4, dst=self.nat_addr) / - TCP(sport=self.tcp_external_port, dport=self.tcp_port_out)) - self.pg1.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg0.get_capture(1) - p = capture[0] - try: - ip = p[IP] - tcp = p[TCP] - except IndexError: - self.logger.error(ppp("Invalid packet:", p)) - raise - else: - self.assertEqual(ip.src, self.pg1.remote_ip4) - self.assertEqual(ip.dst, self.pg0.remote_ip4) - self.assertEqual(tcp.sport, self.tcp_external_port) - self.assertEqual(tcp.dport, self.tcp_port_in) - - def tearDown(self): - super(TestNAT44, self).tearDown() - self.clear_nat44() - self.vapi.cli("clear logging") - - def show_commands_at_teardown(self): - self.logger.info(self.vapi.cli("show nat44 addresses")) - self.logger.info(self.vapi.cli("show nat44 interfaces")) - self.logger.info(self.vapi.cli("show nat44 static mappings")) - self.logger.info(self.vapi.cli("show nat44 interface address")) - self.logger.info(self.vapi.cli("show nat44 sessions detail")) - self.logger.info(self.vapi.cli("show nat virtual-reassembly")) - self.logger.info(self.vapi.cli("show nat44 hash tables detail")) - self.logger.info(self.vapi.cli("show nat timeouts")) - self.logger.info( - self.vapi.cli("show nat addr-port-assignment-alg")) - self.logger.info(self.vapi.cli("show nat ha")) - - -class TestNAT44EndpointDependent(MethodHolder): - """ Endpoint-Dependent mapping and filtering test cases """ - - @classmethod - def setUpConstants(cls): - super(TestNAT44EndpointDependent, cls).setUpConstants() - cls.vpp_cmdline.extend(["nat", "{", "endpoint-dependent", "}"]) - - @classmethod - def setUpClass(cls): - super(TestNAT44EndpointDependent, cls).setUpClass() - cls.vapi.cli("set log class nat level debug") - try: - cls.tcp_port_in = 6303 - cls.tcp_port_out = 6303 - cls.udp_port_in = 6304 - cls.udp_port_out = 6304 - cls.icmp_id_in = 6305 - cls.icmp_id_out = 6305 - cls.nat_addr = '10.0.0.3' - cls.ipfix_src_port = 4739 - cls.ipfix_domain_id = 1 - cls.tcp_external_port = 80 - - cls.create_pg_interfaces(range(7)) - cls.interfaces = list(cls.pg_interfaces[0:3]) - - for i in cls.interfaces: - i.admin_up() - i.config_ip4() - i.resolve_arp() - - cls.pg0.generate_remote_hosts(3) - cls.pg0.configure_ipv4_neighbors() - - cls.pg3.admin_up() - - cls.pg4.generate_remote_hosts(2) - cls.pg4.config_ip4() - cls.vapi.sw_interface_add_del_address( - sw_if_index=cls.pg4.sw_if_index, - prefix=VppIpPrefix("10.0.0.1", 24).encode()) - - cls.pg4.admin_up() - cls.pg4.resolve_arp() - cls.pg4._remote_hosts[1]._ip4 = cls.pg4._remote_hosts[0]._ip4 - cls.pg4.resolve_arp() - - zero_ip4n = socket.inet_pton(socket.AF_INET, "0.0.0.0") - cls.vapi.ip_table_add_del(is_add=1, table_id=1) - - cls.pg5._local_ip4 = VppIpPrefix("10.1.1.1", - cls.pg5.local_ip4_prefix.len) - cls.pg5._remote_hosts[0]._ip4 = "10.1.1.2" - cls.pg5._remote_hosts[0]._ip4n = socket.inet_pton( - socket.AF_INET, cls.pg5.remote_ip4) - cls.pg5.set_table_ip4(1) - cls.pg5.config_ip4() - cls.pg5.admin_up() - r1 = VppIpRoute(cls, cls.pg5.remote_ip4, 32, - [VppRoutePath("0.0.0.0", - cls.pg5.sw_if_index)], - table_id=1, - register=False) - r1.add_vpp_config() - - cls.pg6._local_ip4 = VppIpPrefix("10.1.2.1", - cls.pg6.local_ip4_prefix.len) - cls.pg6._remote_hosts[0]._ip4 = "10.1.2.2" - cls.pg6._remote_hosts[0]._ip4n = socket.inet_pton( - socket.AF_INET, cls.pg6.remote_ip4) - cls.pg6.set_table_ip4(1) - cls.pg6.config_ip4() - cls.pg6.admin_up() - - r2 = VppIpRoute(cls, cls.pg6.remote_ip4, 32, - [VppRoutePath("0.0.0.0", - cls.pg6.sw_if_index)], - table_id=1, - register=False) - r3 = VppIpRoute(cls, cls.pg6.remote_ip4, 16, - [VppRoutePath("0.0.0.0", - 0xffffffff, - nh_table_id=1)], - table_id=0, - register=False) - r4 = VppIpRoute(cls, "0.0.0.0", 0, - [VppRoutePath("0.0.0.0", 0xffffffff, - nh_table_id=0)], - table_id=1, - register=False) - r5 = VppIpRoute(cls, "0.0.0.0", 0, - [VppRoutePath(cls.pg1.local_ip4, - cls.pg1.sw_if_index)], - register=False) - r2.add_vpp_config() - r3.add_vpp_config() - r4.add_vpp_config() - r5.add_vpp_config() - - cls.pg5.resolve_arp() - cls.pg6.resolve_arp() - - except Exception: - super(TestNAT44EndpointDependent, cls).tearDownClass() - raise - - @classmethod - def tearDownClass(cls): - super(TestNAT44EndpointDependent, cls).tearDownClass() - - def test_frag_in_order(self): - """ NAT44 translate fragments arriving in order """ - self.nat44_add_address(self.nat_addr) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg1.sw_if_index, - is_add=1) - self.frag_in_order(proto=IP_PROTOS.tcp) - self.frag_in_order(proto=IP_PROTOS.udp) - self.frag_in_order(proto=IP_PROTOS.icmp) - - def test_frag_in_order_dont_translate(self): - """ NAT44 don't translate fragments arriving in order """ - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg1.sw_if_index, - is_add=1) - self.vapi.nat44_forwarding_enable_disable(enable=True) - reas_cfg1 = self.vapi.nat_get_reass() - # this test was intermittently failing in some cases - # until we temporarily bump the reassembly timeouts - self.vapi.nat_set_reass(timeout=20, max_reass=1024, max_frag=5, - drop_frag=0) - self.frag_in_order(proto=IP_PROTOS.tcp, dont_translate=True) - # restore the reassembly timeouts - self.vapi.nat_set_reass(timeout=reas_cfg1.ip4_timeout, - max_reass=reas_cfg1.ip4_max_reass, - max_frag=reas_cfg1.ip4_max_frag, - drop_frag=reas_cfg1.ip4_drop_frag) - - def test_frag_out_of_order(self): - """ NAT44 translate fragments arriving out of order """ - self.nat44_add_address(self.nat_addr) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg1.sw_if_index, - is_add=1) - self.frag_out_of_order(proto=IP_PROTOS.tcp) - self.frag_out_of_order(proto=IP_PROTOS.udp) - self.frag_out_of_order(proto=IP_PROTOS.icmp) - - def test_frag_out_of_order_dont_translate(self): - """ NAT44 don't translate fragments arriving out of order """ - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg1.sw_if_index, - is_add=1) - self.vapi.nat44_forwarding_enable_disable(enable=True) - self.frag_out_of_order(proto=IP_PROTOS.tcp, dont_translate=True) - - def test_frag_in_order_in_plus_out(self): - """ in+out interface fragments in order """ - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg1.sw_if_index, - is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg1.sw_if_index, - flags=flags, is_add=1) - - self.server = self.pg1.remote_hosts[0] - - self.server_in_addr = self.server.ip4 - self.server_out_addr = '11.11.11.11' - self.server_in_port = random.randint(1025, 65535) - self.server_out_port = random.randint(1025, 65535) - - self.nat44_add_address(self.server_out_addr) - - # add static mappings for server - self.nat44_add_static_mapping(self.server_in_addr, - self.server_out_addr, - self.server_in_port, - self.server_out_port, - proto=IP_PROTOS.tcp) - self.nat44_add_static_mapping(self.server_in_addr, - self.server_out_addr, - self.server_in_port, - self.server_out_port, - proto=IP_PROTOS.udp) - self.nat44_add_static_mapping(self.server_in_addr, - self.server_out_addr, - proto=IP_PROTOS.icmp) - - self.vapi.nat_set_reass(timeout=10, max_reass=1024, max_frag=5, - drop_frag=0) - - self.frag_in_order_in_plus_out(proto=IP_PROTOS.tcp) - self.frag_in_order_in_plus_out(proto=IP_PROTOS.udp) - self.frag_in_order_in_plus_out(proto=IP_PROTOS.icmp) - - def test_frag_out_of_order_in_plus_out(self): - """ in+out interface fragments out of order """ - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg1.sw_if_index, - is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg1.sw_if_index, - flags=flags, is_add=1) - - self.server = self.pg1.remote_hosts[0] - - self.server_in_addr = self.server.ip4 - self.server_out_addr = '11.11.11.11' - self.server_in_port = random.randint(1025, 65535) - self.server_out_port = random.randint(1025, 65535) - - self.nat44_add_address(self.server_out_addr) - - # add static mappings for server - self.nat44_add_static_mapping(self.server_in_addr, - self.server_out_addr, - self.server_in_port, - self.server_out_port, - proto=IP_PROTOS.tcp) - self.nat44_add_static_mapping(self.server_in_addr, - self.server_out_addr, - self.server_in_port, - self.server_out_port, - proto=IP_PROTOS.udp) - self.nat44_add_static_mapping(self.server_in_addr, - self.server_out_addr, - proto=IP_PROTOS.icmp) - - self.vapi.nat_set_reass(timeout=10, max_reass=1024, max_frag=5, - drop_frag=0) - - self.frag_out_of_order_in_plus_out(proto=IP_PROTOS.tcp) - self.frag_out_of_order_in_plus_out(proto=IP_PROTOS.udp) - self.frag_out_of_order_in_plus_out(proto=IP_PROTOS.icmp) - - def test_reass_hairpinning(self): - """ NAT44 fragments hairpinning """ - self.server = self.pg0.remote_hosts[1] - self.host_in_port = random.randint(1025, 65535) - self.server_in_port = random.randint(1025, 65535) - self.server_out_port = random.randint(1025, 65535) - - self.nat44_add_address(self.nat_addr) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg1.sw_if_index, - is_add=1) - # add static mapping for server - self.nat44_add_static_mapping(self.server.ip4, self.nat_addr, - self.server_in_port, - self.server_out_port, - proto=IP_PROTOS.tcp) - self.nat44_add_static_mapping(self.server.ip4, self.nat_addr, - self.server_in_port, - self.server_out_port, - proto=IP_PROTOS.udp) - self.nat44_add_static_mapping(self.server.ip4, self.nat_addr) - - self.reass_hairpinning(proto=IP_PROTOS.tcp) - self.reass_hairpinning(proto=IP_PROTOS.udp) - self.reass_hairpinning(proto=IP_PROTOS.icmp) - - def test_dynamic(self): - """ NAT44 dynamic translation test """ - - self.nat44_add_address(self.nat_addr) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg1.sw_if_index, - is_add=1) - - nat_config = self.vapi.nat_show_config() - self.assertEqual(1, nat_config.endpoint_dependent) - - # in2out - tcpn = self.statistics.get_err_counter( - '/err/nat44-ed-in2out-slowpath/TCP packets') - udpn = self.statistics.get_err_counter( - '/err/nat44-ed-in2out-slowpath/UDP packets') - icmpn = self.statistics.get_err_counter( - '/err/nat44-ed-in2out-slowpath/ICMP packets') - totaln = self.statistics.get_err_counter( - '/err/nat44-ed-in2out-slowpath/good in2out packets processed') - - 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) - - err = self.statistics.get_err_counter( - '/err/nat44-ed-in2out-slowpath/TCP packets') - self.assertEqual(err - tcpn, 1) - err = self.statistics.get_err_counter( - '/err/nat44-ed-in2out-slowpath/UDP packets') - self.assertEqual(err - udpn, 1) - err = self.statistics.get_err_counter( - '/err/nat44-ed-in2out-slowpath/ICMP packets') - self.assertEqual(err - icmpn, 1) - err = self.statistics.get_err_counter( - '/err/nat44-ed-in2out-slowpath/good in2out packets processed') - self.assertEqual(err - totaln, 3) - - # out2in - tcpn = self.statistics.get_err_counter( - '/err/nat44-ed-out2in/TCP packets') - udpn = self.statistics.get_err_counter( - '/err/nat44-ed-out2in/UDP packets') - icmpn = self.statistics.get_err_counter( - '/err/nat44-ed-out2in-slowpath/ICMP packets') - totaln = self.statistics.get_err_counter( - '/err/nat44-ed-out2in/good out2in packets processed') - - pkts = self.create_stream_out(self.pg1) - self.pg1.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg0.get_capture(len(pkts)) - self.verify_capture_in(capture, self.pg0) - - err = self.statistics.get_err_counter( - '/err/nat44-ed-out2in/TCP packets') - self.assertEqual(err - tcpn, 1) - err = self.statistics.get_err_counter( - '/err/nat44-ed-out2in/UDP packets') - self.assertEqual(err - udpn, 1) - err = self.statistics.get_err_counter( - '/err/nat44-ed-out2in-slowpath/ICMP packets') - self.assertEqual(err - icmpn, 1) - err = self.statistics.get_err_counter( - '/err/nat44-ed-out2in/good out2in packets processed') - self.assertEqual(err - totaln, 2) - - users = self.statistics.get_counter('/nat44/total-users') - self.assertEqual(users[0][0], 1) - sessions = self.statistics.get_counter('/nat44/total-sessions') - self.assertEqual(sessions[0][0], 3) - - def test_forwarding(self): - """ NAT44 forwarding test """ - - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg1.sw_if_index, - is_add=1) - self.vapi.nat44_forwarding_enable_disable(enable=1) - - real_ip = self.pg0.remote_ip4 - alias_ip = self.nat_addr - flags = self.config_flags.NAT_IS_ADDR_ONLY - self.vapi.nat44_add_del_static_mapping(is_add=1, - local_ip_address=real_ip, - external_ip_address=alias_ip, - external_sw_if_index=0xFFFFFFFF, - flags=flags) - - try: - # in2out - static mapping match - - pkts = self.create_stream_out(self.pg1) - self.pg1.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg0.get_capture(len(pkts)) - self.verify_capture_in(capture, self.pg0) - - 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, same_port=True) - - # in2out - no static mapping match - - host0 = self.pg0.remote_hosts[0] - self.pg0.remote_hosts[0] = self.pg0.remote_hosts[1] - try: - pkts = self.create_stream_out(self.pg1, - dst_ip=self.pg0.remote_ip4, - use_inside_ports=True) - self.pg1.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg0.get_capture(len(pkts)) - self.verify_capture_in(capture, self.pg0) - - 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, nat_ip=self.pg0.remote_ip4, - same_port=True) - finally: - self.pg0.remote_hosts[0] = host0 - - user = self.pg0.remote_hosts[1] - sessions = self.vapi.nat44_user_session_dump(user.ip4n, 0) - self.assertEqual(len(sessions), 3) - self.assertTrue(sessions[0].flags & - self.config_flags.NAT_IS_EXT_HOST_VALID) - self.vapi.nat44_del_session( - address=sessions[0].inside_ip_address, - port=sessions[0].inside_port, - protocol=sessions[0].protocol, - flags=(self.config_flags.NAT_IS_INSIDE | - self.config_flags.NAT_IS_EXT_HOST_VALID), - ext_host_address=sessions[0].ext_host_address, - ext_host_port=sessions[0].ext_host_port) - sessions = self.vapi.nat44_user_session_dump(user.ip4n, 0) - self.assertEqual(len(sessions), 2) - - finally: - self.vapi.nat44_forwarding_enable_disable(enable=0) - flags = self.config_flags.NAT_IS_ADDR_ONLY - self.vapi.nat44_add_del_static_mapping( - is_add=0, - local_ip_address=real_ip, - external_ip_address=alias_ip, - external_sw_if_index=0xFFFFFFFF, - flags=flags) - - def test_static_lb(self): - """ NAT44 local service load balancing """ - external_addr_n = self.nat_addr - external_port = 80 - local_port = 8080 - server1 = self.pg0.remote_hosts[0] - server2 = self.pg0.remote_hosts[1] - - locals = [{'addr': server1.ip4n, - 'port': local_port, - 'probability': 70, - 'vrf_id': 0}, - {'addr': server2.ip4n, - 'port': local_port, - 'probability': 30, - 'vrf_id': 0}] - - self.nat44_add_address(self.nat_addr) - self.vapi.nat44_add_del_lb_static_mapping( - is_add=1, - external_addr=external_addr_n, - external_port=external_port, - protocol=IP_PROTOS.tcp, - local_num=len(locals), - locals=locals) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg1.sw_if_index, - is_add=1) - - # from client to service - p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / - IP(src=self.pg1.remote_ip4, dst=self.nat_addr) / - TCP(sport=12345, dport=external_port)) - self.pg1.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg0.get_capture(1) - p = capture[0] - server = None - try: - ip = p[IP] - tcp = p[TCP] - self.assertIn(ip.dst, [server1.ip4, server2.ip4]) - if ip.dst == server1.ip4: - server = server1 - else: - server = server2 - self.assertEqual(tcp.dport, local_port) - self.assert_packet_checksums_valid(p) - except: - self.logger.error(ppp("Unexpected or invalid packet:", p)) - raise - - # from service back to client - p = (Ether(src=server.mac, dst=self.pg0.local_mac) / - IP(src=server.ip4, dst=self.pg1.remote_ip4) / - TCP(sport=local_port, dport=12345)) - self.pg0.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg1.get_capture(1) - p = capture[0] - try: - ip = p[IP] - tcp = p[TCP] - self.assertEqual(ip.src, self.nat_addr) - self.assertEqual(tcp.sport, external_port) - self.assert_packet_checksums_valid(p) - except: - self.logger.error(ppp("Unexpected or invalid packet:", p)) - raise - - sessions = self.vapi.nat44_user_session_dump(server.ip4n, 0) - self.assertEqual(len(sessions), 1) - self.assertTrue(sessions[0].flags & - self.config_flags.NAT_IS_EXT_HOST_VALID) - self.vapi.nat44_del_session( - address=sessions[0].inside_ip_address, - port=sessions[0].inside_port, - protocol=sessions[0].protocol, - flags=(self.config_flags.NAT_IS_INSIDE | - self.config_flags.NAT_IS_EXT_HOST_VALID), - ext_host_address=sessions[0].ext_host_address, - ext_host_port=sessions[0].ext_host_port) - sessions = self.vapi.nat44_user_session_dump(server.ip4n, 0) - self.assertEqual(len(sessions), 0) - - @unittest.skipUnless(running_extended_tests, "part of extended tests") - def test_static_lb_multi_clients(self): - """ NAT44 local service load balancing - multiple clients""" - - external_addr = self.nat_addr - external_port = 80 - local_port = 8080 - server1 = self.pg0.remote_hosts[0] - server2 = self.pg0.remote_hosts[1] - server3 = self.pg0.remote_hosts[2] - - locals = [{'addr': server1.ip4n, - 'port': local_port, - 'probability': 90, - 'vrf_id': 0}, - {'addr': server2.ip4n, - 'port': local_port, - 'probability': 10, - 'vrf_id': 0}] - - self.nat44_add_address(self.nat_addr) - self.vapi.nat44_add_del_lb_static_mapping(is_add=1, - external_addr=external_addr, - external_port=external_port, - protocol=IP_PROTOS.tcp, - local_num=len(locals), - locals=locals) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg1.sw_if_index, - is_add=1) - - server1_n = 0 - server2_n = 0 - clients = ip4_range(self.pg1.remote_ip4, 10, 50) - pkts = [] - for client in clients: - p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / - IP(src=client, dst=self.nat_addr) / - TCP(sport=12345, dport=external_port)) - pkts.append(p) - self.pg1.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg0.get_capture(len(pkts)) - for p in capture: - if p[IP].dst == server1.ip4: - server1_n += 1 - else: - server2_n += 1 - self.assertGreater(server1_n, server2_n) - - local = { - 'addr': server3.ip4n, - 'port': local_port, - 'probability': 20, - 'vrf_id': 0 - } - - # add new back-end - self.vapi.nat44_lb_static_mapping_add_del_local( - is_add=1, - external_addr=external_addr, - external_port=external_port, - local=local, - protocol=IP_PROTOS.tcp) - server1_n = 0 - server2_n = 0 - server3_n = 0 - clients = ip4_range(self.pg1.remote_ip4, 60, 110) - pkts = [] - for client in clients: - p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / - IP(src=client, dst=self.nat_addr) / - TCP(sport=12346, dport=external_port)) - pkts.append(p) - self.assertGreater(len(pkts), 0) - self.pg1.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg0.get_capture(len(pkts)) - for p in capture: - if p[IP].dst == server1.ip4: - server1_n += 1 - elif p[IP].dst == server2.ip4: - server2_n += 1 - else: - server3_n += 1 - self.assertGreater(server1_n, 0) - self.assertGreater(server2_n, 0) - self.assertGreater(server3_n, 0) - - local = { - 'addr': server2.ip4n, - 'port': local_port, - 'probability': 10, - 'vrf_id': 0 - } - - # remove one back-end - self.vapi.nat44_lb_static_mapping_add_del_local( - is_add=0, - external_addr=external_addr, - external_port=external_port, - local=local, - protocol=IP_PROTOS.tcp) - server1_n = 0 - server2_n = 0 - server3_n = 0 - self.pg1.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg0.get_capture(len(pkts)) - for p in capture: - if p[IP].dst == server1.ip4: - server1_n += 1 - elif p[IP].dst == server2.ip4: - server2_n += 1 - else: - server3_n += 1 - self.assertGreater(server1_n, 0) - self.assertEqual(server2_n, 0) - self.assertGreater(server3_n, 0) - - def test_static_lb_2(self): - """ NAT44 local service load balancing (asymmetrical rule) """ - external_addr = self.nat_addr - external_port = 80 - local_port = 8080 - server1 = self.pg0.remote_hosts[0] - server2 = self.pg0.remote_hosts[1] - - locals = [{'addr': server1.ip4n, - 'port': local_port, - 'probability': 70, - 'vrf_id': 0}, - {'addr': server2.ip4n, - 'port': local_port, - 'probability': 30, - 'vrf_id': 0}] - - self.vapi.nat44_forwarding_enable_disable(enable=1) - flags = self.config_flags.NAT_IS_OUT2IN_ONLY - self.vapi.nat44_add_del_lb_static_mapping(is_add=1, flags=flags, - external_addr=external_addr, - external_port=external_port, - protocol=IP_PROTOS.tcp, - local_num=len(locals), - locals=locals) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg1.sw_if_index, - is_add=1) - - # from client to service - p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / - IP(src=self.pg1.remote_ip4, dst=self.nat_addr) / - TCP(sport=12345, dport=external_port)) - self.pg1.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg0.get_capture(1) - p = capture[0] - server = None - try: - ip = p[IP] - tcp = p[TCP] - self.assertIn(ip.dst, [server1.ip4, server2.ip4]) - if ip.dst == server1.ip4: - server = server1 - else: - server = server2 - self.assertEqual(tcp.dport, local_port) - self.assert_packet_checksums_valid(p) - except: - self.logger.error(ppp("Unexpected or invalid packet:", p)) - raise - - # from service back to client - p = (Ether(src=server.mac, dst=self.pg0.local_mac) / - IP(src=server.ip4, dst=self.pg1.remote_ip4) / - TCP(sport=local_port, dport=12345)) - self.pg0.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg1.get_capture(1) - p = capture[0] - try: - ip = p[IP] - tcp = p[TCP] - self.assertEqual(ip.src, self.nat_addr) - self.assertEqual(tcp.sport, external_port) - self.assert_packet_checksums_valid(p) - except: - self.logger.error(ppp("Unexpected or invalid packet:", p)) - raise - - # from client to server (no translation) - p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / - IP(src=self.pg1.remote_ip4, dst=server1.ip4) / - TCP(sport=12346, dport=local_port)) - self.pg1.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg0.get_capture(1) - p = capture[0] - server = None - try: - ip = p[IP] - tcp = p[TCP] - self.assertEqual(ip.dst, server1.ip4) - self.assertEqual(tcp.dport, local_port) - self.assert_packet_checksums_valid(p) - except: - self.logger.error(ppp("Unexpected or invalid packet:", p)) - raise - - # from service back to client (no translation) - p = (Ether(src=server1.mac, dst=self.pg0.local_mac) / - IP(src=server1.ip4, dst=self.pg1.remote_ip4) / - TCP(sport=local_port, dport=12346)) - self.pg0.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg1.get_capture(1) - p = capture[0] - try: - ip = p[IP] - tcp = p[TCP] - self.assertEqual(ip.src, server1.ip4) - self.assertEqual(tcp.sport, local_port) - self.assert_packet_checksums_valid(p) - except: - self.logger.error(ppp("Unexpected or invalid packet:", p)) - raise - - def test_lb_affinity(self): - """ NAT44 local service load balancing affinity """ - external_addr = self.nat_addr - external_port = 80 - local_port = 8080 - server1 = self.pg0.remote_hosts[0] - server2 = self.pg0.remote_hosts[1] - - locals = [{'addr': server1.ip4n, - 'port': local_port, - 'probability': 50, - 'vrf_id': 0}, - {'addr': server2.ip4n, - 'port': local_port, - 'probability': 50, - 'vrf_id': 0}] - - self.nat44_add_address(self.nat_addr) - self.vapi.nat44_add_del_lb_static_mapping(is_add=1, - external_addr=external_addr, - external_port=external_port, - protocol=IP_PROTOS.tcp, - affinity=10800, - local_num=len(locals), - locals=locals) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg1.sw_if_index, - is_add=1) - - p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / - IP(src=self.pg1.remote_ip4, dst=self.nat_addr) / - TCP(sport=1025, dport=external_port)) - self.pg1.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg0.get_capture(1) - backend = capture[0][IP].dst - - sessions = self.vapi.nat44_user_session_dump(backend, 0) - self.assertEqual(len(sessions), 1) - self.assertTrue(sessions[0].flags & - self.config_flags.NAT_IS_EXT_HOST_VALID) - self.vapi.nat44_del_session( - address=sessions[0].inside_ip_address, - port=sessions[0].inside_port, - protocol=sessions[0].protocol, - flags=(self.config_flags.NAT_IS_INSIDE | - self.config_flags.NAT_IS_EXT_HOST_VALID), - ext_host_address=sessions[0].ext_host_address, - ext_host_port=sessions[0].ext_host_port) - - pkts = [] - for port in range(1030, 1100): - p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / - IP(src=self.pg1.remote_ip4, dst=self.nat_addr) / - TCP(sport=port, dport=external_port)) - pkts.append(p) - self.pg1.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg0.get_capture(len(pkts)) - for p in capture: - self.assertEqual(p[IP].dst, backend) - - def test_unknown_proto(self): - """ NAT44 translate packet with unknown protocol """ - self.nat44_add_address(self.nat_addr) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg1.sw_if_index, - is_add=1) - - # in2out - 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=self.tcp_port_in, dport=20)) - self.pg0.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - p = self.pg1.get_capture(1) - - p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) / - GRE() / - IP(src=self.pg2.remote_ip4, dst=self.pg2.remote_ip4) / - TCP(sport=1234, dport=1234)) - self.pg0.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - p = self.pg1.get_capture(1) - packet = p[0] - try: - self.assertEqual(packet[IP].src, self.nat_addr) - self.assertEqual(packet[IP].dst, self.pg1.remote_ip4) - self.assertEqual(packet.haslayer(GRE), 1) - self.assert_packet_checksums_valid(packet) - except: - self.logger.error(ppp("Unexpected or invalid packet:", packet)) - raise - - # out2in - p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / - IP(src=self.pg1.remote_ip4, dst=self.nat_addr) / - GRE() / - IP(src=self.pg2.remote_ip4, dst=self.pg2.remote_ip4) / - TCP(sport=1234, dport=1234)) - self.pg1.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - p = self.pg0.get_capture(1) - packet = p[0] - try: - self.assertEqual(packet[IP].src, self.pg1.remote_ip4) - self.assertEqual(packet[IP].dst, self.pg0.remote_ip4) - self.assertEqual(packet.haslayer(GRE), 1) - self.assert_packet_checksums_valid(packet) - except: - self.logger.error(ppp("Unexpected or invalid packet:", packet)) - raise - - def test_hairpinning_unknown_proto(self): - """ NAT44 translate packet with unknown protocol - hairpinning """ - host = self.pg0.remote_hosts[0] - server = self.pg0.remote_hosts[1] - host_in_port = 1234 - server_out_port = 8765 - server_nat_ip = "10.0.0.11" - - self.nat44_add_address(self.nat_addr) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg1.sw_if_index, - is_add=1) - - # add static mapping for server - self.nat44_add_static_mapping(server.ip4, server_nat_ip) - - # host to server - p = (Ether(src=host.mac, dst=self.pg0.local_mac) / - IP(src=host.ip4, dst=server_nat_ip) / - TCP(sport=host_in_port, dport=server_out_port)) - self.pg0.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - self.pg0.get_capture(1) - - p = (Ether(dst=self.pg0.local_mac, src=host.mac) / - IP(src=host.ip4, dst=server_nat_ip) / - GRE() / - IP(src=self.pg2.remote_ip4, dst=self.pg2.remote_ip4) / - TCP(sport=1234, dport=1234)) - self.pg0.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - p = self.pg0.get_capture(1) - packet = p[0] - try: - self.assertEqual(packet[IP].src, self.nat_addr) - self.assertEqual(packet[IP].dst, server.ip4) - self.assertEqual(packet.haslayer(GRE), 1) - self.assert_packet_checksums_valid(packet) - except: - self.logger.error(ppp("Unexpected or invalid packet:", packet)) - raise - - # server to host - p = (Ether(dst=self.pg0.local_mac, src=server.mac) / - IP(src=server.ip4, dst=self.nat_addr) / - GRE() / - IP(src=self.pg2.remote_ip4, dst=self.pg2.remote_ip4) / - TCP(sport=1234, dport=1234)) - self.pg0.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - p = self.pg0.get_capture(1) - packet = p[0] - try: - self.assertEqual(packet[IP].src, server_nat_ip) - self.assertEqual(packet[IP].dst, host.ip4) - self.assertEqual(packet.haslayer(GRE), 1) - self.assert_packet_checksums_valid(packet) - except: - self.logger.error(ppp("Unexpected or invalid packet:", packet)) - raise - - def test_output_feature_and_service(self): - """ NAT44 interface output feature and services """ - external_addr = '1.2.3.4' - external_port = 80 - local_port = 8080 - - self.vapi.nat44_forwarding_enable_disable(enable=1) - self.nat44_add_address(self.nat_addr) - flags = self.config_flags.NAT_IS_ADDR_ONLY - self.vapi.nat44_add_del_identity_mapping( - ip_address=self.pg1.remote_ip4n, sw_if_index=0xFFFFFFFF, - flags=flags, is_add=1) - flags = self.config_flags.NAT_IS_OUT2IN_ONLY - self.nat44_add_static_mapping(self.pg0.remote_ip4, external_addr, - local_port, external_port, - proto=IP_PROTOS.tcp, flags=flags) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_output_feature( - is_add=1, - sw_if_index=self.pg1.sw_if_index) - - # from client to service - p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / - IP(src=self.pg1.remote_ip4, dst=external_addr) / - TCP(sport=12345, dport=external_port)) - self.pg1.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg0.get_capture(1) - p = capture[0] - try: - ip = p[IP] - tcp = p[TCP] - self.assertEqual(ip.dst, self.pg0.remote_ip4) - self.assertEqual(tcp.dport, local_port) - self.assert_packet_checksums_valid(p) - except: - self.logger.error(ppp("Unexpected or invalid packet:", p)) - raise - - # from service back to client - 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=local_port, dport=12345)) - self.pg0.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg1.get_capture(1) - p = capture[0] - try: - ip = p[IP] - tcp = p[TCP] - self.assertEqual(ip.src, external_addr) - self.assertEqual(tcp.sport, external_port) - self.assert_packet_checksums_valid(p) - except: - self.logger.error(ppp("Unexpected or invalid packet:", p)) - raise - - # from local network host to external network - 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) - 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) - - # from external network back to local network host - pkts = self.create_stream_out(self.pg1) - self.pg1.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg0.get_capture(len(pkts)) - self.verify_capture_in(capture, self.pg0) - - def test_output_feature_and_service2(self): - """ NAT44 interface output feature and service host direct access """ - self.vapi.nat44_forwarding_enable_disable(enable=1) - self.nat44_add_address(self.nat_addr) - self.vapi.nat44_interface_add_del_output_feature( - is_add=1, - sw_if_index=self.pg1.sw_if_index) - - # session initiated from service host - translate - 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) - - pkts = self.create_stream_out(self.pg1) - self.pg1.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg0.get_capture(len(pkts)) - self.verify_capture_in(capture, self.pg0) - - # session initiated from remote host - do not translate - self.tcp_port_in = 60303 - self.udp_port_in = 60304 - self.icmp_id_in = 60305 - pkts = self.create_stream_out(self.pg1, - self.pg0.remote_ip4, - use_inside_ports=True) - self.pg1.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg0.get_capture(len(pkts)) - self.verify_capture_in(capture, self.pg0) - - 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, nat_ip=self.pg0.remote_ip4, - same_port=True) - - def test_output_feature_and_service3(self): - """ NAT44 interface output feature and DST NAT """ - external_addr = '1.2.3.4' - external_port = 80 - local_port = 8080 - - self.vapi.nat44_forwarding_enable_disable(enable=1) - self.nat44_add_address(self.nat_addr) - flags = self.config_flags.NAT_IS_OUT2IN_ONLY - self.nat44_add_static_mapping(self.pg1.remote_ip4, external_addr, - local_port, external_port, - proto=IP_PROTOS.tcp, flags=flags) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_output_feature( - is_add=1, - sw_if_index=self.pg1.sw_if_index) - - p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / - IP(src=self.pg0.remote_ip4, dst=external_addr) / - TCP(sport=12345, dport=external_port)) - self.pg0.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg1.get_capture(1) - p = capture[0] - try: - ip = p[IP] - tcp = p[TCP] - self.assertEqual(ip.src, self.pg0.remote_ip4) - self.assertEqual(tcp.sport, 12345) - self.assertEqual(ip.dst, self.pg1.remote_ip4) - self.assertEqual(tcp.dport, local_port) - self.assert_packet_checksums_valid(p) - except: - self.logger.error(ppp("Unexpected or invalid packet:", p)) - raise - - p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / - IP(src=self.pg1.remote_ip4, dst=self.pg0.remote_ip4) / - TCP(sport=local_port, dport=12345)) - self.pg1.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg0.get_capture(1) - p = capture[0] - try: - ip = p[IP] - tcp = p[TCP] - self.assertEqual(ip.src, external_addr) - self.assertEqual(tcp.sport, external_port) - self.assertEqual(ip.dst, self.pg0.remote_ip4) - self.assertEqual(tcp.dport, 12345) - self.assert_packet_checksums_valid(p) - except: - self.logger.error(ppp("Unexpected or invalid packet:", p)) - raise - - def test_next_src_nat(self): - """ On way back forward packet to nat44-in2out node. """ - twice_nat_addr = '10.0.1.3' - external_port = 80 - local_port = 8080 - post_twice_nat_port = 0 - - self.vapi.nat44_forwarding_enable_disable(enable=1) - self.nat44_add_address(twice_nat_addr, twice_nat=1) - flags = (self.config_flags.NAT_IS_OUT2IN_ONLY | - self.config_flags.NAT_IS_SELF_TWICE_NAT) - self.nat44_add_static_mapping(self.pg6.remote_ip4, self.pg1.remote_ip4, - local_port, external_port, - proto=IP_PROTOS.tcp, vrf_id=1, - flags=flags) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg6.sw_if_index, - is_add=1) - - p = (Ether(src=self.pg6.remote_mac, dst=self.pg6.local_mac) / - IP(src=self.pg6.remote_ip4, dst=self.pg1.remote_ip4) / - TCP(sport=12345, dport=external_port)) - self.pg6.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, twice_nat_addr) - self.assertNotEqual(tcp.sport, 12345) - post_twice_nat_port = tcp.sport - self.assertEqual(ip.dst, self.pg6.remote_ip4) - self.assertEqual(tcp.dport, local_port) - self.assert_packet_checksums_valid(p) - except: - self.logger.error(ppp("Unexpected or invalid packet:", p)) - raise - - p = (Ether(src=self.pg6.remote_mac, dst=self.pg6.local_mac) / - IP(src=self.pg6.remote_ip4, dst=twice_nat_addr) / - TCP(sport=local_port, dport=post_twice_nat_port)) - self.pg6.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.pg1.remote_ip4) - self.assertEqual(tcp.sport, external_port) - self.assertEqual(ip.dst, self.pg6.remote_ip4) - self.assertEqual(tcp.dport, 12345) - self.assert_packet_checksums_valid(p) - except: - self.logger.error(ppp("Unexpected or invalid packet:", p)) - raise - - def twice_nat_common(self, self_twice_nat=False, same_pg=False, lb=False, - client_id=None): - twice_nat_addr = '10.0.1.3' - - port_in = 8080 - if lb: - if not same_pg: - port_in1 = port_in - port_in2 = port_in - else: - port_in1 = port_in + 1 - port_in2 = port_in + 2 - - port_out = 80 - eh_port_out = 4567 - - server1 = self.pg0.remote_hosts[0] - server2 = self.pg0.remote_hosts[1] - if lb and same_pg: - server2 = server1 - if not lb: - server = server1 - - pg0 = self.pg0 - if same_pg: - pg1 = self.pg0 - else: - pg1 = self.pg1 - - eh_translate = ((not self_twice_nat) or (not lb and same_pg) or - client_id == 1) - - self.nat44_add_address(self.nat_addr) - self.nat44_add_address(twice_nat_addr, twice_nat=1) - - flags = 0 - if self_twice_nat: - flags |= self.config_flags.NAT_IS_SELF_TWICE_NAT - else: - flags |= self.config_flags.NAT_IS_TWICE_NAT - - if not lb: - self.nat44_add_static_mapping(pg0.remote_ip4, self.nat_addr, - port_in, port_out, - proto=IP_PROTOS.tcp, - flags=flags) - else: - locals = [{'addr': server1.ip4n, - 'port': port_in1, - 'probability': 50, - 'vrf_id': 0}, - {'addr': server2.ip4n, - 'port': port_in2, - 'probability': 50, - 'vrf_id': 0}] - out_addr = self.nat_addr - - self.vapi.nat44_add_del_lb_static_mapping(is_add=1, flags=flags, - external_addr=out_addr, - external_port=port_out, - protocol=IP_PROTOS.tcp, - local_num=len(locals), - locals=locals) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=pg1.sw_if_index, - is_add=1) - - if same_pg: - if not lb: - client = server - else: - assert client_id is not None - if client_id == 1: - client = self.pg0.remote_hosts[0] - elif client_id == 2: - client = self.pg0.remote_hosts[1] - else: - client = pg1.remote_hosts[0] - p = (Ether(src=pg1.remote_mac, dst=pg1.local_mac) / - IP(src=client.ip4, dst=self.nat_addr) / - TCP(sport=eh_port_out, dport=port_out)) - pg1.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = pg0.get_capture(1) - p = capture[0] - try: - ip = p[IP] - tcp = p[TCP] - if lb: - if ip.dst == server1.ip4: - server = server1 - port_in = port_in1 - else: - server = server2 - port_in = port_in2 - self.assertEqual(ip.dst, server.ip4) - if lb and same_pg: - self.assertIn(tcp.dport, [port_in1, port_in2]) - else: - self.assertEqual(tcp.dport, port_in) - if eh_translate: - self.assertEqual(ip.src, twice_nat_addr) - self.assertNotEqual(tcp.sport, eh_port_out) - else: - self.assertEqual(ip.src, client.ip4) - self.assertEqual(tcp.sport, eh_port_out) - eh_addr_in = ip.src - eh_port_in = tcp.sport - saved_port_in = tcp.dport - self.assert_packet_checksums_valid(p) - except: - self.logger.error(ppp("Unexpected or invalid packet:", p)) - raise - - p = (Ether(src=server.mac, dst=pg0.local_mac) / - IP(src=server.ip4, dst=eh_addr_in) / - TCP(sport=saved_port_in, dport=eh_port_in)) - pg0.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = pg1.get_capture(1) - p = capture[0] - try: - ip = p[IP] - tcp = p[TCP] - self.assertEqual(ip.dst, client.ip4) - self.assertEqual(ip.src, self.nat_addr) - self.assertEqual(tcp.dport, eh_port_out) - self.assertEqual(tcp.sport, port_out) - self.assert_packet_checksums_valid(p) - except: - self.logger.error(ppp("Unexpected or invalid packet:", p)) - raise - - if eh_translate: - sessions = self.vapi.nat44_user_session_dump(server.ip4n, 0) - self.assertEqual(len(sessions), 1) - self.assertTrue(sessions[0].flags & - self.config_flags.NAT_IS_EXT_HOST_VALID) - self.assertTrue(sessions[0].flags & - self.config_flags.NAT_IS_TWICE_NAT) - self.logger.info(self.vapi.cli("show nat44 sessions detail")) - self.vapi.nat44_del_session( - address=sessions[0].inside_ip_address, - port=sessions[0].inside_port, - protocol=sessions[0].protocol, - flags=(self.config_flags.NAT_IS_INSIDE | - self.config_flags.NAT_IS_EXT_HOST_VALID), - ext_host_address=sessions[0].ext_host_nat_address, - ext_host_port=sessions[0].ext_host_nat_port) - sessions = self.vapi.nat44_user_session_dump(server.ip4n, 0) - self.assertEqual(len(sessions), 0) - - def test_twice_nat(self): - """ Twice NAT44 """ - self.twice_nat_common() - - def test_self_twice_nat_positive(self): - """ Self Twice NAT44 (positive test) """ - self.twice_nat_common(self_twice_nat=True, same_pg=True) - - def test_self_twice_nat_negative(self): - """ Self Twice NAT44 (negative test) """ - self.twice_nat_common(self_twice_nat=True) - - def test_twice_nat_lb(self): - """ Twice NAT44 local service load balancing """ - self.twice_nat_common(lb=True) - - def test_self_twice_nat_lb_positive(self): - """ Self Twice NAT44 local service load balancing (positive test) """ - self.twice_nat_common(lb=True, self_twice_nat=True, same_pg=True, - client_id=1) - - def test_self_twice_nat_lb_negative(self): - """ Self Twice NAT44 local service load balancing (negative test) """ - self.twice_nat_common(lb=True, self_twice_nat=True, same_pg=True, - client_id=2) - - def test_twice_nat_interface_addr(self): - """ Acquire twice NAT44 addresses from interface """ - flags = self.config_flags.NAT_IS_TWICE_NAT - self.vapi.nat44_add_del_interface_addr( - is_add=1, - sw_if_index=self.pg3.sw_if_index, - flags=flags) - - # no address in NAT pool - adresses = self.vapi.nat44_address_dump() - self.assertEqual(0, len(adresses)) - - # configure interface address and check NAT address pool - self.pg3.config_ip4() - adresses = self.vapi.nat44_address_dump() - self.assertEqual(1, len(adresses)) - self.assertEqual(str(adresses[0].ip_address), - self.pg3.local_ip4) - self.assertEqual(adresses[0].flags, flags) - - # remove interface address and check NAT address pool - self.pg3.unconfig_ip4() - adresses = self.vapi.nat44_address_dump() - self.assertEqual(0, len(adresses)) - - def test_tcp_close(self): - """ Close TCP session from inside network - output feature """ - self.vapi.nat44_forwarding_enable_disable(enable=1) - self.nat44_add_address(self.pg1.local_ip4) - twice_nat_addr = '10.0.1.3' - service_ip = '192.168.16.150' - self.nat44_add_address(twice_nat_addr, twice_nat=1) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_output_feature( - is_add=1, - sw_if_index=self.pg1.sw_if_index) - flags = (self.config_flags.NAT_IS_OUT2IN_ONLY | - self.config_flags.NAT_IS_TWICE_NAT) - self.nat44_add_static_mapping(self.pg0.remote_ip4, - service_ip, - 80, - 80, - proto=IP_PROTOS.tcp, - flags=flags) - sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4n, 0) - start_sessnum = len(sessions) - - # SYN packet out->in - p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / - IP(src=self.pg1.remote_ip4, dst=service_ip) / - TCP(sport=33898, dport=80, flags="S")) - self.pg1.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg0.get_capture(1) - p = capture[0] - tcp_port = p[TCP].sport - - # SYN + ACK packet in->out - p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / - IP(src=self.pg0.remote_ip4, dst=twice_nat_addr) / - TCP(sport=80, dport=tcp_port, flags="SA")) - self.pg0.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - self.pg1.get_capture(1) - - # ACK packet out->in - p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / - IP(src=self.pg1.remote_ip4, dst=service_ip) / - TCP(sport=33898, dport=80, flags="A")) - self.pg1.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - self.pg0.get_capture(1) - - # FIN packet in -> out - p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / - IP(src=self.pg0.remote_ip4, dst=twice_nat_addr) / - TCP(sport=80, dport=tcp_port, flags="FA", seq=100, ack=300)) - self.pg0.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - self.pg1.get_capture(1) - - # FIN+ACK packet out -> in - p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / - IP(src=self.pg1.remote_ip4, dst=service_ip) / - TCP(sport=33898, dport=80, flags="FA", seq=300, ack=101)) - self.pg1.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - self.pg0.get_capture(1) - - # ACK packet in -> out - p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / - IP(src=self.pg0.remote_ip4, dst=twice_nat_addr) / - TCP(sport=80, dport=tcp_port, flags="A", seq=101, ack=301)) - self.pg0.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - self.pg1.get_capture(1) - - sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4n, - 0) - self.assertEqual(len(sessions) - start_sessnum, 0) - - def test_tcp_session_close_in(self): - """ Close TCP session from inside network """ - self.tcp_port_out = 10505 - self.nat44_add_address(self.nat_addr) - flags = self.config_flags.NAT_IS_TWICE_NAT - self.nat44_add_static_mapping(self.pg0.remote_ip4, - self.nat_addr, - self.tcp_port_in, - self.tcp_port_out, - proto=IP_PROTOS.tcp, - flags=flags) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg1.sw_if_index, - is_add=1) - - sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4n, 0) - start_sessnum = len(sessions) - - self.initiate_tcp_session(self.pg0, self.pg1) - - # FIN packet in -> out - 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=self.tcp_port_in, dport=self.tcp_external_port, - flags="FA", seq=100, ack=300)) - self.pg0.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - self.pg1.get_capture(1) - - pkts = [] - - # ACK packet out -> in - p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / - IP(src=self.pg1.remote_ip4, dst=self.nat_addr) / - TCP(sport=self.tcp_external_port, dport=self.tcp_port_out, - flags="A", seq=300, ack=101)) - pkts.append(p) - - # FIN packet out -> in - p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / - IP(src=self.pg1.remote_ip4, dst=self.nat_addr) / - TCP(sport=self.tcp_external_port, dport=self.tcp_port_out, - flags="FA", seq=300, ack=101)) - pkts.append(p) - - self.pg1.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - self.pg0.get_capture(2) - - # ACK packet in -> out - 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=self.tcp_port_in, dport=self.tcp_external_port, - flags="A", seq=101, ack=301)) - self.pg0.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - self.pg1.get_capture(1) - - sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4n, - 0) - self.assertEqual(len(sessions) - start_sessnum, 0) - - def test_tcp_session_close_out(self): - """ Close TCP session from outside network """ - self.tcp_port_out = 10505 - self.nat44_add_address(self.nat_addr) - flags = self.config_flags.NAT_IS_TWICE_NAT - self.nat44_add_static_mapping(self.pg0.remote_ip4, - self.nat_addr, - self.tcp_port_in, - self.tcp_port_out, - proto=IP_PROTOS.tcp, - flags=flags) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg1.sw_if_index, - is_add=1) - - sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4n, 0) - start_sessnum = len(sessions) - - self.initiate_tcp_session(self.pg0, self.pg1) - - # FIN packet out -> in - p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / - IP(src=self.pg1.remote_ip4, dst=self.nat_addr) / - TCP(sport=self.tcp_external_port, dport=self.tcp_port_out, - flags="FA", seq=100, ack=300)) - self.pg1.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - self.pg0.get_capture(1) - - # FIN+ACK packet in -> out - 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=self.tcp_port_in, dport=self.tcp_external_port, - flags="FA", seq=300, ack=101)) - - self.pg0.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - self.pg1.get_capture(1) - - # ACK packet out -> in - p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / - IP(src=self.pg1.remote_ip4, dst=self.nat_addr) / - TCP(sport=self.tcp_external_port, dport=self.tcp_port_out, - flags="A", seq=101, ack=301)) - self.pg1.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - self.pg0.get_capture(1) - - sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4n, - 0) - self.assertEqual(len(sessions) - start_sessnum, 0) - - def test_tcp_session_close_simultaneous(self): - """ Close TCP session from inside network """ - self.tcp_port_out = 10505 - self.nat44_add_address(self.nat_addr) - flags = self.config_flags.NAT_IS_TWICE_NAT - self.nat44_add_static_mapping(self.pg0.remote_ip4, - self.nat_addr, - self.tcp_port_in, - self.tcp_port_out, - proto=IP_PROTOS.tcp, - flags=flags) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg1.sw_if_index, - is_add=1) - - sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4n, 0) - start_sessnum = len(sessions) - - self.initiate_tcp_session(self.pg0, self.pg1) - - # FIN packet in -> out - 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=self.tcp_port_in, dport=self.tcp_external_port, - flags="FA", seq=100, ack=300)) - self.pg0.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - self.pg1.get_capture(1) - - # FIN packet out -> in - p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / - IP(src=self.pg1.remote_ip4, dst=self.nat_addr) / - TCP(sport=self.tcp_external_port, dport=self.tcp_port_out, - flags="FA", seq=300, ack=100)) - self.pg1.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - self.pg0.get_capture(1) - - # ACK packet in -> out - 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=self.tcp_port_in, dport=self.tcp_external_port, - flags="A", seq=101, ack=301)) - self.pg0.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - self.pg1.get_capture(1) - - # ACK packet out -> in - p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / - IP(src=self.pg1.remote_ip4, dst=self.nat_addr) / - TCP(sport=self.tcp_external_port, dport=self.tcp_port_out, - flags="A", seq=301, ack=101)) - self.pg1.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - self.pg0.get_capture(1) - - sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4n, - 0) - self.assertEqual(len(sessions) - start_sessnum, 0) - - def test_one_armed_nat44_static(self): - """ One armed NAT44 and 1:1 NAPT asymmetrical rule """ - remote_host = self.pg4.remote_hosts[0] - local_host = self.pg4.remote_hosts[1] - external_port = 80 - local_port = 8080 - eh_port_in = 0 - - self.vapi.nat44_forwarding_enable_disable(enable=1) - self.nat44_add_address(self.nat_addr, twice_nat=1) - flags = (self.config_flags.NAT_IS_OUT2IN_ONLY | - self.config_flags.NAT_IS_TWICE_NAT) - self.nat44_add_static_mapping(local_host.ip4, self.nat_addr, - local_port, external_port, - proto=IP_PROTOS.tcp, flags=flags) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg4.sw_if_index, - is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg4.sw_if_index, - flags=flags, is_add=1) - - # from client to service - p = (Ether(src=self.pg4.remote_mac, dst=self.pg4.local_mac) / - IP(src=remote_host.ip4, dst=self.nat_addr) / - TCP(sport=12345, dport=external_port)) - self.pg4.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg4.get_capture(1) - p = capture[0] - try: - ip = p[IP] - tcp = p[TCP] - self.assertEqual(ip.dst, local_host.ip4) - self.assertEqual(ip.src, self.nat_addr) - self.assertEqual(tcp.dport, local_port) - self.assertNotEqual(tcp.sport, 12345) - eh_port_in = tcp.sport - self.assert_packet_checksums_valid(p) - except: - self.logger.error(ppp("Unexpected or invalid packet:", p)) - raise - - # from service back to client - p = (Ether(src=self.pg4.remote_mac, dst=self.pg4.local_mac) / - IP(src=local_host.ip4, dst=self.nat_addr) / - TCP(sport=local_port, dport=eh_port_in)) - self.pg4.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg4.get_capture(1) - p = capture[0] - try: - ip = p[IP] - tcp = p[TCP] - self.assertEqual(ip.src, self.nat_addr) - self.assertEqual(ip.dst, remote_host.ip4) - self.assertEqual(tcp.sport, external_port) - self.assertEqual(tcp.dport, 12345) - self.assert_packet_checksums_valid(p) - except: - self.logger.error(ppp("Unexpected or invalid packet:", p)) - raise - - def test_static_with_port_out2(self): - """ 1:1 NAPT asymmetrical rule """ - - external_port = 80 - local_port = 8080 - - self.vapi.nat44_forwarding_enable_disable(enable=1) - flags = self.config_flags.NAT_IS_OUT2IN_ONLY - self.nat44_add_static_mapping(self.pg0.remote_ip4, self.nat_addr, - local_port, external_port, - proto=IP_PROTOS.tcp, flags=flags) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg1.sw_if_index, - is_add=1) - - # from client to service - p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / - IP(src=self.pg1.remote_ip4, dst=self.nat_addr) / - TCP(sport=12345, dport=external_port)) - self.pg1.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg0.get_capture(1) - p = capture[0] - try: - ip = p[IP] - tcp = p[TCP] - self.assertEqual(ip.dst, self.pg0.remote_ip4) - self.assertEqual(tcp.dport, local_port) - self.assert_packet_checksums_valid(p) - except: - self.logger.error(ppp("Unexpected or invalid packet:", p)) - raise - - # ICMP error - p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) / - ICMP(type=11) / capture[0][IP]) - self.pg0.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg1.get_capture(1) - p = capture[0] - try: - self.assertEqual(p[IP].src, self.nat_addr) - inner = p[IPerror] - self.assertEqual(inner.dst, self.nat_addr) - self.assertEqual(inner[TCPerror].dport, external_port) - except: - self.logger.error(ppp("Unexpected or invalid packet:", p)) - raise - - # from service back to client - 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=local_port, dport=12345)) - self.pg0.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg1.get_capture(1) - p = capture[0] - try: - ip = p[IP] - tcp = p[TCP] - self.assertEqual(ip.src, self.nat_addr) - self.assertEqual(tcp.sport, external_port) - self.assert_packet_checksums_valid(p) - except: - self.logger.error(ppp("Unexpected or invalid packet:", p)) - raise - - # ICMP error - p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / - IP(src=self.pg1.remote_ip4, dst=self.nat_addr) / - ICMP(type=11) / capture[0][IP]) - self.pg1.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg0.get_capture(1) - p = capture[0] - try: - self.assertEqual(p[IP].dst, self.pg0.remote_ip4) - inner = p[IPerror] - self.assertEqual(inner.src, self.pg0.remote_ip4) - self.assertEqual(inner[TCPerror].sport, local_port) - except: - self.logger.error(ppp("Unexpected or invalid packet:", p)) - raise - - # from client to server (no translation) - p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / - IP(src=self.pg1.remote_ip4, dst=self.pg0.remote_ip4) / - TCP(sport=12346, dport=local_port)) - self.pg1.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg0.get_capture(1) - p = capture[0] - try: - ip = p[IP] - tcp = p[TCP] - self.assertEqual(ip.dst, self.pg0.remote_ip4) - self.assertEqual(tcp.dport, local_port) - self.assert_packet_checksums_valid(p) - except: - self.logger.error(ppp("Unexpected or invalid packet:", p)) - raise - - # from service back to client (no translation) - 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=local_port, dport=12346)) - self.pg0.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg1.get_capture(1) - p = capture[0] - try: - ip = p[IP] - tcp = p[TCP] - self.assertEqual(ip.src, self.pg0.remote_ip4) - self.assertEqual(tcp.sport, local_port) - self.assert_packet_checksums_valid(p) - except: - self.logger.error(ppp("Unexpected or invalid packet:", p)) - raise - - def test_output_feature(self): - """ NAT44 interface output feature (in2out postrouting) """ - self.vapi.nat44_forwarding_enable_disable(enable=1) - self.nat44_add_address(self.nat_addr) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - is_add=1) - self.vapi.nat44_interface_add_del_output_feature( - is_add=1, - sw_if_index=self.pg1.sw_if_index) - - # in2out - 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) - - # out2in - pkts = self.create_stream_out(self.pg1) - self.pg1.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg0.get_capture(len(pkts)) - self.verify_capture_in(capture, self.pg0) - - def test_multiple_vrf(self): - """ Multiple VRF setup """ - external_addr = '1.2.3.4' - external_port = 80 - local_port = 8080 - port = 0 - - self.vapi.nat44_forwarding_enable_disable(enable=1) - self.nat44_add_address(self.nat_addr) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_output_feature( - is_add=1, - sw_if_index=self.pg1.sw_if_index) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg5.sw_if_index, - is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg5.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg6.sw_if_index, - is_add=1) - flags = self.config_flags.NAT_IS_OUT2IN_ONLY - self.nat44_add_static_mapping(self.pg5.remote_ip4, external_addr, - local_port, external_port, vrf_id=1, - proto=IP_PROTOS.tcp, flags=flags) - self.nat44_add_static_mapping( - self.pg0.remote_ip4, - external_sw_if_index=self.pg0.sw_if_index, - local_port=local_port, - vrf_id=0, - external_port=external_port, - proto=IP_PROTOS.tcp, - flags=flags - ) - - # from client to service (both VRF1) - p = (Ether(src=self.pg6.remote_mac, dst=self.pg6.local_mac) / - IP(src=self.pg6.remote_ip4, dst=external_addr) / - TCP(sport=12345, dport=external_port)) - self.pg6.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg5.get_capture(1) - p = capture[0] - try: - ip = p[IP] - tcp = p[TCP] - self.assertEqual(ip.dst, self.pg5.remote_ip4) - self.assertEqual(tcp.dport, local_port) - self.assert_packet_checksums_valid(p) - except: - self.logger.error(ppp("Unexpected or invalid packet:", p)) - raise - - # from service back to client (both VRF1) - p = (Ether(src=self.pg5.remote_mac, dst=self.pg5.local_mac) / - IP(src=self.pg5.remote_ip4, dst=self.pg6.remote_ip4) / - TCP(sport=local_port, dport=12345)) - self.pg5.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, external_addr) - self.assertEqual(tcp.sport, external_port) - self.assert_packet_checksums_valid(p) - except: - self.logger.error(ppp("Unexpected or invalid packet:", p)) - raise - - # dynamic NAT from VRF1 to VRF0 (output-feature) - p = (Ether(src=self.pg5.remote_mac, dst=self.pg5.local_mac) / - IP(src=self.pg5.remote_ip4, dst=self.pg1.remote_ip4) / - TCP(sport=2345, dport=22)) - self.pg5.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg1.get_capture(1) - p = capture[0] - try: - ip = p[IP] - tcp = p[TCP] - self.assertEqual(ip.src, self.nat_addr) - self.assertNotEqual(tcp.sport, 2345) - self.assert_packet_checksums_valid(p) - port = tcp.sport - except: - self.logger.error(ppp("Unexpected or invalid packet:", p)) - raise - - p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / - IP(src=self.pg1.remote_ip4, dst=self.nat_addr) / - TCP(sport=22, dport=port)) - self.pg1.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg5.get_capture(1) - p = capture[0] - try: - ip = p[IP] - tcp = p[TCP] - self.assertEqual(ip.dst, self.pg5.remote_ip4) - self.assertEqual(tcp.dport, 2345) - self.assert_packet_checksums_valid(p) - except: - self.logger.error(ppp("Unexpected or invalid packet:", p)) - raise - - # from client VRF1 to service VRF0 - p = (Ether(src=self.pg6.remote_mac, dst=self.pg6.local_mac) / - IP(src=self.pg6.remote_ip4, dst=self.pg0.local_ip4) / - TCP(sport=12346, dport=external_port)) - self.pg6.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg0.get_capture(1) - p = capture[0] - try: - ip = p[IP] - tcp = p[TCP] - self.assertEqual(ip.dst, self.pg0.remote_ip4) - self.assertEqual(tcp.dport, local_port) - self.assert_packet_checksums_valid(p) - except: - self.logger.error(ppp("Unexpected or invalid packet:", p)) - raise - - # from service VRF0 back to client VRF1 - p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / - IP(src=self.pg0.remote_ip4, dst=self.pg6.remote_ip4) / - TCP(sport=local_port, dport=12346)) - self.pg0.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.pg0.local_ip4) - self.assertEqual(tcp.sport, external_port) - self.assert_packet_checksums_valid(p) - except: - self.logger.error(ppp("Unexpected or invalid packet:", p)) - raise - - # from client VRF0 to service VRF1 - p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / - IP(src=self.pg0.remote_ip4, dst=external_addr) / - TCP(sport=12347, dport=external_port)) - self.pg0.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg5.get_capture(1) - p = capture[0] - try: - ip = p[IP] - tcp = p[TCP] - self.assertEqual(ip.dst, self.pg5.remote_ip4) - self.assertEqual(tcp.dport, local_port) - self.assert_packet_checksums_valid(p) - except: - self.logger.error(ppp("Unexpected or invalid packet:", p)) - raise - - # from service VRF1 back to client VRF0 - p = (Ether(src=self.pg5.remote_mac, dst=self.pg5.local_mac) / - IP(src=self.pg5.remote_ip4, dst=self.pg0.remote_ip4) / - TCP(sport=local_port, dport=12347)) - self.pg5.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg0.get_capture(1) - p = capture[0] - try: - ip = p[IP] - tcp = p[TCP] - self.assertEqual(ip.src, external_addr) - self.assertEqual(tcp.sport, external_port) - self.assert_packet_checksums_valid(p) - except: - self.logger.error(ppp("Unexpected or invalid packet:", p)) - raise - - # from client to server (both VRF1, no translation) - p = (Ether(src=self.pg6.remote_mac, dst=self.pg6.local_mac) / - IP(src=self.pg6.remote_ip4, dst=self.pg5.remote_ip4) / - TCP(sport=12348, dport=local_port)) - self.pg6.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg5.get_capture(1) - p = capture[0] - try: - ip = p[IP] - tcp = p[TCP] - self.assertEqual(ip.dst, self.pg5.remote_ip4) - self.assertEqual(tcp.dport, local_port) - self.assert_packet_checksums_valid(p) - except: - self.logger.error(ppp("Unexpected or invalid packet:", p)) - raise - - # from server back to client (both VRF1, no translation) - p = (Ether(src=self.pg5.remote_mac, dst=self.pg5.local_mac) / - IP(src=self.pg5.remote_ip4, dst=self.pg6.remote_ip4) / - TCP(sport=local_port, dport=12348)) - self.pg5.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.pg5.remote_ip4) - self.assertEqual(tcp.sport, local_port) - self.assert_packet_checksums_valid(p) - except: - self.logger.error(ppp("Unexpected or invalid packet:", p)) - raise - - # from client VRF1 to server VRF0 (no translation) - p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / - IP(src=self.pg0.remote_ip4, dst=self.pg6.remote_ip4) / - TCP(sport=local_port, dport=12349)) - self.pg0.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.pg0.remote_ip4) - self.assertEqual(tcp.sport, local_port) - self.assert_packet_checksums_valid(p) - except: - self.logger.error(ppp("Unexpected or invalid packet:", p)) - raise - - # from server VRF0 back to client VRF1 (no translation) - p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / - IP(src=self.pg0.remote_ip4, dst=self.pg6.remote_ip4) / - TCP(sport=local_port, dport=12349)) - self.pg0.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.pg0.remote_ip4) - self.assertEqual(tcp.sport, local_port) - self.assert_packet_checksums_valid(p) - except: - self.logger.error(ppp("Unexpected or invalid packet:", p)) - raise - - # from client VRF0 to server VRF1 (no translation) - p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / - IP(src=self.pg0.remote_ip4, dst=self.pg5.remote_ip4) / - TCP(sport=12344, dport=local_port)) - self.pg0.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg5.get_capture(1) - p = capture[0] - try: - ip = p[IP] - tcp = p[TCP] - self.assertEqual(ip.dst, self.pg5.remote_ip4) - self.assertEqual(tcp.dport, local_port) - self.assert_packet_checksums_valid(p) - except: - self.logger.error(ppp("Unexpected or invalid packet:", p)) - raise - - # from server VRF1 back to client VRF0 (no translation) - p = (Ether(src=self.pg5.remote_mac, dst=self.pg5.local_mac) / - IP(src=self.pg5.remote_ip4, dst=self.pg0.remote_ip4) / - TCP(sport=local_port, dport=12344)) - self.pg5.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg0.get_capture(1) - p = capture[0] - try: - ip = p[IP] - tcp = p[TCP] - self.assertEqual(ip.src, self.pg5.remote_ip4) - self.assertEqual(tcp.sport, local_port) - self.assert_packet_checksums_valid(p) - except: - self.logger.error(ppp("Unexpected or invalid packet:", p)) - raise - - @unittest.skipUnless(running_extended_tests, "part of extended tests") - def test_session_timeout(self): - """ NAT44 session timeouts """ - self.nat44_add_address(self.nat_addr) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg1.sw_if_index, - is_add=1) - self.vapi.nat_set_timeouts(udp=300, tcp_established=7440, - tcp_transitory=240, icmp=5) - - max_sessions = 1000 - pkts = [] - for i in range(0, max_sessions): - src = "10.10.%u.%u" % ((i & 0xFF00) >> 8, i & 0xFF) - p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IP(src=src, dst=self.pg1.remote_ip4) / - ICMP(id=1025, type='echo-request')) - pkts.append(p) - self.pg0.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - self.pg1.get_capture(max_sessions) - - sleep(10) - - pkts = [] - for i in range(0, max_sessions): - src = "10.11.%u.%u" % ((i & 0xFF00) >> 8, i & 0xFF) - p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IP(src=src, dst=self.pg1.remote_ip4) / - ICMP(id=1026, type='echo-request')) - pkts.append(p) - self.pg0.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - self.pg1.get_capture(max_sessions) - - nsessions = 0 - users = self.vapi.nat44_user_dump() - for user in users: - nsessions = nsessions + user.nsessions - self.assertLess(nsessions, 2 * max_sessions) - - @unittest.skipUnless(running_extended_tests, "part of extended tests") - def test_session_rst_timeout(self): - """ NAT44 session RST timeouts """ - self.nat44_add_address(self.nat_addr) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg1.sw_if_index, - is_add=1) - self.vapi.nat_set_timeouts(udp=300, tcp_established=7440, - tcp_transitory=5, icmp=60) - - self.initiate_tcp_session(self.pg0, self.pg1) - 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=self.tcp_port_in, dport=self.tcp_external_port, - flags="R")) - self.pg0.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - self.pg1.get_capture(1) - - sleep(6) - - 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=self.tcp_port_in + 1, dport=self.tcp_external_port + 1, - flags="S")) - self.pg0.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - self.pg1.get_capture(1) - - nsessions = 0 - users = self.vapi.nat44_user_dump() - self.assertEqual(len(users), 1) - self.assertEqual(str(users[0].ip_address), - self.pg0.remote_ip4) - self.assertEqual(users[0].nsessions, 1) - - @unittest.skipUnless(running_extended_tests, "part of extended tests") - def test_session_limit_per_user(self): - """ Maximum sessions per user limit """ - self.nat44_add_address(self.nat_addr) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg1.sw_if_index, - is_add=1) - self.vapi.set_ipfix_exporter(collector_address=self.pg2.remote_ip4n, - src_address=self.pg2.local_ip4n, - path_mtu=512, - template_interval=10) - self.vapi.nat_set_timeouts(udp=5, tcp_established=7440, - tcp_transitory=240, icmp=60) - - # get maximum number of translations per user - nat44_config = self.vapi.nat_show_config() - - pkts = [] - for port in range(0, nat44_config.max_translations_per_user): - p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / - IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) / - UDP(sport=1025 + port, dport=1025 + port)) - pkts.append(p) - - self.pg0.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg1.get_capture(len(pkts)) - - self.vapi.nat_ipfix_enable_disable(domain_id=self.ipfix_domain_id, - src_port=self.ipfix_src_port, - enable=1) - - p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / - IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) / - UDP(sport=3001, dport=3002)) - self.pg0.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg1.assert_nothing_captured() - - # verify IPFIX logging - self.vapi.ipfix_flush() - sleep(1) - capture = self.pg2.get_capture(10) - 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_max_entries_per_user( - data, - nat44_config.max_translations_per_user, - self.pg0.remote_ip4n) - - sleep(6) - p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / - IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) / - UDP(sport=3001, dport=3002)) - self.pg0.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - self.pg1.get_capture(1) - - def test_syslog_sess(self): - """ Test syslog session creation and deletion """ - self.vapi.syslog_set_filter( - self.SYSLOG_SEVERITY.SYSLOG_API_SEVERITY_INFO) - self.vapi.syslog_set_sender(self.pg2.local_ip4n, self.pg2.remote_ip4n) - self.nat44_add_address(self.nat_addr) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg1.sw_if_index, - is_add=1) - - 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=self.tcp_port_in, dport=self.tcp_external_port)) - self.pg0.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg1.get_capture(1) - self.tcp_port_out = capture[0][TCP].sport - capture = self.pg2.get_capture(1) - self.verify_syslog_sess(capture[0][Raw].load) - - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - self.nat44_add_address(self.nat_addr, is_add=0) - capture = self.pg2.get_capture(1) - self.verify_syslog_sess(capture[0][Raw].load, False) - - def tearDown(self): - super(TestNAT44EndpointDependent, self).tearDown() - if not self.vpp_dead: - self.clear_nat44() - self.vapi.cli("clear logging") - - def show_commands_at_teardown(self): - self.logger.info(self.vapi.cli("show nat44 addresses")) - self.logger.info(self.vapi.cli("show nat44 interfaces")) - self.logger.info(self.vapi.cli("show nat44 static mappings")) - self.logger.info(self.vapi.cli("show nat44 interface address")) - self.logger.info(self.vapi.cli("show nat44 sessions detail")) - self.logger.info(self.vapi.cli("show nat44 hash tables detail")) - self.logger.info(self.vapi.cli("show nat timeouts")) - - -class TestNAT44Out2InDPO(MethodHolder): - """ NAT44 Test Cases using out2in DPO """ - - @classmethod - def setUpConstants(cls): - super(TestNAT44Out2InDPO, cls).setUpConstants() - cls.vpp_cmdline.extend(["nat", "{", "out2in dpo", "}"]) - - @classmethod - def setUpClass(cls): - super(TestNAT44Out2InDPO, cls).setUpClass() - cls.vapi.cli("set log class nat level debug") - - try: - cls.tcp_port_in = 6303 - cls.tcp_port_out = 6303 - cls.udp_port_in = 6304 - cls.udp_port_out = 6304 - cls.icmp_id_in = 6305 - cls.icmp_id_out = 6305 - cls.nat_addr = '10.0.0.3' - cls.dst_ip4 = '192.168.70.1' - - cls.create_pg_interfaces(range(2)) - - cls.pg0.admin_up() - cls.pg0.config_ip4() - cls.pg0.resolve_arp() - - cls.pg1.admin_up() - cls.pg1.config_ip6() - cls.pg1.resolve_ndp() - - r1 = VppIpRoute(cls, "::", 0, - [VppRoutePath(cls.pg1.remote_ip6, - cls.pg1.sw_if_index)], - register=False) - r1.add_vpp_config() - - except Exception: - super(TestNAT44Out2InDPO, cls).tearDownClass() - raise - - @classmethod - def tearDownClass(cls): - super(TestNAT44Out2InDPO, cls).tearDownClass() - - def configure_xlat(self): - self.dst_ip6_pfx = '1:2:3::' - self.dst_ip6_pfx_n = socket.inet_pton(socket.AF_INET6, - self.dst_ip6_pfx) - self.dst_ip6_pfx_len = 96 - self.src_ip6_pfx = '4:5:6::' - self.src_ip6_pfx_n = socket.inet_pton(socket.AF_INET6, - self.src_ip6_pfx) - self.src_ip6_pfx_len = 96 - self.vapi.map_add_domain(self.dst_ip6_pfx_n, self.dst_ip6_pfx_len, - self.src_ip6_pfx_n, self.src_ip6_pfx_len, - '\x00\x00\x00\x00', 0) - - @unittest.skip('Temporary disabled') - def test_464xlat_ce(self): - """ Test 464XLAT CE with NAT44 """ - - nat_config = self.vapi.nat_show_config() - self.assertEqual(1, nat_config.out2in_dpo) - - self.configure_xlat() - - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_add_del_address_range(first_ip_address=self.nat_addr_n, - last_ip_address=self.nat_addr_n, - vrf_id=0xFFFFFFFF, is_add=1) - - out_src_ip6 = self.compose_ip6(self.dst_ip4, self.dst_ip6_pfx, - self.dst_ip6_pfx_len) - out_dst_ip6 = self.compose_ip6(self.nat_addr, self.src_ip6_pfx, - self.src_ip6_pfx_len) - - try: - pkts = self.create_stream_in(self.pg0, self.pg1, self.dst_ip4) - 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_ip6(capture, nat_ip=out_dst_ip6, - dst_ip=out_src_ip6) - - pkts = self.create_stream_out_ip6(self.pg1, out_src_ip6, - out_dst_ip6) - self.pg1.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg0.get_capture(len(pkts)) - self.verify_capture_in(capture, self.pg0) - finally: - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags) - self.vapi.nat44_add_del_address_range( - first_ip_address=self.nat_addr_n, - last_ip_address=self.nat_addr_n, - vrf_id=0xFFFFFFFF) - - @unittest.skip('Temporary disabled') - def test_464xlat_ce_no_nat(self): - """ Test 464XLAT CE without NAT44 """ - - self.configure_xlat() - - out_src_ip6 = self.compose_ip6(self.dst_ip4, self.dst_ip6_pfx, - self.dst_ip6_pfx_len) - out_dst_ip6 = self.compose_ip6(self.pg0.remote_ip4, self.src_ip6_pfx, - self.src_ip6_pfx_len) - - pkts = self.create_stream_in(self.pg0, self.pg1, self.dst_ip4) - 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_ip6(capture, dst_ip=out_src_ip6, - nat_ip=out_dst_ip6, same_port=True) - - pkts = self.create_stream_out_ip6(self.pg1, out_src_ip6, out_dst_ip6) - self.pg1.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg0.get_capture(len(pkts)) - self.verify_capture_in(capture, self.pg0) - - -class TestDeterministicNAT(MethodHolder): - """ Deterministic NAT Test Cases """ - - @classmethod - def setUpConstants(cls): - super(TestDeterministicNAT, cls).setUpConstants() - cls.vpp_cmdline.extend(["nat", "{", "deterministic", "}"]) - - @classmethod - def setUpClass(cls): - super(TestDeterministicNAT, cls).setUpClass() - cls.vapi.cli("set log class nat level debug") - - try: - cls.tcp_port_in = 6303 - cls.tcp_external_port = 6303 - cls.udp_port_in = 6304 - cls.udp_external_port = 6304 - cls.icmp_id_in = 6305 - cls.nat_addr = '10.0.0.3' - - cls.create_pg_interfaces(range(3)) - cls.interfaces = list(cls.pg_interfaces) - - for i in cls.interfaces: - i.admin_up() - i.config_ip4() - i.resolve_arp() - - cls.pg0.generate_remote_hosts(2) - cls.pg0.configure_ipv4_neighbors() - - except Exception: - super(TestDeterministicNAT, cls).tearDownClass() - raise - - @classmethod - def tearDownClass(cls): - super(TestDeterministicNAT, cls).tearDownClass() - - def create_stream_in(self, in_if, out_if, ttl=64): - """ - Create packet stream for inside network - - :param in_if: Inside interface - :param out_if: Outside interface - :param ttl: TTL of generated packets - """ - pkts = [] - # TCP - p = (Ether(dst=in_if.local_mac, src=in_if.remote_mac) / - IP(src=in_if.remote_ip4, dst=out_if.remote_ip4, ttl=ttl) / - TCP(sport=self.tcp_port_in, dport=self.tcp_external_port)) - pkts.append(p) - - # UDP - p = (Ether(dst=in_if.local_mac, src=in_if.remote_mac) / - IP(src=in_if.remote_ip4, dst=out_if.remote_ip4, ttl=ttl) / - UDP(sport=self.udp_port_in, dport=self.udp_external_port)) - pkts.append(p) - - # ICMP - p = (Ether(dst=in_if.local_mac, src=in_if.remote_mac) / - IP(src=in_if.remote_ip4, dst=out_if.remote_ip4, ttl=ttl) / - ICMP(id=self.icmp_id_in, type='echo-request')) - pkts.append(p) - - return pkts - - def create_stream_out(self, out_if, dst_ip=None, ttl=64): - """ - Create packet stream for outside network - - :param out_if: Outside interface - :param dst_ip: Destination IP address (Default use global NAT address) - :param ttl: TTL of generated packets - """ - if dst_ip is None: - dst_ip = self.nat_addr - pkts = [] - # TCP - p = (Ether(dst=out_if.local_mac, src=out_if.remote_mac) / - IP(src=out_if.remote_ip4, dst=dst_ip, ttl=ttl) / - TCP(dport=self.tcp_port_out, sport=self.tcp_external_port)) - pkts.append(p) - - # UDP - p = (Ether(dst=out_if.local_mac, src=out_if.remote_mac) / - IP(src=out_if.remote_ip4, dst=dst_ip, ttl=ttl) / - UDP(dport=self.udp_port_out, sport=self.udp_external_port)) - pkts.append(p) - - # ICMP - p = (Ether(dst=out_if.local_mac, src=out_if.remote_mac) / - IP(src=out_if.remote_ip4, dst=dst_ip, ttl=ttl) / - ICMP(id=self.icmp_external_id, type='echo-reply')) - pkts.append(p) - - return pkts - - def verify_capture_out(self, capture, nat_ip=None): - """ - Verify captured packets on outside network - - :param capture: Captured packets - :param nat_ip: Translated IP address (Default use global NAT address) - :param same_port: Source port number is not translated (Default False) - """ - if nat_ip is None: - nat_ip = self.nat_addr - for packet in capture: - try: - self.assertEqual(packet[IP].src, nat_ip) - if packet.haslayer(TCP): - self.tcp_port_out = packet[TCP].sport - elif packet.haslayer(UDP): - self.udp_port_out = packet[UDP].sport - else: - self.icmp_external_id = packet[ICMP].id - except: - self.logger.error(ppp("Unexpected or invalid packet " - "(outside network):", packet)) - raise - - def test_deterministic_mode(self): - """ NAT plugin run deterministic mode """ - in_addr = '172.16.255.0' - out_addr = '172.17.255.50' - in_addr_t = '172.16.255.20' - in_plen = 24 - out_plen = 32 - - nat_config = self.vapi.nat_show_config() - self.assertEqual(1, nat_config.deterministic) - - self.vapi.nat_det_add_del_map(is_add=1, in_addr=in_addr, - in_plen=in_plen, out_addr=out_addr, - out_plen=out_plen) - - rep1 = self.vapi.nat_det_forward(in_addr_t) - self.assertEqual(str(rep1.out_addr), out_addr) - rep2 = self.vapi.nat_det_reverse(rep1.out_port_hi, out_addr) - - self.assertEqual(str(rep2.in_addr), in_addr_t) - - deterministic_mappings = self.vapi.nat_det_map_dump() - self.assertEqual(len(deterministic_mappings), 1) - dsm = deterministic_mappings[0] - self.assertEqual(in_addr, str(dsm.in_addr)) - self.assertEqual(in_plen, dsm.in_plen) - self.assertEqual(out_addr, str(dsm.out_addr)) - self.assertEqual(out_plen, dsm.out_plen) - - self.clear_nat_det() - deterministic_mappings = self.vapi.nat_det_map_dump() - self.assertEqual(len(deterministic_mappings), 0) - - def test_set_timeouts(self): - """ Set deterministic NAT timeouts """ - timeouts_before = self.vapi.nat_get_timeouts() - - self.vapi.nat_set_timeouts( - udp=timeouts_before.udp + 10, - tcp_established=timeouts_before.tcp_established + 10, - tcp_transitory=timeouts_before.tcp_transitory + 10, - icmp=timeouts_before.icmp + 10) - - timeouts_after = self.vapi.nat_get_timeouts() - - self.assertNotEqual(timeouts_before.udp, timeouts_after.udp) - self.assertNotEqual(timeouts_before.icmp, timeouts_after.icmp) - self.assertNotEqual(timeouts_before.tcp_established, - timeouts_after.tcp_established) - self.assertNotEqual(timeouts_before.tcp_transitory, - timeouts_after.tcp_transitory) - - def test_det_in(self): - """ Deterministic NAT translation test (TCP, UDP, ICMP) """ - - nat_ip = "10.0.0.10" - - self.vapi.nat_det_add_del_map(is_add=1, in_addr=self.pg0.remote_ip4n, - in_plen=32, - out_addr=socket.inet_aton(nat_ip), - out_plen=32) - - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg1.sw_if_index, - is_add=1) - - # in2out - 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, nat_ip) - - # out2in - pkts = self.create_stream_out(self.pg1, nat_ip) - self.pg1.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg0.get_capture(len(pkts)) - self.verify_capture_in(capture, self.pg0) - - # session dump test - sessions = self.vapi.nat_det_session_dump(self.pg0.remote_ip4n) - self.assertEqual(len(sessions), 3) - - # TCP session - s = sessions[0] - self.assertEqual(str(s.ext_addr), self.pg1.remote_ip4) - self.assertEqual(s.in_port, self.tcp_port_in) - self.assertEqual(s.out_port, self.tcp_port_out) - self.assertEqual(s.ext_port, self.tcp_external_port) - - # UDP session - s = sessions[1] - self.assertEqual(str(s.ext_addr), self.pg1.remote_ip4) - self.assertEqual(s.in_port, self.udp_port_in) - self.assertEqual(s.out_port, self.udp_port_out) - self.assertEqual(s.ext_port, self.udp_external_port) - - # ICMP session - s = sessions[2] - self.assertEqual(str(s.ext_addr), self.pg1.remote_ip4) - self.assertEqual(s.in_port, self.icmp_id_in) - self.assertEqual(s.out_port, self.icmp_external_id) - - def test_multiple_users(self): - """ Deterministic NAT multiple users """ - - nat_ip = "10.0.0.10" - port_in = 80 - external_port = 6303 - - host0 = self.pg0.remote_hosts[0] - host1 = self.pg0.remote_hosts[1] - - self.vapi.nat_det_add_del_map(is_add=1, in_addr=host0.ip4n, in_plen=24, - out_addr=socket.inet_aton(nat_ip), - out_plen=32) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg1.sw_if_index, - is_add=1) - - # host0 to out - p = (Ether(src=host0.mac, dst=self.pg0.local_mac) / - IP(src=host0.ip4, dst=self.pg1.remote_ip4) / - TCP(sport=port_in, dport=external_port)) - self.pg0.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg1.get_capture(1) - p = capture[0] - try: - ip = p[IP] - tcp = p[TCP] - self.assertEqual(ip.src, nat_ip) - self.assertEqual(ip.dst, self.pg1.remote_ip4) - self.assertEqual(tcp.dport, external_port) - port_out0 = tcp.sport - except: - self.logger.error(ppp("Unexpected or invalid packet:", p)) - raise - - # host1 to out - p = (Ether(src=host1.mac, dst=self.pg0.local_mac) / - IP(src=host1.ip4, dst=self.pg1.remote_ip4) / - TCP(sport=port_in, dport=external_port)) - self.pg0.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg1.get_capture(1) - p = capture[0] - try: - ip = p[IP] - tcp = p[TCP] - self.assertEqual(ip.src, nat_ip) - self.assertEqual(ip.dst, self.pg1.remote_ip4) - self.assertEqual(tcp.dport, external_port) - port_out1 = tcp.sport - except: - self.logger.error(ppp("Unexpected or invalid packet:", p)) - raise - - dms = self.vapi.nat_det_map_dump() - self.assertEqual(1, len(dms)) - self.assertEqual(2, dms[0].ses_num) - - # out to host0 - p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / - IP(src=self.pg1.remote_ip4, dst=nat_ip) / - TCP(sport=external_port, dport=port_out0)) - self.pg1.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg0.get_capture(1) - p = capture[0] - try: - ip = p[IP] - tcp = p[TCP] - self.assertEqual(ip.src, self.pg1.remote_ip4) - self.assertEqual(ip.dst, host0.ip4) - self.assertEqual(tcp.dport, port_in) - self.assertEqual(tcp.sport, external_port) - except: - self.logger.error(ppp("Unexpected or invalid packet:", p)) - raise - - # out to host1 - p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / - IP(src=self.pg1.remote_ip4, dst=nat_ip) / - TCP(sport=external_port, dport=port_out1)) - self.pg1.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg0.get_capture(1) - p = capture[0] - try: - ip = p[IP] - tcp = p[TCP] - self.assertEqual(ip.src, self.pg1.remote_ip4) - self.assertEqual(ip.dst, host1.ip4) - self.assertEqual(tcp.dport, port_in) - self.assertEqual(tcp.sport, external_port) - except: - self.logger.error(ppp("Unexpected or invalid packet", p)) - raise - - # session close api test - self.vapi.nat_det_close_session_out(socket.inet_aton(nat_ip), - port_out1, - self.pg1.remote_ip4n, - external_port) - dms = self.vapi.nat_det_map_dump() - self.assertEqual(dms[0].ses_num, 1) - - self.vapi.nat_det_close_session_in(host0.ip4n, - port_in, - self.pg1.remote_ip4n, - external_port) - dms = self.vapi.nat_det_map_dump() - self.assertEqual(dms[0].ses_num, 0) - - def test_tcp_session_close_detection_in(self): - """ Deterministic NAT TCP session close from inside network """ - self.vapi.nat_det_add_del_map(is_add=1, in_addr=self.pg0.remote_ip4n, - in_plen=32, - out_addr=socket.inet_aton(self.nat_addr), - out_plen=32) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg1.sw_if_index, - is_add=1) - - self.initiate_tcp_session(self.pg0, self.pg1) - - # close the session from inside - try: - # FIN packet in -> out - 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=self.tcp_port_in, dport=self.tcp_external_port, - flags="F")) - self.pg0.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - self.pg1.get_capture(1) - - pkts = [] - - # ACK packet out -> in - p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / - IP(src=self.pg1.remote_ip4, dst=self.nat_addr) / - TCP(sport=self.tcp_external_port, dport=self.tcp_port_out, - flags="A")) - pkts.append(p) - - # FIN packet out -> in - p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / - IP(src=self.pg1.remote_ip4, dst=self.nat_addr) / - TCP(sport=self.tcp_external_port, dport=self.tcp_port_out, - flags="F")) - pkts.append(p) - - self.pg1.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - self.pg0.get_capture(2) - - # ACK packet in -> out - 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=self.tcp_port_in, dport=self.tcp_external_port, - flags="A")) - self.pg0.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - self.pg1.get_capture(1) - - # Check if deterministic NAT44 closed the session - dms = self.vapi.nat_det_map_dump() - self.assertEqual(0, dms[0].ses_num) - except: - self.logger.error("TCP session termination failed") - raise - - def test_tcp_session_close_detection_out(self): - """ Deterministic NAT TCP session close from outside network """ - self.vapi.nat_det_add_del_map(is_add=1, in_addr=self.pg0.remote_ip4n, - in_plen=32, - out_addr=socket.inet_aton(self.nat_addr), - out_plen=32) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg1.sw_if_index, - is_add=1) - - self.initiate_tcp_session(self.pg0, self.pg1) - - # close the session from outside - try: - # FIN packet out -> in - p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / - IP(src=self.pg1.remote_ip4, dst=self.nat_addr) / - TCP(sport=self.tcp_external_port, dport=self.tcp_port_out, - flags="F")) - self.pg1.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - self.pg0.get_capture(1) - - pkts = [] - - # ACK packet in -> out - 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=self.tcp_port_in, dport=self.tcp_external_port, - flags="A")) - pkts.append(p) - - # ACK packet in -> out - 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=self.tcp_port_in, dport=self.tcp_external_port, - flags="F")) - pkts.append(p) - - self.pg0.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - self.pg1.get_capture(2) - - # ACK packet out -> in - p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / - IP(src=self.pg1.remote_ip4, dst=self.nat_addr) / - TCP(sport=self.tcp_external_port, dport=self.tcp_port_out, - flags="A")) - self.pg1.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - self.pg0.get_capture(1) - - # Check if deterministic NAT44 closed the session - dms = self.vapi.nat_det_map_dump() - self.assertEqual(0, dms[0].ses_num) - except: - self.logger.error("TCP session termination failed") - raise - - @unittest.skipUnless(running_extended_tests, "part of extended tests") - def test_session_timeout(self): - """ Deterministic NAT session timeouts """ - self.vapi.nat_det_add_del_map(is_add=1, in_addr=self.pg0.remote_ip4n, - in_plen=32, - out_addr=socket.inet_aton(self.nat_addr), - out_plen=32) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg1.sw_if_index, - is_add=1) - - self.initiate_tcp_session(self.pg0, self.pg1) - self.vapi.nat_set_timeouts(udp=5, tcp_established=5, tcp_transitory=5, - icmp=5) - 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)) - sleep(15) - - dms = self.vapi.nat_det_map_dump() - self.assertEqual(0, dms[0].ses_num) - - @unittest.skipUnless(running_extended_tests, "part of extended tests") - def test_session_limit_per_user(self): - """ Deterministic NAT maximum sessions per user limit """ - self.vapi.nat_det_add_del_map(is_add=1, in_addr=self.pg0.remote_ip4n, - in_plen=32, - out_addr=socket.inet_aton(self.nat_addr), - out_plen=32) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=flags, is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg1.sw_if_index, - is_add=1) - self.vapi.set_ipfix_exporter(collector_address=self.pg2.remote_ip4n, - src_address=self.pg2.local_ip4n, - path_mtu=512, - template_interval=10) - self.vapi.nat_ipfix_enable_disable(domain_id=1, src_port=4739, - enable=1) - - pkts = [] - for port in range(1025, 2025): - p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / - IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) / - UDP(sport=port, dport=port)) - pkts.append(p) - - self.pg0.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg1.get_capture(len(pkts)) - - p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / - IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) / - UDP(sport=3001, dport=3002)) - self.pg0.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg1.assert_nothing_captured() - - # verify ICMP error packet - capture = self.pg0.get_capture(1) - p = capture[0] - self.assertTrue(p.haslayer(ICMP)) - icmp = p[ICMP] - self.assertEqual(icmp.type, 3) - self.assertEqual(icmp.code, 1) - self.assertTrue(icmp.haslayer(IPerror)) - inner_ip = icmp[IPerror] - self.assertEqual(inner_ip[UDPerror].sport, 3001) - self.assertEqual(inner_ip[UDPerror].dport, 3002) - - dms = self.vapi.nat_det_map_dump() - - self.assertEqual(1000, dms[0].ses_num) - - # verify IPFIX logging - self.vapi.ipfix_flush() - sleep(1) - capture = self.pg2.get_capture(2) - 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_max_entries_per_user(data, - 1000, - self.pg0.remote_ip4n) - - def clear_nat_det(self): - """ - Clear deterministic NAT configuration. - """ - self.vapi.nat_ipfix_enable_disable(domain_id=1, src_port=4739, - enable=0) - self.vapi.nat_set_timeouts(udp=300, tcp_established=7440, - tcp_transitory=240, icmp=60) - deterministic_mappings = self.vapi.nat_det_map_dump() - for dsm in deterministic_mappings: - self.vapi.nat_det_add_del_map(is_add=0, in_addr=dsm.in_addr, - in_plen=dsm.in_plen, - out_addr=dsm.out_addr, - out_plen=dsm.out_plen) - - interfaces = self.vapi.nat44_interface_dump() - for intf in interfaces: - self.vapi.nat44_interface_add_del_feature( - sw_if_index=intf.sw_if_index, - flags=intf.flags) - - def tearDown(self): - super(TestDeterministicNAT, self).tearDown() - if not self.vpp_dead: - self.clear_nat_det() - - def show_commands_at_teardown(self): - self.logger.info(self.vapi.cli("show nat44 interfaces")) - self.logger.info(self.vapi.cli("show nat timeouts")) - self.logger.info( - self.vapi.cli("show nat44 deterministic mappings")) - self.logger.info( - self.vapi.cli("show nat44 deterministic sessions")) - - -class TestNAT64(MethodHolder): - """ NAT64 Test Cases """ - - @classmethod - def setUpConstants(cls): - super(TestNAT64, cls).setUpConstants() - cls.vpp_cmdline.extend(["nat", "{", "nat64 bib hash buckets 128", - "nat64 st hash buckets 256", "}"]) - - @classmethod - def setUpClass(cls): - super(TestNAT64, cls).setUpClass() - - try: - cls.tcp_port_in = 6303 - cls.tcp_port_out = 6303 - cls.udp_port_in = 6304 - cls.udp_port_out = 6304 - cls.icmp_id_in = 6305 - cls.icmp_id_out = 6305 - cls.tcp_external_port = 80 - cls.nat_addr = '10.0.0.3' - cls.nat_addr_n = socket.inet_pton(socket.AF_INET, cls.nat_addr) - cls.vrf1_id = 10 - cls.vrf1_nat_addr = '10.0.10.3' - cls.ipfix_src_port = 4739 - cls.ipfix_domain_id = 1 - - cls.create_pg_interfaces(range(6)) - cls.ip6_interfaces = list(cls.pg_interfaces[0:1]) - cls.ip6_interfaces.append(cls.pg_interfaces[2]) - cls.ip4_interfaces = list(cls.pg_interfaces[1:2]) - - cls.vapi.ip_table_add_del(is_ipv6=1, is_add=1, - table_id=cls.vrf1_id) - - cls.pg_interfaces[2].set_table_ip6(cls.vrf1_id) - - cls.pg0.generate_remote_hosts(2) - - for i in cls.ip6_interfaces: - i.admin_up() - i.config_ip6() - i.configure_ipv6_neighbors() - - for i in cls.ip4_interfaces: - i.admin_up() - i.config_ip4() - i.resolve_arp() - - cls.pg3.admin_up() - cls.pg3.config_ip4() - cls.pg3.resolve_arp() - cls.pg3.config_ip6() - cls.pg3.configure_ipv6_neighbors() - - cls.pg5.admin_up() - cls.pg5.config_ip6() - - except Exception: - super(TestNAT64, cls).tearDownClass() - raise - - @classmethod - def tearDownClass(cls): - super(TestNAT64, cls).tearDownClass() - - def test_nat64_inside_interface_handles_neighbor_advertisement(self): - """ NAT64 inside interface handles Neighbor Advertisement """ - - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat64_add_del_interface(is_add=1, flags=flags, - sw_if_index=self.pg5.sw_if_index) - - # Try to send ping - ping = (Ether(dst=self.pg5.local_mac, src=self.pg5.remote_mac) / - IPv6(src=self.pg5.remote_ip6, dst=self.pg5.local_ip6) / - ICMPv6EchoRequest()) - pkts = [ping] - self.pg5.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - - # Wait for Neighbor Solicitation - capture = self.pg5.get_capture(len(pkts)) - packet = capture[0] - try: - self.assertEqual(packet[IPv6].src, self.pg5.local_ip6) - self.assertEqual(packet.haslayer(ICMPv6ND_NS), 1) - tgt = packet[ICMPv6ND_NS].tgt - except: - self.logger.error(ppp("Unexpected or invalid packet:", packet)) - raise - - # Send Neighbor Advertisement - p = (Ether(dst=self.pg5.local_mac, src=self.pg5.remote_mac) / - IPv6(src=self.pg5.remote_ip6, dst=self.pg5.local_ip6) / - ICMPv6ND_NA(tgt=tgt) / - ICMPv6NDOptDstLLAddr(lladdr=self.pg5.remote_mac)) - pkts = [p] - self.pg5.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - - # Try to send ping again - pkts = [ping] - self.pg5.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - - # Wait for ping reply - capture = self.pg5.get_capture(len(pkts)) - packet = capture[0] - try: - self.assertEqual(packet[IPv6].src, self.pg5.local_ip6) - self.assertEqual(packet[IPv6].dst, self.pg5.remote_ip6) - self.assertEqual(packet.haslayer(ICMPv6EchoReply), 1) - except: - self.logger.error(ppp("Unexpected or invalid packet:", packet)) - raise - - def test_pool(self): - """ Add/delete address to NAT64 pool """ - nat_addr = '1.2.3.4' - - self.vapi.nat64_add_del_pool_addr_range(start_addr=nat_addr, - end_addr=nat_addr, - vrf_id=0xFFFFFFFF, is_add=1) - - addresses = self.vapi.nat64_pool_addr_dump() - self.assertEqual(len(addresses), 1) - self.assertEqual(str(addresses[0].address), nat_addr) - - self.vapi.nat64_add_del_pool_addr_range(start_addr=nat_addr, - end_addr=nat_addr, - vrf_id=0xFFFFFFFF, is_add=0) - - addresses = self.vapi.nat64_pool_addr_dump() - self.assertEqual(len(addresses), 0) - - def test_interface(self): - """ Enable/disable NAT64 feature on the interface """ - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat64_add_del_interface(is_add=1, flags=flags, - sw_if_index=self.pg0.sw_if_index) - self.vapi.nat64_add_del_interface(is_add=1, flags=0, - sw_if_index=self.pg1.sw_if_index) - - interfaces = self.vapi.nat64_interface_dump() - self.assertEqual(len(interfaces), 2) - pg0_found = False - pg1_found = False - for intf in interfaces: - if intf.sw_if_index == self.pg0.sw_if_index: - self.assertEqual(intf.flags, self.config_flags.NAT_IS_INSIDE) - pg0_found = True - elif intf.sw_if_index == self.pg1.sw_if_index: - self.assertEqual(intf.flags, self.config_flags.NAT_IS_OUTSIDE) - pg1_found = True - self.assertTrue(pg0_found) - self.assertTrue(pg1_found) - - features = self.vapi.cli("show interface features pg0") - self.assertIn('nat64-in2out', features) - features = self.vapi.cli("show interface features pg1") - self.assertIn('nat64-out2in', features) - - self.vapi.nat64_add_del_interface(is_add=0, flags=flags, - sw_if_index=self.pg0.sw_if_index) - self.vapi.nat64_add_del_interface(is_add=0, flags=flags, - sw_if_index=self.pg1.sw_if_index) - - interfaces = self.vapi.nat64_interface_dump() - self.assertEqual(len(interfaces), 0) - - def test_static_bib(self): - """ Add/delete static BIB entry """ - in_addr = '2001:db8:85a3::8a2e:370:7334' - out_addr = '10.1.1.3' - in_port = 1234 - out_port = 5678 - proto = IP_PROTOS.tcp - - self.vapi.nat64_add_del_static_bib(i_addr=in_addr, o_addr=out_addr, - i_port=in_port, o_port=out_port, - proto=proto, vrf_id=0, is_add=1) - bib = self.vapi.nat64_bib_dump(proto=IP_PROTOS.tcp) - static_bib_num = 0 - for bibe in bib: - if bibe.flags & self.config_flags.NAT_IS_STATIC: - static_bib_num += 1 - self.assertEqual(str(bibe.i_addr), in_addr) - self.assertEqual(str(bibe.o_addr), out_addr) - self.assertEqual(bibe.i_port, in_port) - self.assertEqual(bibe.o_port, out_port) - self.assertEqual(static_bib_num, 1) - bibs = self.statistics.get_counter('/nat64/total-bibs') - self.assertEqual(bibs[0][0], 1) - - self.vapi.nat64_add_del_static_bib(i_addr=in_addr, o_addr=out_addr, - i_port=in_port, o_port=out_port, - proto=proto, vrf_id=0, is_add=0) - bib = self.vapi.nat64_bib_dump(proto=IP_PROTOS.tcp) - static_bib_num = 0 - for bibe in bib: - if bibe.flags & self.config_flags.NAT_IS_STATIC: - static_bib_num += 1 - self.assertEqual(static_bib_num, 0) - bibs = self.statistics.get_counter('/nat64/total-bibs') - self.assertEqual(bibs[0][0], 0) - - def test_set_timeouts(self): - """ Set NAT64 timeouts """ - # verify default values - timeouts = self.vapi.nat_get_timeouts() - self.assertEqual(timeouts.udp, 300) - self.assertEqual(timeouts.icmp, 60) - self.assertEqual(timeouts.tcp_transitory, 240) - self.assertEqual(timeouts.tcp_established, 7440) - - # set and verify custom values - self.vapi.nat_set_timeouts(udp=200, tcp_established=7450, - tcp_transitory=250, icmp=30) - timeouts = self.vapi.nat_get_timeouts() - self.assertEqual(timeouts.udp, 200) - self.assertEqual(timeouts.icmp, 30) - self.assertEqual(timeouts.tcp_transitory, 250) - self.assertEqual(timeouts.tcp_established, 7450) - - def test_dynamic(self): - """ NAT64 dynamic translation test """ - self.tcp_port_in = 6303 - self.udp_port_in = 6304 - self.icmp_id_in = 6305 - - ses_num_start = self.nat64_get_ses_num() - - self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr, - end_addr=self.nat_addr, - vrf_id=0xFFFFFFFF, - is_add=1) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat64_add_del_interface(is_add=1, flags=flags, - sw_if_index=self.pg0.sw_if_index) - self.vapi.nat64_add_del_interface(is_add=1, flags=0, - sw_if_index=self.pg1.sw_if_index) - - # in2out - tcpn = self.statistics.get_err_counter('/err/nat64-in2out/TCP packets') - udpn = self.statistics.get_err_counter('/err/nat64-in2out/UDP packets') - icmpn = self.statistics.get_err_counter( - '/err/nat64-in2out/ICMP packets') - totaln = self.statistics.get_err_counter( - '/err/nat64-in2out/good in2out packets processed') - - pkts = self.create_stream_in_ip6(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, nat_ip=self.nat_addr, - dst_ip=self.pg1.remote_ip4) - - err = self.statistics.get_err_counter('/err/nat64-in2out/TCP packets') - self.assertEqual(err - tcpn, 1) - err = self.statistics.get_err_counter('/err/nat64-in2out/UDP packets') - self.assertEqual(err - udpn, 1) - err = self.statistics.get_err_counter('/err/nat64-in2out/ICMP packets') - self.assertEqual(err - icmpn, 1) - err = self.statistics.get_err_counter( - '/err/nat64-in2out/good in2out packets processed') - self.assertEqual(err - totaln, 3) - - # out2in - tcpn = self.statistics.get_err_counter('/err/nat64-out2in/TCP packets') - udpn = self.statistics.get_err_counter('/err/nat64-out2in/UDP packets') - icmpn = self.statistics.get_err_counter( - '/err/nat64-out2in/ICMP packets') - totaln = self.statistics.get_err_counter( - '/err/nat64-out2in/good out2in packets processed') - - pkts = self.create_stream_out(self.pg1, dst_ip=self.nat_addr) - self.pg1.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg0.get_capture(len(pkts)) - ip = IPv6(src=''.join(['64:ff9b::', self.pg1.remote_ip4])) - self.verify_capture_in_ip6(capture, ip[IPv6].src, self.pg0.remote_ip6) - - err = self.statistics.get_err_counter('/err/nat64-out2in/TCP packets') - self.assertEqual(err - tcpn, 1) - err = self.statistics.get_err_counter('/err/nat64-out2in/UDP packets') - self.assertEqual(err - udpn, 1) - err = self.statistics.get_err_counter('/err/nat64-out2in/ICMP packets') - self.assertEqual(err - icmpn, 1) - err = self.statistics.get_err_counter( - '/err/nat64-out2in/good out2in packets processed') - self.assertEqual(err - totaln, 3) - - bibs = self.statistics.get_counter('/nat64/total-bibs') - self.assertEqual(bibs[0][0], 3) - sessions = self.statistics.get_counter('/nat64/total-sessions') - self.assertEqual(sessions[0][0], 3) - - # in2out - pkts = self.create_stream_in_ip6(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, nat_ip=self.nat_addr, - dst_ip=self.pg1.remote_ip4) - - # out2in - pkts = self.create_stream_out(self.pg1, dst_ip=self.nat_addr) - self.pg1.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg0.get_capture(len(pkts)) - self.verify_capture_in_ip6(capture, ip[IPv6].src, self.pg0.remote_ip6) - - ses_num_end = self.nat64_get_ses_num() - - self.assertEqual(ses_num_end - ses_num_start, 3) - - # tenant with specific VRF - self.vapi.nat64_add_del_pool_addr_range(start_addr=self.vrf1_nat_addr, - end_addr=self.vrf1_nat_addr, - vrf_id=self.vrf1_id, is_add=1) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat64_add_del_interface(is_add=1, flags=flags, - sw_if_index=self.pg2.sw_if_index) - - pkts = self.create_stream_in_ip6(self.pg2, self.pg1) - self.pg2.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, nat_ip=self.vrf1_nat_addr, - dst_ip=self.pg1.remote_ip4) - - pkts = self.create_stream_out(self.pg1, dst_ip=self.vrf1_nat_addr) - self.pg1.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg2.get_capture(len(pkts)) - self.verify_capture_in_ip6(capture, ip[IPv6].src, self.pg2.remote_ip6) - - def test_static(self): - """ NAT64 static translation test """ - self.tcp_port_in = 60303 - self.udp_port_in = 60304 - self.icmp_id_in = 60305 - self.tcp_port_out = 60303 - self.udp_port_out = 60304 - self.icmp_id_out = 60305 - - ses_num_start = self.nat64_get_ses_num() - - self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr, - end_addr=self.nat_addr, - vrf_id=0xFFFFFFFF, - is_add=1) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat64_add_del_interface(is_add=1, flags=flags, - sw_if_index=self.pg0.sw_if_index) - self.vapi.nat64_add_del_interface(is_add=1, flags=0, - sw_if_index=self.pg1.sw_if_index) - - self.vapi.nat64_add_del_static_bib(i_addr=self.pg0.remote_ip6n, - o_addr=self.nat_addr, - i_port=self.tcp_port_in, - o_port=self.tcp_port_out, - proto=IP_PROTOS.tcp, vrf_id=0, - is_add=1) - self.vapi.nat64_add_del_static_bib(i_addr=self.pg0.remote_ip6n, - o_addr=self.nat_addr, - i_port=self.udp_port_in, - o_port=self.udp_port_out, - proto=IP_PROTOS.udp, vrf_id=0, - is_add=1) - self.vapi.nat64_add_del_static_bib(i_addr=self.pg0.remote_ip6n, - o_addr=self.nat_addr, - i_port=self.icmp_id_in, - o_port=self.icmp_id_out, - proto=IP_PROTOS.icmp, vrf_id=0, - is_add=1) - - # in2out - pkts = self.create_stream_in_ip6(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, nat_ip=self.nat_addr, - dst_ip=self.pg1.remote_ip4, same_port=True) - - # out2in - pkts = self.create_stream_out(self.pg1, dst_ip=self.nat_addr) - self.pg1.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg0.get_capture(len(pkts)) - ip = IPv6(src=''.join(['64:ff9b::', self.pg1.remote_ip4])) - self.verify_capture_in_ip6(capture, ip[IPv6].src, self.pg0.remote_ip6) - - ses_num_end = self.nat64_get_ses_num() - - self.assertEqual(ses_num_end - ses_num_start, 3) - - @unittest.skipUnless(running_extended_tests, "part of extended tests") - def test_session_timeout(self): - """ NAT64 session timeout """ - self.icmp_id_in = 1234 - self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr, - end_addr=self.nat_addr, - vrf_id=0xFFFFFFFF, - is_add=1) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat64_add_del_interface(is_add=1, flags=flags, - sw_if_index=self.pg0.sw_if_index) - self.vapi.nat64_add_del_interface(is_add=1, flags=0, - sw_if_index=self.pg1.sw_if_index) - self.vapi.nat_set_timeouts(udp=300, tcp_established=5, - tcp_transitory=5, - icmp=5) - - pkts = self.create_stream_in_ip6(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)) - - ses_num_before_timeout = self.nat64_get_ses_num() - - sleep(15) - - # ICMP and TCP session after timeout - ses_num_after_timeout = self.nat64_get_ses_num() - self.assertEqual(ses_num_before_timeout - ses_num_after_timeout, 2) - - def test_icmp_error(self): - """ NAT64 ICMP Error message translation """ - self.tcp_port_in = 6303 - self.udp_port_in = 6304 - self.icmp_id_in = 6305 - - self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr, - end_addr=self.nat_addr, - vrf_id=0xFFFFFFFF, - is_add=1) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat64_add_del_interface(is_add=1, flags=flags, - sw_if_index=self.pg0.sw_if_index) - self.vapi.nat64_add_del_interface(is_add=1, flags=0, - sw_if_index=self.pg1.sw_if_index) - - # send some packets to create sessions - pkts = self.create_stream_in_ip6(self.pg0, self.pg1) - self.pg0.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture_ip4 = self.pg1.get_capture(len(pkts)) - self.verify_capture_out(capture_ip4, - nat_ip=self.nat_addr, - dst_ip=self.pg1.remote_ip4) - - pkts = self.create_stream_out(self.pg1, dst_ip=self.nat_addr) - self.pg1.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture_ip6 = self.pg0.get_capture(len(pkts)) - ip = IPv6(src=''.join(['64:ff9b::', self.pg1.remote_ip4])) - self.verify_capture_in_ip6(capture_ip6, ip[IPv6].src, - self.pg0.remote_ip6) - - # in2out - pkts = [Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IPv6(src=self.pg0.remote_ip6, dst=ip[IPv6].src) / - ICMPv6DestUnreach(code=1) / - packet[IPv6] for packet in capture_ip6] - self.pg0.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg1.get_capture(len(pkts)) - for packet in capture: - try: - self.assertEqual(packet[IP].src, self.nat_addr) - self.assertEqual(packet[IP].dst, self.pg1.remote_ip4) - self.assertEqual(packet[ICMP].type, 3) - self.assertEqual(packet[ICMP].code, 13) - inner = packet[IPerror] - self.assertEqual(inner.src, self.pg1.remote_ip4) - self.assertEqual(inner.dst, self.nat_addr) - self.assert_packet_checksums_valid(packet) - if inner.haslayer(TCPerror): - self.assertEqual(inner[TCPerror].dport, self.tcp_port_out) - elif inner.haslayer(UDPerror): - self.assertEqual(inner[UDPerror].dport, self.udp_port_out) - else: - self.assertEqual(inner[ICMPerror].id, self.icmp_id_out) - except: - self.logger.error(ppp("Unexpected or invalid packet:", packet)) - raise - - # out2in - pkts = [Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / - IP(src=self.pg1.remote_ip4, dst=self.nat_addr) / - ICMP(type=3, code=13) / - packet[IP] for packet in capture_ip4] - self.pg1.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg0.get_capture(len(pkts)) - for packet in capture: - try: - self.assertEqual(packet[IPv6].src, ip.src) - self.assertEqual(packet[IPv6].dst, self.pg0.remote_ip6) - icmp = packet[ICMPv6DestUnreach] - self.assertEqual(icmp.code, 1) - inner = icmp[IPerror6] - self.assertEqual(inner.src, self.pg0.remote_ip6) - self.assertEqual(inner.dst, ip.src) - self.assert_icmpv6_checksum_valid(packet) - if inner.haslayer(TCPerror): - self.assertEqual(inner[TCPerror].sport, self.tcp_port_in) - elif inner.haslayer(UDPerror): - self.assertEqual(inner[UDPerror].sport, self.udp_port_in) - else: - self.assertEqual(inner[ICMPv6EchoRequest].id, - self.icmp_id_in) - except: - self.logger.error(ppp("Unexpected or invalid packet:", packet)) - raise - - def test_hairpinning(self): - """ NAT64 hairpinning """ - - client = self.pg0.remote_hosts[0] - server = self.pg0.remote_hosts[1] - server_tcp_in_port = 22 - server_tcp_out_port = 4022 - server_udp_in_port = 23 - server_udp_out_port = 4023 - client_tcp_in_port = 1234 - client_udp_in_port = 1235 - client_tcp_out_port = 0 - client_udp_out_port = 0 - ip = IPv6(src=''.join(['64:ff9b::', self.nat_addr])) - nat_addr_ip6 = ip.src - - self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr, - end_addr=self.nat_addr, - vrf_id=0xFFFFFFFF, - is_add=1) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat64_add_del_interface(is_add=1, flags=flags, - sw_if_index=self.pg0.sw_if_index) - self.vapi.nat64_add_del_interface(is_add=1, flags=0, - sw_if_index=self.pg1.sw_if_index) - - self.vapi.nat64_add_del_static_bib(i_addr=server.ip6n, - o_addr=self.nat_addr, - i_port=server_tcp_in_port, - o_port=server_tcp_out_port, - proto=IP_PROTOS.tcp, vrf_id=0, - is_add=1) - self.vapi.nat64_add_del_static_bib(i_addr=server.ip6n, - o_addr=self.nat_addr, - i_port=server_udp_in_port, - o_port=server_udp_out_port, - proto=IP_PROTOS.udp, vrf_id=0, - is_add=1) - - # client to server - pkts = [] - p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IPv6(src=client.ip6, dst=nat_addr_ip6) / - TCP(sport=client_tcp_in_port, dport=server_tcp_out_port)) - pkts.append(p) - p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IPv6(src=client.ip6, dst=nat_addr_ip6) / - UDP(sport=client_udp_in_port, dport=server_udp_out_port)) - pkts.append(p) - self.pg0.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg0.get_capture(len(pkts)) - for packet in capture: - try: - self.assertEqual(packet[IPv6].src, nat_addr_ip6) - self.assertEqual(packet[IPv6].dst, server.ip6) - self.assert_packet_checksums_valid(packet) - if packet.haslayer(TCP): - self.assertNotEqual(packet[TCP].sport, client_tcp_in_port) - self.assertEqual(packet[TCP].dport, server_tcp_in_port) - client_tcp_out_port = packet[TCP].sport - else: - self.assertNotEqual(packet[UDP].sport, client_udp_in_port) - self.assertEqual(packet[UDP].dport, server_udp_in_port) - client_udp_out_port = packet[UDP].sport - except: - self.logger.error(ppp("Unexpected or invalid packet:", packet)) - raise - - # server to client - pkts = [] - p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IPv6(src=server.ip6, dst=nat_addr_ip6) / - TCP(sport=server_tcp_in_port, dport=client_tcp_out_port)) - pkts.append(p) - p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IPv6(src=server.ip6, dst=nat_addr_ip6) / - UDP(sport=server_udp_in_port, dport=client_udp_out_port)) - pkts.append(p) - self.pg0.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg0.get_capture(len(pkts)) - for packet in capture: - try: - self.assertEqual(packet[IPv6].src, nat_addr_ip6) - self.assertEqual(packet[IPv6].dst, client.ip6) - self.assert_packet_checksums_valid(packet) - if packet.haslayer(TCP): - self.assertEqual(packet[TCP].sport, server_tcp_out_port) - self.assertEqual(packet[TCP].dport, client_tcp_in_port) - else: - self.assertEqual(packet[UDP].sport, server_udp_out_port) - self.assertEqual(packet[UDP].dport, client_udp_in_port) - except: - self.logger.error(ppp("Unexpected or invalid packet:", packet)) - raise - - # ICMP error - pkts = [] - pkts = [Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IPv6(src=client.ip6, dst=nat_addr_ip6) / - ICMPv6DestUnreach(code=1) / - packet[IPv6] for packet in capture] - self.pg0.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg0.get_capture(len(pkts)) - for packet in capture: - try: - self.assertEqual(packet[IPv6].src, nat_addr_ip6) - self.assertEqual(packet[IPv6].dst, server.ip6) - icmp = packet[ICMPv6DestUnreach] - self.assertEqual(icmp.code, 1) - inner = icmp[IPerror6] - self.assertEqual(inner.src, server.ip6) - self.assertEqual(inner.dst, nat_addr_ip6) - self.assert_packet_checksums_valid(packet) - if inner.haslayer(TCPerror): - self.assertEqual(inner[TCPerror].sport, server_tcp_in_port) - self.assertEqual(inner[TCPerror].dport, - client_tcp_out_port) - else: - self.assertEqual(inner[UDPerror].sport, server_udp_in_port) - self.assertEqual(inner[UDPerror].dport, - client_udp_out_port) - except: - self.logger.error(ppp("Unexpected or invalid packet:", packet)) - raise - - def test_prefix(self): - """ NAT64 Network-Specific Prefix """ - - self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr, - end_addr=self.nat_addr, - vrf_id=0xFFFFFFFF, - is_add=1) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat64_add_del_interface(is_add=1, flags=flags, - sw_if_index=self.pg0.sw_if_index) - self.vapi.nat64_add_del_interface(is_add=1, flags=0, - sw_if_index=self.pg1.sw_if_index) - self.vapi.nat64_add_del_pool_addr_range(start_addr=self.vrf1_nat_addr, - end_addr=self.vrf1_nat_addr, - vrf_id=self.vrf1_id, is_add=1) - self.vapi.nat64_add_del_interface(is_add=1, flags=flags, - sw_if_index=self.pg2.sw_if_index) - - # Add global prefix - global_pref64 = "2001:db8::" - global_pref64_len = 32 - global_pref64_str = "{}/{}".format(global_pref64, global_pref64_len) - self.vapi.nat64_add_del_prefix(prefix=global_pref64_str, vrf_id=0, - is_add=1) - - prefix = self.vapi.nat64_prefix_dump() - self.assertEqual(len(prefix), 1) - self.assertEqual(prefix[0].prefix, - IPv6Network(unicode(global_pref64_str))) - self.assertEqual(prefix[0].vrf_id, 0) - - # Add tenant specific prefix - vrf1_pref64 = "2001:db8:122:300::" - vrf1_pref64_len = 56 - vrf1_pref64_str = "{}/{}".format(vrf1_pref64, vrf1_pref64_len) - self.vapi.nat64_add_del_prefix(prefix=vrf1_pref64_str, - vrf_id=self.vrf1_id, is_add=1) - - prefix = self.vapi.nat64_prefix_dump() - self.assertEqual(len(prefix), 2) - - # Global prefix - pkts = self.create_stream_in_ip6(self.pg0, - self.pg1, - pref=global_pref64, - plen=global_pref64_len) - 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, nat_ip=self.nat_addr, - dst_ip=self.pg1.remote_ip4) - - pkts = self.create_stream_out(self.pg1, dst_ip=self.nat_addr) - self.pg1.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg0.get_capture(len(pkts)) - dst_ip = self.compose_ip6(self.pg1.remote_ip4, - global_pref64, - global_pref64_len) - self.verify_capture_in_ip6(capture, dst_ip, self.pg0.remote_ip6) - - # Tenant specific prefix - pkts = self.create_stream_in_ip6(self.pg2, - self.pg1, - pref=vrf1_pref64, - plen=vrf1_pref64_len) - self.pg2.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, nat_ip=self.vrf1_nat_addr, - dst_ip=self.pg1.remote_ip4) - - pkts = self.create_stream_out(self.pg1, dst_ip=self.vrf1_nat_addr) - self.pg1.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg2.get_capture(len(pkts)) - dst_ip = self.compose_ip6(self.pg1.remote_ip4, - vrf1_pref64, - vrf1_pref64_len) - self.verify_capture_in_ip6(capture, dst_ip, self.pg2.remote_ip6) - - def test_unknown_proto(self): - """ NAT64 translate packet with unknown protocol """ - - self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr, - end_addr=self.nat_addr, - vrf_id=0xFFFFFFFF, - is_add=1) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat64_add_del_interface(is_add=1, flags=flags, - sw_if_index=self.pg0.sw_if_index) - self.vapi.nat64_add_del_interface(is_add=1, flags=0, - sw_if_index=self.pg1.sw_if_index) - remote_ip6 = self.compose_ip6(self.pg1.remote_ip4, '64:ff9b::', 96) - - # in2out - p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IPv6(src=self.pg0.remote_ip6, dst=remote_ip6) / - TCP(sport=self.tcp_port_in, dport=20)) - self.pg0.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - p = self.pg1.get_capture(1) - - p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IPv6(src=self.pg0.remote_ip6, dst=remote_ip6, nh=47) / - GRE() / - IP(src=self.pg2.local_ip4, dst=self.pg2.remote_ip4) / - TCP(sport=1234, dport=1234)) - self.pg0.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - p = self.pg1.get_capture(1) - packet = p[0] - try: - self.assertEqual(packet[IP].src, self.nat_addr) - self.assertEqual(packet[IP].dst, self.pg1.remote_ip4) - self.assertEqual(packet.haslayer(GRE), 1) - self.assert_packet_checksums_valid(packet) - except: - self.logger.error(ppp("Unexpected or invalid packet:", packet)) - raise - - # out2in - p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / - IP(src=self.pg1.remote_ip4, dst=self.nat_addr) / - GRE() / - IP(src=self.pg2.remote_ip4, dst=self.pg2.local_ip4) / - TCP(sport=1234, dport=1234)) - self.pg1.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - p = self.pg0.get_capture(1) - packet = p[0] - try: - self.assertEqual(packet[IPv6].src, remote_ip6) - self.assertEqual(packet[IPv6].dst, self.pg0.remote_ip6) - self.assertEqual(packet[IPv6].nh, 47) - except: - self.logger.error(ppp("Unexpected or invalid packet:", packet)) - raise - - def test_hairpinning_unknown_proto(self): - """ NAT64 translate packet with unknown protocol - hairpinning """ - - client = self.pg0.remote_hosts[0] - server = self.pg0.remote_hosts[1] - server_tcp_in_port = 22 - server_tcp_out_port = 4022 - client_tcp_in_port = 1234 - client_tcp_out_port = 1235 - server_nat_ip = "10.0.0.100" - client_nat_ip = "10.0.0.110" - server_nat_ip6 = self.compose_ip6(server_nat_ip, '64:ff9b::', 96) - client_nat_ip6 = self.compose_ip6(client_nat_ip, '64:ff9b::', 96) - - self.vapi.nat64_add_del_pool_addr_range(start_addr=server_nat_ip, - end_addr=client_nat_ip, - vrf_id=0xFFFFFFFF, - is_add=1) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat64_add_del_interface(is_add=1, flags=flags, - sw_if_index=self.pg0.sw_if_index) - self.vapi.nat64_add_del_interface(is_add=1, flags=0, - sw_if_index=self.pg1.sw_if_index) - - self.vapi.nat64_add_del_static_bib(i_addr=server.ip6n, - o_addr=server_nat_ip, - i_port=server_tcp_in_port, - o_port=server_tcp_out_port, - proto=IP_PROTOS.tcp, vrf_id=0, - is_add=1) - - self.vapi.nat64_add_del_static_bib(i_addr=server.ip6n, - o_addr=server_nat_ip, i_port=0, - o_port=0, - proto=IP_PROTOS.gre, vrf_id=0, - is_add=1) - - self.vapi.nat64_add_del_static_bib(i_addr=client.ip6n, - o_addr=client_nat_ip, - i_port=client_tcp_in_port, - o_port=client_tcp_out_port, - proto=IP_PROTOS.tcp, vrf_id=0, - is_add=1) - - # client to server - p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IPv6(src=client.ip6, dst=server_nat_ip6) / - TCP(sport=client_tcp_in_port, dport=server_tcp_out_port)) - self.pg0.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - p = self.pg0.get_capture(1) - - p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IPv6(src=client.ip6, dst=server_nat_ip6, nh=IP_PROTOS.gre) / - GRE() / - IP(src=self.pg2.local_ip4, dst=self.pg2.remote_ip4) / - TCP(sport=1234, dport=1234)) - self.pg0.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - p = self.pg0.get_capture(1) - packet = p[0] - try: - self.assertEqual(packet[IPv6].src, client_nat_ip6) - self.assertEqual(packet[IPv6].dst, server.ip6) - self.assertEqual(packet[IPv6].nh, IP_PROTOS.gre) - except: - self.logger.error(ppp("Unexpected or invalid packet:", packet)) - raise - - # server to client - p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IPv6(src=server.ip6, dst=client_nat_ip6, nh=IP_PROTOS.gre) / - GRE() / - IP(src=self.pg2.remote_ip4, dst=self.pg2.local_ip4) / - TCP(sport=1234, dport=1234)) - self.pg0.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - p = self.pg0.get_capture(1) - packet = p[0] - try: - self.assertEqual(packet[IPv6].src, server_nat_ip6) - self.assertEqual(packet[IPv6].dst, client.ip6) - self.assertEqual(packet[IPv6].nh, IP_PROTOS.gre) - except: - self.logger.error(ppp("Unexpected or invalid packet:", packet)) - raise - - def test_one_armed_nat64(self): - """ One armed NAT64 """ - external_port = 0 - remote_host_ip6 = self.compose_ip6(self.pg3.remote_ip4, - '64:ff9b::', - 96) - - self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr, - end_addr=self.nat_addr, - vrf_id=0xFFFFFFFF, - is_add=1) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat64_add_del_interface(is_add=1, flags=flags, - sw_if_index=self.pg3.sw_if_index) - self.vapi.nat64_add_del_interface(is_add=1, flags=0, - sw_if_index=self.pg3.sw_if_index) - - # in2out - p = (Ether(src=self.pg3.remote_mac, dst=self.pg3.local_mac) / - IPv6(src=self.pg3.remote_ip6, dst=remote_host_ip6) / - TCP(sport=12345, dport=80)) - self.pg3.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg3.get_capture(1) - p = capture[0] - try: - ip = p[IP] - tcp = p[TCP] - self.assertEqual(ip.src, self.nat_addr) - self.assertEqual(ip.dst, self.pg3.remote_ip4) - self.assertNotEqual(tcp.sport, 12345) - external_port = tcp.sport - self.assertEqual(tcp.dport, 80) - self.assert_packet_checksums_valid(p) - except: - self.logger.error(ppp("Unexpected or invalid packet:", p)) - raise - - # out2in - p = (Ether(src=self.pg3.remote_mac, dst=self.pg3.local_mac) / - IP(src=self.pg3.remote_ip4, dst=self.nat_addr) / - TCP(sport=80, dport=external_port)) - self.pg3.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg3.get_capture(1) - p = capture[0] - try: - ip = p[IPv6] - tcp = p[TCP] - self.assertEqual(ip.src, remote_host_ip6) - self.assertEqual(ip.dst, self.pg3.remote_ip6) - self.assertEqual(tcp.sport, 80) - self.assertEqual(tcp.dport, 12345) - self.assert_packet_checksums_valid(p) - except: - self.logger.error(ppp("Unexpected or invalid packet:", p)) - raise - - def test_frag_in_order(self): - """ NAT64 translate fragments arriving in order """ - self.tcp_port_in = random.randint(1025, 65535) - - self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr, - end_addr=self.nat_addr, - vrf_id=0xFFFFFFFF, - is_add=1) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat64_add_del_interface(is_add=1, flags=flags, - sw_if_index=self.pg0.sw_if_index) - self.vapi.nat64_add_del_interface(is_add=1, flags=0, - sw_if_index=self.pg1.sw_if_index) - - reass = self.vapi.nat_reass_dump() - reass_n_start = len(reass) - - # in2out - data = b'a' * 200 - pkts = self.create_stream_frag_ip6(self.pg0, self.pg1.remote_ip4, - self.tcp_port_in, 20, data) - self.pg0.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - frags = self.pg1.get_capture(len(pkts)) - p = self.reass_frags_and_verify(frags, - self.nat_addr, - self.pg1.remote_ip4) - self.assertEqual(p[TCP].dport, 20) - self.assertNotEqual(p[TCP].sport, self.tcp_port_in) - self.tcp_port_out = p[TCP].sport - self.assertEqual(data, p[Raw].load) - - # out2in - data = b"A" * 4 + b"b" * 16 + b"C" * 3 - pkts = self.create_stream_frag(self.pg1, - self.nat_addr, - 20, - self.tcp_port_out, - data) - self.pg1.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - frags = self.pg0.get_capture(len(pkts)) - src = self.compose_ip6(self.pg1.remote_ip4, '64:ff9b::', 96) - p = self.reass_frags_and_verify_ip6(frags, src, self.pg0.remote_ip6) - self.assertEqual(p[TCP].sport, 20) - self.assertEqual(p[TCP].dport, self.tcp_port_in) - self.assertEqual(data, p[Raw].load) - - reass = self.vapi.nat_reass_dump() - reass_n_end = len(reass) - - self.assertEqual(reass_n_end - reass_n_start, 2) - - def test_reass_hairpinning(self): - """ NAT64 fragments hairpinning """ - data = 'a' * 200 - server = self.pg0.remote_hosts[1] - server_in_port = random.randint(1025, 65535) - server_out_port = random.randint(1025, 65535) - client_in_port = random.randint(1025, 65535) - ip = IPv6(src=''.join(['64:ff9b::', self.nat_addr])) - nat_addr_ip6 = ip.src - - self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr, - end_addr=self.nat_addr, - vrf_id=0xFFFFFFFF, - is_add=1) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat64_add_del_interface(is_add=1, flags=flags, - sw_if_index=self.pg0.sw_if_index) - self.vapi.nat64_add_del_interface(is_add=1, flags=0, - sw_if_index=self.pg1.sw_if_index) - - # add static BIB entry for server - self.vapi.nat64_add_del_static_bib(i_addr=server.ip6n, - o_addr=self.nat_addr, - i_port=server_in_port, - o_port=server_out_port, - proto=IP_PROTOS.tcp, vrf_id=0, - is_add=1) - - # send packet from host to server - pkts = self.create_stream_frag_ip6(self.pg0, - self.nat_addr, - client_in_port, - server_out_port, - data) - self.pg0.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - frags = self.pg0.get_capture(len(pkts)) - p = self.reass_frags_and_verify_ip6(frags, nat_addr_ip6, server.ip6) - self.assertNotEqual(p[TCP].sport, client_in_port) - self.assertEqual(p[TCP].dport, server_in_port) - self.assertEqual(data, p[Raw].load) - - def test_frag_out_of_order(self): - """ NAT64 translate fragments arriving out of order """ - self.tcp_port_in = random.randint(1025, 65535) - - self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr, - end_addr=self.nat_addr, - vrf_id=0xFFFFFFFF, - is_add=1) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat64_add_del_interface(is_add=1, flags=flags, - sw_if_index=self.pg0.sw_if_index) - self.vapi.nat64_add_del_interface(is_add=1, flags=0, - sw_if_index=self.pg1.sw_if_index) - - # in2out - data = b'a' * 200 - pkts = self.create_stream_frag_ip6(self.pg0, self.pg1.remote_ip4, - self.tcp_port_in, 20, data) - pkts.reverse() - self.pg0.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - frags = self.pg1.get_capture(len(pkts)) - p = self.reass_frags_and_verify(frags, - self.nat_addr, - self.pg1.remote_ip4) - self.assertEqual(p[TCP].dport, 20) - self.assertNotEqual(p[TCP].sport, self.tcp_port_in) - self.tcp_port_out = p[TCP].sport - self.assertEqual(data, p[Raw].load) - - # out2in - data = b"A" * 4 + b"B" * 16 + b"C" * 3 - pkts = self.create_stream_frag(self.pg1, - self.nat_addr, - 20, - self.tcp_port_out, - data) - pkts.reverse() - self.pg1.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - frags = self.pg0.get_capture(len(pkts)) - src = self.compose_ip6(self.pg1.remote_ip4, '64:ff9b::', 96) - p = self.reass_frags_and_verify_ip6(frags, src, self.pg0.remote_ip6) - self.assertEqual(p[TCP].sport, 20) - self.assertEqual(p[TCP].dport, self.tcp_port_in) - self.assertEqual(data, p[Raw].load) - - def test_interface_addr(self): - """ Acquire NAT64 pool addresses from interface """ - self.vapi.nat64_add_del_interface_addr( - is_add=1, - sw_if_index=self.pg4.sw_if_index) - - # no address in NAT64 pool - addresses = self.vapi.nat44_address_dump() - self.assertEqual(0, len(addresses)) - - # configure interface address and check NAT64 address pool - self.pg4.config_ip4() - addresses = self.vapi.nat64_pool_addr_dump() - self.assertEqual(len(addresses), 1) - - self.assertEqual(str(addresses[0].address), - self.pg4.local_ip4) - - # remove interface address and check NAT64 address pool - self.pg4.unconfig_ip4() - addresses = self.vapi.nat64_pool_addr_dump() - self.assertEqual(0, len(addresses)) - - @unittest.skipUnless(running_extended_tests, "part of extended tests") - def test_ipfix_max_bibs_sessions(self): - """ IPFIX logging maximum session and BIB entries exceeded """ - max_bibs = 1280 - max_sessions = 2560 - remote_host_ip6 = self.compose_ip6(self.pg1.remote_ip4, - '64:ff9b::', - 96) - - self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr, - end_addr=self.nat_addr, - vrf_id=0xFFFFFFFF, - is_add=1) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat64_add_del_interface(is_add=1, flags=flags, - sw_if_index=self.pg0.sw_if_index) - self.vapi.nat64_add_del_interface(is_add=1, flags=0, - sw_if_index=self.pg1.sw_if_index) - - pkts = [] - src = "" - for i in range(0, max_bibs): - src = "fd01:aa::%x" % (i) - p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / - IPv6(src=src, dst=remote_host_ip6) / - TCP(sport=12345, dport=80)) - pkts.append(p) - p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / - IPv6(src=src, dst=remote_host_ip6) / - TCP(sport=12345, dport=22)) - pkts.append(p) - self.pg0.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - self.pg1.get_capture(max_sessions) - - 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.nat_ipfix_enable_disable(domain_id=self.ipfix_domain_id, - src_port=self.ipfix_src_port, - enable=1) - - p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / - IPv6(src=src, dst=remote_host_ip6) / - TCP(sport=12345, dport=25)) - self.pg0.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - self.pg1.assert_nothing_captured() - sleep(1) - self.vapi.ipfix_flush() - capture = self.pg3.get_capture(9) - ipfix = IPFIXDecoder() - # first load template - for p in capture: - self.assertTrue(p.haslayer(IPFIX)) - self.assertEqual(p[IP].src, self.pg3.local_ip4) - self.assertEqual(p[IP].dst, self.pg3.remote_ip4) - self.assertEqual(p[UDP].sport, self.ipfix_src_port) - self.assertEqual(p[UDP].dport, 4739) - self.assertEqual(p[IPFIX].observationDomainID, - self.ipfix_domain_id) - 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_max_sessions(data, max_sessions) - - p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / - IPv6(src=self.pg0.remote_ip6, dst=remote_host_ip6) / - TCP(sport=12345, dport=80)) - self.pg0.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - self.pg1.assert_nothing_captured() - sleep(1) - self.vapi.ipfix_flush() - capture = self.pg3.get_capture(1) - # verify events in data set - for p in capture: - self.assertTrue(p.haslayer(IPFIX)) - self.assertEqual(p[IP].src, self.pg3.local_ip4) - self.assertEqual(p[IP].dst, self.pg3.remote_ip4) - self.assertEqual(p[UDP].sport, self.ipfix_src_port) - self.assertEqual(p[UDP].dport, 4739) - self.assertEqual(p[IPFIX].observationDomainID, - self.ipfix_domain_id) - if p.haslayer(Data): - data = ipfix.decode_data_set(p.getlayer(Set)) - self.verify_ipfix_max_bibs(data, max_bibs) - - def test_ipfix_max_frags(self): - """ IPFIX logging maximum fragments pending reassembly exceeded """ - self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr, - end_addr=self.nat_addr, - vrf_id=0xFFFFFFFF, - is_add=1) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat64_add_del_interface(is_add=1, flags=flags, - sw_if_index=self.pg0.sw_if_index) - self.vapi.nat64_add_del_interface(is_add=1, flags=0, - sw_if_index=self.pg1.sw_if_index) - self.vapi.nat_set_reass(timeout=2, max_reass=1024, max_frag=1, - drop_frag=0, is_ip6=1) - 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.nat_ipfix_enable_disable(domain_id=self.ipfix_domain_id, - src_port=self.ipfix_src_port, - enable=1) - - data = b'a' * 200 - pkts = self.create_stream_frag_ip6(self.pg0, self.pg1.remote_ip4, - self.tcp_port_in, 20, data) - pkts.reverse() - self.pg0.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - self.pg1.assert_nothing_captured() - sleep(1) - self.vapi.ipfix_flush() - capture = self.pg3.get_capture(9) - ipfix = IPFIXDecoder() - # first load template - for p in capture: - self.assertTrue(p.haslayer(IPFIX)) - self.assertEqual(p[IP].src, self.pg3.local_ip4) - self.assertEqual(p[IP].dst, self.pg3.remote_ip4) - self.assertEqual(p[UDP].sport, self.ipfix_src_port) - self.assertEqual(p[UDP].dport, 4739) - self.assertEqual(p[IPFIX].observationDomainID, - self.ipfix_domain_id) - 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_max_fragments_ip6(data, 1, - self.pg0.remote_ip6n) - - def test_ipfix_bib_ses(self): - """ IPFIX logging NAT64 BIB/session create and delete events """ - self.tcp_port_in = random.randint(1025, 65535) - remote_host_ip6 = self.compose_ip6(self.pg1.remote_ip4, - '64:ff9b::', - 96) - - self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr, - end_addr=self.nat_addr, - vrf_id=0xFFFFFFFF, - is_add=1) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat64_add_del_interface(is_add=1, flags=flags, - sw_if_index=self.pg0.sw_if_index) - self.vapi.nat64_add_del_interface(is_add=1, flags=0, - sw_if_index=self.pg1.sw_if_index) - 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.nat_ipfix_enable_disable(domain_id=self.ipfix_domain_id, - src_port=self.ipfix_src_port, - enable=1) - - # Create - p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / - IPv6(src=self.pg0.remote_ip6, dst=remote_host_ip6) / - TCP(sport=self.tcp_port_in, dport=25)) - self.pg0.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - p = self.pg1.get_capture(1) - self.tcp_port_out = p[0][TCP].sport - self.vapi.ipfix_flush() - capture = self.pg3.get_capture(10) - ipfix = IPFIXDecoder() - # first load template - for p in capture: - self.assertTrue(p.haslayer(IPFIX)) - self.assertEqual(p[IP].src, self.pg3.local_ip4) - self.assertEqual(p[IP].dst, self.pg3.remote_ip4) - self.assertEqual(p[UDP].sport, self.ipfix_src_port) - self.assertEqual(p[UDP].dport, 4739) - self.assertEqual(p[IPFIX].observationDomainID, - self.ipfix_domain_id) - 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)) - if scapy.compat.orb(data[0][230]) == 10: - self.verify_ipfix_bib(data, 1, self.pg0.remote_ip6n) - elif scapy.compat.orb(data[0][230]) == 6: - self.verify_ipfix_nat64_ses(data, - 1, - self.pg0.remote_ip6n, - self.pg1.remote_ip4, - 25) - else: - self.logger.error(ppp("Unexpected or invalid packet: ", p)) - - # Delete - self.pg_enable_capture(self.pg_interfaces) - self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr, - end_addr=self.nat_addr, - vrf_id=0xFFFFFFFF, - is_add=0) - self.vapi.ipfix_flush() - capture = self.pg3.get_capture(2) - # verify events in data set - for p in capture: - self.assertTrue(p.haslayer(IPFIX)) - self.assertEqual(p[IP].src, self.pg3.local_ip4) - self.assertEqual(p[IP].dst, self.pg3.remote_ip4) - self.assertEqual(p[UDP].sport, self.ipfix_src_port) - self.assertEqual(p[UDP].dport, 4739) - self.assertEqual(p[IPFIX].observationDomainID, - self.ipfix_domain_id) - if p.haslayer(Data): - data = ipfix.decode_data_set(p.getlayer(Set)) - if scapy.compat.orb(data[0][230]) == 11: - self.verify_ipfix_bib(data, 0, self.pg0.remote_ip6n) - elif scapy.compat.orb(data[0][230]) == 7: - self.verify_ipfix_nat64_ses(data, - 0, - self.pg0.remote_ip6n, - self.pg1.remote_ip4, - 25) - else: - self.logger.error(ppp("Unexpected or invalid packet: ", p)) - - def test_syslog_sess(self): - """ Test syslog session creation and deletion """ - self.tcp_port_in = random.randint(1025, 65535) - remote_host_ip6 = self.compose_ip6(self.pg1.remote_ip4, - '64:ff9b::', - 96) - - self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr, - end_addr=self.nat_addr, - vrf_id=0xFFFFFFFF, - is_add=1) - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat64_add_del_interface(is_add=1, flags=flags, - sw_if_index=self.pg0.sw_if_index) - self.vapi.nat64_add_del_interface(is_add=1, flags=0, - sw_if_index=self.pg1.sw_if_index) - self.vapi.syslog_set_filter( - self.SYSLOG_SEVERITY.SYSLOG_API_SEVERITY_INFO) - self.vapi.syslog_set_sender(self.pg3.local_ip4n, self.pg3.remote_ip4n) - - p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / - IPv6(src=self.pg0.remote_ip6, dst=remote_host_ip6) / - TCP(sport=self.tcp_port_in, dport=self.tcp_external_port)) - self.pg0.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - p = self.pg1.get_capture(1) - self.tcp_port_out = p[0][TCP].sport - capture = self.pg3.get_capture(1) - self.verify_syslog_sess(capture[0][Raw].load, is_ip6=True) - - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - self.vapi.nat64_add_del_pool_addr_range(start_addr=self.nat_addr, - end_addr=self.nat_addr, - vrf_id=0xFFFFFFFF, - is_add=0) - capture = self.pg3.get_capture(1) - self.verify_syslog_sess(capture[0][Raw].load, False, True) - - def nat64_get_ses_num(self): - """ - Return number of active NAT64 sessions. - """ - st = self.vapi.nat64_st_dump(proto=255) - return len(st) - - def clear_nat64(self): - """ - Clear NAT64 configuration. - """ - self.vapi.nat_ipfix_enable_disable(domain_id=self.ipfix_domain_id, - src_port=self.ipfix_src_port, - enable=0) - self.ipfix_src_port = 4739 - self.ipfix_domain_id = 1 - - self.vapi.syslog_set_filter( - self.SYSLOG_SEVERITY.SYSLOG_API_SEVERITY_EMERG) - - self.vapi.nat_set_timeouts(udp=300, tcp_established=7440, - tcp_transitory=240, icmp=60) - - interfaces = self.vapi.nat64_interface_dump() - for intf in interfaces: - self.vapi.nat64_add_del_interface(is_add=0, flags=intf.flags, - sw_if_index=intf.sw_if_index) - - bib = self.vapi.nat64_bib_dump(proto=255) - for bibe in bib: - if bibe.flags & self.config_flags.NAT_IS_STATIC: - self.vapi.nat64_add_del_static_bib(i_addr=bibe.i_addr, - o_addr=bibe.o_addr, - i_port=bibe.i_port, - o_port=bibe.o_port, - proto=bibe.proto, - vrf_id=bibe.vrf_id, - is_add=0) - - adresses = self.vapi.nat64_pool_addr_dump() - for addr in adresses: - self.vapi.nat64_add_del_pool_addr_range(start_addr=addr.address, - end_addr=addr.address, - vrf_id=addr.vrf_id, - is_add=0) - - prefixes = self.vapi.nat64_prefix_dump() - for prefix in prefixes: - self.vapi.nat64_add_del_prefix(prefix=str(prefix.prefix), - vrf_id=prefix.vrf_id, is_add=0) - - bibs = self.statistics.get_counter('/nat64/total-bibs') - self.assertEqual(bibs[0][0], 0) - sessions = self.statistics.get_counter('/nat64/total-sessions') - self.assertEqual(sessions[0][0], 0) - - def tearDown(self): - super(TestNAT64, self).tearDown() - if not self.vpp_dead: - self.clear_nat64() - - def show_commands_at_teardown(self): - self.logger.info(self.vapi.cli("show nat64 pool")) - self.logger.info(self.vapi.cli("show nat64 interfaces")) - self.logger.info(self.vapi.cli("show nat64 prefix")) - self.logger.info(self.vapi.cli("show nat64 bib all")) - self.logger.info(self.vapi.cli("show nat64 session table all")) - self.logger.info(self.vapi.cli("show nat virtual-reassembly")) - - -class TestDSlite(MethodHolder): - """ DS-Lite Test Cases """ - - @classmethod - def setUpClass(cls): - super(TestDSlite, cls).setUpClass() - - try: - cls.nat_addr = '10.0.0.3' - - cls.create_pg_interfaces(range(3)) - cls.pg0.admin_up() - cls.pg0.config_ip4() - cls.pg0.resolve_arp() - cls.pg1.admin_up() - cls.pg1.config_ip6() - cls.pg1.generate_remote_hosts(2) - cls.pg1.configure_ipv6_neighbors() - cls.pg2.admin_up() - cls.pg2.config_ip4() - cls.pg2.resolve_arp() - - except Exception: - super(TestDSlite, cls).tearDownClass() - raise - - @classmethod - def tearDownClass(cls): - super(TestDSlite, cls).tearDownClass() - - def verify_syslog_apmadd(self, data, isaddr, isport, xsaddr, xsport, - sv6enc, proto): - message = data.decode('utf-8') - try: - message = SyslogMessage.parse(message) - except ParseError as e: - self.logger.error(e) - else: - self.assertEqual(message.severity, SyslogSeverity.info) - self.assertEqual(message.appname, 'NAT') - self.assertEqual(message.msgid, 'APMADD') - sd_params = message.sd.get('napmap') - self.assertTrue(sd_params is not None) - self.assertEqual(sd_params.get('IATYP'), 'IPv4') - self.assertEqual(sd_params.get('ISADDR'), isaddr) - self.assertEqual(sd_params.get('ISPORT'), "%d" % isport) - self.assertEqual(sd_params.get('XATYP'), 'IPv4') - self.assertEqual(sd_params.get('XSADDR'), xsaddr) - self.assertEqual(sd_params.get('XSPORT'), "%d" % xsport) - self.assertEqual(sd_params.get('PROTO'), "%d" % proto) - self.assertTrue(sd_params.get('SSUBIX') is not None) - self.assertEqual(sd_params.get('SV6ENC'), sv6enc) - - def test_dslite(self): - """ Test DS-Lite """ - nat_config = self.vapi.nat_show_config() - self.assertEqual(0, nat_config.dslite_ce) - - self.vapi.dslite_add_del_pool_addr_range(start_addr=self.nat_addr, - end_addr=self.nat_addr, - is_add=1) - aftr_ip4 = '192.0.0.1' - aftr_ip6 = '2001:db8:85a3::8a2e:370:1' - self.vapi.dslite_set_aftr_addr(ip4_addr=aftr_ip4, ip6_addr=aftr_ip6) - self.vapi.syslog_set_sender(self.pg2.local_ip4n, self.pg2.remote_ip4n) - - # UDP - p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / - IPv6(dst=aftr_ip6, src=self.pg1.remote_hosts[0].ip6) / - IP(dst=self.pg0.remote_ip4, src='192.168.1.1') / - UDP(sport=20000, dport=10000)) - self.pg1.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg0.get_capture(1) - capture = capture[0] - self.assertFalse(capture.haslayer(IPv6)) - self.assertEqual(capture[IP].src, self.nat_addr) - self.assertEqual(capture[IP].dst, self.pg0.remote_ip4) - self.assertNotEqual(capture[UDP].sport, 20000) - self.assertEqual(capture[UDP].dport, 10000) - self.assert_packet_checksums_valid(capture) - out_port = capture[UDP].sport - capture = self.pg2.get_capture(1) - self.verify_syslog_apmadd(capture[0][Raw].load, '192.168.1.1', - 20000, self.nat_addr, out_port, - self.pg1.remote_hosts[0].ip6, IP_PROTOS.udp) - - p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IP(dst=self.nat_addr, src=self.pg0.remote_ip4) / - UDP(sport=10000, dport=out_port)) - self.pg0.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg1.get_capture(1) - capture = capture[0] - self.assertEqual(capture[IPv6].src, aftr_ip6) - self.assertEqual(capture[IPv6].dst, self.pg1.remote_hosts[0].ip6) - self.assertEqual(capture[IP].src, self.pg0.remote_ip4) - self.assertEqual(capture[IP].dst, '192.168.1.1') - self.assertEqual(capture[UDP].sport, 10000) - self.assertEqual(capture[UDP].dport, 20000) - self.assert_packet_checksums_valid(capture) - - # TCP - p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / - IPv6(dst=aftr_ip6, src=self.pg1.remote_hosts[1].ip6) / - IP(dst=self.pg0.remote_ip4, src='192.168.1.1') / - TCP(sport=20001, dport=10001)) - self.pg1.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg0.get_capture(1) - capture = capture[0] - self.assertFalse(capture.haslayer(IPv6)) - self.assertEqual(capture[IP].src, self.nat_addr) - self.assertEqual(capture[IP].dst, self.pg0.remote_ip4) - self.assertNotEqual(capture[TCP].sport, 20001) - self.assertEqual(capture[TCP].dport, 10001) - self.assert_packet_checksums_valid(capture) - out_port = capture[TCP].sport - - p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IP(dst=self.nat_addr, src=self.pg0.remote_ip4) / - TCP(sport=10001, dport=out_port)) - self.pg0.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg1.get_capture(1) - capture = capture[0] - self.assertEqual(capture[IPv6].src, aftr_ip6) - self.assertEqual(capture[IPv6].dst, self.pg1.remote_hosts[1].ip6) - self.assertEqual(capture[IP].src, self.pg0.remote_ip4) - self.assertEqual(capture[IP].dst, '192.168.1.1') - self.assertEqual(capture[TCP].sport, 10001) - self.assertEqual(capture[TCP].dport, 20001) - self.assert_packet_checksums_valid(capture) - - # ICMP - p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / - IPv6(dst=aftr_ip6, src=self.pg1.remote_hosts[1].ip6) / - IP(dst=self.pg0.remote_ip4, src='192.168.1.1') / - ICMP(id=4000, type='echo-request')) - self.pg1.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg0.get_capture(1) - capture = capture[0] - self.assertFalse(capture.haslayer(IPv6)) - self.assertEqual(capture[IP].src, self.nat_addr) - self.assertEqual(capture[IP].dst, self.pg0.remote_ip4) - self.assertNotEqual(capture[ICMP].id, 4000) - self.assert_packet_checksums_valid(capture) - out_id = capture[ICMP].id - - p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IP(dst=self.nat_addr, src=self.pg0.remote_ip4) / - ICMP(id=out_id, type='echo-reply')) - self.pg0.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg1.get_capture(1) - capture = capture[0] - self.assertEqual(capture[IPv6].src, aftr_ip6) - self.assertEqual(capture[IPv6].dst, self.pg1.remote_hosts[1].ip6) - self.assertEqual(capture[IP].src, self.pg0.remote_ip4) - self.assertEqual(capture[IP].dst, '192.168.1.1') - self.assertEqual(capture[ICMP].id, 4000) - self.assert_packet_checksums_valid(capture) - - # ping DS-Lite AFTR tunnel endpoint address - p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / - IPv6(src=self.pg1.remote_hosts[1].ip6, dst=aftr_ip6) / - ICMPv6EchoRequest()) - self.pg1.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg1.get_capture(1) - capture = capture[0] - self.assertEqual(capture[IPv6].src, aftr_ip6) - self.assertEqual(capture[IPv6].dst, self.pg1.remote_hosts[1].ip6) - self.assertTrue(capture.haslayer(ICMPv6EchoReply)) - - b4s = self.statistics.get_counter('/dslite/total-b4s') - self.assertEqual(b4s[0][0], 2) - sessions = self.statistics.get_counter('/dslite/total-sessions') - self.assertEqual(sessions[0][0], 3) - - def tearDown(self): - super(TestDSlite, self).tearDown() - - def show_commands_at_teardown(self): - self.logger.info(self.vapi.cli("show dslite pool")) - self.logger.info( - self.vapi.cli("show dslite aftr-tunnel-endpoint-address")) - self.logger.info(self.vapi.cli("show dslite sessions")) - - -class TestDSliteCE(MethodHolder): - """ DS-Lite CE Test Cases """ - - @classmethod - def setUpConstants(cls): - super(TestDSliteCE, cls).setUpConstants() - cls.vpp_cmdline.extend(["nat", "{", "dslite ce", "}"]) - - @classmethod - def setUpClass(cls): - super(TestDSliteCE, cls).setUpClass() - - try: - cls.create_pg_interfaces(range(2)) - cls.pg0.admin_up() - cls.pg0.config_ip4() - cls.pg0.resolve_arp() - cls.pg1.admin_up() - cls.pg1.config_ip6() - cls.pg1.generate_remote_hosts(1) - cls.pg1.configure_ipv6_neighbors() - - except Exception: - super(TestDSliteCE, cls).tearDownClass() - raise - - @classmethod - def tearDownClass(cls): - super(TestDSliteCE, cls).tearDownClass() - - def test_dslite_ce(self): - """ Test DS-Lite CE """ - - nat_config = self.vapi.nat_show_config() - self.assertEqual(1, nat_config.dslite_ce) - - b4_ip4 = '192.0.0.2' - b4_ip6 = '2001:db8:62aa::375e:f4c1:1' - self.vapi.dslite_set_b4_addr(ip4_addr=b4_ip4, ip6_addr=b4_ip6) - - aftr_ip4 = '192.0.0.1' - aftr_ip6 = '2001:db8:85a3::8a2e:370:1' - aftr_ip6_n = socket.inet_pton(socket.AF_INET6, aftr_ip6) - self.vapi.dslite_set_aftr_addr(ip4_addr=aftr_ip4, ip6_addr=aftr_ip6) - - r1 = VppIpRoute(self, aftr_ip6, 128, - [VppRoutePath(self.pg1.remote_ip6, - self.pg1.sw_if_index)]) - r1.add_vpp_config() - - # UDP encapsulation - p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IP(dst=self.pg1.remote_ip4, src=self.pg0.remote_ip4) / - UDP(sport=10000, dport=20000)) - self.pg0.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg1.get_capture(1) - capture = capture[0] - self.assertEqual(capture[IPv6].src, b4_ip6) - self.assertEqual(capture[IPv6].dst, aftr_ip6) - self.assertEqual(capture[IP].src, self.pg0.remote_ip4) - self.assertEqual(capture[IP].dst, self.pg1.remote_ip4) - self.assertEqual(capture[UDP].sport, 10000) - self.assertEqual(capture[UDP].dport, 20000) - self.assert_packet_checksums_valid(capture) - - # UDP decapsulation - p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / - IPv6(dst=b4_ip6, src=aftr_ip6) / - IP(dst=self.pg0.remote_ip4, src=self.pg1.remote_ip4) / - UDP(sport=20000, dport=10000)) - self.pg1.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg0.get_capture(1) - capture = capture[0] - self.assertFalse(capture.haslayer(IPv6)) - self.assertEqual(capture[IP].src, self.pg1.remote_ip4) - self.assertEqual(capture[IP].dst, self.pg0.remote_ip4) - self.assertEqual(capture[UDP].sport, 20000) - self.assertEqual(capture[UDP].dport, 10000) - self.assert_packet_checksums_valid(capture) - - # ping DS-Lite B4 tunnel endpoint address - p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / - IPv6(src=self.pg1.remote_hosts[0].ip6, dst=b4_ip6) / - ICMPv6EchoRequest()) - self.pg1.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg1.get_capture(1) - capture = capture[0] - self.assertEqual(capture[IPv6].src, b4_ip6) - self.assertEqual(capture[IPv6].dst, self.pg1.remote_hosts[0].ip6) - self.assertTrue(capture.haslayer(ICMPv6EchoReply)) - - def tearDown(self): - super(TestDSliteCE, self).tearDown() - - def show_commands_at_teardown(self): - self.logger.info( - self.vapi.cli("show dslite aftr-tunnel-endpoint-address")) - self.logger.info( - self.vapi.cli("show dslite b4-tunnel-endpoint-address")) - - -class TestNAT66(MethodHolder): - """ NAT66 Test Cases """ - - @classmethod - def setUpClass(cls): - super(TestNAT66, cls).setUpClass() - - try: - cls.nat_addr = 'fd01:ff::2' - - cls.create_pg_interfaces(range(2)) - cls.interfaces = list(cls.pg_interfaces) - - for i in cls.interfaces: - i.admin_up() - i.config_ip6() - i.configure_ipv6_neighbors() - - except Exception: - super(TestNAT66, cls).tearDownClass() - raise - - @classmethod - def tearDownClass(cls): - super(TestNAT66, cls).tearDownClass() - - def test_static(self): - """ 1:1 NAT66 test """ - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat66_add_del_interface(is_add=1, flags=flags, - sw_if_index=self.pg0.sw_if_index) - self.vapi.nat66_add_del_interface(is_add=1, - sw_if_index=self.pg1.sw_if_index) - self.vapi.nat66_add_del_static_mapping( - local_ip_address=self.pg0.remote_ip6n, - external_ip_address=self.nat_addr, - is_add=1) - - # in2out - pkts = [] - p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IPv6(src=self.pg0.remote_ip6, dst=self.pg1.remote_ip6) / - TCP()) - pkts.append(p) - p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IPv6(src=self.pg0.remote_ip6, dst=self.pg1.remote_ip6) / - UDP()) - pkts.append(p) - p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IPv6(src=self.pg0.remote_ip6, dst=self.pg1.remote_ip6) / - ICMPv6EchoRequest()) - pkts.append(p) - p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IPv6(src=self.pg0.remote_ip6, dst=self.pg1.remote_ip6) / - GRE() / IP() / TCP()) - pkts.append(p) - self.pg0.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg1.get_capture(len(pkts)) - for packet in capture: - try: - self.assertEqual(packet[IPv6].src, self.nat_addr) - self.assertEqual(packet[IPv6].dst, self.pg1.remote_ip6) - self.assert_packet_checksums_valid(packet) - except: - self.logger.error(ppp("Unexpected or invalid packet:", packet)) - raise - - # out2in - pkts = [] - p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / - IPv6(src=self.pg1.remote_ip6, dst=self.nat_addr) / - TCP()) - pkts.append(p) - p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / - IPv6(src=self.pg1.remote_ip6, dst=self.nat_addr) / - UDP()) - pkts.append(p) - p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / - IPv6(src=self.pg1.remote_ip6, dst=self.nat_addr) / - ICMPv6EchoReply()) - pkts.append(p) - p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / - IPv6(src=self.pg1.remote_ip6, dst=self.nat_addr) / - GRE() / IP() / TCP()) - pkts.append(p) - self.pg1.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg0.get_capture(len(pkts)) - for packet in capture: - try: - self.assertEqual(packet[IPv6].src, self.pg1.remote_ip6) - self.assertEqual(packet[IPv6].dst, self.pg0.remote_ip6) - self.assert_packet_checksums_valid(packet) - except: - self.logger.error(ppp("Unexpected or invalid packet:", packet)) - raise - - sm = self.vapi.nat66_static_mapping_dump() - self.assertEqual(len(sm), 1) - self.assertEqual(sm[0].total_pkts, 8) - - def test_check_no_translate(self): - """ NAT66 translate only when egress interface is outside interface """ - flags = self.config_flags.NAT_IS_INSIDE - self.vapi.nat66_add_del_interface(is_add=1, flags=flags, - sw_if_index=self.pg0.sw_if_index) - self.vapi.nat66_add_del_interface(is_add=1, flags=flags, - sw_if_index=self.pg1.sw_if_index) - self.vapi.nat66_add_del_static_mapping( - local_ip_address=self.pg0.remote_ip6n, - external_ip_address=self.nat_addr, - is_add=1) - - # in2out - p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IPv6(src=self.pg0.remote_ip6, dst=self.pg1.remote_ip6) / - UDP()) - self.pg0.add_stream([p]) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - capture = self.pg1.get_capture(1) - packet = capture[0] - try: - self.assertEqual(packet[IPv6].src, self.pg0.remote_ip6) - self.assertEqual(packet[IPv6].dst, self.pg1.remote_ip6) - except: - self.logger.error(ppp("Unexpected or invalid packet:", packet)) - raise - - def clear_nat66(self): - """ - Clear NAT66 configuration. - """ - interfaces = self.vapi.nat66_interface_dump() - for intf in interfaces: - self.vapi.nat66_add_del_interface(is_add=0, flags=intf.flags, - sw_if_index=intf.sw_if_index) - - static_mappings = self.vapi.nat66_static_mapping_dump() - for sm in static_mappings: - self.vapi.nat66_add_del_static_mapping( - local_ip_address=sm.local_ip_address, - external_ip_address=sm.external_ip_address, vrf_id=sm.vrf_id, - is_add=0) - - def tearDown(self): - super(TestNAT66, self).tearDown() - self.clear_nat66() - - def show_commands_at_teardown(self): - self.logger.info(self.vapi.cli("show nat66 interfaces")) - self.logger.info(self.vapi.cli("show nat66 static mappings")) - - -if __name__ == '__main__': - unittest.main(testRunner=VppTestRunner) diff --git a/test/test_pppoe.py b/test/test_pppoe.py deleted file mode 100644 index 54378673eb4..00000000000 --- a/test/test_pppoe.py +++ /dev/null @@ -1,606 +0,0 @@ -#!/usr/bin/env python - -import socket -import unittest - -from scapy.packet import Raw -from scapy.layers.l2 import Ether -from scapy.layers.ppp import PPPoE, PPPoED, PPP -from scapy.layers.inet import IP - -from framework import VppTestCase, VppTestRunner -from vpp_ip_route import VppIpRoute, VppRoutePath -from vpp_pppoe_interface import VppPppoeInterface -from util import ppp, ppc - - -class TestPPPoE(VppTestCase): - """ PPPoE Test Case """ - - @classmethod - def setUpClass(cls): - super(TestPPPoE, cls).setUpClass() - - cls.session_id = 1 - cls.dst_ip = "100.1.1.100" - cls.dst_ipn = socket.inet_pton(socket.AF_INET, cls.dst_ip) - - @classmethod - def tearDownClass(cls): - super(TestPPPoE, cls).tearDownClass() - - def setUp(self): - super(TestPPPoE, self).setUp() - - # create 2 pg interfaces - self.create_pg_interfaces(range(3)) - - for i in self.pg_interfaces: - i.admin_up() - i.config_ip4() - i.resolve_arp() - - def tearDown(self): - super(TestPPPoE, self).tearDown() - - for i in self.pg_interfaces: - i.unconfig_ip4() - i.admin_down() - - def show_commands_at_teardown(self): - self.logger.info(self.vapi.cli("show int")) - self.logger.info(self.vapi.cli("show pppoe fib")) - self.logger.info(self.vapi.cli("show pppoe session")) - self.logger.info(self.vapi.cli("show ip fib")) - self.logger.info(self.vapi.cli("show trace")) - - def create_stream_pppoe_discovery(self, src_if, dst_if, - client_mac, count=1): - packets = [] - for i in range(count): - # create packet info stored in the test case instance - info = self.create_packet_info(src_if, dst_if) - # convert the info into packet payload - payload = self.info_to_payload(info) - # create the packet itself - p = (Ether(dst=src_if.local_mac, src=client_mac) / - PPPoED(sessionid=0) / - Raw(payload)) - # store a copy of the packet in the packet info - info.data = p.copy() - # append the packet to the list - packets.append(p) - - # return the created packet list - return packets - - def create_stream_pppoe_lcp(self, src_if, dst_if, - client_mac, session_id, count=1): - packets = [] - for i in range(count): - # create packet info stored in the test case instance - info = self.create_packet_info(src_if, dst_if) - # convert the info into packet payload - payload = self.info_to_payload(info) - # create the packet itself - p = (Ether(dst=src_if.local_mac, src=client_mac) / - PPPoE(sessionid=session_id) / - PPP(proto=0xc021) / - Raw(payload)) - # store a copy of the packet in the packet info - info.data = p.copy() - # append the packet to the list - packets.append(p) - - # return the created packet list - return packets - - def create_stream_pppoe_ip4(self, src_if, dst_if, - client_mac, session_id, client_ip, count=1): - packets = [] - for i in range(count): - # create packet info stored in the test case instance - info = self.create_packet_info(src_if, dst_if) - # convert the info into packet payload - payload = self.info_to_payload(info) - # create the packet itself - p = (Ether(dst=src_if.local_mac, src=client_mac) / - PPPoE(sessionid=session_id) / - PPP(proto=0x0021) / - IP(src=client_ip, dst=self.dst_ip) / - Raw(payload)) - # store a copy of the packet in the packet info - info.data = p.copy() - # append the packet to the list - packets.append(p) - - # return the created packet list - return packets - - def create_stream_ip4(self, src_if, dst_if, client_ip, dst_ip, count=1): - pkts = [] - for i in range(count): - # create packet info stored in the test case instance - info = self.create_packet_info(src_if, dst_if) - # convert the info into packet payload - payload = self.info_to_payload(info) - # create the packet itself - p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) / - IP(src=dst_ip, dst=client_ip) / - Raw(payload)) - # store a copy of the packet in the packet info - info.data = p.copy() - # append the packet to the list - pkts.append(p) - - # return the created packet list - return pkts - - def verify_decapped_pppoe(self, src_if, capture, sent): - self.assertEqual(len(capture), len(sent)) - - for i in range(len(capture)): - try: - tx = sent[i] - rx = capture[i] - - tx_ip = tx[IP] - rx_ip = rx[IP] - - self.assertEqual(rx_ip.src, tx_ip.src) - self.assertEqual(rx_ip.dst, tx_ip.dst) - - except: - self.logger.error(ppp("Rx:", rx)) - self.logger.error(ppp("Tx:", tx)) - raise - - def verify_encaped_pppoe(self, src_if, capture, sent, session_id): - - self.assertEqual(len(capture), len(sent)) - - for i in range(len(capture)): - try: - tx = sent[i] - rx = capture[i] - - tx_ip = tx[IP] - rx_ip = rx[IP] - - self.assertEqual(rx_ip.src, tx_ip.src) - self.assertEqual(rx_ip.dst, tx_ip.dst) - - rx_pppoe = rx[PPPoE] - - self.assertEqual(rx_pppoe.sessionid, session_id) - - except: - self.logger.error(ppp("Rx:", rx)) - self.logger.error(ppp("Tx:", tx)) - raise - - def test_PPPoE_Decap(self): - """ PPPoE Decap Test """ - - self.vapi.cli("clear trace") - - # - # Add a route that resolves the server's destination - # - route_sever_dst = VppIpRoute(self, "100.1.1.100", 32, - [VppRoutePath(self.pg1.remote_ip4, - self.pg1.sw_if_index)]) - route_sever_dst.add_vpp_config() - - # Send PPPoE Discovery - tx0 = self.create_stream_pppoe_discovery(self.pg0, self.pg1, - self.pg0.remote_mac) - self.pg0.add_stream(tx0) - self.pg_start() - - # Send PPPoE PPP LCP - tx1 = self.create_stream_pppoe_lcp(self.pg0, self.pg1, - self.pg0.remote_mac, - self.session_id) - self.pg0.add_stream(tx1) - self.pg_start() - - # Create PPPoE session - pppoe_if = VppPppoeInterface(self, - self.pg0.remote_ip4, - self.pg0.remote_mac, - self.session_id) - pppoe_if.add_vpp_config() - - # - # Send tunneled packets that match the created tunnel and - # are decapped and forwarded - # - tx2 = self.create_stream_pppoe_ip4(self.pg0, self.pg1, - self.pg0.remote_mac, - self.session_id, - self.pg0.remote_ip4) - self.pg0.add_stream(tx2) - - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - - rx2 = self.pg1.get_capture(len(tx2)) - self.verify_decapped_pppoe(self.pg0, rx2, tx2) - - self.logger.info(self.vapi.cli("show pppoe fib")) - self.logger.info(self.vapi.cli("show pppoe session")) - self.logger.info(self.vapi.cli("show ip fib")) - - # - # test case cleanup - # - - # Delete PPPoE session - pppoe_if.remove_vpp_config() - - # Delete a route that resolves the server's destination - route_sever_dst.remove_vpp_config() - - def test_PPPoE_Encap(self): - """ PPPoE Encap Test """ - - self.vapi.cli("clear trace") - - # - # Add a route that resolves the server's destination - # - route_sever_dst = VppIpRoute(self, "100.1.1.100", 32, - [VppRoutePath(self.pg1.remote_ip4, - self.pg1.sw_if_index)]) - route_sever_dst.add_vpp_config() - - # Send PPPoE Discovery - tx0 = self.create_stream_pppoe_discovery(self.pg0, self.pg1, - self.pg0.remote_mac) - self.pg0.add_stream(tx0) - self.pg_start() - - # Send PPPoE PPP LCP - tx1 = self.create_stream_pppoe_lcp(self.pg0, self.pg1, - self.pg0.remote_mac, - self.session_id) - self.pg0.add_stream(tx1) - self.pg_start() - - # Create PPPoE session - pppoe_if = VppPppoeInterface(self, - self.pg0.remote_ip4, - self.pg0.remote_mac, - self.session_id) - pppoe_if.add_vpp_config() - - # - # Send a packet stream that is routed into the session - # - packets are PPPoE encapped - # - self.vapi.cli("clear trace") - tx2 = self.create_stream_ip4(self.pg1, self.pg0, - self.pg0.remote_ip4, self.dst_ip, 65) - self.pg1.add_stream(tx2) - - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - - rx2 = self.pg0.get_capture(len(tx2)) - self.verify_encaped_pppoe(self.pg1, rx2, tx2, self.session_id) - - self.logger.info(self.vapi.cli("show pppoe fib")) - self.logger.info(self.vapi.cli("show pppoe session")) - self.logger.info(self.vapi.cli("show ip fib")) - self.logger.info(self.vapi.cli("show adj")) - - # - # test case cleanup - # - - # Delete PPPoE session - pppoe_if.remove_vpp_config() - - # Delete a route that resolves the server's destination - route_sever_dst.remove_vpp_config() - - def test_PPPoE_Add_Twice(self): - """ PPPoE Add Same Session Twice Test """ - - self.vapi.cli("clear trace") - - # - # Add a route that resolves the server's destination - # - route_sever_dst = VppIpRoute(self, "100.1.1.100", 32, - [VppRoutePath(self.pg1.remote_ip4, - self.pg1.sw_if_index)]) - route_sever_dst.add_vpp_config() - - # Send PPPoE Discovery - tx0 = self.create_stream_pppoe_discovery(self.pg0, self.pg1, - self.pg0.remote_mac) - self.pg0.add_stream(tx0) - self.pg_start() - - # Send PPPoE PPP LCP - tx1 = self.create_stream_pppoe_lcp(self.pg0, self.pg1, - self.pg0.remote_mac, - self.session_id) - self.pg0.add_stream(tx1) - self.pg_start() - - # Create PPPoE session - pppoe_if = VppPppoeInterface(self, - self.pg0.remote_ip4, - self.pg0.remote_mac, - self.session_id) - pppoe_if.add_vpp_config() - - # - # The double create (create the same session twice) should fail, - # and we should still be able to use the original - # - try: - pppoe_if.add_vpp_config() - except Exception: - pass - else: - self.fail("Double GRE tunnel add does not fail") - - # - # test case cleanup - # - - # Delete PPPoE session - pppoe_if.remove_vpp_config() - - # Delete a route that resolves the server's destination - route_sever_dst.remove_vpp_config() - - def test_PPPoE_Del_Twice(self): - """ PPPoE Delete Same Session Twice Test """ - - self.vapi.cli("clear trace") - - # - # Add a route that resolves the server's destination - # - route_sever_dst = VppIpRoute(self, "100.1.1.100", 32, - [VppRoutePath(self.pg1.remote_ip4, - self.pg1.sw_if_index)]) - route_sever_dst.add_vpp_config() - - # Send PPPoE Discovery - tx0 = self.create_stream_pppoe_discovery(self.pg0, self.pg1, - self.pg0.remote_mac) - self.pg0.add_stream(tx0) - self.pg_start() - - # Send PPPoE PPP LCP - tx1 = self.create_stream_pppoe_lcp(self.pg0, self.pg1, - self.pg0.remote_mac, - self.session_id) - self.pg0.add_stream(tx1) - self.pg_start() - - # Create PPPoE session - pppoe_if = VppPppoeInterface(self, - self.pg0.remote_ip4, - self.pg0.remote_mac, - self.session_id) - pppoe_if.add_vpp_config() - - # Delete PPPoE session - pppoe_if.remove_vpp_config() - - # - # The double del (del the same session twice) should fail, - # and we should still be able to use the original - # - try: - pppoe_if.remove_vpp_config() - except Exception: - pass - else: - self.fail("Double GRE tunnel del does not fail") - - # - # test case cleanup - # - - # Delete a route that resolves the server's destination - route_sever_dst.remove_vpp_config() - - def test_PPPoE_Decap_Multiple(self): - """ PPPoE Decap Multiple Sessions Test """ - - self.vapi.cli("clear trace") - - # - # Add a route that resolves the server's destination - # - route_sever_dst = VppIpRoute(self, "100.1.1.100", 32, - [VppRoutePath(self.pg1.remote_ip4, - self.pg1.sw_if_index)]) - route_sever_dst.add_vpp_config() - - # Send PPPoE Discovery 1 - tx0 = self.create_stream_pppoe_discovery(self.pg0, self.pg1, - self.pg0.remote_mac) - self.pg0.add_stream(tx0) - self.pg_start() - - # Send PPPoE PPP LCP 1 - tx1 = self.create_stream_pppoe_lcp(self.pg0, self.pg1, - self.pg0.remote_mac, - self.session_id) - self.pg0.add_stream(tx1) - self.pg_start() - - # Create PPPoE session 1 - pppoe_if1 = VppPppoeInterface(self, - self.pg0.remote_ip4, - self.pg0.remote_mac, - self.session_id) - pppoe_if1.add_vpp_config() - - # Send PPPoE Discovery 2 - tx3 = self.create_stream_pppoe_discovery(self.pg2, self.pg1, - self.pg2.remote_mac) - self.pg2.add_stream(tx3) - self.pg_start() - - # Send PPPoE PPP LCP 2 - tx4 = self.create_stream_pppoe_lcp(self.pg2, self.pg1, - self.pg2.remote_mac, - self.session_id + 1) - self.pg2.add_stream(tx4) - self.pg_start() - - # Create PPPoE session 2 - pppoe_if2 = VppPppoeInterface(self, - self.pg2.remote_ip4, - self.pg2.remote_mac, - self.session_id + 1) - pppoe_if2.add_vpp_config() - - # - # Send tunneled packets that match the created tunnel and - # are decapped and forwarded - # - tx2 = self.create_stream_pppoe_ip4(self.pg0, self.pg1, - self.pg0.remote_mac, - self.session_id, - self.pg0.remote_ip4) - self.pg0.add_stream(tx2) - - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - - rx2 = self.pg1.get_capture(len(tx2)) - self.verify_decapped_pppoe(self.pg0, rx2, tx2) - - tx5 = self.create_stream_pppoe_ip4(self.pg2, self.pg1, - self.pg2.remote_mac, - self.session_id + 1, - self.pg2.remote_ip4) - self.pg2.add_stream(tx5) - - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - - rx5 = self.pg1.get_capture(len(tx5)) - self.verify_decapped_pppoe(self.pg2, rx5, tx5) - - self.logger.info(self.vapi.cli("show pppoe fib")) - self.logger.info(self.vapi.cli("show pppoe session")) - self.logger.info(self.vapi.cli("show ip fib")) - - # - # test case cleanup - # - - # Delete PPPoE session - pppoe_if1.remove_vpp_config() - pppoe_if2.remove_vpp_config() - - # Delete a route that resolves the server's destination - route_sever_dst.remove_vpp_config() - - def test_PPPoE_Encap_Multiple(self): - """ PPPoE Encap Multiple Sessions Test """ - - self.vapi.cli("clear trace") - - # - # Add a route that resolves the server's destination - # - route_sever_dst = VppIpRoute(self, "100.1.1.100", 32, - [VppRoutePath(self.pg1.remote_ip4, - self.pg1.sw_if_index)]) - route_sever_dst.add_vpp_config() - - # Send PPPoE Discovery 1 - tx0 = self.create_stream_pppoe_discovery(self.pg0, self.pg1, - self.pg0.remote_mac) - self.pg0.add_stream(tx0) - self.pg_start() - - # Send PPPoE PPP LCP 1 - tx1 = self.create_stream_pppoe_lcp(self.pg0, self.pg1, - self.pg0.remote_mac, - self.session_id) - self.pg0.add_stream(tx1) - self.pg_start() - - # Create PPPoE session 1 - pppoe_if1 = VppPppoeInterface(self, - self.pg0.remote_ip4, - self.pg0.remote_mac, - self.session_id) - pppoe_if1.add_vpp_config() - - # Send PPPoE Discovery 2 - tx3 = self.create_stream_pppoe_discovery(self.pg2, self.pg1, - self.pg2.remote_mac) - self.pg2.add_stream(tx3) - self.pg_start() - - # Send PPPoE PPP LCP 2 - tx4 = self.create_stream_pppoe_lcp(self.pg2, self.pg1, - self.pg2.remote_mac, - self.session_id + 1) - self.pg2.add_stream(tx4) - self.pg_start() - - # Create PPPoE session 2 - pppoe_if2 = VppPppoeInterface(self, - self.pg2.remote_ip4, - self.pg2.remote_mac, - self.session_id + 1) - pppoe_if2.add_vpp_config() - - # - # Send a packet stream that is routed into the session - # - packets are PPPoE encapped - # - self.vapi.cli("clear trace") - tx2 = self.create_stream_ip4(self.pg1, self.pg0, - self.pg0.remote_ip4, self.dst_ip) - self.pg1.add_stream(tx2) - - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - - rx2 = self.pg0.get_capture(len(tx2)) - self.verify_encaped_pppoe(self.pg1, rx2, tx2, self.session_id) - - tx5 = self.create_stream_ip4(self.pg1, self.pg2, - self.pg2.remote_ip4, self.dst_ip) - self.pg1.add_stream(tx5) - - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - - rx5 = self.pg2.get_capture(len(tx5)) - self.verify_encaped_pppoe(self.pg1, rx5, tx5, self.session_id + 1) - - self.logger.info(self.vapi.cli("show pppoe fib")) - self.logger.info(self.vapi.cli("show pppoe session")) - self.logger.info(self.vapi.cli("show ip fib")) - - # - # test case cleanup - # - - # Delete PPPoE session - pppoe_if1.remove_vpp_config() - pppoe_if2.remove_vpp_config() - - # Delete a route that resolves the server's destination - route_sever_dst.remove_vpp_config() - -if __name__ == '__main__': - unittest.main(testRunner=VppTestRunner) diff --git a/test/test_quic.py b/test/test_quic.py deleted file mode 100644 index bbf7d72b838..00000000000 --- a/test/test_quic.py +++ /dev/null @@ -1,248 +0,0 @@ -#!/usr/bin/env python -""" Vpp QUIC tests """ - -import unittest -import os -import subprocess -import signal -from framework import VppTestCase, VppTestRunner, running_extended_tests, \ - Worker -from vpp_ip_route import VppIpTable, VppIpRoute, VppRoutePath - - -class QUICAppWorker(Worker): - """ QUIC Test Application Worker """ - process = None - - def __init__(self, build_dir, appname, args, logger, env={}): - app = "%s/vpp/bin/%s" % (build_dir, appname) - self.args = [app] + args - super(QUICAppWorker, self).__init__(self.args, logger, env) - - def run(self): - super(QUICAppWorker, self).run() - - def teardown(self, logger, timeout): - if self.process is None: - return False - try: - logger.debug("Killing worker process (pid %d)" % self.process.pid) - os.killpg(os.getpgid(self.process.pid), signal.SIGKILL) - self.join(timeout) - except OSError as e: - logger.debug("Couldn't kill worker process") - return True - return False - - -class QUICTestCase(VppTestCase): - """ QUIC Test Case """ - - def setUp(self): - super(QUICTestCase, self).setUp() - var = "VPP_BUILD_DIR" - self.build_dir = os.getenv(var, None) - if self.build_dir is None: - raise Exception("Environment variable `%s' not set" % var) - self.vppDebug = 'vpp_debug' in self.build_dir - self.timeout = 20 - self.vapi.session_enable_disable(is_enabled=1) - self.pre_test_sleep = 0.3 - self.post_test_sleep = 0.2 - - self.create_loopback_interfaces(2) - self.uri = "quic://%s/1234" % self.loop0.local_ip4 - table_id = 1 - for i in self.lo_interfaces: - i.admin_up() - - if table_id != 0: - tbl = VppIpTable(self, table_id) - tbl.add_vpp_config() - - i.set_table_ip4(table_id) - i.config_ip4() - table_id += 1 - - # Configure namespaces - self.vapi.app_namespace_add_del(namespace_id=b"server", - sw_if_index=self.loop0.sw_if_index) - self.vapi.app_namespace_add_del(namespace_id=b"client", - sw_if_index=self.loop1.sw_if_index) - - # Add inter-table routes - self.ip_t01 = VppIpRoute(self, self.loop1.local_ip4, 32, - [VppRoutePath("0.0.0.0", - 0xffffffff, - nh_table_id=2)], table_id=1) - self.ip_t10 = VppIpRoute(self, self.loop0.local_ip4, 32, - [VppRoutePath("0.0.0.0", - 0xffffffff, - nh_table_id=1)], table_id=2) - self.ip_t01.add_vpp_config() - self.ip_t10.add_vpp_config() - self.logger.debug(self.vapi.cli("show ip fib")) - - def tearDown(self): - self.vapi.session_enable_disable(is_enabled=0) - # Delete inter-table routes - self.ip_t01.remove_vpp_config() - self.ip_t10.remove_vpp_config() - - for i in self.lo_interfaces: - i.unconfig_ip4() - i.set_table_ip4(0) - i.admin_down() - super(QUICTestCase, self).tearDown() - - -class QUICEchoInternalTestCase(QUICTestCase): - """QUIC Echo Internal Test Case""" - - def setUp(self): - super(QUICEchoInternalTestCase, self).setUp() - self.client_args = "uri %s fifo-size 64 test-bytes appns client" \ - % self.uri - self.server_args = "uri %s fifo-size 64 appns server" % self.uri - - def server(self, *args): - error = self.vapi.cli( - "test echo server %s %s" % - (self.server_args, ' '.join(args))) - if error: - self.logger.critical(error) - self.assertNotIn("failed", error) - - def client(self, *args): - error = self.vapi.cli( - "test echo client %s %s" % - (self.client_args, ' '.join(args))) - if error: - self.logger.critical(error) - self.assertNotIn("failed", error) - - -class QUICEchoInternalTransferTestCase(QUICEchoInternalTestCase): - """QUIC Echo Internal Transfer Test Case""" - @unittest.skipUnless(running_extended_tests, "part of extended tests") - def test_quic_internal_transfer(self): - self.server() - self.client("no-output", "mbytes", "2") - - -class QUICEchoInternalSerialTestCase(QUICEchoInternalTestCase): - """QUIC Echo Internal Serial Transfer Test Case""" - @unittest.skipUnless(running_extended_tests, "part of extended tests") - def test_quic_serial_internal_transfer(self): - self.server() - self.client("no-output", "mbytes", "2") - self.client("no-output", "mbytes", "2") - self.client("no-output", "mbytes", "2") - self.client("no-output", "mbytes", "2") - self.client("no-output", "mbytes", "2") - - -class QUICEchoInternalMStreamTestCase(QUICEchoInternalTestCase): - """QUIC Echo Internal MultiStream Test Case""" - @unittest.skipUnless(running_extended_tests, "part of extended tests") - def test_quic_internal_multistream_transfer(self): - self.server() - self.client("nclients", "10", "mbytes", "1", "no-output") - - -class QUICEchoExternalTestCase(QUICTestCase): - extra_vpp_punt_config = ["session", "{", "evt_qs_memfd_seg", "}"] - quic_setup = "default" - - def setUp(self): - super(QUICEchoExternalTestCase, self).setUp() - common_args = [ - "uri", - self.uri, - "fifo-size", - "64", - "test-bytes:assert", - "socket-name", - self.api_sock] - self.server_echo_test_args = common_args + \ - ["server", "appns", "server", "quic-setup", self.quic_setup] - self.client_echo_test_args = common_args + \ - ["client", "appns", "client", "quic-setup", self.quic_setup] - - def server(self, *args): - _args = self.server_echo_test_args + list(args) - self.worker_server = QUICAppWorker( - self.build_dir, - "vpp_echo", - _args, - self.logger) - self.worker_server.start() - self.sleep(self.pre_test_sleep) - - def client(self, *args): - _args = self.client_echo_test_args + list(args) - # self.client_echo_test_args += "use-svm-api" - self.worker_client = QUICAppWorker( - self.build_dir, - "vpp_echo", - _args, - self.logger) - self.worker_client.start() - self.worker_client.join(self.timeout) - self.worker_server.join(self.timeout) - self.sleep(self.post_test_sleep) - - def validate_external_test_results(self): - self.logger.info( - "Client worker result is `%s'" % - self.worker_client.result) - server_result = self.worker_server.result - client_result = self.worker_client.result - server_kill_error = False - if self.worker_server.result is None: - server_kill_error = self.worker_server.teardown( - self.logger, self.timeout) - if self.worker_client.result is None: - self.worker_client.teardown(self.logger, self.timeout) - self.assertEqual(server_result, 0, "Wrong server worker return code") - self.assertIsNotNone( - client_result, - "Timeout! Client worker did not finish in %ss" % - self.timeout) - self.assertEqual(client_result, 0, "Wrong client worker return code") - self.assertFalse(server_kill_error, "Server kill errored") - - -class QUICEchoExternalTransferTestCase(QUICEchoExternalTestCase): - """QUIC Echo External Transfer Test Case""" - @unittest.skipUnless(running_extended_tests, "part of extended tests") - def test_quic_external_transfer(self): - self.server() - self.client() - self.validate_external_test_results() - - -class QUICEchoExternalServerStreamTestCase(QUICEchoExternalTestCase): - """QUIC Echo External Transfer Server Stream Test Case""" - quic_setup = "serverstream" - - @unittest.skipUnless(running_extended_tests, "part of extended tests") - def test_quic_external_transfer_server_stream(self): - self.server("TX=1Kb", "RX=0") - self.client("TX=0", "RX=1Kb") - self.validate_external_test_results() - - -class QUICEchoExternalServerStreamWorkersTestCase(QUICEchoExternalTestCase): - """QUIC Echo External Transfer Server Stream MultiWorker Test Case""" - quic_setup = "serverstream" - - @unittest.skipUnless(running_extended_tests, "part of extended tests") - def test_quic_external_transfer_server_stream_multi_workers(self): - self.server("nclients", "4/4", "TX=1Kb", "RX=0") - self.client("nclients", "4/4", "TX=0", "RX=1Kb") - self.validate_external_test_results() - - -if __name__ == '__main__': - unittest.main(testRunner=VppTestRunner) diff --git a/test/test_sctp.py b/test/test_sctp.py deleted file mode 100644 index 75bbb23f31f..00000000000 --- a/test/test_sctp.py +++ /dev/null @@ -1,92 +0,0 @@ -#!/usr/bin/env python - -import unittest - -from framework import VppTestCase, VppTestRunner -from vpp_ip_route import VppIpTable, VppIpRoute, VppRoutePath - - -class TestSCTP(VppTestCase): - """ SCTP Test Case """ - - @classmethod - def setUpClass(cls): - cls.extra_vpp_plugin_config.append("plugin sctp_plugin.so { enable }") - super(TestSCTP, cls).setUpClass() - - @classmethod - def tearDownClass(cls): - super(TestSCTP, cls).tearDownClass() - - def setUp(self): - super(TestSCTP, self).setUp() - self.vapi.session_enable_disable(is_enabled=1) - self.vapi.cli("sctp enable") - self.create_loopback_interfaces(2) - - table_id = 0 - - for i in self.lo_interfaces: - i.admin_up() - - if table_id != 0: - tbl = VppIpTable(self, table_id) - tbl.add_vpp_config() - - i.set_table_ip4(table_id) - i.config_ip4() - table_id += 1 - - # Configure namespaces - self.vapi.app_namespace_add_del(namespace_id=b"0", - sw_if_index=self.loop0.sw_if_index) - self.vapi.app_namespace_add_del(namespace_id=b"1", - sw_if_index=self.loop1.sw_if_index) - - def tearDown(self): - for i in self.lo_interfaces: - i.unconfig_ip4() - i.set_table_ip4(0) - i.admin_down() - self.vapi.session_enable_disable(is_enabled=0) - super(TestSCTP, self).tearDown() - - def test_sctp_transfer(self): - """ SCTP echo client/server transfer """ - - # Add inter-table routes - ip_t01 = VppIpRoute(self, self.loop1.local_ip4, 32, - [VppRoutePath("0.0.0.0", - 0xffffffff, - nh_table_id=1)]) - ip_t10 = VppIpRoute(self, self.loop0.local_ip4, 32, - [VppRoutePath("0.0.0.0", - 0xffffffff, - nh_table_id=0)], table_id=1) - ip_t01.add_vpp_config() - ip_t10.add_vpp_config() - - # Start builtin server and client - uri = "sctp://" + self.loop0.local_ip4 + "/1234" - error = self.vapi.cli("test echo server appns 0 fifo-size 4 " + - "no-echo uri " + uri) - if error: - self.logger.critical(error) - self.assertNotIn("failed", error) - - error = self.vapi.cli("test echo client mbytes 10 no-return " + - " appns 1" + - " fifo-size 4" + - " no-output test-bytes syn-timeout 3" + - " test-timeout 30" + - " uri " + uri) - if error: - self.logger.critical(error) - self.assertNotIn("failed", error) - - # Delete inter-table routes - ip_t01.remove_vpp_config() - ip_t10.remove_vpp_config() - -if __name__ == '__main__': - unittest.main(testRunner=VppTestRunner) diff --git a/test/test_srv6.py b/test/test_srv6.py deleted file mode 100644 index b3e69724028..00000000000 --- a/test/test_srv6.py +++ /dev/null @@ -1,2141 +0,0 @@ -#!/usr/bin/env python - -import unittest -import binascii -from socket import AF_INET6 - -from framework import VppTestCase, VppTestRunner -from vpp_ip_route import VppIpRoute, VppRoutePath, FibPathProto, VppIpTable -from vpp_srv6 import SRv6LocalSIDBehaviors, VppSRv6LocalSID, VppSRv6Policy, \ - SRv6PolicyType, VppSRv6Steering, SRv6PolicySteeringTypes - -import scapy.compat -from scapy.packet import Raw -from scapy.layers.l2 import Ether, Dot1Q -from scapy.layers.inet6 import IPv6, UDP, IPv6ExtHdrSegmentRouting -from scapy.layers.inet import IP, UDP - -from scapy.utils import inet_pton, inet_ntop - -from util import ppp - - -class TestSRv6(VppTestCase): - """ SRv6 Test Case """ - - @classmethod - def setUpClass(cls): - super(TestSRv6, cls).setUpClass() - - @classmethod - def tearDownClass(cls): - super(TestSRv6, cls).tearDownClass() - - def setUp(self): - """ Perform test setup before each test case. - """ - super(TestSRv6, self).setUp() - - # packet sizes, inclusive L2 overhead - self.pg_packet_sizes = [64, 512, 1518, 9018] - - # reset packet_infos - self.reset_packet_infos() - - def tearDown(self): - """ Clean up test setup after each test case. - """ - self.teardown_interfaces() - - super(TestSRv6, self).tearDown() - - def configure_interface(self, - interface, - ipv6=False, ipv4=False, - ipv6_table_id=0, ipv4_table_id=0): - """ Configure interface. - :param ipv6: configure IPv6 on interface - :param ipv4: configure IPv4 on interface - :param ipv6_table_id: FIB table_id for IPv6 - :param ipv4_table_id: FIB table_id for IPv4 - """ - self.logger.debug("Configuring interface %s" % (interface.name)) - if ipv6: - self.logger.debug("Configuring IPv6") - interface.set_table_ip6(ipv6_table_id) - interface.config_ip6() - interface.resolve_ndp(timeout=5) - if ipv4: - self.logger.debug("Configuring IPv4") - interface.set_table_ip4(ipv4_table_id) - interface.config_ip4() - interface.resolve_arp() - interface.admin_up() - - def setup_interfaces(self, ipv6=[], ipv4=[], - ipv6_table_id=[], ipv4_table_id=[]): - """ Create and configure interfaces. - - :param ipv6: list of interface IPv6 capabilities - :param ipv4: list of interface IPv4 capabilities - :param ipv6_table_id: list of intf IPv6 FIB table_ids - :param ipv4_table_id: list of intf IPv4 FIB table_ids - :returns: List of created interfaces. - """ - # how many interfaces? - if len(ipv6): - count = len(ipv6) - else: - count = len(ipv4) - self.logger.debug("Creating and configuring %d interfaces" % (count)) - - # fill up ipv6 and ipv4 lists if needed - # not enabled (False) is the default - if len(ipv6) < count: - ipv6 += (count - len(ipv6)) * [False] - if len(ipv4) < count: - ipv4 += (count - len(ipv4)) * [False] - - # fill up table_id lists if needed - # table_id 0 (global) is the default - if len(ipv6_table_id) < count: - ipv6_table_id += (count - len(ipv6_table_id)) * [0] - if len(ipv4_table_id) < count: - ipv4_table_id += (count - len(ipv4_table_id)) * [0] - - # create 'count' pg interfaces - self.create_pg_interfaces(range(count)) - - # setup all interfaces - for i in range(count): - intf = self.pg_interfaces[i] - self.configure_interface(intf, - ipv6[i], ipv4[i], - ipv6_table_id[i], ipv4_table_id[i]) - - if any(ipv6): - self.logger.debug(self.vapi.cli("show ip6 neighbors")) - if any(ipv4): - self.logger.debug(self.vapi.cli("show ip arp")) - self.logger.debug(self.vapi.cli("show interface")) - self.logger.debug(self.vapi.cli("show hardware")) - - return self.pg_interfaces - - def teardown_interfaces(self): - """ Unconfigure and bring down interface. - """ - self.logger.debug("Tearing down interfaces") - # tear down all interfaces - # AFAIK they cannot be deleted - for i in self.pg_interfaces: - self.logger.debug("Tear down interface %s" % (i.name)) - i.admin_down() - i.unconfig() - i.set_table_ip4(0) - i.set_table_ip6(0) - - @unittest.skipUnless(0, "PC to fix") - def test_SRv6_T_Encaps(self): - """ Test SRv6 Transit.Encaps behavior for IPv6. - """ - # send traffic to one destination interface - # source and destination are IPv6 only - self.setup_interfaces(ipv6=[True, True]) - - # configure FIB entries - route = VppIpRoute(self, "a4::", 64, - [VppRoutePath(self.pg1.remote_ip6, - self.pg1.sw_if_index)]) - route.add_vpp_config() - - # configure encaps IPv6 source address - # needs to be done before SR Policy config - # TODO: API? - self.vapi.cli("set sr encaps source addr a3::") - - bsid = 'a3::9999:1' - # configure SRv6 Policy - # Note: segment list order: first -> last - sr_policy = VppSRv6Policy( - self, bsid=bsid, - is_encap=1, - sr_type=SRv6PolicyType.SR_POLICY_TYPE_DEFAULT, - weight=1, fib_table=0, - segments=['a4::', 'a5::', 'a6::c7'], - source='a3::') - sr_policy.add_vpp_config() - self.sr_policy = sr_policy - - # log the sr policies - self.logger.info(self.vapi.cli("show sr policies")) - - # steer IPv6 traffic to a7::/64 into SRv6 Policy - # use the bsid of the above self.sr_policy - pol_steering = VppSRv6Steering( - self, - bsid=self.sr_policy.bsid, - prefix="a7::", mask_width=64, - traffic_type=SRv6PolicySteeringTypes.SR_STEER_IPV6, - sr_policy_index=0, table_id=0, - sw_if_index=0) - pol_steering.add_vpp_config() - - # log the sr steering policies - self.logger.info(self.vapi.cli("show sr steering policies")) - - # create packets - count = len(self.pg_packet_sizes) - dst_inner = 'a7::1234' - pkts = [] - - # create IPv6 packets without SRH - packet_header = self.create_packet_header_IPv6(dst_inner) - # create traffic stream pg0->pg1 - pkts.extend(self.create_stream(self.pg0, self.pg1, packet_header, - self.pg_packet_sizes, count)) - - # create IPv6 packets with SRH - # packets with segments-left 1, active segment a7:: - packet_header = self.create_packet_header_IPv6_SRH( - sidlist=['a8::', 'a7::', 'a6::'], - segleft=1) - # create traffic stream pg0->pg1 - pkts.extend(self.create_stream(self.pg0, self.pg1, packet_header, - self.pg_packet_sizes, count)) - - # create IPv6 packets with SRH and IPv6 - # packets with segments-left 1, active segment a7:: - packet_header = self.create_packet_header_IPv6_SRH_IPv6( - dst_inner, - sidlist=['a8::', 'a7::', 'a6::'], - segleft=1) - # create traffic stream pg0->pg1 - pkts.extend(self.create_stream(self.pg0, self.pg1, packet_header, - self.pg_packet_sizes, count)) - - # send packets and verify received packets - self.send_and_verify_pkts(self.pg0, pkts, self.pg1, - self.compare_rx_tx_packet_T_Encaps) - - # log the localsid counters - self.logger.info(self.vapi.cli("show sr localsid")) - - # remove SR steering - pol_steering.remove_vpp_config() - self.logger.info(self.vapi.cli("show sr steering policies")) - - # remove SR Policies - self.sr_policy.remove_vpp_config() - self.logger.info(self.vapi.cli("show sr policies")) - - # remove FIB entries - # done by tearDown - - # cleanup interfaces - self.teardown_interfaces() - - @unittest.skipUnless(0, "PC to fix") - def test_SRv6_T_Insert(self): - """ Test SRv6 Transit.Insert behavior (IPv6 only). - """ - # send traffic to one destination interface - # source and destination are IPv6 only - self.setup_interfaces(ipv6=[True, True]) - - # configure FIB entries - route = VppIpRoute(self, "a4::", 64, - [VppRoutePath(self.pg1.remote_ip6, - self.pg1.sw_if_index)]) - route.add_vpp_config() - - # configure encaps IPv6 source address - # needs to be done before SR Policy config - # TODO: API? - self.vapi.cli("set sr encaps source addr a3::") - - bsid = 'a3::9999:1' - # configure SRv6 Policy - # Note: segment list order: first -> last - sr_policy = VppSRv6Policy( - self, bsid=bsid, - is_encap=0, - sr_type=SRv6PolicyType.SR_POLICY_TYPE_DEFAULT, - weight=1, fib_table=0, - segments=['a4::', 'a5::', 'a6::c7'], - source='a3::') - sr_policy.add_vpp_config() - self.sr_policy = sr_policy - - # log the sr policies - self.logger.info(self.vapi.cli("show sr policies")) - - # steer IPv6 traffic to a7::/64 into SRv6 Policy - # use the bsid of the above self.sr_policy - pol_steering = VppSRv6Steering( - self, - bsid=self.sr_policy.bsid, - prefix="a7::", mask_width=64, - traffic_type=SRv6PolicySteeringTypes.SR_STEER_IPV6, - sr_policy_index=0, table_id=0, - sw_if_index=0) - pol_steering.add_vpp_config() - - # log the sr steering policies - self.logger.info(self.vapi.cli("show sr steering policies")) - - # create packets - count = len(self.pg_packet_sizes) - dst_inner = 'a7::1234' - pkts = [] - - # create IPv6 packets without SRH - packet_header = self.create_packet_header_IPv6(dst_inner) - # create traffic stream pg0->pg1 - pkts.extend(self.create_stream(self.pg0, self.pg1, packet_header, - self.pg_packet_sizes, count)) - - # create IPv6 packets with SRH - # packets with segments-left 1, active segment a7:: - packet_header = self.create_packet_header_IPv6_SRH( - sidlist=['a8::', 'a7::', 'a6::'], - segleft=1) - # create traffic stream pg0->pg1 - pkts.extend(self.create_stream(self.pg0, self.pg1, packet_header, - self.pg_packet_sizes, count)) - - # send packets and verify received packets - self.send_and_verify_pkts(self.pg0, pkts, self.pg1, - self.compare_rx_tx_packet_T_Insert) - - # log the localsid counters - self.logger.info(self.vapi.cli("show sr localsid")) - - # remove SR steering - pol_steering.remove_vpp_config() - self.logger.info(self.vapi.cli("show sr steering policies")) - - # remove SR Policies - self.sr_policy.remove_vpp_config() - self.logger.info(self.vapi.cli("show sr policies")) - - # remove FIB entries - # done by tearDown - - # cleanup interfaces - self.teardown_interfaces() - - @unittest.skipUnless(0, "PC to fix") - def test_SRv6_T_Encaps_IPv4(self): - """ Test SRv6 Transit.Encaps behavior for IPv4. - """ - # send traffic to one destination interface - # source interface is IPv4 only - # destination interface is IPv6 only - self.setup_interfaces(ipv6=[False, True], ipv4=[True, False]) - - # configure FIB entries - route = VppIpRoute(self, "a4::", 64, - [VppRoutePath(self.pg1.remote_ip6, - self.pg1.sw_if_index)]) - route.add_vpp_config() - - # configure encaps IPv6 source address - # needs to be done before SR Policy config - # TODO: API? - self.vapi.cli("set sr encaps source addr a3::") - - bsid = 'a3::9999:1' - # configure SRv6 Policy - # Note: segment list order: first -> last - sr_policy = VppSRv6Policy( - self, bsid=bsid, - is_encap=1, - sr_type=SRv6PolicyType.SR_POLICY_TYPE_DEFAULT, - weight=1, fib_table=0, - segments=['a4::', 'a5::', 'a6::c7'], - source='a3::') - sr_policy.add_vpp_config() - self.sr_policy = sr_policy - - # log the sr policies - self.logger.info(self.vapi.cli("show sr policies")) - - # steer IPv4 traffic to 7.1.1.0/24 into SRv6 Policy - # use the bsid of the above self.sr_policy - pol_steering = VppSRv6Steering( - self, - bsid=self.sr_policy.bsid, - prefix="7.1.1.0", mask_width=24, - traffic_type=SRv6PolicySteeringTypes.SR_STEER_IPV4, - sr_policy_index=0, table_id=0, - sw_if_index=0) - pol_steering.add_vpp_config() - - # log the sr steering policies - self.logger.info(self.vapi.cli("show sr steering policies")) - - # create packets - count = len(self.pg_packet_sizes) - dst_inner = '7.1.1.123' - pkts = [] - - # create IPv4 packets - packet_header = self.create_packet_header_IPv4(dst_inner) - # create traffic stream pg0->pg1 - pkts.extend(self.create_stream(self.pg0, self.pg1, packet_header, - self.pg_packet_sizes, count)) - - # send packets and verify received packets - self.send_and_verify_pkts(self.pg0, pkts, self.pg1, - self.compare_rx_tx_packet_T_Encaps_IPv4) - - # log the localsid counters - self.logger.info(self.vapi.cli("show sr localsid")) - - # remove SR steering - pol_steering.remove_vpp_config() - self.logger.info(self.vapi.cli("show sr steering policies")) - - # remove SR Policies - self.sr_policy.remove_vpp_config() - self.logger.info(self.vapi.cli("show sr policies")) - - # remove FIB entries - # done by tearDown - - # cleanup interfaces - self.teardown_interfaces() - - @unittest.skip("VPP crashes after running this test") - def test_SRv6_T_Encaps_L2(self): - """ Test SRv6 Transit.Encaps behavior for L2. - """ - # send traffic to one destination interface - # source interface is IPv4 only TODO? - # destination interface is IPv6 only - self.setup_interfaces(ipv6=[False, True], ipv4=[False, False]) - - # configure FIB entries - route = VppIpRoute(self, "a4::", 64, - [VppRoutePath(self.pg1.remote_ip6, - self.pg1.sw_if_index)]) - route.add_vpp_config() - - # configure encaps IPv6 source address - # needs to be done before SR Policy config - # TODO: API? - self.vapi.cli("set sr encaps source addr a3::") - - bsid = 'a3::9999:1' - # configure SRv6 Policy - # Note: segment list order: first -> last - sr_policy = VppSRv6Policy( - self, bsid=bsid, - is_encap=1, - sr_type=SRv6PolicyType.SR_POLICY_TYPE_DEFAULT, - weight=1, fib_table=0, - segments=['a4::', 'a5::', 'a6::c7'], - source='a3::') - sr_policy.add_vpp_config() - self.sr_policy = sr_policy - - # log the sr policies - self.logger.info(self.vapi.cli("show sr policies")) - - # steer L2 traffic into SRv6 Policy - # use the bsid of the above self.sr_policy - pol_steering = VppSRv6Steering( - self, - bsid=self.sr_policy.bsid, - prefix="::", mask_width=0, - traffic_type=SRv6PolicySteeringTypes.SR_STEER_L2, - sr_policy_index=0, table_id=0, - sw_if_index=self.pg0.sw_if_index) - pol_steering.add_vpp_config() - - # log the sr steering policies - self.logger.info(self.vapi.cli("show sr steering policies")) - - # create packets - count = len(self.pg_packet_sizes) - pkts = [] - - # create L2 packets without dot1q header - packet_header = self.create_packet_header_L2() - # create traffic stream pg0->pg1 - pkts.extend(self.create_stream(self.pg0, self.pg1, packet_header, - self.pg_packet_sizes, count)) - - # create L2 packets with dot1q header - packet_header = self.create_packet_header_L2(vlan=123) - # create traffic stream pg0->pg1 - pkts.extend(self.create_stream(self.pg0, self.pg1, packet_header, - self.pg_packet_sizes, count)) - - # send packets and verify received packets - self.send_and_verify_pkts(self.pg0, pkts, self.pg1, - self.compare_rx_tx_packet_T_Encaps_L2) - - # log the localsid counters - self.logger.info(self.vapi.cli("show sr localsid")) - - # remove SR steering - pol_steering.remove_vpp_config() - self.logger.info(self.vapi.cli("show sr steering policies")) - - # remove SR Policies - self.sr_policy.remove_vpp_config() - self.logger.info(self.vapi.cli("show sr policies")) - - # remove FIB entries - # done by tearDown - - # cleanup interfaces - self.teardown_interfaces() - - def test_SRv6_End(self): - """ Test SRv6 End (without PSP) behavior. - """ - # send traffic to one destination interface - # source and destination interfaces are IPv6 only - self.setup_interfaces(ipv6=[True, True]) - - # configure FIB entries - route = VppIpRoute(self, "a4::", 64, - [VppRoutePath(self.pg1.remote_ip6, - self.pg1.sw_if_index)]) - route.add_vpp_config() - - # configure SRv6 localSID End without PSP behavior - localsid = VppSRv6LocalSID( - self, localsid={'addr': 'A3::0'}, - behavior=SRv6LocalSIDBehaviors.SR_BEHAVIOR_END, - nh_addr4='0.0.0.0', - nh_addr6='::', - end_psp=0, - sw_if_index=0, - vlan_index=0, - fib_table=0) - localsid.add_vpp_config() - # log the localsids - self.logger.debug(self.vapi.cli("show sr localsid")) - - # create IPv6 packets with SRH (SL=2, SL=1, SL=0) - # send one packet per SL value per packet size - # SL=0 packet with localSID End with USP needs 2nd SRH - count = len(self.pg_packet_sizes) - dst_inner = 'a4::1234' - pkts = [] - - # packets with segments-left 2, active segment a3:: - packet_header = self.create_packet_header_IPv6_SRH_IPv6( - dst_inner, - sidlist=['a5::', 'a4::', 'a3::'], - segleft=2) - # create traffic stream pg0->pg1 - pkts.extend(self.create_stream(self.pg0, self.pg1, packet_header, - self.pg_packet_sizes, count)) - - # packets with segments-left 1, active segment a3:: - packet_header = self.create_packet_header_IPv6_SRH_IPv6( - dst_inner, - sidlist=['a4::', 'a3::', 'a2::'], - segleft=1) - # add to traffic stream pg0->pg1 - pkts.extend(self.create_stream(self.pg0, self.pg1, packet_header, - self.pg_packet_sizes, count)) - - # TODO: test behavior with SL=0 packet (needs 2*SRH?) - - # send packets and verify received packets - self.send_and_verify_pkts(self.pg0, pkts, self.pg1, - self.compare_rx_tx_packet_End) - - # log the localsid counters - self.logger.info(self.vapi.cli("show sr localsid")) - - # remove SRv6 localSIDs - localsid.remove_vpp_config() - - # remove FIB entries - # done by tearDown - - # cleanup interfaces - self.teardown_interfaces() - - def test_SRv6_End_with_PSP(self): - """ Test SRv6 End with PSP behavior. - """ - # send traffic to one destination interface - # source and destination interfaces are IPv6 only - self.setup_interfaces(ipv6=[True, True]) - - # configure FIB entries - route = VppIpRoute(self, "a4::", 64, - [VppRoutePath(self.pg1.remote_ip6, - self.pg1.sw_if_index)]) - route.add_vpp_config() - - # configure SRv6 localSID End with PSP behavior - localsid = VppSRv6LocalSID( - self, localsid={'addr': 'A3::0'}, - behavior=SRv6LocalSIDBehaviors.SR_BEHAVIOR_END, - nh_addr4='0.0.0.0', - nh_addr6='::', - end_psp=1, - sw_if_index=0, - vlan_index=0, - fib_table=0) - localsid.add_vpp_config() - # log the localsids - self.logger.debug(self.vapi.cli("show sr localsid")) - - # create IPv6 packets with SRH (SL=2, SL=1) - # send one packet per SL value per packet size - # SL=0 packet with localSID End with PSP is dropped - count = len(self.pg_packet_sizes) - dst_inner = 'a4::1234' - pkts = [] - - # packets with segments-left 2, active segment a3:: - packet_header = self.create_packet_header_IPv6_SRH_IPv6( - dst_inner, - sidlist=['a5::', 'a4::', 'a3::'], - segleft=2) - # create traffic stream pg0->pg1 - pkts.extend(self.create_stream(self.pg0, self.pg1, packet_header, - self.pg_packet_sizes, count)) - - # packets with segments-left 1, active segment a3:: - packet_header = self.create_packet_header_IPv6_SRH_IPv6( - dst_inner, - sidlist=['a4::', 'a3::', 'a2::'], - segleft=1) - # add to traffic stream pg0->pg1 - pkts.extend(self.create_stream(self.pg0, self.pg1, packet_header, - self.pg_packet_sizes, count)) - - # send packets and verify received packets - self.send_and_verify_pkts(self.pg0, pkts, self.pg1, - self.compare_rx_tx_packet_End_PSP) - - # log the localsid counters - self.logger.info(self.vapi.cli("show sr localsid")) - - # remove SRv6 localSIDs - localsid.remove_vpp_config() - - # remove FIB entries - # done by tearDown - - # cleanup interfaces - self.teardown_interfaces() - - def test_SRv6_End_X(self): - """ Test SRv6 End.X (without PSP) behavior. - """ - # create three interfaces (1 source, 2 destinations) - # source and destination interfaces are IPv6 only - self.setup_interfaces(ipv6=[True, True, True]) - - # configure FIB entries - # a4::/64 via pg1 and pg2 - route = VppIpRoute(self, "a4::", 64, - [VppRoutePath(self.pg1.remote_ip6, - self.pg1.sw_if_index), - VppRoutePath(self.pg2.remote_ip6, - self.pg2.sw_if_index)]) - route.add_vpp_config() - self.logger.debug(self.vapi.cli("show ip6 fib")) - - # configure SRv6 localSID End.X without PSP behavior - # End.X points to interface pg1 - localsid = VppSRv6LocalSID( - self, localsid={'addr': 'A3::C4'}, - behavior=SRv6LocalSIDBehaviors.SR_BEHAVIOR_X, - nh_addr4='0.0.0.0', - nh_addr6=self.pg1.remote_ip6, - end_psp=0, - sw_if_index=self.pg1.sw_if_index, - vlan_index=0, - fib_table=0) - localsid.add_vpp_config() - # log the localsids - self.logger.debug(self.vapi.cli("show sr localsid")) - - # create IPv6 packets with SRH (SL=2, SL=1) - # send one packet per SL value per packet size - # SL=0 packet with localSID End with PSP is dropped - count = len(self.pg_packet_sizes) - dst_inner = 'a4::1234' - pkts = [] - - # packets with segments-left 2, active segment a3::c4 - packet_header = self.create_packet_header_IPv6_SRH_IPv6( - dst_inner, - sidlist=['a5::', 'a4::', 'a3::c4'], - segleft=2) - # create traffic stream pg0->pg1 - pkts.extend(self.create_stream(self.pg0, self.pg1, packet_header, - self.pg_packet_sizes, count)) - - # packets with segments-left 1, active segment a3::c4 - packet_header = self.create_packet_header_IPv6_SRH_IPv6( - dst_inner, - sidlist=['a4::', 'a3::c4', 'a2::'], - segleft=1) - # add to traffic stream pg0->pg1 - pkts.extend(self.create_stream(self.pg0, self.pg1, packet_header, - self.pg_packet_sizes, count)) - - # send packets and verify received packets - # using same comparison function as End (no PSP) - self.send_and_verify_pkts(self.pg0, pkts, self.pg1, - self.compare_rx_tx_packet_End) - - # assert nothing was received on the other interface (pg2) - self.pg2.assert_nothing_captured("mis-directed packet(s)") - - # log the localsid counters - self.logger.info(self.vapi.cli("show sr localsid")) - - # remove SRv6 localSIDs - localsid.remove_vpp_config() - - # remove FIB entries - # done by tearDown - - # cleanup interfaces - self.teardown_interfaces() - - def test_SRv6_End_X_with_PSP(self): - """ Test SRv6 End.X with PSP behavior. - """ - # create three interfaces (1 source, 2 destinations) - # source and destination interfaces are IPv6 only - self.setup_interfaces(ipv6=[True, True, True]) - - # configure FIB entries - # a4::/64 via pg1 and pg2 - route = VppIpRoute(self, "a4::", 64, - [VppRoutePath( - self.pg1.remote_ip6, - self.pg1.sw_if_index), - VppRoutePath(self.pg2.remote_ip6, - self.pg2.sw_if_index)]) - route.add_vpp_config() - - # configure SRv6 localSID End with PSP behavior - localsid = VppSRv6LocalSID( - self, localsid={'addr': 'A3::C4'}, - behavior=SRv6LocalSIDBehaviors.SR_BEHAVIOR_X, - nh_addr4='0.0.0.0', - nh_addr6=self.pg1.remote_ip6, - end_psp=1, - sw_if_index=self.pg1.sw_if_index, - vlan_index=0, - fib_table=0) - localsid.add_vpp_config() - # log the localsids - self.logger.debug(self.vapi.cli("show sr localsid")) - - # create IPv6 packets with SRH (SL=2, SL=1) - # send one packet per SL value per packet size - # SL=0 packet with localSID End with PSP is dropped - count = len(self.pg_packet_sizes) - dst_inner = 'a4::1234' - pkts = [] - - # packets with segments-left 2, active segment a3:: - packet_header = self.create_packet_header_IPv6_SRH_IPv6( - dst_inner, - sidlist=['a5::', 'a4::', 'a3::c4'], - segleft=2) - # create traffic stream pg0->pg1 - pkts.extend(self.create_stream(self.pg0, self.pg1, packet_header, - self.pg_packet_sizes, count)) - - # packets with segments-left 1, active segment a3:: - packet_header = self.create_packet_header_IPv6_SRH_IPv6( - dst_inner, - sidlist=['a4::', 'a3::c4', 'a2::'], - segleft=1) - # add to traffic stream pg0->pg1 - pkts.extend(self.create_stream(self.pg0, self.pg1, packet_header, - self.pg_packet_sizes, count)) - - # send packets and verify received packets - # using same comparison function as End with PSP - self.send_and_verify_pkts(self.pg0, pkts, self.pg1, - self.compare_rx_tx_packet_End_PSP) - - # assert nothing was received on the other interface (pg2) - self.pg2.assert_nothing_captured("mis-directed packet(s)") - - # log the localsid counters - self.logger.info(self.vapi.cli("show sr localsid")) - - # remove SRv6 localSIDs - localsid.remove_vpp_config() - - # remove FIB entries - # done by tearDown - - # cleanup interfaces - self.teardown_interfaces() - - def test_SRv6_End_DX6(self): - """ Test SRv6 End.DX6 behavior. - """ - # send traffic to one destination interface - # source and destination interfaces are IPv6 only - self.setup_interfaces(ipv6=[True, True]) - - # configure SRv6 localSID End.DX6 behavior - localsid = VppSRv6LocalSID( - self, localsid={'addr': 'A3::C4'}, - behavior=SRv6LocalSIDBehaviors.SR_BEHAVIOR_DX6, - nh_addr4='0.0.0.0', - nh_addr6=self.pg1.remote_ip6, - end_psp=0, - sw_if_index=self.pg1.sw_if_index, - vlan_index=0, - fib_table=0) - localsid.add_vpp_config() - # log the localsids - self.logger.debug(self.vapi.cli("show sr localsid")) - - # create IPv6 packets with SRH (SL=0) - # send one packet per packet size - count = len(self.pg_packet_sizes) - dst_inner = 'a4::1234' # inner header destination address - pkts = [] - - # packets with SRH, segments-left 0, active segment a3::c4 - packet_header = self.create_packet_header_IPv6_SRH_IPv6( - dst_inner, - sidlist=['a3::c4', 'a2::', 'a1::'], - segleft=0) - # add to traffic stream pg0->pg1 - pkts.extend(self.create_stream(self.pg0, self.pg1, packet_header, - self.pg_packet_sizes, count)) - - # packets without SRH, IPv6 in IPv6 - # outer IPv6 dest addr is the localsid End.DX6 - packet_header = self.create_packet_header_IPv6_IPv6( - dst_inner, - dst_outer='a3::c4') - # add to traffic stream pg0->pg1 - pkts.extend(self.create_stream(self.pg0, self.pg1, packet_header, - self.pg_packet_sizes, count)) - - # send packets and verify received packets - self.send_and_verify_pkts(self.pg0, pkts, self.pg1, - self.compare_rx_tx_packet_End_DX6) - - # log the localsid counters - self.logger.info(self.vapi.cli("show sr localsid")) - - # remove SRv6 localSIDs - localsid.remove_vpp_config() - - # cleanup interfaces - self.teardown_interfaces() - - def test_SRv6_End_DT6(self): - """ Test SRv6 End.DT6 behavior. - """ - # create three interfaces (1 source, 2 destinations) - # all interfaces are IPv6 only - # source interface in global FIB (0) - # destination interfaces in global and vrf - vrf_1 = 1 - ipt = VppIpTable(self, vrf_1, is_ip6=True) - ipt.add_vpp_config() - self.setup_interfaces(ipv6=[True, True, True], - ipv6_table_id=[0, 0, vrf_1]) - - # configure FIB entries - # a4::/64 is reachable - # via pg1 in table 0 (global) - # and via pg2 in table vrf_1 - route0 = VppIpRoute(self, "a4::", 64, - [VppRoutePath(self.pg1.remote_ip6, - self.pg1.sw_if_index, - nh_table_id=0)], - table_id=0) - route0.add_vpp_config() - route1 = VppIpRoute(self, "a4::", 64, - [VppRoutePath(self.pg2.remote_ip6, - self.pg2.sw_if_index, - nh_table_id=vrf_1)], - table_id=vrf_1) - route1.add_vpp_config() - self.logger.debug(self.vapi.cli("show ip6 fib")) - - # configure SRv6 localSID End.DT6 behavior - # Note: - # fib_table: where the localsid is installed - # sw_if_index: in T-variants of localsid this is the vrf table_id - localsid = VppSRv6LocalSID( - self, localsid={'addr': 'A3::C4'}, - behavior=SRv6LocalSIDBehaviors.SR_BEHAVIOR_DT6, - nh_addr4='0.0.0.0', - nh_addr6='::', - end_psp=0, - sw_if_index=vrf_1, - vlan_index=0, - fib_table=0) - localsid.add_vpp_config() - # log the localsids - self.logger.debug(self.vapi.cli("show sr localsid")) - - # create IPv6 packets with SRH (SL=0) - # send one packet per packet size - count = len(self.pg_packet_sizes) - dst_inner = 'a4::1234' # inner header destination address - pkts = [] - - # packets with SRH, segments-left 0, active segment a3::c4 - packet_header = self.create_packet_header_IPv6_SRH_IPv6( - dst_inner, - sidlist=['a3::c4', 'a2::', 'a1::'], - segleft=0) - # add to traffic stream pg0->pg1 - pkts.extend(self.create_stream(self.pg0, self.pg2, packet_header, - self.pg_packet_sizes, count)) - - # packets without SRH, IPv6 in IPv6 - # outer IPv6 dest addr is the localsid End.DT6 - packet_header = self.create_packet_header_IPv6_IPv6( - dst_inner, - dst_outer='a3::c4') - # add to traffic stream pg0->pg1 - pkts.extend(self.create_stream(self.pg0, self.pg2, packet_header, - self.pg_packet_sizes, count)) - - # send packets and verify received packets - # using same comparison function as End.DX6 - self.send_and_verify_pkts(self.pg0, pkts, self.pg2, - self.compare_rx_tx_packet_End_DX6) - - # assert nothing was received on the other interface (pg2) - self.pg1.assert_nothing_captured("mis-directed packet(s)") - - # log the localsid counters - self.logger.info(self.vapi.cli("show sr localsid")) - - # remove SRv6 localSIDs - localsid.remove_vpp_config() - - # remove FIB entries - # done by tearDown - - # cleanup interfaces - self.teardown_interfaces() - - def test_SRv6_End_DX4(self): - """ Test SRv6 End.DX4 behavior. - """ - # send traffic to one destination interface - # source interface is IPv6 only - # destination interface is IPv4 only - self.setup_interfaces(ipv6=[True, False], ipv4=[False, True]) - - # configure SRv6 localSID End.DX4 behavior - localsid = VppSRv6LocalSID( - self, localsid={'addr': 'A3::C4'}, - behavior=SRv6LocalSIDBehaviors.SR_BEHAVIOR_DX4, - nh_addr4=self.pg1.remote_ip4, - nh_addr6='::', - end_psp=0, - sw_if_index=self.pg1.sw_if_index, - vlan_index=0, - fib_table=0) - localsid.add_vpp_config() - # log the localsids - self.logger.debug(self.vapi.cli("show sr localsid")) - - # send one packet per packet size - count = len(self.pg_packet_sizes) - dst_inner = '4.1.1.123' # inner header destination address - pkts = [] - - # packets with SRH, segments-left 0, active segment a3::c4 - packet_header = self.create_packet_header_IPv6_SRH_IPv4( - dst_inner, - sidlist=['a3::c4', 'a2::', 'a1::'], - segleft=0) - # add to traffic stream pg0->pg1 - pkts.extend(self.create_stream(self.pg0, self.pg1, packet_header, - self.pg_packet_sizes, count)) - - # packets without SRH, IPv4 in IPv6 - # outer IPv6 dest addr is the localsid End.DX4 - packet_header = self.create_packet_header_IPv6_IPv4( - dst_inner, - dst_outer='a3::c4') - # add to traffic stream pg0->pg1 - pkts.extend(self.create_stream(self.pg0, self.pg1, packet_header, - self.pg_packet_sizes, count)) - - # send packets and verify received packets - self.send_and_verify_pkts(self.pg0, pkts, self.pg1, - self.compare_rx_tx_packet_End_DX4) - - # log the localsid counters - self.logger.info(self.vapi.cli("show sr localsid")) - - # remove SRv6 localSIDs - localsid.remove_vpp_config() - - # cleanup interfaces - self.teardown_interfaces() - - def test_SRv6_End_DT4(self): - """ Test SRv6 End.DT4 behavior. - """ - # create three interfaces (1 source, 2 destinations) - # source interface is IPv6-only - # destination interfaces are IPv4 only - # source interface in global FIB (0) - # destination interfaces in global and vrf - vrf_1 = 1 - ipt = VppIpTable(self, vrf_1) - ipt.add_vpp_config() - self.setup_interfaces(ipv6=[True, False, False], - ipv4=[False, True, True], - ipv6_table_id=[0, 0, 0], - ipv4_table_id=[0, 0, vrf_1]) - - # configure FIB entries - # 4.1.1.0/24 is reachable - # via pg1 in table 0 (global) - # and via pg2 in table vrf_1 - route0 = VppIpRoute(self, "4.1.1.0", 24, - [VppRoutePath(self.pg1.remote_ip4, - self.pg1.sw_if_index, - nh_table_id=0)], - table_id=0) - route0.add_vpp_config() - route1 = VppIpRoute(self, "4.1.1.0", 24, - [VppRoutePath(self.pg2.remote_ip4, - self.pg2.sw_if_index, - nh_table_id=vrf_1)], - table_id=vrf_1) - route1.add_vpp_config() - self.logger.debug(self.vapi.cli("show ip fib")) - - # configure SRv6 localSID End.DT6 behavior - # Note: - # fib_table: where the localsid is installed - # sw_if_index: in T-variants of localsid: vrf table_id - localsid = VppSRv6LocalSID( - self, localsid={'addr': 'A3::C4'}, - behavior=SRv6LocalSIDBehaviors.SR_BEHAVIOR_DT4, - nh_addr4='0.0.0.0', - nh_addr6='::', - end_psp=0, - sw_if_index=vrf_1, - vlan_index=0, - fib_table=0) - localsid.add_vpp_config() - # log the localsids - self.logger.debug(self.vapi.cli("show sr localsid")) - - # create IPv6 packets with SRH (SL=0) - # send one packet per packet size - count = len(self.pg_packet_sizes) - dst_inner = '4.1.1.123' # inner header destination address - pkts = [] - - # packets with SRH, segments-left 0, active segment a3::c4 - packet_header = self.create_packet_header_IPv6_SRH_IPv4( - dst_inner, - sidlist=['a3::c4', 'a2::', 'a1::'], - segleft=0) - # add to traffic stream pg0->pg1 - pkts.extend(self.create_stream(self.pg0, self.pg2, packet_header, - self.pg_packet_sizes, count)) - - # packets without SRH, IPv6 in IPv6 - # outer IPv6 dest addr is the localsid End.DX4 - packet_header = self.create_packet_header_IPv6_IPv4( - dst_inner, - dst_outer='a3::c4') - # add to traffic stream pg0->pg1 - pkts.extend(self.create_stream(self.pg0, self.pg2, packet_header, - self.pg_packet_sizes, count)) - - # send packets and verify received packets - # using same comparison function as End.DX4 - self.send_and_verify_pkts(self.pg0, pkts, self.pg2, - self.compare_rx_tx_packet_End_DX4) - - # assert nothing was received on the other interface (pg2) - self.pg1.assert_nothing_captured("mis-directed packet(s)") - - # log the localsid counters - self.logger.info(self.vapi.cli("show sr localsid")) - - # remove SRv6 localSIDs - localsid.remove_vpp_config() - - # remove FIB entries - # done by tearDown - - # cleanup interfaces - self.teardown_interfaces() - - def test_SRv6_End_DX2(self): - """ Test SRv6 End.DX2 behavior. - """ - # send traffic to one destination interface - # source interface is IPv6 only - self.setup_interfaces(ipv6=[True, False], ipv4=[False, False]) - - # configure SRv6 localSID End.DX2 behavior - localsid = VppSRv6LocalSID( - self, localsid={'addr': 'A3::C4'}, - behavior=SRv6LocalSIDBehaviors.SR_BEHAVIOR_DX2, - nh_addr4='0.0.0.0', - nh_addr6='::', - end_psp=0, - sw_if_index=self.pg1.sw_if_index, - vlan_index=0, - fib_table=0) - localsid.add_vpp_config() - # log the localsids - self.logger.debug(self.vapi.cli("show sr localsid")) - - # send one packet per packet size - count = len(self.pg_packet_sizes) - pkts = [] - - # packets with SRH, segments-left 0, active segment a3::c4 - # L2 has no dot1q header - packet_header = self.create_packet_header_IPv6_SRH_L2( - sidlist=['a3::c4', 'a2::', 'a1::'], - segleft=0, - vlan=0) - # add to traffic stream pg0->pg1 - pkts.extend(self.create_stream(self.pg0, self.pg1, packet_header, - self.pg_packet_sizes, count)) - - # packets with SRH, segments-left 0, active segment a3::c4 - # L2 has dot1q header - packet_header = self.create_packet_header_IPv6_SRH_L2( - sidlist=['a3::c4', 'a2::', 'a1::'], - segleft=0, - vlan=123) - # add to traffic stream pg0->pg1 - pkts.extend(self.create_stream(self.pg0, self.pg1, packet_header, - self.pg_packet_sizes, count)) - - # packets without SRH, L2 in IPv6 - # outer IPv6 dest addr is the localsid End.DX2 - # L2 has no dot1q header - packet_header = self.create_packet_header_IPv6_L2( - dst_outer='a3::c4', - vlan=0) - # add to traffic stream pg0->pg1 - pkts.extend(self.create_stream(self.pg0, self.pg1, packet_header, - self.pg_packet_sizes, count)) - - # packets without SRH, L2 in IPv6 - # outer IPv6 dest addr is the localsid End.DX2 - # L2 has dot1q header - packet_header = self.create_packet_header_IPv6_L2( - dst_outer='a3::c4', - vlan=123) - # add to traffic stream pg0->pg1 - pkts.extend(self.create_stream(self.pg0, self.pg1, packet_header, - self.pg_packet_sizes, count)) - - # send packets and verify received packets - self.send_and_verify_pkts(self.pg0, pkts, self.pg1, - self.compare_rx_tx_packet_End_DX2) - - # log the localsid counters - self.logger.info(self.vapi.cli("show sr localsid")) - - # remove SRv6 localSIDs - localsid.remove_vpp_config() - - # cleanup interfaces - self.teardown_interfaces() - - @unittest.skipUnless(0, "PC to fix") - def test_SRv6_T_Insert_Classifier(self): - """ Test SRv6 Transit.Insert behavior (IPv6 only). - steer packets using the classifier - """ - # send traffic to one destination interface - # source and destination are IPv6 only - self.setup_interfaces(ipv6=[False, False, False, True, True]) - - # configure FIB entries - route = VppIpRoute(self, "a4::", 64, - [VppRoutePath( - self.pg4.remote_ip6, - self.pg4.sw_if_index)]) - route.add_vpp_config() - - # configure encaps IPv6 source address - # needs to be done before SR Policy config - # TODO: API? - self.vapi.cli("set sr encaps source addr a3::") - - bsid = 'a3::9999:1' - # configure SRv6 Policy - # Note: segment list order: first -> last - sr_policy = VppSRv6Policy( - self, bsid=bsid, - is_encap=0, - sr_type=SRv6PolicyType.SR_POLICY_TYPE_DEFAULT, - weight=1, fib_table=0, - segments=['a4::', 'a5::', 'a6::c7'], - source='a3::') - sr_policy.add_vpp_config() - self.sr_policy = sr_policy - - # log the sr policies - self.logger.info(self.vapi.cli("show sr policies")) - - # add classify table - # mask on dst ip address prefix a7::/8 - mask = '{!s:0<16}'.format('ff') - r = self.vapi.classify_add_del_table( - 1, - binascii.unhexlify(mask), - match_n_vectors=(len(mask) - 1) // 32 + 1, - current_data_flag=1, - skip_n_vectors=2) # data offset - self.assertIsNotNone(r, 'No response msg for add_del_table') - table_index = r.new_table_index - - # add the source routing node as a ip6 inacl netxt node - r = self.vapi.add_node_next('ip6-inacl', - 'sr-pl-rewrite-insert') - inacl_next_node_index = r.node_index - - match = '{!s:0<16}'.format('a7') - r = self.vapi.classify_add_del_session( - 1, - table_index, - binascii.unhexlify(match), - hit_next_index=inacl_next_node_index, - action=3, - metadata=0) # sr policy index - self.assertIsNotNone(r, 'No response msg for add_del_session') - - # log the classify table used in the steering policy - self.logger.info(self.vapi.cli("show classify table")) - - r = self.vapi.input_acl_set_interface( - is_add=1, - sw_if_index=self.pg3.sw_if_index, - ip6_table_index=table_index) - self.assertIsNotNone(r, - 'No response msg for input_acl_set_interface') - - # log the ip6 inacl - self.logger.info(self.vapi.cli("show inacl type ip6")) - - # create packets - count = len(self.pg_packet_sizes) - dst_inner = 'a7::1234' - pkts = [] - - # create IPv6 packets without SRH - packet_header = self.create_packet_header_IPv6(dst_inner) - # create traffic stream pg3->pg4 - pkts.extend(self.create_stream(self.pg3, self.pg4, packet_header, - self.pg_packet_sizes, count)) - - # create IPv6 packets with SRH - # packets with segments-left 1, active segment a7:: - packet_header = self.create_packet_header_IPv6_SRH( - sidlist=['a8::', 'a7::', 'a6::'], - segleft=1) - # create traffic stream pg3->pg4 - pkts.extend(self.create_stream(self.pg3, self.pg4, packet_header, - self.pg_packet_sizes, count)) - - # send packets and verify received packets - self.send_and_verify_pkts(self.pg3, pkts, self.pg4, - self.compare_rx_tx_packet_T_Insert) - - # remove the interface l2 input feature - r = self.vapi.input_acl_set_interface( - is_add=0, - sw_if_index=self.pg3.sw_if_index, - ip6_table_index=table_index) - self.assertIsNotNone(r, - 'No response msg for input_acl_set_interface') - - # log the ip6 inacl after cleaning - self.logger.info(self.vapi.cli("show inacl type ip6")) - - # log the localsid counters - self.logger.info(self.vapi.cli("show sr localsid")) - - # remove classifier SR steering - # classifier_steering.remove_vpp_config() - self.logger.info(self.vapi.cli("show sr steering policies")) - - # remove SR Policies - self.sr_policy.remove_vpp_config() - self.logger.info(self.vapi.cli("show sr policies")) - - # remove classify session and table - r = self.vapi.classify_add_del_session( - 0, - table_index, - binascii.unhexlify(match)) - self.assertIsNotNone(r, 'No response msg for add_del_session') - - r = self.vapi.classify_add_del_table( - 0, - binascii.unhexlify(mask), - table_index=table_index) - self.assertIsNotNone(r, 'No response msg for add_del_table') - - self.logger.info(self.vapi.cli("show classify table")) - - # remove FIB entries - # done by tearDown - - # cleanup interfaces - self.teardown_interfaces() - - def compare_rx_tx_packet_T_Encaps(self, tx_pkt, rx_pkt): - """ Compare input and output packet after passing T.Encaps - - :param tx_pkt: transmitted packet - :param rx_pkt: received packet - """ - # T.Encaps updates the headers as follows: - # SR Policy seglist (S3, S2, S1) - # SR Policy source C - # IPv6: - # in: IPv6(A, B2) - # out: IPv6(C, S1)SRH(S3, S2, S1; SL=2)IPv6(A, B2) - # IPv6 + SRH: - # in: IPv6(A, B2)SRH(B3, B2, B1; SL=1) - # out: IPv6(C, S1)SRH(S3, S2, S1; SL=2)IPv6(a, B2)SRH(B3, B2, B1; SL=1) - - # get first (outer) IPv6 header of rx'ed packet - rx_ip = rx_pkt.getlayer(IPv6) - rx_srh = None - - tx_ip = tx_pkt.getlayer(IPv6) - - # expected segment-list - seglist = self.sr_policy.segments - # reverse list to get order as in SRH - tx_seglist = seglist[::-1] - - # get source address of SR Policy - sr_policy_source = self.sr_policy.source - - # rx'ed packet should have SRH - self.assertTrue(rx_pkt.haslayer(IPv6ExtHdrSegmentRouting)) - # get SRH - rx_srh = rx_pkt.getlayer(IPv6ExtHdrSegmentRouting) - - # received ip.src should be equal to SR Policy source - self.assertEqual(rx_ip.src, sr_policy_source) - # received ip.dst should be equal to expected sidlist[lastentry] - self.assertEqual(rx_ip.dst, tx_seglist[-1]) - # rx'ed seglist should be equal to expected seglist - self.assertEqual(rx_srh.addresses, tx_seglist) - # segleft should be equal to size expected seglist-1 - self.assertEqual(rx_srh.segleft, len(tx_seglist)-1) - # segleft should be equal to lastentry - self.assertEqual(rx_srh.segleft, rx_srh.lastentry) - - # the whole rx'ed pkt beyond SRH should be equal to tx'ed pkt - # except for the hop-limit field - # -> update tx'ed hlim to the expected hlim - tx_ip.hlim = tx_ip.hlim - 1 - - self.assertEqual(rx_srh.payload, tx_ip) - - self.logger.debug("packet verification: SUCCESS") - - def compare_rx_tx_packet_T_Encaps_IPv4(self, tx_pkt, rx_pkt): - """ Compare input and output packet after passing T.Encaps for IPv4 - - :param tx_pkt: transmitted packet - :param rx_pkt: received packet - """ - # T.Encaps for IPv4 updates the headers as follows: - # SR Policy seglist (S3, S2, S1) - # SR Policy source C - # IPv4: - # in: IPv4(A, B2) - # out: IPv6(C, S1)SRH(S3, S2, S1; SL=2)IPv4(A, B2) - - # get first (outer) IPv6 header of rx'ed packet - rx_ip = rx_pkt.getlayer(IPv6) - rx_srh = None - - tx_ip = tx_pkt.getlayer(IP) - - # expected segment-list - seglist = self.sr_policy.segments - # reverse list to get order as in SRH - tx_seglist = seglist[::-1] - - # get source address of SR Policy - sr_policy_source = self.sr_policy.source - - # checks common to cases tx with and without SRH - # rx'ed packet should have SRH and IPv4 header - self.assertTrue(rx_pkt.haslayer(IPv6ExtHdrSegmentRouting)) - self.assertTrue(rx_ip.payload.haslayer(IP)) - # get SRH - rx_srh = rx_pkt.getlayer(IPv6ExtHdrSegmentRouting) - - # received ip.src should be equal to SR Policy source - self.assertEqual(rx_ip.src, sr_policy_source) - # received ip.dst should be equal to sidlist[lastentry] - self.assertEqual(rx_ip.dst, tx_seglist[-1]) - # rx'ed seglist should be equal to seglist - self.assertEqual(rx_srh.addresses, tx_seglist) - # segleft should be equal to size seglist-1 - self.assertEqual(rx_srh.segleft, len(tx_seglist)-1) - # segleft should be equal to lastentry - self.assertEqual(rx_srh.segleft, rx_srh.lastentry) - - # the whole rx'ed pkt beyond SRH should be equal to tx'ed pkt - # except for the ttl field and ip checksum - # -> adjust tx'ed ttl to expected ttl - tx_ip.ttl = tx_ip.ttl - 1 - # -> set tx'ed ip checksum to None and let scapy recompute - tx_ip.chksum = None - # read back the pkt (with str()) to force computing these fields - # probably other ways to accomplish this are possible - tx_ip = IP(scapy.compat.raw(tx_ip)) - - self.assertEqual(rx_srh.payload, tx_ip) - - self.logger.debug("packet verification: SUCCESS") - - def compare_rx_tx_packet_T_Encaps_L2(self, tx_pkt, rx_pkt): - """ Compare input and output packet after passing T.Encaps for L2 - - :param tx_pkt: transmitted packet - :param rx_pkt: received packet - """ - # T.Encaps for L2 updates the headers as follows: - # SR Policy seglist (S3, S2, S1) - # SR Policy source C - # L2: - # in: L2 - # out: IPv6(C, S1)SRH(S3, S2, S1; SL=2)L2 - - # get first (outer) IPv6 header of rx'ed packet - rx_ip = rx_pkt.getlayer(IPv6) - rx_srh = None - - tx_ether = tx_pkt.getlayer(Ether) - - # expected segment-list - seglist = self.sr_policy.segments - # reverse list to get order as in SRH - tx_seglist = seglist[::-1] - - # get source address of SR Policy - sr_policy_source = self.sr_policy.source - - # rx'ed packet should have SRH - self.assertTrue(rx_pkt.haslayer(IPv6ExtHdrSegmentRouting)) - # get SRH - rx_srh = rx_pkt.getlayer(IPv6ExtHdrSegmentRouting) - - # received ip.src should be equal to SR Policy source - self.assertEqual(rx_ip.src, sr_policy_source) - # received ip.dst should be equal to sidlist[lastentry] - self.assertEqual(rx_ip.dst, tx_seglist[-1]) - # rx'ed seglist should be equal to seglist - self.assertEqual(rx_srh.addresses, tx_seglist) - # segleft should be equal to size seglist-1 - self.assertEqual(rx_srh.segleft, len(tx_seglist)-1) - # segleft should be equal to lastentry - self.assertEqual(rx_srh.segleft, rx_srh.lastentry) - # nh should be "No Next Header" (59) - self.assertEqual(rx_srh.nh, 59) - - # the whole rx'ed pkt beyond SRH should be equal to tx'ed pkt - self.assertEqual(Ether(scapy.compat.raw(rx_srh.payload)), tx_ether) - - self.logger.debug("packet verification: SUCCESS") - - def compare_rx_tx_packet_T_Insert(self, tx_pkt, rx_pkt): - """ Compare input and output packet after passing T.Insert - - :param tx_pkt: transmitted packet - :param rx_pkt: received packet - """ - # T.Insert updates the headers as follows: - # IPv6: - # in: IPv6(A, B2) - # out: IPv6(A, S1)SRH(B2, S3, S2, S1; SL=3) - # IPv6 + SRH: - # in: IPv6(A, B2)SRH(B3, B2, B1; SL=1) - # out: IPv6(A, S1)SRH(B2, S3, S2, S1; SL=3)SRH(B3, B2, B1; SL=1) - - # get first (outer) IPv6 header of rx'ed packet - rx_ip = rx_pkt.getlayer(IPv6) - rx_srh = None - rx_ip2 = None - rx_srh2 = None - rx_ip3 = None - rx_udp = rx_pkt[UDP] - - tx_ip = tx_pkt.getlayer(IPv6) - tx_srh = None - tx_ip2 = None - # some packets have been tx'ed with an SRH, some without it - # get SRH if tx'ed packet has it - if tx_pkt.haslayer(IPv6ExtHdrSegmentRouting): - tx_srh = tx_pkt.getlayer(IPv6ExtHdrSegmentRouting) - tx_ip2 = tx_pkt.getlayer(IPv6, 2) - tx_udp = tx_pkt[UDP] - - # expected segment-list (make copy of SR Policy segment list) - seglist = self.sr_policy.segments[:] - # expected seglist has initial dest addr as last segment - seglist.append(tx_ip.dst) - # reverse list to get order as in SRH - tx_seglist = seglist[::-1] - - # get source address of SR Policy - sr_policy_source = self.sr_policy.source - - # checks common to cases tx with and without SRH - # rx'ed packet should have SRH and only one IPv6 header - self.assertTrue(rx_pkt.haslayer(IPv6ExtHdrSegmentRouting)) - self.assertFalse(rx_ip.payload.haslayer(IPv6)) - # get SRH - rx_srh = rx_pkt.getlayer(IPv6ExtHdrSegmentRouting) - - # rx'ed ip.src should be equal to tx'ed ip.src - self.assertEqual(rx_ip.src, tx_ip.src) - # rx'ed ip.dst should be equal to sidlist[lastentry] - self.assertEqual(rx_ip.dst, tx_seglist[-1]) - - # rx'ed seglist should be equal to expected seglist - self.assertEqual(rx_srh.addresses, tx_seglist) - # segleft should be equal to size(expected seglist)-1 - self.assertEqual(rx_srh.segleft, len(tx_seglist)-1) - # segleft should be equal to lastentry - self.assertEqual(rx_srh.segleft, rx_srh.lastentry) - - if tx_srh: # packet was tx'ed with SRH - # packet should have 2nd SRH - self.assertTrue(rx_srh.payload.haslayer(IPv6ExtHdrSegmentRouting)) - # get 2nd SRH - rx_srh2 = rx_pkt.getlayer(IPv6ExtHdrSegmentRouting, 2) - - # rx'ed srh2.addresses should be equal to tx'ed srh.addresses - self.assertEqual(rx_srh2.addresses, tx_srh.addresses) - # rx'ed srh2.segleft should be equal to tx'ed srh.segleft - self.assertEqual(rx_srh2.segleft, tx_srh.segleft) - # rx'ed srh2.lastentry should be equal to tx'ed srh.lastentry - self.assertEqual(rx_srh2.lastentry, tx_srh.lastentry) - - else: # packet was tx'ed without SRH - # rx packet should have no other SRH - self.assertFalse(rx_srh.payload.haslayer(IPv6ExtHdrSegmentRouting)) - - # UDP layer should be unchanged - self.assertEqual(rx_udp, tx_udp) - - self.logger.debug("packet verification: SUCCESS") - - def compare_rx_tx_packet_End(self, tx_pkt, rx_pkt): - """ Compare input and output packet after passing End (without PSP) - - :param tx_pkt: transmitted packet - :param rx_pkt: received packet - """ - # End (no PSP) updates the headers as follows: - # IPv6 + SRH: - # in: IPv6(A, S1)SRH(S3, S2, S1; SL=2) - # out: IPv6(A, S2)SRH(S3, S2, S1; SL=1) - - # get first (outer) IPv6 header of rx'ed packet - rx_ip = rx_pkt.getlayer(IPv6) - rx_srh = None - rx_ip2 = None - rx_udp = rx_pkt[UDP] - - tx_ip = tx_pkt.getlayer(IPv6) - # we know the packet has been tx'ed - # with an inner IPv6 header and an SRH - tx_ip2 = tx_pkt.getlayer(IPv6, 2) - tx_srh = tx_pkt.getlayer(IPv6ExtHdrSegmentRouting) - tx_udp = tx_pkt[UDP] - - # common checks, regardless of tx segleft value - # rx'ed packet should have 2nd IPv6 header - self.assertTrue(rx_ip.payload.haslayer(IPv6)) - # get second (inner) IPv6 header - rx_ip2 = rx_pkt.getlayer(IPv6, 2) - - if tx_ip.segleft > 0: - # SRH should NOT have been popped: - # End SID without PSP does not pop SRH if segleft>0 - self.assertTrue(rx_pkt.haslayer(IPv6ExtHdrSegmentRouting)) - rx_srh = rx_pkt.getlayer(IPv6ExtHdrSegmentRouting) - - # received ip.src should be equal to expected ip.src - self.assertEqual(rx_ip.src, tx_ip.src) - # sidlist should be unchanged - self.assertEqual(rx_srh.addresses, tx_srh.addresses) - # segleft should have been decremented - self.assertEqual(rx_srh.segleft, tx_srh.segleft-1) - # received ip.dst should be equal to sidlist[segleft] - self.assertEqual(rx_ip.dst, rx_srh.addresses[rx_srh.segleft]) - # lastentry should be unchanged - self.assertEqual(rx_srh.lastentry, tx_srh.lastentry) - # inner IPv6 packet (ip2) should be unchanged - self.assertEqual(rx_ip2.src, tx_ip2.src) - self.assertEqual(rx_ip2.dst, tx_ip2.dst) - # else: # tx_ip.segleft == 0 - # TODO: Does this work with 2 SRHs in ingress packet? - - # UDP layer should be unchanged - self.assertEqual(rx_udp, tx_udp) - - self.logger.debug("packet verification: SUCCESS") - - def compare_rx_tx_packet_End_PSP(self, tx_pkt, rx_pkt): - """ Compare input and output packet after passing End with PSP - - :param tx_pkt: transmitted packet - :param rx_pkt: received packet - """ - # End (PSP) updates the headers as follows: - # IPv6 + SRH (SL>1): - # in: IPv6(A, S1)SRH(S3, S2, S1; SL=2) - # out: IPv6(A, S2)SRH(S3, S2, S1; SL=1) - # IPv6 + SRH (SL=1): - # in: IPv6(A, S2)SRH(S3, S2, S1; SL=1) - # out: IPv6(A, S3) - - # get first (outer) IPv6 header of rx'ed packet - rx_ip = rx_pkt.getlayer(IPv6) - rx_srh = None - rx_ip2 = None - rx_udp = rx_pkt[UDP] - - tx_ip = tx_pkt.getlayer(IPv6) - # we know the packet has been tx'ed - # with an inner IPv6 header and an SRH - tx_ip2 = tx_pkt.getlayer(IPv6, 2) - tx_srh = tx_pkt.getlayer(IPv6ExtHdrSegmentRouting) - tx_udp = tx_pkt[UDP] - - # common checks, regardless of tx segleft value - self.assertTrue(rx_ip.payload.haslayer(IPv6)) - rx_ip2 = rx_pkt.getlayer(IPv6, 2) - # inner IPv6 packet (ip2) should be unchanged - self.assertEqual(rx_ip2.src, tx_ip2.src) - self.assertEqual(rx_ip2.dst, tx_ip2.dst) - - if tx_ip.segleft > 1: - # SRH should NOT have been popped: - # End SID with PSP does not pop SRH if segleft>1 - # rx'ed packet should have SRH - self.assertTrue(rx_pkt.haslayer(IPv6ExtHdrSegmentRouting)) - rx_srh = rx_pkt.getlayer(IPv6ExtHdrSegmentRouting) - - # received ip.src should be equal to expected ip.src - self.assertEqual(rx_ip.src, tx_ip.src) - # sidlist should be unchanged - self.assertEqual(rx_srh.addresses, tx_srh.addresses) - # segleft should have been decremented - self.assertEqual(rx_srh.segleft, tx_srh.segleft-1) - # received ip.dst should be equal to sidlist[segleft] - self.assertEqual(rx_ip.dst, rx_srh.addresses[rx_srh.segleft]) - # lastentry should be unchanged - self.assertEqual(rx_srh.lastentry, tx_srh.lastentry) - - else: # tx_ip.segleft <= 1 - # SRH should have been popped: - # End SID with PSP and segleft=1 pops SRH - # the two IPv6 headers are still present - # outer IPv6 header has DA == last segment of popped SRH - # SRH should not be present - self.assertFalse(rx_pkt.haslayer(IPv6ExtHdrSegmentRouting)) - # outer IPv6 header ip.src should be equal to tx'ed ip.src - self.assertEqual(rx_ip.src, tx_ip.src) - # outer IPv6 header ip.dst should be = to tx'ed sidlist[segleft-1] - self.assertEqual(rx_ip.dst, tx_srh.addresses[tx_srh.segleft-1]) - - # UDP layer should be unchanged - self.assertEqual(rx_udp, tx_udp) - - self.logger.debug("packet verification: SUCCESS") - - def compare_rx_tx_packet_End_DX6(self, tx_pkt, rx_pkt): - """ Compare input and output packet after passing End.DX6 - - :param tx_pkt: transmitted packet - :param rx_pkt: received packet - """ - # End.DX6 updates the headers as follows: - # IPv6 + SRH (SL=0): - # in: IPv6(A, S3)SRH(S3, S2, S1; SL=0)IPv6(B, D) - # out: IPv6(B, D) - # IPv6: - # in: IPv6(A, S3)IPv6(B, D) - # out: IPv6(B, D) - - # get first (outer) IPv6 header of rx'ed packet - rx_ip = rx_pkt.getlayer(IPv6) - - tx_ip = tx_pkt.getlayer(IPv6) - tx_ip2 = tx_pkt.getlayer(IPv6, 2) - - # verify if rx'ed packet has no SRH - self.assertFalse(rx_pkt.haslayer(IPv6ExtHdrSegmentRouting)) - - # the whole rx_ip pkt should be equal to tx_ip2 - # except for the hlim field - # -> adjust tx'ed hlim to expected hlim - tx_ip2.hlim = tx_ip2.hlim - 1 - - self.assertEqual(rx_ip, tx_ip2) - - self.logger.debug("packet verification: SUCCESS") - - def compare_rx_tx_packet_End_DX4(self, tx_pkt, rx_pkt): - """ Compare input and output packet after passing End.DX4 - - :param tx_pkt: transmitted packet - :param rx_pkt: received packet - """ - # End.DX4 updates the headers as follows: - # IPv6 + SRH (SL=0): - # in: IPv6(A, S3)SRH(S3, S2, S1; SL=0)IPv4(B, D) - # out: IPv4(B, D) - # IPv6: - # in: IPv6(A, S3)IPv4(B, D) - # out: IPv4(B, D) - - # get IPv4 header of rx'ed packet - rx_ip = rx_pkt.getlayer(IP) - - tx_ip = tx_pkt.getlayer(IPv6) - tx_ip2 = tx_pkt.getlayer(IP) - - # verify if rx'ed packet has no SRH - self.assertFalse(rx_pkt.haslayer(IPv6ExtHdrSegmentRouting)) - - # the whole rx_ip pkt should be equal to tx_ip2 - # except for the ttl field and ip checksum - # -> adjust tx'ed ttl to expected ttl - tx_ip2.ttl = tx_ip2.ttl - 1 - # -> set tx'ed ip checksum to None and let scapy recompute - tx_ip2.chksum = None - # read back the pkt (with str()) to force computing these fields - # probably other ways to accomplish this are possible - tx_ip2 = IP(scapy.compat.raw(tx_ip2)) - - self.assertEqual(rx_ip, tx_ip2) - - self.logger.debug("packet verification: SUCCESS") - - def compare_rx_tx_packet_End_DX2(self, tx_pkt, rx_pkt): - """ Compare input and output packet after passing End.DX2 - - :param tx_pkt: transmitted packet - :param rx_pkt: received packet - """ - # End.DX2 updates the headers as follows: - # IPv6 + SRH (SL=0): - # in: IPv6(A, S3)SRH(S3, S2, S1; SL=0)L2 - # out: L2 - # IPv6: - # in: IPv6(A, S3)L2 - # out: L2 - - # get IPv4 header of rx'ed packet - rx_eth = rx_pkt.getlayer(Ether) - - tx_ip = tx_pkt.getlayer(IPv6) - # we can't just get the 2nd Ether layer - # get the Raw content and dissect it as Ether - tx_eth1 = Ether(scapy.compat.raw(tx_pkt[Raw])) - - # verify if rx'ed packet has no SRH - self.assertFalse(rx_pkt.haslayer(IPv6ExtHdrSegmentRouting)) - - # the whole rx_eth pkt should be equal to tx_eth1 - self.assertEqual(rx_eth, tx_eth1) - - self.logger.debug("packet verification: SUCCESS") - - def create_stream(self, src_if, dst_if, packet_header, packet_sizes, - count): - """Create SRv6 input packet stream for defined interface. - - :param VppInterface src_if: Interface to create packet stream for - :param VppInterface dst_if: destination interface of packet stream - :param packet_header: Layer3 scapy packet headers, - L2 is added when not provided, - Raw(payload) with packet_info is added - :param list packet_sizes: packet stream pckt sizes,sequentially applied - to packets in stream have - :param int count: number of packets in packet stream - :return: list of packets - """ - self.logger.info("Creating packets") - pkts = [] - for i in range(0, count-1): - payload_info = self.create_packet_info(src_if, dst_if) - self.logger.debug( - "Creating packet with index %d" % (payload_info.index)) - payload = self.info_to_payload(payload_info) - # add L2 header if not yet provided in packet_header - if packet_header.getlayer(0).name == 'Ethernet': - p = (packet_header / - Raw(payload)) - else: - p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) / - packet_header / - Raw(payload)) - size = packet_sizes[i % len(packet_sizes)] - self.logger.debug("Packet size %d" % (size)) - self.extend_packet(p, size) - # we need to store the packet with the automatic fields computed - # read back the dumped packet (with str()) - # to force computing these fields - # probably other ways are possible - p = Ether(scapy.compat.raw(p)) - payload_info.data = p.copy() - self.logger.debug(ppp("Created packet:", p)) - pkts.append(p) - self.logger.info("Done creating packets") - return pkts - - def send_and_verify_pkts(self, input, pkts, output, compare_func): - """Send packets and verify received packets using compare_func - - :param input: ingress interface of DUT - :param pkts: list of packets to transmit - :param output: egress interface of DUT - :param compare_func: function to compare in and out packets - """ - # add traffic stream to input interface - input.add_stream(pkts) - - # enable capture on all interfaces - self.pg_enable_capture(self.pg_interfaces) - - # start traffic - self.logger.info("Starting traffic") - self.pg_start() - - # get output capture - self.logger.info("Getting packet capture") - capture = output.get_capture() - - # assert nothing was captured on input interface - input.assert_nothing_captured() - - # verify captured packets - self.verify_captured_pkts(output, capture, compare_func) - - def create_packet_header_IPv6(self, dst): - """Create packet header: IPv6 header, UDP header - - :param dst: IPv6 destination address - - IPv6 source address is 1234::1 - UDP source port and destination port are 1234 - """ - - p = (IPv6(src='1234::1', dst=dst) / - UDP(sport=1234, dport=1234)) - return p - - def create_packet_header_IPv6_SRH(self, sidlist, segleft): - """Create packet header: IPv6 header with SRH, UDP header - - :param list sidlist: segment list - :param int segleft: segments-left field value - - IPv6 destination address is set to sidlist[segleft] - IPv6 source addresses are 1234::1 and 4321::1 - UDP source port and destination port are 1234 - """ - - p = (IPv6(src='1234::1', dst=sidlist[segleft]) / - IPv6ExtHdrSegmentRouting(addresses=sidlist) / - UDP(sport=1234, dport=1234)) - return p - - def create_packet_header_IPv6_SRH_IPv6(self, dst, sidlist, segleft): - """Create packet header: IPv6 encapsulated in SRv6: - IPv6 header with SRH, IPv6 header, UDP header - - :param ipv6address dst: inner IPv6 destination address - :param list sidlist: segment list of outer IPv6 SRH - :param int segleft: segments-left field of outer IPv6 SRH - - Outer IPv6 destination address is set to sidlist[segleft] - IPv6 source addresses are 1234::1 and 4321::1 - UDP source port and destination port are 1234 - """ - - p = (IPv6(src='1234::1', dst=sidlist[segleft]) / - IPv6ExtHdrSegmentRouting(addresses=sidlist, - segleft=segleft, nh=41) / - IPv6(src='4321::1', dst=dst) / - UDP(sport=1234, dport=1234)) - return p - - def create_packet_header_IPv6_IPv6(self, dst_inner, dst_outer): - """Create packet header: IPv6 encapsulated in IPv6: - IPv6 header, IPv6 header, UDP header - - :param ipv6address dst_inner: inner IPv6 destination address - :param ipv6address dst_outer: outer IPv6 destination address - - IPv6 source addresses are 1234::1 and 4321::1 - UDP source port and destination port are 1234 - """ - - p = (IPv6(src='1234::1', dst=dst_outer) / - IPv6(src='4321::1', dst=dst_inner) / - UDP(sport=1234, dport=1234)) - return p - - def create_packet_header_IPv6_SRH_SRH_IPv6(self, dst, sidlist1, segleft1, - sidlist2, segleft2): - """Create packet header: IPv6 encapsulated in SRv6 with 2 SRH: - IPv6 header with SRH, 2nd SRH, IPv6 header, UDP header - - :param ipv6address dst: inner IPv6 destination address - :param list sidlist1: segment list of outer IPv6 SRH - :param int segleft1: segments-left field of outer IPv6 SRH - :param list sidlist2: segment list of inner IPv6 SRH - :param int segleft2: segments-left field of inner IPv6 SRH - - Outer IPv6 destination address is set to sidlist[segleft] - IPv6 source addresses are 1234::1 and 4321::1 - UDP source port and destination port are 1234 - """ - - p = (IPv6(src='1234::1', dst=sidlist1[segleft1]) / - IPv6ExtHdrSegmentRouting(addresses=sidlist1, - segleft=segleft1, nh=43) / - IPv6ExtHdrSegmentRouting(addresses=sidlist2, - segleft=segleft2, nh=41) / - IPv6(src='4321::1', dst=dst) / - UDP(sport=1234, dport=1234)) - return p - - def create_packet_header_IPv4(self, dst): - """Create packet header: IPv4 header, UDP header - - :param dst: IPv4 destination address - - IPv4 source address is 123.1.1.1 - UDP source port and destination port are 1234 - """ - - p = (IP(src='123.1.1.1', dst=dst) / - UDP(sport=1234, dport=1234)) - return p - - def create_packet_header_IPv6_IPv4(self, dst_inner, dst_outer): - """Create packet header: IPv4 encapsulated in IPv6: - IPv6 header, IPv4 header, UDP header - - :param ipv4address dst_inner: inner IPv4 destination address - :param ipv6address dst_outer: outer IPv6 destination address - - IPv6 source address is 1234::1 - IPv4 source address is 123.1.1.1 - UDP source port and destination port are 1234 - """ - - p = (IPv6(src='1234::1', dst=dst_outer) / - IP(src='123.1.1.1', dst=dst_inner) / - UDP(sport=1234, dport=1234)) - return p - - def create_packet_header_IPv6_SRH_IPv4(self, dst, sidlist, segleft): - """Create packet header: IPv4 encapsulated in SRv6: - IPv6 header with SRH, IPv4 header, UDP header - - :param ipv4address dst: inner IPv4 destination address - :param list sidlist: segment list of outer IPv6 SRH - :param int segleft: segments-left field of outer IPv6 SRH - - Outer IPv6 destination address is set to sidlist[segleft] - IPv6 source address is 1234::1 - IPv4 source address is 123.1.1.1 - UDP source port and destination port are 1234 - """ - - p = (IPv6(src='1234::1', dst=sidlist[segleft]) / - IPv6ExtHdrSegmentRouting(addresses=sidlist, - segleft=segleft, nh=4) / - IP(src='123.1.1.1', dst=dst) / - UDP(sport=1234, dport=1234)) - return p - - def create_packet_header_L2(self, vlan=0): - """Create packet header: L2 header - - :param vlan: if vlan!=0 then add 802.1q header - """ - # Note: the dst addr ('00:55:44:33:22:11') is used in - # the compare function compare_rx_tx_packet_T_Encaps_L2 - # to detect presence of L2 in SRH payload - p = Ether(src='00:11:22:33:44:55', dst='00:55:44:33:22:11') - etype = 0x8137 # IPX - if vlan: - # add 802.1q layer - p /= Dot1Q(vlan=vlan, type=etype) - else: - p.type = etype - return p - - def create_packet_header_IPv6_SRH_L2(self, sidlist, segleft, vlan=0): - """Create packet header: L2 encapsulated in SRv6: - IPv6 header with SRH, L2 - - :param list sidlist: segment list of outer IPv6 SRH - :param int segleft: segments-left field of outer IPv6 SRH - :param vlan: L2 vlan; if vlan!=0 then add 802.1q header - - Outer IPv6 destination address is set to sidlist[segleft] - IPv6 source address is 1234::1 - """ - eth = Ether(src='00:11:22:33:44:55', dst='00:55:44:33:22:11') - etype = 0x8137 # IPX - if vlan: - # add 802.1q layer - eth /= Dot1Q(vlan=vlan, type=etype) - else: - eth.type = etype - - p = (IPv6(src='1234::1', dst=sidlist[segleft]) / - IPv6ExtHdrSegmentRouting(addresses=sidlist, - segleft=segleft, nh=59) / - eth) - return p - - def create_packet_header_IPv6_L2(self, dst_outer, vlan=0): - """Create packet header: L2 encapsulated in IPv6: - IPv6 header, L2 - - :param ipv6address dst_outer: outer IPv6 destination address - :param vlan: L2 vlan; if vlan!=0 then add 802.1q header - """ - eth = Ether(src='00:11:22:33:44:55', dst='00:55:44:33:22:11') - etype = 0x8137 # IPX - if vlan: - # add 802.1q layer - eth /= Dot1Q(vlan=vlan, type=etype) - else: - eth.type = etype - - p = (IPv6(src='1234::1', dst=dst_outer, nh=59) / eth) - return p - - def get_payload_info(self, packet): - """ Extract the payload_info from the packet - """ - # in most cases, payload_info is in packet[Raw] - # but packet[Raw] gives the complete payload - # (incl L2 header) for the T.Encaps L2 case - try: - payload_info = self.payload_to_info(packet[Raw]) - - except: - # remote L2 header from packet[Raw]: - # take packet[Raw], convert it to an Ether layer - # and then extract Raw from it - payload_info = self.payload_to_info( - Ether(scapy.compat.r(packet[Raw]))[Raw]) - - return payload_info - - def verify_captured_pkts(self, dst_if, capture, compare_func): - """ - Verify captured packet stream for specified interface. - Compare ingress with egress packets using the specified compare fn - - :param dst_if: egress interface of DUT - :param capture: captured packets - :param compare_func: function to compare in and out packet - """ - self.logger.info("Verifying capture on interface %s using function %s" - % (dst_if.name, compare_func.__name__)) - - last_info = dict() - for i in self.pg_interfaces: - last_info[i.sw_if_index] = None - dst_sw_if_index = dst_if.sw_if_index - - for packet in capture: - try: - # extract payload_info from packet's payload - payload_info = self.get_payload_info(packet) - packet_index = payload_info.index - - self.logger.debug("Verifying packet with index %d" - % (packet_index)) - # packet should have arrived on the expected interface - self.assertEqual(payload_info.dst, dst_sw_if_index) - self.logger.debug( - "Got packet on interface %s: src=%u (idx=%u)" % - (dst_if.name, payload_info.src, packet_index)) - - # search for payload_info with same src and dst if_index - # this will give us the transmitted packet - next_info = self.get_next_packet_info_for_interface2( - payload_info.src, dst_sw_if_index, - last_info[payload_info.src]) - last_info[payload_info.src] = next_info - # next_info should not be None - self.assertTrue(next_info is not None) - # index of tx and rx packets should be equal - self.assertEqual(packet_index, next_info.index) - # data field of next_info contains the tx packet - txed_packet = next_info.data - - self.logger.debug(ppp("Transmitted packet:", - txed_packet)) # ppp=Pretty Print Packet - - self.logger.debug(ppp("Received packet:", packet)) - - # compare rcvd packet with expected packet using compare_func - compare_func(txed_packet, packet) - - except: - self.logger.error(ppp("Unexpected or invalid packet:", packet)) - raise - - # have all expected packets arrived? - for i in self.pg_interfaces: - remaining_packet = self.get_next_packet_info_for_interface2( - i.sw_if_index, dst_sw_if_index, last_info[i.sw_if_index]) - self.assertTrue(remaining_packet is None, - "Interface %s: Packet expected from interface %s " - "didn't arrive" % (dst_if.name, i.name)) - - -if __name__ == '__main__': - unittest.main(testRunner=VppTestRunner) diff --git a/test/test_srv6_ad.py b/test/test_srv6_ad.py deleted file mode 100644 index aa4b8d3c088..00000000000 --- a/test/test_srv6_ad.py +++ /dev/null @@ -1,811 +0,0 @@ -#!/usr/bin/env python - -import unittest -import binascii -from socket import AF_INET6 - -from framework import VppTestCase, VppTestRunner -from vpp_ip import DpoProto -from vpp_ip_route import VppIpRoute, VppRoutePath, VppIpTable -from vpp_srv6 import SRv6LocalSIDBehaviors, VppSRv6LocalSID, VppSRv6Policy, \ - SRv6PolicyType, VppSRv6Steering, SRv6PolicySteeringTypes - -import scapy.compat -from scapy.packet import Raw -from scapy.layers.l2 import Ether, Dot1Q -from scapy.layers.inet6 import IPv6, UDP, IPv6ExtHdrSegmentRouting -from scapy.layers.inet import IP, UDP - -from scapy.utils import inet_pton, inet_ntop - -from util import ppp - - -class TestSRv6(VppTestCase): - """ SRv6 Dynamic Proxy plugin Test Case """ - - @classmethod - def setUpClass(self): - super(TestSRv6, self).setUpClass() - - @classmethod - def tearDownClass(cls): - super(TestSRv6, cls).tearDownClass() - - def setUp(self): - """ Perform test setup before each test case. - """ - super(TestSRv6, self).setUp() - - # packet sizes, inclusive L2 overhead - self.pg_packet_sizes = [64, 512, 1518, 9018] - - # reset packet_infos - self.reset_packet_infos() - - def tearDown(self): - """ Clean up test setup after each test case. - """ - self.teardown_interfaces() - - super(TestSRv6, self).tearDown() - - def configure_interface(self, - interface, - ipv6=False, ipv4=False, - ipv6_table_id=0, ipv4_table_id=0): - """ Configure interface. - :param ipv6: configure IPv6 on interface - :param ipv4: configure IPv4 on interface - :param ipv6_table_id: FIB table_id for IPv6 - :param ipv4_table_id: FIB table_id for IPv4 - """ - self.logger.debug("Configuring interface %s" % (interface.name)) - if ipv6: - self.logger.debug("Configuring IPv6") - interface.set_table_ip6(ipv6_table_id) - interface.config_ip6() - interface.resolve_ndp(timeout=5) - if ipv4: - self.logger.debug("Configuring IPv4") - interface.set_table_ip4(ipv4_table_id) - interface.config_ip4() - interface.resolve_arp() - interface.admin_up() - - def setup_interfaces(self, ipv6=[], ipv4=[], - ipv6_table_id=[], ipv4_table_id=[]): - """ Create and configure interfaces. - - :param ipv6: list of interface IPv6 capabilities - :param ipv4: list of interface IPv4 capabilities - :param ipv6_table_id: list of intf IPv6 FIB table_ids - :param ipv4_table_id: list of intf IPv4 FIB table_ids - :returns: List of created interfaces. - """ - # how many interfaces? - if len(ipv6): - count = len(ipv6) - else: - count = len(ipv4) - self.logger.debug("Creating and configuring %d interfaces" % (count)) - - # fill up ipv6 and ipv4 lists if needed - # not enabled (False) is the default - if len(ipv6) < count: - ipv6 += (count - len(ipv6)) * [False] - if len(ipv4) < count: - ipv4 += (count - len(ipv4)) * [False] - - # fill up table_id lists if needed - # table_id 0 (global) is the default - if len(ipv6_table_id) < count: - ipv6_table_id += (count - len(ipv6_table_id)) * [0] - if len(ipv4_table_id) < count: - ipv4_table_id += (count - len(ipv4_table_id)) * [0] - - # create 'count' pg interfaces - self.create_pg_interfaces(range(count)) - - # setup all interfaces - for i in range(count): - intf = self.pg_interfaces[i] - self.configure_interface(intf, - ipv6[i], ipv4[i], - ipv6_table_id[i], ipv4_table_id[i]) - - if any(ipv6): - self.logger.debug(self.vapi.cli("show ip6 neighbors")) - if any(ipv4): - self.logger.debug(self.vapi.cli("show ip arp")) - self.logger.debug(self.vapi.cli("show interface")) - self.logger.debug(self.vapi.cli("show hardware")) - - return self.pg_interfaces - - def teardown_interfaces(self): - """ Unconfigure and bring down interface. - """ - self.logger.debug("Tearing down interfaces") - # tear down all interfaces - # AFAIK they cannot be deleted - for i in self.pg_interfaces: - self.logger.debug("Tear down interface %s" % (i.name)) - i.admin_down() - i.unconfig() - i.set_table_ip4(0) - i.set_table_ip6(0) - - def test_SRv6_End_AD_IPv6(self): - """ Test SRv6 End.AD behavior with IPv6 traffic. - """ - self.src_addr = 'a0::' - self.sid_list = ['a1::', 'a2::a6', 'a3::'] - self.test_sid_index = 1 - - # send traffic to one destination interface - # source and destination interfaces are IPv6 only - self.setup_interfaces(ipv6=[True, True]) - - # configure route to next segment - route = VppIpRoute(self, self.sid_list[self.test_sid_index + 1], 128, - [VppRoutePath(self.pg0.remote_ip6, - self.pg0.sw_if_index, - proto=DpoProto.DPO_PROTO_IP6)]) - route.add_vpp_config() - - # configure SRv6 localSID behavior - cli_str = "sr localsid address " + \ - self.sid_list[self.test_sid_index] + \ - " behavior end.ad" + \ - " nh " + self.pg1.remote_ip6 + \ - " oif " + self.pg1.name + \ - " iif " + self.pg1.name - self.vapi.cli(cli_str) - - # log the localsids - self.logger.debug(self.vapi.cli("show sr localsid")) - - # send one packet per packet size - count = len(self.pg_packet_sizes) - - # prepare IPv6 in SRv6 headers - packet_header1 = self.create_packet_header_IPv6_SRH_IPv6( - srcaddr=self.src_addr, - sidlist=self.sid_list[::-1], - segleft=len(self.sid_list) - self.test_sid_index - 1) - - # generate packets (pg0->pg1) - pkts1 = self.create_stream(self.pg0, self.pg1, packet_header1, - self.pg_packet_sizes, count) - - # send packets and verify received packets - self.send_and_verify_pkts(self.pg0, pkts1, self.pg1, - self.compare_rx_tx_packet_End_AD_IPv6_out) - - # log the localsid counters - self.logger.info(self.vapi.cli("show sr localsid")) - - # prepare IPv6 header for returning packets - packet_header2 = self.create_packet_header_IPv6() - - # generate returning packets (pg1->pg0) - pkts2 = self.create_stream(self.pg1, self.pg0, packet_header2, - self.pg_packet_sizes, count) - - # send packets and verify received packets - self.send_and_verify_pkts(self.pg1, pkts2, self.pg0, - self.compare_rx_tx_packet_End_AD_IPv6_in) - - # log the localsid counters - self.logger.info(self.vapi.cli("show sr localsid")) - - # remove SRv6 localSIDs - cli_str = "sr localsid del address " + \ - self.sid_list[self.test_sid_index] - self.vapi.cli(cli_str) - - # cleanup interfaces - self.teardown_interfaces() - - def compare_rx_tx_packet_End_AD_IPv6_out(self, tx_pkt, rx_pkt): - """ Compare input and output packet after passing End.AD with IPv6 - - :param tx_pkt: transmitted packet - :param rx_pkt: received packet - """ - - # get first (outer) IPv6 header of rx'ed packet - rx_ip = rx_pkt.getlayer(IPv6) - - tx_ip = tx_pkt.getlayer(IPv6) - tx_ip2 = tx_pkt.getlayer(IPv6, 2) - - # verify if rx'ed packet has no SRH - self.assertFalse(rx_pkt.haslayer(IPv6ExtHdrSegmentRouting)) - - # the whole rx_ip pkt should be equal to tx_ip2 - # except for the hlim field - # -> adjust tx'ed hlim to expected hlim - tx_ip2.hlim = tx_ip2.hlim - 1 - - self.assertEqual(rx_ip, tx_ip2) - - self.logger.debug("packet verification: SUCCESS") - - def compare_rx_tx_packet_End_AD_IPv6_in(self, tx_pkt, rx_pkt): - """ Compare input and output packet after passing End.AD - - :param tx_pkt: transmitted packet - :param rx_pkt: received packet - """ - - # get first (outer) IPv6 header of rx'ed packet - rx_ip = rx_pkt.getlayer(IPv6) - # received ip.src should be equal to SR Policy source - self.assertEqual(rx_ip.src, self.src_addr) - # received ip.dst should be equal to expected sidlist next segment - self.assertEqual(rx_ip.dst, self.sid_list[self.test_sid_index + 1]) - - # rx'ed packet should have SRH - self.assertTrue(rx_pkt.haslayer(IPv6ExtHdrSegmentRouting)) - - # get SRH - rx_srh = rx_pkt.getlayer(IPv6ExtHdrSegmentRouting) - # rx'ed seglist should be equal to SID-list in reversed order - self.assertEqual(rx_srh.addresses, self.sid_list[::-1]) - # segleft should be equal to previous segleft value minus 1 - self.assertEqual(rx_srh.segleft, - len(self.sid_list) - self.test_sid_index - 2) - # lastentry should be equal to the SID-list length minus 1 - self.assertEqual(rx_srh.lastentry, len(self.sid_list) - 1) - - # the whole rx'ed pkt beyond SRH should be equal to tx'ed pkt - # except for the hop-limit field - tx_ip = tx_pkt.getlayer(IPv6) - # -> update tx'ed hlim to the expected hlim - tx_ip.hlim -= 1 - # -> check payload - self.assertEqual(rx_srh.payload, tx_ip) - - self.logger.debug("packet verification: SUCCESS") - - def test_SRv6_End_AD_IPv4(self): - """ Test SRv6 End.AD behavior with IPv4 traffic. - """ - self.src_addr = 'a0::' - self.sid_list = ['a1::', 'a2::a4', 'a3::'] - self.test_sid_index = 1 - - # send traffic to one destination interface - # source and destination interfaces are IPv6 only - self.setup_interfaces(ipv6=[True, False], ipv4=[False, True]) - - # configure route to next segment - route = VppIpRoute(self, self.sid_list[self.test_sid_index + 1], 128, - [VppRoutePath(self.pg0.remote_ip6, - self.pg0.sw_if_index, - proto=DpoProto.DPO_PROTO_IP6)]) - route.add_vpp_config() - - # configure SRv6 localSID behavior - cli_str = "sr localsid address " + \ - self.sid_list[self.test_sid_index] + \ - " behavior end.ad" + \ - " nh " + self.pg1.remote_ip4 + \ - " oif " + self.pg1.name + \ - " iif " + self.pg1.name - self.vapi.cli(cli_str) - - # log the localsids - self.logger.debug(self.vapi.cli("show sr localsid")) - - # send one packet per packet size - count = len(self.pg_packet_sizes) - - # prepare IPv4 in SRv6 headers - packet_header1 = self.create_packet_header_IPv6_SRH_IPv4( - srcaddr=self.src_addr, - sidlist=self.sid_list[::-1], - segleft=len(self.sid_list) - self.test_sid_index - 1) - - # generate packets (pg0->pg1) - pkts1 = self.create_stream(self.pg0, self.pg1, packet_header1, - self.pg_packet_sizes, count) - - # send packets and verify received packets - self.send_and_verify_pkts(self.pg0, pkts1, self.pg1, - self.compare_rx_tx_packet_End_AD_IPv4_out) - - # log the localsid counters - self.logger.info(self.vapi.cli("show sr localsid")) - - # prepare IPv6 header for returning packets - packet_header2 = self.create_packet_header_IPv4() - - # generate returning packets (pg1->pg0) - pkts2 = self.create_stream(self.pg1, self.pg0, packet_header2, - self.pg_packet_sizes, count) - - # send packets and verify received packets - self.send_and_verify_pkts(self.pg1, pkts2, self.pg0, - self.compare_rx_tx_packet_End_AD_IPv4_in) - - # log the localsid counters - self.logger.info(self.vapi.cli("show sr localsid")) - - # remove SRv6 localSIDs - cli_str = "sr localsid del address " + \ - self.sid_list[self.test_sid_index] - self.vapi.cli(cli_str) - - # cleanup interfaces - self.teardown_interfaces() - - def compare_rx_tx_packet_End_AD_IPv4_out(self, tx_pkt, rx_pkt): - """ Compare input and output packet after passing End.AD with IPv4 - - :param tx_pkt: transmitted packet - :param rx_pkt: received packet - """ - - # get IPv4 header of rx'ed packet - rx_ip = rx_pkt.getlayer(IP) - - tx_ip = tx_pkt.getlayer(IPv6) - tx_ip2 = tx_pkt.getlayer(IP) - - # verify if rx'ed packet has no SRH - self.assertFalse(rx_pkt.haslayer(IPv6ExtHdrSegmentRouting)) - - # the whole rx_ip pkt should be equal to tx_ip2 - # except for the ttl field and ip checksum - # -> adjust tx'ed ttl to expected ttl - tx_ip2.ttl = tx_ip2.ttl - 1 - # -> set tx'ed ip checksum to None and let scapy recompute - tx_ip2.chksum = None - # read back the pkt (with str()) to force computing these fields - # probably other ways to accomplish this are possible - tx_ip2 = IP(scapy.compat.raw(tx_ip2)) - - self.assertEqual(rx_ip, tx_ip2) - - self.logger.debug("packet verification: SUCCESS") - - def compare_rx_tx_packet_End_AD_IPv4_in(self, tx_pkt, rx_pkt): - """ Compare input and output packet after passing End.AD - - :param tx_pkt: transmitted packet - :param rx_pkt: received packet - """ - - # get first (outer) IPv6 header of rx'ed packet - rx_ip = rx_pkt.getlayer(IPv6) - # received ip.src should be equal to SR Policy source - self.assertEqual(rx_ip.src, self.src_addr) - # received ip.dst should be equal to expected sidlist next segment - self.assertEqual(rx_ip.dst, self.sid_list[self.test_sid_index + 1]) - - # rx'ed packet should have SRH - self.assertTrue(rx_pkt.haslayer(IPv6ExtHdrSegmentRouting)) - - # get SRH - rx_srh = rx_pkt.getlayer(IPv6ExtHdrSegmentRouting) - # rx'ed seglist should be equal to SID-list in reversed order - self.assertEqual(rx_srh.addresses, self.sid_list[::-1]) - # segleft should be equal to previous segleft value minus 1 - self.assertEqual(rx_srh.segleft, - len(self.sid_list) - self.test_sid_index - 2) - # lastentry should be equal to the SID-list length minus 1 - self.assertEqual(rx_srh.lastentry, len(self.sid_list) - 1) - - # the whole rx'ed pkt beyond SRH should be equal to tx'ed pkt - # except for the ttl field and ip checksum - tx_ip = tx_pkt.getlayer(IP) - # -> adjust tx'ed ttl to expected ttl - tx_ip.ttl = tx_ip.ttl - 1 - # -> set tx'ed ip checksum to None and let scapy recompute - tx_ip.chksum = None - # -> read back the pkt (with str()) to force computing these fields - # probably other ways to accomplish this are possible - self.assertEqual(rx_srh.payload, IP(scapy.compat.raw(tx_ip))) - - self.logger.debug("packet verification: SUCCESS") - - def test_SRv6_End_AD_L2(self): - """ Test SRv6 End.AD behavior with L2 traffic. - """ - self.src_addr = 'a0::' - self.sid_list = ['a1::', 'a2::a4', 'a3::'] - self.test_sid_index = 1 - - # send traffic to one destination interface - # source and destination interfaces are IPv6 only - self.setup_interfaces(ipv6=[True, False]) - - # configure route to next segment - route = VppIpRoute(self, self.sid_list[self.test_sid_index + 1], 128, - [VppRoutePath(self.pg0.remote_ip6, - self.pg0.sw_if_index, - proto=DpoProto.DPO_PROTO_IP6)]) - route.add_vpp_config() - - # configure SRv6 localSID behavior - cli_str = "sr localsid address " + \ - self.sid_list[self.test_sid_index] + \ - " behavior end.ad" + \ - " oif " + self.pg1.name + \ - " iif " + self.pg1.name - self.vapi.cli(cli_str) - - # log the localsids - self.logger.debug(self.vapi.cli("show sr localsid")) - - # send one packet per packet size - count = len(self.pg_packet_sizes) - - # prepare L2 in SRv6 headers - packet_header1 = self.create_packet_header_IPv6_SRH_L2( - srcaddr=self.src_addr, - sidlist=self.sid_list[::-1], - segleft=len(self.sid_list) - self.test_sid_index - 1, - vlan=0) - - # generate packets (pg0->pg1) - pkts1 = self.create_stream(self.pg0, self.pg1, packet_header1, - self.pg_packet_sizes, count) - - # send packets and verify received packets - self.send_and_verify_pkts(self.pg0, pkts1, self.pg1, - self.compare_rx_tx_packet_End_AD_L2_out) - - # log the localsid counters - self.logger.info(self.vapi.cli("show sr localsid")) - - # prepare L2 header for returning packets - packet_header2 = self.create_packet_header_L2() - - # generate returning packets (pg1->pg0) - pkts2 = self.create_stream(self.pg1, self.pg0, packet_header2, - self.pg_packet_sizes, count) - - # send packets and verify received packets - self.send_and_verify_pkts(self.pg1, pkts2, self.pg0, - self.compare_rx_tx_packet_End_AD_L2_in) - - # log the localsid counters - self.logger.info(self.vapi.cli("show sr localsid")) - - # remove SRv6 localSIDs - cli_str = "sr localsid del address " + \ - self.sid_list[self.test_sid_index] - self.vapi.cli(cli_str) - - # cleanup interfaces - self.teardown_interfaces() - - def compare_rx_tx_packet_End_AD_L2_out(self, tx_pkt, rx_pkt): - """ Compare input and output packet after passing End.AD with L2 - - :param tx_pkt: transmitted packet - :param rx_pkt: received packet - """ - - # get IPv4 header of rx'ed packet - rx_eth = rx_pkt.getlayer(Ether) - - tx_ip = tx_pkt.getlayer(IPv6) - # we can't just get the 2nd Ether layer - # get the Raw content and dissect it as Ether - tx_eth1 = Ether(scapy.compat.raw(tx_pkt[Raw])) - - # verify if rx'ed packet has no SRH - self.assertFalse(rx_pkt.haslayer(IPv6ExtHdrSegmentRouting)) - - # the whole rx_eth pkt should be equal to tx_eth1 - self.assertEqual(rx_eth, tx_eth1) - - self.logger.debug("packet verification: SUCCESS") - - def compare_rx_tx_packet_End_AD_L2_in(self, tx_pkt, rx_pkt): - """ Compare input and output packet after passing End.AD - - :param tx_pkt: transmitted packet - :param rx_pkt: received packet - """ - - #### - # get first (outer) IPv6 header of rx'ed packet - rx_ip = rx_pkt.getlayer(IPv6) - # received ip.src should be equal to SR Policy source - self.assertEqual(rx_ip.src, self.src_addr) - # received ip.dst should be equal to expected sidlist next segment - self.assertEqual(rx_ip.dst, self.sid_list[self.test_sid_index + 1]) - - # rx'ed packet should have SRH - self.assertTrue(rx_pkt.haslayer(IPv6ExtHdrSegmentRouting)) - - # get SRH - rx_srh = rx_pkt.getlayer(IPv6ExtHdrSegmentRouting) - # rx'ed seglist should be equal to SID-list in reversed order - self.assertEqual(rx_srh.addresses, self.sid_list[::-1]) - # segleft should be equal to previous segleft value minus 1 - self.assertEqual(rx_srh.segleft, - len(self.sid_list) - self.test_sid_index - 2) - # lastentry should be equal to the SID-list length minus 1 - self.assertEqual(rx_srh.lastentry, len(self.sid_list) - 1) - - # the whole rx'ed pkt beyond SRH should be equal to tx'ed pkt - tx_ether = tx_pkt.getlayer(Ether) - self.assertEqual(Ether(scapy.compat.raw(rx_srh.payload)), tx_ether) - - self.logger.debug("packet verification: SUCCESS") - - def create_stream(self, src_if, dst_if, packet_header, packet_sizes, - count): - """Create SRv6 input packet stream for defined interface. - - :param VppInterface src_if: Interface to create packet stream for - :param VppInterface dst_if: destination interface of packet stream - :param packet_header: Layer3 scapy packet headers, - L2 is added when not provided, - Raw(payload) with packet_info is added - :param list packet_sizes: packet stream pckt sizes,sequentially applied - to packets in stream have - :param int count: number of packets in packet stream - :return: list of packets - """ - self.logger.info("Creating packets") - pkts = [] - for i in range(0, count - 1): - payload_info = self.create_packet_info(src_if, dst_if) - self.logger.debug( - "Creating packet with index %d" % (payload_info.index)) - payload = self.info_to_payload(payload_info) - # add L2 header if not yet provided in packet_header - if packet_header.getlayer(0).name == 'Ethernet': - p = packet_header / Raw(payload) - else: - p = Ether(dst=src_if.local_mac, src=src_if.remote_mac) / \ - packet_header / Raw(payload) - size = packet_sizes[i % len(packet_sizes)] - self.logger.debug("Packet size %d" % (size)) - self.extend_packet(p, size) - # we need to store the packet with the automatic fields computed - # read back the dumped packet (with str()) - # to force computing these fields - # probably other ways are possible - p = Ether(scapy.compat.raw(p)) - payload_info.data = p.copy() - self.logger.debug(ppp("Created packet:", p)) - pkts.append(p) - self.logger.info("Done creating packets") - return pkts - - def send_and_verify_pkts(self, input, pkts, output, compare_func): - """Send packets and verify received packets using compare_func - - :param input: ingress interface of DUT - :param pkts: list of packets to transmit - :param output: egress interface of DUT - :param compare_func: function to compare in and out packets - """ - # add traffic stream to input interface - input.add_stream(pkts) - - # enable capture on all interfaces - self.pg_enable_capture(self.pg_interfaces) - - # start traffic - self.logger.info("Starting traffic") - self.pg_start() - - # get output capture - self.logger.info("Getting packet capture") - capture = output.get_capture() - - # assert nothing was captured on input interface - # input.assert_nothing_captured() - - # verify captured packets - self.verify_captured_pkts(output, capture, compare_func) - - def create_packet_header_IPv6(self): - """Create packet header: IPv6 header, UDP header - - :param dst: IPv6 destination address - - IPv6 source address is 1234::1 - IPv6 destination address is 4321::1 - UDP source port and destination port are 1234 - """ - - p = IPv6(src='1234::1', dst='4321::1') / UDP(sport=1234, dport=1234) - return p - - def create_packet_header_IPv6_SRH_IPv6(self, srcaddr, sidlist, segleft): - """Create packet header: IPv6 encapsulated in SRv6: - IPv6 header with SRH, IPv6 header, UDP header - - :param int srcaddr: outer source address - :param list sidlist: segment list of outer IPv6 SRH - :param int segleft: segments-left field of outer IPv6 SRH - - Outer IPv6 source address is set to srcaddr - Outer IPv6 destination address is set to sidlist[segleft] - Inner IPv6 source addresses is 1234::1 - Inner IPv6 destination address is 4321::1 - UDP source port and destination port are 1234 - """ - - p = IPv6(src=srcaddr, dst=sidlist[segleft]) / \ - IPv6ExtHdrSegmentRouting(addresses=sidlist, - segleft=segleft, nh=41) / \ - IPv6(src='1234::1', dst='4321::1') / \ - UDP(sport=1234, dport=1234) - return p - - def create_packet_header_IPv4(self): - """Create packet header: IPv4 header, UDP header - - :param dst: IPv4 destination address - - IPv4 source address is 123.1.1.1 - IPv4 destination address is 124.1.1.1 - UDP source port and destination port are 1234 - """ - - p = IP(src='123.1.1.1', dst='124.1.1.1') / UDP(sport=1234, dport=1234) - return p - - def create_packet_header_IPv6_SRH_IPv4(self, srcaddr, sidlist, segleft): - """Create packet header: IPv4 encapsulated in SRv6: - IPv6 header with SRH, IPv4 header, UDP header - - :param int srcaddr: outer source address - :param list sidlist: segment list of outer IPv6 SRH - :param int segleft: segments-left field of outer IPv6 SRH - - Outer IPv6 source address is set to srcaddr - Outer IPv6 destination address is set to sidlist[segleft] - Inner IPv4 source address is 123.1.1.1 - Inner IPv4 destination address is 124.1.1.1 - UDP source port and destination port are 1234 - """ - - p = IPv6(src=srcaddr, dst=sidlist[segleft]) / \ - IPv6ExtHdrSegmentRouting(addresses=sidlist, - segleft=segleft, nh=4) / \ - IP(src='123.1.1.1', dst='124.1.1.1') / \ - UDP(sport=1234, dport=1234) - return p - - def create_packet_header_L2(self, vlan=0): - """Create packet header: L2 header - - :param vlan: if vlan!=0 then add 802.1q header - """ - # Note: the dst addr ('00:55:44:33:22:11') is used in - # the compare function compare_rx_tx_packet_T_Encaps_L2 - # to detect presence of L2 in SRH payload - p = Ether(src='00:11:22:33:44:55', dst='00:55:44:33:22:11') - etype = 0x8137 # IPX - if vlan: - # add 802.1q layer - p /= Dot1Q(vlan=vlan, type=etype) - else: - p.type = etype - return p - - def create_packet_header_IPv6_SRH_L2(self, srcaddr, sidlist, segleft, - vlan=0): - """Create packet header: L2 encapsulated in SRv6: - IPv6 header with SRH, L2 - - :param int srcaddr: IPv6 source address - :param list sidlist: segment list of outer IPv6 SRH - :param int segleft: segments-left field of outer IPv6 SRH - :param vlan: L2 vlan; if vlan!=0 then add 802.1q header - - IPv6 source address is set to srcaddr - IPv6 destination address is set to sidlist[segleft] - """ - eth = Ether(src='00:11:22:33:44:55', dst='00:55:44:33:22:11') - etype = 0x8137 # IPX - if vlan: - # add 802.1q layer - eth /= Dot1Q(vlan=vlan, type=etype) - else: - eth.type = etype - - p = IPv6(src=srcaddr, dst=sidlist[segleft]) / \ - IPv6ExtHdrSegmentRouting(addresses=sidlist, - segleft=segleft, nh=59) / \ - eth - return p - - def get_payload_info(self, packet): - """ Extract the payload_info from the packet - """ - # in most cases, payload_info is in packet[Raw] - # but packet[Raw] gives the complete payload - # (incl L2 header) for the T.Encaps L2 case - try: - payload_info = self.payload_to_info(packet[Raw]) - - except: - # remote L2 header from packet[Raw]: - # take packet[Raw], convert it to an Ether layer - # and then extract Raw from it - payload_info = self.payload_to_info( - Ether(scapy.compat.raw(packet[Raw]))[Raw]) - - return payload_info - - def verify_captured_pkts(self, dst_if, capture, compare_func): - """ - Verify captured packet stream for specified interface. - Compare ingress with egress packets using the specified compare fn - - :param dst_if: egress interface of DUT - :param capture: captured packets - :param compare_func: function to compare in and out packet - """ - self.logger.info("Verifying capture on interface %s using function %s" - % (dst_if.name, compare_func.__name__)) - - last_info = dict() - for i in self.pg_interfaces: - last_info[i.sw_if_index] = None - dst_sw_if_index = dst_if.sw_if_index - - for packet in capture: - try: - # extract payload_info from packet's payload - payload_info = self.get_payload_info(packet) - packet_index = payload_info.index - - self.logger.debug("Verifying packet with index %d" - % (packet_index)) - # packet should have arrived on the expected interface - self.assertEqual(payload_info.dst, dst_sw_if_index) - self.logger.debug( - "Got packet on interface %s: src=%u (idx=%u)" % - (dst_if.name, payload_info.src, packet_index)) - - # search for payload_info with same src and dst if_index - # this will give us the transmitted packet - next_info = self.get_next_packet_info_for_interface2( - payload_info.src, dst_sw_if_index, - last_info[payload_info.src]) - last_info[payload_info.src] = next_info - # next_info should not be None - self.assertTrue(next_info is not None) - # index of tx and rx packets should be equal - self.assertEqual(packet_index, next_info.index) - # data field of next_info contains the tx packet - txed_packet = next_info.data - - self.logger.debug(ppp("Transmitted packet:", - txed_packet)) # ppp=Pretty Print Packet - - self.logger.debug(ppp("Received packet:", packet)) - - # compare rcvd packet with expected packet using compare_func - compare_func(txed_packet, packet) - - except: - self.logger.error(ppp("Unexpected or invalid packet:", packet)) - raise - - # have all expected packets arrived? - for i in self.pg_interfaces: - remaining_packet = self.get_next_packet_info_for_interface2( - i.sw_if_index, dst_sw_if_index, last_info[i.sw_if_index]) - self.assertTrue(remaining_packet is None, - "Interface %s: Packet expected from interface %s " - "didn't arrive" % (dst_if.name, i.name)) - - -if __name__ == '__main__': - unittest.main(testRunner=VppTestRunner) diff --git a/test/test_srv6_as.py b/test/test_srv6_as.py deleted file mode 100755 index 2be7865d5bd..00000000000 --- a/test/test_srv6_as.py +++ /dev/null @@ -1,889 +0,0 @@ -#!/usr/bin/env python - -import unittest -import binascii -from socket import AF_INET6 - -from framework import VppTestCase, VppTestRunner -from vpp_ip_route import VppIpRoute, VppRoutePath, FibPathProto, VppIpTable -from vpp_srv6 import SRv6LocalSIDBehaviors, VppSRv6LocalSID, VppSRv6Policy, \ - SRv6PolicyType, VppSRv6Steering, SRv6PolicySteeringTypes - -import scapy.compat -from scapy.packet import Raw -from scapy.layers.l2 import Ether, Dot1Q -from scapy.layers.inet6 import IPv6, UDP, IPv6ExtHdrSegmentRouting -from scapy.layers.inet import IP, UDP - -from scapy.utils import inet_pton, inet_ntop - -from util import ppp - - -class TestSRv6(VppTestCase): - """ SRv6 Static Proxy plugin Test Case """ - - @classmethod - def setUpClass(self): - super(TestSRv6, self).setUpClass() - - @classmethod - def tearDownClass(cls): - super(TestSRv6, cls).tearDownClass() - - def setUp(self): - """ Perform test setup before each test case. - """ - super(TestSRv6, self).setUp() - - # packet sizes, inclusive L2 overhead - self.pg_packet_sizes = [64, 512, 1518, 9018] - - # reset packet_infos - self.reset_packet_infos() - - def tearDown(self): - """ Clean up test setup after each test case. - """ - self.teardown_interfaces() - - super(TestSRv6, self).tearDown() - - def configure_interface(self, - interface, - ipv6=False, ipv4=False, - ipv6_table_id=0, ipv4_table_id=0): - """ Configure interface. - :param ipv6: configure IPv6 on interface - :param ipv4: configure IPv4 on interface - :param ipv6_table_id: FIB table_id for IPv6 - :param ipv4_table_id: FIB table_id for IPv4 - """ - self.logger.debug("Configuring interface %s" % (interface.name)) - if ipv6: - self.logger.debug("Configuring IPv6") - interface.set_table_ip6(ipv6_table_id) - interface.config_ip6() - interface.resolve_ndp(timeout=5) - if ipv4: - self.logger.debug("Configuring IPv4") - interface.set_table_ip4(ipv4_table_id) - interface.config_ip4() - interface.resolve_arp() - interface.admin_up() - - def setup_interfaces(self, ipv6=[], ipv4=[], - ipv6_table_id=[], ipv4_table_id=[]): - """ Create and configure interfaces. - - :param ipv6: list of interface IPv6 capabilities - :param ipv4: list of interface IPv4 capabilities - :param ipv6_table_id: list of intf IPv6 FIB table_ids - :param ipv4_table_id: list of intf IPv4 FIB table_ids - :returns: List of created interfaces. - """ - # how many interfaces? - if len(ipv6): - count = len(ipv6) - else: - count = len(ipv4) - self.logger.debug("Creating and configuring %d interfaces" % (count)) - - # fill up ipv6 and ipv4 lists if needed - # not enabled (False) is the default - if len(ipv6) < count: - ipv6 += (count - len(ipv6)) * [False] - if len(ipv4) < count: - ipv4 += (count - len(ipv4)) * [False] - - # fill up table_id lists if needed - # table_id 0 (global) is the default - if len(ipv6_table_id) < count: - ipv6_table_id += (count - len(ipv6_table_id)) * [0] - if len(ipv4_table_id) < count: - ipv4_table_id += (count - len(ipv4_table_id)) * [0] - - # create 'count' pg interfaces - self.create_pg_interfaces(range(count)) - - # setup all interfaces - for i in range(count): - intf = self.pg_interfaces[i] - self.configure_interface(intf, - ipv6[i], ipv4[i], - ipv6_table_id[i], ipv4_table_id[i]) - - if any(ipv6): - self.logger.debug(self.vapi.cli("show ip6 neighbors")) - if any(ipv4): - self.logger.debug(self.vapi.cli("show ip arp")) - self.logger.debug(self.vapi.cli("show interface")) - self.logger.debug(self.vapi.cli("show hardware")) - - return self.pg_interfaces - - def teardown_interfaces(self): - """ Unconfigure and bring down interface. - """ - self.logger.debug("Tearing down interfaces") - # tear down all interfaces - # AFAIK they cannot be deleted - for i in self.pg_interfaces: - self.logger.debug("Tear down interface %s" % (i.name)) - i.admin_down() - i.unconfig() - i.set_table_ip4(0) - i.set_table_ip6(0) - - def test_SRv6_End_AS_IPv6_noSRH(self): - """ Test SRv6 End.AS behavior with IPv6 traffic and no SRH rewrite. - """ - self.run_SRv6_End_AS_IPv6( - sid_list=['a1::', 'a2::a6', 'a3::'], - test_sid_index=1, - rewrite_src_addr='a2::') - - def test_SRv6_End_AS_IPv6_SRH(self): - """ Test SRv6 End.AS behavior with IPv6 traffic and SRH rewrite. - """ - self.run_SRv6_End_AS_IPv6( - sid_list=['a1::a6', 'a2::', 'a3::'], - test_sid_index=0, - rewrite_src_addr='a1::') - - def test_SRv6_End_AS_IPv4_noSRH(self): - """ Test SRv6 End.AS behavior with IPv4 traffic and no SRH rewrite. - """ - self.run_SRv6_End_AS_IPv4( - sid_list=['a1::', 'a2::a6', 'a3::'], - test_sid_index=1, - rewrite_src_addr='a2::') - - def test_SRv6_End_AS_IPv4_SRH(self): - """ Test SRv6 End.AS behavior with IPv4 traffic and SRH rewrite. - """ - self.run_SRv6_End_AS_IPv4( - sid_list=['a1::a6', 'a2::', 'a3::'], - test_sid_index=0, - rewrite_src_addr='a1::') - - def test_SRv6_End_AS_L2_noSRH(self): - """ Test SRv6 End.AS behavior with L2 traffic and no SRH rewrite. - """ - self.run_SRv6_End_AS_L2( - sid_list=['a1::', 'a2::a6', 'a3::'], - test_sid_index=1, - rewrite_src_addr='a2::') - - def test_SRv6_End_AS_L2_SRH(self): - """ Test SRv6 End.AS behavior with L2 traffic and SRH rewrite. - """ - self.run_SRv6_End_AS_L2( - sid_list=['a1::a6', 'a2::', 'a3::'], - test_sid_index=0, - rewrite_src_addr='a1::') - - def run_SRv6_End_AS_L2(self, sid_list, test_sid_index, rewrite_src_addr): - """ Run SRv6 End.AS test with L2 traffic. - """ - self.rewrite_src_addr = rewrite_src_addr - self.rewrite_sid_list = sid_list[test_sid_index + 1::] - - # send traffic to one destination interface - # source and destination interfaces are IPv6 only - self.setup_interfaces(ipv6=[True, False]) - - # configure route to next segment - route = VppIpRoute(self, sid_list[test_sid_index + 1], 128, - [VppRoutePath(self.pg0.remote_ip6, - self.pg0.sw_if_index)]) - route.add_vpp_config() - - # configure SRv6 localSID behavior - cli_str = "sr localsid address " + sid_list[test_sid_index] \ - + " behavior end.as" \ - + " oif " + self.pg1.name \ - + " iif " + self.pg1.name \ - + " src " + self.rewrite_src_addr - for s in self.rewrite_sid_list: - cli_str += " next " + s - self.vapi.cli(cli_str) - - # log the localsids - self.logger.debug(self.vapi.cli("show sr localsid")) - - # send one packet per packet size - count = len(self.pg_packet_sizes) - - # prepare L2 in SRv6 headers - packet_header1 = self.create_packet_header_IPv6_SRH_L2( - sidlist=sid_list[::-1], - segleft=len(sid_list) - test_sid_index - 1, - vlan=0) - - # generate packets (pg0->pg1) - pkts1 = self.create_stream(self.pg0, self.pg1, packet_header1, - self.pg_packet_sizes, count) - - # send packets and verify received packets - self.send_and_verify_pkts(self.pg0, pkts1, self.pg1, - self.compare_rx_tx_packet_End_AS_L2_out) - - # log the localsid counters - self.logger.info(self.vapi.cli("show sr localsid")) - - # prepare L2 header for returning packets - packet_header2 = self.create_packet_header_L2() - - # generate returning packets (pg1->pg0) - pkts2 = self.create_stream(self.pg1, self.pg0, packet_header2, - self.pg_packet_sizes, count) - - # send packets and verify received packets - self.send_and_verify_pkts(self.pg1, pkts2, self.pg0, - self.compare_rx_tx_packet_End_AS_L2_in) - - # log the localsid counters - self.logger.info(self.vapi.cli("show sr localsid")) - - # remove SRv6 localSIDs - self.vapi.cli("sr localsid del address " + sid_list[test_sid_index]) - - # cleanup interfaces - self.teardown_interfaces() - - def run_SRv6_End_AS_IPv6(self, sid_list, test_sid_index, rewrite_src_addr): - """ Run SRv6 End.AS test with IPv6 traffic. - """ - self.rewrite_src_addr = rewrite_src_addr - self.rewrite_sid_list = sid_list[test_sid_index + 1::] - - # send traffic to one destination interface - # source and destination interfaces are IPv6 only - self.setup_interfaces(ipv6=[True, True]) - - # configure route to next segment - route = VppIpRoute(self, sid_list[test_sid_index + 1], 128, - [VppRoutePath(self.pg0.remote_ip6, - self.pg0.sw_if_index)]) - route.add_vpp_config() - - # configure SRv6 localSID behavior - cli_str = "sr localsid address " + sid_list[test_sid_index] \ - + " behavior end.as" \ - + " nh " + self.pg1.remote_ip6 \ - + " oif " + self.pg1.name \ - + " iif " + self.pg1.name \ - + " src " + self.rewrite_src_addr - for s in self.rewrite_sid_list: - cli_str += " next " + s - self.vapi.cli(cli_str) - - # log the localsids - self.logger.debug(self.vapi.cli("show sr localsid")) - - # send one packet per packet size - count = len(self.pg_packet_sizes) - - # prepare IPv6 in SRv6 headers - packet_header1 = self.create_packet_header_IPv6_SRH_IPv6( - sidlist=sid_list[::-1], - segleft=len(sid_list) - test_sid_index - 1) - - # generate packets (pg0->pg1) - pkts1 = self.create_stream(self.pg0, self.pg1, packet_header1, - self.pg_packet_sizes, count) - - # send packets and verify received packets - self.send_and_verify_pkts(self.pg0, pkts1, self.pg1, - self.compare_rx_tx_packet_End_AS_IPv6_out) - - # log the localsid counters - self.logger.info(self.vapi.cli("show sr localsid")) - - # prepare IPv6 header for returning packets - packet_header2 = self.create_packet_header_IPv6() - - # generate returning packets (pg1->pg0) - pkts2 = self.create_stream(self.pg1, self.pg0, packet_header2, - self.pg_packet_sizes, count) - - # send packets and verify received packets - self.send_and_verify_pkts(self.pg1, pkts2, self.pg0, - self.compare_rx_tx_packet_End_AS_IPv6_in) - - # log the localsid counters - self.logger.info(self.vapi.cli("show sr localsid")) - - # remove SRv6 localSIDs - self.vapi.cli("sr localsid del address " + sid_list[test_sid_index]) - - # cleanup interfaces - self.teardown_interfaces() - - def run_SRv6_End_AS_IPv4(self, sid_list, test_sid_index, rewrite_src_addr): - """ Run SRv6 End.AS test with IPv4 traffic. - """ - self.rewrite_src_addr = rewrite_src_addr - self.rewrite_sid_list = sid_list[test_sid_index + 1::] - - # send traffic to one destination interface - # source and destination interfaces are IPv6 only - self.setup_interfaces(ipv6=[True, False], ipv4=[True, True]) - - # configure route to next segment - route = VppIpRoute(self, sid_list[test_sid_index + 1], 128, - [VppRoutePath(self.pg0.remote_ip6, - self.pg0.sw_if_index)]) - route.add_vpp_config() - - # configure SRv6 localSID behavior - cli_str = "sr localsid address " + sid_list[test_sid_index] \ - + " behavior end.as" \ - + " nh " + self.pg1.remote_ip4 \ - + " oif " + self.pg1.name \ - + " iif " + self.pg1.name \ - + " src " + self.rewrite_src_addr - for s in self.rewrite_sid_list: - cli_str += " next " + s - self.vapi.cli(cli_str) - - # log the localsids - self.logger.debug(self.vapi.cli("show sr localsid")) - - # send one packet per packet size - count = len(self.pg_packet_sizes) - - # prepare IPv4 in SRv6 headers - packet_header1 = self.create_packet_header_IPv6_SRH_IPv4( - sidlist=sid_list[::-1], - segleft=len(sid_list) - test_sid_index - 1) - - # generate packets (pg0->pg1) - pkts1 = self.create_stream(self.pg0, self.pg1, packet_header1, - self.pg_packet_sizes, count) - - # send packets and verify received packets - self.send_and_verify_pkts(self.pg0, pkts1, self.pg1, - self.compare_rx_tx_packet_End_AS_IPv4_out) - - # log the localsid counters - self.logger.info(self.vapi.cli("show sr localsid")) - - # prepare IPv6 header for returning packets - packet_header2 = self.create_packet_header_IPv4() - - # generate returning packets (pg1->pg0) - pkts2 = self.create_stream(self.pg1, self.pg0, packet_header2, - self.pg_packet_sizes, count) - - # send packets and verify received packets - self.send_and_verify_pkts(self.pg1, pkts2, self.pg0, - self.compare_rx_tx_packet_End_AS_IPv4_in) - - # log the localsid counters - self.logger.info(self.vapi.cli("show sr localsid")) - - # remove SRv6 localSIDs - self.vapi.cli("sr localsid del address " + sid_list[test_sid_index]) - - # cleanup interfaces - self.teardown_interfaces() - - def compare_rx_tx_packet_End_AS_IPv6_in(self, tx_pkt, rx_pkt): - """ Compare input and output packet after passing End.AS - - :param tx_pkt: transmitted packet - :param rx_pkt: received packet - """ - - # get first (outer) IPv6 header of rx'ed packet - rx_ip = rx_pkt.getlayer(IPv6) - rx_srh = None - - tx_ip = tx_pkt.getlayer(IPv6) - - # expected segment-list (SRH order) - tx_seglist = self.rewrite_sid_list[::-1] - - # received ip.src should be equal to SR Policy source - self.assertEqual(rx_ip.src, self.rewrite_src_addr) - # received ip.dst should be equal to expected sidlist[lastentry] - self.assertEqual(rx_ip.dst, tx_seglist[-1]) - - if len(tx_seglist) > 1: - # rx'ed packet should have SRH - self.assertTrue(rx_pkt.haslayer(IPv6ExtHdrSegmentRouting)) - # get SRH - rx_srh = rx_pkt.getlayer(IPv6ExtHdrSegmentRouting) - # rx'ed seglist should be equal to expected seglist - self.assertEqual(rx_srh.addresses, tx_seglist) - # segleft should be equal to size expected seglist-1 - self.assertEqual(rx_srh.segleft, len(tx_seglist)-1) - # segleft should be equal to lastentry - self.assertEqual(rx_srh.segleft, rx_srh.lastentry) - # get payload - payload = rx_srh.payload - else: - # rx'ed packet should NOT have SRH - self.assertFalse(rx_pkt.haslayer(IPv6ExtHdrSegmentRouting)) - # get payload - payload = rx_ip.payload - - # the whole rx'ed pkt beyond SRH should be equal to tx'ed pkt - # except for the hop-limit field - # -> update tx'ed hlim to the expected hlim - tx_ip.hlim = tx_ip.hlim - 1 - - self.assertEqual(payload, tx_ip) - - self.logger.debug("packet verification: SUCCESS") - - def compare_rx_tx_packet_End_AS_IPv4_in(self, tx_pkt, rx_pkt): - """ Compare input and output packet after passing End.AS - - :param tx_pkt: transmitted packet - :param rx_pkt: received packet - """ - - # get first (outer) IPv6 header of rx'ed packet - rx_ip = rx_pkt.getlayer(IPv6) - rx_srh = None - - tx_ip = tx_pkt.getlayer(IP) - - # expected segment-list (SRH order) - tx_seglist = self.rewrite_sid_list[::-1] - - # received ip.src should be equal to SR Policy source - self.assertEqual(rx_ip.src, self.rewrite_src_addr) - # received ip.dst should be equal to expected sidlist[lastentry] - self.assertEqual(rx_ip.dst, tx_seglist[-1]) - - if len(tx_seglist) > 1: - # rx'ed packet should have SRH and IPv4 header - self.assertTrue(rx_pkt.haslayer(IPv6ExtHdrSegmentRouting)) - self.assertTrue(rx_ip.payload.haslayer(IP)) - # get SRH - rx_srh = rx_pkt.getlayer(IPv6ExtHdrSegmentRouting) - # rx'ed seglist should be equal to seglist - self.assertEqual(rx_srh.addresses, tx_seglist) - # segleft should be equal to size seglist-1 - self.assertEqual(rx_srh.segleft, len(tx_seglist)-1) - # segleft should be equal to lastentry - self.assertEqual(rx_srh.segleft, rx_srh.lastentry) - payload = rx_srh.payload - else: - # rx'ed packet should NOT have SRH - self.assertFalse(rx_pkt.haslayer(IPv6ExtHdrSegmentRouting)) - # get payload - payload = rx_ip.payload - - # the whole rx'ed pkt beyond SRH should be equal to tx'ed pkt - # except for the ttl field and ip checksum - # -> adjust tx'ed ttl to expected ttl - tx_ip.ttl = tx_ip.ttl - 1 - # -> set tx'ed ip checksum to None and let scapy recompute - tx_ip.chksum = None - # read back the pkt (with str()) to force computing these fields - # probably other ways to accomplish this are possible - tx_ip = IP(scapy.compat.raw(tx_ip)) - - self.assertEqual(payload, tx_ip) - - self.logger.debug("packet verification: SUCCESS") - - def compare_rx_tx_packet_End_AS_L2_in(self, tx_pkt, rx_pkt): - """ Compare input and output packet after passing End.AS - - :param tx_pkt: transmitted packet - :param rx_pkt: received packet - """ - - # get first (outer) IPv6 header of rx'ed packet - rx_ip = rx_pkt.getlayer(IPv6) - rx_srh = None - - tx_ether = tx_pkt.getlayer(Ether) - - # expected segment-list (SRH order) - tx_seglist = self.rewrite_sid_list[::-1] - - # received ip.src should be equal to SR Policy source - self.assertEqual(rx_ip.src, self.rewrite_src_addr) - # received ip.dst should be equal to expected sidlist[lastentry] - self.assertEqual(rx_ip.dst, tx_seglist[-1]) - - if len(tx_seglist) > 1: - # rx'ed packet should have SRH - self.assertTrue(rx_pkt.haslayer(IPv6ExtHdrSegmentRouting)) - # get SRH - rx_srh = rx_pkt.getlayer(IPv6ExtHdrSegmentRouting) - # rx'ed seglist should be equal to seglist - self.assertEqual(rx_srh.addresses, tx_seglist) - # segleft should be equal to size seglist-1 - self.assertEqual(rx_srh.segleft, len(tx_seglist)-1) - # segleft should be equal to lastentry - self.assertEqual(rx_srh.segleft, rx_srh.lastentry) - # nh should be "No Next Header" (59) - self.assertEqual(rx_srh.nh, 59) - # get payload - payload = rx_srh.payload - else: - # rx'ed packet should NOT have SRH - self.assertFalse(rx_pkt.haslayer(IPv6ExtHdrSegmentRouting)) - # get payload - payload = rx_ip.payload - - # the whole rx'ed pkt beyond SRH should be equal to tx'ed pkt - self.assertEqual(Ether(scapy.compat.raw(payload)), tx_ether) - - self.logger.debug("packet verification: SUCCESS") - - def compare_rx_tx_packet_End_AS_IPv6_out(self, tx_pkt, rx_pkt): - """ Compare input and output packet after passing End.AS with IPv6 - - :param tx_pkt: transmitted packet - :param rx_pkt: received packet - """ - - # get first (outer) IPv6 header of rx'ed packet - rx_ip = rx_pkt.getlayer(IPv6) - - tx_ip = tx_pkt.getlayer(IPv6) - tx_ip2 = tx_pkt.getlayer(IPv6, 2) - - # verify if rx'ed packet has no SRH - self.assertFalse(rx_pkt.haslayer(IPv6ExtHdrSegmentRouting)) - - # the whole rx_ip pkt should be equal to tx_ip2 - # except for the hlim field - # -> adjust tx'ed hlim to expected hlim - tx_ip2.hlim = tx_ip2.hlim - 1 - - self.assertEqual(rx_ip, tx_ip2) - - self.logger.debug("packet verification: SUCCESS") - - def compare_rx_tx_packet_End_AS_IPv4_out(self, tx_pkt, rx_pkt): - """ Compare input and output packet after passing End.AS with IPv4 - - :param tx_pkt: transmitted packet - :param rx_pkt: received packet - """ - - # get IPv4 header of rx'ed packet - rx_ip = rx_pkt.getlayer(IP) - - tx_ip = tx_pkt.getlayer(IPv6) - tx_ip2 = tx_pkt.getlayer(IP) - - # verify if rx'ed packet has no SRH - self.assertFalse(rx_pkt.haslayer(IPv6ExtHdrSegmentRouting)) - - # the whole rx_ip pkt should be equal to tx_ip2 - # except for the ttl field and ip checksum - # -> adjust tx'ed ttl to expected ttl - tx_ip2.ttl = tx_ip2.ttl - 1 - # -> set tx'ed ip checksum to None and let scapy recompute - tx_ip2.chksum = None - # read back the pkt (with str()) to force computing these fields - # probably other ways to accomplish this are possible - tx_ip2 = IP(scapy.compat.raw(tx_ip2)) - - self.assertEqual(rx_ip, tx_ip2) - - self.logger.debug("packet verification: SUCCESS") - - def compare_rx_tx_packet_End_AS_L2_out(self, tx_pkt, rx_pkt): - """ Compare input and output packet after passing End.AS with L2 - - :param tx_pkt: transmitted packet - :param rx_pkt: received packet - """ - - # get IPv4 header of rx'ed packet - rx_eth = rx_pkt.getlayer(Ether) - - tx_ip = tx_pkt.getlayer(IPv6) - # we can't just get the 2nd Ether layer - # get the Raw content and dissect it as Ether - tx_eth1 = Ether(scapy.compat.raw(tx_pkt[Raw])) - - # verify if rx'ed packet has no SRH - self.assertFalse(rx_pkt.haslayer(IPv6ExtHdrSegmentRouting)) - - # the whole rx_eth pkt should be equal to tx_eth1 - self.assertEqual(rx_eth, tx_eth1) - - self.logger.debug("packet verification: SUCCESS") - - def create_stream(self, src_if, dst_if, packet_header, packet_sizes, - count): - """Create SRv6 input packet stream for defined interface. - - :param VppInterface src_if: Interface to create packet stream for - :param VppInterface dst_if: destination interface of packet stream - :param packet_header: Layer3 scapy packet headers, - L2 is added when not provided, - Raw(payload) with packet_info is added - :param list packet_sizes: packet stream pckt sizes,sequentially applied - to packets in stream have - :param int count: number of packets in packet stream - :return: list of packets - """ - self.logger.info("Creating packets") - pkts = [] - for i in range(0, count-1): - payload_info = self.create_packet_info(src_if, dst_if) - self.logger.debug( - "Creating packet with index %d" % (payload_info.index)) - payload = self.info_to_payload(payload_info) - # add L2 header if not yet provided in packet_header - if packet_header.getlayer(0).name == 'Ethernet': - p = (packet_header / - Raw(payload)) - else: - p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) / - packet_header / - Raw(payload)) - size = packet_sizes[i % len(packet_sizes)] - self.logger.debug("Packet size %d" % (size)) - self.extend_packet(p, size) - # we need to store the packet with the automatic fields computed - # read back the dumped packet (with str()) - # to force computing these fields - # probably other ways are possible - p = Ether(scapy.compat.raw(p)) - payload_info.data = p.copy() - self.logger.debug(ppp("Created packet:", p)) - pkts.append(p) - self.logger.info("Done creating packets") - return pkts - - def send_and_verify_pkts(self, input, pkts, output, compare_func): - """Send packets and verify received packets using compare_func - - :param input: ingress interface of DUT - :param pkts: list of packets to transmit - :param output: egress interface of DUT - :param compare_func: function to compare in and out packets - """ - # add traffic stream to input interface - input.add_stream(pkts) - - # enable capture on all interfaces - self.pg_enable_capture(self.pg_interfaces) - - # start traffic - self.logger.info("Starting traffic") - self.pg_start() - - # get output capture - self.logger.info("Getting packet capture") - capture = output.get_capture() - - # assert nothing was captured on input interface - # input.assert_nothing_captured() - - # verify captured packets - self.verify_captured_pkts(output, capture, compare_func) - - def create_packet_header_IPv6(self): - """Create packet header: IPv6 header, UDP header - - :param dst: IPv6 destination address - - IPv6 source address is 1234::1 - IPv6 destination address is 4321::1 - UDP source port and destination port are 1234 - """ - - p = (IPv6(src='1234::1', dst='4321::1') / - UDP(sport=1234, dport=1234)) - return p - - def create_packet_header_IPv6_SRH_IPv6(self, sidlist, segleft): - """Create packet header: IPv6 encapsulated in SRv6: - IPv6 header with SRH, IPv6 header, UDP header - - :param list sidlist: segment list of outer IPv6 SRH - :param int segleft: segments-left field of outer IPv6 SRH - - Outer IPv6 source address is set to 5678::1 - Outer IPv6 destination address is set to sidlist[segleft] - IPv6 source addresses is 1234::1 - IPv6 destination address is 4321::1 - UDP source port and destination port are 1234 - """ - - p = (IPv6(src='5678::1', dst=sidlist[segleft]) / - IPv6ExtHdrSegmentRouting(addresses=sidlist, - segleft=segleft, nh=41) / - IPv6(src='1234::1', dst='4321::1') / - UDP(sport=1234, dport=1234)) - return p - - def create_packet_header_IPv4(self): - """Create packet header: IPv4 header, UDP header - - :param dst: IPv4 destination address - - IPv4 source address is 123.1.1.1 - IPv4 destination address is 124.1.1.1 - UDP source port and destination port are 1234 - """ - - p = (IP(src='123.1.1.1', dst='124.1.1.1') / - UDP(sport=1234, dport=1234)) - return p - - def create_packet_header_IPv6_SRH_IPv4(self, sidlist, segleft): - """Create packet header: IPv4 encapsulated in SRv6: - IPv6 header with SRH, IPv4 header, UDP header - - :param ipv4address dst: inner IPv4 destination address - :param list sidlist: segment list of outer IPv6 SRH - :param int segleft: segments-left field of outer IPv6 SRH - - Outer IPv6 destination address is set to sidlist[segleft] - IPv6 source address is 1234::1 - IPv4 source address is 123.1.1.1 - IPv4 destination address is 124.1.1.1 - UDP source port and destination port are 1234 - """ - - p = (IPv6(src='1234::1', dst=sidlist[segleft]) / - IPv6ExtHdrSegmentRouting(addresses=sidlist, - segleft=segleft, nh=4) / - IP(src='123.1.1.1', dst='124.1.1.1') / - UDP(sport=1234, dport=1234)) - return p - - def create_packet_header_L2(self, vlan=0): - """Create packet header: L2 header - - :param vlan: if vlan!=0 then add 802.1q header - """ - # Note: the dst addr ('00:55:44:33:22:11') is used in - # the compare function compare_rx_tx_packet_T_Encaps_L2 - # to detect presence of L2 in SRH payload - p = Ether(src='00:11:22:33:44:55', dst='00:55:44:33:22:11') - etype = 0x8137 # IPX - if vlan: - # add 802.1q layer - p /= Dot1Q(vlan=vlan, type=etype) - else: - p.type = etype - return p - - def create_packet_header_IPv6_SRH_L2(self, sidlist, segleft, vlan=0): - """Create packet header: L2 encapsulated in SRv6: - IPv6 header with SRH, L2 - - :param list sidlist: segment list of outer IPv6 SRH - :param int segleft: segments-left field of outer IPv6 SRH - :param vlan: L2 vlan; if vlan!=0 then add 802.1q header - - Outer IPv6 destination address is set to sidlist[segleft] - IPv6 source address is 1234::1 - """ - eth = Ether(src='00:11:22:33:44:55', dst='00:55:44:33:22:11') - etype = 0x8137 # IPX - if vlan: - # add 802.1q layer - eth /= Dot1Q(vlan=vlan, type=etype) - else: - eth.type = etype - - p = (IPv6(src='1234::1', dst=sidlist[segleft]) / - IPv6ExtHdrSegmentRouting(addresses=sidlist, - segleft=segleft, nh=59) / - eth) - return p - - def get_payload_info(self, packet): - """ Extract the payload_info from the packet - """ - # in most cases, payload_info is in packet[Raw] - # but packet[Raw] gives the complete payload - # (incl L2 header) for the T.Encaps L2 case - try: - payload_info = self.payload_to_info(packet[Raw]) - - except: - # remote L2 header from packet[Raw]: - # take packet[Raw], convert it to an Ether layer - # and then extract Raw from it - payload_info = self.payload_to_info( - Ether(scapy.compat.raw(packet[Raw]))[Raw]) - - return payload_info - - def verify_captured_pkts(self, dst_if, capture, compare_func): - """ - Verify captured packet stream for specified interface. - Compare ingress with egress packets using the specified compare fn - - :param dst_if: egress interface of DUT - :param capture: captured packets - :param compare_func: function to compare in and out packet - """ - self.logger.info("Verifying capture on interface %s using function %s" - % (dst_if.name, compare_func.__name__)) - - last_info = dict() - for i in self.pg_interfaces: - last_info[i.sw_if_index] = None - dst_sw_if_index = dst_if.sw_if_index - - for packet in capture: - try: - # extract payload_info from packet's payload - payload_info = self.get_payload_info(packet) - packet_index = payload_info.index - - self.logger.debug("Verifying packet with index %d" - % (packet_index)) - # packet should have arrived on the expected interface - self.assertEqual(payload_info.dst, dst_sw_if_index) - self.logger.debug( - "Got packet on interface %s: src=%u (idx=%u)" % - (dst_if.name, payload_info.src, packet_index)) - - # search for payload_info with same src and dst if_index - # this will give us the transmitted packet - next_info = self.get_next_packet_info_for_interface2( - payload_info.src, dst_sw_if_index, - last_info[payload_info.src]) - last_info[payload_info.src] = next_info - # next_info should not be None - self.assertTrue(next_info is not None) - # index of tx and rx packets should be equal - self.assertEqual(packet_index, next_info.index) - # data field of next_info contains the tx packet - txed_packet = next_info.data - - self.logger.debug(ppp("Transmitted packet:", - txed_packet)) # ppp=Pretty Print Packet - - self.logger.debug(ppp("Received packet:", packet)) - - # compare rcvd packet with expected packet using compare_func - compare_func(txed_packet, packet) - - except: - self.logger.error(ppp("Unexpected or invalid packet:", packet)) - raise - - # have all expected packets arrived? - for i in self.pg_interfaces: - remaining_packet = self.get_next_packet_info_for_interface2( - i.sw_if_index, dst_sw_if_index, last_info[i.sw_if_index]) - self.assertTrue(remaining_packet is None, - "Interface %s: Packet expected from interface %s " - "didn't arrive" % (dst_if.name, i.name)) - - -if __name__ == '__main__': - unittest.main(testRunner=VppTestRunner) diff --git a/test/test_svs.py b/test/test_svs.py deleted file mode 100644 index 9a9ac57016b..00000000000 --- a/test/test_svs.py +++ /dev/null @@ -1,322 +0,0 @@ -#!/usr/bin/env python - -import unittest - -from framework import VppTestCase, VppTestRunner -from vpp_ip_route import VppIpTable - -from scapy.packet import Raw -from scapy.layers.l2 import Ether -from scapy.layers.inet import IP, UDP, ICMP -from scapy.layers.inet6 import IPv6 - -from vpp_papi import VppEnum - -NUM_PKTS = 67 - - -class TestSVS(VppTestCase): - """ SVS Test Case """ - - @classmethod - def setUpClass(cls): - super(TestSVS, cls).setUpClass() - - @classmethod - def tearDownClass(cls): - super(TestSVS, cls).tearDownClass() - - def setUp(self): - super(TestSVS, self).setUp() - - # create 2 pg interfaces - self.create_pg_interfaces(range(4)) - - table_id = 0 - - for i in self.pg_interfaces: - i.admin_up() - - if table_id != 0: - tbl = VppIpTable(self, table_id) - tbl.add_vpp_config() - tbl = VppIpTable(self, table_id, is_ip6=1) - tbl.add_vpp_config() - - i.set_table_ip4(table_id) - i.set_table_ip6(table_id) - i.config_ip4() - i.resolve_arp() - i.config_ip6() - i.resolve_ndp() - table_id += 1 - - def tearDown(self): - for i in self.pg_interfaces: - i.unconfig_ip4() - i.unconfig_ip6() - i.ip6_disable() - i.set_table_ip4(0) - i.set_table_ip6(0) - i.admin_down() - super(TestSVS, self).tearDown() - - def test_svs4(self): - """ Source VRF Select IP4 """ - - # - # packets destined out of the 3 non-default table interfaces - # - pkts_0 = [(Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IP(src="1.1.1.1", dst=self.pg1.remote_ip4) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)), - (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IP(src="2.2.2.2", dst=self.pg2.remote_ip4) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)), - (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IP(src="3.3.3.3", dst=self.pg3.remote_ip4) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100))] - pkts_1 = [(Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / - IP(src="1.1.1.1", dst=self.pg1.remote_ip4) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)), - (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / - IP(src="2.2.2.2", dst=self.pg2.remote_ip4) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)), - (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / - IP(src="3.3.3.3", dst=self.pg3.remote_ip4) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100))] - - # - # before adding the SVS config all these packets are dropped when - # ingressing on pg0 since pg0 is in the default table - # - for p in pkts_0: - self.send_and_assert_no_replies(self.pg0, p * 1) - - # - # Add table 1001 & 1002 into which we'll add the routes - # determining the source VRF selection - # - table_ids = [101, 102] - - for table_id in table_ids: - self.vapi.svs_table_add_del( - VppEnum.vl_api_address_family_t.ADDRESS_IP4, table_id) - - # - # map X.0.0.0/8 to each SVS table for lookup in table X - # - for i in range(1, 4): - self.vapi.svs_route_add_del( - table_id, "%d.0.0.0/8" % i, i) - - # - # Enable SVS on pg0/pg1 using table 1001/1002 - # - self.vapi.svs_enable_disable( - VppEnum.vl_api_address_family_t.ADDRESS_IP4, table_ids[0], - self.pg0.sw_if_index) - self.vapi.svs_enable_disable( - VppEnum.vl_api_address_family_t.ADDRESS_IP4, table_ids[1], - self.pg1.sw_if_index) - - # - # now all the packets should be delivered out the respective interface - # - self.send_and_expect(self.pg0, pkts_0[0] * NUM_PKTS, self.pg1) - self.send_and_expect(self.pg0, pkts_0[1] * NUM_PKTS, self.pg2) - self.send_and_expect(self.pg0, pkts_0[2] * NUM_PKTS, self.pg3) - self.send_and_expect(self.pg1, pkts_1[0] * NUM_PKTS, self.pg1) - self.send_and_expect(self.pg1, pkts_1[1] * NUM_PKTS, self.pg2) - self.send_and_expect(self.pg1, pkts_1[2] * NUM_PKTS, self.pg3) - - # - # check that if the SVS lookup does not match a route the packet - # is forwarded using the interface's routing table - # - p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IP(src=self.pg0.remote_ip4, dst=self.pg0.remote_ip4) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - self.send_and_expect(self.pg0, p * NUM_PKTS, self.pg0) - - p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / - IP(src=self.pg1.remote_ip4, dst=self.pg1.remote_ip4) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - self.send_and_expect(self.pg1, p * NUM_PKTS, self.pg1) - - # - # dump the SVS configs - # - ss = self.vapi.svs_dump() - - self.assertEqual(ss[0].table_id, table_ids[0]) - self.assertEqual(ss[0].sw_if_index, self.pg0.sw_if_index) - self.assertEqual(ss[0].af, VppEnum.vl_api_address_family_t.ADDRESS_IP4) - self.assertEqual(ss[1].table_id, table_ids[1]) - self.assertEqual(ss[1].sw_if_index, self.pg1.sw_if_index) - self.assertEqual(ss[1].af, VppEnum.vl_api_address_family_t.ADDRESS_IP4) - - # - # cleanup - # - self.vapi.svs_enable_disable( - VppEnum.vl_api_address_family_t.ADDRESS_IP4, - table_ids[0], - self.pg0.sw_if_index, - is_enable=0) - self.vapi.svs_enable_disable( - VppEnum.vl_api_address_family_t.ADDRESS_IP4, - table_ids[1], - self.pg1.sw_if_index, - is_enable=0) - - for table_id in table_ids: - for i in range(1, 4): - self.vapi.svs_route_add_del( - table_id, "%d.0.0.0/8" % i, - 0, is_add=0) - self.vapi.svs_table_add_del( - VppEnum.vl_api_address_family_t.ADDRESS_IP4, - table_id, - is_add=0) - - def test_svs6(self): - """ Source VRF Select IP6 """ - - # - # packets destined out of the 3 non-default table interfaces - # - pkts_0 = [(Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IPv6(src="2001:1::1", dst=self.pg1.remote_ip6) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)), - (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IPv6(src="2001:2::1", dst=self.pg2.remote_ip6) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)), - (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IPv6(src="2001:3::1", dst=self.pg3.remote_ip6) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100))] - pkts_1 = [(Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / - IPv6(src="2001:1::1", dst=self.pg1.remote_ip6) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)), - (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / - IPv6(src="2001:2::1", dst=self.pg2.remote_ip6) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)), - (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / - IPv6(src="2001:3::1", dst=self.pg3.remote_ip6) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100))] - - # - # before adding the SVS config all these packets are dropped when - # ingressing on pg0 since pg0 is in the default table - # - for p in pkts_0: - self.send_and_assert_no_replies(self.pg0, p * 1) - - # - # Add table 1001 & 1002 into which we'll add the routes - # determining the source VRF selection - # - table_ids = [101, 102] - - for table_id in table_ids: - self.vapi.svs_table_add_del( - VppEnum.vl_api_address_family_t.ADDRESS_IP6, table_id) - - # - # map X.0.0.0/8 to each SVS table for lookup in table X - # - for i in range(1, 4): - self.vapi.svs_route_add_del( - table_id, "2001:%d::/32" % i, - i) - - # - # Enable SVS on pg0/pg1 using table 1001/1002 - # - self.vapi.svs_enable_disable( - VppEnum.vl_api_address_family_t.ADDRESS_IP6, - table_ids[0], - self.pg0.sw_if_index) - self.vapi.svs_enable_disable( - VppEnum.vl_api_address_family_t.ADDRESS_IP6, - table_ids[1], - self.pg1.sw_if_index) - - # - # now all the packets should be delivered out the respective interface - # - self.send_and_expect(self.pg0, pkts_0[0] * NUM_PKTS, self.pg1) - self.send_and_expect(self.pg0, pkts_0[1] * NUM_PKTS, self.pg2) - self.send_and_expect(self.pg0, pkts_0[2] * NUM_PKTS, self.pg3) - self.send_and_expect(self.pg1, pkts_1[0] * NUM_PKTS, self.pg1) - self.send_and_expect(self.pg1, pkts_1[1] * NUM_PKTS, self.pg2) - self.send_and_expect(self.pg1, pkts_1[2] * NUM_PKTS, self.pg3) - - # - # check that if the SVS lookup does not match a route the packet - # is forwarded using the interface's routing table - # - p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IPv6(src=self.pg0.remote_ip6, dst=self.pg0.remote_ip6) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - self.send_and_expect(self.pg0, p * NUM_PKTS, self.pg0) - - p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / - IPv6(src=self.pg1.remote_ip6, dst=self.pg1.remote_ip6) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) - self.send_and_expect(self.pg1, p * NUM_PKTS, self.pg1) - - # - # dump the SVS configs - # - ss = self.vapi.svs_dump() - - self.assertEqual(ss[0].table_id, table_ids[0]) - self.assertEqual(ss[0].sw_if_index, self.pg0.sw_if_index) - self.assertEqual(ss[0].af, VppEnum.vl_api_address_family_t.ADDRESS_IP6) - self.assertEqual(ss[1].table_id, table_ids[1]) - self.assertEqual(ss[1].sw_if_index, self.pg1.sw_if_index) - self.assertEqual(ss[1].af, VppEnum.vl_api_address_family_t.ADDRESS_IP6) - - # - # cleanup - # - self.vapi.svs_enable_disable( - VppEnum.vl_api_address_family_t.ADDRESS_IP6, - table_ids[0], - self.pg0.sw_if_index, - is_enable=0) - self.vapi.svs_enable_disable( - VppEnum.vl_api_address_family_t.ADDRESS_IP6, - table_ids[1], - self.pg1.sw_if_index, - is_enable=0) - for table_id in table_ids: - for i in range(1, 4): - self.vapi.svs_route_add_del( - table_id, "2001:%d::/32" % i, - 0, is_add=0) - self.vapi.svs_table_add_del( - VppEnum.vl_api_address_family_t.ADDRESS_IP6, - table_id, - is_add=0) - - -if __name__ == '__main__': - unittest.main(testRunner=VppTestRunner) diff --git a/test/vpp_igmp.py b/test/vpp_igmp.py deleted file mode 100644 index 8f78a9b909a..00000000000 --- a/test/vpp_igmp.py +++ /dev/null @@ -1,75 +0,0 @@ - -from vpp_object import VppObject -import socket - - -class IGMP_MODE: - ROUTER = 0 - HOST = 1 - - -class IGMP_FILTER: - INCLUDE = 1 - EXCLUDE = 0 - - -def find_igmp_state(states, itf, gaddr, saddr): - for s in states: - if s.sw_if_index == itf.sw_if_index and \ - str(s.gaddr) == gaddr and str(s.saddr) == saddr: - return True - return False - - -def wait_for_igmp_event(test, timeout, itf, gaddr, saddr, ff): - ev = test.vapi.wait_for_event(timeout, "igmp_event") - if ev.sw_if_index == itf.sw_if_index and \ - str(ev.gaddr) == gaddr and str(ev.saddr) == saddr and \ - ev.filter == ff: - return True - return False - - -class IgmpSG(): - def __init__(self, gaddr, saddrs): - self.gaddr = gaddr - self.gaddr_p = socket.inet_pton(socket.AF_INET, gaddr) - self.saddrs = saddrs - self.saddrs_p = [] - self.saddrs_encoded = [] - for s in saddrs: - ss = socket.inet_pton(socket.AF_INET, s) - self.saddrs_p.append(ss) - self.saddrs_encoded.append(ss) - - -class IgmpRecord(): - def __init__(self, sg, type): - self.sg = sg - self.type = type - - -class VppHostState(VppObject): - def __init__(self, test, filter, sw_if_index, sg): - self._test = test - self.sw_if_index = sw_if_index - self.filter = filter - self.sg = sg - - def add_vpp_config(self): - self._test.vapi.igmp_listen( - self.filter, self.sw_if_index, - self.sg.saddrs_encoded, self.sg.gaddr_p) - - def remove_vpp_config(self): - self._test.vapi.igmp_listen( - self.filter, - self.sw_if_index, - [], - self.sg.gaddr_p) - - def object_id(self): - return "%s:%d" % (self.sg, self.sw_if_index) - - def query_vpp_config(self): - return self._test.vapi.igmp_dump() diff --git a/test/vpp_lb.py b/test/vpp_lb.py deleted file mode 100644 index d755cef70e5..00000000000 --- a/test/vpp_lb.py +++ /dev/null @@ -1,84 +0,0 @@ -# Copyright (c) 2019. Vinci Consulting Corp. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import vpp_object - - -class VppLbVip(vpp_object.VppObject): - - def __init__(self, test, pfx, sfx, port, protocol): - self._test = test - self.pfx = pfx - self.sfx = sfx - self.port = port - self.protocol = protocol - - def add_vpp_config(self): - self._test_vapi.lb_add_del_vip(pfx=self.pfx, - sfx=self.pfx, - port=self.port, - protocol=self.protocol) - - self._test.registry.register(self, self._test.logger) - - def remove_vpp_config(self): - self._test.vapi.lb_add_del_vip(pfx=self.pfx, - sfx=self.pfx, - port=self.port, - protocol=self.protocol, - is_del=1) - - def query_vpp_config(self): - details = self._test.vapi.lb_add_del_vip(fx=self.pfx, - sfx=self.pfx, - port=self.port, - protocol=self.protocol) - return True if self == details else False - - -class VppLbAs(vpp_object.VppObject): - def __init__(self, test, pfx, port, protocol, app_srv, is_del, is_flush): - self._test = test - # this is the vip - self.pfx = pfx - self.port = port - self.protocol = protocol - - self.app_srv = app_srv - self.is_del = is_del - self.is_flush = is_flush - - def add_vpp_config(self): - self._test_vapi.lb_add_del_as(pfx=self.pfx, - port=self.port, - protocol=self.protocol, - app_srv=self.app_srv, - is_flush=self.is_flush, - ) - - self._test.registry.register(self, self._test.logger) - - def remove_vpp_config(self): - self._test.vapi.lb_add_del_as(pfx=self.pfx, - port=self.port, - protocol=self.protocol, - app_srv=self.app_srv, - is_flush=self.is_flush, - is_del=1) - - def query_vpp_config(self): - details = self._test.vapi.lb_as_dump(pfx=self.pfx, - port=self.port, - protocol=self.protocol) - return True if self == details else False diff --git a/test/vpp_memif.py b/test/vpp_memif.py deleted file mode 100644 index befcc2840c5..00000000000 --- a/test/vpp_memif.py +++ /dev/null @@ -1,155 +0,0 @@ -import socket - -import six - -from vpp_object import VppObject -from vpp_ip import VppIpPrefix -from vpp_papi import VppEnum - - -class MEMIF_ROLE: - MASTER = 0 - SLAVE = 1 - - -class MEMIF_MODE: - ETHERNET = 0 - IP = 1 - PUNT_INJECT = 2 - - -def get_if_dump(dump, sw_if_index): - for d in dump: - if (d.sw_if_index == sw_if_index): - return d - - -def query_all_memif_vpp_config(_test): - return _test.vapi.memif_dump() - - -def remove_all_memif_vpp_config(_test): - dump = _test.vapi.memif_dump() - for d in dump: - _test.vapi.memif_delete(d.sw_if_index) - dump = _test.vapi.memif_socket_filename_dump() - for d in dump: - if d.socket_id != 0: - _test.vapi.memif_socket_filename_add_del( - 0, d.socket_id, d.socket_filename) - - -class VppSocketFilename(VppObject): - def __init__(self, test, socket_id, socket_filename, - add_default_folder=False): - self._test = test - self.socket_id = socket_id - self.socket_filename = socket_filename - - # if True insert default socket folder before socket filename, - # after adding vpp config - self.add_default_folder = add_default_folder - - def add_vpp_config(self): - rv = self._test.vapi.memif_socket_filename_add_del( - 1, self.socket_id, self.socket_filename) - if self.add_default_folder: - self.socket_filename = b"%s/%s" % ( - six.ensure_binary(self._test.tempdir, encoding='utf-8'), - self.socket_filename) - return rv - - def remove_vpp_config(self): - return self._test.vapi.memif_socket_filename_add_del( - 0, self.socket_id, self.socket_filename) - - def query_vpp_config(self): - return self._test.vapi.memif_socket_filename_dump() - - def object_id(self): - return "socket-filename-%d-%s" % (self.socket_id, self.socket_filename) - - -class VppMemif(VppObject): - def __init__(self, test, role, mode, rx_queues=0, tx_queues=0, if_id=0, - socket_id=0, secret="", ring_size=0, buffer_size=0, - hw_addr=""): - self._test = test - self.role = role - self.mode = mode - self.rx_queues = rx_queues - self.tx_queues = tx_queues - self.if_id = if_id - self.socket_id = socket_id - self.secret = secret - self.ring_size = ring_size - self.buffer_size = buffer_size - self.hw_addr = hw_addr - self.sw_if_index = None - self.ip_prefix = VppIpPrefix("192.168.%d.%d" % - (self.if_id + 1, self.role + 1), 24) - - def add_vpp_config(self): - rv = self._test.vapi.memif_create( - role=self.role, - mode=self.mode, - rx_queues=self.rx_queues, - tx_queues=self.tx_queues, - id=self.if_id, - socket_id=self.socket_id, - secret=self.secret, - ring_size=self.ring_size, - buffer_size=self.buffer_size, - hw_addr=self.hw_addr) - try: - self.sw_if_index = 0 - except AttributeError: - raise AttributeError('self: %s' % self.__dict__) - try: - self.sw_if_index = rv.sw_if_index - except AttributeError: - raise AttributeError("%s %s", self, rv) - - return self.sw_if_index - - def admin_up(self): - if self.sw_if_index: - return self._test.vapi.sw_interface_set_flags( - sw_if_index=self.sw_if_index, flags=1) - - def admin_down(self): - if self.sw_if_index: - return self._test.vapi.sw_interface_set_flags( - sw_if_index=self.sw_if_index, flags=0) - - def wait_for_link_up(self, timeout, step=1): - if not self.sw_if_index: - return False - while True: - dump = self.query_vpp_config() - if dump.link_up_down == 1: - return True - self._test.sleep(step) - timeout -= step - if timeout <= 0: - return False - - def config_ip4(self): - return self._test.vapi.sw_interface_add_del_address( - sw_if_index=self.sw_if_index, prefix=self.ip_prefix.encode()) - - def remove_vpp_config(self): - self._test.vapi.memif_delete(self.sw_if_index) - self.sw_if_index = None - - def query_vpp_config(self): - if not self.sw_if_index: - return None - dump = self._test.vapi.memif_dump() - return get_if_dump(dump, self.sw_if_index) - - def object_id(self): - if self.sw_if_index: - return "%d:%d:%d" % (self.role, self.if_id, self.sw_if_index) - else: - return "%d:%d:None" % (self.role, self.if_id) diff --git a/test/vpp_pppoe_interface.py b/test/vpp_pppoe_interface.py deleted file mode 100644 index 9be92327dcf..00000000000 --- a/test/vpp_pppoe_interface.py +++ /dev/null @@ -1,39 +0,0 @@ - -from vpp_interface import VppInterface -import socket -from vpp_papi import mac_pton - - -class VppPppoeInterface(VppInterface): - """ - VPP Pppoe interface - """ - - def __init__(self, test, client_ip, client_mac, - session_id, decap_vrf_id=0): - """ Create VPP PPPoE4 interface """ - super(VppPppoeInterface, self).__init__(test) - self.client_ip = client_ip - self.client_mac = client_mac - self.session_id = session_id - self.decap_vrf_id = decap_vrf_id - - def add_vpp_config(self): - cip = socket.inet_pton(socket.AF_INET, self.client_ip) - cmac = mac_pton(self.client_mac) - r = self.test.vapi.pppoe_add_del_session( - cip, cmac, - session_id=self.session_id, - decap_vrf_id=self.decap_vrf_id) - self.set_sw_if_index(r.sw_if_index) - self.generate_remote_hosts() - - def remove_vpp_config(self): - cip = socket.inet_pton(socket.AF_INET, self.client_ip) - cmac = mac_pton(self.client_mac) - self.unconfig() - self.test.vapi.pppoe_add_del_session( - cip, cmac, - session_id=self.session_id, - decap_vrf_id=self.decap_vrf_id, - is_add=0) diff --git a/test/vpp_srv6.py b/test/vpp_srv6.py deleted file mode 100644 index b6dbc014207..00000000000 --- a/test/vpp_srv6.py +++ /dev/null @@ -1,222 +0,0 @@ -""" - SRv6 LocalSIDs - - object abstractions for representing SRv6 localSIDs in VPP -""" - -from vpp_object import VppObject -from socket import inet_pton, inet_ntop, AF_INET, AF_INET6 - - -class SRv6LocalSIDBehaviors(): - # from src/vnet/srv6/sr.h - SR_BEHAVIOR_END = 1 - SR_BEHAVIOR_X = 2 - SR_BEHAVIOR_T = 3 - SR_BEHAVIOR_D_FIRST = 4 # Unused. Separator in between regular and D - SR_BEHAVIOR_DX2 = 5 - SR_BEHAVIOR_DX6 = 6 - SR_BEHAVIOR_DX4 = 7 - SR_BEHAVIOR_DT6 = 8 - SR_BEHAVIOR_DT4 = 9 - SR_BEHAVIOR_LAST = 10 # Must always be the last one - - -class SRv6PolicyType(): - # from src/vnet/srv6/sr.h - SR_POLICY_TYPE_DEFAULT = 0 - SR_POLICY_TYPE_SPRAY = 1 - - -class SRv6PolicySteeringTypes(): - # from src/vnet/srv6/sr.h - SR_STEER_L2 = 2 - SR_STEER_IPV4 = 4 - SR_STEER_IPV6 = 6 - - -class VppSRv6LocalSID(VppObject): - """ - SRv6 LocalSID - """ - - def __init__(self, test, localsid, behavior, nh_addr4, nh_addr6, - end_psp, sw_if_index, vlan_index, fib_table): - self._test = test - self.localsid = localsid - # keep binary format in _localsid - self.localsid["addr"] = inet_pton(AF_INET6, self.localsid["addr"]) - self.behavior = behavior - self.nh_addr4 = inet_pton(AF_INET, nh_addr4) - self.nh_addr6 = inet_pton(AF_INET6, nh_addr6) - self.end_psp = end_psp - self.sw_if_index = sw_if_index - self.vlan_index = vlan_index - self.fib_table = fib_table - self._configured = False - - def add_vpp_config(self): - self._test.vapi.sr_localsid_add_del( - self.localsid, - self.behavior, - self.nh_addr4, - self.nh_addr6, - is_del=0, - end_psp=self.end_psp, - sw_if_index=self.sw_if_index, - vlan_index=self.vlan_index, - fib_table=self.fib_table) - self._configured = True - - def remove_vpp_config(self): - self._test.vapi.sr_localsid_add_del( - self.localsid, - self.behavior, - self.nh_addr4, - self.nh_addr6, - is_del=1, - end_psp=self.end_psp, - sw_if_index=self.sw_if_index, - vlan_index=self.vlan_index, - fib_table=self.fib_table) - self._configured = False - - def query_vpp_config(self): - # sr_localsids_dump API is disabled - # use _configured flag for now - return self._configured - - def object_id(self): - return ("%d;%s,%d" - % (self.fib_table, - self.localsid, - self.behavior)) - - -class VppSRv6Policy(VppObject): - """ - SRv6 Policy - """ - - def __init__(self, test, bsid, - is_encap, sr_type, weight, fib_table, - segments, source): - self._test = test - self.bsid = bsid - # keep binary format in _bsid - self._bsid = inet_pton(AF_INET6, bsid) - self.is_encap = is_encap - self.sr_type = sr_type - self.weight = weight - self.fib_table = fib_table - self.segments = segments - # keep binary format in _segments - self._segments = [] - for seg in segments: - self._segments.extend(inet_pton(AF_INET6, seg)) - self.n_segments = len(segments) - # source not passed to API - # self.source = inet_pton(AF_INET6, source) - self.source = source - self._configured = False - - def add_vpp_config(self): - self._test.vapi.sr_policy_add( - self._bsid, - self.weight, - self.is_encap, - self.sr_type, - self.fib_table, - self.n_segments, - self._segments) - self._configured = True - - def remove_vpp_config(self): - self._test.vapi.sr_policy_del( - self._bsid) - self._configured = False - - def query_vpp_config(self): - # no API to query SR Policies - # use _configured flag for now - return self._configured - - def object_id(self): - return ("%d;%s-><%s>;%d" - % (self.sr_type, - self.bsid, - ','.join(self.segments), - self.is_encap)) - - -class VppSRv6Steering(VppObject): - """ - SRv6 Steering - """ - - def __init__(self, test, - bsid, - prefix, - mask_width, - traffic_type, - sr_policy_index, - table_id, - sw_if_index): - self._test = test - self.bsid = bsid - # keep binary format in _bsid - self._bsid = inet_pton(AF_INET6, bsid) - self.prefix = prefix - # keep binary format in _prefix - if ':' in prefix: - # IPv6 - self._prefix = inet_pton(AF_INET6, prefix) - else: - # IPv4 - # API expects 16 octets (128 bits) - # last 4 octets are used for IPv4 - # --> prepend 12 octets - self._prefix = ('\x00' * 12) + inet_pton(AF_INET, prefix) - self.mask_width = mask_width - self.traffic_type = traffic_type - self.sr_policy_index = sr_policy_index - self.sw_if_index = sw_if_index - self.table_id = table_id - self._configured = False - - def add_vpp_config(self): - self._test.vapi.sr_steering_add_del( - 0, - self._bsid, - self.sr_policy_index, - self.table_id, - self._prefix, - self.mask_width, - self.sw_if_index, - self.traffic_type) - self._configured = True - - def remove_vpp_config(self): - self._test.vapi.sr_steering_add_del( - 1, - self._bsid, - self.sr_policy_index, - self.table_id, - self._prefix, - self.mask_width, - self.sw_if_index, - self.traffic_type) - self._configured = False - - def query_vpp_config(self): - # no API to query steering entries - # use _configured flag for now - return self._configured - - def object_id(self): - return ("%d;%d;%s/%d->%s" - % (self.table_id, - self.traffic_type, - self.prefix, - self.mask_width, - self.bsid)) |