From 048c752ca38c5eeeacf353958e616e319353ac81 Mon Sep 17 00:00:00 2001 From: Roman Safronov Date: Tue, 30 Jul 2024 16:18:20 +0300 Subject: [PATCH] Fix east_west capture for vlan tenant With vlan tenant we have mac-mapping configured in ovs db for compute nodes. These MAC values should be used when filtering relevant traffic for east_west communication. Also, introduced separate tunnel_interface config parameter to define an appropriate value when capturing traffic on a normal node and on ovs_pod. Change-Id: Ibef4498604bd9fff7ab537ed276ce59e8a052cd6 --- .../common/constants.py | 1 - whitebox_neutron_tempest_plugin/config.py | 16 +++++++++ .../tests/scenario/base.py | 34 ++++++++++++++---- .../tests/scenario/test_dvr_ovn.py | 36 +++++++++++++++---- 4 files changed, 74 insertions(+), 13 deletions(-) diff --git a/whitebox_neutron_tempest_plugin/common/constants.py b/whitebox_neutron_tempest_plugin/common/constants.py index addd287..d9c7fcf 100644 --- a/whitebox_neutron_tempest_plugin/common/constants.py +++ b/whitebox_neutron_tempest_plugin/common/constants.py @@ -15,7 +15,6 @@ GLOBAL_IP = '1.1.1.1' METADATA_SERVICE_IP = '169.254.169.254' -NODE_TUNNEL_INTERFACE = 'genev_sys_6081' OVN_MAX_GW_PORTS_PER_ROUTER = 5 NEUTRON_CONF = { 'devstack': '/etc/neutron/neutron.conf', diff --git a/whitebox_neutron_tempest_plugin/config.py b/whitebox_neutron_tempest_plugin/config.py index 3702bb3..e7e38c9 100644 --- a/whitebox_neutron_tempest_plugin/config.py +++ b/whitebox_neutron_tempest_plugin/config.py @@ -128,6 +128,10 @@ WhiteboxNeutronPluginOptions = [ default='eth1', help='Physical interface of a node that is connected to the ' 'external network.'), + cfg.StrOpt('ovs_pod_ext_interface', + default='datacentre', + help='Interface of a ovs pod (on podified openstack) that is ' + 'connected to the external network.'), cfg.IntOpt('minbw_placement_nic_kbps_egress', default=None, help='BW configured per NIC for the minimum BW placement ' @@ -150,6 +154,18 @@ WhiteboxNeutronPluginOptions = [ help='Interface of a node that intended to pass tenant' 'network traffic. Note: currently only environments with ' 'the same name of the tenant interface are supported'), + cfg.StrOpt('node_tunnel_interface', + default='genev_sys_6081', + help='Interface of a node that intended to pass tunnelled ' + 'traffic. genev_sys_6081 is default for geneve tenant ' + 'networks but for vlan tenant network this value should ' + 'be updated according to the environment.'), + cfg.StrOpt('ovs_pod_tunnel_interface', + default='genev_sys_6081', + help='Interface of a ovs pod that intended to pass tunnelled ' + 'traffic. genev_sys_6081 is default for geneve tenant ' + 'networks but for vlan tenant network this value should ' + 'be updated according to the environment.'), cfg.IntOpt('capture_timeout', default=120, help='Maximal time for running remote capture, in seconds. ' diff --git a/whitebox_neutron_tempest_plugin/tests/scenario/base.py b/whitebox_neutron_tempest_plugin/tests/scenario/base.py index a7058cf..2ce6ae0 100644 --- a/whitebox_neutron_tempest_plugin/tests/scenario/base.py +++ b/whitebox_neutron_tempest_plugin/tests/scenario/base.py @@ -182,6 +182,11 @@ class BaseTempestWhiteboxTestCase(base.BaseTempestTestCase): return host_name return hostname + def get_network_type(self, network_id): + network_details = self.os_admin.network_client.show_network( + network_id) + return network_details['network']['provider:network_type'] + @staticmethod def _get_local_ip_from_network(network): host_ip_addresses = [ifaddresses(iface)[AF_INET][0]['addr'] @@ -1055,7 +1060,7 @@ class TrafficFlowTest(BaseTempestWhiteboxTestCase): if node['name'] == line.split()[0]: node['ovs_pod'] = line.split()[1] - def _start_captures(self, filters, interface=None): + def _start_captures(self, filters, scenario='north_south', interface=None): for node in self.nodes: if not (node['is_controller'] or node['is_compute'] or @@ -1067,18 +1072,27 @@ class TrafficFlowTest(BaseTempestWhiteboxTestCase): node['is_controller']): capture_client = self.proxy_host_client command_prefix = "{} rsh {} ".format(self.OC, node['ovs_pod']) - capture_interface = interface if interface else 'datacentre' + if interface: + capture_interface = interface + else: + if scenario == 'north_south': + capture_interface = WB_CONF.ovs_pod_ext_interface + else: + capture_interface = WB_CONF.ovs_pod_tunnel_interface else: capture_client = node['client'] command_prefix = '' if interface: capture_interface = interface else: - capture_interface = WB_CONF.node_ext_interface + if scenario == 'north_south': + capture_interface = WB_CONF.node_ext_interface + else: + capture_interface = WB_CONF.node_tunnel_interface node['capture'] = capture.TcpdumpCapture( capture_client, capture_interface, filters, command_prefix) self.useFixture(node['capture']) - time.sleep(10) + time.sleep(2) def _stop_captures(self): for node in self.nodes: @@ -1116,9 +1130,9 @@ class TrafficFlowTest(BaseTempestWhiteboxTestCase): else: raise TypeError(expected_macs) - self._start_captures(filters, - interface=local_constants.NODE_TUNNEL_INTERFACE) + self._start_captures(filters, scenario='east_west') self.check_remote_connectivity(ssh_client, dst_ip, ping_count=2) + time.sleep(5) self._stop_captures() LOG.debug('Expected routing nodes: {}'.format( ','.join(expected_routing_nodes))) @@ -1345,6 +1359,14 @@ class BaseTempestTestCaseOvn(BaseTempestWhiteboxTestCase): output = self.run_on_master_controller(cmd) self.assertEqual(output, '') + def get_mac_mappings(self, client, physical_network): + output = client.exec_command( + "sudo ovs-vsctl get open . external_ids:ovn-chassis-mac-" + "mappings").strip().replace('"', '').split(',') + for value in output: + if physical_network in value: + return value.replace(physical_network + ':', '') + class BaseDisruptiveTempestTestCase(BaseTempestWhiteboxTestCase): @classmethod diff --git a/whitebox_neutron_tempest_plugin/tests/scenario/test_dvr_ovn.py b/whitebox_neutron_tempest_plugin/tests/scenario/test_dvr_ovn.py index 747acfb..9f29d08 100644 --- a/whitebox_neutron_tempest_plugin/tests/scenario/test_dvr_ovn.py +++ b/whitebox_neutron_tempest_plugin/tests/scenario/test_dvr_ovn.py @@ -123,9 +123,7 @@ class OvnDvrBase(base.TrafficFlowTest, base.BaseTempestTestCaseOvn): # on environments that schedule ovn routers on compute nodes self.exclude_hosts = [self.chassis_name] - network_details = self.os_admin.network_client.show_network( - self.network['id']) - if network_details['network']['provider:network_type'] == 'vlan': + if self.get_network_type(self.network['id']) == 'vlan': # This helps to avoid false positives with vlan+dvr,see BZ2192633 self.ignore_outbound = True else: @@ -534,10 +532,29 @@ class OvnDvrTest(OvnDvrBase): device_owner=constants.DEVICE_OWNER_ROUTER_INTF, network_id=networks[i]['id'])['ports'][0]['mac_address']) + def get_mac_mapping_for_vm(vm): + return self.get_mac_mappings( + self.find_node_client( + self.get_host_for_server(vm['server']['id'])), + 'datacentre') + + def get_expected_macs_for_vlan_tenant(): + return [ + (servers[0]['port']['mac_address'], + get_mac_mapping_for_vm(servers[1])), + (get_mac_mapping_for_vm(servers[0]), + servers[1]['port']['mac_address'])] + # verify E/W connection between servers - ew_expected_macs = [ - (servers[0]['port']['mac_address'], router_port_subnet_macs[0]), - (router_port_subnet_macs[1], servers[1]['port']['mac_address'])] + if self.get_network_type(networks[0]['id']) == 'vlan' and \ + self.get_network_type(networks[1]['id']) == 'vlan': + ew_expected_macs = get_expected_macs_for_vlan_tenant() + else: + ew_expected_macs = [ + (servers[0]['port']['mac_address'], + router_port_subnet_macs[0]), + (router_port_subnet_macs[1], + servers[1]['port']['mac_address'])] # remove duplicates expected_routing_nodes = list(set([host for host in servers_host])) if len(expected_routing_nodes) == 1: @@ -581,6 +598,13 @@ class OvnDvrTest(OvnDvrBase): ssh_client=servers_ssh_client[i]) # verify E/W connection between servers + # Since with vlan tenant we have MAC mapping on compute nodes + # and VMs migrated, we need to retrieve MAC address combination + # for filtering again + if self.get_network_type(networks[0]['id']) == 'vlan' and \ + self.get_network_type(networks[1]['id']) == 'vlan': + ew_expected_macs = get_expected_macs_for_vlan_tenant() + # remove duplicates expected_routing_nodes = list(set([host for host in new_servers_host])) if len(expected_routing_nodes) == 1: