blob: d28a803e9ddc45903c348fad549b7f8bc5ceecc8 [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/rw_core/coreIf"
22 "github.com/opencord/voltha-go/rw_core/graph"
23 fu "github.com/opencord/voltha-go/rw_core/utils"
Scott Bakercb7c88a2019-10-16 18:32:48 -070024 "github.com/opencord/voltha-lib-go/pkg/log"
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()
Manikkaraj kb1a10922019-07-29 12:10:34 -0400108 meterId := fu.GetMeterIdFromFlow(flow)
109 metadataFromwriteMetadata := fu.GetMetadataFromWriteMetadataAction(flow)
khenaidood20a5852018-10-22 22:09:55 -0400110
Matt Jeanneretb423bad2019-10-10 20:42:19 -0400111 ingressHop := route[0]
khenaidood20a5852018-10-22 22:09:55 -0400112 egressHop := route[1]
113
Humera Kouser4ff89012019-08-25 19:01:51 -0400114 //case of packet_in from NNI port rule
khenaidoo89b0e942018-10-21 21:11:33 -0400115 if agent.GetDeviceGraph().IsRootPort(inPortNo) {
Humera Kouser4ff89012019-08-25 19:01:51 -0400116 // Trap flow for NNI port
khenaidoo89b0e942018-10-21 21:11:33 -0400117 log.Debug("trap-nni")
Humera Kouser4ff89012019-08-25 19:01:51 -0400118
119 var fa *fu.FlowArgs
120 fa = &fu.FlowArgs{
121 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
122 MatchFields: []*ofp.OfpOxmOfbField{
123 fu.InPort(egressHop.Egress),
124 },
125 Actions: fu.GetActions(flow),
126 }
127 // Augment the matchfields with the ofpfields from the flow
Matt Jeanneretb423bad2019-10-10 20:42:19 -0400128 fg := fu.NewFlowsAndGroups()
Humera Kouser4ff89012019-08-25 19:01:51 -0400129 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
130 fg.AddFlow(fu.MkFlowStat(fa))
Matt Jeanneretb423bad2019-10-10 20:42:19 -0400131 deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -0400132 } else {
133 // Trap flow for UNI port
134 log.Debug("trap-uni")
135
136 //inPortNo is 0 for wildcard input case, do not include upstream port for 4000 flow in input
137 var inPorts []uint32
138 if inPortNo == 0 {
khenaidood20a5852018-10-22 22:09:55 -0400139 inPorts = agent.GetWildcardInputPorts(egressHop.Egress) // exclude egress_hop.egress_port.port_no
khenaidoo89b0e942018-10-21 21:11:33 -0400140 } else {
141 inPorts = []uint32{inPortNo}
142 }
143 for _, inputPort := range inPorts {
Matt Jeanneretb423bad2019-10-10 20:42:19 -0400144 // Upstream flow on parent (olt) device
145 var faParent *fu.FlowArgs
146 faParent = &fu.FlowArgs{
Manikkaraj kb1a10922019-07-29 12:10:34 -0400147 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie, "meter_id": uint64(meterId), "write_metadata": metadataFromwriteMetadata},
khenaidoo89b0e942018-10-21 21:11:33 -0400148 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -0400149 fu.InPort(egressHop.Ingress),
khenaidoo68c930b2019-05-13 11:46:51 -0400150 fu.TunnelId(uint64(inputPort)),
khenaidoo89b0e942018-10-21 21:11:33 -0400151 },
152 Actions: []*ofp.OfpAction{
khenaidoo68c930b2019-05-13 11:46:51 -0400153 fu.PushVlan(0x8100),
154 fu.SetField(fu.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 4000)),
155 fu.Output(egressHop.Egress),
khenaidoo89b0e942018-10-21 21:11:33 -0400156 },
157 }
158 // Augment the matchfields with the ofpfields from the flow
Matt Jeanneretb423bad2019-10-10 20:42:19 -0400159 faParent.MatchFields = append(faParent.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
160 fgParent := fu.NewFlowsAndGroups()
161 fgParent.AddFlow(fu.MkFlowStat(faParent))
162 deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fgParent)
163 log.Debugw("parent-trap-flow-set", log.Fields{"flow": faParent})
164
165 // Upstream flow on child (onu) device
166 var actions []*ofp.OfpAction
167 setvid := fu.GetVlanVid(flow)
168 if setvid != nil {
169 // have this child push the vlan the parent is matching/trapping on above
170 actions = []*ofp.OfpAction{
171 fu.PushVlan(0x8100),
172 fu.SetField(fu.VlanVid(*setvid)),
173 fu.Output(ingressHop.Egress),
174 }
175 } else {
176 // otherwise just set the egress port
177 actions = []*ofp.OfpAction{
178 fu.Output(ingressHop.Egress),
179 }
180 }
181 var faChild *fu.FlowArgs
182 faChild = &fu.FlowArgs{
183 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie, "meter_id": uint64(meterId), "write_metadata": metadataFromwriteMetadata},
184 MatchFields: []*ofp.OfpOxmOfbField{
185 fu.InPort(ingressHop.Ingress),
186 fu.TunnelId(uint64(inputPort)),
187 },
188 Actions: actions,
189 }
190 // Augment the matchfields with the ofpfields from the flow.
191 // If the parent has a match vid and the child is setting that match vid exclude the the match vlan
192 // for the child given it will be setting that vlan and the parent will be matching on it
193 if setvid != nil {
194 faChild.MatchFields = append(faChild.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT, fu.VLAN_VID)...)
195 } else {
196 faChild.MatchFields = append(faChild.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
197 }
198 fgChild := fu.NewFlowsAndGroups()
199 fgChild.AddFlow(fu.MkFlowStat(faChild))
200 deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fgChild)
201 log.Debugw("child-trap-flow-set", log.Fields{"flow": faChild})
khenaidoo89b0e942018-10-21 21:11:33 -0400202 }
203 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400204
khenaidoo89b0e942018-10-21 21:11:33 -0400205 return deviceRules
206}
207
208// processUpstreamNonControllerBoundFlow processes non-controller bound flow. We assume that anything that is
209// upstream needs to get Q-in-Q treatment and that this is expressed via two flow rules, the first using the
210// goto-statement. We also assume that the inner tag is applied at the ONU, while the outer tag is
211// applied at the OLT
khenaidood20a5852018-10-22 22:09:55 -0400212func (fd *FlowDecomposer) processUpstreamNonControllerBoundFlow(agent coreIf.LogicalDeviceAgent,
213 route []graph.RouteHop, inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats) *fu.DeviceRules {
214
khenaidoo89b0e942018-10-21 21:11:33 -0400215 log.Debugw("upstream-non-controller-bound-flow", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo})
khenaidood20a5852018-10-22 22:09:55 -0400216 deviceRules := fu.NewDeviceRules()
217
Manikkaraj kb1a10922019-07-29 12:10:34 -0400218 meterId := fu.GetMeterIdFromFlow(flow)
219 metadataFromwriteMetadata := fu.GetMetadataFromWriteMetadataAction(flow)
220
khenaidood20a5852018-10-22 22:09:55 -0400221 ingressHop := route[0]
222 egressHop := route[1]
223
Manikkaraj kb1a10922019-07-29 12:10:34 -0400224 if flow.TableId == 0 && fu.HasNextTable(flow) {
225 log.Debugw("decomposing-onu-flow-in-upstream-has-next-table", log.Fields{"table_id": flow.TableId})
khenaidoo89b0e942018-10-21 21:11:33 -0400226 if outPortNo != 0 {
227 log.Warnw("outPort-should-not-be-specified", log.Fields{"outPortNo": outPortNo})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400228 return deviceRules
khenaidoo89b0e942018-10-21 21:11:33 -0400229 }
230 var fa *fu.FlowArgs
231 fa = &fu.FlowArgs{
Manikkaraj kb1a10922019-07-29 12:10:34 -0400232 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie, "meter_id": uint64(meterId), "write_metadata": metadataFromwriteMetadata},
khenaidoo89b0e942018-10-21 21:11:33 -0400233 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -0400234 fu.InPort(ingressHop.Ingress),
235 fu.TunnelId(uint64(inPortNo)),
khenaidoo89b0e942018-10-21 21:11:33 -0400236 },
khenaidoo68c930b2019-05-13 11:46:51 -0400237 Actions: fu.GetActions(flow),
khenaidoo89b0e942018-10-21 21:11:33 -0400238 }
239 // Augment the matchfields with the ofpfields from the flow
khenaidoo68c930b2019-05-13 11:46:51 -0400240 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
khenaidood20a5852018-10-22 22:09:55 -0400241
242 // Augment the Actions
khenaidoo68c930b2019-05-13 11:46:51 -0400243 fa.Actions = append(fa.Actions, fu.Output(ingressHop.Egress))
khenaidood20a5852018-10-22 22:09:55 -0400244
khenaidoo89b0e942018-10-21 21:11:33 -0400245 fg := fu.NewFlowsAndGroups()
khenaidoo68c930b2019-05-13 11:46:51 -0400246 fg.AddFlow(fu.MkFlowStat(fa))
khenaidood20a5852018-10-22 22:09:55 -0400247 deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fg)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400248 } else if flow.TableId == 1 && outPortNo != 0 {
249 log.Debugw("decomposing-olt-flow-in-upstream-has-next-table", log.Fields{"table_id": flow.TableId})
250 var fa *fu.FlowArgs
251 fa = &fu.FlowArgs{
252 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie, "meter_id": uint64(meterId), "write_metadata": metadataFromwriteMetadata},
253 MatchFields: []*ofp.OfpOxmOfbField{
254 fu.InPort(egressHop.Ingress),
255 fu.TunnelId(uint64(inPortNo)),
256 },
khenaidoo89b0e942018-10-21 21:11:33 -0400257 }
Manikkaraj kb1a10922019-07-29 12:10:34 -0400258 // Augment the matchfields with the ofpfields from the flow
259 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
khenaidoo89b0e942018-10-21 21:11:33 -0400260
Manikkaraj kb1a10922019-07-29 12:10:34 -0400261 //Augment the actions
262 filteredAction := fu.GetActions(flow, fu.OUTPUT)
263 filteredAction = append(filteredAction, fu.Output(egressHop.Egress))
264 fa.Actions = filteredAction
khenaidood20a5852018-10-22 22:09:55 -0400265
Manikkaraj kb1a10922019-07-29 12:10:34 -0400266 fg := fu.NewFlowsAndGroups()
267 fg.AddFlow(fu.MkFlowStat(fa))
268 deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -0400269 }
270 return deviceRules
271}
272
khenaidood20a5852018-10-22 22:09:55 -0400273// processDownstreamFlowWithNextTable decomposes downstream flows containing next table ID instructions
274func (fd *FlowDecomposer) processDownstreamFlowWithNextTable(agent coreIf.LogicalDeviceAgent, route []graph.RouteHop,
275 inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats) *fu.DeviceRules {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400276 log.Debugw("decomposing-olt-flow-in-downstream-flow-with-next-table", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo})
khenaidood20a5852018-10-22 22:09:55 -0400277 deviceRules := fu.NewDeviceRules()
Manikkaraj kb1a10922019-07-29 12:10:34 -0400278 meterId := fu.GetMeterIdFromFlow(flow)
279 metadataFromwriteMetadata := fu.GetMetadataFromWriteMetadataAction(flow)
khenaidood20a5852018-10-22 22:09:55 -0400280
khenaidoo89b0e942018-10-21 21:11:33 -0400281 if outPortNo != 0 {
282 log.Warnw("outPort-should-not-be-specified", log.Fields{"outPortNo": outPortNo})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400283 return deviceRules
khenaidoo89b0e942018-10-21 21:11:33 -0400284 }
Manikkaraj kb1a10922019-07-29 12:10:34 -0400285
286 if flow.TableId != 0 {
287 log.Warnw("This is not olt pipeline table, so skipping", log.Fields{"tableId": flow.TableId})
288 return deviceRules
289 }
290
khenaidoo89b0e942018-10-21 21:11:33 -0400291 ingressHop := route[0]
khenaidood20a5852018-10-22 22:09:55 -0400292 egressHop := route[1]
Manikkaraj kb1a10922019-07-29 12:10:34 -0400293 if metadataFromwriteMetadata != 0 {
khenaidoo89b0e942018-10-21 21:11:33 -0400294 log.Debugw("creating-metadata-flow", log.Fields{"flow": flow})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400295 portNumber := fu.GetEgressPortNumberFromWriteMetadata(flow)
khenaidoo89b0e942018-10-21 21:11:33 -0400296 if portNumber != 0 {
khenaidoo19d7b632018-10-30 10:49:50 -0400297 recalculatedRoute := agent.GetRoute(inPortNo, portNumber)
khenaidoo89b0e942018-10-21 21:11:33 -0400298 switch len(recalculatedRoute) {
299 case 0:
Manikkaraj kb1a10922019-07-29 12:10:34 -0400300 log.Errorw("no-route-double-tag", log.Fields{"inPortNo": inPortNo, "outPortNo": portNumber, "comment": "deleting-flow", "metadata": metadataFromwriteMetadata})
301 //TODO: Delete flow
khenaidoo89b0e942018-10-21 21:11:33 -0400302 return deviceRules
303 case 2:
khenaidood20a5852018-10-22 22:09:55 -0400304 log.Debugw("route-found", log.Fields{"ingressHop": ingressHop, "egressHop": egressHop})
khenaidoo89b0e942018-10-21 21:11:33 -0400305 break
306 default:
307 log.Errorw("invalid-route-length", log.Fields{"routeLen": len(route)})
308 return deviceRules
309 }
310 ingressHop = recalculatedRoute[0]
311 }
khenaidoo68c930b2019-05-13 11:46:51 -0400312 innerTag := fu.GetInnerTagFromMetaData(flow)
khenaidoo89b0e942018-10-21 21:11:33 -0400313 if innerTag == 0 {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400314 log.Errorw("no-inner-route-double-tag", log.Fields{"inPortNo": inPortNo, "outPortNo": portNumber, "comment": "deleting-flow", "metadata": metadataFromwriteMetadata})
315 //TODO: Delete flow
khenaidoo89b0e942018-10-21 21:11:33 -0400316 return deviceRules
317 }
318 var fa *fu.FlowArgs
319 fa = &fu.FlowArgs{
Manikkaraj kb1a10922019-07-29 12:10:34 -0400320 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie, "meter_id": uint64(meterId), "write_metadata": metadataFromwriteMetadata},
khenaidoo89b0e942018-10-21 21:11:33 -0400321 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -0400322 fu.InPort(ingressHop.Ingress),
Manikkaraj kb1a10922019-07-29 12:10:34 -0400323 fu.Metadata_ofp(uint64(innerTag)),
khenaidoo68c930b2019-05-13 11:46:51 -0400324 fu.TunnelId(uint64(portNumber)),
khenaidoo89b0e942018-10-21 21:11:33 -0400325 },
khenaidoo68c930b2019-05-13 11:46:51 -0400326 Actions: fu.GetActions(flow),
khenaidoo89b0e942018-10-21 21:11:33 -0400327 }
328 // Augment the matchfields with the ofpfields from the flow
khenaidoo68c930b2019-05-13 11:46:51 -0400329 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT, fu.METADATA)...)
khenaidood20a5852018-10-22 22:09:55 -0400330
331 // Augment the Actions
khenaidoo68c930b2019-05-13 11:46:51 -0400332 fa.Actions = append(fa.Actions, fu.Output(ingressHop.Egress))
khenaidood20a5852018-10-22 22:09:55 -0400333
khenaidoo89b0e942018-10-21 21:11:33 -0400334 fg := fu.NewFlowsAndGroups()
khenaidoo68c930b2019-05-13 11:46:51 -0400335 fg.AddFlow(fu.MkFlowStat(fa))
khenaidoo89b0e942018-10-21 21:11:33 -0400336 deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fg)
337 } else { // Create standard flow
338 log.Debugw("creating-standard-flow", log.Fields{"flow": flow})
339 var fa *fu.FlowArgs
340 fa = &fu.FlowArgs{
Manikkaraj kb1a10922019-07-29 12:10:34 -0400341 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie, "meter_id": uint64(meterId), "write_metadata": metadataFromwriteMetadata},
khenaidoo89b0e942018-10-21 21:11:33 -0400342 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -0400343 fu.InPort(ingressHop.Ingress),
344 fu.TunnelId(uint64(inPortNo)),
khenaidoo89b0e942018-10-21 21:11:33 -0400345 },
khenaidoo68c930b2019-05-13 11:46:51 -0400346 Actions: fu.GetActions(flow),
khenaidoo89b0e942018-10-21 21:11:33 -0400347 }
348 // Augment the matchfields with the ofpfields from the flow
khenaidoo68c930b2019-05-13 11:46:51 -0400349 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
khenaidood20a5852018-10-22 22:09:55 -0400350
351 // Augment the Actions
khenaidoo68c930b2019-05-13 11:46:51 -0400352 fa.Actions = append(fa.Actions, fu.Output(ingressHop.Egress))
khenaidood20a5852018-10-22 22:09:55 -0400353
khenaidoo89b0e942018-10-21 21:11:33 -0400354 fg := fu.NewFlowsAndGroups()
khenaidoo68c930b2019-05-13 11:46:51 -0400355 fg.AddFlow(fu.MkFlowStat(fa))
khenaidoo89b0e942018-10-21 21:11:33 -0400356 deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fg)
357 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400358
khenaidoo89b0e942018-10-21 21:11:33 -0400359 return deviceRules
360}
361
khenaidood20a5852018-10-22 22:09:55 -0400362// processUnicastFlow decomposes unicast flows
363func (fd *FlowDecomposer) processUnicastFlow(agent coreIf.LogicalDeviceAgent, route []graph.RouteHop,
364 inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats) *fu.DeviceRules {
365
Manikkaraj kb1a10922019-07-29 12:10:34 -0400366 log.Debugw("decomposing-onu-flow-in-downstream-unicast-flow", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo})
khenaidood20a5852018-10-22 22:09:55 -0400367 deviceRules := fu.NewDeviceRules()
368
khenaidood20a5852018-10-22 22:09:55 -0400369 egressHop := route[1]
370
Manikkaraj kb1a10922019-07-29 12:10:34 -0400371 meterId := fu.GetMeterIdFromFlow(flow)
372 metadataFromwriteMetadata := fu.GetMetadataFromWriteMetadataAction(flow)
373 var fa *fu.FlowArgs
374 fa = &fu.FlowArgs{
375 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie, "meter_id": uint64(meterId), "write_metadata": metadataFromwriteMetadata},
376 MatchFields: []*ofp.OfpOxmOfbField{
377 fu.InPort(egressHop.Ingress),
378 },
khenaidoo89b0e942018-10-21 21:11:33 -0400379 }
Manikkaraj kb1a10922019-07-29 12:10:34 -0400380 // Augment the matchfields with the ofpfields from the flow
381 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
khenaidood20a5852018-10-22 22:09:55 -0400382
Manikkaraj kb1a10922019-07-29 12:10:34 -0400383 // Augment the Actions
384 filteredAction := fu.GetActions(flow, fu.OUTPUT)
385 filteredAction = append(filteredAction, fu.Output(egressHop.Egress))
386 fa.Actions = filteredAction
khenaidoo89b0e942018-10-21 21:11:33 -0400387
Manikkaraj kb1a10922019-07-29 12:10:34 -0400388 fg := fu.NewFlowsAndGroups()
389 fg.AddFlow(fu.MkFlowStat(fa))
390 deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -0400391 return deviceRules
392}
393
khenaidood20a5852018-10-22 22:09:55 -0400394// processMulticastFlow decompose multicast flows
395func (fd *FlowDecomposer) processMulticastFlow(agent coreIf.LogicalDeviceAgent, route []graph.RouteHop,
396 inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats, grpId uint32,
397 groupMap map[uint32]*ofp.OfpGroupEntry) *fu.DeviceRules {
398
khenaidoo89b0e942018-10-21 21:11:33 -0400399 log.Debugw("multicast-flow", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo})
khenaidood20a5852018-10-22 22:09:55 -0400400 deviceRules := fu.NewDeviceRules()
khenaidoo89b0e942018-10-21 21:11:33 -0400401
402 //having no Group yet is the same as having a Group with no buckets
403 var grp *ofp.OfpGroupEntry
404 var ok bool
405 if grp, ok = groupMap[grpId]; !ok {
406 log.Warnw("Group-id-not-present-in-map", log.Fields{"grpId": grpId, "groupMap": groupMap})
407 return deviceRules
408 }
409 if grp == nil || grp.Desc == nil {
410 log.Warnw("Group-or-desc-nil", log.Fields{"grpId": grpId, "grp": grp})
411 return deviceRules
412 }
413 for _, bucket := range grp.Desc.Buckets {
414 otherActions := make([]*ofp.OfpAction, 0)
415 for _, action := range bucket.Actions {
khenaidoo68c930b2019-05-13 11:46:51 -0400416 if action.Type == fu.OUTPUT {
khenaidoo89b0e942018-10-21 21:11:33 -0400417 outPortNo = action.GetOutput().Port
khenaidoo68c930b2019-05-13 11:46:51 -0400418 } else if action.Type != fu.POP_VLAN {
khenaidoo89b0e942018-10-21 21:11:33 -0400419 otherActions = append(otherActions, action)
420 }
421 }
422
khenaidoo19d7b632018-10-30 10:49:50 -0400423 route2 := agent.GetRoute(inPortNo, outPortNo)
khenaidoo89b0e942018-10-21 21:11:33 -0400424 switch len(route2) {
425 case 0:
426 log.Errorw("mc-no-route", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo, "comment": "deleting flow"})
427 // TODO: Delete flow
428 return deviceRules
429 case 2:
khenaidood20a5852018-10-22 22:09:55 -0400430 log.Debugw("route-found", log.Fields{"ingressHop": route2[0], "egressHop": route2[1]})
khenaidoo89b0e942018-10-21 21:11:33 -0400431 break
432 default:
433 log.Errorw("invalid-route-length", log.Fields{"routeLen": len(route)})
434 return deviceRules
435 }
436
khenaidood20a5852018-10-22 22:09:55 -0400437 ingressHop := route[0]
438 ingressHop2 := route2[0]
439 egressHop := route2[1]
440
441 if ingressHop.Ingress != ingressHop2.Ingress {
khenaidoo89b0e942018-10-21 21:11:33 -0400442 log.Errorw("mc-ingress-hop-hop2-mismatch", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo, "comment": "ignoring flow"})
443 return deviceRules
444 }
445 // Set the parent device flow
446 var fa *fu.FlowArgs
447 fa = &fu.FlowArgs{
448 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
449 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -0400450 fu.InPort(ingressHop.Ingress),
khenaidoo89b0e942018-10-21 21:11:33 -0400451 },
452 }
453 // Augment the matchfields with the ofpfields from the flow
khenaidoo68c930b2019-05-13 11:46:51 -0400454 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
khenaidood20a5852018-10-22 22:09:55 -0400455
khenaidoo89b0e942018-10-21 21:11:33 -0400456 // Augment the Actions
khenaidoo68c930b2019-05-13 11:46:51 -0400457 filteredAction := fu.GetActions(flow, fu.GROUP)
458 filteredAction = append(filteredAction, fu.PopVlan())
459 filteredAction = append(filteredAction, fu.Output(route2[1].Ingress))
khenaidood20a5852018-10-22 22:09:55 -0400460 fa.Actions = filteredAction
461
khenaidoo89b0e942018-10-21 21:11:33 -0400462 fg := fu.NewFlowsAndGroups()
khenaidoo68c930b2019-05-13 11:46:51 -0400463 fg.AddFlow(fu.MkFlowStat(fa))
khenaidood20a5852018-10-22 22:09:55 -0400464 deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -0400465
466 // Set the child device flow
467 fa = &fu.FlowArgs{
468 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
469 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -0400470 fu.InPort(egressHop.Ingress),
khenaidoo89b0e942018-10-21 21:11:33 -0400471 },
472 }
473 // Augment the matchfields with the ofpfields from the flow
khenaidoo68c930b2019-05-13 11:46:51 -0400474 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT, fu.VLAN_VID, fu.VLAN_PCP)...)
khenaidood20a5852018-10-22 22:09:55 -0400475
khenaidoo89b0e942018-10-21 21:11:33 -0400476 // Augment the Actions
khenaidoo68c930b2019-05-13 11:46:51 -0400477 otherActions = append(otherActions, fu.Output(egressHop.Egress))
khenaidoo89b0e942018-10-21 21:11:33 -0400478 fa.Actions = otherActions
khenaidood20a5852018-10-22 22:09:55 -0400479
khenaidoo89b0e942018-10-21 21:11:33 -0400480 fg = fu.NewFlowsAndGroups()
khenaidoo68c930b2019-05-13 11:46:51 -0400481 fg.AddFlow(fu.MkFlowStat(fa))
khenaidood20a5852018-10-22 22:09:55 -0400482 deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -0400483 }
484 return deviceRules
485}
486
khenaidood20a5852018-10-22 22:09:55 -0400487// decomposeFlow decomposes a flow for a logical device into flows for each physical device
488func (fd *FlowDecomposer) decomposeFlow(agent coreIf.LogicalDeviceAgent, flow *ofp.OfpFlowStats,
489 groupMap map[uint32]*ofp.OfpGroupEntry) *fu.DeviceRules {
490
khenaidoo68c930b2019-05-13 11:46:51 -0400491 inPortNo := fu.GetInPort(flow)
492 outPortNo := fu.GetOutPort(flow)
khenaidoo89b0e942018-10-21 21:11:33 -0400493 deviceRules := fu.NewDeviceRules()
khenaidoo19d7b632018-10-30 10:49:50 -0400494 route := agent.GetRoute(inPortNo, outPortNo)
khenaidoo2c6a0992019-04-29 13:46:56 -0400495
khenaidoo89b0e942018-10-21 21:11:33 -0400496 switch len(route) {
497 case 0:
498 log.Errorw("no-route", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo, "comment": "deleting-flow"})
499 // TODO: Delete flow
500 return deviceRules
501 case 2:
502 log.Debugw("route-found", log.Fields{"ingressHop": route[0], "egressHop": route[1]})
503 break
504 default:
505 log.Errorw("invalid-route-length", log.Fields{"routeLen": len(route)})
506 return deviceRules
507 }
508
khenaidoo89b0e942018-10-21 21:11:33 -0400509 // Process controller bound flow
510 if outPortNo != 0 && (outPortNo&0x7fffffff) == uint32(ofp.OfpPortNo_OFPP_CONTROLLER) {
khenaidood20a5852018-10-22 22:09:55 -0400511 deviceRules = fd.processControllerBoundFlow(agent, route, inPortNo, outPortNo, flow)
khenaidoo89b0e942018-10-21 21:11:33 -0400512 } else {
khenaidoo297cd252019-02-07 22:10:23 -0500513 var ingressDevice *voltha.Device
514 var err error
515 if ingressDevice, err = fd.deviceMgr.GetDevice(route[0].DeviceID); err != nil {
516 log.Errorw("ingress-device-not-found", log.Fields{"deviceId": route[0].DeviceID, "flow": flow})
517 return deviceRules
518 }
519 isUpstream := !ingressDevice.Root
Manikkaraj kb1a10922019-07-29 12:10:34 -0400520 if isUpstream { // Unicast OLT and ONU UL
521 log.Info("processOltAndOnuUpstreamNonControllerBoundUnicastFlows", log.Fields{"flows": flow})
khenaidood20a5852018-10-22 22:09:55 -0400522 deviceRules = fd.processUpstreamNonControllerBoundFlow(agent, route, inPortNo, outPortNo, flow)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400523 } else if fu.HasNextTable(flow) && flow.TableId == 0 { // Unicast OLT flow DL
524 log.Debugw("processOltDownstreamNonControllerBoundFlowWithNextTable", log.Fields{"flows": flow})
khenaidood20a5852018-10-22 22:09:55 -0400525 deviceRules = fd.processDownstreamFlowWithNextTable(agent, route, inPortNo, outPortNo, flow)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400526 } else if flow.TableId == 1 && outPortNo != 0 { // Unicast ONU flow DL
527 log.Debugw("processOnuDownstreamUnicastFlow", log.Fields{"flows": flow})
khenaidood20a5852018-10-22 22:09:55 -0400528 deviceRules = fd.processUnicastFlow(agent, route, inPortNo, outPortNo, flow)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400529 } else if grpId := fu.GetGroup(flow); grpId != 0 && flow.TableId == 0 { //Multicast
530 log.Debugw("processMulticastFlow", log.Fields{"flows": flow})
khenaidood20a5852018-10-22 22:09:55 -0400531 deviceRules = fd.processMulticastFlow(agent, route, inPortNo, outPortNo, flow, grpId, groupMap)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400532 } else {
533 log.Errorw("unknown-downstream-flow", log.Fields{"flow": *flow})
khenaidoo89b0e942018-10-21 21:11:33 -0400534 }
535 }
khenaidoo19d7b632018-10-30 10:49:50 -0400536 deviceRules = fd.updateOutputPortForControllerBoundFlowForParentDevide(flow, deviceRules)
khenaidoo89b0e942018-10-21 21:11:33 -0400537 return deviceRules
538}