From b4e42a341894177a1c870a48b2641bae6c36696e Mon Sep 17 00:00:00 2001 From: Yalei Wang Date: Tue, 9 Jun 2015 13:46:57 +0800 Subject: [PATCH] Add new ovs DB API to inquire interfaces name list in a bridge In OVS, ports don't equal to interfaces when a bond port created. This patch add the new API get_iface_name_list to get the interfaces' name, and it's supplementary to the current get_port_name_list API. Change-Id: I29c220e099b8dcf78248e2d660c435578bb2932d Partial-Bug: #1460494 --- neutron/agent/common/ovs_lib.py | 5 ++++ neutron/agent/ovsdb/api.py | 11 ++++++- neutron/agent/ovsdb/impl_idl.py | 6 ++-- neutron/agent/ovsdb/impl_vsctl.py | 3 ++ neutron/agent/ovsdb/native/commands.py | 29 ++++++++++++++++++- .../tests/functional/agent/test_ovs_lib.py | 4 +++ 6 files changed, 54 insertions(+), 4 deletions(-) diff --git a/neutron/agent/common/ovs_lib.py b/neutron/agent/common/ovs_lib.py index 49c7a6e9c..a26f16e51 100644 --- a/neutron/agent/common/ovs_lib.py +++ b/neutron/agent/common/ovs_lib.py @@ -304,7 +304,12 @@ class OVSBridge(BaseOVS): ('options', {'peer': remote_name})] return self.add_port(local_name, *attrs) + def get_iface_name_list(self): + # get the interface name list for this bridge + return self.ovsdb.list_ifaces(self.br_name).execute(check_error=True) + def get_port_name_list(self): + # get the port name list for this bridge return self.ovsdb.list_ports(self.br_name).execute(check_error=True) def get_port_stats(self, port_name): diff --git a/neutron/agent/ovsdb/api.py b/neutron/agent/ovsdb/api.py index e696f8e85..58fb135f5 100644 --- a/neutron/agent/ovsdb/api.py +++ b/neutron/agent/ovsdb/api.py @@ -308,13 +308,22 @@ class API(object): @abc.abstractmethod def list_ports(self, bridge): - """Create a command to list the names of porsts on a bridge + """Create a command to list the names of ports on a bridge :param bridge: The name of the bridge :type bridge: string :returns: :class:`Command` with list of port names result """ + @abc.abstractmethod + def list_ifaces(self, bridge): + """Create a command to list the names of interfaces on a bridge + + :param bridge: The name of the bridge + :type bridge: string + :returns: :class:`Command` with list of interfaces names result + """ + def val_to_py(val): """Convert a json ovsdb return value to native python object""" diff --git a/neutron/agent/ovsdb/impl_idl.py b/neutron/agent/ovsdb/impl_idl.py index 5b1547287..4edb407c3 100644 --- a/neutron/agent/ovsdb/impl_idl.py +++ b/neutron/agent/ovsdb/impl_idl.py @@ -157,8 +157,7 @@ class OvsdbIdl(api.API): return cmd.PortToBridgeCommand(self, name) def iface_to_br(self, name): - # For our purposes, ports and interfaces always have the same name - return cmd.PortToBridgeCommand(self, name) + return cmd.InterfaceToBridgeCommand(self, name) def list_br(self): return cmd.ListBridgesCommand(self) @@ -204,3 +203,6 @@ class OvsdbIdl(api.API): def list_ports(self, bridge): return cmd.ListPortsCommand(self, bridge) + + def list_ifaces(self, bridge): + return cmd.ListIfacesCommand(self, bridge) diff --git a/neutron/agent/ovsdb/impl_vsctl.py b/neutron/agent/ovsdb/impl_vsctl.py index 15f52529b..aa0092297 100644 --- a/neutron/agent/ovsdb/impl_vsctl.py +++ b/neutron/agent/ovsdb/impl_vsctl.py @@ -241,6 +241,9 @@ class OvsdbVsctl(ovsdb.API): def list_ports(self, bridge): return MultiLineCommand(self.context, 'list-ports', args=[bridge]) + def list_ifaces(self, bridge): + return MultiLineCommand(self.context, 'list-ifaces', args=[bridge]) + def _set_colval_args(*col_values): args = [] diff --git a/neutron/agent/ovsdb/native/commands.py b/neutron/agent/ovsdb/native/commands.py index 973c4cac1..76bb8ae78 100644 --- a/neutron/agent/ovsdb/native/commands.py +++ b/neutron/agent/ovsdb/native/commands.py @@ -332,6 +332,17 @@ class ListPortsCommand(BaseCommand): self.result = [p.name for p in br.ports if p.name != self.bridge] +class ListIfacesCommand(BaseCommand): + def __init__(self, api, bridge): + super(ListIfacesCommand, self).__init__(api) + self.bridge = bridge + + def run_idl(self, txn): + br = idlutils.row_by_value(self.api.idl, 'Bridge', 'name', self.bridge) + self.result = [i.name for p in br.ports if p.name != self.bridge + for i in p.interfaces] + + class PortToBridgeCommand(BaseCommand): def __init__(self, api, name): super(PortToBridgeCommand, self).__init__(api) @@ -340,7 +351,7 @@ class PortToBridgeCommand(BaseCommand): def run_idl(self, txn): # TODO(twilson) This is expensive! # This traversal of all ports could be eliminated by caching the bridge - # name on the Port's (or Interface's for iface_to_br) external_id field + # name on the Port's external_id field # In fact, if we did that, the only place that uses to_br functions # could just add the external_id field to the conditions passed to find port = idlutils.row_by_value(self.api.idl, 'Port', 'name', self.name) @@ -348,6 +359,22 @@ class PortToBridgeCommand(BaseCommand): self.result = next(br.name for br in bridges if port in br.ports) +class InterfaceToBridgeCommand(BaseCommand): + def __init__(self, api, name): + super(InterfaceToBridgeCommand, self).__init__(api) + self.name = name + + def run_idl(self, txn): + interface = idlutils.row_by_value(self.api.idl, 'Interface', 'name', + self.name) + ports = self.api._tables['Port'].rows.values() + pname = next( + port for port in ports if interface in port.interfaces) + + bridges = self.api._tables['Bridge'].rows.values() + self.result = next(br.name for br in bridges if pname in br.ports) + + class DbListCommand(BaseCommand): def __init__(self, api, table, records, columns, if_exists): super(DbListCommand, self).__init__(api) diff --git a/neutron/tests/functional/agent/test_ovs_lib.py b/neutron/tests/functional/agent/test_ovs_lib.py index 5c5409a60..b81e6a526 100644 --- a/neutron/tests/functional/agent/test_ovs_lib.py +++ b/neutron/tests/functional/agent/test_ovs_lib.py @@ -174,6 +174,10 @@ class OVSBridgeTestCase(OVSBridgeTestBase): ports = {self.create_ovs_port()[0] for i in range(5)} self.assertSetEqual(ports, set(self.br.get_port_name_list())) + def test_get_iface_name_list(self): + ifaces = {self.create_ovs_port()[0] for i in range(5)} + self.assertSetEqual(ifaces, set(self.br.get_iface_name_list())) + def test_get_port_stats(self): # Nothing seems to use this function? (port_name, ofport) = self.create_ovs_port() -- 2.45.2