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'),
 
 )