Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CVL Changes #2: YValidator infra changes for evaluating xpath expression #19

Merged
merged 9 commits into from
Aug 10, 2020
55 changes: 48 additions & 7 deletions cvl/cvl.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ type modelTableInfo struct {
//multiple leafref possible for union
mustExp map[string]string
tablesForMustExp map[string]CVLOperation
dfltLeafVal map[string]string //map of leaf names and default value
}


Expand All @@ -94,14 +95,21 @@ type CVLErrorInfo struct {
ErrAppTag string
}

// Struct for request data and YANG data
type requestCacheType struct {
reqData CVLEditConfigData
yangData *xmlquery.Node
}

type CVL struct {
redisClient *redis.Client
yp *yparser.YParser
tmpDbCache map[string]interface{} //map of table storing map of key-value pair
requestCache map[string]map[string][]CVLEditConfigData //Cache of validated data,
//might be used as dependent data in next request
requestCache map[string]map[string][]*requestCacheType//Cache of validated data,
//per table, per key. Can be used as dependent data in next request
batchLeaf string
chkLeafRefWithOthCache bool
yv *YValidator //Custom YANG validator for validating external dependencies
}

type modelNamespace struct {
Expand Down Expand Up @@ -205,6 +213,11 @@ func Debug(on bool) {
yparser.Debug(on)
}

// isLeafListNode checks if the xml node represents a leaf-list field
func isLeafListNode(node *xmlquery.Node) bool {
return len(node.Attr) != 0 && node.Attr[0].Name.Local == "leaf-list"
}

//Get attribute value of xml node
func getXmlNodeAttr(node *xmlquery.Node, attrName string) string {
for _, attr := range node.Attr {
Expand All @@ -216,6 +229,14 @@ func getXmlNodeAttr(node *xmlquery.Node, attrName string) string {
return ""
}

// getNodeName returns database field name for the xml node.
func getNodeName(node *xmlquery.Node) string {
if isLeafListNode(node) {
return node.Data + "@"
}
return node.Data
}

//Store useful schema data during initialization
func storeModelInfo(modelFile string, module *yparser.YParserModule) { //such model info can be maintained in C code and fetched from there
f, err := os.Open(CVL_SCHEMA + modelFile)
Expand Down Expand Up @@ -394,6 +415,20 @@ func storeModelInfo(modelFile string, module *yparser.YParserModule) { //such mo
}
}

// Get YANG list to Redis table name
func getYangListToRedisTbl(yangListName string) string {
if (strings.HasSuffix(yangListName, "_LIST")) {
yangListName = yangListName[0:len(yangListName) - len("_LIST")]
}
tInfo, exists := modelInfo.tableInfo[yangListName]

if exists && (tInfo.redisTableName != "") {
return tInfo.redisTableName
}

return yangListName
}

//Find the tables names in must expression, these tables data need to be fetched
//during semantic validation
func addTableNamesForMustExp() {
Expand Down Expand Up @@ -475,24 +510,30 @@ func splitRedisKey(key string) (string, string) {
return tblName, key[prefixLen:]
}

//Get the YANG list name from Redis key
//Get the YANG list name from Redis key and table name
//This just returns same YANG list name as Redis table name
//when 1:1 mapping is there. For one Redis table to
//multiple YANG list, it returns appropriate YANG list name
//INTERFACE:Ethernet12 returns ==> INTERFACE
//INTERFACE:Ethernet12:1.1.1.0/32 ==> INTERFACE_IPADDR
func getRedisKeyToYangList(tableName, key string) string {
func getRedisTblToYangList(tableName, key string) (yangList string) {
defer func() {
pYangList := &yangList
TRACE_LOG(INFO_API, TRACE_SYNTAX, "Got YANG list '%s' " +
"from Redis Table '%s', Key '%s'", *pYangList, tableName, key)
}()

mapArr, exists := modelInfo.redisTableToYangList[tableName]

if exists == false {
if !exists || (len(mapArr) == 1) { //no map or only one
//1:1 mapping case
return tableName
}

//As of now determine the mapping based on number of keys
var foundIdx int = -1
numOfKeys := 1 //Assume only one key initially
for keyDelim, _ := range modelInfo.allKeyDelims {
for keyDelim := range modelInfo.allKeyDelims {
foundIdx = strings.Index(key, keyDelim)
if (foundIdx >= 0) {
//Matched with key delim
Expand All @@ -505,7 +546,7 @@ func getRedisKeyToYangList(tableName, key string) string {
//Check which list has number of keys as 'numOfKeys'
for i := 0; i < len(mapArr); i++ {
tblInfo, exists := modelInfo.tableInfo[mapArr[i]]
if exists == true {
if exists {
if (len(tblInfo.keys) == numOfKeys) {
//Found the YANG list matching the number of keys
return mapArr[i]
Expand Down
8 changes: 4 additions & 4 deletions cvl/cvl_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ func Finish() {
func ValidationSessOpen() (*CVL, CVLRetCode) {
cvl := &CVL{}
cvl.tmpDbCache = make(map[string]interface{})
cvl.requestCache = make(map[string]map[string][]CVLEditConfigData)
cvl.requestCache = make(map[string]map[string][]*requestCacheType)
cvl.yp = &yparser.YParser{}

if (cvl == nil || cvl.yp == nil) {
Expand Down Expand Up @@ -324,10 +324,10 @@ func (c *CVL) ValidateEditConfig(cfgData []CVLEditConfigData) (CVLErrorInfo, CVL
reqTbl, exists := c.requestCache[tbl]
if (exists == false) {
//Create new table key data
reqTbl = make(map[string][]CVLEditConfigData)
reqTbl = make(map[string][]*requestCacheType)
}
cfgDataItemArr, _ := reqTbl[key]
cfgDataItemArr = append(cfgDataItemArr, cfgDataItem)
cfgDataItemArr = append(cfgDataItemArr, &requestCacheType{cfgDataItem, nil})
reqTbl[key] = cfgDataItemArr
c.requestCache[tbl] = reqTbl

Expand Down Expand Up @@ -431,7 +431,7 @@ func (c *CVL) ValidateEditConfig(cfgData []CVLEditConfigData) (CVLErrorInfo, CVL
deletedInSameSession := false
if tbl != "" && key != "" {
for _, cachedCfgData := range c.requestCache[tbl][key] {
if cachedCfgData.VOp == OP_DELETE {
if cachedCfgData.reqData.VOp == OP_DELETE {
deletedInSameSession = true
break
}
Expand Down
8 changes: 4 additions & 4 deletions cvl/cvl_cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,10 @@ func (c *CVL) fetchDataFromRequestCache(tableName string, key string) (d map[str
if (cfgDataArr != nil) {
for _, cfgReqData := range cfgDataArr {
//Delete request doesn't have depedent data
if (cfgReqData.VOp == OP_CREATE) {
return cfgReqData.Data, false
} else if (cfgReqData.VOp == OP_UPDATE) {
return cfgReqData.Data, true
if (cfgReqData.reqData.VOp == OP_CREATE) {
return cfgReqData.reqData.Data, false
} else if (cfgReqData.reqData.VOp == OP_UPDATE) {
return cfgReqData.reqData.Data, true
}
}
}
Expand Down
Loading