blob: 245c758a17b11217aa2172bbcf5a0a5f919fd549 [file] [log] [blame]
Mahir Gunyel03de0d32020-06-03 01:36:59 -07001/*
Joey Armstrong5f51f2e2023-01-17 17:06:26 -05002 * Copyright 2018-2023 Open Networking Foundation (ONF) and the ONF Contributors
Mahir Gunyel03de0d32020-06-03 01:36:59 -07003
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 (
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070020 "context"
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070021
22 "github.com/gogo/protobuf/proto"
23 coreutils "github.com/opencord/voltha-go/rw_core/utils"
khenaidood948f772021-08-11 17:49:24 -040024 "github.com/opencord/voltha-lib-go/v7/pkg/log"
25 "github.com/opencord/voltha-protos/v5/go/common"
26 ofp "github.com/opencord/voltha-protos/v5/go/openflow_13"
27 "github.com/opencord/voltha-protos/v5/go/voltha"
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070028 "google.golang.org/grpc/codes"
29 "google.golang.org/grpc/status"
Mahir Gunyel03de0d32020-06-03 01:36:59 -070030)
31
32// listDeviceGroups returns logical device flow groups
33func (agent *Agent) listDeviceGroups() map[uint32]*ofp.OfpGroupEntry {
khenaidoo7585a962021-06-10 16:15:38 -040034 groupIDs := agent.groupCache.ListIDs()
Mahir Gunyel03de0d32020-06-03 01:36:59 -070035 groups := make(map[uint32]*ofp.OfpGroupEntry, len(groupIDs))
36 for groupID := range groupIDs {
khenaidoo7585a962021-06-10 16:15:38 -040037 if groupHandle, have := agent.groupCache.Lock(groupID); have {
Mahir Gunyel03de0d32020-06-03 01:36:59 -070038 groups[groupID] = groupHandle.GetReadOnly()
39 groupHandle.Unlock()
40 }
41 }
42 return groups
43}
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070044
khenaidoo9beaaf12021-10-19 17:32:01 -040045func (agent *Agent) addGroupsToAdapter(ctx context.Context, newGroups []*ofp.OfpGroupEntry, flowMetadata *ofp.FlowMetadata) (coreutils.Response, error) {
Rohan Agrawal31f21802020-06-12 05:38:46 +000046 logger.Debugw(ctx, "add-groups-to-adapters", log.Fields{"device-id": agent.deviceID, "groups": newGroups, "flow-metadata": flowMetadata})
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070047
khenaidood948f772021-08-11 17:49:24 -040048 var err error
Maninder9a1bc0d2020-10-26 11:34:02 +053049 var desc string
50 operStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
khenaidood948f772021-08-11 17:49:24 -040051 defer func() { agent.logDeviceUpdate(ctx, nil, nil, operStatus, err, desc) }()
Maninder9a1bc0d2020-10-26 11:34:02 +053052
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070053 if (len(newGroups)) == 0 {
khenaidood948f772021-08-11 17:49:24 -040054 desc = "no new groups"
55 operStatus.Code = common.OperationResp_OPERATION_SUCCESS
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070056 return coreutils.DoneResponse(), nil
57 }
58
Kent Hagermancba2f302020-07-28 13:37:36 -040059 device, err := agent.getDeviceReadOnly(ctx)
60 if err != nil {
khenaidood948f772021-08-11 17:49:24 -040061 return coreutils.DoneResponse(), err
Kent Hagermancba2f302020-07-28 13:37:36 -040062 }
Maninder2195ccc2021-06-23 20:23:01 +053063
64 if !agent.proceedWithRequest(device) {
khenaidood948f772021-08-11 17:49:24 -040065 err = status.Errorf(codes.FailedPrecondition, "%s", "cannot complete operation as device deletion is in progress or reconciling is in progress/failed")
66 return coreutils.DoneResponse(), err
Maninder2195ccc2021-06-23 20:23:01 +053067 }
68
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070069 dType, err := agent.adapterMgr.GetDeviceType(ctx, &voltha.ID{Id: device.Type})
70 if err != nil {
khenaidood948f772021-08-11 17:49:24 -040071 return coreutils.DoneResponse(), err
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070072 }
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070073
74 groupsToAdd := make([]*ofp.OfpGroupEntry, 0)
75 groupsToDelete := make([]*ofp.OfpGroupEntry, 0)
76 for _, group := range newGroups {
khenaidoo7585a962021-06-10 16:15:38 -040077 groupHandle, created, err := agent.groupCache.LockOrCreate(ctx, group)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070078 if err != nil {
79 return coreutils.DoneResponse(), err
80 }
81
82 if created {
83 groupsToAdd = append(groupsToAdd, group)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070084 } else {
85 groupToChange := groupHandle.GetReadOnly()
86 if !proto.Equal(groupToChange, group) {
87 //Group needs to be updated.
khenaidood948f772021-08-11 17:49:24 -040088 if err = groupHandle.Update(ctx, group); err != nil {
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070089 groupHandle.Unlock()
khenaidood948f772021-08-11 17:49:24 -040090 return coreutils.DoneResponse(), err
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070091 }
92 groupsToDelete = append(groupsToDelete, groupToChange)
93 groupsToAdd = append(groupsToAdd, group)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070094 } else {
95 //No need to change the group. It is already exist.
Himani Chawlab4c25912020-11-12 17:16:38 +053096 logger.Debugw(ctx, "no-need-to-change-already-existing-group", log.Fields{"device-id": agent.deviceID, "group": newGroups, "flow-metadata": flowMetadata})
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070097 }
98 }
99
100 groupHandle.Unlock()
101 }
102 // Sanity check
103 if (len(groupsToAdd)) == 0 {
khenaidood948f772021-08-11 17:49:24 -0400104 desc = "no group to update"
105 operStatus.Code = common.OperationResp_OPERATION_SUCCESS
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700106 return coreutils.DoneResponse(), nil
107 }
108
109 // Send update to adapters
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700110 response := coreutils.NewResponse()
khenaidood948f772021-08-11 17:49:24 -0400111 subCtx := coreutils.WithSpanAndRPCMetadataFromContext(ctx)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700112 if !dType.AcceptsAddRemoveFlowUpdates {
Kent Hagermana7c9d792020-07-16 17:39:01 -0400113 updatedAllGroups := agent.listDeviceGroups()
khenaidood948f772021-08-11 17:49:24 -0400114 ctr, groupSlice := 0, make([]*ofp.OfpGroupEntry, len(updatedAllGroups))
115 for _, group := range updatedAllGroups {
116 groupSlice[ctr] = group
117 ctr++
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700118 }
khenaidoo9beaaf12021-10-19 17:32:01 -0400119 go agent.sendBulkFlows(subCtx, device, nil, &ofp.FlowGroups{Items: groupSlice}, flowMetadata, response)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700120 } else {
121 flowChanges := &ofp.FlowChanges{
khenaidoo9beaaf12021-10-19 17:32:01 -0400122 ToAdd: &ofp.Flows{Items: []*ofp.OfpFlowStats{}},
123 ToRemove: &ofp.Flows{Items: []*ofp.OfpFlowStats{}},
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700124 }
125 groupChanges := &ofp.FlowGroupChanges{
khenaidoo9beaaf12021-10-19 17:32:01 -0400126 ToAdd: &ofp.FlowGroups{Items: groupsToAdd},
127 ToRemove: &ofp.FlowGroups{Items: groupsToDelete},
128 ToUpdate: &ofp.FlowGroups{Items: []*ofp.OfpGroupEntry{}},
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700129 }
khenaidood948f772021-08-11 17:49:24 -0400130 go agent.sendIncrementalFlows(subCtx, device, flowChanges, groupChanges, flowMetadata, response)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700131 }
Maninder9a1bc0d2020-10-26 11:34:02 +0530132 operStatus.Code = common.OperationResp_OPERATION_IN_PROGRESS
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700133 return response, nil
134}
135
khenaidoo9beaaf12021-10-19 17:32:01 -0400136func (agent *Agent) deleteGroupsFromAdapter(ctx context.Context, groupsToDel []*ofp.OfpGroupEntry, flowMetadata *ofp.FlowMetadata) (coreutils.Response, error) {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000137 logger.Debugw(ctx, "delete-groups-from-adapter", log.Fields{"device-id": agent.deviceID, "groups": groupsToDel})
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700138
khenaidood948f772021-08-11 17:49:24 -0400139 var desc string
140 var err error
141 operStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
142 defer func() { agent.logDeviceUpdate(ctx, nil, nil, operStatus, err, desc) }()
143
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700144 if (len(groupsToDel)) == 0 {
khenaidood948f772021-08-11 17:49:24 -0400145 desc = "nothing to delete"
146 operStatus.Code = common.OperationResp_OPERATION_SUCCESS
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700147 return coreutils.DoneResponse(), nil
148 }
Maninder9a1bc0d2020-10-26 11:34:02 +0530149
Kent Hagermancba2f302020-07-28 13:37:36 -0400150 device, err := agent.getDeviceReadOnly(ctx)
151 if err != nil {
khenaidood948f772021-08-11 17:49:24 -0400152 return coreutils.DoneResponse(), err
Kent Hagermancba2f302020-07-28 13:37:36 -0400153 }
Maninder2195ccc2021-06-23 20:23:01 +0530154
155 if !agent.proceedWithRequest(device) {
khenaidood948f772021-08-11 17:49:24 -0400156 err = status.Errorf(codes.FailedPrecondition, "%s", "cannot complete operation as device deletion is in progress or reconciling is in progress/failed")
157 return coreutils.DoneResponse(), err
Maninder2195ccc2021-06-23 20:23:01 +0530158 }
159
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700160 dType, err := agent.adapterMgr.GetDeviceType(ctx, &voltha.ID{Id: device.Type})
161 if err != nil {
khenaidood948f772021-08-11 17:49:24 -0400162 return coreutils.DoneResponse(), err
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700163 }
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700164
165 for _, group := range groupsToDel {
khenaidoo7585a962021-06-10 16:15:38 -0400166 if groupHandle, have := agent.groupCache.Lock(group.Desc.GroupId); have {
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700167 // Update the store and cache
khenaidood948f772021-08-11 17:49:24 -0400168 if err = groupHandle.Delete(ctx); err != nil {
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700169 groupHandle.Unlock()
170 return coreutils.DoneResponse(), err
171 }
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700172 groupHandle.Unlock()
173 }
174 }
175
176 // Send update to adapters
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700177 response := coreutils.NewResponse()
khenaidood948f772021-08-11 17:49:24 -0400178 subCtx := coreutils.WithSpanAndRPCMetadataFromContext(ctx)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700179 if !dType.AcceptsAddRemoveFlowUpdates {
Kent Hagermana7c9d792020-07-16 17:39:01 -0400180 updatedAllGroups := agent.listDeviceGroups()
khenaidood948f772021-08-11 17:49:24 -0400181 ctr, groupSlice := 0, make([]*ofp.OfpGroupEntry, len(updatedAllGroups))
182 for _, group := range updatedAllGroups {
183 groupSlice[ctr] = group
184 ctr++
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700185 }
khenaidoo9beaaf12021-10-19 17:32:01 -0400186 go agent.sendBulkFlows(subCtx, device, nil, &ofp.FlowGroups{Items: groupSlice}, flowMetadata, response)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700187 } else {
188 flowChanges := &ofp.FlowChanges{
khenaidoo9beaaf12021-10-19 17:32:01 -0400189 ToAdd: &ofp.Flows{Items: []*ofp.OfpFlowStats{}},
190 ToRemove: &ofp.Flows{Items: []*ofp.OfpFlowStats{}},
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700191 }
192 groupChanges := &ofp.FlowGroupChanges{
khenaidoo9beaaf12021-10-19 17:32:01 -0400193 ToAdd: &ofp.FlowGroups{Items: []*ofp.OfpGroupEntry{}},
194 ToRemove: &ofp.FlowGroups{Items: groupsToDel},
195 ToUpdate: &ofp.FlowGroups{Items: []*ofp.OfpGroupEntry{}},
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700196 }
khenaidood948f772021-08-11 17:49:24 -0400197 go agent.sendIncrementalFlows(subCtx, device, flowChanges, groupChanges, flowMetadata, response)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700198 }
Maninder9a1bc0d2020-10-26 11:34:02 +0530199 operStatus.Code = common.OperationResp_OPERATION_IN_PROGRESS
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700200 return response, nil
201}
202
khenaidoo9beaaf12021-10-19 17:32:01 -0400203func (agent *Agent) updateGroupsToAdapter(ctx context.Context, updatedGroups []*ofp.OfpGroupEntry, flowMetadata *ofp.FlowMetadata) (coreutils.Response, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530204 logger.Debugw(ctx, "update-groups-to-adapter", log.Fields{"device-id": agent.deviceID, "groups": updatedGroups})
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700205
Maninder9a1bc0d2020-10-26 11:34:02 +0530206 var desc string
khenaidood948f772021-08-11 17:49:24 -0400207 var err error
Maninder9a1bc0d2020-10-26 11:34:02 +0530208 operStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
khenaidood948f772021-08-11 17:49:24 -0400209 defer func() { agent.logDeviceUpdate(ctx, nil, nil, operStatus, err, desc) }()
Maninder9a1bc0d2020-10-26 11:34:02 +0530210
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700211 if (len(updatedGroups)) == 0 {
khenaidood948f772021-08-11 17:49:24 -0400212 desc = "no groups to update"
213 operStatus.Code = common.OperationResp_OPERATION_SUCCESS
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700214 return coreutils.DoneResponse(), nil
215 }
216
Kent Hagermancba2f302020-07-28 13:37:36 -0400217 device, err := agent.getDeviceReadOnly(ctx)
218 if err != nil {
khenaidood948f772021-08-11 17:49:24 -0400219 return coreutils.DoneResponse(), err
Kent Hagermancba2f302020-07-28 13:37:36 -0400220 }
Maninder2195ccc2021-06-23 20:23:01 +0530221
222 if !agent.proceedWithRequest(device) {
khenaidood948f772021-08-11 17:49:24 -0400223 err = status.Errorf(codes.FailedPrecondition, "%s", "cannot complete operation as device deletion is in progress or reconciling is in progress/failed")
224 return coreutils.DoneResponse(), err
Maninder2195ccc2021-06-23 20:23:01 +0530225 }
226
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700227 if device.OperStatus != voltha.OperStatus_ACTIVE || device.ConnectStatus != voltha.ConnectStatus_REACHABLE || device.AdminState != voltha.AdminState_ENABLED {
khenaidood948f772021-08-11 17:49:24 -0400228 err = status.Errorf(codes.FailedPrecondition, "invalid device states-oper-%s-connect-%s-admin-%s", device.OperStatus, device.ConnectStatus, device.AdminState)
229 return coreutils.DoneResponse(), err
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700230 }
Maninder2195ccc2021-06-23 20:23:01 +0530231
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700232 dType, err := agent.adapterMgr.GetDeviceType(ctx, &voltha.ID{Id: device.Type})
233 if err != nil {
khenaidood948f772021-08-11 17:49:24 -0400234 err = status.Errorf(codes.FailedPrecondition, "non-existent-device-type-%s", device.Type)
235 return coreutils.DoneResponse(), err
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700236 }
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700237
Kent Hagermana7c9d792020-07-16 17:39:01 -0400238 groupsToUpdate := make([]*ofp.OfpGroupEntry, 0)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700239 for _, group := range updatedGroups {
khenaidoo7585a962021-06-10 16:15:38 -0400240 if groupHandle, have := agent.groupCache.Lock(group.Desc.GroupId); have {
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700241 // Update the store and cache
khenaidood948f772021-08-11 17:49:24 -0400242 if err = groupHandle.Update(ctx, group); err != nil {
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700243 groupHandle.Unlock()
244 return coreutils.DoneResponse(), err
245 }
246 groupsToUpdate = append(groupsToUpdate, group)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700247 groupHandle.Unlock()
248 }
249 }
250
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700251 response := coreutils.NewResponse()
khenaidood948f772021-08-11 17:49:24 -0400252 subCtx := coreutils.WithSpanAndRPCMetadataFromContext(ctx)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700253 // Process bulk flow update differently than incremental update
254 if !dType.AcceptsAddRemoveFlowUpdates {
Kent Hagermana7c9d792020-07-16 17:39:01 -0400255 updatedAllGroups := agent.listDeviceGroups()
khenaidood948f772021-08-11 17:49:24 -0400256 ctr, groupSlice := 0, make([]*ofp.OfpGroupEntry, len(updatedAllGroups))
257 for _, group := range updatedAllGroups {
258 groupSlice[ctr] = group
259 ctr++
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700260 }
khenaidoo9beaaf12021-10-19 17:32:01 -0400261 go agent.sendBulkFlows(subCtx, device, nil, &ofp.FlowGroups{Items: groupSlice}, flowMetadata, response)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700262 } else {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000263 logger.Debugw(ctx, "updating-groups",
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700264 log.Fields{
265 "device-id": agent.deviceID,
266 "groups-to-update": groupsToUpdate,
267 })
268
269 // Sanity check
270 if (len(groupsToUpdate)) == 0 {
khenaidood948f772021-08-11 17:49:24 -0400271 desc = "nothing to update"
272 operStatus.Code = common.OperationResp_OPERATION_SUCCESS
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700273 return coreutils.DoneResponse(), nil
274 }
275
276 flowChanges := &ofp.FlowChanges{
khenaidoo9beaaf12021-10-19 17:32:01 -0400277 ToAdd: &ofp.Flows{Items: []*ofp.OfpFlowStats{}},
278 ToRemove: &ofp.Flows{Items: []*ofp.OfpFlowStats{}},
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700279 }
280 groupChanges := &ofp.FlowGroupChanges{
khenaidoo9beaaf12021-10-19 17:32:01 -0400281 ToAdd: &ofp.FlowGroups{Items: []*ofp.OfpGroupEntry{}},
282 ToRemove: &ofp.FlowGroups{Items: []*ofp.OfpGroupEntry{}},
283 ToUpdate: &ofp.FlowGroups{Items: groupsToUpdate},
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700284 }
khenaidood948f772021-08-11 17:49:24 -0400285 go agent.sendIncrementalFlows(subCtx, device, flowChanges, groupChanges, flowMetadata, response)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700286 }
287
Maninder9a1bc0d2020-10-26 11:34:02 +0530288 operStatus.Code = common.OperationResp_OPERATION_IN_PROGRESS
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700289 return response, nil
290}