blob: 94594b0f761cf47d22103ab3a17497f24ac25ac3 [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
npujar1d86a522019-11-14 17:11:16 +053032// FlowDecomposer represent flow decomposer attribute
khenaidoo89b0e942018-10-21 21:11:33 -040033type FlowDecomposer struct {
npujar1d86a522019-11-14 17:11:16 +053034 deviceMgr coreif.DeviceManager
khenaidoo89b0e942018-10-21 21:11:33 -040035}
36
npujar1d86a522019-11-14 17:11:16 +053037// NewFlowDecomposer creates flow decomposer instance
38func NewFlowDecomposer(deviceMgr coreif.DeviceManager) *FlowDecomposer {
khenaidoo89b0e942018-10-21 21:11:33 -040039 var decomposer FlowDecomposer
40 decomposer.deviceMgr = deviceMgr
41 return &decomposer
42}
43
44//DecomposeRules decomposes per-device flows and flow-groups from the flows and groups defined on a logical device
khenaidoo820197c2020-02-13 16:35:33 -050045func (fd *FlowDecomposer) DecomposeRules(ctx context.Context, agent coreif.LogicalDeviceAgent, flows ofp.Flows, groups ofp.FlowGroups) (*fu.DeviceRules, error) {
khenaidoo3306c992019-05-24 16:57:35 -040046 deviceRules := *fu.NewDeviceRules()
khenaidoo2c6a0992019-04-29 13:46:56 -040047 devicesToUpdate := make(map[string]string)
khenaidoo89b0e942018-10-21 21:11:33 -040048
49 groupMap := make(map[uint32]*ofp.OfpGroupEntry)
50 for _, groupEntry := range groups.Items {
51 groupMap[groupEntry.Desc.GroupId] = groupEntry
52 }
53
khenaidoo89b0e942018-10-21 21:11:33 -040054 for _, flow := range flows.Items {
khenaidoo820197c2020-02-13 16:35:33 -050055 decomposedRules, err := fd.decomposeFlow(ctx, agent, flow, groupMap)
56 if err != nil {
57 return nil, err
58 }
npujar1d86a522019-11-14 17:11:16 +053059 for deviceID, flowAndGroups := range decomposedRules.Rules {
60 deviceRules.CreateEntryIfNotExist(deviceID)
61 deviceRules.Rules[deviceID].AddFrom(flowAndGroups)
62 devicesToUpdate[deviceID] = deviceID
khenaidoo89b0e942018-10-21 21:11:33 -040063 }
64 }
khenaidoo820197c2020-02-13 16:35:33 -050065 return deviceRules.FilterRules(devicesToUpdate), nil
khenaidoo89b0e942018-10-21 21:11:33 -040066}
67
khenaidoo19d7b632018-10-30 10:49:50 -040068// Handles special case of any controller-bound flow for a parent device
69func (fd *FlowDecomposer) updateOutputPortForControllerBoundFlowForParentDevide(flow *ofp.OfpFlowStats,
Scott Bakerfdea1e32020-02-21 15:35:41 -080070 dr *fu.DeviceRules) (*fu.DeviceRules, error) {
khenaidoo68c930b2019-05-13 11:46:51 -040071 EAPOL := fu.EthType(0x888e)
72 IGMP := fu.IpProto(2)
73 UDP := fu.IpProto(17)
khenaidoo19d7b632018-10-30 10:49:50 -040074
75 newDeviceRules := dr.Copy()
76 // Check whether we are dealing with a parent device
npujar1d86a522019-11-14 17:11:16 +053077 for deviceID, fg := range dr.GetRules() {
78 if root, _ := fd.deviceMgr.IsRootDevice(deviceID); root {
79 newDeviceRules.ClearFlows(deviceID)
khenaidoo19d7b632018-10-30 10:49:50 -040080 for i := 0; i < fg.Flows.Len(); i++ {
81 f := fg.GetFlow(i)
82 UpdateOutPortNo := false
khenaidoo68c930b2019-05-13 11:46:51 -040083 for _, field := range fu.GetOfbFields(f) {
khenaidoo19d7b632018-10-30 10:49:50 -040084 UpdateOutPortNo = (field.String() == EAPOL.String())
85 UpdateOutPortNo = UpdateOutPortNo || (field.String() == IGMP.String())
86 UpdateOutPortNo = UpdateOutPortNo || (field.String() == UDP.String())
87 if UpdateOutPortNo {
88 break
89 }
90 }
91 if UpdateOutPortNo {
khenaidoo68c930b2019-05-13 11:46:51 -040092 f = fu.UpdateOutputPortByActionType(f, uint32(ofp.OfpInstructionType_OFPIT_APPLY_ACTIONS),
khenaidoo19d7b632018-10-30 10:49:50 -040093 uint32(ofp.OfpPortNo_OFPP_CONTROLLER))
94 }
95 // Update flow Id as a change in the instruction field will result in a new flow ID
Scott Bakerfdea1e32020-02-21 15:35:41 -080096 var err error
97 if f.Id, err = fu.HashFlowStats(f); err != nil {
98 return nil, err
99 }
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
Scott Bakerfdea1e32020-02-21 15:35:41 -0800105 return newDeviceRules, nil
khenaidoo19d7b632018-10-30 10:49:50 -0400106}
107
khenaidood20a5852018-10-22 22:09:55 -0400108//processControllerBoundFlow decomposes trap flows
khenaidoo820197c2020-02-13 16:35:33 -0500109func (fd *FlowDecomposer) processControllerBoundFlow(ctx context.Context, agent coreif.LogicalDeviceAgent, path []route.Hop,
Scott Bakerfdea1e32020-02-21 15:35:41 -0800110 inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats) (*fu.DeviceRules, error) {
khenaidood20a5852018-10-22 22:09:55 -0400111
Girish Kumarf56a4682020-03-20 20:07:46 +0000112 logger.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
khenaidoo820197c2020-02-13 16:35:33 -0500117 ingressHop := path[0]
118 egressHop := path[1]
khenaidood20a5852018-10-22 22:09:55 -0400119
Humera Kouser4ff89012019-08-25 19:01:51 -0400120 //case of packet_in from NNI port rule
khenaidoo820197c2020-02-13 16:35:33 -0500121 if agent.GetDeviceRoutes().IsRootPort(inPortNo) {
Humera Kouser4ff89012019-08-25 19:01:51 -0400122 // Trap flow for NNI port
Girish Kumarf56a4682020-03-20 20:07:46 +0000123 logger.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)...)
Scott Bakerfdea1e32020-02-21 15:35:41 -0800135 fs, err := fu.MkFlowStat(fa)
136 if err != nil {
137 return nil, err
138 }
139 fg.AddFlow(fs)
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
Girish Kumarf56a4682020-03-20 20:07:46 +0000143 logger.Debug("trap-uni")
khenaidoo89b0e942018-10-21 21:11:33 -0400144
Matt Jeannerete75f2842020-03-14 15:45:12 -0400145 //inPortNo is 0 for wildcard input case, do not include upstream port for controller bound flow in input
khenaidoo89b0e942018-10-21 21:11:33 -0400146 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.Output(egressHop.Egress),
khenaidoo89b0e942018-10-21 21:11:33 -0400162 },
163 }
164 // Augment the matchfields with the ofpfields from the flow
Matt Jeanneretb423bad2019-10-10 20:42:19 -0400165 faParent.MatchFields = append(faParent.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
166 fgParent := fu.NewFlowsAndGroups()
Scott Bakerfdea1e32020-02-21 15:35:41 -0800167 fs, err := fu.MkFlowStat(faParent)
168 if err != nil {
169 return nil, err
170 }
171 fgParent.AddFlow(fs)
Matt Jeanneretb423bad2019-10-10 20:42:19 -0400172 deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fgParent)
Girish Kumarf56a4682020-03-20 20:07:46 +0000173 logger.Debugw("parent-trap-flow-set", log.Fields{"flow": faParent})
Matt Jeanneretb423bad2019-10-10 20:42:19 -0400174
175 // Upstream flow on child (onu) device
176 var actions []*ofp.OfpAction
177 setvid := fu.GetVlanVid(flow)
178 if setvid != nil {
179 // have this child push the vlan the parent is matching/trapping on above
180 actions = []*ofp.OfpAction{
181 fu.PushVlan(0x8100),
182 fu.SetField(fu.VlanVid(*setvid)),
183 fu.Output(ingressHop.Egress),
184 }
185 } else {
186 // otherwise just set the egress port
187 actions = []*ofp.OfpAction{
188 fu.Output(ingressHop.Egress),
189 }
190 }
npujar1d86a522019-11-14 17:11:16 +0530191 faChild := &fu.FlowArgs{
192 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie, "meter_id": uint64(meterID), "write_metadata": metadataFromwriteMetadata},
Matt Jeanneretb423bad2019-10-10 20:42:19 -0400193 MatchFields: []*ofp.OfpOxmOfbField{
194 fu.InPort(ingressHop.Ingress),
195 fu.TunnelId(uint64(inputPort)),
196 },
197 Actions: actions,
198 }
199 // Augment the matchfields with the ofpfields from the flow.
200 // If the parent has a match vid and the child is setting that match vid exclude the the match vlan
201 // for the child given it will be setting that vlan and the parent will be matching on it
202 if setvid != nil {
203 faChild.MatchFields = append(faChild.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT, fu.VLAN_VID)...)
204 } else {
205 faChild.MatchFields = append(faChild.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
206 }
207 fgChild := fu.NewFlowsAndGroups()
Scott Bakerfdea1e32020-02-21 15:35:41 -0800208 fs, err = fu.MkFlowStat(faChild)
209 if err != nil {
210 return nil, err
211 }
212 fgChild.AddFlow(fs)
Matt Jeanneretb423bad2019-10-10 20:42:19 -0400213 deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fgChild)
Girish Kumarf56a4682020-03-20 20:07:46 +0000214 logger.Debugw("child-trap-flow-set", log.Fields{"flow": faChild})
khenaidoo89b0e942018-10-21 21:11:33 -0400215 }
216 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400217
Scott Bakerfdea1e32020-02-21 15:35:41 -0800218 return deviceRules, nil
khenaidoo89b0e942018-10-21 21:11:33 -0400219}
220
221// processUpstreamNonControllerBoundFlow processes non-controller bound flow. We assume that anything that is
222// upstream needs to get Q-in-Q treatment and that this is expressed via two flow rules, the first using the
223// goto-statement. We also assume that the inner tag is applied at the ONU, while the outer tag is
224// applied at the OLT
khenaidoo820197c2020-02-13 16:35:33 -0500225func (fd *FlowDecomposer) processUpstreamNonControllerBoundFlow(ctx context.Context,
Scott Bakerfdea1e32020-02-21 15:35:41 -0800226 path []route.Hop, inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats) (*fu.DeviceRules, error) {
khenaidood20a5852018-10-22 22:09:55 -0400227
Girish Kumarf56a4682020-03-20 20:07:46 +0000228 logger.Debugw("upstream-non-controller-bound-flow", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo})
khenaidood20a5852018-10-22 22:09:55 -0400229 deviceRules := fu.NewDeviceRules()
230
npujar1d86a522019-11-14 17:11:16 +0530231 meterID := fu.GetMeterIdFromFlow(flow)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400232 metadataFromwriteMetadata := fu.GetMetadataFromWriteMetadataAction(flow)
233
khenaidoo820197c2020-02-13 16:35:33 -0500234 ingressHop := path[0]
235 egressHop := path[1]
khenaidood20a5852018-10-22 22:09:55 -0400236
Manikkaraj kb1a10922019-07-29 12:10:34 -0400237 if flow.TableId == 0 && fu.HasNextTable(flow) {
Girish Kumarf56a4682020-03-20 20:07:46 +0000238 logger.Debugw("decomposing-onu-flow-in-upstream-has-next-table", log.Fields{"table_id": flow.TableId})
khenaidoo89b0e942018-10-21 21:11:33 -0400239 if outPortNo != 0 {
Girish Kumarf56a4682020-03-20 20:07:46 +0000240 logger.Warnw("outPort-should-not-be-specified", log.Fields{"outPortNo": outPortNo})
Scott Bakerfdea1e32020-02-21 15:35:41 -0800241 return deviceRules, nil
khenaidoo89b0e942018-10-21 21:11:33 -0400242 }
npujar1d86a522019-11-14 17:11:16 +0530243 fa := &fu.FlowArgs{
244 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie, "meter_id": uint64(meterID), "write_metadata": metadataFromwriteMetadata},
khenaidoo89b0e942018-10-21 21:11:33 -0400245 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -0400246 fu.InPort(ingressHop.Ingress),
247 fu.TunnelId(uint64(inPortNo)),
khenaidoo89b0e942018-10-21 21:11:33 -0400248 },
khenaidoo68c930b2019-05-13 11:46:51 -0400249 Actions: fu.GetActions(flow),
khenaidoo89b0e942018-10-21 21:11:33 -0400250 }
251 // Augment the matchfields with the ofpfields from the flow
khenaidoo68c930b2019-05-13 11:46:51 -0400252 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
khenaidood20a5852018-10-22 22:09:55 -0400253
254 // Augment the Actions
khenaidoo68c930b2019-05-13 11:46:51 -0400255 fa.Actions = append(fa.Actions, fu.Output(ingressHop.Egress))
khenaidood20a5852018-10-22 22:09:55 -0400256
khenaidoo89b0e942018-10-21 21:11:33 -0400257 fg := fu.NewFlowsAndGroups()
Scott Bakerfdea1e32020-02-21 15:35:41 -0800258 fs, err := fu.MkFlowStat(fa)
259 if err != nil {
260 return nil, err
261 }
262 fg.AddFlow(fs)
khenaidood20a5852018-10-22 22:09:55 -0400263 deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fg)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400264 } else if flow.TableId == 1 && outPortNo != 0 {
Girish Kumarf56a4682020-03-20 20:07:46 +0000265 logger.Debugw("decomposing-olt-flow-in-upstream-has-next-table", log.Fields{"table_id": flow.TableId})
npujar1d86a522019-11-14 17:11:16 +0530266 fa := &fu.FlowArgs{
267 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie, "meter_id": uint64(meterID), "write_metadata": metadataFromwriteMetadata},
Manikkaraj kb1a10922019-07-29 12:10:34 -0400268 MatchFields: []*ofp.OfpOxmOfbField{
269 fu.InPort(egressHop.Ingress),
270 fu.TunnelId(uint64(inPortNo)),
271 },
khenaidoo89b0e942018-10-21 21:11:33 -0400272 }
Manikkaraj kb1a10922019-07-29 12:10:34 -0400273 // Augment the matchfields with the ofpfields from the flow
274 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
khenaidoo89b0e942018-10-21 21:11:33 -0400275
Manikkaraj kb1a10922019-07-29 12:10:34 -0400276 //Augment the actions
277 filteredAction := fu.GetActions(flow, fu.OUTPUT)
278 filteredAction = append(filteredAction, fu.Output(egressHop.Egress))
279 fa.Actions = filteredAction
khenaidood20a5852018-10-22 22:09:55 -0400280
Manikkaraj kb1a10922019-07-29 12:10:34 -0400281 fg := fu.NewFlowsAndGroups()
Scott Bakerfdea1e32020-02-21 15:35:41 -0800282 fs, err := fu.MkFlowStat(fa)
283 if err != nil {
284 return nil, err
285 }
286 fg.AddFlow(fs)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400287 deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -0400288 }
Scott Bakerfdea1e32020-02-21 15:35:41 -0800289 return deviceRules, nil
khenaidoo89b0e942018-10-21 21:11:33 -0400290}
291
khenaidood20a5852018-10-22 22:09:55 -0400292// processDownstreamFlowWithNextTable decomposes downstream flows containing next table ID instructions
khenaidoo820197c2020-02-13 16:35:33 -0500293func (fd *FlowDecomposer) processDownstreamFlowWithNextTable(ctx context.Context, agent coreif.LogicalDeviceAgent, path []route.Hop,
Scott Bakerfdea1e32020-02-21 15:35:41 -0800294 inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats) (*fu.DeviceRules, error) {
Girish Kumarf56a4682020-03-20 20:07:46 +0000295 logger.Debugw("decomposing-olt-flow-in-downstream-flow-with-next-table", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo})
khenaidood20a5852018-10-22 22:09:55 -0400296 deviceRules := fu.NewDeviceRules()
npujar1d86a522019-11-14 17:11:16 +0530297 meterID := fu.GetMeterIdFromFlow(flow)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400298 metadataFromwriteMetadata := fu.GetMetadataFromWriteMetadataAction(flow)
khenaidood20a5852018-10-22 22:09:55 -0400299
khenaidoo89b0e942018-10-21 21:11:33 -0400300 if outPortNo != 0 {
Girish Kumarf56a4682020-03-20 20:07:46 +0000301 logger.Warnw("outPort-should-not-be-specified", log.Fields{"outPortNo": outPortNo})
Scott Bakerfdea1e32020-02-21 15:35:41 -0800302 return deviceRules, nil
khenaidoo89b0e942018-10-21 21:11:33 -0400303 }
Manikkaraj kb1a10922019-07-29 12:10:34 -0400304
305 if flow.TableId != 0 {
Girish Kumarf56a4682020-03-20 20:07:46 +0000306 logger.Warnw("This is not olt pipeline table, so skipping", log.Fields{"tableId": flow.TableId})
Scott Bakerfdea1e32020-02-21 15:35:41 -0800307 return deviceRules, nil
Manikkaraj kb1a10922019-07-29 12:10:34 -0400308 }
309
khenaidoo820197c2020-02-13 16:35:33 -0500310 ingressHop := path[0]
311 egressHop := path[1]
Manikkaraj kb1a10922019-07-29 12:10:34 -0400312 if metadataFromwriteMetadata != 0 {
Girish Kumarf56a4682020-03-20 20:07:46 +0000313 logger.Debugw("creating-metadata-flow", log.Fields{"flow": flow})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400314 portNumber := fu.GetEgressPortNumberFromWriteMetadata(flow)
khenaidoo89b0e942018-10-21 21:11:33 -0400315 if portNumber != 0 {
khenaidoo820197c2020-02-13 16:35:33 -0500316 recalculatedRoute, err := agent.GetRoute(ctx, inPortNo, portNumber)
317 if err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000318 logger.Errorw("no-route-double-tag", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo, "metadata": metadataFromwriteMetadata, "error": err})
Scott Bakerfdea1e32020-02-21 15:35:41 -0800319 return deviceRules, nil
khenaidoo820197c2020-02-13 16:35:33 -0500320 }
khenaidoo89b0e942018-10-21 21:11:33 -0400321 switch len(recalculatedRoute) {
322 case 0:
Girish Kumarf56a4682020-03-20 20:07:46 +0000323 logger.Errorw("no-route-double-tag", log.Fields{"inPortNo": inPortNo, "outPortNo": portNumber, "comment": "deleting-flow", "metadata": metadataFromwriteMetadata})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400324 //TODO: Delete flow
Scott Bakerfdea1e32020-02-21 15:35:41 -0800325 return deviceRules, nil
khenaidoo89b0e942018-10-21 21:11:33 -0400326 case 2:
Girish Kumarf56a4682020-03-20 20:07:46 +0000327 logger.Debugw("route-found", log.Fields{"ingressHop": ingressHop, "egressHop": egressHop})
khenaidoo89b0e942018-10-21 21:11:33 -0400328 default:
Girish Kumarf56a4682020-03-20 20:07:46 +0000329 logger.Errorw("invalid-route-length", log.Fields{"routeLen": len(path)})
Scott Bakerfdea1e32020-02-21 15:35:41 -0800330 return deviceRules, nil
khenaidoo89b0e942018-10-21 21:11:33 -0400331 }
332 ingressHop = recalculatedRoute[0]
333 }
khenaidoo68c930b2019-05-13 11:46:51 -0400334 innerTag := fu.GetInnerTagFromMetaData(flow)
khenaidoo89b0e942018-10-21 21:11:33 -0400335 if innerTag == 0 {
Girish Kumarf56a4682020-03-20 20:07:46 +0000336 logger.Errorw("no-inner-route-double-tag", log.Fields{"inPortNo": inPortNo, "outPortNo": portNumber, "comment": "deleting-flow", "metadata": metadataFromwriteMetadata})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400337 //TODO: Delete flow
Scott Bakerfdea1e32020-02-21 15:35:41 -0800338 return deviceRules, nil
khenaidoo89b0e942018-10-21 21:11:33 -0400339 }
npujar1d86a522019-11-14 17:11:16 +0530340 fa := &fu.FlowArgs{
341 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie, "meter_id": uint64(meterID), "write_metadata": metadataFromwriteMetadata},
khenaidoo89b0e942018-10-21 21:11:33 -0400342 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -0400343 fu.InPort(ingressHop.Ingress),
Manikkaraj kb1a10922019-07-29 12:10:34 -0400344 fu.Metadata_ofp(uint64(innerTag)),
khenaidoo68c930b2019-05-13 11:46:51 -0400345 fu.TunnelId(uint64(portNumber)),
khenaidoo89b0e942018-10-21 21:11:33 -0400346 },
khenaidoo68c930b2019-05-13 11:46:51 -0400347 Actions: fu.GetActions(flow),
khenaidoo89b0e942018-10-21 21:11:33 -0400348 }
349 // Augment the matchfields with the ofpfields from the flow
khenaidoo68c930b2019-05-13 11:46:51 -0400350 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT, fu.METADATA)...)
khenaidood20a5852018-10-22 22:09:55 -0400351
352 // Augment the Actions
khenaidoo68c930b2019-05-13 11:46:51 -0400353 fa.Actions = append(fa.Actions, fu.Output(ingressHop.Egress))
khenaidood20a5852018-10-22 22:09:55 -0400354
khenaidoo89b0e942018-10-21 21:11:33 -0400355 fg := fu.NewFlowsAndGroups()
Scott Bakerfdea1e32020-02-21 15:35:41 -0800356 fs, err := fu.MkFlowStat(fa)
357 if err != nil {
358 return nil, err
359 }
360 fg.AddFlow(fs)
khenaidoo89b0e942018-10-21 21:11:33 -0400361 deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fg)
362 } else { // Create standard flow
Girish Kumarf56a4682020-03-20 20:07:46 +0000363 logger.Debugw("creating-standard-flow", log.Fields{"flow": flow})
npujar1d86a522019-11-14 17:11:16 +0530364 fa := &fu.FlowArgs{
365 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie, "meter_id": uint64(meterID), "write_metadata": metadataFromwriteMetadata},
khenaidoo89b0e942018-10-21 21:11:33 -0400366 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -0400367 fu.InPort(ingressHop.Ingress),
368 fu.TunnelId(uint64(inPortNo)),
khenaidoo89b0e942018-10-21 21:11:33 -0400369 },
khenaidoo68c930b2019-05-13 11:46:51 -0400370 Actions: fu.GetActions(flow),
khenaidoo89b0e942018-10-21 21:11:33 -0400371 }
372 // Augment the matchfields with the ofpfields from the flow
khenaidoo68c930b2019-05-13 11:46:51 -0400373 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
khenaidood20a5852018-10-22 22:09:55 -0400374
375 // Augment the Actions
khenaidoo68c930b2019-05-13 11:46:51 -0400376 fa.Actions = append(fa.Actions, fu.Output(ingressHop.Egress))
khenaidood20a5852018-10-22 22:09:55 -0400377
khenaidoo89b0e942018-10-21 21:11:33 -0400378 fg := fu.NewFlowsAndGroups()
Scott Bakerfdea1e32020-02-21 15:35:41 -0800379 fs, err := fu.MkFlowStat(fa)
380 if err != nil {
381 return nil, err
382 }
383 fg.AddFlow(fs)
khenaidoo89b0e942018-10-21 21:11:33 -0400384 deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fg)
385 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400386
Scott Bakerfdea1e32020-02-21 15:35:41 -0800387 return deviceRules, nil
khenaidoo89b0e942018-10-21 21:11:33 -0400388}
389
khenaidood20a5852018-10-22 22:09:55 -0400390// processUnicastFlow decomposes unicast flows
khenaidoo820197c2020-02-13 16:35:33 -0500391func (fd *FlowDecomposer) processUnicastFlow(ctx context.Context, path []route.Hop,
Scott Bakerfdea1e32020-02-21 15:35:41 -0800392 inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats) (*fu.DeviceRules, error) {
khenaidood20a5852018-10-22 22:09:55 -0400393
Girish Kumarf56a4682020-03-20 20:07:46 +0000394 logger.Debugw("decomposing-onu-flow-in-downstream-unicast-flow", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo})
khenaidood20a5852018-10-22 22:09:55 -0400395 deviceRules := fu.NewDeviceRules()
396
khenaidoo820197c2020-02-13 16:35:33 -0500397 egressHop := path[1]
khenaidood20a5852018-10-22 22:09:55 -0400398
npujar1d86a522019-11-14 17:11:16 +0530399 meterID := fu.GetMeterIdFromFlow(flow)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400400 metadataFromwriteMetadata := fu.GetMetadataFromWriteMetadataAction(flow)
npujar1d86a522019-11-14 17:11:16 +0530401 fa := &fu.FlowArgs{
402 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie, "meter_id": uint64(meterID), "write_metadata": metadataFromwriteMetadata},
Manikkaraj kb1a10922019-07-29 12:10:34 -0400403 MatchFields: []*ofp.OfpOxmOfbField{
404 fu.InPort(egressHop.Ingress),
405 },
khenaidoo89b0e942018-10-21 21:11:33 -0400406 }
Manikkaraj kb1a10922019-07-29 12:10:34 -0400407 // Augment the matchfields with the ofpfields from the flow
408 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
khenaidood20a5852018-10-22 22:09:55 -0400409
Manikkaraj kb1a10922019-07-29 12:10:34 -0400410 // Augment the Actions
411 filteredAction := fu.GetActions(flow, fu.OUTPUT)
412 filteredAction = append(filteredAction, fu.Output(egressHop.Egress))
413 fa.Actions = filteredAction
khenaidoo89b0e942018-10-21 21:11:33 -0400414
Manikkaraj kb1a10922019-07-29 12:10:34 -0400415 fg := fu.NewFlowsAndGroups()
Scott Bakerfdea1e32020-02-21 15:35:41 -0800416 fs, err := fu.MkFlowStat(fa)
417 if err != nil {
418 return nil, err
419 }
420 fg.AddFlow(fs)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400421 deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fg)
Scott Bakerfdea1e32020-02-21 15:35:41 -0800422 return deviceRules, nil
khenaidoo89b0e942018-10-21 21:11:33 -0400423}
424
khenaidood20a5852018-10-22 22:09:55 -0400425// processMulticastFlow decompose multicast flows
khenaidoo820197c2020-02-13 16:35:33 -0500426func (fd *FlowDecomposer) processMulticastFlow(ctx context.Context, path []route.Hop,
npujar1d86a522019-11-14 17:11:16 +0530427 inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats, grpID uint32,
khenaidood20a5852018-10-22 22:09:55 -0400428 groupMap map[uint32]*ofp.OfpGroupEntry) *fu.DeviceRules {
429
Girish Kumarf56a4682020-03-20 20:07:46 +0000430 logger.Debugw("multicast-flow", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo})
khenaidood20a5852018-10-22 22:09:55 -0400431 deviceRules := fu.NewDeviceRules()
khenaidoo89b0e942018-10-21 21:11:33 -0400432
433 //having no Group yet is the same as having a Group with no buckets
434 var grp *ofp.OfpGroupEntry
435 var ok bool
npujar1d86a522019-11-14 17:11:16 +0530436 if grp, ok = groupMap[grpID]; !ok {
Girish Kumarf56a4682020-03-20 20:07:46 +0000437 logger.Warnw("Group-id-not-present-in-map", log.Fields{"grpId": grpID, "groupMap": groupMap})
khenaidoo89b0e942018-10-21 21:11:33 -0400438 return deviceRules
439 }
440 if grp == nil || grp.Desc == nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000441 logger.Warnw("Group-or-desc-nil", log.Fields{"grpId": grpID, "grp": grp})
khenaidoo89b0e942018-10-21 21:11:33 -0400442 return deviceRules
443 }
khenaidoo89b0e942018-10-21 21:11:33 -0400444
khenaidoo820197c2020-02-13 16:35:33 -0500445 deviceRules.CreateEntryIfNotExist(path[0].DeviceID)
Esin Karaman09959ae2019-11-29 13:59:58 +0000446 fg := fu.NewFlowsAndGroups()
447 fg.AddFlow(flow)
448 //return the multicast flow without decomposing it
khenaidoo820197c2020-02-13 16:35:33 -0500449 deviceRules.AddFlowsAndGroup(path[0].DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -0400450 return deviceRules
451}
452
khenaidood20a5852018-10-22 22:09:55 -0400453// decomposeFlow decomposes a flow for a logical device into flows for each physical device
npujar467fe752020-01-16 20:17:45 +0530454func (fd *FlowDecomposer) decomposeFlow(ctx context.Context, agent coreif.LogicalDeviceAgent, flow *ofp.OfpFlowStats,
khenaidoo820197c2020-02-13 16:35:33 -0500455 groupMap map[uint32]*ofp.OfpGroupEntry) (*fu.DeviceRules, error) {
khenaidood20a5852018-10-22 22:09:55 -0400456
khenaidoo68c930b2019-05-13 11:46:51 -0400457 inPortNo := fu.GetInPort(flow)
Esin Karaman09959ae2019-11-29 13:59:58 +0000458 if fu.HasGroup(flow) && inPortNo == 0 {
459 //if no in-port specified for a multicast flow, put NNI port as in-port
khenaidoo820197c2020-02-13 16:35:33 -0500460 //so that a valid path can be found for the flow
Esin Karaman09959ae2019-11-29 13:59:58 +0000461 nniPorts := agent.GetNNIPorts()
462 if len(nniPorts) > 0 {
463 inPortNo = nniPorts[0]
Girish Kumarf56a4682020-03-20 20:07:46 +0000464 logger.Debugw("assigning-nni-port-as-in-port-for-multicast-flow", log.Fields{"nni": nniPorts[0], "flow:": flow})
Esin Karaman09959ae2019-11-29 13:59:58 +0000465 }
466 }
khenaidoo68c930b2019-05-13 11:46:51 -0400467 outPortNo := fu.GetOutPort(flow)
khenaidoo89b0e942018-10-21 21:11:33 -0400468 deviceRules := fu.NewDeviceRules()
khenaidoo820197c2020-02-13 16:35:33 -0500469 path, err := agent.GetRoute(ctx, inPortNo, outPortNo)
470 if err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000471 logger.Errorw("no-route", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo, "error": err})
khenaidoo820197c2020-02-13 16:35:33 -0500472 return deviceRules, err
473 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400474
khenaidoo820197c2020-02-13 16:35:33 -0500475 switch len(path) {
khenaidoo89b0e942018-10-21 21:11:33 -0400476 case 0:
khenaidoo820197c2020-02-13 16:35:33 -0500477 return deviceRules, status.Errorf(codes.FailedPrecondition, "no route from:%d to:%d", inPortNo, outPortNo)
khenaidoo89b0e942018-10-21 21:11:33 -0400478 case 2:
Girish Kumarf56a4682020-03-20 20:07:46 +0000479 logger.Debugw("route-found", log.Fields{"ingressHop": path[0], "egressHop": path[1]})
khenaidoo89b0e942018-10-21 21:11:33 -0400480 default:
khenaidoo820197c2020-02-13 16:35:33 -0500481 return deviceRules, status.Errorf(codes.Aborted, "invalid route length %d", len(path))
khenaidoo89b0e942018-10-21 21:11:33 -0400482 }
483
khenaidoo89b0e942018-10-21 21:11:33 -0400484 // Process controller bound flow
485 if outPortNo != 0 && (outPortNo&0x7fffffff) == uint32(ofp.OfpPortNo_OFPP_CONTROLLER) {
Scott Bakerfdea1e32020-02-21 15:35:41 -0800486 deviceRules, err = fd.processControllerBoundFlow(ctx, agent, path, inPortNo, outPortNo, flow)
487 if err != nil {
488 return nil, err
489 }
khenaidoo89b0e942018-10-21 21:11:33 -0400490 } else {
khenaidoo297cd252019-02-07 22:10:23 -0500491 var ingressDevice *voltha.Device
492 var err error
khenaidoo820197c2020-02-13 16:35:33 -0500493 if ingressDevice, err = fd.deviceMgr.GetDevice(ctx, path[0].DeviceID); err != nil {
494 return deviceRules, err
khenaidoo297cd252019-02-07 22:10:23 -0500495 }
496 isUpstream := !ingressDevice.Root
Manikkaraj kb1a10922019-07-29 12:10:34 -0400497 if isUpstream { // Unicast OLT and ONU UL
Girish Kumarf56a4682020-03-20 20:07:46 +0000498 logger.Debug("process-olt-nd-onu-upstream-noncontrollerbound-unicast-flows", log.Fields{"flows": flow})
Scott Bakerfdea1e32020-02-21 15:35:41 -0800499 deviceRules, err = fd.processUpstreamNonControllerBoundFlow(ctx, path, inPortNo, outPortNo, flow)
500 if err != nil {
501 return nil, err
502 }
Manikkaraj kb1a10922019-07-29 12:10:34 -0400503 } else if fu.HasNextTable(flow) && flow.TableId == 0 { // Unicast OLT flow DL
Girish Kumarf56a4682020-03-20 20:07:46 +0000504 logger.Debugw("process-olt-downstream-noncontrollerbound-flow-with-nexttable", log.Fields{"flows": flow})
Scott Bakerfdea1e32020-02-21 15:35:41 -0800505 deviceRules, err = fd.processDownstreamFlowWithNextTable(ctx, agent, path, inPortNo, outPortNo, flow)
506 if err != nil {
507 return nil, err
508 }
Manikkaraj kb1a10922019-07-29 12:10:34 -0400509 } else if flow.TableId == 1 && outPortNo != 0 { // Unicast ONU flow DL
Girish Kumarf56a4682020-03-20 20:07:46 +0000510 logger.Debugw("process-onu-downstream-unicast-flow", log.Fields{"flows": flow})
Scott Bakerfdea1e32020-02-21 15:35:41 -0800511 deviceRules, err = fd.processUnicastFlow(ctx, path, inPortNo, outPortNo, flow)
512 if err != nil {
513 return nil, err
514 }
npujar1d86a522019-11-14 17:11:16 +0530515 } else if grpID := fu.GetGroup(flow); grpID != 0 && flow.TableId == 0 { //Multicast
Girish Kumarf56a4682020-03-20 20:07:46 +0000516 logger.Debugw("process-multicast-flow", log.Fields{"flows": flow})
khenaidoo820197c2020-02-13 16:35:33 -0500517 deviceRules = fd.processMulticastFlow(ctx, path, inPortNo, outPortNo, flow, grpID, groupMap)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400518 } else {
khenaidoo820197c2020-02-13 16:35:33 -0500519 return deviceRules, status.Errorf(codes.Aborted, "unknown downstream flow %v", *flow)
khenaidoo89b0e942018-10-21 21:11:33 -0400520 }
521 }
Scott Bakerfdea1e32020-02-21 15:35:41 -0800522 deviceRules, err = fd.updateOutputPortForControllerBoundFlowForParentDevide(flow, deviceRules)
523 return deviceRules, err
khenaidoo89b0e942018-10-21 21:11:33 -0400524}