Merge "XenAPI: Support neutron security group"
This commit is contained in:
commit
9373f7f2d5
@ -22,6 +22,7 @@ from nova.tests.unit.virt.xenapi import stubs
|
||||
from nova.virt.xenapi import network_utils
|
||||
from nova.virt.xenapi import vif
|
||||
|
||||
|
||||
fake_vif = {
|
||||
'created_at': None,
|
||||
'updated_at': None,
|
||||
@ -190,6 +191,10 @@ class XenAPIOpenVswitchDriverTestCase(XenVIFDriverTestBase):
|
||||
self.assertTrue(mock_create_vif.called)
|
||||
self.assertEqual('fake_vif_ref', ret_vif_ref)
|
||||
|
||||
@mock.patch.object(vif.XenAPIOpenVswitchDriver, '_delete_linux_bridge')
|
||||
@mock.patch.object(vif.XenAPIOpenVswitchDriver, '_delete_linux_port')
|
||||
@mock.patch.object(vif.XenAPIOpenVswitchDriver, '_device_exists',
|
||||
return_value=True)
|
||||
@mock.patch.object(vif.XenAPIOpenVswitchDriver, '_ovs_del_br')
|
||||
@mock.patch.object(vif.XenAPIOpenVswitchDriver, '_ovs_del_port')
|
||||
@mock.patch.object(network_utils, 'find_network_with_name_label',
|
||||
@ -198,7 +203,10 @@ class XenAPIOpenVswitchDriverTestCase(XenVIFDriverTestBase):
|
||||
def test_unplug(self, mock_super_unplug,
|
||||
mock_find_network_with_name_label,
|
||||
mock_ovs_del_port,
|
||||
mock_ovs_del_br):
|
||||
mock_ovs_del_br,
|
||||
mock_device_exists,
|
||||
mock_delete_linux_port,
|
||||
mock_delete_linux_bridge):
|
||||
instance = {'name': "fake_instance"}
|
||||
vm_ref = "fake_vm_ref"
|
||||
|
||||
@ -241,10 +249,12 @@ class XenAPIOpenVswitchDriverTestCase(XenVIFDriverTestBase):
|
||||
self.ovs_driver.unplug, instance, fake_vif,
|
||||
vm_ref)
|
||||
|
||||
@mock.patch.object(vif.XenAPIOpenVswitchDriver, '_ovs_add_patch_port')
|
||||
@mock.patch.object(vif.XenAPIOpenVswitchDriver, '_ovs_map_external_ids')
|
||||
def test_post_start_actions(self, mock_ovs_map_external_ids,
|
||||
mock_ovs_add_patch_port):
|
||||
@mock.patch.object(vif.XenAPIOpenVswitchDriver, '_brctl_add_if')
|
||||
@mock.patch.object(vif.XenAPIOpenVswitchDriver, '_create_linux_bridge')
|
||||
@mock.patch.object(vif.XenAPIOpenVswitchDriver, '_ovs_add_port')
|
||||
def test_post_start_actions(self, mock_ovs_add_port,
|
||||
mock_create_linux_bridge,
|
||||
mock_brctl_add_if):
|
||||
vif_ref = "fake_vif_ref"
|
||||
instance = {'name': 'fake_instance_name'}
|
||||
fake_vif_rec = {'uuid': fake_vif['uuid'],
|
||||
@ -267,8 +277,8 @@ class XenAPIOpenVswitchDriverTestCase(XenVIFDriverTestBase):
|
||||
self.assertTrue(mock_VIF_get_record.called)
|
||||
self.assertTrue(mock_network_get_bridge.called)
|
||||
self.assertTrue(mock_network_get_uuid.called)
|
||||
self.assertEqual(mock_ovs_add_patch_port.call_count, 2)
|
||||
self.assertTrue(mock_ovs_map_external_ids.called)
|
||||
self.assertEqual(mock_ovs_add_port.call_count, 1)
|
||||
self.assertTrue(mock_brctl_add_if.called)
|
||||
|
||||
@mock.patch.object(network_utils, 'find_network_with_name_label',
|
||||
return_value="exist_network_ref")
|
||||
|
@ -70,7 +70,7 @@ class XenAPISession(object):
|
||||
# changed in development environments.
|
||||
# MAJOR VERSION: Incompatible changes with the plugins
|
||||
# MINOR VERSION: Compatible changes, new plguins, etc
|
||||
PLUGIN_REQUIRED_VERSION = '1.5'
|
||||
PLUGIN_REQUIRED_VERSION = '1.6'
|
||||
|
||||
def __init__(self, url, user, pw):
|
||||
version_string = version.version_string_with_package()
|
||||
|
@ -760,7 +760,7 @@ class SessionBase(object):
|
||||
return base64.b64encode(zlib.compress("dom_id: %s" % dom_id))
|
||||
|
||||
def _plugin_nova_plugin_version_get_version(self, method, args):
|
||||
return pickle.dumps("1.5")
|
||||
return pickle.dumps("1.6")
|
||||
|
||||
def _plugin_xenhost_query_gc(self, method, args):
|
||||
return pickle.dumps("False")
|
||||
|
@ -225,11 +225,11 @@ class XenAPIOpenVswitchDriver(XenVIFDriver):
|
||||
|
||||
def unplug(self, instance, vif, vm_ref):
|
||||
"""unplug vif:
|
||||
1. unplug and destroy vif.
|
||||
2. delete the patch port pair between the integration bridge and
|
||||
the interim network.
|
||||
3. destroy the interim network
|
||||
4. delete the OVS bridge service for the interim network
|
||||
1. delete the patch port pair between the integration bridge and
|
||||
the qbr linux bridge(if exist) and the interim network.
|
||||
2. destroy the interim network
|
||||
3. delete the OVS bridge service for the interim network
|
||||
4. delete linux bridge qbr and related ports if exist
|
||||
"""
|
||||
super(XenAPIOpenVswitchDriver, self).unplug(instance, vif, vm_ref)
|
||||
|
||||
@ -248,12 +248,10 @@ class XenAPIOpenVswitchDriver(XenVIFDriver):
|
||||
LOG.debug('destroying patch port pair for vif: vif_id=%(vif_id)s',
|
||||
{'vif_id': vif['id']})
|
||||
bridge_name = self._session.network.get_bridge(network)
|
||||
patch_port1, patch_port2 = self._get_patch_port_pair_names(vif['id'])
|
||||
patch_port1, tap_name = self._get_patch_port_pair_names(vif['id'])
|
||||
try:
|
||||
# delete the patch port pair
|
||||
self._ovs_del_port(bridge_name, patch_port1)
|
||||
self._ovs_del_port(CONF.xenserver.ovs_integration_bridge,
|
||||
patch_port2)
|
||||
except Exception as e:
|
||||
LOG.warn(_LW("Failed to delete patch port pair for vif %(if)s,"
|
||||
" exception:%(exception)s"),
|
||||
@ -272,6 +270,18 @@ class XenAPIOpenVswitchDriver(XenVIFDriver):
|
||||
# won't be destroyed automatically by XAPI. So let's destroy it
|
||||
# at here.
|
||||
self._ovs_del_br(bridge_name)
|
||||
|
||||
qbr_name = self._get_qbr_name(vif['id'])
|
||||
qvb_name, qvo_name = self._get_veth_pair_names(vif['id'])
|
||||
if self._device_exists(qbr_name):
|
||||
# delete tap port, qvb port and qbr
|
||||
LOG.debug(
|
||||
"destroy linux bridge %(qbr)s when unplug vif %(vif)s",
|
||||
{'qbr': qbr_name, 'vif': vif['id']})
|
||||
self._delete_linux_port(qbr_name, tap_name)
|
||||
self._delete_linux_port(qbr_name, qvb_name)
|
||||
self._delete_linux_bridge(qbr_name)
|
||||
self._ovs_del_port(CONF.xenserver.ovs_integration_bridge, qvo_name)
|
||||
except Exception as e:
|
||||
LOG.warn(_LW("Failed to delete bridge for vif %(if)s, "
|
||||
"exception:%(exception)s"),
|
||||
@ -279,6 +289,88 @@ class XenAPIOpenVswitchDriver(XenVIFDriver):
|
||||
raise exception.VirtualInterfaceUnplugException(
|
||||
reason=_("Failed to delete bridge"))
|
||||
|
||||
def _get_qbr_name(self, iface_id):
|
||||
return ("qbr" + iface_id)[:network_model.NIC_NAME_LEN]
|
||||
|
||||
def _get_veth_pair_names(self, iface_id):
|
||||
return (("qvb%s" % iface_id)[:network_model.NIC_NAME_LEN],
|
||||
("qvo%s" % iface_id)[:network_model.NIC_NAME_LEN])
|
||||
|
||||
def _device_exists(self, device):
|
||||
"""Check if ethernet device exists."""
|
||||
try:
|
||||
cmd = 'ip_link_get_dev'
|
||||
args = {'device_name': device}
|
||||
self._exec_dom0_cmd(cmd, args)
|
||||
return True
|
||||
except Exception:
|
||||
# Swallow exception from plugin, since this indicates the device
|
||||
# doesn't exist
|
||||
return False
|
||||
|
||||
def _delete_net_dev(self, dev):
|
||||
"""Delete a network device only if it exists."""
|
||||
if self._device_exists(dev):
|
||||
LOG.debug("delete network device '%s'", dev)
|
||||
args = {'device_name': dev}
|
||||
self._exec_dom0_cmd('ip_link_del_dev', args)
|
||||
|
||||
def _create_veth_pair(self, dev1_name, dev2_name):
|
||||
"""Create a pair of veth devices with the specified names,
|
||||
deleting any previous devices with those names.
|
||||
"""
|
||||
LOG.debug("Create veth pair, port1:%(qvb)s, port2:%(qvo)s",
|
||||
{'qvb': dev1_name, 'qvo': dev2_name})
|
||||
for dev in [dev1_name, dev2_name]:
|
||||
self._delete_net_dev(dev)
|
||||
args = {'dev1_name': dev1_name, 'dev2_name': dev2_name}
|
||||
self._exec_dom0_cmd('ip_link_add_veth_pair', args)
|
||||
for dev in [dev1_name, dev2_name]:
|
||||
args = {'device_name': dev, 'option': 'up'}
|
||||
self._exec_dom0_cmd('ip_link_set_dev', args)
|
||||
args = {'device_name': dev, 'option': 'on'}
|
||||
self._exec_dom0_cmd('ip_link_set_promisc', args)
|
||||
|
||||
def _create_linux_bridge(self, vif_rec):
|
||||
"""create a qbr linux bridge for neutron security group
|
||||
"""
|
||||
iface_id = vif_rec['other_config']['nicira-iface-id']
|
||||
linux_br_name = self._get_qbr_name(iface_id)
|
||||
if not self._device_exists(linux_br_name):
|
||||
LOG.debug("Create linux bridge %s", linux_br_name)
|
||||
self._brctl_add_br(linux_br_name)
|
||||
self._brctl_set_fd(linux_br_name, '0')
|
||||
self._brctl_set_stp(linux_br_name, 'off')
|
||||
args = {'device_name': linux_br_name, 'option': 'up'}
|
||||
self._exec_dom0_cmd('ip_link_set_dev', args)
|
||||
|
||||
qvb_name, qvo_name = self._get_veth_pair_names(iface_id)
|
||||
if not self._device_exists(qvo_name):
|
||||
self._create_veth_pair(qvb_name, qvo_name)
|
||||
self._brctl_add_if(linux_br_name, qvb_name)
|
||||
self._ovs_add_port(CONF.xenserver.ovs_integration_bridge, qvo_name)
|
||||
self._ovs_map_external_ids(qvo_name, vif_rec)
|
||||
return linux_br_name
|
||||
|
||||
def _delete_linux_port(self, qbr_name, port_name):
|
||||
try:
|
||||
# delete port in linux bridge
|
||||
self._brctl_del_if(qbr_name, port_name)
|
||||
self._delete_net_dev(port_name)
|
||||
except Exception:
|
||||
LOG.debug("Fail to delete linux port %(port_name)s on bridge"
|
||||
"%(qbr_name)s",
|
||||
{'port_name': port_name, 'qbr_name': qbr_name})
|
||||
|
||||
def _delete_linux_bridge(self, qbr_name):
|
||||
try:
|
||||
# delete linux bridge qbrxxx
|
||||
args = {'device_name': qbr_name, 'option': 'down'}
|
||||
self._exec_dom0_cmd('ip_link_set_dev', args)
|
||||
self._brctl_del_br(qbr_name)
|
||||
except Exception:
|
||||
LOG.debug("Fail to delete linux bridge %s", qbr_name)
|
||||
|
||||
def post_start_actions(self, instance, vif_ref):
|
||||
"""Do needed actions post vif start:
|
||||
plug the interim ovs bridge to the integration bridge;
|
||||
@ -290,19 +382,25 @@ class XenAPIOpenVswitchDriver(XenVIFDriver):
|
||||
bridge_name = self._session.network.get_bridge(network_ref)
|
||||
network_uuid = self._session.network.get_uuid(network_ref)
|
||||
iface_id = vif_rec['other_config']['nicira-iface-id']
|
||||
patch_port1, patch_port2 = self._get_patch_port_pair_names(iface_id)
|
||||
patch_port1, tap_name = self._get_patch_port_pair_names(iface_id)
|
||||
LOG.debug('plug_ovs_bridge: port1=%(port1)s, port2=%(port2)s,'
|
||||
'network_uuid=%(uuid)s, bridge_name=%(bridge_name)s',
|
||||
{'port1': patch_port1, 'port2': patch_port2,
|
||||
{'port1': patch_port1, 'port2': tap_name,
|
||||
'uuid': network_uuid, 'bridge_name': bridge_name})
|
||||
if bridge_name is None:
|
||||
raise exception.VirtualInterfacePlugException(
|
||||
_("Failed to find bridge for vif"))
|
||||
|
||||
self._ovs_add_patch_port(bridge_name, patch_port1, patch_port2)
|
||||
self._ovs_add_patch_port(CONF.xenserver.ovs_integration_bridge,
|
||||
patch_port2, patch_port1)
|
||||
self._ovs_map_external_ids(patch_port2, vif_rec)
|
||||
# Create Linux bridge qbrXXX
|
||||
linux_br_name = self._create_linux_bridge(vif_rec)
|
||||
LOG.debug("create veth pair for interim bridge %(interim_bridge)s and "
|
||||
"linux bridge %(linux_bridge)s",
|
||||
{'interim_bridge': bridge_name,
|
||||
'linux_bridge': linux_br_name})
|
||||
self._create_veth_pair(tap_name, patch_port1)
|
||||
self._brctl_add_if(linux_br_name, tap_name)
|
||||
# Add port to interim bridge
|
||||
self._ovs_add_port(bridge_name, patch_port1)
|
||||
|
||||
def get_vif_interim_net_name(self, vif):
|
||||
return ("net-" + vif['id'])[:network_model.NIC_NAME_LEN]
|
||||
@ -330,14 +428,13 @@ class XenAPIOpenVswitchDriver(XenVIFDriver):
|
||||
return network_ref
|
||||
|
||||
def _get_patch_port_pair_names(self, iface_id):
|
||||
return (("pp1-%s" % iface_id)[:network_model.NIC_NAME_LEN],
|
||||
("pp2-%s" % iface_id)[:network_model.NIC_NAME_LEN])
|
||||
return (("vif%s" % iface_id)[:network_model.NIC_NAME_LEN],
|
||||
("tap%s" % iface_id)[:network_model.NIC_NAME_LEN])
|
||||
|
||||
def _ovs_add_patch_port(self, bridge_name, port_name, peer_port_name):
|
||||
cmd = 'ovs_add_patch_port'
|
||||
def _ovs_add_port(self, bridge_name, port_name):
|
||||
cmd = 'ovs_add_port'
|
||||
args = {'bridge_name': bridge_name,
|
||||
'port_name': port_name,
|
||||
'peer_port_name': peer_port_name
|
||||
'port_name': port_name
|
||||
}
|
||||
self._exec_dom0_cmd(cmd, args)
|
||||
|
||||
@ -373,6 +470,40 @@ class XenAPIOpenVswitchDriver(XenVIFDriver):
|
||||
self._ovs_set_if_external_id(interface, 'xs-vif-uuid', vif_uuid)
|
||||
self._ovs_set_if_external_id(interface, 'iface-status', status)
|
||||
|
||||
def _brctl_add_if(self, bridge_name, interface_name):
|
||||
cmd = 'brctl_add_if'
|
||||
args = {'bridge_name': bridge_name,
|
||||
'interface_name': interface_name}
|
||||
self._exec_dom0_cmd(cmd, args)
|
||||
|
||||
def _brctl_del_if(self, bridge_name, interface_name):
|
||||
cmd = 'brctl_del_if'
|
||||
args = {'bridge_name': bridge_name,
|
||||
'interface_name': interface_name}
|
||||
self._exec_dom0_cmd(cmd, args)
|
||||
|
||||
def _brctl_del_br(self, bridge_name):
|
||||
cmd = 'brctl_del_br'
|
||||
args = {'bridge_name': bridge_name}
|
||||
self._exec_dom0_cmd(cmd, args)
|
||||
|
||||
def _brctl_add_br(self, bridge_name):
|
||||
cmd = 'brctl_add_br'
|
||||
args = {'bridge_name': bridge_name}
|
||||
self._exec_dom0_cmd(cmd, args)
|
||||
|
||||
def _brctl_set_fd(self, bridge_name, fd):
|
||||
cmd = 'brctl_set_fd'
|
||||
args = {'bridge_name': bridge_name,
|
||||
'fd': fd}
|
||||
self._exec_dom0_cmd(cmd, args)
|
||||
|
||||
def _brctl_set_stp(self, bridge_name, stp_opt):
|
||||
cmd = 'brctl_set_stp'
|
||||
args = {'bridge_name': bridge_name,
|
||||
'option': stp_opt}
|
||||
self._exec_dom0_cmd(cmd, args)
|
||||
|
||||
def _exec_dom0_cmd(self, cmd, cmd_args):
|
||||
args = {'cmd': cmd,
|
||||
'args': cmd_args
|
||||
|
@ -31,7 +31,8 @@ import utils
|
||||
# 1.3 - Add vhd2 functions for doing glance operations by url
|
||||
# 1.4 - Add support of Glance v2 api
|
||||
# 1.5 - Added function for network configuration on ovs bridge
|
||||
PLUGIN_VERSION = "1.5"
|
||||
# 1.6 - Add function for network configuration on Linux bridge
|
||||
PLUGIN_VERSION = "1.6"
|
||||
|
||||
|
||||
def get_version(session):
|
||||
|
@ -252,12 +252,105 @@ def _ovs_set_if_external_id(args):
|
||||
return _run_command(cmd_args)
|
||||
|
||||
|
||||
def _ovs_add_port(args):
|
||||
bridge_name = pluginlib.exists(args, 'bridge_name')
|
||||
port_name = pluginlib.exists(args, 'port_name')
|
||||
cmd_args = ['ovs-vsctl', '--', '--if-exists', 'del-port', port_name,
|
||||
'--', 'add-port', bridge_name, port_name]
|
||||
return _run_command(cmd_args)
|
||||
|
||||
|
||||
def _ip_link_get_dev(args):
|
||||
device_name = pluginlib.exists(args, 'device_name')
|
||||
cmd_args = ['ip', 'link', 'show', device_name]
|
||||
return _run_command(cmd_args)
|
||||
|
||||
|
||||
def _ip_link_del_dev(args):
|
||||
device_name = pluginlib.exists(args, 'device_name')
|
||||
cmd_args = ['ip', 'link', 'delete', device_name]
|
||||
return _run_command(cmd_args)
|
||||
|
||||
def _ip_link_add_veth_pair(args):
|
||||
dev1_name = pluginlib.exists(args, 'dev1_name')
|
||||
dev2_name = pluginlib.exists(args, 'dev2_name')
|
||||
cmd_args = ['ip', 'link', 'add', dev1_name, 'type', 'veth', 'peer',
|
||||
'name', dev2_name]
|
||||
return _run_command(cmd_args)
|
||||
|
||||
|
||||
def _ip_link_set_dev(args):
|
||||
device_name = pluginlib.exists(args, 'device_name')
|
||||
option = pluginlib.exists(args, 'option')
|
||||
cmd_args = ['ip', 'link', 'set', device_name, option]
|
||||
return _run_command(cmd_args)
|
||||
|
||||
|
||||
def _ip_link_set_promisc(args):
|
||||
device_name = pluginlib.exists(args, 'device_name')
|
||||
option = pluginlib.exists(args, 'option')
|
||||
cmd_args = ['ip', 'link', 'set', device_name, 'promisc', option]
|
||||
return _run_command(cmd_args)
|
||||
|
||||
|
||||
def _brctl_add_br(args):
|
||||
bridge_name = pluginlib.exists(args, 'bridge_name')
|
||||
cmd_args = ['brctl', 'addbr', bridge_name]
|
||||
return _run_command(cmd_args)
|
||||
|
||||
|
||||
def _brctl_del_br(args):
|
||||
bridge_name = pluginlib.exists(args, 'bridge_name')
|
||||
cmd_args = ['brctl', 'delbr', bridge_name]
|
||||
return _run_command(cmd_args)
|
||||
|
||||
|
||||
def _brctl_set_fd(args):
|
||||
bridge_name = pluginlib.exists(args, 'bridge_name')
|
||||
fd = pluginlib.exists(args, 'fd')
|
||||
cmd_args = ['brctl', 'setfd', bridge_name, fd]
|
||||
return _run_command(cmd_args)
|
||||
|
||||
|
||||
def _brctl_set_stp(args):
|
||||
bridge_name = pluginlib.exists(args, 'bridge_name')
|
||||
option = pluginlib.exists(args, 'option')
|
||||
cmd_args = ['brctl', 'stp', bridge_name, option]
|
||||
return _run_command(cmd_args)
|
||||
|
||||
|
||||
def _brctl_add_if(args):
|
||||
bridge_name = pluginlib.exists(args, 'bridge_name')
|
||||
if_name = pluginlib.exists(args, 'interface_name')
|
||||
cmd_args = ['brctl', 'addif', bridge_name, if_name]
|
||||
return _run_command(cmd_args)
|
||||
|
||||
|
||||
def _brctl_del_if(args):
|
||||
bridge_name = pluginlib.exists(args, 'bridge_name')
|
||||
if_name = pluginlib.exists(args, 'interface_name')
|
||||
cmd_args = ['brctl', 'delif', bridge_name, if_name]
|
||||
return _run_command(cmd_args)
|
||||
|
||||
|
||||
ALLOWED_NETWORK_CMDS = {
|
||||
# allowed cmds to config OVS bridge
|
||||
'ovs_add_patch_port': _ovs_add_patch_port,
|
||||
'ovs_add_port': _ovs_add_port,
|
||||
'ovs_del_port': _ovs_del_port,
|
||||
'ovs_del_br': _ovs_del_br,
|
||||
'ovs_set_if_external_id': _ovs_set_if_external_id
|
||||
'ovs_set_if_external_id': _ovs_set_if_external_id,
|
||||
'ip_link_add_veth_pair': _ip_link_add_veth_pair,
|
||||
'ip_link_del_dev': _ip_link_del_dev,
|
||||
'ip_link_get_dev': _ip_link_get_dev,
|
||||
'ip_link_set_dev': _ip_link_set_dev,
|
||||
'ip_link_set_promisc': _ip_link_set_promisc,
|
||||
'brctl_add_br': _brctl_add_br,
|
||||
'brctl_add_if': _brctl_add_if,
|
||||
'brctl_del_br': _brctl_del_br,
|
||||
'brctl_del_if': _brctl_del_if,
|
||||
'brctl_set_fd': _brctl_set_fd,
|
||||
'brctl_set_stp': _brctl_set_stp
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user