blob: 1cc167356d56b5e5b9d27e10f9115065153c6b8c [file] [log] [blame]
khenaidoob9203542018-09-17 22:56:37 -04001/*
2 * Copyright 2018-present Open Networking Foundation
3
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7
8 * http://www.apache.org/licenses/LICENSE-2.0
9
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
npujar1d86a522019-11-14 17:11:16 +053016
khenaidoob9203542018-09-17 22:56:37 -040017package core
18
19import (
20 "context"
Matteo Scandolo360605d2019-11-05 18:29:17 -080021 "encoding/hex"
khenaidoo3ab34882019-05-02 21:33:30 -040022 "fmt"
Chaitrashree G Sa773e992019-09-09 21:04:15 -040023 "reflect"
24 "sync"
25 "time"
26
khenaidoob9203542018-09-17 22:56:37 -040027 "github.com/gogo/protobuf/proto"
sbarbari17d7e222019-11-05 10:02:29 -050028 "github.com/opencord/voltha-go/db/model"
Scott Bakerb671a862019-10-24 10:53:40 -070029 coreutils "github.com/opencord/voltha-go/rw_core/utils"
Scott Baker807addd2019-10-24 15:16:21 -070030 fu "github.com/opencord/voltha-lib-go/v2/pkg/flows"
31 "github.com/opencord/voltha-lib-go/v2/pkg/log"
Scott Baker555307d2019-11-04 08:58:01 -080032 ic "github.com/opencord/voltha-protos/v2/go/inter_container"
33 ofp "github.com/opencord/voltha-protos/v2/go/openflow_13"
34 "github.com/opencord/voltha-protos/v2/go/voltha"
khenaidoob9203542018-09-17 22:56:37 -040035 "google.golang.org/grpc/codes"
36 "google.golang.org/grpc/status"
khenaidoob9203542018-09-17 22:56:37 -040037)
38
npujar1d86a522019-11-14 17:11:16 +053039// DeviceAgent represents device agent attributes
khenaidoob9203542018-09-17 22:56:37 -040040type DeviceAgent struct {
npujar1d86a522019-11-14 17:11:16 +053041 deviceID string
42 parentID string
khenaidoo43c82122018-11-22 18:38:28 -050043 deviceType string
khenaidoo2c6a0992019-04-29 13:46:56 -040044 isRootdevice bool
khenaidoo9a468962018-09-19 15:33:13 -040045 adapterProxy *AdapterProxy
serkant.uluderya334479d2019-04-10 08:26:15 -070046 adapterMgr *AdapterManager
khenaidoo9a468962018-09-19 15:33:13 -040047 deviceMgr *DeviceManager
48 clusterDataProxy *model.Proxy
khenaidoo92e62c52018-10-03 14:02:54 -040049 deviceProxy *model.Proxy
khenaidoo9a468962018-09-19 15:33:13 -040050 exitChannel chan int
khenaidoo92e62c52018-10-03 14:02:54 -040051 lockDevice sync.RWMutex
khenaidoo2c6a0992019-04-29 13:46:56 -040052 defaultTimeout int64
khenaidoob9203542018-09-17 22:56:37 -040053}
54
Scott Baker80678602019-11-14 16:57:36 -080055//newDeviceAgent creates a new device agent. The device will be initialized when start() is called.
khenaidoo2c6a0992019-04-29 13:46:56 -040056func newDeviceAgent(ap *AdapterProxy, device *voltha.Device, deviceMgr *DeviceManager, cdProxy *model.Proxy, timeout int64) *DeviceAgent {
khenaidoob9203542018-09-17 22:56:37 -040057 var agent DeviceAgent
khenaidoob9203542018-09-17 22:56:37 -040058 agent.adapterProxy = ap
Scott Baker80678602019-11-14 16:57:36 -080059 if device.Id == "" {
npujar1d86a522019-11-14 17:11:16 +053060 agent.deviceID = CreateDeviceID()
Scott Baker80678602019-11-14 16:57:36 -080061 } else {
npujar1d86a522019-11-14 17:11:16 +053062 agent.deviceID = device.Id
Stephane Barbarie1ab43272018-12-08 21:42:13 -050063 }
Scott Baker80678602019-11-14 16:57:36 -080064
khenaidoo2c6a0992019-04-29 13:46:56 -040065 agent.isRootdevice = device.Root
npujar1d86a522019-11-14 17:11:16 +053066 agent.parentID = device.ParentId
Scott Baker80678602019-11-14 16:57:36 -080067 agent.deviceType = device.Type
khenaidoob9203542018-09-17 22:56:37 -040068 agent.deviceMgr = deviceMgr
khenaidoo21d51152019-02-01 13:48:37 -050069 agent.adapterMgr = deviceMgr.adapterMgr
khenaidoob9203542018-09-17 22:56:37 -040070 agent.exitChannel = make(chan int, 1)
khenaidoo9a468962018-09-19 15:33:13 -040071 agent.clusterDataProxy = cdProxy
khenaidoo92e62c52018-10-03 14:02:54 -040072 agent.lockDevice = sync.RWMutex{}
khenaidoo2c6a0992019-04-29 13:46:56 -040073 agent.defaultTimeout = timeout
khenaidoob9203542018-09-17 22:56:37 -040074 return &agent
75}
76
Scott Baker80678602019-11-14 16:57:36 -080077// start()
78// save the device to the data model and registers for callbacks on that device if deviceToCreate!=nil. Otherwise,
npujar1d86a522019-11-14 17:11:16 +053079// 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 -080080// was started.
81func (agent *DeviceAgent) start(ctx context.Context, deviceToCreate *voltha.Device) (*voltha.Device, error) {
82 var device *voltha.Device
83
khenaidoo92e62c52018-10-03 14:02:54 -040084 agent.lockDevice.Lock()
85 defer agent.lockDevice.Unlock()
npujar1d86a522019-11-14 17:11:16 +053086 log.Debugw("starting-device-agent", log.Fields{"deviceId": agent.deviceID})
Scott Baker80678602019-11-14 16:57:36 -080087 if deviceToCreate == nil {
88 // Load the existing device
npujar1d86a522019-11-14 17:11:16 +053089 if loadedDevice := agent.clusterDataProxy.Get(ctx, "/devices/"+agent.deviceID, 1, true, ""); loadedDevice != nil {
Scott Baker80678602019-11-14 16:57:36 -080090 var ok bool
91 if device, ok = loadedDevice.(*voltha.Device); ok {
92 agent.deviceType = device.Adapter
93 } else {
npujar1d86a522019-11-14 17:11:16 +053094 log.Errorw("failed-to-convert-device", log.Fields{"deviceId": agent.deviceID})
95 return nil, status.Errorf(codes.NotFound, "device-%s", agent.deviceID)
khenaidoo297cd252019-02-07 22:10:23 -050096 }
97 } else {
npujar1d86a522019-11-14 17:11:16 +053098 log.Errorw("failed-to-load-device", log.Fields{"deviceId": agent.deviceID})
99 return nil, status.Errorf(codes.NotFound, "device-%s", agent.deviceID)
khenaidoo297cd252019-02-07 22:10:23 -0500100 }
npujar1d86a522019-11-14 17:11:16 +0530101 log.Debugw("device-loaded-from-dB", log.Fields{"deviceId": agent.deviceID})
khenaidoo297cd252019-02-07 22:10:23 -0500102 } else {
Scott Baker80678602019-11-14 16:57:36 -0800103 // Create a new device
104 // Assumption is that AdminState, FlowGroups, and Flows are unitialized since this
105 // is a new device, so populate them here before passing the device to clusterDataProxy.AddWithId.
106 // agent.deviceId will also have been set during newDeviceAgent().
107 device = (proto.Clone(deviceToCreate)).(*voltha.Device)
npujar1d86a522019-11-14 17:11:16 +0530108 device.Id = agent.deviceID
Scott Baker80678602019-11-14 16:57:36 -0800109 device.AdminState = voltha.AdminState_PREPROVISIONED
110 device.FlowGroups = &ofp.FlowGroups{Items: nil}
111 device.Flows = &ofp.Flows{Items: nil}
112 if !deviceToCreate.GetRoot() && deviceToCreate.ProxyAddress != nil {
113 // Set the default vlan ID to the one specified by the parent adapter. It can be
114 // overwritten by the child adapter during a device update request
115 device.Vlan = deviceToCreate.ProxyAddress.ChannelId
116 }
117
khenaidoo297cd252019-02-07 22:10:23 -0500118 // Add the initial device to the local model
npujar1d86a522019-11-14 17:11:16 +0530119 if added := agent.clusterDataProxy.AddWithID(ctx, "/devices", agent.deviceID, device, ""); added == nil {
120 log.Errorw("failed-to-add-device", log.Fields{"deviceId": agent.deviceID})
121 return nil, status.Errorf(codes.Aborted, "failed-adding-device-%s", agent.deviceID)
khenaidoo297cd252019-02-07 22:10:23 -0500122 }
khenaidoob9203542018-09-17 22:56:37 -0400123 }
khenaidoo297cd252019-02-07 22:10:23 -0500124
npujar1d86a522019-11-14 17:11:16 +0530125 agent.deviceProxy = agent.clusterDataProxy.CreateProxy(ctx, "/devices/"+agent.deviceID, false)
khenaidoo43c82122018-11-22 18:38:28 -0500126 agent.deviceProxy.RegisterCallback(model.POST_UPDATE, agent.processUpdate)
khenaidoo19d7b632018-10-30 10:49:50 -0400127
npujar1d86a522019-11-14 17:11:16 +0530128 log.Debugw("device-agent-started", log.Fields{"deviceId": agent.deviceID})
Scott Baker80678602019-11-14 16:57:36 -0800129 return device, nil
khenaidoob9203542018-09-17 22:56:37 -0400130}
131
khenaidoo4d4802d2018-10-04 21:59:49 -0400132// stop stops the device agent. Not much to do for now
133func (agent *DeviceAgent) stop(ctx context.Context) {
khenaidoo92e62c52018-10-03 14:02:54 -0400134 agent.lockDevice.Lock()
135 defer agent.lockDevice.Unlock()
khenaidoob9203542018-09-17 22:56:37 -0400136 log.Debug("stopping-device-agent")
khenaidoo0a822f92019-05-08 15:15:57 -0400137 // Remove the device from the KV store
npujar1d86a522019-11-14 17:11:16 +0530138 if removed := agent.clusterDataProxy.Remove(ctx, "/devices/"+agent.deviceID, ""); removed == nil {
139 log.Debugw("device-already-removed", log.Fields{"id": agent.deviceID})
khenaidoo0a822f92019-05-08 15:15:57 -0400140 }
khenaidoob9203542018-09-17 22:56:37 -0400141 agent.exitChannel <- 1
142 log.Debug("device-agent-stopped")
khenaidoo0a822f92019-05-08 15:15:57 -0400143
khenaidoob9203542018-09-17 22:56:37 -0400144}
145
Scott Baker80678602019-11-14 16:57:36 -0800146// Load the most recent state from the KVStore for the device.
147func (agent *DeviceAgent) reconcileWithKVStore() {
148 agent.lockDevice.Lock()
149 defer agent.lockDevice.Unlock()
150 log.Debug("reconciling-device-agent-devicetype")
151 // TODO: context timeout
npujar1d86a522019-11-14 17:11:16 +0530152 if device := agent.clusterDataProxy.Get(context.Background(), "/devices/"+agent.deviceID, 1, true, ""); device != nil {
Scott Baker80678602019-11-14 16:57:36 -0800153 if d, ok := device.(*voltha.Device); ok {
154 agent.deviceType = d.Adapter
npujar1d86a522019-11-14 17:11:16 +0530155 log.Debugw("reconciled-device-agent-devicetype", log.Fields{"Id": agent.deviceID, "type": agent.deviceType})
Scott Baker80678602019-11-14 16:57:36 -0800156 }
157 }
158}
159
khenaidoo19d7b632018-10-30 10:49:50 -0400160// GetDevice retrieves the latest device information from the data model
khenaidoo92e62c52018-10-03 14:02:54 -0400161func (agent *DeviceAgent) getDevice() (*voltha.Device, error) {
khenaidoo1ce37ad2019-03-24 22:07:24 -0400162 agent.lockDevice.RLock()
163 defer agent.lockDevice.RUnlock()
npujar1d86a522019-11-14 17:11:16 +0530164 if device := agent.clusterDataProxy.Get(context.Background(), "/devices/"+agent.deviceID, 0, false, ""); device != nil {
khenaidoo92e62c52018-10-03 14:02:54 -0400165 if d, ok := device.(*voltha.Device); ok {
166 cloned := proto.Clone(d).(*voltha.Device)
167 return cloned, nil
168 }
169 }
npujar1d86a522019-11-14 17:11:16 +0530170 return nil, status.Errorf(codes.NotFound, "device-%s", agent.deviceID)
khenaidoo92e62c52018-10-03 14:02:54 -0400171}
172
khenaidoo4d4802d2018-10-04 21:59:49 -0400173// getDeviceWithoutLock is a helper function to be used ONLY by any device agent function AFTER it has acquired the device lock.
khenaidoo92e62c52018-10-03 14:02:54 -0400174// This function is meant so that we do not have duplicate code all over the device agent functions
175func (agent *DeviceAgent) getDeviceWithoutLock() (*voltha.Device, error) {
npujar1d86a522019-11-14 17:11:16 +0530176 if device := agent.clusterDataProxy.Get(context.Background(), "/devices/"+agent.deviceID, 0, false, ""); device != nil {
khenaidoo92e62c52018-10-03 14:02:54 -0400177 if d, ok := device.(*voltha.Device); ok {
178 cloned := proto.Clone(d).(*voltha.Device)
179 return cloned, nil
180 }
181 }
npujar1d86a522019-11-14 17:11:16 +0530182 return nil, status.Errorf(codes.NotFound, "device-%s", agent.deviceID)
khenaidoo92e62c52018-10-03 14:02:54 -0400183}
184
khenaidoo3ab34882019-05-02 21:33:30 -0400185// enableDevice activates a preprovisioned or a disable device
khenaidoob9203542018-09-17 22:56:37 -0400186func (agent *DeviceAgent) enableDevice(ctx context.Context) error {
khenaidoo92e62c52018-10-03 14:02:54 -0400187 agent.lockDevice.Lock()
188 defer agent.lockDevice.Unlock()
npujar1d86a522019-11-14 17:11:16 +0530189 log.Debugw("enableDevice", log.Fields{"id": agent.deviceID})
khenaidoo21d51152019-02-01 13:48:37 -0500190
npujar1d86a522019-11-14 17:11:16 +0530191 device, err := agent.getDeviceWithoutLock()
192 if err != nil {
193 return status.Errorf(codes.NotFound, "%s", agent.deviceID)
194 }
195 // First figure out which adapter will handle this device type. We do it at this stage as allow devices to be
196 // pre-provisionned with the required adapter not registered. At this stage, since we need to communicate
197 // with the adapter then we need to know the adapter that will handle this request
198 adapterName, err := agent.adapterMgr.getAdapterName(device.Type)
199 if err != nil {
200 log.Warnw("no-adapter-registered-for-device-type", log.Fields{"deviceType": device.Type, "deviceAdapter": device.Adapter})
201 return err
202 }
203 device.Adapter = adapterName
204
205 if device.AdminState == voltha.AdminState_ENABLED {
206 log.Debugw("device-already-enabled", log.Fields{"id": agent.deviceID})
207 return nil
208 }
209
210 if device.AdminState == voltha.AdminState_DELETED {
211 // This is a temporary state when a device is deleted before it gets removed from the model.
212 err = status.Error(codes.FailedPrecondition, fmt.Sprintf("cannot-enable-a-deleted-device: %s ", device.Id))
213 log.Warnw("invalid-state", log.Fields{"id": agent.deviceID, "state": device.AdminState, "error": err})
214 return err
215 }
216
217 previousAdminState := device.AdminState
218
219 // Update the Admin State and set the operational state to activating before sending the request to the
220 // Adapters
221 cloned := proto.Clone(device).(*voltha.Device)
222 cloned.AdminState = voltha.AdminState_ENABLED
223 cloned.OperStatus = voltha.OperStatus_ACTIVATING
224
225 if err := agent.updateDeviceInStoreWithoutLock(cloned, false, ""); err != nil {
226 return err
227 }
228
229 // Adopt the device if it was in preprovision state. In all other cases, try to reenable it.
230 if previousAdminState == voltha.AdminState_PREPROVISIONED {
231 if err := agent.adapterProxy.AdoptDevice(ctx, device); err != nil {
232 log.Debugw("adoptDevice-error", log.Fields{"id": agent.deviceID, "error": err})
233 return err
234 }
khenaidoob9203542018-09-17 22:56:37 -0400235 } else {
npujar1d86a522019-11-14 17:11:16 +0530236 if err := agent.adapterProxy.ReEnableDevice(ctx, device); err != nil {
237 log.Debugw("renableDevice-error", log.Fields{"id": agent.deviceID, "error": err})
khenaidoo21d51152019-02-01 13:48:37 -0500238 return err
khenaidoob9203542018-09-17 22:56:37 -0400239 }
240 }
241 return nil
242}
243
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500244func (agent *DeviceAgent) sendBulkFlowsToAdapters(device *voltha.Device, flows *voltha.Flows, groups *voltha.FlowGroups, flowMetadata *voltha.FlowMetadata, response coreutils.Response) {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400245 if err := agent.adapterProxy.UpdateFlowsBulk(device, flows, groups, flowMetadata); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530246 log.Debugw("update-flow-bulk-error", log.Fields{"id": agent.deviceID, "error": err})
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500247 response.Error(err)
khenaidoo2c6a0992019-04-29 13:46:56 -0400248 }
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500249 response.Done()
khenaidoo2c6a0992019-04-29 13:46:56 -0400250}
251
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500252func (agent *DeviceAgent) sendIncrementalFlowsToAdapters(device *voltha.Device, flows *ofp.FlowChanges, groups *ofp.FlowGroupChanges, flowMetadata *voltha.FlowMetadata, response coreutils.Response) {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400253 if err := agent.adapterProxy.UpdateFlowsIncremental(device, flows, groups, flowMetadata); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530254 log.Debugw("update-flow-incremental-error", log.Fields{"id": agent.deviceID, "error": err})
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500255 response.Error(err)
khenaidoo2c6a0992019-04-29 13:46:56 -0400256 }
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500257 response.Done()
khenaidoo2c6a0992019-04-29 13:46:56 -0400258}
259
A R Karthick5c28f552019-12-11 22:47:44 -0800260func (agent *DeviceAgent) addFlowsAndGroupsToAdapter(newFlows []*ofp.OfpFlowStats, newGroups []*ofp.OfpGroupEntry, flowMetadata *voltha.FlowMetadata) (coreutils.Response, error) {
npujar1d86a522019-11-14 17:11:16 +0530261 log.Debugw("addFlowsAndGroups", log.Fields{"deviceId": agent.deviceID, "flows": newFlows, "groups": newGroups, "flowMetadata": flowMetadata})
khenaidoo0458db62019-06-20 08:50:36 -0400262
khenaidoo2c6a0992019-04-29 13:46:56 -0400263 if (len(newFlows) | len(newGroups)) == 0 {
npujar1d86a522019-11-14 17:11:16 +0530264 log.Debugw("nothing-to-update", log.Fields{"deviceId": agent.deviceID, "flows": newFlows, "groups": newGroups})
A R Karthick5c28f552019-12-11 22:47:44 -0800265 return coreutils.DoneResponse(), nil
khenaidoo2c6a0992019-04-29 13:46:56 -0400266 }
267
khenaidoo19d7b632018-10-30 10:49:50 -0400268 agent.lockDevice.Lock()
269 defer agent.lockDevice.Unlock()
khenaidoo2c6a0992019-04-29 13:46:56 -0400270
khenaidoo0458db62019-06-20 08:50:36 -0400271 var device *voltha.Device
272 var err error
273 if device, err = agent.getDeviceWithoutLock(); err != nil {
A R Karthick5c28f552019-12-11 22:47:44 -0800274 return coreutils.DoneResponse(), status.Errorf(codes.NotFound, "%s", agent.deviceID)
khenaidoo0458db62019-06-20 08:50:36 -0400275 }
276
277 existingFlows := proto.Clone(device.Flows).(*voltha.Flows)
278 existingGroups := proto.Clone(device.FlowGroups).(*ofp.FlowGroups)
279
280 var updatedFlows []*ofp.OfpFlowStats
281 var flowsToDelete []*ofp.OfpFlowStats
Matt Jeanneret518b5a42019-10-29 10:30:46 -0400282 var groupsToDelete []*ofp.OfpGroupEntry
khenaidoo0458db62019-06-20 08:50:36 -0400283 var updatedGroups []*ofp.OfpGroupEntry
284
285 // Process flows
npujar1d86a522019-11-14 17:11:16 +0530286 updatedFlows = append(updatedFlows, newFlows...)
khenaidoo0458db62019-06-20 08:50:36 -0400287 for _, flow := range existingFlows.Items {
288 if idx := fu.FindFlows(newFlows, flow); idx == -1 {
Matt Jeanneret518b5a42019-10-29 10:30:46 -0400289 updatedFlows = append(updatedFlows, flow)
khenaidoo0458db62019-06-20 08:50:36 -0400290 } else {
291 flowsToDelete = append(flowsToDelete, flow)
292 }
293 }
294
295 // Process groups
npujar1d86a522019-11-14 17:11:16 +0530296 updatedGroups = append(updatedGroups, newGroups...)
khenaidoo0458db62019-06-20 08:50:36 -0400297 for _, group := range existingGroups.Items {
Matt Jeanneret518b5a42019-10-29 10:30:46 -0400298 if fu.FindGroup(newGroups, group.Desc.GroupId) == -1 { // does not exist now
299 updatedGroups = append(updatedGroups, group)
300 } else {
301 groupsToDelete = append(groupsToDelete, group)
khenaidoo0458db62019-06-20 08:50:36 -0400302 }
303 }
304
305 // Sanity check
Matt Jeanneret518b5a42019-10-29 10:30:46 -0400306 if (len(updatedFlows) | len(flowsToDelete) | len(updatedGroups) | len(groupsToDelete)) == 0 {
npujar1d86a522019-11-14 17:11:16 +0530307 log.Debugw("nothing-to-update", log.Fields{"deviceId": agent.deviceID, "flows": newFlows, "groups": newGroups})
A R Karthick5c28f552019-12-11 22:47:44 -0800308 return coreutils.DoneResponse(), nil
khenaidoo0458db62019-06-20 08:50:36 -0400309 }
310
311 // Send update to adapters
312 // Create two channels to receive responses from the dB and from the adapters.
313 // Do not close these channels as this function may exit on timeout before the dB or adapters get a chance
314 // to send their responses. These channels will be garbage collected once all the responses are
315 // received
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500316 response := coreutils.NewResponse()
khenaidoo0458db62019-06-20 08:50:36 -0400317 dType := agent.adapterMgr.getDeviceType(device.Type)
318 if !dType.AcceptsAddRemoveFlowUpdates {
319
320 if len(updatedGroups) != 0 && reflect.DeepEqual(existingGroups.Items, updatedGroups) && len(updatedFlows) != 0 && reflect.DeepEqual(existingFlows.Items, updatedFlows) {
npujar1d86a522019-11-14 17:11:16 +0530321 log.Debugw("nothing-to-update", log.Fields{"deviceId": agent.deviceID, "flows": newFlows, "groups": newGroups})
A R Karthick5c28f552019-12-11 22:47:44 -0800322 return coreutils.DoneResponse(), nil
khenaidoo0458db62019-06-20 08:50:36 -0400323 }
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500324 go agent.sendBulkFlowsToAdapters(device, &voltha.Flows{Items: updatedFlows}, &voltha.FlowGroups{Items: updatedGroups}, flowMetadata, response)
khenaidoo0458db62019-06-20 08:50:36 -0400325
326 } else {
327 flowChanges := &ofp.FlowChanges{
Matt Jeanneret518b5a42019-10-29 10:30:46 -0400328 ToAdd: &voltha.Flows{Items: newFlows},
khenaidoo0458db62019-06-20 08:50:36 -0400329 ToRemove: &voltha.Flows{Items: flowsToDelete},
330 }
331 groupChanges := &ofp.FlowGroupChanges{
Matt Jeanneret518b5a42019-10-29 10:30:46 -0400332 ToAdd: &voltha.FlowGroups{Items: newGroups},
333 ToRemove: &voltha.FlowGroups{Items: groupsToDelete},
khenaidoo0458db62019-06-20 08:50:36 -0400334 ToUpdate: &voltha.FlowGroups{Items: []*ofp.OfpGroupEntry{}},
335 }
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500336 go agent.sendIncrementalFlowsToAdapters(device, flowChanges, groupChanges, flowMetadata, response)
khenaidoo0458db62019-06-20 08:50:36 -0400337 }
338
339 // store the changed data
340 device.Flows = &voltha.Flows{Items: updatedFlows}
341 device.FlowGroups = &voltha.FlowGroups{Items: updatedGroups}
Kent Hagerman3c513972019-11-25 13:49:41 -0500342 if err := agent.updateDeviceWithoutLock(device); err != nil {
A R Karthick5c28f552019-12-11 22:47:44 -0800343 return coreutils.DoneResponse(), status.Errorf(codes.Internal, "failure-updating-%s", agent.deviceID)
Kent Hagerman3c513972019-11-25 13:49:41 -0500344 }
khenaidoo0458db62019-06-20 08:50:36 -0400345
A R Karthick5c28f552019-12-11 22:47:44 -0800346 return response, nil
347}
348
349//addFlowsAndGroups adds the "newFlows" and "newGroups" from the existing flows/groups and sends the update to the
350//adapters
351func (agent *DeviceAgent) addFlowsAndGroups(newFlows []*ofp.OfpFlowStats, newGroups []*ofp.OfpGroupEntry, flowMetadata *voltha.FlowMetadata) error {
352 response, err := agent.addFlowsAndGroupsToAdapter(newFlows, newGroups, flowMetadata)
353 if err != nil {
354 return err
355 }
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500356 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, response); res != nil {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400357 log.Debugw("Failed to get response from adapter[or] DB", log.Fields{"result": res})
khenaidoo0458db62019-06-20 08:50:36 -0400358 return status.Errorf(codes.Aborted, "errors-%s", res)
359 }
khenaidoo0458db62019-06-20 08:50:36 -0400360 return nil
361}
362
A R Karthick5c28f552019-12-11 22:47:44 -0800363func (agent *DeviceAgent) deleteFlowsAndGroupsFromAdapter(flowsToDel []*ofp.OfpFlowStats, groupsToDel []*ofp.OfpGroupEntry, flowMetadata *voltha.FlowMetadata) (coreutils.Response, error) {
npujar1d86a522019-11-14 17:11:16 +0530364 log.Debugw("deleteFlowsAndGroups", log.Fields{"deviceId": agent.deviceID, "flows": flowsToDel, "groups": groupsToDel})
khenaidoo0458db62019-06-20 08:50:36 -0400365
366 if (len(flowsToDel) | len(groupsToDel)) == 0 {
npujar1d86a522019-11-14 17:11:16 +0530367 log.Debugw("nothing-to-update", log.Fields{"deviceId": agent.deviceID, "flows": flowsToDel, "groups": groupsToDel})
A R Karthick5c28f552019-12-11 22:47:44 -0800368 return coreutils.DoneResponse(), nil
khenaidoo0458db62019-06-20 08:50:36 -0400369 }
370
371 agent.lockDevice.Lock()
372 defer agent.lockDevice.Unlock()
373
374 var device *voltha.Device
375 var err error
376
377 if device, err = agent.getDeviceWithoutLock(); err != nil {
A R Karthick5c28f552019-12-11 22:47:44 -0800378 return coreutils.DoneResponse(), status.Errorf(codes.NotFound, "%s", agent.deviceID)
khenaidoo0458db62019-06-20 08:50:36 -0400379 }
380
381 existingFlows := proto.Clone(device.Flows).(*voltha.Flows)
382 existingGroups := proto.Clone(device.FlowGroups).(*ofp.FlowGroups)
383
384 var flowsToKeep []*ofp.OfpFlowStats
385 var groupsToKeep []*ofp.OfpGroupEntry
386
387 // Process flows
388 for _, flow := range existingFlows.Items {
389 if idx := fu.FindFlows(flowsToDel, flow); idx == -1 {
390 flowsToKeep = append(flowsToKeep, flow)
391 }
392 }
393
394 // Process groups
395 for _, group := range existingGroups.Items {
396 if fu.FindGroup(groupsToDel, group.Desc.GroupId) == -1 { // does not exist now
397 groupsToKeep = append(groupsToKeep, group)
398 }
399 }
400
401 log.Debugw("deleteFlowsAndGroups",
402 log.Fields{
npujar1d86a522019-11-14 17:11:16 +0530403 "deviceId": agent.deviceID,
khenaidoo0458db62019-06-20 08:50:36 -0400404 "flowsToDel": len(flowsToDel),
405 "flowsToKeep": len(flowsToKeep),
406 "groupsToDel": len(groupsToDel),
407 "groupsToKeep": len(groupsToKeep),
408 })
409
410 // Sanity check
411 if (len(flowsToKeep) | len(flowsToDel) | len(groupsToKeep) | len(groupsToDel)) == 0 {
npujar1d86a522019-11-14 17:11:16 +0530412 log.Debugw("nothing-to-update", log.Fields{"deviceId": agent.deviceID, "flowsToDel": flowsToDel, "groupsToDel": groupsToDel})
A R Karthick5c28f552019-12-11 22:47:44 -0800413 return coreutils.DoneResponse(), nil
khenaidoo0458db62019-06-20 08:50:36 -0400414 }
415
416 // Send update to adapters
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500417 response := coreutils.NewResponse()
khenaidoo0458db62019-06-20 08:50:36 -0400418 dType := agent.adapterMgr.getDeviceType(device.Type)
419 if !dType.AcceptsAddRemoveFlowUpdates {
420 if len(groupsToKeep) != 0 && reflect.DeepEqual(existingGroups.Items, groupsToKeep) && len(flowsToKeep) != 0 && reflect.DeepEqual(existingFlows.Items, flowsToKeep) {
npujar1d86a522019-11-14 17:11:16 +0530421 log.Debugw("nothing-to-update", log.Fields{"deviceId": agent.deviceID, "flowsToDel": flowsToDel, "groupsToDel": groupsToDel})
A R Karthick5c28f552019-12-11 22:47:44 -0800422 return coreutils.DoneResponse(), nil
khenaidoo0458db62019-06-20 08:50:36 -0400423 }
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500424 go agent.sendBulkFlowsToAdapters(device, &voltha.Flows{Items: flowsToKeep}, &voltha.FlowGroups{Items: groupsToKeep}, flowMetadata, response)
khenaidoo0458db62019-06-20 08:50:36 -0400425 } else {
426 flowChanges := &ofp.FlowChanges{
427 ToAdd: &voltha.Flows{Items: []*ofp.OfpFlowStats{}},
428 ToRemove: &voltha.Flows{Items: flowsToDel},
429 }
430 groupChanges := &ofp.FlowGroupChanges{
431 ToAdd: &voltha.FlowGroups{Items: []*ofp.OfpGroupEntry{}},
432 ToRemove: &voltha.FlowGroups{Items: groupsToDel},
433 ToUpdate: &voltha.FlowGroups{Items: []*ofp.OfpGroupEntry{}},
434 }
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500435 go agent.sendIncrementalFlowsToAdapters(device, flowChanges, groupChanges, flowMetadata, response)
khenaidoo0458db62019-06-20 08:50:36 -0400436 }
437
438 // store the changed data
439 device.Flows = &voltha.Flows{Items: flowsToKeep}
440 device.FlowGroups = &voltha.FlowGroups{Items: groupsToKeep}
Kent Hagerman3c513972019-11-25 13:49:41 -0500441 if err := agent.updateDeviceWithoutLock(device); err != nil {
A R Karthick5c28f552019-12-11 22:47:44 -0800442 return coreutils.DoneResponse(), status.Errorf(codes.Internal, "failure-updating-%s", agent.deviceID)
Kent Hagerman3c513972019-11-25 13:49:41 -0500443 }
khenaidoo0458db62019-06-20 08:50:36 -0400444
A R Karthick5c28f552019-12-11 22:47:44 -0800445 return response, nil
446
447}
448
449//deleteFlowsAndGroups removes the "flowsToDel" and "groupsToDel" from the existing flows/groups and sends the update to the
450//adapters
451func (agent *DeviceAgent) deleteFlowsAndGroups(flowsToDel []*ofp.OfpFlowStats, groupsToDel []*ofp.OfpGroupEntry, flowMetadata *voltha.FlowMetadata) error {
452 response, err := agent.deleteFlowsAndGroupsFromAdapter(flowsToDel, groupsToDel, flowMetadata)
453 if err != nil {
454 return err
455 }
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500456 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, response); res != nil {
khenaidoo0458db62019-06-20 08:50:36 -0400457 return status.Errorf(codes.Aborted, "errors-%s", res)
458 }
459 return nil
khenaidoo0458db62019-06-20 08:50:36 -0400460}
461
A R Karthick5c28f552019-12-11 22:47:44 -0800462func (agent *DeviceAgent) updateFlowsAndGroupsToAdapter(updatedFlows []*ofp.OfpFlowStats, updatedGroups []*ofp.OfpGroupEntry, flowMetadata *voltha.FlowMetadata) (coreutils.Response, error) {
npujar1d86a522019-11-14 17:11:16 +0530463 log.Debugw("updateFlowsAndGroups", log.Fields{"deviceId": agent.deviceID, "flows": updatedFlows, "groups": updatedGroups})
khenaidoo0458db62019-06-20 08:50:36 -0400464
465 if (len(updatedFlows) | len(updatedGroups)) == 0 {
npujar1d86a522019-11-14 17:11:16 +0530466 log.Debugw("nothing-to-update", log.Fields{"deviceId": agent.deviceID, "flows": updatedFlows, "groups": updatedGroups})
A R Karthick5c28f552019-12-11 22:47:44 -0800467 return coreutils.DoneResponse(), nil
khenaidoo0458db62019-06-20 08:50:36 -0400468 }
469
470 agent.lockDevice.Lock()
471 defer agent.lockDevice.Unlock()
472 var device *voltha.Device
473 var err error
474 if device, err = agent.getDeviceWithoutLock(); err != nil {
A R Karthick5c28f552019-12-11 22:47:44 -0800475 return coreutils.DoneResponse(), status.Errorf(codes.NotFound, "%s", agent.deviceID)
khenaidoo0458db62019-06-20 08:50:36 -0400476 }
477 existingFlows := proto.Clone(device.Flows).(*voltha.Flows)
478 existingGroups := proto.Clone(device.FlowGroups).(*ofp.FlowGroups)
479
480 if len(updatedGroups) != 0 && reflect.DeepEqual(existingGroups.Items, updatedGroups) && len(updatedFlows) != 0 && reflect.DeepEqual(existingFlows.Items, updatedFlows) {
npujar1d86a522019-11-14 17:11:16 +0530481 log.Debugw("nothing-to-update", log.Fields{"deviceId": agent.deviceID, "flows": updatedFlows, "groups": updatedGroups})
A R Karthick5c28f552019-12-11 22:47:44 -0800482 return coreutils.DoneResponse(), nil
khenaidoo0458db62019-06-20 08:50:36 -0400483 }
484
485 log.Debugw("updating-flows-and-groups",
486 log.Fields{
npujar1d86a522019-11-14 17:11:16 +0530487 "deviceId": agent.deviceID,
khenaidoo0458db62019-06-20 08:50:36 -0400488 "updatedFlows": updatedFlows,
489 "updatedGroups": updatedGroups,
490 })
491
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500492 response := coreutils.NewResponse()
khenaidoo0458db62019-06-20 08:50:36 -0400493 dType := agent.adapterMgr.getDeviceType(device.Type)
494
495 // Process bulk flow update differently than incremental update
496 if !dType.AcceptsAddRemoveFlowUpdates {
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500497 go agent.sendBulkFlowsToAdapters(device, &voltha.Flows{Items: updatedFlows}, &voltha.FlowGroups{Items: updatedGroups}, nil, response)
khenaidoo0458db62019-06-20 08:50:36 -0400498 } else {
499 var flowsToAdd []*ofp.OfpFlowStats
khenaidoo2c6a0992019-04-29 13:46:56 -0400500 var flowsToDelete []*ofp.OfpFlowStats
khenaidoo0458db62019-06-20 08:50:36 -0400501 var groupsToAdd []*ofp.OfpGroupEntry
khenaidoo2c6a0992019-04-29 13:46:56 -0400502 var groupsToDelete []*ofp.OfpGroupEntry
khenaidoo2c6a0992019-04-29 13:46:56 -0400503
504 // Process flows
khenaidoo0458db62019-06-20 08:50:36 -0400505 for _, flow := range updatedFlows {
506 if idx := fu.FindFlows(existingFlows.Items, flow); idx == -1 {
507 flowsToAdd = append(flowsToAdd, flow)
508 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400509 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400510 for _, flow := range existingFlows.Items {
khenaidoo0458db62019-06-20 08:50:36 -0400511 if idx := fu.FindFlows(updatedFlows, flow); idx != -1 {
khenaidoo2c6a0992019-04-29 13:46:56 -0400512 flowsToDelete = append(flowsToDelete, flow)
513 }
514 }
515
516 // Process groups
khenaidoo0458db62019-06-20 08:50:36 -0400517 for _, g := range updatedGroups {
518 if fu.FindGroup(existingGroups.Items, g.Desc.GroupId) == -1 { // does not exist now
519 groupsToAdd = append(groupsToAdd, g)
520 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400521 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400522 for _, group := range existingGroups.Items {
khenaidoo0458db62019-06-20 08:50:36 -0400523 if fu.FindGroup(updatedGroups, group.Desc.GroupId) != -1 { // does not exist now
khenaidoo2c6a0992019-04-29 13:46:56 -0400524 groupsToDelete = append(groupsToDelete, group)
525 }
526 }
527
khenaidoo0458db62019-06-20 08:50:36 -0400528 log.Debugw("updating-flows-and-groups",
529 log.Fields{
npujar1d86a522019-11-14 17:11:16 +0530530 "deviceId": agent.deviceID,
khenaidoo0458db62019-06-20 08:50:36 -0400531 "flowsToAdd": flowsToAdd,
532 "flowsToDelete": flowsToDelete,
533 "groupsToAdd": groupsToAdd,
534 "groupsToDelete": groupsToDelete,
535 })
536
khenaidoo2c6a0992019-04-29 13:46:56 -0400537 // Sanity check
khenaidoo0458db62019-06-20 08:50:36 -0400538 if (len(flowsToAdd) | len(flowsToDelete) | len(groupsToAdd) | len(groupsToDelete) | len(updatedGroups)) == 0 {
npujar1d86a522019-11-14 17:11:16 +0530539 log.Debugw("nothing-to-update", log.Fields{"deviceId": agent.deviceID, "flows": updatedFlows, "groups": updatedGroups})
A R Karthick5c28f552019-12-11 22:47:44 -0800540 return coreutils.DoneResponse(), nil
khenaidoo2c6a0992019-04-29 13:46:56 -0400541 }
542
khenaidoo0458db62019-06-20 08:50:36 -0400543 flowChanges := &ofp.FlowChanges{
544 ToAdd: &voltha.Flows{Items: flowsToAdd},
545 ToRemove: &voltha.Flows{Items: flowsToDelete},
khenaidoo19d7b632018-10-30 10:49:50 -0400546 }
khenaidoo0458db62019-06-20 08:50:36 -0400547 groupChanges := &ofp.FlowGroupChanges{
548 ToAdd: &voltha.FlowGroups{Items: groupsToAdd},
549 ToRemove: &voltha.FlowGroups{Items: groupsToDelete},
550 ToUpdate: &voltha.FlowGroups{Items: updatedGroups},
551 }
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500552 go agent.sendIncrementalFlowsToAdapters(device, flowChanges, groupChanges, flowMetadata, response)
khenaidoo19d7b632018-10-30 10:49:50 -0400553 }
khenaidoo0458db62019-06-20 08:50:36 -0400554
555 // store the updated data
556 device.Flows = &voltha.Flows{Items: updatedFlows}
557 device.FlowGroups = &voltha.FlowGroups{Items: updatedGroups}
Kent Hagerman3c513972019-11-25 13:49:41 -0500558 if err := agent.updateDeviceWithoutLock(device); err != nil {
A R Karthick5c28f552019-12-11 22:47:44 -0800559 return coreutils.DoneResponse(), status.Errorf(codes.Internal, "failure-updating-%s", agent.deviceID)
Kent Hagerman3c513972019-11-25 13:49:41 -0500560 }
khenaidoo0458db62019-06-20 08:50:36 -0400561
A R Karthick5c28f552019-12-11 22:47:44 -0800562 return response, nil
563}
564
565//updateFlowsAndGroups replaces the existing flows and groups with "updatedFlows" and "updatedGroups" respectively. It
566//also sends the updates to the adapters
567func (agent *DeviceAgent) updateFlowsAndGroups(updatedFlows []*ofp.OfpFlowStats, updatedGroups []*ofp.OfpGroupEntry, flowMetadata *voltha.FlowMetadata) error {
568 response, err := agent.updateFlowsAndGroupsToAdapter(updatedFlows, updatedGroups, flowMetadata)
569 if err != nil {
570 return err
571 }
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500572 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, response); res != nil {
khenaidoo0458db62019-06-20 08:50:36 -0400573 return status.Errorf(codes.Aborted, "errors-%s", res)
574 }
575 return nil
khenaidoo19d7b632018-10-30 10:49:50 -0400576}
577
khenaidoo4d4802d2018-10-04 21:59:49 -0400578//disableDevice disable a device
khenaidoo92e62c52018-10-03 14:02:54 -0400579func (agent *DeviceAgent) disableDevice(ctx context.Context) error {
khenaidoo59ef7be2019-06-21 12:40:28 -0400580 agent.lockDevice.Lock()
581 defer agent.lockDevice.Unlock()
npujar1d86a522019-11-14 17:11:16 +0530582 log.Debugw("disableDevice", log.Fields{"id": agent.deviceID})
khenaidoo92e62c52018-10-03 14:02:54 -0400583 // Get the most up to date the device info
npujar1d86a522019-11-14 17:11:16 +0530584 device, err := agent.getDeviceWithoutLock()
585 if err != nil {
586 return status.Errorf(codes.NotFound, "%s", agent.deviceID)
587 }
588 if device.AdminState == voltha.AdminState_DISABLED {
589 log.Debugw("device-already-disabled", log.Fields{"id": agent.deviceID})
590 return nil
591 }
592 if device.AdminState == voltha.AdminState_PREPROVISIONED ||
593 device.AdminState == voltha.AdminState_DELETED {
594 log.Debugw("device-not-enabled", log.Fields{"id": agent.deviceID})
595 return status.Errorf(codes.FailedPrecondition, "deviceId:%s, invalid-admin-state:%s", agent.deviceID, device.AdminState)
596 }
khenaidoo4554f7c2019-05-29 22:13:15 -0400597
npujar1d86a522019-11-14 17:11:16 +0530598 // Update the Admin State and operational state before sending the request out
599 cloned := proto.Clone(device).(*voltha.Device)
600 cloned.AdminState = voltha.AdminState_DISABLED
601 cloned.OperStatus = voltha.OperStatus_UNKNOWN
602 if err := agent.updateDeviceInStoreWithoutLock(cloned, false, ""); err != nil {
603 return err
604 }
khenaidoo59ef7be2019-06-21 12:40:28 -0400605
npujar1d86a522019-11-14 17:11:16 +0530606 if err := agent.adapterProxy.DisableDevice(ctx, device); err != nil {
607 log.Debugw("disableDevice-error", log.Fields{"id": agent.deviceID, "error": err})
608 return err
khenaidoo0a822f92019-05-08 15:15:57 -0400609 }
610 return nil
611}
612
613func (agent *DeviceAgent) updateAdminState(adminState voltha.AdminState_AdminState) error {
614 agent.lockDevice.Lock()
615 defer agent.lockDevice.Unlock()
npujar1d86a522019-11-14 17:11:16 +0530616 log.Debugw("updateAdminState", log.Fields{"id": agent.deviceID})
khenaidoo0a822f92019-05-08 15:15:57 -0400617 // Get the most up to date the device info
npujar1d86a522019-11-14 17:11:16 +0530618 device, err := agent.getDeviceWithoutLock()
619 if err != nil {
620 return status.Errorf(codes.NotFound, "%s", agent.deviceID)
621 }
622 if device.AdminState == adminState {
623 log.Debugw("no-change-needed", log.Fields{"id": agent.deviceID, "state": adminState})
624 return nil
625 }
626 // Received an Ack (no error found above). Now update the device in the model to the expected state
627 cloned := proto.Clone(device).(*voltha.Device)
628 cloned.AdminState = adminState
629 if err := agent.updateDeviceInStoreWithoutLock(cloned, false, ""); err != nil {
630 return err
khenaidoo92e62c52018-10-03 14:02:54 -0400631 }
632 return nil
633}
634
khenaidoo4d4802d2018-10-04 21:59:49 -0400635func (agent *DeviceAgent) rebootDevice(ctx context.Context) error {
636 agent.lockDevice.Lock()
637 defer agent.lockDevice.Unlock()
npujar1d86a522019-11-14 17:11:16 +0530638 log.Debugw("rebootDevice", log.Fields{"id": agent.deviceID})
khenaidoo4d4802d2018-10-04 21:59:49 -0400639 // Get the most up to date the device info
npujar1d86a522019-11-14 17:11:16 +0530640 device, err := agent.getDeviceWithoutLock()
641 if err != nil {
642 return status.Errorf(codes.NotFound, "%s", agent.deviceID)
643 }
644 if err := agent.adapterProxy.RebootDevice(ctx, device); err != nil {
645 log.Debugw("rebootDevice-error", log.Fields{"id": agent.deviceID, "error": err})
646 return err
khenaidoo4d4802d2018-10-04 21:59:49 -0400647 }
648 return nil
649}
650
651func (agent *DeviceAgent) deleteDevice(ctx context.Context) error {
652 agent.lockDevice.Lock()
khenaidoo0a822f92019-05-08 15:15:57 -0400653 defer agent.lockDevice.Unlock()
npujar1d86a522019-11-14 17:11:16 +0530654 log.Debugw("deleteDevice", log.Fields{"id": agent.deviceID})
khenaidoo4d4802d2018-10-04 21:59:49 -0400655 // Get the most up to date the device info
npujar1d86a522019-11-14 17:11:16 +0530656 device, err := agent.getDeviceWithoutLock()
657 if err != nil {
658 return status.Errorf(codes.NotFound, "%s", agent.deviceID)
659 }
660 if device.AdminState == voltha.AdminState_DELETED {
661 log.Debugw("device-already-in-deleted-state", log.Fields{"id": agent.deviceID})
662 return nil
663 }
664 if (device.AdminState != voltha.AdminState_DISABLED) &&
665 (device.AdminState != voltha.AdminState_PREPROVISIONED) {
666 log.Debugw("device-not-disabled", log.Fields{"id": agent.deviceID})
667 //TODO: Needs customized error message
668 return status.Errorf(codes.FailedPrecondition, "deviceId:%s, expected-admin-state:%s", agent.deviceID, voltha.AdminState_DISABLED)
669 }
670 if device.AdminState != voltha.AdminState_PREPROVISIONED {
671 // Send the request to an Adapter only if the device is not in poreporovision state and wait for a response
672 if err := agent.adapterProxy.DeleteDevice(ctx, device); err != nil {
673 log.Debugw("deleteDevice-error", log.Fields{"id": agent.deviceID, "error": err})
Mahir Gunyelb5851672019-07-24 10:46:26 +0300674 return err
khenaidoo4d4802d2018-10-04 21:59:49 -0400675 }
npujar1d86a522019-11-14 17:11:16 +0530676 }
677 // Set the state to deleted after we receive an Ack - this will trigger some background process to clean up
678 // the device as well as its association with the logical device
679 cloned := proto.Clone(device).(*voltha.Device)
680 cloned.AdminState = voltha.AdminState_DELETED
681 if err := agent.updateDeviceInStoreWithoutLock(cloned, false, ""); err != nil {
682 return err
683 }
684 // If this is a child device then remove the associated peer ports on the parent device
685 if !device.Root {
686 go func() {
687 err := agent.deviceMgr.deletePeerPorts(device.ParentId, device.Id)
688 if err != nil {
689 log.Errorw("unable-to-delete-peer-ports", log.Fields{"error": err})
690 }
691 }()
khenaidoo4d4802d2018-10-04 21:59:49 -0400692 }
693 return nil
694}
695
npujar1d86a522019-11-14 17:11:16 +0530696func (agent *DeviceAgent) setParentID(device *voltha.Device, parentID string) error {
khenaidooad06fd72019-10-28 12:26:05 -0400697 agent.lockDevice.Lock()
698 defer agent.lockDevice.Unlock()
npujar1d86a522019-11-14 17:11:16 +0530699 log.Debugw("setParentId", log.Fields{"deviceId": device.Id, "parentId": parentID})
700 storeDevice, err := agent.getDeviceWithoutLock()
701 if err != nil {
702 return status.Errorf(codes.NotFound, "%s", agent.deviceID)
khenaidooad06fd72019-10-28 12:26:05 -0400703 }
npujar1d86a522019-11-14 17:11:16 +0530704 // clone the device
705 cloned := proto.Clone(storeDevice).(*voltha.Device)
706 cloned.ParentId = parentID
707 // Store the device
708 if err := agent.updateDeviceInStoreWithoutLock(cloned, false, ""); err != nil {
709 return err
710 }
711 return nil
khenaidooad06fd72019-10-28 12:26:05 -0400712}
713
khenaidoob3127472019-07-24 21:04:55 -0400714func (agent *DeviceAgent) updatePmConfigs(ctx context.Context, pmConfigs *voltha.PmConfigs) error {
715 agent.lockDevice.Lock()
716 defer agent.lockDevice.Unlock()
717 log.Debugw("updatePmConfigs", log.Fields{"id": pmConfigs.Id})
718 // Work only on latest data
npujar1d86a522019-11-14 17:11:16 +0530719 storeDevice, err := agent.getDeviceWithoutLock()
720 if err != nil {
721 return status.Errorf(codes.NotFound, "%s", agent.deviceID)
khenaidoob3127472019-07-24 21:04:55 -0400722 }
npujar1d86a522019-11-14 17:11:16 +0530723 // clone the device
724 cloned := proto.Clone(storeDevice).(*voltha.Device)
725 cloned.PmConfigs = proto.Clone(pmConfigs).(*voltha.PmConfigs)
726 // Store the device
727 if err := agent.updateDeviceInStoreWithoutLock(cloned, false, ""); err != nil {
728 return err
729 }
730 // Send the request to the adapter
731 if err := agent.adapterProxy.UpdatePmConfigs(ctx, cloned, pmConfigs); err != nil {
732 log.Errorw("update-pm-configs-error", log.Fields{"id": agent.deviceID, "error": err})
733 return err
734 }
735 return nil
khenaidoob3127472019-07-24 21:04:55 -0400736}
737
738func (agent *DeviceAgent) initPmConfigs(pmConfigs *voltha.PmConfigs) error {
739 agent.lockDevice.Lock()
740 defer agent.lockDevice.Unlock()
741 log.Debugw("initPmConfigs", log.Fields{"id": pmConfigs.Id})
742 // Work only on latest data
npujar1d86a522019-11-14 17:11:16 +0530743 storeDevice, err := agent.getDeviceWithoutLock()
744 if err != nil {
745 return status.Errorf(codes.NotFound, "%s", agent.deviceID)
khenaidoob3127472019-07-24 21:04:55 -0400746 }
npujar1d86a522019-11-14 17:11:16 +0530747 // clone the device
748 cloned := proto.Clone(storeDevice).(*voltha.Device)
749 cloned.PmConfigs = proto.Clone(pmConfigs).(*voltha.PmConfigs)
750 // Store the device
751 updateCtx := context.WithValue(context.Background(), model.RequestTimestamp, time.Now().UnixNano())
752 afterUpdate := agent.clusterDataProxy.Update(updateCtx, "/devices/"+agent.deviceID, cloned, false, "")
753 if afterUpdate == nil {
754 return status.Errorf(codes.Internal, "%s", agent.deviceID)
755 }
756 return nil
khenaidoob3127472019-07-24 21:04:55 -0400757}
758
759func (agent *DeviceAgent) listPmConfigs(ctx context.Context) (*voltha.PmConfigs, error) {
760 agent.lockDevice.RLock()
761 defer agent.lockDevice.RUnlock()
npujar1d86a522019-11-14 17:11:16 +0530762 log.Debugw("listPmConfigs", log.Fields{"id": agent.deviceID})
khenaidoob3127472019-07-24 21:04:55 -0400763 // Get the most up to date the device info
npujar1d86a522019-11-14 17:11:16 +0530764 device, err := agent.getDeviceWithoutLock()
765 if err != nil {
766 return nil, status.Errorf(codes.NotFound, "%s", agent.deviceID)
khenaidoob3127472019-07-24 21:04:55 -0400767 }
npujar1d86a522019-11-14 17:11:16 +0530768 cloned := proto.Clone(device).(*voltha.Device)
769 return cloned.PmConfigs, nil
khenaidoob3127472019-07-24 21:04:55 -0400770}
771
khenaidoof5a5bfa2019-01-23 22:20:29 -0500772func (agent *DeviceAgent) downloadImage(ctx context.Context, img *voltha.ImageDownload) (*voltha.OperationResp, error) {
773 agent.lockDevice.Lock()
774 defer agent.lockDevice.Unlock()
npujar1d86a522019-11-14 17:11:16 +0530775 log.Debugw("downloadImage", log.Fields{"id": agent.deviceID})
khenaidoof5a5bfa2019-01-23 22:20:29 -0500776 // Get the most up to date the device info
npujar1d86a522019-11-14 17:11:16 +0530777 device, err := agent.getDeviceWithoutLock()
778 if err != nil {
779 return nil, status.Errorf(codes.NotFound, "%s", agent.deviceID)
780 }
781 if device.AdminState != voltha.AdminState_ENABLED {
782 log.Debugw("device-not-enabled", log.Fields{"id": agent.deviceID})
783 return nil, status.Errorf(codes.FailedPrecondition, "deviceId:%s, expected-admin-state:%s", agent.deviceID, voltha.AdminState_ENABLED)
784 }
785 // Save the image
786 clonedImg := proto.Clone(img).(*voltha.ImageDownload)
787 clonedImg.DownloadState = voltha.ImageDownload_DOWNLOAD_REQUESTED
788 cloned := proto.Clone(device).(*voltha.Device)
789 if cloned.ImageDownloads == nil {
790 cloned.ImageDownloads = []*voltha.ImageDownload{clonedImg}
khenaidoof5a5bfa2019-01-23 22:20:29 -0500791 } else {
792 if device.AdminState != voltha.AdminState_ENABLED {
npujar1d86a522019-11-14 17:11:16 +0530793 log.Debugw("device-not-enabled", log.Fields{"id": agent.deviceID})
794 return nil, status.Errorf(codes.FailedPrecondition, "deviceId:%s, expected-admin-state:%s", agent.deviceID, voltha.AdminState_ENABLED)
khenaidoof5a5bfa2019-01-23 22:20:29 -0500795 }
796 // Save the image
797 clonedImg := proto.Clone(img).(*voltha.ImageDownload)
Stephane Barbariedf5479f2019-01-29 22:13:00 -0500798 clonedImg.DownloadState = voltha.ImageDownload_DOWNLOAD_REQUESTED
khenaidoof5a5bfa2019-01-23 22:20:29 -0500799 cloned := proto.Clone(device).(*voltha.Device)
800 if cloned.ImageDownloads == nil {
801 cloned.ImageDownloads = []*voltha.ImageDownload{clonedImg}
802 } else {
803 cloned.ImageDownloads = append(cloned.ImageDownloads, clonedImg)
804 }
805 cloned.AdminState = voltha.AdminState_DOWNLOADING_IMAGE
Mahir Gunyelb5851672019-07-24 10:46:26 +0300806 if err := agent.updateDeviceInStoreWithoutLock(cloned, false, ""); err != nil {
807 return nil, err
khenaidoof5a5bfa2019-01-23 22:20:29 -0500808 }
809 // Send the request to the adapter
810 if err := agent.adapterProxy.DownloadImage(ctx, cloned, clonedImg); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530811 log.Debugw("downloadImage-error", log.Fields{"id": agent.deviceID, "error": err, "image": img.Name})
khenaidoof5a5bfa2019-01-23 22:20:29 -0500812 return nil, err
813 }
814 }
815 return &voltha.OperationResp{Code: voltha.OperationResp_OPERATION_SUCCESS}, nil
816}
817
818// isImageRegistered is a helper method to figure out if an image is already registered
819func isImageRegistered(img *voltha.ImageDownload, device *voltha.Device) bool {
820 for _, image := range device.ImageDownloads {
821 if image.Id == img.Id && image.Name == img.Name {
822 return true
823 }
824 }
825 return false
826}
827
828func (agent *DeviceAgent) cancelImageDownload(ctx context.Context, img *voltha.ImageDownload) (*voltha.OperationResp, error) {
829 agent.lockDevice.Lock()
830 defer agent.lockDevice.Unlock()
npujar1d86a522019-11-14 17:11:16 +0530831 log.Debugw("cancelImageDownload", log.Fields{"id": agent.deviceID})
khenaidoof5a5bfa2019-01-23 22:20:29 -0500832 // Get the most up to date the device info
npujar1d86a522019-11-14 17:11:16 +0530833 device, err := agent.getDeviceWithoutLock()
834 if err != nil {
835 return nil, status.Errorf(codes.NotFound, "%s", agent.deviceID)
836 }
837 // Verify whether the Image is in the list of image being downloaded
838 if !isImageRegistered(img, device) {
839 return nil, status.Errorf(codes.FailedPrecondition, "deviceId:%s, image-not-registered:%s", agent.deviceID, img.Name)
840 }
khenaidoof5a5bfa2019-01-23 22:20:29 -0500841
npujar1d86a522019-11-14 17:11:16 +0530842 // Update image download state
843 cloned := proto.Clone(device).(*voltha.Device)
844 for _, image := range cloned.ImageDownloads {
845 if image.Id == img.Id && image.Name == img.Name {
846 image.DownloadState = voltha.ImageDownload_DOWNLOAD_CANCELLED
khenaidoof5a5bfa2019-01-23 22:20:29 -0500847 }
npujar1d86a522019-11-14 17:11:16 +0530848 }
khenaidoof5a5bfa2019-01-23 22:20:29 -0500849
npujar1d86a522019-11-14 17:11:16 +0530850 if device.AdminState == voltha.AdminState_DOWNLOADING_IMAGE {
851 // Set the device to Enabled
852 cloned.AdminState = voltha.AdminState_ENABLED
853 if err := agent.updateDeviceInStoreWithoutLock(cloned, false, ""); err != nil {
854 return nil, err
855 }
856 // Send the request to the adapter
857 if err := agent.adapterProxy.CancelImageDownload(ctx, device, img); err != nil {
858 log.Debugw("cancelImageDownload-error", log.Fields{"id": agent.deviceID, "error": err, "image": img.Name})
859 return nil, err
khenaidoof5a5bfa2019-01-23 22:20:29 -0500860 }
861 }
862 return &voltha.OperationResp{Code: voltha.OperationResp_OPERATION_SUCCESS}, nil
serkant.uluderya334479d2019-04-10 08:26:15 -0700863}
khenaidoof5a5bfa2019-01-23 22:20:29 -0500864
865func (agent *DeviceAgent) activateImage(ctx context.Context, img *voltha.ImageDownload) (*voltha.OperationResp, error) {
866 agent.lockDevice.Lock()
867 defer agent.lockDevice.Unlock()
npujar1d86a522019-11-14 17:11:16 +0530868 log.Debugw("activateImage", log.Fields{"id": agent.deviceID})
khenaidoof5a5bfa2019-01-23 22:20:29 -0500869 // Get the most up to date the device info
npujar1d86a522019-11-14 17:11:16 +0530870 device, err := agent.getDeviceWithoutLock()
871 if err != nil {
872 return nil, status.Errorf(codes.NotFound, "%s", agent.deviceID)
khenaidoof5a5bfa2019-01-23 22:20:29 -0500873 }
npujar1d86a522019-11-14 17:11:16 +0530874 // Verify whether the Image is in the list of image being downloaded
875 if !isImageRegistered(img, device) {
876 return nil, status.Errorf(codes.FailedPrecondition, "deviceId:%s, image-not-registered:%s", agent.deviceID, img.Name)
877 }
878
879 if device.AdminState == voltha.AdminState_DOWNLOADING_IMAGE {
880 return nil, status.Errorf(codes.FailedPrecondition, "deviceId:%s, device-in-downloading-state:%s", agent.deviceID, img.Name)
881 }
882 // Update image download state
883 cloned := proto.Clone(device).(*voltha.Device)
884 for _, image := range cloned.ImageDownloads {
885 if image.Id == img.Id && image.Name == img.Name {
886 image.ImageState = voltha.ImageDownload_IMAGE_ACTIVATING
887 }
888 }
889 // Set the device to downloading_image
890 cloned.AdminState = voltha.AdminState_DOWNLOADING_IMAGE
891 if err := agent.updateDeviceInStoreWithoutLock(cloned, false, ""); err != nil {
892 return nil, err
893 }
894
895 if err := agent.adapterProxy.ActivateImageUpdate(ctx, device, img); err != nil {
896 log.Debugw("activateImage-error", log.Fields{"id": agent.deviceID, "error": err, "image": img.Name})
897 return nil, err
898 }
899 // The status of the AdminState will be changed following the update_download_status response from the adapter
900 // The image name will also be removed from the device list
serkant.uluderya334479d2019-04-10 08:26:15 -0700901 return &voltha.OperationResp{Code: voltha.OperationResp_OPERATION_SUCCESS}, nil
902}
khenaidoof5a5bfa2019-01-23 22:20:29 -0500903
904func (agent *DeviceAgent) revertImage(ctx context.Context, img *voltha.ImageDownload) (*voltha.OperationResp, error) {
905 agent.lockDevice.Lock()
906 defer agent.lockDevice.Unlock()
npujar1d86a522019-11-14 17:11:16 +0530907 log.Debugw("revertImage", log.Fields{"id": agent.deviceID})
khenaidoof5a5bfa2019-01-23 22:20:29 -0500908 // Get the most up to date the device info
npujar1d86a522019-11-14 17:11:16 +0530909 device, err := agent.getDeviceWithoutLock()
910 if err != nil {
911 return nil, status.Errorf(codes.NotFound, "%s", agent.deviceID)
912 }
913 // Verify whether the Image is in the list of image being downloaded
914 if !isImageRegistered(img, device) {
915 return nil, status.Errorf(codes.FailedPrecondition, "deviceId:%s, image-not-registered:%s", agent.deviceID, img.Name)
916 }
khenaidoof5a5bfa2019-01-23 22:20:29 -0500917
npujar1d86a522019-11-14 17:11:16 +0530918 if device.AdminState != voltha.AdminState_ENABLED {
919 return nil, status.Errorf(codes.FailedPrecondition, "deviceId:%s, device-not-enabled-state:%s", agent.deviceID, img.Name)
920 }
921 // Update image download state
922 cloned := proto.Clone(device).(*voltha.Device)
923 for _, image := range cloned.ImageDownloads {
924 if image.Id == img.Id && image.Name == img.Name {
925 image.ImageState = voltha.ImageDownload_IMAGE_REVERTING
khenaidoof5a5bfa2019-01-23 22:20:29 -0500926 }
npujar1d86a522019-11-14 17:11:16 +0530927 }
Mahir Gunyelb5851672019-07-24 10:46:26 +0300928
npujar1d86a522019-11-14 17:11:16 +0530929 if err := agent.updateDeviceInStoreWithoutLock(cloned, false, ""); err != nil {
930 return nil, err
931 }
khenaidoof5a5bfa2019-01-23 22:20:29 -0500932
npujar1d86a522019-11-14 17:11:16 +0530933 if err := agent.adapterProxy.RevertImageUpdate(ctx, device, img); err != nil {
934 log.Debugw("revertImage-error", log.Fields{"id": agent.deviceID, "error": err, "image": img.Name})
935 return nil, err
khenaidoof5a5bfa2019-01-23 22:20:29 -0500936 }
937 return &voltha.OperationResp{Code: voltha.OperationResp_OPERATION_SUCCESS}, nil
serkant.uluderya334479d2019-04-10 08:26:15 -0700938}
khenaidoof5a5bfa2019-01-23 22:20:29 -0500939
940func (agent *DeviceAgent) getImageDownloadStatus(ctx context.Context, img *voltha.ImageDownload) (*voltha.ImageDownload, error) {
941 agent.lockDevice.Lock()
942 defer agent.lockDevice.Unlock()
npujar1d86a522019-11-14 17:11:16 +0530943 log.Debugw("getImageDownloadStatus", log.Fields{"id": agent.deviceID})
khenaidoof5a5bfa2019-01-23 22:20:29 -0500944 // Get the most up to date the device info
npujar1d86a522019-11-14 17:11:16 +0530945 device, err := agent.getDeviceWithoutLock()
946 if err != nil {
947 return nil, status.Errorf(codes.NotFound, "%s", agent.deviceID)
khenaidoof5a5bfa2019-01-23 22:20:29 -0500948 }
npujar1d86a522019-11-14 17:11:16 +0530949 resp, err := agent.adapterProxy.GetImageDownloadStatus(ctx, device, img)
950 if err != nil {
951 log.Debugw("getImageDownloadStatus-error", log.Fields{"id": agent.deviceID, "error": err, "image": img.Name})
952 return nil, err
953 }
954 return resp, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -0500955}
956
serkant.uluderya334479d2019-04-10 08:26:15 -0700957func (agent *DeviceAgent) updateImageDownload(img *voltha.ImageDownload) error {
khenaidoof5a5bfa2019-01-23 22:20:29 -0500958 agent.lockDevice.Lock()
959 defer agent.lockDevice.Unlock()
npujar1d86a522019-11-14 17:11:16 +0530960 log.Debugw("updateImageDownload", log.Fields{"id": agent.deviceID})
khenaidoof5a5bfa2019-01-23 22:20:29 -0500961 // Get the most up to date the device info
npujar1d86a522019-11-14 17:11:16 +0530962 device, err := agent.getDeviceWithoutLock()
963 if err != nil {
964 return status.Errorf(codes.NotFound, "%s", agent.deviceID)
965 }
966 // Update the image as well as remove it if the download was cancelled
967 cloned := proto.Clone(device).(*voltha.Device)
968 clonedImages := make([]*voltha.ImageDownload, len(cloned.ImageDownloads))
969 for _, image := range cloned.ImageDownloads {
970 if image.Id == img.Id && image.Name == img.Name {
971 if image.DownloadState != voltha.ImageDownload_DOWNLOAD_CANCELLED {
972 clonedImages = append(clonedImages, img)
khenaidoof5a5bfa2019-01-23 22:20:29 -0500973 }
974 }
npujar1d86a522019-11-14 17:11:16 +0530975 }
976 cloned.ImageDownloads = clonedImages
977 // Set the Admin state to enabled if required
978 if (img.DownloadState != voltha.ImageDownload_DOWNLOAD_REQUESTED &&
979 img.DownloadState != voltha.ImageDownload_DOWNLOAD_STARTED) ||
980 (img.ImageState != voltha.ImageDownload_IMAGE_ACTIVATING) {
981 cloned.AdminState = voltha.AdminState_ENABLED
982 }
khenaidoof5a5bfa2019-01-23 22:20:29 -0500983
npujar1d86a522019-11-14 17:11:16 +0530984 if err := agent.updateDeviceInStoreWithoutLock(cloned, false, ""); err != nil {
985 return err
khenaidoof5a5bfa2019-01-23 22:20:29 -0500986 }
987 return nil
988}
989
990func (agent *DeviceAgent) getImageDownload(ctx context.Context, img *voltha.ImageDownload) (*voltha.ImageDownload, error) {
khenaidoo1ce37ad2019-03-24 22:07:24 -0400991 agent.lockDevice.RLock()
992 defer agent.lockDevice.RUnlock()
npujar1d86a522019-11-14 17:11:16 +0530993 log.Debugw("getImageDownload", log.Fields{"id": agent.deviceID})
khenaidoof5a5bfa2019-01-23 22:20:29 -0500994 // Get the most up to date the device info
npujar1d86a522019-11-14 17:11:16 +0530995 device, err := agent.getDeviceWithoutLock()
996 if err != nil {
997 return nil, status.Errorf(codes.NotFound, "%s", agent.deviceID)
khenaidoof5a5bfa2019-01-23 22:20:29 -0500998 }
npujar1d86a522019-11-14 17:11:16 +0530999 for _, image := range device.ImageDownloads {
1000 if image.Id == img.Id && image.Name == img.Name {
1001 return image, nil
1002 }
1003 }
1004 return nil, status.Errorf(codes.NotFound, "image-not-found:%s", img.Name)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001005}
1006
npujar1d86a522019-11-14 17:11:16 +05301007func (agent *DeviceAgent) listImageDownloads(ctx context.Context, deviceID string) (*voltha.ImageDownloads, error) {
khenaidoo1ce37ad2019-03-24 22:07:24 -04001008 agent.lockDevice.RLock()
1009 defer agent.lockDevice.RUnlock()
npujar1d86a522019-11-14 17:11:16 +05301010 log.Debugw("listImageDownloads", log.Fields{"id": agent.deviceID})
khenaidoof5a5bfa2019-01-23 22:20:29 -05001011 // Get the most up to date the device info
npujar1d86a522019-11-14 17:11:16 +05301012 device, err := agent.getDeviceWithoutLock()
1013 if err != nil {
1014 return nil, status.Errorf(codes.NotFound, "%s", agent.deviceID)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001015 }
npujar1d86a522019-11-14 17:11:16 +05301016 return &voltha.ImageDownloads{Items: device.ImageDownloads}, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001017}
1018
khenaidoo4d4802d2018-10-04 21:59:49 -04001019// getPorts retrieves the ports information of the device based on the port type.
khenaidoo92e62c52018-10-03 14:02:54 -04001020func (agent *DeviceAgent) getPorts(ctx context.Context, portType voltha.Port_PortType) *voltha.Ports {
npujar1d86a522019-11-14 17:11:16 +05301021 log.Debugw("getPorts", log.Fields{"id": agent.deviceID, "portType": portType})
khenaidoob9203542018-09-17 22:56:37 -04001022 ports := &voltha.Ports{}
npujar1d86a522019-11-14 17:11:16 +05301023 if device, _ := agent.deviceMgr.GetDevice(agent.deviceID); device != nil {
khenaidoob9203542018-09-17 22:56:37 -04001024 for _, port := range device.Ports {
khenaidoo92e62c52018-10-03 14:02:54 -04001025 if port.Type == portType {
khenaidoob9203542018-09-17 22:56:37 -04001026 ports.Items = append(ports.Items, port)
1027 }
1028 }
1029 }
1030 return ports
1031}
1032
khenaidoo4d4802d2018-10-04 21:59:49 -04001033// getSwitchCapability is a helper method that a logical device agent uses to retrieve the switch capability of a
1034// parent device
khenaidoo79232702018-12-04 11:00:41 -05001035func (agent *DeviceAgent) getSwitchCapability(ctx context.Context) (*ic.SwitchCapability, error) {
npujar1d86a522019-11-14 17:11:16 +05301036 log.Debugw("getSwitchCapability", log.Fields{"deviceId": agent.deviceID})
1037 device, err := agent.deviceMgr.GetDevice(agent.deviceID)
1038 if device == nil {
khenaidoob9203542018-09-17 22:56:37 -04001039 return nil, err
khenaidoob9203542018-09-17 22:56:37 -04001040 }
npujar1d86a522019-11-14 17:11:16 +05301041 var switchCap *ic.SwitchCapability
1042 if switchCap, err = agent.adapterProxy.GetOfpDeviceInfo(ctx, device); err != nil {
1043 log.Debugw("getSwitchCapability-error", log.Fields{"id": device.Id, "error": err})
1044 return nil, err
1045 }
1046 return switchCap, nil
khenaidoob9203542018-09-17 22:56:37 -04001047}
1048
khenaidoo4d4802d2018-10-04 21:59:49 -04001049// getPortCapability is a helper method that a logical device agent uses to retrieve the port capability of a
1050// device
khenaidoo79232702018-12-04 11:00:41 -05001051func (agent *DeviceAgent) getPortCapability(ctx context.Context, portNo uint32) (*ic.PortCapability, error) {
npujar1d86a522019-11-14 17:11:16 +05301052 log.Debugw("getPortCapability", log.Fields{"deviceId": agent.deviceID})
1053 device, err := agent.deviceMgr.GetDevice(agent.deviceID)
1054 if device == nil {
khenaidoob9203542018-09-17 22:56:37 -04001055 return nil, err
khenaidoob9203542018-09-17 22:56:37 -04001056 }
npujar1d86a522019-11-14 17:11:16 +05301057 var portCap *ic.PortCapability
1058 if portCap, err = agent.adapterProxy.GetOfpPortInfo(ctx, device, portNo); err != nil {
1059 log.Debugw("getPortCapability-error", log.Fields{"id": device.Id, "error": err})
1060 return nil, err
1061 }
1062 return portCap, nil
khenaidoob9203542018-09-17 22:56:37 -04001063}
1064
khenaidoofdbad6e2018-11-06 22:26:38 -05001065func (agent *DeviceAgent) packetOut(outPort uint32, packet *ofp.OfpPacketOut) error {
Scott Baker80678602019-11-14 16:57:36 -08001066 // If deviceType=="" then we must have taken ownership of this device.
1067 // Fixes VOL-2226 where a core would take ownership and have stale data
1068 if agent.deviceType == "" {
1069 agent.reconcileWithKVStore()
1070 }
khenaidoofdbad6e2018-11-06 22:26:38 -05001071 // Send packet to adapter
npujar1d86a522019-11-14 17:11:16 +05301072 if err := agent.adapterProxy.packetOut(agent.deviceType, agent.deviceID, outPort, packet); err != nil {
Matteo Scandolo360605d2019-11-05 18:29:17 -08001073 log.Debugw("packet-out-error", log.Fields{
npujar1d86a522019-11-14 17:11:16 +05301074 "id": agent.deviceID,
Matteo Scandolo360605d2019-11-05 18:29:17 -08001075 "error": err,
1076 "packet": hex.EncodeToString(packet.Data),
1077 })
khenaidoofdbad6e2018-11-06 22:26:38 -05001078 return err
1079 }
1080 return nil
1081}
1082
khenaidoo4d4802d2018-10-04 21:59:49 -04001083// processUpdate is a callback invoked whenever there is a change on the device manages by this device agent
khenaidoo92e62c52018-10-03 14:02:54 -04001084func (agent *DeviceAgent) processUpdate(args ...interface{}) interface{} {
khenaidoo43c82122018-11-22 18:38:28 -05001085 //// Run this callback in its own go routine
1086 go func(args ...interface{}) interface{} {
1087 var previous *voltha.Device
1088 var current *voltha.Device
1089 var ok bool
1090 if len(args) == 2 {
1091 if previous, ok = args[0].(*voltha.Device); !ok {
1092 log.Errorw("invalid-callback-type", log.Fields{"data": args[0]})
1093 return nil
1094 }
1095 if current, ok = args[1].(*voltha.Device); !ok {
1096 log.Errorw("invalid-callback-type", log.Fields{"data": args[1]})
1097 return nil
1098 }
1099 } else {
1100 log.Errorw("too-many-args-in-callback", log.Fields{"len": len(args)})
1101 return nil
1102 }
1103 // Perform the state transition in it's own go routine
khenaidoof5a5bfa2019-01-23 22:20:29 -05001104 if err := agent.deviceMgr.processTransition(previous, current); err != nil {
1105 log.Errorw("failed-process-transition", log.Fields{"deviceId": previous.Id,
1106 "previousAdminState": previous.AdminState, "currentAdminState": current.AdminState})
1107 }
khenaidoo43c82122018-11-22 18:38:28 -05001108 return nil
1109 }(args...)
1110
khenaidoo92e62c52018-10-03 14:02:54 -04001111 return nil
1112}
1113
Mahir Gunyel8e2707d2019-07-25 00:36:21 -07001114// updatePartialDeviceData updates a subset of a device that an Adapter can update.
1115// TODO: May need a specific proto to handle only a subset of a device that can be changed by an adapter
1116func (agent *DeviceAgent) mergeDeviceInfoFromAdapter(device *voltha.Device) (*voltha.Device, error) {
1117 // First retrieve the most up to date device info
1118 var currentDevice *voltha.Device
1119 var err error
1120 if currentDevice, err = agent.getDeviceWithoutLock(); err != nil {
1121 return nil, err
1122 }
1123 cloned := proto.Clone(currentDevice).(*voltha.Device)
1124 cloned.Root = device.Root
1125 cloned.Vendor = device.Vendor
1126 cloned.Model = device.Model
1127 cloned.SerialNumber = device.SerialNumber
1128 cloned.MacAddress = device.MacAddress
1129 cloned.Vlan = device.Vlan
1130 cloned.Reason = device.Reason
1131 return cloned, nil
1132}
1133func (agent *DeviceAgent) updateDeviceUsingAdapterData(device *voltha.Device) error {
khenaidoo92e62c52018-10-03 14:02:54 -04001134 agent.lockDevice.Lock()
khenaidoo43c82122018-11-22 18:38:28 -05001135 defer agent.lockDevice.Unlock()
Mahir Gunyel8e2707d2019-07-25 00:36:21 -07001136 log.Debugw("updateDeviceUsingAdapterData", log.Fields{"deviceId": device.Id})
npujar1d86a522019-11-14 17:11:16 +05301137 updatedDevice, err := agent.mergeDeviceInfoFromAdapter(device)
1138 if err != nil {
Mahir Gunyel8e2707d2019-07-25 00:36:21 -07001139 log.Errorw("failed to update device ", log.Fields{"deviceId": device.Id})
1140 return status.Errorf(codes.Internal, "%s", err.Error())
Mahir Gunyel8e2707d2019-07-25 00:36:21 -07001141 }
npujar1d86a522019-11-14 17:11:16 +05301142 cloned := proto.Clone(updatedDevice).(*voltha.Device)
1143 return agent.updateDeviceInStoreWithoutLock(cloned, false, "")
khenaidoo43c82122018-11-22 18:38:28 -05001144}
1145
1146func (agent *DeviceAgent) updateDeviceWithoutLock(device *voltha.Device) error {
1147 log.Debugw("updateDevice", log.Fields{"deviceId": device.Id})
1148 cloned := proto.Clone(device).(*voltha.Device)
Mahir Gunyelb5851672019-07-24 10:46:26 +03001149 return agent.updateDeviceInStoreWithoutLock(cloned, false, "")
khenaidoob9203542018-09-17 22:56:37 -04001150}
1151
khenaidoo92e62c52018-10-03 14:02:54 -04001152func (agent *DeviceAgent) updateDeviceStatus(operStatus voltha.OperStatus_OperStatus, connStatus voltha.ConnectStatus_ConnectStatus) error {
1153 agent.lockDevice.Lock()
khenaidoo0a822f92019-05-08 15:15:57 -04001154 defer agent.lockDevice.Unlock()
khenaidoob9203542018-09-17 22:56:37 -04001155 // Work only on latest data
npujar1d86a522019-11-14 17:11:16 +05301156 storeDevice, err := agent.getDeviceWithoutLock()
1157 if err != nil {
1158 return status.Errorf(codes.NotFound, "%s", agent.deviceID)
khenaidoo92e62c52018-10-03 14:02:54 -04001159 }
npujar1d86a522019-11-14 17:11:16 +05301160 // clone the device
1161 cloned := proto.Clone(storeDevice).(*voltha.Device)
1162 // Ensure the enums passed in are valid - they will be invalid if they are not set when this function is invoked
1163 if s, ok := voltha.ConnectStatus_ConnectStatus_value[connStatus.String()]; ok {
1164 log.Debugw("updateDeviceStatus-conn", log.Fields{"ok": ok, "val": s})
1165 cloned.ConnectStatus = connStatus
1166 }
1167 if s, ok := voltha.OperStatus_OperStatus_value[operStatus.String()]; ok {
1168 log.Debugw("updateDeviceStatus-oper", log.Fields{"ok": ok, "val": s})
1169 cloned.OperStatus = operStatus
1170 }
1171 log.Debugw("updateDeviceStatus", log.Fields{"deviceId": cloned.Id, "operStatus": cloned.OperStatus, "connectStatus": cloned.ConnectStatus})
1172 // Store the device
1173 return agent.updateDeviceInStoreWithoutLock(cloned, false, "")
khenaidoo92e62c52018-10-03 14:02:54 -04001174}
1175
khenaidoo3ab34882019-05-02 21:33:30 -04001176func (agent *DeviceAgent) enablePorts() error {
1177 agent.lockDevice.Lock()
1178 defer agent.lockDevice.Unlock()
npujar1d86a522019-11-14 17:11:16 +05301179 storeDevice, err := agent.getDeviceWithoutLock()
1180 if err != nil {
1181 return status.Errorf(codes.NotFound, "%s", agent.deviceID)
khenaidoo3ab34882019-05-02 21:33:30 -04001182 }
npujar1d86a522019-11-14 17:11:16 +05301183 // clone the device
1184 cloned := proto.Clone(storeDevice).(*voltha.Device)
1185 for _, port := range cloned.Ports {
1186 port.AdminState = voltha.AdminState_ENABLED
1187 port.OperStatus = voltha.OperStatus_ACTIVE
1188 }
1189 // Store the device
1190 return agent.updateDeviceInStoreWithoutLock(cloned, false, "")
khenaidoo3ab34882019-05-02 21:33:30 -04001191}
1192
1193func (agent *DeviceAgent) disablePorts() error {
npujar1d86a522019-11-14 17:11:16 +05301194 log.Debugw("disablePorts", log.Fields{"deviceid": agent.deviceID})
khenaidoo3ab34882019-05-02 21:33:30 -04001195 agent.lockDevice.Lock()
1196 defer agent.lockDevice.Unlock()
npujar1d86a522019-11-14 17:11:16 +05301197 storeDevice, err := agent.getDeviceWithoutLock()
1198 if err != nil {
1199 return status.Errorf(codes.NotFound, "%s", agent.deviceID)
khenaidoo3ab34882019-05-02 21:33:30 -04001200 }
npujar1d86a522019-11-14 17:11:16 +05301201 // clone the device
1202 cloned := proto.Clone(storeDevice).(*voltha.Device)
1203 for _, port := range cloned.Ports {
1204 port.AdminState = voltha.AdminState_DISABLED
1205 port.OperStatus = voltha.OperStatus_UNKNOWN
1206 }
1207 // Store the device
1208 return agent.updateDeviceInStoreWithoutLock(cloned, false, "")
khenaidoo3ab34882019-05-02 21:33:30 -04001209}
1210
khenaidoo92e62c52018-10-03 14:02:54 -04001211func (agent *DeviceAgent) updatePortState(portType voltha.Port_PortType, portNo uint32, operStatus voltha.OperStatus_OperStatus) error {
1212 agent.lockDevice.Lock()
khenaidoo59ef7be2019-06-21 12:40:28 -04001213 defer agent.lockDevice.Unlock()
khenaidoo92e62c52018-10-03 14:02:54 -04001214 // Work only on latest data
1215 // TODO: Get list of ports from device directly instead of the entire device
npujar1d86a522019-11-14 17:11:16 +05301216 storeDevice, err := agent.getDeviceWithoutLock()
1217 if err != nil {
1218 return status.Errorf(codes.NotFound, "%s", agent.deviceID)
khenaidoob9203542018-09-17 22:56:37 -04001219 }
npujar1d86a522019-11-14 17:11:16 +05301220 // clone the device
1221 cloned := proto.Clone(storeDevice).(*voltha.Device)
1222 // Ensure the enums passed in are valid - they will be invalid if they are not set when this function is invoked
1223 if _, ok := voltha.Port_PortType_value[portType.String()]; !ok {
1224 return status.Errorf(codes.InvalidArgument, "%s", portType)
1225 }
1226 for _, port := range cloned.Ports {
1227 if port.Type == portType && port.PortNo == portNo {
1228 port.OperStatus = operStatus
1229 // Set the admin status to ENABLED if the operational status is ACTIVE
1230 // TODO: Set by northbound system?
1231 if operStatus == voltha.OperStatus_ACTIVE {
1232 port.AdminState = voltha.AdminState_ENABLED
1233 }
1234 break
1235 }
1236 }
1237 log.Debugw("portStatusUpdate", log.Fields{"deviceId": cloned.Id})
1238 // Store the device
1239 return agent.updateDeviceInStoreWithoutLock(cloned, false, "")
khenaidoob9203542018-09-17 22:56:37 -04001240}
1241
khenaidoo0a822f92019-05-08 15:15:57 -04001242func (agent *DeviceAgent) deleteAllPorts() error {
npujar1d86a522019-11-14 17:11:16 +05301243 log.Debugw("deleteAllPorts", log.Fields{"deviceId": agent.deviceID})
khenaidoo0a822f92019-05-08 15:15:57 -04001244 agent.lockDevice.Lock()
1245 defer agent.lockDevice.Unlock()
1246 // Work only on latest data
npujar1d86a522019-11-14 17:11:16 +05301247 storeDevice, err := agent.getDeviceWithoutLock()
1248 if err != nil {
1249 return status.Errorf(codes.NotFound, "%s", agent.deviceID)
khenaidoo0a822f92019-05-08 15:15:57 -04001250 }
npujar1d86a522019-11-14 17:11:16 +05301251 if storeDevice.AdminState != voltha.AdminState_DISABLED && storeDevice.AdminState != voltha.AdminState_DELETED {
1252 err = status.Error(codes.FailedPrecondition, fmt.Sprintf("invalid-state-%v", storeDevice.AdminState))
1253 log.Warnw("invalid-state-removing-ports", log.Fields{"state": storeDevice.AdminState, "error": err})
1254 return err
1255 }
1256 if len(storeDevice.Ports) == 0 {
1257 log.Debugw("no-ports-present", log.Fields{"deviceId": agent.deviceID})
1258 return nil
1259 }
1260 // clone the device & set the fields to empty
1261 cloned := proto.Clone(storeDevice).(*voltha.Device)
1262 cloned.Ports = []*voltha.Port{}
1263 log.Debugw("portStatusUpdate", log.Fields{"deviceId": cloned.Id})
1264 // Store the device
1265 return agent.updateDeviceInStoreWithoutLock(cloned, false, "")
khenaidoo0a822f92019-05-08 15:15:57 -04001266}
1267
khenaidoob9203542018-09-17 22:56:37 -04001268func (agent *DeviceAgent) addPort(port *voltha.Port) error {
khenaidoo92e62c52018-10-03 14:02:54 -04001269 agent.lockDevice.Lock()
1270 defer agent.lockDevice.Unlock()
npujar1d86a522019-11-14 17:11:16 +05301271 log.Debugw("addPort", log.Fields{"deviceId": agent.deviceID})
khenaidoob9203542018-09-17 22:56:37 -04001272 // Work only on latest data
npujar1d86a522019-11-14 17:11:16 +05301273 storeDevice, err := agent.getDeviceWithoutLock()
1274 if err != nil {
1275 return status.Errorf(codes.NotFound, "%s", agent.deviceID)
1276 }
1277 // clone the device
1278 cloned := proto.Clone(storeDevice).(*voltha.Device)
1279 if cloned.Ports == nil {
1280 // First port
1281 log.Debugw("addPort-first-port-to-add", log.Fields{"deviceId": agent.deviceID})
1282 cloned.Ports = make([]*voltha.Port, 0)
khenaidoob9203542018-09-17 22:56:37 -04001283 } else {
npujar1d86a522019-11-14 17:11:16 +05301284 for _, p := range cloned.Ports {
1285 if p.Type == port.Type && p.PortNo == port.PortNo {
1286 log.Debugw("port already exists", log.Fields{"port": *port})
1287 return nil
manikkaraj k259a6f72019-05-06 09:55:44 -04001288 }
khenaidoob9203542018-09-17 22:56:37 -04001289 }
khenaidoo92e62c52018-10-03 14:02:54 -04001290 }
npujar1d86a522019-11-14 17:11:16 +05301291 cp := proto.Clone(port).(*voltha.Port)
1292 // Set the admin state of the port to ENABLE if the operational state is ACTIVE
1293 // TODO: Set by northbound system?
1294 if cp.OperStatus == voltha.OperStatus_ACTIVE {
1295 cp.AdminState = voltha.AdminState_ENABLED
1296 }
1297 cloned.Ports = append(cloned.Ports, cp)
1298 // Store the device
1299 return agent.updateDeviceInStoreWithoutLock(cloned, false, "")
khenaidoo92e62c52018-10-03 14:02:54 -04001300}
1301
1302func (agent *DeviceAgent) addPeerPort(port *voltha.Port_PeerPort) error {
1303 agent.lockDevice.Lock()
1304 defer agent.lockDevice.Unlock()
1305 log.Debug("addPeerPort")
1306 // Work only on latest data
npujar1d86a522019-11-14 17:11:16 +05301307 storeDevice, err := agent.getDeviceWithoutLock()
1308 if err != nil {
1309 return status.Errorf(codes.NotFound, "%s", agent.deviceID)
khenaidoob9203542018-09-17 22:56:37 -04001310 }
npujar1d86a522019-11-14 17:11:16 +05301311 // clone the device
1312 cloned := proto.Clone(storeDevice).(*voltha.Device)
1313 // Get the peer port on the device based on the port no
1314 for _, peerPort := range cloned.Ports {
1315 if peerPort.PortNo == port.PortNo { // found port
1316 cp := proto.Clone(port).(*voltha.Port_PeerPort)
1317 peerPort.Peers = append(peerPort.Peers, cp)
1318 log.Debugw("found-peer", log.Fields{"portNo": port.PortNo, "deviceId": agent.deviceID})
1319 break
1320 }
1321 }
1322 // Store the device
1323 return agent.updateDeviceInStoreWithoutLock(cloned, false, "")
khenaidoob9203542018-09-17 22:56:37 -04001324}
1325
npujar1d86a522019-11-14 17:11:16 +05301326func (agent *DeviceAgent) deletePeerPorts(deviceID string) error {
khenaidoo0a822f92019-05-08 15:15:57 -04001327 agent.lockDevice.Lock()
1328 defer agent.lockDevice.Unlock()
1329 log.Debug("deletePeerPorts")
1330 // Work only on latest data
npujar1d86a522019-11-14 17:11:16 +05301331 storeDevice, err := agent.getDeviceWithoutLock()
1332 if err != nil {
1333 return status.Errorf(codes.NotFound, "%s", agent.deviceID)
khenaidoo0a822f92019-05-08 15:15:57 -04001334 }
npujar1d86a522019-11-14 17:11:16 +05301335 // clone the device
1336 cloned := proto.Clone(storeDevice).(*voltha.Device)
1337 var updatedPeers []*voltha.Port_PeerPort
1338 for _, port := range cloned.Ports {
1339 updatedPeers = make([]*voltha.Port_PeerPort, 0)
1340 for _, peerPort := range port.Peers {
1341 if peerPort.DeviceId != deviceID {
1342 updatedPeers = append(updatedPeers, peerPort)
1343 }
1344 }
1345 port.Peers = updatedPeers
1346 }
1347
1348 // Store the device with updated peer ports
1349 return agent.updateDeviceInStoreWithoutLock(cloned, false, "")
khenaidoo0a822f92019-05-08 15:15:57 -04001350}
1351
khenaidoob9203542018-09-17 22:56:37 -04001352// TODO: A generic device update by attribute
1353func (agent *DeviceAgent) updateDeviceAttribute(name string, value interface{}) {
khenaidoo92e62c52018-10-03 14:02:54 -04001354 agent.lockDevice.Lock()
1355 defer agent.lockDevice.Unlock()
khenaidoob9203542018-09-17 22:56:37 -04001356 if value == nil {
1357 return
1358 }
1359 var storeDevice *voltha.Device
1360 var err error
khenaidoo92e62c52018-10-03 14:02:54 -04001361 if storeDevice, err = agent.getDeviceWithoutLock(); err != nil {
khenaidoob9203542018-09-17 22:56:37 -04001362 return
1363 }
1364 updated := false
1365 s := reflect.ValueOf(storeDevice).Elem()
1366 if s.Kind() == reflect.Struct {
1367 // exported field
1368 f := s.FieldByName(name)
1369 if f.IsValid() && f.CanSet() {
1370 switch f.Kind() {
1371 case reflect.String:
1372 f.SetString(value.(string))
1373 updated = true
1374 case reflect.Uint32:
1375 f.SetUint(uint64(value.(uint32)))
1376 updated = true
1377 case reflect.Bool:
1378 f.SetBool(value.(bool))
1379 updated = true
1380 }
1381 }
1382 }
khenaidoo92e62c52018-10-03 14:02:54 -04001383 log.Debugw("update-field-status", log.Fields{"deviceId": storeDevice.Id, "name": name, "updated": updated})
khenaidoob9203542018-09-17 22:56:37 -04001384 // Save the data
khenaidoo92e62c52018-10-03 14:02:54 -04001385 cloned := proto.Clone(storeDevice).(*voltha.Device)
Mahir Gunyelb5851672019-07-24 10:46:26 +03001386 if err = agent.updateDeviceInStoreWithoutLock(cloned, false, ""); err != nil {
khenaidoob9203542018-09-17 22:56:37 -04001387 log.Warnw("attribute-update-failed", log.Fields{"attribute": name, "value": value})
1388 }
khenaidoob9203542018-09-17 22:56:37 -04001389}
serkant.uluderya334479d2019-04-10 08:26:15 -07001390
1391func (agent *DeviceAgent) simulateAlarm(ctx context.Context, simulatereq *voltha.SimulateAlarmRequest) error {
1392 agent.lockDevice.Lock()
1393 defer agent.lockDevice.Unlock()
npujar1d86a522019-11-14 17:11:16 +05301394 log.Debugw("simulateAlarm", log.Fields{"id": agent.deviceID})
serkant.uluderya334479d2019-04-10 08:26:15 -07001395 // Get the most up to date the device info
npujar1d86a522019-11-14 17:11:16 +05301396 device, err := agent.getDeviceWithoutLock()
1397 if err != nil {
1398 return status.Errorf(codes.NotFound, "%s", agent.deviceID)
1399 }
1400 // First send the request to an Adapter and wait for a response
1401 if err := agent.adapterProxy.SimulateAlarm(ctx, device, simulatereq); err != nil {
1402 log.Debugw("simulateAlarm-error", log.Fields{"id": agent.deviceID, "error": err})
1403 return err
serkant.uluderya334479d2019-04-10 08:26:15 -07001404 }
1405 return nil
1406}
Mahir Gunyelb5851672019-07-24 10:46:26 +03001407
1408//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.
1409// It is an internal helper function.
1410func (agent *DeviceAgent) updateDeviceInStoreWithoutLock(device *voltha.Device, strict bool, txid string) error {
1411 updateCtx := context.WithValue(context.Background(), model.RequestTimestamp, time.Now().UnixNano())
npujar1d86a522019-11-14 17:11:16 +05301412 if afterUpdate := agent.clusterDataProxy.Update(updateCtx, "/devices/"+agent.deviceID, device, strict, txid); afterUpdate == nil {
1413 return status.Errorf(codes.Internal, "failed-update-device:%s", agent.deviceID)
Mahir Gunyelb5851672019-07-24 10:46:26 +03001414 }
npujar1d86a522019-11-14 17:11:16 +05301415 log.Debugw("updated-device-in-store", log.Fields{"deviceId: ": agent.deviceID})
Mahir Gunyelb5851672019-07-24 10:46:26 +03001416
1417 return nil
1418}
Mahir Gunyelfdee9212019-10-16 16:52:21 -07001419
1420func (agent *DeviceAgent) updateDeviceReason(reason string) error {
1421 agent.lockDevice.Lock()
1422 defer agent.lockDevice.Unlock()
1423 // Work only on latest data
npujar1d86a522019-11-14 17:11:16 +05301424 storeDevice, err := agent.getDeviceWithoutLock()
1425 if err != nil {
1426 return status.Errorf(codes.NotFound, "%s", agent.deviceID)
Mahir Gunyelfdee9212019-10-16 16:52:21 -07001427 }
npujar1d86a522019-11-14 17:11:16 +05301428 // clone the device
1429 cloned := proto.Clone(storeDevice).(*voltha.Device)
1430 cloned.Reason = reason
1431 log.Debugw("updateDeviceReason", log.Fields{"deviceId": cloned.Id, "reason": cloned.Reason})
1432 // Store the device
1433 return agent.updateDeviceInStoreWithoutLock(cloned, false, "")
Mahir Gunyelfdee9212019-10-16 16:52:21 -07001434}