Skip to content

Commit 9d24a34

Browse files
authored
CVL Changes #2: YValidator infra changes for evaluating xpath expression (#19)
Why I did it Adding YValidator support so that xpath expression (must/when/leafref) can be evaluated using custom xpath engine. Custom xpath engine will be integrated in subsequent PR. How I did it N/A. Please refer to change log for more details. How to verify it No specific test cases to be executed. Run cvl go test cases using - 'make cvl-test'. Description for the changelog Modifying cvl.go for adding new data structure to store cache in CVL session cache, add YValidator data type. Adding API to get Redis table name from YANG list. Modifying cvl_api.go and cvl_cache.go due to change in session cache. Modifying cvl_syntax.go due to change in API name. Modifying cvl_semantics.go to add various API which can operate on YValidator nodes.
1 parent f3fc40f commit 9d24a34

File tree

5 files changed

+714
-16
lines changed

5 files changed

+714
-16
lines changed

cvl/cvl.go

+48-7
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ type modelTableInfo struct {
7878
//multiple leafref possible for union
7979
mustExp map[string]string
8080
tablesForMustExp map[string]CVLOperation
81+
dfltLeafVal map[string]string //map of leaf names and default value
8182
}
8283

8384

@@ -94,14 +95,21 @@ type CVLErrorInfo struct {
9495
ErrAppTag string
9596
}
9697

98+
// Struct for request data and YANG data
99+
type requestCacheType struct {
100+
reqData CVLEditConfigData
101+
yangData *xmlquery.Node
102+
}
103+
97104
type CVL struct {
98105
redisClient *redis.Client
99106
yp *yparser.YParser
100107
tmpDbCache map[string]interface{} //map of table storing map of key-value pair
101-
requestCache map[string]map[string][]CVLEditConfigData //Cache of validated data,
102-
//might be used as dependent data in next request
108+
requestCache map[string]map[string][]*requestCacheType//Cache of validated data,
109+
//per table, per key. Can be used as dependent data in next request
103110
batchLeaf string
104111
chkLeafRefWithOthCache bool
112+
yv *YValidator //Custom YANG validator for validating external dependencies
105113
}
106114

107115
type modelNamespace struct {
@@ -205,6 +213,11 @@ func Debug(on bool) {
205213
yparser.Debug(on)
206214
}
207215

216+
// isLeafListNode checks if the xml node represents a leaf-list field
217+
func isLeafListNode(node *xmlquery.Node) bool {
218+
return len(node.Attr) != 0 && node.Attr[0].Name.Local == "leaf-list"
219+
}
220+
208221
//Get attribute value of xml node
209222
func getXmlNodeAttr(node *xmlquery.Node, attrName string) string {
210223
for _, attr := range node.Attr {
@@ -216,6 +229,14 @@ func getXmlNodeAttr(node *xmlquery.Node, attrName string) string {
216229
return ""
217230
}
218231

232+
// getNodeName returns database field name for the xml node.
233+
func getNodeName(node *xmlquery.Node) string {
234+
if isLeafListNode(node) {
235+
return node.Data + "@"
236+
}
237+
return node.Data
238+
}
239+
219240
//Store useful schema data during initialization
220241
func storeModelInfo(modelFile string, module *yparser.YParserModule) { //such model info can be maintained in C code and fetched from there
221242
f, err := os.Open(CVL_SCHEMA + modelFile)
@@ -394,6 +415,20 @@ func storeModelInfo(modelFile string, module *yparser.YParserModule) { //such mo
394415
}
395416
}
396417

418+
// Get YANG list to Redis table name
419+
func getYangListToRedisTbl(yangListName string) string {
420+
if (strings.HasSuffix(yangListName, "_LIST")) {
421+
yangListName = yangListName[0:len(yangListName) - len("_LIST")]
422+
}
423+
tInfo, exists := modelInfo.tableInfo[yangListName]
424+
425+
if exists && (tInfo.redisTableName != "") {
426+
return tInfo.redisTableName
427+
}
428+
429+
return yangListName
430+
}
431+
397432
//Find the tables names in must expression, these tables data need to be fetched
398433
//during semantic validation
399434
func addTableNamesForMustExp() {
@@ -475,24 +510,30 @@ func splitRedisKey(key string) (string, string) {
475510
return tblName, key[prefixLen:]
476511
}
477512

478-
//Get the YANG list name from Redis key
513+
//Get the YANG list name from Redis key and table name
479514
//This just returns same YANG list name as Redis table name
480515
//when 1:1 mapping is there. For one Redis table to
481516
//multiple YANG list, it returns appropriate YANG list name
482517
//INTERFACE:Ethernet12 returns ==> INTERFACE
483518
//INTERFACE:Ethernet12:1.1.1.0/32 ==> INTERFACE_IPADDR
484-
func getRedisKeyToYangList(tableName, key string) string {
519+
func getRedisTblToYangList(tableName, key string) (yangList string) {
520+
defer func() {
521+
pYangList := &yangList
522+
TRACE_LOG(INFO_API, TRACE_SYNTAX, "Got YANG list '%s' " +
523+
"from Redis Table '%s', Key '%s'", *pYangList, tableName, key)
524+
}()
525+
485526
mapArr, exists := modelInfo.redisTableToYangList[tableName]
486527

487-
if exists == false {
528+
if !exists || (len(mapArr) == 1) { //no map or only one
488529
//1:1 mapping case
489530
return tableName
490531
}
491532

492533
//As of now determine the mapping based on number of keys
493534
var foundIdx int = -1
494535
numOfKeys := 1 //Assume only one key initially
495-
for keyDelim, _ := range modelInfo.allKeyDelims {
536+
for keyDelim := range modelInfo.allKeyDelims {
496537
foundIdx = strings.Index(key, keyDelim)
497538
if (foundIdx >= 0) {
498539
//Matched with key delim
@@ -505,7 +546,7 @@ func getRedisKeyToYangList(tableName, key string) string {
505546
//Check which list has number of keys as 'numOfKeys'
506547
for i := 0; i < len(mapArr); i++ {
507548
tblInfo, exists := modelInfo.tableInfo[mapArr[i]]
508-
if exists == true {
549+
if exists {
509550
if (len(tblInfo.keys) == numOfKeys) {
510551
//Found the YANG list matching the number of keys
511552
return mapArr[i]

cvl/cvl_api.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ func Finish() {
195195
func ValidationSessOpen() (*CVL, CVLRetCode) {
196196
cvl := &CVL{}
197197
cvl.tmpDbCache = make(map[string]interface{})
198-
cvl.requestCache = make(map[string]map[string][]CVLEditConfigData)
198+
cvl.requestCache = make(map[string]map[string][]*requestCacheType)
199199
cvl.yp = &yparser.YParser{}
200200

201201
if (cvl == nil || cvl.yp == nil) {
@@ -324,10 +324,10 @@ func (c *CVL) ValidateEditConfig(cfgData []CVLEditConfigData) (CVLErrorInfo, CVL
324324
reqTbl, exists := c.requestCache[tbl]
325325
if (exists == false) {
326326
//Create new table key data
327-
reqTbl = make(map[string][]CVLEditConfigData)
327+
reqTbl = make(map[string][]*requestCacheType)
328328
}
329329
cfgDataItemArr, _ := reqTbl[key]
330-
cfgDataItemArr = append(cfgDataItemArr, cfgDataItem)
330+
cfgDataItemArr = append(cfgDataItemArr, &requestCacheType{cfgDataItem, nil})
331331
reqTbl[key] = cfgDataItemArr
332332
c.requestCache[tbl] = reqTbl
333333

@@ -431,7 +431,7 @@ func (c *CVL) ValidateEditConfig(cfgData []CVLEditConfigData) (CVLErrorInfo, CVL
431431
deletedInSameSession := false
432432
if tbl != "" && key != "" {
433433
for _, cachedCfgData := range c.requestCache[tbl][key] {
434-
if cachedCfgData.VOp == OP_DELETE {
434+
if cachedCfgData.reqData.VOp == OP_DELETE {
435435
deletedInSameSession = true
436436
break
437437
}

cvl/cvl_cache.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,10 @@ func (c *CVL) fetchDataFromRequestCache(tableName string, key string) (d map[str
4646
if (cfgDataArr != nil) {
4747
for _, cfgReqData := range cfgDataArr {
4848
//Delete request doesn't have depedent data
49-
if (cfgReqData.VOp == OP_CREATE) {
50-
return cfgReqData.Data, false
51-
} else if (cfgReqData.VOp == OP_UPDATE) {
52-
return cfgReqData.Data, true
49+
if (cfgReqData.reqData.VOp == OP_CREATE) {
50+
return cfgReqData.reqData.Data, false
51+
} else if (cfgReqData.reqData.VOp == OP_UPDATE) {
52+
return cfgReqData.reqData.Data, true
5353
}
5454
}
5555
}

0 commit comments

Comments
 (0)