blob: e3dbed2ddd8d996daabcc4ee43e3ea8b64f828fe [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"
20 "errors"
khenaidoo92e62c52018-10-03 14:02:54 -040021 "github.com/gogo/protobuf/proto"
khenaidoob9203542018-09-17 22:56:37 -040022 "github.com/opencord/voltha-go/common/log"
23 "github.com/opencord/voltha-go/db/model"
24 "github.com/opencord/voltha-go/kafka"
25 "github.com/opencord/voltha-go/protos/core_adapter"
26 "github.com/opencord/voltha-go/protos/voltha"
27 "google.golang.org/grpc/codes"
28 "google.golang.org/grpc/status"
29 "reflect"
30 "runtime"
31 "sync"
32)
33
34type DeviceManager struct {
35 deviceAgents map[string]*DeviceAgent
36 adapterProxy *AdapterProxy
37 logicalDeviceMgr *LogicalDeviceManager
38 kafkaProxy *kafka.KafkaMessagingProxy
39 stateTransitions *TransitionMap
khenaidoo9a468962018-09-19 15:33:13 -040040 clusterDataProxy *model.Proxy
khenaidoob9203542018-09-17 22:56:37 -040041 exitChannel chan int
42 lockDeviceAgentsMap sync.RWMutex
43}
44
khenaidoo9a468962018-09-19 15:33:13 -040045func NewDeviceManager(kafkaProxy *kafka.KafkaMessagingProxy, cdProxy *model.Proxy) *DeviceManager {
khenaidoob9203542018-09-17 22:56:37 -040046 var deviceMgr DeviceManager
47 deviceMgr.exitChannel = make(chan int, 1)
48 deviceMgr.deviceAgents = make(map[string]*DeviceAgent)
49 deviceMgr.adapterProxy = NewAdapterProxy(kafkaProxy)
50 deviceMgr.kafkaProxy = kafkaProxy
khenaidoo9a468962018-09-19 15:33:13 -040051 deviceMgr.clusterDataProxy = cdProxy
khenaidoob9203542018-09-17 22:56:37 -040052 deviceMgr.lockDeviceAgentsMap = sync.RWMutex{}
53 return &deviceMgr
54}
55
56func (dMgr *DeviceManager) Start(ctx context.Context, logicalDeviceMgr *LogicalDeviceManager) {
57 log.Info("starting-device-manager")
58 dMgr.logicalDeviceMgr = logicalDeviceMgr
59 dMgr.stateTransitions = NewTransitionMap(dMgr)
60 log.Info("device-manager-started")
61}
62
63func (dMgr *DeviceManager) Stop(ctx context.Context) {
64 log.Info("stopping-device-manager")
65 dMgr.exitChannel <- 1
66 log.Info("device-manager-stopped")
67}
68
69func sendResponse(ctx context.Context, ch chan interface{}, result interface{}) {
70 if ctx.Err() == nil {
71 // Returned response only of the ctx has not been cancelled/timeout/etc
72 // Channel is automatically closed when a context is Done
73 ch <- result
74 log.Debugw("sendResponse", log.Fields{"result": result})
75 } else {
76 // Should the transaction be reverted back?
77 log.Debugw("sendResponse-context-error", log.Fields{"context-error": ctx.Err()})
78 }
79}
80
81func (dMgr *DeviceManager) addDeviceAgentToMap(agent *DeviceAgent) {
82 dMgr.lockDeviceAgentsMap.Lock()
83 defer dMgr.lockDeviceAgentsMap.Unlock()
84 if _, exist := dMgr.deviceAgents[agent.deviceId]; !exist {
85 dMgr.deviceAgents[agent.deviceId] = agent
86 }
87}
88
89func (dMgr *DeviceManager) getDeviceAgent(deviceId string) *DeviceAgent {
90 dMgr.lockDeviceAgentsMap.Lock()
91 defer dMgr.lockDeviceAgentsMap.Unlock()
92 if agent, ok := dMgr.deviceAgents[deviceId]; ok {
93 return agent
94 }
95 return nil
96}
97
98func (dMgr *DeviceManager) createDevice(ctx context.Context, device *voltha.Device, ch chan interface{}) {
khenaidoo92e62c52018-10-03 14:02:54 -040099 log.Debugw("createDevice", log.Fields{"device": device, "aproxy": dMgr.adapterProxy})
khenaidoob9203542018-09-17 22:56:37 -0400100
101 // Create and start a device agent for that device
khenaidoo9a468962018-09-19 15:33:13 -0400102 agent := newDeviceAgent(dMgr.adapterProxy, device, dMgr, dMgr.clusterDataProxy)
khenaidoob9203542018-09-17 22:56:37 -0400103 dMgr.addDeviceAgentToMap(agent)
104 agent.start(ctx)
105
khenaidoo92e62c52018-10-03 14:02:54 -0400106 sendResponse(ctx, ch, agent.lastData)
khenaidoob9203542018-09-17 22:56:37 -0400107}
108
109func (dMgr *DeviceManager) enableDevice(ctx context.Context, id *voltha.ID, ch chan interface{}) {
khenaidoo92e62c52018-10-03 14:02:54 -0400110 log.Debugw("enableDevice", log.Fields{"deviceid": id})
khenaidoob9203542018-09-17 22:56:37 -0400111
112 var res interface{}
113 if agent := dMgr.getDeviceAgent(id.Id); agent != nil {
114 res = agent.enableDevice(ctx)
115 log.Debugw("EnableDevice-result", log.Fields{"result": res})
116 } else {
117 res = status.Errorf(codes.NotFound, "%s", id.Id)
118 }
119
120 sendResponse(ctx, ch, res)
121}
122
khenaidoo92e62c52018-10-03 14:02:54 -0400123func (dMgr *DeviceManager) disableDevice(ctx context.Context, id *voltha.ID, ch chan interface{}) {
124 log.Debugw("disableDevice", log.Fields{"deviceid": id})
khenaidoob9203542018-09-17 22:56:37 -0400125
khenaidoo92e62c52018-10-03 14:02:54 -0400126 var res interface{}
127 if agent := dMgr.getDeviceAgent(id.Id); agent != nil {
128 res = agent.disableDevice(ctx)
129 log.Debugw("disableDevice-result", log.Fields{"result": res})
khenaidoob9203542018-09-17 22:56:37 -0400130 } else {
khenaidoo92e62c52018-10-03 14:02:54 -0400131 res = status.Errorf(codes.NotFound, "%s", id.Id)
khenaidoob9203542018-09-17 22:56:37 -0400132 }
khenaidoo92e62c52018-10-03 14:02:54 -0400133
134 sendResponse(ctx, ch, res)
135}
136
137func (dMgr *DeviceManager) getDevice(id string) (*voltha.Device, error) {
138 log.Debugw("getDevice", log.Fields{"deviceid": id})
139 if agent := dMgr.getDeviceAgent(id); agent != nil {
140 return agent.getDevice()
141 }
142 return nil, status.Errorf(codes.NotFound, "%s", id)
khenaidoob9203542018-09-17 22:56:37 -0400143}
144
145func (dMgr *DeviceManager) ListDevices() (*voltha.Devices, error) {
khenaidoo92e62c52018-10-03 14:02:54 -0400146 log.Debug("ListDevices")
khenaidoob9203542018-09-17 22:56:37 -0400147 result := &voltha.Devices{}
148 dMgr.lockDeviceAgentsMap.Lock()
149 defer dMgr.lockDeviceAgentsMap.Unlock()
150 for _, agent := range dMgr.deviceAgents {
khenaidoo92e62c52018-10-03 14:02:54 -0400151 if device, err := agent.getDevice(); err == nil {
152 cloned := proto.Clone(device).(*voltha.Device)
153 result.Items = append(result.Items, cloned)
khenaidoob9203542018-09-17 22:56:37 -0400154 }
155 }
156 return result, nil
157}
158
159func (dMgr *DeviceManager) updateDevice(device *voltha.Device) error {
khenaidoo92e62c52018-10-03 14:02:54 -0400160 log.Debugw("updateDevice", log.Fields{"deviceid": device.Id, "device": device})
khenaidoob9203542018-09-17 22:56:37 -0400161
162 if agent := dMgr.getDeviceAgent(device.Id); agent != nil {
163 return agent.updateDevice(device)
164 }
165 return status.Errorf(codes.NotFound, "%s", device.Id)
166}
167
168func (dMgr *DeviceManager) addPort(deviceId string, port *voltha.Port) error {
169 if agent := dMgr.getDeviceAgent(deviceId); agent != nil {
khenaidoo92e62c52018-10-03 14:02:54 -0400170 if err := agent.addPort(port); err != nil {
171 return err
172 }
173 // Setup peer ports
174 meAsPeer := &voltha.Port_PeerPort{DeviceId: deviceId, PortNo: port.PortNo}
175 for _, peerPort := range port.Peers {
176 if agent := dMgr.getDeviceAgent(peerPort.DeviceId); agent != nil {
177 if err := agent.addPeerPort(meAsPeer); err != nil {
178 log.Errorw("failed-to-add-peer", log.Fields{"peer-device-id": peerPort.DeviceId})
179 return err
180 }
181 }
182 }
183 return nil
184 } else {
185 return status.Errorf(codes.NotFound, "%s", deviceId)
khenaidoob9203542018-09-17 22:56:37 -0400186 }
khenaidoob9203542018-09-17 22:56:37 -0400187}
188
189func (dMgr *DeviceManager) updatePmConfigs(deviceId string, pmConfigs *voltha.PmConfigs) error {
190 if agent := dMgr.getDeviceAgent(deviceId); agent != nil {
191 return agent.updatePmConfigs(pmConfigs)
192 }
193 return status.Errorf(codes.NotFound, "%s", deviceId)
194}
195
196func (dMgr *DeviceManager) getSwitchCapability(ctx context.Context, deviceId string) (*core_adapter.SwitchCapability, error) {
khenaidoo92e62c52018-10-03 14:02:54 -0400197 log.Debugw("getSwitchCapability", log.Fields{"deviceid": deviceId})
khenaidoob9203542018-09-17 22:56:37 -0400198
199 if agent := dMgr.getDeviceAgent(deviceId); agent != nil {
200 return agent.getSwitchCapability(ctx)
201 }
202 return nil, status.Errorf(codes.NotFound, "%s", deviceId)
203}
204
khenaidoo92e62c52018-10-03 14:02:54 -0400205func (dMgr *DeviceManager) getPorts(ctx context.Context, deviceId string, portType voltha.Port_PortType) (*voltha.Ports, error) {
206 log.Debugw("getPorts", log.Fields{"deviceid": deviceId, "portType": portType})
khenaidoob9203542018-09-17 22:56:37 -0400207
208 if agent := dMgr.getDeviceAgent(deviceId); agent != nil {
khenaidoo92e62c52018-10-03 14:02:54 -0400209 return agent.getPorts(ctx, portType), nil
khenaidoob9203542018-09-17 22:56:37 -0400210 }
211 return nil, status.Errorf(codes.NotFound, "%s", deviceId)
khenaidoo92e62c52018-10-03 14:02:54 -0400212
khenaidoob9203542018-09-17 22:56:37 -0400213}
214
215func (dMgr *DeviceManager) getPortCapability(ctx context.Context, deviceId string, portNo uint32) (*core_adapter.PortCapability, error) {
khenaidoo92e62c52018-10-03 14:02:54 -0400216 log.Debugw("getPortCapability", log.Fields{"deviceid": deviceId})
khenaidoob9203542018-09-17 22:56:37 -0400217
218 if agent := dMgr.getDeviceAgent(deviceId); agent != nil {
219 return agent.getPortCapability(ctx, portNo)
220 }
221 return nil, status.Errorf(codes.NotFound, "%s", deviceId)
222}
223
khenaidoo92e62c52018-10-03 14:02:54 -0400224func (dMgr *DeviceManager) updateDeviceStatus(deviceId string, operStatus voltha.OperStatus_OperStatus, connStatus voltha.ConnectStatus_ConnectStatus) error {
225 log.Debugw("updateDeviceStatus", log.Fields{"deviceid": deviceId, "operStatus": operStatus, "connStatus": connStatus})
khenaidoob9203542018-09-17 22:56:37 -0400226 if agent := dMgr.getDeviceAgent(deviceId); agent != nil {
khenaidoo92e62c52018-10-03 14:02:54 -0400227 return agent.updateDeviceStatus(operStatus, connStatus)
228 }
229 return status.Errorf(codes.NotFound, "%s", deviceId)
230}
231
232func (dMgr *DeviceManager) updatePortState(deviceId string, portType voltha.Port_PortType, portNo uint32, operStatus voltha.OperStatus_OperStatus) error {
233 log.Debugw("updatePortState", log.Fields{"deviceid": deviceId, "portType": portType, "portNo": portNo, "operStatus": operStatus})
234 if agent := dMgr.getDeviceAgent(deviceId); agent != nil {
235 return agent.updatePortState(portType, portNo, operStatus)
khenaidoob9203542018-09-17 22:56:37 -0400236 }
237 return status.Errorf(codes.NotFound, "%s", deviceId)
238}
239
240func (dMgr *DeviceManager) childDeviceDetected(parentDeviceId string, parentPortNo int64, deviceType string, channelId int64) error {
khenaidoo92e62c52018-10-03 14:02:54 -0400241 log.Debugw("childDeviceDetected", log.Fields{"parentDeviceId": parentDeviceId})
khenaidoob9203542018-09-17 22:56:37 -0400242
243 // Create the ONU device
244 childDevice := &voltha.Device{}
khenaidoob9203542018-09-17 22:56:37 -0400245 childDevice.Type = deviceType
246 childDevice.ParentId = parentDeviceId
247 childDevice.ParentPortNo = uint32(parentPortNo)
248 childDevice.Root = false
249 childDevice.ProxyAddress = &voltha.Device_ProxyAddress{ChannelId: uint32(channelId)}
250
251 // Create and start a device agent for that device
khenaidoo9a468962018-09-19 15:33:13 -0400252 agent := newDeviceAgent(dMgr.adapterProxy, childDevice, dMgr, dMgr.clusterDataProxy)
khenaidoob9203542018-09-17 22:56:37 -0400253 dMgr.addDeviceAgentToMap(agent)
254 agent.start(nil)
255
256 // Activate the child device
khenaidoo92e62c52018-10-03 14:02:54 -0400257 if agent := dMgr.getDeviceAgent(agent.deviceId); agent != nil {
khenaidoob9203542018-09-17 22:56:37 -0400258 return agent.enableDevice(nil)
259 }
260
261 return nil
262}
263
264func (dMgr *DeviceManager) processTransition(previous *voltha.Device, current *voltha.Device) error {
265 // This will be triggered on every update to the device.
khenaidoo92e62c52018-10-03 14:02:54 -0400266 handlers := dMgr.stateTransitions.GetTransitionHandler(previous, current)
267 if handlers == nil {
268 log.Debugw("handlers-not-found", log.Fields{"deviceId": current.Id})
269 return nil
khenaidoob9203542018-09-17 22:56:37 -0400270 }
khenaidoo92e62c52018-10-03 14:02:54 -0400271 for _, handler := range handlers {
272 log.Debugw("running-handler", log.Fields{"handler": funcName(handler)})
273 if err := handler(current); err != nil {
274 return err
275 }
276 }
277 //if handler != nil {
278 // log.Debugw("found-handlers", log.Fields{"handlers": funcName(handler)})
279 // return handler(current)
280 //}
khenaidoob9203542018-09-17 22:56:37 -0400281 return nil
282}
283
khenaidoo92e62c52018-10-03 14:02:54 -0400284func (dMgr *DeviceManager) createLogicalDevice(cDevice *voltha.Device) error {
khenaidoob9203542018-09-17 22:56:37 -0400285 log.Info("createLogicalDevice")
286 var logicalId *string
287 var err error
288 if logicalId, err = dMgr.logicalDeviceMgr.CreateLogicalDevice(nil, cDevice); err != nil {
289 log.Warnw("createlogical-device-error", log.Fields{"device": cDevice})
290 return err
291 }
292 // Update the parent device with the logical id
293 dMgr.UpdateDeviceAttribute(cDevice.Id, "ParentId", *logicalId)
294 return nil
295}
296
khenaidoo92e62c52018-10-03 14:02:54 -0400297func (dMgr *DeviceManager) deleteLogicalDevice(cDevice *voltha.Device) error {
298 log.Info("deleteLogicalDevice")
299 var err error
300 if err = dMgr.logicalDeviceMgr.DeleteLogicalDevice(nil, cDevice); err != nil {
301 log.Warnw("deleteLogical-device-error", log.Fields{"deviceId": cDevice.Id})
302 return err
303 }
304 // Remove the logical device Id from the parent device
305 logicalId := ""
306 dMgr.UpdateDeviceAttribute(cDevice.Id, "ParentId", logicalId)
307 return nil
308}
309
310func (dMgr *DeviceManager) deleteLogicalPort(cDevice *voltha.Device) error {
311 log.Info("deleteLogicalPort")
312 var err error
313 if err = dMgr.logicalDeviceMgr.DeleteLogicalPort(nil, cDevice); err != nil {
314 log.Warnw("deleteLogical-port-error", log.Fields{"deviceId": cDevice.Id})
315 return err
316 }
317 //// Remove the logical device Id from the parent device
318 //logicalId := ""
319 //dMgr.UpdateDeviceAttribute(cDevice.Id, "ParentId", logicalId)
320 return nil
321}
322
323func (dMgr *DeviceManager) getParentDevice(childDevice *voltha.Device) *voltha.Device {
324 // Sanity check
325 if childDevice.Root {
326 // childDevice is the parent device
327 return childDevice
328 }
329 parentDevice, _ := dMgr.getDevice(childDevice.ParentId)
330 return parentDevice
331}
332
333func (dMgr *DeviceManager) disableAllChildDevices(cDevice *voltha.Device) error {
334 log.Debug("disableAllChildDevices")
335 var childDeviceIds []string
336 var err error
337 if childDeviceIds, err = dMgr.getAllChildDeviceIds(cDevice); err != nil {
338 return status.Errorf(codes.NotFound, "%s", cDevice.Id)
339 }
340 if len(childDeviceIds) == 0 {
341 log.Debugw("no-child-device", log.Fields{"deviceId": cDevice.Id})
342 }
343 for _, childDeviceId := range childDeviceIds {
344 if agent := dMgr.getDeviceAgent(childDeviceId); agent != nil {
345 if err = agent.disableDevice(nil); err != nil {
346 log.Errorw("failure-disable-device", log.Fields{"deviceId": childDeviceId, "error": err.Error()})
347 }
348 }
349 }
350 return nil
351}
352
353func (dMgr *DeviceManager) getAllChildDeviceIds(cDevice *voltha.Device) ([]string, error) {
354 log.Info("getAllChildDeviceIds")
355 // Get latest device info
356 var device *voltha.Device
357 var err error
358 if device, err = dMgr.getDevice(cDevice.Id); err != nil {
359 return nil, status.Errorf(codes.NotFound, "%s", cDevice.Id)
360 }
361 childDeviceIds := make([]string, 0)
362 for _, port := range device.Ports {
363 for _, peer := range port.Peers {
364 childDeviceIds = append(childDeviceIds, peer.DeviceId)
365 }
366 }
367 return childDeviceIds, nil
368}
369
370func (dMgr *DeviceManager) addUNILogicalPort(cDevice *voltha.Device) error {
khenaidoob9203542018-09-17 22:56:37 -0400371 log.Info("addUNILogicalPort")
372 if err := dMgr.logicalDeviceMgr.AddUNILogicalPort(nil, cDevice); err != nil {
373 log.Warnw("addUNILogicalPort-error", log.Fields{"device": cDevice, "err": err})
374 return err
375 }
376 return nil
377}
378
khenaidoo92e62c52018-10-03 14:02:54 -0400379func (dMgr *DeviceManager) activateDevice(cDevice *voltha.Device) error {
khenaidoob9203542018-09-17 22:56:37 -0400380 log.Info("activateDevice")
381 return nil
382}
383
khenaidoo92e62c52018-10-03 14:02:54 -0400384func (dMgr *DeviceManager) disableDeviceHandler(cDevice *voltha.Device) error {
385 log.Info("disableDevice-donothing")
khenaidoob9203542018-09-17 22:56:37 -0400386 return nil
387}
388
khenaidoo92e62c52018-10-03 14:02:54 -0400389func (dMgr *DeviceManager) abandonDevice(cDevice *voltha.Device) error {
khenaidoob9203542018-09-17 22:56:37 -0400390 log.Info("abandonDevice")
391 return nil
392}
393
khenaidoo92e62c52018-10-03 14:02:54 -0400394func (dMgr *DeviceManager) reEnableDevice(cDevice *voltha.Device) error {
khenaidoob9203542018-09-17 22:56:37 -0400395 log.Info("reEnableDevice")
396 return nil
397}
398
khenaidoo92e62c52018-10-03 14:02:54 -0400399func (dMgr *DeviceManager) noOp(cDevice *voltha.Device) error {
khenaidoob9203542018-09-17 22:56:37 -0400400 log.Info("noOp")
401 return nil
402}
403
khenaidoo92e62c52018-10-03 14:02:54 -0400404func (dMgr *DeviceManager) notAllowed(pcDevice *voltha.Device) error {
khenaidoob9203542018-09-17 22:56:37 -0400405 log.Info("notAllowed")
406 return errors.New("Transition-not-allowed")
407}
408
409func funcName(f interface{}) string {
410 p := reflect.ValueOf(f).Pointer()
411 rf := runtime.FuncForPC(p)
412 return rf.Name()
413}
414
415func (dMgr *DeviceManager) UpdateDeviceAttribute(deviceId string, attribute string, value interface{}) {
416 if agent, ok := dMgr.deviceAgents[deviceId]; ok {
417 agent.updateDeviceAttribute(attribute, value)
418 }
419}
420
421func (dMgr *DeviceManager) GetParentDeviceId(deviceId string) *string {
422 if device, _ := dMgr.getDevice(deviceId); device != nil {
khenaidoo92e62c52018-10-03 14:02:54 -0400423 log.Infow("GetParentDeviceId", log.Fields{"deviceId": device.Id, "parentId": device.ParentId})
khenaidoob9203542018-09-17 22:56:37 -0400424 return &device.ParentId
425 }
426 return nil
427}