[Fullstack] Add segmentation_id update test

This patch adds new fullstack test which spawns 2 "hosts" and 2 "VMs" on
those hosts. Both VMs are plugged to the vlan network with some
segmentation id. Next segmentation id of the network is updated and test
ensures that new vlan id is configured in the physical bridge on both
"hosts" and connectivity between VMs still works fine.

Test runs only with Openvswitch agents as Linuxbridge doesn't supports
live update of the segmentation_id in the network.

Change-Id: I459aac7f4e9afe679d8ece1c27d0be49cec8e4ff
This commit is contained in:
Slawek Kaplonski 2021-03-29 23:22:59 +02:00
parent da2cc29ec0
commit 87a7a5e32e
4 changed files with 93 additions and 34 deletions

View File

@ -135,3 +135,22 @@ def wait_for_dscp_marked_packet(sender_vm, receiver_vm, dscp_mark):
"to %(dst)s" % {'dscp_mark': dscp_mark,
'src': sender_vm.ip,
'dst': receiver_vm.ip})
def extract_vlan_id(flows):
if flows:
flow_list = flows.splitlines()
for flow in flow_list:
if 'mod_vlan_vid' in flow:
actions = flow.partition('actions=')[2]
after_mod = actions.partition('mod_vlan_vid:')[2]
return int(after_mod.partition(',')[0])
def wait_for_mod_vlan_id_applied(bridge, expected_vlan_id):
def _vlan_id_rule_applied():
flows = bridge.dump_flows_for(table='0')
vlan_id = extract_vlan_id(flows)
return vlan_id == expected_vlan_id
common_utils.wait_until_true(_vlan_id_rule_applied)

View File

@ -30,6 +30,7 @@ from neutron.tests.common import helpers
from neutron.tests.common import machine_fixtures
from neutron.tests.common import net_helpers
from neutron.tests.fullstack.resources import client as client_resource
from neutron.tests.fullstack.resources import machine
from neutron.tests.unit import testlib_api
@ -159,6 +160,20 @@ class BaseFullStackTestCase(testlib_api.MySQLTestCaseMixin,
"tag", network.get("provider:segmentation_id"))
return vm
def _prepare_vms_in_net(self, tenant_uuid, network, use_dhcp=False):
vms = machine.FakeFullstackMachinesList(
self.useFixture(
machine.FakeFullstackMachine(
host,
network['id'],
tenant_uuid,
self.safe_client,
use_dhcp=use_dhcp))
for host in self.environment.hosts)
vms.block_until_all_boot()
return vms
def assert_namespace_exists(self, ns_name):
common_utils.wait_until_true(
lambda: ip_lib.network_namespace_exists(ns_name,

View File

@ -24,7 +24,6 @@ from neutron.tests.common import net_helpers
from neutron.tests.fullstack import base
from neutron.tests.fullstack.resources import config
from neutron.tests.fullstack.resources import environment
from neutron.tests.fullstack.resources import machine
from neutron.tests.unit import testlib_api
load_tests = testlib_api.module_load_tests
@ -74,24 +73,10 @@ class BaseConnectivitySameNetworkTest(base.BaseFullStackTestCase):
return network
def _prepare_vms_in_net(self, tenant_uuid, network):
vms = machine.FakeFullstackMachinesList(
self.useFixture(
machine.FakeFullstackMachine(
host,
network['id'],
tenant_uuid,
self.safe_client,
use_dhcp=self.use_dhcp))
for host in self.environment.hosts)
vms.block_until_all_boot()
return vms
def _prepare_vms_in_single_network(self):
tenant_uuid = uuidutils.generate_uuid()
network = self._prepare_network(tenant_uuid)
return self._prepare_vms_in_net(tenant_uuid, network)
return self._prepare_vms_in_net(tenant_uuid, network, self.use_dhcp)
def _test_connectivity(self):
vms = self._prepare_vms_in_single_network()

View File

@ -14,6 +14,7 @@ from neutron_lib import constants
from neutronclient.common import exceptions
from oslo_utils import uuidutils
from neutron.tests.common.agents import l2_extensions
from neutron.tests.fullstack import base
from neutron.tests.fullstack.resources import config
from neutron.tests.fullstack.resources import environment
@ -22,28 +23,28 @@ from neutron.tests.unit import testlib_api
load_tests = testlib_api.module_load_tests
class TestSegmentationId(base.BaseFullStackTestCase):
class BaseSegmentationIdTest(base.BaseFullStackTestCase):
scenarios = [
('Open vSwitch Agent', {'l2_agent_type': constants.AGENT_TYPE_OVS}),
('Linux Bridge Agent', {
'l2_agent_type': constants.AGENT_TYPE_LINUXBRIDGE})]
network_type = "vlan"
def setUp(self):
hosts_description = [
host_descriptions = [
environment.HostDescription(
l2_agent_type=self.l2_agent_type, l3_agent=False)]
l2_agent_type=self.l2_agent_type, l3_agent=False
) for _ in range(self.num_hosts)]
env = environment.Environment(
environment.EnvironmentDescription(),
hosts_description)
environment.EnvironmentDescription(
network_type=self.network_type),
host_descriptions)
super(TestSegmentationId, self).setUp(env)
self.tenant_id = uuidutils.generate_uuid()
super(BaseSegmentationIdTest, self).setUp(env)
self.project_id = uuidutils.generate_uuid()
def _create_network(self):
seg_id = 100
network = self.safe_client.create_network(
self.tenant_id, network_type="vlan", segmentation_id=seg_id,
self.project_id, network_type=self.network_type,
segmentation_id=seg_id,
physical_network=config.PHYSICAL_NETWORK_NAME)
self.assertEqual(seg_id, network['provider:segmentation_id'])
@ -54,7 +55,6 @@ class TestSegmentationId(base.BaseFullStackTestCase):
return network
def _update_segmentation_id(self, network):
# Now change segmentation_id to some other value
new_seg_id = network['provider:segmentation_id'] + 1
new_net_args = {'provider:segmentation_id': new_seg_id}
network = self.safe_client.update_network(
@ -65,21 +65,32 @@ class TestSegmentationId(base.BaseFullStackTestCase):
network = self.safe_client.client.show_network(
network['id'])['network']
self.assertEqual(new_seg_id, network['provider:segmentation_id'])
return network
class TestSegmentationId(BaseSegmentationIdTest):
scenarios = [
('Open vSwitch Agent', {'l2_agent_type': constants.AGENT_TYPE_OVS}),
('Linux Bridge Agent', {
'l2_agent_type': constants.AGENT_TYPE_LINUXBRIDGE})]
num_hosts = 1
def test_change_segmentation_id_no_ports_in_network(self):
network = self._create_network()
# Now change segmentation_id to some other value
self._update_segmentation_id(network)
def test_change_segmentation_id_with_unbound_ports_in_network(self):
network = self._create_network()
self.safe_client.create_subnet(
self.tenant_id, network['id'], '20.0.0.0/24')
self.project_id, network['id'], '20.0.0.0/24')
# Unbound port
self.safe_client.create_port(self.tenant_id, network['id'])
self.safe_client.create_port(self.project_id, network['id'])
# Port failed to bind
self.safe_client.create_port(self.tenant_id, network['id'],
self.safe_client.create_port(self.project_id, network['id'],
"non-exisiting-host")
self._update_segmentation_id(network)
@ -88,8 +99,8 @@ class TestSegmentationId(base.BaseFullStackTestCase):
network = self._create_network()
self.safe_client.create_subnet(
self.tenant_id, network['id'], '20.0.0.0/24')
self.safe_client.create_port(self.tenant_id, network['id'],
self.project_id, network['id'], '20.0.0.0/24')
self.safe_client.create_port(self.project_id, network['id'],
self.environment.hosts[0].hostname)
if self.l2_agent_type == constants.AGENT_TYPE_LINUXBRIDGE:
@ -99,3 +110,32 @@ class TestSegmentationId(base.BaseFullStackTestCase):
self._update_segmentation_id, network)
else:
self._update_segmentation_id(network)
class TestSegmentationIdConnectivity(BaseSegmentationIdTest):
scenarios = [
('Open vSwitch Agent', {'l2_agent_type': constants.AGENT_TYPE_OVS})]
num_hosts = 2
def _ensure_vlan_id_set_in_flows(self, vlan_id):
for host in self.environment.hosts:
l2_extensions.wait_for_mod_vlan_id_applied(host.br_phys, vlan_id)
def test_connectivity_after_segmentation_id_update(self):
network = self._create_network()
self.safe_client.create_subnet(
self.project_id, network['id'],
cidr='10.0.0.0/24',
gateway_ip='10.0.0.1',
name='subnet-test',
enable_dhcp=False)
vms = self._prepare_vms_in_net(self.project_id, network, False)
self._ensure_vlan_id_set_in_flows(network['provider:segmentation_id'])
vms.ping_all()
network = self._update_segmentation_id(network)
self._ensure_vlan_id_set_in_flows(network['provider:segmentation_id'])
vms.ping_all()