Skip to content

Commit 95ce88c

Browse files
faraazbrcmsachinhollambalachandarmaheshwari-mayankshyam-brcm
committed
CVL Infra Enhancments and Fixes
1. Enhancement - Support TABLE keys modelled as container 2. Enhancement - DBAL CountKeysPattern API 3. Optimisation: removing libyang syntax checks for Full entry delete 4. Enhancement - CVL support for SONiC YANG table with distinct YANG 4.1 Enhancement - For multi-list tables correct Redis pattern and sep are matched and picked. 4.2 Fix - The cvl code to build table expression based on YANG list name instead of table name. 4.3 Fix - CVL maintains tableInfo using a LIST name, fixed the inconsistent 4.4 Enhancement - code to lookup using list name instead of table name. 4.5 Fix - recognition of table and fields if the table contains mutiple lists and if table name as prefix is not present in any of the list name 5. Optimisation: removing extra checks in CVL for non existing fields for update operation 6. Fixes: CVL does not honours "not equal" operator in must expression predicate 7. Fixes: clear depDataCache along with semantic cache, when CVL validation completes for clen state. ```text CVL maintains a separate cache to check if dependent data is already to the semantic cache. If the entry is present in this cache, the semantic cache is not updated. When we clear clear the semantic cache after every ValidateEditConfig we also need to clear depDataCache. ``` 8. Fixes: clear Xpath engine cache. ```text CVL maintains a seesion level cache for semantic validation, this cache generates entry for table each time they are operated on. As a result this cache contains duplicate entries for a table and in some cases it creates a stale entries for leaf, if they are deleted in the Latest request. ``` 9 Fixes: stale entries in semantic documents ```text CVL maintains a cache of semantic document at the session level. If Delete for an entry is successful, the cache still contains a deleted entry, this is resulting in must expression failure for count cases, the logic in count() considers this entry in to consideration. Therefore cache is cleared for the deleted entry. - Also modified addYangDataForMustExp() to avoid using global cache and use CVL wrapper for DBAL. - Modified fetchTableDataToTmpCache() to use CVL wrapper for DBAL's pipeline. ``` 10: Fixes: Incorrect match for depdata in checkDeleteInRequestCache ```text For find in request key, case - T2*|K1. If the non-delete configuration exists for dependent data in the Requestcache, its getting matched, and cvl considers its already present in deleteCache and therefore ignores validation. modified the condition to match only if entry is deleted. Further enhanced the code for find in request hash-field case - T2*|K2:{H1: K1} to match correcly for UPDATE cases. Also in case of leaflist. ``` 11: Enhancement: Use DBAL's CVL wrapper for pipeline - All pipelines were modified use CVL's DB wrapper. 12: Enhancement: Use CVL's DB wrapper in validateLeafref and fixes for multi-key table instance 13: Fixes - handle incremental build and stale files removal - Fixed yin generator ```text Tool does not write if the file is not modified and writes only when yin modified or added as new. Also it removes any stale yin files (if present) ``` 14. Enhancement: min-elements support for leaf-list 15. Enhancement - Advanced search functions in cvl DBAccess 16. Go test enhancements 17. Update the test YANGs with more complex cases. 18. Enhancement: changes to the count and filter lua scripts to check both the db and candidate config data; modified the count and lookup 19. Enhancement: Added Pipe query support for HGetAll, HGet, HMGet; NewValidationSession, cvlDBAccess changes, removing validatedDataQuery 20. Fixes: Modify the session cache type from interface to map[string]interface in the custom validations, and used specific cache key name to access its own cache to avoid overwriting the same cache object by other module validation code 21. Enhancement: Added DB access adapter like APIs for redis APIs in CVL layer to access the DB access methods from the CVL layer. 22. Fixes: Added support for NULL field in the Keys, Exists API, fixed merging issue in HGetAll, HGet, HMGet in case of delete operation type 23. Fixes: Made changes to handle the redis.Nil error returned by redis client API. 24. Fixes: Leafref check should check for all DELETE and CREATE of referred configs in request cache. 25. Fixes: Removed DB ping call in CVL whenever a new DB client is created. 26. Enhacement: Debugging and log enhancement. 27. Enhancement: CVL logs to appear in Rest-server logs. 28. Improved CVL performance for bulk configs like ACL rules creation. ```text For evaluation of leafref, When and Must expressions, CVL queries dependent data and merge with config data and prepares im-memory XML to be evaluated by XPath engine. The 'addDependentData" call was adding same dependent data multiple whenever it has to evaluate leafref, when or must expression. When multiple ACL Rules within same Acl-set are configured in single request, CVL was adding Acl-set multiple times dues to which XML size becomes too huge and XPath engines takes long to evaluate. For 750 Acl rules creation there is 95% improvement in performance. ``` 29. Added support for multiple custom validation callbacks per node in CVL 30. Fixes: or Replace operations, before performing semantic validation on Update request, delete fields from yang tree that are provided with Delete request. 31. Enhancement: Added new extension to define dependency between tables. ```text This new extension 'dependent-on <list-name>' has to be used when dependencies between tables can't be defined using leafref. This has to be added under list. It should not be used under container or leaf/leaf-list nodes. Only one list-name can be added to this extension. ``` 32. Fixes: When mandatory node is getting deleted during cascade-delete, entire entry to be deleted. So find dependent entries in this entry and mark them too for delete. 33. Fixed memory leak observed in CVL CGo code that uses libyang third party library for Syntax validation. Co-authored-by: Mohammed Faraaz C <[email protected]> Co-authored-by: Sachin Holla <[email protected]> Co-authored-by: Balachandar Mani <[email protected]> Co-authored-by: Mayank Maheshwari <[email protected]> Co-authored-by: Shyam Mohan <[email protected]>
1 parent a16b59b commit 95ce88c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+6424
-3865
lines changed

azure-pipelines.yml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,10 @@ stages:
9090
STATUS=0
9191
DEBDIR=$(realpath debian/sonic-mgmt-common)
9292
93-
[[ -f tools/test/database_config.json ]] && \
94-
export DB_CONFIG_PATH=${PWD}/tools/test/database_config.json
93+
# Update unixsocket path in database_config.json
94+
tools/test/dbconfig.py -o build/tests/database_config.json
95+
export DB_CONFIG_PATH=${PWD}/build/tests/database_config.json
96+
9597
# Run CVL tests
9698
9799
pushd build/tests/cvl

cvl/Makefile

Lines changed: 41 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -20,67 +20,85 @@
2020
GO?=go
2121
SRC_FILES=$(shell find . -name '*.go' | grep -v '_test.go' | grep -v '/tests/')
2222
TEST_FILES=$(wildcard *_test.go)
23-
TOP_DIR := ..
24-
BUILD_DIR:=$(TOP_DIR)/build/cvl
23+
TOPDIR ?= ..
24+
BUILD_DIR:=$(TOPDIR)/build/cvl
25+
26+
CVL_TEST_DIR = $(TOPDIR)/build/tests/cvl
27+
CVL_TEST_BIN = $(CVL_TEST_DIR)/cvl.test
28+
CVL_TEST_SCHEMA_DIR = $(CVL_TEST_DIR)/testdata/schema
29+
CVL_TEST_CONFIG = $(CVL_TEST_DIR)/cvl_cfg.json
30+
CVL_TEST_DB_CONFIG = $(CVL_TEST_DIR)/database_config.json
2531

2632
CVL_SCHEMA_DIR = $(BUILD_DIR)/schema
27-
CVL_SCHEMA = $(CVL_SCHEMA_DIR)/.done
28-
SONIC_YANG_DIR = $(TOP_DIR)/build/yang/sonic
33+
CVL_SCHEMA = $(CVL_SCHEMA_DIR)/.done
34+
SONIC_YANG_DIR = $(TOPDIR)/build/yang/sonic
2935
SONIC_YANG_FILES = $(shell find $(SONIC_YANG_DIR) -name '*.yang')
3036
YANG_SRC_DIR = ../models/yang
3137

32-
CVL_TEST_DIR = $(TOP_DIR)/build/tests/cvl
33-
CVL_TEST_BIN = $(CVL_TEST_DIR)/cvl.test
34-
CVL_TEST_SCHEMA_DIR = $(CVL_TEST_DIR)/testdata/schema
35-
CVL_TEST_SCHEMA = $(CVL_TEST_SCHEMA_DIR)/.done
36-
CVL_TEST_YANGS = $(wildcard testdata/schema/*.yang)
37-
CVL_TEST_YANGS += $(wildcard $(YANG_SRC_DIR)/sonic/common/*.yang)
38+
SONIC_YANG_COMMON := $(TOPDIR)/models/yang/sonic/common
39+
CVL_TEST_SCHEMA := $(CVL_TEST_SCHEMA_DIR)/.done
40+
CVL_TEST_YANGS = $(shell find testdata/schema -name '*.yang')
41+
CVL_TEST_YANGS += $(wildcard $(SONIC_YANG_COMMON)/*.yang)
3842

39-
DEFAULT_TARGETS = $(CVL_SCHEMA)
43+
ifdef DEBUG
44+
GOFLAGS += -gcflags="all=-N -l"
45+
endif
46+
47+
DEFAULT_TARGETS = $(CVL_SCHEMA) $(STATIC_CHECK) $(FORMAT_CHECK)
4048
ifeq ($(NO_TEST_BINS),)
41-
DEFAULT_TARGETS += $(CVL_TEST_BIN)
49+
DEFAULT_TARGETS += $(CVL_TEST_BIN) $(CVL_TEST_SCHEMA)
4250
endif
4351

4452
all: $(DEFAULT_TARGETS)
4553

46-
.SECONDEXPANSION:
47-
4854
.PRECIOUS: %/.
4955
%/.:
5056
mkdir -p $@
5157

52-
$(CVL_TEST_BIN): $(TEST_FILES) $(SRC_FILES) $(CVL_TEST_SCHEMA)
53-
cp -r testdata/*.json $(@D)/testdata
54-
$(GO) test -mod=vendor -cover -coverpkg=../cvl,../cvl/internal/util,../cvl/internal/yparser -c ../cvl -o $@
58+
.SECONDEXPANSION:
5559

5660
.PHONY: schema
5761
schema: $(CVL_SCHEMA)
5862

5963
$(CVL_SCHEMA): $(SONIC_YANG_FILES) | $$(@D)/.
60-
$(TOP_DIR)/tools/pyang/generate_yin.py \
64+
tools/generate_yin.py \
6165
--path=$(SONIC_YANG_DIR) \
6266
--path=$(YANG_SRC_DIR)/common \
6367
--out-dir=$(@D)
6468
touch $@
6569

70+
$(CVL_TEST_BIN): $(TEST_FILES) $(SRC_FILES) | $$(@D)/testdata/.
71+
cp -r testdata/*.json $(@D)/testdata
72+
$(GO) test -mod=vendor -cover -coverpkg=../cvl,../cvl/internal/util,../cvl/internal/yparser -c ../cvl -o $@
73+
6674
.PHONY: test-schema
6775
test-schema: $(CVL_TEST_SCHEMA)
6876

6977
$(CVL_TEST_SCHEMA): $(CVL_TEST_YANGS) | $$(@D)/.
70-
$(TOP_DIR)/tools/pyang/generate_yin.py \
78+
tools/generate_yin.py \
7179
--path=testdata/schema \
7280
--path=$(YANG_SRC_DIR)/common \
7381
--path=$(YANG_SRC_DIR)/sonic/common \
7482
--out-dir=$(@D)
7583
touch $@
7684

77-
gotest: $(CVL_TEST_SCHEMA)
78-
CVL_CFG_FILE=$(abspath .)/conf/cvl_cfg.json \
79-
CVL_SCHEMA_PATH=$(abspath $(CVL_TEST_SCHEMA_DIR)) \
85+
$(CVL_TEST_CONFIG): conf/cvl_cfg.json
86+
sed -E 's/((TRACE|LOG).*)\"false\"/\1\"true\"/' conf/cvl_cfg.json > $@
87+
88+
$(CVL_TEST_DB_CONFIG): $(TOPDIR)/tools/test/database_config.json
89+
$(TOPDIR)/tools/test/dbconfig.py -o $@
90+
91+
gotest: $(CVL_TEST_SCHEMA) $(CVL_TEST_CONFIG) $(CVL_TEST_DB_CONFIG)
92+
CVL_CFG_FILE=$(abspath $(CVL_TEST_CONFIG)) \
93+
CVL_SCHEMA_PATH=$(CVL_TEST_SCHEMA_DIR) \
94+
DB_CONFIG_PATH=$(abspath $(CVL_TEST_DB_CONFIG)) \
8095
tests/run_test.sh
8196

8297
clean:
83-
$(RM) -r $(CVL_TEST_DIR) $(BUILD_DIR)
98+
make -C tests clean
99+
$(RM) -r $(BUILD_DIR)
100+
$(RM) -r $(wildcard $(PKG_BUILD_DIR)/*/cvl)
101+
$(RM) -r $(CVL_TEST_DIR)
84102

85103
cleanall:clean
86104

cvl/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ Below steps need to be done to enable CVL logging.
2424
{
2525
"TRACE_CACHE": "true",
2626
"TRACE_LIBYANG": "true",
27-
"TRACE_YPARSER": "true",
27+
"TRACE_YPARSER": "true",
2828
"TRACE_CREATE": "true",
2929
"TRACE_UPDATE": "true",
3030
"TRACE_DELETE": "true",

cvl/common/db_utils.go

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package common
2+
3+
// KeyMatch checks if the value matches a key pattern.
4+
// vIndex and pIndex are start positions of value and pattern strings to match.
5+
// Mimics redis pattern matcher - i.e, glob like pattern matcher which
6+
// matches '/' against wildcard.
7+
// Supports '*' and '?' wildcards with '\' as the escape character.
8+
// '*' matches any char sequence or none; '?' matches exactly one char.
9+
// Character classes are not supported (redis supports it).
10+
func KeyMatch(value, pattern string) bool {
11+
return keyMatch(value, 0, pattern, 0)
12+
}
13+
14+
func keyMatch(value string, vIndex int, pattern string, pIndex int) bool {
15+
for pIndex < len(pattern) {
16+
switch pattern[pIndex] {
17+
case '*':
18+
// Skip successive *'s in the pattern
19+
pIndex++
20+
for pIndex < len(pattern) && pattern[pIndex] == '*' {
21+
pIndex++
22+
}
23+
// Pattern ends with *. Its a match always
24+
if pIndex == len(pattern) {
25+
return true
26+
}
27+
// Try to match remaining pattern with every value substring
28+
for ; vIndex < len(value); vIndex++ {
29+
if keyMatch(value, vIndex, pattern, pIndex) {
30+
return true
31+
}
32+
}
33+
// No match for remaining pattern
34+
return false
35+
36+
case '?':
37+
// Accept any char.. there should be at least one
38+
if vIndex >= len(value) {
39+
return false
40+
}
41+
vIndex++
42+
pIndex++
43+
44+
case '\\':
45+
// Do not treat \ as escape char if it is the last pattern char.
46+
// Redis commands behave this way.
47+
if pIndex+1 < len(pattern) {
48+
pIndex++
49+
}
50+
fallthrough
51+
52+
default:
53+
if vIndex >= len(value) || pattern[pIndex] != value[vIndex] {
54+
return false
55+
}
56+
vIndex++
57+
pIndex++
58+
}
59+
}
60+
61+
// All pattern chars have been compared.
62+
// It is a match if all value chars have been exhausted too.
63+
return (vIndex == len(value))
64+
}

cvl/custom_validation/common.go

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,13 @@
2020
package custom_validation
2121

2222
import (
23+
"fmt"
2324
"reflect"
2425

2526
"github.com/Azure/sonic-mgmt-common/cvl/common"
2627
"github.com/Azure/sonic-mgmt-common/cvl/internal/util"
2728
"github.com/Azure/sonic-mgmt-common/cvl/internal/yparser"
2829
"github.com/antchfx/xmlquery"
29-
"github.com/go-redis/redis/v7"
3030
)
3131

3232
type CustomValidation struct{}
@@ -85,6 +85,7 @@ type CVLEditConfigData struct {
8585
VOp CVLOperation //Operation type
8686
Key string //Key format : "PORT|Ethernet4"
8787
Data map[string]string //Value : {"alias": "40GE0/28", "mtu" : 9100, "admin_status": down}
88+
ReplaceOp bool
8889
}
8990

9091
// CVLErrorInfo CVL Error Structure
@@ -101,7 +102,8 @@ type CVLErrorInfo struct {
101102
}
102103

103104
type CustValidationCache struct {
104-
Data interface{}
105+
Data map[string]interface{}
106+
Hint map[string]interface{}
105107
}
106108

107109
// CustValidationCtxt Custom validation context passed to custom validation function
@@ -112,7 +114,7 @@ type CustValidationCtxt struct {
112114
YNodeVal string //YANG node value, leaf-list will have "," separated value
113115
YCur *xmlquery.Node //YANG data tree
114116
SessCache *CustValidationCache //Session cache, can be used for storing data, persistent in session
115-
RClient *redis.Client //Redis client
117+
RClient common.DBAccess //Db access interface
116118
}
117119

118120
// Search criteria for advanced lookup through DBAccess APIs
@@ -137,3 +139,23 @@ func InvokeCustomValidation(cv *CustomValidation, name string, args ...interface
137139

138140
return CVLErrorInfo{ErrCode: CVL_SUCCESS}
139141
}
142+
143+
func (err CVLErrorInfo) String() string {
144+
var s string
145+
if CVL_SUCCESS == err.ErrCode {
146+
s = "Success"
147+
} else {
148+
s = fmt.Sprintf("ErrCode[%v]: ErrDetails[%s], Msg[%s], ConstraintErrMsg[%s], Table[%s:%v], Field[%s:%s]", err.ErrCode, err.CVLErrDetails, err.Msg, err.ConstraintErrMsg, err.TableName, err.Keys, err.Field, err.Value)
149+
}
150+
151+
return s
152+
}
153+
154+
func (vc *CustValidationCtxt) ContainsAnyFields(fields ...string) bool {
155+
for _, f := range fields {
156+
if _, ok := vc.CurCfg.Data[f]; ok {
157+
return true
158+
}
159+
}
160+
return false
161+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
////////////////////////////////////////////////////////////////////////////////
2+
// //
3+
// Copyright 2019 Broadcom. The term Broadcom refers to Broadcom Inc. and/or //
4+
// its subsidiaries. //
5+
// //
6+
// Licensed under the Apache License, Version 2.0 (the "License"); //
7+
// you may not use this file except in compliance with the License. //
8+
// You may obtain a copy of the License at //
9+
// //
10+
// http://www.apache.org/licenses/LICENSE-2.0 //
11+
// //
12+
// Unless required by applicable law or agreed to in writing, software //
13+
// distributed under the License is distributed on an "AS IS" BASIS, //
14+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
15+
// See the License for the specific language governing permissions and //
16+
// limitations under the License. //
17+
// //
18+
////////////////////////////////////////////////////////////////////////////////
19+
20+
//go:build test
21+
// +build test
22+
23+
package custom_validation
24+
25+
func (t *CustomValidation) ValidateIfExtraFieldValidationCalled(
26+
vc *CustValidationCtxt) CVLErrorInfo {
27+
vc.SessCache.Hint["ExtraFieldValidationCalled"] = true
28+
return CVLErrorInfo{ErrCode: CVL_SUCCESS}
29+
30+
}
31+
32+
func (t *CustomValidation) ValidateIfListLevelValidationCalled(
33+
vc *CustValidationCtxt) CVLErrorInfo {
34+
vc.SessCache.Hint["ListLevelValidationCalled"] = true
35+
return CVLErrorInfo{ErrCode: CVL_SUCCESS}
36+
37+
}

0 commit comments

Comments
 (0)