]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
v2 support for the linux bridge plugin
authorGary Kotton <gkotton@redhat.com>
Thu, 28 Jun 2012 10:26:10 +0000 (06:26 -0400)
committerGary Kotton <gkotton@redhat.com>
Tue, 3 Jul 2012 04:56:55 +0000 (00:56 -0400)
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

quantum/plugins/linuxbridge/LinuxBridgePluginV2.py [new file with mode: 0644]
quantum/plugins/linuxbridge/agent/linuxbridge_quantum_agent.py
quantum/plugins/linuxbridge/common/config.py
quantum/plugins/linuxbridge/db/l2network_db.py
quantum/plugins/linuxbridge/db/l2network_models_v2.py [new file with mode: 0644]

diff --git a/quantum/plugins/linuxbridge/LinuxBridgePluginV2.py b/quantum/plugins/linuxbridge/LinuxBridgePluginV2.py
new file mode 100644 (file)
index 0000000..4920812
--- /dev/null
@@ -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)
index 91a1e3218fbb1a76f2e2214af96e964369315197..4168d784a08672b1ce157a8c89c94d0b627c3731 100755 (executable)
@@ -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)
 
index 85cc907bc1d05c765d0ac375658b6597e3faad7b..7e77147f44fa99d342175bb222107a9c8d9520d0 100644 (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),
 ]
 
 
index 8b32614a3672ddcc6332c453db2f0afafe83030c..b661c700e0f93b1983c648a83b8a9be296ad742d 100644 (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:
diff --git a/quantum/plugins/linuxbridge/db/l2network_models_v2.py b/quantum/plugins/linuxbridge/db/l2network_models_v2.py
new file mode 100644 (file)
index 0000000..577f226
--- /dev/null
@@ -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)