Skip to content
Merged
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