blob: 489c79ffbf93b267da934c9aa38bf4e9a6dce626 [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)
khenaidoo43c82122018-11-22 18:38:28 -0500536 //oldData := proto.Clone(lDevice.Flows).(*voltha.Flows)
khenaidoo19d7b632018-10-30 10:49:50 -0400537 changed := false
538 checkOverlap := (mod.Flags & uint32(ofp.OfpFlowModFlags_OFPFF_CHECK_OVERLAP)) != 0
539 if checkOverlap {
540 if overlapped := fu.FindOverlappingFlows(flows, mod); len(overlapped) != 0 {
541 // TODO: should this error be notified other than being logged?
542 log.Warnw("overlapped-flows", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
543 } else {
544 // Add flow
khenaidoo68c930b2019-05-13 11:46:51 -0400545 flow := fu.FlowStatsEntryFromFlowModMessage(mod)
khenaidoo19d7b632018-10-30 10:49:50 -0400546 flows = append(flows, flow)
khenaidoo2c6a0992019-04-29 13:46:56 -0400547 updatedFlows = append(updatedFlows, flow)
khenaidoo19d7b632018-10-30 10:49:50 -0400548 changed = true
549 }
550 } else {
khenaidoo68c930b2019-05-13 11:46:51 -0400551 flow := fu.FlowStatsEntryFromFlowModMessage(mod)
khenaidoo19d7b632018-10-30 10:49:50 -0400552 idx := fu.FindFlows(flows, flow)
553 if idx >= 0 {
554 oldFlow := flows[idx]
555 if (mod.Flags & uint32(ofp.OfpFlowModFlags_OFPFF_RESET_COUNTS)) != 0 {
556 flow.ByteCount = oldFlow.ByteCount
557 flow.PacketCount = oldFlow.PacketCount
558 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400559 if !reflect.DeepEqual(oldFlow, flow) {
560 flows[idx] = flow
561 updatedFlows = append(updatedFlows, flow)
562 changed = true
563 }
khenaidoo19d7b632018-10-30 10:49:50 -0400564 } else {
565 flows = append(flows, flow)
khenaidoo2c6a0992019-04-29 13:46:56 -0400566 updatedFlows = append(updatedFlows, flow)
567 changed = true
khenaidoo19d7b632018-10-30 10:49:50 -0400568 }
khenaidoo19d7b632018-10-30 10:49:50 -0400569 }
570 if changed {
khenaidoo2c6a0992019-04-29 13:46:56 -0400571 // Launch a routine to decompose the flows
khenaidoo3306c992019-05-24 16:57:35 -0400572 if err := agent.decomposeAndSendFlows(&ofp.Flows{Items: updatedFlows}, lDevice.FlowGroups); err != nil {
manikkaraj k259a6f72019-05-06 09:55:44 -0400573 log.Errorw("decomposing-and-sending-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo2c6a0992019-04-29 13:46:56 -0400574 return err
575 }
576
khenaidoo19d7b632018-10-30 10:49:50 -0400577 // Update model
khenaidoo43c82122018-11-22 18:38:28 -0500578 flowsToUpdate := &ofp.Flows{}
579 if lDevice.Flows != nil {
580 flowsToUpdate = &ofp.Flows{Items: flows}
khenaidoo19d7b632018-10-30 10:49:50 -0400581 }
khenaidoo43c82122018-11-22 18:38:28 -0500582 if err := agent.updateLogicalDeviceFlowsWithoutLock(flowsToUpdate); err != nil {
khenaidoo2c6a0992019-04-29 13:46:56 -0400583 log.Errorw("db-flow-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400584 return err
585 }
586 }
khenaidoo19d7b632018-10-30 10:49:50 -0400587 return nil
588}
589
khenaidoo3306c992019-05-24 16:57:35 -0400590func (agent *LogicalDeviceAgent) decomposeAndSendFlows(flows *ofp.Flows, groups *ofp.FlowGroups) error {
khenaidoo2c6a0992019-04-29 13:46:56 -0400591 log.Debugw("decomposeAndSendFlows", log.Fields{"logicalDeviceID": agent.logicalDeviceId})
592
khenaidoo3306c992019-05-24 16:57:35 -0400593 deviceRules := agent.flowDecomposer.DecomposeRules(agent, *flows, *groups)
khenaidoo2c6a0992019-04-29 13:46:56 -0400594 log.Debugw("rules", log.Fields{"rules": deviceRules.String()})
595
596 chnlsList := make([]chan interface{}, 0)
597 for deviceId, value := range deviceRules.GetRules() {
598 ch := make(chan interface{})
599 chnlsList = append(chnlsList, ch)
600 go func(deviceId string, flows []*ofp.OfpFlowStats, groups []*ofp.OfpGroupEntry) {
601 if err := agent.deviceMgr.addFlowsAndGroups(deviceId, flows, groups); err != nil {
602 log.Error("flow-update-failed", log.Fields{"deviceID": deviceId})
603 ch <- status.Errorf(codes.Internal, "flow-update-failed: %s", deviceId)
604 }
605 ch <- nil
606 }(deviceId, value.ListFlows(), value.ListGroups())
607 }
608 // Wait for completion
609 if res := fu.WaitForNilOrErrorResponses(agent.defaultTimeout, chnlsList...); res != nil {
610 return status.Errorf(codes.Aborted, "errors-%s", res)
611 }
612 return nil
613}
614
khenaidoo19d7b632018-10-30 10:49:50 -0400615//flowDelete deletes a flow from the flow table of that logical device
616func (agent *LogicalDeviceAgent) flowDelete(mod *ofp.OfpFlowMod) error {
617 log.Debug("flowDelete")
618 if mod == nil {
619 return nil
620 }
621 agent.lockLogicalDevice.Lock()
622 defer agent.lockLogicalDevice.Unlock()
623
624 var lDevice *voltha.LogicalDevice
625 var err error
626 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
627 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
628 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
629 }
630 flows := lDevice.Flows.Items
631
632 //build a list of what to keep vs what to delete
633 toKeep := make([]*ofp.OfpFlowStats, 0)
634 for _, f := range flows {
635 if !fu.FlowMatchesMod(f, mod) {
636 toKeep = append(toKeep, f)
637 }
638 }
639
640 //Update flows
641 if len(toKeep) < len(flows) {
khenaidoo43c82122018-11-22 18:38:28 -0500642 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: toKeep}); err != nil {
643 log.Errorw("Cannot-update-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400644 return err
645 }
646 }
647
648 //TODO: send announcement on delete
649 return nil
650}
651
652//flowStatsDelete deletes a flow from the flow table of that logical device
653func (agent *LogicalDeviceAgent) flowStatsDelete(flow *ofp.OfpFlowStats) error {
654 log.Debug("flowStatsDelete")
655 if flow == nil {
656 return nil
657 }
658 agent.lockLogicalDevice.Lock()
659 defer agent.lockLogicalDevice.Unlock()
660
661 var lDevice *voltha.LogicalDevice
662 var err error
663 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
664 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
665 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
666 }
667 flows := lDevice.Flows.Items
668
669 //build a list of what to keep vs what to delete
670 toKeep := make([]*ofp.OfpFlowStats, 0)
671 for _, f := range flows {
672 if !fu.FlowMatch(f, flow) {
673 toKeep = append(toKeep, f)
674 }
675 }
676
677 //Update flows
678 if len(toKeep) < len(flows) {
khenaidoo43c82122018-11-22 18:38:28 -0500679 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: toKeep}); err != nil {
khenaidoo19d7b632018-10-30 10:49:50 -0400680 log.Errorw("Cannot-update-logical-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
681 return err
682 }
683 }
684 return nil
685}
686
687//flowDeleteStrict deletes a flow from the flow table of that logical device
688func (agent *LogicalDeviceAgent) flowDeleteStrict(mod *ofp.OfpFlowMod) error {
689 log.Debug("flowDeleteStrict")
690 if mod == nil {
691 return nil
692 }
693 agent.lockLogicalDevice.Lock()
694 defer agent.lockLogicalDevice.Unlock()
695
696 var lDevice *voltha.LogicalDevice
697 var err error
698 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
699 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
700 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
701 }
702 flows := lDevice.Flows.Items
703 changed := false
khenaidoo68c930b2019-05-13 11:46:51 -0400704 flow := fu.FlowStatsEntryFromFlowModMessage(mod)
khenaidoo19d7b632018-10-30 10:49:50 -0400705 idx := fu.FindFlows(flows, flow)
706 if idx >= 0 {
707 flows = append(flows[:idx], flows[idx+1:]...)
708 changed = true
709 } else {
710 return errors.New(fmt.Sprintf("Cannot delete flow - %s", flow))
711 }
712
713 if changed {
khenaidoo43c82122018-11-22 18:38:28 -0500714 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: flows}); err != nil {
khenaidoo19d7b632018-10-30 10:49:50 -0400715 log.Errorw("Cannot-update-logical-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
716 return err
717 }
718 }
719
720 return nil
721}
722
723//flowModify modifies a flow from the flow table of that logical device
724func (agent *LogicalDeviceAgent) flowModify(mod *ofp.OfpFlowMod) error {
725 return errors.New("flowModify not implemented")
726}
727
728//flowModifyStrict deletes a flow from the flow table of that logical device
729func (agent *LogicalDeviceAgent) flowModifyStrict(mod *ofp.OfpFlowMod) error {
730 return errors.New("flowModifyStrict not implemented")
731}
732
733func (agent *LogicalDeviceAgent) groupAdd(groupMod *ofp.OfpGroupMod) error {
734 log.Debug("groupAdd")
735 if groupMod == nil {
736 return nil
737 }
738 agent.lockLogicalDevice.Lock()
739 defer agent.lockLogicalDevice.Unlock()
740
741 var lDevice *voltha.LogicalDevice
742 var err error
743 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
744 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
745 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
746 }
747 groups := lDevice.FlowGroups.Items
khenaidoo19d7b632018-10-30 10:49:50 -0400748 if fu.FindGroup(groups, groupMod.GroupId) == -1 {
khenaidoo68c930b2019-05-13 11:46:51 -0400749 groups = append(groups, fu.GroupEntryFromGroupMod(groupMod))
khenaidoo43c82122018-11-22 18:38:28 -0500750 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(&ofp.FlowGroups{Items: groups}); err != nil {
751 log.Errorw("Cannot-update-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400752 return err
753 }
754 } else {
755 return errors.New(fmt.Sprintf("Groups %d already present", groupMod.GroupId))
756 }
khenaidoo19d7b632018-10-30 10:49:50 -0400757 return nil
758}
759
760func (agent *LogicalDeviceAgent) groupDelete(groupMod *ofp.OfpGroupMod) error {
761 log.Debug("groupDelete")
762 if groupMod == nil {
763 return nil
764 }
765 agent.lockLogicalDevice.Lock()
766 defer agent.lockLogicalDevice.Unlock()
767
768 var lDevice *voltha.LogicalDevice
769 var err error
770 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
771 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
772 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
773 }
774 groups := lDevice.FlowGroups.Items
775 flows := lDevice.Flows.Items
776 groupsChanged := false
777 flowsChanged := false
778 groupId := groupMod.GroupId
779 if groupId == uint32(ofp.OfpGroup_OFPG_ALL) {
780 //TODO we must delete all flows that point to this group and
781 //signal controller as requested by flow's flag
782 groups = []*ofp.OfpGroupEntry{}
783 groupsChanged = true
784 } else {
785 if idx := fu.FindGroup(groups, groupId); idx == -1 {
786 return nil // Valid case
787 } else {
788 flowsChanged, flows = fu.FlowsDeleteByGroupId(flows, groupId)
789 groups = append(groups[:idx], groups[idx+1:]...)
790 groupsChanged = true
791 }
792 }
khenaidoo43c82122018-11-22 18:38:28 -0500793 if groupsChanged {
794 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(&ofp.FlowGroups{Items: groups}); err != nil {
795 log.Errorw("Cannot-update-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400796 return err
797 }
798 }
khenaidoo43c82122018-11-22 18:38:28 -0500799 if flowsChanged {
800 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: flows}); err != nil {
801 log.Errorw("Cannot-update-flow", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
802 return err
803 }
804 }
805
khenaidoo19d7b632018-10-30 10:49:50 -0400806 return nil
807}
808
809func (agent *LogicalDeviceAgent) groupModify(groupMod *ofp.OfpGroupMod) error {
810 log.Debug("groupModify")
811 if groupMod == nil {
812 return nil
813 }
814 agent.lockLogicalDevice.Lock()
815 defer agent.lockLogicalDevice.Unlock()
816
817 var lDevice *voltha.LogicalDevice
818 var err error
819 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
820 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
821 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
822 }
823 groups := lDevice.FlowGroups.Items
824 groupsChanged := false
825 groupId := groupMod.GroupId
826 if idx := fu.FindGroup(groups, groupId); idx == -1 {
khenaidooca301322019-01-09 23:06:32 -0500827 return errors.New(fmt.Sprintf("group-absent:%d", groupId))
khenaidoo19d7b632018-10-30 10:49:50 -0400828 } else {
829 //replace existing group entry with new group definition
khenaidoo68c930b2019-05-13 11:46:51 -0400830 groupEntry := fu.GroupEntryFromGroupMod(groupMod)
khenaidoo19d7b632018-10-30 10:49:50 -0400831 groups[idx] = groupEntry
832 groupsChanged = true
833 }
834 if groupsChanged {
khenaidoo43c82122018-11-22 18:38:28 -0500835 //lDevice.FlowGroups.Items = groups
836 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(&ofp.FlowGroups{Items: groups}); err != nil {
khenaidoo19d7b632018-10-30 10:49:50 -0400837 log.Errorw("Cannot-update-logical-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
838 return err
839 }
840 }
841 return nil
842}
843
844// deleteLogicalPort removes the logical port
845func (agent *LogicalDeviceAgent) deleteLogicalPort(lPort *voltha.LogicalPort) error {
846 agent.lockLogicalDevice.Lock()
847 defer agent.lockLogicalDevice.Unlock()
848
khenaidoo92e62c52018-10-03 14:02:54 -0400849 // Get the most up to date logical device
850 var logicaldevice *voltha.LogicalDevice
851 if logicaldevice, _ = agent.getLogicalDeviceWithoutLock(); logicaldevice == nil {
khenaidoo19d7b632018-10-30 10:49:50 -0400852 log.Debugw("no-logical-device", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "logicalPortId": lPort.Id})
khenaidoob9203542018-09-17 22:56:37 -0400853 return nil
854 }
khenaidoo92e62c52018-10-03 14:02:54 -0400855 index := -1
856 for i, logicalPort := range logicaldevice.Ports {
khenaidoo19d7b632018-10-30 10:49:50 -0400857 if logicalPort.Id == lPort.Id {
khenaidoo92e62c52018-10-03 14:02:54 -0400858 index = i
859 break
860 }
861 }
862 if index >= 0 {
863 copy(logicaldevice.Ports[index:], logicaldevice.Ports[index+1:])
864 logicaldevice.Ports[len(logicaldevice.Ports)-1] = nil
865 logicaldevice.Ports = logicaldevice.Ports[:len(logicaldevice.Ports)-1]
866 log.Debugw("logical-port-deleted", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo0a822f92019-05-08 15:15:57 -0400867 if err := agent.updateLogicalDeviceWithoutLock(logicaldevice); err != nil {
868 log.Errorw("logical-device-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
869 return err
870 }
871 // Reset the logical device graph
khenaidoo3d3b8c22019-05-22 18:10:39 -0400872 go agent.generateDeviceGraph()
khenaidoo92e62c52018-10-03 14:02:54 -0400873 }
874 return nil
khenaidoob9203542018-09-17 22:56:37 -0400875}
876
khenaidoo0a822f92019-05-08 15:15:57 -0400877// deleteLogicalPorts removes the logical ports associated with that deviceId
878func (agent *LogicalDeviceAgent) deleteLogicalPorts(deviceId string) error {
879 agent.lockLogicalDevice.Lock()
880 defer agent.lockLogicalDevice.Unlock()
881
882 // Get the most up to date logical device
883 var logicaldevice *voltha.LogicalDevice
884 if logicaldevice, _ = agent.getLogicalDeviceWithoutLock(); logicaldevice == nil {
885 log.Debugw("no-logical-device", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
886 return nil
887 }
888 updatedLPorts := []*voltha.LogicalPort{}
889 for _, logicalPort := range logicaldevice.Ports {
890 if logicalPort.DeviceId != deviceId {
891 updatedLPorts = append(updatedLPorts, logicalPort)
892 }
893 }
894 logicaldevice.Ports = updatedLPorts
895 log.Debugw("updated-logical-ports", log.Fields{"ports": updatedLPorts})
896 if err := agent.updateLogicalDeviceWithoutLock(logicaldevice); err != nil {
897 log.Errorw("logical-device-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
898 return err
899 }
900 // Reset the logical device graph
khenaidoo3d3b8c22019-05-22 18:10:39 -0400901 go agent.generateDeviceGraph()
khenaidoo0a822f92019-05-08 15:15:57 -0400902
903 return nil
904}
905
khenaidoo19d7b632018-10-30 10:49:50 -0400906// enableLogicalPort enables the logical port
907func (agent *LogicalDeviceAgent) enableLogicalPort(lPort *voltha.LogicalPort) error {
908 agent.lockLogicalDevice.Lock()
909 defer agent.lockLogicalDevice.Unlock()
910
911 // Get the most up to date logical device
912 var logicaldevice *voltha.LogicalDevice
913 if logicaldevice, _ = agent.getLogicalDeviceWithoutLock(); logicaldevice == nil {
914 log.Debugw("no-logical-device", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "logicalPortId": lPort.Id})
915 return nil
916 }
917 index := -1
918 for i, logicalPort := range logicaldevice.Ports {
919 if logicalPort.Id == lPort.Id {
920 index = i
921 break
922 }
923 }
924 if index >= 0 {
925 logicaldevice.Ports[index].OfpPort.Config = logicaldevice.Ports[index].OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
926 return agent.updateLogicalDeviceWithoutLock(logicaldevice)
927 }
928 //TODO: Trigger subsequent actions on the device
929 return nil
930}
931
932// disableLogicalPort disabled the logical port
933func (agent *LogicalDeviceAgent) disableLogicalPort(lPort *voltha.LogicalPort) 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, "logicalPortId": lPort.Id})
941 return nil
942 }
943 index := -1
944 for i, logicalPort := range logicaldevice.Ports {
945 if logicalPort.Id == lPort.Id {
946 index = i
947 break
948 }
949 }
950 if index >= 0 {
951 logicaldevice.Ports[index].OfpPort.Config = (logicaldevice.Ports[index].OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)) | uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
952 return agent.updateLogicalDeviceWithoutLock(logicaldevice)
953 }
954 //TODO: Trigger subsequent actions on the device
955 return nil
956}
957
khenaidoo89b0e942018-10-21 21:11:33 -0400958func (agent *LogicalDeviceAgent) getPreCalculatedRoute(ingress, egress uint32) []graph.RouteHop {
khenaidoo19d7b632018-10-30 10:49:50 -0400959 log.Debugw("ROUTE", log.Fields{"len": len(agent.deviceGraph.Routes)})
khenaidoo89b0e942018-10-21 21:11:33 -0400960 for routeLink, route := range agent.deviceGraph.Routes {
khenaidoo19d7b632018-10-30 10:49:50 -0400961 log.Debugw("ROUTELINKS", log.Fields{"ingress": ingress, "egress": egress, "routelink": routeLink})
khenaidoo89b0e942018-10-21 21:11:33 -0400962 if ingress == routeLink.Ingress && egress == routeLink.Egress {
963 return route
964 }
965 }
966 log.Warnw("no-route", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "ingress": ingress, "egress": egress})
967 return nil
968}
969
khenaidoo19d7b632018-10-30 10:49:50 -0400970func (agent *LogicalDeviceAgent) GetRoute(ingressPortNo uint32, egressPortNo uint32) []graph.RouteHop {
khenaidoo89b0e942018-10-21 21:11:33 -0400971 log.Debugw("getting-route", log.Fields{"ingress-port": ingressPortNo, "egress-port": egressPortNo})
khenaidoo89b0e942018-10-21 21:11:33 -0400972 routes := make([]graph.RouteHop, 0)
khenaidoo2c6a0992019-04-29 13:46:56 -0400973
khenaidoo19d7b632018-10-30 10:49:50 -0400974 // Note: A port value of 0 is equivalent to a nil port
975
khenaidoo89b0e942018-10-21 21:11:33 -0400976 // Consider different possibilities
khenaidoo19d7b632018-10-30 10:49:50 -0400977 if egressPortNo != 0 && ((egressPortNo & 0x7fffffff) == uint32(ofp.OfpPortNo_OFPP_CONTROLLER)) {
khenaidoo2c6a0992019-04-29 13:46:56 -0400978 log.Debugw("controller-flow", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "logicalPortsNo": agent.logicalPortsNo})
979 if agent.isNNIPort(ingressPortNo) {
khenaidoo89b0e942018-10-21 21:11:33 -0400980 log.Debug("returning-half-route")
981 //This is a trap on the NNI Port
khenaidoo8f474192019-04-03 17:20:44 -0400982 if len(agent.deviceGraph.Routes) == 0 {
983 // If there are no routes set (usually when the logical device has only NNI port(s), then just return an
984 // internal route
khenaidoo2c6a0992019-04-29 13:46:56 -0400985 hop := graph.RouteHop{DeviceID: agent.rootDeviceId, Ingress: ingressPortNo, Egress: egressPortNo}
khenaidoo8f474192019-04-03 17:20:44 -0400986 routes = append(routes, hop)
987 routes = append(routes, hop)
988 return routes
989 }
khenaidoo89b0e942018-10-21 21:11:33 -0400990 //Return a 'half' route to make the flow decomposer logic happy
991 for routeLink, route := range agent.deviceGraph.Routes {
khenaidoo2c6a0992019-04-29 13:46:56 -0400992 if agent.isNNIPort(routeLink.Egress) {
khenaidoo89b0e942018-10-21 21:11:33 -0400993 routes = append(routes, graph.RouteHop{}) // first hop is set to empty
994 routes = append(routes, route[1])
995 return routes
996 }
997 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400998 log.Warnw("no-upstream-route", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "logicalPortsNo": agent.logicalPortsNo})
khenaidoo89b0e942018-10-21 21:11:33 -0400999 return nil
1000 }
1001 //treat it as if the output port is the first NNI of the OLT
khenaidoo2c6a0992019-04-29 13:46:56 -04001002 var err error
1003 if egressPortNo, err = agent.getFirstNNIPort(); err != nil {
1004 log.Warnw("no-nni-port", log.Fields{"error": err})
1005 return nil
1006 }
khenaidoo89b0e942018-10-21 21:11:33 -04001007 }
1008 //If ingress port is not specified (nil), it may be a wildcarded
1009 //route if egress port is OFPP_CONTROLLER or a nni logical port,
1010 //in which case we need to create a half-route where only the egress
1011 //hop is filled, the first hop is nil
khenaidoo2c6a0992019-04-29 13:46:56 -04001012 if ingressPortNo == 0 && agent.isNNIPort(egressPortNo) {
khenaidoo89b0e942018-10-21 21:11:33 -04001013 // We can use the 2nd hop of any upstream route, so just find the first upstream:
1014 for routeLink, route := range agent.deviceGraph.Routes {
khenaidoo2c6a0992019-04-29 13:46:56 -04001015 if agent.isNNIPort(routeLink.Egress) {
khenaidoo89b0e942018-10-21 21:11:33 -04001016 routes = append(routes, graph.RouteHop{}) // first hop is set to empty
1017 routes = append(routes, route[1])
1018 return routes
1019 }
1020 }
khenaidoo2c6a0992019-04-29 13:46:56 -04001021 log.Warnw("no-upstream-route", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "logicalPortsNo": agent.logicalPortsNo})
khenaidoo89b0e942018-10-21 21:11:33 -04001022 return nil
1023 }
1024 //If egress port is not specified (nil), we can also can return a "half" route
khenaidoo19d7b632018-10-30 10:49:50 -04001025 if egressPortNo == 0 {
khenaidoo89b0e942018-10-21 21:11:33 -04001026 for routeLink, route := range agent.deviceGraph.Routes {
khenaidoo19d7b632018-10-30 10:49:50 -04001027 if routeLink.Ingress == ingressPortNo {
khenaidoo89b0e942018-10-21 21:11:33 -04001028 routes = append(routes, route[0])
1029 routes = append(routes, graph.RouteHop{})
1030 return routes
1031 }
1032 }
khenaidoo2c6a0992019-04-29 13:46:56 -04001033 log.Warnw("no-downstream-route", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "logicalPortsNo": agent.logicalPortsNo})
khenaidoo89b0e942018-10-21 21:11:33 -04001034 return nil
1035 }
khenaidoo89b0e942018-10-21 21:11:33 -04001036 // Return the pre-calculated route
khenaidoo19d7b632018-10-30 10:49:50 -04001037 return agent.getPreCalculatedRoute(ingressPortNo, egressPortNo)
khenaidoo89b0e942018-10-21 21:11:33 -04001038}
1039
khenaidoo3d3b8c22019-05-22 18:10:39 -04001040//GetWildcardInputPorts filters out the logical port number from the set of logical ports on the device and
1041//returns their port numbers. This function is invoked only during flow decomposition where the lock on the logical
1042//device is already held. Therefore it is safe to retrieve the logical device without lock.
khenaidoo89b0e942018-10-21 21:11:33 -04001043func (agent *LogicalDeviceAgent) GetWildcardInputPorts(excludePort ...uint32) []uint32 {
1044 lPorts := make([]uint32, 0)
1045 var exclPort uint32
1046 if len(excludePort) == 1 {
1047 exclPort = excludePort[0]
1048 }
khenaidoo3d3b8c22019-05-22 18:10:39 -04001049 if lDevice, _ := agent.getLogicalDeviceWithoutLock(); lDevice != nil {
khenaidoo89b0e942018-10-21 21:11:33 -04001050 for _, port := range lDevice.Ports {
1051 if port.OfpPort.PortNo != exclPort {
1052 lPorts = append(lPorts, port.OfpPort.PortNo)
1053 }
1054 }
1055 }
1056 return lPorts
1057}
khenaidoo19d7b632018-10-30 10:49:50 -04001058
1059func (agent *LogicalDeviceAgent) GetDeviceGraph() *graph.DeviceGraph {
1060 return agent.deviceGraph
1061}
1062
khenaidoo3306c992019-05-24 16:57:35 -04001063//updateRoutes rebuilds the device graph if not done already
khenaidoo2c6a0992019-04-29 13:46:56 -04001064func (agent *LogicalDeviceAgent) updateRoutes(device *voltha.Device, port *voltha.Port) error {
1065 log.Debugf("updateRoutes", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "device": device.Id, "port": port})
khenaidoo910204f2019-04-08 17:56:40 -04001066 agent.lockLogicalDevice.Lock()
1067 defer agent.lockLogicalDevice.Unlock()
khenaidoo19d7b632018-10-30 10:49:50 -04001068 if agent.deviceGraph == nil {
khenaidoo910204f2019-04-08 17:56:40 -04001069 agent.deviceGraph = graph.NewDeviceGraph(agent.logicalDeviceId, agent.deviceMgr.GetDevice)
khenaidoo2c6a0992019-04-29 13:46:56 -04001070 }
1071 // Get all the logical ports on that logical device
1072 if lDevice, err := agent.getLogicalDeviceWithoutLock(); err != nil {
manikkaraj k259a6f72019-05-06 09:55:44 -04001073 log.Errorw("unknown-logical-device", log.Fields{"error": err, "logicalDeviceId": agent.logicalDeviceId})
khenaidoo2c6a0992019-04-29 13:46:56 -04001074 return err
1075 } else {
1076 //TODO: Find a better way to refresh only missing routes
1077 agent.deviceGraph.ComputeRoutes(lDevice.Ports)
1078 }
khenaidoo2c6a0992019-04-29 13:46:56 -04001079 agent.deviceGraph.Print()
1080 return nil
khenaidoo19d7b632018-10-30 10:49:50 -04001081}
1082
khenaidoo2c6a0992019-04-29 13:46:56 -04001083//updateDeviceGraph updates the device graph if not done already and setup the default rules as well
khenaidoo910204f2019-04-08 17:56:40 -04001084func (agent *LogicalDeviceAgent) updateDeviceGraph(lp *voltha.LogicalPort) {
khenaidoo2c6a0992019-04-29 13:46:56 -04001085 log.Debugf("updateDeviceGraph", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
1086 agent.lockLogicalDevice.Lock()
1087 defer agent.lockLogicalDevice.Unlock()
khenaidoo910204f2019-04-08 17:56:40 -04001088 if agent.deviceGraph == nil {
1089 agent.deviceGraph = graph.NewDeviceGraph(agent.logicalDeviceId, agent.deviceMgr.GetDevice)
1090 }
1091 agent.deviceGraph.AddPort(lp)
khenaidoo2c6a0992019-04-29 13:46:56 -04001092 agent.deviceGraph.Print()
khenaidoo19d7b632018-10-30 10:49:50 -04001093}
khenaidoofdbad6e2018-11-06 22:26:38 -05001094
khenaidoo3d3b8c22019-05-22 18:10:39 -04001095//generateDeviceGraph regenerates the device graph
1096func (agent *LogicalDeviceAgent) generateDeviceGraph() {
1097 log.Debugf("generateDeviceGraph", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo0a822f92019-05-08 15:15:57 -04001098 agent.lockLogicalDevice.Lock()
1099 defer agent.lockLogicalDevice.Unlock()
1100 // Get the latest logical device
1101 if ld, err := agent.getLogicalDeviceWithoutLock(); err != nil {
1102 log.Errorw("logical-device-not-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "error": err})
1103 } else {
khenaidoo3d3b8c22019-05-22 18:10:39 -04001104 log.Debugw("generating-graph", log.Fields{"lDeviceId": agent.logicalDeviceId, "deviceGraph": agent.deviceGraph, "lPorts": len(ld.Ports)})
1105 if agent.deviceGraph == nil {
1106 agent.deviceGraph = graph.NewDeviceGraph(agent.logicalDeviceId, agent.deviceMgr.GetDevice)
1107 }
khenaidoo0a822f92019-05-08 15:15:57 -04001108 agent.deviceGraph.ComputeRoutes(ld.Ports)
khenaidoo3d3b8c22019-05-22 18:10:39 -04001109 agent.deviceGraph.Print()
khenaidoo0a822f92019-05-08 15:15:57 -04001110 }
1111}
1112
khenaidoofc1314d2019-03-14 09:34:21 -04001113// portAdded is a callback invoked when a port is added to the logical device.
1114// TODO: To use when POST_ADD is fixed.
1115func (agent *LogicalDeviceAgent) portAdded(args ...interface{}) interface{} {
1116 log.Debugw("portAdded-callback", log.Fields{"argsLen": len(args)})
1117
1118 var port *voltha.LogicalPort
1119
1120 // Sanity check
1121 if args[0] != nil {
1122 log.Warnw("previous-data-not-nil", log.Fields{"args0": args[0]})
1123 }
1124 var ok bool
1125 if port, ok = args[1].(*voltha.LogicalPort); !ok {
1126 log.Errorw("invalid-args", log.Fields{"args1": args[1]})
1127 return nil
1128 }
1129
1130 // Set the proxy and callback for that port
1131 agent.portProxiesLock.Lock()
Stephane Barbarie40fd3b22019-04-23 21:50:47 -04001132 agent.portProxies[port.Id] = agent.clusterDataProxy.CreateProxy(
khenaidoofc1314d2019-03-14 09:34:21 -04001133 fmt.Sprintf("/logical_devices/%s/ports/%s", agent.logicalDeviceId, port.Id),
1134 false)
1135 agent.portProxies[port.Id].RegisterCallback(model.POST_UPDATE, agent.portUpdated)
1136 agent.portProxiesLock.Unlock()
1137
1138 // Send the port change event to the OF controller
1139 agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceId,
khenaidoo910204f2019-04-08 17:56:40 -04001140 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_ADD, Desc: port.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001141
1142 return nil
1143}
1144
1145// portRemoved is a callback invoked when a port is removed from the logical device.
1146// TODO: To use when POST_ADD is fixed.
1147func (agent *LogicalDeviceAgent) portRemoved(args ...interface{}) interface{} {
1148 log.Debugw("portRemoved-callback", log.Fields{"argsLen": len(args)})
1149
1150 var port *voltha.LogicalPort
1151
1152 // Sanity check
1153 if args[1] != nil {
1154 log.Warnw("data-not-nil", log.Fields{"args1": args[1]})
1155 }
1156 var ok bool
1157 if port, ok = args[0].(*voltha.LogicalPort); !ok {
1158 log.Errorw("invalid-args", log.Fields{"args0": args[0]})
1159 return nil
1160 }
1161
1162 // Remove the proxy and callback for that port
1163 agent.portProxiesLock.Lock()
1164 agent.portProxies[port.Id].UnregisterCallback(model.POST_UPDATE, agent.portUpdated)
1165 delete(agent.portProxies, port.Id)
1166 agent.portProxiesLock.Unlock()
1167
1168 // Send the port change event to the OF controller
1169 agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceId,
khenaidoo910204f2019-04-08 17:56:40 -04001170 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_DELETE, Desc: port.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001171
1172 return nil
1173}
1174
1175// 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 -04001176func diff(oldList, newList []*voltha.LogicalPort) (newPorts, changedPorts, deletedPorts []*voltha.LogicalPort) {
khenaidoofc1314d2019-03-14 09:34:21 -04001177 newPorts = make([]*voltha.LogicalPort, 0)
1178 changedPorts = make([]*voltha.LogicalPort, 0)
1179 deletedPorts = make([]*voltha.LogicalPort, 0)
1180 for _, o := range oldList {
1181 found := false
1182 changed := false
1183 for _, n := range newList {
1184 if o.Id == n.Id {
1185 changed = !reflect.DeepEqual(o, n)
1186 found = true
1187 break
1188 }
1189 }
1190 if !found {
1191 deletedPorts = append(deletedPorts, o)
1192 }
1193 if changed {
1194 changedPorts = append(changedPorts, o)
1195 }
1196 }
1197 for _, n := range newList {
1198 found := false
1199 for _, o := range oldList {
1200 if o.Id == n.Id {
1201 found = true
1202 break
1203 }
1204 }
1205 if !found {
1206 newPorts = append(newPorts, n)
1207 }
1208 }
1209 return
1210}
1211
1212// portUpdated is invoked when a port is updated on the logical device. Until
1213// the POST_ADD notification is fixed, we will use the logical device to
1214// update that data.
1215func (agent *LogicalDeviceAgent) portUpdated(args ...interface{}) interface{} {
1216 log.Debugw("portUpdated-callback", log.Fields{"argsLen": len(args)})
1217
1218 var oldLD *voltha.LogicalDevice
1219 var newlD *voltha.LogicalDevice
1220
1221 var ok bool
1222 if oldLD, ok = args[0].(*voltha.LogicalDevice); !ok {
1223 log.Errorw("invalid-args", log.Fields{"args0": args[0]})
1224 return nil
1225 }
1226 if newlD, ok = args[1].(*voltha.LogicalDevice); !ok {
1227 log.Errorw("invalid-args", log.Fields{"args1": args[1]})
1228 return nil
1229 }
1230
1231 if reflect.DeepEqual(oldLD.Ports, newlD.Ports) {
1232 log.Debug("ports-have-not-changed")
1233 return nil
1234 }
1235
1236 // Get the difference between the two list
1237 newPorts, changedPorts, deletedPorts := diff(oldLD.Ports, newlD.Ports)
1238
1239 // Send the port change events to the OF controller
khenaidoo2c6a0992019-04-29 13:46:56 -04001240 for _, newP := range newPorts {
khenaidoofc1314d2019-03-14 09:34:21 -04001241 go agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceId,
khenaidoo2c6a0992019-04-29 13:46:56 -04001242 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_ADD, Desc: newP.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001243 }
1244 for _, change := range changedPorts {
1245 go agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceId,
khenaidoo910204f2019-04-08 17:56:40 -04001246 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_MODIFY, Desc: change.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001247 }
1248 for _, del := range deletedPorts {
1249 go agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceId,
khenaidoo910204f2019-04-08 17:56:40 -04001250 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_DELETE, Desc: del.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001251 }
1252
1253 return nil
1254}
1255
khenaidoo8f474192019-04-03 17:20:44 -04001256// addNNILogicalPort adds an NNI port to the logical device. It returns a bool representing whether a port has been
1257// added and an eror in case a valid error is encountered. If the port was successfully added it will return
1258// (true, nil). If the device is not in the correct state it will return (false, nil) as this is a valid
1259// scenario. This also applies to the case where the port was already added.
khenaidoo910204f2019-04-08 17:56:40 -04001260func (agent *LogicalDeviceAgent) addNNILogicalPort(device *voltha.Device, port *voltha.Port) (bool, error) {
khenaidoo1ce37ad2019-03-24 22:07:24 -04001261 log.Debugw("addNNILogicalPort", log.Fields{"NNI": port})
khenaidoo8f474192019-04-03 17:20:44 -04001262 if device.AdminState != voltha.AdminState_ENABLED || device.OperStatus != voltha.OperStatus_ACTIVE {
1263 log.Infow("device-not-ready", log.Fields{"deviceId": device.Id, "admin": device.AdminState, "oper": device.OperStatus})
1264 return false, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001265 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001266 agent.lockLogicalDevice.RLock()
1267 if agent.portExist(device, port) {
1268 log.Debugw("port-already-exist", log.Fields{"port": port})
1269 agent.lockLogicalDevice.RUnlock()
khenaidoo8f474192019-04-03 17:20:44 -04001270 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001271 }
1272 agent.lockLogicalDevice.RUnlock()
1273
khenaidoofc1314d2019-03-14 09:34:21 -04001274 var portCap *ic.PortCapability
1275 var err error
1276 // First get the port capability
1277 if portCap, err = agent.deviceMgr.getPortCapability(nil, device.Id, port.PortNo); err != nil {
1278 log.Errorw("error-retrieving-port-capabilities", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001279 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001280 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001281
1282 agent.lockLogicalDevice.Lock()
1283 defer agent.lockLogicalDevice.Unlock()
1284 // Double check again if this port has been already added since the getPortCapability could have taken a long time
1285 if agent.portExist(device, port) {
1286 log.Debugw("port-already-exist", log.Fields{"port": port})
khenaidoo8f474192019-04-03 17:20:44 -04001287 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001288 }
1289
khenaidoofc1314d2019-03-14 09:34:21 -04001290 portCap.Port.RootPort = true
1291 lp := (proto.Clone(portCap.Port)).(*voltha.LogicalPort)
1292 lp.DeviceId = device.Id
1293 lp.Id = fmt.Sprintf("nni-%d", port.PortNo)
1294 lp.OfpPort.PortNo = port.PortNo
1295 lp.OfpPort.Name = lp.Id
1296 lp.DevicePortNo = port.PortNo
1297
khenaidoofc1314d2019-03-14 09:34:21 -04001298 var ld *voltha.LogicalDevice
1299 if ld, err = agent.getLogicalDeviceWithoutLock(); err != nil {
1300 log.Errorw("error-retrieving-logical-device", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001301 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001302 }
1303 cloned := (proto.Clone(ld)).(*voltha.LogicalDevice)
1304 if cloned.Ports == nil {
1305 cloned.Ports = make([]*voltha.LogicalPort, 0)
1306 }
1307 cloned.Ports = append(cloned.Ports, lp)
1308
1309 if err = agent.updateLogicalDeviceWithoutLock(cloned); err != nil {
1310 log.Errorw("error-updating-logical-device", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001311 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001312 }
khenaidoo910204f2019-04-08 17:56:40 -04001313
1314 // Update the device graph with this new logical port
1315 clonedLP := (proto.Clone(lp)).(*voltha.LogicalPort)
1316 go agent.updateDeviceGraph(clonedLP)
1317
khenaidoo8f474192019-04-03 17:20:44 -04001318 return true, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001319}
1320
khenaidoo910204f2019-04-08 17:56:40 -04001321func (agent *LogicalDeviceAgent) portExist(device *voltha.Device, port *voltha.Port) bool {
khenaidoo54544ae2019-03-18 13:22:39 -04001322 if ldevice, _ := agent.getLogicalDeviceWithoutLock(); ldevice != nil {
khenaidoofc1314d2019-03-14 09:34:21 -04001323 for _, lPort := range ldevice.Ports {
khenaidoo54544ae2019-03-18 13:22:39 -04001324 if lPort.DeviceId == device.Id && lPort.DevicePortNo == port.PortNo && lPort.Id == port.Label {
khenaidoofc1314d2019-03-14 09:34:21 -04001325 return true
1326 }
1327 }
1328 }
1329 return false
1330}
1331
khenaidoo8f474192019-04-03 17:20:44 -04001332// addUNILogicalPort adds an UNI port to the logical device. It returns a bool representing whether a port has been
1333// added and an eror in case a valid error is encountered. If the port was successfully added it will return
1334// (true, nil). If the device is not in the correct state it will return (false, nil) as this is a valid
1335// scenario. This also applies to the case where the port was already added.
khenaidoo910204f2019-04-08 17:56:40 -04001336func (agent *LogicalDeviceAgent) addUNILogicalPort(childDevice *voltha.Device, port *voltha.Port) (bool, error) {
khenaidoofc1314d2019-03-14 09:34:21 -04001337 log.Debugw("addUNILogicalPort", log.Fields{"port": port})
khenaidoo8f474192019-04-03 17:20:44 -04001338 if childDevice.AdminState != voltha.AdminState_ENABLED || childDevice.OperStatus != voltha.OperStatus_ACTIVE {
1339 log.Infow("device-not-ready", log.Fields{"deviceId": childDevice.Id, "admin": childDevice.AdminState, "oper": childDevice.OperStatus})
1340 return false, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001341 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001342 agent.lockLogicalDevice.RLock()
1343 if agent.portExist(childDevice, port) {
1344 log.Debugw("port-already-exist", log.Fields{"port": port})
1345 agent.lockLogicalDevice.RUnlock()
khenaidoo8f474192019-04-03 17:20:44 -04001346 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001347 }
1348 agent.lockLogicalDevice.RUnlock()
khenaidoofc1314d2019-03-14 09:34:21 -04001349 var portCap *ic.PortCapability
1350 var err error
1351 // First get the port capability
1352 if portCap, err = agent.deviceMgr.getPortCapability(nil, childDevice.Id, port.PortNo); err != nil {
1353 log.Errorw("error-retrieving-port-capabilities", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001354 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001355 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001356 agent.lockLogicalDevice.Lock()
1357 defer agent.lockLogicalDevice.Unlock()
1358 // Double check again if this port has been already added since the getPortCapability could have taken a long time
1359 if agent.portExist(childDevice, port) {
1360 log.Debugw("port-already-exist", log.Fields{"port": port})
khenaidoo8f474192019-04-03 17:20:44 -04001361 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001362 }
khenaidoofc1314d2019-03-14 09:34:21 -04001363 // Get stored logical device
1364 if ldevice, err := agent.getLogicalDeviceWithoutLock(); err != nil {
khenaidoo8f474192019-04-03 17:20:44 -04001365 return false, status.Error(codes.NotFound, agent.logicalDeviceId)
khenaidoofc1314d2019-03-14 09:34:21 -04001366 } else {
1367 log.Debugw("adding-uni", log.Fields{"deviceId": childDevice.Id})
1368 portCap.Port.RootPort = false
Matt Jeanneret3815e322019-03-12 19:15:49 -04001369 portCap.Port.Id = port.Label
1370 portCap.Port.OfpPort.PortNo = port.PortNo
khenaidoofc1314d2019-03-14 09:34:21 -04001371 portCap.Port.DeviceId = childDevice.Id
1372 portCap.Port.DevicePortNo = port.PortNo
1373 cloned := (proto.Clone(ldevice)).(*voltha.LogicalDevice)
1374 if cloned.Ports == nil {
1375 cloned.Ports = make([]*voltha.LogicalPort, 0)
1376 }
1377 cloned.Ports = append(cloned.Ports, portCap.Port)
khenaidoo910204f2019-04-08 17:56:40 -04001378 if err := agent.updateLogicalDeviceWithoutLock(cloned); err != nil {
1379 return false, err
1380 }
khenaidoo910204f2019-04-08 17:56:40 -04001381 // Update the device graph with this new logical port
1382 clonedLP := (proto.Clone(portCap.Port)).(*voltha.LogicalPort)
1383 go agent.updateDeviceGraph(clonedLP)
1384 return true, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001385 }
1386}
1387
khenaidoo43c82122018-11-22 18:38:28 -05001388func (agent *LogicalDeviceAgent) packetOut(packet *ofp.OfpPacketOut) {
khenaidoofdbad6e2018-11-06 22:26:38 -05001389 log.Debugw("packet-out", log.Fields{"packet": packet.GetInPort()})
khenaidoo68c930b2019-05-13 11:46:51 -04001390 outPort := fu.GetPacketOutPort(packet)
khenaidoofdbad6e2018-11-06 22:26:38 -05001391 //frame := packet.GetData()
1392 //TODO: Use a channel between the logical agent and the device agent
khenaidooca301322019-01-09 23:06:32 -05001393 if err := agent.deviceMgr.packetOut(agent.rootDeviceId, outPort, packet); err != nil {
khenaidoo910204f2019-04-08 17:56:40 -04001394 log.Error("packetout-failed", log.Fields{"logicalDeviceID": agent.rootDeviceId})
khenaidooca301322019-01-09 23:06:32 -05001395 }
khenaidoofdbad6e2018-11-06 22:26:38 -05001396}
1397
khenaidoo297cd252019-02-07 22:10:23 -05001398func (agent *LogicalDeviceAgent) packetIn(port uint32, transactionId string, packet []byte) {
1399 log.Debugw("packet-in", log.Fields{"port": port, "packet": packet, "transactionId": transactionId})
khenaidoo68c930b2019-05-13 11:46:51 -04001400 packetIn := fu.MkPacketIn(port, packet)
khenaidoo297cd252019-02-07 22:10:23 -05001401 agent.ldeviceMgr.grpcNbiHdlr.sendPacketIn(agent.logicalDeviceId, transactionId, packetIn)
khenaidooca301322019-01-09 23:06:32 -05001402 log.Debugw("sending-packet-in", log.Fields{"packet-in": packetIn})
khenaidoofdbad6e2018-11-06 22:26:38 -05001403}
khenaidoo2c6a0992019-04-29 13:46:56 -04001404
1405func (agent *LogicalDeviceAgent) addLogicalPortToMap(portNo uint32, nniPort bool) {
1406 agent.lockLogicalPortsNo.Lock()
1407 defer agent.lockLogicalPortsNo.Unlock()
1408 if exist := agent.logicalPortsNo[portNo]; !exist {
1409 agent.logicalPortsNo[portNo] = nniPort
1410 }
1411}
1412
khenaidoo3d3b8c22019-05-22 18:10:39 -04001413func (agent *LogicalDeviceAgent) addLogicalPortsToMap(lps []*voltha.LogicalPort) {
1414 agent.lockLogicalPortsNo.Lock()
1415 defer agent.lockLogicalPortsNo.Unlock()
1416 for _, lp := range lps {
1417 if exist := agent.logicalPortsNo[lp.DevicePortNo]; !exist {
1418 agent.logicalPortsNo[lp.DevicePortNo] = lp.RootPort
1419 }
1420 }
1421}
1422
khenaidoo2c6a0992019-04-29 13:46:56 -04001423func (agent *LogicalDeviceAgent) deleteLogicalPortFromMap(portNo uint32) {
1424 agent.lockLogicalPortsNo.Lock()
1425 defer agent.lockLogicalPortsNo.Unlock()
1426 if exist := agent.logicalPortsNo[portNo]; exist {
1427 delete(agent.logicalPortsNo, portNo)
1428 }
1429}
1430
1431func (agent *LogicalDeviceAgent) isNNIPort(portNo uint32) bool {
1432 agent.lockLogicalPortsNo.RLock()
1433 defer agent.lockLogicalPortsNo.RUnlock()
1434 if exist := agent.logicalPortsNo[portNo]; exist {
1435 return agent.logicalPortsNo[portNo]
1436 }
1437 return false
1438}
1439
1440func (agent *LogicalDeviceAgent) getFirstNNIPort() (uint32, error) {
1441 agent.lockLogicalPortsNo.RLock()
1442 defer agent.lockLogicalPortsNo.RUnlock()
1443 for portNo, nni := range agent.logicalPortsNo {
1444 if nni {
1445 return portNo, nil
1446 }
1447 }
1448 return 0, status.Error(codes.NotFound, "No NNI port found")
1449}