blob: 69391fb0ecae98ec20b84e998b65acaafbf20efe [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"
Kent Hagerman4f355f52020-03-30 16:01:33 -040022 "errors"
khenaidoo3ab34882019-05-02 21:33:30 -040023 "fmt"
khenaidoo442e7c72020-03-10 16:13:48 -040024 "github.com/golang/protobuf/ptypes"
25 "github.com/opencord/voltha-lib-go/v3/pkg/kafka"
Chaitrashree G Sa773e992019-09-09 21:04:15 -040026 "reflect"
27 "sync"
28 "time"
29
khenaidoob9203542018-09-17 22:56:37 -040030 "github.com/gogo/protobuf/proto"
sbarbari17d7e222019-11-05 10:02:29 -050031 "github.com/opencord/voltha-go/db/model"
Scott Bakerb671a862019-10-24 10:53:40 -070032 coreutils "github.com/opencord/voltha-go/rw_core/utils"
serkant.uluderya2ae470f2020-01-21 11:13:09 -080033 fu "github.com/opencord/voltha-lib-go/v3/pkg/flows"
34 "github.com/opencord/voltha-lib-go/v3/pkg/log"
35 ic "github.com/opencord/voltha-protos/v3/go/inter_container"
36 ofp "github.com/opencord/voltha-protos/v3/go/openflow_13"
37 "github.com/opencord/voltha-protos/v3/go/voltha"
khenaidoob9203542018-09-17 22:56:37 -040038 "google.golang.org/grpc/codes"
39 "google.golang.org/grpc/status"
khenaidoob9203542018-09-17 22:56:37 -040040)
41
npujar1d86a522019-11-14 17:11:16 +053042// DeviceAgent represents device agent attributes
khenaidoob9203542018-09-17 22:56:37 -040043type DeviceAgent struct {
npujar1d86a522019-11-14 17:11:16 +053044 deviceID string
45 parentID string
khenaidoo43c82122018-11-22 18:38:28 -050046 deviceType string
khenaidoo2c6a0992019-04-29 13:46:56 -040047 isRootdevice bool
khenaidoo9a468962018-09-19 15:33:13 -040048 adapterProxy *AdapterProxy
serkant.uluderya334479d2019-04-10 08:26:15 -070049 adapterMgr *AdapterManager
khenaidoo9a468962018-09-19 15:33:13 -040050 deviceMgr *DeviceManager
51 clusterDataProxy *model.Proxy
52 exitChannel chan int
khenaidoo6e55d9e2019-12-12 18:26:26 -050053 device *voltha.Device
khenaidoo442e7c72020-03-10 16:13:48 -040054 requestQueue *coreutils.RequestQueue
55 defaultTimeout time.Duration
56 startOnce sync.Once
57 stopOnce sync.Once
58 stopped bool
khenaidoob9203542018-09-17 22:56:37 -040059}
60
Scott Baker80678602019-11-14 16:57:36 -080061//newDeviceAgent creates a new device agent. The device will be initialized when start() is called.
khenaidoo442e7c72020-03-10 16:13:48 -040062func newDeviceAgent(ap *AdapterProxy, device *voltha.Device, deviceMgr *DeviceManager, cdProxy *model.Proxy, timeout time.Duration) *DeviceAgent {
khenaidoob9203542018-09-17 22:56:37 -040063 var agent DeviceAgent
khenaidoob9203542018-09-17 22:56:37 -040064 agent.adapterProxy = ap
Scott Baker80678602019-11-14 16:57:36 -080065 if device.Id == "" {
npujar1d86a522019-11-14 17:11:16 +053066 agent.deviceID = CreateDeviceID()
Scott Baker80678602019-11-14 16:57:36 -080067 } else {
npujar1d86a522019-11-14 17:11:16 +053068 agent.deviceID = device.Id
Stephane Barbarie1ab43272018-12-08 21:42:13 -050069 }
Scott Baker80678602019-11-14 16:57:36 -080070
khenaidoo2c6a0992019-04-29 13:46:56 -040071 agent.isRootdevice = device.Root
npujar1d86a522019-11-14 17:11:16 +053072 agent.parentID = device.ParentId
Scott Baker80678602019-11-14 16:57:36 -080073 agent.deviceType = device.Type
khenaidoob9203542018-09-17 22:56:37 -040074 agent.deviceMgr = deviceMgr
khenaidoo21d51152019-02-01 13:48:37 -050075 agent.adapterMgr = deviceMgr.adapterMgr
khenaidoob9203542018-09-17 22:56:37 -040076 agent.exitChannel = make(chan int, 1)
khenaidoo9a468962018-09-19 15:33:13 -040077 agent.clusterDataProxy = cdProxy
khenaidoo2c6a0992019-04-29 13:46:56 -040078 agent.defaultTimeout = timeout
khenaidoo6e55d9e2019-12-12 18:26:26 -050079 agent.device = proto.Clone(device).(*voltha.Device)
Kent Hagerman730cbdf2020-03-31 12:22:08 -040080 agent.requestQueue = coreutils.NewRequestQueue()
khenaidoob9203542018-09-17 22:56:37 -040081 return &agent
82}
83
khenaidoo442e7c72020-03-10 16:13:48 -040084// start() saves the device to the data model and registers for callbacks on that device if deviceToCreate!=nil.
85// 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 -080086// was started.
87func (agent *DeviceAgent) start(ctx context.Context, deviceToCreate *voltha.Device) (*voltha.Device, error) {
khenaidoo442e7c72020-03-10 16:13:48 -040088 needToStart := false
89 if agent.startOnce.Do(func() { needToStart = true }); !needToStart {
90 return agent.getDevice(ctx)
91 }
92 var startSucceeded bool
93 defer func() {
94 if !startSucceeded {
95 if err := agent.stop(ctx); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +000096 logger.Errorw("failed-to-cleanup-after-unsuccessful-start", log.Fields{"device-id": agent.deviceID, "error": err})
khenaidoo442e7c72020-03-10 16:13:48 -040097 }
98 }
99 }()
Scott Baker80678602019-11-14 16:57:36 -0800100
khenaidoo442e7c72020-03-10 16:13:48 -0400101 var device *voltha.Device
Scott Baker80678602019-11-14 16:57:36 -0800102 if deviceToCreate == nil {
103 // Load the existing device
Kent Hagerman4f355f52020-03-30 16:01:33 -0400104 device := &voltha.Device{}
105 have, err := agent.clusterDataProxy.Get(ctx, "devices/"+agent.deviceID, device)
Thomas Lee Se5a44012019-11-07 20:32:24 +0530106 if err != nil {
Thomas Lee Se5a44012019-11-07 20:32:24 +0530107 return nil, err
Kent Hagerman4f355f52020-03-30 16:01:33 -0400108 } else if !have {
109 return nil, status.Errorf(codes.NotFound, "device-%s", agent.deviceID)
Thomas Lee Se5a44012019-11-07 20:32:24 +0530110 }
Kent Hagerman4f355f52020-03-30 16:01:33 -0400111
112 agent.deviceType = device.Adapter
113 agent.device = proto.Clone(device).(*voltha.Device)
114
Girish Kumarf56a4682020-03-20 20:07:46 +0000115 logger.Infow("device-loaded-from-dB", log.Fields{"device-id": agent.deviceID})
khenaidoo297cd252019-02-07 22:10:23 -0500116 } else {
Scott Baker80678602019-11-14 16:57:36 -0800117 // Create a new device
118 // Assumption is that AdminState, FlowGroups, and Flows are unitialized since this
119 // is a new device, so populate them here before passing the device to clusterDataProxy.AddWithId.
120 // agent.deviceId will also have been set during newDeviceAgent().
121 device = (proto.Clone(deviceToCreate)).(*voltha.Device)
npujar1d86a522019-11-14 17:11:16 +0530122 device.Id = agent.deviceID
Scott Baker80678602019-11-14 16:57:36 -0800123 device.AdminState = voltha.AdminState_PREPROVISIONED
124 device.FlowGroups = &ofp.FlowGroups{Items: nil}
125 device.Flows = &ofp.Flows{Items: nil}
126 if !deviceToCreate.GetRoot() && deviceToCreate.ProxyAddress != nil {
127 // Set the default vlan ID to the one specified by the parent adapter. It can be
128 // overwritten by the child adapter during a device update request
129 device.Vlan = deviceToCreate.ProxyAddress.ChannelId
130 }
131
khenaidoo297cd252019-02-07 22:10:23 -0500132 // Add the initial device to the local model
Kent Hagerman4f355f52020-03-30 16:01:33 -0400133 if err := agent.clusterDataProxy.AddWithID(ctx, "devices", agent.deviceID, device); err != nil {
134 return nil, status.Errorf(codes.Aborted, "failed-adding-device-%s: %s", agent.deviceID, err)
khenaidoo297cd252019-02-07 22:10:23 -0500135 }
khenaidoo442e7c72020-03-10 16:13:48 -0400136 agent.device = device
khenaidoob9203542018-09-17 22:56:37 -0400137 }
khenaidoo19d7b632018-10-30 10:49:50 -0400138
khenaidoo442e7c72020-03-10 16:13:48 -0400139 startSucceeded = true
Girish Kumarf56a4682020-03-20 20:07:46 +0000140 logger.Debugw("device-agent-started", log.Fields{"device-id": agent.deviceID})
khenaidoo442e7c72020-03-10 16:13:48 -0400141
142 return agent.getDevice(ctx)
khenaidoob9203542018-09-17 22:56:37 -0400143}
144
khenaidoo4d4802d2018-10-04 21:59:49 -0400145// stop stops the device agent. Not much to do for now
khenaidoo442e7c72020-03-10 16:13:48 -0400146func (agent *DeviceAgent) stop(ctx context.Context) error {
147 needToStop := false
148 if agent.stopOnce.Do(func() { needToStop = true }); !needToStop {
149 return nil
150 }
151 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
152 return err
153 }
154 defer agent.requestQueue.RequestComplete()
khenaidoo49085352020-01-13 19:15:43 -0500155
Girish Kumarf56a4682020-03-20 20:07:46 +0000156 logger.Infow("stopping-device-agent", log.Fields{"deviceId": agent.deviceID, "parentId": agent.parentID})
khenaidoo6e55d9e2019-12-12 18:26:26 -0500157
khenaidoo0a822f92019-05-08 15:15:57 -0400158 // Remove the device from the KV store
Kent Hagerman4f355f52020-03-30 16:01:33 -0400159 if err := agent.clusterDataProxy.Remove(ctx, "devices/"+agent.deviceID); err != nil {
khenaidoo442e7c72020-03-10 16:13:48 -0400160 return err
Thomas Lee Se5a44012019-11-07 20:32:24 +0530161 }
khenaidoo442e7c72020-03-10 16:13:48 -0400162
khenaidoo442e7c72020-03-10 16:13:48 -0400163 close(agent.exitChannel)
164
165 agent.stopped = true
166
Girish Kumarf56a4682020-03-20 20:07:46 +0000167 logger.Infow("device-agent-stopped", log.Fields{"device-id": agent.deviceID, "parent-id": agent.parentID})
khenaidoo442e7c72020-03-10 16:13:48 -0400168
169 return nil
khenaidoob9203542018-09-17 22:56:37 -0400170}
171
Scott Baker80678602019-11-14 16:57:36 -0800172// Load the most recent state from the KVStore for the device.
npujar467fe752020-01-16 20:17:45 +0530173func (agent *DeviceAgent) reconcileWithKVStore(ctx context.Context) {
khenaidoo442e7c72020-03-10 16:13:48 -0400174 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000175 logger.Warnw("request-aborted", log.Fields{"device-id": agent.deviceID, "error": err})
khenaidoo442e7c72020-03-10 16:13:48 -0400176 return
177 }
178 defer agent.requestQueue.RequestComplete()
Girish Kumarf56a4682020-03-20 20:07:46 +0000179 logger.Debug("reconciling-device-agent-devicetype")
Scott Baker80678602019-11-14 16:57:36 -0800180 // TODO: context timeout
Kent Hagerman4f355f52020-03-30 16:01:33 -0400181 device := &voltha.Device{}
182 if have, err := agent.clusterDataProxy.Get(ctx, "devices/"+agent.deviceID, device); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000183 logger.Errorw("kv-get-failed", log.Fields{"device-id": agent.deviceID, "error": err})
Thomas Lee Se5a44012019-11-07 20:32:24 +0530184 return
Kent Hagerman4f355f52020-03-30 16:01:33 -0400185 } else if !have {
186 return // not found in kv
Thomas Lee Se5a44012019-11-07 20:32:24 +0530187 }
Kent Hagerman4f355f52020-03-30 16:01:33 -0400188
189 agent.deviceType = device.Adapter
190 agent.device = device
191 logger.Debugw("reconciled-device-agent-devicetype", log.Fields{"device-id": agent.deviceID, "type": agent.deviceType})
Scott Baker80678602019-11-14 16:57:36 -0800192}
193
khenaidoo442e7c72020-03-10 16:13:48 -0400194// onSuccess is a common callback for scenarios where we receive a nil response following a request to an adapter
195// and the only action required is to publish a successful result on kafka
196func (agent *DeviceAgent) onSuccess(rpc string, response interface{}, reqArgs ...interface{}) {
Girish Kumarf56a4682020-03-20 20:07:46 +0000197 logger.Debugw("response successful", log.Fields{"rpc": rpc, "device-id": agent.deviceID})
khenaidoo442e7c72020-03-10 16:13:48 -0400198 // TODO: Post success message onto kafka
199}
200
201// onFailure is a common callback for scenarios where we receive an error response following a request to an adapter
202// and the only action required is to publish the failed result on kafka
203func (agent *DeviceAgent) onFailure(rpc string, response interface{}, reqArgs ...interface{}) {
204 if res, ok := response.(error); ok {
Girish Kumarf56a4682020-03-20 20:07:46 +0000205 logger.Errorw("rpc-failed", log.Fields{"rpc": rpc, "device-id": agent.deviceID, "error": res, "args": reqArgs})
khenaidoo442e7c72020-03-10 16:13:48 -0400206 } else {
Girish Kumarf56a4682020-03-20 20:07:46 +0000207 logger.Errorw("rpc-failed-invalid-error", log.Fields{"rpc": rpc, "device-id": agent.deviceID, "args": reqArgs})
khenaidoo442e7c72020-03-10 16:13:48 -0400208 }
209 // TODO: Post failure message onto kafka
210}
211
212func (agent *DeviceAgent) waitForAdapterResponse(ctx context.Context, cancel context.CancelFunc, rpc string, ch chan *kafka.RpcResponse,
213 onSuccess coreutils.ResponseCallback, onFailure coreutils.ResponseCallback, reqArgs ...interface{}) {
214 defer cancel()
215 select {
216 case rpcResponse, ok := <-ch:
217 if !ok {
218 onFailure(rpc, status.Errorf(codes.Aborted, "channel-closed"), reqArgs)
219 } else if rpcResponse.Err != nil {
220 onFailure(rpc, rpcResponse.Err, reqArgs)
221 } else {
222 onSuccess(rpc, rpcResponse.Reply, reqArgs)
223 }
224 case <-ctx.Done():
225 onFailure(rpc, ctx.Err(), reqArgs)
226 }
227}
228
khenaidoo6e55d9e2019-12-12 18:26:26 -0500229// getDevice returns the device data from cache
khenaidoo442e7c72020-03-10 16:13:48 -0400230func (agent *DeviceAgent) getDevice(ctx context.Context) (*voltha.Device, error) {
231 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
232 return nil, err
233 }
234 defer agent.requestQueue.RequestComplete()
235 return proto.Clone(agent.device).(*voltha.Device), nil
khenaidoo92e62c52018-10-03 14:02:54 -0400236}
237
khenaidoo4d4802d2018-10-04 21:59:49 -0400238// 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 -0500239func (agent *DeviceAgent) getDeviceWithoutLock() *voltha.Device {
240 return proto.Clone(agent.device).(*voltha.Device)
khenaidoo92e62c52018-10-03 14:02:54 -0400241}
242
khenaidoo3ab34882019-05-02 21:33:30 -0400243// enableDevice activates a preprovisioned or a disable device
khenaidoob9203542018-09-17 22:56:37 -0400244func (agent *DeviceAgent) enableDevice(ctx context.Context) error {
khenaidoo442e7c72020-03-10 16:13:48 -0400245 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
246 return err
247 }
248 defer agent.requestQueue.RequestComplete()
249
Girish Kumarf56a4682020-03-20 20:07:46 +0000250 logger.Debugw("enableDevice", log.Fields{"device-id": agent.deviceID})
khenaidoo21d51152019-02-01 13:48:37 -0500251
khenaidoo6e55d9e2019-12-12 18:26:26 -0500252 cloned := agent.getDeviceWithoutLock()
253
npujar1d86a522019-11-14 17:11:16 +0530254 // 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 -0400255 // pre-provisioned with the required adapter not registered. At this stage, since we need to communicate
npujar1d86a522019-11-14 17:11:16 +0530256 // with the adapter then we need to know the adapter that will handle this request
khenaidoo6e55d9e2019-12-12 18:26:26 -0500257 adapterName, err := agent.adapterMgr.getAdapterName(cloned.Type)
npujar1d86a522019-11-14 17:11:16 +0530258 if err != nil {
npujar1d86a522019-11-14 17:11:16 +0530259 return err
260 }
khenaidoo6e55d9e2019-12-12 18:26:26 -0500261 cloned.Adapter = adapterName
npujar1d86a522019-11-14 17:11:16 +0530262
khenaidoo6e55d9e2019-12-12 18:26:26 -0500263 if cloned.AdminState == voltha.AdminState_ENABLED {
Girish Kumarf56a4682020-03-20 20:07:46 +0000264 logger.Debugw("device-already-enabled", log.Fields{"device-id": agent.deviceID})
npujar1d86a522019-11-14 17:11:16 +0530265 return nil
266 }
267
khenaidoo6e55d9e2019-12-12 18:26:26 -0500268 if cloned.AdminState == voltha.AdminState_DELETED {
npujar1d86a522019-11-14 17:11:16 +0530269 // This is a temporary state when a device is deleted before it gets removed from the model.
khenaidoo6e55d9e2019-12-12 18:26:26 -0500270 err = status.Error(codes.FailedPrecondition, fmt.Sprintf("cannot-enable-a-deleted-device: %s ", cloned.Id))
npujar1d86a522019-11-14 17:11:16 +0530271 return err
272 }
273
khenaidoo6e55d9e2019-12-12 18:26:26 -0500274 previousAdminState := cloned.AdminState
npujar1d86a522019-11-14 17:11:16 +0530275
276 // Update the Admin State and set the operational state to activating before sending the request to the
277 // Adapters
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500278 if err := agent.updateDeviceStateInStoreWithoutLock(ctx, cloned, voltha.AdminState_ENABLED, cloned.ConnectStatus, voltha.OperStatus_ACTIVATING); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530279 return err
280 }
281
khenaidoo442e7c72020-03-10 16:13:48 -0400282 // 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 -0500283 device := proto.Clone(cloned).(*voltha.Device)
khenaidoo442e7c72020-03-10 16:13:48 -0400284 var ch chan *kafka.RpcResponse
285 subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
npujar1d86a522019-11-14 17:11:16 +0530286 if previousAdminState == voltha.AdminState_PREPROVISIONED {
khenaidoo442e7c72020-03-10 16:13:48 -0400287 ch, err = agent.adapterProxy.adoptDevice(subCtx, device)
khenaidoob9203542018-09-17 22:56:37 -0400288 } else {
khenaidoo442e7c72020-03-10 16:13:48 -0400289 ch, err = agent.adapterProxy.reEnableDevice(subCtx, device)
khenaidoob9203542018-09-17 22:56:37 -0400290 }
khenaidoo442e7c72020-03-10 16:13:48 -0400291 if err != nil {
292 cancel()
293 return err
294 }
295 // Wait for response
296 go agent.waitForAdapterResponse(subCtx, cancel, "enableDevice", ch, agent.onSuccess, agent.onFailure)
khenaidoob9203542018-09-17 22:56:37 -0400297 return nil
298}
299
khenaidoo442e7c72020-03-10 16:13:48 -0400300func (agent *DeviceAgent) waitForAdapterFlowResponse(ctx context.Context, cancel context.CancelFunc, ch chan *kafka.RpcResponse, response coreutils.Response) {
301 defer cancel()
302 select {
303 case rpcResponse, ok := <-ch:
304 if !ok {
305 response.Error(status.Errorf(codes.Aborted, "channel-closed"))
306 } else if rpcResponse.Err != nil {
307 response.Error(rpcResponse.Err)
308 } else {
309 response.Done()
310 }
311 case <-ctx.Done():
312 response.Error(ctx.Err())
khenaidoo2c6a0992019-04-29 13:46:56 -0400313 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400314}
315
khenaidoob2121e52019-12-16 17:17:22 -0500316//deleteFlowWithoutPreservingOrder removes a flow specified by index from the flows slice. This function will
317//panic if the index is out of range.
318func deleteFlowWithoutPreservingOrder(flows []*ofp.OfpFlowStats, index int) []*ofp.OfpFlowStats {
319 flows[index] = flows[len(flows)-1]
320 flows[len(flows)-1] = nil
321 return flows[:len(flows)-1]
322}
323
324//deleteGroupWithoutPreservingOrder removes a group specified by index from the groups slice. This function will
325//panic if the index is out of range.
326func deleteGroupWithoutPreservingOrder(groups []*ofp.OfpGroupEntry, index int) []*ofp.OfpGroupEntry {
327 groups[index] = groups[len(groups)-1]
328 groups[len(groups)-1] = nil
329 return groups[:len(groups)-1]
330}
331
332func flowsToUpdateToDelete(newFlows, existingFlows []*ofp.OfpFlowStats) (updatedNewFlows, flowsToDelete, updatedAllFlows []*ofp.OfpFlowStats) {
333 // Process flows
334 for _, flow := range existingFlows {
335 if idx := fu.FindFlows(newFlows, flow); idx == -1 {
336 updatedAllFlows = append(updatedAllFlows, flow)
337 } else {
338 // We have a matching flow (i.e. the following field matches: "TableId", "Priority", "Flags", "Cookie",
339 // "Match". If this is an exact match (i.e. all other fields matches as well) then this flow will be
340 // ignored. Otherwise, the previous flow will be deleted and the new one added
341 if proto.Equal(newFlows[idx], flow) {
342 // Flow already exist, remove it from the new flows but keep it in the updated flows slice
343 newFlows = deleteFlowWithoutPreservingOrder(newFlows, idx)
344 updatedAllFlows = append(updatedAllFlows, flow)
345 } else {
346 // Minor change to flow, delete old and add new one
347 flowsToDelete = append(flowsToDelete, flow)
348 }
349 }
350 }
351 updatedAllFlows = append(updatedAllFlows, newFlows...)
352 return newFlows, flowsToDelete, updatedAllFlows
353}
354
355func groupsToUpdateToDelete(newGroups, existingGroups []*ofp.OfpGroupEntry) (updatedNewGroups, groupsToDelete, updatedAllGroups []*ofp.OfpGroupEntry) {
356 for _, group := range existingGroups {
357 if idx := fu.FindGroup(newGroups, group.Desc.GroupId); idx == -1 { // does not exist now
358 updatedAllGroups = append(updatedAllGroups, group)
359 } else {
360 // Follow same logic as flows
361 if proto.Equal(newGroups[idx], group) {
362 // Group already exist, remove it from the new groups
363 newGroups = deleteGroupWithoutPreservingOrder(newGroups, idx)
364 updatedAllGroups = append(updatedAllGroups, group)
365 } else {
366 // Minor change to group, delete old and add new one
367 groupsToDelete = append(groupsToDelete, group)
368 }
369 }
370 }
371 updatedAllGroups = append(updatedAllGroups, newGroups...)
372 return newGroups, groupsToDelete, updatedAllGroups
373}
374
npujar467fe752020-01-16 20:17:45 +0530375func (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 +0000376 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 -0400377
khenaidoo2c6a0992019-04-29 13:46:56 -0400378 if (len(newFlows) | len(newGroups)) == 0 {
Girish Kumarf56a4682020-03-20 20:07:46 +0000379 logger.Debugw("nothing-to-update", log.Fields{"device-id": agent.deviceID, "flows": newFlows, "groups": newGroups})
A R Karthick5c28f552019-12-11 22:47:44 -0800380 return coreutils.DoneResponse(), nil
khenaidoo2c6a0992019-04-29 13:46:56 -0400381 }
382
khenaidoo442e7c72020-03-10 16:13:48 -0400383 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
384 return coreutils.DoneResponse(), err
385 }
386 defer agent.requestQueue.RequestComplete()
khenaidoo2c6a0992019-04-29 13:46:56 -0400387
khenaidoo6e55d9e2019-12-12 18:26:26 -0500388 device := agent.getDeviceWithoutLock()
khenaidoo442e7c72020-03-10 16:13:48 -0400389 dType := agent.adapterMgr.getDeviceType(device.Type)
390 if dType == nil {
391 return coreutils.DoneResponse(), status.Errorf(codes.FailedPrecondition, "non-existent-device-type-%s", device.Type)
392 }
393
khenaidoo0458db62019-06-20 08:50:36 -0400394 existingFlows := proto.Clone(device.Flows).(*voltha.Flows)
395 existingGroups := proto.Clone(device.FlowGroups).(*ofp.FlowGroups)
396
khenaidoo0458db62019-06-20 08:50:36 -0400397 // Process flows
khenaidoob2121e52019-12-16 17:17:22 -0500398 newFlows, flowsToDelete, updatedAllFlows := flowsToUpdateToDelete(newFlows, existingFlows.Items)
khenaidoo0458db62019-06-20 08:50:36 -0400399
400 // Process groups
khenaidoob2121e52019-12-16 17:17:22 -0500401 newGroups, groupsToDelete, updatedAllGroups := groupsToUpdateToDelete(newGroups, existingGroups.Items)
khenaidoo0458db62019-06-20 08:50:36 -0400402
403 // Sanity check
khenaidoob2121e52019-12-16 17:17:22 -0500404 if (len(updatedAllFlows) | len(flowsToDelete) | len(updatedAllGroups) | len(groupsToDelete)) == 0 {
Girish Kumarf56a4682020-03-20 20:07:46 +0000405 logger.Debugw("nothing-to-update", log.Fields{"device-id": agent.deviceID, "flows": newFlows, "groups": newGroups})
A R Karthick5c28f552019-12-11 22:47:44 -0800406 return coreutils.DoneResponse(), nil
khenaidoo0458db62019-06-20 08:50:36 -0400407 }
408
khenaidoo442e7c72020-03-10 16:13:48 -0400409 // store the changed data
410 device.Flows = &voltha.Flows{Items: updatedAllFlows}
411 device.FlowGroups = &voltha.FlowGroups{Items: updatedAllGroups}
412 if err := agent.updateDeviceWithoutLock(ctx, device); err != nil {
413 return coreutils.DoneResponse(), status.Errorf(codes.Internal, "failure-updating-device-%s", agent.deviceID)
khenaidooe7be1332020-01-24 18:58:33 -0500414 }
khenaidoo0458db62019-06-20 08:50:36 -0400415
khenaidoo442e7c72020-03-10 16:13:48 -0400416 // Send update to adapters
417 subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
418 response := coreutils.NewResponse()
419 if !dType.AcceptsAddRemoveFlowUpdates {
khenaidoob2121e52019-12-16 17:17:22 -0500420 if len(updatedAllGroups) != 0 && reflect.DeepEqual(existingGroups.Items, updatedAllGroups) && len(updatedAllFlows) != 0 && reflect.DeepEqual(existingFlows.Items, updatedAllFlows) {
Girish Kumarf56a4682020-03-20 20:07:46 +0000421 logger.Debugw("nothing-to-update", log.Fields{"device-id": agent.deviceID, "flows": newFlows, "groups": newGroups})
khenaidoo442e7c72020-03-10 16:13:48 -0400422 cancel()
A R Karthick5c28f552019-12-11 22:47:44 -0800423 return coreutils.DoneResponse(), nil
khenaidoo0458db62019-06-20 08:50:36 -0400424 }
khenaidoo442e7c72020-03-10 16:13:48 -0400425 rpcResponse, err := agent.adapterProxy.updateFlowsBulk(subCtx, device, &voltha.Flows{Items: updatedAllFlows}, &voltha.FlowGroups{Items: updatedAllGroups}, flowMetadata)
426 if err != nil {
427 cancel()
428 return coreutils.DoneResponse(), err
429 }
430 go agent.waitForAdapterFlowResponse(subCtx, cancel, rpcResponse, response)
khenaidoo0458db62019-06-20 08:50:36 -0400431 } else {
432 flowChanges := &ofp.FlowChanges{
Matt Jeanneret518b5a42019-10-29 10:30:46 -0400433 ToAdd: &voltha.Flows{Items: newFlows},
khenaidoo0458db62019-06-20 08:50:36 -0400434 ToRemove: &voltha.Flows{Items: flowsToDelete},
435 }
436 groupChanges := &ofp.FlowGroupChanges{
Matt Jeanneret518b5a42019-10-29 10:30:46 -0400437 ToAdd: &voltha.FlowGroups{Items: newGroups},
438 ToRemove: &voltha.FlowGroups{Items: groupsToDelete},
khenaidoo0458db62019-06-20 08:50:36 -0400439 ToUpdate: &voltha.FlowGroups{Items: []*ofp.OfpGroupEntry{}},
440 }
khenaidoo442e7c72020-03-10 16:13:48 -0400441 rpcResponse, err := agent.adapterProxy.updateFlowsIncremental(subCtx, device, flowChanges, groupChanges, flowMetadata)
442 if err != nil {
443 cancel()
444 return coreutils.DoneResponse(), err
445 }
446 go agent.waitForAdapterFlowResponse(subCtx, cancel, rpcResponse, response)
khenaidoo0458db62019-06-20 08:50:36 -0400447 }
A R Karthick5c28f552019-12-11 22:47:44 -0800448 return response, nil
449}
450
451//addFlowsAndGroups adds the "newFlows" and "newGroups" from the existing flows/groups and sends the update to the
452//adapters
npujar467fe752020-01-16 20:17:45 +0530453func (agent *DeviceAgent) addFlowsAndGroups(ctx context.Context, newFlows []*ofp.OfpFlowStats, newGroups []*ofp.OfpGroupEntry, flowMetadata *voltha.FlowMetadata) error {
454 response, err := agent.addFlowsAndGroupsToAdapter(ctx, newFlows, newGroups, flowMetadata)
A R Karthick5c28f552019-12-11 22:47:44 -0800455 if err != nil {
456 return err
457 }
khenaidoo442e7c72020-03-10 16:13:48 -0400458 if errs := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, response); errs != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000459 logger.Warnw("no-adapter-response", log.Fields{"device-id": agent.deviceID, "result": errs})
khenaidoo442e7c72020-03-10 16:13:48 -0400460 return status.Errorf(codes.Aborted, "flow-failure-device-%s", agent.deviceID)
khenaidoo0458db62019-06-20 08:50:36 -0400461 }
khenaidoo0458db62019-06-20 08:50:36 -0400462 return nil
463}
464
npujar467fe752020-01-16 20:17:45 +0530465func (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 +0000466 logger.Debugw("delete-flows-groups-from-adapter", log.Fields{"device-id": agent.deviceID, "flows": flowsToDel, "groups": groupsToDel})
khenaidoo0458db62019-06-20 08:50:36 -0400467
468 if (len(flowsToDel) | len(groupsToDel)) == 0 {
Girish Kumarf56a4682020-03-20 20:07:46 +0000469 logger.Debugw("nothing-to-update", log.Fields{"device-id": agent.deviceID, "flows": flowsToDel, "groups": groupsToDel})
A R Karthick5c28f552019-12-11 22:47:44 -0800470 return coreutils.DoneResponse(), nil
khenaidoo0458db62019-06-20 08:50:36 -0400471 }
472
khenaidoo442e7c72020-03-10 16:13:48 -0400473 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
474 return coreutils.DoneResponse(), err
475 }
476 defer agent.requestQueue.RequestComplete()
khenaidoo0458db62019-06-20 08:50:36 -0400477
khenaidoo6e55d9e2019-12-12 18:26:26 -0500478 device := agent.getDeviceWithoutLock()
khenaidoo442e7c72020-03-10 16:13:48 -0400479 dType := agent.adapterMgr.getDeviceType(device.Type)
480 if dType == nil {
481 return coreutils.DoneResponse(), status.Errorf(codes.FailedPrecondition, "non-existent-device-type-%s", device.Type)
482 }
khenaidoo0458db62019-06-20 08:50:36 -0400483
484 existingFlows := proto.Clone(device.Flows).(*voltha.Flows)
485 existingGroups := proto.Clone(device.FlowGroups).(*ofp.FlowGroups)
486
487 var flowsToKeep []*ofp.OfpFlowStats
488 var groupsToKeep []*ofp.OfpGroupEntry
489
490 // Process flows
491 for _, flow := range existingFlows.Items {
492 if idx := fu.FindFlows(flowsToDel, flow); idx == -1 {
493 flowsToKeep = append(flowsToKeep, flow)
494 }
495 }
496
497 // Process groups
498 for _, group := range existingGroups.Items {
499 if fu.FindGroup(groupsToDel, group.Desc.GroupId) == -1 { // does not exist now
500 groupsToKeep = append(groupsToKeep, group)
501 }
502 }
503
Girish Kumarf56a4682020-03-20 20:07:46 +0000504 logger.Debugw("deleteFlowsAndGroups",
khenaidoo0458db62019-06-20 08:50:36 -0400505 log.Fields{
khenaidoo442e7c72020-03-10 16:13:48 -0400506 "device-id": agent.deviceID,
507 "flows-to-del": len(flowsToDel),
508 "flows-to-keep": len(flowsToKeep),
509 "groups-to-del": len(groupsToDel),
510 "groups-to-keep": len(groupsToKeep),
khenaidoo0458db62019-06-20 08:50:36 -0400511 })
512
513 // Sanity check
514 if (len(flowsToKeep) | len(flowsToDel) | len(groupsToKeep) | len(groupsToDel)) == 0 {
Girish Kumarf56a4682020-03-20 20:07:46 +0000515 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 -0800516 return coreutils.DoneResponse(), nil
khenaidoo0458db62019-06-20 08:50:36 -0400517 }
518
khenaidoo442e7c72020-03-10 16:13:48 -0400519 // store the changed data
520 device.Flows = &voltha.Flows{Items: flowsToKeep}
521 device.FlowGroups = &voltha.FlowGroups{Items: groupsToKeep}
522 if err := agent.updateDeviceWithoutLock(ctx, device); err != nil {
523 return coreutils.DoneResponse(), status.Errorf(codes.Internal, "failure-updating-%s", agent.deviceID)
khenaidooe7be1332020-01-24 18:58:33 -0500524 }
khenaidoo442e7c72020-03-10 16:13:48 -0400525
526 // Send update to adapters
527 subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
528 response := coreutils.NewResponse()
khenaidoo0458db62019-06-20 08:50:36 -0400529 if !dType.AcceptsAddRemoveFlowUpdates {
530 if len(groupsToKeep) != 0 && reflect.DeepEqual(existingGroups.Items, groupsToKeep) && len(flowsToKeep) != 0 && reflect.DeepEqual(existingFlows.Items, flowsToKeep) {
Girish Kumarf56a4682020-03-20 20:07:46 +0000531 logger.Debugw("nothing-to-update", log.Fields{"deviceId": agent.deviceID, "flowsToDel": flowsToDel, "groupsToDel": groupsToDel})
khenaidoo442e7c72020-03-10 16:13:48 -0400532 cancel()
A R Karthick5c28f552019-12-11 22:47:44 -0800533 return coreutils.DoneResponse(), nil
khenaidoo0458db62019-06-20 08:50:36 -0400534 }
khenaidoo442e7c72020-03-10 16:13:48 -0400535 rpcResponse, err := agent.adapterProxy.updateFlowsBulk(subCtx, device, &voltha.Flows{Items: flowsToKeep}, &voltha.FlowGroups{Items: groupsToKeep}, flowMetadata)
536 if err != nil {
537 cancel()
538 return coreutils.DoneResponse(), err
539 }
540 go agent.waitForAdapterFlowResponse(subCtx, cancel, rpcResponse, response)
khenaidoo0458db62019-06-20 08:50:36 -0400541 } else {
542 flowChanges := &ofp.FlowChanges{
543 ToAdd: &voltha.Flows{Items: []*ofp.OfpFlowStats{}},
544 ToRemove: &voltha.Flows{Items: flowsToDel},
545 }
546 groupChanges := &ofp.FlowGroupChanges{
547 ToAdd: &voltha.FlowGroups{Items: []*ofp.OfpGroupEntry{}},
548 ToRemove: &voltha.FlowGroups{Items: groupsToDel},
549 ToUpdate: &voltha.FlowGroups{Items: []*ofp.OfpGroupEntry{}},
550 }
khenaidoo442e7c72020-03-10 16:13:48 -0400551 rpcResponse, err := agent.adapterProxy.updateFlowsIncremental(subCtx, device, flowChanges, groupChanges, flowMetadata)
552 if err != nil {
553 cancel()
554 return coreutils.DoneResponse(), err
555 }
556 go agent.waitForAdapterFlowResponse(subCtx, cancel, rpcResponse, response)
khenaidoo0458db62019-06-20 08:50:36 -0400557 }
A R Karthick5c28f552019-12-11 22:47:44 -0800558 return response, nil
A R Karthick5c28f552019-12-11 22:47:44 -0800559}
560
561//deleteFlowsAndGroups removes the "flowsToDel" and "groupsToDel" from the existing flows/groups and sends the update to the
562//adapters
npujar467fe752020-01-16 20:17:45 +0530563func (agent *DeviceAgent) deleteFlowsAndGroups(ctx context.Context, flowsToDel []*ofp.OfpFlowStats, groupsToDel []*ofp.OfpGroupEntry, flowMetadata *voltha.FlowMetadata) error {
564 response, err := agent.deleteFlowsAndGroupsFromAdapter(ctx, flowsToDel, groupsToDel, flowMetadata)
A R Karthick5c28f552019-12-11 22:47:44 -0800565 if err != nil {
566 return err
567 }
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500568 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, response); res != nil {
khenaidoo0458db62019-06-20 08:50:36 -0400569 return status.Errorf(codes.Aborted, "errors-%s", res)
570 }
571 return nil
khenaidoo0458db62019-06-20 08:50:36 -0400572}
573
npujar467fe752020-01-16 20:17:45 +0530574func (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 +0000575 logger.Debugw("updateFlowsAndGroups", log.Fields{"device-id": agent.deviceID, "flows": updatedFlows, "groups": updatedGroups})
khenaidoo0458db62019-06-20 08:50:36 -0400576
577 if (len(updatedFlows) | len(updatedGroups)) == 0 {
Girish Kumarf56a4682020-03-20 20:07:46 +0000578 logger.Debugw("nothing-to-update", log.Fields{"device-id": agent.deviceID, "flows": updatedFlows, "groups": updatedGroups})
A R Karthick5c28f552019-12-11 22:47:44 -0800579 return coreutils.DoneResponse(), nil
khenaidoo0458db62019-06-20 08:50:36 -0400580 }
581
khenaidoo442e7c72020-03-10 16:13:48 -0400582 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
583 return coreutils.DoneResponse(), err
584 }
585 defer agent.requestQueue.RequestComplete()
khenaidoo6e55d9e2019-12-12 18:26:26 -0500586
587 device := agent.getDeviceWithoutLock()
khenaidoo442e7c72020-03-10 16:13:48 -0400588 if device.OperStatus != voltha.OperStatus_ACTIVE || device.ConnectStatus != voltha.ConnectStatus_REACHABLE || device.AdminState != voltha.AdminState_ENABLED {
589 return coreutils.DoneResponse(), status.Errorf(codes.FailedPrecondition, "invalid device states")
590 }
591 dType := agent.adapterMgr.getDeviceType(device.Type)
592 if dType == nil {
593 return coreutils.DoneResponse(), status.Errorf(codes.FailedPrecondition, "non-existent-device-type-%s", device.Type)
594 }
khenaidoo6e55d9e2019-12-12 18:26:26 -0500595
khenaidoo0458db62019-06-20 08:50:36 -0400596 existingFlows := proto.Clone(device.Flows).(*voltha.Flows)
597 existingGroups := proto.Clone(device.FlowGroups).(*ofp.FlowGroups)
598
599 if len(updatedGroups) != 0 && reflect.DeepEqual(existingGroups.Items, updatedGroups) && len(updatedFlows) != 0 && reflect.DeepEqual(existingFlows.Items, updatedFlows) {
Girish Kumarf56a4682020-03-20 20:07:46 +0000600 logger.Debugw("nothing-to-update", log.Fields{"device-id": agent.deviceID, "flows": updatedFlows, "groups": updatedGroups})
A R Karthick5c28f552019-12-11 22:47:44 -0800601 return coreutils.DoneResponse(), nil
khenaidoo0458db62019-06-20 08:50:36 -0400602 }
603
Girish Kumarf56a4682020-03-20 20:07:46 +0000604 logger.Debugw("updating-flows-and-groups",
khenaidoo0458db62019-06-20 08:50:36 -0400605 log.Fields{
khenaidoo442e7c72020-03-10 16:13:48 -0400606 "device-id": agent.deviceID,
607 "updated-flows": updatedFlows,
608 "updated-groups": updatedGroups,
khenaidoo0458db62019-06-20 08:50:36 -0400609 })
610
khenaidoo442e7c72020-03-10 16:13:48 -0400611 // store the updated data
612 device.Flows = &voltha.Flows{Items: updatedFlows}
613 device.FlowGroups = &voltha.FlowGroups{Items: updatedGroups}
614 if err := agent.updateDeviceWithoutLock(ctx, device); err != nil {
615 return coreutils.DoneResponse(), status.Errorf(codes.Internal, "failure-updating-%s", agent.deviceID)
khenaidooe7be1332020-01-24 18:58:33 -0500616 }
khenaidoo0458db62019-06-20 08:50:36 -0400617
khenaidoo442e7c72020-03-10 16:13:48 -0400618 subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
619 response := coreutils.NewResponse()
khenaidoo0458db62019-06-20 08:50:36 -0400620 // Process bulk flow update differently than incremental update
621 if !dType.AcceptsAddRemoveFlowUpdates {
khenaidoo442e7c72020-03-10 16:13:48 -0400622 rpcResponse, err := agent.adapterProxy.updateFlowsBulk(subCtx, device, &voltha.Flows{Items: updatedFlows}, &voltha.FlowGroups{Items: updatedGroups}, nil)
623 if err != nil {
624 cancel()
625 return coreutils.DoneResponse(), err
626 }
627 go agent.waitForAdapterFlowResponse(subCtx, cancel, rpcResponse, response)
khenaidoo0458db62019-06-20 08:50:36 -0400628 } else {
629 var flowsToAdd []*ofp.OfpFlowStats
khenaidoo2c6a0992019-04-29 13:46:56 -0400630 var flowsToDelete []*ofp.OfpFlowStats
khenaidoo0458db62019-06-20 08:50:36 -0400631 var groupsToAdd []*ofp.OfpGroupEntry
khenaidoo2c6a0992019-04-29 13:46:56 -0400632 var groupsToDelete []*ofp.OfpGroupEntry
khenaidoo2c6a0992019-04-29 13:46:56 -0400633
634 // Process flows
khenaidoo0458db62019-06-20 08:50:36 -0400635 for _, flow := range updatedFlows {
636 if idx := fu.FindFlows(existingFlows.Items, flow); idx == -1 {
637 flowsToAdd = append(flowsToAdd, flow)
638 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400639 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400640 for _, flow := range existingFlows.Items {
khenaidoo0458db62019-06-20 08:50:36 -0400641 if idx := fu.FindFlows(updatedFlows, flow); idx != -1 {
khenaidoo2c6a0992019-04-29 13:46:56 -0400642 flowsToDelete = append(flowsToDelete, flow)
643 }
644 }
645
646 // Process groups
khenaidoo0458db62019-06-20 08:50:36 -0400647 for _, g := range updatedGroups {
648 if fu.FindGroup(existingGroups.Items, g.Desc.GroupId) == -1 { // does not exist now
649 groupsToAdd = append(groupsToAdd, g)
650 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400651 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400652 for _, group := range existingGroups.Items {
khenaidoo0458db62019-06-20 08:50:36 -0400653 if fu.FindGroup(updatedGroups, group.Desc.GroupId) != -1 { // does not exist now
khenaidoo2c6a0992019-04-29 13:46:56 -0400654 groupsToDelete = append(groupsToDelete, group)
655 }
656 }
657
Girish Kumarf56a4682020-03-20 20:07:46 +0000658 logger.Debugw("updating-flows-and-groups",
khenaidoo0458db62019-06-20 08:50:36 -0400659 log.Fields{
khenaidoo442e7c72020-03-10 16:13:48 -0400660 "device-id": agent.deviceID,
661 "flows-to-add": flowsToAdd,
662 "flows-to-delete": flowsToDelete,
663 "groups-to-add": groupsToAdd,
664 "groups-to-delete": groupsToDelete,
khenaidoo0458db62019-06-20 08:50:36 -0400665 })
666
khenaidoo2c6a0992019-04-29 13:46:56 -0400667 // Sanity check
khenaidoo0458db62019-06-20 08:50:36 -0400668 if (len(flowsToAdd) | len(flowsToDelete) | len(groupsToAdd) | len(groupsToDelete) | len(updatedGroups)) == 0 {
Girish Kumarf56a4682020-03-20 20:07:46 +0000669 logger.Debugw("nothing-to-update", log.Fields{"device-id": agent.deviceID, "flows": updatedFlows, "groups": updatedGroups})
khenaidoo442e7c72020-03-10 16:13:48 -0400670 cancel()
A R Karthick5c28f552019-12-11 22:47:44 -0800671 return coreutils.DoneResponse(), nil
khenaidoo2c6a0992019-04-29 13:46:56 -0400672 }
673
khenaidoo0458db62019-06-20 08:50:36 -0400674 flowChanges := &ofp.FlowChanges{
675 ToAdd: &voltha.Flows{Items: flowsToAdd},
676 ToRemove: &voltha.Flows{Items: flowsToDelete},
khenaidoo19d7b632018-10-30 10:49:50 -0400677 }
khenaidoo0458db62019-06-20 08:50:36 -0400678 groupChanges := &ofp.FlowGroupChanges{
679 ToAdd: &voltha.FlowGroups{Items: groupsToAdd},
680 ToRemove: &voltha.FlowGroups{Items: groupsToDelete},
681 ToUpdate: &voltha.FlowGroups{Items: updatedGroups},
682 }
khenaidoo442e7c72020-03-10 16:13:48 -0400683 rpcResponse, err := agent.adapterProxy.updateFlowsIncremental(subCtx, device, flowChanges, groupChanges, flowMetadata)
684 if err != nil {
685 cancel()
686 return coreutils.DoneResponse(), err
687 }
688 go agent.waitForAdapterFlowResponse(subCtx, cancel, rpcResponse, response)
Kent Hagerman3c513972019-11-25 13:49:41 -0500689 }
khenaidoo0458db62019-06-20 08:50:36 -0400690
A R Karthick5c28f552019-12-11 22:47:44 -0800691 return response, nil
692}
693
694//updateFlowsAndGroups replaces the existing flows and groups with "updatedFlows" and "updatedGroups" respectively. It
695//also sends the updates to the adapters
npujar467fe752020-01-16 20:17:45 +0530696func (agent *DeviceAgent) updateFlowsAndGroups(ctx context.Context, updatedFlows []*ofp.OfpFlowStats, updatedGroups []*ofp.OfpGroupEntry, flowMetadata *voltha.FlowMetadata) error {
697 response, err := agent.updateFlowsAndGroupsToAdapter(ctx, updatedFlows, updatedGroups, flowMetadata)
A R Karthick5c28f552019-12-11 22:47:44 -0800698 if err != nil {
699 return err
700 }
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500701 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, response); res != nil {
khenaidoo0458db62019-06-20 08:50:36 -0400702 return status.Errorf(codes.Aborted, "errors-%s", res)
703 }
704 return nil
khenaidoo19d7b632018-10-30 10:49:50 -0400705}
706
Girish Gowdra408cd962020-03-11 14:31:31 -0700707//deleteAllFlows deletes all flows in the device table
708func (agent *DeviceAgent) deleteAllFlows(ctx context.Context) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000709 logger.Debugw("deleteAllFlows", log.Fields{"deviceId": agent.deviceID})
Girish Gowdra408cd962020-03-11 14:31:31 -0700710 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
711 return err
712 }
713 defer agent.requestQueue.RequestComplete()
714
715 device := agent.getDeviceWithoutLock()
716 // purge all flows on the device by setting it to nil
717 device.Flows = &ofp.Flows{Items: nil}
718 if err := agent.updateDeviceWithoutLock(ctx, device); err != nil {
719 // The caller logs the error
720 return err
721 }
722 return nil
723}
724
khenaidoo4d4802d2018-10-04 21:59:49 -0400725//disableDevice disable a device
khenaidoo92e62c52018-10-03 14:02:54 -0400726func (agent *DeviceAgent) disableDevice(ctx context.Context) error {
khenaidoo442e7c72020-03-10 16:13:48 -0400727 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
728 return err
729 }
730 defer agent.requestQueue.RequestComplete()
Girish Kumarf56a4682020-03-20 20:07:46 +0000731 logger.Debugw("disableDevice", log.Fields{"device-id": agent.deviceID})
khenaidoo6e55d9e2019-12-12 18:26:26 -0500732
733 cloned := agent.getDeviceWithoutLock()
734
735 if cloned.AdminState == voltha.AdminState_DISABLED {
Girish Kumarf56a4682020-03-20 20:07:46 +0000736 logger.Debugw("device-already-disabled", log.Fields{"id": agent.deviceID})
npujar1d86a522019-11-14 17:11:16 +0530737 return nil
738 }
khenaidoo6e55d9e2019-12-12 18:26:26 -0500739 if cloned.AdminState == voltha.AdminState_PREPROVISIONED ||
740 cloned.AdminState == voltha.AdminState_DELETED {
khenaidoo6e55d9e2019-12-12 18:26:26 -0500741 return status.Errorf(codes.FailedPrecondition, "deviceId:%s, invalid-admin-state:%s", agent.deviceID, cloned.AdminState)
npujar1d86a522019-11-14 17:11:16 +0530742 }
khenaidoo4554f7c2019-05-29 22:13:15 -0400743
npujar1d86a522019-11-14 17:11:16 +0530744 // Update the Admin State and operational state before sending the request out
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500745 if err := agent.updateDeviceStateInStoreWithoutLock(ctx, cloned, voltha.AdminState_DISABLED, cloned.ConnectStatus, voltha.OperStatus_UNKNOWN); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530746 return err
747 }
khenaidoo442e7c72020-03-10 16:13:48 -0400748
749 subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
750 ch, err := agent.adapterProxy.disableDevice(subCtx, proto.Clone(cloned).(*voltha.Device))
751 if err != nil {
752 cancel()
npujar1d86a522019-11-14 17:11:16 +0530753 return err
khenaidoo0a822f92019-05-08 15:15:57 -0400754 }
khenaidoo442e7c72020-03-10 16:13:48 -0400755 go agent.waitForAdapterResponse(subCtx, cancel, "disableDevice", ch, agent.onSuccess, agent.onFailure)
khenaidoo0a822f92019-05-08 15:15:57 -0400756
khenaidoo92e62c52018-10-03 14:02:54 -0400757 return nil
758}
759
khenaidoo4d4802d2018-10-04 21:59:49 -0400760func (agent *DeviceAgent) rebootDevice(ctx context.Context) error {
khenaidoo442e7c72020-03-10 16:13:48 -0400761 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530762 return err
khenaidoo4d4802d2018-10-04 21:59:49 -0400763 }
khenaidoo442e7c72020-03-10 16:13:48 -0400764 defer agent.requestQueue.RequestComplete()
Girish Kumarf56a4682020-03-20 20:07:46 +0000765 logger.Debugw("rebootDevice", log.Fields{"device-id": agent.deviceID})
khenaidoo442e7c72020-03-10 16:13:48 -0400766
767 device := agent.getDeviceWithoutLock()
768 subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
769 ch, err := agent.adapterProxy.rebootDevice(subCtx, device)
770 if err != nil {
771 cancel()
772 return err
773 }
774 go agent.waitForAdapterResponse(subCtx, cancel, "rebootDevice", ch, agent.onSuccess, agent.onFailure)
khenaidoo4d4802d2018-10-04 21:59:49 -0400775 return nil
776}
777
778func (agent *DeviceAgent) deleteDevice(ctx context.Context) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000779 logger.Debugw("deleteDevice", log.Fields{"device-id": agent.deviceID})
khenaidoo442e7c72020-03-10 16:13:48 -0400780 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
781 return err
782 }
783 defer agent.requestQueue.RequestComplete()
khenaidoo6e55d9e2019-12-12 18:26:26 -0500784
785 cloned := agent.getDeviceWithoutLock()
Chaitrashree G S543df3e2020-02-24 22:36:54 -0500786
khenaidoo442e7c72020-03-10 16:13:48 -0400787 previousState := cloned.AdminState
788
789 // No check is required when deleting a device. Changing the state to DELETE will trigger the removal of this
790 // device by the state machine
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500791 if err := agent.updateDeviceStateInStoreWithoutLock(ctx, cloned, voltha.AdminState_DELETED, cloned.ConnectStatus, cloned.OperStatus); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530792 return err
793 }
khenaidoo442e7c72020-03-10 16:13:48 -0400794
795 // If the device was in pre-prov state (only parent device are in that state) then do not send the request to the
796 // adapter
797 if previousState != ic.AdminState_PREPROVISIONED {
798 subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
799 ch, err := agent.adapterProxy.deleteDevice(subCtx, cloned)
800 if err != nil {
801 cancel()
802 return err
803 }
804 go agent.waitForAdapterResponse(subCtx, cancel, "deleteDevice", ch, agent.onSuccess, agent.onFailure)
805 }
khenaidoo4d4802d2018-10-04 21:59:49 -0400806 return nil
807}
808
npujar467fe752020-01-16 20:17:45 +0530809func (agent *DeviceAgent) setParentID(ctx context.Context, device *voltha.Device, parentID string) error {
khenaidoo442e7c72020-03-10 16:13:48 -0400810 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
811 return err
812 }
813 defer agent.requestQueue.RequestComplete()
814
Girish Kumarf56a4682020-03-20 20:07:46 +0000815 logger.Debugw("setParentId", log.Fields{"device-id": device.Id, "parent-id": parentID})
khenaidoo6e55d9e2019-12-12 18:26:26 -0500816
817 cloned := agent.getDeviceWithoutLock()
npujar1d86a522019-11-14 17:11:16 +0530818 cloned.ParentId = parentID
819 // Store the device
npujar467fe752020-01-16 20:17:45 +0530820 if err := agent.updateDeviceInStoreWithoutLock(ctx, cloned, false, ""); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530821 return err
822 }
khenaidoo442e7c72020-03-10 16:13:48 -0400823
npujar1d86a522019-11-14 17:11:16 +0530824 return nil
khenaidooad06fd72019-10-28 12:26:05 -0400825}
826
khenaidoob3127472019-07-24 21:04:55 -0400827func (agent *DeviceAgent) updatePmConfigs(ctx context.Context, pmConfigs *voltha.PmConfigs) error {
khenaidoo442e7c72020-03-10 16:13:48 -0400828 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
829 return err
830 }
831 defer agent.requestQueue.RequestComplete()
Girish Kumarf56a4682020-03-20 20:07:46 +0000832 logger.Debugw("updatePmConfigs", log.Fields{"device-id": pmConfigs.Id})
khenaidoo6e55d9e2019-12-12 18:26:26 -0500833
834 cloned := agent.getDeviceWithoutLock()
npujar1d86a522019-11-14 17:11:16 +0530835 cloned.PmConfigs = proto.Clone(pmConfigs).(*voltha.PmConfigs)
836 // Store the device
npujar467fe752020-01-16 20:17:45 +0530837 if err := agent.updateDeviceInStoreWithoutLock(ctx, cloned, false, ""); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530838 return err
839 }
840 // Send the request to the adapter
khenaidoo442e7c72020-03-10 16:13:48 -0400841 subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
842 ch, err := agent.adapterProxy.updatePmConfigs(subCtx, cloned, pmConfigs)
843 if err != nil {
844 cancel()
npujar1d86a522019-11-14 17:11:16 +0530845 return err
846 }
khenaidoo442e7c72020-03-10 16:13:48 -0400847 go agent.waitForAdapterResponse(subCtx, cancel, "updatePmConfigs", ch, agent.onSuccess, agent.onFailure)
npujar1d86a522019-11-14 17:11:16 +0530848 return nil
khenaidoob3127472019-07-24 21:04:55 -0400849}
850
npujar467fe752020-01-16 20:17:45 +0530851func (agent *DeviceAgent) initPmConfigs(ctx context.Context, pmConfigs *voltha.PmConfigs) error {
khenaidoo442e7c72020-03-10 16:13:48 -0400852 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
853 return err
854 }
855 defer agent.requestQueue.RequestComplete()
Girish Kumarf56a4682020-03-20 20:07:46 +0000856 logger.Debugw("initPmConfigs", log.Fields{"device-id": pmConfigs.Id})
khenaidoo6e55d9e2019-12-12 18:26:26 -0500857
858 cloned := agent.getDeviceWithoutLock()
npujar1d86a522019-11-14 17:11:16 +0530859 cloned.PmConfigs = proto.Clone(pmConfigs).(*voltha.PmConfigs)
npujar467fe752020-01-16 20:17:45 +0530860 updateCtx := context.WithValue(ctx, model.RequestTimestamp, time.Now().UnixNano())
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500861 return agent.updateDeviceInStoreWithoutLock(updateCtx, cloned, false, "")
khenaidoob3127472019-07-24 21:04:55 -0400862}
863
864func (agent *DeviceAgent) listPmConfigs(ctx context.Context) (*voltha.PmConfigs, error) {
khenaidoo442e7c72020-03-10 16:13:48 -0400865 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
866 return nil, err
867 }
868 defer agent.requestQueue.RequestComplete()
Girish Kumarf56a4682020-03-20 20:07:46 +0000869 logger.Debugw("listPmConfigs", log.Fields{"device-id": agent.deviceID})
khenaidoo6e55d9e2019-12-12 18:26:26 -0500870
871 return agent.getDeviceWithoutLock().PmConfigs, nil
khenaidoob3127472019-07-24 21:04:55 -0400872}
873
khenaidoof5a5bfa2019-01-23 22:20:29 -0500874func (agent *DeviceAgent) downloadImage(ctx context.Context, img *voltha.ImageDownload) (*voltha.OperationResp, error) {
khenaidoo442e7c72020-03-10 16:13:48 -0400875 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
876 return nil, err
877 }
878 defer agent.requestQueue.RequestComplete()
879
Girish Kumarf56a4682020-03-20 20:07:46 +0000880 logger.Debugw("downloadImage", log.Fields{"device-id": agent.deviceID})
khenaidoo6e55d9e2019-12-12 18:26:26 -0500881
882 device := agent.getDeviceWithoutLock()
883
npujar1d86a522019-11-14 17:11:16 +0530884 if device.AdminState != voltha.AdminState_ENABLED {
khenaidoo442e7c72020-03-10 16:13:48 -0400885 return nil, status.Errorf(codes.FailedPrecondition, "device-id:%s, expected-admin-state:%s", agent.deviceID, voltha.AdminState_ENABLED)
npujar1d86a522019-11-14 17:11:16 +0530886 }
887 // Save the image
888 clonedImg := proto.Clone(img).(*voltha.ImageDownload)
889 clonedImg.DownloadState = voltha.ImageDownload_DOWNLOAD_REQUESTED
890 cloned := proto.Clone(device).(*voltha.Device)
891 if cloned.ImageDownloads == nil {
892 cloned.ImageDownloads = []*voltha.ImageDownload{clonedImg}
khenaidoof5a5bfa2019-01-23 22:20:29 -0500893 } else {
894 if device.AdminState != voltha.AdminState_ENABLED {
Girish Kumarf56a4682020-03-20 20:07:46 +0000895 logger.Debugw("device-not-enabled", log.Fields{"id": agent.deviceID})
npujar1d86a522019-11-14 17:11:16 +0530896 return nil, status.Errorf(codes.FailedPrecondition, "deviceId:%s, expected-admin-state:%s", agent.deviceID, voltha.AdminState_ENABLED)
khenaidoof5a5bfa2019-01-23 22:20:29 -0500897 }
898 // Save the image
899 clonedImg := proto.Clone(img).(*voltha.ImageDownload)
Stephane Barbariedf5479f2019-01-29 22:13:00 -0500900 clonedImg.DownloadState = voltha.ImageDownload_DOWNLOAD_REQUESTED
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500901 if device.ImageDownloads == nil {
902 device.ImageDownloads = []*voltha.ImageDownload{clonedImg}
khenaidoof5a5bfa2019-01-23 22:20:29 -0500903 } else {
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500904 device.ImageDownloads = append(device.ImageDownloads, clonedImg)
khenaidoof5a5bfa2019-01-23 22:20:29 -0500905 }
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500906 if err := agent.updateDeviceStateInStoreWithoutLock(ctx, cloned, voltha.AdminState_DOWNLOADING_IMAGE, device.ConnectStatus, device.OperStatus); err != nil {
Mahir Gunyelb5851672019-07-24 10:46:26 +0300907 return nil, err
khenaidoof5a5bfa2019-01-23 22:20:29 -0500908 }
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500909
khenaidoof5a5bfa2019-01-23 22:20:29 -0500910 // Send the request to the adapter
khenaidoo442e7c72020-03-10 16:13:48 -0400911 subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
912 ch, err := agent.adapterProxy.downloadImage(ctx, cloned, clonedImg)
913 if err != nil {
914 cancel()
khenaidoof5a5bfa2019-01-23 22:20:29 -0500915 return nil, err
916 }
khenaidoo442e7c72020-03-10 16:13:48 -0400917 go agent.waitForAdapterResponse(subCtx, cancel, "downloadImage", ch, agent.onSuccess, agent.onFailure)
khenaidoof5a5bfa2019-01-23 22:20:29 -0500918 }
919 return &voltha.OperationResp{Code: voltha.OperationResp_OPERATION_SUCCESS}, nil
920}
921
922// isImageRegistered is a helper method to figure out if an image is already registered
923func isImageRegistered(img *voltha.ImageDownload, device *voltha.Device) bool {
924 for _, image := range device.ImageDownloads {
925 if image.Id == img.Id && image.Name == img.Name {
926 return true
927 }
928 }
929 return false
930}
931
932func (agent *DeviceAgent) cancelImageDownload(ctx context.Context, img *voltha.ImageDownload) (*voltha.OperationResp, error) {
khenaidoo442e7c72020-03-10 16:13:48 -0400933 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
934 return nil, err
935 }
936 defer agent.requestQueue.RequestComplete()
937
Girish Kumarf56a4682020-03-20 20:07:46 +0000938 logger.Debugw("cancelImageDownload", log.Fields{"device-id": agent.deviceID})
khenaidoo6e55d9e2019-12-12 18:26:26 -0500939
940 device := agent.getDeviceWithoutLock()
941
npujar1d86a522019-11-14 17:11:16 +0530942 // Verify whether the Image is in the list of image being downloaded
943 if !isImageRegistered(img, device) {
khenaidoo442e7c72020-03-10 16:13:48 -0400944 return nil, status.Errorf(codes.FailedPrecondition, "device-id:%s, image-not-registered:%s", agent.deviceID, img.Name)
npujar1d86a522019-11-14 17:11:16 +0530945 }
khenaidoof5a5bfa2019-01-23 22:20:29 -0500946
npujar1d86a522019-11-14 17:11:16 +0530947 // Update image download state
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500948 for _, image := range device.ImageDownloads {
npujar1d86a522019-11-14 17:11:16 +0530949 if image.Id == img.Id && image.Name == img.Name {
950 image.DownloadState = voltha.ImageDownload_DOWNLOAD_CANCELLED
khenaidoof5a5bfa2019-01-23 22:20:29 -0500951 }
npujar1d86a522019-11-14 17:11:16 +0530952 }
khenaidoof5a5bfa2019-01-23 22:20:29 -0500953
npujar1d86a522019-11-14 17:11:16 +0530954 if device.AdminState == voltha.AdminState_DOWNLOADING_IMAGE {
955 // Set the device to Enabled
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500956 if err := agent.updateDeviceStateInStoreWithoutLock(ctx, device, voltha.AdminState_ENABLED, device.ConnectStatus, device.OperStatus); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530957 return nil, err
958 }
khenaidoo442e7c72020-03-10 16:13:48 -0400959 subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
960 ch, err := agent.adapterProxy.cancelImageDownload(subCtx, device, img)
961 if err != nil {
962 cancel()
npujar1d86a522019-11-14 17:11:16 +0530963 return nil, err
khenaidoof5a5bfa2019-01-23 22:20:29 -0500964 }
khenaidoo442e7c72020-03-10 16:13:48 -0400965 go agent.waitForAdapterResponse(subCtx, cancel, "cancelImageDownload", ch, agent.onSuccess, agent.onFailure)
khenaidoof5a5bfa2019-01-23 22:20:29 -0500966 }
967 return &voltha.OperationResp{Code: voltha.OperationResp_OPERATION_SUCCESS}, nil
serkant.uluderya334479d2019-04-10 08:26:15 -0700968}
khenaidoof5a5bfa2019-01-23 22:20:29 -0500969
970func (agent *DeviceAgent) activateImage(ctx context.Context, img *voltha.ImageDownload) (*voltha.OperationResp, error) {
khenaidoo442e7c72020-03-10 16:13:48 -0400971 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
972 return nil, err
973 }
974 defer agent.requestQueue.RequestComplete()
Girish Kumarf56a4682020-03-20 20:07:46 +0000975 logger.Debugw("activateImage", log.Fields{"device-id": agent.deviceID})
khenaidoo6e55d9e2019-12-12 18:26:26 -0500976 cloned := agent.getDeviceWithoutLock()
977
npujar1d86a522019-11-14 17:11:16 +0530978 // Verify whether the Image is in the list of image being downloaded
khenaidoo6e55d9e2019-12-12 18:26:26 -0500979 if !isImageRegistered(img, cloned) {
khenaidoo442e7c72020-03-10 16:13:48 -0400980 return nil, status.Errorf(codes.FailedPrecondition, "device-id:%s, image-not-registered:%s", agent.deviceID, img.Name)
npujar1d86a522019-11-14 17:11:16 +0530981 }
982
khenaidoo6e55d9e2019-12-12 18:26:26 -0500983 if cloned.AdminState == voltha.AdminState_DOWNLOADING_IMAGE {
khenaidoo442e7c72020-03-10 16:13:48 -0400984 return nil, status.Errorf(codes.FailedPrecondition, "device-id:%s, device-in-downloading-state:%s", agent.deviceID, img.Name)
npujar1d86a522019-11-14 17:11:16 +0530985 }
986 // Update image download state
npujar1d86a522019-11-14 17:11:16 +0530987 for _, image := range cloned.ImageDownloads {
988 if image.Id == img.Id && image.Name == img.Name {
989 image.ImageState = voltha.ImageDownload_IMAGE_ACTIVATING
990 }
991 }
992 // Set the device to downloading_image
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500993 if err := agent.updateDeviceStateInStoreWithoutLock(ctx, cloned, voltha.AdminState_DOWNLOADING_IMAGE, cloned.ConnectStatus, cloned.OperStatus); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530994 return nil, err
995 }
996
khenaidoo442e7c72020-03-10 16:13:48 -0400997 subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
998 ch, err := agent.adapterProxy.activateImageUpdate(subCtx, proto.Clone(cloned).(*voltha.Device), img)
999 if err != nil {
1000 cancel()
npujar1d86a522019-11-14 17:11:16 +05301001 return nil, err
1002 }
khenaidoo442e7c72020-03-10 16:13:48 -04001003 go agent.waitForAdapterResponse(subCtx, cancel, "activateImageUpdate", ch, agent.onSuccess, agent.onFailure)
1004
npujar1d86a522019-11-14 17:11:16 +05301005 // The status of the AdminState will be changed following the update_download_status response from the adapter
1006 // The image name will also be removed from the device list
serkant.uluderya334479d2019-04-10 08:26:15 -07001007 return &voltha.OperationResp{Code: voltha.OperationResp_OPERATION_SUCCESS}, nil
1008}
khenaidoof5a5bfa2019-01-23 22:20:29 -05001009
1010func (agent *DeviceAgent) revertImage(ctx context.Context, img *voltha.ImageDownload) (*voltha.OperationResp, error) {
khenaidoo442e7c72020-03-10 16:13:48 -04001011 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1012 return nil, err
1013 }
1014 defer agent.requestQueue.RequestComplete()
Girish Kumarf56a4682020-03-20 20:07:46 +00001015 logger.Debugw("revertImage", log.Fields{"device-id": agent.deviceID})
khenaidoo6e55d9e2019-12-12 18:26:26 -05001016
1017 cloned := agent.getDeviceWithoutLock()
1018
npujar1d86a522019-11-14 17:11:16 +05301019 // Verify whether the Image is in the list of image being downloaded
khenaidoo6e55d9e2019-12-12 18:26:26 -05001020 if !isImageRegistered(img, cloned) {
npujar1d86a522019-11-14 17:11:16 +05301021 return nil, status.Errorf(codes.FailedPrecondition, "deviceId:%s, image-not-registered:%s", agent.deviceID, img.Name)
1022 }
khenaidoof5a5bfa2019-01-23 22:20:29 -05001023
khenaidoo6e55d9e2019-12-12 18:26:26 -05001024 if cloned.AdminState != voltha.AdminState_ENABLED {
npujar1d86a522019-11-14 17:11:16 +05301025 return nil, status.Errorf(codes.FailedPrecondition, "deviceId:%s, device-not-enabled-state:%s", agent.deviceID, img.Name)
1026 }
1027 // Update image download state
npujar1d86a522019-11-14 17:11:16 +05301028 for _, image := range cloned.ImageDownloads {
1029 if image.Id == img.Id && image.Name == img.Name {
1030 image.ImageState = voltha.ImageDownload_IMAGE_REVERTING
khenaidoof5a5bfa2019-01-23 22:20:29 -05001031 }
npujar1d86a522019-11-14 17:11:16 +05301032 }
Mahir Gunyelb5851672019-07-24 10:46:26 +03001033
npujar467fe752020-01-16 20:17:45 +05301034 if err := agent.updateDeviceInStoreWithoutLock(ctx, cloned, false, ""); err != nil {
npujar1d86a522019-11-14 17:11:16 +05301035 return nil, err
1036 }
khenaidoof5a5bfa2019-01-23 22:20:29 -05001037
khenaidoo442e7c72020-03-10 16:13:48 -04001038 subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
1039 ch, err := agent.adapterProxy.revertImageUpdate(subCtx, proto.Clone(cloned).(*voltha.Device), img)
1040 if err != nil {
1041 cancel()
npujar1d86a522019-11-14 17:11:16 +05301042 return nil, err
khenaidoof5a5bfa2019-01-23 22:20:29 -05001043 }
khenaidoo442e7c72020-03-10 16:13:48 -04001044 go agent.waitForAdapterResponse(subCtx, cancel, "revertImageUpdate", ch, agent.onSuccess, agent.onFailure)
1045
khenaidoof5a5bfa2019-01-23 22:20:29 -05001046 return &voltha.OperationResp{Code: voltha.OperationResp_OPERATION_SUCCESS}, nil
serkant.uluderya334479d2019-04-10 08:26:15 -07001047}
khenaidoof5a5bfa2019-01-23 22:20:29 -05001048
1049func (agent *DeviceAgent) getImageDownloadStatus(ctx context.Context, img *voltha.ImageDownload) (*voltha.ImageDownload, error) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001050 logger.Debugw("getImageDownloadStatus", log.Fields{"device-id": agent.deviceID})
khenaidoo6e55d9e2019-12-12 18:26:26 -05001051
khenaidoo442e7c72020-03-10 16:13:48 -04001052 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
npujar1d86a522019-11-14 17:11:16 +05301053 return nil, err
1054 }
khenaidoo442e7c72020-03-10 16:13:48 -04001055 device := agent.getDeviceWithoutLock()
1056 ch, err := agent.adapterProxy.getImageDownloadStatus(ctx, device, img)
1057 agent.requestQueue.RequestComplete()
1058 if err != nil {
1059 return nil, err
1060 }
1061 // Wait for the adapter response
1062 rpcResponse, ok := <-ch
1063 if !ok {
1064 return nil, status.Errorf(codes.Aborted, "channel-closed-device-id-%s", agent.deviceID)
1065 }
1066 if rpcResponse.Err != nil {
1067 return nil, rpcResponse.Err
1068 }
1069 // Successful response
1070 imgDownload := &voltha.ImageDownload{}
1071 if err := ptypes.UnmarshalAny(rpcResponse.Reply, imgDownload); err != nil {
1072 return nil, status.Errorf(codes.InvalidArgument, "%s", err.Error())
1073 }
1074 return imgDownload, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001075}
1076
npujar467fe752020-01-16 20:17:45 +05301077func (agent *DeviceAgent) updateImageDownload(ctx context.Context, img *voltha.ImageDownload) error {
khenaidoo442e7c72020-03-10 16:13:48 -04001078 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1079 return err
1080 }
1081 defer agent.requestQueue.RequestComplete()
Girish Kumarf56a4682020-03-20 20:07:46 +00001082 logger.Debugw("updating-image-download", log.Fields{"device-id": agent.deviceID, "img": img})
khenaidoo6e55d9e2019-12-12 18:26:26 -05001083
1084 cloned := agent.getDeviceWithoutLock()
1085
npujar1d86a522019-11-14 17:11:16 +05301086 // Update the image as well as remove it if the download was cancelled
npujar1d86a522019-11-14 17:11:16 +05301087 clonedImages := make([]*voltha.ImageDownload, len(cloned.ImageDownloads))
1088 for _, image := range cloned.ImageDownloads {
1089 if image.Id == img.Id && image.Name == img.Name {
1090 if image.DownloadState != voltha.ImageDownload_DOWNLOAD_CANCELLED {
1091 clonedImages = append(clonedImages, img)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001092 }
1093 }
npujar1d86a522019-11-14 17:11:16 +05301094 }
1095 cloned.ImageDownloads = clonedImages
1096 // Set the Admin state to enabled if required
1097 if (img.DownloadState != voltha.ImageDownload_DOWNLOAD_REQUESTED &&
1098 img.DownloadState != voltha.ImageDownload_DOWNLOAD_STARTED) ||
1099 (img.ImageState != voltha.ImageDownload_IMAGE_ACTIVATING) {
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001100 return agent.updateDeviceStateInStoreWithoutLock(ctx, cloned, voltha.AdminState_ENABLED, cloned.ConnectStatus, cloned.OperStatus)
npujar1d86a522019-11-14 17:11:16 +05301101 }
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001102 return agent.updateDeviceInStoreWithoutLock(ctx, cloned, false, "")
khenaidoof5a5bfa2019-01-23 22:20:29 -05001103}
1104
1105func (agent *DeviceAgent) getImageDownload(ctx context.Context, img *voltha.ImageDownload) (*voltha.ImageDownload, error) {
khenaidoo442e7c72020-03-10 16:13:48 -04001106 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1107 return nil, err
1108 }
1109 defer agent.requestQueue.RequestComplete()
Girish Kumarf56a4682020-03-20 20:07:46 +00001110 logger.Debugw("getImageDownload", log.Fields{"device-id": agent.deviceID})
khenaidoo6e55d9e2019-12-12 18:26:26 -05001111
1112 cloned := agent.getDeviceWithoutLock()
1113 for _, image := range cloned.ImageDownloads {
npujar1d86a522019-11-14 17:11:16 +05301114 if image.Id == img.Id && image.Name == img.Name {
1115 return image, nil
1116 }
1117 }
1118 return nil, status.Errorf(codes.NotFound, "image-not-found:%s", img.Name)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001119}
1120
npujar1d86a522019-11-14 17:11:16 +05301121func (agent *DeviceAgent) listImageDownloads(ctx context.Context, deviceID string) (*voltha.ImageDownloads, error) {
khenaidoo442e7c72020-03-10 16:13:48 -04001122 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1123 return nil, err
1124 }
1125 defer agent.requestQueue.RequestComplete()
Girish Kumarf56a4682020-03-20 20:07:46 +00001126 logger.Debugw("listImageDownloads", log.Fields{"device-id": agent.deviceID})
khenaidoo6e55d9e2019-12-12 18:26:26 -05001127
1128 return &voltha.ImageDownloads{Items: agent.getDeviceWithoutLock().ImageDownloads}, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001129}
1130
khenaidoo4d4802d2018-10-04 21:59:49 -04001131// getPorts retrieves the ports information of the device based on the port type.
khenaidoo92e62c52018-10-03 14:02:54 -04001132func (agent *DeviceAgent) getPorts(ctx context.Context, portType voltha.Port_PortType) *voltha.Ports {
Girish Kumarf56a4682020-03-20 20:07:46 +00001133 logger.Debugw("getPorts", log.Fields{"device-id": agent.deviceID, "port-type": portType})
khenaidoob9203542018-09-17 22:56:37 -04001134 ports := &voltha.Ports{}
npujar467fe752020-01-16 20:17:45 +05301135 if device, _ := agent.deviceMgr.GetDevice(ctx, agent.deviceID); device != nil {
khenaidoob9203542018-09-17 22:56:37 -04001136 for _, port := range device.Ports {
khenaidoo92e62c52018-10-03 14:02:54 -04001137 if port.Type == portType {
khenaidoob9203542018-09-17 22:56:37 -04001138 ports.Items = append(ports.Items, port)
1139 }
1140 }
1141 }
1142 return ports
1143}
1144
khenaidoo442e7c72020-03-10 16:13:48 -04001145// getSwitchCapability retrieves the switch capability of a parent device
khenaidoo79232702018-12-04 11:00:41 -05001146func (agent *DeviceAgent) getSwitchCapability(ctx context.Context) (*ic.SwitchCapability, error) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001147 logger.Debugw("getSwitchCapability", log.Fields{"device-id": agent.deviceID})
khenaidoo442e7c72020-03-10 16:13:48 -04001148
1149 cloned, err := agent.getDevice(ctx)
1150 if err != nil {
khenaidoob9203542018-09-17 22:56:37 -04001151 return nil, err
khenaidoob9203542018-09-17 22:56:37 -04001152 }
khenaidoo442e7c72020-03-10 16:13:48 -04001153 ch, err := agent.adapterProxy.getOfpDeviceInfo(ctx, cloned)
1154 if err != nil {
1155 return nil, err
1156 }
1157
1158 // Wait for adapter response
1159 rpcResponse, ok := <-ch
1160 if !ok {
1161 return nil, status.Errorf(codes.Aborted, "channel-closed")
1162 }
1163 if rpcResponse.Err != nil {
1164 return nil, rpcResponse.Err
1165 }
1166 // Successful response
1167 switchCap := &ic.SwitchCapability{}
1168 if err := ptypes.UnmarshalAny(rpcResponse.Reply, switchCap); err != nil {
npujar1d86a522019-11-14 17:11:16 +05301169 return nil, err
1170 }
1171 return switchCap, nil
khenaidoob9203542018-09-17 22:56:37 -04001172}
1173
khenaidoo442e7c72020-03-10 16:13:48 -04001174// getPortCapability retrieves the port capability of a device
khenaidoo79232702018-12-04 11:00:41 -05001175func (agent *DeviceAgent) getPortCapability(ctx context.Context, portNo uint32) (*ic.PortCapability, error) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001176 logger.Debugw("getPortCapability", log.Fields{"device-id": agent.deviceID})
khenaidoo442e7c72020-03-10 16:13:48 -04001177 device, err := agent.getDevice(ctx)
1178 if err != nil {
khenaidoob9203542018-09-17 22:56:37 -04001179 return nil, err
khenaidoob9203542018-09-17 22:56:37 -04001180 }
khenaidoo442e7c72020-03-10 16:13:48 -04001181 ch, err := agent.adapterProxy.getOfpPortInfo(ctx, device, portNo)
1182 if err != nil {
npujar1d86a522019-11-14 17:11:16 +05301183 return nil, err
1184 }
khenaidoo442e7c72020-03-10 16:13:48 -04001185 // Wait for adapter response
1186 rpcResponse, ok := <-ch
1187 if !ok {
1188 return nil, status.Errorf(codes.Aborted, "channel-closed")
1189 }
1190 if rpcResponse.Err != nil {
1191 return nil, rpcResponse.Err
1192 }
1193 // Successful response
1194 portCap := &ic.PortCapability{}
1195 if err := ptypes.UnmarshalAny(rpcResponse.Reply, portCap); err != nil {
1196 return nil, status.Errorf(codes.InvalidArgument, "%s", err.Error())
1197 }
npujar1d86a522019-11-14 17:11:16 +05301198 return portCap, nil
khenaidoob9203542018-09-17 22:56:37 -04001199}
1200
khenaidoo442e7c72020-03-10 16:13:48 -04001201func (agent *DeviceAgent) onPacketFailure(rpc string, response interface{}, args ...interface{}) {
1202 // packet data is encoded in the args param as the first parameter
1203 var packet []byte
1204 if len(args) >= 1 {
1205 if pkt, ok := args[0].([]byte); ok {
1206 packet = pkt
1207 }
1208 }
1209 var errResp error
1210 if err, ok := response.(error); ok {
1211 errResp = err
1212 }
Girish Kumarf56a4682020-03-20 20:07:46 +00001213 logger.Warnw("packet-out-error", log.Fields{
khenaidoo442e7c72020-03-10 16:13:48 -04001214 "device-id": agent.deviceID,
1215 "error": errResp,
1216 "packet": hex.EncodeToString(packet),
1217 })
1218}
1219
npujar467fe752020-01-16 20:17:45 +05301220func (agent *DeviceAgent) packetOut(ctx context.Context, outPort uint32, packet *ofp.OfpPacketOut) error {
Scott Baker80678602019-11-14 16:57:36 -08001221 // If deviceType=="" then we must have taken ownership of this device.
1222 // Fixes VOL-2226 where a core would take ownership and have stale data
1223 if agent.deviceType == "" {
npujar467fe752020-01-16 20:17:45 +05301224 agent.reconcileWithKVStore(ctx)
Scott Baker80678602019-11-14 16:57:36 -08001225 }
khenaidoofdbad6e2018-11-06 22:26:38 -05001226 // Send packet to adapter
khenaidoo442e7c72020-03-10 16:13:48 -04001227 subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
1228 ch, err := agent.adapterProxy.packetOut(subCtx, agent.deviceType, agent.deviceID, outPort, packet)
1229 if err != nil {
1230 cancel()
1231 return nil
khenaidoofdbad6e2018-11-06 22:26:38 -05001232 }
khenaidoo442e7c72020-03-10 16:13:48 -04001233 go agent.waitForAdapterResponse(subCtx, cancel, "packetOut", ch, agent.onSuccess, agent.onPacketFailure, packet.Data)
khenaidoofdbad6e2018-11-06 22:26:38 -05001234 return nil
1235}
1236
Mahir Gunyel8e2707d2019-07-25 00:36:21 -07001237// updatePartialDeviceData updates a subset of a device that an Adapter can update.
1238// TODO: May need a specific proto to handle only a subset of a device that can be changed by an adapter
1239func (agent *DeviceAgent) mergeDeviceInfoFromAdapter(device *voltha.Device) (*voltha.Device, error) {
khenaidoo6e55d9e2019-12-12 18:26:26 -05001240 cloned := agent.getDeviceWithoutLock()
Mahir Gunyel8e2707d2019-07-25 00:36:21 -07001241 cloned.Root = device.Root
1242 cloned.Vendor = device.Vendor
1243 cloned.Model = device.Model
1244 cloned.SerialNumber = device.SerialNumber
1245 cloned.MacAddress = device.MacAddress
1246 cloned.Vlan = device.Vlan
1247 cloned.Reason = device.Reason
1248 return cloned, nil
1249}
khenaidoo442e7c72020-03-10 16:13:48 -04001250
npujar467fe752020-01-16 20:17:45 +05301251func (agent *DeviceAgent) updateDeviceUsingAdapterData(ctx context.Context, device *voltha.Device) error {
khenaidoo442e7c72020-03-10 16:13:48 -04001252 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1253 return err
1254 }
1255 defer agent.requestQueue.RequestComplete()
Girish Kumarf56a4682020-03-20 20:07:46 +00001256 logger.Debugw("updateDeviceUsingAdapterData", log.Fields{"device-id": device.Id})
khenaidoo442e7c72020-03-10 16:13:48 -04001257
npujar1d86a522019-11-14 17:11:16 +05301258 updatedDevice, err := agent.mergeDeviceInfoFromAdapter(device)
1259 if err != nil {
Mahir Gunyel8e2707d2019-07-25 00:36:21 -07001260 return status.Errorf(codes.Internal, "%s", err.Error())
Mahir Gunyel8e2707d2019-07-25 00:36:21 -07001261 }
npujar1d86a522019-11-14 17:11:16 +05301262 cloned := proto.Clone(updatedDevice).(*voltha.Device)
npujar467fe752020-01-16 20:17:45 +05301263 return agent.updateDeviceInStoreWithoutLock(ctx, cloned, false, "")
khenaidoo43c82122018-11-22 18:38:28 -05001264}
1265
npujar467fe752020-01-16 20:17:45 +05301266func (agent *DeviceAgent) updateDeviceWithoutLock(ctx context.Context, device *voltha.Device) error {
Girish Kumarf56a4682020-03-20 20:07:46 +00001267 logger.Debugw("updateDevice", log.Fields{"deviceId": device.Id})
khenaidoo442e7c72020-03-10 16:13:48 -04001268 //cloned := proto.Clone(device).(*voltha.Device)
1269 cloned := device
npujar467fe752020-01-16 20:17:45 +05301270 return agent.updateDeviceInStoreWithoutLock(ctx, cloned, false, "")
khenaidoob9203542018-09-17 22:56:37 -04001271}
1272
npujar467fe752020-01-16 20:17:45 +05301273func (agent *DeviceAgent) updateDeviceStatus(ctx context.Context, operStatus voltha.OperStatus_Types, connStatus voltha.ConnectStatus_Types) error {
khenaidoo442e7c72020-03-10 16:13:48 -04001274 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1275 return err
1276 }
1277 defer agent.requestQueue.RequestComplete()
khenaidoo6e55d9e2019-12-12 18:26:26 -05001278
1279 cloned := agent.getDeviceWithoutLock()
1280
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001281 newConnStatus, newOperStatus := cloned.ConnectStatus, cloned.OperStatus
npujar1d86a522019-11-14 17:11:16 +05301282 // 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 -08001283 if s, ok := voltha.ConnectStatus_Types_value[connStatus.String()]; ok {
Girish Kumarf56a4682020-03-20 20:07:46 +00001284 logger.Debugw("updateDeviceStatus-conn", log.Fields{"ok": ok, "val": s})
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001285 newConnStatus = connStatus
npujar1d86a522019-11-14 17:11:16 +05301286 }
serkant.uluderya2ae470f2020-01-21 11:13:09 -08001287 if s, ok := voltha.OperStatus_Types_value[operStatus.String()]; ok {
Girish Kumarf56a4682020-03-20 20:07:46 +00001288 logger.Debugw("updateDeviceStatus-oper", log.Fields{"ok": ok, "val": s})
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001289 newOperStatus = operStatus
npujar1d86a522019-11-14 17:11:16 +05301290 }
Girish Kumarf56a4682020-03-20 20:07:46 +00001291 logger.Debugw("updateDeviceStatus", log.Fields{"deviceId": cloned.Id, "operStatus": cloned.OperStatus, "connectStatus": cloned.ConnectStatus})
npujar1d86a522019-11-14 17:11:16 +05301292 // Store the device
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001293 return agent.updateDeviceStateInStoreWithoutLock(ctx, cloned, cloned.AdminState, newConnStatus, newOperStatus)
khenaidoo92e62c52018-10-03 14:02:54 -04001294}
1295
kesavandbc2d1622020-01-21 00:42:01 -05001296func (agent *DeviceAgent) updatePortsOperState(ctx context.Context, operStatus voltha.OperStatus_Types) error {
Girish Kumarf56a4682020-03-20 20:07:46 +00001297 logger.Debugw("updatePortsOperState", log.Fields{"device-id": agent.deviceID})
khenaidoo442e7c72020-03-10 16:13:48 -04001298 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1299 return err
1300 }
1301 defer agent.requestQueue.RequestComplete()
khenaidoo6e55d9e2019-12-12 18:26:26 -05001302 cloned := agent.getDeviceWithoutLock()
npujar1d86a522019-11-14 17:11:16 +05301303 for _, port := range cloned.Ports {
kesavandbc2d1622020-01-21 00:42:01 -05001304 port.OperStatus = operStatus
npujar1d86a522019-11-14 17:11:16 +05301305 }
1306 // Store the device
npujar467fe752020-01-16 20:17:45 +05301307 return agent.updateDeviceInStoreWithoutLock(ctx, cloned, false, "")
khenaidoo3ab34882019-05-02 21:33:30 -04001308}
1309
npujar467fe752020-01-16 20:17:45 +05301310func (agent *DeviceAgent) updatePortState(ctx context.Context, portType voltha.Port_PortType, portNo uint32, operStatus voltha.OperStatus_Types) error {
khenaidoo442e7c72020-03-10 16:13:48 -04001311 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1312 return err
1313 }
1314 defer agent.requestQueue.RequestComplete()
khenaidoo92e62c52018-10-03 14:02:54 -04001315 // Work only on latest data
1316 // TODO: Get list of ports from device directly instead of the entire device
khenaidoo6e55d9e2019-12-12 18:26:26 -05001317 cloned := agent.getDeviceWithoutLock()
1318
npujar1d86a522019-11-14 17:11:16 +05301319 // Ensure the enums passed in are valid - they will be invalid if they are not set when this function is invoked
1320 if _, ok := voltha.Port_PortType_value[portType.String()]; !ok {
1321 return status.Errorf(codes.InvalidArgument, "%s", portType)
1322 }
1323 for _, port := range cloned.Ports {
1324 if port.Type == portType && port.PortNo == portNo {
1325 port.OperStatus = operStatus
npujar1d86a522019-11-14 17:11:16 +05301326 }
1327 }
Girish Kumarf56a4682020-03-20 20:07:46 +00001328 logger.Debugw("portStatusUpdate", log.Fields{"deviceId": cloned.Id})
npujar1d86a522019-11-14 17:11:16 +05301329 // Store the device
npujar467fe752020-01-16 20:17:45 +05301330 return agent.updateDeviceInStoreWithoutLock(ctx, cloned, false, "")
khenaidoob9203542018-09-17 22:56:37 -04001331}
1332
npujar467fe752020-01-16 20:17:45 +05301333func (agent *DeviceAgent) deleteAllPorts(ctx context.Context) error {
Girish Kumarf56a4682020-03-20 20:07:46 +00001334 logger.Debugw("deleteAllPorts", log.Fields{"deviceId": agent.deviceID})
khenaidoo442e7c72020-03-10 16:13:48 -04001335 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1336 return err
1337 }
1338 defer agent.requestQueue.RequestComplete()
khenaidoo6e55d9e2019-12-12 18:26:26 -05001339
1340 cloned := agent.getDeviceWithoutLock()
1341
1342 if cloned.AdminState != voltha.AdminState_DISABLED && cloned.AdminState != voltha.AdminState_DELETED {
1343 err := status.Error(codes.FailedPrecondition, fmt.Sprintf("invalid-state-%v", cloned.AdminState))
Girish Kumarf56a4682020-03-20 20:07:46 +00001344 logger.Warnw("invalid-state-removing-ports", log.Fields{"state": cloned.AdminState, "error": err})
npujar1d86a522019-11-14 17:11:16 +05301345 return err
1346 }
khenaidoo6e55d9e2019-12-12 18:26:26 -05001347 if len(cloned.Ports) == 0 {
Girish Kumarf56a4682020-03-20 20:07:46 +00001348 logger.Debugw("no-ports-present", log.Fields{"deviceId": agent.deviceID})
npujar1d86a522019-11-14 17:11:16 +05301349 return nil
1350 }
khenaidoo6e55d9e2019-12-12 18:26:26 -05001351
npujar1d86a522019-11-14 17:11:16 +05301352 cloned.Ports = []*voltha.Port{}
Girish Kumarf56a4682020-03-20 20:07:46 +00001353 logger.Debugw("portStatusUpdate", log.Fields{"deviceId": cloned.Id})
npujar1d86a522019-11-14 17:11:16 +05301354 // Store the device
npujar467fe752020-01-16 20:17:45 +05301355 return agent.updateDeviceInStoreWithoutLock(ctx, cloned, false, "")
khenaidoo0a822f92019-05-08 15:15:57 -04001356}
1357
npujar467fe752020-01-16 20:17:45 +05301358func (agent *DeviceAgent) addPort(ctx context.Context, port *voltha.Port) error {
khenaidoo442e7c72020-03-10 16:13:48 -04001359 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1360 return err
1361 }
1362 defer agent.requestQueue.RequestComplete()
Girish Kumarf56a4682020-03-20 20:07:46 +00001363 logger.Debugw("addPort", log.Fields{"deviceId": agent.deviceID})
khenaidoo6e55d9e2019-12-12 18:26:26 -05001364
1365 cloned := agent.getDeviceWithoutLock()
khenaidoo80b987d2020-02-20 10:52:52 -05001366 updatePort := false
npujar1d86a522019-11-14 17:11:16 +05301367 if cloned.Ports == nil {
1368 // First port
Girish Kumarf56a4682020-03-20 20:07:46 +00001369 logger.Debugw("addPort-first-port-to-add", log.Fields{"deviceId": agent.deviceID})
npujar1d86a522019-11-14 17:11:16 +05301370 cloned.Ports = make([]*voltha.Port, 0)
khenaidoob9203542018-09-17 22:56:37 -04001371 } else {
npujar1d86a522019-11-14 17:11:16 +05301372 for _, p := range cloned.Ports {
1373 if p.Type == port.Type && p.PortNo == port.PortNo {
khenaidoo80b987d2020-02-20 10:52:52 -05001374 if p.Label == "" && p.Type == voltha.Port_PON_OLT {
1375 //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 +00001376 logger.Infow("update-pon-port-created-by-default", log.Fields{"default-port": p, "port-to-add": port})
khenaidoo80b987d2020-02-20 10:52:52 -05001377 p.Label = port.Label
1378 p.OperStatus = port.OperStatus
1379 updatePort = true
1380 break
1381 }
Girish Kumarf56a4682020-03-20 20:07:46 +00001382 logger.Debugw("port already exists", log.Fields{"port": port})
npujar1d86a522019-11-14 17:11:16 +05301383 return nil
manikkaraj k259a6f72019-05-06 09:55:44 -04001384 }
khenaidoob9203542018-09-17 22:56:37 -04001385 }
khenaidoo92e62c52018-10-03 14:02:54 -04001386 }
khenaidoo80b987d2020-02-20 10:52:52 -05001387 if !updatePort {
1388 cp := proto.Clone(port).(*voltha.Port)
1389 // Set the admin state of the port to ENABLE
1390 cp.AdminState = voltha.AdminState_ENABLED
1391 cloned.Ports = append(cloned.Ports, cp)
1392 }
npujar1d86a522019-11-14 17:11:16 +05301393 // Store the device
npujar467fe752020-01-16 20:17:45 +05301394 return agent.updateDeviceInStoreWithoutLock(ctx, cloned, false, "")
khenaidoo92e62c52018-10-03 14:02:54 -04001395}
1396
khenaidoo80b987d2020-02-20 10:52:52 -05001397func (agent *DeviceAgent) addPeerPort(ctx context.Context, peerPort *voltha.Port_PeerPort) error {
khenaidoo442e7c72020-03-10 16:13:48 -04001398 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1399 return err
1400 }
1401 defer agent.requestQueue.RequestComplete()
Girish Kumarf56a4682020-03-20 20:07:46 +00001402 logger.Debugw("adding-peer-peerPort", log.Fields{"device-id": agent.deviceID, "peer-peerPort": peerPort})
khenaidoo6e55d9e2019-12-12 18:26:26 -05001403
1404 cloned := agent.getDeviceWithoutLock()
1405
khenaidoo80b987d2020-02-20 10:52:52 -05001406 // Get the peer port on the device based on the peerPort no
1407 found := false
1408 for _, port := range cloned.Ports {
1409 if port.PortNo == peerPort.PortNo { // found peerPort
1410 cp := proto.Clone(peerPort).(*voltha.Port_PeerPort)
1411 port.Peers = append(port.Peers, cp)
Girish Kumarf56a4682020-03-20 20:07:46 +00001412 logger.Debugw("found-peer", log.Fields{"device-id": agent.deviceID, "portNo": peerPort.PortNo, "deviceId": agent.deviceID})
khenaidoo80b987d2020-02-20 10:52:52 -05001413 found = true
npujar1d86a522019-11-14 17:11:16 +05301414 break
1415 }
1416 }
khenaidoo80b987d2020-02-20 10:52:52 -05001417 if !found && agent.isRootdevice {
1418 // An ONU PON port has been created before the corresponding creation of the OLT PON port. Create the OLT PON port
1419 // with default values which will be updated once the OLT PON port creation is processed.
1420 ponPort := &voltha.Port{
1421 PortNo: peerPort.PortNo,
1422 Type: voltha.Port_PON_OLT,
1423 AdminState: voltha.AdminState_ENABLED,
1424 DeviceId: agent.deviceID,
1425 Peers: []*voltha.Port_PeerPort{proto.Clone(peerPort).(*voltha.Port_PeerPort)},
1426 }
1427 cloned.Ports = append(cloned.Ports, ponPort)
Girish Kumarf56a4682020-03-20 20:07:46 +00001428 logger.Infow("adding-default-pon-port", log.Fields{"device-id": agent.deviceID, "peer": peerPort, "pon-port": ponPort})
khenaidoo80b987d2020-02-20 10:52:52 -05001429 }
npujar1d86a522019-11-14 17:11:16 +05301430 // Store the device
npujar467fe752020-01-16 20:17:45 +05301431 return agent.updateDeviceInStoreWithoutLock(ctx, cloned, false, "")
khenaidoob9203542018-09-17 22:56:37 -04001432}
1433
1434// TODO: A generic device update by attribute
npujar467fe752020-01-16 20:17:45 +05301435func (agent *DeviceAgent) updateDeviceAttribute(ctx context.Context, name string, value interface{}) {
khenaidoo442e7c72020-03-10 16:13:48 -04001436 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001437 logger.Warnw("request-aborted", log.Fields{"device-id": agent.deviceID, "name": name, "error": err})
khenaidoo442e7c72020-03-10 16:13:48 -04001438 return
1439 }
1440 defer agent.requestQueue.RequestComplete()
khenaidoob9203542018-09-17 22:56:37 -04001441 if value == nil {
1442 return
1443 }
khenaidoo6e55d9e2019-12-12 18:26:26 -05001444
1445 cloned := agent.getDeviceWithoutLock()
khenaidoob9203542018-09-17 22:56:37 -04001446 updated := false
khenaidoo6e55d9e2019-12-12 18:26:26 -05001447 s := reflect.ValueOf(cloned).Elem()
khenaidoob9203542018-09-17 22:56:37 -04001448 if s.Kind() == reflect.Struct {
1449 // exported field
1450 f := s.FieldByName(name)
1451 if f.IsValid() && f.CanSet() {
1452 switch f.Kind() {
1453 case reflect.String:
1454 f.SetString(value.(string))
1455 updated = true
1456 case reflect.Uint32:
1457 f.SetUint(uint64(value.(uint32)))
1458 updated = true
1459 case reflect.Bool:
1460 f.SetBool(value.(bool))
1461 updated = true
1462 }
1463 }
1464 }
Girish Kumarf56a4682020-03-20 20:07:46 +00001465 logger.Debugw("update-field-status", log.Fields{"deviceId": cloned.Id, "name": name, "updated": updated})
khenaidoob9203542018-09-17 22:56:37 -04001466 // Save the data
khenaidoo6e55d9e2019-12-12 18:26:26 -05001467
npujar467fe752020-01-16 20:17:45 +05301468 if err := agent.updateDeviceInStoreWithoutLock(ctx, cloned, false, ""); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001469 logger.Warnw("attribute-update-failed", log.Fields{"attribute": name, "value": value})
khenaidoob9203542018-09-17 22:56:37 -04001470 }
khenaidoob9203542018-09-17 22:56:37 -04001471}
serkant.uluderya334479d2019-04-10 08:26:15 -07001472
1473func (agent *DeviceAgent) simulateAlarm(ctx context.Context, simulatereq *voltha.SimulateAlarmRequest) error {
khenaidoo442e7c72020-03-10 16:13:48 -04001474 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1475 return err
1476 }
1477 defer agent.requestQueue.RequestComplete()
Girish Kumarf56a4682020-03-20 20:07:46 +00001478 logger.Debugw("simulateAlarm", log.Fields{"id": agent.deviceID})
khenaidoo6e55d9e2019-12-12 18:26:26 -05001479
1480 cloned := agent.getDeviceWithoutLock()
1481
khenaidoo442e7c72020-03-10 16:13:48 -04001482 subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
1483 ch, err := agent.adapterProxy.simulateAlarm(subCtx, cloned, simulatereq)
1484 if err != nil {
1485 cancel()
npujar1d86a522019-11-14 17:11:16 +05301486 return err
serkant.uluderya334479d2019-04-10 08:26:15 -07001487 }
khenaidoo442e7c72020-03-10 16:13:48 -04001488 go agent.waitForAdapterResponse(subCtx, cancel, "simulateAlarm", ch, agent.onSuccess, agent.onFailure)
serkant.uluderya334479d2019-04-10 08:26:15 -07001489 return nil
1490}
Mahir Gunyelb5851672019-07-24 10:46:26 +03001491
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001492func (agent *DeviceAgent) updateDeviceStateInStoreWithoutLock(
1493 ctx context.Context,
1494 device *voltha.Device,
1495 adminState voltha.AdminState_Types,
1496 connectStatus voltha.ConnectStatus_Types,
1497 operStatus voltha.OperStatus_Types,
1498) error {
1499 previousState := getDeviceStates(device)
1500 device.AdminState, device.ConnectStatus, device.OperStatus = adminState, connectStatus, operStatus
1501
1502 if err := agent.updateDeviceInStoreWithoutLock(ctx, device, false, ""); err != nil {
1503 return err
1504 }
1505
1506 // process state transition in its own thread
1507 go func() {
1508 if err := agent.deviceMgr.processTransition(context.Background(), device, previousState); err != nil {
1509 log.Errorw("failed-process-transition", log.Fields{"deviceId": device.Id, "previousAdminState": previousState.Admin, "currentAdminState": device.AdminState})
1510 }
1511 }()
1512 return nil
1513}
1514
Mahir Gunyelb5851672019-07-24 10:46:26 +03001515//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.
1516// It is an internal helper function.
npujar467fe752020-01-16 20:17:45 +05301517func (agent *DeviceAgent) updateDeviceInStoreWithoutLock(ctx context.Context, device *voltha.Device, strict bool, txid string) error {
Kent Hagerman4f355f52020-03-30 16:01:33 -04001518 if agent.stopped {
1519 return errors.New("device agent stopped")
Thomas Lee Se5a44012019-11-07 20:32:24 +05301520 }
Kent Hagerman4f355f52020-03-30 16:01:33 -04001521
1522 updateCtx := context.WithValue(ctx, model.RequestTimestamp, time.Now().UnixNano())
1523 if err := agent.clusterDataProxy.Update(updateCtx, "devices/"+agent.deviceID, device); err != nil {
1524 return status.Errorf(codes.Internal, "failed-update-device:%s: %s", agent.deviceID, err)
Mahir Gunyelb5851672019-07-24 10:46:26 +03001525 }
Girish Kumarf56a4682020-03-20 20:07:46 +00001526 logger.Debugw("updated-device-in-store", log.Fields{"deviceId: ": agent.deviceID})
Mahir Gunyelb5851672019-07-24 10:46:26 +03001527
khenaidoo6e55d9e2019-12-12 18:26:26 -05001528 agent.device = proto.Clone(device).(*voltha.Device)
Mahir Gunyelb5851672019-07-24 10:46:26 +03001529 return nil
1530}
Mahir Gunyelfdee9212019-10-16 16:52:21 -07001531
npujar467fe752020-01-16 20:17:45 +05301532func (agent *DeviceAgent) updateDeviceReason(ctx context.Context, reason string) error {
khenaidoo442e7c72020-03-10 16:13:48 -04001533 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1534 return err
1535 }
1536 defer agent.requestQueue.RequestComplete()
khenaidoo6e55d9e2019-12-12 18:26:26 -05001537
1538 cloned := agent.getDeviceWithoutLock()
npujar1d86a522019-11-14 17:11:16 +05301539 cloned.Reason = reason
Girish Kumarf56a4682020-03-20 20:07:46 +00001540 logger.Debugw("updateDeviceReason", log.Fields{"deviceId": cloned.Id, "reason": cloned.Reason})
npujar1d86a522019-11-14 17:11:16 +05301541 // Store the device
npujar467fe752020-01-16 20:17:45 +05301542 return agent.updateDeviceInStoreWithoutLock(ctx, cloned, false, "")
Mahir Gunyelfdee9212019-10-16 16:52:21 -07001543}
kesavandbc2d1622020-01-21 00:42:01 -05001544
1545func (agent *DeviceAgent) disablePort(ctx context.Context, Port *voltha.Port) error {
khenaidoo442e7c72020-03-10 16:13:48 -04001546 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1547 return err
1548 }
1549 defer agent.requestQueue.RequestComplete()
Girish Kumarf56a4682020-03-20 20:07:46 +00001550 logger.Debugw("disablePort", log.Fields{"device-id": agent.deviceID, "port-no": Port.PortNo})
khenaidoo442e7c72020-03-10 16:13:48 -04001551 var cp *voltha.Port
kesavandbc2d1622020-01-21 00:42:01 -05001552 // Get the most up to date the device info
1553 device := agent.getDeviceWithoutLock()
1554 for _, port := range device.Ports {
1555 if port.PortNo == Port.PortNo {
1556 port.AdminState = voltha.AdminState_DISABLED
1557 cp = proto.Clone(port).(*voltha.Port)
1558 break
1559
1560 }
1561 }
1562 if cp == nil {
1563 return status.Errorf(codes.InvalidArgument, "%v", Port.PortNo)
1564 }
1565
1566 if cp.Type != voltha.Port_PON_OLT {
1567 return status.Errorf(codes.InvalidArgument, "Disabling of Port Type %v unimplemented", cp.Type)
1568 }
1569 // Store the device
1570 if err := agent.updateDeviceInStoreWithoutLock(ctx, device, false, ""); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001571 logger.Debugw("updateDeviceInStoreWithoutLock error ", log.Fields{"device-id": agent.deviceID, "port-no": Port.PortNo, "error": err})
kesavandbc2d1622020-01-21 00:42:01 -05001572 return err
1573 }
khenaidoo442e7c72020-03-10 16:13:48 -04001574
kesavandbc2d1622020-01-21 00:42:01 -05001575 //send request to adapter
khenaidoo442e7c72020-03-10 16:13:48 -04001576 subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
1577 ch, err := agent.adapterProxy.disablePort(ctx, device, cp)
1578 if err != nil {
1579 cancel()
kesavandbc2d1622020-01-21 00:42:01 -05001580 return err
1581 }
khenaidoo442e7c72020-03-10 16:13:48 -04001582 go agent.waitForAdapterResponse(subCtx, cancel, "disablePort", ch, agent.onSuccess, agent.onFailure)
kesavandbc2d1622020-01-21 00:42:01 -05001583 return nil
1584}
1585
1586func (agent *DeviceAgent) enablePort(ctx context.Context, Port *voltha.Port) error {
khenaidoo442e7c72020-03-10 16:13:48 -04001587 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1588 return err
1589 }
1590 defer agent.requestQueue.RequestComplete()
Girish Kumarf56a4682020-03-20 20:07:46 +00001591 logger.Debugw("enablePort", log.Fields{"device-id": agent.deviceID, "port-no": Port.PortNo})
khenaidoo442e7c72020-03-10 16:13:48 -04001592
1593 var cp *voltha.Port
kesavandbc2d1622020-01-21 00:42:01 -05001594 // Get the most up to date the device info
1595 device := agent.getDeviceWithoutLock()
1596 for _, port := range device.Ports {
1597 if port.PortNo == Port.PortNo {
1598 port.AdminState = voltha.AdminState_ENABLED
1599 cp = proto.Clone(port).(*voltha.Port)
1600 break
1601 }
1602 }
1603
1604 if cp == nil {
1605 return status.Errorf(codes.InvalidArgument, "%v", Port.PortNo)
1606 }
1607
1608 if cp.Type != voltha.Port_PON_OLT {
1609 return status.Errorf(codes.InvalidArgument, "Enabling of Port Type %v unimplemented", cp.Type)
1610 }
1611 // Store the device
1612 if err := agent.updateDeviceInStoreWithoutLock(ctx, device, false, ""); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001613 logger.Debugw("updateDeviceInStoreWithoutLock error ", log.Fields{"device-id": agent.deviceID, "port-no": Port.PortNo, "error": err})
kesavandbc2d1622020-01-21 00:42:01 -05001614 return err
1615 }
1616 //send request to adapter
khenaidoo442e7c72020-03-10 16:13:48 -04001617 subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
1618 ch, err := agent.adapterProxy.enablePort(ctx, device, cp)
1619 if err != nil {
1620 cancel()
kesavandbc2d1622020-01-21 00:42:01 -05001621 return err
1622 }
khenaidoo442e7c72020-03-10 16:13:48 -04001623 go agent.waitForAdapterResponse(subCtx, cancel, "enablePort", ch, agent.onSuccess, agent.onFailure)
kesavandbc2d1622020-01-21 00:42:01 -05001624 return nil
1625}
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001626
1627func (agent *DeviceAgent) ChildDeviceLost(ctx context.Context, device *voltha.Device) error {
khenaidoo442e7c72020-03-10 16:13:48 -04001628 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1629 return err
1630 }
1631 defer agent.requestQueue.RequestComplete()
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001632
Girish Kumarf56a4682020-03-20 20:07:46 +00001633 logger.Debugw("childDeviceLost", log.Fields{"child-device-id": device.Id, "parent-device-ud": agent.deviceID})
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001634
1635 //Remove the associated peer ports on the parent device
khenaidoo442e7c72020-03-10 16:13:48 -04001636 parentDevice := agent.getDeviceWithoutLock()
1637 var updatedPeers []*voltha.Port_PeerPort
1638 for _, port := range parentDevice.Ports {
1639 updatedPeers = make([]*voltha.Port_PeerPort, 0)
1640 for _, peerPort := range port.Peers {
1641 if peerPort.DeviceId != device.Id {
1642 updatedPeers = append(updatedPeers, peerPort)
1643 }
1644 }
1645 port.Peers = updatedPeers
1646 }
1647 if err := agent.updateDeviceInStoreWithoutLock(ctx, parentDevice, false, ""); err != nil {
1648 return err
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001649 }
1650
khenaidoo442e7c72020-03-10 16:13:48 -04001651 //send request to adapter
1652 subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
1653 ch, err := agent.adapterProxy.childDeviceLost(ctx, agent.deviceType, agent.deviceID, device.ParentPortNo, device.ProxyAddress.OnuId)
1654 if err != nil {
1655 cancel()
1656 return err
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001657 }
khenaidoo442e7c72020-03-10 16:13:48 -04001658 go agent.waitForAdapterResponse(subCtx, cancel, "childDeviceLost", ch, agent.onSuccess, agent.onFailure)
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001659 return nil
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001660}
onkarkundargi87285252020-01-27 11:34:52 +05301661
1662func (agent *DeviceAgent) startOmciTest(ctx context.Context, omcitestrequest *voltha.OmciTestRequest) (*voltha.TestResponse, error) {
1663 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1664 return nil, err
1665 }
1666
1667 device := agent.getDeviceWithoutLock()
1668 adapterName, err := agent.adapterMgr.getAdapterName(device.Type)
1669 if err != nil {
1670 agent.requestQueue.RequestComplete()
1671 return nil, err
1672 }
1673
1674 // Send request to the adapter
1675 device.Adapter = adapterName
1676 ch, err := agent.adapterProxy.startOmciTest(ctx, device, omcitestrequest)
1677 agent.requestQueue.RequestComplete()
1678 if err != nil {
1679 return nil, err
1680 }
1681
1682 // Wait for the adapter response
1683 rpcResponse, ok := <-ch
1684 if !ok {
1685 return nil, status.Errorf(codes.Aborted, "channel-closed-device-id-%s", agent.deviceID)
1686 }
1687 if rpcResponse.Err != nil {
1688 return nil, rpcResponse.Err
1689 }
1690
1691 // Unmarshal and return the response
1692 testResp := &voltha.TestResponse{}
1693 if err := ptypes.UnmarshalAny(rpcResponse.Reply, testResp); err != nil {
1694 return nil, status.Errorf(codes.InvalidArgument, "%s", err.Error())
1695 }
Girish Kumarf56a4682020-03-20 20:07:46 +00001696 logger.Debugw("Omci_test_Request-Success-device-agent", log.Fields{"testResp": testResp})
onkarkundargi87285252020-01-27 11:34:52 +05301697 return testResp, nil
1698}