blob: cae40e1463f3ca5c0b61e7702a768f08a0838bdb [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"
khenaidoo19d7b632018-10-30 10:49:50 -040020 "errors"
21 "fmt"
khenaidoob9203542018-09-17 22:56:37 -040022 "github.com/gogo/protobuf/proto"
23 "github.com/opencord/voltha-go/common/log"
24 "github.com/opencord/voltha-go/db/model"
khenaidoo89b0e942018-10-21 21:11:33 -040025 fd "github.com/opencord/voltha-go/rw_core/flow_decomposition"
26 "github.com/opencord/voltha-go/rw_core/graph"
27 fu "github.com/opencord/voltha-go/rw_core/utils"
khenaidoo8f474192019-04-03 17:20:44 -040028 ic "github.com/opencord/voltha-protos/go/inter_container"
29 ofp "github.com/opencord/voltha-protos/go/openflow_13"
30 "github.com/opencord/voltha-protos/go/voltha"
khenaidoob9203542018-09-17 22:56:37 -040031 "google.golang.org/grpc/codes"
32 "google.golang.org/grpc/status"
khenaidoo19d7b632018-10-30 10:49:50 -040033 "reflect"
khenaidoo92e62c52018-10-03 14:02:54 -040034 "sync"
khenaidoob9203542018-09-17 22:56:37 -040035)
36
37type LogicalDeviceAgent struct {
khenaidoo3306c992019-05-24 16:57:35 -040038 logicalDeviceId string
39 rootDeviceId string
40 deviceMgr *DeviceManager
41 ldeviceMgr *LogicalDeviceManager
42 clusterDataProxy *model.Proxy
43 exitChannel chan int
44 deviceGraph *graph.DeviceGraph
45 flowProxy *model.Proxy
46 groupProxy *model.Proxy
47 ldProxy *model.Proxy
48 portProxies map[string]*model.Proxy
49 portProxiesLock sync.RWMutex
50 lockLogicalDevice sync.RWMutex
51 logicalPortsNo map[uint32]bool //value is true for NNI port
52 lockLogicalPortsNo sync.RWMutex
53 flowDecomposer *fd.FlowDecomposer
54 defaultTimeout int64
khenaidoob9203542018-09-17 22:56:37 -040055}
56
Stephane Barbarie1ab43272018-12-08 21:42:13 -050057func newLogicalDeviceAgent(id string, deviceId string, ldeviceMgr *LogicalDeviceManager,
58 deviceMgr *DeviceManager,
khenaidoo2c6a0992019-04-29 13:46:56 -040059 cdProxy *model.Proxy, timeout int64) *LogicalDeviceAgent {
khenaidoob9203542018-09-17 22:56:37 -040060 var agent LogicalDeviceAgent
61 agent.exitChannel = make(chan int, 1)
62 agent.logicalDeviceId = id
Stephane Barbarie1ab43272018-12-08 21:42:13 -050063 agent.rootDeviceId = deviceId
khenaidoob9203542018-09-17 22:56:37 -040064 agent.deviceMgr = deviceMgr
khenaidoo9a468962018-09-19 15:33:13 -040065 agent.clusterDataProxy = cdProxy
khenaidoob9203542018-09-17 22:56:37 -040066 agent.ldeviceMgr = ldeviceMgr
khenaidoo19d7b632018-10-30 10:49:50 -040067 agent.flowDecomposer = fd.NewFlowDecomposer(agent.deviceMgr)
khenaidoo92e62c52018-10-03 14:02:54 -040068 agent.lockLogicalDevice = sync.RWMutex{}
khenaidoofc1314d2019-03-14 09:34:21 -040069 agent.portProxies = make(map[string]*model.Proxy)
70 agent.portProxiesLock = sync.RWMutex{}
khenaidoo2c6a0992019-04-29 13:46:56 -040071 agent.lockLogicalPortsNo = sync.RWMutex{}
72 agent.logicalPortsNo = make(map[uint32]bool)
khenaidoo2c6a0992019-04-29 13:46:56 -040073 agent.defaultTimeout = timeout
khenaidoob9203542018-09-17 22:56:37 -040074 return &agent
75}
76
khenaidoo4d4802d2018-10-04 21:59:49 -040077// start creates the logical device and add it to the data model
khenaidoo297cd252019-02-07 22:10:23 -050078func (agent *LogicalDeviceAgent) start(ctx context.Context, loadFromdB bool) error {
79 log.Infow("starting-logical_device-agent", log.Fields{"logicaldeviceId": agent.logicalDeviceId, "loadFromdB": loadFromdB})
80 var ld *voltha.LogicalDevice
81 if !loadFromdB {
82 //Build the logical device based on information retrieved from the device adapter
83 var switchCap *ic.SwitchCapability
84 var err error
85 if switchCap, err = agent.deviceMgr.getSwitchCapability(ctx, agent.rootDeviceId); err != nil {
khenaidoob9203542018-09-17 22:56:37 -040086 log.Errorw("error-creating-logical-device", log.Fields{"error": err})
87 return err
88 }
khenaidoo297cd252019-02-07 22:10:23 -050089 ld = &voltha.LogicalDevice{Id: agent.logicalDeviceId, RootDeviceId: agent.rootDeviceId}
90
91 // Create the datapath ID (uint64) using the logical device ID (based on the MAC Address)
92 var datapathID uint64
93 if datapathID, err = CreateDataPathId(agent.logicalDeviceId); err != nil {
94 log.Errorw("error-creating-datapath-id", log.Fields{"error": err})
95 return err
96 }
97 ld.DatapathId = datapathID
98 ld.Desc = (proto.Clone(switchCap.Desc)).(*ofp.OfpDesc)
khenaidoo6d055132019-02-12 16:51:19 -050099 log.Debugw("Switch-capability", log.Fields{"Desc": ld.Desc, "fromAd": switchCap.Desc})
khenaidoo297cd252019-02-07 22:10:23 -0500100 ld.SwitchFeatures = (proto.Clone(switchCap.SwitchFeatures)).(*ofp.OfpSwitchFeatures)
101 ld.Flows = &ofp.Flows{Items: nil}
102 ld.FlowGroups = &ofp.FlowGroups{Items: nil}
103
khenaidoo297cd252019-02-07 22:10:23 -0500104 agent.lockLogicalDevice.Lock()
khenaidoo297cd252019-02-07 22:10:23 -0500105 // Save the logical device
106 if added := agent.clusterDataProxy.AddWithID("/logical_devices", ld.Id, ld, ""); added == nil {
107 log.Errorw("failed-to-add-logical-device", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
108 } else {
109 log.Debugw("logicaldevice-created", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
110 }
111 agent.lockLogicalDevice.Unlock()
khenaidoofc1314d2019-03-14 09:34:21 -0400112
khenaidoo3d3b8c22019-05-22 18:10:39 -0400113 // TODO: Set the logical ports in a separate call once the port update issue is fixed.
114 go agent.setupLogicalPorts(ctx)
115
khenaidoo297cd252019-02-07 22:10:23 -0500116 } else {
117 // load from dB - the logical may not exist at this time. On error, just return and the calling function
118 // will destroy this agent.
119 var err error
120 if ld, err = agent.GetLogicalDevice(); err != nil {
121 log.Warnw("failed-to-load-logical-device", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
122 return err
123 }
khenaidoo3d3b8c22019-05-22 18:10:39 -0400124
khenaidoo8c3303d2019-02-13 14:59:39 -0500125 // Update the root device Id
126 agent.rootDeviceId = ld.RootDeviceId
khenaidoo3d3b8c22019-05-22 18:10:39 -0400127
128 // Setup the local list of logical ports
129 agent.addLogicalPortsToMap(ld.Ports)
130
131 // Setup the device graph
132 agent.generateDeviceGraph()
khenaidoob9203542018-09-17 22:56:37 -0400133 }
khenaidoo92e62c52018-10-03 14:02:54 -0400134 agent.lockLogicalDevice.Lock()
khenaidoo3d3b8c22019-05-22 18:10:39 -0400135 defer agent.lockLogicalDevice.Unlock()
khenaidoofc1314d2019-03-14 09:34:21 -0400136
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400137 agent.flowProxy = agent.clusterDataProxy.CreateProxy(
khenaidoo19d7b632018-10-30 10:49:50 -0400138 fmt.Sprintf("/logical_devices/%s/flows", agent.logicalDeviceId),
139 false)
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400140 agent.groupProxy = agent.clusterDataProxy.CreateProxy(
khenaidoo19d7b632018-10-30 10:49:50 -0400141 fmt.Sprintf("/logical_devices/%s/flow_groups", agent.logicalDeviceId),
142 false)
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400143 agent.ldProxy = agent.clusterDataProxy.CreateProxy(
khenaidoofc1314d2019-03-14 09:34:21 -0400144 fmt.Sprintf("/logical_devices/%s", agent.logicalDeviceId),
145 false)
khenaidoo19d7b632018-10-30 10:49:50 -0400146
khenaidoofc1314d2019-03-14 09:34:21 -0400147 // TODO: Use a port proxy once the POST_ADD is fixed
khenaidoo3d3b8c22019-05-22 18:10:39 -0400148 if agent.ldProxy != nil {
149 agent.ldProxy.RegisterCallback(model.POST_UPDATE, agent.portUpdated)
150 } else {
151 log.Errorw("logical-device-proxy-null", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
152 return status.Error(codes.Internal, "logical-device-proxy-null")
153 }
khenaidoobcf205b2019-01-25 22:21:14 -0500154
khenaidoob9203542018-09-17 22:56:37 -0400155 return nil
156}
157
khenaidoo4d4802d2018-10-04 21:59:49 -0400158// stop stops the logical devuce agent. This removes the logical device from the data model.
159func (agent *LogicalDeviceAgent) stop(ctx context.Context) {
160 log.Info("stopping-logical_device-agent")
161 agent.lockLogicalDevice.Lock()
162 defer agent.lockLogicalDevice.Unlock()
khenaidoo8c3303d2019-02-13 14:59:39 -0500163
khenaidoo4d4802d2018-10-04 21:59:49 -0400164 //Remove the logical device from the model
165 if removed := agent.clusterDataProxy.Remove("/logical_devices/"+agent.logicalDeviceId, ""); removed == nil {
166 log.Errorw("failed-to-remove-logical-device", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
167 } else {
168 log.Debugw("logicaldevice-removed", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
169 }
170 agent.exitChannel <- 1
171 log.Info("logical_device-agent-stopped")
172}
173
khenaidoo19d7b632018-10-30 10:49:50 -0400174// GetLogicalDevice locks the logical device model and then retrieves the latest logical device information
175func (agent *LogicalDeviceAgent) GetLogicalDevice() (*voltha.LogicalDevice, error) {
176 log.Debug("GetLogicalDevice")
khenaidoo1ce37ad2019-03-24 22:07:24 -0400177 agent.lockLogicalDevice.RLock()
178 defer agent.lockLogicalDevice.RUnlock()
khenaidoo8c3303d2019-02-13 14:59:39 -0500179 logicalDevice := agent.clusterDataProxy.Get("/logical_devices/"+agent.logicalDeviceId, 0, false, "")
khenaidoo92e62c52018-10-03 14:02:54 -0400180 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500181 return lDevice, nil
khenaidoo92e62c52018-10-03 14:02:54 -0400182 }
183 return nil, status.Errorf(codes.NotFound, "logical_device-%s", agent.logicalDeviceId)
184}
185
khenaidoodd237172019-05-27 16:37:17 -0400186func (agent *LogicalDeviceAgent) ListLogicalDeviceFlows() (*ofp.Flows, error) {
187 log.Debug("ListLogicalDeviceFlows")
188 agent.lockLogicalDevice.RLock()
189 defer agent.lockLogicalDevice.RUnlock()
190 logicalDevice := agent.clusterDataProxy.Get("/logical_devices/"+agent.logicalDeviceId, 0, false, "")
191 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
192 cFlows := (proto.Clone(lDevice.Flows)).(*ofp.Flows)
193 return cFlows, nil
194 }
195 return nil, status.Errorf(codes.NotFound, "logical_device-%s", agent.logicalDeviceId)
196}
197
198func (agent *LogicalDeviceAgent) ListLogicalDeviceFlowGroups() (*ofp.FlowGroups, error) {
199 log.Debug("ListLogicalDeviceFlowGroups")
200 agent.lockLogicalDevice.RLock()
201 defer agent.lockLogicalDevice.RUnlock()
202 logicalDevice := agent.clusterDataProxy.Get("/logical_devices/"+agent.logicalDeviceId, 0, false, "")
203 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
204 cFlowGroups := (proto.Clone(lDevice.FlowGroups)).(*ofp.FlowGroups)
205 return cFlowGroups, nil
206 }
207 return nil, status.Errorf(codes.NotFound, "logical_device-%s", agent.logicalDeviceId)
208}
209
khenaidoo19d7b632018-10-30 10:49:50 -0400210func (agent *LogicalDeviceAgent) ListLogicalDevicePorts() (*voltha.LogicalPorts, error) {
khenaidoo1ce37ad2019-03-24 22:07:24 -0400211 log.Debug("ListLogicalDevicePorts")
212 agent.lockLogicalDevice.RLock()
213 defer agent.lockLogicalDevice.RUnlock()
khenaidoo8c3303d2019-02-13 14:59:39 -0500214 logicalDevice := agent.clusterDataProxy.Get("/logical_devices/"+agent.logicalDeviceId, 0, false, "")
khenaidoo19d7b632018-10-30 10:49:50 -0400215 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
216 lPorts := make([]*voltha.LogicalPort, 0)
217 for _, port := range lDevice.Ports {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500218 lPorts = append(lPorts, port)
khenaidoo19d7b632018-10-30 10:49:50 -0400219 }
220 return &voltha.LogicalPorts{Items: lPorts}, nil
221 }
222 return nil, status.Errorf(codes.NotFound, "logical_device-%s", agent.logicalDeviceId)
223}
224
225// listFlows locks the logical device model and then retrieves the latest flow information
226func (agent *LogicalDeviceAgent) listFlows() []*ofp.OfpFlowStats {
227 log.Debug("listFlows")
khenaidoo1ce37ad2019-03-24 22:07:24 -0400228 agent.lockLogicalDevice.RLock()
229 defer agent.lockLogicalDevice.RUnlock()
khenaidoo8c3303d2019-02-13 14:59:39 -0500230 logicalDevice := agent.clusterDataProxy.Get("/logical_devices/"+agent.logicalDeviceId, 0, false, "")
khenaidoo19d7b632018-10-30 10:49:50 -0400231 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
232 return lDevice.Flows.Items
233 }
234 return nil
235}
236
237// listFlowGroups locks the logical device model and then retrieves the latest flow groups information
238func (agent *LogicalDeviceAgent) listFlowGroups() []*ofp.OfpGroupEntry {
239 log.Debug("listFlowGroups")
khenaidoo1ce37ad2019-03-24 22:07:24 -0400240 agent.lockLogicalDevice.RLock()
241 defer agent.lockLogicalDevice.RUnlock()
khenaidoo8c3303d2019-02-13 14:59:39 -0500242 logicalDevice := agent.clusterDataProxy.Get("/logical_devices/"+agent.logicalDeviceId, 0, false, "")
khenaidoo19d7b632018-10-30 10:49:50 -0400243 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
244 return lDevice.FlowGroups.Items
245 }
246 return nil
247}
248
khenaidoo43c82122018-11-22 18:38:28 -0500249//updateLogicalDeviceWithoutLock updates the model with the logical device. It clones the logicaldevice before saving it
250func (agent *LogicalDeviceAgent) updateLogicalDeviceFlowsWithoutLock(flows *ofp.Flows) error {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500251 afterUpdate := agent.flowProxy.Update("/", flows, false, "")
khenaidoo43c82122018-11-22 18:38:28 -0500252 if afterUpdate == nil {
253 return status.Errorf(codes.Internal, "failed-updating-logical-device-flows:%s", agent.logicalDeviceId)
254 }
khenaidoo43c82122018-11-22 18:38:28 -0500255 return nil
256}
257
258//updateLogicalDeviceWithoutLock updates the model with the logical device. It clones the logicaldevice before saving it
259func (agent *LogicalDeviceAgent) updateLogicalDeviceFlowGroupsWithoutLock(flowGroups *ofp.FlowGroups) error {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500260 afterUpdate := agent.groupProxy.Update("/", flowGroups, false, "")
khenaidoo43c82122018-11-22 18:38:28 -0500261 if afterUpdate == nil {
262 return status.Errorf(codes.Internal, "failed-updating-logical-device-flow-groups:%s", agent.logicalDeviceId)
263 }
khenaidoo43c82122018-11-22 18:38:28 -0500264 return nil
265}
266
khenaidoo4d4802d2018-10-04 21:59:49 -0400267// getLogicalDeviceWithoutLock retrieves a logical device from the model without locking it. This is used only by
268// functions that have already acquired the logical device lock to the model
khenaidoo92e62c52018-10-03 14:02:54 -0400269func (agent *LogicalDeviceAgent) getLogicalDeviceWithoutLock() (*voltha.LogicalDevice, error) {
270 log.Debug("getLogicalDeviceWithoutLock")
khenaidoo8c3303d2019-02-13 14:59:39 -0500271 logicalDevice := agent.clusterDataProxy.Get("/logical_devices/"+agent.logicalDeviceId, 0, false, "")
khenaidoo92e62c52018-10-03 14:02:54 -0400272 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
khenaidoo1ce37ad2019-03-24 22:07:24 -0400273 //log.Debug("getLogicalDeviceWithoutLock", log.Fields{"ldevice": lDevice})
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500274 return lDevice, nil
khenaidoo92e62c52018-10-03 14:02:54 -0400275 }
276 return nil, status.Errorf(codes.NotFound, "logical_device-%s", agent.logicalDeviceId)
277}
278
khenaidoo2c6a0992019-04-29 13:46:56 -0400279func (agent *LogicalDeviceAgent) updateLogicalPort(device *voltha.Device, port *voltha.Port) error {
280 log.Debugw("updateLogicalPort", log.Fields{"deviceId": device.Id, "port": port})
281 var err error
282 if port.Type == voltha.Port_ETHERNET_NNI {
283 if _, err = agent.addNNILogicalPort(device, port); err != nil {
284 return err
285 }
286 agent.addLogicalPortToMap(port.PortNo, true)
287 } else if port.Type == voltha.Port_ETHERNET_UNI {
288 if _, err = agent.addUNILogicalPort(device, port); err != nil {
289 return err
290 }
291 agent.addLogicalPortToMap(port.PortNo, false)
292 } else {
293 // Update the device graph to ensure all routes on the logical device have been calculated
294 if err = agent.updateRoutes(device, port); err != nil {
295 log.Errorw("failed-to-update-routes", log.Fields{"deviceId": device.Id, "port": port, "error": err})
296 return err
297 }
298 }
299 return nil
300}
301
khenaidoo910204f2019-04-08 17:56:40 -0400302func (agent *LogicalDeviceAgent) addLogicalPort(device *voltha.Device, port *voltha.Port) error {
khenaidoo8f474192019-04-03 17:20:44 -0400303 log.Debugw("addLogicalPort", log.Fields{"deviceId": device.Id, "port": port})
khenaidoo8f474192019-04-03 17:20:44 -0400304 var err error
khenaidoofc1314d2019-03-14 09:34:21 -0400305 if port.Type == voltha.Port_ETHERNET_NNI {
khenaidoo910204f2019-04-08 17:56:40 -0400306 if _, err = agent.addNNILogicalPort(device, port); err != nil {
khenaidoofc1314d2019-03-14 09:34:21 -0400307 return err
308 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400309 agent.addLogicalPortToMap(port.PortNo, true)
khenaidoofc1314d2019-03-14 09:34:21 -0400310 } else if port.Type == voltha.Port_ETHERNET_UNI {
khenaidoo910204f2019-04-08 17:56:40 -0400311 if _, err = agent.addUNILogicalPort(device, port); err != nil {
khenaidoofc1314d2019-03-14 09:34:21 -0400312 return err
313 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400314 agent.addLogicalPortToMap(port.PortNo, false)
khenaidoofc1314d2019-03-14 09:34:21 -0400315 } else {
316 log.Debugw("invalid-port-type", log.Fields{"deviceId": device.Id, "port": port})
317 return nil
318 }
khenaidoofc1314d2019-03-14 09:34:21 -0400319 return nil
320}
321
khenaidoo3d3b8c22019-05-22 18:10:39 -0400322// setupLogicalPorts is invoked once the logical device has been created and is ready to get ports
323// added to it. While the logical device was being created we could have received requests to add
324// NNI and UNI ports which were discarded. Now is the time to add them if needed
325func (agent *LogicalDeviceAgent) setupLogicalPorts(ctx context.Context) error {
326 log.Infow("setupLogicalPorts", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
327 // First add any NNI ports which could have been missing
328 if err := agent.setupNNILogicalPorts(nil, agent.rootDeviceId); err != nil {
329 log.Errorw("error-setting-up-NNI-ports", log.Fields{"error": err, "deviceId": agent.rootDeviceId})
330 return err
331 }
332
333 // Now, set up the UNI ports if needed.
334 if children, err := agent.deviceMgr.getAllChildDevices(agent.rootDeviceId); err != nil {
335 log.Errorw("error-getting-child-devices", log.Fields{"error": err, "deviceId": agent.rootDeviceId})
336 return err
337 } else {
338 chnlsList := make([]chan interface{}, 0)
339 for _, child := range children.Items {
340 ch := make(chan interface{})
341 chnlsList = append(chnlsList, ch)
342 go func(device *voltha.Device, ch chan interface{}) {
343 if err = agent.setupUNILogicalPorts(nil, device); err != nil {
344 log.Error("setting-up-UNI-ports-failed", log.Fields{"deviceID": device.Id})
345 ch <- status.Errorf(codes.Internal, "UNI-ports-setup-failed: %s", device.Id)
346 }
347 ch <- nil
348 }(child, ch)
349 }
350 // Wait for completion
351 if res := fu.WaitForNilOrErrorResponses(agent.defaultTimeout, chnlsList...); res != nil {
352 return status.Errorf(codes.Aborted, "errors-%s", res)
353 }
354 }
355 return nil
356}
357
khenaidoofc1314d2019-03-14 09:34:21 -0400358// setupNNILogicalPorts creates an NNI port on the logical device that represents an NNI interface on a root device
359func (agent *LogicalDeviceAgent) setupNNILogicalPorts(ctx context.Context, deviceId string) error {
360 log.Infow("setupNNILogicalPorts-start", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoob9203542018-09-17 22:56:37 -0400361 // Build the logical device based on information retrieved from the device adapter
khenaidoofc1314d2019-03-14 09:34:21 -0400362 var err error
363
364 var device *voltha.Device
365 if device, err = agent.deviceMgr.GetDevice(deviceId); err != nil {
khenaidoo2c6a0992019-04-29 13:46:56 -0400366 log.Errorw("error-retrieving-device", log.Fields{"error": err, "deviceId": deviceId})
khenaidoofc1314d2019-03-14 09:34:21 -0400367 return err
368 }
369
370 //Get UNI port number
khenaidoofc1314d2019-03-14 09:34:21 -0400371 for _, port := range device.Ports {
372 if port.Type == voltha.Port_ETHERNET_NNI {
khenaidoo910204f2019-04-08 17:56:40 -0400373 if _, err = agent.addNNILogicalPort(device, port); err != nil {
khenaidoofc1314d2019-03-14 09:34:21 -0400374 log.Errorw("error-adding-UNI-port", log.Fields{"error": err})
khenaidoofc1314d2019-03-14 09:34:21 -0400375 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400376 agent.addLogicalPortToMap(port.PortNo, true)
khenaidoofc1314d2019-03-14 09:34:21 -0400377 }
378 }
khenaidoofc1314d2019-03-14 09:34:21 -0400379 return err
380}
381
khenaidoo3ab34882019-05-02 21:33:30 -0400382// updatePortsState updates the ports state related to the device
383func (agent *LogicalDeviceAgent) updatePortsState(device *voltha.Device, state voltha.AdminState_AdminState) error {
384 log.Infow("updatePortsState-start", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
385 agent.lockLogicalDevice.Lock()
386 defer agent.lockLogicalDevice.Unlock()
387 // Get the latest logical device info
388 if ld, err := agent.getLogicalDeviceWithoutLock(); err != nil {
389 log.Warnw("logical-device-unknown", log.Fields{"ldeviceId": agent.logicalDeviceId, "error": err})
390 return err
391 } else {
392 cloned := (proto.Clone(ld)).(*voltha.LogicalDevice)
393 for _, lport := range cloned.Ports {
394 if lport.DeviceId == device.Id {
395 switch state {
396 case voltha.AdminState_ENABLED:
397 lport.OfpPort.Config = lport.OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
khenaidoo0a822f92019-05-08 15:15:57 -0400398 lport.OfpPort.State = uint32(ofp.OfpPortState_OFPPS_LIVE)
khenaidoo3ab34882019-05-02 21:33:30 -0400399 case voltha.AdminState_DISABLED:
400 lport.OfpPort.Config = lport.OfpPort.Config | uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
khenaidoo0a822f92019-05-08 15:15:57 -0400401 lport.OfpPort.State = uint32(ofp.OfpPortState_OFPPS_LINK_DOWN)
khenaidoo3ab34882019-05-02 21:33:30 -0400402 default:
403 log.Warnw("unsupported-state-change", log.Fields{"deviceId": device.Id, "state": state})
404 }
405 }
406 }
407 // Updating the logical device will trigger the poprt change events to be populated to the controller
408 if err := agent.updateLogicalDeviceWithoutLock(cloned); err != nil {
409 log.Warnw("logical-device-update-failed", log.Fields{"ldeviceId": agent.logicalDeviceId, "error": err})
410 return err
411 }
412 }
413 return nil
414}
415
khenaidoofc1314d2019-03-14 09:34:21 -0400416// setupUNILogicalPorts creates a UNI port on the logical device that represents a child UNI interface
417func (agent *LogicalDeviceAgent) setupUNILogicalPorts(ctx context.Context, childDevice *voltha.Device) error {
khenaidoo3d3b8c22019-05-22 18:10:39 -0400418 log.Infow("setupUNILogicalPort", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoofc1314d2019-03-14 09:34:21 -0400419 // Build the logical device based on information retrieved from the device adapter
khenaidoob9203542018-09-17 22:56:37 -0400420 var err error
khenaidoo19d7b632018-10-30 10:49:50 -0400421
422 //Get UNI port number
khenaidoo19d7b632018-10-30 10:49:50 -0400423 for _, port := range childDevice.Ports {
424 if port.Type == voltha.Port_ETHERNET_UNI {
khenaidoo910204f2019-04-08 17:56:40 -0400425 if _, err = agent.addUNILogicalPort(childDevice, port); err != nil {
khenaidoofc1314d2019-03-14 09:34:21 -0400426 log.Errorw("error-adding-UNI-port", log.Fields{"error": err})
khenaidoofc1314d2019-03-14 09:34:21 -0400427 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400428 agent.addLogicalPortToMap(port.PortNo, false)
khenaidoo19d7b632018-10-30 10:49:50 -0400429 }
430 }
khenaidoofc1314d2019-03-14 09:34:21 -0400431 return err
khenaidoo92e62c52018-10-03 14:02:54 -0400432}
433
khenaidoo0a822f92019-05-08 15:15:57 -0400434// deleteAllLogicalPorts deletes all logical ports associated with this device
435func (agent *LogicalDeviceAgent) deleteAllLogicalPorts(device *voltha.Device) error {
436 log.Infow("updatePortsState-start", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
437 agent.lockLogicalDevice.Lock()
438 defer agent.lockLogicalDevice.Unlock()
439 // Get the latest logical device info
440 if ld, err := agent.getLogicalDeviceWithoutLock(); err != nil {
441 log.Warnw("logical-device-unknown", log.Fields{"ldeviceId": agent.logicalDeviceId, "error": err})
442 return err
443 } else {
444 cloned := (proto.Clone(ld)).(*voltha.LogicalDevice)
445 updateLogicalPorts := []*voltha.LogicalPort{}
446 for _, lport := range cloned.Ports {
447 if lport.DeviceId != device.Id {
448 updateLogicalPorts = append(updateLogicalPorts, lport)
449 }
450 }
451 if len(updateLogicalPorts) < len(cloned.Ports) {
452 cloned.Ports = updateLogicalPorts
453 // Updating the logical device will trigger the poprt change events to be populated to the controller
454 if err := agent.updateLogicalDeviceWithoutLock(cloned); err != nil {
455 log.Warnw("logical-device-update-failed", log.Fields{"ldeviceId": agent.logicalDeviceId, "error": err})
456 return err
457 }
458 } else {
459 log.Debugw("no-change-required", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
460 }
461 }
462 return nil
463}
464
khenaidoo92e62c52018-10-03 14:02:54 -0400465//updateLogicalDeviceWithoutLock updates the model with the logical device. It clones the logicaldevice before saving it
466func (agent *LogicalDeviceAgent) updateLogicalDeviceWithoutLock(logicalDevice *voltha.LogicalDevice) error {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500467 afterUpdate := agent.clusterDataProxy.Update("/logical_devices/"+agent.logicalDeviceId, logicalDevice, false, "")
khenaidoo92e62c52018-10-03 14:02:54 -0400468 if afterUpdate == nil {
469 return status.Errorf(codes.Internal, "failed-updating-logical-device:%s", agent.logicalDeviceId)
470 }
471 return nil
472}
473
khenaidoo19d7b632018-10-30 10:49:50 -0400474//updateFlowTable updates the flow table of that logical device
475func (agent *LogicalDeviceAgent) updateFlowTable(ctx context.Context, flow *ofp.OfpFlowMod) error {
476 log.Debug("updateFlowTable")
477 if flow == nil {
478 return nil
479 }
480 switch flow.GetCommand() {
481 case ofp.OfpFlowModCommand_OFPFC_ADD:
482 return agent.flowAdd(flow)
483 case ofp.OfpFlowModCommand_OFPFC_DELETE:
484 return agent.flowDelete(flow)
485 case ofp.OfpFlowModCommand_OFPFC_DELETE_STRICT:
486 return agent.flowDeleteStrict(flow)
487 case ofp.OfpFlowModCommand_OFPFC_MODIFY:
488 return agent.flowModify(flow)
489 case ofp.OfpFlowModCommand_OFPFC_MODIFY_STRICT:
490 return agent.flowModifyStrict(flow)
491 }
492 return status.Errorf(codes.Internal,
493 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceId, flow.GetCommand())
494}
495
496//updateGroupTable updates the group table of that logical device
497func (agent *LogicalDeviceAgent) updateGroupTable(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
498 log.Debug("updateGroupTable")
499 if groupMod == nil {
500 return nil
501 }
502 switch groupMod.GetCommand() {
503 case ofp.OfpGroupModCommand_OFPGC_ADD:
504 return agent.groupAdd(groupMod)
505 case ofp.OfpGroupModCommand_OFPGC_DELETE:
506 return agent.groupDelete(groupMod)
507 case ofp.OfpGroupModCommand_OFPGC_MODIFY:
508 return agent.groupModify(groupMod)
509 }
510 return status.Errorf(codes.Internal,
511 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceId, groupMod.GetCommand())
512}
513
khenaidoo19d7b632018-10-30 10:49:50 -0400514//flowAdd adds a flow to the flow table of that logical device
515func (agent *LogicalDeviceAgent) flowAdd(mod *ofp.OfpFlowMod) error {
516 log.Debug("flowAdd")
517 if mod == nil {
518 return nil
519 }
khenaidoo92e62c52018-10-03 14:02:54 -0400520 agent.lockLogicalDevice.Lock()
521 defer agent.lockLogicalDevice.Unlock()
khenaidoo19d7b632018-10-30 10:49:50 -0400522
523 var lDevice *voltha.LogicalDevice
524 var err error
525 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
526 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
527 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
528 }
529
530 var flows []*ofp.OfpFlowStats
531 if lDevice.Flows != nil && lDevice.Flows.Items != nil {
532 flows = lDevice.Flows.Items
533 }
534
khenaidoo2c6a0992019-04-29 13:46:56 -0400535 updatedFlows := make([]*ofp.OfpFlowStats, 0)
khenaidoo19d7b632018-10-30 10:49:50 -0400536 changed := false
537 checkOverlap := (mod.Flags & uint32(ofp.OfpFlowModFlags_OFPFF_CHECK_OVERLAP)) != 0
538 if checkOverlap {
539 if overlapped := fu.FindOverlappingFlows(flows, mod); len(overlapped) != 0 {
540 // TODO: should this error be notified other than being logged?
541 log.Warnw("overlapped-flows", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
542 } else {
543 // Add flow
khenaidoo68c930b2019-05-13 11:46:51 -0400544 flow := fu.FlowStatsEntryFromFlowModMessage(mod)
khenaidoo19d7b632018-10-30 10:49:50 -0400545 flows = append(flows, flow)
khenaidoo2c6a0992019-04-29 13:46:56 -0400546 updatedFlows = append(updatedFlows, flow)
khenaidoo19d7b632018-10-30 10:49:50 -0400547 changed = true
548 }
549 } else {
khenaidoo68c930b2019-05-13 11:46:51 -0400550 flow := fu.FlowStatsEntryFromFlowModMessage(mod)
khenaidoo19d7b632018-10-30 10:49:50 -0400551 idx := fu.FindFlows(flows, flow)
552 if idx >= 0 {
553 oldFlow := flows[idx]
554 if (mod.Flags & uint32(ofp.OfpFlowModFlags_OFPFF_RESET_COUNTS)) != 0 {
555 flow.ByteCount = oldFlow.ByteCount
556 flow.PacketCount = oldFlow.PacketCount
557 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400558 if !reflect.DeepEqual(oldFlow, flow) {
559 flows[idx] = flow
560 updatedFlows = append(updatedFlows, flow)
561 changed = true
562 }
khenaidoo19d7b632018-10-30 10:49:50 -0400563 } else {
564 flows = append(flows, flow)
khenaidoo2c6a0992019-04-29 13:46:56 -0400565 updatedFlows = append(updatedFlows, flow)
566 changed = true
khenaidoo19d7b632018-10-30 10:49:50 -0400567 }
khenaidoo19d7b632018-10-30 10:49:50 -0400568 }
569 if changed {
khenaidoo0458db62019-06-20 08:50:36 -0400570 deviceRules := agent.flowDecomposer.DecomposeRules(agent, ofp.Flows{Items: updatedFlows}, *lDevice.FlowGroups)
571 log.Debugw("rules", log.Fields{"rules": deviceRules.String()})
572
573 if err := agent.addDeviceFlowsAndGroups(deviceRules); err != nil {
574 log.Errorw("failure-updating-device-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "error": err})
khenaidoo2c6a0992019-04-29 13:46:56 -0400575 return err
576 }
577
khenaidoo19d7b632018-10-30 10:49:50 -0400578 // Update model
khenaidoo0458db62019-06-20 08:50:36 -0400579 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: flows}); err != nil {
khenaidoo2c6a0992019-04-29 13:46:56 -0400580 log.Errorw("db-flow-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400581 return err
582 }
583 }
khenaidoo19d7b632018-10-30 10:49:50 -0400584 return nil
585}
586
587//flowDelete deletes a flow from the flow table of that logical device
588func (agent *LogicalDeviceAgent) flowDelete(mod *ofp.OfpFlowMod) error {
589 log.Debug("flowDelete")
590 if mod == nil {
591 return nil
592 }
593 agent.lockLogicalDevice.Lock()
594 defer agent.lockLogicalDevice.Unlock()
595
596 var lDevice *voltha.LogicalDevice
597 var err error
598 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
599 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
600 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
601 }
602 flows := lDevice.Flows.Items
603
604 //build a list of what to keep vs what to delete
605 toKeep := make([]*ofp.OfpFlowStats, 0)
khenaidoo0458db62019-06-20 08:50:36 -0400606 toDelete := make([]*ofp.OfpFlowStats, 0)
khenaidoo19d7b632018-10-30 10:49:50 -0400607 for _, f := range flows {
khenaidoo0458db62019-06-20 08:50:36 -0400608 // Check whether the flow and the flowmod matches
609 if fu.FlowMatch(f, fu.FlowStatsEntryFromFlowModMessage(mod)) {
610 toDelete = append(toDelete, f)
611 continue
612 }
613 // Check wild card match
khenaidoo19d7b632018-10-30 10:49:50 -0400614 if !fu.FlowMatchesMod(f, mod) {
615 toKeep = append(toKeep, f)
khenaidoo0458db62019-06-20 08:50:36 -0400616 } else {
617 toDelete = append(toDelete, f)
khenaidoo19d7b632018-10-30 10:49:50 -0400618 }
619 }
620
khenaidoo0458db62019-06-20 08:50:36 -0400621 log.Debugw("flowDelete", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "toKeep": len(toKeep), "toDelete": toDelete})
622
khenaidoo19d7b632018-10-30 10:49:50 -0400623 //Update flows
khenaidoo0458db62019-06-20 08:50:36 -0400624 if len(toDelete) > 0 {
625 deviceRules := agent.flowDecomposer.DecomposeRules(agent, ofp.Flows{Items: toDelete}, ofp.FlowGroups{})
626 log.Debugw("rules", log.Fields{"rules": deviceRules.String()})
627
628 if err := agent.deleteDeviceFlowsAndGroups(deviceRules); err != nil {
629 log.Errorw("failure-updating-device-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "error": err})
630 return err
631 }
632
khenaidoo43c82122018-11-22 18:38:28 -0500633 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: toKeep}); err != nil {
634 log.Errorw("Cannot-update-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400635 return err
636 }
637 }
638
639 //TODO: send announcement on delete
640 return nil
641}
642
khenaidoo0458db62019-06-20 08:50:36 -0400643func (agent *LogicalDeviceAgent) addDeviceFlowsAndGroups(deviceRules *fu.DeviceRules) error {
644 log.Debugw("addDeviceFlowsAndGroups", log.Fields{"logicalDeviceID": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400645
khenaidoo0458db62019-06-20 08:50:36 -0400646 chnlsList := make([]chan interface{}, 0)
647 for deviceId, value := range deviceRules.GetRules() {
648 ch := make(chan interface{})
649 chnlsList = append(chnlsList, ch)
650 go func(deviceId string, flows []*ofp.OfpFlowStats, groups []*ofp.OfpGroupEntry) {
651 if err := agent.deviceMgr.addFlowsAndGroups(deviceId, flows, groups); err != nil {
652 log.Errorw("flow-add-failed", log.Fields{"deviceID": deviceId, "error": err})
653 ch <- status.Errorf(codes.Internal, "flow-add-failed: %s", deviceId)
654 }
655 ch <- nil
656 }(deviceId, value.ListFlows(), value.ListGroups())
khenaidoo19d7b632018-10-30 10:49:50 -0400657 }
khenaidoo0458db62019-06-20 08:50:36 -0400658 // Wait for completion
659 if res := fu.WaitForNilOrErrorResponses(agent.defaultTimeout, chnlsList...); res != nil {
660 return status.Errorf(codes.Aborted, "errors-%s", res)
khenaidoo19d7b632018-10-30 10:49:50 -0400661 }
khenaidoo0458db62019-06-20 08:50:36 -0400662 return nil
663}
khenaidoo19d7b632018-10-30 10:49:50 -0400664
khenaidoo0458db62019-06-20 08:50:36 -0400665func (agent *LogicalDeviceAgent) deleteDeviceFlowsAndGroups(deviceRules *fu.DeviceRules) error {
666 log.Debugw("deleteDeviceFlowsAndGroups", log.Fields{"logicalDeviceID": agent.logicalDeviceId})
667
668 chnlsList := make([]chan interface{}, 0)
669 for deviceId, value := range deviceRules.GetRules() {
670 ch := make(chan interface{})
671 chnlsList = append(chnlsList, ch)
672 go func(deviceId string, flows []*ofp.OfpFlowStats, groups []*ofp.OfpGroupEntry) {
673 if err := agent.deviceMgr.deleteFlowsAndGroups(deviceId, flows, groups); err != nil {
674 log.Error("flow-delete-failed", log.Fields{"deviceID": deviceId, "error": err})
675 ch <- status.Errorf(codes.Internal, "flow-delete-failed: %s", deviceId)
676 }
677 ch <- nil
678 }(deviceId, value.ListFlows(), value.ListGroups())
679 }
680 // Wait for completion
681 if res := fu.WaitForNilOrErrorResponses(agent.defaultTimeout, chnlsList...); res != nil {
682 return status.Errorf(codes.Aborted, "errors-%s", res)
683 }
684 return nil
685}
686
687func (agent *LogicalDeviceAgent) updateDeviceFlowsAndGroups(deviceRules *fu.DeviceRules) error {
688 log.Debugw("updateDeviceFlowsAndGroups", log.Fields{"logicalDeviceID": agent.logicalDeviceId})
689
690 chnlsList := make([]chan interface{}, 0)
691 for deviceId, value := range deviceRules.GetRules() {
692 ch := make(chan interface{})
693 chnlsList = append(chnlsList, ch)
694 go func(deviceId string, flows []*ofp.OfpFlowStats, groups []*ofp.OfpGroupEntry) {
695 if err := agent.deviceMgr.updateFlowsAndGroups(deviceId, flows, groups); err != nil {
696 log.Error("flow-update-failed", log.Fields{"deviceID": deviceId, "error": err})
697 ch <- status.Errorf(codes.Internal, "flow-update-failed: %s", deviceId)
698 }
699 ch <- nil
700 }(deviceId, value.ListFlows(), value.ListGroups())
701 }
702 // Wait for completion
703 if res := fu.WaitForNilOrErrorResponses(agent.defaultTimeout, chnlsList...); res != nil {
704 return status.Errorf(codes.Aborted, "errors-%s", res)
khenaidoo19d7b632018-10-30 10:49:50 -0400705 }
706 return nil
707}
708
709//flowDeleteStrict deletes a flow from the flow table of that logical device
710func (agent *LogicalDeviceAgent) flowDeleteStrict(mod *ofp.OfpFlowMod) error {
711 log.Debug("flowDeleteStrict")
712 if mod == nil {
713 return nil
714 }
715 agent.lockLogicalDevice.Lock()
716 defer agent.lockLogicalDevice.Unlock()
717
718 var lDevice *voltha.LogicalDevice
719 var err error
720 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
721 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
722 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
723 }
724 flows := lDevice.Flows.Items
725 changed := false
khenaidoo68c930b2019-05-13 11:46:51 -0400726 flow := fu.FlowStatsEntryFromFlowModMessage(mod)
khenaidoo19d7b632018-10-30 10:49:50 -0400727 idx := fu.FindFlows(flows, flow)
728 if idx >= 0 {
729 flows = append(flows[:idx], flows[idx+1:]...)
730 changed = true
731 } else {
732 return errors.New(fmt.Sprintf("Cannot delete flow - %s", flow))
733 }
734
735 if changed {
khenaidoo0458db62019-06-20 08:50:36 -0400736 deviceRules := agent.flowDecomposer.DecomposeRules(agent, ofp.Flows{Items: []*ofp.OfpFlowStats{flow}}, ofp.FlowGroups{})
737 log.Debugw("rules", log.Fields{"rules": deviceRules.String()})
738
739 if err := agent.deleteDeviceFlowsAndGroups(deviceRules); err != nil {
740 log.Errorw("failure-deleting-device-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "error": err})
741 return err
742 }
743
khenaidoo43c82122018-11-22 18:38:28 -0500744 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: flows}); err != nil {
khenaidoo0458db62019-06-20 08:50:36 -0400745 log.Errorw("Cannot-update-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400746 return err
747 }
748 }
khenaidoo19d7b632018-10-30 10:49:50 -0400749 return nil
750}
751
752//flowModify modifies a flow from the flow table of that logical device
753func (agent *LogicalDeviceAgent) flowModify(mod *ofp.OfpFlowMod) error {
754 return errors.New("flowModify not implemented")
755}
756
757//flowModifyStrict deletes a flow from the flow table of that logical device
758func (agent *LogicalDeviceAgent) flowModifyStrict(mod *ofp.OfpFlowMod) error {
759 return errors.New("flowModifyStrict not implemented")
760}
761
762func (agent *LogicalDeviceAgent) groupAdd(groupMod *ofp.OfpGroupMod) error {
763 log.Debug("groupAdd")
764 if groupMod == nil {
765 return nil
766 }
767 agent.lockLogicalDevice.Lock()
768 defer agent.lockLogicalDevice.Unlock()
769
770 var lDevice *voltha.LogicalDevice
771 var err error
772 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
773 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
774 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
775 }
776 groups := lDevice.FlowGroups.Items
khenaidoo19d7b632018-10-30 10:49:50 -0400777 if fu.FindGroup(groups, groupMod.GroupId) == -1 {
khenaidoo68c930b2019-05-13 11:46:51 -0400778 groups = append(groups, fu.GroupEntryFromGroupMod(groupMod))
khenaidoo0458db62019-06-20 08:50:36 -0400779
780 deviceRules := agent.flowDecomposer.DecomposeRules(agent, *lDevice.Flows, ofp.FlowGroups{Items: groups})
781 log.Debugw("rules", log.Fields{"rules": deviceRules.String()})
782
783 if err := agent.addDeviceFlowsAndGroups(deviceRules); err != nil {
784 log.Errorw("failure-updating-device-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "error": err})
785 return err
786 }
787
khenaidoo43c82122018-11-22 18:38:28 -0500788 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(&ofp.FlowGroups{Items: groups}); err != nil {
789 log.Errorw("Cannot-update-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400790 return err
791 }
792 } else {
793 return errors.New(fmt.Sprintf("Groups %d already present", groupMod.GroupId))
794 }
khenaidoo19d7b632018-10-30 10:49:50 -0400795 return nil
796}
797
798func (agent *LogicalDeviceAgent) groupDelete(groupMod *ofp.OfpGroupMod) error {
799 log.Debug("groupDelete")
800 if groupMod == nil {
801 return nil
802 }
803 agent.lockLogicalDevice.Lock()
804 defer agent.lockLogicalDevice.Unlock()
805
806 var lDevice *voltha.LogicalDevice
807 var err error
808 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
809 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
810 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
811 }
812 groups := lDevice.FlowGroups.Items
813 flows := lDevice.Flows.Items
814 groupsChanged := false
815 flowsChanged := false
816 groupId := groupMod.GroupId
817 if groupId == uint32(ofp.OfpGroup_OFPG_ALL) {
818 //TODO we must delete all flows that point to this group and
819 //signal controller as requested by flow's flag
820 groups = []*ofp.OfpGroupEntry{}
821 groupsChanged = true
822 } else {
823 if idx := fu.FindGroup(groups, groupId); idx == -1 {
824 return nil // Valid case
825 } else {
826 flowsChanged, flows = fu.FlowsDeleteByGroupId(flows, groupId)
827 groups = append(groups[:idx], groups[idx+1:]...)
828 groupsChanged = true
829 }
830 }
khenaidoo0458db62019-06-20 08:50:36 -0400831 if flowsChanged || groupsChanged {
832 deviceRules := agent.flowDecomposer.DecomposeRules(agent, ofp.Flows{Items: flows}, ofp.FlowGroups{Items: groups})
833 log.Debugw("rules", log.Fields{"rules": deviceRules.String()})
834
835 if err := agent.updateDeviceFlowsAndGroups(deviceRules); err != nil {
836 log.Errorw("failure-updating-device-flows-groups", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "error": err})
837 return err
838 }
839 }
840
khenaidoo43c82122018-11-22 18:38:28 -0500841 if groupsChanged {
842 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(&ofp.FlowGroups{Items: groups}); err != nil {
843 log.Errorw("Cannot-update-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400844 return err
845 }
846 }
khenaidoo43c82122018-11-22 18:38:28 -0500847 if flowsChanged {
848 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: flows}); err != nil {
849 log.Errorw("Cannot-update-flow", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
850 return err
851 }
852 }
khenaidoo19d7b632018-10-30 10:49:50 -0400853 return nil
854}
855
856func (agent *LogicalDeviceAgent) groupModify(groupMod *ofp.OfpGroupMod) error {
857 log.Debug("groupModify")
858 if groupMod == nil {
859 return nil
860 }
861 agent.lockLogicalDevice.Lock()
862 defer agent.lockLogicalDevice.Unlock()
863
864 var lDevice *voltha.LogicalDevice
865 var err error
866 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
867 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
868 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
869 }
870 groups := lDevice.FlowGroups.Items
871 groupsChanged := false
872 groupId := groupMod.GroupId
873 if idx := fu.FindGroup(groups, groupId); idx == -1 {
khenaidooca301322019-01-09 23:06:32 -0500874 return errors.New(fmt.Sprintf("group-absent:%d", groupId))
khenaidoo19d7b632018-10-30 10:49:50 -0400875 } else {
876 //replace existing group entry with new group definition
khenaidoo68c930b2019-05-13 11:46:51 -0400877 groupEntry := fu.GroupEntryFromGroupMod(groupMod)
khenaidoo19d7b632018-10-30 10:49:50 -0400878 groups[idx] = groupEntry
879 groupsChanged = true
880 }
881 if groupsChanged {
khenaidoo0458db62019-06-20 08:50:36 -0400882 deviceRules := agent.flowDecomposer.DecomposeRules(agent, ofp.Flows{Items: lDevice.Flows.Items}, ofp.FlowGroups{Items: groups})
883 log.Debugw("rules", log.Fields{"rules": deviceRules.String()})
884
885 if err := agent.updateDeviceFlowsAndGroups(deviceRules); err != nil {
886 log.Errorw("failure-updating-device-flows-groups", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "error": err})
887 return err
888 }
889
khenaidoo43c82122018-11-22 18:38:28 -0500890 //lDevice.FlowGroups.Items = groups
891 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(&ofp.FlowGroups{Items: groups}); err != nil {
khenaidoo19d7b632018-10-30 10:49:50 -0400892 log.Errorw("Cannot-update-logical-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
893 return err
894 }
895 }
896 return nil
897}
898
899// deleteLogicalPort removes the logical port
900func (agent *LogicalDeviceAgent) deleteLogicalPort(lPort *voltha.LogicalPort) error {
901 agent.lockLogicalDevice.Lock()
902 defer agent.lockLogicalDevice.Unlock()
903
khenaidoo92e62c52018-10-03 14:02:54 -0400904 // Get the most up to date logical device
905 var logicaldevice *voltha.LogicalDevice
906 if logicaldevice, _ = agent.getLogicalDeviceWithoutLock(); logicaldevice == nil {
khenaidoo19d7b632018-10-30 10:49:50 -0400907 log.Debugw("no-logical-device", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "logicalPortId": lPort.Id})
khenaidoob9203542018-09-17 22:56:37 -0400908 return nil
909 }
khenaidoo92e62c52018-10-03 14:02:54 -0400910 index := -1
911 for i, logicalPort := range logicaldevice.Ports {
khenaidoo19d7b632018-10-30 10:49:50 -0400912 if logicalPort.Id == lPort.Id {
khenaidoo92e62c52018-10-03 14:02:54 -0400913 index = i
914 break
915 }
916 }
917 if index >= 0 {
918 copy(logicaldevice.Ports[index:], logicaldevice.Ports[index+1:])
919 logicaldevice.Ports[len(logicaldevice.Ports)-1] = nil
920 logicaldevice.Ports = logicaldevice.Ports[:len(logicaldevice.Ports)-1]
921 log.Debugw("logical-port-deleted", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo0a822f92019-05-08 15:15:57 -0400922 if err := agent.updateLogicalDeviceWithoutLock(logicaldevice); err != nil {
923 log.Errorw("logical-device-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
924 return err
925 }
926 // Reset the logical device graph
khenaidoo3d3b8c22019-05-22 18:10:39 -0400927 go agent.generateDeviceGraph()
khenaidoo92e62c52018-10-03 14:02:54 -0400928 }
929 return nil
khenaidoob9203542018-09-17 22:56:37 -0400930}
931
khenaidoo0a822f92019-05-08 15:15:57 -0400932// deleteLogicalPorts removes the logical ports associated with that deviceId
933func (agent *LogicalDeviceAgent) deleteLogicalPorts(deviceId string) error {
934 agent.lockLogicalDevice.Lock()
935 defer agent.lockLogicalDevice.Unlock()
936
937 // Get the most up to date logical device
938 var logicaldevice *voltha.LogicalDevice
939 if logicaldevice, _ = agent.getLogicalDeviceWithoutLock(); logicaldevice == nil {
940 log.Debugw("no-logical-device", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
941 return nil
942 }
943 updatedLPorts := []*voltha.LogicalPort{}
944 for _, logicalPort := range logicaldevice.Ports {
945 if logicalPort.DeviceId != deviceId {
946 updatedLPorts = append(updatedLPorts, logicalPort)
947 }
948 }
949 logicaldevice.Ports = updatedLPorts
950 log.Debugw("updated-logical-ports", log.Fields{"ports": updatedLPorts})
951 if err := agent.updateLogicalDeviceWithoutLock(logicaldevice); err != nil {
952 log.Errorw("logical-device-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
953 return err
954 }
955 // Reset the logical device graph
khenaidoo3d3b8c22019-05-22 18:10:39 -0400956 go agent.generateDeviceGraph()
khenaidoo0a822f92019-05-08 15:15:57 -0400957
958 return nil
959}
960
khenaidoo19d7b632018-10-30 10:49:50 -0400961// enableLogicalPort enables the logical port
962func (agent *LogicalDeviceAgent) enableLogicalPort(lPort *voltha.LogicalPort) error {
963 agent.lockLogicalDevice.Lock()
964 defer agent.lockLogicalDevice.Unlock()
965
966 // Get the most up to date logical device
967 var logicaldevice *voltha.LogicalDevice
968 if logicaldevice, _ = agent.getLogicalDeviceWithoutLock(); logicaldevice == nil {
969 log.Debugw("no-logical-device", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "logicalPortId": lPort.Id})
970 return nil
971 }
972 index := -1
973 for i, logicalPort := range logicaldevice.Ports {
974 if logicalPort.Id == lPort.Id {
975 index = i
976 break
977 }
978 }
979 if index >= 0 {
980 logicaldevice.Ports[index].OfpPort.Config = logicaldevice.Ports[index].OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
981 return agent.updateLogicalDeviceWithoutLock(logicaldevice)
982 }
983 //TODO: Trigger subsequent actions on the device
984 return nil
985}
986
987// disableLogicalPort disabled the logical port
988func (agent *LogicalDeviceAgent) disableLogicalPort(lPort *voltha.LogicalPort) error {
989 agent.lockLogicalDevice.Lock()
990 defer agent.lockLogicalDevice.Unlock()
991
992 // Get the most up to date logical device
993 var logicaldevice *voltha.LogicalDevice
994 if logicaldevice, _ = agent.getLogicalDeviceWithoutLock(); logicaldevice == nil {
995 log.Debugw("no-logical-device", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "logicalPortId": lPort.Id})
996 return nil
997 }
998 index := -1
999 for i, logicalPort := range logicaldevice.Ports {
1000 if logicalPort.Id == lPort.Id {
1001 index = i
1002 break
1003 }
1004 }
1005 if index >= 0 {
1006 logicaldevice.Ports[index].OfpPort.Config = (logicaldevice.Ports[index].OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)) | uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
1007 return agent.updateLogicalDeviceWithoutLock(logicaldevice)
1008 }
1009 //TODO: Trigger subsequent actions on the device
1010 return nil
1011}
1012
khenaidoo89b0e942018-10-21 21:11:33 -04001013func (agent *LogicalDeviceAgent) getPreCalculatedRoute(ingress, egress uint32) []graph.RouteHop {
khenaidoo19d7b632018-10-30 10:49:50 -04001014 log.Debugw("ROUTE", log.Fields{"len": len(agent.deviceGraph.Routes)})
khenaidoo89b0e942018-10-21 21:11:33 -04001015 for routeLink, route := range agent.deviceGraph.Routes {
khenaidoo19d7b632018-10-30 10:49:50 -04001016 log.Debugw("ROUTELINKS", log.Fields{"ingress": ingress, "egress": egress, "routelink": routeLink})
khenaidoo89b0e942018-10-21 21:11:33 -04001017 if ingress == routeLink.Ingress && egress == routeLink.Egress {
1018 return route
1019 }
1020 }
1021 log.Warnw("no-route", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "ingress": ingress, "egress": egress})
1022 return nil
1023}
1024
khenaidoo19d7b632018-10-30 10:49:50 -04001025func (agent *LogicalDeviceAgent) GetRoute(ingressPortNo uint32, egressPortNo uint32) []graph.RouteHop {
khenaidoo89b0e942018-10-21 21:11:33 -04001026 log.Debugw("getting-route", log.Fields{"ingress-port": ingressPortNo, "egress-port": egressPortNo})
khenaidoo89b0e942018-10-21 21:11:33 -04001027 routes := make([]graph.RouteHop, 0)
khenaidoo2c6a0992019-04-29 13:46:56 -04001028
khenaidoo19d7b632018-10-30 10:49:50 -04001029 // Note: A port value of 0 is equivalent to a nil port
1030
khenaidoo89b0e942018-10-21 21:11:33 -04001031 // Consider different possibilities
khenaidoo19d7b632018-10-30 10:49:50 -04001032 if egressPortNo != 0 && ((egressPortNo & 0x7fffffff) == uint32(ofp.OfpPortNo_OFPP_CONTROLLER)) {
khenaidoo2c6a0992019-04-29 13:46:56 -04001033 log.Debugw("controller-flow", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "logicalPortsNo": agent.logicalPortsNo})
1034 if agent.isNNIPort(ingressPortNo) {
khenaidoo89b0e942018-10-21 21:11:33 -04001035 log.Debug("returning-half-route")
1036 //This is a trap on the NNI Port
khenaidoo8f474192019-04-03 17:20:44 -04001037 if len(agent.deviceGraph.Routes) == 0 {
1038 // If there are no routes set (usually when the logical device has only NNI port(s), then just return an
1039 // internal route
khenaidoo2c6a0992019-04-29 13:46:56 -04001040 hop := graph.RouteHop{DeviceID: agent.rootDeviceId, Ingress: ingressPortNo, Egress: egressPortNo}
khenaidoo8f474192019-04-03 17:20:44 -04001041 routes = append(routes, hop)
1042 routes = append(routes, hop)
1043 return routes
1044 }
khenaidoo89b0e942018-10-21 21:11:33 -04001045 //Return a 'half' route to make the flow decomposer logic happy
1046 for routeLink, route := range agent.deviceGraph.Routes {
khenaidoo2c6a0992019-04-29 13:46:56 -04001047 if agent.isNNIPort(routeLink.Egress) {
khenaidoo89b0e942018-10-21 21:11:33 -04001048 routes = append(routes, graph.RouteHop{}) // first hop is set to empty
1049 routes = append(routes, route[1])
1050 return routes
1051 }
1052 }
khenaidoo2c6a0992019-04-29 13:46:56 -04001053 log.Warnw("no-upstream-route", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "logicalPortsNo": agent.logicalPortsNo})
khenaidoo89b0e942018-10-21 21:11:33 -04001054 return nil
1055 }
1056 //treat it as if the output port is the first NNI of the OLT
khenaidoo2c6a0992019-04-29 13:46:56 -04001057 var err error
1058 if egressPortNo, err = agent.getFirstNNIPort(); err != nil {
1059 log.Warnw("no-nni-port", log.Fields{"error": err})
1060 return nil
1061 }
khenaidoo89b0e942018-10-21 21:11:33 -04001062 }
1063 //If ingress port is not specified (nil), it may be a wildcarded
1064 //route if egress port is OFPP_CONTROLLER or a nni logical port,
1065 //in which case we need to create a half-route where only the egress
1066 //hop is filled, the first hop is nil
khenaidoo2c6a0992019-04-29 13:46:56 -04001067 if ingressPortNo == 0 && agent.isNNIPort(egressPortNo) {
khenaidoo89b0e942018-10-21 21:11:33 -04001068 // We can use the 2nd hop of any upstream route, so just find the first upstream:
1069 for routeLink, route := range agent.deviceGraph.Routes {
khenaidoo2c6a0992019-04-29 13:46:56 -04001070 if agent.isNNIPort(routeLink.Egress) {
khenaidoo89b0e942018-10-21 21:11:33 -04001071 routes = append(routes, graph.RouteHop{}) // first hop is set to empty
1072 routes = append(routes, route[1])
1073 return routes
1074 }
1075 }
khenaidoo2c6a0992019-04-29 13:46:56 -04001076 log.Warnw("no-upstream-route", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "logicalPortsNo": agent.logicalPortsNo})
khenaidoo89b0e942018-10-21 21:11:33 -04001077 return nil
1078 }
1079 //If egress port is not specified (nil), we can also can return a "half" route
khenaidoo19d7b632018-10-30 10:49:50 -04001080 if egressPortNo == 0 {
khenaidoo89b0e942018-10-21 21:11:33 -04001081 for routeLink, route := range agent.deviceGraph.Routes {
khenaidoo19d7b632018-10-30 10:49:50 -04001082 if routeLink.Ingress == ingressPortNo {
khenaidoo89b0e942018-10-21 21:11:33 -04001083 routes = append(routes, route[0])
1084 routes = append(routes, graph.RouteHop{})
1085 return routes
1086 }
1087 }
khenaidoo2c6a0992019-04-29 13:46:56 -04001088 log.Warnw("no-downstream-route", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "logicalPortsNo": agent.logicalPortsNo})
khenaidoo89b0e942018-10-21 21:11:33 -04001089 return nil
1090 }
khenaidoo89b0e942018-10-21 21:11:33 -04001091 // Return the pre-calculated route
khenaidoo19d7b632018-10-30 10:49:50 -04001092 return agent.getPreCalculatedRoute(ingressPortNo, egressPortNo)
khenaidoo89b0e942018-10-21 21:11:33 -04001093}
1094
khenaidoo3d3b8c22019-05-22 18:10:39 -04001095//GetWildcardInputPorts filters out the logical port number from the set of logical ports on the device and
1096//returns their port numbers. This function is invoked only during flow decomposition where the lock on the logical
1097//device is already held. Therefore it is safe to retrieve the logical device without lock.
khenaidoo89b0e942018-10-21 21:11:33 -04001098func (agent *LogicalDeviceAgent) GetWildcardInputPorts(excludePort ...uint32) []uint32 {
1099 lPorts := make([]uint32, 0)
1100 var exclPort uint32
1101 if len(excludePort) == 1 {
1102 exclPort = excludePort[0]
1103 }
khenaidoo3d3b8c22019-05-22 18:10:39 -04001104 if lDevice, _ := agent.getLogicalDeviceWithoutLock(); lDevice != nil {
khenaidoo89b0e942018-10-21 21:11:33 -04001105 for _, port := range lDevice.Ports {
1106 if port.OfpPort.PortNo != exclPort {
1107 lPorts = append(lPorts, port.OfpPort.PortNo)
1108 }
1109 }
1110 }
1111 return lPorts
1112}
khenaidoo19d7b632018-10-30 10:49:50 -04001113
1114func (agent *LogicalDeviceAgent) GetDeviceGraph() *graph.DeviceGraph {
1115 return agent.deviceGraph
1116}
1117
khenaidoo3306c992019-05-24 16:57:35 -04001118//updateRoutes rebuilds the device graph if not done already
khenaidoo2c6a0992019-04-29 13:46:56 -04001119func (agent *LogicalDeviceAgent) updateRoutes(device *voltha.Device, port *voltha.Port) error {
1120 log.Debugf("updateRoutes", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "device": device.Id, "port": port})
khenaidoo910204f2019-04-08 17:56:40 -04001121 agent.lockLogicalDevice.Lock()
1122 defer agent.lockLogicalDevice.Unlock()
khenaidoo19d7b632018-10-30 10:49:50 -04001123 if agent.deviceGraph == nil {
khenaidoo910204f2019-04-08 17:56:40 -04001124 agent.deviceGraph = graph.NewDeviceGraph(agent.logicalDeviceId, agent.deviceMgr.GetDevice)
khenaidoo2c6a0992019-04-29 13:46:56 -04001125 }
1126 // Get all the logical ports on that logical device
1127 if lDevice, err := agent.getLogicalDeviceWithoutLock(); err != nil {
manikkaraj k259a6f72019-05-06 09:55:44 -04001128 log.Errorw("unknown-logical-device", log.Fields{"error": err, "logicalDeviceId": agent.logicalDeviceId})
khenaidoo2c6a0992019-04-29 13:46:56 -04001129 return err
1130 } else {
1131 //TODO: Find a better way to refresh only missing routes
1132 agent.deviceGraph.ComputeRoutes(lDevice.Ports)
1133 }
khenaidoo2c6a0992019-04-29 13:46:56 -04001134 agent.deviceGraph.Print()
1135 return nil
khenaidoo19d7b632018-10-30 10:49:50 -04001136}
1137
khenaidoo2c6a0992019-04-29 13:46:56 -04001138//updateDeviceGraph updates the device graph if not done already and setup the default rules as well
khenaidoo910204f2019-04-08 17:56:40 -04001139func (agent *LogicalDeviceAgent) updateDeviceGraph(lp *voltha.LogicalPort) {
khenaidoo2c6a0992019-04-29 13:46:56 -04001140 log.Debugf("updateDeviceGraph", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
1141 agent.lockLogicalDevice.Lock()
1142 defer agent.lockLogicalDevice.Unlock()
khenaidoo910204f2019-04-08 17:56:40 -04001143 if agent.deviceGraph == nil {
1144 agent.deviceGraph = graph.NewDeviceGraph(agent.logicalDeviceId, agent.deviceMgr.GetDevice)
1145 }
1146 agent.deviceGraph.AddPort(lp)
khenaidoo2c6a0992019-04-29 13:46:56 -04001147 agent.deviceGraph.Print()
khenaidoo19d7b632018-10-30 10:49:50 -04001148}
khenaidoofdbad6e2018-11-06 22:26:38 -05001149
khenaidoo3d3b8c22019-05-22 18:10:39 -04001150//generateDeviceGraph regenerates the device graph
1151func (agent *LogicalDeviceAgent) generateDeviceGraph() {
1152 log.Debugf("generateDeviceGraph", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo0a822f92019-05-08 15:15:57 -04001153 agent.lockLogicalDevice.Lock()
1154 defer agent.lockLogicalDevice.Unlock()
1155 // Get the latest logical device
1156 if ld, err := agent.getLogicalDeviceWithoutLock(); err != nil {
1157 log.Errorw("logical-device-not-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "error": err})
1158 } else {
khenaidoo3d3b8c22019-05-22 18:10:39 -04001159 log.Debugw("generating-graph", log.Fields{"lDeviceId": agent.logicalDeviceId, "deviceGraph": agent.deviceGraph, "lPorts": len(ld.Ports)})
1160 if agent.deviceGraph == nil {
1161 agent.deviceGraph = graph.NewDeviceGraph(agent.logicalDeviceId, agent.deviceMgr.GetDevice)
1162 }
khenaidoo0a822f92019-05-08 15:15:57 -04001163 agent.deviceGraph.ComputeRoutes(ld.Ports)
khenaidoo3d3b8c22019-05-22 18:10:39 -04001164 agent.deviceGraph.Print()
khenaidoo0a822f92019-05-08 15:15:57 -04001165 }
1166}
1167
khenaidoofc1314d2019-03-14 09:34:21 -04001168// portAdded is a callback invoked when a port is added to the logical device.
1169// TODO: To use when POST_ADD is fixed.
1170func (agent *LogicalDeviceAgent) portAdded(args ...interface{}) interface{} {
1171 log.Debugw("portAdded-callback", log.Fields{"argsLen": len(args)})
1172
1173 var port *voltha.LogicalPort
1174
1175 // Sanity check
1176 if args[0] != nil {
1177 log.Warnw("previous-data-not-nil", log.Fields{"args0": args[0]})
1178 }
1179 var ok bool
1180 if port, ok = args[1].(*voltha.LogicalPort); !ok {
1181 log.Errorw("invalid-args", log.Fields{"args1": args[1]})
1182 return nil
1183 }
1184
1185 // Set the proxy and callback for that port
1186 agent.portProxiesLock.Lock()
Stephane Barbarie40fd3b22019-04-23 21:50:47 -04001187 agent.portProxies[port.Id] = agent.clusterDataProxy.CreateProxy(
khenaidoofc1314d2019-03-14 09:34:21 -04001188 fmt.Sprintf("/logical_devices/%s/ports/%s", agent.logicalDeviceId, port.Id),
1189 false)
1190 agent.portProxies[port.Id].RegisterCallback(model.POST_UPDATE, agent.portUpdated)
1191 agent.portProxiesLock.Unlock()
1192
1193 // Send the port change event to the OF controller
1194 agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceId,
khenaidoo910204f2019-04-08 17:56:40 -04001195 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_ADD, Desc: port.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001196
1197 return nil
1198}
1199
1200// portRemoved is a callback invoked when a port is removed from the logical device.
1201// TODO: To use when POST_ADD is fixed.
1202func (agent *LogicalDeviceAgent) portRemoved(args ...interface{}) interface{} {
1203 log.Debugw("portRemoved-callback", log.Fields{"argsLen": len(args)})
1204
1205 var port *voltha.LogicalPort
1206
1207 // Sanity check
1208 if args[1] != nil {
1209 log.Warnw("data-not-nil", log.Fields{"args1": args[1]})
1210 }
1211 var ok bool
1212 if port, ok = args[0].(*voltha.LogicalPort); !ok {
1213 log.Errorw("invalid-args", log.Fields{"args0": args[0]})
1214 return nil
1215 }
1216
1217 // Remove the proxy and callback for that port
1218 agent.portProxiesLock.Lock()
1219 agent.portProxies[port.Id].UnregisterCallback(model.POST_UPDATE, agent.portUpdated)
1220 delete(agent.portProxies, port.Id)
1221 agent.portProxiesLock.Unlock()
1222
1223 // Send the port change event to the OF controller
1224 agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceId,
khenaidoo910204f2019-04-08 17:56:40 -04001225 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_DELETE, Desc: port.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001226
1227 return nil
1228}
1229
1230// diff go over two lists of logical ports and return what's new, what's changed and what's removed.
khenaidoo910204f2019-04-08 17:56:40 -04001231func diff(oldList, newList []*voltha.LogicalPort) (newPorts, changedPorts, deletedPorts []*voltha.LogicalPort) {
khenaidoofc1314d2019-03-14 09:34:21 -04001232 newPorts = make([]*voltha.LogicalPort, 0)
1233 changedPorts = make([]*voltha.LogicalPort, 0)
1234 deletedPorts = make([]*voltha.LogicalPort, 0)
1235 for _, o := range oldList {
1236 found := false
1237 changed := false
1238 for _, n := range newList {
1239 if o.Id == n.Id {
1240 changed = !reflect.DeepEqual(o, n)
1241 found = true
1242 break
1243 }
1244 }
1245 if !found {
1246 deletedPorts = append(deletedPorts, o)
1247 }
1248 if changed {
1249 changedPorts = append(changedPorts, o)
1250 }
1251 }
1252 for _, n := range newList {
1253 found := false
1254 for _, o := range oldList {
1255 if o.Id == n.Id {
1256 found = true
1257 break
1258 }
1259 }
1260 if !found {
1261 newPorts = append(newPorts, n)
1262 }
1263 }
1264 return
1265}
1266
1267// portUpdated is invoked when a port is updated on the logical device. Until
1268// the POST_ADD notification is fixed, we will use the logical device to
1269// update that data.
1270func (agent *LogicalDeviceAgent) portUpdated(args ...interface{}) interface{} {
1271 log.Debugw("portUpdated-callback", log.Fields{"argsLen": len(args)})
1272
1273 var oldLD *voltha.LogicalDevice
1274 var newlD *voltha.LogicalDevice
1275
1276 var ok bool
1277 if oldLD, ok = args[0].(*voltha.LogicalDevice); !ok {
1278 log.Errorw("invalid-args", log.Fields{"args0": args[0]})
1279 return nil
1280 }
1281 if newlD, ok = args[1].(*voltha.LogicalDevice); !ok {
1282 log.Errorw("invalid-args", log.Fields{"args1": args[1]})
1283 return nil
1284 }
1285
1286 if reflect.DeepEqual(oldLD.Ports, newlD.Ports) {
1287 log.Debug("ports-have-not-changed")
1288 return nil
1289 }
1290
1291 // Get the difference between the two list
1292 newPorts, changedPorts, deletedPorts := diff(oldLD.Ports, newlD.Ports)
1293
1294 // Send the port change events to the OF controller
khenaidoo2c6a0992019-04-29 13:46:56 -04001295 for _, newP := range newPorts {
khenaidoofc1314d2019-03-14 09:34:21 -04001296 go agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceId,
khenaidoo2c6a0992019-04-29 13:46:56 -04001297 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_ADD, Desc: newP.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001298 }
1299 for _, change := range changedPorts {
1300 go agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceId,
khenaidoo910204f2019-04-08 17:56:40 -04001301 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_MODIFY, Desc: change.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001302 }
1303 for _, del := range deletedPorts {
1304 go agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceId,
khenaidoo910204f2019-04-08 17:56:40 -04001305 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_DELETE, Desc: del.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001306 }
1307
1308 return nil
1309}
1310
khenaidoo8f474192019-04-03 17:20:44 -04001311// addNNILogicalPort adds an NNI port to the logical device. It returns a bool representing whether a port has been
1312// added and an eror in case a valid error is encountered. If the port was successfully added it will return
1313// (true, nil). If the device is not in the correct state it will return (false, nil) as this is a valid
1314// scenario. This also applies to the case where the port was already added.
khenaidoo910204f2019-04-08 17:56:40 -04001315func (agent *LogicalDeviceAgent) addNNILogicalPort(device *voltha.Device, port *voltha.Port) (bool, error) {
khenaidoo1ce37ad2019-03-24 22:07:24 -04001316 log.Debugw("addNNILogicalPort", log.Fields{"NNI": port})
khenaidoo8f474192019-04-03 17:20:44 -04001317 if device.AdminState != voltha.AdminState_ENABLED || device.OperStatus != voltha.OperStatus_ACTIVE {
1318 log.Infow("device-not-ready", log.Fields{"deviceId": device.Id, "admin": device.AdminState, "oper": device.OperStatus})
1319 return false, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001320 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001321 agent.lockLogicalDevice.RLock()
1322 if agent.portExist(device, port) {
1323 log.Debugw("port-already-exist", log.Fields{"port": port})
1324 agent.lockLogicalDevice.RUnlock()
khenaidoo8f474192019-04-03 17:20:44 -04001325 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001326 }
1327 agent.lockLogicalDevice.RUnlock()
1328
khenaidoofc1314d2019-03-14 09:34:21 -04001329 var portCap *ic.PortCapability
1330 var err error
1331 // First get the port capability
1332 if portCap, err = agent.deviceMgr.getPortCapability(nil, device.Id, port.PortNo); err != nil {
1333 log.Errorw("error-retrieving-port-capabilities", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001334 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001335 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001336
1337 agent.lockLogicalDevice.Lock()
1338 defer agent.lockLogicalDevice.Unlock()
1339 // Double check again if this port has been already added since the getPortCapability could have taken a long time
1340 if agent.portExist(device, port) {
1341 log.Debugw("port-already-exist", log.Fields{"port": port})
khenaidoo8f474192019-04-03 17:20:44 -04001342 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001343 }
1344
khenaidoofc1314d2019-03-14 09:34:21 -04001345 portCap.Port.RootPort = true
1346 lp := (proto.Clone(portCap.Port)).(*voltha.LogicalPort)
1347 lp.DeviceId = device.Id
1348 lp.Id = fmt.Sprintf("nni-%d", port.PortNo)
1349 lp.OfpPort.PortNo = port.PortNo
1350 lp.OfpPort.Name = lp.Id
1351 lp.DevicePortNo = port.PortNo
1352
khenaidoofc1314d2019-03-14 09:34:21 -04001353 var ld *voltha.LogicalDevice
1354 if ld, err = agent.getLogicalDeviceWithoutLock(); err != nil {
1355 log.Errorw("error-retrieving-logical-device", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001356 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001357 }
1358 cloned := (proto.Clone(ld)).(*voltha.LogicalDevice)
1359 if cloned.Ports == nil {
1360 cloned.Ports = make([]*voltha.LogicalPort, 0)
1361 }
1362 cloned.Ports = append(cloned.Ports, lp)
1363
1364 if err = agent.updateLogicalDeviceWithoutLock(cloned); err != nil {
1365 log.Errorw("error-updating-logical-device", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001366 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001367 }
khenaidoo910204f2019-04-08 17:56:40 -04001368
1369 // Update the device graph with this new logical port
1370 clonedLP := (proto.Clone(lp)).(*voltha.LogicalPort)
1371 go agent.updateDeviceGraph(clonedLP)
1372
khenaidoo8f474192019-04-03 17:20:44 -04001373 return true, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001374}
1375
khenaidoo910204f2019-04-08 17:56:40 -04001376func (agent *LogicalDeviceAgent) portExist(device *voltha.Device, port *voltha.Port) bool {
khenaidoo54544ae2019-03-18 13:22:39 -04001377 if ldevice, _ := agent.getLogicalDeviceWithoutLock(); ldevice != nil {
khenaidoofc1314d2019-03-14 09:34:21 -04001378 for _, lPort := range ldevice.Ports {
khenaidoo54544ae2019-03-18 13:22:39 -04001379 if lPort.DeviceId == device.Id && lPort.DevicePortNo == port.PortNo && lPort.Id == port.Label {
khenaidoofc1314d2019-03-14 09:34:21 -04001380 return true
1381 }
1382 }
1383 }
1384 return false
1385}
1386
khenaidoo8f474192019-04-03 17:20:44 -04001387// addUNILogicalPort adds an UNI port to the logical device. It returns a bool representing whether a port has been
1388// added and an eror in case a valid error is encountered. If the port was successfully added it will return
1389// (true, nil). If the device is not in the correct state it will return (false, nil) as this is a valid
1390// scenario. This also applies to the case where the port was already added.
khenaidoo910204f2019-04-08 17:56:40 -04001391func (agent *LogicalDeviceAgent) addUNILogicalPort(childDevice *voltha.Device, port *voltha.Port) (bool, error) {
khenaidoofc1314d2019-03-14 09:34:21 -04001392 log.Debugw("addUNILogicalPort", log.Fields{"port": port})
khenaidoo8f474192019-04-03 17:20:44 -04001393 if childDevice.AdminState != voltha.AdminState_ENABLED || childDevice.OperStatus != voltha.OperStatus_ACTIVE {
1394 log.Infow("device-not-ready", log.Fields{"deviceId": childDevice.Id, "admin": childDevice.AdminState, "oper": childDevice.OperStatus})
1395 return false, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001396 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001397 agent.lockLogicalDevice.RLock()
1398 if agent.portExist(childDevice, port) {
1399 log.Debugw("port-already-exist", log.Fields{"port": port})
1400 agent.lockLogicalDevice.RUnlock()
khenaidoo8f474192019-04-03 17:20:44 -04001401 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001402 }
1403 agent.lockLogicalDevice.RUnlock()
khenaidoofc1314d2019-03-14 09:34:21 -04001404 var portCap *ic.PortCapability
1405 var err error
1406 // First get the port capability
1407 if portCap, err = agent.deviceMgr.getPortCapability(nil, childDevice.Id, port.PortNo); err != nil {
1408 log.Errorw("error-retrieving-port-capabilities", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001409 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001410 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001411 agent.lockLogicalDevice.Lock()
1412 defer agent.lockLogicalDevice.Unlock()
1413 // Double check again if this port has been already added since the getPortCapability could have taken a long time
1414 if agent.portExist(childDevice, port) {
1415 log.Debugw("port-already-exist", log.Fields{"port": port})
khenaidoo8f474192019-04-03 17:20:44 -04001416 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001417 }
khenaidoofc1314d2019-03-14 09:34:21 -04001418 // Get stored logical device
1419 if ldevice, err := agent.getLogicalDeviceWithoutLock(); err != nil {
khenaidoo8f474192019-04-03 17:20:44 -04001420 return false, status.Error(codes.NotFound, agent.logicalDeviceId)
khenaidoofc1314d2019-03-14 09:34:21 -04001421 } else {
1422 log.Debugw("adding-uni", log.Fields{"deviceId": childDevice.Id})
1423 portCap.Port.RootPort = false
Matt Jeanneret3815e322019-03-12 19:15:49 -04001424 portCap.Port.Id = port.Label
1425 portCap.Port.OfpPort.PortNo = port.PortNo
khenaidoofc1314d2019-03-14 09:34:21 -04001426 portCap.Port.DeviceId = childDevice.Id
1427 portCap.Port.DevicePortNo = port.PortNo
1428 cloned := (proto.Clone(ldevice)).(*voltha.LogicalDevice)
1429 if cloned.Ports == nil {
1430 cloned.Ports = make([]*voltha.LogicalPort, 0)
1431 }
1432 cloned.Ports = append(cloned.Ports, portCap.Port)
khenaidoo910204f2019-04-08 17:56:40 -04001433 if err := agent.updateLogicalDeviceWithoutLock(cloned); err != nil {
1434 return false, err
1435 }
khenaidoo910204f2019-04-08 17:56:40 -04001436 // Update the device graph with this new logical port
1437 clonedLP := (proto.Clone(portCap.Port)).(*voltha.LogicalPort)
1438 go agent.updateDeviceGraph(clonedLP)
1439 return true, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001440 }
1441}
1442
khenaidoo43c82122018-11-22 18:38:28 -05001443func (agent *LogicalDeviceAgent) packetOut(packet *ofp.OfpPacketOut) {
khenaidoofdbad6e2018-11-06 22:26:38 -05001444 log.Debugw("packet-out", log.Fields{"packet": packet.GetInPort()})
khenaidoo68c930b2019-05-13 11:46:51 -04001445 outPort := fu.GetPacketOutPort(packet)
khenaidoofdbad6e2018-11-06 22:26:38 -05001446 //frame := packet.GetData()
1447 //TODO: Use a channel between the logical agent and the device agent
khenaidooca301322019-01-09 23:06:32 -05001448 if err := agent.deviceMgr.packetOut(agent.rootDeviceId, outPort, packet); err != nil {
khenaidoo910204f2019-04-08 17:56:40 -04001449 log.Error("packetout-failed", log.Fields{"logicalDeviceID": agent.rootDeviceId})
khenaidooca301322019-01-09 23:06:32 -05001450 }
khenaidoofdbad6e2018-11-06 22:26:38 -05001451}
1452
khenaidoo297cd252019-02-07 22:10:23 -05001453func (agent *LogicalDeviceAgent) packetIn(port uint32, transactionId string, packet []byte) {
1454 log.Debugw("packet-in", log.Fields{"port": port, "packet": packet, "transactionId": transactionId})
khenaidoo68c930b2019-05-13 11:46:51 -04001455 packetIn := fu.MkPacketIn(port, packet)
khenaidoo297cd252019-02-07 22:10:23 -05001456 agent.ldeviceMgr.grpcNbiHdlr.sendPacketIn(agent.logicalDeviceId, transactionId, packetIn)
khenaidooca301322019-01-09 23:06:32 -05001457 log.Debugw("sending-packet-in", log.Fields{"packet-in": packetIn})
khenaidoofdbad6e2018-11-06 22:26:38 -05001458}
khenaidoo2c6a0992019-04-29 13:46:56 -04001459
1460func (agent *LogicalDeviceAgent) addLogicalPortToMap(portNo uint32, nniPort bool) {
1461 agent.lockLogicalPortsNo.Lock()
1462 defer agent.lockLogicalPortsNo.Unlock()
1463 if exist := agent.logicalPortsNo[portNo]; !exist {
1464 agent.logicalPortsNo[portNo] = nniPort
1465 }
1466}
1467
khenaidoo3d3b8c22019-05-22 18:10:39 -04001468func (agent *LogicalDeviceAgent) addLogicalPortsToMap(lps []*voltha.LogicalPort) {
1469 agent.lockLogicalPortsNo.Lock()
1470 defer agent.lockLogicalPortsNo.Unlock()
1471 for _, lp := range lps {
1472 if exist := agent.logicalPortsNo[lp.DevicePortNo]; !exist {
1473 agent.logicalPortsNo[lp.DevicePortNo] = lp.RootPort
1474 }
1475 }
1476}
1477
khenaidoo2c6a0992019-04-29 13:46:56 -04001478func (agent *LogicalDeviceAgent) deleteLogicalPortFromMap(portNo uint32) {
1479 agent.lockLogicalPortsNo.Lock()
1480 defer agent.lockLogicalPortsNo.Unlock()
1481 if exist := agent.logicalPortsNo[portNo]; exist {
1482 delete(agent.logicalPortsNo, portNo)
1483 }
1484}
1485
1486func (agent *LogicalDeviceAgent) isNNIPort(portNo uint32) bool {
1487 agent.lockLogicalPortsNo.RLock()
1488 defer agent.lockLogicalPortsNo.RUnlock()
1489 if exist := agent.logicalPortsNo[portNo]; exist {
1490 return agent.logicalPortsNo[portNo]
1491 }
1492 return false
1493}
1494
1495func (agent *LogicalDeviceAgent) getFirstNNIPort() (uint32, error) {
1496 agent.lockLogicalPortsNo.RLock()
1497 defer agent.lockLogicalPortsNo.RUnlock()
1498 for portNo, nni := range agent.logicalPortsNo {
1499 if nni {
1500 return portNo, nil
1501 }
1502 }
1503 return 0, status.Error(codes.NotFound, "No NNI port found")
1504}