blob: 18bc30ab5c5491cce40fe679a5ca107442561d67 [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{}
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500116 if logicalDevices := ldMgr.clusterDataProxy.Get("/logical_devices", 0, false, ""); logicalDevices != nil {
117 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)
127 go agent.start(nil)
128 }
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)
khenaidoo4d4802d2018-10-04 21:59:49 -0400169 go agent.start(ctx)
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
khenaidoo4d4802d2018-10-04 21:59:49 -0400175func (ldMgr *LogicalDeviceManager) deleteLogicalDevice(ctx context.Context, device *voltha.Device) error {
khenaidoo92e62c52018-10-03 14:02:54 -0400176 log.Debugw("deleting-logical-device", log.Fields{"deviceId": device.Id})
177 // Sanity check
178 if !device.Root {
179 return errors.New("Device-not-root")
180 }
181 logDeviceId := device.ParentId
182 if agent := ldMgr.getLogicalDeviceAgent(logDeviceId); agent != nil {
183 // Stop the logical device agent
khenaidoo4d4802d2018-10-04 21:59:49 -0400184 agent.stop(ctx)
khenaidoo92e62c52018-10-03 14:02:54 -0400185 //Remove the logical device agent from the Map
186 ldMgr.deleteLogicalDeviceAgent(logDeviceId)
187 }
188
189 log.Debug("deleting-logical-device-ends")
190 return nil
191}
192
193func (ldMgr *LogicalDeviceManager) getLogicalDeviceId(device *voltha.Device) (*string, error) {
194 // Device can either be a parent or a child device
195 if device.Root {
196 // Parent device. The ID of a parent device is the logical device ID
197 return &device.ParentId, nil
198 }
199 // Device is child device
200 // retrieve parent device using child device ID
201 if parentDevice := ldMgr.deviceMgr.getParentDevice(device); parentDevice != nil {
202 return &parentDevice.ParentId, nil
203 }
204 return nil, status.Errorf(codes.NotFound, "%s", device.Id)
205}
206
khenaidoo19d7b632018-10-30 10:49:50 -0400207func (ldMgr *LogicalDeviceManager) getLogicalPortId(device *voltha.Device) (*voltha.LogicalPortId, error) {
208 // Get the logical device where this device is attached
209 var lDeviceId *string
210 var err error
211 if lDeviceId, err = ldMgr.getLogicalDeviceId(device); err != nil {
212 return nil, err
213 }
214 var lDevice *voltha.LogicalDevice
215 if lDevice, err = ldMgr.getLogicalDevice(*lDeviceId); err != nil {
216 return nil, err
217 }
218 // Go over list of ports
219 for _, port := range lDevice.Ports {
220 if port.DeviceId == device.Id {
221 return &voltha.LogicalPortId{Id: *lDeviceId, PortId: port.Id}, nil
222 }
223 }
224 return nil, status.Errorf(codes.NotFound, "%s", device.Id)
225}
226
227func (ldMgr *LogicalDeviceManager) ListLogicalDevicePorts(ctx context.Context, id string) (*voltha.LogicalPorts, error) {
228 log.Debugw("ListLogicalDevicePorts", log.Fields{"logicaldeviceid": id})
229 if agent := ldMgr.getLogicalDeviceAgent(id); agent != nil {
230 return agent.ListLogicalDevicePorts()
231 }
232 return nil, status.Errorf(codes.NotFound, "%s", id)
233
234}
235
236func (ldMgr *LogicalDeviceManager) getLogicalPort(lPortId *voltha.LogicalPortId) (*voltha.LogicalPort, error) {
237 // Get the logical device where this device is attached
238 var err error
239 var lDevice *voltha.LogicalDevice
240 if lDevice, err = ldMgr.getLogicalDevice(lPortId.Id); err != nil {
241 return nil, err
242 }
243 // Go over list of ports
244 for _, port := range lDevice.Ports {
245 if port.Id == lPortId.PortId {
246 return port, nil
247 }
248 }
249 return nil, status.Errorf(codes.NotFound, "%s-$s", lPortId.Id, lPortId.PortId)
250}
251
252// deleteLogicalPort removes the logical port associated with a child device
253func (ldMgr *LogicalDeviceManager) deleteLogicalPort(ctx context.Context, lPortId *voltha.LogicalPortId) error {
254 log.Debugw("deleting-logical-port", log.Fields{"LDeviceId": lPortId.Id})
255 // Get logical port
256 var logicalPort *voltha.LogicalPort
257 var err error
258 if logicalPort, err = ldMgr.getLogicalPort(lPortId); err != nil {
259 log.Debugw("no-logical-device-port-present", log.Fields{"logicalPortId": lPortId.PortId})
260 return err
261 }
khenaidoo92e62c52018-10-03 14:02:54 -0400262 // Sanity check
khenaidoo19d7b632018-10-30 10:49:50 -0400263 if logicalPort.RootPort {
khenaidoo92e62c52018-10-03 14:02:54 -0400264 return errors.New("Device-root")
265 }
khenaidoo19d7b632018-10-30 10:49:50 -0400266 if agent := ldMgr.getLogicalDeviceAgent(lPortId.Id); agent != nil {
267 agent.deleteLogicalPort(logicalPort)
khenaidoo92e62c52018-10-03 14:02:54 -0400268 }
269
270 log.Debug("deleting-logical-port-ends")
271 return nil
272}
273
khenaidoo4d4802d2018-10-04 21:59:49 -0400274func (ldMgr *LogicalDeviceManager) addUNILogicalPort(ctx context.Context, childDevice *voltha.Device) error {
khenaidoo92e62c52018-10-03 14:02:54 -0400275 log.Debugw("AddUNILogicalPort", log.Fields{"deviceId": childDevice.Id})
khenaidoob9203542018-09-17 22:56:37 -0400276 // Sanity check
277 if childDevice.Root {
278 return errors.New("Device-root")
279 }
280
281 // Get the logical device id parent device
282 parentId := childDevice.ParentId
283 logDeviceId := ldMgr.deviceMgr.GetParentDeviceId(parentId)
284
khenaidoo92e62c52018-10-03 14:02:54 -0400285 log.Debugw("AddUNILogicalPort", log.Fields{"logDeviceId": logDeviceId, "parentId": parentId})
khenaidoob9203542018-09-17 22:56:37 -0400286
287 if agent := ldMgr.getLogicalDeviceAgent(*logDeviceId); agent != nil {
khenaidoobcf205b2019-01-25 22:21:14 -0500288 if err := agent.addUNILogicalPort(ctx, childDevice); err != nil {
289 return err
290 }
291 // Update the device routes - let it run in its own go routine as it can take time
292 go agent.updateRoutes()
khenaidoob9203542018-09-17 22:56:37 -0400293 }
khenaidoo21d51152019-02-01 13:48:37 -0500294 return nil
khenaidoob9203542018-09-17 22:56:37 -0400295}
khenaidoo19d7b632018-10-30 10:49:50 -0400296
297func (ldMgr *LogicalDeviceManager) updateFlowTable(ctx context.Context, id string, flow *openflow_13.OfpFlowMod, ch chan interface{}) {
298 log.Debugw("updateFlowTable", log.Fields{"logicalDeviceId": id})
299 var res interface{}
300 if agent := ldMgr.getLogicalDeviceAgent(id); agent != nil {
301 res = agent.updateFlowTable(ctx, flow)
302 log.Debugw("updateFlowTable-result", log.Fields{"result": res})
303 } else {
304 res = status.Errorf(codes.NotFound, "%s", id)
305 }
306 sendAPIResponse(ctx, ch, res)
307}
308
309func (ldMgr *LogicalDeviceManager) updateGroupTable(ctx context.Context, id string, groupMod *openflow_13.OfpGroupMod, ch chan interface{}) {
310 log.Debugw("updateGroupTable", log.Fields{"logicalDeviceId": id})
311 var res interface{}
312 if agent := ldMgr.getLogicalDeviceAgent(id); agent != nil {
313 res = agent.updateGroupTable(ctx, groupMod)
314 log.Debugw("updateGroupTable-result", log.Fields{"result": res})
315 } else {
316 res = status.Errorf(codes.NotFound, "%s", id)
317 }
318 sendAPIResponse(ctx, ch, res)
319}
320
321func (ldMgr *LogicalDeviceManager) enableLogicalPort(ctx context.Context, id *voltha.LogicalPortId, ch chan interface{}) {
322 log.Debugw("enableLogicalPort", log.Fields{"logicalDeviceId": id})
323 var res interface{}
324 // Get logical port
325 var logicalPort *voltha.LogicalPort
326 var err error
327 if logicalPort, err = ldMgr.getLogicalPort(id); err != nil {
328 log.Debugw("no-logical-device-port-present", log.Fields{"logicalPortId": id.PortId})
329 res = err
330 }
331 if agent := ldMgr.getLogicalDeviceAgent(id.Id); agent != nil {
332 res = agent.enableLogicalPort(logicalPort)
333 log.Debugw("enableLogicalPort-result", log.Fields{"result": res})
334 } else {
335 res = status.Errorf(codes.NotFound, "%s", id.Id)
336 }
337 sendAPIResponse(ctx, ch, res)
338}
339
340func (ldMgr *LogicalDeviceManager) disableLogicalPort(ctx context.Context, id *voltha.LogicalPortId, ch chan interface{}) {
341 log.Debugw("disableLogicalPort", log.Fields{"logicalDeviceId": id})
342 var res interface{}
343 // Get logical port
344 var logicalPort *voltha.LogicalPort
345 var err error
346 if logicalPort, err = ldMgr.getLogicalPort(id); err != nil {
347 log.Debugw("no-logical-device-port-present", log.Fields{"logicalPortId": id.PortId})
348 res = err
349 }
350 if agent := ldMgr.getLogicalDeviceAgent(id.Id); agent != nil {
351 res = agent.disableLogicalPort(logicalPort)
352 log.Debugw("disableLogicalPort-result", log.Fields{"result": res})
353 } else {
354 res = status.Errorf(codes.NotFound, "%s", id.Id)
355 }
356 sendAPIResponse(ctx, ch, res)
357}
khenaidoofdbad6e2018-11-06 22:26:38 -0500358
khenaidoo43c82122018-11-22 18:38:28 -0500359func (ldMgr *LogicalDeviceManager) packetOut(packetOut *openflow_13.PacketOut) {
khenaidoofdbad6e2018-11-06 22:26:38 -0500360 log.Debugw("packetOut", log.Fields{"logicalDeviceId": packetOut.Id})
361 if agent := ldMgr.getLogicalDeviceAgent(packetOut.Id); agent != nil {
362 agent.packetOut(packetOut.PacketOut)
363 } else {
364 log.Error("logical-device-not-exist", log.Fields{"logicalDeviceId": packetOut.Id})
365 }
366}
367
368func (ldMgr *LogicalDeviceManager) packetIn(logicalDeviceId string, port uint32, packet []byte) error {
369 log.Debugw("packetIn", log.Fields{"logicalDeviceId": logicalDeviceId, "port": port})
370 if agent := ldMgr.getLogicalDeviceAgent(logicalDeviceId); agent != nil {
371 agent.packetIn(port, packet)
372 } else {
373 log.Error("logical-device-not-exist", log.Fields{"logicalDeviceId": logicalDeviceId})
374 }
375 return nil
376}