OVS plugin support for v2 Quantum API

blueprint: ovs-api-v2-support

This commit allows the ovs_quantum_plugin to work with the v2 api.

change-Id: I9e332a799f6bee8a90755f961fbb9711a1ecdaca
This commit is contained in:
Aaron Rosen 2012-06-28 18:17:16 -07:00
parent 1c93399f6f
commit f21343cdb2
9 changed files with 250 additions and 66 deletions

View File

@ -38,6 +38,8 @@ polling_interval = 2
# Change to "sudo quantum-rootwrap" to limit commands that can be run # Change to "sudo quantum-rootwrap" to limit commands that can be run
# as root. # as root.
root_helper = sudo root_helper = sudo
# Use Quantumv2 API
target_v2_api = False
#----------------------------------------------------------------------------- #-----------------------------------------------------------------------------
# Sample Configurations. # Sample Configurations.
@ -53,6 +55,8 @@ root_helper = sudo
# root_helper = sudo # root_helper = sudo
# Add the following setting, if you want to log to a file # Add the following setting, if you want to log to a file
# log_file = /var/log/quantum/ovs_quantum_agent.log # log_file = /var/log/quantum/ovs_quantum_agent.log
# Use Quantumv2 API
# target_v2_api = False
# #
# 2. With tunneling. # 2. With tunneling.
# [DATABASE] # [DATABASE]

View File

@ -26,6 +26,7 @@ import inspect
import logging import logging
import os import os
import subprocess import subprocess
import uuid
from quantum.common import exceptions as exception from quantum.common import exceptions as exception
from quantum.common import flags from quantum.common import flags
@ -153,3 +154,8 @@ def find_config_file(options, config_file):
cfg_file = os.path.join(cfg_dir, config_file) cfg_file = os.path.join(cfg_dir, config_file)
if os.path.exists(cfg_file): if os.path.exists(cfg_file):
return cfg_file return cfg_file
def str_uuid():
"""Return a uuid as a string"""
return str(uuid.uuid4())

View File

@ -13,17 +13,11 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
import uuid
import sqlalchemy as sa import sqlalchemy as sa
from sqlalchemy.ext import declarative from sqlalchemy.ext import declarative
from sqlalchemy import orm from sqlalchemy import orm
def str_uuid():
return str(uuid.uuid4())
class QuantumBase(object): class QuantumBase(object):
"""Base class for Quantum Models.""" """Base class for Quantum Models."""
@ -60,7 +54,6 @@ class QuantumBase(object):
class QuantumBaseV2(QuantumBase): class QuantumBaseV2(QuantumBase):
id = sa.Column(sa.String(36), primary_key=True, default=str_uuid)
@declarative.declared_attr @declarative.declared_attr
def __tablename__(cls): def __tablename__(cls):

View File

@ -16,6 +16,7 @@
import sqlalchemy as sa import sqlalchemy as sa
from sqlalchemy import orm from sqlalchemy import orm
from quantum.common import utils
from quantum.db import model_base from quantum.db import model_base
@ -25,7 +26,12 @@ class HasTenant(object):
tenant_id = sa.Column(sa.String(255)) tenant_id = sa.Column(sa.String(255))
class IPAllocationRange(model_base.BASEV2): class HasId(object):
"""id mixin, add to subclasses that have an id."""
id = sa.Column(sa.String(36), primary_key=True, default=utils.str_uuid)
class IPAllocationRange(model_base.BASEV2, HasId):
"""Internal representation of a free IP address range in a Quantum """Internal representation of a free IP address range in a Quantum
subnet. The range of available ips is [first_ip..last_ip]. The subnet. The range of available ips is [first_ip..last_ip]. The
allocation retrieves the first entry from the range. If the first allocation retrieves the first entry from the range. If the first
@ -53,7 +59,7 @@ class IPAllocation(model_base.BASEV2):
nullable=False, primary_key=True) nullable=False, primary_key=True)
class Port(model_base.BASEV2, HasTenant): class Port(model_base.BASEV2, HasId, HasTenant):
"""Represents a port on a quantum v2 network.""" """Represents a port on a quantum v2 network."""
network_id = sa.Column(sa.String(36), sa.ForeignKey("networks.id"), network_id = sa.Column(sa.String(36), sa.ForeignKey("networks.id"),
nullable=False) nullable=False)
@ -64,7 +70,7 @@ class Port(model_base.BASEV2, HasTenant):
device_id = sa.Column(sa.String(255), nullable=False) device_id = sa.Column(sa.String(255), nullable=False)
class Subnet(model_base.BASEV2): class Subnet(model_base.BASEV2, HasId):
"""Represents a quantum subnet. """Represents a quantum subnet.
When a subnet is created the first and last entries will be created. These When a subnet is created the first and last entries will be created. These
@ -81,7 +87,7 @@ class Subnet(model_base.BASEV2):
# - additional_routes # - additional_routes
class Network(model_base.BASEV2, HasTenant): class Network(model_base.BASEV2, HasId, HasTenant):
"""Represents a v2 quantum network.""" """Represents a v2 quantum network."""
name = sa.Column(sa.String(255)) name = sa.Column(sa.String(255))
ports = orm.relationship(Port, backref='networks') ports = orm.relationship(Port, backref='networks')

View File

@ -18,6 +18,7 @@
# @author: Brad Hall, Nicira Networks, Inc. # @author: Brad Hall, Nicira Networks, Inc.
# @author: Dan Wendlandt, Nicira Networks, Inc. # @author: Dan Wendlandt, Nicira Networks, Inc.
# @author: Dave Lapsley, Nicira Networks, Inc. # @author: Dave Lapsley, Nicira Networks, Inc.
# @author: Aaron Rosen, Nicira Networks, Inc.
import logging import logging
from optparse import OptionParser from optparse import OptionParser
@ -59,21 +60,21 @@ class LocalVLANMapping:
class Port(object): class Port(object):
'''class stores port data in an ORM-free way, """Represents a quantum port.
so attributes are still available even if a
row has been deleted. Class stores port data in a ORM-free way, so attributres are
''' still available even if a row has been deleted.
"""
def __init__(self, p): def __init__(self, p):
self.uuid = p.uuid self.uuid = p.uuid
self.network_id = p.network_id self.network_id = p.network_id
self.interface_id = p.interface_id self.interface_id = p.interface_id
self.state = p.state self.state = p.state
self.op_status = p.op_status self.status = p.op_status
def __eq__(self, other): def __eq__(self, other):
'''compare only fields that will cause us to re-wire '''Compare only fields that will cause us to re-wire.'''
'''
try: try:
return (self and other return (self and other
and self.interface_id == other.interface_id and self.interface_id == other.interface_id
@ -88,14 +89,45 @@ class Port(object):
return hash(self.uuid) return hash(self.uuid)
class Portv2(object):
"""Represents a quantumv2 port.
Class stores port data in a ORM-free way, so attributres are
still available even if a row has been deleted.
"""
def __init__(self, p):
self.id = p.id
self.network_id = p.network_id
self.device_id = p.device_id
self.admin_state_up = p.admin_state_up
self.status = p.status
def __eq__(self, other):
'''Compare only fields that will cause us to re-wire.'''
try:
return (self and other
and self.id == other.id
and self.admin_state_up == other.admin_state_up)
except:
return False
def __ne__(self, other):
return not self.__eq__(other)
def __hash__(self):
return hash(self.id)
class OVSQuantumAgent(object): class OVSQuantumAgent(object):
def __init__(self, integ_br, root_helper, def __init__(self, integ_br, root_helper, polling_interval,
polling_interval, reconnect_interval): reconnect_interval, target_v2_api=False):
self.root_helper = root_helper self.root_helper = root_helper
self.setup_integration_br(integ_br) self.setup_integration_br(integ_br)
self.polling_interval = polling_interval self.polling_interval = polling_interval
self.reconnect_interval = reconnect_interval self.reconnect_interval = reconnect_interval
self.target_v2_api = target_v2_api
def port_bound(self, port, vlan_id): def port_bound(self, port, vlan_id):
self.int_br.set_db_attribute("Port", port.port_name, self.int_br.set_db_attribute("Port", port.port_name,
@ -139,7 +171,10 @@ class OVSQuantumAgent(object):
continue continue
for port in ports: for port in ports:
all_bindings[port.interface_id] = port if self.target_v2_api:
all_bindings[port.id] = port
else:
all_bindings[port.interface_id] = port
vlan_bindings = {} vlan_bindings = {}
try: try:
@ -177,7 +212,7 @@ class OVSQuantumAgent(object):
% (old_b, str(p))) % (old_b, str(p)))
self.port_unbound(p, True) self.port_unbound(p, True)
if p.vif_id in all_bindings: if p.vif_id in all_bindings:
all_bindings[p.vif_id].op_status = OP_STATUS_DOWN all_bindings[p.vif_id].status = OP_STATUS_DOWN
if new_b is not None: if new_b is not None:
# If we don't have a binding we have to stick it on # If we don't have a binding we have to stick it on
# the dead vlan # the dead vlan
@ -185,7 +220,7 @@ class OVSQuantumAgent(object):
vlan_id = vlan_bindings.get(net_id, DEAD_VLAN_TAG) vlan_id = vlan_bindings.get(net_id, DEAD_VLAN_TAG)
self.port_bound(p, vlan_id) self.port_bound(p, vlan_id)
if p.vif_id in all_bindings: if p.vif_id in all_bindings:
all_bindings[p.vif_id].op_status = OP_STATUS_UP all_bindings[p.vif_id].status = OP_STATUS_UP
LOG.info(("Adding binding to net-id = %s " LOG.info(("Adding binding to net-id = %s "
"for %s on vlan %s") % "for %s on vlan %s") %
(new_b, str(p), vlan_id)) (new_b, str(p), vlan_id))
@ -197,7 +232,7 @@ class OVSQuantumAgent(object):
old_b = old_local_bindings[vif_id] old_b = old_local_bindings[vif_id]
self.port_unbound(old_vif_ports[vif_id], False) self.port_unbound(old_vif_ports[vif_id], False)
if vif_id in all_bindings: if vif_id in all_bindings:
all_bindings[vif_id].op_status = OP_STATUS_DOWN all_bindings[vif_id].status = OP_STATUS_DOWN
old_vif_ports = new_vif_ports old_vif_ports = new_vif_ports
old_local_bindings = new_local_bindings old_local_bindings = new_local_bindings
@ -237,7 +272,7 @@ class OVSQuantumTunnelAgent(object):
MAX_VLAN_TAG = 4094 MAX_VLAN_TAG = 4094
def __init__(self, integ_br, tun_br, local_ip, root_helper, def __init__(self, integ_br, tun_br, local_ip, root_helper,
polling_interval, reconnect_interval): polling_interval, reconnect_interval, target_v2_api=False):
'''Constructor. '''Constructor.
:param integ_br: name of the integration bridge. :param integ_br: name of the integration bridge.
@ -245,7 +280,9 @@ class OVSQuantumTunnelAgent(object):
:param local_ip: local IP address of this hypervisor. :param local_ip: local IP address of this hypervisor.
:param root_helper: utility to use when running shell cmds. :param root_helper: utility to use when running shell cmds.
:param polling_interval: interval (secs) to poll DB. :param polling_interval: interval (secs) to poll DB.
:param reconnect_internal: retry interval (secs) on DB error.''' :param reconnect_internal: retry interval (secs) on DB error.
:param target_v2_api: if True use v2 api.
'''
self.root_helper = root_helper self.root_helper = root_helper
self.available_local_vlans = set( self.available_local_vlans = set(
xrange(OVSQuantumTunnelAgent.MIN_VLAN_TAG, xrange(OVSQuantumTunnelAgent.MIN_VLAN_TAG,
@ -259,6 +296,7 @@ class OVSQuantumTunnelAgent(object):
self.local_ip = local_ip self.local_ip = local_ip
self.tunnel_count = 0 self.tunnel_count = 0
self.setup_tunnel_br(tun_br) self.setup_tunnel_br(tun_br)
self.target_v2_api = target_v2_api
def provision_local_vlan(self, net_uuid, lsw_id): def provision_local_vlan(self, net_uuid, lsw_id):
'''Provisions a local VLAN. '''Provisions a local VLAN.
@ -294,7 +332,8 @@ class OVSQuantumTunnelAgent(object):
self.available_local_vlans.add(lvm.vlan) self.available_local_vlans.add(lvm.vlan)
def port_bound(self, port, net_uuid, lsw_id): def port_bound(self, port, net_uuid, lsw_id):
'''Bind port to net_uuid/lsw_id. '''Bind port to net_uuid/lsw_id and install flow for inbound traffic
to vm.
:param port: a ovslib.VifPort object. :param port: a ovslib.VifPort object.
:param net_uuid: the net_uuid this port is to be associated with. :param net_uuid: the net_uuid this port is to be associated with.
@ -405,8 +444,12 @@ class OVSQuantumTunnelAgent(object):
while True: while True:
try: try:
all_bindings = dict((p.interface_id, Port(p)) if self.target_v2_api:
for p in db.ports.all()) all_bindings = dict((p.id, Portv2(p))
for p in db.ports.all())
else:
all_bindings = dict((p.interface_id, Port(p))
for p in db.ports.all())
all_bindings_vif_port_ids = set(all_bindings) all_bindings_vif_port_ids = set(all_bindings)
lsw_id_bindings = dict((bind.network_id, bind.vlan_id) lsw_id_bindings = dict((bind.network_id, bind.vlan_id)
for bind in db.vlan_bindings.all()) for bind in db.vlan_bindings.all())
@ -461,7 +504,8 @@ class OVSQuantumTunnelAgent(object):
old_net_uuid + " for " + str(p) old_net_uuid + " for " + str(p)
+ " added to dead vlan") + " added to dead vlan")
self.port_unbound(p, old_net_uuid) self.port_unbound(p, old_net_uuid)
all_bindings[p.vif_id].op_status = OP_STATUS_DOWN if p.vif_id in all_bindings:
all_bindings[p.vif_id].status = OP_STATUS_DOWN
if not new_port: if not new_port:
self.port_dead(p) self.port_dead(p)
@ -474,7 +518,7 @@ class OVSQuantumTunnelAgent(object):
lsw_id = lsw_id_bindings[new_net_uuid] lsw_id = lsw_id_bindings[new_net_uuid]
self.port_bound(p, new_net_uuid, lsw_id) self.port_bound(p, new_net_uuid, lsw_id)
all_bindings[p.vif_id].op_status = OP_STATUS_UP all_bindings[p.vif_id].status = OP_STATUS_UP
LOG.info("Port %s on net-id = %s bound to %s " % ( LOG.info("Port %s on net-id = %s bound to %s " % (
str(p), new_net_uuid, str(p), new_net_uuid,
str(self.local_vlan_map[new_net_uuid]))) str(self.local_vlan_map[new_net_uuid])))
@ -482,7 +526,7 @@ class OVSQuantumTunnelAgent(object):
for vif_id in disappeared_vif_ports_ids: for vif_id in disappeared_vif_ports_ids:
LOG.info("Port Disappeared: " + vif_id) LOG.info("Port Disappeared: " + vif_id)
if vif_id in all_bindings: if vif_id in all_bindings:
all_bindings[vif_id].op_status = OP_STATUS_DOWN all_bindings[vif_id].status = OP_STATUS_DOWN
old_port = old_local_bindings.get(vif_id) old_port = old_local_bindings.get(vif_id)
if old_port: if old_port:
self.port_unbound(old_vif_ports[vif_id], self.port_unbound(old_vif_ports[vif_id],
@ -540,17 +584,21 @@ def main():
reconnect_interval = conf.DATABASE.reconnect_interval reconnect_interval = conf.DATABASE.reconnect_interval
root_helper = conf.AGENT.root_helper root_helper = conf.AGENT.root_helper
# Determine API Version to use
target_v2_api = conf.AGENT.target_v2_api
if enable_tunneling: if enable_tunneling:
# Get parameters for OVSQuantumTunnelAgent # Get parameters for OVSQuantumTunnelAgent
tun_br = conf.OVS.tunnel_bridge tun_br = conf.OVS.tunnel_bridge
# Mandatory parameter. # Mandatory parameter.
local_ip = conf.OVS.local_ip local_ip = conf.OVS.local_ip
plugin = OVSQuantumTunnelAgent(integ_br, tun_br, local_ip, root_helper, plugin = OVSQuantumTunnelAgent(integ_br, tun_br, local_ip, root_helper,
polling_interval, reconnect_interval) polling_interval, reconnect_interval,
target_v2_api)
else: else:
# Get parameters for OVSQuantumAgent. # Get parameters for OVSQuantumAgent.
plugin = OVSQuantumAgent(integ_br, root_helper, plugin = OVSQuantumAgent(integ_br, root_helper, polling_interval,
polling_interval, reconnect_interval) reconnect_interval, target_v2_api)
# Start everything. # Start everything.
plugin.daemon_loop(db_connection_url) plugin.daemon_loop(db_connection_url)

View File

@ -32,6 +32,7 @@ ovs_opts = [
] ]
agent_opts = [ agent_opts = [
cfg.BoolOpt('target_v2_api', default=True),
cfg.IntOpt('polling_interval', default=2), cfg.IntOpt('polling_interval', default=2),
cfg.StrOpt('root_helper', default='sudo'), cfg.StrOpt('root_helper', default='sudo'),
cfg.StrOpt('log_file', default=None), cfg.StrOpt('log_file', default=None),

View File

@ -0,0 +1,51 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2011 Nicira Networks, Inc.
# All Rights Reserved.
#
# 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.
# @author: Aaron Rosen, Nicira Networks, Inc.
from sqlalchemy.orm import exc
import quantum.db.api as db
from quantum.plugins.openvswitch import ovs_models_v2
def get_vlans():
session = db.get_session()
try:
bindings = (session.query(ovs_models_v2.VlanBinding).
all())
except exc.NoResultFound:
return []
return [(binding.vlan_id, binding.network_id) for binding in bindings]
def add_vlan_binding(vlan_id, net_id):
session = db.get_session()
binding = ovs_models_v2.VlanBinding(vlan_id, net_id)
session.add(binding)
session.flush()
return binding
def remove_vlan_binding(net_id):
session = db.get_session()
try:
binding = (session.query(ovs_models_v2.VlanBinding).
filter_by(network_id=net_id).
one())
session.delete(binding)
except exc.NoResultFound:
pass
session.flush()

View File

@ -0,0 +1,49 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2011 Nicira Networks, Inc.
# All Rights Reserved.
#
# 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.
# @author: Aaron Rosen, Nicira Networks, Inc.
from sqlalchemy import Column, Integer, String
from quantum.db import models_v2
class VlanBinding(models_v2.model_base.BASEV2):
"""Represents a binding of network_id to vlan_id."""
__tablename__ = 'vlan_bindings'
vlan_id = Column(Integer, primary_key=True)
network_id = Column(String(255))
def __init__(self, vlan_id, network_id):
self.network_id = network_id
self.vlan_id = vlan_id
def __repr__(self):
return "<VlanBinding(%s,%s)>" % (self.vlan_id, self.network_id)
class TunnelIP(models_v2.model_base.BASEV2):
"""Represents a remote IP in tunnel mode."""
__tablename__ = 'tunnel_ips'
ip_address = Column(String(255), primary_key=True)
def __init__(self, ip_address):
self.ip_address = ip_address
def __repr__(self):
return "<TunnelIP(%s)>" % (self.ip_address)

View File

@ -17,6 +17,7 @@
# @author: Brad Hall, Nicira Networks, Inc. # @author: Brad Hall, Nicira Networks, Inc.
# @author: Dan Wendlandt, Nicira Networks, Inc. # @author: Dan Wendlandt, Nicira Networks, Inc.
# @author: Dave Lapsley, Nicira Networks, Inc. # @author: Dave Lapsley, Nicira Networks, Inc.
# @author: Aaron Rosen, Nicira Networks, Inc.
import logging import logging
import os import os
@ -24,14 +25,16 @@ import os
from quantum.api.api_common import OperationalStatus from quantum.api.api_common import OperationalStatus
from quantum.common import exceptions as q_exc from quantum.common import exceptions as q_exc
from quantum.common.utils import find_config_file from quantum.common.utils import find_config_file
import quantum.db.api as db from quantum.db import api as db
from quantum.db import db_base_plugin_v2
from quantum.db import models_v2
from quantum.plugins.openvswitch.common import config from quantum.plugins.openvswitch.common import config
from quantum.plugins.openvswitch import ovs_db from quantum.plugins.openvswitch import ovs_db
from quantum.plugins.openvswitch import ovs_db_v2
from quantum.quantum_plugin_base import QuantumPluginBase from quantum.quantum_plugin_base import QuantumPluginBase
LOG = logging.getLogger("ovs_quantum_plugin") LOG = logging.getLogger("ovs_quantum_plugin")
CONF_FILE = find_config_file({"plugin": "openvswitch"}, CONF_FILE = find_config_file({"plugin": "openvswitch"},
"ovs_quantum_plugin.ini") "ovs_quantum_plugin.ini")
@ -47,6 +50,12 @@ class VlanMap(object):
free_vlans = set() free_vlans = set()
def __init__(self, vlan_min=1, vlan_max=4094): def __init__(self, vlan_min=1, vlan_max=4094):
if vlan_min > vlan_max:
LOG.warn("Using default VLAN values! vlan_min = %s is larger"
" than vlan_max = %s!" % (vlan_min, vlan_max))
vlan_min = 1
vlan_max = 4094
self.vlan_min = vlan_min self.vlan_min = vlan_min
self.vlan_max = vlan_max self.vlan_max = vlan_max
self.vlans.clear() self.vlans.clear()
@ -82,44 +91,26 @@ class VlanMap(object):
else: else:
LOG.error("No vlan found with network \"%s\"", network_id) LOG.error("No vlan found with network \"%s\"", network_id)
def populate_already_used(self, vlans):
for vlan_id, network_id in vlans:
LOG.debug("Adding already populated vlan %s -> %s" %
(vlan_id, network_id))
self.already_used(vlan_id, network_id)
class OVSQuantumPlugin(QuantumPluginBase): class OVSQuantumPlugin(QuantumPluginBase):
def __init__(self, configfile=None): def __init__(self, configfile=None):
if configfile is None: conf = config.parse(CONF_FILE)
if os.path.exists(CONF_FILE):
configfile = CONF_FILE
else:
configfile = find_config(os.path.abspath(
os.path.dirname(__file__)))
if configfile is None:
raise Exception("Configuration file \"%s\" doesn't exist" %
(configfile))
LOG.debug("Using configuration file: %s" % configfile)
conf = config.parse(configfile)
options = {"sql_connection": conf.DATABASE.sql_connection} options = {"sql_connection": conf.DATABASE.sql_connection}
reconnect_interval = conf.DATABASE.reconnect_interval reconnect_interval = conf.DATABASE.reconnect_interval
options.update({"reconnect_interval": reconnect_interval}) options.update({"reconnect_interval": reconnect_interval})
db.configure_db(options) db.configure_db(options)
vlan_min = conf.OVS.vlan_min self.vmap = VlanMap(conf.OVS.vlan_min, conf.OVS.vlan_max)
vlan_max = conf.OVS.vlan_max
if vlan_min > vlan_max:
LOG.warn("Using default VLAN values! vlan_min = %s is larger"
" than vlan_max = %s!" % (vlan_min, vlan_max))
vlan_min = 1
vlan_max = 4094
self.vmap = VlanMap(vlan_min, vlan_max)
# Populate the map with anything that is already present in the # Populate the map with anything that is already present in the
# database # database
vlans = ovs_db.get_vlans() self.vmap.populate_already_used(ovs_db.get_vlans())
for x in vlans:
vlan_id, network_id = x
LOG.debug("Adding already populated vlan %s -> %s" %
(vlan_id, network_id))
self.vmap.already_used(vlan_id, network_id)
def get_all_networks(self, tenant_id, **kwargs): def get_all_networks(self, tenant_id, **kwargs):
nets = [] nets = []
@ -142,8 +133,13 @@ class OVSQuantumPlugin(QuantumPluginBase):
def create_network(self, tenant_id, net_name, **kwargs): def create_network(self, tenant_id, net_name, **kwargs):
net = db.network_create(tenant_id, net_name, net = db.network_create(tenant_id, net_name,
op_status=OperationalStatus.UP) op_status=OperationalStatus.UP)
try:
vlan_id = self.vmap.acquire(str(net.uuid))
except NoFreeVLANException:
db.network_destroy(net.uuid)
raise
LOG.debug("Created network: %s" % net) LOG.debug("Created network: %s" % net)
vlan_id = self.vmap.acquire(str(net.uuid))
ovs_db.add_vlan_binding(vlan_id, str(net.uuid)) ovs_db.add_vlan_binding(vlan_id, str(net.uuid))
return self._make_net_dict(str(net.uuid), net.name, [], net.op_status) return self._make_net_dict(str(net.uuid), net.name, [], net.op_status)
@ -233,3 +229,33 @@ class OVSQuantumPlugin(QuantumPluginBase):
db.validate_port_ownership(tenant_id, net_id, port_id) db.validate_port_ownership(tenant_id, net_id, port_id)
res = db.port_get(port_id, net_id) res = db.port_get(port_id, net_id)
return res.interface_id return res.interface_id
class OVSQuantumPluginV2(db_base_plugin_v2.QuantumDbPluginV2):
def __init__(self, configfile=None):
conf = config.parse(CONF_FILE)
options = {"sql_connection": conf.DATABASE.sql_connection}
options.update({'base': models_v2.model_base.BASEV2})
reconnect_interval = conf.DATABASE.reconnect_interval
options.update({"reconnect_interval": reconnect_interval})
db.configure_db(options)
self.vmap = VlanMap(conf.OVS.vlan_min, conf.OVS.vlan_max)
self.vmap.populate_already_used(ovs_db_v2.get_vlans())
def create_network(self, context, network):
net = super(OVSQuantumPluginV2, self).create_network(context, network)
try:
vlan_id = self.vmap.acquire(str(net['id']))
except NoFreeVLANException:
super(OVSQuantumPluginV2, self).delete_network(context, net['id'])
raise
LOG.debug("Created network: %s" % net['id'])
ovs_db_v2.add_vlan_binding(vlan_id, str(net['id']))
return net
def delete_network(self, context, id):
ovs_db_v2.remove_vlan_binding(id)
self.vmap.release(id)
return super(OVSQuantumPluginV2, self).delete_network(context, id)