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:
parent
95c9163986
commit
9247dabd6a
54
quantum/plugins/linuxbridge/LinuxBridgePluginV2.py
Normal file
54
quantum/plugins/linuxbridge/LinuxBridgePluginV2.py
Normal 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)
|
@ -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)
|
||||
|
||||
|
@ -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),
|
||||
]
|
||||
|
||||
|
||||
|
@ -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:
|
||||
|
50
quantum/plugins/linuxbridge/db/l2network_models_v2.py
Normal file
50
quantum/plugins/linuxbridge/db/l2network_models_v2.py
Normal 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)
|
Loading…
x
Reference in New Issue
Block a user