blob: bb25b4b0207cde9e24fcc74a6e257d1433cb8868 [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 {
khenaidoo910204f2019-04-08 17:56:40 -040038 logicalDeviceId string
khenaidoo8c3303d2019-02-13 14:59:39 -050039 //lastData *voltha.LogicalDevice
khenaidoo2c6a0992019-04-29 13:46:56 -040040 rootDeviceId string
41 deviceMgr *DeviceManager
42 ldeviceMgr *LogicalDeviceManager
43 clusterDataProxy *model.Proxy
44 exitChannel chan int
45 deviceGraph *graph.DeviceGraph
46 DefaultFlowRules *fu.DeviceRules
47 flowProxy *model.Proxy
48 groupProxy *model.Proxy
49 ldProxy *model.Proxy
50 portProxies map[string]*model.Proxy
51 portProxiesLock sync.RWMutex
52 lockLogicalDevice sync.RWMutex
53 logicalPortsNo map[uint32]bool //value is true for NNI port
54 lockLogicalPortsNo sync.RWMutex
55 flowDecomposer *fd.FlowDecomposer
56 includeDefaultFlows bool
57 defaultTimeout int64
khenaidoob9203542018-09-17 22:56:37 -040058}
59
Stephane Barbarie1ab43272018-12-08 21:42:13 -050060func newLogicalDeviceAgent(id string, deviceId string, ldeviceMgr *LogicalDeviceManager,
61 deviceMgr *DeviceManager,
khenaidoo2c6a0992019-04-29 13:46:56 -040062 cdProxy *model.Proxy, timeout int64) *LogicalDeviceAgent {
khenaidoob9203542018-09-17 22:56:37 -040063 var agent LogicalDeviceAgent
64 agent.exitChannel = make(chan int, 1)
65 agent.logicalDeviceId = id
Stephane Barbarie1ab43272018-12-08 21:42:13 -050066 agent.rootDeviceId = deviceId
khenaidoob9203542018-09-17 22:56:37 -040067 agent.deviceMgr = deviceMgr
khenaidoo9a468962018-09-19 15:33:13 -040068 agent.clusterDataProxy = cdProxy
khenaidoob9203542018-09-17 22:56:37 -040069 agent.ldeviceMgr = ldeviceMgr
khenaidoo19d7b632018-10-30 10:49:50 -040070 agent.flowDecomposer = fd.NewFlowDecomposer(agent.deviceMgr)
khenaidoo92e62c52018-10-03 14:02:54 -040071 agent.lockLogicalDevice = sync.RWMutex{}
khenaidoofc1314d2019-03-14 09:34:21 -040072 agent.portProxies = make(map[string]*model.Proxy)
73 agent.portProxiesLock = sync.RWMutex{}
khenaidoo2c6a0992019-04-29 13:46:56 -040074 agent.lockLogicalPortsNo = sync.RWMutex{}
75 agent.logicalPortsNo = make(map[uint32]bool)
76 agent.includeDefaultFlows = true
77 agent.defaultTimeout = timeout
khenaidoob9203542018-09-17 22:56:37 -040078 return &agent
79}
80
khenaidoo4d4802d2018-10-04 21:59:49 -040081// start creates the logical device and add it to the data model
khenaidoo297cd252019-02-07 22:10:23 -050082func (agent *LogicalDeviceAgent) start(ctx context.Context, loadFromdB bool) error {
83 log.Infow("starting-logical_device-agent", log.Fields{"logicaldeviceId": agent.logicalDeviceId, "loadFromdB": loadFromdB})
84 var ld *voltha.LogicalDevice
85 if !loadFromdB {
86 //Build the logical device based on information retrieved from the device adapter
87 var switchCap *ic.SwitchCapability
88 var err error
89 if switchCap, err = agent.deviceMgr.getSwitchCapability(ctx, agent.rootDeviceId); err != nil {
khenaidoob9203542018-09-17 22:56:37 -040090 log.Errorw("error-creating-logical-device", log.Fields{"error": err})
91 return err
92 }
khenaidoo297cd252019-02-07 22:10:23 -050093 ld = &voltha.LogicalDevice{Id: agent.logicalDeviceId, RootDeviceId: agent.rootDeviceId}
94
95 // Create the datapath ID (uint64) using the logical device ID (based on the MAC Address)
96 var datapathID uint64
97 if datapathID, err = CreateDataPathId(agent.logicalDeviceId); err != nil {
98 log.Errorw("error-creating-datapath-id", log.Fields{"error": err})
99 return err
100 }
101 ld.DatapathId = datapathID
102 ld.Desc = (proto.Clone(switchCap.Desc)).(*ofp.OfpDesc)
khenaidoo6d055132019-02-12 16:51:19 -0500103 log.Debugw("Switch-capability", log.Fields{"Desc": ld.Desc, "fromAd": switchCap.Desc})
khenaidoo297cd252019-02-07 22:10:23 -0500104 ld.SwitchFeatures = (proto.Clone(switchCap.SwitchFeatures)).(*ofp.OfpSwitchFeatures)
105 ld.Flows = &ofp.Flows{Items: nil}
106 ld.FlowGroups = &ofp.FlowGroups{Items: nil}
107
khenaidoo297cd252019-02-07 22:10:23 -0500108 agent.lockLogicalDevice.Lock()
khenaidoo297cd252019-02-07 22:10:23 -0500109 // Save the logical device
110 if added := agent.clusterDataProxy.AddWithID("/logical_devices", ld.Id, ld, ""); added == nil {
111 log.Errorw("failed-to-add-logical-device", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
112 } else {
113 log.Debugw("logicaldevice-created", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
114 }
115 agent.lockLogicalDevice.Unlock()
khenaidoofc1314d2019-03-14 09:34:21 -0400116
khenaidoo3d3b8c22019-05-22 18:10:39 -0400117 // TODO: Set the logical ports in a separate call once the port update issue is fixed.
118 go agent.setupLogicalPorts(ctx)
119
khenaidoo297cd252019-02-07 22:10:23 -0500120 } else {
121 // load from dB - the logical may not exist at this time. On error, just return and the calling function
122 // will destroy this agent.
123 var err error
124 if ld, err = agent.GetLogicalDevice(); err != nil {
125 log.Warnw("failed-to-load-logical-device", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
126 return err
127 }
khenaidoo3d3b8c22019-05-22 18:10:39 -0400128
khenaidoo8c3303d2019-02-13 14:59:39 -0500129 // Update the root device Id
130 agent.rootDeviceId = ld.RootDeviceId
khenaidoo3d3b8c22019-05-22 18:10:39 -0400131
132 // Setup the local list of logical ports
133 agent.addLogicalPortsToMap(ld.Ports)
134
135 // Setup the device graph
136 agent.generateDeviceGraph()
khenaidoob9203542018-09-17 22:56:37 -0400137 }
khenaidoo92e62c52018-10-03 14:02:54 -0400138 agent.lockLogicalDevice.Lock()
khenaidoo3d3b8c22019-05-22 18:10:39 -0400139 defer agent.lockLogicalDevice.Unlock()
khenaidoofc1314d2019-03-14 09:34:21 -0400140
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400141 agent.flowProxy = agent.clusterDataProxy.CreateProxy(
khenaidoo19d7b632018-10-30 10:49:50 -0400142 fmt.Sprintf("/logical_devices/%s/flows", agent.logicalDeviceId),
143 false)
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400144 agent.groupProxy = agent.clusterDataProxy.CreateProxy(
khenaidoo19d7b632018-10-30 10:49:50 -0400145 fmt.Sprintf("/logical_devices/%s/flow_groups", agent.logicalDeviceId),
146 false)
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400147 agent.ldProxy = agent.clusterDataProxy.CreateProxy(
khenaidoofc1314d2019-03-14 09:34:21 -0400148 fmt.Sprintf("/logical_devices/%s", agent.logicalDeviceId),
149 false)
khenaidoo19d7b632018-10-30 10:49:50 -0400150
khenaidoofc1314d2019-03-14 09:34:21 -0400151 // TODO: Use a port proxy once the POST_ADD is fixed
khenaidoo3d3b8c22019-05-22 18:10:39 -0400152 if agent.ldProxy != nil {
153 agent.ldProxy.RegisterCallback(model.POST_UPDATE, agent.portUpdated)
154 } else {
155 log.Errorw("logical-device-proxy-null", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
156 return status.Error(codes.Internal, "logical-device-proxy-null")
157 }
khenaidoobcf205b2019-01-25 22:21:14 -0500158
khenaidoo2c6a0992019-04-29 13:46:56 -0400159 agent.includeDefaultFlows = true
160
khenaidoob9203542018-09-17 22:56:37 -0400161 return nil
162}
163
khenaidoo4d4802d2018-10-04 21:59:49 -0400164// stop stops the logical devuce agent. This removes the logical device from the data model.
165func (agent *LogicalDeviceAgent) stop(ctx context.Context) {
166 log.Info("stopping-logical_device-agent")
167 agent.lockLogicalDevice.Lock()
168 defer agent.lockLogicalDevice.Unlock()
khenaidoo8c3303d2019-02-13 14:59:39 -0500169
khenaidoo4d4802d2018-10-04 21:59:49 -0400170 //Remove the logical device from the model
171 if removed := agent.clusterDataProxy.Remove("/logical_devices/"+agent.logicalDeviceId, ""); removed == nil {
172 log.Errorw("failed-to-remove-logical-device", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
173 } else {
174 log.Debugw("logicaldevice-removed", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
175 }
176 agent.exitChannel <- 1
177 log.Info("logical_device-agent-stopped")
178}
179
khenaidoo19d7b632018-10-30 10:49:50 -0400180// GetLogicalDevice locks the logical device model and then retrieves the latest logical device information
181func (agent *LogicalDeviceAgent) GetLogicalDevice() (*voltha.LogicalDevice, error) {
182 log.Debug("GetLogicalDevice")
khenaidoo1ce37ad2019-03-24 22:07:24 -0400183 agent.lockLogicalDevice.RLock()
184 defer agent.lockLogicalDevice.RUnlock()
khenaidoo8c3303d2019-02-13 14:59:39 -0500185 logicalDevice := agent.clusterDataProxy.Get("/logical_devices/"+agent.logicalDeviceId, 0, false, "")
khenaidoo92e62c52018-10-03 14:02:54 -0400186 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500187 return lDevice, nil
khenaidoo92e62c52018-10-03 14:02:54 -0400188 }
189 return nil, status.Errorf(codes.NotFound, "logical_device-%s", agent.logicalDeviceId)
190}
191
khenaidoo19d7b632018-10-30 10:49:50 -0400192func (agent *LogicalDeviceAgent) ListLogicalDevicePorts() (*voltha.LogicalPorts, error) {
khenaidoo1ce37ad2019-03-24 22:07:24 -0400193 log.Debug("ListLogicalDevicePorts")
194 agent.lockLogicalDevice.RLock()
195 defer agent.lockLogicalDevice.RUnlock()
khenaidoo8c3303d2019-02-13 14:59:39 -0500196 logicalDevice := agent.clusterDataProxy.Get("/logical_devices/"+agent.logicalDeviceId, 0, false, "")
khenaidoo19d7b632018-10-30 10:49:50 -0400197 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
198 lPorts := make([]*voltha.LogicalPort, 0)
199 for _, port := range lDevice.Ports {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500200 lPorts = append(lPorts, port)
khenaidoo19d7b632018-10-30 10:49:50 -0400201 }
202 return &voltha.LogicalPorts{Items: lPorts}, nil
203 }
204 return nil, status.Errorf(codes.NotFound, "logical_device-%s", agent.logicalDeviceId)
205}
206
207// listFlows locks the logical device model and then retrieves the latest flow information
208func (agent *LogicalDeviceAgent) listFlows() []*ofp.OfpFlowStats {
209 log.Debug("listFlows")
khenaidoo1ce37ad2019-03-24 22:07:24 -0400210 agent.lockLogicalDevice.RLock()
211 defer agent.lockLogicalDevice.RUnlock()
khenaidoo8c3303d2019-02-13 14:59:39 -0500212 logicalDevice := agent.clusterDataProxy.Get("/logical_devices/"+agent.logicalDeviceId, 0, false, "")
khenaidoo19d7b632018-10-30 10:49:50 -0400213 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
214 return lDevice.Flows.Items
215 }
216 return nil
217}
218
219// listFlowGroups locks the logical device model and then retrieves the latest flow groups information
220func (agent *LogicalDeviceAgent) listFlowGroups() []*ofp.OfpGroupEntry {
221 log.Debug("listFlowGroups")
khenaidoo1ce37ad2019-03-24 22:07:24 -0400222 agent.lockLogicalDevice.RLock()
223 defer agent.lockLogicalDevice.RUnlock()
khenaidoo8c3303d2019-02-13 14:59:39 -0500224 logicalDevice := agent.clusterDataProxy.Get("/logical_devices/"+agent.logicalDeviceId, 0, false, "")
khenaidoo19d7b632018-10-30 10:49:50 -0400225 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
226 return lDevice.FlowGroups.Items
227 }
228 return nil
229}
230
khenaidoo43c82122018-11-22 18:38:28 -0500231//updateLogicalDeviceWithoutLock updates the model with the logical device. It clones the logicaldevice before saving it
232func (agent *LogicalDeviceAgent) updateLogicalDeviceFlowsWithoutLock(flows *ofp.Flows) error {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500233 afterUpdate := agent.flowProxy.Update("/", flows, false, "")
khenaidoo43c82122018-11-22 18:38:28 -0500234 if afterUpdate == nil {
235 return status.Errorf(codes.Internal, "failed-updating-logical-device-flows:%s", agent.logicalDeviceId)
236 }
khenaidoo43c82122018-11-22 18:38:28 -0500237 return nil
238}
239
240//updateLogicalDeviceWithoutLock updates the model with the logical device. It clones the logicaldevice before saving it
241func (agent *LogicalDeviceAgent) updateLogicalDeviceFlowGroupsWithoutLock(flowGroups *ofp.FlowGroups) error {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500242 afterUpdate := agent.groupProxy.Update("/", flowGroups, false, "")
khenaidoo43c82122018-11-22 18:38:28 -0500243 if afterUpdate == nil {
244 return status.Errorf(codes.Internal, "failed-updating-logical-device-flow-groups:%s", agent.logicalDeviceId)
245 }
khenaidoo43c82122018-11-22 18:38:28 -0500246 return nil
247}
248
khenaidoo4d4802d2018-10-04 21:59:49 -0400249// getLogicalDeviceWithoutLock retrieves a logical device from the model without locking it. This is used only by
250// functions that have already acquired the logical device lock to the model
khenaidoo92e62c52018-10-03 14:02:54 -0400251func (agent *LogicalDeviceAgent) getLogicalDeviceWithoutLock() (*voltha.LogicalDevice, error) {
252 log.Debug("getLogicalDeviceWithoutLock")
khenaidoo8c3303d2019-02-13 14:59:39 -0500253 logicalDevice := agent.clusterDataProxy.Get("/logical_devices/"+agent.logicalDeviceId, 0, false, "")
khenaidoo92e62c52018-10-03 14:02:54 -0400254 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
khenaidoo1ce37ad2019-03-24 22:07:24 -0400255 //log.Debug("getLogicalDeviceWithoutLock", log.Fields{"ldevice": lDevice})
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500256 return lDevice, nil
khenaidoo92e62c52018-10-03 14:02:54 -0400257 }
258 return nil, status.Errorf(codes.NotFound, "logical_device-%s", agent.logicalDeviceId)
259}
260
khenaidoo2c6a0992019-04-29 13:46:56 -0400261func (agent *LogicalDeviceAgent) updateLogicalPort(device *voltha.Device, port *voltha.Port) error {
262 log.Debugw("updateLogicalPort", log.Fields{"deviceId": device.Id, "port": port})
263 var err error
264 if port.Type == voltha.Port_ETHERNET_NNI {
265 if _, err = agent.addNNILogicalPort(device, port); err != nil {
266 return err
267 }
268 agent.addLogicalPortToMap(port.PortNo, true)
269 } else if port.Type == voltha.Port_ETHERNET_UNI {
270 if _, err = agent.addUNILogicalPort(device, port); err != nil {
271 return err
272 }
273 agent.addLogicalPortToMap(port.PortNo, false)
274 } else {
275 // Update the device graph to ensure all routes on the logical device have been calculated
276 if err = agent.updateRoutes(device, port); err != nil {
277 log.Errorw("failed-to-update-routes", log.Fields{"deviceId": device.Id, "port": port, "error": err})
278 return err
279 }
280 }
281 return nil
282}
283
khenaidoo910204f2019-04-08 17:56:40 -0400284func (agent *LogicalDeviceAgent) addLogicalPort(device *voltha.Device, port *voltha.Port) error {
khenaidoo8f474192019-04-03 17:20:44 -0400285 log.Debugw("addLogicalPort", log.Fields{"deviceId": device.Id, "port": port})
khenaidoo8f474192019-04-03 17:20:44 -0400286 var err error
khenaidoofc1314d2019-03-14 09:34:21 -0400287 if port.Type == voltha.Port_ETHERNET_NNI {
khenaidoo910204f2019-04-08 17:56:40 -0400288 if _, err = agent.addNNILogicalPort(device, port); err != nil {
khenaidoofc1314d2019-03-14 09:34:21 -0400289 return err
290 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400291 agent.addLogicalPortToMap(port.PortNo, true)
khenaidoofc1314d2019-03-14 09:34:21 -0400292 } else if port.Type == voltha.Port_ETHERNET_UNI {
khenaidoo910204f2019-04-08 17:56:40 -0400293 if _, err = agent.addUNILogicalPort(device, port); err != nil {
khenaidoofc1314d2019-03-14 09:34:21 -0400294 return err
295 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400296 agent.addLogicalPortToMap(port.PortNo, false)
khenaidoofc1314d2019-03-14 09:34:21 -0400297 } else {
298 log.Debugw("invalid-port-type", log.Fields{"deviceId": device.Id, "port": port})
299 return nil
300 }
khenaidoofc1314d2019-03-14 09:34:21 -0400301 return nil
302}
303
khenaidoo3d3b8c22019-05-22 18:10:39 -0400304// setupLogicalPorts is invoked once the logical device has been created and is ready to get ports
305// added to it. While the logical device was being created we could have received requests to add
306// NNI and UNI ports which were discarded. Now is the time to add them if needed
307func (agent *LogicalDeviceAgent) setupLogicalPorts(ctx context.Context) error {
308 log.Infow("setupLogicalPorts", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
309 // First add any NNI ports which could have been missing
310 if err := agent.setupNNILogicalPorts(nil, agent.rootDeviceId); err != nil {
311 log.Errorw("error-setting-up-NNI-ports", log.Fields{"error": err, "deviceId": agent.rootDeviceId})
312 return err
313 }
314
315 // Now, set up the UNI ports if needed.
316 if children, err := agent.deviceMgr.getAllChildDevices(agent.rootDeviceId); err != nil {
317 log.Errorw("error-getting-child-devices", log.Fields{"error": err, "deviceId": agent.rootDeviceId})
318 return err
319 } else {
320 chnlsList := make([]chan interface{}, 0)
321 for _, child := range children.Items {
322 ch := make(chan interface{})
323 chnlsList = append(chnlsList, ch)
324 go func(device *voltha.Device, ch chan interface{}) {
325 if err = agent.setupUNILogicalPorts(nil, device); err != nil {
326 log.Error("setting-up-UNI-ports-failed", log.Fields{"deviceID": device.Id})
327 ch <- status.Errorf(codes.Internal, "UNI-ports-setup-failed: %s", device.Id)
328 }
329 ch <- nil
330 }(child, ch)
331 }
332 // Wait for completion
333 if res := fu.WaitForNilOrErrorResponses(agent.defaultTimeout, chnlsList...); res != nil {
334 return status.Errorf(codes.Aborted, "errors-%s", res)
335 }
336 }
337 return nil
338}
339
khenaidoofc1314d2019-03-14 09:34:21 -0400340// setupNNILogicalPorts creates an NNI port on the logical device that represents an NNI interface on a root device
341func (agent *LogicalDeviceAgent) setupNNILogicalPorts(ctx context.Context, deviceId string) error {
342 log.Infow("setupNNILogicalPorts-start", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoob9203542018-09-17 22:56:37 -0400343 // Build the logical device based on information retrieved from the device adapter
khenaidoofc1314d2019-03-14 09:34:21 -0400344 var err error
345
346 var device *voltha.Device
347 if device, err = agent.deviceMgr.GetDevice(deviceId); err != nil {
khenaidoo2c6a0992019-04-29 13:46:56 -0400348 log.Errorw("error-retrieving-device", log.Fields{"error": err, "deviceId": deviceId})
khenaidoofc1314d2019-03-14 09:34:21 -0400349 return err
350 }
351
352 //Get UNI port number
khenaidoofc1314d2019-03-14 09:34:21 -0400353 for _, port := range device.Ports {
354 if port.Type == voltha.Port_ETHERNET_NNI {
khenaidoo910204f2019-04-08 17:56:40 -0400355 if _, err = agent.addNNILogicalPort(device, port); err != nil {
khenaidoofc1314d2019-03-14 09:34:21 -0400356 log.Errorw("error-adding-UNI-port", log.Fields{"error": err})
khenaidoofc1314d2019-03-14 09:34:21 -0400357 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400358 agent.addLogicalPortToMap(port.PortNo, true)
khenaidoofc1314d2019-03-14 09:34:21 -0400359 }
360 }
khenaidoofc1314d2019-03-14 09:34:21 -0400361 return err
362}
363
khenaidoo3ab34882019-05-02 21:33:30 -0400364// updatePortsState updates the ports state related to the device
365func (agent *LogicalDeviceAgent) updatePortsState(device *voltha.Device, state voltha.AdminState_AdminState) error {
366 log.Infow("updatePortsState-start", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
367 agent.lockLogicalDevice.Lock()
368 defer agent.lockLogicalDevice.Unlock()
369 // Get the latest logical device info
370 if ld, err := agent.getLogicalDeviceWithoutLock(); err != nil {
371 log.Warnw("logical-device-unknown", log.Fields{"ldeviceId": agent.logicalDeviceId, "error": err})
372 return err
373 } else {
374 cloned := (proto.Clone(ld)).(*voltha.LogicalDevice)
375 for _, lport := range cloned.Ports {
376 if lport.DeviceId == device.Id {
377 switch state {
378 case voltha.AdminState_ENABLED:
379 lport.OfpPort.Config = lport.OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
khenaidoo0a822f92019-05-08 15:15:57 -0400380 lport.OfpPort.State = uint32(ofp.OfpPortState_OFPPS_LIVE)
khenaidoo3ab34882019-05-02 21:33:30 -0400381 case voltha.AdminState_DISABLED:
382 lport.OfpPort.Config = lport.OfpPort.Config | uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
khenaidoo0a822f92019-05-08 15:15:57 -0400383 lport.OfpPort.State = uint32(ofp.OfpPortState_OFPPS_LINK_DOWN)
khenaidoo3ab34882019-05-02 21:33:30 -0400384 default:
385 log.Warnw("unsupported-state-change", log.Fields{"deviceId": device.Id, "state": state})
386 }
387 }
388 }
389 // Updating the logical device will trigger the poprt change events to be populated to the controller
390 if err := agent.updateLogicalDeviceWithoutLock(cloned); err != nil {
391 log.Warnw("logical-device-update-failed", log.Fields{"ldeviceId": agent.logicalDeviceId, "error": err})
392 return err
393 }
394 }
395 return nil
396}
397
khenaidoofc1314d2019-03-14 09:34:21 -0400398// setupUNILogicalPorts creates a UNI port on the logical device that represents a child UNI interface
399func (agent *LogicalDeviceAgent) setupUNILogicalPorts(ctx context.Context, childDevice *voltha.Device) error {
khenaidoo3d3b8c22019-05-22 18:10:39 -0400400 log.Infow("setupUNILogicalPort", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoofc1314d2019-03-14 09:34:21 -0400401 // Build the logical device based on information retrieved from the device adapter
khenaidoob9203542018-09-17 22:56:37 -0400402 var err error
khenaidoo19d7b632018-10-30 10:49:50 -0400403
404 //Get UNI port number
khenaidoo19d7b632018-10-30 10:49:50 -0400405 for _, port := range childDevice.Ports {
406 if port.Type == voltha.Port_ETHERNET_UNI {
khenaidoo910204f2019-04-08 17:56:40 -0400407 if _, err = agent.addUNILogicalPort(childDevice, port); err != nil {
khenaidoofc1314d2019-03-14 09:34:21 -0400408 log.Errorw("error-adding-UNI-port", log.Fields{"error": err})
khenaidoofc1314d2019-03-14 09:34:21 -0400409 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400410 agent.addLogicalPortToMap(port.PortNo, false)
khenaidoo19d7b632018-10-30 10:49:50 -0400411 }
412 }
khenaidoofc1314d2019-03-14 09:34:21 -0400413 return err
khenaidoo92e62c52018-10-03 14:02:54 -0400414}
415
khenaidoo0a822f92019-05-08 15:15:57 -0400416// deleteAllLogicalPorts deletes all logical ports associated with this device
417func (agent *LogicalDeviceAgent) deleteAllLogicalPorts(device *voltha.Device) error {
418 log.Infow("updatePortsState-start", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
419 agent.lockLogicalDevice.Lock()
420 defer agent.lockLogicalDevice.Unlock()
421 // Get the latest logical device info
422 if ld, err := agent.getLogicalDeviceWithoutLock(); err != nil {
423 log.Warnw("logical-device-unknown", log.Fields{"ldeviceId": agent.logicalDeviceId, "error": err})
424 return err
425 } else {
426 cloned := (proto.Clone(ld)).(*voltha.LogicalDevice)
427 updateLogicalPorts := []*voltha.LogicalPort{}
428 for _, lport := range cloned.Ports {
429 if lport.DeviceId != device.Id {
430 updateLogicalPorts = append(updateLogicalPorts, lport)
431 }
432 }
433 if len(updateLogicalPorts) < len(cloned.Ports) {
434 cloned.Ports = updateLogicalPorts
435 // Updating the logical device will trigger the poprt change events to be populated to the controller
436 if err := agent.updateLogicalDeviceWithoutLock(cloned); err != nil {
437 log.Warnw("logical-device-update-failed", log.Fields{"ldeviceId": agent.logicalDeviceId, "error": err})
438 return err
439 }
440 } else {
441 log.Debugw("no-change-required", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
442 }
443 }
444 return nil
445}
446
khenaidoo92e62c52018-10-03 14:02:54 -0400447//updateLogicalDeviceWithoutLock updates the model with the logical device. It clones the logicaldevice before saving it
448func (agent *LogicalDeviceAgent) updateLogicalDeviceWithoutLock(logicalDevice *voltha.LogicalDevice) error {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500449 afterUpdate := agent.clusterDataProxy.Update("/logical_devices/"+agent.logicalDeviceId, logicalDevice, false, "")
khenaidoo92e62c52018-10-03 14:02:54 -0400450 if afterUpdate == nil {
451 return status.Errorf(codes.Internal, "failed-updating-logical-device:%s", agent.logicalDeviceId)
452 }
453 return nil
454}
455
khenaidoo19d7b632018-10-30 10:49:50 -0400456//updateFlowTable updates the flow table of that logical device
457func (agent *LogicalDeviceAgent) updateFlowTable(ctx context.Context, flow *ofp.OfpFlowMod) error {
458 log.Debug("updateFlowTable")
459 if flow == nil {
460 return nil
461 }
462 switch flow.GetCommand() {
463 case ofp.OfpFlowModCommand_OFPFC_ADD:
464 return agent.flowAdd(flow)
465 case ofp.OfpFlowModCommand_OFPFC_DELETE:
466 return agent.flowDelete(flow)
467 case ofp.OfpFlowModCommand_OFPFC_DELETE_STRICT:
468 return agent.flowDeleteStrict(flow)
469 case ofp.OfpFlowModCommand_OFPFC_MODIFY:
470 return agent.flowModify(flow)
471 case ofp.OfpFlowModCommand_OFPFC_MODIFY_STRICT:
472 return agent.flowModifyStrict(flow)
473 }
474 return status.Errorf(codes.Internal,
475 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceId, flow.GetCommand())
476}
477
478//updateGroupTable updates the group table of that logical device
479func (agent *LogicalDeviceAgent) updateGroupTable(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
480 log.Debug("updateGroupTable")
481 if groupMod == nil {
482 return nil
483 }
484 switch groupMod.GetCommand() {
485 case ofp.OfpGroupModCommand_OFPGC_ADD:
486 return agent.groupAdd(groupMod)
487 case ofp.OfpGroupModCommand_OFPGC_DELETE:
488 return agent.groupDelete(groupMod)
489 case ofp.OfpGroupModCommand_OFPGC_MODIFY:
490 return agent.groupModify(groupMod)
491 }
492 return status.Errorf(codes.Internal,
493 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceId, groupMod.GetCommand())
494}
495
khenaidoo19d7b632018-10-30 10:49:50 -0400496//flowAdd adds a flow to the flow table of that logical device
497func (agent *LogicalDeviceAgent) flowAdd(mod *ofp.OfpFlowMod) error {
498 log.Debug("flowAdd")
499 if mod == nil {
500 return nil
501 }
khenaidoo92e62c52018-10-03 14:02:54 -0400502 agent.lockLogicalDevice.Lock()
503 defer agent.lockLogicalDevice.Unlock()
khenaidoo19d7b632018-10-30 10:49:50 -0400504
505 var lDevice *voltha.LogicalDevice
506 var err error
507 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
508 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
509 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
510 }
511
512 var flows []*ofp.OfpFlowStats
513 if lDevice.Flows != nil && lDevice.Flows.Items != nil {
514 flows = lDevice.Flows.Items
515 }
516
khenaidoo2c6a0992019-04-29 13:46:56 -0400517 updatedFlows := make([]*ofp.OfpFlowStats, 0)
khenaidoo43c82122018-11-22 18:38:28 -0500518 //oldData := proto.Clone(lDevice.Flows).(*voltha.Flows)
khenaidoo19d7b632018-10-30 10:49:50 -0400519 changed := false
520 checkOverlap := (mod.Flags & uint32(ofp.OfpFlowModFlags_OFPFF_CHECK_OVERLAP)) != 0
521 if checkOverlap {
522 if overlapped := fu.FindOverlappingFlows(flows, mod); len(overlapped) != 0 {
523 // TODO: should this error be notified other than being logged?
524 log.Warnw("overlapped-flows", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
525 } else {
526 // Add flow
khenaidoo68c930b2019-05-13 11:46:51 -0400527 flow := fu.FlowStatsEntryFromFlowModMessage(mod)
khenaidoo19d7b632018-10-30 10:49:50 -0400528 flows = append(flows, flow)
khenaidoo2c6a0992019-04-29 13:46:56 -0400529 updatedFlows = append(updatedFlows, flow)
khenaidoo19d7b632018-10-30 10:49:50 -0400530 changed = true
531 }
532 } else {
khenaidoo68c930b2019-05-13 11:46:51 -0400533 flow := fu.FlowStatsEntryFromFlowModMessage(mod)
khenaidoo19d7b632018-10-30 10:49:50 -0400534 idx := fu.FindFlows(flows, flow)
535 if idx >= 0 {
536 oldFlow := flows[idx]
537 if (mod.Flags & uint32(ofp.OfpFlowModFlags_OFPFF_RESET_COUNTS)) != 0 {
538 flow.ByteCount = oldFlow.ByteCount
539 flow.PacketCount = oldFlow.PacketCount
540 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400541 if !reflect.DeepEqual(oldFlow, flow) {
542 flows[idx] = flow
543 updatedFlows = append(updatedFlows, flow)
544 changed = true
545 }
khenaidoo19d7b632018-10-30 10:49:50 -0400546 } else {
547 flows = append(flows, flow)
khenaidoo2c6a0992019-04-29 13:46:56 -0400548 updatedFlows = append(updatedFlows, flow)
549 changed = true
khenaidoo19d7b632018-10-30 10:49:50 -0400550 }
khenaidoo19d7b632018-10-30 10:49:50 -0400551 }
552 if changed {
khenaidoo2c6a0992019-04-29 13:46:56 -0400553 // Launch a routine to decompose the flows
554 if err := agent.decomposeAndSendFlows(&ofp.Flows{Items: updatedFlows}, lDevice.FlowGroups, agent.includeDefaultFlows); err != nil {
manikkaraj k259a6f72019-05-06 09:55:44 -0400555 log.Errorw("decomposing-and-sending-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo2c6a0992019-04-29 13:46:56 -0400556 return err
557 }
558
559 // We no longer need to sent the default flows, unless there is a change in device topology
560 agent.includeDefaultFlows = false
561
khenaidoo19d7b632018-10-30 10:49:50 -0400562 // Update model
khenaidoo43c82122018-11-22 18:38:28 -0500563 flowsToUpdate := &ofp.Flows{}
564 if lDevice.Flows != nil {
565 flowsToUpdate = &ofp.Flows{Items: flows}
khenaidoo19d7b632018-10-30 10:49:50 -0400566 }
khenaidoo43c82122018-11-22 18:38:28 -0500567 if err := agent.updateLogicalDeviceFlowsWithoutLock(flowsToUpdate); err != nil {
khenaidoo2c6a0992019-04-29 13:46:56 -0400568 log.Errorw("db-flow-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400569 return err
570 }
571 }
khenaidoo19d7b632018-10-30 10:49:50 -0400572 return nil
573}
574
khenaidoo2c6a0992019-04-29 13:46:56 -0400575func (agent *LogicalDeviceAgent) decomposeAndSendFlows(flows *ofp.Flows, groups *ofp.FlowGroups, includeDefaultFlows bool) error {
576 log.Debugw("decomposeAndSendFlows", log.Fields{"logicalDeviceID": agent.logicalDeviceId})
577
578 deviceRules := agent.flowDecomposer.DecomposeRules(agent, *flows, *groups, includeDefaultFlows)
579 log.Debugw("rules", log.Fields{"rules": deviceRules.String()})
580
581 chnlsList := make([]chan interface{}, 0)
582 for deviceId, value := range deviceRules.GetRules() {
583 ch := make(chan interface{})
584 chnlsList = append(chnlsList, ch)
585 go func(deviceId string, flows []*ofp.OfpFlowStats, groups []*ofp.OfpGroupEntry) {
586 if err := agent.deviceMgr.addFlowsAndGroups(deviceId, flows, groups); err != nil {
587 log.Error("flow-update-failed", log.Fields{"deviceID": deviceId})
588 ch <- status.Errorf(codes.Internal, "flow-update-failed: %s", deviceId)
589 }
590 ch <- nil
591 }(deviceId, value.ListFlows(), value.ListGroups())
592 }
593 // Wait for completion
594 if res := fu.WaitForNilOrErrorResponses(agent.defaultTimeout, chnlsList...); res != nil {
595 return status.Errorf(codes.Aborted, "errors-%s", res)
596 }
597 return nil
598}
599
khenaidoo19d7b632018-10-30 10:49:50 -0400600//flowDelete deletes a flow from the flow table of that logical device
601func (agent *LogicalDeviceAgent) flowDelete(mod *ofp.OfpFlowMod) error {
602 log.Debug("flowDelete")
603 if mod == nil {
604 return nil
605 }
606 agent.lockLogicalDevice.Lock()
607 defer agent.lockLogicalDevice.Unlock()
608
609 var lDevice *voltha.LogicalDevice
610 var err error
611 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
612 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
613 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
614 }
615 flows := lDevice.Flows.Items
616
617 //build a list of what to keep vs what to delete
618 toKeep := make([]*ofp.OfpFlowStats, 0)
619 for _, f := range flows {
620 if !fu.FlowMatchesMod(f, mod) {
621 toKeep = append(toKeep, f)
622 }
623 }
624
625 //Update flows
626 if len(toKeep) < len(flows) {
khenaidoo43c82122018-11-22 18:38:28 -0500627 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: toKeep}); err != nil {
628 log.Errorw("Cannot-update-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400629 return err
630 }
631 }
632
633 //TODO: send announcement on delete
634 return nil
635}
636
637//flowStatsDelete deletes a flow from the flow table of that logical device
638func (agent *LogicalDeviceAgent) flowStatsDelete(flow *ofp.OfpFlowStats) error {
639 log.Debug("flowStatsDelete")
640 if flow == nil {
641 return nil
642 }
643 agent.lockLogicalDevice.Lock()
644 defer agent.lockLogicalDevice.Unlock()
645
646 var lDevice *voltha.LogicalDevice
647 var err error
648 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
649 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
650 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
651 }
652 flows := lDevice.Flows.Items
653
654 //build a list of what to keep vs what to delete
655 toKeep := make([]*ofp.OfpFlowStats, 0)
656 for _, f := range flows {
657 if !fu.FlowMatch(f, flow) {
658 toKeep = append(toKeep, f)
659 }
660 }
661
662 //Update flows
663 if len(toKeep) < len(flows) {
khenaidoo43c82122018-11-22 18:38:28 -0500664 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: toKeep}); err != nil {
khenaidoo19d7b632018-10-30 10:49:50 -0400665 log.Errorw("Cannot-update-logical-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
666 return err
667 }
668 }
669 return nil
670}
671
672//flowDeleteStrict deletes a flow from the flow table of that logical device
673func (agent *LogicalDeviceAgent) flowDeleteStrict(mod *ofp.OfpFlowMod) error {
674 log.Debug("flowDeleteStrict")
675 if mod == nil {
676 return nil
677 }
678 agent.lockLogicalDevice.Lock()
679 defer agent.lockLogicalDevice.Unlock()
680
681 var lDevice *voltha.LogicalDevice
682 var err error
683 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
684 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
685 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
686 }
687 flows := lDevice.Flows.Items
688 changed := false
khenaidoo68c930b2019-05-13 11:46:51 -0400689 flow := fu.FlowStatsEntryFromFlowModMessage(mod)
khenaidoo19d7b632018-10-30 10:49:50 -0400690 idx := fu.FindFlows(flows, flow)
691 if idx >= 0 {
692 flows = append(flows[:idx], flows[idx+1:]...)
693 changed = true
694 } else {
695 return errors.New(fmt.Sprintf("Cannot delete flow - %s", flow))
696 }
697
698 if changed {
khenaidoo43c82122018-11-22 18:38:28 -0500699 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: flows}); err != nil {
khenaidoo19d7b632018-10-30 10:49:50 -0400700 log.Errorw("Cannot-update-logical-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
701 return err
702 }
703 }
704
705 return nil
706}
707
708//flowModify modifies a flow from the flow table of that logical device
709func (agent *LogicalDeviceAgent) flowModify(mod *ofp.OfpFlowMod) error {
710 return errors.New("flowModify not implemented")
711}
712
713//flowModifyStrict deletes a flow from the flow table of that logical device
714func (agent *LogicalDeviceAgent) flowModifyStrict(mod *ofp.OfpFlowMod) error {
715 return errors.New("flowModifyStrict not implemented")
716}
717
718func (agent *LogicalDeviceAgent) groupAdd(groupMod *ofp.OfpGroupMod) error {
719 log.Debug("groupAdd")
720 if groupMod == nil {
721 return nil
722 }
723 agent.lockLogicalDevice.Lock()
724 defer agent.lockLogicalDevice.Unlock()
725
726 var lDevice *voltha.LogicalDevice
727 var err error
728 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
729 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
730 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
731 }
732 groups := lDevice.FlowGroups.Items
khenaidoo19d7b632018-10-30 10:49:50 -0400733 if fu.FindGroup(groups, groupMod.GroupId) == -1 {
khenaidoo68c930b2019-05-13 11:46:51 -0400734 groups = append(groups, fu.GroupEntryFromGroupMod(groupMod))
khenaidoo43c82122018-11-22 18:38:28 -0500735 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(&ofp.FlowGroups{Items: groups}); err != nil {
736 log.Errorw("Cannot-update-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400737 return err
738 }
739 } else {
740 return errors.New(fmt.Sprintf("Groups %d already present", groupMod.GroupId))
741 }
khenaidoo19d7b632018-10-30 10:49:50 -0400742 return nil
743}
744
745func (agent *LogicalDeviceAgent) groupDelete(groupMod *ofp.OfpGroupMod) error {
746 log.Debug("groupDelete")
747 if groupMod == nil {
748 return nil
749 }
750 agent.lockLogicalDevice.Lock()
751 defer agent.lockLogicalDevice.Unlock()
752
753 var lDevice *voltha.LogicalDevice
754 var err error
755 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
756 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
757 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
758 }
759 groups := lDevice.FlowGroups.Items
760 flows := lDevice.Flows.Items
761 groupsChanged := false
762 flowsChanged := false
763 groupId := groupMod.GroupId
764 if groupId == uint32(ofp.OfpGroup_OFPG_ALL) {
765 //TODO we must delete all flows that point to this group and
766 //signal controller as requested by flow's flag
767 groups = []*ofp.OfpGroupEntry{}
768 groupsChanged = true
769 } else {
770 if idx := fu.FindGroup(groups, groupId); idx == -1 {
771 return nil // Valid case
772 } else {
773 flowsChanged, flows = fu.FlowsDeleteByGroupId(flows, groupId)
774 groups = append(groups[:idx], groups[idx+1:]...)
775 groupsChanged = true
776 }
777 }
khenaidoo43c82122018-11-22 18:38:28 -0500778 if groupsChanged {
779 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(&ofp.FlowGroups{Items: groups}); err != nil {
780 log.Errorw("Cannot-update-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400781 return err
782 }
783 }
khenaidoo43c82122018-11-22 18:38:28 -0500784 if flowsChanged {
785 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: flows}); err != nil {
786 log.Errorw("Cannot-update-flow", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
787 return err
788 }
789 }
790
khenaidoo19d7b632018-10-30 10:49:50 -0400791 return nil
792}
793
794func (agent *LogicalDeviceAgent) groupModify(groupMod *ofp.OfpGroupMod) error {
795 log.Debug("groupModify")
796 if groupMod == nil {
797 return nil
798 }
799 agent.lockLogicalDevice.Lock()
800 defer agent.lockLogicalDevice.Unlock()
801
802 var lDevice *voltha.LogicalDevice
803 var err error
804 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
805 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
806 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
807 }
808 groups := lDevice.FlowGroups.Items
809 groupsChanged := false
810 groupId := groupMod.GroupId
811 if idx := fu.FindGroup(groups, groupId); idx == -1 {
khenaidooca301322019-01-09 23:06:32 -0500812 return errors.New(fmt.Sprintf("group-absent:%d", groupId))
khenaidoo19d7b632018-10-30 10:49:50 -0400813 } else {
814 //replace existing group entry with new group definition
khenaidoo68c930b2019-05-13 11:46:51 -0400815 groupEntry := fu.GroupEntryFromGroupMod(groupMod)
khenaidoo19d7b632018-10-30 10:49:50 -0400816 groups[idx] = groupEntry
817 groupsChanged = true
818 }
819 if groupsChanged {
khenaidoo43c82122018-11-22 18:38:28 -0500820 //lDevice.FlowGroups.Items = groups
821 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(&ofp.FlowGroups{Items: groups}); err != nil {
khenaidoo19d7b632018-10-30 10:49:50 -0400822 log.Errorw("Cannot-update-logical-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
823 return err
824 }
825 }
826 return nil
827}
828
829// deleteLogicalPort removes the logical port
830func (agent *LogicalDeviceAgent) deleteLogicalPort(lPort *voltha.LogicalPort) error {
831 agent.lockLogicalDevice.Lock()
832 defer agent.lockLogicalDevice.Unlock()
833
khenaidoo92e62c52018-10-03 14:02:54 -0400834 // Get the most up to date logical device
835 var logicaldevice *voltha.LogicalDevice
836 if logicaldevice, _ = agent.getLogicalDeviceWithoutLock(); logicaldevice == nil {
khenaidoo19d7b632018-10-30 10:49:50 -0400837 log.Debugw("no-logical-device", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "logicalPortId": lPort.Id})
khenaidoob9203542018-09-17 22:56:37 -0400838 return nil
839 }
khenaidoo92e62c52018-10-03 14:02:54 -0400840 index := -1
841 for i, logicalPort := range logicaldevice.Ports {
khenaidoo19d7b632018-10-30 10:49:50 -0400842 if logicalPort.Id == lPort.Id {
khenaidoo92e62c52018-10-03 14:02:54 -0400843 index = i
844 break
845 }
846 }
847 if index >= 0 {
848 copy(logicaldevice.Ports[index:], logicaldevice.Ports[index+1:])
849 logicaldevice.Ports[len(logicaldevice.Ports)-1] = nil
850 logicaldevice.Ports = logicaldevice.Ports[:len(logicaldevice.Ports)-1]
851 log.Debugw("logical-port-deleted", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo0a822f92019-05-08 15:15:57 -0400852 if err := agent.updateLogicalDeviceWithoutLock(logicaldevice); err != nil {
853 log.Errorw("logical-device-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
854 return err
855 }
856 // Reset the logical device graph
khenaidoo3d3b8c22019-05-22 18:10:39 -0400857 go agent.generateDeviceGraph()
khenaidoo92e62c52018-10-03 14:02:54 -0400858 }
859 return nil
khenaidoob9203542018-09-17 22:56:37 -0400860}
861
khenaidoo0a822f92019-05-08 15:15:57 -0400862// deleteLogicalPorts removes the logical ports associated with that deviceId
863func (agent *LogicalDeviceAgent) deleteLogicalPorts(deviceId string) error {
864 agent.lockLogicalDevice.Lock()
865 defer agent.lockLogicalDevice.Unlock()
866
867 // Get the most up to date logical device
868 var logicaldevice *voltha.LogicalDevice
869 if logicaldevice, _ = agent.getLogicalDeviceWithoutLock(); logicaldevice == nil {
870 log.Debugw("no-logical-device", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
871 return nil
872 }
873 updatedLPorts := []*voltha.LogicalPort{}
874 for _, logicalPort := range logicaldevice.Ports {
875 if logicalPort.DeviceId != deviceId {
876 updatedLPorts = append(updatedLPorts, logicalPort)
877 }
878 }
879 logicaldevice.Ports = updatedLPorts
880 log.Debugw("updated-logical-ports", log.Fields{"ports": updatedLPorts})
881 if err := agent.updateLogicalDeviceWithoutLock(logicaldevice); err != nil {
882 log.Errorw("logical-device-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
883 return err
884 }
885 // Reset the logical device graph
khenaidoo3d3b8c22019-05-22 18:10:39 -0400886 go agent.generateDeviceGraph()
khenaidoo0a822f92019-05-08 15:15:57 -0400887
888 return nil
889}
890
khenaidoo19d7b632018-10-30 10:49:50 -0400891// enableLogicalPort enables the logical port
892func (agent *LogicalDeviceAgent) enableLogicalPort(lPort *voltha.LogicalPort) error {
893 agent.lockLogicalDevice.Lock()
894 defer agent.lockLogicalDevice.Unlock()
895
896 // Get the most up to date logical device
897 var logicaldevice *voltha.LogicalDevice
898 if logicaldevice, _ = agent.getLogicalDeviceWithoutLock(); logicaldevice == nil {
899 log.Debugw("no-logical-device", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "logicalPortId": lPort.Id})
900 return nil
901 }
902 index := -1
903 for i, logicalPort := range logicaldevice.Ports {
904 if logicalPort.Id == lPort.Id {
905 index = i
906 break
907 }
908 }
909 if index >= 0 {
910 logicaldevice.Ports[index].OfpPort.Config = logicaldevice.Ports[index].OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
911 return agent.updateLogicalDeviceWithoutLock(logicaldevice)
912 }
913 //TODO: Trigger subsequent actions on the device
914 return nil
915}
916
917// disableLogicalPort disabled the logical port
918func (agent *LogicalDeviceAgent) disableLogicalPort(lPort *voltha.LogicalPort) error {
919 agent.lockLogicalDevice.Lock()
920 defer agent.lockLogicalDevice.Unlock()
921
922 // Get the most up to date logical device
923 var logicaldevice *voltha.LogicalDevice
924 if logicaldevice, _ = agent.getLogicalDeviceWithoutLock(); logicaldevice == nil {
925 log.Debugw("no-logical-device", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "logicalPortId": lPort.Id})
926 return nil
927 }
928 index := -1
929 for i, logicalPort := range logicaldevice.Ports {
930 if logicalPort.Id == lPort.Id {
931 index = i
932 break
933 }
934 }
935 if index >= 0 {
936 logicaldevice.Ports[index].OfpPort.Config = (logicaldevice.Ports[index].OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)) | uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
937 return agent.updateLogicalDeviceWithoutLock(logicaldevice)
938 }
939 //TODO: Trigger subsequent actions on the device
940 return nil
941}
942
khenaidoo89b0e942018-10-21 21:11:33 -0400943func (agent *LogicalDeviceAgent) getPreCalculatedRoute(ingress, egress uint32) []graph.RouteHop {
khenaidoo19d7b632018-10-30 10:49:50 -0400944 log.Debugw("ROUTE", log.Fields{"len": len(agent.deviceGraph.Routes)})
khenaidoo89b0e942018-10-21 21:11:33 -0400945 for routeLink, route := range agent.deviceGraph.Routes {
khenaidoo19d7b632018-10-30 10:49:50 -0400946 log.Debugw("ROUTELINKS", log.Fields{"ingress": ingress, "egress": egress, "routelink": routeLink})
khenaidoo89b0e942018-10-21 21:11:33 -0400947 if ingress == routeLink.Ingress && egress == routeLink.Egress {
948 return route
949 }
950 }
951 log.Warnw("no-route", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "ingress": ingress, "egress": egress})
952 return nil
953}
954
khenaidoo19d7b632018-10-30 10:49:50 -0400955func (agent *LogicalDeviceAgent) GetRoute(ingressPortNo uint32, egressPortNo uint32) []graph.RouteHop {
khenaidoo89b0e942018-10-21 21:11:33 -0400956 log.Debugw("getting-route", log.Fields{"ingress-port": ingressPortNo, "egress-port": egressPortNo})
khenaidoo89b0e942018-10-21 21:11:33 -0400957 routes := make([]graph.RouteHop, 0)
khenaidoo2c6a0992019-04-29 13:46:56 -0400958
khenaidoo19d7b632018-10-30 10:49:50 -0400959 // Note: A port value of 0 is equivalent to a nil port
960
khenaidoo89b0e942018-10-21 21:11:33 -0400961 // Consider different possibilities
khenaidoo19d7b632018-10-30 10:49:50 -0400962 if egressPortNo != 0 && ((egressPortNo & 0x7fffffff) == uint32(ofp.OfpPortNo_OFPP_CONTROLLER)) {
khenaidoo2c6a0992019-04-29 13:46:56 -0400963 log.Debugw("controller-flow", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "logicalPortsNo": agent.logicalPortsNo})
964 if agent.isNNIPort(ingressPortNo) {
khenaidoo89b0e942018-10-21 21:11:33 -0400965 log.Debug("returning-half-route")
966 //This is a trap on the NNI Port
khenaidoo8f474192019-04-03 17:20:44 -0400967 if len(agent.deviceGraph.Routes) == 0 {
968 // If there are no routes set (usually when the logical device has only NNI port(s), then just return an
969 // internal route
khenaidoo2c6a0992019-04-29 13:46:56 -0400970 hop := graph.RouteHop{DeviceID: agent.rootDeviceId, Ingress: ingressPortNo, Egress: egressPortNo}
khenaidoo8f474192019-04-03 17:20:44 -0400971 routes = append(routes, hop)
972 routes = append(routes, hop)
973 return routes
974 }
khenaidoo89b0e942018-10-21 21:11:33 -0400975 //Return a 'half' route to make the flow decomposer logic happy
976 for routeLink, route := range agent.deviceGraph.Routes {
khenaidoo2c6a0992019-04-29 13:46:56 -0400977 if agent.isNNIPort(routeLink.Egress) {
khenaidoo89b0e942018-10-21 21:11:33 -0400978 routes = append(routes, graph.RouteHop{}) // first hop is set to empty
979 routes = append(routes, route[1])
980 return routes
981 }
982 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400983 log.Warnw("no-upstream-route", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "logicalPortsNo": agent.logicalPortsNo})
khenaidoo89b0e942018-10-21 21:11:33 -0400984 return nil
985 }
986 //treat it as if the output port is the first NNI of the OLT
khenaidoo2c6a0992019-04-29 13:46:56 -0400987 var err error
988 if egressPortNo, err = agent.getFirstNNIPort(); err != nil {
989 log.Warnw("no-nni-port", log.Fields{"error": err})
990 return nil
991 }
khenaidoo89b0e942018-10-21 21:11:33 -0400992 }
993 //If ingress port is not specified (nil), it may be a wildcarded
994 //route if egress port is OFPP_CONTROLLER or a nni logical port,
995 //in which case we need to create a half-route where only the egress
996 //hop is filled, the first hop is nil
khenaidoo2c6a0992019-04-29 13:46:56 -0400997 if ingressPortNo == 0 && agent.isNNIPort(egressPortNo) {
khenaidoo89b0e942018-10-21 21:11:33 -0400998 // We can use the 2nd hop of any upstream route, so just find the first upstream:
999 for routeLink, route := range agent.deviceGraph.Routes {
khenaidoo2c6a0992019-04-29 13:46:56 -04001000 if agent.isNNIPort(routeLink.Egress) {
khenaidoo89b0e942018-10-21 21:11:33 -04001001 routes = append(routes, graph.RouteHop{}) // first hop is set to empty
1002 routes = append(routes, route[1])
1003 return routes
1004 }
1005 }
khenaidoo2c6a0992019-04-29 13:46:56 -04001006 log.Warnw("no-upstream-route", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "logicalPortsNo": agent.logicalPortsNo})
khenaidoo89b0e942018-10-21 21:11:33 -04001007 return nil
1008 }
1009 //If egress port is not specified (nil), we can also can return a "half" route
khenaidoo19d7b632018-10-30 10:49:50 -04001010 if egressPortNo == 0 {
khenaidoo89b0e942018-10-21 21:11:33 -04001011 for routeLink, route := range agent.deviceGraph.Routes {
khenaidoo19d7b632018-10-30 10:49:50 -04001012 if routeLink.Ingress == ingressPortNo {
khenaidoo89b0e942018-10-21 21:11:33 -04001013 routes = append(routes, route[0])
1014 routes = append(routes, graph.RouteHop{})
1015 return routes
1016 }
1017 }
khenaidoo2c6a0992019-04-29 13:46:56 -04001018 log.Warnw("no-downstream-route", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "logicalPortsNo": agent.logicalPortsNo})
khenaidoo89b0e942018-10-21 21:11:33 -04001019 return nil
1020 }
khenaidoo89b0e942018-10-21 21:11:33 -04001021 // Return the pre-calculated route
khenaidoo19d7b632018-10-30 10:49:50 -04001022 return agent.getPreCalculatedRoute(ingressPortNo, egressPortNo)
khenaidoo89b0e942018-10-21 21:11:33 -04001023}
1024
khenaidoo89b0e942018-10-21 21:11:33 -04001025func (agent *LogicalDeviceAgent) rootDeviceDefaultRules() *fu.FlowsAndGroups {
1026 return fu.NewFlowsAndGroups()
1027}
1028
1029func (agent *LogicalDeviceAgent) leafDeviceDefaultRules(deviceId string) *fu.FlowsAndGroups {
1030 fg := fu.NewFlowsAndGroups()
1031 var device *voltha.Device
1032 var err error
khenaidoo19d7b632018-10-30 10:49:50 -04001033 if device, err = agent.deviceMgr.GetDevice(deviceId); err != nil {
khenaidoo89b0e942018-10-21 21:11:33 -04001034 return fg
1035 }
1036 //set the upstream and downstream ports
1037 upstreamPorts := make([]*voltha.Port, 0)
1038 downstreamPorts := make([]*voltha.Port, 0)
1039 for _, port := range device.Ports {
1040 if port.Type == voltha.Port_PON_ONU || port.Type == voltha.Port_VENET_ONU {
1041 upstreamPorts = append(upstreamPorts, port)
1042 } else if port.Type == voltha.Port_ETHERNET_UNI {
1043 downstreamPorts = append(downstreamPorts, port)
1044 }
1045 }
1046 //it is possible that the downstream ports are not created, but the flow_decomposition has already
1047 //kicked in. In such scenarios, cut short the processing and return.
khenaidoo910204f2019-04-08 17:56:40 -04001048 if len(downstreamPorts) == 0 || len(upstreamPorts) == 0 {
khenaidoo89b0e942018-10-21 21:11:33 -04001049 return fg
1050 }
1051 // set up the default flows
1052 var fa *fu.FlowArgs
1053 fa = &fu.FlowArgs{
1054 KV: fu.OfpFlowModArgs{"priority": 500},
1055 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -04001056 fu.InPort(downstreamPorts[0].PortNo),
1057 fu.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 0),
khenaidoo89b0e942018-10-21 21:11:33 -04001058 },
1059 Actions: []*ofp.OfpAction{
khenaidoo68c930b2019-05-13 11:46:51 -04001060 fu.SetField(fu.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | device.Vlan)),
1061 fu.Output(upstreamPorts[0].PortNo),
khenaidoo89b0e942018-10-21 21:11:33 -04001062 },
1063 }
khenaidoo68c930b2019-05-13 11:46:51 -04001064 fg.AddFlow(fu.MkFlowStat(fa))
khenaidoo89b0e942018-10-21 21:11:33 -04001065
1066 fa = &fu.FlowArgs{
1067 KV: fu.OfpFlowModArgs{"priority": 500},
1068 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -04001069 fu.InPort(downstreamPorts[0].PortNo),
1070 fu.VlanVid(0),
khenaidoo89b0e942018-10-21 21:11:33 -04001071 },
1072 Actions: []*ofp.OfpAction{
khenaidoo68c930b2019-05-13 11:46:51 -04001073 fu.PushVlan(0x8100),
1074 fu.SetField(fu.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | device.Vlan)),
1075 fu.Output(upstreamPorts[0].PortNo),
khenaidoo89b0e942018-10-21 21:11:33 -04001076 },
1077 }
khenaidoo68c930b2019-05-13 11:46:51 -04001078 fg.AddFlow(fu.MkFlowStat(fa))
khenaidoo89b0e942018-10-21 21:11:33 -04001079
1080 fa = &fu.FlowArgs{
1081 KV: fu.OfpFlowModArgs{"priority": 500},
1082 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -04001083 fu.InPort(upstreamPorts[0].PortNo),
1084 fu.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | device.Vlan),
khenaidoo89b0e942018-10-21 21:11:33 -04001085 },
1086 Actions: []*ofp.OfpAction{
khenaidoo68c930b2019-05-13 11:46:51 -04001087 fu.SetField(fu.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 0)),
1088 fu.Output(downstreamPorts[0].PortNo),
khenaidoo89b0e942018-10-21 21:11:33 -04001089 },
1090 }
khenaidoo68c930b2019-05-13 11:46:51 -04001091 fg.AddFlow(fu.MkFlowStat(fa))
khenaidoo89b0e942018-10-21 21:11:33 -04001092
1093 return fg
1094}
1095
1096func (agent *LogicalDeviceAgent) generateDefaultRules() *fu.DeviceRules {
1097 rules := fu.NewDeviceRules()
1098 var ld *voltha.LogicalDevice
1099 var err error
khenaidoo19d7b632018-10-30 10:49:50 -04001100 if ld, err = agent.GetLogicalDevice(); err != nil {
khenaidoo89b0e942018-10-21 21:11:33 -04001101 log.Warnw("no-logical-device", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
1102 return rules
1103 }
1104
1105 deviceNodeIds := agent.deviceGraph.GetDeviceNodeIds()
khenaidooca301322019-01-09 23:06:32 -05001106 for deviceId := range deviceNodeIds {
khenaidoo89b0e942018-10-21 21:11:33 -04001107 if deviceId == ld.RootDeviceId {
1108 rules.AddFlowsAndGroup(deviceId, agent.rootDeviceDefaultRules())
khenaidoo89b0e942018-10-21 21:11:33 -04001109 }
1110 }
1111 return rules
1112}
1113
1114func (agent *LogicalDeviceAgent) GetAllDefaultRules() *fu.DeviceRules {
khenaidoo89b0e942018-10-21 21:11:33 -04001115 return agent.DefaultFlowRules
1116}
1117
khenaidoo3d3b8c22019-05-22 18:10:39 -04001118//GetWildcardInputPorts filters out the logical port number from the set of logical ports on the device and
1119//returns their port numbers. This function is invoked only during flow decomposition where the lock on the logical
1120//device is already held. Therefore it is safe to retrieve the logical device without lock.
khenaidoo89b0e942018-10-21 21:11:33 -04001121func (agent *LogicalDeviceAgent) GetWildcardInputPorts(excludePort ...uint32) []uint32 {
1122 lPorts := make([]uint32, 0)
1123 var exclPort uint32
1124 if len(excludePort) == 1 {
1125 exclPort = excludePort[0]
1126 }
khenaidoo3d3b8c22019-05-22 18:10:39 -04001127 if lDevice, _ := agent.getLogicalDeviceWithoutLock(); lDevice != nil {
khenaidoo89b0e942018-10-21 21:11:33 -04001128 for _, port := range lDevice.Ports {
1129 if port.OfpPort.PortNo != exclPort {
1130 lPorts = append(lPorts, port.OfpPort.PortNo)
1131 }
1132 }
1133 }
1134 return lPorts
1135}
khenaidoo19d7b632018-10-30 10:49:50 -04001136
1137func (agent *LogicalDeviceAgent) GetDeviceGraph() *graph.DeviceGraph {
1138 return agent.deviceGraph
1139}
1140
khenaidoo2c6a0992019-04-29 13:46:56 -04001141//updateRoutes redo the device graph if not done already and setup the default rules as well
1142func (agent *LogicalDeviceAgent) updateRoutes(device *voltha.Device, port *voltha.Port) error {
1143 log.Debugf("updateRoutes", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "device": device.Id, "port": port})
khenaidoo910204f2019-04-08 17:56:40 -04001144 agent.lockLogicalDevice.Lock()
1145 defer agent.lockLogicalDevice.Unlock()
khenaidoo2c6a0992019-04-29 13:46:56 -04001146 rules := fu.NewDeviceRules()
khenaidoo19d7b632018-10-30 10:49:50 -04001147 if agent.deviceGraph == nil {
khenaidoo910204f2019-04-08 17:56:40 -04001148 agent.deviceGraph = graph.NewDeviceGraph(agent.logicalDeviceId, agent.deviceMgr.GetDevice)
khenaidoo2c6a0992019-04-29 13:46:56 -04001149 }
1150 // Get all the logical ports on that logical device
1151 if lDevice, err := agent.getLogicalDeviceWithoutLock(); err != nil {
manikkaraj k259a6f72019-05-06 09:55:44 -04001152 log.Errorw("unknown-logical-device", log.Fields{"error": err, "logicalDeviceId": agent.logicalDeviceId})
khenaidoo2c6a0992019-04-29 13:46:56 -04001153 return err
1154 } else {
1155 //TODO: Find a better way to refresh only missing routes
1156 agent.deviceGraph.ComputeRoutes(lDevice.Ports)
1157 }
1158 deviceNodeIds := agent.deviceGraph.GetDeviceNodeIds()
1159 for deviceId := range deviceNodeIds {
1160 if deviceId == agent.rootDeviceId {
1161 rules.AddFlowsAndGroup(deviceId, agent.rootDeviceDefaultRules())
khenaidoo910204f2019-04-08 17:56:40 -04001162 }
khenaidoo19d7b632018-10-30 10:49:50 -04001163 }
khenaidoo2c6a0992019-04-29 13:46:56 -04001164 agent.DefaultFlowRules = rules
1165
1166 // Reset the default flows flag to ensure all default flows are sent to all devices, including the newly added
1167 // one when a flow request is received.
1168 agent.includeDefaultFlows = true
1169 agent.deviceGraph.Print()
1170 return nil
khenaidoo19d7b632018-10-30 10:49:50 -04001171}
1172
khenaidoo2c6a0992019-04-29 13:46:56 -04001173//updateDeviceGraph updates the device graph if not done already and setup the default rules as well
khenaidoo910204f2019-04-08 17:56:40 -04001174func (agent *LogicalDeviceAgent) updateDeviceGraph(lp *voltha.LogicalPort) {
khenaidoo2c6a0992019-04-29 13:46:56 -04001175 log.Debugf("updateDeviceGraph", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
1176 agent.lockLogicalDevice.Lock()
1177 defer agent.lockLogicalDevice.Unlock()
1178 rules := fu.NewDeviceRules()
khenaidoo910204f2019-04-08 17:56:40 -04001179 if agent.deviceGraph == nil {
1180 agent.deviceGraph = graph.NewDeviceGraph(agent.logicalDeviceId, agent.deviceMgr.GetDevice)
1181 }
1182 agent.deviceGraph.AddPort(lp)
khenaidoo2c6a0992019-04-29 13:46:56 -04001183 deviceNodeIds := agent.deviceGraph.GetDeviceNodeIds()
1184 for deviceId := range deviceNodeIds {
1185 if deviceId == agent.rootDeviceId {
1186 rules.AddFlowsAndGroup(deviceId, agent.rootDeviceDefaultRules())
khenaidooca301322019-01-09 23:06:32 -05001187 }
Stephane Barbarie1ab43272018-12-08 21:42:13 -05001188 }
khenaidoo2c6a0992019-04-29 13:46:56 -04001189 agent.DefaultFlowRules = rules
khenaidoo19d7b632018-10-30 10:49:50 -04001190
khenaidoo2c6a0992019-04-29 13:46:56 -04001191 // Reset the default flows flag to ensure all default flows are sent to all devices, including the newly added
1192 // one when a flow request is received.
1193 agent.includeDefaultFlows = true
1194 agent.deviceGraph.Print()
khenaidoo19d7b632018-10-30 10:49:50 -04001195}
khenaidoofdbad6e2018-11-06 22:26:38 -05001196
khenaidoo3d3b8c22019-05-22 18:10:39 -04001197//generateDeviceGraph regenerates the device graph
1198func (agent *LogicalDeviceAgent) generateDeviceGraph() {
1199 log.Debugf("generateDeviceGraph", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo0a822f92019-05-08 15:15:57 -04001200 agent.lockLogicalDevice.Lock()
1201 defer agent.lockLogicalDevice.Unlock()
1202 // Get the latest logical device
1203 if ld, err := agent.getLogicalDeviceWithoutLock(); err != nil {
1204 log.Errorw("logical-device-not-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "error": err})
1205 } else {
khenaidoo3d3b8c22019-05-22 18:10:39 -04001206 log.Debugw("generating-graph", log.Fields{"lDeviceId": agent.logicalDeviceId, "deviceGraph": agent.deviceGraph, "lPorts": len(ld.Ports)})
1207 if agent.deviceGraph == nil {
1208 agent.deviceGraph = graph.NewDeviceGraph(agent.logicalDeviceId, agent.deviceMgr.GetDevice)
1209 }
khenaidoo0a822f92019-05-08 15:15:57 -04001210 agent.deviceGraph.ComputeRoutes(ld.Ports)
khenaidoo3d3b8c22019-05-22 18:10:39 -04001211 agent.deviceGraph.Print()
khenaidoo0a822f92019-05-08 15:15:57 -04001212 }
1213}
1214
khenaidoofc1314d2019-03-14 09:34:21 -04001215// portAdded is a callback invoked when a port is added to the logical device.
1216// TODO: To use when POST_ADD is fixed.
1217func (agent *LogicalDeviceAgent) portAdded(args ...interface{}) interface{} {
1218 log.Debugw("portAdded-callback", log.Fields{"argsLen": len(args)})
1219
1220 var port *voltha.LogicalPort
1221
1222 // Sanity check
1223 if args[0] != nil {
1224 log.Warnw("previous-data-not-nil", log.Fields{"args0": args[0]})
1225 }
1226 var ok bool
1227 if port, ok = args[1].(*voltha.LogicalPort); !ok {
1228 log.Errorw("invalid-args", log.Fields{"args1": args[1]})
1229 return nil
1230 }
1231
1232 // Set the proxy and callback for that port
1233 agent.portProxiesLock.Lock()
Stephane Barbarie40fd3b22019-04-23 21:50:47 -04001234 agent.portProxies[port.Id] = agent.clusterDataProxy.CreateProxy(
khenaidoofc1314d2019-03-14 09:34:21 -04001235 fmt.Sprintf("/logical_devices/%s/ports/%s", agent.logicalDeviceId, port.Id),
1236 false)
1237 agent.portProxies[port.Id].RegisterCallback(model.POST_UPDATE, agent.portUpdated)
1238 agent.portProxiesLock.Unlock()
1239
1240 // Send the port change event to the OF controller
1241 agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceId,
khenaidoo910204f2019-04-08 17:56:40 -04001242 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_ADD, Desc: port.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001243
1244 return nil
1245}
1246
1247// portRemoved is a callback invoked when a port is removed from the logical device.
1248// TODO: To use when POST_ADD is fixed.
1249func (agent *LogicalDeviceAgent) portRemoved(args ...interface{}) interface{} {
1250 log.Debugw("portRemoved-callback", log.Fields{"argsLen": len(args)})
1251
1252 var port *voltha.LogicalPort
1253
1254 // Sanity check
1255 if args[1] != nil {
1256 log.Warnw("data-not-nil", log.Fields{"args1": args[1]})
1257 }
1258 var ok bool
1259 if port, ok = args[0].(*voltha.LogicalPort); !ok {
1260 log.Errorw("invalid-args", log.Fields{"args0": args[0]})
1261 return nil
1262 }
1263
1264 // Remove the proxy and callback for that port
1265 agent.portProxiesLock.Lock()
1266 agent.portProxies[port.Id].UnregisterCallback(model.POST_UPDATE, agent.portUpdated)
1267 delete(agent.portProxies, port.Id)
1268 agent.portProxiesLock.Unlock()
1269
1270 // Send the port change event to the OF controller
1271 agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceId,
khenaidoo910204f2019-04-08 17:56:40 -04001272 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_DELETE, Desc: port.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001273
1274 return nil
1275}
1276
1277// 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 -04001278func diff(oldList, newList []*voltha.LogicalPort) (newPorts, changedPorts, deletedPorts []*voltha.LogicalPort) {
khenaidoofc1314d2019-03-14 09:34:21 -04001279 newPorts = make([]*voltha.LogicalPort, 0)
1280 changedPorts = make([]*voltha.LogicalPort, 0)
1281 deletedPorts = make([]*voltha.LogicalPort, 0)
1282 for _, o := range oldList {
1283 found := false
1284 changed := false
1285 for _, n := range newList {
1286 if o.Id == n.Id {
1287 changed = !reflect.DeepEqual(o, n)
1288 found = true
1289 break
1290 }
1291 }
1292 if !found {
1293 deletedPorts = append(deletedPorts, o)
1294 }
1295 if changed {
1296 changedPorts = append(changedPorts, o)
1297 }
1298 }
1299 for _, n := range newList {
1300 found := false
1301 for _, o := range oldList {
1302 if o.Id == n.Id {
1303 found = true
1304 break
1305 }
1306 }
1307 if !found {
1308 newPorts = append(newPorts, n)
1309 }
1310 }
1311 return
1312}
1313
1314// portUpdated is invoked when a port is updated on the logical device. Until
1315// the POST_ADD notification is fixed, we will use the logical device to
1316// update that data.
1317func (agent *LogicalDeviceAgent) portUpdated(args ...interface{}) interface{} {
1318 log.Debugw("portUpdated-callback", log.Fields{"argsLen": len(args)})
1319
1320 var oldLD *voltha.LogicalDevice
1321 var newlD *voltha.LogicalDevice
1322
1323 var ok bool
1324 if oldLD, ok = args[0].(*voltha.LogicalDevice); !ok {
1325 log.Errorw("invalid-args", log.Fields{"args0": args[0]})
1326 return nil
1327 }
1328 if newlD, ok = args[1].(*voltha.LogicalDevice); !ok {
1329 log.Errorw("invalid-args", log.Fields{"args1": args[1]})
1330 return nil
1331 }
1332
1333 if reflect.DeepEqual(oldLD.Ports, newlD.Ports) {
1334 log.Debug("ports-have-not-changed")
1335 return nil
1336 }
1337
1338 // Get the difference between the two list
1339 newPorts, changedPorts, deletedPorts := diff(oldLD.Ports, newlD.Ports)
1340
1341 // Send the port change events to the OF controller
khenaidoo2c6a0992019-04-29 13:46:56 -04001342 for _, newP := range newPorts {
khenaidoofc1314d2019-03-14 09:34:21 -04001343 go agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceId,
khenaidoo2c6a0992019-04-29 13:46:56 -04001344 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_ADD, Desc: newP.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001345 }
1346 for _, change := range changedPorts {
1347 go agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceId,
khenaidoo910204f2019-04-08 17:56:40 -04001348 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_MODIFY, Desc: change.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001349 }
1350 for _, del := range deletedPorts {
1351 go agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceId,
khenaidoo910204f2019-04-08 17:56:40 -04001352 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_DELETE, Desc: del.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001353 }
1354
1355 return nil
1356}
1357
khenaidoo8f474192019-04-03 17:20:44 -04001358// addNNILogicalPort adds an NNI port to the logical device. It returns a bool representing whether a port has been
1359// added and an eror in case a valid error is encountered. If the port was successfully added it will return
1360// (true, nil). If the device is not in the correct state it will return (false, nil) as this is a valid
1361// scenario. This also applies to the case where the port was already added.
khenaidoo910204f2019-04-08 17:56:40 -04001362func (agent *LogicalDeviceAgent) addNNILogicalPort(device *voltha.Device, port *voltha.Port) (bool, error) {
khenaidoo1ce37ad2019-03-24 22:07:24 -04001363 log.Debugw("addNNILogicalPort", log.Fields{"NNI": port})
khenaidoo8f474192019-04-03 17:20:44 -04001364 if device.AdminState != voltha.AdminState_ENABLED || device.OperStatus != voltha.OperStatus_ACTIVE {
1365 log.Infow("device-not-ready", log.Fields{"deviceId": device.Id, "admin": device.AdminState, "oper": device.OperStatus})
1366 return false, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001367 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001368 agent.lockLogicalDevice.RLock()
1369 if agent.portExist(device, port) {
1370 log.Debugw("port-already-exist", log.Fields{"port": port})
1371 agent.lockLogicalDevice.RUnlock()
khenaidoo8f474192019-04-03 17:20:44 -04001372 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001373 }
1374 agent.lockLogicalDevice.RUnlock()
1375
khenaidoofc1314d2019-03-14 09:34:21 -04001376 var portCap *ic.PortCapability
1377 var err error
1378 // First get the port capability
1379 if portCap, err = agent.deviceMgr.getPortCapability(nil, device.Id, port.PortNo); err != nil {
1380 log.Errorw("error-retrieving-port-capabilities", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001381 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001382 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001383
1384 agent.lockLogicalDevice.Lock()
1385 defer agent.lockLogicalDevice.Unlock()
1386 // Double check again if this port has been already added since the getPortCapability could have taken a long time
1387 if agent.portExist(device, port) {
1388 log.Debugw("port-already-exist", log.Fields{"port": port})
khenaidoo8f474192019-04-03 17:20:44 -04001389 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001390 }
1391
khenaidoofc1314d2019-03-14 09:34:21 -04001392 portCap.Port.RootPort = true
1393 lp := (proto.Clone(portCap.Port)).(*voltha.LogicalPort)
1394 lp.DeviceId = device.Id
1395 lp.Id = fmt.Sprintf("nni-%d", port.PortNo)
1396 lp.OfpPort.PortNo = port.PortNo
1397 lp.OfpPort.Name = lp.Id
1398 lp.DevicePortNo = port.PortNo
1399
khenaidoofc1314d2019-03-14 09:34:21 -04001400 var ld *voltha.LogicalDevice
1401 if ld, err = agent.getLogicalDeviceWithoutLock(); err != nil {
1402 log.Errorw("error-retrieving-logical-device", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001403 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001404 }
1405 cloned := (proto.Clone(ld)).(*voltha.LogicalDevice)
1406 if cloned.Ports == nil {
1407 cloned.Ports = make([]*voltha.LogicalPort, 0)
1408 }
1409 cloned.Ports = append(cloned.Ports, lp)
1410
1411 if err = agent.updateLogicalDeviceWithoutLock(cloned); err != nil {
1412 log.Errorw("error-updating-logical-device", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001413 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001414 }
khenaidoo910204f2019-04-08 17:56:40 -04001415
1416 // Update the device graph with this new logical port
1417 clonedLP := (proto.Clone(lp)).(*voltha.LogicalPort)
1418 go agent.updateDeviceGraph(clonedLP)
1419
khenaidoo8f474192019-04-03 17:20:44 -04001420 return true, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001421}
1422
khenaidoo910204f2019-04-08 17:56:40 -04001423func (agent *LogicalDeviceAgent) portExist(device *voltha.Device, port *voltha.Port) bool {
khenaidoo54544ae2019-03-18 13:22:39 -04001424 if ldevice, _ := agent.getLogicalDeviceWithoutLock(); ldevice != nil {
khenaidoofc1314d2019-03-14 09:34:21 -04001425 for _, lPort := range ldevice.Ports {
khenaidoo54544ae2019-03-18 13:22:39 -04001426 if lPort.DeviceId == device.Id && lPort.DevicePortNo == port.PortNo && lPort.Id == port.Label {
khenaidoofc1314d2019-03-14 09:34:21 -04001427 return true
1428 }
1429 }
1430 }
1431 return false
1432}
1433
khenaidoo8f474192019-04-03 17:20:44 -04001434// addUNILogicalPort adds an UNI port to the logical device. It returns a bool representing whether a port has been
1435// added and an eror in case a valid error is encountered. If the port was successfully added it will return
1436// (true, nil). If the device is not in the correct state it will return (false, nil) as this is a valid
1437// scenario. This also applies to the case where the port was already added.
khenaidoo910204f2019-04-08 17:56:40 -04001438func (agent *LogicalDeviceAgent) addUNILogicalPort(childDevice *voltha.Device, port *voltha.Port) (bool, error) {
khenaidoofc1314d2019-03-14 09:34:21 -04001439 log.Debugw("addUNILogicalPort", log.Fields{"port": port})
khenaidoo8f474192019-04-03 17:20:44 -04001440 if childDevice.AdminState != voltha.AdminState_ENABLED || childDevice.OperStatus != voltha.OperStatus_ACTIVE {
1441 log.Infow("device-not-ready", log.Fields{"deviceId": childDevice.Id, "admin": childDevice.AdminState, "oper": childDevice.OperStatus})
1442 return false, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001443 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001444 agent.lockLogicalDevice.RLock()
1445 if agent.portExist(childDevice, port) {
1446 log.Debugw("port-already-exist", log.Fields{"port": port})
1447 agent.lockLogicalDevice.RUnlock()
khenaidoo8f474192019-04-03 17:20:44 -04001448 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001449 }
1450 agent.lockLogicalDevice.RUnlock()
khenaidoofc1314d2019-03-14 09:34:21 -04001451 var portCap *ic.PortCapability
1452 var err error
1453 // First get the port capability
1454 if portCap, err = agent.deviceMgr.getPortCapability(nil, childDevice.Id, port.PortNo); err != nil {
1455 log.Errorw("error-retrieving-port-capabilities", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001456 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001457 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001458 agent.lockLogicalDevice.Lock()
1459 defer agent.lockLogicalDevice.Unlock()
1460 // Double check again if this port has been already added since the getPortCapability could have taken a long time
1461 if agent.portExist(childDevice, port) {
1462 log.Debugw("port-already-exist", log.Fields{"port": port})
khenaidoo8f474192019-04-03 17:20:44 -04001463 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001464 }
khenaidoofc1314d2019-03-14 09:34:21 -04001465 // Get stored logical device
1466 if ldevice, err := agent.getLogicalDeviceWithoutLock(); err != nil {
khenaidoo8f474192019-04-03 17:20:44 -04001467 return false, status.Error(codes.NotFound, agent.logicalDeviceId)
khenaidoofc1314d2019-03-14 09:34:21 -04001468 } else {
1469 log.Debugw("adding-uni", log.Fields{"deviceId": childDevice.Id})
1470 portCap.Port.RootPort = false
Matt Jeanneret3815e322019-03-12 19:15:49 -04001471 portCap.Port.Id = port.Label
1472 portCap.Port.OfpPort.PortNo = port.PortNo
khenaidoofc1314d2019-03-14 09:34:21 -04001473 portCap.Port.DeviceId = childDevice.Id
1474 portCap.Port.DevicePortNo = port.PortNo
1475 cloned := (proto.Clone(ldevice)).(*voltha.LogicalDevice)
1476 if cloned.Ports == nil {
1477 cloned.Ports = make([]*voltha.LogicalPort, 0)
1478 }
1479 cloned.Ports = append(cloned.Ports, portCap.Port)
khenaidoo910204f2019-04-08 17:56:40 -04001480 if err := agent.updateLogicalDeviceWithoutLock(cloned); err != nil {
1481 return false, err
1482 }
khenaidoo910204f2019-04-08 17:56:40 -04001483 // Update the device graph with this new logical port
1484 clonedLP := (proto.Clone(portCap.Port)).(*voltha.LogicalPort)
1485 go agent.updateDeviceGraph(clonedLP)
1486 return true, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001487 }
1488}
1489
khenaidoo43c82122018-11-22 18:38:28 -05001490func (agent *LogicalDeviceAgent) packetOut(packet *ofp.OfpPacketOut) {
khenaidoofdbad6e2018-11-06 22:26:38 -05001491 log.Debugw("packet-out", log.Fields{"packet": packet.GetInPort()})
khenaidoo68c930b2019-05-13 11:46:51 -04001492 outPort := fu.GetPacketOutPort(packet)
khenaidoofdbad6e2018-11-06 22:26:38 -05001493 //frame := packet.GetData()
1494 //TODO: Use a channel between the logical agent and the device agent
khenaidooca301322019-01-09 23:06:32 -05001495 if err := agent.deviceMgr.packetOut(agent.rootDeviceId, outPort, packet); err != nil {
khenaidoo910204f2019-04-08 17:56:40 -04001496 log.Error("packetout-failed", log.Fields{"logicalDeviceID": agent.rootDeviceId})
khenaidooca301322019-01-09 23:06:32 -05001497 }
khenaidoofdbad6e2018-11-06 22:26:38 -05001498}
1499
khenaidoo297cd252019-02-07 22:10:23 -05001500func (agent *LogicalDeviceAgent) packetIn(port uint32, transactionId string, packet []byte) {
1501 log.Debugw("packet-in", log.Fields{"port": port, "packet": packet, "transactionId": transactionId})
khenaidoo68c930b2019-05-13 11:46:51 -04001502 packetIn := fu.MkPacketIn(port, packet)
khenaidoo297cd252019-02-07 22:10:23 -05001503 agent.ldeviceMgr.grpcNbiHdlr.sendPacketIn(agent.logicalDeviceId, transactionId, packetIn)
khenaidooca301322019-01-09 23:06:32 -05001504 log.Debugw("sending-packet-in", log.Fields{"packet-in": packetIn})
khenaidoofdbad6e2018-11-06 22:26:38 -05001505}
khenaidoo2c6a0992019-04-29 13:46:56 -04001506
1507func (agent *LogicalDeviceAgent) addLogicalPortToMap(portNo uint32, nniPort bool) {
1508 agent.lockLogicalPortsNo.Lock()
1509 defer agent.lockLogicalPortsNo.Unlock()
1510 if exist := agent.logicalPortsNo[portNo]; !exist {
1511 agent.logicalPortsNo[portNo] = nniPort
1512 }
1513}
1514
khenaidoo3d3b8c22019-05-22 18:10:39 -04001515func (agent *LogicalDeviceAgent) addLogicalPortsToMap(lps []*voltha.LogicalPort) {
1516 agent.lockLogicalPortsNo.Lock()
1517 defer agent.lockLogicalPortsNo.Unlock()
1518 for _, lp := range lps {
1519 if exist := agent.logicalPortsNo[lp.DevicePortNo]; !exist {
1520 agent.logicalPortsNo[lp.DevicePortNo] = lp.RootPort
1521 }
1522 }
1523}
1524
khenaidoo2c6a0992019-04-29 13:46:56 -04001525func (agent *LogicalDeviceAgent) deleteLogicalPortFromMap(portNo uint32) {
1526 agent.lockLogicalPortsNo.Lock()
1527 defer agent.lockLogicalPortsNo.Unlock()
1528 if exist := agent.logicalPortsNo[portNo]; exist {
1529 delete(agent.logicalPortsNo, portNo)
1530 }
1531}
1532
1533func (agent *LogicalDeviceAgent) isNNIPort(portNo uint32) bool {
1534 agent.lockLogicalPortsNo.RLock()
1535 defer agent.lockLogicalPortsNo.RUnlock()
1536 if exist := agent.logicalPortsNo[portNo]; exist {
1537 return agent.logicalPortsNo[portNo]
1538 }
1539 return false
1540}
1541
1542func (agent *LogicalDeviceAgent) getFirstNNIPort() (uint32, error) {
1543 agent.lockLogicalPortsNo.RLock()
1544 defer agent.lockLogicalPortsNo.RUnlock()
1545 for portNo, nni := range agent.logicalPortsNo {
1546 if nni {
1547 return portNo, nil
1548 }
1549 }
1550 return 0, status.Error(codes.NotFound, "No NNI port found")
1551}