blob: 0e997ec10bf4e5ddf665b9fbf1719ea73e89bcc2 [file] [log] [blame]
Kent Hagerman3136fbd2020-05-14 10:30:45 -04001/*
Joey Armstrong7a9af442024-01-03 19:26:36 -05002 * Copyright 2018-2024 Open Networking Foundation (ONF) and the ONF Contributors
Kent Hagerman3136fbd2020-05-14 10:30:45 -04003
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"
Himani Chawlab4c25912020-11-12 17:16:38 +053024 "time"
Himani Chawla531af4f2020-09-22 10:42:17 +053025
Kent Hagerman3136fbd2020-05-14 10:30:45 -040026 "github.com/gogo/protobuf/proto"
khenaidood948f772021-08-11 17:49:24 -040027 "github.com/opencord/voltha-go/rw_core/core/device/flow"
Kent Hagerman3136fbd2020-05-14 10:30:45 -040028 "github.com/opencord/voltha-go/rw_core/route"
29 coreutils "github.com/opencord/voltha-go/rw_core/utils"
khenaidood948f772021-08-11 17:49:24 -040030 fu "github.com/opencord/voltha-lib-go/v7/pkg/flows"
31 "github.com/opencord/voltha-lib-go/v7/pkg/log"
32 ofp "github.com/opencord/voltha-protos/v5/go/openflow_13"
33 "github.com/opencord/voltha-protos/v5/go/voltha"
Kent Hagerman3136fbd2020-05-14 10:30:45 -040034 "google.golang.org/grpc/codes"
35 "google.golang.org/grpc/status"
36)
37
Kent Hagerman433a31a2020-05-20 19:04:48 -040038// listLogicalDeviceFlows returns logical device flows
39func (agent *LogicalAgent) listLogicalDeviceFlows() map[uint64]*ofp.OfpFlowStats {
khenaidoo7585a962021-06-10 16:15:38 -040040 flowIDs := agent.flowCache.ListIDs()
Kent Hagerman433a31a2020-05-20 19:04:48 -040041 flows := make(map[uint64]*ofp.OfpFlowStats, len(flowIDs))
42 for flowID := range flowIDs {
khenaidoo7585a962021-06-10 16:15:38 -040043 if flowHandle, have := agent.flowCache.Lock(flowID); have {
Kent Hagerman433a31a2020-05-20 19:04:48 -040044 flows[flowID] = flowHandle.GetReadOnly()
45 flowHandle.Unlock()
46 }
47 }
48 return flows
49}
50
Joey Armstrong393daca2023-07-06 08:47:54 -040051// updateFlowTable updates the flow table of that logical device
Maninderf421da62020-12-04 11:44:58 +053052func (agent *LogicalAgent) updateFlowTable(ctx context.Context, flow *ofp.FlowTableUpdate) error {
Himani Chawlab4c25912020-11-12 17:16:38 +053053 logger.Debug(ctx, "update-flow-table")
Kent Hagerman3136fbd2020-05-14 10:30:45 -040054 if flow == nil {
55 return nil
56 }
57
Maninderf421da62020-12-04 11:44:58 +053058 switch flow.FlowMod.GetCommand() {
Kent Hagerman3136fbd2020-05-14 10:30:45 -040059 case ofp.OfpFlowModCommand_OFPFC_ADD:
60 return agent.flowAdd(ctx, flow)
61 case ofp.OfpFlowModCommand_OFPFC_DELETE:
62 return agent.flowDelete(ctx, flow)
63 case ofp.OfpFlowModCommand_OFPFC_DELETE_STRICT:
64 return agent.flowDeleteStrict(ctx, flow)
65 case ofp.OfpFlowModCommand_OFPFC_MODIFY:
66 return agent.flowModify(flow)
67 case ofp.OfpFlowModCommand_OFPFC_MODIFY_STRICT:
68 return agent.flowModifyStrict(flow)
69 }
70 return status.Errorf(codes.Internal,
Maninderf421da62020-12-04 11:44:58 +053071 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceID, flow.FlowMod.GetCommand())
Kent Hagerman3136fbd2020-05-14 10:30:45 -040072}
73
Joey Armstrong393daca2023-07-06 08:47:54 -040074// flowAdd adds a flow to the flow table of that logical device
Maninderf421da62020-12-04 11:44:58 +053075func (agent *LogicalAgent) flowAdd(ctx context.Context, flowUpdate *ofp.FlowTableUpdate) error {
76 mod := flowUpdate.FlowMod
Himani Chawlab4c25912020-11-12 17:16:38 +053077 logger.Debugw(ctx, "flow-add", log.Fields{"flow": mod})
Kent Hagerman3136fbd2020-05-14 10:30:45 -040078 if mod == nil {
79 return nil
80 }
81 flow, err := fu.FlowStatsEntryFromFlowModMessage(mod)
82 if err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +053083 logger.Errorw(ctx, "flow-add-failed", log.Fields{"flow-mod": mod, "err": err})
Kent Hagerman3136fbd2020-05-14 10:30:45 -040084 return err
85 }
86 var updated bool
87 var changed bool
Maninderf421da62020-12-04 11:44:58 +053088 if changed, updated, err = agent.decomposeAndAdd(ctx, flow, flowUpdate); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +053089 logger.Errorw(ctx, "flow-decompose-and-add-failed ", log.Fields{"flow-mod": mod, "err": err})
Kent Hagerman3136fbd2020-05-14 10:30:45 -040090 return err
91 }
92 if changed && !updated {
93 if dbupdated := agent.updateFlowCountOfMeterStats(ctx, mod, flow, false); !dbupdated {
94 return fmt.Errorf("couldnt-updated-flow-stats-%s", strconv.FormatUint(flow.Id, 10))
95 }
96 }
97 return nil
98
99}
100
Maninderf421da62020-12-04 11:44:58 +0530101func (agent *LogicalAgent) decomposeAndAdd(ctx context.Context, flow *ofp.OfpFlowStats, flowUpdate *ofp.FlowTableUpdate) (bool, bool, error) {
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400102 changed := false
103 updated := false
Maninderf421da62020-12-04 11:44:58 +0530104 mod := flowUpdate.FlowMod
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400105 var flowToReplace *ofp.OfpFlowStats
106
107 //if flow is not found in the map, create a new entry, otherwise get the existing one.
khenaidood948f772021-08-11 17:49:24 -0400108 flowHandle, flowCreated, err := agent.flowCache.LockOrCreate(ctx, flow)
Kent Hagerman433a31a2020-05-20 19:04:48 -0400109 if err != nil {
110 return changed, updated, err
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400111 }
Kent Hagerman433a31a2020-05-20 19:04:48 -0400112 defer flowHandle.Unlock()
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400113
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400114 flows := make([]*ofp.OfpFlowStats, 0)
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400115 checkOverlap := (mod.Flags & uint32(ofp.OfpFlowModFlags_OFPFF_CHECK_OVERLAP)) != 0
116 if checkOverlap {
Kent Hagerman433a31a2020-05-20 19:04:48 -0400117 // TODO: this currently does nothing
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400118 if overlapped := fu.FindOverlappingFlows(flows, mod); len(overlapped) != 0 {
Kent Hagerman433a31a2020-05-20 19:04:48 -0400119 // TODO: should this error be notified other than being logged?
Himani Chawlab4c25912020-11-12 17:16:38 +0530120 logger.Warnw(ctx, "overlapped-flows", log.Fields{"logical-device-id": agent.logicalDeviceID})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400121 } else {
122 // Add flow
123 changed = true
124 }
125 } else {
khenaidood948f772021-08-11 17:49:24 -0400126 if !flowCreated {
Kent Hagerman433a31a2020-05-20 19:04:48 -0400127 flowToReplace = flowHandle.GetReadOnly()
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400128 if (mod.Flags & uint32(ofp.OfpFlowModFlags_OFPFF_RESET_COUNTS)) != 0 {
129 flow.ByteCount = flowToReplace.ByteCount
130 flow.PacketCount = flowToReplace.PacketCount
131 }
132 if !proto.Equal(flowToReplace, flow) {
133 changed = true
134 updated = true
135 }
136 } else {
137 changed = true
138 }
139 }
Rohan Agrawal31f21802020-06-12 05:38:46 +0000140 logger.Debugw(ctx, "flowAdd-changed", log.Fields{"changed": changed, "updated": updated})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400141 if changed {
Kent Hagerman433a31a2020-05-20 19:04:48 -0400142 updatedFlows := map[uint64]*ofp.OfpFlowStats{flow.Id: flow}
143
khenaidoo7585a962021-06-10 16:15:38 -0400144 groupIDs := agent.groupCache.ListIDs()
Kent Hagerman433a31a2020-05-20 19:04:48 -0400145 groups := make(map[uint32]*ofp.OfpGroupEntry, len(groupIDs))
146 for groupID := range groupIDs {
khenaidoo7585a962021-06-10 16:15:38 -0400147 if groupHandle, have := agent.groupCache.Lock(groupID); have {
Kent Hagerman433a31a2020-05-20 19:04:48 -0400148 groups[groupID] = groupHandle.GetReadOnly()
149 groupHandle.Unlock()
150 }
151 }
152
153 deviceRules, err := agent.flowDecomposer.DecomposeRules(ctx, agent, updatedFlows, groups)
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400154 if err != nil {
khenaidood948f772021-08-11 17:49:24 -0400155 if flowCreated {
156 if er := flowHandle.Delete(ctx); er != nil {
157 logger.Errorw(ctx, "deleting-flow-from-cache-failed", log.Fields{"error": er, "flow-id": flow.Id})
158 }
159 }
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400160 return changed, updated, err
161 }
162
khenaidood948f772021-08-11 17:49:24 -0400163 // Verify whether the flow request can proceed, usually to multiple adapters
164 // This is an optimization to address the case where a decomposed set of flows need to
165 // be sent to multiple adapters. One or more adapters may not be ready at this time.
166 // If one adapter is not ready this will result in flows being reverted from the
167 // other adapters, at times continuously as the OF controller will keep sending the
168 // flows until they are successfully added.
169 if err := agent.deviceMgr.canMultipleAdapterRequestProceed(ctx, deviceRules.Keys()); err != nil {
170 logger.Warnw(ctx, "adapters-not-ready", log.Fields{"logical-device-id": agent.logicalDeviceID, "flow-id": flow.Id, "error": err})
171 if flowCreated {
172 if er := flowHandle.Delete(ctx); er != nil {
173 logger.Errorw(ctx, "deleting-flow-from-cache-failed", log.Fields{"error": er, "flow-id": flow.Id})
174 }
175 }
176 return false, false, err
177 }
178
Rohan Agrawal31f21802020-06-12 05:38:46 +0000179 logger.Debugw(ctx, "rules", log.Fields{"rules": deviceRules.String()})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400180 // Update store and cache
181 if updated {
Kent Hagerman433a31a2020-05-20 19:04:48 -0400182 if err := flowHandle.Update(ctx, flow); err != nil {
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400183 return changed, updated, err
184 }
185 }
Gamze Abakafac8c192021-06-28 12:04:32 +0000186 respChannels := agent.addFlowsAndGroupsToDevices(ctx, deviceRules)
Maninderf421da62020-12-04 11:44:58 +0530187
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400188 // Create the go routines to wait
189 go func() {
nikesh.krishnan95142d52023-02-24 15:32:11 +0530190
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400191 // Wait for completion
khenaidood948f772021-08-11 17:49:24 -0400192 if res := coreutils.WaitForNilOrErrorResponses(agent.internalTimeout, respChannels...); res != nil {
ssiddiqui21e54c32021-07-27 11:30:46 +0530193 logger.Errorw(ctx, "failed-to-add-flow-will-attempt-deletion", log.Fields{
Matteo Scandolo45e514a2020-08-05 15:27:10 -0700194 "errors": res,
195 "logical-device-id": agent.logicalDeviceID,
Himani Chawla531af4f2020-09-22 10:42:17 +0530196 "flow": flow,
Matteo Scandolo45e514a2020-08-05 15:27:10 -0700197 "groups": groups,
198 })
Himani Chawlab4c25912020-11-12 17:16:38 +0530199 subCtx := coreutils.WithSpanAndRPCMetadataFromContext(ctx)
200
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400201 // Revert added flows
Gamze Abakafac8c192021-06-28 12:04:32 +0000202 if err := agent.revertAddedFlows(subCtx, mod, flow, flowToReplace, deviceRules); err != nil {
Himani Chawla531af4f2020-09-22 10:42:17 +0530203 logger.Errorw(ctx, "failure-to-delete-flow-after-failed-addition", log.Fields{
Matteo Scandolo45e514a2020-08-05 15:27:10 -0700204 "error": err,
205 "logical-device-id": agent.logicalDeviceID,
Himani Chawla531af4f2020-09-22 10:42:17 +0530206 "flow": flow,
Matteo Scandolo45e514a2020-08-05 15:27:10 -0700207 "groups": groups,
208 })
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400209 }
Maninderf421da62020-12-04 11:44:58 +0530210 // send event
Andrea Campanella4afb2f02021-01-29 09:38:57 +0100211 agent.ldeviceMgr.SendFlowChangeEvent(ctx, agent.logicalDeviceID, res, flowUpdate.Xid, flowUpdate.FlowMod.Cookie)
Himani Chawlab4c25912020-11-12 17:16:38 +0530212 context := make(map[string]string)
213 context["rpc"] = coreutils.GetRPCMetadataFromContext(ctx)
Himani Chawla03510772021-02-17 12:48:49 +0530214 context["flow-id"] = fmt.Sprintf("%v", flow.Id)
215 context["flow-cookie"] = fmt.Sprintf("%v", flowUpdate.FlowMod.Cookie)
216 context["logical-device-id"] = agent.logicalDeviceID
217 if deviceRules != nil {
218 context["device-rules"] = deviceRules.String()
219 }
Himani Chawla606a4f02021-03-23 19:45:58 +0530220 agent.ldeviceMgr.SendRPCEvent(ctx,
Himani Chawlab4c25912020-11-12 17:16:38 +0530221 agent.logicalDeviceID, "failed-to-add-flow", context, "RPC_ERROR_RAISE_EVENT",
Himani Chawla606a4f02021-03-23 19:45:58 +0530222 voltha.EventCategory_COMMUNICATION, nil, time.Now().Unix())
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400223 }
224 }()
225 }
226 return changed, updated, nil
227}
228
229// revertAddedFlows reverts flows after the flowAdd request has failed. All flows corresponding to that flowAdd request
230// will be reverted, both from the logical devices and the devices.
Gamze Abakafac8c192021-06-28 12:04:32 +0000231func (agent *LogicalAgent) revertAddedFlows(ctx context.Context, mod *ofp.OfpFlowMod, addedFlow *ofp.OfpFlowStats, replacedFlow *ofp.OfpFlowStats, deviceRules *fu.DeviceRules) error {
232 logger.Debugw(ctx, "revert-flow-add", log.Fields{"added-flow": addedFlow, "replaced-flow": replacedFlow, "device-rules": deviceRules})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400233
khenaidoo7585a962021-06-10 16:15:38 -0400234 flowHandle, have := agent.flowCache.Lock(addedFlow.Id)
Kent Hagerman433a31a2020-05-20 19:04:48 -0400235 if !have {
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400236 // Not found - do nothing
Girish Kumar3e8ee212020-08-19 17:50:11 +0000237 logger.Debugw(ctx, "flow-not-found", log.Fields{"added-flow": addedFlow})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400238 return nil
239 }
Kent Hagerman433a31a2020-05-20 19:04:48 -0400240 defer flowHandle.Unlock()
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400241
242 if replacedFlow != nil {
Kent Hagerman433a31a2020-05-20 19:04:48 -0400243 if err := flowHandle.Update(ctx, replacedFlow); err != nil {
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400244 return err
245 }
246 } else {
Kent Hagerman433a31a2020-05-20 19:04:48 -0400247 if err := flowHandle.Delete(ctx); err != nil {
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400248 return err
249 }
250 }
Kent Hagerman433a31a2020-05-20 19:04:48 -0400251
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400252 // Revert meters
253 if changedMeterStats := agent.updateFlowCountOfMeterStats(ctx, mod, addedFlow, true); !changedMeterStats {
254 return fmt.Errorf("Unable-to-revert-meterstats-for-flow-%s", strconv.FormatUint(addedFlow.Id, 10))
255 }
256
257 // Update the devices
Gamze Abakafac8c192021-06-28 12:04:32 +0000258 respChnls := agent.deleteFlowsAndGroupsFromDevices(ctx, deviceRules, mod)
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400259
260 // Wait for the responses
nikesh.krishnan95142d52023-02-24 15:32:11 +0530261
262 // Since this action is taken following an add failure, we may also receive a failure for the revert
263 if res := coreutils.WaitForNilOrErrorResponses(agent.internalTimeout, respChnls...); res != nil {
264 logger.Warnw(ctx, "failure-reverting-added-flows", log.Fields{
265 "logical-device-id": agent.logicalDeviceID,
266 "flow-cookie": mod.Cookie,
267 "errors": res,
268 })
269 }
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400270
271 return nil
272}
273
Joey Armstrong393daca2023-07-06 08:47:54 -0400274// flowDelete deletes a flow from the flow table of that logical device
Maninderf421da62020-12-04 11:44:58 +0530275func (agent *LogicalAgent) flowDelete(ctx context.Context, flowUpdate *ofp.FlowTableUpdate) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530276 logger.Debug(ctx, "flow-delete")
Maninderf421da62020-12-04 11:44:58 +0530277 mod := flowUpdate.FlowMod
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400278 if mod == nil {
279 return nil
280 }
281
Kent Hagerman433a31a2020-05-20 19:04:48 -0400282 //build a list of what to delete
283 toDelete := make(map[uint64]*ofp.OfpFlowStats)
284
285 // add perfectly matching entry if exists
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400286 fs, err := fu.FlowStatsEntryFromFlowModMessage(mod)
287 if err != nil {
288 return err
289 }
khenaidoo7585a962021-06-10 16:15:38 -0400290 if handle, have := agent.flowCache.Lock(fs.Id); have {
Kent Hagerman433a31a2020-05-20 19:04:48 -0400291 toDelete[fs.Id] = handle.GetReadOnly()
292 handle.Unlock()
293 }
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400294
Kent Hagerman433a31a2020-05-20 19:04:48 -0400295 // search through all the flows
khenaidoo7585a962021-06-10 16:15:38 -0400296 for flowID := range agent.flowCache.ListIDs() {
297 if flowHandle, have := agent.flowCache.Lock(flowID); have {
Kent Hagerman433a31a2020-05-20 19:04:48 -0400298 if flow := flowHandle.GetReadOnly(); fu.FlowMatchesMod(flow, mod) {
299 toDelete[flow.Id] = flow
300 }
301 flowHandle.Unlock()
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400302 }
303 }
Kent Hagerman433a31a2020-05-20 19:04:48 -0400304
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400305 //Delete the matched flows
306 if len(toDelete) > 0 {
Himani Chawlab4c25912020-11-12 17:16:38 +0530307 logger.Debugw(ctx, "flow-delete", log.Fields{"logical-device-id": agent.logicalDeviceID, "to-delete": len(toDelete)})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400308
Kent Hagerman433a31a2020-05-20 19:04:48 -0400309 for _, flow := range toDelete {
khenaidoo7585a962021-06-10 16:15:38 -0400310 if flowHandle, have := agent.flowCache.Lock(flow.Id); have {
Kent Hagerman433a31a2020-05-20 19:04:48 -0400311 // TODO: Flow should only be updated if meter is updated, and meter should only be updated if flow is updated
312 // currently an error while performing the second operation will leave an inconsistent state in kv.
313 // This should be a single atomic operation down to the kv.
314 if changedMeter := agent.updateFlowCountOfMeterStats(ctx, mod, flowHandle.GetReadOnly(), false); !changedMeter {
315 flowHandle.Unlock()
316 return fmt.Errorf("cannot-delete-flow-%d. Meter-update-failed", flow.Id)
317 }
318 // Update store and cache
319 if err := flowHandle.Delete(ctx); err != nil {
320 flowHandle.Unlock()
321 return fmt.Errorf("cannot-delete-flows-%d. Delete-from-store-failed", flow.Id)
322 }
323 flowHandle.Unlock()
324 // TODO: since this is executed in a loop without also updating meter stats, and error part way through this
325 // operation will leave inconsistent state in the meter stats & flows on the devices.
326 // This & related meter updates should be a single atomic operation down to the kv.
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400327 }
328 }
Kent Hagerman433a31a2020-05-20 19:04:48 -0400329
Kent Hagerman433a31a2020-05-20 19:04:48 -0400330 groups := make(map[uint32]*ofp.OfpGroupEntry)
khenaidoo7585a962021-06-10 16:15:38 -0400331 for groupID := range agent.groupCache.ListIDs() {
332 if groupHandle, have := agent.groupCache.Lock(groupID); have {
Kent Hagerman433a31a2020-05-20 19:04:48 -0400333 groups[groupID] = groupHandle.GetReadOnly()
334 groupHandle.Unlock()
335 }
336 }
337
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400338 var respChnls []coreutils.Response
339 var partialRoute bool
340 var deviceRules *fu.DeviceRules
Kent Hagerman433a31a2020-05-20 19:04:48 -0400341 deviceRules, err = agent.flowDecomposer.DecomposeRules(ctx, agent, toDelete, groups)
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400342 if err != nil {
343 // A no route error means no route exists between the ports specified in the flow. This can happen when the
344 // child device is deleted and a request to delete flows from the parent device is received
345 if !errors.Is(err, route.ErrNoRoute) {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000346 logger.Errorw(ctx, "unexpected-error-received", log.Fields{"flows-to-delete": toDelete, "error": err})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400347 return err
348 }
349 partialRoute = true
350 }
351
khenaidood948f772021-08-11 17:49:24 -0400352 var devicesInFlows []string
353 if deviceRules != nil {
354 devicesInFlows = deviceRules.Keys()
355 } else {
356 devicesInFlows = []string{agent.rootDeviceID}
357 }
358
Elia Battiston509fdc72022-01-04 13:28:09 +0100359 for _, deviceID := range devicesInFlows {
360 if err := agent.deviceMgr.canAdapterRequestProceed(ctx, deviceID); err != nil {
361 //If the error has code.NotFound the device is not there anymore, there is no need to delete flows, just ignore it
362 if status.Code(err) != codes.NotFound {
363 logger.Warnw(ctx, "adapters-not-ready", log.Fields{"logical-device-id": agent.logicalDeviceID, "flow": toDelete, "error": err})
364 return err
365 } else {
366 logger.Debugw(ctx, "flow-delete-for-nil-device-proceeding-deletion", log.Fields{"deviceID": deviceID})
367 if deviceRules != nil {
368 deviceRules.RemoveRule(deviceID)
369 partialRoute = true
370 }
371 }
372 }
khenaidood948f772021-08-11 17:49:24 -0400373 }
374
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400375 // Update the devices
376 if partialRoute {
Gamze Abakafac8c192021-06-28 12:04:32 +0000377 respChnls = agent.deleteFlowsFromParentDevice(ctx, toDelete, mod)
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400378 } else {
Gamze Abakafac8c192021-06-28 12:04:32 +0000379 respChnls = agent.deleteFlowsAndGroupsFromDevices(ctx, deviceRules, mod)
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400380 }
381
382 // Wait for the responses
383 go func() {
384 // Wait for completion
khenaidood948f772021-08-11 17:49:24 -0400385 if res := coreutils.WaitForNilOrErrorResponses(agent.internalTimeout, respChnls...); res != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530386 logger.Errorw(ctx, "failure-updating-device-flows", log.Fields{"logical-device-id": agent.logicalDeviceID, "errors": res})
387 context := make(map[string]string)
388 context["rpc"] = coreutils.GetRPCMetadataFromContext(ctx)
Himani Chawla03510772021-02-17 12:48:49 +0530389 context["logical-device-id"] = agent.logicalDeviceID
390 context["flow-id"] = fmt.Sprintf("%v", fs.Id)
391 context["flow-cookie"] = fmt.Sprintf("%v", flowUpdate.FlowMod.Cookie)
392 if deviceRules != nil {
393 context["device-rules"] = deviceRules.String()
394 }
395
Himani Chawla606a4f02021-03-23 19:45:58 +0530396 agent.ldeviceMgr.SendRPCEvent(ctx,
Himani Chawlab4c25912020-11-12 17:16:38 +0530397 agent.logicalDeviceID, "failed-to-update-device-flows", context, "RPC_ERROR_RAISE_EVENT",
Himani Chawla606a4f02021-03-23 19:45:58 +0530398 voltha.EventCategory_COMMUNICATION, nil, time.Now().Unix())
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400399 // TODO: Revert the flow deletion
Maninderf421da62020-12-04 11:44:58 +0530400 // send event, and allow any queued events to be sent as well
Andrea Campanella4afb2f02021-01-29 09:38:57 +0100401 agent.ldeviceMgr.SendFlowChangeEvent(ctx, agent.logicalDeviceID, res, flowUpdate.Xid, flowUpdate.FlowMod.Cookie)
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400402 }
403 }()
404 }
405 //TODO: send announcement on delete
406 return nil
407}
408
Joey Armstrong393daca2023-07-06 08:47:54 -0400409// flowDeleteStrict deletes a flow from the flow table of that logical device
Maninderf421da62020-12-04 11:44:58 +0530410func (agent *LogicalAgent) flowDeleteStrict(ctx context.Context, flowUpdate *ofp.FlowTableUpdate) error {
khenaidood948f772021-08-11 17:49:24 -0400411 var flowHandle *flow.Handle
412 var have bool
413
Maninderf421da62020-12-04 11:44:58 +0530414 mod := flowUpdate.FlowMod
Himani Chawlab4c25912020-11-12 17:16:38 +0530415 logger.Debugw(ctx, "flow-delete-strict", log.Fields{"mod": mod})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400416 if mod == nil {
417 return nil
418 }
419
420 flow, err := fu.FlowStatsEntryFromFlowModMessage(mod)
421 if err != nil {
422 return err
423 }
khenaidood948f772021-08-11 17:49:24 -0400424
425 defer func() {
426 if flowHandle != nil {
427 flowHandle.Unlock()
428 }
429 }()
430
Himani Chawlab4c25912020-11-12 17:16:38 +0530431 logger.Debugw(ctx, "flow-id-in-flow-delete-strict", log.Fields{"flow-id": flow.Id})
khenaidood948f772021-08-11 17:49:24 -0400432 flowHandle, have = agent.flowCache.Lock(flow.Id)
Kent Hagerman433a31a2020-05-20 19:04:48 -0400433 if !have {
khenaidood948f772021-08-11 17:49:24 -0400434 logger.Debugw(ctx, "flow-delete-strict-request-no-flow-found-continuing", log.Fields{"flow-mod": mod})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400435 }
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400436
Kent Hagerman433a31a2020-05-20 19:04:48 -0400437 groups := make(map[uint32]*ofp.OfpGroupEntry)
khenaidoo7585a962021-06-10 16:15:38 -0400438 for groupID := range agent.groupCache.ListIDs() {
439 if groupHandle, have := agent.groupCache.Lock(groupID); have {
Kent Hagerman433a31a2020-05-20 19:04:48 -0400440 groups[groupID] = groupHandle.GetReadOnly()
441 groupHandle.Unlock()
442 }
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400443 }
Kent Hagerman433a31a2020-05-20 19:04:48 -0400444
khenaidood948f772021-08-11 17:49:24 -0400445 flowsToDelete := map[uint64]*ofp.OfpFlowStats{flow.Id: flow}
446 if flowHandle != nil {
447 flowsToDelete = map[uint64]*ofp.OfpFlowStats{flow.Id: flowHandle.GetReadOnly()}
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400448 }
449
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400450 var respChnls []coreutils.Response
451 var partialRoute bool
Kent Hagerman433a31a2020-05-20 19:04:48 -0400452 deviceRules, err := agent.flowDecomposer.DecomposeRules(ctx, agent, flowsToDelete, groups)
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400453 if err != nil {
454 // A no route error means no route exists between the ports specified in the flow. This can happen when the
455 // child device is deleted and a request to delete flows from the parent device is received
456 if !errors.Is(err, route.ErrNoRoute) {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000457 logger.Errorw(ctx, "unexpected-error-received", log.Fields{"flows-to-delete": flowsToDelete, "error": err})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400458 return err
459 }
460 partialRoute = true
461 }
462
khenaidood948f772021-08-11 17:49:24 -0400463 var devicesInFlows []string
464 if deviceRules != nil {
465 devicesInFlows = deviceRules.Keys()
466 } else {
467 devicesInFlows = []string{agent.rootDeviceID}
468 }
469
Elia Battiston509fdc72022-01-04 13:28:09 +0100470 for _, deviceID := range devicesInFlows {
471 if err := agent.deviceMgr.canAdapterRequestProceed(ctx, deviceID); err != nil {
472 //If the error has code.NotFound the device is not there anymore, there is no need to delete flows, just ignore it
473 if status.Code(err) != codes.NotFound {
474 logger.Warnw(ctx, "adapters-not-ready", log.Fields{"logical-device-id": agent.logicalDeviceID, "flow": flowsToDelete, "error": err})
475 return err
476 } else {
477 logger.Debugw(ctx, "flow-delete-strict-for-nil-device-proceeding-deletion", log.Fields{"deviceID": deviceID})
478 if deviceRules != nil {
479 deviceRules.RemoveRule(deviceID)
480 partialRoute = true
481 }
482 }
483 }
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400484 }
khenaidood948f772021-08-11 17:49:24 -0400485
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400486 // Update the devices
487 if partialRoute {
Gamze Abakafac8c192021-06-28 12:04:32 +0000488 respChnls = agent.deleteFlowsFromParentDevice(ctx, flowsToDelete, mod)
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400489 } else {
Gamze Abakafac8c192021-06-28 12:04:32 +0000490 respChnls = agent.deleteFlowsAndGroupsFromDevices(ctx, deviceRules, mod)
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400491 }
492
493 // Wait for completion
khenaidood948f772021-08-11 17:49:24 -0400494 if res := coreutils.WaitForNilOrErrorResponses(agent.internalTimeout, respChnls...); res != nil {
495 logger.Warnw(ctx, "failure-deleting-device-flows", log.Fields{
496 "flow-cookie": mod.Cookie,
497 "logical-device-id": agent.logicalDeviceID,
498 "errors": res,
499 })
500 context := make(map[string]string)
501 context["rpc"] = coreutils.GetRPCMetadataFromContext(ctx)
502 context["flow-id"] = fmt.Sprintf("%v", flow.Id)
503 context["flow-cookie"] = fmt.Sprintf("%v", flowUpdate.FlowMod.Cookie)
504 context["logical-device-id"] = agent.logicalDeviceID
505 if deviceRules != nil {
506 context["device-rules"] = deviceRules.String()
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400507 }
khenaidood948f772021-08-11 17:49:24 -0400508 // Create context and send extra information as part of it.
509 agent.ldeviceMgr.SendRPCEvent(ctx,
510 agent.logicalDeviceID, "failed-to-delete-device-flows", context, "RPC_ERROR_RAISE_EVENT",
511 voltha.EventCategory_COMMUNICATION, nil, time.Now().Unix())
512
513 return status.Errorf(codes.Aborted, "failed deleting flows id:%d, errors:%v", flow.Id, res)
514 }
515
516 // Update meter count
517 if changedMeter := agent.updateFlowCountOfMeterStats(ctx, mod, flow, false); !changedMeter {
518 return fmt.Errorf("cannot delete flow - %s. Meter update failed", flow)
519 }
520
521 // Update the model
522 if flowHandle != nil {
523 if err := flowHandle.Delete(ctx); err != nil {
524 return err
525 }
526 }
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400527
528 return nil
529}
530
Joey Armstrong393daca2023-07-06 08:47:54 -0400531// flowModify modifies a flow from the flow table of that logical device
Maninderf421da62020-12-04 11:44:58 +0530532func (agent *LogicalAgent) flowModify(flowUpdate *ofp.FlowTableUpdate) error {
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400533 return errors.New("flowModify not implemented")
534}
535
Joey Armstrong393daca2023-07-06 08:47:54 -0400536// flowModifyStrict deletes a flow from the flow table of that logical device
Maninderf421da62020-12-04 11:44:58 +0530537func (agent *LogicalAgent) flowModifyStrict(flowUpdate *ofp.FlowTableUpdate) error {
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400538 return errors.New("flowModifyStrict not implemented")
539}
Kent Hagerman433a31a2020-05-20 19:04:48 -0400540
541// TODO: Remove this helper, just pass the map through to functions directly
khenaidoo9beaaf12021-10-19 17:32:01 -0400542func toMetadata(meters map[uint32]*ofp.OfpMeterConfig) *ofp.FlowMetadata {
Kent Hagerman433a31a2020-05-20 19:04:48 -0400543 ctr, ret := 0, make([]*ofp.OfpMeterConfig, len(meters))
544 for _, meter := range meters {
545 ret[ctr] = meter
546 ctr++
547 }
khenaidoo9beaaf12021-10-19 17:32:01 -0400548 return &ofp.FlowMetadata{Meters: ret}
Kent Hagerman433a31a2020-05-20 19:04:48 -0400549}
550
551func (agent *LogicalAgent) deleteFlowsHavingMeter(ctx context.Context, meterID uint32) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530552 logger.Infow(ctx, "delete-flows-matching-meter", log.Fields{"meter": meterID})
khenaidoo7585a962021-06-10 16:15:38 -0400553 for flowID := range agent.flowCache.ListIDs() {
554 if flowHandle, have := agent.flowCache.Lock(flowID); have {
Kent Hagerman433a31a2020-05-20 19:04:48 -0400555 if flowMeterID := fu.GetMeterIdFromFlow(flowHandle.GetReadOnly()); flowMeterID != 0 && flowMeterID == meterID {
556 if err := flowHandle.Delete(ctx); err != nil {
557 //TODO: Think on carrying on and deleting the remaining flows, instead of returning.
558 //Anyways this returns an error to controller which possibly results with a re-deletion.
559 //Then how can we handle the new deletion request(Same for group deletion)?
560 return err
561 }
562 }
563 flowHandle.Unlock()
564 }
565 }
566 return nil
567}
568
569func (agent *LogicalAgent) deleteFlowsHavingGroup(ctx context.Context, groupID uint32) (map[uint64]*ofp.OfpFlowStats, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530570 logger.Infow(ctx, "delete-flows-matching-group", log.Fields{"group-id": groupID})
Kent Hagerman433a31a2020-05-20 19:04:48 -0400571 flowsRemoved := make(map[uint64]*ofp.OfpFlowStats)
khenaidoo7585a962021-06-10 16:15:38 -0400572 for flowID := range agent.flowCache.ListIDs() {
573 if flowHandle, have := agent.flowCache.Lock(flowID); have {
Kent Hagerman433a31a2020-05-20 19:04:48 -0400574 if flow := flowHandle.GetReadOnly(); fu.FlowHasOutGroup(flow, groupID) {
575 if err := flowHandle.Delete(ctx); err != nil {
576 return nil, err
577 }
578 flowsRemoved[flowID] = flow
579 }
580 flowHandle.Unlock()
581 }
582 }
583 return flowsRemoved, nil
584}