blob: 176634d48b28101e30cb10a3eb9b94f62bd13ed6 [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
khenaidoo19d7b632018-10-30 10:49:50 -0400186func (agent *LogicalDeviceAgent) ListLogicalDevicePorts() (*voltha.LogicalPorts, error) {
khenaidoo1ce37ad2019-03-24 22:07:24 -0400187 log.Debug("ListLogicalDevicePorts")
188 agent.lockLogicalDevice.RLock()
189 defer agent.lockLogicalDevice.RUnlock()
khenaidoo8c3303d2019-02-13 14:59:39 -0500190 logicalDevice := agent.clusterDataProxy.Get("/logical_devices/"+agent.logicalDeviceId, 0, false, "")
khenaidoo19d7b632018-10-30 10:49:50 -0400191 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
192 lPorts := make([]*voltha.LogicalPort, 0)
193 for _, port := range lDevice.Ports {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500194 lPorts = append(lPorts, port)
khenaidoo19d7b632018-10-30 10:49:50 -0400195 }
196 return &voltha.LogicalPorts{Items: lPorts}, nil
197 }
198 return nil, status.Errorf(codes.NotFound, "logical_device-%s", agent.logicalDeviceId)
199}
200
201// listFlows locks the logical device model and then retrieves the latest flow information
202func (agent *LogicalDeviceAgent) listFlows() []*ofp.OfpFlowStats {
203 log.Debug("listFlows")
khenaidoo1ce37ad2019-03-24 22:07:24 -0400204 agent.lockLogicalDevice.RLock()
205 defer agent.lockLogicalDevice.RUnlock()
khenaidoo8c3303d2019-02-13 14:59:39 -0500206 logicalDevice := agent.clusterDataProxy.Get("/logical_devices/"+agent.logicalDeviceId, 0, false, "")
khenaidoo19d7b632018-10-30 10:49:50 -0400207 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
208 return lDevice.Flows.Items
209 }
210 return nil
211}
212
213// listFlowGroups locks the logical device model and then retrieves the latest flow groups information
214func (agent *LogicalDeviceAgent) listFlowGroups() []*ofp.OfpGroupEntry {
215 log.Debug("listFlowGroups")
khenaidoo1ce37ad2019-03-24 22:07:24 -0400216 agent.lockLogicalDevice.RLock()
217 defer agent.lockLogicalDevice.RUnlock()
khenaidoo8c3303d2019-02-13 14:59:39 -0500218 logicalDevice := agent.clusterDataProxy.Get("/logical_devices/"+agent.logicalDeviceId, 0, false, "")
khenaidoo19d7b632018-10-30 10:49:50 -0400219 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
220 return lDevice.FlowGroups.Items
221 }
222 return nil
223}
224
khenaidoo43c82122018-11-22 18:38:28 -0500225//updateLogicalDeviceWithoutLock updates the model with the logical device. It clones the logicaldevice before saving it
226func (agent *LogicalDeviceAgent) updateLogicalDeviceFlowsWithoutLock(flows *ofp.Flows) error {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500227 afterUpdate := agent.flowProxy.Update("/", flows, false, "")
khenaidoo43c82122018-11-22 18:38:28 -0500228 if afterUpdate == nil {
229 return status.Errorf(codes.Internal, "failed-updating-logical-device-flows:%s", agent.logicalDeviceId)
230 }
khenaidoo43c82122018-11-22 18:38:28 -0500231 return nil
232}
233
234//updateLogicalDeviceWithoutLock updates the model with the logical device. It clones the logicaldevice before saving it
235func (agent *LogicalDeviceAgent) updateLogicalDeviceFlowGroupsWithoutLock(flowGroups *ofp.FlowGroups) error {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500236 afterUpdate := agent.groupProxy.Update("/", flowGroups, false, "")
khenaidoo43c82122018-11-22 18:38:28 -0500237 if afterUpdate == nil {
238 return status.Errorf(codes.Internal, "failed-updating-logical-device-flow-groups:%s", agent.logicalDeviceId)
239 }
khenaidoo43c82122018-11-22 18:38:28 -0500240 return nil
241}
242
khenaidoo4d4802d2018-10-04 21:59:49 -0400243// getLogicalDeviceWithoutLock retrieves a logical device from the model without locking it. This is used only by
244// functions that have already acquired the logical device lock to the model
khenaidoo92e62c52018-10-03 14:02:54 -0400245func (agent *LogicalDeviceAgent) getLogicalDeviceWithoutLock() (*voltha.LogicalDevice, error) {
246 log.Debug("getLogicalDeviceWithoutLock")
khenaidoo8c3303d2019-02-13 14:59:39 -0500247 logicalDevice := agent.clusterDataProxy.Get("/logical_devices/"+agent.logicalDeviceId, 0, false, "")
khenaidoo92e62c52018-10-03 14:02:54 -0400248 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
khenaidoo1ce37ad2019-03-24 22:07:24 -0400249 //log.Debug("getLogicalDeviceWithoutLock", log.Fields{"ldevice": lDevice})
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500250 return lDevice, nil
khenaidoo92e62c52018-10-03 14:02:54 -0400251 }
252 return nil, status.Errorf(codes.NotFound, "logical_device-%s", agent.logicalDeviceId)
253}
254
khenaidoo2c6a0992019-04-29 13:46:56 -0400255func (agent *LogicalDeviceAgent) updateLogicalPort(device *voltha.Device, port *voltha.Port) error {
256 log.Debugw("updateLogicalPort", log.Fields{"deviceId": device.Id, "port": port})
257 var err error
258 if port.Type == voltha.Port_ETHERNET_NNI {
259 if _, err = agent.addNNILogicalPort(device, port); err != nil {
260 return err
261 }
262 agent.addLogicalPortToMap(port.PortNo, true)
263 } else if port.Type == voltha.Port_ETHERNET_UNI {
264 if _, err = agent.addUNILogicalPort(device, port); err != nil {
265 return err
266 }
267 agent.addLogicalPortToMap(port.PortNo, false)
268 } else {
269 // Update the device graph to ensure all routes on the logical device have been calculated
270 if err = agent.updateRoutes(device, port); err != nil {
271 log.Errorw("failed-to-update-routes", log.Fields{"deviceId": device.Id, "port": port, "error": err})
272 return err
273 }
274 }
275 return nil
276}
277
khenaidoo910204f2019-04-08 17:56:40 -0400278func (agent *LogicalDeviceAgent) addLogicalPort(device *voltha.Device, port *voltha.Port) error {
khenaidoo8f474192019-04-03 17:20:44 -0400279 log.Debugw("addLogicalPort", log.Fields{"deviceId": device.Id, "port": port})
khenaidoo8f474192019-04-03 17:20:44 -0400280 var err error
khenaidoofc1314d2019-03-14 09:34:21 -0400281 if port.Type == voltha.Port_ETHERNET_NNI {
khenaidoo910204f2019-04-08 17:56:40 -0400282 if _, err = agent.addNNILogicalPort(device, port); err != nil {
khenaidoofc1314d2019-03-14 09:34:21 -0400283 return err
284 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400285 agent.addLogicalPortToMap(port.PortNo, true)
khenaidoofc1314d2019-03-14 09:34:21 -0400286 } else if port.Type == voltha.Port_ETHERNET_UNI {
khenaidoo910204f2019-04-08 17:56:40 -0400287 if _, err = agent.addUNILogicalPort(device, port); err != nil {
khenaidoofc1314d2019-03-14 09:34:21 -0400288 return err
289 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400290 agent.addLogicalPortToMap(port.PortNo, false)
khenaidoofc1314d2019-03-14 09:34:21 -0400291 } else {
292 log.Debugw("invalid-port-type", log.Fields{"deviceId": device.Id, "port": port})
293 return nil
294 }
khenaidoofc1314d2019-03-14 09:34:21 -0400295 return nil
296}
297
khenaidoo3d3b8c22019-05-22 18:10:39 -0400298// setupLogicalPorts is invoked once the logical device has been created and is ready to get ports
299// added to it. While the logical device was being created we could have received requests to add
300// NNI and UNI ports which were discarded. Now is the time to add them if needed
301func (agent *LogicalDeviceAgent) setupLogicalPorts(ctx context.Context) error {
302 log.Infow("setupLogicalPorts", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
303 // First add any NNI ports which could have been missing
304 if err := agent.setupNNILogicalPorts(nil, agent.rootDeviceId); err != nil {
305 log.Errorw("error-setting-up-NNI-ports", log.Fields{"error": err, "deviceId": agent.rootDeviceId})
306 return err
307 }
308
309 // Now, set up the UNI ports if needed.
310 if children, err := agent.deviceMgr.getAllChildDevices(agent.rootDeviceId); err != nil {
311 log.Errorw("error-getting-child-devices", log.Fields{"error": err, "deviceId": agent.rootDeviceId})
312 return err
313 } else {
314 chnlsList := make([]chan interface{}, 0)
315 for _, child := range children.Items {
316 ch := make(chan interface{})
317 chnlsList = append(chnlsList, ch)
318 go func(device *voltha.Device, ch chan interface{}) {
319 if err = agent.setupUNILogicalPorts(nil, device); err != nil {
320 log.Error("setting-up-UNI-ports-failed", log.Fields{"deviceID": device.Id})
321 ch <- status.Errorf(codes.Internal, "UNI-ports-setup-failed: %s", device.Id)
322 }
323 ch <- nil
324 }(child, ch)
325 }
326 // Wait for completion
327 if res := fu.WaitForNilOrErrorResponses(agent.defaultTimeout, chnlsList...); res != nil {
328 return status.Errorf(codes.Aborted, "errors-%s", res)
329 }
330 }
331 return nil
332}
333
khenaidoofc1314d2019-03-14 09:34:21 -0400334// setupNNILogicalPorts creates an NNI port on the logical device that represents an NNI interface on a root device
335func (agent *LogicalDeviceAgent) setupNNILogicalPorts(ctx context.Context, deviceId string) error {
336 log.Infow("setupNNILogicalPorts-start", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoob9203542018-09-17 22:56:37 -0400337 // Build the logical device based on information retrieved from the device adapter
khenaidoofc1314d2019-03-14 09:34:21 -0400338 var err error
339
340 var device *voltha.Device
341 if device, err = agent.deviceMgr.GetDevice(deviceId); err != nil {
khenaidoo2c6a0992019-04-29 13:46:56 -0400342 log.Errorw("error-retrieving-device", log.Fields{"error": err, "deviceId": deviceId})
khenaidoofc1314d2019-03-14 09:34:21 -0400343 return err
344 }
345
346 //Get UNI port number
khenaidoofc1314d2019-03-14 09:34:21 -0400347 for _, port := range device.Ports {
348 if port.Type == voltha.Port_ETHERNET_NNI {
khenaidoo910204f2019-04-08 17:56:40 -0400349 if _, err = agent.addNNILogicalPort(device, port); err != nil {
khenaidoofc1314d2019-03-14 09:34:21 -0400350 log.Errorw("error-adding-UNI-port", log.Fields{"error": err})
khenaidoofc1314d2019-03-14 09:34:21 -0400351 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400352 agent.addLogicalPortToMap(port.PortNo, true)
khenaidoofc1314d2019-03-14 09:34:21 -0400353 }
354 }
khenaidoofc1314d2019-03-14 09:34:21 -0400355 return err
356}
357
khenaidoo3ab34882019-05-02 21:33:30 -0400358// updatePortsState updates the ports state related to the device
359func (agent *LogicalDeviceAgent) updatePortsState(device *voltha.Device, state voltha.AdminState_AdminState) error {
360 log.Infow("updatePortsState-start", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
361 agent.lockLogicalDevice.Lock()
362 defer agent.lockLogicalDevice.Unlock()
363 // Get the latest logical device info
364 if ld, err := agent.getLogicalDeviceWithoutLock(); err != nil {
365 log.Warnw("logical-device-unknown", log.Fields{"ldeviceId": agent.logicalDeviceId, "error": err})
366 return err
367 } else {
368 cloned := (proto.Clone(ld)).(*voltha.LogicalDevice)
369 for _, lport := range cloned.Ports {
370 if lport.DeviceId == device.Id {
371 switch state {
372 case voltha.AdminState_ENABLED:
373 lport.OfpPort.Config = lport.OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
khenaidoo0a822f92019-05-08 15:15:57 -0400374 lport.OfpPort.State = uint32(ofp.OfpPortState_OFPPS_LIVE)
khenaidoo3ab34882019-05-02 21:33:30 -0400375 case voltha.AdminState_DISABLED:
376 lport.OfpPort.Config = lport.OfpPort.Config | uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
khenaidoo0a822f92019-05-08 15:15:57 -0400377 lport.OfpPort.State = uint32(ofp.OfpPortState_OFPPS_LINK_DOWN)
khenaidoo3ab34882019-05-02 21:33:30 -0400378 default:
379 log.Warnw("unsupported-state-change", log.Fields{"deviceId": device.Id, "state": state})
380 }
381 }
382 }
383 // Updating the logical device will trigger the poprt change events to be populated to the controller
384 if err := agent.updateLogicalDeviceWithoutLock(cloned); err != nil {
385 log.Warnw("logical-device-update-failed", log.Fields{"ldeviceId": agent.logicalDeviceId, "error": err})
386 return err
387 }
388 }
389 return nil
390}
391
khenaidoofc1314d2019-03-14 09:34:21 -0400392// setupUNILogicalPorts creates a UNI port on the logical device that represents a child UNI interface
393func (agent *LogicalDeviceAgent) setupUNILogicalPorts(ctx context.Context, childDevice *voltha.Device) error {
khenaidoo3d3b8c22019-05-22 18:10:39 -0400394 log.Infow("setupUNILogicalPort", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoofc1314d2019-03-14 09:34:21 -0400395 // Build the logical device based on information retrieved from the device adapter
khenaidoob9203542018-09-17 22:56:37 -0400396 var err error
khenaidoo19d7b632018-10-30 10:49:50 -0400397
398 //Get UNI port number
khenaidoo19d7b632018-10-30 10:49:50 -0400399 for _, port := range childDevice.Ports {
400 if port.Type == voltha.Port_ETHERNET_UNI {
khenaidoo910204f2019-04-08 17:56:40 -0400401 if _, err = agent.addUNILogicalPort(childDevice, port); err != nil {
khenaidoofc1314d2019-03-14 09:34:21 -0400402 log.Errorw("error-adding-UNI-port", log.Fields{"error": err})
khenaidoofc1314d2019-03-14 09:34:21 -0400403 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400404 agent.addLogicalPortToMap(port.PortNo, false)
khenaidoo19d7b632018-10-30 10:49:50 -0400405 }
406 }
khenaidoofc1314d2019-03-14 09:34:21 -0400407 return err
khenaidoo92e62c52018-10-03 14:02:54 -0400408}
409
khenaidoo0a822f92019-05-08 15:15:57 -0400410// deleteAllLogicalPorts deletes all logical ports associated with this device
411func (agent *LogicalDeviceAgent) deleteAllLogicalPorts(device *voltha.Device) error {
412 log.Infow("updatePortsState-start", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
413 agent.lockLogicalDevice.Lock()
414 defer agent.lockLogicalDevice.Unlock()
415 // Get the latest logical device info
416 if ld, err := agent.getLogicalDeviceWithoutLock(); err != nil {
417 log.Warnw("logical-device-unknown", log.Fields{"ldeviceId": agent.logicalDeviceId, "error": err})
418 return err
419 } else {
420 cloned := (proto.Clone(ld)).(*voltha.LogicalDevice)
421 updateLogicalPorts := []*voltha.LogicalPort{}
422 for _, lport := range cloned.Ports {
423 if lport.DeviceId != device.Id {
424 updateLogicalPorts = append(updateLogicalPorts, lport)
425 }
426 }
427 if len(updateLogicalPorts) < len(cloned.Ports) {
428 cloned.Ports = updateLogicalPorts
429 // Updating the logical device will trigger the poprt change events to be populated to the controller
430 if err := agent.updateLogicalDeviceWithoutLock(cloned); err != nil {
431 log.Warnw("logical-device-update-failed", log.Fields{"ldeviceId": agent.logicalDeviceId, "error": err})
432 return err
433 }
434 } else {
435 log.Debugw("no-change-required", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
436 }
437 }
438 return nil
439}
440
khenaidoo92e62c52018-10-03 14:02:54 -0400441//updateLogicalDeviceWithoutLock updates the model with the logical device. It clones the logicaldevice before saving it
442func (agent *LogicalDeviceAgent) updateLogicalDeviceWithoutLock(logicalDevice *voltha.LogicalDevice) error {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500443 afterUpdate := agent.clusterDataProxy.Update("/logical_devices/"+agent.logicalDeviceId, logicalDevice, false, "")
khenaidoo92e62c52018-10-03 14:02:54 -0400444 if afterUpdate == nil {
445 return status.Errorf(codes.Internal, "failed-updating-logical-device:%s", agent.logicalDeviceId)
446 }
447 return nil
448}
449
khenaidoo19d7b632018-10-30 10:49:50 -0400450//updateFlowTable updates the flow table of that logical device
451func (agent *LogicalDeviceAgent) updateFlowTable(ctx context.Context, flow *ofp.OfpFlowMod) error {
452 log.Debug("updateFlowTable")
453 if flow == nil {
454 return nil
455 }
456 switch flow.GetCommand() {
457 case ofp.OfpFlowModCommand_OFPFC_ADD:
458 return agent.flowAdd(flow)
459 case ofp.OfpFlowModCommand_OFPFC_DELETE:
460 return agent.flowDelete(flow)
461 case ofp.OfpFlowModCommand_OFPFC_DELETE_STRICT:
462 return agent.flowDeleteStrict(flow)
463 case ofp.OfpFlowModCommand_OFPFC_MODIFY:
464 return agent.flowModify(flow)
465 case ofp.OfpFlowModCommand_OFPFC_MODIFY_STRICT:
466 return agent.flowModifyStrict(flow)
467 }
468 return status.Errorf(codes.Internal,
469 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceId, flow.GetCommand())
470}
471
472//updateGroupTable updates the group table of that logical device
473func (agent *LogicalDeviceAgent) updateGroupTable(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
474 log.Debug("updateGroupTable")
475 if groupMod == nil {
476 return nil
477 }
478 switch groupMod.GetCommand() {
479 case ofp.OfpGroupModCommand_OFPGC_ADD:
480 return agent.groupAdd(groupMod)
481 case ofp.OfpGroupModCommand_OFPGC_DELETE:
482 return agent.groupDelete(groupMod)
483 case ofp.OfpGroupModCommand_OFPGC_MODIFY:
484 return agent.groupModify(groupMod)
485 }
486 return status.Errorf(codes.Internal,
487 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceId, groupMod.GetCommand())
488}
489
khenaidoo19d7b632018-10-30 10:49:50 -0400490//flowAdd adds a flow to the flow table of that logical device
491func (agent *LogicalDeviceAgent) flowAdd(mod *ofp.OfpFlowMod) error {
492 log.Debug("flowAdd")
493 if mod == nil {
494 return nil
495 }
khenaidoo92e62c52018-10-03 14:02:54 -0400496 agent.lockLogicalDevice.Lock()
497 defer agent.lockLogicalDevice.Unlock()
khenaidoo19d7b632018-10-30 10:49:50 -0400498
499 var lDevice *voltha.LogicalDevice
500 var err error
501 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
502 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
503 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
504 }
505
506 var flows []*ofp.OfpFlowStats
507 if lDevice.Flows != nil && lDevice.Flows.Items != nil {
508 flows = lDevice.Flows.Items
509 }
510
khenaidoo2c6a0992019-04-29 13:46:56 -0400511 updatedFlows := make([]*ofp.OfpFlowStats, 0)
khenaidoo43c82122018-11-22 18:38:28 -0500512 //oldData := proto.Clone(lDevice.Flows).(*voltha.Flows)
khenaidoo19d7b632018-10-30 10:49:50 -0400513 changed := false
514 checkOverlap := (mod.Flags & uint32(ofp.OfpFlowModFlags_OFPFF_CHECK_OVERLAP)) != 0
515 if checkOverlap {
516 if overlapped := fu.FindOverlappingFlows(flows, mod); len(overlapped) != 0 {
517 // TODO: should this error be notified other than being logged?
518 log.Warnw("overlapped-flows", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
519 } else {
520 // Add flow
khenaidoo68c930b2019-05-13 11:46:51 -0400521 flow := fu.FlowStatsEntryFromFlowModMessage(mod)
khenaidoo19d7b632018-10-30 10:49:50 -0400522 flows = append(flows, flow)
khenaidoo2c6a0992019-04-29 13:46:56 -0400523 updatedFlows = append(updatedFlows, flow)
khenaidoo19d7b632018-10-30 10:49:50 -0400524 changed = true
525 }
526 } else {
khenaidoo68c930b2019-05-13 11:46:51 -0400527 flow := fu.FlowStatsEntryFromFlowModMessage(mod)
khenaidoo19d7b632018-10-30 10:49:50 -0400528 idx := fu.FindFlows(flows, flow)
529 if idx >= 0 {
530 oldFlow := flows[idx]
531 if (mod.Flags & uint32(ofp.OfpFlowModFlags_OFPFF_RESET_COUNTS)) != 0 {
532 flow.ByteCount = oldFlow.ByteCount
533 flow.PacketCount = oldFlow.PacketCount
534 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400535 if !reflect.DeepEqual(oldFlow, flow) {
536 flows[idx] = flow
537 updatedFlows = append(updatedFlows, flow)
538 changed = true
539 }
khenaidoo19d7b632018-10-30 10:49:50 -0400540 } else {
541 flows = append(flows, flow)
khenaidoo2c6a0992019-04-29 13:46:56 -0400542 updatedFlows = append(updatedFlows, flow)
543 changed = true
khenaidoo19d7b632018-10-30 10:49:50 -0400544 }
khenaidoo19d7b632018-10-30 10:49:50 -0400545 }
546 if changed {
khenaidoo2c6a0992019-04-29 13:46:56 -0400547 // Launch a routine to decompose the flows
khenaidoo3306c992019-05-24 16:57:35 -0400548 if err := agent.decomposeAndSendFlows(&ofp.Flows{Items: updatedFlows}, lDevice.FlowGroups); err != nil {
manikkaraj k259a6f72019-05-06 09:55:44 -0400549 log.Errorw("decomposing-and-sending-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo2c6a0992019-04-29 13:46:56 -0400550 return err
551 }
552
khenaidoo19d7b632018-10-30 10:49:50 -0400553 // Update model
khenaidoo43c82122018-11-22 18:38:28 -0500554 flowsToUpdate := &ofp.Flows{}
555 if lDevice.Flows != nil {
556 flowsToUpdate = &ofp.Flows{Items: flows}
khenaidoo19d7b632018-10-30 10:49:50 -0400557 }
khenaidoo43c82122018-11-22 18:38:28 -0500558 if err := agent.updateLogicalDeviceFlowsWithoutLock(flowsToUpdate); err != nil {
khenaidoo2c6a0992019-04-29 13:46:56 -0400559 log.Errorw("db-flow-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400560 return err
561 }
562 }
khenaidoo19d7b632018-10-30 10:49:50 -0400563 return nil
564}
565
khenaidoo3306c992019-05-24 16:57:35 -0400566func (agent *LogicalDeviceAgent) decomposeAndSendFlows(flows *ofp.Flows, groups *ofp.FlowGroups) error {
khenaidoo2c6a0992019-04-29 13:46:56 -0400567 log.Debugw("decomposeAndSendFlows", log.Fields{"logicalDeviceID": agent.logicalDeviceId})
568
khenaidoo3306c992019-05-24 16:57:35 -0400569 deviceRules := agent.flowDecomposer.DecomposeRules(agent, *flows, *groups)
khenaidoo2c6a0992019-04-29 13:46:56 -0400570 log.Debugw("rules", log.Fields{"rules": deviceRules.String()})
571
572 chnlsList := make([]chan interface{}, 0)
573 for deviceId, value := range deviceRules.GetRules() {
574 ch := make(chan interface{})
575 chnlsList = append(chnlsList, ch)
576 go func(deviceId string, flows []*ofp.OfpFlowStats, groups []*ofp.OfpGroupEntry) {
577 if err := agent.deviceMgr.addFlowsAndGroups(deviceId, flows, groups); err != nil {
578 log.Error("flow-update-failed", log.Fields{"deviceID": deviceId})
579 ch <- status.Errorf(codes.Internal, "flow-update-failed: %s", deviceId)
580 }
581 ch <- nil
582 }(deviceId, value.ListFlows(), value.ListGroups())
583 }
584 // Wait for completion
585 if res := fu.WaitForNilOrErrorResponses(agent.defaultTimeout, chnlsList...); res != nil {
586 return status.Errorf(codes.Aborted, "errors-%s", res)
587 }
588 return nil
589}
590
khenaidoo19d7b632018-10-30 10:49:50 -0400591//flowDelete deletes a flow from the flow table of that logical device
592func (agent *LogicalDeviceAgent) flowDelete(mod *ofp.OfpFlowMod) error {
593 log.Debug("flowDelete")
594 if mod == nil {
595 return nil
596 }
597 agent.lockLogicalDevice.Lock()
598 defer agent.lockLogicalDevice.Unlock()
599
600 var lDevice *voltha.LogicalDevice
601 var err error
602 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
603 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
604 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
605 }
606 flows := lDevice.Flows.Items
607
608 //build a list of what to keep vs what to delete
609 toKeep := make([]*ofp.OfpFlowStats, 0)
610 for _, f := range flows {
611 if !fu.FlowMatchesMod(f, mod) {
612 toKeep = append(toKeep, f)
613 }
614 }
615
616 //Update flows
617 if len(toKeep) < len(flows) {
khenaidoo43c82122018-11-22 18:38:28 -0500618 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: toKeep}); err != nil {
619 log.Errorw("Cannot-update-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400620 return err
621 }
622 }
623
624 //TODO: send announcement on delete
625 return nil
626}
627
628//flowStatsDelete deletes a flow from the flow table of that logical device
629func (agent *LogicalDeviceAgent) flowStatsDelete(flow *ofp.OfpFlowStats) error {
630 log.Debug("flowStatsDelete")
631 if flow == nil {
632 return nil
633 }
634 agent.lockLogicalDevice.Lock()
635 defer agent.lockLogicalDevice.Unlock()
636
637 var lDevice *voltha.LogicalDevice
638 var err error
639 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
640 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
641 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
642 }
643 flows := lDevice.Flows.Items
644
645 //build a list of what to keep vs what to delete
646 toKeep := make([]*ofp.OfpFlowStats, 0)
647 for _, f := range flows {
648 if !fu.FlowMatch(f, flow) {
649 toKeep = append(toKeep, f)
650 }
651 }
652
653 //Update flows
654 if len(toKeep) < len(flows) {
khenaidoo43c82122018-11-22 18:38:28 -0500655 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: toKeep}); err != nil {
khenaidoo19d7b632018-10-30 10:49:50 -0400656 log.Errorw("Cannot-update-logical-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
657 return err
658 }
659 }
660 return nil
661}
662
663//flowDeleteStrict deletes a flow from the flow table of that logical device
664func (agent *LogicalDeviceAgent) flowDeleteStrict(mod *ofp.OfpFlowMod) error {
665 log.Debug("flowDeleteStrict")
666 if mod == nil {
667 return nil
668 }
669 agent.lockLogicalDevice.Lock()
670 defer agent.lockLogicalDevice.Unlock()
671
672 var lDevice *voltha.LogicalDevice
673 var err error
674 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
675 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
676 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
677 }
678 flows := lDevice.Flows.Items
679 changed := false
khenaidoo68c930b2019-05-13 11:46:51 -0400680 flow := fu.FlowStatsEntryFromFlowModMessage(mod)
khenaidoo19d7b632018-10-30 10:49:50 -0400681 idx := fu.FindFlows(flows, flow)
682 if idx >= 0 {
683 flows = append(flows[:idx], flows[idx+1:]...)
684 changed = true
685 } else {
686 return errors.New(fmt.Sprintf("Cannot delete flow - %s", flow))
687 }
688
689 if changed {
khenaidoo43c82122018-11-22 18:38:28 -0500690 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: flows}); err != nil {
khenaidoo19d7b632018-10-30 10:49:50 -0400691 log.Errorw("Cannot-update-logical-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
692 return err
693 }
694 }
695
696 return nil
697}
698
699//flowModify modifies a flow from the flow table of that logical device
700func (agent *LogicalDeviceAgent) flowModify(mod *ofp.OfpFlowMod) error {
701 return errors.New("flowModify not implemented")
702}
703
704//flowModifyStrict deletes a flow from the flow table of that logical device
705func (agent *LogicalDeviceAgent) flowModifyStrict(mod *ofp.OfpFlowMod) error {
706 return errors.New("flowModifyStrict not implemented")
707}
708
709func (agent *LogicalDeviceAgent) groupAdd(groupMod *ofp.OfpGroupMod) error {
710 log.Debug("groupAdd")
711 if groupMod == nil {
712 return nil
713 }
714 agent.lockLogicalDevice.Lock()
715 defer agent.lockLogicalDevice.Unlock()
716
717 var lDevice *voltha.LogicalDevice
718 var err error
719 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
720 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
721 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
722 }
723 groups := lDevice.FlowGroups.Items
khenaidoo19d7b632018-10-30 10:49:50 -0400724 if fu.FindGroup(groups, groupMod.GroupId) == -1 {
khenaidoo68c930b2019-05-13 11:46:51 -0400725 groups = append(groups, fu.GroupEntryFromGroupMod(groupMod))
khenaidoo43c82122018-11-22 18:38:28 -0500726 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(&ofp.FlowGroups{Items: groups}); err != nil {
727 log.Errorw("Cannot-update-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400728 return err
729 }
730 } else {
731 return errors.New(fmt.Sprintf("Groups %d already present", groupMod.GroupId))
732 }
khenaidoo19d7b632018-10-30 10:49:50 -0400733 return nil
734}
735
736func (agent *LogicalDeviceAgent) groupDelete(groupMod *ofp.OfpGroupMod) error {
737 log.Debug("groupDelete")
738 if groupMod == nil {
739 return nil
740 }
741 agent.lockLogicalDevice.Lock()
742 defer agent.lockLogicalDevice.Unlock()
743
744 var lDevice *voltha.LogicalDevice
745 var err error
746 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
747 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
748 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
749 }
750 groups := lDevice.FlowGroups.Items
751 flows := lDevice.Flows.Items
752 groupsChanged := false
753 flowsChanged := false
754 groupId := groupMod.GroupId
755 if groupId == uint32(ofp.OfpGroup_OFPG_ALL) {
756 //TODO we must delete all flows that point to this group and
757 //signal controller as requested by flow's flag
758 groups = []*ofp.OfpGroupEntry{}
759 groupsChanged = true
760 } else {
761 if idx := fu.FindGroup(groups, groupId); idx == -1 {
762 return nil // Valid case
763 } else {
764 flowsChanged, flows = fu.FlowsDeleteByGroupId(flows, groupId)
765 groups = append(groups[:idx], groups[idx+1:]...)
766 groupsChanged = true
767 }
768 }
khenaidoo43c82122018-11-22 18:38:28 -0500769 if groupsChanged {
770 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(&ofp.FlowGroups{Items: groups}); err != nil {
771 log.Errorw("Cannot-update-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400772 return err
773 }
774 }
khenaidoo43c82122018-11-22 18:38:28 -0500775 if flowsChanged {
776 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: flows}); err != nil {
777 log.Errorw("Cannot-update-flow", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
778 return err
779 }
780 }
781
khenaidoo19d7b632018-10-30 10:49:50 -0400782 return nil
783}
784
785func (agent *LogicalDeviceAgent) groupModify(groupMod *ofp.OfpGroupMod) error {
786 log.Debug("groupModify")
787 if groupMod == nil {
788 return nil
789 }
790 agent.lockLogicalDevice.Lock()
791 defer agent.lockLogicalDevice.Unlock()
792
793 var lDevice *voltha.LogicalDevice
794 var err error
795 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
796 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
797 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
798 }
799 groups := lDevice.FlowGroups.Items
800 groupsChanged := false
801 groupId := groupMod.GroupId
802 if idx := fu.FindGroup(groups, groupId); idx == -1 {
khenaidooca301322019-01-09 23:06:32 -0500803 return errors.New(fmt.Sprintf("group-absent:%d", groupId))
khenaidoo19d7b632018-10-30 10:49:50 -0400804 } else {
805 //replace existing group entry with new group definition
khenaidoo68c930b2019-05-13 11:46:51 -0400806 groupEntry := fu.GroupEntryFromGroupMod(groupMod)
khenaidoo19d7b632018-10-30 10:49:50 -0400807 groups[idx] = groupEntry
808 groupsChanged = true
809 }
810 if groupsChanged {
khenaidoo43c82122018-11-22 18:38:28 -0500811 //lDevice.FlowGroups.Items = groups
812 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(&ofp.FlowGroups{Items: groups}); err != nil {
khenaidoo19d7b632018-10-30 10:49:50 -0400813 log.Errorw("Cannot-update-logical-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
814 return err
815 }
816 }
817 return nil
818}
819
820// deleteLogicalPort removes the logical port
821func (agent *LogicalDeviceAgent) deleteLogicalPort(lPort *voltha.LogicalPort) error {
822 agent.lockLogicalDevice.Lock()
823 defer agent.lockLogicalDevice.Unlock()
824
khenaidoo92e62c52018-10-03 14:02:54 -0400825 // Get the most up to date logical device
826 var logicaldevice *voltha.LogicalDevice
827 if logicaldevice, _ = agent.getLogicalDeviceWithoutLock(); logicaldevice == nil {
khenaidoo19d7b632018-10-30 10:49:50 -0400828 log.Debugw("no-logical-device", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "logicalPortId": lPort.Id})
khenaidoob9203542018-09-17 22:56:37 -0400829 return nil
830 }
khenaidoo92e62c52018-10-03 14:02:54 -0400831 index := -1
832 for i, logicalPort := range logicaldevice.Ports {
khenaidoo19d7b632018-10-30 10:49:50 -0400833 if logicalPort.Id == lPort.Id {
khenaidoo92e62c52018-10-03 14:02:54 -0400834 index = i
835 break
836 }
837 }
838 if index >= 0 {
839 copy(logicaldevice.Ports[index:], logicaldevice.Ports[index+1:])
840 logicaldevice.Ports[len(logicaldevice.Ports)-1] = nil
841 logicaldevice.Ports = logicaldevice.Ports[:len(logicaldevice.Ports)-1]
842 log.Debugw("logical-port-deleted", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo0a822f92019-05-08 15:15:57 -0400843 if err := agent.updateLogicalDeviceWithoutLock(logicaldevice); err != nil {
844 log.Errorw("logical-device-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
845 return err
846 }
847 // Reset the logical device graph
khenaidoo3d3b8c22019-05-22 18:10:39 -0400848 go agent.generateDeviceGraph()
khenaidoo92e62c52018-10-03 14:02:54 -0400849 }
850 return nil
khenaidoob9203542018-09-17 22:56:37 -0400851}
852
khenaidoo0a822f92019-05-08 15:15:57 -0400853// deleteLogicalPorts removes the logical ports associated with that deviceId
854func (agent *LogicalDeviceAgent) deleteLogicalPorts(deviceId string) error {
855 agent.lockLogicalDevice.Lock()
856 defer agent.lockLogicalDevice.Unlock()
857
858 // Get the most up to date logical device
859 var logicaldevice *voltha.LogicalDevice
860 if logicaldevice, _ = agent.getLogicalDeviceWithoutLock(); logicaldevice == nil {
861 log.Debugw("no-logical-device", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
862 return nil
863 }
864 updatedLPorts := []*voltha.LogicalPort{}
865 for _, logicalPort := range logicaldevice.Ports {
866 if logicalPort.DeviceId != deviceId {
867 updatedLPorts = append(updatedLPorts, logicalPort)
868 }
869 }
870 logicaldevice.Ports = updatedLPorts
871 log.Debugw("updated-logical-ports", log.Fields{"ports": updatedLPorts})
872 if err := agent.updateLogicalDeviceWithoutLock(logicaldevice); err != nil {
873 log.Errorw("logical-device-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
874 return err
875 }
876 // Reset the logical device graph
khenaidoo3d3b8c22019-05-22 18:10:39 -0400877 go agent.generateDeviceGraph()
khenaidoo0a822f92019-05-08 15:15:57 -0400878
879 return nil
880}
881
khenaidoo19d7b632018-10-30 10:49:50 -0400882// enableLogicalPort enables the logical port
883func (agent *LogicalDeviceAgent) enableLogicalPort(lPort *voltha.LogicalPort) error {
884 agent.lockLogicalDevice.Lock()
885 defer agent.lockLogicalDevice.Unlock()
886
887 // Get the most up to date logical device
888 var logicaldevice *voltha.LogicalDevice
889 if logicaldevice, _ = agent.getLogicalDeviceWithoutLock(); logicaldevice == nil {
890 log.Debugw("no-logical-device", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "logicalPortId": lPort.Id})
891 return nil
892 }
893 index := -1
894 for i, logicalPort := range logicaldevice.Ports {
895 if logicalPort.Id == lPort.Id {
896 index = i
897 break
898 }
899 }
900 if index >= 0 {
901 logicaldevice.Ports[index].OfpPort.Config = logicaldevice.Ports[index].OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
902 return agent.updateLogicalDeviceWithoutLock(logicaldevice)
903 }
904 //TODO: Trigger subsequent actions on the device
905 return nil
906}
907
908// disableLogicalPort disabled the logical port
909func (agent *LogicalDeviceAgent) disableLogicalPort(lPort *voltha.LogicalPort) error {
910 agent.lockLogicalDevice.Lock()
911 defer agent.lockLogicalDevice.Unlock()
912
913 // Get the most up to date logical device
914 var logicaldevice *voltha.LogicalDevice
915 if logicaldevice, _ = agent.getLogicalDeviceWithoutLock(); logicaldevice == nil {
916 log.Debugw("no-logical-device", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "logicalPortId": lPort.Id})
917 return nil
918 }
919 index := -1
920 for i, logicalPort := range logicaldevice.Ports {
921 if logicalPort.Id == lPort.Id {
922 index = i
923 break
924 }
925 }
926 if index >= 0 {
927 logicaldevice.Ports[index].OfpPort.Config = (logicaldevice.Ports[index].OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)) | uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
928 return agent.updateLogicalDeviceWithoutLock(logicaldevice)
929 }
930 //TODO: Trigger subsequent actions on the device
931 return nil
932}
933
khenaidoo89b0e942018-10-21 21:11:33 -0400934func (agent *LogicalDeviceAgent) getPreCalculatedRoute(ingress, egress uint32) []graph.RouteHop {
khenaidoo19d7b632018-10-30 10:49:50 -0400935 log.Debugw("ROUTE", log.Fields{"len": len(agent.deviceGraph.Routes)})
khenaidoo89b0e942018-10-21 21:11:33 -0400936 for routeLink, route := range agent.deviceGraph.Routes {
khenaidoo19d7b632018-10-30 10:49:50 -0400937 log.Debugw("ROUTELINKS", log.Fields{"ingress": ingress, "egress": egress, "routelink": routeLink})
khenaidoo89b0e942018-10-21 21:11:33 -0400938 if ingress == routeLink.Ingress && egress == routeLink.Egress {
939 return route
940 }
941 }
942 log.Warnw("no-route", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "ingress": ingress, "egress": egress})
943 return nil
944}
945
khenaidoo19d7b632018-10-30 10:49:50 -0400946func (agent *LogicalDeviceAgent) GetRoute(ingressPortNo uint32, egressPortNo uint32) []graph.RouteHop {
khenaidoo89b0e942018-10-21 21:11:33 -0400947 log.Debugw("getting-route", log.Fields{"ingress-port": ingressPortNo, "egress-port": egressPortNo})
khenaidoo89b0e942018-10-21 21:11:33 -0400948 routes := make([]graph.RouteHop, 0)
khenaidoo2c6a0992019-04-29 13:46:56 -0400949
khenaidoo19d7b632018-10-30 10:49:50 -0400950 // Note: A port value of 0 is equivalent to a nil port
951
khenaidoo89b0e942018-10-21 21:11:33 -0400952 // Consider different possibilities
khenaidoo19d7b632018-10-30 10:49:50 -0400953 if egressPortNo != 0 && ((egressPortNo & 0x7fffffff) == uint32(ofp.OfpPortNo_OFPP_CONTROLLER)) {
khenaidoo2c6a0992019-04-29 13:46:56 -0400954 log.Debugw("controller-flow", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "logicalPortsNo": agent.logicalPortsNo})
955 if agent.isNNIPort(ingressPortNo) {
khenaidoo89b0e942018-10-21 21:11:33 -0400956 log.Debug("returning-half-route")
957 //This is a trap on the NNI Port
khenaidoo8f474192019-04-03 17:20:44 -0400958 if len(agent.deviceGraph.Routes) == 0 {
959 // If there are no routes set (usually when the logical device has only NNI port(s), then just return an
960 // internal route
khenaidoo2c6a0992019-04-29 13:46:56 -0400961 hop := graph.RouteHop{DeviceID: agent.rootDeviceId, Ingress: ingressPortNo, Egress: egressPortNo}
khenaidoo8f474192019-04-03 17:20:44 -0400962 routes = append(routes, hop)
963 routes = append(routes, hop)
964 return routes
965 }
khenaidoo89b0e942018-10-21 21:11:33 -0400966 //Return a 'half' route to make the flow decomposer logic happy
967 for routeLink, route := range agent.deviceGraph.Routes {
khenaidoo2c6a0992019-04-29 13:46:56 -0400968 if agent.isNNIPort(routeLink.Egress) {
khenaidoo89b0e942018-10-21 21:11:33 -0400969 routes = append(routes, graph.RouteHop{}) // first hop is set to empty
970 routes = append(routes, route[1])
971 return routes
972 }
973 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400974 log.Warnw("no-upstream-route", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "logicalPortsNo": agent.logicalPortsNo})
khenaidoo89b0e942018-10-21 21:11:33 -0400975 return nil
976 }
977 //treat it as if the output port is the first NNI of the OLT
khenaidoo2c6a0992019-04-29 13:46:56 -0400978 var err error
979 if egressPortNo, err = agent.getFirstNNIPort(); err != nil {
980 log.Warnw("no-nni-port", log.Fields{"error": err})
981 return nil
982 }
khenaidoo89b0e942018-10-21 21:11:33 -0400983 }
984 //If ingress port is not specified (nil), it may be a wildcarded
985 //route if egress port is OFPP_CONTROLLER or a nni logical port,
986 //in which case we need to create a half-route where only the egress
987 //hop is filled, the first hop is nil
khenaidoo2c6a0992019-04-29 13:46:56 -0400988 if ingressPortNo == 0 && agent.isNNIPort(egressPortNo) {
khenaidoo89b0e942018-10-21 21:11:33 -0400989 // We can use the 2nd hop of any upstream route, so just find the first upstream:
990 for routeLink, route := range agent.deviceGraph.Routes {
khenaidoo2c6a0992019-04-29 13:46:56 -0400991 if agent.isNNIPort(routeLink.Egress) {
khenaidoo89b0e942018-10-21 21:11:33 -0400992 routes = append(routes, graph.RouteHop{}) // first hop is set to empty
993 routes = append(routes, route[1])
994 return routes
995 }
996 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400997 log.Warnw("no-upstream-route", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "logicalPortsNo": agent.logicalPortsNo})
khenaidoo89b0e942018-10-21 21:11:33 -0400998 return nil
999 }
1000 //If egress port is not specified (nil), we can also can return a "half" route
khenaidoo19d7b632018-10-30 10:49:50 -04001001 if egressPortNo == 0 {
khenaidoo89b0e942018-10-21 21:11:33 -04001002 for routeLink, route := range agent.deviceGraph.Routes {
khenaidoo19d7b632018-10-30 10:49:50 -04001003 if routeLink.Ingress == ingressPortNo {
khenaidoo89b0e942018-10-21 21:11:33 -04001004 routes = append(routes, route[0])
1005 routes = append(routes, graph.RouteHop{})
1006 return routes
1007 }
1008 }
khenaidoo2c6a0992019-04-29 13:46:56 -04001009 log.Warnw("no-downstream-route", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "logicalPortsNo": agent.logicalPortsNo})
khenaidoo89b0e942018-10-21 21:11:33 -04001010 return nil
1011 }
khenaidoo89b0e942018-10-21 21:11:33 -04001012 // Return the pre-calculated route
khenaidoo19d7b632018-10-30 10:49:50 -04001013 return agent.getPreCalculatedRoute(ingressPortNo, egressPortNo)
khenaidoo89b0e942018-10-21 21:11:33 -04001014}
1015
khenaidoo3d3b8c22019-05-22 18:10:39 -04001016//GetWildcardInputPorts filters out the logical port number from the set of logical ports on the device and
1017//returns their port numbers. This function is invoked only during flow decomposition where the lock on the logical
1018//device is already held. Therefore it is safe to retrieve the logical device without lock.
khenaidoo89b0e942018-10-21 21:11:33 -04001019func (agent *LogicalDeviceAgent) GetWildcardInputPorts(excludePort ...uint32) []uint32 {
1020 lPorts := make([]uint32, 0)
1021 var exclPort uint32
1022 if len(excludePort) == 1 {
1023 exclPort = excludePort[0]
1024 }
khenaidoo3d3b8c22019-05-22 18:10:39 -04001025 if lDevice, _ := agent.getLogicalDeviceWithoutLock(); lDevice != nil {
khenaidoo89b0e942018-10-21 21:11:33 -04001026 for _, port := range lDevice.Ports {
1027 if port.OfpPort.PortNo != exclPort {
1028 lPorts = append(lPorts, port.OfpPort.PortNo)
1029 }
1030 }
1031 }
1032 return lPorts
1033}
khenaidoo19d7b632018-10-30 10:49:50 -04001034
1035func (agent *LogicalDeviceAgent) GetDeviceGraph() *graph.DeviceGraph {
1036 return agent.deviceGraph
1037}
1038
khenaidoo3306c992019-05-24 16:57:35 -04001039//updateRoutes rebuilds the device graph if not done already
khenaidoo2c6a0992019-04-29 13:46:56 -04001040func (agent *LogicalDeviceAgent) updateRoutes(device *voltha.Device, port *voltha.Port) error {
1041 log.Debugf("updateRoutes", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "device": device.Id, "port": port})
khenaidoo910204f2019-04-08 17:56:40 -04001042 agent.lockLogicalDevice.Lock()
1043 defer agent.lockLogicalDevice.Unlock()
khenaidoo19d7b632018-10-30 10:49:50 -04001044 if agent.deviceGraph == nil {
khenaidoo910204f2019-04-08 17:56:40 -04001045 agent.deviceGraph = graph.NewDeviceGraph(agent.logicalDeviceId, agent.deviceMgr.GetDevice)
khenaidoo2c6a0992019-04-29 13:46:56 -04001046 }
1047 // Get all the logical ports on that logical device
1048 if lDevice, err := agent.getLogicalDeviceWithoutLock(); err != nil {
manikkaraj k259a6f72019-05-06 09:55:44 -04001049 log.Errorw("unknown-logical-device", log.Fields{"error": err, "logicalDeviceId": agent.logicalDeviceId})
khenaidoo2c6a0992019-04-29 13:46:56 -04001050 return err
1051 } else {
1052 //TODO: Find a better way to refresh only missing routes
1053 agent.deviceGraph.ComputeRoutes(lDevice.Ports)
1054 }
khenaidoo2c6a0992019-04-29 13:46:56 -04001055 agent.deviceGraph.Print()
1056 return nil
khenaidoo19d7b632018-10-30 10:49:50 -04001057}
1058
khenaidoo2c6a0992019-04-29 13:46:56 -04001059//updateDeviceGraph updates the device graph if not done already and setup the default rules as well
khenaidoo910204f2019-04-08 17:56:40 -04001060func (agent *LogicalDeviceAgent) updateDeviceGraph(lp *voltha.LogicalPort) {
khenaidoo2c6a0992019-04-29 13:46:56 -04001061 log.Debugf("updateDeviceGraph", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
1062 agent.lockLogicalDevice.Lock()
1063 defer agent.lockLogicalDevice.Unlock()
khenaidoo910204f2019-04-08 17:56:40 -04001064 if agent.deviceGraph == nil {
1065 agent.deviceGraph = graph.NewDeviceGraph(agent.logicalDeviceId, agent.deviceMgr.GetDevice)
1066 }
1067 agent.deviceGraph.AddPort(lp)
khenaidoo2c6a0992019-04-29 13:46:56 -04001068 agent.deviceGraph.Print()
khenaidoo19d7b632018-10-30 10:49:50 -04001069}
khenaidoofdbad6e2018-11-06 22:26:38 -05001070
khenaidoo3d3b8c22019-05-22 18:10:39 -04001071//generateDeviceGraph regenerates the device graph
1072func (agent *LogicalDeviceAgent) generateDeviceGraph() {
1073 log.Debugf("generateDeviceGraph", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo0a822f92019-05-08 15:15:57 -04001074 agent.lockLogicalDevice.Lock()
1075 defer agent.lockLogicalDevice.Unlock()
1076 // Get the latest logical device
1077 if ld, err := agent.getLogicalDeviceWithoutLock(); err != nil {
1078 log.Errorw("logical-device-not-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "error": err})
1079 } else {
khenaidoo3d3b8c22019-05-22 18:10:39 -04001080 log.Debugw("generating-graph", log.Fields{"lDeviceId": agent.logicalDeviceId, "deviceGraph": agent.deviceGraph, "lPorts": len(ld.Ports)})
1081 if agent.deviceGraph == nil {
1082 agent.deviceGraph = graph.NewDeviceGraph(agent.logicalDeviceId, agent.deviceMgr.GetDevice)
1083 }
khenaidoo0a822f92019-05-08 15:15:57 -04001084 agent.deviceGraph.ComputeRoutes(ld.Ports)
khenaidoo3d3b8c22019-05-22 18:10:39 -04001085 agent.deviceGraph.Print()
khenaidoo0a822f92019-05-08 15:15:57 -04001086 }
1087}
1088
khenaidoofc1314d2019-03-14 09:34:21 -04001089// portAdded is a callback invoked when a port is added to the logical device.
1090// TODO: To use when POST_ADD is fixed.
1091func (agent *LogicalDeviceAgent) portAdded(args ...interface{}) interface{} {
1092 log.Debugw("portAdded-callback", log.Fields{"argsLen": len(args)})
1093
1094 var port *voltha.LogicalPort
1095
1096 // Sanity check
1097 if args[0] != nil {
1098 log.Warnw("previous-data-not-nil", log.Fields{"args0": args[0]})
1099 }
1100 var ok bool
1101 if port, ok = args[1].(*voltha.LogicalPort); !ok {
1102 log.Errorw("invalid-args", log.Fields{"args1": args[1]})
1103 return nil
1104 }
1105
1106 // Set the proxy and callback for that port
1107 agent.portProxiesLock.Lock()
Stephane Barbarie40fd3b22019-04-23 21:50:47 -04001108 agent.portProxies[port.Id] = agent.clusterDataProxy.CreateProxy(
khenaidoofc1314d2019-03-14 09:34:21 -04001109 fmt.Sprintf("/logical_devices/%s/ports/%s", agent.logicalDeviceId, port.Id),
1110 false)
1111 agent.portProxies[port.Id].RegisterCallback(model.POST_UPDATE, agent.portUpdated)
1112 agent.portProxiesLock.Unlock()
1113
1114 // Send the port change event to the OF controller
1115 agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceId,
khenaidoo910204f2019-04-08 17:56:40 -04001116 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_ADD, Desc: port.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001117
1118 return nil
1119}
1120
1121// portRemoved is a callback invoked when a port is removed from the logical device.
1122// TODO: To use when POST_ADD is fixed.
1123func (agent *LogicalDeviceAgent) portRemoved(args ...interface{}) interface{} {
1124 log.Debugw("portRemoved-callback", log.Fields{"argsLen": len(args)})
1125
1126 var port *voltha.LogicalPort
1127
1128 // Sanity check
1129 if args[1] != nil {
1130 log.Warnw("data-not-nil", log.Fields{"args1": args[1]})
1131 }
1132 var ok bool
1133 if port, ok = args[0].(*voltha.LogicalPort); !ok {
1134 log.Errorw("invalid-args", log.Fields{"args0": args[0]})
1135 return nil
1136 }
1137
1138 // Remove the proxy and callback for that port
1139 agent.portProxiesLock.Lock()
1140 agent.portProxies[port.Id].UnregisterCallback(model.POST_UPDATE, agent.portUpdated)
1141 delete(agent.portProxies, port.Id)
1142 agent.portProxiesLock.Unlock()
1143
1144 // Send the port change event to the OF controller
1145 agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceId,
khenaidoo910204f2019-04-08 17:56:40 -04001146 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_DELETE, Desc: port.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001147
1148 return nil
1149}
1150
1151// 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 -04001152func diff(oldList, newList []*voltha.LogicalPort) (newPorts, changedPorts, deletedPorts []*voltha.LogicalPort) {
khenaidoofc1314d2019-03-14 09:34:21 -04001153 newPorts = make([]*voltha.LogicalPort, 0)
1154 changedPorts = make([]*voltha.LogicalPort, 0)
1155 deletedPorts = make([]*voltha.LogicalPort, 0)
1156 for _, o := range oldList {
1157 found := false
1158 changed := false
1159 for _, n := range newList {
1160 if o.Id == n.Id {
1161 changed = !reflect.DeepEqual(o, n)
1162 found = true
1163 break
1164 }
1165 }
1166 if !found {
1167 deletedPorts = append(deletedPorts, o)
1168 }
1169 if changed {
1170 changedPorts = append(changedPorts, o)
1171 }
1172 }
1173 for _, n := range newList {
1174 found := false
1175 for _, o := range oldList {
1176 if o.Id == n.Id {
1177 found = true
1178 break
1179 }
1180 }
1181 if !found {
1182 newPorts = append(newPorts, n)
1183 }
1184 }
1185 return
1186}
1187
1188// portUpdated is invoked when a port is updated on the logical device. Until
1189// the POST_ADD notification is fixed, we will use the logical device to
1190// update that data.
1191func (agent *LogicalDeviceAgent) portUpdated(args ...interface{}) interface{} {
1192 log.Debugw("portUpdated-callback", log.Fields{"argsLen": len(args)})
1193
1194 var oldLD *voltha.LogicalDevice
1195 var newlD *voltha.LogicalDevice
1196
1197 var ok bool
1198 if oldLD, ok = args[0].(*voltha.LogicalDevice); !ok {
1199 log.Errorw("invalid-args", log.Fields{"args0": args[0]})
1200 return nil
1201 }
1202 if newlD, ok = args[1].(*voltha.LogicalDevice); !ok {
1203 log.Errorw("invalid-args", log.Fields{"args1": args[1]})
1204 return nil
1205 }
1206
1207 if reflect.DeepEqual(oldLD.Ports, newlD.Ports) {
1208 log.Debug("ports-have-not-changed")
1209 return nil
1210 }
1211
1212 // Get the difference between the two list
1213 newPorts, changedPorts, deletedPorts := diff(oldLD.Ports, newlD.Ports)
1214
1215 // Send the port change events to the OF controller
khenaidoo2c6a0992019-04-29 13:46:56 -04001216 for _, newP := range newPorts {
khenaidoofc1314d2019-03-14 09:34:21 -04001217 go agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceId,
khenaidoo2c6a0992019-04-29 13:46:56 -04001218 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_ADD, Desc: newP.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001219 }
1220 for _, change := range changedPorts {
1221 go agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceId,
khenaidoo910204f2019-04-08 17:56:40 -04001222 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_MODIFY, Desc: change.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001223 }
1224 for _, del := range deletedPorts {
1225 go agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceId,
khenaidoo910204f2019-04-08 17:56:40 -04001226 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_DELETE, Desc: del.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001227 }
1228
1229 return nil
1230}
1231
khenaidoo8f474192019-04-03 17:20:44 -04001232// addNNILogicalPort adds an NNI port to the logical device. It returns a bool representing whether a port has been
1233// added and an eror in case a valid error is encountered. If the port was successfully added it will return
1234// (true, nil). If the device is not in the correct state it will return (false, nil) as this is a valid
1235// scenario. This also applies to the case where the port was already added.
khenaidoo910204f2019-04-08 17:56:40 -04001236func (agent *LogicalDeviceAgent) addNNILogicalPort(device *voltha.Device, port *voltha.Port) (bool, error) {
khenaidoo1ce37ad2019-03-24 22:07:24 -04001237 log.Debugw("addNNILogicalPort", log.Fields{"NNI": port})
khenaidoo8f474192019-04-03 17:20:44 -04001238 if device.AdminState != voltha.AdminState_ENABLED || device.OperStatus != voltha.OperStatus_ACTIVE {
1239 log.Infow("device-not-ready", log.Fields{"deviceId": device.Id, "admin": device.AdminState, "oper": device.OperStatus})
1240 return false, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001241 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001242 agent.lockLogicalDevice.RLock()
1243 if agent.portExist(device, port) {
1244 log.Debugw("port-already-exist", log.Fields{"port": port})
1245 agent.lockLogicalDevice.RUnlock()
khenaidoo8f474192019-04-03 17:20:44 -04001246 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001247 }
1248 agent.lockLogicalDevice.RUnlock()
1249
khenaidoofc1314d2019-03-14 09:34:21 -04001250 var portCap *ic.PortCapability
1251 var err error
1252 // First get the port capability
1253 if portCap, err = agent.deviceMgr.getPortCapability(nil, device.Id, port.PortNo); err != nil {
1254 log.Errorw("error-retrieving-port-capabilities", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001255 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001256 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001257
1258 agent.lockLogicalDevice.Lock()
1259 defer agent.lockLogicalDevice.Unlock()
1260 // Double check again if this port has been already added since the getPortCapability could have taken a long time
1261 if agent.portExist(device, port) {
1262 log.Debugw("port-already-exist", log.Fields{"port": port})
khenaidoo8f474192019-04-03 17:20:44 -04001263 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001264 }
1265
khenaidoofc1314d2019-03-14 09:34:21 -04001266 portCap.Port.RootPort = true
1267 lp := (proto.Clone(portCap.Port)).(*voltha.LogicalPort)
1268 lp.DeviceId = device.Id
1269 lp.Id = fmt.Sprintf("nni-%d", port.PortNo)
1270 lp.OfpPort.PortNo = port.PortNo
1271 lp.OfpPort.Name = lp.Id
1272 lp.DevicePortNo = port.PortNo
1273
khenaidoofc1314d2019-03-14 09:34:21 -04001274 var ld *voltha.LogicalDevice
1275 if ld, err = agent.getLogicalDeviceWithoutLock(); err != nil {
1276 log.Errorw("error-retrieving-logical-device", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001277 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001278 }
1279 cloned := (proto.Clone(ld)).(*voltha.LogicalDevice)
1280 if cloned.Ports == nil {
1281 cloned.Ports = make([]*voltha.LogicalPort, 0)
1282 }
1283 cloned.Ports = append(cloned.Ports, lp)
1284
1285 if err = agent.updateLogicalDeviceWithoutLock(cloned); err != nil {
1286 log.Errorw("error-updating-logical-device", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001287 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001288 }
khenaidoo910204f2019-04-08 17:56:40 -04001289
1290 // Update the device graph with this new logical port
1291 clonedLP := (proto.Clone(lp)).(*voltha.LogicalPort)
1292 go agent.updateDeviceGraph(clonedLP)
1293
khenaidoo8f474192019-04-03 17:20:44 -04001294 return true, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001295}
1296
khenaidoo910204f2019-04-08 17:56:40 -04001297func (agent *LogicalDeviceAgent) portExist(device *voltha.Device, port *voltha.Port) bool {
khenaidoo54544ae2019-03-18 13:22:39 -04001298 if ldevice, _ := agent.getLogicalDeviceWithoutLock(); ldevice != nil {
khenaidoofc1314d2019-03-14 09:34:21 -04001299 for _, lPort := range ldevice.Ports {
khenaidoo54544ae2019-03-18 13:22:39 -04001300 if lPort.DeviceId == device.Id && lPort.DevicePortNo == port.PortNo && lPort.Id == port.Label {
khenaidoofc1314d2019-03-14 09:34:21 -04001301 return true
1302 }
1303 }
1304 }
1305 return false
1306}
1307
khenaidoo8f474192019-04-03 17:20:44 -04001308// addUNILogicalPort adds an UNI port to the logical device. It returns a bool representing whether a port has been
1309// added and an eror in case a valid error is encountered. If the port was successfully added it will return
1310// (true, nil). If the device is not in the correct state it will return (false, nil) as this is a valid
1311// scenario. This also applies to the case where the port was already added.
khenaidoo910204f2019-04-08 17:56:40 -04001312func (agent *LogicalDeviceAgent) addUNILogicalPort(childDevice *voltha.Device, port *voltha.Port) (bool, error) {
khenaidoofc1314d2019-03-14 09:34:21 -04001313 log.Debugw("addUNILogicalPort", log.Fields{"port": port})
khenaidoo8f474192019-04-03 17:20:44 -04001314 if childDevice.AdminState != voltha.AdminState_ENABLED || childDevice.OperStatus != voltha.OperStatus_ACTIVE {
1315 log.Infow("device-not-ready", log.Fields{"deviceId": childDevice.Id, "admin": childDevice.AdminState, "oper": childDevice.OperStatus})
1316 return false, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001317 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001318 agent.lockLogicalDevice.RLock()
1319 if agent.portExist(childDevice, port) {
1320 log.Debugw("port-already-exist", log.Fields{"port": port})
1321 agent.lockLogicalDevice.RUnlock()
khenaidoo8f474192019-04-03 17:20:44 -04001322 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001323 }
1324 agent.lockLogicalDevice.RUnlock()
khenaidoofc1314d2019-03-14 09:34:21 -04001325 var portCap *ic.PortCapability
1326 var err error
1327 // First get the port capability
1328 if portCap, err = agent.deviceMgr.getPortCapability(nil, childDevice.Id, port.PortNo); err != nil {
1329 log.Errorw("error-retrieving-port-capabilities", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001330 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001331 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001332 agent.lockLogicalDevice.Lock()
1333 defer agent.lockLogicalDevice.Unlock()
1334 // Double check again if this port has been already added since the getPortCapability could have taken a long time
1335 if agent.portExist(childDevice, port) {
1336 log.Debugw("port-already-exist", log.Fields{"port": port})
khenaidoo8f474192019-04-03 17:20:44 -04001337 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001338 }
khenaidoofc1314d2019-03-14 09:34:21 -04001339 // Get stored logical device
1340 if ldevice, err := agent.getLogicalDeviceWithoutLock(); err != nil {
khenaidoo8f474192019-04-03 17:20:44 -04001341 return false, status.Error(codes.NotFound, agent.logicalDeviceId)
khenaidoofc1314d2019-03-14 09:34:21 -04001342 } else {
1343 log.Debugw("adding-uni", log.Fields{"deviceId": childDevice.Id})
1344 portCap.Port.RootPort = false
Matt Jeanneret3815e322019-03-12 19:15:49 -04001345 portCap.Port.Id = port.Label
1346 portCap.Port.OfpPort.PortNo = port.PortNo
khenaidoofc1314d2019-03-14 09:34:21 -04001347 portCap.Port.DeviceId = childDevice.Id
1348 portCap.Port.DevicePortNo = port.PortNo
1349 cloned := (proto.Clone(ldevice)).(*voltha.LogicalDevice)
1350 if cloned.Ports == nil {
1351 cloned.Ports = make([]*voltha.LogicalPort, 0)
1352 }
1353 cloned.Ports = append(cloned.Ports, portCap.Port)
khenaidoo910204f2019-04-08 17:56:40 -04001354 if err := agent.updateLogicalDeviceWithoutLock(cloned); err != nil {
1355 return false, err
1356 }
khenaidoo910204f2019-04-08 17:56:40 -04001357 // Update the device graph with this new logical port
1358 clonedLP := (proto.Clone(portCap.Port)).(*voltha.LogicalPort)
1359 go agent.updateDeviceGraph(clonedLP)
1360 return true, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001361 }
1362}
1363
khenaidoo43c82122018-11-22 18:38:28 -05001364func (agent *LogicalDeviceAgent) packetOut(packet *ofp.OfpPacketOut) {
khenaidoofdbad6e2018-11-06 22:26:38 -05001365 log.Debugw("packet-out", log.Fields{"packet": packet.GetInPort()})
khenaidoo68c930b2019-05-13 11:46:51 -04001366 outPort := fu.GetPacketOutPort(packet)
khenaidoofdbad6e2018-11-06 22:26:38 -05001367 //frame := packet.GetData()
1368 //TODO: Use a channel between the logical agent and the device agent
khenaidooca301322019-01-09 23:06:32 -05001369 if err := agent.deviceMgr.packetOut(agent.rootDeviceId, outPort, packet); err != nil {
khenaidoo910204f2019-04-08 17:56:40 -04001370 log.Error("packetout-failed", log.Fields{"logicalDeviceID": agent.rootDeviceId})
khenaidooca301322019-01-09 23:06:32 -05001371 }
khenaidoofdbad6e2018-11-06 22:26:38 -05001372}
1373
khenaidoo297cd252019-02-07 22:10:23 -05001374func (agent *LogicalDeviceAgent) packetIn(port uint32, transactionId string, packet []byte) {
1375 log.Debugw("packet-in", log.Fields{"port": port, "packet": packet, "transactionId": transactionId})
khenaidoo68c930b2019-05-13 11:46:51 -04001376 packetIn := fu.MkPacketIn(port, packet)
khenaidoo297cd252019-02-07 22:10:23 -05001377 agent.ldeviceMgr.grpcNbiHdlr.sendPacketIn(agent.logicalDeviceId, transactionId, packetIn)
khenaidooca301322019-01-09 23:06:32 -05001378 log.Debugw("sending-packet-in", log.Fields{"packet-in": packetIn})
khenaidoofdbad6e2018-11-06 22:26:38 -05001379}
khenaidoo2c6a0992019-04-29 13:46:56 -04001380
1381func (agent *LogicalDeviceAgent) addLogicalPortToMap(portNo uint32, nniPort bool) {
1382 agent.lockLogicalPortsNo.Lock()
1383 defer agent.lockLogicalPortsNo.Unlock()
1384 if exist := agent.logicalPortsNo[portNo]; !exist {
1385 agent.logicalPortsNo[portNo] = nniPort
1386 }
1387}
1388
khenaidoo3d3b8c22019-05-22 18:10:39 -04001389func (agent *LogicalDeviceAgent) addLogicalPortsToMap(lps []*voltha.LogicalPort) {
1390 agent.lockLogicalPortsNo.Lock()
1391 defer agent.lockLogicalPortsNo.Unlock()
1392 for _, lp := range lps {
1393 if exist := agent.logicalPortsNo[lp.DevicePortNo]; !exist {
1394 agent.logicalPortsNo[lp.DevicePortNo] = lp.RootPort
1395 }
1396 }
1397}
1398
khenaidoo2c6a0992019-04-29 13:46:56 -04001399func (agent *LogicalDeviceAgent) deleteLogicalPortFromMap(portNo uint32) {
1400 agent.lockLogicalPortsNo.Lock()
1401 defer agent.lockLogicalPortsNo.Unlock()
1402 if exist := agent.logicalPortsNo[portNo]; exist {
1403 delete(agent.logicalPortsNo, portNo)
1404 }
1405}
1406
1407func (agent *LogicalDeviceAgent) isNNIPort(portNo uint32) bool {
1408 agent.lockLogicalPortsNo.RLock()
1409 defer agent.lockLogicalPortsNo.RUnlock()
1410 if exist := agent.logicalPortsNo[portNo]; exist {
1411 return agent.logicalPortsNo[portNo]
1412 }
1413 return false
1414}
1415
1416func (agent *LogicalDeviceAgent) getFirstNNIPort() (uint32, error) {
1417 agent.lockLogicalPortsNo.RLock()
1418 defer agent.lockLogicalPortsNo.RUnlock()
1419 for portNo, nni := range agent.logicalPortsNo {
1420 if nni {
1421 return portNo, nil
1422 }
1423 }
1424 return 0, status.Error(codes.NotFound, "No NNI port found")
1425}