for d in ns_ip.get_devices(exclude_loopback=True):
if d.name.startswith(INTERNAL_DEV_PREFIX):
# device is on default bridge
- self.driver.unplug(d.name, namespace=namespace)
+ self.driver.unplug(d.name, namespace=namespace,
+ prefix=INTERNAL_DEV_PREFIX)
elif d.name.startswith(EXTERNAL_DEV_PREFIX):
self.driver.unplug(d.name,
bridge=self.conf.external_network_bridge,
- namespace=namespace)
+ namespace=namespace,
+ prefix=EXTERNAL_DEV_PREFIX)
#(TODO) Address the failure for the deletion of the namespace
def _create_router_namespace(self, ri):
namespace=ri.ns_name()):
self.driver.unplug(interface_name,
bridge=self.conf.external_network_bridge,
- namespace=ri.ns_name())
+ namespace=ri.ns_name(),
+ prefix=EXTERNAL_DEV_PREFIX)
ex_gw_ip = ex_gw_port['fixed_ips'][0]['ip_address']
for c, r in self.external_gateway_filter_rules():
if ip_lib.device_exists(interface_name,
root_helper=self.conf.root_helper,
namespace=ri.ns_name()):
- self.driver.unplug(interface_name, namespace=ri.ns_name())
+ self.driver.unplug(interface_name, namespace=ri.ns_name(),
+ prefix=INTERNAL_DEV_PREFIX)
if ex_gw_port:
ex_gw_ip = ex_gw_port['fixed_ips'][0]['ip_address']
"""Plug in the interface."""
@abc.abstractmethod
- def unplug(self, device_name, bridge=None, namespace=None):
+ def unplug(self, device_name, bridge=None, namespace=None, prefix=None):
"""Unplug the interface."""
bridge=None, namespace=None, prefix=None):
pass
- def unplug(self, device_name, bridge=None, namespace=None):
+ def unplug(self, device_name, bridge=None, namespace=None, prefix=None):
pass
class OVSInterfaceDriver(LinuxInterfaceDriver):
"""Driver for creating an internal interface on an OVS bridge."""
+ def _ovs_add_port(self, bridge, device_name, port_id, mac_address,
+ internal=True):
+ cmd = ['ovs-vsctl', '--', '--may-exist',
+ 'add-port', bridge, device_name]
+ if internal:
+ cmd += ['--', 'set', 'Interface', device_name, 'type=internal']
+ cmd += ['--', 'set', 'Interface', device_name,
+ 'external-ids:iface-id=%s' % port_id,
+ '--', 'set', 'Interface', device_name,
+ 'external-ids:iface-status=active',
+ '--', 'set', 'Interface', device_name,
+ 'external-ids:attached-mac=%s' % mac_address]
+ utils.execute(cmd, self.conf.root_helper)
+
def plug(self, network_id, port_id, device_name, mac_address,
bridge=None, namespace=None, prefix=None):
"""Plug in the interface."""
self.conf.root_helper,
namespace=namespace):
- utils.execute(['ovs-vsctl',
- '--', '--may-exist', 'add-port', bridge,
- device_name,
- '--', 'set', 'Interface', device_name,
- 'type=internal',
- '--', 'set', 'Interface', device_name,
- 'external-ids:iface-id=%s' % port_id,
- '--', 'set', 'Interface', device_name,
- 'external-ids:iface-status=active',
- '--', 'set', 'Interface', device_name,
- 'external-ids:attached-mac=%s' %
- mac_address],
- self.conf.root_helper)
+ self._ovs_add_port(bridge, device_name, port_id, mac_address)
ip = ip_lib.IPWrapper(self.conf.root_helper)
device = ip.device(device_name)
namespace_obj.add_device_to_namespace(device)
device.link.set_up()
- def unplug(self, device_name, bridge=None, namespace=None):
+ def unplug(self, device_name, bridge=None, namespace=None, prefix=None):
"""Unplug the interface."""
if not bridge:
bridge = self.conf.ovs_integration_bridge
else:
LOG.warn(_("Device %s already exists") % device_name)
- def unplug(self, device_name, bridge=None, namespace=None):
+ def unplug(self, device_name, bridge=None, namespace=None, prefix=None):
"""Unplug the interface."""
device = ip_lib.IPDevice(device_name, self.conf.root_helper, namespace)
try:
self.ryu_client.create_port(network_id, datapath_id, port_no)
+class OVSVethInterfaceDriver(OVSInterfaceDriver):
+ """Driver for creating an OVS interface using veth."""
+
+ DEV_NAME_PREFIX = 'ns-'
+
+ def _get_tap_name(self, device_name, prefix=None):
+ if not prefix:
+ prefix = self.DEV_NAME_PREFIX
+ return device_name.replace(prefix, 'tap')
+
+ def plug(self, network_id, port_id, device_name, mac_address,
+ bridge=None, namespace=None, prefix=None):
+ """Plugin the interface."""
+ if not bridge:
+ bridge = self.conf.ovs_integration_bridge
+
+ self.check_bridge_exists(bridge)
+
+ if not ip_lib.device_exists(device_name,
+ self.conf.root_helper,
+ namespace=namespace):
+ ip = ip_lib.IPWrapper(self.conf.root_helper)
+
+ tap_name = self._get_tap_name(device_name, prefix)
+ root_veth, ns_veth = ip.add_veth(tap_name, device_name)
+
+ self._ovs_add_port(bridge, tap_name, port_id, mac_address,
+ internal=False)
+
+ ns_veth.link.set_address(mac_address)
+ if self.conf.network_device_mtu:
+ ns_veth.link.set_mtu(self.conf.network_device_mtu)
+ root_veth.link.set_mtu(self.conf.network_device_mtu)
+
+ if namespace:
+ namespace_obj = ip.ensure_namespace(namespace)
+ namespace_obj.add_device_to_namespace(ns_veth)
+
+ root_veth.link.set_up()
+ ns_veth.link.set_up()
+ else:
+ LOG.warn(_("Device %s already exists") % device_name)
+
+ def unplug(self, device_name, bridge=None, namespace=None, prefix=None):
+ """Unplug the interface."""
+ if not bridge:
+ bridge = self.conf.ovs_integration_bridge
+
+ tap_name = self._get_tap_name(device_name, prefix)
+ self.check_bridge_exists(bridge)
+ ovs = ovs_lib.OVSBridge(bridge, self.conf.root_helper)
+
+ try:
+ ovs.delete_port(tap_name)
+ device = ip_lib.IPDevice(device_name, self.conf.root_helper,
+ namespace)
+ device.link.delete()
+ LOG.debug(_("Unplugged interface '%s'") % device_name)
+ except RuntimeError:
+ LOG.error(_("Failed unplugging interface '%s'") %
+ device_name)
+
+
class MetaInterfaceDriver(LinuxInterfaceDriver):
def __init__(self, conf):
super(MetaInterfaceDriver, self).__init__(conf)
return driver.plug(network_id, port_id, device_name, mac_address,
bridge=bridge, namespace=namespace, prefix=prefix)
- def unplug(self, device_name, bridge=None, namespace=None):
+ def unplug(self, device_name, bridge=None, namespace=None, prefix=None):
driver = self._get_driver_by_device_name(device_name, namespace=None)
- return driver.unplug(device_name, bridge, namespace)
+ return driver.unplug(device_name, bridge, namespace, prefix)
def _load_driver(self, driver_provider):
LOG.debug("Driver location:%s", driver_provider)
mock.call().delete_port('tap0')])
+class TestOVSVethInterfaceDriver(TestOVSInterfaceDriver):
+
+ def test_get_device_name(self):
+ br = interface.OVSVethInterfaceDriver(self.conf)
+ device_name = br.get_device_name(FakePort())
+ self.assertEqual('ns-abcdef01-12', device_name)
+
+ def test_plug_with_prefix(self):
+ self._test_plug(devname='qr-0', prefix='qr-')
+
+ def _test_plug(self, devname=None, bridge=None, namespace=None,
+ prefix=None, mtu=None):
+
+ if not devname:
+ devname = 'ns-0'
+ if not bridge:
+ bridge = 'br-int'
+
+ def device_exists(dev, root_helper=None, namespace=None):
+ return dev == bridge
+
+ ovs = interface.OVSVethInterfaceDriver(self.conf)
+ self.device_exists.side_effect = device_exists
+
+ root_veth = mock.Mock()
+ ns_veth = mock.Mock()
+ self.ip().add_veth = mock.Mock(return_value=(root_veth, ns_veth))
+ expected = [mock.call('sudo'), mock.call().add_veth('tap0', devname)]
+
+ vsctl_cmd = ['ovs-vsctl', '--', '--may-exist', 'add-port',
+ bridge, 'tap0', '--', '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']
+ with mock.patch.object(utils, 'execute') as execute:
+ ovs.plug('01234567-1234-1234-99',
+ 'port-1234',
+ devname,
+ 'aa:bb:cc:dd:ee:ff',
+ bridge=bridge,
+ namespace=namespace,
+ prefix=prefix)
+ execute.assert_called_once_with(vsctl_cmd, 'sudo')
+
+ ns_veth.assert_has_calls(
+ [mock.call.link.set_address('aa:bb:cc:dd:ee:ff')])
+ if mtu:
+ ns_veth.assert_has_calls([mock.call.link.set_mtu(mtu)])
+ root_veth.assert_has_calls([mock.call.link.set_mtu(mtu)])
+ if namespace:
+ expected.extend(
+ [mock.call().ensure_namespace(namespace),
+ mock.call().ensure_namespace().add_device_to_namespace(
+ mock.ANY)])
+
+ self.ip.assert_has_calls(expected)
+ root_veth.assert_has_calls([mock.call.link.set_up()])
+ ns_veth.assert_has_calls([mock.call.link.set_up()])
+
+ def test_plug_mtu(self):
+ self.conf.set_override('network_device_mtu', 9000)
+ self._test_plug(mtu=9000)
+
+ def test_unplug(self, bridge=None):
+ if not bridge:
+ bridge = 'br-int'
+ with mock.patch('quantum.agent.linux.ovs_lib.OVSBridge') as ovs_br:
+ ovs = interface.OVSVethInterfaceDriver(self.conf)
+ ovs.unplug('ns-0', bridge=bridge)
+ ovs_br.assert_has_calls([mock.call(bridge, 'sudo'),
+ mock.call().delete_port('tap0')])
+ self.ip_dev.assert_has_calls([mock.call('ns-0', 'sudo', None),
+ mock.call().link.delete()])
+
+
class TestBridgeInterfaceDriver(TestBase):
def test_get_device_name(self):
br = interface.BridgeInterfaceDriver(self.conf)