Skip to content

Commit

Permalink
faster quantum-openvswitch-agent periodic reports
Browse files Browse the repository at this point in the history
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
(cherry picked from commit 364e97b)
  • Loading branch information
Peter Feiner authored and Édouard Thuleau committed Jul 3, 2013
1 parent b9daf57 commit 5f32671
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 4 deletions.
15 changes: 12 additions & 3 deletions quantum/agent/linux/ovs_lib.py
Expand Up @@ -21,6 +21,7 @@
import re

from quantum.agent.linux import utils
from quantum.openstack.common import jsonutils
from quantum.openstack.common import log as logging

LOG = logging.getLogger(__name__)
Expand Down Expand Up @@ -239,10 +240,18 @@ def get_vif_ports(self):
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
Expand Down
84 changes: 83 additions & 1 deletion quantum/tests/unit/openvswitch/test_ovs_lib.py
Expand Up @@ -17,7 +17,9 @@

import mox

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

Expand Down Expand Up @@ -262,12 +264,92 @@ def _test_get_vif_ports(self, is_xen=False):
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",
Expand Down

0 comments on commit 5f32671

Please sign in to comment.