blob: 4c2b9f6bf112dc28c4498b4d3d318953e7e989e7 [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
khenaidoob9203542018-09-17 22:56:37 -040017package core
18
19import (
20 "context"
Matteo Scandolo360605d2019-11-05 18:29:17 -080021 "encoding/hex"
khenaidoo3ab34882019-05-02 21:33:30 -040022 "fmt"
khenaidoo442e7c72020-03-10 16:13:48 -040023 "github.com/golang/protobuf/ptypes"
24 "github.com/opencord/voltha-lib-go/v3/pkg/kafka"
Chaitrashree G Sa773e992019-09-09 21:04:15 -040025 "reflect"
26 "sync"
27 "time"
28
khenaidoob9203542018-09-17 22:56:37 -040029 "github.com/gogo/protobuf/proto"
sbarbari17d7e222019-11-05 10:02:29 -050030 "github.com/opencord/voltha-go/db/model"
Scott Bakerb671a862019-10-24 10:53:40 -070031 coreutils "github.com/opencord/voltha-go/rw_core/utils"
serkant.uluderya2ae470f2020-01-21 11:13:09 -080032 fu "github.com/opencord/voltha-lib-go/v3/pkg/flows"
33 "github.com/opencord/voltha-lib-go/v3/pkg/log"
34 ic "github.com/opencord/voltha-protos/v3/go/inter_container"
35 ofp "github.com/opencord/voltha-protos/v3/go/openflow_13"
36 "github.com/opencord/voltha-protos/v3/go/voltha"
khenaidoob9203542018-09-17 22:56:37 -040037 "google.golang.org/grpc/codes"
38 "google.golang.org/grpc/status"
khenaidoob9203542018-09-17 22:56:37 -040039)
40
npujar1d86a522019-11-14 17:11:16 +053041// DeviceAgent represents device agent attributes
khenaidoob9203542018-09-17 22:56:37 -040042type DeviceAgent struct {
npujar1d86a522019-11-14 17:11:16 +053043 deviceID string
44 parentID string
khenaidoo43c82122018-11-22 18:38:28 -050045 deviceType string
khenaidoo2c6a0992019-04-29 13:46:56 -040046 isRootdevice bool
khenaidoo9a468962018-09-19 15:33:13 -040047 adapterProxy *AdapterProxy
serkant.uluderya334479d2019-04-10 08:26:15 -070048 adapterMgr *AdapterManager
khenaidoo9a468962018-09-19 15:33:13 -040049 deviceMgr *DeviceManager
50 clusterDataProxy *model.Proxy
51 exitChannel chan int
khenaidoo6e55d9e2019-12-12 18:26:26 -050052 device *voltha.Device
khenaidoo442e7c72020-03-10 16:13:48 -040053 requestQueue *coreutils.RequestQueue
54 defaultTimeout time.Duration
55 startOnce sync.Once
56 stopOnce sync.Once
57 stopped bool
khenaidoob9203542018-09-17 22:56:37 -040058}
59
Scott Baker80678602019-11-14 16:57:36 -080060//newDeviceAgent creates a new device agent. The device will be initialized when start() is called.
khenaidoo442e7c72020-03-10 16:13:48 -040061func newDeviceAgent(ap *AdapterProxy, device *voltha.Device, deviceMgr *DeviceManager, cdProxy *model.Proxy, timeout time.Duration) *DeviceAgent {
khenaidoob9203542018-09-17 22:56:37 -040062 var agent DeviceAgent
khenaidoob9203542018-09-17 22:56:37 -040063 agent.adapterProxy = ap
Scott Baker80678602019-11-14 16:57:36 -080064 if device.Id == "" {
npujar1d86a522019-11-14 17:11:16 +053065 agent.deviceID = CreateDeviceID()
Scott Baker80678602019-11-14 16:57:36 -080066 } else {
npujar1d86a522019-11-14 17:11:16 +053067 agent.deviceID = device.Id
Stephane Barbarie1ab43272018-12-08 21:42:13 -050068 }
Scott Baker80678602019-11-14 16:57:36 -080069
khenaidoo2c6a0992019-04-29 13:46:56 -040070 agent.isRootdevice = device.Root
npujar1d86a522019-11-14 17:11:16 +053071 agent.parentID = device.ParentId
Scott Baker80678602019-11-14 16:57:36 -080072 agent.deviceType = device.Type
khenaidoob9203542018-09-17 22:56:37 -040073 agent.deviceMgr = deviceMgr
khenaidoo21d51152019-02-01 13:48:37 -050074 agent.adapterMgr = deviceMgr.adapterMgr
khenaidoob9203542018-09-17 22:56:37 -040075 agent.exitChannel = make(chan int, 1)
khenaidoo9a468962018-09-19 15:33:13 -040076 agent.clusterDataProxy = cdProxy
khenaidoo2c6a0992019-04-29 13:46:56 -040077 agent.defaultTimeout = timeout
khenaidoo6e55d9e2019-12-12 18:26:26 -050078 agent.device = proto.Clone(device).(*voltha.Device)
Kent Hagerman730cbdf2020-03-31 12:22:08 -040079 agent.requestQueue = coreutils.NewRequestQueue()
khenaidoob9203542018-09-17 22:56:37 -040080 return &agent
81}
82
khenaidoo442e7c72020-03-10 16:13:48 -040083// start() saves the device to the data model and registers for callbacks on that device if deviceToCreate!=nil.
84// 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 -080085// was started.
86func (agent *DeviceAgent) start(ctx context.Context, deviceToCreate *voltha.Device) (*voltha.Device, error) {
khenaidoo442e7c72020-03-10 16:13:48 -040087 needToStart := false
88 if agent.startOnce.Do(func() { needToStart = true }); !needToStart {
89 return agent.getDevice(ctx)
90 }
91 var startSucceeded bool
92 defer func() {
93 if !startSucceeded {
94 if err := agent.stop(ctx); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +000095 logger.Errorw("failed-to-cleanup-after-unsuccessful-start", log.Fields{"device-id": agent.deviceID, "error": err})
khenaidoo442e7c72020-03-10 16:13:48 -040096 }
97 }
98 }()
Scott Baker80678602019-11-14 16:57:36 -080099
khenaidoo442e7c72020-03-10 16:13:48 -0400100 var device *voltha.Device
Scott Baker80678602019-11-14 16:57:36 -0800101 if deviceToCreate == nil {
102 // Load the existing device
Thomas Lee Se5a44012019-11-07 20:32:24 +0530103 loadedDevice, err := agent.clusterDataProxy.Get(ctx, "/devices/"+agent.deviceID, 1, true, "")
104 if err != nil {
Thomas Lee Se5a44012019-11-07 20:32:24 +0530105 return nil, err
106 }
107 if loadedDevice != nil {
Scott Baker80678602019-11-14 16:57:36 -0800108 var ok bool
109 if device, ok = loadedDevice.(*voltha.Device); ok {
110 agent.deviceType = device.Adapter
khenaidoo6e55d9e2019-12-12 18:26:26 -0500111 agent.device = proto.Clone(device).(*voltha.Device)
Scott Baker80678602019-11-14 16:57:36 -0800112 } else {
npujar1d86a522019-11-14 17:11:16 +0530113 return nil, status.Errorf(codes.NotFound, "device-%s", agent.deviceID)
khenaidoo297cd252019-02-07 22:10:23 -0500114 }
115 } else {
khenaidoo442e7c72020-03-10 16:13:48 -0400116 return nil, status.Errorf(codes.NotFound, "device-%s-loading-failed", agent.deviceID)
khenaidoo297cd252019-02-07 22:10:23 -0500117 }
Girish Kumarf56a4682020-03-20 20:07:46 +0000118 logger.Infow("device-loaded-from-dB", log.Fields{"device-id": agent.deviceID})
khenaidoo297cd252019-02-07 22:10:23 -0500119 } else {
Scott Baker80678602019-11-14 16:57:36 -0800120 // Create a new device
121 // Assumption is that AdminState, FlowGroups, and Flows are unitialized since this
122 // is a new device, so populate them here before passing the device to clusterDataProxy.AddWithId.
123 // agent.deviceId will also have been set during newDeviceAgent().
124 device = (proto.Clone(deviceToCreate)).(*voltha.Device)
npujar1d86a522019-11-14 17:11:16 +0530125 device.Id = agent.deviceID
Scott Baker80678602019-11-14 16:57:36 -0800126 device.AdminState = voltha.AdminState_PREPROVISIONED
127 device.FlowGroups = &ofp.FlowGroups{Items: nil}
128 device.Flows = &ofp.Flows{Items: nil}
129 if !deviceToCreate.GetRoot() && deviceToCreate.ProxyAddress != nil {
130 // Set the default vlan ID to the one specified by the parent adapter. It can be
131 // overwritten by the child adapter during a device update request
132 device.Vlan = deviceToCreate.ProxyAddress.ChannelId
133 }
134
khenaidoo297cd252019-02-07 22:10:23 -0500135 // Add the initial device to the local model
Thomas Lee Se5a44012019-11-07 20:32:24 +0530136 added, err := agent.clusterDataProxy.AddWithID(ctx, "/devices", agent.deviceID, device, "")
137 if err != nil {
Thomas Lee Se5a44012019-11-07 20:32:24 +0530138 return nil, err
139 }
140 if added == nil {
npujar1d86a522019-11-14 17:11:16 +0530141 return nil, status.Errorf(codes.Aborted, "failed-adding-device-%s", agent.deviceID)
khenaidoo297cd252019-02-07 22:10:23 -0500142 }
khenaidoo442e7c72020-03-10 16:13:48 -0400143 agent.device = device
khenaidoob9203542018-09-17 22:56:37 -0400144 }
khenaidoo19d7b632018-10-30 10:49:50 -0400145
khenaidoo442e7c72020-03-10 16:13:48 -0400146 startSucceeded = true
Girish Kumarf56a4682020-03-20 20:07:46 +0000147 logger.Debugw("device-agent-started", log.Fields{"device-id": agent.deviceID})
khenaidoo442e7c72020-03-10 16:13:48 -0400148
149 return agent.getDevice(ctx)
khenaidoob9203542018-09-17 22:56:37 -0400150}
151
khenaidoo4d4802d2018-10-04 21:59:49 -0400152// stop stops the device agent. Not much to do for now
khenaidoo442e7c72020-03-10 16:13:48 -0400153func (agent *DeviceAgent) stop(ctx context.Context) error {
154 needToStop := false
155 if agent.stopOnce.Do(func() { needToStop = true }); !needToStop {
156 return nil
157 }
158 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
159 return err
160 }
161 defer agent.requestQueue.RequestComplete()
khenaidoo49085352020-01-13 19:15:43 -0500162
Girish Kumarf56a4682020-03-20 20:07:46 +0000163 logger.Infow("stopping-device-agent", log.Fields{"deviceId": agent.deviceID, "parentId": agent.parentID})
khenaidoo6e55d9e2019-12-12 18:26:26 -0500164
khenaidoo0a822f92019-05-08 15:15:57 -0400165 // Remove the device from the KV store
Thomas Lee Se5a44012019-11-07 20:32:24 +0530166 removed, err := agent.clusterDataProxy.Remove(ctx, "/devices/"+agent.deviceID, "")
167 if err != nil {
khenaidoo442e7c72020-03-10 16:13:48 -0400168 return err
Thomas Lee Se5a44012019-11-07 20:32:24 +0530169 }
170 if removed == nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000171 logger.Debugw("device-already-removed", log.Fields{"device-id": agent.deviceID})
khenaidoo0a822f92019-05-08 15:15:57 -0400172 }
khenaidoo442e7c72020-03-10 16:13:48 -0400173
khenaidoo442e7c72020-03-10 16:13:48 -0400174 close(agent.exitChannel)
175
176 agent.stopped = true
177
Girish Kumarf56a4682020-03-20 20:07:46 +0000178 logger.Infow("device-agent-stopped", log.Fields{"device-id": agent.deviceID, "parent-id": agent.parentID})
khenaidoo442e7c72020-03-10 16:13:48 -0400179
180 return nil
khenaidoob9203542018-09-17 22:56:37 -0400181}
182
Scott Baker80678602019-11-14 16:57:36 -0800183// Load the most recent state from the KVStore for the device.
npujar467fe752020-01-16 20:17:45 +0530184func (agent *DeviceAgent) reconcileWithKVStore(ctx context.Context) {
khenaidoo442e7c72020-03-10 16:13:48 -0400185 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000186 logger.Warnw("request-aborted", log.Fields{"device-id": agent.deviceID, "error": err})
khenaidoo442e7c72020-03-10 16:13:48 -0400187 return
188 }
189 defer agent.requestQueue.RequestComplete()
Girish Kumarf56a4682020-03-20 20:07:46 +0000190 logger.Debug("reconciling-device-agent-devicetype")
Scott Baker80678602019-11-14 16:57:36 -0800191 // TODO: context timeout
npujar467fe752020-01-16 20:17:45 +0530192 device, err := agent.clusterDataProxy.Get(ctx, "/devices/"+agent.deviceID, 1, true, "")
Thomas Lee Se5a44012019-11-07 20:32:24 +0530193 if err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000194 logger.Errorw("kv-get-failed", log.Fields{"device-id": agent.deviceID, "error": err})
Thomas Lee Se5a44012019-11-07 20:32:24 +0530195 return
196 }
197 if device != nil {
Scott Baker80678602019-11-14 16:57:36 -0800198 if d, ok := device.(*voltha.Device); ok {
199 agent.deviceType = d.Adapter
khenaidoo6e55d9e2019-12-12 18:26:26 -0500200 agent.device = proto.Clone(d).(*voltha.Device)
Girish Kumarf56a4682020-03-20 20:07:46 +0000201 logger.Debugw("reconciled-device-agent-devicetype", log.Fields{"device-id": agent.deviceID, "type": agent.deviceType})
Scott Baker80678602019-11-14 16:57:36 -0800202 }
203 }
204}
205
khenaidoo442e7c72020-03-10 16:13:48 -0400206// onSuccess is a common callback for scenarios where we receive a nil response following a request to an adapter
207// and the only action required is to publish a successful result on kafka
208func (agent *DeviceAgent) onSuccess(rpc string, response interface{}, reqArgs ...interface{}) {
Girish Kumarf56a4682020-03-20 20:07:46 +0000209 logger.Debugw("response successful", log.Fields{"rpc": rpc, "device-id": agent.deviceID})
khenaidoo442e7c72020-03-10 16:13:48 -0400210 // TODO: Post success message onto kafka
211}
212
213// onFailure is a common callback for scenarios where we receive an error response following a request to an adapter
214// and the only action required is to publish the failed result on kafka
215func (agent *DeviceAgent) onFailure(rpc string, response interface{}, reqArgs ...interface{}) {
216 if res, ok := response.(error); ok {
Girish Kumarf56a4682020-03-20 20:07:46 +0000217 logger.Errorw("rpc-failed", log.Fields{"rpc": rpc, "device-id": agent.deviceID, "error": res, "args": reqArgs})
khenaidoo442e7c72020-03-10 16:13:48 -0400218 } else {
Girish Kumarf56a4682020-03-20 20:07:46 +0000219 logger.Errorw("rpc-failed-invalid-error", log.Fields{"rpc": rpc, "device-id": agent.deviceID, "args": reqArgs})
khenaidoo442e7c72020-03-10 16:13:48 -0400220 }
221 // TODO: Post failure message onto kafka
222}
223
224func (agent *DeviceAgent) waitForAdapterResponse(ctx context.Context, cancel context.CancelFunc, rpc string, ch chan *kafka.RpcResponse,
225 onSuccess coreutils.ResponseCallback, onFailure coreutils.ResponseCallback, reqArgs ...interface{}) {
226 defer cancel()
227 select {
228 case rpcResponse, ok := <-ch:
229 if !ok {
230 onFailure(rpc, status.Errorf(codes.Aborted, "channel-closed"), reqArgs)
231 } else if rpcResponse.Err != nil {
232 onFailure(rpc, rpcResponse.Err, reqArgs)
233 } else {
234 onSuccess(rpc, rpcResponse.Reply, reqArgs)
235 }
236 case <-ctx.Done():
237 onFailure(rpc, ctx.Err(), reqArgs)
238 }
239}
240
khenaidoo6e55d9e2019-12-12 18:26:26 -0500241// getDevice returns the device data from cache
khenaidoo442e7c72020-03-10 16:13:48 -0400242func (agent *DeviceAgent) getDevice(ctx context.Context) (*voltha.Device, error) {
243 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
244 return nil, err
245 }
246 defer agent.requestQueue.RequestComplete()
247 return proto.Clone(agent.device).(*voltha.Device), nil
khenaidoo92e62c52018-10-03 14:02:54 -0400248}
249
khenaidoo4d4802d2018-10-04 21:59:49 -0400250// getDeviceWithoutLock is a helper function to be used ONLY by any device agent function AFTER it has acquired the device lock.
khenaidoo6e55d9e2019-12-12 18:26:26 -0500251func (agent *DeviceAgent) getDeviceWithoutLock() *voltha.Device {
252 return proto.Clone(agent.device).(*voltha.Device)
khenaidoo92e62c52018-10-03 14:02:54 -0400253}
254
khenaidoo3ab34882019-05-02 21:33:30 -0400255// enableDevice activates a preprovisioned or a disable device
khenaidoob9203542018-09-17 22:56:37 -0400256func (agent *DeviceAgent) enableDevice(ctx context.Context) error {
khenaidoo442e7c72020-03-10 16:13:48 -0400257 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
258 return err
259 }
260 defer agent.requestQueue.RequestComplete()
261
Girish Kumarf56a4682020-03-20 20:07:46 +0000262 logger.Debugw("enableDevice", log.Fields{"device-id": agent.deviceID})
khenaidoo21d51152019-02-01 13:48:37 -0500263
khenaidoo6e55d9e2019-12-12 18:26:26 -0500264 cloned := agent.getDeviceWithoutLock()
265
npujar1d86a522019-11-14 17:11:16 +0530266 // 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 -0400267 // pre-provisioned with the required adapter not registered. At this stage, since we need to communicate
npujar1d86a522019-11-14 17:11:16 +0530268 // with the adapter then we need to know the adapter that will handle this request
khenaidoo6e55d9e2019-12-12 18:26:26 -0500269 adapterName, err := agent.adapterMgr.getAdapterName(cloned.Type)
npujar1d86a522019-11-14 17:11:16 +0530270 if err != nil {
npujar1d86a522019-11-14 17:11:16 +0530271 return err
272 }
khenaidoo6e55d9e2019-12-12 18:26:26 -0500273 cloned.Adapter = adapterName
npujar1d86a522019-11-14 17:11:16 +0530274
khenaidoo6e55d9e2019-12-12 18:26:26 -0500275 if cloned.AdminState == voltha.AdminState_ENABLED {
Girish Kumarf56a4682020-03-20 20:07:46 +0000276 logger.Debugw("device-already-enabled", log.Fields{"device-id": agent.deviceID})
npujar1d86a522019-11-14 17:11:16 +0530277 return nil
278 }
279
khenaidoo6e55d9e2019-12-12 18:26:26 -0500280 if cloned.AdminState == voltha.AdminState_DELETED {
npujar1d86a522019-11-14 17:11:16 +0530281 // This is a temporary state when a device is deleted before it gets removed from the model.
khenaidoo6e55d9e2019-12-12 18:26:26 -0500282 err = status.Error(codes.FailedPrecondition, fmt.Sprintf("cannot-enable-a-deleted-device: %s ", cloned.Id))
npujar1d86a522019-11-14 17:11:16 +0530283 return err
284 }
285
khenaidoo6e55d9e2019-12-12 18:26:26 -0500286 previousAdminState := cloned.AdminState
npujar1d86a522019-11-14 17:11:16 +0530287
288 // Update the Admin State and set the operational state to activating before sending the request to the
289 // Adapters
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500290 if err := agent.updateDeviceStateInStoreWithoutLock(ctx, cloned, voltha.AdminState_ENABLED, cloned.ConnectStatus, voltha.OperStatus_ACTIVATING); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530291 return err
292 }
293
khenaidoo442e7c72020-03-10 16:13:48 -0400294 // 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 -0500295 device := proto.Clone(cloned).(*voltha.Device)
khenaidoo442e7c72020-03-10 16:13:48 -0400296 var ch chan *kafka.RpcResponse
297 subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
npujar1d86a522019-11-14 17:11:16 +0530298 if previousAdminState == voltha.AdminState_PREPROVISIONED {
khenaidoo442e7c72020-03-10 16:13:48 -0400299 ch, err = agent.adapterProxy.adoptDevice(subCtx, device)
khenaidoob9203542018-09-17 22:56:37 -0400300 } else {
khenaidoo442e7c72020-03-10 16:13:48 -0400301 ch, err = agent.adapterProxy.reEnableDevice(subCtx, device)
khenaidoob9203542018-09-17 22:56:37 -0400302 }
khenaidoo442e7c72020-03-10 16:13:48 -0400303 if err != nil {
304 cancel()
305 return err
306 }
307 // Wait for response
308 go agent.waitForAdapterResponse(subCtx, cancel, "enableDevice", ch, agent.onSuccess, agent.onFailure)
khenaidoob9203542018-09-17 22:56:37 -0400309 return nil
310}
311
khenaidoo442e7c72020-03-10 16:13:48 -0400312func (agent *DeviceAgent) waitForAdapterFlowResponse(ctx context.Context, cancel context.CancelFunc, ch chan *kafka.RpcResponse, response coreutils.Response) {
313 defer cancel()
314 select {
315 case rpcResponse, ok := <-ch:
316 if !ok {
317 response.Error(status.Errorf(codes.Aborted, "channel-closed"))
318 } else if rpcResponse.Err != nil {
319 response.Error(rpcResponse.Err)
320 } else {
321 response.Done()
322 }
323 case <-ctx.Done():
324 response.Error(ctx.Err())
khenaidoo2c6a0992019-04-29 13:46:56 -0400325 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400326}
327
khenaidoob2121e52019-12-16 17:17:22 -0500328//deleteFlowWithoutPreservingOrder removes a flow specified by index from the flows slice. This function will
329//panic if the index is out of range.
330func deleteFlowWithoutPreservingOrder(flows []*ofp.OfpFlowStats, index int) []*ofp.OfpFlowStats {
331 flows[index] = flows[len(flows)-1]
332 flows[len(flows)-1] = nil
333 return flows[:len(flows)-1]
334}
335
336//deleteGroupWithoutPreservingOrder removes a group specified by index from the groups slice. This function will
337//panic if the index is out of range.
338func deleteGroupWithoutPreservingOrder(groups []*ofp.OfpGroupEntry, index int) []*ofp.OfpGroupEntry {
339 groups[index] = groups[len(groups)-1]
340 groups[len(groups)-1] = nil
341 return groups[:len(groups)-1]
342}
343
344func flowsToUpdateToDelete(newFlows, existingFlows []*ofp.OfpFlowStats) (updatedNewFlows, flowsToDelete, updatedAllFlows []*ofp.OfpFlowStats) {
345 // Process flows
346 for _, flow := range existingFlows {
347 if idx := fu.FindFlows(newFlows, flow); idx == -1 {
348 updatedAllFlows = append(updatedAllFlows, flow)
349 } else {
350 // We have a matching flow (i.e. the following field matches: "TableId", "Priority", "Flags", "Cookie",
351 // "Match". If this is an exact match (i.e. all other fields matches as well) then this flow will be
352 // ignored. Otherwise, the previous flow will be deleted and the new one added
353 if proto.Equal(newFlows[idx], flow) {
354 // Flow already exist, remove it from the new flows but keep it in the updated flows slice
355 newFlows = deleteFlowWithoutPreservingOrder(newFlows, idx)
356 updatedAllFlows = append(updatedAllFlows, flow)
357 } else {
358 // Minor change to flow, delete old and add new one
359 flowsToDelete = append(flowsToDelete, flow)
360 }
361 }
362 }
363 updatedAllFlows = append(updatedAllFlows, newFlows...)
364 return newFlows, flowsToDelete, updatedAllFlows
365}
366
367func groupsToUpdateToDelete(newGroups, existingGroups []*ofp.OfpGroupEntry) (updatedNewGroups, groupsToDelete, updatedAllGroups []*ofp.OfpGroupEntry) {
368 for _, group := range existingGroups {
369 if idx := fu.FindGroup(newGroups, group.Desc.GroupId); idx == -1 { // does not exist now
370 updatedAllGroups = append(updatedAllGroups, group)
371 } else {
372 // Follow same logic as flows
373 if proto.Equal(newGroups[idx], group) {
374 // Group already exist, remove it from the new groups
375 newGroups = deleteGroupWithoutPreservingOrder(newGroups, idx)
376 updatedAllGroups = append(updatedAllGroups, group)
377 } else {
378 // Minor change to group, delete old and add new one
379 groupsToDelete = append(groupsToDelete, group)
380 }
381 }
382 }
383 updatedAllGroups = append(updatedAllGroups, newGroups...)
384 return newGroups, groupsToDelete, updatedAllGroups
385}
386
npujar467fe752020-01-16 20:17:45 +0530387func (agent *DeviceAgent) addFlowsAndGroupsToAdapter(ctx context.Context, newFlows []*ofp.OfpFlowStats, newGroups []*ofp.OfpGroupEntry, flowMetadata *voltha.FlowMetadata) (coreutils.Response, error) {
Girish Kumarf56a4682020-03-20 20:07:46 +0000388 logger.Debugw("add-flows-groups-to-adapters", log.Fields{"device-id": agent.deviceID, "flows": newFlows, "groups": newGroups, "flow-metadata": flowMetadata})
khenaidoo0458db62019-06-20 08:50:36 -0400389
khenaidoo2c6a0992019-04-29 13:46:56 -0400390 if (len(newFlows) | len(newGroups)) == 0 {
Girish Kumarf56a4682020-03-20 20:07:46 +0000391 logger.Debugw("nothing-to-update", log.Fields{"device-id": agent.deviceID, "flows": newFlows, "groups": newGroups})
A R Karthick5c28f552019-12-11 22:47:44 -0800392 return coreutils.DoneResponse(), nil
khenaidoo2c6a0992019-04-29 13:46:56 -0400393 }
394
khenaidoo442e7c72020-03-10 16:13:48 -0400395 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
396 return coreutils.DoneResponse(), err
397 }
398 defer agent.requestQueue.RequestComplete()
khenaidoo2c6a0992019-04-29 13:46:56 -0400399
khenaidoo6e55d9e2019-12-12 18:26:26 -0500400 device := agent.getDeviceWithoutLock()
khenaidoo442e7c72020-03-10 16:13:48 -0400401 dType := agent.adapterMgr.getDeviceType(device.Type)
402 if dType == nil {
403 return coreutils.DoneResponse(), status.Errorf(codes.FailedPrecondition, "non-existent-device-type-%s", device.Type)
404 }
405
khenaidoo0458db62019-06-20 08:50:36 -0400406 existingFlows := proto.Clone(device.Flows).(*voltha.Flows)
407 existingGroups := proto.Clone(device.FlowGroups).(*ofp.FlowGroups)
408
khenaidoo0458db62019-06-20 08:50:36 -0400409 // Process flows
khenaidoob2121e52019-12-16 17:17:22 -0500410 newFlows, flowsToDelete, updatedAllFlows := flowsToUpdateToDelete(newFlows, existingFlows.Items)
khenaidoo0458db62019-06-20 08:50:36 -0400411
412 // Process groups
khenaidoob2121e52019-12-16 17:17:22 -0500413 newGroups, groupsToDelete, updatedAllGroups := groupsToUpdateToDelete(newGroups, existingGroups.Items)
khenaidoo0458db62019-06-20 08:50:36 -0400414
415 // Sanity check
khenaidoob2121e52019-12-16 17:17:22 -0500416 if (len(updatedAllFlows) | len(flowsToDelete) | len(updatedAllGroups) | len(groupsToDelete)) == 0 {
Girish Kumarf56a4682020-03-20 20:07:46 +0000417 logger.Debugw("nothing-to-update", log.Fields{"device-id": agent.deviceID, "flows": newFlows, "groups": newGroups})
A R Karthick5c28f552019-12-11 22:47:44 -0800418 return coreutils.DoneResponse(), nil
khenaidoo0458db62019-06-20 08:50:36 -0400419 }
420
khenaidoo442e7c72020-03-10 16:13:48 -0400421 // store the changed data
422 device.Flows = &voltha.Flows{Items: updatedAllFlows}
423 device.FlowGroups = &voltha.FlowGroups{Items: updatedAllGroups}
424 if err := agent.updateDeviceWithoutLock(ctx, device); err != nil {
425 return coreutils.DoneResponse(), status.Errorf(codes.Internal, "failure-updating-device-%s", agent.deviceID)
khenaidooe7be1332020-01-24 18:58:33 -0500426 }
khenaidoo0458db62019-06-20 08:50:36 -0400427
khenaidoo442e7c72020-03-10 16:13:48 -0400428 // Send update to adapters
429 subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
430 response := coreutils.NewResponse()
431 if !dType.AcceptsAddRemoveFlowUpdates {
khenaidoob2121e52019-12-16 17:17:22 -0500432 if len(updatedAllGroups) != 0 && reflect.DeepEqual(existingGroups.Items, updatedAllGroups) && len(updatedAllFlows) != 0 && reflect.DeepEqual(existingFlows.Items, updatedAllFlows) {
Girish Kumarf56a4682020-03-20 20:07:46 +0000433 logger.Debugw("nothing-to-update", log.Fields{"device-id": agent.deviceID, "flows": newFlows, "groups": newGroups})
khenaidoo442e7c72020-03-10 16:13:48 -0400434 cancel()
A R Karthick5c28f552019-12-11 22:47:44 -0800435 return coreutils.DoneResponse(), nil
khenaidoo0458db62019-06-20 08:50:36 -0400436 }
khenaidoo442e7c72020-03-10 16:13:48 -0400437 rpcResponse, err := agent.adapterProxy.updateFlowsBulk(subCtx, device, &voltha.Flows{Items: updatedAllFlows}, &voltha.FlowGroups{Items: updatedAllGroups}, flowMetadata)
438 if err != nil {
439 cancel()
440 return coreutils.DoneResponse(), err
441 }
442 go agent.waitForAdapterFlowResponse(subCtx, cancel, rpcResponse, response)
khenaidoo0458db62019-06-20 08:50:36 -0400443 } else {
444 flowChanges := &ofp.FlowChanges{
Matt Jeanneret518b5a42019-10-29 10:30:46 -0400445 ToAdd: &voltha.Flows{Items: newFlows},
khenaidoo0458db62019-06-20 08:50:36 -0400446 ToRemove: &voltha.Flows{Items: flowsToDelete},
447 }
448 groupChanges := &ofp.FlowGroupChanges{
Matt Jeanneret518b5a42019-10-29 10:30:46 -0400449 ToAdd: &voltha.FlowGroups{Items: newGroups},
450 ToRemove: &voltha.FlowGroups{Items: groupsToDelete},
khenaidoo0458db62019-06-20 08:50:36 -0400451 ToUpdate: &voltha.FlowGroups{Items: []*ofp.OfpGroupEntry{}},
452 }
khenaidoo442e7c72020-03-10 16:13:48 -0400453 rpcResponse, err := agent.adapterProxy.updateFlowsIncremental(subCtx, device, flowChanges, groupChanges, flowMetadata)
454 if err != nil {
455 cancel()
456 return coreutils.DoneResponse(), err
457 }
458 go agent.waitForAdapterFlowResponse(subCtx, cancel, rpcResponse, response)
khenaidoo0458db62019-06-20 08:50:36 -0400459 }
A R Karthick5c28f552019-12-11 22:47:44 -0800460 return response, nil
461}
462
463//addFlowsAndGroups adds the "newFlows" and "newGroups" from the existing flows/groups and sends the update to the
464//adapters
npujar467fe752020-01-16 20:17:45 +0530465func (agent *DeviceAgent) addFlowsAndGroups(ctx context.Context, newFlows []*ofp.OfpFlowStats, newGroups []*ofp.OfpGroupEntry, flowMetadata *voltha.FlowMetadata) error {
466 response, err := agent.addFlowsAndGroupsToAdapter(ctx, newFlows, newGroups, flowMetadata)
A R Karthick5c28f552019-12-11 22:47:44 -0800467 if err != nil {
468 return err
469 }
khenaidoo442e7c72020-03-10 16:13:48 -0400470 if errs := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, response); errs != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000471 logger.Warnw("no-adapter-response", log.Fields{"device-id": agent.deviceID, "result": errs})
khenaidoo442e7c72020-03-10 16:13:48 -0400472 return status.Errorf(codes.Aborted, "flow-failure-device-%s", agent.deviceID)
khenaidoo0458db62019-06-20 08:50:36 -0400473 }
khenaidoo0458db62019-06-20 08:50:36 -0400474 return nil
475}
476
npujar467fe752020-01-16 20:17:45 +0530477func (agent *DeviceAgent) deleteFlowsAndGroupsFromAdapter(ctx context.Context, flowsToDel []*ofp.OfpFlowStats, groupsToDel []*ofp.OfpGroupEntry, flowMetadata *voltha.FlowMetadata) (coreutils.Response, error) {
Girish Kumarf56a4682020-03-20 20:07:46 +0000478 logger.Debugw("delete-flows-groups-from-adapter", log.Fields{"device-id": agent.deviceID, "flows": flowsToDel, "groups": groupsToDel})
khenaidoo0458db62019-06-20 08:50:36 -0400479
480 if (len(flowsToDel) | len(groupsToDel)) == 0 {
Girish Kumarf56a4682020-03-20 20:07:46 +0000481 logger.Debugw("nothing-to-update", log.Fields{"device-id": agent.deviceID, "flows": flowsToDel, "groups": groupsToDel})
A R Karthick5c28f552019-12-11 22:47:44 -0800482 return coreutils.DoneResponse(), nil
khenaidoo0458db62019-06-20 08:50:36 -0400483 }
484
khenaidoo442e7c72020-03-10 16:13:48 -0400485 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
486 return coreutils.DoneResponse(), err
487 }
488 defer agent.requestQueue.RequestComplete()
khenaidoo0458db62019-06-20 08:50:36 -0400489
khenaidoo6e55d9e2019-12-12 18:26:26 -0500490 device := agent.getDeviceWithoutLock()
khenaidoo442e7c72020-03-10 16:13:48 -0400491 dType := agent.adapterMgr.getDeviceType(device.Type)
492 if dType == nil {
493 return coreutils.DoneResponse(), status.Errorf(codes.FailedPrecondition, "non-existent-device-type-%s", device.Type)
494 }
khenaidoo0458db62019-06-20 08:50:36 -0400495
496 existingFlows := proto.Clone(device.Flows).(*voltha.Flows)
497 existingGroups := proto.Clone(device.FlowGroups).(*ofp.FlowGroups)
498
499 var flowsToKeep []*ofp.OfpFlowStats
500 var groupsToKeep []*ofp.OfpGroupEntry
501
502 // Process flows
503 for _, flow := range existingFlows.Items {
504 if idx := fu.FindFlows(flowsToDel, flow); idx == -1 {
505 flowsToKeep = append(flowsToKeep, flow)
506 }
507 }
508
509 // Process groups
510 for _, group := range existingGroups.Items {
511 if fu.FindGroup(groupsToDel, group.Desc.GroupId) == -1 { // does not exist now
512 groupsToKeep = append(groupsToKeep, group)
513 }
514 }
515
Girish Kumarf56a4682020-03-20 20:07:46 +0000516 logger.Debugw("deleteFlowsAndGroups",
khenaidoo0458db62019-06-20 08:50:36 -0400517 log.Fields{
khenaidoo442e7c72020-03-10 16:13:48 -0400518 "device-id": agent.deviceID,
519 "flows-to-del": len(flowsToDel),
520 "flows-to-keep": len(flowsToKeep),
521 "groups-to-del": len(groupsToDel),
522 "groups-to-keep": len(groupsToKeep),
khenaidoo0458db62019-06-20 08:50:36 -0400523 })
524
525 // Sanity check
526 if (len(flowsToKeep) | len(flowsToDel) | len(groupsToKeep) | len(groupsToDel)) == 0 {
Girish Kumarf56a4682020-03-20 20:07:46 +0000527 logger.Debugw("nothing-to-update", log.Fields{"device-id": agent.deviceID, "flows-to-del": flowsToDel, "groups-to-del": groupsToDel})
A R Karthick5c28f552019-12-11 22:47:44 -0800528 return coreutils.DoneResponse(), nil
khenaidoo0458db62019-06-20 08:50:36 -0400529 }
530
khenaidoo442e7c72020-03-10 16:13:48 -0400531 // store the changed data
532 device.Flows = &voltha.Flows{Items: flowsToKeep}
533 device.FlowGroups = &voltha.FlowGroups{Items: groupsToKeep}
534 if err := agent.updateDeviceWithoutLock(ctx, device); err != nil {
535 return coreutils.DoneResponse(), status.Errorf(codes.Internal, "failure-updating-%s", agent.deviceID)
khenaidooe7be1332020-01-24 18:58:33 -0500536 }
khenaidoo442e7c72020-03-10 16:13:48 -0400537
538 // Send update to adapters
539 subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
540 response := coreutils.NewResponse()
khenaidoo0458db62019-06-20 08:50:36 -0400541 if !dType.AcceptsAddRemoveFlowUpdates {
542 if len(groupsToKeep) != 0 && reflect.DeepEqual(existingGroups.Items, groupsToKeep) && len(flowsToKeep) != 0 && reflect.DeepEqual(existingFlows.Items, flowsToKeep) {
Girish Kumarf56a4682020-03-20 20:07:46 +0000543 logger.Debugw("nothing-to-update", log.Fields{"deviceId": agent.deviceID, "flowsToDel": flowsToDel, "groupsToDel": groupsToDel})
khenaidoo442e7c72020-03-10 16:13:48 -0400544 cancel()
A R Karthick5c28f552019-12-11 22:47:44 -0800545 return coreutils.DoneResponse(), nil
khenaidoo0458db62019-06-20 08:50:36 -0400546 }
khenaidoo442e7c72020-03-10 16:13:48 -0400547 rpcResponse, err := agent.adapterProxy.updateFlowsBulk(subCtx, device, &voltha.Flows{Items: flowsToKeep}, &voltha.FlowGroups{Items: groupsToKeep}, flowMetadata)
548 if err != nil {
549 cancel()
550 return coreutils.DoneResponse(), err
551 }
552 go agent.waitForAdapterFlowResponse(subCtx, cancel, rpcResponse, response)
khenaidoo0458db62019-06-20 08:50:36 -0400553 } else {
554 flowChanges := &ofp.FlowChanges{
555 ToAdd: &voltha.Flows{Items: []*ofp.OfpFlowStats{}},
556 ToRemove: &voltha.Flows{Items: flowsToDel},
557 }
558 groupChanges := &ofp.FlowGroupChanges{
559 ToAdd: &voltha.FlowGroups{Items: []*ofp.OfpGroupEntry{}},
560 ToRemove: &voltha.FlowGroups{Items: groupsToDel},
561 ToUpdate: &voltha.FlowGroups{Items: []*ofp.OfpGroupEntry{}},
562 }
khenaidoo442e7c72020-03-10 16:13:48 -0400563 rpcResponse, err := agent.adapterProxy.updateFlowsIncremental(subCtx, device, flowChanges, groupChanges, flowMetadata)
564 if err != nil {
565 cancel()
566 return coreutils.DoneResponse(), err
567 }
568 go agent.waitForAdapterFlowResponse(subCtx, cancel, rpcResponse, response)
khenaidoo0458db62019-06-20 08:50:36 -0400569 }
A R Karthick5c28f552019-12-11 22:47:44 -0800570 return response, nil
A R Karthick5c28f552019-12-11 22:47:44 -0800571}
572
573//deleteFlowsAndGroups removes the "flowsToDel" and "groupsToDel" from the existing flows/groups and sends the update to the
574//adapters
npujar467fe752020-01-16 20:17:45 +0530575func (agent *DeviceAgent) deleteFlowsAndGroups(ctx context.Context, flowsToDel []*ofp.OfpFlowStats, groupsToDel []*ofp.OfpGroupEntry, flowMetadata *voltha.FlowMetadata) error {
576 response, err := agent.deleteFlowsAndGroupsFromAdapter(ctx, flowsToDel, groupsToDel, flowMetadata)
A R Karthick5c28f552019-12-11 22:47:44 -0800577 if err != nil {
578 return err
579 }
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500580 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, response); res != nil {
khenaidoo0458db62019-06-20 08:50:36 -0400581 return status.Errorf(codes.Aborted, "errors-%s", res)
582 }
583 return nil
khenaidoo0458db62019-06-20 08:50:36 -0400584}
585
npujar467fe752020-01-16 20:17:45 +0530586func (agent *DeviceAgent) updateFlowsAndGroupsToAdapter(ctx context.Context, updatedFlows []*ofp.OfpFlowStats, updatedGroups []*ofp.OfpGroupEntry, flowMetadata *voltha.FlowMetadata) (coreutils.Response, error) {
Girish Kumarf56a4682020-03-20 20:07:46 +0000587 logger.Debugw("updateFlowsAndGroups", log.Fields{"device-id": agent.deviceID, "flows": updatedFlows, "groups": updatedGroups})
khenaidoo0458db62019-06-20 08:50:36 -0400588
589 if (len(updatedFlows) | len(updatedGroups)) == 0 {
Girish Kumarf56a4682020-03-20 20:07:46 +0000590 logger.Debugw("nothing-to-update", log.Fields{"device-id": agent.deviceID, "flows": updatedFlows, "groups": updatedGroups})
A R Karthick5c28f552019-12-11 22:47:44 -0800591 return coreutils.DoneResponse(), nil
khenaidoo0458db62019-06-20 08:50:36 -0400592 }
593
khenaidoo442e7c72020-03-10 16:13:48 -0400594 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
595 return coreutils.DoneResponse(), err
596 }
597 defer agent.requestQueue.RequestComplete()
khenaidoo6e55d9e2019-12-12 18:26:26 -0500598
599 device := agent.getDeviceWithoutLock()
khenaidoo442e7c72020-03-10 16:13:48 -0400600 if device.OperStatus != voltha.OperStatus_ACTIVE || device.ConnectStatus != voltha.ConnectStatus_REACHABLE || device.AdminState != voltha.AdminState_ENABLED {
601 return coreutils.DoneResponse(), status.Errorf(codes.FailedPrecondition, "invalid device states")
602 }
603 dType := agent.adapterMgr.getDeviceType(device.Type)
604 if dType == nil {
605 return coreutils.DoneResponse(), status.Errorf(codes.FailedPrecondition, "non-existent-device-type-%s", device.Type)
606 }
khenaidoo6e55d9e2019-12-12 18:26:26 -0500607
khenaidoo0458db62019-06-20 08:50:36 -0400608 existingFlows := proto.Clone(device.Flows).(*voltha.Flows)
609 existingGroups := proto.Clone(device.FlowGroups).(*ofp.FlowGroups)
610
611 if len(updatedGroups) != 0 && reflect.DeepEqual(existingGroups.Items, updatedGroups) && len(updatedFlows) != 0 && reflect.DeepEqual(existingFlows.Items, updatedFlows) {
Girish Kumarf56a4682020-03-20 20:07:46 +0000612 logger.Debugw("nothing-to-update", log.Fields{"device-id": agent.deviceID, "flows": updatedFlows, "groups": updatedGroups})
A R Karthick5c28f552019-12-11 22:47:44 -0800613 return coreutils.DoneResponse(), nil
khenaidoo0458db62019-06-20 08:50:36 -0400614 }
615
Girish Kumarf56a4682020-03-20 20:07:46 +0000616 logger.Debugw("updating-flows-and-groups",
khenaidoo0458db62019-06-20 08:50:36 -0400617 log.Fields{
khenaidoo442e7c72020-03-10 16:13:48 -0400618 "device-id": agent.deviceID,
619 "updated-flows": updatedFlows,
620 "updated-groups": updatedGroups,
khenaidoo0458db62019-06-20 08:50:36 -0400621 })
622
khenaidoo442e7c72020-03-10 16:13:48 -0400623 // store the updated data
624 device.Flows = &voltha.Flows{Items: updatedFlows}
625 device.FlowGroups = &voltha.FlowGroups{Items: updatedGroups}
626 if err := agent.updateDeviceWithoutLock(ctx, device); err != nil {
627 return coreutils.DoneResponse(), status.Errorf(codes.Internal, "failure-updating-%s", agent.deviceID)
khenaidooe7be1332020-01-24 18:58:33 -0500628 }
khenaidoo0458db62019-06-20 08:50:36 -0400629
khenaidoo442e7c72020-03-10 16:13:48 -0400630 subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
631 response := coreutils.NewResponse()
khenaidoo0458db62019-06-20 08:50:36 -0400632 // Process bulk flow update differently than incremental update
633 if !dType.AcceptsAddRemoveFlowUpdates {
khenaidoo442e7c72020-03-10 16:13:48 -0400634 rpcResponse, err := agent.adapterProxy.updateFlowsBulk(subCtx, device, &voltha.Flows{Items: updatedFlows}, &voltha.FlowGroups{Items: updatedGroups}, nil)
635 if err != nil {
636 cancel()
637 return coreutils.DoneResponse(), err
638 }
639 go agent.waitForAdapterFlowResponse(subCtx, cancel, rpcResponse, response)
khenaidoo0458db62019-06-20 08:50:36 -0400640 } else {
641 var flowsToAdd []*ofp.OfpFlowStats
khenaidoo2c6a0992019-04-29 13:46:56 -0400642 var flowsToDelete []*ofp.OfpFlowStats
khenaidoo0458db62019-06-20 08:50:36 -0400643 var groupsToAdd []*ofp.OfpGroupEntry
khenaidoo2c6a0992019-04-29 13:46:56 -0400644 var groupsToDelete []*ofp.OfpGroupEntry
khenaidoo2c6a0992019-04-29 13:46:56 -0400645
646 // Process flows
khenaidoo0458db62019-06-20 08:50:36 -0400647 for _, flow := range updatedFlows {
648 if idx := fu.FindFlows(existingFlows.Items, flow); idx == -1 {
649 flowsToAdd = append(flowsToAdd, flow)
650 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400651 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400652 for _, flow := range existingFlows.Items {
khenaidoo0458db62019-06-20 08:50:36 -0400653 if idx := fu.FindFlows(updatedFlows, flow); idx != -1 {
khenaidoo2c6a0992019-04-29 13:46:56 -0400654 flowsToDelete = append(flowsToDelete, flow)
655 }
656 }
657
658 // Process groups
khenaidoo0458db62019-06-20 08:50:36 -0400659 for _, g := range updatedGroups {
660 if fu.FindGroup(existingGroups.Items, g.Desc.GroupId) == -1 { // does not exist now
661 groupsToAdd = append(groupsToAdd, g)
662 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400663 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400664 for _, group := range existingGroups.Items {
khenaidoo0458db62019-06-20 08:50:36 -0400665 if fu.FindGroup(updatedGroups, group.Desc.GroupId) != -1 { // does not exist now
khenaidoo2c6a0992019-04-29 13:46:56 -0400666 groupsToDelete = append(groupsToDelete, group)
667 }
668 }
669
Girish Kumarf56a4682020-03-20 20:07:46 +0000670 logger.Debugw("updating-flows-and-groups",
khenaidoo0458db62019-06-20 08:50:36 -0400671 log.Fields{
khenaidoo442e7c72020-03-10 16:13:48 -0400672 "device-id": agent.deviceID,
673 "flows-to-add": flowsToAdd,
674 "flows-to-delete": flowsToDelete,
675 "groups-to-add": groupsToAdd,
676 "groups-to-delete": groupsToDelete,
khenaidoo0458db62019-06-20 08:50:36 -0400677 })
678
khenaidoo2c6a0992019-04-29 13:46:56 -0400679 // Sanity check
khenaidoo0458db62019-06-20 08:50:36 -0400680 if (len(flowsToAdd) | len(flowsToDelete) | len(groupsToAdd) | len(groupsToDelete) | len(updatedGroups)) == 0 {
Girish Kumarf56a4682020-03-20 20:07:46 +0000681 logger.Debugw("nothing-to-update", log.Fields{"device-id": agent.deviceID, "flows": updatedFlows, "groups": updatedGroups})
khenaidoo442e7c72020-03-10 16:13:48 -0400682 cancel()
A R Karthick5c28f552019-12-11 22:47:44 -0800683 return coreutils.DoneResponse(), nil
khenaidoo2c6a0992019-04-29 13:46:56 -0400684 }
685
khenaidoo0458db62019-06-20 08:50:36 -0400686 flowChanges := &ofp.FlowChanges{
687 ToAdd: &voltha.Flows{Items: flowsToAdd},
688 ToRemove: &voltha.Flows{Items: flowsToDelete},
khenaidoo19d7b632018-10-30 10:49:50 -0400689 }
khenaidoo0458db62019-06-20 08:50:36 -0400690 groupChanges := &ofp.FlowGroupChanges{
691 ToAdd: &voltha.FlowGroups{Items: groupsToAdd},
692 ToRemove: &voltha.FlowGroups{Items: groupsToDelete},
693 ToUpdate: &voltha.FlowGroups{Items: updatedGroups},
694 }
khenaidoo442e7c72020-03-10 16:13:48 -0400695 rpcResponse, err := agent.adapterProxy.updateFlowsIncremental(subCtx, device, flowChanges, groupChanges, flowMetadata)
696 if err != nil {
697 cancel()
698 return coreutils.DoneResponse(), err
699 }
700 go agent.waitForAdapterFlowResponse(subCtx, cancel, rpcResponse, response)
Kent Hagerman3c513972019-11-25 13:49:41 -0500701 }
khenaidoo0458db62019-06-20 08:50:36 -0400702
A R Karthick5c28f552019-12-11 22:47:44 -0800703 return response, nil
704}
705
706//updateFlowsAndGroups replaces the existing flows and groups with "updatedFlows" and "updatedGroups" respectively. It
707//also sends the updates to the adapters
npujar467fe752020-01-16 20:17:45 +0530708func (agent *DeviceAgent) updateFlowsAndGroups(ctx context.Context, updatedFlows []*ofp.OfpFlowStats, updatedGroups []*ofp.OfpGroupEntry, flowMetadata *voltha.FlowMetadata) error {
709 response, err := agent.updateFlowsAndGroupsToAdapter(ctx, updatedFlows, updatedGroups, flowMetadata)
A R Karthick5c28f552019-12-11 22:47:44 -0800710 if err != nil {
711 return err
712 }
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500713 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, response); res != nil {
khenaidoo0458db62019-06-20 08:50:36 -0400714 return status.Errorf(codes.Aborted, "errors-%s", res)
715 }
716 return nil
khenaidoo19d7b632018-10-30 10:49:50 -0400717}
718
Girish Gowdra408cd962020-03-11 14:31:31 -0700719//deleteAllFlows deletes all flows in the device table
720func (agent *DeviceAgent) deleteAllFlows(ctx context.Context) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000721 logger.Debugw("deleteAllFlows", log.Fields{"deviceId": agent.deviceID})
Girish Gowdra408cd962020-03-11 14:31:31 -0700722 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
723 return err
724 }
725 defer agent.requestQueue.RequestComplete()
726
727 device := agent.getDeviceWithoutLock()
728 // purge all flows on the device by setting it to nil
729 device.Flows = &ofp.Flows{Items: nil}
730 if err := agent.updateDeviceWithoutLock(ctx, device); err != nil {
731 // The caller logs the error
732 return err
733 }
734 return nil
735}
736
khenaidoo4d4802d2018-10-04 21:59:49 -0400737//disableDevice disable a device
khenaidoo92e62c52018-10-03 14:02:54 -0400738func (agent *DeviceAgent) disableDevice(ctx context.Context) error {
khenaidoo442e7c72020-03-10 16:13:48 -0400739 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
740 return err
741 }
742 defer agent.requestQueue.RequestComplete()
Girish Kumarf56a4682020-03-20 20:07:46 +0000743 logger.Debugw("disableDevice", log.Fields{"device-id": agent.deviceID})
khenaidoo6e55d9e2019-12-12 18:26:26 -0500744
745 cloned := agent.getDeviceWithoutLock()
746
747 if cloned.AdminState == voltha.AdminState_DISABLED {
Girish Kumarf56a4682020-03-20 20:07:46 +0000748 logger.Debugw("device-already-disabled", log.Fields{"id": agent.deviceID})
npujar1d86a522019-11-14 17:11:16 +0530749 return nil
750 }
khenaidoo6e55d9e2019-12-12 18:26:26 -0500751 if cloned.AdminState == voltha.AdminState_PREPROVISIONED ||
752 cloned.AdminState == voltha.AdminState_DELETED {
khenaidoo6e55d9e2019-12-12 18:26:26 -0500753 return status.Errorf(codes.FailedPrecondition, "deviceId:%s, invalid-admin-state:%s", agent.deviceID, cloned.AdminState)
npujar1d86a522019-11-14 17:11:16 +0530754 }
khenaidoo4554f7c2019-05-29 22:13:15 -0400755
npujar1d86a522019-11-14 17:11:16 +0530756 // Update the Admin State and operational state before sending the request out
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500757 if err := agent.updateDeviceStateInStoreWithoutLock(ctx, cloned, voltha.AdminState_DISABLED, cloned.ConnectStatus, voltha.OperStatus_UNKNOWN); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530758 return err
759 }
khenaidoo442e7c72020-03-10 16:13:48 -0400760
761 subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
762 ch, err := agent.adapterProxy.disableDevice(subCtx, proto.Clone(cloned).(*voltha.Device))
763 if err != nil {
764 cancel()
npujar1d86a522019-11-14 17:11:16 +0530765 return err
khenaidoo0a822f92019-05-08 15:15:57 -0400766 }
khenaidoo442e7c72020-03-10 16:13:48 -0400767 go agent.waitForAdapterResponse(subCtx, cancel, "disableDevice", ch, agent.onSuccess, agent.onFailure)
khenaidoo0a822f92019-05-08 15:15:57 -0400768
khenaidoo92e62c52018-10-03 14:02:54 -0400769 return nil
770}
771
khenaidoo4d4802d2018-10-04 21:59:49 -0400772func (agent *DeviceAgent) rebootDevice(ctx context.Context) error {
khenaidoo442e7c72020-03-10 16:13:48 -0400773 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530774 return err
khenaidoo4d4802d2018-10-04 21:59:49 -0400775 }
khenaidoo442e7c72020-03-10 16:13:48 -0400776 defer agent.requestQueue.RequestComplete()
Girish Kumarf56a4682020-03-20 20:07:46 +0000777 logger.Debugw("rebootDevice", log.Fields{"device-id": agent.deviceID})
khenaidoo442e7c72020-03-10 16:13:48 -0400778
779 device := agent.getDeviceWithoutLock()
780 subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
781 ch, err := agent.adapterProxy.rebootDevice(subCtx, device)
782 if err != nil {
783 cancel()
784 return err
785 }
786 go agent.waitForAdapterResponse(subCtx, cancel, "rebootDevice", ch, agent.onSuccess, agent.onFailure)
khenaidoo4d4802d2018-10-04 21:59:49 -0400787 return nil
788}
789
790func (agent *DeviceAgent) deleteDevice(ctx context.Context) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000791 logger.Debugw("deleteDevice", log.Fields{"device-id": agent.deviceID})
khenaidoo442e7c72020-03-10 16:13:48 -0400792 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
793 return err
794 }
795 defer agent.requestQueue.RequestComplete()
khenaidoo6e55d9e2019-12-12 18:26:26 -0500796
797 cloned := agent.getDeviceWithoutLock()
Chaitrashree G S543df3e2020-02-24 22:36:54 -0500798
khenaidoo442e7c72020-03-10 16:13:48 -0400799 previousState := cloned.AdminState
800
801 // No check is required when deleting a device. Changing the state to DELETE will trigger the removal of this
802 // device by the state machine
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500803 if err := agent.updateDeviceStateInStoreWithoutLock(ctx, cloned, voltha.AdminState_DELETED, cloned.ConnectStatus, cloned.OperStatus); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530804 return err
805 }
khenaidoo442e7c72020-03-10 16:13:48 -0400806
807 // If the device was in pre-prov state (only parent device are in that state) then do not send the request to the
808 // adapter
809 if previousState != ic.AdminState_PREPROVISIONED {
810 subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
811 ch, err := agent.adapterProxy.deleteDevice(subCtx, cloned)
812 if err != nil {
813 cancel()
814 return err
815 }
816 go agent.waitForAdapterResponse(subCtx, cancel, "deleteDevice", ch, agent.onSuccess, agent.onFailure)
817 }
khenaidoo4d4802d2018-10-04 21:59:49 -0400818 return nil
819}
820
npujar467fe752020-01-16 20:17:45 +0530821func (agent *DeviceAgent) setParentID(ctx context.Context, device *voltha.Device, parentID string) error {
khenaidoo442e7c72020-03-10 16:13:48 -0400822 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
823 return err
824 }
825 defer agent.requestQueue.RequestComplete()
826
Girish Kumarf56a4682020-03-20 20:07:46 +0000827 logger.Debugw("setParentId", log.Fields{"device-id": device.Id, "parent-id": parentID})
khenaidoo6e55d9e2019-12-12 18:26:26 -0500828
829 cloned := agent.getDeviceWithoutLock()
npujar1d86a522019-11-14 17:11:16 +0530830 cloned.ParentId = parentID
831 // Store the device
npujar467fe752020-01-16 20:17:45 +0530832 if err := agent.updateDeviceInStoreWithoutLock(ctx, cloned, false, ""); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530833 return err
834 }
khenaidoo442e7c72020-03-10 16:13:48 -0400835
npujar1d86a522019-11-14 17:11:16 +0530836 return nil
khenaidooad06fd72019-10-28 12:26:05 -0400837}
838
khenaidoob3127472019-07-24 21:04:55 -0400839func (agent *DeviceAgent) updatePmConfigs(ctx context.Context, pmConfigs *voltha.PmConfigs) error {
khenaidoo442e7c72020-03-10 16:13:48 -0400840 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
841 return err
842 }
843 defer agent.requestQueue.RequestComplete()
Girish Kumarf56a4682020-03-20 20:07:46 +0000844 logger.Debugw("updatePmConfigs", log.Fields{"device-id": pmConfigs.Id})
khenaidoo6e55d9e2019-12-12 18:26:26 -0500845
846 cloned := agent.getDeviceWithoutLock()
npujar1d86a522019-11-14 17:11:16 +0530847 cloned.PmConfigs = proto.Clone(pmConfigs).(*voltha.PmConfigs)
848 // Store the device
npujar467fe752020-01-16 20:17:45 +0530849 if err := agent.updateDeviceInStoreWithoutLock(ctx, cloned, false, ""); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530850 return err
851 }
852 // Send the request to the adapter
khenaidoo442e7c72020-03-10 16:13:48 -0400853 subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
854 ch, err := agent.adapterProxy.updatePmConfigs(subCtx, cloned, pmConfigs)
855 if err != nil {
856 cancel()
npujar1d86a522019-11-14 17:11:16 +0530857 return err
858 }
khenaidoo442e7c72020-03-10 16:13:48 -0400859 go agent.waitForAdapterResponse(subCtx, cancel, "updatePmConfigs", ch, agent.onSuccess, agent.onFailure)
npujar1d86a522019-11-14 17:11:16 +0530860 return nil
khenaidoob3127472019-07-24 21:04:55 -0400861}
862
npujar467fe752020-01-16 20:17:45 +0530863func (agent *DeviceAgent) initPmConfigs(ctx context.Context, pmConfigs *voltha.PmConfigs) error {
khenaidoo442e7c72020-03-10 16:13:48 -0400864 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
865 return err
866 }
867 defer agent.requestQueue.RequestComplete()
Girish Kumarf56a4682020-03-20 20:07:46 +0000868 logger.Debugw("initPmConfigs", log.Fields{"device-id": pmConfigs.Id})
khenaidoo6e55d9e2019-12-12 18:26:26 -0500869
870 cloned := agent.getDeviceWithoutLock()
npujar1d86a522019-11-14 17:11:16 +0530871 cloned.PmConfigs = proto.Clone(pmConfigs).(*voltha.PmConfigs)
npujar467fe752020-01-16 20:17:45 +0530872 updateCtx := context.WithValue(ctx, model.RequestTimestamp, time.Now().UnixNano())
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500873 return agent.updateDeviceInStoreWithoutLock(updateCtx, cloned, false, "")
khenaidoob3127472019-07-24 21:04:55 -0400874}
875
876func (agent *DeviceAgent) listPmConfigs(ctx context.Context) (*voltha.PmConfigs, error) {
khenaidoo442e7c72020-03-10 16:13:48 -0400877 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
878 return nil, err
879 }
880 defer agent.requestQueue.RequestComplete()
Girish Kumarf56a4682020-03-20 20:07:46 +0000881 logger.Debugw("listPmConfigs", log.Fields{"device-id": agent.deviceID})
khenaidoo6e55d9e2019-12-12 18:26:26 -0500882
883 return agent.getDeviceWithoutLock().PmConfigs, nil
khenaidoob3127472019-07-24 21:04:55 -0400884}
885
khenaidoof5a5bfa2019-01-23 22:20:29 -0500886func (agent *DeviceAgent) downloadImage(ctx context.Context, img *voltha.ImageDownload) (*voltha.OperationResp, error) {
khenaidoo442e7c72020-03-10 16:13:48 -0400887 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
888 return nil, err
889 }
890 defer agent.requestQueue.RequestComplete()
891
Girish Kumarf56a4682020-03-20 20:07:46 +0000892 logger.Debugw("downloadImage", log.Fields{"device-id": agent.deviceID})
khenaidoo6e55d9e2019-12-12 18:26:26 -0500893
894 device := agent.getDeviceWithoutLock()
895
npujar1d86a522019-11-14 17:11:16 +0530896 if device.AdminState != voltha.AdminState_ENABLED {
khenaidoo442e7c72020-03-10 16:13:48 -0400897 return nil, status.Errorf(codes.FailedPrecondition, "device-id:%s, expected-admin-state:%s", agent.deviceID, voltha.AdminState_ENABLED)
npujar1d86a522019-11-14 17:11:16 +0530898 }
899 // Save the image
900 clonedImg := proto.Clone(img).(*voltha.ImageDownload)
901 clonedImg.DownloadState = voltha.ImageDownload_DOWNLOAD_REQUESTED
902 cloned := proto.Clone(device).(*voltha.Device)
903 if cloned.ImageDownloads == nil {
904 cloned.ImageDownloads = []*voltha.ImageDownload{clonedImg}
khenaidoof5a5bfa2019-01-23 22:20:29 -0500905 } else {
906 if device.AdminState != voltha.AdminState_ENABLED {
Girish Kumarf56a4682020-03-20 20:07:46 +0000907 logger.Debugw("device-not-enabled", log.Fields{"id": agent.deviceID})
npujar1d86a522019-11-14 17:11:16 +0530908 return nil, status.Errorf(codes.FailedPrecondition, "deviceId:%s, expected-admin-state:%s", agent.deviceID, voltha.AdminState_ENABLED)
khenaidoof5a5bfa2019-01-23 22:20:29 -0500909 }
910 // Save the image
911 clonedImg := proto.Clone(img).(*voltha.ImageDownload)
Stephane Barbariedf5479f2019-01-29 22:13:00 -0500912 clonedImg.DownloadState = voltha.ImageDownload_DOWNLOAD_REQUESTED
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500913 if device.ImageDownloads == nil {
914 device.ImageDownloads = []*voltha.ImageDownload{clonedImg}
khenaidoof5a5bfa2019-01-23 22:20:29 -0500915 } else {
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500916 device.ImageDownloads = append(device.ImageDownloads, clonedImg)
khenaidoof5a5bfa2019-01-23 22:20:29 -0500917 }
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500918 if err := agent.updateDeviceStateInStoreWithoutLock(ctx, cloned, voltha.AdminState_DOWNLOADING_IMAGE, device.ConnectStatus, device.OperStatus); err != nil {
Mahir Gunyelb5851672019-07-24 10:46:26 +0300919 return nil, err
khenaidoof5a5bfa2019-01-23 22:20:29 -0500920 }
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500921
khenaidoof5a5bfa2019-01-23 22:20:29 -0500922 // Send the request to the adapter
khenaidoo442e7c72020-03-10 16:13:48 -0400923 subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
924 ch, err := agent.adapterProxy.downloadImage(ctx, cloned, clonedImg)
925 if err != nil {
926 cancel()
khenaidoof5a5bfa2019-01-23 22:20:29 -0500927 return nil, err
928 }
khenaidoo442e7c72020-03-10 16:13:48 -0400929 go agent.waitForAdapterResponse(subCtx, cancel, "downloadImage", ch, agent.onSuccess, agent.onFailure)
khenaidoof5a5bfa2019-01-23 22:20:29 -0500930 }
931 return &voltha.OperationResp{Code: voltha.OperationResp_OPERATION_SUCCESS}, nil
932}
933
934// isImageRegistered is a helper method to figure out if an image is already registered
935func isImageRegistered(img *voltha.ImageDownload, device *voltha.Device) bool {
936 for _, image := range device.ImageDownloads {
937 if image.Id == img.Id && image.Name == img.Name {
938 return true
939 }
940 }
941 return false
942}
943
944func (agent *DeviceAgent) cancelImageDownload(ctx context.Context, img *voltha.ImageDownload) (*voltha.OperationResp, error) {
khenaidoo442e7c72020-03-10 16:13:48 -0400945 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
946 return nil, err
947 }
948 defer agent.requestQueue.RequestComplete()
949
Girish Kumarf56a4682020-03-20 20:07:46 +0000950 logger.Debugw("cancelImageDownload", log.Fields{"device-id": agent.deviceID})
khenaidoo6e55d9e2019-12-12 18:26:26 -0500951
952 device := agent.getDeviceWithoutLock()
953
npujar1d86a522019-11-14 17:11:16 +0530954 // Verify whether the Image is in the list of image being downloaded
955 if !isImageRegistered(img, device) {
khenaidoo442e7c72020-03-10 16:13:48 -0400956 return nil, status.Errorf(codes.FailedPrecondition, "device-id:%s, image-not-registered:%s", agent.deviceID, img.Name)
npujar1d86a522019-11-14 17:11:16 +0530957 }
khenaidoof5a5bfa2019-01-23 22:20:29 -0500958
npujar1d86a522019-11-14 17:11:16 +0530959 // Update image download state
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500960 for _, image := range device.ImageDownloads {
npujar1d86a522019-11-14 17:11:16 +0530961 if image.Id == img.Id && image.Name == img.Name {
962 image.DownloadState = voltha.ImageDownload_DOWNLOAD_CANCELLED
khenaidoof5a5bfa2019-01-23 22:20:29 -0500963 }
npujar1d86a522019-11-14 17:11:16 +0530964 }
khenaidoof5a5bfa2019-01-23 22:20:29 -0500965
npujar1d86a522019-11-14 17:11:16 +0530966 if device.AdminState == voltha.AdminState_DOWNLOADING_IMAGE {
967 // Set the device to Enabled
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500968 if err := agent.updateDeviceStateInStoreWithoutLock(ctx, device, voltha.AdminState_ENABLED, device.ConnectStatus, device.OperStatus); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530969 return nil, err
970 }
khenaidoo442e7c72020-03-10 16:13:48 -0400971 subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
972 ch, err := agent.adapterProxy.cancelImageDownload(subCtx, device, img)
973 if err != nil {
974 cancel()
npujar1d86a522019-11-14 17:11:16 +0530975 return nil, err
khenaidoof5a5bfa2019-01-23 22:20:29 -0500976 }
khenaidoo442e7c72020-03-10 16:13:48 -0400977 go agent.waitForAdapterResponse(subCtx, cancel, "cancelImageDownload", ch, agent.onSuccess, agent.onFailure)
khenaidoof5a5bfa2019-01-23 22:20:29 -0500978 }
979 return &voltha.OperationResp{Code: voltha.OperationResp_OPERATION_SUCCESS}, nil
serkant.uluderya334479d2019-04-10 08:26:15 -0700980}
khenaidoof5a5bfa2019-01-23 22:20:29 -0500981
982func (agent *DeviceAgent) activateImage(ctx context.Context, img *voltha.ImageDownload) (*voltha.OperationResp, error) {
khenaidoo442e7c72020-03-10 16:13:48 -0400983 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
984 return nil, err
985 }
986 defer agent.requestQueue.RequestComplete()
Girish Kumarf56a4682020-03-20 20:07:46 +0000987 logger.Debugw("activateImage", log.Fields{"device-id": agent.deviceID})
khenaidoo6e55d9e2019-12-12 18:26:26 -0500988 cloned := agent.getDeviceWithoutLock()
989
npujar1d86a522019-11-14 17:11:16 +0530990 // Verify whether the Image is in the list of image being downloaded
khenaidoo6e55d9e2019-12-12 18:26:26 -0500991 if !isImageRegistered(img, cloned) {
khenaidoo442e7c72020-03-10 16:13:48 -0400992 return nil, status.Errorf(codes.FailedPrecondition, "device-id:%s, image-not-registered:%s", agent.deviceID, img.Name)
npujar1d86a522019-11-14 17:11:16 +0530993 }
994
khenaidoo6e55d9e2019-12-12 18:26:26 -0500995 if cloned.AdminState == voltha.AdminState_DOWNLOADING_IMAGE {
khenaidoo442e7c72020-03-10 16:13:48 -0400996 return nil, status.Errorf(codes.FailedPrecondition, "device-id:%s, device-in-downloading-state:%s", agent.deviceID, img.Name)
npujar1d86a522019-11-14 17:11:16 +0530997 }
998 // Update image download state
npujar1d86a522019-11-14 17:11:16 +0530999 for _, image := range cloned.ImageDownloads {
1000 if image.Id == img.Id && image.Name == img.Name {
1001 image.ImageState = voltha.ImageDownload_IMAGE_ACTIVATING
1002 }
1003 }
1004 // Set the device to downloading_image
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001005 if err := agent.updateDeviceStateInStoreWithoutLock(ctx, cloned, voltha.AdminState_DOWNLOADING_IMAGE, cloned.ConnectStatus, cloned.OperStatus); err != nil {
npujar1d86a522019-11-14 17:11:16 +05301006 return nil, err
1007 }
1008
khenaidoo442e7c72020-03-10 16:13:48 -04001009 subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
1010 ch, err := agent.adapterProxy.activateImageUpdate(subCtx, proto.Clone(cloned).(*voltha.Device), img)
1011 if err != nil {
1012 cancel()
npujar1d86a522019-11-14 17:11:16 +05301013 return nil, err
1014 }
khenaidoo442e7c72020-03-10 16:13:48 -04001015 go agent.waitForAdapterResponse(subCtx, cancel, "activateImageUpdate", ch, agent.onSuccess, agent.onFailure)
1016
npujar1d86a522019-11-14 17:11:16 +05301017 // The status of the AdminState will be changed following the update_download_status response from the adapter
1018 // The image name will also be removed from the device list
serkant.uluderya334479d2019-04-10 08:26:15 -07001019 return &voltha.OperationResp{Code: voltha.OperationResp_OPERATION_SUCCESS}, nil
1020}
khenaidoof5a5bfa2019-01-23 22:20:29 -05001021
1022func (agent *DeviceAgent) revertImage(ctx context.Context, img *voltha.ImageDownload) (*voltha.OperationResp, error) {
khenaidoo442e7c72020-03-10 16:13:48 -04001023 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1024 return nil, err
1025 }
1026 defer agent.requestQueue.RequestComplete()
Girish Kumarf56a4682020-03-20 20:07:46 +00001027 logger.Debugw("revertImage", log.Fields{"device-id": agent.deviceID})
khenaidoo6e55d9e2019-12-12 18:26:26 -05001028
1029 cloned := agent.getDeviceWithoutLock()
1030
npujar1d86a522019-11-14 17:11:16 +05301031 // Verify whether the Image is in the list of image being downloaded
khenaidoo6e55d9e2019-12-12 18:26:26 -05001032 if !isImageRegistered(img, cloned) {
npujar1d86a522019-11-14 17:11:16 +05301033 return nil, status.Errorf(codes.FailedPrecondition, "deviceId:%s, image-not-registered:%s", agent.deviceID, img.Name)
1034 }
khenaidoof5a5bfa2019-01-23 22:20:29 -05001035
khenaidoo6e55d9e2019-12-12 18:26:26 -05001036 if cloned.AdminState != voltha.AdminState_ENABLED {
npujar1d86a522019-11-14 17:11:16 +05301037 return nil, status.Errorf(codes.FailedPrecondition, "deviceId:%s, device-not-enabled-state:%s", agent.deviceID, img.Name)
1038 }
1039 // Update image download state
npujar1d86a522019-11-14 17:11:16 +05301040 for _, image := range cloned.ImageDownloads {
1041 if image.Id == img.Id && image.Name == img.Name {
1042 image.ImageState = voltha.ImageDownload_IMAGE_REVERTING
khenaidoof5a5bfa2019-01-23 22:20:29 -05001043 }
npujar1d86a522019-11-14 17:11:16 +05301044 }
Mahir Gunyelb5851672019-07-24 10:46:26 +03001045
npujar467fe752020-01-16 20:17:45 +05301046 if err := agent.updateDeviceInStoreWithoutLock(ctx, cloned, false, ""); err != nil {
npujar1d86a522019-11-14 17:11:16 +05301047 return nil, err
1048 }
khenaidoof5a5bfa2019-01-23 22:20:29 -05001049
khenaidoo442e7c72020-03-10 16:13:48 -04001050 subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
1051 ch, err := agent.adapterProxy.revertImageUpdate(subCtx, proto.Clone(cloned).(*voltha.Device), img)
1052 if err != nil {
1053 cancel()
npujar1d86a522019-11-14 17:11:16 +05301054 return nil, err
khenaidoof5a5bfa2019-01-23 22:20:29 -05001055 }
khenaidoo442e7c72020-03-10 16:13:48 -04001056 go agent.waitForAdapterResponse(subCtx, cancel, "revertImageUpdate", ch, agent.onSuccess, agent.onFailure)
1057
khenaidoof5a5bfa2019-01-23 22:20:29 -05001058 return &voltha.OperationResp{Code: voltha.OperationResp_OPERATION_SUCCESS}, nil
serkant.uluderya334479d2019-04-10 08:26:15 -07001059}
khenaidoof5a5bfa2019-01-23 22:20:29 -05001060
1061func (agent *DeviceAgent) getImageDownloadStatus(ctx context.Context, img *voltha.ImageDownload) (*voltha.ImageDownload, error) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001062 logger.Debugw("getImageDownloadStatus", log.Fields{"device-id": agent.deviceID})
khenaidoo6e55d9e2019-12-12 18:26:26 -05001063
khenaidoo442e7c72020-03-10 16:13:48 -04001064 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
npujar1d86a522019-11-14 17:11:16 +05301065 return nil, err
1066 }
khenaidoo442e7c72020-03-10 16:13:48 -04001067 device := agent.getDeviceWithoutLock()
1068 ch, err := agent.adapterProxy.getImageDownloadStatus(ctx, device, img)
1069 agent.requestQueue.RequestComplete()
1070 if err != nil {
1071 return nil, err
1072 }
1073 // Wait for the adapter response
1074 rpcResponse, ok := <-ch
1075 if !ok {
1076 return nil, status.Errorf(codes.Aborted, "channel-closed-device-id-%s", agent.deviceID)
1077 }
1078 if rpcResponse.Err != nil {
1079 return nil, rpcResponse.Err
1080 }
1081 // Successful response
1082 imgDownload := &voltha.ImageDownload{}
1083 if err := ptypes.UnmarshalAny(rpcResponse.Reply, imgDownload); err != nil {
1084 return nil, status.Errorf(codes.InvalidArgument, "%s", err.Error())
1085 }
1086 return imgDownload, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001087}
1088
npujar467fe752020-01-16 20:17:45 +05301089func (agent *DeviceAgent) updateImageDownload(ctx context.Context, img *voltha.ImageDownload) error {
khenaidoo442e7c72020-03-10 16:13:48 -04001090 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1091 return err
1092 }
1093 defer agent.requestQueue.RequestComplete()
Girish Kumarf56a4682020-03-20 20:07:46 +00001094 logger.Debugw("updating-image-download", log.Fields{"device-id": agent.deviceID, "img": img})
khenaidoo6e55d9e2019-12-12 18:26:26 -05001095
1096 cloned := agent.getDeviceWithoutLock()
1097
npujar1d86a522019-11-14 17:11:16 +05301098 // Update the image as well as remove it if the download was cancelled
npujar1d86a522019-11-14 17:11:16 +05301099 clonedImages := make([]*voltha.ImageDownload, len(cloned.ImageDownloads))
1100 for _, image := range cloned.ImageDownloads {
1101 if image.Id == img.Id && image.Name == img.Name {
1102 if image.DownloadState != voltha.ImageDownload_DOWNLOAD_CANCELLED {
1103 clonedImages = append(clonedImages, img)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001104 }
1105 }
npujar1d86a522019-11-14 17:11:16 +05301106 }
1107 cloned.ImageDownloads = clonedImages
1108 // Set the Admin state to enabled if required
1109 if (img.DownloadState != voltha.ImageDownload_DOWNLOAD_REQUESTED &&
1110 img.DownloadState != voltha.ImageDownload_DOWNLOAD_STARTED) ||
1111 (img.ImageState != voltha.ImageDownload_IMAGE_ACTIVATING) {
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001112 return agent.updateDeviceStateInStoreWithoutLock(ctx, cloned, voltha.AdminState_ENABLED, cloned.ConnectStatus, cloned.OperStatus)
npujar1d86a522019-11-14 17:11:16 +05301113 }
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001114 return agent.updateDeviceInStoreWithoutLock(ctx, cloned, false, "")
khenaidoof5a5bfa2019-01-23 22:20:29 -05001115}
1116
1117func (agent *DeviceAgent) getImageDownload(ctx context.Context, img *voltha.ImageDownload) (*voltha.ImageDownload, error) {
khenaidoo442e7c72020-03-10 16:13:48 -04001118 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1119 return nil, err
1120 }
1121 defer agent.requestQueue.RequestComplete()
Girish Kumarf56a4682020-03-20 20:07:46 +00001122 logger.Debugw("getImageDownload", log.Fields{"device-id": agent.deviceID})
khenaidoo6e55d9e2019-12-12 18:26:26 -05001123
1124 cloned := agent.getDeviceWithoutLock()
1125 for _, image := range cloned.ImageDownloads {
npujar1d86a522019-11-14 17:11:16 +05301126 if image.Id == img.Id && image.Name == img.Name {
1127 return image, nil
1128 }
1129 }
1130 return nil, status.Errorf(codes.NotFound, "image-not-found:%s", img.Name)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001131}
1132
npujar1d86a522019-11-14 17:11:16 +05301133func (agent *DeviceAgent) listImageDownloads(ctx context.Context, deviceID string) (*voltha.ImageDownloads, error) {
khenaidoo442e7c72020-03-10 16:13:48 -04001134 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1135 return nil, err
1136 }
1137 defer agent.requestQueue.RequestComplete()
Girish Kumarf56a4682020-03-20 20:07:46 +00001138 logger.Debugw("listImageDownloads", log.Fields{"device-id": agent.deviceID})
khenaidoo6e55d9e2019-12-12 18:26:26 -05001139
1140 return &voltha.ImageDownloads{Items: agent.getDeviceWithoutLock().ImageDownloads}, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001141}
1142
khenaidoo4d4802d2018-10-04 21:59:49 -04001143// getPorts retrieves the ports information of the device based on the port type.
khenaidoo92e62c52018-10-03 14:02:54 -04001144func (agent *DeviceAgent) getPorts(ctx context.Context, portType voltha.Port_PortType) *voltha.Ports {
Girish Kumarf56a4682020-03-20 20:07:46 +00001145 logger.Debugw("getPorts", log.Fields{"device-id": agent.deviceID, "port-type": portType})
khenaidoob9203542018-09-17 22:56:37 -04001146 ports := &voltha.Ports{}
npujar467fe752020-01-16 20:17:45 +05301147 if device, _ := agent.deviceMgr.GetDevice(ctx, agent.deviceID); device != nil {
khenaidoob9203542018-09-17 22:56:37 -04001148 for _, port := range device.Ports {
khenaidoo92e62c52018-10-03 14:02:54 -04001149 if port.Type == portType {
khenaidoob9203542018-09-17 22:56:37 -04001150 ports.Items = append(ports.Items, port)
1151 }
1152 }
1153 }
1154 return ports
1155}
1156
khenaidoo442e7c72020-03-10 16:13:48 -04001157// getSwitchCapability retrieves the switch capability of a parent device
khenaidoo79232702018-12-04 11:00:41 -05001158func (agent *DeviceAgent) getSwitchCapability(ctx context.Context) (*ic.SwitchCapability, error) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001159 logger.Debugw("getSwitchCapability", log.Fields{"device-id": agent.deviceID})
khenaidoo442e7c72020-03-10 16:13:48 -04001160
1161 cloned, err := agent.getDevice(ctx)
1162 if err != nil {
khenaidoob9203542018-09-17 22:56:37 -04001163 return nil, err
khenaidoob9203542018-09-17 22:56:37 -04001164 }
khenaidoo442e7c72020-03-10 16:13:48 -04001165 ch, err := agent.adapterProxy.getOfpDeviceInfo(ctx, cloned)
1166 if err != nil {
1167 return nil, err
1168 }
1169
1170 // Wait for adapter response
1171 rpcResponse, ok := <-ch
1172 if !ok {
1173 return nil, status.Errorf(codes.Aborted, "channel-closed")
1174 }
1175 if rpcResponse.Err != nil {
1176 return nil, rpcResponse.Err
1177 }
1178 // Successful response
1179 switchCap := &ic.SwitchCapability{}
1180 if err := ptypes.UnmarshalAny(rpcResponse.Reply, switchCap); err != nil {
npujar1d86a522019-11-14 17:11:16 +05301181 return nil, err
1182 }
1183 return switchCap, nil
khenaidoob9203542018-09-17 22:56:37 -04001184}
1185
khenaidoo442e7c72020-03-10 16:13:48 -04001186// getPortCapability retrieves the port capability of a device
khenaidoo79232702018-12-04 11:00:41 -05001187func (agent *DeviceAgent) getPortCapability(ctx context.Context, portNo uint32) (*ic.PortCapability, error) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001188 logger.Debugw("getPortCapability", log.Fields{"device-id": agent.deviceID})
khenaidoo442e7c72020-03-10 16:13:48 -04001189 device, err := agent.getDevice(ctx)
1190 if err != nil {
khenaidoob9203542018-09-17 22:56:37 -04001191 return nil, err
khenaidoob9203542018-09-17 22:56:37 -04001192 }
khenaidoo442e7c72020-03-10 16:13:48 -04001193 ch, err := agent.adapterProxy.getOfpPortInfo(ctx, device, portNo)
1194 if err != nil {
npujar1d86a522019-11-14 17:11:16 +05301195 return nil, err
1196 }
khenaidoo442e7c72020-03-10 16:13:48 -04001197 // Wait for adapter response
1198 rpcResponse, ok := <-ch
1199 if !ok {
1200 return nil, status.Errorf(codes.Aborted, "channel-closed")
1201 }
1202 if rpcResponse.Err != nil {
1203 return nil, rpcResponse.Err
1204 }
1205 // Successful response
1206 portCap := &ic.PortCapability{}
1207 if err := ptypes.UnmarshalAny(rpcResponse.Reply, portCap); err != nil {
1208 return nil, status.Errorf(codes.InvalidArgument, "%s", err.Error())
1209 }
npujar1d86a522019-11-14 17:11:16 +05301210 return portCap, nil
khenaidoob9203542018-09-17 22:56:37 -04001211}
1212
khenaidoo442e7c72020-03-10 16:13:48 -04001213func (agent *DeviceAgent) onPacketFailure(rpc string, response interface{}, args ...interface{}) {
1214 // packet data is encoded in the args param as the first parameter
1215 var packet []byte
1216 if len(args) >= 1 {
1217 if pkt, ok := args[0].([]byte); ok {
1218 packet = pkt
1219 }
1220 }
1221 var errResp error
1222 if err, ok := response.(error); ok {
1223 errResp = err
1224 }
Girish Kumarf56a4682020-03-20 20:07:46 +00001225 logger.Warnw("packet-out-error", log.Fields{
khenaidoo442e7c72020-03-10 16:13:48 -04001226 "device-id": agent.deviceID,
1227 "error": errResp,
1228 "packet": hex.EncodeToString(packet),
1229 })
1230}
1231
npujar467fe752020-01-16 20:17:45 +05301232func (agent *DeviceAgent) packetOut(ctx context.Context, outPort uint32, packet *ofp.OfpPacketOut) error {
Scott Baker80678602019-11-14 16:57:36 -08001233 // If deviceType=="" then we must have taken ownership of this device.
1234 // Fixes VOL-2226 where a core would take ownership and have stale data
1235 if agent.deviceType == "" {
npujar467fe752020-01-16 20:17:45 +05301236 agent.reconcileWithKVStore(ctx)
Scott Baker80678602019-11-14 16:57:36 -08001237 }
khenaidoofdbad6e2018-11-06 22:26:38 -05001238 // Send packet to adapter
khenaidoo442e7c72020-03-10 16:13:48 -04001239 subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
1240 ch, err := agent.adapterProxy.packetOut(subCtx, agent.deviceType, agent.deviceID, outPort, packet)
1241 if err != nil {
1242 cancel()
1243 return nil
khenaidoofdbad6e2018-11-06 22:26:38 -05001244 }
khenaidoo442e7c72020-03-10 16:13:48 -04001245 go agent.waitForAdapterResponse(subCtx, cancel, "packetOut", ch, agent.onSuccess, agent.onPacketFailure, packet.Data)
khenaidoofdbad6e2018-11-06 22:26:38 -05001246 return nil
1247}
1248
Mahir Gunyel8e2707d2019-07-25 00:36:21 -07001249// updatePartialDeviceData updates a subset of a device that an Adapter can update.
1250// TODO: May need a specific proto to handle only a subset of a device that can be changed by an adapter
1251func (agent *DeviceAgent) mergeDeviceInfoFromAdapter(device *voltha.Device) (*voltha.Device, error) {
khenaidoo6e55d9e2019-12-12 18:26:26 -05001252 cloned := agent.getDeviceWithoutLock()
Mahir Gunyel8e2707d2019-07-25 00:36:21 -07001253 cloned.Root = device.Root
1254 cloned.Vendor = device.Vendor
1255 cloned.Model = device.Model
1256 cloned.SerialNumber = device.SerialNumber
1257 cloned.MacAddress = device.MacAddress
1258 cloned.Vlan = device.Vlan
1259 cloned.Reason = device.Reason
1260 return cloned, nil
1261}
khenaidoo442e7c72020-03-10 16:13:48 -04001262
npujar467fe752020-01-16 20:17:45 +05301263func (agent *DeviceAgent) updateDeviceUsingAdapterData(ctx context.Context, device *voltha.Device) error {
khenaidoo442e7c72020-03-10 16:13:48 -04001264 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1265 return err
1266 }
1267 defer agent.requestQueue.RequestComplete()
Girish Kumarf56a4682020-03-20 20:07:46 +00001268 logger.Debugw("updateDeviceUsingAdapterData", log.Fields{"device-id": device.Id})
khenaidoo442e7c72020-03-10 16:13:48 -04001269
npujar1d86a522019-11-14 17:11:16 +05301270 updatedDevice, err := agent.mergeDeviceInfoFromAdapter(device)
1271 if err != nil {
Mahir Gunyel8e2707d2019-07-25 00:36:21 -07001272 return status.Errorf(codes.Internal, "%s", err.Error())
Mahir Gunyel8e2707d2019-07-25 00:36:21 -07001273 }
npujar1d86a522019-11-14 17:11:16 +05301274 cloned := proto.Clone(updatedDevice).(*voltha.Device)
npujar467fe752020-01-16 20:17:45 +05301275 return agent.updateDeviceInStoreWithoutLock(ctx, cloned, false, "")
khenaidoo43c82122018-11-22 18:38:28 -05001276}
1277
npujar467fe752020-01-16 20:17:45 +05301278func (agent *DeviceAgent) updateDeviceWithoutLock(ctx context.Context, device *voltha.Device) error {
Girish Kumarf56a4682020-03-20 20:07:46 +00001279 logger.Debugw("updateDevice", log.Fields{"deviceId": device.Id})
khenaidoo442e7c72020-03-10 16:13:48 -04001280 //cloned := proto.Clone(device).(*voltha.Device)
1281 cloned := device
npujar467fe752020-01-16 20:17:45 +05301282 return agent.updateDeviceInStoreWithoutLock(ctx, cloned, false, "")
khenaidoob9203542018-09-17 22:56:37 -04001283}
1284
npujar467fe752020-01-16 20:17:45 +05301285func (agent *DeviceAgent) updateDeviceStatus(ctx context.Context, operStatus voltha.OperStatus_Types, connStatus voltha.ConnectStatus_Types) error {
khenaidoo442e7c72020-03-10 16:13:48 -04001286 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1287 return err
1288 }
1289 defer agent.requestQueue.RequestComplete()
khenaidoo6e55d9e2019-12-12 18:26:26 -05001290
1291 cloned := agent.getDeviceWithoutLock()
1292
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001293 newConnStatus, newOperStatus := cloned.ConnectStatus, cloned.OperStatus
npujar1d86a522019-11-14 17:11:16 +05301294 // 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 -08001295 if s, ok := voltha.ConnectStatus_Types_value[connStatus.String()]; ok {
Girish Kumarf56a4682020-03-20 20:07:46 +00001296 logger.Debugw("updateDeviceStatus-conn", log.Fields{"ok": ok, "val": s})
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001297 newConnStatus = connStatus
npujar1d86a522019-11-14 17:11:16 +05301298 }
serkant.uluderya2ae470f2020-01-21 11:13:09 -08001299 if s, ok := voltha.OperStatus_Types_value[operStatus.String()]; ok {
Girish Kumarf56a4682020-03-20 20:07:46 +00001300 logger.Debugw("updateDeviceStatus-oper", log.Fields{"ok": ok, "val": s})
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001301 newOperStatus = operStatus
npujar1d86a522019-11-14 17:11:16 +05301302 }
Girish Kumarf56a4682020-03-20 20:07:46 +00001303 logger.Debugw("updateDeviceStatus", log.Fields{"deviceId": cloned.Id, "operStatus": cloned.OperStatus, "connectStatus": cloned.ConnectStatus})
npujar1d86a522019-11-14 17:11:16 +05301304 // Store the device
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001305 return agent.updateDeviceStateInStoreWithoutLock(ctx, cloned, cloned.AdminState, newConnStatus, newOperStatus)
khenaidoo92e62c52018-10-03 14:02:54 -04001306}
1307
kesavandbc2d1622020-01-21 00:42:01 -05001308func (agent *DeviceAgent) updatePortsOperState(ctx context.Context, operStatus voltha.OperStatus_Types) error {
Girish Kumarf56a4682020-03-20 20:07:46 +00001309 logger.Debugw("updatePortsOperState", log.Fields{"device-id": agent.deviceID})
khenaidoo442e7c72020-03-10 16:13:48 -04001310 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1311 return err
1312 }
1313 defer agent.requestQueue.RequestComplete()
khenaidoo6e55d9e2019-12-12 18:26:26 -05001314 cloned := agent.getDeviceWithoutLock()
npujar1d86a522019-11-14 17:11:16 +05301315 for _, port := range cloned.Ports {
kesavandbc2d1622020-01-21 00:42:01 -05001316 port.OperStatus = operStatus
npujar1d86a522019-11-14 17:11:16 +05301317 }
1318 // Store the device
npujar467fe752020-01-16 20:17:45 +05301319 return agent.updateDeviceInStoreWithoutLock(ctx, cloned, false, "")
khenaidoo3ab34882019-05-02 21:33:30 -04001320}
1321
npujar467fe752020-01-16 20:17:45 +05301322func (agent *DeviceAgent) updatePortState(ctx context.Context, portType voltha.Port_PortType, portNo uint32, operStatus voltha.OperStatus_Types) error {
khenaidoo442e7c72020-03-10 16:13:48 -04001323 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1324 return err
1325 }
1326 defer agent.requestQueue.RequestComplete()
khenaidoo92e62c52018-10-03 14:02:54 -04001327 // Work only on latest data
1328 // TODO: Get list of ports from device directly instead of the entire device
khenaidoo6e55d9e2019-12-12 18:26:26 -05001329 cloned := agent.getDeviceWithoutLock()
1330
npujar1d86a522019-11-14 17:11:16 +05301331 // Ensure the enums passed in are valid - they will be invalid if they are not set when this function is invoked
1332 if _, ok := voltha.Port_PortType_value[portType.String()]; !ok {
1333 return status.Errorf(codes.InvalidArgument, "%s", portType)
1334 }
1335 for _, port := range cloned.Ports {
1336 if port.Type == portType && port.PortNo == portNo {
1337 port.OperStatus = operStatus
npujar1d86a522019-11-14 17:11:16 +05301338 }
1339 }
Girish Kumarf56a4682020-03-20 20:07:46 +00001340 logger.Debugw("portStatusUpdate", log.Fields{"deviceId": cloned.Id})
npujar1d86a522019-11-14 17:11:16 +05301341 // Store the device
npujar467fe752020-01-16 20:17:45 +05301342 return agent.updateDeviceInStoreWithoutLock(ctx, cloned, false, "")
khenaidoob9203542018-09-17 22:56:37 -04001343}
1344
npujar467fe752020-01-16 20:17:45 +05301345func (agent *DeviceAgent) deleteAllPorts(ctx context.Context) error {
Girish Kumarf56a4682020-03-20 20:07:46 +00001346 logger.Debugw("deleteAllPorts", log.Fields{"deviceId": agent.deviceID})
khenaidoo442e7c72020-03-10 16:13:48 -04001347 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1348 return err
1349 }
1350 defer agent.requestQueue.RequestComplete()
khenaidoo6e55d9e2019-12-12 18:26:26 -05001351
1352 cloned := agent.getDeviceWithoutLock()
1353
1354 if cloned.AdminState != voltha.AdminState_DISABLED && cloned.AdminState != voltha.AdminState_DELETED {
1355 err := status.Error(codes.FailedPrecondition, fmt.Sprintf("invalid-state-%v", cloned.AdminState))
Girish Kumarf56a4682020-03-20 20:07:46 +00001356 logger.Warnw("invalid-state-removing-ports", log.Fields{"state": cloned.AdminState, "error": err})
npujar1d86a522019-11-14 17:11:16 +05301357 return err
1358 }
khenaidoo6e55d9e2019-12-12 18:26:26 -05001359 if len(cloned.Ports) == 0 {
Girish Kumarf56a4682020-03-20 20:07:46 +00001360 logger.Debugw("no-ports-present", log.Fields{"deviceId": agent.deviceID})
npujar1d86a522019-11-14 17:11:16 +05301361 return nil
1362 }
khenaidoo6e55d9e2019-12-12 18:26:26 -05001363
npujar1d86a522019-11-14 17:11:16 +05301364 cloned.Ports = []*voltha.Port{}
Girish Kumarf56a4682020-03-20 20:07:46 +00001365 logger.Debugw("portStatusUpdate", log.Fields{"deviceId": cloned.Id})
npujar1d86a522019-11-14 17:11:16 +05301366 // Store the device
npujar467fe752020-01-16 20:17:45 +05301367 return agent.updateDeviceInStoreWithoutLock(ctx, cloned, false, "")
khenaidoo0a822f92019-05-08 15:15:57 -04001368}
1369
npujar467fe752020-01-16 20:17:45 +05301370func (agent *DeviceAgent) addPort(ctx context.Context, port *voltha.Port) error {
khenaidoo442e7c72020-03-10 16:13:48 -04001371 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1372 return err
1373 }
1374 defer agent.requestQueue.RequestComplete()
Girish Kumarf56a4682020-03-20 20:07:46 +00001375 logger.Debugw("addPort", log.Fields{"deviceId": agent.deviceID})
khenaidoo6e55d9e2019-12-12 18:26:26 -05001376
1377 cloned := agent.getDeviceWithoutLock()
khenaidoo80b987d2020-02-20 10:52:52 -05001378 updatePort := false
npujar1d86a522019-11-14 17:11:16 +05301379 if cloned.Ports == nil {
1380 // First port
Girish Kumarf56a4682020-03-20 20:07:46 +00001381 logger.Debugw("addPort-first-port-to-add", log.Fields{"deviceId": agent.deviceID})
npujar1d86a522019-11-14 17:11:16 +05301382 cloned.Ports = make([]*voltha.Port, 0)
khenaidoob9203542018-09-17 22:56:37 -04001383 } else {
npujar1d86a522019-11-14 17:11:16 +05301384 for _, p := range cloned.Ports {
1385 if p.Type == port.Type && p.PortNo == port.PortNo {
khenaidoo80b987d2020-02-20 10:52:52 -05001386 if p.Label == "" && p.Type == voltha.Port_PON_OLT {
1387 //Creation of OLT PON port is being processed after a default PON port was created. Just update it.
Girish Kumarf56a4682020-03-20 20:07:46 +00001388 logger.Infow("update-pon-port-created-by-default", log.Fields{"default-port": p, "port-to-add": port})
khenaidoo80b987d2020-02-20 10:52:52 -05001389 p.Label = port.Label
1390 p.OperStatus = port.OperStatus
1391 updatePort = true
1392 break
1393 }
Girish Kumarf56a4682020-03-20 20:07:46 +00001394 logger.Debugw("port already exists", log.Fields{"port": port})
npujar1d86a522019-11-14 17:11:16 +05301395 return nil
manikkaraj k259a6f72019-05-06 09:55:44 -04001396 }
khenaidoob9203542018-09-17 22:56:37 -04001397 }
khenaidoo92e62c52018-10-03 14:02:54 -04001398 }
khenaidoo80b987d2020-02-20 10:52:52 -05001399 if !updatePort {
1400 cp := proto.Clone(port).(*voltha.Port)
1401 // Set the admin state of the port to ENABLE
1402 cp.AdminState = voltha.AdminState_ENABLED
1403 cloned.Ports = append(cloned.Ports, cp)
1404 }
npujar1d86a522019-11-14 17:11:16 +05301405 // Store the device
npujar467fe752020-01-16 20:17:45 +05301406 return agent.updateDeviceInStoreWithoutLock(ctx, cloned, false, "")
khenaidoo92e62c52018-10-03 14:02:54 -04001407}
1408
khenaidoo80b987d2020-02-20 10:52:52 -05001409func (agent *DeviceAgent) addPeerPort(ctx context.Context, peerPort *voltha.Port_PeerPort) error {
khenaidoo442e7c72020-03-10 16:13:48 -04001410 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1411 return err
1412 }
1413 defer agent.requestQueue.RequestComplete()
Girish Kumarf56a4682020-03-20 20:07:46 +00001414 logger.Debugw("adding-peer-peerPort", log.Fields{"device-id": agent.deviceID, "peer-peerPort": peerPort})
khenaidoo6e55d9e2019-12-12 18:26:26 -05001415
1416 cloned := agent.getDeviceWithoutLock()
1417
khenaidoo80b987d2020-02-20 10:52:52 -05001418 // Get the peer port on the device based on the peerPort no
1419 found := false
1420 for _, port := range cloned.Ports {
1421 if port.PortNo == peerPort.PortNo { // found peerPort
1422 cp := proto.Clone(peerPort).(*voltha.Port_PeerPort)
1423 port.Peers = append(port.Peers, cp)
Girish Kumarf56a4682020-03-20 20:07:46 +00001424 logger.Debugw("found-peer", log.Fields{"device-id": agent.deviceID, "portNo": peerPort.PortNo, "deviceId": agent.deviceID})
khenaidoo80b987d2020-02-20 10:52:52 -05001425 found = true
npujar1d86a522019-11-14 17:11:16 +05301426 break
1427 }
1428 }
khenaidoo80b987d2020-02-20 10:52:52 -05001429 if !found && agent.isRootdevice {
1430 // An ONU PON port has been created before the corresponding creation of the OLT PON port. Create the OLT PON port
1431 // with default values which will be updated once the OLT PON port creation is processed.
1432 ponPort := &voltha.Port{
1433 PortNo: peerPort.PortNo,
1434 Type: voltha.Port_PON_OLT,
1435 AdminState: voltha.AdminState_ENABLED,
1436 DeviceId: agent.deviceID,
1437 Peers: []*voltha.Port_PeerPort{proto.Clone(peerPort).(*voltha.Port_PeerPort)},
1438 }
1439 cloned.Ports = append(cloned.Ports, ponPort)
Girish Kumarf56a4682020-03-20 20:07:46 +00001440 logger.Infow("adding-default-pon-port", log.Fields{"device-id": agent.deviceID, "peer": peerPort, "pon-port": ponPort})
khenaidoo80b987d2020-02-20 10:52:52 -05001441 }
npujar1d86a522019-11-14 17:11:16 +05301442 // Store the device
npujar467fe752020-01-16 20:17:45 +05301443 return agent.updateDeviceInStoreWithoutLock(ctx, cloned, false, "")
khenaidoob9203542018-09-17 22:56:37 -04001444}
1445
1446// TODO: A generic device update by attribute
npujar467fe752020-01-16 20:17:45 +05301447func (agent *DeviceAgent) updateDeviceAttribute(ctx context.Context, name string, value interface{}) {
khenaidoo442e7c72020-03-10 16:13:48 -04001448 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001449 logger.Warnw("request-aborted", log.Fields{"device-id": agent.deviceID, "name": name, "error": err})
khenaidoo442e7c72020-03-10 16:13:48 -04001450 return
1451 }
1452 defer agent.requestQueue.RequestComplete()
khenaidoob9203542018-09-17 22:56:37 -04001453 if value == nil {
1454 return
1455 }
khenaidoo6e55d9e2019-12-12 18:26:26 -05001456
1457 cloned := agent.getDeviceWithoutLock()
khenaidoob9203542018-09-17 22:56:37 -04001458 updated := false
khenaidoo6e55d9e2019-12-12 18:26:26 -05001459 s := reflect.ValueOf(cloned).Elem()
khenaidoob9203542018-09-17 22:56:37 -04001460 if s.Kind() == reflect.Struct {
1461 // exported field
1462 f := s.FieldByName(name)
1463 if f.IsValid() && f.CanSet() {
1464 switch f.Kind() {
1465 case reflect.String:
1466 f.SetString(value.(string))
1467 updated = true
1468 case reflect.Uint32:
1469 f.SetUint(uint64(value.(uint32)))
1470 updated = true
1471 case reflect.Bool:
1472 f.SetBool(value.(bool))
1473 updated = true
1474 }
1475 }
1476 }
Girish Kumarf56a4682020-03-20 20:07:46 +00001477 logger.Debugw("update-field-status", log.Fields{"deviceId": cloned.Id, "name": name, "updated": updated})
khenaidoob9203542018-09-17 22:56:37 -04001478 // Save the data
khenaidoo6e55d9e2019-12-12 18:26:26 -05001479
npujar467fe752020-01-16 20:17:45 +05301480 if err := agent.updateDeviceInStoreWithoutLock(ctx, cloned, false, ""); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001481 logger.Warnw("attribute-update-failed", log.Fields{"attribute": name, "value": value})
khenaidoob9203542018-09-17 22:56:37 -04001482 }
khenaidoob9203542018-09-17 22:56:37 -04001483}
serkant.uluderya334479d2019-04-10 08:26:15 -07001484
1485func (agent *DeviceAgent) simulateAlarm(ctx context.Context, simulatereq *voltha.SimulateAlarmRequest) error {
khenaidoo442e7c72020-03-10 16:13:48 -04001486 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1487 return err
1488 }
1489 defer agent.requestQueue.RequestComplete()
Girish Kumarf56a4682020-03-20 20:07:46 +00001490 logger.Debugw("simulateAlarm", log.Fields{"id": agent.deviceID})
khenaidoo6e55d9e2019-12-12 18:26:26 -05001491
1492 cloned := agent.getDeviceWithoutLock()
1493
khenaidoo442e7c72020-03-10 16:13:48 -04001494 subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
1495 ch, err := agent.adapterProxy.simulateAlarm(subCtx, cloned, simulatereq)
1496 if err != nil {
1497 cancel()
npujar1d86a522019-11-14 17:11:16 +05301498 return err
serkant.uluderya334479d2019-04-10 08:26:15 -07001499 }
khenaidoo442e7c72020-03-10 16:13:48 -04001500 go agent.waitForAdapterResponse(subCtx, cancel, "simulateAlarm", ch, agent.onSuccess, agent.onFailure)
serkant.uluderya334479d2019-04-10 08:26:15 -07001501 return nil
1502}
Mahir Gunyelb5851672019-07-24 10:46:26 +03001503
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001504func (agent *DeviceAgent) updateDeviceStateInStoreWithoutLock(
1505 ctx context.Context,
1506 device *voltha.Device,
1507 adminState voltha.AdminState_Types,
1508 connectStatus voltha.ConnectStatus_Types,
1509 operStatus voltha.OperStatus_Types,
1510) error {
1511 previousState := getDeviceStates(device)
1512 device.AdminState, device.ConnectStatus, device.OperStatus = adminState, connectStatus, operStatus
1513
1514 if err := agent.updateDeviceInStoreWithoutLock(ctx, device, false, ""); err != nil {
1515 return err
1516 }
1517
1518 // process state transition in its own thread
1519 go func() {
1520 if err := agent.deviceMgr.processTransition(context.Background(), device, previousState); err != nil {
1521 log.Errorw("failed-process-transition", log.Fields{"deviceId": device.Id, "previousAdminState": previousState.Admin, "currentAdminState": device.AdminState})
1522 }
1523 }()
1524 return nil
1525}
1526
Mahir Gunyelb5851672019-07-24 10:46:26 +03001527//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.
1528// It is an internal helper function.
npujar467fe752020-01-16 20:17:45 +05301529func (agent *DeviceAgent) updateDeviceInStoreWithoutLock(ctx context.Context, device *voltha.Device, strict bool, txid string) error {
1530 updateCtx := context.WithValue(ctx, model.RequestTimestamp, time.Now().UnixNano())
Thomas Lee Se5a44012019-11-07 20:32:24 +05301531 afterUpdate, err := agent.clusterDataProxy.Update(updateCtx, "/devices/"+agent.deviceID, device, strict, txid)
1532 if err != nil {
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001533 return status.Errorf(codes.Internal, "failed-update-device:%s: %s", agent.deviceID, err)
Thomas Lee Se5a44012019-11-07 20:32:24 +05301534 }
1535 if afterUpdate == nil {
npujar1d86a522019-11-14 17:11:16 +05301536 return status.Errorf(codes.Internal, "failed-update-device:%s", agent.deviceID)
Mahir Gunyelb5851672019-07-24 10:46:26 +03001537 }
Girish Kumarf56a4682020-03-20 20:07:46 +00001538 logger.Debugw("updated-device-in-store", log.Fields{"deviceId: ": agent.deviceID})
Mahir Gunyelb5851672019-07-24 10:46:26 +03001539
khenaidoo6e55d9e2019-12-12 18:26:26 -05001540 agent.device = proto.Clone(device).(*voltha.Device)
Mahir Gunyelb5851672019-07-24 10:46:26 +03001541 return nil
1542}
Mahir Gunyelfdee9212019-10-16 16:52:21 -07001543
npujar467fe752020-01-16 20:17:45 +05301544func (agent *DeviceAgent) updateDeviceReason(ctx context.Context, reason string) error {
khenaidoo442e7c72020-03-10 16:13:48 -04001545 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1546 return err
1547 }
1548 defer agent.requestQueue.RequestComplete()
khenaidoo6e55d9e2019-12-12 18:26:26 -05001549
1550 cloned := agent.getDeviceWithoutLock()
npujar1d86a522019-11-14 17:11:16 +05301551 cloned.Reason = reason
Girish Kumarf56a4682020-03-20 20:07:46 +00001552 logger.Debugw("updateDeviceReason", log.Fields{"deviceId": cloned.Id, "reason": cloned.Reason})
npujar1d86a522019-11-14 17:11:16 +05301553 // Store the device
npujar467fe752020-01-16 20:17:45 +05301554 return agent.updateDeviceInStoreWithoutLock(ctx, cloned, false, "")
Mahir Gunyelfdee9212019-10-16 16:52:21 -07001555}
kesavandbc2d1622020-01-21 00:42:01 -05001556
1557func (agent *DeviceAgent) disablePort(ctx context.Context, Port *voltha.Port) error {
khenaidoo442e7c72020-03-10 16:13:48 -04001558 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1559 return err
1560 }
1561 defer agent.requestQueue.RequestComplete()
Girish Kumarf56a4682020-03-20 20:07:46 +00001562 logger.Debugw("disablePort", log.Fields{"device-id": agent.deviceID, "port-no": Port.PortNo})
khenaidoo442e7c72020-03-10 16:13:48 -04001563 var cp *voltha.Port
kesavandbc2d1622020-01-21 00:42:01 -05001564 // Get the most up to date the device info
1565 device := agent.getDeviceWithoutLock()
1566 for _, port := range device.Ports {
1567 if port.PortNo == Port.PortNo {
1568 port.AdminState = voltha.AdminState_DISABLED
1569 cp = proto.Clone(port).(*voltha.Port)
1570 break
1571
1572 }
1573 }
1574 if cp == nil {
1575 return status.Errorf(codes.InvalidArgument, "%v", Port.PortNo)
1576 }
1577
1578 if cp.Type != voltha.Port_PON_OLT {
1579 return status.Errorf(codes.InvalidArgument, "Disabling of Port Type %v unimplemented", cp.Type)
1580 }
1581 // Store the device
1582 if err := agent.updateDeviceInStoreWithoutLock(ctx, device, false, ""); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001583 logger.Debugw("updateDeviceInStoreWithoutLock error ", log.Fields{"device-id": agent.deviceID, "port-no": Port.PortNo, "error": err})
kesavandbc2d1622020-01-21 00:42:01 -05001584 return err
1585 }
khenaidoo442e7c72020-03-10 16:13:48 -04001586
kesavandbc2d1622020-01-21 00:42:01 -05001587 //send request to adapter
khenaidoo442e7c72020-03-10 16:13:48 -04001588 subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
1589 ch, err := agent.adapterProxy.disablePort(ctx, device, cp)
1590 if err != nil {
1591 cancel()
kesavandbc2d1622020-01-21 00:42:01 -05001592 return err
1593 }
khenaidoo442e7c72020-03-10 16:13:48 -04001594 go agent.waitForAdapterResponse(subCtx, cancel, "disablePort", ch, agent.onSuccess, agent.onFailure)
kesavandbc2d1622020-01-21 00:42:01 -05001595 return nil
1596}
1597
1598func (agent *DeviceAgent) enablePort(ctx context.Context, Port *voltha.Port) error {
khenaidoo442e7c72020-03-10 16:13:48 -04001599 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1600 return err
1601 }
1602 defer agent.requestQueue.RequestComplete()
Girish Kumarf56a4682020-03-20 20:07:46 +00001603 logger.Debugw("enablePort", log.Fields{"device-id": agent.deviceID, "port-no": Port.PortNo})
khenaidoo442e7c72020-03-10 16:13:48 -04001604
1605 var cp *voltha.Port
kesavandbc2d1622020-01-21 00:42:01 -05001606 // Get the most up to date the device info
1607 device := agent.getDeviceWithoutLock()
1608 for _, port := range device.Ports {
1609 if port.PortNo == Port.PortNo {
1610 port.AdminState = voltha.AdminState_ENABLED
1611 cp = proto.Clone(port).(*voltha.Port)
1612 break
1613 }
1614 }
1615
1616 if cp == nil {
1617 return status.Errorf(codes.InvalidArgument, "%v", Port.PortNo)
1618 }
1619
1620 if cp.Type != voltha.Port_PON_OLT {
1621 return status.Errorf(codes.InvalidArgument, "Enabling of Port Type %v unimplemented", cp.Type)
1622 }
1623 // Store the device
1624 if err := agent.updateDeviceInStoreWithoutLock(ctx, device, false, ""); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001625 logger.Debugw("updateDeviceInStoreWithoutLock error ", log.Fields{"device-id": agent.deviceID, "port-no": Port.PortNo, "error": err})
kesavandbc2d1622020-01-21 00:42:01 -05001626 return err
1627 }
1628 //send request to adapter
khenaidoo442e7c72020-03-10 16:13:48 -04001629 subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
1630 ch, err := agent.adapterProxy.enablePort(ctx, device, cp)
1631 if err != nil {
1632 cancel()
kesavandbc2d1622020-01-21 00:42:01 -05001633 return err
1634 }
khenaidoo442e7c72020-03-10 16:13:48 -04001635 go agent.waitForAdapterResponse(subCtx, cancel, "enablePort", ch, agent.onSuccess, agent.onFailure)
kesavandbc2d1622020-01-21 00:42:01 -05001636 return nil
1637}
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001638
1639func (agent *DeviceAgent) ChildDeviceLost(ctx context.Context, device *voltha.Device) error {
khenaidoo442e7c72020-03-10 16:13:48 -04001640 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1641 return err
1642 }
1643 defer agent.requestQueue.RequestComplete()
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001644
Girish Kumarf56a4682020-03-20 20:07:46 +00001645 logger.Debugw("childDeviceLost", log.Fields{"child-device-id": device.Id, "parent-device-ud": agent.deviceID})
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001646
1647 //Remove the associated peer ports on the parent device
khenaidoo442e7c72020-03-10 16:13:48 -04001648 parentDevice := agent.getDeviceWithoutLock()
1649 var updatedPeers []*voltha.Port_PeerPort
1650 for _, port := range parentDevice.Ports {
1651 updatedPeers = make([]*voltha.Port_PeerPort, 0)
1652 for _, peerPort := range port.Peers {
1653 if peerPort.DeviceId != device.Id {
1654 updatedPeers = append(updatedPeers, peerPort)
1655 }
1656 }
1657 port.Peers = updatedPeers
1658 }
1659 if err := agent.updateDeviceInStoreWithoutLock(ctx, parentDevice, false, ""); err != nil {
1660 return err
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001661 }
1662
khenaidoo442e7c72020-03-10 16:13:48 -04001663 //send request to adapter
1664 subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
1665 ch, err := agent.adapterProxy.childDeviceLost(ctx, agent.deviceType, agent.deviceID, device.ParentPortNo, device.ProxyAddress.OnuId)
1666 if err != nil {
1667 cancel()
1668 return err
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001669 }
khenaidoo442e7c72020-03-10 16:13:48 -04001670 go agent.waitForAdapterResponse(subCtx, cancel, "childDeviceLost", ch, agent.onSuccess, agent.onFailure)
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001671 return nil
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001672}
onkarkundargi87285252020-01-27 11:34:52 +05301673
1674func (agent *DeviceAgent) startOmciTest(ctx context.Context, omcitestrequest *voltha.OmciTestRequest) (*voltha.TestResponse, error) {
1675 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1676 return nil, err
1677 }
1678
1679 device := agent.getDeviceWithoutLock()
1680 adapterName, err := agent.adapterMgr.getAdapterName(device.Type)
1681 if err != nil {
1682 agent.requestQueue.RequestComplete()
1683 return nil, err
1684 }
1685
1686 // Send request to the adapter
1687 device.Adapter = adapterName
1688 ch, err := agent.adapterProxy.startOmciTest(ctx, device, omcitestrequest)
1689 agent.requestQueue.RequestComplete()
1690 if err != nil {
1691 return nil, err
1692 }
1693
1694 // Wait for the adapter response
1695 rpcResponse, ok := <-ch
1696 if !ok {
1697 return nil, status.Errorf(codes.Aborted, "channel-closed-device-id-%s", agent.deviceID)
1698 }
1699 if rpcResponse.Err != nil {
1700 return nil, rpcResponse.Err
1701 }
1702
1703 // Unmarshal and return the response
1704 testResp := &voltha.TestResponse{}
1705 if err := ptypes.UnmarshalAny(rpcResponse.Reply, testResp); err != nil {
1706 return nil, status.Errorf(codes.InvalidArgument, "%s", err.Error())
1707 }
Girish Kumarf56a4682020-03-20 20:07:46 +00001708 logger.Debugw("Omci_test_Request-Success-device-agent", log.Fields{"testResp": testResp})
onkarkundargi87285252020-01-27 11:34:52 +05301709 return testResp, nil
1710}