blob: d4058bce58c14d350125fdb05671495b78d0005c [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()
Humera Kouser4ff89012019-08-25 19:01:51 -0400114
115 //case of packet_in from NNI port rule
khenaidoo89b0e942018-10-21 21:11:33 -0400116 if agent.GetDeviceGraph().IsRootPort(inPortNo) {
Humera Kouser4ff89012019-08-25 19:01:51 -0400117 // Trap flow for NNI port
khenaidoo89b0e942018-10-21 21:11:33 -0400118 log.Debug("trap-nni")
Humera Kouser4ff89012019-08-25 19:01:51 -0400119
120 var fa *fu.FlowArgs
121 fa = &fu.FlowArgs{
122 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
123 MatchFields: []*ofp.OfpOxmOfbField{
124 fu.InPort(egressHop.Egress),
125 },
126 Actions: fu.GetActions(flow),
127 }
128 // Augment the matchfields with the ofpfields from the flow
129 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
130 fg.AddFlow(fu.MkFlowStat(fa))
khenaidoo89b0e942018-10-21 21:11:33 -0400131 } else {
132 // Trap flow for UNI port
133 log.Debug("trap-uni")
134
135 //inPortNo is 0 for wildcard input case, do not include upstream port for 4000 flow in input
136 var inPorts []uint32
137 if inPortNo == 0 {
khenaidood20a5852018-10-22 22:09:55 -0400138 inPorts = agent.GetWildcardInputPorts(egressHop.Egress) // exclude egress_hop.egress_port.port_no
khenaidoo89b0e942018-10-21 21:11:33 -0400139 } else {
140 inPorts = []uint32{inPortNo}
141 }
142 for _, inputPort := range inPorts {
143 var fa *fu.FlowArgs
144 // Upstream flow
145 fa = &fu.FlowArgs{
Manikkaraj kb1a10922019-07-29 12:10:34 -0400146 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie, "meter_id": uint64(meterId), "write_metadata": metadataFromwriteMetadata},
khenaidoo89b0e942018-10-21 21:11:33 -0400147 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -0400148 fu.InPort(egressHop.Ingress),
khenaidoo68c930b2019-05-13 11:46:51 -0400149 fu.TunnelId(uint64(inputPort)),
khenaidoo89b0e942018-10-21 21:11:33 -0400150 },
151 Actions: []*ofp.OfpAction{
khenaidoo68c930b2019-05-13 11:46:51 -0400152 fu.PushVlan(0x8100),
153 fu.SetField(fu.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 4000)),
154 fu.Output(egressHop.Egress),
khenaidoo89b0e942018-10-21 21:11:33 -0400155 },
156 }
157 // Augment the matchfields with the ofpfields from the flow
Manikkaraj kb1a10922019-07-29 12:10:34 -0400158 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
khenaidoo68c930b2019-05-13 11:46:51 -0400159 fg.AddFlow(fu.MkFlowStat(fa))
khenaidoo89b0e942018-10-21 21:11:33 -0400160 }
161 }
khenaidood20a5852018-10-22 22:09:55 -0400162 deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fg)
khenaidoo2c6a0992019-04-29 13:46:56 -0400163
khenaidoo89b0e942018-10-21 21:11:33 -0400164 return deviceRules
165}
166
167// processUpstreamNonControllerBoundFlow processes non-controller bound flow. We assume that anything that is
168// upstream needs to get Q-in-Q treatment and that this is expressed via two flow rules, the first using the
169// goto-statement. We also assume that the inner tag is applied at the ONU, while the outer tag is
170// applied at the OLT
khenaidood20a5852018-10-22 22:09:55 -0400171func (fd *FlowDecomposer) processUpstreamNonControllerBoundFlow(agent coreIf.LogicalDeviceAgent,
172 route []graph.RouteHop, inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats) *fu.DeviceRules {
173
khenaidoo89b0e942018-10-21 21:11:33 -0400174 log.Debugw("upstream-non-controller-bound-flow", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo})
khenaidood20a5852018-10-22 22:09:55 -0400175 deviceRules := fu.NewDeviceRules()
176
Manikkaraj kb1a10922019-07-29 12:10:34 -0400177 meterId := fu.GetMeterIdFromFlow(flow)
178 metadataFromwriteMetadata := fu.GetMetadataFromWriteMetadataAction(flow)
179
khenaidood20a5852018-10-22 22:09:55 -0400180 ingressHop := route[0]
181 egressHop := route[1]
182
Manikkaraj kb1a10922019-07-29 12:10:34 -0400183 if flow.TableId == 0 && fu.HasNextTable(flow) {
184 log.Debugw("decomposing-onu-flow-in-upstream-has-next-table", log.Fields{"table_id": flow.TableId})
khenaidoo89b0e942018-10-21 21:11:33 -0400185 if outPortNo != 0 {
186 log.Warnw("outPort-should-not-be-specified", log.Fields{"outPortNo": outPortNo})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400187 return deviceRules
khenaidoo89b0e942018-10-21 21:11:33 -0400188 }
189 var fa *fu.FlowArgs
190 fa = &fu.FlowArgs{
Manikkaraj kb1a10922019-07-29 12:10:34 -0400191 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie, "meter_id": uint64(meterId), "write_metadata": metadataFromwriteMetadata},
khenaidoo89b0e942018-10-21 21:11:33 -0400192 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -0400193 fu.InPort(ingressHop.Ingress),
194 fu.TunnelId(uint64(inPortNo)),
khenaidoo89b0e942018-10-21 21:11:33 -0400195 },
khenaidoo68c930b2019-05-13 11:46:51 -0400196 Actions: fu.GetActions(flow),
khenaidoo89b0e942018-10-21 21:11:33 -0400197 }
198 // Augment the matchfields with the ofpfields from the flow
khenaidoo68c930b2019-05-13 11:46:51 -0400199 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
khenaidood20a5852018-10-22 22:09:55 -0400200
201 // Augment the Actions
khenaidoo68c930b2019-05-13 11:46:51 -0400202 fa.Actions = append(fa.Actions, fu.Output(ingressHop.Egress))
khenaidood20a5852018-10-22 22:09:55 -0400203
khenaidoo89b0e942018-10-21 21:11:33 -0400204 fg := fu.NewFlowsAndGroups()
khenaidoo68c930b2019-05-13 11:46:51 -0400205 fg.AddFlow(fu.MkFlowStat(fa))
khenaidood20a5852018-10-22 22:09:55 -0400206 deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fg)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400207 } else if flow.TableId == 1 && outPortNo != 0 {
208 log.Debugw("decomposing-olt-flow-in-upstream-has-next-table", log.Fields{"table_id": flow.TableId})
209 var fa *fu.FlowArgs
210 fa = &fu.FlowArgs{
211 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie, "meter_id": uint64(meterId), "write_metadata": metadataFromwriteMetadata},
212 MatchFields: []*ofp.OfpOxmOfbField{
213 fu.InPort(egressHop.Ingress),
214 fu.TunnelId(uint64(inPortNo)),
215 },
khenaidoo89b0e942018-10-21 21:11:33 -0400216 }
Manikkaraj kb1a10922019-07-29 12:10:34 -0400217 // Augment the matchfields with the ofpfields from the flow
218 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
khenaidoo89b0e942018-10-21 21:11:33 -0400219
Manikkaraj kb1a10922019-07-29 12:10:34 -0400220 //Augment the actions
221 filteredAction := fu.GetActions(flow, fu.OUTPUT)
222 filteredAction = append(filteredAction, fu.Output(egressHop.Egress))
223 fa.Actions = filteredAction
khenaidood20a5852018-10-22 22:09:55 -0400224
Manikkaraj kb1a10922019-07-29 12:10:34 -0400225 fg := fu.NewFlowsAndGroups()
226 fg.AddFlow(fu.MkFlowStat(fa))
227 deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -0400228 }
229 return deviceRules
230}
231
khenaidood20a5852018-10-22 22:09:55 -0400232// processDownstreamFlowWithNextTable decomposes downstream flows containing next table ID instructions
233func (fd *FlowDecomposer) processDownstreamFlowWithNextTable(agent coreIf.LogicalDeviceAgent, route []graph.RouteHop,
234 inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats) *fu.DeviceRules {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400235 log.Debugw("decomposing-olt-flow-in-downstream-flow-with-next-table", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo})
khenaidood20a5852018-10-22 22:09:55 -0400236 deviceRules := fu.NewDeviceRules()
Manikkaraj kb1a10922019-07-29 12:10:34 -0400237 meterId := fu.GetMeterIdFromFlow(flow)
238 metadataFromwriteMetadata := fu.GetMetadataFromWriteMetadataAction(flow)
khenaidood20a5852018-10-22 22:09:55 -0400239
khenaidoo89b0e942018-10-21 21:11:33 -0400240 if outPortNo != 0 {
241 log.Warnw("outPort-should-not-be-specified", log.Fields{"outPortNo": outPortNo})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400242 return deviceRules
khenaidoo89b0e942018-10-21 21:11:33 -0400243 }
Manikkaraj kb1a10922019-07-29 12:10:34 -0400244
245 if flow.TableId != 0 {
246 log.Warnw("This is not olt pipeline table, so skipping", log.Fields{"tableId": flow.TableId})
247 return deviceRules
248 }
249
khenaidoo89b0e942018-10-21 21:11:33 -0400250 ingressHop := route[0]
khenaidood20a5852018-10-22 22:09:55 -0400251 egressHop := route[1]
Manikkaraj kb1a10922019-07-29 12:10:34 -0400252 if metadataFromwriteMetadata != 0 {
khenaidoo89b0e942018-10-21 21:11:33 -0400253 log.Debugw("creating-metadata-flow", log.Fields{"flow": flow})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400254 portNumber := fu.GetEgressPortNumberFromWriteMetadata(flow)
khenaidoo89b0e942018-10-21 21:11:33 -0400255 if portNumber != 0 {
khenaidoo19d7b632018-10-30 10:49:50 -0400256 recalculatedRoute := agent.GetRoute(inPortNo, portNumber)
khenaidoo89b0e942018-10-21 21:11:33 -0400257 switch len(recalculatedRoute) {
258 case 0:
Manikkaraj kb1a10922019-07-29 12:10:34 -0400259 log.Errorw("no-route-double-tag", log.Fields{"inPortNo": inPortNo, "outPortNo": portNumber, "comment": "deleting-flow", "metadata": metadataFromwriteMetadata})
260 //TODO: Delete flow
khenaidoo89b0e942018-10-21 21:11:33 -0400261 return deviceRules
262 case 2:
khenaidood20a5852018-10-22 22:09:55 -0400263 log.Debugw("route-found", log.Fields{"ingressHop": ingressHop, "egressHop": egressHop})
khenaidoo89b0e942018-10-21 21:11:33 -0400264 break
265 default:
266 log.Errorw("invalid-route-length", log.Fields{"routeLen": len(route)})
267 return deviceRules
268 }
269 ingressHop = recalculatedRoute[0]
270 }
khenaidoo68c930b2019-05-13 11:46:51 -0400271 innerTag := fu.GetInnerTagFromMetaData(flow)
khenaidoo89b0e942018-10-21 21:11:33 -0400272 if innerTag == 0 {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400273 log.Errorw("no-inner-route-double-tag", log.Fields{"inPortNo": inPortNo, "outPortNo": portNumber, "comment": "deleting-flow", "metadata": metadataFromwriteMetadata})
274 //TODO: Delete flow
khenaidoo89b0e942018-10-21 21:11:33 -0400275 return deviceRules
276 }
277 var fa *fu.FlowArgs
278 fa = &fu.FlowArgs{
Manikkaraj kb1a10922019-07-29 12:10:34 -0400279 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie, "meter_id": uint64(meterId), "write_metadata": metadataFromwriteMetadata},
khenaidoo89b0e942018-10-21 21:11:33 -0400280 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -0400281 fu.InPort(ingressHop.Ingress),
Manikkaraj kb1a10922019-07-29 12:10:34 -0400282 fu.Metadata_ofp(uint64(innerTag)),
khenaidoo68c930b2019-05-13 11:46:51 -0400283 fu.TunnelId(uint64(portNumber)),
khenaidoo89b0e942018-10-21 21:11:33 -0400284 },
khenaidoo68c930b2019-05-13 11:46:51 -0400285 Actions: fu.GetActions(flow),
khenaidoo89b0e942018-10-21 21:11:33 -0400286 }
287 // Augment the matchfields with the ofpfields from the flow
khenaidoo68c930b2019-05-13 11:46:51 -0400288 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT, fu.METADATA)...)
khenaidood20a5852018-10-22 22:09:55 -0400289
290 // Augment the Actions
khenaidoo68c930b2019-05-13 11:46:51 -0400291 fa.Actions = append(fa.Actions, fu.Output(ingressHop.Egress))
khenaidood20a5852018-10-22 22:09:55 -0400292
khenaidoo89b0e942018-10-21 21:11:33 -0400293 fg := fu.NewFlowsAndGroups()
khenaidoo68c930b2019-05-13 11:46:51 -0400294 fg.AddFlow(fu.MkFlowStat(fa))
khenaidoo89b0e942018-10-21 21:11:33 -0400295 deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fg)
296 } else { // Create standard flow
297 log.Debugw("creating-standard-flow", log.Fields{"flow": flow})
298 var fa *fu.FlowArgs
299 fa = &fu.FlowArgs{
Manikkaraj kb1a10922019-07-29 12:10:34 -0400300 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie, "meter_id": uint64(meterId), "write_metadata": metadataFromwriteMetadata},
khenaidoo89b0e942018-10-21 21:11:33 -0400301 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -0400302 fu.InPort(ingressHop.Ingress),
303 fu.TunnelId(uint64(inPortNo)),
khenaidoo89b0e942018-10-21 21:11:33 -0400304 },
khenaidoo68c930b2019-05-13 11:46:51 -0400305 Actions: fu.GetActions(flow),
khenaidoo89b0e942018-10-21 21:11:33 -0400306 }
307 // Augment the matchfields with the ofpfields from the flow
khenaidoo68c930b2019-05-13 11:46:51 -0400308 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
khenaidood20a5852018-10-22 22:09:55 -0400309
310 // Augment the Actions
khenaidoo68c930b2019-05-13 11:46:51 -0400311 fa.Actions = append(fa.Actions, fu.Output(ingressHop.Egress))
khenaidood20a5852018-10-22 22:09:55 -0400312
khenaidoo89b0e942018-10-21 21:11:33 -0400313 fg := fu.NewFlowsAndGroups()
khenaidoo68c930b2019-05-13 11:46:51 -0400314 fg.AddFlow(fu.MkFlowStat(fa))
khenaidoo89b0e942018-10-21 21:11:33 -0400315 deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fg)
316 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400317
khenaidoo89b0e942018-10-21 21:11:33 -0400318 return deviceRules
319}
320
khenaidood20a5852018-10-22 22:09:55 -0400321// processUnicastFlow decomposes unicast flows
322func (fd *FlowDecomposer) processUnicastFlow(agent coreIf.LogicalDeviceAgent, route []graph.RouteHop,
323 inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats) *fu.DeviceRules {
324
Manikkaraj kb1a10922019-07-29 12:10:34 -0400325 log.Debugw("decomposing-onu-flow-in-downstream-unicast-flow", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo})
khenaidood20a5852018-10-22 22:09:55 -0400326 deviceRules := fu.NewDeviceRules()
327
khenaidood20a5852018-10-22 22:09:55 -0400328 egressHop := route[1]
329
Manikkaraj kb1a10922019-07-29 12:10:34 -0400330 meterId := fu.GetMeterIdFromFlow(flow)
331 metadataFromwriteMetadata := fu.GetMetadataFromWriteMetadataAction(flow)
332 var fa *fu.FlowArgs
333 fa = &fu.FlowArgs{
334 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie, "meter_id": uint64(meterId), "write_metadata": metadataFromwriteMetadata},
335 MatchFields: []*ofp.OfpOxmOfbField{
336 fu.InPort(egressHop.Ingress),
337 },
khenaidoo89b0e942018-10-21 21:11:33 -0400338 }
Manikkaraj kb1a10922019-07-29 12:10:34 -0400339 // Augment the matchfields with the ofpfields from the flow
340 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
khenaidood20a5852018-10-22 22:09:55 -0400341
Manikkaraj kb1a10922019-07-29 12:10:34 -0400342 // Augment the Actions
343 filteredAction := fu.GetActions(flow, fu.OUTPUT)
344 filteredAction = append(filteredAction, fu.Output(egressHop.Egress))
345 fa.Actions = filteredAction
khenaidoo89b0e942018-10-21 21:11:33 -0400346
Manikkaraj kb1a10922019-07-29 12:10:34 -0400347 fg := fu.NewFlowsAndGroups()
348 fg.AddFlow(fu.MkFlowStat(fa))
349 deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -0400350 return deviceRules
351}
352
khenaidood20a5852018-10-22 22:09:55 -0400353// processMulticastFlow decompose multicast flows
354func (fd *FlowDecomposer) processMulticastFlow(agent coreIf.LogicalDeviceAgent, route []graph.RouteHop,
355 inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats, grpId uint32,
356 groupMap map[uint32]*ofp.OfpGroupEntry) *fu.DeviceRules {
357
khenaidoo89b0e942018-10-21 21:11:33 -0400358 log.Debugw("multicast-flow", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo})
khenaidood20a5852018-10-22 22:09:55 -0400359 deviceRules := fu.NewDeviceRules()
khenaidoo89b0e942018-10-21 21:11:33 -0400360
361 //having no Group yet is the same as having a Group with no buckets
362 var grp *ofp.OfpGroupEntry
363 var ok bool
364 if grp, ok = groupMap[grpId]; !ok {
365 log.Warnw("Group-id-not-present-in-map", log.Fields{"grpId": grpId, "groupMap": groupMap})
366 return deviceRules
367 }
368 if grp == nil || grp.Desc == nil {
369 log.Warnw("Group-or-desc-nil", log.Fields{"grpId": grpId, "grp": grp})
370 return deviceRules
371 }
372 for _, bucket := range grp.Desc.Buckets {
373 otherActions := make([]*ofp.OfpAction, 0)
374 for _, action := range bucket.Actions {
khenaidoo68c930b2019-05-13 11:46:51 -0400375 if action.Type == fu.OUTPUT {
khenaidoo89b0e942018-10-21 21:11:33 -0400376 outPortNo = action.GetOutput().Port
khenaidoo68c930b2019-05-13 11:46:51 -0400377 } else if action.Type != fu.POP_VLAN {
khenaidoo89b0e942018-10-21 21:11:33 -0400378 otherActions = append(otherActions, action)
379 }
380 }
381
khenaidoo19d7b632018-10-30 10:49:50 -0400382 route2 := agent.GetRoute(inPortNo, outPortNo)
khenaidoo89b0e942018-10-21 21:11:33 -0400383 switch len(route2) {
384 case 0:
385 log.Errorw("mc-no-route", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo, "comment": "deleting flow"})
386 // TODO: Delete flow
387 return deviceRules
388 case 2:
khenaidood20a5852018-10-22 22:09:55 -0400389 log.Debugw("route-found", log.Fields{"ingressHop": route2[0], "egressHop": route2[1]})
khenaidoo89b0e942018-10-21 21:11:33 -0400390 break
391 default:
392 log.Errorw("invalid-route-length", log.Fields{"routeLen": len(route)})
393 return deviceRules
394 }
395
khenaidood20a5852018-10-22 22:09:55 -0400396 ingressHop := route[0]
397 ingressHop2 := route2[0]
398 egressHop := route2[1]
399
400 if ingressHop.Ingress != ingressHop2.Ingress {
khenaidoo89b0e942018-10-21 21:11:33 -0400401 log.Errorw("mc-ingress-hop-hop2-mismatch", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo, "comment": "ignoring flow"})
402 return deviceRules
403 }
404 // Set the parent device flow
405 var fa *fu.FlowArgs
406 fa = &fu.FlowArgs{
407 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
408 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -0400409 fu.InPort(ingressHop.Ingress),
khenaidoo89b0e942018-10-21 21:11:33 -0400410 },
411 }
412 // Augment the matchfields with the ofpfields from the flow
khenaidoo68c930b2019-05-13 11:46:51 -0400413 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
khenaidood20a5852018-10-22 22:09:55 -0400414
khenaidoo89b0e942018-10-21 21:11:33 -0400415 // Augment the Actions
khenaidoo68c930b2019-05-13 11:46:51 -0400416 filteredAction := fu.GetActions(flow, fu.GROUP)
417 filteredAction = append(filteredAction, fu.PopVlan())
418 filteredAction = append(filteredAction, fu.Output(route2[1].Ingress))
khenaidood20a5852018-10-22 22:09:55 -0400419 fa.Actions = filteredAction
420
khenaidoo89b0e942018-10-21 21:11:33 -0400421 fg := fu.NewFlowsAndGroups()
khenaidoo68c930b2019-05-13 11:46:51 -0400422 fg.AddFlow(fu.MkFlowStat(fa))
khenaidood20a5852018-10-22 22:09:55 -0400423 deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -0400424
425 // Set the child device flow
426 fa = &fu.FlowArgs{
427 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
428 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -0400429 fu.InPort(egressHop.Ingress),
khenaidoo89b0e942018-10-21 21:11:33 -0400430 },
431 }
432 // Augment the matchfields with the ofpfields from the flow
khenaidoo68c930b2019-05-13 11:46:51 -0400433 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT, fu.VLAN_VID, fu.VLAN_PCP)...)
khenaidood20a5852018-10-22 22:09:55 -0400434
khenaidoo89b0e942018-10-21 21:11:33 -0400435 // Augment the Actions
khenaidoo68c930b2019-05-13 11:46:51 -0400436 otherActions = append(otherActions, fu.Output(egressHop.Egress))
khenaidoo89b0e942018-10-21 21:11:33 -0400437 fa.Actions = otherActions
khenaidood20a5852018-10-22 22:09:55 -0400438
khenaidoo89b0e942018-10-21 21:11:33 -0400439 fg = fu.NewFlowsAndGroups()
khenaidoo68c930b2019-05-13 11:46:51 -0400440 fg.AddFlow(fu.MkFlowStat(fa))
khenaidood20a5852018-10-22 22:09:55 -0400441 deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -0400442 }
443 return deviceRules
444}
445
khenaidood20a5852018-10-22 22:09:55 -0400446// decomposeFlow decomposes a flow for a logical device into flows for each physical device
447func (fd *FlowDecomposer) decomposeFlow(agent coreIf.LogicalDeviceAgent, flow *ofp.OfpFlowStats,
448 groupMap map[uint32]*ofp.OfpGroupEntry) *fu.DeviceRules {
449
khenaidoo68c930b2019-05-13 11:46:51 -0400450 inPortNo := fu.GetInPort(flow)
451 outPortNo := fu.GetOutPort(flow)
khenaidoo89b0e942018-10-21 21:11:33 -0400452 deviceRules := fu.NewDeviceRules()
khenaidoo19d7b632018-10-30 10:49:50 -0400453 route := agent.GetRoute(inPortNo, outPortNo)
khenaidoo2c6a0992019-04-29 13:46:56 -0400454
khenaidoo89b0e942018-10-21 21:11:33 -0400455 switch len(route) {
456 case 0:
457 log.Errorw("no-route", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo, "comment": "deleting-flow"})
458 // TODO: Delete flow
459 return deviceRules
460 case 2:
461 log.Debugw("route-found", log.Fields{"ingressHop": route[0], "egressHop": route[1]})
462 break
463 default:
464 log.Errorw("invalid-route-length", log.Fields{"routeLen": len(route)})
465 return deviceRules
466 }
467
khenaidoo89b0e942018-10-21 21:11:33 -0400468 // Process controller bound flow
469 if outPortNo != 0 && (outPortNo&0x7fffffff) == uint32(ofp.OfpPortNo_OFPP_CONTROLLER) {
khenaidood20a5852018-10-22 22:09:55 -0400470 deviceRules = fd.processControllerBoundFlow(agent, route, inPortNo, outPortNo, flow)
khenaidoo89b0e942018-10-21 21:11:33 -0400471 } else {
khenaidoo297cd252019-02-07 22:10:23 -0500472 var ingressDevice *voltha.Device
473 var err error
474 if ingressDevice, err = fd.deviceMgr.GetDevice(route[0].DeviceID); err != nil {
475 log.Errorw("ingress-device-not-found", log.Fields{"deviceId": route[0].DeviceID, "flow": flow})
476 return deviceRules
477 }
478 isUpstream := !ingressDevice.Root
Manikkaraj kb1a10922019-07-29 12:10:34 -0400479 if isUpstream { // Unicast OLT and ONU UL
480 log.Info("processOltAndOnuUpstreamNonControllerBoundUnicastFlows", log.Fields{"flows": flow})
khenaidood20a5852018-10-22 22:09:55 -0400481 deviceRules = fd.processUpstreamNonControllerBoundFlow(agent, route, inPortNo, outPortNo, flow)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400482 } else if fu.HasNextTable(flow) && flow.TableId == 0 { // Unicast OLT flow DL
483 log.Debugw("processOltDownstreamNonControllerBoundFlowWithNextTable", log.Fields{"flows": flow})
khenaidood20a5852018-10-22 22:09:55 -0400484 deviceRules = fd.processDownstreamFlowWithNextTable(agent, route, inPortNo, outPortNo, flow)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400485 } else if flow.TableId == 1 && outPortNo != 0 { // Unicast ONU flow DL
486 log.Debugw("processOnuDownstreamUnicastFlow", log.Fields{"flows": flow})
khenaidood20a5852018-10-22 22:09:55 -0400487 deviceRules = fd.processUnicastFlow(agent, route, inPortNo, outPortNo, flow)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400488 } else if grpId := fu.GetGroup(flow); grpId != 0 && flow.TableId == 0 { //Multicast
489 log.Debugw("processMulticastFlow", log.Fields{"flows": flow})
khenaidood20a5852018-10-22 22:09:55 -0400490 deviceRules = fd.processMulticastFlow(agent, route, inPortNo, outPortNo, flow, grpId, groupMap)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400491 } else {
492 log.Errorw("unknown-downstream-flow", log.Fields{"flow": *flow})
khenaidoo89b0e942018-10-21 21:11:33 -0400493 }
494 }
khenaidoo19d7b632018-10-30 10:49:50 -0400495 deviceRules = fd.updateOutputPortForControllerBoundFlowForParentDevide(flow, deviceRules)
khenaidoo89b0e942018-10-21 21:11:33 -0400496 return deviceRules
497}