Multi-segment and trunk support for the Cisco N1Kv Plugin

This patch adds vlan and vxlan trunk support in the
Cisco N1Kv plugin. It also adds support for multi-segment
networks for bridging vlan networks with vxlan networks.

Change-Id: Ibecbbfbce1eb4d18ef6a1bc5250622b9ae87d39c
Implements: blueprint multi-segment-and-trunk-support-cisco-nexus1000v
This commit is contained in:
Rudrajit Tapadar 2013-08-09 23:42:45 -07:00
parent 9928edb42d
commit 996bb5e218
11 changed files with 1264 additions and 80 deletions

View File

@ -0,0 +1,80 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
#
# Copyright 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.
#
"""cisco_n1kv_multisegment_trunk
Revision ID: 46a0efbd8f0
Revises: 53bbd27ec841
Create Date: 2013-08-20 20:44:08.711110
"""
revision = '46a0efbd8f0'
down_revision = '53bbd27ec841'
migration_for_plugins = [
'neutron.plugins.cisco.network_plugin.PluginV2'
]
from alembic import op
import sqlalchemy as sa
from neutron.db import migration
def upgrade(active_plugins=None, options=None):
if not migration.should_run(active_plugins, migration_for_plugins):
return
op.create_table(
'cisco_n1kv_trunk_segments',
sa.Column('trunk_segment_id', sa.String(length=36), nullable=False),
sa.Column('segment_id', sa.String(length=36), nullable=False),
sa.Column('dot1qtag', sa.String(length=36), nullable=False),
sa.ForeignKeyConstraint(['trunk_segment_id'], ['networks.id'],
ondelete='CASCADE'),
sa.PrimaryKeyConstraint('trunk_segment_id', 'segment_id', 'dot1qtag')
)
op.create_table(
'cisco_n1kv_multi_segments',
sa.Column('multi_segment_id', sa.String(length=36), nullable=False),
sa.Column('segment1_id', sa.String(length=36), nullable=False),
sa.Column('segment2_id', sa.String(length=36), nullable=False),
sa.Column('encap_profile_name', sa.String(length=36), nullable=True),
sa.ForeignKeyConstraint(['multi_segment_id'], ['networks.id'],
ondelete='CASCADE'),
sa.PrimaryKeyConstraint('multi_segment_id', 'segment1_id',
'segment2_id')
)
op.alter_column('cisco_network_profiles', 'segment_type',
existing_type=sa.Enum('vlan', 'vxlan', 'trunk',
'multi-segment'),
existing_nullable=False)
op.add_column('cisco_network_profiles',
sa.Column('sub_type', sa.String(length=255), nullable=True))
def downgrade(active_plugins=None, options=None):
if not migration.should_run(active_plugins, migration_for_plugins):
return
op.drop_table('cisco_n1kv_trunk_segments')
op.drop_table('cisco_n1kv_multi_segments')
op.alter_column('cisco_network_profiles', 'segment_type',
existing_type=sa.Enum('vlan', 'vxlan'),
existing_nullable=False)
op.drop_column('cisco_network_profiles', 'sub_type')

View File

@ -77,6 +77,12 @@ NETWORK_TYPE_VLAN = 'vlan'
NETWORK_TYPE_VXLAN = 'vxlan'
NETWORK_TYPE_LOCAL = 'local'
NETWORK_TYPE_NONE = 'none'
NETWORK_TYPE_TRUNK = 'trunk'
NETWORK_TYPE_MULTI_SEGMENT = 'multi-segment'
# Values for network sub_type
NETWORK_SUBTYPE_TRUNK_VLAN = NETWORK_TYPE_VLAN
NETWORK_SUBTYPE_TRUNK_VXLAN = NETWORK_TYPE_VXLAN
# Prefix for VM Network name
VM_NETWORK_NAME_PREFIX = 'vmn_'
@ -88,3 +94,14 @@ NAME = 'name'
ID = 'id'
POLICY = 'policy'
TENANT_ID_NOT_SET = 'TENANT_ID_NOT_SET'
ENCAPSULATIONS = 'encapsulations'
STATE = 'state'
ONLINE = 'online'
MAPPINGS = 'mappings'
MAPPING = 'mapping'
SEGMENTS = 'segments'
SEGMENT = 'segment'
BRIDGE_DOMAIN_SUFFIX = '_bd'
ENCAPSULATION_PROFILE_SUFFIX = '_profile'
UUID_LENGTH = 36

View File

@ -212,3 +212,8 @@ class ProfileTenantBindingNotFound(exceptions.NotFound):
"""Profile to Tenant binding for given profile ID cannot be found."""
message = _("Profile-Tenant binding for profile %(profile_id)s could "
"not be found.")
class NoClusterFound(exceptions.NotFound):
"""No service cluster found to perform multi-segment bridging."""
message = _("No service cluster found to perform multi-segment bridging.")

View File

@ -40,6 +40,230 @@ def initialize():
db.configure_db()
def del_trunk_segment_binding(db_session, trunk_segment_id, segment_pairs):
"""
Delete a trunk network binding.
:param db_session: database session
:param trunk_segment_id: UUID representing the trunk network
:param segment_pairs: List of segment UUIDs in pair
representing the segments that are trunked
"""
with db_session.begin(subtransactions=True):
for (segment_id, dot1qtag) in segment_pairs:
(db_session.query(n1kv_models_v2.N1kvTrunkSegmentBinding).
filter_by(trunk_segment_id=trunk_segment_id,
segment_id=segment_id,
dot1qtag=dot1qtag).delete())
alloc = (db_session.query(n1kv_models_v2.
N1kvTrunkSegmentBinding).
filter_by(trunk_segment_id=trunk_segment_id).first())
if not alloc:
binding = get_network_binding(db_session, trunk_segment_id)
binding.physical_network = None
def del_multi_segment_binding(db_session, multi_segment_id, segment_pairs):
"""
Delete a multi-segment network binding.
:param db_session: database session
:param multi_segment_id: UUID representing the multi-segment network
:param segment_pairs: List of segment UUIDs in pair
representing the segments that are bridged
"""
with db_session.begin(subtransactions=True):
for (segment1_id, segment2_id) in segment_pairs:
(db_session.query(n1kv_models_v2.
N1kvMultiSegmentNetworkBinding).filter_by(
multi_segment_id=multi_segment_id,
segment1_id=segment1_id,
segment2_id=segment2_id).delete())
def add_trunk_segment_binding(db_session, trunk_segment_id, segment_pairs):
"""
Create a trunk network binding.
:param db_session: database session
:param trunk_segment_id: UUID representing the multi-segment network
:param segment_pairs: List of segment UUIDs in pair
representing the segments to be trunked
"""
with db_session.begin(subtransactions=True):
binding = get_network_binding(db_session, trunk_segment_id)
for (segment_id, tag) in segment_pairs:
if not binding.physical_network:
member_seg_binding = get_network_binding(db_session,
segment_id)
binding.physical_network = member_seg_binding.physical_network
trunk_segment_binding = (
n1kv_models_v2.N1kvTrunkSegmentBinding(
trunk_segment_id=trunk_segment_id,
segment_id=segment_id, dot1qtag=tag))
db_session.add(trunk_segment_binding)
def add_multi_segment_binding(db_session, multi_segment_id, segment_pairs):
"""
Create a multi-segment network binding.
:param db_session: database session
:param multi_segment_id: UUID representing the multi-segment network
:param segment_pairs: List of segment UUIDs in pair
representing the segments to be bridged
"""
with db_session.begin(subtransactions=True):
for (segment1_id, segment2_id) in segment_pairs:
multi_segment_binding = (
n1kv_models_v2.N1kvMultiSegmentNetworkBinding(
multi_segment_id=multi_segment_id,
segment1_id=segment1_id,
segment2_id=segment2_id))
db_session.add(multi_segment_binding)
def add_multi_segment_encap_profile_name(db_session, multi_segment_id,
segment_pair, profile_name):
"""
Add the encapsulation profile name to the multi-segment network binding.
:param db_session: database session
:param multi_segment_id: UUID representing the multi-segment network
:param segment_pair: set containing the segment UUIDs that are bridged
"""
with db_session.begin(subtransactions=True):
binding = get_multi_segment_network_binding(db_session,
multi_segment_id,
segment_pair)
binding.encap_profile_name = profile_name
def get_multi_segment_network_binding(db_session,
multi_segment_id, segment_pair):
"""
Retrieve multi-segment network binding.
:param db_session: database session
:param multi_segment_id: UUID representing the trunk network whose binding
is to fetch
:param segment_pair: set containing the segment UUIDs that are bridged
:returns: binding object
"""
try:
(segment1_id, segment2_id) = segment_pair
return (db_session.query(
n1kv_models_v2.N1kvMultiSegmentNetworkBinding).
filter_by(multi_segment_id=multi_segment_id,
segment1_id=segment1_id,
segment2_id=segment2_id)).one()
except exc.NoResultFound:
raise c_exc.NetworkBindingNotFound(network_id=multi_segment_id)
def get_multi_segment_members(db_session, multi_segment_id):
"""
Retrieve all the member segments of a multi-segment network.
:param db_session: database session
:param multi_segment_id: UUID representing the multi-segment network
:returns: a list of tuples representing the mapped segments
"""
with db_session.begin(subtransactions=True):
allocs = (db_session.query(
n1kv_models_v2.N1kvMultiSegmentNetworkBinding).
filter_by(multi_segment_id=multi_segment_id))
return [(a.segment1_id, a.segment2_id) for a in allocs]
def get_multi_segment_encap_dict(db_session, multi_segment_id):
"""
Retrieve the encapsulation profiles for every segment pairs bridged.
:param db_session: database session
:param multi_segment_id: UUID representing the multi-segment network
:returns: a dictionary of lists containing the segment pairs in sets
"""
with db_session.begin(subtransactions=True):
encap_dict = {}
allocs = (db_session.query(
n1kv_models_v2.N1kvMultiSegmentNetworkBinding).
filter_by(multi_segment_id=multi_segment_id))
for alloc in allocs:
if alloc.encap_profile_name not in encap_dict:
encap_dict[alloc.encap_profile_name] = []
seg_pair = (alloc.segment1_id, alloc.segment2_id)
encap_dict[alloc.encap_profile_name].append(seg_pair)
return encap_dict
def get_trunk_network_binding(db_session, trunk_segment_id, segment_pair):
"""
Retrieve trunk network binding.
:param db_session: database session
:param trunk_segment_id: UUID representing the trunk network whose binding
is to fetch
:param segment_pair: set containing the segment_id and dot1qtag
:returns: binding object
"""
try:
(segment_id, dot1qtag) = segment_pair
return (db_session.query(n1kv_models_v2.N1kvTrunkSegmentBinding).
filter_by(trunk_segment_id=trunk_segment_id,
segment_id=segment_id,
dot1qtag=dot1qtag)).one()
except exc.NoResultFound:
raise c_exc.NetworkBindingNotFound(network_id=trunk_segment_id)
def get_trunk_members(db_session, trunk_segment_id):
"""
Retrieve all the member segments of a trunk network.
:param db_session: database session
:param trunk_segment_id: UUID representing the trunk network
:returns: a list of tuples representing the segment and their
corresponding dot1qtag
"""
with db_session.begin(subtransactions=True):
allocs = (db_session.query(n1kv_models_v2.N1kvTrunkSegmentBinding).
filter_by(trunk_segment_id=trunk_segment_id))
return [(a.segment_id, a.dot1qtag) for a in allocs]
def is_trunk_member(db_session, segment_id):
"""
Checks if a segment is a member of a trunk segment.
:param db_session: database session
:param segment_id: UUID of the segment to be checked
:returns: boolean
"""
with db_session.begin(subtransactions=True):
ret = (db_session.query(n1kv_models_v2.N1kvTrunkSegmentBinding).
filter_by(segment_id=segment_id).first())
return bool(ret)
def is_multi_segment_member(db_session, segment_id):
"""
Checks if a segment is a member of a multi-segment network.
:param db_session: database session
:param segment_id: UUID of the segment to be checked
:returns: boolean
"""
with db_session.begin(subtransactions=True):
ret1 = (db_session.query(
n1kv_models_v2.N1kvMultiSegmentNetworkBinding).
filter_by(segment1_id=segment_id).first())
ret2 = (db_session.query(
n1kv_models_v2.N1kvMultiSegmentNetworkBinding).
filter_by(segment2_id=segment_id).first())
return bool(ret1 or ret2)
def get_network_binding(db_session, network_id):
"""
Retrieve network binding.
@ -59,13 +283,14 @@ def get_network_binding(db_session, network_id):
def add_network_binding(db_session, network_id, network_type,
physical_network, segmentation_id,
multicast_ip, network_profile_id):
multicast_ip, network_profile_id, add_segments):
"""
Create network binding.
:param db_session: database session
:param network_id: UUID representing the network
:param network_type: string representing type of network (VLAN or VXLAN)
:param network_type: string representing type of network (VLAN, VXLAN,
MULTI_SEGMENT or TRUNK)
:param physical_network: Only applicable for VLAN networks. It
represents a L2 Domain
:param segmentation_id: integer representing VLAN or VXLAN ID
@ -75,6 +300,8 @@ def add_network_binding(db_session, network_id, network_type,
IDs.
:param network_profile_id: network profile ID based on which this network
is created
:param add_segments: List of segment UUIDs in pairs to be added to either a
multi-segment or trunk network
"""
with db_session.begin(subtransactions=True):
binding = n1kv_models_v2.N1kvNetworkBinding(
@ -85,6 +312,12 @@ def add_network_binding(db_session, network_id, network_type,
multicast_ip=multicast_ip,
profile_id=network_profile_id)
db_session.add(binding)
if add_segments is None:
pass
elif network_type == c_const.NETWORK_TYPE_MULTI_SEGMENT:
add_multi_segment_binding(db_session, network_id, add_segments)
elif network_type == c_const.NETWORK_TYPE_TRUNK:
add_trunk_segment_binding(db_session, network_id, add_segments)
def get_segment_range(network_profile):
@ -262,6 +495,8 @@ def reserve_vlan(db_session, network_profile):
filter(and_(
n1kv_models_v2.N1kvVlanAllocation.vlan_id >= seg_min,
n1kv_models_v2.N1kvVlanAllocation.vlan_id <= seg_max,
n1kv_models_v2.N1kvVlanAllocation.physical_network ==
network_profile['physical_network'],
n1kv_models_v2.N1kvVlanAllocation.allocated == False)
)).first()
if alloc:
@ -314,8 +549,9 @@ def alloc_network(db_session, network_profile_id):
network_profile_id)
if network_profile.segment_type == c_const.NETWORK_TYPE_VLAN:
return reserve_vlan(db_session, network_profile)
else:
if network_profile.segment_type == c_const.NETWORK_TYPE_VXLAN:
return reserve_vxlan(db_session, network_profile)
return (None, network_profile.segment_type, 0, "0.0.0.0")
def reserve_specific_vlan(db_session, physical_network, vlan_id):
@ -601,14 +837,17 @@ def create_network_profile(db_session, network_profile):
LOG.debug(_("create_network_profile()"))
with db_session.begin(subtransactions=True):
kwargs = {"name": network_profile["name"],
"segment_type": network_profile["segment_type"],
"segment_range": network_profile["segment_range"]}
"segment_type": network_profile["segment_type"]}
if network_profile["segment_type"] == c_const.NETWORK_TYPE_VLAN:
kwargs["physical_network"] = network_profile["physical_network"]
kwargs["segment_range"] = network_profile["segment_range"]
elif network_profile["segment_type"] == c_const.NETWORK_TYPE_VXLAN:
kwargs["multicast_ip_index"] = 0
kwargs["multicast_ip_range"] = network_profile[
"multicast_ip_range"]
kwargs["segment_range"] = network_profile["segment_range"]
elif network_profile["segment_type"] == c_const.NETWORK_TYPE_TRUNK:
kwargs["sub_type"] = network_profile["sub_type"]
net_profile = n1kv_models_v2.NetworkProfile(**kwargs)
db_session.add(net_profile)
return net_profile
@ -659,8 +898,7 @@ def _get_network_profiles(**kwargs):
if "physical_network" in kwargs:
return (db_session.query(n1kv_models_v2.NetworkProfile).
filter_by(physical_network=kwargs["physical_network"]))
else:
return db_session.query(n1kv_models_v2.NetworkProfile)
return db_session.query(n1kv_models_v2.NetworkProfile)
def create_policy_profile(policy_profile):
@ -730,9 +968,8 @@ def _profile_binding_exists(tenant_id, profile_id, profile_type):
def _get_profile_binding(tenant_id, profile_id):
LOG.debug(_("_get_profile_binding"))
db_session = db.get_session()
binding = db_session.query(n1kv_models_v2.ProfileBinding).filter_by(
tenant_id=tenant_id, profile_id=profile_id).one()
return binding
return (db_session.query(n1kv_models_v2.ProfileBinding).filter_by(
tenant_id=tenant_id, profile_id=profile_id).one())
def get_profile_binding(tenant_id, profile_id):
@ -773,8 +1010,7 @@ def _get_profile_bindings(profile_type=None):
profile_bindings = (db_session.query(n1kv_models_v2.ProfileBinding).
filter_by(profile_type=profile_type))
return profile_bindings
else:
return db_session.query(n1kv_models_v2.ProfileBinding)
return db_session.query(n1kv_models_v2.ProfileBinding)
class NetworkProfile_db_mixin(object):
@ -815,6 +1051,7 @@ class NetworkProfile_db_mixin(object):
res = {"id": network_profile["id"],
"name": network_profile["name"],
"segment_type": network_profile["segment_type"],
"sub_type": network_profile["sub_type"],
"segment_range": network_profile["segment_range"],
"multicast_ip_index": network_profile["multicast_ip_index"],
"multicast_ip_range": network_profile["multicast_ip_range"],
@ -888,13 +1125,12 @@ class NetworkProfile_db_mixin(object):
self.add_network_profile_tenant(id, p["add_tenant"])
return self._make_network_profile_dict(get_network_profile(
context.session, id))
elif context.is_admin and "remove_tenant" in p:
if context.is_admin and "remove_tenant" in p:
delete_profile_binding(p["remove_tenant"], id)
return self._make_network_profile_dict(get_network_profile(
context.session, id))
else:
return self._make_network_profile_dict(
update_network_profile(context.session, id, p))
return self._make_network_profile_dict(
update_network_profile(context.session, id, p))
def get_network_profile(self, context, id, fields=None):
"""
@ -930,11 +1166,10 @@ class NetworkProfile_db_mixin(object):
return self._get_collection(context, n1kv_models_v2.NetworkProfile,
self._make_network_profile_dict,
filters=filters, fields=fields)
else:
return self._get_network_collection_for_tenant(context.session,
n1kv_models_v2.
NetworkProfile,
context.tenant_id)
return self._get_network_collection_for_tenant(context.session,
n1kv_models_v2.
NetworkProfile,
context.tenant_id)
def add_network_profile_tenant(self, network_profile_id, tenant_id):
"""
@ -992,19 +1227,41 @@ class NetworkProfile_db_mixin(object):
:param net_p: network profile object
"""
if any(net_p[arg] == "" for arg in ("segment_type", "segment_range")):
msg = _("arguments segment_type and segment_range missing"
if any(net_p[arg] == "" for arg in ["segment_type"]):
msg = _("arguments segment_type missing"
" for network profile")
LOG.exception(msg)
raise q_exc.InvalidInput(error_message=msg)
_segment_type = net_p["segment_type"].lower()
if _segment_type not in [c_const.NETWORK_TYPE_VLAN,
c_const.NETWORK_TYPE_VXLAN]:
msg = _("segment_type should either be vlan or vxlan")
segment_type = net_p["segment_type"].lower()
if segment_type not in [c_const.NETWORK_TYPE_VLAN,
c_const.NETWORK_TYPE_VXLAN,
c_const.NETWORK_TYPE_TRUNK,
c_const.NETWORK_TYPE_MULTI_SEGMENT]:
msg = _("segment_type should either be vlan, vxlan, "
"multi-segment or trunk")
LOG.exception(msg)
raise q_exc.InvalidInput(error_message=msg)
self._validate_segment_range(net_p)
if _segment_type == c_const.NETWORK_TYPE_VLAN:
if segment_type == c_const.NETWORK_TYPE_VLAN:
if "physical_network" not in net_p:
msg = _("argument physical_network missing "
"for network profile")
LOG.exception(msg)
raise q_exc.InvalidInput(error_message=msg)
if segment_type == c_const.NETWORK_TYPE_TRUNK:
if "sub_type" not in net_p:
msg = _("argument sub_type missing "
"for trunk network profile")
LOG.exception(msg)
raise q_exc.InvalidInput(error_message=msg)
if segment_type in [c_const.NETWORK_TYPE_VLAN,
c_const.NETWORK_TYPE_VXLAN]:
if "segment_range" not in net_p:
msg = _("argument segment_range missing "
"for network profile")
LOG.exception(msg)
raise q_exc.InvalidInput(error_message=msg)
self._validate_segment_range(net_p)
if segment_type != c_const.NETWORK_TYPE_VXLAN:
net_p["multicast_ip_range"] = "0.0.0.0"
def _validate_segment_range_uniqueness(self, context, net_p):
@ -1018,28 +1275,30 @@ class NetworkProfile_db_mixin(object):
if segment_type == c_const.NETWORK_TYPE_VLAN:
profiles = _get_network_profiles(
physical_network=net_p["physical_network"])
elif segment_type == c_const.NETWORK_TYPE_VXLAN:
profiles = _get_network_profiles()
else:
# TODO(Abhishek): Handle this when we support other segment types
return
profiles = _get_network_profiles()
if profiles:
for prfl in profiles:
name = prfl.name
segment_range = prfl.segment_range
for profile in profiles:
name = profile.name
segment_range = profile.segment_range
if net_p["name"] == name:
msg = (_("NetworkProfile name %s already exists"),
net_p["name"])
LOG.exception(msg)
raise q_exc.InvalidInput(error_message=msg)
if (c_const.NETWORK_TYPE_MULTI_SEGMENT in
[profile.segment_type, net_p["segment_type"]] or
c_const.NETWORK_TYPE_TRUNK in
[profile.segment_type, net_p["segment_type"]]):
continue
seg_min, seg_max = self._get_segment_range(
net_p["segment_range"])
prfl_seg_min, prfl_seg_max = self._get_segment_range(
profile_seg_min, profile_seg_max = self._get_segment_range(
segment_range)
if ((prfl_seg_min <= seg_min <= prfl_seg_max) or
(prfl_seg_min <= seg_max <= prfl_seg_max) or
((seg_min <= prfl_seg_min) and
(seg_max >= prfl_seg_max))):
if ((profile_seg_min <= seg_min <= profile_seg_max) or
(profile_seg_min <= seg_max <= profile_seg_max) or
((seg_min <= profile_seg_min) and
(seg_max >= profile_seg_max))):
msg = _("segment range overlaps with another profile")
LOG.exception(msg)
raise q_exc.InvalidInput(error_message=msg)
@ -1149,13 +1408,12 @@ class PolicyProfile_db_mixin(object):
self.add_policy_profile_tenant(id, p["add_tenant"])
return self._make_policy_profile_dict(get_policy_profile(
context.session, id))
elif context.is_admin and "remove_tenant" in p:
if context.is_admin and "remove_tenant" in p:
delete_profile_binding(p["remove_tenant"], id)
return self._make_policy_profile_dict(get_policy_profile(
context.session, id))
else:
return self._make_policy_profile_dict(
update_policy_profile(context.session, id, p))
return self._make_policy_profile_dict(
update_policy_profile(context.session, id, p))
def add_policy_profile_tenant(self, policy_profile_id, tenant_id):
"""

View File

@ -15,6 +15,7 @@
# under the License.
#
# @author: Abhishek Raut, Cisco Systems Inc.
# @author: Rudrajit Tapadar, Cisco Systems Inc.
import sqlalchemy as sa
@ -95,7 +96,8 @@ class NetworkProfile(model_base.BASEV2, models_v2.HasId):
"""
Nexus1000V Network Profiles
segment_type - VLAN, VXLAN
segment_type - VLAN, VXLAN, TRUNK, MULTI_SEGMENT
sub_type - TRUNK_VLAN, TRUNK_VXLAN
segment_range - '<integer>-<integer>'
multicast_ip_index - <integer>
multicast_ip_range - '<ip>-<ip>'
@ -106,8 +108,12 @@ class NetworkProfile(model_base.BASEV2, models_v2.HasId):
name = sa.Column(sa.String(255))
segment_type = sa.Column(sa.Enum(cisco_constants.NETWORK_TYPE_VLAN,
cisco_constants.NETWORK_TYPE_VXLAN,
cisco_constants.NETWORK_TYPE_TRUNK,
cisco_constants.
NETWORK_TYPE_MULTI_SEGMENT,
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))
@ -142,3 +148,30 @@ class ProfileBinding(model_base.BASEV2):
primary_key=True,
default=cisco_constants.TENANT_ID_NOT_SET)
profile_id = sa.Column(sa.String(36), primary_key=True)
class N1kvTrunkSegmentBinding(model_base.BASEV2):
"""Represents binding of segments in trunk networks."""
__tablename__ = 'cisco_n1kv_trunk_segments'
trunk_segment_id = sa.Column(sa.String(36),
sa.ForeignKey('networks.id',
ondelete="CASCADE"),
primary_key=True)
segment_id = sa.Column(sa.String(36), nullable=False, primary_key=True)
dot1qtag = sa.Column(sa.String(36), nullable=False, primary_key=True)
class N1kvMultiSegmentNetworkBinding(model_base.BASEV2):
"""Represents binding of segments in multi-segment networks."""
__tablename__ = 'cisco_n1kv_multi_segments'
multi_segment_id = sa.Column(sa.String(36),
sa.ForeignKey('networks.id',
ondelete="CASCADE"),
primary_key=True)
segment1_id = sa.Column(sa.String(36), nullable=False, primary_key=True)
segment2_id = sa.Column(sa.String(36), nullable=False, primary_key=True)
encap_profile_name = sa.Column(sa.String(36))

View File

@ -24,6 +24,9 @@ from neutron.api.v2 import attributes
PROFILE_ID = 'n1kv:profile_id'
MULTICAST_IP = 'n1kv:multicast_ip'
SEGMENT_ADD = 'n1kv:segment_add'
SEGMENT_DEL = 'n1kv:segment_del'
MEMBER_SEGMENTS = 'n1kv:member_segments'
EXTENDED_ATTRIBUTES_2_0 = {
'networks': {
@ -34,6 +37,15 @@ EXTENDED_ATTRIBUTES_2_0 = {
MULTICAST_IP: {'allow_post': True, 'allow_put': True,
'default': attributes.ATTR_NOT_SPECIFIED,
'is_visible': True},
SEGMENT_ADD: {'allow_post': True, 'allow_put': True,
'default': attributes.ATTR_NOT_SPECIFIED,
'is_visible': True},
SEGMENT_DEL: {'allow_post': True, 'allow_put': True,
'default': attributes.ATTR_NOT_SPECIFIED,
'is_visible': True},
MEMBER_SEGMENTS: {'allow_post': True, 'allow_put': True,
'default': attributes.ATTR_NOT_SPECIFIED,
'is_visible': True},
},
'ports': {
PROFILE_ID: {'allow_post': True, 'allow_put': True,

View File

@ -16,6 +16,7 @@
#
# @author: Abhishek Raut, Cisco Systems, Inc.
# @author: Sergey Sudakovich, Cisco Systems, Inc.
# @author: Rudrajit Tapadar, Cisco Systems, Inc.
from neutron.api import extensions
from neutron.api.v2 import attributes
@ -33,6 +34,9 @@ RESOURCE_ATTRIBUTE_MAP = {
'is_visible': True, 'default': ''},
'segment_type': {'allow_post': True, 'allow_put': True,
'is_visible': True, 'default': ''},
'sub_type': {'allow_post': True, 'allow_put': True,
'is_visible': True,
'default': attributes.ATTR_NOT_SPECIFIED},
'segment_range': {'allow_post': True, 'allow_put': True,
'is_visible': True, 'default': ''},
'multicast_ip_range': {'allow_post': True, 'allow_put': True,
@ -82,7 +86,7 @@ class Network_profile(extensions.ExtensionDescriptor):
@classmethod
def get_resources(cls):
"""Returns Ext Resources."""
"""Returns Extended Resources."""
exts = []
plugin = manager.NeutronManager.get_plugin()
for resource_name in ['network_profile', 'network_profile_binding']:

View File

@ -69,7 +69,7 @@ class Policy_profile(extensions.ExtensionDescriptor):
@classmethod
def get_resources(cls):
"""Returns Ext Resources."""
"""Returns Extended Resources."""
exts = []
plugin = manager.NeutronManager.get_plugin()
for resource_name in ['policy_profile', 'policy_profile_binding']:

View File

@ -15,6 +15,7 @@
# under the License.
#
# @author: Abhishek Raut, Cisco Systems, Inc.
# @author: Rudrajit Tapadar, Cisco Systems, Inc.
import base64
import httplib2
@ -117,7 +118,9 @@ class Client(object):
"networks": "network",
"ports": "port",
"set": "instance",
"subnets": "subnet"
"subnets": "subnet",
"mappings": "mapping",
"segments": "segment"
}
}
@ -138,6 +141,9 @@ class Client(object):
logical_networks_path = "/logical-network"
logical_network_path = "/logical-network/%s"
events_path = "/kvm/events"
clusters_path = "/cluster"
encap_profiles_path = "/encapsulation-profile"
encap_profile_path = "/encapsulation-profile/%s"
def __init__(self, **kwargs):
"""Initialize a new client for the plugin."""
@ -171,7 +177,7 @@ class Client(object):
:param network: network dict
"""
body = {'name': network['name'] + '_bd',
body = {'name': network['name'] + c_const.BRIDGE_DOMAIN_SUFFIX,
'segmentId': network[providernet.SEGMENTATION_ID],
'groupIp': network[n1kv_profile.MULTICAST_IP], }
return self._post(self.bridge_domains_path,
@ -199,7 +205,20 @@ class Client(object):
if network[providernet.NETWORK_TYPE] == c_const.NETWORK_TYPE_VLAN:
body['vlan'] = network[providernet.SEGMENTATION_ID]
elif network[providernet.NETWORK_TYPE] == c_const.NETWORK_TYPE_VXLAN:
body['bridgeDomain'] = network['name'] + '_bd'
body['bridgeDomain'] = (network['name'] +
c_const.BRIDGE_DOMAIN_SUFFIX)
if network_profile['segment_type'] == c_const.NETWORK_TYPE_TRUNK:
body['mode'] = c_const.NETWORK_TYPE_TRUNK
body['segmentType'] = network_profile['sub_type']
if network_profile['sub_type'] == c_const.NETWORK_TYPE_VLAN:
body['addSegments'] = network['add_segment_list']
body['delSegments'] = network['del_segment_list']
else:
body['encapProfile'] = (network['name'] +
c_const.ENCAPSULATION_PROFILE_SUFFIX)
else:
body['mode'] = 'access'
body['segmentType'] = network_profile['segment_type']
return self._post(self.network_segments_path,
body=body)
@ -498,3 +517,37 @@ class Client(object):
auth = base64.encodestring("%s:%s" % (username, password))
header = {"Authorization": "Basic %s" % auth}
return header
def get_clusters(self):
"""Fetches a list of all vxlan gateway clusters."""
return self._get(self.clusters_path)
def create_encapsulation_profile(self, encap):
"""
Create an encapsulation profile on VSM.
:param encap: encapsulation dict
"""
body = {'name': encap['name'],
'addMappings': encap['add_segment_list'],
'delMappings': encap['del_segment_list']}
return self._post(self.encap_profiles_path,
body=body)
def update_encapsulation_profile(self, context, profile_name, body):
"""
Adds a vlan to bridge-domain mapping to an encapsulation profile.
:param profile_name: Name of the encapsulation profile
:param body: mapping dictionary
"""
return self._post(self.encap_profile_path
% (profile_name), body=body)
def delete_encapsulation_profile(self, name):
"""
Delete an encapsulation profile on VSM.
:param name: name of the encapsulation profile to be deleted
"""
return self._delete(self.encap_profile_path % (name))

View File

@ -30,6 +30,7 @@ from neutron.api.v2 import attributes
from neutron.common import exceptions as q_exc
from neutron.common import rpc as q_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
@ -41,6 +42,7 @@ from neutron.extensions import providernet
from neutron.openstack.common import log as logging
from neutron.openstack.common import rpc
from neutron.openstack.common.rpc import proxy
from neutron.openstack.common import uuidutils as uuidutils
from neutron.plugins.cisco.common import cisco_constants as c_const
from neutron.plugins.cisco.common import cisco_credentials_v2 as c_cred
from neutron.plugins.cisco.common import cisco_exceptions
@ -281,6 +283,14 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
elif binding.network_type == c_const.NETWORK_TYPE_VLAN:
network[providernet.PHYSICAL_NETWORK] = binding.physical_network
network[providernet.SEGMENTATION_ID] = binding.segmentation_id
elif binding.network_type == c_const.NETWORK_TYPE_TRUNK:
network[providernet.PHYSICAL_NETWORK] = binding.physical_network
network[providernet.SEGMENTATION_ID] = None
network[n1kv_profile.MULTICAST_IP] = None
elif binding.network_type == c_const.NETWORK_TYPE_MULTI_SEGMENT:
network[providernet.PHYSICAL_NETWORK] = None
network[providernet.SEGMENTATION_ID] = None
network[n1kv_profile.MULTICAST_IP] = None
def _process_provider_create(self, context, attrs):
network_type = attrs.get(providernet.NETWORK_TYPE)
@ -356,6 +366,283 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
msg = _("plugin does not support updating provider attributes")
raise q_exc.InvalidInput(error_message=msg)
def _get_cluster(self, segment1, segment2, clusters):
"""
Returns a cluster to apply the segment mapping
:param segment1: UUID of segment to be mapped
:param segment2: UUID of segment to be mapped
:param clusters: List of clusters
"""
for cluster in sorted(clusters, key=lambda k: k['size']):
for mapping in cluster[c_const.MAPPINGS]:
for segment in mapping[c_const.SEGMENTS]:
if segment1 in segment or segment2 in segment:
break
else:
cluster['size'] += 2
return cluster['encapProfileName']
break
return
def _extend_mapping_dict(self, context, mapping_dict, segment):
"""
Extends a mapping dictionary by populating dot1q tag and
bridge-domain name.
:param context: neutron api request context
:param mapping_dict: dictionary to populate values
:param segment: id of the segment being populated
"""
net = self.get_network(context, segment)
if net[providernet.NETWORK_TYPE] == c_const.NETWORK_TYPE_VLAN:
mapping_dict['dot1q'] = str(net[providernet.SEGMENTATION_ID])
else:
mapping_dict['bridgeDomain'] = (net['name'] +
c_const.BRIDGE_DOMAIN_SUFFIX)
def _send_add_multi_segment_request(self, context, net_id, segment_pairs):
"""
Send Add multi-segment network request to VSM.
:param context: neutron api request context
:param net_id: UUID of the multi-segment network
:param segment_pairs: List of segments in UUID pairs
that need to be bridged
"""
if not segment_pairs:
return
session = context.session
n1kvclient = n1kv_client.Client()
clusters = n1kvclient.get_clusters()
online_clusters = []
encap_dict = {}
for cluster in clusters['body'][c_const.SET]:
cluster = cluster[c_const.PROPERTIES]
if cluster[c_const.STATE] == c_const.ONLINE:
cluster['size'] = 0
for mapping in cluster[c_const.MAPPINGS]:
cluster['size'] += (
len(mapping[c_const.SEGMENTS]))
online_clusters.append(cluster)
for (segment1, segment2) in segment_pairs:
encap_profile = self._get_cluster(segment1, segment2,
online_clusters)
if encap_profile is not None:
if encap_profile in encap_dict:
profile_dict = encap_dict[encap_profile]
else:
profile_dict = {'name': encap_profile,
'addMappings': [],
'delMappings': []}
encap_dict[encap_profile] = profile_dict
mapping_dict = {}
self._extend_mapping_dict(context,
mapping_dict, segment1)
self._extend_mapping_dict(context,
mapping_dict, segment2)
profile_dict['addMappings'].append(mapping_dict)
n1kv_db_v2.add_multi_segment_encap_profile_name(session,
net_id,
(segment1,
segment2),
encap_profile)
else:
raise cisco_exceptions.NoClusterFound
for profile in encap_dict:
n1kvclient.update_encapsulation_profile(context, profile,
encap_dict[profile])
def _send_del_multi_segment_request(self, context, net_id, segment_pairs):
"""
Send Delete multi-segment network request to VSM.
:param context: neutron api request context
:param net_id: UUID of the multi-segment network
:param segment_pairs: List of segments in UUID pairs
whose bridging needs to be removed
"""
if not segment_pairs:
return
session = context.session
encap_dict = {}
n1kvclient = n1kv_client.Client()
for (segment1, segment2) in segment_pairs:
binding = (
n1kv_db_v2.get_multi_segment_network_binding(session, net_id,
(segment1,
segment2)))
encap_profile = binding['encap_profile_name']
if encap_profile in encap_dict:
profile_dict = encap_dict[encap_profile]
else:
profile_dict = {'name': encap_profile,
'addMappings': [],
'delMappings': []}
encap_dict[encap_profile] = profile_dict
mapping_dict = {}
self._extend_mapping_dict(context,
mapping_dict, segment1)
self._extend_mapping_dict(context,
mapping_dict, segment2)
profile_dict['delMappings'].append(mapping_dict)
for profile in encap_dict:
n1kvclient.update_encapsulation_profile(context, profile,
encap_dict[profile])
def _get_encap_segments(self, context, segment_pairs):
"""
Get the list of segments in encapsulation profile format.
:param context: neutron api request context
:param segment_pairs: List of segments that need to be bridged
"""
member_list = []
for pair in segment_pairs:
(segment, dot1qtag) = pair
member_dict = {}
net = self.get_network(context, segment)
member_dict['bridgeDomain'] = (net['name'] +
c_const.BRIDGE_DOMAIN_SUFFIX)
member_dict['dot1q'] = dot1qtag
member_list.append(member_dict)
return member_list
def _populate_member_segments(self, context, network, segment_pairs, oper):
"""
Populate trunk network dict with member segments.
:param context: neutron api request context
:param network: Dictionary containing the trunk network information
:param segment_pairs: List of segments in UUID pairs
that needs to be trunked
:param oper: Operation to be performed
"""
LOG.debug(_('_populate_member_segments %s'), segment_pairs)
trunk_list = []
for (segment, dot1qtag) in segment_pairs:
net = self.get_network(context, segment)
member_dict = {'segment': net['name'],
'dot1qtag': dot1qtag}
trunk_list.append(member_dict)
if oper == n1kv_profile.SEGMENT_ADD:
network['add_segment_list'] = trunk_list
elif oper == n1kv_profile.SEGMENT_DEL:
network['del_segment_list'] = trunk_list
def _parse_multi_segments(self, context, attrs, param):
"""
Parse the multi-segment network attributes
:param context: neutron api request context
:param attrs: Attributes of the network
:param param: Additional parameter indicating an add
or del operation
:returns: List of segment UUIDs in set pairs
"""
pair_list = []
valid_seg_types = [c_const.NETWORK_TYPE_VLAN,
c_const.NETWORK_TYPE_VXLAN]
segments = attrs.get(param)
if not attributes.is_attr_set(segments):
return pair_list
for pair in segments.split(','):
segment1, sep, segment2 = pair.partition(':')
if (uuidutils.is_uuid_like(segment1) and
uuidutils.is_uuid_like(segment2)):
binding1 = n1kv_db_v2.get_network_binding(context.session,
segment1)
binding2 = n1kv_db_v2.get_network_binding(context.session,
segment2)
if (binding1.network_type not in valid_seg_types or
binding2.network_type not in valid_seg_types or
binding1.network_type == binding2.network_type):
msg = _("Invalid pairing supplied")
raise q_exc.InvalidInput(error_message=msg)
else:
pair_list.append((segment1, segment2))
else:
LOG.debug(_('Invalid UUID supplied in %s'), pair)
msg = _("Invalid UUID supplied")
raise q_exc.InvalidInput(error_message=msg)
return pair_list
def _parse_trunk_segments(self, context, attrs, param, physical_network,
sub_type):
"""
Parse the trunk network attributes
:param context: neutron api request context
:param attrs: Attributes of the network
:param param: Additional parameter indicating an add
or del operation
:param physical_network: Physical network of the trunk segment
:param sub_type: Sub-type of the trunk segment
:returns: List of segment UUIDs and dot1qtag (for vxlan) in set pairs
"""
pair_list = []
segments = attrs.get(param)
if not attributes.is_attr_set(segments):
return pair_list
for pair in segments.split(','):
segment, sep, dot1qtag = pair.partition(':')
if sub_type == c_const.NETWORK_TYPE_VLAN:
dot1qtag = ''
if uuidutils.is_uuid_like(segment):
binding = n1kv_db_v2.get_network_binding(context.session,
segment)
if binding.network_type == c_const.NETWORK_TYPE_TRUNK:
msg = _("Cannot add a trunk segment '%s' as a member of "
"another trunk segment") % segment
raise q_exc.InvalidInput(error_message=msg)
elif binding.network_type == c_const.NETWORK_TYPE_VLAN:
if sub_type == c_const.NETWORK_TYPE_VXLAN:
msg = _("Cannot add vlan segment '%s' as a member of "
"a vxlan trunk segment") % segment
raise q_exc.InvalidInput(error_message=msg)
if not physical_network:
physical_network = binding.physical_network
elif physical_network != binding.physical_network:
msg = _("Network UUID '%s' belongs to a different "
"physical network") % segment
raise q_exc.InvalidInput(error_message=msg)
elif binding.network_type == c_const.NETWORK_TYPE_VXLAN:
if sub_type == c_const.NETWORK_TYPE_VLAN:
msg = _("Cannot add vxlan segment '%s' as a member of "
"a vlan trunk segment") % segment
raise q_exc.InvalidInput(error_message=msg)
try:
if not utils.is_valid_vlan_tag(int(dot1qtag)):
msg = _("Vlan tag '%s' is out of range") % dot1qtag
raise q_exc.InvalidInput(error_message=msg)
except ValueError:
msg = _("Vlan tag '%s' is not an integer "
"value") % dot1qtag
raise q_exc.InvalidInput(error_message=msg)
pair_list.append((segment, dot1qtag))
else:
LOG.debug(_('%s is not a valid uuid'), segment)
msg = _("'%s' is not a valid UUID") % segment
raise q_exc.InvalidInput(error_message=msg)
return pair_list
def _extend_network_dict_member_segments(self, context, network):
"""Add the extended parameter member segments to the network."""
members = []
binding = n1kv_db_v2.get_network_binding(context.session,
network['id'])
if binding.network_type == c_const.NETWORK_TYPE_TRUNK:
members = n1kv_db_v2.get_trunk_members(context.session,
network['id'])
elif binding.network_type == c_const.NETWORK_TYPE_MULTI_SEGMENT:
members = n1kv_db_v2.get_multi_segment_members(context.session,
network['id'])
network[n1kv_profile.MEMBER_SEGMENTS] = members
def _extend_network_dict_profile(self, context, network):
"""Add the extended parameter network profile to the network."""
binding = n1kv_db_v2.get_network_binding(context.session,
@ -435,13 +722,15 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
n1kvclient = n1kv_client.Client()
n1kvclient.delete_network_segment_pool(profile['name'])
def _send_create_network_request(self, context, network):
def _send_create_network_request(self, context, network, segment_pairs):
"""
Send create network request to VSM.
Create a bridge domain for network of type VXLAN.
:param context: neutron api request context
:param network: network dictionary
:param segment_pairs: List of segments in UUID pairs
that need to be bridged
"""
LOG.debug(_('_send_create_network_request: %s'), network['id'])
profile = self.get_network_profile(context,
@ -449,36 +738,110 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
n1kvclient = n1kv_client.Client()
if network[providernet.NETWORK_TYPE] == c_const.NETWORK_TYPE_VXLAN:
n1kvclient.create_bridge_domain(network)
if network[providernet.NETWORK_TYPE] == c_const.NETWORK_TYPE_TRUNK:
self._populate_member_segments(context, network, segment_pairs,
n1kv_profile.SEGMENT_ADD)
network['del_segment_list'] = []
if profile['sub_type'] == c_const.NETWORK_TYPE_VXLAN:
encap_dict = {'name': (network['name'] +
c_const.ENCAPSULATION_PROFILE_SUFFIX),
'add_segment_list': (
self._get_encap_segments(context,
segment_pairs)),
'del_segment_list': []}
n1kvclient.create_encapsulation_profile(encap_dict)
n1kvclient.create_network_segment(network, profile)
def _send_update_network_request(self, db_session, network):
def _send_update_network_request(self, context, network, add_segments,
del_segments):
"""
Send update network request to VSM.
:param context: neutron api request context
:param network: network dictionary
:param add_segments: List of segments bindings
that need to be deleted
:param del_segments: List of segments bindings
that need to be deleted
"""
LOG.debug(_('_send_update_network_request: %s'), network['id'])
db_session = context.session
profile = n1kv_db_v2.get_network_profile(
db_session, network[n1kv_profile.PROFILE_ID])
n1kvclient = n1kv_client.Client()
body = {'name': network['name'],
'id': network['id'],
'networkDefinition': profile['name'],
'vlan': network[providernet.SEGMENTATION_ID]}
n1kvclient = n1kv_client.Client()
'vlan': network[providernet.SEGMENTATION_ID],
'mode': 'access',
'segmentType': profile['segment_type'],
'addSegments': [],
'delSegments': []}
if network[providernet.NETWORK_TYPE] == c_const.NETWORK_TYPE_TRUNK:
self._populate_member_segments(context, network, add_segments,
n1kv_profile.SEGMENT_ADD)
self._populate_member_segments(context, network, del_segments,
n1kv_profile.SEGMENT_DEL)
body['mode'] = c_const.NETWORK_TYPE_TRUNK
body['segmentType'] = profile['sub_type']
body['addSegments'] = network['add_segment_list']
body['delSegments'] = network['del_segment_list']
LOG.debug(_('add_segments=%s'), body['addSegments'])
LOG.debug(_('del_segments=%s'), body['delSegments'])
if profile['sub_type'] == c_const.NETWORK_TYPE_VXLAN:
encap_profile = (network['name'] +
c_const.ENCAPSULATION_PROFILE_SUFFIX)
encap_dict = {'name': encap_profile,
'addMappings': (
self._get_encap_segments(context,
add_segments)),
'delMappings': (
self._get_encap_segments(context,
del_segments))}
n1kvclient.update_encapsulation_profile(context, encap_profile,
encap_dict)
n1kvclient.update_network_segment(network['name'], body)
def _send_delete_network_request(self, network):
def _send_delete_network_request(self, context, network):
"""
Send delete network request to VSM.
Delete bridge domain if network is of type VXLAN.
Delete encapsulation profile if network is of type VXLAN Trunk.
:param context: neutron api request context
:param network: network dictionary
"""
LOG.debug(_('_send_delete_network_request: %s'), network['id'])
n1kvclient = n1kv_client.Client()
session = context.session
if network[providernet.NETWORK_TYPE] == c_const.NETWORK_TYPE_VXLAN:
name = network['name'] + '_bd'
name = network['name'] + c_const.BRIDGE_DOMAIN_SUFFIX
n1kvclient.delete_bridge_domain(name)
elif network[providernet.NETWORK_TYPE] == c_const.NETWORK_TYPE_TRUNK:
profile = self.get_network_profile(
context, network[n1kv_profile.PROFILE_ID])
if profile['sub_type'] == c_const.NETWORK_TYPE_VXLAN:
profile_name = (network['name'] +
c_const.ENCAPSULATION_PROFILE_SUFFIX)
n1kvclient.delete_encapsulation_profile(profile_name)
elif (network[providernet.NETWORK_TYPE] ==
c_const.NETWORK_TYPE_MULTI_SEGMENT):
encap_dict = n1kv_db_v2.get_multi_segment_encap_dict(session,
network['id'])
for profile in encap_dict:
profile_dict = {'name': profile,
'addSegments': [],
'delSegments': []}
for segment_pair in encap_dict[profile]:
mapping_dict = {}
(segment1, segment2) = segment_pair
self._extend_mapping_dict(context,
mapping_dict, segment1)
self._extend_mapping_dict(context,
mapping_dict, segment2)
profile_dict['delSegments'].append(mapping_dict)
n1kvclient.update_encapsulation_profile(context, profile,
profile_dict)
n1kvclient.delete_network_segment(network['name'])
def _send_create_subnet_request(self, context, subnet):
@ -616,6 +979,7 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
network['network'])
self._add_dummy_profile_only_if_testing(network)
profile_id = self._process_network_profile(context, network['network'])
segment_pairs = None
LOG.debug(_('create network: profile_id=%s'), profile_id)
session = context.session
with session.begin(subtransactions=True):
@ -632,8 +996,24 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
'net_type': network_type,
'seg_id': segmentation_id,
'multicast_ip': multicast_ip})
if not segmentation_id:
raise q_exc.TenantNetworksDisabled()
if network_type == c_const.NETWORK_TYPE_MULTI_SEGMENT:
segment_pairs = (
self._parse_multi_segments(context, network['network'],
n1kv_profile.SEGMENT_ADD))
LOG.debug(_('seg list %s '), segment_pairs)
elif network_type == c_const.NETWORK_TYPE_TRUNK:
network_profile = self.get_network_profile(context,
profile_id)
segment_pairs = (
self._parse_trunk_segments(context, network['network'],
n1kv_profile.SEGMENT_ADD,
physical_network,
network_profile['sub_type']
))
LOG.debug(_('seg list %s '), segment_pairs)
else:
if not segmentation_id:
raise q_exc.TenantNetworksDisabled()
else:
# provider network
if network_type == c_const.NETWORK_TYPE_VLAN:
@ -655,13 +1035,19 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
physical_network,
segmentation_id,
multicast_ip,
profile_id)
profile_id,
segment_pairs)
self._process_l3_create(context, net, network['network'])
self._extend_network_dict_provider(context, net)
self._extend_network_dict_profile(context, net)
try:
self._send_create_network_request(context, net)
if network_type == c_const.NETWORK_TYPE_MULTI_SEGMENT:
self._send_add_multi_segment_request(context, net['id'],
segment_pairs)
else:
self._send_create_network_request(context, net, segment_pairs)
# note - exception will rollback entire transaction
except(cisco_exceptions.VSMError,
cisco_exceptions.VSMConnectionFailed):
super(N1kvNeutronPluginV2, self).delete_network(context, net['id'])
@ -679,15 +1065,52 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
:returns: updated network object
"""
self._check_provider_update(context, network['network'])
add_segments = []
del_segments = []
session = context.session
with session.begin(subtransactions=True):
net = super(N1kvNeutronPluginV2, self).update_network(context, id,
network)
self._process_l3_update(context, net, network['network'])
binding = n1kv_db_v2.get_network_binding(session, id)
if binding.network_type == c_const.NETWORK_TYPE_MULTI_SEGMENT:
add_segments = (
self._parse_multi_segments(context, network['network'],
n1kv_profile.SEGMENT_ADD))
n1kv_db_v2.add_multi_segment_binding(session,
net['id'], add_segments)
del_segments = (
self._parse_multi_segments(context, network['network'],
n1kv_profile.SEGMENT_DEL))
self._send_add_multi_segment_request(context, net['id'],
add_segments)
self._send_del_multi_segment_request(context, net['id'],
del_segments)
n1kv_db_v2.del_multi_segment_binding(session,
net['id'], del_segments)
elif binding.network_type == c_const.NETWORK_TYPE_TRUNK:
network_profile = self.get_network_profile(context,
binding.profile_id)
add_segments = (
self._parse_trunk_segments(context, network['network'],
n1kv_profile.SEGMENT_ADD,
binding.physical_network,
network_profile['sub_type']))
n1kv_db_v2.add_trunk_segment_binding(session,
net['id'], add_segments)
del_segments = (
self._parse_trunk_segments(context, network['network'],
n1kv_profile.SEGMENT_DEL,
binding.physical_network,
network_profile['sub_type']))
n1kv_db_v2.del_trunk_segment_binding(session,
net['id'], del_segments)
self._extend_network_dict_provider(context, net)
self._extend_network_dict_profile(context, net)
self._send_update_network_request(context.session, net)
if binding.network_type not in [c_const.NETWORK_TYPE_MULTI_SEGMENT]:
self._send_update_network_request(context, net, add_segments,
del_segments)
LOG.debug(_("Updated network: %s"), net['id'])
return net
@ -702,6 +1125,20 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
with session.begin(subtransactions=True):
binding = n1kv_db_v2.get_network_binding(session, id)
network = self.get_network(context, id)
if n1kv_db_v2.is_trunk_member(session, id):
msg = _("Cannot delete a network "
"that is a member of a trunk segment")
raise q_exc.InvalidInput(error_message=msg)
if n1kv_db_v2.is_multi_segment_member(session, id):
msg = _("Cannot delete a network "
"that is a member of a multi-segment network")
raise q_exc.InvalidInput(error_message=msg)
if self.agent_vsm:
try:
self._send_delete_network_request(context, network)
except(cisco_exceptions.VSMError,
cisco_exceptions.VSMConnectionFailed):
LOG.debug(_('Delete failed in VSM'))
super(N1kvNeutronPluginV2, self).delete_network(context, id)
if binding.network_type == c_const.NETWORK_TYPE_VXLAN:
n1kv_db_v2.release_vxlan(session, binding.segmentation_id,
@ -712,8 +1149,6 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
self.network_vlan_ranges)
# the network_binding record is deleted via cascade from
# the network record, so explicit removal is not necessary
if self.agent_vsm:
self._send_delete_network_request(network)
LOG.debug(_("Deleted network: %s"), id)
def get_network(self, context, id, fields=None):
@ -728,6 +1163,7 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
net = super(N1kvNeutronPluginV2, self).get_network(context, id, None)
self._extend_network_dict_provider(context, net)
self._extend_network_dict_profile(context, net)
self._extend_network_dict_member_segments(context, net)
return self._fields(net, fields)
def get_networks(self, context, filters=None, fields=None):
@ -969,19 +1405,20 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
_network_profile = super(
N1kvNeutronPluginV2, self).create_network_profile(context,
network_profile)
seg_min, seg_max = self._get_segment_range(
_network_profile['segment_range'])
if _network_profile['segment_type'] == c_const.NETWORK_TYPE_VLAN:
self._add_network_vlan_range(_network_profile['physical_network'],
int(seg_min),
int(seg_max))
n1kv_db_v2.sync_vlan_allocations(context.session,
self.network_vlan_ranges)
elif _network_profile['segment_type'] == c_const.NETWORK_TYPE_VXLAN:
self.vxlan_id_ranges = []
self.vxlan_id_ranges.append((int(seg_min), int(seg_max)))
n1kv_db_v2.sync_vxlan_allocations(context.session,
self.vxlan_id_ranges)
if _network_profile['segment_type'] in [c_const.NETWORK_TYPE_VLAN,
c_const.NETWORK_TYPE_VXLAN]:
seg_min, seg_max = self._get_segment_range(
_network_profile['segment_range'])
if _network_profile['segment_type'] == c_const.NETWORK_TYPE_VLAN:
self._add_network_vlan_range(
_network_profile['physical_network'], int(seg_min),
int(seg_max))
n1kv_db_v2.sync_vlan_allocations(context.session,
self.network_vlan_ranges)
else:
self.vxlan_id_ranges = [(int(seg_min), int(seg_max))]
n1kv_db_v2.sync_vxlan_allocations(context.session,
self.vxlan_id_ranges)
try:
self._send_create_logical_network_request(_network_profile)
except(cisco_exceptions.VSMError,
@ -1018,8 +1455,7 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
n1kv_db_v2.delete_vlan_allocations(context.session,
self.network_vlan_ranges)
elif _network_profile['segment_type'] == c_const.NETWORK_TYPE_VXLAN:
self.delete_vxlan_ranges = []
self.delete_vxlan_ranges.append((int(seg_min), int(seg_max)))
self.delete_vxlan_ranges = [(int(seg_min), int(seg_max))]
n1kv_db_v2.delete_vxlan_allocations(context.session,
self.delete_vxlan_ranges)
self._send_delete_network_profile_request(_network_profile)

View File

@ -16,6 +16,7 @@
#
# @author: Juergen Brendel, Cisco Systems Inc.
# @author: Abhishek Raut, Cisco Systems Inc.
# @author: Rudrajit Tapadar, Cisco Systems Inc.
from sqlalchemy.orm import exc as s_exc
from testtools import matchers
@ -48,6 +49,8 @@ SEGMENT_RANGE_MIN_OVERLAP = '210-230'
SEGMENT_RANGE_MAX_OVERLAP = '190-209'
SEGMENT_RANGE_OVERLAP = '190-230'
TEST_NETWORK_ID = 'abcdefghijklmnopqrstuvwxyz'
TEST_NETWORK_ID2 = 'abcdefghijklmnopqrstuvwxy2'
TEST_NETWORK_ID3 = 'abcdefghijklmnopqrstuvwxy3'
TEST_NETWORK_PROFILE = {'name': 'test_profile',
'segment_type': 'vlan',
'physical_network': 'physnet1',
@ -62,6 +65,14 @@ TEST_NETWORK_PROFILE_VXLAN = {'name': 'test_profile',
'multicast_ip_range': '239.0.0.70-239.0.0.80'}
TEST_POLICY_PROFILE = {'id': '4a417990-76fb-11e2-bcfd-0800200c9a66',
'name': 'test_policy_profile'}
TEST_NETWORK_PROFILE_MULTI_SEGMENT = {'name': 'test_profile',
'segment_type': 'multi-segment'}
TEST_NETWORK_PROFILE_VLAN_TRUNK = {'name': 'test_profile',
'segment_type': 'trunk',
'sub_type': 'vlan'}
TEST_NETWORK_PROFILE_VXLAN_TRUNK = {'name': 'test_profile',
'segment_type': 'trunk',
'sub_type': 'vxlan'}
def _create_test_network_profile_if_not_there(session,
@ -398,7 +409,7 @@ class NetworkBindingsTest(test_plugin.NeutronDbPluginV2TestCase):
p = _create_test_network_profile_if_not_there(self.session)
n1kv_db_v2.add_network_binding(
self.session, TEST_NETWORK_ID, 'vlan',
PHYS_NET, 1234, '0.0.0.0', p.id)
PHYS_NET, 1234, '0.0.0.0', p.id, None)
binding = n1kv_db_v2.get_network_binding(
self.session, TEST_NETWORK_ID)
self.assertIsNotNone(binding)
@ -407,6 +418,224 @@ class NetworkBindingsTest(test_plugin.NeutronDbPluginV2TestCase):
self.assertEqual(binding.physical_network, PHYS_NET)
self.assertEqual(binding.segmentation_id, 1234)
def test_create_multi_segment_network(self):
with self.network() as network:
TEST_NETWORK_ID = network['network']['id']
self.assertRaises(c_exc.NetworkBindingNotFound,
n1kv_db_v2.get_network_binding,
self.session,
TEST_NETWORK_ID)
p = _create_test_network_profile_if_not_there(
self.session,
TEST_NETWORK_PROFILE_MULTI_SEGMENT)
n1kv_db_v2.add_network_binding(
self.session, TEST_NETWORK_ID, 'multi-segment',
None, 0, '0.0.0.0', p.id, None)
binding = n1kv_db_v2.get_network_binding(
self.session, TEST_NETWORK_ID)
self.assertIsNotNone(binding)
self.assertEqual(binding.network_id, TEST_NETWORK_ID)
self.assertEqual(binding.network_type, 'multi-segment')
self.assertIsNone(binding.physical_network)
self.assertEqual(binding.segmentation_id, 0)
def test_add_multi_segment_binding(self):
with self.network() as network:
TEST_NETWORK_ID = network['network']['id']
self.assertRaises(c_exc.NetworkBindingNotFound,
n1kv_db_v2.get_network_binding,
self.session,
TEST_NETWORK_ID)
p = _create_test_network_profile_if_not_there(
self.session,
TEST_NETWORK_PROFILE_MULTI_SEGMENT)
n1kv_db_v2.add_network_binding(
self.session, TEST_NETWORK_ID, 'multi-segment',
None, 0, '0.0.0.0', p.id,
[(TEST_NETWORK_ID2, TEST_NETWORK_ID3)])
binding = n1kv_db_v2.get_network_binding(
self.session, TEST_NETWORK_ID)
self.assertIsNotNone(binding)
self.assertEqual(binding.network_id, TEST_NETWORK_ID)
self.assertEqual(binding.network_type, 'multi-segment')
self.assertIsNone(binding.physical_network)
self.assertEqual(binding.segmentation_id, 0)
ms_binding = (n1kv_db_v2.get_multi_segment_network_binding(
self.session, TEST_NETWORK_ID,
(TEST_NETWORK_ID2, TEST_NETWORK_ID3)))
self.assertIsNotNone(ms_binding)
self.assertEqual(ms_binding.multi_segment_id, TEST_NETWORK_ID)
self.assertEqual(ms_binding.segment1_id, TEST_NETWORK_ID2)
self.assertEqual(ms_binding.segment2_id, TEST_NETWORK_ID3)
ms_members = (n1kv_db_v2.get_multi_segment_members(
self.session, TEST_NETWORK_ID))
self.assertEqual(ms_members,
[(TEST_NETWORK_ID2, TEST_NETWORK_ID3)])
self.assertTrue(n1kv_db_v2.is_multi_segment_member(
self.session, TEST_NETWORK_ID2))
self.assertTrue(n1kv_db_v2.is_multi_segment_member(
self.session, TEST_NETWORK_ID3))
n1kv_db_v2.del_multi_segment_binding(
self.session, TEST_NETWORK_ID,
[(TEST_NETWORK_ID2, TEST_NETWORK_ID3)])
ms_members = (n1kv_db_v2.get_multi_segment_members(
self.session, TEST_NETWORK_ID))
self.assertEqual(ms_members, [])
def test_create_vlan_trunk_network(self):
with self.network() as network:
TEST_NETWORK_ID = network['network']['id']
self.assertRaises(c_exc.NetworkBindingNotFound,
n1kv_db_v2.get_network_binding,
self.session,
TEST_NETWORK_ID)
p = _create_test_network_profile_if_not_there(
self.session,
TEST_NETWORK_PROFILE_VLAN_TRUNK)
n1kv_db_v2.add_network_binding(
self.session, TEST_NETWORK_ID, 'trunk',
None, 0, '0.0.0.0', p.id, None)
binding = n1kv_db_v2.get_network_binding(
self.session, TEST_NETWORK_ID)
self.assertIsNotNone(binding)
self.assertEqual(binding.network_id, TEST_NETWORK_ID)
self.assertEqual(binding.network_type, 'trunk')
self.assertIsNone(binding.physical_network)
self.assertEqual(binding.segmentation_id, 0)
def test_create_vxlan_trunk_network(self):
with self.network() as network:
TEST_NETWORK_ID = network['network']['id']
self.assertRaises(c_exc.NetworkBindingNotFound,
n1kv_db_v2.get_network_binding,
self.session,
TEST_NETWORK_ID)
p = _create_test_network_profile_if_not_there(
self.session,
TEST_NETWORK_PROFILE_VXLAN_TRUNK)
n1kv_db_v2.add_network_binding(
self.session, TEST_NETWORK_ID, 'trunk',
None, 0, '0.0.0.0', p.id, None)
binding = n1kv_db_v2.get_network_binding(
self.session, TEST_NETWORK_ID)
self.assertIsNotNone(binding)
self.assertEqual(binding.network_id, TEST_NETWORK_ID)
self.assertEqual(binding.network_type, 'trunk')
self.assertIsNone(binding.physical_network)
self.assertEqual(binding.segmentation_id, 0)
def test_add_vlan_trunk_binding(self):
with self.network() as network1:
with self.network() as network2:
TEST_NETWORK_ID = network1['network']['id']
self.assertRaises(c_exc.NetworkBindingNotFound,
n1kv_db_v2.get_network_binding,
self.session,
TEST_NETWORK_ID)
TEST_NETWORK_ID2 = network2['network']['id']
self.assertRaises(c_exc.NetworkBindingNotFound,
n1kv_db_v2.get_network_binding,
self.session,
TEST_NETWORK_ID2)
p_v = _create_test_network_profile_if_not_there(self.session)
n1kv_db_v2.add_network_binding(
self.session, TEST_NETWORK_ID2, 'vlan',
PHYS_NET, 1234, '0.0.0.0', p_v.id, None)
p = _create_test_network_profile_if_not_there(
self.session,
TEST_NETWORK_PROFILE_VLAN_TRUNK)
n1kv_db_v2.add_network_binding(
self.session, TEST_NETWORK_ID, 'trunk',
None, 0, '0.0.0.0', p.id, [(TEST_NETWORK_ID2, 0)])
binding = n1kv_db_v2.get_network_binding(
self.session, TEST_NETWORK_ID)
self.assertIsNotNone(binding)
self.assertEqual(binding.network_id, TEST_NETWORK_ID)
self.assertEqual(binding.network_type, 'trunk')
self.assertEqual(binding.physical_network, PHYS_NET)
self.assertEqual(binding.segmentation_id, 0)
t_binding = (n1kv_db_v2.get_trunk_network_binding(
self.session, TEST_NETWORK_ID,
(TEST_NETWORK_ID2, 0)))
self.assertIsNotNone(t_binding)
self.assertEqual(t_binding.trunk_segment_id, TEST_NETWORK_ID)
self.assertEqual(t_binding.segment_id, TEST_NETWORK_ID2)
self.assertEqual(t_binding.dot1qtag, '0')
t_members = (n1kv_db_v2.get_trunk_members(
self.session, TEST_NETWORK_ID))
self.assertEqual(t_members,
[(TEST_NETWORK_ID2, '0')])
self.assertTrue(n1kv_db_v2.is_trunk_member(
self.session, TEST_NETWORK_ID2))
n1kv_db_v2.del_trunk_segment_binding(
self.session, TEST_NETWORK_ID,
[(TEST_NETWORK_ID2, '0')])
t_members = (n1kv_db_v2.get_multi_segment_members(
self.session, TEST_NETWORK_ID))
self.assertEqual(t_members, [])
def test_add_vxlan_trunk_binding(self):
with self.network() as network1:
with self.network() as network2:
TEST_NETWORK_ID = network1['network']['id']
self.assertRaises(c_exc.NetworkBindingNotFound,
n1kv_db_v2.get_network_binding,
self.session,
TEST_NETWORK_ID)
TEST_NETWORK_ID2 = network2['network']['id']
self.assertRaises(c_exc.NetworkBindingNotFound,
n1kv_db_v2.get_network_binding,
self.session,
TEST_NETWORK_ID2)
p_v = _create_test_network_profile_if_not_there(
self.session, TEST_NETWORK_PROFILE_VXLAN_TRUNK)
n1kv_db_v2.add_network_binding(
self.session, TEST_NETWORK_ID2, 'vxlan',
None, 5100, '224.10.10.10', p_v.id, None)
p = _create_test_network_profile_if_not_there(
self.session,
TEST_NETWORK_PROFILE_VXLAN_TRUNK)
n1kv_db_v2.add_network_binding(
self.session, TEST_NETWORK_ID, 'trunk',
None, 0, '0.0.0.0', p.id,
[(TEST_NETWORK_ID2, 5)])
binding = n1kv_db_v2.get_network_binding(
self.session, TEST_NETWORK_ID)
self.assertIsNotNone(binding)
self.assertEqual(binding.network_id, TEST_NETWORK_ID)
self.assertEqual(binding.network_type, 'trunk')
self.assertIsNone(binding.physical_network)
self.assertEqual(binding.segmentation_id, 0)
t_binding = (n1kv_db_v2.get_trunk_network_binding(
self.session, TEST_NETWORK_ID,
(TEST_NETWORK_ID2, '5')))
self.assertIsNotNone(t_binding)
self.assertEqual(t_binding.trunk_segment_id, TEST_NETWORK_ID)
self.assertEqual(t_binding.segment_id, TEST_NETWORK_ID2)
self.assertEqual(t_binding.dot1qtag, '5')
t_members = (n1kv_db_v2.get_trunk_members(
self.session, TEST_NETWORK_ID))
self.assertEqual(t_members,
[(TEST_NETWORK_ID2, '5')])
self.assertTrue(n1kv_db_v2.is_trunk_member(
self.session, TEST_NETWORK_ID2))
n1kv_db_v2.del_trunk_segment_binding(
self.session, TEST_NETWORK_ID,
[(TEST_NETWORK_ID2, '5')])
t_members = (n1kv_db_v2.get_multi_segment_members(
self.session, TEST_NETWORK_ID))
self.assertEqual(t_members, [])
class NetworkProfileTests(base.BaseTestCase,
n1kv_db_v2.NetworkProfile_db_mixin):
@ -436,6 +665,63 @@ class NetworkProfileTests(base.BaseTestCase,
db_profile.multicast_ip_range)
n1kv_db_v2.delete_network_profile(self.session, _db_profile.id)
def test_create_multi_segment_network_profile(self):
_db_profile = (n1kv_db_v2.create_network_profile(
self.session, TEST_NETWORK_PROFILE_MULTI_SEGMENT))
self.assertIsNotNone(_db_profile)
db_profile = (self.session.query(n1kv_models_v2.NetworkProfile).
filter_by(
name=TEST_NETWORK_PROFILE_MULTI_SEGMENT['name']).
one())
self.assertIsNotNone(db_profile)
self.assertEqual(_db_profile.id, db_profile.id)
self.assertEqual(_db_profile.name, db_profile.name)
self.assertEqual(_db_profile.segment_type, db_profile.segment_type)
self.assertEqual(_db_profile.segment_range, db_profile.segment_range)
self.assertEqual(_db_profile.multicast_ip_index,
db_profile.multicast_ip_index)
self.assertEqual(_db_profile.multicast_ip_range,
db_profile.multicast_ip_range)
n1kv_db_v2.delete_network_profile(self.session, _db_profile.id)
def test_create_vlan_trunk_network_profile(self):
_db_profile = (n1kv_db_v2.create_network_profile(
self.session, TEST_NETWORK_PROFILE_VLAN_TRUNK))
self.assertIsNotNone(_db_profile)
db_profile = (self.session.query(n1kv_models_v2.NetworkProfile).
filter_by(name=TEST_NETWORK_PROFILE_VLAN_TRUNK['name']).
one())
self.assertIsNotNone(db_profile)
self.assertEqual(_db_profile.id, db_profile.id)
self.assertEqual(_db_profile.name, db_profile.name)
self.assertEqual(_db_profile.segment_type, db_profile.segment_type)
self.assertEqual(_db_profile.segment_range, db_profile.segment_range)
self.assertEqual(_db_profile.multicast_ip_index,
db_profile.multicast_ip_index)
self.assertEqual(_db_profile.multicast_ip_range,
db_profile.multicast_ip_range)
self.assertEqual(_db_profile.sub_type, db_profile.sub_type)
n1kv_db_v2.delete_network_profile(self.session, _db_profile.id)
def test_create_vxlan_trunk_network_profile(self):
_db_profile = (n1kv_db_v2.create_network_profile(
self.session, TEST_NETWORK_PROFILE_VXLAN_TRUNK))
self.assertIsNotNone(_db_profile)
db_profile = (self.session.query(n1kv_models_v2.NetworkProfile).
filter_by(name=TEST_NETWORK_PROFILE_VXLAN_TRUNK['name']).
one())
self.assertIsNotNone(db_profile)
self.assertEqual(_db_profile.id, db_profile.id)
self.assertEqual(_db_profile.name, db_profile.name)
self.assertEqual(_db_profile.segment_type, db_profile.segment_type)
self.assertEqual(_db_profile.segment_range, db_profile.segment_range)
self.assertEqual(_db_profile.multicast_ip_index,
db_profile.multicast_ip_index)
self.assertEqual(_db_profile.multicast_ip_range,
db_profile.multicast_ip_range)
self.assertEqual(_db_profile.sub_type, db_profile.sub_type)
n1kv_db_v2.delete_network_profile(self.session, _db_profile.id)
def test_create_network_profile_overlap(self):
_db_profile = n1kv_db_v2.create_network_profile(self.session,
TEST_NETWORK_PROFILE_2)