CLI support for Segment Routing Policy config
diff --git a/cli/cli/c_actions.py b/cli/cli/c_actions.py
index 4e01de3..72abeba 100755
--- a/cli/cli/c_actions.py
+++ b/cli/cli/c_actions.py
@@ -103,7 +103,7 @@
obj_data['tunnel-path']=entries
data = sdnsh.store.rest_post_request(url_str,obj_data)
# LOOK! successful stuff should be returned in json too.
- if data != "saved":
+ if data != "success":
result = json.loads(data)
return result
else:
@@ -111,7 +111,64 @@
#Clear the transit information
tunnel_dict = {}
+def tunnel_remove(data=None):
+ if sdnsh.description: # description debugging
+ print "tunnel_remove:" , data
+ tunnel_id=data['tunnel-id']
+ url_str = "http://%s/rest/v1/tunnel/" % (sdnsh.controller)
+ obj_data = {}
+ obj_data['tunnel-id']=data['tunnel_id']
+ data = sdnsh.store.rest_post_request(url_str,obj_data,'DELETE')
+ if data != "deleted":
+ result = json.loads(data)
+ return result
+
+policy_obj_data = {}
+flow = {}
+def policy_create(data=None):
+ global policy_obj_data
+ if sdnsh.description: # description debugging
+ print "policy_create:" , data
+ if data.has_key('policy-id'):
+ policy_obj_data['policy_id'] = data['policy-id']
+ if data.has_key('src-ip'):
+ for key in data:
+ policy_obj_data[key] = data[key]
+ if data.has_key('priority'):
+ policy_obj_data['priority'] = data['priority']
+ if data.has_key('tunnel-id'):
+ policy_obj_data['tunnel_id'] = data['tunnel-id']
+
+ print policy_obj_data
+def policy_config_exit():
+ global policy_obj_data
+ if sdnsh.description: # description debugging
+ print "policy_config_exit entered", policy_obj_data
+ if policy_obj_data:
+ url_str = "http://%s/rest/v1/policy/" % (sdnsh.controller)
+ data = sdnsh.store.rest_post_request(url_str,policy_obj_data)
+ # LOOK! successful stuff should be returned in json too.
+ if data != "success":
+ result = json.loads(data)
+ return result
+ else:
+ print "empty command"
+ #Clear the transit information
+ policy_obj_data = {}
+
+def policy_remove(data=None):
+ if sdnsh.description: # description debugging
+ print "policy_remove:" , data
+ policy_id=data['policy-id']
+ url_str = "http://%s/rest/v1/policy/" % (sdnsh.controller)
+ obj_data = {}
+ obj_data['policy-id']=data['policy-id']
+ data = sdnsh.store.rest_post_request(url_str,obj_data,'DELETE')
+ if data != "deleted":
+ result = json.loads(data)
+ return result
+
def write_fields(obj_type, obj_id, data):
"""
Typical action to update fields of a row in the model
@@ -753,6 +810,8 @@
exitCallback = None
if (mode_name == 'config-tunnel'):
exitCallback = tunnel_config_exit
+ if (mode_name == 'config-policy'):
+ exitCallback = policy_config_exit
sdnsh.push_mode(mode_name, obj_type, key, exitCallback)
@@ -3611,6 +3670,18 @@
command.add_action('create-tunnel',
tunnel_create,
{'kwargs': {'data' : '$data',}})
+
+ command.add_action('remove-tunnel',
+ tunnel_remove,
+ {'kwargs': {'data' : '$data',}})
+
+ command.add_action('create-policy',
+ policy_create,
+ {'kwargs': {'data' : '$data',}})
+
+ command.add_action('remove-policy',
+ policy_remove,
+ {'kwargs': {'data' : '$data',}})
command.add_action('write-fields', write_fields,
{'kwargs': {'obj_type': '$current-mode-obj-type',
diff --git a/cli/cli/command.py b/cli/cli/command.py
index 6428f04..f585453 100755
--- a/cli/cli/command.py
+++ b/cli/cli/command.py
@@ -3782,10 +3782,11 @@
for mode in modes:
if mode.endswith('*') and current_mode.startswith(mode[:-1]):
return True
- if command.get('command-type') == 'config-submode':
- for mode in modes:
- if current_mode.startswith(mode):
- return True
+ #if command.get('command-type') == 'config-submode':
+ # for mode in modes:
+ # if current_mode.startswith(mode):
+ # print "_match_current_modes: current command type is config-submode",current_mode,mode
+ # return True
return False
@@ -3868,6 +3869,18 @@
'action': 'create-tunnel'
})
+ add_command_type('remove-tunnel', {
+ 'action': 'remove-tunnel'
+ })
+
+ add_command_type('create-policy', {
+ 'action': 'create-policy'
+ })
+
+ add_command_type('remove-policy', {
+ 'action': 'remove-policy'
+ })
+
add_command_type('display-table', {
'action': 'display-table'
})
diff --git a/cli/cli/desc/version200/switch.py b/cli/cli/desc/version200/switch.py
index 47a56a5..8713379 100755
--- a/cli/cli/desc/version200/switch.py
+++ b/cli/cli/desc/version200/switch.py
@@ -15,14 +15,15 @@
#
import command
import json
+import fmtcnv
TUNNEL_SUBMODE_COMMAND_DESCRIPTION = {
'name' : 'tunnel',
'short-help' : 'Enter tunnel submode, configure tunnel details',
- 'mode' : 'config*',
+ 'mode' : 'config',
+ 'parent-field' : None,
'command-type' : 'config-submode',
'obj-type' : 'tunnel-config',
- 'parent-field' : None,
'submode-name' : 'config-tunnel',
'doc' : 'tunnel|tunnel',
'doc-example' : 'tunnel|tunnel-example',
@@ -42,6 +43,11 @@
'proc' : 'push-mode-stack',
},
),
+ 'no-action': (
+ {
+ 'proc' : 'remove-tunnel',
+ }
+ ),
}
)
}
@@ -69,6 +75,7 @@
'short-help' : 'Set node for this tunnel',
'doc' : 'tunnel|node',
'doc-example' : 'tunnel|node',
+ 'parent-field' : 'tunnel',
'command-type' : 'config',
'args' : (
{
@@ -86,7 +93,7 @@
}
)
}
-
+"""
TUNNEL_ADJACENCY_ENTRY_COMMAND_DESCRIPTION = {
'name' : 'adjacency',
'mode' : 'config-tunnel',
@@ -107,6 +114,312 @@
}
)
}
+"""
+
+POLICY_SUBMODE_COMMAND_DESCRIPTION = {
+ 'name' : 'policy',
+ 'short-help' : 'Enter policy submode, configure SR policy details',
+ 'mode' : 'config',
+ 'command-type' : 'config-submode',
+ 'obj-type' : 'policy-config',
+ 'submode-name' : 'config-policy',
+ 'parent-field' : None,
+ 'doc' : 'policy|policy',
+ 'doc-example' : 'policy|policy-example',
+ 'args' : (
+ {
+ 'field' : 'policy-id',
+ 'type' : 'identifier',
+ 'completion' : 'complete-object-field',
+ 'syntax-help' : 'Enter a policy name',
+ 'doc' : 'policy|policy',
+ 'doc-include' : [ 'type-doc' ],
+ 'action' : (
+ {
+ 'proc' : 'create-policy',
+ },
+ {
+ 'proc' : 'push-mode-stack',
+ },
+ ),
+ 'no-action': (
+ {
+ 'proc' : 'remove-policy',
+ },
+ )
+ }
+ )
+}
+
+SRC_IP_MATCH = {
+ 'choices' : (
+ (
+ {
+ 'field' : 'src-ip',
+ 'type' : 'ip-address-not-mask',
+ 'doc' : 'vns|vns-access-list-ip-and-mask-ip',
+ },
+ {
+ 'field' : 'src-ip-mask',
+ 'type' : 'inverse-netmask',
+ 'data' : {
+ 'dst-ip' : '0.0.0.0',
+ 'dst-ip-mask' : '255.255.255.255',
+ },
+ 'doc' : 'vns|vns-access-list-ip-and-mask-mask',
+ },
+ ),
+ (
+ {
+ 'field' : 'src-ip',
+ 'type' : 'ip-address-not-mask',
+ 'data' : {
+ 'src-ip-mask' : '0.0.0.0',
+ 'dst-ip' : '0.0.0.0',
+ 'dst-ip-mask' : '255.255.255.255',
+ },
+ 'doc' : 'vns|vns-access-list-ip-only',
+ },
+ ),
+ (
+ {
+ 'field' : 'src-ip',
+ 'type' : 'cidr-range',
+ 'help-name' : 'src-cidr',
+ 'data-handler' : 'split-cidr-data-inverse',
+ 'dest-ip' : 'src-ip',
+ 'dest-netmask' : 'src-ip-mask',
+ 'data' : {
+ 'dst-ip' : '0.0.0.0',
+ 'dst-ip-mask' : '255.255.255.255',
+ },
+ 'doc' : 'vns|vns-access-list-cidr-range',
+ }
+ ),
+ (
+ {
+ 'token' : 'any',
+ 'data' : {
+ 'src-ip' : '0.0.0.0',
+ 'src-ip-mask' : '255.255.255.255',
+ 'dst-ip' : '0.0.0.0',
+ 'dst-ip-mask' : '255.255.255.255',
+ },
+ 'doc' : 'vns|vns-access-list-ip-any',
+ }
+ ),
+ )
+}
+
+SRC_PORT_MATCH = (
+ {
+ 'field' : 'src-tp-port-op',
+ 'type' : 'enum',
+ 'values' : ('eq', 'neq'),
+ 'doc' : 'vns|vns-access-list-port-op-+',
+ },
+ {
+ 'choices' : (
+ {
+ 'field' : 'src-tp-port',
+ 'base-type' : 'hex-or-decimal-integer',
+ 'range' : (0,65535),
+ 'data-handler' : 'hex-to-integer',
+ 'doc' : 'vns|vns-access-list-port-hex',
+ 'doc-include' : [ 'range' ],
+ },
+ {
+ 'field' : 'src-tp-port',
+ 'type' : 'enum',
+ 'values' : fmtcnv.tcp_name_to_number_dict,
+ 'permute' : 'skip',
+ 'doc' : 'vns|vns-access-list-port-type',
+ },
+ ),
+ },
+)
+
+
+DST_IP_MATCH = {
+ 'choices' : (
+ (
+ {
+ 'field' : 'dst-ip',
+ 'type' : 'ip-address-not-mask',
+ 'doc' : 'vns|vns-access-list-ip-and-mask-ip',
+ },
+ {
+ 'field' : 'dst-ip-mask',
+ 'type' : 'inverse-netmask',
+ 'doc' : 'vns|vns-access-list-ip-and-mask-mask',
+ },
+ ),
+ (
+ {
+ 'field' : 'dst-ip',
+ 'type' : 'ip-address-not-mask',
+ 'data' : {
+ 'dst-ip-mask' : '0.0.0.0',
+ },
+ 'doc' : 'vns|vns-access-list-ip-only',
+ },
+ ),
+ (
+ {
+ 'field' : 'dst-ip',
+ 'type' : 'cidr-range',
+ 'help-name' : 'dst-cidr',
+ 'data-handler' : 'split-cidr-data-inverse',
+ 'dest-ip' : 'dst-ip',
+ 'dest-netmask' : 'dst-ip-mask',
+ 'doc' : 'vns|vns-access-list-cidr-range',
+ },
+ ),
+ (
+ {
+ 'token' : 'any',
+ 'data' : {
+ 'dst-ip' : '0.0.0.0',
+ 'dst-ip-mask' : '255.255.255.255',
+ },
+ 'doc' : 'vns|vns-access-list-ip-any',
+ }
+ ),
+ )
+}
+
+
+DST_PORT_MATCH = (
+ {
+ 'field' : 'dst-tp-port-op',
+ 'type' : 'enum',
+ 'values' : ('eq', 'neq'),
+ 'doc' : 'vns|vns-access-list-port-op+',
+ },
+ {
+ 'choices' : (
+ {
+ 'field' : 'dst-tp-port',
+ 'base-type' : 'hex-or-decimal-integer',
+ 'range' : (0,65535),
+ 'data-handler' : 'hex-to-integer',
+ 'doc' : 'vns|vns-access-list-port-hex',
+ },
+ {
+ 'field' : 'dst-tp-port',
+ 'type' : 'enum',
+ 'values' : fmtcnv.tcp_name_to_number_dict,
+ 'permute' : 'skip'
+ },
+ ),
+ }
+)
+
+POLICY_FLOW_ENTRY_COMMAND_DESCRIPTION = {
+ 'name' : 'flow-entry',
+ 'mode' : 'config-policy',
+ 'command-type' : 'config',
+ 'short-help' : 'Configure flow entry',
+ 'doc' : 'flow-entry|flow-entry',
+ 'doc-example' : 'flow-entry|flow-entry-example',
+ 'parent-field' : 'policy',
+ 'args' : {
+ 'action' : (
+ {
+ 'proc' : 'create-policy',
+ },
+ ),
+ 'choices' : (
+ (
+ {
+ 'choices' : (
+ {
+ 'field' : 'type',
+ 'type' : 'enum',
+ 'values' : ('ip','tcp','udp'),
+ 'doc' : 'vns|vns-access-list-entry-type-+',
+ },
+ {
+ 'field' : 'type',
+ 'base-type' : 'hex-or-decimal-integer',
+ 'range' : (0,255),
+ 'help-name' : 'ip protocol',
+ 'data-handler' : 'hex-to-integer',
+ 'doc' : 'vns|vns-access-entry-type-ip-protocol',
+ 'doc-include' : [ 'range' ],
+ },
+ )
+ },
+ # Complexity arises from the SRC_IP match part
+ # being, required, while the port match
+ # is optional, as is the DST_IP match, but the
+ # DST_PORT_MATCH is only possible to describe when
+ # the DST_IP part is included
+ SRC_IP_MATCH,
+ {
+ 'optional' : True,
+ 'optional-for-no' : True,
+ 'args' : SRC_PORT_MATCH,
+ },
+ {
+ 'optional' : True,
+ 'optional-for-no' : True,
+ 'args' : (
+ DST_IP_MATCH,
+ {
+ 'optional' : True,
+ 'optional-for-no' : True,
+ 'args' : DST_PORT_MATCH,
+ },
+ ),
+ },
+ ),
+ ),
+ },
+}
+
+POLICY_TUNNEL_ID_COMMAND_DESCRIPTION = {
+ 'name' : 'tunnel',
+ 'mode' : 'config-policy',
+ #'obj-type' : 'policy-config',
+ 'command-type' : 'config',
+ 'short-help' : 'Configure tunnel id',
+ #'doc' : 'policy|tunnel',
+ #'doc-example' : 'policy|policy-tunnel-example',
+ 'parent-field' : 'policy',
+ 'args' : {
+ 'action' : (
+ {
+ 'proc' : 'create-policy',
+ },
+ ),
+ 'field' : 'tunnel-id',
+ 'type' : 'identifier',
+ 'syntax-help' : 'Enter tunnel id',
+ 'doc' : 'policy|tunnel-id',
+ 'doc-include' : [ 'type-doc' ],
+ }
+}
+
+POLICY_PRIORITY_COMMAND_DESCRIPTION = {
+ 'name' : 'priority',
+ 'mode' : 'config-policy',
+ 'command-type' : 'config',
+ 'short-help' : 'Configure policy priority',
+ 'doc' : 'policy|priority',
+ 'doc-example' : 'policy|policy-priority-example',
+ 'parent-field' : 'policy',
+ 'args' : {
+ 'action' : (
+ {
+ 'proc' : 'create-policy',
+ },
+ ),
+ 'field' : 'priority',
+ 'base-type' : 'integer',
+ 'range' : (0, 65535),
+ }
+}
"""
SWITCH_SUBMODE_COMMAND_DESCRIPTION = {
diff --git a/cli/sdncon/controller/models.py b/cli/sdncon/controller/models.py
index a3db737..25f715c 100755
--- a/cli/sdncon/controller/models.py
+++ b/cli/sdncon/controller/models.py
@@ -120,6 +120,39 @@
{'name': 'path_seq', 'rest_name': 'path-seq'},
)
+class SRPolicy(models.Model):
+
+ id_max_length = 64
+ #
+ # fields ----------------------------------------
+
+ #
+ # Unique name of the Tunnel
+ #
+ sr_policy_id = models.CharField(
+ primary_key = True,
+ verbose_name = 'SR Policy Id',
+ help_text = 'A unique Id for a SR Policy',
+ validators = [ TenantNameValidator() ],
+ max_length = id_max_length)
+
+ #
+ # end fields ----------------------------------------
+
+ def __unicode__ (self):
+ return self.tunnel_id
+
+ class CassandraSettings:
+ COMPOUND_KEY_FIELDS = ('sr_policy_id')
+
+ def delete(self):
+ super(Tunnel, self).delete()
+ class Rest:
+ NAME = 'policy-config'
+ FIELD_INFO = (
+ {'name': 'sr_policy_id', 'rest_name': 'policy-id'},
+ )
+
#
# ------------------------------------------------------------
diff --git a/cli/sdncon/rest/views.py b/cli/sdncon/rest/views.py
index f8c616b..66ec9d7 100755
--- a/cli/sdncon/rest/views.py
+++ b/cli/sdncon/rest/views.py
@@ -2136,13 +2136,35 @@
@safe_rest_view
def do_sdnplatform_tunnel_config(request):
- if request.method != 'PUT':
+ if request.method != 'PUT' and request.method != 'DELETE':
raise RestInvalidMethodException()
url = controller_url('onos', 'segmentrouting', 'tunnel')
post_data = request.raw_post_data
put_request = urllib2.Request(url, post_data)
- put_request.get_method = lambda: 'POST'
+ method = request.method
+ if method == 'PUT':
+ method = 'POST'
+ put_request.get_method = lambda: method
+ put_request.add_header('Content-Type', 'application/json')
+ response = urllib2.urlopen(put_request)
+ response_text = response.read()
+ response = HttpResponse(response_text, JSON_CONTENT_TYPE)
+
+ return response
+
+@safe_rest_view
+def do_sdnplatform_policy_config(request):
+ if request.method != 'PUT' and request.method != 'DELETE':
+ raise RestInvalidMethodException()
+
+ url = controller_url('onos', 'segmentrouting', 'policy')
+ post_data = request.raw_post_data
+ put_request = urllib2.Request(url, post_data)
+ method = request.method
+ if method == 'PUT':
+ method = 'POST'
+ put_request.get_method = lambda: method
put_request.add_header('Content-Type', 'application/json')
response = urllib2.urlopen(put_request)
response_text = response.read()
diff --git a/cli/sdncon/urls.py b/cli/sdncon/urls.py
index 4237d17..9857de0 100755
--- a/cli/sdncon/urls.py
+++ b/cli/sdncon/urls.py
@@ -168,8 +168,10 @@
# REST APIs for controller summary statistics
(r'^rest/v1/controller/summary$', 'sdncon.rest.views.do_sdnplatform_controller_summary'),
- # REST APIs for tunnel
+ # REST APIs for SR tunnel
(r'^rest/v1/tunnel/?$', 'sdncon.rest.views.do_sdnplatform_tunnel_config'),
+ # REST APIs for SR policy
+ (r'^rest/v1/policy/?$', 'sdncon.rest.views.do_sdnplatform_policy_config'),
)