Remove mlnx plugin

Mellanox plugin was marked deprecated in Juno.
This commit actually removes the code for Kilo.

Mellanox recommends users to use mlnx or SR-IOV MD

DocImpact
Closes-Bug: #1386539

Change-Id: I7d109bf62f71b2996aef4e0002f447ca3439a5cf
Signed-off-by: Moshe Levi <moshele@mellanox.com>
This commit is contained in:
Moshe Levi 2014-12-09 10:38:24 +02:00
parent b4a0fa3c34
commit 3f8c8abd0a
20 changed files with 80 additions and 1807 deletions

View File

@ -1,38 +1,3 @@
[mlnx]
# (StrOpt) Type of network to allocate for tenant networks. The
# default value is 'vlan' You MUST configure network_vlan_ranges below
# in order for tenant networks to provide connectivity between hosts.
# Set to 'none' to disable creation of tenant networks.
#
# tenant_network_type = vlan
# Example: tenant_network_type = vlan
# (ListOpt) Comma-separated list of
# <physical_network>[:<vlan_min>:<vlan_max>] tuples enumerating ranges
# of VLAN IDs on named physical networks that are available for
# allocation. All physical networks listed are available for flat and
# VLAN provider network creation. Specified ranges of VLAN IDs are
# available for tenant network allocation if tenant_network_type is
# 'vlan'. If empty, only local networks may be created.
#
# network_vlan_ranges =
# Example: network_vlan_ranges = default:1:100
# (ListOpt) Comma-separated list of
# <physical_network>:<physical_network_type> tuples mapping physical
# network names to physical network types. All physical
# networks listed in network_vlan_ranges should have
# mappings to appropriate physical network type.
# Type of the physical network can be either eth (Ethernet) or
# ib (InfiniBand). If empty, physical network eth type is assumed.
#
# physical_network_type_mappings =
# Example: physical_network_type_mappings = default:eth
# (StrOpt) Type of the physical network, can be either 'eth' or 'ib'
# The default value is 'eth'
# physical_network_type = eth
[eswitch]
# (ListOpt) Comma-separated list of
# <physical_network>:<physical_interface> tuples mapping physical
@ -67,13 +32,3 @@
[agent]
# Agent's polling interval in seconds
# polling_interval = 2
# (BoolOpt) Enable server RPC compatibility with old (pre-havana)
# agents.
#
# rpc_support_old_agents = False
[securitygroup]
# Controls if neutron security group is enabled or not.
# It should be false when you use nova security group.
# enable_security_group = True

View File

@ -0,0 +1,75 @@
# Copyright 2014 OpenStack Foundation
#
# 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.
#
"""remove mlnx plugin
Revision ID: 28c0ffb8ebbd
Revises: 408cfbf6923c
Create Date: 2014-12-08 23:58:49.288830
"""
# revision identifiers, used by Alembic.
revision = '28c0ffb8ebbd'
down_revision = '408cfbf6923c'
from alembic import op
import sqlalchemy as sa
def upgrade():
op.drop_table('mlnx_network_bindings')
op.drop_table('segmentation_id_allocation')
op.drop_table('port_profile')
def downgrade():
op.create_table(
'port_profile',
sa.Column(
'port_id', sa.String(length=36), nullable=False),
sa.Column(
'vnic_type', sa.String(length=32), nullable=False),
sa.ForeignKeyConstraint(['port_id'], ['ports.id'],
ondelete='CASCADE'),
sa.PrimaryKeyConstraint('port_id'),
)
op.create_table(
'segmentation_id_allocation',
sa.Column('physical_network',
sa.String(length=64),
nullable=False),
sa.Column('segmentation_id',
sa.Integer(),
autoincrement=False,
nullable=False),
sa.Column('allocated',
sa.Boolean(),
server_default=sa.sql.false(),
nullable=False),
sa.PrimaryKeyConstraint('physical_network', 'segmentation_id')
)
op.create_table(
'mlnx_network_bindings',
sa.Column('network_id', sa.String(length=36), nullable=False),
sa.Column('network_type', sa.String(length=32), nullable=False),
sa.Column('physical_network', sa.String(length=64), nullable=True),
sa.Column('segmentation_id',
sa.Integer(),
autoincrement=False, nullable=False),
sa.ForeignKeyConstraint(['network_id'],
['networks.id']),
sa.PrimaryKeyConstraint('network_id'),
)

View File

@ -1 +1 @@
408cfbf6923c
28c0ffb8ebbd

View File

@ -64,7 +64,6 @@ from neutron.plugins.ml2.drivers import type_gre # noqa
from neutron.plugins.ml2.drivers import type_vlan # noqa
from neutron.plugins.ml2.drivers import type_vxlan # noqa
from neutron.plugins.ml2 import models # noqa
from neutron.plugins.mlnx.db import mlnx_models_v2 # noqa
from neutron.plugins.nec.db import models as nec_models # noqa
from neutron.plugins.nec.db import packetfilter as nec_packetfilter # noqa
from neutron.plugins.nec.db import router # noqa

View File

@ -1,8 +1,4 @@
Mellanox Neutron Plugin
This plugin implements Neutron v2 APIs with support for
Mellanox embedded switch functionality as part of the
VPI (Ethernet/InfiniBand) HCA.
For more details on the plugin, please refer to the following link:
https://wiki.openstack.org/wiki/Mellanox-Quantum
The Neutron Mellanox plugin has removed from the tree in Kilo.
This directory includes Mellanox L2 agent for MLNX mechanism driver.
For more details, please refer to the following link:
https://wiki.openstack.org/wiki/Mellanox-Neutron-ML2

View File

@ -1,62 +0,0 @@
# Copyright 2013 Mellanox Technologies, Ltd
#
# 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 oslo.config import cfg
from oslo import messaging
from neutron.agent import securitygroups_rpc as sg_rpc
from neutron.common import rpc as n_rpc
from neutron.common import topics
from neutron.openstack.common import log as logging
LOG = logging.getLogger(__name__)
class AgentNotifierApi(sg_rpc.SecurityGroupAgentRpcApiMixin):
"""Agent side of the Embedded Switch RPC API.
API version history:
1.0 - Initial version.
1.1 - Added get_active_networks_info, create_dhcp_port,
and update_dhcp_port methods.
"""
def __init__(self, topic):
self.topic = topic
self.topic_network_delete = topics.get_topic_name(topic,
topics.NETWORK,
topics.DELETE)
self.topic_port_update = topics.get_topic_name(topic,
topics.PORT,
topics.UPDATE)
target = messaging.Target(topic=topic, version='1.0')
self.client = n_rpc.get_client(target)
def network_delete(self, context, network_id):
LOG.debug("Sending delete network message")
cctxt = self.client.prepare(topic=self.topic_network_delete,
fanout=True)
cctxt.cast(context, 'network_delete', network_id=network_id)
def port_update(self, context, port, physical_network,
network_type, vlan_id):
LOG.debug("Sending update port message")
kwargs = {'port': port,
'network_type': network_type,
'physical_network': physical_network,
'segmentation_id': vlan_id}
if cfg.CONF.AGENT.rpc_support_old_agents:
kwargs['vlan_id'] = vlan_id
cctxt = self.client.prepare(topic=self.topic_port_update, fanout=True)
cctxt.cast(context, 'port_update', **kwargs)

View File

@ -18,27 +18,8 @@ from oslo.config import cfg
from neutron.agent.common import config
from neutron.plugins.mlnx.common import constants
DEFAULT_VLAN_RANGES = ['default:1:1000']
DEFAULT_INTERFACE_MAPPINGS = []
vlan_opts = [
cfg.StrOpt('tenant_network_type', default='vlan',
help=_("Network type for tenant networks "
"(local, vlan, or none)")),
cfg.ListOpt('network_vlan_ranges',
default=DEFAULT_VLAN_RANGES,
help=_("List of <physical_network>:<vlan_min>:<vlan_max> "
"or <physical_network>")),
cfg.ListOpt('physical_network_type_mappings',
default=[],
help=_("List of <physical_network>:<physical_network_type> "
" with physical_network_type is either eth or ib")),
cfg.StrOpt('physical_network_type', default='eth',
help=_("Physical network type for provider network "
"(eth or ib)"))
]
eswitch_opts = [
cfg.ListOpt('physical_interface_mappings',
default=DEFAULT_INTERFACE_MAPPINGS,
@ -66,12 +47,9 @@ agent_opts = [
cfg.IntOpt('polling_interval', default=2,
help=_("The number of seconds the agent will wait between "
"polling for local device changes.")),
cfg.BoolOpt('rpc_support_old_agents', default=False,
help=_("Enable server RPC compatibility with old agents")),
]
cfg.CONF.register_opts(vlan_opts, "MLNX")
cfg.CONF.register_opts(eswitch_opts, "ESWITCH")
cfg.CONF.register_opts(agent_opts, "AGENT")
config.register_agent_state_opts_helper(cfg.CONF)

View File

@ -1,256 +0,0 @@
# Copyright 2013 Mellanox Technologies, Ltd
#
# 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 six import moves
from sqlalchemy.orm import exc
from neutron.common import exceptions as n_exc
import neutron.db.api as db
from neutron.db import models_v2
from neutron.db import securitygroups_db as sg_db
from neutron.i18n import _LW
from neutron import manager
from neutron.openstack.common import log as logging
from neutron.plugins.mlnx.common import config # noqa
from neutron.plugins.mlnx.db import mlnx_models_v2
LOG = logging.getLogger(__name__)
def _remove_non_allocatable_vlans(session, allocations,
physical_network, vlan_ids):
if physical_network in allocations:
for entry in allocations[physical_network]:
try:
# see if vlan is allocatable
vlan_ids.remove(entry.segmentation_id)
except KeyError:
# it's not allocatable, so check if its allocated
if not entry.allocated:
# it's not, so remove it from table
LOG.debug(
"Removing vlan %(seg_id)s on "
"physical network "
"%(net)s from pool",
{'seg_id': entry.segmentation_id,
'net': physical_network})
session.delete(entry)
del allocations[physical_network]
def _add_missing_allocatable_vlans(session, physical_network, vlan_ids):
for vlan_id in sorted(vlan_ids):
entry = mlnx_models_v2.SegmentationIdAllocation(physical_network,
vlan_id)
session.add(entry)
def _remove_unconfigured_vlans(session, allocations):
for entries in allocations.itervalues():
for entry in entries:
if not entry.allocated:
LOG.debug("Removing vlan %(seg_id)s on physical "
"network %(net)s from pool",
{'seg_id': entry.segmentation_id,
'net': entry.physical_network})
session.delete(entry)
def sync_network_states(network_vlan_ranges):
"""Synchronize network_states table with current configured VLAN ranges."""
session = db.get_session()
with session.begin():
# get existing allocations for all physical networks
allocations = dict()
entries = (session.query(mlnx_models_v2.SegmentationIdAllocation).
all())
for entry in entries:
allocations.setdefault(entry.physical_network, set()).add(entry)
# process vlan ranges for each configured physical network
for physical_network, vlan_ranges in network_vlan_ranges.iteritems():
# determine current configured allocatable vlans for this
# physical network
vlan_ids = set()
for vlan_range in vlan_ranges:
vlan_ids |= set(moves.xrange(vlan_range[0], vlan_range[1] + 1))
# remove from table unallocated vlans not currently allocatable
_remove_non_allocatable_vlans(session, allocations,
physical_network, vlan_ids)
# add missing allocatable vlans to table
_add_missing_allocatable_vlans(session, physical_network, vlan_ids)
# remove from table unallocated vlans for any unconfigured physical
# networks
_remove_unconfigured_vlans(session, allocations)
def get_network_state(physical_network, segmentation_id):
"""Get entry of specified network."""
session = db.get_session()
qry = session.query(mlnx_models_v2.SegmentationIdAllocation)
qry = qry.filter_by(physical_network=physical_network,
segmentation_id=segmentation_id)
return qry.first()
def reserve_network(session):
with session.begin(subtransactions=True):
entry = (session.query(mlnx_models_v2.SegmentationIdAllocation).
filter_by(allocated=False).
with_lockmode('update').
first())
if not entry:
raise n_exc.NoNetworkAvailable()
LOG.debug("Reserving vlan %(seg_id)s on physical network "
"%(net)s from pool",
{'seg_id': entry.segmentation_id,
'net': entry.physical_network})
entry.allocated = True
return (entry.physical_network, entry.segmentation_id)
def reserve_specific_network(session, physical_network, segmentation_id):
with session.begin(subtransactions=True):
log_args = {'seg_id': segmentation_id, 'phy_net': physical_network}
try:
entry = (session.query(mlnx_models_v2.SegmentationIdAllocation).
filter_by(physical_network=physical_network,
segmentation_id=segmentation_id).
with_lockmode('update').one())
if entry.allocated:
raise n_exc.VlanIdInUse(vlan_id=segmentation_id,
physical_network=physical_network)
LOG.debug("Reserving specific vlan %(seg_id)s "
"on physical network %(phy_net)s from pool",
log_args)
entry.allocated = True
except exc.NoResultFound:
LOG.debug("Reserving specific vlan %(seg_id)s on "
"physical network %(phy_net)s outside pool",
log_args)
entry = mlnx_models_v2.SegmentationIdAllocation(physical_network,
segmentation_id)
entry.allocated = True
session.add(entry)
def release_network(session, physical_network,
segmentation_id, network_vlan_ranges):
with session.begin(subtransactions=True):
log_args = {'seg_id': segmentation_id, 'phy_net': physical_network}
try:
state = (session.query(mlnx_models_v2.SegmentationIdAllocation).
filter_by(physical_network=physical_network,
segmentation_id=segmentation_id).
with_lockmode('update').
one())
state.allocated = False
inside = False
for vlan_range in network_vlan_ranges.get(physical_network, []):
if (segmentation_id >= vlan_range[0] and
segmentation_id <= vlan_range[1]):
inside = True
break
if inside:
LOG.debug("Releasing vlan %(seg_id)s "
"on physical network "
"%(phy_net)s to pool",
log_args)
else:
LOG.debug("Releasing vlan %(seg_id)s "
"on physical network "
"%(phy_net)s outside pool",
log_args)
session.delete(state)
except exc.NoResultFound:
LOG.warning(_LW("vlan_id %(seg_id)s on physical network "
"%(phy_net)s not found"),
log_args)
def add_network_binding(session, network_id, network_type,
physical_network, vlan_id):
with session.begin(subtransactions=True):
binding = mlnx_models_v2.NetworkBinding(network_id, network_type,
physical_network, vlan_id)
session.add(binding)
def get_network_binding(session, network_id):
return (session.query(mlnx_models_v2.NetworkBinding).
filter_by(network_id=network_id).first())
def add_port_profile_binding(session, port_id, vnic_type):
with session.begin(subtransactions=True):
binding = mlnx_models_v2.PortProfileBinding(port_id, vnic_type)
session.add(binding)
def get_port_profile_binding(session, port_id):
return (session.query(mlnx_models_v2.PortProfileBinding).
filter_by(port_id=port_id).first())
def get_port_from_device(device):
"""Get port from database."""
LOG.debug("get_port_from_device() called")
session = db.get_session()
sg_binding_port = sg_db.SecurityGroupPortBinding.port_id
query = session.query(models_v2.Port,
sg_db.SecurityGroupPortBinding.security_group_id)
query = query.outerjoin(sg_db.SecurityGroupPortBinding,
models_v2.Port.id == sg_binding_port)
query = query.filter(models_v2.Port.id.startswith(device))
port_and_sgs = query.all()
if not port_and_sgs:
return
port = port_and_sgs[0][0]
plugin = manager.NeutronManager.get_plugin()
port_dict = plugin._make_port_dict(port)
port_dict['security_groups'] = [
sg_id for port_in_db, sg_id in port_and_sgs if sg_id
]
port_dict['security_group_rules'] = []
port_dict['security_group_source_groups'] = []
port_dict['fixed_ips'] = [ip['ip_address']
for ip in port['fixed_ips']]
return port_dict
def get_port_from_device_mac(device_mac):
"""Get port from database."""
LOG.debug("Get_port_from_device_mac() called")
session = db.get_session()
qry = session.query(models_v2.Port).filter_by(mac_address=device_mac)
return qry.first()
def set_port_status(port_id, status):
"""Set the port status."""
LOG.debug("Set_port_status as %s called", status)
session = db.get_session()
try:
port = session.query(models_v2.Port).filter_by(id=port_id).one()
port['status'] = status
session.merge(port)
session.flush()
except exc.NoResultFound:
raise n_exc.PortNotFound(port_id=port_id)

View File

@ -1,86 +0,0 @@
# Copyright 2013 Mellanox Technologies, Ltd
#
# 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 sql
from neutron.db import model_base
class SegmentationIdAllocation(model_base.BASEV2):
"""Represents allocation state of segmentation_id on physical network."""
__tablename__ = 'segmentation_id_allocation'
physical_network = sa.Column(sa.String(64), nullable=False,
primary_key=True)
segmentation_id = sa.Column(sa.Integer, nullable=False, primary_key=True,
autoincrement=False)
allocated = sa.Column(sa.Boolean, nullable=False, default=False,
server_default=sql.false())
def __init__(self, physical_network, segmentation_id):
self.physical_network = physical_network
self.segmentation_id = segmentation_id
self.allocated = False
def __repr__(self):
return "<SegmentationIdAllocation(%s,%d,%s)>" % (self.physical_network,
self.segmentation_id,
self.allocated)
class NetworkBinding(model_base.BASEV2):
"""Represents binding of virtual network.
Binds network to physical_network and segmentation_id
"""
__tablename__ = 'mlnx_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)
physical_network = sa.Column(sa.String(64))
segmentation_id = sa.Column(sa.Integer, nullable=False)
def __init__(self, network_id, network_type, physical_network, vlan_id):
self.network_id = network_id
self.network_type = network_type
self.physical_network = physical_network
self.segmentation_id = vlan_id
def __repr__(self):
return "<NetworkBinding(%s,%s,%s,%d)>" % (self.network_id,
self.network_type,
self.physical_network,
self.segmentation_id)
class PortProfileBinding(model_base.BASEV2):
"""Represents port profile binding to the port on virtual network."""
__tablename__ = 'port_profile'
port_id = sa.Column(sa.String(36),
sa.ForeignKey('ports.id', ondelete="CASCADE"),
primary_key=True)
vnic_type = sa.Column(sa.String(32), nullable=False)
def __init__(self, port_id, vnic_type):
self.port_id = port_id
self.vnic_type = vnic_type
def __repr__(self):
return "<PortProfileBinding(%s,%s)>" % (self.port_id,
self.vnic_type)

View File

@ -1,541 +0,0 @@
# Copyright 2013 Mellanox Technologies, Ltd
#
# 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 sys
from oslo.config import cfg
from oslo.utils import importutils
from neutron.agent import securitygroups_rpc as sg_rpc
from neutron.api.rpc.agentnotifiers import dhcp_rpc_agent_api
from neutron.api.rpc.agentnotifiers import l3_rpc_agent_api
from neutron.api.rpc.handlers import dhcp_rpc
from neutron.api.rpc.handlers import l3_rpc
from neutron.api.rpc.handlers import metadata_rpc
from neutron.api.rpc.handlers import securitygroups_rpc
from neutron.api.v2 import attributes
from neutron.common import constants as q_const
from neutron.common import exceptions as n_exc
from neutron.common import rpc as n_rpc
from neutron.common import topics
from neutron.common import utils
from neutron.db import agents_db
from neutron.db import agentschedulers_db
from neutron.db import db_base_plugin_v2
from neutron.db import external_net_db
from neutron.db import extraroute_db
from neutron.db import l3_agentschedulers_db
from neutron.db import l3_gwmode_db
from neutron.db import portbindings_db
from neutron.db import quota_db # noqa
from neutron.db import securitygroups_rpc_base as sg_db_rpc
from neutron.extensions import portbindings
from neutron.extensions import providernet as provider
from neutron.i18n import _LE, _LI
from neutron.openstack.common import log as logging
from neutron.plugins.common import constants as svc_constants
from neutron.plugins.common import utils as plugin_utils
from neutron.plugins.mlnx import agent_notify_api
from neutron.plugins.mlnx.common import constants
from neutron.plugins.mlnx.db import mlnx_db_v2 as db
from neutron.plugins.mlnx import rpc_callbacks
LOG = logging.getLogger(__name__)
class MellanoxEswitchPlugin(db_base_plugin_v2.NeutronDbPluginV2,
external_net_db.External_net_db_mixin,
extraroute_db.ExtraRoute_db_mixin,
l3_gwmode_db.L3_NAT_db_mixin,
sg_db_rpc.SecurityGroupServerRpcMixin,
l3_agentschedulers_db.L3AgentSchedulerDbMixin,
agentschedulers_db.DhcpAgentSchedulerDbMixin,
portbindings_db.PortBindingMixin):
"""Realization of Neutron API on Mellanox HCA embedded switch technology.
Current plugin provides embedded HCA Switch connectivity.
Code is based on the Linux Bridge plugin content to
support consistency with L3 & DHCP Agents.
A new VLAN is created for each network. An agent is relied upon
to perform the actual HCA configuration on each host.
The provider extension is also supported.
The port binding extension enables an external application relay
information to and from the plugin.
"""
# This attribute specifies whether the plugin supports or not
# bulk operations. Name mangling is used in order to ensure it
# is qualified by class
__native_bulk_support = True
_supported_extension_aliases = ["provider", "external-net", "router",
"ext-gw-mode", "binding", "quotas",
"security-group", "agent", "extraroute",
"l3_agent_scheduler",
"dhcp_agent_scheduler"]
@property
def supported_extension_aliases(self):
if not hasattr(self, '_aliases'):
aliases = self._supported_extension_aliases[:]
sg_rpc.disable_security_group_extension_by_config(aliases)
self._aliases = aliases
return self._aliases
def __init__(self):
"""Start Mellanox Neutron Plugin."""
super(MellanoxEswitchPlugin, self).__init__()
self._parse_network_config()
db.sync_network_states(self.network_vlan_ranges)
self._set_tenant_network_type()
self.vnic_type = cfg.CONF.ESWITCH.vnic_type
self.base_binding_dict = {
portbindings.VIF_TYPE: self.vnic_type,
portbindings.VIF_DETAILS: {
# TODO(rkukura): Replace with new VIF security details
portbindings.CAP_PORT_FILTER:
'security-group' in self.supported_extension_aliases}}
self._setup_rpc()
self.network_scheduler = importutils.import_object(
cfg.CONF.network_scheduler_driver
)
self.router_scheduler = importutils.import_object(
cfg.CONF.router_scheduler_driver
)
LOG.debug("Mellanox Embedded Switch Plugin initialisation complete")
def _setup_rpc(self):
# RPC support
self.service_topics = {svc_constants.CORE: topics.PLUGIN,
svc_constants.L3_ROUTER_NAT: topics.L3PLUGIN}
self.conn = n_rpc.create_connection(new=True)
self.endpoints = [rpc_callbacks.MlnxRpcCallbacks(),
securitygroups_rpc.SecurityGroupServerRpcCallback(),
dhcp_rpc.DhcpRpcCallback(),
l3_rpc.L3RpcCallback(),
agents_db.AgentExtRpcCallback(),
metadata_rpc.MetadataRpcCallback()]
for svc_topic in self.service_topics.values():
self.conn.create_consumer(svc_topic, self.endpoints, fanout=False)
# Consume from all consumers in threads
self.conn.consume_in_threads()
self.notifier = agent_notify_api.AgentNotifierApi(topics.AGENT)
self.agent_notifiers[q_const.AGENT_TYPE_DHCP] = (
dhcp_rpc_agent_api.DhcpAgentNotifyAPI()
)
self.agent_notifiers[q_const.AGENT_TYPE_L3] = (
l3_rpc_agent_api.L3AgentNotifyAPI()
)
def _parse_network_config(self):
self._parse_physical_network_types()
self._parse_network_vlan_ranges()
for network in self.network_vlan_ranges.keys():
if not self.phys_network_type_maps.get(network):
self.phys_network_type_maps[network] = self.physical_net_type
def _parse_physical_network_types(self):
"""Parse physical network types configuration.
Verify default physical network type is valid.
Parse physical network mappings.
"""
self.physical_net_type = cfg.CONF.MLNX.physical_network_type
if self.physical_net_type not in (constants.TYPE_ETH,
constants.TYPE_IB):
LOG.error(_LE("Invalid physical network type %(type)s. "
"Server terminated!"),
{'type': self.physical_net_type})
raise SystemExit(1)
try:
self.phys_network_type_maps = utils.parse_mappings(
cfg.CONF.MLNX.physical_network_type_mappings)
except ValueError as e:
LOG.error(_LE("Parsing physical_network_type failed: %s. "
"Server terminated!"), e)
raise SystemExit(1)
for network, type in self.phys_network_type_maps.iteritems():
if type not in (constants.TYPE_ETH, constants.TYPE_IB):
LOG.error(_LE("Invalid physical network type %(type)s "
"for network %(net)s. Server terminated!"),
{'net': network, 'type': type})
raise SystemExit(1)
LOG.info(_LI("Physical Network type mappings: %s"),
self.phys_network_type_maps)
def _parse_network_vlan_ranges(self):
try:
self.network_vlan_ranges = plugin_utils.parse_network_vlan_ranges(
cfg.CONF.MLNX.network_vlan_ranges)
except Exception as ex:
LOG.error(_LE("%s. Server terminated!"), ex)
sys.exit(1)
LOG.info(_LI("Network VLAN ranges: %s"), self.network_vlan_ranges)
def _extend_network_dict_provider(self, context, network):
binding = db.get_network_binding(context.session, network['id'])
network[provider.NETWORK_TYPE] = binding.network_type
if binding.network_type == svc_constants.TYPE_FLAT:
network[provider.PHYSICAL_NETWORK] = binding.physical_network
network[provider.SEGMENTATION_ID] = None
elif binding.network_type == svc_constants.TYPE_LOCAL:
network[provider.PHYSICAL_NETWORK] = None
network[provider.SEGMENTATION_ID] = None
else:
network[provider.PHYSICAL_NETWORK] = binding.physical_network
network[provider.SEGMENTATION_ID] = binding.segmentation_id
def _set_tenant_network_type(self):
self.tenant_network_type = cfg.CONF.MLNX.tenant_network_type
if self.tenant_network_type not in [svc_constants.TYPE_VLAN,
svc_constants.TYPE_LOCAL,
svc_constants.TYPE_NONE]:
LOG.error(_LE("Invalid tenant_network_type: %s. "
"Service terminated!"),
self.tenant_network_type)
sys.exit(1)
def _process_provider_create(self, context, attrs):
network_type = attrs.get(provider.NETWORK_TYPE)
physical_network = attrs.get(provider.PHYSICAL_NETWORK)
segmentation_id = attrs.get(provider.SEGMENTATION_ID)
network_type_set = attributes.is_attr_set(network_type)
physical_network_set = attributes.is_attr_set(physical_network)
segmentation_id_set = attributes.is_attr_set(segmentation_id)
if not (network_type_set or physical_network_set or
segmentation_id_set):
return (None, None, None)
if not network_type_set:
msg = _("provider:network_type required")
raise n_exc.InvalidInput(error_message=msg)
elif network_type == svc_constants.TYPE_FLAT:
self._process_flat_net(segmentation_id_set)
segmentation_id = constants.FLAT_VLAN_ID
elif network_type == svc_constants.TYPE_VLAN:
self._process_vlan_net(segmentation_id, segmentation_id_set)
elif network_type == svc_constants.TYPE_LOCAL:
self._process_local_net(physical_network_set,
segmentation_id_set)
segmentation_id = constants.LOCAL_VLAN_ID
physical_network = None
else:
msg = _LE("provider:network_type %s not supported") % network_type
raise n_exc.InvalidInput(error_message=msg)
physical_network = self._process_net_type(network_type,
physical_network,
physical_network_set)
return (network_type, physical_network, segmentation_id)
def _process_flat_net(self, segmentation_id_set):
if segmentation_id_set:
msg = _LE("provider:segmentation_id specified for flat network")
raise n_exc.InvalidInput(error_message=msg)
def _process_vlan_net(self, segmentation_id, segmentation_id_set):
if not segmentation_id_set:
msg = _LE("provider:segmentation_id required")
raise n_exc.InvalidInput(error_message=msg)
if not utils.is_valid_vlan_tag(segmentation_id):
msg = (_LE("provider:segmentation_id out of range "
"(%(min_id)s through %(max_id)s)") %
{'min_id': q_const.MIN_VLAN_TAG,
'max_id': q_const.MAX_VLAN_TAG})
raise n_exc.InvalidInput(error_message=msg)
def _process_local_net(self, physical_network_set, segmentation_id_set):
if physical_network_set:
msg = _LE("provider:physical_network specified for local "
"network")
raise n_exc.InvalidInput(error_message=msg)
if segmentation_id_set:
msg = _LE("provider:segmentation_id specified for local "
"network")
raise n_exc.InvalidInput(error_message=msg)
def _process_net_type(self, network_type,
physical_network,
physical_network_set):
if network_type in [svc_constants.TYPE_VLAN,
svc_constants.TYPE_FLAT]:
if physical_network_set:
if physical_network not in self.network_vlan_ranges:
msg = _LE("Unknown provider:physical_network "
"%s") % physical_network
raise n_exc.InvalidInput(error_message=msg)
elif 'default' in self.network_vlan_ranges:
physical_network = 'default'
else:
msg = _LE("provider:physical_network required")
raise n_exc.InvalidInput(error_message=msg)
return physical_network
def _check_port_binding_for_net_type(self, vnic_type, net_type):
"""
VIF_TYPE_DIRECT is valid only for Ethernet fabric
"""
if net_type == constants.TYPE_ETH:
return vnic_type in (constants.VIF_TYPE_DIRECT,
constants.VIF_TYPE_HOSTDEV)
elif net_type == constants.TYPE_IB:
return vnic_type == constants.VIF_TYPE_HOSTDEV
return False
def _process_port_binding_create(self, context, attrs):
binding_profile = attrs.get(portbindings.PROFILE)
binding_profile_set = attributes.is_attr_set(binding_profile)
net_binding = db.get_network_binding(context.session,
attrs.get('network_id'))
phy_net = net_binding.physical_network
if not binding_profile_set:
return self.vnic_type
if constants.VNIC_TYPE in binding_profile:
vnic_type = binding_profile[constants.VNIC_TYPE]
phy_net_type = self.phys_network_type_maps[phy_net]
if vnic_type in (constants.VIF_TYPE_DIRECT,
constants.VIF_TYPE_HOSTDEV):
if self._check_port_binding_for_net_type(vnic_type,
phy_net_type):
self.base_binding_dict[portbindings.VIF_TYPE] = vnic_type
return vnic_type
else:
msg = (_LE("Unsupported vnic type %(vnic_type)s "
"for physical network type %(net_type)s") %
{'vnic_type': vnic_type, 'net_type': phy_net_type})
else:
msg = _LE("Invalid vnic_type on port_create")
else:
msg = _LE("vnic_type is not defined in port profile")
raise n_exc.InvalidInput(error_message=msg)
def create_network(self, context, network):
(network_type, physical_network,
vlan_id) = self._process_provider_create(context,
network['network'])
session = context.session
with session.begin(subtransactions=True):
#set up default security groups
tenant_id = self._get_tenant_id_for_create(
context, network['network'])
self._ensure_default_security_group(context, tenant_id)
if not network_type:
# tenant network
network_type = self.tenant_network_type
if network_type == svc_constants.TYPE_NONE:
raise n_exc.TenantNetworksDisabled()
elif network_type == svc_constants.TYPE_VLAN:
physical_network, vlan_id = db.reserve_network(session)
else: # TYPE_LOCAL
vlan_id = constants.LOCAL_VLAN_ID
else:
# provider network
if network_type in [svc_constants.TYPE_VLAN,
svc_constants.TYPE_FLAT]:
db.reserve_specific_network(session,
physical_network,
vlan_id)
net = super(MellanoxEswitchPlugin, self).create_network(context,
network)
db.add_network_binding(session, net['id'],
network_type,
physical_network,
vlan_id)
self._process_l3_create(context, net, network['network'])
self._extend_network_dict_provider(context, net)
# note - exception will rollback entire transaction
LOG.debug("Created network: %s", net['id'])
return net
def update_network(self, context, net_id, network):
LOG.debug("Update network")
provider._raise_if_updates_provider_attributes(network['network'])
session = context.session
with session.begin(subtransactions=True):
net = super(MellanoxEswitchPlugin, self).update_network(context,
net_id,
network)
self._process_l3_update(context, net, network['network'])
self._extend_network_dict_provider(context, net)
return net
def delete_network(self, context, net_id):
LOG.debug("Delete network")
session = context.session
with session.begin(subtransactions=True):
binding = db.get_network_binding(session, net_id)
self._process_l3_delete(context, net_id)
super(MellanoxEswitchPlugin, self).delete_network(context,
net_id)
if binding.segmentation_id != constants.LOCAL_VLAN_ID:
db.release_network(session, binding.physical_network,
binding.segmentation_id,
self.network_vlan_ranges)
# the network_binding record is deleted via cascade from
# the network record, so explicit removal is not necessary
self.notifier.network_delete(context, net_id)
def get_network(self, context, net_id, fields=None):
session = context.session
with session.begin(subtransactions=True):
net = super(MellanoxEswitchPlugin, self).get_network(context,
net_id,
None)
self._extend_network_dict_provider(context, net)
return self._fields(net, fields)
def get_networks(self, context, filters=None, fields=None,
sorts=None, limit=None, marker=None, page_reverse=False):
session = context.session
with session.begin(subtransactions=True):
nets = super(MellanoxEswitchPlugin,
self).get_networks(context, filters, None, sorts,
limit, marker, page_reverse)
for net in nets:
self._extend_network_dict_provider(context, net)
return [self._fields(net, fields) for net in nets]
def _extend_port_dict_binding(self, context, port):
port_binding = db.get_port_profile_binding(context.session,
port['id'])
if port_binding:
port[portbindings.VIF_TYPE] = port_binding.vnic_type
binding = db.get_network_binding(context.session,
port['network_id'])
fabric = binding.physical_network
port[portbindings.PROFILE] = {'physical_network': fabric}
return port
def create_port(self, context, port):
LOG.debug("create_port with %s", port)
session = context.session
port_data = port['port']
with session.begin(subtransactions=True):
self._ensure_default_security_group_on_port(context, port)
sgids = self._get_security_groups_on_port(context, port)
# Set port status as 'DOWN'. This will be updated by agent
port['port']['status'] = q_const.PORT_STATUS_DOWN
vnic_type = self._process_port_binding_create(context,
port['port'])
port = super(MellanoxEswitchPlugin,
self).create_port(context, port)
self._process_portbindings_create_and_update(context,
port_data,
port)
db.add_port_profile_binding(context.session, port['id'], vnic_type)
self._process_port_create_security_group(
context, port, sgids)
self.notify_security_groups_member_updated(context, port)
return self._extend_port_dict_binding(context, port)
def get_port(self, context, id, fields=None):
port = super(MellanoxEswitchPlugin, self).get_port(context,
id,
fields)
self._extend_port_dict_binding(context, port)
return self._fields(port, fields)
def get_ports(self, context, filters=None, fields=None,
sorts=None, limit=None, marker=None, page_reverse=False):
res_ports = []
ports = super(MellanoxEswitchPlugin,
self).get_ports(context, filters, fields, sorts,
limit, marker, page_reverse)
for port in ports:
port = self._extend_port_dict_binding(context, port)
res_ports.append(self._fields(port, fields))
return res_ports
def update_port(self, context, port_id, port):
original_port = self.get_port(context, port_id)
session = context.session
need_port_update_notify = False
with session.begin(subtransactions=True):
updated_port = super(MellanoxEswitchPlugin, self).update_port(
context, port_id, port)
self._process_portbindings_create_and_update(context,
port['port'],
updated_port)
need_port_update_notify = self.update_security_group_on_port(
context, port_id, port, original_port, updated_port)
need_port_update_notify |= self.is_security_group_member_updated(
context, original_port, updated_port)
if original_port['admin_state_up'] != updated_port['admin_state_up']:
need_port_update_notify = True
if need_port_update_notify:
binding = db.get_network_binding(context.session,
updated_port['network_id'])
self.notifier.port_update(context, updated_port,
binding.physical_network,
binding.network_type,
binding.segmentation_id)
return self._extend_port_dict_binding(context, updated_port)
def delete_port(self, context, port_id, l3_port_check=True):
# if needed, check to see if this is a port owned by
# and l3-router. If so, we should prevent deletion.
if l3_port_check:
self.prevent_l3_port_deletion(context, port_id)
session = context.session
with session.begin(subtransactions=True):
router_ids = self.disassociate_floatingips(
context, port_id, do_notify=False)
port = self.get_port(context, port_id)
self._delete_port_security_group_bindings(context, port_id)
super(MellanoxEswitchPlugin, self).delete_port(context, port_id)
# now that we've left db transaction, we are safe to notify
self.notify_routers_updated(context, router_ids)
self.notify_security_groups_member_updated(context, port)
@classmethod
def get_port_from_device(cls, device):
"""Get port according to device.
To maintain compatibility with Linux Bridge L2 Agent for DHCP/L3
services get device either by linux bridge plugin
device name convention or by mac address
"""
port = db.get_port_from_device(
device[len(q_const.TAP_DEVICE_PREFIX):])
if port:
port['device'] = device
else:
port = db.get_port_from_device_mac(device)
if port:
port['device'] = device
return port

View File

@ -1,107 +0,0 @@
# Copyright 2013 Mellanox Technologies, Ltd
#
# 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 oslo.config import cfg
from oslo import messaging
from neutron.common import constants as q_const
from neutron.db import api as db_api
from neutron import manager
from neutron.openstack.common import log as logging
from neutron.plugins.mlnx.db import mlnx_db_v2 as db
LOG = logging.getLogger(__name__)
class MlnxRpcCallbacks(object):
# History
# 1.1 Support Security Group RPC
# 1.2 Support get_devices_details_list
target = messaging.Target(version='1.2')
def get_device_details(self, rpc_context, **kwargs):
"""Agent requests device details."""
agent_id = kwargs.get('agent_id')
device = kwargs.get('device')
LOG.debug("Device %(device)s details requested from %(agent_id)s",
{'device': device, 'agent_id': agent_id})
plugin = manager.NeutronManager.get_plugin()
port = plugin.get_port_from_device(device)
if port:
binding = db.get_network_binding(db_api.get_session(),
port['network_id'])
entry = {'device': device,
'physical_network': binding.physical_network,
'network_type': binding.network_type,
'segmentation_id': binding.segmentation_id,
'network_id': port['network_id'],
'port_mac': port['mac_address'],
'port_id': port['id'],
'admin_state_up': port['admin_state_up']}
if cfg.CONF.AGENT.rpc_support_old_agents:
entry['vlan_id'] = binding.segmentation_id
new_status = (q_const.PORT_STATUS_ACTIVE if port['admin_state_up']
else q_const.PORT_STATUS_DOWN)
if port['status'] != new_status:
db.set_port_status(port['id'], new_status)
else:
entry = {'device': device}
LOG.debug("%s can not be found in database", device)
return entry
def get_devices_details_list(self, rpc_context, **kwargs):
return [
self.get_device_details(
rpc_context,
device=device,
**kwargs
)
for device in kwargs.pop('devices', [])
]
def update_device_down(self, rpc_context, **kwargs):
"""Device no longer exists on agent."""
agent_id = kwargs.get('agent_id')
device = kwargs.get('device')
LOG.debug("Device %(device)s no longer exists on %(agent_id)s",
{'device': device, 'agent_id': agent_id})
plugin = manager.NeutronManager.get_plugin()
port = plugin.get_port_from_device(device)
if port:
entry = {'device': device,
'exists': True}
if port['status'] != q_const.PORT_STATUS_DOWN:
# Set port status to DOWN
db.set_port_status(port['id'], q_const.PORT_STATUS_DOWN)
else:
entry = {'device': device,
'exists': False}
LOG.debug("%s can not be found in database", device)
return entry
def update_device_up(self, rpc_context, **kwargs):
"""Device is up on agent."""
agent_id = kwargs.get('agent_id')
device = kwargs.get('device')
LOG.debug("Device %(device)s up %(agent_id)s",
{'device': device, 'agent_id': agent_id})
plugin = manager.NeutronManager.get_plugin()
port = plugin.get_port_from_device(device)
if port:
if port['status'] != q_const.PORT_STATUS_ACTIVE:
# Set port status to ACTIVE
db.set_port_status(port['id'], q_const.PORT_STATUS_ACTIVE)
else:
LOG.debug("%s can not be found in database", device)

View File

@ -1,34 +0,0 @@
# Copyright (c) 2013 OpenStack Foundation
#
# 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 neutron.tests.unit.mlnx import test_mlnx_plugin
from neutron.tests.unit.openvswitch import test_agent_scheduler
class MlnxAgentSchedulerTestCase(
test_agent_scheduler.OvsAgentSchedulerTestCase):
plugin_str = test_mlnx_plugin.PLUGIN_NAME
l3_plugin = None
class MlnxL3AgentNotifierTestCase(
test_agent_scheduler.OvsL3AgentNotifierTestCase):
plugin_str = test_mlnx_plugin.PLUGIN_NAME
l3_plugin = None
class MlnxDhcpAgentNotifierTestCase(
test_agent_scheduler.OvsDhcpAgentNotifierTestCase):
plugin_str = test_mlnx_plugin.PLUGIN_NAME

View File

@ -25,13 +25,6 @@ class ConfigurationTest(base.BaseTestCase):
def test_defaults(self):
self.assertEqual(2,
cfg.CONF.AGENT.polling_interval)
self.assertEqual('vlan',
cfg.CONF.MLNX.tenant_network_type)
self.assertEqual(1,
len(cfg.CONF.MLNX.network_vlan_ranges))
self.assertEqual('eth',
cfg.CONF.MLNX.physical_network_type)
self.assertFalse(cfg.CONF.MLNX.physical_network_type_mappings)
self.assertEqual(0,
len(cfg.CONF.ESWITCH.
physical_interface_mappings))

View File

@ -1,204 +0,0 @@
# Copyright (c) 2013 OpenStack Foundation
#
# 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 six import moves
from testtools import matchers
from neutron.common import exceptions as n_exc
from neutron.db import api as db
from neutron.plugins.mlnx.db import mlnx_db_v2 as mlnx_db
from neutron.tests.unit import test_db_plugin as test_plugin
from neutron.tests.unit import testlib_api
PHYS_NET = 'physnet1'
PHYS_NET_2 = 'physnet2'
NET_TYPE = 'vlan'
VLAN_MIN = 10
VLAN_MAX = 19
VLAN_RANGES = {PHYS_NET: [(VLAN_MIN, VLAN_MAX)]}
UPDATED_VLAN_RANGES = {PHYS_NET: [(VLAN_MIN + 5, VLAN_MAX + 5)],
PHYS_NET_2: [(VLAN_MIN + 20, VLAN_MAX + 20)]}
TEST_NETWORK_ID = 'abcdefghijklmnopqrstuvwxyz'
class SegmentationIdAllocationTest(testlib_api.SqlTestCase):
def setUp(self):
super(SegmentationIdAllocationTest, self).setUp()
mlnx_db.sync_network_states(VLAN_RANGES)
self.session = db.get_session()
def test_sync_segmentationIdAllocation(self):
self.assertIsNone(mlnx_db.get_network_state(PHYS_NET,
VLAN_MIN - 1))
self.assertFalse(mlnx_db.get_network_state(PHYS_NET,
VLAN_MIN).allocated)
self.assertFalse(mlnx_db.get_network_state(PHYS_NET,
VLAN_MIN + 1).allocated)
self.assertFalse(mlnx_db.get_network_state(PHYS_NET,
VLAN_MAX - 1).allocated)
self.assertFalse(mlnx_db.get_network_state(PHYS_NET,
VLAN_MAX).allocated)
self.assertIsNone(mlnx_db.get_network_state(PHYS_NET,
VLAN_MAX + 1))
mlnx_db.sync_network_states(UPDATED_VLAN_RANGES)
self.assertIsNone(mlnx_db.get_network_state(PHYS_NET,
VLAN_MIN + 5 - 1))
self.assertFalse(mlnx_db.get_network_state(PHYS_NET,
VLAN_MIN + 5).allocated)
self.assertFalse(mlnx_db.get_network_state(PHYS_NET,
VLAN_MIN + 5 + 1).allocated)
self.assertFalse(mlnx_db.get_network_state(PHYS_NET,
VLAN_MAX + 5 - 1).allocated)
self.assertFalse(mlnx_db.get_network_state(PHYS_NET,
VLAN_MAX + 5).allocated)
self.assertIsNone(mlnx_db.get_network_state(PHYS_NET,
VLAN_MAX + 5 + 1))
self.assertIsNone(mlnx_db.get_network_state(PHYS_NET_2,
VLAN_MIN + 20 - 1))
self.assertFalse(mlnx_db.get_network_state(PHYS_NET_2,
VLAN_MIN + 20).allocated)
self.assertFalse(
mlnx_db.get_network_state(PHYS_NET_2,
VLAN_MIN + 20 + 1).allocated)
self.assertFalse(
mlnx_db.get_network_state(PHYS_NET_2,
VLAN_MAX + 20 - 1).allocated)
self.assertFalse(mlnx_db.get_network_state(PHYS_NET_2,
VLAN_MAX + 20).allocated)
self.assertIsNone(mlnx_db.get_network_state(PHYS_NET_2,
VLAN_MAX + 20 + 1))
mlnx_db.sync_network_states(VLAN_RANGES)
self.assertIsNone(mlnx_db.get_network_state(PHYS_NET,
VLAN_MIN - 1))
self.assertFalse(mlnx_db.get_network_state(PHYS_NET,
VLAN_MIN).allocated)
self.assertFalse(mlnx_db.get_network_state(PHYS_NET,
VLAN_MIN + 1).allocated)
self.assertFalse(mlnx_db.get_network_state(PHYS_NET,
VLAN_MAX - 1).allocated)
self.assertFalse(mlnx_db.get_network_state(PHYS_NET,
VLAN_MAX).allocated)
self.assertIsNone(mlnx_db.get_network_state(PHYS_NET,
VLAN_MAX + 1))
self.assertIsNone(mlnx_db.get_network_state(PHYS_NET_2,
VLAN_MIN + 20))
self.assertIsNone(mlnx_db.get_network_state(PHYS_NET_2,
VLAN_MAX + 20))
def test_segmentationId_pool(self):
vlan_ids = set()
for x in moves.xrange(VLAN_MIN, VLAN_MAX + 1):
physical_network, vlan_id = mlnx_db.reserve_network(self.session)
self.assertEqual(physical_network, PHYS_NET)
self.assertThat(vlan_id, matchers.GreaterThan(VLAN_MIN - 1))
self.assertThat(vlan_id, matchers.LessThan(VLAN_MAX + 1))
vlan_ids.add(vlan_id)
self.assertRaises(n_exc.NoNetworkAvailable,
mlnx_db.reserve_network,
self.session)
for vlan_id in vlan_ids:
mlnx_db.release_network(self.session, PHYS_NET,
vlan_id, VLAN_RANGES)
def test_specific_segmentationId_inside_pool(self):
vlan_id = VLAN_MIN + 5
self.assertFalse(mlnx_db.get_network_state(PHYS_NET,
vlan_id).allocated)
mlnx_db.reserve_specific_network(self.session, PHYS_NET, vlan_id)
self.assertTrue(mlnx_db.get_network_state(PHYS_NET,
vlan_id).allocated)
self.assertRaises(n_exc.VlanIdInUse,
mlnx_db.reserve_specific_network,
self.session,
PHYS_NET,
vlan_id)
mlnx_db.release_network(self.session, PHYS_NET, vlan_id, VLAN_RANGES)
self.assertFalse(mlnx_db.get_network_state(PHYS_NET,
vlan_id).allocated)
def test_specific_segmentationId_outside_pool(self):
vlan_id = VLAN_MAX + 5
self.assertIsNone(mlnx_db.get_network_state(PHYS_NET, vlan_id))
mlnx_db.reserve_specific_network(self.session, PHYS_NET, vlan_id)
self.assertTrue(mlnx_db.get_network_state(PHYS_NET,
vlan_id).allocated)
self.assertRaises(n_exc.VlanIdInUse,
mlnx_db.reserve_specific_network,
self.session,
PHYS_NET,
vlan_id)
mlnx_db.release_network(self.session, PHYS_NET, vlan_id, VLAN_RANGES)
self.assertIsNone(mlnx_db.get_network_state(PHYS_NET, vlan_id))
class NetworkBindingsTest(test_plugin.NeutronDbPluginV2TestCase):
def setUp(self):
super(NetworkBindingsTest, self).setUp()
self.session = db.get_session()
def test_add_network_binding(self):
with self.network() as network:
TEST_NETWORK_ID = network['network']['id']
self.assertIsNone(mlnx_db.get_network_binding(self.session,
TEST_NETWORK_ID))
mlnx_db.add_network_binding(self.session,
TEST_NETWORK_ID,
NET_TYPE,
PHYS_NET,
1234)
binding = mlnx_db.get_network_binding(self.session,
TEST_NETWORK_ID)
self.assertIsNotNone(binding)
self.assertEqual(binding.network_id, TEST_NETWORK_ID)
self.assertEqual(binding.network_type, NET_TYPE)
self.assertEqual(binding.physical_network, PHYS_NET)
self.assertEqual(binding.segmentation_id, 1234)
self.assertTrue(repr(binding))
class PortProfileBindingTest(test_plugin.NeutronDbPluginV2TestCase):
def setUp(self):
super(PortProfileBindingTest, self).setUp()
self.session = db.get_session()
def test_add_port_profile_binding(self):
with self.port() as port:
TEST_PORT_ID = port['port']['id']
VNIC_TYPE = 'normal'
self.assertIsNone(mlnx_db.get_port_profile_binding(self.session,
TEST_PORT_ID))
mlnx_db.add_port_profile_binding(self.session,
TEST_PORT_ID,
VNIC_TYPE)
binding = mlnx_db.get_port_profile_binding(self.session,
TEST_PORT_ID)
self.assertIsNotNone(binding)
self.assertEqual(binding.port_id, TEST_PORT_ID)
self.assertEqual(binding.vnic_type, VNIC_TYPE)
self.assertTrue(repr(binding))

View File

@ -1,118 +0,0 @@
# Copyright (c) 2013 OpenStack Foundation
#
# 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 oslo.config import cfg
from webob import exc
from neutron.extensions import portbindings
from neutron.plugins.mlnx.common import constants
from neutron.tests.unit import _test_extension_portbindings as test_bindings
from neutron.tests.unit import test_db_plugin as test_plugin
from neutron.tests.unit import test_security_groups_rpc as test_sg_rpc
PLUGIN_NAME = ('neutron.plugins.mlnx.mlnx_plugin.MellanoxEswitchPlugin')
class MlnxPluginV2TestCase(test_plugin.NeutronDbPluginV2TestCase):
_plugin_name = PLUGIN_NAME
def setUp(self):
super(MlnxPluginV2TestCase, self).setUp(self._plugin_name)
self.port_create_status = 'DOWN'
class TestMlnxBasicGet(test_plugin.TestBasicGet, MlnxPluginV2TestCase):
pass
class TestMlnxV2HTTPResponse(test_plugin.TestV2HTTPResponse,
MlnxPluginV2TestCase):
pass
class TestMlnxPortsV2(test_plugin.TestPortsV2,
MlnxPluginV2TestCase):
pass
class TestMlnxNetworksV2(test_plugin.TestNetworksV2, MlnxPluginV2TestCase):
pass
class TestMlnxPortBinding(MlnxPluginV2TestCase,
test_bindings.PortBindingsTestCase):
VIF_TYPE = constants.VIF_TYPE_DIRECT
ENABLE_SG = False
HAS_PORT_FILTER = False
def setUp(self, firewall_driver=None):
cfg.CONF.set_override(
'enable_security_group', self.ENABLE_SG,
group='SECURITYGROUP')
super(TestMlnxPortBinding, self).setUp()
def _check_default_port_binding_profole(self, port,
expected_vif_type=None):
if expected_vif_type is None:
expected_vif_type = constants.VIF_TYPE_DIRECT
p = port['port']
self.assertIn('id', p)
self.assertEqual(expected_vif_type, p[portbindings.VIF_TYPE])
self.assertEqual({'physical_network': 'default'},
p[portbindings.PROFILE])
def test_create_port_no_binding_profile(self):
with self.port() as port:
self._check_default_port_binding_profole(port)
def test_create_port_binding_profile_none(self):
profile_arg = {portbindings.PROFILE: None}
with self.port(arg_list=(portbindings.PROFILE,),
**profile_arg) as port:
self._check_default_port_binding_profole(port)
def test_create_port_binding_profile_vif_type(self):
for vif_type in [constants.VIF_TYPE_HOSTDEV,
constants.VIF_TYPE_DIRECT]:
profile_arg = {portbindings.PROFILE:
{constants.VNIC_TYPE: vif_type}}
with self.port(arg_list=(portbindings.PROFILE,),
**profile_arg) as port:
self._check_default_port_binding_profole(
port, expected_vif_type=vif_type)
self._delete('ports', port['port']['id'])
self._delete('networks', port['port']['network_id'])
def test_create_port_binding_profile_with_empty_dict(self):
profile_arg = {portbindings.PROFILE: {}}
try:
with self.port(arg_list=(portbindings.PROFILE,),
expected_res_status=400, **profile_arg):
pass
except exc.HTTPClientError:
pass
class TestMlnxPortBindingNoSG(TestMlnxPortBinding):
HAS_PORT_FILTER = False
ENABLE_SG = False
FIREWALL_DRIVER = test_sg_rpc.FIREWALL_NOOP_DRIVER
class TestMlnxPortBindingHost(
MlnxPluginV2TestCase,
test_bindings.PortBindingsHostTestCaseMixin):
pass

View File

@ -1,87 +0,0 @@
# Copyright (c) 2014 OpenStack Foundation
#
# 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 mock
from oslo.config import cfg
#NOTE this import loads tests required options
from neutron.plugins.mlnx.common import config # noqa
from neutron.plugins.mlnx.common import constants
from neutron.plugins.mlnx import mlnx_plugin
from neutron.tests.unit import testlib_api
class TestMlnxPluginConfig(testlib_api.SqlTestCase):
expected_vlan_mappings = {'physnet1': [(1, 1000)],
'physnet2': [(1, 1000)]}
expected_network_types = {'physnet1': constants.TYPE_ETH,
'physnet2': constants.TYPE_IB}
config_vlan_ranges = ['physnet1:1:1000', 'physnet2:1:1000']
config_network_types = ['physnet1:eth', 'physnet2:ib']
def setUp(self):
super(TestMlnxPluginConfig, self).setUp()
cfg.CONF.set_override(group='MLNX',
name='network_vlan_ranges',
override=self.config_vlan_ranges)
def _create_mlnx_plugin(self):
with mock.patch('neutron.plugins.mlnx.db.mlnx_db_v2'):
return mlnx_plugin.MellanoxEswitchPlugin()
def _assert_expected_config(self):
plugin = self._create_mlnx_plugin()
self.assertEqual(plugin.network_vlan_ranges,
self.expected_vlan_mappings)
self.assertEqual(plugin.phys_network_type_maps,
self.expected_network_types)
def test_vlan_ranges_with_network_type(self):
cfg.CONF.set_override(group='MLNX',
name='physical_network_type_mappings',
override=self.config_network_types)
self._assert_expected_config()
def test_vlan_ranges_partial_network_type(self):
cfg.CONF.set_override(group='MLNX',
name='physical_network_type_mappings',
override=self.config_network_types[:1])
cfg.CONF.set_override(group='MLNX',
name='physical_network_type',
override=constants.TYPE_IB)
self._assert_expected_config()
def test_vlan_ranges_no_network_type(self):
cfg.CONF.set_override(group='MLNX',
name='physical_network_type',
override=constants.TYPE_IB)
cfg.CONF.set_override(group='MLNX',
name='physical_network_type_mappings',
override=[])
self.expected_network_types.update({'physnet1': constants.TYPE_IB})
self._assert_expected_config()
self.expected_network_types.update({'physnet1': constants.TYPE_ETH})
def test_parse_physical_network_mappings_invalid_type(self):
cfg.CONF.set_override(group='MLNX',
name='physical_network_type_mappings',
override=['physnet:invalid-type'])
self.assertRaises(SystemExit, self._create_mlnx_plugin)
def test_invalid_network_type(self):
cfg.CONF.set_override(group='MLNX',
name='physical_network_type',
override='invalid-type')
self.assertRaises(SystemExit, self._create_mlnx_plugin)

View File

@ -1,92 +0,0 @@
# Copyright (c) 2013 OpenStack Foundation
#
# 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 mock
import webob.exc
from neutron.api.v2 import attributes
from neutron.extensions import securitygroup as ext_sg
from neutron.plugins.mlnx.db import mlnx_db_v2 as mlnx_db
from neutron.tests.unit import test_extension_security_group as test_sg
from neutron.tests.unit import test_security_groups_rpc as test_sg_rpc
PLUGIN_NAME = ('neutron.plugins.mlnx.'
'mlnx_plugin.MellanoxEswitchPlugin')
NOTIFIER = ('neutron.plugins.mlnx.'
'agent_notify_api.AgentNotifierApi')
class MlnxSecurityGroupsTestCase(test_sg.SecurityGroupDBTestCase):
_plugin_name = PLUGIN_NAME
def setUp(self, plugin=None):
test_sg_rpc.set_firewall_driver(test_sg_rpc.FIREWALL_IPTABLES_DRIVER)
notifier_p = mock.patch(NOTIFIER)
notifier_cls = notifier_p.start()
self.notifier = mock.Mock()
notifier_cls.return_value = self.notifier
self._attribute_map_bk_ = {}
for item in attributes.RESOURCE_ATTRIBUTE_MAP:
self._attribute_map_bk_[item] = (attributes.
RESOURCE_ATTRIBUTE_MAP[item].
copy())
super(MlnxSecurityGroupsTestCase, self).setUp(PLUGIN_NAME)
def tearDown(self):
attributes.RESOURCE_ATTRIBUTE_MAP = self._attribute_map_bk_
super(MlnxSecurityGroupsTestCase, self).tearDown()
class TestMlnxSecurityGroups(MlnxSecurityGroupsTestCase,
test_sg.TestSecurityGroups,
test_sg_rpc.SGNotificationTestMixin):
pass
class TestMlnxSecurityGroupsDB(MlnxSecurityGroupsTestCase):
def test_security_group_get_port_from_device(self):
with self.network() as n:
with self.subnet(n):
with self.security_group() as sg:
security_group_id = sg['security_group']['id']
res = self._create_port(self.fmt, n['network']['id'])
port = self.deserialize(self.fmt, res)
fixed_ips = port['port']['fixed_ips']
data = {'port': {'fixed_ips': fixed_ips,
'name': port['port']['name'],
ext_sg.SECURITYGROUPS:
[security_group_id]}}
req = self.new_update_request('ports', data,
port['port']['id'])
if res.status_int >= 400:
raise webob.exc.HTTPClientError(code=res.status_int)
res = self.deserialize(self.fmt,
req.get_response(self.api))
port_id = res['port']['id']
device_id = port_id[:8]
port_dict = mlnx_db.get_port_from_device(device_id)
self.assertEqual(port_id, port_dict['id'])
self.assertEqual([security_group_id],
port_dict[ext_sg.SECURITYGROUPS])
self.assertEqual([], port_dict['security_group_rules'])
self.assertEqual([fixed_ips[0]['ip_address']],
port_dict['fixed_ips'])
self._delete('ports', port['port']['id'])
def test_security_group_get_port_from_device_with_no_port(self):
port_dict = mlnx_db.get_port_from_device('bad_device_id')
self.assertIsNone(port_dict)

View File

@ -1,135 +0,0 @@
# Copyright 2013 Mellanox Technologies, Ltd
#
# 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.
"""
Unit Tests for Mellanox RPC (major reuse of linuxbridge rpc unit tests)
"""
import contextlib
import mock
from oslo.config import cfg
from oslo_context import context as oslo_context
from neutron.agent import rpc as agent_rpc
from neutron.common import topics
from neutron.plugins.mlnx import agent_notify_api
from neutron.tests import base
class rpcApiTestCase(base.BaseTestCase):
def _test_mlnx_api(self, rpcapi, topic, method, rpc_method, **kwargs):
ctxt = oslo_context.RequestContext('fake_user', 'fake_project')
expected_retval = 'foo' if rpc_method == 'call' else None
expected_version = kwargs.pop('version', None)
fanout = kwargs.pop('fanout', False)
with contextlib.nested(
mock.patch.object(rpcapi.client, rpc_method),
mock.patch.object(rpcapi.client, 'prepare'),
) as (
rpc_mock, prepare_mock
):
prepare_mock.return_value = rpcapi.client
rpc_mock.return_value = expected_retval
retval = getattr(rpcapi, method)(ctxt, **kwargs)
prepare_args = {}
if expected_version:
prepare_args['version'] = expected_version
if fanout:
prepare_args['fanout'] = True
if topic:
prepare_args['topic'] = topic
prepare_mock.assert_called_once_with(**prepare_args)
if method == 'port_update':
kwargs['segmentation_id'] = kwargs['vlan_id']
if not cfg.CONF.AGENT.rpc_support_old_agents:
del kwargs['vlan_id']
self.assertEqual(retval, expected_retval)
rpc_mock.assert_called_once_with(ctxt, method, **kwargs)
def test_delete_network(self):
rpcapi = agent_notify_api.AgentNotifierApi(topics.AGENT)
self._test_mlnx_api(
rpcapi,
topics.get_topic_name(topics.AGENT,
topics.NETWORK,
topics.DELETE),
'network_delete', rpc_method='cast', fanout=True,
network_id='fake_request_spec')
def test_port_update(self):
cfg.CONF.set_override('rpc_support_old_agents', False, 'AGENT')
rpcapi = agent_notify_api.AgentNotifierApi(topics.AGENT)
self._test_mlnx_api(
rpcapi,
topics.get_topic_name(topics.AGENT,
topics.PORT,
topics.UPDATE),
'port_update', rpc_method='cast', fanout=True,
port='fake_port',
network_type='vlan',
physical_network='fake_net',
vlan_id='fake_vlan_id')
def test_port_update_old_agent(self):
cfg.CONF.set_override('rpc_support_old_agents', True, 'AGENT')
rpcapi = agent_notify_api.AgentNotifierApi(topics.AGENT)
self._test_mlnx_api(
rpcapi,
topics.get_topic_name(topics.AGENT,
topics.PORT,
topics.UPDATE),
'port_update', rpc_method='cast', fanout=True,
port='fake_port',
network_type='vlan',
physical_network='fake_net',
vlan_id='fake_vlan_id')
def test_device_details(self):
rpcapi = agent_rpc.PluginApi(topics.PLUGIN)
self._test_mlnx_api(rpcapi, None,
'get_device_details', rpc_method='call',
device='fake_device',
agent_id='fake_agent_id',
host='fake_host')
def test_devices_details_list(self):
rpcapi = agent_rpc.PluginApi(topics.PLUGIN)
self._test_mlnx_api(rpcapi, None,
'get_devices_details_list', rpc_method='call',
devices=['fake_device1', 'fake_device1'],
agent_id='fake_agent_id', host='fake_host',
version='1.3')
def test_update_device_down(self):
rpcapi = agent_rpc.PluginApi(topics.PLUGIN)
self._test_mlnx_api(rpcapi, None,
'update_device_down', rpc_method='call',
device='fake_device',
agent_id='fake_agent_id',
host='fake_host')
def test_update_device_up(self):
rpcapi = agent_rpc.PluginApi(topics.PLUGIN)
self._test_mlnx_api(rpcapi, None,
'update_device_up', rpc_method='call',
device='fake_device',
agent_id='fake_agent_id',
host='fake_host')

View File

@ -133,7 +133,6 @@ neutron.core_plugins =
ibm = neutron.plugins.ibm.sdnve_neutron_plugin:SdnvePluginV2
midonet = neutron.plugins.midonet.plugin:MidonetPluginV2
ml2 = neutron.plugins.ml2.plugin:Ml2Plugin
mlnx = neutron.plugins.mlnx.mlnx_plugin:MellanoxEswitchPlugin
nec = neutron.plugins.nec.nec_plugin:NECPluginV2
nuage = neutron.plugins.nuage.plugin:NuagePlugin
metaplugin = neutron.plugins.metaplugin.meta_neutron_plugin:MetaPluginV2