blob: e9e53ddbd2dd3305770b576f18f6e4863f10901e [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"
Himani Chawla531af4f2020-09-22 10:42:17 +053023 "strconv"
24
Kent Hagerman3136fbd2020-05-14 10:30:45 -040025 "github.com/gogo/protobuf/proto"
26 "github.com/opencord/voltha-go/rw_core/route"
27 coreutils "github.com/opencord/voltha-go/rw_core/utils"
28 fu "github.com/opencord/voltha-lib-go/v3/pkg/flows"
29 "github.com/opencord/voltha-lib-go/v3/pkg/log"
30 ofp "github.com/opencord/voltha-protos/v3/go/openflow_13"
31 "github.com/opencord/voltha-protos/v3/go/voltha"
32 "google.golang.org/grpc/codes"
33 "google.golang.org/grpc/status"
34)
35
Kent Hagerman433a31a2020-05-20 19:04:48 -040036// listLogicalDeviceFlows returns logical device flows
37func (agent *LogicalAgent) listLogicalDeviceFlows() map[uint64]*ofp.OfpFlowStats {
Kent Hagermanfa9d6d42020-05-25 11:49:40 -040038 flowIDs := agent.flowLoader.ListIDs()
Kent Hagerman433a31a2020-05-20 19:04:48 -040039 flows := make(map[uint64]*ofp.OfpFlowStats, len(flowIDs))
40 for flowID := range flowIDs {
41 if flowHandle, have := agent.flowLoader.Lock(flowID); have {
42 flows[flowID] = flowHandle.GetReadOnly()
43 flowHandle.Unlock()
44 }
45 }
46 return flows
47}
48
Kent Hagerman3136fbd2020-05-14 10:30:45 -040049//updateFlowTable updates the flow table of that logical device
50func (agent *LogicalAgent) updateFlowTable(ctx context.Context, flow *ofp.OfpFlowMod) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +000051 logger.Debug(ctx, "UpdateFlowTable")
Kent Hagerman3136fbd2020-05-14 10:30:45 -040052 if flow == nil {
53 return nil
54 }
55
Kent Hagerman3136fbd2020-05-14 10:30:45 -040056 switch flow.GetCommand() {
57 case ofp.OfpFlowModCommand_OFPFC_ADD:
58 return agent.flowAdd(ctx, flow)
59 case ofp.OfpFlowModCommand_OFPFC_DELETE:
60 return agent.flowDelete(ctx, flow)
61 case ofp.OfpFlowModCommand_OFPFC_DELETE_STRICT:
62 return agent.flowDeleteStrict(ctx, flow)
63 case ofp.OfpFlowModCommand_OFPFC_MODIFY:
64 return agent.flowModify(flow)
65 case ofp.OfpFlowModCommand_OFPFC_MODIFY_STRICT:
66 return agent.flowModifyStrict(flow)
67 }
68 return status.Errorf(codes.Internal,
69 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceID, flow.GetCommand())
70}
71
72//flowAdd adds a flow to the flow table of that logical device
73func (agent *LogicalAgent) flowAdd(ctx context.Context, mod *ofp.OfpFlowMod) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +000074 logger.Debugw(ctx, "flowAdd", log.Fields{"flow": mod})
Kent Hagerman3136fbd2020-05-14 10:30:45 -040075 if mod == nil {
76 return nil
77 }
78 flow, err := fu.FlowStatsEntryFromFlowModMessage(mod)
79 if err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +000080 logger.Errorw(ctx, "flowAdd-failed", log.Fields{"flowMod": mod, "err": err})
Kent Hagerman3136fbd2020-05-14 10:30:45 -040081 return err
82 }
83 var updated bool
84 var changed bool
85 if changed, updated, err = agent.decomposeAndAdd(ctx, flow, mod); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +000086 logger.Errorw(ctx, "flow-decompose-and-add-failed ", log.Fields{"flowMod": mod, "err": err})
Kent Hagerman3136fbd2020-05-14 10:30:45 -040087 return err
88 }
89 if changed && !updated {
90 if dbupdated := agent.updateFlowCountOfMeterStats(ctx, mod, flow, false); !dbupdated {
91 return fmt.Errorf("couldnt-updated-flow-stats-%s", strconv.FormatUint(flow.Id, 10))
92 }
93 }
94 return nil
95
96}
97
98func (agent *LogicalAgent) decomposeAndAdd(ctx context.Context, flow *ofp.OfpFlowStats, mod *ofp.OfpFlowMod) (bool, bool, error) {
99 changed := false
100 updated := false
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400101 var flowToReplace *ofp.OfpFlowStats
102
103 //if flow is not found in the map, create a new entry, otherwise get the existing one.
Kent Hagerman433a31a2020-05-20 19:04:48 -0400104 flowHandle, created, err := agent.flowLoader.LockOrCreate(ctx, flow)
105 if err != nil {
106 return changed, updated, err
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400107 }
Kent Hagerman433a31a2020-05-20 19:04:48 -0400108 defer flowHandle.Unlock()
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400109
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400110 flows := make([]*ofp.OfpFlowStats, 0)
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400111 checkOverlap := (mod.Flags & uint32(ofp.OfpFlowModFlags_OFPFF_CHECK_OVERLAP)) != 0
112 if checkOverlap {
Kent Hagerman433a31a2020-05-20 19:04:48 -0400113 // TODO: this currently does nothing
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400114 if overlapped := fu.FindOverlappingFlows(flows, mod); len(overlapped) != 0 {
Kent Hagerman433a31a2020-05-20 19:04:48 -0400115 // TODO: should this error be notified other than being logged?
Rohan Agrawal31f21802020-06-12 05:38:46 +0000116 logger.Warnw(ctx, "overlapped-flows", log.Fields{"logicaldeviceId": agent.logicalDeviceID})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400117 } else {
118 // Add flow
119 changed = true
120 }
121 } else {
Kent Hagerman433a31a2020-05-20 19:04:48 -0400122 if !created {
123 flowToReplace = flowHandle.GetReadOnly()
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400124 if (mod.Flags & uint32(ofp.OfpFlowModFlags_OFPFF_RESET_COUNTS)) != 0 {
125 flow.ByteCount = flowToReplace.ByteCount
126 flow.PacketCount = flowToReplace.PacketCount
127 }
128 if !proto.Equal(flowToReplace, flow) {
129 changed = true
130 updated = true
131 }
132 } else {
133 changed = true
134 }
135 }
Rohan Agrawal31f21802020-06-12 05:38:46 +0000136 logger.Debugw(ctx, "flowAdd-changed", log.Fields{"changed": changed, "updated": updated})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400137 if changed {
Kent Hagerman433a31a2020-05-20 19:04:48 -0400138 updatedFlows := map[uint64]*ofp.OfpFlowStats{flow.Id: flow}
139
Rohan Agrawal31f21802020-06-12 05:38:46 +0000140 flowMeterConfig, err := agent.GetMeterConfig(ctx, updatedFlows)
Kent Hagerman433a31a2020-05-20 19:04:48 -0400141 if err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000142 logger.Error(ctx, "Meter-referred-in-flow-not-present")
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400143 return changed, updated, err
144 }
Kent Hagerman433a31a2020-05-20 19:04:48 -0400145
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400146 groupIDs := agent.groupLoader.ListIDs()
Kent Hagerman433a31a2020-05-20 19:04:48 -0400147 groups := make(map[uint32]*ofp.OfpGroupEntry, len(groupIDs))
148 for groupID := range groupIDs {
149 if groupHandle, have := agent.groupLoader.Lock(groupID); have {
150 groups[groupID] = groupHandle.GetReadOnly()
151 groupHandle.Unlock()
152 }
153 }
154
155 deviceRules, err := agent.flowDecomposer.DecomposeRules(ctx, agent, updatedFlows, groups)
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400156 if err != nil {
157 return changed, updated, err
158 }
159
Rohan Agrawal31f21802020-06-12 05:38:46 +0000160 logger.Debugw(ctx, "rules", log.Fields{"rules": deviceRules.String()})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400161 // Update store and cache
162 if updated {
Kent Hagerman433a31a2020-05-20 19:04:48 -0400163 if err := flowHandle.Update(ctx, flow); err != nil {
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400164 return changed, updated, err
165 }
166 }
Rohan Agrawal31f21802020-06-12 05:38:46 +0000167 respChannels := agent.addFlowsAndGroupsToDevices(ctx, deviceRules, toMetadata(flowMeterConfig))
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400168 // Create the go routines to wait
169 go func() {
170 // Wait for completion
171 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChannels...); res != nil {
Himani Chawla531af4f2020-09-22 10:42:17 +0530172 logger.Infow(ctx, "failed-to-add-flow-will-attempt-deletion", log.Fields{
Matteo Scandolo45e514a2020-08-05 15:27:10 -0700173 "errors": res,
174 "logical-device-id": agent.logicalDeviceID,
Himani Chawla531af4f2020-09-22 10:42:17 +0530175 "flow": flow,
Matteo Scandolo45e514a2020-08-05 15:27:10 -0700176 "groups": groups,
177 })
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400178 // Revert added flows
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000179 if err := agent.revertAddedFlows(log.WithSpanFromContext(context.Background(), ctx), mod, flow, flowToReplace, deviceRules, toMetadata(flowMeterConfig)); err != nil {
Himani Chawla531af4f2020-09-22 10:42:17 +0530180 logger.Errorw(ctx, "failure-to-delete-flow-after-failed-addition", log.Fields{
Matteo Scandolo45e514a2020-08-05 15:27:10 -0700181 "error": err,
182 "logical-device-id": agent.logicalDeviceID,
Himani Chawla531af4f2020-09-22 10:42:17 +0530183 "flow": flow,
Matteo Scandolo45e514a2020-08-05 15:27:10 -0700184 "groups": groups,
185 })
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400186 }
187 }
188 }()
189 }
190 return changed, updated, nil
191}
192
193// revertAddedFlows reverts flows after the flowAdd request has failed. All flows corresponding to that flowAdd request
194// will be reverted, both from the logical devices and the devices.
195func (agent *LogicalAgent) revertAddedFlows(ctx context.Context, mod *ofp.OfpFlowMod, addedFlow *ofp.OfpFlowStats, replacedFlow *ofp.OfpFlowStats, deviceRules *fu.DeviceRules, metadata *voltha.FlowMetadata) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000196 logger.Debugw(ctx, "revertFlowAdd", log.Fields{"added-flow": addedFlow, "replaced-flow": replacedFlow, "device-rules": deviceRules, "metadata": metadata})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400197
Kent Hagerman433a31a2020-05-20 19:04:48 -0400198 flowHandle, have := agent.flowLoader.Lock(addedFlow.Id)
199 if !have {
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400200 // Not found - do nothing
Girish Kumar3e8ee212020-08-19 17:50:11 +0000201 logger.Debugw(ctx, "flow-not-found", log.Fields{"added-flow": addedFlow})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400202 return nil
203 }
Kent Hagerman433a31a2020-05-20 19:04:48 -0400204 defer flowHandle.Unlock()
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400205
206 if replacedFlow != nil {
Kent Hagerman433a31a2020-05-20 19:04:48 -0400207 if err := flowHandle.Update(ctx, replacedFlow); err != nil {
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400208 return err
209 }
210 } else {
Kent Hagerman433a31a2020-05-20 19:04:48 -0400211 if err := flowHandle.Delete(ctx); err != nil {
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400212 return err
213 }
214 }
Kent Hagerman433a31a2020-05-20 19:04:48 -0400215
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400216 // Revert meters
217 if changedMeterStats := agent.updateFlowCountOfMeterStats(ctx, mod, addedFlow, true); !changedMeterStats {
218 return fmt.Errorf("Unable-to-revert-meterstats-for-flow-%s", strconv.FormatUint(addedFlow.Id, 10))
219 }
220
221 // Update the devices
Rohan Agrawal31f21802020-06-12 05:38:46 +0000222 respChnls := agent.deleteFlowsAndGroupsFromDevices(ctx, deviceRules, metadata, mod)
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400223
224 // Wait for the responses
225 go func() {
226 // Since this action is taken following an add failure, we may also receive a failure for the revert
227 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000228 logger.Warnw(ctx, "failure-reverting-added-flows", log.Fields{
Matteo Scandolo367162b2020-06-22 15:07:33 -0700229 "logical-device-id": agent.logicalDeviceID,
230 "flow-cookie": mod.Cookie,
231 "errors": res,
232 })
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400233 }
234 }()
235
236 return nil
237}
238
239//flowDelete deletes a flow from the flow table of that logical device
240func (agent *LogicalAgent) flowDelete(ctx context.Context, mod *ofp.OfpFlowMod) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000241 logger.Debug(ctx, "flowDelete")
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400242 if mod == nil {
243 return nil
244 }
245
Kent Hagerman433a31a2020-05-20 19:04:48 -0400246 //build a list of what to delete
247 toDelete := make(map[uint64]*ofp.OfpFlowStats)
248
249 // add perfectly matching entry if exists
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400250 fs, err := fu.FlowStatsEntryFromFlowModMessage(mod)
251 if err != nil {
252 return err
253 }
Kent Hagerman433a31a2020-05-20 19:04:48 -0400254 if handle, have := agent.flowLoader.Lock(fs.Id); have {
255 toDelete[fs.Id] = handle.GetReadOnly()
256 handle.Unlock()
257 }
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400258
Kent Hagerman433a31a2020-05-20 19:04:48 -0400259 // search through all the flows
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400260 for flowID := range agent.flowLoader.ListIDs() {
Kent Hagerman433a31a2020-05-20 19:04:48 -0400261 if flowHandle, have := agent.flowLoader.Lock(flowID); have {
262 if flow := flowHandle.GetReadOnly(); fu.FlowMatchesMod(flow, mod) {
263 toDelete[flow.Id] = flow
264 }
265 flowHandle.Unlock()
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400266 }
267 }
Kent Hagerman433a31a2020-05-20 19:04:48 -0400268
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400269 //Delete the matched flows
270 if len(toDelete) > 0 {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000271 logger.Debugw(ctx, "flowDelete", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "toDelete": len(toDelete)})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400272
Kent Hagerman433a31a2020-05-20 19:04:48 -0400273 for _, flow := range toDelete {
274 if flowHandle, have := agent.flowLoader.Lock(flow.Id); have {
275 // TODO: Flow should only be updated if meter is updated, and meter should only be updated if flow is updated
276 // currently an error while performing the second operation will leave an inconsistent state in kv.
277 // This should be a single atomic operation down to the kv.
278 if changedMeter := agent.updateFlowCountOfMeterStats(ctx, mod, flowHandle.GetReadOnly(), false); !changedMeter {
279 flowHandle.Unlock()
280 return fmt.Errorf("cannot-delete-flow-%d. Meter-update-failed", flow.Id)
281 }
282 // Update store and cache
283 if err := flowHandle.Delete(ctx); err != nil {
284 flowHandle.Unlock()
285 return fmt.Errorf("cannot-delete-flows-%d. Delete-from-store-failed", flow.Id)
286 }
287 flowHandle.Unlock()
288 // TODO: since this is executed in a loop without also updating meter stats, and error part way through this
289 // operation will leave inconsistent state in the meter stats & flows on the devices.
290 // This & related meter updates should be a single atomic operation down to the kv.
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400291 }
292 }
Kent Hagerman433a31a2020-05-20 19:04:48 -0400293
Rohan Agrawal31f21802020-06-12 05:38:46 +0000294 metersConfig, err := agent.GetMeterConfig(ctx, toDelete)
Kent Hagerman433a31a2020-05-20 19:04:48 -0400295 if err != nil { // This should never happen
Rohan Agrawal31f21802020-06-12 05:38:46 +0000296 logger.Error(ctx, "Meter-referred-in-flows-not-present")
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400297 return err
298 }
Kent Hagerman433a31a2020-05-20 19:04:48 -0400299
300 groups := make(map[uint32]*ofp.OfpGroupEntry)
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400301 for groupID := range agent.groupLoader.ListIDs() {
Kent Hagerman433a31a2020-05-20 19:04:48 -0400302 if groupHandle, have := agent.groupLoader.Lock(groupID); have {
303 groups[groupID] = groupHandle.GetReadOnly()
304 groupHandle.Unlock()
305 }
306 }
307
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400308 var respChnls []coreutils.Response
309 var partialRoute bool
310 var deviceRules *fu.DeviceRules
Kent Hagerman433a31a2020-05-20 19:04:48 -0400311 deviceRules, err = agent.flowDecomposer.DecomposeRules(ctx, agent, toDelete, groups)
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400312 if err != nil {
313 // A no route error means no route exists between the ports specified in the flow. This can happen when the
314 // child device is deleted and a request to delete flows from the parent device is received
315 if !errors.Is(err, route.ErrNoRoute) {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000316 logger.Errorw(ctx, "unexpected-error-received", log.Fields{"flows-to-delete": toDelete, "error": err})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400317 return err
318 }
319 partialRoute = true
320 }
321
322 // Update the devices
323 if partialRoute {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000324 respChnls = agent.deleteFlowsFromParentDevice(ctx, toDelete, toMetadata(metersConfig), mod)
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400325 } else {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000326 respChnls = agent.deleteFlowsAndGroupsFromDevices(ctx, deviceRules, toMetadata(metersConfig), mod)
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400327 }
328
329 // Wait for the responses
330 go func() {
331 // Wait for completion
332 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000333 logger.Errorw(ctx, "failure-updating-device-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "errors": res})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400334 // TODO: Revert the flow deletion
335 }
336 }()
337 }
338 //TODO: send announcement on delete
339 return nil
340}
341
342//flowDeleteStrict deletes a flow from the flow table of that logical device
343func (agent *LogicalAgent) flowDeleteStrict(ctx context.Context, mod *ofp.OfpFlowMod) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000344 logger.Debugw(ctx, "flowDeleteStrict", log.Fields{"mod": mod})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400345 if mod == nil {
346 return nil
347 }
348
349 flow, err := fu.FlowStatsEntryFromFlowModMessage(mod)
350 if err != nil {
351 return err
352 }
Rohan Agrawal31f21802020-06-12 05:38:46 +0000353 logger.Debugw(ctx, "flow-id-in-flow-delete-strict", log.Fields{"flowID": flow.Id})
Kent Hagerman433a31a2020-05-20 19:04:48 -0400354 flowHandle, have := agent.flowLoader.Lock(flow.Id)
355 if !have {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000356 logger.Debugw(ctx, "Skipping-flow-delete-strict-request. No-flow-found", log.Fields{"flowMod": mod})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400357 return nil
358 }
Kent Hagerman433a31a2020-05-20 19:04:48 -0400359 defer flowHandle.Unlock()
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400360
Kent Hagerman433a31a2020-05-20 19:04:48 -0400361 groups := make(map[uint32]*ofp.OfpGroupEntry)
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400362 for groupID := range agent.groupLoader.ListIDs() {
Kent Hagerman433a31a2020-05-20 19:04:48 -0400363 if groupHandle, have := agent.groupLoader.Lock(groupID); have {
364 groups[groupID] = groupHandle.GetReadOnly()
365 groupHandle.Unlock()
366 }
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400367 }
Kent Hagerman433a31a2020-05-20 19:04:48 -0400368
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400369 if changedMeter := agent.updateFlowCountOfMeterStats(ctx, mod, flow, false); !changedMeter {
370 return fmt.Errorf("Cannot delete flow - %s. Meter update failed", flow)
371 }
372
Kent Hagerman433a31a2020-05-20 19:04:48 -0400373 flowsToDelete := map[uint64]*ofp.OfpFlowStats{flow.Id: flowHandle.GetReadOnly()}
374
Rohan Agrawal31f21802020-06-12 05:38:46 +0000375 flowMetadata, err := agent.GetMeterConfig(ctx, flowsToDelete)
Kent Hagerman433a31a2020-05-20 19:04:48 -0400376 if err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000377 logger.Error(ctx, "meter-referred-in-flows-not-present")
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400378 return err
379 }
380 var respChnls []coreutils.Response
381 var partialRoute bool
Kent Hagerman433a31a2020-05-20 19:04:48 -0400382 deviceRules, err := agent.flowDecomposer.DecomposeRules(ctx, agent, flowsToDelete, groups)
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400383 if err != nil {
384 // A no route error means no route exists between the ports specified in the flow. This can happen when the
385 // child device is deleted and a request to delete flows from the parent device is received
386 if !errors.Is(err, route.ErrNoRoute) {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000387 logger.Errorw(ctx, "unexpected-error-received", log.Fields{"flows-to-delete": flowsToDelete, "error": err})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400388 return err
389 }
390 partialRoute = true
391 }
392
393 // Update the model
Kent Hagerman433a31a2020-05-20 19:04:48 -0400394 if err := flowHandle.Delete(ctx); err != nil {
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400395 return err
396 }
397 // Update the devices
398 if partialRoute {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000399 respChnls = agent.deleteFlowsFromParentDevice(ctx, flowsToDelete, toMetadata(flowMetadata), mod)
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400400 } else {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000401 respChnls = agent.deleteFlowsAndGroupsFromDevices(ctx, deviceRules, toMetadata(flowMetadata), mod)
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400402 }
403
404 // Wait for completion
405 go func() {
406 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000407 logger.Warnw(ctx, "failure-deleting-device-flows", log.Fields{
Matteo Scandolo367162b2020-06-22 15:07:33 -0700408 "flow-cookie": mod.Cookie,
409 "logical-device-id": agent.logicalDeviceID,
410 "errors": res,
411 })
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400412 //TODO: Revert flow changes
413 }
414 }()
415
416 return nil
417}
418
419//flowModify modifies a flow from the flow table of that logical device
420func (agent *LogicalAgent) flowModify(mod *ofp.OfpFlowMod) error {
421 return errors.New("flowModify not implemented")
422}
423
424//flowModifyStrict deletes a flow from the flow table of that logical device
425func (agent *LogicalAgent) flowModifyStrict(mod *ofp.OfpFlowMod) error {
426 return errors.New("flowModifyStrict not implemented")
427}
Kent Hagerman433a31a2020-05-20 19:04:48 -0400428
429// TODO: Remove this helper, just pass the map through to functions directly
430func toMetadata(meters map[uint32]*ofp.OfpMeterConfig) *voltha.FlowMetadata {
431 ctr, ret := 0, make([]*ofp.OfpMeterConfig, len(meters))
432 for _, meter := range meters {
433 ret[ctr] = meter
434 ctr++
435 }
436 return &voltha.FlowMetadata{Meters: ret}
437}
438
439func (agent *LogicalAgent) deleteFlowsHavingMeter(ctx context.Context, meterID uint32) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000440 logger.Infow(ctx, "Delete-flows-matching-meter", log.Fields{"meter": meterID})
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400441 for flowID := range agent.flowLoader.ListIDs() {
Kent Hagerman433a31a2020-05-20 19:04:48 -0400442 if flowHandle, have := agent.flowLoader.Lock(flowID); have {
443 if flowMeterID := fu.GetMeterIdFromFlow(flowHandle.GetReadOnly()); flowMeterID != 0 && flowMeterID == meterID {
444 if err := flowHandle.Delete(ctx); err != nil {
445 //TODO: Think on carrying on and deleting the remaining flows, instead of returning.
446 //Anyways this returns an error to controller which possibly results with a re-deletion.
447 //Then how can we handle the new deletion request(Same for group deletion)?
448 return err
449 }
450 }
451 flowHandle.Unlock()
452 }
453 }
454 return nil
455}
456
457func (agent *LogicalAgent) deleteFlowsHavingGroup(ctx context.Context, groupID uint32) (map[uint64]*ofp.OfpFlowStats, error) {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000458 logger.Infow(ctx, "Delete-flows-matching-group", log.Fields{"groupID": groupID})
Kent Hagerman433a31a2020-05-20 19:04:48 -0400459 flowsRemoved := make(map[uint64]*ofp.OfpFlowStats)
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400460 for flowID := range agent.flowLoader.ListIDs() {
Kent Hagerman433a31a2020-05-20 19:04:48 -0400461 if flowHandle, have := agent.flowLoader.Lock(flowID); have {
462 if flow := flowHandle.GetReadOnly(); fu.FlowHasOutGroup(flow, groupID) {
463 if err := flowHandle.Delete(ctx); err != nil {
464 return nil, err
465 }
466 flowsRemoved[flowID] = flow
467 }
468 flowHandle.Unlock()
469 }
470 }
471 return flowsRemoved, nil
472}