Merge "Add sub-type field to VXLAN network profiles for Cisco N1KV plugin"

This commit is contained in:
Jenkins 2013-09-05 16:13:17 +00:00 committed by Gerrit Code Review
commit b15c0b3c95
9 changed files with 191 additions and 102 deletions

View File

@ -0,0 +1,56 @@
# 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 overlay support
Revision ID: 38fc1f6789f8
Revises: 1efb85914233
Create Date: 2013-08-20 18:31:16.158387
"""
revision = '38fc1f6789f8'
down_revision = '1efb85914233'
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.alter_column('cisco_network_profiles', 'segment_type',
existing_type=sa.Enum('vlan', 'overlay', 'trunk',
'multi-segment'),
existing_nullable=False)
def downgrade(active_plugins=None, options=None):
if not migration.should_run(active_plugins, migration_for_plugins):
return
op.alter_column('cisco_network_profiles', 'segment_type',
existing_type=sa.Enum('vlan', 'vxlan', 'trunk',
'multi-segment'),
existing_nullable=False)

View File

@ -81,12 +81,15 @@ NETWORK_TYPE_TRUNK = 'trunk'
NETWORK_TYPE_MULTI_SEGMENT = 'multi-segment' NETWORK_TYPE_MULTI_SEGMENT = 'multi-segment'
# Values for network sub_type # Values for network sub_type
NETWORK_TYPE_OVERLAY = 'overlay'
NETWORK_SUBTYPE_NATIVE_VXLAN = 'native_vxlan'
NETWORK_SUBTYPE_TRUNK_VLAN = NETWORK_TYPE_VLAN NETWORK_SUBTYPE_TRUNK_VLAN = NETWORK_TYPE_VLAN
NETWORK_SUBTYPE_TRUNK_VXLAN = NETWORK_TYPE_VXLAN NETWORK_SUBTYPE_TRUNK_VXLAN = NETWORK_TYPE_OVERLAY
# Prefix for VM Network name # Prefix for VM Network name
VM_NETWORK_NAME_PREFIX = 'vmn_' VM_NETWORK_NAME_PREFIX = 'vmn_'
DEFAULT_HTTP_TIMEOUT = 15
SET = 'set' SET = 'set'
INSTANCE = 'instance' INSTANCE = 'instance'
PROPERTIES = 'properties' PROPERTIES = 'properties'

View File

@ -289,15 +289,15 @@ def add_network_binding(db_session, network_id, network_type,
: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, VXLAN, :param network_type: string representing type of network (VLAN, OVERLAY,
MULTI_SEGMENT or TRUNK) 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
:param multicast_ip: VXLAN technology needs a multicast IP to be associated :param multicast_ip: Native VXLAN technology needs a multicast IP to be
with every VXLAN ID to deal with broadcast packets. A associated with every VXLAN ID to deal with broadcast
single multicast IP can be shared by multiple VXLAN packets. A single multicast IP can be shared by
IDs. multiple VXLAN 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 :param add_segments: List of segment UUIDs in pairs to be added to either a
@ -516,7 +516,7 @@ def reserve_vxlan(db_session, network_profile):
:param network_profile: network profile object :param network_profile: network profile object
""" """
seg_min, seg_max = get_segment_range(network_profile) seg_min, seg_max = get_segment_range(network_profile)
segment_type = c_const.NETWORK_TYPE_VXLAN segment_type = c_const.NETWORK_TYPE_OVERLAY
physical_network = "" physical_network = ""
with db_session.begin(subtransactions=True): with db_session.begin(subtransactions=True):
@ -531,10 +531,13 @@ def reserve_vxlan(db_session, network_profile):
if alloc: if alloc:
segment_id = alloc.vxlan_id segment_id = alloc.vxlan_id
alloc.allocated = True alloc.allocated = True
return (physical_network, segment_type, if network_profile.sub_type == (c_const.
segment_id, get_multicast_ip(network_profile)) NETWORK_SUBTYPE_NATIVE_VXLAN):
raise c_exc.NoMoreNetworkSegments( return (physical_network, segment_type,
network_profile_name=network_profile.name) segment_id, get_multicast_ip(network_profile))
else:
return (physical_network, segment_type, segment_id, "0.0.0.0")
raise q_exc.NoNetworkAvailable()
def alloc_network(db_session, network_profile_id): def alloc_network(db_session, network_profile_id):
@ -549,7 +552,7 @@ 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)
if network_profile.segment_type == c_const.NETWORK_TYPE_VXLAN: if network_profile.segment_type == c_const.NETWORK_TYPE_OVERLAY:
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") return (None, network_profile.segment_type, 0, "0.0.0.0")
@ -841,7 +844,7 @@ def create_network_profile(db_session, network_profile):
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"] 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_OVERLAY:
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"]
@ -1234,10 +1237,10 @@ class NetworkProfile_db_mixin(object):
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_OVERLAY,
c_const.NETWORK_TYPE_TRUNK, c_const.NETWORK_TYPE_TRUNK,
c_const.NETWORK_TYPE_MULTI_SEGMENT]: c_const.NETWORK_TYPE_MULTI_SEGMENT]:
msg = _("segment_type should either be vlan, vxlan, " msg = _("segment_type should either be vlan, overlay, "
"multi-segment or trunk") "multi-segment or trunk")
LOG.exception(msg) LOG.exception(msg)
raise q_exc.InvalidInput(error_message=msg) raise q_exc.InvalidInput(error_message=msg)
@ -1247,22 +1250,26 @@ class NetworkProfile_db_mixin(object):
"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)
if segment_type == c_const.NETWORK_TYPE_TRUNK: if segment_type in [c_const.NETWORK_TYPE_TRUNK,
c_const.NETWORK_TYPE_OVERLAY]:
if "sub_type" not in net_p: if "sub_type" not in net_p:
msg = _("argument sub_type missing " msg = _("argument sub_type missing "
"for trunk 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)
if segment_type in [c_const.NETWORK_TYPE_VLAN, if segment_type in [c_const.NETWORK_TYPE_VLAN,
c_const.NETWORK_TYPE_VXLAN]: c_const.NETWORK_TYPE_OVERLAY]:
if "segment_range" not in net_p: if "segment_range" not in net_p:
msg = _("argument segment_range missing " msg = _("argument segment_range 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)
self._validate_segment_range(net_p) self._validate_segment_range(net_p)
if segment_type != c_const.NETWORK_TYPE_VXLAN: if segment_type == c_const.NETWORK_TYPE_OVERLAY:
net_p["multicast_ip_range"] = "0.0.0.0" if net_p['sub_type'] != c_const.NETWORK_SUBTYPE_NATIVE_VXLAN:
net_p['multicast_ip_range'] = '0.0.0.0'
else:
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):
""" """

View File

@ -96,8 +96,8 @@ class NetworkProfile(model_base.BASEV2, models_v2.HasId):
""" """
Nexus1000V Network Profiles Nexus1000V Network Profiles
segment_type - VLAN, VXLAN, TRUNK, MULTI_SEGMENT segment_type - VLAN, OVERLAY, TRUNK, MULTI_SEGMENT
sub_type - TRUNK_VLAN, TRUNK_VXLAN sub_type - TRUNK_VLAN, TRUNK_VXLAN, native_vxlan, enhanced_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>'
@ -107,7 +107,7 @@ 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_OVERLAY,
cisco_constants.NETWORK_TYPE_TRUNK, cisco_constants.NETWORK_TYPE_TRUNK,
cisco_constants. cisco_constants.
NETWORK_TYPE_MULTI_SEGMENT, NETWORK_TYPE_MULTI_SEGMENT,

View File

@ -31,6 +31,8 @@ RESOURCE_ATTRIBUTE_MAP = {
'is_visible': True}, 'is_visible': True},
'credential_name': {'allow_post': True, 'allow_put': True, 'credential_name': {'allow_post': True, 'allow_put': True,
'is_visible': True, 'default': ''}, 'is_visible': True, 'default': ''},
'tenant_id': {'allow_post': True, 'allow_put': False,
'is_visible': False, 'default': ''},
'type': {'allow_post': True, 'allow_put': True, 'type': {'allow_post': True, 'allow_put': True,
'is_visible': True, 'default': ''}, 'is_visible': True, 'default': ''},
'user_name': {'allow_post': True, 'allow_put': True, 'user_name': {'allow_post': True, 'allow_put': True,

View File

@ -39,6 +39,8 @@ RESOURCE_ATTRIBUTE_MAP = {
'default': attributes.ATTR_NOT_SPECIFIED}, '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': ''},
'sub_type': {'allow_post': True, 'allow_put': True,
'is_visible': True, 'default': ''},
'multicast_ip_range': {'allow_post': True, 'allow_put': True, 'multicast_ip_range': {'allow_post': True, 'allow_put': True,
'is_visible': True, 'default': '0.0.0.0'}, 'is_visible': True, 'default': '0.0.0.0'},
'multicast_ip_index': {'allow_post': False, 'allow_put': False, 'multicast_ip_index': {'allow_post': False, 'allow_put': False,

View File

@ -150,6 +150,7 @@ class Client(object):
self.format = 'json' self.format = 'json'
self.hosts = self._get_vsm_hosts() self.hosts = self._get_vsm_hosts()
self.action_prefix = 'http://%s/api/n1k' % self.hosts[0] self.action_prefix = 'http://%s/api/n1k' % self.hosts[0]
self.timeout = c_const.DEFAULT_HTTP_TIMEOUT
def list_port_profiles(self): def list_port_profiles(self):
""" """
@ -171,15 +172,18 @@ class Client(object):
self.events_path = self.events_path + '?type=' + event_type self.events_path = self.events_path + '?type=' + event_type
return self._get(self.events_path) return self._get(self.events_path)
def create_bridge_domain(self, network): def create_bridge_domain(self, network, overlay_subtype):
""" """
Create a bridge domain on VSM. Create a bridge domain on VSM.
:param network: network dict :param network: network dict
:param overlay_subtype: string representing subtype of overlay network
""" """
body = {'name': network['name'] + c_const.BRIDGE_DOMAIN_SUFFIX, 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], } 'subType': overlay_subtype}
if overlay_subtype == c_const.NETWORK_SUBTYPE_NATIVE_VXLAN:
body['groupIp'] = network[n1kv_profile.MULTICAST_IP]
return self._post(self.bridge_domains_path, return self._post(self.bridge_domains_path,
body=body) body=body)
@ -198,13 +202,12 @@ class Client(object):
:param network: network dict :param network: network dict
:param network_profile: network profile dict :param network_profile: network profile dict
""" """
LOG.debug(_("seg id %s\n"), network_profile['name'])
body = {'name': network['name'], body = {'name': network['name'],
'id': network['id'], 'id': network['id'],
'networkSegmentPool': network_profile['name'], } 'networkSegmentPool': network_profile['name'], }
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_OVERLAY:
body['bridgeDomain'] = (network['name'] + body['bridgeDomain'] = (network['name'] +
c_const.BRIDGE_DOMAIN_SUFFIX) c_const.BRIDGE_DOMAIN_SUFFIX)
if network_profile['segment_type'] == c_const.NETWORK_TYPE_TRUNK: if network_profile['segment_type'] == c_const.NETWORK_TYPE_TRUNK:
@ -427,20 +430,22 @@ class Client(object):
if body: if body:
body = self._serialize(body) body = self._serialize(body)
LOG.debug(_("req: %s"), body) LOG.debug(_("req: %s"), body)
resp, replybody = httplib2.Http().request(action, try:
method, resp, replybody = (httplib2.Http(timeout=self.timeout).
body=body, request(action,
headers=headers) method,
body=body,
headers=headers))
except Exception as e:
raise c_exc.VSMConnectionFailed(reason=e)
LOG.debug(_("status_code %s"), resp.status) LOG.debug(_("status_code %s"), resp.status)
if resp.status == 200: if resp.status == 200:
if 'application/xml' in resp['content-type']: if 'application/xml' in resp['content-type']:
return self._deserialize(replybody, resp.status) return self._deserialize(replybody, resp.status)
elif 'text/plain' in resp['content-type']: elif 'text/plain' in resp['content-type']:
LOG.debug(_("VSM: %s"), replybody) LOG.debug(_("VSM: %s"), replybody)
elif resp.status == 500: else:
raise c_exc.VSMError(reason=replybody) raise c_exc.VSMError(reason=replybody)
elif resp.status == 503:
raise c_exc.VSMConnectionFailed
def _serialize(self, data): def _serialize(self, data):
""" """

View File

@ -159,7 +159,7 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
""" """
n1kv_db_v2.initialize() n1kv_db_v2.initialize()
c_cred.Store.initialize() c_cred.Store.initialize()
self._initialize_network_vlan_ranges() self._initialize_network_ranges()
# If no api_extensions_path is provided set the following # If no api_extensions_path is provided set the following
if not q_conf.CONF.api_extensions_path: if not q_conf.CONF.api_extensions_path:
q_conf.CONF.set_override( q_conf.CONF.set_override(
@ -212,56 +212,69 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
tenant-ids. tenant-ids.
""" """
LOG.debug(_('_populate_policy_profiles')) LOG.debug(_('_populate_policy_profiles'))
n1kvclient = n1kv_client.Client() try:
policy_profiles = n1kvclient.list_port_profiles() n1kvclient = n1kv_client.Client()
LOG.debug(_('_populate_policy_profiles %s'), policy_profiles) policy_profiles = n1kvclient.list_port_profiles()
if policy_profiles: LOG.debug(_('_populate_policy_profiles %s'), policy_profiles)
for profile in policy_profiles['body'][c_const.SET]: if policy_profiles:
if c_const.ID and c_const.NAME in profile: for profile in policy_profiles['body'][c_const.SET]:
profile_id = profile[c_const.PROPERTIES][c_const.ID] if c_const.ID and c_const.NAME in profile:
profile_name = profile[c_const.PROPERTIES][c_const.NAME] profile_id = profile[c_const.PROPERTIES][c_const.ID]
self._add_policy_profile(profile_name, profile_id) profile_name = profile[c_const.
else: PROPERTIES][c_const.NAME]
self._add_policy_profile(profile_name, profile_id)
self._remove_all_fake_policy_profiles()
except (cisco_exceptions.VSMError,
cisco_exceptions.VSMConnectionFailed):
LOG.warning(_('No policy profile populated from VSM')) LOG.warning(_('No policy profile populated from VSM'))
self._remove_all_fake_policy_profiles()
def _poll_policies(self, event_type=None, epoch=None, tenant_id=None): def _poll_policies(self, event_type=None, epoch=None, tenant_id=None):
""" """
Poll for Policy Profiles from Cisco Nexus1000V for any update/delete. Poll for Policy Profiles from Cisco Nexus1000V for any update/delete.
""" """
LOG.debug(_('_poll_policies')) LOG.debug(_('_poll_policies'))
n1kvclient = n1kv_client.Client() try:
policy_profiles = n1kvclient.list_events(event_type, epoch) n1kvclient = n1kv_client.Client()
if policy_profiles: policy_profiles = n1kvclient.list_events(event_type, epoch)
for profile in policy_profiles['body'][c_const.SET]: if policy_profiles:
if c_const.NAME in profile: for profile in policy_profiles['body'][c_const.SET]:
# Extract commands from the events XML. if c_const.NAME in profile:
cmd = profile[c_const.PROPERTIES]['cmd'] # Extract commands from the events XML.
cmds = cmd.split(';') cmd = profile[c_const.PROPERTIES]['cmd']
cmdwords = cmds[1].split() cmds = cmd.split(';')
profile_name = profile[c_const.PROPERTIES][c_const.NAME] cmdwords = cmds[1].split()
# Delete the policy profile from db if it's deleted on VSM profile_name = profile[c_const.
if 'no' in cmdwords[0]: PROPERTIES][c_const.NAME]
p = self._get_policy_profile_by_name(profile_name) # Delete the policy profile from db if deleted on VSM
if p: if 'no' in cmdwords[0]:
self._delete_policy_profile(p['id']) p = self._get_policy_profile_by_name(profile_name)
# Add policy profile to neutron DB idempotently if p:
elif c_const.ID in profile[c_const.PROPERTIES]: self._delete_policy_profile(p['id'])
profile_id = profile[c_const.PROPERTIES][c_const.ID] # Add policy profile to neutron DB idempotently
self._add_policy_profile( elif c_const.ID in profile[c_const.PROPERTIES]:
profile_name, profile_id, tenant_id) profile_id = profile[c_const.
# Replace tenant-id for profile bindings with admin's tenant-id PROPERTIES][c_const.ID]
self._remove_all_fake_policy_profiles() self._add_policy_profile(
profile_name, profile_id, tenant_id)
# Replace tenant-id for profile bindings with admin's tenant-id
self._remove_all_fake_policy_profiles()
except (cisco_exceptions.VSMError,
cisco_exceptions.VSMConnectionFailed):
LOG.warning(_('No policy profile updated from VSM'))
def _initialize_network_vlan_ranges(self): def _initialize_network_ranges(self):
self.network_vlan_ranges = {} self.network_vlan_ranges = {}
self.vxlan_id_ranges = []
network_profiles = n1kv_db_v2._get_network_profiles() network_profiles = n1kv_db_v2._get_network_profiles()
for network_profile in network_profiles: for network_profile in network_profiles:
seg_min, seg_max = self._get_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:
seg_min, seg_max = self._get_segment_range(
network_profile['segment_range'])
self._add_network_vlan_range(network_profile[ self._add_network_vlan_range(network_profile[
'physical_network'], int(seg_min), int(seg_max)) 'physical_network'], int(seg_min), int(seg_max))
elif network_profile['segment_type'] == (c_const.
NETWORK_TYPE_OVERLAY):
self.vxlan_id_ranges.append((int(seg_min), int(seg_max)))
def _add_network_vlan_range(self, physical_network, vlan_min, vlan_max): def _add_network_vlan_range(self, physical_network, vlan_min, vlan_max):
self._add_network(physical_network) self._add_network(physical_network)
@ -276,7 +289,7 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
binding = n1kv_db_v2.get_network_binding(context.session, binding = n1kv_db_v2.get_network_binding(context.session,
network['id']) network['id'])
network[providernet.NETWORK_TYPE] = binding.network_type network[providernet.NETWORK_TYPE] = binding.network_type
if binding.network_type == c_const.NETWORK_TYPE_VXLAN: if binding.network_type == c_const.NETWORK_TYPE_OVERLAY:
network[providernet.PHYSICAL_NETWORK] = None network[providernet.PHYSICAL_NETWORK] = None
network[providernet.SEGMENTATION_ID] = binding.segmentation_id network[providernet.SEGMENTATION_ID] = binding.segmentation_id
network[n1kv_profile.MULTICAST_IP] = binding.multicast_ip network[n1kv_profile.MULTICAST_IP] = binding.multicast_ip
@ -316,9 +329,9 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
msg = _("provider:segmentation_id out of range " msg = _("provider:segmentation_id out of range "
"(1 through 4094)") "(1 through 4094)")
raise q_exc.InvalidInput(error_message=msg) raise q_exc.InvalidInput(error_message=msg)
elif network_type == c_const.NETWORK_TYPE_VXLAN: elif network_type == c_const.NETWORK_TYPE_OVERLAY:
if physical_network_set: if physical_network_set:
msg = _("provider:physical_network specified for VXLAN " msg = _("provider:physical_network specified for Overlay "
"network") "network")
raise q_exc.InvalidInput(error_message=msg) raise q_exc.InvalidInput(error_message=msg)
else: else:
@ -387,8 +400,7 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
def _extend_mapping_dict(self, context, mapping_dict, segment): def _extend_mapping_dict(self, context, mapping_dict, segment):
""" """
Extends a mapping dictionary by populating dot1q tag and Extend a mapping dictionary with dot1q tag and bridge-domain name.
bridge-domain name.
:param context: neutron api request context :param context: neutron api request context
:param mapping_dict: dictionary to populate values :param mapping_dict: dictionary to populate values
@ -536,7 +548,7 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
def _parse_multi_segments(self, context, attrs, param): def _parse_multi_segments(self, context, attrs, param):
""" """
Parse the multi-segment network attributes Parse the multi-segment network attributes.
:param context: neutron api request context :param context: neutron api request context
:param attrs: Attributes of the network :param attrs: Attributes of the network
@ -546,7 +558,7 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
""" """
pair_list = [] pair_list = []
valid_seg_types = [c_const.NETWORK_TYPE_VLAN, valid_seg_types = [c_const.NETWORK_TYPE_VLAN,
c_const.NETWORK_TYPE_VXLAN] c_const.NETWORK_TYPE_OVERLAY]
segments = attrs.get(param) segments = attrs.get(param)
if not attributes.is_attr_set(segments): if not attributes.is_attr_set(segments):
return pair_list return pair_list
@ -574,7 +586,7 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
def _parse_trunk_segments(self, context, attrs, param, physical_network, def _parse_trunk_segments(self, context, attrs, param, physical_network,
sub_type): sub_type):
""" """
Parse the trunk network attributes Parse the trunk network attributes.
:param context: neutron api request context :param context: neutron api request context
:param attrs: Attributes of the network :param attrs: Attributes of the network
@ -600,7 +612,7 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
"another trunk segment") % segment "another trunk segment") % segment
raise q_exc.InvalidInput(error_message=msg) raise q_exc.InvalidInput(error_message=msg)
elif binding.network_type == c_const.NETWORK_TYPE_VLAN: elif binding.network_type == c_const.NETWORK_TYPE_VLAN:
if sub_type == c_const.NETWORK_TYPE_VXLAN: if sub_type == c_const.NETWORK_TYPE_OVERLAY:
msg = _("Cannot add vlan segment '%s' as a member of " msg = _("Cannot add vlan segment '%s' as a member of "
"a vxlan trunk segment") % segment "a vxlan trunk segment") % segment
raise q_exc.InvalidInput(error_message=msg) raise q_exc.InvalidInput(error_message=msg)
@ -610,7 +622,7 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
msg = _("Network UUID '%s' belongs to a different " msg = _("Network UUID '%s' belongs to a different "
"physical network") % segment "physical network") % segment
raise q_exc.InvalidInput(error_message=msg) raise q_exc.InvalidInput(error_message=msg)
elif binding.network_type == c_const.NETWORK_TYPE_VXLAN: elif binding.network_type == c_const.NETWORK_TYPE_OVERLAY:
if sub_type == c_const.NETWORK_TYPE_VLAN: if sub_type == c_const.NETWORK_TYPE_VLAN:
msg = _("Cannot add vxlan segment '%s' as a member of " msg = _("Cannot add vxlan segment '%s' as a member of "
"a vlan trunk segment") % segment "a vlan trunk segment") % segment
@ -726,7 +738,7 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
""" """
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 Overlay.
: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 :param segment_pairs: List of segments in UUID pairs
@ -736,13 +748,13 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
profile = self.get_network_profile(context, profile = self.get_network_profile(context,
network[n1kv_profile.PROFILE_ID]) network[n1kv_profile.PROFILE_ID])
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_OVERLAY:
n1kvclient.create_bridge_domain(network) n1kvclient.create_bridge_domain(network, profile['sub_type'])
if network[providernet.NETWORK_TYPE] == c_const.NETWORK_TYPE_TRUNK: if network[providernet.NETWORK_TYPE] == c_const.NETWORK_TYPE_TRUNK:
self._populate_member_segments(context, network, segment_pairs, self._populate_member_segments(context, network, segment_pairs,
n1kv_profile.SEGMENT_ADD) n1kv_profile.SEGMENT_ADD)
network['del_segment_list'] = [] network['del_segment_list'] = []
if profile['sub_type'] == c_const.NETWORK_TYPE_VXLAN: if profile['sub_type'] == c_const.NETWORK_TYPE_OVERLAY:
encap_dict = {'name': (network['name'] + encap_dict = {'name': (network['name'] +
c_const.ENCAPSULATION_PROFILE_SUFFIX), c_const.ENCAPSULATION_PROFILE_SUFFIX),
'add_segment_list': ( 'add_segment_list': (
@ -788,7 +800,7 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
body['delSegments'] = network['del_segment_list'] body['delSegments'] = network['del_segment_list']
LOG.debug(_('add_segments=%s'), body['addSegments']) LOG.debug(_('add_segments=%s'), body['addSegments'])
LOG.debug(_('del_segments=%s'), body['delSegments']) LOG.debug(_('del_segments=%s'), body['delSegments'])
if profile['sub_type'] == c_const.NETWORK_TYPE_VXLAN: if profile['sub_type'] == c_const.NETWORK_TYPE_OVERLAY:
encap_profile = (network['name'] + encap_profile = (network['name'] +
c_const.ENCAPSULATION_PROFILE_SUFFIX) c_const.ENCAPSULATION_PROFILE_SUFFIX)
encap_dict = {'name': encap_profile, encap_dict = {'name': encap_profile,
@ -806,21 +818,21 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
""" """
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 Overlay.
Delete encapsulation profile if network is of type VXLAN Trunk. Delete encapsulation profile if network is of type OVERLAY Trunk.
:param context: neutron api request context :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 session = context.session
if network[providernet.NETWORK_TYPE] == c_const.NETWORK_TYPE_VXLAN: if network[providernet.NETWORK_TYPE] == c_const.NETWORK_TYPE_OVERLAY:
name = network['name'] + c_const.BRIDGE_DOMAIN_SUFFIX 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: elif network[providernet.NETWORK_TYPE] == c_const.NETWORK_TYPE_TRUNK:
profile = self.get_network_profile( profile = self.get_network_profile(
context, network[n1kv_profile.PROFILE_ID]) context, network[n1kv_profile.PROFILE_ID])
if profile['sub_type'] == c_const.NETWORK_TYPE_VXLAN: if profile['sub_type'] == c_const.NETWORK_TYPE_OVERLAY:
profile_name = (network['name'] + profile_name = (network['name'] +
c_const.ENCAPSULATION_PROFILE_SUFFIX) c_const.ENCAPSULATION_PROFILE_SUFFIX)
n1kvclient.delete_encapsulation_profile(profile_name) n1kvclient.delete_encapsulation_profile(profile_name)
@ -1126,12 +1138,12 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
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): if n1kv_db_v2.is_trunk_member(session, id):
msg = _("Cannot delete a network " msg = _("Cannot delete network '%s' "
"that is a member of a trunk segment") "that is member of a trunk segment") % network['name']
raise q_exc.InvalidInput(error_message=msg) raise q_exc.InvalidInput(error_message=msg)
if n1kv_db_v2.is_multi_segment_member(session, id): if n1kv_db_v2.is_multi_segment_member(session, id):
msg = _("Cannot delete a network " msg = _("Cannot delete network '%s' that is a member of a "
"that is a member of a multi-segment network") "multi-segment network") % network['name']
raise q_exc.InvalidInput(error_message=msg) raise q_exc.InvalidInput(error_message=msg)
if self.agent_vsm: if self.agent_vsm:
try: try:
@ -1140,7 +1152,7 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
cisco_exceptions.VSMConnectionFailed): cisco_exceptions.VSMConnectionFailed):
LOG.debug(_('Delete failed in VSM')) 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_OVERLAY:
n1kv_db_v2.release_vxlan(session, binding.segmentation_id, n1kv_db_v2.release_vxlan(session, binding.segmentation_id,
self.vxlan_id_ranges) self.vxlan_id_ranges)
elif binding.network_type == c_const.NETWORK_TYPE_VLAN: elif binding.network_type == c_const.NETWORK_TYPE_VLAN:
@ -1394,7 +1406,7 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
Create a network profile. Create a network profile.
Create a network profile, which represents a pool of networks Create a network profile, which represents a pool of networks
belonging to one type (VLAN or VXLAN). On creation of network belonging to one type (VLAN or Overlay). On creation of network
profile, we retrieve the admin tenant-id which we use to replace profile, we retrieve the admin tenant-id which we use to replace
the previously stored fake tenant-id in tenant-profile bindings. the previously stored fake tenant-id in tenant-profile bindings.
:param context: neutron api request context :param context: neutron api request context
@ -1406,7 +1418,7 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
N1kvNeutronPluginV2, self).create_network_profile(context, N1kvNeutronPluginV2, self).create_network_profile(context,
network_profile) network_profile)
if _network_profile['segment_type'] in [c_const.NETWORK_TYPE_VLAN, if _network_profile['segment_type'] in [c_const.NETWORK_TYPE_VLAN,
c_const.NETWORK_TYPE_VXLAN]: c_const.NETWORK_TYPE_OVERLAY]:
seg_min, seg_max = self._get_segment_range( seg_min, seg_max = self._get_segment_range(
_network_profile['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:
@ -1454,8 +1466,9 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
int(seg_max)) int(seg_max))
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_OVERLAY:
self.delete_vxlan_ranges = [(int(seg_min), int(seg_max))] self.delete_vxlan_ranges = []
self.delete_vxlan_ranges.append((int(seg_min), int(seg_max)))
n1kv_db_v2.delete_vxlan_allocations(context.session, n1kv_db_v2.delete_vxlan_allocations(context.session,
self.delete_vxlan_ranges) self.delete_vxlan_ranges)
self._send_delete_network_profile_request(_network_profile) self._send_delete_network_profile_request(_network_profile)

View File

@ -60,7 +60,8 @@ TEST_NETWORK_PROFILE_2 = {'name': 'test_profile_2',
'physical_network': 'physnet1', 'physical_network': 'physnet1',
'segment_range': SEGMENT_RANGE} 'segment_range': SEGMENT_RANGE}
TEST_NETWORK_PROFILE_VXLAN = {'name': 'test_profile', TEST_NETWORK_PROFILE_VXLAN = {'name': 'test_profile',
'segment_type': 'vxlan', 'segment_type': 'overlay',
'sub_type': 'native_vxlan',
'segment_range': '5000-5009', 'segment_range': '5000-5009',
'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',
@ -72,7 +73,7 @@ TEST_NETWORK_PROFILE_VLAN_TRUNK = {'name': 'test_profile',
'sub_type': 'vlan'} 'sub_type': 'vlan'}
TEST_NETWORK_PROFILE_VXLAN_TRUNK = {'name': 'test_profile', TEST_NETWORK_PROFILE_VXLAN_TRUNK = {'name': 'test_profile',
'segment_type': 'trunk', 'segment_type': 'trunk',
'sub_type': 'vxlan'} 'sub_type': 'overlay'}
def _create_test_network_profile_if_not_there(session, def _create_test_network_profile_if_not_there(session,
@ -600,7 +601,7 @@ class NetworkBindingsTest(test_plugin.NeutronDbPluginV2TestCase):
p_v = _create_test_network_profile_if_not_there( p_v = _create_test_network_profile_if_not_there(
self.session, TEST_NETWORK_PROFILE_VXLAN_TRUNK) self.session, TEST_NETWORK_PROFILE_VXLAN_TRUNK)
n1kv_db_v2.add_network_binding( n1kv_db_v2.add_network_binding(
self.session, TEST_NETWORK_ID2, 'vxlan', self.session, TEST_NETWORK_ID2, 'overlay',
None, 5100, '224.10.10.10', p_v.id, None) None, 5100, '224.10.10.10', p_v.id, None)
p = _create_test_network_profile_if_not_there( p = _create_test_network_profile_if_not_there(
self.session, self.session,