v2 support for the linux bridge plugin

blueprint lb-api-v2-support

Plugin support for the linuxbridge using the v2 API

1. The core_plugin in quantum.conf must be set to:
quantum.plugins.linuxbridge.LinuxBridgePluginV2.LinuxBridgePluginV2
2. By default the agent is v2. A configuration file entry 'target_v2_api'
in the section 'AGENT' can be set as False to support v1.

Change-Id: I2e196859c13b28e535c6ec394ec3f5bc907bf019
This commit is contained in:
Gary Kotton 2012-06-28 06:26:10 -04:00
parent 95c9163986
commit 9247dabd6a
5 changed files with 164 additions and 36 deletions

View File

@ -0,0 +1,54 @@
# 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 logging
from quantum.db import db_base_plugin_v2
from quantum.db import models_v2
from quantum.plugins.linuxbridge.db import l2network_db as cdb
LOG = logging.getLogger(__name__)
class LinuxBridgePluginV2(db_base_plugin_v2.QuantumDbPluginV2):
"""
LinuxBridgePlugin provides support for Quantum abstractions
using LinuxBridge. A new VLAN is created for each network.
It relies on an agent to perform the actual bridge configuration
on each host.
"""
def __init__(self):
cdb.initialize(base=models_v2.model_base.BASEV2)
LOG.debug("Linux Bridge Plugin initialization complete")
def create_network(self, context, network):
new_network = super(LinuxBridgePluginV2, self).create_network(context,
network)
try:
vlan_id = cdb.reserve_vlanid()
cdb.add_vlan_binding(vlan_id, new_network['id'])
except:
super(LinuxBridgePluginV2, self).delete_network(context,
new_network['id'])
raise
return new_network
def delete_network(self, context, id):
vlan_binding = cdb.get_vlan_binding(id)
cdb.release_vlanid(vlan_binding[const.VLANID])
cdb.remove_vlan_binding(id)
return super(LinuxBridgePluginV2, self).delete_network(context, id)

View File

@ -314,12 +314,13 @@ class LinuxBridge:
class LinuxBridgeQuantumAgent:
def __init__(self, br_name_prefix, physical_interface, polling_interval,
reconnect_interval, root_helper):
reconnect_interval, root_helper, target_v2_api):
self.polling_interval = polling_interval
self.reconnect_interval = reconnect_interval
self.root_helper = root_helper
self.setup_linux_bridge(br_name_prefix, physical_interface)
self.db_connected = False
self.target_v2_api = target_v2_api
def setup_linux_bridge(self, br_name_prefix, physical_interface):
self.linux_br = LinuxBridge(br_name_prefix, physical_interface,
@ -407,25 +408,41 @@ class LinuxBridgeQuantumAgent:
all_bindings = {}
for bind in port_binds:
all_bindings[bind.uuid] = bind
entry = {'network_id': bind.network_id, 'state': bind.state,
'op_status': bind.op_status, 'uuid': bind.uuid,
'interface_id': bind.interface_id}
if bind.state == 'ACTIVE':
append_entry = False
if self.target_v2_api:
all_bindings[bind.id] = bind
entry = {'network_id': bind.network_id,
'uuid': bind.id,
'status': bind.status,
'interface_id': bind.id}
append_entry = bind.admin_state_up
else:
all_bindings[bind.uuid] = bind
entry = {'network_id': bind.network_id, 'state': bind.state,
'op_status': bind.op_status, 'uuid': bind.uuid,
'interface_id': bind.interface_id}
append_entry = bind.state == 'ACTIVE'
if append_entry:
port_bindings.append(entry)
plugged_interfaces = []
ports_string = ""
for pb in port_bindings:
ports_string = "%s %s" % (ports_string, pb)
if pb['interface_id']:
vlan_id = str(vlan_bindings[pb['network_id']]['vlan_id'])
if self.process_port_binding(pb['uuid'],
pb['network_id'],
pb['interface_id'],
vlan_id):
all_bindings[pb['uuid']].op_status = OP_STATUS_UP
plugged_interfaces.append(pb['interface_id'])
port_id = pb['uuid']
interface_id = pb['interface_id']
vlan_id = str(vlan_bindings[pb['network_id']]['vlan_id'])
if self.process_port_binding(port_id,
pb['network_id'],
interface_id,
vlan_id):
if self.target_v2_api:
all_bindings[port_id].status = OP_STATUS_UP
else:
all_bindings[port_id].op_status = OP_STATUS_UP
plugged_interfaces.append(interface_id)
if old_port_bindings != port_bindings:
LOG.debug("Port-bindings: %s" % ports_string)
@ -495,11 +512,9 @@ def main():
root_helper = conf.AGENT.root_helper
'Establish database connection and load models'
db_connection_url = conf.DATABASE.sql_connection
LOG.info("Connecting to %s" % (db_connection_url))
plugin = LinuxBridgeQuantumAgent(br_name_prefix, physical_interface,
polling_interval, reconnect_interval,
root_helper)
root_helper, conf.AGENT.target_v2_api)
LOG.info("Agent initialized successfully, now running... ")
plugin.daemon_loop(db_connection_url)

View File

@ -37,6 +37,7 @@ bridge_opts = [
agent_opts = [
cfg.IntOpt('polling_interval', default=2),
cfg.StrOpt('root_helper', default='sudo'),
cfg.BoolOpt('target_v2_api', default=False),
]

View File

@ -26,16 +26,24 @@ import quantum.db.api as db
from quantum.plugins.linuxbridge.common import config
from quantum.plugins.linuxbridge.common import exceptions as c_exc
from quantum.plugins.linuxbridge.db import l2network_models
from quantum.plugins.linuxbridge.db import l2network_models_v2
LOG = logging.getLogger(__name__)
CONF_FILE = find_config_file({'plugin': 'linuxbridge'},
"linuxbridge_conf.ini")
CONF = config.parse(CONF_FILE)
# The global variable for the database version model
L2_MODEL = l2network_models
def initialize():
def initialize(base=None):
global L2_MODEL
options = {"sql_connection": "%s" % CONF.DATABASE.sql_connection}
options.update({"reconnect_interval": CONF.DATABASE.reconnect_interval})
if base:
options.update({"base": base})
L2_MODEL = l2network_models_v2
db.configure_db(options)
create_vlanids()
@ -47,7 +55,7 @@ def create_vlanids():
start = CONF.VLANS.vlan_start
end = CONF.VLANS.vlan_end
try:
vlanid = session.query(l2network_models.VlanID).one()
vlanid = session.query(L2_MODEL.VlanID).one()
except exc.MultipleResultsFound:
"""
TODO (Sumit): Salvatore rightly points out that this will not handle
@ -57,10 +65,10 @@ def create_vlanids():
Per Dan's suggestion we just throw a server exception for now.
"""
current_start = (
int(session.query(func.min(l2network_models.VlanID.vlan_id)).
int(session.query(func.min(L2_MODEL.VlanID.vlan_id)).
one()[0]))
current_end = (
int(session.query(func.max(l2network_models.VlanID.vlan_id)).
int(session.query(func.max(L2_MODEL.VlanID.vlan_id)).
one()[0]))
if current_start != start or current_end != end:
LOG.debug("Old VLAN range %s-%s" % (current_start, current_end))
@ -70,7 +78,7 @@ def create_vlanids():
except exc.NoResultFound:
LOG.debug("Setting VLAN range to %s-%s" % (start, end))
while start <= end:
vlanid = l2network_models.VlanID(start)
vlanid = L2_MODEL.VlanID(start)
session.add(vlanid)
start += 1
session.flush()
@ -82,7 +90,7 @@ def get_all_vlanids():
LOG.debug("get_all_vlanids() called")
session = db.get_session()
try:
vlanids = (session.query(l2network_models.VlanID).
vlanids = (session.query(L2_MODEL.VlanID).
all())
return vlanids
except exc.NoResultFound:
@ -94,7 +102,7 @@ def is_vlanid_used(vlan_id):
LOG.debug("is_vlanid_used() called")
session = db.get_session()
try:
vlanid = (session.query(l2network_models.VlanID).
vlanid = (session.query(L2_MODEL.VlanID).
filter_by(vlan_id=vlan_id).
one())
return vlanid["vlan_used"]
@ -107,7 +115,7 @@ def release_vlanid(vlan_id):
LOG.debug("release_vlanid() called")
session = db.get_session()
try:
vlanid = (session.query(l2network_models.VlanID).
vlanid = (session.query(L2_MODEL.VlanID).
filter_by(vlan_id=vlan_id).
one())
vlanid["vlan_used"] = False
@ -124,7 +132,7 @@ def delete_vlanid(vlan_id):
LOG.debug("delete_vlanid() called")
session = db.get_session()
try:
vlanid = (session.query(l2network_models.VlanID).
vlanid = (session.query(L2_MODEL.VlanID).
filter_by(vlan_id=vlan_id).
one())
session.delete(vlanid)
@ -139,18 +147,18 @@ def reserve_vlanid():
LOG.debug("reserve_vlanid() called")
session = db.get_session()
try:
rvlan = (session.query(l2network_models.VlanID).
rvlan = (session.query(L2_MODEL.VlanID).
first())
if not rvlan:
create_vlanids()
rvlan = (session.query(l2network_models.VlanID).
rvlan = (session.query(L2_MODEL.VlanID).
filter_by(vlan_used=False).
first())
if not rvlan:
raise c_exc.VlanIDNotAvailable()
rvlanid = (session.query(l2network_models.VlanID).
rvlanid = (session.query(L2_MODEL.VlanID).
filter_by(vlan_id=rvlan["vlan_id"]).
one())
rvlanid["vlan_used"] = True
@ -166,7 +174,7 @@ def get_all_vlanids_used():
LOG.debug("get_all_vlanids() called")
session = db.get_session()
try:
vlanids = (session.query(l2network_models.VlanID).
vlanids = (session.query(L2_MODEL.VlanID).
filter_by(vlan_used=True).
all())
return vlanids
@ -179,7 +187,7 @@ def get_all_vlan_bindings():
LOG.debug("get_all_vlan_bindings() called")
session = db.get_session()
try:
bindings = (session.query(l2network_models.VlanBinding).
bindings = (session.query(L2_MODEL.VlanBinding).
all())
return bindings
except exc.NoResultFound:
@ -191,7 +199,7 @@ def get_vlan_binding(netid):
LOG.debug("get_vlan_binding() called")
session = db.get_session()
try:
binding = (session.query(l2network_models.VlanBinding).
binding = (session.query(L2_MODEL.VlanBinding).
filter_by(network_id=netid).
one())
return binding
@ -204,13 +212,13 @@ def add_vlan_binding(vlanid, netid):
LOG.debug("add_vlan_binding() called")
session = db.get_session()
try:
binding = (session.query(l2network_models.VlanBinding).
binding = (session.query(L2_MODEL.VlanBinding).
filter_by(vlan_id=vlanid).
one())
raise c_exc.NetworkVlanBindingAlreadyExists(vlan_id=vlanid,
network_id=netid)
except exc.NoResultFound:
binding = l2network_models.VlanBinding(vlanid, netid)
binding = L2_MODEL.VlanBinding(vlanid, netid)
session.add(binding)
session.flush()
return binding
@ -221,7 +229,7 @@ def remove_vlan_binding(netid):
LOG.debug("remove_vlan_binding() called")
session = db.get_session()
try:
binding = (session.query(l2network_models.VlanBinding).
binding = (session.query(L2_MODEL.VlanBinding).
filter_by(network_id=netid).
one())
session.delete(binding)
@ -236,7 +244,7 @@ def update_vlan_binding(netid, newvlanid=None):
LOG.debug("update_vlan_binding() called")
session = db.get_session()
try:
binding = (session.query(l2network_models.VlanBinding).
binding = (session.query(L2_MODEL.VlanBinding).
filter_by(network_id=netid).
one())
if newvlanid:

View File

@ -0,0 +1,50 @@
# 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 sqlalchemy as sa
from sqlalchemy import orm
from quantum.db import model_base
class VlanID(model_base.BASEV2):
"""Represents a vlan_id usage"""
__tablename__ = 'vlan_ids'
vlan_id = sa.Column(sa.Integer, nullable=False, primary_key=True)
vlan_used = sa.Column(sa.Boolean, nullable=False)
def __init__(self, vlan_id):
self.vlan_id = vlan_id
self.vlan_used = False
def __repr__(self):
return "<VlanID(%d,%s)>" % (self.vlan_id, self.vlan_used)
class VlanBinding(model_base.BASEV2):
"""Represents a binding of vlan_id to network_id"""
__tablename__ = 'vlan_bindings'
network_id = sa.Column(sa.String(36), sa.ForeignKey('networks.id'),
primary_key=True)
vlan_id = sa.Column(sa.Integer, nullable=False)
def __init__(self, vlan_id, network_id):
self.vlan_id = vlan_id
self.network_id = network_id
def __repr__(self):
return "<VlanBinding(%d,%s)>" % (self.vlan_id, self.network_id)