]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
faster quantum-openvswitch-agent periodic reports
authorPeter Feiner <peter@gridcentric.ca>
Tue, 18 Jun 2013 20:48:30 +0000 (20:48 +0000)
committerPeter Feiner <peter@gridcentric.ca>
Fri, 28 Jun 2013 17:55:41 +0000 (17:55 +0000)
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

quantum/agent/linux/ovs_lib.py
quantum/tests/unit/openvswitch/test_ovs_lib.py

index b13bbc9e9a5f87bbbaf130cd92254308cf4c81c6..66441e19245317c3de355d87da4fd25734b221f0 100644 (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
index 1995c8987b14dc9fbfbe7403b4fdff9ad8a8b00c..7deb0a25d6601cd6ecc1666aa2de300f0b0a86eb 100644 (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",