blob: 6e32bfee0c8a569e31172eddf50565bd2b6d3885 [file] [log] [blame]
khenaidoob9203542018-09-17 22:56:37 -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 */
npujar1d86a522019-11-14 17:11:16 +053016
Kent Hagerman2b216042020-04-03 18:28:56 -040017package device
khenaidoob9203542018-09-17 22:56:37 -040018
19import (
20 "context"
Matteo Scandolo360605d2019-11-05 18:29:17 -080021 "encoding/hex"
Kent Hagerman4f355f52020-03-30 16:01:33 -040022 "errors"
khenaidoo3ab34882019-05-02 21:33:30 -040023 "fmt"
Mahir Gunyelb0343bf2021-05-11 14:14:26 -070024 "reflect"
25 "sync"
26 "time"
27
Maninder0aabf0c2021-03-17 14:55:14 +053028 "github.com/cenkalti/backoff/v3"
Maninder9a1bc0d2020-10-26 11:34:02 +053029 "github.com/gogo/protobuf/proto"
30 "github.com/golang/protobuf/ptypes"
31 "github.com/golang/protobuf/ptypes/empty"
Maninder0aabf0c2021-03-17 14:55:14 +053032 "github.com/opencord/voltha-go/rw_core/config"
Maninder9a1bc0d2020-10-26 11:34:02 +053033 "google.golang.org/grpc/codes"
34 "google.golang.org/grpc/status"
Mahir Gunyeladdb66a2020-04-29 18:08:50 -070035
Himani Chawla2ba1c9c2020-10-07 13:19:03 +053036 "github.com/opencord/voltha-go/db/model"
Kent Hagerman2b216042020-04-03 18:28:56 -040037 "github.com/opencord/voltha-go/rw_core/core/adapter"
Mahir Gunyel03de0d32020-06-03 01:36:59 -070038 "github.com/opencord/voltha-go/rw_core/core/device/flow"
39 "github.com/opencord/voltha-go/rw_core/core/device/group"
Kent Hagerman2a07b862020-06-19 15:23:07 -040040 "github.com/opencord/voltha-go/rw_core/core/device/port"
Kent Hagerman2b216042020-04-03 18:28:56 -040041 "github.com/opencord/voltha-go/rw_core/core/device/remote"
Himani Chawla2ba1c9c2020-10-07 13:19:03 +053042 "github.com/opencord/voltha-go/rw_core/core/device/transientstate"
Scott Bakerb671a862019-10-24 10:53:40 -070043 coreutils "github.com/opencord/voltha-go/rw_core/utils"
Himani Chawla2ba1c9c2020-10-07 13:19:03 +053044 "github.com/opencord/voltha-lib-go/v4/pkg/kafka"
Maninderdfadc982020-10-28 14:04:33 +053045 "github.com/opencord/voltha-lib-go/v4/pkg/log"
Maninder9a1bc0d2020-10-26 11:34:02 +053046 "github.com/opencord/voltha-protos/v4/go/common"
Salman Siddiqui1cf95042020-11-19 00:42:56 +053047 "github.com/opencord/voltha-protos/v4/go/extension"
Maninderdfadc982020-10-28 14:04:33 +053048 ic "github.com/opencord/voltha-protos/v4/go/inter_container"
49 ofp "github.com/opencord/voltha-protos/v4/go/openflow_13"
50 "github.com/opencord/voltha-protos/v4/go/voltha"
khenaidoob9203542018-09-17 22:56:37 -040051)
52
Kent Hagerman2b216042020-04-03 18:28:56 -040053// Agent represents device agent attributes
54type Agent struct {
Maninder0aabf0c2021-03-17 14:55:14 +053055 deviceID string
56 parentID string
57 deviceType string
58 isRootDevice bool
59 adapterProxy *remote.AdapterProxy
60 adapterMgr *adapter.Manager
61 deviceMgr *Manager
62 dbProxy *model.Proxy
63 exitChannel chan int
64 device *voltha.Device
65 requestQueue *coreutils.RequestQueue
66 defaultTimeout time.Duration
67 startOnce sync.Once
68 stopOnce sync.Once
69 stopped bool
70 stopReconciling chan int
71 stopReconcilingMutex sync.RWMutex
72 config *config.RWCoreFlags
Mahir Gunyel03de0d32020-06-03 01:36:59 -070073
Himani Chawla2ba1c9c2020-10-07 13:19:03 +053074 flowLoader *flow.Loader
75 groupLoader *group.Loader
76 portLoader *port.Loader
77 transientStateLoader *transientstate.Loader
khenaidoob9203542018-09-17 22:56:37 -040078}
79
Kent Hagerman2b216042020-04-03 18:28:56 -040080//newAgent creates a new device agent. The device will be initialized when start() is called.
Kent Hagerman2a07b862020-06-19 15:23:07 -040081func newAgent(ap *remote.AdapterProxy, device *voltha.Device, deviceMgr *Manager, dbPath *model.Path, deviceProxy *model.Proxy, timeout time.Duration) *Agent {
82 deviceID := device.Id
83 if deviceID == "" {
84 deviceID = coreutils.CreateDeviceID()
Stephane Barbarie1ab43272018-12-08 21:42:13 -050085 }
Scott Baker80678602019-11-14 16:57:36 -080086
Kent Hagerman2a07b862020-06-19 15:23:07 -040087 return &Agent{
Himani Chawla2ba1c9c2020-10-07 13:19:03 +053088 deviceID: deviceID,
89 adapterProxy: ap,
90 isRootDevice: device.Root,
91 parentID: device.ParentId,
92 deviceType: device.Type,
93 deviceMgr: deviceMgr,
94 adapterMgr: deviceMgr.adapterMgr,
95 exitChannel: make(chan int, 1),
96 dbProxy: deviceProxy,
97 defaultTimeout: timeout,
98 device: proto.Clone(device).(*voltha.Device),
99 requestQueue: coreutils.NewRequestQueue(),
Maninder0aabf0c2021-03-17 14:55:14 +0530100 config: deviceMgr.config,
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530101 flowLoader: flow.NewLoader(dbPath.SubPath("flows").Proxy(deviceID)),
102 groupLoader: group.NewLoader(dbPath.SubPath("groups").Proxy(deviceID)),
103 portLoader: port.NewLoader(dbPath.SubPath("ports").Proxy(deviceID)),
104 transientStateLoader: transientstate.NewLoader(dbPath.SubPath("core").Proxy("transientstate"), deviceID),
Kent Hagerman2a07b862020-06-19 15:23:07 -0400105 }
khenaidoob9203542018-09-17 22:56:37 -0400106}
107
khenaidoo442e7c72020-03-10 16:13:48 -0400108// start() saves the device to the data model and registers for callbacks on that device if deviceToCreate!=nil.
109// Otherwise, it will load the data from the dB and setup the necessary callbacks and proxies. Returns the device that
Scott Baker80678602019-11-14 16:57:36 -0800110// was started.
Kent Hagerman2b216042020-04-03 18:28:56 -0400111func (agent *Agent) start(ctx context.Context, deviceToCreate *voltha.Device) (*voltha.Device, error) {
khenaidoo442e7c72020-03-10 16:13:48 -0400112 needToStart := false
113 if agent.startOnce.Do(func() { needToStart = true }); !needToStart {
Kent Hagermancba2f302020-07-28 13:37:36 -0400114 return agent.getDeviceReadOnly(ctx)
khenaidoo442e7c72020-03-10 16:13:48 -0400115 }
116 var startSucceeded bool
117 defer func() {
118 if !startSucceeded {
119 if err := agent.stop(ctx); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000120 logger.Errorw(ctx, "failed-to-cleanup-after-unsuccessful-start", log.Fields{"device-id": agent.deviceID, "error": err})
khenaidoo442e7c72020-03-10 16:13:48 -0400121 }
122 }
123 }()
Scott Baker80678602019-11-14 16:57:36 -0800124
khenaidoo442e7c72020-03-10 16:13:48 -0400125 var device *voltha.Device
Scott Baker80678602019-11-14 16:57:36 -0800126 if deviceToCreate == nil {
127 // Load the existing device
Kent Hagerman4f355f52020-03-30 16:01:33 -0400128 device := &voltha.Device{}
Kent Hagermanf5a67352020-04-30 15:15:26 -0400129 have, err := agent.dbProxy.Get(ctx, agent.deviceID, device)
Thomas Lee Se5a44012019-11-07 20:32:24 +0530130 if err != nil {
Thomas Lee Se5a44012019-11-07 20:32:24 +0530131 return nil, err
Kent Hagerman4f355f52020-03-30 16:01:33 -0400132 } else if !have {
133 return nil, status.Errorf(codes.NotFound, "device-%s", agent.deviceID)
Thomas Lee Se5a44012019-11-07 20:32:24 +0530134 }
Kent Hagerman4f355f52020-03-30 16:01:33 -0400135
136 agent.deviceType = device.Adapter
137 agent.device = proto.Clone(device).(*voltha.Device)
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700138 // load the flows and groups from KV to cache
139 agent.flowLoader.Load(ctx)
140 agent.groupLoader.Load(ctx)
Kent Hagerman2a07b862020-06-19 15:23:07 -0400141 agent.portLoader.Load(ctx)
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530142 agent.transientStateLoader.Load(ctx)
Kent Hagerman4f355f52020-03-30 16:01:33 -0400143
Himani Chawlab4c25912020-11-12 17:16:38 +0530144 logger.Infow(ctx, "device-loaded-from-db", log.Fields{"device-id": agent.deviceID})
khenaidoo297cd252019-02-07 22:10:23 -0500145 } else {
Scott Baker80678602019-11-14 16:57:36 -0800146 // Create a new device
Maninder9a1bc0d2020-10-26 11:34:02 +0530147 var desc string
148 prevState := common.AdminState_UNKNOWN
149 currState := common.AdminState_UNKNOWN
150 operStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
151
152 defer agent.logDeviceUpdate(ctx, "createDevice", &prevState, &currState, operStatus, &desc)
153
Kent Hagermanf5a67352020-04-30 15:15:26 -0400154 // Assumption is that AdminState, FlowGroups, and Flows are uninitialized since this
155 // is a new device, so populate them here before passing the device to ldProxy.Set.
Kent Hagerman2b216042020-04-03 18:28:56 -0400156 // agent.deviceId will also have been set during newAgent().
Scott Baker80678602019-11-14 16:57:36 -0800157 device = (proto.Clone(deviceToCreate)).(*voltha.Device)
npujar1d86a522019-11-14 17:11:16 +0530158 device.Id = agent.deviceID
Scott Baker80678602019-11-14 16:57:36 -0800159 device.AdminState = voltha.AdminState_PREPROVISIONED
Maninder9a1bc0d2020-10-26 11:34:02 +0530160 currState = device.AdminState
Scott Baker80678602019-11-14 16:57:36 -0800161 if !deviceToCreate.GetRoot() && deviceToCreate.ProxyAddress != nil {
162 // Set the default vlan ID to the one specified by the parent adapter. It can be
163 // overwritten by the child adapter during a device update request
164 device.Vlan = deviceToCreate.ProxyAddress.ChannelId
165 }
166
khenaidoo297cd252019-02-07 22:10:23 -0500167 // Add the initial device to the local model
Kent Hagermanf5a67352020-04-30 15:15:26 -0400168 if err := agent.dbProxy.Set(ctx, agent.deviceID, device); err != nil {
Maninder9a1bc0d2020-10-26 11:34:02 +0530169 desc = fmt.Sprintf("failed-adding-device-%s: %s", agent.deviceID, err.Error())
Kent Hagerman4f355f52020-03-30 16:01:33 -0400170 return nil, status.Errorf(codes.Aborted, "failed-adding-device-%s: %s", agent.deviceID, err)
khenaidoo297cd252019-02-07 22:10:23 -0500171 }
Mahir Gunyelb0343bf2021-05-11 14:14:26 -0700172 _ = agent.deviceMgr.Agent.SendDeviceStateChangeEvent(ctx, device.OperStatus, device.ConnectStatus, prevState, device, time.Now().Unix())
Maninder9a1bc0d2020-10-26 11:34:02 +0530173 operStatus.Code = common.OperationResp_OPERATION_SUCCESS
khenaidoo442e7c72020-03-10 16:13:48 -0400174 agent.device = device
khenaidoob9203542018-09-17 22:56:37 -0400175 }
khenaidoo442e7c72020-03-10 16:13:48 -0400176 startSucceeded = true
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000177 log.EnrichSpan(ctx, log.Fields{"device-id": agent.deviceID})
Rohan Agrawal31f21802020-06-12 05:38:46 +0000178 logger.Debugw(ctx, "device-agent-started", log.Fields{"device-id": agent.deviceID})
khenaidoo442e7c72020-03-10 16:13:48 -0400179
Kent Hagermancba2f302020-07-28 13:37:36 -0400180 return agent.getDeviceReadOnly(ctx)
khenaidoob9203542018-09-17 22:56:37 -0400181}
182
khenaidoo4d4802d2018-10-04 21:59:49 -0400183// stop stops the device agent. Not much to do for now
Kent Hagerman2b216042020-04-03 18:28:56 -0400184func (agent *Agent) stop(ctx context.Context) error {
khenaidoo442e7c72020-03-10 16:13:48 -0400185 needToStop := false
186 if agent.stopOnce.Do(func() { needToStop = true }); !needToStop {
187 return nil
188 }
189 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
190 return err
191 }
192 defer agent.requestQueue.RequestComplete()
khenaidoo49085352020-01-13 19:15:43 -0500193
Himani Chawlab4c25912020-11-12 17:16:38 +0530194 logger.Infow(ctx, "stopping-device-agent", log.Fields{"device-id": agent.deviceID, "parent-id": agent.parentID})
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530195 // Remove the device transient loader
196 if err := agent.deleteTransientState(ctx); err != nil {
197 return err
198 }
khenaidoo0a822f92019-05-08 15:15:57 -0400199 // Remove the device from the KV store
Kent Hagermanf5a67352020-04-30 15:15:26 -0400200 if err := agent.dbProxy.Remove(ctx, agent.deviceID); err != nil {
khenaidoo442e7c72020-03-10 16:13:48 -0400201 return err
Thomas Lee Se5a44012019-11-07 20:32:24 +0530202 }
khenaidoo442e7c72020-03-10 16:13:48 -0400203
khenaidoo442e7c72020-03-10 16:13:48 -0400204 close(agent.exitChannel)
205
206 agent.stopped = true
207
Rohan Agrawal31f21802020-06-12 05:38:46 +0000208 logger.Infow(ctx, "device-agent-stopped", log.Fields{"device-id": agent.deviceID, "parent-id": agent.parentID})
khenaidoo442e7c72020-03-10 16:13:48 -0400209
210 return nil
khenaidoob9203542018-09-17 22:56:37 -0400211}
212
Scott Baker80678602019-11-14 16:57:36 -0800213// Load the most recent state from the KVStore for the device.
Kent Hagerman2b216042020-04-03 18:28:56 -0400214func (agent *Agent) reconcileWithKVStore(ctx context.Context) {
khenaidoo442e7c72020-03-10 16:13:48 -0400215 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000216 logger.Warnw(ctx, "request-aborted", log.Fields{"device-id": agent.deviceID, "error": err})
khenaidoo442e7c72020-03-10 16:13:48 -0400217 return
218 }
219 defer agent.requestQueue.RequestComplete()
Rohan Agrawal31f21802020-06-12 05:38:46 +0000220 logger.Debug(ctx, "reconciling-device-agent-devicetype")
Scott Baker80678602019-11-14 16:57:36 -0800221 // TODO: context timeout
Kent Hagerman4f355f52020-03-30 16:01:33 -0400222 device := &voltha.Device{}
Kent Hagermanf5a67352020-04-30 15:15:26 -0400223 if have, err := agent.dbProxy.Get(ctx, agent.deviceID, device); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000224 logger.Errorw(ctx, "kv-get-failed", log.Fields{"device-id": agent.deviceID, "error": err})
Thomas Lee Se5a44012019-11-07 20:32:24 +0530225 return
Kent Hagerman4f355f52020-03-30 16:01:33 -0400226 } else if !have {
227 return // not found in kv
Thomas Lee Se5a44012019-11-07 20:32:24 +0530228 }
Kent Hagerman4f355f52020-03-30 16:01:33 -0400229
230 agent.deviceType = device.Adapter
231 agent.device = device
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700232 agent.flowLoader.Load(ctx)
233 agent.groupLoader.Load(ctx)
Kent Hagerman2a07b862020-06-19 15:23:07 -0400234 agent.portLoader.Load(ctx)
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530235 agent.transientStateLoader.Load(ctx)
236
Rohan Agrawal31f21802020-06-12 05:38:46 +0000237 logger.Debugw(ctx, "reconciled-device-agent-devicetype", log.Fields{"device-id": agent.deviceID, "type": agent.deviceType})
Scott Baker80678602019-11-14 16:57:36 -0800238}
239
khenaidoo442e7c72020-03-10 16:13:48 -0400240// onSuccess is a common callback for scenarios where we receive a nil response following a request to an adapter
241// and the only action required is to publish a successful result on kafka
Rohan Agrawal31f21802020-06-12 05:38:46 +0000242func (agent *Agent) onSuccess(ctx context.Context, rpc string, response interface{}, reqArgs ...interface{}) {
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530243 logger.Debugw(ctx, "response-successful", log.Fields{"rpc": rpc, "device-id": agent.deviceID})
khenaidoo442e7c72020-03-10 16:13:48 -0400244 // TODO: Post success message onto kafka
245}
246
247// onFailure is a common callback for scenarios where we receive an error response following a request to an adapter
248// and the only action required is to publish the failed result on kafka
Rohan Agrawal31f21802020-06-12 05:38:46 +0000249func (agent *Agent) onFailure(ctx context.Context, rpc string, response interface{}, reqArgs ...interface{}) {
khenaidoo442e7c72020-03-10 16:13:48 -0400250 if res, ok := response.(error); ok {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000251 logger.Errorw(ctx, "rpc-failed", log.Fields{"rpc": rpc, "device-id": agent.deviceID, "error": res, "args": reqArgs})
khenaidoo442e7c72020-03-10 16:13:48 -0400252 } else {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000253 logger.Errorw(ctx, "rpc-failed-invalid-error", log.Fields{"rpc": rpc, "device-id": agent.deviceID, "args": reqArgs})
khenaidoo442e7c72020-03-10 16:13:48 -0400254 }
255 // TODO: Post failure message onto kafka
256}
257
Himani Chawlab4c25912020-11-12 17:16:38 +0530258func (agent *Agent) waitForAdapterForceDeleteResponse(ctx context.Context, cancel context.CancelFunc, rpc string, ch chan *kafka.RpcResponse,
khenaidoo442e7c72020-03-10 16:13:48 -0400259 onSuccess coreutils.ResponseCallback, onFailure coreutils.ResponseCallback, reqArgs ...interface{}) {
260 defer cancel()
261 select {
262 case rpcResponse, ok := <-ch:
263 if !ok {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000264 onFailure(ctx, rpc, status.Errorf(codes.Aborted, "channel-closed"), reqArgs)
khenaidoo442e7c72020-03-10 16:13:48 -0400265 } else if rpcResponse.Err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000266 onFailure(ctx, rpc, rpcResponse.Err, reqArgs)
khenaidoo442e7c72020-03-10 16:13:48 -0400267 } else {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000268 onSuccess(ctx, rpc, rpcResponse.Reply, reqArgs)
khenaidoo442e7c72020-03-10 16:13:48 -0400269 }
270 case <-ctx.Done():
Rohan Agrawal31f21802020-06-12 05:38:46 +0000271 onFailure(ctx, rpc, ctx.Err(), reqArgs)
khenaidoo442e7c72020-03-10 16:13:48 -0400272 }
273}
274
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530275// onDeleteSuccess is a common callback for scenarios where we receive a nil response following a delete request
276// to an adapter.
277func (agent *Agent) onDeleteSuccess(ctx context.Context, rpc string, response interface{}, reqArgs ...interface{}) {
278 logger.Debugw(ctx, "response-successful", log.Fields{"rpc": rpc, "device-id": agent.deviceID})
279 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
280 logger.Errorw(ctx, "delete-device-failure", log.Fields{"device-id": agent.deviceID, "error": err, "args": reqArgs})
281 }
282 previousDeviceTransientState := agent.getTransientState()
283 newDevice := agent.cloneDeviceWithoutLock()
284 if err := agent.updateDeviceWithTransientStateAndReleaseLock(ctx, newDevice,
285 voltha.DeviceTransientState_DELETING_POST_ADAPTER_RESPONSE, previousDeviceTransientState); err != nil {
286 logger.Errorw(ctx, "delete-device-failure", log.Fields{"device-id": agent.deviceID, "error": err, "args": reqArgs})
287 }
288}
289
290// onDeleteFailure is a common callback for scenarios where we receive an error response following a delete request
291// to an adapter and the only action required is to return the error response.
292func (agent *Agent) onDeleteFailure(ctx context.Context, rpc string, response interface{}, reqArgs ...interface{}) {
293 if res, ok := response.(error); ok {
294 logger.Errorw(ctx, "rpc-failed", log.Fields{"rpc": rpc, "device-id": agent.deviceID, "error": res, "args": reqArgs})
295 } else {
296 logger.Errorw(ctx, "rpc-failed-invalid-error", log.Fields{"rpc": rpc, "device-id": agent.deviceID, "args": reqArgs})
297 }
298 //Only updating of transient state is required, no transition.
299 if err := agent.updateTransientState(ctx, voltha.DeviceTransientState_DELETE_FAILED); err != nil {
300 logger.Errorw(ctx, "failed-to-update-transient-state-as-delete-failed", log.Fields{"device-id": agent.deviceID})
301 }
302
303}
304
Himani Chawlab4c25912020-11-12 17:16:38 +0530305func (agent *Agent) waitForAdapterResponse(ctx context.Context, cancel context.CancelFunc, rpc string, ch chan *kafka.RpcResponse,
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530306 onSuccess coreutils.ResponseCallback, onFailure coreutils.ResponseCallback, reqArgs ...interface{}) {
307 defer cancel()
Himani Chawlab4c25912020-11-12 17:16:38 +0530308 var rpce *voltha.RPCEvent
309 defer func() {
310 if rpce != nil {
Himani Chawla606a4f02021-03-23 19:45:58 +0530311 agent.deviceMgr.SendRPCEvent(ctx, "RPC_ERROR_RAISE_EVENT", rpce,
312 voltha.EventCategory_COMMUNICATION, nil, time.Now().Unix())
Himani Chawlab4c25912020-11-12 17:16:38 +0530313 }
314 }()
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530315 select {
316 case rpcResponse, ok := <-ch:
317 if !ok {
Himani Chawlab4c25912020-11-12 17:16:38 +0530318 rpce = agent.deviceMgr.NewRPCEvent(ctx, agent.deviceID, "Response Channel Closed", nil)
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530319 onFailure(ctx, rpc, status.Errorf(codes.Aborted, "channel-closed"), reqArgs)
Himani Chawlab4c25912020-11-12 17:16:38 +0530320 //add failure
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530321 } else if rpcResponse.Err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530322 rpce = agent.deviceMgr.NewRPCEvent(ctx, agent.deviceID, rpcResponse.Err.Error(), nil)
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530323 onFailure(ctx, rpc, rpcResponse.Err, reqArgs)
Himani Chawlab4c25912020-11-12 17:16:38 +0530324 //add failure
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530325 } else {
326 onSuccess(ctx, rpc, rpcResponse.Reply, reqArgs)
327 }
328 case <-ctx.Done():
Himani Chawlab4c25912020-11-12 17:16:38 +0530329 rpce = agent.deviceMgr.NewRPCEvent(ctx, agent.deviceID, ctx.Err().Error(), nil)
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530330 onFailure(ctx, rpc, ctx.Err(), reqArgs)
331 }
332}
333
Maninder9a1bc0d2020-10-26 11:34:02 +0530334func (agent *Agent) waitForAdapterResponseAndLogDeviceUpdate(ctx context.Context, cancel context.CancelFunc, rpc string, ch chan *kafka.RpcResponse,
335 onSuccess coreutils.ResponseCallback, onFailure coreutils.ResponseCallback, prevState *common.AdminState_Types, reqArgs ...interface{}) {
336 defer cancel()
337 var desc string
338 operStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
khenaidoodd3324d2021-04-27 16:22:55 -0400339 defer func() {
340 currAdminState := prevState
341 if d, _ := agent.getDeviceReadOnly(ctx); d != nil {
342 currAdminState = &d.AdminState
343 }
344 agent.logDeviceUpdate(ctx, rpc, prevState, currAdminState, operStatus, &desc)
345 }()
Maninder9a1bc0d2020-10-26 11:34:02 +0530346 var rpce *voltha.RPCEvent
347 defer func() {
348 if rpce != nil {
Himani Chawla606a4f02021-03-23 19:45:58 +0530349 agent.deviceMgr.SendRPCEvent(ctx, "RPC_ERROR_RAISE_EVENT", rpce,
350 voltha.EventCategory_COMMUNICATION, nil, time.Now().Unix())
Maninder9a1bc0d2020-10-26 11:34:02 +0530351 }
352 }()
353
354 select {
355 case rpcResponse, ok := <-ch:
356 if !ok {
357 rpce = agent.deviceMgr.NewRPCEvent(ctx, agent.deviceID, "Response Channel Closed", nil)
358 onFailure(ctx, rpc, status.Errorf(codes.Aborted, "channel-closed"), reqArgs)
359 //add failure
360 } else if rpcResponse.Err != nil {
361 desc = rpcResponse.Err.Error()
362 rpce = agent.deviceMgr.NewRPCEvent(ctx, agent.deviceID, desc, nil)
363 onFailure(ctx, rpc, rpcResponse.Err, reqArgs)
364 //add failure
365 } else {
366 operStatus.Code = common.OperationResp_OPERATION_SUCCESS
367 onSuccess(ctx, rpc, rpcResponse.Reply, reqArgs)
368 }
369 case <-ctx.Done():
370 desc = ctx.Err().Error()
371 rpce = agent.deviceMgr.NewRPCEvent(ctx, agent.deviceID, desc, nil)
372 onFailure(ctx, rpc, ctx.Err(), reqArgs)
373 }
374}
375
Kent Hagermancba2f302020-07-28 13:37:36 -0400376// getDeviceReadOnly returns a device which MUST NOT be modified, but is safe to keep forever.
377func (agent *Agent) getDeviceReadOnly(ctx context.Context) (*voltha.Device, error) {
khenaidoo442e7c72020-03-10 16:13:48 -0400378 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
379 return nil, err
380 }
381 defer agent.requestQueue.RequestComplete()
Kent Hagermancba2f302020-07-28 13:37:36 -0400382 return agent.device, nil
khenaidoo92e62c52018-10-03 14:02:54 -0400383}
384
Kent Hagermancba2f302020-07-28 13:37:36 -0400385// getDeviceReadOnlyWithoutLock returns a device which MUST NOT be modified, but is safe to keep forever. This is very efficient.
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400386// The device lock MUST be held by the caller.
Kent Hagermancba2f302020-07-28 13:37:36 -0400387func (agent *Agent) getDeviceReadOnlyWithoutLock() *voltha.Device {
khenaidoo0db4c812020-05-27 15:27:30 -0400388 return agent.device
khenaidoo92e62c52018-10-03 14:02:54 -0400389}
390
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400391// cloneDeviceWithoutLock returns a copy of the device which is safe to modify.
392// The device lock MUST be held by the caller.
393func (agent *Agent) cloneDeviceWithoutLock() *voltha.Device {
394 return proto.Clone(agent.device).(*voltha.Device)
395}
396
khenaidoo3ab34882019-05-02 21:33:30 -0400397// enableDevice activates a preprovisioned or a disable device
Kent Hagerman2b216042020-04-03 18:28:56 -0400398func (agent *Agent) enableDevice(ctx context.Context) error {
Maninder9a1bc0d2020-10-26 11:34:02 +0530399 //To preserve and use oldDevice state as prev state in new device
Maninder9a1bc0d2020-10-26 11:34:02 +0530400 var desc string
401 operStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
402
403 defer agent.logDeviceUpdate(ctx, "enableDevice", nil, nil, operStatus, &desc)
404
khenaidoo442e7c72020-03-10 16:13:48 -0400405 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
406 return err
407 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530408 logger.Debugw(ctx, "enable-device", log.Fields{"device-id": agent.deviceID})
khenaidoo21d51152019-02-01 13:48:37 -0500409
khenaidoodd3324d2021-04-27 16:22:55 -0400410 prevDeviceState := agent.device.AdminState
411
Kent Hagermancba2f302020-07-28 13:37:36 -0400412 oldDevice := agent.getDeviceReadOnlyWithoutLock()
Maninder9a1bc0d2020-10-26 11:34:02 +0530413
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400414 if oldDevice.AdminState == voltha.AdminState_ENABLED {
415 logger.Warnw(ctx, "device-already-enabled", log.Fields{"device-id": agent.deviceID})
416 agent.requestQueue.RequestComplete()
Maninder9a1bc0d2020-10-26 11:34:02 +0530417 desc = fmt.Sprintf("cannot-enable-an-already-enabled-device: %s", oldDevice.Id)
418 return status.Error(codes.FailedPrecondition, desc)
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400419 }
Maninder0aabf0c2021-03-17 14:55:14 +0530420 if !agent.proceedWithRequestNoLock() {
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400421 agent.requestQueue.RequestComplete()
Maninder9a1bc0d2020-10-26 11:34:02 +0530422
Maninder0aabf0c2021-03-17 14:55:14 +0530423 desc = fmt.Sprintf("deviceId:%s, Device deletion or reconciling is in progress.", agent.deviceID)
Maninder9a1bc0d2020-10-26 11:34:02 +0530424 return status.Error(codes.FailedPrecondition, desc)
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400425 }
npujar1d86a522019-11-14 17:11:16 +0530426 // First figure out which adapter will handle this device type. We do it at this stage as allow devices to be
khenaidoo442e7c72020-03-10 16:13:48 -0400427 // pre-provisioned with the required adapter not registered. At this stage, since we need to communicate
npujar1d86a522019-11-14 17:11:16 +0530428 // with the adapter then we need to know the adapter that will handle this request
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400429 adapterName, err := agent.adapterMgr.GetAdapterType(oldDevice.Type)
npujar1d86a522019-11-14 17:11:16 +0530430 if err != nil {
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400431 agent.requestQueue.RequestComplete()
Maninder9a1bc0d2020-10-26 11:34:02 +0530432 desc = err.Error()
Matteo Scandolod525ae32020-04-02 17:27:29 -0700433 return err
npujar1d86a522019-11-14 17:11:16 +0530434 }
435
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400436 newDevice := agent.cloneDeviceWithoutLock()
437 newDevice.Adapter = adapterName
npujar1d86a522019-11-14 17:11:16 +0530438
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400439 // Update the Admin State and set the operational state to activating before sending the request to the Adapters
440 newDevice.AdminState = voltha.AdminState_ENABLED
441 newDevice.OperStatus = voltha.OperStatus_ACTIVATING
Maninder9a1bc0d2020-10-26 11:34:02 +0530442
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400443 if err := agent.updateDeviceAndReleaseLock(ctx, newDevice); err != nil {
Maninder9a1bc0d2020-10-26 11:34:02 +0530444 desc = err.Error()
npujar1d86a522019-11-14 17:11:16 +0530445 return err
446 }
447
khenaidoo442e7c72020-03-10 16:13:48 -0400448 // Adopt the device if it was in pre-provision state. In all other cases, try to re-enable it.
khenaidoo442e7c72020-03-10 16:13:48 -0400449 var ch chan *kafka.RpcResponse
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000450 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
Himani Chawlab4c25912020-11-12 17:16:38 +0530451 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
Maninder9a1bc0d2020-10-26 11:34:02 +0530452 subCtx = coreutils.WithFromTopicMetadataFromContext(subCtx, ctx)
Himani Chawlab4c25912020-11-12 17:16:38 +0530453
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400454 if oldDevice.AdminState == voltha.AdminState_PREPROVISIONED {
455 ch, err = agent.adapterProxy.AdoptDevice(subCtx, newDevice)
khenaidoob9203542018-09-17 22:56:37 -0400456 } else {
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400457 ch, err = agent.adapterProxy.ReEnableDevice(subCtx, newDevice)
khenaidoob9203542018-09-17 22:56:37 -0400458 }
khenaidoo442e7c72020-03-10 16:13:48 -0400459 if err != nil {
460 cancel()
Maninder9a1bc0d2020-10-26 11:34:02 +0530461 desc = err.Error()
khenaidoo442e7c72020-03-10 16:13:48 -0400462 return err
463 }
Maninder9a1bc0d2020-10-26 11:34:02 +0530464
465 operStatus.Code = common.OperationResp_OPERATION_IN_PROGRESS
466
khenaidoo442e7c72020-03-10 16:13:48 -0400467 // Wait for response
Maninder9a1bc0d2020-10-26 11:34:02 +0530468 go agent.waitForAdapterResponseAndLogDeviceUpdate(subCtx, cancel, "enableDevice", ch, agent.onSuccess, agent.onFailure, &prevDeviceState)
khenaidoob9203542018-09-17 22:56:37 -0400469 return nil
470}
471
Maninder9a1bc0d2020-10-26 11:34:02 +0530472func (agent *Agent) waitForAdapterFlowResponse(ctx context.Context, cancel context.CancelFunc, rpc string, ch chan *kafka.RpcResponse, response coreutils.Response) {
khenaidoo442e7c72020-03-10 16:13:48 -0400473 defer cancel()
Maninder9a1bc0d2020-10-26 11:34:02 +0530474 var desc string
475 operStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
476 defer agent.logDeviceUpdate(ctx, rpc, nil, nil, operStatus, &desc)
477
Himani Chawlab4c25912020-11-12 17:16:38 +0530478 var rpce *voltha.RPCEvent
479 defer func() {
480 if rpce != nil {
Himani Chawla606a4f02021-03-23 19:45:58 +0530481 agent.deviceMgr.SendRPCEvent(ctx, "RPC_ERROR_RAISE_EVENT", rpce,
482 voltha.EventCategory_COMMUNICATION, nil, time.Now().Unix())
Himani Chawlab4c25912020-11-12 17:16:38 +0530483 }
484 }()
khenaidoo442e7c72020-03-10 16:13:48 -0400485 select {
486 case rpcResponse, ok := <-ch:
487 if !ok {
Himani Chawlab4c25912020-11-12 17:16:38 +0530488 //add failure
Maninder9a1bc0d2020-10-26 11:34:02 +0530489 desc = "Response Channel Closed"
Himani Chawlab4c25912020-11-12 17:16:38 +0530490 rpce = agent.deviceMgr.NewRPCEvent(ctx, agent.deviceID, "Response Channel Closed", nil)
khenaidoo442e7c72020-03-10 16:13:48 -0400491 response.Error(status.Errorf(codes.Aborted, "channel-closed"))
492 } else if rpcResponse.Err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530493 //add failure
Maninder9a1bc0d2020-10-26 11:34:02 +0530494 desc = rpcResponse.Err.Error()
495 rpce = agent.deviceMgr.NewRPCEvent(ctx, agent.deviceID, desc, nil)
khenaidoo442e7c72020-03-10 16:13:48 -0400496 response.Error(rpcResponse.Err)
497 } else {
Maninder9a1bc0d2020-10-26 11:34:02 +0530498 operStatus.Code = common.OperationResp_OPERATION_SUCCESS
khenaidoo442e7c72020-03-10 16:13:48 -0400499 response.Done()
500 }
501 case <-ctx.Done():
Maninder9a1bc0d2020-10-26 11:34:02 +0530502 desc = ctx.Err().Error()
503 rpce = agent.deviceMgr.NewRPCEvent(ctx, agent.deviceID, desc, nil)
khenaidoo442e7c72020-03-10 16:13:48 -0400504 response.Error(ctx.Err())
khenaidoo2c6a0992019-04-29 13:46:56 -0400505 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400506}
507
A R Karthick5c28f552019-12-11 22:47:44 -0800508//addFlowsAndGroups adds the "newFlows" and "newGroups" from the existing flows/groups and sends the update to the
509//adapters
Kent Hagerman2b216042020-04-03 18:28:56 -0400510func (agent *Agent) addFlowsAndGroups(ctx context.Context, newFlows []*ofp.OfpFlowStats, newGroups []*ofp.OfpGroupEntry, flowMetadata *voltha.FlowMetadata) error {
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700511 var flwResponse, grpResponse coreutils.Response
512 var err error
513 //if new flow list is empty then the called function returns quickly
514 if flwResponse, err = agent.addFlowsToAdapter(ctx, newFlows, flowMetadata); err != nil {
A R Karthick5c28f552019-12-11 22:47:44 -0800515 return err
516 }
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700517 //if new group list is empty then the called function returns quickly
518 if grpResponse, err = agent.addGroupsToAdapter(ctx, newGroups, flowMetadata); err != nil {
519 return err
520 }
521 if errs := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, flwResponse, grpResponse); errs != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000522 logger.Warnw(ctx, "no-adapter-response", log.Fields{"device-id": agent.deviceID, "result": errs})
khenaidoo442e7c72020-03-10 16:13:48 -0400523 return status.Errorf(codes.Aborted, "flow-failure-device-%s", agent.deviceID)
khenaidoo0458db62019-06-20 08:50:36 -0400524 }
khenaidoo0458db62019-06-20 08:50:36 -0400525 return nil
526}
527
A R Karthick5c28f552019-12-11 22:47:44 -0800528//deleteFlowsAndGroups removes the "flowsToDel" and "groupsToDel" from the existing flows/groups and sends the update to the
529//adapters
Kent Hagerman2b216042020-04-03 18:28:56 -0400530func (agent *Agent) deleteFlowsAndGroups(ctx context.Context, flowsToDel []*ofp.OfpFlowStats, groupsToDel []*ofp.OfpGroupEntry, flowMetadata *voltha.FlowMetadata) error {
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700531 var flwResponse, grpResponse coreutils.Response
532 var err error
533 if flwResponse, err = agent.deleteFlowsFromAdapter(ctx, flowsToDel, flowMetadata); err != nil {
A R Karthick5c28f552019-12-11 22:47:44 -0800534 return err
535 }
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700536 if grpResponse, err = agent.deleteGroupsFromAdapter(ctx, groupsToDel, flowMetadata); err != nil {
537 return err
538 }
539
540 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, flwResponse, grpResponse); res != nil {
khenaidoo0458db62019-06-20 08:50:36 -0400541 return status.Errorf(codes.Aborted, "errors-%s", res)
542 }
543 return nil
khenaidoo0458db62019-06-20 08:50:36 -0400544}
545
A R Karthick5c28f552019-12-11 22:47:44 -0800546//updateFlowsAndGroups replaces the existing flows and groups with "updatedFlows" and "updatedGroups" respectively. It
547//also sends the updates to the adapters
Kent Hagerman2b216042020-04-03 18:28:56 -0400548func (agent *Agent) updateFlowsAndGroups(ctx context.Context, updatedFlows []*ofp.OfpFlowStats, updatedGroups []*ofp.OfpGroupEntry, flowMetadata *voltha.FlowMetadata) error {
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700549 var flwResponse, grpResponse coreutils.Response
550 var err error
551 if flwResponse, err = agent.updateFlowsToAdapter(ctx, updatedFlows, flowMetadata); err != nil {
A R Karthick5c28f552019-12-11 22:47:44 -0800552 return err
553 }
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700554 if grpResponse, err = agent.updateGroupsToAdapter(ctx, updatedGroups, flowMetadata); err != nil {
555 return err
556 }
557
558 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, flwResponse, grpResponse); res != nil {
khenaidoo0458db62019-06-20 08:50:36 -0400559 return status.Errorf(codes.Aborted, "errors-%s", res)
560 }
561 return nil
khenaidoo19d7b632018-10-30 10:49:50 -0400562}
563
khenaidoo4d4802d2018-10-04 21:59:49 -0400564//disableDevice disable a device
Kent Hagerman2b216042020-04-03 18:28:56 -0400565func (agent *Agent) disableDevice(ctx context.Context) error {
Maninder9a1bc0d2020-10-26 11:34:02 +0530566 var desc string
567 operStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
568
569 prevDeviceState := agent.device.AdminState
570
571 defer agent.logDeviceUpdate(ctx, "disableDevice", nil, nil, operStatus, &desc)
572
khenaidoo442e7c72020-03-10 16:13:48 -0400573 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
Maninder9a1bc0d2020-10-26 11:34:02 +0530574 desc = err.Error()
khenaidoo442e7c72020-03-10 16:13:48 -0400575 return err
576 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530577 logger.Debugw(ctx, "disable-device", log.Fields{"device-id": agent.deviceID})
khenaidoo6e55d9e2019-12-12 18:26:26 -0500578
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400579 cloned := agent.cloneDeviceWithoutLock()
khenaidoo6e55d9e2019-12-12 18:26:26 -0500580
581 if cloned.AdminState == voltha.AdminState_DISABLED {
Maninder9a1bc0d2020-10-26 11:34:02 +0530582 desc = "device-already-disabled"
divyadesaicb8b59d2020-08-18 09:55:47 +0000583 logger.Debugw(ctx, "device-already-disabled", log.Fields{"device-id": agent.deviceID})
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400584 agent.requestQueue.RequestComplete()
npujar1d86a522019-11-14 17:11:16 +0530585 return nil
586 }
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530587 if cloned.AdminState == voltha.AdminState_PREPROVISIONED {
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400588 agent.requestQueue.RequestComplete()
Maninder9a1bc0d2020-10-26 11:34:02 +0530589 desc = fmt.Sprintf("deviceId:%s, invalid-admin-state:%s", agent.deviceID, cloned.AdminState)
khenaidoo6e55d9e2019-12-12 18:26:26 -0500590 return status.Errorf(codes.FailedPrecondition, "deviceId:%s, invalid-admin-state:%s", agent.deviceID, cloned.AdminState)
npujar1d86a522019-11-14 17:11:16 +0530591 }
Maninder0aabf0c2021-03-17 14:55:14 +0530592
593 if !agent.proceedWithRequestNoLock() {
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530594 agent.requestQueue.RequestComplete()
Maninder0aabf0c2021-03-17 14:55:14 +0530595 desc = fmt.Sprintf("deviceId:%s, Device deletion or reconciling is in progress.", agent.deviceID)
596 return status.Errorf(codes.FailedPrecondition, "deviceId:%s, Device reconciling is in progress.", agent.deviceID)
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530597 }
Maninder0aabf0c2021-03-17 14:55:14 +0530598
npujar1d86a522019-11-14 17:11:16 +0530599 // Update the Admin State and operational state before sending the request out
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400600 cloned.AdminState = voltha.AdminState_DISABLED
601 cloned.OperStatus = voltha.OperStatus_UNKNOWN
Maninder9a1bc0d2020-10-26 11:34:02 +0530602
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400603 if err := agent.updateDeviceAndReleaseLock(ctx, cloned); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530604 return err
605 }
khenaidoo442e7c72020-03-10 16:13:48 -0400606
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000607 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
Himani Chawlab4c25912020-11-12 17:16:38 +0530608 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
609
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400610 ch, err := agent.adapterProxy.DisableDevice(subCtx, cloned)
khenaidoo442e7c72020-03-10 16:13:48 -0400611 if err != nil {
612 cancel()
Maninder9a1bc0d2020-10-26 11:34:02 +0530613 desc = err.Error()
npujar1d86a522019-11-14 17:11:16 +0530614 return err
khenaidoo0a822f92019-05-08 15:15:57 -0400615 }
Maninder9a1bc0d2020-10-26 11:34:02 +0530616 operStatus.Code = common.OperationResp_OPERATION_IN_PROGRESS
617
618 // Wait for response
619 go agent.waitForAdapterResponseAndLogDeviceUpdate(subCtx, cancel, "disableDevice", ch, agent.onSuccess, agent.onFailure, &prevDeviceState)
khenaidoo0a822f92019-05-08 15:15:57 -0400620
khenaidoo92e62c52018-10-03 14:02:54 -0400621 return nil
622}
623
Kent Hagerman2b216042020-04-03 18:28:56 -0400624func (agent *Agent) rebootDevice(ctx context.Context) error {
Maninder9a1bc0d2020-10-26 11:34:02 +0530625 var desc string
626 operStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
627
628 prevDeviceState := agent.device.AdminState
629
630 defer agent.logDeviceUpdate(ctx, "rebootDevice", nil, nil, operStatus, &desc)
631
khenaidoo442e7c72020-03-10 16:13:48 -0400632 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
Maninder9a1bc0d2020-10-26 11:34:02 +0530633 desc = err.Error()
npujar1d86a522019-11-14 17:11:16 +0530634 return err
khenaidoo4d4802d2018-10-04 21:59:49 -0400635 }
khenaidoo442e7c72020-03-10 16:13:48 -0400636 defer agent.requestQueue.RequestComplete()
Himani Chawlab4c25912020-11-12 17:16:38 +0530637 logger.Debugw(ctx, "reboot-device", log.Fields{"device-id": agent.deviceID})
khenaidoo442e7c72020-03-10 16:13:48 -0400638
Kent Hagermancba2f302020-07-28 13:37:36 -0400639 device := agent.getDeviceReadOnlyWithoutLock()
Maninder0aabf0c2021-03-17 14:55:14 +0530640 if !agent.proceedWithRequestNoLock() {
641 desc = fmt.Sprintf("deviceId:%s, Device delection or reconciling is in progress.", agent.deviceID)
642 return status.Errorf(codes.FailedPrecondition, "deviceId:%s, Device reconciling is in progress.", agent.deviceID)
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530643 }
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000644 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
Himani Chawlab4c25912020-11-12 17:16:38 +0530645 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
646
Kent Hagerman2b216042020-04-03 18:28:56 -0400647 ch, err := agent.adapterProxy.RebootDevice(subCtx, device)
khenaidoo442e7c72020-03-10 16:13:48 -0400648 if err != nil {
649 cancel()
Maninder9a1bc0d2020-10-26 11:34:02 +0530650 desc = err.Error()
khenaidoo442e7c72020-03-10 16:13:48 -0400651 return err
652 }
Maninder9a1bc0d2020-10-26 11:34:02 +0530653 operStatus.Code = common.OperationResp_OPERATION_IN_PROGRESS
654
655 // Wait for response
656 go agent.waitForAdapterResponseAndLogDeviceUpdate(subCtx, cancel, "rebootDevice", ch, agent.onSuccess, agent.onFailure, &prevDeviceState)
khenaidoo4d4802d2018-10-04 21:59:49 -0400657 return nil
658}
659
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530660func (agent *Agent) deleteDeviceForce(ctx context.Context) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530661 logger.Debugw(ctx, "delete-device-force", log.Fields{"device-id": agent.deviceID})
Maninder9a1bc0d2020-10-26 11:34:02 +0530662
663 var desc string
664 operStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
665
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530666 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
Maninder9a1bc0d2020-10-26 11:34:02 +0530667 desc = err.Error()
668 agent.logDeviceUpdate(ctx, "deleteDeviceForce", nil, nil, operStatus, &desc)
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530669 return err
670 }
671 // Get the device Transient state, return err if it is DELETING
672 previousDeviceTransientState := agent.getTransientState()
673
674 if agent.isStateDeleting(previousDeviceTransientState) {
675 agent.requestQueue.RequestComplete()
Maninder9a1bc0d2020-10-26 11:34:02 +0530676 desc = fmt.Sprintf("deviceId:%s, Device Deletion is in progress",
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530677 agent.deviceID)
Maninder9a1bc0d2020-10-26 11:34:02 +0530678 agent.logDeviceUpdate(ctx, "deleteDeviceForce", nil, nil, operStatus, &desc)
679 return status.Error(codes.FailedPrecondition, desc)
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530680 }
Maninder0aabf0c2021-03-17 14:55:14 +0530681
682 //Send stop Reconcile if in progress
683 agent.stopReconcile()
684
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530685 device := agent.cloneDeviceWithoutLock()
Himani Chawlab4c25912020-11-12 17:16:38 +0530686 if err := agent.updateDeviceWithTransientStateAndReleaseLock(ctx, device,
687 voltha.DeviceTransientState_FORCE_DELETING, previousDeviceTransientState); err != nil {
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530688 return err
689 }
690 previousAdminState := device.AdminState
691 if previousAdminState != ic.AdminState_PREPROVISIONED {
692 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
Himani Chawlab4c25912020-11-12 17:16:38 +0530693 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
694
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530695 ch, err := agent.adapterProxy.DeleteDevice(subCtx, device)
696 if err != nil {
697 cancel()
Maninder9a1bc0d2020-10-26 11:34:02 +0530698 desc = err.Error()
699 agent.logDeviceUpdate(ctx, "deleteDeviceForce", nil, nil, operStatus, &desc)
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530700 return err
701 }
Maninder9a1bc0d2020-10-26 11:34:02 +0530702 // As force delete will not be dependent over the response of adapter, marking this operation as success
703 operStatus.Code = common.OperationResp_OPERATION_SUCCESS
704 agent.logDeviceUpdate(ctx, "deleteDeviceForce", nil, nil, operStatus, &desc)
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530705 // Since it is a case of force delete, nothing needs to be done on adapter responses.
Himani Chawlab4c25912020-11-12 17:16:38 +0530706 go agent.waitForAdapterForceDeleteResponse(subCtx, cancel, "deleteDeviceForce", ch, agent.onSuccess,
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530707 agent.onFailure)
708 }
709 return nil
710}
711
Kent Hagerman2b216042020-04-03 18:28:56 -0400712func (agent *Agent) deleteDevice(ctx context.Context) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530713 logger.Debugw(ctx, "delete-device", log.Fields{"device-id": agent.deviceID})
Maninder9a1bc0d2020-10-26 11:34:02 +0530714
715 var desc string
716 operStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
717 prevState := agent.device.AdminState
718
719 defer agent.logDeviceUpdate(ctx, "deleteDevice", nil, nil, operStatus, &desc)
720
khenaidoo442e7c72020-03-10 16:13:48 -0400721 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
Maninder9a1bc0d2020-10-26 11:34:02 +0530722 desc = err.Error()
khenaidoo442e7c72020-03-10 16:13:48 -0400723 return err
724 }
Maninder0aabf0c2021-03-17 14:55:14 +0530725
726 if agent.isReconcileInProgress() {
727 agent.requestQueue.RequestComplete()
728 desc = fmt.Sprintf("deviceId:%s, Device Reconciling is in progress", agent.deviceID)
729 return status.Error(codes.FailedPrecondition, desc)
730 }
731
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530732 // Get the device Transient state, return err if it is DELETING
733 previousDeviceTransientState := agent.getTransientState()
khenaidoo6e55d9e2019-12-12 18:26:26 -0500734
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530735 if agent.isStateDeleting(previousDeviceTransientState) {
736 agent.requestQueue.RequestComplete()
Maninder9a1bc0d2020-10-26 11:34:02 +0530737 desc = fmt.Sprintf("deviceId:%s, Device Deletion is in progress", agent.deviceID)
738 return status.Error(codes.FailedPrecondition, desc)
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530739 }
740 device := agent.cloneDeviceWithoutLock()
741 previousAdminState := device.AdminState
742 // Change the device transient state to DELETING_FROM_ADAPTER state till the device is removed from adapters.
743 currentDeviceTransientState := voltha.DeviceTransientState_DELETING_FROM_ADAPTER
khenaidoo442e7c72020-03-10 16:13:48 -0400744
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530745 if previousAdminState == ic.AdminState_PREPROVISIONED {
746 // Change the state to DELETING POST ADAPTER RESPONSE directly as adapters have no info of the device.
747 currentDeviceTransientState = voltha.DeviceTransientState_DELETING_POST_ADAPTER_RESPONSE
748 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530749 if err := agent.updateDeviceWithTransientStateAndReleaseLock(ctx, device,
750 currentDeviceTransientState, previousDeviceTransientState); err != nil {
Maninder9a1bc0d2020-10-26 11:34:02 +0530751 desc = err.Error()
npujar1d86a522019-11-14 17:11:16 +0530752 return err
753 }
khenaidoo442e7c72020-03-10 16:13:48 -0400754 // If the device was in pre-prov state (only parent device are in that state) then do not send the request to the
755 // adapter
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530756 if previousAdminState != ic.AdminState_PREPROVISIONED {
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000757 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
Himani Chawlab4c25912020-11-12 17:16:38 +0530758 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
759
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530760 ch, err := agent.adapterProxy.DeleteDevice(subCtx, device)
khenaidoo442e7c72020-03-10 16:13:48 -0400761 if err != nil {
762 cancel()
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530763 //updating of transient state is required in error
764 if err := agent.updateTransientState(ctx, voltha.DeviceTransientState_DELETE_FAILED); err != nil {
765 logger.Errorw(ctx, "failed-to-update-transient-state-as-delete-failed", log.Fields{"device-id": agent.deviceID})
766 }
Maninder9a1bc0d2020-10-26 11:34:02 +0530767 desc = err.Error()
khenaidoo442e7c72020-03-10 16:13:48 -0400768 return err
769 }
Maninder9a1bc0d2020-10-26 11:34:02 +0530770
771 operStatus.Code = common.OperationResp_OPERATION_IN_PROGRESS
772 go agent.waitForAdapterResponseAndLogDeviceUpdate(subCtx, cancel, "deleteDevice", ch, agent.onDeleteSuccess,
773 agent.onDeleteFailure, &prevState)
khenaidoo442e7c72020-03-10 16:13:48 -0400774 }
khenaidoo4d4802d2018-10-04 21:59:49 -0400775 return nil
776}
777
Kent Hagerman2b216042020-04-03 18:28:56 -0400778func (agent *Agent) setParentID(ctx context.Context, device *voltha.Device, parentID string) error {
khenaidoo442e7c72020-03-10 16:13:48 -0400779 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
780 return err
781 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530782 logger.Debugw(ctx, "set-parent-id", log.Fields{"device-id": device.Id, "parent-id": parentID})
khenaidoo6e55d9e2019-12-12 18:26:26 -0500783
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400784 cloned := agent.cloneDeviceWithoutLock()
npujar1d86a522019-11-14 17:11:16 +0530785 cloned.ParentId = parentID
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400786 return agent.updateDeviceAndReleaseLock(ctx, cloned)
khenaidooad06fd72019-10-28 12:26:05 -0400787}
788
khenaidoo442e7c72020-03-10 16:13:48 -0400789// getSwitchCapability retrieves the switch capability of a parent device
Kent Hagerman2b216042020-04-03 18:28:56 -0400790func (agent *Agent) getSwitchCapability(ctx context.Context) (*ic.SwitchCapability, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530791 logger.Debugw(ctx, "get-switch-capability", log.Fields{"device-id": agent.deviceID})
khenaidoo442e7c72020-03-10 16:13:48 -0400792
Kent Hagermancba2f302020-07-28 13:37:36 -0400793 device, err := agent.getDeviceReadOnly(ctx)
khenaidoo442e7c72020-03-10 16:13:48 -0400794 if err != nil {
khenaidoob9203542018-09-17 22:56:37 -0400795 return nil, err
khenaidoob9203542018-09-17 22:56:37 -0400796 }
Kent Hagermancba2f302020-07-28 13:37:36 -0400797 ch, err := agent.adapterProxy.GetOfpDeviceInfo(ctx, device)
khenaidoo442e7c72020-03-10 16:13:48 -0400798 if err != nil {
799 return nil, err
800 }
801
802 // Wait for adapter response
803 rpcResponse, ok := <-ch
804 if !ok {
805 return nil, status.Errorf(codes.Aborted, "channel-closed")
806 }
807 if rpcResponse.Err != nil {
808 return nil, rpcResponse.Err
809 }
810 // Successful response
811 switchCap := &ic.SwitchCapability{}
812 if err := ptypes.UnmarshalAny(rpcResponse.Reply, switchCap); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530813 return nil, err
814 }
815 return switchCap, nil
khenaidoob9203542018-09-17 22:56:37 -0400816}
817
Rohan Agrawal31f21802020-06-12 05:38:46 +0000818func (agent *Agent) onPacketFailure(ctx context.Context, rpc string, response interface{}, args ...interface{}) {
khenaidoo442e7c72020-03-10 16:13:48 -0400819 // packet data is encoded in the args param as the first parameter
820 var packet []byte
821 if len(args) >= 1 {
822 if pkt, ok := args[0].([]byte); ok {
823 packet = pkt
824 }
825 }
826 var errResp error
827 if err, ok := response.(error); ok {
828 errResp = err
829 }
Rohan Agrawal31f21802020-06-12 05:38:46 +0000830 logger.Warnw(ctx, "packet-out-error", log.Fields{
khenaidoo442e7c72020-03-10 16:13:48 -0400831 "device-id": agent.deviceID,
832 "error": errResp,
833 "packet": hex.EncodeToString(packet),
834 })
835}
836
Kent Hagerman2b216042020-04-03 18:28:56 -0400837func (agent *Agent) packetOut(ctx context.Context, outPort uint32, packet *ofp.OfpPacketOut) error {
Scott Baker80678602019-11-14 16:57:36 -0800838 // If deviceType=="" then we must have taken ownership of this device.
839 // Fixes VOL-2226 where a core would take ownership and have stale data
840 if agent.deviceType == "" {
npujar467fe752020-01-16 20:17:45 +0530841 agent.reconcileWithKVStore(ctx)
Scott Baker80678602019-11-14 16:57:36 -0800842 }
khenaidoofdbad6e2018-11-06 22:26:38 -0500843 // Send packet to adapter
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000844 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
Himani Chawlab4c25912020-11-12 17:16:38 +0530845 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
846
Kent Hagerman2b216042020-04-03 18:28:56 -0400847 ch, err := agent.adapterProxy.PacketOut(subCtx, agent.deviceType, agent.deviceID, outPort, packet)
khenaidoo442e7c72020-03-10 16:13:48 -0400848 if err != nil {
849 cancel()
850 return nil
khenaidoofdbad6e2018-11-06 22:26:38 -0500851 }
khenaidoo442e7c72020-03-10 16:13:48 -0400852 go agent.waitForAdapterResponse(subCtx, cancel, "packetOut", ch, agent.onSuccess, agent.onPacketFailure, packet.Data)
khenaidoofdbad6e2018-11-06 22:26:38 -0500853 return nil
854}
855
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400856func (agent *Agent) updateDeviceUsingAdapterData(ctx context.Context, device *voltha.Device) error {
857 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
858 return err
859 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530860 logger.Debugw(ctx, "update-device-using-adapter-data", log.Fields{"device-id": device.Id})
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400861
862 cloned := agent.cloneDeviceWithoutLock()
Mahir Gunyel8e2707d2019-07-25 00:36:21 -0700863 cloned.Root = device.Root
864 cloned.Vendor = device.Vendor
865 cloned.Model = device.Model
866 cloned.SerialNumber = device.SerialNumber
867 cloned.MacAddress = device.MacAddress
868 cloned.Vlan = device.Vlan
869 cloned.Reason = device.Reason
Andrea Campanella025667e2021-01-14 11:50:07 +0100870 cloned.ImageDownloads = device.ImageDownloads
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400871 return agent.updateDeviceAndReleaseLock(ctx, cloned)
khenaidoo43c82122018-11-22 18:38:28 -0500872}
873
Kent Hagerman2b216042020-04-03 18:28:56 -0400874func (agent *Agent) updateDeviceStatus(ctx context.Context, operStatus voltha.OperStatus_Types, connStatus voltha.ConnectStatus_Types) error {
khenaidoo442e7c72020-03-10 16:13:48 -0400875 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
876 return err
877 }
khenaidoo6e55d9e2019-12-12 18:26:26 -0500878
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400879 cloned := agent.cloneDeviceWithoutLock()
npujar1d86a522019-11-14 17:11:16 +0530880 // Ensure the enums passed in are valid - they will be invalid if they are not set when this function is invoked
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400881 if s, ok := voltha.ConnectStatus_Types_name[int32(connStatus)]; ok {
Himani Chawlab4c25912020-11-12 17:16:38 +0530882 logger.Debugw(ctx, "update-device-status-conn", log.Fields{"ok": ok, "val": s})
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400883 cloned.ConnectStatus = connStatus
npujar1d86a522019-11-14 17:11:16 +0530884 }
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400885 if s, ok := voltha.OperStatus_Types_name[int32(operStatus)]; ok {
Himani Chawlab4c25912020-11-12 17:16:38 +0530886 logger.Debugw(ctx, "update-device-status-conn", log.Fields{"ok": ok, "val": s})
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400887 cloned.OperStatus = operStatus
npujar1d86a522019-11-14 17:11:16 +0530888 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530889 logger.Debugw(ctx, "update-device-status", log.Fields{"device-id": cloned.Id, "oper-status": cloned.OperStatus, "connect-status": cloned.ConnectStatus})
npujar1d86a522019-11-14 17:11:16 +0530890 // Store the device
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400891 return agent.updateDeviceAndReleaseLock(ctx, cloned)
khenaidoo92e62c52018-10-03 14:02:54 -0400892}
893
khenaidoob9203542018-09-17 22:56:37 -0400894// TODO: A generic device update by attribute
Kent Hagerman2b216042020-04-03 18:28:56 -0400895func (agent *Agent) updateDeviceAttribute(ctx context.Context, name string, value interface{}) {
khenaidoob9203542018-09-17 22:56:37 -0400896 if value == nil {
897 return
898 }
khenaidoo6e55d9e2019-12-12 18:26:26 -0500899
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400900 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
901 logger.Warnw(ctx, "request-aborted", log.Fields{"device-id": agent.deviceID, "name": name, "error": err})
902 return
903 }
904
905 cloned := agent.cloneDeviceWithoutLock()
khenaidoob9203542018-09-17 22:56:37 -0400906 updated := false
khenaidoo6e55d9e2019-12-12 18:26:26 -0500907 s := reflect.ValueOf(cloned).Elem()
khenaidoob9203542018-09-17 22:56:37 -0400908 if s.Kind() == reflect.Struct {
909 // exported field
910 f := s.FieldByName(name)
911 if f.IsValid() && f.CanSet() {
912 switch f.Kind() {
913 case reflect.String:
914 f.SetString(value.(string))
915 updated = true
916 case reflect.Uint32:
917 f.SetUint(uint64(value.(uint32)))
918 updated = true
919 case reflect.Bool:
920 f.SetBool(value.(bool))
921 updated = true
922 }
923 }
924 }
divyadesaicb8b59d2020-08-18 09:55:47 +0000925 logger.Debugw(ctx, "update-field-status", log.Fields{"device-id": cloned.Id, "name": name, "updated": updated})
khenaidoob9203542018-09-17 22:56:37 -0400926 // Save the data
khenaidoo6e55d9e2019-12-12 18:26:26 -0500927
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400928 if err := agent.updateDeviceAndReleaseLock(ctx, cloned); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000929 logger.Warnw(ctx, "attribute-update-failed", log.Fields{"attribute": name, "value": value})
khenaidoob9203542018-09-17 22:56:37 -0400930 }
khenaidoob9203542018-09-17 22:56:37 -0400931}
serkant.uluderya334479d2019-04-10 08:26:15 -0700932
Kent Hagerman45a13e42020-04-13 12:23:50 -0400933func (agent *Agent) simulateAlarm(ctx context.Context, simulateReq *voltha.SimulateAlarmRequest) error {
khenaidoo442e7c72020-03-10 16:13:48 -0400934 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
935 return err
936 }
937 defer agent.requestQueue.RequestComplete()
Himani Chawlab4c25912020-11-12 17:16:38 +0530938 logger.Debugw(ctx, "simulate-alarm", log.Fields{"device-id": agent.deviceID})
khenaidoo6e55d9e2019-12-12 18:26:26 -0500939
Kent Hagermancba2f302020-07-28 13:37:36 -0400940 device := agent.getDeviceReadOnlyWithoutLock()
khenaidoo6e55d9e2019-12-12 18:26:26 -0500941
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000942 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
Himani Chawlab4c25912020-11-12 17:16:38 +0530943 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
944
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400945 ch, err := agent.adapterProxy.SimulateAlarm(subCtx, device, simulateReq)
khenaidoo442e7c72020-03-10 16:13:48 -0400946 if err != nil {
947 cancel()
npujar1d86a522019-11-14 17:11:16 +0530948 return err
serkant.uluderya334479d2019-04-10 08:26:15 -0700949 }
khenaidoo442e7c72020-03-10 16:13:48 -0400950 go agent.waitForAdapterResponse(subCtx, cancel, "simulateAlarm", ch, agent.onSuccess, agent.onFailure)
serkant.uluderya334479d2019-04-10 08:26:15 -0700951 return nil
952}
Mahir Gunyelb5851672019-07-24 10:46:26 +0300953
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400954// This function updates the device in the DB, releases the device lock, and runs any state transitions.
955// The calling function MUST hold the device lock. The caller MUST NOT modify the device after this is called.
956func (agent *Agent) updateDeviceAndReleaseLock(ctx context.Context, device *voltha.Device) error {
957 // fail early if this agent is no longer valid
Kent Hagerman4f355f52020-03-30 16:01:33 -0400958 if agent.stopped {
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400959 agent.requestQueue.RequestComplete()
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530960 return errors.New("device-agent-stopped")
Thomas Lee Se5a44012019-11-07 20:32:24 +0530961 }
Kent Hagerman4f355f52020-03-30 16:01:33 -0400962
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400963 // update in db
Kent Hagermanf5a67352020-04-30 15:15:26 -0400964 if err := agent.dbProxy.Set(ctx, agent.deviceID, device); err != nil {
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400965 agent.requestQueue.RequestComplete()
Kent Hagerman4f355f52020-03-30 16:01:33 -0400966 return status.Errorf(codes.Internal, "failed-update-device:%s: %s", agent.deviceID, err)
Mahir Gunyelb5851672019-07-24 10:46:26 +0300967 }
divyadesaicb8b59d2020-08-18 09:55:47 +0000968 logger.Debugw(ctx, "updated-device-in-store", log.Fields{"device-id: ": agent.deviceID})
Mahir Gunyelb5851672019-07-24 10:46:26 +0300969
Kent Hagerman6031aad2020-07-29 16:36:33 -0400970 prevDevice := agent.device
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400971 // update the device
khenaidoo0db4c812020-05-27 15:27:30 -0400972 agent.device = device
Mahir Gunyelb0343bf2021-05-11 14:14:26 -0700973 //If any of the states has chenged, send the change event.
974 if prevDevice.OperStatus != device.OperStatus || prevDevice.ConnectStatus != device.ConnectStatus || prevDevice.AdminState != device.AdminState {
975 _ = agent.deviceMgr.Agent.SendDeviceStateChangeEvent(ctx, prevDevice.OperStatus, prevDevice.ConnectStatus, prevDevice.AdminState, device, time.Now().Unix())
976 }
Maninder0aabf0c2021-03-17 14:55:14 +0530977 deviceTransientState := agent.getTransientState()
978
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400979 // release lock before processing transition
980 agent.requestQueue.RequestComplete()
Himani Chawlab4c25912020-11-12 17:16:38 +0530981 subCtx := coreutils.WithSpanAndRPCMetadataFromContext(ctx)
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400982
Himani Chawlab4c25912020-11-12 17:16:38 +0530983 if err := agent.deviceMgr.stateTransitions.ProcessTransition(subCtx,
Maninder0aabf0c2021-03-17 14:55:14 +0530984 device, prevDevice, deviceTransientState, deviceTransientState); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530985 logger.Errorw(ctx, "failed-process-transition", log.Fields{"device-id": device.Id, "previous-admin-state": prevDevice.AdminState, "current-admin-state": device.AdminState})
986 // Sending RPC EVENT here
987 rpce := agent.deviceMgr.NewRPCEvent(ctx, agent.deviceID, err.Error(), nil)
Himani Chawla606a4f02021-03-23 19:45:58 +0530988 agent.deviceMgr.SendRPCEvent(ctx, "RPC_ERROR_RAISE_EVENT", rpce, voltha.EventCategory_COMMUNICATION,
989 nil, time.Now().Unix())
Himani Chawlab4c25912020-11-12 17:16:38 +0530990
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400991 }
Mahir Gunyelb5851672019-07-24 10:46:26 +0300992 return nil
993}
Mahir Gunyelfdee9212019-10-16 16:52:21 -0700994
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530995// This function updates the device transient in the DB through loader, releases the device lock, and runs any state transitions.
996// The calling function MUST hold the device lock. The caller MUST NOT modify the device after this is called.
997func (agent *Agent) updateDeviceWithTransientStateAndReleaseLock(ctx context.Context, device *voltha.Device,
998 transientState, prevTransientState voltha.DeviceTransientState_Types) error {
999 // fail early if this agent is no longer valid
1000 if agent.stopped {
1001 agent.requestQueue.RequestComplete()
1002 return errors.New("device-agent-stopped")
1003 }
1004 //update device TransientState
1005 if err := agent.updateTransientState(ctx, transientState); err != nil {
1006 agent.requestQueue.RequestComplete()
1007 return err
1008 }
1009 // update in db
1010 if err := agent.dbProxy.Set(ctx, agent.deviceID, device); err != nil {
1011 //Reverting TransientState update
1012 err := agent.updateTransientState(ctx, prevTransientState)
1013 logger.Errorw(ctx, "failed-to-revert-transient-state-update-on-error", log.Fields{"device-id": device.Id,
Himani Chawlab4c25912020-11-12 17:16:38 +05301014 "previous-transient-state": prevTransientState, "current-transient-state": transientState})
Himani Chawla2ba1c9c2020-10-07 13:19:03 +05301015 agent.requestQueue.RequestComplete()
1016 return status.Errorf(codes.Internal, "failed-update-device:%s: %s", agent.deviceID, err)
1017 }
1018
1019 logger.Debugw(ctx, "updated-device-in-store", log.Fields{"device-id: ": agent.deviceID})
1020
1021 prevDevice := agent.device
1022 // update the device
1023 agent.device = device
Mahir Gunyelb0343bf2021-05-11 14:14:26 -07001024 //If any of the states has chenged, send the change event.
1025 if prevDevice.OperStatus != device.OperStatus || prevDevice.ConnectStatus != device.ConnectStatus || prevDevice.AdminState != device.AdminState {
1026 _ = agent.deviceMgr.Agent.SendDeviceStateChangeEvent(ctx, prevDevice.OperStatus, prevDevice.ConnectStatus, prevDevice.AdminState, device, time.Now().Unix())
1027 }
Himani Chawla2ba1c9c2020-10-07 13:19:03 +05301028
1029 // release lock before processing transition
1030 agent.requestQueue.RequestComplete()
Himani Chawlab4c25912020-11-12 17:16:38 +05301031 subCtx := coreutils.WithSpanAndRPCMetadataFromContext(ctx)
1032 if err := agent.deviceMgr.stateTransitions.ProcessTransition(subCtx,
Himani Chawla2ba1c9c2020-10-07 13:19:03 +05301033 device, prevDevice, transientState, prevTransientState); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +05301034 logger.Errorw(ctx, "failed-process-transition", log.Fields{"device-id": device.Id, "previous-admin-state": prevDevice.AdminState, "current-admin-state": device.AdminState})
1035 // Sending RPC EVENT here
1036 rpce := agent.deviceMgr.NewRPCEvent(ctx, agent.deviceID, err.Error(), nil)
Himani Chawla606a4f02021-03-23 19:45:58 +05301037 agent.deviceMgr.SendRPCEvent(ctx, "RPC_ERROR_RAISE_EVENT", rpce, voltha.EventCategory_COMMUNICATION,
1038 nil, time.Now().Unix())
Himani Chawla2ba1c9c2020-10-07 13:19:03 +05301039 }
1040 return nil
1041}
Kent Hagerman2b216042020-04-03 18:28:56 -04001042func (agent *Agent) updateDeviceReason(ctx context.Context, reason string) error {
khenaidoo442e7c72020-03-10 16:13:48 -04001043 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1044 return err
1045 }
Maninder9a1bc0d2020-10-26 11:34:02 +05301046
Himani Chawlab4c25912020-11-12 17:16:38 +05301047 logger.Debugw(ctx, "update-device-reason", log.Fields{"device-id": agent.deviceID, "reason": reason})
khenaidoo6e55d9e2019-12-12 18:26:26 -05001048
Maninder9a1bc0d2020-10-26 11:34:02 +05301049 var desc string
1050 operStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
1051
1052 defer agent.logDeviceUpdate(ctx, "updateDeviceReason", nil, nil, operStatus, &desc)
1053
Kent Hagermanf6db9f12020-07-22 17:16:19 -04001054 cloned := agent.cloneDeviceWithoutLock()
npujar1d86a522019-11-14 17:11:16 +05301055 cloned.Reason = reason
Maninder9a1bc0d2020-10-26 11:34:02 +05301056 retErr := agent.updateDeviceAndReleaseLock(ctx, cloned)
1057 if retErr != nil {
1058 desc = retErr.Error()
1059 } else {
1060 operStatus.Code = common.OperationResp_OPERATION_SUCCESS
1061 desc = reason
1062 }
1063 return retErr
Mahir Gunyelfdee9212019-10-16 16:52:21 -07001064}
kesavandbc2d1622020-01-21 00:42:01 -05001065
Kent Hagerman2b216042020-04-03 18:28:56 -04001066func (agent *Agent) ChildDeviceLost(ctx context.Context, device *voltha.Device) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301067 logger.Debugw(ctx, "child-device-lost", log.Fields{"child-device-id": device.Id, "parent-device-id": agent.deviceID})
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001068
Kent Hagerman2a07b862020-06-19 15:23:07 -04001069 // Remove the associated peer ports on the parent device
1070 for portID := range agent.portLoader.ListIDs() {
1071 if portHandle, have := agent.portLoader.Lock(portID); have {
1072 oldPort := portHandle.GetReadOnly()
1073 updatedPeers := make([]*voltha.Port_PeerPort, 0)
1074 for _, peerPort := range oldPort.Peers {
1075 if peerPort.DeviceId != device.Id {
1076 updatedPeers = append(updatedPeers, peerPort)
1077 }
khenaidoo442e7c72020-03-10 16:13:48 -04001078 }
Kent Hagerman2a07b862020-06-19 15:23:07 -04001079 newPort := *oldPort
1080 newPort.Peers = updatedPeers
1081 if err := portHandle.Update(ctx, &newPort); err != nil {
1082 portHandle.Unlock()
1083 return nil
1084 }
1085 portHandle.Unlock()
khenaidoo442e7c72020-03-10 16:13:48 -04001086 }
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001087 }
1088
khenaidoo442e7c72020-03-10 16:13:48 -04001089 //send request to adapter
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001090 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
Himani Chawlab4c25912020-11-12 17:16:38 +05301091 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
1092
Girish Gowdra6f9b10e2021-03-11 14:36:39 -08001093 ch, err := agent.adapterProxy.ChildDeviceLost(ctx, agent.deviceType, device)
khenaidoo442e7c72020-03-10 16:13:48 -04001094 if err != nil {
1095 cancel()
1096 return err
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001097 }
khenaidoo442e7c72020-03-10 16:13:48 -04001098 go agent.waitForAdapterResponse(subCtx, cancel, "childDeviceLost", ch, agent.onSuccess, agent.onFailure)
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001099 return nil
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001100}
onkarkundargi87285252020-01-27 11:34:52 +05301101
Kent Hagerman2b216042020-04-03 18:28:56 -04001102func (agent *Agent) startOmciTest(ctx context.Context, omcitestrequest *voltha.OmciTestRequest) (*voltha.TestResponse, error) {
onkarkundargi87285252020-01-27 11:34:52 +05301103 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1104 return nil, err
1105 }
1106
Kent Hagermanf6db9f12020-07-22 17:16:19 -04001107 cloned := agent.cloneDeviceWithoutLock()
Matteo Scandolod525ae32020-04-02 17:27:29 -07001108
Kent Hagermanf6db9f12020-07-22 17:16:19 -04001109 if cloned.Adapter == "" {
1110 adapterName, err := agent.adapterMgr.GetAdapterType(cloned.Type)
Matteo Scandolod525ae32020-04-02 17:27:29 -07001111 if err != nil {
1112 agent.requestQueue.RequestComplete()
1113 return nil, err
1114 }
Kent Hagermanf6db9f12020-07-22 17:16:19 -04001115 cloned.Adapter = adapterName
onkarkundargi87285252020-01-27 11:34:52 +05301116 }
1117
1118 // Send request to the adapter
Kent Hagermanf6db9f12020-07-22 17:16:19 -04001119 ch, err := agent.adapterProxy.StartOmciTest(ctx, cloned, omcitestrequest)
onkarkundargi87285252020-01-27 11:34:52 +05301120 agent.requestQueue.RequestComplete()
1121 if err != nil {
1122 return nil, err
1123 }
1124
1125 // Wait for the adapter response
1126 rpcResponse, ok := <-ch
1127 if !ok {
1128 return nil, status.Errorf(codes.Aborted, "channel-closed-device-id-%s", agent.deviceID)
1129 }
1130 if rpcResponse.Err != nil {
1131 return nil, rpcResponse.Err
1132 }
1133
1134 // Unmarshal and return the response
1135 testResp := &voltha.TestResponse{}
1136 if err := ptypes.UnmarshalAny(rpcResponse.Reply, testResp); err != nil {
1137 return nil, status.Errorf(codes.InvalidArgument, "%s", err.Error())
1138 }
Himani Chawlab4c25912020-11-12 17:16:38 +05301139 logger.Debugw(ctx, "omci_test_request-success-device-agent", log.Fields{"test-resp": testResp})
onkarkundargi87285252020-01-27 11:34:52 +05301140 return testResp, nil
1141}
Dinesh Belwalkarc1129f12020-02-27 10:41:33 -08001142
1143func (agent *Agent) getExtValue(ctx context.Context, pdevice *voltha.Device, cdevice *voltha.Device, valueparam *voltha.ValueSpecifier) (*voltha.ReturnValues, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301144 logger.Debugw(ctx, "get-ext-value", log.Fields{"device-id": agent.deviceID, "onu-id": valueparam.Id, "value-type": valueparam.Value})
Dinesh Belwalkarc1129f12020-02-27 10:41:33 -08001145 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1146 return nil, err
1147 }
1148
1149 //send request to adapter
1150 ch, err := agent.adapterProxy.GetExtValue(ctx, pdevice, cdevice, valueparam.Id, valueparam.Value)
1151 agent.requestQueue.RequestComplete()
1152 if err != nil {
1153 return nil, err
1154 }
1155
1156 // Wait for the adapter response
1157 rpcResponse, ok := <-ch
1158 if !ok {
1159 return nil, status.Errorf(codes.Aborted, "channel-closed-device-id-%s", agent.deviceID)
1160 }
1161 if rpcResponse.Err != nil {
1162 return nil, rpcResponse.Err
1163 }
1164
1165 // Unmarshal and return the response
1166 Resp := &voltha.ReturnValues{}
1167 if err := ptypes.UnmarshalAny(rpcResponse.Reply, Resp); err != nil {
1168 return nil, status.Errorf(codes.InvalidArgument, "%s", err.Error())
1169 }
Himani Chawlab4c25912020-11-12 17:16:38 +05301170 logger.Debugw(ctx, "get-ext-value-success-device-agent", log.Fields{"Resp": Resp})
Dinesh Belwalkarc1129f12020-02-27 10:41:33 -08001171 return Resp, nil
1172}
dpaul62686312020-06-23 14:17:36 +05301173
1174func (agent *Agent) setExtValue(ctx context.Context, device *voltha.Device, value *voltha.ValueSet) (*empty.Empty, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301175 logger.Debugw(ctx, "set-ext-value", log.Fields{"device-id": value.Id})
dpaul62686312020-06-23 14:17:36 +05301176 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1177 return nil, err
1178 }
1179
1180 //send request to adapter
1181 ch, err := agent.adapterProxy.SetExtValue(ctx, device, value)
1182 agent.requestQueue.RequestComplete()
1183 if err != nil {
1184 return nil, err
1185 }
1186
1187 // Wait for the adapter response
1188 rpcResponse, ok := <-ch
1189 if !ok {
1190 return nil, status.Errorf(codes.Aborted, "channel-closed-device-id-%s", agent.deviceID)
1191 }
1192 if rpcResponse.Err != nil {
1193 return nil, rpcResponse.Err
1194 }
1195
1196 // Unmarshal and return the response
Himani Chawlab4c25912020-11-12 17:16:38 +05301197 logger.Debug(ctx, "set-ext-value-success-device-agent")
dpaul62686312020-06-23 14:17:36 +05301198 return &empty.Empty{}, nil
1199}
Salman Siddiqui1cf95042020-11-19 00:42:56 +05301200
1201func (agent *Agent) getSingleValue(ctx context.Context, request *extension.SingleGetValueRequest) (*extension.SingleGetValueResponse, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301202 logger.Debugw(ctx, "get-single-value", log.Fields{"device-id": request.TargetId})
Salman Siddiqui1cf95042020-11-19 00:42:56 +05301203
1204 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1205 return nil, err
1206 }
1207
1208 cloned := agent.cloneDeviceWithoutLock()
1209
1210 //send request to adapter
1211 ch, err := agent.adapterProxy.GetSingleValue(ctx, cloned.Adapter, request)
1212 agent.requestQueue.RequestComplete()
1213 if err != nil {
1214 return nil, err
1215 }
1216
1217 // Wait for the adapter response
1218 rpcResponse, ok := <-ch
1219 if !ok {
1220 return nil, status.Errorf(codes.Aborted, "channel-closed-device-id-%s", agent.deviceID)
1221 }
1222
1223 if rpcResponse.Err != nil {
1224 return nil, rpcResponse.Err
1225 }
1226
1227 resp := &extension.SingleGetValueResponse{}
1228 if err := ptypes.UnmarshalAny(rpcResponse.Reply, resp); err != nil {
1229 return nil, status.Errorf(codes.InvalidArgument, "%s", err.Error())
1230 }
1231
1232 return resp, nil
1233}
1234
1235func (agent *Agent) setSingleValue(ctx context.Context, request *extension.SingleSetValueRequest) (*extension.SingleSetValueResponse, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301236 logger.Debugw(ctx, "set-single-value", log.Fields{"device-id": request.TargetId})
Salman Siddiqui1cf95042020-11-19 00:42:56 +05301237
1238 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1239 return nil, err
1240 }
1241
1242 cloned := agent.cloneDeviceWithoutLock()
1243
1244 //send request to adapter
1245 ch, err := agent.adapterProxy.SetSingleValue(ctx, cloned.Adapter, request)
1246 agent.requestQueue.RequestComplete()
1247 if err != nil {
1248 return nil, err
1249 }
1250
1251 // Wait for the adapter response
1252 rpcResponse, ok := <-ch
1253 if !ok {
1254 return nil, status.Errorf(codes.Aborted, "channel-closed-cloned-id-%s", agent.deviceID)
1255 }
1256
1257 if rpcResponse.Err != nil {
1258 return nil, rpcResponse.Err
1259 }
1260
1261 resp := &extension.SingleSetValueResponse{}
1262 if err := ptypes.UnmarshalAny(rpcResponse.Reply, resp); err != nil {
1263 return nil, status.Errorf(codes.InvalidArgument, "%s", err.Error())
1264 }
1265
1266 return resp, nil
1267}
Maninder0aabf0c2021-03-17 14:55:14 +05301268
1269// The device lock MUST be held by the caller.
1270func (agent *Agent) proceedWithRequestNoLock() bool {
1271 return !agent.isDeletionInProgress() && !agent.isReconcileInProgress()
1272}
1273
1274func (agent *Agent) stopReconcile() {
1275 agent.stopReconcilingMutex.Lock()
1276 if agent.stopReconciling != nil {
1277 agent.stopReconciling <- 0
1278 }
1279 agent.stopReconcilingMutex.Unlock()
1280}
1281
1282func (agent *Agent) ReconcileDevice(ctx context.Context, device *voltha.Device) {
1283 var desc string
1284 operStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
1285
1286 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1287 desc = err.Error()
1288 agent.logDeviceUpdate(ctx, "Reconciling", nil, nil, operStatus, &desc)
1289 return
1290 }
1291
1292 if !agent.proceedWithRequestNoLock() {
1293 agent.requestQueue.RequestComplete()
1294 desc = fmt.Sprintf("Either device is in deletion or reconcile is already in progress for device : %s", device.Id)
1295 logger.Errorf(ctx, desc)
1296 agent.logDeviceUpdate(ctx, "Reconciling", nil, nil, operStatus, &desc)
1297 return
1298 }
1299
1300 //set transient state to RECONCILE IN PROGRESS
1301 err := agent.updateTransientState(ctx, voltha.DeviceTransientState_RECONCILE_IN_PROGRESS)
1302 if err != nil {
1303 agent.requestQueue.RequestComplete()
1304 desc = fmt.Sprintf("Not able to set device transient state to Reconcile in progress."+
1305 "Err: %s", err.Error())
1306 logger.Errorf(ctx, desc)
1307 agent.logDeviceUpdate(ctx, "Reconciling", nil, nil, operStatus, &desc)
1308 return
1309 }
1310
1311 logger.Debugw(ctx, "retrying-reconciling", log.Fields{"deviceID": device.Id})
1312 reconcilingBackoff := backoff.NewExponentialBackOff()
1313 reconcilingBackoff.InitialInterval = agent.config.BackoffRetryInitialInterval
1314 reconcilingBackoff.MaxElapsedTime = agent.config.BackoffRetryMaxElapsedTime
1315 reconcilingBackoff.MaxInterval = agent.config.BackoffRetryMaxInterval
1316
1317 //making here to keep lifecycle of this channel within the scope of retryReconcile
1318 agent.stopReconcilingMutex.Lock()
1319 agent.stopReconciling = make(chan int)
1320 agent.stopReconcilingMutex.Unlock()
1321
1322Loop:
1323 for {
1324 // Use an exponential back off to prevent getting into a tight loop
1325 duration := reconcilingBackoff.NextBackOff()
1326 //This case should never occur in default case as max elapsed time for backoff is 0(by default) , so it will never return stop
1327 if duration == backoff.Stop {
1328 // If we reach a maximum then warn and reset the backoff
1329 // timer and keep attempting.
1330 logger.Warnw(ctx, "maximum-reconciling-backoff-reached--resetting-backoff-timer",
1331 log.Fields{"max-reconciling-backoff": reconcilingBackoff.MaxElapsedTime,
1332 "device-id": device.Id})
1333 reconcilingBackoff.Reset()
1334 duration = reconcilingBackoff.NextBackOff()
1335 }
1336
1337 backoffTimer := time.NewTimer(duration)
1338
1339 // Send a reconcile request to the adapter.
1340 ch, err := agent.adapterProxy.ReconcileDevice(ctx, agent.device)
1341 //release lock before moving further
1342 agent.requestQueue.RequestComplete()
1343 if err != nil {
1344 desc := fmt.Sprintf("Failed reconciling from adapter side. Err: %s", err.Error())
1345 agent.logDeviceUpdate(ctx, "Reconciling", nil, nil, operStatus, &desc)
1346 <-backoffTimer.C
1347 // backoffTimer expired continue
1348 // Take lock back before retrying
1349 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1350 desc = err.Error()
1351 agent.logDeviceUpdate(ctx, "Reconciling", nil, nil, operStatus, &desc)
1352 return
1353 }
1354 continue
1355 }
1356
1357 // if return err retry if not then break loop and quit retrying reconcile
1358 if err = agent.waitForReconcileResponse(backoffTimer, ch); err != nil {
1359 desc = err.Error()
1360 logger.Errorf(ctx, desc)
1361 agent.logDeviceUpdate(ctx, "Reconciling", nil, nil, operStatus, &desc)
1362 } else {
1363 operStatus = &common.OperationResp{Code: common.OperationResp_OPERATION_IN_PROGRESS}
1364 agent.logDeviceUpdate(ctx, "Reconciling", nil, nil, operStatus, &desc)
1365 break Loop
1366 }
1367
1368 // Take lock back before retrying
1369 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1370 desc = err.Error()
1371 agent.logDeviceUpdate(ctx, "Reconciling", nil, nil, operStatus, &desc)
1372 return
1373 }
1374 }
1375}
1376
1377func (agent *Agent) waitForReconcileResponse(backoffTimer *time.Timer, ch chan *kafka.RpcResponse) error {
1378 select {
1379 // wait for response
1380 case resp, ok := <-ch:
1381 if !ok {
1382 //channel-closed
1383 return errors.New("channel on which reconcile response is awaited is closed")
1384 } else if resp.Err != nil {
1385 //error encountered
1386 return errors.New("error encountered while retrying reconcile")
1387 }
1388
1389 //In case of success quit retrying and wait for adapter to reset operation state of device
1390 agent.stopReconcilingMutex.Lock()
1391 agent.stopReconciling = nil
1392 agent.stopReconcilingMutex.Unlock()
1393 return nil
1394
1395 //if reconciling need to be stopped
1396 case _, ok := <-agent.stopReconciling:
1397 agent.stopReconcilingMutex.Lock()
1398 agent.stopReconciling = nil
1399 agent.stopReconcilingMutex.Unlock()
1400 if !ok {
1401 //channel-closed
1402 return errors.New("channel used to notify to stop reconcile is closed")
1403 }
1404 return nil
1405 //continue if timer expired
1406 case <-backoffTimer.C:
1407 }
1408 return nil
1409}
1410
1411func (agent *Agent) reconcilingCleanup(ctx context.Context) error {
1412 var desc string
1413 operStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
1414 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1415 desc = err.Error()
1416 agent.logDeviceUpdate(ctx, "Reconciling", nil, nil, operStatus, &desc)
1417 return err
1418 }
1419 defer agent.requestQueue.RequestComplete()
1420 err := agent.updateTransientState(ctx, voltha.DeviceTransientState_NONE)
1421 if err != nil {
1422 desc = fmt.Sprintf("Not able to clear device transient state from Reconcile in progress."+
1423 "Err: %s", err.Error())
1424 logger.Errorf(ctx, desc)
1425 agent.logDeviceUpdate(ctx, "Reconciling", nil, nil, operStatus, &desc)
1426 return err
1427 }
1428 operStatus = &common.OperationResp{Code: common.OperationResp_OPERATION_SUCCESS}
1429 agent.logDeviceUpdate(ctx, "Reconciling", nil, nil, operStatus, &desc)
1430 return nil
1431}