[VOL-4478] OLT adapter should rollback itself from a failure, and leave a clean environment for a possible retry or reprovisioning.
Change-Id: I98b16be6b7901dd8c7240656098dc352fe14009b
diff --git a/internal/pkg/core/openolt_flowmgr.go b/internal/pkg/core/openolt_flowmgr.go
index 7c3681e..1f65744 100644
--- a/internal/pkg/core/openolt_flowmgr.go
+++ b/internal/pkg/core/openolt_flowmgr.go
@@ -548,11 +548,16 @@
log.Fields{"direction": sq.direction,
"traffic-queues": trafficQueues,
"device-id": f.deviceHandler.device.Id})
- if _, err := f.deviceHandler.Client.CreateTrafficQueues(ctx,
- &tp_pb.TrafficQueues{IntfId: sq.intfID, OnuId: sq.onuID,
- UniId: sq.uniID, PortNo: sq.uniPort,
- TrafficQueues: trafficQueues,
- TechProfileId: TrafficSched[0].TechProfileId}); err != nil {
+ queues := &tp_pb.TrafficQueues{IntfId: sq.intfID, OnuId: sq.onuID,
+ UniId: sq.uniID, PortNo: sq.uniPort,
+ TrafficQueues: trafficQueues,
+ TechProfileId: TrafficSched[0].TechProfileId}
+ if _, err := f.deviceHandler.Client.CreateTrafficQueues(ctx, queues); err != nil {
+ if len(queues.TrafficQueues) > 1 {
+ logger.Debug(ctx, "removing-queues-for-1tcont-multi-gem", log.Fields{"intfID": sq.intfID, "onuID": sq.onuID, "dir": sq.direction})
+ _, _ = f.deviceHandler.Client.RemoveTrafficQueues(ctx, queues)
+ }
+ f.revertScheduler(ctx, sq, TrafficSched)
return olterrors.NewErrAdapter("failed-to-create-traffic-queues-in-device", log.Fields{"traffic-queues": trafficQueues}, err)
}
logger.Infow(ctx, "successfully-created-traffic-schedulers", log.Fields{
@@ -847,6 +852,7 @@
"intf-id": intfID,
"meter-id": UsMeterID,
"device-id": f.deviceHandler.device.Id})
+ f.revertTechProfileInstance(ctx, sq)
return 0, nil, nil
}
}
@@ -862,6 +868,7 @@
"intf-id": intfID,
"meter-id": DsMeterID,
"device-id": f.deviceHandler.device.Id})
+ f.revertTechProfileInstance(ctx, sq)
return 0, nil, nil
}
}
@@ -1904,7 +1911,7 @@
//clearResources clears pon resources in kv store and the device
// nolint: gocyclo
func (f *OpenOltFlowMgr) clearResources(ctx context.Context, intfID uint32, onuID int32, uniID int32,
- flowID uint64, portNum uint32, tpID uint32) error {
+ flowID uint64, portNum uint32, tpID uint32, sendDeleteGemRequest bool) error {
logger.Debugw(ctx, "clearing-resources", log.Fields{"intfID": intfID, "onuID": onuID, "uniID": uniID, "tpID": tpID})
@@ -2022,15 +2029,17 @@
f.resourceMgr.FreeGemPortID(ctx, intfID, uint32(onuID), uint32(uniID), gemPortID)
// Delete the gem port on the ONU.
- if err := f.sendDeleteGemPortToChild(ctx, intfID, uint32(onuID), uint32(uniID), gemPortID, tpPath); err != nil {
- logger.Errorw(ctx, "error-processing-delete-gem-port-towards-onu",
- log.Fields{
- "err": err,
- "intfID": intfID,
- "onu-id": onuID,
- "uni-id": uniID,
- "device-id": f.deviceHandler.device.Id,
- "gemport-id": gemPortID})
+ if sendDeleteGemRequest {
+ if err := f.sendDeleteGemPortToChild(ctx, intfID, uint32(onuID), uint32(uniID), gemPortID, tpPath); err != nil {
+ logger.Errorw(ctx, "error-processing-delete-gem-port-towards-onu",
+ log.Fields{
+ "err": err,
+ "intfID": intfID,
+ "onu-id": onuID,
+ "uni-id": uniID,
+ "device-id": f.deviceHandler.device.Id,
+ "gemport-id": gemPortID})
+ }
}
}
}
@@ -2132,7 +2141,7 @@
delete(f.flowIDToGems, flow.Id)
f.flowIDToGemsLock.Unlock()
- if err = f.clearResources(ctx, Intf, onuID, uniID, flow.Id, portNum, tpID); err != nil {
+ if err = f.clearResources(ctx, Intf, onuID, uniID, flow.Id, portNum, tpID, true); err != nil {
logger.Errorw(ctx, "failed-to-clear-resources-for-flow", log.Fields{
"flow-id": flow.Id,
"device-id": f.deviceHandler.device.Id,
@@ -2931,6 +2940,8 @@
//Adding DHCP upstream flow
if err := f.addDHCPTrapFlow(ctx, flowContext); err != nil {
logger.Warn(ctx, err)
+ logger.Errorw(ctx, "reverting-scheduler-and-queue-for-onu", log.Fields{"intf-id": intfID, "onu-id": onuID, "uni-id": uniID, "flow-id": flow.Id, "tp-id": tpID})
+ _ = f.clearResources(ctx, intfID, int32(onuID), int32(uniID), flow.Id, portNo, tpID, false)
return err
}
@@ -2943,6 +2954,8 @@
"classifier-info:": classifierInfo})
if err := f.addIGMPTrapFlow(ctx, flowContext); err != nil {
logger.Warn(ctx, err)
+ logger.Errorw(ctx, "reverting-scheduler-and-queue-for-onu", log.Fields{"intf-id": intfID, "onu-id": onuID, "uni-id": uniID, "flow-id": flow.Id, "tp-id": tpID})
+ _ = f.clearResources(ctx, intfID, int32(onuID), int32(uniID), flow.Id, portNo, tpID, false)
return err
}
} else {
@@ -2965,6 +2978,8 @@
}
if err := f.addEthTypeBasedFlow(ctx, flowContext, vlanID, ethType.(uint32)); err != nil {
logger.Warn(ctx, err)
+ logger.Errorw(ctx, "reverting-scheduler-and-queue-for-onu", log.Fields{"intf-id": intfID, "onu-id": onuID, "uni-id": uniID, "flow-id": flow.Id, "tp-id": tpID})
+ _ = f.clearResources(ctx, intfID, int32(onuID), int32(uniID), flow.Id, portNo, tpID, false)
return err
}
} else if ethType.(uint32) == PPPoEDEthType {
@@ -2978,6 +2993,8 @@
//Adding PPPOED upstream flow
if err := f.addUpstreamTrapFlow(ctx, flowContext); err != nil {
logger.Warn(ctx, err)
+ logger.Errorw(ctx, "reverting-scheduler-and-queue-for-onu", log.Fields{"intf-id": intfID, "onu-id": onuID, "uni-id": uniID, "flow-id": flow.Id, "tp-id": tpID})
+ _ = f.clearResources(ctx, intfID, int32(onuID), int32(uniID), flow.Id, portNo, tpID, false)
return err
}
}
@@ -2990,6 +3007,8 @@
//Adding HSIA upstream flow
if err := f.addUpstreamDataPathFlow(ctx, flowContext); err != nil {
logger.Warn(ctx, err)
+ logger.Errorw(ctx, "reverting-scheduler-and-queue-for-onu", log.Fields{"intf-id": intfID, "onu-id": onuID, "uni-id": uniID, "flow-id": flow.Id, "tp-id": tpID})
+ _ = f.clearResources(ctx, intfID, int32(onuID), int32(uniID), flow.Id, portNo, tpID, false)
return err
}
} else if direction == tp_pb.Direction_DOWNSTREAM {
@@ -3001,6 +3020,8 @@
//Adding HSIA downstream flow
if err := f.addDownstreamDataPathFlow(ctx, flowContext); err != nil {
logger.Warn(ctx, err)
+ logger.Errorw(ctx, "reverting-scheduler-and-queue-for-onu", log.Fields{"intf-id": intfID, "onu-id": onuID, "uni-id": uniID, "flow-id": flow.Id, "tp-id": tpID})
+ _ = f.clearResources(ctx, intfID, int32(onuID), int32(uniID), flow.Id, portNo, tpID, false)
return err
}
} else {
@@ -3452,3 +3473,49 @@
}
return onuGemInfoLst
}
+
+// revertTechProfileInstance is called when CreateScheduler or CreateQueues request fails
+func (f *OpenOltFlowMgr) revertTechProfileInstance(ctx context.Context, sq schedQueue) {
+
+ intfID := sq.intfID
+ onuID := sq.onuID
+ uniID := sq.uniID
+ tpID := sq.tpID
+
+ var reverseDirection string
+ if sq.direction == tp_pb.Direction_UPSTREAM {
+ reverseDirection = "downstream"
+ } else {
+ reverseDirection = "upstream"
+ }
+
+ // check reverse direction - if reverse meter exists, tech profile instance is in use - do not delete
+ if KvStoreMeter, _ := f.resourceMgr.GetMeterInfoForOnu(ctx, reverseDirection, intfID, onuID, uniID, tpID); KvStoreMeter != nil {
+ return
+ }
+
+ // revert-delete tech-profile instance and delete tech profile id for onu
+ logger.Warnw(ctx, "reverting-tech-profile-instance-and-tech-profile-id-for-onu", log.Fields{"intf-id": intfID, "onu-id": onuID, "uni-id": uniID, "tp-id": tpID})
+ uniPortName := getUniPortPath(f.deviceHandler.device.Id, intfID, int32(onuID), int32(uniID))
+ _ = f.DeleteTechProfileInstance(ctx, intfID, onuID, uniID, uniPortName, tpID)
+ _ = f.resourceMgr.RemoveTechProfileIDForOnu(ctx, intfID, onuID, uniID, tpID)
+
+ // free gem/alloc
+ switch techprofileInst := sq.tpInst.(type) {
+ case *tp_pb.TechProfileInstance:
+ for _, gem := range techprofileInst.UpstreamGemPortAttributeList {
+ f.resourceMgr.FreeGemPortID(ctx, intfID, onuID, uniID, gem.GemportId)
+ }
+ f.resourceMgr.FreeAllocID(ctx, intfID, onuID, uniID, techprofileInst.UsScheduler.AllocId)
+ }
+}
+
+// revertSchduler is called when CreateQueues request fails
+func (f *OpenOltFlowMgr) revertScheduler(ctx context.Context, sq schedQueue, TrafficSched []*tp_pb.TrafficScheduler) {
+ // revert scheduler
+ logger.Warnw(ctx, "reverting-scheduler-for-onu", log.Fields{"intf-id": sq.intfID, "onu-id": sq.onuID, "uni-id": sq.uniID, "tp-id": sq.tpID})
+ _, _ = f.deviceHandler.Client.RemoveTrafficSchedulers(ctx, &tp_pb.TrafficSchedulers{
+ IntfId: sq.intfID, OnuId: sq.onuID,
+ UniId: sq.uniID, PortNo: sq.uniPort,
+ TrafficScheds: TrafficSched})
+}