From 49bb62257d21e86ff0ee7c0541ff7db893632f2a Mon Sep 17 00:00:00 2001 From: Sumalatha G Date: Fri, 10 Apr 2026 08:46:51 +0530 Subject: [PATCH] [cvl] Enforce mandatory field validation for OP_CREATE operations Issue: CVL's ValidateEditConfig() does not enforce YANG mandatory true fields on OP_CREATE operations, allowing invalid configurations to be written to CONFIG_DB. Root Cause: CVL performs mandatory field validation only for OP_DELETE operations but skips this critical check for OP_CREATE operations. This allows entries to be created without required mandatory fields defined in YANG models. Solution: - Added checkMandatoryFieldsForCreate() function to validate mandatory fields - Function iterates through YANG leaf nodes and checks if mandatory fields exist - Returns CVL_SEMANTIC_ERROR with clear error message if mandatory field is missing - Called during OP_CREATE case in ValidateEditConfig() Impact: - Prevents invalid configurations from being written to CONFIG_DB - Provides clear error messages indicating which mandatory field is missing - Consistent with existing OP_DELETE mandatory field validation - No hardware dependency - pure software validation Testing: - CREATE operations with missing mandatory fields will now fail with proper error - CREATE operations with all mandatory fields will continue to work normally - Error includes table name, key, field name, and descriptive message Fixes: https://github.com/sonic-net/SONiC/issues/2283 Signed-off-by: Sumalatha G --- cvl/cvl_api.go | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/cvl/cvl_api.go b/cvl/cvl_api.go index 18e7632cb..fd8eebaa3 100644 --- a/cvl/cvl_api.go +++ b/cvl/cvl_api.go @@ -390,6 +390,13 @@ func (c *CVL) ValidateEditConfig(cfgData []cmn.CVLEditConfigData) (cvlErr CVLErr return cvlErrObj, CVL_SYNTAX_ERROR } + //Check mandatory fields for OP_CREATE (Fixes issue #2283) + //Enforce YANG "mandatory true" constraint during CREATE operations + yangListName := getRedisTblToYangList(tbl, key) + if cvlErrObj := c.checkMandatoryFieldsForCreate(cfgData[i], yangListName, tbl, key); cvlErrObj.ErrCode != CVL_SUCCESS { + return cvlErrObj, cvlErrObj.ErrCode + } + case cmn.OP_UPDATE: //Get the existing data from Redis to cache, so that final //validation can be done after merging this dependent data @@ -604,6 +611,47 @@ func (c *CVL) ValidateEditConfig(cfgData []cmn.CVLEditConfigData) (cvlErr CVLErr return cvlErrObj, CVL_SUCCESS } +// checkMandatoryFieldsForCreate checks if all mandatory fields are present during OP_CREATE +// This function enforces YANG "mandatory true" constraint for CREATE operations +// Fixes issue: https://github.com/sonic-net/SONiC/issues/2283 +func (c *CVL) checkMandatoryFieldsForCreate(cfgData cmn.CVLEditConfigData, yangListName, tbl, key string) CVLErrorInfo { + var cvlErrObj CVLErrorInfo + cvlErrObj.ErrCode = CVL_SUCCESS + + // Get YANG schema information for this table + listInfo, exists := modelInfo.tableInfo[tbl] + if !exists { + CVL_LOG(INFO_DEBUG, "No YANG model found for table %s, skipping mandatory check", tbl) + return cvlErrObj + } + + // Iterate through all leaf nodes in the YANG model + for fieldName, fieldInfo := range listInfo.mapLeaf { + // Check if this is a mandatory field + if fieldInfo.yangEntry != nil && fieldInfo.yangEntry.Mandatory { + // Check if the mandatory field is present in the data + if _, exists := cfgData.Data[fieldName]; !exists { + // Mandatory field is missing + CVL_LOG(WARNING, "Mandatory field '%s' missing for CREATE operation on table %s, key %s", + fieldName, tbl, key) + + cvlErrObj.ErrCode = CVL_SEMANTIC_ERROR + cvlErrObj.TableName = tbl + cvlErrObj.Keys = splitKeyComponents(tbl, key) + cvlErrObj.Field = fieldName + cvlErrObj.Msg = fmt.Sprintf("Mandatory field '%s' is missing", fieldName) + cvlErrObj.CVLErrDetails = cvlErrorMap[cvlErrObj.ErrCode] + cvlErrObj.ErrAppTag = "missing-mandatory-field" + cvlErrObj.ConstraintErrMsg = cvlErrObj.Msg + + return cvlErrObj + } + } + } + + return cvlErrObj +} + func (c *CVL) markCfgDataValidated(cfgData *cmn.CVLEditConfigData, tbl, key string) { if cfgData.VType != cmn.VALIDATE_NONE { for k := range c.requestCache[tbl][key] {