Merge "Enhance the test_multicast_between_vms_on_same_network test"

This commit is contained in:
Zuul 2020-02-13 02:22:06 +00:00 committed by Gerrit Code Review
commit c654d8a408
3 changed files with 82 additions and 8 deletions

View File

@ -123,6 +123,12 @@ NeutronPluginOptions = [
default=False, default=False,
help='Allow creation of shared resources.' help='Allow creation of shared resources.'
'The default value is false.'), 'The default value is false.'),
cfg.BoolOpt('is_igmp_snooping_enabled',
default=False,
help='Indicates whether IGMP snooping is enabled or not. '
'If True, multicast test(s) will assert that multicast '
'traffic is not being flooded to all ports. Defaults '
'to False.'),
] ]
# TODO(amuller): Redo configuration options registration as part of the planned # TODO(amuller): Redo configuration options registration as part of the planned

View File

@ -111,6 +111,14 @@ with open('%(result_file)s', 'w') as f:
'result_file': result_file} 'result_file': result_file}
def get_unregistered_script(group, result_file):
return """#!/bin/bash
export LC_ALL=en_US.UTF-8
tcpdump -i any -s0 -vv host %(group)s -vvneA -s0 -l &> %(result_file)s &
""" % {'group': group,
'result_file': result_file}
class BaseMulticastTest(object): class BaseMulticastTest(object):
credentials = ['primary'] credentials = ['primary']
@ -125,6 +133,7 @@ class BaseMulticastTest(object):
multicast_message = "Big Bang" multicast_message = "Big Bang"
receiver_output_file = "/tmp/receiver_mcast_out" receiver_output_file = "/tmp/receiver_mcast_out"
sender_output_file = "/tmp/sender_mcast_out" sender_output_file = "/tmp/sender_mcast_out"
unregistered_output_file = "/tmp/unregistered_mcast_out"
@classmethod @classmethod
def skip_checks(cls): def skip_checks(cls):
@ -198,16 +207,16 @@ class BaseMulticastTest(object):
server['ssh_client'] = ssh.Client(server['fip']['floating_ip_address'], server['ssh_client'] = ssh.Client(server['fip']['floating_ip_address'],
self.username, self.username,
pkey=self.keypair['private_key']) pkey=self.keypair['private_key'])
self._check_python_installed_on_server(server['ssh_client'], self._check_cmd_installed_on_server(server['ssh_client'],
server['id']) server['id'], PYTHON3_BIN)
return server return server
def _check_python_installed_on_server(self, ssh_client, server_id): def _check_cmd_installed_on_server(self, ssh_client, server_id, cmd):
try: try:
ssh_client.execute_script('which %s' % PYTHON3_BIN) ssh_client.execute_script('which %s' % cmd)
except exceptions.SSHScriptFailed: except exceptions.SSHScriptFailed:
raise self.skipException( raise self.skipException(
"%s is not available on server %s" % (PYTHON3_BIN, server_id)) "%s is not available on server %s" % (cmd, server_id))
def _prepare_sender(self, server, mcast_address): def _prepare_sender(self, server, mcast_address):
check_script = get_sender_script( check_script = get_sender_script(
@ -226,10 +235,23 @@ class BaseMulticastTest(object):
server['fip']['floating_ip_address'], server['fip']['floating_ip_address'],
self.username, self.username,
pkey=self.keypair['private_key']) pkey=self.keypair['private_key'])
self._check_python_installed_on_server(ssh_client, server['id']) self._check_cmd_installed_on_server(ssh_client, server['id'],
PYTHON3_BIN)
server['ssh_client'].execute_script( server['ssh_client'].execute_script(
'echo "%s" > ~/multicast_traffic_receiver.py' % check_script) 'echo "%s" > ~/multicast_traffic_receiver.py' % check_script)
def _prepare_unregistered(self, server, mcast_address):
check_script = get_unregistered_script(
group=mcast_address, result_file=self.unregistered_output_file)
ssh_client = ssh.Client(
server['fip']['floating_ip_address'],
self.username,
pkey=self.keypair['private_key'])
self._check_cmd_installed_on_server(ssh_client, server['id'],
'tcpdump')
server['ssh_client'].execute_script(
'echo "%s" > ~/unregistered_traffic_receiver.sh' % check_script)
@test.unstable_test("bug 1850288") @test.unstable_test("bug 1850288")
@decorators.idempotent_id('113486fc-24c9-4be4-8361-03b1c9892867') @decorators.idempotent_id('113486fc-24c9-4be4-8361-03b1c9892867')
def test_multicast_between_vms_on_same_network(self): def test_multicast_between_vms_on_same_network(self):
@ -241,9 +263,26 @@ class BaseMulticastTest(object):
receivers = [self._create_server() for _ in range(1)] receivers = [self._create_server() for _ in range(1)]
# Sender can be also receiver of multicast traffic # Sender can be also receiver of multicast traffic
receivers.append(sender) receivers.append(sender)
self._check_multicast_conectivity(sender=sender, receivers=receivers) unregistered = self._create_server()
self._check_multicast_conectivity(sender=sender, receivers=receivers,
unregistered=unregistered)
def _check_multicast_conectivity(self, sender, receivers): def _is_multicast_traffic_expected(self, mcast_address):
"""Checks if multicast traffic is expected to arrive.
Checks if multicast traffic is expected to arrive to the
unregistered VM.
If IGMP snooping is enabled, multicast traffic should not be
flooded unless the destination IP is in the range of 224.0.0.X
[0].
[0] https://tools.ietf.org/html/rfc4541 (See section 2.1.2)
"""
return (mcast_address.startswith('224.0.0') or not
CONF.neutron_plugin_options.is_igmp_snooping_enabled)
def _check_multicast_conectivity(self, sender, receivers, unregistered):
"""Test multi-cast messaging between two servers """Test multi-cast messaging between two servers
[Sender server] -> ... some network topology ... -> [Receiver server] [Sender server] -> ... some network topology ... -> [Receiver server]
@ -257,6 +296,12 @@ class BaseMulticastTest(object):
path=file_path)) path=file_path))
return msg in result return msg in result
self._prepare_unregistered(unregistered, mcast_address)
# Run the unregistered node script
unregistered['ssh_client'].execute_script(
"bash ~/unregistered_traffic_receiver.sh", become_root=True)
self._prepare_sender(sender, mcast_address) self._prepare_sender(sender, mcast_address)
receiver_ids = [] receiver_ids = []
for receiver in receivers: for receiver in receivers:
@ -295,6 +340,18 @@ class BaseMulticastTest(object):
for receiver_id in receiver_ids: for receiver_id in receiver_ids:
self.assertIn(receiver_id, replies_result) self.assertIn(receiver_id, replies_result)
# Kill the tcpdump command running on the unregistered node so
# tcpdump flushes its output to the output file
unregistered['ssh_client'].execute_script(
"killall tcpdump && sleep 2", become_root=True)
unregistered_result = unregistered['ssh_client'].execute_script(
"cat {path} || echo '{path} not exists yet'".format(
path=self.unregistered_output_file))
num_of_pckt = (1 if self._is_multicast_traffic_expected(mcast_address)
else 0)
self.assertIn('%d packets captured' % num_of_pckt, unregistered_result)
class MulticastTestIPv4(BaseMulticastTest, base.BaseTempestTestCase): class MulticastTestIPv4(BaseMulticastTest, base.BaseTempestTestCase):

View File

@ -0,0 +1,11 @@
---
features:
- |
Enhanced the ``test_multicast_between_vms_on_same_network`` adding
IGMP test coverage to it. A new VM running tcpdump is spawned as
part of the test to verify whether the traffic is reaching it or not.
upgrade:
- |
Add a new configuration option called ``is_igmp_snooping_enabled``
to enable/disable IGMP testing as part of the
``test_multicast_between_vms_on_same_network`` test case.