blob: 9e996dcfdd97419b55aae40c3c26ccd5bf5285aa [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"
khenaidoo820197c2020-02-13 16:35:33 -050023 "github.com/opencord/voltha-go/rw_core/route"
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"
khenaidoo820197c2020-02-13 16:35:33 -050028 "google.golang.org/grpc/codes"
29 "google.golang.org/grpc/status"
khenaidoo89b0e942018-10-21 21:11:33 -040030)
31
32func init() {
npujar1d86a522019-11-14 17:11:16 +053033 _, err := log.AddPackage(log.JSON, log.DebugLevel, nil)
34 if err != nil {
35 log.Errorw("unable-to-register-package-to-the-log-map", log.Fields{"error": err})
36 }
khenaidoo89b0e942018-10-21 21:11:33 -040037}
38
npujar1d86a522019-11-14 17:11:16 +053039// FlowDecomposer represent flow decomposer attribute
khenaidoo89b0e942018-10-21 21:11:33 -040040type FlowDecomposer struct {
npujar1d86a522019-11-14 17:11:16 +053041 deviceMgr coreif.DeviceManager
khenaidoo89b0e942018-10-21 21:11:33 -040042}
43
npujar1d86a522019-11-14 17:11:16 +053044// NewFlowDecomposer creates flow decomposer instance
45func NewFlowDecomposer(deviceMgr coreif.DeviceManager) *FlowDecomposer {
khenaidoo89b0e942018-10-21 21:11:33 -040046 var decomposer FlowDecomposer
47 decomposer.deviceMgr = deviceMgr
48 return &decomposer
49}
50
51//DecomposeRules decomposes per-device flows and flow-groups from the flows and groups defined on a logical device
khenaidoo820197c2020-02-13 16:35:33 -050052func (fd *FlowDecomposer) DecomposeRules(ctx context.Context, agent coreif.LogicalDeviceAgent, flows ofp.Flows, groups ofp.FlowGroups) (*fu.DeviceRules, error) {
khenaidoo3306c992019-05-24 16:57:35 -040053 deviceRules := *fu.NewDeviceRules()
khenaidoo2c6a0992019-04-29 13:46:56 -040054 devicesToUpdate := make(map[string]string)
khenaidoo89b0e942018-10-21 21:11:33 -040055
56 groupMap := make(map[uint32]*ofp.OfpGroupEntry)
57 for _, groupEntry := range groups.Items {
58 groupMap[groupEntry.Desc.GroupId] = groupEntry
59 }
60
khenaidoo89b0e942018-10-21 21:11:33 -040061 for _, flow := range flows.Items {
khenaidoo820197c2020-02-13 16:35:33 -050062 decomposedRules, err := fd.decomposeFlow(ctx, agent, flow, groupMap)
63 if err != nil {
64 return nil, err
65 }
npujar1d86a522019-11-14 17:11:16 +053066 for deviceID, flowAndGroups := range decomposedRules.Rules {
67 deviceRules.CreateEntryIfNotExist(deviceID)
68 deviceRules.Rules[deviceID].AddFrom(flowAndGroups)
69 devicesToUpdate[deviceID] = deviceID
khenaidoo89b0e942018-10-21 21:11:33 -040070 }
71 }
khenaidoo820197c2020-02-13 16:35:33 -050072 return deviceRules.FilterRules(devicesToUpdate), nil
khenaidoo89b0e942018-10-21 21:11:33 -040073}
74
khenaidoo19d7b632018-10-30 10:49:50 -040075// Handles special case of any controller-bound flow for a parent device
76func (fd *FlowDecomposer) updateOutputPortForControllerBoundFlowForParentDevide(flow *ofp.OfpFlowStats,
77 dr *fu.DeviceRules) *fu.DeviceRules {
khenaidoo68c930b2019-05-13 11:46:51 -040078 EAPOL := fu.EthType(0x888e)
79 IGMP := fu.IpProto(2)
80 UDP := fu.IpProto(17)
khenaidoo19d7b632018-10-30 10:49:50 -040081
82 newDeviceRules := dr.Copy()
83 // Check whether we are dealing with a parent device
npujar1d86a522019-11-14 17:11:16 +053084 for deviceID, fg := range dr.GetRules() {
85 if root, _ := fd.deviceMgr.IsRootDevice(deviceID); root {
86 newDeviceRules.ClearFlows(deviceID)
khenaidoo19d7b632018-10-30 10:49:50 -040087 for i := 0; i < fg.Flows.Len(); i++ {
88 f := fg.GetFlow(i)
89 UpdateOutPortNo := false
khenaidoo68c930b2019-05-13 11:46:51 -040090 for _, field := range fu.GetOfbFields(f) {
khenaidoo19d7b632018-10-30 10:49:50 -040091 UpdateOutPortNo = (field.String() == EAPOL.String())
92 UpdateOutPortNo = UpdateOutPortNo || (field.String() == IGMP.String())
93 UpdateOutPortNo = UpdateOutPortNo || (field.String() == UDP.String())
94 if UpdateOutPortNo {
95 break
96 }
97 }
98 if UpdateOutPortNo {
khenaidoo68c930b2019-05-13 11:46:51 -040099 f = fu.UpdateOutputPortByActionType(f, uint32(ofp.OfpInstructionType_OFPIT_APPLY_ACTIONS),
khenaidoo19d7b632018-10-30 10:49:50 -0400100 uint32(ofp.OfpPortNo_OFPP_CONTROLLER))
101 }
102 // Update flow Id as a change in the instruction field will result in a new flow ID
khenaidoo68c930b2019-05-13 11:46:51 -0400103 f.Id = fu.HashFlowStats(f)
npujar1d86a522019-11-14 17:11:16 +0530104 newDeviceRules.AddFlow(deviceID, (proto.Clone(f)).(*ofp.OfpFlowStats))
khenaidoo19d7b632018-10-30 10:49:50 -0400105 }
106 }
107 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400108
khenaidoo19d7b632018-10-30 10:49:50 -0400109 return newDeviceRules
110}
111
khenaidood20a5852018-10-22 22:09:55 -0400112//processControllerBoundFlow decomposes trap flows
khenaidoo820197c2020-02-13 16:35:33 -0500113func (fd *FlowDecomposer) processControllerBoundFlow(ctx context.Context, agent coreif.LogicalDeviceAgent, path []route.Hop,
khenaidood20a5852018-10-22 22:09:55 -0400114 inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats) *fu.DeviceRules {
115
khenaidoo89b0e942018-10-21 21:11:33 -0400116 log.Debugw("trap-flow", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo, "flow": flow})
khenaidood20a5852018-10-22 22:09:55 -0400117 deviceRules := fu.NewDeviceRules()
npujar1d86a522019-11-14 17:11:16 +0530118 meterID := fu.GetMeterIdFromFlow(flow)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400119 metadataFromwriteMetadata := fu.GetMetadataFromWriteMetadataAction(flow)
khenaidood20a5852018-10-22 22:09:55 -0400120
khenaidoo820197c2020-02-13 16:35:33 -0500121 ingressHop := path[0]
122 egressHop := path[1]
khenaidood20a5852018-10-22 22:09:55 -0400123
Humera Kouser4ff89012019-08-25 19:01:51 -0400124 //case of packet_in from NNI port rule
khenaidoo820197c2020-02-13 16:35:33 -0500125 if agent.GetDeviceRoutes().IsRootPort(inPortNo) {
Humera Kouser4ff89012019-08-25 19:01:51 -0400126 // Trap flow for NNI port
khenaidoo89b0e942018-10-21 21:11:33 -0400127 log.Debug("trap-nni")
Humera Kouser4ff89012019-08-25 19:01:51 -0400128
npujar1d86a522019-11-14 17:11:16 +0530129 fa := &fu.FlowArgs{
Humera Kouser4ff89012019-08-25 19:01:51 -0400130 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
131 MatchFields: []*ofp.OfpOxmOfbField{
132 fu.InPort(egressHop.Egress),
133 },
134 Actions: fu.GetActions(flow),
135 }
136 // Augment the matchfields with the ofpfields from the flow
Matt Jeanneretb423bad2019-10-10 20:42:19 -0400137 fg := fu.NewFlowsAndGroups()
Humera Kouser4ff89012019-08-25 19:01:51 -0400138 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
139 fg.AddFlow(fu.MkFlowStat(fa))
Matt Jeanneretb423bad2019-10-10 20:42:19 -0400140 deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -0400141 } else {
142 // Trap flow for UNI port
143 log.Debug("trap-uni")
144
145 //inPortNo is 0 for wildcard input case, do not include upstream port for 4000 flow in input
146 var inPorts []uint32
147 if inPortNo == 0 {
khenaidood20a5852018-10-22 22:09:55 -0400148 inPorts = agent.GetWildcardInputPorts(egressHop.Egress) // exclude egress_hop.egress_port.port_no
khenaidoo89b0e942018-10-21 21:11:33 -0400149 } else {
150 inPorts = []uint32{inPortNo}
151 }
152 for _, inputPort := range inPorts {
Matt Jeanneretb423bad2019-10-10 20:42:19 -0400153 // Upstream flow on parent (olt) device
npujar1d86a522019-11-14 17:11:16 +0530154 faParent := &fu.FlowArgs{
155 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie, "meter_id": uint64(meterID), "write_metadata": metadataFromwriteMetadata},
khenaidoo89b0e942018-10-21 21:11:33 -0400156 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -0400157 fu.InPort(egressHop.Ingress),
khenaidoo68c930b2019-05-13 11:46:51 -0400158 fu.TunnelId(uint64(inputPort)),
khenaidoo89b0e942018-10-21 21:11:33 -0400159 },
160 Actions: []*ofp.OfpAction{
khenaidoo68c930b2019-05-13 11:46:51 -0400161 fu.PushVlan(0x8100),
162 fu.SetField(fu.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 4000)),
163 fu.Output(egressHop.Egress),
khenaidoo89b0e942018-10-21 21:11:33 -0400164 },
165 }
166 // Augment the matchfields with the ofpfields from the flow
Matt Jeanneretb423bad2019-10-10 20:42:19 -0400167 faParent.MatchFields = append(faParent.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
168 fgParent := fu.NewFlowsAndGroups()
169 fgParent.AddFlow(fu.MkFlowStat(faParent))
170 deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fgParent)
171 log.Debugw("parent-trap-flow-set", log.Fields{"flow": faParent})
172
173 // Upstream flow on child (onu) device
174 var actions []*ofp.OfpAction
175 setvid := fu.GetVlanVid(flow)
176 if setvid != nil {
177 // have this child push the vlan the parent is matching/trapping on above
178 actions = []*ofp.OfpAction{
179 fu.PushVlan(0x8100),
180 fu.SetField(fu.VlanVid(*setvid)),
181 fu.Output(ingressHop.Egress),
182 }
183 } else {
184 // otherwise just set the egress port
185 actions = []*ofp.OfpAction{
186 fu.Output(ingressHop.Egress),
187 }
188 }
npujar1d86a522019-11-14 17:11:16 +0530189 faChild := &fu.FlowArgs{
190 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie, "meter_id": uint64(meterID), "write_metadata": metadataFromwriteMetadata},
Matt Jeanneretb423bad2019-10-10 20:42:19 -0400191 MatchFields: []*ofp.OfpOxmOfbField{
192 fu.InPort(ingressHop.Ingress),
193 fu.TunnelId(uint64(inputPort)),
194 },
195 Actions: actions,
196 }
197 // Augment the matchfields with the ofpfields from the flow.
198 // If the parent has a match vid and the child is setting that match vid exclude the the match vlan
199 // for the child given it will be setting that vlan and the parent will be matching on it
200 if setvid != nil {
201 faChild.MatchFields = append(faChild.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT, fu.VLAN_VID)...)
202 } else {
203 faChild.MatchFields = append(faChild.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
204 }
205 fgChild := fu.NewFlowsAndGroups()
206 fgChild.AddFlow(fu.MkFlowStat(faChild))
207 deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fgChild)
208 log.Debugw("child-trap-flow-set", log.Fields{"flow": faChild})
khenaidoo89b0e942018-10-21 21:11:33 -0400209 }
210 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400211
khenaidoo89b0e942018-10-21 21:11:33 -0400212 return deviceRules
213}
214
215// processUpstreamNonControllerBoundFlow processes non-controller bound flow. We assume that anything that is
216// upstream needs to get Q-in-Q treatment and that this is expressed via two flow rules, the first using the
217// goto-statement. We also assume that the inner tag is applied at the ONU, while the outer tag is
218// applied at the OLT
khenaidoo820197c2020-02-13 16:35:33 -0500219func (fd *FlowDecomposer) processUpstreamNonControllerBoundFlow(ctx context.Context,
220 path []route.Hop, inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats) *fu.DeviceRules {
khenaidood20a5852018-10-22 22:09:55 -0400221
khenaidoo89b0e942018-10-21 21:11:33 -0400222 log.Debugw("upstream-non-controller-bound-flow", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo})
khenaidood20a5852018-10-22 22:09:55 -0400223 deviceRules := fu.NewDeviceRules()
224
npujar1d86a522019-11-14 17:11:16 +0530225 meterID := fu.GetMeterIdFromFlow(flow)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400226 metadataFromwriteMetadata := fu.GetMetadataFromWriteMetadataAction(flow)
227
khenaidoo820197c2020-02-13 16:35:33 -0500228 ingressHop := path[0]
229 egressHop := path[1]
khenaidood20a5852018-10-22 22:09:55 -0400230
Manikkaraj kb1a10922019-07-29 12:10:34 -0400231 if flow.TableId == 0 && fu.HasNextTable(flow) {
232 log.Debugw("decomposing-onu-flow-in-upstream-has-next-table", log.Fields{"table_id": flow.TableId})
khenaidoo89b0e942018-10-21 21:11:33 -0400233 if outPortNo != 0 {
234 log.Warnw("outPort-should-not-be-specified", log.Fields{"outPortNo": outPortNo})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400235 return deviceRules
khenaidoo89b0e942018-10-21 21:11:33 -0400236 }
npujar1d86a522019-11-14 17:11:16 +0530237 fa := &fu.FlowArgs{
238 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie, "meter_id": uint64(meterID), "write_metadata": metadataFromwriteMetadata},
khenaidoo89b0e942018-10-21 21:11:33 -0400239 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -0400240 fu.InPort(ingressHop.Ingress),
241 fu.TunnelId(uint64(inPortNo)),
khenaidoo89b0e942018-10-21 21:11:33 -0400242 },
khenaidoo68c930b2019-05-13 11:46:51 -0400243 Actions: fu.GetActions(flow),
khenaidoo89b0e942018-10-21 21:11:33 -0400244 }
245 // Augment the matchfields with the ofpfields from the flow
khenaidoo68c930b2019-05-13 11:46:51 -0400246 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
khenaidood20a5852018-10-22 22:09:55 -0400247
248 // Augment the Actions
khenaidoo68c930b2019-05-13 11:46:51 -0400249 fa.Actions = append(fa.Actions, fu.Output(ingressHop.Egress))
khenaidood20a5852018-10-22 22:09:55 -0400250
khenaidoo89b0e942018-10-21 21:11:33 -0400251 fg := fu.NewFlowsAndGroups()
khenaidoo68c930b2019-05-13 11:46:51 -0400252 fg.AddFlow(fu.MkFlowStat(fa))
khenaidood20a5852018-10-22 22:09:55 -0400253 deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fg)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400254 } else if flow.TableId == 1 && outPortNo != 0 {
255 log.Debugw("decomposing-olt-flow-in-upstream-has-next-table", log.Fields{"table_id": flow.TableId})
npujar1d86a522019-11-14 17:11:16 +0530256 fa := &fu.FlowArgs{
257 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie, "meter_id": uint64(meterID), "write_metadata": metadataFromwriteMetadata},
Manikkaraj kb1a10922019-07-29 12:10:34 -0400258 MatchFields: []*ofp.OfpOxmOfbField{
259 fu.InPort(egressHop.Ingress),
260 fu.TunnelId(uint64(inPortNo)),
261 },
khenaidoo89b0e942018-10-21 21:11:33 -0400262 }
Manikkaraj kb1a10922019-07-29 12:10:34 -0400263 // Augment the matchfields with the ofpfields from the flow
264 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
khenaidoo89b0e942018-10-21 21:11:33 -0400265
Manikkaraj kb1a10922019-07-29 12:10:34 -0400266 //Augment the actions
267 filteredAction := fu.GetActions(flow, fu.OUTPUT)
268 filteredAction = append(filteredAction, fu.Output(egressHop.Egress))
269 fa.Actions = filteredAction
khenaidood20a5852018-10-22 22:09:55 -0400270
Manikkaraj kb1a10922019-07-29 12:10:34 -0400271 fg := fu.NewFlowsAndGroups()
272 fg.AddFlow(fu.MkFlowStat(fa))
273 deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -0400274 }
275 return deviceRules
276}
277
khenaidood20a5852018-10-22 22:09:55 -0400278// processDownstreamFlowWithNextTable decomposes downstream flows containing next table ID instructions
khenaidoo820197c2020-02-13 16:35:33 -0500279func (fd *FlowDecomposer) processDownstreamFlowWithNextTable(ctx context.Context, agent coreif.LogicalDeviceAgent, path []route.Hop,
khenaidood20a5852018-10-22 22:09:55 -0400280 inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats) *fu.DeviceRules {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400281 log.Debugw("decomposing-olt-flow-in-downstream-flow-with-next-table", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo})
khenaidood20a5852018-10-22 22:09:55 -0400282 deviceRules := fu.NewDeviceRules()
npujar1d86a522019-11-14 17:11:16 +0530283 meterID := fu.GetMeterIdFromFlow(flow)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400284 metadataFromwriteMetadata := fu.GetMetadataFromWriteMetadataAction(flow)
khenaidood20a5852018-10-22 22:09:55 -0400285
khenaidoo89b0e942018-10-21 21:11:33 -0400286 if outPortNo != 0 {
287 log.Warnw("outPort-should-not-be-specified", log.Fields{"outPortNo": outPortNo})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400288 return deviceRules
khenaidoo89b0e942018-10-21 21:11:33 -0400289 }
Manikkaraj kb1a10922019-07-29 12:10:34 -0400290
291 if flow.TableId != 0 {
292 log.Warnw("This is not olt pipeline table, so skipping", log.Fields{"tableId": flow.TableId})
293 return deviceRules
294 }
295
khenaidoo820197c2020-02-13 16:35:33 -0500296 ingressHop := path[0]
297 egressHop := path[1]
Manikkaraj kb1a10922019-07-29 12:10:34 -0400298 if metadataFromwriteMetadata != 0 {
khenaidoo89b0e942018-10-21 21:11:33 -0400299 log.Debugw("creating-metadata-flow", log.Fields{"flow": flow})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400300 portNumber := fu.GetEgressPortNumberFromWriteMetadata(flow)
khenaidoo89b0e942018-10-21 21:11:33 -0400301 if portNumber != 0 {
khenaidoo820197c2020-02-13 16:35:33 -0500302 recalculatedRoute, err := agent.GetRoute(ctx, inPortNo, portNumber)
303 if err != nil {
304 log.Errorw("no-route-double-tag", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo, "metadata": metadataFromwriteMetadata, "error": err})
305 return deviceRules
306 }
khenaidoo89b0e942018-10-21 21:11:33 -0400307 switch len(recalculatedRoute) {
308 case 0:
Manikkaraj kb1a10922019-07-29 12:10:34 -0400309 log.Errorw("no-route-double-tag", log.Fields{"inPortNo": inPortNo, "outPortNo": portNumber, "comment": "deleting-flow", "metadata": metadataFromwriteMetadata})
310 //TODO: Delete flow
khenaidoo89b0e942018-10-21 21:11:33 -0400311 return deviceRules
312 case 2:
khenaidood20a5852018-10-22 22:09:55 -0400313 log.Debugw("route-found", log.Fields{"ingressHop": ingressHop, "egressHop": egressHop})
khenaidoo89b0e942018-10-21 21:11:33 -0400314 default:
khenaidoo820197c2020-02-13 16:35:33 -0500315 log.Errorw("invalid-route-length", log.Fields{"routeLen": len(path)})
khenaidoo89b0e942018-10-21 21:11:33 -0400316 return deviceRules
317 }
318 ingressHop = recalculatedRoute[0]
319 }
khenaidoo68c930b2019-05-13 11:46:51 -0400320 innerTag := fu.GetInnerTagFromMetaData(flow)
khenaidoo89b0e942018-10-21 21:11:33 -0400321 if innerTag == 0 {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400322 log.Errorw("no-inner-route-double-tag", log.Fields{"inPortNo": inPortNo, "outPortNo": portNumber, "comment": "deleting-flow", "metadata": metadataFromwriteMetadata})
323 //TODO: Delete flow
khenaidoo89b0e942018-10-21 21:11:33 -0400324 return deviceRules
325 }
npujar1d86a522019-11-14 17:11:16 +0530326 fa := &fu.FlowArgs{
327 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie, "meter_id": uint64(meterID), "write_metadata": metadataFromwriteMetadata},
khenaidoo89b0e942018-10-21 21:11:33 -0400328 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -0400329 fu.InPort(ingressHop.Ingress),
Manikkaraj kb1a10922019-07-29 12:10:34 -0400330 fu.Metadata_ofp(uint64(innerTag)),
khenaidoo68c930b2019-05-13 11:46:51 -0400331 fu.TunnelId(uint64(portNumber)),
khenaidoo89b0e942018-10-21 21:11:33 -0400332 },
khenaidoo68c930b2019-05-13 11:46:51 -0400333 Actions: fu.GetActions(flow),
khenaidoo89b0e942018-10-21 21:11:33 -0400334 }
335 // Augment the matchfields with the ofpfields from the flow
khenaidoo68c930b2019-05-13 11:46:51 -0400336 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT, fu.METADATA)...)
khenaidood20a5852018-10-22 22:09:55 -0400337
338 // Augment the Actions
khenaidoo68c930b2019-05-13 11:46:51 -0400339 fa.Actions = append(fa.Actions, fu.Output(ingressHop.Egress))
khenaidood20a5852018-10-22 22:09:55 -0400340
khenaidoo89b0e942018-10-21 21:11:33 -0400341 fg := fu.NewFlowsAndGroups()
khenaidoo68c930b2019-05-13 11:46:51 -0400342 fg.AddFlow(fu.MkFlowStat(fa))
khenaidoo89b0e942018-10-21 21:11:33 -0400343 deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fg)
344 } else { // Create standard flow
345 log.Debugw("creating-standard-flow", log.Fields{"flow": flow})
npujar1d86a522019-11-14 17:11:16 +0530346 fa := &fu.FlowArgs{
347 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie, "meter_id": uint64(meterID), "write_metadata": metadataFromwriteMetadata},
khenaidoo89b0e942018-10-21 21:11:33 -0400348 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -0400349 fu.InPort(ingressHop.Ingress),
350 fu.TunnelId(uint64(inPortNo)),
khenaidoo89b0e942018-10-21 21:11:33 -0400351 },
khenaidoo68c930b2019-05-13 11:46:51 -0400352 Actions: fu.GetActions(flow),
khenaidoo89b0e942018-10-21 21:11:33 -0400353 }
354 // Augment the matchfields with the ofpfields from the flow
khenaidoo68c930b2019-05-13 11:46:51 -0400355 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
khenaidood20a5852018-10-22 22:09:55 -0400356
357 // Augment the Actions
khenaidoo68c930b2019-05-13 11:46:51 -0400358 fa.Actions = append(fa.Actions, fu.Output(ingressHop.Egress))
khenaidood20a5852018-10-22 22:09:55 -0400359
khenaidoo89b0e942018-10-21 21:11:33 -0400360 fg := fu.NewFlowsAndGroups()
khenaidoo68c930b2019-05-13 11:46:51 -0400361 fg.AddFlow(fu.MkFlowStat(fa))
khenaidoo89b0e942018-10-21 21:11:33 -0400362 deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fg)
363 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400364
khenaidoo89b0e942018-10-21 21:11:33 -0400365 return deviceRules
366}
367
khenaidood20a5852018-10-22 22:09:55 -0400368// processUnicastFlow decomposes unicast flows
khenaidoo820197c2020-02-13 16:35:33 -0500369func (fd *FlowDecomposer) processUnicastFlow(ctx context.Context, path []route.Hop,
khenaidood20a5852018-10-22 22:09:55 -0400370 inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats) *fu.DeviceRules {
371
Manikkaraj kb1a10922019-07-29 12:10:34 -0400372 log.Debugw("decomposing-onu-flow-in-downstream-unicast-flow", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo})
khenaidood20a5852018-10-22 22:09:55 -0400373 deviceRules := fu.NewDeviceRules()
374
khenaidoo820197c2020-02-13 16:35:33 -0500375 egressHop := path[1]
khenaidood20a5852018-10-22 22:09:55 -0400376
npujar1d86a522019-11-14 17:11:16 +0530377 meterID := fu.GetMeterIdFromFlow(flow)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400378 metadataFromwriteMetadata := fu.GetMetadataFromWriteMetadataAction(flow)
npujar1d86a522019-11-14 17:11:16 +0530379 fa := &fu.FlowArgs{
380 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie, "meter_id": uint64(meterID), "write_metadata": metadataFromwriteMetadata},
Manikkaraj kb1a10922019-07-29 12:10:34 -0400381 MatchFields: []*ofp.OfpOxmOfbField{
382 fu.InPort(egressHop.Ingress),
383 },
khenaidoo89b0e942018-10-21 21:11:33 -0400384 }
Manikkaraj kb1a10922019-07-29 12:10:34 -0400385 // Augment the matchfields with the ofpfields from the flow
386 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
khenaidood20a5852018-10-22 22:09:55 -0400387
Manikkaraj kb1a10922019-07-29 12:10:34 -0400388 // Augment the Actions
389 filteredAction := fu.GetActions(flow, fu.OUTPUT)
390 filteredAction = append(filteredAction, fu.Output(egressHop.Egress))
391 fa.Actions = filteredAction
khenaidoo89b0e942018-10-21 21:11:33 -0400392
Manikkaraj kb1a10922019-07-29 12:10:34 -0400393 fg := fu.NewFlowsAndGroups()
394 fg.AddFlow(fu.MkFlowStat(fa))
395 deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -0400396 return deviceRules
397}
398
khenaidood20a5852018-10-22 22:09:55 -0400399// processMulticastFlow decompose multicast flows
khenaidoo820197c2020-02-13 16:35:33 -0500400func (fd *FlowDecomposer) processMulticastFlow(ctx context.Context, path []route.Hop,
npujar1d86a522019-11-14 17:11:16 +0530401 inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats, grpID uint32,
khenaidood20a5852018-10-22 22:09:55 -0400402 groupMap map[uint32]*ofp.OfpGroupEntry) *fu.DeviceRules {
403
khenaidoo89b0e942018-10-21 21:11:33 -0400404 log.Debugw("multicast-flow", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo})
khenaidood20a5852018-10-22 22:09:55 -0400405 deviceRules := fu.NewDeviceRules()
khenaidoo89b0e942018-10-21 21:11:33 -0400406
407 //having no Group yet is the same as having a Group with no buckets
408 var grp *ofp.OfpGroupEntry
409 var ok bool
npujar1d86a522019-11-14 17:11:16 +0530410 if grp, ok = groupMap[grpID]; !ok {
411 log.Warnw("Group-id-not-present-in-map", log.Fields{"grpId": grpID, "groupMap": groupMap})
khenaidoo89b0e942018-10-21 21:11:33 -0400412 return deviceRules
413 }
414 if grp == nil || grp.Desc == nil {
npujar1d86a522019-11-14 17:11:16 +0530415 log.Warnw("Group-or-desc-nil", log.Fields{"grpId": grpID, "grp": grp})
khenaidoo89b0e942018-10-21 21:11:33 -0400416 return deviceRules
417 }
khenaidoo89b0e942018-10-21 21:11:33 -0400418
khenaidoo820197c2020-02-13 16:35:33 -0500419 deviceRules.CreateEntryIfNotExist(path[0].DeviceID)
Esin Karaman09959ae2019-11-29 13:59:58 +0000420 fg := fu.NewFlowsAndGroups()
421 fg.AddFlow(flow)
422 //return the multicast flow without decomposing it
khenaidoo820197c2020-02-13 16:35:33 -0500423 deviceRules.AddFlowsAndGroup(path[0].DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -0400424 return deviceRules
425}
426
khenaidood20a5852018-10-22 22:09:55 -0400427// decomposeFlow decomposes a flow for a logical device into flows for each physical device
npujar467fe752020-01-16 20:17:45 +0530428func (fd *FlowDecomposer) decomposeFlow(ctx context.Context, agent coreif.LogicalDeviceAgent, flow *ofp.OfpFlowStats,
khenaidoo820197c2020-02-13 16:35:33 -0500429 groupMap map[uint32]*ofp.OfpGroupEntry) (*fu.DeviceRules, error) {
khenaidood20a5852018-10-22 22:09:55 -0400430
khenaidoo68c930b2019-05-13 11:46:51 -0400431 inPortNo := fu.GetInPort(flow)
Esin Karaman09959ae2019-11-29 13:59:58 +0000432 if fu.HasGroup(flow) && inPortNo == 0 {
433 //if no in-port specified for a multicast flow, put NNI port as in-port
khenaidoo820197c2020-02-13 16:35:33 -0500434 //so that a valid path can be found for the flow
Esin Karaman09959ae2019-11-29 13:59:58 +0000435 nniPorts := agent.GetNNIPorts()
436 if len(nniPorts) > 0 {
437 inPortNo = nniPorts[0]
khenaidoo820197c2020-02-13 16:35:33 -0500438 log.Debugw("assigning-nni-port-as-in-port-for-multicast-flow", log.Fields{"nni": nniPorts[0], "flow:": flow})
Esin Karaman09959ae2019-11-29 13:59:58 +0000439 }
440 }
khenaidoo68c930b2019-05-13 11:46:51 -0400441 outPortNo := fu.GetOutPort(flow)
khenaidoo89b0e942018-10-21 21:11:33 -0400442 deviceRules := fu.NewDeviceRules()
khenaidoo820197c2020-02-13 16:35:33 -0500443 path, err := agent.GetRoute(ctx, inPortNo, outPortNo)
444 if err != nil {
445 log.Errorw("no-route", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo, "error": err})
446 return deviceRules, err
447 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400448
khenaidoo820197c2020-02-13 16:35:33 -0500449 switch len(path) {
khenaidoo89b0e942018-10-21 21:11:33 -0400450 case 0:
khenaidoo820197c2020-02-13 16:35:33 -0500451 return deviceRules, status.Errorf(codes.FailedPrecondition, "no route from:%d to:%d", inPortNo, outPortNo)
khenaidoo89b0e942018-10-21 21:11:33 -0400452 case 2:
khenaidoo820197c2020-02-13 16:35:33 -0500453 log.Debugw("route-found", log.Fields{"ingressHop": path[0], "egressHop": path[1]})
khenaidoo89b0e942018-10-21 21:11:33 -0400454 default:
khenaidoo820197c2020-02-13 16:35:33 -0500455 return deviceRules, status.Errorf(codes.Aborted, "invalid route length %d", len(path))
khenaidoo89b0e942018-10-21 21:11:33 -0400456 }
457
khenaidoo89b0e942018-10-21 21:11:33 -0400458 // Process controller bound flow
459 if outPortNo != 0 && (outPortNo&0x7fffffff) == uint32(ofp.OfpPortNo_OFPP_CONTROLLER) {
khenaidoo820197c2020-02-13 16:35:33 -0500460 deviceRules = fd.processControllerBoundFlow(ctx, agent, path, inPortNo, outPortNo, flow)
khenaidoo89b0e942018-10-21 21:11:33 -0400461 } else {
khenaidoo297cd252019-02-07 22:10:23 -0500462 var ingressDevice *voltha.Device
463 var err error
khenaidoo820197c2020-02-13 16:35:33 -0500464 if ingressDevice, err = fd.deviceMgr.GetDevice(ctx, path[0].DeviceID); err != nil {
465 return deviceRules, err
khenaidoo297cd252019-02-07 22:10:23 -0500466 }
467 isUpstream := !ingressDevice.Root
Manikkaraj kb1a10922019-07-29 12:10:34 -0400468 if isUpstream { // Unicast OLT and ONU UL
khenaidoo820197c2020-02-13 16:35:33 -0500469 log.Debug("process-olt-nd-onu-upstream-noncontrollerbound-unicast-flows", log.Fields{"flows": flow})
470 deviceRules = fd.processUpstreamNonControllerBoundFlow(ctx, path, inPortNo, outPortNo, flow)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400471 } else if fu.HasNextTable(flow) && flow.TableId == 0 { // Unicast OLT flow DL
khenaidoo820197c2020-02-13 16:35:33 -0500472 log.Debugw("process-olt-downstream-noncontrollerbound-flow-with-nexttable", log.Fields{"flows": flow})
473 deviceRules = fd.processDownstreamFlowWithNextTable(ctx, agent, path, inPortNo, outPortNo, flow)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400474 } else if flow.TableId == 1 && outPortNo != 0 { // Unicast ONU flow DL
khenaidoo820197c2020-02-13 16:35:33 -0500475 log.Debugw("process-onu-downstream-unicast-flow", log.Fields{"flows": flow})
476 deviceRules = fd.processUnicastFlow(ctx, path, inPortNo, outPortNo, flow)
npujar1d86a522019-11-14 17:11:16 +0530477 } else if grpID := fu.GetGroup(flow); grpID != 0 && flow.TableId == 0 { //Multicast
khenaidoo820197c2020-02-13 16:35:33 -0500478 log.Debugw("process-multicast-flow", log.Fields{"flows": flow})
479 deviceRules = fd.processMulticastFlow(ctx, path, inPortNo, outPortNo, flow, grpID, groupMap)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400480 } else {
khenaidoo820197c2020-02-13 16:35:33 -0500481 return deviceRules, status.Errorf(codes.Aborted, "unknown downstream flow %v", *flow)
khenaidoo89b0e942018-10-21 21:11:33 -0400482 }
483 }
khenaidoo19d7b632018-10-30 10:49:50 -0400484 deviceRules = fd.updateOutputPortForControllerBoundFlowForParentDevide(flow, deviceRules)
khenaidoo820197c2020-02-13 16:35:33 -0500485 return deviceRules, nil
khenaidoo89b0e942018-10-21 21:11:33 -0400486}