blob: 98d509291bf791edd78019a253d9491f9a0dce7e [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
khenaidoo3306c992019-05-24 16:57:35 -040044func (fd *FlowDecomposer) DecomposeRules(agent coreIf.LogicalDeviceAgent, flows ofp.Flows, groups ofp.FlowGroups) *fu.DeviceRules {
45 deviceRules := *fu.NewDeviceRules()
khenaidoo2c6a0992019-04-29 13:46:56 -040046 devicesToUpdate := make(map[string]string)
khenaidoo89b0e942018-10-21 21:11:33 -040047
48 groupMap := make(map[uint32]*ofp.OfpGroupEntry)
49 for _, groupEntry := range groups.Items {
50 groupMap[groupEntry.Desc.GroupId] = groupEntry
51 }
52
53 var decomposedRules *fu.DeviceRules
54 for _, flow := range flows.Items {
55 decomposedRules = fd.decomposeFlow(agent, flow, groupMap)
56 for deviceId, flowAndGroups := range decomposedRules.Rules {
khenaidood20a5852018-10-22 22:09:55 -040057 deviceRules.CreateEntryIfNotExist(deviceId)
khenaidoo89b0e942018-10-21 21:11:33 -040058 deviceRules.Rules[deviceId].AddFrom(flowAndGroups)
khenaidoo2c6a0992019-04-29 13:46:56 -040059 devicesToUpdate[deviceId] = deviceId
khenaidoo89b0e942018-10-21 21:11:33 -040060 }
61 }
khenaidoo3306c992019-05-24 16:57:35 -040062 return deviceRules.FilterRules(devicesToUpdate)
khenaidoo89b0e942018-10-21 21:11:33 -040063}
64
khenaidoo19d7b632018-10-30 10:49:50 -040065// Handles special case of any controller-bound flow for a parent device
66func (fd *FlowDecomposer) updateOutputPortForControllerBoundFlowForParentDevide(flow *ofp.OfpFlowStats,
67 dr *fu.DeviceRules) *fu.DeviceRules {
khenaidoo68c930b2019-05-13 11:46:51 -040068 EAPOL := fu.EthType(0x888e)
69 IGMP := fu.IpProto(2)
70 UDP := fu.IpProto(17)
khenaidoo19d7b632018-10-30 10:49:50 -040071
72 newDeviceRules := dr.Copy()
73 // Check whether we are dealing with a parent device
74 for deviceId, fg := range dr.GetRules() {
75 if root, _ := fd.deviceMgr.IsRootDevice(deviceId); root {
76 newDeviceRules.ClearFlows(deviceId)
77 for i := 0; i < fg.Flows.Len(); i++ {
78 f := fg.GetFlow(i)
79 UpdateOutPortNo := false
khenaidoo68c930b2019-05-13 11:46:51 -040080 for _, field := range fu.GetOfbFields(f) {
khenaidoo19d7b632018-10-30 10:49:50 -040081 UpdateOutPortNo = (field.String() == EAPOL.String())
82 UpdateOutPortNo = UpdateOutPortNo || (field.String() == IGMP.String())
83 UpdateOutPortNo = UpdateOutPortNo || (field.String() == UDP.String())
84 if UpdateOutPortNo {
85 break
86 }
87 }
88 if UpdateOutPortNo {
khenaidoo68c930b2019-05-13 11:46:51 -040089 f = fu.UpdateOutputPortByActionType(f, uint32(ofp.OfpInstructionType_OFPIT_APPLY_ACTIONS),
khenaidoo19d7b632018-10-30 10:49:50 -040090 uint32(ofp.OfpPortNo_OFPP_CONTROLLER))
91 }
92 // Update flow Id as a change in the instruction field will result in a new flow ID
khenaidoo68c930b2019-05-13 11:46:51 -040093 f.Id = fu.HashFlowStats(f)
khenaidoo19d7b632018-10-30 10:49:50 -040094 newDeviceRules.AddFlow(deviceId, (proto.Clone(f)).(*ofp.OfpFlowStats))
95 }
96 }
97 }
khenaidoo2c6a0992019-04-29 13:46:56 -040098
khenaidoo19d7b632018-10-30 10:49:50 -040099 return newDeviceRules
100}
101
khenaidood20a5852018-10-22 22:09:55 -0400102//processControllerBoundFlow decomposes trap flows
103func (fd *FlowDecomposer) processControllerBoundFlow(agent coreIf.LogicalDeviceAgent, route []graph.RouteHop,
104 inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats) *fu.DeviceRules {
105
khenaidoo89b0e942018-10-21 21:11:33 -0400106 log.Debugw("trap-flow", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo, "flow": flow})
khenaidood20a5852018-10-22 22:09:55 -0400107 deviceRules := fu.NewDeviceRules()
108
109 egressHop := route[1]
110
khenaidoo89b0e942018-10-21 21:11:33 -0400111 fg := fu.NewFlowsAndGroups()
112 if agent.GetDeviceGraph().IsRootPort(inPortNo) {
113 log.Debug("trap-nni")
khenaidoo8f474192019-04-03 17:20:44 -0400114 // no decomposition required - it is already an OLT flow from NNI
115 fg.AddFlow(flow)
khenaidoo89b0e942018-10-21 21:11:33 -0400116 } else {
117 // Trap flow for UNI port
118 log.Debug("trap-uni")
119
120 //inPortNo is 0 for wildcard input case, do not include upstream port for 4000 flow in input
121 var inPorts []uint32
122 if inPortNo == 0 {
khenaidood20a5852018-10-22 22:09:55 -0400123 inPorts = agent.GetWildcardInputPorts(egressHop.Egress) // exclude egress_hop.egress_port.port_no
khenaidoo89b0e942018-10-21 21:11:33 -0400124 } else {
125 inPorts = []uint32{inPortNo}
126 }
127 for _, inputPort := range inPorts {
128 var fa *fu.FlowArgs
129 // Upstream flow
130 fa = &fu.FlowArgs{
131 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
132 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -0400133 fu.InPort(egressHop.Ingress),
134 fu.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | inputPort),
135 fu.TunnelId(uint64(inputPort)),
khenaidoo89b0e942018-10-21 21:11:33 -0400136 },
137 Actions: []*ofp.OfpAction{
khenaidoo68c930b2019-05-13 11:46:51 -0400138 fu.PushVlan(0x8100),
139 fu.SetField(fu.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 4000)),
140 fu.Output(egressHop.Egress),
khenaidoo89b0e942018-10-21 21:11:33 -0400141 },
142 }
143 // Augment the matchfields with the ofpfields from the flow
khenaidoo68c930b2019-05-13 11:46:51 -0400144 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT, fu.VLAN_VID)...)
145 fg.AddFlow(fu.MkFlowStat(fa))
khenaidoo89b0e942018-10-21 21:11:33 -0400146
147 // Downstream flow
148 fa = &fu.FlowArgs{
149 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority)},
150 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -0400151 fu.InPort(egressHop.Egress),
152 fu.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 4000),
153 fu.VlanPcp(0),
154 fu.Metadata_ofp(uint64(inputPort)),
155 fu.TunnelId(uint64(inputPort)),
khenaidoo89b0e942018-10-21 21:11:33 -0400156 },
157 Actions: []*ofp.OfpAction{
khenaidoo68c930b2019-05-13 11:46:51 -0400158 fu.PopVlan(),
159 fu.Output(egressHop.Ingress),
khenaidoo89b0e942018-10-21 21:11:33 -0400160 },
161 }
khenaidoo68c930b2019-05-13 11:46:51 -0400162 fg.AddFlow(fu.MkFlowStat(fa))
khenaidoo89b0e942018-10-21 21:11:33 -0400163 }
164 }
khenaidood20a5852018-10-22 22:09:55 -0400165 deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fg)
khenaidoo2c6a0992019-04-29 13:46:56 -0400166
khenaidoo89b0e942018-10-21 21:11:33 -0400167 return deviceRules
168}
169
170// processUpstreamNonControllerBoundFlow processes non-controller bound flow. We assume that anything that is
171// upstream needs to get Q-in-Q treatment and that this is expressed via two flow rules, the first using the
172// goto-statement. We also assume that the inner tag is applied at the ONU, while the outer tag is
173// applied at the OLT
khenaidood20a5852018-10-22 22:09:55 -0400174func (fd *FlowDecomposer) processUpstreamNonControllerBoundFlow(agent coreIf.LogicalDeviceAgent,
175 route []graph.RouteHop, inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats) *fu.DeviceRules {
176
khenaidoo89b0e942018-10-21 21:11:33 -0400177 log.Debugw("upstream-non-controller-bound-flow", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo})
khenaidood20a5852018-10-22 22:09:55 -0400178 deviceRules := fu.NewDeviceRules()
179
180 ingressHop := route[0]
181 egressHop := route[1]
182
khenaidoo68c930b2019-05-13 11:46:51 -0400183 if fu.HasNextTable(flow) {
khenaidoo89b0e942018-10-21 21:11:33 -0400184 log.Debugw("has-next-table", log.Fields{"table_id": flow.TableId})
185 if outPortNo != 0 {
186 log.Warnw("outPort-should-not-be-specified", log.Fields{"outPortNo": outPortNo})
187 }
188 var fa *fu.FlowArgs
189 fa = &fu.FlowArgs{
190 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
191 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -0400192 fu.InPort(ingressHop.Ingress),
193 fu.TunnelId(uint64(inPortNo)),
khenaidoo89b0e942018-10-21 21:11:33 -0400194 },
khenaidoo68c930b2019-05-13 11:46:51 -0400195 Actions: fu.GetActions(flow),
khenaidoo89b0e942018-10-21 21:11:33 -0400196 }
197 // Augment the matchfields with the ofpfields from the flow
khenaidoo68c930b2019-05-13 11:46:51 -0400198 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
khenaidood20a5852018-10-22 22:09:55 -0400199
200 // Augment the Actions
khenaidoo68c930b2019-05-13 11:46:51 -0400201 fa.Actions = append(fa.Actions, fu.Output(ingressHop.Egress))
khenaidood20a5852018-10-22 22:09:55 -0400202
khenaidoo89b0e942018-10-21 21:11:33 -0400203 fg := fu.NewFlowsAndGroups()
khenaidoo68c930b2019-05-13 11:46:51 -0400204 fg.AddFlow(fu.MkFlowStat(fa))
khenaidood20a5852018-10-22 22:09:55 -0400205 deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -0400206 } else {
207 var actions []ofp.OfpActionType
208 var isOutputTypeInActions bool
khenaidoo68c930b2019-05-13 11:46:51 -0400209 for _, action := range fu.GetActions(flow) {
khenaidoo89b0e942018-10-21 21:11:33 -0400210 actions = append(actions, action.Type)
khenaidoo68c930b2019-05-13 11:46:51 -0400211 if !isOutputTypeInActions && action.Type == fu.OUTPUT {
khenaidoo89b0e942018-10-21 21:11:33 -0400212 isOutputTypeInActions = true
213 }
214 }
215 if len(actions) == 1 && isOutputTypeInActions {
216 var fa *fu.FlowArgs
217 // child device flow
218 fa = &fu.FlowArgs{
219 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
220 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -0400221 fu.InPort(ingressHop.Ingress),
khenaidoo89b0e942018-10-21 21:11:33 -0400222 },
223 Actions: []*ofp.OfpAction{
khenaidoo68c930b2019-05-13 11:46:51 -0400224 fu.Output(ingressHop.Egress),
khenaidoo89b0e942018-10-21 21:11:33 -0400225 },
226 }
227 // Augment the matchfields with the ofpfields from the flow
khenaidoo68c930b2019-05-13 11:46:51 -0400228 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
khenaidoo89b0e942018-10-21 21:11:33 -0400229 fg := fu.NewFlowsAndGroups()
khenaidoo68c930b2019-05-13 11:46:51 -0400230 fg.AddFlow(fu.MkFlowStat(fa))
khenaidood20a5852018-10-22 22:09:55 -0400231 deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -0400232
233 // parent device flow
234 fa = &fu.FlowArgs{
235 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
236 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -0400237 fu.InPort(egressHop.Ingress), //egress_hop.ingress_port.port_no
238 fu.TunnelId(uint64(inPortNo)),
khenaidoo89b0e942018-10-21 21:11:33 -0400239 },
240 Actions: []*ofp.OfpAction{
khenaidoo68c930b2019-05-13 11:46:51 -0400241 fu.Output(egressHop.Egress),
khenaidoo89b0e942018-10-21 21:11:33 -0400242 },
243 }
244 // Augment the matchfields with the ofpfields from the flow
khenaidoo68c930b2019-05-13 11:46:51 -0400245 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
khenaidoo89b0e942018-10-21 21:11:33 -0400246 fg = fu.NewFlowsAndGroups()
khenaidoo68c930b2019-05-13 11:46:51 -0400247 fg.AddFlow(fu.MkFlowStat(fa))
khenaidood20a5852018-10-22 22:09:55 -0400248 deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -0400249 } else {
250 if outPortNo == 0 {
251 log.Warnw("outPort-should-be-specified", log.Fields{"outPortNo": outPortNo})
252 }
253 var fa *fu.FlowArgs
254 fa = &fu.FlowArgs{
255 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
256 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -0400257 fu.InPort(egressHop.Ingress),
258 fu.TunnelId(uint64(inPortNo)),
khenaidoo89b0e942018-10-21 21:11:33 -0400259 },
260 }
261 // Augment the matchfields with the ofpfields from the flow
khenaidoo68c930b2019-05-13 11:46:51 -0400262 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
khenaidood20a5852018-10-22 22:09:55 -0400263
264 //Augment the actions
khenaidoo68c930b2019-05-13 11:46:51 -0400265 filteredAction := fu.GetActions(flow, fu.OUTPUT)
266 filteredAction = append(filteredAction, fu.Output(egressHop.Egress))
khenaidood20a5852018-10-22 22:09:55 -0400267 fa.Actions = filteredAction
268
khenaidoo89b0e942018-10-21 21:11:33 -0400269 fg := fu.NewFlowsAndGroups()
khenaidoo68c930b2019-05-13 11:46:51 -0400270 fg.AddFlow(fu.MkFlowStat(fa))
khenaidood20a5852018-10-22 22:09:55 -0400271 deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -0400272 }
273 }
274 return deviceRules
275}
276
khenaidood20a5852018-10-22 22:09:55 -0400277// processDownstreamFlowWithNextTable decomposes downstream flows containing next table ID instructions
278func (fd *FlowDecomposer) processDownstreamFlowWithNextTable(agent coreIf.LogicalDeviceAgent, route []graph.RouteHop,
279 inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats) *fu.DeviceRules {
280
khenaidoo89b0e942018-10-21 21:11:33 -0400281 log.Debugw("downstream-flow-with-next-table", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo})
khenaidood20a5852018-10-22 22:09:55 -0400282 deviceRules := fu.NewDeviceRules()
283
khenaidoo89b0e942018-10-21 21:11:33 -0400284 if outPortNo != 0 {
285 log.Warnw("outPort-should-not-be-specified", log.Fields{"outPortNo": outPortNo})
286 }
287 ingressHop := route[0]
khenaidood20a5852018-10-22 22:09:55 -0400288 egressHop := route[1]
289
khenaidoo68c930b2019-05-13 11:46:51 -0400290 if fu.GetMetaData(flow) != 0 {
khenaidoo89b0e942018-10-21 21:11:33 -0400291 log.Debugw("creating-metadata-flow", log.Fields{"flow": flow})
khenaidoo68c930b2019-05-13 11:46:51 -0400292 portNumber := uint32(fu.GetPortNumberFromMetadata(flow))
khenaidoo89b0e942018-10-21 21:11:33 -0400293 if portNumber != 0 {
khenaidoo19d7b632018-10-30 10:49:50 -0400294 recalculatedRoute := agent.GetRoute(inPortNo, portNumber)
khenaidoo89b0e942018-10-21 21:11:33 -0400295 switch len(recalculatedRoute) {
296 case 0:
khenaidoo68c930b2019-05-13 11:46:51 -0400297 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 -0400298 // TODO: Delete flow
299 return deviceRules
300 case 2:
khenaidood20a5852018-10-22 22:09:55 -0400301 log.Debugw("route-found", log.Fields{"ingressHop": ingressHop, "egressHop": egressHop})
khenaidoo89b0e942018-10-21 21:11:33 -0400302 break
303 default:
304 log.Errorw("invalid-route-length", log.Fields{"routeLen": len(route)})
305 return deviceRules
306 }
307 ingressHop = recalculatedRoute[0]
308 }
khenaidoo68c930b2019-05-13 11:46:51 -0400309 innerTag := fu.GetInnerTagFromMetaData(flow)
khenaidoo89b0e942018-10-21 21:11:33 -0400310 if innerTag == 0 {
khenaidoo68c930b2019-05-13 11:46:51 -0400311 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 -0400312 // TODO: Delete flow
313 return deviceRules
314 }
315 var fa *fu.FlowArgs
316 fa = &fu.FlowArgs{
317 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
318 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -0400319 fu.InPort(ingressHop.Ingress),
320 fu.Metadata_ofp(innerTag),
321 fu.TunnelId(uint64(portNumber)),
khenaidoo89b0e942018-10-21 21:11:33 -0400322 },
khenaidoo68c930b2019-05-13 11:46:51 -0400323 Actions: fu.GetActions(flow),
khenaidoo89b0e942018-10-21 21:11:33 -0400324 }
325 // Augment the matchfields with the ofpfields from the flow
khenaidoo68c930b2019-05-13 11:46:51 -0400326 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT, fu.METADATA)...)
khenaidood20a5852018-10-22 22:09:55 -0400327
328 // Augment the Actions
khenaidoo68c930b2019-05-13 11:46:51 -0400329 fa.Actions = append(fa.Actions, fu.Output(ingressHop.Egress))
khenaidood20a5852018-10-22 22:09:55 -0400330
khenaidoo89b0e942018-10-21 21:11:33 -0400331 fg := fu.NewFlowsAndGroups()
khenaidoo68c930b2019-05-13 11:46:51 -0400332 fg.AddFlow(fu.MkFlowStat(fa))
khenaidoo89b0e942018-10-21 21:11:33 -0400333 deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fg)
334 } else { // Create standard flow
335 log.Debugw("creating-standard-flow", log.Fields{"flow": flow})
336 var fa *fu.FlowArgs
337 fa = &fu.FlowArgs{
338 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
339 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -0400340 fu.InPort(ingressHop.Ingress),
341 fu.TunnelId(uint64(inPortNo)),
khenaidoo89b0e942018-10-21 21:11:33 -0400342 },
khenaidoo68c930b2019-05-13 11:46:51 -0400343 Actions: fu.GetActions(flow),
khenaidoo89b0e942018-10-21 21:11:33 -0400344 }
345 // Augment the matchfields with the ofpfields from the flow
khenaidoo68c930b2019-05-13 11:46:51 -0400346 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
khenaidood20a5852018-10-22 22:09:55 -0400347
348 // Augment the Actions
khenaidoo68c930b2019-05-13 11:46:51 -0400349 fa.Actions = append(fa.Actions, fu.Output(ingressHop.Egress))
khenaidood20a5852018-10-22 22:09:55 -0400350
khenaidoo89b0e942018-10-21 21:11:33 -0400351 fg := fu.NewFlowsAndGroups()
khenaidoo68c930b2019-05-13 11:46:51 -0400352 fg.AddFlow(fu.MkFlowStat(fa))
khenaidoo89b0e942018-10-21 21:11:33 -0400353 deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fg)
354 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400355
khenaidoo89b0e942018-10-21 21:11:33 -0400356 return deviceRules
357}
358
khenaidood20a5852018-10-22 22:09:55 -0400359// processUnicastFlow decomposes unicast flows
360func (fd *FlowDecomposer) processUnicastFlow(agent coreIf.LogicalDeviceAgent, route []graph.RouteHop,
361 inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats) *fu.DeviceRules {
362
khenaidoo89b0e942018-10-21 21:11:33 -0400363 log.Debugw("unicast-flow", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo})
khenaidood20a5852018-10-22 22:09:55 -0400364 deviceRules := fu.NewDeviceRules()
365
366 ingressHop := route[0]
367 egressHop := route[1]
368
khenaidoo89b0e942018-10-21 21:11:33 -0400369 var actions []ofp.OfpActionType
370 var isOutputTypeInActions bool
khenaidoo68c930b2019-05-13 11:46:51 -0400371 for _, action := range fu.GetActions(flow) {
khenaidoo89b0e942018-10-21 21:11:33 -0400372 actions = append(actions, action.Type)
khenaidoo68c930b2019-05-13 11:46:51 -0400373 if !isOutputTypeInActions && action.Type == fu.OUTPUT {
khenaidoo89b0e942018-10-21 21:11:33 -0400374 isOutputTypeInActions = true
375 }
376 }
377 if len(actions) == 1 && isOutputTypeInActions {
378 var fa *fu.FlowArgs
379 // Parent device flow
380 fa = &fu.FlowArgs{
381 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
382 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -0400383 fu.InPort(ingressHop.Ingress),
384 fu.TunnelId(uint64(inPortNo)),
khenaidoo89b0e942018-10-21 21:11:33 -0400385 },
386 Actions: []*ofp.OfpAction{
khenaidoo68c930b2019-05-13 11:46:51 -0400387 fu.Output(ingressHop.Egress),
khenaidoo89b0e942018-10-21 21:11:33 -0400388 },
389 }
390 // Augment the matchfields with the ofpfields from the flow
khenaidoo68c930b2019-05-13 11:46:51 -0400391 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
khenaidood20a5852018-10-22 22:09:55 -0400392
khenaidoo89b0e942018-10-21 21:11:33 -0400393 fg := fu.NewFlowsAndGroups()
khenaidoo68c930b2019-05-13 11:46:51 -0400394 fg.AddFlow(fu.MkFlowStat(fa))
khenaidood20a5852018-10-22 22:09:55 -0400395 deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -0400396
397 // Child device flow
398 fa = &fu.FlowArgs{
399 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
400 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -0400401 fu.InPort(egressHop.Ingress),
khenaidoo89b0e942018-10-21 21:11:33 -0400402 },
403 Actions: []*ofp.OfpAction{
khenaidoo68c930b2019-05-13 11:46:51 -0400404 fu.Output(egressHop.Egress),
khenaidoo89b0e942018-10-21 21:11:33 -0400405 },
406 }
407 // Augment the matchfields with the ofpfields from the flow
khenaidoo68c930b2019-05-13 11:46:51 -0400408 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
khenaidood20a5852018-10-22 22:09:55 -0400409
khenaidoo89b0e942018-10-21 21:11:33 -0400410 fg = fu.NewFlowsAndGroups()
khenaidoo68c930b2019-05-13 11:46:51 -0400411 fg.AddFlow(fu.MkFlowStat(fa))
khenaidood20a5852018-10-22 22:09:55 -0400412 deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -0400413 } else {
414 var fa *fu.FlowArgs
415 fa = &fu.FlowArgs{
416 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
417 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -0400418 fu.InPort(egressHop.Ingress),
khenaidoo89b0e942018-10-21 21:11:33 -0400419 },
420 }
421 // Augment the matchfields with the ofpfields from the flow
khenaidoo68c930b2019-05-13 11:46:51 -0400422 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
khenaidood20a5852018-10-22 22:09:55 -0400423
khenaidoo89b0e942018-10-21 21:11:33 -0400424 // Augment the Actions
khenaidoo68c930b2019-05-13 11:46:51 -0400425 filteredAction := fu.GetActions(flow, fu.OUTPUT)
426 filteredAction = append(filteredAction, fu.Output(egressHop.Egress))
khenaidood20a5852018-10-22 22:09:55 -0400427 fa.Actions = filteredAction
428
khenaidoo89b0e942018-10-21 21:11:33 -0400429 fg := fu.NewFlowsAndGroups()
khenaidoo68c930b2019-05-13 11:46:51 -0400430 fg.AddFlow(fu.MkFlowStat(fa))
khenaidood20a5852018-10-22 22:09:55 -0400431 deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -0400432 }
433 return deviceRules
434}
435
khenaidood20a5852018-10-22 22:09:55 -0400436// processMulticastFlow decompose multicast flows
437func (fd *FlowDecomposer) processMulticastFlow(agent coreIf.LogicalDeviceAgent, route []graph.RouteHop,
438 inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats, grpId uint32,
439 groupMap map[uint32]*ofp.OfpGroupEntry) *fu.DeviceRules {
440
khenaidoo89b0e942018-10-21 21:11:33 -0400441 log.Debugw("multicast-flow", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo})
khenaidood20a5852018-10-22 22:09:55 -0400442 deviceRules := fu.NewDeviceRules()
khenaidoo89b0e942018-10-21 21:11:33 -0400443
444 //having no Group yet is the same as having a Group with no buckets
445 var grp *ofp.OfpGroupEntry
446 var ok bool
447 if grp, ok = groupMap[grpId]; !ok {
448 log.Warnw("Group-id-not-present-in-map", log.Fields{"grpId": grpId, "groupMap": groupMap})
449 return deviceRules
450 }
451 if grp == nil || grp.Desc == nil {
452 log.Warnw("Group-or-desc-nil", log.Fields{"grpId": grpId, "grp": grp})
453 return deviceRules
454 }
455 for _, bucket := range grp.Desc.Buckets {
456 otherActions := make([]*ofp.OfpAction, 0)
457 for _, action := range bucket.Actions {
khenaidoo68c930b2019-05-13 11:46:51 -0400458 if action.Type == fu.OUTPUT {
khenaidoo89b0e942018-10-21 21:11:33 -0400459 outPortNo = action.GetOutput().Port
khenaidoo68c930b2019-05-13 11:46:51 -0400460 } else if action.Type != fu.POP_VLAN {
khenaidoo89b0e942018-10-21 21:11:33 -0400461 otherActions = append(otherActions, action)
462 }
463 }
464
khenaidoo19d7b632018-10-30 10:49:50 -0400465 route2 := agent.GetRoute(inPortNo, outPortNo)
khenaidoo89b0e942018-10-21 21:11:33 -0400466 switch len(route2) {
467 case 0:
468 log.Errorw("mc-no-route", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo, "comment": "deleting flow"})
469 // TODO: Delete flow
470 return deviceRules
471 case 2:
khenaidood20a5852018-10-22 22:09:55 -0400472 log.Debugw("route-found", log.Fields{"ingressHop": route2[0], "egressHop": route2[1]})
khenaidoo89b0e942018-10-21 21:11:33 -0400473 break
474 default:
475 log.Errorw("invalid-route-length", log.Fields{"routeLen": len(route)})
476 return deviceRules
477 }
478
khenaidood20a5852018-10-22 22:09:55 -0400479 ingressHop := route[0]
480 ingressHop2 := route2[0]
481 egressHop := route2[1]
482
483 if ingressHop.Ingress != ingressHop2.Ingress {
khenaidoo89b0e942018-10-21 21:11:33 -0400484 log.Errorw("mc-ingress-hop-hop2-mismatch", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo, "comment": "ignoring flow"})
485 return deviceRules
486 }
487 // Set the parent device flow
488 var fa *fu.FlowArgs
489 fa = &fu.FlowArgs{
490 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
491 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -0400492 fu.InPort(ingressHop.Ingress),
khenaidoo89b0e942018-10-21 21:11:33 -0400493 },
494 }
495 // Augment the matchfields with the ofpfields from the flow
khenaidoo68c930b2019-05-13 11:46:51 -0400496 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
khenaidood20a5852018-10-22 22:09:55 -0400497
khenaidoo89b0e942018-10-21 21:11:33 -0400498 // Augment the Actions
khenaidoo68c930b2019-05-13 11:46:51 -0400499 filteredAction := fu.GetActions(flow, fu.GROUP)
500 filteredAction = append(filteredAction, fu.PopVlan())
501 filteredAction = append(filteredAction, fu.Output(route2[1].Ingress))
khenaidood20a5852018-10-22 22:09:55 -0400502 fa.Actions = filteredAction
503
khenaidoo89b0e942018-10-21 21:11:33 -0400504 fg := fu.NewFlowsAndGroups()
khenaidoo68c930b2019-05-13 11:46:51 -0400505 fg.AddFlow(fu.MkFlowStat(fa))
khenaidood20a5852018-10-22 22:09:55 -0400506 deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -0400507
508 // Set the child device flow
509 fa = &fu.FlowArgs{
510 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
511 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -0400512 fu.InPort(egressHop.Ingress),
khenaidoo89b0e942018-10-21 21:11:33 -0400513 },
514 }
515 // Augment the matchfields with the ofpfields from the flow
khenaidoo68c930b2019-05-13 11:46:51 -0400516 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT, fu.VLAN_VID, fu.VLAN_PCP)...)
khenaidood20a5852018-10-22 22:09:55 -0400517
khenaidoo89b0e942018-10-21 21:11:33 -0400518 // Augment the Actions
khenaidoo68c930b2019-05-13 11:46:51 -0400519 otherActions = append(otherActions, fu.Output(egressHop.Egress))
khenaidoo89b0e942018-10-21 21:11:33 -0400520 fa.Actions = otherActions
khenaidood20a5852018-10-22 22:09:55 -0400521
khenaidoo89b0e942018-10-21 21:11:33 -0400522 fg = fu.NewFlowsAndGroups()
khenaidoo68c930b2019-05-13 11:46:51 -0400523 fg.AddFlow(fu.MkFlowStat(fa))
khenaidood20a5852018-10-22 22:09:55 -0400524 deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -0400525 }
526 return deviceRules
527}
528
khenaidood20a5852018-10-22 22:09:55 -0400529// decomposeFlow decomposes a flow for a logical device into flows for each physical device
530func (fd *FlowDecomposer) decomposeFlow(agent coreIf.LogicalDeviceAgent, flow *ofp.OfpFlowStats,
531 groupMap map[uint32]*ofp.OfpGroupEntry) *fu.DeviceRules {
532
khenaidoo68c930b2019-05-13 11:46:51 -0400533 inPortNo := fu.GetInPort(flow)
534 outPortNo := fu.GetOutPort(flow)
khenaidoo89b0e942018-10-21 21:11:33 -0400535 deviceRules := fu.NewDeviceRules()
khenaidoo19d7b632018-10-30 10:49:50 -0400536 route := agent.GetRoute(inPortNo, outPortNo)
khenaidoo2c6a0992019-04-29 13:46:56 -0400537
khenaidoo89b0e942018-10-21 21:11:33 -0400538 switch len(route) {
539 case 0:
540 log.Errorw("no-route", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo, "comment": "deleting-flow"})
541 // TODO: Delete flow
542 return deviceRules
543 case 2:
544 log.Debugw("route-found", log.Fields{"ingressHop": route[0], "egressHop": route[1]})
545 break
546 default:
547 log.Errorw("invalid-route-length", log.Fields{"routeLen": len(route)})
548 return deviceRules
549 }
550
khenaidoo89b0e942018-10-21 21:11:33 -0400551 // Process controller bound flow
552 if outPortNo != 0 && (outPortNo&0x7fffffff) == uint32(ofp.OfpPortNo_OFPP_CONTROLLER) {
khenaidood20a5852018-10-22 22:09:55 -0400553 deviceRules = fd.processControllerBoundFlow(agent, route, inPortNo, outPortNo, flow)
khenaidoo89b0e942018-10-21 21:11:33 -0400554 } else {
khenaidoo297cd252019-02-07 22:10:23 -0500555 var ingressDevice *voltha.Device
556 var err error
557 if ingressDevice, err = fd.deviceMgr.GetDevice(route[0].DeviceID); err != nil {
558 log.Errorw("ingress-device-not-found", log.Fields{"deviceId": route[0].DeviceID, "flow": flow})
559 return deviceRules
560 }
561 isUpstream := !ingressDevice.Root
khenaidoo89b0e942018-10-21 21:11:33 -0400562 if isUpstream {
khenaidood20a5852018-10-22 22:09:55 -0400563 deviceRules = fd.processUpstreamNonControllerBoundFlow(agent, route, inPortNo, outPortNo, flow)
khenaidoo68c930b2019-05-13 11:46:51 -0400564 } else if fu.HasNextTable(flow) {
khenaidood20a5852018-10-22 22:09:55 -0400565 deviceRules = fd.processDownstreamFlowWithNextTable(agent, route, inPortNo, outPortNo, flow)
khenaidoo89b0e942018-10-21 21:11:33 -0400566 } else if outPortNo != 0 { // Unicast
khenaidood20a5852018-10-22 22:09:55 -0400567 deviceRules = fd.processUnicastFlow(agent, route, inPortNo, outPortNo, flow)
khenaidoo68c930b2019-05-13 11:46:51 -0400568 } else if grpId := fu.GetGroup(flow); grpId != 0 { //Multicast
khenaidood20a5852018-10-22 22:09:55 -0400569 deviceRules = fd.processMulticastFlow(agent, route, inPortNo, outPortNo, flow, grpId, groupMap)
khenaidoo89b0e942018-10-21 21:11:33 -0400570 }
571 }
khenaidoo19d7b632018-10-30 10:49:50 -0400572 deviceRules = fd.updateOutputPortForControllerBoundFlowForParentDevide(flow, deviceRules)
khenaidoo89b0e942018-10-21 21:11:33 -0400573 return deviceRules
574}