From 1f9132db60dface799f1e9d75be8e7954588c3d7 Mon Sep 17 00:00:00 2001 From: Praveen Chaudhary Date: Thu, 5 Nov 2020 00:25:33 -0800 Subject: [PATCH] [sonic-yang]: Yang model update fields (#5577) Changes: -- ACL stage allow lower and upper. -- ACL include services leaf-list. -- PORT include pfc_asym leaf. -- PORT fec alloe none as per code. -- 3 Tests for above changes. Signed-off-by: Praveen Chaudhary pchaudhary@linkedin.com --- .../yang_model_tests/yangModelTesting.py | 79 +++++++++- .../tests/yang_model_tests/yangTest.json | 137 +++++++++++++++++- .../yang-models/sonic-acl.yang | 11 +- .../yang-models/sonic-port.yang | 8 +- .../yang-models/sonic-portchannel.yang | 4 +- 5 files changed, 227 insertions(+), 12 deletions(-) diff --git a/src/sonic-yang-models/tests/yang_model_tests/yangModelTesting.py b/src/sonic-yang-models/tests/yang_model_tests/yangModelTesting.py index e1b106a17a..5f21485a5f 100644 --- a/src/sonic-yang-models/tests/yang_model_tests/yangModelTesting.py +++ b/src/sonic-yang-models/tests/yang_model_tests/yangModelTesting.py @@ -61,6 +61,10 @@ class YangModelTesting: 'desc': 'Configure a member port in VLAN_MEMBER table which does not exist.', 'eStr': self.defaultYANGFailure['LeafRef'] }, + 'PORT_CHANNEL_TEST': { + 'desc': 'Configure a member port in PORT_CHANNEL table.', + 'eStr': self.defaultYANGFailure['None'] + }, 'VLAN_MEMEBER_WITH_NON_EXIST_VLAN': { 'desc': 'Configure vlan-id in VLAN_MEMBER table which does not exist in VLAN table.', 'eStr': self.defaultYANGFailure['LeafRef'] @@ -123,7 +127,47 @@ class YangModelTesting: }, 'INCORRECT_VLAN_NAME': { 'desc': 'INCORRECT VLAN_NAME FIELD IN VLAN TABLE.', - 'eStr': self.defaultYANGFailure['Pattern'] + 'eStr': self.defaultYANGFailure['Pattern'] + ["Vlan"] + }, + 'ACL_TABLE_MANDATORY_TYPE': { + 'desc': 'ACL_TABLE MANDATORY TYPE FIELD.', + 'eStr': self.defaultYANGFailure['Mandatory'] + ['type'] + ['ACL_TABLE'] + }, + 'ACL_TABLE_DEFAULT_VALUE_STAGE': { + 'desc': 'ACL_TABLE DEFAULT VALUE FOR STAGE FIELD.', + 'eStr': self.defaultYANGFailure['Verify'], + 'verify': {'xpath': "/sonic-acl:sonic-acl/ACL_TABLE/ACL_TABLE_LIST[ACL_TABLE_NAME='NO-NSW-PACL-V4']/ACL_TABLE_NAME", + 'key': 'sonic-acl:stage', + 'value': 'INGRESS' + } + }, + 'INCORRECT_VLAN_NAME': { + 'desc': 'INCORRECT VLAN_NAME FIELD IN VLAN TABLE.', + 'eStr': self.defaultYANGFailure['Pattern'] + ["Vlan"] + }, + 'PORT_CHANNEL_WRONG_PATTERN': { + 'desc': 'INCORRECT PORTCHANNEL_NAME IN PORT_CHANNEL TABLE.', + 'eStr': self.defaultYANGFailure['Pattern'] + ["PortChannel"] + }, + 'ACL_TABLE_STAGE_SERVICES': { + 'desc': 'ACL_TABLE LOAD STAGE SERVICES SUCCESSFULLY.', + 'eStr': self.defaultYANGFailure['Verify'], + 'verify': {'xpath': "/sonic-acl:sonic-acl/ACL_TABLE/ACL_TABLE_LIST[ACL_TABLE_NAME='NO-NSW-PACL-V4']/ACL_TABLE_NAME", + 'key': 'sonic-acl:services', + 'value': ["SNMP"] + } + }, + 'PORT_TEST': { + 'desc': 'LOAD PORT TABLE WITH FEC AND PFC_ASYM SUCCESSFULLY. VERIFY PFC_ASYM.', + 'eStr': self.defaultYANGFailure['Verify'], + 'verify': {'xpath': "/sonic-port:sonic-port/PORT/PORT_LIST[port_name='Ethernet8']/port_name", + 'key': 'sonic-port:pfc_asym', + 'value': 'on' + } + }, + 'PORT_NEG_TEST': { + 'desc': 'LOAD PORT TABLE FEC PATTERN FAILURE', + 'eStr': self.defaultYANGFailure['Pattern'] + ['rc'] } } @@ -200,7 +244,7 @@ class YangModelTesting: jInst = ijson.items(f, test) for it in jInst: jInput = jInput + json.dumps(it) - log.debug(jInput) + log.debug("Read json JIn: {}".format(jInput)) except Exception as e: printExceptionDetails() return jInput @@ -216,12 +260,37 @@ class YangModelTesting: """ Load Config Data and return Exception as String + + Parameters: + jInput (dict): input config to load. + verify (dict): contains xpath, key and value. This is used to verify, + that node tree at xpath contains correct key and value. + Example: + 'verify': {'xpath': "/sonic-acl:sonic-acl/ACL_TABLE/ACL_TABLE_LIST\ + [ACL_TABLE_NAME='NO-NSW-PACL-V4']/stage", + 'key': 'sonic-acl:stage', + 'value': 'INGRESS' + } """ - def loadConfigData(self, jInput): + def loadConfigData(self, jInput, verify=None): s = "" try: node = self.ctx.parse_data_mem(jInput, ly.LYD_JSON, \ ly.LYD_OPT_CONFIG | ly.LYD_OPT_STRICT) + # verify the data tree if asked + if verify is not None: + xpath = verify['xpath'] + log.debug("Verify xpath: {}".format(xpath)) + set = node.find_path(xpath) + for dnode in set.data(): + if (xpath == dnode.path()): + log.debug("Verify dnode: {}".format(dnode.path())) + data = dnode.print_mem(ly.LYD_JSON, ly.LYP_WITHSIBLINGS \ + | ly.LYP_FORMAT | ly.LYP_WD_ALL) + data = json.loads(data) + log.debug("Verify data: {}".format(data)) + assert (data[verify['key']] == verify['value']) + s = 'verified' except Exception as e: s = str(e) log.debug(s) @@ -236,9 +305,9 @@ class YangModelTesting: self.logStartTest(desc) jInput = self.readJsonInput(test) # load the data, expect a exception with must condition failure - s = self.loadConfigData(jInput) + s = self.loadConfigData(jInput, self.ExceptionTests[test].get('verify')) eStr = self.ExceptionTests[test]['eStr'] - log.debug(eStr) + log.debug("eStr: {}".format(eStr)) if len(eStr) == 0 and s != "": raise Exception("{} in not empty".format(s)) elif (sum(1 for str in eStr if str not in s) == 0): diff --git a/src/sonic-yang-models/tests/yang_model_tests/yangTest.json b/src/sonic-yang-models/tests/yang_model_tests/yangTest.json index b42d1cf24c..cd0dafd9e8 100644 --- a/src/sonic-yang-models/tests/yang_model_tests/yangTest.json +++ b/src/sonic-yang-models/tests/yang_model_tests/yangTest.json @@ -108,6 +108,47 @@ } }, + "PORT_CHANNEL_TEST": { + "sonic-portchannel:sonic-portchannel": { + "sonic-portchannel:PORTCHANNEL": { + "PORTCHANNEL_LIST": [{ + "portchannel_name": "PortChannel0001", + "admin_status": "up", + "members": [ + "Ethernet0" + ], + "min_links": "1", + "mtu": "9100" + }] + } + }, + "sonic-port:sonic-port": { + "sonic-port:PORT": { + "PORT_LIST": [{ + "port_name": "Ethernet0", + "alias": "eth0", + "description": "Ethernet0", + "speed": 25000, + "mtu": 9000, + "lanes": "65", + "admin_status": "up" + }] + } + } + }, + + "PORT_CHANNEL_WRONG_PATTERN": { + "sonic-portchannel:sonic-portchannel": { + "sonic-portchannel:PORTCHANNEL": { + "PORTCHANNEL_LIST": [{ + "portchannel_name": "PortChannel11001", + "admin_status": "up", + "mtu": "9100" + }] + } + } + }, + "VLAN_MEMEBER_WITH_NON_EXIST_VLAN": { "sonic-vlan:sonic-vlan": { "sonic-vlan:VLAN_MEMBER": { @@ -557,6 +598,7 @@ "lanes": "65", "description": "Ethernet8", "speed": 25000, + "fec": "rs", "mtu": 9000, "admin_status": "up" }] @@ -564,6 +606,42 @@ } }, + "PORT_TEST": { + "sonic-port:sonic-port": { + "sonic-port:PORT": { + "PORT_LIST": [{ + "port_name": "Ethernet8", + "alias": "eth8", + "lanes": "65", + "description": "Ethernet8", + "speed": 25000, + "fec": "rs", + "mtu": 9000, + "admin_status": "up", + "pfc_asym": "on" + }] + } + } + }, + + "PORT_NEG_TEST": { + "sonic-port:sonic-port": { + "sonic-port:PORT": { + "PORT_LIST": [{ + "port_name": "Ethernet8", + "alias": "eth8", + "lanes": "65", + "description": "Ethernet8", + "speed": 25000, + "fec": "rc", + "mtu": 9000, + "admin_status": "up", + "pfc_asym": "off" + }] + } + } + }, + "ACL_RULE_ARP_TYPE_ICMPV6_CODE_MISMATCH": { "sonic-acl:sonic-acl": { "sonic-acl:ACL_RULE": { @@ -612,6 +690,43 @@ } }, + "ACL_TABLE_MANDATORY_TYPE": { + "sonic-acl:sonic-acl": { + "sonic-acl:ACL_TABLE": { + "ACL_TABLE_LIST": [{ + "ACL_TABLE_NAME": "NO-NSW-PACL-V4", + "policy_desc": "Filter IPv4", + "stage": "EGRESS" + }] + } + } + }, + + "ACL_TABLE_DEFAULT_VALUE_STAGE": { + "sonic-acl:sonic-acl": { + "sonic-acl:ACL_TABLE": { + "ACL_TABLE_LIST": [{ + "ACL_TABLE_NAME": "NO-NSW-PACL-V4", + "policy_desc": "Filter IPv4", + "type": "L3" + }] + } + } + }, + + "ACL_TABLE_STAGE_SERVICES": { + "sonic-acl:sonic-acl": { + "sonic-acl:ACL_TABLE": { + "ACL_TABLE_LIST": [{ + "ACL_TABLE_NAME": "NO-NSW-PACL-V4", + "policy_desc": "Filter IPv4", + "type": "L3", + "stage": "ingress", + "services": ["SNMP"] + }] + } + } + }, "ACL_RULE_WRONG_INNER_ETHER_TYPE": { "sonic-acl:sonic-acl": { "sonic-acl:ACL_RULE": { @@ -661,6 +776,24 @@ }, "SAMPLE_CONFIG_DB_JSON": { + "PORTCHANNEL": { + "PortChannel0003": { + "admin_status": "up", + "min_links": "1", + "members": [ + "Ethernet1" + ], + "mtu": "9100" + }, + "PortChannel0004": { + "admin_status": "up", + "min_links": "1", + "members": [ + "Ethernet2" + ], + "mtu": "9100" + } + }, "VLAN_INTERFACE": { "Vlan111": {}, "Vlan777": {}, @@ -1196,7 +1329,9 @@ "Ethernet26", "Ethernet27", "Ethernet24" - ] + ], + "stage": "INGRESS", + "services": ["SNMP", "SSH"] }, "V6-ACL-TBLE": { "type": "L3V6", diff --git a/src/sonic-yang-models/yang-models/sonic-acl.yang b/src/sonic-yang-models/yang-models/sonic-acl.yang index ec8a485b48..dcddd247e1 100644 --- a/src/sonic-yang-models/yang-models/sonic-acl.yang +++ b/src/sonic-yang-models/yang-models/sonic-acl.yang @@ -252,14 +252,19 @@ module sonic-acl { } leaf type { + mandatory true; type stypes:acl_table_type; } leaf stage { - type enumeration { - enum INGRESS; - enum EGRESS; + type string { + pattern "ingress|egress|INGRESS|EGRESS"; } + default "INGRESS"; + } + + leaf-list services { + type string; } leaf-list ports { diff --git a/src/sonic-yang-models/yang-models/sonic-port.yang b/src/sonic-yang-models/yang-models/sonic-port.yang index 88fcf72dad..574780dcf0 100644 --- a/src/sonic-yang-models/yang-models/sonic-port.yang +++ b/src/sonic-yang-models/yang-models/sonic-port.yang @@ -93,7 +93,13 @@ module sonic-port{ leaf fec { type string { - pattern "rc|fc|None"; + pattern "rs|fc|none"; + } + } + + leaf pfc_asym { + type string { + pattern "on|off"; } } } /* end of list PORT_LIST */ diff --git a/src/sonic-yang-models/yang-models/sonic-portchannel.yang b/src/sonic-yang-models/yang-models/sonic-portchannel.yang index 8f758fd51c..8d27398c61 100644 --- a/src/sonic-yang-models/yang-models/sonic-portchannel.yang +++ b/src/sonic-yang-models/yang-models/sonic-portchannel.yang @@ -43,9 +43,9 @@ module sonic-portchannel { key "portchannel_name"; - ext:key-regex-configdb-to-yang "^(Ethernet[0-9]+)$"; + ext:key-regex-configdb-to-yang "^(PortChannel[0-9]{1,4})$"; - ext:key-regex-yang-to-configdb ""; + ext:key-regex-yang-to-configdb ""; leaf portchannel_name { type string {