blob: bc5fc1a77b44a6acb239757f95b6723d8b6b3bf3 [file] [log] [blame]
khenaidoob9203542018-09-17 22:56:37 -04001/*
2 * Copyright 2018-present Open Networking Foundation
3
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7
8 * http://www.apache.org/licenses/LICENSE-2.0
9
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
npujar1d86a522019-11-14 17:11:16 +053016
Kent Hagerman2b216042020-04-03 18:28:56 -040017package device
khenaidoob9203542018-09-17 22:56:37 -040018
19import (
20 "context"
Matteo Scandolo360605d2019-11-05 18:29:17 -080021 "encoding/hex"
Kent Hagerman4f355f52020-03-30 16:01:33 -040022 "errors"
khenaidoo3ab34882019-05-02 21:33:30 -040023 "fmt"
Mahir Gunyeladdb66a2020-04-29 18:08:50 -070024 "reflect"
25 "sync"
26 "time"
27
Himani Chawla2ba1c9c2020-10-07 13:19:03 +053028 "github.com/gogo/protobuf/proto"
khenaidoo442e7c72020-03-10 16:13:48 -040029 "github.com/golang/protobuf/ptypes"
dpaul62686312020-06-23 14:17:36 +053030 "github.com/golang/protobuf/ptypes/empty"
Himani Chawla2ba1c9c2020-10-07 13:19:03 +053031 "github.com/opencord/voltha-go/db/model"
Kent Hagerman2b216042020-04-03 18:28:56 -040032 "github.com/opencord/voltha-go/rw_core/core/adapter"
Mahir Gunyel03de0d32020-06-03 01:36:59 -070033 "github.com/opencord/voltha-go/rw_core/core/device/flow"
34 "github.com/opencord/voltha-go/rw_core/core/device/group"
Kent Hagerman2a07b862020-06-19 15:23:07 -040035 "github.com/opencord/voltha-go/rw_core/core/device/port"
Kent Hagerman2b216042020-04-03 18:28:56 -040036 "github.com/opencord/voltha-go/rw_core/core/device/remote"
Himani Chawla2ba1c9c2020-10-07 13:19:03 +053037 "github.com/opencord/voltha-go/rw_core/core/device/transientstate"
Scott Bakerb671a862019-10-24 10:53:40 -070038 coreutils "github.com/opencord/voltha-go/rw_core/utils"
Himani Chawla2ba1c9c2020-10-07 13:19:03 +053039 "github.com/opencord/voltha-lib-go/v4/pkg/kafka"
Maninderdfadc982020-10-28 14:04:33 +053040 "github.com/opencord/voltha-lib-go/v4/pkg/log"
Salman Siddiqui1cf95042020-11-19 00:42:56 +053041 "github.com/opencord/voltha-protos/v4/go/extension"
Maninderdfadc982020-10-28 14:04:33 +053042 ic "github.com/opencord/voltha-protos/v4/go/inter_container"
43 ofp "github.com/opencord/voltha-protos/v4/go/openflow_13"
44 "github.com/opencord/voltha-protos/v4/go/voltha"
khenaidoob9203542018-09-17 22:56:37 -040045 "google.golang.org/grpc/codes"
46 "google.golang.org/grpc/status"
khenaidoob9203542018-09-17 22:56:37 -040047)
48
Kent Hagerman2b216042020-04-03 18:28:56 -040049// Agent represents device agent attributes
50type Agent struct {
Kent Hagermanf5a67352020-04-30 15:15:26 -040051 deviceID string
52 parentID string
53 deviceType string
Kent Hagerman2a07b862020-06-19 15:23:07 -040054 isRootDevice bool
Kent Hagermanf5a67352020-04-30 15:15:26 -040055 adapterProxy *remote.AdapterProxy
56 adapterMgr *adapter.Manager
57 deviceMgr *Manager
58 dbProxy *model.Proxy
59 exitChannel chan int
60 device *voltha.Device
61 requestQueue *coreutils.RequestQueue
62 defaultTimeout time.Duration
63 startOnce sync.Once
64 stopOnce sync.Once
65 stopped bool
Mahir Gunyel03de0d32020-06-03 01:36:59 -070066
Himani Chawla2ba1c9c2020-10-07 13:19:03 +053067 flowLoader *flow.Loader
68 groupLoader *group.Loader
69 portLoader *port.Loader
70 transientStateLoader *transientstate.Loader
khenaidoob9203542018-09-17 22:56:37 -040071}
72
Kent Hagerman2b216042020-04-03 18:28:56 -040073//newAgent creates a new device agent. The device will be initialized when start() is called.
Kent Hagerman2a07b862020-06-19 15:23:07 -040074func newAgent(ap *remote.AdapterProxy, device *voltha.Device, deviceMgr *Manager, dbPath *model.Path, deviceProxy *model.Proxy, timeout time.Duration) *Agent {
75 deviceID := device.Id
76 if deviceID == "" {
77 deviceID = coreutils.CreateDeviceID()
Stephane Barbarie1ab43272018-12-08 21:42:13 -050078 }
Scott Baker80678602019-11-14 16:57:36 -080079
Kent Hagerman2a07b862020-06-19 15:23:07 -040080 return &Agent{
Himani Chawla2ba1c9c2020-10-07 13:19:03 +053081 deviceID: deviceID,
82 adapterProxy: ap,
83 isRootDevice: device.Root,
84 parentID: device.ParentId,
85 deviceType: device.Type,
86 deviceMgr: deviceMgr,
87 adapterMgr: deviceMgr.adapterMgr,
88 exitChannel: make(chan int, 1),
89 dbProxy: deviceProxy,
90 defaultTimeout: timeout,
91 device: proto.Clone(device).(*voltha.Device),
92 requestQueue: coreutils.NewRequestQueue(),
93 flowLoader: flow.NewLoader(dbPath.SubPath("flows").Proxy(deviceID)),
94 groupLoader: group.NewLoader(dbPath.SubPath("groups").Proxy(deviceID)),
95 portLoader: port.NewLoader(dbPath.SubPath("ports").Proxy(deviceID)),
96 transientStateLoader: transientstate.NewLoader(dbPath.SubPath("core").Proxy("transientstate"), deviceID),
Kent Hagerman2a07b862020-06-19 15:23:07 -040097 }
khenaidoob9203542018-09-17 22:56:37 -040098}
99
khenaidoo442e7c72020-03-10 16:13:48 -0400100// start() saves the device to the data model and registers for callbacks on that device if deviceToCreate!=nil.
101// 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 -0800102// was started.
Kent Hagerman2b216042020-04-03 18:28:56 -0400103func (agent *Agent) start(ctx context.Context, deviceToCreate *voltha.Device) (*voltha.Device, error) {
khenaidoo442e7c72020-03-10 16:13:48 -0400104 needToStart := false
105 if agent.startOnce.Do(func() { needToStart = true }); !needToStart {
Kent Hagermancba2f302020-07-28 13:37:36 -0400106 return agent.getDeviceReadOnly(ctx)
khenaidoo442e7c72020-03-10 16:13:48 -0400107 }
108 var startSucceeded bool
109 defer func() {
110 if !startSucceeded {
111 if err := agent.stop(ctx); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000112 logger.Errorw(ctx, "failed-to-cleanup-after-unsuccessful-start", log.Fields{"device-id": agent.deviceID, "error": err})
khenaidoo442e7c72020-03-10 16:13:48 -0400113 }
114 }
115 }()
Scott Baker80678602019-11-14 16:57:36 -0800116
khenaidoo442e7c72020-03-10 16:13:48 -0400117 var device *voltha.Device
Scott Baker80678602019-11-14 16:57:36 -0800118 if deviceToCreate == nil {
119 // Load the existing device
Kent Hagerman4f355f52020-03-30 16:01:33 -0400120 device := &voltha.Device{}
Kent Hagermanf5a67352020-04-30 15:15:26 -0400121 have, err := agent.dbProxy.Get(ctx, agent.deviceID, device)
Thomas Lee Se5a44012019-11-07 20:32:24 +0530122 if err != nil {
Thomas Lee Se5a44012019-11-07 20:32:24 +0530123 return nil, err
Kent Hagerman4f355f52020-03-30 16:01:33 -0400124 } else if !have {
125 return nil, status.Errorf(codes.NotFound, "device-%s", agent.deviceID)
Thomas Lee Se5a44012019-11-07 20:32:24 +0530126 }
Kent Hagerman4f355f52020-03-30 16:01:33 -0400127
128 agent.deviceType = device.Adapter
129 agent.device = proto.Clone(device).(*voltha.Device)
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700130 // load the flows and groups from KV to cache
131 agent.flowLoader.Load(ctx)
132 agent.groupLoader.Load(ctx)
Kent Hagerman2a07b862020-06-19 15:23:07 -0400133 agent.portLoader.Load(ctx)
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530134 agent.transientStateLoader.Load(ctx)
Kent Hagerman4f355f52020-03-30 16:01:33 -0400135
Himani Chawlab4c25912020-11-12 17:16:38 +0530136 logger.Infow(ctx, "device-loaded-from-db", log.Fields{"device-id": agent.deviceID})
khenaidoo297cd252019-02-07 22:10:23 -0500137 } else {
Scott Baker80678602019-11-14 16:57:36 -0800138 // Create a new device
Kent Hagermanf5a67352020-04-30 15:15:26 -0400139 // Assumption is that AdminState, FlowGroups, and Flows are uninitialized since this
140 // is a new device, so populate them here before passing the device to ldProxy.Set.
Kent Hagerman2b216042020-04-03 18:28:56 -0400141 // agent.deviceId will also have been set during newAgent().
Scott Baker80678602019-11-14 16:57:36 -0800142 device = (proto.Clone(deviceToCreate)).(*voltha.Device)
npujar1d86a522019-11-14 17:11:16 +0530143 device.Id = agent.deviceID
Scott Baker80678602019-11-14 16:57:36 -0800144 device.AdminState = voltha.AdminState_PREPROVISIONED
Scott Baker80678602019-11-14 16:57:36 -0800145 if !deviceToCreate.GetRoot() && deviceToCreate.ProxyAddress != nil {
146 // Set the default vlan ID to the one specified by the parent adapter. It can be
147 // overwritten by the child adapter during a device update request
148 device.Vlan = deviceToCreate.ProxyAddress.ChannelId
149 }
150
khenaidoo297cd252019-02-07 22:10:23 -0500151 // Add the initial device to the local model
Kent Hagermanf5a67352020-04-30 15:15:26 -0400152 if err := agent.dbProxy.Set(ctx, agent.deviceID, device); err != nil {
Kent Hagerman4f355f52020-03-30 16:01:33 -0400153 return nil, status.Errorf(codes.Aborted, "failed-adding-device-%s: %s", agent.deviceID, err)
khenaidoo297cd252019-02-07 22:10:23 -0500154 }
khenaidoo442e7c72020-03-10 16:13:48 -0400155 agent.device = device
khenaidoob9203542018-09-17 22:56:37 -0400156 }
khenaidoo442e7c72020-03-10 16:13:48 -0400157 startSucceeded = true
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000158 log.EnrichSpan(ctx, log.Fields{"device-id": agent.deviceID})
Rohan Agrawal31f21802020-06-12 05:38:46 +0000159 logger.Debugw(ctx, "device-agent-started", log.Fields{"device-id": agent.deviceID})
khenaidoo442e7c72020-03-10 16:13:48 -0400160
Kent Hagermancba2f302020-07-28 13:37:36 -0400161 return agent.getDeviceReadOnly(ctx)
khenaidoob9203542018-09-17 22:56:37 -0400162}
163
khenaidoo4d4802d2018-10-04 21:59:49 -0400164// stop stops the device agent. Not much to do for now
Kent Hagerman2b216042020-04-03 18:28:56 -0400165func (agent *Agent) stop(ctx context.Context) error {
khenaidoo442e7c72020-03-10 16:13:48 -0400166 needToStop := false
167 if agent.stopOnce.Do(func() { needToStop = true }); !needToStop {
168 return nil
169 }
170 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
171 return err
172 }
173 defer agent.requestQueue.RequestComplete()
khenaidoo49085352020-01-13 19:15:43 -0500174
Himani Chawlab4c25912020-11-12 17:16:38 +0530175 logger.Infow(ctx, "stopping-device-agent", log.Fields{"device-id": agent.deviceID, "parent-id": agent.parentID})
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530176 // Remove the device transient loader
177 if err := agent.deleteTransientState(ctx); err != nil {
178 return err
179 }
khenaidoo0a822f92019-05-08 15:15:57 -0400180 // Remove the device from the KV store
Kent Hagermanf5a67352020-04-30 15:15:26 -0400181 if err := agent.dbProxy.Remove(ctx, agent.deviceID); err != nil {
khenaidoo442e7c72020-03-10 16:13:48 -0400182 return err
Thomas Lee Se5a44012019-11-07 20:32:24 +0530183 }
khenaidoo442e7c72020-03-10 16:13:48 -0400184
khenaidoo442e7c72020-03-10 16:13:48 -0400185 close(agent.exitChannel)
186
187 agent.stopped = true
188
Rohan Agrawal31f21802020-06-12 05:38:46 +0000189 logger.Infow(ctx, "device-agent-stopped", log.Fields{"device-id": agent.deviceID, "parent-id": agent.parentID})
khenaidoo442e7c72020-03-10 16:13:48 -0400190
191 return nil
khenaidoob9203542018-09-17 22:56:37 -0400192}
193
Scott Baker80678602019-11-14 16:57:36 -0800194// Load the most recent state from the KVStore for the device.
Kent Hagerman2b216042020-04-03 18:28:56 -0400195func (agent *Agent) reconcileWithKVStore(ctx context.Context) {
khenaidoo442e7c72020-03-10 16:13:48 -0400196 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000197 logger.Warnw(ctx, "request-aborted", log.Fields{"device-id": agent.deviceID, "error": err})
khenaidoo442e7c72020-03-10 16:13:48 -0400198 return
199 }
200 defer agent.requestQueue.RequestComplete()
Rohan Agrawal31f21802020-06-12 05:38:46 +0000201 logger.Debug(ctx, "reconciling-device-agent-devicetype")
Scott Baker80678602019-11-14 16:57:36 -0800202 // TODO: context timeout
Kent Hagerman4f355f52020-03-30 16:01:33 -0400203 device := &voltha.Device{}
Kent Hagermanf5a67352020-04-30 15:15:26 -0400204 if have, err := agent.dbProxy.Get(ctx, agent.deviceID, device); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000205 logger.Errorw(ctx, "kv-get-failed", log.Fields{"device-id": agent.deviceID, "error": err})
Thomas Lee Se5a44012019-11-07 20:32:24 +0530206 return
Kent Hagerman4f355f52020-03-30 16:01:33 -0400207 } else if !have {
208 return // not found in kv
Thomas Lee Se5a44012019-11-07 20:32:24 +0530209 }
Kent Hagerman4f355f52020-03-30 16:01:33 -0400210
211 agent.deviceType = device.Adapter
212 agent.device = device
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700213 agent.flowLoader.Load(ctx)
214 agent.groupLoader.Load(ctx)
Kent Hagerman2a07b862020-06-19 15:23:07 -0400215 agent.portLoader.Load(ctx)
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530216 agent.transientStateLoader.Load(ctx)
217
Rohan Agrawal31f21802020-06-12 05:38:46 +0000218 logger.Debugw(ctx, "reconciled-device-agent-devicetype", log.Fields{"device-id": agent.deviceID, "type": agent.deviceType})
Scott Baker80678602019-11-14 16:57:36 -0800219}
220
khenaidoo442e7c72020-03-10 16:13:48 -0400221// onSuccess is a common callback for scenarios where we receive a nil response following a request to an adapter
222// and the only action required is to publish a successful result on kafka
Rohan Agrawal31f21802020-06-12 05:38:46 +0000223func (agent *Agent) onSuccess(ctx context.Context, rpc string, response interface{}, reqArgs ...interface{}) {
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530224 logger.Debugw(ctx, "response-successful", log.Fields{"rpc": rpc, "device-id": agent.deviceID})
khenaidoo442e7c72020-03-10 16:13:48 -0400225 // TODO: Post success message onto kafka
226}
227
228// onFailure is a common callback for scenarios where we receive an error response following a request to an adapter
229// and the only action required is to publish the failed result on kafka
Rohan Agrawal31f21802020-06-12 05:38:46 +0000230func (agent *Agent) onFailure(ctx context.Context, rpc string, response interface{}, reqArgs ...interface{}) {
khenaidoo442e7c72020-03-10 16:13:48 -0400231 if res, ok := response.(error); ok {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000232 logger.Errorw(ctx, "rpc-failed", log.Fields{"rpc": rpc, "device-id": agent.deviceID, "error": res, "args": reqArgs})
khenaidoo442e7c72020-03-10 16:13:48 -0400233 } else {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000234 logger.Errorw(ctx, "rpc-failed-invalid-error", log.Fields{"rpc": rpc, "device-id": agent.deviceID, "args": reqArgs})
khenaidoo442e7c72020-03-10 16:13:48 -0400235 }
236 // TODO: Post failure message onto kafka
237}
238
Himani Chawlab4c25912020-11-12 17:16:38 +0530239func (agent *Agent) waitForAdapterForceDeleteResponse(ctx context.Context, cancel context.CancelFunc, rpc string, ch chan *kafka.RpcResponse,
khenaidoo442e7c72020-03-10 16:13:48 -0400240 onSuccess coreutils.ResponseCallback, onFailure coreutils.ResponseCallback, reqArgs ...interface{}) {
241 defer cancel()
242 select {
243 case rpcResponse, ok := <-ch:
244 if !ok {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000245 onFailure(ctx, rpc, status.Errorf(codes.Aborted, "channel-closed"), reqArgs)
khenaidoo442e7c72020-03-10 16:13:48 -0400246 } else if rpcResponse.Err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000247 onFailure(ctx, rpc, rpcResponse.Err, reqArgs)
khenaidoo442e7c72020-03-10 16:13:48 -0400248 } else {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000249 onSuccess(ctx, rpc, rpcResponse.Reply, reqArgs)
khenaidoo442e7c72020-03-10 16:13:48 -0400250 }
251 case <-ctx.Done():
Rohan Agrawal31f21802020-06-12 05:38:46 +0000252 onFailure(ctx, rpc, ctx.Err(), reqArgs)
khenaidoo442e7c72020-03-10 16:13:48 -0400253 }
254}
255
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530256// onDeleteSuccess is a common callback for scenarios where we receive a nil response following a delete request
257// to an adapter.
258func (agent *Agent) onDeleteSuccess(ctx context.Context, rpc string, response interface{}, reqArgs ...interface{}) {
259 logger.Debugw(ctx, "response-successful", log.Fields{"rpc": rpc, "device-id": agent.deviceID})
260 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
261 logger.Errorw(ctx, "delete-device-failure", log.Fields{"device-id": agent.deviceID, "error": err, "args": reqArgs})
262 }
263 previousDeviceTransientState := agent.getTransientState()
264 newDevice := agent.cloneDeviceWithoutLock()
265 if err := agent.updateDeviceWithTransientStateAndReleaseLock(ctx, newDevice,
266 voltha.DeviceTransientState_DELETING_POST_ADAPTER_RESPONSE, previousDeviceTransientState); err != nil {
267 logger.Errorw(ctx, "delete-device-failure", log.Fields{"device-id": agent.deviceID, "error": err, "args": reqArgs})
268 }
269}
270
271// onDeleteFailure is a common callback for scenarios where we receive an error response following a delete request
272// to an adapter and the only action required is to return the error response.
273func (agent *Agent) onDeleteFailure(ctx context.Context, rpc string, response interface{}, reqArgs ...interface{}) {
274 if res, ok := response.(error); ok {
275 logger.Errorw(ctx, "rpc-failed", log.Fields{"rpc": rpc, "device-id": agent.deviceID, "error": res, "args": reqArgs})
276 } else {
277 logger.Errorw(ctx, "rpc-failed-invalid-error", log.Fields{"rpc": rpc, "device-id": agent.deviceID, "args": reqArgs})
278 }
279 //Only updating of transient state is required, no transition.
280 if err := agent.updateTransientState(ctx, voltha.DeviceTransientState_DELETE_FAILED); err != nil {
281 logger.Errorw(ctx, "failed-to-update-transient-state-as-delete-failed", log.Fields{"device-id": agent.deviceID})
282 }
283
284}
285
Himani Chawlab4c25912020-11-12 17:16:38 +0530286func (agent *Agent) waitForAdapterResponse(ctx context.Context, cancel context.CancelFunc, rpc string, ch chan *kafka.RpcResponse,
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530287 onSuccess coreutils.ResponseCallback, onFailure coreutils.ResponseCallback, reqArgs ...interface{}) {
288 defer cancel()
Himani Chawlab4c25912020-11-12 17:16:38 +0530289 var rpce *voltha.RPCEvent
290 defer func() {
291 if rpce != nil {
292 go agent.deviceMgr.SendRPCEvent(ctx, "RPC_ERROR_RAISE_EVENT", rpce,
293 voltha.EventCategory_COMMUNICATION, nil, time.Now().UnixNano())
294 }
295 }()
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530296 select {
297 case rpcResponse, ok := <-ch:
298 if !ok {
Himani Chawlab4c25912020-11-12 17:16:38 +0530299 rpce = agent.deviceMgr.NewRPCEvent(ctx, agent.deviceID, "Response Channel Closed", nil)
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530300 onFailure(ctx, rpc, status.Errorf(codes.Aborted, "channel-closed"), reqArgs)
Himani Chawlab4c25912020-11-12 17:16:38 +0530301 //add failure
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530302 } else if rpcResponse.Err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530303 rpce = agent.deviceMgr.NewRPCEvent(ctx, agent.deviceID, rpcResponse.Err.Error(), nil)
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530304 onFailure(ctx, rpc, rpcResponse.Err, reqArgs)
Himani Chawlab4c25912020-11-12 17:16:38 +0530305 //add failure
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530306 } else {
307 onSuccess(ctx, rpc, rpcResponse.Reply, reqArgs)
308 }
309 case <-ctx.Done():
Himani Chawlab4c25912020-11-12 17:16:38 +0530310 rpce = agent.deviceMgr.NewRPCEvent(ctx, agent.deviceID, ctx.Err().Error(), nil)
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530311 onFailure(ctx, rpc, ctx.Err(), reqArgs)
312 }
313}
314
Kent Hagermancba2f302020-07-28 13:37:36 -0400315// getDeviceReadOnly returns a device which MUST NOT be modified, but is safe to keep forever.
316func (agent *Agent) getDeviceReadOnly(ctx context.Context) (*voltha.Device, error) {
khenaidoo442e7c72020-03-10 16:13:48 -0400317 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
318 return nil, err
319 }
320 defer agent.requestQueue.RequestComplete()
Kent Hagermancba2f302020-07-28 13:37:36 -0400321 return agent.device, nil
khenaidoo92e62c52018-10-03 14:02:54 -0400322}
323
Kent Hagermancba2f302020-07-28 13:37:36 -0400324// 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 -0400325// The device lock MUST be held by the caller.
Kent Hagermancba2f302020-07-28 13:37:36 -0400326func (agent *Agent) getDeviceReadOnlyWithoutLock() *voltha.Device {
khenaidoo0db4c812020-05-27 15:27:30 -0400327 return agent.device
khenaidoo92e62c52018-10-03 14:02:54 -0400328}
329
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400330// cloneDeviceWithoutLock returns a copy of the device which is safe to modify.
331// The device lock MUST be held by the caller.
332func (agent *Agent) cloneDeviceWithoutLock() *voltha.Device {
333 return proto.Clone(agent.device).(*voltha.Device)
334}
335
khenaidoo3ab34882019-05-02 21:33:30 -0400336// enableDevice activates a preprovisioned or a disable device
Kent Hagerman2b216042020-04-03 18:28:56 -0400337func (agent *Agent) enableDevice(ctx context.Context) error {
khenaidoo442e7c72020-03-10 16:13:48 -0400338 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
339 return err
340 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530341 logger.Debugw(ctx, "enable-device", log.Fields{"device-id": agent.deviceID})
khenaidoo21d51152019-02-01 13:48:37 -0500342
Kent Hagermancba2f302020-07-28 13:37:36 -0400343 oldDevice := agent.getDeviceReadOnlyWithoutLock()
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400344 if oldDevice.AdminState == voltha.AdminState_ENABLED {
345 logger.Warnw(ctx, "device-already-enabled", log.Fields{"device-id": agent.deviceID})
346 agent.requestQueue.RequestComplete()
347 return status.Error(codes.FailedPrecondition, fmt.Sprintf("cannot-enable-an-already-enabled-device: %s", oldDevice.Id))
348 }
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530349 if agent.isDeletionInProgress() {
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400350 agent.requestQueue.RequestComplete()
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530351 return status.Errorf(codes.FailedPrecondition, "deviceId:%s, Device deletion is in progress.", agent.deviceID)
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400352 }
npujar1d86a522019-11-14 17:11:16 +0530353 // 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 -0400354 // pre-provisioned with the required adapter not registered. At this stage, since we need to communicate
npujar1d86a522019-11-14 17:11:16 +0530355 // with the adapter then we need to know the adapter that will handle this request
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400356 adapterName, err := agent.adapterMgr.GetAdapterType(oldDevice.Type)
npujar1d86a522019-11-14 17:11:16 +0530357 if err != nil {
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400358 agent.requestQueue.RequestComplete()
Matteo Scandolod525ae32020-04-02 17:27:29 -0700359 return err
npujar1d86a522019-11-14 17:11:16 +0530360 }
361
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400362 newDevice := agent.cloneDeviceWithoutLock()
363 newDevice.Adapter = adapterName
npujar1d86a522019-11-14 17:11:16 +0530364
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400365 // Update the Admin State and set the operational state to activating before sending the request to the Adapters
366 newDevice.AdminState = voltha.AdminState_ENABLED
367 newDevice.OperStatus = voltha.OperStatus_ACTIVATING
368 if err := agent.updateDeviceAndReleaseLock(ctx, newDevice); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530369 return err
370 }
371
khenaidoo442e7c72020-03-10 16:13:48 -0400372 // 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 -0400373 var ch chan *kafka.RpcResponse
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000374 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
Himani Chawlab4c25912020-11-12 17:16:38 +0530375 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
376
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400377 if oldDevice.AdminState == voltha.AdminState_PREPROVISIONED {
378 ch, err = agent.adapterProxy.AdoptDevice(subCtx, newDevice)
khenaidoob9203542018-09-17 22:56:37 -0400379 } else {
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400380 ch, err = agent.adapterProxy.ReEnableDevice(subCtx, newDevice)
khenaidoob9203542018-09-17 22:56:37 -0400381 }
khenaidoo442e7c72020-03-10 16:13:48 -0400382 if err != nil {
383 cancel()
384 return err
385 }
386 // Wait for response
387 go agent.waitForAdapterResponse(subCtx, cancel, "enableDevice", ch, agent.onSuccess, agent.onFailure)
khenaidoob9203542018-09-17 22:56:37 -0400388 return nil
389}
390
Kent Hagerman2b216042020-04-03 18:28:56 -0400391func (agent *Agent) waitForAdapterFlowResponse(ctx context.Context, cancel context.CancelFunc, ch chan *kafka.RpcResponse, response coreutils.Response) {
khenaidoo442e7c72020-03-10 16:13:48 -0400392 defer cancel()
Himani Chawlab4c25912020-11-12 17:16:38 +0530393 var rpce *voltha.RPCEvent
394 defer func() {
395 if rpce != nil {
396 go agent.deviceMgr.SendRPCEvent(ctx, "RPC_ERROR_RAISE_EVENT", rpce,
397 voltha.EventCategory_COMMUNICATION, nil, time.Now().UnixNano())
398 }
399 }()
khenaidoo442e7c72020-03-10 16:13:48 -0400400 select {
401 case rpcResponse, ok := <-ch:
402 if !ok {
Himani Chawlab4c25912020-11-12 17:16:38 +0530403 //add failure
404 rpce = agent.deviceMgr.NewRPCEvent(ctx, agent.deviceID, "Response Channel Closed", nil)
khenaidoo442e7c72020-03-10 16:13:48 -0400405 response.Error(status.Errorf(codes.Aborted, "channel-closed"))
406 } else if rpcResponse.Err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530407 //add failure
408 rpce = agent.deviceMgr.NewRPCEvent(ctx, agent.deviceID, rpcResponse.Err.Error(), nil)
khenaidoo442e7c72020-03-10 16:13:48 -0400409 response.Error(rpcResponse.Err)
410 } else {
411 response.Done()
412 }
413 case <-ctx.Done():
Himani Chawlab4c25912020-11-12 17:16:38 +0530414 rpce = agent.deviceMgr.NewRPCEvent(ctx, agent.deviceID, ctx.Err().Error(), nil)
khenaidoo442e7c72020-03-10 16:13:48 -0400415 response.Error(ctx.Err())
khenaidoo2c6a0992019-04-29 13:46:56 -0400416 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400417}
418
A R Karthick5c28f552019-12-11 22:47:44 -0800419//addFlowsAndGroups adds the "newFlows" and "newGroups" from the existing flows/groups and sends the update to the
420//adapters
Kent Hagerman2b216042020-04-03 18:28:56 -0400421func (agent *Agent) addFlowsAndGroups(ctx context.Context, newFlows []*ofp.OfpFlowStats, newGroups []*ofp.OfpGroupEntry, flowMetadata *voltha.FlowMetadata) error {
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700422 var flwResponse, grpResponse coreutils.Response
423 var err error
424 //if new flow list is empty then the called function returns quickly
425 if flwResponse, err = agent.addFlowsToAdapter(ctx, newFlows, flowMetadata); err != nil {
A R Karthick5c28f552019-12-11 22:47:44 -0800426 return err
427 }
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700428 //if new group list is empty then the called function returns quickly
429 if grpResponse, err = agent.addGroupsToAdapter(ctx, newGroups, flowMetadata); err != nil {
430 return err
431 }
432 if errs := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, flwResponse, grpResponse); errs != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000433 logger.Warnw(ctx, "no-adapter-response", log.Fields{"device-id": agent.deviceID, "result": errs})
khenaidoo442e7c72020-03-10 16:13:48 -0400434 return status.Errorf(codes.Aborted, "flow-failure-device-%s", agent.deviceID)
khenaidoo0458db62019-06-20 08:50:36 -0400435 }
khenaidoo0458db62019-06-20 08:50:36 -0400436 return nil
437}
438
A R Karthick5c28f552019-12-11 22:47:44 -0800439//deleteFlowsAndGroups removes the "flowsToDel" and "groupsToDel" from the existing flows/groups and sends the update to the
440//adapters
Kent Hagerman2b216042020-04-03 18:28:56 -0400441func (agent *Agent) deleteFlowsAndGroups(ctx context.Context, flowsToDel []*ofp.OfpFlowStats, groupsToDel []*ofp.OfpGroupEntry, flowMetadata *voltha.FlowMetadata) error {
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700442 var flwResponse, grpResponse coreutils.Response
443 var err error
444 if flwResponse, err = agent.deleteFlowsFromAdapter(ctx, flowsToDel, flowMetadata); err != nil {
A R Karthick5c28f552019-12-11 22:47:44 -0800445 return err
446 }
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700447 if grpResponse, err = agent.deleteGroupsFromAdapter(ctx, groupsToDel, flowMetadata); err != nil {
448 return err
449 }
450
451 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, flwResponse, grpResponse); res != nil {
khenaidoo0458db62019-06-20 08:50:36 -0400452 return status.Errorf(codes.Aborted, "errors-%s", res)
453 }
454 return nil
khenaidoo0458db62019-06-20 08:50:36 -0400455}
456
A R Karthick5c28f552019-12-11 22:47:44 -0800457//updateFlowsAndGroups replaces the existing flows and groups with "updatedFlows" and "updatedGroups" respectively. It
458//also sends the updates to the adapters
Kent Hagerman2b216042020-04-03 18:28:56 -0400459func (agent *Agent) updateFlowsAndGroups(ctx context.Context, updatedFlows []*ofp.OfpFlowStats, updatedGroups []*ofp.OfpGroupEntry, flowMetadata *voltha.FlowMetadata) error {
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700460 var flwResponse, grpResponse coreutils.Response
461 var err error
462 if flwResponse, err = agent.updateFlowsToAdapter(ctx, updatedFlows, flowMetadata); err != nil {
A R Karthick5c28f552019-12-11 22:47:44 -0800463 return err
464 }
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700465 if grpResponse, err = agent.updateGroupsToAdapter(ctx, updatedGroups, flowMetadata); err != nil {
466 return err
467 }
468
469 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, flwResponse, grpResponse); res != nil {
khenaidoo0458db62019-06-20 08:50:36 -0400470 return status.Errorf(codes.Aborted, "errors-%s", res)
471 }
472 return nil
khenaidoo19d7b632018-10-30 10:49:50 -0400473}
474
khenaidoo4d4802d2018-10-04 21:59:49 -0400475//disableDevice disable a device
Kent Hagerman2b216042020-04-03 18:28:56 -0400476func (agent *Agent) disableDevice(ctx context.Context) error {
khenaidoo442e7c72020-03-10 16:13:48 -0400477 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
478 return err
479 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530480 logger.Debugw(ctx, "disable-device", log.Fields{"device-id": agent.deviceID})
khenaidoo6e55d9e2019-12-12 18:26:26 -0500481
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400482 cloned := agent.cloneDeviceWithoutLock()
khenaidoo6e55d9e2019-12-12 18:26:26 -0500483
484 if cloned.AdminState == voltha.AdminState_DISABLED {
divyadesaicb8b59d2020-08-18 09:55:47 +0000485 logger.Debugw(ctx, "device-already-disabled", log.Fields{"device-id": agent.deviceID})
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400486 agent.requestQueue.RequestComplete()
npujar1d86a522019-11-14 17:11:16 +0530487 return nil
488 }
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530489 if cloned.AdminState == voltha.AdminState_PREPROVISIONED {
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400490 agent.requestQueue.RequestComplete()
khenaidoo6e55d9e2019-12-12 18:26:26 -0500491 return status.Errorf(codes.FailedPrecondition, "deviceId:%s, invalid-admin-state:%s", agent.deviceID, cloned.AdminState)
npujar1d86a522019-11-14 17:11:16 +0530492 }
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530493 if agent.isDeletionInProgress() {
494 agent.requestQueue.RequestComplete()
495 return status.Errorf(codes.FailedPrecondition, "deviceId:%s, Device deletion is in progress.", agent.deviceID)
496 }
npujar1d86a522019-11-14 17:11:16 +0530497 // Update the Admin State and operational state before sending the request out
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400498 cloned.AdminState = voltha.AdminState_DISABLED
499 cloned.OperStatus = voltha.OperStatus_UNKNOWN
500 if err := agent.updateDeviceAndReleaseLock(ctx, cloned); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530501 return err
502 }
khenaidoo442e7c72020-03-10 16:13:48 -0400503
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000504 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
Himani Chawlab4c25912020-11-12 17:16:38 +0530505 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
506
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400507 ch, err := agent.adapterProxy.DisableDevice(subCtx, cloned)
khenaidoo442e7c72020-03-10 16:13:48 -0400508 if err != nil {
509 cancel()
npujar1d86a522019-11-14 17:11:16 +0530510 return err
khenaidoo0a822f92019-05-08 15:15:57 -0400511 }
khenaidoo442e7c72020-03-10 16:13:48 -0400512 go agent.waitForAdapterResponse(subCtx, cancel, "disableDevice", ch, agent.onSuccess, agent.onFailure)
khenaidoo0a822f92019-05-08 15:15:57 -0400513
khenaidoo92e62c52018-10-03 14:02:54 -0400514 return nil
515}
516
Kent Hagerman2b216042020-04-03 18:28:56 -0400517func (agent *Agent) rebootDevice(ctx context.Context) error {
khenaidoo442e7c72020-03-10 16:13:48 -0400518 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530519 return err
khenaidoo4d4802d2018-10-04 21:59:49 -0400520 }
khenaidoo442e7c72020-03-10 16:13:48 -0400521 defer agent.requestQueue.RequestComplete()
Himani Chawlab4c25912020-11-12 17:16:38 +0530522 logger.Debugw(ctx, "reboot-device", log.Fields{"device-id": agent.deviceID})
khenaidoo442e7c72020-03-10 16:13:48 -0400523
Kent Hagermancba2f302020-07-28 13:37:36 -0400524 device := agent.getDeviceReadOnlyWithoutLock()
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530525 if agent.isDeletionInProgress() {
526 return status.Errorf(codes.FailedPrecondition, "deviceId:%s, Device deletion is in progress.", agent.deviceID)
527 }
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000528 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
Himani Chawlab4c25912020-11-12 17:16:38 +0530529 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
530
Kent Hagerman2b216042020-04-03 18:28:56 -0400531 ch, err := agent.adapterProxy.RebootDevice(subCtx, device)
khenaidoo442e7c72020-03-10 16:13:48 -0400532 if err != nil {
533 cancel()
534 return err
535 }
536 go agent.waitForAdapterResponse(subCtx, cancel, "rebootDevice", ch, agent.onSuccess, agent.onFailure)
khenaidoo4d4802d2018-10-04 21:59:49 -0400537 return nil
538}
539
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530540func (agent *Agent) deleteDeviceForce(ctx context.Context) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530541 logger.Debugw(ctx, "delete-device-force", log.Fields{"device-id": agent.deviceID})
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530542 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
543 return err
544 }
545 // Get the device Transient state, return err if it is DELETING
546 previousDeviceTransientState := agent.getTransientState()
547
548 if agent.isStateDeleting(previousDeviceTransientState) {
549 agent.requestQueue.RequestComplete()
550 return status.Errorf(codes.FailedPrecondition, "deviceId:%s, Device Deletion is in progress",
551 agent.deviceID)
552 }
553 device := agent.cloneDeviceWithoutLock()
Himani Chawlab4c25912020-11-12 17:16:38 +0530554 if err := agent.updateDeviceWithTransientStateAndReleaseLock(ctx, device,
555 voltha.DeviceTransientState_FORCE_DELETING, previousDeviceTransientState); err != nil {
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530556 return err
557 }
558 previousAdminState := device.AdminState
559 if previousAdminState != ic.AdminState_PREPROVISIONED {
560 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
Himani Chawlab4c25912020-11-12 17:16:38 +0530561 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
562
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530563 ch, err := agent.adapterProxy.DeleteDevice(subCtx, device)
564 if err != nil {
565 cancel()
566 return err
567 }
568 // Since it is a case of force delete, nothing needs to be done on adapter responses.
Himani Chawlab4c25912020-11-12 17:16:38 +0530569 go agent.waitForAdapterForceDeleteResponse(subCtx, cancel, "deleteDeviceForce", ch, agent.onSuccess,
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530570 agent.onFailure)
571 }
572 return nil
573}
574
Kent Hagerman2b216042020-04-03 18:28:56 -0400575func (agent *Agent) deleteDevice(ctx context.Context) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530576 logger.Debugw(ctx, "delete-device", log.Fields{"device-id": agent.deviceID})
khenaidoo442e7c72020-03-10 16:13:48 -0400577 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
578 return err
579 }
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530580 // Get the device Transient state, return err if it is DELETING
581 previousDeviceTransientState := agent.getTransientState()
khenaidoo6e55d9e2019-12-12 18:26:26 -0500582
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530583 if agent.isStateDeleting(previousDeviceTransientState) {
584 agent.requestQueue.RequestComplete()
585 return status.Errorf(codes.FailedPrecondition, "deviceId:%s, Device Deletion is in progress", agent.deviceID)
586 }
587 device := agent.cloneDeviceWithoutLock()
588 previousAdminState := device.AdminState
589 // Change the device transient state to DELETING_FROM_ADAPTER state till the device is removed from adapters.
590 currentDeviceTransientState := voltha.DeviceTransientState_DELETING_FROM_ADAPTER
khenaidoo442e7c72020-03-10 16:13:48 -0400591
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530592 if previousAdminState == ic.AdminState_PREPROVISIONED {
593 // Change the state to DELETING POST ADAPTER RESPONSE directly as adapters have no info of the device.
594 currentDeviceTransientState = voltha.DeviceTransientState_DELETING_POST_ADAPTER_RESPONSE
595 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530596 if err := agent.updateDeviceWithTransientStateAndReleaseLock(ctx, device,
597 currentDeviceTransientState, previousDeviceTransientState); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530598 return err
599 }
khenaidoo442e7c72020-03-10 16:13:48 -0400600 // If the device was in pre-prov state (only parent device are in that state) then do not send the request to the
601 // adapter
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530602 if previousAdminState != ic.AdminState_PREPROVISIONED {
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000603 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
Himani Chawlab4c25912020-11-12 17:16:38 +0530604 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
605
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530606 ch, err := agent.adapterProxy.DeleteDevice(subCtx, device)
khenaidoo442e7c72020-03-10 16:13:48 -0400607 if err != nil {
608 cancel()
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530609 //updating of transient state is required in error
610 if err := agent.updateTransientState(ctx, voltha.DeviceTransientState_DELETE_FAILED); err != nil {
611 logger.Errorw(ctx, "failed-to-update-transient-state-as-delete-failed", log.Fields{"device-id": agent.deviceID})
612 }
khenaidoo442e7c72020-03-10 16:13:48 -0400613 return err
614 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530615 go agent.waitForAdapterResponse(subCtx, cancel, "deleteDevice", ch, agent.onDeleteSuccess,
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530616 agent.onDeleteFailure)
khenaidoo442e7c72020-03-10 16:13:48 -0400617 }
khenaidoo4d4802d2018-10-04 21:59:49 -0400618 return nil
619}
620
Kent Hagerman2b216042020-04-03 18:28:56 -0400621func (agent *Agent) setParentID(ctx context.Context, device *voltha.Device, parentID string) error {
khenaidoo442e7c72020-03-10 16:13:48 -0400622 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
623 return err
624 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530625 logger.Debugw(ctx, "set-parent-id", log.Fields{"device-id": device.Id, "parent-id": parentID})
khenaidoo6e55d9e2019-12-12 18:26:26 -0500626
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400627 cloned := agent.cloneDeviceWithoutLock()
npujar1d86a522019-11-14 17:11:16 +0530628 cloned.ParentId = parentID
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400629 return agent.updateDeviceAndReleaseLock(ctx, cloned)
khenaidooad06fd72019-10-28 12:26:05 -0400630}
631
khenaidoo442e7c72020-03-10 16:13:48 -0400632// getSwitchCapability retrieves the switch capability of a parent device
Kent Hagerman2b216042020-04-03 18:28:56 -0400633func (agent *Agent) getSwitchCapability(ctx context.Context) (*ic.SwitchCapability, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530634 logger.Debugw(ctx, "get-switch-capability", log.Fields{"device-id": agent.deviceID})
khenaidoo442e7c72020-03-10 16:13:48 -0400635
Kent Hagermancba2f302020-07-28 13:37:36 -0400636 device, err := agent.getDeviceReadOnly(ctx)
khenaidoo442e7c72020-03-10 16:13:48 -0400637 if err != nil {
khenaidoob9203542018-09-17 22:56:37 -0400638 return nil, err
khenaidoob9203542018-09-17 22:56:37 -0400639 }
Kent Hagermancba2f302020-07-28 13:37:36 -0400640 ch, err := agent.adapterProxy.GetOfpDeviceInfo(ctx, device)
khenaidoo442e7c72020-03-10 16:13:48 -0400641 if err != nil {
642 return nil, err
643 }
644
645 // Wait for adapter response
646 rpcResponse, ok := <-ch
647 if !ok {
648 return nil, status.Errorf(codes.Aborted, "channel-closed")
649 }
650 if rpcResponse.Err != nil {
651 return nil, rpcResponse.Err
652 }
653 // Successful response
654 switchCap := &ic.SwitchCapability{}
655 if err := ptypes.UnmarshalAny(rpcResponse.Reply, switchCap); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530656 return nil, err
657 }
658 return switchCap, nil
khenaidoob9203542018-09-17 22:56:37 -0400659}
660
Rohan Agrawal31f21802020-06-12 05:38:46 +0000661func (agent *Agent) onPacketFailure(ctx context.Context, rpc string, response interface{}, args ...interface{}) {
khenaidoo442e7c72020-03-10 16:13:48 -0400662 // packet data is encoded in the args param as the first parameter
663 var packet []byte
664 if len(args) >= 1 {
665 if pkt, ok := args[0].([]byte); ok {
666 packet = pkt
667 }
668 }
669 var errResp error
670 if err, ok := response.(error); ok {
671 errResp = err
672 }
Rohan Agrawal31f21802020-06-12 05:38:46 +0000673 logger.Warnw(ctx, "packet-out-error", log.Fields{
khenaidoo442e7c72020-03-10 16:13:48 -0400674 "device-id": agent.deviceID,
675 "error": errResp,
676 "packet": hex.EncodeToString(packet),
677 })
678}
679
Kent Hagerman2b216042020-04-03 18:28:56 -0400680func (agent *Agent) packetOut(ctx context.Context, outPort uint32, packet *ofp.OfpPacketOut) error {
Scott Baker80678602019-11-14 16:57:36 -0800681 // If deviceType=="" then we must have taken ownership of this device.
682 // Fixes VOL-2226 where a core would take ownership and have stale data
683 if agent.deviceType == "" {
npujar467fe752020-01-16 20:17:45 +0530684 agent.reconcileWithKVStore(ctx)
Scott Baker80678602019-11-14 16:57:36 -0800685 }
khenaidoofdbad6e2018-11-06 22:26:38 -0500686 // Send packet to adapter
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000687 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
Himani Chawlab4c25912020-11-12 17:16:38 +0530688 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
689
Kent Hagerman2b216042020-04-03 18:28:56 -0400690 ch, err := agent.adapterProxy.PacketOut(subCtx, agent.deviceType, agent.deviceID, outPort, packet)
khenaidoo442e7c72020-03-10 16:13:48 -0400691 if err != nil {
692 cancel()
693 return nil
khenaidoofdbad6e2018-11-06 22:26:38 -0500694 }
khenaidoo442e7c72020-03-10 16:13:48 -0400695 go agent.waitForAdapterResponse(subCtx, cancel, "packetOut", ch, agent.onSuccess, agent.onPacketFailure, packet.Data)
khenaidoofdbad6e2018-11-06 22:26:38 -0500696 return nil
697}
698
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400699func (agent *Agent) updateDeviceUsingAdapterData(ctx context.Context, device *voltha.Device) error {
700 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
701 return err
702 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530703 logger.Debugw(ctx, "update-device-using-adapter-data", log.Fields{"device-id": device.Id})
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400704
705 cloned := agent.cloneDeviceWithoutLock()
Mahir Gunyel8e2707d2019-07-25 00:36:21 -0700706 cloned.Root = device.Root
707 cloned.Vendor = device.Vendor
708 cloned.Model = device.Model
709 cloned.SerialNumber = device.SerialNumber
710 cloned.MacAddress = device.MacAddress
711 cloned.Vlan = device.Vlan
712 cloned.Reason = device.Reason
Andrea Campanella025667e2021-01-14 11:50:07 +0100713 cloned.ImageDownloads = device.ImageDownloads
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400714 return agent.updateDeviceAndReleaseLock(ctx, cloned)
khenaidoo43c82122018-11-22 18:38:28 -0500715}
716
Kent Hagerman2b216042020-04-03 18:28:56 -0400717func (agent *Agent) updateDeviceStatus(ctx context.Context, operStatus voltha.OperStatus_Types, connStatus voltha.ConnectStatus_Types) error {
khenaidoo442e7c72020-03-10 16:13:48 -0400718 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
719 return err
720 }
khenaidoo6e55d9e2019-12-12 18:26:26 -0500721
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400722 cloned := agent.cloneDeviceWithoutLock()
npujar1d86a522019-11-14 17:11:16 +0530723 // 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 -0400724 if s, ok := voltha.ConnectStatus_Types_name[int32(connStatus)]; ok {
Himani Chawlab4c25912020-11-12 17:16:38 +0530725 logger.Debugw(ctx, "update-device-status-conn", log.Fields{"ok": ok, "val": s})
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400726 cloned.ConnectStatus = connStatus
npujar1d86a522019-11-14 17:11:16 +0530727 }
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400728 if s, ok := voltha.OperStatus_Types_name[int32(operStatus)]; ok {
Himani Chawlab4c25912020-11-12 17:16:38 +0530729 logger.Debugw(ctx, "update-device-status-conn", log.Fields{"ok": ok, "val": s})
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400730 cloned.OperStatus = operStatus
npujar1d86a522019-11-14 17:11:16 +0530731 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530732 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 +0530733 // Store the device
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400734 return agent.updateDeviceAndReleaseLock(ctx, cloned)
khenaidoo92e62c52018-10-03 14:02:54 -0400735}
736
khenaidoob9203542018-09-17 22:56:37 -0400737// TODO: A generic device update by attribute
Kent Hagerman2b216042020-04-03 18:28:56 -0400738func (agent *Agent) updateDeviceAttribute(ctx context.Context, name string, value interface{}) {
khenaidoob9203542018-09-17 22:56:37 -0400739 if value == nil {
740 return
741 }
khenaidoo6e55d9e2019-12-12 18:26:26 -0500742
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400743 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
744 logger.Warnw(ctx, "request-aborted", log.Fields{"device-id": agent.deviceID, "name": name, "error": err})
745 return
746 }
747
748 cloned := agent.cloneDeviceWithoutLock()
khenaidoob9203542018-09-17 22:56:37 -0400749 updated := false
khenaidoo6e55d9e2019-12-12 18:26:26 -0500750 s := reflect.ValueOf(cloned).Elem()
khenaidoob9203542018-09-17 22:56:37 -0400751 if s.Kind() == reflect.Struct {
752 // exported field
753 f := s.FieldByName(name)
754 if f.IsValid() && f.CanSet() {
755 switch f.Kind() {
756 case reflect.String:
757 f.SetString(value.(string))
758 updated = true
759 case reflect.Uint32:
760 f.SetUint(uint64(value.(uint32)))
761 updated = true
762 case reflect.Bool:
763 f.SetBool(value.(bool))
764 updated = true
765 }
766 }
767 }
divyadesaicb8b59d2020-08-18 09:55:47 +0000768 logger.Debugw(ctx, "update-field-status", log.Fields{"device-id": cloned.Id, "name": name, "updated": updated})
khenaidoob9203542018-09-17 22:56:37 -0400769 // Save the data
khenaidoo6e55d9e2019-12-12 18:26:26 -0500770
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400771 if err := agent.updateDeviceAndReleaseLock(ctx, cloned); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000772 logger.Warnw(ctx, "attribute-update-failed", log.Fields{"attribute": name, "value": value})
khenaidoob9203542018-09-17 22:56:37 -0400773 }
khenaidoob9203542018-09-17 22:56:37 -0400774}
serkant.uluderya334479d2019-04-10 08:26:15 -0700775
Kent Hagerman45a13e42020-04-13 12:23:50 -0400776func (agent *Agent) simulateAlarm(ctx context.Context, simulateReq *voltha.SimulateAlarmRequest) error {
khenaidoo442e7c72020-03-10 16:13:48 -0400777 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
778 return err
779 }
780 defer agent.requestQueue.RequestComplete()
Himani Chawlab4c25912020-11-12 17:16:38 +0530781 logger.Debugw(ctx, "simulate-alarm", log.Fields{"device-id": agent.deviceID})
khenaidoo6e55d9e2019-12-12 18:26:26 -0500782
Kent Hagermancba2f302020-07-28 13:37:36 -0400783 device := agent.getDeviceReadOnlyWithoutLock()
khenaidoo6e55d9e2019-12-12 18:26:26 -0500784
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000785 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
Himani Chawlab4c25912020-11-12 17:16:38 +0530786 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
787
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400788 ch, err := agent.adapterProxy.SimulateAlarm(subCtx, device, simulateReq)
khenaidoo442e7c72020-03-10 16:13:48 -0400789 if err != nil {
790 cancel()
npujar1d86a522019-11-14 17:11:16 +0530791 return err
serkant.uluderya334479d2019-04-10 08:26:15 -0700792 }
khenaidoo442e7c72020-03-10 16:13:48 -0400793 go agent.waitForAdapterResponse(subCtx, cancel, "simulateAlarm", ch, agent.onSuccess, agent.onFailure)
serkant.uluderya334479d2019-04-10 08:26:15 -0700794 return nil
795}
Mahir Gunyelb5851672019-07-24 10:46:26 +0300796
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400797// This function updates the device in the DB, releases the device lock, and runs any state transitions.
798// The calling function MUST hold the device lock. The caller MUST NOT modify the device after this is called.
799func (agent *Agent) updateDeviceAndReleaseLock(ctx context.Context, device *voltha.Device) error {
800 // fail early if this agent is no longer valid
Kent Hagerman4f355f52020-03-30 16:01:33 -0400801 if agent.stopped {
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400802 agent.requestQueue.RequestComplete()
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530803 return errors.New("device-agent-stopped")
Thomas Lee Se5a44012019-11-07 20:32:24 +0530804 }
Kent Hagerman4f355f52020-03-30 16:01:33 -0400805
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400806 // update in db
Kent Hagermanf5a67352020-04-30 15:15:26 -0400807 if err := agent.dbProxy.Set(ctx, agent.deviceID, device); err != nil {
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400808 agent.requestQueue.RequestComplete()
Kent Hagerman4f355f52020-03-30 16:01:33 -0400809 return status.Errorf(codes.Internal, "failed-update-device:%s: %s", agent.deviceID, err)
Mahir Gunyelb5851672019-07-24 10:46:26 +0300810 }
divyadesaicb8b59d2020-08-18 09:55:47 +0000811 logger.Debugw(ctx, "updated-device-in-store", log.Fields{"device-id: ": agent.deviceID})
Mahir Gunyelb5851672019-07-24 10:46:26 +0300812
Kent Hagerman6031aad2020-07-29 16:36:33 -0400813 prevDevice := agent.device
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400814 // update the device
khenaidoo0db4c812020-05-27 15:27:30 -0400815 agent.device = device
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400816
817 // release lock before processing transition
818 agent.requestQueue.RequestComplete()
Himani Chawlab4c25912020-11-12 17:16:38 +0530819 subCtx := coreutils.WithSpanAndRPCMetadataFromContext(ctx)
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400820
Himani Chawlab4c25912020-11-12 17:16:38 +0530821 if err := agent.deviceMgr.stateTransitions.ProcessTransition(subCtx,
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530822 device, prevDevice, voltha.DeviceTransientState_NONE, voltha.DeviceTransientState_NONE); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530823 logger.Errorw(ctx, "failed-process-transition", log.Fields{"device-id": device.Id, "previous-admin-state": prevDevice.AdminState, "current-admin-state": device.AdminState})
824 // Sending RPC EVENT here
825 rpce := agent.deviceMgr.NewRPCEvent(ctx, agent.deviceID, err.Error(), nil)
826 go agent.deviceMgr.SendRPCEvent(ctx, "RPC_ERROR_RAISE_EVENT", rpce, voltha.EventCategory_COMMUNICATION,
827 nil, time.Now().UnixNano())
828
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400829 }
Mahir Gunyelb5851672019-07-24 10:46:26 +0300830 return nil
831}
Mahir Gunyelfdee9212019-10-16 16:52:21 -0700832
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530833// This function updates the device transient in the DB through loader, releases the device lock, and runs any state transitions.
834// The calling function MUST hold the device lock. The caller MUST NOT modify the device after this is called.
835func (agent *Agent) updateDeviceWithTransientStateAndReleaseLock(ctx context.Context, device *voltha.Device,
836 transientState, prevTransientState voltha.DeviceTransientState_Types) error {
837 // fail early if this agent is no longer valid
838 if agent.stopped {
839 agent.requestQueue.RequestComplete()
840 return errors.New("device-agent-stopped")
841 }
842 //update device TransientState
843 if err := agent.updateTransientState(ctx, transientState); err != nil {
844 agent.requestQueue.RequestComplete()
845 return err
846 }
847 // update in db
848 if err := agent.dbProxy.Set(ctx, agent.deviceID, device); err != nil {
849 //Reverting TransientState update
850 err := agent.updateTransientState(ctx, prevTransientState)
851 logger.Errorw(ctx, "failed-to-revert-transient-state-update-on-error", log.Fields{"device-id": device.Id,
Himani Chawlab4c25912020-11-12 17:16:38 +0530852 "previous-transient-state": prevTransientState, "current-transient-state": transientState})
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530853 agent.requestQueue.RequestComplete()
854 return status.Errorf(codes.Internal, "failed-update-device:%s: %s", agent.deviceID, err)
855 }
856
857 logger.Debugw(ctx, "updated-device-in-store", log.Fields{"device-id: ": agent.deviceID})
858
859 prevDevice := agent.device
860 // update the device
861 agent.device = device
862
863 // release lock before processing transition
864 agent.requestQueue.RequestComplete()
Himani Chawlab4c25912020-11-12 17:16:38 +0530865 subCtx := coreutils.WithSpanAndRPCMetadataFromContext(ctx)
866 if err := agent.deviceMgr.stateTransitions.ProcessTransition(subCtx,
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530867 device, prevDevice, transientState, prevTransientState); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530868 logger.Errorw(ctx, "failed-process-transition", log.Fields{"device-id": device.Id, "previous-admin-state": prevDevice.AdminState, "current-admin-state": device.AdminState})
869 // Sending RPC EVENT here
870 rpce := agent.deviceMgr.NewRPCEvent(ctx, agent.deviceID, err.Error(), nil)
871 go agent.deviceMgr.SendRPCEvent(ctx, "RPC_ERROR_RAISE_EVENT", rpce, voltha.EventCategory_COMMUNICATION,
872 nil, time.Now().UnixNano())
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530873 }
874 return nil
875}
Kent Hagerman2b216042020-04-03 18:28:56 -0400876func (agent *Agent) updateDeviceReason(ctx context.Context, reason string) error {
khenaidoo442e7c72020-03-10 16:13:48 -0400877 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
878 return err
879 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530880 logger.Debugw(ctx, "update-device-reason", log.Fields{"device-id": agent.deviceID, "reason": reason})
khenaidoo6e55d9e2019-12-12 18:26:26 -0500881
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400882 cloned := agent.cloneDeviceWithoutLock()
npujar1d86a522019-11-14 17:11:16 +0530883 cloned.Reason = reason
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400884 return agent.updateDeviceAndReleaseLock(ctx, cloned)
Mahir Gunyelfdee9212019-10-16 16:52:21 -0700885}
kesavandbc2d1622020-01-21 00:42:01 -0500886
Kent Hagerman2b216042020-04-03 18:28:56 -0400887func (agent *Agent) ChildDeviceLost(ctx context.Context, device *voltha.Device) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530888 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 -0500889
Kent Hagerman2a07b862020-06-19 15:23:07 -0400890 // Remove the associated peer ports on the parent device
891 for portID := range agent.portLoader.ListIDs() {
892 if portHandle, have := agent.portLoader.Lock(portID); have {
893 oldPort := portHandle.GetReadOnly()
894 updatedPeers := make([]*voltha.Port_PeerPort, 0)
895 for _, peerPort := range oldPort.Peers {
896 if peerPort.DeviceId != device.Id {
897 updatedPeers = append(updatedPeers, peerPort)
898 }
khenaidoo442e7c72020-03-10 16:13:48 -0400899 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400900 newPort := *oldPort
901 newPort.Peers = updatedPeers
902 if err := portHandle.Update(ctx, &newPort); err != nil {
903 portHandle.Unlock()
904 return nil
905 }
906 portHandle.Unlock()
khenaidoo442e7c72020-03-10 16:13:48 -0400907 }
Chaitrashree G S543df3e2020-02-24 22:36:54 -0500908 }
909
khenaidoo442e7c72020-03-10 16:13:48 -0400910 //send request to adapter
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000911 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
Himani Chawlab4c25912020-11-12 17:16:38 +0530912 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
913
Girish Gowdra6f9b10e2021-03-11 14:36:39 -0800914 ch, err := agent.adapterProxy.ChildDeviceLost(ctx, agent.deviceType, device)
khenaidoo442e7c72020-03-10 16:13:48 -0400915 if err != nil {
916 cancel()
917 return err
Chaitrashree G S543df3e2020-02-24 22:36:54 -0500918 }
khenaidoo442e7c72020-03-10 16:13:48 -0400919 go agent.waitForAdapterResponse(subCtx, cancel, "childDeviceLost", ch, agent.onSuccess, agent.onFailure)
Chaitrashree G S543df3e2020-02-24 22:36:54 -0500920 return nil
Chaitrashree G S543df3e2020-02-24 22:36:54 -0500921}
onkarkundargi87285252020-01-27 11:34:52 +0530922
Kent Hagerman2b216042020-04-03 18:28:56 -0400923func (agent *Agent) startOmciTest(ctx context.Context, omcitestrequest *voltha.OmciTestRequest) (*voltha.TestResponse, error) {
onkarkundargi87285252020-01-27 11:34:52 +0530924 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
925 return nil, err
926 }
927
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400928 cloned := agent.cloneDeviceWithoutLock()
Matteo Scandolod525ae32020-04-02 17:27:29 -0700929
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400930 if cloned.Adapter == "" {
931 adapterName, err := agent.adapterMgr.GetAdapterType(cloned.Type)
Matteo Scandolod525ae32020-04-02 17:27:29 -0700932 if err != nil {
933 agent.requestQueue.RequestComplete()
934 return nil, err
935 }
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400936 cloned.Adapter = adapterName
onkarkundargi87285252020-01-27 11:34:52 +0530937 }
938
939 // Send request to the adapter
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400940 ch, err := agent.adapterProxy.StartOmciTest(ctx, cloned, omcitestrequest)
onkarkundargi87285252020-01-27 11:34:52 +0530941 agent.requestQueue.RequestComplete()
942 if err != nil {
943 return nil, err
944 }
945
946 // Wait for the adapter response
947 rpcResponse, ok := <-ch
948 if !ok {
949 return nil, status.Errorf(codes.Aborted, "channel-closed-device-id-%s", agent.deviceID)
950 }
951 if rpcResponse.Err != nil {
952 return nil, rpcResponse.Err
953 }
954
955 // Unmarshal and return the response
956 testResp := &voltha.TestResponse{}
957 if err := ptypes.UnmarshalAny(rpcResponse.Reply, testResp); err != nil {
958 return nil, status.Errorf(codes.InvalidArgument, "%s", err.Error())
959 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530960 logger.Debugw(ctx, "omci_test_request-success-device-agent", log.Fields{"test-resp": testResp})
onkarkundargi87285252020-01-27 11:34:52 +0530961 return testResp, nil
962}
Dinesh Belwalkarc1129f12020-02-27 10:41:33 -0800963
964func (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 +0530965 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 -0800966 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
967 return nil, err
968 }
969
970 //send request to adapter
971 ch, err := agent.adapterProxy.GetExtValue(ctx, pdevice, cdevice, valueparam.Id, valueparam.Value)
972 agent.requestQueue.RequestComplete()
973 if err != nil {
974 return nil, err
975 }
976
977 // Wait for the adapter response
978 rpcResponse, ok := <-ch
979 if !ok {
980 return nil, status.Errorf(codes.Aborted, "channel-closed-device-id-%s", agent.deviceID)
981 }
982 if rpcResponse.Err != nil {
983 return nil, rpcResponse.Err
984 }
985
986 // Unmarshal and return the response
987 Resp := &voltha.ReturnValues{}
988 if err := ptypes.UnmarshalAny(rpcResponse.Reply, Resp); err != nil {
989 return nil, status.Errorf(codes.InvalidArgument, "%s", err.Error())
990 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530991 logger.Debugw(ctx, "get-ext-value-success-device-agent", log.Fields{"Resp": Resp})
Dinesh Belwalkarc1129f12020-02-27 10:41:33 -0800992 return Resp, nil
993}
dpaul62686312020-06-23 14:17:36 +0530994
995func (agent *Agent) setExtValue(ctx context.Context, device *voltha.Device, value *voltha.ValueSet) (*empty.Empty, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530996 logger.Debugw(ctx, "set-ext-value", log.Fields{"device-id": value.Id})
dpaul62686312020-06-23 14:17:36 +0530997 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
998 return nil, err
999 }
1000
1001 //send request to adapter
1002 ch, err := agent.adapterProxy.SetExtValue(ctx, device, value)
1003 agent.requestQueue.RequestComplete()
1004 if err != nil {
1005 return nil, err
1006 }
1007
1008 // Wait for the adapter response
1009 rpcResponse, ok := <-ch
1010 if !ok {
1011 return nil, status.Errorf(codes.Aborted, "channel-closed-device-id-%s", agent.deviceID)
1012 }
1013 if rpcResponse.Err != nil {
1014 return nil, rpcResponse.Err
1015 }
1016
1017 // Unmarshal and return the response
Himani Chawlab4c25912020-11-12 17:16:38 +05301018 logger.Debug(ctx, "set-ext-value-success-device-agent")
dpaul62686312020-06-23 14:17:36 +05301019 return &empty.Empty{}, nil
1020}
Salman Siddiqui1cf95042020-11-19 00:42:56 +05301021
1022func (agent *Agent) getSingleValue(ctx context.Context, request *extension.SingleGetValueRequest) (*extension.SingleGetValueResponse, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301023 logger.Debugw(ctx, "get-single-value", log.Fields{"device-id": request.TargetId})
Salman Siddiqui1cf95042020-11-19 00:42:56 +05301024
1025 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1026 return nil, err
1027 }
1028
1029 cloned := agent.cloneDeviceWithoutLock()
1030
1031 //send request to adapter
1032 ch, err := agent.adapterProxy.GetSingleValue(ctx, cloned.Adapter, request)
1033 agent.requestQueue.RequestComplete()
1034 if err != nil {
1035 return nil, err
1036 }
1037
1038 // Wait for the adapter response
1039 rpcResponse, ok := <-ch
1040 if !ok {
1041 return nil, status.Errorf(codes.Aborted, "channel-closed-device-id-%s", agent.deviceID)
1042 }
1043
1044 if rpcResponse.Err != nil {
1045 return nil, rpcResponse.Err
1046 }
1047
1048 resp := &extension.SingleGetValueResponse{}
1049 if err := ptypes.UnmarshalAny(rpcResponse.Reply, resp); err != nil {
1050 return nil, status.Errorf(codes.InvalidArgument, "%s", err.Error())
1051 }
1052
1053 return resp, nil
1054}
1055
1056func (agent *Agent) setSingleValue(ctx context.Context, request *extension.SingleSetValueRequest) (*extension.SingleSetValueResponse, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301057 logger.Debugw(ctx, "set-single-value", log.Fields{"device-id": request.TargetId})
Salman Siddiqui1cf95042020-11-19 00:42:56 +05301058
1059 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1060 return nil, err
1061 }
1062
1063 cloned := agent.cloneDeviceWithoutLock()
1064
1065 //send request to adapter
1066 ch, err := agent.adapterProxy.SetSingleValue(ctx, cloned.Adapter, request)
1067 agent.requestQueue.RequestComplete()
1068 if err != nil {
1069 return nil, err
1070 }
1071
1072 // Wait for the adapter response
1073 rpcResponse, ok := <-ch
1074 if !ok {
1075 return nil, status.Errorf(codes.Aborted, "channel-closed-cloned-id-%s", agent.deviceID)
1076 }
1077
1078 if rpcResponse.Err != nil {
1079 return nil, rpcResponse.Err
1080 }
1081
1082 resp := &extension.SingleSetValueResponse{}
1083 if err := ptypes.UnmarshalAny(rpcResponse.Reply, resp); err != nil {
1084 return nil, status.Errorf(codes.InvalidArgument, "%s", err.Error())
1085 }
1086
1087 return resp, nil
1088}