blob: 581970599b6d96e5d47fa9f06a4b12a794653b1d [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 (
npujar467fe752020-01-16 20:17:45 +053020 "context"
khenaidoo19d7b632018-10-30 10:49:50 -040021 "github.com/gogo/protobuf/proto"
npujar1d86a522019-11-14 17:11:16 +053022 "github.com/opencord/voltha-go/rw_core/coreif"
khenaidoo89b0e942018-10-21 21:11:33 -040023 "github.com/opencord/voltha-go/rw_core/graph"
serkant.uluderya2ae470f2020-01-21 11:13:09 -080024 fu "github.com/opencord/voltha-lib-go/v3/pkg/flows"
25 "github.com/opencord/voltha-lib-go/v3/pkg/log"
26 ofp "github.com/opencord/voltha-protos/v3/go/openflow_13"
27 "github.com/opencord/voltha-protos/v3/go/voltha"
khenaidoo89b0e942018-10-21 21:11:33 -040028)
29
30func init() {
npujar1d86a522019-11-14 17:11:16 +053031 _, err := log.AddPackage(log.JSON, log.DebugLevel, nil)
32 if err != nil {
33 log.Errorw("unable-to-register-package-to-the-log-map", log.Fields{"error": err})
34 }
khenaidoo89b0e942018-10-21 21:11:33 -040035}
36
npujar1d86a522019-11-14 17:11:16 +053037// FlowDecomposer represent flow decomposer attribute
khenaidoo89b0e942018-10-21 21:11:33 -040038type FlowDecomposer struct {
npujar1d86a522019-11-14 17:11:16 +053039 deviceMgr coreif.DeviceManager
khenaidoo89b0e942018-10-21 21:11:33 -040040}
41
npujar1d86a522019-11-14 17:11:16 +053042// NewFlowDecomposer creates flow decomposer instance
43func NewFlowDecomposer(deviceMgr coreif.DeviceManager) *FlowDecomposer {
khenaidoo89b0e942018-10-21 21:11:33 -040044 var decomposer FlowDecomposer
45 decomposer.deviceMgr = deviceMgr
46 return &decomposer
47}
48
49//DecomposeRules decomposes per-device flows and flow-groups from the flows and groups defined on a logical device
npujar467fe752020-01-16 20:17:45 +053050func (fd *FlowDecomposer) DecomposeRules(ctx context.Context, agent coreif.LogicalDeviceAgent, flows ofp.Flows, groups ofp.FlowGroups) *fu.DeviceRules {
khenaidoo3306c992019-05-24 16:57:35 -040051 deviceRules := *fu.NewDeviceRules()
khenaidoo2c6a0992019-04-29 13:46:56 -040052 devicesToUpdate := make(map[string]string)
khenaidoo89b0e942018-10-21 21:11:33 -040053
54 groupMap := make(map[uint32]*ofp.OfpGroupEntry)
55 for _, groupEntry := range groups.Items {
56 groupMap[groupEntry.Desc.GroupId] = groupEntry
57 }
58
59 var decomposedRules *fu.DeviceRules
60 for _, flow := range flows.Items {
npujar467fe752020-01-16 20:17:45 +053061 decomposedRules = fd.decomposeFlow(ctx, agent, flow, groupMap)
npujar1d86a522019-11-14 17:11:16 +053062 for deviceID, flowAndGroups := range decomposedRules.Rules {
63 deviceRules.CreateEntryIfNotExist(deviceID)
64 deviceRules.Rules[deviceID].AddFrom(flowAndGroups)
65 devicesToUpdate[deviceID] = deviceID
khenaidoo89b0e942018-10-21 21:11:33 -040066 }
67 }
khenaidoo3306c992019-05-24 16:57:35 -040068 return deviceRules.FilterRules(devicesToUpdate)
khenaidoo89b0e942018-10-21 21:11:33 -040069}
70
khenaidoo19d7b632018-10-30 10:49:50 -040071// Handles special case of any controller-bound flow for a parent device
72func (fd *FlowDecomposer) updateOutputPortForControllerBoundFlowForParentDevide(flow *ofp.OfpFlowStats,
73 dr *fu.DeviceRules) *fu.DeviceRules {
khenaidoo68c930b2019-05-13 11:46:51 -040074 EAPOL := fu.EthType(0x888e)
75 IGMP := fu.IpProto(2)
76 UDP := fu.IpProto(17)
khenaidoo19d7b632018-10-30 10:49:50 -040077
78 newDeviceRules := dr.Copy()
79 // Check whether we are dealing with a parent device
npujar1d86a522019-11-14 17:11:16 +053080 for deviceID, fg := range dr.GetRules() {
81 if root, _ := fd.deviceMgr.IsRootDevice(deviceID); root {
82 newDeviceRules.ClearFlows(deviceID)
khenaidoo19d7b632018-10-30 10:49:50 -040083 for i := 0; i < fg.Flows.Len(); i++ {
84 f := fg.GetFlow(i)
85 UpdateOutPortNo := false
khenaidoo68c930b2019-05-13 11:46:51 -040086 for _, field := range fu.GetOfbFields(f) {
khenaidoo19d7b632018-10-30 10:49:50 -040087 UpdateOutPortNo = (field.String() == EAPOL.String())
88 UpdateOutPortNo = UpdateOutPortNo || (field.String() == IGMP.String())
89 UpdateOutPortNo = UpdateOutPortNo || (field.String() == UDP.String())
90 if UpdateOutPortNo {
91 break
92 }
93 }
94 if UpdateOutPortNo {
khenaidoo68c930b2019-05-13 11:46:51 -040095 f = fu.UpdateOutputPortByActionType(f, uint32(ofp.OfpInstructionType_OFPIT_APPLY_ACTIONS),
khenaidoo19d7b632018-10-30 10:49:50 -040096 uint32(ofp.OfpPortNo_OFPP_CONTROLLER))
97 }
98 // Update flow Id as a change in the instruction field will result in a new flow ID
khenaidoo68c930b2019-05-13 11:46:51 -040099 f.Id = fu.HashFlowStats(f)
npujar1d86a522019-11-14 17:11:16 +0530100 newDeviceRules.AddFlow(deviceID, (proto.Clone(f)).(*ofp.OfpFlowStats))
khenaidoo19d7b632018-10-30 10:49:50 -0400101 }
102 }
103 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400104
khenaidoo19d7b632018-10-30 10:49:50 -0400105 return newDeviceRules
106}
107
khenaidood20a5852018-10-22 22:09:55 -0400108//processControllerBoundFlow decomposes trap flows
npujar1d86a522019-11-14 17:11:16 +0530109func (fd *FlowDecomposer) processControllerBoundFlow(agent coreif.LogicalDeviceAgent, route []graph.RouteHop,
khenaidood20a5852018-10-22 22:09:55 -0400110 inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats) *fu.DeviceRules {
111
khenaidoo89b0e942018-10-21 21:11:33 -0400112 log.Debugw("trap-flow", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo, "flow": flow})
khenaidood20a5852018-10-22 22:09:55 -0400113 deviceRules := fu.NewDeviceRules()
npujar1d86a522019-11-14 17:11:16 +0530114 meterID := fu.GetMeterIdFromFlow(flow)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400115 metadataFromwriteMetadata := fu.GetMetadataFromWriteMetadataAction(flow)
khenaidood20a5852018-10-22 22:09:55 -0400116
Matt Jeanneretb423bad2019-10-10 20:42:19 -0400117 ingressHop := route[0]
khenaidood20a5852018-10-22 22:09:55 -0400118 egressHop := route[1]
119
Humera Kouser4ff89012019-08-25 19:01:51 -0400120 //case of packet_in from NNI port rule
khenaidoo89b0e942018-10-21 21:11:33 -0400121 if agent.GetDeviceGraph().IsRootPort(inPortNo) {
Humera Kouser4ff89012019-08-25 19:01:51 -0400122 // Trap flow for NNI port
khenaidoo89b0e942018-10-21 21:11:33 -0400123 log.Debug("trap-nni")
Humera Kouser4ff89012019-08-25 19:01:51 -0400124
npujar1d86a522019-11-14 17:11:16 +0530125 fa := &fu.FlowArgs{
Humera Kouser4ff89012019-08-25 19:01:51 -0400126 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
127 MatchFields: []*ofp.OfpOxmOfbField{
128 fu.InPort(egressHop.Egress),
129 },
130 Actions: fu.GetActions(flow),
131 }
132 // Augment the matchfields with the ofpfields from the flow
Matt Jeanneretb423bad2019-10-10 20:42:19 -0400133 fg := fu.NewFlowsAndGroups()
Humera Kouser4ff89012019-08-25 19:01:51 -0400134 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
135 fg.AddFlow(fu.MkFlowStat(fa))
Matt Jeanneretb423bad2019-10-10 20:42:19 -0400136 deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -0400137 } else {
138 // Trap flow for UNI port
139 log.Debug("trap-uni")
140
141 //inPortNo is 0 for wildcard input case, do not include upstream port for 4000 flow in input
142 var inPorts []uint32
143 if inPortNo == 0 {
khenaidood20a5852018-10-22 22:09:55 -0400144 inPorts = agent.GetWildcardInputPorts(egressHop.Egress) // exclude egress_hop.egress_port.port_no
khenaidoo89b0e942018-10-21 21:11:33 -0400145 } else {
146 inPorts = []uint32{inPortNo}
147 }
148 for _, inputPort := range inPorts {
Matt Jeanneretb423bad2019-10-10 20:42:19 -0400149 // Upstream flow on parent (olt) device
npujar1d86a522019-11-14 17:11:16 +0530150 faParent := &fu.FlowArgs{
151 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie, "meter_id": uint64(meterID), "write_metadata": metadataFromwriteMetadata},
khenaidoo89b0e942018-10-21 21:11:33 -0400152 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -0400153 fu.InPort(egressHop.Ingress),
khenaidoo68c930b2019-05-13 11:46:51 -0400154 fu.TunnelId(uint64(inputPort)),
khenaidoo89b0e942018-10-21 21:11:33 -0400155 },
156 Actions: []*ofp.OfpAction{
khenaidoo68c930b2019-05-13 11:46:51 -0400157 fu.PushVlan(0x8100),
158 fu.SetField(fu.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 4000)),
159 fu.Output(egressHop.Egress),
khenaidoo89b0e942018-10-21 21:11:33 -0400160 },
161 }
162 // Augment the matchfields with the ofpfields from the flow
Matt Jeanneretb423bad2019-10-10 20:42:19 -0400163 faParent.MatchFields = append(faParent.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
164 fgParent := fu.NewFlowsAndGroups()
165 fgParent.AddFlow(fu.MkFlowStat(faParent))
166 deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fgParent)
167 log.Debugw("parent-trap-flow-set", log.Fields{"flow": faParent})
168
169 // Upstream flow on child (onu) device
170 var actions []*ofp.OfpAction
171 setvid := fu.GetVlanVid(flow)
172 if setvid != nil {
173 // have this child push the vlan the parent is matching/trapping on above
174 actions = []*ofp.OfpAction{
175 fu.PushVlan(0x8100),
176 fu.SetField(fu.VlanVid(*setvid)),
177 fu.Output(ingressHop.Egress),
178 }
179 } else {
180 // otherwise just set the egress port
181 actions = []*ofp.OfpAction{
182 fu.Output(ingressHop.Egress),
183 }
184 }
npujar1d86a522019-11-14 17:11:16 +0530185 faChild := &fu.FlowArgs{
186 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie, "meter_id": uint64(meterID), "write_metadata": metadataFromwriteMetadata},
Matt Jeanneretb423bad2019-10-10 20:42:19 -0400187 MatchFields: []*ofp.OfpOxmOfbField{
188 fu.InPort(ingressHop.Ingress),
189 fu.TunnelId(uint64(inputPort)),
190 },
191 Actions: actions,
192 }
193 // Augment the matchfields with the ofpfields from the flow.
194 // If the parent has a match vid and the child is setting that match vid exclude the the match vlan
195 // for the child given it will be setting that vlan and the parent will be matching on it
196 if setvid != nil {
197 faChild.MatchFields = append(faChild.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT, fu.VLAN_VID)...)
198 } else {
199 faChild.MatchFields = append(faChild.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
200 }
201 fgChild := fu.NewFlowsAndGroups()
202 fgChild.AddFlow(fu.MkFlowStat(faChild))
203 deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fgChild)
204 log.Debugw("child-trap-flow-set", log.Fields{"flow": faChild})
khenaidoo89b0e942018-10-21 21:11:33 -0400205 }
206 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400207
khenaidoo89b0e942018-10-21 21:11:33 -0400208 return deviceRules
209}
210
211// processUpstreamNonControllerBoundFlow processes non-controller bound flow. We assume that anything that is
212// upstream needs to get Q-in-Q treatment and that this is expressed via two flow rules, the first using the
213// goto-statement. We also assume that the inner tag is applied at the ONU, while the outer tag is
214// applied at the OLT
npujar1d86a522019-11-14 17:11:16 +0530215func (fd *FlowDecomposer) processUpstreamNonControllerBoundFlow(agent coreif.LogicalDeviceAgent,
khenaidood20a5852018-10-22 22:09:55 -0400216 route []graph.RouteHop, inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats) *fu.DeviceRules {
217
khenaidoo89b0e942018-10-21 21:11:33 -0400218 log.Debugw("upstream-non-controller-bound-flow", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo})
khenaidood20a5852018-10-22 22:09:55 -0400219 deviceRules := fu.NewDeviceRules()
220
npujar1d86a522019-11-14 17:11:16 +0530221 meterID := fu.GetMeterIdFromFlow(flow)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400222 metadataFromwriteMetadata := fu.GetMetadataFromWriteMetadataAction(flow)
223
khenaidood20a5852018-10-22 22:09:55 -0400224 ingressHop := route[0]
225 egressHop := route[1]
226
Manikkaraj kb1a10922019-07-29 12:10:34 -0400227 if flow.TableId == 0 && fu.HasNextTable(flow) {
228 log.Debugw("decomposing-onu-flow-in-upstream-has-next-table", log.Fields{"table_id": flow.TableId})
khenaidoo89b0e942018-10-21 21:11:33 -0400229 if outPortNo != 0 {
230 log.Warnw("outPort-should-not-be-specified", log.Fields{"outPortNo": outPortNo})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400231 return deviceRules
khenaidoo89b0e942018-10-21 21:11:33 -0400232 }
npujar1d86a522019-11-14 17:11:16 +0530233 fa := &fu.FlowArgs{
234 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie, "meter_id": uint64(meterID), "write_metadata": metadataFromwriteMetadata},
khenaidoo89b0e942018-10-21 21:11:33 -0400235 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -0400236 fu.InPort(ingressHop.Ingress),
237 fu.TunnelId(uint64(inPortNo)),
khenaidoo89b0e942018-10-21 21:11:33 -0400238 },
khenaidoo68c930b2019-05-13 11:46:51 -0400239 Actions: fu.GetActions(flow),
khenaidoo89b0e942018-10-21 21:11:33 -0400240 }
241 // Augment the matchfields with the ofpfields from the flow
khenaidoo68c930b2019-05-13 11:46:51 -0400242 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
khenaidood20a5852018-10-22 22:09:55 -0400243
244 // Augment the Actions
khenaidoo68c930b2019-05-13 11:46:51 -0400245 fa.Actions = append(fa.Actions, fu.Output(ingressHop.Egress))
khenaidood20a5852018-10-22 22:09:55 -0400246
khenaidoo89b0e942018-10-21 21:11:33 -0400247 fg := fu.NewFlowsAndGroups()
khenaidoo68c930b2019-05-13 11:46:51 -0400248 fg.AddFlow(fu.MkFlowStat(fa))
khenaidood20a5852018-10-22 22:09:55 -0400249 deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fg)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400250 } else if flow.TableId == 1 && outPortNo != 0 {
251 log.Debugw("decomposing-olt-flow-in-upstream-has-next-table", log.Fields{"table_id": flow.TableId})
npujar1d86a522019-11-14 17:11:16 +0530252 fa := &fu.FlowArgs{
253 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie, "meter_id": uint64(meterID), "write_metadata": metadataFromwriteMetadata},
Manikkaraj kb1a10922019-07-29 12:10:34 -0400254 MatchFields: []*ofp.OfpOxmOfbField{
255 fu.InPort(egressHop.Ingress),
256 fu.TunnelId(uint64(inPortNo)),
257 },
khenaidoo89b0e942018-10-21 21:11:33 -0400258 }
Manikkaraj kb1a10922019-07-29 12:10:34 -0400259 // Augment the matchfields with the ofpfields from the flow
260 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
khenaidoo89b0e942018-10-21 21:11:33 -0400261
Manikkaraj kb1a10922019-07-29 12:10:34 -0400262 //Augment the actions
263 filteredAction := fu.GetActions(flow, fu.OUTPUT)
264 filteredAction = append(filteredAction, fu.Output(egressHop.Egress))
265 fa.Actions = filteredAction
khenaidood20a5852018-10-22 22:09:55 -0400266
Manikkaraj kb1a10922019-07-29 12:10:34 -0400267 fg := fu.NewFlowsAndGroups()
268 fg.AddFlow(fu.MkFlowStat(fa))
269 deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -0400270 }
271 return deviceRules
272}
273
khenaidood20a5852018-10-22 22:09:55 -0400274// processDownstreamFlowWithNextTable decomposes downstream flows containing next table ID instructions
npujar1d86a522019-11-14 17:11:16 +0530275func (fd *FlowDecomposer) processDownstreamFlowWithNextTable(agent coreif.LogicalDeviceAgent, route []graph.RouteHop,
khenaidood20a5852018-10-22 22:09:55 -0400276 inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats) *fu.DeviceRules {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400277 log.Debugw("decomposing-olt-flow-in-downstream-flow-with-next-table", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo})
khenaidood20a5852018-10-22 22:09:55 -0400278 deviceRules := fu.NewDeviceRules()
npujar1d86a522019-11-14 17:11:16 +0530279 meterID := fu.GetMeterIdFromFlow(flow)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400280 metadataFromwriteMetadata := fu.GetMetadataFromWriteMetadataAction(flow)
khenaidood20a5852018-10-22 22:09:55 -0400281
khenaidoo89b0e942018-10-21 21:11:33 -0400282 if outPortNo != 0 {
283 log.Warnw("outPort-should-not-be-specified", log.Fields{"outPortNo": outPortNo})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400284 return deviceRules
khenaidoo89b0e942018-10-21 21:11:33 -0400285 }
Manikkaraj kb1a10922019-07-29 12:10:34 -0400286
287 if flow.TableId != 0 {
288 log.Warnw("This is not olt pipeline table, so skipping", log.Fields{"tableId": flow.TableId})
289 return deviceRules
290 }
291
khenaidoo89b0e942018-10-21 21:11:33 -0400292 ingressHop := route[0]
khenaidood20a5852018-10-22 22:09:55 -0400293 egressHop := route[1]
Manikkaraj kb1a10922019-07-29 12:10:34 -0400294 if metadataFromwriteMetadata != 0 {
khenaidoo89b0e942018-10-21 21:11:33 -0400295 log.Debugw("creating-metadata-flow", log.Fields{"flow": flow})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400296 portNumber := fu.GetEgressPortNumberFromWriteMetadata(flow)
khenaidoo89b0e942018-10-21 21:11:33 -0400297 if portNumber != 0 {
khenaidoo19d7b632018-10-30 10:49:50 -0400298 recalculatedRoute := agent.GetRoute(inPortNo, portNumber)
khenaidoo89b0e942018-10-21 21:11:33 -0400299 switch len(recalculatedRoute) {
300 case 0:
Manikkaraj kb1a10922019-07-29 12:10:34 -0400301 log.Errorw("no-route-double-tag", log.Fields{"inPortNo": inPortNo, "outPortNo": portNumber, "comment": "deleting-flow", "metadata": metadataFromwriteMetadata})
302 //TODO: Delete flow
khenaidoo89b0e942018-10-21 21:11:33 -0400303 return deviceRules
304 case 2:
khenaidood20a5852018-10-22 22:09:55 -0400305 log.Debugw("route-found", log.Fields{"ingressHop": ingressHop, "egressHop": egressHop})
khenaidoo89b0e942018-10-21 21:11:33 -0400306 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 }
npujar1d86a522019-11-14 17:11:16 +0530318 fa := &fu.FlowArgs{
319 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie, "meter_id": uint64(meterID), "write_metadata": metadataFromwriteMetadata},
khenaidoo89b0e942018-10-21 21:11:33 -0400320 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -0400321 fu.InPort(ingressHop.Ingress),
Manikkaraj kb1a10922019-07-29 12:10:34 -0400322 fu.Metadata_ofp(uint64(innerTag)),
khenaidoo68c930b2019-05-13 11:46:51 -0400323 fu.TunnelId(uint64(portNumber)),
khenaidoo89b0e942018-10-21 21:11:33 -0400324 },
khenaidoo68c930b2019-05-13 11:46:51 -0400325 Actions: fu.GetActions(flow),
khenaidoo89b0e942018-10-21 21:11:33 -0400326 }
327 // Augment the matchfields with the ofpfields from the flow
khenaidoo68c930b2019-05-13 11:46:51 -0400328 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT, fu.METADATA)...)
khenaidood20a5852018-10-22 22:09:55 -0400329
330 // Augment the Actions
khenaidoo68c930b2019-05-13 11:46:51 -0400331 fa.Actions = append(fa.Actions, fu.Output(ingressHop.Egress))
khenaidood20a5852018-10-22 22:09:55 -0400332
khenaidoo89b0e942018-10-21 21:11:33 -0400333 fg := fu.NewFlowsAndGroups()
khenaidoo68c930b2019-05-13 11:46:51 -0400334 fg.AddFlow(fu.MkFlowStat(fa))
khenaidoo89b0e942018-10-21 21:11:33 -0400335 deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fg)
336 } else { // Create standard flow
337 log.Debugw("creating-standard-flow", log.Fields{"flow": flow})
npujar1d86a522019-11-14 17:11:16 +0530338 fa := &fu.FlowArgs{
339 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie, "meter_id": uint64(meterID), "write_metadata": metadataFromwriteMetadata},
khenaidoo89b0e942018-10-21 21:11:33 -0400340 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -0400341 fu.InPort(ingressHop.Ingress),
342 fu.TunnelId(uint64(inPortNo)),
khenaidoo89b0e942018-10-21 21:11:33 -0400343 },
khenaidoo68c930b2019-05-13 11:46:51 -0400344 Actions: fu.GetActions(flow),
khenaidoo89b0e942018-10-21 21:11:33 -0400345 }
346 // Augment the matchfields with the ofpfields from the flow
khenaidoo68c930b2019-05-13 11:46:51 -0400347 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
khenaidood20a5852018-10-22 22:09:55 -0400348
349 // Augment the Actions
khenaidoo68c930b2019-05-13 11:46:51 -0400350 fa.Actions = append(fa.Actions, fu.Output(ingressHop.Egress))
khenaidood20a5852018-10-22 22:09:55 -0400351
khenaidoo89b0e942018-10-21 21:11:33 -0400352 fg := fu.NewFlowsAndGroups()
khenaidoo68c930b2019-05-13 11:46:51 -0400353 fg.AddFlow(fu.MkFlowStat(fa))
khenaidoo89b0e942018-10-21 21:11:33 -0400354 deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fg)
355 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400356
khenaidoo89b0e942018-10-21 21:11:33 -0400357 return deviceRules
358}
359
khenaidood20a5852018-10-22 22:09:55 -0400360// processUnicastFlow decomposes unicast flows
npujar1d86a522019-11-14 17:11:16 +0530361func (fd *FlowDecomposer) processUnicastFlow(agent coreif.LogicalDeviceAgent, route []graph.RouteHop,
khenaidood20a5852018-10-22 22:09:55 -0400362 inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats) *fu.DeviceRules {
363
Manikkaraj kb1a10922019-07-29 12:10:34 -0400364 log.Debugw("decomposing-onu-flow-in-downstream-unicast-flow", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo})
khenaidood20a5852018-10-22 22:09:55 -0400365 deviceRules := fu.NewDeviceRules()
366
khenaidood20a5852018-10-22 22:09:55 -0400367 egressHop := route[1]
368
npujar1d86a522019-11-14 17:11:16 +0530369 meterID := fu.GetMeterIdFromFlow(flow)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400370 metadataFromwriteMetadata := fu.GetMetadataFromWriteMetadataAction(flow)
npujar1d86a522019-11-14 17:11:16 +0530371 fa := &fu.FlowArgs{
372 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie, "meter_id": uint64(meterID), "write_metadata": metadataFromwriteMetadata},
Manikkaraj kb1a10922019-07-29 12:10:34 -0400373 MatchFields: []*ofp.OfpOxmOfbField{
374 fu.InPort(egressHop.Ingress),
375 },
khenaidoo89b0e942018-10-21 21:11:33 -0400376 }
Manikkaraj kb1a10922019-07-29 12:10:34 -0400377 // Augment the matchfields with the ofpfields from the flow
378 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
khenaidood20a5852018-10-22 22:09:55 -0400379
Manikkaraj kb1a10922019-07-29 12:10:34 -0400380 // Augment the Actions
381 filteredAction := fu.GetActions(flow, fu.OUTPUT)
382 filteredAction = append(filteredAction, fu.Output(egressHop.Egress))
383 fa.Actions = filteredAction
khenaidoo89b0e942018-10-21 21:11:33 -0400384
Manikkaraj kb1a10922019-07-29 12:10:34 -0400385 fg := fu.NewFlowsAndGroups()
386 fg.AddFlow(fu.MkFlowStat(fa))
387 deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -0400388 return deviceRules
389}
390
khenaidood20a5852018-10-22 22:09:55 -0400391// processMulticastFlow decompose multicast flows
npujar1d86a522019-11-14 17:11:16 +0530392func (fd *FlowDecomposer) processMulticastFlow(agent coreif.LogicalDeviceAgent, route []graph.RouteHop,
393 inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats, grpID uint32,
khenaidood20a5852018-10-22 22:09:55 -0400394 groupMap map[uint32]*ofp.OfpGroupEntry) *fu.DeviceRules {
395
khenaidoo89b0e942018-10-21 21:11:33 -0400396 log.Debugw("multicast-flow", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo})
khenaidood20a5852018-10-22 22:09:55 -0400397 deviceRules := fu.NewDeviceRules()
khenaidoo89b0e942018-10-21 21:11:33 -0400398
399 //having no Group yet is the same as having a Group with no buckets
400 var grp *ofp.OfpGroupEntry
401 var ok bool
npujar1d86a522019-11-14 17:11:16 +0530402 if grp, ok = groupMap[grpID]; !ok {
403 log.Warnw("Group-id-not-present-in-map", log.Fields{"grpId": grpID, "groupMap": groupMap})
khenaidoo89b0e942018-10-21 21:11:33 -0400404 return deviceRules
405 }
406 if grp == nil || grp.Desc == nil {
npujar1d86a522019-11-14 17:11:16 +0530407 log.Warnw("Group-or-desc-nil", log.Fields{"grpId": grpID, "grp": grp})
khenaidoo89b0e942018-10-21 21:11:33 -0400408 return deviceRules
409 }
khenaidoo89b0e942018-10-21 21:11:33 -0400410
Esin Karaman09959ae2019-11-29 13:59:58 +0000411 deviceRules.CreateEntryIfNotExist(route[0].DeviceID)
412 fg := fu.NewFlowsAndGroups()
413 fg.AddFlow(flow)
414 //return the multicast flow without decomposing it
415 deviceRules.AddFlowsAndGroup(route[0].DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -0400416 return deviceRules
417}
418
khenaidood20a5852018-10-22 22:09:55 -0400419// decomposeFlow decomposes a flow for a logical device into flows for each physical device
npujar467fe752020-01-16 20:17:45 +0530420func (fd *FlowDecomposer) decomposeFlow(ctx context.Context, agent coreif.LogicalDeviceAgent, flow *ofp.OfpFlowStats,
khenaidood20a5852018-10-22 22:09:55 -0400421 groupMap map[uint32]*ofp.OfpGroupEntry) *fu.DeviceRules {
422
khenaidoo68c930b2019-05-13 11:46:51 -0400423 inPortNo := fu.GetInPort(flow)
Esin Karaman09959ae2019-11-29 13:59:58 +0000424 if fu.HasGroup(flow) && inPortNo == 0 {
425 //if no in-port specified for a multicast flow, put NNI port as in-port
426 //so that a valid route can be found for the flow
427 nniPorts := agent.GetNNIPorts()
428 if len(nniPorts) > 0 {
429 inPortNo = nniPorts[0]
430 log.Debugw("Assigning NNI port as in-port for the multicast flow", log.Fields{"nni": nniPorts[0], "flow:": flow})
431 }
432 }
khenaidoo68c930b2019-05-13 11:46:51 -0400433 outPortNo := fu.GetOutPort(flow)
khenaidoo89b0e942018-10-21 21:11:33 -0400434 deviceRules := fu.NewDeviceRules()
khenaidoo19d7b632018-10-30 10:49:50 -0400435 route := agent.GetRoute(inPortNo, outPortNo)
khenaidoo2c6a0992019-04-29 13:46:56 -0400436
khenaidoo89b0e942018-10-21 21:11:33 -0400437 switch len(route) {
438 case 0:
439 log.Errorw("no-route", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo, "comment": "deleting-flow"})
440 // TODO: Delete flow
441 return deviceRules
442 case 2:
443 log.Debugw("route-found", log.Fields{"ingressHop": route[0], "egressHop": route[1]})
khenaidoo89b0e942018-10-21 21:11:33 -0400444 default:
445 log.Errorw("invalid-route-length", log.Fields{"routeLen": len(route)})
446 return deviceRules
447 }
448
khenaidoo89b0e942018-10-21 21:11:33 -0400449 // Process controller bound flow
450 if outPortNo != 0 && (outPortNo&0x7fffffff) == uint32(ofp.OfpPortNo_OFPP_CONTROLLER) {
khenaidood20a5852018-10-22 22:09:55 -0400451 deviceRules = fd.processControllerBoundFlow(agent, route, inPortNo, outPortNo, flow)
khenaidoo89b0e942018-10-21 21:11:33 -0400452 } else {
khenaidoo297cd252019-02-07 22:10:23 -0500453 var ingressDevice *voltha.Device
454 var err error
npujar467fe752020-01-16 20:17:45 +0530455 if ingressDevice, err = fd.deviceMgr.GetDevice(ctx, route[0].DeviceID); err != nil {
khenaidoo297cd252019-02-07 22:10:23 -0500456 log.Errorw("ingress-device-not-found", log.Fields{"deviceId": route[0].DeviceID, "flow": flow})
457 return deviceRules
458 }
459 isUpstream := !ingressDevice.Root
Manikkaraj kb1a10922019-07-29 12:10:34 -0400460 if isUpstream { // Unicast OLT and ONU UL
461 log.Info("processOltAndOnuUpstreamNonControllerBoundUnicastFlows", log.Fields{"flows": flow})
khenaidood20a5852018-10-22 22:09:55 -0400462 deviceRules = fd.processUpstreamNonControllerBoundFlow(agent, route, inPortNo, outPortNo, flow)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400463 } else if fu.HasNextTable(flow) && flow.TableId == 0 { // Unicast OLT flow DL
464 log.Debugw("processOltDownstreamNonControllerBoundFlowWithNextTable", log.Fields{"flows": flow})
khenaidood20a5852018-10-22 22:09:55 -0400465 deviceRules = fd.processDownstreamFlowWithNextTable(agent, route, inPortNo, outPortNo, flow)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400466 } else if flow.TableId == 1 && outPortNo != 0 { // Unicast ONU flow DL
467 log.Debugw("processOnuDownstreamUnicastFlow", log.Fields{"flows": flow})
khenaidood20a5852018-10-22 22:09:55 -0400468 deviceRules = fd.processUnicastFlow(agent, route, inPortNo, outPortNo, flow)
npujar1d86a522019-11-14 17:11:16 +0530469 } else if grpID := fu.GetGroup(flow); grpID != 0 && flow.TableId == 0 { //Multicast
Manikkaraj kb1a10922019-07-29 12:10:34 -0400470 log.Debugw("processMulticastFlow", log.Fields{"flows": flow})
npujar1d86a522019-11-14 17:11:16 +0530471 deviceRules = fd.processMulticastFlow(agent, route, inPortNo, outPortNo, flow, grpID, groupMap)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400472 } else {
473 log.Errorw("unknown-downstream-flow", log.Fields{"flow": *flow})
khenaidoo89b0e942018-10-21 21:11:33 -0400474 }
475 }
khenaidoo19d7b632018-10-30 10:49:50 -0400476 deviceRules = fd.updateOutputPortForControllerBoundFlowForParentDevide(flow, deviceRules)
khenaidoo89b0e942018-10-21 21:11:33 -0400477 return deviceRules
478}