blob: 9358d8a2b9258b4921096b68cc06398b64effcb7 [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}
331 defer agent.logDeviceUpdate(ctx, rpc, prevState, &agent.device.AdminState, operStatus, &desc)
332 var rpce *voltha.RPCEvent
333 defer func() {
334 if rpce != nil {
335 go agent.deviceMgr.SendRPCEvent(ctx, "RPC_ERROR_RAISE_EVENT", rpce,
336 voltha.EventCategory_COMMUNICATION, nil, time.Now().UnixNano())
337 }
338 }()
339
340 select {
341 case rpcResponse, ok := <-ch:
342 if !ok {
343 rpce = agent.deviceMgr.NewRPCEvent(ctx, agent.deviceID, "Response Channel Closed", nil)
344 onFailure(ctx, rpc, status.Errorf(codes.Aborted, "channel-closed"), reqArgs)
345 //add failure
346 } else if rpcResponse.Err != nil {
347 desc = rpcResponse.Err.Error()
348 rpce = agent.deviceMgr.NewRPCEvent(ctx, agent.deviceID, desc, nil)
349 onFailure(ctx, rpc, rpcResponse.Err, reqArgs)
350 //add failure
351 } else {
352 operStatus.Code = common.OperationResp_OPERATION_SUCCESS
353 onSuccess(ctx, rpc, rpcResponse.Reply, reqArgs)
354 }
355 case <-ctx.Done():
356 desc = ctx.Err().Error()
357 rpce = agent.deviceMgr.NewRPCEvent(ctx, agent.deviceID, desc, nil)
358 onFailure(ctx, rpc, ctx.Err(), reqArgs)
359 }
360}
361
Kent Hagermancba2f302020-07-28 13:37:36 -0400362// getDeviceReadOnly returns a device which MUST NOT be modified, but is safe to keep forever.
363func (agent *Agent) getDeviceReadOnly(ctx context.Context) (*voltha.Device, error) {
khenaidoo442e7c72020-03-10 16:13:48 -0400364 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
365 return nil, err
366 }
367 defer agent.requestQueue.RequestComplete()
Kent Hagermancba2f302020-07-28 13:37:36 -0400368 return agent.device, nil
khenaidoo92e62c52018-10-03 14:02:54 -0400369}
370
Kent Hagermancba2f302020-07-28 13:37:36 -0400371// 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 -0400372// The device lock MUST be held by the caller.
Kent Hagermancba2f302020-07-28 13:37:36 -0400373func (agent *Agent) getDeviceReadOnlyWithoutLock() *voltha.Device {
khenaidoo0db4c812020-05-27 15:27:30 -0400374 return agent.device
khenaidoo92e62c52018-10-03 14:02:54 -0400375}
376
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400377// cloneDeviceWithoutLock returns a copy of the device which is safe to modify.
378// The device lock MUST be held by the caller.
379func (agent *Agent) cloneDeviceWithoutLock() *voltha.Device {
380 return proto.Clone(agent.device).(*voltha.Device)
381}
382
khenaidoo3ab34882019-05-02 21:33:30 -0400383// enableDevice activates a preprovisioned or a disable device
Kent Hagerman2b216042020-04-03 18:28:56 -0400384func (agent *Agent) enableDevice(ctx context.Context) error {
Maninder9a1bc0d2020-10-26 11:34:02 +0530385 //To preserve and use oldDevice state as prev state in new device
386 prevDeviceState := agent.device.AdminState
387 var desc string
388 operStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
389
390 defer agent.logDeviceUpdate(ctx, "enableDevice", nil, nil, operStatus, &desc)
391
khenaidoo442e7c72020-03-10 16:13:48 -0400392 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
393 return err
394 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530395 logger.Debugw(ctx, "enable-device", log.Fields{"device-id": agent.deviceID})
khenaidoo21d51152019-02-01 13:48:37 -0500396
Kent Hagermancba2f302020-07-28 13:37:36 -0400397 oldDevice := agent.getDeviceReadOnlyWithoutLock()
Maninder9a1bc0d2020-10-26 11:34:02 +0530398
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400399 if oldDevice.AdminState == voltha.AdminState_ENABLED {
400 logger.Warnw(ctx, "device-already-enabled", log.Fields{"device-id": agent.deviceID})
401 agent.requestQueue.RequestComplete()
Maninder9a1bc0d2020-10-26 11:34:02 +0530402 desc = fmt.Sprintf("cannot-enable-an-already-enabled-device: %s", oldDevice.Id)
403 return status.Error(codes.FailedPrecondition, desc)
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400404 }
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530405 if agent.isDeletionInProgress() {
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400406 agent.requestQueue.RequestComplete()
Maninder9a1bc0d2020-10-26 11:34:02 +0530407
408 operStatus.Code = common.OperationResp_OPERATION_IN_PROGRESS
409
410 desc = fmt.Sprintf("deviceId:%s, Device deletion is in progress.", agent.deviceID)
411 return status.Error(codes.FailedPrecondition, desc)
412
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400413 }
npujar1d86a522019-11-14 17:11:16 +0530414 // 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 -0400415 // pre-provisioned with the required adapter not registered. At this stage, since we need to communicate
npujar1d86a522019-11-14 17:11:16 +0530416 // with the adapter then we need to know the adapter that will handle this request
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400417 adapterName, err := agent.adapterMgr.GetAdapterType(oldDevice.Type)
npujar1d86a522019-11-14 17:11:16 +0530418 if err != nil {
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400419 agent.requestQueue.RequestComplete()
Maninder9a1bc0d2020-10-26 11:34:02 +0530420 desc = err.Error()
Matteo Scandolod525ae32020-04-02 17:27:29 -0700421 return err
npujar1d86a522019-11-14 17:11:16 +0530422 }
423
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400424 newDevice := agent.cloneDeviceWithoutLock()
425 newDevice.Adapter = adapterName
npujar1d86a522019-11-14 17:11:16 +0530426
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400427 // Update the Admin State and set the operational state to activating before sending the request to the Adapters
428 newDevice.AdminState = voltha.AdminState_ENABLED
429 newDevice.OperStatus = voltha.OperStatus_ACTIVATING
Maninder9a1bc0d2020-10-26 11:34:02 +0530430
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400431 if err := agent.updateDeviceAndReleaseLock(ctx, newDevice); err != nil {
Maninder9a1bc0d2020-10-26 11:34:02 +0530432 desc = err.Error()
npujar1d86a522019-11-14 17:11:16 +0530433 return err
434 }
435
khenaidoo442e7c72020-03-10 16:13:48 -0400436 // 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 -0400437 var ch chan *kafka.RpcResponse
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000438 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
Himani Chawlab4c25912020-11-12 17:16:38 +0530439 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
Maninder9a1bc0d2020-10-26 11:34:02 +0530440 subCtx = coreutils.WithFromTopicMetadataFromContext(subCtx, ctx)
Himani Chawlab4c25912020-11-12 17:16:38 +0530441
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400442 if oldDevice.AdminState == voltha.AdminState_PREPROVISIONED {
443 ch, err = agent.adapterProxy.AdoptDevice(subCtx, newDevice)
khenaidoob9203542018-09-17 22:56:37 -0400444 } else {
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400445 ch, err = agent.adapterProxy.ReEnableDevice(subCtx, newDevice)
khenaidoob9203542018-09-17 22:56:37 -0400446 }
khenaidoo442e7c72020-03-10 16:13:48 -0400447 if err != nil {
448 cancel()
Maninder9a1bc0d2020-10-26 11:34:02 +0530449 desc = err.Error()
khenaidoo442e7c72020-03-10 16:13:48 -0400450 return err
451 }
Maninder9a1bc0d2020-10-26 11:34:02 +0530452
453 operStatus.Code = common.OperationResp_OPERATION_IN_PROGRESS
454
khenaidoo442e7c72020-03-10 16:13:48 -0400455 // Wait for response
Maninder9a1bc0d2020-10-26 11:34:02 +0530456 go agent.waitForAdapterResponseAndLogDeviceUpdate(subCtx, cancel, "enableDevice", ch, agent.onSuccess, agent.onFailure, &prevDeviceState)
khenaidoob9203542018-09-17 22:56:37 -0400457 return nil
458}
459
Maninder9a1bc0d2020-10-26 11:34:02 +0530460func (agent *Agent) waitForAdapterFlowResponse(ctx context.Context, cancel context.CancelFunc, rpc string, ch chan *kafka.RpcResponse, response coreutils.Response) {
khenaidoo442e7c72020-03-10 16:13:48 -0400461 defer cancel()
Maninder9a1bc0d2020-10-26 11:34:02 +0530462 var desc string
463 operStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
464 defer agent.logDeviceUpdate(ctx, rpc, nil, nil, operStatus, &desc)
465
Himani Chawlab4c25912020-11-12 17:16:38 +0530466 var rpce *voltha.RPCEvent
467 defer func() {
468 if rpce != nil {
469 go agent.deviceMgr.SendRPCEvent(ctx, "RPC_ERROR_RAISE_EVENT", rpce,
470 voltha.EventCategory_COMMUNICATION, nil, time.Now().UnixNano())
471 }
472 }()
khenaidoo442e7c72020-03-10 16:13:48 -0400473 select {
474 case rpcResponse, ok := <-ch:
475 if !ok {
Himani Chawlab4c25912020-11-12 17:16:38 +0530476 //add failure
Maninder9a1bc0d2020-10-26 11:34:02 +0530477 desc = "Response Channel Closed"
Himani Chawlab4c25912020-11-12 17:16:38 +0530478 rpce = agent.deviceMgr.NewRPCEvent(ctx, agent.deviceID, "Response Channel Closed", nil)
khenaidoo442e7c72020-03-10 16:13:48 -0400479 response.Error(status.Errorf(codes.Aborted, "channel-closed"))
480 } else if rpcResponse.Err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530481 //add failure
Maninder9a1bc0d2020-10-26 11:34:02 +0530482 desc = rpcResponse.Err.Error()
483 rpce = agent.deviceMgr.NewRPCEvent(ctx, agent.deviceID, desc, nil)
khenaidoo442e7c72020-03-10 16:13:48 -0400484 response.Error(rpcResponse.Err)
485 } else {
Maninder9a1bc0d2020-10-26 11:34:02 +0530486 operStatus.Code = common.OperationResp_OPERATION_SUCCESS
khenaidoo442e7c72020-03-10 16:13:48 -0400487 response.Done()
488 }
489 case <-ctx.Done():
Maninder9a1bc0d2020-10-26 11:34:02 +0530490 desc = ctx.Err().Error()
491 rpce = agent.deviceMgr.NewRPCEvent(ctx, agent.deviceID, desc, nil)
khenaidoo442e7c72020-03-10 16:13:48 -0400492 response.Error(ctx.Err())
khenaidoo2c6a0992019-04-29 13:46:56 -0400493 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400494}
495
A R Karthick5c28f552019-12-11 22:47:44 -0800496//addFlowsAndGroups adds the "newFlows" and "newGroups" from the existing flows/groups and sends the update to the
497//adapters
Kent Hagerman2b216042020-04-03 18:28:56 -0400498func (agent *Agent) addFlowsAndGroups(ctx context.Context, newFlows []*ofp.OfpFlowStats, newGroups []*ofp.OfpGroupEntry, flowMetadata *voltha.FlowMetadata) error {
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700499 var flwResponse, grpResponse coreutils.Response
500 var err error
501 //if new flow list is empty then the called function returns quickly
502 if flwResponse, err = agent.addFlowsToAdapter(ctx, newFlows, flowMetadata); err != nil {
A R Karthick5c28f552019-12-11 22:47:44 -0800503 return err
504 }
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700505 //if new group list is empty then the called function returns quickly
506 if grpResponse, err = agent.addGroupsToAdapter(ctx, newGroups, flowMetadata); err != nil {
507 return err
508 }
509 if errs := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, flwResponse, grpResponse); errs != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000510 logger.Warnw(ctx, "no-adapter-response", log.Fields{"device-id": agent.deviceID, "result": errs})
khenaidoo442e7c72020-03-10 16:13:48 -0400511 return status.Errorf(codes.Aborted, "flow-failure-device-%s", agent.deviceID)
khenaidoo0458db62019-06-20 08:50:36 -0400512 }
khenaidoo0458db62019-06-20 08:50:36 -0400513 return nil
514}
515
A R Karthick5c28f552019-12-11 22:47:44 -0800516//deleteFlowsAndGroups removes the "flowsToDel" and "groupsToDel" from the existing flows/groups and sends the update to the
517//adapters
Kent Hagerman2b216042020-04-03 18:28:56 -0400518func (agent *Agent) deleteFlowsAndGroups(ctx context.Context, flowsToDel []*ofp.OfpFlowStats, groupsToDel []*ofp.OfpGroupEntry, flowMetadata *voltha.FlowMetadata) error {
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700519 var flwResponse, grpResponse coreutils.Response
520 var err error
521 if flwResponse, err = agent.deleteFlowsFromAdapter(ctx, flowsToDel, flowMetadata); err != nil {
A R Karthick5c28f552019-12-11 22:47:44 -0800522 return err
523 }
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700524 if grpResponse, err = agent.deleteGroupsFromAdapter(ctx, groupsToDel, flowMetadata); err != nil {
525 return err
526 }
527
528 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, flwResponse, grpResponse); res != nil {
khenaidoo0458db62019-06-20 08:50:36 -0400529 return status.Errorf(codes.Aborted, "errors-%s", res)
530 }
531 return nil
khenaidoo0458db62019-06-20 08:50:36 -0400532}
533
A R Karthick5c28f552019-12-11 22:47:44 -0800534//updateFlowsAndGroups replaces the existing flows and groups with "updatedFlows" and "updatedGroups" respectively. It
535//also sends the updates to the adapters
Kent Hagerman2b216042020-04-03 18:28:56 -0400536func (agent *Agent) updateFlowsAndGroups(ctx context.Context, updatedFlows []*ofp.OfpFlowStats, updatedGroups []*ofp.OfpGroupEntry, flowMetadata *voltha.FlowMetadata) error {
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700537 var flwResponse, grpResponse coreutils.Response
538 var err error
539 if flwResponse, err = agent.updateFlowsToAdapter(ctx, updatedFlows, flowMetadata); err != nil {
A R Karthick5c28f552019-12-11 22:47:44 -0800540 return err
541 }
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700542 if grpResponse, err = agent.updateGroupsToAdapter(ctx, updatedGroups, flowMetadata); err != nil {
543 return err
544 }
545
546 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, flwResponse, grpResponse); res != nil {
khenaidoo0458db62019-06-20 08:50:36 -0400547 return status.Errorf(codes.Aborted, "errors-%s", res)
548 }
549 return nil
khenaidoo19d7b632018-10-30 10:49:50 -0400550}
551
khenaidoo4d4802d2018-10-04 21:59:49 -0400552//disableDevice disable a device
Kent Hagerman2b216042020-04-03 18:28:56 -0400553func (agent *Agent) disableDevice(ctx context.Context) error {
Maninder9a1bc0d2020-10-26 11:34:02 +0530554 var desc string
555 operStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
556
557 prevDeviceState := agent.device.AdminState
558
559 defer agent.logDeviceUpdate(ctx, "disableDevice", nil, nil, operStatus, &desc)
560
khenaidoo442e7c72020-03-10 16:13:48 -0400561 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
Maninder9a1bc0d2020-10-26 11:34:02 +0530562 desc = err.Error()
khenaidoo442e7c72020-03-10 16:13:48 -0400563 return err
564 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530565 logger.Debugw(ctx, "disable-device", log.Fields{"device-id": agent.deviceID})
khenaidoo6e55d9e2019-12-12 18:26:26 -0500566
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400567 cloned := agent.cloneDeviceWithoutLock()
khenaidoo6e55d9e2019-12-12 18:26:26 -0500568
569 if cloned.AdminState == voltha.AdminState_DISABLED {
Maninder9a1bc0d2020-10-26 11:34:02 +0530570 desc = "device-already-disabled"
divyadesaicb8b59d2020-08-18 09:55:47 +0000571 logger.Debugw(ctx, "device-already-disabled", log.Fields{"device-id": agent.deviceID})
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400572 agent.requestQueue.RequestComplete()
npujar1d86a522019-11-14 17:11:16 +0530573 return nil
574 }
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530575 if cloned.AdminState == voltha.AdminState_PREPROVISIONED {
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400576 agent.requestQueue.RequestComplete()
Maninder9a1bc0d2020-10-26 11:34:02 +0530577 desc = fmt.Sprintf("deviceId:%s, invalid-admin-state:%s", agent.deviceID, cloned.AdminState)
khenaidoo6e55d9e2019-12-12 18:26:26 -0500578 return status.Errorf(codes.FailedPrecondition, "deviceId:%s, invalid-admin-state:%s", agent.deviceID, cloned.AdminState)
npujar1d86a522019-11-14 17:11:16 +0530579 }
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530580 if agent.isDeletionInProgress() {
581 agent.requestQueue.RequestComplete()
582 return status.Errorf(codes.FailedPrecondition, "deviceId:%s, Device deletion is in progress.", agent.deviceID)
583 }
npujar1d86a522019-11-14 17:11:16 +0530584 // Update the Admin State and operational state before sending the request out
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400585 cloned.AdminState = voltha.AdminState_DISABLED
586 cloned.OperStatus = voltha.OperStatus_UNKNOWN
Maninder9a1bc0d2020-10-26 11:34:02 +0530587
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400588 if err := agent.updateDeviceAndReleaseLock(ctx, cloned); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530589 return err
590 }
khenaidoo442e7c72020-03-10 16:13:48 -0400591
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000592 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
Himani Chawlab4c25912020-11-12 17:16:38 +0530593 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
594
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400595 ch, err := agent.adapterProxy.DisableDevice(subCtx, cloned)
khenaidoo442e7c72020-03-10 16:13:48 -0400596 if err != nil {
597 cancel()
Maninder9a1bc0d2020-10-26 11:34:02 +0530598 desc = err.Error()
npujar1d86a522019-11-14 17:11:16 +0530599 return err
khenaidoo0a822f92019-05-08 15:15:57 -0400600 }
Maninder9a1bc0d2020-10-26 11:34:02 +0530601 operStatus.Code = common.OperationResp_OPERATION_IN_PROGRESS
602
603 // Wait for response
604 go agent.waitForAdapterResponseAndLogDeviceUpdate(subCtx, cancel, "disableDevice", ch, agent.onSuccess, agent.onFailure, &prevDeviceState)
khenaidoo0a822f92019-05-08 15:15:57 -0400605
khenaidoo92e62c52018-10-03 14:02:54 -0400606 return nil
607}
608
Kent Hagerman2b216042020-04-03 18:28:56 -0400609func (agent *Agent) rebootDevice(ctx context.Context) error {
Maninder9a1bc0d2020-10-26 11:34:02 +0530610 var desc string
611 operStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
612
613 prevDeviceState := agent.device.AdminState
614
615 defer agent.logDeviceUpdate(ctx, "rebootDevice", nil, nil, operStatus, &desc)
616
khenaidoo442e7c72020-03-10 16:13:48 -0400617 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
Maninder9a1bc0d2020-10-26 11:34:02 +0530618 desc = err.Error()
npujar1d86a522019-11-14 17:11:16 +0530619 return err
khenaidoo4d4802d2018-10-04 21:59:49 -0400620 }
khenaidoo442e7c72020-03-10 16:13:48 -0400621 defer agent.requestQueue.RequestComplete()
Himani Chawlab4c25912020-11-12 17:16:38 +0530622 logger.Debugw(ctx, "reboot-device", log.Fields{"device-id": agent.deviceID})
khenaidoo442e7c72020-03-10 16:13:48 -0400623
Kent Hagermancba2f302020-07-28 13:37:36 -0400624 device := agent.getDeviceReadOnlyWithoutLock()
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530625 if agent.isDeletionInProgress() {
626 return status.Errorf(codes.FailedPrecondition, "deviceId:%s, Device deletion is in progress.", agent.deviceID)
627 }
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000628 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
Himani Chawlab4c25912020-11-12 17:16:38 +0530629 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
630
Kent Hagerman2b216042020-04-03 18:28:56 -0400631 ch, err := agent.adapterProxy.RebootDevice(subCtx, device)
khenaidoo442e7c72020-03-10 16:13:48 -0400632 if err != nil {
633 cancel()
Maninder9a1bc0d2020-10-26 11:34:02 +0530634 desc = err.Error()
khenaidoo442e7c72020-03-10 16:13:48 -0400635 return err
636 }
Maninder9a1bc0d2020-10-26 11:34:02 +0530637 operStatus.Code = common.OperationResp_OPERATION_IN_PROGRESS
638
639 // Wait for response
640 go agent.waitForAdapterResponseAndLogDeviceUpdate(subCtx, cancel, "rebootDevice", ch, agent.onSuccess, agent.onFailure, &prevDeviceState)
khenaidoo4d4802d2018-10-04 21:59:49 -0400641 return nil
642}
643
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530644func (agent *Agent) deleteDeviceForce(ctx context.Context) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530645 logger.Debugw(ctx, "delete-device-force", log.Fields{"device-id": agent.deviceID})
Maninder9a1bc0d2020-10-26 11:34:02 +0530646
647 var desc string
648 operStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
649
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530650 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
Maninder9a1bc0d2020-10-26 11:34:02 +0530651 desc = err.Error()
652 agent.logDeviceUpdate(ctx, "deleteDeviceForce", nil, nil, operStatus, &desc)
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530653 return err
654 }
655 // Get the device Transient state, return err if it is DELETING
656 previousDeviceTransientState := agent.getTransientState()
657
658 if agent.isStateDeleting(previousDeviceTransientState) {
659 agent.requestQueue.RequestComplete()
Maninder9a1bc0d2020-10-26 11:34:02 +0530660 desc = fmt.Sprintf("deviceId:%s, Device Deletion is in progress",
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530661 agent.deviceID)
Maninder9a1bc0d2020-10-26 11:34:02 +0530662 agent.logDeviceUpdate(ctx, "deleteDeviceForce", nil, nil, operStatus, &desc)
663 return status.Error(codes.FailedPrecondition, desc)
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530664 }
665 device := agent.cloneDeviceWithoutLock()
Himani Chawlab4c25912020-11-12 17:16:38 +0530666 if err := agent.updateDeviceWithTransientStateAndReleaseLock(ctx, device,
667 voltha.DeviceTransientState_FORCE_DELETING, previousDeviceTransientState); err != nil {
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530668 return err
669 }
670 previousAdminState := device.AdminState
671 if previousAdminState != ic.AdminState_PREPROVISIONED {
672 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
Himani Chawlab4c25912020-11-12 17:16:38 +0530673 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
674
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530675 ch, err := agent.adapterProxy.DeleteDevice(subCtx, device)
676 if err != nil {
677 cancel()
Maninder9a1bc0d2020-10-26 11:34:02 +0530678 desc = err.Error()
679 agent.logDeviceUpdate(ctx, "deleteDeviceForce", nil, nil, operStatus, &desc)
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530680 return err
681 }
Maninder9a1bc0d2020-10-26 11:34:02 +0530682 // As force delete will not be dependent over the response of adapter, marking this operation as success
683 operStatus.Code = common.OperationResp_OPERATION_SUCCESS
684 agent.logDeviceUpdate(ctx, "deleteDeviceForce", nil, nil, operStatus, &desc)
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530685 // Since it is a case of force delete, nothing needs to be done on adapter responses.
Himani Chawlab4c25912020-11-12 17:16:38 +0530686 go agent.waitForAdapterForceDeleteResponse(subCtx, cancel, "deleteDeviceForce", ch, agent.onSuccess,
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530687 agent.onFailure)
688 }
689 return nil
690}
691
Kent Hagerman2b216042020-04-03 18:28:56 -0400692func (agent *Agent) deleteDevice(ctx context.Context) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530693 logger.Debugw(ctx, "delete-device", log.Fields{"device-id": agent.deviceID})
Maninder9a1bc0d2020-10-26 11:34:02 +0530694
695 var desc string
696 operStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
697 prevState := agent.device.AdminState
698
699 defer agent.logDeviceUpdate(ctx, "deleteDevice", nil, nil, operStatus, &desc)
700
khenaidoo442e7c72020-03-10 16:13:48 -0400701 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
Maninder9a1bc0d2020-10-26 11:34:02 +0530702 desc = err.Error()
khenaidoo442e7c72020-03-10 16:13:48 -0400703 return err
704 }
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530705 // Get the device Transient state, return err if it is DELETING
706 previousDeviceTransientState := agent.getTransientState()
khenaidoo6e55d9e2019-12-12 18:26:26 -0500707
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530708 if agent.isStateDeleting(previousDeviceTransientState) {
709 agent.requestQueue.RequestComplete()
Maninder9a1bc0d2020-10-26 11:34:02 +0530710 desc = fmt.Sprintf("deviceId:%s, Device Deletion is in progress", agent.deviceID)
711 return status.Error(codes.FailedPrecondition, desc)
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530712 }
713 device := agent.cloneDeviceWithoutLock()
714 previousAdminState := device.AdminState
715 // Change the device transient state to DELETING_FROM_ADAPTER state till the device is removed from adapters.
716 currentDeviceTransientState := voltha.DeviceTransientState_DELETING_FROM_ADAPTER
khenaidoo442e7c72020-03-10 16:13:48 -0400717
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530718 if previousAdminState == ic.AdminState_PREPROVISIONED {
719 // Change the state to DELETING POST ADAPTER RESPONSE directly as adapters have no info of the device.
720 currentDeviceTransientState = voltha.DeviceTransientState_DELETING_POST_ADAPTER_RESPONSE
721 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530722 if err := agent.updateDeviceWithTransientStateAndReleaseLock(ctx, device,
723 currentDeviceTransientState, previousDeviceTransientState); err != nil {
Maninder9a1bc0d2020-10-26 11:34:02 +0530724 desc = err.Error()
npujar1d86a522019-11-14 17:11:16 +0530725 return err
726 }
khenaidoo442e7c72020-03-10 16:13:48 -0400727 // If the device was in pre-prov state (only parent device are in that state) then do not send the request to the
728 // adapter
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530729 if previousAdminState != ic.AdminState_PREPROVISIONED {
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000730 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
Himani Chawlab4c25912020-11-12 17:16:38 +0530731 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
732
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530733 ch, err := agent.adapterProxy.DeleteDevice(subCtx, device)
khenaidoo442e7c72020-03-10 16:13:48 -0400734 if err != nil {
735 cancel()
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530736 //updating of transient state is required in error
737 if err := agent.updateTransientState(ctx, voltha.DeviceTransientState_DELETE_FAILED); err != nil {
738 logger.Errorw(ctx, "failed-to-update-transient-state-as-delete-failed", log.Fields{"device-id": agent.deviceID})
739 }
Maninder9a1bc0d2020-10-26 11:34:02 +0530740 desc = err.Error()
khenaidoo442e7c72020-03-10 16:13:48 -0400741 return err
742 }
Maninder9a1bc0d2020-10-26 11:34:02 +0530743
744 operStatus.Code = common.OperationResp_OPERATION_IN_PROGRESS
745 go agent.waitForAdapterResponseAndLogDeviceUpdate(subCtx, cancel, "deleteDevice", ch, agent.onDeleteSuccess,
746 agent.onDeleteFailure, &prevState)
khenaidoo442e7c72020-03-10 16:13:48 -0400747 }
khenaidoo4d4802d2018-10-04 21:59:49 -0400748 return nil
749}
750
Kent Hagerman2b216042020-04-03 18:28:56 -0400751func (agent *Agent) setParentID(ctx context.Context, device *voltha.Device, parentID string) error {
khenaidoo442e7c72020-03-10 16:13:48 -0400752 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
753 return err
754 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530755 logger.Debugw(ctx, "set-parent-id", log.Fields{"device-id": device.Id, "parent-id": parentID})
khenaidoo6e55d9e2019-12-12 18:26:26 -0500756
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400757 cloned := agent.cloneDeviceWithoutLock()
npujar1d86a522019-11-14 17:11:16 +0530758 cloned.ParentId = parentID
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400759 return agent.updateDeviceAndReleaseLock(ctx, cloned)
khenaidooad06fd72019-10-28 12:26:05 -0400760}
761
khenaidoo442e7c72020-03-10 16:13:48 -0400762// getSwitchCapability retrieves the switch capability of a parent device
Kent Hagerman2b216042020-04-03 18:28:56 -0400763func (agent *Agent) getSwitchCapability(ctx context.Context) (*ic.SwitchCapability, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530764 logger.Debugw(ctx, "get-switch-capability", log.Fields{"device-id": agent.deviceID})
khenaidoo442e7c72020-03-10 16:13:48 -0400765
Kent Hagermancba2f302020-07-28 13:37:36 -0400766 device, err := agent.getDeviceReadOnly(ctx)
khenaidoo442e7c72020-03-10 16:13:48 -0400767 if err != nil {
khenaidoob9203542018-09-17 22:56:37 -0400768 return nil, err
khenaidoob9203542018-09-17 22:56:37 -0400769 }
Kent Hagermancba2f302020-07-28 13:37:36 -0400770 ch, err := agent.adapterProxy.GetOfpDeviceInfo(ctx, device)
khenaidoo442e7c72020-03-10 16:13:48 -0400771 if err != nil {
772 return nil, err
773 }
774
775 // Wait for adapter response
776 rpcResponse, ok := <-ch
777 if !ok {
778 return nil, status.Errorf(codes.Aborted, "channel-closed")
779 }
780 if rpcResponse.Err != nil {
781 return nil, rpcResponse.Err
782 }
783 // Successful response
784 switchCap := &ic.SwitchCapability{}
785 if err := ptypes.UnmarshalAny(rpcResponse.Reply, switchCap); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530786 return nil, err
787 }
788 return switchCap, nil
khenaidoob9203542018-09-17 22:56:37 -0400789}
790
Rohan Agrawal31f21802020-06-12 05:38:46 +0000791func (agent *Agent) onPacketFailure(ctx context.Context, rpc string, response interface{}, args ...interface{}) {
khenaidoo442e7c72020-03-10 16:13:48 -0400792 // packet data is encoded in the args param as the first parameter
793 var packet []byte
794 if len(args) >= 1 {
795 if pkt, ok := args[0].([]byte); ok {
796 packet = pkt
797 }
798 }
799 var errResp error
800 if err, ok := response.(error); ok {
801 errResp = err
802 }
Rohan Agrawal31f21802020-06-12 05:38:46 +0000803 logger.Warnw(ctx, "packet-out-error", log.Fields{
khenaidoo442e7c72020-03-10 16:13:48 -0400804 "device-id": agent.deviceID,
805 "error": errResp,
806 "packet": hex.EncodeToString(packet),
807 })
808}
809
Kent Hagerman2b216042020-04-03 18:28:56 -0400810func (agent *Agent) packetOut(ctx context.Context, outPort uint32, packet *ofp.OfpPacketOut) error {
Scott Baker80678602019-11-14 16:57:36 -0800811 // If deviceType=="" then we must have taken ownership of this device.
812 // Fixes VOL-2226 where a core would take ownership and have stale data
813 if agent.deviceType == "" {
npujar467fe752020-01-16 20:17:45 +0530814 agent.reconcileWithKVStore(ctx)
Scott Baker80678602019-11-14 16:57:36 -0800815 }
khenaidoofdbad6e2018-11-06 22:26:38 -0500816 // Send packet to adapter
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000817 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
Himani Chawlab4c25912020-11-12 17:16:38 +0530818 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
819
Kent Hagerman2b216042020-04-03 18:28:56 -0400820 ch, err := agent.adapterProxy.PacketOut(subCtx, agent.deviceType, agent.deviceID, outPort, packet)
khenaidoo442e7c72020-03-10 16:13:48 -0400821 if err != nil {
822 cancel()
823 return nil
khenaidoofdbad6e2018-11-06 22:26:38 -0500824 }
khenaidoo442e7c72020-03-10 16:13:48 -0400825 go agent.waitForAdapterResponse(subCtx, cancel, "packetOut", ch, agent.onSuccess, agent.onPacketFailure, packet.Data)
khenaidoofdbad6e2018-11-06 22:26:38 -0500826 return nil
827}
828
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400829func (agent *Agent) updateDeviceUsingAdapterData(ctx context.Context, device *voltha.Device) error {
830 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
831 return err
832 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530833 logger.Debugw(ctx, "update-device-using-adapter-data", log.Fields{"device-id": device.Id})
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400834
835 cloned := agent.cloneDeviceWithoutLock()
Mahir Gunyel8e2707d2019-07-25 00:36:21 -0700836 cloned.Root = device.Root
837 cloned.Vendor = device.Vendor
838 cloned.Model = device.Model
839 cloned.SerialNumber = device.SerialNumber
840 cloned.MacAddress = device.MacAddress
841 cloned.Vlan = device.Vlan
842 cloned.Reason = device.Reason
Andrea Campanella025667e2021-01-14 11:50:07 +0100843 cloned.ImageDownloads = device.ImageDownloads
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400844 return agent.updateDeviceAndReleaseLock(ctx, cloned)
khenaidoo43c82122018-11-22 18:38:28 -0500845}
846
Kent Hagerman2b216042020-04-03 18:28:56 -0400847func (agent *Agent) updateDeviceStatus(ctx context.Context, operStatus voltha.OperStatus_Types, connStatus voltha.ConnectStatus_Types) error {
khenaidoo442e7c72020-03-10 16:13:48 -0400848 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
849 return err
850 }
khenaidoo6e55d9e2019-12-12 18:26:26 -0500851
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400852 cloned := agent.cloneDeviceWithoutLock()
npujar1d86a522019-11-14 17:11:16 +0530853 // 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 -0400854 if s, ok := voltha.ConnectStatus_Types_name[int32(connStatus)]; ok {
Himani Chawlab4c25912020-11-12 17:16:38 +0530855 logger.Debugw(ctx, "update-device-status-conn", log.Fields{"ok": ok, "val": s})
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400856 cloned.ConnectStatus = connStatus
npujar1d86a522019-11-14 17:11:16 +0530857 }
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400858 if s, ok := voltha.OperStatus_Types_name[int32(operStatus)]; ok {
Himani Chawlab4c25912020-11-12 17:16:38 +0530859 logger.Debugw(ctx, "update-device-status-conn", log.Fields{"ok": ok, "val": s})
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400860 cloned.OperStatus = operStatus
npujar1d86a522019-11-14 17:11:16 +0530861 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530862 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 +0530863 // Store the device
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400864 return agent.updateDeviceAndReleaseLock(ctx, cloned)
khenaidoo92e62c52018-10-03 14:02:54 -0400865}
866
khenaidoob9203542018-09-17 22:56:37 -0400867// TODO: A generic device update by attribute
Kent Hagerman2b216042020-04-03 18:28:56 -0400868func (agent *Agent) updateDeviceAttribute(ctx context.Context, name string, value interface{}) {
khenaidoob9203542018-09-17 22:56:37 -0400869 if value == nil {
870 return
871 }
khenaidoo6e55d9e2019-12-12 18:26:26 -0500872
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400873 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
874 logger.Warnw(ctx, "request-aborted", log.Fields{"device-id": agent.deviceID, "name": name, "error": err})
875 return
876 }
877
878 cloned := agent.cloneDeviceWithoutLock()
khenaidoob9203542018-09-17 22:56:37 -0400879 updated := false
khenaidoo6e55d9e2019-12-12 18:26:26 -0500880 s := reflect.ValueOf(cloned).Elem()
khenaidoob9203542018-09-17 22:56:37 -0400881 if s.Kind() == reflect.Struct {
882 // exported field
883 f := s.FieldByName(name)
884 if f.IsValid() && f.CanSet() {
885 switch f.Kind() {
886 case reflect.String:
887 f.SetString(value.(string))
888 updated = true
889 case reflect.Uint32:
890 f.SetUint(uint64(value.(uint32)))
891 updated = true
892 case reflect.Bool:
893 f.SetBool(value.(bool))
894 updated = true
895 }
896 }
897 }
divyadesaicb8b59d2020-08-18 09:55:47 +0000898 logger.Debugw(ctx, "update-field-status", log.Fields{"device-id": cloned.Id, "name": name, "updated": updated})
khenaidoob9203542018-09-17 22:56:37 -0400899 // Save the data
khenaidoo6e55d9e2019-12-12 18:26:26 -0500900
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400901 if err := agent.updateDeviceAndReleaseLock(ctx, cloned); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000902 logger.Warnw(ctx, "attribute-update-failed", log.Fields{"attribute": name, "value": value})
khenaidoob9203542018-09-17 22:56:37 -0400903 }
khenaidoob9203542018-09-17 22:56:37 -0400904}
serkant.uluderya334479d2019-04-10 08:26:15 -0700905
Kent Hagerman45a13e42020-04-13 12:23:50 -0400906func (agent *Agent) simulateAlarm(ctx context.Context, simulateReq *voltha.SimulateAlarmRequest) error {
khenaidoo442e7c72020-03-10 16:13:48 -0400907 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
908 return err
909 }
910 defer agent.requestQueue.RequestComplete()
Himani Chawlab4c25912020-11-12 17:16:38 +0530911 logger.Debugw(ctx, "simulate-alarm", log.Fields{"device-id": agent.deviceID})
khenaidoo6e55d9e2019-12-12 18:26:26 -0500912
Kent Hagermancba2f302020-07-28 13:37:36 -0400913 device := agent.getDeviceReadOnlyWithoutLock()
khenaidoo6e55d9e2019-12-12 18:26:26 -0500914
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000915 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
Himani Chawlab4c25912020-11-12 17:16:38 +0530916 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
917
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400918 ch, err := agent.adapterProxy.SimulateAlarm(subCtx, device, simulateReq)
khenaidoo442e7c72020-03-10 16:13:48 -0400919 if err != nil {
920 cancel()
npujar1d86a522019-11-14 17:11:16 +0530921 return err
serkant.uluderya334479d2019-04-10 08:26:15 -0700922 }
khenaidoo442e7c72020-03-10 16:13:48 -0400923 go agent.waitForAdapterResponse(subCtx, cancel, "simulateAlarm", ch, agent.onSuccess, agent.onFailure)
serkant.uluderya334479d2019-04-10 08:26:15 -0700924 return nil
925}
Mahir Gunyelb5851672019-07-24 10:46:26 +0300926
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400927// This function updates the device in the DB, releases the device lock, and runs any state transitions.
928// The calling function MUST hold the device lock. The caller MUST NOT modify the device after this is called.
929func (agent *Agent) updateDeviceAndReleaseLock(ctx context.Context, device *voltha.Device) error {
930 // fail early if this agent is no longer valid
Kent Hagerman4f355f52020-03-30 16:01:33 -0400931 if agent.stopped {
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400932 agent.requestQueue.RequestComplete()
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530933 return errors.New("device-agent-stopped")
Thomas Lee Se5a44012019-11-07 20:32:24 +0530934 }
Kent Hagerman4f355f52020-03-30 16:01:33 -0400935
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400936 // update in db
Kent Hagermanf5a67352020-04-30 15:15:26 -0400937 if err := agent.dbProxy.Set(ctx, agent.deviceID, device); err != nil {
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400938 agent.requestQueue.RequestComplete()
Kent Hagerman4f355f52020-03-30 16:01:33 -0400939 return status.Errorf(codes.Internal, "failed-update-device:%s: %s", agent.deviceID, err)
Mahir Gunyelb5851672019-07-24 10:46:26 +0300940 }
divyadesaicb8b59d2020-08-18 09:55:47 +0000941 logger.Debugw(ctx, "updated-device-in-store", log.Fields{"device-id: ": agent.deviceID})
Mahir Gunyelb5851672019-07-24 10:46:26 +0300942
Kent Hagerman6031aad2020-07-29 16:36:33 -0400943 prevDevice := agent.device
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400944 // update the device
khenaidoo0db4c812020-05-27 15:27:30 -0400945 agent.device = device
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400946
947 // release lock before processing transition
948 agent.requestQueue.RequestComplete()
Himani Chawlab4c25912020-11-12 17:16:38 +0530949 subCtx := coreutils.WithSpanAndRPCMetadataFromContext(ctx)
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400950
Himani Chawlab4c25912020-11-12 17:16:38 +0530951 if err := agent.deviceMgr.stateTransitions.ProcessTransition(subCtx,
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530952 device, prevDevice, voltha.DeviceTransientState_NONE, voltha.DeviceTransientState_NONE); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530953 logger.Errorw(ctx, "failed-process-transition", log.Fields{"device-id": device.Id, "previous-admin-state": prevDevice.AdminState, "current-admin-state": device.AdminState})
954 // Sending RPC EVENT here
955 rpce := agent.deviceMgr.NewRPCEvent(ctx, agent.deviceID, err.Error(), nil)
956 go agent.deviceMgr.SendRPCEvent(ctx, "RPC_ERROR_RAISE_EVENT", rpce, voltha.EventCategory_COMMUNICATION,
957 nil, time.Now().UnixNano())
958
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400959 }
Mahir Gunyelb5851672019-07-24 10:46:26 +0300960 return nil
961}
Mahir Gunyelfdee9212019-10-16 16:52:21 -0700962
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530963// This function updates the device transient in the DB through loader, releases the device lock, and runs any state transitions.
964// The calling function MUST hold the device lock. The caller MUST NOT modify the device after this is called.
965func (agent *Agent) updateDeviceWithTransientStateAndReleaseLock(ctx context.Context, device *voltha.Device,
966 transientState, prevTransientState voltha.DeviceTransientState_Types) error {
967 // fail early if this agent is no longer valid
968 if agent.stopped {
969 agent.requestQueue.RequestComplete()
970 return errors.New("device-agent-stopped")
971 }
972 //update device TransientState
973 if err := agent.updateTransientState(ctx, transientState); err != nil {
974 agent.requestQueue.RequestComplete()
975 return err
976 }
977 // update in db
978 if err := agent.dbProxy.Set(ctx, agent.deviceID, device); err != nil {
979 //Reverting TransientState update
980 err := agent.updateTransientState(ctx, prevTransientState)
981 logger.Errorw(ctx, "failed-to-revert-transient-state-update-on-error", log.Fields{"device-id": device.Id,
Himani Chawlab4c25912020-11-12 17:16:38 +0530982 "previous-transient-state": prevTransientState, "current-transient-state": transientState})
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530983 agent.requestQueue.RequestComplete()
984 return status.Errorf(codes.Internal, "failed-update-device:%s: %s", agent.deviceID, err)
985 }
986
987 logger.Debugw(ctx, "updated-device-in-store", log.Fields{"device-id: ": agent.deviceID})
988
989 prevDevice := agent.device
990 // update the device
991 agent.device = device
992
993 // release lock before processing transition
994 agent.requestQueue.RequestComplete()
Himani Chawlab4c25912020-11-12 17:16:38 +0530995 subCtx := coreutils.WithSpanAndRPCMetadataFromContext(ctx)
996 if err := agent.deviceMgr.stateTransitions.ProcessTransition(subCtx,
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530997 device, prevDevice, transientState, prevTransientState); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530998 logger.Errorw(ctx, "failed-process-transition", log.Fields{"device-id": device.Id, "previous-admin-state": prevDevice.AdminState, "current-admin-state": device.AdminState})
999 // Sending RPC EVENT here
1000 rpce := agent.deviceMgr.NewRPCEvent(ctx, agent.deviceID, err.Error(), nil)
1001 go agent.deviceMgr.SendRPCEvent(ctx, "RPC_ERROR_RAISE_EVENT", rpce, voltha.EventCategory_COMMUNICATION,
1002 nil, time.Now().UnixNano())
Himani Chawla2ba1c9c2020-10-07 13:19:03 +05301003 }
1004 return nil
1005}
Kent Hagerman2b216042020-04-03 18:28:56 -04001006func (agent *Agent) updateDeviceReason(ctx context.Context, reason string) error {
khenaidoo442e7c72020-03-10 16:13:48 -04001007 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1008 return err
1009 }
Maninder9a1bc0d2020-10-26 11:34:02 +05301010
Himani Chawlab4c25912020-11-12 17:16:38 +05301011 logger.Debugw(ctx, "update-device-reason", log.Fields{"device-id": agent.deviceID, "reason": reason})
khenaidoo6e55d9e2019-12-12 18:26:26 -05001012
Maninder9a1bc0d2020-10-26 11:34:02 +05301013 var desc string
1014 operStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
1015
1016 defer agent.logDeviceUpdate(ctx, "updateDeviceReason", nil, nil, operStatus, &desc)
1017
Kent Hagermanf6db9f12020-07-22 17:16:19 -04001018 cloned := agent.cloneDeviceWithoutLock()
npujar1d86a522019-11-14 17:11:16 +05301019 cloned.Reason = reason
Maninder9a1bc0d2020-10-26 11:34:02 +05301020 retErr := agent.updateDeviceAndReleaseLock(ctx, cloned)
1021 if retErr != nil {
1022 desc = retErr.Error()
1023 } else {
1024 operStatus.Code = common.OperationResp_OPERATION_SUCCESS
1025 desc = reason
1026 }
1027 return retErr
Mahir Gunyelfdee9212019-10-16 16:52:21 -07001028}
kesavandbc2d1622020-01-21 00:42:01 -05001029
Kent Hagerman2b216042020-04-03 18:28:56 -04001030func (agent *Agent) ChildDeviceLost(ctx context.Context, device *voltha.Device) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301031 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 -05001032
Kent Hagerman2a07b862020-06-19 15:23:07 -04001033 // Remove the associated peer ports on the parent device
1034 for portID := range agent.portLoader.ListIDs() {
1035 if portHandle, have := agent.portLoader.Lock(portID); have {
1036 oldPort := portHandle.GetReadOnly()
1037 updatedPeers := make([]*voltha.Port_PeerPort, 0)
1038 for _, peerPort := range oldPort.Peers {
1039 if peerPort.DeviceId != device.Id {
1040 updatedPeers = append(updatedPeers, peerPort)
1041 }
khenaidoo442e7c72020-03-10 16:13:48 -04001042 }
Kent Hagerman2a07b862020-06-19 15:23:07 -04001043 newPort := *oldPort
1044 newPort.Peers = updatedPeers
1045 if err := portHandle.Update(ctx, &newPort); err != nil {
1046 portHandle.Unlock()
1047 return nil
1048 }
1049 portHandle.Unlock()
khenaidoo442e7c72020-03-10 16:13:48 -04001050 }
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001051 }
1052
khenaidoo442e7c72020-03-10 16:13:48 -04001053 //send request to adapter
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001054 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
Himani Chawlab4c25912020-11-12 17:16:38 +05301055 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
1056
Girish Gowdra6f9b10e2021-03-11 14:36:39 -08001057 ch, err := agent.adapterProxy.ChildDeviceLost(ctx, agent.deviceType, device)
khenaidoo442e7c72020-03-10 16:13:48 -04001058 if err != nil {
1059 cancel()
1060 return err
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001061 }
khenaidoo442e7c72020-03-10 16:13:48 -04001062 go agent.waitForAdapterResponse(subCtx, cancel, "childDeviceLost", ch, agent.onSuccess, agent.onFailure)
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001063 return nil
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001064}
onkarkundargi87285252020-01-27 11:34:52 +05301065
Kent Hagerman2b216042020-04-03 18:28:56 -04001066func (agent *Agent) startOmciTest(ctx context.Context, omcitestrequest *voltha.OmciTestRequest) (*voltha.TestResponse, error) {
onkarkundargi87285252020-01-27 11:34:52 +05301067 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1068 return nil, err
1069 }
1070
Kent Hagermanf6db9f12020-07-22 17:16:19 -04001071 cloned := agent.cloneDeviceWithoutLock()
Matteo Scandolod525ae32020-04-02 17:27:29 -07001072
Kent Hagermanf6db9f12020-07-22 17:16:19 -04001073 if cloned.Adapter == "" {
1074 adapterName, err := agent.adapterMgr.GetAdapterType(cloned.Type)
Matteo Scandolod525ae32020-04-02 17:27:29 -07001075 if err != nil {
1076 agent.requestQueue.RequestComplete()
1077 return nil, err
1078 }
Kent Hagermanf6db9f12020-07-22 17:16:19 -04001079 cloned.Adapter = adapterName
onkarkundargi87285252020-01-27 11:34:52 +05301080 }
1081
1082 // Send request to the adapter
Kent Hagermanf6db9f12020-07-22 17:16:19 -04001083 ch, err := agent.adapterProxy.StartOmciTest(ctx, cloned, omcitestrequest)
onkarkundargi87285252020-01-27 11:34:52 +05301084 agent.requestQueue.RequestComplete()
1085 if err != nil {
1086 return nil, err
1087 }
1088
1089 // Wait for the adapter response
1090 rpcResponse, ok := <-ch
1091 if !ok {
1092 return nil, status.Errorf(codes.Aborted, "channel-closed-device-id-%s", agent.deviceID)
1093 }
1094 if rpcResponse.Err != nil {
1095 return nil, rpcResponse.Err
1096 }
1097
1098 // Unmarshal and return the response
1099 testResp := &voltha.TestResponse{}
1100 if err := ptypes.UnmarshalAny(rpcResponse.Reply, testResp); err != nil {
1101 return nil, status.Errorf(codes.InvalidArgument, "%s", err.Error())
1102 }
Himani Chawlab4c25912020-11-12 17:16:38 +05301103 logger.Debugw(ctx, "omci_test_request-success-device-agent", log.Fields{"test-resp": testResp})
onkarkundargi87285252020-01-27 11:34:52 +05301104 return testResp, nil
1105}
Dinesh Belwalkarc1129f12020-02-27 10:41:33 -08001106
1107func (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 +05301108 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 -08001109 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1110 return nil, err
1111 }
1112
1113 //send request to adapter
1114 ch, err := agent.adapterProxy.GetExtValue(ctx, pdevice, cdevice, valueparam.Id, valueparam.Value)
1115 agent.requestQueue.RequestComplete()
1116 if err != nil {
1117 return nil, err
1118 }
1119
1120 // Wait for the adapter response
1121 rpcResponse, ok := <-ch
1122 if !ok {
1123 return nil, status.Errorf(codes.Aborted, "channel-closed-device-id-%s", agent.deviceID)
1124 }
1125 if rpcResponse.Err != nil {
1126 return nil, rpcResponse.Err
1127 }
1128
1129 // Unmarshal and return the response
1130 Resp := &voltha.ReturnValues{}
1131 if err := ptypes.UnmarshalAny(rpcResponse.Reply, Resp); err != nil {
1132 return nil, status.Errorf(codes.InvalidArgument, "%s", err.Error())
1133 }
Himani Chawlab4c25912020-11-12 17:16:38 +05301134 logger.Debugw(ctx, "get-ext-value-success-device-agent", log.Fields{"Resp": Resp})
Dinesh Belwalkarc1129f12020-02-27 10:41:33 -08001135 return Resp, nil
1136}
dpaul62686312020-06-23 14:17:36 +05301137
1138func (agent *Agent) setExtValue(ctx context.Context, device *voltha.Device, value *voltha.ValueSet) (*empty.Empty, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301139 logger.Debugw(ctx, "set-ext-value", log.Fields{"device-id": value.Id})
dpaul62686312020-06-23 14:17:36 +05301140 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1141 return nil, err
1142 }
1143
1144 //send request to adapter
1145 ch, err := agent.adapterProxy.SetExtValue(ctx, device, value)
1146 agent.requestQueue.RequestComplete()
1147 if err != nil {
1148 return nil, err
1149 }
1150
1151 // Wait for the adapter response
1152 rpcResponse, ok := <-ch
1153 if !ok {
1154 return nil, status.Errorf(codes.Aborted, "channel-closed-device-id-%s", agent.deviceID)
1155 }
1156 if rpcResponse.Err != nil {
1157 return nil, rpcResponse.Err
1158 }
1159
1160 // Unmarshal and return the response
Himani Chawlab4c25912020-11-12 17:16:38 +05301161 logger.Debug(ctx, "set-ext-value-success-device-agent")
dpaul62686312020-06-23 14:17:36 +05301162 return &empty.Empty{}, nil
1163}
Salman Siddiqui1cf95042020-11-19 00:42:56 +05301164
1165func (agent *Agent) getSingleValue(ctx context.Context, request *extension.SingleGetValueRequest) (*extension.SingleGetValueResponse, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301166 logger.Debugw(ctx, "get-single-value", log.Fields{"device-id": request.TargetId})
Salman Siddiqui1cf95042020-11-19 00:42:56 +05301167
1168 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1169 return nil, err
1170 }
1171
1172 cloned := agent.cloneDeviceWithoutLock()
1173
1174 //send request to adapter
1175 ch, err := agent.adapterProxy.GetSingleValue(ctx, cloned.Adapter, request)
1176 agent.requestQueue.RequestComplete()
1177 if err != nil {
1178 return nil, err
1179 }
1180
1181 // Wait for the adapter response
1182 rpcResponse, ok := <-ch
1183 if !ok {
1184 return nil, status.Errorf(codes.Aborted, "channel-closed-device-id-%s", agent.deviceID)
1185 }
1186
1187 if rpcResponse.Err != nil {
1188 return nil, rpcResponse.Err
1189 }
1190
1191 resp := &extension.SingleGetValueResponse{}
1192 if err := ptypes.UnmarshalAny(rpcResponse.Reply, resp); err != nil {
1193 return nil, status.Errorf(codes.InvalidArgument, "%s", err.Error())
1194 }
1195
1196 return resp, nil
1197}
1198
1199func (agent *Agent) setSingleValue(ctx context.Context, request *extension.SingleSetValueRequest) (*extension.SingleSetValueResponse, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301200 logger.Debugw(ctx, "set-single-value", log.Fields{"device-id": request.TargetId})
Salman Siddiqui1cf95042020-11-19 00:42:56 +05301201
1202 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1203 return nil, err
1204 }
1205
1206 cloned := agent.cloneDeviceWithoutLock()
1207
1208 //send request to adapter
1209 ch, err := agent.adapterProxy.SetSingleValue(ctx, cloned.Adapter, request)
1210 agent.requestQueue.RequestComplete()
1211 if err != nil {
1212 return nil, err
1213 }
1214
1215 // Wait for the adapter response
1216 rpcResponse, ok := <-ch
1217 if !ok {
1218 return nil, status.Errorf(codes.Aborted, "channel-closed-cloned-id-%s", agent.deviceID)
1219 }
1220
1221 if rpcResponse.Err != nil {
1222 return nil, rpcResponse.Err
1223 }
1224
1225 resp := &extension.SingleSetValueResponse{}
1226 if err := ptypes.UnmarshalAny(rpcResponse.Reply, resp); err != nil {
1227 return nil, status.Errorf(codes.InvalidArgument, "%s", err.Error())
1228 }
1229
1230 return resp, nil
1231}