VOL-4338: Relaxed MIB Upload Next response decoding
Change-Id: I4c0db4d4786a1d8501daec18a6980821a9267b84
diff --git a/generated/decodeerror.go b/generated/decodeerror.go
new file mode 100644
index 0000000..4358c0c
--- /dev/null
+++ b/generated/decodeerror.go
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2018 - present. Boling Consulting Solutions (bcsw.net)
+ * Copyright 2020-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
+ * NOTE: This file was generated, manual edits will be overwritten!
+ *
+ * Generated by 'goCodeGenerator.py':
+ * https://github.com/cboling/OMCI-parser/README.md
+ */
+
+package generated
+
+import (
+ "errors"
+)
+
+// Custom Go Error messages for relaxed decode error signaling.
+//
+// gopacket does not provide a way to easily perform relaxed decoding calls
+// during the 'DecodeFromBytes' decoding of a layer. It does allow for an error
+// code returned and this will be used to allow for relaxed decoding. If a
+// particular message type decode can be relaxed, process it as relax and
+// return an error derived from the RelaxedDecodeError below and check for
+// it as appropriate.
+
+// IRelaxedDecodeError provides a base interface that can be used to derive
+// other decode specific errors that can be relaxed at the application's
+// discretion
+type IRelaxedDecodeError interface {
+ // Error interface, so if relaxed decode is not supported, this behaves as
+ // a normal error
+ Error() string
+ GetError() error
+
+ ////////////////////////////////
+ // Relaxed error specific
+
+ // GetContents returns the octet payload specific to the error if it can be
+ // determined. Derived relaxed decode errors may provide more specific control
+ // and information
+ GetContents() []byte
+}
+
+type RelaxedDecodeError struct {
+ err string
+ Contents []byte
+}
+
+func (e *RelaxedDecodeError) GetError() error {
+ return errors.New(e.err)
+}
+
+func (e *RelaxedDecodeError) Error() string {
+ return e.err
+}
+
+func (e *RelaxedDecodeError) GetContents() []byte {
+ return e.Contents
+}
+
+// UnknownAttributeDecodeError is used to convey unknown attributes found in
+// a received packet undergoing decode. These will always be trailing attributes
+// in packets and are often due to:
+// o New versions of ITU G.988 being issued with an existing ME getting new
+// attributes,
+//
+// o An error in the code generated classes in this library where one or more
+// attributes were missed, or
+//
+// o An error in the OLT/ONU that serialized the message
+type UnknownAttributeDecodeError struct {
+ RelaxedDecodeError
+ AttributeMask uint16
+
+ EntityClass ClassID // Set by first level handler of the error
+ EntityInstance uint16 // Set by first level handler of the error
+}
+
+func NewUnknownAttributeDecodeError(msg string, mask uint16, contents []byte) *UnknownAttributeDecodeError {
+ err := &UnknownAttributeDecodeError{
+ RelaxedDecodeError: RelaxedDecodeError{
+ err: msg,
+ },
+ AttributeMask: mask,
+ }
+ if contents != nil {
+ err.Contents = make([]byte, len(contents))
+ copy(err.Contents, contents)
+ }
+ return err
+}
diff --git a/generated/me.go b/generated/me.go
index 8bec058..2d83255 100644
--- a/generated/me.go
+++ b/generated/me.go
@@ -286,15 +286,26 @@
entity.definition = meDefinition.definition
entity.attributeMask = binary.BigEndian.Uint16(data[4:6])
entity.attributes = make(map[string]interface{})
- entity.SetEntityID(entityID)
+ setErr := entity.SetEntityID(entityID)
+ if setErr != nil {
+ return setErr
+ }
packetAttributes, err := entity.DecodeAttributes(entity.GetAttributeMask(), data[6:], p, msgType)
+
+ // Decode packet attributes even if present in case relaxed attribute decoding is enabled.
+ if packetAttributes != nil {
+ for name, value := range packetAttributes {
+ entity.attributes[name] = value
+ }
+ }
if err != nil {
- return err
+ if attrError, ok := err.(*UnknownAttributeDecodeError); ok && GetRelaxedDecodeByOctetType(msgType) {
+ // Subtract off bad mask from what we computed
+ badMask := attrError.AttributeMask
+ entity.attributeMask &= ^badMask
+ }
}
- for name, value := range packetAttributes {
- entity.attributes[name] = value
- }
- return nil
+ return err
}
// SerializeTo serializes a Managed Entity into an octet stream
diff --git a/generated/medef.go b/generated/medef.go
index d6ab352..6d2c2dd 100644
--- a/generated/medef.go
+++ b/generated/medef.go
@@ -90,10 +90,15 @@
}
func (bme ManagedEntityDefinition) DecodeAttributes(mask uint16, data []byte, p gopacket.PacketBuilder, msgType byte) (AttributeValueMap, error) {
- if (mask | bme.GetAllowedAttributeMask()) != bme.GetAllowedAttributeMask() {
- return nil, fmt.Errorf("unsupported attribute mask %#x, valid: %#x for ME %v (Class ID: %d)",
+ badMask := (mask | bme.GetAllowedAttributeMask()) ^ bme.GetAllowedAttributeMask()
+
+ var maskErr error
+ if badMask != 0 {
+ maskErr = fmt.Errorf("unsupported attribute mask %#x, valid: %#x for ME %v (Class ID: %d)",
mask, bme.GetAllowedAttributeMask(), bme.GetName(), bme.ClassID)
+ mask &= bme.GetAllowedAttributeMask()
}
+ // Process known attributes
keyList := GetAttributeDefinitionMapKeys(bme.AttributeDefinitions)
attrMap := make(AttributeValueMap, bits.OnesCount16(mask))
@@ -153,7 +158,13 @@
}
}
}
- return attrMap, nil
+ // If badMask is non-zero. Handle it by re-encoding the error as a custom relaxed
+ // decode error that the caller of this decode can process if they wish to relax
+ // the decoding
+ if badMask != 0 {
+ maskErr = NewUnknownAttributeDecodeError(maskErr.Error(), badMask, data)
+ }
+ return attrMap, maskErr
}
func (bme ManagedEntityDefinition) SerializeAttributes(attr AttributeValueMap, mask uint16,
diff --git a/generated/relaxed.go b/generated/relaxed.go
new file mode 100644
index 0000000..a1e49d3
--- /dev/null
+++ b/generated/relaxed.go
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2018 - present. Boling Consulting Solutions (bcsw.net)
+ * Copyright 2020-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
+ * NOTE: This file was generated, manual edits will be overwritten!
+ *
+ * Generated by 'goCodeGenerator.py':
+ * https://github.com/cboling/OMCI-parser/README.md
+ */
+package generated
+
+import (
+ "fmt"
+)
+
+var relaxedDecode map[int]bool
+
+func init() {
+ relaxedDecode = make(map[int]bool)
+
+ // Default for relaxed decode is True if there is relaxed decode support available
+ // relaxedDecode[mkRelaxedKey(Get, false)] = true
+ relaxedDecode[mkRelaxedKey(MibUploadNext, false)] = true
+}
+
+func mkRelaxedKey(msgType MsgType, request bool) int {
+ if request {
+ return int(msgType)
+ }
+ return 100 + int(msgType)
+}
+
+func SetRelaxedDecode(msgType MsgType, request bool, relax bool) error {
+ key := mkRelaxedKey(msgType, request)
+
+ if _, ok := relaxedDecode[key]; !ok {
+ return fmt.Errorf("relax decode of '%v' is not supported", msgType)
+ }
+ relaxedDecode[key] = relax
+ return nil
+}
+
+func GetRelaxedDecode(msgType MsgType, request bool) bool {
+ key := mkRelaxedKey(msgType, request)
+
+ relaxed, ok := relaxedDecode[key]
+ return ok && relaxed
+}
+
+// GetRelaxedDecodeByOctetType decodes the payload message-type value and determine if
+// relaxed decode is enabled
+func GetRelaxedDecodeByOctetType(value byte) bool {
+ msgType := MsgType(value & MsgTypeMask)
+ var request bool
+
+ if msgType != AlarmNotification && msgType != AttributeValueChange && msgType != TestResult {
+ request = value&AR == AR || value&AK == 0
+ }
+ return GetRelaxedDecode(msgType, request)
+}