blob: a6c0c8de60817fcd27d49800e8f6eab980488fe2 [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"
21 "github.com/opencord/voltha-go/common/log"
22 "github.com/opencord/voltha-go/db/model"
23 "github.com/opencord/voltha-go/kafka"
24 "github.com/opencord/voltha-go/protos/core_adapter"
25 "github.com/opencord/voltha-go/protos/voltha"
26 "google.golang.org/grpc/codes"
27 "google.golang.org/grpc/status"
28 "reflect"
29 "runtime"
30 "sync"
31)
32
33type DeviceManager struct {
34 deviceAgents map[string]*DeviceAgent
35 adapterProxy *AdapterProxy
36 logicalDeviceMgr *LogicalDeviceManager
37 kafkaProxy *kafka.KafkaMessagingProxy
38 stateTransitions *TransitionMap
39 localDataProxy *model.Proxy
40 exitChannel chan int
41 lockDeviceAgentsMap sync.RWMutex
42}
43
44func NewDeviceManager(kafkaProxy *kafka.KafkaMessagingProxy, ldProxy *model.Proxy) *DeviceManager {
45 var deviceMgr DeviceManager
46 deviceMgr.exitChannel = make(chan int, 1)
47 deviceMgr.deviceAgents = make(map[string]*DeviceAgent)
48 deviceMgr.adapterProxy = NewAdapterProxy(kafkaProxy)
49 deviceMgr.kafkaProxy = kafkaProxy
50 deviceMgr.localDataProxy = ldProxy
51 deviceMgr.lockDeviceAgentsMap = sync.RWMutex{}
52 return &deviceMgr
53}
54
55func (dMgr *DeviceManager) Start(ctx context.Context, logicalDeviceMgr *LogicalDeviceManager) {
56 log.Info("starting-device-manager")
57 dMgr.logicalDeviceMgr = logicalDeviceMgr
58 dMgr.stateTransitions = NewTransitionMap(dMgr)
59 log.Info("device-manager-started")
60}
61
62func (dMgr *DeviceManager) Stop(ctx context.Context) {
63 log.Info("stopping-device-manager")
64 dMgr.exitChannel <- 1
65 log.Info("device-manager-stopped")
66}
67
68func sendResponse(ctx context.Context, ch chan interface{}, result interface{}) {
69 if ctx.Err() == nil {
70 // Returned response only of the ctx has not been cancelled/timeout/etc
71 // Channel is automatically closed when a context is Done
72 ch <- result
73 log.Debugw("sendResponse", log.Fields{"result": result})
74 } else {
75 // Should the transaction be reverted back?
76 log.Debugw("sendResponse-context-error", log.Fields{"context-error": ctx.Err()})
77 }
78}
79
80func (dMgr *DeviceManager) addDeviceAgentToMap(agent *DeviceAgent) {
81 dMgr.lockDeviceAgentsMap.Lock()
82 defer dMgr.lockDeviceAgentsMap.Unlock()
83 if _, exist := dMgr.deviceAgents[agent.deviceId]; !exist {
84 dMgr.deviceAgents[agent.deviceId] = agent
85 }
86}
87
88func (dMgr *DeviceManager) getDeviceAgent(deviceId string) *DeviceAgent {
89 dMgr.lockDeviceAgentsMap.Lock()
90 defer dMgr.lockDeviceAgentsMap.Unlock()
91 if agent, ok := dMgr.deviceAgents[deviceId]; ok {
92 return agent
93 }
94 return nil
95}
96
97func (dMgr *DeviceManager) createDevice(ctx context.Context, device *voltha.Device, ch chan interface{}) {
98 log.Debugw("createDevice-start", log.Fields{"device": device, "aproxy": dMgr.adapterProxy})
99
100 // Create and start a device agent for that device
101 agent := newDeviceAgent(dMgr.adapterProxy, device, dMgr, dMgr.localDataProxy)
102 dMgr.addDeviceAgentToMap(agent)
103 agent.start(ctx)
104
105 sendResponse(ctx, ch, nil)
106}
107
108func (dMgr *DeviceManager) enableDevice(ctx context.Context, id *voltha.ID, ch chan interface{}) {
109 log.Debugw("enableDevice-start", log.Fields{"deviceid": id})
110
111 var res interface{}
112 if agent := dMgr.getDeviceAgent(id.Id); agent != nil {
113 res = agent.enableDevice(ctx)
114 log.Debugw("EnableDevice-result", log.Fields{"result": res})
115 } else {
116 res = status.Errorf(codes.NotFound, "%s", id.Id)
117 }
118
119 sendResponse(ctx, ch, res)
120}
121
122func (dMgr *DeviceManager) getDevice(id string) (*voltha.Device, error) {
123 log.Debugw("getDevice-start", log.Fields{"deviceid": id})
124
125 if device := dMgr.localDataProxy.Get("/devices/"+id, 1, false, ""); device == nil {
126 return nil, status.Errorf(codes.NotFound, "%s", id)
127 } else {
128 cloned := reflect.ValueOf(device).Elem().Interface().(voltha.Device)
129 return &cloned, nil
130 }
131}
132
133func (dMgr *DeviceManager) ListDevices() (*voltha.Devices, error) {
134 log.Debug("ListDevices-start")
135 result := &voltha.Devices{}
136 dMgr.lockDeviceAgentsMap.Lock()
137 defer dMgr.lockDeviceAgentsMap.Unlock()
138 for _, agent := range dMgr.deviceAgents {
139 if device := dMgr.localDataProxy.Get("/devices/"+agent.deviceId, 1, false, ""); device != nil {
140 cloned := reflect.ValueOf(device).Elem().Interface().(voltha.Device)
141 result.Items = append(result.Items, &cloned)
142 }
143 }
144 return result, nil
145}
146
147func (dMgr *DeviceManager) updateDevice(device *voltha.Device) error {
148 log.Debugw("updateDevice-start", log.Fields{"deviceid": device.Id, "device": device})
149
150 if agent := dMgr.getDeviceAgent(device.Id); agent != nil {
151 return agent.updateDevice(device)
152 }
153 return status.Errorf(codes.NotFound, "%s", device.Id)
154}
155
156func (dMgr *DeviceManager) addPort(deviceId string, port *voltha.Port) error {
157 if agent := dMgr.getDeviceAgent(deviceId); agent != nil {
158 return agent.addPort(port)
159 }
160 return status.Errorf(codes.NotFound, "%s", deviceId)
161}
162
163func (dMgr *DeviceManager) updatePmConfigs(deviceId string, pmConfigs *voltha.PmConfigs) error {
164 if agent := dMgr.getDeviceAgent(deviceId); agent != nil {
165 return agent.updatePmConfigs(pmConfigs)
166 }
167 return status.Errorf(codes.NotFound, "%s", deviceId)
168}
169
170func (dMgr *DeviceManager) getSwitchCapability(ctx context.Context, deviceId string) (*core_adapter.SwitchCapability, error) {
171 log.Debugw("getSwitchCapability-start", log.Fields{"deviceid": deviceId})
172
173 if agent := dMgr.getDeviceAgent(deviceId); agent != nil {
174 return agent.getSwitchCapability(ctx)
175 }
176 return nil, status.Errorf(codes.NotFound, "%s", deviceId)
177}
178
179func (dMgr *DeviceManager) getNNIPorts(ctx context.Context, deviceId string) (*voltha.Ports, error) {
180 log.Debugw("getNNIPorts-start", log.Fields{"deviceid": deviceId})
181
182 if agent := dMgr.getDeviceAgent(deviceId); agent != nil {
183 return agent.getNNIPorts(ctx), nil
184 }
185 return nil, status.Errorf(codes.NotFound, "%s", deviceId)
186}
187
188func (dMgr *DeviceManager) getPortCapability(ctx context.Context, deviceId string, portNo uint32) (*core_adapter.PortCapability, error) {
189 log.Debugw("getPortCapability-start", log.Fields{"deviceid": deviceId})
190
191 if agent := dMgr.getDeviceAgent(deviceId); agent != nil {
192 return agent.getPortCapability(ctx, portNo)
193 }
194 return nil, status.Errorf(codes.NotFound, "%s", deviceId)
195}
196
197func (dMgr *DeviceManager) updateDeviceState(deviceId string, operState *core_adapter.IntType, connState *core_adapter.IntType) error {
198 log.Debugw("updateDeviceState-start", log.Fields{"deviceid": deviceId, "operState": operState, "connState": connState})
199 if agent := dMgr.getDeviceAgent(deviceId); agent != nil {
200 return agent.updateDeviceState(operState, connState)
201 }
202 return status.Errorf(codes.NotFound, "%s", deviceId)
203}
204
205func (dMgr *DeviceManager) childDeviceDetected(parentDeviceId string, parentPortNo int64, deviceType string, channelId int64) error {
206 log.Debugw("childDeviceDetected-start", log.Fields{"parentDeviceId": parentDeviceId})
207
208 // Create the ONU device
209 childDevice := &voltha.Device{}
210 childDevice.Id = CreateDeviceId()
211 childDevice.Type = deviceType
212 childDevice.ParentId = parentDeviceId
213 childDevice.ParentPortNo = uint32(parentPortNo)
214 childDevice.Root = false
215 childDevice.ProxyAddress = &voltha.Device_ProxyAddress{ChannelId: uint32(channelId)}
216
217 // Create and start a device agent for that device
218 agent := newDeviceAgent(dMgr.adapterProxy, childDevice, dMgr, dMgr.localDataProxy)
219 dMgr.addDeviceAgentToMap(agent)
220 agent.start(nil)
221
222 // Activate the child device
223 if agent := dMgr.getDeviceAgent(childDevice.Id); agent != nil {
224 return agent.enableDevice(nil)
225 }
226
227 return nil
228}
229
230func (dMgr *DeviceManager) processTransition(previous *voltha.Device, current *voltha.Device) error {
231 // This will be triggered on every update to the device.
232 handler := dMgr.stateTransitions.GetTransitionHandler(previous, current)
233 if handler != nil {
234 log.Debugw("found-handler", log.Fields{"handler": funcName(handler)})
235 return handler(previous, current)
236 }
237 log.Debugw("handler-not-found", log.Fields{"deviceId": current.Id})
238 return nil
239}
240
241func (dMgr *DeviceManager) createLogicalDevice(pDevice *voltha.Device, cDevice *voltha.Device) error {
242 log.Info("createLogicalDevice")
243 var logicalId *string
244 var err error
245 if logicalId, err = dMgr.logicalDeviceMgr.CreateLogicalDevice(nil, cDevice); err != nil {
246 log.Warnw("createlogical-device-error", log.Fields{"device": cDevice})
247 return err
248 }
249 // Update the parent device with the logical id
250 dMgr.UpdateDeviceAttribute(cDevice.Id, "ParentId", *logicalId)
251 return nil
252}
253
254func (dMgr *DeviceManager) addUNILogicalPort(pDevice *voltha.Device, cDevice *voltha.Device) error {
255 log.Info("addUNILogicalPort")
256 if err := dMgr.logicalDeviceMgr.AddUNILogicalPort(nil, cDevice); err != nil {
257 log.Warnw("addUNILogicalPort-error", log.Fields{"device": cDevice, "err": err})
258 return err
259 }
260 return nil
261}
262
263func (dMgr *DeviceManager) activateDevice(pDevice *voltha.Device, cDevice *voltha.Device) error {
264 log.Info("activateDevice")
265 return nil
266}
267
268func (dMgr *DeviceManager) disableDevice(pDevice *voltha.Device, cDevice *voltha.Device) error {
269 log.Info("disableDevice")
270 return nil
271}
272
273func (dMgr *DeviceManager) abandonDevice(pDevice *voltha.Device, cDevice *voltha.Device) error {
274 log.Info("abandonDevice")
275 return nil
276}
277
278func (dMgr *DeviceManager) reEnableDevice(pDevice *voltha.Device, cDevice *voltha.Device) error {
279 log.Info("reEnableDevice")
280 return nil
281}
282
283func (dMgr *DeviceManager) noOp(pDevice *voltha.Device, cDevice *voltha.Device) error {
284 log.Info("noOp")
285 return nil
286}
287
288func (dMgr *DeviceManager) notAllowed(pDevice *voltha.Device, cDevice *voltha.Device) error {
289 log.Info("notAllowed")
290 return errors.New("Transition-not-allowed")
291}
292
293func funcName(f interface{}) string {
294 p := reflect.ValueOf(f).Pointer()
295 rf := runtime.FuncForPC(p)
296 return rf.Name()
297}
298
299func (dMgr *DeviceManager) UpdateDeviceAttribute(deviceId string, attribute string, value interface{}) {
300 if agent, ok := dMgr.deviceAgents[deviceId]; ok {
301 agent.updateDeviceAttribute(attribute, value)
302 }
303}
304
305func (dMgr *DeviceManager) GetParentDeviceId(deviceId string) *string {
306 if device, _ := dMgr.getDevice(deviceId); device != nil {
307 log.Infow("GetParentDeviceId", log.Fields{"device": device})
308 return &device.ParentId
309 }
310 return nil
311}