VOL-3614 Other multicast ME created after multicast gem detected.
Change-Id: Idc272aa9f6ae3c8da3910031bc226847f253a78f
diff --git a/VERSION b/VERSION
index 736f74c..e515aee 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-0.1.15-dev146
+0.1.15-dev147
diff --git a/go.mod b/go.mod
index c315675..2a56590 100644
--- a/go.mod
+++ b/go.mod
@@ -8,7 +8,7 @@
github.com/golang/protobuf v1.4.2
github.com/google/gopacket v1.1.17
github.com/looplab/fsm v0.1.0
- github.com/opencord/omci-lib-go v0.13.3
+ github.com/opencord/omci-lib-go v0.13.4
github.com/opencord/voltha-lib-go/v3 v3.1.23
github.com/opencord/voltha-protos/v3 v3.3.9
github.com/stretchr/testify v1.6.1
diff --git a/go.sum b/go.sum
index 89c8c62..ca7f92e 100644
--- a/go.sum
+++ b/go.sum
@@ -217,8 +217,8 @@
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v1.4.2 h1:3mYCb7aPxS/RU7TI1y4rkEn1oKmPRjNJLNEXgw7MH2I=
github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
-github.com/opencord/omci-lib-go v0.13.3 h1:HlBw/bdCsfz/sRVm8bXNrxdRcCpPqEqJ7xQk7CUqWkA=
-github.com/opencord/omci-lib-go v0.13.3/go.mod h1:6OIHB14Ch5qGgHzwSWlMACtk5KFoLzQ4LAhdcy4jwvo=
+github.com/opencord/omci-lib-go v0.13.4 h1:L3GpFHrx3DASixkCvztnJbcLGUTU/21wJYdE/qG9/XA=
+github.com/opencord/omci-lib-go v0.13.4/go.mod h1:6OIHB14Ch5qGgHzwSWlMACtk5KFoLzQ4LAhdcy4jwvo=
github.com/opencord/voltha-lib-go/v3 v3.1.23 h1:cbrg+QmIXR3fQHSlo5+QokmSDkFdU7fTYmwxCU5QprY=
github.com/opencord/voltha-lib-go/v3 v3.1.23/go.mod h1:sa508HZ5vlOauh0i+WC0XFX1JZnfHtJqNIms5XBT/Z0=
github.com/opencord/voltha-protos/v3 v3.3.9 h1:BnfDN9oaRBgyAiH9ZN7LpBpEJYxjX/ZS7R4OT2hDrtY=
diff --git a/internal/pkg/onuadaptercore/device_handler.go b/internal/pkg/onuadaptercore/device_handler.go
index 8c46421..8349d51 100644
--- a/internal/pkg/onuadaptercore/device_handler.go
+++ b/internal/pkg/onuadaptercore/device_handler.go
@@ -2443,3 +2443,13 @@
}
return nil
}
+
+// getUniPortMEEntityID takes uniPortNo as the input and returns the Entity ID corresponding to this UNI-G ME Instance
+func (dh *deviceHandler) getUniPortMEEntityID(uniPortNo uint32) (uint16, error) {
+ dh.lockDevice.RLock()
+ defer dh.lockDevice.RUnlock()
+ if uniPort, ok := dh.uniEntityMap[uniPortNo]; ok {
+ return uniPort.entityID, nil
+ }
+ return 0, errors.New("error-fetching-uni-port")
+}
diff --git a/internal/pkg/onuadaptercore/mib_download.go b/internal/pkg/onuadaptercore/mib_download.go
index 48abc65..cc39da0 100644
--- a/internal/pkg/onuadaptercore/mib_download.go
+++ b/internal/pkg/onuadaptercore/mib_download.go
@@ -158,7 +158,7 @@
return
}
logger.Debugw("CreateResponse Data", log.Fields{"device-id": onuDeviceEntry.deviceID, "data-fields": msgObj})
- if msgObj.Result != me.Success {
+ if msgObj.Result != me.Success && msgObj.Result != me.InstanceExists {
logger.Errorw("Omci CreateResponse Error - later: drive FSM to abort state ?", log.Fields{"device-id": onuDeviceEntry.deviceID, "Error": msgObj.Result})
// possibly force FSM into abort or ignore some errors for some messages? store error for mgmt display?
return
diff --git a/internal/pkg/onuadaptercore/omci_ani_config.go b/internal/pkg/onuadaptercore/omci_ani_config.go
index 70b5f67..2cef989 100644
--- a/internal/pkg/onuadaptercore/omci_ani_config.go
+++ b/internal/pkg/onuadaptercore/omci_ani_config.go
@@ -307,10 +307,10 @@
mapGemPortParams := oFsm.pUniTechProf.mapPonAniConfig[oFsm.uniTpKey].mapGemPortParams
oFsm.pUniTechProf.mutexTPState.Unlock()
- loGemPortAttribs := ponAniGemPortAttribs{}
//for all TechProfile set GemIndices
-
for _, gemEntry := range mapGemPortParams {
+ loGemPortAttribs := ponAniGemPortAttribs{}
+
//collect all GemConfigData in a separate Fsm related slice (needed also to avoid mix-up with unsorted mapPonAniConfig)
if queueInstKeys := oFsm.pOnuDB.getSortedInstKeys(me.PriorityQueueClassID); len(queueInstKeys) > 0 {
@@ -368,23 +368,30 @@
loGemPortAttribs.weight = gemEntry.queueWeight
loGemPortAttribs.pbitString = gemEntry.pbitString
if gemEntry.isMulticast {
+ //TODO this might effectively ignore the for loop starting at line 316
+ loGemPortAttribs.gemPortID = gemEntry.multicastGemPortID
loGemPortAttribs.isMulticast = true
loGemPortAttribs.multicastGemID = gemEntry.multicastGemPortID
loGemPortAttribs.staticACL = gemEntry.staticACL
loGemPortAttribs.dynamicACL = gemEntry.dynamicACL
- }
- logger.Debugw("prio-related GemPort attributes:", log.Fields{
- "gemPortID": loGemPortAttribs.gemPortID,
- "upQueueID": loGemPortAttribs.upQueueID,
- "downQueueID": loGemPortAttribs.downQueueID,
- "pbitString": loGemPortAttribs.pbitString,
- "prioQueueIndex": gemEntry.prioQueueIndex,
- "isMulticast": loGemPortAttribs.isMulticast,
- "multicastGemID": loGemPortAttribs.multicastGemID,
- "staticACL": loGemPortAttribs.staticACL,
- "dynamicACL": loGemPortAttribs.dynamicACL,
- })
+ logger.Debugw("Multicast GemPort attributes:", log.Fields{
+ "gemPortID": loGemPortAttribs.gemPortID,
+ "isMulticast": loGemPortAttribs.isMulticast,
+ "multicastGemID": loGemPortAttribs.multicastGemID,
+ "staticACL": loGemPortAttribs.staticACL,
+ "dynamicACL": loGemPortAttribs.dynamicACL,
+ })
+
+ } else {
+ logger.Debugw("Upstream GemPort attributes:", log.Fields{
+ "gemPortID": loGemPortAttribs.gemPortID,
+ "upQueueID": loGemPortAttribs.upQueueID,
+ "downQueueID": loGemPortAttribs.downQueueID,
+ "pbitString": loGemPortAttribs.pbitString,
+ "prioQueueIndex": gemEntry.prioQueueIndex,
+ })
+ }
oFsm.gemPortAttribsSlice = append(oFsm.gemPortAttribsSlice, loGemPortAttribs)
}
@@ -493,6 +500,7 @@
}
func (oFsm *uniPonAniConfigFsm) enterSettingDot1PMapper(e *fsm.Event) {
+
logger.Debugw("uniPonAniConfigFsm Tx Set::.1pMapper with all PBits set", log.Fields{"EntitytId": 0x8042, /*cmp above*/
"toGemIw": 1024, /* cmp above */
"device-id": oFsm.deviceID, "uni-id": oFsm.pOnuUniPort.uniID})
@@ -509,6 +517,18 @@
//assign the GemPorts according to the configured Prio
var loPrioGemPortArray [8]uint16
for _, gemPortAttribs := range oFsm.gemPortAttribsSlice {
+ if gemPortAttribs.isMulticast {
+ logger.Debugw("uniPonAniConfigFsm Port is Multicast, ignoring .1pMapper", log.Fields{
+ "device-id": oFsm.deviceID, "GemPort": gemPortAttribs.gemPortID,
+ "prioString": gemPortAttribs.pbitString})
+ continue
+ }
+ if gemPortAttribs.pbitString == "" {
+ logger.Warnw("uniPonAniConfigFsm PrioString empty string error", log.Fields{
+ "device-id": oFsm.deviceID, "GemPort": gemPortAttribs.gemPortID,
+ "prioString": gemPortAttribs.pbitString})
+ continue
+ }
for i := 0; i < 8; i++ {
// "lenOfPbitMap(8) - i + 1" will give i-th pbit value from LSB position in the pbit map string
if prio, err := strconv.Atoi(string(gemPortAttribs.pbitString[7-i])); err == nil {
@@ -529,39 +549,58 @@
}
}
+
var foundIwPtr = false
for index, value := range loPrioGemPortArray {
+ meAttribute := fmt.Sprintf("InterworkTpPointerForPBitPriority%d", index)
if value != 0 {
foundIwPtr = true
- meAttribute := fmt.Sprintf("InterworkTpPointerForPBitPriority%d", index)
meParams.Attributes[meAttribute] = value
logger.Debugw("UniPonAniConfigFsm Set::1pMapper", log.Fields{
"for Prio": index,
"IwPtr": strconv.FormatInt(int64(value), 16),
"device-id": oFsm.deviceID})
+ } else {
+ // The null pointer 0xFFFF specifies that frames with the associated priority are to be discarded.
+ meParams.Attributes[meAttribute] = 0xffff
}
}
+ // The TP type value 0 also indicates bridging mapping, and the TP pointer should be set to 0xFFFF
+ meParams.Attributes["TpPointer"] = 0xffff
if !foundIwPtr {
- logger.Errorw("UniPonAniConfigFsm no GemIwPtr found for .1pMapper - abort", log.Fields{
+ logger.Debugw("UniPonAniConfigFsm no GemIwPtr found for .1pMapper - abort", log.Fields{
"device-id": oFsm.deviceID})
+ //TODO With multicast is possible that no upstream gem ports are not present in the tech profile,
+ // this reset needs to be performed only if the tech profile provides upstream gem ports but no priority is set
//let's reset the state machine in order to release all resources now
+ //pConfigAniStateAFsm := oFsm.pAdaptFsm
+ //if pConfigAniStateAFsm != nil {
+ // // obviously calling some FSM event here directly does not work - so trying to decouple it ...
+ // go func(aPAFsm *AdapterFsm) {
+ // if aPAFsm != nil && aPAFsm.pFsm != nil {
+ // _ = aPAFsm.pFsm.Event(aniEvReset)
+ // }
+ // }(pConfigAniStateAFsm)
+ //}
+ //Moving forward the FSM as if the response was received correctly.
pConfigAniStateAFsm := oFsm.pAdaptFsm
if pConfigAniStateAFsm != nil {
// obviously calling some FSM event here directly does not work - so trying to decouple it ...
go func(aPAFsm *AdapterFsm) {
if aPAFsm != nil && aPAFsm.pFsm != nil {
- _ = aPAFsm.pFsm.Event(aniEvReset)
+ _ = oFsm.pAdaptFsm.pFsm.Event(aniEvRxDot1pmapSResp)
}
}(pConfigAniStateAFsm)
}
+ } else {
+ meInstance := oFsm.pOmciCC.sendSetDot1PMapperVar(context.TODO(), ConstDefaultOmciTimeout, true,
+ oFsm.pAdaptFsm.commChan, meParams)
+ //accept also nil as (error) return value for writing to LastTx
+ // - this avoids misinterpretation of new received OMCI messages
+ oFsm.pLastTxMeInstance = meInstance
}
- meInstance := oFsm.pOmciCC.sendSetDot1PMapperVar(context.TODO(), ConstDefaultOmciTimeout, true,
- oFsm.pAdaptFsm.commChan, meParams)
- //accept also nil as (error) return value for writing to LastTx
- // - this avoids misinterpretation of new received OMCI messages
- oFsm.pLastTxMeInstance = meInstance
}
func (oFsm *uniPonAniConfigFsm) enterAniConfigDone(e *fsm.Event) {
@@ -775,7 +814,7 @@
{ // let the FSM proceed ...
_ = oFsm.pAdaptFsm.pFsm.Event(aniEvRxMbpcdResp)
}
- case "GemPortNetworkCtp", "GemInterworkingTerminationPoint":
+ case "GemPortNetworkCtp", "GemInterworkingTerminationPoint", "MulticastGemInterworkingTerminationPoint":
{ // let aniConfig Multi-Id processing proceed by stopping the wait function
oFsm.omciMIdsResponseReceived <- true
}
@@ -823,7 +862,7 @@
_ = oFsm.pAdaptFsm.pFsm.Event(aniEvRxResetTcontResp)
}
}
- case "PriorityQueue":
+ case "PriorityQueue", "MulticastGemInterworkingTerminationPoint":
{ // let the PrioQueue init proceed by stopping the wait function
oFsm.omciMIdsResponseReceived <- true
}
@@ -961,27 +1000,46 @@
//TODO if the port has only downstream direction the isMulticast flag can be removed.
if gemPortAttribs.isMulticast {
- ipv4MulticastTable := make([]uint8, 12)
- binary.BigEndian.PutUint16(ipv4MulticastTable[0:], gemPortAttribs.gemPortID)
- binary.BigEndian.PutUint16(ipv4MulticastTable[2:], 0)
- // This is the 224.0.0.1 address
- binary.BigEndian.PutUint32(ipv4MulticastTable[4:], IPToInt32(net.IPv4allsys))
- // this is the 255.255.255.255 address
- binary.BigEndian.PutUint32(ipv4MulticastTable[8:], IPToInt32(net.IPv4bcast))
meParams := me.ParamData{
- EntityID: gemPortAttribs.gemPortID,
+ EntityID: gemPortAttribs.multicastGemID,
Attributes: me.AttributeValueMap{
- "GemPortNetworkCtpConnectivityPointer": gemPortAttribs.gemPortID,
+ "GemPortNetworkCtpConnectivityPointer": gemPortAttribs.multicastGemID,
"InterworkingOption": 0, // Don't Care
"ServiceProfilePointer": 0, // Don't Care
"GalProfilePointer": galEthernetEID,
- "Ipv4MulticastAddressTable": ipv4MulticastTable,
},
}
meInstance := oFsm.pOmciCC.sendCreateMulticastGemIWTPVar(context.TODO(), ConstDefaultOmciTimeout,
true, oFsm.pAdaptFsm.commChan, meParams)
oFsm.pLastTxMeInstance = meInstance
+ //verify response
+ err := oFsm.waitforOmciResponse()
+ if err != nil {
+ logger.Errorw("GemTP IW multicast create failed, aborting AniConfig FSM!",
+ log.Fields{"device-id": oFsm.deviceID, "GemIndex": gemIndex})
+ _ = oFsm.pAdaptFsm.pFsm.Event(aniEvReset)
+ return
+ }
+ ipv4MulticastTable := make([]uint8, 12)
+ //Gem Port ID
+ binary.BigEndian.PutUint16(ipv4MulticastTable[0:], gemPortAttribs.multicastGemID)
+ //Secondary Key
+ binary.BigEndian.PutUint16(ipv4MulticastTable[2:], 0)
+ // Multicast IP range start This is the 224.0.0.1 address
+ binary.BigEndian.PutUint32(ipv4MulticastTable[4:], IPToInt32(net.IPv4(224, 0, 0, 0)))
+ // MulticastIp range stop
+ binary.BigEndian.PutUint32(ipv4MulticastTable[8:], IPToInt32(net.IPv4(239, 255, 255, 255)))
+
+ meIPV4MCTableParams := me.ParamData{
+ EntityID: gemPortAttribs.multicastGemID,
+ Attributes: me.AttributeValueMap{
+ "Ipv4MulticastAddressTable": ipv4MulticastTable,
+ },
+ }
+ meIPV4MCTableInstance := oFsm.pOmciCC.sendSetMulticastGemIWTPVar(context.TODO(), ConstDefaultOmciTimeout,
+ true, oFsm.pAdaptFsm.commChan, meIPV4MCTableParams)
+ oFsm.pLastTxMeInstance = meIPV4MCTableInstance
} else {
meParams := me.ParamData{
@@ -1020,6 +1078,12 @@
//find all upstream PrioQueues related to this T-Cont
loQueueMap := ordered_map.NewOrderedMap()
for _, gemPortAttribs := range oFsm.gemPortAttribsSlice {
+ if gemPortAttribs.isMulticast {
+ logger.Debugw("uniPonAniConfigFsm Port is Multicast, ignoring PQs", log.Fields{
+ "device-id": oFsm.deviceID, "GemPort": gemPortAttribs.gemPortID,
+ "prioString": gemPortAttribs.pbitString})
+ continue
+ }
if gemPortAttribs.qosPolicy == "WRR" {
if _, ok := loQueueMap.Get(gemPortAttribs.upQueueID); !ok {
//key does not yet exist
diff --git a/internal/pkg/onuadaptercore/omci_cc.go b/internal/pkg/onuadaptercore/omci_cc.go
index 17e674d..deb0905 100644
--- a/internal/pkg/onuadaptercore/omci_cc.go
+++ b/internal/pkg/onuadaptercore/omci_cc.go
@@ -804,13 +804,11 @@
meParams := me.ParamData{
EntityID: instID,
Attributes: me.AttributeValueMap{
- "Priority": 0x8000,
- "MaxAge": 20 * 256, //20s
- "HelloTime": 2 * 256, //2s
- "ForwardDelay": 15 * 256, //15s
- //note: DynamicFilteringAgeingTime is taken from omci lib default as
- // which is obviously different from default value used in python lib,
- // where the value seems to be 0 (ONU defined) - to be considered in case of test artifacts ...
+ "Priority": 0x8000,
+ "MaxAge": 20 * 256, //20s
+ "HelloTime": 2 * 256, //2s
+ "ForwardDelay": 15 * 256, //15s
+ "DynamicFilteringAgeingTime": 0,
},
}
@@ -1526,6 +1524,7 @@
return nil
}
+// nolint: unused
func (oo *omciCC) sendSetVtfdVar(ctx context.Context, timeout int, highPrio bool,
rxChan chan Message, params ...me.ParamData) *me.ManagedEntity {
tid := oo.getNextTid(highPrio)
@@ -1571,6 +1570,47 @@
return nil
}
+func (oo *omciCC) sendCreateEvtocdVar(ctx context.Context, timeout int, highPrio bool,
+ rxChan chan Message, params ...me.ParamData) *me.ManagedEntity {
+ tid := oo.getNextTid(highPrio)
+ logger.Debugw("send EVTOCD-Create-msg:", log.Fields{"device-id": oo.deviceID,
+ "SequNo": strconv.FormatInt(int64(tid), 16),
+ "InstId": strconv.FormatInt(int64(params[0].EntityID), 16)})
+
+ meInstance, omciErr := me.NewExtendedVlanTaggingOperationConfigurationData(params[0])
+ if omciErr.GetError() == nil {
+ omciLayer, msgLayer, err := omci.EncodeFrame(meInstance, omci.CreateRequestType, omci.TransactionID(tid))
+ if err != nil {
+ logger.Errorw("Cannot encode EVTOCD for create", log.Fields{
+ "Err": err, "device-id": oo.deviceID})
+ return nil
+ }
+
+ pkt, err := serializeOmciLayer(omciLayer, msgLayer)
+ if err != nil {
+ logger.Errorw("Cannot serialize EVTOCD create", log.Fields{
+ "Err": err, "device-id": oo.deviceID})
+ return nil
+ }
+
+ omciRxCallbackPair := callbackPair{
+ cbKey: tid,
+ cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse},
+ }
+ err = oo.send(ctx, pkt, timeout, 0, highPrio, omciRxCallbackPair)
+ if err != nil {
+ logger.Errorw("Cannot send EVTOCD create", log.Fields{
+ "Err": err, "device-id": oo.deviceID})
+ return nil
+ }
+ logger.Debug("send EVTOCD-set msg done")
+ return meInstance
+ }
+ logger.Errorw("Cannot generate EVTOCD Instance", log.Fields{
+ "Err": omciErr.GetError(), "device-id": oo.deviceID})
+ return nil
+}
+
func (oo *omciCC) sendSetEvtocdVar(ctx context.Context, timeout int, highPrio bool,
rxChan chan Message, params ...me.ParamData) *me.ManagedEntity {
tid := oo.getNextTid(highPrio)
@@ -1612,6 +1652,47 @@
return nil
}
+func (oo *omciCC) sendDeleteEvtocd(ctx context.Context, timeout int, highPrio bool,
+ rxChan chan Message, params ...me.ParamData) *me.ManagedEntity {
+ tid := oo.getNextTid(highPrio)
+ logger.Debugw("send EVTOCD-Delete-msg:", log.Fields{"device-id": oo.deviceID,
+ "SequNo": strconv.FormatInt(int64(tid), 16),
+ "InstId": strconv.FormatInt(int64(params[0].EntityID), 16)})
+
+ meInstance, omciErr := me.NewExtendedVlanTaggingOperationConfigurationData(params[0])
+ if omciErr.GetError() == nil {
+ omciLayer, msgLayer, err := omci.EncodeFrame(meInstance, omci.DeleteRequestType, omci.TransactionID(tid))
+ if err != nil {
+ logger.Errorw("Cannot encode EVTOCD for delete", log.Fields{
+ "Err": err, "device-id": oo.deviceID})
+ return nil
+ }
+
+ pkt, err := serializeOmciLayer(omciLayer, msgLayer)
+ if err != nil {
+ logger.Errorw("Cannot serialize EVTOCD delete", log.Fields{
+ "Err": err, "device-id": oo.deviceID})
+ return nil
+ }
+
+ omciRxCallbackPair := callbackPair{
+ cbKey: tid,
+ cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse},
+ }
+ err = oo.send(ctx, pkt, timeout, 0, highPrio, omciRxCallbackPair)
+ if err != nil {
+ logger.Errorw("Cannot send EVTOCD delete", log.Fields{
+ "Err": err, "device-id": oo.deviceID})
+ return nil
+ }
+ logger.Debug("send EVTOCD-delete msg done")
+ return meInstance
+ }
+ logger.Errorw("Cannot generate EVTOCD Instance", log.Fields{
+ "Err": omciErr.GetError(), "device-id": oo.deviceID})
+ return nil
+}
+
func (oo *omciCC) sendDeleteVtfd(ctx context.Context, timeout int, highPrio bool,
rxChan chan Message, aInstID uint16) *me.ManagedEntity {
tid := oo.getNextTid(highPrio)
@@ -1882,6 +1963,45 @@
}
// nolint: unused
+func (oo *omciCC) sendSetMulticastGemIWTPVar(ctx context.Context, timeout int, highPrio bool,
+ rxChan chan Message, params ...me.ParamData) *me.ManagedEntity {
+ tid := oo.getNextTid(highPrio)
+ logger.Debugw("send MulticastGemIWTP-set-msg:", log.Fields{"device-id": oo.deviceID,
+ "SequNo": strconv.FormatInt(int64(tid), 16),
+ "InstId": strconv.FormatInt(int64(params[0].EntityID), 16)})
+
+ meInstance, omciErr := me.NewMulticastGemInterworkingTerminationPoint(params[0])
+ if omciErr.GetError() == nil {
+ omciLayer, msgLayer, err := omci.EncodeFrame(meInstance, omci.SetRequestType, omci.TransactionID(tid),
+ omci.AddDefaults(true))
+ if err != nil {
+ logger.Errorw("Cannot encode MulticastGEMIWTP for set", log.Fields{"Err": err, "device-id": oo.deviceID})
+ return nil
+ }
+
+ pkt, err := serializeOmciLayer(omciLayer, msgLayer)
+ if err != nil {
+ logger.Errorw("Cannot serialize MulticastGEMIWTP create", log.Fields{"Err": err, "device-id": oo.deviceID})
+ return nil
+ }
+
+ omciRxCallbackPair := callbackPair{cbKey: tid,
+ cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse},
+ }
+ err = oo.send(ctx, pkt, timeout, 0, highPrio, omciRxCallbackPair)
+ if err != nil {
+ logger.Errorw("Cannot send MulticastGEMIWTP set", log.Fields{"Err": err, "device-id": oo.deviceID})
+ return nil
+ }
+ logger.Debug("send MulticastGEMIWTP-set-msg done")
+ return meInstance
+ }
+ logger.Errorw("Cannot generate MulticastGEMIWTP Instance", log.Fields{"Err": omciErr.GetError(),
+ "device-id": oo.deviceID})
+ return nil
+}
+
+// nolint: unused
func (oo *omciCC) sendCreateMulticastOperationProfileVar(ctx context.Context, timeout int, highPrio bool,
rxChan chan Message, params ...me.ParamData) *me.ManagedEntity {
tid := oo.getNextTid(highPrio)
diff --git a/internal/pkg/onuadaptercore/omci_vlan_config.go b/internal/pkg/onuadaptercore/omci_vlan_config.go
index aeb6967..b9c9d79 100644
--- a/internal/pkg/onuadaptercore/omci_vlan_config.go
+++ b/internal/pkg/onuadaptercore/omci_vlan_config.go
@@ -21,6 +21,7 @@
"context"
"encoding/binary"
"fmt"
+ "net"
"strconv"
"sync"
"time"
@@ -135,7 +136,6 @@
pOnuUniPort *onuUniPort
pUniTechProf *onuUniTechProf
pOnuDB *onuDeviceDB
- techProfileID uint16
requestEvent OnuDeviceEvent
omciMIdsResponseReceived chan bool //seperate channel needed for checking multiInstance OMCI message responses
pAdaptFsm *AdapterFsm
@@ -149,7 +149,6 @@
numRemoveFlows uint8
numVlanFilterEntries uint8
vlanFilterList [cVtfdTableSize]uint16
- vtfdID uint16
evtocdID uint16
pLastTxMeInstance *me.ManagedEntity
requestEventOffset uint8
@@ -168,7 +167,6 @@
pOnuUniPort: apUniPort,
pUniTechProf: apUniTechProf,
pOnuDB: apOnuDB,
- techProfileID: aTechProfileID,
requestEvent: aRequestEvent,
acceptIncrementalEvtoOption: aAcceptIncrementalEvto,
numUniFlows: 0,
@@ -482,7 +480,7 @@
oFsm.uniVlanFlowParamsSlice = nil //reset the slice
//at this point it is evident that no flow anymore refers to a still possibly active Techprofile
//request that this profile gets deleted before a new flow add is allowed
- oFsm.pUniTechProf.setProfileToDelete(oFsm.pOnuUniPort.uniID, uint8(oFsm.techProfileID), true)
+ oFsm.pUniTechProf.setProfileToDelete(oFsm.pOnuUniPort.uniID, uint8(loRemoveParams.vlanRuleParams.TpID), true)
logger.Debugw("UniVlanConfigFsm flow removal - no more flows", log.Fields{
"device-id": oFsm.deviceID})
} else {
@@ -512,7 +510,7 @@
logger.Debugw("UniVlanConfigFsm tp-id used in deleted flow is not used anymore", log.Fields{
"device-id": oFsm.deviceID, "tp-id": usedTpID})
//request that this profile gets deleted before a new flow add is allowed
- oFsm.pUniTechProf.setProfileToDelete(oFsm.pOnuUniPort.uniID, uint8(oFsm.techProfileID), true)
+ oFsm.pUniTechProf.setProfileToDelete(oFsm.pOnuUniPort.uniID, uint8(usedTpID), true)
}
logger.Debugw("UniVlanConfigFsm flow removal - specific flow removed from data", log.Fields{
"device-id": oFsm.deviceID})
@@ -588,12 +586,11 @@
// obviously calling some FSM event here directly does not work - so trying to decouple it ...
go func(a_pAFsm *AdapterFsm) {
if a_pAFsm != nil && a_pAFsm.pFsm != nil {
- //stick to pythonAdapter numbering scheme
- oFsm.vtfdID = macBridgePortAniEID + oFsm.pOnuUniPort.entityID + oFsm.techProfileID
+ tpID := oFsm.uniVlanFlowParamsSlice[oFsm.configuredUniFlow].VlanRuleParams.TpID
//cmp also usage in EVTOCDE create in omci_cc
oFsm.evtocdID = macBridgeServiceProfileEID + uint16(oFsm.pOnuUniPort.macBpNo)
- if oFsm.pUniTechProf.getTechProfileDone(oFsm.pOnuUniPort.uniID, uint8(oFsm.techProfileID)) {
+ if oFsm.pUniTechProf.getTechProfileDone(oFsm.pOnuUniPort.uniID, uint8(tpID)) {
// let the vlan processing begin
_ = a_pAFsm.pFsm.Event(vlanEvStartConfig)
} else {
@@ -630,8 +627,11 @@
_ = a_pAFsm.pFsm.Event(vlanEvRxConfigVtfd)
}(pConfigVlanStateAFsm)
} else {
+ // This attribute uniquely identifies each instance of this managed entity. Through an identical ID,
+ // this managed entity is implicitly linked to an instance of the MAC bridge port configuration data ME.
+ vtfdID := macBridgePortAniEID + oFsm.pOnuUniPort.entityID + oFsm.uniVlanFlowParamsSlice[0].VlanRuleParams.TpID
logger.Debugw("UniVlanConfigFsm create VTFD", log.Fields{
- "EntitytId": strconv.FormatInt(int64(oFsm.vtfdID), 16),
+ "EntitytId": strconv.FormatInt(int64(vtfdID), 16),
"in state": e.FSM.Current(), "device-id": oFsm.deviceID})
// setVid is assumed to be masked already by the caller to 12 bit
oFsm.vlanFilterList[0] = uint16(oFsm.uniVlanFlowParamsSlice[0].VlanRuleParams.SetVid)
@@ -640,7 +640,7 @@
vtfdFilterList[0] = oFsm.vlanFilterList[0]
oFsm.numVlanFilterEntries = 1
meParams := me.ParamData{
- EntityID: oFsm.vtfdID,
+ EntityID: vtfdID,
Attributes: me.AttributeValueMap{
"VlanFilterList": vtfdFilterList, //omci lib wants a slice for serialization
"ForwardOperation": uint8(0x10), //VID investigation
@@ -664,7 +664,28 @@
logger.Debugw("UniVlanConfigFsm - start config EVTOCD loop", log.Fields{
"in state": e.FSM.Current(), "device-id": oFsm.deviceID})
oFsm.requestEventOffset = 0 //0 offset for last flow-add activity
- go oFsm.performConfigEvtocdEntries(0)
+ go func() {
+ tpID := oFsm.uniVlanFlowParamsSlice[0].VlanRuleParams.TpID
+ vlanID := oFsm.uniVlanFlowParamsSlice[0].VlanRuleParams.SetVid
+ errEvto := oFsm.performConfigEvtocdEntries(oFsm.configuredUniFlow)
+ //This is correct passing scenario
+ if errEvto == nil {
+ for _, gemPort := range oFsm.pUniTechProf.getMulticastGemPorts(oFsm.pOnuUniPort.uniID, uint8(tpID)) {
+ log.Infow("Setting multicast MEs, with first flow", log.Fields{"deviceID": oFsm.deviceID,
+ "techProfile": tpID, "gemPort": gemPort, "vlanID": vlanID, "configuredUniFlow": oFsm.configuredUniFlow})
+ //can Use the first elements in the slice because it's the first flow.
+ errCreateAllMulticastME := oFsm.performSettingMulticastME(tpID, gemPort,
+ vlanID)
+ if errCreateAllMulticastME != nil {
+ logger.Errorw("Multicast ME create failed, aborting AniConfig FSM!",
+ log.Fields{"device-id": oFsm.deviceID})
+ _ = oFsm.pAdaptFsm.pFsm.Event(vlanEvReset)
+ }
+ }
+ //TODO Possibly insert new state for multicast --> possibly another jira/later time.
+ _ = oFsm.pAdaptFsm.pFsm.Event(vlanEvRxConfigEvtocd)
+ }
+ }()
}
func (oFsm *UniVlanConfigFsm) enterVlanConfigDone(e *fsm.Event) {
@@ -732,18 +753,25 @@
"in state": e.FSM.Current(), "device-id": oFsm.deviceID})
} else {
if oFsm.numVlanFilterEntries == 0 {
+ // This attribute uniquely identifies each instance of this managed entity. Through an identical ID,
+ // this managed entity is implicitly linked to an instance of the MAC bridge port configuration data ME.
+ vtfdID := macBridgePortAniEID + oFsm.pOnuUniPort.entityID + oFsm.uniVlanFlowParamsSlice[0].VlanRuleParams.TpID
//no VTFD yet created
logger.Debugw("UniVlanConfigFsm create VTFD", log.Fields{
- "EntitytId": strconv.FormatInt(int64(oFsm.vtfdID), 16),
+ "EntitytId": strconv.FormatInt(int64(vtfdID), 16),
"in state": e.FSM.Current(), "device-id": oFsm.deviceID})
- // setVid is assumed to be masked already by the caller to 12 bit
- oFsm.vlanFilterList[0] = uint16(oFsm.uniVlanFlowParamsSlice[oFsm.configuredUniFlow].VlanRuleParams.SetVid)
+ // FIXME: VOL-3673: using oFsm.uniVlanFlowParamsSlice[0] is incorrect here, as the relevant (first) VTFD may
+ // result from some incremented rule (not all rules enforce a VTFD configuration). But this is Ok for the
+ // current scenarios we support.
+ // 'SetVid' below is assumed to be masked already by the caller to 12 bit
+ oFsm.vlanFilterList[0] = uint16(oFsm.uniVlanFlowParamsSlice[0].VlanRuleParams.SetVid)
+
oFsm.mutexFlowParams.Unlock()
vtfdFilterList := make([]uint16, cVtfdTableSize) //needed for parameter serialization
vtfdFilterList[0] = oFsm.vlanFilterList[0]
oFsm.numVlanFilterEntries = 1
meParams := me.ParamData{
- EntityID: oFsm.vtfdID,
+ EntityID: vtfdID,
Attributes: me.AttributeValueMap{
"VlanFilterList": vtfdFilterList,
"ForwardOperation": uint8(0x10), //VID investigation
@@ -759,29 +787,34 @@
// (relevant to all used sendXX() methods in this (and other) FSM's)
oFsm.pLastTxMeInstance = meInstance
} else {
- //VTFD already exists - just modify by 'set'
- //TODO!!: but only if the VID is not already present, skipped by now to test basic working
+ // This attribute uniquely identifies each instance of this managed entity. Through an identical ID,
+ // this managed entity is implicitly linked to an instance of the MAC bridge port configuration data ME.
+ vtfdID := macBridgePortAniEID + oFsm.pOnuUniPort.entityID + oFsm.uniVlanFlowParamsSlice[oFsm.configuredUniFlow].VlanRuleParams.TpID
+
logger.Debugw("UniVlanConfigFsm set VTFD", log.Fields{
- "EntitytId": strconv.FormatInt(int64(oFsm.vtfdID), 16),
+ "EntitytId": strconv.FormatInt(int64(vtfdID), 16),
"in state": e.FSM.Current(), "device-id": oFsm.deviceID})
// setVid is assumed to be masked already by the caller to 12 bit
oFsm.vlanFilterList[oFsm.numVlanFilterEntries] =
uint16(oFsm.uniVlanFlowParamsSlice[oFsm.configuredUniFlow].VlanRuleParams.SetVid)
- oFsm.mutexFlowParams.Unlock()
vtfdFilterList := make([]uint16, cVtfdTableSize) //needed for parameter serialization
- for i := uint8(0); i <= oFsm.numVlanFilterEntries; i++ {
- vtfdFilterList[i] = oFsm.vlanFilterList[i]
- }
+
+ // FIXME: VOL-3685: Issues with resetting a table entry in EVTOCD ME
+ // VTFD has to be created afresh with a new entity ID that has the same entity ID as the MBPCD ME for every
+ // new vlan associated with a different TP.
+ vtfdFilterList[0] = uint16(oFsm.uniVlanFlowParamsSlice[oFsm.configuredUniFlow].VlanRuleParams.SetVid)
+ oFsm.mutexFlowParams.Unlock()
oFsm.numVlanFilterEntries++
meParams := me.ParamData{
- EntityID: oFsm.vtfdID,
+ EntityID: vtfdID,
Attributes: me.AttributeValueMap{
- "VlanFilterList": vtfdFilterList,
- "NumberOfEntries": oFsm.numVlanFilterEntries,
+ "VlanFilterList": vtfdFilterList,
+ "ForwardOperation": uint8(0x10), //VID investigation
+ "NumberOfEntries": oFsm.numVlanFilterEntries,
},
}
- meInstance := oFsm.pOmciCC.sendSetVtfdVar(context.TODO(), ConstDefaultOmciTimeout, true,
+ meInstance := oFsm.pOmciCC.sendCreateVtfdVar(context.TODO(), ConstDefaultOmciTimeout, true,
oFsm.pAdaptFsm.commChan, meParams)
//accept also nil as (error) return value for writing to LastTx
// - this avoids misinterpretation of new received OMCI messages
@@ -803,7 +836,28 @@
}
}
oFsm.requestEventOffset = 0 //0 offset for last flow-add activity
- go oFsm.performConfigEvtocdEntries(oFsm.configuredUniFlow)
+ go func() {
+ tpID := oFsm.uniVlanFlowParamsSlice[oFsm.configuredUniFlow].VlanRuleParams.TpID
+ errEvto := oFsm.performConfigEvtocdEntries(oFsm.configuredUniFlow)
+ //This is correct passing scenario
+ if errEvto == nil {
+ //TODO Possibly insert new state for multicast --> possibly another jira/later time.
+ for _, gemPort := range oFsm.pUniTechProf.getMulticastGemPorts(oFsm.pOnuUniPort.uniID, uint8(tpID)) {
+ vlanID := oFsm.uniVlanFlowParamsSlice[oFsm.configuredUniFlow-1].VlanRuleParams.SetVid
+ log.Infow("Setting multicast MEs for additional flows", log.Fields{"deviceID": oFsm.deviceID,
+ "techProfile": tpID, "gemPort": gemPort,
+ "vlanID": vlanID, "configuredUniFlow": oFsm.configuredUniFlow})
+ //-1 is to use the last configured flow
+ errCreateAllMulticastME := oFsm.performSettingMulticastME(tpID, gemPort, vlanID)
+ if errCreateAllMulticastME != nil {
+ logger.Errorw("Multicast ME create failed, aborting AniConfig FSM!",
+ log.Fields{"device-id": oFsm.deviceID})
+ _ = oFsm.pAdaptFsm.pFsm.Event(vlanEvReset)
+ }
+ }
+ _ = oFsm.pAdaptFsm.pFsm.Event(vlanEvRxConfigEvtocd)
+ }
+ }()
}
func (oFsm *UniVlanConfigFsm) enterRemoveFlow(e *fsm.Event) {
@@ -831,6 +885,7 @@
} else {
vtfdFilterList := make([]uint16, cVtfdTableSize) //needed for parameter serialization and 're-copy'
if oFsm.numVlanFilterEntries == 1 {
+ vtfdID := macBridgePortAniEID + oFsm.pOnuUniPort.entityID + loRuleParams.TpID
//only one active VLAN entry (hopefully the SetVID we want to remove - should be, but not verified ..)
// so we can just delete the VTFD entry
logger.Debugw("UniVlanConfigFsm: VTFD delete (no more vlan filters)",
@@ -839,7 +894,7 @@
loVlanEntryClear = 1 //full VlanFilter clear request
if loAllowSpecificOmciConfig { //specific OMCI config is expected to work acc. to the device state
meInstance := oFsm.pOmciCC.sendDeleteVtfd(context.TODO(), ConstDefaultOmciTimeout, true,
- oFsm.pAdaptFsm.commChan, oFsm.vtfdID)
+ oFsm.pAdaptFsm.commChan, vtfdID)
oFsm.pLastTxMeInstance = meInstance
} else {
logger.Debugw("UniVlanConfigFsm delete VTFD OMCI handling skipped based on device state", log.Fields{
@@ -858,6 +913,7 @@
}
}
if loVlanEntryRmPos < cVtfdTableSize {
+ vtfdID := macBridgePortAniEID + oFsm.pOnuUniPort.entityID + loRuleParams.TpID
//valid entry was found - to be eclipsed
loVlanEntryClear = 2 //VlanFilter remove request for a specific entry
for i := uint8(0); i < oFsm.numVlanFilterEntries; i++ {
@@ -870,19 +926,13 @@
}
}
logger.Debugw("UniVlanConfigFsm set VTFD", log.Fields{
- "EntitytId": strconv.FormatInt(int64(oFsm.vtfdID), 16),
+ "EntitytId": strconv.FormatInt(int64(vtfdID), 16),
"new vlan list": vtfdFilterList, "device-id": oFsm.deviceID})
if loAllowSpecificOmciConfig { //specific OMCI config is expected to work acc. to the device state
- meParams := me.ParamData{
- EntityID: oFsm.vtfdID,
- Attributes: me.AttributeValueMap{
- "VlanFilterList": vtfdFilterList,
- "NumberOfEntries": oFsm.numVlanFilterEntries - 1, //one element less
- },
- }
- meInstance := oFsm.pOmciCC.sendSetVtfdVar(context.TODO(), ConstDefaultOmciTimeout, true,
- oFsm.pAdaptFsm.commChan, meParams)
+ // FIXME: VOL-3685: Issues with resetting a table entry in EVTOCD ME
+ meInstance := oFsm.pOmciCC.sendDeleteVtfd(context.TODO(), ConstDefaultOmciTimeout, true,
+ oFsm.pAdaptFsm.commChan, vtfdID)
oFsm.pLastTxMeInstance = meInstance
} else {
logger.Debugw("UniVlanConfigFsm set VTFD OMCI handling skipped based on device state", log.Fields{
@@ -1083,8 +1133,7 @@
if msgObj.EntityClass == oFsm.pLastTxMeInstance.GetClassID() &&
msgObj.EntityInstance == oFsm.pLastTxMeInstance.GetEntityID() {
switch oFsm.pLastTxMeInstance.GetName() {
- case "VlanTaggingFilterData",
- "ExtendedVlanTaggingOperationConfigurationData":
+ case "VlanTaggingFilterData", "ExtendedVlanTaggingOperationConfigurationData", "MulticastOperationsProfile":
{ // let the MultiEntity config proceed by stopping the wait function
oFsm.omciMIdsResponseReceived <- true
}
@@ -1123,7 +1172,7 @@
oFsm.deviceID)
}
logger.Debugw("UniVlanConfigFsm CreateResponse Data", log.Fields{"device-id": oFsm.deviceID, "data-fields": msgObj})
- if msgObj.Result != me.Success {
+ if msgObj.Result != me.Success && msgObj.Result != me.InstanceExists {
logger.Errorw("Omci CreateResponse Error - later: drive FSM to abort state ?", log.Fields{"device-id": oFsm.deviceID,
"Error": msgObj.Result})
// possibly force FSM into abort or ignore some errors for some messages? store error for mgmt display?
@@ -1134,7 +1183,9 @@
msgObj.EntityInstance == oFsm.pLastTxMeInstance.GetEntityID() {
// to satisfy StaticCodeAnalysis I had to move the small processing into a separate method :-(
switch oFsm.pLastTxMeInstance.GetName() {
- case "VlanTaggingFilterData":
+ case "VlanTaggingFilterData", "MulticastOperationsProfile",
+ "MulticastSubscriberConfigInfo", "MacBridgePortConfigurationData",
+ "ExtendedVlanTaggingOperationConfigurationData":
{
if oFsm.pAdaptFsm.pFsm.Current() == vlanStConfigVtfd {
// Only if CreateResponse is received from first flow entry - let the FSM proceed ...
@@ -1174,7 +1225,7 @@
if msgObj.EntityClass == oFsm.pLastTxMeInstance.GetClassID() &&
msgObj.EntityInstance == oFsm.pLastTxMeInstance.GetEntityID() {
switch oFsm.pLastTxMeInstance.GetName() {
- case "VlanTaggingFilterData":
+ case "VlanTaggingFilterData", "ExtendedVlanTaggingOperationConfigurationData":
{ // let the MultiEntity config proceed by stopping the wait function
oFsm.omciMIdsResponseReceived <- true
}
@@ -1183,24 +1234,31 @@
return nil
}
-func (oFsm *UniVlanConfigFsm) performConfigEvtocdEntries(aFlowEntryNo uint8) {
+func (oFsm *UniVlanConfigFsm) performConfigEvtocdEntries(aFlowEntryNo uint8) error {
if aFlowEntryNo == 0 {
// EthType set only at first flow element
// EVTOCD ME is expected to exist at this point already from MIB-Download (with AssociationType/Pointer)
// we need to extend the configuration by EthType definition and, to be sure, downstream 'inverse' mode
- logger.Debugw("UniVlanConfigFsm Tx Set::EVTOCD", log.Fields{
+ logger.Debugw("UniVlanConfigFsm Tx Create::EVTOCD", log.Fields{
"EntitytId": strconv.FormatInt(int64(oFsm.evtocdID), 16),
"i/oEthType": strconv.FormatInt(int64(cDefaultTpid), 16),
"device-id": oFsm.deviceID})
+ associationType := 2 // default to uniPPTP
+ if oFsm.pOnuUniPort.portType == uniVEIP {
+ associationType = 10
+ }
+ // Create the EVTOCD ME
meParams := me.ParamData{
EntityID: oFsm.evtocdID,
Attributes: me.AttributeValueMap{
- "InputTpid": uint16(cDefaultTpid), //could be possibly retrieved from flow config one day, by now just like py-code base
- "OutputTpid": uint16(cDefaultTpid), //could be possibly retrieved from flow config one day, by now just like py-code base
- "DownstreamMode": uint8(cDefaultDownstreamMode),
+ "InputTpid": uint16(cDefaultTpid), //could be possibly retrieved from flow config one day, by now just like py-code base
+ "OutputTpid": uint16(cDefaultTpid), //could be possibly retrieved from flow config one day, by now just like py-code base
+ "DownstreamMode": uint8(cDefaultDownstreamMode),
+ "AssociationType": uint8(associationType),
+ "AssociatedMePointer": oFsm.pOnuUniPort.entityID,
},
}
- meInstance := oFsm.pOmciCC.sendSetEvtocdVar(context.TODO(), ConstDefaultOmciTimeout, true,
+ meInstance := oFsm.pOmciCC.sendCreateEvtocdVar(context.TODO(), ConstDefaultOmciTimeout, true,
oFsm.pAdaptFsm.commChan, meParams)
//accept also nil as (error) return value for writing to LastTx
// - this avoids misinterpretation of new received OMCI messages
@@ -1209,10 +1267,34 @@
//verify response
err := oFsm.waitforOmciResponse()
if err != nil {
+ logger.Errorw("Evtocd create failed, aborting VlanConfig FSM!",
+ log.Fields{"device-id": oFsm.deviceID})
+ _ = oFsm.pAdaptFsm.pFsm.Event(vlanEvReset)
+ return fmt.Errorf("evtocd create failed %s, error %s", oFsm.deviceID, err)
+ }
+
+ // Set the EVTOCD ME default params
+ meParams = me.ParamData{
+ EntityID: oFsm.evtocdID,
+ Attributes: me.AttributeValueMap{
+ "InputTpid": uint16(cDefaultTpid), //could be possibly retrieved from flow config one day, by now just like py-code base
+ "OutputTpid": uint16(cDefaultTpid), //could be possibly retrieved from flow config one day, by now just like py-code base
+ "DownstreamMode": uint8(cDefaultDownstreamMode),
+ },
+ }
+ meInstance = oFsm.pOmciCC.sendSetEvtocdVar(context.TODO(), ConstDefaultOmciTimeout, true,
+ oFsm.pAdaptFsm.commChan, meParams)
+ //accept also nil as (error) return value for writing to LastTx
+ // - this avoids misinterpretation of new received OMCI messages
+ oFsm.pLastTxMeInstance = meInstance
+
+ //verify response
+ err = oFsm.waitforOmciResponse()
+ if err != nil {
logger.Errorw("Evtocd set TPID failed, aborting VlanConfig FSM!",
log.Fields{"device-id": oFsm.deviceID})
_ = oFsm.pAdaptFsm.pFsm.Event(vlanEvReset)
- return
+ return fmt.Errorf("evtocd set TPID failed %s, error %s", oFsm.deviceID, err)
}
} //first flow element
@@ -1225,7 +1307,7 @@
go func(a_pAFsm *AdapterFsm) {
_ = a_pAFsm.pFsm.Event(vlanEvReset)
}(pConfigVlanStateAFsm)
- return
+ return nil
}
if oFsm.uniVlanFlowParamsSlice[aFlowEntryNo].VlanRuleParams.SetVid == uint32(of.OfpVlanId_OFPVID_PRESENT) {
@@ -1275,14 +1357,19 @@
logger.Errorw("Evtocd set transparent singletagged rule failed, aborting VlanConfig FSM!",
log.Fields{"device-id": oFsm.deviceID})
_ = oFsm.pAdaptFsm.pFsm.Event(vlanEvReset)
- return
+ return fmt.Errorf("evtocd set transparent singletagged rule failed %s, error %s", oFsm.deviceID, err)
+
}
} else {
// according to py-code acceptIncrementalEvto program option decides upon stacking or translation scenario
if oFsm.acceptIncrementalEvtoOption {
+ matchPcp := oFsm.uniVlanFlowParamsSlice[aFlowEntryNo].VlanRuleParams.MatchPcp
+ matchVid := oFsm.uniVlanFlowParamsSlice[aFlowEntryNo].VlanRuleParams.MatchVid
+ setPcp := oFsm.uniVlanFlowParamsSlice[aFlowEntryNo].VlanRuleParams.SetPcp
+ setVid := oFsm.uniVlanFlowParamsSlice[aFlowEntryNo].VlanRuleParams.SetVid
// this defines VID translation scenario: singletagged->singletagged (if not transparent)
logger.Debugw("UniVlanConfigFsm Tx Set::EVTOCD single tagged translation rule", log.Fields{
- "device-id": oFsm.deviceID})
+ "match-pcp": matchPcp, "match-vid": matchVid, "set-pcp": setPcp, "set-vid:": setVid, "device-id": oFsm.deviceID})
sliceEvtocdRule := make([]uint8, 16)
// fill vlan tagging operation table bit fields using network=bigEndian order and using slice offset 0 as highest 'word'
binary.BigEndian.PutUint32(sliceEvtocdRule[cFilterOuterOffset:],
@@ -1326,7 +1413,7 @@
logger.Errorw("Evtocd set singletagged translation rule failed, aborting VlanConfig FSM!",
log.Fields{"device-id": oFsm.deviceID})
_ = oFsm.pAdaptFsm.pFsm.Event(vlanEvReset)
- return
+ return fmt.Errorf("evtocd set singletagged translation rule failed %s, error %s", oFsm.deviceID, err)
}
} else {
//not transparent and not acceptIncrementalEvtoOption untagged/priotagged->singletagged
@@ -1378,7 +1465,8 @@
logger.Errorw("Evtocd set untagged->singletagged rule failed, aborting VlanConfig FSM!",
log.Fields{"device-id": oFsm.deviceID})
_ = oFsm.pAdaptFsm.pFsm.Event(vlanEvReset)
- return
+ return fmt.Errorf("evtocd set untagged->singletagged rule failed %s, error %s", oFsm.deviceID, err)
+
}
} // just for local var's
{ // just for local var's
@@ -1430,7 +1518,8 @@
logger.Errorw("Evtocd set priotagged->singletagged rule failed, aborting VlanConfig FSM!",
log.Fields{"device-id": oFsm.deviceID})
_ = oFsm.pAdaptFsm.pFsm.Event(vlanEvReset)
- return
+ return fmt.Errorf("evtocd set priotagged->singletagged rule failed %s, error %s", oFsm.deviceID, err)
+
}
} //just for local var's
}
@@ -1439,7 +1528,7 @@
// if Config has been done for all EVTOCD entries let the FSM proceed
logger.Debugw("EVTOCD set loop finished", log.Fields{"device-id": oFsm.deviceID})
oFsm.configuredUniFlow++ // one (more) flow configured
- _ = oFsm.pAdaptFsm.pFsm.Event(vlanEvRxConfigEvtocd)
+ return nil
}
func (oFsm *UniVlanConfigFsm) removeEvtocdEntries(aRuleParams uniVlanRuleParams) {
@@ -1538,46 +1627,24 @@
return
}
} else {
- //not transparent and not acceptIncrementalEvtoOption: untagged/priotagged->singletagged
- { // just for local var's
- // this defines stacking scenario: untagged->singletagged
- //TODO!! in theory there could be different rules running in setting different PCP/VID'S
- // for untagged/priotagged, last rule wins (and remains the only one), maybe that should be
- // checked already at flow-add (and rejected) - to be observed if such is possible in Voltha
- // delete now assumes there is only one such rule!
- logger.Debugw("UniVlanConfigFsm Tx Set::EVTOCD reset untagged rule to default", log.Fields{
- "device-id": oFsm.deviceID})
- sliceEvtocdRule := make([]uint8, 16)
- // fill vlan tagging operation table bit fields using network=bigEndian order and using slice offset 0 as highest 'word'
- binary.BigEndian.PutUint32(sliceEvtocdRule[cFilterOuterOffset:],
- cPrioIgnoreTag<<cFilterPrioOffset| // Not an outer-tag rule
- cDoNotFilterVid<<cFilterVidOffset| // Do not filter on outer vid
- cDoNotFilterTPID<<cFilterTpidOffset) // Do not filter on outer TPID field
-
- binary.BigEndian.PutUint32(sliceEvtocdRule[cFilterInnerOffset:],
- cPrioIgnoreTag<<cFilterPrioOffset| // Not an inner-tag rule
- cDoNotFilterVid<<cFilterVidOffset| // Do not filter on inner vid
- cDoNotFilterTPID<<cFilterTpidOffset| // Do not filter on inner TPID field
- cDoNotFilterEtherType<<cFilterEtherTypeOffset) // Do not filter of EtherType
-
- binary.BigEndian.PutUint32(sliceEvtocdRule[cTreatOuterOffset:],
- 0<<cTreatTTROffset| // Do not pop any tags
- cDoNotAddPrio<<cTreatPrioOffset| // do not add outer tag
- cDontCareVid<<cTreatVidOffset| // Outer VID don't care
- cDontCareTpid<<cTreatTpidOffset) // Outer TPID field don't care
-
- binary.BigEndian.PutUint32(sliceEvtocdRule[cTreatInnerOffset:],
- cDoNotAddPrio<<cTreatPrioOffset| // do not add inner tag
- cDontCareVid<<cTreatVidOffset| // Outer VID don't care
- cDontCareTpid<<cTreatTpidOffset) // copy TPID and DEI
-
+ // VOL-3685
+ // NOTE: With ALPHA ONUs it was seen that just resetting a particular entry in the EVTOCD table
+ // and re-configuring a new entry would not work. The old entry is removed and new entry is created
+ // indeed, but the traffic landing upstream would carry old vlan sometimes.
+ // This is only a WORKAROUND which basically deletes the entire EVTOCD ME and re-creates it again
+ // later when the flow is being re-installed.
+ // Of course this is applicable to case only where single service (or single tcont) is in use and
+ // there is only one service vlan (oFsm.acceptIncrementalEvtoOption is false in this case).
+ // Interstingly this problem has not been observed in multi-tcont (or multi-service) scenario (in
+ // which case the oFsm.acceptIncrementalEvtoOption is set to true).
+ if oFsm.configuredUniFlow == 0 && !oFsm.acceptIncrementalEvtoOption {
+ logger.Debugw("UniVlanConfigFsm Tx Remove::EVTOCD", log.Fields{"device-id": oFsm.deviceID})
+ // When there are no more EVTOCD vlan configurations on the ONU and acceptIncrementalEvtoOption
+ // is not enabled, delete the EVTOCD ME.
meParams := me.ParamData{
EntityID: oFsm.evtocdID,
- Attributes: me.AttributeValueMap{
- "ReceivedFrameVlanTaggingOperationTable": sliceEvtocdRule,
- },
}
- meInstance := oFsm.pOmciCC.sendSetEvtocdVar(context.TODO(), ConstDefaultOmciTimeout, true,
+ meInstance := oFsm.pOmciCC.sendDeleteEvtocd(context.TODO(), ConstDefaultOmciTimeout, true,
oFsm.pAdaptFsm.commChan, meParams)
//accept also nil as (error) return value for writing to LastTx
// - this avoids misinterpretation of new received OMCI messages
@@ -1586,52 +1653,111 @@
//verify response
err := oFsm.waitforOmciResponse()
if err != nil {
- logger.Errorw("Evtocd reset untagged rule to default failed, aborting VlanConfig FSM!",
+ logger.Errorw("Evtocd delete rule failed, aborting VlanConfig FSM!",
log.Fields{"device-id": oFsm.deviceID})
_ = oFsm.pAdaptFsm.pFsm.Event(vlanEvReset)
return
}
- } // just for local var's
- { // just for local var's
- // this defines 'stacking' scenario: priotagged->singletagged
- logger.Debugw("UniVlanConfigFsm Tx Set::EVTOCD delete priotagged rule", log.Fields{
- "device-id": oFsm.deviceID})
- sliceEvtocdRule := make([]uint8, 16)
- // fill vlan tagging operation table bit fields using network=bigEndian order and using slice offset 0 as highest 'word'
- binary.BigEndian.PutUint32(sliceEvtocdRule[cFilterOuterOffset:],
- cPrioIgnoreTag<<cFilterPrioOffset| // Not an outer-tag rule
- cDoNotFilterVid<<cFilterVidOffset| // Do not filter on outer vid
- cDoNotFilterTPID<<cFilterTpidOffset) // Do not filter on outer TPID field
+ } else {
+ // NOTE : We should ideally never ether this section when oFsm.acceptIncrementalEvtoOption is set to false
+ // This is true for only ATT/DT workflow
+ logger.Debugw("UniVlanConfigFsm: Remove EVTOCD set operation",
+ log.Fields{"configured-flow": oFsm.configuredUniFlow, "incremental-evto": oFsm.acceptIncrementalEvtoOption})
+ //not transparent and not acceptIncrementalEvtoOption: untagged/priotagged->singletagged
+ { // just for local var's
+ // this defines stacking scenario: untagged->singletagged
+ //TODO!! in theory there could be different rules running in setting different PCP/VID'S
+ // for untagged/priotagged, last rule wins (and remains the only one), maybe that should be
+ // checked already at flow-add (and rejected) - to be observed if such is possible in Voltha
+ // delete now assumes there is only one such rule!
+ logger.Debugw("UniVlanConfigFsm Tx Set::EVTOCD reset untagged rule to default", log.Fields{
+ "device-id": oFsm.deviceID})
+ sliceEvtocdRule := make([]uint8, 16)
+ // fill vlan tagging operation table bit fields using network=bigEndian order and using slice offset 0 as highest 'word'
+ binary.BigEndian.PutUint32(sliceEvtocdRule[cFilterOuterOffset:],
+ cPrioIgnoreTag<<cFilterPrioOffset| // Not an outer-tag rule
+ cDoNotFilterVid<<cFilterVidOffset| // Do not filter on outer vid
+ cDoNotFilterTPID<<cFilterTpidOffset) // Do not filter on outer TPID field
- binary.BigEndian.PutUint32(sliceEvtocdRule[cFilterInnerOffset:],
- cPrioDoNotFilter<<cFilterPrioOffset| // Do not Filter on innerprio
- 0<<cFilterVidOffset| // filter on inner vid 0 (prioTagged)
- cDoNotFilterTPID<<cFilterTpidOffset| // Do not filter on inner TPID field
- cDoNotFilterEtherType<<cFilterEtherTypeOffset) // Do not filter of EtherType
+ binary.BigEndian.PutUint32(sliceEvtocdRule[cFilterInnerOffset:],
+ cPrioIgnoreTag<<cFilterPrioOffset| // Not an inner-tag rule
+ cDoNotFilterVid<<cFilterVidOffset| // Do not filter on inner vid
+ cDoNotFilterTPID<<cFilterTpidOffset| // Do not filter on inner TPID field
+ cDoNotFilterEtherType<<cFilterEtherTypeOffset) // Do not filter of EtherType
- // delete indication for the indicated Filter
- binary.BigEndian.PutUint32(sliceEvtocdRule[cTreatOuterOffset:], 0xFFFFFFFF)
- binary.BigEndian.PutUint32(sliceEvtocdRule[cTreatInnerOffset:], 0xFFFFFFFF)
+ binary.BigEndian.PutUint32(sliceEvtocdRule[cTreatOuterOffset:],
+ 0<<cTreatTTROffset| // Do not pop any tags
+ cDoNotAddPrio<<cTreatPrioOffset| // do not add outer tag
+ cDontCareVid<<cTreatVidOffset| // Outer VID don't care
+ cDontCareTpid<<cTreatTpidOffset) // Outer TPID field don't care
- meParams := me.ParamData{
- EntityID: oFsm.evtocdID,
- Attributes: me.AttributeValueMap{
- "ReceivedFrameVlanTaggingOperationTable": sliceEvtocdRule,
- },
- }
- meInstance := oFsm.pOmciCC.sendSetEvtocdVar(context.TODO(), ConstDefaultOmciTimeout, true,
- oFsm.pAdaptFsm.commChan, meParams)
- //accept also nil as (error) return value for writing to LastTx
- // - this avoids misinterpretation of new received OMCI messages
- oFsm.pLastTxMeInstance = meInstance
+ binary.BigEndian.PutUint32(sliceEvtocdRule[cTreatInnerOffset:],
+ cDoNotAddPrio<<cTreatPrioOffset| // do not add inner tag
+ cDontCareVid<<cTreatVidOffset| // Outer VID don't care
+ cDontCareTpid<<cTreatTpidOffset) // copy TPID and DEI
- //verify response
- err := oFsm.waitforOmciResponse()
- if err != nil {
- logger.Errorw("Evtocd delete priotagged rule failed, aborting VlanConfig FSM!",
- log.Fields{"device-id": oFsm.deviceID})
- _ = oFsm.pAdaptFsm.pFsm.Event(vlanEvReset)
- return
+ meParams := me.ParamData{
+ EntityID: oFsm.evtocdID,
+ Attributes: me.AttributeValueMap{
+ "ReceivedFrameVlanTaggingOperationTable": sliceEvtocdRule,
+ },
+ }
+ meInstance := oFsm.pOmciCC.sendSetEvtocdVar(context.TODO(), ConstDefaultOmciTimeout, true,
+ oFsm.pAdaptFsm.commChan, meParams)
+ //accept also nil as (error) return value for writing to LastTx
+ // - this avoids misinterpretation of new received OMCI messages
+ oFsm.pLastTxMeInstance = meInstance
+
+ //verify response
+ err := oFsm.waitforOmciResponse()
+ if err != nil {
+ logger.Errorw("Evtocd reset untagged rule to default failed, aborting VlanConfig FSM!",
+ log.Fields{"device-id": oFsm.deviceID})
+ _ = oFsm.pAdaptFsm.pFsm.Event(vlanEvReset)
+ return
+ }
+ } // just for local var's
+ { // just for local var's
+ // this defines 'stacking' scenario: priotagged->singletagged
+ logger.Debugw("UniVlanConfigFsm Tx Set::EVTOCD delete priotagged rule", log.Fields{
+ "device-id": oFsm.deviceID})
+ sliceEvtocdRule := make([]uint8, 16)
+ // fill vlan tagging operation table bit fields using network=bigEndian order and using slice offset 0 as highest 'word'
+ binary.BigEndian.PutUint32(sliceEvtocdRule[cFilterOuterOffset:],
+ cPrioIgnoreTag<<cFilterPrioOffset| // Not an outer-tag rule
+ cDoNotFilterVid<<cFilterVidOffset| // Do not filter on outer vid
+ cDoNotFilterTPID<<cFilterTpidOffset) // Do not filter on outer TPID field
+
+ binary.BigEndian.PutUint32(sliceEvtocdRule[cFilterInnerOffset:],
+ cPrioDoNotFilter<<cFilterPrioOffset| // Do not Filter on innerprio
+ 0<<cFilterVidOffset| // filter on inner vid 0 (prioTagged)
+ cDoNotFilterTPID<<cFilterTpidOffset| // Do not filter on inner TPID field
+ cDoNotFilterEtherType<<cFilterEtherTypeOffset) // Do not filter of EtherType
+
+ // delete indication for the indicated Filter
+ binary.BigEndian.PutUint32(sliceEvtocdRule[cTreatOuterOffset:], 0xFFFFFFFF)
+ binary.BigEndian.PutUint32(sliceEvtocdRule[cTreatInnerOffset:], 0xFFFFFFFF)
+
+ meParams := me.ParamData{
+ EntityID: oFsm.evtocdID,
+ Attributes: me.AttributeValueMap{
+ "ReceivedFrameVlanTaggingOperationTable": sliceEvtocdRule,
+ },
+ }
+ meInstance := oFsm.pOmciCC.sendSetEvtocdVar(context.TODO(), ConstDefaultOmciTimeout, true,
+ oFsm.pAdaptFsm.commChan, meParams)
+ //accept also nil as (error) return value for writing to LastTx
+ // - this avoids misinterpretation of new received OMCI messages
+ oFsm.pLastTxMeInstance = meInstance
+
+ //verify response
+ err := oFsm.waitforOmciResponse()
+ if err != nil {
+ logger.Errorw("Evtocd delete priotagged rule failed, aborting VlanConfig FSM!",
+ log.Fields{"device-id": oFsm.deviceID})
+ _ = oFsm.pAdaptFsm.pFsm.Event(vlanEvReset)
+ return
+ }
}
} //just for local var's
}
@@ -1660,3 +1786,206 @@
return fmt.Errorf("uniVlanConfigFsm multi entity responseError %s", oFsm.deviceID)
}
}
+
+func (oFsm *UniVlanConfigFsm) performSettingMulticastME(tpID uint16, multicastGemPortID uint16, vlanID uint32) error {
+ logger.Debugw("Setting Multicast MEs", log.Fields{"device-id": oFsm.deviceID, "tpID": tpID,
+ "multicastGemPortID": multicastGemPortID, "vlanID": vlanID})
+ errCreateMOP := oFsm.performCreatingMulticastOperationProfile()
+ if errCreateMOP != nil {
+ logger.Errorw("MulticastOperationProfile create failed, aborting AniConfig FSM!",
+ log.Fields{"device-id": oFsm.deviceID})
+ _ = oFsm.pAdaptFsm.pFsm.Event(aniEvReset)
+ return fmt.Errorf("creatingMulticastSubscriberConfigInfo responseError %s, error %s", oFsm.deviceID, errCreateMOP)
+ }
+
+ errSettingMOP := oFsm.performSettingMulticastOperationProfile(multicastGemPortID, vlanID)
+ if errSettingMOP != nil {
+ logger.Errorw("MulticastOperationProfile setting failed, aborting AniConfig FSM!",
+ log.Fields{"device-id": oFsm.deviceID})
+ _ = oFsm.pAdaptFsm.pFsm.Event(aniEvReset)
+ return fmt.Errorf("creatingMulticastSubscriberConfigInfo responseError %s, error %s", oFsm.deviceID, errSettingMOP)
+ }
+
+ errCreateMSCI := oFsm.performCreatingMulticastSubscriberConfigInfo()
+ if errCreateMSCI != nil {
+ logger.Errorw("MulticastOperationProfile setting failed, aborting AniConfig FSM!",
+ log.Fields{"device-id": oFsm.deviceID})
+ _ = oFsm.pAdaptFsm.pFsm.Event(aniEvReset)
+ return fmt.Errorf("creatingMulticastSubscriberConfigInfo responseError %s, error %s", oFsm.deviceID, errCreateMSCI)
+ }
+
+ meParams := me.ParamData{
+ EntityID: macBridgeServiceProfileEID + uint16(oFsm.pOnuUniPort.macBpNo),
+ Attributes: me.AttributeValueMap{
+ "BridgeIdPointer": macBridgeServiceProfileEID + uint16(oFsm.pOnuUniPort.macBpNo),
+ "PortNum": 0xf0, //fixed unique ANI side indication
+ "TpType": 6, //MCGemIWTP
+ "TpPointer": multicastGemPortID,
+ },
+ }
+ meInstance := oFsm.pOmciCC.sendCreateMBPConfigDataVar(context.TODO(), ConstDefaultOmciTimeout, true,
+ oFsm.pAdaptFsm.commChan, meParams)
+ //accept also nil as (error) return value for writing to LastTx
+ // - this avoids misinterpretation of new received OMCI messages
+ oFsm.pLastTxMeInstance = meInstance
+ err := oFsm.waitforOmciResponse()
+ if err != nil {
+ logger.Errorw("CreateMBPConfigData failed, aborting AniConfig FSM!",
+ log.Fields{"device-id": oFsm.deviceID, "MBPConfigDataID": macBridgeServiceProfileEID})
+ _ = oFsm.pAdaptFsm.pFsm.Event(aniEvReset)
+ return fmt.Errorf("creatingMulticastSubscriberConfigInfo responseError %s, error %s", oFsm.deviceID, err)
+ }
+
+ // ==> Start creating VTFD for mcast vlan
+
+ // This attribute uniquely identifies each instance of this managed entity. Through an identical ID,
+ // this managed entity is implicitly linked to an instance of the MAC bridge port configuration data ME.
+ mcastVtfdID := macBridgeServiceProfileEID + uint16(oFsm.pOnuUniPort.macBpNo)
+
+ logger.Debugw("UniVlanConfigFsm set VTFD for mcast", log.Fields{
+ "EntitytId": strconv.FormatInt(int64(mcastVtfdID), 16), "mcastVlanID": vlanID,
+ "in state": oFsm.pAdaptFsm.pFsm.Current(), "device-id": oFsm.deviceID})
+ vtfdFilterList := make([]uint16, cVtfdTableSize) //needed for parameter serialization
+
+ // FIXME: VOL-3685: Issues with resetting a table entry in EVTOCD ME
+ // VTFD has to be created afresh with a new entity ID that has the same entity ID as the MBPCD ME for every
+ // new vlan associated with a different TP.
+ vtfdFilterList[0] = uint16(vlanID)
+
+ meParams = me.ParamData{
+ EntityID: mcastVtfdID,
+ Attributes: me.AttributeValueMap{
+ "VlanFilterList": vtfdFilterList,
+ "ForwardOperation": uint8(0x10), //VID investigation
+ "NumberOfEntries": oFsm.numVlanFilterEntries,
+ },
+ }
+ meInstance = oFsm.pOmciCC.sendCreateVtfdVar(context.TODO(), ConstDefaultOmciTimeout, true,
+ oFsm.pAdaptFsm.commChan, meParams)
+ oFsm.pLastTxMeInstance = meInstance
+ err = oFsm.waitforOmciResponse()
+ if err != nil {
+ logger.Errorw("CreateMcastVlanFilterData failed, aborting AniConfig FSM!",
+ log.Fields{"device-id": oFsm.deviceID, "mcastVtfdID": mcastVtfdID})
+ _ = oFsm.pAdaptFsm.pFsm.Event(aniEvReset)
+ return fmt.Errorf("createMcastVlanFilterData responseError %s, error %s", oFsm.deviceID, err)
+ }
+
+ return nil
+}
+
+func (oFsm *UniVlanConfigFsm) performCreatingMulticastSubscriberConfigInfo() error {
+ instID, err := oFsm.pDeviceHandler.getUniPortMEEntityID(oFsm.pOnuUniPort.portNo)
+ if err != nil {
+ log.Errorw("error fetching uni port me instance",
+ log.Fields{"device-id": oFsm.deviceID, "portNo": oFsm.pOnuUniPort.portNo})
+ return err
+ }
+ meParams := me.ParamData{
+ EntityID: instID,
+ Attributes: me.AttributeValueMap{
+ "MeType": 0,
+ //Direct reference to the Operation profile
+ //TODO ANI side used on UNI side, not the clearest option.
+ "MulticastOperationsProfilePointer": macBridgePortAniEID + uint16(oFsm.pOnuUniPort.macBpNo),
+ },
+ }
+ meInstance := oFsm.pOmciCC.sendCreateMulticastSubConfigInfoVar(context.TODO(), ConstDefaultOmciTimeout, true,
+ oFsm.pAdaptFsm.commChan, meParams)
+ //accept also nil as (error) return value for writing to LastTx
+ // - this avoids misinterpretation of new received OMCI messages
+ oFsm.pLastTxMeInstance = meInstance
+ //verify response
+ err = oFsm.waitforOmciResponse()
+ if err != nil {
+ logger.Errorw("CreateMulticastSubConfigInfo create failed, aborting AniConfig FSM!",
+ log.Fields{"device-id": oFsm.deviceID, "MulticastSubConfigInfo": instID})
+ return fmt.Errorf("creatingMulticastSubscriberConfigInfo responseError %s", oFsm.deviceID)
+ }
+ return nil
+}
+
+func (oFsm *UniVlanConfigFsm) performCreatingMulticastOperationProfile() error {
+ instID := macBridgePortAniEID + uint16(oFsm.pOnuUniPort.macBpNo)
+ meParams := me.ParamData{
+ EntityID: instID,
+ Attributes: me.AttributeValueMap{
+ "IgmpVersion": 2,
+ "IgmpFunction": 0,
+ //0 means false
+ "ImmediateLeave": 0,
+ "Robustness": 2,
+ "QuerierIp": 0,
+ "QueryInterval": 125,
+ "QuerierMaxResponseTime": 100,
+ "LastMemberResponseTime": 10,
+ //0 means false
+ "UnauthorizedJoinBehaviour": 0,
+ },
+ }
+ meInstance := oFsm.pOmciCC.sendCreateMulticastOperationProfileVar(context.TODO(), ConstDefaultOmciTimeout, true,
+ oFsm.pAdaptFsm.commChan, meParams)
+ //accept also nil as (error) return value for writing to LastTx
+ // - this avoids misinterpretation of new received OMCI messages
+ oFsm.pLastTxMeInstance = meInstance
+ //verify response
+ err := oFsm.waitforOmciResponse()
+ if err != nil {
+ logger.Errorw("CreateMulticastOperationProfile create failed, aborting AniConfig FSM!",
+ log.Fields{"device-id": oFsm.deviceID, "MulticastOperationProfileID": instID})
+ return fmt.Errorf("createMulticastOperationProfile responseError %s", oFsm.deviceID)
+ }
+ return nil
+}
+
+func (oFsm *UniVlanConfigFsm) performSettingMulticastOperationProfile(multicastGemPortID uint16, vlanID uint32) error {
+ instID := macBridgePortAniEID + uint16(oFsm.pOnuUniPort.macBpNo)
+ //TODO check that this is correct
+ // Table control
+ //setCtrl = 1
+ //rowPartId = 0
+ //test = 0
+ //rowKey = 0
+ tableCtrlStr := "0100000000000000"
+ tableCtrl := AsByteSlice(tableCtrlStr)
+ //TODO Building it as a Table, even though the attribute is `StringAttributeType`
+ // see line 56 of multicastoperationsprofileframe.go, it's an error in the conversion.
+ // FIXED 30/12/2020 Fixed for now with a local copy of multicastoperationsprofileframe.go in vendor/omci-lib-go
+ // provided by Chip, needs upstreaming and version change.
+ dynamicAccessCL := make([]uint8, 24)
+ copy(dynamicAccessCL, tableCtrl)
+ //Multicast GemPortId
+ binary.BigEndian.PutUint16(dynamicAccessCL[2:], multicastGemPortID)
+ // python version waits for installation of flows, see line 723 onward of
+ // brcm_openomci_onu_handler.py
+ binary.BigEndian.PutUint16(dynamicAccessCL[4:], uint16(vlanID))
+ //Source IP all to 0
+ binary.BigEndian.PutUint32(dynamicAccessCL[6:], IPToInt32(net.IPv4(0, 0, 0, 0)))
+ //TODO start and end are hardcoded, get from TP
+ // Destination IP address start of range
+ binary.BigEndian.PutUint32(dynamicAccessCL[10:], IPToInt32(net.IPv4(225, 0, 0, 0)))
+ // Destination IP address end of range
+ binary.BigEndian.PutUint32(dynamicAccessCL[14:], IPToInt32(net.IPv4(239, 255, 255, 255)))
+ //imputed group bandwidth
+ binary.BigEndian.PutUint16(dynamicAccessCL[18:], 0)
+
+ meParams := me.ParamData{
+ EntityID: instID,
+ Attributes: me.AttributeValueMap{
+ "DynamicAccessControlListTable": dynamicAccessCL,
+ },
+ }
+ meInstance := oFsm.pOmciCC.sendSetMulticastOperationProfileVar(context.TODO(), ConstDefaultOmciTimeout, true,
+ oFsm.pAdaptFsm.commChan, meParams)
+ //accept also nil as (error) return value for writing to LastTx
+ // - this avoids misinterpretation of new received OMCI messages
+ oFsm.pLastTxMeInstance = meInstance
+ //verify response
+ err := oFsm.waitforOmciResponse()
+ if err != nil {
+ logger.Errorw("CreateMulticastOperationProfile create failed, aborting AniConfig FSM!",
+ log.Fields{"device-id": oFsm.deviceID, "MulticastOperationProfileID": instID})
+ return fmt.Errorf("createMulticastOperationProfile responseError %s", oFsm.deviceID)
+ }
+ return nil
+}
diff --git a/internal/pkg/onuadaptercore/onu_uni_tp.go b/internal/pkg/onuadaptercore/onu_uni_tp.go
index 1ab6c0b..2be93b9 100644
--- a/internal/pkg/onuadaptercore/onu_uni_tp.go
+++ b/internal/pkg/onuadaptercore/onu_uni_tp.go
@@ -425,22 +425,25 @@
uint8(content.Weight)
}
- for pos, downstreamContent := range tpInst.DownstreamGemPortAttributeList {
- if uint32(pos) == loNumGemPorts {
- logger.Debugw("PonAniConfig abort GemPortList - GemList exceeds set NumberOfGemPorts",
- log.Fields{"device-id": onuTP.deviceID, "index": pos, "NumGem": loNumGemPorts})
- break
- }
-
+ for _, downstreamContent := range tpInst.DownstreamGemPortAttributeList {
+ log.Debugw("Operating on Downstream Gem Port", log.Fields{"downstream-gem": downstreamContent})
+ //Commenting this out due to faliure, needs investigation
+ //if uint32(pos) == loNumGemPorts {
+ // logger.Debugw("PonAniConfig abort GemPortList - GemList exceeds set NumberOfGemPorts",
+ // log.Fields{"device-id": onuTP.deviceID, "index": pos, "NumGem": loNumGemPorts})
+ // break
+ //}
+ isMulticast := false
//Flag is defined as string in the TP in voltha-lib-go, parsing it from string
- isMulticast, err := strconv.ParseBool(downstreamContent.IsMulticast)
-
- if err != nil {
- logger.Errorw("multicast-error-config-unknown-flag-in-technology-profile", log.Fields{"UniTpKey": uniTPKey,
- "downstream-gem": downstreamContent, "error": err})
- continue
+ if downstreamContent.IsMulticast != "" {
+ isMulticast, err = strconv.ParseBool(downstreamContent.IsMulticast)
+ if err != nil {
+ logger.Errorw("multicast-error-config-unknown-flag-in-technology-profile",
+ log.Fields{"UniTpKey": uniTPKey, "downstream-gem": downstreamContent, "error": err})
+ continue
+ }
}
-
+ log.Infow("Gem Port is multicast", log.Fields{"isMulticast": isMulticast})
if isMulticast {
mcastGemID := uint16(downstreamContent.McastGemID)
_, existing := onuTP.mapPonAniConfig[uniTPKey].mapGemPortParams[mcastGemID]
@@ -451,7 +454,7 @@
continue
} else {
//GEM port is not configured, setting multicast attributes
- logger.Infow("creating-multicast-gem-port", log.Fields{"uniPtKEy": uniTPKey,
+ logger.Infow("creating-multicast-gem-port", log.Fields{"uniTpKey": uniTPKey,
"gemPortId": mcastGemID, "key": mcastGemID})
//for all further GemPorts we need to extend the mapGemPortParams
@@ -460,13 +463,35 @@
//Separate McastGemId is derived from OMCI-lib-go, if not needed first needs to be removed there.
onuTP.mapPonAniConfig[uniTPKey].mapGemPortParams[mcastGemID].gemPortID = mcastGemID
onuTP.mapPonAniConfig[uniTPKey].mapGemPortParams[mcastGemID].direction = 2 // for ANI to UNI as defined in G.988
- //Downstream Priority Queue is set in the data of any message exchanged, using in mcast too.
+
+ if downstreamContent.AesEncryption == "True" {
+ onuTP.mapPonAniConfig[uniTPKey].mapGemPortParams[mcastGemID].gemPortEncState = 1
+ } else {
+ onuTP.mapPonAniConfig[uniTPKey].mapGemPortParams[mcastGemID].gemPortEncState = 0
+ }
+
+ // expected Prio-Queue values 0..7 with 7 for highest PrioQueue, QueueIndex=Prio = 0..7
if downstreamContent.PriorityQueue > 7 {
logger.Errorw("PonAniConfig reject on GemPortList - PrioQueue value invalid",
- log.Fields{"device-id": onuTP.deviceID, "index": pos, "PrioQueue": downstreamContent.PriorityQueue})
+ log.Fields{"device-id": onuTP.deviceID, "index": mcastGemID, "PrioQueue": downstreamContent.PriorityQueue})
+ //remove PonAniConfig as done so far, delete map should be safe, even if not existing
+ delete(onuTP.mapPonAniConfig, uniTPKey)
+ onuTP.chTpConfigProcessingStep <- 0 //error indication
+ return
}
onuTP.mapPonAniConfig[uniTPKey].mapGemPortParams[mcastGemID].prioQueueIndex =
uint8(downstreamContent.PriorityQueue)
+ onuTP.mapPonAniConfig[uniTPKey].mapGemPortParams[mcastGemID].pbitString =
+ strings.TrimPrefix(downstreamContent.PbitMap, binaryStringPrefix)
+
+ onuTP.mapPonAniConfig[uniTPKey].mapGemPortParams[mcastGemID].discardPolicy =
+ downstreamContent.DiscardPolicy
+ onuTP.mapPonAniConfig[uniTPKey].mapGemPortParams[mcastGemID].queueSchedPolicy =
+ downstreamContent.SchedulingPolicy
+ //'GemWeight' looks strange in default profile, for now we just copy the weight to first queue
+ onuTP.mapPonAniConfig[uniTPKey].mapGemPortParams[mcastGemID].queueWeight =
+ uint8(downstreamContent.Weight)
+
onuTP.mapPonAniConfig[uniTPKey].mapGemPortParams[mcastGemID].isMulticast = isMulticast
onuTP.mapPonAniConfig[uniTPKey].mapGemPortParams[mcastGemID].multicastGemPortID =
uint16(downstreamContent.McastGemID)
@@ -836,3 +861,22 @@
onuTP.mapUniTpIndication[uniTpKey].techProfileToDelete = aState
} //else: the state is just ignored (does not exist)
}
+
+// setProfileToDelete sets the requested techProfile toDelete state (if possible)
+func (onuTP *onuUniTechProf) getMulticastGemPorts(aUniID uint8, aTpID uint8) []uint16 {
+ uniTpKey := uniTP{uniID: aUniID, tpID: aTpID}
+ onuTP.mutexTPState.Lock()
+ defer onuTP.mutexTPState.Unlock()
+ gemPortIds := make([]uint16, 0)
+ if techProfile, existTP := onuTP.mapPonAniConfig[uniTpKey]; existTP {
+ for _, gemPortParam := range techProfile.mapGemPortParams {
+ if gemPortParam.isMulticast {
+ log.Debugw("Detected multicast gemPort", log.Fields{"device-id": onuTP.deviceID,
+ "aUniID": aUniID, "aTPID": aTpID, "uniTPKey": uniTpKey,
+ "mcastGemId": gemPortParam.multicastGemPortID})
+ gemPortIds = append(gemPortIds, gemPortParam.multicastGemPortID)
+ }
+ }
+ } //else: the state is just ignored (does not exist)
+ return gemPortIds
+}
diff --git a/internal/pkg/onuadaptercore/openonu_utils.go b/internal/pkg/onuadaptercore/openonu_utils.go
index 0db62ed..32eeed8 100644
--- a/internal/pkg/onuadaptercore/openonu_utils.go
+++ b/internal/pkg/onuadaptercore/openonu_utils.go
@@ -51,3 +51,23 @@
}
return binary.BigEndian.Uint32(ip)
}
+
+//AsByteSlice transforms a string of manually set bits to a byt array
+func AsByteSlice(bitString string) []byte {
+ var out []byte
+ var str string
+
+ for i := len(bitString); i > 0; i -= 8 {
+ if i-8 < 0 {
+ str = bitString[0:i]
+ } else {
+ str = bitString[i-8 : i]
+ }
+ v, err := strconv.ParseUint(str, 2, 8)
+ if err != nil {
+ panic(err)
+ }
+ out = append([]byte{byte(v)}, out...)
+ }
+ return out
+}
diff --git a/vendor/github.com/opencord/omci-lib-go/VERSION b/vendor/github.com/opencord/omci-lib-go/VERSION
index 288adf5..dffa40e 100644
--- a/vendor/github.com/opencord/omci-lib-go/VERSION
+++ b/vendor/github.com/opencord/omci-lib-go/VERSION
@@ -1 +1 @@
-0.13.3
+0.13.4
diff --git a/vendor/github.com/opencord/omci-lib-go/generated/multicastoperationsprofileframe.go b/vendor/github.com/opencord/omci-lib-go/generated/multicastoperationsprofileframe.go
index 61f36fb..6204894 100644
--- a/vendor/github.com/opencord/omci-lib-go/generated/multicastoperationsprofileframe.go
+++ b/vendor/github.com/opencord/omci-lib-go/generated/multicastoperationsprofileframe.go
@@ -1,5 +1,4 @@
/*
- * 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");
@@ -15,11 +14,9 @@
* 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
-*/
+* NOTE: This file was hand coded (not generated by omci-parser) due to complexity
+* of the ME's entry in the G.988 (11/2017) specification.
+ */
package generated
import "github.com/deckarep/golang-set"
@@ -28,14 +25,14 @@
var multicastoperationsprofileME *ManagedEntityDefinition
-type MulticastOperationsProfile struct{
+type MulticastOperationsProfile struct {
ManagedEntityDefinition
Attributes AttributeValueMap
}
-func init(){
+func init() {
multicastoperationsprofileME = &ManagedEntityDefinition{
- Name: "MulticastOperationsProfile",
+ Name: "MulticastOperationsProfile",
ClassID: 309,
MessageTypes: mapset.NewSetWith(
Create,
@@ -43,28 +40,28 @@
Get,
Set,
GetNext,
- ),
+ ),
AllowedAttributeMask: 0xffff,
AttributeDefinitions: AttributeDefinitionMap{
- 0: Uint16Field("ManagedEntityId", PointerAttributeType, 0x0000, 0, mapset.NewSetWith(Read, SetByCreate), false,false,false,0),
- 1: ByteField("IgmpVersion", EnumerationAttributeType, 0x8000, 0, mapset.NewSetWith(Read, SetByCreate, Write), false, false, false, 1),
- 2: ByteField("IgmpFunction", EnumerationAttributeType, 0x4000, 0, mapset.NewSetWith(Read, SetByCreate, Write), false, false, false, 2),
- 3: ByteField("ImmediateLeave", EnumerationAttributeType, 0x2000, 0, mapset.NewSetWith(Read, SetByCreate, Write), false, false, false, 3),
- 4: Uint16Field("USIgmpTci", PointerAttributeType, 0x1000, 0, mapset.NewSetWith(Read, SetByCreate, Write), false, true, false, 4),
- 5: ByteField("USIgmpTagCtrl", EnumerationAttributeType, 0x0800, 0, mapset.NewSetWith(Read, SetByCreate, Write), false, true, false, 5),
- 6: Uint32Field("USIgmpRate", CounterAttributeType, 0x0400, 0, mapset.NewSetWith(Read), false, true, false, 6),
- 7: MultiByteField("DynamicAccessControlListTable", StringAttributeType, 0x0200, 24, toOctets("AAAAAAAAAAAAAAAAAAAAAAAAAAA="), mapset.NewSetWith(Read), false, false, false, 7),
- 8: MultiByteField("StaticAccessControlListTable", StringAttributeType, 0x0100, 24, toOctets("AAAAAAAAAAAAAAAAAAAAAAAAAAA="), mapset.NewSetWith(Read), false, true, false, 8),
- 9: MultiByteField("LostGroupsListTable", StringAttributeType, 0x0080, 10, toOctets("AAAAAAAAAAAAAAAAAAAAAAAAAAA="), mapset.NewSetWith(Read), false, true, false, 9),
- 10: ByteField("Robustness", EnumerationAttributeType, 0x0040, 0, mapset.NewSetWith(Read, SetByCreate, Write), false, false, false, 10),
- 11: Uint32Field("QuerierIp", CounterAttributeType, 0x0020, 0, mapset.NewSetWith(Read), false, false, false, 11),
- 12: Uint32Field("QueryInterval", CounterAttributeType, 0x0010, 0, mapset.NewSetWith(Read), false, false, false, 12),
- 13: Uint32Field("QuerierMaxResponseTime", CounterAttributeType, 0x0008, 0, mapset.NewSetWith(Read), false, false, false, 13),
- 14: Uint32Field("LastMemberResponseTime", CounterAttributeType, 0x0004, 0, mapset.NewSetWith(Read), false, false, false, 14),
- 15: ByteField("UnauthorizedJoinBehaviour", EnumerationAttributeType, 0x0002, 0, mapset.NewSetWith(Read, SetByCreate, Write), false, false, false, 15),
- 16: MultiByteField("DSIgmpMcastTci", StringAttributeType, 0x0001, 10, toOctets("AAAAAAAAAAAAAAAAAAAAAAAAAAA="), mapset.NewSetWith(Read), false, true, false, 16),
+ 0: Uint16Field("ManagedEntityId", PointerAttributeType, 0x0000, 0, mapset.NewSetWith(Read, SetByCreate), false, false, false, 0),
+ 1: ByteField("IgmpVersion", EnumerationAttributeType, 0x8000, 0, mapset.NewSetWith(Read, SetByCreate, Write), false, false, false, 1),
+ 2: ByteField("IgmpFunction", EnumerationAttributeType, 0x4000, 0, mapset.NewSetWith(Read, SetByCreate, Write), false, false, false, 2),
+ 3: ByteField("ImmediateLeave", EnumerationAttributeType, 0x2000, 0, mapset.NewSetWith(Read, SetByCreate, Write), false, false, false, 3),
+ 4: Uint16Field("USIgmpTci", UnsignedIntegerAttributeType, 0x1000, 0, mapset.NewSetWith(Read, SetByCreate, Write), false, true, false, 4),
+ 5: ByteField("USIgmpTagCtrl", EnumerationAttributeType, 0x0800, 0, mapset.NewSetWith(Read, SetByCreate, Write), false, true, false, 5),
+ 6: Uint32Field("USIgmpRate", UnsignedIntegerAttributeType, 0x0400, 0, mapset.NewSetWith(Read, SetByCreate, Write), false, true, false, 6),
+ 7: TableField("DynamicAccessControlListTable", TableAttributeType, 0x0200, TableInfo{nil, 24}, mapset.NewSetWith(Read, Write), false, false, false, 7),
+ 8: TableField("StaticAccessControlListTable", TableAttributeType, 0x0100, TableInfo{nil, 24}, mapset.NewSetWith(Read, Write), false, true, false, 8),
+ 9: TableField("LostGroupsListTable", TableAttributeType, 0x0080, TableInfo{nil, 10}, mapset.NewSetWith(Read), false, true, false, 9),
+ 10: ByteField("Robustness", UnsignedIntegerAttributeType, 0x0040, 0, mapset.NewSetWith(Read, SetByCreate, Write), false, true, false, 10),
+ 11: Uint32Field("QuerierIp", UnsignedIntegerAttributeType, 0x0020, 0, mapset.NewSetWith(Read, SetByCreate, Write), false, true, false, 11),
+ 12: Uint32Field("QueryInterval", UnsignedIntegerAttributeType, 0x0010, 0, mapset.NewSetWith(Read, SetByCreate, Write), false, true, false, 12),
+ 13: Uint32Field("QuerierMaxResponseTime", UnsignedIntegerAttributeType, 0x0008, 0, mapset.NewSetWith(Read, SetByCreate, Write), false, true, false, 13),
+ 14: Uint32Field("LastMemberResponseTime", UnsignedIntegerAttributeType, 0x0004, 0, mapset.NewSetWith(Read, Write), false, true, false, 14),
+ 15: ByteField("UnauthorizedJoinBehaviour", UnsignedIntegerAttributeType, 0x0002, 0, mapset.NewSetWith(Read, Write), false, true, false, 15),
+ 16: MultiByteField("DSIgmpMcastTci", OctetsAttributeType, 0x0001, 3, toOctets("AAAA"), mapset.NewSetWith(Read, SetByCreate, Write), false, true, false, 16),
},
- Access: CreatedByOlt,
+ Access: CreatedByOlt,
Support: UnknownSupport,
}
}
@@ -72,6 +69,6 @@
// NewMulticastOperationsProfilePoint (class ID 309) creates the basic
// Managed Entity definition that is used to validate an ME of this type that
// is received from or transmitted to the OMCC.
-func NewMulticastOperationsProfile(params ...ParamData) (*ManagedEntity, OmciErrors){
+func NewMulticastOperationsProfile(params ...ParamData) (*ManagedEntity, OmciErrors) {
return NewManagedEntity(*multicastoperationsprofileME, params...)
-}
\ No newline at end of file
+}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 8d18d5c..ba226fa 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -71,7 +71,7 @@
github.com/mitchellh/go-homedir
# github.com/mitchellh/mapstructure v1.1.2
github.com/mitchellh/mapstructure
-# github.com/opencord/omci-lib-go v0.13.3
+# github.com/opencord/omci-lib-go v0.13.4
github.com/opencord/omci-lib-go
github.com/opencord/omci-lib-go/generated
# github.com/opencord/voltha-lib-go/v3 v3.1.23