blob: 7e401aa527aa9cfe0b0f7d60099749737f9c2879 [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"
Maninder9a1bc0d2020-10-26 11:34:02 +053024 "github.com/gogo/protobuf/proto"
25 "github.com/golang/protobuf/ptypes"
26 "github.com/golang/protobuf/ptypes/empty"
27 "google.golang.org/grpc/codes"
28 "google.golang.org/grpc/status"
Mahir Gunyeladdb66a2020-04-29 18:08:50 -070029 "reflect"
30 "sync"
31 "time"
32
Himani Chawla2ba1c9c2020-10-07 13:19:03 +053033 "github.com/opencord/voltha-go/db/model"
Kent Hagerman2b216042020-04-03 18:28:56 -040034 "github.com/opencord/voltha-go/rw_core/core/adapter"
Mahir Gunyel03de0d32020-06-03 01:36:59 -070035 "github.com/opencord/voltha-go/rw_core/core/device/flow"
36 "github.com/opencord/voltha-go/rw_core/core/device/group"
Kent Hagerman2a07b862020-06-19 15:23:07 -040037 "github.com/opencord/voltha-go/rw_core/core/device/port"
Kent Hagerman2b216042020-04-03 18:28:56 -040038 "github.com/opencord/voltha-go/rw_core/core/device/remote"
Himani Chawla2ba1c9c2020-10-07 13:19:03 +053039 "github.com/opencord/voltha-go/rw_core/core/device/transientstate"
Scott Bakerb671a862019-10-24 10:53:40 -070040 coreutils "github.com/opencord/voltha-go/rw_core/utils"
Himani Chawla2ba1c9c2020-10-07 13:19:03 +053041 "github.com/opencord/voltha-lib-go/v4/pkg/kafka"
Maninderdfadc982020-10-28 14:04:33 +053042 "github.com/opencord/voltha-lib-go/v4/pkg/log"
Maninder9a1bc0d2020-10-26 11:34:02 +053043 "github.com/opencord/voltha-protos/v4/go/common"
Salman Siddiqui1cf95042020-11-19 00:42:56 +053044 "github.com/opencord/voltha-protos/v4/go/extension"
Maninderdfadc982020-10-28 14:04:33 +053045 ic "github.com/opencord/voltha-protos/v4/go/inter_container"
46 ofp "github.com/opencord/voltha-protos/v4/go/openflow_13"
47 "github.com/opencord/voltha-protos/v4/go/voltha"
khenaidoob9203542018-09-17 22:56:37 -040048)
49
Kent Hagerman2b216042020-04-03 18:28:56 -040050// Agent represents device agent attributes
51type Agent struct {
Kent Hagermanf5a67352020-04-30 15:15:26 -040052 deviceID string
53 parentID string
54 deviceType string
Kent Hagerman2a07b862020-06-19 15:23:07 -040055 isRootDevice bool
Kent Hagermanf5a67352020-04-30 15:15:26 -040056 adapterProxy *remote.AdapterProxy
57 adapterMgr *adapter.Manager
58 deviceMgr *Manager
59 dbProxy *model.Proxy
60 exitChannel chan int
61 device *voltha.Device
62 requestQueue *coreutils.RequestQueue
63 defaultTimeout time.Duration
64 startOnce sync.Once
65 stopOnce sync.Once
66 stopped bool
Mahir Gunyel03de0d32020-06-03 01:36:59 -070067
Himani Chawla2ba1c9c2020-10-07 13:19:03 +053068 flowLoader *flow.Loader
69 groupLoader *group.Loader
70 portLoader *port.Loader
71 transientStateLoader *transientstate.Loader
khenaidoob9203542018-09-17 22:56:37 -040072}
73
Kent Hagerman2b216042020-04-03 18:28:56 -040074//newAgent creates a new device agent. The device will be initialized when start() is called.
Kent Hagerman2a07b862020-06-19 15:23:07 -040075func newAgent(ap *remote.AdapterProxy, device *voltha.Device, deviceMgr *Manager, dbPath *model.Path, deviceProxy *model.Proxy, timeout time.Duration) *Agent {
76 deviceID := device.Id
77 if deviceID == "" {
78 deviceID = coreutils.CreateDeviceID()
Stephane Barbarie1ab43272018-12-08 21:42:13 -050079 }
Scott Baker80678602019-11-14 16:57:36 -080080
Kent Hagerman2a07b862020-06-19 15:23:07 -040081 return &Agent{
Himani Chawla2ba1c9c2020-10-07 13:19:03 +053082 deviceID: deviceID,
83 adapterProxy: ap,
84 isRootDevice: device.Root,
85 parentID: device.ParentId,
86 deviceType: device.Type,
87 deviceMgr: deviceMgr,
88 adapterMgr: deviceMgr.adapterMgr,
89 exitChannel: make(chan int, 1),
90 dbProxy: deviceProxy,
91 defaultTimeout: timeout,
92 device: proto.Clone(device).(*voltha.Device),
93 requestQueue: coreutils.NewRequestQueue(),
94 flowLoader: flow.NewLoader(dbPath.SubPath("flows").Proxy(deviceID)),
95 groupLoader: group.NewLoader(dbPath.SubPath("groups").Proxy(deviceID)),
96 portLoader: port.NewLoader(dbPath.SubPath("ports").Proxy(deviceID)),
97 transientStateLoader: transientstate.NewLoader(dbPath.SubPath("core").Proxy("transientstate"), deviceID),
Kent Hagerman2a07b862020-06-19 15:23:07 -040098 }
khenaidoob9203542018-09-17 22:56:37 -040099}
100
khenaidoo442e7c72020-03-10 16:13:48 -0400101// start() saves the device to the data model and registers for callbacks on that device if deviceToCreate!=nil.
102// 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 -0800103// was started.
Kent Hagerman2b216042020-04-03 18:28:56 -0400104func (agent *Agent) start(ctx context.Context, deviceToCreate *voltha.Device) (*voltha.Device, error) {
khenaidoo442e7c72020-03-10 16:13:48 -0400105 needToStart := false
106 if agent.startOnce.Do(func() { needToStart = true }); !needToStart {
Kent Hagermancba2f302020-07-28 13:37:36 -0400107 return agent.getDeviceReadOnly(ctx)
khenaidoo442e7c72020-03-10 16:13:48 -0400108 }
109 var startSucceeded bool
110 defer func() {
111 if !startSucceeded {
112 if err := agent.stop(ctx); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000113 logger.Errorw(ctx, "failed-to-cleanup-after-unsuccessful-start", log.Fields{"device-id": agent.deviceID, "error": err})
khenaidoo442e7c72020-03-10 16:13:48 -0400114 }
115 }
116 }()
Scott Baker80678602019-11-14 16:57:36 -0800117
khenaidoo442e7c72020-03-10 16:13:48 -0400118 var device *voltha.Device
Scott Baker80678602019-11-14 16:57:36 -0800119 if deviceToCreate == nil {
120 // Load the existing device
Kent Hagerman4f355f52020-03-30 16:01:33 -0400121 device := &voltha.Device{}
Kent Hagermanf5a67352020-04-30 15:15:26 -0400122 have, err := agent.dbProxy.Get(ctx, agent.deviceID, device)
Thomas Lee Se5a44012019-11-07 20:32:24 +0530123 if err != nil {
Thomas Lee Se5a44012019-11-07 20:32:24 +0530124 return nil, err
Kent Hagerman4f355f52020-03-30 16:01:33 -0400125 } else if !have {
126 return nil, status.Errorf(codes.NotFound, "device-%s", agent.deviceID)
Thomas Lee Se5a44012019-11-07 20:32:24 +0530127 }
Kent Hagerman4f355f52020-03-30 16:01:33 -0400128
129 agent.deviceType = device.Adapter
130 agent.device = proto.Clone(device).(*voltha.Device)
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700131 // load the flows and groups from KV to cache
132 agent.flowLoader.Load(ctx)
133 agent.groupLoader.Load(ctx)
Kent Hagerman2a07b862020-06-19 15:23:07 -0400134 agent.portLoader.Load(ctx)
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530135 agent.transientStateLoader.Load(ctx)
Kent Hagerman4f355f52020-03-30 16:01:33 -0400136
Himani Chawlab4c25912020-11-12 17:16:38 +0530137 logger.Infow(ctx, "device-loaded-from-db", log.Fields{"device-id": agent.deviceID})
khenaidoo297cd252019-02-07 22:10:23 -0500138 } else {
Scott Baker80678602019-11-14 16:57:36 -0800139 // Create a new device
Maninder9a1bc0d2020-10-26 11:34:02 +0530140 var desc string
141 prevState := common.AdminState_UNKNOWN
142 currState := common.AdminState_UNKNOWN
143 operStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
144
145 defer agent.logDeviceUpdate(ctx, "createDevice", &prevState, &currState, operStatus, &desc)
146
Kent Hagermanf5a67352020-04-30 15:15:26 -0400147 // Assumption is that AdminState, FlowGroups, and Flows are uninitialized since this
148 // is a new device, so populate them here before passing the device to ldProxy.Set.
Kent Hagerman2b216042020-04-03 18:28:56 -0400149 // agent.deviceId will also have been set during newAgent().
Scott Baker80678602019-11-14 16:57:36 -0800150 device = (proto.Clone(deviceToCreate)).(*voltha.Device)
npujar1d86a522019-11-14 17:11:16 +0530151 device.Id = agent.deviceID
Scott Baker80678602019-11-14 16:57:36 -0800152 device.AdminState = voltha.AdminState_PREPROVISIONED
Maninder9a1bc0d2020-10-26 11:34:02 +0530153 currState = device.AdminState
Scott Baker80678602019-11-14 16:57:36 -0800154 if !deviceToCreate.GetRoot() && deviceToCreate.ProxyAddress != nil {
155 // Set the default vlan ID to the one specified by the parent adapter. It can be
156 // overwritten by the child adapter during a device update request
157 device.Vlan = deviceToCreate.ProxyAddress.ChannelId
158 }
159
khenaidoo297cd252019-02-07 22:10:23 -0500160 // Add the initial device to the local model
Kent Hagermanf5a67352020-04-30 15:15:26 -0400161 if err := agent.dbProxy.Set(ctx, agent.deviceID, device); err != nil {
Maninder9a1bc0d2020-10-26 11:34:02 +0530162 desc = fmt.Sprintf("failed-adding-device-%s: %s", agent.deviceID, err.Error())
Kent Hagerman4f355f52020-03-30 16:01:33 -0400163 return nil, status.Errorf(codes.Aborted, "failed-adding-device-%s: %s", agent.deviceID, err)
khenaidoo297cd252019-02-07 22:10:23 -0500164 }
Maninder9a1bc0d2020-10-26 11:34:02 +0530165 operStatus.Code = common.OperationResp_OPERATION_SUCCESS
khenaidoo442e7c72020-03-10 16:13:48 -0400166 agent.device = device
khenaidoob9203542018-09-17 22:56:37 -0400167 }
khenaidoo442e7c72020-03-10 16:13:48 -0400168 startSucceeded = true
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000169 log.EnrichSpan(ctx, log.Fields{"device-id": agent.deviceID})
Rohan Agrawal31f21802020-06-12 05:38:46 +0000170 logger.Debugw(ctx, "device-agent-started", log.Fields{"device-id": agent.deviceID})
khenaidoo442e7c72020-03-10 16:13:48 -0400171
Kent Hagermancba2f302020-07-28 13:37:36 -0400172 return agent.getDeviceReadOnly(ctx)
khenaidoob9203542018-09-17 22:56:37 -0400173}
174
khenaidoo4d4802d2018-10-04 21:59:49 -0400175// stop stops the device agent. Not much to do for now
Kent Hagerman2b216042020-04-03 18:28:56 -0400176func (agent *Agent) stop(ctx context.Context) error {
khenaidoo442e7c72020-03-10 16:13:48 -0400177 needToStop := false
178 if agent.stopOnce.Do(func() { needToStop = true }); !needToStop {
179 return nil
180 }
181 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
182 return err
183 }
184 defer agent.requestQueue.RequestComplete()
khenaidoo49085352020-01-13 19:15:43 -0500185
Himani Chawlab4c25912020-11-12 17:16:38 +0530186 logger.Infow(ctx, "stopping-device-agent", log.Fields{"device-id": agent.deviceID, "parent-id": agent.parentID})
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530187 // Remove the device transient loader
188 if err := agent.deleteTransientState(ctx); err != nil {
189 return err
190 }
khenaidoo0a822f92019-05-08 15:15:57 -0400191 // Remove the device from the KV store
Kent Hagermanf5a67352020-04-30 15:15:26 -0400192 if err := agent.dbProxy.Remove(ctx, agent.deviceID); err != nil {
khenaidoo442e7c72020-03-10 16:13:48 -0400193 return err
Thomas Lee Se5a44012019-11-07 20:32:24 +0530194 }
khenaidoo442e7c72020-03-10 16:13:48 -0400195
khenaidoo442e7c72020-03-10 16:13:48 -0400196 close(agent.exitChannel)
197
198 agent.stopped = true
199
Rohan Agrawal31f21802020-06-12 05:38:46 +0000200 logger.Infow(ctx, "device-agent-stopped", log.Fields{"device-id": agent.deviceID, "parent-id": agent.parentID})
khenaidoo442e7c72020-03-10 16:13:48 -0400201
202 return nil
khenaidoob9203542018-09-17 22:56:37 -0400203}
204
Scott Baker80678602019-11-14 16:57:36 -0800205// Load the most recent state from the KVStore for the device.
Kent Hagerman2b216042020-04-03 18:28:56 -0400206func (agent *Agent) reconcileWithKVStore(ctx context.Context) {
khenaidoo442e7c72020-03-10 16:13:48 -0400207 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000208 logger.Warnw(ctx, "request-aborted", log.Fields{"device-id": agent.deviceID, "error": err})
khenaidoo442e7c72020-03-10 16:13:48 -0400209 return
210 }
211 defer agent.requestQueue.RequestComplete()
Rohan Agrawal31f21802020-06-12 05:38:46 +0000212 logger.Debug(ctx, "reconciling-device-agent-devicetype")
Scott Baker80678602019-11-14 16:57:36 -0800213 // TODO: context timeout
Kent Hagerman4f355f52020-03-30 16:01:33 -0400214 device := &voltha.Device{}
Kent Hagermanf5a67352020-04-30 15:15:26 -0400215 if have, err := agent.dbProxy.Get(ctx, agent.deviceID, device); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000216 logger.Errorw(ctx, "kv-get-failed", log.Fields{"device-id": agent.deviceID, "error": err})
Thomas Lee Se5a44012019-11-07 20:32:24 +0530217 return
Kent Hagerman4f355f52020-03-30 16:01:33 -0400218 } else if !have {
219 return // not found in kv
Thomas Lee Se5a44012019-11-07 20:32:24 +0530220 }
Kent Hagerman4f355f52020-03-30 16:01:33 -0400221
222 agent.deviceType = device.Adapter
223 agent.device = device
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700224 agent.flowLoader.Load(ctx)
225 agent.groupLoader.Load(ctx)
Kent Hagerman2a07b862020-06-19 15:23:07 -0400226 agent.portLoader.Load(ctx)
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530227 agent.transientStateLoader.Load(ctx)
228
Rohan Agrawal31f21802020-06-12 05:38:46 +0000229 logger.Debugw(ctx, "reconciled-device-agent-devicetype", log.Fields{"device-id": agent.deviceID, "type": agent.deviceType})
Scott Baker80678602019-11-14 16:57:36 -0800230}
231
khenaidoo442e7c72020-03-10 16:13:48 -0400232// onSuccess is a common callback for scenarios where we receive a nil response following a request to an adapter
233// and the only action required is to publish a successful result on kafka
Rohan Agrawal31f21802020-06-12 05:38:46 +0000234func (agent *Agent) onSuccess(ctx context.Context, rpc string, response interface{}, reqArgs ...interface{}) {
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530235 logger.Debugw(ctx, "response-successful", log.Fields{"rpc": rpc, "device-id": agent.deviceID})
khenaidoo442e7c72020-03-10 16:13:48 -0400236 // TODO: Post success message onto kafka
237}
238
239// onFailure is a common callback for scenarios where we receive an error response following a request to an adapter
240// and the only action required is to publish the failed result on kafka
Rohan Agrawal31f21802020-06-12 05:38:46 +0000241func (agent *Agent) onFailure(ctx context.Context, rpc string, response interface{}, reqArgs ...interface{}) {
khenaidoo442e7c72020-03-10 16:13:48 -0400242 if res, ok := response.(error); ok {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000243 logger.Errorw(ctx, "rpc-failed", log.Fields{"rpc": rpc, "device-id": agent.deviceID, "error": res, "args": reqArgs})
khenaidoo442e7c72020-03-10 16:13:48 -0400244 } else {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000245 logger.Errorw(ctx, "rpc-failed-invalid-error", log.Fields{"rpc": rpc, "device-id": agent.deviceID, "args": reqArgs})
khenaidoo442e7c72020-03-10 16:13:48 -0400246 }
247 // TODO: Post failure message onto kafka
248}
249
Himani Chawlab4c25912020-11-12 17:16:38 +0530250func (agent *Agent) waitForAdapterForceDeleteResponse(ctx context.Context, cancel context.CancelFunc, rpc string, ch chan *kafka.RpcResponse,
khenaidoo442e7c72020-03-10 16:13:48 -0400251 onSuccess coreutils.ResponseCallback, onFailure coreutils.ResponseCallback, reqArgs ...interface{}) {
252 defer cancel()
253 select {
254 case rpcResponse, ok := <-ch:
255 if !ok {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000256 onFailure(ctx, rpc, status.Errorf(codes.Aborted, "channel-closed"), reqArgs)
khenaidoo442e7c72020-03-10 16:13:48 -0400257 } else if rpcResponse.Err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000258 onFailure(ctx, rpc, rpcResponse.Err, reqArgs)
khenaidoo442e7c72020-03-10 16:13:48 -0400259 } else {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000260 onSuccess(ctx, rpc, rpcResponse.Reply, reqArgs)
khenaidoo442e7c72020-03-10 16:13:48 -0400261 }
262 case <-ctx.Done():
Rohan Agrawal31f21802020-06-12 05:38:46 +0000263 onFailure(ctx, rpc, ctx.Err(), reqArgs)
khenaidoo442e7c72020-03-10 16:13:48 -0400264 }
265}
266
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530267// onDeleteSuccess is a common callback for scenarios where we receive a nil response following a delete request
268// to an adapter.
269func (agent *Agent) onDeleteSuccess(ctx context.Context, rpc string, response interface{}, reqArgs ...interface{}) {
270 logger.Debugw(ctx, "response-successful", log.Fields{"rpc": rpc, "device-id": agent.deviceID})
271 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
272 logger.Errorw(ctx, "delete-device-failure", log.Fields{"device-id": agent.deviceID, "error": err, "args": reqArgs})
273 }
274 previousDeviceTransientState := agent.getTransientState()
275 newDevice := agent.cloneDeviceWithoutLock()
276 if err := agent.updateDeviceWithTransientStateAndReleaseLock(ctx, newDevice,
277 voltha.DeviceTransientState_DELETING_POST_ADAPTER_RESPONSE, previousDeviceTransientState); err != nil {
278 logger.Errorw(ctx, "delete-device-failure", log.Fields{"device-id": agent.deviceID, "error": err, "args": reqArgs})
279 }
280}
281
282// onDeleteFailure is a common callback for scenarios where we receive an error response following a delete request
283// to an adapter and the only action required is to return the error response.
284func (agent *Agent) onDeleteFailure(ctx context.Context, rpc string, response interface{}, reqArgs ...interface{}) {
285 if res, ok := response.(error); ok {
286 logger.Errorw(ctx, "rpc-failed", log.Fields{"rpc": rpc, "device-id": agent.deviceID, "error": res, "args": reqArgs})
287 } else {
288 logger.Errorw(ctx, "rpc-failed-invalid-error", log.Fields{"rpc": rpc, "device-id": agent.deviceID, "args": reqArgs})
289 }
290 //Only updating of transient state is required, no transition.
291 if err := agent.updateTransientState(ctx, voltha.DeviceTransientState_DELETE_FAILED); err != nil {
292 logger.Errorw(ctx, "failed-to-update-transient-state-as-delete-failed", log.Fields{"device-id": agent.deviceID})
293 }
294
295}
296
Himani Chawlab4c25912020-11-12 17:16:38 +0530297func (agent *Agent) waitForAdapterResponse(ctx context.Context, cancel context.CancelFunc, rpc string, ch chan *kafka.RpcResponse,
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530298 onSuccess coreutils.ResponseCallback, onFailure coreutils.ResponseCallback, reqArgs ...interface{}) {
299 defer cancel()
Himani Chawlab4c25912020-11-12 17:16:38 +0530300 var rpce *voltha.RPCEvent
301 defer func() {
302 if rpce != nil {
303 go agent.deviceMgr.SendRPCEvent(ctx, "RPC_ERROR_RAISE_EVENT", rpce,
304 voltha.EventCategory_COMMUNICATION, nil, time.Now().UnixNano())
305 }
306 }()
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530307 select {
308 case rpcResponse, ok := <-ch:
309 if !ok {
Himani Chawlab4c25912020-11-12 17:16:38 +0530310 rpce = agent.deviceMgr.NewRPCEvent(ctx, agent.deviceID, "Response Channel Closed", nil)
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530311 onFailure(ctx, rpc, status.Errorf(codes.Aborted, "channel-closed"), reqArgs)
Himani Chawlab4c25912020-11-12 17:16:38 +0530312 //add failure
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530313 } else if rpcResponse.Err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530314 rpce = agent.deviceMgr.NewRPCEvent(ctx, agent.deviceID, rpcResponse.Err.Error(), nil)
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530315 onFailure(ctx, rpc, rpcResponse.Err, reqArgs)
Himani Chawlab4c25912020-11-12 17:16:38 +0530316 //add failure
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530317 } else {
318 onSuccess(ctx, rpc, rpcResponse.Reply, reqArgs)
319 }
320 case <-ctx.Done():
Himani Chawlab4c25912020-11-12 17:16:38 +0530321 rpce = agent.deviceMgr.NewRPCEvent(ctx, agent.deviceID, ctx.Err().Error(), nil)
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530322 onFailure(ctx, rpc, ctx.Err(), reqArgs)
323 }
324}
325
Maninder9a1bc0d2020-10-26 11:34:02 +0530326func (agent *Agent) waitForAdapterResponseAndLogDeviceUpdate(ctx context.Context, cancel context.CancelFunc, rpc string, ch chan *kafka.RpcResponse,
327 onSuccess coreutils.ResponseCallback, onFailure coreutils.ResponseCallback, prevState *common.AdminState_Types, reqArgs ...interface{}) {
328 defer cancel()
329 var desc string
330 operStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
khenaidoodd3324d2021-04-27 16:22:55 -0400331 defer func() {
332 currAdminState := prevState
333 if d, _ := agent.getDeviceReadOnly(ctx); d != nil {
334 currAdminState = &d.AdminState
335 }
336 agent.logDeviceUpdate(ctx, rpc, prevState, currAdminState, operStatus, &desc)
337 }()
Maninder9a1bc0d2020-10-26 11:34:02 +0530338 var rpce *voltha.RPCEvent
339 defer func() {
340 if rpce != nil {
341 go agent.deviceMgr.SendRPCEvent(ctx, "RPC_ERROR_RAISE_EVENT", rpce,
342 voltha.EventCategory_COMMUNICATION, nil, time.Now().UnixNano())
343 }
344 }()
345
346 select {
347 case rpcResponse, ok := <-ch:
348 if !ok {
349 rpce = agent.deviceMgr.NewRPCEvent(ctx, agent.deviceID, "Response Channel Closed", nil)
350 onFailure(ctx, rpc, status.Errorf(codes.Aborted, "channel-closed"), reqArgs)
351 //add failure
352 } else if rpcResponse.Err != nil {
353 desc = rpcResponse.Err.Error()
354 rpce = agent.deviceMgr.NewRPCEvent(ctx, agent.deviceID, desc, nil)
355 onFailure(ctx, rpc, rpcResponse.Err, reqArgs)
356 //add failure
357 } else {
358 operStatus.Code = common.OperationResp_OPERATION_SUCCESS
359 onSuccess(ctx, rpc, rpcResponse.Reply, reqArgs)
360 }
361 case <-ctx.Done():
362 desc = ctx.Err().Error()
363 rpce = agent.deviceMgr.NewRPCEvent(ctx, agent.deviceID, desc, nil)
364 onFailure(ctx, rpc, ctx.Err(), reqArgs)
365 }
366}
367
Kent Hagermancba2f302020-07-28 13:37:36 -0400368// getDeviceReadOnly returns a device which MUST NOT be modified, but is safe to keep forever.
369func (agent *Agent) getDeviceReadOnly(ctx context.Context) (*voltha.Device, error) {
khenaidoo442e7c72020-03-10 16:13:48 -0400370 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
371 return nil, err
372 }
373 defer agent.requestQueue.RequestComplete()
Kent Hagermancba2f302020-07-28 13:37:36 -0400374 return agent.device, nil
khenaidoo92e62c52018-10-03 14:02:54 -0400375}
376
Kent Hagermancba2f302020-07-28 13:37:36 -0400377// 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 -0400378// The device lock MUST be held by the caller.
Kent Hagermancba2f302020-07-28 13:37:36 -0400379func (agent *Agent) getDeviceReadOnlyWithoutLock() *voltha.Device {
khenaidoo0db4c812020-05-27 15:27:30 -0400380 return agent.device
khenaidoo92e62c52018-10-03 14:02:54 -0400381}
382
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400383// cloneDeviceWithoutLock returns a copy of the device which is safe to modify.
384// The device lock MUST be held by the caller.
385func (agent *Agent) cloneDeviceWithoutLock() *voltha.Device {
386 return proto.Clone(agent.device).(*voltha.Device)
387}
388
khenaidoo3ab34882019-05-02 21:33:30 -0400389// enableDevice activates a preprovisioned or a disable device
Kent Hagerman2b216042020-04-03 18:28:56 -0400390func (agent *Agent) enableDevice(ctx context.Context) error {
Maninder9a1bc0d2020-10-26 11:34:02 +0530391 //To preserve and use oldDevice state as prev state in new device
Maninder9a1bc0d2020-10-26 11:34:02 +0530392 var desc string
393 operStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
394
395 defer agent.logDeviceUpdate(ctx, "enableDevice", nil, nil, operStatus, &desc)
396
khenaidoo442e7c72020-03-10 16:13:48 -0400397 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
398 return err
399 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530400 logger.Debugw(ctx, "enable-device", log.Fields{"device-id": agent.deviceID})
khenaidoo21d51152019-02-01 13:48:37 -0500401
khenaidoodd3324d2021-04-27 16:22:55 -0400402 prevDeviceState := agent.device.AdminState
403
Kent Hagermancba2f302020-07-28 13:37:36 -0400404 oldDevice := agent.getDeviceReadOnlyWithoutLock()
Maninder9a1bc0d2020-10-26 11:34:02 +0530405
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400406 if oldDevice.AdminState == voltha.AdminState_ENABLED {
407 logger.Warnw(ctx, "device-already-enabled", log.Fields{"device-id": agent.deviceID})
408 agent.requestQueue.RequestComplete()
Maninder9a1bc0d2020-10-26 11:34:02 +0530409 desc = fmt.Sprintf("cannot-enable-an-already-enabled-device: %s", oldDevice.Id)
410 return status.Error(codes.FailedPrecondition, desc)
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400411 }
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530412 if agent.isDeletionInProgress() {
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400413 agent.requestQueue.RequestComplete()
Maninder9a1bc0d2020-10-26 11:34:02 +0530414
415 operStatus.Code = common.OperationResp_OPERATION_IN_PROGRESS
416
417 desc = fmt.Sprintf("deviceId:%s, Device deletion is in progress.", agent.deviceID)
418 return status.Error(codes.FailedPrecondition, desc)
419
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400420 }
npujar1d86a522019-11-14 17:11:16 +0530421 // 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 -0400422 // pre-provisioned with the required adapter not registered. At this stage, since we need to communicate
npujar1d86a522019-11-14 17:11:16 +0530423 // with the adapter then we need to know the adapter that will handle this request
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400424 adapterName, err := agent.adapterMgr.GetAdapterType(oldDevice.Type)
npujar1d86a522019-11-14 17:11:16 +0530425 if err != nil {
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400426 agent.requestQueue.RequestComplete()
Maninder9a1bc0d2020-10-26 11:34:02 +0530427 desc = err.Error()
Matteo Scandolod525ae32020-04-02 17:27:29 -0700428 return err
npujar1d86a522019-11-14 17:11:16 +0530429 }
430
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400431 newDevice := agent.cloneDeviceWithoutLock()
432 newDevice.Adapter = adapterName
npujar1d86a522019-11-14 17:11:16 +0530433
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400434 // Update the Admin State and set the operational state to activating before sending the request to the Adapters
435 newDevice.AdminState = voltha.AdminState_ENABLED
436 newDevice.OperStatus = voltha.OperStatus_ACTIVATING
Maninder9a1bc0d2020-10-26 11:34:02 +0530437
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400438 if err := agent.updateDeviceAndReleaseLock(ctx, newDevice); err != nil {
Maninder9a1bc0d2020-10-26 11:34:02 +0530439 desc = err.Error()
npujar1d86a522019-11-14 17:11:16 +0530440 return err
441 }
442
khenaidoo442e7c72020-03-10 16:13:48 -0400443 // 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 -0400444 var ch chan *kafka.RpcResponse
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000445 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
Himani Chawlab4c25912020-11-12 17:16:38 +0530446 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
Maninder9a1bc0d2020-10-26 11:34:02 +0530447 subCtx = coreutils.WithFromTopicMetadataFromContext(subCtx, ctx)
Himani Chawlab4c25912020-11-12 17:16:38 +0530448
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400449 if oldDevice.AdminState == voltha.AdminState_PREPROVISIONED {
450 ch, err = agent.adapterProxy.AdoptDevice(subCtx, newDevice)
khenaidoob9203542018-09-17 22:56:37 -0400451 } else {
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400452 ch, err = agent.adapterProxy.ReEnableDevice(subCtx, newDevice)
khenaidoob9203542018-09-17 22:56:37 -0400453 }
khenaidoo442e7c72020-03-10 16:13:48 -0400454 if err != nil {
455 cancel()
Maninder9a1bc0d2020-10-26 11:34:02 +0530456 desc = err.Error()
khenaidoo442e7c72020-03-10 16:13:48 -0400457 return err
458 }
Maninder9a1bc0d2020-10-26 11:34:02 +0530459
460 operStatus.Code = common.OperationResp_OPERATION_IN_PROGRESS
461
khenaidoo442e7c72020-03-10 16:13:48 -0400462 // Wait for response
Maninder9a1bc0d2020-10-26 11:34:02 +0530463 go agent.waitForAdapterResponseAndLogDeviceUpdate(subCtx, cancel, "enableDevice", ch, agent.onSuccess, agent.onFailure, &prevDeviceState)
khenaidoob9203542018-09-17 22:56:37 -0400464 return nil
465}
466
Maninder9a1bc0d2020-10-26 11:34:02 +0530467func (agent *Agent) waitForAdapterFlowResponse(ctx context.Context, cancel context.CancelFunc, rpc string, ch chan *kafka.RpcResponse, response coreutils.Response) {
khenaidoo442e7c72020-03-10 16:13:48 -0400468 defer cancel()
Maninder9a1bc0d2020-10-26 11:34:02 +0530469 var desc string
470 operStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
471 defer agent.logDeviceUpdate(ctx, rpc, nil, nil, operStatus, &desc)
472
Himani Chawlab4c25912020-11-12 17:16:38 +0530473 var rpce *voltha.RPCEvent
474 defer func() {
475 if rpce != nil {
476 go agent.deviceMgr.SendRPCEvent(ctx, "RPC_ERROR_RAISE_EVENT", rpce,
477 voltha.EventCategory_COMMUNICATION, nil, time.Now().UnixNano())
478 }
479 }()
khenaidoo442e7c72020-03-10 16:13:48 -0400480 select {
481 case rpcResponse, ok := <-ch:
482 if !ok {
Himani Chawlab4c25912020-11-12 17:16:38 +0530483 //add failure
Maninder9a1bc0d2020-10-26 11:34:02 +0530484 desc = "Response Channel Closed"
Himani Chawlab4c25912020-11-12 17:16:38 +0530485 rpce = agent.deviceMgr.NewRPCEvent(ctx, agent.deviceID, "Response Channel Closed", nil)
khenaidoo442e7c72020-03-10 16:13:48 -0400486 response.Error(status.Errorf(codes.Aborted, "channel-closed"))
487 } else if rpcResponse.Err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530488 //add failure
Maninder9a1bc0d2020-10-26 11:34:02 +0530489 desc = rpcResponse.Err.Error()
490 rpce = agent.deviceMgr.NewRPCEvent(ctx, agent.deviceID, desc, nil)
khenaidoo442e7c72020-03-10 16:13:48 -0400491 response.Error(rpcResponse.Err)
492 } else {
Maninder9a1bc0d2020-10-26 11:34:02 +0530493 operStatus.Code = common.OperationResp_OPERATION_SUCCESS
khenaidoo442e7c72020-03-10 16:13:48 -0400494 response.Done()
495 }
496 case <-ctx.Done():
Maninder9a1bc0d2020-10-26 11:34:02 +0530497 desc = ctx.Err().Error()
498 rpce = agent.deviceMgr.NewRPCEvent(ctx, agent.deviceID, desc, nil)
khenaidoo442e7c72020-03-10 16:13:48 -0400499 response.Error(ctx.Err())
khenaidoo2c6a0992019-04-29 13:46:56 -0400500 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400501}
502
A R Karthick5c28f552019-12-11 22:47:44 -0800503//addFlowsAndGroups adds the "newFlows" and "newGroups" from the existing flows/groups and sends the update to the
504//adapters
Kent Hagerman2b216042020-04-03 18:28:56 -0400505func (agent *Agent) addFlowsAndGroups(ctx context.Context, newFlows []*ofp.OfpFlowStats, newGroups []*ofp.OfpGroupEntry, flowMetadata *voltha.FlowMetadata) error {
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700506 var flwResponse, grpResponse coreutils.Response
507 var err error
508 //if new flow list is empty then the called function returns quickly
509 if flwResponse, err = agent.addFlowsToAdapter(ctx, newFlows, flowMetadata); err != nil {
A R Karthick5c28f552019-12-11 22:47:44 -0800510 return err
511 }
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700512 //if new group list is empty then the called function returns quickly
513 if grpResponse, err = agent.addGroupsToAdapter(ctx, newGroups, flowMetadata); err != nil {
514 return err
515 }
516 if errs := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, flwResponse, grpResponse); errs != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000517 logger.Warnw(ctx, "no-adapter-response", log.Fields{"device-id": agent.deviceID, "result": errs})
khenaidoo442e7c72020-03-10 16:13:48 -0400518 return status.Errorf(codes.Aborted, "flow-failure-device-%s", agent.deviceID)
khenaidoo0458db62019-06-20 08:50:36 -0400519 }
khenaidoo0458db62019-06-20 08:50:36 -0400520 return nil
521}
522
A R Karthick5c28f552019-12-11 22:47:44 -0800523//deleteFlowsAndGroups removes the "flowsToDel" and "groupsToDel" from the existing flows/groups and sends the update to the
524//adapters
Kent Hagerman2b216042020-04-03 18:28:56 -0400525func (agent *Agent) deleteFlowsAndGroups(ctx context.Context, flowsToDel []*ofp.OfpFlowStats, groupsToDel []*ofp.OfpGroupEntry, flowMetadata *voltha.FlowMetadata) error {
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700526 var flwResponse, grpResponse coreutils.Response
527 var err error
528 if flwResponse, err = agent.deleteFlowsFromAdapter(ctx, flowsToDel, flowMetadata); err != nil {
A R Karthick5c28f552019-12-11 22:47:44 -0800529 return err
530 }
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700531 if grpResponse, err = agent.deleteGroupsFromAdapter(ctx, groupsToDel, flowMetadata); err != nil {
532 return err
533 }
534
535 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, flwResponse, grpResponse); res != nil {
khenaidoo0458db62019-06-20 08:50:36 -0400536 return status.Errorf(codes.Aborted, "errors-%s", res)
537 }
538 return nil
khenaidoo0458db62019-06-20 08:50:36 -0400539}
540
A R Karthick5c28f552019-12-11 22:47:44 -0800541//updateFlowsAndGroups replaces the existing flows and groups with "updatedFlows" and "updatedGroups" respectively. It
542//also sends the updates to the adapters
Kent Hagerman2b216042020-04-03 18:28:56 -0400543func (agent *Agent) updateFlowsAndGroups(ctx context.Context, updatedFlows []*ofp.OfpFlowStats, updatedGroups []*ofp.OfpGroupEntry, flowMetadata *voltha.FlowMetadata) error {
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700544 var flwResponse, grpResponse coreutils.Response
545 var err error
546 if flwResponse, err = agent.updateFlowsToAdapter(ctx, updatedFlows, flowMetadata); err != nil {
A R Karthick5c28f552019-12-11 22:47:44 -0800547 return err
548 }
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700549 if grpResponse, err = agent.updateGroupsToAdapter(ctx, updatedGroups, flowMetadata); err != nil {
550 return err
551 }
552
553 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, flwResponse, grpResponse); res != nil {
khenaidoo0458db62019-06-20 08:50:36 -0400554 return status.Errorf(codes.Aborted, "errors-%s", res)
555 }
556 return nil
khenaidoo19d7b632018-10-30 10:49:50 -0400557}
558
khenaidoo4d4802d2018-10-04 21:59:49 -0400559//disableDevice disable a device
Kent Hagerman2b216042020-04-03 18:28:56 -0400560func (agent *Agent) disableDevice(ctx context.Context) error {
Maninder9a1bc0d2020-10-26 11:34:02 +0530561 var desc string
562 operStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
563
564 prevDeviceState := agent.device.AdminState
565
566 defer agent.logDeviceUpdate(ctx, "disableDevice", nil, nil, operStatus, &desc)
567
khenaidoo442e7c72020-03-10 16:13:48 -0400568 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
Maninder9a1bc0d2020-10-26 11:34:02 +0530569 desc = err.Error()
khenaidoo442e7c72020-03-10 16:13:48 -0400570 return err
571 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530572 logger.Debugw(ctx, "disable-device", log.Fields{"device-id": agent.deviceID})
khenaidoo6e55d9e2019-12-12 18:26:26 -0500573
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400574 cloned := agent.cloneDeviceWithoutLock()
khenaidoo6e55d9e2019-12-12 18:26:26 -0500575
576 if cloned.AdminState == voltha.AdminState_DISABLED {
Maninder9a1bc0d2020-10-26 11:34:02 +0530577 desc = "device-already-disabled"
divyadesaicb8b59d2020-08-18 09:55:47 +0000578 logger.Debugw(ctx, "device-already-disabled", log.Fields{"device-id": agent.deviceID})
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400579 agent.requestQueue.RequestComplete()
npujar1d86a522019-11-14 17:11:16 +0530580 return nil
581 }
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530582 if cloned.AdminState == voltha.AdminState_PREPROVISIONED {
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400583 agent.requestQueue.RequestComplete()
Maninder9a1bc0d2020-10-26 11:34:02 +0530584 desc = fmt.Sprintf("deviceId:%s, invalid-admin-state:%s", agent.deviceID, cloned.AdminState)
khenaidoo6e55d9e2019-12-12 18:26:26 -0500585 return status.Errorf(codes.FailedPrecondition, "deviceId:%s, invalid-admin-state:%s", agent.deviceID, cloned.AdminState)
npujar1d86a522019-11-14 17:11:16 +0530586 }
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530587 if agent.isDeletionInProgress() {
588 agent.requestQueue.RequestComplete()
589 return status.Errorf(codes.FailedPrecondition, "deviceId:%s, Device deletion is in progress.", agent.deviceID)
590 }
npujar1d86a522019-11-14 17:11:16 +0530591 // Update the Admin State and operational state before sending the request out
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400592 cloned.AdminState = voltha.AdminState_DISABLED
593 cloned.OperStatus = voltha.OperStatus_UNKNOWN
Maninder9a1bc0d2020-10-26 11:34:02 +0530594
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400595 if err := agent.updateDeviceAndReleaseLock(ctx, cloned); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530596 return err
597 }
khenaidoo442e7c72020-03-10 16:13:48 -0400598
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000599 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
Himani Chawlab4c25912020-11-12 17:16:38 +0530600 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
601
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400602 ch, err := agent.adapterProxy.DisableDevice(subCtx, cloned)
khenaidoo442e7c72020-03-10 16:13:48 -0400603 if err != nil {
604 cancel()
Maninder9a1bc0d2020-10-26 11:34:02 +0530605 desc = err.Error()
npujar1d86a522019-11-14 17:11:16 +0530606 return err
khenaidoo0a822f92019-05-08 15:15:57 -0400607 }
Maninder9a1bc0d2020-10-26 11:34:02 +0530608 operStatus.Code = common.OperationResp_OPERATION_IN_PROGRESS
609
610 // Wait for response
611 go agent.waitForAdapterResponseAndLogDeviceUpdate(subCtx, cancel, "disableDevice", ch, agent.onSuccess, agent.onFailure, &prevDeviceState)
khenaidoo0a822f92019-05-08 15:15:57 -0400612
khenaidoo92e62c52018-10-03 14:02:54 -0400613 return nil
614}
615
Kent Hagerman2b216042020-04-03 18:28:56 -0400616func (agent *Agent) rebootDevice(ctx context.Context) error {
Maninder9a1bc0d2020-10-26 11:34:02 +0530617 var desc string
618 operStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
619
620 prevDeviceState := agent.device.AdminState
621
622 defer agent.logDeviceUpdate(ctx, "rebootDevice", nil, nil, operStatus, &desc)
623
khenaidoo442e7c72020-03-10 16:13:48 -0400624 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
Maninder9a1bc0d2020-10-26 11:34:02 +0530625 desc = err.Error()
npujar1d86a522019-11-14 17:11:16 +0530626 return err
khenaidoo4d4802d2018-10-04 21:59:49 -0400627 }
khenaidoo442e7c72020-03-10 16:13:48 -0400628 defer agent.requestQueue.RequestComplete()
Himani Chawlab4c25912020-11-12 17:16:38 +0530629 logger.Debugw(ctx, "reboot-device", log.Fields{"device-id": agent.deviceID})
khenaidoo442e7c72020-03-10 16:13:48 -0400630
Kent Hagermancba2f302020-07-28 13:37:36 -0400631 device := agent.getDeviceReadOnlyWithoutLock()
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530632 if agent.isDeletionInProgress() {
633 return status.Errorf(codes.FailedPrecondition, "deviceId:%s, Device deletion is in progress.", agent.deviceID)
634 }
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000635 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
Himani Chawlab4c25912020-11-12 17:16:38 +0530636 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
637
Kent Hagerman2b216042020-04-03 18:28:56 -0400638 ch, err := agent.adapterProxy.RebootDevice(subCtx, device)
khenaidoo442e7c72020-03-10 16:13:48 -0400639 if err != nil {
640 cancel()
Maninder9a1bc0d2020-10-26 11:34:02 +0530641 desc = err.Error()
khenaidoo442e7c72020-03-10 16:13:48 -0400642 return err
643 }
Maninder9a1bc0d2020-10-26 11:34:02 +0530644 operStatus.Code = common.OperationResp_OPERATION_IN_PROGRESS
645
646 // Wait for response
647 go agent.waitForAdapterResponseAndLogDeviceUpdate(subCtx, cancel, "rebootDevice", ch, agent.onSuccess, agent.onFailure, &prevDeviceState)
khenaidoo4d4802d2018-10-04 21:59:49 -0400648 return nil
649}
650
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530651func (agent *Agent) deleteDeviceForce(ctx context.Context) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530652 logger.Debugw(ctx, "delete-device-force", log.Fields{"device-id": agent.deviceID})
Maninder9a1bc0d2020-10-26 11:34:02 +0530653
654 var desc string
655 operStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
656
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530657 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
Maninder9a1bc0d2020-10-26 11:34:02 +0530658 desc = err.Error()
659 agent.logDeviceUpdate(ctx, "deleteDeviceForce", nil, nil, operStatus, &desc)
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530660 return err
661 }
662 // Get the device Transient state, return err if it is DELETING
663 previousDeviceTransientState := agent.getTransientState()
664
665 if agent.isStateDeleting(previousDeviceTransientState) {
666 agent.requestQueue.RequestComplete()
Maninder9a1bc0d2020-10-26 11:34:02 +0530667 desc = fmt.Sprintf("deviceId:%s, Device Deletion is in progress",
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530668 agent.deviceID)
Maninder9a1bc0d2020-10-26 11:34:02 +0530669 agent.logDeviceUpdate(ctx, "deleteDeviceForce", nil, nil, operStatus, &desc)
670 return status.Error(codes.FailedPrecondition, desc)
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530671 }
672 device := agent.cloneDeviceWithoutLock()
Himani Chawlab4c25912020-11-12 17:16:38 +0530673 if err := agent.updateDeviceWithTransientStateAndReleaseLock(ctx, device,
674 voltha.DeviceTransientState_FORCE_DELETING, previousDeviceTransientState); err != nil {
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530675 return err
676 }
677 previousAdminState := device.AdminState
678 if previousAdminState != ic.AdminState_PREPROVISIONED {
679 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
Himani Chawlab4c25912020-11-12 17:16:38 +0530680 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
681
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530682 ch, err := agent.adapterProxy.DeleteDevice(subCtx, device)
683 if err != nil {
684 cancel()
Maninder9a1bc0d2020-10-26 11:34:02 +0530685 desc = err.Error()
686 agent.logDeviceUpdate(ctx, "deleteDeviceForce", nil, nil, operStatus, &desc)
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530687 return err
688 }
Maninder9a1bc0d2020-10-26 11:34:02 +0530689 // As force delete will not be dependent over the response of adapter, marking this operation as success
690 operStatus.Code = common.OperationResp_OPERATION_SUCCESS
691 agent.logDeviceUpdate(ctx, "deleteDeviceForce", nil, nil, operStatus, &desc)
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530692 // Since it is a case of force delete, nothing needs to be done on adapter responses.
Himani Chawlab4c25912020-11-12 17:16:38 +0530693 go agent.waitForAdapterForceDeleteResponse(subCtx, cancel, "deleteDeviceForce", ch, agent.onSuccess,
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530694 agent.onFailure)
695 }
696 return nil
697}
698
Kent Hagerman2b216042020-04-03 18:28:56 -0400699func (agent *Agent) deleteDevice(ctx context.Context) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530700 logger.Debugw(ctx, "delete-device", log.Fields{"device-id": agent.deviceID})
Maninder9a1bc0d2020-10-26 11:34:02 +0530701
702 var desc string
703 operStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
704 prevState := agent.device.AdminState
705
706 defer agent.logDeviceUpdate(ctx, "deleteDevice", nil, nil, operStatus, &desc)
707
khenaidoo442e7c72020-03-10 16:13:48 -0400708 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
Maninder9a1bc0d2020-10-26 11:34:02 +0530709 desc = err.Error()
khenaidoo442e7c72020-03-10 16:13:48 -0400710 return err
711 }
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530712 // Get the device Transient state, return err if it is DELETING
713 previousDeviceTransientState := agent.getTransientState()
khenaidoo6e55d9e2019-12-12 18:26:26 -0500714
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530715 if agent.isStateDeleting(previousDeviceTransientState) {
716 agent.requestQueue.RequestComplete()
Maninder9a1bc0d2020-10-26 11:34:02 +0530717 desc = fmt.Sprintf("deviceId:%s, Device Deletion is in progress", agent.deviceID)
718 return status.Error(codes.FailedPrecondition, desc)
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530719 }
720 device := agent.cloneDeviceWithoutLock()
721 previousAdminState := device.AdminState
722 // Change the device transient state to DELETING_FROM_ADAPTER state till the device is removed from adapters.
723 currentDeviceTransientState := voltha.DeviceTransientState_DELETING_FROM_ADAPTER
khenaidoo442e7c72020-03-10 16:13:48 -0400724
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530725 if previousAdminState == ic.AdminState_PREPROVISIONED {
726 // Change the state to DELETING POST ADAPTER RESPONSE directly as adapters have no info of the device.
727 currentDeviceTransientState = voltha.DeviceTransientState_DELETING_POST_ADAPTER_RESPONSE
728 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530729 if err := agent.updateDeviceWithTransientStateAndReleaseLock(ctx, device,
730 currentDeviceTransientState, previousDeviceTransientState); err != nil {
Maninder9a1bc0d2020-10-26 11:34:02 +0530731 desc = err.Error()
npujar1d86a522019-11-14 17:11:16 +0530732 return err
733 }
khenaidoo442e7c72020-03-10 16:13:48 -0400734 // If the device was in pre-prov state (only parent device are in that state) then do not send the request to the
735 // adapter
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530736 if previousAdminState != ic.AdminState_PREPROVISIONED {
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000737 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
Himani Chawlab4c25912020-11-12 17:16:38 +0530738 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
739
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530740 ch, err := agent.adapterProxy.DeleteDevice(subCtx, device)
khenaidoo442e7c72020-03-10 16:13:48 -0400741 if err != nil {
742 cancel()
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530743 //updating of transient state is required in error
744 if err := agent.updateTransientState(ctx, voltha.DeviceTransientState_DELETE_FAILED); err != nil {
745 logger.Errorw(ctx, "failed-to-update-transient-state-as-delete-failed", log.Fields{"device-id": agent.deviceID})
746 }
Maninder9a1bc0d2020-10-26 11:34:02 +0530747 desc = err.Error()
khenaidoo442e7c72020-03-10 16:13:48 -0400748 return err
749 }
Maninder9a1bc0d2020-10-26 11:34:02 +0530750
751 operStatus.Code = common.OperationResp_OPERATION_IN_PROGRESS
752 go agent.waitForAdapterResponseAndLogDeviceUpdate(subCtx, cancel, "deleteDevice", ch, agent.onDeleteSuccess,
753 agent.onDeleteFailure, &prevState)
khenaidoo442e7c72020-03-10 16:13:48 -0400754 }
khenaidoo4d4802d2018-10-04 21:59:49 -0400755 return nil
756}
757
Kent Hagerman2b216042020-04-03 18:28:56 -0400758func (agent *Agent) setParentID(ctx context.Context, device *voltha.Device, parentID string) error {
khenaidoo442e7c72020-03-10 16:13:48 -0400759 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
760 return err
761 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530762 logger.Debugw(ctx, "set-parent-id", log.Fields{"device-id": device.Id, "parent-id": parentID})
khenaidoo6e55d9e2019-12-12 18:26:26 -0500763
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400764 cloned := agent.cloneDeviceWithoutLock()
npujar1d86a522019-11-14 17:11:16 +0530765 cloned.ParentId = parentID
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400766 return agent.updateDeviceAndReleaseLock(ctx, cloned)
khenaidooad06fd72019-10-28 12:26:05 -0400767}
768
khenaidoo442e7c72020-03-10 16:13:48 -0400769// getSwitchCapability retrieves the switch capability of a parent device
Kent Hagerman2b216042020-04-03 18:28:56 -0400770func (agent *Agent) getSwitchCapability(ctx context.Context) (*ic.SwitchCapability, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530771 logger.Debugw(ctx, "get-switch-capability", log.Fields{"device-id": agent.deviceID})
khenaidoo442e7c72020-03-10 16:13:48 -0400772
Kent Hagermancba2f302020-07-28 13:37:36 -0400773 device, err := agent.getDeviceReadOnly(ctx)
khenaidoo442e7c72020-03-10 16:13:48 -0400774 if err != nil {
khenaidoob9203542018-09-17 22:56:37 -0400775 return nil, err
khenaidoob9203542018-09-17 22:56:37 -0400776 }
Kent Hagermancba2f302020-07-28 13:37:36 -0400777 ch, err := agent.adapterProxy.GetOfpDeviceInfo(ctx, device)
khenaidoo442e7c72020-03-10 16:13:48 -0400778 if err != nil {
779 return nil, err
780 }
781
782 // Wait for adapter response
783 rpcResponse, ok := <-ch
784 if !ok {
785 return nil, status.Errorf(codes.Aborted, "channel-closed")
786 }
787 if rpcResponse.Err != nil {
788 return nil, rpcResponse.Err
789 }
790 // Successful response
791 switchCap := &ic.SwitchCapability{}
792 if err := ptypes.UnmarshalAny(rpcResponse.Reply, switchCap); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530793 return nil, err
794 }
795 return switchCap, nil
khenaidoob9203542018-09-17 22:56:37 -0400796}
797
Rohan Agrawal31f21802020-06-12 05:38:46 +0000798func (agent *Agent) onPacketFailure(ctx context.Context, rpc string, response interface{}, args ...interface{}) {
khenaidoo442e7c72020-03-10 16:13:48 -0400799 // packet data is encoded in the args param as the first parameter
800 var packet []byte
801 if len(args) >= 1 {
802 if pkt, ok := args[0].([]byte); ok {
803 packet = pkt
804 }
805 }
806 var errResp error
807 if err, ok := response.(error); ok {
808 errResp = err
809 }
Rohan Agrawal31f21802020-06-12 05:38:46 +0000810 logger.Warnw(ctx, "packet-out-error", log.Fields{
khenaidoo442e7c72020-03-10 16:13:48 -0400811 "device-id": agent.deviceID,
812 "error": errResp,
813 "packet": hex.EncodeToString(packet),
814 })
815}
816
Kent Hagerman2b216042020-04-03 18:28:56 -0400817func (agent *Agent) packetOut(ctx context.Context, outPort uint32, packet *ofp.OfpPacketOut) error {
Scott Baker80678602019-11-14 16:57:36 -0800818 // If deviceType=="" then we must have taken ownership of this device.
819 // Fixes VOL-2226 where a core would take ownership and have stale data
820 if agent.deviceType == "" {
npujar467fe752020-01-16 20:17:45 +0530821 agent.reconcileWithKVStore(ctx)
Scott Baker80678602019-11-14 16:57:36 -0800822 }
khenaidoofdbad6e2018-11-06 22:26:38 -0500823 // Send packet to adapter
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000824 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
Himani Chawlab4c25912020-11-12 17:16:38 +0530825 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
826
Kent Hagerman2b216042020-04-03 18:28:56 -0400827 ch, err := agent.adapterProxy.PacketOut(subCtx, agent.deviceType, agent.deviceID, outPort, packet)
khenaidoo442e7c72020-03-10 16:13:48 -0400828 if err != nil {
829 cancel()
830 return nil
khenaidoofdbad6e2018-11-06 22:26:38 -0500831 }
khenaidoo442e7c72020-03-10 16:13:48 -0400832 go agent.waitForAdapterResponse(subCtx, cancel, "packetOut", ch, agent.onSuccess, agent.onPacketFailure, packet.Data)
khenaidoofdbad6e2018-11-06 22:26:38 -0500833 return nil
834}
835
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400836func (agent *Agent) updateDeviceUsingAdapterData(ctx context.Context, device *voltha.Device) error {
837 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
838 return err
839 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530840 logger.Debugw(ctx, "update-device-using-adapter-data", log.Fields{"device-id": device.Id})
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400841
842 cloned := agent.cloneDeviceWithoutLock()
Mahir Gunyel8e2707d2019-07-25 00:36:21 -0700843 cloned.Root = device.Root
844 cloned.Vendor = device.Vendor
845 cloned.Model = device.Model
846 cloned.SerialNumber = device.SerialNumber
847 cloned.MacAddress = device.MacAddress
848 cloned.Vlan = device.Vlan
849 cloned.Reason = device.Reason
Andrea Campanella025667e2021-01-14 11:50:07 +0100850 cloned.ImageDownloads = device.ImageDownloads
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400851 return agent.updateDeviceAndReleaseLock(ctx, cloned)
khenaidoo43c82122018-11-22 18:38:28 -0500852}
853
Kent Hagerman2b216042020-04-03 18:28:56 -0400854func (agent *Agent) updateDeviceStatus(ctx context.Context, operStatus voltha.OperStatus_Types, connStatus voltha.ConnectStatus_Types) error {
khenaidoo442e7c72020-03-10 16:13:48 -0400855 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
856 return err
857 }
khenaidoo6e55d9e2019-12-12 18:26:26 -0500858
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400859 cloned := agent.cloneDeviceWithoutLock()
npujar1d86a522019-11-14 17:11:16 +0530860 // 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 -0400861 if s, ok := voltha.ConnectStatus_Types_name[int32(connStatus)]; ok {
Himani Chawlab4c25912020-11-12 17:16:38 +0530862 logger.Debugw(ctx, "update-device-status-conn", log.Fields{"ok": ok, "val": s})
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400863 cloned.ConnectStatus = connStatus
npujar1d86a522019-11-14 17:11:16 +0530864 }
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400865 if s, ok := voltha.OperStatus_Types_name[int32(operStatus)]; ok {
Himani Chawlab4c25912020-11-12 17:16:38 +0530866 logger.Debugw(ctx, "update-device-status-conn", log.Fields{"ok": ok, "val": s})
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400867 cloned.OperStatus = operStatus
npujar1d86a522019-11-14 17:11:16 +0530868 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530869 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 +0530870 // Store the device
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400871 return agent.updateDeviceAndReleaseLock(ctx, cloned)
khenaidoo92e62c52018-10-03 14:02:54 -0400872}
873
khenaidoob9203542018-09-17 22:56:37 -0400874// TODO: A generic device update by attribute
Kent Hagerman2b216042020-04-03 18:28:56 -0400875func (agent *Agent) updateDeviceAttribute(ctx context.Context, name string, value interface{}) {
khenaidoob9203542018-09-17 22:56:37 -0400876 if value == nil {
877 return
878 }
khenaidoo6e55d9e2019-12-12 18:26:26 -0500879
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400880 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
881 logger.Warnw(ctx, "request-aborted", log.Fields{"device-id": agent.deviceID, "name": name, "error": err})
882 return
883 }
884
885 cloned := agent.cloneDeviceWithoutLock()
khenaidoob9203542018-09-17 22:56:37 -0400886 updated := false
khenaidoo6e55d9e2019-12-12 18:26:26 -0500887 s := reflect.ValueOf(cloned).Elem()
khenaidoob9203542018-09-17 22:56:37 -0400888 if s.Kind() == reflect.Struct {
889 // exported field
890 f := s.FieldByName(name)
891 if f.IsValid() && f.CanSet() {
892 switch f.Kind() {
893 case reflect.String:
894 f.SetString(value.(string))
895 updated = true
896 case reflect.Uint32:
897 f.SetUint(uint64(value.(uint32)))
898 updated = true
899 case reflect.Bool:
900 f.SetBool(value.(bool))
901 updated = true
902 }
903 }
904 }
divyadesaicb8b59d2020-08-18 09:55:47 +0000905 logger.Debugw(ctx, "update-field-status", log.Fields{"device-id": cloned.Id, "name": name, "updated": updated})
khenaidoob9203542018-09-17 22:56:37 -0400906 // Save the data
khenaidoo6e55d9e2019-12-12 18:26:26 -0500907
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400908 if err := agent.updateDeviceAndReleaseLock(ctx, cloned); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000909 logger.Warnw(ctx, "attribute-update-failed", log.Fields{"attribute": name, "value": value})
khenaidoob9203542018-09-17 22:56:37 -0400910 }
khenaidoob9203542018-09-17 22:56:37 -0400911}
serkant.uluderya334479d2019-04-10 08:26:15 -0700912
Kent Hagerman45a13e42020-04-13 12:23:50 -0400913func (agent *Agent) simulateAlarm(ctx context.Context, simulateReq *voltha.SimulateAlarmRequest) error {
khenaidoo442e7c72020-03-10 16:13:48 -0400914 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
915 return err
916 }
917 defer agent.requestQueue.RequestComplete()
Himani Chawlab4c25912020-11-12 17:16:38 +0530918 logger.Debugw(ctx, "simulate-alarm", log.Fields{"device-id": agent.deviceID})
khenaidoo6e55d9e2019-12-12 18:26:26 -0500919
Kent Hagermancba2f302020-07-28 13:37:36 -0400920 device := agent.getDeviceReadOnlyWithoutLock()
khenaidoo6e55d9e2019-12-12 18:26:26 -0500921
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000922 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
Himani Chawlab4c25912020-11-12 17:16:38 +0530923 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
924
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400925 ch, err := agent.adapterProxy.SimulateAlarm(subCtx, device, simulateReq)
khenaidoo442e7c72020-03-10 16:13:48 -0400926 if err != nil {
927 cancel()
npujar1d86a522019-11-14 17:11:16 +0530928 return err
serkant.uluderya334479d2019-04-10 08:26:15 -0700929 }
khenaidoo442e7c72020-03-10 16:13:48 -0400930 go agent.waitForAdapterResponse(subCtx, cancel, "simulateAlarm", ch, agent.onSuccess, agent.onFailure)
serkant.uluderya334479d2019-04-10 08:26:15 -0700931 return nil
932}
Mahir Gunyelb5851672019-07-24 10:46:26 +0300933
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400934// This function updates the device in the DB, releases the device lock, and runs any state transitions.
935// The calling function MUST hold the device lock. The caller MUST NOT modify the device after this is called.
936func (agent *Agent) updateDeviceAndReleaseLock(ctx context.Context, device *voltha.Device) error {
937 // fail early if this agent is no longer valid
Kent Hagerman4f355f52020-03-30 16:01:33 -0400938 if agent.stopped {
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400939 agent.requestQueue.RequestComplete()
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530940 return errors.New("device-agent-stopped")
Thomas Lee Se5a44012019-11-07 20:32:24 +0530941 }
Kent Hagerman4f355f52020-03-30 16:01:33 -0400942
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400943 // update in db
Kent Hagermanf5a67352020-04-30 15:15:26 -0400944 if err := agent.dbProxy.Set(ctx, agent.deviceID, device); err != nil {
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400945 agent.requestQueue.RequestComplete()
Kent Hagerman4f355f52020-03-30 16:01:33 -0400946 return status.Errorf(codes.Internal, "failed-update-device:%s: %s", agent.deviceID, err)
Mahir Gunyelb5851672019-07-24 10:46:26 +0300947 }
divyadesaicb8b59d2020-08-18 09:55:47 +0000948 logger.Debugw(ctx, "updated-device-in-store", log.Fields{"device-id: ": agent.deviceID})
Mahir Gunyelb5851672019-07-24 10:46:26 +0300949
Kent Hagerman6031aad2020-07-29 16:36:33 -0400950 prevDevice := agent.device
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400951 // update the device
khenaidoo0db4c812020-05-27 15:27:30 -0400952 agent.device = device
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400953
954 // release lock before processing transition
955 agent.requestQueue.RequestComplete()
Himani Chawlab4c25912020-11-12 17:16:38 +0530956 subCtx := coreutils.WithSpanAndRPCMetadataFromContext(ctx)
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400957
Himani Chawlab4c25912020-11-12 17:16:38 +0530958 if err := agent.deviceMgr.stateTransitions.ProcessTransition(subCtx,
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530959 device, prevDevice, voltha.DeviceTransientState_NONE, voltha.DeviceTransientState_NONE); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530960 logger.Errorw(ctx, "failed-process-transition", log.Fields{"device-id": device.Id, "previous-admin-state": prevDevice.AdminState, "current-admin-state": device.AdminState})
961 // Sending RPC EVENT here
962 rpce := agent.deviceMgr.NewRPCEvent(ctx, agent.deviceID, err.Error(), nil)
963 go agent.deviceMgr.SendRPCEvent(ctx, "RPC_ERROR_RAISE_EVENT", rpce, voltha.EventCategory_COMMUNICATION,
964 nil, time.Now().UnixNano())
965
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400966 }
Mahir Gunyelb5851672019-07-24 10:46:26 +0300967 return nil
968}
Mahir Gunyelfdee9212019-10-16 16:52:21 -0700969
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530970// This function updates the device transient in the DB through loader, releases the device lock, and runs any state transitions.
971// The calling function MUST hold the device lock. The caller MUST NOT modify the device after this is called.
972func (agent *Agent) updateDeviceWithTransientStateAndReleaseLock(ctx context.Context, device *voltha.Device,
973 transientState, prevTransientState voltha.DeviceTransientState_Types) error {
974 // fail early if this agent is no longer valid
975 if agent.stopped {
976 agent.requestQueue.RequestComplete()
977 return errors.New("device-agent-stopped")
978 }
979 //update device TransientState
980 if err := agent.updateTransientState(ctx, transientState); err != nil {
981 agent.requestQueue.RequestComplete()
982 return err
983 }
984 // update in db
985 if err := agent.dbProxy.Set(ctx, agent.deviceID, device); err != nil {
986 //Reverting TransientState update
987 err := agent.updateTransientState(ctx, prevTransientState)
988 logger.Errorw(ctx, "failed-to-revert-transient-state-update-on-error", log.Fields{"device-id": device.Id,
Himani Chawlab4c25912020-11-12 17:16:38 +0530989 "previous-transient-state": prevTransientState, "current-transient-state": transientState})
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530990 agent.requestQueue.RequestComplete()
991 return status.Errorf(codes.Internal, "failed-update-device:%s: %s", agent.deviceID, err)
992 }
993
994 logger.Debugw(ctx, "updated-device-in-store", log.Fields{"device-id: ": agent.deviceID})
995
996 prevDevice := agent.device
997 // update the device
998 agent.device = device
999
1000 // release lock before processing transition
1001 agent.requestQueue.RequestComplete()
Himani Chawlab4c25912020-11-12 17:16:38 +05301002 subCtx := coreutils.WithSpanAndRPCMetadataFromContext(ctx)
1003 if err := agent.deviceMgr.stateTransitions.ProcessTransition(subCtx,
Himani Chawla2ba1c9c2020-10-07 13:19:03 +05301004 device, prevDevice, transientState, prevTransientState); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +05301005 logger.Errorw(ctx, "failed-process-transition", log.Fields{"device-id": device.Id, "previous-admin-state": prevDevice.AdminState, "current-admin-state": device.AdminState})
1006 // Sending RPC EVENT here
1007 rpce := agent.deviceMgr.NewRPCEvent(ctx, agent.deviceID, err.Error(), nil)
1008 go agent.deviceMgr.SendRPCEvent(ctx, "RPC_ERROR_RAISE_EVENT", rpce, voltha.EventCategory_COMMUNICATION,
1009 nil, time.Now().UnixNano())
Himani Chawla2ba1c9c2020-10-07 13:19:03 +05301010 }
1011 return nil
1012}
Kent Hagerman2b216042020-04-03 18:28:56 -04001013func (agent *Agent) updateDeviceReason(ctx context.Context, reason string) error {
khenaidoo442e7c72020-03-10 16:13:48 -04001014 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1015 return err
1016 }
Maninder9a1bc0d2020-10-26 11:34:02 +05301017
Himani Chawlab4c25912020-11-12 17:16:38 +05301018 logger.Debugw(ctx, "update-device-reason", log.Fields{"device-id": agent.deviceID, "reason": reason})
khenaidoo6e55d9e2019-12-12 18:26:26 -05001019
Maninder9a1bc0d2020-10-26 11:34:02 +05301020 var desc string
1021 operStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
1022
1023 defer agent.logDeviceUpdate(ctx, "updateDeviceReason", nil, nil, operStatus, &desc)
1024
Kent Hagermanf6db9f12020-07-22 17:16:19 -04001025 cloned := agent.cloneDeviceWithoutLock()
npujar1d86a522019-11-14 17:11:16 +05301026 cloned.Reason = reason
Maninder9a1bc0d2020-10-26 11:34:02 +05301027 retErr := agent.updateDeviceAndReleaseLock(ctx, cloned)
1028 if retErr != nil {
1029 desc = retErr.Error()
1030 } else {
1031 operStatus.Code = common.OperationResp_OPERATION_SUCCESS
1032 desc = reason
1033 }
1034 return retErr
Mahir Gunyelfdee9212019-10-16 16:52:21 -07001035}
kesavandbc2d1622020-01-21 00:42:01 -05001036
Kent Hagerman2b216042020-04-03 18:28:56 -04001037func (agent *Agent) ChildDeviceLost(ctx context.Context, device *voltha.Device) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301038 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 -05001039
Kent Hagerman2a07b862020-06-19 15:23:07 -04001040 // Remove the associated peer ports on the parent device
1041 for portID := range agent.portLoader.ListIDs() {
1042 if portHandle, have := agent.portLoader.Lock(portID); have {
1043 oldPort := portHandle.GetReadOnly()
1044 updatedPeers := make([]*voltha.Port_PeerPort, 0)
1045 for _, peerPort := range oldPort.Peers {
1046 if peerPort.DeviceId != device.Id {
1047 updatedPeers = append(updatedPeers, peerPort)
1048 }
khenaidoo442e7c72020-03-10 16:13:48 -04001049 }
Kent Hagerman2a07b862020-06-19 15:23:07 -04001050 newPort := *oldPort
1051 newPort.Peers = updatedPeers
1052 if err := portHandle.Update(ctx, &newPort); err != nil {
1053 portHandle.Unlock()
1054 return nil
1055 }
1056 portHandle.Unlock()
khenaidoo442e7c72020-03-10 16:13:48 -04001057 }
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001058 }
1059
khenaidoo442e7c72020-03-10 16:13:48 -04001060 //send request to adapter
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001061 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
Himani Chawlab4c25912020-11-12 17:16:38 +05301062 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
1063
Girish Gowdra6f9b10e2021-03-11 14:36:39 -08001064 ch, err := agent.adapterProxy.ChildDeviceLost(ctx, agent.deviceType, device)
khenaidoo442e7c72020-03-10 16:13:48 -04001065 if err != nil {
1066 cancel()
1067 return err
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001068 }
khenaidoo442e7c72020-03-10 16:13:48 -04001069 go agent.waitForAdapterResponse(subCtx, cancel, "childDeviceLost", ch, agent.onSuccess, agent.onFailure)
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001070 return nil
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001071}
onkarkundargi87285252020-01-27 11:34:52 +05301072
Kent Hagerman2b216042020-04-03 18:28:56 -04001073func (agent *Agent) startOmciTest(ctx context.Context, omcitestrequest *voltha.OmciTestRequest) (*voltha.TestResponse, error) {
onkarkundargi87285252020-01-27 11:34:52 +05301074 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1075 return nil, err
1076 }
1077
Kent Hagermanf6db9f12020-07-22 17:16:19 -04001078 cloned := agent.cloneDeviceWithoutLock()
Matteo Scandolod525ae32020-04-02 17:27:29 -07001079
Kent Hagermanf6db9f12020-07-22 17:16:19 -04001080 if cloned.Adapter == "" {
1081 adapterName, err := agent.adapterMgr.GetAdapterType(cloned.Type)
Matteo Scandolod525ae32020-04-02 17:27:29 -07001082 if err != nil {
1083 agent.requestQueue.RequestComplete()
1084 return nil, err
1085 }
Kent Hagermanf6db9f12020-07-22 17:16:19 -04001086 cloned.Adapter = adapterName
onkarkundargi87285252020-01-27 11:34:52 +05301087 }
1088
1089 // Send request to the adapter
Kent Hagermanf6db9f12020-07-22 17:16:19 -04001090 ch, err := agent.adapterProxy.StartOmciTest(ctx, cloned, omcitestrequest)
onkarkundargi87285252020-01-27 11:34:52 +05301091 agent.requestQueue.RequestComplete()
1092 if err != nil {
1093 return nil, err
1094 }
1095
1096 // Wait for the adapter response
1097 rpcResponse, ok := <-ch
1098 if !ok {
1099 return nil, status.Errorf(codes.Aborted, "channel-closed-device-id-%s", agent.deviceID)
1100 }
1101 if rpcResponse.Err != nil {
1102 return nil, rpcResponse.Err
1103 }
1104
1105 // Unmarshal and return the response
1106 testResp := &voltha.TestResponse{}
1107 if err := ptypes.UnmarshalAny(rpcResponse.Reply, testResp); err != nil {
1108 return nil, status.Errorf(codes.InvalidArgument, "%s", err.Error())
1109 }
Himani Chawlab4c25912020-11-12 17:16:38 +05301110 logger.Debugw(ctx, "omci_test_request-success-device-agent", log.Fields{"test-resp": testResp})
onkarkundargi87285252020-01-27 11:34:52 +05301111 return testResp, nil
1112}
Dinesh Belwalkarc1129f12020-02-27 10:41:33 -08001113
1114func (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 +05301115 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 -08001116 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1117 return nil, err
1118 }
1119
1120 //send request to adapter
1121 ch, err := agent.adapterProxy.GetExtValue(ctx, pdevice, cdevice, valueparam.Id, valueparam.Value)
1122 agent.requestQueue.RequestComplete()
1123 if err != nil {
1124 return nil, err
1125 }
1126
1127 // Wait for the adapter response
1128 rpcResponse, ok := <-ch
1129 if !ok {
1130 return nil, status.Errorf(codes.Aborted, "channel-closed-device-id-%s", agent.deviceID)
1131 }
1132 if rpcResponse.Err != nil {
1133 return nil, rpcResponse.Err
1134 }
1135
1136 // Unmarshal and return the response
1137 Resp := &voltha.ReturnValues{}
1138 if err := ptypes.UnmarshalAny(rpcResponse.Reply, Resp); err != nil {
1139 return nil, status.Errorf(codes.InvalidArgument, "%s", err.Error())
1140 }
Himani Chawlab4c25912020-11-12 17:16:38 +05301141 logger.Debugw(ctx, "get-ext-value-success-device-agent", log.Fields{"Resp": Resp})
Dinesh Belwalkarc1129f12020-02-27 10:41:33 -08001142 return Resp, nil
1143}
dpaul62686312020-06-23 14:17:36 +05301144
1145func (agent *Agent) setExtValue(ctx context.Context, device *voltha.Device, value *voltha.ValueSet) (*empty.Empty, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301146 logger.Debugw(ctx, "set-ext-value", log.Fields{"device-id": value.Id})
dpaul62686312020-06-23 14:17:36 +05301147 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1148 return nil, err
1149 }
1150
1151 //send request to adapter
1152 ch, err := agent.adapterProxy.SetExtValue(ctx, device, value)
1153 agent.requestQueue.RequestComplete()
1154 if err != nil {
1155 return nil, err
1156 }
1157
1158 // Wait for the adapter response
1159 rpcResponse, ok := <-ch
1160 if !ok {
1161 return nil, status.Errorf(codes.Aborted, "channel-closed-device-id-%s", agent.deviceID)
1162 }
1163 if rpcResponse.Err != nil {
1164 return nil, rpcResponse.Err
1165 }
1166
1167 // Unmarshal and return the response
Himani Chawlab4c25912020-11-12 17:16:38 +05301168 logger.Debug(ctx, "set-ext-value-success-device-agent")
dpaul62686312020-06-23 14:17:36 +05301169 return &empty.Empty{}, nil
1170}
Salman Siddiqui1cf95042020-11-19 00:42:56 +05301171
1172func (agent *Agent) getSingleValue(ctx context.Context, request *extension.SingleGetValueRequest) (*extension.SingleGetValueResponse, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301173 logger.Debugw(ctx, "get-single-value", log.Fields{"device-id": request.TargetId})
Salman Siddiqui1cf95042020-11-19 00:42:56 +05301174
1175 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1176 return nil, err
1177 }
1178
1179 cloned := agent.cloneDeviceWithoutLock()
1180
1181 //send request to adapter
1182 ch, err := agent.adapterProxy.GetSingleValue(ctx, cloned.Adapter, request)
1183 agent.requestQueue.RequestComplete()
1184 if err != nil {
1185 return nil, err
1186 }
1187
1188 // Wait for the adapter response
1189 rpcResponse, ok := <-ch
1190 if !ok {
1191 return nil, status.Errorf(codes.Aborted, "channel-closed-device-id-%s", agent.deviceID)
1192 }
1193
1194 if rpcResponse.Err != nil {
1195 return nil, rpcResponse.Err
1196 }
1197
1198 resp := &extension.SingleGetValueResponse{}
1199 if err := ptypes.UnmarshalAny(rpcResponse.Reply, resp); err != nil {
1200 return nil, status.Errorf(codes.InvalidArgument, "%s", err.Error())
1201 }
1202
1203 return resp, nil
1204}
1205
1206func (agent *Agent) setSingleValue(ctx context.Context, request *extension.SingleSetValueRequest) (*extension.SingleSetValueResponse, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301207 logger.Debugw(ctx, "set-single-value", log.Fields{"device-id": request.TargetId})
Salman Siddiqui1cf95042020-11-19 00:42:56 +05301208
1209 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1210 return nil, err
1211 }
1212
1213 cloned := agent.cloneDeviceWithoutLock()
1214
1215 //send request to adapter
1216 ch, err := agent.adapterProxy.SetSingleValue(ctx, cloned.Adapter, request)
1217 agent.requestQueue.RequestComplete()
1218 if err != nil {
1219 return nil, err
1220 }
1221
1222 // Wait for the adapter response
1223 rpcResponse, ok := <-ch
1224 if !ok {
1225 return nil, status.Errorf(codes.Aborted, "channel-closed-cloned-id-%s", agent.deviceID)
1226 }
1227
1228 if rpcResponse.Err != nil {
1229 return nil, rpcResponse.Err
1230 }
1231
1232 resp := &extension.SingleSetValueResponse{}
1233 if err := ptypes.UnmarshalAny(rpcResponse.Reply, resp); err != nil {
1234 return nil, status.Errorf(codes.InvalidArgument, "%s", err.Error())
1235 }
1236
1237 return resp, nil
1238}