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:
parent
9928edb42d
commit
996bb5e218
@ -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')
|
@ -77,6 +77,12 @@ NETWORK_TYPE_VLAN = 'vlan'
|
||||
NETWORK_TYPE_VXLAN = 'vxlan'
|
||||
NETWORK_TYPE_LOCAL = 'local'
|
||||
NETWORK_TYPE_NONE = 'none'
|
||||
NETWORK_TYPE_TRUNK = 'trunk'
|
||||
NETWORK_TYPE_MULTI_SEGMENT = 'multi-segment'
|
||||
|
||||
# Values for network sub_type
|
||||
NETWORK_SUBTYPE_TRUNK_VLAN = NETWORK_TYPE_VLAN
|
||||
NETWORK_SUBTYPE_TRUNK_VXLAN = NETWORK_TYPE_VXLAN
|
||||
|
||||
# Prefix for VM Network name
|
||||
VM_NETWORK_NAME_PREFIX = 'vmn_'
|
||||
@ -88,3 +94,14 @@ NAME = 'name'
|
||||
ID = 'id'
|
||||
POLICY = 'policy'
|
||||
TENANT_ID_NOT_SET = 'TENANT_ID_NOT_SET'
|
||||
ENCAPSULATIONS = 'encapsulations'
|
||||
STATE = 'state'
|
||||
ONLINE = 'online'
|
||||
MAPPINGS = 'mappings'
|
||||
MAPPING = 'mapping'
|
||||
SEGMENTS = 'segments'
|
||||
SEGMENT = 'segment'
|
||||
BRIDGE_DOMAIN_SUFFIX = '_bd'
|
||||
ENCAPSULATION_PROFILE_SUFFIX = '_profile'
|
||||
|
||||
UUID_LENGTH = 36
|
||||
|
@ -212,3 +212,8 @@ class ProfileTenantBindingNotFound(exceptions.NotFound):
|
||||
"""Profile to Tenant binding for given profile ID cannot be found."""
|
||||
message = _("Profile-Tenant binding for profile %(profile_id)s could "
|
||||
"not be found.")
|
||||
|
||||
|
||||
class NoClusterFound(exceptions.NotFound):
|
||||
"""No service cluster found to perform multi-segment bridging."""
|
||||
message = _("No service cluster found to perform multi-segment bridging.")
|
||||
|
@ -40,6 +40,230 @@ def initialize():
|
||||
db.configure_db()
|
||||
|
||||
|
||||
def del_trunk_segment_binding(db_session, trunk_segment_id, segment_pairs):
|
||||
"""
|
||||
Delete a trunk network binding.
|
||||
|
||||
:param db_session: database session
|
||||
:param trunk_segment_id: UUID representing the trunk network
|
||||
:param segment_pairs: List of segment UUIDs in pair
|
||||
representing the segments that are trunked
|
||||
"""
|
||||
with db_session.begin(subtransactions=True):
|
||||
for (segment_id, dot1qtag) in segment_pairs:
|
||||
(db_session.query(n1kv_models_v2.N1kvTrunkSegmentBinding).
|
||||
filter_by(trunk_segment_id=trunk_segment_id,
|
||||
segment_id=segment_id,
|
||||
dot1qtag=dot1qtag).delete())
|
||||
alloc = (db_session.query(n1kv_models_v2.
|
||||
N1kvTrunkSegmentBinding).
|
||||
filter_by(trunk_segment_id=trunk_segment_id).first())
|
||||
if not alloc:
|
||||
binding = get_network_binding(db_session, trunk_segment_id)
|
||||
binding.physical_network = None
|
||||
|
||||
|
||||
def del_multi_segment_binding(db_session, multi_segment_id, segment_pairs):
|
||||
"""
|
||||
Delete a multi-segment network binding.
|
||||
|
||||
:param db_session: database session
|
||||
:param multi_segment_id: UUID representing the multi-segment network
|
||||
:param segment_pairs: List of segment UUIDs in pair
|
||||
representing the segments that are bridged
|
||||
"""
|
||||
with db_session.begin(subtransactions=True):
|
||||
for (segment1_id, segment2_id) in segment_pairs:
|
||||
(db_session.query(n1kv_models_v2.
|
||||
N1kvMultiSegmentNetworkBinding).filter_by(
|
||||
multi_segment_id=multi_segment_id,
|
||||
segment1_id=segment1_id,
|
||||
segment2_id=segment2_id).delete())
|
||||
|
||||
|
||||
def add_trunk_segment_binding(db_session, trunk_segment_id, segment_pairs):
|
||||
"""
|
||||
Create a trunk network binding.
|
||||
|
||||
:param db_session: database session
|
||||
:param trunk_segment_id: UUID representing the multi-segment network
|
||||
:param segment_pairs: List of segment UUIDs in pair
|
||||
representing the segments to be trunked
|
||||
"""
|
||||
with db_session.begin(subtransactions=True):
|
||||
binding = get_network_binding(db_session, trunk_segment_id)
|
||||
for (segment_id, tag) in segment_pairs:
|
||||
if not binding.physical_network:
|
||||
member_seg_binding = get_network_binding(db_session,
|
||||
segment_id)
|
||||
binding.physical_network = member_seg_binding.physical_network
|
||||
trunk_segment_binding = (
|
||||
n1kv_models_v2.N1kvTrunkSegmentBinding(
|
||||
trunk_segment_id=trunk_segment_id,
|
||||
segment_id=segment_id, dot1qtag=tag))
|
||||
db_session.add(trunk_segment_binding)
|
||||
|
||||
|
||||
def add_multi_segment_binding(db_session, multi_segment_id, segment_pairs):
|
||||
"""
|
||||
Create a multi-segment network binding.
|
||||
|
||||
:param db_session: database session
|
||||
:param multi_segment_id: UUID representing the multi-segment network
|
||||
:param segment_pairs: List of segment UUIDs in pair
|
||||
representing the segments to be bridged
|
||||
"""
|
||||
with db_session.begin(subtransactions=True):
|
||||
for (segment1_id, segment2_id) in segment_pairs:
|
||||
multi_segment_binding = (
|
||||
n1kv_models_v2.N1kvMultiSegmentNetworkBinding(
|
||||
multi_segment_id=multi_segment_id,
|
||||
segment1_id=segment1_id,
|
||||
segment2_id=segment2_id))
|
||||
db_session.add(multi_segment_binding)
|
||||
|
||||
|
||||
def add_multi_segment_encap_profile_name(db_session, multi_segment_id,
|
||||
segment_pair, profile_name):
|
||||
"""
|
||||
Add the encapsulation profile name to the multi-segment network binding.
|
||||
|
||||
:param db_session: database session
|
||||
:param multi_segment_id: UUID representing the multi-segment network
|
||||
:param segment_pair: set containing the segment UUIDs that are bridged
|
||||
"""
|
||||
with db_session.begin(subtransactions=True):
|
||||
binding = get_multi_segment_network_binding(db_session,
|
||||
multi_segment_id,
|
||||
segment_pair)
|
||||
binding.encap_profile_name = profile_name
|
||||
|
||||
|
||||
def get_multi_segment_network_binding(db_session,
|
||||
multi_segment_id, segment_pair):
|
||||
"""
|
||||
Retrieve multi-segment network binding.
|
||||
|
||||
:param db_session: database session
|
||||
:param multi_segment_id: UUID representing the trunk network whose binding
|
||||
is to fetch
|
||||
:param segment_pair: set containing the segment UUIDs that are bridged
|
||||
:returns: binding object
|
||||
"""
|
||||
try:
|
||||
(segment1_id, segment2_id) = segment_pair
|
||||
return (db_session.query(
|
||||
n1kv_models_v2.N1kvMultiSegmentNetworkBinding).
|
||||
filter_by(multi_segment_id=multi_segment_id,
|
||||
segment1_id=segment1_id,
|
||||
segment2_id=segment2_id)).one()
|
||||
except exc.NoResultFound:
|
||||
raise c_exc.NetworkBindingNotFound(network_id=multi_segment_id)
|
||||
|
||||
|
||||
def get_multi_segment_members(db_session, multi_segment_id):
|
||||
"""
|
||||
Retrieve all the member segments of a multi-segment network.
|
||||
|
||||
:param db_session: database session
|
||||
:param multi_segment_id: UUID representing the multi-segment network
|
||||
:returns: a list of tuples representing the mapped segments
|
||||
"""
|
||||
with db_session.begin(subtransactions=True):
|
||||
allocs = (db_session.query(
|
||||
n1kv_models_v2.N1kvMultiSegmentNetworkBinding).
|
||||
filter_by(multi_segment_id=multi_segment_id))
|
||||
return [(a.segment1_id, a.segment2_id) for a in allocs]
|
||||
|
||||
|
||||
def get_multi_segment_encap_dict(db_session, multi_segment_id):
|
||||
"""
|
||||
Retrieve the encapsulation profiles for every segment pairs bridged.
|
||||
|
||||
:param db_session: database session
|
||||
:param multi_segment_id: UUID representing the multi-segment network
|
||||
:returns: a dictionary of lists containing the segment pairs in sets
|
||||
"""
|
||||
with db_session.begin(subtransactions=True):
|
||||
encap_dict = {}
|
||||
allocs = (db_session.query(
|
||||
n1kv_models_v2.N1kvMultiSegmentNetworkBinding).
|
||||
filter_by(multi_segment_id=multi_segment_id))
|
||||
for alloc in allocs:
|
||||
if alloc.encap_profile_name not in encap_dict:
|
||||
encap_dict[alloc.encap_profile_name] = []
|
||||
seg_pair = (alloc.segment1_id, alloc.segment2_id)
|
||||
encap_dict[alloc.encap_profile_name].append(seg_pair)
|
||||
return encap_dict
|
||||
|
||||
|
||||
def get_trunk_network_binding(db_session, trunk_segment_id, segment_pair):
|
||||
"""
|
||||
Retrieve trunk network binding.
|
||||
|
||||
:param db_session: database session
|
||||
:param trunk_segment_id: UUID representing the trunk network whose binding
|
||||
is to fetch
|
||||
:param segment_pair: set containing the segment_id and dot1qtag
|
||||
:returns: binding object
|
||||
"""
|
||||
try:
|
||||
(segment_id, dot1qtag) = segment_pair
|
||||
return (db_session.query(n1kv_models_v2.N1kvTrunkSegmentBinding).
|
||||
filter_by(trunk_segment_id=trunk_segment_id,
|
||||
segment_id=segment_id,
|
||||
dot1qtag=dot1qtag)).one()
|
||||
except exc.NoResultFound:
|
||||
raise c_exc.NetworkBindingNotFound(network_id=trunk_segment_id)
|
||||
|
||||
|
||||
def get_trunk_members(db_session, trunk_segment_id):
|
||||
"""
|
||||
Retrieve all the member segments of a trunk network.
|
||||
|
||||
:param db_session: database session
|
||||
:param trunk_segment_id: UUID representing the trunk network
|
||||
:returns: a list of tuples representing the segment and their
|
||||
corresponding dot1qtag
|
||||
"""
|
||||
with db_session.begin(subtransactions=True):
|
||||
allocs = (db_session.query(n1kv_models_v2.N1kvTrunkSegmentBinding).
|
||||
filter_by(trunk_segment_id=trunk_segment_id))
|
||||
return [(a.segment_id, a.dot1qtag) for a in allocs]
|
||||
|
||||
|
||||
def is_trunk_member(db_session, segment_id):
|
||||
"""
|
||||
Checks if a segment is a member of a trunk segment.
|
||||
|
||||
:param db_session: database session
|
||||
:param segment_id: UUID of the segment to be checked
|
||||
:returns: boolean
|
||||
"""
|
||||
with db_session.begin(subtransactions=True):
|
||||
ret = (db_session.query(n1kv_models_v2.N1kvTrunkSegmentBinding).
|
||||
filter_by(segment_id=segment_id).first())
|
||||
return bool(ret)
|
||||
|
||||
|
||||
def is_multi_segment_member(db_session, segment_id):
|
||||
"""
|
||||
Checks if a segment is a member of a multi-segment network.
|
||||
|
||||
:param db_session: database session
|
||||
:param segment_id: UUID of the segment to be checked
|
||||
:returns: boolean
|
||||
"""
|
||||
with db_session.begin(subtransactions=True):
|
||||
ret1 = (db_session.query(
|
||||
n1kv_models_v2.N1kvMultiSegmentNetworkBinding).
|
||||
filter_by(segment1_id=segment_id).first())
|
||||
ret2 = (db_session.query(
|
||||
n1kv_models_v2.N1kvMultiSegmentNetworkBinding).
|
||||
filter_by(segment2_id=segment_id).first())
|
||||
return bool(ret1 or ret2)
|
||||
|
||||
|
||||
def get_network_binding(db_session, network_id):
|
||||
"""
|
||||
Retrieve network binding.
|
||||
@ -59,13 +283,14 @@ def get_network_binding(db_session, network_id):
|
||||
|
||||
def add_network_binding(db_session, network_id, network_type,
|
||||
physical_network, segmentation_id,
|
||||
multicast_ip, network_profile_id):
|
||||
multicast_ip, network_profile_id, add_segments):
|
||||
"""
|
||||
Create network binding.
|
||||
|
||||
:param db_session: database session
|
||||
:param network_id: UUID representing the network
|
||||
:param network_type: string representing type of network (VLAN or VXLAN)
|
||||
:param network_type: string representing type of network (VLAN, VXLAN,
|
||||
MULTI_SEGMENT or TRUNK)
|
||||
:param physical_network: Only applicable for VLAN networks. It
|
||||
represents a L2 Domain
|
||||
:param segmentation_id: integer representing VLAN or VXLAN ID
|
||||
@ -75,6 +300,8 @@ def add_network_binding(db_session, network_id, network_type,
|
||||
IDs.
|
||||
:param network_profile_id: network profile ID based on which this network
|
||||
is created
|
||||
:param add_segments: List of segment UUIDs in pairs to be added to either a
|
||||
multi-segment or trunk network
|
||||
"""
|
||||
with db_session.begin(subtransactions=True):
|
||||
binding = n1kv_models_v2.N1kvNetworkBinding(
|
||||
@ -85,6 +312,12 @@ def add_network_binding(db_session, network_id, network_type,
|
||||
multicast_ip=multicast_ip,
|
||||
profile_id=network_profile_id)
|
||||
db_session.add(binding)
|
||||
if add_segments is None:
|
||||
pass
|
||||
elif network_type == c_const.NETWORK_TYPE_MULTI_SEGMENT:
|
||||
add_multi_segment_binding(db_session, network_id, add_segments)
|
||||
elif network_type == c_const.NETWORK_TYPE_TRUNK:
|
||||
add_trunk_segment_binding(db_session, network_id, add_segments)
|
||||
|
||||
|
||||
def get_segment_range(network_profile):
|
||||
@ -262,6 +495,8 @@ def reserve_vlan(db_session, network_profile):
|
||||
filter(and_(
|
||||
n1kv_models_v2.N1kvVlanAllocation.vlan_id >= seg_min,
|
||||
n1kv_models_v2.N1kvVlanAllocation.vlan_id <= seg_max,
|
||||
n1kv_models_v2.N1kvVlanAllocation.physical_network ==
|
||||
network_profile['physical_network'],
|
||||
n1kv_models_v2.N1kvVlanAllocation.allocated == False)
|
||||
)).first()
|
||||
if alloc:
|
||||
@ -314,8 +549,9 @@ def alloc_network(db_session, network_profile_id):
|
||||
network_profile_id)
|
||||
if network_profile.segment_type == c_const.NETWORK_TYPE_VLAN:
|
||||
return reserve_vlan(db_session, network_profile)
|
||||
else:
|
||||
if network_profile.segment_type == c_const.NETWORK_TYPE_VXLAN:
|
||||
return reserve_vxlan(db_session, network_profile)
|
||||
return (None, network_profile.segment_type, 0, "0.0.0.0")
|
||||
|
||||
|
||||
def reserve_specific_vlan(db_session, physical_network, vlan_id):
|
||||
@ -601,14 +837,17 @@ def create_network_profile(db_session, network_profile):
|
||||
LOG.debug(_("create_network_profile()"))
|
||||
with db_session.begin(subtransactions=True):
|
||||
kwargs = {"name": network_profile["name"],
|
||||
"segment_type": network_profile["segment_type"],
|
||||
"segment_range": network_profile["segment_range"]}
|
||||
"segment_type": network_profile["segment_type"]}
|
||||
if network_profile["segment_type"] == c_const.NETWORK_TYPE_VLAN:
|
||||
kwargs["physical_network"] = network_profile["physical_network"]
|
||||
kwargs["segment_range"] = network_profile["segment_range"]
|
||||
elif network_profile["segment_type"] == c_const.NETWORK_TYPE_VXLAN:
|
||||
kwargs["multicast_ip_index"] = 0
|
||||
kwargs["multicast_ip_range"] = network_profile[
|
||||
"multicast_ip_range"]
|
||||
kwargs["segment_range"] = network_profile["segment_range"]
|
||||
elif network_profile["segment_type"] == c_const.NETWORK_TYPE_TRUNK:
|
||||
kwargs["sub_type"] = network_profile["sub_type"]
|
||||
net_profile = n1kv_models_v2.NetworkProfile(**kwargs)
|
||||
db_session.add(net_profile)
|
||||
return net_profile
|
||||
@ -659,7 +898,6 @@ def _get_network_profiles(**kwargs):
|
||||
if "physical_network" in kwargs:
|
||||
return (db_session.query(n1kv_models_v2.NetworkProfile).
|
||||
filter_by(physical_network=kwargs["physical_network"]))
|
||||
else:
|
||||
return db_session.query(n1kv_models_v2.NetworkProfile)
|
||||
|
||||
|
||||
@ -730,9 +968,8 @@ def _profile_binding_exists(tenant_id, profile_id, profile_type):
|
||||
def _get_profile_binding(tenant_id, profile_id):
|
||||
LOG.debug(_("_get_profile_binding"))
|
||||
db_session = db.get_session()
|
||||
binding = db_session.query(n1kv_models_v2.ProfileBinding).filter_by(
|
||||
tenant_id=tenant_id, profile_id=profile_id).one()
|
||||
return binding
|
||||
return (db_session.query(n1kv_models_v2.ProfileBinding).filter_by(
|
||||
tenant_id=tenant_id, profile_id=profile_id).one())
|
||||
|
||||
|
||||
def get_profile_binding(tenant_id, profile_id):
|
||||
@ -773,7 +1010,6 @@ def _get_profile_bindings(profile_type=None):
|
||||
profile_bindings = (db_session.query(n1kv_models_v2.ProfileBinding).
|
||||
filter_by(profile_type=profile_type))
|
||||
return profile_bindings
|
||||
else:
|
||||
return db_session.query(n1kv_models_v2.ProfileBinding)
|
||||
|
||||
|
||||
@ -815,6 +1051,7 @@ class NetworkProfile_db_mixin(object):
|
||||
res = {"id": network_profile["id"],
|
||||
"name": network_profile["name"],
|
||||
"segment_type": network_profile["segment_type"],
|
||||
"sub_type": network_profile["sub_type"],
|
||||
"segment_range": network_profile["segment_range"],
|
||||
"multicast_ip_index": network_profile["multicast_ip_index"],
|
||||
"multicast_ip_range": network_profile["multicast_ip_range"],
|
||||
@ -888,11 +1125,10 @@ class NetworkProfile_db_mixin(object):
|
||||
self.add_network_profile_tenant(id, p["add_tenant"])
|
||||
return self._make_network_profile_dict(get_network_profile(
|
||||
context.session, id))
|
||||
elif context.is_admin and "remove_tenant" in p:
|
||||
if context.is_admin and "remove_tenant" in p:
|
||||
delete_profile_binding(p["remove_tenant"], id)
|
||||
return self._make_network_profile_dict(get_network_profile(
|
||||
context.session, id))
|
||||
else:
|
||||
return self._make_network_profile_dict(
|
||||
update_network_profile(context.session, id, p))
|
||||
|
||||
@ -930,7 +1166,6 @@ class NetworkProfile_db_mixin(object):
|
||||
return self._get_collection(context, n1kv_models_v2.NetworkProfile,
|
||||
self._make_network_profile_dict,
|
||||
filters=filters, fields=fields)
|
||||
else:
|
||||
return self._get_network_collection_for_tenant(context.session,
|
||||
n1kv_models_v2.
|
||||
NetworkProfile,
|
||||
@ -992,19 +1227,41 @@ class NetworkProfile_db_mixin(object):
|
||||
|
||||
:param net_p: network profile object
|
||||
"""
|
||||
if any(net_p[arg] == "" for arg in ("segment_type", "segment_range")):
|
||||
msg = _("arguments segment_type and segment_range missing"
|
||||
if any(net_p[arg] == "" for arg in ["segment_type"]):
|
||||
msg = _("arguments segment_type missing"
|
||||
" for network profile")
|
||||
LOG.exception(msg)
|
||||
raise q_exc.InvalidInput(error_message=msg)
|
||||
_segment_type = net_p["segment_type"].lower()
|
||||
if _segment_type not in [c_const.NETWORK_TYPE_VLAN,
|
||||
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)
|
||||
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]:
|
||||
msg = _("segment_type should either be vlan or 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_VLAN:
|
||||
if segment_type != c_const.NETWORK_TYPE_VXLAN:
|
||||
net_p["multicast_ip_range"] = "0.0.0.0"
|
||||
|
||||
def _validate_segment_range_uniqueness(self, context, net_p):
|
||||
@ -1018,28 +1275,30 @@ class NetworkProfile_db_mixin(object):
|
||||
if segment_type == c_const.NETWORK_TYPE_VLAN:
|
||||
profiles = _get_network_profiles(
|
||||
physical_network=net_p["physical_network"])
|
||||
elif segment_type == c_const.NETWORK_TYPE_VXLAN:
|
||||
profiles = _get_network_profiles()
|
||||
else:
|
||||
# TODO(Abhishek): Handle this when we support other segment types
|
||||
return
|
||||
profiles = _get_network_profiles()
|
||||
if profiles:
|
||||
for prfl in profiles:
|
||||
name = prfl.name
|
||||
segment_range = prfl.segment_range
|
||||
for profile in profiles:
|
||||
name = profile.name
|
||||
segment_range = profile.segment_range
|
||||
if net_p["name"] == name:
|
||||
msg = (_("NetworkProfile name %s already exists"),
|
||||
net_p["name"])
|
||||
LOG.exception(msg)
|
||||
raise q_exc.InvalidInput(error_message=msg)
|
||||
if (c_const.NETWORK_TYPE_MULTI_SEGMENT in
|
||||
[profile.segment_type, net_p["segment_type"]] or
|
||||
c_const.NETWORK_TYPE_TRUNK in
|
||||
[profile.segment_type, net_p["segment_type"]]):
|
||||
continue
|
||||
seg_min, seg_max = self._get_segment_range(
|
||||
net_p["segment_range"])
|
||||
prfl_seg_min, prfl_seg_max = self._get_segment_range(
|
||||
profile_seg_min, profile_seg_max = self._get_segment_range(
|
||||
segment_range)
|
||||
if ((prfl_seg_min <= seg_min <= prfl_seg_max) or
|
||||
(prfl_seg_min <= seg_max <= prfl_seg_max) or
|
||||
((seg_min <= prfl_seg_min) and
|
||||
(seg_max >= prfl_seg_max))):
|
||||
if ((profile_seg_min <= seg_min <= profile_seg_max) or
|
||||
(profile_seg_min <= seg_max <= profile_seg_max) or
|
||||
((seg_min <= profile_seg_min) and
|
||||
(seg_max >= profile_seg_max))):
|
||||
msg = _("segment range overlaps with another profile")
|
||||
LOG.exception(msg)
|
||||
raise q_exc.InvalidInput(error_message=msg)
|
||||
@ -1149,11 +1408,10 @@ class PolicyProfile_db_mixin(object):
|
||||
self.add_policy_profile_tenant(id, p["add_tenant"])
|
||||
return self._make_policy_profile_dict(get_policy_profile(
|
||||
context.session, id))
|
||||
elif context.is_admin and "remove_tenant" in p:
|
||||
if context.is_admin and "remove_tenant" in p:
|
||||
delete_profile_binding(p["remove_tenant"], id)
|
||||
return self._make_policy_profile_dict(get_policy_profile(
|
||||
context.session, id))
|
||||
else:
|
||||
return self._make_policy_profile_dict(
|
||||
update_policy_profile(context.session, id, p))
|
||||
|
||||
|
@ -15,6 +15,7 @@
|
||||
# under the License.
|
||||
#
|
||||
# @author: Abhishek Raut, Cisco Systems Inc.
|
||||
# @author: Rudrajit Tapadar, Cisco Systems Inc.
|
||||
|
||||
import sqlalchemy as sa
|
||||
|
||||
@ -95,7 +96,8 @@ class NetworkProfile(model_base.BASEV2, models_v2.HasId):
|
||||
"""
|
||||
Nexus1000V Network Profiles
|
||||
|
||||
segment_type - VLAN, VXLAN
|
||||
segment_type - VLAN, VXLAN, TRUNK, MULTI_SEGMENT
|
||||
sub_type - TRUNK_VLAN, TRUNK_VXLAN
|
||||
segment_range - '<integer>-<integer>'
|
||||
multicast_ip_index - <integer>
|
||||
multicast_ip_range - '<ip>-<ip>'
|
||||
@ -106,8 +108,12 @@ class NetworkProfile(model_base.BASEV2, models_v2.HasId):
|
||||
name = sa.Column(sa.String(255))
|
||||
segment_type = sa.Column(sa.Enum(cisco_constants.NETWORK_TYPE_VLAN,
|
||||
cisco_constants.NETWORK_TYPE_VXLAN,
|
||||
cisco_constants.NETWORK_TYPE_TRUNK,
|
||||
cisco_constants.
|
||||
NETWORK_TYPE_MULTI_SEGMENT,
|
||||
name='segment_type'),
|
||||
nullable=False)
|
||||
sub_type = sa.Column(sa.String(255))
|
||||
segment_range = sa.Column(sa.String(255))
|
||||
multicast_ip_index = sa.Column(sa.Integer, default=0)
|
||||
multicast_ip_range = sa.Column(sa.String(255))
|
||||
@ -142,3 +148,30 @@ class ProfileBinding(model_base.BASEV2):
|
||||
primary_key=True,
|
||||
default=cisco_constants.TENANT_ID_NOT_SET)
|
||||
profile_id = sa.Column(sa.String(36), primary_key=True)
|
||||
|
||||
|
||||
class N1kvTrunkSegmentBinding(model_base.BASEV2):
|
||||
|
||||
"""Represents binding of segments in trunk networks."""
|
||||
__tablename__ = 'cisco_n1kv_trunk_segments'
|
||||
|
||||
trunk_segment_id = sa.Column(sa.String(36),
|
||||
sa.ForeignKey('networks.id',
|
||||
ondelete="CASCADE"),
|
||||
primary_key=True)
|
||||
segment_id = sa.Column(sa.String(36), nullable=False, primary_key=True)
|
||||
dot1qtag = sa.Column(sa.String(36), nullable=False, primary_key=True)
|
||||
|
||||
|
||||
class N1kvMultiSegmentNetworkBinding(model_base.BASEV2):
|
||||
|
||||
"""Represents binding of segments in multi-segment networks."""
|
||||
__tablename__ = 'cisco_n1kv_multi_segments'
|
||||
|
||||
multi_segment_id = sa.Column(sa.String(36),
|
||||
sa.ForeignKey('networks.id',
|
||||
ondelete="CASCADE"),
|
||||
primary_key=True)
|
||||
segment1_id = sa.Column(sa.String(36), nullable=False, primary_key=True)
|
||||
segment2_id = sa.Column(sa.String(36), nullable=False, primary_key=True)
|
||||
encap_profile_name = sa.Column(sa.String(36))
|
||||
|
@ -24,6 +24,9 @@ from neutron.api.v2 import attributes
|
||||
|
||||
PROFILE_ID = 'n1kv:profile_id'
|
||||
MULTICAST_IP = 'n1kv:multicast_ip'
|
||||
SEGMENT_ADD = 'n1kv:segment_add'
|
||||
SEGMENT_DEL = 'n1kv:segment_del'
|
||||
MEMBER_SEGMENTS = 'n1kv:member_segments'
|
||||
|
||||
EXTENDED_ATTRIBUTES_2_0 = {
|
||||
'networks': {
|
||||
@ -34,6 +37,15 @@ EXTENDED_ATTRIBUTES_2_0 = {
|
||||
MULTICAST_IP: {'allow_post': True, 'allow_put': True,
|
||||
'default': attributes.ATTR_NOT_SPECIFIED,
|
||||
'is_visible': True},
|
||||
SEGMENT_ADD: {'allow_post': True, 'allow_put': True,
|
||||
'default': attributes.ATTR_NOT_SPECIFIED,
|
||||
'is_visible': True},
|
||||
SEGMENT_DEL: {'allow_post': True, 'allow_put': True,
|
||||
'default': attributes.ATTR_NOT_SPECIFIED,
|
||||
'is_visible': True},
|
||||
MEMBER_SEGMENTS: {'allow_post': True, 'allow_put': True,
|
||||
'default': attributes.ATTR_NOT_SPECIFIED,
|
||||
'is_visible': True},
|
||||
},
|
||||
'ports': {
|
||||
PROFILE_ID: {'allow_post': True, 'allow_put': True,
|
||||
|
@ -16,6 +16,7 @@
|
||||
#
|
||||
# @author: Abhishek Raut, Cisco Systems, Inc.
|
||||
# @author: Sergey Sudakovich, Cisco Systems, Inc.
|
||||
# @author: Rudrajit Tapadar, Cisco Systems, Inc.
|
||||
|
||||
from neutron.api import extensions
|
||||
from neutron.api.v2 import attributes
|
||||
@ -33,6 +34,9 @@ RESOURCE_ATTRIBUTE_MAP = {
|
||||
'is_visible': True, 'default': ''},
|
||||
'segment_type': {'allow_post': True, 'allow_put': True,
|
||||
'is_visible': True, 'default': ''},
|
||||
'sub_type': {'allow_post': True, 'allow_put': True,
|
||||
'is_visible': True,
|
||||
'default': attributes.ATTR_NOT_SPECIFIED},
|
||||
'segment_range': {'allow_post': True, 'allow_put': True,
|
||||
'is_visible': True, 'default': ''},
|
||||
'multicast_ip_range': {'allow_post': True, 'allow_put': True,
|
||||
@ -82,7 +86,7 @@ class Network_profile(extensions.ExtensionDescriptor):
|
||||
|
||||
@classmethod
|
||||
def get_resources(cls):
|
||||
"""Returns Ext Resources."""
|
||||
"""Returns Extended Resources."""
|
||||
exts = []
|
||||
plugin = manager.NeutronManager.get_plugin()
|
||||
for resource_name in ['network_profile', 'network_profile_binding']:
|
||||
|
@ -69,7 +69,7 @@ class Policy_profile(extensions.ExtensionDescriptor):
|
||||
|
||||
@classmethod
|
||||
def get_resources(cls):
|
||||
"""Returns Ext Resources."""
|
||||
"""Returns Extended Resources."""
|
||||
exts = []
|
||||
plugin = manager.NeutronManager.get_plugin()
|
||||
for resource_name in ['policy_profile', 'policy_profile_binding']:
|
||||
|
@ -15,6 +15,7 @@
|
||||
# under the License.
|
||||
#
|
||||
# @author: Abhishek Raut, Cisco Systems, Inc.
|
||||
# @author: Rudrajit Tapadar, Cisco Systems, Inc.
|
||||
|
||||
import base64
|
||||
import httplib2
|
||||
@ -117,7 +118,9 @@ class Client(object):
|
||||
"networks": "network",
|
||||
"ports": "port",
|
||||
"set": "instance",
|
||||
"subnets": "subnet"
|
||||
"subnets": "subnet",
|
||||
"mappings": "mapping",
|
||||
"segments": "segment"
|
||||
}
|
||||
}
|
||||
|
||||
@ -138,6 +141,9 @@ class Client(object):
|
||||
logical_networks_path = "/logical-network"
|
||||
logical_network_path = "/logical-network/%s"
|
||||
events_path = "/kvm/events"
|
||||
clusters_path = "/cluster"
|
||||
encap_profiles_path = "/encapsulation-profile"
|
||||
encap_profile_path = "/encapsulation-profile/%s"
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
"""Initialize a new client for the plugin."""
|
||||
@ -171,7 +177,7 @@ class Client(object):
|
||||
|
||||
:param network: network dict
|
||||
"""
|
||||
body = {'name': network['name'] + '_bd',
|
||||
body = {'name': network['name'] + c_const.BRIDGE_DOMAIN_SUFFIX,
|
||||
'segmentId': network[providernet.SEGMENTATION_ID],
|
||||
'groupIp': network[n1kv_profile.MULTICAST_IP], }
|
||||
return self._post(self.bridge_domains_path,
|
||||
@ -199,7 +205,20 @@ class Client(object):
|
||||
if network[providernet.NETWORK_TYPE] == c_const.NETWORK_TYPE_VLAN:
|
||||
body['vlan'] = network[providernet.SEGMENTATION_ID]
|
||||
elif network[providernet.NETWORK_TYPE] == c_const.NETWORK_TYPE_VXLAN:
|
||||
body['bridgeDomain'] = network['name'] + '_bd'
|
||||
body['bridgeDomain'] = (network['name'] +
|
||||
c_const.BRIDGE_DOMAIN_SUFFIX)
|
||||
if network_profile['segment_type'] == c_const.NETWORK_TYPE_TRUNK:
|
||||
body['mode'] = c_const.NETWORK_TYPE_TRUNK
|
||||
body['segmentType'] = network_profile['sub_type']
|
||||
if network_profile['sub_type'] == c_const.NETWORK_TYPE_VLAN:
|
||||
body['addSegments'] = network['add_segment_list']
|
||||
body['delSegments'] = network['del_segment_list']
|
||||
else:
|
||||
body['encapProfile'] = (network['name'] +
|
||||
c_const.ENCAPSULATION_PROFILE_SUFFIX)
|
||||
else:
|
||||
body['mode'] = 'access'
|
||||
body['segmentType'] = network_profile['segment_type']
|
||||
return self._post(self.network_segments_path,
|
||||
body=body)
|
||||
|
||||
@ -498,3 +517,37 @@ class Client(object):
|
||||
auth = base64.encodestring("%s:%s" % (username, password))
|
||||
header = {"Authorization": "Basic %s" % auth}
|
||||
return header
|
||||
|
||||
def get_clusters(self):
|
||||
"""Fetches a list of all vxlan gateway clusters."""
|
||||
return self._get(self.clusters_path)
|
||||
|
||||
def create_encapsulation_profile(self, encap):
|
||||
"""
|
||||
Create an encapsulation profile on VSM.
|
||||
|
||||
:param encap: encapsulation dict
|
||||
"""
|
||||
body = {'name': encap['name'],
|
||||
'addMappings': encap['add_segment_list'],
|
||||
'delMappings': encap['del_segment_list']}
|
||||
return self._post(self.encap_profiles_path,
|
||||
body=body)
|
||||
|
||||
def update_encapsulation_profile(self, context, profile_name, body):
|
||||
"""
|
||||
Adds a vlan to bridge-domain mapping to an encapsulation profile.
|
||||
|
||||
:param profile_name: Name of the encapsulation profile
|
||||
:param body: mapping dictionary
|
||||
"""
|
||||
return self._post(self.encap_profile_path
|
||||
% (profile_name), body=body)
|
||||
|
||||
def delete_encapsulation_profile(self, name):
|
||||
"""
|
||||
Delete an encapsulation profile on VSM.
|
||||
|
||||
:param name: name of the encapsulation profile to be deleted
|
||||
"""
|
||||
return self._delete(self.encap_profile_path % (name))
|
||||
|
@ -30,6 +30,7 @@ from neutron.api.v2 import attributes
|
||||
from neutron.common import exceptions as q_exc
|
||||
from neutron.common import rpc as q_rpc
|
||||
from neutron.common import topics
|
||||
from neutron.common import utils
|
||||
from neutron.db import agents_db
|
||||
from neutron.db import agentschedulers_db
|
||||
from neutron.db import db_base_plugin_v2
|
||||
@ -41,6 +42,7 @@ from neutron.extensions import providernet
|
||||
from neutron.openstack.common import log as logging
|
||||
from neutron.openstack.common import rpc
|
||||
from neutron.openstack.common.rpc import proxy
|
||||
from neutron.openstack.common import uuidutils as uuidutils
|
||||
from neutron.plugins.cisco.common import cisco_constants as c_const
|
||||
from neutron.plugins.cisco.common import cisco_credentials_v2 as c_cred
|
||||
from neutron.plugins.cisco.common import cisco_exceptions
|
||||
@ -281,6 +283,14 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
elif binding.network_type == c_const.NETWORK_TYPE_VLAN:
|
||||
network[providernet.PHYSICAL_NETWORK] = binding.physical_network
|
||||
network[providernet.SEGMENTATION_ID] = binding.segmentation_id
|
||||
elif binding.network_type == c_const.NETWORK_TYPE_TRUNK:
|
||||
network[providernet.PHYSICAL_NETWORK] = binding.physical_network
|
||||
network[providernet.SEGMENTATION_ID] = None
|
||||
network[n1kv_profile.MULTICAST_IP] = None
|
||||
elif binding.network_type == c_const.NETWORK_TYPE_MULTI_SEGMENT:
|
||||
network[providernet.PHYSICAL_NETWORK] = None
|
||||
network[providernet.SEGMENTATION_ID] = None
|
||||
network[n1kv_profile.MULTICAST_IP] = None
|
||||
|
||||
def _process_provider_create(self, context, attrs):
|
||||
network_type = attrs.get(providernet.NETWORK_TYPE)
|
||||
@ -356,6 +366,283 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
msg = _("plugin does not support updating provider attributes")
|
||||
raise q_exc.InvalidInput(error_message=msg)
|
||||
|
||||
def _get_cluster(self, segment1, segment2, clusters):
|
||||
"""
|
||||
Returns a cluster to apply the segment mapping
|
||||
|
||||
:param segment1: UUID of segment to be mapped
|
||||
:param segment2: UUID of segment to be mapped
|
||||
:param clusters: List of clusters
|
||||
"""
|
||||
for cluster in sorted(clusters, key=lambda k: k['size']):
|
||||
for mapping in cluster[c_const.MAPPINGS]:
|
||||
for segment in mapping[c_const.SEGMENTS]:
|
||||
if segment1 in segment or segment2 in segment:
|
||||
break
|
||||
else:
|
||||
cluster['size'] += 2
|
||||
return cluster['encapProfileName']
|
||||
break
|
||||
return
|
||||
|
||||
def _extend_mapping_dict(self, context, mapping_dict, segment):
|
||||
"""
|
||||
Extends a mapping dictionary by populating dot1q tag and
|
||||
bridge-domain name.
|
||||
|
||||
:param context: neutron api request context
|
||||
:param mapping_dict: dictionary to populate values
|
||||
:param segment: id of the segment being populated
|
||||
"""
|
||||
net = self.get_network(context, segment)
|
||||
if net[providernet.NETWORK_TYPE] == c_const.NETWORK_TYPE_VLAN:
|
||||
mapping_dict['dot1q'] = str(net[providernet.SEGMENTATION_ID])
|
||||
else:
|
||||
mapping_dict['bridgeDomain'] = (net['name'] +
|
||||
c_const.BRIDGE_DOMAIN_SUFFIX)
|
||||
|
||||
def _send_add_multi_segment_request(self, context, net_id, segment_pairs):
|
||||
"""
|
||||
Send Add multi-segment network request to VSM.
|
||||
|
||||
:param context: neutron api request context
|
||||
:param net_id: UUID of the multi-segment network
|
||||
:param segment_pairs: List of segments in UUID pairs
|
||||
that need to be bridged
|
||||
"""
|
||||
|
||||
if not segment_pairs:
|
||||
return
|
||||
|
||||
session = context.session
|
||||
n1kvclient = n1kv_client.Client()
|
||||
clusters = n1kvclient.get_clusters()
|
||||
online_clusters = []
|
||||
encap_dict = {}
|
||||
for cluster in clusters['body'][c_const.SET]:
|
||||
cluster = cluster[c_const.PROPERTIES]
|
||||
if cluster[c_const.STATE] == c_const.ONLINE:
|
||||
cluster['size'] = 0
|
||||
for mapping in cluster[c_const.MAPPINGS]:
|
||||
cluster['size'] += (
|
||||
len(mapping[c_const.SEGMENTS]))
|
||||
online_clusters.append(cluster)
|
||||
for (segment1, segment2) in segment_pairs:
|
||||
encap_profile = self._get_cluster(segment1, segment2,
|
||||
online_clusters)
|
||||
if encap_profile is not None:
|
||||
if encap_profile in encap_dict:
|
||||
profile_dict = encap_dict[encap_profile]
|
||||
else:
|
||||
profile_dict = {'name': encap_profile,
|
||||
'addMappings': [],
|
||||
'delMappings': []}
|
||||
encap_dict[encap_profile] = profile_dict
|
||||
mapping_dict = {}
|
||||
self._extend_mapping_dict(context,
|
||||
mapping_dict, segment1)
|
||||
self._extend_mapping_dict(context,
|
||||
mapping_dict, segment2)
|
||||
profile_dict['addMappings'].append(mapping_dict)
|
||||
n1kv_db_v2.add_multi_segment_encap_profile_name(session,
|
||||
net_id,
|
||||
(segment1,
|
||||
segment2),
|
||||
encap_profile)
|
||||
else:
|
||||
raise cisco_exceptions.NoClusterFound
|
||||
|
||||
for profile in encap_dict:
|
||||
n1kvclient.update_encapsulation_profile(context, profile,
|
||||
encap_dict[profile])
|
||||
|
||||
def _send_del_multi_segment_request(self, context, net_id, segment_pairs):
|
||||
"""
|
||||
Send Delete multi-segment network request to VSM.
|
||||
|
||||
:param context: neutron api request context
|
||||
:param net_id: UUID of the multi-segment network
|
||||
:param segment_pairs: List of segments in UUID pairs
|
||||
whose bridging needs to be removed
|
||||
"""
|
||||
if not segment_pairs:
|
||||
return
|
||||
session = context.session
|
||||
encap_dict = {}
|
||||
n1kvclient = n1kv_client.Client()
|
||||
for (segment1, segment2) in segment_pairs:
|
||||
binding = (
|
||||
n1kv_db_v2.get_multi_segment_network_binding(session, net_id,
|
||||
(segment1,
|
||||
segment2)))
|
||||
encap_profile = binding['encap_profile_name']
|
||||
if encap_profile in encap_dict:
|
||||
profile_dict = encap_dict[encap_profile]
|
||||
else:
|
||||
profile_dict = {'name': encap_profile,
|
||||
'addMappings': [],
|
||||
'delMappings': []}
|
||||
encap_dict[encap_profile] = profile_dict
|
||||
mapping_dict = {}
|
||||
self._extend_mapping_dict(context,
|
||||
mapping_dict, segment1)
|
||||
self._extend_mapping_dict(context,
|
||||
mapping_dict, segment2)
|
||||
profile_dict['delMappings'].append(mapping_dict)
|
||||
|
||||
for profile in encap_dict:
|
||||
n1kvclient.update_encapsulation_profile(context, profile,
|
||||
encap_dict[profile])
|
||||
|
||||
def _get_encap_segments(self, context, segment_pairs):
|
||||
"""
|
||||
Get the list of segments in encapsulation profile format.
|
||||
|
||||
:param context: neutron api request context
|
||||
:param segment_pairs: List of segments that need to be bridged
|
||||
"""
|
||||
member_list = []
|
||||
for pair in segment_pairs:
|
||||
(segment, dot1qtag) = pair
|
||||
member_dict = {}
|
||||
net = self.get_network(context, segment)
|
||||
member_dict['bridgeDomain'] = (net['name'] +
|
||||
c_const.BRIDGE_DOMAIN_SUFFIX)
|
||||
member_dict['dot1q'] = dot1qtag
|
||||
member_list.append(member_dict)
|
||||
return member_list
|
||||
|
||||
def _populate_member_segments(self, context, network, segment_pairs, oper):
|
||||
"""
|
||||
Populate trunk network dict with member segments.
|
||||
|
||||
:param context: neutron api request context
|
||||
:param network: Dictionary containing the trunk network information
|
||||
:param segment_pairs: List of segments in UUID pairs
|
||||
that needs to be trunked
|
||||
:param oper: Operation to be performed
|
||||
"""
|
||||
LOG.debug(_('_populate_member_segments %s'), segment_pairs)
|
||||
trunk_list = []
|
||||
for (segment, dot1qtag) in segment_pairs:
|
||||
net = self.get_network(context, segment)
|
||||
member_dict = {'segment': net['name'],
|
||||
'dot1qtag': dot1qtag}
|
||||
trunk_list.append(member_dict)
|
||||
if oper == n1kv_profile.SEGMENT_ADD:
|
||||
network['add_segment_list'] = trunk_list
|
||||
elif oper == n1kv_profile.SEGMENT_DEL:
|
||||
network['del_segment_list'] = trunk_list
|
||||
|
||||
def _parse_multi_segments(self, context, attrs, param):
|
||||
"""
|
||||
Parse the multi-segment network attributes
|
||||
|
||||
:param context: neutron api request context
|
||||
:param attrs: Attributes of the network
|
||||
:param param: Additional parameter indicating an add
|
||||
or del operation
|
||||
:returns: List of segment UUIDs in set pairs
|
||||
"""
|
||||
pair_list = []
|
||||
valid_seg_types = [c_const.NETWORK_TYPE_VLAN,
|
||||
c_const.NETWORK_TYPE_VXLAN]
|
||||
segments = attrs.get(param)
|
||||
if not attributes.is_attr_set(segments):
|
||||
return pair_list
|
||||
for pair in segments.split(','):
|
||||
segment1, sep, segment2 = pair.partition(':')
|
||||
if (uuidutils.is_uuid_like(segment1) and
|
||||
uuidutils.is_uuid_like(segment2)):
|
||||
binding1 = n1kv_db_v2.get_network_binding(context.session,
|
||||
segment1)
|
||||
binding2 = n1kv_db_v2.get_network_binding(context.session,
|
||||
segment2)
|
||||
if (binding1.network_type not in valid_seg_types or
|
||||
binding2.network_type not in valid_seg_types or
|
||||
binding1.network_type == binding2.network_type):
|
||||
msg = _("Invalid pairing supplied")
|
||||
raise q_exc.InvalidInput(error_message=msg)
|
||||
else:
|
||||
pair_list.append((segment1, segment2))
|
||||
else:
|
||||
LOG.debug(_('Invalid UUID supplied in %s'), pair)
|
||||
msg = _("Invalid UUID supplied")
|
||||
raise q_exc.InvalidInput(error_message=msg)
|
||||
return pair_list
|
||||
|
||||
def _parse_trunk_segments(self, context, attrs, param, physical_network,
|
||||
sub_type):
|
||||
"""
|
||||
Parse the trunk network attributes
|
||||
|
||||
:param context: neutron api request context
|
||||
:param attrs: Attributes of the network
|
||||
:param param: Additional parameter indicating an add
|
||||
or del operation
|
||||
:param physical_network: Physical network of the trunk segment
|
||||
:param sub_type: Sub-type of the trunk segment
|
||||
:returns: List of segment UUIDs and dot1qtag (for vxlan) in set pairs
|
||||
"""
|
||||
pair_list = []
|
||||
segments = attrs.get(param)
|
||||
if not attributes.is_attr_set(segments):
|
||||
return pair_list
|
||||
for pair in segments.split(','):
|
||||
segment, sep, dot1qtag = pair.partition(':')
|
||||
if sub_type == c_const.NETWORK_TYPE_VLAN:
|
||||
dot1qtag = ''
|
||||
if uuidutils.is_uuid_like(segment):
|
||||
binding = n1kv_db_v2.get_network_binding(context.session,
|
||||
segment)
|
||||
if binding.network_type == c_const.NETWORK_TYPE_TRUNK:
|
||||
msg = _("Cannot add a trunk segment '%s' as a member of "
|
||||
"another trunk segment") % segment
|
||||
raise q_exc.InvalidInput(error_message=msg)
|
||||
elif binding.network_type == c_const.NETWORK_TYPE_VLAN:
|
||||
if sub_type == c_const.NETWORK_TYPE_VXLAN:
|
||||
msg = _("Cannot add vlan segment '%s' as a member of "
|
||||
"a vxlan trunk segment") % segment
|
||||
raise q_exc.InvalidInput(error_message=msg)
|
||||
if not physical_network:
|
||||
physical_network = binding.physical_network
|
||||
elif physical_network != binding.physical_network:
|
||||
msg = _("Network UUID '%s' belongs to a different "
|
||||
"physical network") % segment
|
||||
raise q_exc.InvalidInput(error_message=msg)
|
||||
elif binding.network_type == c_const.NETWORK_TYPE_VXLAN:
|
||||
if sub_type == c_const.NETWORK_TYPE_VLAN:
|
||||
msg = _("Cannot add vxlan segment '%s' as a member of "
|
||||
"a vlan trunk segment") % segment
|
||||
raise q_exc.InvalidInput(error_message=msg)
|
||||
try:
|
||||
if not utils.is_valid_vlan_tag(int(dot1qtag)):
|
||||
msg = _("Vlan tag '%s' is out of range") % dot1qtag
|
||||
raise q_exc.InvalidInput(error_message=msg)
|
||||
except ValueError:
|
||||
msg = _("Vlan tag '%s' is not an integer "
|
||||
"value") % dot1qtag
|
||||
raise q_exc.InvalidInput(error_message=msg)
|
||||
pair_list.append((segment, dot1qtag))
|
||||
else:
|
||||
LOG.debug(_('%s is not a valid uuid'), segment)
|
||||
msg = _("'%s' is not a valid UUID") % segment
|
||||
raise q_exc.InvalidInput(error_message=msg)
|
||||
return pair_list
|
||||
|
||||
def _extend_network_dict_member_segments(self, context, network):
|
||||
"""Add the extended parameter member segments to the network."""
|
||||
members = []
|
||||
binding = n1kv_db_v2.get_network_binding(context.session,
|
||||
network['id'])
|
||||
if binding.network_type == c_const.NETWORK_TYPE_TRUNK:
|
||||
members = n1kv_db_v2.get_trunk_members(context.session,
|
||||
network['id'])
|
||||
elif binding.network_type == c_const.NETWORK_TYPE_MULTI_SEGMENT:
|
||||
members = n1kv_db_v2.get_multi_segment_members(context.session,
|
||||
network['id'])
|
||||
network[n1kv_profile.MEMBER_SEGMENTS] = members
|
||||
|
||||
def _extend_network_dict_profile(self, context, network):
|
||||
"""Add the extended parameter network profile to the network."""
|
||||
binding = n1kv_db_v2.get_network_binding(context.session,
|
||||
@ -435,13 +722,15 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
n1kvclient = n1kv_client.Client()
|
||||
n1kvclient.delete_network_segment_pool(profile['name'])
|
||||
|
||||
def _send_create_network_request(self, context, network):
|
||||
def _send_create_network_request(self, context, network, segment_pairs):
|
||||
"""
|
||||
Send create network request to VSM.
|
||||
|
||||
Create a bridge domain for network of type VXLAN.
|
||||
:param context: neutron api request context
|
||||
:param network: network dictionary
|
||||
:param segment_pairs: List of segments in UUID pairs
|
||||
that need to be bridged
|
||||
"""
|
||||
LOG.debug(_('_send_create_network_request: %s'), network['id'])
|
||||
profile = self.get_network_profile(context,
|
||||
@ -449,36 +738,110 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
n1kvclient = n1kv_client.Client()
|
||||
if network[providernet.NETWORK_TYPE] == c_const.NETWORK_TYPE_VXLAN:
|
||||
n1kvclient.create_bridge_domain(network)
|
||||
if network[providernet.NETWORK_TYPE] == c_const.NETWORK_TYPE_TRUNK:
|
||||
self._populate_member_segments(context, network, segment_pairs,
|
||||
n1kv_profile.SEGMENT_ADD)
|
||||
network['del_segment_list'] = []
|
||||
if profile['sub_type'] == c_const.NETWORK_TYPE_VXLAN:
|
||||
encap_dict = {'name': (network['name'] +
|
||||
c_const.ENCAPSULATION_PROFILE_SUFFIX),
|
||||
'add_segment_list': (
|
||||
self._get_encap_segments(context,
|
||||
segment_pairs)),
|
||||
'del_segment_list': []}
|
||||
n1kvclient.create_encapsulation_profile(encap_dict)
|
||||
n1kvclient.create_network_segment(network, profile)
|
||||
|
||||
def _send_update_network_request(self, db_session, network):
|
||||
def _send_update_network_request(self, context, network, add_segments,
|
||||
del_segments):
|
||||
"""
|
||||
Send update network request to VSM.
|
||||
|
||||
:param context: neutron api request context
|
||||
:param network: network dictionary
|
||||
:param add_segments: List of segments bindings
|
||||
that need to be deleted
|
||||
:param del_segments: List of segments bindings
|
||||
that need to be deleted
|
||||
"""
|
||||
LOG.debug(_('_send_update_network_request: %s'), network['id'])
|
||||
db_session = context.session
|
||||
profile = n1kv_db_v2.get_network_profile(
|
||||
db_session, network[n1kv_profile.PROFILE_ID])
|
||||
n1kvclient = n1kv_client.Client()
|
||||
body = {'name': network['name'],
|
||||
'id': network['id'],
|
||||
'networkDefinition': profile['name'],
|
||||
'vlan': network[providernet.SEGMENTATION_ID]}
|
||||
n1kvclient = n1kv_client.Client()
|
||||
'vlan': network[providernet.SEGMENTATION_ID],
|
||||
'mode': 'access',
|
||||
'segmentType': profile['segment_type'],
|
||||
'addSegments': [],
|
||||
'delSegments': []}
|
||||
if network[providernet.NETWORK_TYPE] == c_const.NETWORK_TYPE_TRUNK:
|
||||
self._populate_member_segments(context, network, add_segments,
|
||||
n1kv_profile.SEGMENT_ADD)
|
||||
self._populate_member_segments(context, network, del_segments,
|
||||
n1kv_profile.SEGMENT_DEL)
|
||||
body['mode'] = c_const.NETWORK_TYPE_TRUNK
|
||||
body['segmentType'] = profile['sub_type']
|
||||
body['addSegments'] = network['add_segment_list']
|
||||
body['delSegments'] = network['del_segment_list']
|
||||
LOG.debug(_('add_segments=%s'), body['addSegments'])
|
||||
LOG.debug(_('del_segments=%s'), body['delSegments'])
|
||||
if profile['sub_type'] == c_const.NETWORK_TYPE_VXLAN:
|
||||
encap_profile = (network['name'] +
|
||||
c_const.ENCAPSULATION_PROFILE_SUFFIX)
|
||||
encap_dict = {'name': encap_profile,
|
||||
'addMappings': (
|
||||
self._get_encap_segments(context,
|
||||
add_segments)),
|
||||
'delMappings': (
|
||||
self._get_encap_segments(context,
|
||||
del_segments))}
|
||||
n1kvclient.update_encapsulation_profile(context, encap_profile,
|
||||
encap_dict)
|
||||
n1kvclient.update_network_segment(network['name'], body)
|
||||
|
||||
def _send_delete_network_request(self, network):
|
||||
def _send_delete_network_request(self, context, network):
|
||||
"""
|
||||
Send delete network request to VSM.
|
||||
|
||||
Delete bridge domain if network is of type VXLAN.
|
||||
Delete encapsulation profile if network is of type VXLAN Trunk.
|
||||
:param context: neutron api request context
|
||||
:param network: network dictionary
|
||||
"""
|
||||
LOG.debug(_('_send_delete_network_request: %s'), network['id'])
|
||||
n1kvclient = n1kv_client.Client()
|
||||
session = context.session
|
||||
if network[providernet.NETWORK_TYPE] == c_const.NETWORK_TYPE_VXLAN:
|
||||
name = network['name'] + '_bd'
|
||||
name = network['name'] + c_const.BRIDGE_DOMAIN_SUFFIX
|
||||
n1kvclient.delete_bridge_domain(name)
|
||||
elif network[providernet.NETWORK_TYPE] == c_const.NETWORK_TYPE_TRUNK:
|
||||
profile = self.get_network_profile(
|
||||
context, network[n1kv_profile.PROFILE_ID])
|
||||
if profile['sub_type'] == c_const.NETWORK_TYPE_VXLAN:
|
||||
profile_name = (network['name'] +
|
||||
c_const.ENCAPSULATION_PROFILE_SUFFIX)
|
||||
n1kvclient.delete_encapsulation_profile(profile_name)
|
||||
elif (network[providernet.NETWORK_TYPE] ==
|
||||
c_const.NETWORK_TYPE_MULTI_SEGMENT):
|
||||
encap_dict = n1kv_db_v2.get_multi_segment_encap_dict(session,
|
||||
network['id'])
|
||||
for profile in encap_dict:
|
||||
profile_dict = {'name': profile,
|
||||
'addSegments': [],
|
||||
'delSegments': []}
|
||||
for segment_pair in encap_dict[profile]:
|
||||
mapping_dict = {}
|
||||
(segment1, segment2) = segment_pair
|
||||
self._extend_mapping_dict(context,
|
||||
mapping_dict, segment1)
|
||||
self._extend_mapping_dict(context,
|
||||
mapping_dict, segment2)
|
||||
profile_dict['delSegments'].append(mapping_dict)
|
||||
n1kvclient.update_encapsulation_profile(context, profile,
|
||||
profile_dict)
|
||||
n1kvclient.delete_network_segment(network['name'])
|
||||
|
||||
def _send_create_subnet_request(self, context, subnet):
|
||||
@ -616,6 +979,7 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
network['network'])
|
||||
self._add_dummy_profile_only_if_testing(network)
|
||||
profile_id = self._process_network_profile(context, network['network'])
|
||||
segment_pairs = None
|
||||
LOG.debug(_('create network: profile_id=%s'), profile_id)
|
||||
session = context.session
|
||||
with session.begin(subtransactions=True):
|
||||
@ -632,6 +996,22 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
'net_type': network_type,
|
||||
'seg_id': segmentation_id,
|
||||
'multicast_ip': multicast_ip})
|
||||
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:
|
||||
@ -655,13 +1035,19 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
physical_network,
|
||||
segmentation_id,
|
||||
multicast_ip,
|
||||
profile_id)
|
||||
profile_id,
|
||||
segment_pairs)
|
||||
self._process_l3_create(context, net, network['network'])
|
||||
self._extend_network_dict_provider(context, net)
|
||||
self._extend_network_dict_profile(context, net)
|
||||
|
||||
try:
|
||||
self._send_create_network_request(context, net)
|
||||
if network_type == c_const.NETWORK_TYPE_MULTI_SEGMENT:
|
||||
self._send_add_multi_segment_request(context, net['id'],
|
||||
segment_pairs)
|
||||
else:
|
||||
self._send_create_network_request(context, net, segment_pairs)
|
||||
# note - exception will rollback entire transaction
|
||||
except(cisco_exceptions.VSMError,
|
||||
cisco_exceptions.VSMConnectionFailed):
|
||||
super(N1kvNeutronPluginV2, self).delete_network(context, net['id'])
|
||||
@ -679,15 +1065,52 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
:returns: updated network object
|
||||
"""
|
||||
self._check_provider_update(context, network['network'])
|
||||
add_segments = []
|
||||
del_segments = []
|
||||
|
||||
session = context.session
|
||||
with session.begin(subtransactions=True):
|
||||
net = super(N1kvNeutronPluginV2, self).update_network(context, id,
|
||||
network)
|
||||
self._process_l3_update(context, net, network['network'])
|
||||
binding = n1kv_db_v2.get_network_binding(session, id)
|
||||
if binding.network_type == c_const.NETWORK_TYPE_MULTI_SEGMENT:
|
||||
add_segments = (
|
||||
self._parse_multi_segments(context, network['network'],
|
||||
n1kv_profile.SEGMENT_ADD))
|
||||
n1kv_db_v2.add_multi_segment_binding(session,
|
||||
net['id'], add_segments)
|
||||
del_segments = (
|
||||
self._parse_multi_segments(context, network['network'],
|
||||
n1kv_profile.SEGMENT_DEL))
|
||||
self._send_add_multi_segment_request(context, net['id'],
|
||||
add_segments)
|
||||
self._send_del_multi_segment_request(context, net['id'],
|
||||
del_segments)
|
||||
n1kv_db_v2.del_multi_segment_binding(session,
|
||||
net['id'], del_segments)
|
||||
elif binding.network_type == c_const.NETWORK_TYPE_TRUNK:
|
||||
network_profile = self.get_network_profile(context,
|
||||
binding.profile_id)
|
||||
add_segments = (
|
||||
self._parse_trunk_segments(context, network['network'],
|
||||
n1kv_profile.SEGMENT_ADD,
|
||||
binding.physical_network,
|
||||
network_profile['sub_type']))
|
||||
n1kv_db_v2.add_trunk_segment_binding(session,
|
||||
net['id'], add_segments)
|
||||
del_segments = (
|
||||
self._parse_trunk_segments(context, network['network'],
|
||||
n1kv_profile.SEGMENT_DEL,
|
||||
binding.physical_network,
|
||||
network_profile['sub_type']))
|
||||
n1kv_db_v2.del_trunk_segment_binding(session,
|
||||
net['id'], del_segments)
|
||||
self._extend_network_dict_provider(context, net)
|
||||
self._extend_network_dict_profile(context, net)
|
||||
self._send_update_network_request(context.session, net)
|
||||
if binding.network_type not in [c_const.NETWORK_TYPE_MULTI_SEGMENT]:
|
||||
self._send_update_network_request(context, net, add_segments,
|
||||
del_segments)
|
||||
LOG.debug(_("Updated network: %s"), net['id'])
|
||||
return net
|
||||
|
||||
@ -702,6 +1125,20 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
with session.begin(subtransactions=True):
|
||||
binding = n1kv_db_v2.get_network_binding(session, id)
|
||||
network = self.get_network(context, id)
|
||||
if n1kv_db_v2.is_trunk_member(session, id):
|
||||
msg = _("Cannot delete a network "
|
||||
"that is a member of a trunk segment")
|
||||
raise q_exc.InvalidInput(error_message=msg)
|
||||
if n1kv_db_v2.is_multi_segment_member(session, id):
|
||||
msg = _("Cannot delete a network "
|
||||
"that is a member of a multi-segment network")
|
||||
raise q_exc.InvalidInput(error_message=msg)
|
||||
if self.agent_vsm:
|
||||
try:
|
||||
self._send_delete_network_request(context, network)
|
||||
except(cisco_exceptions.VSMError,
|
||||
cisco_exceptions.VSMConnectionFailed):
|
||||
LOG.debug(_('Delete failed in VSM'))
|
||||
super(N1kvNeutronPluginV2, self).delete_network(context, id)
|
||||
if binding.network_type == c_const.NETWORK_TYPE_VXLAN:
|
||||
n1kv_db_v2.release_vxlan(session, binding.segmentation_id,
|
||||
@ -712,8 +1149,6 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
self.network_vlan_ranges)
|
||||
# the network_binding record is deleted via cascade from
|
||||
# the network record, so explicit removal is not necessary
|
||||
if self.agent_vsm:
|
||||
self._send_delete_network_request(network)
|
||||
LOG.debug(_("Deleted network: %s"), id)
|
||||
|
||||
def get_network(self, context, id, fields=None):
|
||||
@ -728,6 +1163,7 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
net = super(N1kvNeutronPluginV2, self).get_network(context, id, None)
|
||||
self._extend_network_dict_provider(context, net)
|
||||
self._extend_network_dict_profile(context, net)
|
||||
self._extend_network_dict_member_segments(context, net)
|
||||
return self._fields(net, fields)
|
||||
|
||||
def get_networks(self, context, filters=None, fields=None):
|
||||
@ -969,17 +1405,18 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
_network_profile = super(
|
||||
N1kvNeutronPluginV2, self).create_network_profile(context,
|
||||
network_profile)
|
||||
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),
|
||||
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)))
|
||||
else:
|
||||
self.vxlan_id_ranges = [(int(seg_min), int(seg_max))]
|
||||
n1kv_db_v2.sync_vxlan_allocations(context.session,
|
||||
self.vxlan_id_ranges)
|
||||
try:
|
||||
@ -1018,8 +1455,7 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
n1kv_db_v2.delete_vlan_allocations(context.session,
|
||||
self.network_vlan_ranges)
|
||||
elif _network_profile['segment_type'] == c_const.NETWORK_TYPE_VXLAN:
|
||||
self.delete_vxlan_ranges = []
|
||||
self.delete_vxlan_ranges.append((int(seg_min), int(seg_max)))
|
||||
self.delete_vxlan_ranges = [(int(seg_min), int(seg_max))]
|
||||
n1kv_db_v2.delete_vxlan_allocations(context.session,
|
||||
self.delete_vxlan_ranges)
|
||||
self._send_delete_network_profile_request(_network_profile)
|
||||
|
@ -16,6 +16,7 @@
|
||||
#
|
||||
# @author: Juergen Brendel, Cisco Systems Inc.
|
||||
# @author: Abhishek Raut, Cisco Systems Inc.
|
||||
# @author: Rudrajit Tapadar, Cisco Systems Inc.
|
||||
|
||||
from sqlalchemy.orm import exc as s_exc
|
||||
from testtools import matchers
|
||||
@ -48,6 +49,8 @@ SEGMENT_RANGE_MIN_OVERLAP = '210-230'
|
||||
SEGMENT_RANGE_MAX_OVERLAP = '190-209'
|
||||
SEGMENT_RANGE_OVERLAP = '190-230'
|
||||
TEST_NETWORK_ID = 'abcdefghijklmnopqrstuvwxyz'
|
||||
TEST_NETWORK_ID2 = 'abcdefghijklmnopqrstuvwxy2'
|
||||
TEST_NETWORK_ID3 = 'abcdefghijklmnopqrstuvwxy3'
|
||||
TEST_NETWORK_PROFILE = {'name': 'test_profile',
|
||||
'segment_type': 'vlan',
|
||||
'physical_network': 'physnet1',
|
||||
@ -62,6 +65,14 @@ TEST_NETWORK_PROFILE_VXLAN = {'name': 'test_profile',
|
||||
'multicast_ip_range': '239.0.0.70-239.0.0.80'}
|
||||
TEST_POLICY_PROFILE = {'id': '4a417990-76fb-11e2-bcfd-0800200c9a66',
|
||||
'name': 'test_policy_profile'}
|
||||
TEST_NETWORK_PROFILE_MULTI_SEGMENT = {'name': 'test_profile',
|
||||
'segment_type': 'multi-segment'}
|
||||
TEST_NETWORK_PROFILE_VLAN_TRUNK = {'name': 'test_profile',
|
||||
'segment_type': 'trunk',
|
||||
'sub_type': 'vlan'}
|
||||
TEST_NETWORK_PROFILE_VXLAN_TRUNK = {'name': 'test_profile',
|
||||
'segment_type': 'trunk',
|
||||
'sub_type': 'vxlan'}
|
||||
|
||||
|
||||
def _create_test_network_profile_if_not_there(session,
|
||||
@ -398,7 +409,7 @@ class NetworkBindingsTest(test_plugin.NeutronDbPluginV2TestCase):
|
||||
p = _create_test_network_profile_if_not_there(self.session)
|
||||
n1kv_db_v2.add_network_binding(
|
||||
self.session, TEST_NETWORK_ID, 'vlan',
|
||||
PHYS_NET, 1234, '0.0.0.0', p.id)
|
||||
PHYS_NET, 1234, '0.0.0.0', p.id, None)
|
||||
binding = n1kv_db_v2.get_network_binding(
|
||||
self.session, TEST_NETWORK_ID)
|
||||
self.assertIsNotNone(binding)
|
||||
@ -407,6 +418,224 @@ class NetworkBindingsTest(test_plugin.NeutronDbPluginV2TestCase):
|
||||
self.assertEqual(binding.physical_network, PHYS_NET)
|
||||
self.assertEqual(binding.segmentation_id, 1234)
|
||||
|
||||
def test_create_multi_segment_network(self):
|
||||
with self.network() as network:
|
||||
TEST_NETWORK_ID = network['network']['id']
|
||||
|
||||
self.assertRaises(c_exc.NetworkBindingNotFound,
|
||||
n1kv_db_v2.get_network_binding,
|
||||
self.session,
|
||||
TEST_NETWORK_ID)
|
||||
|
||||
p = _create_test_network_profile_if_not_there(
|
||||
self.session,
|
||||
TEST_NETWORK_PROFILE_MULTI_SEGMENT)
|
||||
n1kv_db_v2.add_network_binding(
|
||||
self.session, TEST_NETWORK_ID, 'multi-segment',
|
||||
None, 0, '0.0.0.0', p.id, None)
|
||||
binding = n1kv_db_v2.get_network_binding(
|
||||
self.session, TEST_NETWORK_ID)
|
||||
self.assertIsNotNone(binding)
|
||||
self.assertEqual(binding.network_id, TEST_NETWORK_ID)
|
||||
self.assertEqual(binding.network_type, 'multi-segment')
|
||||
self.assertIsNone(binding.physical_network)
|
||||
self.assertEqual(binding.segmentation_id, 0)
|
||||
|
||||
def test_add_multi_segment_binding(self):
|
||||
with self.network() as network:
|
||||
TEST_NETWORK_ID = network['network']['id']
|
||||
|
||||
self.assertRaises(c_exc.NetworkBindingNotFound,
|
||||
n1kv_db_v2.get_network_binding,
|
||||
self.session,
|
||||
TEST_NETWORK_ID)
|
||||
|
||||
p = _create_test_network_profile_if_not_there(
|
||||
self.session,
|
||||
TEST_NETWORK_PROFILE_MULTI_SEGMENT)
|
||||
n1kv_db_v2.add_network_binding(
|
||||
self.session, TEST_NETWORK_ID, 'multi-segment',
|
||||
None, 0, '0.0.0.0', p.id,
|
||||
[(TEST_NETWORK_ID2, TEST_NETWORK_ID3)])
|
||||
binding = n1kv_db_v2.get_network_binding(
|
||||
self.session, TEST_NETWORK_ID)
|
||||
self.assertIsNotNone(binding)
|
||||
self.assertEqual(binding.network_id, TEST_NETWORK_ID)
|
||||
self.assertEqual(binding.network_type, 'multi-segment')
|
||||
self.assertIsNone(binding.physical_network)
|
||||
self.assertEqual(binding.segmentation_id, 0)
|
||||
ms_binding = (n1kv_db_v2.get_multi_segment_network_binding(
|
||||
self.session, TEST_NETWORK_ID,
|
||||
(TEST_NETWORK_ID2, TEST_NETWORK_ID3)))
|
||||
self.assertIsNotNone(ms_binding)
|
||||
self.assertEqual(ms_binding.multi_segment_id, TEST_NETWORK_ID)
|
||||
self.assertEqual(ms_binding.segment1_id, TEST_NETWORK_ID2)
|
||||
self.assertEqual(ms_binding.segment2_id, TEST_NETWORK_ID3)
|
||||
ms_members = (n1kv_db_v2.get_multi_segment_members(
|
||||
self.session, TEST_NETWORK_ID))
|
||||
self.assertEqual(ms_members,
|
||||
[(TEST_NETWORK_ID2, TEST_NETWORK_ID3)])
|
||||
self.assertTrue(n1kv_db_v2.is_multi_segment_member(
|
||||
self.session, TEST_NETWORK_ID2))
|
||||
self.assertTrue(n1kv_db_v2.is_multi_segment_member(
|
||||
self.session, TEST_NETWORK_ID3))
|
||||
n1kv_db_v2.del_multi_segment_binding(
|
||||
self.session, TEST_NETWORK_ID,
|
||||
[(TEST_NETWORK_ID2, TEST_NETWORK_ID3)])
|
||||
ms_members = (n1kv_db_v2.get_multi_segment_members(
|
||||
self.session, TEST_NETWORK_ID))
|
||||
self.assertEqual(ms_members, [])
|
||||
|
||||
def test_create_vlan_trunk_network(self):
|
||||
with self.network() as network:
|
||||
TEST_NETWORK_ID = network['network']['id']
|
||||
|
||||
self.assertRaises(c_exc.NetworkBindingNotFound,
|
||||
n1kv_db_v2.get_network_binding,
|
||||
self.session,
|
||||
TEST_NETWORK_ID)
|
||||
|
||||
p = _create_test_network_profile_if_not_there(
|
||||
self.session,
|
||||
TEST_NETWORK_PROFILE_VLAN_TRUNK)
|
||||
n1kv_db_v2.add_network_binding(
|
||||
self.session, TEST_NETWORK_ID, 'trunk',
|
||||
None, 0, '0.0.0.0', p.id, None)
|
||||
binding = n1kv_db_v2.get_network_binding(
|
||||
self.session, TEST_NETWORK_ID)
|
||||
self.assertIsNotNone(binding)
|
||||
self.assertEqual(binding.network_id, TEST_NETWORK_ID)
|
||||
self.assertEqual(binding.network_type, 'trunk')
|
||||
self.assertIsNone(binding.physical_network)
|
||||
self.assertEqual(binding.segmentation_id, 0)
|
||||
|
||||
def test_create_vxlan_trunk_network(self):
|
||||
with self.network() as network:
|
||||
TEST_NETWORK_ID = network['network']['id']
|
||||
|
||||
self.assertRaises(c_exc.NetworkBindingNotFound,
|
||||
n1kv_db_v2.get_network_binding,
|
||||
self.session,
|
||||
TEST_NETWORK_ID)
|
||||
|
||||
p = _create_test_network_profile_if_not_there(
|
||||
self.session,
|
||||
TEST_NETWORK_PROFILE_VXLAN_TRUNK)
|
||||
n1kv_db_v2.add_network_binding(
|
||||
self.session, TEST_NETWORK_ID, 'trunk',
|
||||
None, 0, '0.0.0.0', p.id, None)
|
||||
binding = n1kv_db_v2.get_network_binding(
|
||||
self.session, TEST_NETWORK_ID)
|
||||
self.assertIsNotNone(binding)
|
||||
self.assertEqual(binding.network_id, TEST_NETWORK_ID)
|
||||
self.assertEqual(binding.network_type, 'trunk')
|
||||
self.assertIsNone(binding.physical_network)
|
||||
self.assertEqual(binding.segmentation_id, 0)
|
||||
|
||||
def test_add_vlan_trunk_binding(self):
|
||||
with self.network() as network1:
|
||||
with self.network() as network2:
|
||||
TEST_NETWORK_ID = network1['network']['id']
|
||||
|
||||
self.assertRaises(c_exc.NetworkBindingNotFound,
|
||||
n1kv_db_v2.get_network_binding,
|
||||
self.session,
|
||||
TEST_NETWORK_ID)
|
||||
TEST_NETWORK_ID2 = network2['network']['id']
|
||||
self.assertRaises(c_exc.NetworkBindingNotFound,
|
||||
n1kv_db_v2.get_network_binding,
|
||||
self.session,
|
||||
TEST_NETWORK_ID2)
|
||||
p_v = _create_test_network_profile_if_not_there(self.session)
|
||||
n1kv_db_v2.add_network_binding(
|
||||
self.session, TEST_NETWORK_ID2, 'vlan',
|
||||
PHYS_NET, 1234, '0.0.0.0', p_v.id, None)
|
||||
p = _create_test_network_profile_if_not_there(
|
||||
self.session,
|
||||
TEST_NETWORK_PROFILE_VLAN_TRUNK)
|
||||
n1kv_db_v2.add_network_binding(
|
||||
self.session, TEST_NETWORK_ID, 'trunk',
|
||||
None, 0, '0.0.0.0', p.id, [(TEST_NETWORK_ID2, 0)])
|
||||
binding = n1kv_db_v2.get_network_binding(
|
||||
self.session, TEST_NETWORK_ID)
|
||||
self.assertIsNotNone(binding)
|
||||
self.assertEqual(binding.network_id, TEST_NETWORK_ID)
|
||||
self.assertEqual(binding.network_type, 'trunk')
|
||||
self.assertEqual(binding.physical_network, PHYS_NET)
|
||||
self.assertEqual(binding.segmentation_id, 0)
|
||||
t_binding = (n1kv_db_v2.get_trunk_network_binding(
|
||||
self.session, TEST_NETWORK_ID,
|
||||
(TEST_NETWORK_ID2, 0)))
|
||||
self.assertIsNotNone(t_binding)
|
||||
self.assertEqual(t_binding.trunk_segment_id, TEST_NETWORK_ID)
|
||||
self.assertEqual(t_binding.segment_id, TEST_NETWORK_ID2)
|
||||
self.assertEqual(t_binding.dot1qtag, '0')
|
||||
t_members = (n1kv_db_v2.get_trunk_members(
|
||||
self.session, TEST_NETWORK_ID))
|
||||
self.assertEqual(t_members,
|
||||
[(TEST_NETWORK_ID2, '0')])
|
||||
self.assertTrue(n1kv_db_v2.is_trunk_member(
|
||||
self.session, TEST_NETWORK_ID2))
|
||||
n1kv_db_v2.del_trunk_segment_binding(
|
||||
self.session, TEST_NETWORK_ID,
|
||||
[(TEST_NETWORK_ID2, '0')])
|
||||
t_members = (n1kv_db_v2.get_multi_segment_members(
|
||||
self.session, TEST_NETWORK_ID))
|
||||
self.assertEqual(t_members, [])
|
||||
|
||||
def test_add_vxlan_trunk_binding(self):
|
||||
with self.network() as network1:
|
||||
with self.network() as network2:
|
||||
TEST_NETWORK_ID = network1['network']['id']
|
||||
|
||||
self.assertRaises(c_exc.NetworkBindingNotFound,
|
||||
n1kv_db_v2.get_network_binding,
|
||||
self.session,
|
||||
TEST_NETWORK_ID)
|
||||
TEST_NETWORK_ID2 = network2['network']['id']
|
||||
self.assertRaises(c_exc.NetworkBindingNotFound,
|
||||
n1kv_db_v2.get_network_binding,
|
||||
self.session,
|
||||
TEST_NETWORK_ID2)
|
||||
p_v = _create_test_network_profile_if_not_there(
|
||||
self.session, TEST_NETWORK_PROFILE_VXLAN_TRUNK)
|
||||
n1kv_db_v2.add_network_binding(
|
||||
self.session, TEST_NETWORK_ID2, 'vxlan',
|
||||
None, 5100, '224.10.10.10', p_v.id, None)
|
||||
p = _create_test_network_profile_if_not_there(
|
||||
self.session,
|
||||
TEST_NETWORK_PROFILE_VXLAN_TRUNK)
|
||||
n1kv_db_v2.add_network_binding(
|
||||
self.session, TEST_NETWORK_ID, 'trunk',
|
||||
None, 0, '0.0.0.0', p.id,
|
||||
[(TEST_NETWORK_ID2, 5)])
|
||||
binding = n1kv_db_v2.get_network_binding(
|
||||
self.session, TEST_NETWORK_ID)
|
||||
self.assertIsNotNone(binding)
|
||||
self.assertEqual(binding.network_id, TEST_NETWORK_ID)
|
||||
self.assertEqual(binding.network_type, 'trunk')
|
||||
self.assertIsNone(binding.physical_network)
|
||||
self.assertEqual(binding.segmentation_id, 0)
|
||||
t_binding = (n1kv_db_v2.get_trunk_network_binding(
|
||||
self.session, TEST_NETWORK_ID,
|
||||
(TEST_NETWORK_ID2, '5')))
|
||||
self.assertIsNotNone(t_binding)
|
||||
self.assertEqual(t_binding.trunk_segment_id, TEST_NETWORK_ID)
|
||||
self.assertEqual(t_binding.segment_id, TEST_NETWORK_ID2)
|
||||
self.assertEqual(t_binding.dot1qtag, '5')
|
||||
t_members = (n1kv_db_v2.get_trunk_members(
|
||||
self.session, TEST_NETWORK_ID))
|
||||
self.assertEqual(t_members,
|
||||
[(TEST_NETWORK_ID2, '5')])
|
||||
self.assertTrue(n1kv_db_v2.is_trunk_member(
|
||||
self.session, TEST_NETWORK_ID2))
|
||||
n1kv_db_v2.del_trunk_segment_binding(
|
||||
self.session, TEST_NETWORK_ID,
|
||||
[(TEST_NETWORK_ID2, '5')])
|
||||
t_members = (n1kv_db_v2.get_multi_segment_members(
|
||||
self.session, TEST_NETWORK_ID))
|
||||
self.assertEqual(t_members, [])
|
||||
|
||||
|
||||
class NetworkProfileTests(base.BaseTestCase,
|
||||
n1kv_db_v2.NetworkProfile_db_mixin):
|
||||
@ -436,6 +665,63 @@ class NetworkProfileTests(base.BaseTestCase,
|
||||
db_profile.multicast_ip_range)
|
||||
n1kv_db_v2.delete_network_profile(self.session, _db_profile.id)
|
||||
|
||||
def test_create_multi_segment_network_profile(self):
|
||||
_db_profile = (n1kv_db_v2.create_network_profile(
|
||||
self.session, TEST_NETWORK_PROFILE_MULTI_SEGMENT))
|
||||
self.assertIsNotNone(_db_profile)
|
||||
db_profile = (self.session.query(n1kv_models_v2.NetworkProfile).
|
||||
filter_by(
|
||||
name=TEST_NETWORK_PROFILE_MULTI_SEGMENT['name']).
|
||||
one())
|
||||
self.assertIsNotNone(db_profile)
|
||||
self.assertEqual(_db_profile.id, db_profile.id)
|
||||
self.assertEqual(_db_profile.name, db_profile.name)
|
||||
self.assertEqual(_db_profile.segment_type, db_profile.segment_type)
|
||||
self.assertEqual(_db_profile.segment_range, db_profile.segment_range)
|
||||
self.assertEqual(_db_profile.multicast_ip_index,
|
||||
db_profile.multicast_ip_index)
|
||||
self.assertEqual(_db_profile.multicast_ip_range,
|
||||
db_profile.multicast_ip_range)
|
||||
n1kv_db_v2.delete_network_profile(self.session, _db_profile.id)
|
||||
|
||||
def test_create_vlan_trunk_network_profile(self):
|
||||
_db_profile = (n1kv_db_v2.create_network_profile(
|
||||
self.session, TEST_NETWORK_PROFILE_VLAN_TRUNK))
|
||||
self.assertIsNotNone(_db_profile)
|
||||
db_profile = (self.session.query(n1kv_models_v2.NetworkProfile).
|
||||
filter_by(name=TEST_NETWORK_PROFILE_VLAN_TRUNK['name']).
|
||||
one())
|
||||
self.assertIsNotNone(db_profile)
|
||||
self.assertEqual(_db_profile.id, db_profile.id)
|
||||
self.assertEqual(_db_profile.name, db_profile.name)
|
||||
self.assertEqual(_db_profile.segment_type, db_profile.segment_type)
|
||||
self.assertEqual(_db_profile.segment_range, db_profile.segment_range)
|
||||
self.assertEqual(_db_profile.multicast_ip_index,
|
||||
db_profile.multicast_ip_index)
|
||||
self.assertEqual(_db_profile.multicast_ip_range,
|
||||
db_profile.multicast_ip_range)
|
||||
self.assertEqual(_db_profile.sub_type, db_profile.sub_type)
|
||||
n1kv_db_v2.delete_network_profile(self.session, _db_profile.id)
|
||||
|
||||
def test_create_vxlan_trunk_network_profile(self):
|
||||
_db_profile = (n1kv_db_v2.create_network_profile(
|
||||
self.session, TEST_NETWORK_PROFILE_VXLAN_TRUNK))
|
||||
self.assertIsNotNone(_db_profile)
|
||||
db_profile = (self.session.query(n1kv_models_v2.NetworkProfile).
|
||||
filter_by(name=TEST_NETWORK_PROFILE_VXLAN_TRUNK['name']).
|
||||
one())
|
||||
self.assertIsNotNone(db_profile)
|
||||
self.assertEqual(_db_profile.id, db_profile.id)
|
||||
self.assertEqual(_db_profile.name, db_profile.name)
|
||||
self.assertEqual(_db_profile.segment_type, db_profile.segment_type)
|
||||
self.assertEqual(_db_profile.segment_range, db_profile.segment_range)
|
||||
self.assertEqual(_db_profile.multicast_ip_index,
|
||||
db_profile.multicast_ip_index)
|
||||
self.assertEqual(_db_profile.multicast_ip_range,
|
||||
db_profile.multicast_ip_range)
|
||||
self.assertEqual(_db_profile.sub_type, db_profile.sub_type)
|
||||
n1kv_db_v2.delete_network_profile(self.session, _db_profile.id)
|
||||
|
||||
def test_create_network_profile_overlap(self):
|
||||
_db_profile = n1kv_db_v2.create_network_profile(self.session,
|
||||
TEST_NETWORK_PROFILE_2)
|
||||
|
Loading…
Reference in New Issue
Block a user