blob: 3679201c348b4e38f176d2c83da52c8de19eeb1a [file] [log] [blame]
Kent Hagerman3136fbd2020-05-14 10:30:45 -04001/*
2 * Copyright 2018-present Open Networking Foundation
3
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7
8 * http://www.apache.org/licenses/LICENSE-2.0
9
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package device
18
19import (
20 "context"
21 "errors"
22 "fmt"
Kent Hagerman3136fbd2020-05-14 10:30:45 -040023 "github.com/gogo/protobuf/proto"
24 "github.com/opencord/voltha-go/rw_core/route"
25 coreutils "github.com/opencord/voltha-go/rw_core/utils"
26 fu "github.com/opencord/voltha-lib-go/v3/pkg/flows"
27 "github.com/opencord/voltha-lib-go/v3/pkg/log"
28 ofp "github.com/opencord/voltha-protos/v3/go/openflow_13"
29 "github.com/opencord/voltha-protos/v3/go/voltha"
30 "google.golang.org/grpc/codes"
31 "google.golang.org/grpc/status"
khenaidoo0db4c812020-05-27 15:27:30 -040032 "strconv"
Kent Hagerman3136fbd2020-05-14 10:30:45 -040033)
34
Kent Hagerman433a31a2020-05-20 19:04:48 -040035// listLogicalDeviceFlows returns logical device flows
36func (agent *LogicalAgent) listLogicalDeviceFlows() map[uint64]*ofp.OfpFlowStats {
Kent Hagermanfa9d6d42020-05-25 11:49:40 -040037 flowIDs := agent.flowLoader.ListIDs()
Kent Hagerman433a31a2020-05-20 19:04:48 -040038 flows := make(map[uint64]*ofp.OfpFlowStats, len(flowIDs))
39 for flowID := range flowIDs {
40 if flowHandle, have := agent.flowLoader.Lock(flowID); have {
41 flows[flowID] = flowHandle.GetReadOnly()
42 flowHandle.Unlock()
43 }
44 }
45 return flows
46}
47
Kent Hagerman3136fbd2020-05-14 10:30:45 -040048//updateFlowTable updates the flow table of that logical device
49func (agent *LogicalAgent) updateFlowTable(ctx context.Context, flow *ofp.OfpFlowMod) error {
50 logger.Debug("UpdateFlowTable")
51 if flow == nil {
52 return nil
53 }
54
Kent Hagerman3136fbd2020-05-14 10:30:45 -040055 switch flow.GetCommand() {
56 case ofp.OfpFlowModCommand_OFPFC_ADD:
57 return agent.flowAdd(ctx, flow)
58 case ofp.OfpFlowModCommand_OFPFC_DELETE:
59 return agent.flowDelete(ctx, flow)
60 case ofp.OfpFlowModCommand_OFPFC_DELETE_STRICT:
61 return agent.flowDeleteStrict(ctx, flow)
62 case ofp.OfpFlowModCommand_OFPFC_MODIFY:
63 return agent.flowModify(flow)
64 case ofp.OfpFlowModCommand_OFPFC_MODIFY_STRICT:
65 return agent.flowModifyStrict(flow)
66 }
67 return status.Errorf(codes.Internal,
68 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceID, flow.GetCommand())
69}
70
71//flowAdd adds a flow to the flow table of that logical device
72func (agent *LogicalAgent) flowAdd(ctx context.Context, mod *ofp.OfpFlowMod) error {
73 logger.Debugw("flowAdd", log.Fields{"flow": mod})
74 if mod == nil {
75 return nil
76 }
77 flow, err := fu.FlowStatsEntryFromFlowModMessage(mod)
78 if err != nil {
79 logger.Errorw("flowAdd-failed", log.Fields{"flowMod": mod, "err": err})
80 return err
81 }
82 var updated bool
83 var changed bool
84 if changed, updated, err = agent.decomposeAndAdd(ctx, flow, mod); err != nil {
85 logger.Errorw("flow-decompose-and-add-failed ", log.Fields{"flowMod": mod, "err": err})
86 return err
87 }
88 if changed && !updated {
89 if dbupdated := agent.updateFlowCountOfMeterStats(ctx, mod, flow, false); !dbupdated {
90 return fmt.Errorf("couldnt-updated-flow-stats-%s", strconv.FormatUint(flow.Id, 10))
91 }
92 }
93 return nil
94
95}
96
97func (agent *LogicalAgent) decomposeAndAdd(ctx context.Context, flow *ofp.OfpFlowStats, mod *ofp.OfpFlowMod) (bool, bool, error) {
98 changed := false
99 updated := false
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400100 var flowToReplace *ofp.OfpFlowStats
101
102 //if flow is not found in the map, create a new entry, otherwise get the existing one.
Kent Hagerman433a31a2020-05-20 19:04:48 -0400103 flowHandle, created, err := agent.flowLoader.LockOrCreate(ctx, flow)
104 if err != nil {
105 return changed, updated, err
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400106 }
Kent Hagerman433a31a2020-05-20 19:04:48 -0400107 defer flowHandle.Unlock()
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400108
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400109 flows := make([]*ofp.OfpFlowStats, 0)
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400110 checkOverlap := (mod.Flags & uint32(ofp.OfpFlowModFlags_OFPFF_CHECK_OVERLAP)) != 0
111 if checkOverlap {
Kent Hagerman433a31a2020-05-20 19:04:48 -0400112 // TODO: this currently does nothing
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400113 if overlapped := fu.FindOverlappingFlows(flows, mod); len(overlapped) != 0 {
Kent Hagerman433a31a2020-05-20 19:04:48 -0400114 // TODO: should this error be notified other than being logged?
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400115 logger.Warnw("overlapped-flows", log.Fields{"logicaldeviceId": agent.logicalDeviceID})
116 } else {
117 // Add flow
118 changed = true
119 }
120 } else {
Kent Hagerman433a31a2020-05-20 19:04:48 -0400121 if !created {
122 flowToReplace = flowHandle.GetReadOnly()
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400123 if (mod.Flags & uint32(ofp.OfpFlowModFlags_OFPFF_RESET_COUNTS)) != 0 {
124 flow.ByteCount = flowToReplace.ByteCount
125 flow.PacketCount = flowToReplace.PacketCount
126 }
127 if !proto.Equal(flowToReplace, flow) {
128 changed = true
129 updated = true
130 }
131 } else {
132 changed = true
133 }
134 }
135 logger.Debugw("flowAdd-changed", log.Fields{"changed": changed, "updated": updated})
136 if changed {
Kent Hagerman433a31a2020-05-20 19:04:48 -0400137 updatedFlows := map[uint64]*ofp.OfpFlowStats{flow.Id: flow}
138
139 flowMeterConfig, err := agent.GetMeterConfig(updatedFlows)
140 if err != nil {
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400141 logger.Error("Meter-referred-in-flow-not-present")
142 return changed, updated, err
143 }
Kent Hagerman433a31a2020-05-20 19:04:48 -0400144
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400145 groupIDs := agent.groupLoader.ListIDs()
Kent Hagerman433a31a2020-05-20 19:04:48 -0400146 groups := make(map[uint32]*ofp.OfpGroupEntry, len(groupIDs))
147 for groupID := range groupIDs {
148 if groupHandle, have := agent.groupLoader.Lock(groupID); have {
149 groups[groupID] = groupHandle.GetReadOnly()
150 groupHandle.Unlock()
151 }
152 }
153
154 deviceRules, err := agent.flowDecomposer.DecomposeRules(ctx, agent, updatedFlows, groups)
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400155 if err != nil {
156 return changed, updated, err
157 }
158
159 logger.Debugw("rules", log.Fields{"rules": deviceRules.String()})
160 // Update store and cache
161 if updated {
Kent Hagerman433a31a2020-05-20 19:04:48 -0400162 if err := flowHandle.Update(ctx, flow); err != nil {
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400163 return changed, updated, err
164 }
165 }
Kent Hagerman433a31a2020-05-20 19:04:48 -0400166 respChannels := agent.addFlowsAndGroupsToDevices(deviceRules, toMetadata(flowMeterConfig))
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400167 // Create the go routines to wait
168 go func() {
169 // Wait for completion
170 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChannels...); res != nil {
Matteo Scandolo5bd2f6f2020-08-05 15:27:10 -0700171 logger.Infow("failed-to-add-flows-will-attempt-deletion", log.Fields{
172 "errors": res,
173 "logical-device-id": agent.logicalDeviceID,
174 "flows": flows,
175 "groups": groups,
176 })
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400177 // Revert added flows
Kent Hagerman433a31a2020-05-20 19:04:48 -0400178 if err := agent.revertAddedFlows(context.Background(), mod, flow, flowToReplace, deviceRules, toMetadata(flowMeterConfig)); err != nil {
Matteo Scandolo5bd2f6f2020-08-05 15:27:10 -0700179 logger.Errorw("failure-to-delete-flows-after-failed-addition", log.Fields{
180 "error": err,
181 "logical-device-id": agent.logicalDeviceID,
182 "flows": flows,
183 "groups": groups,
184 })
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400185 }
186 }
187 }()
188 }
189 return changed, updated, nil
190}
191
192// revertAddedFlows reverts flows after the flowAdd request has failed. All flows corresponding to that flowAdd request
193// will be reverted, both from the logical devices and the devices.
194func (agent *LogicalAgent) revertAddedFlows(ctx context.Context, mod *ofp.OfpFlowMod, addedFlow *ofp.OfpFlowStats, replacedFlow *ofp.OfpFlowStats, deviceRules *fu.DeviceRules, metadata *voltha.FlowMetadata) error {
195 logger.Debugw("revertFlowAdd", log.Fields{"added-flow": addedFlow, "replaced-flow": replacedFlow, "device-rules": deviceRules, "metadata": metadata})
196
Kent Hagerman433a31a2020-05-20 19:04:48 -0400197 flowHandle, have := agent.flowLoader.Lock(addedFlow.Id)
198 if !have {
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400199 // Not found - do nothing
200 log.Debugw("flow-not-found", log.Fields{"added-flow": addedFlow})
201 return nil
202 }
Kent Hagerman433a31a2020-05-20 19:04:48 -0400203 defer flowHandle.Unlock()
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400204
205 if replacedFlow != nil {
Kent Hagerman433a31a2020-05-20 19:04:48 -0400206 if err := flowHandle.Update(ctx, replacedFlow); err != nil {
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400207 return err
208 }
209 } else {
Kent Hagerman433a31a2020-05-20 19:04:48 -0400210 if err := flowHandle.Delete(ctx); err != nil {
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400211 return err
212 }
213 }
Kent Hagerman433a31a2020-05-20 19:04:48 -0400214
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400215 // Revert meters
216 if changedMeterStats := agent.updateFlowCountOfMeterStats(ctx, mod, addedFlow, true); !changedMeterStats {
217 return fmt.Errorf("Unable-to-revert-meterstats-for-flow-%s", strconv.FormatUint(addedFlow.Id, 10))
218 }
219
220 // Update the devices
Matteo Scandolo367162b2020-06-22 15:07:33 -0700221 respChnls := agent.deleteFlowsAndGroupsFromDevices(deviceRules, metadata, mod)
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400222
223 // Wait for the responses
224 go func() {
225 // Since this action is taken following an add failure, we may also receive a failure for the revert
226 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil {
Matteo Scandolo367162b2020-06-22 15:07:33 -0700227 logger.Warnw("failure-reverting-added-flows", log.Fields{
228 "logical-device-id": agent.logicalDeviceID,
229 "flow-cookie": mod.Cookie,
230 "errors": res,
231 })
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400232 }
233 }()
234
235 return nil
236}
237
238//flowDelete deletes a flow from the flow table of that logical device
239func (agent *LogicalAgent) flowDelete(ctx context.Context, mod *ofp.OfpFlowMod) error {
240 logger.Debug("flowDelete")
241 if mod == nil {
242 return nil
243 }
244
Kent Hagerman433a31a2020-05-20 19:04:48 -0400245 //build a list of what to delete
246 toDelete := make(map[uint64]*ofp.OfpFlowStats)
247
248 // add perfectly matching entry if exists
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400249 fs, err := fu.FlowStatsEntryFromFlowModMessage(mod)
250 if err != nil {
251 return err
252 }
Kent Hagerman433a31a2020-05-20 19:04:48 -0400253 if handle, have := agent.flowLoader.Lock(fs.Id); have {
254 toDelete[fs.Id] = handle.GetReadOnly()
255 handle.Unlock()
256 }
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400257
Kent Hagerman433a31a2020-05-20 19:04:48 -0400258 // search through all the flows
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400259 for flowID := range agent.flowLoader.ListIDs() {
Kent Hagerman433a31a2020-05-20 19:04:48 -0400260 if flowHandle, have := agent.flowLoader.Lock(flowID); have {
261 if flow := flowHandle.GetReadOnly(); fu.FlowMatchesMod(flow, mod) {
262 toDelete[flow.Id] = flow
263 }
264 flowHandle.Unlock()
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400265 }
266 }
Kent Hagerman433a31a2020-05-20 19:04:48 -0400267
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400268 //Delete the matched flows
269 if len(toDelete) > 0 {
270 logger.Debugw("flowDelete", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "toDelete": len(toDelete)})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400271
Kent Hagerman433a31a2020-05-20 19:04:48 -0400272 for _, flow := range toDelete {
273 if flowHandle, have := agent.flowLoader.Lock(flow.Id); have {
274 // TODO: Flow should only be updated if meter is updated, and meter should only be updated if flow is updated
275 // currently an error while performing the second operation will leave an inconsistent state in kv.
276 // This should be a single atomic operation down to the kv.
277 if changedMeter := agent.updateFlowCountOfMeterStats(ctx, mod, flowHandle.GetReadOnly(), false); !changedMeter {
278 flowHandle.Unlock()
279 return fmt.Errorf("cannot-delete-flow-%d. Meter-update-failed", flow.Id)
280 }
281 // Update store and cache
282 if err := flowHandle.Delete(ctx); err != nil {
283 flowHandle.Unlock()
284 return fmt.Errorf("cannot-delete-flows-%d. Delete-from-store-failed", flow.Id)
285 }
286 flowHandle.Unlock()
287 // TODO: since this is executed in a loop without also updating meter stats, and error part way through this
288 // operation will leave inconsistent state in the meter stats & flows on the devices.
289 // This & related meter updates should be a single atomic operation down to the kv.
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400290 }
291 }
Kent Hagerman433a31a2020-05-20 19:04:48 -0400292
293 metersConfig, err := agent.GetMeterConfig(toDelete)
294 if err != nil { // This should never happen
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400295 logger.Error("Meter-referred-in-flows-not-present")
296 return err
297 }
Kent Hagerman433a31a2020-05-20 19:04:48 -0400298
299 groups := make(map[uint32]*ofp.OfpGroupEntry)
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400300 for groupID := range agent.groupLoader.ListIDs() {
Kent Hagerman433a31a2020-05-20 19:04:48 -0400301 if groupHandle, have := agent.groupLoader.Lock(groupID); have {
302 groups[groupID] = groupHandle.GetReadOnly()
303 groupHandle.Unlock()
304 }
305 }
306
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400307 var respChnls []coreutils.Response
308 var partialRoute bool
309 var deviceRules *fu.DeviceRules
Kent Hagerman433a31a2020-05-20 19:04:48 -0400310 deviceRules, err = agent.flowDecomposer.DecomposeRules(ctx, agent, toDelete, groups)
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400311 if err != nil {
312 // A no route error means no route exists between the ports specified in the flow. This can happen when the
313 // child device is deleted and a request to delete flows from the parent device is received
314 if !errors.Is(err, route.ErrNoRoute) {
315 logger.Errorw("unexpected-error-received", log.Fields{"flows-to-delete": toDelete, "error": err})
316 return err
317 }
318 partialRoute = true
319 }
320
321 // Update the devices
322 if partialRoute {
Matteo Scandolo367162b2020-06-22 15:07:33 -0700323 respChnls = agent.deleteFlowsFromParentDevice(toDelete, toMetadata(metersConfig), mod)
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400324 } else {
Matteo Scandolo367162b2020-06-22 15:07:33 -0700325 respChnls = agent.deleteFlowsAndGroupsFromDevices(deviceRules, toMetadata(metersConfig), mod)
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400326 }
327
328 // Wait for the responses
329 go func() {
330 // Wait for completion
331 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil {
332 logger.Errorw("failure-updating-device-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "errors": res})
333 // TODO: Revert the flow deletion
334 }
335 }()
336 }
337 //TODO: send announcement on delete
338 return nil
339}
340
341//flowDeleteStrict deletes a flow from the flow table of that logical device
342func (agent *LogicalAgent) flowDeleteStrict(ctx context.Context, mod *ofp.OfpFlowMod) error {
343 logger.Debugw("flowDeleteStrict", log.Fields{"mod": mod})
344 if mod == nil {
345 return nil
346 }
347
348 flow, err := fu.FlowStatsEntryFromFlowModMessage(mod)
349 if err != nil {
350 return err
351 }
352 logger.Debugw("flow-id-in-flow-delete-strict", log.Fields{"flowID": flow.Id})
Kent Hagerman433a31a2020-05-20 19:04:48 -0400353 flowHandle, have := agent.flowLoader.Lock(flow.Id)
354 if !have {
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400355 logger.Debugw("Skipping-flow-delete-strict-request. No-flow-found", log.Fields{"flowMod": mod})
356 return nil
357 }
Kent Hagerman433a31a2020-05-20 19:04:48 -0400358 defer flowHandle.Unlock()
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400359
Kent Hagerman433a31a2020-05-20 19:04:48 -0400360 groups := make(map[uint32]*ofp.OfpGroupEntry)
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400361 for groupID := range agent.groupLoader.ListIDs() {
Kent Hagerman433a31a2020-05-20 19:04:48 -0400362 if groupHandle, have := agent.groupLoader.Lock(groupID); have {
363 groups[groupID] = groupHandle.GetReadOnly()
364 groupHandle.Unlock()
365 }
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400366 }
Kent Hagerman433a31a2020-05-20 19:04:48 -0400367
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400368 if changedMeter := agent.updateFlowCountOfMeterStats(ctx, mod, flow, false); !changedMeter {
369 return fmt.Errorf("Cannot delete flow - %s. Meter update failed", flow)
370 }
371
Kent Hagerman433a31a2020-05-20 19:04:48 -0400372 flowsToDelete := map[uint64]*ofp.OfpFlowStats{flow.Id: flowHandle.GetReadOnly()}
373
374 flowMetadata, err := agent.GetMeterConfig(flowsToDelete)
375 if err != nil {
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400376 logger.Error("meter-referred-in-flows-not-present")
377 return err
378 }
379 var respChnls []coreutils.Response
380 var partialRoute bool
Kent Hagerman433a31a2020-05-20 19:04:48 -0400381 deviceRules, err := agent.flowDecomposer.DecomposeRules(ctx, agent, flowsToDelete, groups)
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400382 if err != nil {
383 // A no route error means no route exists between the ports specified in the flow. This can happen when the
384 // child device is deleted and a request to delete flows from the parent device is received
385 if !errors.Is(err, route.ErrNoRoute) {
386 logger.Errorw("unexpected-error-received", log.Fields{"flows-to-delete": flowsToDelete, "error": err})
387 return err
388 }
389 partialRoute = true
390 }
391
392 // Update the model
Kent Hagerman433a31a2020-05-20 19:04:48 -0400393 if err := flowHandle.Delete(ctx); err != nil {
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400394 return err
395 }
396 // Update the devices
397 if partialRoute {
Matteo Scandolo367162b2020-06-22 15:07:33 -0700398 respChnls = agent.deleteFlowsFromParentDevice(flowsToDelete, toMetadata(flowMetadata), mod)
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400399 } else {
Matteo Scandolo367162b2020-06-22 15:07:33 -0700400 respChnls = agent.deleteFlowsAndGroupsFromDevices(deviceRules, toMetadata(flowMetadata), mod)
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400401 }
402
403 // Wait for completion
404 go func() {
405 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil {
Matteo Scandolo367162b2020-06-22 15:07:33 -0700406 logger.Warnw("failure-deleting-device-flows", log.Fields{
407 "flow-cookie": mod.Cookie,
408 "logical-device-id": agent.logicalDeviceID,
409 "errors": res,
410 })
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400411 //TODO: Revert flow changes
412 }
413 }()
414
415 return nil
416}
417
418//flowModify modifies a flow from the flow table of that logical device
419func (agent *LogicalAgent) flowModify(mod *ofp.OfpFlowMod) error {
420 return errors.New("flowModify not implemented")
421}
422
423//flowModifyStrict deletes a flow from the flow table of that logical device
424func (agent *LogicalAgent) flowModifyStrict(mod *ofp.OfpFlowMod) error {
425 return errors.New("flowModifyStrict not implemented")
426}
Kent Hagerman433a31a2020-05-20 19:04:48 -0400427
428// TODO: Remove this helper, just pass the map through to functions directly
429func toMetadata(meters map[uint32]*ofp.OfpMeterConfig) *voltha.FlowMetadata {
430 ctr, ret := 0, make([]*ofp.OfpMeterConfig, len(meters))
431 for _, meter := range meters {
432 ret[ctr] = meter
433 ctr++
434 }
435 return &voltha.FlowMetadata{Meters: ret}
436}
437
438func (agent *LogicalAgent) deleteFlowsHavingMeter(ctx context.Context, meterID uint32) error {
439 logger.Infow("Delete-flows-matching-meter", log.Fields{"meter": meterID})
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400440 for flowID := range agent.flowLoader.ListIDs() {
Kent Hagerman433a31a2020-05-20 19:04:48 -0400441 if flowHandle, have := agent.flowLoader.Lock(flowID); have {
442 if flowMeterID := fu.GetMeterIdFromFlow(flowHandle.GetReadOnly()); flowMeterID != 0 && flowMeterID == meterID {
443 if err := flowHandle.Delete(ctx); err != nil {
444 //TODO: Think on carrying on and deleting the remaining flows, instead of returning.
445 //Anyways this returns an error to controller which possibly results with a re-deletion.
446 //Then how can we handle the new deletion request(Same for group deletion)?
447 return err
448 }
449 }
450 flowHandle.Unlock()
451 }
452 }
453 return nil
454}
455
456func (agent *LogicalAgent) deleteFlowsHavingGroup(ctx context.Context, groupID uint32) (map[uint64]*ofp.OfpFlowStats, error) {
457 logger.Infow("Delete-flows-matching-group", log.Fields{"groupID": groupID})
458 flowsRemoved := make(map[uint64]*ofp.OfpFlowStats)
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400459 for flowID := range agent.flowLoader.ListIDs() {
Kent Hagerman433a31a2020-05-20 19:04:48 -0400460 if flowHandle, have := agent.flowLoader.Lock(flowID); have {
461 if flow := flowHandle.GetReadOnly(); fu.FlowHasOutGroup(flow, groupID) {
462 if err := flowHandle.Delete(ctx); err != nil {
463 return nil, err
464 }
465 flowsRemoved[flowID] = flow
466 }
467 flowHandle.Unlock()
468 }
469 }
470 return flowsRemoved, nil
471}