From b9c6c804f2046a32d3637b51fa034968233ca2c6 Mon Sep 17 00:00:00 2001 From: Jichen Dou Date: Mon, 4 May 2026 16:05:01 -0700 Subject: [PATCH] sonic-optical-amplifier: add custom validation for dynamic range - Introduce sonic-ext:custom-validation to support component-specific dynamic range validation - Add additional identities to extend amplifier type coverage - Use target-gain as a reference example for dynamic range enforcement - Exclude src/sonic-yang-models/common since sonic-mgmt-common already has sonic-extension.yang. Cause import conflicts --- cvl/custom_validation/otn_validations.go | 80 +++++++++ .../yang/sonic/sonic-optical-amplifier.yang | 169 +++++++++++++++++- tools/pyang/import_yang.py | 2 + 3 files changed, 243 insertions(+), 8 deletions(-) create mode 100644 cvl/custom_validation/otn_validations.go diff --git a/cvl/custom_validation/otn_validations.go b/cvl/custom_validation/otn_validations.go new file mode 100644 index 000000000..a7a106719 --- /dev/null +++ b/cvl/custom_validation/otn_validations.go @@ -0,0 +1,80 @@ +package custom_validation + +import ( + "fmt" + "math" + "strconv" + "strings" + + "github.com/Azure/sonic-mgmt-common/cvl/internal/util" +) + +// ValidateOtnGain validates target-gain against per-amplifier bounds stored +// in CONFIG_DB OTN_OA| (fields: min-gain, max-gain). +// +// If min-gain or max-gain is absent the check is skipped (permissive). +func (t *CustomValidation) ValidateOtnGain(vc *CustValidationCtxt) CVLErrorInfo { + if vc.CurCfg.VOp == OP_DELETE { + return CVLErrorInfo{ErrCode: CVL_SUCCESS} + } + + // Key format: "OTN_OA|" + parts := strings.SplitN(vc.CurCfg.Key, "|", 2) + if len(parts) != 2 { + return CVLErrorInfo{ErrCode: CVL_SUCCESS} + } + ampName := parts[1] + + cfgDb := util.NewDbClient("CONFIG_DB") + if cfgDb == nil { + return CVLErrorInfo{ + ErrCode: CVL_INTERNAL_UNKNOWN, + CVLErrDetails: "CONFIG_DB connection failed", + } + } + + entryKey := "OTN_OA|" + ampName + entry, err := cfgDb.HGetAll(entryKey).Result() + if err != nil || len(entry) == 0 { + return CVLErrorInfo{ErrCode: CVL_SUCCESS} + } + + minGainStr, hasMin := entry["min-gain"] + maxGainStr, hasMax := entry["max-gain"] + if !hasMin || !hasMax { + return CVLErrorInfo{ErrCode: CVL_SUCCESS} + } + + minGain, errMin := strconv.ParseFloat(minGainStr, 64) + maxGain, errMax := strconv.ParseFloat(maxGainStr, 64) + if errMin != nil || errMax != nil { + return CVLErrorInfo{ErrCode: CVL_SUCCESS} + } + + val, errVal := strconv.ParseFloat(vc.YNodeVal, 64) + if errVal != nil { + return CVLErrorInfo{ + ErrCode: CVL_SYNTAX_ERROR, + TableName: parts[0], + Keys: parts, + Field: vc.YNodeName, + Value: vc.YNodeVal, + ConstraintErrMsg: "target-gain must be a valid decimal number", + } + } + + val = math.Round(val*100) / 100 + + if val < minGain || val > maxGain { + return CVLErrorInfo{ + ErrCode: CVL_SEMANTIC_ERROR, + TableName: parts[0], + Keys: parts, + Field: vc.YNodeName, + Value: vc.YNodeVal, + ConstraintErrMsg: fmt.Sprintf("target-gain %.2f out of configured range [%.2f, %.2f]", val, minGain, maxGain), + } + } + + return CVLErrorInfo{ErrCode: CVL_SUCCESS} +} diff --git a/models/yang/sonic/sonic-optical-amplifier.yang b/models/yang/sonic/sonic-optical-amplifier.yang index df3d973a7..f6adee529 100644 --- a/models/yang/sonic/sonic-optical-amplifier.yang +++ b/models/yang/sonic/sonic-optical-amplifier.yang @@ -1,9 +1,10 @@ module sonic-optical-amplifier { - /* Generated from openconfig-optical-amplifier.yang and - * openconfig-optical-amplifier-annot.yang. */ + namespace "http://github.com/Azure/sonic-optical-amplifier"; prefix "sopt-amp"; + import sonic-extension { prefix sonic-ext; } + organization "SONiC"; @@ -13,11 +14,131 @@ module sonic-optical-amplifier { description "SONIC OPTICAL AMPLIFIER"; + revision 2026-04-30 { + description + "Add openconfig identity definition."; + } + revision 2022-06-13 { description "Initial revision."; } + identity OPTICAL_AMPLIFIER_TYPE { + description + "Type definition for different types of optical amplifiers"; + } + + identity EDFA { + base OPTICAL_AMPLIFIER_TYPE; + description + "Erbium doped fiber amplifer (EDFA)"; + } + + identity FORWARD_RAMAN { + base OPTICAL_AMPLIFIER_TYPE; + description + "Forward pumping Raman amplifier"; + } + + identity BACKWARD_RAMAN { + base OPTICAL_AMPLIFIER_TYPE; + description + "Backward pumping Raman amplifier"; + } + + identity HYBRID { + base OPTICAL_AMPLIFIER_TYPE; + description + "Hybrid backward pumping Raman + EDFA amplifier"; + } + + identity GAIN_RANGE { + description + "Base type for expressing the gain range for a switched gain amplifier."; + } + + identity LOW_GAIN_RANGE { + base GAIN_RANGE; + description + "LOW gain range setting"; + } + + identity MID_GAIN_RANGE { + base GAIN_RANGE; + description + "MID gain range setting"; + } + + identity HIGH_GAIN_RANGE { + base GAIN_RANGE; + description + "HIGH gain range setting"; + } + + identity FIXED_GAIN_RANGE { + base GAIN_RANGE; + description + "Fixed or non-switched gain amplifier"; + } + + identity OPTICAL_AMPLIFIER_MODE { + description + "Type definition for different types of optical amplifier operating modes"; + } + + identity CONSTANT_POWER { + base OPTICAL_AMPLIFIER_MODE; + description + "Constant power mode"; + } + + identity CONSTANT_GAIN { + base OPTICAL_AMPLIFIER_MODE; + description + "Constant gain mode"; + } + + identity DYNAMIC_GAIN { + base OPTICAL_AMPLIFIER_MODE; + description + "Dynamic gain mode"; + } + + identity FIBER_TYPE_PROFILE { + description + "Type definition for different profiles of fiber types"; + } + + identity DSF { + base FIBER_TYPE_PROFILE; + description + "Dispersion shifted fiber"; + } + + identity LEAF { + base FIBER_TYPE_PROFILE; + description + "Large effective area fiber"; + } + + identity SSMF { + base FIBER_TYPE_PROFILE; + description + "Standard single mode fiber"; + } + + identity TWC { + base FIBER_TYPE_PROFILE; + description + "True wave classic"; + } + + identity TWRS { + base FIBER_TYPE_PROFILE; + description + "True wave reduced slope"; + } container sonic-optical-amplifier { @@ -34,7 +155,9 @@ module sonic-optical-amplifier { } leaf type { - type string; + type identityref { + base OPTICAL_AMPLIFIER_TYPE; + } description "Type of the amplifier"; } @@ -43,10 +166,34 @@ module sonic-optical-amplifier { type decimal64 { fraction-digits 2; } + sonic-ext:custom-validation "ValidateOtnGain"; description "Positive gain applied by the amplifier."; } - + leaf min-gain { + type decimal64 { + fraction-digits 2; + } + units "dBm"; + description + "The minimum allowed gain of the amplifier. This is used + when the amp-mode is in CONSTANT_POWER or DYNAMIC_GAIN mode + to prevent the gain from dropping below a desired threshold. + If left empty, the platform will apply a minimum gain based + on hardware specifications."; + } + leaf max-gain { + type decimal64 { + fraction-digits 2; + } + units "dBm"; + description + "The maximum allowed gain of the amplifier. This is used + when the amp-mode is in CONSTANT_POWER or DYNAMIC_GAIN mode + to prevent the gain from exceeding a desired threshold. If + left empty, the platform will apply a maximum gain based on + hardware specifications."; + } leaf target-gain-tilt { type decimal64 { fraction-digits 2; @@ -56,14 +203,18 @@ module sonic-optical-amplifier { } leaf gain-range { - type string; + type identityref { + base GAIN_RANGE; + } description "Selected gain range. The gain range is a platform-defined value indicating the switched gain amplifier setting"; } leaf amp-mode { - type string; + type identityref { + base OPTICAL_AMPLIFIER_MODE; + } description "The operating mode of the amplifier"; } @@ -83,13 +234,15 @@ module sonic-optical-amplifier { } leaf fiber-type-profile { - type string; + type identityref { + base FIBER_TYPE_PROFILE; + } description "The fiber type profile specifies details about the fiber type which are needed to accurately determine the gain and perform efficient amplification. This is only needed for Raman type amplifiers."; - } + } leaf autolos { type boolean; diff --git a/tools/pyang/import_yang.py b/tools/pyang/import_yang.py index d4b7f690b..d4ea5174a 100755 --- a/tools/pyang/import_yang.py +++ b/tools/pyang/import_yang.py @@ -77,6 +77,8 @@ def __init__(self, files, options): ctx.keep_comments = options.keep_comments excludes = [f.stem for f in options.to_dir.glob("*.yang")] + # Exclude common yang-models since they are already included in sonic-mgmt-common + excludes += [f.stem for f in options.to_dir.glob("common/*.yang")] if options.exclude: excludes += [f.stem for f in options.exclude]