[VOL-3663] Supporting PPPoE trap rules olt adapter

Signed-off-by: Marcos Aurelio Carrero (Furukawa) <mcarrero@furukawalatam.com>
Change-Id: I0d96432493e25f3397f55730e04d35052aa148cf
diff --git a/internal/pkg/core/openolt_flowmgr.go b/internal/pkg/core/openolt_flowmgr.go
index 618a3f4..a9e2431 100644
--- a/internal/pkg/core/openolt_flowmgr.go
+++ b/internal/pkg/core/openolt_flowmgr.go
@@ -54,6 +54,8 @@
 	LldpEthType = 0x88cc
 	//IPv4EthType IPv4 ethernet type value
 	IPv4EthType = 0x800
+	//PPPoEDEthType PPPoE discovery ethernet type value
+	PPPoEDEthType = 0x8863
 
 	//ReservedVlan Transparent Vlan (Masked Vlan, VLAN_ANY in ONOS Flows)
 	ReservedVlan = 4096
@@ -1274,11 +1276,11 @@
 	return nil
 }
 
-// Add EAPOL flow to  device with mac, vlanId as classifier for upstream and downstream
-func (f *OpenOltFlowMgr) addEAPOLFlow(ctx context.Context, intfID uint32, onuID uint32, uniID uint32, portNo uint32,
+// Add EthType flow to  device with mac, vlanId as classifier for upstream and downstream
+func (f *OpenOltFlowMgr) addEthTypeBasedFlow(ctx context.Context, intfID uint32, onuID uint32, uniID uint32, portNo uint32,
 	classifier map[string]interface{}, action map[string]interface{}, logicalFlow *ofp.OfpFlowStats, allocID uint32,
-	gemPortID uint32, vlanID uint32, tpID uint32, pbitToGem map[uint32]uint32) error {
-	logger.Infow(ctx, "adding-eapol-to-device",
+	gemPortID uint32, vlanID uint32, tpID uint32, pbitToGem map[uint32]uint32, ethType uint32) error {
+	logger.Infow(ctx, "adding-ethType-flow-to-device",
 		log.Fields{
 			"intf-id":    intfID,
 			"onu-id":     onuID,
@@ -1286,13 +1288,14 @@
 			"alloc-id":   allocID,
 			"gemport-id": gemPortID,
 			"vlan-id":    vlanID,
-			"flow":       logicalFlow})
+			"flow":       logicalFlow,
+			"ethType":    ethType})
 
 	uplinkClassifier := make(map[string]interface{})
 	uplinkAction := make(map[string]interface{})
 
 	// Fill Classfier
-	uplinkClassifier[EthType] = uint32(EapEthType)
+	uplinkClassifier[EthType] = uint32(ethType)
 	uplinkClassifier[PacketTagType] = SingleTag
 	uplinkClassifier[VlanVid] = vlanID
 	uplinkClassifier[VlanPcp] = classifier[VlanPcp]
@@ -1302,11 +1305,12 @@
 		logger.Infow(ctx, "flow-exists-not-re-adding", log.Fields{
 			"device-id": f.deviceHandler.device.Id,
 			"onu-id":    onuID,
-			"intf-id":   intfID})
+			"intf-id":   intfID,
+			"ethType":   ethType})
 		return nil
 	}
-	//Add Uplink EAPOL Flow
-	logger.Debugw(ctx, "creating-ul-eapol-flow",
+	//Add Uplink EthType Flow
+	logger.Debugw(ctx, "creating-ul-ethType-flow",
 		log.Fields{
 			"ul_classifier": uplinkClassifier,
 			"ul_action":     uplinkAction,
@@ -1362,11 +1366,12 @@
 	if err := f.addFlowToDevice(ctx, logicalFlow, &upstreamFlow); err != nil {
 		return olterrors.NewErrFlowOp("add", logicalFlow.Id, log.Fields{"flow": upstreamFlow}, err).Log()
 	}
-	logger.Infow(ctx, "eapol-ul-flow-added-to-device-successfully",
+	logger.Infow(ctx, "ethType-ul-flow-added-to-device-successfully",
 		log.Fields{
 			"device-id": f.deviceHandler.device.Id,
 			"onu-id":    onuID,
 			"intf-id":   intfID,
+			"ethType":   ethType,
 		})
 	flowInfo := rsrcMgr.FlowInfo{Flow: &upstreamFlow}
 	if err := f.resourceMgr.UpdateFlowIDInfo(ctx, uint32(upstreamFlow.AccessIntfId), upstreamFlow.OnuId, upstreamFlow.UniId, upstreamFlow.FlowId, flowInfo); err != nil {
@@ -2253,13 +2258,19 @@
 			logger.Info(ctx, "adding-lldp-flow")
 			return f.addLLDPFlow(ctx, flow, portNo)
 		}
+		if ethType.(uint32) == PPPoEDEthType {
+			if voltha.Port_ETHERNET_NNI == IntfIDToPortTypeName(classifierInfo[InPort].(uint32)) {
+				logger.Debug(ctx, "trap-pppoed-from-nni-flow")
+				return f.addTrapFlowOnNNI(ctx, flow, classifierInfo, portNo)
+			}
+		}
 	}
 	if ipProto, ok := classifierInfo[IPProto]; ok {
 		if ipProto.(uint32) == IPProtoDhcp {
 			if udpSrc, ok := classifierInfo[UDPSrc]; ok {
 				if udpSrc.(uint32) == uint32(67) || udpSrc.(uint32) == uint32(546) {
 					logger.Debug(ctx, "trap-dhcp-from-nni-flow")
-					return f.addDHCPTrapFlowOnNNI(ctx, flow, classifierInfo, portNo)
+					return f.addTrapFlowOnNNI(ctx, flow, classifierInfo, portNo)
 				}
 			}
 		}
@@ -2604,15 +2615,15 @@
 
 }
 
-func (f *OpenOltFlowMgr) addDHCPTrapFlowOnNNI(ctx context.Context, logicalFlow *ofp.OfpFlowStats, classifier map[string]interface{}, portNo uint32) error {
-	logger.Debug(ctx, "adding-trap-dhcp-of-nni-flow")
+func (f *OpenOltFlowMgr) addTrapFlowOnNNI(ctx context.Context, logicalFlow *ofp.OfpFlowStats, classifier map[string]interface{}, portNo uint32) error {
+	logger.Debug(ctx, "adding-trap-of-nni-flow")
 	action := make(map[string]interface{})
 	classifier[PacketTagType] = DoubleTag
 	action[TrapToHost] = true
 	/* We manage flowId resource pool on per PON port basis.
 	   Since this situation is tricky, as a hack, we pass the NNI port
 	   index (network_intf_id) as PON port Index for the flowId resource
-	   pool. Also, there is no ONU Id available for trapping DHCP packets
+	   pool. Also, there is no ONU Id available for trapping packets
 	   on NNI port, use onu_id as -1 (invalid)
 	   ****************** CAVEAT *******************
 	   This logic works if the NNI Port Id falls within the same valid
@@ -2638,6 +2649,13 @@
 		return nil
 	}
 
+	logger.Debugw(ctx, "creating-trap-of-nni-flow",
+		log.Fields{
+			"classifier": classifier,
+			"action":     action,
+			"flowId":     logicalFlow.Id,
+			"intf-id":    networkInterfaceID})
+
 	classifierProto, err := makeOpenOltClassifierField(classifier)
 	if err != nil {
 		return olterrors.NewErrInvalidValue(log.Fields{"classifier": classifier}, err)
@@ -2664,7 +2682,7 @@
 	if err := f.addFlowToDevice(ctx, logicalFlow, &downstreamflow); err != nil {
 		return olterrors.NewErrFlowOp("add", logicalFlow.Id, log.Fields{"flow": downstreamflow}, err)
 	}
-	logger.Info(ctx, "dhcp-trap-on-nni-flow-added–to-device-successfully")
+	logger.Info(ctx, "trap-on-nni-flow-added–to-device-successfully")
 	flowInfo := rsrcMgr.FlowInfo{Flow: &downstreamflow}
 	if err := f.resourceMgr.UpdateFlowIDInfo(ctx, networkInterfaceID, int32(onuID), int32(uniID), logicalFlow.Id, flowInfo); err != nil {
 		return olterrors.NewErrPersistence("update", "flow", logicalFlow.Id, log.Fields{"flow": downstreamflow}, err)
@@ -2847,11 +2865,12 @@
 			return
 		}
 	} else if ethType, ok := classifierInfo[EthType]; ok {
-		if ethType.(uint32) == EapEthType {
-			logger.Infow(ctx, "adding-eapol-flow", log.Fields{
+		if ethType.(uint32) == EapEthType || ethType.(uint32) == PPPoEDEthType {
+			logger.Infow(ctx, "adding-ethType-flow", log.Fields{
 				"intf-id": intfID,
 				"onu-id":  onuID,
 				"uni-id":  uniID,
+				"ethType": ethType,
 			})
 			var vlanID uint32
 			if val, ok := classifierInfo[VlanVid]; ok {
@@ -2859,7 +2878,7 @@
 			} else {
 				vlanID = DefaultMgmtVlan
 			}
-			if err := f.addEAPOLFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, allocID, gemPort, vlanID, tpID, pbitToGem); err != nil {
+			if err := f.addEthTypeBasedFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, allocID, gemPort, vlanID, tpID, pbitToGem, ethType.(uint32)); err != nil {
 				logger.Warn(ctx, err)
 			}
 		}
diff --git a/internal/pkg/core/openolt_flowmgr_test.go b/internal/pkg/core/openolt_flowmgr_test.go
index 35c5d23..fad128a 100644
--- a/internal/pkg/core/openolt_flowmgr_test.go
+++ b/internal/pkg/core/openolt_flowmgr_test.go
@@ -305,6 +305,19 @@
 	multicastOfpStats, _ := fu.MkFlowStat(multicastFa)
 	multicastOfpStats.Id = 1
 
+	pppoedFa := &fu.FlowArgs{
+		KV: fu.OfpFlowModArgs{"priority": 1000, "cookie": 48132224281636694},
+		MatchFields: []*ofp.OfpOxmOfbField{
+			fu.InPort(1),
+			fu.EthType(0x8863),
+			fu.TunnelId(536870912),
+		},
+		Actions: []*ofp.OfpAction{
+			fu.Output(uint32(ofp.OfpPortNo_OFPP_CONTROLLER)),
+		},
+	}
+	pppoedOfpStats, _ := fu.MkFlowStat(pppoedFa)
+
 	type args struct {
 		flow *ofp.OfpFlowStats
 	}
@@ -317,6 +330,7 @@
 		{"RemoveFlow", args{flow: lldpofpstats}},
 		{"RemoveFlow", args{flow: dhcpofpstats}},
 		{"RemoveFlow", args{flow: multicastOfpStats}},
+		{"RemoveFlow", args{flow: pppoedOfpStats}},
 	}
 	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
 	defer cancel()
@@ -469,6 +483,19 @@
 		},
 	}
 
+	pppoedFa := &fu.FlowArgs{
+		KV: fu.OfpFlowModArgs{"priority": 1000, "cookie": 48132224281636694},
+		MatchFields: []*ofp.OfpOxmOfbField{
+			fu.InPort(1),
+			fu.EthType(0x8863),
+			fu.TunnelId(536870912),
+		},
+		Actions: []*ofp.OfpAction{
+			fu.SetField(fu.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 257)),
+			fu.Output(uint32(ofp.OfpPortNo_OFPP_CONTROLLER)),
+		},
+	}
+
 	fa9 := &fu.FlowArgs{
 		MatchFields: []*ofp.OfpOxmOfbField{
 			fu.InPort(536870912),
@@ -534,6 +561,7 @@
 	ofpstats10, _ := fu.MkFlowStat(fa10)
 	igmpstats, _ := fu.MkFlowStat(igmpFa)
 	ofpstats11, _ := fu.MkFlowStat(fa11)
+	pppoedstats, _ := fu.MkFlowStat(pppoedFa)
 
 	fmt.Println(ofpstats6, ofpstats9, ofpstats10)
 
@@ -563,6 +591,7 @@
 		//{"AddFlow", args{flow: ofpstats10, flowMetadata: flowMetadata}},
 		//ofpstats10
 		{"AddFlow", args{flow: ofpstats11, flowMetadata: flowMetadata}},
+		{"AddFlow", args{flow: pppoedstats, flowMetadata: flowMetadata}},
 	}
 	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
 	defer cancel()
@@ -919,6 +948,23 @@
 		KV: kw,
 	}
 
+	// PPPOED
+	pppoedFA := &fu.FlowArgs{
+		MatchFields: []*ofp.OfpOxmOfbField{
+			fu.InPort(536870912),
+			fu.Metadata_ofp(1),
+			fu.EthType(0x8863),
+			fu.VlanPcp(1),
+			fu.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 257),
+		},
+		Actions: []*ofp.OfpAction{
+			fu.SetField(fu.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 257)),
+			fu.Output(1048576),
+			fu.PushVlan(0x8100),
+		},
+		KV: kw,
+	}
+
 	classifierInfo := make(map[string]interface{})
 	actionInfo := make(map[string]interface{})
 	classifierInfo2 := make(map[string]interface{})
@@ -927,14 +973,18 @@
 	actionInfo3 := make(map[string]interface{})
 	classifierInfo4 := make(map[string]interface{})
 	actionInfo4 := make(map[string]interface{})
+	classifierInfo5 := make(map[string]interface{})
+	actionInfo5 := make(map[string]interface{})
 	flow, _ := fu.MkFlowStat(fa)
 	flow2, _ := fu.MkFlowStat(fa2)
 	flow3, _ := fu.MkFlowStat(fa3)
 	flow4, _ := fu.MkFlowStat(fa4)
+	flow5, _ := fu.MkFlowStat(pppoedFA)
 	formulateClassifierInfoFromFlow(ctx, classifierInfo, flow)
 	formulateClassifierInfoFromFlow(ctx, classifierInfo2, flow2)
 	formulateClassifierInfoFromFlow(ctx, classifierInfo3, flow3)
 	formulateClassifierInfoFromFlow(ctx, classifierInfo4, flow4)
+	formulateClassifierInfoFromFlow(ctx, classifierInfo5, flow5)
 
 	err := formulateActionInfoFromFlow(ctx, actionInfo, classifierInfo, flow)
 	if err != nil {
@@ -964,6 +1014,13 @@
 		return
 	}
 
+	err = formulateActionInfoFromFlow(ctx, actionInfo5, classifierInfo5, flow5)
+	if err != nil {
+		// Error logging is already done in the called function
+		// So just return in case of error
+		return
+	}
+
 	TpInst := &tp.TechProfile{
 		Name:                 "Test-Tech-Profile",
 		SubscriberIdentifier: "257",
@@ -1105,6 +1162,25 @@
 				uni:            "16",
 			},
 		},
+		{
+			name: "checkAndAddFlow-5",
+			args: args{
+				args:           nil,
+				classifierInfo: classifierInfo5,
+				actionInfo:     actionInfo5,
+				flow:           flow5,
+				gemPort:        1,
+				intfID:         1,
+				onuID:          1,
+				uniID:          16,
+				portNo:         1,
+				TpInst:         TpInst,
+				allocID:        []uint32{0x8001},
+				gemPorts:       []uint32{1, 2, 3, 4},
+				TpID:           64,
+				uni:            "16",
+			},
+		},
 	}
 	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
 	defer cancel()
@@ -1313,6 +1389,7 @@
 		},
 		KV: kwTable1Meter1,
 	}
+
 	// Upstream EAPOL - ONU1 UNI0 PON15
 	fa6 := &fu.FlowArgs{
 		MatchFields: []*ofp.OfpOxmOfbField{
@@ -1331,6 +1408,44 @@
 		},
 		KV: kwTable1Meter1,
 	}
+
+	// Upstream PPPOED - ONU1 UNI0 PON0
+	fa7 := &fu.FlowArgs{
+		MatchFields: []*ofp.OfpOxmOfbField{
+			fu.InPort(536870912),
+			fu.Metadata_ofp(1),
+			fu.EthType(0x8863),
+			fu.VlanPcp(1),
+			fu.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 257),
+			fu.TunnelId(16),
+		},
+		Actions: []*ofp.OfpAction{
+			//fu.SetField(fu.Metadata_ofp(uint64(ofp.OfpInstructionType_OFPIT_WRITE_METADATA | 2))),
+			fu.SetField(fu.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 257)),
+			fu.Output(2147483645),
+			fu.PushVlan(0x8100),
+		},
+		KV: kwTable1Meter1,
+	}
+
+	// Upstream PPPOED - ONU1 UNI0 PON15
+	fa8 := &fu.FlowArgs{
+		MatchFields: []*ofp.OfpOxmOfbField{
+			fu.InPort(536870927),
+			fu.Metadata_ofp(1),
+			fu.EthType(0x8863),
+			fu.VlanPcp(1),
+			fu.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 259),
+			fu.TunnelId(16),
+		},
+		Actions: []*ofp.OfpAction{
+			//fu.SetField(fu.Metadata_ofp(uint64(ofp.OfpInstructionType_OFPIT_WRITE_METADATA | 2))),
+			fu.SetField(fu.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 257)),
+			fu.Output(2147483645),
+			fu.PushVlan(0x8100),
+		},
+		KV: kwTable1Meter1,
+	}
 	flow0, _ := fu.MkFlowStat(fa0)
 	flow1, _ := fu.MkFlowStat(fa1)
 	flow2, _ := fu.MkFlowStat(fa2)
@@ -1339,6 +1454,8 @@
 
 	flow5, _ := fu.MkFlowStat(fa5)
 	flow6, _ := fu.MkFlowStat(fa6)
+	flow7, _ := fu.MkFlowStat(fa7)
+	flow8, _ := fu.MkFlowStat(fa8)
 
 	type args struct {
 		ctx          context.Context
@@ -1442,6 +1559,26 @@
 			},
 			wantErr: false,
 		},
+		{
+			name: "RouteFlowToOnuChannel-9",
+			args: args{
+				ctx:          ctx,
+				flow:         flow7,
+				addFlow:      true,
+				flowMetadata: &flowMetadata1,
+			},
+			wantErr: false,
+		},
+		{
+			name: "RouteFlowToOnuChannel-10",
+			args: args{
+				ctx:          ctx,
+				flow:         flow8,
+				addFlow:      true,
+				flowMetadata: &flowMetadata1,
+			},
+			wantErr: false,
+		},
 	}
 
 	var wg sync.WaitGroup