Merge "dhcp-agent: Ryu plugin support for dhcp agent"
This commit is contained in:
commit
314a2deb66
@ -15,6 +15,8 @@ state_path = /opt/stack/data
|
||||
interface_driver = quantum.agent.linux.interface.OVSInterfaceDriver
|
||||
# LinuxBridge
|
||||
#interface_driver = quantum.agent.linux.interface.BridgeInterfaceDriver
|
||||
# Ryu
|
||||
#interface_driver = quantum.agent.linux.interface.RyuInterfaceDriver
|
||||
|
||||
# The agent can use other DHCP drivers. Dnsmasq is the simplest and requires
|
||||
# no additional setup of the DHCP server.
|
||||
@ -29,6 +31,9 @@ db_connection = mysql://root:password@localhost/ovs_quantum?charset=utf8
|
||||
# The database used by the LinuxBridge Quantum plugin
|
||||
#db_connection = mysql://root:password@localhost/quantum_linux_bridge
|
||||
|
||||
# The database used by the Ryu Quantum plugin
|
||||
#db_connection = mysql://root:password@localhost/ryu_quantum
|
||||
|
||||
# The Quantum user information for accessing the Quantum API.
|
||||
auth_url = http://localhost:35357/v2.0
|
||||
auth_region = RegionOne
|
||||
|
@ -34,6 +34,9 @@ OPTS = [
|
||||
help='Name of Open vSwitch bridge to use'),
|
||||
cfg.StrOpt('network_device_mtu',
|
||||
help='MTU setting for device.'),
|
||||
cfg.StrOpt('ryu_api_host',
|
||||
default='127.0.0.1:8080',
|
||||
help='Openflow Ryu REST API host:port')
|
||||
]
|
||||
|
||||
|
||||
@ -164,3 +167,27 @@ class BridgeInterfaceDriver(LinuxInterfaceDriver):
|
||||
except RuntimeError:
|
||||
LOG.error(_("Failed unplugging interface '%s'") %
|
||||
device_name)
|
||||
|
||||
|
||||
class RyuInterfaceDriver(OVSInterfaceDriver):
|
||||
"""Driver for creating a Ryu OVS interface."""
|
||||
|
||||
def __init__(self, conf):
|
||||
super(RyuInterfaceDriver, self).__init__(conf)
|
||||
|
||||
from ryu.app.client import OFPClient
|
||||
LOG.debug('ryu rest host %s', self.conf.ryu_api_host)
|
||||
self.ryu_client = OFPClient(self.conf.ryu_api_host)
|
||||
|
||||
self.check_bridge_exists(self.conf.ovs_integration_bridge)
|
||||
self.ovs_br = ovs_lib.OVSBridge(self.conf.ovs_integration_bridge,
|
||||
self.conf.root_helper)
|
||||
self.datapath_id = self.ovs_br.get_datapath_id()
|
||||
|
||||
def plug(self, network_id, port_id, device_name, mac_address):
|
||||
"""Plug in the interface."""
|
||||
super(RyuInterfaceDriver, self).plug(network_id, port_id, device_name,
|
||||
mac_address)
|
||||
|
||||
port_no = self.ovs_br.get_port_ofport(device_name)
|
||||
self.ryu_client.create_port(network_id, self.datapath_id, port_no)
|
||||
|
@ -82,6 +82,10 @@ class OVSBridge:
|
||||
def get_port_ofport(self, port_name):
|
||||
return self.db_get_val("Interface", port_name, "ofport")
|
||||
|
||||
def get_datapath_id(self):
|
||||
return self.db_get_val('Bridge',
|
||||
self.br_name, 'datapath_id').strip('"')
|
||||
|
||||
def _build_flow_expr_arr(self, **kwargs):
|
||||
flow_expr_arr = []
|
||||
is_delete_expr = kwargs.get('delete', False)
|
||||
|
@ -217,3 +217,72 @@ class TestBridgeInterfaceDriver(TestBase):
|
||||
|
||||
self.ip_dev.assert_has_calls([mock.call('tap0', 'sudo'),
|
||||
mock.call().link.delete()])
|
||||
|
||||
|
||||
class TestRyuInterfaceDriver(TestBase):
|
||||
def setUp(self):
|
||||
super(TestRyuInterfaceDriver, self).setUp()
|
||||
self.ryu_mod = mock.Mock()
|
||||
self.ryu_app_mod = self.ryu_mod.app
|
||||
self.ryu_app_client = self.ryu_app_mod.client
|
||||
self.ryu_mod_p = mock.patch.dict('sys.modules',
|
||||
{'ryu': self.ryu_mod,
|
||||
'ryu.app': self.ryu_app_mod,
|
||||
'ryu.app.client':
|
||||
self.ryu_app_client})
|
||||
self.ryu_mod_p.start()
|
||||
|
||||
def tearDown(self):
|
||||
self.ryu_mod_p.stop()
|
||||
super(TestRyuInterfaceDriver, self).tearDown()
|
||||
|
||||
@staticmethod
|
||||
def _device_exists(dev, root_helper=None):
|
||||
return dev == 'br-int'
|
||||
|
||||
_vsctl_cmd_init = ['ovs-vsctl', '--timeout=2',
|
||||
'get', 'Bridge', 'br-int', 'datapath_id']
|
||||
|
||||
def test_init(self):
|
||||
with mock.patch.object(utils, 'execute') as execute:
|
||||
self.device_exists.side_effect = self._device_exists
|
||||
interface.RyuInterfaceDriver(self.conf)
|
||||
execute.assert_called_once_with(self._vsctl_cmd_init,
|
||||
root_helper='sudo')
|
||||
|
||||
self.ryu_app_client.OFPClient.assert_called_once_with('127.0.0.1:8080')
|
||||
|
||||
def test_plug(self):
|
||||
vsctl_cmd_plug = ['ovs-vsctl', '--', '--may-exist', 'add-port',
|
||||
'br-int', 'tap0', '--', 'set', 'Interface', 'tap0',
|
||||
'type=internal', '--', 'set', 'Interface', 'tap0',
|
||||
'external-ids:iface-id=port-1234', '--', 'set',
|
||||
'Interface', 'tap0',
|
||||
'external-ids:iface-status=active', '--', 'set',
|
||||
'Interface', 'tap0',
|
||||
'external-ids:attached-mac=aa:bb:cc:dd:ee:ff']
|
||||
vsctl_cmd_ofport = ['ovs-vsctl', '--timeout=2',
|
||||
'get', 'Interface', 'tap0', 'ofport']
|
||||
|
||||
with mock.patch.object(utils, 'execute') as execute:
|
||||
self.device_exists.side_effect = self._device_exists
|
||||
ryu = interface.RyuInterfaceDriver(self.conf)
|
||||
|
||||
ryu.plug('01234567-1234-1234-99',
|
||||
'port-1234',
|
||||
'tap0',
|
||||
'aa:bb:cc:dd:ee:ff')
|
||||
|
||||
execute.assert_has_calls([mock.call(self._vsctl_cmd_init,
|
||||
root_helper='sudo')])
|
||||
execute.assert_has_calls([mock.call(vsctl_cmd_plug, 'sudo')])
|
||||
execute.assert_has_calls([mock.call(vsctl_cmd_ofport,
|
||||
root_helper='sudo')])
|
||||
|
||||
self.ryu_app_client.OFPClient.assert_called_once_with('127.0.0.1:8080')
|
||||
|
||||
expected = [mock.call('sudo'),
|
||||
mock.call().device('tap0'),
|
||||
mock.call().device().link.set_address('aa:bb:cc:dd:ee:ff'),
|
||||
mock.call().device().link.set_up()]
|
||||
self.ip.assert_has_calls(expected)
|
||||
|
@ -144,6 +144,16 @@ class OVS_Lib_Test(unittest.TestCase):
|
||||
self.assertEqual(self.br.get_port_ofport(pname), ofport)
|
||||
self.mox.VerifyAll()
|
||||
|
||||
def test_get_datapath_id(self):
|
||||
datapath_id = '"0000b67f4fbcc149"'
|
||||
utils.execute(["ovs-vsctl", self.TO, "get",
|
||||
"Bridge", self.BR_NAME, "datapath_id"],
|
||||
root_helper=self.root_helper).AndReturn(datapath_id)
|
||||
self.mox.ReplayAll()
|
||||
|
||||
self.assertEqual(self.br.get_datapath_id(), datapath_id.strip('"'))
|
||||
self.mox.VerifyAll()
|
||||
|
||||
def test_count_flows(self):
|
||||
utils.execute(["ovs-ofctl", "dump-flows", self.BR_NAME],
|
||||
root_helper=self.root_helper).AndReturn('ignore'
|
||||
|
Loading…
Reference in New Issue
Block a user