Validate multicast ip range in Cisco N1kv Plugin

Do the validation of multicast ip range in Cisco N1kv Plugin and send
appropriate parameters to VSM.

Change-Id: Iaa1288d8a6deb2a2f32b263d4556dde8938d75f5
Closes-Bug: #1282754
This commit is contained in:
Dhanashree Gosavi 2014-02-06 21:07:58 -08:00
parent adbf6c5289
commit 4cacfa22eb
5 changed files with 107 additions and 10 deletions

View File

@ -24,6 +24,7 @@ import re
from sqlalchemy.orm import exc from sqlalchemy.orm import exc
from sqlalchemy.sql import and_ from sqlalchemy.sql import and_
from neutron.api.v2 import attributes
from neutron.common import exceptions as n_exc from neutron.common import exceptions as n_exc
import neutron.db.api as db import neutron.db.api as db
from neutron.db import models_v2 from neutron.db import models_v2
@ -1226,6 +1227,37 @@ class NetworkProfile_db_mixin(object):
msg = _("Invalid segment range. example range: 500-550") msg = _("Invalid segment range. example range: 500-550")
raise n_exc.InvalidInput(error_message=msg) raise n_exc.InvalidInput(error_message=msg)
def _validate_multicast_ip_range(self, network_profile):
"""
Validate multicast ip range values.
:param network_profile: network profile object
"""
try:
min_ip, max_ip = (network_profile
['multicast_ip_range'].split('-', 1))
except ValueError:
msg = _("Invalid multicast ip address range. "
"example range: 224.1.1.1-224.1.1.10")
LOG.error(msg)
raise n_exc.InvalidInput(error_message=msg)
for ip in [min_ip, max_ip]:
try:
if not netaddr.IPAddress(ip).is_multicast():
msg = _("%s is not a valid multicast ip address") % ip
LOG.error(msg)
raise n_exc.InvalidInput(error_message=msg)
except netaddr.AddrFormatError:
msg = _("%s is not a valid ip address") % ip
LOG.error(msg)
raise n_exc.InvalidInput(error_message=msg)
if netaddr.IPAddress(min_ip) > netaddr.IPAddress(max_ip):
msg = (_("Invalid multicast IP range '%(min_ip)s-%(max_ip)s':"
" Range should be from low address to high address") %
{'min_ip': min_ip, 'max_ip': max_ip})
LOG.error(msg)
raise n_exc.InvalidInput(error_message=msg)
def _validate_network_profile(self, net_p): def _validate_network_profile(self, net_p):
""" """
Validate completeness of a network profile arguments. Validate completeness of a network profile arguments.
@ -1270,6 +1302,14 @@ class NetworkProfile_db_mixin(object):
if segment_type == c_const.NETWORK_TYPE_OVERLAY: if segment_type == c_const.NETWORK_TYPE_OVERLAY:
if net_p['sub_type'] != c_const.NETWORK_SUBTYPE_NATIVE_VXLAN: if net_p['sub_type'] != c_const.NETWORK_SUBTYPE_NATIVE_VXLAN:
net_p['multicast_ip_range'] = '0.0.0.0' net_p['multicast_ip_range'] = '0.0.0.0'
else:
multicast_ip_range = net_p.get("multicast_ip_range")
if not attributes.is_attr_set(multicast_ip_range):
msg = _("Argument multicast_ip_range missing"
" for VXLAN multicast network profile")
LOG.error(msg)
raise n_exc.InvalidInput(error_message=msg)
self._validate_multicast_ip_range(net_p)
else: else:
net_p['multicast_ip_range'] = '0.0.0.0' net_p['multicast_ip_range'] = '0.0.0.0'

View File

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

View File

@ -199,7 +199,7 @@ class Client(object):
:param network: network dict :param network: network dict
:param network_profile: network profile dict :param network_profile: network profile dict
""" """
body = {'publishName': network['name'], body = {'publishName': network['id'],
'description': network['name'], 'description': network['name'],
'id': network['id'], 'id': network['id'],
'tenantId': network['tenant_id'], 'tenantId': network['tenant_id'],

View File

@ -746,7 +746,7 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
profile = n1kv_db_v2.get_network_profile( profile = n1kv_db_v2.get_network_profile(
db_session, network[n1kv.PROFILE_ID]) db_session, network[n1kv.PROFILE_ID])
n1kvclient = n1kv_client.Client() n1kvclient = n1kv_client.Client()
body = {'publishName': network['name'], body = {'description': network['name'],
'id': network['id'], 'id': network['id'],
'networkSegmentPool': profile['id'], 'networkSegmentPool': profile['id'],
'vlan': network[providernet.SEGMENTATION_ID], 'vlan': network[providernet.SEGMENTATION_ID],
@ -1088,11 +1088,11 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
net['id'], del_segments) 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)
if binding.network_type not in [c_const.NETWORK_TYPE_MULTI_SEGMENT]: if binding.network_type != c_const.NETWORK_TYPE_MULTI_SEGMENT:
self._send_update_network_request(context, net, add_segments, self._send_update_network_request(context, net, add_segments,
del_segments) del_segments)
LOG.debug(_("Updated network: %s"), net['id']) LOG.debug(_("Updated network: %s"), net['id'])
return net return net
def delete_network(self, context, id): def delete_network(self, context, id):
""" """
@ -1465,4 +1465,4 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
net_profile_id, net_profile_id,
network_profile)) network_profile))
self._send_update_network_profile_request(net_p) self._send_update_network_profile_request(net_p)
return net_p return net_p

View File

@ -250,7 +250,9 @@ class TestN1kvNetworkProfiles(N1kvPluginTestCase):
netp['network_profile']['physical_network'] = 'phys1' netp['network_profile']['physical_network'] = 'phys1'
elif segment_type == 'overlay': elif segment_type == 'overlay':
netp['network_profile']['segment_range'] = '10000-10010' netp['network_profile']['segment_range'] = '10000-10010'
netp['network_profile']['sub_type'] = 'enhanced' netp['network_profile']['sub_type'] = 'enhanced' or 'native_vxlan'
netp['network_profile']['multicast_ip_range'] = ("224.1.1.1-"
"224.1.1.10")
return netp return netp
def test_create_network_profile_plugin(self): def test_create_network_profile_plugin(self):
@ -289,6 +291,60 @@ class TestN1kvNetworkProfiles(N1kvPluginTestCase):
update_res = update_req.get_response(self.ext_api) update_res = update_req.get_response(self.ext_api)
self.assertEqual(update_res.status_int, 400) self.assertEqual(update_res.status_int, 400)
def test_create_overlay_network_profile_invalid_multicast_fail(self):
net_p_dict = self._prepare_net_profile_data('overlay')
data = {'network_profile': {'sub_type': 'native_vxlan',
'multicast_ip_range': '1.1.1.1'}}
net_p_req = self.new_create_request('network_profiles', data,
net_p_dict)
res = net_p_req.get_response(self.ext_api)
self.assertEqual(res.status_int, 400)
def test_create_overlay_network_profile_no_multicast_fail(self):
net_p_dict = self._prepare_net_profile_data('overlay')
data = {'network_profile': {'sub_type': 'native_vxlan',
'multicast_ip_range': ''}}
net_p_req = self.new_create_request('network_profiles', data,
net_p_dict)
res = net_p_req.get_response(self.ext_api)
self.assertEqual(res.status_int, 400)
def test_create_overlay_network_profile_wrong_split_multicast_fail(self):
net_p_dict = self._prepare_net_profile_data('overlay')
data = {'network_profile': {
'sub_type': 'native_vxlan',
'multicast_ip_range': '224.1.1.1.224.1.1.3'}}
net_p_req = self.new_create_request('network_profiles', data,
net_p_dict)
res = net_p_req.get_response(self.ext_api)
self.assertEqual(res.status_int, 400)
def test_create_overlay_network_profile_invalid_minip_multicast_fail(self):
net_p_dict = self._prepare_net_profile_data('overlay')
data = {'network_profile': {
'sub_type': 'native_vxlan',
'multicast_ip_range': '10.0.0.1-224.1.1.3'}}
net_p_req = self.new_create_request('network_profiles', data,
net_p_dict)
res = net_p_req.get_response(self.ext_api)
self.assertEqual(res.status_int, 400)
def test_create_overlay_network_profile_invalid_maxip_multicast_fail(self):
net_p_dict = self._prepare_net_profile_data('overlay')
data = {'network_profile': {
'sub_type': 'native_vxlan',
'multicast_ip_range': '224.1.1.1-20.0.0.1'}}
net_p_req = self.new_create_request('network_profiles', data,
net_p_dict)
res = net_p_req.get_response(self.ext_api)
self.assertEqual(res.status_int, 400)
def test_create_overlay_network_profile_correct_multicast_pass(self):
data = self._prepare_net_profile_data('overlay')
net_p_req = self.new_create_request('network_profiles', data)
res = net_p_req.get_response(self.ext_api)
self.assertEqual(res.status_int, 201)
class TestN1kvBasicGet(test_plugin.TestBasicGet, class TestN1kvBasicGet(test_plugin.TestBasicGet,
N1kvPluginTestCase): N1kvPluginTestCase):