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_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
|
||||||
|
@ -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.")
|
||||||
|
@ -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):
|
||||||
"""
|
"""
|
||||||
|
@ -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))
|
||||||
|
@ -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,
|
||||||
|
@ -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']:
|
||||||
|
@ -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']:
|
||||||
|
@ -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))
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
Loading…
Reference in New Issue
Block a user