--- /dev/null
+# 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')
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_'
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
"""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.")
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.
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
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(
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):
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:
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):
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
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):
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):
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):
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"],
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):
"""
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):
"""
: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):
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)
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):
"""
# under the License.
#
# @author: Abhishek Raut, Cisco Systems Inc.
+# @author: Rudrajit Tapadar, Cisco Systems Inc.
import sqlalchemy as sa
"""
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>'
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))
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))
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': {
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,
#
# @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
'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,
@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']:
@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']:
# under the License.
#
# @author: Abhishek Raut, Cisco Systems, Inc.
+# @author: Rudrajit Tapadar, Cisco Systems, Inc.
import base64
import httplib2
"networks": "network",
"ports": "port",
"set": "instance",
- "subnets": "subnet"
+ "subnets": "subnet",
+ "mappings": "mapping",
+ "segments": "segment"
}
}
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."""
: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,
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)
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))
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
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
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)
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,
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,
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):
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):
'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:
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'])
: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
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,
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):
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):
_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,
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)
#
# @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
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',
'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,
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)
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):
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)