blob: 53faec83d298d4ebbc6cf3c29dd054c56952126d [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
khenaidoo59ef7be2019-06-21 12:40:28 -0400421 var added bool
khenaidoo19d7b632018-10-30 10:49:50 -0400422 //Get UNI port number
khenaidoo19d7b632018-10-30 10:49:50 -0400423 for _, port := range childDevice.Ports {
424 if port.Type == voltha.Port_ETHERNET_UNI {
khenaidoo59ef7be2019-06-21 12:40:28 -0400425 if added, 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 }
khenaidoo59ef7be2019-06-21 12:40:28 -0400428 if added {
429 agent.addLogicalPortToMap(port.PortNo, false)
430 }
khenaidoo19d7b632018-10-30 10:49:50 -0400431 }
432 }
khenaidoofc1314d2019-03-14 09:34:21 -0400433 return err
khenaidoo92e62c52018-10-03 14:02:54 -0400434}
435
khenaidoo0a822f92019-05-08 15:15:57 -0400436// deleteAllLogicalPorts deletes all logical ports associated with this device
437func (agent *LogicalDeviceAgent) deleteAllLogicalPorts(device *voltha.Device) error {
438 log.Infow("updatePortsState-start", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
439 agent.lockLogicalDevice.Lock()
440 defer agent.lockLogicalDevice.Unlock()
441 // Get the latest logical device info
442 if ld, err := agent.getLogicalDeviceWithoutLock(); err != nil {
443 log.Warnw("logical-device-unknown", log.Fields{"ldeviceId": agent.logicalDeviceId, "error": err})
444 return err
445 } else {
446 cloned := (proto.Clone(ld)).(*voltha.LogicalDevice)
447 updateLogicalPorts := []*voltha.LogicalPort{}
448 for _, lport := range cloned.Ports {
449 if lport.DeviceId != device.Id {
450 updateLogicalPorts = append(updateLogicalPorts, lport)
451 }
452 }
453 if len(updateLogicalPorts) < len(cloned.Ports) {
454 cloned.Ports = updateLogicalPorts
455 // Updating the logical device will trigger the poprt change events to be populated to the controller
456 if err := agent.updateLogicalDeviceWithoutLock(cloned); err != nil {
457 log.Warnw("logical-device-update-failed", log.Fields{"ldeviceId": agent.logicalDeviceId, "error": err})
458 return err
459 }
460 } else {
461 log.Debugw("no-change-required", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
462 }
463 }
464 return nil
465}
466
khenaidoo92e62c52018-10-03 14:02:54 -0400467//updateLogicalDeviceWithoutLock updates the model with the logical device. It clones the logicaldevice before saving it
468func (agent *LogicalDeviceAgent) updateLogicalDeviceWithoutLock(logicalDevice *voltha.LogicalDevice) error {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500469 afterUpdate := agent.clusterDataProxy.Update("/logical_devices/"+agent.logicalDeviceId, logicalDevice, false, "")
khenaidoo92e62c52018-10-03 14:02:54 -0400470 if afterUpdate == nil {
471 return status.Errorf(codes.Internal, "failed-updating-logical-device:%s", agent.logicalDeviceId)
472 }
473 return nil
474}
475
khenaidoo19d7b632018-10-30 10:49:50 -0400476//updateFlowTable updates the flow table of that logical device
477func (agent *LogicalDeviceAgent) updateFlowTable(ctx context.Context, flow *ofp.OfpFlowMod) error {
478 log.Debug("updateFlowTable")
479 if flow == nil {
480 return nil
481 }
482 switch flow.GetCommand() {
483 case ofp.OfpFlowModCommand_OFPFC_ADD:
484 return agent.flowAdd(flow)
485 case ofp.OfpFlowModCommand_OFPFC_DELETE:
486 return agent.flowDelete(flow)
487 case ofp.OfpFlowModCommand_OFPFC_DELETE_STRICT:
488 return agent.flowDeleteStrict(flow)
489 case ofp.OfpFlowModCommand_OFPFC_MODIFY:
490 return agent.flowModify(flow)
491 case ofp.OfpFlowModCommand_OFPFC_MODIFY_STRICT:
492 return agent.flowModifyStrict(flow)
493 }
494 return status.Errorf(codes.Internal,
495 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceId, flow.GetCommand())
496}
497
498//updateGroupTable updates the group table of that logical device
499func (agent *LogicalDeviceAgent) updateGroupTable(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
500 log.Debug("updateGroupTable")
501 if groupMod == nil {
502 return nil
503 }
504 switch groupMod.GetCommand() {
505 case ofp.OfpGroupModCommand_OFPGC_ADD:
506 return agent.groupAdd(groupMod)
507 case ofp.OfpGroupModCommand_OFPGC_DELETE:
508 return agent.groupDelete(groupMod)
509 case ofp.OfpGroupModCommand_OFPGC_MODIFY:
510 return agent.groupModify(groupMod)
511 }
512 return status.Errorf(codes.Internal,
513 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceId, groupMod.GetCommand())
514}
515
khenaidoo19d7b632018-10-30 10:49:50 -0400516//flowAdd adds a flow to the flow table of that logical device
517func (agent *LogicalDeviceAgent) flowAdd(mod *ofp.OfpFlowMod) error {
518 log.Debug("flowAdd")
519 if mod == nil {
520 return nil
521 }
khenaidoo92e62c52018-10-03 14:02:54 -0400522 agent.lockLogicalDevice.Lock()
523 defer agent.lockLogicalDevice.Unlock()
khenaidoo19d7b632018-10-30 10:49:50 -0400524
525 var lDevice *voltha.LogicalDevice
526 var err error
527 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
528 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
529 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
530 }
531
532 var flows []*ofp.OfpFlowStats
533 if lDevice.Flows != nil && lDevice.Flows.Items != nil {
534 flows = lDevice.Flows.Items
535 }
536
khenaidoo2c6a0992019-04-29 13:46:56 -0400537 updatedFlows := make([]*ofp.OfpFlowStats, 0)
khenaidoo19d7b632018-10-30 10:49:50 -0400538 changed := false
539 checkOverlap := (mod.Flags & uint32(ofp.OfpFlowModFlags_OFPFF_CHECK_OVERLAP)) != 0
540 if checkOverlap {
541 if overlapped := fu.FindOverlappingFlows(flows, mod); len(overlapped) != 0 {
542 // TODO: should this error be notified other than being logged?
543 log.Warnw("overlapped-flows", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
544 } else {
545 // Add flow
khenaidoo68c930b2019-05-13 11:46:51 -0400546 flow := fu.FlowStatsEntryFromFlowModMessage(mod)
khenaidoo19d7b632018-10-30 10:49:50 -0400547 flows = append(flows, flow)
khenaidoo2c6a0992019-04-29 13:46:56 -0400548 updatedFlows = append(updatedFlows, flow)
khenaidoo19d7b632018-10-30 10:49:50 -0400549 changed = true
550 }
551 } else {
khenaidoo68c930b2019-05-13 11:46:51 -0400552 flow := fu.FlowStatsEntryFromFlowModMessage(mod)
khenaidoo19d7b632018-10-30 10:49:50 -0400553 idx := fu.FindFlows(flows, flow)
554 if idx >= 0 {
555 oldFlow := flows[idx]
556 if (mod.Flags & uint32(ofp.OfpFlowModFlags_OFPFF_RESET_COUNTS)) != 0 {
557 flow.ByteCount = oldFlow.ByteCount
558 flow.PacketCount = oldFlow.PacketCount
559 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400560 if !reflect.DeepEqual(oldFlow, flow) {
561 flows[idx] = flow
562 updatedFlows = append(updatedFlows, flow)
563 changed = true
564 }
khenaidoo19d7b632018-10-30 10:49:50 -0400565 } else {
566 flows = append(flows, flow)
khenaidoo2c6a0992019-04-29 13:46:56 -0400567 updatedFlows = append(updatedFlows, flow)
568 changed = true
khenaidoo19d7b632018-10-30 10:49:50 -0400569 }
khenaidoo19d7b632018-10-30 10:49:50 -0400570 }
571 if changed {
khenaidoo0458db62019-06-20 08:50:36 -0400572 deviceRules := agent.flowDecomposer.DecomposeRules(agent, ofp.Flows{Items: updatedFlows}, *lDevice.FlowGroups)
573 log.Debugw("rules", log.Fields{"rules": deviceRules.String()})
574
575 if err := agent.addDeviceFlowsAndGroups(deviceRules); err != nil {
576 log.Errorw("failure-updating-device-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "error": err})
khenaidoo2c6a0992019-04-29 13:46:56 -0400577 return err
578 }
579
khenaidoo19d7b632018-10-30 10:49:50 -0400580 // Update model
khenaidoo0458db62019-06-20 08:50:36 -0400581 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: flows}); err != nil {
khenaidoo2c6a0992019-04-29 13:46:56 -0400582 log.Errorw("db-flow-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400583 return err
584 }
585 }
khenaidoo19d7b632018-10-30 10:49:50 -0400586 return nil
587}
588
589//flowDelete deletes a flow from the flow table of that logical device
590func (agent *LogicalDeviceAgent) flowDelete(mod *ofp.OfpFlowMod) error {
591 log.Debug("flowDelete")
592 if mod == nil {
593 return nil
594 }
595 agent.lockLogicalDevice.Lock()
596 defer agent.lockLogicalDevice.Unlock()
597
598 var lDevice *voltha.LogicalDevice
599 var err error
600 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
601 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
602 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
603 }
604 flows := lDevice.Flows.Items
605
606 //build a list of what to keep vs what to delete
607 toKeep := make([]*ofp.OfpFlowStats, 0)
khenaidoo0458db62019-06-20 08:50:36 -0400608 toDelete := make([]*ofp.OfpFlowStats, 0)
khenaidoo19d7b632018-10-30 10:49:50 -0400609 for _, f := range flows {
khenaidoo0458db62019-06-20 08:50:36 -0400610 // Check whether the flow and the flowmod matches
611 if fu.FlowMatch(f, fu.FlowStatsEntryFromFlowModMessage(mod)) {
612 toDelete = append(toDelete, f)
613 continue
614 }
615 // Check wild card match
khenaidoo19d7b632018-10-30 10:49:50 -0400616 if !fu.FlowMatchesMod(f, mod) {
617 toKeep = append(toKeep, f)
khenaidoo0458db62019-06-20 08:50:36 -0400618 } else {
619 toDelete = append(toDelete, f)
khenaidoo19d7b632018-10-30 10:49:50 -0400620 }
621 }
622
khenaidoo0458db62019-06-20 08:50:36 -0400623 log.Debugw("flowDelete", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "toKeep": len(toKeep), "toDelete": toDelete})
624
khenaidoo19d7b632018-10-30 10:49:50 -0400625 //Update flows
khenaidoo0458db62019-06-20 08:50:36 -0400626 if len(toDelete) > 0 {
627 deviceRules := agent.flowDecomposer.DecomposeRules(agent, ofp.Flows{Items: toDelete}, ofp.FlowGroups{})
628 log.Debugw("rules", log.Fields{"rules": deviceRules.String()})
629
630 if err := agent.deleteDeviceFlowsAndGroups(deviceRules); err != nil {
631 log.Errorw("failure-updating-device-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "error": err})
632 return err
633 }
634
khenaidoo43c82122018-11-22 18:38:28 -0500635 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: toKeep}); err != nil {
636 log.Errorw("Cannot-update-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400637 return err
638 }
639 }
640
641 //TODO: send announcement on delete
642 return nil
643}
644
khenaidoo0458db62019-06-20 08:50:36 -0400645func (agent *LogicalDeviceAgent) addDeviceFlowsAndGroups(deviceRules *fu.DeviceRules) error {
646 log.Debugw("addDeviceFlowsAndGroups", log.Fields{"logicalDeviceID": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400647
khenaidoo0458db62019-06-20 08:50:36 -0400648 chnlsList := make([]chan interface{}, 0)
649 for deviceId, value := range deviceRules.GetRules() {
650 ch := make(chan interface{})
651 chnlsList = append(chnlsList, ch)
652 go func(deviceId string, flows []*ofp.OfpFlowStats, groups []*ofp.OfpGroupEntry) {
653 if err := agent.deviceMgr.addFlowsAndGroups(deviceId, flows, groups); err != nil {
654 log.Errorw("flow-add-failed", log.Fields{"deviceID": deviceId, "error": err})
655 ch <- status.Errorf(codes.Internal, "flow-add-failed: %s", deviceId)
656 }
657 ch <- nil
658 }(deviceId, value.ListFlows(), value.ListGroups())
khenaidoo19d7b632018-10-30 10:49:50 -0400659 }
khenaidoo0458db62019-06-20 08:50:36 -0400660 // Wait for completion
661 if res := fu.WaitForNilOrErrorResponses(agent.defaultTimeout, chnlsList...); res != nil {
662 return status.Errorf(codes.Aborted, "errors-%s", res)
khenaidoo19d7b632018-10-30 10:49:50 -0400663 }
khenaidoo0458db62019-06-20 08:50:36 -0400664 return nil
665}
khenaidoo19d7b632018-10-30 10:49:50 -0400666
khenaidoo0458db62019-06-20 08:50:36 -0400667func (agent *LogicalDeviceAgent) deleteDeviceFlowsAndGroups(deviceRules *fu.DeviceRules) error {
668 log.Debugw("deleteDeviceFlowsAndGroups", log.Fields{"logicalDeviceID": agent.logicalDeviceId})
669
670 chnlsList := make([]chan interface{}, 0)
671 for deviceId, value := range deviceRules.GetRules() {
672 ch := make(chan interface{})
673 chnlsList = append(chnlsList, ch)
674 go func(deviceId string, flows []*ofp.OfpFlowStats, groups []*ofp.OfpGroupEntry) {
675 if err := agent.deviceMgr.deleteFlowsAndGroups(deviceId, flows, groups); err != nil {
676 log.Error("flow-delete-failed", log.Fields{"deviceID": deviceId, "error": err})
677 ch <- status.Errorf(codes.Internal, "flow-delete-failed: %s", deviceId)
678 }
679 ch <- nil
680 }(deviceId, value.ListFlows(), value.ListGroups())
681 }
682 // Wait for completion
683 if res := fu.WaitForNilOrErrorResponses(agent.defaultTimeout, chnlsList...); res != nil {
684 return status.Errorf(codes.Aborted, "errors-%s", res)
685 }
686 return nil
687}
688
689func (agent *LogicalDeviceAgent) updateDeviceFlowsAndGroups(deviceRules *fu.DeviceRules) error {
690 log.Debugw("updateDeviceFlowsAndGroups", log.Fields{"logicalDeviceID": agent.logicalDeviceId})
691
692 chnlsList := make([]chan interface{}, 0)
693 for deviceId, value := range deviceRules.GetRules() {
694 ch := make(chan interface{})
695 chnlsList = append(chnlsList, ch)
696 go func(deviceId string, flows []*ofp.OfpFlowStats, groups []*ofp.OfpGroupEntry) {
697 if err := agent.deviceMgr.updateFlowsAndGroups(deviceId, flows, groups); err != nil {
698 log.Error("flow-update-failed", log.Fields{"deviceID": deviceId, "error": err})
699 ch <- status.Errorf(codes.Internal, "flow-update-failed: %s", deviceId)
700 }
701 ch <- nil
702 }(deviceId, value.ListFlows(), value.ListGroups())
703 }
704 // Wait for completion
705 if res := fu.WaitForNilOrErrorResponses(agent.defaultTimeout, chnlsList...); res != nil {
706 return status.Errorf(codes.Aborted, "errors-%s", res)
khenaidoo19d7b632018-10-30 10:49:50 -0400707 }
708 return nil
709}
710
711//flowDeleteStrict deletes a flow from the flow table of that logical device
712func (agent *LogicalDeviceAgent) flowDeleteStrict(mod *ofp.OfpFlowMod) error {
713 log.Debug("flowDeleteStrict")
714 if mod == nil {
715 return nil
716 }
717 agent.lockLogicalDevice.Lock()
718 defer agent.lockLogicalDevice.Unlock()
719
720 var lDevice *voltha.LogicalDevice
721 var err error
722 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
723 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
724 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
725 }
726 flows := lDevice.Flows.Items
727 changed := false
khenaidoo68c930b2019-05-13 11:46:51 -0400728 flow := fu.FlowStatsEntryFromFlowModMessage(mod)
khenaidoo19d7b632018-10-30 10:49:50 -0400729 idx := fu.FindFlows(flows, flow)
730 if idx >= 0 {
731 flows = append(flows[:idx], flows[idx+1:]...)
732 changed = true
733 } else {
734 return errors.New(fmt.Sprintf("Cannot delete flow - %s", flow))
735 }
736
737 if changed {
khenaidoo0458db62019-06-20 08:50:36 -0400738 deviceRules := agent.flowDecomposer.DecomposeRules(agent, ofp.Flows{Items: []*ofp.OfpFlowStats{flow}}, ofp.FlowGroups{})
739 log.Debugw("rules", log.Fields{"rules": deviceRules.String()})
740
741 if err := agent.deleteDeviceFlowsAndGroups(deviceRules); err != nil {
742 log.Errorw("failure-deleting-device-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "error": err})
743 return err
744 }
745
khenaidoo43c82122018-11-22 18:38:28 -0500746 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: flows}); err != nil {
khenaidoo0458db62019-06-20 08:50:36 -0400747 log.Errorw("Cannot-update-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400748 return err
749 }
750 }
khenaidoo19d7b632018-10-30 10:49:50 -0400751 return nil
752}
753
754//flowModify modifies a flow from the flow table of that logical device
755func (agent *LogicalDeviceAgent) flowModify(mod *ofp.OfpFlowMod) error {
756 return errors.New("flowModify not implemented")
757}
758
759//flowModifyStrict deletes a flow from the flow table of that logical device
760func (agent *LogicalDeviceAgent) flowModifyStrict(mod *ofp.OfpFlowMod) error {
761 return errors.New("flowModifyStrict not implemented")
762}
763
764func (agent *LogicalDeviceAgent) groupAdd(groupMod *ofp.OfpGroupMod) error {
765 log.Debug("groupAdd")
766 if groupMod == nil {
767 return nil
768 }
769 agent.lockLogicalDevice.Lock()
770 defer agent.lockLogicalDevice.Unlock()
771
772 var lDevice *voltha.LogicalDevice
773 var err error
774 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
775 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
776 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
777 }
778 groups := lDevice.FlowGroups.Items
khenaidoo19d7b632018-10-30 10:49:50 -0400779 if fu.FindGroup(groups, groupMod.GroupId) == -1 {
khenaidoo68c930b2019-05-13 11:46:51 -0400780 groups = append(groups, fu.GroupEntryFromGroupMod(groupMod))
khenaidoo0458db62019-06-20 08:50:36 -0400781
782 deviceRules := agent.flowDecomposer.DecomposeRules(agent, *lDevice.Flows, ofp.FlowGroups{Items: groups})
783 log.Debugw("rules", log.Fields{"rules": deviceRules.String()})
784
785 if err := agent.addDeviceFlowsAndGroups(deviceRules); err != nil {
786 log.Errorw("failure-updating-device-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "error": err})
787 return err
788 }
789
khenaidoo43c82122018-11-22 18:38:28 -0500790 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(&ofp.FlowGroups{Items: groups}); err != nil {
791 log.Errorw("Cannot-update-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400792 return err
793 }
794 } else {
795 return errors.New(fmt.Sprintf("Groups %d already present", groupMod.GroupId))
796 }
khenaidoo19d7b632018-10-30 10:49:50 -0400797 return nil
798}
799
800func (agent *LogicalDeviceAgent) groupDelete(groupMod *ofp.OfpGroupMod) error {
801 log.Debug("groupDelete")
802 if groupMod == nil {
803 return nil
804 }
805 agent.lockLogicalDevice.Lock()
806 defer agent.lockLogicalDevice.Unlock()
807
808 var lDevice *voltha.LogicalDevice
809 var err error
810 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
811 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
812 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
813 }
814 groups := lDevice.FlowGroups.Items
815 flows := lDevice.Flows.Items
816 groupsChanged := false
817 flowsChanged := false
818 groupId := groupMod.GroupId
819 if groupId == uint32(ofp.OfpGroup_OFPG_ALL) {
820 //TODO we must delete all flows that point to this group and
821 //signal controller as requested by flow's flag
822 groups = []*ofp.OfpGroupEntry{}
823 groupsChanged = true
824 } else {
825 if idx := fu.FindGroup(groups, groupId); idx == -1 {
826 return nil // Valid case
827 } else {
828 flowsChanged, flows = fu.FlowsDeleteByGroupId(flows, groupId)
829 groups = append(groups[:idx], groups[idx+1:]...)
830 groupsChanged = true
831 }
832 }
khenaidoo0458db62019-06-20 08:50:36 -0400833 if flowsChanged || groupsChanged {
834 deviceRules := agent.flowDecomposer.DecomposeRules(agent, ofp.Flows{Items: flows}, ofp.FlowGroups{Items: groups})
835 log.Debugw("rules", log.Fields{"rules": deviceRules.String()})
836
837 if err := agent.updateDeviceFlowsAndGroups(deviceRules); err != nil {
838 log.Errorw("failure-updating-device-flows-groups", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "error": err})
839 return err
840 }
841 }
842
khenaidoo43c82122018-11-22 18:38:28 -0500843 if groupsChanged {
844 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(&ofp.FlowGroups{Items: groups}); err != nil {
845 log.Errorw("Cannot-update-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400846 return err
847 }
848 }
khenaidoo43c82122018-11-22 18:38:28 -0500849 if flowsChanged {
850 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: flows}); err != nil {
851 log.Errorw("Cannot-update-flow", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
852 return err
853 }
854 }
khenaidoo19d7b632018-10-30 10:49:50 -0400855 return nil
856}
857
858func (agent *LogicalDeviceAgent) groupModify(groupMod *ofp.OfpGroupMod) error {
859 log.Debug("groupModify")
860 if groupMod == nil {
861 return nil
862 }
863 agent.lockLogicalDevice.Lock()
864 defer agent.lockLogicalDevice.Unlock()
865
866 var lDevice *voltha.LogicalDevice
867 var err error
868 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
869 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
870 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
871 }
872 groups := lDevice.FlowGroups.Items
873 groupsChanged := false
874 groupId := groupMod.GroupId
875 if idx := fu.FindGroup(groups, groupId); idx == -1 {
khenaidooca301322019-01-09 23:06:32 -0500876 return errors.New(fmt.Sprintf("group-absent:%d", groupId))
khenaidoo19d7b632018-10-30 10:49:50 -0400877 } else {
878 //replace existing group entry with new group definition
khenaidoo68c930b2019-05-13 11:46:51 -0400879 groupEntry := fu.GroupEntryFromGroupMod(groupMod)
khenaidoo19d7b632018-10-30 10:49:50 -0400880 groups[idx] = groupEntry
881 groupsChanged = true
882 }
883 if groupsChanged {
khenaidoo0458db62019-06-20 08:50:36 -0400884 deviceRules := agent.flowDecomposer.DecomposeRules(agent, ofp.Flows{Items: lDevice.Flows.Items}, ofp.FlowGroups{Items: groups})
885 log.Debugw("rules", log.Fields{"rules": deviceRules.String()})
886
887 if err := agent.updateDeviceFlowsAndGroups(deviceRules); err != nil {
888 log.Errorw("failure-updating-device-flows-groups", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "error": err})
889 return err
890 }
891
khenaidoo43c82122018-11-22 18:38:28 -0500892 //lDevice.FlowGroups.Items = groups
893 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(&ofp.FlowGroups{Items: groups}); err != nil {
khenaidoo19d7b632018-10-30 10:49:50 -0400894 log.Errorw("Cannot-update-logical-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
895 return err
896 }
897 }
898 return nil
899}
900
901// deleteLogicalPort removes the logical port
902func (agent *LogicalDeviceAgent) deleteLogicalPort(lPort *voltha.LogicalPort) error {
903 agent.lockLogicalDevice.Lock()
904 defer agent.lockLogicalDevice.Unlock()
905
khenaidoo92e62c52018-10-03 14:02:54 -0400906 // Get the most up to date logical device
907 var logicaldevice *voltha.LogicalDevice
908 if logicaldevice, _ = agent.getLogicalDeviceWithoutLock(); logicaldevice == nil {
khenaidoo19d7b632018-10-30 10:49:50 -0400909 log.Debugw("no-logical-device", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "logicalPortId": lPort.Id})
khenaidoob9203542018-09-17 22:56:37 -0400910 return nil
911 }
khenaidoo92e62c52018-10-03 14:02:54 -0400912 index := -1
913 for i, logicalPort := range logicaldevice.Ports {
khenaidoo19d7b632018-10-30 10:49:50 -0400914 if logicalPort.Id == lPort.Id {
khenaidoo92e62c52018-10-03 14:02:54 -0400915 index = i
916 break
917 }
918 }
919 if index >= 0 {
920 copy(logicaldevice.Ports[index:], logicaldevice.Ports[index+1:])
921 logicaldevice.Ports[len(logicaldevice.Ports)-1] = nil
922 logicaldevice.Ports = logicaldevice.Ports[:len(logicaldevice.Ports)-1]
923 log.Debugw("logical-port-deleted", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo0a822f92019-05-08 15:15:57 -0400924 if err := agent.updateLogicalDeviceWithoutLock(logicaldevice); err != nil {
925 log.Errorw("logical-device-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
926 return err
927 }
928 // Reset the logical device graph
khenaidoo3d3b8c22019-05-22 18:10:39 -0400929 go agent.generateDeviceGraph()
khenaidoo92e62c52018-10-03 14:02:54 -0400930 }
931 return nil
khenaidoob9203542018-09-17 22:56:37 -0400932}
933
khenaidoo0a822f92019-05-08 15:15:57 -0400934// deleteLogicalPorts removes the logical ports associated with that deviceId
935func (agent *LogicalDeviceAgent) deleteLogicalPorts(deviceId string) error {
936 agent.lockLogicalDevice.Lock()
937 defer agent.lockLogicalDevice.Unlock()
938
939 // Get the most up to date logical device
940 var logicaldevice *voltha.LogicalDevice
941 if logicaldevice, _ = agent.getLogicalDeviceWithoutLock(); logicaldevice == nil {
942 log.Debugw("no-logical-device", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
943 return nil
944 }
945 updatedLPorts := []*voltha.LogicalPort{}
946 for _, logicalPort := range logicaldevice.Ports {
947 if logicalPort.DeviceId != deviceId {
948 updatedLPorts = append(updatedLPorts, logicalPort)
949 }
950 }
951 logicaldevice.Ports = updatedLPorts
952 log.Debugw("updated-logical-ports", log.Fields{"ports": updatedLPorts})
953 if err := agent.updateLogicalDeviceWithoutLock(logicaldevice); err != nil {
954 log.Errorw("logical-device-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
955 return err
956 }
957 // Reset the logical device graph
khenaidoo3d3b8c22019-05-22 18:10:39 -0400958 go agent.generateDeviceGraph()
khenaidoo0a822f92019-05-08 15:15:57 -0400959
960 return nil
961}
962
khenaidoo19d7b632018-10-30 10:49:50 -0400963// enableLogicalPort enables the logical port
964func (agent *LogicalDeviceAgent) enableLogicalPort(lPort *voltha.LogicalPort) error {
965 agent.lockLogicalDevice.Lock()
966 defer agent.lockLogicalDevice.Unlock()
967
968 // Get the most up to date logical device
969 var logicaldevice *voltha.LogicalDevice
970 if logicaldevice, _ = agent.getLogicalDeviceWithoutLock(); logicaldevice == nil {
971 log.Debugw("no-logical-device", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "logicalPortId": lPort.Id})
972 return nil
973 }
974 index := -1
975 for i, logicalPort := range logicaldevice.Ports {
976 if logicalPort.Id == lPort.Id {
977 index = i
978 break
979 }
980 }
981 if index >= 0 {
982 logicaldevice.Ports[index].OfpPort.Config = logicaldevice.Ports[index].OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
983 return agent.updateLogicalDeviceWithoutLock(logicaldevice)
984 }
985 //TODO: Trigger subsequent actions on the device
986 return nil
987}
988
989// disableLogicalPort disabled the logical port
990func (agent *LogicalDeviceAgent) disableLogicalPort(lPort *voltha.LogicalPort) error {
991 agent.lockLogicalDevice.Lock()
992 defer agent.lockLogicalDevice.Unlock()
993
994 // Get the most up to date logical device
995 var logicaldevice *voltha.LogicalDevice
996 if logicaldevice, _ = agent.getLogicalDeviceWithoutLock(); logicaldevice == nil {
997 log.Debugw("no-logical-device", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "logicalPortId": lPort.Id})
998 return nil
999 }
1000 index := -1
1001 for i, logicalPort := range logicaldevice.Ports {
1002 if logicalPort.Id == lPort.Id {
1003 index = i
1004 break
1005 }
1006 }
1007 if index >= 0 {
1008 logicaldevice.Ports[index].OfpPort.Config = (logicaldevice.Ports[index].OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)) | uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
1009 return agent.updateLogicalDeviceWithoutLock(logicaldevice)
1010 }
1011 //TODO: Trigger subsequent actions on the device
1012 return nil
1013}
1014
khenaidoo89b0e942018-10-21 21:11:33 -04001015func (agent *LogicalDeviceAgent) getPreCalculatedRoute(ingress, egress uint32) []graph.RouteHop {
khenaidoo19d7b632018-10-30 10:49:50 -04001016 log.Debugw("ROUTE", log.Fields{"len": len(agent.deviceGraph.Routes)})
khenaidoo89b0e942018-10-21 21:11:33 -04001017 for routeLink, route := range agent.deviceGraph.Routes {
khenaidoo19d7b632018-10-30 10:49:50 -04001018 log.Debugw("ROUTELINKS", log.Fields{"ingress": ingress, "egress": egress, "routelink": routeLink})
khenaidoo89b0e942018-10-21 21:11:33 -04001019 if ingress == routeLink.Ingress && egress == routeLink.Egress {
1020 return route
1021 }
1022 }
1023 log.Warnw("no-route", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "ingress": ingress, "egress": egress})
1024 return nil
1025}
1026
khenaidoo19d7b632018-10-30 10:49:50 -04001027func (agent *LogicalDeviceAgent) GetRoute(ingressPortNo uint32, egressPortNo uint32) []graph.RouteHop {
khenaidoo89b0e942018-10-21 21:11:33 -04001028 log.Debugw("getting-route", log.Fields{"ingress-port": ingressPortNo, "egress-port": egressPortNo})
khenaidoo89b0e942018-10-21 21:11:33 -04001029 routes := make([]graph.RouteHop, 0)
khenaidoo2c6a0992019-04-29 13:46:56 -04001030
khenaidoo19d7b632018-10-30 10:49:50 -04001031 // Note: A port value of 0 is equivalent to a nil port
1032
khenaidoo89b0e942018-10-21 21:11:33 -04001033 // Consider different possibilities
khenaidoo19d7b632018-10-30 10:49:50 -04001034 if egressPortNo != 0 && ((egressPortNo & 0x7fffffff) == uint32(ofp.OfpPortNo_OFPP_CONTROLLER)) {
khenaidoo2c6a0992019-04-29 13:46:56 -04001035 log.Debugw("controller-flow", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "logicalPortsNo": agent.logicalPortsNo})
1036 if agent.isNNIPort(ingressPortNo) {
khenaidoo89b0e942018-10-21 21:11:33 -04001037 log.Debug("returning-half-route")
1038 //This is a trap on the NNI Port
khenaidoo8f474192019-04-03 17:20:44 -04001039 if len(agent.deviceGraph.Routes) == 0 {
1040 // If there are no routes set (usually when the logical device has only NNI port(s), then just return an
1041 // internal route
khenaidoo2c6a0992019-04-29 13:46:56 -04001042 hop := graph.RouteHop{DeviceID: agent.rootDeviceId, Ingress: ingressPortNo, Egress: egressPortNo}
khenaidoo8f474192019-04-03 17:20:44 -04001043 routes = append(routes, hop)
1044 routes = append(routes, hop)
1045 return routes
1046 }
khenaidoo89b0e942018-10-21 21:11:33 -04001047 //Return a 'half' route to make the flow decomposer logic happy
1048 for routeLink, route := range agent.deviceGraph.Routes {
khenaidoo2c6a0992019-04-29 13:46:56 -04001049 if agent.isNNIPort(routeLink.Egress) {
khenaidoo89b0e942018-10-21 21:11:33 -04001050 routes = append(routes, graph.RouteHop{}) // first hop is set to empty
1051 routes = append(routes, route[1])
1052 return routes
1053 }
1054 }
khenaidoo2c6a0992019-04-29 13:46:56 -04001055 log.Warnw("no-upstream-route", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "logicalPortsNo": agent.logicalPortsNo})
khenaidoo89b0e942018-10-21 21:11:33 -04001056 return nil
1057 }
1058 //treat it as if the output port is the first NNI of the OLT
khenaidoo2c6a0992019-04-29 13:46:56 -04001059 var err error
1060 if egressPortNo, err = agent.getFirstNNIPort(); err != nil {
1061 log.Warnw("no-nni-port", log.Fields{"error": err})
1062 return nil
1063 }
khenaidoo89b0e942018-10-21 21:11:33 -04001064 }
1065 //If ingress port is not specified (nil), it may be a wildcarded
1066 //route if egress port is OFPP_CONTROLLER or a nni logical port,
1067 //in which case we need to create a half-route where only the egress
1068 //hop is filled, the first hop is nil
khenaidoo2c6a0992019-04-29 13:46:56 -04001069 if ingressPortNo == 0 && agent.isNNIPort(egressPortNo) {
khenaidoo89b0e942018-10-21 21:11:33 -04001070 // We can use the 2nd hop of any upstream route, so just find the first upstream:
1071 for routeLink, route := range agent.deviceGraph.Routes {
khenaidoo2c6a0992019-04-29 13:46:56 -04001072 if agent.isNNIPort(routeLink.Egress) {
khenaidoo89b0e942018-10-21 21:11:33 -04001073 routes = append(routes, graph.RouteHop{}) // first hop is set to empty
1074 routes = append(routes, route[1])
1075 return routes
1076 }
1077 }
khenaidoo2c6a0992019-04-29 13:46:56 -04001078 log.Warnw("no-upstream-route", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "logicalPortsNo": agent.logicalPortsNo})
khenaidoo89b0e942018-10-21 21:11:33 -04001079 return nil
1080 }
1081 //If egress port is not specified (nil), we can also can return a "half" route
khenaidoo19d7b632018-10-30 10:49:50 -04001082 if egressPortNo == 0 {
khenaidoo89b0e942018-10-21 21:11:33 -04001083 for routeLink, route := range agent.deviceGraph.Routes {
khenaidoo19d7b632018-10-30 10:49:50 -04001084 if routeLink.Ingress == ingressPortNo {
khenaidoo89b0e942018-10-21 21:11:33 -04001085 routes = append(routes, route[0])
1086 routes = append(routes, graph.RouteHop{})
1087 return routes
1088 }
1089 }
khenaidoo2c6a0992019-04-29 13:46:56 -04001090 log.Warnw("no-downstream-route", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "logicalPortsNo": agent.logicalPortsNo})
khenaidoo89b0e942018-10-21 21:11:33 -04001091 return nil
1092 }
khenaidoo89b0e942018-10-21 21:11:33 -04001093 // Return the pre-calculated route
khenaidoo19d7b632018-10-30 10:49:50 -04001094 return agent.getPreCalculatedRoute(ingressPortNo, egressPortNo)
khenaidoo89b0e942018-10-21 21:11:33 -04001095}
1096
khenaidoo3d3b8c22019-05-22 18:10:39 -04001097//GetWildcardInputPorts filters out the logical port number from the set of logical ports on the device and
1098//returns their port numbers. This function is invoked only during flow decomposition where the lock on the logical
1099//device is already held. Therefore it is safe to retrieve the logical device without lock.
khenaidoo89b0e942018-10-21 21:11:33 -04001100func (agent *LogicalDeviceAgent) GetWildcardInputPorts(excludePort ...uint32) []uint32 {
1101 lPorts := make([]uint32, 0)
1102 var exclPort uint32
1103 if len(excludePort) == 1 {
1104 exclPort = excludePort[0]
1105 }
khenaidoo3d3b8c22019-05-22 18:10:39 -04001106 if lDevice, _ := agent.getLogicalDeviceWithoutLock(); lDevice != nil {
khenaidoo89b0e942018-10-21 21:11:33 -04001107 for _, port := range lDevice.Ports {
1108 if port.OfpPort.PortNo != exclPort {
1109 lPorts = append(lPorts, port.OfpPort.PortNo)
1110 }
1111 }
1112 }
1113 return lPorts
1114}
khenaidoo19d7b632018-10-30 10:49:50 -04001115
1116func (agent *LogicalDeviceAgent) GetDeviceGraph() *graph.DeviceGraph {
1117 return agent.deviceGraph
1118}
1119
khenaidoo3306c992019-05-24 16:57:35 -04001120//updateRoutes rebuilds the device graph if not done already
khenaidoo2c6a0992019-04-29 13:46:56 -04001121func (agent *LogicalDeviceAgent) updateRoutes(device *voltha.Device, port *voltha.Port) error {
1122 log.Debugf("updateRoutes", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "device": device.Id, "port": port})
khenaidoo910204f2019-04-08 17:56:40 -04001123 agent.lockLogicalDevice.Lock()
1124 defer agent.lockLogicalDevice.Unlock()
khenaidoo19d7b632018-10-30 10:49:50 -04001125 if agent.deviceGraph == nil {
khenaidoo910204f2019-04-08 17:56:40 -04001126 agent.deviceGraph = graph.NewDeviceGraph(agent.logicalDeviceId, agent.deviceMgr.GetDevice)
khenaidoo2c6a0992019-04-29 13:46:56 -04001127 }
1128 // Get all the logical ports on that logical device
1129 if lDevice, err := agent.getLogicalDeviceWithoutLock(); err != nil {
manikkaraj k259a6f72019-05-06 09:55:44 -04001130 log.Errorw("unknown-logical-device", log.Fields{"error": err, "logicalDeviceId": agent.logicalDeviceId})
khenaidoo2c6a0992019-04-29 13:46:56 -04001131 return err
1132 } else {
1133 //TODO: Find a better way to refresh only missing routes
1134 agent.deviceGraph.ComputeRoutes(lDevice.Ports)
1135 }
khenaidoo2c6a0992019-04-29 13:46:56 -04001136 agent.deviceGraph.Print()
1137 return nil
khenaidoo19d7b632018-10-30 10:49:50 -04001138}
1139
khenaidoo2c6a0992019-04-29 13:46:56 -04001140//updateDeviceGraph updates the device graph if not done already and setup the default rules as well
khenaidoo910204f2019-04-08 17:56:40 -04001141func (agent *LogicalDeviceAgent) updateDeviceGraph(lp *voltha.LogicalPort) {
khenaidoo2c6a0992019-04-29 13:46:56 -04001142 log.Debugf("updateDeviceGraph", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
1143 agent.lockLogicalDevice.Lock()
1144 defer agent.lockLogicalDevice.Unlock()
khenaidoo910204f2019-04-08 17:56:40 -04001145 if agent.deviceGraph == nil {
1146 agent.deviceGraph = graph.NewDeviceGraph(agent.logicalDeviceId, agent.deviceMgr.GetDevice)
1147 }
1148 agent.deviceGraph.AddPort(lp)
khenaidoo2c6a0992019-04-29 13:46:56 -04001149 agent.deviceGraph.Print()
khenaidoo19d7b632018-10-30 10:49:50 -04001150}
khenaidoofdbad6e2018-11-06 22:26:38 -05001151
khenaidoo3d3b8c22019-05-22 18:10:39 -04001152//generateDeviceGraph regenerates the device graph
1153func (agent *LogicalDeviceAgent) generateDeviceGraph() {
1154 log.Debugf("generateDeviceGraph", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo0a822f92019-05-08 15:15:57 -04001155 agent.lockLogicalDevice.Lock()
1156 defer agent.lockLogicalDevice.Unlock()
1157 // Get the latest logical device
1158 if ld, err := agent.getLogicalDeviceWithoutLock(); err != nil {
1159 log.Errorw("logical-device-not-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "error": err})
1160 } else {
khenaidoo3d3b8c22019-05-22 18:10:39 -04001161 log.Debugw("generating-graph", log.Fields{"lDeviceId": agent.logicalDeviceId, "deviceGraph": agent.deviceGraph, "lPorts": len(ld.Ports)})
1162 if agent.deviceGraph == nil {
1163 agent.deviceGraph = graph.NewDeviceGraph(agent.logicalDeviceId, agent.deviceMgr.GetDevice)
1164 }
khenaidoo0a822f92019-05-08 15:15:57 -04001165 agent.deviceGraph.ComputeRoutes(ld.Ports)
khenaidoo3d3b8c22019-05-22 18:10:39 -04001166 agent.deviceGraph.Print()
khenaidoo0a822f92019-05-08 15:15:57 -04001167 }
1168}
1169
khenaidoofc1314d2019-03-14 09:34:21 -04001170// portAdded is a callback invoked when a port is added to the logical device.
1171// TODO: To use when POST_ADD is fixed.
1172func (agent *LogicalDeviceAgent) portAdded(args ...interface{}) interface{} {
1173 log.Debugw("portAdded-callback", log.Fields{"argsLen": len(args)})
1174
1175 var port *voltha.LogicalPort
1176
1177 // Sanity check
1178 if args[0] != nil {
1179 log.Warnw("previous-data-not-nil", log.Fields{"args0": args[0]})
1180 }
1181 var ok bool
1182 if port, ok = args[1].(*voltha.LogicalPort); !ok {
1183 log.Errorw("invalid-args", log.Fields{"args1": args[1]})
1184 return nil
1185 }
1186
1187 // Set the proxy and callback for that port
1188 agent.portProxiesLock.Lock()
Stephane Barbarie40fd3b22019-04-23 21:50:47 -04001189 agent.portProxies[port.Id] = agent.clusterDataProxy.CreateProxy(
khenaidoofc1314d2019-03-14 09:34:21 -04001190 fmt.Sprintf("/logical_devices/%s/ports/%s", agent.logicalDeviceId, port.Id),
1191 false)
1192 agent.portProxies[port.Id].RegisterCallback(model.POST_UPDATE, agent.portUpdated)
1193 agent.portProxiesLock.Unlock()
1194
1195 // Send the port change event to the OF controller
1196 agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceId,
khenaidoo910204f2019-04-08 17:56:40 -04001197 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_ADD, Desc: port.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001198
1199 return nil
1200}
1201
1202// portRemoved is a callback invoked when a port is removed from the logical device.
1203// TODO: To use when POST_ADD is fixed.
1204func (agent *LogicalDeviceAgent) portRemoved(args ...interface{}) interface{} {
1205 log.Debugw("portRemoved-callback", log.Fields{"argsLen": len(args)})
1206
1207 var port *voltha.LogicalPort
1208
1209 // Sanity check
1210 if args[1] != nil {
1211 log.Warnw("data-not-nil", log.Fields{"args1": args[1]})
1212 }
1213 var ok bool
1214 if port, ok = args[0].(*voltha.LogicalPort); !ok {
1215 log.Errorw("invalid-args", log.Fields{"args0": args[0]})
1216 return nil
1217 }
1218
1219 // Remove the proxy and callback for that port
1220 agent.portProxiesLock.Lock()
1221 agent.portProxies[port.Id].UnregisterCallback(model.POST_UPDATE, agent.portUpdated)
1222 delete(agent.portProxies, port.Id)
1223 agent.portProxiesLock.Unlock()
1224
1225 // Send the port change event to the OF controller
1226 agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceId,
khenaidoo910204f2019-04-08 17:56:40 -04001227 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_DELETE, Desc: port.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001228
1229 return nil
1230}
1231
1232// 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 -04001233func diff(oldList, newList []*voltha.LogicalPort) (newPorts, changedPorts, deletedPorts []*voltha.LogicalPort) {
khenaidoofc1314d2019-03-14 09:34:21 -04001234 newPorts = make([]*voltha.LogicalPort, 0)
1235 changedPorts = make([]*voltha.LogicalPort, 0)
1236 deletedPorts = make([]*voltha.LogicalPort, 0)
1237 for _, o := range oldList {
1238 found := false
khenaidoofc1314d2019-03-14 09:34:21 -04001239 for _, n := range newList {
1240 if o.Id == n.Id {
khenaidoofc1314d2019-03-14 09:34:21 -04001241 found = true
1242 break
1243 }
1244 }
1245 if !found {
1246 deletedPorts = append(deletedPorts, o)
1247 }
khenaidoofc1314d2019-03-14 09:34:21 -04001248 }
1249 for _, n := range newList {
1250 found := false
khenaidoo2bc48282019-07-16 18:13:46 -04001251 changed := false
khenaidoofc1314d2019-03-14 09:34:21 -04001252 for _, o := range oldList {
1253 if o.Id == n.Id {
khenaidoo2bc48282019-07-16 18:13:46 -04001254 changed = !reflect.DeepEqual(o, n)
khenaidoofc1314d2019-03-14 09:34:21 -04001255 found = true
1256 break
1257 }
1258 }
1259 if !found {
1260 newPorts = append(newPorts, n)
1261 }
khenaidoo2bc48282019-07-16 18:13:46 -04001262 if changed {
1263 changedPorts = append(changedPorts, n)
1264 }
khenaidoofc1314d2019-03-14 09:34:21 -04001265 }
1266 return
1267}
1268
1269// portUpdated is invoked when a port is updated on the logical device. Until
1270// the POST_ADD notification is fixed, we will use the logical device to
1271// update that data.
1272func (agent *LogicalDeviceAgent) portUpdated(args ...interface{}) interface{} {
1273 log.Debugw("portUpdated-callback", log.Fields{"argsLen": len(args)})
1274
1275 var oldLD *voltha.LogicalDevice
1276 var newlD *voltha.LogicalDevice
1277
1278 var ok bool
1279 if oldLD, ok = args[0].(*voltha.LogicalDevice); !ok {
1280 log.Errorw("invalid-args", log.Fields{"args0": args[0]})
1281 return nil
1282 }
1283 if newlD, ok = args[1].(*voltha.LogicalDevice); !ok {
1284 log.Errorw("invalid-args", log.Fields{"args1": args[1]})
1285 return nil
1286 }
1287
1288 if reflect.DeepEqual(oldLD.Ports, newlD.Ports) {
1289 log.Debug("ports-have-not-changed")
1290 return nil
1291 }
1292
1293 // Get the difference between the two list
1294 newPorts, changedPorts, deletedPorts := diff(oldLD.Ports, newlD.Ports)
1295
1296 // Send the port change events to the OF controller
khenaidoo2c6a0992019-04-29 13:46:56 -04001297 for _, newP := range newPorts {
khenaidoofc1314d2019-03-14 09:34:21 -04001298 go agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceId,
khenaidoo2c6a0992019-04-29 13:46:56 -04001299 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_ADD, Desc: newP.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001300 }
1301 for _, change := range changedPorts {
1302 go agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceId,
khenaidoo910204f2019-04-08 17:56:40 -04001303 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_MODIFY, Desc: change.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001304 }
1305 for _, del := range deletedPorts {
1306 go agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceId,
khenaidoo910204f2019-04-08 17:56:40 -04001307 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_DELETE, Desc: del.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001308 }
1309
1310 return nil
1311}
1312
khenaidoo8f474192019-04-03 17:20:44 -04001313// addNNILogicalPort adds an NNI port to the logical device. It returns a bool representing whether a port has been
1314// added and an eror in case a valid error is encountered. If the port was successfully added it will return
1315// (true, nil). If the device is not in the correct state it will return (false, nil) as this is a valid
1316// scenario. This also applies to the case where the port was already added.
khenaidoo910204f2019-04-08 17:56:40 -04001317func (agent *LogicalDeviceAgent) addNNILogicalPort(device *voltha.Device, port *voltha.Port) (bool, error) {
khenaidoo1ce37ad2019-03-24 22:07:24 -04001318 log.Debugw("addNNILogicalPort", log.Fields{"NNI": port})
khenaidoo8f474192019-04-03 17:20:44 -04001319 if device.AdminState != voltha.AdminState_ENABLED || device.OperStatus != voltha.OperStatus_ACTIVE {
1320 log.Infow("device-not-ready", log.Fields{"deviceId": device.Id, "admin": device.AdminState, "oper": device.OperStatus})
1321 return false, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001322 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001323 agent.lockLogicalDevice.RLock()
1324 if agent.portExist(device, port) {
1325 log.Debugw("port-already-exist", log.Fields{"port": port})
1326 agent.lockLogicalDevice.RUnlock()
khenaidoo8f474192019-04-03 17:20:44 -04001327 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001328 }
1329 agent.lockLogicalDevice.RUnlock()
1330
khenaidoofc1314d2019-03-14 09:34:21 -04001331 var portCap *ic.PortCapability
1332 var err error
1333 // First get the port capability
1334 if portCap, err = agent.deviceMgr.getPortCapability(nil, device.Id, port.PortNo); err != nil {
1335 log.Errorw("error-retrieving-port-capabilities", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001336 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001337 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001338
1339 agent.lockLogicalDevice.Lock()
1340 defer agent.lockLogicalDevice.Unlock()
1341 // Double check again if this port has been already added since the getPortCapability could have taken a long time
1342 if agent.portExist(device, port) {
1343 log.Debugw("port-already-exist", log.Fields{"port": port})
khenaidoo8f474192019-04-03 17:20:44 -04001344 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001345 }
1346
khenaidoofc1314d2019-03-14 09:34:21 -04001347 portCap.Port.RootPort = true
1348 lp := (proto.Clone(portCap.Port)).(*voltha.LogicalPort)
1349 lp.DeviceId = device.Id
1350 lp.Id = fmt.Sprintf("nni-%d", port.PortNo)
1351 lp.OfpPort.PortNo = port.PortNo
1352 lp.OfpPort.Name = lp.Id
1353 lp.DevicePortNo = port.PortNo
1354
khenaidoofc1314d2019-03-14 09:34:21 -04001355 var ld *voltha.LogicalDevice
1356 if ld, err = agent.getLogicalDeviceWithoutLock(); err != nil {
1357 log.Errorw("error-retrieving-logical-device", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001358 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001359 }
1360 cloned := (proto.Clone(ld)).(*voltha.LogicalDevice)
1361 if cloned.Ports == nil {
1362 cloned.Ports = make([]*voltha.LogicalPort, 0)
1363 }
1364 cloned.Ports = append(cloned.Ports, lp)
1365
1366 if err = agent.updateLogicalDeviceWithoutLock(cloned); err != nil {
1367 log.Errorw("error-updating-logical-device", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001368 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001369 }
khenaidoo910204f2019-04-08 17:56:40 -04001370
1371 // Update the device graph with this new logical port
1372 clonedLP := (proto.Clone(lp)).(*voltha.LogicalPort)
1373 go agent.updateDeviceGraph(clonedLP)
1374
khenaidoo8f474192019-04-03 17:20:44 -04001375 return true, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001376}
1377
khenaidoo910204f2019-04-08 17:56:40 -04001378func (agent *LogicalDeviceAgent) portExist(device *voltha.Device, port *voltha.Port) bool {
khenaidoo54544ae2019-03-18 13:22:39 -04001379 if ldevice, _ := agent.getLogicalDeviceWithoutLock(); ldevice != nil {
khenaidoofc1314d2019-03-14 09:34:21 -04001380 for _, lPort := range ldevice.Ports {
khenaidoo54544ae2019-03-18 13:22:39 -04001381 if lPort.DeviceId == device.Id && lPort.DevicePortNo == port.PortNo && lPort.Id == port.Label {
khenaidoofc1314d2019-03-14 09:34:21 -04001382 return true
1383 }
1384 }
1385 }
1386 return false
1387}
1388
khenaidoo8f474192019-04-03 17:20:44 -04001389// addUNILogicalPort adds an UNI port to the logical device. It returns a bool representing whether a port has been
1390// added and an eror in case a valid error is encountered. If the port was successfully added it will return
1391// (true, nil). If the device is not in the correct state it will return (false, nil) as this is a valid
1392// scenario. This also applies to the case where the port was already added.
khenaidoo910204f2019-04-08 17:56:40 -04001393func (agent *LogicalDeviceAgent) addUNILogicalPort(childDevice *voltha.Device, port *voltha.Port) (bool, error) {
khenaidoofc1314d2019-03-14 09:34:21 -04001394 log.Debugw("addUNILogicalPort", log.Fields{"port": port})
khenaidoo8f474192019-04-03 17:20:44 -04001395 if childDevice.AdminState != voltha.AdminState_ENABLED || childDevice.OperStatus != voltha.OperStatus_ACTIVE {
1396 log.Infow("device-not-ready", log.Fields{"deviceId": childDevice.Id, "admin": childDevice.AdminState, "oper": childDevice.OperStatus})
1397 return false, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001398 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001399 agent.lockLogicalDevice.RLock()
1400 if agent.portExist(childDevice, port) {
1401 log.Debugw("port-already-exist", log.Fields{"port": port})
1402 agent.lockLogicalDevice.RUnlock()
khenaidoo8f474192019-04-03 17:20:44 -04001403 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001404 }
1405 agent.lockLogicalDevice.RUnlock()
khenaidoofc1314d2019-03-14 09:34:21 -04001406 var portCap *ic.PortCapability
1407 var err error
1408 // First get the port capability
1409 if portCap, err = agent.deviceMgr.getPortCapability(nil, childDevice.Id, port.PortNo); err != nil {
1410 log.Errorw("error-retrieving-port-capabilities", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001411 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001412 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001413 agent.lockLogicalDevice.Lock()
1414 defer agent.lockLogicalDevice.Unlock()
1415 // Double check again if this port has been already added since the getPortCapability could have taken a long time
1416 if agent.portExist(childDevice, port) {
1417 log.Debugw("port-already-exist", log.Fields{"port": port})
khenaidoo8f474192019-04-03 17:20:44 -04001418 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001419 }
khenaidoofc1314d2019-03-14 09:34:21 -04001420 // Get stored logical device
1421 if ldevice, err := agent.getLogicalDeviceWithoutLock(); err != nil {
khenaidoo8f474192019-04-03 17:20:44 -04001422 return false, status.Error(codes.NotFound, agent.logicalDeviceId)
khenaidoofc1314d2019-03-14 09:34:21 -04001423 } else {
1424 log.Debugw("adding-uni", log.Fields{"deviceId": childDevice.Id})
1425 portCap.Port.RootPort = false
Matt Jeanneret3815e322019-03-12 19:15:49 -04001426 portCap.Port.Id = port.Label
1427 portCap.Port.OfpPort.PortNo = port.PortNo
khenaidoofc1314d2019-03-14 09:34:21 -04001428 portCap.Port.DeviceId = childDevice.Id
1429 portCap.Port.DevicePortNo = port.PortNo
1430 cloned := (proto.Clone(ldevice)).(*voltha.LogicalDevice)
1431 if cloned.Ports == nil {
1432 cloned.Ports = make([]*voltha.LogicalPort, 0)
1433 }
1434 cloned.Ports = append(cloned.Ports, portCap.Port)
khenaidoo910204f2019-04-08 17:56:40 -04001435 if err := agent.updateLogicalDeviceWithoutLock(cloned); err != nil {
1436 return false, err
1437 }
khenaidoo910204f2019-04-08 17:56:40 -04001438 // Update the device graph with this new logical port
1439 clonedLP := (proto.Clone(portCap.Port)).(*voltha.LogicalPort)
1440 go agent.updateDeviceGraph(clonedLP)
1441 return true, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001442 }
1443}
1444
khenaidoo43c82122018-11-22 18:38:28 -05001445func (agent *LogicalDeviceAgent) packetOut(packet *ofp.OfpPacketOut) {
khenaidoofdbad6e2018-11-06 22:26:38 -05001446 log.Debugw("packet-out", log.Fields{"packet": packet.GetInPort()})
khenaidoo68c930b2019-05-13 11:46:51 -04001447 outPort := fu.GetPacketOutPort(packet)
khenaidoofdbad6e2018-11-06 22:26:38 -05001448 //frame := packet.GetData()
1449 //TODO: Use a channel between the logical agent and the device agent
khenaidooca301322019-01-09 23:06:32 -05001450 if err := agent.deviceMgr.packetOut(agent.rootDeviceId, outPort, packet); err != nil {
khenaidoo910204f2019-04-08 17:56:40 -04001451 log.Error("packetout-failed", log.Fields{"logicalDeviceID": agent.rootDeviceId})
khenaidooca301322019-01-09 23:06:32 -05001452 }
khenaidoofdbad6e2018-11-06 22:26:38 -05001453}
1454
khenaidoo297cd252019-02-07 22:10:23 -05001455func (agent *LogicalDeviceAgent) packetIn(port uint32, transactionId string, packet []byte) {
1456 log.Debugw("packet-in", log.Fields{"port": port, "packet": packet, "transactionId": transactionId})
khenaidoo68c930b2019-05-13 11:46:51 -04001457 packetIn := fu.MkPacketIn(port, packet)
khenaidoo297cd252019-02-07 22:10:23 -05001458 agent.ldeviceMgr.grpcNbiHdlr.sendPacketIn(agent.logicalDeviceId, transactionId, packetIn)
khenaidooca301322019-01-09 23:06:32 -05001459 log.Debugw("sending-packet-in", log.Fields{"packet-in": packetIn})
khenaidoofdbad6e2018-11-06 22:26:38 -05001460}
khenaidoo2c6a0992019-04-29 13:46:56 -04001461
1462func (agent *LogicalDeviceAgent) addLogicalPortToMap(portNo uint32, nniPort bool) {
1463 agent.lockLogicalPortsNo.Lock()
1464 defer agent.lockLogicalPortsNo.Unlock()
1465 if exist := agent.logicalPortsNo[portNo]; !exist {
1466 agent.logicalPortsNo[portNo] = nniPort
1467 }
1468}
1469
khenaidoo3d3b8c22019-05-22 18:10:39 -04001470func (agent *LogicalDeviceAgent) addLogicalPortsToMap(lps []*voltha.LogicalPort) {
1471 agent.lockLogicalPortsNo.Lock()
1472 defer agent.lockLogicalPortsNo.Unlock()
1473 for _, lp := range lps {
1474 if exist := agent.logicalPortsNo[lp.DevicePortNo]; !exist {
1475 agent.logicalPortsNo[lp.DevicePortNo] = lp.RootPort
1476 }
1477 }
1478}
1479
khenaidoo2c6a0992019-04-29 13:46:56 -04001480func (agent *LogicalDeviceAgent) deleteLogicalPortFromMap(portNo uint32) {
1481 agent.lockLogicalPortsNo.Lock()
1482 defer agent.lockLogicalPortsNo.Unlock()
1483 if exist := agent.logicalPortsNo[portNo]; exist {
1484 delete(agent.logicalPortsNo, portNo)
1485 }
1486}
1487
1488func (agent *LogicalDeviceAgent) isNNIPort(portNo uint32) bool {
1489 agent.lockLogicalPortsNo.RLock()
1490 defer agent.lockLogicalPortsNo.RUnlock()
1491 if exist := agent.logicalPortsNo[portNo]; exist {
1492 return agent.logicalPortsNo[portNo]
1493 }
1494 return false
1495}
1496
1497func (agent *LogicalDeviceAgent) getFirstNNIPort() (uint32, error) {
1498 agent.lockLogicalPortsNo.RLock()
1499 defer agent.lockLogicalPortsNo.RUnlock()
1500 for portNo, nni := range agent.logicalPortsNo {
1501 if nni {
1502 return portNo, nil
1503 }
1504 }
1505 return 0, status.Error(codes.NotFound, "No NNI port found")
1506}