VOL-2041: Controller bound flows now decompose for parent and child device
This allows child device specific filtering and actions
to be more directly controlled by the core and northbound api
rather than indirectly from the parent adapter
Change-Id: I57844940786431d55dbe3fd65d3ec83e149560ab
diff --git a/rw_core/flow_decomposition/flow_decomposer.go b/rw_core/flow_decomposition/flow_decomposer.go
index c3c66ca..d28a803 100644
--- a/rw_core/flow_decomposition/flow_decomposer.go
+++ b/rw_core/flow_decomposition/flow_decomposer.go
@@ -108,10 +108,9 @@
meterId := fu.GetMeterIdFromFlow(flow)
metadataFromwriteMetadata := fu.GetMetadataFromWriteMetadataAction(flow)
+ ingressHop := route[0]
egressHop := route[1]
- fg := fu.NewFlowsAndGroups()
-
//case of packet_in from NNI port rule
if agent.GetDeviceGraph().IsRootPort(inPortNo) {
// Trap flow for NNI port
@@ -126,8 +125,10 @@
Actions: fu.GetActions(flow),
}
// Augment the matchfields with the ofpfields from the flow
+ fg := fu.NewFlowsAndGroups()
fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
fg.AddFlow(fu.MkFlowStat(fa))
+ deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fg)
} else {
// Trap flow for UNI port
log.Debug("trap-uni")
@@ -140,9 +141,9 @@
inPorts = []uint32{inPortNo}
}
for _, inputPort := range inPorts {
- var fa *fu.FlowArgs
- // Upstream flow
- fa = &fu.FlowArgs{
+ // Upstream flow on parent (olt) device
+ var faParent *fu.FlowArgs
+ faParent = &fu.FlowArgs{
KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie, "meter_id": uint64(meterId), "write_metadata": metadataFromwriteMetadata},
MatchFields: []*ofp.OfpOxmOfbField{
fu.InPort(egressHop.Ingress),
@@ -155,11 +156,51 @@
},
}
// 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))
+ faParent.MatchFields = append(faParent.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
+ fgParent := fu.NewFlowsAndGroups()
+ fgParent.AddFlow(fu.MkFlowStat(faParent))
+ deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fgParent)
+ log.Debugw("parent-trap-flow-set", log.Fields{"flow": faParent})
+
+ // Upstream flow on child (onu) device
+ var actions []*ofp.OfpAction
+ setvid := fu.GetVlanVid(flow)
+ if setvid != nil {
+ // have this child push the vlan the parent is matching/trapping on above
+ actions = []*ofp.OfpAction{
+ fu.PushVlan(0x8100),
+ fu.SetField(fu.VlanVid(*setvid)),
+ fu.Output(ingressHop.Egress),
+ }
+ } else {
+ // otherwise just set the egress port
+ actions = []*ofp.OfpAction{
+ fu.Output(ingressHop.Egress),
+ }
+ }
+ var faChild *fu.FlowArgs
+ faChild = &fu.FlowArgs{
+ KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie, "meter_id": uint64(meterId), "write_metadata": metadataFromwriteMetadata},
+ MatchFields: []*ofp.OfpOxmOfbField{
+ fu.InPort(ingressHop.Ingress),
+ fu.TunnelId(uint64(inputPort)),
+ },
+ Actions: actions,
+ }
+ // Augment the matchfields with the ofpfields from the flow.
+ // If the parent has a match vid and the child is setting that match vid exclude the the match vlan
+ // for the child given it will be setting that vlan and the parent will be matching on it
+ if setvid != nil {
+ faChild.MatchFields = append(faChild.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT, fu.VLAN_VID)...)
+ } else {
+ faChild.MatchFields = append(faChild.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
+ }
+ fgChild := fu.NewFlowsAndGroups()
+ fgChild.AddFlow(fu.MkFlowStat(faChild))
+ deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fgChild)
+ log.Debugw("child-trap-flow-set", log.Fields{"flow": faChild})
}
}
- deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fg)
return deviceRules
}
diff --git a/rw_core/flow_decomposition/flow_decomposer_test.go b/rw_core/flow_decomposition/flow_decomposer_test.go
index f122380..3264c12 100644
--- a/rw_core/flow_decomposition/flow_decomposer_test.go
+++ b/rw_core/flow_decomposition/flow_decomposer_test.go
@@ -487,7 +487,137 @@
return nil
}
-func TestEapolReRouteRuleDecomposition(t *testing.T) {
+func TestEapolReRouteRuleVlanDecomposition(t *testing.T) {
+
+ var fa *fu.FlowArgs
+ fa = &fu.FlowArgs{
+ KV: fu.OfpFlowModArgs{"priority": 1000},
+ MatchFields: []*ofp.OfpOxmOfbField{
+ fu.InPort(1),
+ fu.VlanVid(50),
+ fu.EthType(0x888e),
+ },
+ Actions: []*ofp.OfpAction{
+ fu.SetField(fu.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 101)),
+ 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.Equal(t, 1, onu1FlowAndGroup.Flows.Len())
+ assert.Equal(t, 1, oltFlowAndGroup.Flows.Len())
+ assert.Equal(t, 0, oltFlowAndGroup.Groups.Len())
+
+ var faParent *fu.FlowArgs
+ faParent = &fu.FlowArgs{
+ KV: fu.OfpFlowModArgs{"priority": 1000},
+ MatchFields: []*ofp.OfpOxmOfbField{
+ fu.InPort(1),
+ fu.TunnelId(uint64(1)),
+ fu.VlanVid(50),
+ fu.EthType(0x888e),
+ },
+ Actions: []*ofp.OfpAction{
+ fu.PushVlan(0x8100),
+ fu.SetField(fu.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 4000)),
+ fu.Output(uint32(ofp.OfpPortNo_OFPP_CONTROLLER)),
+ },
+ }
+ expectedOltFlow := fu.MkFlowStat(faParent)
+ derivedFlow := oltFlowAndGroup.GetFlow(0)
+ assert.Equal(t, expectedOltFlow.String(), derivedFlow.String())
+
+ var faChild *fu.FlowArgs
+ faChild = &fu.FlowArgs{
+ KV: fu.OfpFlowModArgs{"priority": 1000},
+ MatchFields: []*ofp.OfpOxmOfbField{
+ fu.InPort(2),
+ fu.TunnelId(uint64(1)),
+ fu.EthType(0x888e),
+ },
+ Actions: []*ofp.OfpAction{
+ fu.PushVlan(0x8100),
+ fu.SetField(fu.VlanVid(50)),
+ fu.Output(1),
+ },
+ }
+ expectedOnuFlow := fu.MkFlowStat(faChild)
+ derivedFlow = onu1FlowAndGroup.GetFlow(0)
+ assert.Equal(t, expectedOnuFlow.String(), derivedFlow.String())
+}
+
+func TestEapolReRouteRuleZeroVlanDecomposition(t *testing.T) {
+
+ var fa *fu.FlowArgs
+ fa = &fu.FlowArgs{
+ KV: fu.OfpFlowModArgs{"priority": 1000},
+ MatchFields: []*ofp.OfpOxmOfbField{
+ fu.InPort(1),
+ fu.VlanVid(0),
+ fu.EthType(0x888e),
+ },
+ Actions: []*ofp.OfpAction{
+ fu.SetField(fu.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 101)),
+ 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.Equal(t, 1, onu1FlowAndGroup.Flows.Len())
+ assert.Equal(t, 1, oltFlowAndGroup.Flows.Len())
+ assert.Equal(t, 0, oltFlowAndGroup.Groups.Len())
+
+ var faParent *fu.FlowArgs
+ faParent = &fu.FlowArgs{
+ KV: fu.OfpFlowModArgs{"priority": 1000},
+ MatchFields: []*ofp.OfpOxmOfbField{
+ fu.InPort(1),
+ fu.TunnelId(uint64(1)),
+ fu.VlanVid(0),
+ fu.EthType(0x888e),
+ },
+ Actions: []*ofp.OfpAction{
+ fu.PushVlan(0x8100),
+ fu.SetField(fu.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 4000)),
+ fu.Output(uint32(ofp.OfpPortNo_OFPP_CONTROLLER)),
+ },
+ }
+ expectedOltFlow := fu.MkFlowStat(faParent)
+ derivedFlow := oltFlowAndGroup.GetFlow(0)
+ assert.Equal(t, expectedOltFlow.String(), derivedFlow.String())
+
+ var faChild *fu.FlowArgs
+ faChild = &fu.FlowArgs{
+ KV: fu.OfpFlowModArgs{"priority": 1000},
+ MatchFields: []*ofp.OfpOxmOfbField{
+ fu.InPort(2),
+ fu.TunnelId(uint64(1)),
+ fu.EthType(0x888e),
+ },
+ Actions: []*ofp.OfpAction{
+ fu.PushVlan(0x8100),
+ fu.SetField(fu.VlanVid(0)),
+ fu.Output(1),
+ },
+ }
+ expectedOnuFlow := fu.MkFlowStat(faChild)
+ derivedFlow = onu1FlowAndGroup.GetFlow(0)
+ assert.Equal(t, expectedOnuFlow.String(), derivedFlow.String())
+}
+
+func TestEapolReRouteRuleNoVlanDecomposition(t *testing.T) {
var fa *fu.FlowArgs
fa = &fu.FlowArgs{
@@ -509,11 +639,12 @@
deviceRules := tfd.fd.DecomposeRules(tfd, flows, groups)
onu1FlowAndGroup := deviceRules.Rules["onu1"]
oltFlowAndGroup := deviceRules.Rules["olt"]
- assert.Nil(t, onu1FlowAndGroup)
+ assert.Equal(t, 1, onu1FlowAndGroup.Flows.Len())
assert.Equal(t, 1, oltFlowAndGroup.Flows.Len())
assert.Equal(t, 0, oltFlowAndGroup.Groups.Len())
- fa = &fu.FlowArgs{
+ var faParent *fu.FlowArgs
+ faParent = &fu.FlowArgs{
KV: fu.OfpFlowModArgs{"priority": 1000},
MatchFields: []*ofp.OfpOxmOfbField{
fu.InPort(1),
@@ -526,9 +657,25 @@
fu.Output(uint32(ofp.OfpPortNo_OFPP_CONTROLLER)),
},
}
- expectedOltFlow := fu.MkFlowStat(fa)
+ expectedOltFlow := fu.MkFlowStat(faParent)
derivedFlow := oltFlowAndGroup.GetFlow(0)
assert.Equal(t, expectedOltFlow.String(), derivedFlow.String())
+
+ var faChild *fu.FlowArgs
+ faChild = &fu.FlowArgs{
+ KV: fu.OfpFlowModArgs{"priority": 1000},
+ MatchFields: []*ofp.OfpOxmOfbField{
+ fu.InPort(2),
+ fu.TunnelId(uint64(1)),
+ fu.EthType(0x888e),
+ },
+ Actions: []*ofp.OfpAction{
+ fu.Output(1),
+ },
+ }
+ expectedOnuFlow := fu.MkFlowStat(faChild)
+ derivedFlow = onu1FlowAndGroup.GetFlow(0)
+ assert.Equal(t, expectedOnuFlow.String(), derivedFlow.String())
}
func TestDhcpReRouteRuleDecomposition(t *testing.T) {
@@ -556,11 +703,13 @@
deviceRules := tfd.fd.DecomposeRules(tfd, flows, groups)
onu1FlowAndGroup := deviceRules.Rules["onu1"]
oltFlowAndGroup := deviceRules.Rules["olt"]
- assert.Nil(t, onu1FlowAndGroup)
+ 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{
+ var faParent *fu.FlowArgs
+ faParent = &fu.FlowArgs{
KV: fu.OfpFlowModArgs{"priority": 1000},
MatchFields: []*ofp.OfpOxmOfbField{
fu.InPort(1),
@@ -577,9 +726,29 @@
fu.Output(uint32(ofp.OfpPortNo_OFPP_CONTROLLER)),
},
}
- expectedOltFlow := fu.MkFlowStat(fa)
+ expectedOltFlow := fu.MkFlowStat(faParent)
derivedFlow := oltFlowAndGroup.GetFlow(0)
assert.Equal(t, expectedOltFlow.String(), derivedFlow.String())
+
+ var faChild *fu.FlowArgs
+ faChild = &fu.FlowArgs{
+ KV: fu.OfpFlowModArgs{"priority": 1000},
+ MatchFields: []*ofp.OfpOxmOfbField{
+ fu.InPort(2),
+ fu.TunnelId(uint64(1)),
+ fu.EthType(0x0800),
+ fu.Ipv4Dst(0xffffffff),
+ fu.IpProto(17),
+ fu.UdpSrc(68),
+ fu.UdpDst(67),
+ },
+ Actions: []*ofp.OfpAction{
+ fu.Output(1),
+ },
+ }
+ expectedOnuFlow := fu.MkFlowStat(faChild)
+ derivedFlow = onu1FlowAndGroup.GetFlow(0)
+ assert.Equal(t, expectedOnuFlow.String(), derivedFlow.String())
}
func TestLldpReRouteRuleDecomposition(t *testing.T) {
diff --git a/rw_core/utils/flow_utils.go b/rw_core/utils/flow_utils.go
index 7ead52d..7cb718e 100644
--- a/rw_core/utils/flow_utils.go
+++ b/rw_core/utils/flow_utils.go
@@ -474,6 +474,20 @@
return 0
}
+func GetVlanVid(flow *ofp.OfpFlowStats) *uint32 {
+ if flow == nil {
+ return nil
+ }
+ for _, field := range GetOfbFields(flow) {
+ if field.Type == VLAN_VID {
+ ret := field.GetVlanVid()
+ return &ret
+ }
+ }
+ // Dont return 0 if the field is missing as vlan id value 0 has meaning and cannot be overloaded as "not found"
+ return nil
+}
+
func GetTunnelId(flow *ofp.OfpFlowStats) uint64 {
if flow == nil {
return 0