faster quantum-openvswitch-agent periodic reports
One of two patches that fixes bug #1194438. Instead of spawning ovs-vsctl for every port on br-int, we just dump the required columns from the Interfaces table and grab the rows that we need. This is a big win because the time it takes for ovs-vsctl to connect to the openvswitch controller is orders of magnitude greater than the time it takes to parse the rows. In practice, instead of taking roughly 1s per interface, the agent's periodic task only takes 1s in total. Change-Id: Idbf32c38e0c4a9c9634c1e4f0e79bd556b720493
This commit is contained in:
parent
67548e10f0
commit
364e97b441
|
@ -22,6 +22,7 @@ import re
|
|||
|
||||
from quantum.agent.linux import ip_lib
|
||||
from quantum.agent.linux import utils
|
||||
from quantum.openstack.common import jsonutils
|
||||
from quantum.openstack.common import log as logging
|
||||
from quantum.plugins.openvswitch.common import constants
|
||||
|
||||
|
@ -252,10 +253,18 @@ class OVSBridge:
|
|||
return edge_ports
|
||||
|
||||
def get_vif_port_set(self):
|
||||
edge_ports = set()
|
||||
port_names = self.get_port_name_list()
|
||||
for name in port_names:
|
||||
external_ids = self.db_get_map("Interface", name, "external_ids")
|
||||
edge_ports = set()
|
||||
args = ['--format=json', '--', '--columns=name,external_ids',
|
||||
'list', 'Interface']
|
||||
result = self.run_vsctl(args)
|
||||
if not result:
|
||||
return edge_ports
|
||||
for row in jsonutils.loads(result)['data']:
|
||||
name = row[0]
|
||||
if name not in port_names:
|
||||
continue
|
||||
external_ids = dict(row[1][1])
|
||||
if "iface-id" in external_ids and "attached-mac" in external_ids:
|
||||
edge_ports.add(external_ids['iface-id'])
|
||||
elif ("xs-vif-uuid" in external_ids and
|
||||
|
|
|
@ -19,7 +19,9 @@ import mock
|
|||
import mox
|
||||
import testtools
|
||||
|
||||
from quantum.agent.linux import ovs_lib, utils
|
||||
from quantum.agent.linux import ovs_lib
|
||||
from quantum.agent.linux import utils
|
||||
from quantum.openstack.common import jsonutils
|
||||
from quantum.openstack.common import uuidutils
|
||||
from quantum.tests import base
|
||||
|
||||
|
@ -264,12 +266,92 @@ class OVS_Lib_Test(base.BaseTestCase):
|
|||
self.assertEqual(ports[0].switch.br_name, self.BR_NAME)
|
||||
self.mox.VerifyAll()
|
||||
|
||||
def _encode_ovs_json(self, headings, data):
|
||||
# See man ovs-vsctl(8) for the encoding details.
|
||||
r = {"data": [],
|
||||
"headings": headings}
|
||||
for row in data:
|
||||
ovs_row = []
|
||||
r["data"].append(ovs_row)
|
||||
for cell in row:
|
||||
if isinstance(cell, str):
|
||||
ovs_row.append(cell)
|
||||
elif isinstance(cell, dict):
|
||||
ovs_row.append(["map", cell.items()])
|
||||
else:
|
||||
raise TypeError('%r not str or dict' % type(cell))
|
||||
return jsonutils.dumps(r)
|
||||
|
||||
def _test_get_vif_port_set(self, is_xen):
|
||||
utils.execute(["ovs-vsctl", self.TO, "list-ports", self.BR_NAME],
|
||||
root_helper=self.root_helper).AndReturn('tap99\ntun22')
|
||||
|
||||
if is_xen:
|
||||
id_key = 'xs-vif-uuid'
|
||||
else:
|
||||
id_key = 'iface-id'
|
||||
|
||||
headings = ['name', 'external_ids']
|
||||
data = [
|
||||
# A vif port on this bridge:
|
||||
['tap99', {id_key: 'tap99id', 'attached-mac': 'tap99mac'}],
|
||||
# A vif port on another bridge:
|
||||
['tap88', {id_key: 'tap88id', 'attached-mac': 'tap88id'}],
|
||||
# Non-vif port on this bridge:
|
||||
['tun22', {}],
|
||||
]
|
||||
|
||||
utils.execute(["ovs-vsctl", self.TO, "--format=json",
|
||||
"--", "--columns=name,external_ids",
|
||||
"list", "Interface"],
|
||||
root_helper=self.root_helper).AndReturn(
|
||||
self._encode_ovs_json(headings, data))
|
||||
|
||||
if is_xen:
|
||||
self.mox.StubOutWithMock(self.br, 'get_xapi_iface_id')
|
||||
self.br.get_xapi_iface_id('tap99id').AndReturn('tap99id')
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
port_set = self.br.get_vif_port_set()
|
||||
self.assertEqual(set(['tap99id']), port_set)
|
||||
self.mox.VerifyAll()
|
||||
|
||||
def test_get_vif_ports_nonxen(self):
|
||||
self._test_get_vif_ports(False)
|
||||
|
||||
def test_get_vif_ports_xen(self):
|
||||
self._test_get_vif_ports(True)
|
||||
|
||||
def test_get_vif_port_set_nonxen(self):
|
||||
self._test_get_vif_port_set(False)
|
||||
|
||||
def test_get_vif_port_set_xen(self):
|
||||
self._test_get_vif_port_set(True)
|
||||
|
||||
def test_get_vif_port_set_list_ports_error(self):
|
||||
utils.execute(["ovs-vsctl", self.TO, "list-ports", self.BR_NAME],
|
||||
root_helper=self.root_helper).AndRaise(RuntimeError())
|
||||
utils.execute(["ovs-vsctl", self.TO, "--format=json",
|
||||
"--", "--columns=name,external_ids",
|
||||
"list", "Interface"],
|
||||
root_helper=self.root_helper).AndReturn(
|
||||
self._encode_ovs_json(['name', 'external_ids'], []))
|
||||
self.mox.ReplayAll()
|
||||
self.assertEqual(set(), self.br.get_vif_port_set())
|
||||
self.mox.VerifyAll()
|
||||
|
||||
def test_get_vif_port_set_list_interface_error(self):
|
||||
utils.execute(["ovs-vsctl", self.TO, "list-ports", self.BR_NAME],
|
||||
root_helper=self.root_helper).AndRaise('tap99\n')
|
||||
utils.execute(["ovs-vsctl", self.TO, "--format=json",
|
||||
"--", "--columns=name,external_ids",
|
||||
"list", "Interface"],
|
||||
root_helper=self.root_helper).AndRaise(RuntimeError())
|
||||
self.mox.ReplayAll()
|
||||
self.assertEqual(set(), self.br.get_vif_port_set())
|
||||
self.mox.VerifyAll()
|
||||
|
||||
def test_clear_db_attribute(self):
|
||||
pname = "tap77"
|
||||
utils.execute(["ovs-vsctl", self.TO, "clear", "Port",
|
||||
|
|
Loading…
Reference in New Issue