blob: 06d1b8bf887bfcf32b5713018738378e026e28ec [file] [log] [blame]
khenaidoo89b0e942018-10-21 21:11:33 -04001/*
2 * Copyright 2018-present Open Networking Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package flow_decomposition
18
19import (
khenaidoo19d7b632018-10-30 10:49:50 -040020 "github.com/gogo/protobuf/proto"
khenaidoo89b0e942018-10-21 21:11:33 -040021 "github.com/opencord/voltha-go/common/log"
khenaidoo89b0e942018-10-21 21:11:33 -040022 "github.com/opencord/voltha-go/rw_core/coreIf"
23 "github.com/opencord/voltha-go/rw_core/graph"
24 fu "github.com/opencord/voltha-go/rw_core/utils"
khenaidoo2c6a0992019-04-29 13:46:56 -040025 ofp "github.com/opencord/voltha-protos/go/openflow_13"
26 "github.com/opencord/voltha-protos/go/voltha"
khenaidoo89b0e942018-10-21 21:11:33 -040027)
28
29func init() {
30 log.AddPackage(log.JSON, log.DebugLevel, nil)
31}
32
khenaidoo89b0e942018-10-21 21:11:33 -040033type FlowDecomposer struct {
34 deviceMgr coreIf.DeviceManager
35}
36
37func NewFlowDecomposer(deviceMgr coreIf.DeviceManager) *FlowDecomposer {
38 var decomposer FlowDecomposer
39 decomposer.deviceMgr = deviceMgr
40 return &decomposer
41}
42
43//DecomposeRules decomposes per-device flows and flow-groups from the flows and groups defined on a logical device
khenaidoo2c6a0992019-04-29 13:46:56 -040044func (fd *FlowDecomposer) DecomposeRules(agent coreIf.LogicalDeviceAgent, flows ofp.Flows, groups ofp.FlowGroups, includeDefaultFlows bool) *fu.DeviceRules {
khenaidoo89b0e942018-10-21 21:11:33 -040045 rules := agent.GetAllDefaultRules()
46 deviceRules := rules.Copy()
khenaidoo2c6a0992019-04-29 13:46:56 -040047 devicesToUpdate := make(map[string]string)
khenaidoo89b0e942018-10-21 21:11:33 -040048
49 groupMap := make(map[uint32]*ofp.OfpGroupEntry)
50 for _, groupEntry := range groups.Items {
51 groupMap[groupEntry.Desc.GroupId] = groupEntry
52 }
53
54 var decomposedRules *fu.DeviceRules
55 for _, flow := range flows.Items {
56 decomposedRules = fd.decomposeFlow(agent, flow, groupMap)
57 for deviceId, flowAndGroups := range decomposedRules.Rules {
khenaidood20a5852018-10-22 22:09:55 -040058 deviceRules.CreateEntryIfNotExist(deviceId)
khenaidoo89b0e942018-10-21 21:11:33 -040059 deviceRules.Rules[deviceId].AddFrom(flowAndGroups)
khenaidoo2c6a0992019-04-29 13:46:56 -040060 devicesToUpdate[deviceId] = deviceId
khenaidoo89b0e942018-10-21 21:11:33 -040061 }
62 }
khenaidoo2c6a0992019-04-29 13:46:56 -040063 if includeDefaultFlows {
64 return deviceRules
65 }
66 updatedDeviceRules := deviceRules.FilterRules(devicesToUpdate)
67
68 return updatedDeviceRules
khenaidoo89b0e942018-10-21 21:11:33 -040069}
70
khenaidoo19d7b632018-10-30 10:49:50 -040071// Handles special case of any controller-bound flow for a parent device
72func (fd *FlowDecomposer) updateOutputPortForControllerBoundFlowForParentDevide(flow *ofp.OfpFlowStats,
73 dr *fu.DeviceRules) *fu.DeviceRules {
khenaidoo68c930b2019-05-13 11:46:51 -040074 EAPOL := fu.EthType(0x888e)
75 IGMP := fu.IpProto(2)
76 UDP := fu.IpProto(17)
khenaidoo19d7b632018-10-30 10:49:50 -040077
78 newDeviceRules := dr.Copy()
79 // Check whether we are dealing with a parent device
80 for deviceId, fg := range dr.GetRules() {
81 if root, _ := fd.deviceMgr.IsRootDevice(deviceId); root {
82 newDeviceRules.ClearFlows(deviceId)
83 for i := 0; i < fg.Flows.Len(); i++ {
84 f := fg.GetFlow(i)
85 UpdateOutPortNo := false
khenaidoo68c930b2019-05-13 11:46:51 -040086 for _, field := range fu.GetOfbFields(f) {
khenaidoo19d7b632018-10-30 10:49:50 -040087 UpdateOutPortNo = (field.String() == EAPOL.String())
88 UpdateOutPortNo = UpdateOutPortNo || (field.String() == IGMP.String())
89 UpdateOutPortNo = UpdateOutPortNo || (field.String() == UDP.String())
90 if UpdateOutPortNo {
91 break
92 }
93 }
94 if UpdateOutPortNo {
khenaidoo68c930b2019-05-13 11:46:51 -040095 f = fu.UpdateOutputPortByActionType(f, uint32(ofp.OfpInstructionType_OFPIT_APPLY_ACTIONS),
khenaidoo19d7b632018-10-30 10:49:50 -040096 uint32(ofp.OfpPortNo_OFPP_CONTROLLER))
97 }
98 // Update flow Id as a change in the instruction field will result in a new flow ID
khenaidoo68c930b2019-05-13 11:46:51 -040099 f.Id = fu.HashFlowStats(f)
khenaidoo19d7b632018-10-30 10:49:50 -0400100 newDeviceRules.AddFlow(deviceId, (proto.Clone(f)).(*ofp.OfpFlowStats))
101 }
102 }
103 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400104
khenaidoo19d7b632018-10-30 10:49:50 -0400105 return newDeviceRules
106}
107
khenaidood20a5852018-10-22 22:09:55 -0400108//processControllerBoundFlow decomposes trap flows
109func (fd *FlowDecomposer) processControllerBoundFlow(agent coreIf.LogicalDeviceAgent, route []graph.RouteHop,
110 inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats) *fu.DeviceRules {
111
khenaidoo89b0e942018-10-21 21:11:33 -0400112 log.Debugw("trap-flow", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo, "flow": flow})
khenaidood20a5852018-10-22 22:09:55 -0400113 deviceRules := fu.NewDeviceRules()
114
115 egressHop := route[1]
116
khenaidoo89b0e942018-10-21 21:11:33 -0400117 fg := fu.NewFlowsAndGroups()
118 if agent.GetDeviceGraph().IsRootPort(inPortNo) {
119 log.Debug("trap-nni")
khenaidoo8f474192019-04-03 17:20:44 -0400120 // no decomposition required - it is already an OLT flow from NNI
121 fg.AddFlow(flow)
khenaidoo89b0e942018-10-21 21:11:33 -0400122 } else {
123 // Trap flow for UNI port
124 log.Debug("trap-uni")
125
126 //inPortNo is 0 for wildcard input case, do not include upstream port for 4000 flow in input
127 var inPorts []uint32
128 if inPortNo == 0 {
khenaidood20a5852018-10-22 22:09:55 -0400129 inPorts = agent.GetWildcardInputPorts(egressHop.Egress) // exclude egress_hop.egress_port.port_no
khenaidoo89b0e942018-10-21 21:11:33 -0400130 } else {
131 inPorts = []uint32{inPortNo}
132 }
133 for _, inputPort := range inPorts {
134 var fa *fu.FlowArgs
135 // Upstream flow
136 fa = &fu.FlowArgs{
137 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
138 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -0400139 fu.InPort(egressHop.Ingress),
140 fu.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | inputPort),
141 fu.TunnelId(uint64(inputPort)),
khenaidoo89b0e942018-10-21 21:11:33 -0400142 },
143 Actions: []*ofp.OfpAction{
khenaidoo68c930b2019-05-13 11:46:51 -0400144 fu.PushVlan(0x8100),
145 fu.SetField(fu.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 4000)),
146 fu.Output(egressHop.Egress),
khenaidoo89b0e942018-10-21 21:11:33 -0400147 },
148 }
149 // Augment the matchfields with the ofpfields from the flow
khenaidoo68c930b2019-05-13 11:46:51 -0400150 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT, fu.VLAN_VID)...)
151 fg.AddFlow(fu.MkFlowStat(fa))
khenaidoo89b0e942018-10-21 21:11:33 -0400152
153 // Downstream flow
154 fa = &fu.FlowArgs{
155 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority)},
156 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -0400157 fu.InPort(egressHop.Egress),
158 fu.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 4000),
159 fu.VlanPcp(0),
160 fu.Metadata_ofp(uint64(inputPort)),
161 fu.TunnelId(uint64(inputPort)),
khenaidoo89b0e942018-10-21 21:11:33 -0400162 },
163 Actions: []*ofp.OfpAction{
khenaidoo68c930b2019-05-13 11:46:51 -0400164 fu.PopVlan(),
165 fu.Output(egressHop.Ingress),
khenaidoo89b0e942018-10-21 21:11:33 -0400166 },
167 }
khenaidoo68c930b2019-05-13 11:46:51 -0400168 fg.AddFlow(fu.MkFlowStat(fa))
khenaidoo89b0e942018-10-21 21:11:33 -0400169 }
170 }
khenaidood20a5852018-10-22 22:09:55 -0400171 deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fg)
khenaidoo2c6a0992019-04-29 13:46:56 -0400172
khenaidoo89b0e942018-10-21 21:11:33 -0400173 return deviceRules
174}
175
176// processUpstreamNonControllerBoundFlow processes non-controller bound flow. We assume that anything that is
177// upstream needs to get Q-in-Q treatment and that this is expressed via two flow rules, the first using the
178// goto-statement. We also assume that the inner tag is applied at the ONU, while the outer tag is
179// applied at the OLT
khenaidood20a5852018-10-22 22:09:55 -0400180func (fd *FlowDecomposer) processUpstreamNonControllerBoundFlow(agent coreIf.LogicalDeviceAgent,
181 route []graph.RouteHop, inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats) *fu.DeviceRules {
182
khenaidoo89b0e942018-10-21 21:11:33 -0400183 log.Debugw("upstream-non-controller-bound-flow", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo})
khenaidood20a5852018-10-22 22:09:55 -0400184 deviceRules := fu.NewDeviceRules()
185
186 ingressHop := route[0]
187 egressHop := route[1]
188
khenaidoo68c930b2019-05-13 11:46:51 -0400189 if fu.HasNextTable(flow) {
khenaidoo89b0e942018-10-21 21:11:33 -0400190 log.Debugw("has-next-table", log.Fields{"table_id": flow.TableId})
191 if outPortNo != 0 {
192 log.Warnw("outPort-should-not-be-specified", log.Fields{"outPortNo": outPortNo})
193 }
194 var fa *fu.FlowArgs
195 fa = &fu.FlowArgs{
196 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
197 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -0400198 fu.InPort(ingressHop.Ingress),
199 fu.TunnelId(uint64(inPortNo)),
khenaidoo89b0e942018-10-21 21:11:33 -0400200 },
khenaidoo68c930b2019-05-13 11:46:51 -0400201 Actions: fu.GetActions(flow),
khenaidoo89b0e942018-10-21 21:11:33 -0400202 }
203 // Augment the matchfields with the ofpfields from the flow
khenaidoo68c930b2019-05-13 11:46:51 -0400204 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
khenaidood20a5852018-10-22 22:09:55 -0400205
206 // Augment the Actions
khenaidoo68c930b2019-05-13 11:46:51 -0400207 fa.Actions = append(fa.Actions, fu.Output(ingressHop.Egress))
khenaidood20a5852018-10-22 22:09:55 -0400208
khenaidoo89b0e942018-10-21 21:11:33 -0400209 fg := fu.NewFlowsAndGroups()
khenaidoo68c930b2019-05-13 11:46:51 -0400210 fg.AddFlow(fu.MkFlowStat(fa))
khenaidood20a5852018-10-22 22:09:55 -0400211 deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -0400212 } else {
213 var actions []ofp.OfpActionType
214 var isOutputTypeInActions bool
khenaidoo68c930b2019-05-13 11:46:51 -0400215 for _, action := range fu.GetActions(flow) {
khenaidoo89b0e942018-10-21 21:11:33 -0400216 actions = append(actions, action.Type)
khenaidoo68c930b2019-05-13 11:46:51 -0400217 if !isOutputTypeInActions && action.Type == fu.OUTPUT {
khenaidoo89b0e942018-10-21 21:11:33 -0400218 isOutputTypeInActions = true
219 }
220 }
221 if len(actions) == 1 && isOutputTypeInActions {
222 var fa *fu.FlowArgs
223 // child device flow
224 fa = &fu.FlowArgs{
225 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
226 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -0400227 fu.InPort(ingressHop.Ingress),
khenaidoo89b0e942018-10-21 21:11:33 -0400228 },
229 Actions: []*ofp.OfpAction{
khenaidoo68c930b2019-05-13 11:46:51 -0400230 fu.Output(ingressHop.Egress),
khenaidoo89b0e942018-10-21 21:11:33 -0400231 },
232 }
233 // Augment the matchfields with the ofpfields from the flow
khenaidoo68c930b2019-05-13 11:46:51 -0400234 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
khenaidoo89b0e942018-10-21 21:11:33 -0400235 fg := fu.NewFlowsAndGroups()
khenaidoo68c930b2019-05-13 11:46:51 -0400236 fg.AddFlow(fu.MkFlowStat(fa))
khenaidood20a5852018-10-22 22:09:55 -0400237 deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -0400238
239 // parent device flow
240 fa = &fu.FlowArgs{
241 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
242 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -0400243 fu.InPort(egressHop.Ingress), //egress_hop.ingress_port.port_no
244 fu.TunnelId(uint64(inPortNo)),
khenaidoo89b0e942018-10-21 21:11:33 -0400245 },
246 Actions: []*ofp.OfpAction{
khenaidoo68c930b2019-05-13 11:46:51 -0400247 fu.Output(egressHop.Egress),
khenaidoo89b0e942018-10-21 21:11:33 -0400248 },
249 }
250 // Augment the matchfields with the ofpfields from the flow
khenaidoo68c930b2019-05-13 11:46:51 -0400251 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
khenaidoo89b0e942018-10-21 21:11:33 -0400252 fg = fu.NewFlowsAndGroups()
khenaidoo68c930b2019-05-13 11:46:51 -0400253 fg.AddFlow(fu.MkFlowStat(fa))
khenaidood20a5852018-10-22 22:09:55 -0400254 deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -0400255 } else {
256 if outPortNo == 0 {
257 log.Warnw("outPort-should-be-specified", log.Fields{"outPortNo": outPortNo})
258 }
259 var fa *fu.FlowArgs
260 fa = &fu.FlowArgs{
261 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
262 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -0400263 fu.InPort(egressHop.Ingress),
264 fu.TunnelId(uint64(inPortNo)),
khenaidoo89b0e942018-10-21 21:11:33 -0400265 },
266 }
267 // Augment the matchfields with the ofpfields from the flow
khenaidoo68c930b2019-05-13 11:46:51 -0400268 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
khenaidood20a5852018-10-22 22:09:55 -0400269
270 //Augment the actions
khenaidoo68c930b2019-05-13 11:46:51 -0400271 filteredAction := fu.GetActions(flow, fu.OUTPUT)
272 filteredAction = append(filteredAction, fu.Output(egressHop.Egress))
khenaidood20a5852018-10-22 22:09:55 -0400273 fa.Actions = filteredAction
274
khenaidoo89b0e942018-10-21 21:11:33 -0400275 fg := fu.NewFlowsAndGroups()
khenaidoo68c930b2019-05-13 11:46:51 -0400276 fg.AddFlow(fu.MkFlowStat(fa))
khenaidood20a5852018-10-22 22:09:55 -0400277 deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -0400278 }
279 }
280 return deviceRules
281}
282
khenaidood20a5852018-10-22 22:09:55 -0400283// processDownstreamFlowWithNextTable decomposes downstream flows containing next table ID instructions
284func (fd *FlowDecomposer) processDownstreamFlowWithNextTable(agent coreIf.LogicalDeviceAgent, route []graph.RouteHop,
285 inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats) *fu.DeviceRules {
286
khenaidoo89b0e942018-10-21 21:11:33 -0400287 log.Debugw("downstream-flow-with-next-table", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo})
khenaidood20a5852018-10-22 22:09:55 -0400288 deviceRules := fu.NewDeviceRules()
289
khenaidoo89b0e942018-10-21 21:11:33 -0400290 if outPortNo != 0 {
291 log.Warnw("outPort-should-not-be-specified", log.Fields{"outPortNo": outPortNo})
292 }
293 ingressHop := route[0]
khenaidood20a5852018-10-22 22:09:55 -0400294 egressHop := route[1]
295
khenaidoo68c930b2019-05-13 11:46:51 -0400296 if fu.GetMetaData(flow) != 0 {
khenaidoo89b0e942018-10-21 21:11:33 -0400297 log.Debugw("creating-metadata-flow", log.Fields{"flow": flow})
khenaidoo68c930b2019-05-13 11:46:51 -0400298 portNumber := uint32(fu.GetPortNumberFromMetadata(flow))
khenaidoo89b0e942018-10-21 21:11:33 -0400299 if portNumber != 0 {
khenaidoo19d7b632018-10-30 10:49:50 -0400300 recalculatedRoute := agent.GetRoute(inPortNo, portNumber)
khenaidoo89b0e942018-10-21 21:11:33 -0400301 switch len(recalculatedRoute) {
302 case 0:
khenaidoo68c930b2019-05-13 11:46:51 -0400303 log.Errorw("no-route-double-tag", log.Fields{"inPortNo": inPortNo, "outPortNo": portNumber, "comment": "deleting-flow", "metadata": fu.GetMetaData64Bit(flow)})
khenaidoo89b0e942018-10-21 21:11:33 -0400304 // TODO: Delete flow
305 return deviceRules
306 case 2:
khenaidood20a5852018-10-22 22:09:55 -0400307 log.Debugw("route-found", log.Fields{"ingressHop": ingressHop, "egressHop": egressHop})
khenaidoo89b0e942018-10-21 21:11:33 -0400308 break
309 default:
310 log.Errorw("invalid-route-length", log.Fields{"routeLen": len(route)})
311 return deviceRules
312 }
313 ingressHop = recalculatedRoute[0]
314 }
khenaidoo68c930b2019-05-13 11:46:51 -0400315 innerTag := fu.GetInnerTagFromMetaData(flow)
khenaidoo89b0e942018-10-21 21:11:33 -0400316 if innerTag == 0 {
khenaidoo68c930b2019-05-13 11:46:51 -0400317 log.Errorw("no-inner-route-double-tag", log.Fields{"inPortNo": inPortNo, "outPortNo": portNumber, "comment": "deleting-flow", "metadata": fu.GetMetaData64Bit(flow)})
khenaidoo89b0e942018-10-21 21:11:33 -0400318 // TODO: Delete flow
319 return deviceRules
320 }
321 var fa *fu.FlowArgs
322 fa = &fu.FlowArgs{
323 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
324 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -0400325 fu.InPort(ingressHop.Ingress),
326 fu.Metadata_ofp(innerTag),
327 fu.TunnelId(uint64(portNumber)),
khenaidoo89b0e942018-10-21 21:11:33 -0400328 },
khenaidoo68c930b2019-05-13 11:46:51 -0400329 Actions: fu.GetActions(flow),
khenaidoo89b0e942018-10-21 21:11:33 -0400330 }
331 // Augment the matchfields with the ofpfields from the flow
khenaidoo68c930b2019-05-13 11:46:51 -0400332 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT, fu.METADATA)...)
khenaidood20a5852018-10-22 22:09:55 -0400333
334 // Augment the Actions
khenaidoo68c930b2019-05-13 11:46:51 -0400335 fa.Actions = append(fa.Actions, fu.Output(ingressHop.Egress))
khenaidood20a5852018-10-22 22:09:55 -0400336
khenaidoo89b0e942018-10-21 21:11:33 -0400337 fg := fu.NewFlowsAndGroups()
khenaidoo68c930b2019-05-13 11:46:51 -0400338 fg.AddFlow(fu.MkFlowStat(fa))
khenaidoo89b0e942018-10-21 21:11:33 -0400339 deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fg)
340 } else { // Create standard flow
341 log.Debugw("creating-standard-flow", log.Fields{"flow": flow})
342 var fa *fu.FlowArgs
343 fa = &fu.FlowArgs{
344 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
345 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -0400346 fu.InPort(ingressHop.Ingress),
347 fu.TunnelId(uint64(inPortNo)),
khenaidoo89b0e942018-10-21 21:11:33 -0400348 },
khenaidoo68c930b2019-05-13 11:46:51 -0400349 Actions: fu.GetActions(flow),
khenaidoo89b0e942018-10-21 21:11:33 -0400350 }
351 // Augment the matchfields with the ofpfields from the flow
khenaidoo68c930b2019-05-13 11:46:51 -0400352 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
khenaidood20a5852018-10-22 22:09:55 -0400353
354 // Augment the Actions
khenaidoo68c930b2019-05-13 11:46:51 -0400355 fa.Actions = append(fa.Actions, fu.Output(ingressHop.Egress))
khenaidood20a5852018-10-22 22:09:55 -0400356
khenaidoo89b0e942018-10-21 21:11:33 -0400357 fg := fu.NewFlowsAndGroups()
khenaidoo68c930b2019-05-13 11:46:51 -0400358 fg.AddFlow(fu.MkFlowStat(fa))
khenaidoo89b0e942018-10-21 21:11:33 -0400359 deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fg)
360 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400361
khenaidoo89b0e942018-10-21 21:11:33 -0400362 return deviceRules
363}
364
khenaidood20a5852018-10-22 22:09:55 -0400365// processUnicastFlow decomposes unicast flows
366func (fd *FlowDecomposer) processUnicastFlow(agent coreIf.LogicalDeviceAgent, route []graph.RouteHop,
367 inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats) *fu.DeviceRules {
368
khenaidoo89b0e942018-10-21 21:11:33 -0400369 log.Debugw("unicast-flow", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo})
khenaidood20a5852018-10-22 22:09:55 -0400370 deviceRules := fu.NewDeviceRules()
371
372 ingressHop := route[0]
373 egressHop := route[1]
374
khenaidoo89b0e942018-10-21 21:11:33 -0400375 var actions []ofp.OfpActionType
376 var isOutputTypeInActions bool
khenaidoo68c930b2019-05-13 11:46:51 -0400377 for _, action := range fu.GetActions(flow) {
khenaidoo89b0e942018-10-21 21:11:33 -0400378 actions = append(actions, action.Type)
khenaidoo68c930b2019-05-13 11:46:51 -0400379 if !isOutputTypeInActions && action.Type == fu.OUTPUT {
khenaidoo89b0e942018-10-21 21:11:33 -0400380 isOutputTypeInActions = true
381 }
382 }
383 if len(actions) == 1 && isOutputTypeInActions {
384 var fa *fu.FlowArgs
385 // Parent device flow
386 fa = &fu.FlowArgs{
387 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
388 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -0400389 fu.InPort(ingressHop.Ingress),
390 fu.TunnelId(uint64(inPortNo)),
khenaidoo89b0e942018-10-21 21:11:33 -0400391 },
392 Actions: []*ofp.OfpAction{
khenaidoo68c930b2019-05-13 11:46:51 -0400393 fu.Output(ingressHop.Egress),
khenaidoo89b0e942018-10-21 21:11:33 -0400394 },
395 }
396 // Augment the matchfields with the ofpfields from the flow
khenaidoo68c930b2019-05-13 11:46:51 -0400397 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
khenaidood20a5852018-10-22 22:09:55 -0400398
khenaidoo89b0e942018-10-21 21:11:33 -0400399 fg := fu.NewFlowsAndGroups()
khenaidoo68c930b2019-05-13 11:46:51 -0400400 fg.AddFlow(fu.MkFlowStat(fa))
khenaidood20a5852018-10-22 22:09:55 -0400401 deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -0400402
403 // Child device flow
404 fa = &fu.FlowArgs{
405 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
406 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -0400407 fu.InPort(egressHop.Ingress),
khenaidoo89b0e942018-10-21 21:11:33 -0400408 },
409 Actions: []*ofp.OfpAction{
khenaidoo68c930b2019-05-13 11:46:51 -0400410 fu.Output(egressHop.Egress),
khenaidoo89b0e942018-10-21 21:11:33 -0400411 },
412 }
413 // Augment the matchfields with the ofpfields from the flow
khenaidoo68c930b2019-05-13 11:46:51 -0400414 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
khenaidood20a5852018-10-22 22:09:55 -0400415
khenaidoo89b0e942018-10-21 21:11:33 -0400416 fg = fu.NewFlowsAndGroups()
khenaidoo68c930b2019-05-13 11:46:51 -0400417 fg.AddFlow(fu.MkFlowStat(fa))
khenaidood20a5852018-10-22 22:09:55 -0400418 deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -0400419 } else {
420 var fa *fu.FlowArgs
421 fa = &fu.FlowArgs{
422 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
423 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -0400424 fu.InPort(egressHop.Ingress),
khenaidoo89b0e942018-10-21 21:11:33 -0400425 },
426 }
427 // Augment the matchfields with the ofpfields from the flow
khenaidoo68c930b2019-05-13 11:46:51 -0400428 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
khenaidood20a5852018-10-22 22:09:55 -0400429
khenaidoo89b0e942018-10-21 21:11:33 -0400430 // Augment the Actions
khenaidoo68c930b2019-05-13 11:46:51 -0400431 filteredAction := fu.GetActions(flow, fu.OUTPUT)
432 filteredAction = append(filteredAction, fu.Output(egressHop.Egress))
khenaidood20a5852018-10-22 22:09:55 -0400433 fa.Actions = filteredAction
434
khenaidoo89b0e942018-10-21 21:11:33 -0400435 fg := fu.NewFlowsAndGroups()
khenaidoo68c930b2019-05-13 11:46:51 -0400436 fg.AddFlow(fu.MkFlowStat(fa))
khenaidood20a5852018-10-22 22:09:55 -0400437 deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -0400438 }
439 return deviceRules
440}
441
khenaidood20a5852018-10-22 22:09:55 -0400442// processMulticastFlow decompose multicast flows
443func (fd *FlowDecomposer) processMulticastFlow(agent coreIf.LogicalDeviceAgent, route []graph.RouteHop,
444 inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats, grpId uint32,
445 groupMap map[uint32]*ofp.OfpGroupEntry) *fu.DeviceRules {
446
khenaidoo89b0e942018-10-21 21:11:33 -0400447 log.Debugw("multicast-flow", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo})
khenaidood20a5852018-10-22 22:09:55 -0400448 deviceRules := fu.NewDeviceRules()
khenaidoo89b0e942018-10-21 21:11:33 -0400449
450 //having no Group yet is the same as having a Group with no buckets
451 var grp *ofp.OfpGroupEntry
452 var ok bool
453 if grp, ok = groupMap[grpId]; !ok {
454 log.Warnw("Group-id-not-present-in-map", log.Fields{"grpId": grpId, "groupMap": groupMap})
455 return deviceRules
456 }
457 if grp == nil || grp.Desc == nil {
458 log.Warnw("Group-or-desc-nil", log.Fields{"grpId": grpId, "grp": grp})
459 return deviceRules
460 }
461 for _, bucket := range grp.Desc.Buckets {
462 otherActions := make([]*ofp.OfpAction, 0)
463 for _, action := range bucket.Actions {
khenaidoo68c930b2019-05-13 11:46:51 -0400464 if action.Type == fu.OUTPUT {
khenaidoo89b0e942018-10-21 21:11:33 -0400465 outPortNo = action.GetOutput().Port
khenaidoo68c930b2019-05-13 11:46:51 -0400466 } else if action.Type != fu.POP_VLAN {
khenaidoo89b0e942018-10-21 21:11:33 -0400467 otherActions = append(otherActions, action)
468 }
469 }
470
khenaidoo19d7b632018-10-30 10:49:50 -0400471 route2 := agent.GetRoute(inPortNo, outPortNo)
khenaidoo89b0e942018-10-21 21:11:33 -0400472 switch len(route2) {
473 case 0:
474 log.Errorw("mc-no-route", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo, "comment": "deleting flow"})
475 // TODO: Delete flow
476 return deviceRules
477 case 2:
khenaidood20a5852018-10-22 22:09:55 -0400478 log.Debugw("route-found", log.Fields{"ingressHop": route2[0], "egressHop": route2[1]})
khenaidoo89b0e942018-10-21 21:11:33 -0400479 break
480 default:
481 log.Errorw("invalid-route-length", log.Fields{"routeLen": len(route)})
482 return deviceRules
483 }
484
khenaidood20a5852018-10-22 22:09:55 -0400485 ingressHop := route[0]
486 ingressHop2 := route2[0]
487 egressHop := route2[1]
488
489 if ingressHop.Ingress != ingressHop2.Ingress {
khenaidoo89b0e942018-10-21 21:11:33 -0400490 log.Errorw("mc-ingress-hop-hop2-mismatch", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo, "comment": "ignoring flow"})
491 return deviceRules
492 }
493 // Set the parent device flow
494 var fa *fu.FlowArgs
495 fa = &fu.FlowArgs{
496 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
497 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -0400498 fu.InPort(ingressHop.Ingress),
khenaidoo89b0e942018-10-21 21:11:33 -0400499 },
500 }
501 // Augment the matchfields with the ofpfields from the flow
khenaidoo68c930b2019-05-13 11:46:51 -0400502 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
khenaidood20a5852018-10-22 22:09:55 -0400503
khenaidoo89b0e942018-10-21 21:11:33 -0400504 // Augment the Actions
khenaidoo68c930b2019-05-13 11:46:51 -0400505 filteredAction := fu.GetActions(flow, fu.GROUP)
506 filteredAction = append(filteredAction, fu.PopVlan())
507 filteredAction = append(filteredAction, fu.Output(route2[1].Ingress))
khenaidood20a5852018-10-22 22:09:55 -0400508 fa.Actions = filteredAction
509
khenaidoo89b0e942018-10-21 21:11:33 -0400510 fg := fu.NewFlowsAndGroups()
khenaidoo68c930b2019-05-13 11:46:51 -0400511 fg.AddFlow(fu.MkFlowStat(fa))
khenaidood20a5852018-10-22 22:09:55 -0400512 deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -0400513
514 // Set the child device flow
515 fa = &fu.FlowArgs{
516 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
517 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -0400518 fu.InPort(egressHop.Ingress),
khenaidoo89b0e942018-10-21 21:11:33 -0400519 },
520 }
521 // Augment the matchfields with the ofpfields from the flow
khenaidoo68c930b2019-05-13 11:46:51 -0400522 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT, fu.VLAN_VID, fu.VLAN_PCP)...)
khenaidood20a5852018-10-22 22:09:55 -0400523
khenaidoo89b0e942018-10-21 21:11:33 -0400524 // Augment the Actions
khenaidoo68c930b2019-05-13 11:46:51 -0400525 otherActions = append(otherActions, fu.Output(egressHop.Egress))
khenaidoo89b0e942018-10-21 21:11:33 -0400526 fa.Actions = otherActions
khenaidood20a5852018-10-22 22:09:55 -0400527
khenaidoo89b0e942018-10-21 21:11:33 -0400528 fg = fu.NewFlowsAndGroups()
khenaidoo68c930b2019-05-13 11:46:51 -0400529 fg.AddFlow(fu.MkFlowStat(fa))
khenaidood20a5852018-10-22 22:09:55 -0400530 deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -0400531 }
532 return deviceRules
533}
534
khenaidood20a5852018-10-22 22:09:55 -0400535// decomposeFlow decomposes a flow for a logical device into flows for each physical device
536func (fd *FlowDecomposer) decomposeFlow(agent coreIf.LogicalDeviceAgent, flow *ofp.OfpFlowStats,
537 groupMap map[uint32]*ofp.OfpGroupEntry) *fu.DeviceRules {
538
khenaidoo68c930b2019-05-13 11:46:51 -0400539 inPortNo := fu.GetInPort(flow)
540 outPortNo := fu.GetOutPort(flow)
khenaidoo89b0e942018-10-21 21:11:33 -0400541 deviceRules := fu.NewDeviceRules()
khenaidoo19d7b632018-10-30 10:49:50 -0400542 route := agent.GetRoute(inPortNo, outPortNo)
khenaidoo2c6a0992019-04-29 13:46:56 -0400543
khenaidoo89b0e942018-10-21 21:11:33 -0400544 switch len(route) {
545 case 0:
546 log.Errorw("no-route", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo, "comment": "deleting-flow"})
547 // TODO: Delete flow
548 return deviceRules
549 case 2:
550 log.Debugw("route-found", log.Fields{"ingressHop": route[0], "egressHop": route[1]})
551 break
552 default:
553 log.Errorw("invalid-route-length", log.Fields{"routeLen": len(route)})
554 return deviceRules
555 }
556
khenaidoo89b0e942018-10-21 21:11:33 -0400557 // Process controller bound flow
558 if outPortNo != 0 && (outPortNo&0x7fffffff) == uint32(ofp.OfpPortNo_OFPP_CONTROLLER) {
khenaidood20a5852018-10-22 22:09:55 -0400559 deviceRules = fd.processControllerBoundFlow(agent, route, inPortNo, outPortNo, flow)
khenaidoo89b0e942018-10-21 21:11:33 -0400560 } else {
khenaidoo297cd252019-02-07 22:10:23 -0500561 var ingressDevice *voltha.Device
562 var err error
563 if ingressDevice, err = fd.deviceMgr.GetDevice(route[0].DeviceID); err != nil {
564 log.Errorw("ingress-device-not-found", log.Fields{"deviceId": route[0].DeviceID, "flow": flow})
565 return deviceRules
566 }
567 isUpstream := !ingressDevice.Root
khenaidoo89b0e942018-10-21 21:11:33 -0400568 if isUpstream {
khenaidood20a5852018-10-22 22:09:55 -0400569 deviceRules = fd.processUpstreamNonControllerBoundFlow(agent, route, inPortNo, outPortNo, flow)
khenaidoo68c930b2019-05-13 11:46:51 -0400570 } else if fu.HasNextTable(flow) {
khenaidood20a5852018-10-22 22:09:55 -0400571 deviceRules = fd.processDownstreamFlowWithNextTable(agent, route, inPortNo, outPortNo, flow)
khenaidoo89b0e942018-10-21 21:11:33 -0400572 } else if outPortNo != 0 { // Unicast
khenaidood20a5852018-10-22 22:09:55 -0400573 deviceRules = fd.processUnicastFlow(agent, route, inPortNo, outPortNo, flow)
khenaidoo68c930b2019-05-13 11:46:51 -0400574 } else if grpId := fu.GetGroup(flow); grpId != 0 { //Multicast
khenaidood20a5852018-10-22 22:09:55 -0400575 deviceRules = fd.processMulticastFlow(agent, route, inPortNo, outPortNo, flow, grpId, groupMap)
khenaidoo89b0e942018-10-21 21:11:33 -0400576 }
577 }
khenaidoo19d7b632018-10-30 10:49:50 -0400578 deviceRules = fd.updateOutputPortForControllerBoundFlowForParentDevide(flow, deviceRules)
khenaidoo89b0e942018-10-21 21:11:33 -0400579 return deviceRules
580}