Merge "Fix multicast traffic with IGMP snooping enabled" into stable/train

This commit is contained in:
Zuul 2021-03-29 21:01:14 +00:00 committed by Gerrit Code Review
commit e6466edf79
6 changed files with 65 additions and 6 deletions

View File

@ -294,7 +294,7 @@ class OVSBridge(BaseOVS):
def set_igmp_snooping_state(self, state): def set_igmp_snooping_state(self, state):
state = bool(state) state = bool(state)
other_config = { other_config = {
'mcast-snooping-disable-flood-unregistered': str(state)} 'mcast-snooping-disable-flood-unregistered': 'false'}
with self.ovsdb.transaction() as txn: with self.ovsdb.transaction() as txn:
txn.add( txn.add(
self.ovsdb.db_set('Bridge', self.br_name, self.ovsdb.db_set('Bridge', self.br_name,
@ -303,6 +303,16 @@ class OVSBridge(BaseOVS):
self.ovsdb.db_set('Bridge', self.br_name, self.ovsdb.db_set('Bridge', self.br_name,
('other_config', other_config))) ('other_config', other_config)))
def set_igmp_snooping_flood(self, port_name, state):
state = str(state)
other_config = {
'mcast-snooping-flood-reports': state,
'mcast-snooping-flood': state}
self.ovsdb.db_set(
'Port', port_name,
('other_config', other_config)).execute(
check_error=True, log_errors=True)
def create(self, secure_mode=False): def create(self, secure_mode=False):
other_config = { other_config = {
'mac-table-size': str(cfg.CONF.OVS.bridge_mac_table_size)} 'mac-table-size': str(cfg.CONF.OVS.bridge_mac_table_size)}

View File

@ -1431,6 +1431,9 @@ class OVSNeutronAgent(l2population_rpc.L2populationRpcCallBackTunnelMixin,
"version of OVS does not support tunnels or patch " "version of OVS does not support tunnels or patch "
"ports. Agent terminated!") "ports. Agent terminated!")
sys.exit(1) sys.exit(1)
self.int_br.set_igmp_snooping_flood(
self.conf.OVS.int_peer_patch_port,
self.conf.OVS.igmp_snooping_enable)
if self.conf.AGENT.drop_flows_on_start: if self.conf.AGENT.drop_flows_on_start:
self.tun_br.uninstall_flows(cookie=ovs_lib.COOKIE_ANY) self.tun_br.uninstall_flows(cookie=ovs_lib.COOKIE_ANY)
@ -1584,6 +1587,8 @@ class OVSNeutronAgent(l2population_rpc.L2populationRpcCallBackTunnelMixin,
phys_ofport = br.add_patch_port( phys_ofport = br.add_patch_port(
phys_if_name, constants.NONEXISTENT_PEER) phys_if_name, constants.NONEXISTENT_PEER)
self.int_br.set_igmp_snooping_flood(
int_if_name, self.conf.OVS.igmp_snooping_enable)
self.int_ofports[physical_network] = int_ofport self.int_ofports[physical_network] = int_ofport
self.phys_ofports[physical_network] = phys_ofport self.phys_ofports[physical_network] = phys_ofport

View File

@ -481,3 +481,27 @@ class BaseOVSTestCase(base.BaseSudoTestCase):
self.assertEqual(p_const.TYPE_GRE, ipv4_port_type) self.assertEqual(p_const.TYPE_GRE, ipv4_port_type)
self.assertEqual(ovs_lib.TYPE_GRE_IP6, ipv6_port_type) self.assertEqual(ovs_lib.TYPE_GRE_IP6, ipv6_port_type)
self.assertEqual('legacy_l2', ipv6_port_options.get('packet_type')) self.assertEqual('legacy_l2', ipv6_port_options.get('packet_type'))
def test_set_igmp_snooping_flood(self):
port_name = 'test_output_port_2'
self._create_bridge()
self._create_port(port_name)
self.ovs.set_igmp_snooping_flood(port_name, True)
ports_other_config = self.ovs.db_get_val('Port', port_name,
'other_config')
self.assertEqual(
'true',
ports_other_config.get('mcast-snooping-flood', '').lower())
self.assertEqual(
'true',
ports_other_config.get('mcast-snooping-flood-reports', '').lower())
self.ovs.set_igmp_snooping_flood(port_name, False)
ports_other_config = self.ovs.db_get_val('Port', port_name,
'other_config')
self.assertEqual(
'false',
ports_other_config.get('mcast-snooping-flood', '').lower())
self.assertEqual(
'false',
ports_other_config.get('mcast-snooping-flood-reports', '').lower())

View File

@ -196,8 +196,9 @@ class OVSBridgeTestCase(OVSBridgeTestBase):
'Bridge', ('name', '=', self.br.br_name), columns=['other_config'] 'Bridge', ('name', '=', self.br.br_name), columns=['other_config']
).execute()[0]['other_config'] ).execute()[0]['other_config']
self.assertEqual( self.assertEqual(
str(state), 'false',
br_other_config['mcast-snooping-disable-flood-unregistered']) br_other_config.get(
'mcast-snooping-disable-flood-unregistered', '').lower())
def test_set_igmp_snooping_enabled(self): def test_set_igmp_snooping_enabled(self):
self._test_set_igmp_snooping_state(True) self._test_set_igmp_snooping_state(True)

View File

@ -1526,7 +1526,8 @@ class TestOvsNeutronAgent(object):
self.assertNotIn('activated_port_id', port_info['added']) self.assertNotIn('activated_port_id', port_info['added'])
def _test_setup_physical_bridges(self, port_exists=False, def _test_setup_physical_bridges(self, port_exists=False,
dvr_enabled=False): dvr_enabled=False,
igmp_snooping_enabled=False):
self.agent.enable_distributed_routing = dvr_enabled self.agent.enable_distributed_routing = dvr_enabled
with mock.patch.object(ip_lib.IPDevice, "exists") as devex_fn,\ with mock.patch.object(ip_lib.IPDevice, "exists") as devex_fn,\
mock.patch.object(sys, "exit"),\ mock.patch.object(sys, "exit"),\
@ -1584,6 +1585,8 @@ class TestOvsNeutronAgent(object):
'phy-br-eth', constants.NONEXISTENT_PEER), 'phy-br-eth', constants.NONEXISTENT_PEER),
] ]
expected_calls += [ expected_calls += [
mock.call.int_br.set_igmp_snooping_flood(
'int-br-eth', igmp_snooping_enabled),
mock.call.int_br.drop_port(in_port='int_ofport') mock.call.int_br.drop_port(in_port='int_ofport')
] ]
if not dvr_enabled: if not dvr_enabled:
@ -1653,6 +1656,10 @@ class TestOvsNeutronAgent(object):
int_br.add_port.assert_called_with("int-br-eth") int_br.add_port.assert_called_with("int-br-eth")
phys_br.add_port.assert_called_with("phy-br-eth") phys_br.add_port.assert_called_with("phy-br-eth")
def test_setup_physical_bridges_igmp_snooping_enabled(self):
cfg.CONF.set_override('igmp_snooping_enable', True, 'OVS')
self._test_setup_physical_bridges(igmp_snooping_enabled=True)
def _test_setup_physical_bridges_change_from_veth_to_patch_conf( def _test_setup_physical_bridges_change_from_veth_to_patch_conf(
self, port_exists=False): self, port_exists=False):
with mock.patch.object(sys, "exit"),\ with mock.patch.object(sys, "exit"),\
@ -1708,6 +1715,8 @@ class TestOvsNeutronAgent(object):
'phy-br-eth', constants.NONEXISTENT_PEER), 'phy-br-eth', constants.NONEXISTENT_PEER),
] ]
expected_calls += [ expected_calls += [
mock.call.int_br.set_igmp_snooping_flood(
'int-br-eth', False),
mock.call.int_br.drop_port(in_port='int_ofport'), mock.call.int_br.drop_port(in_port='int_ofport'),
mock.call.phys_br.drop_port(in_port='phy_ofport'), mock.call.phys_br.drop_port(in_port='phy_ofport'),
mock.call.int_br.set_db_attribute('Interface', 'int-br-eth', mock.call.int_br.set_db_attribute('Interface', 'int-br-eth',
@ -1748,6 +1757,8 @@ class TestOvsNeutronAgent(object):
return_value=False),\ return_value=False),\
mock.patch.object(self.agent.int_br, 'port_exists', mock.patch.object(self.agent.int_br, 'port_exists',
return_value=False),\ return_value=False),\
mock.patch.object(self.agent.int_br,
'set_igmp_snooping_flood'),\
mock.patch.object(sys, "exit"): mock.patch.object(sys, "exit"):
self.agent.setup_tunnel_br(None) self.agent.setup_tunnel_br(None)
self.agent.setup_tunnel_br() self.agent.setup_tunnel_br()
@ -1772,6 +1783,8 @@ class TestOvsNeutronAgent(object):
"add_patch_port") as int_patch_port,\ "add_patch_port") as int_patch_port,\
mock.patch.object(self.agent.tun_br, mock.patch.object(self.agent.tun_br,
"add_patch_port") as tun_patch_port,\ "add_patch_port") as tun_patch_port,\
mock.patch.object(self.agent.int_br,
'set_igmp_snooping_flood'),\
mock.patch.object(sys, "exit"): mock.patch.object(sys, "exit"):
self.agent.setup_tunnel_br(None) self.agent.setup_tunnel_br(None)
self.agent.setup_tunnel_br() self.agent.setup_tunnel_br()

View File

@ -234,6 +234,8 @@ class TunnelTest(object):
mock.call.port_exists('int-%s' % self.MAP_TUN_BRIDGE), mock.call.port_exists('int-%s' % self.MAP_TUN_BRIDGE),
mock.call.add_patch_port('int-%s' % self.MAP_TUN_BRIDGE, mock.call.add_patch_port('int-%s' % self.MAP_TUN_BRIDGE,
constants.NONEXISTENT_PEER), constants.NONEXISTENT_PEER),
mock.call.set_igmp_snooping_flood('int-%s' % self.MAP_TUN_BRIDGE,
igmp_snooping),
] ]
self.mock_int_bridge_expected += [ self.mock_int_bridge_expected += [
@ -263,6 +265,7 @@ class TunnelTest(object):
self.mock_int_bridge_expected += [ self.mock_int_bridge_expected += [
mock.call.port_exists('patch-tun'), mock.call.port_exists('patch-tun'),
mock.call.add_patch_port('patch-tun', 'patch-int'), mock.call.add_patch_port('patch-tun', 'patch-int'),
mock.call.set_igmp_snooping_flood('patch-tun', igmp_snooping),
] ]
self.mock_int_bridge_expected += [ self.mock_int_bridge_expected += [
mock.call.get_vif_ports((ovs_lib.INVALID_OFPORT, mock.call.get_vif_ports((ovs_lib.INVALID_OFPORT,
@ -715,7 +718,9 @@ class TunnelTestUseVethInterco(TunnelTest):
self.mock_int_bridge_expected += [ self.mock_int_bridge_expected += [
mock.call.db_get_val('Interface', 'int-%s' % self.MAP_TUN_BRIDGE, mock.call.db_get_val('Interface', 'int-%s' % self.MAP_TUN_BRIDGE,
'type', log_errors=False), 'type', log_errors=False),
mock.call.add_port('int-%s' % self.MAP_TUN_BRIDGE) mock.call.add_port('int-%s' % self.MAP_TUN_BRIDGE),
mock.call.set_igmp_snooping_flood('int-%s' % self.MAP_TUN_BRIDGE,
igmp_snooping),
] ]
self.mock_int_bridge_expected += [ self.mock_int_bridge_expected += [
@ -738,7 +743,8 @@ class TunnelTestUseVethInterco(TunnelTest):
] ]
self.mock_int_bridge_expected += [ self.mock_int_bridge_expected += [
mock.call.port_exists('patch-tun'), mock.call.port_exists('patch-tun'),
mock.call.add_patch_port('patch-tun', 'patch-int') mock.call.add_patch_port('patch-tun', 'patch-int'),
mock.call.set_igmp_snooping_flood('patch-tun', igmp_snooping),
] ]
self.mock_int_bridge_expected += [ self.mock_int_bridge_expected += [
mock.call.get_vif_ports((ovs_lib.INVALID_OFPORT, mock.call.get_vif_ports((ovs_lib.INVALID_OFPORT,