blob: 09b29e8ac99c672c1ce0373101913079e5020a9f [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()
Manikkaraj kb1a10922019-07-29 12:10:34 -0400108 meterId := fu.GetMeterIdFromFlow(flow)
109 metadataFromwriteMetadata := fu.GetMetadataFromWriteMetadataAction(flow)
khenaidood20a5852018-10-22 22:09:55 -0400110
111 egressHop := route[1]
112
khenaidoo89b0e942018-10-21 21:11:33 -0400113 fg := fu.NewFlowsAndGroups()
114 if agent.GetDeviceGraph().IsRootPort(inPortNo) {
115 log.Debug("trap-nni")
khenaidoo8f474192019-04-03 17:20:44 -0400116 // no decomposition required - it is already an OLT flow from NNI
117 fg.AddFlow(flow)
khenaidoo89b0e942018-10-21 21:11:33 -0400118 } else {
119 // Trap flow for UNI port
120 log.Debug("trap-uni")
121
122 //inPortNo is 0 for wildcard input case, do not include upstream port for 4000 flow in input
123 var inPorts []uint32
124 if inPortNo == 0 {
khenaidood20a5852018-10-22 22:09:55 -0400125 inPorts = agent.GetWildcardInputPorts(egressHop.Egress) // exclude egress_hop.egress_port.port_no
khenaidoo89b0e942018-10-21 21:11:33 -0400126 } else {
127 inPorts = []uint32{inPortNo}
128 }
129 for _, inputPort := range inPorts {
130 var fa *fu.FlowArgs
131 // Upstream flow
132 fa = &fu.FlowArgs{
Manikkaraj kb1a10922019-07-29 12:10:34 -0400133 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie, "meter_id": uint64(meterId), "write_metadata": metadataFromwriteMetadata},
khenaidoo89b0e942018-10-21 21:11:33 -0400134 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -0400135 fu.InPort(egressHop.Ingress),
khenaidoo68c930b2019-05-13 11:46:51 -0400136 fu.TunnelId(uint64(inputPort)),
khenaidoo89b0e942018-10-21 21:11:33 -0400137 },
138 Actions: []*ofp.OfpAction{
khenaidoo68c930b2019-05-13 11:46:51 -0400139 fu.PushVlan(0x8100),
140 fu.SetField(fu.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 4000)),
141 fu.Output(egressHop.Egress),
khenaidoo89b0e942018-10-21 21:11:33 -0400142 },
143 }
144 // Augment the matchfields with the ofpfields from the flow
Manikkaraj kb1a10922019-07-29 12:10:34 -0400145 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
khenaidoo68c930b2019-05-13 11:46:51 -0400146 fg.AddFlow(fu.MkFlowStat(fa))
khenaidoo89b0e942018-10-21 21:11:33 -0400147 }
148 }
khenaidood20a5852018-10-22 22:09:55 -0400149 deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fg)
khenaidoo2c6a0992019-04-29 13:46:56 -0400150
khenaidoo89b0e942018-10-21 21:11:33 -0400151 return deviceRules
152}
153
154// processUpstreamNonControllerBoundFlow processes non-controller bound flow. We assume that anything that is
155// upstream needs to get Q-in-Q treatment and that this is expressed via two flow rules, the first using the
156// goto-statement. We also assume that the inner tag is applied at the ONU, while the outer tag is
157// applied at the OLT
khenaidood20a5852018-10-22 22:09:55 -0400158func (fd *FlowDecomposer) processUpstreamNonControllerBoundFlow(agent coreIf.LogicalDeviceAgent,
159 route []graph.RouteHop, inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats) *fu.DeviceRules {
160
khenaidoo89b0e942018-10-21 21:11:33 -0400161 log.Debugw("upstream-non-controller-bound-flow", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo})
khenaidood20a5852018-10-22 22:09:55 -0400162 deviceRules := fu.NewDeviceRules()
163
Manikkaraj kb1a10922019-07-29 12:10:34 -0400164 meterId := fu.GetMeterIdFromFlow(flow)
165 metadataFromwriteMetadata := fu.GetMetadataFromWriteMetadataAction(flow)
166
khenaidood20a5852018-10-22 22:09:55 -0400167 ingressHop := route[0]
168 egressHop := route[1]
169
Manikkaraj kb1a10922019-07-29 12:10:34 -0400170 if flow.TableId == 0 && fu.HasNextTable(flow) {
171 log.Debugw("decomposing-onu-flow-in-upstream-has-next-table", log.Fields{"table_id": flow.TableId})
khenaidoo89b0e942018-10-21 21:11:33 -0400172 if outPortNo != 0 {
173 log.Warnw("outPort-should-not-be-specified", log.Fields{"outPortNo": outPortNo})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400174 return deviceRules
khenaidoo89b0e942018-10-21 21:11:33 -0400175 }
176 var fa *fu.FlowArgs
177 fa = &fu.FlowArgs{
Manikkaraj kb1a10922019-07-29 12:10:34 -0400178 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie, "meter_id": uint64(meterId), "write_metadata": metadataFromwriteMetadata},
khenaidoo89b0e942018-10-21 21:11:33 -0400179 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -0400180 fu.InPort(ingressHop.Ingress),
181 fu.TunnelId(uint64(inPortNo)),
khenaidoo89b0e942018-10-21 21:11:33 -0400182 },
khenaidoo68c930b2019-05-13 11:46:51 -0400183 Actions: fu.GetActions(flow),
khenaidoo89b0e942018-10-21 21:11:33 -0400184 }
185 // Augment the matchfields with the ofpfields from the flow
khenaidoo68c930b2019-05-13 11:46:51 -0400186 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
khenaidood20a5852018-10-22 22:09:55 -0400187
188 // Augment the Actions
khenaidoo68c930b2019-05-13 11:46:51 -0400189 fa.Actions = append(fa.Actions, fu.Output(ingressHop.Egress))
khenaidood20a5852018-10-22 22:09:55 -0400190
khenaidoo89b0e942018-10-21 21:11:33 -0400191 fg := fu.NewFlowsAndGroups()
khenaidoo68c930b2019-05-13 11:46:51 -0400192 fg.AddFlow(fu.MkFlowStat(fa))
khenaidood20a5852018-10-22 22:09:55 -0400193 deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fg)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400194 } else if flow.TableId == 1 && outPortNo != 0 {
195 log.Debugw("decomposing-olt-flow-in-upstream-has-next-table", log.Fields{"table_id": flow.TableId})
196 var fa *fu.FlowArgs
197 fa = &fu.FlowArgs{
198 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie, "meter_id": uint64(meterId), "write_metadata": metadataFromwriteMetadata},
199 MatchFields: []*ofp.OfpOxmOfbField{
200 fu.InPort(egressHop.Ingress),
201 fu.TunnelId(uint64(inPortNo)),
202 },
khenaidoo89b0e942018-10-21 21:11:33 -0400203 }
Manikkaraj kb1a10922019-07-29 12:10:34 -0400204 // Augment the matchfields with the ofpfields from the flow
205 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
khenaidoo89b0e942018-10-21 21:11:33 -0400206
Manikkaraj kb1a10922019-07-29 12:10:34 -0400207 //Augment the actions
208 filteredAction := fu.GetActions(flow, fu.OUTPUT)
209 filteredAction = append(filteredAction, fu.Output(egressHop.Egress))
210 fa.Actions = filteredAction
khenaidood20a5852018-10-22 22:09:55 -0400211
Manikkaraj kb1a10922019-07-29 12:10:34 -0400212 fg := fu.NewFlowsAndGroups()
213 fg.AddFlow(fu.MkFlowStat(fa))
214 deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -0400215 }
216 return deviceRules
217}
218
khenaidood20a5852018-10-22 22:09:55 -0400219// processDownstreamFlowWithNextTable decomposes downstream flows containing next table ID instructions
220func (fd *FlowDecomposer) processDownstreamFlowWithNextTable(agent coreIf.LogicalDeviceAgent, route []graph.RouteHop,
221 inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats) *fu.DeviceRules {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400222 log.Debugw("decomposing-olt-flow-in-downstream-flow-with-next-table", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo})
khenaidood20a5852018-10-22 22:09:55 -0400223 deviceRules := fu.NewDeviceRules()
Manikkaraj kb1a10922019-07-29 12:10:34 -0400224 meterId := fu.GetMeterIdFromFlow(flow)
225 metadataFromwriteMetadata := fu.GetMetadataFromWriteMetadataAction(flow)
khenaidood20a5852018-10-22 22:09:55 -0400226
khenaidoo89b0e942018-10-21 21:11:33 -0400227 if outPortNo != 0 {
228 log.Warnw("outPort-should-not-be-specified", log.Fields{"outPortNo": outPortNo})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400229 return deviceRules
khenaidoo89b0e942018-10-21 21:11:33 -0400230 }
Manikkaraj kb1a10922019-07-29 12:10:34 -0400231
232 if flow.TableId != 0 {
233 log.Warnw("This is not olt pipeline table, so skipping", log.Fields{"tableId": flow.TableId})
234 return deviceRules
235 }
236
khenaidoo89b0e942018-10-21 21:11:33 -0400237 ingressHop := route[0]
khenaidood20a5852018-10-22 22:09:55 -0400238 egressHop := route[1]
Manikkaraj kb1a10922019-07-29 12:10:34 -0400239 if metadataFromwriteMetadata != 0 {
khenaidoo89b0e942018-10-21 21:11:33 -0400240 log.Debugw("creating-metadata-flow", log.Fields{"flow": flow})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400241 portNumber := fu.GetEgressPortNumberFromWriteMetadata(flow)
khenaidoo89b0e942018-10-21 21:11:33 -0400242 if portNumber != 0 {
khenaidoo19d7b632018-10-30 10:49:50 -0400243 recalculatedRoute := agent.GetRoute(inPortNo, portNumber)
khenaidoo89b0e942018-10-21 21:11:33 -0400244 switch len(recalculatedRoute) {
245 case 0:
Manikkaraj kb1a10922019-07-29 12:10:34 -0400246 log.Errorw("no-route-double-tag", log.Fields{"inPortNo": inPortNo, "outPortNo": portNumber, "comment": "deleting-flow", "metadata": metadataFromwriteMetadata})
247 //TODO: Delete flow
khenaidoo89b0e942018-10-21 21:11:33 -0400248 return deviceRules
249 case 2:
khenaidood20a5852018-10-22 22:09:55 -0400250 log.Debugw("route-found", log.Fields{"ingressHop": ingressHop, "egressHop": egressHop})
khenaidoo89b0e942018-10-21 21:11:33 -0400251 break
252 default:
253 log.Errorw("invalid-route-length", log.Fields{"routeLen": len(route)})
254 return deviceRules
255 }
256 ingressHop = recalculatedRoute[0]
257 }
khenaidoo68c930b2019-05-13 11:46:51 -0400258 innerTag := fu.GetInnerTagFromMetaData(flow)
khenaidoo89b0e942018-10-21 21:11:33 -0400259 if innerTag == 0 {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400260 log.Errorw("no-inner-route-double-tag", log.Fields{"inPortNo": inPortNo, "outPortNo": portNumber, "comment": "deleting-flow", "metadata": metadataFromwriteMetadata})
261 //TODO: Delete flow
khenaidoo89b0e942018-10-21 21:11:33 -0400262 return deviceRules
263 }
264 var fa *fu.FlowArgs
265 fa = &fu.FlowArgs{
Manikkaraj kb1a10922019-07-29 12:10:34 -0400266 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie, "meter_id": uint64(meterId), "write_metadata": metadataFromwriteMetadata},
khenaidoo89b0e942018-10-21 21:11:33 -0400267 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -0400268 fu.InPort(ingressHop.Ingress),
Manikkaraj kb1a10922019-07-29 12:10:34 -0400269 fu.Metadata_ofp(uint64(innerTag)),
khenaidoo68c930b2019-05-13 11:46:51 -0400270 fu.TunnelId(uint64(portNumber)),
khenaidoo89b0e942018-10-21 21:11:33 -0400271 },
khenaidoo68c930b2019-05-13 11:46:51 -0400272 Actions: fu.GetActions(flow),
khenaidoo89b0e942018-10-21 21:11:33 -0400273 }
274 // Augment the matchfields with the ofpfields from the flow
khenaidoo68c930b2019-05-13 11:46:51 -0400275 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT, fu.METADATA)...)
khenaidood20a5852018-10-22 22:09:55 -0400276
277 // Augment the Actions
khenaidoo68c930b2019-05-13 11:46:51 -0400278 fa.Actions = append(fa.Actions, fu.Output(ingressHop.Egress))
khenaidood20a5852018-10-22 22:09:55 -0400279
khenaidoo89b0e942018-10-21 21:11:33 -0400280 fg := fu.NewFlowsAndGroups()
khenaidoo68c930b2019-05-13 11:46:51 -0400281 fg.AddFlow(fu.MkFlowStat(fa))
khenaidoo89b0e942018-10-21 21:11:33 -0400282 deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fg)
283 } else { // Create standard flow
284 log.Debugw("creating-standard-flow", log.Fields{"flow": flow})
285 var fa *fu.FlowArgs
286 fa = &fu.FlowArgs{
Manikkaraj kb1a10922019-07-29 12:10:34 -0400287 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie, "meter_id": uint64(meterId), "write_metadata": metadataFromwriteMetadata},
khenaidoo89b0e942018-10-21 21:11:33 -0400288 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -0400289 fu.InPort(ingressHop.Ingress),
290 fu.TunnelId(uint64(inPortNo)),
khenaidoo89b0e942018-10-21 21:11:33 -0400291 },
khenaidoo68c930b2019-05-13 11:46:51 -0400292 Actions: fu.GetActions(flow),
khenaidoo89b0e942018-10-21 21:11:33 -0400293 }
294 // Augment the matchfields with the ofpfields from the flow
khenaidoo68c930b2019-05-13 11:46:51 -0400295 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
khenaidood20a5852018-10-22 22:09:55 -0400296
297 // Augment the Actions
khenaidoo68c930b2019-05-13 11:46:51 -0400298 fa.Actions = append(fa.Actions, fu.Output(ingressHop.Egress))
khenaidood20a5852018-10-22 22:09:55 -0400299
khenaidoo89b0e942018-10-21 21:11:33 -0400300 fg := fu.NewFlowsAndGroups()
khenaidoo68c930b2019-05-13 11:46:51 -0400301 fg.AddFlow(fu.MkFlowStat(fa))
khenaidoo89b0e942018-10-21 21:11:33 -0400302 deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fg)
303 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400304
khenaidoo89b0e942018-10-21 21:11:33 -0400305 return deviceRules
306}
307
khenaidood20a5852018-10-22 22:09:55 -0400308// processUnicastFlow decomposes unicast flows
309func (fd *FlowDecomposer) processUnicastFlow(agent coreIf.LogicalDeviceAgent, route []graph.RouteHop,
310 inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats) *fu.DeviceRules {
311
Manikkaraj kb1a10922019-07-29 12:10:34 -0400312 log.Debugw("decomposing-onu-flow-in-downstream-unicast-flow", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo})
khenaidood20a5852018-10-22 22:09:55 -0400313 deviceRules := fu.NewDeviceRules()
314
khenaidood20a5852018-10-22 22:09:55 -0400315 egressHop := route[1]
316
Manikkaraj kb1a10922019-07-29 12:10:34 -0400317 meterId := fu.GetMeterIdFromFlow(flow)
318 metadataFromwriteMetadata := fu.GetMetadataFromWriteMetadataAction(flow)
319 var fa *fu.FlowArgs
320 fa = &fu.FlowArgs{
321 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie, "meter_id": uint64(meterId), "write_metadata": metadataFromwriteMetadata},
322 MatchFields: []*ofp.OfpOxmOfbField{
323 fu.InPort(egressHop.Ingress),
324 },
khenaidoo89b0e942018-10-21 21:11:33 -0400325 }
Manikkaraj kb1a10922019-07-29 12:10:34 -0400326 // Augment the matchfields with the ofpfields from the flow
327 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
khenaidood20a5852018-10-22 22:09:55 -0400328
Manikkaraj kb1a10922019-07-29 12:10:34 -0400329 // Augment the Actions
330 filteredAction := fu.GetActions(flow, fu.OUTPUT)
331 filteredAction = append(filteredAction, fu.Output(egressHop.Egress))
332 fa.Actions = filteredAction
khenaidoo89b0e942018-10-21 21:11:33 -0400333
Manikkaraj kb1a10922019-07-29 12:10:34 -0400334 fg := fu.NewFlowsAndGroups()
335 fg.AddFlow(fu.MkFlowStat(fa))
336 deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -0400337 return deviceRules
338}
339
khenaidood20a5852018-10-22 22:09:55 -0400340// processMulticastFlow decompose multicast flows
341func (fd *FlowDecomposer) processMulticastFlow(agent coreIf.LogicalDeviceAgent, route []graph.RouteHop,
342 inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats, grpId uint32,
343 groupMap map[uint32]*ofp.OfpGroupEntry) *fu.DeviceRules {
344
khenaidoo89b0e942018-10-21 21:11:33 -0400345 log.Debugw("multicast-flow", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo})
khenaidood20a5852018-10-22 22:09:55 -0400346 deviceRules := fu.NewDeviceRules()
khenaidoo89b0e942018-10-21 21:11:33 -0400347
348 //having no Group yet is the same as having a Group with no buckets
349 var grp *ofp.OfpGroupEntry
350 var ok bool
351 if grp, ok = groupMap[grpId]; !ok {
352 log.Warnw("Group-id-not-present-in-map", log.Fields{"grpId": grpId, "groupMap": groupMap})
353 return deviceRules
354 }
355 if grp == nil || grp.Desc == nil {
356 log.Warnw("Group-or-desc-nil", log.Fields{"grpId": grpId, "grp": grp})
357 return deviceRules
358 }
359 for _, bucket := range grp.Desc.Buckets {
360 otherActions := make([]*ofp.OfpAction, 0)
361 for _, action := range bucket.Actions {
khenaidoo68c930b2019-05-13 11:46:51 -0400362 if action.Type == fu.OUTPUT {
khenaidoo89b0e942018-10-21 21:11:33 -0400363 outPortNo = action.GetOutput().Port
khenaidoo68c930b2019-05-13 11:46:51 -0400364 } else if action.Type != fu.POP_VLAN {
khenaidoo89b0e942018-10-21 21:11:33 -0400365 otherActions = append(otherActions, action)
366 }
367 }
368
khenaidoo19d7b632018-10-30 10:49:50 -0400369 route2 := agent.GetRoute(inPortNo, outPortNo)
khenaidoo89b0e942018-10-21 21:11:33 -0400370 switch len(route2) {
371 case 0:
372 log.Errorw("mc-no-route", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo, "comment": "deleting flow"})
373 // TODO: Delete flow
374 return deviceRules
375 case 2:
khenaidood20a5852018-10-22 22:09:55 -0400376 log.Debugw("route-found", log.Fields{"ingressHop": route2[0], "egressHop": route2[1]})
khenaidoo89b0e942018-10-21 21:11:33 -0400377 break
378 default:
379 log.Errorw("invalid-route-length", log.Fields{"routeLen": len(route)})
380 return deviceRules
381 }
382
khenaidood20a5852018-10-22 22:09:55 -0400383 ingressHop := route[0]
384 ingressHop2 := route2[0]
385 egressHop := route2[1]
386
387 if ingressHop.Ingress != ingressHop2.Ingress {
khenaidoo89b0e942018-10-21 21:11:33 -0400388 log.Errorw("mc-ingress-hop-hop2-mismatch", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo, "comment": "ignoring flow"})
389 return deviceRules
390 }
391 // Set the parent device flow
392 var fa *fu.FlowArgs
393 fa = &fu.FlowArgs{
394 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
395 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -0400396 fu.InPort(ingressHop.Ingress),
khenaidoo89b0e942018-10-21 21:11:33 -0400397 },
398 }
399 // Augment the matchfields with the ofpfields from the flow
khenaidoo68c930b2019-05-13 11:46:51 -0400400 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
khenaidood20a5852018-10-22 22:09:55 -0400401
khenaidoo89b0e942018-10-21 21:11:33 -0400402 // Augment the Actions
khenaidoo68c930b2019-05-13 11:46:51 -0400403 filteredAction := fu.GetActions(flow, fu.GROUP)
404 filteredAction = append(filteredAction, fu.PopVlan())
405 filteredAction = append(filteredAction, fu.Output(route2[1].Ingress))
khenaidood20a5852018-10-22 22:09:55 -0400406 fa.Actions = filteredAction
407
khenaidoo89b0e942018-10-21 21:11:33 -0400408 fg := fu.NewFlowsAndGroups()
khenaidoo68c930b2019-05-13 11:46:51 -0400409 fg.AddFlow(fu.MkFlowStat(fa))
khenaidood20a5852018-10-22 22:09:55 -0400410 deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -0400411
412 // Set the child device flow
413 fa = &fu.FlowArgs{
414 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
415 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -0400416 fu.InPort(egressHop.Ingress),
khenaidoo89b0e942018-10-21 21:11:33 -0400417 },
418 }
419 // Augment the matchfields with the ofpfields from the flow
khenaidoo68c930b2019-05-13 11:46:51 -0400420 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT, fu.VLAN_VID, fu.VLAN_PCP)...)
khenaidood20a5852018-10-22 22:09:55 -0400421
khenaidoo89b0e942018-10-21 21:11:33 -0400422 // Augment the Actions
khenaidoo68c930b2019-05-13 11:46:51 -0400423 otherActions = append(otherActions, fu.Output(egressHop.Egress))
khenaidoo89b0e942018-10-21 21:11:33 -0400424 fa.Actions = otherActions
khenaidood20a5852018-10-22 22:09:55 -0400425
khenaidoo89b0e942018-10-21 21:11:33 -0400426 fg = fu.NewFlowsAndGroups()
khenaidoo68c930b2019-05-13 11:46:51 -0400427 fg.AddFlow(fu.MkFlowStat(fa))
khenaidood20a5852018-10-22 22:09:55 -0400428 deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -0400429 }
430 return deviceRules
431}
432
khenaidood20a5852018-10-22 22:09:55 -0400433// decomposeFlow decomposes a flow for a logical device into flows for each physical device
434func (fd *FlowDecomposer) decomposeFlow(agent coreIf.LogicalDeviceAgent, flow *ofp.OfpFlowStats,
435 groupMap map[uint32]*ofp.OfpGroupEntry) *fu.DeviceRules {
436
khenaidoo68c930b2019-05-13 11:46:51 -0400437 inPortNo := fu.GetInPort(flow)
438 outPortNo := fu.GetOutPort(flow)
khenaidoo89b0e942018-10-21 21:11:33 -0400439 deviceRules := fu.NewDeviceRules()
khenaidoo19d7b632018-10-30 10:49:50 -0400440 route := agent.GetRoute(inPortNo, outPortNo)
khenaidoo2c6a0992019-04-29 13:46:56 -0400441
khenaidoo89b0e942018-10-21 21:11:33 -0400442 switch len(route) {
443 case 0:
444 log.Errorw("no-route", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo, "comment": "deleting-flow"})
445 // TODO: Delete flow
446 return deviceRules
447 case 2:
448 log.Debugw("route-found", log.Fields{"ingressHop": route[0], "egressHop": route[1]})
449 break
450 default:
451 log.Errorw("invalid-route-length", log.Fields{"routeLen": len(route)})
452 return deviceRules
453 }
454
khenaidoo89b0e942018-10-21 21:11:33 -0400455 // Process controller bound flow
456 if outPortNo != 0 && (outPortNo&0x7fffffff) == uint32(ofp.OfpPortNo_OFPP_CONTROLLER) {
khenaidood20a5852018-10-22 22:09:55 -0400457 deviceRules = fd.processControllerBoundFlow(agent, route, inPortNo, outPortNo, flow)
khenaidoo89b0e942018-10-21 21:11:33 -0400458 } else {
khenaidoo297cd252019-02-07 22:10:23 -0500459 var ingressDevice *voltha.Device
460 var err error
461 if ingressDevice, err = fd.deviceMgr.GetDevice(route[0].DeviceID); err != nil {
462 log.Errorw("ingress-device-not-found", log.Fields{"deviceId": route[0].DeviceID, "flow": flow})
463 return deviceRules
464 }
465 isUpstream := !ingressDevice.Root
Manikkaraj kb1a10922019-07-29 12:10:34 -0400466 if isUpstream { // Unicast OLT and ONU UL
467 log.Info("processOltAndOnuUpstreamNonControllerBoundUnicastFlows", log.Fields{"flows": flow})
khenaidood20a5852018-10-22 22:09:55 -0400468 deviceRules = fd.processUpstreamNonControllerBoundFlow(agent, route, inPortNo, outPortNo, flow)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400469 } else if fu.HasNextTable(flow) && flow.TableId == 0 { // Unicast OLT flow DL
470 log.Debugw("processOltDownstreamNonControllerBoundFlowWithNextTable", log.Fields{"flows": flow})
khenaidood20a5852018-10-22 22:09:55 -0400471 deviceRules = fd.processDownstreamFlowWithNextTable(agent, route, inPortNo, outPortNo, flow)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400472 } else if flow.TableId == 1 && outPortNo != 0 { // Unicast ONU flow DL
473 log.Debugw("processOnuDownstreamUnicastFlow", log.Fields{"flows": flow})
khenaidood20a5852018-10-22 22:09:55 -0400474 deviceRules = fd.processUnicastFlow(agent, route, inPortNo, outPortNo, flow)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400475 } else if grpId := fu.GetGroup(flow); grpId != 0 && flow.TableId == 0 { //Multicast
476 log.Debugw("processMulticastFlow", log.Fields{"flows": flow})
khenaidood20a5852018-10-22 22:09:55 -0400477 deviceRules = fd.processMulticastFlow(agent, route, inPortNo, outPortNo, flow, grpId, groupMap)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400478 } else {
479 log.Errorw("unknown-downstream-flow", log.Fields{"flow": *flow})
khenaidoo89b0e942018-10-21 21:11:33 -0400480 }
481 }
khenaidoo19d7b632018-10-30 10:49:50 -0400482 deviceRules = fd.updateOutputPortForControllerBoundFlowForParentDevide(flow, deviceRules)
khenaidoo89b0e942018-10-21 21:11:33 -0400483 return deviceRules
484}