Enhancements to AT&T workflow

- Add DHCP IPV6 flow in upstream trap flow
- Add DHCP IPV6 NNI trap flow and LLDP NNI trap flow

Change-Id: Iae13aff7e5990ae3662ccea1e308b5a1efae9724
diff --git a/core/att_workflow.go b/core/att_workflow.go
index 0bc0f69..4417c27 100644
--- a/core/att_workflow.go
+++ b/core/att_workflow.go
@@ -37,8 +37,7 @@
 type AttWorkFlow struct {
 }
 
-func ProvisionAttNniTrapFlow(oo oop.OpenoltClient, config *config.OpenOltScaleTesterConfig,
-	rsrMgr *OpenOltResourceMgr) error {
+func AddDhcpIPV4Flow(oo oop.OpenoltClient, config *config.OpenOltScaleTesterConfig, rsrMgr *OpenOltResourceMgr) error {
 	var flowID []uint32
 	var err error
 
@@ -47,6 +46,7 @@
 		return err
 	}
 
+	// DHCP IPV4
 	flowClassifier := &oop.Classifier{EthType: 2048, IpProto: 17, SrcPort: 67, DstPort: 68, PktTagType: "double_tag"}
 	actionCmd := &oop.ActionCmd{TrapToHost: true}
 	actionInfo := &oop.Action{Cmd: actionCmd}
@@ -54,7 +54,7 @@
 	flow := oop.Flow{AccessIntfId: -1, OnuId: -1, UniId: -1, FlowId: flowID[0],
 		FlowType: "downstream", AllocId: -1, GemportId: -1,
 		Classifier: flowClassifier, Action: actionInfo,
-		Priority: 1000, PortNo: 65536}
+		Priority: 1000, PortNo: uint32(config.NniIntfID)}
 
 	_, err = oo.FlowAdd(context.Background(), &flow)
 
@@ -65,12 +65,96 @@
 	}
 
 	if err != nil {
-		log.Errorw("Failed to Add flow to device", log.Fields{"err": err, "deviceFlow": flow})
+		log.Errorw("Failed to Add DHCP IPv4 to device", log.Fields{"err": err, "deviceFlow": flow})
 		rsrMgr.ResourceMgrs[uint32(config.NniIntfID)].FreeResourceID(uint32(config.NniIntfID),
 			ponresourcemanager.FLOW_ID, flowID)
 		return err
 	}
-	log.Debugw("Flow added to device successfully ", log.Fields{"flow": flow})
+	log.Debugw("DHCP IPV4 added to device successfully ", log.Fields{"flow": flow})
+
+	return nil
+}
+
+func AddDhcpIPV6Flow(oo oop.OpenoltClient, config *config.OpenOltScaleTesterConfig, rsrMgr *OpenOltResourceMgr) error {
+	var flowID []uint32
+	var err error
+
+	if flowID, err = rsrMgr.ResourceMgrs[uint32(config.NniIntfID)].GetResourceID(uint32(config.NniIntfID),
+		ponresourcemanager.FLOW_ID, 1); err != nil {
+		return err
+	}
+
+	// DHCP IPV6
+	flowClassifier := &oop.Classifier{EthType: 34525, IpProto: 17, SrcPort: 546, DstPort: 547, PktTagType: "double_tag"}
+	actionCmd := &oop.ActionCmd{TrapToHost: true}
+	actionInfo := &oop.Action{Cmd: actionCmd}
+
+	flow := oop.Flow{AccessIntfId: -1, OnuId: -1, UniId: -1, FlowId: flowID[0],
+		FlowType: "downstream", AllocId: -1, GemportId: -1,
+		Classifier: flowClassifier, Action: actionInfo,
+		Priority: 1000, PortNo: uint32(config.NniIntfID)}
+
+	_, err = oo.FlowAdd(context.Background(), &flow)
+
+	st, _ := status.FromError(err)
+	if st.Code() == codes.AlreadyExists {
+		log.Debugw("Flow already exists", log.Fields{"err": err, "deviceFlow": flow})
+		return nil
+	}
+
+	if err != nil {
+		log.Errorw("Failed to Add DHCP IPV6 to device", log.Fields{"err": err, "deviceFlow": flow})
+		rsrMgr.ResourceMgrs[uint32(config.NniIntfID)].FreeResourceID(uint32(config.NniIntfID),
+			ponresourcemanager.FLOW_ID, flowID)
+		return err
+	}
+	log.Debugw("DHCP IPV6 added to device successfully ", log.Fields{"flow": flow})
+
+	return nil
+}
+
+func AddLldpFlow(oo oop.OpenoltClient, config *config.OpenOltScaleTesterConfig, rsrMgr *OpenOltResourceMgr) error {
+	var flowID []uint32
+	var err error
+
+	if flowID, err = rsrMgr.ResourceMgrs[uint32(config.NniIntfID)].GetResourceID(uint32(config.NniIntfID),
+		ponresourcemanager.FLOW_ID, 1); err != nil {
+		return err
+	}
+
+	// DHCP IPV4
+	flowClassifier := &oop.Classifier{EthType: 35020, PktTagType: "untagged"}
+	actionCmd := &oop.ActionCmd{TrapToHost: true}
+	actionInfo := &oop.Action{Cmd: actionCmd}
+
+	flow := oop.Flow{AccessIntfId: -1, OnuId: -1, UniId: -1, FlowId: flowID[0],
+		FlowType: "downstream", AllocId: -1, GemportId: -1,
+		Classifier: flowClassifier, Action: actionInfo,
+		Priority: 1000, PortNo: uint32(config.NniIntfID)}
+
+	_, err = oo.FlowAdd(context.Background(), &flow)
+
+	st, _ := status.FromError(err)
+	if st.Code() == codes.AlreadyExists {
+		log.Debugw("Flow already exists", log.Fields{"err": err, "deviceFlow": flow})
+		return nil
+	}
+
+	if err != nil {
+		log.Errorw("Failed to Add LLDP flow to device", log.Fields{"err": err, "deviceFlow": flow})
+		rsrMgr.ResourceMgrs[uint32(config.NniIntfID)].FreeResourceID(uint32(config.NniIntfID),
+			ponresourcemanager.FLOW_ID, flowID)
+		return err
+	}
+	log.Debugw("LLDP flow added to device successfully ", log.Fields{"flow": flow})
+
+	return nil
+}
+
+func ProvisionAttNniTrapFlow(oo oop.OpenoltClient, config *config.OpenOltScaleTesterConfig, rsrMgr *OpenOltResourceMgr) error {
+	_ = AddDhcpIPV4Flow(oo, config, rsrMgr)
+	_ = AddDhcpIPV6Flow(oo, config, rsrMgr)
+	_ = AddLldpFlow(oo, config, rsrMgr)
 
 	return nil
 }
@@ -179,7 +263,7 @@
 	return nil
 }
 
-func (att AttWorkFlow) ProvisionDhcpFlow(subs *Subscriber) error {
+func (att AttWorkFlow) ProvisionDhcpIPV4Flow(subs *Subscriber) error {
 	var err error
 	var flowID []uint32
 	var gemPortIDs []uint32
@@ -194,7 +278,32 @@
 			ponresourcemanager.FLOW_ID, 1); err != nil {
 			return errors.New(ReasonCodeToReasonString(FLOW_ID_GENERATION_FAILED))
 		} else {
-			if err := AddFlow(subs, DhcpFlow, Upstream, flowID[0], allocID, gemID); err != nil {
+			if err := AddFlow(subs, DhcpFlowIPV4, Upstream, flowID[0], allocID, gemID); err != nil {
+				subs.RsrMgr.ResourceMgrs[uint32(subs.PonIntf)].FreeResourceID(uint32(subs.PonIntf),
+					ponresourcemanager.FLOW_ID, flowID)
+				return err
+			}
+		}
+	}
+	return nil
+}
+
+func (att AttWorkFlow) ProvisionDhcpIPV6Flow(subs *Subscriber) error {
+	var err error
+	var flowID []uint32
+	var gemPortIDs []uint32
+
+	var allocID = subs.TpInstance[subs.TestConfig.TpIDList[0]].UsScheduler.AllocID
+	for _, gem := range subs.TpInstance[subs.TestConfig.TpIDList[0]].UpstreamGemPortAttributeList {
+		gemPortIDs = append(gemPortIDs, gem.GemportID)
+	}
+
+	for _, gemID := range gemPortIDs {
+		if flowID, err = subs.RsrMgr.ResourceMgrs[uint32(subs.PonIntf)].GetResourceID(uint32(subs.PonIntf),
+			ponresourcemanager.FLOW_ID, 1); err != nil {
+			return errors.New(ReasonCodeToReasonString(FLOW_ID_GENERATION_FAILED))
+		} else {
+			if err := AddFlow(subs, DhcpFlowIPV6, Upstream, flowID[0], allocID, gemID); err != nil {
 				subs.RsrMgr.ResourceMgrs[uint32(subs.PonIntf)].FreeResourceID(uint32(subs.PonIntf),
 					ponresourcemanager.FLOW_ID, flowID)
 				return err
@@ -224,13 +333,24 @@
 			ponresourcemanager.FLOW_ID, 1); err != nil {
 			return errors.New(ReasonCodeToReasonString(FLOW_ID_GENERATION_FAILED))
 		} else {
-			if err := AddFlow(subs, HsiaFlow, Upstream, flowID[0], allocID, gemID); err != nil {
+			var errUs, errDs error
+			if errUs = AddFlow(subs, HsiaFlow, Upstream, flowID[0], allocID, gemID); errUs != nil {
+				log.Errorw("failed to install US HSIA flow",
+					log.Fields{"onuID": subs.OnuID, "uniID": subs.UniID, "intf": subs.PonIntf})
+			}
+			if errDs = AddFlow(subs, HsiaFlow, Downstream, flowID[0], allocID, gemID); errDs != nil {
+				log.Errorw("failed to install US HSIA flow",
+					log.Fields{"onuID": subs.OnuID, "uniID": subs.UniID, "intf": subs.PonIntf})
+			}
+			if errUs != nil && errDs != nil {
 				subs.RsrMgr.ResourceMgrs[uint32(subs.PonIntf)].FreeResourceID(uint32(subs.PonIntf),
 					ponresourcemanager.FLOW_ID, flowID)
-				return err
 			}
-			if err := AddFlow(subs, HsiaFlow, Downstream, flowID[0], allocID, gemID); err != nil {
-				return err
+			if errUs != nil || errDs != nil {
+				if errUs != nil {
+					return errUs
+				}
+				return errDs
 			}
 		}
 	}
diff --git a/core/dt_workflow.go b/core/dt_workflow.go
index 2b06b71..46608ee 100644
--- a/core/dt_workflow.go
+++ b/core/dt_workflow.go
@@ -117,8 +117,13 @@
 	return nil
 }
 
-func (dt DtWorkFlow) ProvisionDhcpFlow(subs *Subscriber) error {
-	log.Info("dt-workflow-does-not-require-dhcp-support--nothing-to-do")
+func (dt DtWorkFlow) ProvisionDhcpIPV4Flow(subs *Subscriber) error {
+	log.Info("dt-workflow-does-not-require-dhcp-ipv4-support--nothing-to-do")
+	return nil
+}
+
+func (dt DtWorkFlow) ProvisionDhcpIPV6Flow(subs *Subscriber) error {
+	log.Info("dt-workflow-does-not-require-dhcp-ipv6-support--nothing-to-do")
 	return nil
 }
 
diff --git a/core/workflow_manager.go b/core/workflow_manager.go
index 95233c1..7a6860d 100644
--- a/core/workflow_manager.go
+++ b/core/workflow_manager.go
@@ -31,7 +31,8 @@
 	ProvisionScheds(subs *Subscriber) error
 	ProvisionQueues(subs *Subscriber) error
 	ProvisionEapFlow(subs *Subscriber) error
-	ProvisionDhcpFlow(subs *Subscriber) error
+	ProvisionDhcpIPV4Flow(subs *Subscriber) error
+	ProvisionDhcpIPV6Flow(subs *Subscriber) error
 	ProvisionIgmpFlow(subs *Subscriber) error
 	ProvisionHsiaFlow(subs *Subscriber) error
 	// TODO: Add new items here as needed.
@@ -56,7 +57,12 @@
 		return
 	}
 
-	if err := wf.ProvisionDhcpFlow(subs); err != nil {
+	if err := wf.ProvisionDhcpIPV4Flow(subs); err != nil {
+		subs.Reason = err.Error()
+		return
+	}
+
+	if err := wf.ProvisionDhcpIPV6Flow(subs); err != nil {
 		subs.Reason = err.Error()
 		return
 	}
diff --git a/core/workflow_utils.go b/core/workflow_utils.go
index d4d16f9..e078e6d 100644
--- a/core/workflow_utils.go
+++ b/core/workflow_utils.go
@@ -28,15 +28,22 @@
 )
 
 const (
-	//Constants utilised while forming HSIA Flow
-	HsiaFlow                 = "HSIA_FLOW"
-
-	//Constants utilised while forming DHCP Flow
-	DhcpFlow    = "DHCP_FLOW"
-	IPv4EthType = 0x800 //2048
 	DhcpIPProto = 17
-	DhcpSrcPort = 68
-	DhcpDstPort = 67
+
+	//Constants utilised while forming HSIA Flow
+	HsiaFlow = "HSIA_FLOW"
+
+	//Constants utilised while forming DHCP IPV4 Flow
+	DhcpFlowIPV4    = "DHCP_FLOW_IPV4"
+	IPv4EthType     = 0x800 //2048
+	DhcpSrcPortIPV4 = 68
+	DhcpDstPortIPV4 = 67
+
+	//Constants utilised while forming DHCP IPV6 Flow
+	DhcpFlowIPV6    = "DHCP_FLOW_IPV6"
+	IPv6EthType     = 0x86dd //34525
+	DhcpSrcPortIPV6 = 547
+	DhcpDstPortIPV6 = 546
 
 	//Constants utilised while forming EAPOL Flow
 	EapolFlow  = "EAPOL_FLOW"
@@ -102,11 +109,19 @@
 			flowClassifier.PktTagType = SingleTag
 			actionCmd.TrapToHost = true
 			actionInfo.Cmd = &actionCmd
-		case DhcpFlow:
+		case DhcpFlowIPV4:
 			flowClassifier.EthType = IPv4EthType
 			flowClassifier.IpProto = DhcpIPProto
-			flowClassifier.SrcPort = DhcpSrcPort
-			flowClassifier.DstPort = DhcpDstPort
+			flowClassifier.SrcPort = DhcpSrcPortIPV4
+			flowClassifier.DstPort = DhcpDstPortIPV4
+			flowClassifier.PktTagType = SingleTag
+			actionCmd.TrapToHost = true
+			actionInfo.Cmd = &actionCmd
+		case DhcpFlowIPV6:
+			flowClassifier.EthType = IPv6EthType
+			flowClassifier.IpProto = DhcpIPProto
+			flowClassifier.SrcPort = DhcpSrcPortIPV6
+			flowClassifier.DstPort = DhcpDstPortIPV6
 			flowClassifier.PktTagType = SingleTag
 			actionCmd.TrapToHost = true
 			actionInfo.Cmd = &actionCmd
@@ -126,8 +141,12 @@
 			log.Errorw("Downstream EAP flows are not required instead controller "+
 				"packet outs EAP response directly to onu in downstream", log.Fields{"flowtype": flowType,
 				"direction": direction})
-		case DhcpFlow:
-			log.Errorw("Downstream DHCP flows are not required instead we have "+
+		case DhcpFlowIPV4:
+			log.Errorw("Downstream DHCPIPV4 flows are not required instead we have "+
+				"NNI trap flows already installed", log.Fields{"flowtype": flowType,
+				"direction": direction})
+		case DhcpFlowIPV6:
+			log.Errorw("Downstream DHCPIPV6 flows are not required instead we have "+
 				"NNI trap flows already installed", log.Fields{"flowtype": flowType,
 				"direction": direction})
 		case HsiaFlow: