]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Cisco UCS Manager ML2 Mechanism Driver
authorSandhya Dasu <sadasu@cisco.com>
Thu, 5 Feb 2015 17:21:05 +0000 (12:21 -0500)
committerSandhya Dasu <sadasu@cisco.com>
Wed, 25 Mar 2015 17:03:07 +0000 (17:03 +0000)
Introduces a ML2 based Mechanism Driver for Cisco UCS Manager. The vendor
specific driver code referenced by this MD resides in stackforge repo
networking-cisco. This MD did not exist in the Neutron tree before so no files
have to be removed as part of this change.

DocImpact

Partially-implements: blueprint core-vendor-decomposition
Implements: blueprint ml2-ucs-manager-mechanism-driver
Closes-Bug: #1434401

Conflicts:
etc/neutron/plugins/ml2/ml2_conf_cisco.ini
neutron/db/migration/alembic_migrations/versions/HEAD
setup.cfg

Change-Id: I5a32b18f0d4e3ef55738c51e65e3e81d8f415da4

etc/neutron/plugins/ml2/ml2_conf_cisco.ini
neutron/db/migration/alembic_migrations/versions/20b99fd19d4f_cisco_ucs_manager_mechanism_driver.py [new file with mode: 0644]
neutron/db/migration/alembic_migrations/versions/HEAD
neutron/db/migration/models/head.py
neutron/plugins/ml2/drivers/cisco/ucsm/__init__.py [new file with mode: 0644]
neutron/plugins/ml2/drivers/cisco/ucsm/mech_cisco_ucsm.py [new file with mode: 0644]
neutron/plugins/ml2/drivers/cisco/ucsm/ucsm_model.py [new file with mode: 0644]
setup.cfg

index cb88d88bf3bcc4e4b17913df322fc6a30372a405..fa4b5b0d529c7056865a091aaa204b01bddeb5a1 100644 (file)
 # cidr_exposed=10.10.40.2/16
 # gateway_ip=10.10.40.1
 
-[ml2_cisco_ucsm]
-
-# Cisco UCS Manager IP address
-# ucsm_ip=1.1.1.1
-
-# Username to connect to UCS Manager
-# ucsm_username=user
-
-# Password to connect to UCS Manager
-# ucsm_password=password
-
-# SR-IOV and VM-FEX vendors supported by this plugin
-# xxxx:yyyy represents vendor_id:product_id
-# supported_pci_devs = ['2222:3333', '4444:5555']
 
 [ml2_cisco_n1kv]
 
 # n1kv_vsm_ips = 1.1.1.1,1.1.1.2
 # username = user
 # password = password
+
+[ml2_cisco_ucsm]
+
+# Cisco UCS Manager IP address
+# ucsm_ip=1.1.1.1
+
+# Username to connect to UCS Manager
+# ucsm_username=user
+
+# Password to connect to UCS Manager
+# ucsm_password=password
+
+# SR-IOV and VM-FEX vendors supported by this plugin
+# xxxx:yyyy represents vendor_id:product_id
+# supported_pci_devs = ['2222:3333', '4444:5555']
+
+# Hostname to Service profile mapping for UCS Manager
+# controlled compute hosts
+# ucsm_host_list=Hostname1:Serviceprofile1, Hostname2:Serviceprofile2
diff --git a/neutron/db/migration/alembic_migrations/versions/20b99fd19d4f_cisco_ucs_manager_mechanism_driver.py b/neutron/db/migration/alembic_migrations/versions/20b99fd19d4f_cisco_ucs_manager_mechanism_driver.py
new file mode 100644 (file)
index 0000000..5090ef7
--- /dev/null
@@ -0,0 +1,40 @@
+# Copyright 2015 Cisco Systems, 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.
+#
+
+"""Cisco UCS Manager Mechanism Driver
+
+Revision ID: 20b99fd19d4f
+Revises: 589f9237ca0e
+Create Date: 2014-07-30 21:01:13.754637
+
+"""
+
+# revision identifiers, used by Alembic.
+revision = '20b99fd19d4f'
+down_revision = '589f9237ca0e'
+
+from alembic import op
+import sqlalchemy as sa
+
+
+def upgrade():
+    op.create_table(
+        'ml2_ucsm_port_profiles',
+        sa.Column('vlan_id', sa.Integer(), nullable=False),
+        sa.Column('profile_id', sa.String(length=64), nullable=False),
+        sa.Column('created_on_ucs', sa.Boolean(), nullable=False),
+        sa.PrimaryKeyConstraint('vlan_id')
+    )
index d21c061a43b553fa07972664d3676aa610d2a0bf..0dd06323d96ab259614dd97d91af2bbef9486cd8 100644 (file)
@@ -1 +1 @@
-589f9237ca0e
+20b99fd19d4f
index 407c5b08902539155b9ce7e84ed25b2519f6c3a6..56de64239a7b1fdeab10b687e775c166668ee9d8 100644 (file)
@@ -57,6 +57,7 @@ from neutron.plugins.ml2.drivers.cisco.apic import apic_model  # noqa
 from neutron.plugins.ml2.drivers.cisco.n1kv import n1kv_models  # noqa
 from neutron.plugins.ml2.drivers.cisco.nexus import (  # noqa
     nexus_models_v2 as ml2_nexus_models_v2)
+from neutron.plugins.ml2.drivers.cisco.ucsm import ucsm_model  # noqa
 from neutron.plugins.ml2.drivers import type_flat  # noqa
 from neutron.plugins.ml2.drivers import type_gre  # noqa
 from neutron.plugins.ml2.drivers import type_vlan  # noqa
diff --git a/neutron/plugins/ml2/drivers/cisco/ucsm/__init__.py b/neutron/plugins/ml2/drivers/cisco/ucsm/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/neutron/plugins/ml2/drivers/cisco/ucsm/mech_cisco_ucsm.py b/neutron/plugins/ml2/drivers/cisco/ucsm/mech_cisco_ucsm.py
new file mode 100644 (file)
index 0000000..8f88966
--- /dev/null
@@ -0,0 +1,218 @@
+# Copyright 2015 Cisco Systems, 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.
+
+from networking_cisco.plugins.ml2.drivers.cisco.ucsm import constants as const
+from networking_cisco.plugins.ml2.drivers.cisco.ucsm import ucsm_db
+from networking_cisco.plugins.ml2.drivers.cisco.ucsm import ucsm_network_driver
+
+from oslo_log import log as logging
+
+from neutron.common import constants
+from neutron.extensions import portbindings
+from neutron.i18n import _LE, _LW
+from neutron.plugins.common import constants as p_const
+from neutron.plugins.ml2 import driver_api as api
+
+LOG = logging.getLogger(__name__)
+
+
+class CiscoUcsmMechanismDriver(api.MechanismDriver):
+
+    """ML2 Mechanism Driver for Cisco UCS Manager."""
+
+    def initialize(self):
+        self.vif_type = portbindings.VIF_TYPE_802_QBH
+        self.vif_details = {portbindings.CAP_PORT_FILTER: False}
+        self.driver = ucsm_network_driver.CiscoUcsmDriver()
+        self.ucsm_db = ucsm_db.UcsmDbModel()
+
+    def _get_vlanid(self, context):
+        """Returns vlan_id associated with a bound VLAN segment."""
+        segment = context.bottom_bound_segment
+        if segment and self.check_segment(segment):
+            return segment.get(api.SEGMENTATION_ID)
+
+    def update_port_precommit(self, context):
+        """Adds port profile and vlan information to the DB.
+
+        Assign a port profile to this port. To do that:
+        1. Get the vlan_id associated with the bound segment
+        2. Check if a port profile already exists for this vlan_id
+        3. If yes, associate that port profile with this port.
+        4. If no, create a new port profile with this vlan_id and
+        associate with this port
+        """
+        LOG.debug("Inside update_port_precommit")
+        vnic_type = context.current.get(portbindings.VNIC_TYPE,
+                                        portbindings.VNIC_NORMAL)
+
+        profile = context.current.get(portbindings.PROFILE, {})
+
+        if not self.driver.check_vnic_type_and_vendor_info(vnic_type,
+                                                           profile):
+            LOG.debug("update_port_precommit encountered a non-SR-IOV port")
+            return
+
+        # If this is an Intel SR-IOV vnic, then no need to create port
+        # profile on the UCS manager. So no need to update the DB.
+        if not self.driver.is_vmfex_port(profile):
+            LOG.debug("update_port_precommit has nothing to do for this "
+                      "sr-iov port")
+            return
+
+        vlan_id = self._get_vlanid(context)
+
+        if not vlan_id:
+            LOG.warn(_LW("update_port_precommit: vlan_id is None."))
+            return
+
+        p_profile_name = self.make_profile_name(vlan_id)
+        LOG.debug("update_port_precommit: Profile: %s, VLAN_id: %d",
+                  p_profile_name, vlan_id)
+
+        # Create a new port profile entry in the db
+        self.ucsm_db.add_port_profile(p_profile_name, vlan_id)
+
+    def update_port_postcommit(self, context):
+        """Creates a port profile on UCS Manager.
+
+        Creates a Port Profile for this VLAN if it does not already
+        exist.
+        """
+        LOG.debug("Inside update_port_postcommit")
+        vlan_id = self._get_vlanid(context)
+
+        if not vlan_id:
+            LOG.warn(_LW("update_port_postcommit: vlan_id is None."))
+            return
+
+        # Check if UCS Manager needs to create a Port Profile.
+        # 1. Make sure this is a vm_fex_port.(Port profiles are created
+        # only for VM-FEX ports.)
+        # 2. Make sure update_port_precommit added an entry in the DB
+        # for this port profile
+        # 3. Make sure that the Port Profile hasn't already been created.
+
+        profile = context.current.get(portbindings.PROFILE, {})
+        vnic_type = context.current.get(portbindings.VNIC_TYPE,
+                                        portbindings.VNIC_NORMAL)
+
+        if (self.driver.check_vnic_type_and_vendor_info(vnic_type, profile) and
+            self.driver.is_vmfex_port(profile)):
+
+            LOG.debug("update_port_postcommit: VM-FEX port updated for "
+                      "vlan_id %d", vlan_id)
+
+            profile_name = self.ucsm_db.get_port_profile_for_vlan(vlan_id)
+            if self.ucsm_db.is_port_profile_created(vlan_id):
+                LOG.debug("update_port_postcommit: Port Profile %s for "
+                          "vlan_id %d already exists. Nothing to do.",
+                          profile_name, vlan_id)
+                return
+
+            # Ask the UCS Manager driver to create the above Port Profile.
+            # Connection to the UCS Manager is managed from within the driver.
+            if self.driver.create_portprofile(profile_name, vlan_id,
+                                              vnic_type):
+                # Port profile created on UCS, record that in the DB.
+                self.ucsm_db.set_port_profile_created(vlan_id, profile_name)
+            return
+
+        else:
+            # Enable vlan-id for this regular Neutron virtual port.
+            host_id = context.current.get(portbindings.HOST_ID)
+            LOG.debug("update_port_postcommit: Host_id is %s", host_id)
+            self.driver.update_serviceprofile(host_id, vlan_id)
+
+    def delete_network_precommit(self, context):
+        """Delete entry corresponding to Network's VLAN in the DB."""
+
+        segments = context.network_segments
+        vlan_id = segments[0]['segmentation_id']
+
+        if vlan_id:
+            self.ucsm_db.delete_vlan_entry(vlan_id)
+
+    def delete_network_postcommit(self, context):
+        """Delete all configuration added to UCS Manager for the vlan_id."""
+
+        segments = context.network_segments
+        vlan_id = segments[0]['segmentation_id']
+        port_profile = self.make_profile_name(vlan_id)
+
+        if vlan_id:
+            self.driver.delete_all_config_for_vlan(vlan_id, port_profile)
+
+    def bind_port(self, context):
+        """Binds port to current network segment.
+
+        Binds port only if the vnic_type is direct or macvtap and
+        the port is from a supported vendor. While binding port set it
+        in ACTIVE state and provide the Port Profile or Vlan Id as part
+        vif_details.
+        """
+        vnic_type = context.current.get(portbindings.VNIC_TYPE,
+                                        portbindings.VNIC_NORMAL)
+
+        LOG.debug("Attempting to bind port %(port)s with vnic_type "
+                  "%(vnic_type)s on network %(network)s",
+                  {'port': context.current['id'],
+                   'vnic_type': vnic_type,
+                   'network': context.network.current['id']})
+
+        profile = context.current.get(portbindings.PROFILE, {})
+
+        if not self.driver.check_vnic_type_and_vendor_info(vnic_type,
+                                                           profile):
+            return
+
+        for segment in context.network.network_segments:
+            if self.check_segment(segment):
+                vlan_id = segment[api.SEGMENTATION_ID]
+
+                if not vlan_id:
+                    LOG.warn(_LW("Bind port: vlan_id is None."))
+                    return
+
+                LOG.debug("Port binding to Vlan_id: %s", str(vlan_id))
+
+                # Check if this is a Cisco VM-FEX port or Intel SR_IOV port
+                if self.driver.is_vmfex_port(profile):
+                    profile_name = self.make_profile_name(vlan_id)
+                    self.vif_details[
+                        const.VIF_DETAILS_PROFILEID] = profile_name
+                else:
+                    self.vif_details[
+                        portbindings.VIF_DETAILS_VLAN] = str(vlan_id)
+
+                context.set_binding(segment[api.ID],
+                                    self.vif_type,
+                                    self.vif_details,
+                                    constants.PORT_STATUS_ACTIVE)
+                return
+
+        LOG.error(_LE("UCS Mech Driver: Failed binding port ID %(id)s "
+                      "on any segment of network %(network)s"),
+                  {'id': context.current['id'],
+                   'network': context.network.current['id']})
+
+    @staticmethod
+    def check_segment(segment):
+        network_type = segment[api.NETWORK_TYPE]
+        return network_type == p_const.TYPE_VLAN
+
+    @staticmethod
+    def make_profile_name(vlan_id):
+        return const.PORT_PROFILE_NAME_PREFIX + str(vlan_id)
diff --git a/neutron/plugins/ml2/drivers/cisco/ucsm/ucsm_model.py b/neutron/plugins/ml2/drivers/cisco/ucsm/ucsm_model.py
new file mode 100644 (file)
index 0000000..05b1648
--- /dev/null
@@ -0,0 +1,29 @@
+# Copyright 2015 Cisco Systems, 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.
+
+import sqlalchemy as sa
+
+from neutron.db import model_base
+
+
+class PortProfile(model_base.BASEV2):
+
+    """Port profiles created on the UCS Manager."""
+
+    __tablename__ = 'ml2_ucsm_port_profiles'
+
+    vlan_id = sa.Column(sa.Integer(), nullable=False, primary_key=True)
+    profile_id = sa.Column(sa.String(64), nullable=False)
+    created_on_ucs = sa.Column(sa.Boolean(), nullable=False)
index 93a0b3a8124acc4a0413b01824a97a6fe85312f9..c5af580b5ef4aaefdfb93817f8873ff0d5f09a53 100644 (file)
--- a/setup.cfg
+++ b/setup.cfg
@@ -180,6 +180,7 @@ neutron.ml2.mechanism_drivers =
     cisco_nexus = neutron.plugins.ml2.drivers.cisco.nexus.mech_cisco_nexus:CiscoNexusMechanismDriver
     cisco_apic = neutron.plugins.ml2.drivers.cisco.apic.mechanism_apic:APICMechanismDriver
     cisco_n1kv = neutron.plugins.ml2.drivers.cisco.n1kv.mech_cisco_n1kv:N1KVMechanismDriver
+    cisco_ucsm = neutron.plugins.ml2.drivers.cisco.ucsm.mech_cisco_ucsm:CiscoUcsmMechanismDriver
     l2population = neutron.plugins.ml2.drivers.l2pop.mech_driver:L2populationMechanismDriver
     bigswitch = neutron.plugins.ml2.drivers.mech_bigswitch.driver:BigSwitchMechanismDriver
     ofagent = neutron.plugins.ml2.drivers.ofagent.driver:OfagentMechanismDriver