[VOL-3331] Implement incremental ONU traffic flow setup request with according OMCI VLAN configuration,
now already merged with git merged patch for [VOL-3051] Create MIB template from first ONU + correction TechProfile channel processing
Signed-off-by: mpagenko <michael.pagenkopf@adtran.com>
Change-Id: Iabbf4e1bc16da9c115e8e4002fd328a4c6bf33fb
diff --git a/internal/pkg/config/config.go b/internal/pkg/config/config.go
index 2112b85..d47245a 100644
--- a/internal/pkg/config/config.go
+++ b/internal/pkg/config/config.go
@@ -39,6 +39,7 @@
defaultLoglevel = "WARN"
defaultBanner = false
defaultDisplayVersionOnly = false
+ defaultAccIncrEvto = false
defaultTopic = "openonu"
defaultCoretopic = "rwcore"
defaultEventtopic = "voltha.events"
@@ -76,6 +77,7 @@
OnuNumber int
Banner bool
DisplayVersionOnly bool
+ AccIncrEvto bool
ProbeHost string
ProbePort int
LiveProbeInterval time.Duration
@@ -106,6 +108,7 @@
OnuNumber: defaultOnunumber,
Banner: defaultBanner,
DisplayVersionOnly: defaultDisplayVersionOnly,
+ AccIncrEvto: defaultAccIncrEvto,
ProbeHost: defaultProbeHost,
ProbePort: defaultProbePort,
LiveProbeInterval: defaultLiveProbeInterval,
@@ -167,6 +170,9 @@
help = fmt.Sprintf("Show version information and exit")
flag.BoolVar(&(so.DisplayVersionOnly), "version", defaultDisplayVersionOnly, help)
+ help = fmt.Sprintf("Acceptance of incremental EVTOCD configuration")
+ flag.BoolVar(&(so.AccIncrEvto), "accept_incr_evto", defaultAccIncrEvto, help)
+
help = fmt.Sprintf("The address on which to listen to answer liveness and readiness probe queries over HTTP.")
flag.StringVar(&(so.ProbeHost), "probe_host", defaultProbeHost, help)
diff --git a/internal/pkg/onuadaptercore/device_handler.go b/internal/pkg/onuadaptercore/device_handler.go
index 93dbb6c..395b369 100644
--- a/internal/pkg/onuadaptercore/device_handler.go
+++ b/internal/pkg/onuadaptercore/device_handler.go
@@ -32,9 +32,13 @@
me "github.com/opencord/omci-lib-go/generated"
"github.com/opencord/voltha-lib-go/v3/pkg/adapters/adapterif"
"github.com/opencord/voltha-lib-go/v3/pkg/db"
+ flow "github.com/opencord/voltha-lib-go/v3/pkg/flows"
"github.com/opencord/voltha-lib-go/v3/pkg/log"
vc "github.com/opencord/voltha-protos/v3/go/common"
ic "github.com/opencord/voltha-protos/v3/go/inter_container"
+ "github.com/opencord/voltha-protos/v3/go/openflow_13"
+ of "github.com/opencord/voltha-protos/v3/go/openflow_13"
+ ofp "github.com/opencord/voltha-protos/v3/go/openflow_13"
oop "github.com/opencord/voltha-protos/v3/go/openolt"
"github.com/opencord/voltha-protos/v3/go/voltha"
)
@@ -123,11 +127,12 @@
//onus sync.Map
//portStats *OpenOltStatisticsMgr
//metrics *pmmetrics.PmMetrics
- stopCollector chan bool
- stopHeartbeatCheck chan bool
- activePorts sync.Map
- uniEntityMap map[uint32]*OnuUniPort
- reconciling bool
+ stopCollector chan bool
+ stopHeartbeatCheck chan bool
+ activePorts sync.Map
+ uniEntityMap map[uint32]*OnuUniPort
+ UniVlanConfigFsmMap map[uint8]*UniVlanConfigFsm
+ reconciling bool
}
//NewDeviceHandler creates a new device handler
@@ -151,6 +156,7 @@
dh.activePorts = sync.Map{}
//TODO initialize the support classes.
dh.uniEntityMap = make(map[uint32]*OnuUniPort)
+ dh.UniVlanConfigFsmMap = make(map[uint8]*UniVlanConfigFsm)
dh.reconciling = false
// Device related state machine
@@ -315,7 +321,7 @@
var wg sync.WaitGroup
wg.Add(2) // for the 2 go routines to finish
// attention: deadline completion check and wg.Done is to be done in both routines
- go dh.pOnuTP.configureUniTp(dctx, techProfMsg.UniId, techProfMsg.Path, &wg)
+ go dh.pOnuTP.configureUniTp(dctx, uint8(techProfMsg.UniId), techProfMsg.Path, &wg)
go dh.pOnuTP.updateOnuTpPathKvStore(dctx, &wg)
//the wait.. function is responsible for tpProcMutex.Unlock()
err := dh.pOnuTP.waitForTpCompletion(cancel, &wg) //wait for background process to finish and collect their result
@@ -408,6 +414,58 @@
return nil
}
+//FlowUpdateIncremental removes and/or adds the flow changes on a given device
+func (dh *DeviceHandler) FlowUpdateIncremental(apOfFlowChanges *openflow_13.FlowChanges,
+ apOfGroupChanges *openflow_13.FlowGroupChanges, apFlowMetaData *voltha.FlowMetadata) error {
+
+ //Remove flows
+ if apOfFlowChanges.ToRemove != nil {
+ for _, flowItem := range apOfFlowChanges.ToRemove.Items {
+ logger.Debugw("incremental flow item remove", log.Fields{"deviceId": dh.deviceID,
+ "Item": flowItem})
+ }
+ }
+ if apOfFlowChanges.ToAdd != nil {
+ for _, flowItem := range apOfFlowChanges.ToAdd.Items {
+ if flowItem.GetCookie() == 0 {
+ logger.Debugw("incremental flow add - no cookie - ignore", log.Fields{
+ "deviceId": dh.deviceID})
+ continue
+ }
+ flowInPort := flow.GetInPort(flowItem)
+ if flowInPort == uint32(of.OfpPortNo_OFPP_INVALID) {
+ logger.Errorw("flow inPort invalid", log.Fields{"deviceID": dh.deviceID})
+ return errors.New("flow inPort invalid")
+ } else if flowInPort == dh.ponPortNumber {
+ //this is some downstream flow
+ logger.Debugw("incremental flow ignore downstream", log.Fields{
+ "deviceId": dh.deviceID, "inPort": flowInPort})
+ continue
+ } else {
+ // this is the relevant upstream flow
+ var loUniPort *OnuUniPort
+ if uniPort, exist := dh.uniEntityMap[flowInPort]; exist {
+ loUniPort = uniPort
+ } else {
+ logger.Errorw("flow inPort not found in UniPorts",
+ log.Fields{"deviceID": dh.deviceID, "inPort": flowInPort})
+ return fmt.Errorf("flow-parameter inPort %d not found in internal UniPorts", flowInPort)
+ }
+ flowOutPort := flow.GetOutPort(flowItem)
+ logger.Debugw("incremental flow-add port indications", log.Fields{
+ "deviceId": dh.deviceID, "inPort": flowInPort, "outPort": flowOutPort,
+ "uniPortName": loUniPort.name})
+ err := dh.addFlowItemToUniPort(flowItem, loUniPort)
+ //abort processing in error case
+ if err != nil {
+ return err
+ }
+ }
+ }
+ }
+ return nil
+}
+
//DisableDevice locks the ONU and its UNI/VEIP ports (admin lock via OMCI)
// TODO!!! Clarify usage of this method, it is for sure not used within ONOS (OLT) device disable
// maybe it is obsolete by now
@@ -509,7 +567,7 @@
var wg sync.WaitGroup
wg.Add(1) // for the 1 go routines to finish
// attention: deadline completion check and wg.Done is to be done in both routines
- go dh.pOnuTP.configureUniTp(dctx, uniData.PersUniId, uniData.PersTpPath, &wg)
+ go dh.pOnuTP.configureUniTp(dctx, uint8(uniData.PersUniId), uniData.PersTpPath, &wg)
//the wait.. function is responsible for tpProcMutex.Unlock()
dh.pOnuTP.waitForTpCompletion(cancel, &wg) //wait for background process to finish and collect their result
return
@@ -1080,6 +1138,18 @@
if dh.pOnuTP.pAniConfigFsm != nil {
dh.pOnuTP.pAniConfigFsm.pAdaptFsm.pFsm.Event(aniEvReset)
}
+ for _, uniPort := range dh.uniEntityMap {
+ //reset the TechProfileConfig Done state for all (active) UNI's
+ dh.pOnuTP.setConfigDone(uniPort.uniId, false)
+ // reset tjhe possibly existing VlanConfigFsm
+ if pVlanFilterFsm, exist := dh.UniVlanConfigFsmMap[uniPort.uniId]; exist {
+ //VlanFilterFsm exists and was already started
+ pVlanFilterStatemachine := pVlanFilterFsm.pAdaptFsm.pFsm
+ if pVlanFilterStatemachine != nil {
+ pVlanFilterStatemachine.Event(vlanEvReset)
+ }
+ }
+ }
}
//TODO!!! care about PM/Alarm processing once started
}
@@ -1275,8 +1345,6 @@
case OmciAniConfigDone:
{
logger.Debugw("OmciAniConfigDone event received", log.Fields{"device-id": dh.deviceID})
- //TODO!: it might be needed to check some 'cached' pending flow configuration (vlan setting)
- // - to consider with outstanding flow implementation
// attention: the device reason update is done based on ONU-UNI-Port related activity
// - which may cause some inconsistency
if dh.deviceReason != "tech-profile-config-download-success" {
@@ -1298,6 +1366,28 @@
dh.deviceReason = "tech-profile-config-download-success"
}
}
+ case OmciVlanFilterDone:
+ {
+ logger.Debugw("OmciVlanFilterDone event received",
+ log.Fields{"device-id": dh.deviceID})
+ // attention: the device reason update is done based on ONU-UNI-Port related activity
+ // - which may cause some inconsistency
+ // yield self.core_proxy.device_reason_update(self.device_id, 'omci-flows-pushed')
+
+ if dh.deviceReason != "omci-flows-pushed" {
+ // which may be the case from some previous actvity on another UNI Port of the ONU
+ // or even some previous flow add activity on the same port
+ if err := dh.coreProxy.DeviceReasonUpdate(context.TODO(), dh.deviceID, "omci-flows-pushed"); err != nil {
+ logger.Errorw("error-DeviceReasonUpdate to 'omci-flows-pushed'",
+ log.Fields{"device-id": dh.deviceID, "error": err})
+ } else {
+ logger.Infow("updated dev reason to ''omci-flows-pushed'",
+ log.Fields{"device-id": dh.deviceID})
+ }
+ //set internal state anyway - as it was done
+ dh.deviceReason = "omci-flows-pushed"
+ }
+ }
default:
{
logger.Warnw("unhandled-device-event", log.Fields{"device-id": dh.deviceID, "event": dev_Event})
@@ -1415,7 +1505,7 @@
log.Fields{"device-id": a_deviceID, "with-EventName": de.DeviceEventName})
}
-// createUniLockFsm initialises and runs the UniLock FSM to transfer teh OMCi related commands for port lock/unlock
+// createUniLockFsm initialises and runs the UniLock FSM to transfer the OMCI related commands for port lock/unlock
func (dh *DeviceHandler) createUniLockFsm(aAdminState bool, devEvent OnuDeviceEvent) {
chLSFsm := make(chan Message, 2048)
var sFsmName string
@@ -1503,3 +1593,257 @@
return kvbackend
}
+
+//addFlowItemToUniPort parses the actual flow item to add it to the UniPort
+func (dh *DeviceHandler) addFlowItemToUniPort(apFlowItem *ofp.OfpFlowStats, apUniPort *OnuUniPort) error {
+ var loSetVlan uint16 = uint16(of.OfpVlanId_OFPVID_NONE) //noValidEntry
+ var loMatchVlan uint16 = uint16(of.OfpVlanId_OFPVID_PRESENT) //reserved VLANID entry
+ var loAddPcp, loSetPcp uint8
+ /* the TechProfileId is part of the flow Metadata - compare also comment within
+ * OLT-Adapter:openolt_flowmgr.go
+ * Metadata 8 bytes:
+ * Most Significant 2 Bytes = Inner VLAN
+ * Next 2 Bytes = Tech Profile ID(TPID)
+ * Least Significant 4 Bytes = Port ID
+ * Flow Metadata carries Tech-Profile (TP) ID and is mandatory in all
+ * subscriber related flows.
+ */
+
+ metadata := flow.GetMetadataFromWriteMetadataAction(apFlowItem)
+ if metadata == 0 {
+ logger.Debugw("FlowAdd invalid metadata - abort",
+ log.Fields{"device-id": dh.deviceID})
+ return errors.New("FlowAdd invalid metadata")
+ }
+ loTpID := flow.GetTechProfileIDFromWriteMetaData(metadata)
+ logger.Debugw("FlowAdd TechProfileId", log.Fields{"device-id": dh.deviceID, "TP-Id": loTpID})
+ for _, field := range flow.GetOfbFields(apFlowItem) {
+ switch field.Type {
+ case of.OxmOfbFieldTypes_OFPXMT_OFB_ETH_TYPE:
+ {
+ logger.Debugw("FlowAdd type EthType", log.Fields{"device-id": dh.deviceID,
+ "EthType": strconv.FormatInt(int64(field.GetEthType()), 16)})
+ }
+ case of.OxmOfbFieldTypes_OFPXMT_OFB_IP_PROTO:
+ {
+ loIPProto := field.GetIpProto()
+ logger.Debugw("FlowAdd type IpProto", log.Fields{"device-id": dh.deviceID,
+ "IpProto": strconv.FormatInt(int64(loIPProto), 16)})
+ if loIPProto == 2 {
+ // some workaround for TT workflow at proto == 2 (IGMP trap) -> ignore the flow
+ // avoids installing invalid EVTOCD rule
+ logger.Debugw("FlowAdd type IpProto 2: TT workaround: ignore flow",
+ log.Fields{"device-id": dh.deviceID,
+ "IpProto": strconv.FormatInt(int64(loIPProto), 16)})
+ return nil
+ }
+ }
+ case of.OxmOfbFieldTypes_OFPXMT_OFB_VLAN_VID:
+ {
+ loMatchVlan = uint16(field.GetVlanVid())
+ loMatchVlanMask := uint16(field.GetVlanVidMask())
+ if !(loMatchVlan == uint16(of.OfpVlanId_OFPVID_PRESENT) &&
+ loMatchVlanMask == uint16(of.OfpVlanId_OFPVID_PRESENT)) {
+ loMatchVlan = loMatchVlan & 0xFFF // not transparent: copy only ID bits
+ }
+ logger.Debugw("FlowAdd field type", log.Fields{"device-id": dh.deviceID,
+ "VID": strconv.FormatInt(int64(loMatchVlan), 16)})
+ }
+ case of.OxmOfbFieldTypes_OFPXMT_OFB_VLAN_PCP:
+ {
+ loAddPcp = uint8(field.GetVlanPcp())
+ logger.Debugw("FlowAdd field type", log.Fields{"device-id": dh.deviceID,
+ "PCP": loAddPcp})
+ }
+ case of.OxmOfbFieldTypes_OFPXMT_OFB_UDP_DST:
+ {
+ logger.Debugw("FlowAdd field type", log.Fields{"device-id": dh.deviceID,
+ "UDP-DST": strconv.FormatInt(int64(field.GetUdpDst()), 16)})
+ }
+ case of.OxmOfbFieldTypes_OFPXMT_OFB_UDP_SRC:
+ {
+ logger.Debugw("FlowAdd field type", log.Fields{"device-id": dh.deviceID,
+ "UDP-SRC": strconv.FormatInt(int64(field.GetUdpSrc()), 16)})
+ }
+ case of.OxmOfbFieldTypes_OFPXMT_OFB_IPV4_DST:
+ {
+ logger.Debugw("FlowAdd field type", log.Fields{"device-id": dh.deviceID,
+ "IPv4-DST": field.GetIpv4Dst()})
+ }
+ case of.OxmOfbFieldTypes_OFPXMT_OFB_IPV4_SRC:
+ {
+ logger.Debugw("FlowAdd field type", log.Fields{"device-id": dh.deviceID,
+ "IPv4-SRC": field.GetIpv4Src()})
+ }
+ case of.OxmOfbFieldTypes_OFPXMT_OFB_METADATA:
+ {
+ logger.Debugw("FlowAdd field type", log.Fields{"device-id": dh.deviceID,
+ "Metadata": field.GetTableMetadata()})
+ }
+ /*
+ default:
+ {
+ //all other entires ignored
+ }
+ */
+ }
+ } //for all OfbFields
+
+ for _, action := range flow.GetActions(apFlowItem) {
+ switch action.Type {
+ /* not used:
+ case of.OfpActionType_OFPAT_OUTPUT:
+ {
+ logger.Debugw("FlowAdd action type", log.Fields{"device-id": dh.deviceID,
+ "Output": action.GetOutput()})
+ }
+ */
+ case of.OfpActionType_OFPAT_PUSH_VLAN:
+ {
+ logger.Debugw("FlowAdd action type", log.Fields{"device-id": dh.deviceID,
+ "PushEthType": strconv.FormatInt(int64(action.GetPush().Ethertype), 16)})
+ }
+ case of.OfpActionType_OFPAT_SET_FIELD:
+ {
+ pActionSetField := action.GetSetField()
+ if pActionSetField.Field.OxmClass != of.OfpOxmClass_OFPXMC_OPENFLOW_BASIC {
+ logger.Warnw("FlowAdd action SetField invalid OxmClass (ignored)", log.Fields{"device-id": dh.deviceID,
+ "OxcmClass": pActionSetField.Field.OxmClass})
+ }
+ if pActionSetField.Field.GetOfbField().Type == of.OxmOfbFieldTypes_OFPXMT_OFB_VLAN_VID {
+ loSetVlan = uint16(pActionSetField.Field.GetOfbField().GetVlanVid())
+ logger.Debugw("FlowAdd Set VLAN from SetField action", log.Fields{"device-id": dh.deviceID,
+ "SetVlan": strconv.FormatInt(int64(loSetVlan), 16)})
+ } else if pActionSetField.Field.GetOfbField().Type == of.OxmOfbFieldTypes_OFPXMT_OFB_VLAN_PCP {
+ loSetPcp = uint8(pActionSetField.Field.GetOfbField().GetVlanPcp())
+ logger.Debugw("FlowAdd Set PCP from SetField action", log.Fields{"device-id": dh.deviceID,
+ "SetPcp": loSetPcp})
+ } else {
+ logger.Warnw("FlowAdd action SetField invalid FieldType", log.Fields{"device-id": dh.deviceID,
+ "Type": pActionSetField.Field.GetOfbField().Type})
+ }
+ }
+ /*
+ default:
+ {
+ //all other entires ignored
+ }
+ */
+ }
+ } //for all Actions
+
+ if loSetVlan == uint16(of.OfpVlanId_OFPVID_NONE) && loMatchVlan != uint16(of.OfpVlanId_OFPVID_PRESENT) {
+ logger.Errorw("FlowAdd aborted - SetVlanId undefined, but MatchVid set", log.Fields{
+ "device-id": dh.deviceID, "UniPort": apUniPort.portNo,
+ "set_vid": strconv.FormatInt(int64(loSetVlan), 16),
+ "match_vid": strconv.FormatInt(int64(loMatchVlan), 16)})
+ //TODO!!: Use DeviceId within the error response to rwCore
+ // likewise also in other error response cases to calling components as requested in [VOL-3458]
+ return errors.New("FlowAdd Set/Match VlanId inconsistent")
+ }
+ if loSetVlan == uint16(of.OfpVlanId_OFPVID_NONE) && loMatchVlan == uint16(of.OfpVlanId_OFPVID_PRESENT) {
+ logger.Debugw("FlowAdd vlan-any/copy", log.Fields{"device-id": dh.deviceID})
+ loSetVlan = loMatchVlan //both 'transparent' (copy any)
+ } else {
+ //looks like OMCI value 4097 (copyFromOuter - for Uni double tagged) is not supported here
+ if loSetVlan != uint16(of.OfpVlanId_OFPVID_PRESENT) {
+ // not set to transparent
+ loSetVlan &= 0x0FFF //mask VID bits as prerequiste for vlanConfigFsm
+ }
+ logger.Debugw("FlowAdd vlan-set", log.Fields{"device-id": dh.deviceID})
+ }
+ //TODO!!: further FlowAdd requests may be valid even in case the FSM is already running,
+ // e.g. for multi-step flow configuration, error treatment must be redefined in this context as requested in [VOL-3441]
+ if _, exist := dh.UniVlanConfigFsmMap[apUniPort.uniId]; exist {
+ logger.Errorw("FlowAdd aborted - FSM already running", log.Fields{
+ "device-id": dh.deviceID, "UniPort": apUniPort.portNo})
+ return errors.New("FlowAdd FSM already running")
+ }
+ return dh.createVlanFilterFsm(apUniPort,
+ loTpID, loMatchVlan, loSetVlan, loSetPcp, OmciVlanFilterDone)
+}
+
+// createVlanFilterFsm initialises and runs the VlanFilter FSM to transfer OMCI related VLAN config
+func (dh *DeviceHandler) createVlanFilterFsm(apUniPort *OnuUniPort,
+ aTpID uint16, aMatchVlan uint16, aSetVlan uint16, aSetPcp uint8, aDevEvent OnuDeviceEvent) error {
+ chVlanFilterFsm := make(chan Message, 2048)
+
+ pDevEntry := dh.GetOnuDeviceEntry(true)
+ if pDevEntry == nil {
+ logger.Errorw("No valid OnuDevice -aborting", log.Fields{"device-id": dh.deviceID})
+ return fmt.Errorf("No valid OnuDevice for device-id %x - aborting", dh.deviceID)
+ }
+
+ pVlanFilterFsm := NewUniVlanConfigFsm(dh, pDevEntry.PDevOmciCC, apUniPort, dh.pOnuTP,
+ pDevEntry.pOnuDB, aTpID, aDevEvent, "UniVlanConfigFsm", dh.deviceID, chVlanFilterFsm,
+ dh.pOpenOnuAc.AcceptIncrementalEvto, aMatchVlan, aSetVlan, aSetPcp)
+ if pVlanFilterFsm != nil {
+ dh.UniVlanConfigFsmMap[apUniPort.uniId] = pVlanFilterFsm
+ pVlanFilterStatemachine := pVlanFilterFsm.pAdaptFsm.pFsm
+ if pVlanFilterStatemachine != nil {
+ if pVlanFilterStatemachine.Is(vlanStDisabled) {
+ if err := pVlanFilterStatemachine.Event(vlanEvStart); err != nil {
+ logger.Warnw("UniVlanConfigFsm: can't start", log.Fields{"err": err})
+ return fmt.Errorf("Can't start UniVlanConfigFsm for device-id %x", dh.deviceID)
+ } else {
+ /***** UniVlanConfigFsm started */
+ logger.Debugw("UniVlanConfigFsm started", log.Fields{
+ "state": pVlanFilterStatemachine.Current(), "device-id": dh.deviceID,
+ "UniPort": apUniPort.portNo})
+ }
+ } else {
+ logger.Warnw("wrong state of UniVlanConfigFsm - want: disabled", log.Fields{
+ "have": pVlanFilterStatemachine.Current(), "device-id": dh.deviceID})
+ return fmt.Errorf("UniVlanConfigFsm not in expected disabled state for device-id %x", dh.deviceID)
+ }
+ } else {
+ logger.Errorw("UniVlanConfigFsm StateMachine invalid - cannot be executed!!", log.Fields{
+ "device-id": dh.deviceID})
+ return fmt.Errorf("UniVlanConfigFsm invalid for device-id %x", dh.deviceID)
+ }
+ } else {
+ logger.Errorw("UniVlanConfigFsm could not be created - abort!!", log.Fields{
+ "device-id": dh.deviceID, "UniPort": apUniPort.portNo})
+ return fmt.Errorf("UniVlanConfigFsm could not be created for device-id %x", dh.deviceID)
+ }
+ return nil
+}
+
+//verifyUniVlanConfigRequest checks on existence of flow configuration and starts it accordingly
+func (dh *DeviceHandler) verifyUniVlanConfigRequest(apUniPort *OnuUniPort) {
+ //TODO!! verify and start pending flow configuration
+ //some pending config request my exist in case the UniVlanConfig FSM was already started - with internal data -
+ //but execution was set to 'on hold' as first the TechProfile config had to be applied
+ if pVlanFilterFsm, exist := dh.UniVlanConfigFsmMap[apUniPort.uniId]; exist {
+ //VlanFilterFsm exists and was already started (assumed to wait for TechProfile execution here)
+ pVlanFilterStatemachine := pVlanFilterFsm.pAdaptFsm.pFsm
+ if pVlanFilterStatemachine != nil {
+ if pVlanFilterStatemachine.Is(vlanStWaitingTechProf) {
+ if err := pVlanFilterStatemachine.Event(vlanEvContinueConfig); err != nil {
+ logger.Warnw("UniVlanConfigFsm: can't continue processing", log.Fields{"err": err})
+ } else {
+ /***** UniVlanConfigFsm continued */
+ logger.Debugw("UniVlanConfigFsm continued", log.Fields{
+ "state": pVlanFilterStatemachine.Current(), "device-id": dh.deviceID,
+ "UniPort": apUniPort.portNo})
+ }
+ } else {
+ logger.Debugw("no state of UniVlanConfigFsm to be continued", log.Fields{
+ "have": pVlanFilterStatemachine.Current(), "device-id": dh.deviceID})
+ }
+ } else {
+ logger.Debugw("UniVlanConfigFsm StateMachine does not exist, no flow processing", log.Fields{
+ "device-id": dh.deviceID})
+ }
+
+ } // else: nothing to do
+}
+
+//RemoveVlanFilterFsm deletes the stored pointer to the VlanConfigFsm
+// intention is to provide this method to be called from VlanConfigFsm itself, when resources (and methods!) are cleaned up
+func (dh *DeviceHandler) RemoveVlanFilterFsm(apUniPort *OnuUniPort) {
+ logger.Debugw("remove UniVlanConfigFsm StateMachine", log.Fields{
+ "device-id": dh.deviceID, "uniPort": apUniPort.portNo})
+ //save to do, even if entry dows not exist
+ delete(dh.UniVlanConfigFsmMap, apUniPort.uniId)
+}
diff --git a/internal/pkg/onuadaptercore/omci_ani_config.go b/internal/pkg/onuadaptercore/omci_ani_config.go
index f724e0f..b152818 100644
--- a/internal/pkg/onuadaptercore/omci_ani_config.go
+++ b/internal/pkg/onuadaptercore/omci_ani_config.go
@@ -37,13 +37,13 @@
// events of config PON ANI port FSM
aniEvStart = "uniEvStart"
aniEvStartConfig = "aniEvStartConfig"
- aniEvRxDot1pmapCresp = "aniEvRxDot1pmapCresp"
+ aniEvRxDot1pmapCResp = "aniEvRxDot1pmapCResp"
aniEvRxMbpcdResp = "aniEvRxMbpcdResp"
aniEvRxTcontsResp = "aniEvRxTcontsResp"
aniEvRxGemntcpsResp = "aniEvRxGemntcpsResp"
aniEvRxGemiwsResp = "aniEvRxGemiwsResp"
aniEvRxPrioqsResp = "aniEvRxPrioqsResp"
- aniEvRxDot1pmapSresp = "aniEvRxDot1pmapSresp"
+ aniEvRxDot1pmapSResp = "aniEvRxDot1pmapSResp"
aniEvTimeoutSimple = "aniEvTimeoutSimple"
aniEvTimeoutMids = "aniEvTimeoutMids"
aniEvReset = "aniEvReset"
@@ -124,7 +124,7 @@
//Note: .1p-Mapper and MBPCD might also have multi instances (per T-Cont) - by now only one 1 T-Cont considered!
{Name: aniEvStartConfig, Src: []string{aniStStarting}, Dst: aniStCreatingDot1PMapper},
- {Name: aniEvRxDot1pmapCresp, Src: []string{aniStCreatingDot1PMapper}, Dst: aniStCreatingMBPCD},
+ {Name: aniEvRxDot1pmapCResp, Src: []string{aniStCreatingDot1PMapper}, Dst: aniStCreatingMBPCD},
{Name: aniEvRxMbpcdResp, Src: []string{aniStCreatingMBPCD}, Dst: aniStSettingTconts},
{Name: aniEvRxTcontsResp, Src: []string{aniStSettingTconts}, Dst: aniStCreatingGemNCTPs},
// the creatingGemNCTPs state is used for multi ME config if required for all configured/available GemPorts
@@ -133,7 +133,7 @@
{Name: aniEvRxGemiwsResp, Src: []string{aniStCreatingGemIWs}, Dst: aniStSettingPQs},
// the settingPQs state is used for multi ME config if required for all configured/available upstream PriorityQueues
{Name: aniEvRxPrioqsResp, Src: []string{aniStSettingPQs}, Dst: aniStSettingDot1PMapper},
- {Name: aniEvRxDot1pmapSresp, Src: []string{aniStSettingDot1PMapper}, Dst: aniStConfigDone},
+ {Name: aniEvRxDot1pmapSResp, Src: []string{aniStSettingDot1PMapper}, Dst: aniStConfigDone},
{Name: aniEvTimeoutSimple, Src: []string{
aniStCreatingDot1PMapper, aniStCreatingMBPCD, aniStSettingTconts, aniStSettingDot1PMapper}, Dst: aniStStarting},
@@ -199,7 +199,7 @@
oFsm.gemPortAttribsSlice = nil
// start go routine for processing of LockState messages
- go oFsm.ProcessOmciAniMessages()
+ go oFsm.processOmciAniMessages()
//let the state machine run forward from here directly
pConfigAniStateAFsm := oFsm.pAdaptFsm
@@ -226,10 +226,10 @@
} else {
logger.Warnw("No TCont instances found", log.Fields{"device-id": oFsm.pAdaptFsm.deviceID})
}
- oFsm.alloc0ID = (*(oFsm.pUniTechProf.mapPonAniConfig[uint32(oFsm.pOnuUniPort.uniId)]))[0].tcontParams.allocID
+ oFsm.alloc0ID = (*(oFsm.pUniTechProf.mapPonAniConfig[oFsm.pOnuUniPort.uniId]))[0].tcontParams.allocID
loGemPortAttribs := ponAniGemPortAttribs{}
//for all TechProfile set GemIndices
- for _, gemEntry := range (*(oFsm.pUniTechProf.mapPonAniConfig[uint32(oFsm.pOnuUniPort.uniId)]))[0].mapGemPortParams {
+ for _, gemEntry := range (*(oFsm.pUniTechProf.mapPonAniConfig[oFsm.pOnuUniPort.uniId]))[0].mapGemPortParams {
//collect all GemConfigData in a seperate Fsm related slice (needed also to avoid mix-up with unsorted mapPonAniConfig)
if queueInstKeys := oFsm.pOnuDB.GetSortedInstKeys(me.PriorityQueueClassID); len(queueInstKeys) > 0 {
@@ -272,7 +272,7 @@
logger.Warnw("Could not convert attribute value", log.Fields{"device-id": oFsm.pAdaptFsm.deviceID})
}
} else {
- logger.Warnw("'relatedPort' not found in meAttributes:", log.Fields{"device-id": oFsm.pAdaptFsm.deviceID})
+ logger.Warnw("'RelatedPort' not found in meAttributes:", log.Fields{"device-id": oFsm.pAdaptFsm.deviceID})
}
} else {
logger.Warnw("No attributes available in DB:", log.Fields{"meClassID": me.PriorityQueueClassID,
@@ -356,7 +356,6 @@
}
func (oFsm *UniPonAniConfigFsm) enterCreatingGemNCTPs(e *fsm.Event) {
- //TODO!! this is just for the first GemPort right now - needs update
logger.Debugw("UniPonAniConfigFsm - start creating GemNWCtp loop", log.Fields{
"in state": e.FSM.Current(), "device-id": oFsm.pAdaptFsm.deviceID})
go oFsm.performCreatingGemNCTPs()
@@ -530,6 +529,10 @@
oFsm.pOmciCC.pBaseDeviceHandler.DeviceProcStatusUpdate(oFsm.requestEvent)
oFsm.aniConfigCompleted = false
}
+ //store that the UNI related techProfile processing is done for the given Profile and Uni
+ oFsm.pUniTechProf.setConfigDone(oFsm.pOnuUniPort.uniId, true)
+ //if techProfile processing is done it must be checked, if some prior/parallel flow configuration is pending
+ go oFsm.pOmciCC.pBaseDeviceHandler.verifyUniVlanConfigRequest(oFsm.pOnuUniPort)
if oFsm.chanSet {
// indicate processing done to the caller
@@ -541,7 +544,7 @@
}
-func (oFsm *UniPonAniConfigFsm) ProcessOmciAniMessages( /*ctx context.Context*/ ) {
+func (oFsm *UniPonAniConfigFsm) processOmciAniMessages( /*ctx context.Context*/ ) {
logger.Debugw("Start UniPonAniConfigFsm Msg processing", log.Fields{"for device-id": oFsm.pAdaptFsm.deviceID})
loop:
for {
@@ -603,16 +606,12 @@
}
if msgObj.EntityClass == oFsm.pOmciCC.pLastTxMeInstance.GetClassID() &&
msgObj.EntityInstance == oFsm.pOmciCC.pLastTxMeInstance.GetEntityID() {
- //store the created ME into DB //TODO??? obviously the Python code does not store the config ...
- // if, then something like:
- //oFsm.pOnuDB.StoreMe(msgObj)
-
// maybe we can use just the same eventName for different state transitions like "forward"
// - might be checked, but so far I go for sure and have to inspect the concrete state events ...
switch oFsm.pOmciCC.pLastTxMeInstance.GetName() {
case "Ieee8021PMapperServiceProfile":
{ // let the FSM proceed ...
- oFsm.pAdaptFsm.pFsm.Event(aniEvRxDot1pmapCresp)
+ oFsm.pAdaptFsm.pFsm.Event(aniEvRxDot1pmapCResp)
}
case "MacBridgePortConfigurationData":
{ // let the FSM proceed ...
@@ -660,7 +659,7 @@
}
case "Ieee8021PMapperServiceProfile":
{ // let the FSM proceed ...
- oFsm.pAdaptFsm.pFsm.Event(aniEvRxDot1pmapSresp)
+ oFsm.pAdaptFsm.pFsm.Event(aniEvRxDot1pmapSResp)
}
}
}
diff --git a/internal/pkg/onuadaptercore/omci_cc.go b/internal/pkg/onuadaptercore/omci_cc.go
index 5ee61f1..23fd506 100644
--- a/internal/pkg/onuadaptercore/omci_cc.go
+++ b/internal/pkg/onuadaptercore/omci_cc.go
@@ -25,6 +25,7 @@
"errors"
"strconv"
"sync"
+
//"time"
"github.com/google/gopacket"
@@ -395,6 +396,7 @@
// block parallel omci send requests at least until SendIAP is 'committed'
// that should be feasible for an onu instance as on OMCI anyway window size 1 is assumed
oo.mutexTxQueue.Lock()
+ defer oo.mutexTxQueue.Unlock()
for oo.txQueue.Len() > 0 {
queueElement := oo.txQueue.Front() // First element
omciTxRequest := queueElement.Value.(omciTransferStructure)
@@ -476,7 +478,6 @@
}
oo.txQueue.Remove(queueElement) // Dequeue
}
- oo.mutexTxQueue.Unlock()
return nil
}
@@ -1391,3 +1392,90 @@
"Err": omciErr.GetError(), "device-id": oo.deviceID})
return nil
}
+
+func (oo *OmciCC) sendCreateVtfdVar(ctx context.Context, timeout int, highPrio bool,
+ rxChan chan Message, params ...me.ParamData) *me.ManagedEntity {
+ tid := oo.GetNextTid(highPrio)
+ logger.Debugw("send VTFD-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.NewVlanTaggingFilterData(params[0])
+ if omciErr.GetError() == nil {
+ //all SetByCreate Parameters (assumed to be) set here, for optimisation no 'AddDefaults'
+ omciLayer, msgLayer, err := omci.EncodeFrame(meInstance, omci.CreateRequestType,
+ omci.TransactionID(tid))
+ if err != nil {
+ logger.Errorw("Cannot encode VTFD for create", log.Fields{
+ "Err": err, "device-id": oo.deviceID})
+ //TODO!!: refactoring improvement requested, here as an example for [VOL-3457]:
+ // return (dual format) error code that can be used at caller for immediate error treatment
+ // (relevant to all used sendXX() methods and their error conditions)
+ return nil
+ }
+
+ pkt, err := serializeOmciLayer(omciLayer, msgLayer)
+ if err != nil {
+ logger.Errorw("Cannot serialize VTFD 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 VTFD create", log.Fields{
+ "Err": err, "device-id": oo.deviceID})
+ return nil
+ }
+ logger.Debug("send VTFD-Create-msg done")
+ return meInstance
+ }
+ logger.Errorw("Cannot generate VTFD 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)
+ logger.Debugw("send EVTOCD-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.NewExtendedVlanTaggingOperationConfigurationData(params[0])
+ if omciErr.GetError() == nil {
+ omciLayer, msgLayer, err := omci.EncodeFrame(meInstance, omci.SetRequestType, omci.TransactionID(tid))
+ if err != nil {
+ logger.Errorw("Cannot encode EVTOCD for set", log.Fields{
+ "Err": err, "device-id": oo.deviceID})
+ return nil
+ }
+
+ pkt, err := serializeOmciLayer(omciLayer, msgLayer)
+ if err != nil {
+ logger.Errorw("Cannot serialize EVTOCD set", 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 set", 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
+}
diff --git a/internal/pkg/onuadaptercore/omci_vlan_config.go b/internal/pkg/onuadaptercore/omci_vlan_config.go
new file mode 100644
index 0000000..f60cd93
--- /dev/null
+++ b/internal/pkg/onuadaptercore/omci_vlan_config.go
@@ -0,0 +1,726 @@
+/*
+ * 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.
+ */
+
+//Package adaptercoreonu provides the utility for onu devices, flows and statistics
+package adaptercoreonu
+
+import (
+ "context"
+ "encoding/binary"
+ "errors"
+ "strconv"
+ "time"
+
+ "github.com/looplab/fsm"
+ "github.com/opencord/omci-lib-go"
+ me "github.com/opencord/omci-lib-go/generated"
+ "github.com/opencord/voltha-lib-go/v3/pkg/log"
+ of "github.com/opencord/voltha-protos/v3/go/openflow_13"
+)
+
+const (
+ // internal predefined values
+ cDefaultDownstreamMode = 0
+ cDefaultTpid = 0x8100
+)
+
+const (
+ // bit mask offsets for EVTOCD VlanTaggingOperationTable related to 32 bits (4 bytes)
+ cFilterPrioOffset = 28
+ cFilterVidOffset = 15
+ cFilterTpidOffset = 12
+ cFilterEtherTypeOffset = 0
+ cTreatTTROffset = 30
+ cTreatPrioOffset = 16
+ cTreatVidOffset = 3
+ cTreatTpidOffset = 0
+)
+const (
+ // byte offsets for EVTOCD VlanTaggingOperationTable related to overall 16 byte size with slice byte 0 as first Byte (MSB)
+ cFilterOuterOffset = 0
+ cFilterInnerOffset = 4
+ cTreatOuterOffset = 8
+ cTreatInnerOffset = 12
+)
+const (
+ // basic values used within EVTOCD VlanTaggingOperationTable in respect to their bitfields
+ cPrioIgnoreTag uint32 = 15
+ cPrioDefaultFilter uint32 = 14
+ cPrioDoNotFilter uint32 = 8
+ cDoNotFilterVid uint32 = 4096
+ cDoNotFilterTPID uint32 = 0
+ cDoNotFilterEtherType uint32 = 0
+ cDoNotAddPrio uint32 = 15
+ cCopyPrioFromInner uint32 = 8
+ cDontCarePrio uint32 = 0
+ cDontCareVid uint32 = 0
+ cDontCareTpid uint32 = 0
+ cSetOutputTpidCopyDei uint32 = 4
+)
+
+const (
+ // events of config PON ANI port FSM
+ vlanEvStart = "vlanEvStart"
+ vlanEvWaitTechProf = "vlanEvWaitTechProf"
+ vlanEvContinueConfig = "vlanEvContinueConfig"
+ vlanEvStartConfig = "vlanEvStartConfig"
+ vlanEvRxConfigVtfd = "vlanEvRxConfigVtfd"
+ vlanEvRxConfigEvtocd = "vlanEvRxConfigEvtocd"
+ vlanEvCleanupConfig = "vlanEvCleanupConfig"
+ vlanEvRxCleanVtfd = "vlanEvRxCleanVtfd"
+ vlanEvRxCleanEvtocd = "vlanEvRxCleanEvtocd"
+ vlanEvTimeoutSimple = "vlanEvTimeoutSimple"
+ vlanEvTimeoutMids = "vlanEvTimeoutMids"
+ vlanEvReset = "vlanEvReset"
+ vlanEvRestart = "vlanEvRestart"
+)
+const (
+ // states of config PON ANI port FSM
+ vlanStDisabled = "vlanStDisabled"
+ vlanStStarting = "vlanStStarting"
+ vlanStWaitingTechProf = "vlanStWaitingTechProf"
+ vlanStConfigVtfd = "vlanStConfigVtfd"
+ vlanStConfigEvtocd = "vlanStConfigEvtocd"
+ vlanStConfigDone = "vlanStConfigDone"
+ vlanStCleanEvtocd = "vlanStCleanEvtocd"
+ vlanStCleanVtfd = "vlanStCleanVtfd"
+ vlanStCleanupDone = "vlanStCleanupDone"
+ vlanStResetting = "vlanStResetting"
+)
+
+//UniVlanConfigFsm defines the structure for the state machine to config the PON ANI ports of ONU UNI ports via OMCI
+type UniVlanConfigFsm struct {
+ pDeviceHandler *DeviceHandler
+ pOmciCC *OmciCC
+ pOnuUniPort *OnuUniPort
+ pUniTechProf *OnuUniTechProf
+ pOnuDB *OnuDeviceDB
+ techProfileID uint16
+ requestEvent OnuDeviceEvent
+ omciMIdsResponseReceived chan bool //seperate channel needed for checking multiInstance OMCI message responses
+ pAdaptFsm *AdapterFsm
+ acceptIncrementalEvtoOption bool
+ //use uint32 types for allowing immediate bitshifting
+ matchVid uint32
+ matchPcp uint32
+ tagsToRemove uint32
+ setVid uint32
+ setPcp uint32
+ vtfdID uint16
+ evtocdID uint16
+}
+
+//NewUniVlanConfigFsm is the 'constructor' for the state machine to config the PON ANI ports of ONU UNI ports via OMCI
+func NewUniVlanConfigFsm(apDeviceHandler *DeviceHandler, apDevOmciCC *OmciCC, apUniPort *OnuUniPort, apUniTechProf *OnuUniTechProf,
+ apOnuDB *OnuDeviceDB, aTechProfileID uint16, aRequestEvent OnuDeviceEvent, aName string,
+ aDeviceID string, aCommChannel chan Message,
+ aAcceptIncrementalEvto bool, aMatchVlan uint16, aSetVlan uint16, aSetPcp uint8) *UniVlanConfigFsm {
+ instFsm := &UniVlanConfigFsm{
+ pDeviceHandler: apDeviceHandler,
+ pOmciCC: apDevOmciCC,
+ pOnuUniPort: apUniPort,
+ pUniTechProf: apUniTechProf,
+ pOnuDB: apOnuDB,
+ techProfileID: aTechProfileID,
+ requestEvent: aRequestEvent,
+ acceptIncrementalEvtoOption: aAcceptIncrementalEvto,
+ matchVid: uint32(aMatchVlan),
+ setVid: uint32(aSetVlan),
+ setPcp: uint32(aSetPcp),
+ }
+ // some automatic adjustments on the filter/treat parameters as not specifically configured/ensured by flow configuration parameters
+ instFsm.tagsToRemove = 1 //one tag to remove as default setting
+ instFsm.matchPcp = cPrioDoNotFilter // do not Filter on prio as default
+ if instFsm.matchVid == uint32(of.OfpVlanId_OFPVID_PRESENT) {
+ // no prio/vid filtering requested
+ instFsm.tagsToRemove = 0 //no tag pop action
+ instFsm.matchPcp = cPrioIgnoreTag // no vlan tag filtering
+ if instFsm.setPcp == cCopyPrioFromInner {
+ //in case of no filtering and configured PrioCopy ensure default prio setting to 0
+ // which is required for stacking of untagged, but obviously also ensures prio setting for prio/singletagged
+ // might collide with NoMatchVid/CopyPrio(/setVid) setting
+ // this was some precondition setting taken over from py adapter ..
+ instFsm.setPcp = 0
+ }
+ }
+
+ instFsm.pAdaptFsm = NewAdapterFsm(aName, aDeviceID, aCommChannel)
+ if instFsm.pAdaptFsm == nil {
+ logger.Errorw("UniVlanConfigFsm's AdapterFsm could not be instantiated!!", log.Fields{
+ "device-id": aDeviceID})
+ return nil
+ }
+
+ instFsm.pAdaptFsm.pFsm = fsm.NewFSM(
+ vlanStDisabled,
+ fsm.Events{
+ {Name: vlanEvStart, Src: []string{vlanStDisabled}, Dst: vlanStStarting},
+ {Name: vlanEvWaitTechProf, Src: []string{vlanStStarting}, Dst: vlanStWaitingTechProf},
+ {Name: vlanEvContinueConfig, Src: []string{vlanStWaitingTechProf}, Dst: vlanStConfigVtfd},
+ {Name: vlanEvStartConfig, Src: []string{vlanStStarting}, Dst: vlanStConfigVtfd},
+ {Name: vlanEvRxConfigVtfd, Src: []string{vlanStConfigVtfd}, Dst: vlanStConfigEvtocd},
+ {Name: vlanEvRxConfigEvtocd, Src: []string{vlanStConfigEvtocd}, Dst: vlanStConfigDone},
+ //TODO:!!! Also define state transitions for cleanup states and timeouts
+ /*
+ {Name: vlanEvTimeoutSimple, Src: []string{
+ vlanStCreatingDot1PMapper, vlanStCreatingMBPCD, vlanStSettingTconts, vlanStSettingDot1PMapper}, Dst: vlanStStarting},
+ {Name: vlanEvTimeoutMids, Src: []string{
+ vlanStCreatingGemNCTPs, vlanStCreatingGemIWs, vlanStSettingPQs}, Dst: vlanStStarting},
+ */
+ // exceptional treatment for all states except vlanStResetting
+ {Name: vlanEvReset, Src: []string{vlanStStarting, vlanStWaitingTechProf,
+ vlanStConfigVtfd, vlanStConfigEvtocd, vlanStConfigDone,
+ vlanStCleanEvtocd, vlanStCleanVtfd, vlanStCleanupDone},
+ Dst: vlanStResetting},
+ // the only way to get to resource-cleared disabled state again is via "resseting"
+ {Name: vlanEvRestart, Src: []string{vlanStResetting}, Dst: vlanStDisabled},
+ },
+
+ fsm.Callbacks{
+ "enter_state": func(e *fsm.Event) { instFsm.pAdaptFsm.logFsmStateChange(e) },
+ ("enter_" + vlanStStarting): func(e *fsm.Event) { instFsm.enterConfigStarting(e) },
+ ("enter_" + vlanStConfigVtfd): func(e *fsm.Event) { instFsm.enterConfigVtfd(e) },
+ ("enter_" + vlanStConfigEvtocd): func(e *fsm.Event) { instFsm.enterConfigEvtocd(e) },
+ ("enter_" + vlanStConfigDone): func(e *fsm.Event) { instFsm.enterVlanConfigDone(e) },
+ ("enter_" + vlanStCleanVtfd): func(e *fsm.Event) { instFsm.enterCleanVtfd(e) },
+ ("enter_" + vlanStCleanEvtocd): func(e *fsm.Event) { instFsm.enterCleanEvtocd(e) },
+ ("enter_" + vlanStCleanupDone): func(e *fsm.Event) { instFsm.enterVlanCleanupDone(e) },
+ ("enter_" + vlanStResetting): func(e *fsm.Event) { instFsm.enterResetting(e) },
+ ("enter_" + vlanStDisabled): func(e *fsm.Event) { instFsm.enterDisabled(e) },
+ },
+ )
+ if instFsm.pAdaptFsm.pFsm == nil {
+ logger.Errorw("UniVlanConfigFsm's Base FSM could not be instantiated!!", log.Fields{
+ "device-id": aDeviceID})
+ return nil
+ }
+
+ logger.Infow("UniVlanConfigFsm created", log.Fields{"device-id": aDeviceID,
+ "accIncrEvto": instFsm.acceptIncrementalEvtoOption,
+ "matchVid": strconv.FormatInt(int64(instFsm.matchVid), 16),
+ "setVid": strconv.FormatInt(int64(instFsm.setVid), 16),
+ "setPcp": instFsm.setPcp})
+ return instFsm
+}
+
+func (oFsm *UniVlanConfigFsm) enterConfigStarting(e *fsm.Event) {
+ logger.Debugw("UniVlanConfigFsm start", log.Fields{"in state": e.FSM.Current(),
+ "device-id": oFsm.pAdaptFsm.deviceID})
+
+ // this FSM is not intended for re-start, needs always new creation for a new run
+ oFsm.omciMIdsResponseReceived = make(chan bool)
+ // start go routine for processing of LockState messages
+ go oFsm.processOmciVlanMessages()
+ //let the state machine run forward from here directly
+ pConfigVlanStateAFsm := oFsm.pAdaptFsm
+ if pConfigVlanStateAFsm != nil {
+ // 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
+ //cmp also usage in EVTOCDE create in omci_cc
+ oFsm.evtocdID = macBridgeServiceProfileEID + uint16(oFsm.pOnuUniPort.macBpNo)
+
+ if oFsm.pUniTechProf.getTechProfileDone(oFsm.pOnuUniPort.uniId, oFsm.techProfileID) {
+ // let the vlan processing begin
+ a_pAFsm.pFsm.Event(vlanEvStartConfig)
+ } else {
+ // set to waiting for Techprofile
+ a_pAFsm.pFsm.Event(vlanEvWaitTechProf)
+ }
+ }
+ }(pConfigVlanStateAFsm)
+ }
+}
+
+func (oFsm *UniVlanConfigFsm) enterConfigVtfd(e *fsm.Event) {
+ if oFsm.setVid == uint32(of.OfpVlanId_OFPVID_PRESENT) {
+ // meaning transparent setup - no specific VTFD setting required
+ logger.Debugw("UniVlanConfigFsm: no VTFD config required", log.Fields{
+ "in state": e.FSM.Current(), "device-id": oFsm.pAdaptFsm.deviceID})
+ // let the FSM proceed ... (from within this state all internal pointers may be expected to be correct)
+ // obviously calling some FSM event here directly does not work - so trying to decouple it ...
+ pConfigVlanStateAFsm := oFsm.pAdaptFsm
+ go func(a_pAFsm *AdapterFsm) {
+ a_pAFsm.pFsm.Event(vlanEvRxConfigVtfd)
+ }(pConfigVlanStateAFsm)
+ } else {
+ logger.Debugw("UniVlanConfigFsm create VTFD", log.Fields{
+ "EntitytId": strconv.FormatInt(int64(oFsm.vtfdID), 16),
+ "in state": e.FSM.Current(), "device-id": oFsm.pAdaptFsm.deviceID})
+ vlanFilterList := make([]uint16, 12)
+ vlanFilterList[0] = uint16(oFsm.setVid) // setVid is assumed to be masked already by the caller to 12 bit
+ meParams := me.ParamData{
+ EntityID: oFsm.vtfdID,
+ Attributes: me.AttributeValueMap{
+ "VlanFilterList": vlanFilterList,
+ "ForwardOperation": uint8(0x10), //VID investigation
+ "NumberOfEntries": uint8(1),
+ },
+ }
+ 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
+ //TODO!!: refactoring improvement requested, here as an example for [VOL-3457]:
+ // send shall return (dual format) error code that can be used here for immediate error treatment
+ // (relevant to all used sendXX() methods in this (and other) FSM's)
+ oFsm.pOmciCC.pLastTxMeInstance = meInstance
+ }
+}
+
+func (oFsm *UniVlanConfigFsm) enterConfigEvtocd(e *fsm.Event) {
+ logger.Debugw("UniVlanConfigFsm - start config EVTOCD loop", log.Fields{
+ "in state": e.FSM.Current(), "device-id": oFsm.pAdaptFsm.deviceID})
+ go oFsm.performConfigEvtocdEntries()
+}
+
+func (oFsm *UniVlanConfigFsm) enterVlanConfigDone(e *fsm.Event) {
+ logger.Debugw("UniVlanConfigFsm - VLAN config done: send dh event notification", log.Fields{
+ "in state": e.FSM.Current(), "device-id": oFsm.pAdaptFsm.deviceID})
+ if oFsm.pDeviceHandler != nil {
+ oFsm.pDeviceHandler.DeviceProcStatusUpdate(oFsm.requestEvent)
+ }
+}
+
+func (oFsm *UniVlanConfigFsm) enterCleanVtfd(e *fsm.Event) {
+ logger.Debugw("UniVlanConfigFsm Tx Delete::VTFD", log.Fields{
+ /*"EntitytId": strconv.FormatInt(int64(oFsm.mapperSP0ID), 16),*/
+ "in state": e.FSM.Current(), "device-id": oFsm.pAdaptFsm.deviceID})
+}
+
+func (oFsm *UniVlanConfigFsm) enterCleanEvtocd(e *fsm.Event) {
+ logger.Debugw("UniVlanConfigFsm cleanup EVTOCD", log.Fields{
+ /*"EntitytId": strconv.FormatInt(int64(oFsm.macBPCD0ID), 16),
+ "TPPtr": strconv.FormatInt(int64(oFsm.mapperSP0ID), 16),*/
+ "in state": e.FSM.Current(), "device-id": oFsm.pAdaptFsm.deviceID})
+}
+
+func (oFsm *UniVlanConfigFsm) enterVlanCleanupDone(e *fsm.Event) {
+ logger.Debugw("UniVlanConfigFsm - VLAN cleanup done", log.Fields{
+ "in state": e.FSM.Current(), "device-id": oFsm.pAdaptFsm.deviceID})
+
+ //let's reset the state machine in order to release all resources now
+ pConfigVlanStateAFsm := oFsm.pAdaptFsm
+ if pConfigVlanStateAFsm != nil {
+ // 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 {
+ a_pAFsm.pFsm.Event(vlanEvReset)
+ }
+ }(pConfigVlanStateAFsm)
+ }
+}
+
+func (oFsm *UniVlanConfigFsm) enterResetting(e *fsm.Event) {
+ logger.Debugw("UniVlanConfigFsm resetting", log.Fields{"device-id": oFsm.pAdaptFsm.deviceID})
+
+ pConfigVlanStateAFsm := oFsm.pAdaptFsm
+ if pConfigVlanStateAFsm != nil {
+ // abort running message processing
+ fsmAbortMsg := Message{
+ Type: TestMsg,
+ Data: TestMessage{
+ TestMessageVal: AbortMessageProcessing,
+ },
+ }
+ pConfigVlanStateAFsm.commChan <- fsmAbortMsg
+
+ //try to restart the FSM to 'disabled', decouple event transfer
+ go func(a_pAFsm *AdapterFsm) {
+ if a_pAFsm != nil && a_pAFsm.pFsm != nil {
+ a_pAFsm.pFsm.Event(vlanEvRestart)
+ }
+ }(pConfigVlanStateAFsm)
+ }
+}
+
+func (oFsm *UniVlanConfigFsm) enterDisabled(e *fsm.Event) {
+ logger.Debugw("UniVlanConfigFsm enters disabled state", log.Fields{"device-id": oFsm.pAdaptFsm.deviceID})
+ if oFsm.pDeviceHandler != nil {
+ //request removal of 'reference' in the Handler (completely clear the FSM)
+ go oFsm.pDeviceHandler.RemoveVlanFilterFsm(oFsm.pOnuUniPort)
+ }
+}
+
+func (oFsm *UniVlanConfigFsm) processOmciVlanMessages() { //ctx context.Context?
+ logger.Debugw("Start UniVlanConfigFsm Msg processing", log.Fields{"for device-id": oFsm.pAdaptFsm.deviceID})
+loop:
+ for {
+ select {
+ // case <-ctx.Done():
+ // logger.Info("MibSync Msg", log.Fields{"Message handling canceled via context for device-id": oFsm.pAdaptFsm.deviceID})
+ // break loop
+ case message, ok := <-oFsm.pAdaptFsm.commChan:
+ if !ok {
+ logger.Info("UniVlanConfigFsm Rx Msg - could not read from channel", log.Fields{"device-id": oFsm.pAdaptFsm.deviceID})
+ // but then we have to ensure a restart of the FSM as well - as exceptional procedure
+ oFsm.pAdaptFsm.pFsm.Event(vlanEvReset)
+ break loop
+ }
+ logger.Debugw("UniVlanConfigFsm Rx Msg", log.Fields{"device-id": oFsm.pAdaptFsm.deviceID})
+
+ switch message.Type {
+ case TestMsg:
+ msg, _ := message.Data.(TestMessage)
+ if msg.TestMessageVal == AbortMessageProcessing {
+ logger.Infow("UniVlanConfigFsm abort ProcessMsg", log.Fields{"for device-id": oFsm.pAdaptFsm.deviceID})
+ break loop
+ }
+ logger.Warnw("UniVlanConfigFsm unknown TestMessage", log.Fields{"device-id": oFsm.pAdaptFsm.deviceID, "MessageVal": msg.TestMessageVal})
+ case OMCI:
+ msg, _ := message.Data.(OmciMessage)
+ oFsm.handleOmciVlanConfigMessage(msg)
+ default:
+ logger.Warn("UniVlanConfigFsm Rx unknown message", log.Fields{"device-id": oFsm.pAdaptFsm.deviceID,
+ "message.Type": message.Type})
+ }
+ }
+ }
+ logger.Infow("End UniVlanConfigFsm Msg processing", log.Fields{"device-id": oFsm.pAdaptFsm.deviceID})
+}
+
+func (oFsm *UniVlanConfigFsm) handleOmciVlanConfigMessage(msg OmciMessage) {
+ logger.Debugw("Rx OMCI UniVlanConfigFsm Msg", log.Fields{"device-id": oFsm.pAdaptFsm.deviceID,
+ "msgType": msg.OmciMsg.MessageType})
+
+ switch msg.OmciMsg.MessageType {
+ case omci.CreateResponseType:
+ {
+ msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeCreateResponse)
+ if msgLayer == nil {
+ logger.Error("Omci Msg layer could not be detected for CreateResponse")
+ return
+ }
+ msgObj, msgOk := msgLayer.(*omci.CreateResponse)
+ if !msgOk {
+ logger.Error("Omci Msg layer could not be assigned for CreateResponse")
+ return
+ }
+ logger.Debugw("CreateResponse Data", log.Fields{"device-id": oFsm.pAdaptFsm.deviceID, "data-fields": msgObj})
+ if msgObj.Result != me.Success {
+ logger.Errorw("Omci CreateResponse Error - later: drive FSM to abort state ?", log.Fields{"Error": msgObj.Result})
+ // possibly force FSM into abort or ignore some errors for some messages? store error for mgmt display?
+ return
+ }
+ if msgObj.EntityClass == oFsm.pOmciCC.pLastTxMeInstance.GetClassID() &&
+ msgObj.EntityInstance == oFsm.pOmciCC.pLastTxMeInstance.GetEntityID() {
+ // maybe we can use just the same eventName for different state transitions like "forward"
+ // - might be checked, but so far I go for sure and have to inspect the concrete state events ...
+ switch oFsm.pOmciCC.pLastTxMeInstance.GetName() {
+ case "VlanTaggingFilterData":
+ { // let the FSM proceed ...
+ oFsm.pAdaptFsm.pFsm.Event(vlanEvRxConfigVtfd)
+ }
+ }
+ }
+ } //CreateResponseType
+ case omci.SetResponseType:
+ {
+ msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeSetResponse)
+ if msgLayer == nil {
+ logger.Error("UniVlanConfigFsm - Omci Msg layer could not be detected for SetResponse")
+ return
+ }
+ msgObj, msgOk := msgLayer.(*omci.SetResponse)
+ if !msgOk {
+ logger.Error("UniVlanConfigFsm - Omci Msg layer could not be assigned for SetResponse")
+ return
+ }
+ logger.Debugw("UniVlanConfigFsm SetResponse Data", log.Fields{"deviceId": oFsm.pAdaptFsm.deviceID, "data-fields": msgObj})
+ if msgObj.Result != me.Success {
+ logger.Errorw("UniVlanConfigFsm - Omci SetResponse Error - later: drive FSM to abort state ?", log.Fields{"Error": msgObj.Result})
+ // possibly force FSM into abort or ignore some errors for some messages? store error for mgmt display?
+ return
+ }
+ if msgObj.EntityClass == oFsm.pOmciCC.pLastTxMeInstance.GetClassID() &&
+ msgObj.EntityInstance == oFsm.pOmciCC.pLastTxMeInstance.GetEntityID() {
+ switch oFsm.pOmciCC.pLastTxMeInstance.GetName() {
+ case "ExtendedVlanTaggingOperationConfigurationData":
+ { // let the EVTO config proceed by stopping the wait function
+ oFsm.omciMIdsResponseReceived <- true
+ }
+ }
+ }
+ } //SetResponseType
+ default:
+ {
+ logger.Errorw("UniVlanConfigFsm - Rx OMCI unhandled MsgType", log.Fields{"omciMsgType": msg.OmciMsg.MessageType})
+ return
+ }
+ }
+}
+
+func (oFsm *UniVlanConfigFsm) performConfigEvtocdEntries() {
+ { // for local var
+ // 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{
+ "EntitytId": strconv.FormatInt(int64(oFsm.evtocdID), 16),
+ "i/oEthType": strconv.FormatInt(int64(cDefaultTpid), 16),
+ "device-id": oFsm.pAdaptFsm.deviceID})
+ 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.pOmciCC.pLastTxMeInstance = meInstance
+
+ //verify response
+ err := oFsm.waitforOmciResponse()
+ if err != nil {
+ logger.Errorw("Evtocd set TPID failed, aborting VlanConfig FSM!",
+ log.Fields{"device-id": oFsm.pAdaptFsm.deviceID})
+ oFsm.pAdaptFsm.pFsm.Event(vlanEvReset)
+ return
+ }
+ } //for local var
+
+ if oFsm.setVid == uint32(of.OfpVlanId_OFPVID_PRESENT) {
+ //transparent transmission required
+ logger.Debugw("UniVlanConfigFsm Tx Set::EVTOCD single tagged transparent rule", log.Fields{
+ "device-id": oFsm.pAdaptFsm.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:],
+ cPrioDefaultFilter<<cFilterPrioOffset| // default 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
+ cSetOutputTpidCopyDei<<cTreatTpidOffset) // Set TPID = 0x8100
+
+ 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.pOmciCC.pLastTxMeInstance = meInstance
+
+ //verify response
+ err := oFsm.waitforOmciResponse()
+ if err != nil {
+ logger.Errorw("Evtocd set transparent singletagged rule failed, aborting VlanConfig FSM!",
+ log.Fields{"device-id": oFsm.pAdaptFsm.deviceID})
+ oFsm.pAdaptFsm.pFsm.Event(vlanEvReset)
+ return
+ }
+ } else {
+ // according to py-code acceptIncrementalEvto program option decides upon stacking or translation scenario
+ if oFsm.acceptIncrementalEvtoOption {
+ // 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.pAdaptFsm.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:],
+ oFsm.matchPcp<<cFilterPrioOffset| // either DNFonPrio or ignore tag (default) on innerVLAN
+ oFsm.matchVid<<cFilterVidOffset| // either DNFonVid or real filter VID
+ cDoNotFilterTPID<<cFilterTpidOffset| // Do not filter on inner TPID field
+ cDoNotFilterEtherType<<cFilterEtherTypeOffset) // Do not filter of EtherType
+
+ binary.BigEndian.PutUint32(sliceEvtocdRule[cTreatOuterOffset:],
+ oFsm.tagsToRemove<<cTreatTTROffset| // either 1 or 0
+ 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:],
+ oFsm.setPcp<<cTreatPrioOffset| // as configured in flow
+ oFsm.setVid<<cTreatVidOffset| //as configured in flow
+ cSetOutputTpidCopyDei<<cTreatTpidOffset) // Set TPID = 0x8100
+
+ 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.pOmciCC.pLastTxMeInstance = meInstance
+
+ //verify response
+ err := oFsm.waitforOmciResponse()
+ if err != nil {
+ logger.Errorw("Evtocd set singletagged translation rule failed, aborting VlanConfig FSM!",
+ log.Fields{"device-id": oFsm.pAdaptFsm.deviceID})
+ oFsm.pAdaptFsm.pFsm.Event(vlanEvReset)
+ return
+ }
+ } else {
+ //not transparent and not acceptIncrementalEvtoOption untagged/priotagged->singletagged
+ { // just for local var's
+ // this defines stacking scenario: untagged->singletagged
+ logger.Debugw("UniVlanConfigFsm Tx Set::EVTOCD untagged->singletagged rule", log.Fields{
+ "device-id": oFsm.pAdaptFsm.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:],
+ 0<<cTreatPrioOffset| // vlan prio set to 0
+ // (as done in Py code, maybe better option would be setPcp here, which still could be 0?)
+ oFsm.setVid<<cTreatVidOffset| // Outer VID don't care
+ cSetOutputTpidCopyDei<<cTreatTpidOffset) // Set TPID = 0x8100
+
+ 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.pOmciCC.pLastTxMeInstance = meInstance
+
+ //verify response
+ err := oFsm.waitforOmciResponse()
+ if err != nil {
+ logger.Errorw("Evtocd set untagged->singletagged rule failed, aborting VlanConfig FSM!",
+ log.Fields{"device-id": oFsm.pAdaptFsm.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 priotagged->singletagged rule", log.Fields{
+ "device-id": oFsm.pAdaptFsm.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[cTreatOuterOffset:],
+ 1<<cTreatTTROffset| // pop the prio-tag
+ 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:],
+ cCopyPrioFromInner<<cTreatPrioOffset| // vlan copy from PrioTag
+ // (as done in Py code, maybe better option would be setPcp here, which still could be PrioCopy?)
+ oFsm.setVid<<cTreatVidOffset| // Outer VID as configured
+ cSetOutputTpidCopyDei<<cTreatTpidOffset) // Set TPID = 0x8100
+
+ 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.pOmciCC.pLastTxMeInstance = meInstance
+
+ //verify response
+ err := oFsm.waitforOmciResponse()
+ if err != nil {
+ logger.Errorw("Evtocd set priotagged->singletagged rule failed, aborting VlanConfig FSM!",
+ log.Fields{"device-id": oFsm.pAdaptFsm.deviceID})
+ oFsm.pAdaptFsm.pFsm.Event(vlanEvReset)
+ return
+ }
+ } //just for local var's
+ }
+ }
+
+ // if Config has been done for all GemPort instances let the FSM proceed
+ logger.Debugw("EVTOCD set loop finished", log.Fields{"device-id": oFsm.pAdaptFsm.deviceID})
+ oFsm.pAdaptFsm.pFsm.Event(vlanEvRxConfigEvtocd)
+ return
+}
+
+func (oFsm *UniVlanConfigFsm) waitforOmciResponse() error {
+ select {
+ // maybe be also some outside cancel (but no context modelled for the moment ...)
+ // case <-ctx.Done():
+ // logger.Infow("LockState-bridge-init message reception canceled", log.Fields{"for device-id": oFsm.pAdaptFsm.deviceID})
+ case <-time.After(30 * time.Second): //AS FOR THE OTHER OMCI FSM's
+ logger.Warnw("UniVlanConfigFsm multi entity timeout", log.Fields{"for device-id": oFsm.pAdaptFsm.deviceID})
+ return errors.New("UniVlanConfigFsm multi entity timeout")
+ case success := <-oFsm.omciMIdsResponseReceived:
+ if success == true {
+ logger.Debug("UniVlanConfigFsm multi entity response received")
+ return nil
+ }
+ // should not happen so far
+ logger.Warnw("UniVlanConfigFsm multi entity response error", log.Fields{"for device-id": oFsm.pAdaptFsm.deviceID})
+ return errors.New("UniVlanConfigFsm multi entity responseError")
+ }
+}
diff --git a/internal/pkg/onuadaptercore/onu_device_db.go b/internal/pkg/onuadaptercore/onu_device_db.go
index aa12728..4b80a94 100644
--- a/internal/pkg/onuadaptercore/onu_device_db.go
+++ b/internal/pkg/onuadaptercore/onu_device_db.go
@@ -64,16 +64,21 @@
} else {
meAttribs, ok := onuDeviceDB.meDb[meClassId][meEntityId]
if !ok {
+ /* verbose logging, avoid in >= debug level
logger.Debugw("meEntityId not found - add to db :", log.Fields{"device-id": onuDeviceDB.pOnuDeviceEntry.deviceID})
+ */
onuDeviceDB.meDb[meClassId][meEntityId] = meAttributes
} else {
+ /* verbose logging, avoid in >= debug level
logger.Debugw("ME-Instance exists already: merge attribute data :", log.Fields{"device-id": onuDeviceDB.pOnuDeviceEntry.deviceID, "meAttribs": meAttribs})
-
+ */
for k, v := range meAttributes {
meAttribs[k] = v
}
onuDeviceDB.meDb[meClassId][meEntityId] = meAttribs
+ /* verbose logging, avoid in >= debug level
logger.Debugw("ME-Instance updated :", log.Fields{"device-id": onuDeviceDB.pOnuDeviceEntry.deviceID, "meAttribs": meAttribs})
+ */
}
}
}
@@ -81,8 +86,10 @@
func (onuDeviceDB *OnuDeviceDB) GetMe(meClassId me.ClassID, meEntityId uint16) me.AttributeValueMap {
if meAttributes, present := onuDeviceDB.meDb[meClassId][meEntityId]; present {
+ /* verbose logging, avoid in >= debug level
logger.Debugw("ME found:", log.Fields{"meClassId": meClassId, "meEntityId": meEntityId, "meAttributes": meAttributes,
"device-id": onuDeviceDB.pOnuDeviceEntry.deviceID})
+ */
return meAttributes
} else {
return nil
diff --git a/internal/pkg/onuadaptercore/onu_device_entry.go b/internal/pkg/onuadaptercore/onu_device_entry.go
index a29bf05..154e513 100644
--- a/internal/pkg/onuadaptercore/onu_device_entry.go
+++ b/internal/pkg/onuadaptercore/onu_device_entry.go
@@ -110,16 +110,17 @@
const (
// Events of interest to Device Adapters and OpenOMCI State Machines
- DeviceStatusInit OnuDeviceEvent = 0 // OnuDeviceEntry default start state
- MibDatabaseSync OnuDeviceEvent = 1 // MIB database sync (upload done)
- OmciCapabilitiesDone OnuDeviceEvent = 2 // OMCI ME and message type capabilities known
- MibDownloadDone OnuDeviceEvent = 3 // MIB database sync (upload done)
- UniLockStateDone OnuDeviceEvent = 4 // Uni ports admin set to lock
- UniUnlockStateDone OnuDeviceEvent = 5 // Uni ports admin set to unlock
- UniAdminStateDone OnuDeviceEvent = 6 // Uni ports admin set done - general
- PortLinkUp OnuDeviceEvent = 7 // Port link state change
- PortLinkDw OnuDeviceEvent = 8 // Port link state change
- OmciAniConfigDone OnuDeviceEvent = 9 // AniSide config according to TechProfile done
+ DeviceStatusInit OnuDeviceEvent = 0 // OnuDeviceEntry default start state
+ MibDatabaseSync OnuDeviceEvent = 1 // MIB database sync (upload done)
+ OmciCapabilitiesDone OnuDeviceEvent = 2 // OMCI ME and message type capabilities known
+ MibDownloadDone OnuDeviceEvent = 3 // MIB database sync (upload done)
+ UniLockStateDone OnuDeviceEvent = 4 // Uni ports admin set to lock
+ UniUnlockStateDone OnuDeviceEvent = 5 // Uni ports admin set to unlock
+ UniAdminStateDone OnuDeviceEvent = 6 // Uni ports admin set done - general
+ PortLinkUp OnuDeviceEvent = 7 // Port link state change
+ PortLinkDw OnuDeviceEvent = 8 // Port link state change
+ OmciAniConfigDone OnuDeviceEvent = 9 // AniSide config according to TechProfile done
+ OmciVlanFilterDone OnuDeviceEvent = 10 // Omci Vlan config according to flowConfig done
// Add other events here as needed (alarms separate???)
)
diff --git a/internal/pkg/onuadaptercore/onu_uni_tp.go b/internal/pkg/onuadaptercore/onu_uni_tp.go
index 728cac8..a5a8ba4 100644
--- a/internal/pkg/onuadaptercore/onu_uni_tp.go
+++ b/internal/pkg/onuadaptercore/onu_uni_tp.go
@@ -67,8 +67,9 @@
}
type tTechProfileIndication struct {
- techProfileType string
- techProfileID uint16
+ techProfileType string
+ techProfileID uint16
+ techProfileConfigDone bool
}
type tcontParamStruct struct {
@@ -100,19 +101,21 @@
//OnuUniTechProf structure holds information about the TechProfiles attached to Uni Ports of the ONU
type OnuUniTechProf struct {
- deviceID string
- baseDeviceHandler *DeviceHandler
- tpProcMutex sync.RWMutex
- mapUniTpPath map[uint32]string
- sOnuPersistentData onuPersistentData
- techProfileKVStore *db.Backend
- onuKVStore *db.Backend
- onuKVStorePath string
- chTpProcessingStep chan uint8
- mapUniTpIndication map[uint32]*tTechProfileIndication //use pointer values to ease assignments to the map
- mapPonAniConfig map[uint32]*tMapPonAniConfig //per UNI: use pointer values to ease assignments to the map
- pAniConfigFsm *UniPonAniConfigFsm
- procResult error //error indication of processing
+ deviceID string
+ baseDeviceHandler *DeviceHandler
+ tpProcMutex sync.RWMutex
+ mapUniTpPath map[uint32]string
+ sOnuPersistentData onuPersistentData
+ techProfileKVStore *db.Backend
+ onuKVStore *db.Backend
+ onuKVStorePath string
+ chTpConfigProcessingStep chan uint8
+ chTpKvProcessingStep chan uint8
+ mapUniTpIndication map[uint8]*tTechProfileIndication //use pointer values to ease assignments to the map
+ mapPonAniConfig map[uint8]*tMapPonAniConfig //per UNI: use pointer values to ease assignments to the map
+ pAniConfigFsm *UniPonAniConfigFsm
+ procResult error //error indication of processing
+ mutexTPState sync.Mutex
}
//NewOnuUniTechProf returns the instance of a OnuUniTechProf
@@ -125,9 +128,10 @@
onuTP.tpProcMutex = sync.RWMutex{}
onuTP.mapUniTpPath = make(map[uint32]string)
onuTP.sOnuPersistentData.PersUniTpPath = make([]uniPersData, 1)
- onuTP.chTpProcessingStep = make(chan uint8)
- onuTP.mapUniTpIndication = make(map[uint32]*tTechProfileIndication)
- onuTP.mapPonAniConfig = make(map[uint32]*tMapPonAniConfig)
+ onuTP.chTpConfigProcessingStep = make(chan uint8)
+ onuTP.chTpKvProcessingStep = make(chan uint8)
+ onuTP.mapUniTpIndication = make(map[uint8]*tTechProfileIndication)
+ onuTP.mapPonAniConfig = make(map[uint8]*tMapPonAniConfig)
onuTP.procResult = nil //default assumption processing done with success
onuTP.techProfileKVStore = aDeviceHandler.SetBackend(cBasePathTechProfileKVStore)
@@ -214,9 +218,9 @@
// configureUniTp checks existing tp resources to delete and starts the corresponding OMCI configuation of the UNI port
// all possibly blocking processing must be run in background to allow for deadline supervision!
// but take care on sequential background processing when needed (logical dependencies)
-// use waitForTimeoutOrCompletion(ctx, processingStep) for internal synchronisation
+// use waitForTimeoutOrCompletion(ctx, chTpConfigProcessingStep, processingStep) for internal synchronisation
func (onuTP *OnuUniTechProf) configureUniTp(ctx context.Context,
- aUniID uint32, aPathString string, wg *sync.WaitGroup) {
+ aUniID uint8, aPathString string, wg *sync.WaitGroup) {
defer wg.Done() //always decrement the waitGroup on return
logger.Debugw("configure the Uni according to TpPath", log.Fields{
"device-id": onuTP.deviceID, "uniID": aUniID, "path": aPathString})
@@ -243,7 +247,7 @@
return
}
- var processingStep uint8 = 1 // used to synchronize the different processing steps with chTpProcessingStep
+ var processingStep uint8 = 1 // used to synchronize the different processing steps with chTpConfigProcessingStep
//according to updateOnuUniTpPath() logic the assumption here is, that this configuration is only called
// in case the KVPath has changed for the given UNI,
@@ -254,7 +258,7 @@
//TODO!!!:
/* if tcontMap not empty {
go onuTP.deleteAniSideConfig(ctx, aUniID, processingStep)
- if !onuTP.waitForTimeoutOrCompletion(ctx, processingStep) {
+ if !onuTP.waitForTimeoutOrCompletion(ctx, chTpConfigProcessingStep, processingStep) {
//timeout or error detected
return
}
@@ -264,7 +268,7 @@
processingStep++
*/
go onuTP.readAniSideConfigFromTechProfile(ctx, aUniID, aPathString, processingStep)
- if !onuTP.waitForTimeoutOrCompletion(ctx, processingStep) {
+ if !onuTP.waitForTimeoutOrCompletion(ctx, onuTP.chTpConfigProcessingStep, processingStep) {
//timeout or error detected
logger.Debugw("tech-profile related configuration aborted on read",
log.Fields{"device-id": onuTP.deviceID, "UniId": aUniID})
@@ -277,7 +281,7 @@
if _, existTG := (*valuePA)[0]; existTG {
//Config data for this uni and and at least TCont Index 0 exist
go onuTP.setAniSideConfigFromTechProfile(ctx, aUniID, pCurrentUniPort, processingStep)
- if !onuTP.waitForTimeoutOrCompletion(ctx, processingStep) {
+ if !onuTP.waitForTimeoutOrCompletion(ctx, onuTP.chTpConfigProcessingStep, processingStep) {
//timeout or error detected
logger.Debugw("tech-profile related configuration aborted on set",
log.Fields{"device-id": onuTP.deviceID, "UniId": aUniID})
@@ -311,9 +315,9 @@
onuTP.procResult = errors.New("ONU/TP-data update aborted: onuKVStore not set")
return
}
- var processingStep uint8 = 1 // used to synchronize the different processing steps with chTpProcessingStep
+ var processingStep uint8 = 1 // used to synchronize the different processing steps with chTpKvProcessingStep
go onuTP.storePersistentData(ctx, processingStep)
- if !onuTP.waitForTimeoutOrCompletion(ctx, processingStep) {
+ if !onuTP.waitForTimeoutOrCompletion(ctx, onuTP.chTpKvProcessingStep, processingStep) {
//timeout or error detected
logger.Debugw("ONU/TP-data not written - abort", log.Fields{"device-id": onuTP.deviceID})
onuTP.procResult = errors.New("ONU/TP-data update aborted: during writing process")
@@ -355,9 +359,9 @@
//TODO!!!
//delete the given resource from ONU OMCI config and data base - as background routine
/*
- var processingStep uint8 = 1 // used to synchronize the different processing steps with chTpProcessingStep
+ var processingStep uint8 = 1 // used to synchronize the different processing steps with chTpConfigProcessingStep
go onuTp.deleteAniResource(ctx, processingStep)
- if !onuTP.waitForTimeoutOrCompletion(ctx, processingStep) {
+ if !onuTP.waitForTimeoutOrCompletion(ctx, chTpConfigProcessingStep, processingStep) {
//timeout or error detected
return
}
@@ -387,16 +391,16 @@
if err != nil {
logger.Errorw("unable to marshal ONU/TP-data", log.Fields{"onuTP.sOnuPersistentData": onuTP.sOnuPersistentData,
"device-id": onuTP.deviceID, "err": err})
- onuTP.chTpProcessingStep <- 0 //error indication
+ onuTP.chTpKvProcessingStep <- 0 //error indication
return
}
err = onuTP.onuKVStore.Put(ctx, onuTP.onuKVStorePath, Value)
if err != nil {
logger.Errorw("unable to write ONU/TP-data into KVstore", log.Fields{"device-id": onuTP.deviceID, "err": err})
- onuTP.chTpProcessingStep <- 0 //error indication
+ onuTP.chTpKvProcessingStep <- 0 //error indication
return
}
- onuTP.chTpProcessingStep <- aProcessingStep //done
+ onuTP.chTpKvProcessingStep <- aProcessingStep //done
}
func (onuTP *OnuUniTechProf) restorePersistentData(ctx context.Context) error {
@@ -446,7 +450,7 @@
}
func (onuTP *OnuUniTechProf) readAniSideConfigFromTechProfile(
- ctx context.Context, aUniID uint32, aPathString string, aProcessingStep uint8) {
+ ctx context.Context, aUniID uint8, aPathString string, aProcessingStep uint8) {
var tpInst tp.TechProfile
//store profile type and identifier for later usage within the OMCI identifier and possibly ME setup
@@ -455,7 +459,7 @@
if len(subStringSlice) <= 2 {
logger.Errorw("invalid path name format",
log.Fields{"path": aPathString, "device-id": onuTP.deviceID})
- onuTP.chTpProcessingStep <- 0 //error indication
+ onuTP.chTpConfigProcessingStep <- 0 //error indication
return
}
@@ -483,7 +487,7 @@
if err != nil {
logger.Errorw("invalid ProfileId from path",
log.Fields{"ParseErr": err})
- onuTP.chTpProcessingStep <- 0 //error indication
+ onuTP.chTpConfigProcessingStep <- 0 //error indication
return
}
@@ -504,7 +508,7 @@
if err = json.Unmarshal(tpTmpBytes, &tpInst); err != nil {
logger.Errorw("TechProf - Failed to unmarshal tech-profile into tpInst",
log.Fields{"error": err, "device-id": onuTP.deviceID})
- onuTP.chTpProcessingStep <- 0 //error indication
+ onuTP.chTpConfigProcessingStep <- 0 //error indication
return
}
logger.Debugw("TechProf - tpInst", log.Fields{"tpInst": tpInst})
@@ -515,13 +519,13 @@
} else {
logger.Errorw("No tech-profile found",
log.Fields{"path": aPathString, "device-id": onuTP.deviceID})
- onuTP.chTpProcessingStep <- 0 //error indication
+ onuTP.chTpConfigProcessingStep <- 0 //error indication
return
}
} else {
logger.Errorw("kvstore-get failed for path",
log.Fields{"path": aPathString, "device-id": onuTP.deviceID})
- onuTP.chTpProcessingStep <- 0 //error indication
+ onuTP.chTpConfigProcessingStep <- 0 //error indication
return
}
@@ -569,7 +573,7 @@
log.Fields{"device-id": onuTP.deviceID, "index": pos, "PrioQueue": content.PriorityQueue})
//remove PonAniConfig as done so far, delete map should be safe, even if not existing
delete(onuTP.mapPonAniConfig, aUniID)
- onuTP.chTpProcessingStep <- 0 //error indication
+ onuTP.chTpConfigProcessingStep <- 0 //error indication
return
}
(*(onuTP.mapPonAniConfig[aUniID]))[0].mapGemPortParams[uint16(pos)].prioQueueIndex =
@@ -594,7 +598,7 @@
log.Fields{"path": aPathString, "device-id": onuTP.deviceID})
//remove PonAniConfig as done so far, delete map should be safe, even if not existing
delete(onuTP.mapPonAniConfig, aUniID)
- onuTP.chTpProcessingStep <- 0 //error indication
+ onuTP.chTpConfigProcessingStep <- 0 //error indication
return
}
//TODO!! MC (downstream) GemPorts can be set using DownstreamGemPortAttributeList seperately
@@ -610,15 +614,15 @@
"QueueScheduling": gemEntry.queueSchedPolicy})
}
- onuTP.chTpProcessingStep <- aProcessingStep //done
+ onuTP.chTpConfigProcessingStep <- aProcessingStep //done
}
func (onuTP *OnuUniTechProf) setAniSideConfigFromTechProfile(
- ctx context.Context, aUniID uint32, apCurrentUniPort *OnuUniPort, aProcessingStep uint8) {
+ ctx context.Context, aUniID uint8, apCurrentUniPort *OnuUniPort, aProcessingStep uint8) {
//OMCI transfer of ANI data acc. to mapPonAniConfig
// also the FSM's are running in background,
- // hence we have to make sure they indicate 'success' success on chTpProcessingStep with aProcessingStep
+ // hence we have to make sure they indicate 'success' success on chTpConfigProcessingStep with aProcessingStep
if onuTP.pAniConfigFsm == nil {
onuTP.createAniConfigFsm(aUniID, apCurrentUniPort, OmciAniConfigDone, aProcessingStep)
} else { //AniConfigFsm already init
@@ -627,13 +631,13 @@
}
func (onuTP *OnuUniTechProf) waitForTimeoutOrCompletion(
- ctx context.Context, aProcessingStep uint8) bool {
+ ctx context.Context, aChTpProcessingStep <-chan uint8, aProcessingStep uint8) bool {
select {
case <-ctx.Done():
logger.Warnw("processing not completed in-time: force release of TpProcMutex!",
log.Fields{"device-id": onuTP.deviceID, "error": ctx.Err()})
return false
- case rxStep := <-onuTP.chTpProcessingStep:
+ case rxStep := <-aChTpProcessingStep:
if rxStep == aProcessingStep {
return true
}
@@ -646,7 +650,7 @@
}
// createUniLockFsm initialises and runs the AniConfig FSM to transfer the OMCI related commands for ANI side configuration
-func (onuTP *OnuUniTechProf) createAniConfigFsm(aUniID uint32,
+func (onuTP *OnuUniTechProf) createAniConfigFsm(aUniID uint8,
apCurrentUniPort *OnuUniPort, devEvent OnuDeviceEvent, aProcessingStep uint8) {
logger.Debugw("createAniConfigFsm", log.Fields{"device-id": onuTP.deviceID})
chAniConfigFsm := make(chan Message, 2048)
@@ -676,7 +680,7 @@
if pACStatemachine != nil {
if pACStatemachine.Is(aniStDisabled) {
//FSM init requirement to get informed abou FSM completion! (otherwise timeout of the TechProf config)
- onuTP.pAniConfigFsm.SetFsmCompleteChannel(onuTP.chTpProcessingStep, aProcessingStep)
+ onuTP.pAniConfigFsm.SetFsmCompleteChannel(onuTP.chTpConfigProcessingStep, aProcessingStep)
if err := pACStatemachine.Event(aniEvStart); err != nil {
logger.Warnw("AniConfigFSM: can't start", log.Fields{"err": err})
// maybe try a FSM reset and then again ... - TODO!!!
@@ -695,3 +699,25 @@
// maybe try a FSM reset and then again ... - TODO!!!
}
}
+
+// setConfigDone sets the requested techProfile config state (if possible)
+func (onuTP *OnuUniTechProf) setConfigDone(aUniID uint8, aState bool) {
+ if _, existTP := onuTP.mapUniTpIndication[aUniID]; existTP {
+ onuTP.mutexTPState.Lock()
+ onuTP.mapUniTpIndication[aUniID].techProfileConfigDone = aState
+ onuTP.mutexTPState.Unlock()
+ } //else: the state is just ignored (does not exist)
+}
+
+// getTechProfileDone checks if the Techprofile processing with the requested TechProfile ID was done
+func (onuTP *OnuUniTechProf) getTechProfileDone(aUniID uint8, aTpID uint16) bool {
+ if _, existTP := onuTP.mapUniTpIndication[aUniID]; existTP {
+ if onuTP.mapUniTpIndication[aUniID].techProfileID == aTpID {
+ onuTP.mutexTPState.Lock()
+ defer onuTP.mutexTPState.Unlock()
+ return onuTP.mapUniTpIndication[aUniID].techProfileConfigDone
+ }
+ }
+ //for all other constellations indicate false = Config not done
+ return false
+}
diff --git a/internal/pkg/onuadaptercore/openonu.go b/internal/pkg/onuadaptercore/openonu.go
index 5dcf108..c9d4b37 100644
--- a/internal/pkg/onuadaptercore/openonu.go
+++ b/internal/pkg/onuadaptercore/openonu.go
@@ -52,6 +52,7 @@
exitChannel chan int
HeartbeatCheckInterval time.Duration
HeartbeatFailReportInterval time.Duration
+ AcceptIncrementalEvto bool
//GrpcTimeoutInterval time.Duration
lockDeviceHandlersMap sync.RWMutex
pSupportedFsms *OmciDeviceFsms
@@ -77,6 +78,7 @@
openOnuAc.KVStoreTimeout = cfg.KVStoreTimeout
openOnuAc.HeartbeatCheckInterval = cfg.HeartbeatCheckInterval
openOnuAc.HeartbeatFailReportInterval = cfg.HeartbeatFailReportInterval
+ openOnuAc.AcceptIncrementalEvto = cfg.AccIncrEvto
//openOnuAc.GrpcTimeoutInterval = cfg.GrpcTimeoutInterval
openOnuAc.lockDeviceHandlersMap = sync.RWMutex{}
@@ -304,10 +306,32 @@
}
//Update_flows_incrementally updates (add/remove) the flows on a given device
-func (oo *OpenONUAC) Update_flows_incrementally(device *voltha.Device, flows *openflow_13.FlowChanges, groups *openflow_13.FlowGroupChanges, flowMetadata *voltha.FlowMetadata) error {
- // return errors.New("unImplemented")
- // testwise: just acknowledge to see, if that avoids ongoing TechProfile config sequences ...
- return nil
+func (oo *OpenONUAC) Update_flows_incrementally(device *voltha.Device,
+ flows *openflow_13.FlowChanges, groups *openflow_13.FlowGroupChanges, flowMetadata *voltha.FlowMetadata) error {
+ // no point in pushing omci flows if the device isn't reachable
+ if device.ConnectStatus != voltha.ConnectStatus_REACHABLE ||
+ device.AdminState != voltha.AdminState_ENABLED {
+ logger.Warnw("device disabled or offline - skipping flow-update", log.Fields{"deviceId": device.Id})
+ return errors.New("non-matching device state")
+ }
+
+ // For now, there is no support for group changes (as in the actual Py-adapter code)
+ if groups.ToAdd != nil && groups.ToAdd.Items != nil {
+ logger.Debugw("Update-flow-incr: group add not supported (ignored)", log.Fields{"deviceId": device.Id})
+ }
+ if groups.ToRemove != nil && groups.ToRemove.Items != nil {
+ logger.Debugw("Update-flow-incr: group remove not supported (ignored)", log.Fields{"deviceId": device.Id})
+ }
+ if groups.ToUpdate != nil && groups.ToUpdate.Items != nil {
+ logger.Debugw("Update-flow-incr: group update not supported (ignored)", log.Fields{"deviceId": device.Id})
+ }
+
+ if handler := oo.getDeviceHandler(device.Id); handler != nil {
+ err := handler.FlowUpdateIncremental(flows, groups, flowMetadata)
+ return err
+ }
+ logger.Warnw("no handler found for incremental flow update", log.Fields{"deviceId": device.Id})
+ return fmt.Errorf(fmt.Sprintf("handler-not-found-%s", device.Id))
}
//Update_pm_config returns PmConfigs nil or error