blob: 2b18296abfa9efee4d618dccec7bee53e042fef3 [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
khenaidoo442e7c72020-03-10 16:13:48 -040028 "github.com/golang/protobuf/ptypes"
Kent Hagerman2b216042020-04-03 18:28:56 -040029 "github.com/opencord/voltha-go/rw_core/core/adapter"
Mahir Gunyel03de0d32020-06-03 01:36:59 -070030 "github.com/opencord/voltha-go/rw_core/core/device/flow"
31 "github.com/opencord/voltha-go/rw_core/core/device/group"
Kent Hagerman2b216042020-04-03 18:28:56 -040032 "github.com/opencord/voltha-go/rw_core/core/device/remote"
khenaidoo442e7c72020-03-10 16:13:48 -040033 "github.com/opencord/voltha-lib-go/v3/pkg/kafka"
Chaitrashree G Sa773e992019-09-09 21:04:15 -040034
khenaidoob9203542018-09-17 22:56:37 -040035 "github.com/gogo/protobuf/proto"
sbarbari17d7e222019-11-05 10:02:29 -050036 "github.com/opencord/voltha-go/db/model"
Scott Bakerb671a862019-10-24 10:53:40 -070037 coreutils "github.com/opencord/voltha-go/rw_core/utils"
serkant.uluderya2ae470f2020-01-21 11:13:09 -080038 "github.com/opencord/voltha-lib-go/v3/pkg/log"
39 ic "github.com/opencord/voltha-protos/v3/go/inter_container"
40 ofp "github.com/opencord/voltha-protos/v3/go/openflow_13"
41 "github.com/opencord/voltha-protos/v3/go/voltha"
khenaidoob9203542018-09-17 22:56:37 -040042 "google.golang.org/grpc/codes"
43 "google.golang.org/grpc/status"
khenaidoob9203542018-09-17 22:56:37 -040044)
45
Kent Hagerman2b216042020-04-03 18:28:56 -040046// Agent represents device agent attributes
47type Agent struct {
Kent Hagermanf5a67352020-04-30 15:15:26 -040048 deviceID string
49 parentID string
50 deviceType string
51 isRootdevice bool
52 adapterProxy *remote.AdapterProxy
53 adapterMgr *adapter.Manager
54 deviceMgr *Manager
55 dbProxy *model.Proxy
56 exitChannel chan int
57 device *voltha.Device
58 requestQueue *coreutils.RequestQueue
59 defaultTimeout time.Duration
60 startOnce sync.Once
61 stopOnce sync.Once
62 stopped bool
Mahir Gunyel03de0d32020-06-03 01:36:59 -070063
64 flowLoader *flow.Loader
65 groupLoader *group.Loader
khenaidoob9203542018-09-17 22:56:37 -040066}
67
Kent Hagerman2b216042020-04-03 18:28:56 -040068//newAgent creates a new device agent. The device will be initialized when start() is called.
Mahir Gunyel03de0d32020-06-03 01:36:59 -070069func newAgent(ap *remote.AdapterProxy, device *voltha.Device, deviceMgr *Manager, dbProxy *model.Path, deviceProxy *model.Proxy, timeout time.Duration) *Agent {
Kent Hagerman2b216042020-04-03 18:28:56 -040070 var agent Agent
khenaidoob9203542018-09-17 22:56:37 -040071 agent.adapterProxy = ap
Scott Baker80678602019-11-14 16:57:36 -080072 if device.Id == "" {
Kent Hagerman2b216042020-04-03 18:28:56 -040073 agent.deviceID = coreutils.CreateDeviceID()
Scott Baker80678602019-11-14 16:57:36 -080074 } else {
npujar1d86a522019-11-14 17:11:16 +053075 agent.deviceID = device.Id
Stephane Barbarie1ab43272018-12-08 21:42:13 -050076 }
Scott Baker80678602019-11-14 16:57:36 -080077
khenaidoo2c6a0992019-04-29 13:46:56 -040078 agent.isRootdevice = device.Root
npujar1d86a522019-11-14 17:11:16 +053079 agent.parentID = device.ParentId
Scott Baker80678602019-11-14 16:57:36 -080080 agent.deviceType = device.Type
khenaidoob9203542018-09-17 22:56:37 -040081 agent.deviceMgr = deviceMgr
khenaidoo21d51152019-02-01 13:48:37 -050082 agent.adapterMgr = deviceMgr.adapterMgr
khenaidoob9203542018-09-17 22:56:37 -040083 agent.exitChannel = make(chan int, 1)
Kent Hagermanf5a67352020-04-30 15:15:26 -040084 agent.dbProxy = deviceProxy
khenaidoo2c6a0992019-04-29 13:46:56 -040085 agent.defaultTimeout = timeout
khenaidoo6e55d9e2019-12-12 18:26:26 -050086 agent.device = proto.Clone(device).(*voltha.Device)
Kent Hagerman730cbdf2020-03-31 12:22:08 -040087 agent.requestQueue = coreutils.NewRequestQueue()
Mahir Gunyel03de0d32020-06-03 01:36:59 -070088 agent.flowLoader = flow.NewLoader(dbProxy.SubPath("flows").Proxy(device.Id))
89 agent.groupLoader = group.NewLoader(dbProxy.SubPath("groups").Proxy(device.Id))
90
khenaidoob9203542018-09-17 22:56:37 -040091 return &agent
92}
93
khenaidoo442e7c72020-03-10 16:13:48 -040094// start() saves the device to the data model and registers for callbacks on that device if deviceToCreate!=nil.
95// 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 -080096// was started.
Kent Hagerman2b216042020-04-03 18:28:56 -040097func (agent *Agent) start(ctx context.Context, deviceToCreate *voltha.Device) (*voltha.Device, error) {
khenaidoo442e7c72020-03-10 16:13:48 -040098 needToStart := false
99 if agent.startOnce.Do(func() { needToStart = true }); !needToStart {
100 return agent.getDevice(ctx)
101 }
102 var startSucceeded bool
103 defer func() {
104 if !startSucceeded {
105 if err := agent.stop(ctx); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000106 logger.Errorw(ctx, "failed-to-cleanup-after-unsuccessful-start", log.Fields{"device-id": agent.deviceID, "error": err})
khenaidoo442e7c72020-03-10 16:13:48 -0400107 }
108 }
109 }()
Scott Baker80678602019-11-14 16:57:36 -0800110
khenaidoo442e7c72020-03-10 16:13:48 -0400111 var device *voltha.Device
Scott Baker80678602019-11-14 16:57:36 -0800112 if deviceToCreate == nil {
113 // Load the existing device
Kent Hagerman4f355f52020-03-30 16:01:33 -0400114 device := &voltha.Device{}
Kent Hagermanf5a67352020-04-30 15:15:26 -0400115 have, err := agent.dbProxy.Get(ctx, agent.deviceID, device)
Thomas Lee Se5a44012019-11-07 20:32:24 +0530116 if err != nil {
Thomas Lee Se5a44012019-11-07 20:32:24 +0530117 return nil, err
Kent Hagerman4f355f52020-03-30 16:01:33 -0400118 } else if !have {
119 return nil, status.Errorf(codes.NotFound, "device-%s", agent.deviceID)
Thomas Lee Se5a44012019-11-07 20:32:24 +0530120 }
Kent Hagerman4f355f52020-03-30 16:01:33 -0400121
122 agent.deviceType = device.Adapter
123 agent.device = proto.Clone(device).(*voltha.Device)
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700124 // load the flows and groups from KV to cache
125 agent.flowLoader.Load(ctx)
126 agent.groupLoader.Load(ctx)
Kent Hagerman4f355f52020-03-30 16:01:33 -0400127
Rohan Agrawal31f21802020-06-12 05:38:46 +0000128 logger.Infow(ctx, "device-loaded-from-dB", log.Fields{"device-id": agent.deviceID})
khenaidoo297cd252019-02-07 22:10:23 -0500129 } else {
Scott Baker80678602019-11-14 16:57:36 -0800130 // Create a new device
Kent Hagermanf5a67352020-04-30 15:15:26 -0400131 // Assumption is that AdminState, FlowGroups, and Flows are uninitialized since this
132 // is a new device, so populate them here before passing the device to ldProxy.Set.
Kent Hagerman2b216042020-04-03 18:28:56 -0400133 // agent.deviceId will also have been set during newAgent().
Scott Baker80678602019-11-14 16:57:36 -0800134 device = (proto.Clone(deviceToCreate)).(*voltha.Device)
npujar1d86a522019-11-14 17:11:16 +0530135 device.Id = agent.deviceID
Scott Baker80678602019-11-14 16:57:36 -0800136 device.AdminState = voltha.AdminState_PREPROVISIONED
137 device.FlowGroups = &ofp.FlowGroups{Items: nil}
138 device.Flows = &ofp.Flows{Items: nil}
139 if !deviceToCreate.GetRoot() && deviceToCreate.ProxyAddress != nil {
140 // Set the default vlan ID to the one specified by the parent adapter. It can be
141 // overwritten by the child adapter during a device update request
142 device.Vlan = deviceToCreate.ProxyAddress.ChannelId
143 }
144
khenaidoo297cd252019-02-07 22:10:23 -0500145 // Add the initial device to the local model
Kent Hagermanf5a67352020-04-30 15:15:26 -0400146 if err := agent.dbProxy.Set(ctx, agent.deviceID, device); err != nil {
Kent Hagerman4f355f52020-03-30 16:01:33 -0400147 return nil, status.Errorf(codes.Aborted, "failed-adding-device-%s: %s", agent.deviceID, err)
khenaidoo297cd252019-02-07 22:10:23 -0500148 }
khenaidoo442e7c72020-03-10 16:13:48 -0400149 agent.device = device
khenaidoob9203542018-09-17 22:56:37 -0400150 }
khenaidoo442e7c72020-03-10 16:13:48 -0400151 startSucceeded = true
Rohan Agrawal31f21802020-06-12 05:38:46 +0000152 logger.Debugw(ctx, "device-agent-started", log.Fields{"device-id": agent.deviceID})
khenaidoo442e7c72020-03-10 16:13:48 -0400153
154 return agent.getDevice(ctx)
khenaidoob9203542018-09-17 22:56:37 -0400155}
156
khenaidoo4d4802d2018-10-04 21:59:49 -0400157// stop stops the device agent. Not much to do for now
Kent Hagerman2b216042020-04-03 18:28:56 -0400158func (agent *Agent) stop(ctx context.Context) error {
khenaidoo442e7c72020-03-10 16:13:48 -0400159 needToStop := false
160 if agent.stopOnce.Do(func() { needToStop = true }); !needToStop {
161 return nil
162 }
163 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
164 return err
165 }
166 defer agent.requestQueue.RequestComplete()
khenaidoo49085352020-01-13 19:15:43 -0500167
Rohan Agrawal31f21802020-06-12 05:38:46 +0000168 logger.Infow(ctx, "stopping-device-agent", log.Fields{"deviceId": agent.deviceID, "parentId": agent.parentID})
khenaidoo6e55d9e2019-12-12 18:26:26 -0500169
khenaidoo0a822f92019-05-08 15:15:57 -0400170 // Remove the device from the KV store
Kent Hagermanf5a67352020-04-30 15:15:26 -0400171 if err := agent.dbProxy.Remove(ctx, agent.deviceID); err != nil {
khenaidoo442e7c72020-03-10 16:13:48 -0400172 return err
Thomas Lee Se5a44012019-11-07 20:32:24 +0530173 }
khenaidoo442e7c72020-03-10 16:13:48 -0400174
khenaidoo442e7c72020-03-10 16:13:48 -0400175 close(agent.exitChannel)
176
177 agent.stopped = true
178
Rohan Agrawal31f21802020-06-12 05:38:46 +0000179 logger.Infow(ctx, "device-agent-stopped", log.Fields{"device-id": agent.deviceID, "parent-id": agent.parentID})
khenaidoo442e7c72020-03-10 16:13:48 -0400180
181 return nil
khenaidoob9203542018-09-17 22:56:37 -0400182}
183
Scott Baker80678602019-11-14 16:57:36 -0800184// Load the most recent state from the KVStore for the device.
Kent Hagerman2b216042020-04-03 18:28:56 -0400185func (agent *Agent) reconcileWithKVStore(ctx context.Context) {
khenaidoo442e7c72020-03-10 16:13:48 -0400186 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000187 logger.Warnw(ctx, "request-aborted", log.Fields{"device-id": agent.deviceID, "error": err})
khenaidoo442e7c72020-03-10 16:13:48 -0400188 return
189 }
190 defer agent.requestQueue.RequestComplete()
Rohan Agrawal31f21802020-06-12 05:38:46 +0000191 logger.Debug(ctx, "reconciling-device-agent-devicetype")
Scott Baker80678602019-11-14 16:57:36 -0800192 // TODO: context timeout
Kent Hagerman4f355f52020-03-30 16:01:33 -0400193 device := &voltha.Device{}
Kent Hagermanf5a67352020-04-30 15:15:26 -0400194 if have, err := agent.dbProxy.Get(ctx, agent.deviceID, device); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000195 logger.Errorw(ctx, "kv-get-failed", log.Fields{"device-id": agent.deviceID, "error": err})
Thomas Lee Se5a44012019-11-07 20:32:24 +0530196 return
Kent Hagerman4f355f52020-03-30 16:01:33 -0400197 } else if !have {
198 return // not found in kv
Thomas Lee Se5a44012019-11-07 20:32:24 +0530199 }
Kent Hagerman4f355f52020-03-30 16:01:33 -0400200
201 agent.deviceType = device.Adapter
202 agent.device = device
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700203 agent.flowLoader.Load(ctx)
204 agent.groupLoader.Load(ctx)
Rohan Agrawal31f21802020-06-12 05:38:46 +0000205 logger.Debugw(ctx, "reconciled-device-agent-devicetype", log.Fields{"device-id": agent.deviceID, "type": agent.deviceType})
Scott Baker80678602019-11-14 16:57:36 -0800206}
207
khenaidoo442e7c72020-03-10 16:13:48 -0400208// onSuccess is a common callback for scenarios where we receive a nil response following a request to an adapter
209// and the only action required is to publish a successful result on kafka
Rohan Agrawal31f21802020-06-12 05:38:46 +0000210func (agent *Agent) onSuccess(ctx context.Context, rpc string, response interface{}, reqArgs ...interface{}) {
211 logger.Debugw(ctx, "response successful", log.Fields{"rpc": rpc, "device-id": agent.deviceID})
khenaidoo442e7c72020-03-10 16:13:48 -0400212 // TODO: Post success message onto kafka
213}
214
215// onFailure is a common callback for scenarios where we receive an error response following a request to an adapter
216// and the only action required is to publish the failed result on kafka
Rohan Agrawal31f21802020-06-12 05:38:46 +0000217func (agent *Agent) onFailure(ctx context.Context, rpc string, response interface{}, reqArgs ...interface{}) {
khenaidoo442e7c72020-03-10 16:13:48 -0400218 if res, ok := response.(error); ok {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000219 logger.Errorw(ctx, "rpc-failed", log.Fields{"rpc": rpc, "device-id": agent.deviceID, "error": res, "args": reqArgs})
khenaidoo442e7c72020-03-10 16:13:48 -0400220 } else {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000221 logger.Errorw(ctx, "rpc-failed-invalid-error", log.Fields{"rpc": rpc, "device-id": agent.deviceID, "args": reqArgs})
khenaidoo442e7c72020-03-10 16:13:48 -0400222 }
223 // TODO: Post failure message onto kafka
224}
225
Kent Hagerman2b216042020-04-03 18:28:56 -0400226func (agent *Agent) waitForAdapterResponse(ctx context.Context, cancel context.CancelFunc, rpc string, ch chan *kafka.RpcResponse,
khenaidoo442e7c72020-03-10 16:13:48 -0400227 onSuccess coreutils.ResponseCallback, onFailure coreutils.ResponseCallback, reqArgs ...interface{}) {
228 defer cancel()
229 select {
230 case rpcResponse, ok := <-ch:
231 if !ok {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000232 onFailure(ctx, rpc, status.Errorf(codes.Aborted, "channel-closed"), reqArgs)
khenaidoo442e7c72020-03-10 16:13:48 -0400233 } else if rpcResponse.Err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000234 onFailure(ctx, rpc, rpcResponse.Err, reqArgs)
khenaidoo442e7c72020-03-10 16:13:48 -0400235 } else {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000236 onSuccess(ctx, rpc, rpcResponse.Reply, reqArgs)
khenaidoo442e7c72020-03-10 16:13:48 -0400237 }
238 case <-ctx.Done():
Rohan Agrawal31f21802020-06-12 05:38:46 +0000239 onFailure(ctx, rpc, ctx.Err(), reqArgs)
khenaidoo442e7c72020-03-10 16:13:48 -0400240 }
241}
242
khenaidoo6e55d9e2019-12-12 18:26:26 -0500243// getDevice returns the device data from cache
Kent Hagerman2b216042020-04-03 18:28:56 -0400244func (agent *Agent) getDevice(ctx context.Context) (*voltha.Device, error) {
khenaidoo442e7c72020-03-10 16:13:48 -0400245 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
246 return nil, err
247 }
248 defer agent.requestQueue.RequestComplete()
249 return proto.Clone(agent.device).(*voltha.Device), nil
khenaidoo92e62c52018-10-03 14:02:54 -0400250}
251
khenaidoo4d4802d2018-10-04 21:59:49 -0400252// getDeviceWithoutLock is a helper function to be used ONLY by any device agent function AFTER it has acquired the device lock.
Kent Hagerman2b216042020-04-03 18:28:56 -0400253func (agent *Agent) getDeviceWithoutLock() *voltha.Device {
khenaidoo0db4c812020-05-27 15:27:30 -0400254 return agent.device
khenaidoo92e62c52018-10-03 14:02:54 -0400255}
256
khenaidoo3ab34882019-05-02 21:33:30 -0400257// enableDevice activates a preprovisioned or a disable device
Kent Hagerman2b216042020-04-03 18:28:56 -0400258func (agent *Agent) enableDevice(ctx context.Context) error {
khenaidoo442e7c72020-03-10 16:13:48 -0400259 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
260 return err
261 }
262 defer agent.requestQueue.RequestComplete()
263
Rohan Agrawal31f21802020-06-12 05:38:46 +0000264 logger.Debugw(ctx, "enableDevice", log.Fields{"device-id": agent.deviceID})
khenaidoo21d51152019-02-01 13:48:37 -0500265
khenaidoo6e55d9e2019-12-12 18:26:26 -0500266 cloned := agent.getDeviceWithoutLock()
267
npujar1d86a522019-11-14 17:11:16 +0530268 // 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 -0400269 // pre-provisioned with the required adapter not registered. At this stage, since we need to communicate
npujar1d86a522019-11-14 17:11:16 +0530270 // with the adapter then we need to know the adapter that will handle this request
Kent Hagerman2b216042020-04-03 18:28:56 -0400271 adapterName, err := agent.adapterMgr.GetAdapterType(cloned.Type)
npujar1d86a522019-11-14 17:11:16 +0530272 if err != nil {
npujar1d86a522019-11-14 17:11:16 +0530273 return err
274 }
khenaidoo6e55d9e2019-12-12 18:26:26 -0500275 cloned.Adapter = adapterName
npujar1d86a522019-11-14 17:11:16 +0530276
khenaidoo6e55d9e2019-12-12 18:26:26 -0500277 if cloned.AdminState == voltha.AdminState_ENABLED {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000278 logger.Warnw(ctx, "device-already-enabled", log.Fields{"device-id": agent.deviceID})
Matteo Scandolod525ae32020-04-02 17:27:29 -0700279 err = status.Error(codes.FailedPrecondition, fmt.Sprintf("cannot-enable-an-already-enabled-device: %s ", cloned.Id))
280 return err
npujar1d86a522019-11-14 17:11:16 +0530281 }
282
khenaidoo6e55d9e2019-12-12 18:26:26 -0500283 if cloned.AdminState == voltha.AdminState_DELETED {
npujar1d86a522019-11-14 17:11:16 +0530284 // This is a temporary state when a device is deleted before it gets removed from the model.
khenaidoo6e55d9e2019-12-12 18:26:26 -0500285 err = status.Error(codes.FailedPrecondition, fmt.Sprintf("cannot-enable-a-deleted-device: %s ", cloned.Id))
npujar1d86a522019-11-14 17:11:16 +0530286 return err
287 }
288
khenaidoo6e55d9e2019-12-12 18:26:26 -0500289 previousAdminState := cloned.AdminState
npujar1d86a522019-11-14 17:11:16 +0530290
291 // Update the Admin State and set the operational state to activating before sending the request to the
292 // Adapters
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500293 if err := agent.updateDeviceStateInStoreWithoutLock(ctx, cloned, voltha.AdminState_ENABLED, cloned.ConnectStatus, voltha.OperStatus_ACTIVATING); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530294 return err
295 }
296
khenaidoo442e7c72020-03-10 16:13:48 -0400297 // Adopt the device if it was in pre-provision state. In all other cases, try to re-enable it.
khenaidoo6e55d9e2019-12-12 18:26:26 -0500298 device := proto.Clone(cloned).(*voltha.Device)
khenaidoo442e7c72020-03-10 16:13:48 -0400299 var ch chan *kafka.RpcResponse
300 subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
npujar1d86a522019-11-14 17:11:16 +0530301 if previousAdminState == voltha.AdminState_PREPROVISIONED {
Kent Hagerman2b216042020-04-03 18:28:56 -0400302 ch, err = agent.adapterProxy.AdoptDevice(subCtx, device)
khenaidoob9203542018-09-17 22:56:37 -0400303 } else {
Kent Hagerman2b216042020-04-03 18:28:56 -0400304 ch, err = agent.adapterProxy.ReEnableDevice(subCtx, device)
khenaidoob9203542018-09-17 22:56:37 -0400305 }
khenaidoo442e7c72020-03-10 16:13:48 -0400306 if err != nil {
307 cancel()
308 return err
309 }
310 // Wait for response
311 go agent.waitForAdapterResponse(subCtx, cancel, "enableDevice", ch, agent.onSuccess, agent.onFailure)
khenaidoob9203542018-09-17 22:56:37 -0400312 return nil
313}
314
Kent Hagerman2b216042020-04-03 18:28:56 -0400315func (agent *Agent) waitForAdapterFlowResponse(ctx context.Context, cancel context.CancelFunc, ch chan *kafka.RpcResponse, response coreutils.Response) {
khenaidoo442e7c72020-03-10 16:13:48 -0400316 defer cancel()
317 select {
318 case rpcResponse, ok := <-ch:
319 if !ok {
320 response.Error(status.Errorf(codes.Aborted, "channel-closed"))
321 } else if rpcResponse.Err != nil {
322 response.Error(rpcResponse.Err)
323 } else {
324 response.Done()
325 }
326 case <-ctx.Done():
327 response.Error(ctx.Err())
khenaidoo2c6a0992019-04-29 13:46:56 -0400328 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400329}
330
A R Karthick5c28f552019-12-11 22:47:44 -0800331//addFlowsAndGroups adds the "newFlows" and "newGroups" from the existing flows/groups and sends the update to the
332//adapters
Kent Hagerman2b216042020-04-03 18:28:56 -0400333func (agent *Agent) addFlowsAndGroups(ctx context.Context, newFlows []*ofp.OfpFlowStats, newGroups []*ofp.OfpGroupEntry, flowMetadata *voltha.FlowMetadata) error {
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700334 var flwResponse, grpResponse coreutils.Response
335 var err error
336 //if new flow list is empty then the called function returns quickly
337 if flwResponse, err = agent.addFlowsToAdapter(ctx, newFlows, flowMetadata); err != nil {
A R Karthick5c28f552019-12-11 22:47:44 -0800338 return err
339 }
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700340 //if new group list is empty then the called function returns quickly
341 if grpResponse, err = agent.addGroupsToAdapter(ctx, newGroups, flowMetadata); err != nil {
342 return err
343 }
344 if errs := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, flwResponse, grpResponse); errs != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000345 logger.Warnw(ctx, "no-adapter-response", log.Fields{"device-id": agent.deviceID, "result": errs})
khenaidoo442e7c72020-03-10 16:13:48 -0400346 return status.Errorf(codes.Aborted, "flow-failure-device-%s", agent.deviceID)
khenaidoo0458db62019-06-20 08:50:36 -0400347 }
khenaidoo0458db62019-06-20 08:50:36 -0400348 return nil
349}
350
A R Karthick5c28f552019-12-11 22:47:44 -0800351//deleteFlowsAndGroups removes the "flowsToDel" and "groupsToDel" from the existing flows/groups and sends the update to the
352//adapters
Kent Hagerman2b216042020-04-03 18:28:56 -0400353func (agent *Agent) deleteFlowsAndGroups(ctx context.Context, flowsToDel []*ofp.OfpFlowStats, groupsToDel []*ofp.OfpGroupEntry, flowMetadata *voltha.FlowMetadata) error {
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700354 var flwResponse, grpResponse coreutils.Response
355 var err error
356 if flwResponse, err = agent.deleteFlowsFromAdapter(ctx, flowsToDel, flowMetadata); err != nil {
A R Karthick5c28f552019-12-11 22:47:44 -0800357 return err
358 }
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700359 if grpResponse, err = agent.deleteGroupsFromAdapter(ctx, groupsToDel, flowMetadata); err != nil {
360 return err
361 }
362
363 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, flwResponse, grpResponse); res != nil {
khenaidoo0458db62019-06-20 08:50:36 -0400364 return status.Errorf(codes.Aborted, "errors-%s", res)
365 }
366 return nil
khenaidoo0458db62019-06-20 08:50:36 -0400367}
368
A R Karthick5c28f552019-12-11 22:47:44 -0800369//updateFlowsAndGroups replaces the existing flows and groups with "updatedFlows" and "updatedGroups" respectively. It
370//also sends the updates to the adapters
Kent Hagerman2b216042020-04-03 18:28:56 -0400371func (agent *Agent) updateFlowsAndGroups(ctx context.Context, updatedFlows []*ofp.OfpFlowStats, updatedGroups []*ofp.OfpGroupEntry, flowMetadata *voltha.FlowMetadata) error {
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700372 var flwResponse, grpResponse coreutils.Response
373 var err error
374 if flwResponse, err = agent.updateFlowsToAdapter(ctx, updatedFlows, flowMetadata); err != nil {
A R Karthick5c28f552019-12-11 22:47:44 -0800375 return err
376 }
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700377 if grpResponse, err = agent.updateGroupsToAdapter(ctx, updatedGroups, flowMetadata); err != nil {
378 return err
379 }
380
381 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, flwResponse, grpResponse); res != nil {
khenaidoo0458db62019-06-20 08:50:36 -0400382 return status.Errorf(codes.Aborted, "errors-%s", res)
383 }
384 return nil
khenaidoo19d7b632018-10-30 10:49:50 -0400385}
386
khenaidoo4d4802d2018-10-04 21:59:49 -0400387//disableDevice disable a device
Kent Hagerman2b216042020-04-03 18:28:56 -0400388func (agent *Agent) disableDevice(ctx context.Context) error {
khenaidoo442e7c72020-03-10 16:13:48 -0400389 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
390 return err
391 }
392 defer agent.requestQueue.RequestComplete()
Rohan Agrawal31f21802020-06-12 05:38:46 +0000393 logger.Debugw(ctx, "disableDevice", log.Fields{"device-id": agent.deviceID})
khenaidoo6e55d9e2019-12-12 18:26:26 -0500394
395 cloned := agent.getDeviceWithoutLock()
396
397 if cloned.AdminState == voltha.AdminState_DISABLED {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000398 logger.Debugw(ctx, "device-already-disabled", log.Fields{"id": agent.deviceID})
npujar1d86a522019-11-14 17:11:16 +0530399 return nil
400 }
khenaidoo6e55d9e2019-12-12 18:26:26 -0500401 if cloned.AdminState == voltha.AdminState_PREPROVISIONED ||
402 cloned.AdminState == voltha.AdminState_DELETED {
khenaidoo6e55d9e2019-12-12 18:26:26 -0500403 return status.Errorf(codes.FailedPrecondition, "deviceId:%s, invalid-admin-state:%s", agent.deviceID, cloned.AdminState)
npujar1d86a522019-11-14 17:11:16 +0530404 }
khenaidoo4554f7c2019-05-29 22:13:15 -0400405
npujar1d86a522019-11-14 17:11:16 +0530406 // Update the Admin State and operational state before sending the request out
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500407 if err := agent.updateDeviceStateInStoreWithoutLock(ctx, cloned, voltha.AdminState_DISABLED, cloned.ConnectStatus, voltha.OperStatus_UNKNOWN); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530408 return err
409 }
khenaidoo442e7c72020-03-10 16:13:48 -0400410
411 subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
Kent Hagerman2b216042020-04-03 18:28:56 -0400412 ch, err := agent.adapterProxy.DisableDevice(subCtx, proto.Clone(cloned).(*voltha.Device))
khenaidoo442e7c72020-03-10 16:13:48 -0400413 if err != nil {
414 cancel()
npujar1d86a522019-11-14 17:11:16 +0530415 return err
khenaidoo0a822f92019-05-08 15:15:57 -0400416 }
khenaidoo442e7c72020-03-10 16:13:48 -0400417 go agent.waitForAdapterResponse(subCtx, cancel, "disableDevice", ch, agent.onSuccess, agent.onFailure)
khenaidoo0a822f92019-05-08 15:15:57 -0400418
khenaidoo92e62c52018-10-03 14:02:54 -0400419 return nil
420}
421
Kent Hagerman2b216042020-04-03 18:28:56 -0400422func (agent *Agent) rebootDevice(ctx context.Context) error {
khenaidoo442e7c72020-03-10 16:13:48 -0400423 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530424 return err
khenaidoo4d4802d2018-10-04 21:59:49 -0400425 }
khenaidoo442e7c72020-03-10 16:13:48 -0400426 defer agent.requestQueue.RequestComplete()
Rohan Agrawal31f21802020-06-12 05:38:46 +0000427 logger.Debugw(ctx, "rebootDevice", log.Fields{"device-id": agent.deviceID})
khenaidoo442e7c72020-03-10 16:13:48 -0400428
429 device := agent.getDeviceWithoutLock()
430 subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
Kent Hagerman2b216042020-04-03 18:28:56 -0400431 ch, err := agent.adapterProxy.RebootDevice(subCtx, device)
khenaidoo442e7c72020-03-10 16:13:48 -0400432 if err != nil {
433 cancel()
434 return err
435 }
436 go agent.waitForAdapterResponse(subCtx, cancel, "rebootDevice", ch, agent.onSuccess, agent.onFailure)
khenaidoo4d4802d2018-10-04 21:59:49 -0400437 return nil
438}
439
Kent Hagerman2b216042020-04-03 18:28:56 -0400440func (agent *Agent) deleteDevice(ctx context.Context) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000441 logger.Debugw(ctx, "deleteDevice", log.Fields{"device-id": agent.deviceID})
khenaidoo442e7c72020-03-10 16:13:48 -0400442 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
443 return err
444 }
445 defer agent.requestQueue.RequestComplete()
khenaidoo6e55d9e2019-12-12 18:26:26 -0500446
447 cloned := agent.getDeviceWithoutLock()
Chaitrashree G S543df3e2020-02-24 22:36:54 -0500448
khenaidoo442e7c72020-03-10 16:13:48 -0400449 previousState := cloned.AdminState
450
451 // No check is required when deleting a device. Changing the state to DELETE will trigger the removal of this
452 // device by the state machine
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500453 if err := agent.updateDeviceStateInStoreWithoutLock(ctx, cloned, voltha.AdminState_DELETED, cloned.ConnectStatus, cloned.OperStatus); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530454 return err
455 }
khenaidoo442e7c72020-03-10 16:13:48 -0400456
457 // If the device was in pre-prov state (only parent device are in that state) then do not send the request to the
458 // adapter
459 if previousState != ic.AdminState_PREPROVISIONED {
460 subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
Kent Hagerman2b216042020-04-03 18:28:56 -0400461 ch, err := agent.adapterProxy.DeleteDevice(subCtx, cloned)
khenaidoo442e7c72020-03-10 16:13:48 -0400462 if err != nil {
463 cancel()
464 return err
465 }
466 go agent.waitForAdapterResponse(subCtx, cancel, "deleteDevice", ch, agent.onSuccess, agent.onFailure)
467 }
khenaidoo4d4802d2018-10-04 21:59:49 -0400468 return nil
469}
470
Kent Hagerman2b216042020-04-03 18:28:56 -0400471func (agent *Agent) setParentID(ctx context.Context, device *voltha.Device, parentID string) error {
khenaidoo442e7c72020-03-10 16:13:48 -0400472 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
473 return err
474 }
475 defer agent.requestQueue.RequestComplete()
476
Rohan Agrawal31f21802020-06-12 05:38:46 +0000477 logger.Debugw(ctx, "setParentId", log.Fields{"device-id": device.Id, "parent-id": parentID})
khenaidoo6e55d9e2019-12-12 18:26:26 -0500478
479 cloned := agent.getDeviceWithoutLock()
npujar1d86a522019-11-14 17:11:16 +0530480 cloned.ParentId = parentID
481 // Store the device
npujar467fe752020-01-16 20:17:45 +0530482 if err := agent.updateDeviceInStoreWithoutLock(ctx, cloned, false, ""); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530483 return err
484 }
khenaidoo442e7c72020-03-10 16:13:48 -0400485
npujar1d86a522019-11-14 17:11:16 +0530486 return nil
khenaidooad06fd72019-10-28 12:26:05 -0400487}
488
khenaidoo442e7c72020-03-10 16:13:48 -0400489// getSwitchCapability retrieves the switch capability of a parent device
Kent Hagerman2b216042020-04-03 18:28:56 -0400490func (agent *Agent) getSwitchCapability(ctx context.Context) (*ic.SwitchCapability, error) {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000491 logger.Debugw(ctx, "getSwitchCapability", log.Fields{"device-id": agent.deviceID})
khenaidoo442e7c72020-03-10 16:13:48 -0400492
493 cloned, err := agent.getDevice(ctx)
494 if err != nil {
khenaidoob9203542018-09-17 22:56:37 -0400495 return nil, err
khenaidoob9203542018-09-17 22:56:37 -0400496 }
Kent Hagerman2b216042020-04-03 18:28:56 -0400497 ch, err := agent.adapterProxy.GetOfpDeviceInfo(ctx, cloned)
khenaidoo442e7c72020-03-10 16:13:48 -0400498 if err != nil {
499 return nil, err
500 }
501
502 // Wait for adapter response
503 rpcResponse, ok := <-ch
504 if !ok {
505 return nil, status.Errorf(codes.Aborted, "channel-closed")
506 }
507 if rpcResponse.Err != nil {
508 return nil, rpcResponse.Err
509 }
510 // Successful response
511 switchCap := &ic.SwitchCapability{}
512 if err := ptypes.UnmarshalAny(rpcResponse.Reply, switchCap); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530513 return nil, err
514 }
515 return switchCap, nil
khenaidoob9203542018-09-17 22:56:37 -0400516}
517
Rohan Agrawal31f21802020-06-12 05:38:46 +0000518func (agent *Agent) onPacketFailure(ctx context.Context, rpc string, response interface{}, args ...interface{}) {
khenaidoo442e7c72020-03-10 16:13:48 -0400519 // packet data is encoded in the args param as the first parameter
520 var packet []byte
521 if len(args) >= 1 {
522 if pkt, ok := args[0].([]byte); ok {
523 packet = pkt
524 }
525 }
526 var errResp error
527 if err, ok := response.(error); ok {
528 errResp = err
529 }
Rohan Agrawal31f21802020-06-12 05:38:46 +0000530 logger.Warnw(ctx, "packet-out-error", log.Fields{
khenaidoo442e7c72020-03-10 16:13:48 -0400531 "device-id": agent.deviceID,
532 "error": errResp,
533 "packet": hex.EncodeToString(packet),
534 })
535}
536
Kent Hagerman2b216042020-04-03 18:28:56 -0400537func (agent *Agent) packetOut(ctx context.Context, outPort uint32, packet *ofp.OfpPacketOut) error {
Scott Baker80678602019-11-14 16:57:36 -0800538 // If deviceType=="" then we must have taken ownership of this device.
539 // Fixes VOL-2226 where a core would take ownership and have stale data
540 if agent.deviceType == "" {
npujar467fe752020-01-16 20:17:45 +0530541 agent.reconcileWithKVStore(ctx)
Scott Baker80678602019-11-14 16:57:36 -0800542 }
khenaidoofdbad6e2018-11-06 22:26:38 -0500543 // Send packet to adapter
khenaidoo442e7c72020-03-10 16:13:48 -0400544 subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
Kent Hagerman2b216042020-04-03 18:28:56 -0400545 ch, err := agent.adapterProxy.PacketOut(subCtx, agent.deviceType, agent.deviceID, outPort, packet)
khenaidoo442e7c72020-03-10 16:13:48 -0400546 if err != nil {
547 cancel()
548 return nil
khenaidoofdbad6e2018-11-06 22:26:38 -0500549 }
khenaidoo442e7c72020-03-10 16:13:48 -0400550 go agent.waitForAdapterResponse(subCtx, cancel, "packetOut", ch, agent.onSuccess, agent.onPacketFailure, packet.Data)
khenaidoofdbad6e2018-11-06 22:26:38 -0500551 return nil
552}
553
Mahir Gunyel8e2707d2019-07-25 00:36:21 -0700554// updatePartialDeviceData updates a subset of a device that an Adapter can update.
555// TODO: May need a specific proto to handle only a subset of a device that can be changed by an adapter
Kent Hagerman2b216042020-04-03 18:28:56 -0400556func (agent *Agent) mergeDeviceInfoFromAdapter(device *voltha.Device) (*voltha.Device, error) {
khenaidoo6e55d9e2019-12-12 18:26:26 -0500557 cloned := agent.getDeviceWithoutLock()
Mahir Gunyel8e2707d2019-07-25 00:36:21 -0700558 cloned.Root = device.Root
559 cloned.Vendor = device.Vendor
560 cloned.Model = device.Model
561 cloned.SerialNumber = device.SerialNumber
562 cloned.MacAddress = device.MacAddress
563 cloned.Vlan = device.Vlan
564 cloned.Reason = device.Reason
565 return cloned, nil
566}
khenaidoo442e7c72020-03-10 16:13:48 -0400567
Kent Hagerman2b216042020-04-03 18:28:56 -0400568func (agent *Agent) updateDeviceUsingAdapterData(ctx context.Context, device *voltha.Device) error {
khenaidoo442e7c72020-03-10 16:13:48 -0400569 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
570 return err
571 }
572 defer agent.requestQueue.RequestComplete()
Rohan Agrawal31f21802020-06-12 05:38:46 +0000573 logger.Debugw(ctx, "updateDeviceUsingAdapterData", log.Fields{"device-id": device.Id})
khenaidoo442e7c72020-03-10 16:13:48 -0400574
npujar1d86a522019-11-14 17:11:16 +0530575 updatedDevice, err := agent.mergeDeviceInfoFromAdapter(device)
576 if err != nil {
Mahir Gunyel8e2707d2019-07-25 00:36:21 -0700577 return status.Errorf(codes.Internal, "%s", err.Error())
Mahir Gunyel8e2707d2019-07-25 00:36:21 -0700578 }
npujar1d86a522019-11-14 17:11:16 +0530579 cloned := proto.Clone(updatedDevice).(*voltha.Device)
npujar467fe752020-01-16 20:17:45 +0530580 return agent.updateDeviceInStoreWithoutLock(ctx, cloned, false, "")
khenaidoo43c82122018-11-22 18:38:28 -0500581}
582
Kent Hagerman2b216042020-04-03 18:28:56 -0400583func (agent *Agent) updateDeviceStatus(ctx context.Context, operStatus voltha.OperStatus_Types, connStatus voltha.ConnectStatus_Types) error {
khenaidoo442e7c72020-03-10 16:13:48 -0400584 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
585 return err
586 }
587 defer agent.requestQueue.RequestComplete()
khenaidoo6e55d9e2019-12-12 18:26:26 -0500588
589 cloned := agent.getDeviceWithoutLock()
590
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500591 newConnStatus, newOperStatus := cloned.ConnectStatus, cloned.OperStatus
npujar1d86a522019-11-14 17:11:16 +0530592 // Ensure the enums passed in are valid - they will be invalid if they are not set when this function is invoked
serkant.uluderya2ae470f2020-01-21 11:13:09 -0800593 if s, ok := voltha.ConnectStatus_Types_value[connStatus.String()]; ok {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000594 logger.Debugw(ctx, "updateDeviceStatus-conn", log.Fields{"ok": ok, "val": s})
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500595 newConnStatus = connStatus
npujar1d86a522019-11-14 17:11:16 +0530596 }
serkant.uluderya2ae470f2020-01-21 11:13:09 -0800597 if s, ok := voltha.OperStatus_Types_value[operStatus.String()]; ok {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000598 logger.Debugw(ctx, "updateDeviceStatus-oper", log.Fields{"ok": ok, "val": s})
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500599 newOperStatus = operStatus
npujar1d86a522019-11-14 17:11:16 +0530600 }
Rohan Agrawal31f21802020-06-12 05:38:46 +0000601 logger.Debugw(ctx, "updateDeviceStatus", log.Fields{"deviceId": cloned.Id, "operStatus": cloned.OperStatus, "connectStatus": cloned.ConnectStatus})
npujar1d86a522019-11-14 17:11:16 +0530602 // Store the device
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500603 return agent.updateDeviceStateInStoreWithoutLock(ctx, cloned, cloned.AdminState, newConnStatus, newOperStatus)
khenaidoo92e62c52018-10-03 14:02:54 -0400604}
605
khenaidoob9203542018-09-17 22:56:37 -0400606// TODO: A generic device update by attribute
Kent Hagerman2b216042020-04-03 18:28:56 -0400607func (agent *Agent) updateDeviceAttribute(ctx context.Context, name string, value interface{}) {
khenaidoo442e7c72020-03-10 16:13:48 -0400608 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000609 logger.Warnw(ctx, "request-aborted", log.Fields{"device-id": agent.deviceID, "name": name, "error": err})
khenaidoo442e7c72020-03-10 16:13:48 -0400610 return
611 }
612 defer agent.requestQueue.RequestComplete()
khenaidoob9203542018-09-17 22:56:37 -0400613 if value == nil {
614 return
615 }
khenaidoo6e55d9e2019-12-12 18:26:26 -0500616
617 cloned := agent.getDeviceWithoutLock()
khenaidoob9203542018-09-17 22:56:37 -0400618 updated := false
khenaidoo6e55d9e2019-12-12 18:26:26 -0500619 s := reflect.ValueOf(cloned).Elem()
khenaidoob9203542018-09-17 22:56:37 -0400620 if s.Kind() == reflect.Struct {
621 // exported field
622 f := s.FieldByName(name)
623 if f.IsValid() && f.CanSet() {
624 switch f.Kind() {
625 case reflect.String:
626 f.SetString(value.(string))
627 updated = true
628 case reflect.Uint32:
629 f.SetUint(uint64(value.(uint32)))
630 updated = true
631 case reflect.Bool:
632 f.SetBool(value.(bool))
633 updated = true
634 }
635 }
636 }
Rohan Agrawal31f21802020-06-12 05:38:46 +0000637 logger.Debugw(ctx, "update-field-status", log.Fields{"deviceId": cloned.Id, "name": name, "updated": updated})
khenaidoob9203542018-09-17 22:56:37 -0400638 // Save the data
khenaidoo6e55d9e2019-12-12 18:26:26 -0500639
npujar467fe752020-01-16 20:17:45 +0530640 if err := agent.updateDeviceInStoreWithoutLock(ctx, cloned, false, ""); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000641 logger.Warnw(ctx, "attribute-update-failed", log.Fields{"attribute": name, "value": value})
khenaidoob9203542018-09-17 22:56:37 -0400642 }
khenaidoob9203542018-09-17 22:56:37 -0400643}
serkant.uluderya334479d2019-04-10 08:26:15 -0700644
Kent Hagerman45a13e42020-04-13 12:23:50 -0400645func (agent *Agent) simulateAlarm(ctx context.Context, simulateReq *voltha.SimulateAlarmRequest) error {
khenaidoo442e7c72020-03-10 16:13:48 -0400646 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
647 return err
648 }
649 defer agent.requestQueue.RequestComplete()
Rohan Agrawal31f21802020-06-12 05:38:46 +0000650 logger.Debugw(ctx, "simulateAlarm", log.Fields{"id": agent.deviceID})
khenaidoo6e55d9e2019-12-12 18:26:26 -0500651
652 cloned := agent.getDeviceWithoutLock()
653
khenaidoo442e7c72020-03-10 16:13:48 -0400654 subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
Kent Hagerman45a13e42020-04-13 12:23:50 -0400655 ch, err := agent.adapterProxy.SimulateAlarm(subCtx, cloned, simulateReq)
khenaidoo442e7c72020-03-10 16:13:48 -0400656 if err != nil {
657 cancel()
npujar1d86a522019-11-14 17:11:16 +0530658 return err
serkant.uluderya334479d2019-04-10 08:26:15 -0700659 }
khenaidoo442e7c72020-03-10 16:13:48 -0400660 go agent.waitForAdapterResponse(subCtx, cancel, "simulateAlarm", ch, agent.onSuccess, agent.onFailure)
serkant.uluderya334479d2019-04-10 08:26:15 -0700661 return nil
662}
Mahir Gunyelb5851672019-07-24 10:46:26 +0300663
Kent Hagerman2b216042020-04-03 18:28:56 -0400664func (agent *Agent) updateDeviceStateInStoreWithoutLock(
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500665 ctx context.Context,
666 device *voltha.Device,
667 adminState voltha.AdminState_Types,
668 connectStatus voltha.ConnectStatus_Types,
669 operStatus voltha.OperStatus_Types,
670) error {
671 previousState := getDeviceStates(device)
672 device.AdminState, device.ConnectStatus, device.OperStatus = adminState, connectStatus, operStatus
673
674 if err := agent.updateDeviceInStoreWithoutLock(ctx, device, false, ""); err != nil {
675 return err
676 }
677
678 // process state transition in its own thread
679 go func() {
680 if err := agent.deviceMgr.processTransition(context.Background(), device, previousState); err != nil {
681 log.Errorw("failed-process-transition", log.Fields{"deviceId": device.Id, "previousAdminState": previousState.Admin, "currentAdminState": device.AdminState})
682 }
683 }()
684 return nil
685}
686
Mahir Gunyelb5851672019-07-24 10:46:26 +0300687//This is an update operation to model without Lock.This function must never be invoked by another function unless the latter holds a lock on the device.
688// It is an internal helper function.
Kent Hagerman2b216042020-04-03 18:28:56 -0400689func (agent *Agent) updateDeviceInStoreWithoutLock(ctx context.Context, device *voltha.Device, strict bool, txid string) error {
Kent Hagerman4f355f52020-03-30 16:01:33 -0400690 if agent.stopped {
691 return errors.New("device agent stopped")
Thomas Lee Se5a44012019-11-07 20:32:24 +0530692 }
Kent Hagerman4f355f52020-03-30 16:01:33 -0400693
Kent Hagermanf5a67352020-04-30 15:15:26 -0400694 if err := agent.dbProxy.Set(ctx, agent.deviceID, device); err != nil {
Kent Hagerman4f355f52020-03-30 16:01:33 -0400695 return status.Errorf(codes.Internal, "failed-update-device:%s: %s", agent.deviceID, err)
Mahir Gunyelb5851672019-07-24 10:46:26 +0300696 }
Rohan Agrawal31f21802020-06-12 05:38:46 +0000697 logger.Debugw(ctx, "updated-device-in-store", log.Fields{"deviceId: ": agent.deviceID})
Mahir Gunyelb5851672019-07-24 10:46:26 +0300698
khenaidoo0db4c812020-05-27 15:27:30 -0400699 agent.device = device
Mahir Gunyelb5851672019-07-24 10:46:26 +0300700 return nil
701}
Mahir Gunyelfdee9212019-10-16 16:52:21 -0700702
Kent Hagerman2b216042020-04-03 18:28:56 -0400703func (agent *Agent) updateDeviceReason(ctx context.Context, reason string) error {
khenaidoo442e7c72020-03-10 16:13:48 -0400704 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
705 return err
706 }
707 defer agent.requestQueue.RequestComplete()
khenaidoo6e55d9e2019-12-12 18:26:26 -0500708
709 cloned := agent.getDeviceWithoutLock()
npujar1d86a522019-11-14 17:11:16 +0530710 cloned.Reason = reason
Rohan Agrawal31f21802020-06-12 05:38:46 +0000711 logger.Debugw(ctx, "updateDeviceReason", log.Fields{"deviceId": cloned.Id, "reason": cloned.Reason})
npujar1d86a522019-11-14 17:11:16 +0530712 // Store the device
npujar467fe752020-01-16 20:17:45 +0530713 return agent.updateDeviceInStoreWithoutLock(ctx, cloned, false, "")
Mahir Gunyelfdee9212019-10-16 16:52:21 -0700714}
kesavandbc2d1622020-01-21 00:42:01 -0500715
Kent Hagerman2b216042020-04-03 18:28:56 -0400716func (agent *Agent) ChildDeviceLost(ctx context.Context, device *voltha.Device) error {
khenaidoo442e7c72020-03-10 16:13:48 -0400717 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
718 return err
719 }
720 defer agent.requestQueue.RequestComplete()
Chaitrashree G S543df3e2020-02-24 22:36:54 -0500721
Rohan Agrawal31f21802020-06-12 05:38:46 +0000722 logger.Debugw(ctx, "childDeviceLost", log.Fields{"child-device-id": device.Id, "parent-device-ud": agent.deviceID})
Chaitrashree G S543df3e2020-02-24 22:36:54 -0500723
724 //Remove the associated peer ports on the parent device
khenaidoo442e7c72020-03-10 16:13:48 -0400725 parentDevice := agent.getDeviceWithoutLock()
726 var updatedPeers []*voltha.Port_PeerPort
727 for _, port := range parentDevice.Ports {
728 updatedPeers = make([]*voltha.Port_PeerPort, 0)
729 for _, peerPort := range port.Peers {
730 if peerPort.DeviceId != device.Id {
731 updatedPeers = append(updatedPeers, peerPort)
732 }
733 }
734 port.Peers = updatedPeers
735 }
736 if err := agent.updateDeviceInStoreWithoutLock(ctx, parentDevice, false, ""); err != nil {
737 return err
Chaitrashree G S543df3e2020-02-24 22:36:54 -0500738 }
739
khenaidoo442e7c72020-03-10 16:13:48 -0400740 //send request to adapter
741 subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
Kent Hagerman2b216042020-04-03 18:28:56 -0400742 ch, err := agent.adapterProxy.ChildDeviceLost(ctx, agent.deviceType, agent.deviceID, device.ParentPortNo, device.ProxyAddress.OnuId)
khenaidoo442e7c72020-03-10 16:13:48 -0400743 if err != nil {
744 cancel()
745 return err
Chaitrashree G S543df3e2020-02-24 22:36:54 -0500746 }
khenaidoo442e7c72020-03-10 16:13:48 -0400747 go agent.waitForAdapterResponse(subCtx, cancel, "childDeviceLost", ch, agent.onSuccess, agent.onFailure)
Chaitrashree G S543df3e2020-02-24 22:36:54 -0500748 return nil
Chaitrashree G S543df3e2020-02-24 22:36:54 -0500749}
onkarkundargi87285252020-01-27 11:34:52 +0530750
Kent Hagerman2b216042020-04-03 18:28:56 -0400751func (agent *Agent) startOmciTest(ctx context.Context, omcitestrequest *voltha.OmciTestRequest) (*voltha.TestResponse, error) {
onkarkundargi87285252020-01-27 11:34:52 +0530752 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
753 return nil, err
754 }
755
756 device := agent.getDeviceWithoutLock()
Matteo Scandolod525ae32020-04-02 17:27:29 -0700757
758 if device.Adapter == "" {
Kent Hagerman2b216042020-04-03 18:28:56 -0400759 adapterName, err := agent.adapterMgr.GetAdapterType(device.Type)
Matteo Scandolod525ae32020-04-02 17:27:29 -0700760 if err != nil {
761 agent.requestQueue.RequestComplete()
762 return nil, err
763 }
Matteo Scandolod525ae32020-04-02 17:27:29 -0700764 device.Adapter = adapterName
onkarkundargi87285252020-01-27 11:34:52 +0530765 }
766
767 // Send request to the adapter
Kent Hagerman2b216042020-04-03 18:28:56 -0400768 ch, err := agent.adapterProxy.StartOmciTest(ctx, device, omcitestrequest)
onkarkundargi87285252020-01-27 11:34:52 +0530769 agent.requestQueue.RequestComplete()
770 if err != nil {
771 return nil, err
772 }
773
774 // Wait for the adapter response
775 rpcResponse, ok := <-ch
776 if !ok {
777 return nil, status.Errorf(codes.Aborted, "channel-closed-device-id-%s", agent.deviceID)
778 }
779 if rpcResponse.Err != nil {
780 return nil, rpcResponse.Err
781 }
782
783 // Unmarshal and return the response
784 testResp := &voltha.TestResponse{}
785 if err := ptypes.UnmarshalAny(rpcResponse.Reply, testResp); err != nil {
786 return nil, status.Errorf(codes.InvalidArgument, "%s", err.Error())
787 }
Rohan Agrawal31f21802020-06-12 05:38:46 +0000788 logger.Debugw(ctx, "Omci_test_Request-Success-device-agent", log.Fields{"testResp": testResp})
onkarkundargi87285252020-01-27 11:34:52 +0530789 return testResp, nil
790}
Dinesh Belwalkarc1129f12020-02-27 10:41:33 -0800791
792func (agent *Agent) getExtValue(ctx context.Context, pdevice *voltha.Device, cdevice *voltha.Device, valueparam *voltha.ValueSpecifier) (*voltha.ReturnValues, error) {
793 log.Debugw("getExtValue", log.Fields{"device-id": agent.deviceID, "onuid": valueparam.Id, "valuetype": valueparam.Value})
794 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
795 return nil, err
796 }
797
798 //send request to adapter
799 ch, err := agent.adapterProxy.GetExtValue(ctx, pdevice, cdevice, valueparam.Id, valueparam.Value)
800 agent.requestQueue.RequestComplete()
801 if err != nil {
802 return nil, err
803 }
804
805 // Wait for the adapter response
806 rpcResponse, ok := <-ch
807 if !ok {
808 return nil, status.Errorf(codes.Aborted, "channel-closed-device-id-%s", agent.deviceID)
809 }
810 if rpcResponse.Err != nil {
811 return nil, rpcResponse.Err
812 }
813
814 // Unmarshal and return the response
815 Resp := &voltha.ReturnValues{}
816 if err := ptypes.UnmarshalAny(rpcResponse.Reply, Resp); err != nil {
817 return nil, status.Errorf(codes.InvalidArgument, "%s", err.Error())
818 }
Rohan Agrawal31f21802020-06-12 05:38:46 +0000819 logger.Debugw(ctx, "getExtValue-Success-device-agent", log.Fields{"Resp": Resp})
Dinesh Belwalkarc1129f12020-02-27 10:41:33 -0800820 return Resp, nil
821}