Skip to content

Commit

Permalink
Part of the patch set that enables VM's to use libvirts bridge type.
Browse files Browse the repository at this point in the history
Fixes bug 1078210

The patch set enables the following:
1. Bridges to be created by Nova
2. Bridges to be created by the agent

The code is backward compatible, that is, if Nova does not create the brdige
then the agent will create the bridge.

In addition to this it cleans gateway code no longer used.

The patch enables the following Nova code to be backported:
https://review.openstack.org/#/c/14830/

Change-Id: Ia621ba5edd12d8eb7ea412a2993fea43189bd511
  • Loading branch information
Gary Kotton committed Nov 17, 2012
1 parent aeef038 commit 04aab72
Show file tree
Hide file tree
Showing 2 changed files with 100 additions and 67 deletions.
113 changes: 46 additions & 67 deletions quantum/plugins/linuxbridge/agent/linuxbridge_quantum_agent.py
Expand Up @@ -51,7 +51,6 @@
LOG = logging.getLogger(__name__)

BRIDGE_NAME_PREFIX = "brq"
GATEWAY_INTERFACE_PREFIX = "gw-"
TAP_INTERFACE_PREFIX = "tap"
BRIDGE_FS = "/sys/devices/virtual/net/"
BRIDGE_NAME_PLACEHOLDER = "bridge_name"
Expand Down Expand Up @@ -147,12 +146,6 @@ def get_all_tap_devices(self):
except RuntimeError:
return self._get_prefixed_ip_link_devices(TAP_INTERFACE_PREFIX)

def get_all_gateway_devices(self):
try:
return self._get_prefixed_tap_devices(GATEWAY_INTERFACE_PREFIX)
except RuntimeError:
return self._get_prefixed_ip_link_devices(GATEWAY_INTERFACE_PREFIX)

def get_bridge_for_tap_device(self, tap_device_name):
bridges = self.get_all_quantum_bridges()
for bridge in bridges:
Expand Down Expand Up @@ -281,72 +274,64 @@ def ensure_bridge(self, bridge_name, interface=None, ips=None,
bridge_name, e)
return

def ensure_physical_in_bridge(self, network_id,
physical_network,
vlan_id):
physical_interface = self.interface_mappings.get(physical_network)
if not physical_interface:
LOG.error("No mapping for physical network %s" %
physical_network)
return False

if int(vlan_id) == lconst.FLAT_VLAN_ID:
self.ensure_flat_bridge(network_id, physical_interface)
else:
self.ensure_vlan_bridge(network_id, physical_interface,
vlan_id)
return True

def add_tap_interface(self, network_id, physical_network, vlan_id,
tap_device_name):
"""
If a VIF has been plugged into a network, this function will
add the corresponding tap device to the relevant bridge
"""
if not tap_device_name:
return False

if not self.device_exists(tap_device_name):
LOG.debug("Tap device: %s does not exist on this host, skipped" %
tap_device_name)
LOG.debug(_("Tap device: %s does not exist on "
"this host, skipped" % tap_device_name))
return False

current_bridge_name = self.get_bridge_for_tap_device(tap_device_name)
bridge_name = self.get_bridge_name(network_id)
if bridge_name == current_bridge_name:
return False
LOG.debug("Adding device %s to bridge %s" % (tap_device_name,
bridge_name))
if current_bridge_name:
if utils.execute(['brctl', 'delif', current_bridge_name,
tap_device_name], root_helper=self.root_helper):
return False

if int(vlan_id) == lconst.LOCAL_VLAN_ID:
self.ensure_local_bridge(network_id)
else:
physical_interface = self.interface_mappings.get(physical_network)
if not physical_interface:
LOG.error("No mapping for physical network %s" %
physical_network)
result = self.ensure_physical_in_bridge(network_id,
physical_network,
vlan_id)
if not result:
return False

if int(vlan_id) == lconst.FLAT_VLAN_ID:
self.ensure_flat_bridge(network_id, physical_interface)
else:
self.ensure_vlan_bridge(network_id, physical_interface,
vlan_id)

if utils.execute(['brctl', 'addif', bridge_name, tap_device_name],
root_helper=self.root_helper):
return False

LOG.debug("Done adding device %s to bridge %s" % (tap_device_name,
bridge_name))
# Check if device needs to be added to bridge
tap_device_in_bridge = self.get_bridge_for_tap_device(tap_device_name)
if not tap_device_in_bridge:
msg = _("Adding device %(tap_device_name)s to bridge "
"%(bridge_name)s") % locals()
LOG.debug(msg)
if utils.execute(['brctl', 'addif', bridge_name, tap_device_name],
root_helper=self.root_helper):
return False
else:
msg = _("%(tap_device_name)s already exists on bridge "
"%(bridge_name)s") % locals()
LOG.debug(msg)
return True

def add_interface(self, network_id, physical_network, vlan_id,
interface_id):
if not interface_id:
"""
Since the VIF id is null, no VIF is plugged into this port
no more processing is required
"""
return False

if interface_id.startswith(GATEWAY_INTERFACE_PREFIX):
return self.add_tap_interface(network_id,
physical_network, vlan_id,
interface_id)
else:
tap_device_name = self.get_tap_device_name(interface_id)
return self.add_tap_interface(network_id,
physical_network, vlan_id,
tap_device_name)
port_id):
tap_device_name = self.get_tap_device_name(port_id)
return self.add_tap_interface(network_id,
physical_network, vlan_id,
tap_device_name)

def delete_vlan_bridge(self, bridge_name):
if self.device_exists(bridge_name):
Expand Down Expand Up @@ -667,12 +652,6 @@ def setup_rpc(self, physical_interfaces):
def setup_linux_bridge(self, interface_mappings):
self.linux_br = LinuxBridge(interface_mappings, self.root_helper)

def process_port_binding(self, network_id, interface_id,
physical_network, vlan_id):
return self.linux_br.add_interface(network_id,
physical_network, vlan_id,
interface_id)

def remove_port_binding(self, network_id, interface_id):
bridge_name = self.linux_br.get_bridge_name(network_id)
tap_device_name = self.linux_br.get_tap_device_name(interface_id)
Expand Down Expand Up @@ -715,7 +694,7 @@ def process_network_devices(self, device_info):
def treat_devices_added(self, devices):
resync = False
for device in devices:
LOG.info("Port %s added", device)
LOG.debug("Port %s added", device)
try:
details = self.plugin_rpc.get_device_details(self.context,
device,
Expand All @@ -728,15 +707,15 @@ def treat_devices_added(self, devices):
LOG.info("Port %s updated. Details: %s", device, details)
if details['admin_state_up']:
# create the networking for the port
self.process_port_binding(details['network_id'],
details['port_id'],
details['physical_network'],
details['vlan_id'])
self.linux_br.add_interface(details['network_id'],
details['physical_network'],
details['vlan_id'],
details['port_id'])
else:
self.remove_port_binding(details['network_id'],
details['port_id'])
else:
LOG.debug("Device %s not defined on plugin", device)
LOG.info("Device %s not defined on plugin", device)
return resync

def treat_devices_removed(self, devices):
Expand Down
54 changes: 54 additions & 0 deletions quantum/tests/unit/linuxbridge/test_lb_quantum_agent.py
@@ -0,0 +1,54 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4

# Copyright (c) 2012 OpenStack, LLC.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.

import mock
import unittest2 as unittest

from quantum.openstack.common import cfg
from quantum.plugins.linuxbridge.agent import linuxbridge_quantum_agent
from quantum.plugins.linuxbridge.common import config
from quantum.plugins.linuxbridge.common import constants as lconst


class TestLinuxBridge(unittest.TestCase):

def setUp(self):
self.addCleanup(cfg.CONF.reset)
interface_mappings = {'physnet1': 'eth1'}
root_helper = cfg.CONF.AGENT.root_helper

self.linux_bridge = linuxbridge_quantum_agent.LinuxBridge(
interface_mappings, root_helper)

def test_ensure_physical_in_bridge_invalid(self):
result = self.linux_bridge.ensure_physical_in_bridge('network_id',
'physnetx',
7)
self.assertFalse(result)

def test_ensure_physical_in_bridge_flat(self):
with mock.patch.object(self.linux_bridge,
'ensure_flat_bridge') as flat_bridge_func:
result = self.linux_bridge.ensure_physical_in_bridge(
'network_id', 'physnet1', lconst.FLAT_VLAN_ID)
self.assertTrue(flat_bridge_func.called)

def test_ensure_physical_in_bridge_vlan(self):
with mock.patch.object(self.linux_bridge,
'ensure_vlan_bridge') as vlan_bridge_func:
result = self.linux_bridge.ensure_physical_in_bridge(
'network_id', 'physnet1', 7)
self.assertTrue(vlan_bridge_func.called)

0 comments on commit 04aab72

Please sign in to comment.