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:
Peter Feiner 2013-06-18 20:48:30 +00:00
parent 67548e10f0
commit 364e97b441
2 changed files with 95 additions and 4 deletions

View File

@ -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

View File

@ -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",