VOL-2294 Flow-decomposer should not decompose multicast flows;
it should leave it as it is.
Change-Id: I6020b66257ed6f19145298dde34c2bae7b338650
diff --git a/rw_core/core/device_manager.go b/rw_core/core/device_manager.go
index 7bb869f..0094264 100755
--- a/rw_core/core/device_manager.go
+++ b/rw_core/core/device_manager.go
@@ -762,7 +762,7 @@
}
func (dMgr *DeviceManager) addFlowsAndGroups(deviceID string, flows []*ofp.OfpFlowStats, groups []*ofp.OfpGroupEntry, flowMetadata *voltha.FlowMetadata) error {
- log.Debugw("addFlowsAndGroups", log.Fields{"deviceid": deviceID, "flowMetadata": flowMetadata})
+ log.Debugw("addFlowsAndGroups", log.Fields{"deviceid": deviceID, "groups:": groups, "flowMetadata": flowMetadata})
if agent := dMgr.getDeviceAgent(deviceID); agent != nil {
return agent.addFlowsAndGroups(flows, groups, flowMetadata)
}
diff --git a/rw_core/core/logical_device_agent.go b/rw_core/core/logical_device_agent.go
index b85d572..5da6d40 100644
--- a/rw_core/core/logical_device_agent.go
+++ b/rw_core/core/logical_device_agent.go
@@ -1772,3 +1772,16 @@
}
return 0, status.Error(codes.NotFound, "No NNI port found")
}
+
+//GetNNIPorts returns NNI ports.
+func (agent *LogicalDeviceAgent) GetNNIPorts() []uint32 {
+ agent.lockLogicalPortsNo.RLock()
+ defer agent.lockLogicalPortsNo.RUnlock()
+ nniPorts := make([]uint32, 0)
+ for portNo, nni := range agent.logicalPortsNo {
+ if nni {
+ nniPorts = append(nniPorts, portNo)
+ }
+ }
+ return nniPorts
+}
diff --git a/rw_core/coreif/logical_device_agent_if.go b/rw_core/coreif/logical_device_agent_if.go
index 167d309..c9dbe6c 100644
--- a/rw_core/coreif/logical_device_agent_if.go
+++ b/rw_core/coreif/logical_device_agent_if.go
@@ -31,4 +31,5 @@
GetDeviceGraph() *graph.DeviceGraph
GetWildcardInputPorts(excludePort ...uint32) []uint32
GetRoute(ingressPortNo uint32, egressPortNo uint32) []graph.RouteHop
+ GetNNIPorts() []uint32
}
diff --git a/rw_core/flowdecomposition/flow_decomposer.go b/rw_core/flowdecomposition/flow_decomposer.go
index 330a4af..1d8d0a7 100644
--- a/rw_core/flowdecomposition/flow_decomposer.go
+++ b/rw_core/flowdecomposition/flow_decomposer.go
@@ -406,75 +406,12 @@
log.Warnw("Group-or-desc-nil", log.Fields{"grpId": grpID, "grp": grp})
return deviceRules
}
- for _, bucket := range grp.Desc.Buckets {
- otherActions := make([]*ofp.OfpAction, 0)
- for _, action := range bucket.Actions {
- if action.Type == fu.OUTPUT {
- outPortNo = action.GetOutput().Port
- } else if action.Type != fu.POP_VLAN {
- otherActions = append(otherActions, action)
- }
- }
- route2 := agent.GetRoute(inPortNo, outPortNo)
- switch len(route2) {
- case 0:
- log.Errorw("mc-no-route", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo, "comment": "deleting flow"})
- // TODO: Delete flow
- return deviceRules
- case 2:
- log.Debugw("route-found", log.Fields{"ingressHop": route2[0], "egressHop": route2[1]})
- default:
- log.Errorw("invalid-route-length", log.Fields{"routeLen": len(route)})
- return deviceRules
- }
-
- ingressHop := route[0]
- ingressHop2 := route2[0]
- egressHop := route2[1]
-
- if ingressHop.Ingress != ingressHop2.Ingress {
- log.Errorw("mc-ingress-hop-hop2-mismatch", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo, "comment": "ignoring flow"})
- return deviceRules
- }
- // Set the parent device flow
- fa := &fu.FlowArgs{
- KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
- MatchFields: []*ofp.OfpOxmOfbField{
- fu.InPort(ingressHop.Ingress),
- },
- }
- // Augment the matchfields with the ofpfields from the flow
- fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
-
- // Augment the Actions
- filteredAction := fu.GetActions(flow, fu.GROUP)
- filteredAction = append(filteredAction, fu.PopVlan())
- filteredAction = append(filteredAction, fu.Output(route2[1].Ingress))
- fa.Actions = filteredAction
-
- fg := fu.NewFlowsAndGroups()
- fg.AddFlow(fu.MkFlowStat(fa))
- deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fg)
-
- // Set the child device flow
- fa = &fu.FlowArgs{
- KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
- MatchFields: []*ofp.OfpOxmOfbField{
- fu.InPort(egressHop.Ingress),
- },
- }
- // Augment the matchfields with the ofpfields from the flow
- fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT, fu.VLAN_VID, fu.VLAN_PCP)...)
-
- // Augment the Actions
- otherActions = append(otherActions, fu.Output(egressHop.Egress))
- fa.Actions = otherActions
-
- fg = fu.NewFlowsAndGroups()
- fg.AddFlow(fu.MkFlowStat(fa))
- deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fg)
- }
+ deviceRules.CreateEntryIfNotExist(route[0].DeviceID)
+ fg := fu.NewFlowsAndGroups()
+ fg.AddFlow(flow)
+ //return the multicast flow without decomposing it
+ deviceRules.AddFlowsAndGroup(route[0].DeviceID, fg)
return deviceRules
}
@@ -483,6 +420,15 @@
groupMap map[uint32]*ofp.OfpGroupEntry) *fu.DeviceRules {
inPortNo := fu.GetInPort(flow)
+ if fu.HasGroup(flow) && inPortNo == 0 {
+ //if no in-port specified for a multicast flow, put NNI port as in-port
+ //so that a valid route can be found for the flow
+ nniPorts := agent.GetNNIPorts()
+ if len(nniPorts) > 0 {
+ inPortNo = nniPorts[0]
+ log.Debugw("Assigning NNI port as in-port for the multicast flow", log.Fields{"nni": nniPorts[0], "flow:": flow})
+ }
+ }
outPortNo := fu.GetOutPort(flow)
deviceRules := fu.NewDeviceRules()
route := agent.GetRoute(inPortNo, outPortNo)
diff --git a/rw_core/flowdecomposition/flow_decomposer_test.go b/rw_core/flowdecomposition/flow_decomposer_test.go
index cf05549..dac2e6b 100644
--- a/rw_core/flowdecomposition/flow_decomposer_test.go
+++ b/rw_core/flowdecomposition/flow_decomposer_test.go
@@ -17,7 +17,6 @@
import (
"errors"
-
"github.com/opencord/voltha-go/rw_core/graph"
"github.com/opencord/voltha-go/rw_core/mocks"
fu "github.com/opencord/voltha-lib-go/v2/pkg/flows"
@@ -114,12 +113,13 @@
}
type testFlowDecomposer struct {
- dMgr *testDeviceManager
- logicalPorts map[uint32]*voltha.LogicalPort
- routes map[graph.OFPortLink][]graph.RouteHop
- defaultRules *fu.DeviceRules
- deviceGraph *graph.DeviceGraph
- fd *FlowDecomposer
+ dMgr *testDeviceManager
+ logicalPorts map[uint32]*voltha.LogicalPort
+ routes map[graph.OFPortLink][]graph.RouteHop
+ defaultRules *fu.DeviceRules
+ deviceGraph *graph.DeviceGraph
+ fd *FlowDecomposer
+ logicalPortsNo map[uint32]bool
}
func newTestFlowDecomposer(deviceMgr *testDeviceManager) *testFlowDecomposer {
@@ -127,14 +127,19 @@
tfd.dMgr = deviceMgr
tfd.logicalPorts = make(map[uint32]*voltha.LogicalPort)
+ tfd.logicalPortsNo = make(map[uint32]bool)
// Go protobuf interpreted absence of a port as 0, so we can't use port #0 as an openflow
// port
tfd.logicalPorts[10] = &voltha.LogicalPort{Id: "10", DeviceId: "olt", DevicePortNo: 2}
+ tfd.logicalPorts[65536] = &voltha.LogicalPort{Id: "65536", DeviceId: "olt", DevicePortNo: 65536}
tfd.logicalPorts[1] = &voltha.LogicalPort{Id: "1", DeviceId: "onu1", DevicePortNo: 2}
tfd.logicalPorts[2] = &voltha.LogicalPort{Id: "2", DeviceId: "onu2", DevicePortNo: 2}
tfd.logicalPorts[3] = &voltha.LogicalPort{Id: "3", DeviceId: "onu3", DevicePortNo: 2}
tfd.logicalPorts[4] = &voltha.LogicalPort{Id: "4", DeviceId: "onu4", DevicePortNo: 2}
+ tfd.logicalPortsNo[10] = false
+ tfd.logicalPortsNo[65536] = true // nni
+
tfd.routes = make(map[graph.OFPortLink][]graph.RouteHop)
//DOWNSTREAM ROUTES
@@ -449,6 +454,16 @@
return nil
}
+func (tfd *testFlowDecomposer) GetNNIPorts() []uint32 {
+ nniPorts := make([]uint32, 0)
+ for portNo, nni := range tfd.logicalPortsNo {
+ if nni {
+ nniPorts = append(nniPorts, portNo)
+ }
+ }
+ return nniPorts
+}
+
func TestEapolReRouteRuleVlanDecomposition(t *testing.T) {
fa := &fu.FlowArgs{
@@ -968,43 +983,24 @@
tfd := newTestFlowDecomposer(newTestDeviceManager())
deviceRules := tfd.fd.DecomposeRules(tfd, flows, groups)
- onu1FlowAndGroup := deviceRules.Rules["onu1"]
oltFlowAndGroup := deviceRules.Rules["olt"]
- assert.Equal(t, 1, onu1FlowAndGroup.Flows.Len())
- assert.Equal(t, 0, onu1FlowAndGroup.Groups.Len())
assert.Equal(t, 1, oltFlowAndGroup.Flows.Len())
assert.Equal(t, 0, oltFlowAndGroup.Groups.Len())
fa = &fu.FlowArgs{
KV: fu.OfpFlowModArgs{"priority": 500},
MatchFields: []*ofp.OfpOxmOfbField{
- fu.InPort(2),
+ fu.InPort(10),
fu.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 170),
fu.VlanPcp(0),
fu.EthType(0x800),
fu.Ipv4Dst(0xe00a0a0a),
},
Actions: []*ofp.OfpAction{
- fu.PopVlan(),
- fu.Output(1),
+ fu.Group(10),
},
}
expectedOltFlow := fu.MkFlowStat(fa)
derivedFlow := oltFlowAndGroup.GetFlow(0)
assert.Equal(t, expectedOltFlow.String(), derivedFlow.String())
-
- fa = &fu.FlowArgs{
- KV: fu.OfpFlowModArgs{"priority": 500},
- MatchFields: []*ofp.OfpOxmOfbField{
- fu.InPort(1),
- fu.EthType(0x800),
- fu.Ipv4Dst(0xe00a0a0a),
- },
- Actions: []*ofp.OfpAction{
- fu.Output(2),
- },
- }
- expectedOnu1Flow := fu.MkFlowStat(fa)
- derivedFlow = onu1FlowAndGroup.GetFlow(0)
- assert.Equal(t, expectedOnu1Flow.String(), derivedFlow.String())
}