blob: 57186149abefe1031aafe963ea00b07f8d042f07 [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
khenaidoo6d62c002019-05-15 21:57:03 -040036 parentId string
khenaidoo43c82122018-11-22 18:38:28 -050037 deviceType string
khenaidoo2c6a0992019-04-29 13:46:56 -040038 isRootdevice bool
khenaidoo9a468962018-09-19 15:33:13 -040039 lastData *voltha.Device
40 adapterProxy *AdapterProxy
serkant.uluderya334479d2019-04-10 08:26:15 -070041 adapterMgr *AdapterManager
khenaidoo9a468962018-09-19 15:33:13 -040042 deviceMgr *DeviceManager
43 clusterDataProxy *model.Proxy
khenaidoo92e62c52018-10-03 14:02:54 -040044 deviceProxy *model.Proxy
khenaidoo9a468962018-09-19 15:33:13 -040045 exitChannel chan int
khenaidoo92e62c52018-10-03 14:02:54 -040046 lockDevice sync.RWMutex
khenaidoo2c6a0992019-04-29 13:46:56 -040047 defaultTimeout int64
khenaidoob9203542018-09-17 22:56:37 -040048}
49
khenaidoo4d4802d2018-10-04 21:59:49 -040050//newDeviceAgent creates a new device agent along as creating a unique ID for the device and set the device state to
51//preprovisioning
khenaidoo2c6a0992019-04-29 13:46:56 -040052func newDeviceAgent(ap *AdapterProxy, device *voltha.Device, deviceMgr *DeviceManager, cdProxy *model.Proxy, timeout int64) *DeviceAgent {
khenaidoob9203542018-09-17 22:56:37 -040053 var agent DeviceAgent
khenaidoob9203542018-09-17 22:56:37 -040054 agent.adapterProxy = ap
khenaidoo92e62c52018-10-03 14:02:54 -040055 cloned := (proto.Clone(device)).(*voltha.Device)
Stephane Barbarie1ab43272018-12-08 21:42:13 -050056 if cloned.Id == "" {
57 cloned.Id = CreateDeviceId()
khenaidoo297cd252019-02-07 22:10:23 -050058 cloned.AdminState = voltha.AdminState_PREPROVISIONED
59 cloned.FlowGroups = &ofp.FlowGroups{Items: nil}
60 cloned.Flows = &ofp.Flows{Items: nil}
Stephane Barbarie1ab43272018-12-08 21:42:13 -050061 }
khenaidoo19d7b632018-10-30 10:49:50 -040062 if !device.GetRoot() && device.ProxyAddress != nil {
63 // Set the default vlan ID to the one specified by the parent adapter. It can be
64 // overwritten by the child adapter during a device update request
65 cloned.Vlan = device.ProxyAddress.ChannelId
66 }
khenaidoo2c6a0992019-04-29 13:46:56 -040067 agent.isRootdevice = device.Root
khenaidoo92e62c52018-10-03 14:02:54 -040068 agent.deviceId = cloned.Id
khenaidoo6d62c002019-05-15 21:57:03 -040069 agent.parentId = device.ParentId
khenaidoofdbad6e2018-11-06 22:26:38 -050070 agent.deviceType = cloned.Type
khenaidoo92e62c52018-10-03 14:02:54 -040071 agent.lastData = cloned
khenaidoob9203542018-09-17 22:56:37 -040072 agent.deviceMgr = deviceMgr
khenaidoo21d51152019-02-01 13:48:37 -050073 agent.adapterMgr = deviceMgr.adapterMgr
khenaidoob9203542018-09-17 22:56:37 -040074 agent.exitChannel = make(chan int, 1)
khenaidoo9a468962018-09-19 15:33:13 -040075 agent.clusterDataProxy = cdProxy
khenaidoo92e62c52018-10-03 14:02:54 -040076 agent.lockDevice = sync.RWMutex{}
khenaidoo2c6a0992019-04-29 13:46:56 -040077 agent.defaultTimeout = timeout
khenaidoob9203542018-09-17 22:56:37 -040078 return &agent
79}
80
khenaidoo297cd252019-02-07 22:10:23 -050081// start save the device to the data model and registers for callbacks on that device if loadFromdB is false. Otherwise,
82// it will load the data from the dB and setup teh necessary callbacks and proxies.
83func (agent *DeviceAgent) start(ctx context.Context, loadFromdB bool) error {
khenaidoo92e62c52018-10-03 14:02:54 -040084 agent.lockDevice.Lock()
85 defer agent.lockDevice.Unlock()
khenaidoo297cd252019-02-07 22:10:23 -050086 log.Debugw("starting-device-agent", log.Fields{"deviceId": agent.deviceId})
87 if loadFromdB {
88 if device := agent.clusterDataProxy.Get("/devices/"+agent.deviceId, 1, false, ""); device != nil {
89 if d, ok := device.(*voltha.Device); ok {
90 agent.lastData = proto.Clone(d).(*voltha.Device)
khenaidoo6d055132019-02-12 16:51:19 -050091 agent.deviceType = agent.lastData.Adapter
khenaidoo297cd252019-02-07 22:10:23 -050092 }
93 } else {
94 log.Errorw("failed-to-load-device", log.Fields{"deviceId": agent.deviceId})
95 return status.Errorf(codes.NotFound, "device-%s", agent.deviceId)
96 }
97 log.Debugw("device-loaded-from-dB", log.Fields{"device": agent.lastData})
98 } else {
99 // Add the initial device to the local model
100 if added := agent.clusterDataProxy.AddWithID("/devices", agent.deviceId, agent.lastData, ""); added == nil {
101 log.Errorw("failed-to-add-device", log.Fields{"deviceId": agent.deviceId})
102 }
khenaidoob9203542018-09-17 22:56:37 -0400103 }
khenaidoo297cd252019-02-07 22:10:23 -0500104
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400105 agent.deviceProxy = agent.clusterDataProxy.CreateProxy("/devices/"+agent.deviceId, false)
khenaidoo43c82122018-11-22 18:38:28 -0500106 agent.deviceProxy.RegisterCallback(model.POST_UPDATE, agent.processUpdate)
khenaidoo19d7b632018-10-30 10:49:50 -0400107
khenaidoob9203542018-09-17 22:56:37 -0400108 log.Debug("device-agent-started")
khenaidoo297cd252019-02-07 22:10:23 -0500109 return nil
khenaidoob9203542018-09-17 22:56:37 -0400110}
111
khenaidoo4d4802d2018-10-04 21:59:49 -0400112// stop stops the device agent. Not much to do for now
113func (agent *DeviceAgent) stop(ctx context.Context) {
khenaidoo92e62c52018-10-03 14:02:54 -0400114 agent.lockDevice.Lock()
115 defer agent.lockDevice.Unlock()
khenaidoob9203542018-09-17 22:56:37 -0400116 log.Debug("stopping-device-agent")
khenaidoo0a822f92019-05-08 15:15:57 -0400117 // Remove the device from the KV store
118 if removed := agent.clusterDataProxy.Remove("/devices/"+agent.deviceId, ""); removed == nil {
khenaidoo4554f7c2019-05-29 22:13:15 -0400119 log.Debugw("device-already-removed", log.Fields{"id": agent.deviceId})
khenaidoo0a822f92019-05-08 15:15:57 -0400120 }
khenaidoob9203542018-09-17 22:56:37 -0400121 agent.exitChannel <- 1
122 log.Debug("device-agent-stopped")
khenaidoo0a822f92019-05-08 15:15:57 -0400123
khenaidoob9203542018-09-17 22:56:37 -0400124}
125
khenaidoo19d7b632018-10-30 10:49:50 -0400126// GetDevice retrieves the latest device information from the data model
khenaidoo92e62c52018-10-03 14:02:54 -0400127func (agent *DeviceAgent) getDevice() (*voltha.Device, error) {
khenaidoo1ce37ad2019-03-24 22:07:24 -0400128 agent.lockDevice.RLock()
129 defer agent.lockDevice.RUnlock()
khenaidoo297cd252019-02-07 22:10:23 -0500130 if device := agent.clusterDataProxy.Get("/devices/"+agent.deviceId, 0, false, ""); device != nil {
khenaidoo92e62c52018-10-03 14:02:54 -0400131 if d, ok := device.(*voltha.Device); ok {
132 cloned := proto.Clone(d).(*voltha.Device)
133 return cloned, nil
134 }
135 }
136 return nil, status.Errorf(codes.NotFound, "device-%s", agent.deviceId)
137}
138
khenaidoo4d4802d2018-10-04 21:59:49 -0400139// 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 -0400140// This function is meant so that we do not have duplicate code all over the device agent functions
141func (agent *DeviceAgent) getDeviceWithoutLock() (*voltha.Device, error) {
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400142 if device := agent.clusterDataProxy.Get("/devices/"+agent.deviceId, 0, false, ""); device != nil {
khenaidoo92e62c52018-10-03 14:02:54 -0400143 if d, ok := device.(*voltha.Device); ok {
144 cloned := proto.Clone(d).(*voltha.Device)
145 return cloned, nil
146 }
147 }
148 return nil, status.Errorf(codes.NotFound, "device-%s", agent.deviceId)
149}
150
khenaidoo3ab34882019-05-02 21:33:30 -0400151// enableDevice activates a preprovisioned or a disable device
khenaidoob9203542018-09-17 22:56:37 -0400152func (agent *DeviceAgent) enableDevice(ctx context.Context) error {
khenaidoo92e62c52018-10-03 14:02:54 -0400153 agent.lockDevice.Lock()
154 defer agent.lockDevice.Unlock()
155 log.Debugw("enableDevice", log.Fields{"id": agent.deviceId})
khenaidoo21d51152019-02-01 13:48:37 -0500156
khenaidoo92e62c52018-10-03 14:02:54 -0400157 if device, err := agent.getDeviceWithoutLock(); err != nil {
khenaidoob9203542018-09-17 22:56:37 -0400158 return status.Errorf(codes.NotFound, "%s", agent.deviceId)
159 } else {
khenaidoo21d51152019-02-01 13:48:37 -0500160 // First figure out which adapter will handle this device type. We do it at this stage as allow devices to be
161 // pre-provisionned with the required adapter not registered. At this stage, since we need to communicate
162 // with the adapter then we need to know the adapter that will handle this request
163 if adapterName, err := agent.adapterMgr.getAdapterName(device.Type); err != nil {
164 log.Warnw("no-adapter-registered-for-device-type", log.Fields{"deviceType": device.Type, "deviceAdapter": device.Adapter})
165 return err
166 } else {
167 device.Adapter = adapterName
168 }
169
khenaidoo92e62c52018-10-03 14:02:54 -0400170 if device.AdminState == voltha.AdminState_ENABLED {
171 log.Debugw("device-already-enabled", log.Fields{"id": agent.deviceId})
khenaidoo92e62c52018-10-03 14:02:54 -0400172 return nil
173 }
khenaidoo3ab34882019-05-02 21:33:30 -0400174 // If this is a child device then verify the parent state before proceeding
175 if !agent.isRootdevice {
176 if parent := agent.deviceMgr.getParentDevice(device); parent != nil {
177 if parent.AdminState == voltha.AdminState_DISABLED ||
178 parent.AdminState == voltha.AdminState_DELETED ||
179 parent.AdminState == voltha.AdminState_UNKNOWN {
180 err = status.Error(codes.FailedPrecondition, fmt.Sprintf("incorrect-parent-state: %s %d", parent.Id, parent.AdminState))
181 log.Warnw("incorrect-parent-state", log.Fields{"id": agent.deviceId, "error": err})
182 return err
183 }
184 } else {
185 err = status.Error(codes.Unavailable, fmt.Sprintf("parent-not-existent: %s ", device.Id))
186 log.Warnw("parent-not-existent", log.Fields{"id": agent.deviceId, "error": err})
187 return err
188 }
189 }
khenaidoo92e62c52018-10-03 14:02:54 -0400190 if device.AdminState == voltha.AdminState_PREPROVISIONED {
191 // First send the request to an Adapter and wait for a response
192 if err := agent.adapterProxy.AdoptDevice(ctx, device); err != nil {
193 log.Debugw("adoptDevice-error", log.Fields{"id": agent.lastData.Id, "error": err})
khenaidoob9203542018-09-17 22:56:37 -0400194 return err
195 }
khenaidoo0a822f92019-05-08 15:15:57 -0400196 } else if device.AdminState == voltha.AdminState_DISABLED {
khenaidoo92e62c52018-10-03 14:02:54 -0400197 // First send the request to an Adapter and wait for a response
198 if err := agent.adapterProxy.ReEnableDevice(ctx, device); err != nil {
199 log.Debugw("renableDevice-error", log.Fields{"id": agent.lastData.Id, "error": err})
200 return err
201 }
khenaidoo0a822f92019-05-08 15:15:57 -0400202 } else {
203 err = status.Error(codes.FailedPrecondition, fmt.Sprintf("cannot-delete-a-deleted-device: %s ", device.Id))
204 log.Warnw("invalid-state", log.Fields{"id": agent.deviceId, "state": device.AdminState, "error": err})
205 return err
khenaidoo92e62c52018-10-03 14:02:54 -0400206 }
207 // Received an Ack (no error found above). Now update the device in the model to the expected state
208 cloned := proto.Clone(device).(*voltha.Device)
khenaidoo92e62c52018-10-03 14:02:54 -0400209 cloned.OperStatus = voltha.OperStatus_ACTIVATING
210 if afterUpdate := agent.clusterDataProxy.Update("/devices/"+agent.deviceId, cloned, false, ""); afterUpdate == nil {
211 return status.Errorf(codes.Internal, "failed-update-device:%s", agent.deviceId)
khenaidoob9203542018-09-17 22:56:37 -0400212 }
213 }
214 return nil
215}
216
khenaidoo2c6a0992019-04-29 13:46:56 -0400217func (agent *DeviceAgent) updateDeviceWithoutLockAsync(device *voltha.Device, ch chan interface{}) {
218 if err := agent.updateDeviceWithoutLock(device); err != nil {
219 ch <- status.Errorf(codes.Internal, "failure-updating-%s", agent.deviceId)
khenaidoo19d7b632018-10-30 10:49:50 -0400220 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400221 ch <- nil
khenaidoo19d7b632018-10-30 10:49:50 -0400222}
223
khenaidoo2c6a0992019-04-29 13:46:56 -0400224func (agent *DeviceAgent) sendBulkFlowsToAdapters(device *voltha.Device, flows *voltha.Flows, groups *voltha.FlowGroups, ch chan interface{}) {
225 if err := agent.adapterProxy.UpdateFlowsBulk(device, flows, groups); err != nil {
226 log.Debugw("update-flow-bulk-error", log.Fields{"id": agent.lastData.Id, "error": err})
227 ch <- err
228 }
229 ch <- nil
230}
231
232func (agent *DeviceAgent) sendIncrementalFlowsToAdapters(device *voltha.Device, flows *ofp.FlowChanges, groups *ofp.FlowGroupChanges, ch chan interface{}) {
233 if err := agent.adapterProxy.UpdateFlowsIncremental(device, flows, groups); err != nil {
234 log.Debugw("update-flow-incremental-error", log.Fields{"id": agent.lastData.Id, "error": err})
235 ch <- err
236 }
237 ch <- nil
238}
239
khenaidoo0458db62019-06-20 08:50:36 -0400240//addFlowsAndGroups adds the "newFlows" and "newGroups" from the existing flows/groups and sends the update to the
241//adapters
khenaidoo2c6a0992019-04-29 13:46:56 -0400242func (agent *DeviceAgent) addFlowsAndGroups(newFlows []*ofp.OfpFlowStats, newGroups []*ofp.OfpGroupEntry) error {
khenaidoo0458db62019-06-20 08:50:36 -0400243 log.Debugw("addFlowsAndGroups", log.Fields{"deviceId": agent.deviceId, "flows": newFlows, "groups": newGroups})
244
khenaidoo2c6a0992019-04-29 13:46:56 -0400245 if (len(newFlows) | len(newGroups)) == 0 {
246 log.Debugw("nothing-to-update", log.Fields{"deviceId": agent.deviceId, "flows": newFlows, "groups": newGroups})
247 return nil
248 }
249
khenaidoo19d7b632018-10-30 10:49:50 -0400250 agent.lockDevice.Lock()
251 defer agent.lockDevice.Unlock()
khenaidoo2c6a0992019-04-29 13:46:56 -0400252
khenaidoo0458db62019-06-20 08:50:36 -0400253 var device *voltha.Device
254 var err error
255 if device, err = agent.getDeviceWithoutLock(); err != nil {
256 return status.Errorf(codes.NotFound, "%s", agent.deviceId)
257 }
258
259 existingFlows := proto.Clone(device.Flows).(*voltha.Flows)
260 existingGroups := proto.Clone(device.FlowGroups).(*ofp.FlowGroups)
261
262 var updatedFlows []*ofp.OfpFlowStats
263 var flowsToDelete []*ofp.OfpFlowStats
264 var groupsToDelete []*ofp.OfpGroupEntry
265 var updatedGroups []*ofp.OfpGroupEntry
266
267 // Process flows
268 for _, flow := range newFlows {
269 updatedFlows = append(updatedFlows, flow)
270 }
271 for _, flow := range existingFlows.Items {
272 if idx := fu.FindFlows(newFlows, flow); idx == -1 {
273 updatedFlows = append(updatedFlows, flow)
274 } else {
275 flowsToDelete = append(flowsToDelete, flow)
276 }
277 }
278
279 // Process groups
280 for _, g := range newGroups {
281 updatedGroups = append(updatedGroups, g)
282 }
283 for _, group := range existingGroups.Items {
284 if fu.FindGroup(newGroups, group.Desc.GroupId) == -1 { // does not exist now
285 updatedGroups = append(updatedGroups, group)
286 } else {
287 groupsToDelete = append(groupsToDelete, group)
288 }
289 }
290
291 // Sanity check
292 if (len(updatedFlows) | len(flowsToDelete) | len(updatedGroups) | len(groupsToDelete)) == 0 {
293 log.Debugw("nothing-to-update", log.Fields{"deviceId": agent.deviceId, "flows": newFlows, "groups": newGroups})
294 return nil
295 }
296
297 // Send update to adapters
298 // Create two channels to receive responses from the dB and from the adapters.
299 // Do not close these channels as this function may exit on timeout before the dB or adapters get a chance
300 // to send their responses. These channels will be garbage collected once all the responses are
301 // received
302 chAdapters := make(chan interface{})
303 chdB := make(chan interface{})
304 dType := agent.adapterMgr.getDeviceType(device.Type)
305 if !dType.AcceptsAddRemoveFlowUpdates {
306
307 if len(updatedGroups) != 0 && reflect.DeepEqual(existingGroups.Items, updatedGroups) && len(updatedFlows) != 0 && reflect.DeepEqual(existingFlows.Items, updatedFlows) {
308 log.Debugw("nothing-to-update", log.Fields{"deviceId": agent.deviceId, "flows": newFlows, "groups": newGroups})
309 return nil
310 }
311 go agent.sendBulkFlowsToAdapters(device, &voltha.Flows{Items: updatedFlows}, &voltha.FlowGroups{Items: updatedGroups}, chAdapters)
312
313 } else {
314 flowChanges := &ofp.FlowChanges{
315 ToAdd: &voltha.Flows{Items: newFlows},
316 ToRemove: &voltha.Flows{Items: flowsToDelete},
317 }
318 groupChanges := &ofp.FlowGroupChanges{
319 ToAdd: &voltha.FlowGroups{Items: newGroups},
320 ToRemove: &voltha.FlowGroups{Items: groupsToDelete},
321 ToUpdate: &voltha.FlowGroups{Items: []*ofp.OfpGroupEntry{}},
322 }
323 go agent.sendIncrementalFlowsToAdapters(device, flowChanges, groupChanges, chAdapters)
324 }
325
326 // store the changed data
327 device.Flows = &voltha.Flows{Items: updatedFlows}
328 device.FlowGroups = &voltha.FlowGroups{Items: updatedGroups}
329 go agent.updateDeviceWithoutLockAsync(device, chdB)
330
331 if res := fu.WaitForNilOrErrorResponses(agent.defaultTimeout, chAdapters, chdB); res != nil {
332 return status.Errorf(codes.Aborted, "errors-%s", res)
333 }
334
335 return nil
336}
337
338//deleteFlowsAndGroups removes the "flowsToDel" and "groupsToDel" from the existing flows/groups and sends the update to the
339//adapters
340func (agent *DeviceAgent) deleteFlowsAndGroups(flowsToDel []*ofp.OfpFlowStats, groupsToDel []*ofp.OfpGroupEntry) error {
341 log.Debugw("deleteFlowsAndGroups", log.Fields{"deviceId": agent.deviceId, "flows": flowsToDel, "groups": groupsToDel})
342
343 if (len(flowsToDel) | len(groupsToDel)) == 0 {
344 log.Debugw("nothing-to-update", log.Fields{"deviceId": agent.deviceId, "flows": flowsToDel, "groups": groupsToDel})
345 return nil
346 }
347
348 agent.lockDevice.Lock()
349 defer agent.lockDevice.Unlock()
350
351 var device *voltha.Device
352 var err error
353
354 if device, err = agent.getDeviceWithoutLock(); err != nil {
355 return status.Errorf(codes.NotFound, "%s", agent.deviceId)
356 }
357
358 existingFlows := proto.Clone(device.Flows).(*voltha.Flows)
359 existingGroups := proto.Clone(device.FlowGroups).(*ofp.FlowGroups)
360
361 var flowsToKeep []*ofp.OfpFlowStats
362 var groupsToKeep []*ofp.OfpGroupEntry
363
364 // Process flows
365 for _, flow := range existingFlows.Items {
366 if idx := fu.FindFlows(flowsToDel, flow); idx == -1 {
367 flowsToKeep = append(flowsToKeep, flow)
368 }
369 }
370
371 // Process groups
372 for _, group := range existingGroups.Items {
373 if fu.FindGroup(groupsToDel, group.Desc.GroupId) == -1 { // does not exist now
374 groupsToKeep = append(groupsToKeep, group)
375 }
376 }
377
378 log.Debugw("deleteFlowsAndGroups",
379 log.Fields{
380 "deviceId": agent.deviceId,
381 "flowsToDel": len(flowsToDel),
382 "flowsToKeep": len(flowsToKeep),
383 "groupsToDel": len(groupsToDel),
384 "groupsToKeep": len(groupsToKeep),
385 })
386
387 // Sanity check
388 if (len(flowsToKeep) | len(flowsToDel) | len(groupsToKeep) | len(groupsToDel)) == 0 {
389 log.Debugw("nothing-to-update", log.Fields{"deviceId": agent.deviceId, "flowsToDel": flowsToDel, "groupsToDel": groupsToDel})
390 return nil
391 }
392
393 // Send update to adapters
394 chAdapters := make(chan interface{})
395 chdB := make(chan interface{})
396 dType := agent.adapterMgr.getDeviceType(device.Type)
397 if !dType.AcceptsAddRemoveFlowUpdates {
398 if len(groupsToKeep) != 0 && reflect.DeepEqual(existingGroups.Items, groupsToKeep) && len(flowsToKeep) != 0 && reflect.DeepEqual(existingFlows.Items, flowsToKeep) {
399 log.Debugw("nothing-to-update", log.Fields{"deviceId": agent.deviceId, "flowsToDel": flowsToDel, "groupsToDel": groupsToDel})
400 return nil
401 }
402 go agent.sendBulkFlowsToAdapters(device, &voltha.Flows{Items: flowsToKeep}, &voltha.FlowGroups{Items: groupsToKeep}, chAdapters)
403 } else {
404 flowChanges := &ofp.FlowChanges{
405 ToAdd: &voltha.Flows{Items: []*ofp.OfpFlowStats{}},
406 ToRemove: &voltha.Flows{Items: flowsToDel},
407 }
408 groupChanges := &ofp.FlowGroupChanges{
409 ToAdd: &voltha.FlowGroups{Items: []*ofp.OfpGroupEntry{}},
410 ToRemove: &voltha.FlowGroups{Items: groupsToDel},
411 ToUpdate: &voltha.FlowGroups{Items: []*ofp.OfpGroupEntry{}},
412 }
413 go agent.sendIncrementalFlowsToAdapters(device, flowChanges, groupChanges, chAdapters)
414 }
415
416 // store the changed data
417 device.Flows = &voltha.Flows{Items: flowsToKeep}
418 device.FlowGroups = &voltha.FlowGroups{Items: groupsToKeep}
419 go agent.updateDeviceWithoutLockAsync(device, chdB)
420
421 if res := fu.WaitForNilOrErrorResponses(agent.defaultTimeout, chAdapters, chdB); res != nil {
422 return status.Errorf(codes.Aborted, "errors-%s", res)
423 }
424 return nil
425
426}
427
428//updateFlowsAndGroups replaces the existing flows and groups with "updatedFlows" and "updatedGroups" respectively. It
429//also sends the updates to the adapters
430func (agent *DeviceAgent) updateFlowsAndGroups(updatedFlows []*ofp.OfpFlowStats, updatedGroups []*ofp.OfpGroupEntry) error {
431 log.Debugw("updateFlowsAndGroups", log.Fields{"deviceId": agent.deviceId, "flows": updatedFlows, "groups": updatedGroups})
432
433 if (len(updatedFlows) | len(updatedGroups)) == 0 {
434 log.Debugw("nothing-to-update", log.Fields{"deviceId": agent.deviceId, "flows": updatedFlows, "groups": updatedGroups})
435 return nil
436 }
437
438 agent.lockDevice.Lock()
439 defer agent.lockDevice.Unlock()
440 var device *voltha.Device
441 var err error
442 if device, err = agent.getDeviceWithoutLock(); err != nil {
443 return status.Errorf(codes.NotFound, "%s", agent.deviceId)
444 }
445 existingFlows := proto.Clone(device.Flows).(*voltha.Flows)
446 existingGroups := proto.Clone(device.FlowGroups).(*ofp.FlowGroups)
447
448 if len(updatedGroups) != 0 && reflect.DeepEqual(existingGroups.Items, updatedGroups) && len(updatedFlows) != 0 && reflect.DeepEqual(existingFlows.Items, updatedFlows) {
449 log.Debugw("nothing-to-update", log.Fields{"deviceId": agent.deviceId, "flows": updatedFlows, "groups": updatedGroups})
450 return nil
451 }
452
453 log.Debugw("updating-flows-and-groups",
454 log.Fields{
455 "deviceId": agent.deviceId,
456 "updatedFlows": updatedFlows,
457 "updatedGroups": updatedGroups,
458 })
459
460 chAdapters := make(chan interface{})
461 chdB := make(chan interface{})
462 dType := agent.adapterMgr.getDeviceType(device.Type)
463
464 // Process bulk flow update differently than incremental update
465 if !dType.AcceptsAddRemoveFlowUpdates {
466 go agent.sendBulkFlowsToAdapters(device, &voltha.Flows{Items: updatedFlows}, &voltha.FlowGroups{Items: updatedGroups}, chAdapters)
467 } else {
468 var flowsToAdd []*ofp.OfpFlowStats
khenaidoo2c6a0992019-04-29 13:46:56 -0400469 var flowsToDelete []*ofp.OfpFlowStats
khenaidoo0458db62019-06-20 08:50:36 -0400470 var groupsToAdd []*ofp.OfpGroupEntry
khenaidoo2c6a0992019-04-29 13:46:56 -0400471 var groupsToDelete []*ofp.OfpGroupEntry
khenaidoo2c6a0992019-04-29 13:46:56 -0400472
473 // Process flows
khenaidoo0458db62019-06-20 08:50:36 -0400474 for _, flow := range updatedFlows {
475 if idx := fu.FindFlows(existingFlows.Items, flow); idx == -1 {
476 flowsToAdd = append(flowsToAdd, flow)
477 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400478 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400479 for _, flow := range existingFlows.Items {
khenaidoo0458db62019-06-20 08:50:36 -0400480 if idx := fu.FindFlows(updatedFlows, flow); idx != -1 {
khenaidoo2c6a0992019-04-29 13:46:56 -0400481 flowsToDelete = append(flowsToDelete, flow)
482 }
483 }
484
485 // Process groups
khenaidoo0458db62019-06-20 08:50:36 -0400486 for _, g := range updatedGroups {
487 if fu.FindGroup(existingGroups.Items, g.Desc.GroupId) == -1 { // does not exist now
488 groupsToAdd = append(groupsToAdd, g)
489 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400490 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400491 for _, group := range existingGroups.Items {
khenaidoo0458db62019-06-20 08:50:36 -0400492 if fu.FindGroup(updatedGroups, group.Desc.GroupId) != -1 { // does not exist now
khenaidoo2c6a0992019-04-29 13:46:56 -0400493 groupsToDelete = append(groupsToDelete, group)
494 }
495 }
496
khenaidoo0458db62019-06-20 08:50:36 -0400497 log.Debugw("updating-flows-and-groups",
498 log.Fields{
499 "deviceId": agent.deviceId,
500 "flowsToAdd": flowsToAdd,
501 "flowsToDelete": flowsToDelete,
502 "groupsToAdd": groupsToAdd,
503 "groupsToDelete": groupsToDelete,
504 })
505
khenaidoo2c6a0992019-04-29 13:46:56 -0400506 // Sanity check
khenaidoo0458db62019-06-20 08:50:36 -0400507 if (len(flowsToAdd) | len(flowsToDelete) | len(groupsToAdd) | len(groupsToDelete) | len(updatedGroups)) == 0 {
508 log.Debugw("nothing-to-update", log.Fields{"deviceId": agent.deviceId, "flows": updatedFlows, "groups": updatedGroups})
khenaidoo2c6a0992019-04-29 13:46:56 -0400509 return nil
khenaidoo2c6a0992019-04-29 13:46:56 -0400510 }
511
khenaidoo0458db62019-06-20 08:50:36 -0400512 flowChanges := &ofp.FlowChanges{
513 ToAdd: &voltha.Flows{Items: flowsToAdd},
514 ToRemove: &voltha.Flows{Items: flowsToDelete},
khenaidoo19d7b632018-10-30 10:49:50 -0400515 }
khenaidoo0458db62019-06-20 08:50:36 -0400516 groupChanges := &ofp.FlowGroupChanges{
517 ToAdd: &voltha.FlowGroups{Items: groupsToAdd},
518 ToRemove: &voltha.FlowGroups{Items: groupsToDelete},
519 ToUpdate: &voltha.FlowGroups{Items: updatedGroups},
520 }
521 go agent.sendIncrementalFlowsToAdapters(device, flowChanges, groupChanges, chAdapters)
khenaidoo19d7b632018-10-30 10:49:50 -0400522 }
khenaidoo0458db62019-06-20 08:50:36 -0400523
524 // store the updated data
525 device.Flows = &voltha.Flows{Items: updatedFlows}
526 device.FlowGroups = &voltha.FlowGroups{Items: updatedGroups}
527 go agent.updateDeviceWithoutLockAsync(device, chdB)
528
529 if res := fu.WaitForNilOrErrorResponses(agent.defaultTimeout, chAdapters, chdB); res != nil {
530 return status.Errorf(codes.Aborted, "errors-%s", res)
531 }
532 return nil
khenaidoo19d7b632018-10-30 10:49:50 -0400533}
534
khenaidoo4d4802d2018-10-04 21:59:49 -0400535//disableDevice disable a device
khenaidoo92e62c52018-10-03 14:02:54 -0400536func (agent *DeviceAgent) disableDevice(ctx context.Context) error {
khenaidoo0a822f92019-05-08 15:15:57 -0400537 agent.lockDevice.RLock()
khenaidoo92e62c52018-10-03 14:02:54 -0400538 log.Debugw("disableDevice", log.Fields{"id": agent.deviceId})
539 // Get the most up to date the device info
540 if device, err := agent.getDeviceWithoutLock(); err != nil {
khenaidoo0a822f92019-05-08 15:15:57 -0400541 agent.lockDevice.RUnlock()
khenaidoo92e62c52018-10-03 14:02:54 -0400542 return status.Errorf(codes.NotFound, "%s", agent.deviceId)
543 } else {
khenaidoo0a822f92019-05-08 15:15:57 -0400544 agent.lockDevice.RUnlock()
khenaidoo92e62c52018-10-03 14:02:54 -0400545 if device.AdminState == voltha.AdminState_DISABLED {
546 log.Debugw("device-already-disabled", log.Fields{"id": agent.deviceId})
khenaidoo92e62c52018-10-03 14:02:54 -0400547 return nil
548 }
khenaidoo4554f7c2019-05-29 22:13:15 -0400549 if device.AdminState == voltha.AdminState_PREPROVISIONED ||
550 device.AdminState == voltha.AdminState_DELETED {
551 log.Debugw("device-not-enabled", log.Fields{"id": agent.deviceId})
552 return status.Errorf(codes.FailedPrecondition, "deviceId:%s, invalid-admin-state:%s", agent.deviceId, device.AdminState)
553 }
554
khenaidoo92e62c52018-10-03 14:02:54 -0400555 // First send the request to an Adapter and wait for a response
556 if err := agent.adapterProxy.DisableDevice(ctx, device); err != nil {
557 log.Debugw("disableDevice-error", log.Fields{"id": agent.lastData.Id, "error": err})
khenaidoo92e62c52018-10-03 14:02:54 -0400558 return err
559 }
khenaidoo0a822f92019-05-08 15:15:57 -0400560 if err = agent.updateAdminState(voltha.AdminState_DISABLED); err != nil {
561 log.Errorw("failed-update-device", log.Fields{"deviceId": device.Id, "currentState": device.AdminState, "expectedState": voltha.AdminState_DISABLED})
562 }
563 }
564 return nil
565}
566
567func (agent *DeviceAgent) updateAdminState(adminState voltha.AdminState_AdminState) error {
568 agent.lockDevice.Lock()
569 defer agent.lockDevice.Unlock()
570 log.Debugw("updateAdminState", log.Fields{"id": agent.deviceId})
571 // Get the most up to date the device info
572 if device, err := agent.getDeviceWithoutLock(); err != nil {
573 return status.Errorf(codes.NotFound, "%s", agent.deviceId)
574 } else {
575 if device.AdminState == adminState {
576 log.Debugw("no-change-needed", log.Fields{"id": agent.deviceId, "state": adminState})
577 return nil
578 }
khenaidoo92e62c52018-10-03 14:02:54 -0400579 // Received an Ack (no error found above). Now update the device in the model to the expected state
580 cloned := proto.Clone(device).(*voltha.Device)
khenaidoo0a822f92019-05-08 15:15:57 -0400581 cloned.AdminState = adminState
khenaidoo92e62c52018-10-03 14:02:54 -0400582 if afterUpdate := agent.clusterDataProxy.Update("/devices/"+agent.deviceId, cloned, false, ""); afterUpdate == nil {
khenaidoo92e62c52018-10-03 14:02:54 -0400583 return status.Errorf(codes.Internal, "failed-update-device:%s", agent.deviceId)
584 }
khenaidoo92e62c52018-10-03 14:02:54 -0400585 }
586 return nil
587}
588
khenaidoo4d4802d2018-10-04 21:59:49 -0400589func (agent *DeviceAgent) rebootDevice(ctx context.Context) error {
590 agent.lockDevice.Lock()
591 defer agent.lockDevice.Unlock()
592 log.Debugw("rebootDevice", log.Fields{"id": agent.deviceId})
593 // Get the most up to date the device info
594 if device, err := agent.getDeviceWithoutLock(); err != nil {
595 return status.Errorf(codes.NotFound, "%s", agent.deviceId)
596 } else {
597 if device.AdminState != voltha.AdminState_DISABLED {
598 log.Debugw("device-not-disabled", log.Fields{"id": agent.deviceId})
599 //TODO: Needs customized error message
600 return status.Errorf(codes.FailedPrecondition, "deviceId:%s, expected-admin-state:%s", agent.deviceId, voltha.AdminState_DISABLED)
601 }
602 // First send the request to an Adapter and wait for a response
603 if err := agent.adapterProxy.RebootDevice(ctx, device); err != nil {
604 log.Debugw("rebootDevice-error", log.Fields{"id": agent.lastData.Id, "error": err})
605 return err
606 }
607 }
608 return nil
609}
610
611func (agent *DeviceAgent) deleteDevice(ctx context.Context) error {
612 agent.lockDevice.Lock()
khenaidoo0a822f92019-05-08 15:15:57 -0400613 defer agent.lockDevice.Unlock()
khenaidoo4d4802d2018-10-04 21:59:49 -0400614 log.Debugw("deleteDevice", log.Fields{"id": agent.deviceId})
615 // Get the most up to date the device info
616 if device, err := agent.getDeviceWithoutLock(); err != nil {
khenaidoo4d4802d2018-10-04 21:59:49 -0400617 return status.Errorf(codes.NotFound, "%s", agent.deviceId)
618 } else {
khenaidoo0a822f92019-05-08 15:15:57 -0400619 if device.AdminState == voltha.AdminState_DELETED {
620 log.Debugw("device-already-in-deleted-state", log.Fields{"id": agent.deviceId})
621 return nil
622 }
khenaidoo43c82122018-11-22 18:38:28 -0500623 if (device.AdminState != voltha.AdminState_DISABLED) &&
624 (device.AdminState != voltha.AdminState_PREPROVISIONED) {
khenaidoo4d4802d2018-10-04 21:59:49 -0400625 log.Debugw("device-not-disabled", log.Fields{"id": agent.deviceId})
626 //TODO: Needs customized error message
khenaidoo4d4802d2018-10-04 21:59:49 -0400627 return status.Errorf(codes.FailedPrecondition, "deviceId:%s, expected-admin-state:%s", agent.deviceId, voltha.AdminState_DISABLED)
628 }
khenaidoo4554f7c2019-05-29 22:13:15 -0400629 if device.AdminState != voltha.AdminState_PREPROVISIONED {
630 // Send the request to an Adapter only if the device is not in poreporovision state and wait for a response
631 if err := agent.adapterProxy.DeleteDevice(ctx, device); err != nil {
632 log.Debugw("deleteDevice-error", log.Fields{"id": agent.lastData.Id, "error": err})
633 return err
634 }
khenaidoo4d4802d2018-10-04 21:59:49 -0400635 }
khenaidoo0a822f92019-05-08 15:15:57 -0400636 // Set the state to deleted - this will trigger some background process to clean up the device as well
637 // as its association with the logical device
638 cloned := proto.Clone(device).(*voltha.Device)
639 cloned.AdminState = voltha.AdminState_DELETED
640 if afterUpdate := agent.clusterDataProxy.Update("/devices/"+agent.deviceId, cloned, false, ""); afterUpdate == nil {
khenaidoo4d4802d2018-10-04 21:59:49 -0400641 return status.Errorf(codes.Internal, "failed-update-device:%s", agent.deviceId)
642 }
khenaidoo0a822f92019-05-08 15:15:57 -0400643
644 // If this is a child device then remove the associated peer ports on the parent device
645 if !device.Root {
646 go agent.deviceMgr.deletePeerPorts(device.ParentId, device.Id)
647 }
648
khenaidoo4d4802d2018-10-04 21:59:49 -0400649 }
650 return nil
651}
652
khenaidoof5a5bfa2019-01-23 22:20:29 -0500653func (agent *DeviceAgent) downloadImage(ctx context.Context, img *voltha.ImageDownload) (*voltha.OperationResp, error) {
654 agent.lockDevice.Lock()
655 defer agent.lockDevice.Unlock()
656 log.Debugw("downloadImage", log.Fields{"id": agent.deviceId})
657 // Get the most up to date the device info
658 if device, err := agent.getDeviceWithoutLock(); err != nil {
659 return nil, status.Errorf(codes.NotFound, "%s", agent.deviceId)
660 } else {
661 if device.AdminState != voltha.AdminState_ENABLED {
662 log.Debugw("device-not-enabled", log.Fields{"id": agent.deviceId})
663 return nil, status.Errorf(codes.FailedPrecondition, "deviceId:%s, expected-admin-state:%s", agent.deviceId, voltha.AdminState_ENABLED)
664 }
665 // Save the image
666 clonedImg := proto.Clone(img).(*voltha.ImageDownload)
Stephane Barbariedf5479f2019-01-29 22:13:00 -0500667 clonedImg.DownloadState = voltha.ImageDownload_DOWNLOAD_REQUESTED
khenaidoof5a5bfa2019-01-23 22:20:29 -0500668 cloned := proto.Clone(device).(*voltha.Device)
669 if cloned.ImageDownloads == nil {
670 cloned.ImageDownloads = []*voltha.ImageDownload{clonedImg}
671 } else {
672 cloned.ImageDownloads = append(cloned.ImageDownloads, clonedImg)
673 }
674 cloned.AdminState = voltha.AdminState_DOWNLOADING_IMAGE
675 if afterUpdate := agent.clusterDataProxy.Update("/devices/"+agent.deviceId, cloned, false, ""); afterUpdate == nil {
676 return nil, status.Errorf(codes.Internal, "failed-update-device:%s", agent.deviceId)
677 }
678 // Send the request to the adapter
679 if err := agent.adapterProxy.DownloadImage(ctx, cloned, clonedImg); err != nil {
680 log.Debugw("downloadImage-error", log.Fields{"id": agent.lastData.Id, "error": err, "image": img.Name})
681 return nil, err
682 }
683 }
684 return &voltha.OperationResp{Code: voltha.OperationResp_OPERATION_SUCCESS}, nil
685}
686
687// isImageRegistered is a helper method to figure out if an image is already registered
688func isImageRegistered(img *voltha.ImageDownload, device *voltha.Device) bool {
689 for _, image := range device.ImageDownloads {
690 if image.Id == img.Id && image.Name == img.Name {
691 return true
692 }
693 }
694 return false
695}
696
697func (agent *DeviceAgent) cancelImageDownload(ctx context.Context, img *voltha.ImageDownload) (*voltha.OperationResp, error) {
698 agent.lockDevice.Lock()
699 defer agent.lockDevice.Unlock()
700 log.Debugw("cancelImageDownload", log.Fields{"id": agent.deviceId})
701 // Get the most up to date the device info
702 if device, err := agent.getDeviceWithoutLock(); err != nil {
703 return nil, status.Errorf(codes.NotFound, "%s", agent.deviceId)
704 } else {
705 // Verify whether the Image is in the list of image being downloaded
706 if !isImageRegistered(img, device) {
707 return nil, status.Errorf(codes.FailedPrecondition, "deviceId:%s, image-not-registered:%s", agent.deviceId, img.Name)
708 }
709
710 // Update image download state
711 cloned := proto.Clone(device).(*voltha.Device)
712 for _, image := range cloned.ImageDownloads {
713 if image.Id == img.Id && image.Name == img.Name {
Stephane Barbariedf5479f2019-01-29 22:13:00 -0500714 image.DownloadState = voltha.ImageDownload_DOWNLOAD_CANCELLED
khenaidoof5a5bfa2019-01-23 22:20:29 -0500715 }
716 }
717
718 //If device is in downloading state, send the request to cancel the download
719 if device.AdminState == voltha.AdminState_DOWNLOADING_IMAGE {
720 if err := agent.adapterProxy.CancelImageDownload(ctx, device, img); err != nil {
721 log.Debugw("cancelImageDownload-error", log.Fields{"id": agent.lastData.Id, "error": err, "image": img.Name})
722 return nil, err
723 }
724 // Set the device to Enabled
725 cloned.AdminState = voltha.AdminState_ENABLED
726 if afterUpdate := agent.clusterDataProxy.Update("/devices/"+agent.deviceId, cloned, false, ""); afterUpdate == nil {
727 return nil, status.Errorf(codes.Internal, "failed-update-device:%s", agent.deviceId)
728 }
729 }
730 }
731 return &voltha.OperationResp{Code: voltha.OperationResp_OPERATION_SUCCESS}, nil
serkant.uluderya334479d2019-04-10 08:26:15 -0700732}
khenaidoof5a5bfa2019-01-23 22:20:29 -0500733
734func (agent *DeviceAgent) activateImage(ctx context.Context, img *voltha.ImageDownload) (*voltha.OperationResp, error) {
735 agent.lockDevice.Lock()
736 defer agent.lockDevice.Unlock()
737 log.Debugw("activateImage", log.Fields{"id": agent.deviceId})
738 // Get the most up to date the device info
739 if device, err := agent.getDeviceWithoutLock(); err != nil {
740 return nil, status.Errorf(codes.NotFound, "%s", agent.deviceId)
741 } else {
742 // Verify whether the Image is in the list of image being downloaded
743 if !isImageRegistered(img, device) {
744 return nil, status.Errorf(codes.FailedPrecondition, "deviceId:%s, image-not-registered:%s", agent.deviceId, img.Name)
745 }
746
747 if device.AdminState == voltha.AdminState_DOWNLOADING_IMAGE {
748 return nil, status.Errorf(codes.FailedPrecondition, "deviceId:%s, device-in-downloading-state:%s", agent.deviceId, img.Name)
749 }
750 // Update image download state
751 cloned := proto.Clone(device).(*voltha.Device)
752 for _, image := range cloned.ImageDownloads {
753 if image.Id == img.Id && image.Name == img.Name {
754 image.ImageState = voltha.ImageDownload_IMAGE_ACTIVATING
755 }
756 }
757 // Set the device to downloading_image
758 cloned.AdminState = voltha.AdminState_DOWNLOADING_IMAGE
759 if afterUpdate := agent.clusterDataProxy.Update("/devices/"+agent.deviceId, cloned, false, ""); afterUpdate == nil {
760 return nil, status.Errorf(codes.Internal, "failed-update-device:%s", agent.deviceId)
761 }
762
763 if err := agent.adapterProxy.ActivateImageUpdate(ctx, device, img); err != nil {
764 log.Debugw("activateImage-error", log.Fields{"id": agent.lastData.Id, "error": err, "image": img.Name})
765 return nil, err
766 }
767 // The status of the AdminState will be changed following the update_download_status response from the adapter
768 // The image name will also be removed from the device list
769 }
serkant.uluderya334479d2019-04-10 08:26:15 -0700770 return &voltha.OperationResp{Code: voltha.OperationResp_OPERATION_SUCCESS}, nil
771}
khenaidoof5a5bfa2019-01-23 22:20:29 -0500772
773func (agent *DeviceAgent) revertImage(ctx context.Context, img *voltha.ImageDownload) (*voltha.OperationResp, error) {
774 agent.lockDevice.Lock()
775 defer agent.lockDevice.Unlock()
776 log.Debugw("revertImage", log.Fields{"id": agent.deviceId})
777 // Get the most up to date the device info
778 if device, err := agent.getDeviceWithoutLock(); err != nil {
779 return nil, status.Errorf(codes.NotFound, "%s", agent.deviceId)
780 } else {
781 // Verify whether the Image is in the list of image being downloaded
782 if !isImageRegistered(img, device) {
783 return nil, status.Errorf(codes.FailedPrecondition, "deviceId:%s, image-not-registered:%s", agent.deviceId, img.Name)
784 }
785
786 if device.AdminState != voltha.AdminState_ENABLED {
787 return nil, status.Errorf(codes.FailedPrecondition, "deviceId:%s, device-not-enabled-state:%s", agent.deviceId, img.Name)
788 }
789 // Update image download state
790 cloned := proto.Clone(device).(*voltha.Device)
791 for _, image := range cloned.ImageDownloads {
792 if image.Id == img.Id && image.Name == img.Name {
793 image.ImageState = voltha.ImageDownload_IMAGE_REVERTING
794 }
795 }
796 if afterUpdate := agent.clusterDataProxy.Update("/devices/"+agent.deviceId, cloned, false, ""); afterUpdate == nil {
797 return nil, status.Errorf(codes.Internal, "failed-update-device:%s", agent.deviceId)
798 }
799
800 if err := agent.adapterProxy.RevertImageUpdate(ctx, device, img); err != nil {
801 log.Debugw("revertImage-error", log.Fields{"id": agent.lastData.Id, "error": err, "image": img.Name})
802 return nil, err
803 }
804 }
805 return &voltha.OperationResp{Code: voltha.OperationResp_OPERATION_SUCCESS}, nil
serkant.uluderya334479d2019-04-10 08:26:15 -0700806}
khenaidoof5a5bfa2019-01-23 22:20:29 -0500807
808func (agent *DeviceAgent) getImageDownloadStatus(ctx context.Context, img *voltha.ImageDownload) (*voltha.ImageDownload, error) {
809 agent.lockDevice.Lock()
810 defer agent.lockDevice.Unlock()
811 log.Debugw("getImageDownloadStatus", log.Fields{"id": agent.deviceId})
812 // Get the most up to date the device info
813 if device, err := agent.getDeviceWithoutLock(); err != nil {
814 return nil, status.Errorf(codes.NotFound, "%s", agent.deviceId)
815 } else {
816 if resp, err := agent.adapterProxy.GetImageDownloadStatus(ctx, device, img); err != nil {
817 log.Debugw("getImageDownloadStatus-error", log.Fields{"id": agent.lastData.Id, "error": err, "image": img.Name})
818 return nil, err
819 } else {
820 return resp, nil
821 }
822 }
823}
824
serkant.uluderya334479d2019-04-10 08:26:15 -0700825func (agent *DeviceAgent) updateImageDownload(img *voltha.ImageDownload) error {
khenaidoof5a5bfa2019-01-23 22:20:29 -0500826 agent.lockDevice.Lock()
827 defer agent.lockDevice.Unlock()
828 log.Debugw("updateImageDownload", log.Fields{"id": agent.deviceId})
829 // Get the most up to date the device info
830 if device, err := agent.getDeviceWithoutLock(); err != nil {
831 return status.Errorf(codes.NotFound, "%s", agent.deviceId)
832 } else {
833 // Update the image as well as remove it if the download was cancelled
834 cloned := proto.Clone(device).(*voltha.Device)
835 clonedImages := make([]*voltha.ImageDownload, len(cloned.ImageDownloads))
836 for _, image := range cloned.ImageDownloads {
837 if image.Id == img.Id && image.Name == img.Name {
Stephane Barbariedf5479f2019-01-29 22:13:00 -0500838 if image.DownloadState != voltha.ImageDownload_DOWNLOAD_CANCELLED {
khenaidoof5a5bfa2019-01-23 22:20:29 -0500839 clonedImages = append(clonedImages, img)
840 }
841 }
842 }
843 cloned.ImageDownloads = clonedImages
844 // Set the Admin state to enabled if required
Stephane Barbariedf5479f2019-01-29 22:13:00 -0500845 if (img.DownloadState != voltha.ImageDownload_DOWNLOAD_REQUESTED &&
846 img.DownloadState != voltha.ImageDownload_DOWNLOAD_STARTED) ||
serkant.uluderya334479d2019-04-10 08:26:15 -0700847 (img.ImageState != voltha.ImageDownload_IMAGE_ACTIVATING) {
khenaidoof5a5bfa2019-01-23 22:20:29 -0500848 cloned.AdminState = voltha.AdminState_ENABLED
849 }
850
851 if afterUpdate := agent.clusterDataProxy.Update("/devices/"+agent.deviceId, cloned, false, ""); afterUpdate == nil {
852 return status.Errorf(codes.Internal, "failed-update-device:%s", agent.deviceId)
853 }
854 }
855 return nil
856}
857
858func (agent *DeviceAgent) getImageDownload(ctx context.Context, img *voltha.ImageDownload) (*voltha.ImageDownload, error) {
khenaidoo1ce37ad2019-03-24 22:07:24 -0400859 agent.lockDevice.RLock()
860 defer agent.lockDevice.RUnlock()
khenaidoof5a5bfa2019-01-23 22:20:29 -0500861 log.Debugw("getImageDownload", log.Fields{"id": agent.deviceId})
862 // Get the most up to date the device info
863 if device, err := agent.getDeviceWithoutLock(); err != nil {
864 return nil, status.Errorf(codes.NotFound, "%s", agent.deviceId)
865 } else {
866 for _, image := range device.ImageDownloads {
867 if image.Id == img.Id && image.Name == img.Name {
868 return image, nil
869 }
870 }
871 return nil, status.Errorf(codes.NotFound, "image-not-found:%s", img.Name)
872 }
873}
874
875func (agent *DeviceAgent) listImageDownloads(ctx context.Context, deviceId string) (*voltha.ImageDownloads, error) {
khenaidoo1ce37ad2019-03-24 22:07:24 -0400876 agent.lockDevice.RLock()
877 defer agent.lockDevice.RUnlock()
khenaidoof5a5bfa2019-01-23 22:20:29 -0500878 log.Debugw("listImageDownloads", log.Fields{"id": agent.deviceId})
879 // Get the most up to date the device info
880 if device, err := agent.getDeviceWithoutLock(); err != nil {
881 return nil, status.Errorf(codes.NotFound, "%s", agent.deviceId)
882 } else {
serkant.uluderya334479d2019-04-10 08:26:15 -0700883 return &voltha.ImageDownloads{Items: device.ImageDownloads}, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -0500884 }
885}
886
khenaidoo4d4802d2018-10-04 21:59:49 -0400887// getPorts retrieves the ports information of the device based on the port type.
khenaidoo92e62c52018-10-03 14:02:54 -0400888func (agent *DeviceAgent) getPorts(ctx context.Context, portType voltha.Port_PortType) *voltha.Ports {
889 log.Debugw("getPorts", log.Fields{"id": agent.deviceId, "portType": portType})
khenaidoob9203542018-09-17 22:56:37 -0400890 ports := &voltha.Ports{}
khenaidoo19d7b632018-10-30 10:49:50 -0400891 if device, _ := agent.deviceMgr.GetDevice(agent.deviceId); device != nil {
khenaidoob9203542018-09-17 22:56:37 -0400892 for _, port := range device.Ports {
khenaidoo92e62c52018-10-03 14:02:54 -0400893 if port.Type == portType {
khenaidoob9203542018-09-17 22:56:37 -0400894 ports.Items = append(ports.Items, port)
895 }
896 }
897 }
898 return ports
899}
900
khenaidoo4d4802d2018-10-04 21:59:49 -0400901// getSwitchCapability is a helper method that a logical device agent uses to retrieve the switch capability of a
902// parent device
khenaidoo79232702018-12-04 11:00:41 -0500903func (agent *DeviceAgent) getSwitchCapability(ctx context.Context) (*ic.SwitchCapability, error) {
khenaidoob9203542018-09-17 22:56:37 -0400904 log.Debugw("getSwitchCapability", log.Fields{"deviceId": agent.deviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400905 if device, err := agent.deviceMgr.GetDevice(agent.deviceId); device == nil {
khenaidoob9203542018-09-17 22:56:37 -0400906 return nil, err
907 } else {
khenaidoo79232702018-12-04 11:00:41 -0500908 var switchCap *ic.SwitchCapability
khenaidoob9203542018-09-17 22:56:37 -0400909 var err error
910 if switchCap, err = agent.adapterProxy.GetOfpDeviceInfo(ctx, device); err != nil {
911 log.Debugw("getSwitchCapability-error", log.Fields{"id": device.Id, "error": err})
912 return nil, err
913 }
914 return switchCap, nil
915 }
916}
917
khenaidoo4d4802d2018-10-04 21:59:49 -0400918// getPortCapability is a helper method that a logical device agent uses to retrieve the port capability of a
919// device
khenaidoo79232702018-12-04 11:00:41 -0500920func (agent *DeviceAgent) getPortCapability(ctx context.Context, portNo uint32) (*ic.PortCapability, error) {
khenaidoob9203542018-09-17 22:56:37 -0400921 log.Debugw("getPortCapability", log.Fields{"deviceId": agent.deviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400922 if device, err := agent.deviceMgr.GetDevice(agent.deviceId); device == nil {
khenaidoob9203542018-09-17 22:56:37 -0400923 return nil, err
924 } else {
khenaidoo79232702018-12-04 11:00:41 -0500925 var portCap *ic.PortCapability
khenaidoob9203542018-09-17 22:56:37 -0400926 var err error
927 if portCap, err = agent.adapterProxy.GetOfpPortInfo(ctx, device, portNo); err != nil {
928 log.Debugw("getPortCapability-error", log.Fields{"id": device.Id, "error": err})
929 return nil, err
930 }
931 return portCap, nil
932 }
933}
934
khenaidoofdbad6e2018-11-06 22:26:38 -0500935func (agent *DeviceAgent) packetOut(outPort uint32, packet *ofp.OfpPacketOut) error {
936 // Send packet to adapter
937 if err := agent.adapterProxy.packetOut(agent.deviceType, agent.deviceId, outPort, packet); err != nil {
938 log.Debugw("packet-out-error", log.Fields{"id": agent.lastData.Id, "error": err})
939 return err
940 }
941 return nil
942}
943
khenaidoo4d4802d2018-10-04 21:59:49 -0400944// processUpdate is a callback invoked whenever there is a change on the device manages by this device agent
khenaidoo92e62c52018-10-03 14:02:54 -0400945func (agent *DeviceAgent) processUpdate(args ...interface{}) interface{} {
khenaidoo43c82122018-11-22 18:38:28 -0500946 //// Run this callback in its own go routine
947 go func(args ...interface{}) interface{} {
948 var previous *voltha.Device
949 var current *voltha.Device
950 var ok bool
951 if len(args) == 2 {
952 if previous, ok = args[0].(*voltha.Device); !ok {
953 log.Errorw("invalid-callback-type", log.Fields{"data": args[0]})
954 return nil
955 }
956 if current, ok = args[1].(*voltha.Device); !ok {
957 log.Errorw("invalid-callback-type", log.Fields{"data": args[1]})
958 return nil
959 }
960 } else {
961 log.Errorw("too-many-args-in-callback", log.Fields{"len": len(args)})
962 return nil
963 }
964 // Perform the state transition in it's own go routine
khenaidoof5a5bfa2019-01-23 22:20:29 -0500965 if err := agent.deviceMgr.processTransition(previous, current); err != nil {
966 log.Errorw("failed-process-transition", log.Fields{"deviceId": previous.Id,
967 "previousAdminState": previous.AdminState, "currentAdminState": current.AdminState})
968 }
khenaidoo43c82122018-11-22 18:38:28 -0500969 return nil
970 }(args...)
971
khenaidoo92e62c52018-10-03 14:02:54 -0400972 return nil
973}
974
khenaidoob9203542018-09-17 22:56:37 -0400975func (agent *DeviceAgent) updateDevice(device *voltha.Device) error {
khenaidoo92e62c52018-10-03 14:02:54 -0400976 agent.lockDevice.Lock()
khenaidoo43c82122018-11-22 18:38:28 -0500977 defer agent.lockDevice.Unlock()
khenaidoob9203542018-09-17 22:56:37 -0400978 log.Debugw("updateDevice", log.Fields{"deviceId": device.Id})
khenaidoo43c82122018-11-22 18:38:28 -0500979 cloned := proto.Clone(device).(*voltha.Device)
980 afterUpdate := agent.clusterDataProxy.Update("/devices/"+device.Id, cloned, false, "")
981 if afterUpdate == nil {
982 return status.Errorf(codes.Internal, "%s", device.Id)
khenaidoob9203542018-09-17 22:56:37 -0400983 }
khenaidoo43c82122018-11-22 18:38:28 -0500984 return nil
985}
986
987func (agent *DeviceAgent) updateDeviceWithoutLock(device *voltha.Device) error {
988 log.Debugw("updateDevice", log.Fields{"deviceId": device.Id})
989 cloned := proto.Clone(device).(*voltha.Device)
990 afterUpdate := agent.clusterDataProxy.Update("/devices/"+device.Id, cloned, false, "")
991 if afterUpdate == nil {
992 return status.Errorf(codes.Internal, "%s", device.Id)
993 }
994 return nil
khenaidoob9203542018-09-17 22:56:37 -0400995}
996
khenaidoo92e62c52018-10-03 14:02:54 -0400997func (agent *DeviceAgent) updateDeviceStatus(operStatus voltha.OperStatus_OperStatus, connStatus voltha.ConnectStatus_ConnectStatus) error {
998 agent.lockDevice.Lock()
khenaidoo0a822f92019-05-08 15:15:57 -0400999 defer agent.lockDevice.Unlock()
khenaidoob9203542018-09-17 22:56:37 -04001000 // Work only on latest data
khenaidoo92e62c52018-10-03 14:02:54 -04001001 if storeDevice, err := agent.getDeviceWithoutLock(); err != nil {
khenaidoob9203542018-09-17 22:56:37 -04001002 return status.Errorf(codes.NotFound, "%s", agent.deviceId)
1003 } else {
1004 // clone the device
khenaidoo92e62c52018-10-03 14:02:54 -04001005 cloned := proto.Clone(storeDevice).(*voltha.Device)
1006 // Ensure the enums passed in are valid - they will be invalid if they are not set when this function is invoked
1007 if s, ok := voltha.ConnectStatus_ConnectStatus_value[connStatus.String()]; ok {
1008 log.Debugw("updateDeviceStatus-conn", log.Fields{"ok": ok, "val": s})
1009 cloned.ConnectStatus = connStatus
khenaidoob9203542018-09-17 22:56:37 -04001010 }
khenaidoo92e62c52018-10-03 14:02:54 -04001011 if s, ok := voltha.OperStatus_OperStatus_value[operStatus.String()]; ok {
1012 log.Debugw("updateDeviceStatus-oper", log.Fields{"ok": ok, "val": s})
1013 cloned.OperStatus = operStatus
khenaidoob9203542018-09-17 22:56:37 -04001014 }
khenaidoo92e62c52018-10-03 14:02:54 -04001015 log.Debugw("updateDeviceStatus", log.Fields{"deviceId": cloned.Id, "operStatus": cloned.OperStatus, "connectStatus": cloned.ConnectStatus})
khenaidoob9203542018-09-17 22:56:37 -04001016 // Store the device
khenaidoo92e62c52018-10-03 14:02:54 -04001017 if afterUpdate := agent.clusterDataProxy.Update("/devices/"+agent.deviceId, cloned, false, ""); afterUpdate == nil {
khenaidoob9203542018-09-17 22:56:37 -04001018 return status.Errorf(codes.Internal, "%s", agent.deviceId)
1019 }
khenaidoo92e62c52018-10-03 14:02:54 -04001020 return nil
1021 }
1022}
1023
khenaidoo3ab34882019-05-02 21:33:30 -04001024func (agent *DeviceAgent) enablePorts() error {
1025 agent.lockDevice.Lock()
1026 defer agent.lockDevice.Unlock()
1027 if storeDevice, err := agent.getDeviceWithoutLock(); err != nil {
1028 return status.Errorf(codes.NotFound, "%s", agent.deviceId)
1029 } else {
1030 // clone the device
1031 cloned := proto.Clone(storeDevice).(*voltha.Device)
1032 for _, port := range cloned.Ports {
1033 port.AdminState = voltha.AdminState_ENABLED
1034 port.OperStatus = voltha.OperStatus_ACTIVE
1035 }
1036 // Store the device
1037 if afterUpdate := agent.clusterDataProxy.Update("/devices/"+agent.deviceId, cloned, false, ""); afterUpdate == nil {
1038 return status.Errorf(codes.Internal, "%s", agent.deviceId)
1039 }
1040 return nil
1041 }
1042}
1043
1044func (agent *DeviceAgent) disablePorts() error {
khenaidoo0a822f92019-05-08 15:15:57 -04001045 log.Debugw("disablePorts", log.Fields{"deviceid": agent.deviceId})
khenaidoo3ab34882019-05-02 21:33:30 -04001046 agent.lockDevice.Lock()
1047 defer agent.lockDevice.Unlock()
1048 if storeDevice, err := agent.getDeviceWithoutLock(); err != nil {
1049 return status.Errorf(codes.NotFound, "%s", agent.deviceId)
1050 } else {
1051 // clone the device
1052 cloned := proto.Clone(storeDevice).(*voltha.Device)
1053 for _, port := range cloned.Ports {
1054 port.AdminState = voltha.AdminState_DISABLED
1055 port.OperStatus = voltha.OperStatus_UNKNOWN
1056 }
1057 // Store the device
1058 if afterUpdate := agent.clusterDataProxy.Update("/devices/"+agent.deviceId, cloned, false, ""); afterUpdate == nil {
1059 return status.Errorf(codes.Internal, "%s", agent.deviceId)
1060 }
1061 return nil
1062 }
1063}
1064
khenaidoo92e62c52018-10-03 14:02:54 -04001065func (agent *DeviceAgent) updatePortState(portType voltha.Port_PortType, portNo uint32, operStatus voltha.OperStatus_OperStatus) error {
1066 agent.lockDevice.Lock()
khenaidoo92e62c52018-10-03 14:02:54 -04001067 // Work only on latest data
1068 // TODO: Get list of ports from device directly instead of the entire device
1069 if storeDevice, err := agent.getDeviceWithoutLock(); err != nil {
1070 agent.lockDevice.Unlock()
1071 return status.Errorf(codes.NotFound, "%s", agent.deviceId)
1072 } else {
1073 // clone the device
1074 cloned := proto.Clone(storeDevice).(*voltha.Device)
1075 // Ensure the enums passed in are valid - they will be invalid if they are not set when this function is invoked
1076 if _, ok := voltha.Port_PortType_value[portType.String()]; !ok {
1077 agent.lockDevice.Unlock()
1078 return status.Errorf(codes.InvalidArgument, "%s", portType)
1079 }
1080 for _, port := range cloned.Ports {
1081 if port.Type == portType && port.PortNo == portNo {
1082 port.OperStatus = operStatus
1083 // Set the admin status to ENABLED if the operational status is ACTIVE
1084 // TODO: Set by northbound system?
1085 if operStatus == voltha.OperStatus_ACTIVE {
1086 port.AdminState = voltha.AdminState_ENABLED
1087 }
1088 break
1089 }
1090 }
1091 log.Debugw("portStatusUpdate", log.Fields{"deviceId": cloned.Id})
1092 // Store the device
1093 if afterUpdate := agent.clusterDataProxy.Update("/devices/"+agent.deviceId, cloned, false, ""); afterUpdate == nil {
1094 agent.lockDevice.Unlock()
1095 return status.Errorf(codes.Internal, "%s", agent.deviceId)
1096 }
1097 agent.lockDevice.Unlock()
khenaidoob9203542018-09-17 22:56:37 -04001098 return nil
1099 }
1100}
1101
khenaidoo0a822f92019-05-08 15:15:57 -04001102func (agent *DeviceAgent) deleteAllPorts() error {
1103 log.Debugw("deleteAllPorts", log.Fields{"deviceId": agent.deviceId})
1104 agent.lockDevice.Lock()
1105 defer agent.lockDevice.Unlock()
1106 // Work only on latest data
1107 if storeDevice, err := agent.getDeviceWithoutLock(); err != nil {
1108 return status.Errorf(codes.NotFound, "%s", agent.deviceId)
1109 } else {
1110 if storeDevice.AdminState != voltha.AdminState_DISABLED && storeDevice.AdminState != voltha.AdminState_DELETED {
1111 err = status.Error(codes.FailedPrecondition, fmt.Sprintf("invalid-state-%v", storeDevice.AdminState))
1112 log.Warnw("invalid-state-removing-ports", log.Fields{"state": storeDevice.AdminState, "error": err})
1113 return err
1114 }
1115 if len(storeDevice.Ports) == 0 {
1116 log.Debugw("no-ports-present", log.Fields{"deviceId": agent.deviceId})
1117 return nil
1118 }
1119 // clone the device & set the fields to empty
1120 cloned := proto.Clone(storeDevice).(*voltha.Device)
1121 cloned.Ports = []*voltha.Port{}
1122 log.Debugw("portStatusUpdate", log.Fields{"deviceId": cloned.Id})
1123 // Store the device
1124 if afterUpdate := agent.clusterDataProxy.Update("/devices/"+agent.deviceId, cloned, false, ""); afterUpdate == nil {
1125 return status.Errorf(codes.Internal, "%s", agent.deviceId)
1126 }
1127 return nil
1128 }
1129}
1130
khenaidoob9203542018-09-17 22:56:37 -04001131func (agent *DeviceAgent) updatePmConfigs(pmConfigs *voltha.PmConfigs) error {
khenaidoo92e62c52018-10-03 14:02:54 -04001132 agent.lockDevice.Lock()
1133 defer agent.lockDevice.Unlock()
khenaidoob9203542018-09-17 22:56:37 -04001134 log.Debug("updatePmConfigs")
1135 // Work only on latest data
khenaidoo92e62c52018-10-03 14:02:54 -04001136 if storeDevice, err := agent.getDeviceWithoutLock(); err != nil {
khenaidoob9203542018-09-17 22:56:37 -04001137 return status.Errorf(codes.NotFound, "%s", agent.deviceId)
1138 } else {
1139 // clone the device
khenaidoo92e62c52018-10-03 14:02:54 -04001140 cloned := proto.Clone(storeDevice).(*voltha.Device)
1141 cloned.PmConfigs = proto.Clone(pmConfigs).(*voltha.PmConfigs)
khenaidoob9203542018-09-17 22:56:37 -04001142 // Store the device
khenaidoo92e62c52018-10-03 14:02:54 -04001143 afterUpdate := agent.clusterDataProxy.Update("/devices/"+agent.deviceId, cloned, false, "")
khenaidoob9203542018-09-17 22:56:37 -04001144 if afterUpdate == nil {
1145 return status.Errorf(codes.Internal, "%s", agent.deviceId)
1146 }
1147 return nil
1148 }
1149}
1150
1151func (agent *DeviceAgent) addPort(port *voltha.Port) error {
khenaidoo92e62c52018-10-03 14:02:54 -04001152 agent.lockDevice.Lock()
1153 defer agent.lockDevice.Unlock()
khenaidoo0a822f92019-05-08 15:15:57 -04001154 log.Debugw("addPort", log.Fields{"deviceId": agent.deviceId})
khenaidoob9203542018-09-17 22:56:37 -04001155 // Work only on latest data
khenaidoo92e62c52018-10-03 14:02:54 -04001156 if storeDevice, err := agent.getDeviceWithoutLock(); err != nil {
khenaidoob9203542018-09-17 22:56:37 -04001157 return status.Errorf(codes.NotFound, "%s", agent.deviceId)
1158 } else {
1159 // clone the device
khenaidoo92e62c52018-10-03 14:02:54 -04001160 cloned := proto.Clone(storeDevice).(*voltha.Device)
khenaidoob9203542018-09-17 22:56:37 -04001161 if cloned.Ports == nil {
1162 // First port
khenaidoo0a822f92019-05-08 15:15:57 -04001163 log.Debugw("addPort-first-port-to-add", log.Fields{"deviceId": agent.deviceId})
khenaidoob9203542018-09-17 22:56:37 -04001164 cloned.Ports = make([]*voltha.Port, 0)
manikkaraj k259a6f72019-05-06 09:55:44 -04001165 } else {
1166 for _, p := range cloned.Ports {
1167 if p.Type == port.Type && p.PortNo == port.PortNo {
1168 log.Debugw("port already exists", log.Fields{"port": *port})
1169 return nil
1170 }
1171 }
khenaidoob9203542018-09-17 22:56:37 -04001172 }
khenaidoo92e62c52018-10-03 14:02:54 -04001173 cp := proto.Clone(port).(*voltha.Port)
1174 // Set the admin state of the port to ENABLE if the operational state is ACTIVE
1175 // TODO: Set by northbound system?
1176 if cp.OperStatus == voltha.OperStatus_ACTIVE {
1177 cp.AdminState = voltha.AdminState_ENABLED
1178 }
1179 cloned.Ports = append(cloned.Ports, cp)
khenaidoob9203542018-09-17 22:56:37 -04001180 // Store the device
khenaidoo92e62c52018-10-03 14:02:54 -04001181 afterUpdate := agent.clusterDataProxy.Update("/devices/"+agent.deviceId, cloned, false, "")
1182 if afterUpdate == nil {
1183 return status.Errorf(codes.Internal, "%s", agent.deviceId)
1184 }
1185 return nil
1186 }
1187}
1188
1189func (agent *DeviceAgent) addPeerPort(port *voltha.Port_PeerPort) error {
1190 agent.lockDevice.Lock()
1191 defer agent.lockDevice.Unlock()
1192 log.Debug("addPeerPort")
1193 // Work only on latest data
1194 if storeDevice, err := agent.getDeviceWithoutLock(); err != nil {
1195 return status.Errorf(codes.NotFound, "%s", agent.deviceId)
1196 } else {
1197 // clone the device
1198 cloned := proto.Clone(storeDevice).(*voltha.Device)
1199 // Get the peer port on the device based on the port no
1200 for _, peerPort := range cloned.Ports {
1201 if peerPort.PortNo == port.PortNo { // found port
1202 cp := proto.Clone(port).(*voltha.Port_PeerPort)
1203 peerPort.Peers = append(peerPort.Peers, cp)
1204 log.Debugw("found-peer", log.Fields{"portNo": port.PortNo, "deviceId": agent.deviceId})
1205 break
1206 }
1207 }
1208 // Store the device
1209 afterUpdate := agent.clusterDataProxy.Update("/devices/"+agent.deviceId, cloned, false, "")
khenaidoob9203542018-09-17 22:56:37 -04001210 if afterUpdate == nil {
1211 return status.Errorf(codes.Internal, "%s", agent.deviceId)
1212 }
1213 return nil
1214 }
1215}
1216
khenaidoo0a822f92019-05-08 15:15:57 -04001217func (agent *DeviceAgent) deletePeerPorts(deviceId string) error {
1218 agent.lockDevice.Lock()
1219 defer agent.lockDevice.Unlock()
1220 log.Debug("deletePeerPorts")
1221 // Work only on latest data
1222 if storeDevice, err := agent.getDeviceWithoutLock(); err != nil {
1223 return status.Errorf(codes.NotFound, "%s", agent.deviceId)
1224 } else {
1225 // clone the device
1226 cloned := proto.Clone(storeDevice).(*voltha.Device)
1227 var updatedPeers []*voltha.Port_PeerPort
1228 for _, port := range cloned.Ports {
1229 updatedPeers = make([]*voltha.Port_PeerPort, 0)
1230 for _, peerPort := range port.Peers {
1231 if peerPort.DeviceId != deviceId {
1232 updatedPeers = append(updatedPeers, peerPort)
1233 }
1234 }
1235 port.Peers = updatedPeers
1236 }
1237
1238 // Store the device with updated peer ports
1239 afterUpdate := agent.clusterDataProxy.Update("/devices/"+agent.deviceId, cloned, false, "")
1240 if afterUpdate == nil {
1241 return status.Errorf(codes.Internal, "%s", agent.deviceId)
1242 }
1243 return nil
1244 }
1245}
1246
khenaidoob9203542018-09-17 22:56:37 -04001247// TODO: A generic device update by attribute
1248func (agent *DeviceAgent) updateDeviceAttribute(name string, value interface{}) {
khenaidoo92e62c52018-10-03 14:02:54 -04001249 agent.lockDevice.Lock()
1250 defer agent.lockDevice.Unlock()
khenaidoob9203542018-09-17 22:56:37 -04001251 if value == nil {
1252 return
1253 }
1254 var storeDevice *voltha.Device
1255 var err error
khenaidoo92e62c52018-10-03 14:02:54 -04001256 if storeDevice, err = agent.getDeviceWithoutLock(); err != nil {
khenaidoob9203542018-09-17 22:56:37 -04001257 return
1258 }
1259 updated := false
1260 s := reflect.ValueOf(storeDevice).Elem()
1261 if s.Kind() == reflect.Struct {
1262 // exported field
1263 f := s.FieldByName(name)
1264 if f.IsValid() && f.CanSet() {
1265 switch f.Kind() {
1266 case reflect.String:
1267 f.SetString(value.(string))
1268 updated = true
1269 case reflect.Uint32:
1270 f.SetUint(uint64(value.(uint32)))
1271 updated = true
1272 case reflect.Bool:
1273 f.SetBool(value.(bool))
1274 updated = true
1275 }
1276 }
1277 }
khenaidoo92e62c52018-10-03 14:02:54 -04001278 log.Debugw("update-field-status", log.Fields{"deviceId": storeDevice.Id, "name": name, "updated": updated})
khenaidoob9203542018-09-17 22:56:37 -04001279 // Save the data
khenaidoo92e62c52018-10-03 14:02:54 -04001280 cloned := proto.Clone(storeDevice).(*voltha.Device)
1281 if afterUpdate := agent.clusterDataProxy.Update("/devices/"+agent.deviceId, cloned, false, ""); afterUpdate == nil {
khenaidoob9203542018-09-17 22:56:37 -04001282 log.Warnw("attribute-update-failed", log.Fields{"attribute": name, "value": value})
1283 }
1284 return
1285}
serkant.uluderya334479d2019-04-10 08:26:15 -07001286
1287func (agent *DeviceAgent) simulateAlarm(ctx context.Context, simulatereq *voltha.SimulateAlarmRequest) error {
1288 agent.lockDevice.Lock()
1289 defer agent.lockDevice.Unlock()
1290 log.Debugw("simulateAlarm", log.Fields{"id": agent.deviceId})
1291 // Get the most up to date the device info
1292 if device, err := agent.getDeviceWithoutLock(); err != nil {
1293 return status.Errorf(codes.NotFound, "%s", agent.deviceId)
1294 } else {
1295 // First send the request to an Adapter and wait for a response
1296 if err := agent.adapterProxy.SimulateAlarm(ctx, device, simulatereq); err != nil {
1297 log.Debugw("simulateAlarm-error", log.Fields{"id": agent.lastData.Id, "error": err})
1298 return err
1299 }
1300 }
1301 return nil
1302}