blob: 057cc6bc4ec5142dc64d3b09ad6017e495742148 [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
117 // TODO: Set the NNI ports in a separate call once the port update issue is fixed.
118 go agent.setupNNILogicalPorts(ctx, agent.rootDeviceId)
khenaidoo297cd252019-02-07 22:10:23 -0500119 } else {
120 // load from dB - the logical may not exist at this time. On error, just return and the calling function
121 // will destroy this agent.
122 var err error
123 if ld, err = agent.GetLogicalDevice(); err != nil {
124 log.Warnw("failed-to-load-logical-device", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
125 return err
126 }
khenaidoo8c3303d2019-02-13 14:59:39 -0500127 // Update the root device Id
128 agent.rootDeviceId = ld.RootDeviceId
khenaidoob9203542018-09-17 22:56:37 -0400129 }
khenaidoo92e62c52018-10-03 14:02:54 -0400130 agent.lockLogicalDevice.Lock()
khenaidoofc1314d2019-03-14 09:34:21 -0400131
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400132 agent.flowProxy = agent.clusterDataProxy.CreateProxy(
khenaidoo19d7b632018-10-30 10:49:50 -0400133 fmt.Sprintf("/logical_devices/%s/flows", agent.logicalDeviceId),
134 false)
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400135 agent.groupProxy = agent.clusterDataProxy.CreateProxy(
khenaidoo19d7b632018-10-30 10:49:50 -0400136 fmt.Sprintf("/logical_devices/%s/flow_groups", agent.logicalDeviceId),
137 false)
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400138 agent.ldProxy = agent.clusterDataProxy.CreateProxy(
khenaidoofc1314d2019-03-14 09:34:21 -0400139 fmt.Sprintf("/logical_devices/%s", agent.logicalDeviceId),
140 false)
khenaidoo19d7b632018-10-30 10:49:50 -0400141
khenaidoofc1314d2019-03-14 09:34:21 -0400142 // TODO: Use a port proxy once the POST_ADD is fixed
143 agent.ldProxy.RegisterCallback(model.POST_UPDATE, agent.portUpdated)
khenaidoobcf205b2019-01-25 22:21:14 -0500144
khenaidoo2c6a0992019-04-29 13:46:56 -0400145 agent.includeDefaultFlows = true
146
khenaidoofc1314d2019-03-14 09:34:21 -0400147 agent.lockLogicalDevice.Unlock()
khenaidoobcf205b2019-01-25 22:21:14 -0500148
khenaidoob9203542018-09-17 22:56:37 -0400149 return nil
150}
151
khenaidoo4d4802d2018-10-04 21:59:49 -0400152// stop stops the logical devuce agent. This removes the logical device from the data model.
153func (agent *LogicalDeviceAgent) stop(ctx context.Context) {
154 log.Info("stopping-logical_device-agent")
155 agent.lockLogicalDevice.Lock()
156 defer agent.lockLogicalDevice.Unlock()
khenaidoo8c3303d2019-02-13 14:59:39 -0500157
khenaidoo4d4802d2018-10-04 21:59:49 -0400158 //Remove the logical device from the model
159 if removed := agent.clusterDataProxy.Remove("/logical_devices/"+agent.logicalDeviceId, ""); removed == nil {
160 log.Errorw("failed-to-remove-logical-device", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
161 } else {
162 log.Debugw("logicaldevice-removed", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
163 }
164 agent.exitChannel <- 1
165 log.Info("logical_device-agent-stopped")
166}
167
khenaidoo19d7b632018-10-30 10:49:50 -0400168// GetLogicalDevice locks the logical device model and then retrieves the latest logical device information
169func (agent *LogicalDeviceAgent) GetLogicalDevice() (*voltha.LogicalDevice, error) {
170 log.Debug("GetLogicalDevice")
khenaidoo1ce37ad2019-03-24 22:07:24 -0400171 agent.lockLogicalDevice.RLock()
172 defer agent.lockLogicalDevice.RUnlock()
khenaidoo8c3303d2019-02-13 14:59:39 -0500173 logicalDevice := agent.clusterDataProxy.Get("/logical_devices/"+agent.logicalDeviceId, 0, false, "")
khenaidoo92e62c52018-10-03 14:02:54 -0400174 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500175 return lDevice, nil
khenaidoo92e62c52018-10-03 14:02:54 -0400176 }
177 return nil, status.Errorf(codes.NotFound, "logical_device-%s", agent.logicalDeviceId)
178}
179
khenaidoo19d7b632018-10-30 10:49:50 -0400180func (agent *LogicalDeviceAgent) ListLogicalDevicePorts() (*voltha.LogicalPorts, error) {
khenaidoo1ce37ad2019-03-24 22:07:24 -0400181 log.Debug("ListLogicalDevicePorts")
182 agent.lockLogicalDevice.RLock()
183 defer agent.lockLogicalDevice.RUnlock()
khenaidoo8c3303d2019-02-13 14:59:39 -0500184 logicalDevice := agent.clusterDataProxy.Get("/logical_devices/"+agent.logicalDeviceId, 0, false, "")
khenaidoo19d7b632018-10-30 10:49:50 -0400185 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
186 lPorts := make([]*voltha.LogicalPort, 0)
187 for _, port := range lDevice.Ports {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500188 lPorts = append(lPorts, port)
khenaidoo19d7b632018-10-30 10:49:50 -0400189 }
190 return &voltha.LogicalPorts{Items: lPorts}, nil
191 }
192 return nil, status.Errorf(codes.NotFound, "logical_device-%s", agent.logicalDeviceId)
193}
194
195// listFlows locks the logical device model and then retrieves the latest flow information
196func (agent *LogicalDeviceAgent) listFlows() []*ofp.OfpFlowStats {
197 log.Debug("listFlows")
khenaidoo1ce37ad2019-03-24 22:07:24 -0400198 agent.lockLogicalDevice.RLock()
199 defer agent.lockLogicalDevice.RUnlock()
khenaidoo8c3303d2019-02-13 14:59:39 -0500200 logicalDevice := agent.clusterDataProxy.Get("/logical_devices/"+agent.logicalDeviceId, 0, false, "")
khenaidoo19d7b632018-10-30 10:49:50 -0400201 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
202 return lDevice.Flows.Items
203 }
204 return nil
205}
206
207// listFlowGroups locks the logical device model and then retrieves the latest flow groups information
208func (agent *LogicalDeviceAgent) listFlowGroups() []*ofp.OfpGroupEntry {
209 log.Debug("listFlowGroups")
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.FlowGroups.Items
215 }
216 return nil
217}
218
khenaidoo43c82122018-11-22 18:38:28 -0500219//updateLogicalDeviceWithoutLock updates the model with the logical device. It clones the logicaldevice before saving it
220func (agent *LogicalDeviceAgent) updateLogicalDeviceFlowsWithoutLock(flows *ofp.Flows) error {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500221 afterUpdate := agent.flowProxy.Update("/", flows, false, "")
khenaidoo43c82122018-11-22 18:38:28 -0500222 if afterUpdate == nil {
223 return status.Errorf(codes.Internal, "failed-updating-logical-device-flows:%s", agent.logicalDeviceId)
224 }
khenaidoo43c82122018-11-22 18:38:28 -0500225 return nil
226}
227
228//updateLogicalDeviceWithoutLock updates the model with the logical device. It clones the logicaldevice before saving it
229func (agent *LogicalDeviceAgent) updateLogicalDeviceFlowGroupsWithoutLock(flowGroups *ofp.FlowGroups) error {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500230 afterUpdate := agent.groupProxy.Update("/", flowGroups, false, "")
khenaidoo43c82122018-11-22 18:38:28 -0500231 if afterUpdate == nil {
232 return status.Errorf(codes.Internal, "failed-updating-logical-device-flow-groups:%s", agent.logicalDeviceId)
233 }
khenaidoo43c82122018-11-22 18:38:28 -0500234 return nil
235}
236
khenaidoo4d4802d2018-10-04 21:59:49 -0400237// getLogicalDeviceWithoutLock retrieves a logical device from the model without locking it. This is used only by
238// functions that have already acquired the logical device lock to the model
khenaidoo92e62c52018-10-03 14:02:54 -0400239func (agent *LogicalDeviceAgent) getLogicalDeviceWithoutLock() (*voltha.LogicalDevice, error) {
240 log.Debug("getLogicalDeviceWithoutLock")
khenaidoo8c3303d2019-02-13 14:59:39 -0500241 logicalDevice := agent.clusterDataProxy.Get("/logical_devices/"+agent.logicalDeviceId, 0, false, "")
khenaidoo92e62c52018-10-03 14:02:54 -0400242 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
khenaidoo1ce37ad2019-03-24 22:07:24 -0400243 //log.Debug("getLogicalDeviceWithoutLock", log.Fields{"ldevice": lDevice})
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500244 return lDevice, nil
khenaidoo92e62c52018-10-03 14:02:54 -0400245 }
246 return nil, status.Errorf(codes.NotFound, "logical_device-%s", agent.logicalDeviceId)
247}
248
khenaidoo2c6a0992019-04-29 13:46:56 -0400249func (agent *LogicalDeviceAgent) updateLogicalPort(device *voltha.Device, port *voltha.Port) error {
250 log.Debugw("updateLogicalPort", log.Fields{"deviceId": device.Id, "port": port})
251 var err error
252 if port.Type == voltha.Port_ETHERNET_NNI {
253 if _, err = agent.addNNILogicalPort(device, port); err != nil {
254 return err
255 }
256 agent.addLogicalPortToMap(port.PortNo, true)
257 } else if port.Type == voltha.Port_ETHERNET_UNI {
258 if _, err = agent.addUNILogicalPort(device, port); err != nil {
259 return err
260 }
261 agent.addLogicalPortToMap(port.PortNo, false)
262 } else {
263 // Update the device graph to ensure all routes on the logical device have been calculated
264 if err = agent.updateRoutes(device, port); err != nil {
265 log.Errorw("failed-to-update-routes", log.Fields{"deviceId": device.Id, "port": port, "error": err})
266 return err
267 }
268 }
269 return nil
270}
271
khenaidoo910204f2019-04-08 17:56:40 -0400272func (agent *LogicalDeviceAgent) addLogicalPort(device *voltha.Device, port *voltha.Port) error {
khenaidoo8f474192019-04-03 17:20:44 -0400273 log.Debugw("addLogicalPort", log.Fields{"deviceId": device.Id, "port": port})
khenaidoo8f474192019-04-03 17:20:44 -0400274 var err error
khenaidoofc1314d2019-03-14 09:34:21 -0400275 if port.Type == voltha.Port_ETHERNET_NNI {
khenaidoo910204f2019-04-08 17:56:40 -0400276 if _, err = agent.addNNILogicalPort(device, port); err != nil {
khenaidoofc1314d2019-03-14 09:34:21 -0400277 return err
278 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400279 agent.addLogicalPortToMap(port.PortNo, true)
khenaidoofc1314d2019-03-14 09:34:21 -0400280 } else if port.Type == voltha.Port_ETHERNET_UNI {
khenaidoo910204f2019-04-08 17:56:40 -0400281 if _, err = agent.addUNILogicalPort(device, port); err != nil {
khenaidoofc1314d2019-03-14 09:34:21 -0400282 return err
283 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400284 agent.addLogicalPortToMap(port.PortNo, false)
khenaidoofc1314d2019-03-14 09:34:21 -0400285 } else {
286 log.Debugw("invalid-port-type", log.Fields{"deviceId": device.Id, "port": port})
287 return nil
288 }
khenaidoofc1314d2019-03-14 09:34:21 -0400289 return nil
290}
291
292// setupNNILogicalPorts creates an NNI port on the logical device that represents an NNI interface on a root device
293func (agent *LogicalDeviceAgent) setupNNILogicalPorts(ctx context.Context, deviceId string) error {
294 log.Infow("setupNNILogicalPorts-start", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoob9203542018-09-17 22:56:37 -0400295 // Build the logical device based on information retrieved from the device adapter
khenaidoofc1314d2019-03-14 09:34:21 -0400296 var err error
297
298 var device *voltha.Device
299 if device, err = agent.deviceMgr.GetDevice(deviceId); err != nil {
khenaidoo2c6a0992019-04-29 13:46:56 -0400300 log.Errorw("error-retrieving-device", log.Fields{"error": err, "deviceId": deviceId})
khenaidoofc1314d2019-03-14 09:34:21 -0400301 return err
302 }
303
304 //Get UNI port number
khenaidoofc1314d2019-03-14 09:34:21 -0400305 for _, port := range device.Ports {
306 if port.Type == voltha.Port_ETHERNET_NNI {
khenaidoo910204f2019-04-08 17:56:40 -0400307 if _, err = agent.addNNILogicalPort(device, port); err != nil {
khenaidoofc1314d2019-03-14 09:34:21 -0400308 log.Errorw("error-adding-UNI-port", log.Fields{"error": err})
khenaidoofc1314d2019-03-14 09:34:21 -0400309 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400310 agent.addLogicalPortToMap(port.PortNo, true)
khenaidoofc1314d2019-03-14 09:34:21 -0400311 }
312 }
khenaidoofc1314d2019-03-14 09:34:21 -0400313 return err
314}
315
khenaidoo3ab34882019-05-02 21:33:30 -0400316// updatePortsState updates the ports state related to the device
317func (agent *LogicalDeviceAgent) updatePortsState(device *voltha.Device, state voltha.AdminState_AdminState) error {
318 log.Infow("updatePortsState-start", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
319 agent.lockLogicalDevice.Lock()
320 defer agent.lockLogicalDevice.Unlock()
321 // Get the latest logical device info
322 if ld, err := agent.getLogicalDeviceWithoutLock(); err != nil {
323 log.Warnw("logical-device-unknown", log.Fields{"ldeviceId": agent.logicalDeviceId, "error": err})
324 return err
325 } else {
326 cloned := (proto.Clone(ld)).(*voltha.LogicalDevice)
327 for _, lport := range cloned.Ports {
328 if lport.DeviceId == device.Id {
329 switch state {
330 case voltha.AdminState_ENABLED:
331 lport.OfpPort.Config = lport.OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
khenaidoo0a822f92019-05-08 15:15:57 -0400332 lport.OfpPort.State = uint32(ofp.OfpPortState_OFPPS_LIVE)
khenaidoo3ab34882019-05-02 21:33:30 -0400333 case voltha.AdminState_DISABLED:
334 lport.OfpPort.Config = lport.OfpPort.Config | uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
khenaidoo0a822f92019-05-08 15:15:57 -0400335 lport.OfpPort.State = uint32(ofp.OfpPortState_OFPPS_LINK_DOWN)
khenaidoo3ab34882019-05-02 21:33:30 -0400336 default:
337 log.Warnw("unsupported-state-change", log.Fields{"deviceId": device.Id, "state": state})
338 }
339 }
340 }
341 // Updating the logical device will trigger the poprt change events to be populated to the controller
342 if err := agent.updateLogicalDeviceWithoutLock(cloned); err != nil {
343 log.Warnw("logical-device-update-failed", log.Fields{"ldeviceId": agent.logicalDeviceId, "error": err})
344 return err
345 }
346 }
347 return nil
348}
349
khenaidoofc1314d2019-03-14 09:34:21 -0400350// setupUNILogicalPorts creates a UNI port on the logical device that represents a child UNI interface
351func (agent *LogicalDeviceAgent) setupUNILogicalPorts(ctx context.Context, childDevice *voltha.Device) error {
352 log.Infow("setupUNILogicalPort-start", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
353 // Build the logical device based on information retrieved from the device adapter
khenaidoob9203542018-09-17 22:56:37 -0400354 var err error
khenaidoo19d7b632018-10-30 10:49:50 -0400355
356 //Get UNI port number
khenaidoo19d7b632018-10-30 10:49:50 -0400357 for _, port := range childDevice.Ports {
358 if port.Type == voltha.Port_ETHERNET_UNI {
khenaidoo910204f2019-04-08 17:56:40 -0400359 if _, err = agent.addUNILogicalPort(childDevice, port); err != nil {
khenaidoofc1314d2019-03-14 09:34:21 -0400360 log.Errorw("error-adding-UNI-port", log.Fields{"error": err})
khenaidoofc1314d2019-03-14 09:34:21 -0400361 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400362 agent.addLogicalPortToMap(port.PortNo, false)
khenaidoo19d7b632018-10-30 10:49:50 -0400363 }
364 }
khenaidoofc1314d2019-03-14 09:34:21 -0400365 return err
khenaidoo92e62c52018-10-03 14:02:54 -0400366}
367
khenaidoo0a822f92019-05-08 15:15:57 -0400368// deleteAllLogicalPorts deletes all logical ports associated with this device
369func (agent *LogicalDeviceAgent) deleteAllLogicalPorts(device *voltha.Device) error {
370 log.Infow("updatePortsState-start", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
371 agent.lockLogicalDevice.Lock()
372 defer agent.lockLogicalDevice.Unlock()
373 // Get the latest logical device info
374 if ld, err := agent.getLogicalDeviceWithoutLock(); err != nil {
375 log.Warnw("logical-device-unknown", log.Fields{"ldeviceId": agent.logicalDeviceId, "error": err})
376 return err
377 } else {
378 cloned := (proto.Clone(ld)).(*voltha.LogicalDevice)
379 updateLogicalPorts := []*voltha.LogicalPort{}
380 for _, lport := range cloned.Ports {
381 if lport.DeviceId != device.Id {
382 updateLogicalPorts = append(updateLogicalPorts, lport)
383 }
384 }
385 if len(updateLogicalPorts) < len(cloned.Ports) {
386 cloned.Ports = updateLogicalPorts
387 // Updating the logical device will trigger the poprt change events to be populated to the controller
388 if err := agent.updateLogicalDeviceWithoutLock(cloned); err != nil {
389 log.Warnw("logical-device-update-failed", log.Fields{"ldeviceId": agent.logicalDeviceId, "error": err})
390 return err
391 }
392 } else {
393 log.Debugw("no-change-required", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
394 }
395 }
396 return nil
397}
398
khenaidoo92e62c52018-10-03 14:02:54 -0400399//updateLogicalDeviceWithoutLock updates the model with the logical device. It clones the logicaldevice before saving it
400func (agent *LogicalDeviceAgent) updateLogicalDeviceWithoutLock(logicalDevice *voltha.LogicalDevice) error {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500401 afterUpdate := agent.clusterDataProxy.Update("/logical_devices/"+agent.logicalDeviceId, logicalDevice, false, "")
khenaidoo92e62c52018-10-03 14:02:54 -0400402 if afterUpdate == nil {
403 return status.Errorf(codes.Internal, "failed-updating-logical-device:%s", agent.logicalDeviceId)
404 }
405 return nil
406}
407
khenaidoo19d7b632018-10-30 10:49:50 -0400408//updateFlowTable updates the flow table of that logical device
409func (agent *LogicalDeviceAgent) updateFlowTable(ctx context.Context, flow *ofp.OfpFlowMod) error {
410 log.Debug("updateFlowTable")
411 if flow == nil {
412 return nil
413 }
414 switch flow.GetCommand() {
415 case ofp.OfpFlowModCommand_OFPFC_ADD:
416 return agent.flowAdd(flow)
417 case ofp.OfpFlowModCommand_OFPFC_DELETE:
418 return agent.flowDelete(flow)
419 case ofp.OfpFlowModCommand_OFPFC_DELETE_STRICT:
420 return agent.flowDeleteStrict(flow)
421 case ofp.OfpFlowModCommand_OFPFC_MODIFY:
422 return agent.flowModify(flow)
423 case ofp.OfpFlowModCommand_OFPFC_MODIFY_STRICT:
424 return agent.flowModifyStrict(flow)
425 }
426 return status.Errorf(codes.Internal,
427 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceId, flow.GetCommand())
428}
429
430//updateGroupTable updates the group table of that logical device
431func (agent *LogicalDeviceAgent) updateGroupTable(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
432 log.Debug("updateGroupTable")
433 if groupMod == nil {
434 return nil
435 }
436 switch groupMod.GetCommand() {
437 case ofp.OfpGroupModCommand_OFPGC_ADD:
438 return agent.groupAdd(groupMod)
439 case ofp.OfpGroupModCommand_OFPGC_DELETE:
440 return agent.groupDelete(groupMod)
441 case ofp.OfpGroupModCommand_OFPGC_MODIFY:
442 return agent.groupModify(groupMod)
443 }
444 return status.Errorf(codes.Internal,
445 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceId, groupMod.GetCommand())
446}
447
khenaidoo19d7b632018-10-30 10:49:50 -0400448//flowAdd adds a flow to the flow table of that logical device
449func (agent *LogicalDeviceAgent) flowAdd(mod *ofp.OfpFlowMod) error {
450 log.Debug("flowAdd")
451 if mod == nil {
452 return nil
453 }
khenaidoo92e62c52018-10-03 14:02:54 -0400454 agent.lockLogicalDevice.Lock()
455 defer agent.lockLogicalDevice.Unlock()
khenaidoo19d7b632018-10-30 10:49:50 -0400456
457 var lDevice *voltha.LogicalDevice
458 var err error
459 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
460 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
461 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
462 }
463
464 var flows []*ofp.OfpFlowStats
465 if lDevice.Flows != nil && lDevice.Flows.Items != nil {
466 flows = lDevice.Flows.Items
467 }
468
khenaidoo2c6a0992019-04-29 13:46:56 -0400469 updatedFlows := make([]*ofp.OfpFlowStats, 0)
khenaidoo43c82122018-11-22 18:38:28 -0500470 //oldData := proto.Clone(lDevice.Flows).(*voltha.Flows)
khenaidoo19d7b632018-10-30 10:49:50 -0400471 changed := false
472 checkOverlap := (mod.Flags & uint32(ofp.OfpFlowModFlags_OFPFF_CHECK_OVERLAP)) != 0
473 if checkOverlap {
474 if overlapped := fu.FindOverlappingFlows(flows, mod); len(overlapped) != 0 {
475 // TODO: should this error be notified other than being logged?
476 log.Warnw("overlapped-flows", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
477 } else {
478 // Add flow
khenaidoo68c930b2019-05-13 11:46:51 -0400479 flow := fu.FlowStatsEntryFromFlowModMessage(mod)
khenaidoo19d7b632018-10-30 10:49:50 -0400480 flows = append(flows, flow)
khenaidoo2c6a0992019-04-29 13:46:56 -0400481 updatedFlows = append(updatedFlows, flow)
khenaidoo19d7b632018-10-30 10:49:50 -0400482 changed = true
483 }
484 } else {
khenaidoo68c930b2019-05-13 11:46:51 -0400485 flow := fu.FlowStatsEntryFromFlowModMessage(mod)
khenaidoo19d7b632018-10-30 10:49:50 -0400486 idx := fu.FindFlows(flows, flow)
487 if idx >= 0 {
488 oldFlow := flows[idx]
489 if (mod.Flags & uint32(ofp.OfpFlowModFlags_OFPFF_RESET_COUNTS)) != 0 {
490 flow.ByteCount = oldFlow.ByteCount
491 flow.PacketCount = oldFlow.PacketCount
492 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400493 if !reflect.DeepEqual(oldFlow, flow) {
494 flows[idx] = flow
495 updatedFlows = append(updatedFlows, flow)
496 changed = true
497 }
khenaidoo19d7b632018-10-30 10:49:50 -0400498 } else {
499 flows = append(flows, flow)
khenaidoo2c6a0992019-04-29 13:46:56 -0400500 updatedFlows = append(updatedFlows, flow)
501 changed = true
khenaidoo19d7b632018-10-30 10:49:50 -0400502 }
khenaidoo19d7b632018-10-30 10:49:50 -0400503 }
504 if changed {
khenaidoo2c6a0992019-04-29 13:46:56 -0400505 // Launch a routine to decompose the flows
506 if err := agent.decomposeAndSendFlows(&ofp.Flows{Items: updatedFlows}, lDevice.FlowGroups, agent.includeDefaultFlows); err != nil {
manikkaraj k259a6f72019-05-06 09:55:44 -0400507 log.Errorw("decomposing-and-sending-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo2c6a0992019-04-29 13:46:56 -0400508 return err
509 }
510
511 // We no longer need to sent the default flows, unless there is a change in device topology
512 agent.includeDefaultFlows = false
513
khenaidoo19d7b632018-10-30 10:49:50 -0400514 // Update model
khenaidoo43c82122018-11-22 18:38:28 -0500515 flowsToUpdate := &ofp.Flows{}
516 if lDevice.Flows != nil {
517 flowsToUpdate = &ofp.Flows{Items: flows}
khenaidoo19d7b632018-10-30 10:49:50 -0400518 }
khenaidoo43c82122018-11-22 18:38:28 -0500519 if err := agent.updateLogicalDeviceFlowsWithoutLock(flowsToUpdate); err != nil {
khenaidoo2c6a0992019-04-29 13:46:56 -0400520 log.Errorw("db-flow-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400521 return err
522 }
523 }
khenaidoo19d7b632018-10-30 10:49:50 -0400524 return nil
525}
526
khenaidoo2c6a0992019-04-29 13:46:56 -0400527func (agent *LogicalDeviceAgent) decomposeAndSendFlows(flows *ofp.Flows, groups *ofp.FlowGroups, includeDefaultFlows bool) error {
528 log.Debugw("decomposeAndSendFlows", log.Fields{"logicalDeviceID": agent.logicalDeviceId})
529
530 deviceRules := agent.flowDecomposer.DecomposeRules(agent, *flows, *groups, includeDefaultFlows)
531 log.Debugw("rules", log.Fields{"rules": deviceRules.String()})
532
533 chnlsList := make([]chan interface{}, 0)
534 for deviceId, value := range deviceRules.GetRules() {
535 ch := make(chan interface{})
536 chnlsList = append(chnlsList, ch)
537 go func(deviceId string, flows []*ofp.OfpFlowStats, groups []*ofp.OfpGroupEntry) {
538 if err := agent.deviceMgr.addFlowsAndGroups(deviceId, flows, groups); err != nil {
539 log.Error("flow-update-failed", log.Fields{"deviceID": deviceId})
540 ch <- status.Errorf(codes.Internal, "flow-update-failed: %s", deviceId)
541 }
542 ch <- nil
543 }(deviceId, value.ListFlows(), value.ListGroups())
544 }
545 // Wait for completion
546 if res := fu.WaitForNilOrErrorResponses(agent.defaultTimeout, chnlsList...); res != nil {
547 return status.Errorf(codes.Aborted, "errors-%s", res)
548 }
549 return nil
550}
551
khenaidoo19d7b632018-10-30 10:49:50 -0400552//flowDelete deletes a flow from the flow table of that logical device
553func (agent *LogicalDeviceAgent) flowDelete(mod *ofp.OfpFlowMod) error {
554 log.Debug("flowDelete")
555 if mod == nil {
556 return nil
557 }
558 agent.lockLogicalDevice.Lock()
559 defer agent.lockLogicalDevice.Unlock()
560
561 var lDevice *voltha.LogicalDevice
562 var err error
563 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
564 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
565 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
566 }
567 flows := lDevice.Flows.Items
568
569 //build a list of what to keep vs what to delete
570 toKeep := make([]*ofp.OfpFlowStats, 0)
571 for _, f := range flows {
572 if !fu.FlowMatchesMod(f, mod) {
573 toKeep = append(toKeep, f)
574 }
575 }
576
577 //Update flows
578 if len(toKeep) < len(flows) {
khenaidoo43c82122018-11-22 18:38:28 -0500579 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: toKeep}); err != nil {
580 log.Errorw("Cannot-update-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400581 return err
582 }
583 }
584
585 //TODO: send announcement on delete
586 return nil
587}
588
589//flowStatsDelete deletes a flow from the flow table of that logical device
590func (agent *LogicalDeviceAgent) flowStatsDelete(flow *ofp.OfpFlowStats) error {
591 log.Debug("flowStatsDelete")
592 if flow == nil {
593 return nil
594 }
595 agent.lockLogicalDevice.Lock()
596 defer agent.lockLogicalDevice.Unlock()
597
598 var lDevice *voltha.LogicalDevice
599 var err error
600 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
601 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
602 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
603 }
604 flows := lDevice.Flows.Items
605
606 //build a list of what to keep vs what to delete
607 toKeep := make([]*ofp.OfpFlowStats, 0)
608 for _, f := range flows {
609 if !fu.FlowMatch(f, flow) {
610 toKeep = append(toKeep, f)
611 }
612 }
613
614 //Update flows
615 if len(toKeep) < len(flows) {
khenaidoo43c82122018-11-22 18:38:28 -0500616 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: toKeep}); err != nil {
khenaidoo19d7b632018-10-30 10:49:50 -0400617 log.Errorw("Cannot-update-logical-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
618 return err
619 }
620 }
621 return nil
622}
623
624//flowDeleteStrict deletes a flow from the flow table of that logical device
625func (agent *LogicalDeviceAgent) flowDeleteStrict(mod *ofp.OfpFlowMod) error {
626 log.Debug("flowDeleteStrict")
627 if mod == nil {
628 return nil
629 }
630 agent.lockLogicalDevice.Lock()
631 defer agent.lockLogicalDevice.Unlock()
632
633 var lDevice *voltha.LogicalDevice
634 var err error
635 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
636 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
637 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
638 }
639 flows := lDevice.Flows.Items
640 changed := false
khenaidoo68c930b2019-05-13 11:46:51 -0400641 flow := fu.FlowStatsEntryFromFlowModMessage(mod)
khenaidoo19d7b632018-10-30 10:49:50 -0400642 idx := fu.FindFlows(flows, flow)
643 if idx >= 0 {
644 flows = append(flows[:idx], flows[idx+1:]...)
645 changed = true
646 } else {
647 return errors.New(fmt.Sprintf("Cannot delete flow - %s", flow))
648 }
649
650 if changed {
khenaidoo43c82122018-11-22 18:38:28 -0500651 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: flows}); err != nil {
khenaidoo19d7b632018-10-30 10:49:50 -0400652 log.Errorw("Cannot-update-logical-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
653 return err
654 }
655 }
656
657 return nil
658}
659
660//flowModify modifies a flow from the flow table of that logical device
661func (agent *LogicalDeviceAgent) flowModify(mod *ofp.OfpFlowMod) error {
662 return errors.New("flowModify not implemented")
663}
664
665//flowModifyStrict deletes a flow from the flow table of that logical device
666func (agent *LogicalDeviceAgent) flowModifyStrict(mod *ofp.OfpFlowMod) error {
667 return errors.New("flowModifyStrict not implemented")
668}
669
670func (agent *LogicalDeviceAgent) groupAdd(groupMod *ofp.OfpGroupMod) error {
671 log.Debug("groupAdd")
672 if groupMod == nil {
673 return nil
674 }
675 agent.lockLogicalDevice.Lock()
676 defer agent.lockLogicalDevice.Unlock()
677
678 var lDevice *voltha.LogicalDevice
679 var err error
680 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
681 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
682 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
683 }
684 groups := lDevice.FlowGroups.Items
khenaidoo19d7b632018-10-30 10:49:50 -0400685 if fu.FindGroup(groups, groupMod.GroupId) == -1 {
khenaidoo68c930b2019-05-13 11:46:51 -0400686 groups = append(groups, fu.GroupEntryFromGroupMod(groupMod))
khenaidoo43c82122018-11-22 18:38:28 -0500687 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(&ofp.FlowGroups{Items: groups}); err != nil {
688 log.Errorw("Cannot-update-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400689 return err
690 }
691 } else {
692 return errors.New(fmt.Sprintf("Groups %d already present", groupMod.GroupId))
693 }
khenaidoo19d7b632018-10-30 10:49:50 -0400694 return nil
695}
696
697func (agent *LogicalDeviceAgent) groupDelete(groupMod *ofp.OfpGroupMod) error {
698 log.Debug("groupDelete")
699 if groupMod == nil {
700 return nil
701 }
702 agent.lockLogicalDevice.Lock()
703 defer agent.lockLogicalDevice.Unlock()
704
705 var lDevice *voltha.LogicalDevice
706 var err error
707 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
708 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
709 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
710 }
711 groups := lDevice.FlowGroups.Items
712 flows := lDevice.Flows.Items
713 groupsChanged := false
714 flowsChanged := false
715 groupId := groupMod.GroupId
716 if groupId == uint32(ofp.OfpGroup_OFPG_ALL) {
717 //TODO we must delete all flows that point to this group and
718 //signal controller as requested by flow's flag
719 groups = []*ofp.OfpGroupEntry{}
720 groupsChanged = true
721 } else {
722 if idx := fu.FindGroup(groups, groupId); idx == -1 {
723 return nil // Valid case
724 } else {
725 flowsChanged, flows = fu.FlowsDeleteByGroupId(flows, groupId)
726 groups = append(groups[:idx], groups[idx+1:]...)
727 groupsChanged = true
728 }
729 }
khenaidoo43c82122018-11-22 18:38:28 -0500730 if groupsChanged {
731 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(&ofp.FlowGroups{Items: groups}); err != nil {
732 log.Errorw("Cannot-update-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400733 return err
734 }
735 }
khenaidoo43c82122018-11-22 18:38:28 -0500736 if flowsChanged {
737 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: flows}); err != nil {
738 log.Errorw("Cannot-update-flow", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
739 return err
740 }
741 }
742
khenaidoo19d7b632018-10-30 10:49:50 -0400743 return nil
744}
745
746func (agent *LogicalDeviceAgent) groupModify(groupMod *ofp.OfpGroupMod) error {
747 log.Debug("groupModify")
748 if groupMod == nil {
749 return nil
750 }
751 agent.lockLogicalDevice.Lock()
752 defer agent.lockLogicalDevice.Unlock()
753
754 var lDevice *voltha.LogicalDevice
755 var err error
756 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
757 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
758 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
759 }
760 groups := lDevice.FlowGroups.Items
761 groupsChanged := false
762 groupId := groupMod.GroupId
763 if idx := fu.FindGroup(groups, groupId); idx == -1 {
khenaidooca301322019-01-09 23:06:32 -0500764 return errors.New(fmt.Sprintf("group-absent:%d", groupId))
khenaidoo19d7b632018-10-30 10:49:50 -0400765 } else {
766 //replace existing group entry with new group definition
khenaidoo68c930b2019-05-13 11:46:51 -0400767 groupEntry := fu.GroupEntryFromGroupMod(groupMod)
khenaidoo19d7b632018-10-30 10:49:50 -0400768 groups[idx] = groupEntry
769 groupsChanged = true
770 }
771 if groupsChanged {
khenaidoo43c82122018-11-22 18:38:28 -0500772 //lDevice.FlowGroups.Items = groups
773 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(&ofp.FlowGroups{Items: groups}); err != nil {
khenaidoo19d7b632018-10-30 10:49:50 -0400774 log.Errorw("Cannot-update-logical-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
775 return err
776 }
777 }
778 return nil
779}
780
781// deleteLogicalPort removes the logical port
782func (agent *LogicalDeviceAgent) deleteLogicalPort(lPort *voltha.LogicalPort) error {
783 agent.lockLogicalDevice.Lock()
784 defer agent.lockLogicalDevice.Unlock()
785
khenaidoo92e62c52018-10-03 14:02:54 -0400786 // Get the most up to date logical device
787 var logicaldevice *voltha.LogicalDevice
788 if logicaldevice, _ = agent.getLogicalDeviceWithoutLock(); logicaldevice == nil {
khenaidoo19d7b632018-10-30 10:49:50 -0400789 log.Debugw("no-logical-device", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "logicalPortId": lPort.Id})
khenaidoob9203542018-09-17 22:56:37 -0400790 return nil
791 }
khenaidoo92e62c52018-10-03 14:02:54 -0400792 index := -1
793 for i, logicalPort := range logicaldevice.Ports {
khenaidoo19d7b632018-10-30 10:49:50 -0400794 if logicalPort.Id == lPort.Id {
khenaidoo92e62c52018-10-03 14:02:54 -0400795 index = i
796 break
797 }
798 }
799 if index >= 0 {
800 copy(logicaldevice.Ports[index:], logicaldevice.Ports[index+1:])
801 logicaldevice.Ports[len(logicaldevice.Ports)-1] = nil
802 logicaldevice.Ports = logicaldevice.Ports[:len(logicaldevice.Ports)-1]
803 log.Debugw("logical-port-deleted", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo0a822f92019-05-08 15:15:57 -0400804 if err := agent.updateLogicalDeviceWithoutLock(logicaldevice); err != nil {
805 log.Errorw("logical-device-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
806 return err
807 }
808 // Reset the logical device graph
809 go agent.redoDeviceGraph()
khenaidoo92e62c52018-10-03 14:02:54 -0400810 }
811 return nil
khenaidoob9203542018-09-17 22:56:37 -0400812}
813
khenaidoo0a822f92019-05-08 15:15:57 -0400814// deleteLogicalPorts removes the logical ports associated with that deviceId
815func (agent *LogicalDeviceAgent) deleteLogicalPorts(deviceId string) error {
816 agent.lockLogicalDevice.Lock()
817 defer agent.lockLogicalDevice.Unlock()
818
819 // Get the most up to date logical device
820 var logicaldevice *voltha.LogicalDevice
821 if logicaldevice, _ = agent.getLogicalDeviceWithoutLock(); logicaldevice == nil {
822 log.Debugw("no-logical-device", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
823 return nil
824 }
825 updatedLPorts := []*voltha.LogicalPort{}
826 for _, logicalPort := range logicaldevice.Ports {
827 if logicalPort.DeviceId != deviceId {
828 updatedLPorts = append(updatedLPorts, logicalPort)
829 }
830 }
831 logicaldevice.Ports = updatedLPorts
832 log.Debugw("updated-logical-ports", log.Fields{"ports": updatedLPorts})
833 if err := agent.updateLogicalDeviceWithoutLock(logicaldevice); err != nil {
834 log.Errorw("logical-device-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
835 return err
836 }
837 // Reset the logical device graph
838 go agent.redoDeviceGraph()
839
840 return nil
841}
842
khenaidoo19d7b632018-10-30 10:49:50 -0400843// enableLogicalPort enables the logical port
844func (agent *LogicalDeviceAgent) enableLogicalPort(lPort *voltha.LogicalPort) error {
845 agent.lockLogicalDevice.Lock()
846 defer agent.lockLogicalDevice.Unlock()
847
848 // Get the most up to date logical device
849 var logicaldevice *voltha.LogicalDevice
850 if logicaldevice, _ = agent.getLogicalDeviceWithoutLock(); logicaldevice == nil {
851 log.Debugw("no-logical-device", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "logicalPortId": lPort.Id})
852 return nil
853 }
854 index := -1
855 for i, logicalPort := range logicaldevice.Ports {
856 if logicalPort.Id == lPort.Id {
857 index = i
858 break
859 }
860 }
861 if index >= 0 {
862 logicaldevice.Ports[index].OfpPort.Config = logicaldevice.Ports[index].OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
863 return agent.updateLogicalDeviceWithoutLock(logicaldevice)
864 }
865 //TODO: Trigger subsequent actions on the device
866 return nil
867}
868
869// disableLogicalPort disabled the logical port
870func (agent *LogicalDeviceAgent) disableLogicalPort(lPort *voltha.LogicalPort) error {
871 agent.lockLogicalDevice.Lock()
872 defer agent.lockLogicalDevice.Unlock()
873
874 // Get the most up to date logical device
875 var logicaldevice *voltha.LogicalDevice
876 if logicaldevice, _ = agent.getLogicalDeviceWithoutLock(); logicaldevice == nil {
877 log.Debugw("no-logical-device", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "logicalPortId": lPort.Id})
878 return nil
879 }
880 index := -1
881 for i, logicalPort := range logicaldevice.Ports {
882 if logicalPort.Id == lPort.Id {
883 index = i
884 break
885 }
886 }
887 if index >= 0 {
888 logicaldevice.Ports[index].OfpPort.Config = (logicaldevice.Ports[index].OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)) | uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
889 return agent.updateLogicalDeviceWithoutLock(logicaldevice)
890 }
891 //TODO: Trigger subsequent actions on the device
892 return nil
893}
894
khenaidoo89b0e942018-10-21 21:11:33 -0400895func (agent *LogicalDeviceAgent) getPreCalculatedRoute(ingress, egress uint32) []graph.RouteHop {
khenaidoo19d7b632018-10-30 10:49:50 -0400896 log.Debugw("ROUTE", log.Fields{"len": len(agent.deviceGraph.Routes)})
khenaidoo89b0e942018-10-21 21:11:33 -0400897 for routeLink, route := range agent.deviceGraph.Routes {
khenaidoo19d7b632018-10-30 10:49:50 -0400898 log.Debugw("ROUTELINKS", log.Fields{"ingress": ingress, "egress": egress, "routelink": routeLink})
khenaidoo89b0e942018-10-21 21:11:33 -0400899 if ingress == routeLink.Ingress && egress == routeLink.Egress {
900 return route
901 }
902 }
903 log.Warnw("no-route", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "ingress": ingress, "egress": egress})
904 return nil
905}
906
khenaidoo19d7b632018-10-30 10:49:50 -0400907func (agent *LogicalDeviceAgent) GetRoute(ingressPortNo uint32, egressPortNo uint32) []graph.RouteHop {
khenaidoo89b0e942018-10-21 21:11:33 -0400908 log.Debugw("getting-route", log.Fields{"ingress-port": ingressPortNo, "egress-port": egressPortNo})
khenaidoo89b0e942018-10-21 21:11:33 -0400909 routes := make([]graph.RouteHop, 0)
khenaidoo2c6a0992019-04-29 13:46:56 -0400910
khenaidoo19d7b632018-10-30 10:49:50 -0400911 // Note: A port value of 0 is equivalent to a nil port
912
khenaidoo89b0e942018-10-21 21:11:33 -0400913 // Consider different possibilities
khenaidoo19d7b632018-10-30 10:49:50 -0400914 if egressPortNo != 0 && ((egressPortNo & 0x7fffffff) == uint32(ofp.OfpPortNo_OFPP_CONTROLLER)) {
khenaidoo2c6a0992019-04-29 13:46:56 -0400915 log.Debugw("controller-flow", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "logicalPortsNo": agent.logicalPortsNo})
916 if agent.isNNIPort(ingressPortNo) {
khenaidoo89b0e942018-10-21 21:11:33 -0400917 log.Debug("returning-half-route")
918 //This is a trap on the NNI Port
khenaidoo8f474192019-04-03 17:20:44 -0400919 if len(agent.deviceGraph.Routes) == 0 {
920 // If there are no routes set (usually when the logical device has only NNI port(s), then just return an
921 // internal route
khenaidoo2c6a0992019-04-29 13:46:56 -0400922 hop := graph.RouteHop{DeviceID: agent.rootDeviceId, Ingress: ingressPortNo, Egress: egressPortNo}
khenaidoo8f474192019-04-03 17:20:44 -0400923 routes = append(routes, hop)
924 routes = append(routes, hop)
925 return routes
926 }
khenaidoo89b0e942018-10-21 21:11:33 -0400927 //Return a 'half' route to make the flow decomposer logic happy
928 for routeLink, route := range agent.deviceGraph.Routes {
khenaidoo2c6a0992019-04-29 13:46:56 -0400929 if agent.isNNIPort(routeLink.Egress) {
khenaidoo89b0e942018-10-21 21:11:33 -0400930 routes = append(routes, graph.RouteHop{}) // first hop is set to empty
931 routes = append(routes, route[1])
932 return routes
933 }
934 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400935 log.Warnw("no-upstream-route", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "logicalPortsNo": agent.logicalPortsNo})
khenaidoo89b0e942018-10-21 21:11:33 -0400936 return nil
937 }
938 //treat it as if the output port is the first NNI of the OLT
khenaidoo2c6a0992019-04-29 13:46:56 -0400939 var err error
940 if egressPortNo, err = agent.getFirstNNIPort(); err != nil {
941 log.Warnw("no-nni-port", log.Fields{"error": err})
942 return nil
943 }
khenaidoo89b0e942018-10-21 21:11:33 -0400944 }
945 //If ingress port is not specified (nil), it may be a wildcarded
946 //route if egress port is OFPP_CONTROLLER or a nni logical port,
947 //in which case we need to create a half-route where only the egress
948 //hop is filled, the first hop is nil
khenaidoo2c6a0992019-04-29 13:46:56 -0400949 if ingressPortNo == 0 && agent.isNNIPort(egressPortNo) {
khenaidoo89b0e942018-10-21 21:11:33 -0400950 // We can use the 2nd hop of any upstream route, so just find the first upstream:
951 for routeLink, route := range agent.deviceGraph.Routes {
khenaidoo2c6a0992019-04-29 13:46:56 -0400952 if agent.isNNIPort(routeLink.Egress) {
khenaidoo89b0e942018-10-21 21:11:33 -0400953 routes = append(routes, graph.RouteHop{}) // first hop is set to empty
954 routes = append(routes, route[1])
955 return routes
956 }
957 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400958 log.Warnw("no-upstream-route", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "logicalPortsNo": agent.logicalPortsNo})
khenaidoo89b0e942018-10-21 21:11:33 -0400959 return nil
960 }
961 //If egress port is not specified (nil), we can also can return a "half" route
khenaidoo19d7b632018-10-30 10:49:50 -0400962 if egressPortNo == 0 {
khenaidoo89b0e942018-10-21 21:11:33 -0400963 for routeLink, route := range agent.deviceGraph.Routes {
khenaidoo19d7b632018-10-30 10:49:50 -0400964 if routeLink.Ingress == ingressPortNo {
khenaidoo89b0e942018-10-21 21:11:33 -0400965 routes = append(routes, route[0])
966 routes = append(routes, graph.RouteHop{})
967 return routes
968 }
969 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400970 log.Warnw("no-downstream-route", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "logicalPortsNo": agent.logicalPortsNo})
khenaidoo89b0e942018-10-21 21:11:33 -0400971 return nil
972 }
khenaidoo89b0e942018-10-21 21:11:33 -0400973 // Return the pre-calculated route
khenaidoo19d7b632018-10-30 10:49:50 -0400974 return agent.getPreCalculatedRoute(ingressPortNo, egressPortNo)
khenaidoo89b0e942018-10-21 21:11:33 -0400975}
976
khenaidoo89b0e942018-10-21 21:11:33 -0400977func (agent *LogicalDeviceAgent) rootDeviceDefaultRules() *fu.FlowsAndGroups {
978 return fu.NewFlowsAndGroups()
979}
980
981func (agent *LogicalDeviceAgent) leafDeviceDefaultRules(deviceId string) *fu.FlowsAndGroups {
982 fg := fu.NewFlowsAndGroups()
983 var device *voltha.Device
984 var err error
khenaidoo19d7b632018-10-30 10:49:50 -0400985 if device, err = agent.deviceMgr.GetDevice(deviceId); err != nil {
khenaidoo89b0e942018-10-21 21:11:33 -0400986 return fg
987 }
988 //set the upstream and downstream ports
989 upstreamPorts := make([]*voltha.Port, 0)
990 downstreamPorts := make([]*voltha.Port, 0)
991 for _, port := range device.Ports {
992 if port.Type == voltha.Port_PON_ONU || port.Type == voltha.Port_VENET_ONU {
993 upstreamPorts = append(upstreamPorts, port)
994 } else if port.Type == voltha.Port_ETHERNET_UNI {
995 downstreamPorts = append(downstreamPorts, port)
996 }
997 }
998 //it is possible that the downstream ports are not created, but the flow_decomposition has already
999 //kicked in. In such scenarios, cut short the processing and return.
khenaidoo910204f2019-04-08 17:56:40 -04001000 if len(downstreamPorts) == 0 || len(upstreamPorts) == 0 {
khenaidoo89b0e942018-10-21 21:11:33 -04001001 return fg
1002 }
1003 // set up the default flows
1004 var fa *fu.FlowArgs
1005 fa = &fu.FlowArgs{
1006 KV: fu.OfpFlowModArgs{"priority": 500},
1007 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -04001008 fu.InPort(downstreamPorts[0].PortNo),
1009 fu.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 0),
khenaidoo89b0e942018-10-21 21:11:33 -04001010 },
1011 Actions: []*ofp.OfpAction{
khenaidoo68c930b2019-05-13 11:46:51 -04001012 fu.SetField(fu.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | device.Vlan)),
1013 fu.Output(upstreamPorts[0].PortNo),
khenaidoo89b0e942018-10-21 21:11:33 -04001014 },
1015 }
khenaidoo68c930b2019-05-13 11:46:51 -04001016 fg.AddFlow(fu.MkFlowStat(fa))
khenaidoo89b0e942018-10-21 21:11:33 -04001017
1018 fa = &fu.FlowArgs{
1019 KV: fu.OfpFlowModArgs{"priority": 500},
1020 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -04001021 fu.InPort(downstreamPorts[0].PortNo),
1022 fu.VlanVid(0),
khenaidoo89b0e942018-10-21 21:11:33 -04001023 },
1024 Actions: []*ofp.OfpAction{
khenaidoo68c930b2019-05-13 11:46:51 -04001025 fu.PushVlan(0x8100),
1026 fu.SetField(fu.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | device.Vlan)),
1027 fu.Output(upstreamPorts[0].PortNo),
khenaidoo89b0e942018-10-21 21:11:33 -04001028 },
1029 }
khenaidoo68c930b2019-05-13 11:46:51 -04001030 fg.AddFlow(fu.MkFlowStat(fa))
khenaidoo89b0e942018-10-21 21:11:33 -04001031
1032 fa = &fu.FlowArgs{
1033 KV: fu.OfpFlowModArgs{"priority": 500},
1034 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -04001035 fu.InPort(upstreamPorts[0].PortNo),
1036 fu.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | device.Vlan),
khenaidoo89b0e942018-10-21 21:11:33 -04001037 },
1038 Actions: []*ofp.OfpAction{
khenaidoo68c930b2019-05-13 11:46:51 -04001039 fu.SetField(fu.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 0)),
1040 fu.Output(downstreamPorts[0].PortNo),
khenaidoo89b0e942018-10-21 21:11:33 -04001041 },
1042 }
khenaidoo68c930b2019-05-13 11:46:51 -04001043 fg.AddFlow(fu.MkFlowStat(fa))
khenaidoo89b0e942018-10-21 21:11:33 -04001044
1045 return fg
1046}
1047
1048func (agent *LogicalDeviceAgent) generateDefaultRules() *fu.DeviceRules {
1049 rules := fu.NewDeviceRules()
1050 var ld *voltha.LogicalDevice
1051 var err error
khenaidoo19d7b632018-10-30 10:49:50 -04001052 if ld, err = agent.GetLogicalDevice(); err != nil {
khenaidoo89b0e942018-10-21 21:11:33 -04001053 log.Warnw("no-logical-device", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
1054 return rules
1055 }
1056
1057 deviceNodeIds := agent.deviceGraph.GetDeviceNodeIds()
khenaidooca301322019-01-09 23:06:32 -05001058 for deviceId := range deviceNodeIds {
khenaidoo89b0e942018-10-21 21:11:33 -04001059 if deviceId == ld.RootDeviceId {
1060 rules.AddFlowsAndGroup(deviceId, agent.rootDeviceDefaultRules())
khenaidoo89b0e942018-10-21 21:11:33 -04001061 }
1062 }
1063 return rules
1064}
1065
1066func (agent *LogicalDeviceAgent) GetAllDefaultRules() *fu.DeviceRules {
khenaidoo89b0e942018-10-21 21:11:33 -04001067 return agent.DefaultFlowRules
1068}
1069
1070func (agent *LogicalDeviceAgent) GetWildcardInputPorts(excludePort ...uint32) []uint32 {
1071 lPorts := make([]uint32, 0)
1072 var exclPort uint32
1073 if len(excludePort) == 1 {
1074 exclPort = excludePort[0]
1075 }
khenaidoo19d7b632018-10-30 10:49:50 -04001076 if lDevice, _ := agent.GetLogicalDevice(); lDevice != nil {
khenaidoo89b0e942018-10-21 21:11:33 -04001077 for _, port := range lDevice.Ports {
1078 if port.OfpPort.PortNo != exclPort {
1079 lPorts = append(lPorts, port.OfpPort.PortNo)
1080 }
1081 }
1082 }
1083 return lPorts
1084}
khenaidoo19d7b632018-10-30 10:49:50 -04001085
1086func (agent *LogicalDeviceAgent) GetDeviceGraph() *graph.DeviceGraph {
1087 return agent.deviceGraph
1088}
1089
khenaidoo2c6a0992019-04-29 13:46:56 -04001090//updateRoutes redo the device graph if not done already and setup the default rules as well
1091func (agent *LogicalDeviceAgent) updateRoutes(device *voltha.Device, port *voltha.Port) error {
1092 log.Debugf("updateRoutes", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "device": device.Id, "port": port})
khenaidoo910204f2019-04-08 17:56:40 -04001093 agent.lockLogicalDevice.Lock()
1094 defer agent.lockLogicalDevice.Unlock()
khenaidoo2c6a0992019-04-29 13:46:56 -04001095 rules := fu.NewDeviceRules()
khenaidoo19d7b632018-10-30 10:49:50 -04001096 if agent.deviceGraph == nil {
khenaidoo910204f2019-04-08 17:56:40 -04001097 agent.deviceGraph = graph.NewDeviceGraph(agent.logicalDeviceId, agent.deviceMgr.GetDevice)
khenaidoo2c6a0992019-04-29 13:46:56 -04001098 }
1099 // Get all the logical ports on that logical device
1100 if lDevice, err := agent.getLogicalDeviceWithoutLock(); err != nil {
manikkaraj k259a6f72019-05-06 09:55:44 -04001101 log.Errorw("unknown-logical-device", log.Fields{"error": err, "logicalDeviceId": agent.logicalDeviceId})
khenaidoo2c6a0992019-04-29 13:46:56 -04001102 return err
1103 } else {
1104 //TODO: Find a better way to refresh only missing routes
1105 agent.deviceGraph.ComputeRoutes(lDevice.Ports)
1106 }
1107 deviceNodeIds := agent.deviceGraph.GetDeviceNodeIds()
1108 for deviceId := range deviceNodeIds {
1109 if deviceId == agent.rootDeviceId {
1110 rules.AddFlowsAndGroup(deviceId, agent.rootDeviceDefaultRules())
khenaidoo910204f2019-04-08 17:56:40 -04001111 }
khenaidoo19d7b632018-10-30 10:49:50 -04001112 }
khenaidoo2c6a0992019-04-29 13:46:56 -04001113 agent.DefaultFlowRules = rules
1114
1115 // Reset the default flows flag to ensure all default flows are sent to all devices, including the newly added
1116 // one when a flow request is received.
1117 agent.includeDefaultFlows = true
1118 agent.deviceGraph.Print()
1119 return nil
khenaidoo19d7b632018-10-30 10:49:50 -04001120}
1121
khenaidoo2c6a0992019-04-29 13:46:56 -04001122//updateDeviceGraph updates the device graph if not done already and setup the default rules as well
khenaidoo910204f2019-04-08 17:56:40 -04001123func (agent *LogicalDeviceAgent) updateDeviceGraph(lp *voltha.LogicalPort) {
khenaidoo2c6a0992019-04-29 13:46:56 -04001124 log.Debugf("updateDeviceGraph", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
1125 agent.lockLogicalDevice.Lock()
1126 defer agent.lockLogicalDevice.Unlock()
1127 rules := fu.NewDeviceRules()
khenaidoo910204f2019-04-08 17:56:40 -04001128 if agent.deviceGraph == nil {
1129 agent.deviceGraph = graph.NewDeviceGraph(agent.logicalDeviceId, agent.deviceMgr.GetDevice)
1130 }
1131 agent.deviceGraph.AddPort(lp)
khenaidoo2c6a0992019-04-29 13:46:56 -04001132 deviceNodeIds := agent.deviceGraph.GetDeviceNodeIds()
1133 for deviceId := range deviceNodeIds {
1134 if deviceId == agent.rootDeviceId {
1135 rules.AddFlowsAndGroup(deviceId, agent.rootDeviceDefaultRules())
khenaidooca301322019-01-09 23:06:32 -05001136 }
Stephane Barbarie1ab43272018-12-08 21:42:13 -05001137 }
khenaidoo2c6a0992019-04-29 13:46:56 -04001138 agent.DefaultFlowRules = rules
khenaidoo19d7b632018-10-30 10:49:50 -04001139
khenaidoo2c6a0992019-04-29 13:46:56 -04001140 // Reset the default flows flag to ensure all default flows are sent to all devices, including the newly added
1141 // one when a flow request is received.
1142 agent.includeDefaultFlows = true
1143 agent.deviceGraph.Print()
khenaidoo19d7b632018-10-30 10:49:50 -04001144}
khenaidoofdbad6e2018-11-06 22:26:38 -05001145
khenaidoo0a822f92019-05-08 15:15:57 -04001146//redoDeviceGraph regenerates the device graph upon port changes on a device graph
1147//TODO: it may yield better performance to have separate deleteLogicalPort functions that would remove
1148// all the routes/nodes related to the deleted logical port.
1149func (agent *LogicalDeviceAgent) redoDeviceGraph() {
1150 log.Debugf("redoDeviceGraph", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
1151 agent.lockLogicalDevice.Lock()
1152 defer agent.lockLogicalDevice.Unlock()
1153 // Get the latest logical device
1154 if ld, err := agent.getLogicalDeviceWithoutLock(); err != nil {
1155 log.Errorw("logical-device-not-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "error": err})
1156 } else {
1157 agent.deviceGraph.ComputeRoutes(ld.Ports)
1158 }
1159}
1160
khenaidoofc1314d2019-03-14 09:34:21 -04001161// portAdded is a callback invoked when a port is added to the logical device.
1162// TODO: To use when POST_ADD is fixed.
1163func (agent *LogicalDeviceAgent) portAdded(args ...interface{}) interface{} {
1164 log.Debugw("portAdded-callback", log.Fields{"argsLen": len(args)})
1165
1166 var port *voltha.LogicalPort
1167
1168 // Sanity check
1169 if args[0] != nil {
1170 log.Warnw("previous-data-not-nil", log.Fields{"args0": args[0]})
1171 }
1172 var ok bool
1173 if port, ok = args[1].(*voltha.LogicalPort); !ok {
1174 log.Errorw("invalid-args", log.Fields{"args1": args[1]})
1175 return nil
1176 }
1177
1178 // Set the proxy and callback for that port
1179 agent.portProxiesLock.Lock()
Stephane Barbarie40fd3b22019-04-23 21:50:47 -04001180 agent.portProxies[port.Id] = agent.clusterDataProxy.CreateProxy(
khenaidoofc1314d2019-03-14 09:34:21 -04001181 fmt.Sprintf("/logical_devices/%s/ports/%s", agent.logicalDeviceId, port.Id),
1182 false)
1183 agent.portProxies[port.Id].RegisterCallback(model.POST_UPDATE, agent.portUpdated)
1184 agent.portProxiesLock.Unlock()
1185
1186 // Send the port change event to the OF controller
1187 agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceId,
khenaidoo910204f2019-04-08 17:56:40 -04001188 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_ADD, Desc: port.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001189
1190 return nil
1191}
1192
1193// portRemoved is a callback invoked when a port is removed from the logical device.
1194// TODO: To use when POST_ADD is fixed.
1195func (agent *LogicalDeviceAgent) portRemoved(args ...interface{}) interface{} {
1196 log.Debugw("portRemoved-callback", log.Fields{"argsLen": len(args)})
1197
1198 var port *voltha.LogicalPort
1199
1200 // Sanity check
1201 if args[1] != nil {
1202 log.Warnw("data-not-nil", log.Fields{"args1": args[1]})
1203 }
1204 var ok bool
1205 if port, ok = args[0].(*voltha.LogicalPort); !ok {
1206 log.Errorw("invalid-args", log.Fields{"args0": args[0]})
1207 return nil
1208 }
1209
1210 // Remove the proxy and callback for that port
1211 agent.portProxiesLock.Lock()
1212 agent.portProxies[port.Id].UnregisterCallback(model.POST_UPDATE, agent.portUpdated)
1213 delete(agent.portProxies, port.Id)
1214 agent.portProxiesLock.Unlock()
1215
1216 // Send the port change event to the OF controller
1217 agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceId,
khenaidoo910204f2019-04-08 17:56:40 -04001218 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_DELETE, Desc: port.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001219
1220 return nil
1221}
1222
1223// 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 -04001224func diff(oldList, newList []*voltha.LogicalPort) (newPorts, changedPorts, deletedPorts []*voltha.LogicalPort) {
khenaidoofc1314d2019-03-14 09:34:21 -04001225 newPorts = make([]*voltha.LogicalPort, 0)
1226 changedPorts = make([]*voltha.LogicalPort, 0)
1227 deletedPorts = make([]*voltha.LogicalPort, 0)
1228 for _, o := range oldList {
1229 found := false
1230 changed := false
1231 for _, n := range newList {
1232 if o.Id == n.Id {
1233 changed = !reflect.DeepEqual(o, n)
1234 found = true
1235 break
1236 }
1237 }
1238 if !found {
1239 deletedPorts = append(deletedPorts, o)
1240 }
1241 if changed {
1242 changedPorts = append(changedPorts, o)
1243 }
1244 }
1245 for _, n := range newList {
1246 found := false
1247 for _, o := range oldList {
1248 if o.Id == n.Id {
1249 found = true
1250 break
1251 }
1252 }
1253 if !found {
1254 newPorts = append(newPorts, n)
1255 }
1256 }
1257 return
1258}
1259
1260// portUpdated is invoked when a port is updated on the logical device. Until
1261// the POST_ADD notification is fixed, we will use the logical device to
1262// update that data.
1263func (agent *LogicalDeviceAgent) portUpdated(args ...interface{}) interface{} {
1264 log.Debugw("portUpdated-callback", log.Fields{"argsLen": len(args)})
1265
1266 var oldLD *voltha.LogicalDevice
1267 var newlD *voltha.LogicalDevice
1268
1269 var ok bool
1270 if oldLD, ok = args[0].(*voltha.LogicalDevice); !ok {
1271 log.Errorw("invalid-args", log.Fields{"args0": args[0]})
1272 return nil
1273 }
1274 if newlD, ok = args[1].(*voltha.LogicalDevice); !ok {
1275 log.Errorw("invalid-args", log.Fields{"args1": args[1]})
1276 return nil
1277 }
1278
1279 if reflect.DeepEqual(oldLD.Ports, newlD.Ports) {
1280 log.Debug("ports-have-not-changed")
1281 return nil
1282 }
1283
1284 // Get the difference between the two list
1285 newPorts, changedPorts, deletedPorts := diff(oldLD.Ports, newlD.Ports)
1286
1287 // Send the port change events to the OF controller
khenaidoo2c6a0992019-04-29 13:46:56 -04001288 for _, newP := range newPorts {
khenaidoofc1314d2019-03-14 09:34:21 -04001289 go agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceId,
khenaidoo2c6a0992019-04-29 13:46:56 -04001290 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_ADD, Desc: newP.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001291 }
1292 for _, change := range changedPorts {
1293 go agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceId,
khenaidoo910204f2019-04-08 17:56:40 -04001294 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_MODIFY, Desc: change.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001295 }
1296 for _, del := range deletedPorts {
1297 go agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceId,
khenaidoo910204f2019-04-08 17:56:40 -04001298 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_DELETE, Desc: del.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001299 }
1300
1301 return nil
1302}
1303
khenaidoo8f474192019-04-03 17:20:44 -04001304// addNNILogicalPort adds an NNI port to the logical device. It returns a bool representing whether a port has been
1305// added and an eror in case a valid error is encountered. If the port was successfully added it will return
1306// (true, nil). If the device is not in the correct state it will return (false, nil) as this is a valid
1307// scenario. This also applies to the case where the port was already added.
khenaidoo910204f2019-04-08 17:56:40 -04001308func (agent *LogicalDeviceAgent) addNNILogicalPort(device *voltha.Device, port *voltha.Port) (bool, error) {
khenaidoo1ce37ad2019-03-24 22:07:24 -04001309 log.Debugw("addNNILogicalPort", log.Fields{"NNI": port})
khenaidoo8f474192019-04-03 17:20:44 -04001310 if device.AdminState != voltha.AdminState_ENABLED || device.OperStatus != voltha.OperStatus_ACTIVE {
1311 log.Infow("device-not-ready", log.Fields{"deviceId": device.Id, "admin": device.AdminState, "oper": device.OperStatus})
1312 return false, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001313 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001314 agent.lockLogicalDevice.RLock()
1315 if agent.portExist(device, port) {
1316 log.Debugw("port-already-exist", log.Fields{"port": port})
1317 agent.lockLogicalDevice.RUnlock()
khenaidoo8f474192019-04-03 17:20:44 -04001318 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001319 }
1320 agent.lockLogicalDevice.RUnlock()
1321
khenaidoofc1314d2019-03-14 09:34:21 -04001322 var portCap *ic.PortCapability
1323 var err error
1324 // First get the port capability
1325 if portCap, err = agent.deviceMgr.getPortCapability(nil, device.Id, port.PortNo); err != nil {
1326 log.Errorw("error-retrieving-port-capabilities", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001327 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001328 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001329
1330 agent.lockLogicalDevice.Lock()
1331 defer agent.lockLogicalDevice.Unlock()
1332 // Double check again if this port has been already added since the getPortCapability could have taken a long time
1333 if agent.portExist(device, port) {
1334 log.Debugw("port-already-exist", log.Fields{"port": port})
khenaidoo8f474192019-04-03 17:20:44 -04001335 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001336 }
1337
khenaidoofc1314d2019-03-14 09:34:21 -04001338 portCap.Port.RootPort = true
1339 lp := (proto.Clone(portCap.Port)).(*voltha.LogicalPort)
1340 lp.DeviceId = device.Id
1341 lp.Id = fmt.Sprintf("nni-%d", port.PortNo)
1342 lp.OfpPort.PortNo = port.PortNo
1343 lp.OfpPort.Name = lp.Id
1344 lp.DevicePortNo = port.PortNo
1345
khenaidoofc1314d2019-03-14 09:34:21 -04001346 var ld *voltha.LogicalDevice
1347 if ld, err = agent.getLogicalDeviceWithoutLock(); err != nil {
1348 log.Errorw("error-retrieving-logical-device", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001349 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001350 }
1351 cloned := (proto.Clone(ld)).(*voltha.LogicalDevice)
1352 if cloned.Ports == nil {
1353 cloned.Ports = make([]*voltha.LogicalPort, 0)
1354 }
1355 cloned.Ports = append(cloned.Ports, lp)
1356
1357 if err = agent.updateLogicalDeviceWithoutLock(cloned); err != nil {
1358 log.Errorw("error-updating-logical-device", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001359 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001360 }
khenaidoo910204f2019-04-08 17:56:40 -04001361
1362 // Update the device graph with this new logical port
1363 clonedLP := (proto.Clone(lp)).(*voltha.LogicalPort)
1364 go agent.updateDeviceGraph(clonedLP)
1365
khenaidoo8f474192019-04-03 17:20:44 -04001366 return true, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001367}
1368
khenaidoo910204f2019-04-08 17:56:40 -04001369func (agent *LogicalDeviceAgent) portExist(device *voltha.Device, port *voltha.Port) bool {
khenaidoo54544ae2019-03-18 13:22:39 -04001370 if ldevice, _ := agent.getLogicalDeviceWithoutLock(); ldevice != nil {
khenaidoofc1314d2019-03-14 09:34:21 -04001371 for _, lPort := range ldevice.Ports {
khenaidoo54544ae2019-03-18 13:22:39 -04001372 if lPort.DeviceId == device.Id && lPort.DevicePortNo == port.PortNo && lPort.Id == port.Label {
khenaidoofc1314d2019-03-14 09:34:21 -04001373 return true
1374 }
1375 }
1376 }
1377 return false
1378}
1379
khenaidoo8f474192019-04-03 17:20:44 -04001380// addUNILogicalPort adds an UNI port to the logical device. It returns a bool representing whether a port has been
1381// added and an eror in case a valid error is encountered. If the port was successfully added it will return
1382// (true, nil). If the device is not in the correct state it will return (false, nil) as this is a valid
1383// scenario. This also applies to the case where the port was already added.
khenaidoo910204f2019-04-08 17:56:40 -04001384func (agent *LogicalDeviceAgent) addUNILogicalPort(childDevice *voltha.Device, port *voltha.Port) (bool, error) {
khenaidoofc1314d2019-03-14 09:34:21 -04001385 log.Debugw("addUNILogicalPort", log.Fields{"port": port})
khenaidoo8f474192019-04-03 17:20:44 -04001386 if childDevice.AdminState != voltha.AdminState_ENABLED || childDevice.OperStatus != voltha.OperStatus_ACTIVE {
1387 log.Infow("device-not-ready", log.Fields{"deviceId": childDevice.Id, "admin": childDevice.AdminState, "oper": childDevice.OperStatus})
1388 return false, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001389 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001390 agent.lockLogicalDevice.RLock()
1391 if agent.portExist(childDevice, port) {
1392 log.Debugw("port-already-exist", log.Fields{"port": port})
1393 agent.lockLogicalDevice.RUnlock()
khenaidoo8f474192019-04-03 17:20:44 -04001394 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001395 }
1396 agent.lockLogicalDevice.RUnlock()
khenaidoofc1314d2019-03-14 09:34:21 -04001397 var portCap *ic.PortCapability
1398 var err error
1399 // First get the port capability
1400 if portCap, err = agent.deviceMgr.getPortCapability(nil, childDevice.Id, port.PortNo); err != nil {
1401 log.Errorw("error-retrieving-port-capabilities", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001402 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001403 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001404 agent.lockLogicalDevice.Lock()
1405 defer agent.lockLogicalDevice.Unlock()
1406 // Double check again if this port has been already added since the getPortCapability could have taken a long time
1407 if agent.portExist(childDevice, port) {
1408 log.Debugw("port-already-exist", log.Fields{"port": port})
khenaidoo8f474192019-04-03 17:20:44 -04001409 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001410 }
khenaidoofc1314d2019-03-14 09:34:21 -04001411 // Get stored logical device
1412 if ldevice, err := agent.getLogicalDeviceWithoutLock(); err != nil {
khenaidoo8f474192019-04-03 17:20:44 -04001413 return false, status.Error(codes.NotFound, agent.logicalDeviceId)
khenaidoofc1314d2019-03-14 09:34:21 -04001414 } else {
1415 log.Debugw("adding-uni", log.Fields{"deviceId": childDevice.Id})
1416 portCap.Port.RootPort = false
Matt Jeanneret3815e322019-03-12 19:15:49 -04001417 portCap.Port.Id = port.Label
1418 portCap.Port.OfpPort.PortNo = port.PortNo
khenaidoofc1314d2019-03-14 09:34:21 -04001419 portCap.Port.DeviceId = childDevice.Id
1420 portCap.Port.DevicePortNo = port.PortNo
1421 cloned := (proto.Clone(ldevice)).(*voltha.LogicalDevice)
1422 if cloned.Ports == nil {
1423 cloned.Ports = make([]*voltha.LogicalPort, 0)
1424 }
1425 cloned.Ports = append(cloned.Ports, portCap.Port)
khenaidoo910204f2019-04-08 17:56:40 -04001426 if err := agent.updateLogicalDeviceWithoutLock(cloned); err != nil {
1427 return false, err
1428 }
khenaidoo910204f2019-04-08 17:56:40 -04001429 // Update the device graph with this new logical port
1430 clonedLP := (proto.Clone(portCap.Port)).(*voltha.LogicalPort)
1431 go agent.updateDeviceGraph(clonedLP)
1432 return true, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001433 }
1434}
1435
khenaidoo43c82122018-11-22 18:38:28 -05001436func (agent *LogicalDeviceAgent) packetOut(packet *ofp.OfpPacketOut) {
khenaidoofdbad6e2018-11-06 22:26:38 -05001437 log.Debugw("packet-out", log.Fields{"packet": packet.GetInPort()})
khenaidoo68c930b2019-05-13 11:46:51 -04001438 outPort := fu.GetPacketOutPort(packet)
khenaidoofdbad6e2018-11-06 22:26:38 -05001439 //frame := packet.GetData()
1440 //TODO: Use a channel between the logical agent and the device agent
khenaidooca301322019-01-09 23:06:32 -05001441 if err := agent.deviceMgr.packetOut(agent.rootDeviceId, outPort, packet); err != nil {
khenaidoo910204f2019-04-08 17:56:40 -04001442 log.Error("packetout-failed", log.Fields{"logicalDeviceID": agent.rootDeviceId})
khenaidooca301322019-01-09 23:06:32 -05001443 }
khenaidoofdbad6e2018-11-06 22:26:38 -05001444}
1445
khenaidoo297cd252019-02-07 22:10:23 -05001446func (agent *LogicalDeviceAgent) packetIn(port uint32, transactionId string, packet []byte) {
1447 log.Debugw("packet-in", log.Fields{"port": port, "packet": packet, "transactionId": transactionId})
khenaidoo68c930b2019-05-13 11:46:51 -04001448 packetIn := fu.MkPacketIn(port, packet)
khenaidoo297cd252019-02-07 22:10:23 -05001449 agent.ldeviceMgr.grpcNbiHdlr.sendPacketIn(agent.logicalDeviceId, transactionId, packetIn)
khenaidooca301322019-01-09 23:06:32 -05001450 log.Debugw("sending-packet-in", log.Fields{"packet-in": packetIn})
khenaidoofdbad6e2018-11-06 22:26:38 -05001451}
khenaidoo2c6a0992019-04-29 13:46:56 -04001452
1453func (agent *LogicalDeviceAgent) addLogicalPortToMap(portNo uint32, nniPort bool) {
1454 agent.lockLogicalPortsNo.Lock()
1455 defer agent.lockLogicalPortsNo.Unlock()
1456 if exist := agent.logicalPortsNo[portNo]; !exist {
1457 agent.logicalPortsNo[portNo] = nniPort
1458 }
1459}
1460
1461func (agent *LogicalDeviceAgent) deleteLogicalPortFromMap(portNo uint32) {
1462 agent.lockLogicalPortsNo.Lock()
1463 defer agent.lockLogicalPortsNo.Unlock()
1464 if exist := agent.logicalPortsNo[portNo]; exist {
1465 delete(agent.logicalPortsNo, portNo)
1466 }
1467}
1468
1469func (agent *LogicalDeviceAgent) isNNIPort(portNo uint32) bool {
1470 agent.lockLogicalPortsNo.RLock()
1471 defer agent.lockLogicalPortsNo.RUnlock()
1472 if exist := agent.logicalPortsNo[portNo]; exist {
1473 return agent.logicalPortsNo[portNo]
1474 }
1475 return false
1476}
1477
1478func (agent *LogicalDeviceAgent) getFirstNNIPort() (uint32, error) {
1479 agent.lockLogicalPortsNo.RLock()
1480 defer agent.lockLogicalPortsNo.RUnlock()
1481 for portNo, nni := range agent.logicalPortsNo {
1482 if nni {
1483 return portNo, nil
1484 }
1485 }
1486 return 0, status.Error(codes.NotFound, "No NNI port found")
1487}