blob: b4dc7ea5b6c750bab6913e0915e41998767b395d [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"
khenaidoo19d7b632018-10-30 10:49:50 -040024 "github.com/opencord/voltha-go/protos/openflow_13"
khenaidoob9203542018-09-17 22:56:37 -040025 "github.com/opencord/voltha-go/protos/voltha"
26 "google.golang.org/grpc/codes"
27 "google.golang.org/grpc/status"
khenaidoob9203542018-09-17 22:56:37 -040028 "strings"
29 "sync"
30)
31
32type LogicalDeviceManager struct {
33 logicalDeviceAgents map[string]*LogicalDeviceAgent
34 deviceMgr *DeviceManager
Richard Jankowskidbab94a2018-12-06 16:20:25 -050035 grpcNbiHdlr *APIHandler
khenaidoob9203542018-09-17 22:56:37 -040036 adapterProxy *AdapterProxy
khenaidoo43c82122018-11-22 18:38:28 -050037 kafkaICProxy *kafka.InterContainerProxy
khenaidoo9a468962018-09-19 15:33:13 -040038 clusterDataProxy *model.Proxy
khenaidoob9203542018-09-17 22:56:37 -040039 exitChannel chan int
40 lockLogicalDeviceAgentsMap sync.RWMutex
41}
42
khenaidoo43c82122018-11-22 18:38:28 -050043func newLogicalDeviceManager(deviceMgr *DeviceManager, kafkaICProxy *kafka.InterContainerProxy, cdProxy *model.Proxy) *LogicalDeviceManager {
khenaidoob9203542018-09-17 22:56:37 -040044 var logicalDeviceMgr LogicalDeviceManager
45 logicalDeviceMgr.exitChannel = make(chan int, 1)
46 logicalDeviceMgr.logicalDeviceAgents = make(map[string]*LogicalDeviceAgent)
47 logicalDeviceMgr.deviceMgr = deviceMgr
khenaidoo43c82122018-11-22 18:38:28 -050048 logicalDeviceMgr.kafkaICProxy = kafkaICProxy
khenaidoo9a468962018-09-19 15:33:13 -040049 logicalDeviceMgr.clusterDataProxy = cdProxy
khenaidoob9203542018-09-17 22:56:37 -040050 logicalDeviceMgr.lockLogicalDeviceAgentsMap = sync.RWMutex{}
51 return &logicalDeviceMgr
52}
53
Richard Jankowskidbab94a2018-12-06 16:20:25 -050054func (ldMgr *LogicalDeviceManager) setGrpcNbiHandler(grpcNbiHandler *APIHandler) {
55 ldMgr.grpcNbiHdlr = grpcNbiHandler
56}
57
khenaidoo4d4802d2018-10-04 21:59:49 -040058func (ldMgr *LogicalDeviceManager) start(ctx context.Context) {
khenaidoob9203542018-09-17 22:56:37 -040059 log.Info("starting-logical-device-manager")
60 log.Info("logical-device-manager-started")
61}
62
khenaidoo4d4802d2018-10-04 21:59:49 -040063func (ldMgr *LogicalDeviceManager) stop(ctx context.Context) {
khenaidoob9203542018-09-17 22:56:37 -040064 log.Info("stopping-logical-device-manager")
65 ldMgr.exitChannel <- 1
66 log.Info("logical-device-manager-stopped")
67}
68
khenaidoo19d7b632018-10-30 10:49:50 -040069func sendAPIResponse(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
khenaidoob9203542018-09-17 22:56:37 -040081func (ldMgr *LogicalDeviceManager) addLogicalDeviceAgentToMap(agent *LogicalDeviceAgent) {
82 ldMgr.lockLogicalDeviceAgentsMap.Lock()
83 defer ldMgr.lockLogicalDeviceAgentsMap.Unlock()
84 if _, exist := ldMgr.logicalDeviceAgents[agent.logicalDeviceId]; !exist {
85 ldMgr.logicalDeviceAgents[agent.logicalDeviceId] = agent
86 }
87}
88
89func (ldMgr *LogicalDeviceManager) getLogicalDeviceAgent(logicalDeviceId string) *LogicalDeviceAgent {
90 ldMgr.lockLogicalDeviceAgentsMap.Lock()
91 defer ldMgr.lockLogicalDeviceAgentsMap.Unlock()
92 if agent, ok := ldMgr.logicalDeviceAgents[logicalDeviceId]; ok {
93 return agent
94 }
95 return nil
96}
97
khenaidoo92e62c52018-10-03 14:02:54 -040098func (ldMgr *LogicalDeviceManager) deleteLogicalDeviceAgent(logicalDeviceId string) {
99 ldMgr.lockLogicalDeviceAgentsMap.Lock()
100 defer ldMgr.lockLogicalDeviceAgentsMap.Unlock()
101 delete(ldMgr.logicalDeviceAgents, logicalDeviceId)
102}
103
khenaidoo19d7b632018-10-30 10:49:50 -0400104// GetLogicalDevice provides a cloned most up to date logical device
khenaidoob9203542018-09-17 22:56:37 -0400105func (ldMgr *LogicalDeviceManager) getLogicalDevice(id string) (*voltha.LogicalDevice, error) {
khenaidoo92e62c52018-10-03 14:02:54 -0400106 log.Debugw("getlogicalDevice", log.Fields{"logicaldeviceid": id})
107 if agent := ldMgr.getLogicalDeviceAgent(id); agent != nil {
khenaidoo19d7b632018-10-30 10:49:50 -0400108 return agent.GetLogicalDevice()
khenaidoob9203542018-09-17 22:56:37 -0400109 }
110 return nil, status.Errorf(codes.NotFound, "%s", id)
111}
112
113func (ldMgr *LogicalDeviceManager) listLogicalDevices() (*voltha.LogicalDevices, error) {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500114 log.Debug("ListAllLogicalDevices")
khenaidoob9203542018-09-17 22:56:37 -0400115 result := &voltha.LogicalDevices{}
khenaidoo297cd252019-02-07 22:10:23 -0500116 if logicalDevices := ldMgr.clusterDataProxy.List("/logical_devices", 0, false, ""); logicalDevices != nil {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500117 for _, logicalDevice := range logicalDevices.([]interface{}) {
118 if agent := ldMgr.getLogicalDeviceAgent(logicalDevice.(*voltha.LogicalDevice).Id); agent == nil {
119 agent = newLogicalDeviceAgent(
120 logicalDevice.(*voltha.LogicalDevice).Id,
121 logicalDevice.(*voltha.LogicalDevice).RootDeviceId,
122 ldMgr,
123 ldMgr.deviceMgr,
124 ldMgr.clusterDataProxy,
125 )
126 ldMgr.addLogicalDeviceAgentToMap(agent)
khenaidoo297cd252019-02-07 22:10:23 -0500127 go agent.start(nil, true)
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500128 }
129 result.Items = append(result.Items, logicalDevice.(*voltha.LogicalDevice))
khenaidoob9203542018-09-17 22:56:37 -0400130 }
131 }
132 return result, nil
133}
134
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500135//func (ldMgr *LogicalDeviceManager) listLogicalDevices() (*voltha.LogicalDevices, error) {
136// log.Debug("listLogicalDevices")
137// result := &voltha.LogicalDevices{}
138// ldMgr.lockLogicalDeviceAgentsMap.Lock()
139// defer ldMgr.lockLogicalDeviceAgentsMap.Unlock()
140// for _, agent := range ldMgr.logicalDeviceAgents {
141// if lDevice, err := agent.GetLogicalDevice(); err == nil {
142// result.Items = append(result.Items, lDevice)
143// }
144// }
145// return result, nil
146//}
147
khenaidoo4d4802d2018-10-04 21:59:49 -0400148func (ldMgr *LogicalDeviceManager) createLogicalDevice(ctx context.Context, device *voltha.Device) (*string, error) {
khenaidoo92e62c52018-10-03 14:02:54 -0400149 log.Debugw("creating-logical-device", log.Fields{"deviceId": device.Id})
khenaidoob9203542018-09-17 22:56:37 -0400150 // Sanity check
151 if !device.Root {
152 return nil, errors.New("Device-not-root")
153 }
154
155 // Create a logical device agent - the logical device Id is based on the mac address of the device
156 // For now use the serial number - it may contain any combination of alphabetic characters and numbers,
157 // with length varying from eight characters to a maximum of 14 characters. Mac Address is part of oneof
158 // in the Device model. May need to be moved out.
159 macAddress := device.MacAddress
160 id := strings.Replace(macAddress, ":", "", -1)
khenaidoo92e62c52018-10-03 14:02:54 -0400161 if id == "" {
162 log.Errorw("mac-address-not-set", log.Fields{"deviceId": device.Id})
163 return nil, errors.New("mac-address-not-set")
164 }
165 log.Debugw("logical-device-id", log.Fields{"logicaldeviceId": id})
khenaidoob9203542018-09-17 22:56:37 -0400166
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500167 agent := newLogicalDeviceAgent(id, device.Id, ldMgr, ldMgr.deviceMgr, ldMgr.clusterDataProxy)
khenaidoob9203542018-09-17 22:56:37 -0400168 ldMgr.addLogicalDeviceAgentToMap(agent)
khenaidoo297cd252019-02-07 22:10:23 -0500169 go agent.start(ctx, false)
khenaidoob9203542018-09-17 22:56:37 -0400170
khenaidoo92e62c52018-10-03 14:02:54 -0400171 log.Debug("creating-logical-device-ends")
khenaidoob9203542018-09-17 22:56:37 -0400172 return &id, nil
173}
174
khenaidoo297cd252019-02-07 22:10:23 -0500175// load loads a logical device manager in memory
176func (ldMgr *LogicalDeviceManager) load(lDeviceId string) error {
177 log.Debugw("loading-logical-device", log.Fields{"lDeviceId": lDeviceId})
178 // To prevent a race condition, let's hold the logical device agent map lock. This will prevent a loading and
179 // a create logical device callback from occurring at the same time.
180 ldMgr.lockLogicalDeviceAgentsMap.Lock()
181 defer ldMgr.lockLogicalDeviceAgentsMap.Unlock()
182 if ldAgent, _ := ldMgr.logicalDeviceAgents[lDeviceId]; ldAgent == nil {
183 // Logical device not in memory - create a temp logical device Agent and let it load from memory
184 agent := newLogicalDeviceAgent(lDeviceId, "", ldMgr, ldMgr.deviceMgr, ldMgr.clusterDataProxy)
185 if err := agent.start(nil, true); err != nil {
186 agent.stop(nil)
187 return err
188 }
189 ldMgr.logicalDeviceAgents[agent.logicalDeviceId] = agent
190 }
191 // TODO: load the child device
192 return nil
193}
194
khenaidoo4d4802d2018-10-04 21:59:49 -0400195func (ldMgr *LogicalDeviceManager) deleteLogicalDevice(ctx context.Context, device *voltha.Device) error {
khenaidoo92e62c52018-10-03 14:02:54 -0400196 log.Debugw("deleting-logical-device", log.Fields{"deviceId": device.Id})
197 // Sanity check
198 if !device.Root {
199 return errors.New("Device-not-root")
200 }
201 logDeviceId := device.ParentId
202 if agent := ldMgr.getLogicalDeviceAgent(logDeviceId); agent != nil {
203 // Stop the logical device agent
khenaidoo4d4802d2018-10-04 21:59:49 -0400204 agent.stop(ctx)
khenaidoo92e62c52018-10-03 14:02:54 -0400205 //Remove the logical device agent from the Map
206 ldMgr.deleteLogicalDeviceAgent(logDeviceId)
207 }
208
209 log.Debug("deleting-logical-device-ends")
210 return nil
211}
212
213func (ldMgr *LogicalDeviceManager) getLogicalDeviceId(device *voltha.Device) (*string, error) {
214 // Device can either be a parent or a child device
215 if device.Root {
216 // Parent device. The ID of a parent device is the logical device ID
217 return &device.ParentId, nil
218 }
219 // Device is child device
220 // retrieve parent device using child device ID
221 if parentDevice := ldMgr.deviceMgr.getParentDevice(device); parentDevice != nil {
222 return &parentDevice.ParentId, nil
223 }
224 return nil, status.Errorf(codes.NotFound, "%s", device.Id)
225}
226
khenaidoo19d7b632018-10-30 10:49:50 -0400227func (ldMgr *LogicalDeviceManager) getLogicalPortId(device *voltha.Device) (*voltha.LogicalPortId, error) {
228 // Get the logical device where this device is attached
229 var lDeviceId *string
230 var err error
231 if lDeviceId, err = ldMgr.getLogicalDeviceId(device); err != nil {
232 return nil, err
233 }
234 var lDevice *voltha.LogicalDevice
235 if lDevice, err = ldMgr.getLogicalDevice(*lDeviceId); err != nil {
236 return nil, err
237 }
238 // Go over list of ports
239 for _, port := range lDevice.Ports {
240 if port.DeviceId == device.Id {
241 return &voltha.LogicalPortId{Id: *lDeviceId, PortId: port.Id}, nil
242 }
243 }
244 return nil, status.Errorf(codes.NotFound, "%s", device.Id)
245}
246
247func (ldMgr *LogicalDeviceManager) ListLogicalDevicePorts(ctx context.Context, id string) (*voltha.LogicalPorts, error) {
248 log.Debugw("ListLogicalDevicePorts", log.Fields{"logicaldeviceid": id})
249 if agent := ldMgr.getLogicalDeviceAgent(id); agent != nil {
250 return agent.ListLogicalDevicePorts()
251 }
252 return nil, status.Errorf(codes.NotFound, "%s", id)
253
254}
255
256func (ldMgr *LogicalDeviceManager) getLogicalPort(lPortId *voltha.LogicalPortId) (*voltha.LogicalPort, error) {
257 // Get the logical device where this device is attached
258 var err error
259 var lDevice *voltha.LogicalDevice
260 if lDevice, err = ldMgr.getLogicalDevice(lPortId.Id); err != nil {
261 return nil, err
262 }
263 // Go over list of ports
264 for _, port := range lDevice.Ports {
265 if port.Id == lPortId.PortId {
266 return port, nil
267 }
268 }
269 return nil, status.Errorf(codes.NotFound, "%s-$s", lPortId.Id, lPortId.PortId)
270}
271
272// deleteLogicalPort removes the logical port associated with a child device
273func (ldMgr *LogicalDeviceManager) deleteLogicalPort(ctx context.Context, lPortId *voltha.LogicalPortId) error {
274 log.Debugw("deleting-logical-port", log.Fields{"LDeviceId": lPortId.Id})
275 // Get logical port
276 var logicalPort *voltha.LogicalPort
277 var err error
278 if logicalPort, err = ldMgr.getLogicalPort(lPortId); err != nil {
279 log.Debugw("no-logical-device-port-present", log.Fields{"logicalPortId": lPortId.PortId})
280 return err
281 }
khenaidoo92e62c52018-10-03 14:02:54 -0400282 // Sanity check
khenaidoo19d7b632018-10-30 10:49:50 -0400283 if logicalPort.RootPort {
khenaidoo92e62c52018-10-03 14:02:54 -0400284 return errors.New("Device-root")
285 }
khenaidoo19d7b632018-10-30 10:49:50 -0400286 if agent := ldMgr.getLogicalDeviceAgent(lPortId.Id); agent != nil {
287 agent.deleteLogicalPort(logicalPort)
khenaidoo92e62c52018-10-03 14:02:54 -0400288 }
289
290 log.Debug("deleting-logical-port-ends")
291 return nil
292}
293
khenaidoo4d4802d2018-10-04 21:59:49 -0400294func (ldMgr *LogicalDeviceManager) addUNILogicalPort(ctx context.Context, childDevice *voltha.Device) error {
khenaidoo92e62c52018-10-03 14:02:54 -0400295 log.Debugw("AddUNILogicalPort", log.Fields{"deviceId": childDevice.Id})
khenaidoob9203542018-09-17 22:56:37 -0400296 // Sanity check
297 if childDevice.Root {
298 return errors.New("Device-root")
299 }
300
301 // Get the logical device id parent device
302 parentId := childDevice.ParentId
303 logDeviceId := ldMgr.deviceMgr.GetParentDeviceId(parentId)
304
khenaidoo92e62c52018-10-03 14:02:54 -0400305 log.Debugw("AddUNILogicalPort", log.Fields{"logDeviceId": logDeviceId, "parentId": parentId})
khenaidoob9203542018-09-17 22:56:37 -0400306
307 if agent := ldMgr.getLogicalDeviceAgent(*logDeviceId); agent != nil {
khenaidoobcf205b2019-01-25 22:21:14 -0500308 if err := agent.addUNILogicalPort(ctx, childDevice); err != nil {
309 return err
310 }
311 // Update the device routes - let it run in its own go routine as it can take time
312 go agent.updateRoutes()
khenaidoob9203542018-09-17 22:56:37 -0400313 }
khenaidoo21d51152019-02-01 13:48:37 -0500314 return nil
khenaidoob9203542018-09-17 22:56:37 -0400315}
khenaidoo19d7b632018-10-30 10:49:50 -0400316
317func (ldMgr *LogicalDeviceManager) updateFlowTable(ctx context.Context, id string, flow *openflow_13.OfpFlowMod, ch chan interface{}) {
318 log.Debugw("updateFlowTable", log.Fields{"logicalDeviceId": id})
319 var res interface{}
320 if agent := ldMgr.getLogicalDeviceAgent(id); agent != nil {
321 res = agent.updateFlowTable(ctx, flow)
322 log.Debugw("updateFlowTable-result", log.Fields{"result": res})
323 } else {
324 res = status.Errorf(codes.NotFound, "%s", id)
325 }
326 sendAPIResponse(ctx, ch, res)
327}
328
329func (ldMgr *LogicalDeviceManager) updateGroupTable(ctx context.Context, id string, groupMod *openflow_13.OfpGroupMod, ch chan interface{}) {
330 log.Debugw("updateGroupTable", log.Fields{"logicalDeviceId": id})
331 var res interface{}
332 if agent := ldMgr.getLogicalDeviceAgent(id); agent != nil {
333 res = agent.updateGroupTable(ctx, groupMod)
334 log.Debugw("updateGroupTable-result", log.Fields{"result": res})
335 } else {
336 res = status.Errorf(codes.NotFound, "%s", id)
337 }
338 sendAPIResponse(ctx, ch, res)
339}
340
341func (ldMgr *LogicalDeviceManager) enableLogicalPort(ctx context.Context, id *voltha.LogicalPortId, ch chan interface{}) {
342 log.Debugw("enableLogicalPort", log.Fields{"logicalDeviceId": id})
343 var res interface{}
344 // Get logical port
345 var logicalPort *voltha.LogicalPort
346 var err error
347 if logicalPort, err = ldMgr.getLogicalPort(id); err != nil {
348 log.Debugw("no-logical-device-port-present", log.Fields{"logicalPortId": id.PortId})
349 res = err
350 }
351 if agent := ldMgr.getLogicalDeviceAgent(id.Id); agent != nil {
352 res = agent.enableLogicalPort(logicalPort)
353 log.Debugw("enableLogicalPort-result", log.Fields{"result": res})
354 } else {
355 res = status.Errorf(codes.NotFound, "%s", id.Id)
356 }
357 sendAPIResponse(ctx, ch, res)
358}
359
360func (ldMgr *LogicalDeviceManager) disableLogicalPort(ctx context.Context, id *voltha.LogicalPortId, ch chan interface{}) {
361 log.Debugw("disableLogicalPort", log.Fields{"logicalDeviceId": id})
362 var res interface{}
363 // Get logical port
364 var logicalPort *voltha.LogicalPort
365 var err error
366 if logicalPort, err = ldMgr.getLogicalPort(id); err != nil {
367 log.Debugw("no-logical-device-port-present", log.Fields{"logicalPortId": id.PortId})
368 res = err
369 }
370 if agent := ldMgr.getLogicalDeviceAgent(id.Id); agent != nil {
371 res = agent.disableLogicalPort(logicalPort)
372 log.Debugw("disableLogicalPort-result", log.Fields{"result": res})
373 } else {
374 res = status.Errorf(codes.NotFound, "%s", id.Id)
375 }
376 sendAPIResponse(ctx, ch, res)
377}
khenaidoofdbad6e2018-11-06 22:26:38 -0500378
khenaidoo43c82122018-11-22 18:38:28 -0500379func (ldMgr *LogicalDeviceManager) packetOut(packetOut *openflow_13.PacketOut) {
khenaidoofdbad6e2018-11-06 22:26:38 -0500380 log.Debugw("packetOut", log.Fields{"logicalDeviceId": packetOut.Id})
381 if agent := ldMgr.getLogicalDeviceAgent(packetOut.Id); agent != nil {
382 agent.packetOut(packetOut.PacketOut)
383 } else {
384 log.Error("logical-device-not-exist", log.Fields{"logicalDeviceId": packetOut.Id})
385 }
386}
387
khenaidoo297cd252019-02-07 22:10:23 -0500388func (ldMgr *LogicalDeviceManager) packetIn(logicalDeviceId string, port uint32, transactionId string, packet []byte) error {
khenaidoofdbad6e2018-11-06 22:26:38 -0500389 log.Debugw("packetIn", log.Fields{"logicalDeviceId": logicalDeviceId, "port": port})
390 if agent := ldMgr.getLogicalDeviceAgent(logicalDeviceId); agent != nil {
khenaidoo297cd252019-02-07 22:10:23 -0500391 agent.packetIn(port, transactionId, packet)
khenaidoofdbad6e2018-11-06 22:26:38 -0500392 } else {
393 log.Error("logical-device-not-exist", log.Fields{"logicalDeviceId": logicalDeviceId})
394 }
395 return nil
396}