blob: 6c3a2b8d9e7b63cf0fd24d4088687ba1a7cc81d1 [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"
Maninderdfadc982020-10-28 14:04:33 +053028 fu "github.com/opencord/voltha-lib-go/v4/pkg/flows"
29 "github.com/opencord/voltha-lib-go/v4/pkg/log"
30 ofp "github.com/opencord/voltha-protos/v4/go/openflow_13"
31 "github.com/opencord/voltha-protos/v4/go/voltha"
Kent Hagerman3136fbd2020-05-14 10:30:45 -040032 "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
Maninderf421da62020-12-04 11:44:58 +053050func (agent *LogicalAgent) updateFlowTable(ctx context.Context, flow *ofp.FlowTableUpdate) 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
Maninderf421da62020-12-04 11:44:58 +053056 switch flow.FlowMod.GetCommand() {
Kent Hagerman3136fbd2020-05-14 10:30:45 -040057 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,
Maninderf421da62020-12-04 11:44:58 +053069 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceID, flow.FlowMod.GetCommand())
Kent Hagerman3136fbd2020-05-14 10:30:45 -040070}
71
72//flowAdd adds a flow to the flow table of that logical device
Maninderf421da62020-12-04 11:44:58 +053073func (agent *LogicalAgent) flowAdd(ctx context.Context, flowUpdate *ofp.FlowTableUpdate) error {
74 mod := flowUpdate.FlowMod
Rohan Agrawal31f21802020-06-12 05:38:46 +000075 logger.Debugw(ctx, "flowAdd", log.Fields{"flow": mod})
Kent Hagerman3136fbd2020-05-14 10:30:45 -040076 if mod == nil {
77 return nil
78 }
79 flow, err := fu.FlowStatsEntryFromFlowModMessage(mod)
80 if err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +000081 logger.Errorw(ctx, "flowAdd-failed", log.Fields{"flowMod": mod, "err": err})
Kent Hagerman3136fbd2020-05-14 10:30:45 -040082 return err
83 }
84 var updated bool
85 var changed bool
Maninderf421da62020-12-04 11:44:58 +053086 if changed, updated, err = agent.decomposeAndAdd(ctx, flow, flowUpdate); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +000087 logger.Errorw(ctx, "flow-decompose-and-add-failed ", log.Fields{"flowMod": mod, "err": err})
Kent Hagerman3136fbd2020-05-14 10:30:45 -040088 return err
89 }
90 if changed && !updated {
91 if dbupdated := agent.updateFlowCountOfMeterStats(ctx, mod, flow, false); !dbupdated {
92 return fmt.Errorf("couldnt-updated-flow-stats-%s", strconv.FormatUint(flow.Id, 10))
93 }
94 }
95 return nil
96
97}
98
Maninderf421da62020-12-04 11:44:58 +053099func (agent *LogicalAgent) decomposeAndAdd(ctx context.Context, flow *ofp.OfpFlowStats, flowUpdate *ofp.FlowTableUpdate) (bool, bool, error) {
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400100 changed := false
101 updated := false
Maninderf421da62020-12-04 11:44:58 +0530102 mod := flowUpdate.FlowMod
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400103 var flowToReplace *ofp.OfpFlowStats
104
105 //if flow is not found in the map, create a new entry, otherwise get the existing one.
Kent Hagerman433a31a2020-05-20 19:04:48 -0400106 flowHandle, created, err := agent.flowLoader.LockOrCreate(ctx, flow)
107 if err != nil {
108 return changed, updated, err
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400109 }
Kent Hagerman433a31a2020-05-20 19:04:48 -0400110 defer flowHandle.Unlock()
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400111
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400112 flows := make([]*ofp.OfpFlowStats, 0)
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400113 checkOverlap := (mod.Flags & uint32(ofp.OfpFlowModFlags_OFPFF_CHECK_OVERLAP)) != 0
114 if checkOverlap {
Kent Hagerman433a31a2020-05-20 19:04:48 -0400115 // TODO: this currently does nothing
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400116 if overlapped := fu.FindOverlappingFlows(flows, mod); len(overlapped) != 0 {
Kent Hagerman433a31a2020-05-20 19:04:48 -0400117 // TODO: should this error be notified other than being logged?
Rohan Agrawal31f21802020-06-12 05:38:46 +0000118 logger.Warnw(ctx, "overlapped-flows", log.Fields{"logicaldeviceId": agent.logicalDeviceID})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400119 } else {
120 // Add flow
121 changed = true
122 }
123 } else {
Kent Hagerman433a31a2020-05-20 19:04:48 -0400124 if !created {
125 flowToReplace = flowHandle.GetReadOnly()
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400126 if (mod.Flags & uint32(ofp.OfpFlowModFlags_OFPFF_RESET_COUNTS)) != 0 {
127 flow.ByteCount = flowToReplace.ByteCount
128 flow.PacketCount = flowToReplace.PacketCount
129 }
130 if !proto.Equal(flowToReplace, flow) {
131 changed = true
132 updated = true
133 }
134 } else {
135 changed = true
136 }
137 }
Rohan Agrawal31f21802020-06-12 05:38:46 +0000138 logger.Debugw(ctx, "flowAdd-changed", log.Fields{"changed": changed, "updated": updated})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400139 if changed {
Kent Hagerman433a31a2020-05-20 19:04:48 -0400140 updatedFlows := map[uint64]*ofp.OfpFlowStats{flow.Id: flow}
141
Rohan Agrawal31f21802020-06-12 05:38:46 +0000142 flowMeterConfig, err := agent.GetMeterConfig(ctx, updatedFlows)
Kent Hagerman433a31a2020-05-20 19:04:48 -0400143 if err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000144 logger.Error(ctx, "Meter-referred-in-flow-not-present")
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400145 return changed, updated, err
146 }
Kent Hagerman433a31a2020-05-20 19:04:48 -0400147
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400148 groupIDs := agent.groupLoader.ListIDs()
Kent Hagerman433a31a2020-05-20 19:04:48 -0400149 groups := make(map[uint32]*ofp.OfpGroupEntry, len(groupIDs))
150 for groupID := range groupIDs {
151 if groupHandle, have := agent.groupLoader.Lock(groupID); have {
152 groups[groupID] = groupHandle.GetReadOnly()
153 groupHandle.Unlock()
154 }
155 }
156
157 deviceRules, err := agent.flowDecomposer.DecomposeRules(ctx, agent, updatedFlows, groups)
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400158 if err != nil {
159 return changed, updated, err
160 }
161
Rohan Agrawal31f21802020-06-12 05:38:46 +0000162 logger.Debugw(ctx, "rules", log.Fields{"rules": deviceRules.String()})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400163 // Update store and cache
164 if updated {
Kent Hagerman433a31a2020-05-20 19:04:48 -0400165 if err := flowHandle.Update(ctx, flow); err != nil {
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400166 return changed, updated, err
167 }
168 }
Rohan Agrawal31f21802020-06-12 05:38:46 +0000169 respChannels := agent.addFlowsAndGroupsToDevices(ctx, deviceRules, toMetadata(flowMeterConfig))
Maninderf421da62020-12-04 11:44:58 +0530170
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400171 // Create the go routines to wait
172 go func() {
173 // Wait for completion
174 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChannels...); res != nil {
Himani Chawla531af4f2020-09-22 10:42:17 +0530175 logger.Infow(ctx, "failed-to-add-flow-will-attempt-deletion", log.Fields{
Matteo Scandolo45e514a2020-08-05 15:27:10 -0700176 "errors": res,
177 "logical-device-id": agent.logicalDeviceID,
Himani Chawla531af4f2020-09-22 10:42:17 +0530178 "flow": flow,
Matteo Scandolo45e514a2020-08-05 15:27:10 -0700179 "groups": groups,
180 })
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400181 // Revert added flows
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000182 if err := agent.revertAddedFlows(log.WithSpanFromContext(context.Background(), ctx), mod, flow, flowToReplace, deviceRules, toMetadata(flowMeterConfig)); err != nil {
Himani Chawla531af4f2020-09-22 10:42:17 +0530183 logger.Errorw(ctx, "failure-to-delete-flow-after-failed-addition", log.Fields{
Matteo Scandolo45e514a2020-08-05 15:27:10 -0700184 "error": err,
185 "logical-device-id": agent.logicalDeviceID,
Himani Chawla531af4f2020-09-22 10:42:17 +0530186 "flow": flow,
Matteo Scandolo45e514a2020-08-05 15:27:10 -0700187 "groups": groups,
188 })
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400189 }
Maninderf421da62020-12-04 11:44:58 +0530190 // send event
191 agent.ldeviceMgr.SendFlowChangeEvent(ctx, agent.logicalDeviceID, res, flowUpdate.Xid)
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400192 }
193 }()
194 }
195 return changed, updated, nil
196}
197
198// revertAddedFlows reverts flows after the flowAdd request has failed. All flows corresponding to that flowAdd request
199// will be reverted, both from the logical devices and the devices.
200func (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 +0000201 logger.Debugw(ctx, "revertFlowAdd", log.Fields{"added-flow": addedFlow, "replaced-flow": replacedFlow, "device-rules": deviceRules, "metadata": metadata})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400202
Kent Hagerman433a31a2020-05-20 19:04:48 -0400203 flowHandle, have := agent.flowLoader.Lock(addedFlow.Id)
204 if !have {
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400205 // Not found - do nothing
Girish Kumar3e8ee212020-08-19 17:50:11 +0000206 logger.Debugw(ctx, "flow-not-found", log.Fields{"added-flow": addedFlow})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400207 return nil
208 }
Kent Hagerman433a31a2020-05-20 19:04:48 -0400209 defer flowHandle.Unlock()
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400210
211 if replacedFlow != nil {
Kent Hagerman433a31a2020-05-20 19:04:48 -0400212 if err := flowHandle.Update(ctx, replacedFlow); err != nil {
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400213 return err
214 }
215 } else {
Kent Hagerman433a31a2020-05-20 19:04:48 -0400216 if err := flowHandle.Delete(ctx); err != nil {
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400217 return err
218 }
219 }
Kent Hagerman433a31a2020-05-20 19:04:48 -0400220
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400221 // Revert meters
222 if changedMeterStats := agent.updateFlowCountOfMeterStats(ctx, mod, addedFlow, true); !changedMeterStats {
223 return fmt.Errorf("Unable-to-revert-meterstats-for-flow-%s", strconv.FormatUint(addedFlow.Id, 10))
224 }
225
226 // Update the devices
Rohan Agrawal31f21802020-06-12 05:38:46 +0000227 respChnls := agent.deleteFlowsAndGroupsFromDevices(ctx, deviceRules, metadata, mod)
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400228
229 // Wait for the responses
230 go func() {
231 // Since this action is taken following an add failure, we may also receive a failure for the revert
232 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000233 logger.Warnw(ctx, "failure-reverting-added-flows", log.Fields{
Matteo Scandolo367162b2020-06-22 15:07:33 -0700234 "logical-device-id": agent.logicalDeviceID,
235 "flow-cookie": mod.Cookie,
236 "errors": res,
237 })
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400238 }
239 }()
240
241 return nil
242}
243
244//flowDelete deletes a flow from the flow table of that logical device
Maninderf421da62020-12-04 11:44:58 +0530245func (agent *LogicalAgent) flowDelete(ctx context.Context, flowUpdate *ofp.FlowTableUpdate) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000246 logger.Debug(ctx, "flowDelete")
Maninderf421da62020-12-04 11:44:58 +0530247 mod := flowUpdate.FlowMod
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400248 if mod == nil {
249 return nil
250 }
251
Kent Hagerman433a31a2020-05-20 19:04:48 -0400252 //build a list of what to delete
253 toDelete := make(map[uint64]*ofp.OfpFlowStats)
254
255 // add perfectly matching entry if exists
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400256 fs, err := fu.FlowStatsEntryFromFlowModMessage(mod)
257 if err != nil {
258 return err
259 }
Kent Hagerman433a31a2020-05-20 19:04:48 -0400260 if handle, have := agent.flowLoader.Lock(fs.Id); have {
261 toDelete[fs.Id] = handle.GetReadOnly()
262 handle.Unlock()
263 }
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400264
Kent Hagerman433a31a2020-05-20 19:04:48 -0400265 // search through all the flows
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400266 for flowID := range agent.flowLoader.ListIDs() {
Kent Hagerman433a31a2020-05-20 19:04:48 -0400267 if flowHandle, have := agent.flowLoader.Lock(flowID); have {
268 if flow := flowHandle.GetReadOnly(); fu.FlowMatchesMod(flow, mod) {
269 toDelete[flow.Id] = flow
270 }
271 flowHandle.Unlock()
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400272 }
273 }
Kent Hagerman433a31a2020-05-20 19:04:48 -0400274
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400275 //Delete the matched flows
276 if len(toDelete) > 0 {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000277 logger.Debugw(ctx, "flowDelete", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "toDelete": len(toDelete)})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400278
Kent Hagerman433a31a2020-05-20 19:04:48 -0400279 for _, flow := range toDelete {
280 if flowHandle, have := agent.flowLoader.Lock(flow.Id); have {
281 // TODO: Flow should only be updated if meter is updated, and meter should only be updated if flow is updated
282 // currently an error while performing the second operation will leave an inconsistent state in kv.
283 // This should be a single atomic operation down to the kv.
284 if changedMeter := agent.updateFlowCountOfMeterStats(ctx, mod, flowHandle.GetReadOnly(), false); !changedMeter {
285 flowHandle.Unlock()
286 return fmt.Errorf("cannot-delete-flow-%d. Meter-update-failed", flow.Id)
287 }
288 // Update store and cache
289 if err := flowHandle.Delete(ctx); err != nil {
290 flowHandle.Unlock()
291 return fmt.Errorf("cannot-delete-flows-%d. Delete-from-store-failed", flow.Id)
292 }
293 flowHandle.Unlock()
294 // TODO: since this is executed in a loop without also updating meter stats, and error part way through this
295 // operation will leave inconsistent state in the meter stats & flows on the devices.
296 // This & related meter updates should be a single atomic operation down to the kv.
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400297 }
298 }
Kent Hagerman433a31a2020-05-20 19:04:48 -0400299
Rohan Agrawal31f21802020-06-12 05:38:46 +0000300 metersConfig, err := agent.GetMeterConfig(ctx, toDelete)
Kent Hagerman433a31a2020-05-20 19:04:48 -0400301 if err != nil { // This should never happen
Rohan Agrawal31f21802020-06-12 05:38:46 +0000302 logger.Error(ctx, "Meter-referred-in-flows-not-present")
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400303 return err
304 }
Kent Hagerman433a31a2020-05-20 19:04:48 -0400305
306 groups := make(map[uint32]*ofp.OfpGroupEntry)
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400307 for groupID := range agent.groupLoader.ListIDs() {
Kent Hagerman433a31a2020-05-20 19:04:48 -0400308 if groupHandle, have := agent.groupLoader.Lock(groupID); have {
309 groups[groupID] = groupHandle.GetReadOnly()
310 groupHandle.Unlock()
311 }
312 }
313
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400314 var respChnls []coreutils.Response
315 var partialRoute bool
316 var deviceRules *fu.DeviceRules
Kent Hagerman433a31a2020-05-20 19:04:48 -0400317 deviceRules, err = agent.flowDecomposer.DecomposeRules(ctx, agent, toDelete, groups)
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400318 if err != nil {
319 // A no route error means no route exists between the ports specified in the flow. This can happen when the
320 // child device is deleted and a request to delete flows from the parent device is received
321 if !errors.Is(err, route.ErrNoRoute) {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000322 logger.Errorw(ctx, "unexpected-error-received", log.Fields{"flows-to-delete": toDelete, "error": err})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400323 return err
324 }
325 partialRoute = true
326 }
327
328 // Update the devices
329 if partialRoute {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000330 respChnls = agent.deleteFlowsFromParentDevice(ctx, toDelete, toMetadata(metersConfig), mod)
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400331 } else {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000332 respChnls = agent.deleteFlowsAndGroupsFromDevices(ctx, deviceRules, toMetadata(metersConfig), mod)
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400333 }
334
335 // Wait for the responses
336 go func() {
337 // Wait for completion
338 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000339 logger.Errorw(ctx, "failure-updating-device-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "errors": res})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400340 // TODO: Revert the flow deletion
Maninderf421da62020-12-04 11:44:58 +0530341 // send event, and allow any queued events to be sent as well
342 agent.ldeviceMgr.SendFlowChangeEvent(ctx, agent.logicalDeviceID, res, flowUpdate.Xid)
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400343 }
344 }()
345 }
346 //TODO: send announcement on delete
347 return nil
348}
349
350//flowDeleteStrict deletes a flow from the flow table of that logical device
Maninderf421da62020-12-04 11:44:58 +0530351func (agent *LogicalAgent) flowDeleteStrict(ctx context.Context, flowUpdate *ofp.FlowTableUpdate) error {
352 mod := flowUpdate.FlowMod
Rohan Agrawal31f21802020-06-12 05:38:46 +0000353 logger.Debugw(ctx, "flowDeleteStrict", log.Fields{"mod": mod})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400354 if mod == nil {
355 return nil
356 }
357
358 flow, err := fu.FlowStatsEntryFromFlowModMessage(mod)
359 if err != nil {
360 return err
361 }
Rohan Agrawal31f21802020-06-12 05:38:46 +0000362 logger.Debugw(ctx, "flow-id-in-flow-delete-strict", log.Fields{"flowID": flow.Id})
Kent Hagerman433a31a2020-05-20 19:04:48 -0400363 flowHandle, have := agent.flowLoader.Lock(flow.Id)
364 if !have {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000365 logger.Debugw(ctx, "Skipping-flow-delete-strict-request. No-flow-found", log.Fields{"flowMod": mod})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400366 return nil
367 }
Kent Hagerman433a31a2020-05-20 19:04:48 -0400368 defer flowHandle.Unlock()
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400369
Kent Hagerman433a31a2020-05-20 19:04:48 -0400370 groups := make(map[uint32]*ofp.OfpGroupEntry)
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400371 for groupID := range agent.groupLoader.ListIDs() {
Kent Hagerman433a31a2020-05-20 19:04:48 -0400372 if groupHandle, have := agent.groupLoader.Lock(groupID); have {
373 groups[groupID] = groupHandle.GetReadOnly()
374 groupHandle.Unlock()
375 }
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400376 }
Kent Hagerman433a31a2020-05-20 19:04:48 -0400377
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400378 if changedMeter := agent.updateFlowCountOfMeterStats(ctx, mod, flow, false); !changedMeter {
379 return fmt.Errorf("Cannot delete flow - %s. Meter update failed", flow)
380 }
381
Kent Hagerman433a31a2020-05-20 19:04:48 -0400382 flowsToDelete := map[uint64]*ofp.OfpFlowStats{flow.Id: flowHandle.GetReadOnly()}
383
Rohan Agrawal31f21802020-06-12 05:38:46 +0000384 flowMetadata, err := agent.GetMeterConfig(ctx, flowsToDelete)
Kent Hagerman433a31a2020-05-20 19:04:48 -0400385 if err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000386 logger.Error(ctx, "meter-referred-in-flows-not-present")
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400387 return err
388 }
389 var respChnls []coreutils.Response
390 var partialRoute bool
Kent Hagerman433a31a2020-05-20 19:04:48 -0400391 deviceRules, err := agent.flowDecomposer.DecomposeRules(ctx, agent, flowsToDelete, groups)
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400392 if err != nil {
393 // A no route error means no route exists between the ports specified in the flow. This can happen when the
394 // child device is deleted and a request to delete flows from the parent device is received
395 if !errors.Is(err, route.ErrNoRoute) {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000396 logger.Errorw(ctx, "unexpected-error-received", log.Fields{"flows-to-delete": flowsToDelete, "error": err})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400397 return err
398 }
399 partialRoute = true
400 }
401
402 // Update the model
Kent Hagerman433a31a2020-05-20 19:04:48 -0400403 if err := flowHandle.Delete(ctx); err != nil {
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400404 return err
405 }
406 // Update the devices
407 if partialRoute {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000408 respChnls = agent.deleteFlowsFromParentDevice(ctx, flowsToDelete, toMetadata(flowMetadata), mod)
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400409 } else {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000410 respChnls = agent.deleteFlowsAndGroupsFromDevices(ctx, deviceRules, toMetadata(flowMetadata), mod)
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400411 }
412
413 // Wait for completion
414 go func() {
415 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000416 logger.Warnw(ctx, "failure-deleting-device-flows", log.Fields{
Matteo Scandolo367162b2020-06-22 15:07:33 -0700417 "flow-cookie": mod.Cookie,
418 "logical-device-id": agent.logicalDeviceID,
419 "errors": res,
420 })
Maninderf421da62020-12-04 11:44:58 +0530421 // TODO: Revert flow changes
422 // send event, and allow any queued events to be sent as well
423 agent.ldeviceMgr.SendFlowChangeEvent(ctx, agent.logicalDeviceID, res, flowUpdate.Xid)
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400424 }
425 }()
426
427 return nil
428}
429
430//flowModify modifies a flow from the flow table of that logical device
Maninderf421da62020-12-04 11:44:58 +0530431func (agent *LogicalAgent) flowModify(flowUpdate *ofp.FlowTableUpdate) error {
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400432 return errors.New("flowModify not implemented")
433}
434
435//flowModifyStrict deletes a flow from the flow table of that logical device
Maninderf421da62020-12-04 11:44:58 +0530436func (agent *LogicalAgent) flowModifyStrict(flowUpdate *ofp.FlowTableUpdate) error {
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400437 return errors.New("flowModifyStrict not implemented")
438}
Kent Hagerman433a31a2020-05-20 19:04:48 -0400439
440// TODO: Remove this helper, just pass the map through to functions directly
441func toMetadata(meters map[uint32]*ofp.OfpMeterConfig) *voltha.FlowMetadata {
442 ctr, ret := 0, make([]*ofp.OfpMeterConfig, len(meters))
443 for _, meter := range meters {
444 ret[ctr] = meter
445 ctr++
446 }
447 return &voltha.FlowMetadata{Meters: ret}
448}
449
450func (agent *LogicalAgent) deleteFlowsHavingMeter(ctx context.Context, meterID uint32) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000451 logger.Infow(ctx, "Delete-flows-matching-meter", log.Fields{"meter": meterID})
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400452 for flowID := range agent.flowLoader.ListIDs() {
Kent Hagerman433a31a2020-05-20 19:04:48 -0400453 if flowHandle, have := agent.flowLoader.Lock(flowID); have {
454 if flowMeterID := fu.GetMeterIdFromFlow(flowHandle.GetReadOnly()); flowMeterID != 0 && flowMeterID == meterID {
455 if err := flowHandle.Delete(ctx); err != nil {
456 //TODO: Think on carrying on and deleting the remaining flows, instead of returning.
457 //Anyways this returns an error to controller which possibly results with a re-deletion.
458 //Then how can we handle the new deletion request(Same for group deletion)?
459 return err
460 }
461 }
462 flowHandle.Unlock()
463 }
464 }
465 return nil
466}
467
468func (agent *LogicalAgent) deleteFlowsHavingGroup(ctx context.Context, groupID uint32) (map[uint64]*ofp.OfpFlowStats, error) {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000469 logger.Infow(ctx, "Delete-flows-matching-group", log.Fields{"groupID": groupID})
Kent Hagerman433a31a2020-05-20 19:04:48 -0400470 flowsRemoved := make(map[uint64]*ofp.OfpFlowStats)
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400471 for flowID := range agent.flowLoader.ListIDs() {
Kent Hagerman433a31a2020-05-20 19:04:48 -0400472 if flowHandle, have := agent.flowLoader.Lock(flowID); have {
473 if flow := flowHandle.GetReadOnly(); fu.FlowHasOutGroup(flow, groupID) {
474 if err := flowHandle.Delete(ctx); err != nil {
475 return nil, err
476 }
477 flowsRemoved[flowID] = flow
478 }
479 flowHandle.Unlock()
480 }
481 }
482 return flowsRemoved, nil
483}