VOL-1878 : Support for LLDP trap flow

Implemenetation of addLLDP flow in Openolt adapter require change
in flow decomposer to decompose the flow with respect to nni trap.

Fixed sca issues.

Change-Id: Ie9464a320ae92058c4433a7f4d63ed192b244739
(cherry picked from commit 4ff89015c8a0f612ade41837cb731e5d7143a46f)
diff --git a/rw_core/core/logical_device_agent.go b/rw_core/core/logical_device_agent.go
index 65b3b30..9461c94 100644
--- a/rw_core/core/logical_device_agent.go
+++ b/rw_core/core/logical_device_agent.go
@@ -1437,12 +1437,11 @@
 	if egressPortNo != 0 && ((egressPortNo & 0x7fffffff) == uint32(ofp.OfpPortNo_OFPP_CONTROLLER)) {
 		log.Debugw("controller-flow", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "logicalPortsNo": agent.logicalPortsNo})
 		if agent.isNNIPort(ingressPortNo) {
-			log.Debug("returning-half-route")
 			//This is a trap on the NNI Port
 			if len(agent.deviceGraph.Routes) == 0 {
 				// If there are no routes set (usually when the logical device has only NNI port(s), then just return an
-				// internal route
-				hop := graph.RouteHop{DeviceID: agent.rootDeviceId, Ingress: ingressPortNo, Egress: egressPortNo}
+				// route with same IngressHop and EgressHop
+				hop := graph.RouteHop{DeviceID: agent.rootDeviceId, Ingress: ingressPortNo, Egress: ingressPortNo}
 				routes = append(routes, hop)
 				routes = append(routes, hop)
 				return routes
diff --git a/rw_core/flow_decomposition/flow_decomposer.go b/rw_core/flow_decomposition/flow_decomposer.go
index 09b29e8..d4058bc 100644
--- a/rw_core/flow_decomposition/flow_decomposer.go
+++ b/rw_core/flow_decomposition/flow_decomposer.go
@@ -111,10 +111,23 @@
 	egressHop := route[1]
 
 	fg := fu.NewFlowsAndGroups()
+
+	//case of packet_in from NNI port rule
 	if agent.GetDeviceGraph().IsRootPort(inPortNo) {
+		// Trap flow for NNI port
 		log.Debug("trap-nni")
-		// no decomposition required - it is already an OLT flow from NNI
-		fg.AddFlow(flow)
+
+		var fa *fu.FlowArgs
+		fa = &fu.FlowArgs{
+			KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
+			MatchFields: []*ofp.OfpOxmOfbField{
+				fu.InPort(egressHop.Egress),
+			},
+			Actions: fu.GetActions(flow),
+		}
+		// Augment the matchfields with the ofpfields from the flow
+		fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
+		fg.AddFlow(fu.MkFlowStat(fa))
 	} else {
 		// Trap flow for UNI port
 		log.Debug("trap-uni")
diff --git a/rw_core/flow_decomposition/flow_decomposer_test.go b/rw_core/flow_decomposition/flow_decomposer_test.go
index f4632cd..5e1dbe7 100644
--- a/rw_core/flow_decomposition/flow_decomposer_test.go
+++ b/rw_core/flow_decomposition/flow_decomposer_test.go
@@ -225,6 +225,18 @@
 			Egress:   tfd.dMgr.devices["onu4"].Ports[1].PortNo,
 		},
 	}
+	tfd.routes[graph.OFPortLink{Ingress: 10, Egress: 10}] = []graph.RouteHop{
+		{
+			DeviceID: "olt",
+			Ingress:  tfd.dMgr.devices["olt"].Ports[1].PortNo,
+			Egress:   tfd.dMgr.devices["olt"].Ports[1].PortNo,
+		},
+		{
+			DeviceID: "olt",
+			Ingress:  tfd.dMgr.devices["olt"].Ports[1].PortNo,
+			Egress:   tfd.dMgr.devices["olt"].Ports[1].PortNo,
+		},
+	}
 
 	//UPSTREAM DATA PLANE
 
@@ -570,6 +582,44 @@
 	assert.Equal(t, expectedOltFlow.String(), derivedFlow.String())
 }
 
+func TestLldpReRouteRuleDecomposition(t *testing.T) {
+	var fa *fu.FlowArgs
+	fa = &fu.FlowArgs{
+		KV: fu.OfpFlowModArgs{"priority": 1000},
+		MatchFields: []*ofp.OfpOxmOfbField{
+			fu.InPort(10),
+			fu.EthType(0x88CC),
+		},
+		Actions: []*ofp.OfpAction{
+			fu.Output(uint32(ofp.OfpPortNo_OFPP_CONTROLLER)),
+		},
+	}
+
+	flows := ofp.Flows{Items: []*ofp.OfpFlowStats{fu.MkFlowStat(fa)}}
+	groups := ofp.FlowGroups{}
+	tfd := newTestFlowDecomposer(newTestDeviceManager())
+	deviceRules := tfd.fd.DecomposeRules(tfd, flows, groups)
+	onu1FlowAndGroup := deviceRules.Rules["onu1"]
+	oltFlowAndGroup := deviceRules.Rules["olt"]
+	assert.Nil(t, onu1FlowAndGroup)
+	assert.Equal(t, 1, oltFlowAndGroup.Flows.Len())
+	assert.Equal(t, 0, oltFlowAndGroup.Groups.Len())
+
+	fa = &fu.FlowArgs{
+		KV: fu.OfpFlowModArgs{"priority": 1000},
+		MatchFields: []*ofp.OfpOxmOfbField{
+			fu.InPort(2),
+			fu.EthType(0x88CC),
+		},
+		Actions: []*ofp.OfpAction{
+			fu.Output(uint32(ofp.OfpPortNo_OFPP_CONTROLLER)),
+		},
+	}
+	expectedOltFlow := fu.MkFlowStat(fa)
+	derivedFlow := oltFlowAndGroup.GetFlow(0)
+	assert.Equal(t, expectedOltFlow.String(), derivedFlow.String())
+}
+
 func TestUnicastUpstreamRuleDecomposition(t *testing.T) {
 	var fa *fu.FlowArgs
 	fa = &fu.FlowArgs{