diff --git a/config/transformer/models_list b/config/transformer/models_list index bc192c902a..c7e34647c0 100644 --- a/config/transformer/models_list +++ b/config/transformer/models_list @@ -2,3 +2,4 @@ openconfig-acl.yang openconfig-acl-annot.yang +sonic-vxlan.yang diff --git a/models/yang/openconfig-spanning-tree-ext.yang b/models/yang/openconfig-spanning-tree-ext.yang index 3546a7c8fa..6e91e7113a 100755 --- a/models/yang/openconfig-spanning-tree-ext.yang +++ b/models/yang/openconfig-spanning-tree-ext.yang @@ -85,6 +85,12 @@ module openconfig-spanning-tree-ext { description "Instance identifier of STP"; } + + leaf root-port-name { + type string; + description + "Name of root port"; + } } grouping vlan-interface-extra-state-field { diff --git a/models/yang/sonic/sonic-vxlan.yang b/models/yang/sonic/sonic-vxlan.yang new file mode 100644 index 0000000000..2c962959d3 --- /dev/null +++ b/models/yang/sonic/sonic-vxlan.yang @@ -0,0 +1,105 @@ +module sonic-vxlan { + namespace "http://github.com/Azure/sonic-vxlan"; + prefix svxlan; + yang-version 1.1; + + import ietf-yang-types { + prefix yang; + } + + import ietf-inet-types { + prefix inet; + } + + organization + "SONiC"; + + contact + "SONiC"; + + description + "SONIC VXLAN"; + + revision 2019-10-01 { + description + "Initial revision."; + } + + container sonic-vxlan { + + container VXLAN_TUNNEL { + + list VXLAN_TUNNEL_LIST { + key "name"; + max-elements 1; + + leaf name { + type string; + } + + leaf src_ip { + mandatory true; + type inet:ipv4-address; + } + } + } + + container VXLAN_TUNNEL_MAP { + + list VXLAN_TUNNEL_MAP_LIST { + key "name mapname"; + + leaf name { + type leafref { + path "../../../VXLAN_TUNNEL/VXLAN_TUNNEL_LIST/name"; + } + } + + leaf mapname { + type string; + } + + leaf vlan { + mandatory true; + type string { + pattern "Vlan(409[0-5]|40[0-8][0-9]|[1-3][0-9]{3}|[1-9][0-9]{2}|[1-9][0-9]|[1-9])" { + error-message "Invalid Vlan name pattern"; + error-app-tag vlan-name-invalid; + } + } + } + + leaf vni { + mandatory true; + type uint32 { + range "1..16777215" { + error-message "VNI ID out of range"; + error-app-tag vnid-invalid; + } + } + } + } + } + + container EVPN_NVO { + + list EVPN_NVO_LIST { + + key "name"; + max-elements 1; + + leaf name { + type string; + } + + leaf source_vtep { + mandatory true; + type leafref { + path "../../../VXLAN_TUNNEL/VXLAN_TUNNEL_LIST/name"; + } + } + } + } + } + +} diff --git a/src/CLI/actioner/README_cli_client.md b/src/CLI/actioner/README_cli_client.md new file mode 100644 index 0000000000..9792310b58 --- /dev/null +++ b/src/CLI/actioner/README_cli_client.md @@ -0,0 +1,42 @@ +# Generic RESTful Python client + +A generic RESTful Python client for interacting with JSON APIs. + +## Usage + +To use this client you just need to import ApiClient and initialize it with an URL endpoint + + from cli_client import ApiClient + api = ApiClient('#your_api_endpoint') #your_api_endpoint is optional default is https://localhost:443 + +Now that you have a RESTful API object you can start sending requests. + + +## Making a request + +The framework supports GET, PUT, POST, PATCH and DELETE requests: + + from cli_client import ApiClient + api = ApiClient() + response = api.get('/authors/') + response = api.post('/authors/', {'title': 'Broadcom', 'author': 'Faraaz Mohammed'}) + response = api.put('/author/faraaz/', {'dob': '06/09/2006'}) + response = api.delete('/author/faraaz/') + +## To get the Response Data +response = api.get('/authors/') +Use response.content object + +For Successful request response.content will contain valid JSON data +For Non-Successful request response.content will contain errors object returned by REST Server + +## Verifying Requests + +Two helpers are built in to verify the success of requests made. `ok()` checks for a 20x status code and returns a boolean, `errors()` returns the body content as a dict object if the status code is not 20x: + + response = api.get('/books/') + if response.ok(): + print 'Success!' + else: + print req.errors() + diff --git a/src/CLI/actioner/cli_client.py b/src/CLI/actioner/cli_client.py new file mode 100644 index 0000000000..e2aea16887 --- /dev/null +++ b/src/CLI/actioner/cli_client.py @@ -0,0 +1,119 @@ +################################################################################ +# # +# Copyright 2019 Broadcom. The term Broadcom refers to Broadcom Inc. and/or # +# its subsidiaries. # +# # +# 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. # +# # +################################################################################ +import json +import urllib3 + +class ApiClient(object): + """ + A client for accessing a RESTful API + """ + def __init__(self, api_uri=None): + """ + Create a RESTful API client. + """ + api_uri="https://localhost:443" + self.api_uri = api_uri + + self.checkCertificate = False + + if not self.checkCertificate: + urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) + + self.version = "0.0.1" + + def set_headers(self, nonce = None): + from base64 import b64encode + from hashlib import sha256 + from platform import platform, python_version + from hmac import new + + if not nonce: + from time import time + nonce = int(time()) + + return { + 'User-Agent': "PythonClient/{0} ({1}; Python {2})".format(self.version, + platform(True), + python_version()) + } + + @staticmethod + def merge_dicts(*dict_args): + result = {} + for dictionary in dict_args: + result.update(dictionary) + + return result + + def request(self, method, path, data = {}, headers = {}): + from requests import request + + url = '{0}{1}'.format(self.api_uri, path) + params = {} + headers = self.merge_dicts(self.set_headers(), headers) + + if method == "GET": + params.update(data) + return request(method, url, headers=headers, params=params, verify=self.checkCertificate) + else: + return request(method, url, headers=headers, params=params, data=json.dumps(data), verify=self.checkCertificate) + + def post(self, path, data = {}): + return Response(self.request("POST", path, data, {'Content-Type': 'application/json'})) + + def get(self, path, data = {}): + return Response(self.request("GET", path, data)) + + def put(self, path, data = {}): + return Response(self.request("PUT", path, data, {'Content-Type': 'application/json'})) + + def patch(self, path, data = {}): + return Response(self.request("PATCH", path, data, {'Content-Type': 'application/json'})) + + def delete(self, path, data = {}): + return Response(self.request("DELETE", path, data)) + +class Response(object): + def __init__(self, response): + self.response = response + + try: + self.content = self.response.json() + except ValueError: + self.content = self.response.text + + def ok(self): + import requests + return self.response.status_code == requests.codes.ok + + def errors(self): + if self.ok(): + return {} + + errors = self.content + + if(not isinstance(errors, dict)): + errors = {"error": errors} # convert to dict for consistency + elif('errors' in errors): + errors = errors['ietf-restconf:errors'] + + return errors + + def __getitem__(self, key): + return self.content[key] diff --git a/src/CLI/actioner/sonic-cli-if.py b/src/CLI/actioner/sonic-cli-if.py index df36e97c72..d4869cf3b7 100755 --- a/src/CLI/actioner/sonic-cli-if.py +++ b/src/CLI/actioner/sonic-cli-if.py @@ -197,6 +197,10 @@ def run(func, args): try: # Temporary code for #show vlan command with dummy data + if func.__name__ == "get_openconfig_vlan_interfaces_interface_ethernet_switched_vlan_state": + api_response = {'Vlan100': {'Ethernet20': 'tagged', 'Ethernet40': 'untagged'}} + show_cli_output(args[0], api_response) + return if body is not None: api_response = getattr(aa,func.__name__)(*keypath, body=body) else : diff --git a/src/CLI/actioner/sonic-cli-ptp.py b/src/CLI/actioner/sonic-cli-ptp.py new file mode 100644 index 0000000000..123306fc6c --- /dev/null +++ b/src/CLI/actioner/sonic-cli-ptp.py @@ -0,0 +1,88 @@ +#!/usr/bin/python + +import sys +import swsssdk +from rpipe_utils import pipestr +from scripts.render_cli import show_cli_output +from swsssdk import ConfigDBConnector + +import urllib3 +urllib3.disable_warnings() + +PTP_CLOCK = 'PTP_CLOCK' +PTP_GLOBAL = 'GLOBAL' + +if __name__ == '__main__': + pipestr().write(sys.argv) + db = swsssdk.SonicV2Connector(host='127.0.0.1') + db.connect(db.CONFIG_DB) + db.connect(db.COUNTERS_DB) + + config_db = ConfigDBConnector() + if config_db is None: + sys.exit() + config_db.connect() + if sys.argv[1] == 'get_ietf_ptp_ptp_instance_list_default_ds': + raw_data = config_db.get_entry(PTP_CLOCK, PTP_GLOBAL) + api_response = {} + api_response['ietf-ptp:default-ds'] = raw_data + show_cli_output(sys.argv[3], api_response) + elif sys.argv[1] == 'get_ietf_ptp_ptp_instance_list_time_properties_ds': + print "Nothing" + sys.exit() + elif sys.argv[1] == 'get_ietf_ptp_ptp_instance_list_parent_ds': + print "Nothing" + sys.exit() + elif sys.argv[1] == 'get_ietf_ptp_ptp_instance_list_port_ds_list': + print "Nothing" + sys.exit() + elif sys.argv[1] == 'get_ietf_ptp_ptp_instance_list': + raw_data = config_db.get_keys(PTP_CLOCK) + api_response = {} + api_response_list = [] + port_ds_dict = {} + port_ds_list = [] + port_ds_entry = {} + for key in raw_data: + if "Ethernet" in key: + port_ds_entry = {} + port_ds_entry["port-number"] = key + port_ds_entry["port-state"] = "online" + port_ds_list.append(port_ds_entry) + port_ds_dict['port-ds-list'] = port_ds_list + api_response_list.append(port_ds_dict) + api_response['ietf-ptp:instance_list'] = api_response_list + show_cli_output(sys.argv[3], api_response) + elif sys.argv[1] == 'patch_ietf_ptp_ptp_instance_list_default_ds_domain_number': + data = {} + data['domain-number'] = sys.argv[3] + config_db.mod_entry(PTP_CLOCK, PTP_GLOBAL, data) + elif sys.argv[1] == 'patch_ietf_ptp_ptp_instance_list_default_ds_priority1': + data = {} + data['priority1'] = sys.argv[3] + config_db.mod_entry(PTP_CLOCK, PTP_GLOBAL, data) + elif sys.argv[1] == 'patch_ietf_ptp_ptp_instance_list_default_ds_priority2': + data = {} + data['priority2'] = sys.argv[3] + config_db.mod_entry(PTP_CLOCK, PTP_GLOBAL, data) + elif sys.argv[1] == 'patch_ietf_ptp_ptp_instance_list_default_ds_two_step_flag': + data = {} + if sys.argv[3] == "enable": + data['two-step-flag'] = '1' + else: + data['two-step-flag'] = '0' + config_db.mod_entry(PTP_CLOCK, PTP_GLOBAL, data) + elif sys.argv[1] == 'patch_ietf_ptp_ptp_transparent_clock_default_ds_delay_mechanism': + data = {} + data['tc-delay-mechanism'] = sys.argv[2] + config_db.mod_entry(PTP_CLOCK, PTP_GLOBAL, data) + elif sys.argv[1] == 'add_port': + data = {} + data['enable'] = '1' + config_db.set_entry(PTP_CLOCK, sys.argv[2], data) + elif sys.argv[1] == 'del_port': + config_db.set_entry(PTP_CLOCK, sys.argv[2], None) + else: + data = {} + data[sys.argv[1]] = sys.argv[2] + config_db.mod_entry(PTP_CLOCK, PTP_GLOBAL, data) diff --git a/src/CLI/actioner/sonic-cli-vxlan.py b/src/CLI/actioner/sonic-cli-vxlan.py new file mode 100755 index 0000000000..3bcb1fe2ed --- /dev/null +++ b/src/CLI/actioner/sonic-cli-vxlan.py @@ -0,0 +1,143 @@ +#!/usr/bin/python +import sys +import time +import json +import ast +import sonic_vxlan_client +from rpipe_utils import pipestr +from sonic_vxlan_client.rest import ApiException +from scripts.render_cli import show_cli_output + +import urllib3 +urllib3.disable_warnings() + + +plugins = dict() + +def register(func): + """Register sdk client method as a plug-in""" + plugins[func.__name__] = func + return func + + +def call_method(name, args): + method = plugins[name] + return method(args) + +def generate_body(func, args): + body = None + # Get the rules of all ACL table entries. + if func.__name__ == 'patch_list_sonic_vxlan_sonic_vxlan_vxlan_tunnel_vxlan_tunnel_list': + keypath = [] + body = { + "sonic-vxlan:VXLAN_TUNNEL_LIST": [ + { + "name": args[0][5:], + "src_ip": args[1] + } + ] + } + elif func.__name__ == 'delete_sonic_vxlan_sonic_vxlan_vxlan_tunnel': + #keypath = [ args[0][5:] ] + keypath = [] + elif func.__name__ == 'patch_list_sonic_vxlan_sonic_vxlan_evpn_nvo_evpn_nvo_list': + keypath = [] + body = { + "sonic-vxlan:EVPN_NVO_LIST": [ + { + "name": args[0][4:], + "source_vtep": args[1] + } + ] + } + elif func.__name__ == 'delete_sonic_vxlan_sonic_vxlan_evpn_nvo': + #keypath = [ args[0][4:] ] + keypath = [] + elif func.__name__ == 'patch_list_sonic_vxlan_sonic_vxlan_vxlan_tunnel_map_vxlan_tunnel_map_list': + keypath = [] + body = { + "sonic-vxlan:VXLAN_TUNNEL_MAP_LIST": [ + { + "name": args[0][5:], + "mapname": 'map_'+ args[1] + '_' + args[2], + "vlan": 'Vlan' + args[2], + "vni": int(args[1]) + } + ] + } + elif func.__name__ == 'delete_sonic_vxlan_sonic_vxlan_vxlan_tunnel_map_vxlan_tunnel_map_list': + keypath = [ args[0][5:] , 'map_'+ args[1] + '_' + args[2]] + else: + body = {} + + return keypath,body + +def getId(item): + prfx = "Ethernet" + state_dict = item['state'] + ifName = state_dict['name'] + + if ifName.startswith(prfx): + ifId = int(ifName[len(prfx):]) + return ifId + return ifName + +def run(func, args): + + c = sonic_vxlan_client.Configuration() + c.verify_ssl = False + aa = sonic_vxlan_client.SonicVxlanApi(api_client=sonic_vxlan_client.ApiClient(configuration=c)) + + # create a body block + keypath, body = generate_body(func, args) + + try: + if body is not None: + api_response = getattr(aa,func.__name__)(*keypath, body=body) + else : + api_response = getattr(aa,func.__name__)(*keypath) + + if api_response is None: + print ("Success") + else: + # Get Command Output + api_response = aa.api_client.sanitize_for_serialization(api_response) +# if 'openconfig-interfaces:interfaces' in api_response: +# value = api_response['openconfig-interfaces:interfaces'] +# if 'interface' in value: +# tup = value['interface'] +# value['interface'] = sorted(tup, key=getId) + + if api_response is None: + print("Failed") + else: + return + + except ApiException as e: + if e.body != "": + body = json.loads(e.body) + if "ietf-restconf:errors" in body: + err = body["ietf-restconf:errors"] + if "error" in err: + errList = err["error"] + + errDict = {} + for dict in errList: + for k, v in dict.iteritems(): + errDict[k] = v + + if "error-message" in errDict: + print "%Error: " + errDict["error-message"] + return + print "%Error: Transaction Failure" + return + print "%Error: Transaction Failure" + else: + print "Failed" + +if __name__ == '__main__': + + pipestr().write(sys.argv) + func = eval(sys.argv[1], globals(), sonic_vxlan_client.SonicVxlanApi.__dict__) + + run(func, sys.argv[2:]) diff --git a/src/CLI/actioner/sonic-cli.py b/src/CLI/actioner/sonic-cli.py index f694c29db9..9665da747f 100755 --- a/src/CLI/actioner/sonic-cli.py +++ b/src/CLI/actioner/sonic-cli.py @@ -59,14 +59,17 @@ def generate_body(func, args): # Configure ACL table elif func.__name__ == 'patch_openconfig_acl_acl_acl_sets_acl_set' : - keypath = [ args[0], args[1] ] - body = { "openconfig-acl:config": { - "name": args[0], - "type": args[1], - "description": "" - } - } - + keypath = [ args[0], args[1] ] + body=collections.defaultdict(dict) + body["acl-set"]=[{ + "name": args[0], + "type": args[1], + "config": { + "name": args[0], + "type": args[1], + "description": "" + } + }] # Configure ACL rule specific to an ACL table elif func.__name__ == 'patch_list_openconfig_acl_acl_acl_sets_acl_set_acl_entries_acl_entry' : keypath = [ args[0], args[1] ] diff --git a/src/CLI/clitree/cli-xml/ptp.xml b/src/CLI/clitree/cli-xml/ptp.xml new file mode 100644 index 0000000000..fcb9905787 --- /dev/null +++ b/src/CLI/clitree/cli-xml/ptp.xml @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + if test "${ptp-subcommands}" = "time-property"; then + python $SONIC_CLI_ROOT/sonic-cli-ptp.py get_ietf_ptp_ptp_instance_list_time_properties_ds 0 ptp_tp_show.j2 + elif test "${ptp-subcommands}" = "clock"; then + python $SONIC_CLI_ROOT/sonic-cli-ptp.py get_ietf_ptp_ptp_instance_list_default_ds 0 ptp_clock_show.j2 + elif test "${ptp-subcommands}" = "parent"; then + python $SONIC_CLI_ROOT/sonic-cli-ptp.py get_ietf_ptp_ptp_instance_list_parent_ds 0 ptp_parent_show.j2 + elif test "${ptp-subcommands}" = "foreign-masters-record"; then + echo "nothing" + elif test "${ptp-subcommands}" = "port"; then + python $SONIC_CLI_ROOT/sonic-cli-ptp.py get_ietf_ptp_ptp_instance_list_port_ds_list 0 ${ptp_port_number} ptp_port_show.j2 + elif test "${ptp-subcommands}" = ""; then + python $SONIC_CLI_ROOT/sonic-cli-ptp.py get_ietf_ptp_ptp_instance_list 0 ptp_show.j2 + else + python $SONIC_CLI_ROOT/sonic-cli-ptp.py get_ietf_ptp_ptp_instance_list 0 ptp_port_show.j2 + fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + if test "${cfg-ptp-subcommands}" = "mode"; then + python $SONIC_CLI_ROOT/sonic-cli-ptp.py "clock-type" ${mode_type} + elif test "${cfg-ptp-subcommands}" = "delay-mechanism"; then + python $SONIC_CLI_ROOT/sonic-cli-ptp.py patch_ietf_ptp_ptp_transparent_clock_default_ds_delay_mechanism ${ptp_delay_mechanism_type} + elif test "${cfg-ptp-subcommands}" = "network-transport"; then + python $SONIC_CLI_ROOT/sonic-cli-ptp.py "network-transport" ${ptp_network_transport_type} + elif test "${cfg-ptp-subcommands}" = "source-ip"; then + python $SONIC_CLI_ROOT/sonic-cli-ptp.py "source-ip" ${ptp_source_ip} + elif test "${cfg-ptp-subcommands}" = "domain"; then + python $SONIC_CLI_ROOT/sonic-cli-ptp.py patch_ietf_ptp_ptp_instance_list_default_ds_domain_number 0 ${ptp_domain} + elif test "${cfg-ptp-subcommands}" = "domain-profile"; then + python $SONIC_CLI_ROOT/sonic-cli-ptp.py "domain-profile" ${ptp_domain_profile} + elif test "${cfg-ptp-subcommands}" = "two-step"; then + python $SONIC_CLI_ROOT/sonic-cli-ptp.py patch_ietf_ptp_ptp_instance_list_default_ds_two_step_flag 0 ${ptp_two_step} + elif test "${cfg-ptp-subcommands}" = "priority1"; then + python $SONIC_CLI_ROOT/sonic-cli-ptp.py patch_ietf_ptp_ptp_instance_list_default_ds_priority1 0 ${ptp_priority1} + elif test "${cfg-ptp-subcommands}" = "priority2"; then + python $SONIC_CLI_ROOT/sonic-cli-ptp.py patch_ietf_ptp_ptp_instance_list_default_ds_priority2 0 ${ptp_priority2} + elif test "${cfg-ptp-subcommands}" = "log-announce-interval"; then + python $SONIC_CLI_ROOT/sonic-cli-ptp.py "log-announce-interval" ${ptp_announce_interval} + elif test "${cfg-ptp-subcommands}" = "announce-timeout"; then + python $SONIC_CLI_ROOT/sonic-cli-ptp.py "announce-receipt-timeout" ${ptp_announce_timeout} + elif test "${cfg-ptp-subcommands}" = "log-sync-interval"; then + python $SONIC_CLI_ROOT/sonic-cli-ptp.py "log-sync-interval" ${ptp_sync_interval} + elif test "${cfg-ptp-subcommands}" = "log-min-delay-req-interval"; then + python $SONIC_CLI_ROOT/sonic-cli-ptp.py "log-min-delay-req-interval" ${ptp_delay_request_interval} + elif test "${cfg-ptp-subcommands}" = "port"; then + if test "${add}" = "add"; then + python $SONIC_CLI_ROOT/sonic-cli-ptp.py "add_port" ${Ethernet}${ptp_port_number} + elif test "${del}" = "del"; then + python $SONIC_CLI_ROOT/sonic-cli-ptp.py "del_port" ${Ethernet}${ptp_port_number} + fi + fi + + + + diff --git a/src/CLI/clitree/cli-xml/sonic_types.xml b/src/CLI/clitree/cli-xml/sonic_types.xml index 6d4f8fef01..1c011d47a4 100644 --- a/src/CLI/clitree/cli-xml/sonic_types.xml +++ b/src/CLI/clitree/cli-xml/sonic_types.xml @@ -76,6 +76,13 @@ limitations under the License. help="on|off" /> + + + + + + + + + + + + + + + + diff --git a/src/CLI/clitree/cli-xml/vxlan.xml b/src/CLI/clitree/cli-xml/vxlan.xml new file mode 100644 index 0000000000..fe44328284 --- /dev/null +++ b/src/CLI/clitree/cli-xml/vxlan.xml @@ -0,0 +1,102 @@ + + + + + + + + + + + + + + + + + + + + python $SONIC_CLI_ROOT/sonic-cli-vxlan.py delete_sonic_vxlan_sonic_vxlan_evpn_nvo ${iface} + + + + python $SONIC_CLI_ROOT/sonic-cli-vxlan.py patch_list_sonic_vxlan_sonic_vxlan_evpn_nvo_evpn_nvo_list ${iface} ${vxlan_name} + + + + + + + + + python $SONIC_CLI_ROOT/sonic-cli-vxlan.py delete_sonic_vxlan_sonic_vxlan_vxlan_tunnel ${iface} + + + + + + + + + + + + python $SONIC_CLI_ROOT/sonic-cli-vxlan.py delete_sonic_vxlan_sonic_vxlan_vxlan_tunnel_map_vxlan_tunnel_map_list ${iface} ${vnid} ${vid} + + + + + python $SONIC_CLI_ROOT/sonic-cli-vxlan.py patch_list_sonic_vxlan_sonic_vxlan_vxlan_tunnel_vxlan_tunnel_list ${iface} ${SIP} + + + + + + + + + + + + + python $SONIC_CLI_ROOT/sonic-cli-vxlan.py patch_list_sonic_vxlan_sonic_vxlan_vxlan_tunnel_map_vxlan_tunnel_map_list ${iface} ${vnid} ${vid} + + + + + diff --git a/src/CLI/klish/clish_start b/src/CLI/klish/clish_start index ddf43a7676..410b85345e 100755 --- a/src/CLI/klish/clish_start +++ b/src/CLI/klish/clish_start @@ -2,7 +2,10 @@ export SONIC_MGMT_ROOT=/usr/sbin export SONIC_CLI_ROOT=$SONIC_MGMT_ROOT/cli -export SYSTEM_NAME="${HOSTNAME%%.*}" +if [ -z $SYSTEM_NAME ] +then + export SYSTEM_NAME="${HOSTNAME%%.*}" +fi export PYTHONPATH=$SONIC_MGMT_ROOT:$SONIC_MGMT_ROOT/lib/swagger_client_py:$SONIC_CLI_ROOT:$SONIC_CLI_ROOT/scripts:$PYTHONPATH export CLISH_PATH=$SONIC_CLI_ROOT/command-tree export LD_LIBRARY_PATH=/usr/local/lib:$SONIC_CLI_ROOT/.libs:$LD_LIBRARY_PATH diff --git a/src/CLI/renderer/templates/ptp_clock_show.j2 b/src/CLI/renderer/templates/ptp_clock_show.j2 new file mode 100755 index 0000000000..2371fee3bd --- /dev/null +++ b/src/CLI/renderer/templates/ptp_clock_show.j2 @@ -0,0 +1,35 @@ +{{'-----------------------------------------------------------'}} +{{'Attribute'.ljust(21)}} {{'Value/State'}} +{{'-----------------------------------------------------------'}} +{% for key,value in json_output.items() %} +{% if 'domain-number' in value.keys() %} +{{ 'Domain Number'.ljust(21)}} {{ value['domain-number']}} +{% endif %} +{% if 'priority1' in value.keys() %} +{{ 'Priority1'.ljust(21)}} {{ value['priority1']}} +{% endif %} +{% if 'priority2' in value.keys() %} +{{ 'Priority2'.ljust(21)}} {{ value['priority2']}} +{% endif %} +{% if 'two-step-flag' in value.keys() %} +{{ 'Two Step'.ljust(21)}} {{ value['two-step-flag']}} +{% endif %} +{% if 'slave-only' in value.keys() %} +{{ 'Slave Only'.ljust(21)}} {{ value['slave-only']}} +{% endif %} +{% if 'number-ports' in value.keys() %} +{{ 'Number Ports'.ljust(21)}} {{ value['number-ports']}} +{% endif %} +{% if 'clock-quality' in value.keys() %} +{{ 'Clock Quality:'.ljust(21)}} +{% if 'clock-class' in value['clock-quality'].keys() %} +{{ ' Clock Class'.ljust(21)}} {{ value['clock-quality']['clock-class']}} +{% endif %} +{% if 'clock-accuracy' in value['clock-quality'].keys() %} +{{ ' Clock Accuracy'.ljust(21)}} {{ value['clock-quality']['clock-accuracy']}} +{% endif %} +{% if 'offset-scaled-log-variance' in value['clock-quality'].keys() %} +{{ ' Ofst Scaled Log Var'.ljust(21)}} {{ value['clock-quality']['offset-scaled-log-variance']}} +{% endif %} +{% endif %} +{% endfor %} diff --git a/src/CLI/renderer/templates/ptp_parent_show.j2 b/src/CLI/renderer/templates/ptp_parent_show.j2 new file mode 100755 index 0000000000..228eec87fb --- /dev/null +++ b/src/CLI/renderer/templates/ptp_parent_show.j2 @@ -0,0 +1,24 @@ +{{'-----------------------------------------------------------'}} +{{'Attribute'.ljust(30)}} {{'Value/State'}} +{{'-----------------------------------------------------------'}} +{% for key,value in json_output.items() %} +{% if 'grandmaster-identity' in value.keys() %} +{{ 'Grandmaster Identity'.ljust(30)}} {{ value['grandmaster-identity']}} +{% endif %} +{% if 'grandmaster-priority1' in value.keys() %} +{{ 'Grandmaster Priority1'.ljust(30)}} {{ value['grandmaster-priority1']}} +{% endif %} +{% if 'grandmaster-priority2' in value.keys() %} +{{ 'Grandmaster Priority2'.ljust(30)}} {{ value['grandmaster-priority2']}} +{% endif %} +{% if 'parent-stats' in value.keys() %} +{{ 'Stats Valid'.ljust(30)}} {{ value['parent-stats']}} +{% endif %} +{% if 'observed-parent-offset-scaled-log-variance' in value.keys() %} +{{ 'Observed Off Scaled Log Var'.ljust(30)}} {{ value['observed-parent-offset-scaled-log-variance']}} +{% endif %} +{% if 'observed-parent-clock-phase-change-rate' in value.keys() %} +{{ 'Observed Clock Phase Chg Rate'.ljust(30)}} {{ value['observed-parent-clock-phase-change-rate']}} +{% endif %} +{% endfor %} + diff --git a/src/CLI/renderer/templates/ptp_port_show.j2 b/src/CLI/renderer/templates/ptp_port_show.j2 new file mode 100755 index 0000000000..c19afaadf9 --- /dev/null +++ b/src/CLI/renderer/templates/ptp_port_show.j2 @@ -0,0 +1,23 @@ +{{'-----------------------------------------------------------'}} +{{'Attribute'.ljust(30)}} {{'Value/State'}} +{{'-----------------------------------------------------------'}} +{% for key,value in json_output.items() %} +{% for key2,value2 in value.items() %} +{% if 'port-number' in value2.keys() %} +{{ 'Port Number'.ljust(30)}} {{ value2['port-number']}} +{% endif %} +{% if 'port-state' in value2.keys() %} +{{ 'Port State'.ljust(30)}} {{ value2['port-state']}} +{% endif %} +{% if 'log-min-pdelay-req-interval' in value2.keys() %} +{{ 'Log Min Pdelay Req Intvl'.ljust(30)}} {{ value2['log-min-pdelay-req-interval']}} +{% endif %} +{% if 'log-min-delay-req-interval' in value2.keys() %} +{{ 'Log Min delay Req Intvl'.ljust(30)}} {{ value2['log-min-delay-req-interval']}} +{% endif %} +{% if 'peer-mean-path-delay' in value2.keys() %} +{{ 'Peer Mean Path delay'.ljust(30)}} {{ value2['peer-mean-path-delay']}} +{% endif %} +{% endfor %} +{% endfor %} + diff --git a/src/CLI/renderer/templates/ptp_show.j2 b/src/CLI/renderer/templates/ptp_show.j2 new file mode 100755 index 0000000000..5fb4d8803b --- /dev/null +++ b/src/CLI/renderer/templates/ptp_show.j2 @@ -0,0 +1,19 @@ +{{'-----------------------------------------------------------'}} +{{'Interface'.ljust(20)}} {{'State'}} +{{'-----------------------------------------------------------'}} +{% for key,value in json_output.items() %} +{% for i in value %} + +{% for key2,value2 in i.items() %} +{% for i2 in value2 %} + +{% if 'port-number' in i2.keys() and 'port-state' in i2.keys() %} +{{ i2['port-number'].ljust(20)}}{{ i2['port-state']}} +{% endif %} + +{% endfor %} +{% endfor %} + +{% endfor %} +{% endfor %} + diff --git a/src/CLI/renderer/templates/ptp_tp_show.j2 b/src/CLI/renderer/templates/ptp_tp_show.j2 new file mode 100755 index 0000000000..12013673b5 --- /dev/null +++ b/src/CLI/renderer/templates/ptp_tp_show.j2 @@ -0,0 +1,30 @@ +{{'-----------------------------------------------------------'}} +{{'Attribute'.ljust(20)}} {{'Value/State'}} +{{'-----------------------------------------------------------'}} +{% for key,value in json_output.items() %} +{% if 'current-utc-offset-valid' in value.keys() %} +{{ 'Curr UTC Offset Vld'.ljust(20)}} {{ value['current-utc-offset-valid']}} +{% endif %} +{% if 'current-utc-offset' in value.keys() %} +{{ 'Curr UTC Offset'.ljust(20)}} {{ value['current-utc-offset']}} +{% endif %} +{% if 'leap59' in value.keys() %} +{{ 'Leap59'.ljust(20)}} {{ value['leap59']}} +{% endif %} +{% if 'leap61' in value.keys() %} +{{ 'Leap61'.ljust(20)}} {{ value['leap61']}} +{% endif %} +{% if 'time-traceable' in value.keys() %} +{{ 'Time Traceable'.ljust(20)}} {{ value['time-traceable']}} +{% endif %} +{% if 'frequency-traceable' in value.keys() %} +{{ 'Freq Traceable'.ljust(20)}} {{ value['frequency-traceable']}} +{% endif %} +{% if 'ptp-timescale' in value.keys() %} +{{ 'PTP Timescale'.ljust(20)}} {{ value['ptp-timescale']}} +{% endif %} +{% if 'time-source' in value.keys() %} +{{ 'Time Source'.ljust(20)}} {{ value['time-source']}} +{% endif %} +{% endfor %} + diff --git a/src/cvl/schema/sonic-mgmt-interface.yang b/src/cvl/schema/sonic-mgmt-interface.yang new file mode 100644 index 0000000000..0095b9f6b4 --- /dev/null +++ b/src/cvl/schema/sonic-mgmt-interface.yang @@ -0,0 +1,55 @@ +module sonic-mgmt-interface { + namespace "http://github.com/Azure/sonic-mgmt-interface"; + prefix sint; + + import ietf-yang-types { + prefix yang; + } + + import ietf-inet-types { + prefix inet; + } + + import sonic-common { + prefix scommon; + } + + import sonic-mgmt-port { + prefix mgmtprt; + } + + organization + "DELL"; + + contact + "DELL"; + + description + "SONIC MANAGEMENT INTERFACE"; + + revision 2019-07-02 { + description + "Initial revision."; + } + + container sonic-mgmt-interface { + list MGMT_INTERFACE { + key "portname ip_prefix"; + + leaf portname{ + type leafref { + path "/mgmtprt:sonic-mgmt-port/mgmtprt:MGMT_PORT/mgmtprt:ifname"; + } + } + + leaf ip_prefix { + mandatory true; + type inet:ip-prefix; + + } + leaf gwaddr { + type inet:ip-prefix; + } + } + } +} diff --git a/src/cvl/schema/sonic-mgmt-port.yang b/src/cvl/schema/sonic-mgmt-port.yang new file mode 100644 index 0000000000..dec56e1e78 --- /dev/null +++ b/src/cvl/schema/sonic-mgmt-port.yang @@ -0,0 +1,66 @@ +module sonic-mgmt-port { + namespace "http://github.com/Azure/sonic-mgmt-port"; + prefix prt; + + import ietf-yang-types { + prefix yang; + } + + import sonic-common { + prefix scommon; + } + + organization + "DELL"; + + contact + "DELL"; + + description + "SONIC Management Interface"; + + revision 2019-09-17 { + description + "Initial revision."; + } + + + container sonic-mgmt-port { + list MGMT_PORT { + key "ifname"; + + leaf ifname { + type string { + pattern "eth([1-3][0-9]{3}|[1-9][0-9]{2}|[1-9][0-9]|[0-9])"{ + error-message "Invalid interface name"; + error-app-tag interface-name-invalid; + } + } + } + + leaf speed { + type uint64; + } + + leaf autoneg { + type boolean; + } + + leaf alias { + type string; + } + + leaf description { + type string; + } + + leaf mtu{ + type uint32; + } + + leaf admin_status { + type scommon:admin-status; + } + } + } +} diff --git a/src/cvl/testdata/schema/sonic-spanning-tree.yang b/src/cvl/testdata/schema/sonic-spanning-tree.yang index 2ff9f5e8c6..b8633a4991 100755 --- a/src/cvl/testdata/schema/sonic-spanning-tree.yang +++ b/src/cvl/testdata/schema/sonic-spanning-tree.yang @@ -15,8 +15,8 @@ module sonic-spanning-tree { prefix spc; } - import sonic-pf-limits { - prefix spf; + import sonic-vlan { + prefix svlan; } organization @@ -33,17 +33,6 @@ module sonic-spanning-tree { "Initial revision."; } - typedef interface-type { - type union { - type leafref { - path "/prt:sonic-port/prt:PORT/prt:ifname"; - } - type leafref { - path "/spc:sonic-portchannel/spc:PORTCHANNEL/spc:name"; - } - } - } - grouping vlanModeAttr { leaf forward_delay { type uint8 { @@ -108,7 +97,6 @@ module sonic-spanning-tree { container sonic-spanning-tree { - /* container STP { list STP_LIST { key "keyleaf"; @@ -150,11 +138,8 @@ module sonic-spanning-tree { } leaf name { - type string { - pattern "Vlan(409[0-5]|40[0-8][0-9]|[1-3][0-9]{3}|[1-9][0-9]{2}|[1-9][0-9]|[1-9])" { - error-message "Invalid Vlan name pattern"; - error-app-tag vlan-name-invalid; - } + type leafref { + path "/svlan:sonic-vlan/svlan:VLAN/svlan:VLAN_LIST/svlan:name"; } } @@ -187,7 +172,9 @@ module sonic-spanning-tree { } leaf ifname { - type interface-type; + type leafref { + path "../../../STP_INTF/STP_INTF_LIST/ifname"; + } } uses interfaceAttr; @@ -199,7 +186,14 @@ module sonic-spanning-tree { key "ifname"; leaf ifname { - type interface-type; + type union { + type leafref { + path "/prt:sonic-port/prt:PORT/prt:PORT_LIST/prt:ifname"; + } + type leafref { + path "/spc:sonic-portchannel/spc:PORTCHANNEL/spc:PORTCHANNEL_LIST/spc:name"; + } + } } leaf enabled { @@ -214,6 +208,10 @@ module sonic-spanning-tree { type boolean; } + leaf bpdu_filter { + type boolean; + } + leaf bpdu_guard_do_disable { type boolean; } @@ -240,142 +238,5 @@ module sonic-spanning-tree { } } } - */ - - list STP { - key "keyleaf"; - - leaf keyleaf { - type enumeration { - enum GLOBAL; - } - } - - leaf mode { - type enumeration { - enum pvst; - enum rpvst; - enum mstp; - enum rstp; - } - } - - leaf rootguard_timeout { - type uint16 { - range "5..600" { - error-message "Invalid Root-guard Timeout value."; - } - } - units seconds; - default 30; - } - - uses vlanModeAttr; - } - - list STP_VLAN { - key "name"; - /*must "./name = concat('Vlan', string(./vlanid))" { - error-app-tag vlan-invalid; - }*/ - - leaf name { - type string { - pattern "Vlan(409[0-5]|40[0-8][0-9]|[1-3][0-9]{3}|[1-9][0-9]{2}|[1-9][0-9]|[1-9])" { - error-message "Invalid Vlan name pattern"; - error-app-tag vlan-name-invalid; - } - } - } - - leaf vlanid { - mandatory true; - type uint16 { - range "1..4095" { - error-message "Vlan ID out of range"; - error-app-tag vlanid-invalid; - } - } - } - - leaf enabled { - type boolean; - } - - uses vlanModeAttr; - } - - list STP_INTF { - key "ifname"; - - leaf ifname { - type string; - //type interface-type; - } - - leaf enabled { - type boolean; - } - - leaf root_guard { - type boolean; - } - - leaf bpdu_guard { - type boolean; - } - - leaf bpdu_filter { - type boolean; - } - - leaf bpdu_guard_do_disable { - type boolean; - } - - leaf uplink_fast { - type boolean; - } - - leaf portfast { - type boolean; - } - - uses interfaceAttr; - - // For RPVST+ - leaf edge_port { - //when ("../../STP/mode='rpvst'"); - type boolean; - } - - leaf pt2pt_mac { - //when ("../../STP/mode='rpvst'"); - type boolean; - } - } - - list STP_VLAN_INTF { - key "vlan-name ifname"; - - leaf vlan-name { - /*type leafref { - path "../../STP_VLAN/name"; - }*/ - type string { - pattern "Vlan(409[0-5]|40[0-8][0-9]|[1-3][0-9]{3}|[1-9][0-9]{2}|[1-9][0-9]|[1-9])" { - error-message "Invalid Vlan name pattern"; - error-app-tag vlan-name-invalid; - } - } - } - - leaf ifname { - type string; - //type interface-type; - } - - uses interfaceAttr; - } } } diff --git a/src/rest/Makefile b/src/rest/Makefile index f4f4d335d7..0eb6901f44 100644 --- a/src/rest/Makefile +++ b/src/rest/Makefile @@ -36,6 +36,7 @@ REST_TEST_SRCS = $(shell find . -name '*_test.go') # Source files affecting REST server REST_SRCS := $(ALL_GO_SRCS) \ $(shell find $(TOPDIR)/models/yang -name '*.yang' | sort) \ + $(shell find $(TOPDIR)/src/cvl/schema '*.yang' | sort) \ $(shell find $(TOPDIR)/models/openapi -name '*.yaml' | sort) REST_GOPATH := $(GOPATH):$(abspath $(REST_BUILD_DIR)/dist) diff --git a/src/translib/acl_app_test.go b/src/translib/acl_app_test.go index d1773866ac..ee81023070 100644 --- a/src/translib/acl_app_test.go +++ b/src/translib/acl_app_test.go @@ -501,7 +501,7 @@ var bulkAclCreateJsonRequest string = "{\"acl-sets\":{\"acl-set\":[{\"name\":\"M var bulkAclCreateJsonResponse string = "{\"openconfig-acl:acl\":{\"acl-sets\":{\"acl-set\":[{\"acl-entries\":{\"acl-entry\":[{\"actions\":{\"config\":{\"forwarding-action\":\"openconfig-acl:ACCEPT\"},\"state\":{\"forwarding-action\":\"openconfig-acl:ACCEPT\"}},\"config\":{\"sequence-id\":1},\"ipv4\":{\"config\":{\"destination-address\":\"21.1.1.1/32\",\"dscp\":1,\"protocol\":\"openconfig-packet-match-types:IP_TCP\",\"source-address\":\"11.1.1.1/32\"},\"state\":{\"destination-address\":\"21.1.1.1/32\",\"dscp\":1,\"protocol\":\"openconfig-packet-match-types:IP_TCP\",\"source-address\":\"11.1.1.1/32\"}},\"sequence-id\":1,\"state\":{\"matched-octets\":\"0\",\"matched-packets\":\"0\",\"sequence-id\":1},\"transport\":{\"config\":{\"destination-port\":201,\"source-port\":101},\"state\":{\"destination-port\":201,\"source-port\":101}}},{\"actions\":{\"config\":{\"forwarding-action\":\"openconfig-acl:DROP\"},\"state\":{\"forwarding-action\":\"openconfig-acl:DROP\"}},\"config\":{\"sequence-id\":2},\"ipv4\":{\"config\":{\"destination-address\":\"21.1.1.2/32\",\"dscp\":2,\"protocol\":\"openconfig-packet-match-types:IP_TCP\",\"source-address\":\"11.1.1.2/32\"},\"state\":{\"destination-address\":\"21.1.1.2/32\",\"dscp\":2,\"protocol\":\"openconfig-packet-match-types:IP_TCP\",\"source-address\":\"11.1.1.2/32\"}},\"sequence-id\":2,\"state\":{\"matched-octets\":\"0\",\"matched-packets\":\"0\",\"sequence-id\":2},\"transport\":{\"config\":{\"destination-port\":202,\"source-port\":102},\"state\":{\"destination-port\":202,\"source-port\":102}}},{\"actions\":{\"config\":{\"forwarding-action\":\"openconfig-acl:ACCEPT\"},\"state\":{\"forwarding-action\":\"openconfig-acl:ACCEPT\"}},\"config\":{\"sequence-id\":3},\"ipv4\":{\"config\":{\"destination-address\":\"21.1.1.3/32\",\"dscp\":3,\"protocol\":\"openconfig-packet-match-types:IP_TCP\",\"source-address\":\"11.1.1.3/32\"},\"state\":{\"destination-address\":\"21.1.1.3/32\",\"dscp\":3,\"protocol\":\"openconfig-packet-match-types:IP_TCP\",\"source-address\":\"11.1.1.3/32\"}},\"sequence-id\":3,\"state\":{\"matched-octets\":\"0\",\"matched-packets\":\"0\",\"sequence-id\":3},\"transport\":{\"config\":{\"destination-port\":203,\"source-port\":103},\"state\":{\"destination-port\":203,\"source-port\":103}}},{\"actions\":{\"config\":{\"forwarding-action\":\"openconfig-acl:DROP\"},\"state\":{\"forwarding-action\":\"openconfig-acl:DROP\"}},\"config\":{\"sequence-id\":4},\"ipv4\":{\"config\":{\"destination-address\":\"21.1.1.4/32\",\"dscp\":4,\"protocol\":\"openconfig-packet-match-types:IP_TCP\",\"source-address\":\"11.1.1.4/32\"},\"state\":{\"destination-address\":\"21.1.1.4/32\",\"dscp\":4,\"protocol\":\"openconfig-packet-match-types:IP_TCP\",\"source-address\":\"11.1.1.4/32\"}},\"sequence-id\":4,\"state\":{\"matched-octets\":\"0\",\"matched-packets\":\"0\",\"sequence-id\":4},\"transport\":{\"config\":{\"destination-port\":204,\"source-port\":104},\"state\":{\"destination-port\":204,\"source-port\":104}}},{\"actions\":{\"config\":{\"forwarding-action\":\"openconfig-acl:ACCEPT\"},\"state\":{\"forwarding-action\":\"openconfig-acl:ACCEPT\"}},\"config\":{\"sequence-id\":5},\"ipv4\":{\"config\":{\"destination-address\":\"21.1.1.5/32\",\"dscp\":5,\"protocol\":\"openconfig-packet-match-types:IP_TCP\",\"source-address\":\"11.1.1.5/32\"},\"state\":{\"destination-address\":\"21.1.1.5/32\",\"dscp\":5,\"protocol\":\"openconfig-packet-match-types:IP_TCP\",\"source-address\":\"11.1.1.5/32\"}},\"sequence-id\":5,\"state\":{\"matched-octets\":\"0\",\"matched-packets\":\"0\",\"sequence-id\":5},\"transport\":{\"config\":{\"destination-port\":205,\"source-port\":105},\"state\":{\"destination-port\":205,\"source-port\":105}}}]},\"config\":{\"description\":\"Description for MyACL1\",\"name\":\"MyACL1\",\"type\":\"openconfig-acl:ACL_IPV4\"},\"name\":\"MyACL1\",\"state\":{\"description\":\"Description for MyACL1\",\"name\":\"MyACL1\",\"type\":\"openconfig-acl:ACL_IPV4\"},\"type\":\"openconfig-acl:ACL_IPV4\"},{\"acl-entries\":{\"acl-entry\":[{\"actions\":{\"config\":{\"forwarding-action\":\"openconfig-acl:ACCEPT\"},\"state\":{\"forwarding-action\":\"openconfig-acl:ACCEPT\"}},\"config\":{\"sequence-id\":1},\"ipv4\":{\"config\":{\"destination-address\":\"22.1.1.1/32\",\"dscp\":1,\"protocol\":\"openconfig-packet-match-types:IP_TCP\",\"source-address\":\"12.1.1.1/32\"},\"state\":{\"destination-address\":\"22.1.1.1/32\",\"dscp\":1,\"protocol\":\"openconfig-packet-match-types:IP_TCP\",\"source-address\":\"12.1.1.1/32\"}},\"sequence-id\":1,\"state\":{\"matched-octets\":\"0\",\"matched-packets\":\"0\",\"sequence-id\":1},\"transport\":{\"config\":{\"destination-port\":201,\"source-port\":101},\"state\":{\"destination-port\":201,\"source-port\":101}}},{\"actions\":{\"config\":{\"forwarding-action\":\"openconfig-acl:ACCEPT\"},\"state\":{\"forwarding-action\":\"openconfig-acl:ACCEPT\"}},\"config\":{\"sequence-id\":2},\"ipv4\":{\"config\":{\"destination-address\":\"22.1.1.2/32\",\"dscp\":2,\"protocol\":\"openconfig-packet-match-types:IP_TCP\",\"source-address\":\"12.1.1.2/32\"},\"state\":{\"destination-address\":\"22.1.1.2/32\",\"dscp\":2,\"protocol\":\"openconfig-packet-match-types:IP_TCP\",\"source-address\":\"12.1.1.2/32\"}},\"sequence-id\":2,\"state\":{\"matched-octets\":\"0\",\"matched-packets\":\"0\",\"sequence-id\":2},\"transport\":{\"config\":{\"destination-port\":202,\"source-port\":102},\"state\":{\"destination-port\":202,\"source-port\":102}}},{\"actions\":{\"config\":{\"forwarding-action\":\"openconfig-acl:ACCEPT\"},\"state\":{\"forwarding-action\":\"openconfig-acl:ACCEPT\"}},\"config\":{\"sequence-id\":3},\"ipv4\":{\"config\":{\"destination-address\":\"22.1.1.3/32\",\"dscp\":3,\"protocol\":\"openconfig-packet-match-types:IP_TCP\",\"source-address\":\"12.1.1.3/32\"},\"state\":{\"destination-address\":\"22.1.1.3/32\",\"dscp\":3,\"protocol\":\"openconfig-packet-match-types:IP_TCP\",\"source-address\":\"12.1.1.3/32\"}},\"sequence-id\":3,\"state\":{\"matched-octets\":\"0\",\"matched-packets\":\"0\",\"sequence-id\":3},\"transport\":{\"config\":{\"destination-port\":203,\"source-port\":103},\"state\":{\"destination-port\":203,\"source-port\":103}}},{\"actions\":{\"config\":{\"forwarding-action\":\"openconfig-acl:ACCEPT\"},\"state\":{\"forwarding-action\":\"openconfig-acl:ACCEPT\"}},\"config\":{\"sequence-id\":4},\"ipv4\":{\"config\":{\"destination-address\":\"22.1.1.4/32\",\"dscp\":4,\"protocol\":\"openconfig-packet-match-types:IP_TCP\",\"source-address\":\"12.1.1.4/32\"},\"state\":{\"destination-address\":\"22.1.1.4/32\",\"dscp\":4,\"protocol\":\"openconfig-packet-match-types:IP_TCP\",\"source-address\":\"12.1.1.4/32\"}},\"sequence-id\":4,\"state\":{\"matched-octets\":\"0\",\"matched-packets\":\"0\",\"sequence-id\":4},\"transport\":{\"config\":{\"destination-port\":204,\"source-port\":104},\"state\":{\"destination-port\":204,\"source-port\":104}}},{\"actions\":{\"config\":{\"forwarding-action\":\"openconfig-acl:ACCEPT\"},\"state\":{\"forwarding-action\":\"openconfig-acl:ACCEPT\"}},\"config\":{\"sequence-id\":5},\"ipv4\":{\"config\":{\"destination-address\":\"22.1.1.5/32\",\"dscp\":5,\"protocol\":\"openconfig-packet-match-types:IP_TCP\",\"source-address\":\"12.1.1.5/32\"},\"state\":{\"destination-address\":\"22.1.1.5/32\",\"dscp\":5,\"protocol\":\"openconfig-packet-match-types:IP_TCP\",\"source-address\":\"12.1.1.5/32\"}},\"sequence-id\":5,\"state\":{\"matched-octets\":\"0\",\"matched-packets\":\"0\",\"sequence-id\":5},\"transport\":{\"config\":{\"destination-port\":205,\"source-port\":105},\"state\":{\"destination-port\":205,\"source-port\":105}}}]},\"config\":{\"description\":\"Description for MyACL2\",\"name\":\"MyACL2\",\"type\":\"openconfig-acl:ACL_IPV4\"},\"name\":\"MyACL2\",\"state\":{\"description\":\"Description for MyACL2\",\"name\":\"MyACL2\",\"type\":\"openconfig-acl:ACL_IPV4\"},\"type\":\"openconfig-acl:ACL_IPV4\"}]},\"interfaces\":{\"interface\":[{\"config\":{\"id\":\"Ethernet0\"},\"id\":\"Ethernet0\",\"ingress-acl-sets\":{\"ingress-acl-set\":[{\"acl-entries\":{\"acl-entry\":[{\"sequence-id\":1,\"state\":{\"matched-octets\":\"0\",\"matched-packets\":\"0\",\"sequence-id\":1}},{\"sequence-id\":2,\"state\":{\"matched-octets\":\"0\",\"matched-packets\":\"0\",\"sequence-id\":2}},{\"sequence-id\":3,\"state\":{\"matched-octets\":\"0\",\"matched-packets\":\"0\",\"sequence-id\":3}},{\"sequence-id\":4,\"state\":{\"matched-octets\":\"0\",\"matched-packets\":\"0\",\"sequence-id\":4}},{\"sequence-id\":5,\"state\":{\"matched-octets\":\"0\",\"matched-packets\":\"0\",\"sequence-id\":5}}]},\"config\":{\"set-name\":\"MyACL1\",\"type\":\"openconfig-acl:ACL_IPV4\"},\"set-name\":\"MyACL1\",\"state\":{\"set-name\":\"MyACL1\",\"type\":\"openconfig-acl:ACL_IPV4\"},\"type\":\"openconfig-acl:ACL_IPV4\"}]},\"state\":{\"id\":\"Ethernet0\"}},{\"config\":{\"id\":\"Ethernet4\"},\"id\":\"Ethernet4\",\"ingress-acl-sets\":{\"ingress-acl-set\":[{\"acl-entries\":{\"acl-entry\":[{\"sequence-id\":1,\"state\":{\"matched-octets\":\"0\",\"matched-packets\":\"0\",\"sequence-id\":1}},{\"sequence-id\":2,\"state\":{\"matched-octets\":\"0\",\"matched-packets\":\"0\",\"sequence-id\":2}},{\"sequence-id\":3,\"state\":{\"matched-octets\":\"0\",\"matched-packets\":\"0\",\"sequence-id\":3}},{\"sequence-id\":4,\"state\":{\"matched-octets\":\"0\",\"matched-packets\":\"0\",\"sequence-id\":4}},{\"sequence-id\":5,\"state\":{\"matched-octets\":\"0\",\"matched-packets\":\"0\",\"sequence-id\":5}}]},\"config\":{\"set-name\":\"MyACL2\",\"type\":\"openconfig-acl:ACL_IPV4\"},\"set-name\":\"MyACL2\",\"state\":{\"set-name\":\"MyACL2\",\"type\":\"openconfig-acl:ACL_IPV4\"},\"type\":\"openconfig-acl:ACL_IPV4\"}]},\"state\":{\"id\":\"Ethernet4\"}}]}}}" -var oneAclCreateWithRulesJsonRequest string = "{ \"name\": \"MyACL3\", \"type\": \"ACL_IPV4\", \"config\": { \"name\": \"MyACL3\", \"type\": \"ACL_IPV4\", \"description\": \"Description for MyACL3\" }, \"acl-entries\": { \"acl-entry\": [ { \"sequence-id\": 1, \"config\": { \"sequence-id\": 1, \"description\": \"Description for MyACL3 Rule Seq 1\" }, \"ipv4\": { \"config\": { \"source-address\": \"11.1.1.1/32\", \"destination-address\": \"21.1.1.1/32\", \"dscp\": 1, \"protocol\": \"IP_TCP\" } }, \"transport\": { \"config\": { \"source-port\": 101, \"destination-port\": 201 } }, \"actions\": { \"config\": { \"forwarding-action\": \"ACCEPT\" } } }, { \"sequence-id\": 2, \"config\": { \"sequence-id\": 2, \"description\": \"Description for MyACL3 Rule Seq 2\" }, \"ipv4\": { \"config\": { \"source-address\": \"11.1.1.2/32\", \"destination-address\": \"21.1.1.2/32\", \"dscp\": 2, \"protocol\": \"IP_UDP\" } }, \"transport\": { \"config\": { \"source-port\": 102, \"destination-port\": 202 } }, \"actions\": { \"config\": { \"forwarding-action\": \"DROP\" } } }, { \"sequence-id\": 3, \"config\": { \"sequence-id\": 3, \"description\": \"Description for MyACL3 Rule Seq 3\" }, \"ipv4\": { \"config\": { \"source-address\": \"11.1.1.3/32\", \"destination-address\": \"21.1.1.3/32\", \"dscp\": 3, \"protocol\": \"IP_TCP\" } }, \"transport\": { \"config\": { \"source-port\": 103, \"destination-port\": 203 } }, \"actions\": { \"config\": { \"forwarding-action\": \"ACCEPT\" } } }, { \"sequence-id\": 4, \"config\": { \"sequence-id\": 4, \"description\": \"Description for MyACL3 Rule Seq 4\" }, \"ipv4\": { \"config\": { \"source-address\": \"11.1.1.4/32\", \"destination-address\": \"21.1.1.4/32\", \"dscp\": 4, \"protocol\": \"IP_TCP\" } }, \"transport\": { \"config\": { \"source-port\": 104, \"destination-port\": 204 } }, \"actions\": { \"config\": { \"forwarding-action\": \"DROP\" } } }, { \"sequence-id\": 5, \"config\": { \"sequence-id\": 5, \"description\": \"Description for MyACL3 Rule Seq 5\" }, \"ipv4\": { \"config\": { \"source-address\": \"11.1.1.5/32\", \"destination-address\": \"21.1.1.5/32\", \"dscp\": 5, \"protocol\": \"IP_TCP\" } }, \"transport\": { \"config\": { \"source-port\": 105, \"destination-port\": 205 } }, \"actions\": { \"config\": { \"forwarding-action\": \"ACCEPT\" } } } ] }}" +var oneAclCreateWithRulesJsonRequest string = "{ \"openconfig-acl:acl-set\": [ { \"name\": \"MyACL3\", \"type\": \"ACL_IPV4\", \"config\": { \"name\": \"MyACL3\", \"type\": \"ACL_IPV4\", \"description\": \"Description for MyACL3\" }, \"acl-entries\": { \"acl-entry\": [ { \"sequence-id\": 1, \"config\": { \"sequence-id\": 1, \"description\": \"Description for MyACL3 Rule Seq 1\" }, \"ipv4\": { \"config\": { \"source-address\": \"11.1.1.1/32\", \"destination-address\": \"21.1.1.1/32\", \"dscp\": 1, \"protocol\": \"IP_TCP\" } }, \"transport\": { \"config\": { \"source-port\": 101, \"destination-port\": 201 } }, \"actions\": { \"config\": { \"forwarding-action\": \"ACCEPT\" } } }, { \"sequence-id\": 2, \"config\": { \"sequence-id\": 2, \"description\": \"Description for MyACL3 Rule Seq 2\" }, \"ipv4\": { \"config\": { \"source-address\": \"11.1.1.2/32\", \"destination-address\": \"21.1.1.2/32\", \"dscp\": 2, \"protocol\": \"IP_UDP\" } }, \"transport\": { \"config\": { \"source-port\": 102, \"destination-port\": 202 } }, \"actions\": { \"config\": { \"forwarding-action\": \"DROP\" } } }, { \"sequence-id\": 3, \"config\": { \"sequence-id\": 3, \"description\": \"Description for MyACL3 Rule Seq 3\" }, \"ipv4\": { \"config\": { \"source-address\": \"11.1.1.3/32\", \"destination-address\": \"21.1.1.3/32\", \"dscp\": 3, \"protocol\": \"IP_TCP\" } }, \"transport\": { \"config\": { \"source-port\": 103, \"destination-port\": 203 } }, \"actions\": { \"config\": { \"forwarding-action\": \"ACCEPT\" } } }, { \"sequence-id\": 4, \"config\": { \"sequence-id\": 4, \"description\": \"Description for MyACL3 Rule Seq 4\" }, \"ipv4\": { \"config\": { \"source-address\": \"11.1.1.4/32\", \"destination-address\": \"21.1.1.4/32\", \"dscp\": 4, \"protocol\": \"IP_TCP\" } }, \"transport\": { \"config\": { \"source-port\": 104, \"destination-port\": 204 } }, \"actions\": { \"config\": { \"forwarding-action\": \"DROP\" } } }, { \"sequence-id\": 5, \"config\": { \"sequence-id\": 5, \"description\": \"Description for MyACL3 Rule Seq 5\" }, \"ipv4\": { \"config\": { \"source-address\": \"11.1.1.5/32\", \"destination-address\": \"21.1.1.5/32\", \"dscp\": 5, \"protocol\": \"IP_TCP\" } }, \"transport\": { \"config\": { \"source-port\": 105, \"destination-port\": 205 } }, \"actions\": { \"config\": { \"forwarding-action\": \"ACCEPT\" } } } ] }} ] }" var oneAclCreateWithRulesJsonResponse string = "{\"openconfig-acl:acl-set\":[{\"acl-entries\":{\"acl-entry\":[{\"actions\":{\"config\":{\"forwarding-action\":\"openconfig-acl:ACCEPT\"},\"state\":{\"forwarding-action\":\"openconfig-acl:ACCEPT\"}},\"config\":{\"sequence-id\":1},\"ipv4\":{\"config\":{\"destination-address\":\"21.1.1.1/32\",\"dscp\":1,\"protocol\":\"openconfig-packet-match-types:IP_TCP\",\"source-address\":\"11.1.1.1/32\"},\"state\":{\"destination-address\":\"21.1.1.1/32\",\"dscp\":1,\"protocol\":\"openconfig-packet-match-types:IP_TCP\",\"source-address\":\"11.1.1.1/32\"}},\"sequence-id\":1,\"state\":{\"matched-octets\":\"0\",\"matched-packets\":\"0\",\"sequence-id\":1},\"transport\":{\"config\":{\"destination-port\":201,\"source-port\":101},\"state\":{\"destination-port\":201,\"source-port\":101}}},{\"actions\":{\"config\":{\"forwarding-action\":\"openconfig-acl:DROP\"},\"state\":{\"forwarding-action\":\"openconfig-acl:DROP\"}},\"config\":{\"sequence-id\":2},\"ipv4\":{\"config\":{\"destination-address\":\"21.1.1.2/32\",\"dscp\":2,\"protocol\":\"openconfig-packet-match-types:IP_UDP\",\"source-address\":\"11.1.1.2/32\"},\"state\":{\"destination-address\":\"21.1.1.2/32\",\"dscp\":2,\"protocol\":\"openconfig-packet-match-types:IP_UDP\",\"source-address\":\"11.1.1.2/32\"}},\"sequence-id\":2,\"state\":{\"matched-octets\":\"0\",\"matched-packets\":\"0\",\"sequence-id\":2},\"transport\":{\"config\":{\"destination-port\":202,\"source-port\":102},\"state\":{\"destination-port\":202,\"source-port\":102}}},{\"actions\":{\"config\":{\"forwarding-action\":\"openconfig-acl:ACCEPT\"},\"state\":{\"forwarding-action\":\"openconfig-acl:ACCEPT\"}},\"config\":{\"sequence-id\":3},\"ipv4\":{\"config\":{\"destination-address\":\"21.1.1.3/32\",\"dscp\":3,\"protocol\":\"openconfig-packet-match-types:IP_TCP\",\"source-address\":\"11.1.1.3/32\"},\"state\":{\"destination-address\":\"21.1.1.3/32\",\"dscp\":3,\"protocol\":\"openconfig-packet-match-types:IP_TCP\",\"source-address\":\"11.1.1.3/32\"}},\"sequence-id\":3,\"state\":{\"matched-octets\":\"0\",\"matched-packets\":\"0\",\"sequence-id\":3},\"transport\":{\"config\":{\"destination-port\":203,\"source-port\":103},\"state\":{\"destination-port\":203,\"source-port\":103}}},{\"actions\":{\"config\":{\"forwarding-action\":\"openconfig-acl:DROP\"},\"state\":{\"forwarding-action\":\"openconfig-acl:DROP\"}},\"config\":{\"sequence-id\":4},\"ipv4\":{\"config\":{\"destination-address\":\"21.1.1.4/32\",\"dscp\":4,\"protocol\":\"openconfig-packet-match-types:IP_TCP\",\"source-address\":\"11.1.1.4/32\"},\"state\":{\"destination-address\":\"21.1.1.4/32\",\"dscp\":4,\"protocol\":\"openconfig-packet-match-types:IP_TCP\",\"source-address\":\"11.1.1.4/32\"}},\"sequence-id\":4,\"state\":{\"matched-octets\":\"0\",\"matched-packets\":\"0\",\"sequence-id\":4},\"transport\":{\"config\":{\"destination-port\":204,\"source-port\":104},\"state\":{\"destination-port\":204,\"source-port\":104}}},{\"actions\":{\"config\":{\"forwarding-action\":\"openconfig-acl:ACCEPT\"},\"state\":{\"forwarding-action\":\"openconfig-acl:ACCEPT\"}},\"config\":{\"sequence-id\":5},\"ipv4\":{\"config\":{\"destination-address\":\"21.1.1.5/32\",\"dscp\":5,\"protocol\":\"openconfig-packet-match-types:IP_TCP\",\"source-address\":\"11.1.1.5/32\"},\"state\":{\"destination-address\":\"21.1.1.5/32\",\"dscp\":5,\"protocol\":\"openconfig-packet-match-types:IP_TCP\",\"source-address\":\"11.1.1.5/32\"}},\"sequence-id\":5,\"state\":{\"matched-octets\":\"0\",\"matched-packets\":\"0\",\"sequence-id\":5},\"transport\":{\"config\":{\"destination-port\":205,\"source-port\":105},\"state\":{\"destination-port\":205,\"source-port\":105}}}]},\"config\":{\"description\":\"Description for MyACL3\",\"name\":\"MyACL3\",\"type\":\"openconfig-acl:ACL_IPV4\"},\"name\":\"MyACL3\",\"state\":{\"description\":\"Description for MyACL3\",\"name\":\"MyACL3\",\"type\":\"openconfig-acl:ACL_IPV4\"},\"type\":\"openconfig-acl:ACL_IPV4\"}]}" @@ -512,7 +512,7 @@ var aclDescrUpdateJson string = "{\"openconfig-acl:description\":\"Verifying ACL var requestOneRulePostJson string = "{\"sequence-id\": 8,\"config\": {\"sequence-id\": 8,\"description\": \"Description for MyACL5 Rule Seq 8\"},\"ipv4\": {\"config\": {\"source-address\": \"4.4.4.4/24\",\"destination-address\": \"5.5.5.5/24\",\"protocol\": \"IP_TCP\"}},\"transport\": {\"config\": {\"source-port\": 101,\"destination-port\": 100,\"tcp-flags\": [\"TCP_FIN\",\"TCP_ACK\"]}},\"actions\": {\"config\": {\"forwarding-action\": \"ACCEPT\"}}}" -var requestOneRulePatchJson string = "{\"sequence-id\": 8,\"config\": {\"sequence-id\": 8,\"description\": \"Description for MyACL5 Rule Seq 8\"},\"ipv4\": {\"config\": {\"source-address\": \"4.8.4.8/24\",\"destination-address\": \"15.5.15.5/24\",\"protocol\": \"IP_L2TP\"}},\"transport\": {\"config\": {\"source-port\": 101,\"destination-port\": 100,\"tcp-flags\": [\"TCP_FIN\",\"TCP_ACK\",\"TCP_RST\",\"TCP_ECE\"]}},\"actions\": {\"config\": {\"forwarding-action\": \"ACCEPT\"}}}" +var requestOneRulePatchJson string = "{ \"openconfig-acl:acl-entry\": [ {\"sequence-id\": 8,\"config\": {\"sequence-id\": 8,\"description\": \"Description for MyACL5 Rule Seq 8\"},\"ipv4\": {\"config\": {\"source-address\": \"4.8.4.8/24\",\"destination-address\": \"15.5.15.5/24\",\"protocol\": \"IP_L2TP\"}},\"transport\": {\"config\": {\"source-port\": 101,\"destination-port\": 100,\"tcp-flags\": [\"TCP_FIN\",\"TCP_ACK\",\"TCP_RST\",\"TCP_ECE\"]}},\"actions\": {\"config\": {\"forwarding-action\": \"ACCEPT\"}}} ] }" var responseOneRuleJson string = "{\"openconfig-acl:acl-entry\":[{\"actions\":{\"config\":{\"forwarding-action\":\"openconfig-acl:ACCEPT\"},\"state\":{\"forwarding-action\":\"openconfig-acl:ACCEPT\"}},\"config\":{\"sequence-id\":8},\"ipv4\":{\"config\":{\"destination-address\":\"5.5.5.5/24\",\"protocol\":\"openconfig-packet-match-types:IP_TCP\",\"source-address\":\"4.4.4.4/24\"},\"state\":{\"destination-address\":\"5.5.5.5/24\",\"protocol\":\"openconfig-packet-match-types:IP_TCP\",\"source-address\":\"4.4.4.4/24\"}},\"sequence-id\":8,\"state\":{\"matched-octets\":\"0\",\"matched-packets\":\"0\",\"sequence-id\":8},\"transport\":{\"config\":{\"destination-port\":100,\"source-port\":101,\"tcp-flags\":[\"openconfig-packet-match-types:TCP_FIN\",\"openconfig-packet-match-types:TCP_ACK\"]},\"state\":{\"destination-port\":100,\"source-port\":101,\"tcp-flags\":[\"openconfig-packet-match-types:TCP_FIN\",\"openconfig-packet-match-types:TCP_ACK\"]}}}]}" @@ -526,7 +526,7 @@ var ingressAclSetCreateJsonResponse string = "{\"openconfig-acl:ingress-acl-set\ var egressAclSetCreateJsonResponse string = "{\"openconfig-acl:egress-acl-set\":[{\"acl-entries\":{\"acl-entry\":[{\"sequence-id\":8,\"state\":{\"matched-octets\":\"0\",\"matched-packets\":\"0\",\"sequence-id\":8}}]},\"config\":{\"set-name\":\"MyACL5\",\"type\":\"openconfig-acl:ACL_IPV4\"},\"set-name\":\"MyACL5\",\"state\":{\"set-name\":\"MyACL5\",\"type\":\"openconfig-acl:ACL_IPV4\"},\"type\":\"openconfig-acl:ACL_IPV4\"}]}" -var replaceMultiRulesWithOneRuleJsonRequest string = "{\"name\": \"MyACL3\",\"type\": \"ACL_IPV4\",\"config\": {\"name\": \"MyACL3\",\"type\": \"ACL_IPV4\",\"description\": \"Description for MyACL3\"},\"acl-entries\": {\"acl-entry\": [{\"sequence-id\": 8,\"config\": {\"sequence-id\": 8,\"description\": \"Description for MyACL3 Rule Seq 8\"},\"ipv4\": {\"config\": {\"source-address\": \"81.1.1.1/32\",\"destination-address\": \"91.1.1.1/32\",\"protocol\": \"IP_TCP\"}},\"transport\": {\"config\": {\"source-port\": \"801..811\",\"destination-port\": \"901..921\"}},\"actions\": {\"config\": {\"forwarding-action\": \"REJECT\"}}}]}}" +var replaceMultiRulesWithOneRuleJsonRequest string = "{ \"openconfig-acl:acl-set\": [ {\"name\": \"MyACL3\",\"type\": \"ACL_IPV4\",\"config\": {\"name\": \"MyACL3\",\"type\": \"ACL_IPV4\",\"description\": \"Description for MyACL3\"},\"acl-entries\": {\"acl-entry\": [{\"sequence-id\": 8,\"config\": {\"sequence-id\": 8,\"description\": \"Description for MyACL3 Rule Seq 8\"},\"ipv4\": {\"config\": {\"source-address\": \"81.1.1.1/32\",\"destination-address\": \"91.1.1.1/32\",\"protocol\": \"IP_TCP\"}},\"transport\": {\"config\": {\"source-port\": \"801..811\",\"destination-port\": \"901..921\"}},\"actions\": {\"config\": {\"forwarding-action\": \"REJECT\"}}}]}} ] }" var replaceMultiRulesWithOneRuleJsonResponse string = "{\"openconfig-acl:acl-set\":[{\"acl-entries\":{\"acl-entry\":[{\"actions\":{\"config\":{\"forwarding-action\":\"openconfig-acl:DROP\"},\"state\":{\"forwarding-action\":\"openconfig-acl:DROP\"}},\"config\":{\"sequence-id\":8},\"ipv4\":{\"config\":{\"destination-address\":\"91.1.1.1/32\",\"protocol\":\"openconfig-packet-match-types:IP_TCP\",\"source-address\":\"81.1.1.1/32\"},\"state\":{\"destination-address\":\"91.1.1.1/32\",\"protocol\":\"openconfig-packet-match-types:IP_TCP\",\"source-address\":\"81.1.1.1/32\"}},\"sequence-id\":8,\"state\":{\"matched-octets\":\"0\",\"matched-packets\":\"0\",\"sequence-id\":8},\"transport\":{\"config\":{\"destination-port\":\"901-921\",\"source-port\":\"801-811\"},\"state\":{\"destination-port\":\"901-921\",\"source-port\":\"801-811\"}}}]},\"config\":{\"description\":\"Description for MyACL3\",\"name\":\"MyACL3\",\"type\":\"openconfig-acl:ACL_IPV4\"},\"name\":\"MyACL3\",\"state\":{\"description\":\"Description for MyACL3\",\"name\":\"MyACL3\",\"type\":\"openconfig-acl:ACL_IPV4\"},\"type\":\"openconfig-acl:ACL_IPV4\"}]}" diff --git a/src/translib/stp_app.go b/src/translib/stp_app.go index e1a6976b78..a28739ebc8 100644 --- a/src/translib/stp_app.go +++ b/src/translib/stp_app.go @@ -1,9 +1,21 @@ -/////////////////////////////////////////////////////////////////////// -// -// Copyright 2019 Broadcom. All rights reserved. -// The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. -// -/////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// // +// Copyright 2019 Broadcom. The term Broadcom refers to Broadcom Inc. and/or // +// its subsidiaries. // +// // +// 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. // +// // +//////////////////////////////////////////////////////////////////////////////// package translib @@ -23,17 +35,17 @@ import ( ) const ( - GLOBAL_TABLE = "STP" - VLAN_TABLE = "STP_VLAN" - VLAN_INTF_TABLE = "STP_VLAN_INTF" - INTF_TABLE = "STP_INTF" - VLAN_OPER_TABLE = "_STP_VLAN_TABLE" - VLAN_INTF_OPER_TABLE = "_STP_VLAN_INTF_TABLE" - INTF_OPER_TABLE = "_STP_INTF_TABLE" - STP_MODE = "mode" - OC_STP_APP_MODULE_NAME = "/openconfig-spanning-tree:stp" - OC_STP_YANG_PATH_PREFIX = "/device/stp" - PVST_MAX_INSTANCES = 255 + STP_GLOBAL_TABLE = "STP" + STP_VLAN_TABLE = "STP_VLAN" + STP_VLAN_INTF_TABLE = "STP_VLAN_INTF" + STP_INTF_TABLE = "STP_INTF" + STP_VLAN_OPER_TABLE = "_STP_VLAN_TABLE" + STP_VLAN_INTF_OPER_TABLE = "_STP_VLAN_INTF_TABLE" + STP_INTF_OPER_TABLE = "_STP_INTF_TABLE" + STP_MODE = "mode" + OC_STP_APP_MODULE_NAME = "/openconfig-spanning-tree:stp" + OC_STP_YANG_PATH_PREFIX = "/device/stp" + PVST_MAX_INSTANCES = 255 STP_DEFAULT_ROOT_GUARD_TIMEOUT = "30" STP_DEFAULT_FORWARD_DELAY = "15" @@ -73,7 +85,7 @@ func init() { &appInfo{appType: reflect.TypeOf(StpApp{}), ygotRootType: reflect.TypeOf(ocbinds.OpenconfigSpanningTree_Stp{}), isNative: false, - tablesToWatch: []*db.TableSpec{&db.TableSpec{Name: GLOBAL_TABLE}, &db.TableSpec{Name: VLAN_TABLE}, &db.TableSpec{Name: VLAN_INTF_TABLE}, &db.TableSpec{Name: INTF_TABLE}}}) + tablesToWatch: []*db.TableSpec{&db.TableSpec{Name: STP_GLOBAL_TABLE}, &db.TableSpec{Name: STP_VLAN_TABLE}, &db.TableSpec{Name: STP_VLAN_INTF_TABLE}, &db.TableSpec{Name: STP_INTF_TABLE}}}) if err != nil { log.Fatal("Register STP app module with App Interface failed with error=", err) @@ -91,14 +103,14 @@ func (app *StpApp) initialize(data appData) { app.ygotRoot = data.ygotRoot app.ygotTarget = data.ygotTarget - app.globalTable = &db.TableSpec{Name: GLOBAL_TABLE} - app.vlanTable = &db.TableSpec{Name: VLAN_TABLE} - app.vlanIntfTable = &db.TableSpec{Name: VLAN_INTF_TABLE} - app.interfaceTable = &db.TableSpec{Name: INTF_TABLE} + app.globalTable = &db.TableSpec{Name: STP_GLOBAL_TABLE} + app.vlanTable = &db.TableSpec{Name: STP_VLAN_TABLE} + app.vlanIntfTable = &db.TableSpec{Name: STP_VLAN_INTF_TABLE} + app.interfaceTable = &db.TableSpec{Name: STP_INTF_TABLE} - app.vlanOperTable = &db.TableSpec{Name: VLAN_OPER_TABLE} - app.vlanIntfOperTable = &db.TableSpec{Name: VLAN_INTF_OPER_TABLE} - app.intfOperTable = &db.TableSpec{Name: INTF_OPER_TABLE} + app.vlanOperTable = &db.TableSpec{Name: STP_VLAN_OPER_TABLE} + app.vlanIntfOperTable = &db.TableSpec{Name: STP_VLAN_INTF_OPER_TABLE} + app.intfOperTable = &db.TableSpec{Name: STP_INTF_OPER_TABLE} app.globalInfo = db.Value{Field: map[string]string{}} app.vlanTableMap = make(map[string]db.Value) @@ -129,6 +141,7 @@ func (app *StpApp) translateUpdate(d *db.DB) ([]db.WatchKeys, error) { var keys []db.WatchKeys log.Info("translateUpdate:stp:path =", app.pathInfo.Template) + keys, err = app.translateCRUCommon(d, UPDATE) return keys, err } @@ -137,6 +150,7 @@ func (app *StpApp) translateReplace(d *db.DB) ([]db.WatchKeys, error) { var keys []db.WatchKeys log.Info("translateReplace:stp:path =", app.pathInfo.Template) + keys, err = app.translateCRUCommon(d, REPLACE) return keys, err } @@ -179,7 +193,10 @@ func (app *StpApp) processUpdate(d *db.DB) (SetResponse, error) { var err error var resp SetResponse - err = errors.New("Not Implemented") + if err = app.processCommon(d, UPDATE); err != nil { + log.Error(err) + resp = SetResponse{ErrSrc: AppErr} + } return resp, err } @@ -187,7 +204,10 @@ func (app *StpApp) processReplace(d *db.DB) (SetResponse, error) { var err error var resp SetResponse - err = errors.New("Not Implemented") + if err = app.processCommon(d, REPLACE); err != nil { + log.Error(err) + resp = SetResponse{ErrSrc: AppErr} + } return resp, err } @@ -234,9 +254,9 @@ func (app *StpApp) translateCRUCommon(d *db.DB, opcode int) ([]db.WatchKeys, err var keys []db.WatchKeys log.Info("translateCRUCommon:STP:path =", app.pathInfo.Template) - app.convertOCStpGlobalConfToInternal() - app.convertOCPvstToInternal() - app.convertOCRpvstConfToInternal() + app.convertOCStpGlobalConfToInternal(opcode) + app.convertOCPvstToInternal(opcode) + app.convertOCRpvstConfToInternal(opcode) app.convertOCStpInterfacesToInternal() return keys, err @@ -261,17 +281,22 @@ func (app *StpApp) processCommon(d *db.DB, opcode int) error { if isSubtreeRequest(app.pathInfo.Template, "/openconfig-spanning-tree:stp/global") { switch opcode { case CREATE: - err = app.setStpGlobalConfigInDB(d) - if err != nil { - return err - } - err = app.enableStpForInterfaces(d) - if err != nil { - return err + err = app.enableStpMode(d) + case REPLACE, UPDATE: + mode, _ := app.getStpModeFromConfigDB(d) + if *app.ygotTarget == stp.Global || *app.ygotTarget == stp.Global.Config || targetUriPath == "/openconfig-spanning-tree:stp/global/config/enabled-protocol" { + if len(mode) == 0 { + err = app.enableStpMode(d) + } else { + if mode != app.convertOCStpModeToInternal(stp.Global.Config.EnabledProtocol[0]) { + return tlerr.InvalidArgs("STP mode is configured as %s", mode) + } else { + app.handleStpGlobalFieldsUpdation(d, opcode) + } + } + } else { + app.handleStpGlobalFieldsUpdation(d, opcode) } - err = app.enableStpForVlans(d) - case REPLACE: - case UPDATE: case DELETE: if *app.ygotTarget == stp.Global || *app.ygotTarget == stp.Global.Config || targetUriPath == "/openconfig-spanning-tree:stp/global/config/enabled-protocol" { if app.pathInfo.Template == "/openconfig-spanning-tree:stp/global/config/enabled-protocol{}" { @@ -306,19 +331,10 @@ func (app *StpApp) processCommon(d *db.DB, opcode int) error { for intfId, _ := range pvstVlan.Interfaces.Interface { pvstVlanIntf := pvstVlan.Interfaces.Interface[intfId] switch opcode { - case CREATE: - if *app.ygotTarget == pvstVlanIntf { - err = app.setRpvstVlanInterfaceDataInDB(d, true) - } else { - err = app.setRpvstVlanInterfaceDataInDB(d, false) - } - case REPLACE: - case UPDATE: - case DELETE: - if *app.ygotTarget == pvstVlanIntf { - err = d.DeleteEntry(app.vlanIntfTable, asKey(vlanName, intfId)) - } else { - err = app.handleVlanInterfaceFieldsDeletion(d, vlanName, intfId) + case CREATE, REPLACE, UPDATE, DELETE: + err = app.handleRpvstCRUDOperationsAtVlanInterfaceLevel(d, opcode, vlanName, intfId, pvstVlan, pvstVlanIntf) + if err != nil { + return err } case GET: err = app.convertDBRpvstVlanInterfaceToInternal(d, vlanName, intfId, asKey(vlanName, intfId), true) @@ -334,32 +350,10 @@ func (app *StpApp) processCommon(d *db.DB, opcode int) error { } else { isInterfacesSubtree := isSubtreeRequest(app.pathInfo.Template, "/openconfig-spanning-tree:stp/openconfig-spanning-tree-ext:pvst/vlan{}/interfaces") switch opcode { - case CREATE: - if *app.ygotTarget == pvstVlan { - log.Info("ygotTarget is pvstVlan") - err = app.setRpvstVlanDataInDB(d, true) - if err != nil { - return err - } - err = app.setRpvstVlanInterfaceDataInDB(d, true) - } else if isInterfacesSubtree { - err = app.setRpvstVlanInterfaceDataInDB(d, true) - } else { - err = d.SetEntry(app.vlanTable, asKey(vlanName), app.vlanTableMap[vlanName]) - } - case REPLACE: - case UPDATE: - case DELETE: - if *app.ygotTarget == pvstVlan { - err = d.DeleteKeys(app.vlanIntfTable, asKey(vlanName+TABLE_SEPARATOR+"*")) - if err != nil { - return err - } - err = d.DeleteEntry(app.vlanTable, asKey(vlanName)) - } else if isInterfacesSubtree { - err = d.DeleteKeys(app.vlanIntfTable, asKey(vlanName+TABLE_SEPARATOR+"*")) - } else { - err = app.handleVlanFieldsDeletion(d, vlanName) + case CREATE, REPLACE, UPDATE, DELETE: + err = app.handleRpvstCRUDOperationsAtVlanLevel(d, opcode, vlanName, isInterfacesSubtree, stp.Pvst, pvstVlan) + if err != nil { + return err } case GET: err = app.convertDBRpvstVlanConfigToInternal(d, asKey(vlanName)) @@ -373,6 +367,18 @@ func (app *StpApp) processCommon(d *db.DB, opcode int) error { } } else { // Handle top PVST + switch opcode { + case CREATE, REPLACE, UPDATE, DELETE: + log.Infof("Implementation in progress for URL: %s", app.pathInfo.Template) + return tlerr.NotSupported("Implementation in progress") + case GET: + ygot.BuildEmptyTree(stp.Pvst) + err = app.convertDBRpvstVlanConfigToInternal(d, db.Key{}) + if err != nil { + return err + } + app.convertInternalToOCPvstVlan("", stp.Pvst, nil) + } } } else if isSubtreeRequest(app.pathInfo.Template, "/openconfig-spanning-tree:stp/rapid-pvst") { mode, _ := app.getStpModeFromConfigDB(d) @@ -388,19 +394,10 @@ func (app *StpApp) processCommon(d *db.DB, opcode int) error { for intfId, _ := range rpvstVlanConf.Interfaces.Interface { rpvstVlanIntfConf := rpvstVlanConf.Interfaces.Interface[intfId] switch opcode { - case CREATE: - if *app.ygotTarget == rpvstVlanIntfConf { - err = app.setRpvstVlanInterfaceDataInDB(d, true) - } else { - err = app.setRpvstVlanInterfaceDataInDB(d, false) - } - case REPLACE: - case UPDATE: - case DELETE: - if *app.ygotTarget == rpvstVlanIntfConf { - err = d.DeleteEntry(app.vlanIntfTable, asKey(vlanName, intfId)) - } else { - err = app.handleVlanInterfaceFieldsDeletion(d, vlanName, intfId) + case CREATE, REPLACE, UPDATE, DELETE: + err = app.handleRpvstCRUDOperationsAtVlanInterfaceLevel(d, opcode, vlanName, intfId, rpvstVlanConf, rpvstVlanIntfConf) + if err != nil { + return err } case GET: err = app.convertDBRpvstVlanInterfaceToInternal(d, vlanName, intfId, asKey(vlanName, intfId), true) @@ -416,31 +413,10 @@ func (app *StpApp) processCommon(d *db.DB, opcode int) error { } else { isInterfacesSubtree := isSubtreeRequest(app.pathInfo.Template, "/openconfig-spanning-tree:stp/rapid-pvst/vlan{}/interfaces") switch opcode { - case CREATE: - if *app.ygotTarget == rpvstVlanConf { - err = app.setRpvstVlanDataInDB(d, true) - if err != nil { - return err - } - err = app.setRpvstVlanInterfaceDataInDB(d, true) - } else if isInterfacesSubtree { - err = app.setRpvstVlanInterfaceDataInDB(d, true) - } else { - err = d.SetEntry(app.vlanTable, asKey(vlanName), app.vlanTableMap[vlanName]) - } - case REPLACE: - case UPDATE: - case DELETE: - if *app.ygotTarget == rpvstVlanConf { - err = d.DeleteKeys(app.vlanIntfTable, asKey(vlanName+TABLE_SEPARATOR+"*")) - if err != nil { - return err - } - err = d.DeleteEntry(app.vlanTable, asKey(vlanName)) - } else if isInterfacesSubtree { - err = d.DeleteKeys(app.vlanIntfTable, asKey(vlanName+TABLE_SEPARATOR+"*")) - } else { - err = app.handleVlanFieldsDeletion(d, vlanName) + case CREATE, REPLACE, UPDATE, DELETE: + err = app.handleRpvstCRUDOperationsAtVlanLevel(d, opcode, vlanName, isInterfacesSubtree, stp.RapidPvst, rpvstVlanConf) + if err != nil { + return err } case GET: err = app.convertDBRpvstVlanConfigToInternal(d, asKey(vlanName)) @@ -454,7 +430,18 @@ func (app *StpApp) processCommon(d *db.DB, opcode int) error { } } else { // Handle both rapid-pvst and rapid-pvst/vlan - err = app.processCommonRpvstVlanToplevelPath(d, stp, opcode) + switch opcode { + case CREATE, REPLACE, UPDATE, DELETE: + log.Infof("Implementation in progress for URL: %s", app.pathInfo.Template) + return tlerr.NotSupported("Implementation in progress") + case GET: + ygot.BuildEmptyTree(stp.RapidPvst) + err = app.convertDBRpvstVlanConfigToInternal(d, db.Key{}) + if err != nil { + return err + } + app.convertInternalToOCRpvstVlanConfig("", stp.RapidPvst, nil) + } } } else if isSubtreeRequest(app.pathInfo.Template, "/openconfig-spanning-tree:stp/mstp") { mode, _ := app.getStpModeFromConfigDB(d) @@ -467,13 +454,19 @@ func (app *StpApp) processCommon(d *db.DB, opcode int) error { intfData := stp.Interfaces.Interface[intfId] switch opcode { case CREATE: + err = app.setStpInterfacesDataInDB(d, true) + case REPLACE: if *app.ygotTarget == intfData { + err = d.DeleteEntry(app.interfaceTable, asKey(intfId)) + if err != nil { + return err + } err = app.setStpInterfacesDataInDB(d, true) } else { err = app.setStpInterfacesDataInDB(d, false) } - case REPLACE: case UPDATE: + err = app.setStpInterfacesDataInDB(d, false) case DELETE: if *app.ygotTarget == intfData { err = d.DeleteEntry(app.interfaceTable, asKey(intfId)) @@ -490,37 +483,76 @@ func (app *StpApp) processCommon(d *db.DB, opcode int) error { } } } else { + switch opcode { + case CREATE, REPLACE, UPDATE, DELETE: + log.Infof("Implementation in progress for URL: %s", app.pathInfo.Template) + return tlerr.NotSupported("Implementation in progress") + case GET: + ygot.BuildEmptyTree(stp.Interfaces) + err = app.convertDBStpInterfacesToInternal(d, db.Key{}) + if err != nil { + return err + } + app.convertInternalToOCStpInterfaces("", stp.Interfaces, nil) + } } } else if topmostPath { switch opcode { case CREATE: + err = app.enableStpMode(d) + if err != nil { + return err + } + err = app.setRpvstVlanDataInDB(d, true) + if err != nil { + return err + } + err = app.setRpvstVlanInterfaceDataInDB(d, true) + if err != nil { + return err + } + err = app.setStpInterfacesDataInDB(d, true) + case REPLACE: + err = app.disableStpMode(d) + if err != nil { + return err + } + err = app.enableStpMode(d) + if err != nil { + return err + } + err = app.setRpvstVlanDataInDB(d, true) + if err != nil { + return err + } + err = app.setRpvstVlanInterfaceDataInDB(d, true) + if err != nil { + return err + } + err = app.setStpInterfacesDataInDB(d, true) case DELETE: err = app.disableStpMode(d) case GET: ygot.BuildEmptyTree(stp) ////////////////////// - ygot.BuildEmptyTree(stp.Global) err = app.convertDBStpGlobalConfigToInternal(d) if err != nil { return err } app.convertInternalToOCStpGlobalConfig(stp.Global) + ////////////////////// + err = app.convertDBRpvstVlanConfigToInternal(d, db.Key{}) + if err != nil { + return err + } stpMode := (&app.globalInfo).Get(STP_MODE) switch stpMode { case "pvst": ygot.BuildEmptyTree(stp.Pvst) - err = app.convertDBRpvstVlanConfigToInternal(d, db.Key{}) - if err != nil { - return err - } app.convertInternalToOCPvstVlan("", stp.Pvst, nil) case "rpvst": ygot.BuildEmptyTree(stp.RapidPvst) - err = app.convertDBRpvstVlanConfigToInternal(d, db.Key{}) - if err != nil { - return err - } app.convertInternalToOCRpvstVlanConfig("", stp.RapidPvst, nil) case "mstp": } @@ -551,6 +583,114 @@ func (app *StpApp) processCommonRpvstVlanToplevelPath(d *db.DB, stp *ocbinds.Ope return err } +func (app *StpApp) handleRpvstCRUDOperationsAtVlanLevel(d *db.DB, opcode int, vlanName string, isInterfacesSubtree bool, mode interface{}, vlan interface{}) error { + var err error + + log.Infof("handleRpvstCRUDOperationsAtVlanLevel --> Perform CRUD for %s", reflect.TypeOf(vlan).Elem().Name()) + switch opcode { + case CREATE: + if *app.ygotTarget == vlan { + err = app.setRpvstVlanDataInDB(d, true) + if err != nil { + return err + } + err = app.setRpvstVlanInterfaceDataInDB(d, true) + } else if isInterfacesSubtree { + err = app.setRpvstVlanInterfaceDataInDB(d, true) + } else { + err = d.SetEntry(app.vlanTable, asKey(vlanName), app.vlanTableMap[vlanName]) + } + case REPLACE: + if *app.ygotTarget == vlan { + err = d.DeleteKeys(app.vlanIntfTable, asKey(vlanName+TABLE_SEPARATOR+"*")) + if err != nil { + return err + } + err = d.DeleteEntry(app.vlanTable, asKey(vlanName)) + if err != nil { + return err + } + err = app.setRpvstVlanDataInDB(d, true) + if err != nil { + return err + } + err = app.setRpvstVlanInterfaceDataInDB(d, true) + } else if isInterfacesSubtree { + err = d.DeleteKeys(app.vlanIntfTable, asKey(vlanName+TABLE_SEPARATOR+"*")) + if err != nil { + return err + } + err = app.setRpvstVlanInterfaceDataInDB(d, true) + } else { + err = d.SetEntry(app.vlanTable, asKey(vlanName), app.vlanTableMap[vlanName]) + } + case UPDATE: + if *app.ygotTarget == vlan { + err = app.setRpvstVlanDataInDB(d, false) + if err != nil { + return err + } + err = app.setRpvstVlanInterfaceDataInDB(d, false) + } else if isInterfacesSubtree { + err = app.setRpvstVlanInterfaceDataInDB(d, false) + } else { + err = d.ModEntry(app.vlanTable, asKey(vlanName), app.vlanTableMap[vlanName]) + } + case DELETE: + if *app.ygotTarget == vlan { + err = d.DeleteKeys(app.vlanIntfTable, asKey(vlanName+TABLE_SEPARATOR+"*")) + if err != nil { + return err + } + err = d.DeleteEntry(app.vlanTable, asKey(vlanName)) + } else if isInterfacesSubtree { + err = d.DeleteKeys(app.vlanIntfTable, asKey(vlanName+TABLE_SEPARATOR+"*")) + } else { + err = app.handleVlanFieldsDeletion(d, vlanName) + } + } + + return err +} + +func (app *StpApp) handleRpvstCRUDOperationsAtVlanInterfaceLevel(d *db.DB, opcode int, vlanName string, intfId string, vlan interface{}, vlanIntf interface{}) error { + var err error + + log.Infof("handleRpvstCRUDOperationsAtVlanInterfaceLevel --> Perform CRUD for %s", reflect.TypeOf(vlanIntf).Elem().Name()) + switch opcode { + case CREATE: + if *app.ygotTarget == vlanIntf { + err = app.setRpvstVlanInterfaceDataInDB(d, true) + } else { + err = app.setRpvstVlanInterfaceDataInDB(d, false) + } + case REPLACE: + if *app.ygotTarget == vlanIntf { + err = d.DeleteEntry(app.vlanIntfTable, asKey(vlanName, intfId)) + if err != nil { + return err + } + err = app.setRpvstVlanInterfaceDataInDB(d, true) + } else { + err = app.handleVlanInterfaceFieldsDeletion(d, vlanName, intfId) + if err != nil { + return err + } + err = app.setRpvstVlanInterfaceDataInDB(d, false) + } + case UPDATE: + err = app.setRpvstVlanInterfaceDataInDB(d, false) + case DELETE: + if *app.ygotTarget == vlanIntf { + err = d.DeleteEntry(app.vlanIntfTable, asKey(vlanName, intfId)) + } else { + err = app.handleVlanInterfaceFieldsDeletion(d, vlanName, intfId) + } + } + + return err +} + ///////////////// STP GLOBAL ////////////////////// func (app *StpApp) setStpGlobalConfigInDB(d *db.DB) error { var err error @@ -560,39 +700,42 @@ func (app *StpApp) setStpGlobalConfigInDB(d *db.DB) error { return err } -func (app *StpApp) convertOCStpGlobalConfToInternal() { +func (app *StpApp) convertOCStpGlobalConfToInternal(opcode int) { stp := app.getAppRootObject() + setDefaultFlag := (opcode == CREATE || opcode == REPLACE) if stp != nil { if stp.Global != nil && stp.Global.Config != nil { if stp.Global.Config.BridgePriority != nil { (&app.globalInfo).Set("priority", strconv.Itoa(int(*stp.Global.Config.BridgePriority))) - } else { + } else if setDefaultFlag { (&app.globalInfo).Set("priority", STP_DEFAULT_BRIDGE_PRIORITY) } if stp.Global.Config.ForwardingDelay != nil { (&app.globalInfo).Set("forward_delay", strconv.Itoa(int(*stp.Global.Config.ForwardingDelay))) - } else { + } else if setDefaultFlag { (&app.globalInfo).Set("forward_delay", STP_DEFAULT_FORWARD_DELAY) } if stp.Global.Config.HelloTime != nil { (&app.globalInfo).Set("hello_time", strconv.Itoa(int(*stp.Global.Config.HelloTime))) - } else { + } else if setDefaultFlag { (&app.globalInfo).Set("hello_time", STP_DEFAULT_HELLO_INTERVAL) } if stp.Global.Config.MaxAge != nil { (&app.globalInfo).Set("max_age", strconv.Itoa(int(*stp.Global.Config.MaxAge))) - } else { + } else if setDefaultFlag { (&app.globalInfo).Set("max_age", STP_DEFAULT_MAX_AGE) } if stp.Global.Config.RootguardTimeout != nil { (&app.globalInfo).Set("rootguard_timeout", strconv.Itoa(int(*stp.Global.Config.RootguardTimeout))) - } else { + } else if setDefaultFlag { (&app.globalInfo).Set("rootguard_timeout", STP_DEFAULT_ROOT_GUARD_TIMEOUT) } - mode := app.convertOCStpModeToInternal(stp.Global.Config.EnabledProtocol[0]) - if len(mode) > 0 { - (&app.globalInfo).Set(STP_MODE, mode) + if len(stp.Global.Config.EnabledProtocol) > 0 { + mode := app.convertOCStpModeToInternal(stp.Global.Config.EnabledProtocol[0]) + if len(mode) > 0 { + (&app.globalInfo).Set(STP_MODE, mode) + } } log.Infof("convertOCStpGlobalConfToInternal -- Internal Stp global config: %v", app.globalInfo) @@ -615,6 +758,8 @@ func (app *StpApp) convertInternalToOCStpGlobalConfig(stpGlobal *ocbinds.Opencon var priority uint32 var forDelay, helloTime, maxAge uint8 var rootGTimeout uint16 + ygot.BuildEmptyTree(stpGlobal) + if stpGlobal.Config != nil { stpGlobal.Config.EnabledProtocol = app.convertInternalStpModeToOC((&app.globalInfo).Get(STP_MODE)) @@ -651,8 +796,9 @@ func (app *StpApp) convertInternalToOCStpGlobalConfig(stpGlobal *ocbinds.Opencon } ///////////////// RPVST ////////////////////// -func (app *StpApp) convertOCRpvstConfToInternal() { +func (app *StpApp) convertOCRpvstConfToInternal(opcode int) { stp := app.getAppRootObject() + setDefaultFlag := (opcode == CREATE || opcode == REPLACE) if stp != nil && stp.RapidPvst != nil && len(stp.RapidPvst.Vlan) > 0 { for vlanId, _ := range stp.RapidPvst.Vlan { vlanName := "Vlan" + strconv.Itoa(int(vlanId)) @@ -663,22 +809,22 @@ func (app *StpApp) convertOCRpvstConfToInternal() { (&dbVal).Set("vlanid", strconv.Itoa(int(vlanId))) if rpvstVlanConf.Config.BridgePriority != nil { (&dbVal).Set("priority", strconv.Itoa(int(*rpvstVlanConf.Config.BridgePriority))) - } else { + } else if setDefaultFlag { (&dbVal).Set("priority", "32768") } if rpvstVlanConf.Config.ForwardingDelay != nil { (&dbVal).Set("forward_delay", strconv.Itoa(int(*rpvstVlanConf.Config.ForwardingDelay))) - } else { + } else if setDefaultFlag { (&dbVal).Set("forward_delay", "15") } if rpvstVlanConf.Config.HelloTime != nil { (&dbVal).Set("hello_time", strconv.Itoa(int(*rpvstVlanConf.Config.HelloTime))) - } else { + } else if setDefaultFlag { (&dbVal).Set("hello_time", "2") } if rpvstVlanConf.Config.MaxAge != nil { (&dbVal).Set("max_age", strconv.Itoa(int(*rpvstVlanConf.Config.MaxAge))) - } else { + } else if setDefaultFlag { (&dbVal).Set("max_age", "20") } if rpvstVlanConf.Config.SpanningTreeEnable != nil { @@ -687,7 +833,7 @@ func (app *StpApp) convertOCRpvstConfToInternal() { } else { (&dbVal).Set("enabled", "false") } - } else { + } else if setDefaultFlag { (&dbVal).Set("enabled", "false") } } @@ -698,16 +844,14 @@ func (app *StpApp) convertOCRpvstConfToInternal() { app.vlanIntfTableMap[vlanName][intfId] = db.Value{Field: map[string]string{}} if rpvstVlanIntfConf.Config != nil { dbVal := app.vlanIntfTableMap[vlanName][intfId] - (&dbVal).Set("vlan-name", vlanName) - (&dbVal).Set("ifname", intfId) if rpvstVlanIntfConf.Config.Cost != nil { (&dbVal).Set("path_cost", strconv.Itoa(int(*rpvstVlanIntfConf.Config.Cost))) - } else { + } else if setDefaultFlag { (&dbVal).Set("path_cost", "200") } if rpvstVlanIntfConf.Config.PortPriority != nil { (&dbVal).Set("priority", strconv.Itoa(int(*rpvstVlanIntfConf.Config.PortPriority))) - } else { + } else if setDefaultFlag { (&dbVal).Set("priority", "128") } } @@ -745,7 +889,6 @@ func (app *StpApp) setRpvstVlanInterfaceDataInDB(d *db.DB, createFlag bool) erro } if createFlag || (!createFlag && err != nil && !existingEntry.IsPopulated()) { err = d.CreateEntry(app.vlanIntfTable, asKey(vlanName, intfId), app.vlanIntfTableMap[vlanName][intfId]) - log.Error(err) } else { if existingEntry.IsPopulated() { err = d.ModEntry(app.vlanIntfTable, asKey(vlanName, intfId), app.vlanIntfTableMap[vlanName][intfId]) @@ -880,8 +1023,8 @@ func (app *StpApp) convertInternalToOCRpvstVlanConfig(vlanName string, rpvst *oc desigRootAddr := (&operDbVal).Get("desig_bridge_id") rpvstVlanConf.State.DesignatedRootAddress = &desigRootAddr - //rootPortStr := (&operDbVal).Get("root_port") - //rpvstVlanConf.State.RootPort = &rootPortStr + rootPortStr := (&operDbVal).Get("root_port") + rpvstVlanConf.State.RootPortName = &rootPortStr } app.convertInternalToOCRpvstVlanInterface(vlanName, "", rpvstVlanConf, nil) @@ -960,8 +1103,9 @@ func (app *StpApp) convertInternalToOCRpvstVlanInterface(vlanName string, intfId } /////////// PVST ////////////////////// -func (app *StpApp) convertOCPvstToInternal() { +func (app *StpApp) convertOCPvstToInternal(opcode int) { stp := app.getAppRootObject() + setDefaultFlag := (opcode == CREATE || opcode == REPLACE) if stp != nil && stp.Pvst != nil && len(stp.Pvst.Vlan) > 0 { for vlanId, _ := range stp.Pvst.Vlan { vlanName := "Vlan" + strconv.Itoa(int(vlanId)) @@ -972,22 +1116,22 @@ func (app *StpApp) convertOCPvstToInternal() { (&dbVal).Set("vlanid", strconv.Itoa(int(vlanId))) if pvstVlan.Config.BridgePriority != nil { (&dbVal).Set("priority", strconv.Itoa(int(*pvstVlan.Config.BridgePriority))) - } else { + } else if setDefaultFlag { (&dbVal).Set("priority", "32768") } if pvstVlan.Config.ForwardingDelay != nil { (&dbVal).Set("forward_delay", strconv.Itoa(int(*pvstVlan.Config.ForwardingDelay))) - } else { + } else if setDefaultFlag { (&dbVal).Set("forward_delay", "15") } if pvstVlan.Config.HelloTime != nil { (&dbVal).Set("hello_time", strconv.Itoa(int(*pvstVlan.Config.HelloTime))) - } else { + } else if setDefaultFlag { (&dbVal).Set("hello_time", "2") } if pvstVlan.Config.MaxAge != nil { (&dbVal).Set("max_age", strconv.Itoa(int(*pvstVlan.Config.MaxAge))) - } else { + } else if setDefaultFlag { (&dbVal).Set("max_age", "20") } if pvstVlan.Config.SpanningTreeEnable != nil { @@ -996,7 +1140,7 @@ func (app *StpApp) convertOCPvstToInternal() { } else { (&dbVal).Set("enabled", "false") } - } else { + } else if setDefaultFlag { (&dbVal).Set("enabled", "false") } } @@ -1007,16 +1151,14 @@ func (app *StpApp) convertOCPvstToInternal() { app.vlanIntfTableMap[vlanName][intfId] = db.Value{Field: map[string]string{}} if pvstVlanIntf.Config != nil { dbVal := app.vlanIntfTableMap[vlanName][intfId] - (&dbVal).Set("vlan-name", vlanName) - (&dbVal).Set("ifname", intfId) if pvstVlanIntf.Config.Cost != nil { (&dbVal).Set("path_cost", strconv.Itoa(int(*pvstVlanIntf.Config.Cost))) - } else { + } else if setDefaultFlag { (&dbVal).Set("path_cost", "200") } if pvstVlanIntf.Config.PortPriority != nil { (&dbVal).Set("priority", strconv.Itoa(int(*pvstVlanIntf.Config.PortPriority))) - } else { + } else if setDefaultFlag { (&dbVal).Set("priority", "128") } } @@ -1112,8 +1254,8 @@ func (app *StpApp) convertInternalToOCPvstVlan(vlanName string, pvst *ocbinds.Op desigRootAddr := (&operDbVal).Get("desig_bridge_id") pvstVlan.State.DesignatedRootAddress = &desigRootAddr - //rootPortStr := (&operDbVal).Get("root_port") - //pvstVlan.State.RootPort = &rootPortStr + rootPortStr := (&operDbVal).Get("root_port") + pvstVlan.State.RootPortName = &rootPortStr } app.convertInternalToOCPvstVlanInterface(vlanName, "", pvstVlan, nil) @@ -1172,7 +1314,6 @@ func (app *StpApp) convertOCStpInterfacesToInternal() { stpIntfConf := stp.Interfaces.Interface[intfId] if stpIntfConf.Config != nil { dbVal := app.intfTableMap[intfId] - (&dbVal).Set("ifname", intfId) if stpIntfConf.Config.BpduGuard != nil { if *stpIntfConf.Config.BpduGuard == true { @@ -1257,7 +1398,21 @@ func (app *StpApp) convertOCStpInterfacesToInternal() { func (app *StpApp) setStpInterfacesDataInDB(d *db.DB, createFlag bool) error { var err error + // Fetch list of interfaces which are L2 i.e. members of any Vlan + l2IntfList, err1 := app.getAllInterfacesFromVlanMemberTable(d) + if err1 != nil { + return tlerr.InvalidArgs("There are no L2 interfaces configured") + } + // Fetch list of interfaces which are members of port-channel + poMemberIntfList, _ := app.getAllInterfacesFromPortChannelMemberTable(d) + for intfName := range app.intfTableMap { + if !contains(l2IntfList, intfName) { + return tlerr.InvalidArgs("%s has no VLAN configured - It's not a L2 interface", intfName) + } + if contains(poMemberIntfList, intfName) { + return tlerr.InvalidArgs("%s is a portchannel member port - STP can't be configured", intfName) + } existingEntry, err := d.GetEntry(app.interfaceTable, asKey(intfName)) if createFlag && existingEntry.IsPopulated() { return tlerr.AlreadyExists("Stp Interface %s already configured", intfName) @@ -1420,7 +1575,10 @@ func (app *StpApp) convertOperInternalToOCVlanInterface(vlanName string, intfId case "OpenconfigSpanningTree_Stp_Pvst_Vlan": pvstVlan, _ = vlan.(*ocbinds.OpenconfigSpanningTree_Stp_Pvst_Vlan) if vlanIntf == nil { - pvstVlanIntf, _ = pvstVlan.Interfaces.NewInterface(intfId) + pvstVlanIntf = pvstVlan.Interfaces.Interface[intfId] + if pvstVlanIntf == nil { + pvstVlanIntf, _ = pvstVlan.Interfaces.NewInterface(intfId) + } ygot.BuildEmptyTree(pvstVlanIntf) ygot.BuildEmptyTree(pvstVlanIntf.State) } else { @@ -1429,7 +1587,10 @@ func (app *StpApp) convertOperInternalToOCVlanInterface(vlanName string, intfId case "OpenconfigSpanningTree_Stp_RapidPvst_Vlan": rpvstVlan, _ = vlan.(*ocbinds.OpenconfigSpanningTree_Stp_RapidPvst_Vlan) if vlanIntf == nil { - rpvstVlanIntf, _ = rpvstVlan.Interfaces.NewInterface(intfId) + rpvstVlanIntf = rpvstVlan.Interfaces.Interface[intfId] + if rpvstVlanIntf == nil { + rpvstVlanIntf, _ = rpvstVlan.Interfaces.NewInterface(intfId) + } ygot.BuildEmptyTree(rpvstVlanIntf) ygot.BuildEmptyTree(rpvstVlanIntf.State) } else { @@ -1492,15 +1653,15 @@ func (app *StpApp) convertOperInternalToOCVlanInterface(vlanName string, intfId pvstVlanIntf.State.DesignatedRootAddress = &desigRootAddr pvstVlanIntf.State.DesignatedBridgeAddress = &desigBridgeAddr switch portState { - case "disabled": + case "DISABLED": pvstVlanIntf.State.PortState = ocbinds.OpenconfigSpanningTreeTypes_STP_PORT_STATE_DISABLED - case "block": + case "BLOCKING": pvstVlanIntf.State.PortState = ocbinds.OpenconfigSpanningTreeTypes_STP_PORT_STATE_BLOCKING - case "listen": + case "LISTENING": pvstVlanIntf.State.PortState = ocbinds.OpenconfigSpanningTreeTypes_STP_PORT_STATE_LISTENING - case "learn": + case "LEARNING": pvstVlanIntf.State.PortState = ocbinds.OpenconfigSpanningTreeTypes_STP_PORT_STATE_LEARNING - case "forward": + case "FORWARDING": pvstVlanIntf.State.PortState = ocbinds.OpenconfigSpanningTreeTypes_STP_PORT_STATE_FORWARDING } if pvstVlanIntf.State.Counters != nil { @@ -1521,15 +1682,15 @@ func (app *StpApp) convertOperInternalToOCVlanInterface(vlanName string, intfId rpvstVlanIntf.State.DesignatedRootAddress = &desigRootAddr rpvstVlanIntf.State.DesignatedBridgeAddress = &desigBridgeAddr switch portState { - case "disabled": + case "DISABLED": rpvstVlanIntf.State.PortState = ocbinds.OpenconfigSpanningTreeTypes_STP_PORT_STATE_DISABLED - case "block": + case "BLOCKING": rpvstVlanIntf.State.PortState = ocbinds.OpenconfigSpanningTreeTypes_STP_PORT_STATE_BLOCKING - case "listen": + case "LISTENING": rpvstVlanIntf.State.PortState = ocbinds.OpenconfigSpanningTreeTypes_STP_PORT_STATE_LISTENING - case "learn": + case "LEARNING": rpvstVlanIntf.State.PortState = ocbinds.OpenconfigSpanningTreeTypes_STP_PORT_STATE_LEARNING - case "forward": + case "FORWARDING": rpvstVlanIntf.State.PortState = ocbinds.OpenconfigSpanningTreeTypes_STP_PORT_STATE_FORWARDING } if rpvstVlanIntf.State.Counters != nil { @@ -1659,6 +1820,22 @@ func (app *StpApp) getAllInterfacesFromVlanMemberTable(d *db.DB) ([]string, erro return intfList, err } +func (app *StpApp) getAllInterfacesFromPortChannelMemberTable(d *db.DB) ([]string, error) { + var intfList []string + + keys, err := d.GetKeys(&db.TableSpec{Name: "PORTCHANNEL_MEMBER"}) + if err != nil { + return intfList, err + } + for i, _ := range keys { + key := keys[i] + if !contains(intfList, (&key).Get(1)) { + intfList = append(intfList, (&key).Get(1)) + } + } + return intfList, err +} + func (app *StpApp) enableStpForInterfaces(d *db.DB) error { defaultDBValues := db.Value{Field: map[string]string{}} (&defaultDBValues).Set("enabled", "true") @@ -1737,30 +1914,86 @@ func (app *StpApp) enableStpForVlans(d *db.DB) error { return err } -func (app *StpApp) updateGlobalFieldsToStpVlanTable(d *db.DB, fldName string, valStr string) error { - stpGlobalDbEntry, err := d.GetEntry(app.globalTable, asKey("GLOBAL")) - if err != nil { - return err +func enableStpOnVlanCreation(d *db.DB, vlanList []string) { + if len(vlanList) == 0 { + return } - globalFldVal := (&stpGlobalDbEntry).Get(fldName) + vlanKeys, _ := d.GetKeys(&db.TableSpec{Name: STP_VLAN_TABLE}) + existingEntriesCount := len(vlanKeys) + if existingEntriesCount < PVST_MAX_INSTANCES { + stpGlobalDBEntry, err := d.GetEntry(&db.TableSpec{Name: STP_GLOBAL_TABLE}, asKey("GLOBAL")) + if err != nil { + return + } + fDelay := (&stpGlobalDBEntry).Get("forward_delay") + helloTime := (&stpGlobalDBEntry).Get("hello_time") + maxAge := (&stpGlobalDBEntry).Get("max_age") + priority := (&stpGlobalDBEntry).Get("priority") + + // Sort vlanList in natural order such that 'Vlan2' < 'Vlan10' + natsort.Sort(vlanList) + + for i, _ := range vlanList { + if (existingEntriesCount + i) < PVST_MAX_INSTANCES { + defaultDBValues := db.Value{Field: map[string]string{}} + (&defaultDBValues).Set("enabled", "true") + (&defaultDBValues).Set("forward_delay", fDelay) + (&defaultDBValues).Set("hello_time", helloTime) + (&defaultDBValues).Set("max_age", maxAge) + (&defaultDBValues).Set("priority", priority) + + vlanId := strings.Replace(vlanList[i], "Vlan", "", 1) + (&defaultDBValues).Set("vlanid", vlanId) + d.CreateEntry(&db.TableSpec{Name: STP_VLAN_TABLE}, asKey(vlanList[i]), defaultDBValues) + } + } + } +} +// This function accepts map where key is Interface name (i.e. Eth or Portchannel) +// and value will be slice of VlanIds +//func enableStpOnInterfaceVlanMembership(d *db.DB, intfVlansMap map[string][]string) { +//} + +func (app *StpApp) updateGlobalFieldsToStpVlanTable(d *db.DB, fldValuePair map[string]string, stpGlobalDbEntry db.Value) error { vlanKeys, err := d.GetKeys(app.vlanTable) if err != nil { return err } for i, _ := range vlanKeys { vlanEntry, _ := d.GetEntry(app.vlanTable, vlanKeys[i]) - if (&vlanEntry).Get(fldName) == globalFldVal { - (&vlanEntry).Set(fldName, valStr) - err := d.ModEntry(app.vlanTable, vlanKeys[i], vlanEntry) - if err != nil { - return err + + for fldName := range fldValuePair { + valStr := fldValuePair[fldName] + globalFldVal := (&stpGlobalDbEntry).Get(fldName) + + if (&vlanEntry).Get(fldName) == globalFldVal { + (&vlanEntry).Set(fldName, valStr) + err := d.ModEntry(app.vlanTable, vlanKeys[i], vlanEntry) + if err != nil { + return err + } } } } return nil } +func (app *StpApp) enableStpMode(d *db.DB) error { + var err error + err = app.setStpGlobalConfigInDB(d) + if err != nil { + return err + } + err = app.enableStpForInterfaces(d) + if err != nil { + return err + } + err = app.enableStpForVlans(d) + + return err +} + func (app *StpApp) disableStpMode(d *db.DB) error { var err error err = d.DeleteTable(app.vlanIntfTable) @@ -1780,6 +2013,40 @@ func (app *StpApp) disableStpMode(d *db.DB) error { return err } +func (app *StpApp) handleStpGlobalFieldsUpdation(d *db.DB, opcode int) error { + stpGlobalDBEntry, err := d.GetEntry(app.globalTable, asKey("GLOBAL")) + if err != nil { + return err + } + // Make a copy of StpGlobalDBEntry to modify fields value. + tmpDbEntry := db.Value{Field: map[string]string{}} + for field, value := range stpGlobalDBEntry.Field { + tmpDbEntry.Field[field] = value + } + fldValuePair := make(map[string]string) + + for fld := range app.globalInfo.Field { + valStr := app.globalInfo.Field[fld] + (&tmpDbEntry).Set(fld, valStr) + + if fld != "rootguard_timeout" { + fldValuePair[fld] = valStr + } + } + + err = d.ModEntry(app.globalTable, asKey("GLOBAL"), tmpDbEntry) + if err != nil { + return err + } + + err = app.updateGlobalFieldsToStpVlanTable(d, fldValuePair, stpGlobalDBEntry) + if err != nil { + return err + } + + return nil +} + func (app *StpApp) handleStpGlobalFieldsDeletion(d *db.DB) error { stpGlobalDBEntry, err := d.GetEntry(app.globalTable, asKey("GLOBAL")) if err != nil { @@ -1811,17 +2078,26 @@ func (app *StpApp) handleStpGlobalFieldsDeletion(d *db.DB) error { valStr = STP_DEFAULT_BRIDGE_PRIORITY } - (&stpGlobalDBEntry).Set(fldName, valStr) - err := d.ModEntry(app.globalTable, asKey("GLOBAL"), stpGlobalDBEntry) + // Make a copy of StpGlobalDBEntry to modify fields value. + tmpDbEntry := db.Value{Field: map[string]string{}} + for field, value := range stpGlobalDBEntry.Field { + tmpDbEntry.Field[field] = value + } + fldValuePair := make(map[string]string) + + (&tmpDbEntry).Set(fldName, valStr) + err = d.ModEntry(app.globalTable, asKey("GLOBAL"), tmpDbEntry) if err != nil { return err } if fldName != "rootguard_timeout" { - err := app.updateGlobalFieldsToStpVlanTable(d, fldName, valStr) - if err != nil { - return err - } + fldValuePair[fldName] = valStr + } + + err = app.updateGlobalFieldsToStpVlanTable(d, fldValuePair, stpGlobalDBEntry) + if err != nil { + return err } } return nil @@ -1856,6 +2132,15 @@ func (app *StpApp) handleVlanInterfaceFieldsDeletion(d *db.DB, vlanName string, } func (app *StpApp) handleVlanFieldsDeletion(d *db.DB, vlanName string) error { + stpGlobalDBEntry, err := d.GetEntry(app.globalTable, asKey("GLOBAL")) + if err != nil { + return err + } + fDelay := (&stpGlobalDBEntry).Get("forward_delay") + helloTime := (&stpGlobalDBEntry).Get("hello_time") + maxAge := (&stpGlobalDBEntry).Get("max_age") + priority := (&stpGlobalDBEntry).Get("priority") + dbEntry, err := d.GetEntry(app.vlanTable, asKey(vlanName)) if err != nil { return err @@ -1869,19 +2154,19 @@ func (app *StpApp) handleVlanFieldsDeletion(d *db.DB, vlanName string) error { if nodeInfo.IsLeaf() { switch nodeInfo.Name { case "hello-time": - (&dbEntry).Remove("hello_time") + (&dbEntry).Set("hello_time", helloTime) case "max-age": - (&dbEntry).Remove("max_age") + (&dbEntry).Set("max_age", maxAge) case "bridge-priority": - (&dbEntry).Remove("priority") + (&dbEntry).Set("priority", priority) case "forwarding-delay": - (&dbEntry).Remove("forward_delay") + (&dbEntry).Set("forward_delay", fDelay) case "spanning-tree-enable": - (&dbEntry).Remove("enabled") + (&dbEntry).Set("enabled", "false") } } - err = d.SetEntry(app.vlanTable, asKey(vlanName), dbEntry) + err = d.ModEntry(app.vlanTable, asKey(vlanName), dbEntry) if err != nil { return err } diff --git a/tools/pyang/pyang_plugins/openapi.py b/tools/pyang/pyang_plugins/openapi.py index 4a2d62af60..ebc1127d4b 100644 --- a/tools/pyang/pyang_plugins/openapi.py +++ b/tools/pyang/pyang_plugins/openapi.py @@ -246,7 +246,7 @@ def add_swagger_tag(module): else: return -def swagger_it(child, defName, pathstr, payload, metadata, verb, operId=False): +def swagger_it(child, defName, pathstr, payload, metadata, verb, operId=False, xParamsList=[]): firstEncounter = True verbPathStr = pathstr @@ -272,6 +272,18 @@ def swagger_it(child, defName, pathstr, payload, metadata, verb, operId=False): swaggerDict["paths"][verbPathStr][verb]["responses"] = copy.deepcopy(merge_two_dicts(responses, verb_responses[verb])) firstEncounter = False + haveXParams = False + tempParamsList = [] + for entry in xParamsList: + if entry["yangName"] not in tempParamsList: + tempParamsList.append(entry["yangName"]) + else: + haveXParams = True + break + + if haveXParams: + swaggerDict["paths"][verbPathStr][verb]["x-params"] = {"varMapping":copy.deepcopy(xParamsList)} + opId = None if "operationId" not in swaggerDict["paths"][verbPathStr][verb]: if not operId: @@ -412,7 +424,8 @@ def walk_child(child): actXpath = statements.mk_path_str(child, True) metadata = [] keyNodesInPath = [] - pathstr = mk_path_refine(child, metadata, keyNodesInPath) + paramsList = [] + pathstr = mk_path_refine(child, metadata, keyNodesInPath, False, paramsList) if actXpath in keysToLeafRefObjSet: return @@ -452,7 +465,7 @@ def walk_child(child): swaggerDict["definitions"][defName_get] = OrderedDict() swaggerDict["definitions"][defName_get]["type"] = "object" swaggerDict["definitions"][defName_get]["properties"] = copy.deepcopy(payload_get) - swagger_it(child, defName_get, pathstr, payload_get, metadata, "get", defName_get) + swagger_it(child, defName_get, pathstr, payload_get, metadata, "get", defName_get, paramsList) else: swaggerDict["definitions"][defName] = OrderedDict() swaggerDict["definitions"][defName]["type"] = "object" @@ -462,7 +475,8 @@ def walk_child(child): if child.keyword == "leaf-list": metadata_leaf_list = [] keyNodesInPath_leaf_list = [] - pathstr_leaf_list = mk_path_refine(child, metadata_leaf_list, keyNodesInPath_leaf_list, True) + paramsLeafList = [] + pathstr_leaf_list = mk_path_refine(child, metadata_leaf_list, keyNodesInPath_leaf_list, True, paramsLeafList) if verb == "get": payload_get = OrderedDict() @@ -473,11 +487,11 @@ def walk_child(child): swaggerDict["definitions"][defName_get] = OrderedDict() swaggerDict["definitions"][defName_get]["type"] = "object" swaggerDict["definitions"][defName_get]["properties"] = copy.deepcopy(payload_get) - swagger_it(child, defName_get, pathstr, payload_get, metadata, verb, defName_get) + swagger_it(child, defName_get, pathstr, payload_get, metadata, verb, defName_get, paramsList) if child.keyword == "leaf-list": defName_get_leaf_list = "get" + '_llist_' + defName - swagger_it(child, defName_get, pathstr_leaf_list, payload_get, metadata_leaf_list, verb, defName_get_leaf_list) + swagger_it(child, defName_get, pathstr_leaf_list, payload_get, metadata_leaf_list, verb, defName_get_leaf_list, paramsLeafList) continue @@ -490,20 +504,21 @@ def walk_child(child): if isUriKeyInPayload(child,keyNodesInPath): continue - swagger_it(child, defName, pathstr, payload, metadata, verb) + swagger_it(child, defName, pathstr, payload, metadata, verb, False, paramsList) if verb == "delete" and child.keyword == "leaf-list": defName_del_leaf_list = "del" + '_llist_' + defName - swagger_it(child, defName, pathstr_leaf_list, payload, metadata_leaf_list, verb, defName_del_leaf_list) + swagger_it(child, defName, pathstr_leaf_list, payload, metadata_leaf_list, verb, defName_del_leaf_list, paramsLeafList) if child.keyword == "list": listMetaData = copy.deepcopy(metadata) - walk_child_for_list_base(child,actXpath,pathstr, listMetaData, defName) + listparamsList = copy.deepcopy(paramsList) + walk_child_for_list_base(child,actXpath,pathstr, listMetaData, defName, listparamsList) if hasattr(child, 'i_children'): for ch in child.i_children: walk_child(ch) -def walk_child_for_list_base(child, actXpath, pathstr, metadata, nonBaseDefName=None): +def walk_child_for_list_base(child, actXpath, pathstr, metadata, nonBaseDefName=None, paramsList=[]): payload = OrderedDict() pathstrList = pathstr.split('/') @@ -521,6 +536,8 @@ def walk_child_for_list_base(child, actXpath, pathstr, metadata, nonBaseDefName= for key in child.i_key: metadata.pop() + if len(paramsList) > 0: + paramsList.pop() add_swagger_tag(child.i_module) build_payload(child, payload, pathstr, False, "", True) @@ -542,12 +559,12 @@ def walk_child_for_list_base(child, actXpath, pathstr, metadata, nonBaseDefName= defName_get = "get" + '_' + defName if nonBaseDefName is not None: - swagger_it(child, "get" + '_' + nonBaseDefName, pathstr, payload_get, metadata, "get", defName_get) + swagger_it(child, "get" + '_' + nonBaseDefName, pathstr, payload_get, metadata, "get", defName_get, paramsList) else: swaggerDict["definitions"][defName_get] = OrderedDict() swaggerDict["definitions"][defName_get]["type"] = "object" swaggerDict["definitions"][defName_get]["properties"] = copy.deepcopy(payload_get) - swagger_it(child, defName_get, pathstr, payload_get, metadata, "get", defName_get) + swagger_it(child, defName_get, pathstr, payload_get, metadata, "get", defName_get, paramsList) else: if nonBaseDefName is None: swaggerDict["definitions"][defName] = OrderedDict() @@ -564,18 +581,18 @@ def walk_child_for_list_base(child, actXpath, pathstr, metadata, nonBaseDefName= defName_get = "get" + '_' + defName if nonBaseDefName is not None: - swagger_it(child, "get" + '_' + nonBaseDefName, pathstr, payload_get, metadata, verb, defName_get) + swagger_it(child, "get" + '_' + nonBaseDefName, pathstr, payload_get, metadata, verb, defName_get, paramsList) else: swaggerDict["definitions"][defName_get] = OrderedDict() swaggerDict["definitions"][defName_get]["type"] = "object" swaggerDict["definitions"][defName_get]["properties"] = copy.deepcopy(payload_get) - swagger_it(child, defName_get, pathstr, payload_get, metadata, verb, defName_get) + swagger_it(child, defName_get, pathstr, payload_get, metadata, verb, defName_get, paramsList) continue if nonBaseDefName is not None: - swagger_it(child, nonBaseDefName, pathstr, payload, metadata, verb, verb + '_' + defName) + swagger_it(child, nonBaseDefName, pathstr, payload, metadata, verb, verb + '_' + defName, paramsList) else: - swagger_it(child, defName, pathstr, payload, metadata, verb, verb + '_' + defName) + swagger_it(child, defName, pathstr, payload, metadata, verb, verb + '_' + defName, paramsList) def build_payload(child, payloadDict, uriPath="", oneInstance=False, Xpath="", firstCall=False, config_false=False, moduleList=[]): @@ -701,7 +718,36 @@ def build_payload(child, payloadDict, uriPath="", oneInstance=False, Xpath="", f for ch in child.i_children: build_payload(ch,childJson,uriPath, False, Xpath, False, config_false, copy.deepcopy(moduleList)) -def mk_path_refine(node, metadata, keyNodes=[], restconf_leaflist=False): +def handleDuplicateParams(node, paramMeta={}): + paramNamesList = paramMeta["paramNamesList"] + paramsList = paramMeta["paramsList"] + paramName = node.arg + paramNamesList.append(paramName) + paramNameCount = paramNamesList.count(paramName) + paramDictEntry = OrderedDict() + + if paramNameCount > 1: + origParamName = paramName + paramName = paramName + str(paramNameCount-1) + while paramName in paramNamesList: + paramNameCount = paramNameCount + 1 + paramName = origParamName + str(paramNameCount-1) + paramNamesList.append(paramName) + + paramDictEntry["uriName"] = paramName + paramDictEntry["yangName"] = node.arg + if paramName != node.arg: + paramMeta["sameParams"] = True + paramsList.append(paramDictEntry) + + return paramName + +def mk_path_refine(node, metadata, keyNodes=[], restconf_leaflist=False, paramsList=[]): + paramMeta={} + paramMeta["paramNamesList"] = [] + paramMeta["paramsList"] = [] + paramMeta["sameParams"] = False + def mk_path(node): """Returns the XPath path of the node""" if node.keyword in ['choice', 'case']: @@ -709,8 +755,9 @@ def mk_path(node): def name(node): extra = "" if node.keyword == "leaf-list" and restconf_leaflist: - extraKeys = [] - extraKeys.append('{' + node.arg + '}') + extraKeys = [] + paramName = handleDuplicateParams(node,paramMeta) + extraKeys.append('{' + paramName + '}') desc = node.search_one('description') if desc is None: desc = '' @@ -718,7 +765,7 @@ def name(node): desc = desc.arg metaInfo = OrderedDict() metaInfo["desc"] = desc - metaInfo["name"] = node.arg + metaInfo["name"] = paramName metaInfo["type"] = "string" metaInfo["format"] = "" metadata.append(metaInfo) @@ -729,8 +776,9 @@ def name(node): for index, list_key in enumerate(node.i_key): keyNodes.append(list_key) if list_key.i_leafref is not None: - keyNodes.append(list_key.i_leafref_ptr[0]) - extraKeys.append('{' + list_key.arg + '}') + keyNodes.append(list_key.i_leafref_ptr[0]) + paramName = handleDuplicateParams(list_key,paramMeta) + extraKeys.append('{' + paramName + '}') desc = list_key.search_one('description') if desc is None: desc = '' @@ -738,7 +786,7 @@ def name(node): desc = desc.arg metaInfo = OrderedDict() metaInfo["desc"] = desc - metaInfo["name"] = list_key.arg + metaInfo["name"] = paramName typeInfo = getType(list_key) if isinstance(typeInfo, tuple): @@ -786,6 +834,11 @@ def name(node): xpath = "/".join(final_xpathList) if not xpath.startswith('/'): xpath = '/' + xpath + + if paramMeta["sameParams"]: + for entry in paramMeta["paramsList"]: + paramsList.append(copy.deepcopy(entry)) + return xpath def handle_leafref(node,xpath): diff --git a/tools/swagger_codegen/go-server/templates-yang/controller-api.mustache b/tools/swagger_codegen/go-server/templates-yang/controller-api.mustache index 790f1ee6b2..15b5c77a3e 100644 --- a/tools/swagger_codegen/go-server/templates-yang/controller-api.mustache +++ b/tools/swagger_codegen/go-server/templates-yang/controller-api.mustache @@ -17,5 +17,10 @@ func {{nickname}}(w http.ResponseWriter, r *http.Request) { {{#produces}} rc.Produces.Add("{{mediaType}}") {{/produces}} + {{#vendorExtensions}} + {{#x-params}} + rc.PMap = server.NameMap{ {{#varMapping}}"{{uriName}}":"{{yangName}}", {{/varMapping}} } + {{/x-params}} + {{/vendorExtensions}} server.Process(w, r) }{{/operation}}{{/operations}}