Cisco UCS Manager ML2 Mechanism Driver

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
This commit is contained in:
Sandhya Dasu 2015-02-05 12:21:05 -05:00
parent 81ac74359c
commit c96b4f0f6e
8 changed files with 309 additions and 15 deletions

View File

@ -207,20 +207,6 @@
# 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]
@ -259,3 +245,22 @@
# 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

View File

@ -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')
)

View File

@ -1 +1 @@
589f9237ca0e
20b99fd19d4f

View 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

View File

@ -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)

View File

@ -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)

View File

@ -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