]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Cisco Nexus1000V ML2 Mechanism Driver
authorAbhishek Raut <abhraut@cisco.com>
Thu, 19 Feb 2015 02:37:29 +0000 (18:37 -0800)
committerSandhya Dasu <sadasu@cisco.com>
Wed, 25 Mar 2015 16:57:04 +0000 (16:57 +0000)
Introduces the Cisco Nexus1000V Mechanism driver for ML2 plugin.
All the vendor specific code resides in stackforge repo networking-cisco.

Closes-Bug: #1425632
Partial-Implements: blueprint core-vendor-decomposition

Change-Id: I66bf83f45bf1e0269d0876196f6aa032b0fa859f
Co-Authored-By: Steven Hillman <sthillma@cisco.com>
12 files changed:
etc/neutron/plugins/ml2/ml2_conf_cisco.ini
neutron/db/migration/alembic_migrations/versions/589f9237ca0e_cisco_n1kv_ml2_driver_tables.py [new file with mode: 0644]
neutron/db/migration/alembic_migrations/versions/HEAD
neutron/db/migration/models/head.py
neutron/plugins/ml2/drivers/cisco/n1kv/__init__.py [new file with mode: 0644]
neutron/plugins/ml2/drivers/cisco/n1kv/extensions/__init__.py [new file with mode: 0644]
neutron/plugins/ml2/drivers/cisco/n1kv/extensions/n1kv.py [new file with mode: 0644]
neutron/plugins/ml2/drivers/cisco/n1kv/mech_cisco_n1kv.py [new file with mode: 0644]
neutron/plugins/ml2/drivers/cisco/n1kv/n1kv_ext_driver.py [new file with mode: 0644]
neutron/plugins/ml2/drivers/cisco/n1kv/n1kv_models.py [new file with mode: 0644]
neutron/plugins/ml2/drivers/cisco/requirements.txt [new file with mode: 0644]
setup.cfg

index e7a09af1083fb1f2310ab36dbd38ab86bdda3a1d..cb88d88bf3bcc4e4b17913df322fc6a30372a405 100644 (file)
 # 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]
+
+# (StrOpt) Name of the policy profile to be associated with a port when no
+# policy profile is specified during port creates.
+# default_policy_profile = default-pp
+
+# (StrOpt) Name of the VLAN network profile to be associated with a network.
+# default_vlan_network_profile = default-vlan-np
+
+# (StrOpt) Name of the VXLAN network profile to be associated with a network.
+# default_vxlan_network_profile = default-vxlan-np
+
+# (IntOpt) Time in seconds for which the plugin polls the VSM for updates in
+# policy profiles.
+# poll_duration = 60
+
+# (IntOpt) Timeout duration in seconds for the http request
+# http_timeout = 15
+
+# (BoolOpt) Specify whether tenants are restricted from accessing all the
+# policy profiles.
+# Default value: False, indicating all tenants can access all policy profiles.
+#
+# restrict_policy_profiles = False
+
+# Describe Cisco N1KV VSM connectivity
+# In this section you can specify connectivity details in order for plugin
+# to connect to N1KV Virtual Supervisor Module (VSM).
+#
+# n1kv_vsm_ips =<vsm1_ip>,<vsm2_ip>,....
+# username = <username>
+# password = <password>
+#
+# An example would be:
+# n1kv_vsm_ips = 1.1.1.1,1.1.1.2
+# username = user
+# password = password
diff --git a/neutron/db/migration/alembic_migrations/versions/589f9237ca0e_cisco_n1kv_ml2_driver_tables.py b/neutron/db/migration/alembic_migrations/versions/589f9237ca0e_cisco_n1kv_ml2_driver_tables.py
new file mode 100644 (file)
index 0000000..6c091ce
--- /dev/null
@@ -0,0 +1,114 @@
+# Copyright 2015 Cisco Systems, Inc.
+#
+#    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 N1kv ML2 driver tables
+
+Revision ID: 589f9237ca0e
+Revises: 51c54792158e
+Create Date: 2014-08-13 13:31:43.537460
+
+"""
+
+# revision identifiers, used by Alembic.
+revision = '589f9237ca0e'
+down_revision = '51c54792158e'
+
+
+from alembic import op
+import sqlalchemy as sa
+
+network_profile_type = sa.Enum('vlan', 'vxlan',
+                               name='network_profile_type')
+profile_type = sa.Enum('network', 'policy', name='profile_type')
+
+
+def upgrade():
+
+    op.create_table(
+        'cisco_ml2_n1kv_policy_profiles',
+        sa.Column('id', sa.String(length=36), nullable=False),
+        sa.Column('name', sa.String(length=255), nullable=False),
+        sa.Column('vsm_ip', sa.String(length=16), nullable=False),
+        sa.PrimaryKeyConstraint('id', 'vsm_ip'),
+    )
+
+    op.create_table(
+        'cisco_ml2_n1kv_network_profiles',
+        sa.Column('id', sa.String(length=36), nullable=False),
+        sa.Column('name', sa.String(length=255), nullable=False),
+        sa.Column('segment_type', network_profile_type, nullable=False),
+        sa.Column('segment_range', sa.String(length=255), nullable=True),
+        sa.Column('multicast_ip_index', sa.Integer(), nullable=True),
+        sa.Column('multicast_ip_range', sa.String(length=255), nullable=True),
+        sa.Column('sub_type', sa.String(length=255), nullable=True),
+        sa.Column('physical_network', sa.String(length=255), nullable=True),
+        sa.PrimaryKeyConstraint('id'),
+    )
+
+    op.create_table(
+        'cisco_ml2_n1kv_port_bindings',
+        sa.Column('port_id', sa.String(length=36), nullable=False),
+        sa.Column('profile_id', sa.String(length=36), nullable=False),
+        sa.ForeignKeyConstraint(['port_id'], ['ports.id'], ondelete='CASCADE'),
+        sa.PrimaryKeyConstraint('port_id'),
+    )
+
+    op.create_table(
+        'cisco_ml2_n1kv_network_bindings',
+        sa.Column('network_id', sa.String(length=36), nullable=False),
+        sa.Column('network_type', sa.String(length=32), nullable=False),
+        sa.Column('segmentation_id', sa.Integer(), autoincrement=False),
+        sa.Column('profile_id', sa.String(length=36), nullable=False),
+        sa.ForeignKeyConstraint(['network_id'], ['networks.id'],
+                                ondelete='CASCADE'),
+        sa.ForeignKeyConstraint(['profile_id'],
+                                ['cisco_ml2_n1kv_network_profiles.id']),
+        sa.PrimaryKeyConstraint('network_id')
+    )
+
+    op.create_table(
+        'cisco_ml2_n1kv_vxlan_allocations',
+        sa.Column('vxlan_id', sa.Integer(), autoincrement=False,
+                  nullable=False),
+        sa.Column('allocated', sa.Boolean(), nullable=False),
+        sa.Column('network_profile_id', sa.String(length=36), nullable=False),
+        sa.ForeignKeyConstraint(['network_profile_id'],
+                                ['cisco_ml2_n1kv_network_profiles.id'],
+                                ondelete='CASCADE'),
+        sa.PrimaryKeyConstraint('vxlan_id')
+    )
+
+    op.create_table(
+        'cisco_ml2_n1kv_vlan_allocations',
+        sa.Column('physical_network', sa.String(length=64), nullable=False),
+        sa.Column('vlan_id', sa.Integer(), autoincrement=False,
+                  nullable=False),
+        sa.Column('allocated', sa.Boolean(), autoincrement=False,
+                  nullable=False),
+        sa.Column('network_profile_id', sa.String(length=36), nullable=False),
+        sa.ForeignKeyConstraint(['network_profile_id'],
+                                ['cisco_ml2_n1kv_network_profiles.id'],
+                                ondelete='CASCADE'),
+        sa.PrimaryKeyConstraint('physical_network', 'vlan_id')
+    )
+
+    op.create_table(
+        'cisco_ml2_n1kv_profile_bindings',
+        sa.Column('profile_type', profile_type, nullable=True),
+        sa.Column('tenant_id', sa.String(length=36), nullable=False,
+                  server_default='tenant_id_not_set'),
+        sa.Column('profile_id', sa.String(length=36), nullable=False),
+        sa.PrimaryKeyConstraint('tenant_id', 'profile_id')
+    )
index a5f702c7f6432d40504f3eb3f5faa8996078c186..d21c061a43b553fa07972664d3676aa610d2a0bf 100644 (file)
@@ -1 +1 @@
-51c54792158e
+589f9237ca0e
index c63304f0a6cfeb5b2c92a4d0de2bf633a861302c..407c5b08902539155b9ce7e84ed25b2519f6c3a6 100644 (file)
@@ -54,6 +54,7 @@ from neutron.plugins.ml2.drivers.arista import db  # noqa
 from neutron.plugins.ml2.drivers.brocade.db import (  # noqa
     models as ml2_brocade_models)
 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 import type_flat  # noqa
diff --git a/neutron/plugins/ml2/drivers/cisco/n1kv/__init__.py b/neutron/plugins/ml2/drivers/cisco/n1kv/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/neutron/plugins/ml2/drivers/cisco/n1kv/extensions/__init__.py b/neutron/plugins/ml2/drivers/cisco/n1kv/extensions/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/neutron/plugins/ml2/drivers/cisco/n1kv/extensions/n1kv.py b/neutron/plugins/ml2/drivers/cisco/n1kv/extensions/n1kv.py
new file mode 100644 (file)
index 0000000..7cd4f8c
--- /dev/null
@@ -0,0 +1,57 @@
+# Copyright 2014 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.n1kv import constants
+
+from neutron.api import extensions
+from neutron.api.v2 import attributes
+
+
+PROFILE = constants.N1KV_PROFILE
+EXTENDED_ATTRIBUTES_2_0 = {
+    'ports': {PROFILE: {
+        'allow_post': True,
+        'allow_put': False,
+        'default': attributes.ATTR_NOT_SPECIFIED,
+        'is_visible': True}}}
+
+
+class N1kv(extensions.ExtensionDescriptor):
+
+    @classmethod
+    def get_name(cls):
+        return "Cisco Nexus1000V Profile Extension"
+
+    @classmethod
+    def get_alias(cls):
+        return "n1kv"
+
+    @classmethod
+    def get_description(cls):
+        return _("Add new policy profile attribute to port resource.")
+
+    @classmethod
+    def get_namespace(cls):
+        return "http://docs.openstack.org/ext/neutron/n1kv/api/v2.0"
+
+    @classmethod
+    def get_updated(cls):
+        return "2014-11-23T13:33:25-00:00"
+
+    def get_extended_resources(self, version):
+        if version == "2.0":
+            return EXTENDED_ATTRIBUTES_2_0
+        else:
+            return {}
diff --git a/neutron/plugins/ml2/drivers/cisco/n1kv/mech_cisco_n1kv.py b/neutron/plugins/ml2/drivers/cisco/n1kv/mech_cisco_n1kv.py
new file mode 100644 (file)
index 0000000..04e83a7
--- /dev/null
@@ -0,0 +1,24 @@
+# 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.
+
+"""
+ML2 Mechanism Driver for Cisco Nexus1000V distributed virtual switches.
+"""
+
+from networking_cisco.plugins.ml2.drivers.cisco.n1kv import mech_cisco_n1kv
+
+
+class N1KVMechanismDriver(mech_cisco_n1kv.N1KVMechanismDriver):
+    pass
diff --git a/neutron/plugins/ml2/drivers/cisco/n1kv/n1kv_ext_driver.py b/neutron/plugins/ml2/drivers/cisco/n1kv/n1kv_ext_driver.py
new file mode 100644 (file)
index 0000000..eb118c9
--- /dev/null
@@ -0,0 +1,101 @@
+# 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.
+
+"""Extensions Driver for Cisco Nexus1000V."""
+
+from oslo_config import cfg
+from oslo_log import log
+
+from networking_cisco.plugins.ml2.drivers.cisco.n1kv import (
+    constants)
+from networking_cisco.plugins.ml2.drivers.cisco.n1kv import (
+    exceptions as n1kv_exc)
+from networking_cisco.plugins.ml2.drivers.cisco.n1kv import (
+    n1kv_db)
+
+from neutron.api import extensions as api_extensions
+from neutron.api.v2 import attributes
+from neutron.i18n import _LE
+from neutron.openstack.common import uuidutils
+from neutron.plugins.ml2.common import exceptions as ml2_exc
+from neutron.plugins.ml2 import driver_api as api
+from neutron.plugins.ml2.drivers.cisco.n1kv import extensions
+
+LOG = log.getLogger(__name__)
+
+
+class CiscoN1kvExtensionDriver(api.ExtensionDriver):
+    """Cisco N1KV ML2 Extension Driver."""
+
+    # List of supported extensions for cisco Nexus1000V.
+    _supported_extension_alias = "n1kv"
+
+    def initialize(self):
+        api_extensions.append_api_extensions_path(extensions.__path__)
+
+    @property
+    def extension_alias(self):
+        """
+        Supported extension alias.
+
+        :returns: alias identifying the core API extension supported
+                  by this driver
+        """
+        return self._supported_extension_alias
+
+    def process_create_port(self, context, data, result):
+        """Implementation of abstract method from ExtensionDriver class."""
+        port_id = result.get('id')
+        policy_profile_attr = data.get(constants.N1KV_PROFILE)
+        if not attributes.is_attr_set(policy_profile_attr):
+            policy_profile_attr = (cfg.CONF.ml2_cisco_n1kv.
+                                   default_policy_profile)
+        with context.session.begin(subtransactions=True):
+            try:
+                n1kv_db.get_policy_binding(port_id, context.session)
+            except n1kv_exc.PortBindingNotFound:
+                if not uuidutils.is_uuid_like(policy_profile_attr):
+                    policy_profile = n1kv_db.get_policy_profile_by_name(
+                        policy_profile_attr,
+                        context.session)
+                    if policy_profile:
+                        policy_profile_attr = policy_profile.id
+                    else:
+                        LOG.error(_LE("Policy Profile %(profile)s does "
+                                      "not exist."),
+                                  {"profile": policy_profile_attr})
+                        raise ml2_exc.MechanismDriverError()
+                elif not (n1kv_db.get_policy_profile_by_uuid(
+                             context.session,
+                             policy_profile_attr)):
+                    LOG.error(_LE("Policy Profile %(profile)s does not "
+                                  "exist."),
+                              {"profile": policy_profile_attr})
+                    raise ml2_exc.MechanismDriverError()
+                n1kv_db.add_policy_binding(port_id,
+                                           policy_profile_attr,
+                                           context.session)
+        result[constants.N1KV_PROFILE] = policy_profile_attr
+
+    def extend_port_dict(self, session, model, result):
+        """Implementation of abstract method from ExtensionDriver class."""
+        port_id = result.get('id')
+        with session.begin(subtransactions=True):
+            try:
+                res = n1kv_db.get_policy_binding(port_id, session)
+                result[constants.N1KV_PROFILE] = res.profile_id
+            except n1kv_exc.PortBindingNotFound:
+                # Do nothing if the port binding is not found.
+                pass
diff --git a/neutron/plugins/ml2/drivers/cisco/n1kv/n1kv_models.py b/neutron/plugins/ml2/drivers/cisco/n1kv/n1kv_models.py
new file mode 100644 (file)
index 0000000..bfbbb51
--- /dev/null
@@ -0,0 +1,138 @@
+# 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 sqlalchemy import orm
+
+from neutron.db import model_base
+from neutron.db import models_v2
+from neutron.plugins.common import constants
+
+
+class PolicyProfile(model_base.BASEV2):
+
+    """
+    Nexus1000V Policy Profiles
+
+    Both 'profile_id' and 'name' are populated from Nexus1000V switch.
+    """
+    __tablename__ = 'cisco_ml2_n1kv_policy_profiles'
+
+    id = sa.Column(sa.String(36), nullable=False, primary_key=True)
+    name = sa.Column(sa.String(255), nullable=False)
+    vsm_ip = sa.Column(sa.String(16), nullable=False, primary_key=True)
+
+
+class NetworkProfile(model_base.BASEV2, models_v2.HasId):
+
+    """Nexus1000V Network Profiles created on the VSM."""
+    __tablename__ = 'cisco_ml2_n1kv_network_profiles'
+
+    name = sa.Column(sa.String(255), nullable=False)
+    segment_type = sa.Column(sa.Enum(constants.TYPE_VLAN,
+                                     constants.TYPE_VXLAN,
+                                     name='segment_type'),
+                             nullable=False)
+    sub_type = sa.Column(sa.String(255))
+    segment_range = sa.Column(sa.String(255))
+    multicast_ip_index = sa.Column(sa.Integer, default=0)
+    multicast_ip_range = sa.Column(sa.String(255))
+    physical_network = sa.Column(sa.String(255))
+
+
+class N1kvPortBinding(model_base.BASEV2):
+
+    """Represents binding of ports to policy profile."""
+    __tablename__ = 'cisco_ml2_n1kv_port_bindings'
+
+    port_id = sa.Column(sa.String(36),
+                        sa.ForeignKey('ports.id', ondelete="CASCADE"),
+                        primary_key=True)
+    profile_id = sa.Column(sa.String(36),
+                           nullable=False)
+    # Add a relationship to the Port model in order to instruct SQLAlchemy to
+    # eagerly load port bindings
+    port = orm.relationship(
+        models_v2.Port,
+        backref=orm.backref("n1kv_port_binding",
+                            lazy='joined', uselist=False,
+                            cascade='delete'))
+
+
+class N1kvNetworkBinding(model_base.BASEV2):
+
+    """Represents binding of virtual network to network profiles."""
+    __tablename__ = 'cisco_ml2_n1kv_network_bindings'
+
+    network_id = sa.Column(sa.String(36),
+                           sa.ForeignKey('networks.id', ondelete="CASCADE"),
+                           primary_key=True)
+    network_type = sa.Column(sa.String(32), nullable=False)
+    segmentation_id = sa.Column(sa.Integer)
+    profile_id = sa.Column(sa.String(36),
+                           sa.ForeignKey('cisco_ml2_n1kv_network_profiles.id'),
+                           nullable=False)
+
+
+class N1kvVlanAllocation(model_base.BASEV2):
+
+    """Represents allocation state of vlan_id on physical network."""
+    __tablename__ = 'cisco_ml2_n1kv_vlan_allocations'
+
+    physical_network = sa.Column(sa.String(64),
+                                 nullable=False,
+                                 primary_key=True)
+    vlan_id = sa.Column(sa.Integer, nullable=False, primary_key=True,
+                        autoincrement=False)
+    allocated = sa.Column(sa.Boolean, nullable=False, default=False)
+    network_profile_id = sa.Column(sa.String(36),
+                                   sa.ForeignKey(
+                                      'cisco_ml2_n1kv_network_profiles.id',
+                                      ondelete="CASCADE"),
+                                   nullable=False)
+
+
+class N1kvVxlanAllocation(model_base.BASEV2):
+
+    """Represents allocation state of vxlan_id."""
+    __tablename__ = 'cisco_ml2_n1kv_vxlan_allocations'
+
+    vxlan_id = sa.Column(sa.Integer, nullable=False, primary_key=True,
+                         autoincrement=False)
+    allocated = sa.Column(sa.Boolean, nullable=False, default=False)
+    network_profile_id = sa.Column(sa.String(36),
+                                   sa.ForeignKey(
+                                       'cisco_ml2_n1kv_network_profiles.id',
+                                       ondelete="CASCADE"),
+                                   nullable=False)
+
+
+class ProfileBinding(model_base.BASEV2):
+
+    """
+    Represents a binding of Network Profile
+    or Policy Profile to tenant_id
+    """
+    __tablename__ = 'cisco_ml2_n1kv_profile_bindings'
+
+    profile_type = sa.Column(sa.Enum('network', 'policy',
+                                     name='profile_type'),
+                             nullable=True)
+    tenant_id = sa.Column(sa.String(36),
+                          primary_key=True,
+                          nullable=False,
+                          default='tenant_id_not_set',
+                          server_default='tenant_id_not_set')
+    profile_id = sa.Column(sa.String(36), primary_key=True, nullable=False)
diff --git a/neutron/plugins/ml2/drivers/cisco/requirements.txt b/neutron/plugins/ml2/drivers/cisco/requirements.txt
new file mode 100644 (file)
index 0000000..ef631a3
--- /dev/null
@@ -0,0 +1 @@
+networking-cisco
index b3d8824c824b29deaf132260693656c9d5559cef..93a0b3a8124acc4a0413b01824a97a6fe85312f9 100644 (file)
--- a/setup.cfg
+++ b/setup.cfg
@@ -179,6 +179,7 @@ neutron.ml2.mechanism_drivers =
     cisco_ncs = neutron.plugins.ml2.drivers.cisco.ncs.driver:NCSMechanismDriver
     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
     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
@@ -194,6 +195,7 @@ neutron.ml2.extension_drivers =
     test = neutron.tests.unit.ml2.drivers.ext_test:TestExtensionDriver
     testdb = neutron.tests.unit.ml2.drivers.ext_test:TestDBExtensionDriver
     port_security = neutron.plugins.ml2.extensions.port_security:PortSecurityExtensionDriver
+    cisco_n1kv_ext = neutron.plugins.ml2.drivers.cisco.n1kv.n1kv_ext_driver:CiscoN1kvExtensionDriver
 neutron.openstack.common.cache.backends =
     memory = neutron.openstack.common.cache._backends.memory:MemoryBackend
 # These are for backwards compat with Icehouse notification_driver configuration values