blob: 6e26e429696870648532fa1dce82694a42c6ab88 [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"
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"
27 "github.com/opencord/voltha-go/rw_core/route"
28 coreutils "github.com/opencord/voltha-go/rw_core/utils"
Maninderdfadc982020-10-28 14:04:33 +053029 fu "github.com/opencord/voltha-lib-go/v4/pkg/flows"
30 "github.com/opencord/voltha-lib-go/v4/pkg/log"
31 ofp "github.com/opencord/voltha-protos/v4/go/openflow_13"
32 "github.com/opencord/voltha-protos/v4/go/voltha"
Kent Hagerman3136fbd2020-05-14 10:30:45 -040033 "google.golang.org/grpc/codes"
34 "google.golang.org/grpc/status"
35)
36
Kent Hagerman433a31a2020-05-20 19:04:48 -040037// listLogicalDeviceFlows returns logical device flows
38func (agent *LogicalAgent) listLogicalDeviceFlows() map[uint64]*ofp.OfpFlowStats {
Kent Hagermanfa9d6d42020-05-25 11:49:40 -040039 flowIDs := agent.flowLoader.ListIDs()
Kent Hagerman433a31a2020-05-20 19:04:48 -040040 flows := make(map[uint64]*ofp.OfpFlowStats, len(flowIDs))
41 for flowID := range flowIDs {
42 if flowHandle, have := agent.flowLoader.Lock(flowID); have {
43 flows[flowID] = flowHandle.GetReadOnly()
44 flowHandle.Unlock()
45 }
46 }
47 return flows
48}
49
Kent Hagerman3136fbd2020-05-14 10:30:45 -040050//updateFlowTable updates the flow table of that logical device
Maninderf421da62020-12-04 11:44:58 +053051func (agent *LogicalAgent) updateFlowTable(ctx context.Context, flow *ofp.FlowTableUpdate) error {
Himani Chawlab4c25912020-11-12 17:16:38 +053052 logger.Debug(ctx, "update-flow-table")
Kent Hagerman3136fbd2020-05-14 10:30:45 -040053 if flow == nil {
54 return nil
55 }
56
Maninderf421da62020-12-04 11:44:58 +053057 switch flow.FlowMod.GetCommand() {
Kent Hagerman3136fbd2020-05-14 10:30:45 -040058 case ofp.OfpFlowModCommand_OFPFC_ADD:
59 return agent.flowAdd(ctx, flow)
60 case ofp.OfpFlowModCommand_OFPFC_DELETE:
61 return agent.flowDelete(ctx, flow)
62 case ofp.OfpFlowModCommand_OFPFC_DELETE_STRICT:
63 return agent.flowDeleteStrict(ctx, flow)
64 case ofp.OfpFlowModCommand_OFPFC_MODIFY:
65 return agent.flowModify(flow)
66 case ofp.OfpFlowModCommand_OFPFC_MODIFY_STRICT:
67 return agent.flowModifyStrict(flow)
68 }
69 return status.Errorf(codes.Internal,
Maninderf421da62020-12-04 11:44:58 +053070 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceID, flow.FlowMod.GetCommand())
Kent Hagerman3136fbd2020-05-14 10:30:45 -040071}
72
73//flowAdd adds a flow to the flow table of that logical device
Maninderf421da62020-12-04 11:44:58 +053074func (agent *LogicalAgent) flowAdd(ctx context.Context, flowUpdate *ofp.FlowTableUpdate) error {
75 mod := flowUpdate.FlowMod
Himani Chawlab4c25912020-11-12 17:16:38 +053076 logger.Debugw(ctx, "flow-add", log.Fields{"flow": mod})
Kent Hagerman3136fbd2020-05-14 10:30:45 -040077 if mod == nil {
78 return nil
79 }
80 flow, err := fu.FlowStatsEntryFromFlowModMessage(mod)
81 if err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +053082 logger.Errorw(ctx, "flow-add-failed", log.Fields{"flow-mod": mod, "err": err})
Kent Hagerman3136fbd2020-05-14 10:30:45 -040083 return err
84 }
85 var updated bool
86 var changed bool
Maninderf421da62020-12-04 11:44:58 +053087 if changed, updated, err = agent.decomposeAndAdd(ctx, flow, flowUpdate); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +053088 logger.Errorw(ctx, "flow-decompose-and-add-failed ", log.Fields{"flow-mod": mod, "err": err})
Kent Hagerman3136fbd2020-05-14 10:30:45 -040089 return err
90 }
91 if changed && !updated {
92 if dbupdated := agent.updateFlowCountOfMeterStats(ctx, mod, flow, false); !dbupdated {
93 return fmt.Errorf("couldnt-updated-flow-stats-%s", strconv.FormatUint(flow.Id, 10))
94 }
95 }
96 return nil
97
98}
99
Maninderf421da62020-12-04 11:44:58 +0530100func (agent *LogicalAgent) decomposeAndAdd(ctx context.Context, flow *ofp.OfpFlowStats, flowUpdate *ofp.FlowTableUpdate) (bool, bool, error) {
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400101 changed := false
102 updated := false
Maninderf421da62020-12-04 11:44:58 +0530103 mod := flowUpdate.FlowMod
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400104 var flowToReplace *ofp.OfpFlowStats
105
106 //if flow is not found in the map, create a new entry, otherwise get the existing one.
Kent Hagerman433a31a2020-05-20 19:04:48 -0400107 flowHandle, created, err := agent.flowLoader.LockOrCreate(ctx, flow)
108 if err != nil {
109 return changed, updated, err
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400110 }
Kent Hagerman433a31a2020-05-20 19:04:48 -0400111 defer flowHandle.Unlock()
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400112
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400113 flows := make([]*ofp.OfpFlowStats, 0)
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400114 checkOverlap := (mod.Flags & uint32(ofp.OfpFlowModFlags_OFPFF_CHECK_OVERLAP)) != 0
115 if checkOverlap {
Kent Hagerman433a31a2020-05-20 19:04:48 -0400116 // TODO: this currently does nothing
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400117 if overlapped := fu.FindOverlappingFlows(flows, mod); len(overlapped) != 0 {
Kent Hagerman433a31a2020-05-20 19:04:48 -0400118 // TODO: should this error be notified other than being logged?
Himani Chawlab4c25912020-11-12 17:16:38 +0530119 logger.Warnw(ctx, "overlapped-flows", log.Fields{"logical-device-id": agent.logicalDeviceID})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400120 } else {
121 // Add flow
122 changed = true
123 }
124 } else {
Kent Hagerman433a31a2020-05-20 19:04:48 -0400125 if !created {
126 flowToReplace = flowHandle.GetReadOnly()
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400127 if (mod.Flags & uint32(ofp.OfpFlowModFlags_OFPFF_RESET_COUNTS)) != 0 {
128 flow.ByteCount = flowToReplace.ByteCount
129 flow.PacketCount = flowToReplace.PacketCount
130 }
131 if !proto.Equal(flowToReplace, flow) {
132 changed = true
133 updated = true
134 }
135 } else {
136 changed = true
137 }
138 }
Rohan Agrawal31f21802020-06-12 05:38:46 +0000139 logger.Debugw(ctx, "flowAdd-changed", log.Fields{"changed": changed, "updated": updated})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400140 if changed {
Kent Hagerman433a31a2020-05-20 19:04:48 -0400141 updatedFlows := map[uint64]*ofp.OfpFlowStats{flow.Id: flow}
142
Rohan Agrawal31f21802020-06-12 05:38:46 +0000143 flowMeterConfig, err := agent.GetMeterConfig(ctx, updatedFlows)
Kent Hagerman433a31a2020-05-20 19:04:48 -0400144 if err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530145 logger.Error(ctx, "meter-referred-in-flow-not-present")
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400146 return changed, updated, err
147 }
Kent Hagerman433a31a2020-05-20 19:04:48 -0400148
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400149 groupIDs := agent.groupLoader.ListIDs()
Kent Hagerman433a31a2020-05-20 19:04:48 -0400150 groups := make(map[uint32]*ofp.OfpGroupEntry, len(groupIDs))
151 for groupID := range groupIDs {
152 if groupHandle, have := agent.groupLoader.Lock(groupID); have {
153 groups[groupID] = groupHandle.GetReadOnly()
154 groupHandle.Unlock()
155 }
156 }
157
158 deviceRules, err := agent.flowDecomposer.DecomposeRules(ctx, agent, updatedFlows, groups)
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400159 if err != nil {
160 return changed, updated, err
161 }
162
Rohan Agrawal31f21802020-06-12 05:38:46 +0000163 logger.Debugw(ctx, "rules", log.Fields{"rules": deviceRules.String()})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400164 // Update store and cache
165 if updated {
Kent Hagerman433a31a2020-05-20 19:04:48 -0400166 if err := flowHandle.Update(ctx, flow); err != nil {
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400167 return changed, updated, err
168 }
169 }
Rohan Agrawal31f21802020-06-12 05:38:46 +0000170 respChannels := agent.addFlowsAndGroupsToDevices(ctx, deviceRules, toMetadata(flowMeterConfig))
Maninderf421da62020-12-04 11:44:58 +0530171
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400172 // Create the go routines to wait
173 go func() {
174 // Wait for completion
175 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChannels...); res != nil {
Himani Chawla531af4f2020-09-22 10:42:17 +0530176 logger.Infow(ctx, "failed-to-add-flow-will-attempt-deletion", log.Fields{
Matteo Scandolo45e514a2020-08-05 15:27:10 -0700177 "errors": res,
178 "logical-device-id": agent.logicalDeviceID,
Himani Chawla531af4f2020-09-22 10:42:17 +0530179 "flow": flow,
Matteo Scandolo45e514a2020-08-05 15:27:10 -0700180 "groups": groups,
181 })
Himani Chawlab4c25912020-11-12 17:16:38 +0530182 subCtx := coreutils.WithSpanAndRPCMetadataFromContext(ctx)
183
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400184 // Revert added flows
Himani Chawlab4c25912020-11-12 17:16:38 +0530185 if err := agent.revertAddedFlows(subCtx, mod, flow, flowToReplace, deviceRules, toMetadata(flowMeterConfig)); err != nil {
Himani Chawla531af4f2020-09-22 10:42:17 +0530186 logger.Errorw(ctx, "failure-to-delete-flow-after-failed-addition", log.Fields{
Matteo Scandolo45e514a2020-08-05 15:27:10 -0700187 "error": err,
188 "logical-device-id": agent.logicalDeviceID,
Himani Chawla531af4f2020-09-22 10:42:17 +0530189 "flow": flow,
Matteo Scandolo45e514a2020-08-05 15:27:10 -0700190 "groups": groups,
191 })
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400192 }
Maninderf421da62020-12-04 11:44:58 +0530193 // send event
Andrea Campanella4afb2f02021-01-29 09:38:57 +0100194 agent.ldeviceMgr.SendFlowChangeEvent(ctx, agent.logicalDeviceID, res, flowUpdate.Xid, flowUpdate.FlowMod.Cookie)
Himani Chawlab4c25912020-11-12 17:16:38 +0530195 context := make(map[string]string)
196 context["rpc"] = coreutils.GetRPCMetadataFromContext(ctx)
Himani Chawla03510772021-02-17 12:48:49 +0530197 context["flow-id"] = fmt.Sprintf("%v", flow.Id)
198 context["flow-cookie"] = fmt.Sprintf("%v", flowUpdate.FlowMod.Cookie)
199 context["logical-device-id"] = agent.logicalDeviceID
200 if deviceRules != nil {
201 context["device-rules"] = deviceRules.String()
202 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530203 go agent.ldeviceMgr.SendRPCEvent(ctx,
204 agent.logicalDeviceID, "failed-to-add-flow", context, "RPC_ERROR_RAISE_EVENT",
205 voltha.EventCategory_COMMUNICATION, nil, time.Now().UnixNano())
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400206 }
207 }()
208 }
209 return changed, updated, nil
210}
211
212// revertAddedFlows reverts flows after the flowAdd request has failed. All flows corresponding to that flowAdd request
213// will be reverted, both from the logical devices and the devices.
214func (agent *LogicalAgent) revertAddedFlows(ctx context.Context, mod *ofp.OfpFlowMod, addedFlow *ofp.OfpFlowStats, replacedFlow *ofp.OfpFlowStats, deviceRules *fu.DeviceRules, metadata *voltha.FlowMetadata) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530215 logger.Debugw(ctx, "revert-flow-add", log.Fields{"added-flow": addedFlow, "replaced-flow": replacedFlow, "device-rules": deviceRules, "metadata": metadata})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400216
Kent Hagerman433a31a2020-05-20 19:04:48 -0400217 flowHandle, have := agent.flowLoader.Lock(addedFlow.Id)
218 if !have {
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400219 // Not found - do nothing
Girish Kumar3e8ee212020-08-19 17:50:11 +0000220 logger.Debugw(ctx, "flow-not-found", log.Fields{"added-flow": addedFlow})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400221 return nil
222 }
Kent Hagerman433a31a2020-05-20 19:04:48 -0400223 defer flowHandle.Unlock()
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400224
225 if replacedFlow != nil {
Kent Hagerman433a31a2020-05-20 19:04:48 -0400226 if err := flowHandle.Update(ctx, replacedFlow); err != nil {
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400227 return err
228 }
229 } else {
Kent Hagerman433a31a2020-05-20 19:04:48 -0400230 if err := flowHandle.Delete(ctx); err != nil {
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400231 return err
232 }
233 }
Kent Hagerman433a31a2020-05-20 19:04:48 -0400234
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400235 // Revert meters
236 if changedMeterStats := agent.updateFlowCountOfMeterStats(ctx, mod, addedFlow, true); !changedMeterStats {
237 return fmt.Errorf("Unable-to-revert-meterstats-for-flow-%s", strconv.FormatUint(addedFlow.Id, 10))
238 }
239
240 // Update the devices
Rohan Agrawal31f21802020-06-12 05:38:46 +0000241 respChnls := agent.deleteFlowsAndGroupsFromDevices(ctx, deviceRules, metadata, mod)
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400242
243 // Wait for the responses
244 go func() {
245 // Since this action is taken following an add failure, we may also receive a failure for the revert
246 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000247 logger.Warnw(ctx, "failure-reverting-added-flows", log.Fields{
Matteo Scandolo367162b2020-06-22 15:07:33 -0700248 "logical-device-id": agent.logicalDeviceID,
249 "flow-cookie": mod.Cookie,
250 "errors": res,
251 })
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400252 }
253 }()
254
255 return nil
256}
257
258//flowDelete deletes a flow from the flow table of that logical device
Maninderf421da62020-12-04 11:44:58 +0530259func (agent *LogicalAgent) flowDelete(ctx context.Context, flowUpdate *ofp.FlowTableUpdate) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530260 logger.Debug(ctx, "flow-delete")
Maninderf421da62020-12-04 11:44:58 +0530261 mod := flowUpdate.FlowMod
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400262 if mod == nil {
263 return nil
264 }
265
Kent Hagerman433a31a2020-05-20 19:04:48 -0400266 //build a list of what to delete
267 toDelete := make(map[uint64]*ofp.OfpFlowStats)
268
269 // add perfectly matching entry if exists
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400270 fs, err := fu.FlowStatsEntryFromFlowModMessage(mod)
271 if err != nil {
272 return err
273 }
Kent Hagerman433a31a2020-05-20 19:04:48 -0400274 if handle, have := agent.flowLoader.Lock(fs.Id); have {
275 toDelete[fs.Id] = handle.GetReadOnly()
276 handle.Unlock()
277 }
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400278
Kent Hagerman433a31a2020-05-20 19:04:48 -0400279 // search through all the flows
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400280 for flowID := range agent.flowLoader.ListIDs() {
Kent Hagerman433a31a2020-05-20 19:04:48 -0400281 if flowHandle, have := agent.flowLoader.Lock(flowID); have {
282 if flow := flowHandle.GetReadOnly(); fu.FlowMatchesMod(flow, mod) {
283 toDelete[flow.Id] = flow
284 }
285 flowHandle.Unlock()
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400286 }
287 }
Kent Hagerman433a31a2020-05-20 19:04:48 -0400288
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400289 //Delete the matched flows
290 if len(toDelete) > 0 {
Himani Chawlab4c25912020-11-12 17:16:38 +0530291 logger.Debugw(ctx, "flow-delete", log.Fields{"logical-device-id": agent.logicalDeviceID, "to-delete": len(toDelete)})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400292
Kent Hagerman433a31a2020-05-20 19:04:48 -0400293 for _, flow := range toDelete {
294 if flowHandle, have := agent.flowLoader.Lock(flow.Id); have {
295 // TODO: Flow should only be updated if meter is updated, and meter should only be updated if flow is updated
296 // currently an error while performing the second operation will leave an inconsistent state in kv.
297 // This should be a single atomic operation down to the kv.
298 if changedMeter := agent.updateFlowCountOfMeterStats(ctx, mod, flowHandle.GetReadOnly(), false); !changedMeter {
299 flowHandle.Unlock()
300 return fmt.Errorf("cannot-delete-flow-%d. Meter-update-failed", flow.Id)
301 }
302 // Update store and cache
303 if err := flowHandle.Delete(ctx); err != nil {
304 flowHandle.Unlock()
305 return fmt.Errorf("cannot-delete-flows-%d. Delete-from-store-failed", flow.Id)
306 }
307 flowHandle.Unlock()
308 // TODO: since this is executed in a loop without also updating meter stats, and error part way through this
309 // operation will leave inconsistent state in the meter stats & flows on the devices.
310 // This & related meter updates should be a single atomic operation down to the kv.
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400311 }
312 }
Kent Hagerman433a31a2020-05-20 19:04:48 -0400313
Rohan Agrawal31f21802020-06-12 05:38:46 +0000314 metersConfig, err := agent.GetMeterConfig(ctx, toDelete)
Kent Hagerman433a31a2020-05-20 19:04:48 -0400315 if err != nil { // This should never happen
Himani Chawlab4c25912020-11-12 17:16:38 +0530316 logger.Error(ctx, "meter-referred-in-flows-not-present")
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400317 return err
318 }
Kent Hagerman433a31a2020-05-20 19:04:48 -0400319
320 groups := make(map[uint32]*ofp.OfpGroupEntry)
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400321 for groupID := range agent.groupLoader.ListIDs() {
Kent Hagerman433a31a2020-05-20 19:04:48 -0400322 if groupHandle, have := agent.groupLoader.Lock(groupID); have {
323 groups[groupID] = groupHandle.GetReadOnly()
324 groupHandle.Unlock()
325 }
326 }
327
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400328 var respChnls []coreutils.Response
329 var partialRoute bool
330 var deviceRules *fu.DeviceRules
Kent Hagerman433a31a2020-05-20 19:04:48 -0400331 deviceRules, err = agent.flowDecomposer.DecomposeRules(ctx, agent, toDelete, groups)
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400332 if err != nil {
333 // A no route error means no route exists between the ports specified in the flow. This can happen when the
334 // child device is deleted and a request to delete flows from the parent device is received
335 if !errors.Is(err, route.ErrNoRoute) {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000336 logger.Errorw(ctx, "unexpected-error-received", log.Fields{"flows-to-delete": toDelete, "error": err})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400337 return err
338 }
339 partialRoute = true
340 }
341
342 // Update the devices
343 if partialRoute {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000344 respChnls = agent.deleteFlowsFromParentDevice(ctx, toDelete, toMetadata(metersConfig), mod)
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400345 } else {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000346 respChnls = agent.deleteFlowsAndGroupsFromDevices(ctx, deviceRules, toMetadata(metersConfig), mod)
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400347 }
348
349 // Wait for the responses
350 go func() {
351 // Wait for completion
352 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530353 logger.Errorw(ctx, "failure-updating-device-flows", log.Fields{"logical-device-id": agent.logicalDeviceID, "errors": res})
354 context := make(map[string]string)
355 context["rpc"] = coreutils.GetRPCMetadataFromContext(ctx)
Himani Chawla03510772021-02-17 12:48:49 +0530356 context["logical-device-id"] = agent.logicalDeviceID
357 context["flow-id"] = fmt.Sprintf("%v", fs.Id)
358 context["flow-cookie"] = fmt.Sprintf("%v", flowUpdate.FlowMod.Cookie)
359 if deviceRules != nil {
360 context["device-rules"] = deviceRules.String()
361 }
362
Himani Chawlab4c25912020-11-12 17:16:38 +0530363 go agent.ldeviceMgr.SendRPCEvent(ctx,
364 agent.logicalDeviceID, "failed-to-update-device-flows", context, "RPC_ERROR_RAISE_EVENT",
365 voltha.EventCategory_COMMUNICATION, nil, time.Now().UnixNano())
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400366 // TODO: Revert the flow deletion
Maninderf421da62020-12-04 11:44:58 +0530367 // send event, and allow any queued events to be sent as well
Andrea Campanella4afb2f02021-01-29 09:38:57 +0100368 agent.ldeviceMgr.SendFlowChangeEvent(ctx, agent.logicalDeviceID, res, flowUpdate.Xid, flowUpdate.FlowMod.Cookie)
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400369 }
370 }()
371 }
372 //TODO: send announcement on delete
373 return nil
374}
375
376//flowDeleteStrict deletes a flow from the flow table of that logical device
Maninderf421da62020-12-04 11:44:58 +0530377func (agent *LogicalAgent) flowDeleteStrict(ctx context.Context, flowUpdate *ofp.FlowTableUpdate) error {
378 mod := flowUpdate.FlowMod
Himani Chawlab4c25912020-11-12 17:16:38 +0530379 logger.Debugw(ctx, "flow-delete-strict", log.Fields{"mod": mod})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400380 if mod == nil {
381 return nil
382 }
383
384 flow, err := fu.FlowStatsEntryFromFlowModMessage(mod)
385 if err != nil {
386 return err
387 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530388 logger.Debugw(ctx, "flow-id-in-flow-delete-strict", log.Fields{"flow-id": flow.Id})
Kent Hagerman433a31a2020-05-20 19:04:48 -0400389 flowHandle, have := agent.flowLoader.Lock(flow.Id)
390 if !have {
Himani Chawlab4c25912020-11-12 17:16:38 +0530391 logger.Debugw(ctx, "skipping-flow-delete-strict-request-no-flow-found", log.Fields{"flow-mod": mod})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400392 return nil
393 }
Kent Hagerman433a31a2020-05-20 19:04:48 -0400394 defer flowHandle.Unlock()
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400395
Kent Hagerman433a31a2020-05-20 19:04:48 -0400396 groups := make(map[uint32]*ofp.OfpGroupEntry)
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400397 for groupID := range agent.groupLoader.ListIDs() {
Kent Hagerman433a31a2020-05-20 19:04:48 -0400398 if groupHandle, have := agent.groupLoader.Lock(groupID); have {
399 groups[groupID] = groupHandle.GetReadOnly()
400 groupHandle.Unlock()
401 }
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400402 }
Kent Hagerman433a31a2020-05-20 19:04:48 -0400403
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400404 if changedMeter := agent.updateFlowCountOfMeterStats(ctx, mod, flow, false); !changedMeter {
405 return fmt.Errorf("Cannot delete flow - %s. Meter update failed", flow)
406 }
407
Kent Hagerman433a31a2020-05-20 19:04:48 -0400408 flowsToDelete := map[uint64]*ofp.OfpFlowStats{flow.Id: flowHandle.GetReadOnly()}
409
Rohan Agrawal31f21802020-06-12 05:38:46 +0000410 flowMetadata, err := agent.GetMeterConfig(ctx, flowsToDelete)
Kent Hagerman433a31a2020-05-20 19:04:48 -0400411 if err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000412 logger.Error(ctx, "meter-referred-in-flows-not-present")
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400413 return err
414 }
415 var respChnls []coreutils.Response
416 var partialRoute bool
Kent Hagerman433a31a2020-05-20 19:04:48 -0400417 deviceRules, err := agent.flowDecomposer.DecomposeRules(ctx, agent, flowsToDelete, groups)
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400418 if err != nil {
419 // A no route error means no route exists between the ports specified in the flow. This can happen when the
420 // child device is deleted and a request to delete flows from the parent device is received
421 if !errors.Is(err, route.ErrNoRoute) {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000422 logger.Errorw(ctx, "unexpected-error-received", log.Fields{"flows-to-delete": flowsToDelete, "error": err})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400423 return err
424 }
425 partialRoute = true
426 }
427
428 // Update the model
Kent Hagerman433a31a2020-05-20 19:04:48 -0400429 if err := flowHandle.Delete(ctx); err != nil {
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400430 return err
431 }
432 // Update the devices
433 if partialRoute {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000434 respChnls = agent.deleteFlowsFromParentDevice(ctx, flowsToDelete, toMetadata(flowMetadata), mod)
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400435 } else {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000436 respChnls = agent.deleteFlowsAndGroupsFromDevices(ctx, deviceRules, toMetadata(flowMetadata), mod)
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400437 }
438
439 // Wait for completion
440 go func() {
441 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000442 logger.Warnw(ctx, "failure-deleting-device-flows", log.Fields{
Matteo Scandolo367162b2020-06-22 15:07:33 -0700443 "flow-cookie": mod.Cookie,
444 "logical-device-id": agent.logicalDeviceID,
445 "errors": res,
446 })
Maninderf421da62020-12-04 11:44:58 +0530447 // TODO: Revert flow changes
448 // send event, and allow any queued events to be sent as well
Andrea Campanella4afb2f02021-01-29 09:38:57 +0100449 agent.ldeviceMgr.SendFlowChangeEvent(ctx, agent.logicalDeviceID, res, flowUpdate.Xid, flowUpdate.FlowMod.Cookie)
Himani Chawlab4c25912020-11-12 17:16:38 +0530450 context := make(map[string]string)
451 context["rpc"] = coreutils.GetRPCMetadataFromContext(ctx)
Himani Chawla03510772021-02-17 12:48:49 +0530452 context["flow-id"] = fmt.Sprintf("%v", flow.Id)
453 context["flow-cookie"] = fmt.Sprintf("%v", flowUpdate.FlowMod.Cookie)
454 context["logical-device-id"] = agent.logicalDeviceID
455 if deviceRules != nil {
456 context["device-rules"] = deviceRules.String()
457 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530458 // Create context and send extra information as part of it.
459 go agent.ldeviceMgr.SendRPCEvent(ctx,
460 agent.logicalDeviceID, "failed-to-delete-device-flows", context, "RPC_ERROR_RAISE_EVENT",
461 voltha.EventCategory_COMMUNICATION, nil, time.Now().UnixNano())
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400462 }
463 }()
464
465 return nil
466}
467
468//flowModify modifies a flow from the flow table of that logical device
Maninderf421da62020-12-04 11:44:58 +0530469func (agent *LogicalAgent) flowModify(flowUpdate *ofp.FlowTableUpdate) error {
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400470 return errors.New("flowModify not implemented")
471}
472
473//flowModifyStrict deletes a flow from the flow table of that logical device
Maninderf421da62020-12-04 11:44:58 +0530474func (agent *LogicalAgent) flowModifyStrict(flowUpdate *ofp.FlowTableUpdate) error {
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400475 return errors.New("flowModifyStrict not implemented")
476}
Kent Hagerman433a31a2020-05-20 19:04:48 -0400477
478// TODO: Remove this helper, just pass the map through to functions directly
479func toMetadata(meters map[uint32]*ofp.OfpMeterConfig) *voltha.FlowMetadata {
480 ctr, ret := 0, make([]*ofp.OfpMeterConfig, len(meters))
481 for _, meter := range meters {
482 ret[ctr] = meter
483 ctr++
484 }
485 return &voltha.FlowMetadata{Meters: ret}
486}
487
488func (agent *LogicalAgent) deleteFlowsHavingMeter(ctx context.Context, meterID uint32) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530489 logger.Infow(ctx, "delete-flows-matching-meter", log.Fields{"meter": meterID})
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400490 for flowID := range agent.flowLoader.ListIDs() {
Kent Hagerman433a31a2020-05-20 19:04:48 -0400491 if flowHandle, have := agent.flowLoader.Lock(flowID); have {
492 if flowMeterID := fu.GetMeterIdFromFlow(flowHandle.GetReadOnly()); flowMeterID != 0 && flowMeterID == meterID {
493 if err := flowHandle.Delete(ctx); err != nil {
494 //TODO: Think on carrying on and deleting the remaining flows, instead of returning.
495 //Anyways this returns an error to controller which possibly results with a re-deletion.
496 //Then how can we handle the new deletion request(Same for group deletion)?
497 return err
498 }
499 }
500 flowHandle.Unlock()
501 }
502 }
503 return nil
504}
505
506func (agent *LogicalAgent) deleteFlowsHavingGroup(ctx context.Context, groupID uint32) (map[uint64]*ofp.OfpFlowStats, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530507 logger.Infow(ctx, "delete-flows-matching-group", log.Fields{"group-id": groupID})
Kent Hagerman433a31a2020-05-20 19:04:48 -0400508 flowsRemoved := make(map[uint64]*ofp.OfpFlowStats)
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400509 for flowID := range agent.flowLoader.ListIDs() {
Kent Hagerman433a31a2020-05-20 19:04:48 -0400510 if flowHandle, have := agent.flowLoader.Lock(flowID); have {
511 if flow := flowHandle.GetReadOnly(); fu.FlowHasOutGroup(flow, groupID) {
512 if err := flowHandle.Delete(ctx); err != nil {
513 return nil, err
514 }
515 flowsRemoved[flowID] = flow
516 }
517 flowHandle.Unlock()
518 }
519 }
520 return flowsRemoved, nil
521}