[VOL-3662] Supporting PPPoE trap rules on voltha core

Signed-off-by: Marcos Aurelio Carrero (Furukawa) <mcarrero@furukawalatam.com>
Change-Id: I9117c1d97412a2173a7ce232032cbd366a83cab9
diff --git a/rw_core/core/api/grpc_nbi_handler_test.go b/rw_core/core/api/grpc_nbi_handler_test.go
index 2891c36..7436083 100755
--- a/rw_core/core/api/grpc_nbi_handler_test.go
+++ b/rw_core/core/api/grpc_nbi_handler_test.go
@@ -50,6 +50,8 @@
 	"google.golang.org/grpc/status"
 )
 
+const numTrapOnNNIFlows = 4
+
 type NBTest struct {
 	etcdServer        *mock_etcd.EtcdServer
 	deviceMgr         *device.Manager
@@ -1119,7 +1121,7 @@
 }
 
 func (nb *NBTest) verifyLogicalDeviceFlowCount(t *testing.T, nbi *NBIHandler, numNNIPorts int, numUNIPorts int, flowAddFail bool) {
-	expectedNumFlows := numNNIPorts*3 + numNNIPorts*numUNIPorts
+	expectedNumFlows := numNNIPorts*numTrapOnNNIFlows + numNNIPorts*numUNIPorts
 	if flowAddFail {
 		expectedNumFlows = 0
 	}
@@ -1198,6 +1200,20 @@
 	_, err = nbi.UpdateLogicalDeviceFlowTable(getContext(), &flowIPV6)
 	assert.Nil(t, err)
 
+	fa = &flows.FlowArgs{
+		KV: flows.OfpFlowModArgs{"priority": 10000, "buffer_id": maxInt32, "out_port": maxInt32, "out_group": maxInt32, "flags": 1},
+		MatchFields: []*ofp.OfpOxmOfbField{
+			flows.InPort(nniPort),
+			flows.EthType(34915),
+		},
+		Actions: []*ofp.OfpAction{
+			flows.Output(controllerPortMask),
+		},
+	}
+	flowPPPoEP := ofp.FlowTableUpdate{FlowMod: makeSimpleFlowMod(fa), Id: logicalDeviceID}
+	_, err = nbi.UpdateLogicalDeviceFlowTable(getContext(), &flowPPPoEP)
+	assert.Nil(t, err)
+
 	return len(nniPorts), len(uniPorts)
 }
 
@@ -1330,7 +1346,7 @@
 	nb.verifyLogicalDeviceFlowCount(t, nbi, numNNIPorts, numUNIPorts, flowAddFail)
 
 	// Wait until all flows have been sent to the OLT adapters (or all failed)
-	expectedFlowCount := (numNNIPorts * 3) + numNNIPorts*numUNIPorts
+	expectedFlowCount := (numNNIPorts * numTrapOnNNIFlows) + numNNIPorts*numUNIPorts
 	if flowAddFail {
 		expectedFlowCount = 0
 	}
diff --git a/rw_core/flowdecomposition/flow_decomposer.go b/rw_core/flowdecomposition/flow_decomposer.go
index 236570d..dfd0771 100644
--- a/rw_core/flowdecomposition/flow_decomposer.go
+++ b/rw_core/flowdecomposition/flow_decomposer.go
@@ -72,6 +72,7 @@
 // Handles special case of any controller-bound flow for a parent device
 func (fd *FlowDecomposer) updateOutputPortForControllerBoundFlowForParentDevide(ctx context.Context, dr *fu.DeviceRules) (*fu.DeviceRules, error) {
 	EAPOL := fu.EthType(0x888e)
+	PPPoED := fu.EthType(0x8863)
 	IGMP := fu.IpProto(2)
 	UDP := fu.IpProto(17)
 
@@ -85,6 +86,7 @@
 				UpdateOutPortNo := false
 				for _, field := range fu.GetOfbFields(f) {
 					UpdateOutPortNo = (field.String() == EAPOL.String())
+					UpdateOutPortNo = UpdateOutPortNo || (field.String() == PPPoED.String())
 					UpdateOutPortNo = UpdateOutPortNo || (field.String() == IGMP.String())
 					UpdateOutPortNo = UpdateOutPortNo || (field.String() == UDP.String())
 					if UpdateOutPortNo {
diff --git a/rw_core/flowdecomposition/flow_decomposer_test.go b/rw_core/flowdecomposition/flow_decomposer_test.go
index e9c6fd0..88e6c03 100644
--- a/rw_core/flowdecomposition/flow_decomposer_test.go
+++ b/rw_core/flowdecomposition/flow_decomposer_test.go
@@ -655,6 +655,71 @@
 	assert.Equal(t, expectedOnuFlow.String(), derivedFlow.String())
 }
 
+func TestPppoedReRouteRuleVlanDecomposition(t *testing.T) {
+
+	fa := &fu.FlowArgs{
+		KV: fu.OfpFlowModArgs{"priority": 1000},
+		MatchFields: []*ofp.OfpOxmOfbField{
+			fu.InPort(1),
+			fu.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 50),
+			fu.EthType(0x8863),
+		},
+		Actions: []*ofp.OfpAction{
+			fu.SetField(fu.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 101)),
+			fu.Output(uint32(ofp.OfpPortNo_OFPP_CONTROLLER)),
+		},
+	}
+
+	fs, err := fu.MkFlowStat(fa)
+	assert.Nil(t, err)
+	flows := map[uint64]*ofp.OfpFlowStats{fs.Id: fs}
+	tfd := newTestFlowDecomposer(t, newTestDeviceManager())
+
+	deviceRules, err := tfd.fd.DecomposeRules(context.Background(), tfd, flows, nil)
+	assert.Nil(t, err)
+	onu1FlowAndGroup := deviceRules.Rules["onu1"]
+	oltFlowAndGroup := deviceRules.Rules["olt"]
+	assert.Equal(t, 1, onu1FlowAndGroup.Flows.Len())
+	assert.Equal(t, 1, oltFlowAndGroup.Flows.Len())
+	assert.Equal(t, 0, oltFlowAndGroup.Groups.Len())
+
+	faParent := &fu.FlowArgs{
+		KV: fu.OfpFlowModArgs{"priority": 1000},
+		MatchFields: []*ofp.OfpOxmOfbField{
+			fu.InPort(1),
+			fu.TunnelId(uint64(1)),
+			fu.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 101),
+			fu.EthType(0x8863),
+		},
+		Actions: []*ofp.OfpAction{
+			fu.Output(uint32(ofp.OfpPortNo_OFPP_CONTROLLER)),
+		},
+	}
+	expectedOltFlow, err := fu.MkFlowStat(faParent)
+	assert.Nil(t, err)
+	derivedFlow := oltFlowAndGroup.GetFlow(0)
+	assert.Equal(t, expectedOltFlow.String(), derivedFlow.String())
+
+	faChild := &fu.FlowArgs{
+		KV: fu.OfpFlowModArgs{"priority": 1000},
+		MatchFields: []*ofp.OfpOxmOfbField{
+			fu.InPort(2),
+			fu.TunnelId(uint64(1)),
+			fu.EthType(0x8863),
+			fu.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 50),
+		},
+		Actions: []*ofp.OfpAction{
+			fu.PushVlan(0x8100),
+			fu.SetField(fu.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 101)),
+			fu.Output(1),
+		},
+	}
+	expectedOnuFlow, err := fu.MkFlowStat(faChild)
+	assert.Nil(t, err)
+	derivedFlow = onu1FlowAndGroup.GetFlow(0)
+	assert.Equal(t, expectedOnuFlow.String(), derivedFlow.String())
+}
+
 func TestDhcpReRouteRuleDecomposition(t *testing.T) {
 
 	fa := &fu.FlowArgs{