Optimize get_bridge_for_tap_device

Currently get_bridge_for_tap_device[1] iterates over all neutron bridges
and their interfaces.

This change proposes to deduce interface bridge from:

 /sys/class/net/%(interface)s/brif/bridge

which is a symlink to bridge interface path to improve performance.

[1] neutron.plugins.ml2.drivers.linuxbridge.agent.linuxbridge_neutron_agent

Closes-Bug: #1508789
Change-Id: Ia40cd81f47ff082a90d17f58514942ec50553241
This commit is contained in:
Cedric Brandily 2015-10-26 09:50:20 +09:00
parent 0f471be1de
commit 75c881a748
3 changed files with 37 additions and 13 deletions

View File

@ -65,6 +65,7 @@ BRIDGE_FS = "/sys/class/net/"
BRIDGE_INTERFACE_FS = BRIDGE_FS + "%(bridge)s/brif/%(interface)s"
BRIDGE_INTERFACES_FS = BRIDGE_FS + "%s/brif/"
BRIDGE_PORT_FS_FOR_DEVICE = BRIDGE_FS + "%s/brport"
BRIDGE_PATH_FOR_DEVICE = BRIDGE_PORT_FS_FOR_DEVICE + '/bridge'
VXLAN_INTERFACE_PREFIX = "vxlan-"
@ -201,12 +202,15 @@ class LinuxBridgeManager(object):
return 0
def get_bridge_for_tap_device(self, tap_device_name):
bridges = self.get_all_neutron_bridges()
for bridge in bridges:
interfaces = self.get_interfaces_on_bridge(bridge)
if tap_device_name in interfaces:
try:
path = os.readlink(BRIDGE_PATH_FOR_DEVICE % tap_device_name)
except OSError:
pass
else:
bridge = path.rpartition('/')[-1]
if (bridge.startswith(BRIDGE_NAME_PREFIX)
or bridge in self.bridge_mappings.values()):
return bridge
return None
def is_device_on_bridge(self, device_name):

View File

@ -76,3 +76,15 @@ class LinuxBridgeAgentTests(test_ip_lib.IpLibTestFramework):
self.assertFalse(
lba.LinuxBridgeManager.interface_exists_on_bridge(
port_fixture.bridge.name, port_fixture.port.name))
def test_get_bridge_for_tap_device(self):
port_fixture = self.create_bridge_port_fixture()
mappings = {'physnet1': port_fixture.bridge.name}
lbm = lba.LinuxBridgeManager(mappings, {})
self.assertEqual(
port_fixture.bridge.name,
lbm.get_bridge_for_tap_device(port_fixture.br_port.name))
def test_get_no_bridge_for_tap_device(self):
lbm = lba.LinuxBridgeManager({}, {})
self.assertIsNone(lbm.get_bridge_for_tap_device('fake'))

View File

@ -32,7 +32,8 @@ from neutron.tests import base
LOCAL_IP = '192.168.0.33'
DEVICE_1 = 'tapabcdef01-12'
BRIDGE_MAPPINGS = {'physnet0': 'br-eth2'}
BRIDGE_MAPPING_VALUE = 'br-eth2'
BRIDGE_MAPPINGS = {'physnet0': BRIDGE_MAPPING_VALUE}
INTERFACE_MAPPINGS = {'physnet1': 'eth1'}
FAKE_DEFAULT_DEV = mock.Mock()
FAKE_DEFAULT_DEV.name = 'eth1'
@ -492,14 +493,21 @@ class TestLinuxBridgeManager(base.BaseTestCase):
self.assertEqual(self.lbm.get_tap_devices_count('br0'), 0)
def test_get_bridge_for_tap_device(self):
with mock.patch.object(self.lbm,
"get_all_neutron_bridges") as get_all_qbr_fn,\
mock.patch.object(self.lbm,
"get_interfaces_on_bridge") as get_if_fn:
get_all_qbr_fn.return_value = ["br-int", "br-ex"]
get_if_fn.return_value = ["tap1", "tap2", "tap3"]
with mock.patch.object(os, 'readlink') as readlink:
readlink.return_value = (
'blah/%s-fake' % linuxbridge_neutron_agent.BRIDGE_NAME_PREFIX)
self.assertEqual(self.lbm.get_bridge_for_tap_device("tap1"),
"br-int")
"brq-fake")
readlink.return_value = 'blah/%s' % BRIDGE_MAPPING_VALUE
self.assertEqual(self.lbm.get_bridge_for_tap_device("tap2"),
BRIDGE_MAPPING_VALUE)
readlink.return_value = 'blah/notneutronbridge'
self.assertIsNone(self.lbm.get_bridge_for_tap_device("tap3"))
readlink.side_effect = OSError()
self.assertIsNone(self.lbm.get_bridge_for_tap_device("tap4"))
def test_is_device_on_bridge(self):