blob: fcac69ca43bccf240d7b82932ef516e260a83b3a [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 */
16package core
17
18import (
19 "context"
khenaidoo3ab34882019-05-02 21:33:30 -040020 "fmt"
khenaidoob9203542018-09-17 22:56:37 -040021 "github.com/gogo/protobuf/proto"
22 "github.com/opencord/voltha-go/common/log"
23 "github.com/opencord/voltha-go/db/model"
serkant.uluderya334479d2019-04-10 08:26:15 -070024 fu "github.com/opencord/voltha-go/rw_core/utils"
William Kurkiandaa6bb22019-03-07 12:26:28 -050025 ic "github.com/opencord/voltha-protos/go/inter_container"
26 ofp "github.com/opencord/voltha-protos/go/openflow_13"
27 "github.com/opencord/voltha-protos/go/voltha"
khenaidoob9203542018-09-17 22:56:37 -040028 "google.golang.org/grpc/codes"
29 "google.golang.org/grpc/status"
khenaidoo19d7b632018-10-30 10:49:50 -040030 "reflect"
31 "sync"
khenaidoob9203542018-09-17 22:56:37 -040032)
33
34type DeviceAgent struct {
khenaidoo9a468962018-09-19 15:33:13 -040035 deviceId string
khenaidoo43c82122018-11-22 18:38:28 -050036 deviceType string
khenaidoo2c6a0992019-04-29 13:46:56 -040037 isRootdevice bool
khenaidoo9a468962018-09-19 15:33:13 -040038 lastData *voltha.Device
39 adapterProxy *AdapterProxy
serkant.uluderya334479d2019-04-10 08:26:15 -070040 adapterMgr *AdapterManager
khenaidoo9a468962018-09-19 15:33:13 -040041 deviceMgr *DeviceManager
42 clusterDataProxy *model.Proxy
khenaidoo92e62c52018-10-03 14:02:54 -040043 deviceProxy *model.Proxy
khenaidoo9a468962018-09-19 15:33:13 -040044 exitChannel chan int
khenaidoo92e62c52018-10-03 14:02:54 -040045 lockDevice sync.RWMutex
khenaidoo2c6a0992019-04-29 13:46:56 -040046 defaultTimeout int64
khenaidoob9203542018-09-17 22:56:37 -040047}
48
khenaidoo4d4802d2018-10-04 21:59:49 -040049//newDeviceAgent creates a new device agent along as creating a unique ID for the device and set the device state to
50//preprovisioning
khenaidoo2c6a0992019-04-29 13:46:56 -040051func newDeviceAgent(ap *AdapterProxy, device *voltha.Device, deviceMgr *DeviceManager, cdProxy *model.Proxy, timeout int64) *DeviceAgent {
khenaidoob9203542018-09-17 22:56:37 -040052 var agent DeviceAgent
khenaidoob9203542018-09-17 22:56:37 -040053 agent.adapterProxy = ap
khenaidoo92e62c52018-10-03 14:02:54 -040054 cloned := (proto.Clone(device)).(*voltha.Device)
Stephane Barbarie1ab43272018-12-08 21:42:13 -050055 if cloned.Id == "" {
56 cloned.Id = CreateDeviceId()
khenaidoo297cd252019-02-07 22:10:23 -050057 cloned.AdminState = voltha.AdminState_PREPROVISIONED
58 cloned.FlowGroups = &ofp.FlowGroups{Items: nil}
59 cloned.Flows = &ofp.Flows{Items: nil}
Stephane Barbarie1ab43272018-12-08 21:42:13 -050060 }
khenaidoo19d7b632018-10-30 10:49:50 -040061 if !device.GetRoot() && device.ProxyAddress != nil {
62 // Set the default vlan ID to the one specified by the parent adapter. It can be
63 // overwritten by the child adapter during a device update request
64 cloned.Vlan = device.ProxyAddress.ChannelId
65 }
khenaidoo2c6a0992019-04-29 13:46:56 -040066 agent.isRootdevice = device.Root
khenaidoo92e62c52018-10-03 14:02:54 -040067 agent.deviceId = cloned.Id
khenaidoofdbad6e2018-11-06 22:26:38 -050068 agent.deviceType = cloned.Type
khenaidoo92e62c52018-10-03 14:02:54 -040069 agent.lastData = cloned
khenaidoob9203542018-09-17 22:56:37 -040070 agent.deviceMgr = deviceMgr
khenaidoo21d51152019-02-01 13:48:37 -050071 agent.adapterMgr = deviceMgr.adapterMgr
khenaidoob9203542018-09-17 22:56:37 -040072 agent.exitChannel = make(chan int, 1)
khenaidoo9a468962018-09-19 15:33:13 -040073 agent.clusterDataProxy = cdProxy
khenaidoo92e62c52018-10-03 14:02:54 -040074 agent.lockDevice = sync.RWMutex{}
khenaidoo2c6a0992019-04-29 13:46:56 -040075 agent.defaultTimeout = timeout
khenaidoob9203542018-09-17 22:56:37 -040076 return &agent
77}
78
khenaidoo297cd252019-02-07 22:10:23 -050079// start save the device to the data model and registers for callbacks on that device if loadFromdB is false. Otherwise,
80// it will load the data from the dB and setup teh necessary callbacks and proxies.
81func (agent *DeviceAgent) start(ctx context.Context, loadFromdB bool) error {
khenaidoo92e62c52018-10-03 14:02:54 -040082 agent.lockDevice.Lock()
83 defer agent.lockDevice.Unlock()
khenaidoo297cd252019-02-07 22:10:23 -050084 log.Debugw("starting-device-agent", log.Fields{"deviceId": agent.deviceId})
85 if loadFromdB {
86 if device := agent.clusterDataProxy.Get("/devices/"+agent.deviceId, 1, false, ""); device != nil {
87 if d, ok := device.(*voltha.Device); ok {
88 agent.lastData = proto.Clone(d).(*voltha.Device)
khenaidoo6d055132019-02-12 16:51:19 -050089 agent.deviceType = agent.lastData.Adapter
khenaidoo297cd252019-02-07 22:10:23 -050090 }
91 } else {
92 log.Errorw("failed-to-load-device", log.Fields{"deviceId": agent.deviceId})
93 return status.Errorf(codes.NotFound, "device-%s", agent.deviceId)
94 }
95 log.Debugw("device-loaded-from-dB", log.Fields{"device": agent.lastData})
96 } else {
97 // Add the initial device to the local model
98 if added := agent.clusterDataProxy.AddWithID("/devices", agent.deviceId, agent.lastData, ""); added == nil {
99 log.Errorw("failed-to-add-device", log.Fields{"deviceId": agent.deviceId})
100 }
khenaidoob9203542018-09-17 22:56:37 -0400101 }
khenaidoo297cd252019-02-07 22:10:23 -0500102
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400103 agent.deviceProxy = agent.clusterDataProxy.CreateProxy("/devices/"+agent.deviceId, false)
khenaidoo43c82122018-11-22 18:38:28 -0500104 agent.deviceProxy.RegisterCallback(model.POST_UPDATE, agent.processUpdate)
khenaidoo19d7b632018-10-30 10:49:50 -0400105
khenaidoob9203542018-09-17 22:56:37 -0400106 log.Debug("device-agent-started")
khenaidoo297cd252019-02-07 22:10:23 -0500107 return nil
khenaidoob9203542018-09-17 22:56:37 -0400108}
109
khenaidoo4d4802d2018-10-04 21:59:49 -0400110// stop stops the device agent. Not much to do for now
111func (agent *DeviceAgent) stop(ctx context.Context) {
khenaidoo92e62c52018-10-03 14:02:54 -0400112 agent.lockDevice.Lock()
113 defer agent.lockDevice.Unlock()
khenaidoob9203542018-09-17 22:56:37 -0400114 log.Debug("stopping-device-agent")
115 agent.exitChannel <- 1
116 log.Debug("device-agent-stopped")
117}
118
khenaidoo19d7b632018-10-30 10:49:50 -0400119// GetDevice retrieves the latest device information from the data model
khenaidoo92e62c52018-10-03 14:02:54 -0400120func (agent *DeviceAgent) getDevice() (*voltha.Device, error) {
khenaidoo1ce37ad2019-03-24 22:07:24 -0400121 agent.lockDevice.RLock()
122 defer agent.lockDevice.RUnlock()
khenaidoo297cd252019-02-07 22:10:23 -0500123 if device := agent.clusterDataProxy.Get("/devices/"+agent.deviceId, 0, false, ""); device != nil {
khenaidoo92e62c52018-10-03 14:02:54 -0400124 if d, ok := device.(*voltha.Device); ok {
125 cloned := proto.Clone(d).(*voltha.Device)
126 return cloned, nil
127 }
128 }
129 return nil, status.Errorf(codes.NotFound, "device-%s", agent.deviceId)
130}
131
khenaidoo4d4802d2018-10-04 21:59:49 -0400132// 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 -0400133// This function is meant so that we do not have duplicate code all over the device agent functions
134func (agent *DeviceAgent) getDeviceWithoutLock() (*voltha.Device, error) {
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400135 if device := agent.clusterDataProxy.Get("/devices/"+agent.deviceId, 0, false, ""); device != nil {
khenaidoo92e62c52018-10-03 14:02:54 -0400136 if d, ok := device.(*voltha.Device); ok {
137 cloned := proto.Clone(d).(*voltha.Device)
138 return cloned, nil
139 }
140 }
141 return nil, status.Errorf(codes.NotFound, "device-%s", agent.deviceId)
142}
143
khenaidoo3ab34882019-05-02 21:33:30 -0400144// enableDevice activates a preprovisioned or a disable device
khenaidoob9203542018-09-17 22:56:37 -0400145func (agent *DeviceAgent) enableDevice(ctx context.Context) error {
khenaidoo92e62c52018-10-03 14:02:54 -0400146 agent.lockDevice.Lock()
147 defer agent.lockDevice.Unlock()
148 log.Debugw("enableDevice", log.Fields{"id": agent.deviceId})
khenaidoo21d51152019-02-01 13:48:37 -0500149
khenaidoo92e62c52018-10-03 14:02:54 -0400150 if device, err := agent.getDeviceWithoutLock(); err != nil {
khenaidoob9203542018-09-17 22:56:37 -0400151 return status.Errorf(codes.NotFound, "%s", agent.deviceId)
152 } else {
khenaidoo21d51152019-02-01 13:48:37 -0500153 // First figure out which adapter will handle this device type. We do it at this stage as allow devices to be
154 // pre-provisionned with the required adapter not registered. At this stage, since we need to communicate
155 // with the adapter then we need to know the adapter that will handle this request
156 if adapterName, err := agent.adapterMgr.getAdapterName(device.Type); err != nil {
157 log.Warnw("no-adapter-registered-for-device-type", log.Fields{"deviceType": device.Type, "deviceAdapter": device.Adapter})
158 return err
159 } else {
160 device.Adapter = adapterName
161 }
162
khenaidoo92e62c52018-10-03 14:02:54 -0400163 if device.AdminState == voltha.AdminState_ENABLED {
164 log.Debugw("device-already-enabled", log.Fields{"id": agent.deviceId})
khenaidoo92e62c52018-10-03 14:02:54 -0400165 return nil
166 }
khenaidoo3ab34882019-05-02 21:33:30 -0400167 // If this is a child device then verify the parent state before proceeding
168 if !agent.isRootdevice {
169 if parent := agent.deviceMgr.getParentDevice(device); parent != nil {
170 if parent.AdminState == voltha.AdminState_DISABLED ||
171 parent.AdminState == voltha.AdminState_DELETED ||
172 parent.AdminState == voltha.AdminState_UNKNOWN {
173 err = status.Error(codes.FailedPrecondition, fmt.Sprintf("incorrect-parent-state: %s %d", parent.Id, parent.AdminState))
174 log.Warnw("incorrect-parent-state", log.Fields{"id": agent.deviceId, "error": err})
175 return err
176 }
177 } else {
178 err = status.Error(codes.Unavailable, fmt.Sprintf("parent-not-existent: %s ", device.Id))
179 log.Warnw("parent-not-existent", log.Fields{"id": agent.deviceId, "error": err})
180 return err
181 }
182 }
khenaidoo92e62c52018-10-03 14:02:54 -0400183 if device.AdminState == voltha.AdminState_PREPROVISIONED {
184 // First send the request to an Adapter and wait for a response
185 if err := agent.adapterProxy.AdoptDevice(ctx, device); err != nil {
186 log.Debugw("adoptDevice-error", log.Fields{"id": agent.lastData.Id, "error": err})
khenaidoob9203542018-09-17 22:56:37 -0400187 return err
188 }
khenaidoo92e62c52018-10-03 14:02:54 -0400189 } else {
190 // First send the request to an Adapter and wait for a response
191 if err := agent.adapterProxy.ReEnableDevice(ctx, device); err != nil {
192 log.Debugw("renableDevice-error", log.Fields{"id": agent.lastData.Id, "error": err})
193 return err
194 }
195 }
196 // Received an Ack (no error found above). Now update the device in the model to the expected state
197 cloned := proto.Clone(device).(*voltha.Device)
198 cloned.AdminState = voltha.AdminState_ENABLED
199 cloned.OperStatus = voltha.OperStatus_ACTIVATING
200 if afterUpdate := agent.clusterDataProxy.Update("/devices/"+agent.deviceId, cloned, false, ""); afterUpdate == nil {
201 return status.Errorf(codes.Internal, "failed-update-device:%s", agent.deviceId)
khenaidoob9203542018-09-17 22:56:37 -0400202 }
203 }
204 return nil
205}
206
khenaidoo2c6a0992019-04-29 13:46:56 -0400207func (agent *DeviceAgent) updateDeviceWithoutLockAsync(device *voltha.Device, ch chan interface{}) {
208 if err := agent.updateDeviceWithoutLock(device); err != nil {
209 ch <- status.Errorf(codes.Internal, "failure-updating-%s", agent.deviceId)
khenaidoo19d7b632018-10-30 10:49:50 -0400210 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400211 ch <- nil
khenaidoo19d7b632018-10-30 10:49:50 -0400212}
213
khenaidoo2c6a0992019-04-29 13:46:56 -0400214func (agent *DeviceAgent) sendBulkFlowsToAdapters(device *voltha.Device, flows *voltha.Flows, groups *voltha.FlowGroups, ch chan interface{}) {
215 if err := agent.adapterProxy.UpdateFlowsBulk(device, flows, groups); err != nil {
216 log.Debugw("update-flow-bulk-error", log.Fields{"id": agent.lastData.Id, "error": err})
217 ch <- err
218 }
219 ch <- nil
220}
221
222func (agent *DeviceAgent) sendIncrementalFlowsToAdapters(device *voltha.Device, flows *ofp.FlowChanges, groups *ofp.FlowGroupChanges, ch chan interface{}) {
223 if err := agent.adapterProxy.UpdateFlowsIncremental(device, flows, groups); err != nil {
224 log.Debugw("update-flow-incremental-error", log.Fields{"id": agent.lastData.Id, "error": err})
225 ch <- err
226 }
227 ch <- nil
228}
229
230func (agent *DeviceAgent) addFlowsAndGroups(newFlows []*ofp.OfpFlowStats, newGroups []*ofp.OfpGroupEntry) error {
231 if (len(newFlows) | len(newGroups)) == 0 {
232 log.Debugw("nothing-to-update", log.Fields{"deviceId": agent.deviceId, "flows": newFlows, "groups": newGroups})
233 return nil
234 }
235
khenaidoo19d7b632018-10-30 10:49:50 -0400236 agent.lockDevice.Lock()
237 defer agent.lockDevice.Unlock()
khenaidoo2c6a0992019-04-29 13:46:56 -0400238 log.Debugw("addFlowsAndGroups", log.Fields{"deviceId": agent.deviceId, "flows": newFlows, "groups": newGroups})
239 var existingFlows *voltha.Flows
240 if device, err := agent.getDeviceWithoutLock(); err != nil {
khenaidoo19d7b632018-10-30 10:49:50 -0400241 return status.Errorf(codes.NotFound, "%s", agent.deviceId)
242 } else {
khenaidoo2c6a0992019-04-29 13:46:56 -0400243 existingFlows = proto.Clone(device.Flows).(*voltha.Flows)
244 existingGroups := proto.Clone(device.FlowGroups).(*ofp.FlowGroups)
245 log.Debugw("addFlows", log.Fields{"deviceId": agent.deviceId, "flows": newFlows, "existingFlows": existingFlows, "groups": newGroups, "existingGroups": existingGroups})
246
247 var updatedFlows []*ofp.OfpFlowStats
248 var flowsToDelete []*ofp.OfpFlowStats
249 var groupsToDelete []*ofp.OfpGroupEntry
250 var updatedGroups []*ofp.OfpGroupEntry
251
252 // Process flows
253 for _, flow := range newFlows {
254 updatedFlows = append(updatedFlows, flow)
255 }
256
257 for _, flow := range existingFlows.Items {
258 if idx := fu.FindFlows(newFlows, flow); idx == -1 {
259 updatedFlows = append(updatedFlows, flow)
260 } else {
261 flowsToDelete = append(flowsToDelete, flow)
262 }
263 }
264
265 // Process groups
266 for _, g := range newGroups {
267 updatedGroups = append(updatedGroups, g)
268 }
269
270 for _, group := range existingGroups.Items {
271 if fu.FindGroup(newGroups, group.Desc.GroupId) == -1 { // does not exist now
272 updatedGroups = append(updatedGroups, group)
273 } else {
274 groupsToDelete = append(groupsToDelete, group)
275 }
276 }
277
278 // Sanity check
279 if (len(updatedFlows) | len(flowsToDelete) | len(updatedGroups) | len(groupsToDelete)) == 0 {
280 log.Debugw("nothing-to-update", log.Fields{"deviceId": agent.deviceId, "flows": newFlows, "groups": newGroups})
281 return nil
282
283 }
284 // Send update to adapters
285 chAdapters := make(chan interface{})
286 defer close(chAdapters)
287 chdB := make(chan interface{})
288 defer close(chdB)
289 dType := agent.adapterMgr.getDeviceType(device.Type)
290 if !dType.AcceptsAddRemoveFlowUpdates {
291
292 if len(updatedGroups) != 0 && reflect.DeepEqual(existingGroups.Items, updatedGroups) && len(updatedFlows) != 0 && reflect.DeepEqual(existingFlows.Items, updatedFlows) {
293 log.Debugw("nothing-to-update", log.Fields{"deviceId": agent.deviceId, "flows": newFlows, "groups": newGroups})
294 return nil
295 }
296 go agent.sendBulkFlowsToAdapters(device, &voltha.Flows{Items: updatedFlows}, &voltha.FlowGroups{Items: updatedGroups}, chAdapters)
297
298 } else {
299 flowChanges := &ofp.FlowChanges{
300 ToAdd: &voltha.Flows{Items: newFlows},
301 ToRemove: &voltha.Flows{Items: flowsToDelete},
302 }
303 groupChanges := &ofp.FlowGroupChanges{
304 ToAdd: &voltha.FlowGroups{Items: newGroups},
305 ToRemove: &voltha.FlowGroups{Items: groupsToDelete},
306 ToUpdate: &voltha.FlowGroups{Items: []*ofp.OfpGroupEntry{}},
307 }
308 go agent.sendIncrementalFlowsToAdapters(device, flowChanges, groupChanges, chAdapters)
309 }
310
khenaidoo19d7b632018-10-30 10:49:50 -0400311 // store the changed data
khenaidoo2c6a0992019-04-29 13:46:56 -0400312 device.Flows = &voltha.Flows{Items: updatedFlows}
313 device.FlowGroups = &voltha.FlowGroups{Items: updatedGroups}
314 go agent.updateDeviceWithoutLockAsync(device, chdB)
315
316 if res := fu.WaitForNilOrErrorResponses(agent.defaultTimeout, chAdapters, chdB); res != nil {
317 return status.Errorf(codes.Aborted, "errors-%s", res)
khenaidoo19d7b632018-10-30 10:49:50 -0400318 }
319
khenaidoo19d7b632018-10-30 10:49:50 -0400320 return nil
321 }
322}
323
khenaidoo4d4802d2018-10-04 21:59:49 -0400324//disableDevice disable a device
khenaidoo92e62c52018-10-03 14:02:54 -0400325func (agent *DeviceAgent) disableDevice(ctx context.Context) error {
326 agent.lockDevice.Lock()
khenaidoo92e62c52018-10-03 14:02:54 -0400327 log.Debugw("disableDevice", log.Fields{"id": agent.deviceId})
328 // Get the most up to date the device info
329 if device, err := agent.getDeviceWithoutLock(); err != nil {
khenaidoo3ab34882019-05-02 21:33:30 -0400330 agent.lockDevice.Unlock()
khenaidoo92e62c52018-10-03 14:02:54 -0400331 return status.Errorf(codes.NotFound, "%s", agent.deviceId)
332 } else {
333 if device.AdminState == voltha.AdminState_DISABLED {
334 log.Debugw("device-already-disabled", log.Fields{"id": agent.deviceId})
khenaidoo92e62c52018-10-03 14:02:54 -0400335 agent.lockDevice.Unlock()
336 return nil
337 }
338 // First send the request to an Adapter and wait for a response
339 if err := agent.adapterProxy.DisableDevice(ctx, device); err != nil {
340 log.Debugw("disableDevice-error", log.Fields{"id": agent.lastData.Id, "error": err})
341 agent.lockDevice.Unlock()
342 return err
343 }
344 // Received an Ack (no error found above). Now update the device in the model to the expected state
345 cloned := proto.Clone(device).(*voltha.Device)
346 cloned.AdminState = voltha.AdminState_DISABLED
khenaidoo92e62c52018-10-03 14:02:54 -0400347 if afterUpdate := agent.clusterDataProxy.Update("/devices/"+agent.deviceId, cloned, false, ""); afterUpdate == nil {
348 agent.lockDevice.Unlock()
349 return status.Errorf(codes.Internal, "failed-update-device:%s", agent.deviceId)
350 }
351 agent.lockDevice.Unlock()
khenaidoo92e62c52018-10-03 14:02:54 -0400352 }
353 return nil
354}
355
khenaidoo4d4802d2018-10-04 21:59:49 -0400356func (agent *DeviceAgent) rebootDevice(ctx context.Context) error {
357 agent.lockDevice.Lock()
358 defer agent.lockDevice.Unlock()
359 log.Debugw("rebootDevice", log.Fields{"id": agent.deviceId})
360 // Get the most up to date the device info
361 if device, err := agent.getDeviceWithoutLock(); err != nil {
362 return status.Errorf(codes.NotFound, "%s", agent.deviceId)
363 } else {
364 if device.AdminState != voltha.AdminState_DISABLED {
365 log.Debugw("device-not-disabled", log.Fields{"id": agent.deviceId})
366 //TODO: Needs customized error message
367 return status.Errorf(codes.FailedPrecondition, "deviceId:%s, expected-admin-state:%s", agent.deviceId, voltha.AdminState_DISABLED)
368 }
369 // First send the request to an Adapter and wait for a response
370 if err := agent.adapterProxy.RebootDevice(ctx, device); err != nil {
371 log.Debugw("rebootDevice-error", log.Fields{"id": agent.lastData.Id, "error": err})
372 return err
373 }
374 }
375 return nil
376}
377
378func (agent *DeviceAgent) deleteDevice(ctx context.Context) error {
379 agent.lockDevice.Lock()
380 log.Debugw("deleteDevice", log.Fields{"id": agent.deviceId})
381 // Get the most up to date the device info
382 if device, err := agent.getDeviceWithoutLock(); err != nil {
383 agent.lockDevice.Unlock()
384 return status.Errorf(codes.NotFound, "%s", agent.deviceId)
385 } else {
khenaidoo43c82122018-11-22 18:38:28 -0500386 if (device.AdminState != voltha.AdminState_DISABLED) &&
387 (device.AdminState != voltha.AdminState_PREPROVISIONED) {
khenaidoo4d4802d2018-10-04 21:59:49 -0400388 log.Debugw("device-not-disabled", log.Fields{"id": agent.deviceId})
389 //TODO: Needs customized error message
390 agent.lockDevice.Unlock()
391 return status.Errorf(codes.FailedPrecondition, "deviceId:%s, expected-admin-state:%s", agent.deviceId, voltha.AdminState_DISABLED)
392 }
khenaidoo7ccedd52018-12-14 16:48:54 -0500393 if device.AdminState != voltha.AdminState_PREPROVISIONED {
394 // Send the request to an Adapter and wait for a response
395 if err := agent.adapterProxy.DeleteDevice(ctx, device); err != nil {
396 log.Debugw("deleteDevice-error", log.Fields{"id": agent.lastData.Id, "error": err})
397 agent.lockDevice.Unlock()
398 return err
399 }
khenaidoo4d4802d2018-10-04 21:59:49 -0400400 }
khenaidoo7ccedd52018-12-14 16:48:54 -0500401 if removed := agent.clusterDataProxy.Remove("/devices/"+agent.deviceId, ""); removed == nil {
khenaidoo4d4802d2018-10-04 21:59:49 -0400402 agent.lockDevice.Unlock()
403 return status.Errorf(codes.Internal, "failed-update-device:%s", agent.deviceId)
404 }
405 agent.lockDevice.Unlock()
khenaidoo4d4802d2018-10-04 21:59:49 -0400406 }
407 return nil
408}
409
khenaidoof5a5bfa2019-01-23 22:20:29 -0500410func (agent *DeviceAgent) downloadImage(ctx context.Context, img *voltha.ImageDownload) (*voltha.OperationResp, error) {
411 agent.lockDevice.Lock()
412 defer agent.lockDevice.Unlock()
413 log.Debugw("downloadImage", log.Fields{"id": agent.deviceId})
414 // Get the most up to date the device info
415 if device, err := agent.getDeviceWithoutLock(); err != nil {
416 return nil, status.Errorf(codes.NotFound, "%s", agent.deviceId)
417 } else {
418 if device.AdminState != voltha.AdminState_ENABLED {
419 log.Debugw("device-not-enabled", log.Fields{"id": agent.deviceId})
420 return nil, status.Errorf(codes.FailedPrecondition, "deviceId:%s, expected-admin-state:%s", agent.deviceId, voltha.AdminState_ENABLED)
421 }
422 // Save the image
423 clonedImg := proto.Clone(img).(*voltha.ImageDownload)
Stephane Barbariedf5479f2019-01-29 22:13:00 -0500424 clonedImg.DownloadState = voltha.ImageDownload_DOWNLOAD_REQUESTED
khenaidoof5a5bfa2019-01-23 22:20:29 -0500425 cloned := proto.Clone(device).(*voltha.Device)
426 if cloned.ImageDownloads == nil {
427 cloned.ImageDownloads = []*voltha.ImageDownload{clonedImg}
428 } else {
429 cloned.ImageDownloads = append(cloned.ImageDownloads, clonedImg)
430 }
431 cloned.AdminState = voltha.AdminState_DOWNLOADING_IMAGE
432 if afterUpdate := agent.clusterDataProxy.Update("/devices/"+agent.deviceId, cloned, false, ""); afterUpdate == nil {
433 return nil, status.Errorf(codes.Internal, "failed-update-device:%s", agent.deviceId)
434 }
435 // Send the request to the adapter
436 if err := agent.adapterProxy.DownloadImage(ctx, cloned, clonedImg); err != nil {
437 log.Debugw("downloadImage-error", log.Fields{"id": agent.lastData.Id, "error": err, "image": img.Name})
438 return nil, err
439 }
440 }
441 return &voltha.OperationResp{Code: voltha.OperationResp_OPERATION_SUCCESS}, nil
442}
443
444// isImageRegistered is a helper method to figure out if an image is already registered
445func isImageRegistered(img *voltha.ImageDownload, device *voltha.Device) bool {
446 for _, image := range device.ImageDownloads {
447 if image.Id == img.Id && image.Name == img.Name {
448 return true
449 }
450 }
451 return false
452}
453
454func (agent *DeviceAgent) cancelImageDownload(ctx context.Context, img *voltha.ImageDownload) (*voltha.OperationResp, error) {
455 agent.lockDevice.Lock()
456 defer agent.lockDevice.Unlock()
457 log.Debugw("cancelImageDownload", log.Fields{"id": agent.deviceId})
458 // Get the most up to date the device info
459 if device, err := agent.getDeviceWithoutLock(); err != nil {
460 return nil, status.Errorf(codes.NotFound, "%s", agent.deviceId)
461 } else {
462 // Verify whether the Image is in the list of image being downloaded
463 if !isImageRegistered(img, device) {
464 return nil, status.Errorf(codes.FailedPrecondition, "deviceId:%s, image-not-registered:%s", agent.deviceId, img.Name)
465 }
466
467 // Update image download state
468 cloned := proto.Clone(device).(*voltha.Device)
469 for _, image := range cloned.ImageDownloads {
470 if image.Id == img.Id && image.Name == img.Name {
Stephane Barbariedf5479f2019-01-29 22:13:00 -0500471 image.DownloadState = voltha.ImageDownload_DOWNLOAD_CANCELLED
khenaidoof5a5bfa2019-01-23 22:20:29 -0500472 }
473 }
474
475 //If device is in downloading state, send the request to cancel the download
476 if device.AdminState == voltha.AdminState_DOWNLOADING_IMAGE {
477 if err := agent.adapterProxy.CancelImageDownload(ctx, device, img); err != nil {
478 log.Debugw("cancelImageDownload-error", log.Fields{"id": agent.lastData.Id, "error": err, "image": img.Name})
479 return nil, err
480 }
481 // Set the device to Enabled
482 cloned.AdminState = voltha.AdminState_ENABLED
483 if afterUpdate := agent.clusterDataProxy.Update("/devices/"+agent.deviceId, cloned, false, ""); afterUpdate == nil {
484 return nil, status.Errorf(codes.Internal, "failed-update-device:%s", agent.deviceId)
485 }
486 }
487 }
488 return &voltha.OperationResp{Code: voltha.OperationResp_OPERATION_SUCCESS}, nil
serkant.uluderya334479d2019-04-10 08:26:15 -0700489}
khenaidoof5a5bfa2019-01-23 22:20:29 -0500490
491func (agent *DeviceAgent) activateImage(ctx context.Context, img *voltha.ImageDownload) (*voltha.OperationResp, error) {
492 agent.lockDevice.Lock()
493 defer agent.lockDevice.Unlock()
494 log.Debugw("activateImage", log.Fields{"id": agent.deviceId})
495 // Get the most up to date the device info
496 if device, err := agent.getDeviceWithoutLock(); err != nil {
497 return nil, status.Errorf(codes.NotFound, "%s", agent.deviceId)
498 } else {
499 // Verify whether the Image is in the list of image being downloaded
500 if !isImageRegistered(img, device) {
501 return nil, status.Errorf(codes.FailedPrecondition, "deviceId:%s, image-not-registered:%s", agent.deviceId, img.Name)
502 }
503
504 if device.AdminState == voltha.AdminState_DOWNLOADING_IMAGE {
505 return nil, status.Errorf(codes.FailedPrecondition, "deviceId:%s, device-in-downloading-state:%s", agent.deviceId, img.Name)
506 }
507 // Update image download state
508 cloned := proto.Clone(device).(*voltha.Device)
509 for _, image := range cloned.ImageDownloads {
510 if image.Id == img.Id && image.Name == img.Name {
511 image.ImageState = voltha.ImageDownload_IMAGE_ACTIVATING
512 }
513 }
514 // Set the device to downloading_image
515 cloned.AdminState = voltha.AdminState_DOWNLOADING_IMAGE
516 if afterUpdate := agent.clusterDataProxy.Update("/devices/"+agent.deviceId, cloned, false, ""); afterUpdate == nil {
517 return nil, status.Errorf(codes.Internal, "failed-update-device:%s", agent.deviceId)
518 }
519
520 if err := agent.adapterProxy.ActivateImageUpdate(ctx, device, img); err != nil {
521 log.Debugw("activateImage-error", log.Fields{"id": agent.lastData.Id, "error": err, "image": img.Name})
522 return nil, err
523 }
524 // The status of the AdminState will be changed following the update_download_status response from the adapter
525 // The image name will also be removed from the device list
526 }
serkant.uluderya334479d2019-04-10 08:26:15 -0700527 return &voltha.OperationResp{Code: voltha.OperationResp_OPERATION_SUCCESS}, nil
528}
khenaidoof5a5bfa2019-01-23 22:20:29 -0500529
530func (agent *DeviceAgent) revertImage(ctx context.Context, img *voltha.ImageDownload) (*voltha.OperationResp, error) {
531 agent.lockDevice.Lock()
532 defer agent.lockDevice.Unlock()
533 log.Debugw("revertImage", log.Fields{"id": agent.deviceId})
534 // Get the most up to date the device info
535 if device, err := agent.getDeviceWithoutLock(); err != nil {
536 return nil, status.Errorf(codes.NotFound, "%s", agent.deviceId)
537 } else {
538 // Verify whether the Image is in the list of image being downloaded
539 if !isImageRegistered(img, device) {
540 return nil, status.Errorf(codes.FailedPrecondition, "deviceId:%s, image-not-registered:%s", agent.deviceId, img.Name)
541 }
542
543 if device.AdminState != voltha.AdminState_ENABLED {
544 return nil, status.Errorf(codes.FailedPrecondition, "deviceId:%s, device-not-enabled-state:%s", agent.deviceId, img.Name)
545 }
546 // Update image download state
547 cloned := proto.Clone(device).(*voltha.Device)
548 for _, image := range cloned.ImageDownloads {
549 if image.Id == img.Id && image.Name == img.Name {
550 image.ImageState = voltha.ImageDownload_IMAGE_REVERTING
551 }
552 }
553 if afterUpdate := agent.clusterDataProxy.Update("/devices/"+agent.deviceId, cloned, false, ""); afterUpdate == nil {
554 return nil, status.Errorf(codes.Internal, "failed-update-device:%s", agent.deviceId)
555 }
556
557 if err := agent.adapterProxy.RevertImageUpdate(ctx, device, img); err != nil {
558 log.Debugw("revertImage-error", log.Fields{"id": agent.lastData.Id, "error": err, "image": img.Name})
559 return nil, err
560 }
561 }
562 return &voltha.OperationResp{Code: voltha.OperationResp_OPERATION_SUCCESS}, nil
serkant.uluderya334479d2019-04-10 08:26:15 -0700563}
khenaidoof5a5bfa2019-01-23 22:20:29 -0500564
565func (agent *DeviceAgent) getImageDownloadStatus(ctx context.Context, img *voltha.ImageDownload) (*voltha.ImageDownload, error) {
566 agent.lockDevice.Lock()
567 defer agent.lockDevice.Unlock()
568 log.Debugw("getImageDownloadStatus", log.Fields{"id": agent.deviceId})
569 // Get the most up to date the device info
570 if device, err := agent.getDeviceWithoutLock(); err != nil {
571 return nil, status.Errorf(codes.NotFound, "%s", agent.deviceId)
572 } else {
573 if resp, err := agent.adapterProxy.GetImageDownloadStatus(ctx, device, img); err != nil {
574 log.Debugw("getImageDownloadStatus-error", log.Fields{"id": agent.lastData.Id, "error": err, "image": img.Name})
575 return nil, err
576 } else {
577 return resp, nil
578 }
579 }
580}
581
serkant.uluderya334479d2019-04-10 08:26:15 -0700582func (agent *DeviceAgent) updateImageDownload(img *voltha.ImageDownload) error {
khenaidoof5a5bfa2019-01-23 22:20:29 -0500583 agent.lockDevice.Lock()
584 defer agent.lockDevice.Unlock()
585 log.Debugw("updateImageDownload", log.Fields{"id": agent.deviceId})
586 // Get the most up to date the device info
587 if device, err := agent.getDeviceWithoutLock(); err != nil {
588 return status.Errorf(codes.NotFound, "%s", agent.deviceId)
589 } else {
590 // Update the image as well as remove it if the download was cancelled
591 cloned := proto.Clone(device).(*voltha.Device)
592 clonedImages := make([]*voltha.ImageDownload, len(cloned.ImageDownloads))
593 for _, image := range cloned.ImageDownloads {
594 if image.Id == img.Id && image.Name == img.Name {
Stephane Barbariedf5479f2019-01-29 22:13:00 -0500595 if image.DownloadState != voltha.ImageDownload_DOWNLOAD_CANCELLED {
khenaidoof5a5bfa2019-01-23 22:20:29 -0500596 clonedImages = append(clonedImages, img)
597 }
598 }
599 }
600 cloned.ImageDownloads = clonedImages
601 // Set the Admin state to enabled if required
Stephane Barbariedf5479f2019-01-29 22:13:00 -0500602 if (img.DownloadState != voltha.ImageDownload_DOWNLOAD_REQUESTED &&
603 img.DownloadState != voltha.ImageDownload_DOWNLOAD_STARTED) ||
serkant.uluderya334479d2019-04-10 08:26:15 -0700604 (img.ImageState != voltha.ImageDownload_IMAGE_ACTIVATING) {
khenaidoof5a5bfa2019-01-23 22:20:29 -0500605 cloned.AdminState = voltha.AdminState_ENABLED
606 }
607
608 if afterUpdate := agent.clusterDataProxy.Update("/devices/"+agent.deviceId, cloned, false, ""); afterUpdate == nil {
609 return status.Errorf(codes.Internal, "failed-update-device:%s", agent.deviceId)
610 }
611 }
612 return nil
613}
614
615func (agent *DeviceAgent) getImageDownload(ctx context.Context, img *voltha.ImageDownload) (*voltha.ImageDownload, error) {
khenaidoo1ce37ad2019-03-24 22:07:24 -0400616 agent.lockDevice.RLock()
617 defer agent.lockDevice.RUnlock()
khenaidoof5a5bfa2019-01-23 22:20:29 -0500618 log.Debugw("getImageDownload", log.Fields{"id": agent.deviceId})
619 // Get the most up to date the device info
620 if device, err := agent.getDeviceWithoutLock(); err != nil {
621 return nil, status.Errorf(codes.NotFound, "%s", agent.deviceId)
622 } else {
623 for _, image := range device.ImageDownloads {
624 if image.Id == img.Id && image.Name == img.Name {
625 return image, nil
626 }
627 }
628 return nil, status.Errorf(codes.NotFound, "image-not-found:%s", img.Name)
629 }
630}
631
632func (agent *DeviceAgent) listImageDownloads(ctx context.Context, deviceId string) (*voltha.ImageDownloads, error) {
khenaidoo1ce37ad2019-03-24 22:07:24 -0400633 agent.lockDevice.RLock()
634 defer agent.lockDevice.RUnlock()
khenaidoof5a5bfa2019-01-23 22:20:29 -0500635 log.Debugw("listImageDownloads", log.Fields{"id": agent.deviceId})
636 // Get the most up to date the device info
637 if device, err := agent.getDeviceWithoutLock(); err != nil {
638 return nil, status.Errorf(codes.NotFound, "%s", agent.deviceId)
639 } else {
serkant.uluderya334479d2019-04-10 08:26:15 -0700640 return &voltha.ImageDownloads{Items: device.ImageDownloads}, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -0500641 }
642}
643
khenaidoo4d4802d2018-10-04 21:59:49 -0400644// getPorts retrieves the ports information of the device based on the port type.
khenaidoo92e62c52018-10-03 14:02:54 -0400645func (agent *DeviceAgent) getPorts(ctx context.Context, portType voltha.Port_PortType) *voltha.Ports {
646 log.Debugw("getPorts", log.Fields{"id": agent.deviceId, "portType": portType})
khenaidoob9203542018-09-17 22:56:37 -0400647 ports := &voltha.Ports{}
khenaidoo19d7b632018-10-30 10:49:50 -0400648 if device, _ := agent.deviceMgr.GetDevice(agent.deviceId); device != nil {
khenaidoob9203542018-09-17 22:56:37 -0400649 for _, port := range device.Ports {
khenaidoo92e62c52018-10-03 14:02:54 -0400650 if port.Type == portType {
khenaidoob9203542018-09-17 22:56:37 -0400651 ports.Items = append(ports.Items, port)
652 }
653 }
654 }
655 return ports
656}
657
khenaidoo4d4802d2018-10-04 21:59:49 -0400658// getSwitchCapability is a helper method that a logical device agent uses to retrieve the switch capability of a
659// parent device
khenaidoo79232702018-12-04 11:00:41 -0500660func (agent *DeviceAgent) getSwitchCapability(ctx context.Context) (*ic.SwitchCapability, error) {
khenaidoob9203542018-09-17 22:56:37 -0400661 log.Debugw("getSwitchCapability", log.Fields{"deviceId": agent.deviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400662 if device, err := agent.deviceMgr.GetDevice(agent.deviceId); device == nil {
khenaidoob9203542018-09-17 22:56:37 -0400663 return nil, err
664 } else {
khenaidoo79232702018-12-04 11:00:41 -0500665 var switchCap *ic.SwitchCapability
khenaidoob9203542018-09-17 22:56:37 -0400666 var err error
667 if switchCap, err = agent.adapterProxy.GetOfpDeviceInfo(ctx, device); err != nil {
668 log.Debugw("getSwitchCapability-error", log.Fields{"id": device.Id, "error": err})
669 return nil, err
670 }
671 return switchCap, nil
672 }
673}
674
khenaidoo4d4802d2018-10-04 21:59:49 -0400675// getPortCapability is a helper method that a logical device agent uses to retrieve the port capability of a
676// device
khenaidoo79232702018-12-04 11:00:41 -0500677func (agent *DeviceAgent) getPortCapability(ctx context.Context, portNo uint32) (*ic.PortCapability, error) {
khenaidoob9203542018-09-17 22:56:37 -0400678 log.Debugw("getPortCapability", log.Fields{"deviceId": agent.deviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400679 if device, err := agent.deviceMgr.GetDevice(agent.deviceId); device == nil {
khenaidoob9203542018-09-17 22:56:37 -0400680 return nil, err
681 } else {
khenaidoo79232702018-12-04 11:00:41 -0500682 var portCap *ic.PortCapability
khenaidoob9203542018-09-17 22:56:37 -0400683 var err error
684 if portCap, err = agent.adapterProxy.GetOfpPortInfo(ctx, device, portNo); err != nil {
685 log.Debugw("getPortCapability-error", log.Fields{"id": device.Id, "error": err})
686 return nil, err
687 }
688 return portCap, nil
689 }
690}
691
khenaidoofdbad6e2018-11-06 22:26:38 -0500692func (agent *DeviceAgent) packetOut(outPort uint32, packet *ofp.OfpPacketOut) error {
693 // Send packet to adapter
694 if err := agent.adapterProxy.packetOut(agent.deviceType, agent.deviceId, outPort, packet); err != nil {
695 log.Debugw("packet-out-error", log.Fields{"id": agent.lastData.Id, "error": err})
696 return err
697 }
698 return nil
699}
700
khenaidoo4d4802d2018-10-04 21:59:49 -0400701// processUpdate is a callback invoked whenever there is a change on the device manages by this device agent
khenaidoo92e62c52018-10-03 14:02:54 -0400702func (agent *DeviceAgent) processUpdate(args ...interface{}) interface{} {
khenaidoo43c82122018-11-22 18:38:28 -0500703 //// Run this callback in its own go routine
704 go func(args ...interface{}) interface{} {
705 var previous *voltha.Device
706 var current *voltha.Device
707 var ok bool
708 if len(args) == 2 {
709 if previous, ok = args[0].(*voltha.Device); !ok {
710 log.Errorw("invalid-callback-type", log.Fields{"data": args[0]})
711 return nil
712 }
713 if current, ok = args[1].(*voltha.Device); !ok {
714 log.Errorw("invalid-callback-type", log.Fields{"data": args[1]})
715 return nil
716 }
717 } else {
718 log.Errorw("too-many-args-in-callback", log.Fields{"len": len(args)})
719 return nil
720 }
721 // Perform the state transition in it's own go routine
khenaidoof5a5bfa2019-01-23 22:20:29 -0500722 if err := agent.deviceMgr.processTransition(previous, current); err != nil {
723 log.Errorw("failed-process-transition", log.Fields{"deviceId": previous.Id,
724 "previousAdminState": previous.AdminState, "currentAdminState": current.AdminState})
725 }
khenaidoo43c82122018-11-22 18:38:28 -0500726 return nil
727 }(args...)
728
khenaidoo92e62c52018-10-03 14:02:54 -0400729 return nil
730}
731
khenaidoob9203542018-09-17 22:56:37 -0400732func (agent *DeviceAgent) updateDevice(device *voltha.Device) error {
khenaidoo92e62c52018-10-03 14:02:54 -0400733 agent.lockDevice.Lock()
khenaidoo43c82122018-11-22 18:38:28 -0500734 defer agent.lockDevice.Unlock()
khenaidoob9203542018-09-17 22:56:37 -0400735 log.Debugw("updateDevice", log.Fields{"deviceId": device.Id})
khenaidoo43c82122018-11-22 18:38:28 -0500736 cloned := proto.Clone(device).(*voltha.Device)
737 afterUpdate := agent.clusterDataProxy.Update("/devices/"+device.Id, cloned, false, "")
738 if afterUpdate == nil {
739 return status.Errorf(codes.Internal, "%s", device.Id)
khenaidoob9203542018-09-17 22:56:37 -0400740 }
khenaidoo43c82122018-11-22 18:38:28 -0500741 return nil
742}
743
744func (agent *DeviceAgent) updateDeviceWithoutLock(device *voltha.Device) error {
745 log.Debugw("updateDevice", log.Fields{"deviceId": device.Id})
746 cloned := proto.Clone(device).(*voltha.Device)
747 afterUpdate := agent.clusterDataProxy.Update("/devices/"+device.Id, cloned, false, "")
748 if afterUpdate == nil {
749 return status.Errorf(codes.Internal, "%s", device.Id)
750 }
751 return nil
khenaidoob9203542018-09-17 22:56:37 -0400752}
753
khenaidoo92e62c52018-10-03 14:02:54 -0400754func (agent *DeviceAgent) updateDeviceStatus(operStatus voltha.OperStatus_OperStatus, connStatus voltha.ConnectStatus_ConnectStatus) error {
755 agent.lockDevice.Lock()
khenaidoob9203542018-09-17 22:56:37 -0400756 // Work only on latest data
khenaidoo92e62c52018-10-03 14:02:54 -0400757 if storeDevice, err := agent.getDeviceWithoutLock(); err != nil {
758 agent.lockDevice.Unlock()
khenaidoob9203542018-09-17 22:56:37 -0400759 return status.Errorf(codes.NotFound, "%s", agent.deviceId)
760 } else {
761 // clone the device
khenaidoo92e62c52018-10-03 14:02:54 -0400762 cloned := proto.Clone(storeDevice).(*voltha.Device)
763 // Ensure the enums passed in are valid - they will be invalid if they are not set when this function is invoked
764 if s, ok := voltha.ConnectStatus_ConnectStatus_value[connStatus.String()]; ok {
765 log.Debugw("updateDeviceStatus-conn", log.Fields{"ok": ok, "val": s})
766 cloned.ConnectStatus = connStatus
khenaidoob9203542018-09-17 22:56:37 -0400767 }
khenaidoo92e62c52018-10-03 14:02:54 -0400768 if s, ok := voltha.OperStatus_OperStatus_value[operStatus.String()]; ok {
769 log.Debugw("updateDeviceStatus-oper", log.Fields{"ok": ok, "val": s})
770 cloned.OperStatus = operStatus
khenaidoob9203542018-09-17 22:56:37 -0400771 }
khenaidoo92e62c52018-10-03 14:02:54 -0400772 log.Debugw("updateDeviceStatus", log.Fields{"deviceId": cloned.Id, "operStatus": cloned.OperStatus, "connectStatus": cloned.ConnectStatus})
khenaidoob9203542018-09-17 22:56:37 -0400773 // Store the device
khenaidoo92e62c52018-10-03 14:02:54 -0400774 if afterUpdate := agent.clusterDataProxy.Update("/devices/"+agent.deviceId, cloned, false, ""); afterUpdate == nil {
775 agent.lockDevice.Unlock()
khenaidoob9203542018-09-17 22:56:37 -0400776 return status.Errorf(codes.Internal, "%s", agent.deviceId)
777 }
khenaidoo92e62c52018-10-03 14:02:54 -0400778 agent.lockDevice.Unlock()
khenaidoo92e62c52018-10-03 14:02:54 -0400779 return nil
780 }
781}
782
khenaidoo3ab34882019-05-02 21:33:30 -0400783func (agent *DeviceAgent) enablePorts() error {
784 agent.lockDevice.Lock()
785 defer agent.lockDevice.Unlock()
786 if storeDevice, err := agent.getDeviceWithoutLock(); err != nil {
787 return status.Errorf(codes.NotFound, "%s", agent.deviceId)
788 } else {
789 // clone the device
790 cloned := proto.Clone(storeDevice).(*voltha.Device)
791 for _, port := range cloned.Ports {
792 port.AdminState = voltha.AdminState_ENABLED
793 port.OperStatus = voltha.OperStatus_ACTIVE
794 }
795 // Store the device
796 if afterUpdate := agent.clusterDataProxy.Update("/devices/"+agent.deviceId, cloned, false, ""); afterUpdate == nil {
797 return status.Errorf(codes.Internal, "%s", agent.deviceId)
798 }
799 return nil
800 }
801}
802
803func (agent *DeviceAgent) disablePorts() error {
804 agent.lockDevice.Lock()
805 defer agent.lockDevice.Unlock()
806 if storeDevice, err := agent.getDeviceWithoutLock(); err != nil {
807 return status.Errorf(codes.NotFound, "%s", agent.deviceId)
808 } else {
809 // clone the device
810 cloned := proto.Clone(storeDevice).(*voltha.Device)
811 for _, port := range cloned.Ports {
812 port.AdminState = voltha.AdminState_DISABLED
813 port.OperStatus = voltha.OperStatus_UNKNOWN
814 }
815 // Store the device
816 if afterUpdate := agent.clusterDataProxy.Update("/devices/"+agent.deviceId, cloned, false, ""); afterUpdate == nil {
817 return status.Errorf(codes.Internal, "%s", agent.deviceId)
818 }
819 return nil
820 }
821}
822
khenaidoo92e62c52018-10-03 14:02:54 -0400823func (agent *DeviceAgent) updatePortState(portType voltha.Port_PortType, portNo uint32, operStatus voltha.OperStatus_OperStatus) error {
824 agent.lockDevice.Lock()
khenaidoo92e62c52018-10-03 14:02:54 -0400825 // Work only on latest data
826 // TODO: Get list of ports from device directly instead of the entire device
827 if storeDevice, err := agent.getDeviceWithoutLock(); err != nil {
828 agent.lockDevice.Unlock()
829 return status.Errorf(codes.NotFound, "%s", agent.deviceId)
830 } else {
831 // clone the device
832 cloned := proto.Clone(storeDevice).(*voltha.Device)
833 // Ensure the enums passed in are valid - they will be invalid if they are not set when this function is invoked
834 if _, ok := voltha.Port_PortType_value[portType.String()]; !ok {
835 agent.lockDevice.Unlock()
836 return status.Errorf(codes.InvalidArgument, "%s", portType)
837 }
838 for _, port := range cloned.Ports {
839 if port.Type == portType && port.PortNo == portNo {
840 port.OperStatus = operStatus
841 // Set the admin status to ENABLED if the operational status is ACTIVE
842 // TODO: Set by northbound system?
843 if operStatus == voltha.OperStatus_ACTIVE {
844 port.AdminState = voltha.AdminState_ENABLED
845 }
846 break
847 }
848 }
849 log.Debugw("portStatusUpdate", log.Fields{"deviceId": cloned.Id})
850 // Store the device
851 if afterUpdate := agent.clusterDataProxy.Update("/devices/"+agent.deviceId, cloned, false, ""); afterUpdate == nil {
852 agent.lockDevice.Unlock()
853 return status.Errorf(codes.Internal, "%s", agent.deviceId)
854 }
855 agent.lockDevice.Unlock()
khenaidoob9203542018-09-17 22:56:37 -0400856 return nil
857 }
858}
859
860func (agent *DeviceAgent) updatePmConfigs(pmConfigs *voltha.PmConfigs) error {
khenaidoo92e62c52018-10-03 14:02:54 -0400861 agent.lockDevice.Lock()
862 defer agent.lockDevice.Unlock()
khenaidoob9203542018-09-17 22:56:37 -0400863 log.Debug("updatePmConfigs")
864 // Work only on latest data
khenaidoo92e62c52018-10-03 14:02:54 -0400865 if storeDevice, err := agent.getDeviceWithoutLock(); err != nil {
khenaidoob9203542018-09-17 22:56:37 -0400866 return status.Errorf(codes.NotFound, "%s", agent.deviceId)
867 } else {
868 // clone the device
khenaidoo92e62c52018-10-03 14:02:54 -0400869 cloned := proto.Clone(storeDevice).(*voltha.Device)
870 cloned.PmConfigs = proto.Clone(pmConfigs).(*voltha.PmConfigs)
khenaidoob9203542018-09-17 22:56:37 -0400871 // Store the device
khenaidoo92e62c52018-10-03 14:02:54 -0400872 afterUpdate := agent.clusterDataProxy.Update("/devices/"+agent.deviceId, cloned, false, "")
khenaidoob9203542018-09-17 22:56:37 -0400873 if afterUpdate == nil {
874 return status.Errorf(codes.Internal, "%s", agent.deviceId)
875 }
876 return nil
877 }
878}
879
880func (agent *DeviceAgent) addPort(port *voltha.Port) error {
khenaidoo92e62c52018-10-03 14:02:54 -0400881 agent.lockDevice.Lock()
882 defer agent.lockDevice.Unlock()
khenaidoo2c6a0992019-04-29 13:46:56 -0400883 log.Debugw("addLogicalPortToMap", log.Fields{"deviceId": agent.deviceId})
khenaidoob9203542018-09-17 22:56:37 -0400884 // Work only on latest data
khenaidoo92e62c52018-10-03 14:02:54 -0400885 if storeDevice, err := agent.getDeviceWithoutLock(); err != nil {
khenaidoob9203542018-09-17 22:56:37 -0400886 return status.Errorf(codes.NotFound, "%s", agent.deviceId)
887 } else {
888 // clone the device
khenaidoo92e62c52018-10-03 14:02:54 -0400889 cloned := proto.Clone(storeDevice).(*voltha.Device)
khenaidoob9203542018-09-17 22:56:37 -0400890 if cloned.Ports == nil {
891 // First port
khenaidoo2c6a0992019-04-29 13:46:56 -0400892 log.Debugw("addLogicalPortToMap-first-port-to-add", log.Fields{"deviceId": agent.deviceId})
khenaidoob9203542018-09-17 22:56:37 -0400893 cloned.Ports = make([]*voltha.Port, 0)
894 }
khenaidoo92e62c52018-10-03 14:02:54 -0400895 cp := proto.Clone(port).(*voltha.Port)
896 // Set the admin state of the port to ENABLE if the operational state is ACTIVE
897 // TODO: Set by northbound system?
898 if cp.OperStatus == voltha.OperStatus_ACTIVE {
899 cp.AdminState = voltha.AdminState_ENABLED
900 }
901 cloned.Ports = append(cloned.Ports, cp)
khenaidoob9203542018-09-17 22:56:37 -0400902 // Store the device
khenaidoo92e62c52018-10-03 14:02:54 -0400903 afterUpdate := agent.clusterDataProxy.Update("/devices/"+agent.deviceId, cloned, false, "")
904 if afterUpdate == nil {
905 return status.Errorf(codes.Internal, "%s", agent.deviceId)
906 }
907 return nil
908 }
909}
910
911func (agent *DeviceAgent) addPeerPort(port *voltha.Port_PeerPort) error {
912 agent.lockDevice.Lock()
913 defer agent.lockDevice.Unlock()
914 log.Debug("addPeerPort")
915 // Work only on latest data
916 if storeDevice, err := agent.getDeviceWithoutLock(); err != nil {
917 return status.Errorf(codes.NotFound, "%s", agent.deviceId)
918 } else {
919 // clone the device
920 cloned := proto.Clone(storeDevice).(*voltha.Device)
921 // Get the peer port on the device based on the port no
922 for _, peerPort := range cloned.Ports {
923 if peerPort.PortNo == port.PortNo { // found port
924 cp := proto.Clone(port).(*voltha.Port_PeerPort)
925 peerPort.Peers = append(peerPort.Peers, cp)
926 log.Debugw("found-peer", log.Fields{"portNo": port.PortNo, "deviceId": agent.deviceId})
927 break
928 }
929 }
930 // Store the device
931 afterUpdate := agent.clusterDataProxy.Update("/devices/"+agent.deviceId, cloned, false, "")
khenaidoob9203542018-09-17 22:56:37 -0400932 if afterUpdate == nil {
933 return status.Errorf(codes.Internal, "%s", agent.deviceId)
934 }
935 return nil
936 }
937}
938
939// TODO: A generic device update by attribute
940func (agent *DeviceAgent) updateDeviceAttribute(name string, value interface{}) {
khenaidoo92e62c52018-10-03 14:02:54 -0400941 agent.lockDevice.Lock()
942 defer agent.lockDevice.Unlock()
khenaidoob9203542018-09-17 22:56:37 -0400943 if value == nil {
944 return
945 }
946 var storeDevice *voltha.Device
947 var err error
khenaidoo92e62c52018-10-03 14:02:54 -0400948 if storeDevice, err = agent.getDeviceWithoutLock(); err != nil {
khenaidoob9203542018-09-17 22:56:37 -0400949 return
950 }
951 updated := false
952 s := reflect.ValueOf(storeDevice).Elem()
953 if s.Kind() == reflect.Struct {
954 // exported field
955 f := s.FieldByName(name)
956 if f.IsValid() && f.CanSet() {
957 switch f.Kind() {
958 case reflect.String:
959 f.SetString(value.(string))
960 updated = true
961 case reflect.Uint32:
962 f.SetUint(uint64(value.(uint32)))
963 updated = true
964 case reflect.Bool:
965 f.SetBool(value.(bool))
966 updated = true
967 }
968 }
969 }
khenaidoo92e62c52018-10-03 14:02:54 -0400970 log.Debugw("update-field-status", log.Fields{"deviceId": storeDevice.Id, "name": name, "updated": updated})
khenaidoob9203542018-09-17 22:56:37 -0400971 // Save the data
khenaidoo92e62c52018-10-03 14:02:54 -0400972 cloned := proto.Clone(storeDevice).(*voltha.Device)
973 if afterUpdate := agent.clusterDataProxy.Update("/devices/"+agent.deviceId, cloned, false, ""); afterUpdate == nil {
khenaidoob9203542018-09-17 22:56:37 -0400974 log.Warnw("attribute-update-failed", log.Fields{"attribute": name, "value": value})
975 }
976 return
977}
serkant.uluderya334479d2019-04-10 08:26:15 -0700978
979func (agent *DeviceAgent) simulateAlarm(ctx context.Context, simulatereq *voltha.SimulateAlarmRequest) error {
980 agent.lockDevice.Lock()
981 defer agent.lockDevice.Unlock()
982 log.Debugw("simulateAlarm", log.Fields{"id": agent.deviceId})
983 // Get the most up to date the device info
984 if device, err := agent.getDeviceWithoutLock(); err != nil {
985 return status.Errorf(codes.NotFound, "%s", agent.deviceId)
986 } else {
987 // First send the request to an Adapter and wait for a response
988 if err := agent.adapterProxy.SimulateAlarm(ctx, device, simulatereq); err != nil {
989 log.Debugw("simulateAlarm-error", log.Fields{"id": agent.lastData.Id, "error": err})
990 return err
991 }
992 }
993 return nil
994}