Skip to content

Commit

Permalink
Merge pull request #746 from openstack-charmers/hugepages-vfio
Browse files Browse the repository at this point in the history
Add connectivity test with DPDK
  • Loading branch information
dshcherb authored May 12, 2022
2 parents 0d07a39 + ffa98f3 commit 8fae05e
Show file tree
Hide file tree
Showing 10 changed files with 503 additions and 57 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@ dist/
zaza.openstack.egg-info/
.coverage
.vscode/
*.swp
# Sphinx
doc/build
14 changes: 14 additions & 0 deletions unit_tests/utilities/test_zaza_utilities_openstack.py
Original file line number Diff line number Diff line change
Expand Up @@ -1500,6 +1500,20 @@ def test_configure_charmed_openstack_on_maas(self):
self.configure_networking_charms.assert_called_once_with(
'fakenetworkingdata', expect, use_juju_wait=False)

def test_update_subnet_dhcp(self):
neutron_client = mock.MagicMock()
openstack_utils.update_subnet_dhcp(
neutron_client, {'id': 'aId'}, True)
neutron_client.update_subnet.assert_called_once_with(
'aId',
{'subnet': {'enable_dhcp': True}})
neutron_client.reset_mock()
openstack_utils.update_subnet_dhcp(
neutron_client, {'id': 'aId'}, False)
neutron_client.update_subnet.assert_called_once_with(
'aId',
{'subnet': {'enable_dhcp': False}})


class TestAsyncOpenstackUtils(ut_utils.AioTestCase):

Expand Down
43 changes: 31 additions & 12 deletions zaza/openstack/charm_tests/neutron/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@
"prefix_len": "24",
"subnetpool_name": "pooled_subnets",
"subnetpool_prefix": "192.168.0.0/16",
"project_net_name": "private",
"project_subnet_name": "private_subnet",
}

OVERCLOUD_PROVIDER_VLAN_NETWORK_CONFIG = {
Expand All @@ -67,29 +69,19 @@
}


def basic_overcloud_network(limit_gws=None):
"""Run setup for neutron networking.

Configure the following:
The overcloud network using subnet pools
def undercloud_and_charm_setup(limit_gws=None):
"""Perform undercloud and charm setup for network plumbing.

:param limit_gws: Limit the number of gateways that get a port attached
:type limit_gws: int
"""
cli_utils.setup_logging()

# Get network configuration settings
network_config = {}
# Declared overcloud settings
network_config.update(OVERCLOUD_NETWORK_CONFIG)
# Default undercloud settings
network_config.update(DEFAULT_UNDERCLOUD_NETWORK_CONFIG)
# Environment specific settings
network_config.update(generic_utils.get_undercloud_env_vars())

# Get keystone session
keystone_session = openstack_utils.get_overcloud_keystone_session()

# Get optional use_juju_wait for network option
options = (lifecycle_utils
.get_charm_config(fatal=False)
Expand Down Expand Up @@ -118,6 +110,33 @@ def basic_overcloud_network(limit_gws=None):
' charm network configuration.'
.format(provider_type))


def basic_overcloud_network(limit_gws=None):
"""Run setup for neutron networking.

Configure the following:
The overcloud network using subnet pools

:param limit_gws: Limit the number of gateways that get a port attached
:type limit_gws: int
"""
cli_utils.setup_logging()

# Get network configuration settings
network_config = {}
# Declared overcloud settings
network_config.update(OVERCLOUD_NETWORK_CONFIG)
# Default undercloud settings
network_config.update(DEFAULT_UNDERCLOUD_NETWORK_CONFIG)
# Environment specific settings
network_config.update(generic_utils.get_undercloud_env_vars())

# Get keystone session
keystone_session = openstack_utils.get_overcloud_keystone_session()

# Perform undercloud and charm setup for network plumbing
undercloud_and_charm_setup(limit_gws=limit_gws)

# Configure the overcloud network
network.setup_sdn(network_config, keystone_session=keystone_session)

Expand Down
130 changes: 112 additions & 18 deletions zaza/openstack/charm_tests/neutron/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,12 @@

import yaml
import zaza
import zaza.openstack.charm_tests.neutron.setup as neutron_setup
import zaza.openstack.charm_tests.nova.utils as nova_utils
import zaza.openstack.charm_tests.test_utils as test_utils
import zaza.openstack.configure.guest as guest
import zaza.openstack.utilities.openstack as openstack_utils
import zaza.utilities.machine_os


class NeutronPluginApiSharedTests(test_utils.OpenStackBaseTest):
Expand Down Expand Up @@ -805,6 +807,11 @@ def test_800_ovs_bridges_are_managed_by_us(self):
self.assertEqual(actual_external_id, expected_external_id)


def router_address_from_subnet(subnet):
"""Retrieve router address from subnet."""
return subnet['gateway_ip']


class NeutronNetworkingBase(test_utils.OpenStackBaseTest):
"""Base for checking openstack instances have valid networking."""

Expand All @@ -818,6 +825,21 @@ def setUpClass(cls):
cls.neutron_client = (
openstack_utils.get_neutron_session_client(cls.keystone_session))

cls.project_subnet = cls.neutron_client.find_resource(
'subnet',
neutron_setup.OVERCLOUD_NETWORK_CONFIG['project_subnet_name'])
cls.external_subnet = cls.neutron_client.find_resource(
'subnet',
neutron_setup.OVERCLOUD_NETWORK_CONFIG['external_subnet_name'])

# Override this if you want your test to attach instances directly to
# the external provider network
cls.attach_to_external_network = False

# Override this if you want your test to launch instances with a
# specific flavor
cls.instance_flavor = None

@tenacity.retry(wait=tenacity.wait_exponential(multiplier=1, max=60),
reraise=True, stop=tenacity.stop_after_attempt(8))
def validate_instance_can_reach_other(self,
Expand All @@ -840,8 +862,10 @@ def validate_instance_can_reach_other(self,
:param mtu: Check that we can send non-fragmented packets of given size
:type mtu: Optional[int]
"""
floating_1 = floating_ips_from_instance(instance_1)[0]
floating_2 = floating_ips_from_instance(instance_2)[0]
if not self.attach_to_external_network:
floating_1 = floating_ips_from_instance(instance_1)[0]
floating_2 = floating_ips_from_instance(instance_2)[0]
address_1 = fixed_ips_from_instance(instance_1)[0]
address_2 = fixed_ips_from_instance(instance_2)[0]

username = guest.boot_tests['bionic']['username']
Expand All @@ -859,27 +883,28 @@ def validate_instance_can_reach_other(self,
'ping -M do -s {} -c 1'.format(packetsize))

for cmd in cmds:
openstack_utils.ssh_command(
username, floating_1, 'instance-1',
'{} {}'.format(cmd, address_2),
password=password, privkey=privkey, verify=verify)
if self.attach_to_external_network:
openstack_utils.ssh_command(
username, address_1, 'instance-1',
'{} {}'.format(cmd, address_2),
password=password, privkey=privkey, verify=verify)
else:
openstack_utils.ssh_command(
username, floating_1, 'instance-1',
'{} {}'.format(cmd, address_2),
password=password, privkey=privkey, verify=verify)

openstack_utils.ssh_command(
username, floating_1, 'instance-1',
'{} {}'.format(cmd, floating_2),
password=password, privkey=privkey, verify=verify)
openstack_utils.ssh_command(
username, floating_1, 'instance-1',
'{} {}'.format(cmd, floating_2),
password=password, privkey=privkey, verify=verify)

@tenacity.retry(wait=tenacity.wait_exponential(multiplier=1, max=60),
reraise=True, stop=tenacity.stop_after_attempt(8))
def validate_instance_can_reach_router(self, instance, verify, mtu=None):
"""
Validate that an instance can reach it's primary gateway.

We make the assumption that the router's IP is 192.168.0.1
as that's the network that is setup in
neutron.setup.basic_overcloud_network which is used in all
Zaza Neutron validations.

:param instance: The instance to check networking from
:type instance: nova_client.Server

Expand All @@ -889,7 +914,12 @@ def validate_instance_can_reach_router(self, instance, verify, mtu=None):
:param mtu: Check that we can send non-fragmented packets of given size
:type mtu: Optional[int]
"""
address = floating_ips_from_instance(instance)[0]
if self.attach_to_external_network:
router = router_address_from_subnet(self.external_subnet)
address = fixed_ips_from_instance(instance)[0]
else:
router = router_address_from_subnet(self.project_subnet)
address = floating_ips_from_instance(instance)[0]

username = guest.boot_tests['bionic']['username']
password = guest.boot_tests['bionic'].get('password')
Expand All @@ -907,7 +937,7 @@ def validate_instance_can_reach_router(self, instance, verify, mtu=None):

for cmd in cmds:
openstack_utils.ssh_command(
username, address, 'instance', '{} 192.168.0.1'.format(cmd),
username, address, 'instance', '{} {}'.format(cmd, router),
password=password, privkey=privkey, verify=verify)

@tenacity.retry(wait=tenacity.wait_exponential(min=5, max=60),
Expand Down Expand Up @@ -1086,13 +1116,77 @@ class name + run_tearDown key under the `tests_options` key in
"""
instance_1, instance_2 = self.retrieve_guests()
if not all([instance_1, instance_2]):
self.launch_guests()
self.launch_guests(
attach_to_external_network=self.attach_to_external_network,
flavor_name=self.instance_flavor)
instance_1, instance_2 = self.retrieve_guests()
self.check_connectivity(instance_1, instance_2)
self.run_resource_cleanup = self.get_my_tests_options(
'run_resource_cleanup', True)


class DPDKNeutronNetworkingTest(NeutronNetworkingTest):
"""Ensure that openstack instances have valid networking with DPDK."""

@classmethod
def setUpClass(cls):
"""Run class setup for running Neutron API Networking tests."""
super(DPDKNeutronNetworkingTest, cls).setUpClass()

# At this point in time the charms do not support configuring overlay
# networks with DPDK. To perform end to end validation we need to
# attach instances directly to the provider network and subsequently
# DHCP needs to be enabled on that network.
#
# Note that for instances wired with DPDK the DHCP request/response is
# handled as private communication between the ovn-controller and the
# instance, and as such there is no risk of rogue DHCP replies escaping
# to the surrounding network.
cls.attach_to_external_network = True
cls.instance_flavor = 'hugepages'
cls.external_subnet = cls.neutron_client.find_resource(
'subnet',
neutron_setup.OVERCLOUD_NETWORK_CONFIG['external_subnet_name'])
if ('dhcp_enabled' not in cls.external_subnet or
not cls.external_subnet['dhcp_enabled']):
logging.info('Enabling DHCP on subnet {}'
.format(cls.external_subnet['name']))
openstack_utils.update_subnet_dhcp(
cls.neutron_client, cls.external_subnet, True)

def test_instances_have_networking(self):
"""Enable DPDK then Validate North/South and East/West networking."""
self.enable_hugepages_vfio_on_hvs_in_vms(4)
with self.config_change(
{
'enable-dpdk': False,
'dpdk-driver': '',
},
{
'enable-dpdk': True,
'dpdk-driver': 'vfio-pci',
},
application_name='ovn-chassis'):
super().test_instances_have_networking()
self.run_resource_cleanup = self.get_my_tests_options(
'run_resource_cleanup', True)

def resource_cleanup(self):
"""Extend to also revert VFIO NOIOMMU mode on units under test."""
super().resource_cleanup()
if not self.run_resource_cleanup:
return

if ('dhcp_enabled' not in self.external_subnet or
not self.external_subnet['dhcp_enabled']):
logging.info('Disabling DHCP on subnet {}'
.format(self.external_subnet['name']))
openstack_utils.update_subnet_dhcp(
self.neutron_client, self.external_subnet, False)

self.disable_hugepages_vfio_on_hvs_in_vms()


class NeutronNetworkingVRRPTests(NeutronNetworkingBase):
"""Check networking when gateways are restarted."""

Expand Down
9 changes: 9 additions & 0 deletions zaza/openstack/charm_tests/nova/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,5 +65,14 @@
'hw:tpm_model': 'tpm-crb',
},
},
'hugepages': {
'flavorid': 'auto',
'ram': 1024,
'disk': 20,
'vcpus': 1,
'extra-specs': {
'hw:mem_page_size': 'large',
},
},
}
KEYPAIR_NAME = 'zaza'
Loading

0 comments on commit 8fae05e

Please sign in to comment.