blob: 330a4af12304c3617abe1e7ee187a9c322c51cda [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
npujar1d86a522019-11-14 17:11:16 +053017package flowdecomposition
khenaidoo89b0e942018-10-21 21:11:33 -040018
19import (
khenaidoo19d7b632018-10-30 10:49:50 -040020 "github.com/gogo/protobuf/proto"
npujar1d86a522019-11-14 17:11:16 +053021 "github.com/opencord/voltha-go/rw_core/coreif"
khenaidoo89b0e942018-10-21 21:11:33 -040022 "github.com/opencord/voltha-go/rw_core/graph"
Scott Baker807addd2019-10-24 15:16:21 -070023 fu "github.com/opencord/voltha-lib-go/v2/pkg/flows"
24 "github.com/opencord/voltha-lib-go/v2/pkg/log"
Scott Baker555307d2019-11-04 08:58:01 -080025 ofp "github.com/opencord/voltha-protos/v2/go/openflow_13"
26 "github.com/opencord/voltha-protos/v2/go/voltha"
khenaidoo89b0e942018-10-21 21:11:33 -040027)
28
29func init() {
npujar1d86a522019-11-14 17:11:16 +053030 _, err := log.AddPackage(log.JSON, log.DebugLevel, nil)
31 if err != nil {
32 log.Errorw("unable-to-register-package-to-the-log-map", log.Fields{"error": err})
33 }
khenaidoo89b0e942018-10-21 21:11:33 -040034}
35
npujar1d86a522019-11-14 17:11:16 +053036// FlowDecomposer represent flow decomposer attribute
khenaidoo89b0e942018-10-21 21:11:33 -040037type FlowDecomposer struct {
npujar1d86a522019-11-14 17:11:16 +053038 deviceMgr coreif.DeviceManager
khenaidoo89b0e942018-10-21 21:11:33 -040039}
40
npujar1d86a522019-11-14 17:11:16 +053041// NewFlowDecomposer creates flow decomposer instance
42func NewFlowDecomposer(deviceMgr coreif.DeviceManager) *FlowDecomposer {
khenaidoo89b0e942018-10-21 21:11:33 -040043 var decomposer FlowDecomposer
44 decomposer.deviceMgr = deviceMgr
45 return &decomposer
46}
47
48//DecomposeRules decomposes per-device flows and flow-groups from the flows and groups defined on a logical device
npujar1d86a522019-11-14 17:11:16 +053049func (fd *FlowDecomposer) DecomposeRules(agent coreif.LogicalDeviceAgent, flows ofp.Flows, groups ofp.FlowGroups) *fu.DeviceRules {
khenaidoo3306c992019-05-24 16:57:35 -040050 deviceRules := *fu.NewDeviceRules()
khenaidoo2c6a0992019-04-29 13:46:56 -040051 devicesToUpdate := make(map[string]string)
khenaidoo89b0e942018-10-21 21:11:33 -040052
53 groupMap := make(map[uint32]*ofp.OfpGroupEntry)
54 for _, groupEntry := range groups.Items {
55 groupMap[groupEntry.Desc.GroupId] = groupEntry
56 }
57
58 var decomposedRules *fu.DeviceRules
59 for _, flow := range flows.Items {
60 decomposedRules = fd.decomposeFlow(agent, flow, groupMap)
npujar1d86a522019-11-14 17:11:16 +053061 for deviceID, flowAndGroups := range decomposedRules.Rules {
62 deviceRules.CreateEntryIfNotExist(deviceID)
63 deviceRules.Rules[deviceID].AddFrom(flowAndGroups)
64 devicesToUpdate[deviceID] = deviceID
khenaidoo89b0e942018-10-21 21:11:33 -040065 }
66 }
khenaidoo3306c992019-05-24 16:57:35 -040067 return deviceRules.FilterRules(devicesToUpdate)
khenaidoo89b0e942018-10-21 21:11:33 -040068}
69
khenaidoo19d7b632018-10-30 10:49:50 -040070// Handles special case of any controller-bound flow for a parent device
71func (fd *FlowDecomposer) updateOutputPortForControllerBoundFlowForParentDevide(flow *ofp.OfpFlowStats,
72 dr *fu.DeviceRules) *fu.DeviceRules {
khenaidoo68c930b2019-05-13 11:46:51 -040073 EAPOL := fu.EthType(0x888e)
74 IGMP := fu.IpProto(2)
75 UDP := fu.IpProto(17)
khenaidoo19d7b632018-10-30 10:49:50 -040076
77 newDeviceRules := dr.Copy()
78 // Check whether we are dealing with a parent device
npujar1d86a522019-11-14 17:11:16 +053079 for deviceID, fg := range dr.GetRules() {
80 if root, _ := fd.deviceMgr.IsRootDevice(deviceID); root {
81 newDeviceRules.ClearFlows(deviceID)
khenaidoo19d7b632018-10-30 10:49:50 -040082 for i := 0; i < fg.Flows.Len(); i++ {
83 f := fg.GetFlow(i)
84 UpdateOutPortNo := false
khenaidoo68c930b2019-05-13 11:46:51 -040085 for _, field := range fu.GetOfbFields(f) {
khenaidoo19d7b632018-10-30 10:49:50 -040086 UpdateOutPortNo = (field.String() == EAPOL.String())
87 UpdateOutPortNo = UpdateOutPortNo || (field.String() == IGMP.String())
88 UpdateOutPortNo = UpdateOutPortNo || (field.String() == UDP.String())
89 if UpdateOutPortNo {
90 break
91 }
92 }
93 if UpdateOutPortNo {
khenaidoo68c930b2019-05-13 11:46:51 -040094 f = fu.UpdateOutputPortByActionType(f, uint32(ofp.OfpInstructionType_OFPIT_APPLY_ACTIONS),
khenaidoo19d7b632018-10-30 10:49:50 -040095 uint32(ofp.OfpPortNo_OFPP_CONTROLLER))
96 }
97 // Update flow Id as a change in the instruction field will result in a new flow ID
khenaidoo68c930b2019-05-13 11:46:51 -040098 f.Id = fu.HashFlowStats(f)
npujar1d86a522019-11-14 17:11:16 +053099 newDeviceRules.AddFlow(deviceID, (proto.Clone(f)).(*ofp.OfpFlowStats))
khenaidoo19d7b632018-10-30 10:49:50 -0400100 }
101 }
102 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400103
khenaidoo19d7b632018-10-30 10:49:50 -0400104 return newDeviceRules
105}
106
khenaidood20a5852018-10-22 22:09:55 -0400107//processControllerBoundFlow decomposes trap flows
npujar1d86a522019-11-14 17:11:16 +0530108func (fd *FlowDecomposer) processControllerBoundFlow(agent coreif.LogicalDeviceAgent, route []graph.RouteHop,
khenaidood20a5852018-10-22 22:09:55 -0400109 inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats) *fu.DeviceRules {
110
khenaidoo89b0e942018-10-21 21:11:33 -0400111 log.Debugw("trap-flow", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo, "flow": flow})
khenaidood20a5852018-10-22 22:09:55 -0400112 deviceRules := fu.NewDeviceRules()
npujar1d86a522019-11-14 17:11:16 +0530113 meterID := fu.GetMeterIdFromFlow(flow)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400114 metadataFromwriteMetadata := fu.GetMetadataFromWriteMetadataAction(flow)
khenaidood20a5852018-10-22 22:09:55 -0400115
Matt Jeanneretb423bad2019-10-10 20:42:19 -0400116 ingressHop := route[0]
khenaidood20a5852018-10-22 22:09:55 -0400117 egressHop := route[1]
118
Humera Kouser4ff89012019-08-25 19:01:51 -0400119 //case of packet_in from NNI port rule
khenaidoo89b0e942018-10-21 21:11:33 -0400120 if agent.GetDeviceGraph().IsRootPort(inPortNo) {
Humera Kouser4ff89012019-08-25 19:01:51 -0400121 // Trap flow for NNI port
khenaidoo89b0e942018-10-21 21:11:33 -0400122 log.Debug("trap-nni")
Humera Kouser4ff89012019-08-25 19:01:51 -0400123
npujar1d86a522019-11-14 17:11:16 +0530124 fa := &fu.FlowArgs{
Humera Kouser4ff89012019-08-25 19:01:51 -0400125 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
126 MatchFields: []*ofp.OfpOxmOfbField{
127 fu.InPort(egressHop.Egress),
128 },
129 Actions: fu.GetActions(flow),
130 }
131 // Augment the matchfields with the ofpfields from the flow
Matt Jeanneretb423bad2019-10-10 20:42:19 -0400132 fg := fu.NewFlowsAndGroups()
Humera Kouser4ff89012019-08-25 19:01:51 -0400133 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
134 fg.AddFlow(fu.MkFlowStat(fa))
Matt Jeanneretb423bad2019-10-10 20:42:19 -0400135 deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -0400136 } else {
137 // Trap flow for UNI port
138 log.Debug("trap-uni")
139
140 //inPortNo is 0 for wildcard input case, do not include upstream port for 4000 flow in input
141 var inPorts []uint32
142 if inPortNo == 0 {
khenaidood20a5852018-10-22 22:09:55 -0400143 inPorts = agent.GetWildcardInputPorts(egressHop.Egress) // exclude egress_hop.egress_port.port_no
khenaidoo89b0e942018-10-21 21:11:33 -0400144 } else {
145 inPorts = []uint32{inPortNo}
146 }
147 for _, inputPort := range inPorts {
Matt Jeanneretb423bad2019-10-10 20:42:19 -0400148 // Upstream flow on parent (olt) device
npujar1d86a522019-11-14 17:11:16 +0530149 faParent := &fu.FlowArgs{
150 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie, "meter_id": uint64(meterID), "write_metadata": metadataFromwriteMetadata},
khenaidoo89b0e942018-10-21 21:11:33 -0400151 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -0400152 fu.InPort(egressHop.Ingress),
khenaidoo68c930b2019-05-13 11:46:51 -0400153 fu.TunnelId(uint64(inputPort)),
khenaidoo89b0e942018-10-21 21:11:33 -0400154 },
155 Actions: []*ofp.OfpAction{
khenaidoo68c930b2019-05-13 11:46:51 -0400156 fu.PushVlan(0x8100),
157 fu.SetField(fu.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 4000)),
158 fu.Output(egressHop.Egress),
khenaidoo89b0e942018-10-21 21:11:33 -0400159 },
160 }
161 // Augment the matchfields with the ofpfields from the flow
Matt Jeanneretb423bad2019-10-10 20:42:19 -0400162 faParent.MatchFields = append(faParent.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
163 fgParent := fu.NewFlowsAndGroups()
164 fgParent.AddFlow(fu.MkFlowStat(faParent))
165 deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fgParent)
166 log.Debugw("parent-trap-flow-set", log.Fields{"flow": faParent})
167
168 // Upstream flow on child (onu) device
169 var actions []*ofp.OfpAction
170 setvid := fu.GetVlanVid(flow)
171 if setvid != nil {
172 // have this child push the vlan the parent is matching/trapping on above
173 actions = []*ofp.OfpAction{
174 fu.PushVlan(0x8100),
175 fu.SetField(fu.VlanVid(*setvid)),
176 fu.Output(ingressHop.Egress),
177 }
178 } else {
179 // otherwise just set the egress port
180 actions = []*ofp.OfpAction{
181 fu.Output(ingressHop.Egress),
182 }
183 }
npujar1d86a522019-11-14 17:11:16 +0530184 faChild := &fu.FlowArgs{
185 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie, "meter_id": uint64(meterID), "write_metadata": metadataFromwriteMetadata},
Matt Jeanneretb423bad2019-10-10 20:42:19 -0400186 MatchFields: []*ofp.OfpOxmOfbField{
187 fu.InPort(ingressHop.Ingress),
188 fu.TunnelId(uint64(inputPort)),
189 },
190 Actions: actions,
191 }
192 // Augment the matchfields with the ofpfields from the flow.
193 // If the parent has a match vid and the child is setting that match vid exclude the the match vlan
194 // for the child given it will be setting that vlan and the parent will be matching on it
195 if setvid != nil {
196 faChild.MatchFields = append(faChild.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT, fu.VLAN_VID)...)
197 } else {
198 faChild.MatchFields = append(faChild.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
199 }
200 fgChild := fu.NewFlowsAndGroups()
201 fgChild.AddFlow(fu.MkFlowStat(faChild))
202 deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fgChild)
203 log.Debugw("child-trap-flow-set", log.Fields{"flow": faChild})
khenaidoo89b0e942018-10-21 21:11:33 -0400204 }
205 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400206
khenaidoo89b0e942018-10-21 21:11:33 -0400207 return deviceRules
208}
209
210// processUpstreamNonControllerBoundFlow processes non-controller bound flow. We assume that anything that is
211// upstream needs to get Q-in-Q treatment and that this is expressed via two flow rules, the first using the
212// goto-statement. We also assume that the inner tag is applied at the ONU, while the outer tag is
213// applied at the OLT
npujar1d86a522019-11-14 17:11:16 +0530214func (fd *FlowDecomposer) processUpstreamNonControllerBoundFlow(agent coreif.LogicalDeviceAgent,
khenaidood20a5852018-10-22 22:09:55 -0400215 route []graph.RouteHop, inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats) *fu.DeviceRules {
216
khenaidoo89b0e942018-10-21 21:11:33 -0400217 log.Debugw("upstream-non-controller-bound-flow", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo})
khenaidood20a5852018-10-22 22:09:55 -0400218 deviceRules := fu.NewDeviceRules()
219
npujar1d86a522019-11-14 17:11:16 +0530220 meterID := fu.GetMeterIdFromFlow(flow)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400221 metadataFromwriteMetadata := fu.GetMetadataFromWriteMetadataAction(flow)
222
khenaidood20a5852018-10-22 22:09:55 -0400223 ingressHop := route[0]
224 egressHop := route[1]
225
Manikkaraj kb1a10922019-07-29 12:10:34 -0400226 if flow.TableId == 0 && fu.HasNextTable(flow) {
227 log.Debugw("decomposing-onu-flow-in-upstream-has-next-table", log.Fields{"table_id": flow.TableId})
khenaidoo89b0e942018-10-21 21:11:33 -0400228 if outPortNo != 0 {
229 log.Warnw("outPort-should-not-be-specified", log.Fields{"outPortNo": outPortNo})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400230 return deviceRules
khenaidoo89b0e942018-10-21 21:11:33 -0400231 }
npujar1d86a522019-11-14 17:11:16 +0530232 fa := &fu.FlowArgs{
233 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie, "meter_id": uint64(meterID), "write_metadata": metadataFromwriteMetadata},
khenaidoo89b0e942018-10-21 21:11:33 -0400234 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -0400235 fu.InPort(ingressHop.Ingress),
236 fu.TunnelId(uint64(inPortNo)),
khenaidoo89b0e942018-10-21 21:11:33 -0400237 },
khenaidoo68c930b2019-05-13 11:46:51 -0400238 Actions: fu.GetActions(flow),
khenaidoo89b0e942018-10-21 21:11:33 -0400239 }
240 // Augment the matchfields with the ofpfields from the flow
khenaidoo68c930b2019-05-13 11:46:51 -0400241 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
khenaidood20a5852018-10-22 22:09:55 -0400242
243 // Augment the Actions
khenaidoo68c930b2019-05-13 11:46:51 -0400244 fa.Actions = append(fa.Actions, fu.Output(ingressHop.Egress))
khenaidood20a5852018-10-22 22:09:55 -0400245
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(ingressHop.DeviceID, fg)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400249 } else if flow.TableId == 1 && outPortNo != 0 {
250 log.Debugw("decomposing-olt-flow-in-upstream-has-next-table", log.Fields{"table_id": flow.TableId})
npujar1d86a522019-11-14 17:11:16 +0530251 fa := &fu.FlowArgs{
252 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie, "meter_id": uint64(meterID), "write_metadata": metadataFromwriteMetadata},
Manikkaraj kb1a10922019-07-29 12:10:34 -0400253 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
npujar1d86a522019-11-14 17:11:16 +0530274func (fd *FlowDecomposer) processDownstreamFlowWithNextTable(agent coreif.LogicalDeviceAgent, route []graph.RouteHop,
khenaidood20a5852018-10-22 22:09:55 -0400275 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()
npujar1d86a522019-11-14 17:11:16 +0530278 meterID := fu.GetMeterIdFromFlow(flow)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400279 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 default:
306 log.Errorw("invalid-route-length", log.Fields{"routeLen": len(route)})
307 return deviceRules
308 }
309 ingressHop = recalculatedRoute[0]
310 }
khenaidoo68c930b2019-05-13 11:46:51 -0400311 innerTag := fu.GetInnerTagFromMetaData(flow)
khenaidoo89b0e942018-10-21 21:11:33 -0400312 if innerTag == 0 {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400313 log.Errorw("no-inner-route-double-tag", log.Fields{"inPortNo": inPortNo, "outPortNo": portNumber, "comment": "deleting-flow", "metadata": metadataFromwriteMetadata})
314 //TODO: Delete flow
khenaidoo89b0e942018-10-21 21:11:33 -0400315 return deviceRules
316 }
npujar1d86a522019-11-14 17:11:16 +0530317 fa := &fu.FlowArgs{
318 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie, "meter_id": uint64(meterID), "write_metadata": metadataFromwriteMetadata},
khenaidoo89b0e942018-10-21 21:11:33 -0400319 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -0400320 fu.InPort(ingressHop.Ingress),
Manikkaraj kb1a10922019-07-29 12:10:34 -0400321 fu.Metadata_ofp(uint64(innerTag)),
khenaidoo68c930b2019-05-13 11:46:51 -0400322 fu.TunnelId(uint64(portNumber)),
khenaidoo89b0e942018-10-21 21:11:33 -0400323 },
khenaidoo68c930b2019-05-13 11:46:51 -0400324 Actions: fu.GetActions(flow),
khenaidoo89b0e942018-10-21 21:11:33 -0400325 }
326 // Augment the matchfields with the ofpfields from the flow
khenaidoo68c930b2019-05-13 11:46:51 -0400327 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT, fu.METADATA)...)
khenaidood20a5852018-10-22 22:09:55 -0400328
329 // Augment the Actions
khenaidoo68c930b2019-05-13 11:46:51 -0400330 fa.Actions = append(fa.Actions, fu.Output(ingressHop.Egress))
khenaidood20a5852018-10-22 22:09:55 -0400331
khenaidoo89b0e942018-10-21 21:11:33 -0400332 fg := fu.NewFlowsAndGroups()
khenaidoo68c930b2019-05-13 11:46:51 -0400333 fg.AddFlow(fu.MkFlowStat(fa))
khenaidoo89b0e942018-10-21 21:11:33 -0400334 deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fg)
335 } else { // Create standard flow
336 log.Debugw("creating-standard-flow", log.Fields{"flow": flow})
npujar1d86a522019-11-14 17:11:16 +0530337 fa := &fu.FlowArgs{
338 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie, "meter_id": uint64(meterID), "write_metadata": metadataFromwriteMetadata},
khenaidoo89b0e942018-10-21 21:11:33 -0400339 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
npujar1d86a522019-11-14 17:11:16 +0530360func (fd *FlowDecomposer) processUnicastFlow(agent coreif.LogicalDeviceAgent, route []graph.RouteHop,
khenaidood20a5852018-10-22 22:09:55 -0400361 inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats) *fu.DeviceRules {
362
Manikkaraj kb1a10922019-07-29 12:10:34 -0400363 log.Debugw("decomposing-onu-flow-in-downstream-unicast-flow", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo})
khenaidood20a5852018-10-22 22:09:55 -0400364 deviceRules := fu.NewDeviceRules()
365
khenaidood20a5852018-10-22 22:09:55 -0400366 egressHop := route[1]
367
npujar1d86a522019-11-14 17:11:16 +0530368 meterID := fu.GetMeterIdFromFlow(flow)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400369 metadataFromwriteMetadata := fu.GetMetadataFromWriteMetadataAction(flow)
npujar1d86a522019-11-14 17:11:16 +0530370 fa := &fu.FlowArgs{
371 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie, "meter_id": uint64(meterID), "write_metadata": metadataFromwriteMetadata},
Manikkaraj kb1a10922019-07-29 12:10:34 -0400372 MatchFields: []*ofp.OfpOxmOfbField{
373 fu.InPort(egressHop.Ingress),
374 },
khenaidoo89b0e942018-10-21 21:11:33 -0400375 }
Manikkaraj kb1a10922019-07-29 12:10:34 -0400376 // Augment the matchfields with the ofpfields from the flow
377 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
khenaidood20a5852018-10-22 22:09:55 -0400378
Manikkaraj kb1a10922019-07-29 12:10:34 -0400379 // Augment the Actions
380 filteredAction := fu.GetActions(flow, fu.OUTPUT)
381 filteredAction = append(filteredAction, fu.Output(egressHop.Egress))
382 fa.Actions = filteredAction
khenaidoo89b0e942018-10-21 21:11:33 -0400383
Manikkaraj kb1a10922019-07-29 12:10:34 -0400384 fg := fu.NewFlowsAndGroups()
385 fg.AddFlow(fu.MkFlowStat(fa))
386 deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -0400387 return deviceRules
388}
389
khenaidood20a5852018-10-22 22:09:55 -0400390// processMulticastFlow decompose multicast flows
npujar1d86a522019-11-14 17:11:16 +0530391func (fd *FlowDecomposer) processMulticastFlow(agent coreif.LogicalDeviceAgent, route []graph.RouteHop,
392 inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats, grpID uint32,
khenaidood20a5852018-10-22 22:09:55 -0400393 groupMap map[uint32]*ofp.OfpGroupEntry) *fu.DeviceRules {
394
khenaidoo89b0e942018-10-21 21:11:33 -0400395 log.Debugw("multicast-flow", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo})
khenaidood20a5852018-10-22 22:09:55 -0400396 deviceRules := fu.NewDeviceRules()
khenaidoo89b0e942018-10-21 21:11:33 -0400397
398 //having no Group yet is the same as having a Group with no buckets
399 var grp *ofp.OfpGroupEntry
400 var ok bool
npujar1d86a522019-11-14 17:11:16 +0530401 if grp, ok = groupMap[grpID]; !ok {
402 log.Warnw("Group-id-not-present-in-map", log.Fields{"grpId": grpID, "groupMap": groupMap})
khenaidoo89b0e942018-10-21 21:11:33 -0400403 return deviceRules
404 }
405 if grp == nil || grp.Desc == nil {
npujar1d86a522019-11-14 17:11:16 +0530406 log.Warnw("Group-or-desc-nil", log.Fields{"grpId": grpID, "grp": grp})
khenaidoo89b0e942018-10-21 21:11:33 -0400407 return deviceRules
408 }
409 for _, bucket := range grp.Desc.Buckets {
410 otherActions := make([]*ofp.OfpAction, 0)
411 for _, action := range bucket.Actions {
khenaidoo68c930b2019-05-13 11:46:51 -0400412 if action.Type == fu.OUTPUT {
khenaidoo89b0e942018-10-21 21:11:33 -0400413 outPortNo = action.GetOutput().Port
khenaidoo68c930b2019-05-13 11:46:51 -0400414 } else if action.Type != fu.POP_VLAN {
khenaidoo89b0e942018-10-21 21:11:33 -0400415 otherActions = append(otherActions, action)
416 }
417 }
418
khenaidoo19d7b632018-10-30 10:49:50 -0400419 route2 := agent.GetRoute(inPortNo, outPortNo)
khenaidoo89b0e942018-10-21 21:11:33 -0400420 switch len(route2) {
421 case 0:
422 log.Errorw("mc-no-route", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo, "comment": "deleting flow"})
423 // TODO: Delete flow
424 return deviceRules
425 case 2:
khenaidood20a5852018-10-22 22:09:55 -0400426 log.Debugw("route-found", log.Fields{"ingressHop": route2[0], "egressHop": route2[1]})
khenaidoo89b0e942018-10-21 21:11:33 -0400427 default:
428 log.Errorw("invalid-route-length", log.Fields{"routeLen": len(route)})
429 return deviceRules
430 }
431
khenaidood20a5852018-10-22 22:09:55 -0400432 ingressHop := route[0]
433 ingressHop2 := route2[0]
434 egressHop := route2[1]
435
436 if ingressHop.Ingress != ingressHop2.Ingress {
khenaidoo89b0e942018-10-21 21:11:33 -0400437 log.Errorw("mc-ingress-hop-hop2-mismatch", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo, "comment": "ignoring flow"})
438 return deviceRules
439 }
440 // Set the parent device flow
npujar1d86a522019-11-14 17:11:16 +0530441 fa := &fu.FlowArgs{
khenaidoo89b0e942018-10-21 21:11:33 -0400442 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
443 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -0400444 fu.InPort(ingressHop.Ingress),
khenaidoo89b0e942018-10-21 21:11:33 -0400445 },
446 }
447 // Augment the matchfields with the ofpfields from the flow
khenaidoo68c930b2019-05-13 11:46:51 -0400448 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
khenaidood20a5852018-10-22 22:09:55 -0400449
khenaidoo89b0e942018-10-21 21:11:33 -0400450 // Augment the Actions
khenaidoo68c930b2019-05-13 11:46:51 -0400451 filteredAction := fu.GetActions(flow, fu.GROUP)
452 filteredAction = append(filteredAction, fu.PopVlan())
453 filteredAction = append(filteredAction, fu.Output(route2[1].Ingress))
khenaidood20a5852018-10-22 22:09:55 -0400454 fa.Actions = filteredAction
455
khenaidoo89b0e942018-10-21 21:11:33 -0400456 fg := fu.NewFlowsAndGroups()
khenaidoo68c930b2019-05-13 11:46:51 -0400457 fg.AddFlow(fu.MkFlowStat(fa))
khenaidood20a5852018-10-22 22:09:55 -0400458 deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -0400459
460 // Set the child device flow
461 fa = &fu.FlowArgs{
462 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
463 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -0400464 fu.InPort(egressHop.Ingress),
khenaidoo89b0e942018-10-21 21:11:33 -0400465 },
466 }
467 // Augment the matchfields with the ofpfields from the flow
khenaidoo68c930b2019-05-13 11:46:51 -0400468 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT, fu.VLAN_VID, fu.VLAN_PCP)...)
khenaidood20a5852018-10-22 22:09:55 -0400469
khenaidoo89b0e942018-10-21 21:11:33 -0400470 // Augment the Actions
khenaidoo68c930b2019-05-13 11:46:51 -0400471 otherActions = append(otherActions, fu.Output(egressHop.Egress))
khenaidoo89b0e942018-10-21 21:11:33 -0400472 fa.Actions = otherActions
khenaidood20a5852018-10-22 22:09:55 -0400473
khenaidoo89b0e942018-10-21 21:11:33 -0400474 fg = fu.NewFlowsAndGroups()
khenaidoo68c930b2019-05-13 11:46:51 -0400475 fg.AddFlow(fu.MkFlowStat(fa))
khenaidood20a5852018-10-22 22:09:55 -0400476 deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -0400477 }
478 return deviceRules
479}
480
khenaidood20a5852018-10-22 22:09:55 -0400481// decomposeFlow decomposes a flow for a logical device into flows for each physical device
npujar1d86a522019-11-14 17:11:16 +0530482func (fd *FlowDecomposer) decomposeFlow(agent coreif.LogicalDeviceAgent, flow *ofp.OfpFlowStats,
khenaidood20a5852018-10-22 22:09:55 -0400483 groupMap map[uint32]*ofp.OfpGroupEntry) *fu.DeviceRules {
484
khenaidoo68c930b2019-05-13 11:46:51 -0400485 inPortNo := fu.GetInPort(flow)
486 outPortNo := fu.GetOutPort(flow)
khenaidoo89b0e942018-10-21 21:11:33 -0400487 deviceRules := fu.NewDeviceRules()
khenaidoo19d7b632018-10-30 10:49:50 -0400488 route := agent.GetRoute(inPortNo, outPortNo)
khenaidoo2c6a0992019-04-29 13:46:56 -0400489
khenaidoo89b0e942018-10-21 21:11:33 -0400490 switch len(route) {
491 case 0:
492 log.Errorw("no-route", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo, "comment": "deleting-flow"})
493 // TODO: Delete flow
494 return deviceRules
495 case 2:
496 log.Debugw("route-found", log.Fields{"ingressHop": route[0], "egressHop": route[1]})
khenaidoo89b0e942018-10-21 21:11:33 -0400497 default:
498 log.Errorw("invalid-route-length", log.Fields{"routeLen": len(route)})
499 return deviceRules
500 }
501
khenaidoo89b0e942018-10-21 21:11:33 -0400502 // Process controller bound flow
503 if outPortNo != 0 && (outPortNo&0x7fffffff) == uint32(ofp.OfpPortNo_OFPP_CONTROLLER) {
khenaidood20a5852018-10-22 22:09:55 -0400504 deviceRules = fd.processControllerBoundFlow(agent, route, inPortNo, outPortNo, flow)
khenaidoo89b0e942018-10-21 21:11:33 -0400505 } else {
khenaidoo297cd252019-02-07 22:10:23 -0500506 var ingressDevice *voltha.Device
507 var err error
508 if ingressDevice, err = fd.deviceMgr.GetDevice(route[0].DeviceID); err != nil {
509 log.Errorw("ingress-device-not-found", log.Fields{"deviceId": route[0].DeviceID, "flow": flow})
510 return deviceRules
511 }
512 isUpstream := !ingressDevice.Root
Manikkaraj kb1a10922019-07-29 12:10:34 -0400513 if isUpstream { // Unicast OLT and ONU UL
514 log.Info("processOltAndOnuUpstreamNonControllerBoundUnicastFlows", log.Fields{"flows": flow})
khenaidood20a5852018-10-22 22:09:55 -0400515 deviceRules = fd.processUpstreamNonControllerBoundFlow(agent, route, inPortNo, outPortNo, flow)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400516 } else if fu.HasNextTable(flow) && flow.TableId == 0 { // Unicast OLT flow DL
517 log.Debugw("processOltDownstreamNonControllerBoundFlowWithNextTable", log.Fields{"flows": flow})
khenaidood20a5852018-10-22 22:09:55 -0400518 deviceRules = fd.processDownstreamFlowWithNextTable(agent, route, inPortNo, outPortNo, flow)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400519 } else if flow.TableId == 1 && outPortNo != 0 { // Unicast ONU flow DL
520 log.Debugw("processOnuDownstreamUnicastFlow", log.Fields{"flows": flow})
khenaidood20a5852018-10-22 22:09:55 -0400521 deviceRules = fd.processUnicastFlow(agent, route, inPortNo, outPortNo, flow)
npujar1d86a522019-11-14 17:11:16 +0530522 } else if grpID := fu.GetGroup(flow); grpID != 0 && flow.TableId == 0 { //Multicast
Manikkaraj kb1a10922019-07-29 12:10:34 -0400523 log.Debugw("processMulticastFlow", log.Fields{"flows": flow})
npujar1d86a522019-11-14 17:11:16 +0530524 deviceRules = fd.processMulticastFlow(agent, route, inPortNo, outPortNo, flow, grpID, groupMap)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400525 } else {
526 log.Errorw("unknown-downstream-flow", log.Fields{"flow": *flow})
khenaidoo89b0e942018-10-21 21:11:33 -0400527 }
528 }
khenaidoo19d7b632018-10-30 10:49:50 -0400529 deviceRules = fd.updateOutputPortForControllerBoundFlowForParentDevide(flow, deviceRules)
khenaidoo89b0e942018-10-21 21:11:33 -0400530 return deviceRules
531}