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_VXLAN = 'vxlan'
NETWORK_TYPE_LOCAL = 'local' NETWORK_TYPE_LOCAL = 'local'
NETWORK_TYPE_NONE = 'none' 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 # Prefix for VM Network name
VM_NETWORK_NAME_PREFIX = 'vmn_' VM_NETWORK_NAME_PREFIX = 'vmn_'
@ -88,3 +94,14 @@ NAME = 'name'
ID = 'id' ID = 'id'
POLICY = 'policy' POLICY = 'policy'
TENANT_ID_NOT_SET = 'TENANT_ID_NOT_SET' 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.""" """Profile to Tenant binding for given profile ID cannot be found."""
message = _("Profile-Tenant binding for profile %(profile_id)s could " message = _("Profile-Tenant binding for profile %(profile_id)s could "
"not be found.") "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() 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): def get_network_binding(db_session, network_id):
""" """
Retrieve network binding. 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, def add_network_binding(db_session, network_id, network_type,
physical_network, segmentation_id, physical_network, segmentation_id,
multicast_ip, network_profile_id): multicast_ip, network_profile_id, add_segments):
""" """
Create network binding. Create network binding.
:param db_session: database session :param db_session: database session
:param network_id: UUID representing the network :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 :param physical_network: Only applicable for VLAN networks. It
represents a L2 Domain represents a L2 Domain
:param segmentation_id: integer representing VLAN or VXLAN ID :param segmentation_id: integer representing VLAN or VXLAN ID
@ -75,6 +300,8 @@ def add_network_binding(db_session, network_id, network_type,
IDs. IDs.
:param network_profile_id: network profile ID based on which this network :param network_profile_id: network profile ID based on which this network
is created 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): with db_session.begin(subtransactions=True):
binding = n1kv_models_v2.N1kvNetworkBinding( binding = n1kv_models_v2.N1kvNetworkBinding(
@ -85,6 +312,12 @@ def add_network_binding(db_session, network_id, network_type,
multicast_ip=multicast_ip, multicast_ip=multicast_ip,
profile_id=network_profile_id) profile_id=network_profile_id)
db_session.add(binding) 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): def get_segment_range(network_profile):
@ -262,6 +495,8 @@ def reserve_vlan(db_session, network_profile):
filter(and_( filter(and_(
n1kv_models_v2.N1kvVlanAllocation.vlan_id >= seg_min, n1kv_models_v2.N1kvVlanAllocation.vlan_id >= seg_min,
n1kv_models_v2.N1kvVlanAllocation.vlan_id <= seg_max, n1kv_models_v2.N1kvVlanAllocation.vlan_id <= seg_max,
n1kv_models_v2.N1kvVlanAllocation.physical_network ==
network_profile['physical_network'],
n1kv_models_v2.N1kvVlanAllocation.allocated == False) n1kv_models_v2.N1kvVlanAllocation.allocated == False)
)).first() )).first()
if alloc: if alloc:
@ -314,8 +549,9 @@ def alloc_network(db_session, network_profile_id):
network_profile_id) network_profile_id)
if network_profile.segment_type == c_const.NETWORK_TYPE_VLAN: if network_profile.segment_type == c_const.NETWORK_TYPE_VLAN:
return reserve_vlan(db_session, network_profile) 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 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): 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()")) LOG.debug(_("create_network_profile()"))
with db_session.begin(subtransactions=True): with db_session.begin(subtransactions=True):
kwargs = {"name": network_profile["name"], kwargs = {"name": network_profile["name"],
"segment_type": network_profile["segment_type"], "segment_type": network_profile["segment_type"]}
"segment_range": network_profile["segment_range"]}
if network_profile["segment_type"] == c_const.NETWORK_TYPE_VLAN: if network_profile["segment_type"] == c_const.NETWORK_TYPE_VLAN:
kwargs["physical_network"] = network_profile["physical_network"] kwargs["physical_network"] = network_profile["physical_network"]
kwargs["segment_range"] = network_profile["segment_range"]
elif network_profile["segment_type"] == c_const.NETWORK_TYPE_VXLAN: elif network_profile["segment_type"] == c_const.NETWORK_TYPE_VXLAN:
kwargs["multicast_ip_index"] = 0 kwargs["multicast_ip_index"] = 0
kwargs["multicast_ip_range"] = network_profile[ kwargs["multicast_ip_range"] = network_profile[
"multicast_ip_range"] "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) net_profile = n1kv_models_v2.NetworkProfile(**kwargs)
db_session.add(net_profile) db_session.add(net_profile)
return net_profile return net_profile
@ -659,8 +898,7 @@ def _get_network_profiles(**kwargs):
if "physical_network" in kwargs: if "physical_network" in kwargs:
return (db_session.query(n1kv_models_v2.NetworkProfile). return (db_session.query(n1kv_models_v2.NetworkProfile).
filter_by(physical_network=kwargs["physical_network"])) 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 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): def _get_profile_binding(tenant_id, profile_id):
LOG.debug(_("_get_profile_binding")) LOG.debug(_("_get_profile_binding"))
db_session = db.get_session() db_session = db.get_session()
binding = db_session.query(n1kv_models_v2.ProfileBinding).filter_by( return (db_session.query(n1kv_models_v2.ProfileBinding).filter_by(
tenant_id=tenant_id, profile_id=profile_id).one() tenant_id=tenant_id, profile_id=profile_id).one())
return binding
def get_profile_binding(tenant_id, profile_id): 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). profile_bindings = (db_session.query(n1kv_models_v2.ProfileBinding).
filter_by(profile_type=profile_type)) filter_by(profile_type=profile_type))
return profile_bindings 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): class NetworkProfile_db_mixin(object):
@ -815,6 +1051,7 @@ class NetworkProfile_db_mixin(object):
res = {"id": network_profile["id"], res = {"id": network_profile["id"],
"name": network_profile["name"], "name": network_profile["name"],
"segment_type": network_profile["segment_type"], "segment_type": network_profile["segment_type"],
"sub_type": network_profile["sub_type"],
"segment_range": network_profile["segment_range"], "segment_range": network_profile["segment_range"],
"multicast_ip_index": network_profile["multicast_ip_index"], "multicast_ip_index": network_profile["multicast_ip_index"],
"multicast_ip_range": network_profile["multicast_ip_range"], "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"]) self.add_network_profile_tenant(id, p["add_tenant"])
return self._make_network_profile_dict(get_network_profile( return self._make_network_profile_dict(get_network_profile(
context.session, id)) 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) delete_profile_binding(p["remove_tenant"], id)
return self._make_network_profile_dict(get_network_profile( return self._make_network_profile_dict(get_network_profile(
context.session, id)) context.session, id))
else: return self._make_network_profile_dict(
return self._make_network_profile_dict( update_network_profile(context.session, id, p))
update_network_profile(context.session, id, p))
def get_network_profile(self, context, id, fields=None): 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, return self._get_collection(context, n1kv_models_v2.NetworkProfile,
self._make_network_profile_dict, self._make_network_profile_dict,
filters=filters, fields=fields) filters=filters, fields=fields)
else: return self._get_network_collection_for_tenant(context.session,
return self._get_network_collection_for_tenant(context.session, n1kv_models_v2.
n1kv_models_v2. NetworkProfile,
NetworkProfile, context.tenant_id)
context.tenant_id)
def add_network_profile_tenant(self, network_profile_id, 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 :param net_p: network profile object
""" """
if any(net_p[arg] == "" for arg in ("segment_type", "segment_range")): if any(net_p[arg] == "" for arg in ["segment_type"]):
msg = _("arguments segment_type and segment_range missing" msg = _("arguments segment_type missing"
" for network profile") " for network profile")
LOG.exception(msg) LOG.exception(msg)
raise q_exc.InvalidInput(error_message=msg) raise q_exc.InvalidInput(error_message=msg)
_segment_type = net_p["segment_type"].lower() segment_type = net_p["segment_type"].lower()
if _segment_type not in [c_const.NETWORK_TYPE_VLAN, if segment_type not in [c_const.NETWORK_TYPE_VLAN,
c_const.NETWORK_TYPE_VXLAN]: c_const.NETWORK_TYPE_VXLAN,
msg = _("segment_type should either be vlan or 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) LOG.exception(msg)
raise q_exc.InvalidInput(error_message=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" net_p["multicast_ip_range"] = "0.0.0.0"
def _validate_segment_range_uniqueness(self, context, net_p): 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: if segment_type == c_const.NETWORK_TYPE_VLAN:
profiles = _get_network_profiles( profiles = _get_network_profiles(
physical_network=net_p["physical_network"]) physical_network=net_p["physical_network"])
elif segment_type == c_const.NETWORK_TYPE_VXLAN:
profiles = _get_network_profiles()
else: else:
# TODO(Abhishek): Handle this when we support other segment types profiles = _get_network_profiles()
return
if profiles: if profiles:
for prfl in profiles: for profile in profiles:
name = prfl.name name = profile.name
segment_range = prfl.segment_range segment_range = profile.segment_range
if net_p["name"] == name: if net_p["name"] == name:
msg = (_("NetworkProfile name %s already exists"), msg = (_("NetworkProfile name %s already exists"),
net_p["name"]) net_p["name"])
LOG.exception(msg) LOG.exception(msg)
raise q_exc.InvalidInput(error_message=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( seg_min, seg_max = self._get_segment_range(
net_p["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) segment_range)
if ((prfl_seg_min <= seg_min <= prfl_seg_max) or if ((profile_seg_min <= seg_min <= profile_seg_max) or
(prfl_seg_min <= seg_max <= prfl_seg_max) or (profile_seg_min <= seg_max <= profile_seg_max) or
((seg_min <= prfl_seg_min) and ((seg_min <= profile_seg_min) and
(seg_max >= prfl_seg_max))): (seg_max >= profile_seg_max))):
msg = _("segment range overlaps with another profile") msg = _("segment range overlaps with another profile")
LOG.exception(msg) LOG.exception(msg)
raise q_exc.InvalidInput(error_message=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"]) self.add_policy_profile_tenant(id, p["add_tenant"])
return self._make_policy_profile_dict(get_policy_profile( return self._make_policy_profile_dict(get_policy_profile(
context.session, id)) 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) delete_profile_binding(p["remove_tenant"], id)
return self._make_policy_profile_dict(get_policy_profile( return self._make_policy_profile_dict(get_policy_profile(
context.session, id)) context.session, id))
else: return self._make_policy_profile_dict(
return self._make_policy_profile_dict( update_policy_profile(context.session, id, p))
update_policy_profile(context.session, id, p))
def add_policy_profile_tenant(self, policy_profile_id, tenant_id): def add_policy_profile_tenant(self, policy_profile_id, tenant_id):
""" """

View File

@ -15,6 +15,7 @@
# under the License. # under the License.
# #
# @author: Abhishek Raut, Cisco Systems Inc. # @author: Abhishek Raut, Cisco Systems Inc.
# @author: Rudrajit Tapadar, Cisco Systems Inc.
import sqlalchemy as sa import sqlalchemy as sa
@ -95,7 +96,8 @@ class NetworkProfile(model_base.BASEV2, models_v2.HasId):
""" """
Nexus1000V Network Profiles Nexus1000V Network Profiles
segment_type - VLAN, VXLAN segment_type - VLAN, VXLAN, TRUNK, MULTI_SEGMENT
sub_type - TRUNK_VLAN, TRUNK_VXLAN
segment_range - '<integer>-<integer>' segment_range - '<integer>-<integer>'
multicast_ip_index - <integer> multicast_ip_index - <integer>
multicast_ip_range - '<ip>-<ip>' multicast_ip_range - '<ip>-<ip>'
@ -106,8 +108,12 @@ class NetworkProfile(model_base.BASEV2, models_v2.HasId):
name = sa.Column(sa.String(255)) name = sa.Column(sa.String(255))
segment_type = sa.Column(sa.Enum(cisco_constants.NETWORK_TYPE_VLAN, segment_type = sa.Column(sa.Enum(cisco_constants.NETWORK_TYPE_VLAN,
cisco_constants.NETWORK_TYPE_VXLAN, cisco_constants.NETWORK_TYPE_VXLAN,
cisco_constants.NETWORK_TYPE_TRUNK,
cisco_constants.
NETWORK_TYPE_MULTI_SEGMENT,
name='segment_type'), name='segment_type'),
nullable=False) nullable=False)
sub_type = sa.Column(sa.String(255))
segment_range = sa.Column(sa.String(255)) segment_range = sa.Column(sa.String(255))
multicast_ip_index = sa.Column(sa.Integer, default=0) multicast_ip_index = sa.Column(sa.Integer, default=0)
multicast_ip_range = sa.Column(sa.String(255)) multicast_ip_range = sa.Column(sa.String(255))
@ -142,3 +148,30 @@ class ProfileBinding(model_base.BASEV2):
primary_key=True, primary_key=True,
default=cisco_constants.TENANT_ID_NOT_SET) default=cisco_constants.TENANT_ID_NOT_SET)
profile_id = sa.Column(sa.String(36), primary_key=True) 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' PROFILE_ID = 'n1kv:profile_id'
MULTICAST_IP = 'n1kv:multicast_ip' MULTICAST_IP = 'n1kv:multicast_ip'
SEGMENT_ADD = 'n1kv:segment_add'
SEGMENT_DEL = 'n1kv:segment_del'
MEMBER_SEGMENTS = 'n1kv:member_segments'
EXTENDED_ATTRIBUTES_2_0 = { EXTENDED_ATTRIBUTES_2_0 = {
'networks': { 'networks': {
@ -34,6 +37,15 @@ EXTENDED_ATTRIBUTES_2_0 = {
MULTICAST_IP: {'allow_post': True, 'allow_put': True, MULTICAST_IP: {'allow_post': True, 'allow_put': True,
'default': attributes.ATTR_NOT_SPECIFIED, 'default': attributes.ATTR_NOT_SPECIFIED,
'is_visible': True}, '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': { 'ports': {
PROFILE_ID: {'allow_post': True, 'allow_put': True, PROFILE_ID: {'allow_post': True, 'allow_put': True,

View File

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

View File

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

View File

@ -15,6 +15,7 @@
# under the License. # under the License.
# #
# @author: Abhishek Raut, Cisco Systems, Inc. # @author: Abhishek Raut, Cisco Systems, Inc.
# @author: Rudrajit Tapadar, Cisco Systems, Inc.
import base64 import base64
import httplib2 import httplib2
@ -117,7 +118,9 @@ class Client(object):
"networks": "network", "networks": "network",
"ports": "port", "ports": "port",
"set": "instance", "set": "instance",
"subnets": "subnet" "subnets": "subnet",
"mappings": "mapping",
"segments": "segment"
} }
} }
@ -138,6 +141,9 @@ class Client(object):
logical_networks_path = "/logical-network" logical_networks_path = "/logical-network"
logical_network_path = "/logical-network/%s" logical_network_path = "/logical-network/%s"
events_path = "/kvm/events" events_path = "/kvm/events"
clusters_path = "/cluster"
encap_profiles_path = "/encapsulation-profile"
encap_profile_path = "/encapsulation-profile/%s"
def __init__(self, **kwargs): def __init__(self, **kwargs):
"""Initialize a new client for the plugin.""" """Initialize a new client for the plugin."""
@ -171,7 +177,7 @@ class Client(object):
:param network: network dict :param network: network dict
""" """
body = {'name': network['name'] + '_bd', body = {'name': network['name'] + c_const.BRIDGE_DOMAIN_SUFFIX,
'segmentId': network[providernet.SEGMENTATION_ID], 'segmentId': network[providernet.SEGMENTATION_ID],
'groupIp': network[n1kv_profile.MULTICAST_IP], } 'groupIp': network[n1kv_profile.MULTICAST_IP], }
return self._post(self.bridge_domains_path, return self._post(self.bridge_domains_path,
@ -199,7 +205,20 @@ class Client(object):
if network[providernet.NETWORK_TYPE] == c_const.NETWORK_TYPE_VLAN: if network[providernet.NETWORK_TYPE] == c_const.NETWORK_TYPE_VLAN:
body['vlan'] = network[providernet.SEGMENTATION_ID] body['vlan'] = network[providernet.SEGMENTATION_ID]
elif network[providernet.NETWORK_TYPE] == c_const.NETWORK_TYPE_VXLAN: 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, return self._post(self.network_segments_path,
body=body) body=body)
@ -498,3 +517,37 @@ class Client(object):
auth = base64.encodestring("%s:%s" % (username, password)) auth = base64.encodestring("%s:%s" % (username, password))
header = {"Authorization": "Basic %s" % auth} header = {"Authorization": "Basic %s" % auth}
return header 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 exceptions as q_exc
from neutron.common import rpc as q_rpc from neutron.common import rpc as q_rpc
from neutron.common import topics from neutron.common import topics
from neutron.common import utils
from neutron.db import agents_db from neutron.db import agents_db
from neutron.db import agentschedulers_db from neutron.db import agentschedulers_db
from neutron.db import db_base_plugin_v2 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 log as logging
from neutron.openstack.common import rpc from neutron.openstack.common import rpc
from neutron.openstack.common.rpc import proxy 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_constants as c_const
from neutron.plugins.cisco.common import cisco_credentials_v2 as c_cred from neutron.plugins.cisco.common import cisco_credentials_v2 as c_cred
from neutron.plugins.cisco.common import cisco_exceptions 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: elif binding.network_type == c_const.NETWORK_TYPE_VLAN:
network[providernet.PHYSICAL_NETWORK] = binding.physical_network network[providernet.PHYSICAL_NETWORK] = binding.physical_network
network[providernet.SEGMENTATION_ID] = binding.segmentation_id 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): def _process_provider_create(self, context, attrs):
network_type = attrs.get(providernet.NETWORK_TYPE) 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") msg = _("plugin does not support updating provider attributes")
raise q_exc.InvalidInput(error_message=msg) 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): def _extend_network_dict_profile(self, context, network):
"""Add the extended parameter network profile to the network.""" """Add the extended parameter network profile to the network."""
binding = n1kv_db_v2.get_network_binding(context.session, 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 = n1kv_client.Client()
n1kvclient.delete_network_segment_pool(profile['name']) 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. Send create network request to VSM.
Create a bridge domain for network of type VXLAN. Create a bridge domain for network of type VXLAN.
:param context: neutron api request context :param context: neutron api request context
:param network: network dictionary :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']) LOG.debug(_('_send_create_network_request: %s'), network['id'])
profile = self.get_network_profile(context, profile = self.get_network_profile(context,
@ -449,36 +738,110 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
n1kvclient = n1kv_client.Client() n1kvclient = n1kv_client.Client()
if network[providernet.NETWORK_TYPE] == c_const.NETWORK_TYPE_VXLAN: if network[providernet.NETWORK_TYPE] == c_const.NETWORK_TYPE_VXLAN:
n1kvclient.create_bridge_domain(network) 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) 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. Send update network request to VSM.
:param context: neutron api request context
:param network: network dictionary :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']) LOG.debug(_('_send_update_network_request: %s'), network['id'])
db_session = context.session
profile = n1kv_db_v2.get_network_profile( profile = n1kv_db_v2.get_network_profile(
db_session, network[n1kv_profile.PROFILE_ID]) db_session, network[n1kv_profile.PROFILE_ID])
n1kvclient = n1kv_client.Client()
body = {'name': network['name'], body = {'name': network['name'],
'id': network['id'], 'id': network['id'],
'networkDefinition': profile['name'], 'networkDefinition': profile['name'],
'vlan': network[providernet.SEGMENTATION_ID]} 'vlan': network[providernet.SEGMENTATION_ID],
n1kvclient = n1kv_client.Client() '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) 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. Send delete network request to VSM.
Delete bridge domain if network is of type VXLAN. 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 :param network: network dictionary
""" """
LOG.debug(_('_send_delete_network_request: %s'), network['id']) LOG.debug(_('_send_delete_network_request: %s'), network['id'])
n1kvclient = n1kv_client.Client() n1kvclient = n1kv_client.Client()
session = context.session
if network[providernet.NETWORK_TYPE] == c_const.NETWORK_TYPE_VXLAN: 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) 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']) n1kvclient.delete_network_segment(network['name'])
def _send_create_subnet_request(self, context, subnet): def _send_create_subnet_request(self, context, subnet):
@ -616,6 +979,7 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
network['network']) network['network'])
self._add_dummy_profile_only_if_testing(network) self._add_dummy_profile_only_if_testing(network)
profile_id = self._process_network_profile(context, network['network']) profile_id = self._process_network_profile(context, network['network'])
segment_pairs = None
LOG.debug(_('create network: profile_id=%s'), profile_id) LOG.debug(_('create network: profile_id=%s'), profile_id)
session = context.session session = context.session
with session.begin(subtransactions=True): with session.begin(subtransactions=True):
@ -632,8 +996,24 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
'net_type': network_type, 'net_type': network_type,
'seg_id': segmentation_id, 'seg_id': segmentation_id,
'multicast_ip': multicast_ip}) 'multicast_ip': multicast_ip})
if not segmentation_id: if network_type == c_const.NETWORK_TYPE_MULTI_SEGMENT:
raise q_exc.TenantNetworksDisabled() 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: else:
# provider network # provider network
if network_type == c_const.NETWORK_TYPE_VLAN: if network_type == c_const.NETWORK_TYPE_VLAN:
@ -655,13 +1035,19 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
physical_network, physical_network,
segmentation_id, segmentation_id,
multicast_ip, multicast_ip,
profile_id) profile_id,
segment_pairs)
self._process_l3_create(context, net, network['network']) self._process_l3_create(context, net, network['network'])
self._extend_network_dict_provider(context, net) self._extend_network_dict_provider(context, net)
self._extend_network_dict_profile(context, net) self._extend_network_dict_profile(context, net)
try: 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, except(cisco_exceptions.VSMError,
cisco_exceptions.VSMConnectionFailed): cisco_exceptions.VSMConnectionFailed):
super(N1kvNeutronPluginV2, self).delete_network(context, net['id']) super(N1kvNeutronPluginV2, self).delete_network(context, net['id'])
@ -679,15 +1065,52 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
:returns: updated network object :returns: updated network object
""" """
self._check_provider_update(context, network['network']) self._check_provider_update(context, network['network'])
add_segments = []
del_segments = []
session = context.session session = context.session
with session.begin(subtransactions=True): with session.begin(subtransactions=True):
net = super(N1kvNeutronPluginV2, self).update_network(context, id, net = super(N1kvNeutronPluginV2, self).update_network(context, id,
network) network)
self._process_l3_update(context, net, network['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_provider(context, net)
self._extend_network_dict_profile(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']) LOG.debug(_("Updated network: %s"), net['id'])
return net return net
@ -702,6 +1125,20 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
with session.begin(subtransactions=True): with session.begin(subtransactions=True):
binding = n1kv_db_v2.get_network_binding(session, id) binding = n1kv_db_v2.get_network_binding(session, id)
network = self.get_network(context, 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) super(N1kvNeutronPluginV2, self).delete_network(context, id)
if binding.network_type == c_const.NETWORK_TYPE_VXLAN: if binding.network_type == c_const.NETWORK_TYPE_VXLAN:
n1kv_db_v2.release_vxlan(session, binding.segmentation_id, n1kv_db_v2.release_vxlan(session, binding.segmentation_id,
@ -712,8 +1149,6 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
self.network_vlan_ranges) self.network_vlan_ranges)
# the network_binding record is deleted via cascade from # the network_binding record is deleted via cascade from
# the network record, so explicit removal is not necessary # 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) LOG.debug(_("Deleted network: %s"), id)
def get_network(self, context, id, fields=None): 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) net = super(N1kvNeutronPluginV2, self).get_network(context, id, None)
self._extend_network_dict_provider(context, net) self._extend_network_dict_provider(context, net)
self._extend_network_dict_profile(context, net) self._extend_network_dict_profile(context, net)
self._extend_network_dict_member_segments(context, net)
return self._fields(net, fields) return self._fields(net, fields)
def get_networks(self, context, filters=None, fields=None): def get_networks(self, context, filters=None, fields=None):
@ -969,19 +1405,20 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
_network_profile = super( _network_profile = super(
N1kvNeutronPluginV2, self).create_network_profile(context, N1kvNeutronPluginV2, self).create_network_profile(context,
network_profile) network_profile)
seg_min, seg_max = self._get_segment_range( if _network_profile['segment_type'] in [c_const.NETWORK_TYPE_VLAN,
_network_profile['segment_range']) c_const.NETWORK_TYPE_VXLAN]:
if _network_profile['segment_type'] == c_const.NETWORK_TYPE_VLAN: seg_min, seg_max = self._get_segment_range(
self._add_network_vlan_range(_network_profile['physical_network'], _network_profile['segment_range'])
int(seg_min), if _network_profile['segment_type'] == c_const.NETWORK_TYPE_VLAN:
int(seg_max)) self._add_network_vlan_range(
n1kv_db_v2.sync_vlan_allocations(context.session, _network_profile['physical_network'], int(seg_min),
self.network_vlan_ranges) int(seg_max))
elif _network_profile['segment_type'] == c_const.NETWORK_TYPE_VXLAN: n1kv_db_v2.sync_vlan_allocations(context.session,
self.vxlan_id_ranges = [] self.network_vlan_ranges)
self.vxlan_id_ranges.append((int(seg_min), int(seg_max))) else:
n1kv_db_v2.sync_vxlan_allocations(context.session, self.vxlan_id_ranges = [(int(seg_min), int(seg_max))]
self.vxlan_id_ranges) n1kv_db_v2.sync_vxlan_allocations(context.session,
self.vxlan_id_ranges)
try: try:
self._send_create_logical_network_request(_network_profile) self._send_create_logical_network_request(_network_profile)
except(cisco_exceptions.VSMError, except(cisco_exceptions.VSMError,
@ -1018,8 +1455,7 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
n1kv_db_v2.delete_vlan_allocations(context.session, n1kv_db_v2.delete_vlan_allocations(context.session,
self.network_vlan_ranges) self.network_vlan_ranges)
elif _network_profile['segment_type'] == c_const.NETWORK_TYPE_VXLAN: elif _network_profile['segment_type'] == c_const.NETWORK_TYPE_VXLAN:
self.delete_vxlan_ranges = [] self.delete_vxlan_ranges = [(int(seg_min), int(seg_max))]
self.delete_vxlan_ranges.append((int(seg_min), int(seg_max)))
n1kv_db_v2.delete_vxlan_allocations(context.session, n1kv_db_v2.delete_vxlan_allocations(context.session,
self.delete_vxlan_ranges) self.delete_vxlan_ranges)
self._send_delete_network_profile_request(_network_profile) self._send_delete_network_profile_request(_network_profile)

View File

@ -16,6 +16,7 @@
# #
# @author: Juergen Brendel, Cisco Systems Inc. # @author: Juergen Brendel, Cisco Systems Inc.
# @author: Abhishek Raut, Cisco Systems Inc. # @author: Abhishek Raut, Cisco Systems Inc.
# @author: Rudrajit Tapadar, Cisco Systems Inc.
from sqlalchemy.orm import exc as s_exc from sqlalchemy.orm import exc as s_exc
from testtools import matchers from testtools import matchers
@ -48,6 +49,8 @@ SEGMENT_RANGE_MIN_OVERLAP = '210-230'
SEGMENT_RANGE_MAX_OVERLAP = '190-209' SEGMENT_RANGE_MAX_OVERLAP = '190-209'
SEGMENT_RANGE_OVERLAP = '190-230' SEGMENT_RANGE_OVERLAP = '190-230'
TEST_NETWORK_ID = 'abcdefghijklmnopqrstuvwxyz' TEST_NETWORK_ID = 'abcdefghijklmnopqrstuvwxyz'
TEST_NETWORK_ID2 = 'abcdefghijklmnopqrstuvwxy2'
TEST_NETWORK_ID3 = 'abcdefghijklmnopqrstuvwxy3'
TEST_NETWORK_PROFILE = {'name': 'test_profile', TEST_NETWORK_PROFILE = {'name': 'test_profile',
'segment_type': 'vlan', 'segment_type': 'vlan',
'physical_network': 'physnet1', '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'} 'multicast_ip_range': '239.0.0.70-239.0.0.80'}
TEST_POLICY_PROFILE = {'id': '4a417990-76fb-11e2-bcfd-0800200c9a66', TEST_POLICY_PROFILE = {'id': '4a417990-76fb-11e2-bcfd-0800200c9a66',
'name': 'test_policy_profile'} '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, 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) p = _create_test_network_profile_if_not_there(self.session)
n1kv_db_v2.add_network_binding( n1kv_db_v2.add_network_binding(
self.session, TEST_NETWORK_ID, 'vlan', 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( binding = n1kv_db_v2.get_network_binding(
self.session, TEST_NETWORK_ID) self.session, TEST_NETWORK_ID)
self.assertIsNotNone(binding) self.assertIsNotNone(binding)
@ -407,6 +418,224 @@ class NetworkBindingsTest(test_plugin.NeutronDbPluginV2TestCase):
self.assertEqual(binding.physical_network, PHYS_NET) self.assertEqual(binding.physical_network, PHYS_NET)
self.assertEqual(binding.segmentation_id, 1234) 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, class NetworkProfileTests(base.BaseTestCase,
n1kv_db_v2.NetworkProfile_db_mixin): n1kv_db_v2.NetworkProfile_db_mixin):
@ -436,6 +665,63 @@ class NetworkProfileTests(base.BaseTestCase,
db_profile.multicast_ip_range) db_profile.multicast_ip_range)
n1kv_db_v2.delete_network_profile(self.session, _db_profile.id) 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): def test_create_network_profile_overlap(self):
_db_profile = n1kv_db_v2.create_network_profile(self.session, _db_profile = n1kv_db_v2.create_network_profile(self.session,
TEST_NETWORK_PROFILE_2) TEST_NETWORK_PROFILE_2)