blob: a2b449408886603db2cf7b3d648a3430a814e4f4 [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
khenaidoofc1314d2019-03-14 09:34:21 -0400316// setupUNILogicalPorts creates a UNI port on the logical device that represents a child UNI interface
317func (agent *LogicalDeviceAgent) setupUNILogicalPorts(ctx context.Context, childDevice *voltha.Device) error {
318 log.Infow("setupUNILogicalPort-start", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
319 // Build the logical device based on information retrieved from the device adapter
khenaidoob9203542018-09-17 22:56:37 -0400320 var err error
khenaidoo19d7b632018-10-30 10:49:50 -0400321
322 //Get UNI port number
khenaidoo19d7b632018-10-30 10:49:50 -0400323 for _, port := range childDevice.Ports {
324 if port.Type == voltha.Port_ETHERNET_UNI {
khenaidoo910204f2019-04-08 17:56:40 -0400325 if _, err = agent.addUNILogicalPort(childDevice, port); err != nil {
khenaidoofc1314d2019-03-14 09:34:21 -0400326 log.Errorw("error-adding-UNI-port", log.Fields{"error": err})
khenaidoofc1314d2019-03-14 09:34:21 -0400327 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400328 agent.addLogicalPortToMap(port.PortNo, false)
khenaidoo19d7b632018-10-30 10:49:50 -0400329 }
330 }
khenaidoofc1314d2019-03-14 09:34:21 -0400331 return err
khenaidoo92e62c52018-10-03 14:02:54 -0400332}
333
334//updateLogicalDeviceWithoutLock updates the model with the logical device. It clones the logicaldevice before saving it
335func (agent *LogicalDeviceAgent) updateLogicalDeviceWithoutLock(logicalDevice *voltha.LogicalDevice) error {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500336 afterUpdate := agent.clusterDataProxy.Update("/logical_devices/"+agent.logicalDeviceId, logicalDevice, false, "")
khenaidoo92e62c52018-10-03 14:02:54 -0400337 if afterUpdate == nil {
338 return status.Errorf(codes.Internal, "failed-updating-logical-device:%s", agent.logicalDeviceId)
339 }
340 return nil
341}
342
khenaidoo19d7b632018-10-30 10:49:50 -0400343//updateFlowTable updates the flow table of that logical device
344func (agent *LogicalDeviceAgent) updateFlowTable(ctx context.Context, flow *ofp.OfpFlowMod) error {
345 log.Debug("updateFlowTable")
346 if flow == nil {
347 return nil
348 }
349 switch flow.GetCommand() {
350 case ofp.OfpFlowModCommand_OFPFC_ADD:
351 return agent.flowAdd(flow)
352 case ofp.OfpFlowModCommand_OFPFC_DELETE:
353 return agent.flowDelete(flow)
354 case ofp.OfpFlowModCommand_OFPFC_DELETE_STRICT:
355 return agent.flowDeleteStrict(flow)
356 case ofp.OfpFlowModCommand_OFPFC_MODIFY:
357 return agent.flowModify(flow)
358 case ofp.OfpFlowModCommand_OFPFC_MODIFY_STRICT:
359 return agent.flowModifyStrict(flow)
360 }
361 return status.Errorf(codes.Internal,
362 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceId, flow.GetCommand())
363}
364
365//updateGroupTable updates the group table of that logical device
366func (agent *LogicalDeviceAgent) updateGroupTable(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
367 log.Debug("updateGroupTable")
368 if groupMod == nil {
369 return nil
370 }
371 switch groupMod.GetCommand() {
372 case ofp.OfpGroupModCommand_OFPGC_ADD:
373 return agent.groupAdd(groupMod)
374 case ofp.OfpGroupModCommand_OFPGC_DELETE:
375 return agent.groupDelete(groupMod)
376 case ofp.OfpGroupModCommand_OFPGC_MODIFY:
377 return agent.groupModify(groupMod)
378 }
379 return status.Errorf(codes.Internal,
380 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceId, groupMod.GetCommand())
381}
382
khenaidoo19d7b632018-10-30 10:49:50 -0400383//flowAdd adds a flow to the flow table of that logical device
384func (agent *LogicalDeviceAgent) flowAdd(mod *ofp.OfpFlowMod) error {
385 log.Debug("flowAdd")
386 if mod == nil {
387 return nil
388 }
khenaidoo92e62c52018-10-03 14:02:54 -0400389 agent.lockLogicalDevice.Lock()
390 defer agent.lockLogicalDevice.Unlock()
khenaidoo19d7b632018-10-30 10:49:50 -0400391
392 var lDevice *voltha.LogicalDevice
393 var err error
394 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
395 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
396 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
397 }
398
399 var flows []*ofp.OfpFlowStats
400 if lDevice.Flows != nil && lDevice.Flows.Items != nil {
401 flows = lDevice.Flows.Items
402 }
403
khenaidoo2c6a0992019-04-29 13:46:56 -0400404 updatedFlows := make([]*ofp.OfpFlowStats, 0)
khenaidoo43c82122018-11-22 18:38:28 -0500405 //oldData := proto.Clone(lDevice.Flows).(*voltha.Flows)
khenaidoo19d7b632018-10-30 10:49:50 -0400406 changed := false
407 checkOverlap := (mod.Flags & uint32(ofp.OfpFlowModFlags_OFPFF_CHECK_OVERLAP)) != 0
408 if checkOverlap {
409 if overlapped := fu.FindOverlappingFlows(flows, mod); len(overlapped) != 0 {
410 // TODO: should this error be notified other than being logged?
411 log.Warnw("overlapped-flows", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
412 } else {
413 // Add flow
414 flow := fd.FlowStatsEntryFromFlowModMessage(mod)
415 flows = append(flows, flow)
khenaidoo2c6a0992019-04-29 13:46:56 -0400416 updatedFlows = append(updatedFlows, flow)
khenaidoo19d7b632018-10-30 10:49:50 -0400417 changed = true
418 }
419 } else {
420 flow := fd.FlowStatsEntryFromFlowModMessage(mod)
421 idx := fu.FindFlows(flows, flow)
422 if idx >= 0 {
423 oldFlow := flows[idx]
424 if (mod.Flags & uint32(ofp.OfpFlowModFlags_OFPFF_RESET_COUNTS)) != 0 {
425 flow.ByteCount = oldFlow.ByteCount
426 flow.PacketCount = oldFlow.PacketCount
427 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400428 if !reflect.DeepEqual(oldFlow, flow) {
429 flows[idx] = flow
430 updatedFlows = append(updatedFlows, flow)
431 changed = true
432 }
khenaidoo19d7b632018-10-30 10:49:50 -0400433 } else {
434 flows = append(flows, flow)
khenaidoo2c6a0992019-04-29 13:46:56 -0400435 updatedFlows = append(updatedFlows, flow)
436 changed = true
khenaidoo19d7b632018-10-30 10:49:50 -0400437 }
khenaidoo19d7b632018-10-30 10:49:50 -0400438 }
439 if changed {
khenaidoo2c6a0992019-04-29 13:46:56 -0400440 // Launch a routine to decompose the flows
441 if err := agent.decomposeAndSendFlows(&ofp.Flows{Items: updatedFlows}, lDevice.FlowGroups, agent.includeDefaultFlows); err != nil {
442 log.Errorf("decomposing-and-sending-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
443 return err
444 }
445
446 // We no longer need to sent the default flows, unless there is a change in device topology
447 agent.includeDefaultFlows = false
448
khenaidoo19d7b632018-10-30 10:49:50 -0400449 // Update model
khenaidoo43c82122018-11-22 18:38:28 -0500450 flowsToUpdate := &ofp.Flows{}
451 if lDevice.Flows != nil {
452 flowsToUpdate = &ofp.Flows{Items: flows}
khenaidoo19d7b632018-10-30 10:49:50 -0400453 }
khenaidoo43c82122018-11-22 18:38:28 -0500454 if err := agent.updateLogicalDeviceFlowsWithoutLock(flowsToUpdate); err != nil {
khenaidoo2c6a0992019-04-29 13:46:56 -0400455 log.Errorw("db-flow-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400456 return err
457 }
458 }
khenaidoo19d7b632018-10-30 10:49:50 -0400459 return nil
460}
461
khenaidoo2c6a0992019-04-29 13:46:56 -0400462func (agent *LogicalDeviceAgent) decomposeAndSendFlows(flows *ofp.Flows, groups *ofp.FlowGroups, includeDefaultFlows bool) error {
463 log.Debugw("decomposeAndSendFlows", log.Fields{"logicalDeviceID": agent.logicalDeviceId})
464
465 deviceRules := agent.flowDecomposer.DecomposeRules(agent, *flows, *groups, includeDefaultFlows)
466 log.Debugw("rules", log.Fields{"rules": deviceRules.String()})
467
468 chnlsList := make([]chan interface{}, 0)
469 for deviceId, value := range deviceRules.GetRules() {
470 ch := make(chan interface{})
471 chnlsList = append(chnlsList, ch)
472 go func(deviceId string, flows []*ofp.OfpFlowStats, groups []*ofp.OfpGroupEntry) {
473 if err := agent.deviceMgr.addFlowsAndGroups(deviceId, flows, groups); err != nil {
474 log.Error("flow-update-failed", log.Fields{"deviceID": deviceId})
475 ch <- status.Errorf(codes.Internal, "flow-update-failed: %s", deviceId)
476 }
477 ch <- nil
478 }(deviceId, value.ListFlows(), value.ListGroups())
479 }
480 // Wait for completion
481 if res := fu.WaitForNilOrErrorResponses(agent.defaultTimeout, chnlsList...); res != nil {
482 return status.Errorf(codes.Aborted, "errors-%s", res)
483 }
484 return nil
485}
486
khenaidoo19d7b632018-10-30 10:49:50 -0400487//flowDelete deletes a flow from the flow table of that logical device
488func (agent *LogicalDeviceAgent) flowDelete(mod *ofp.OfpFlowMod) error {
489 log.Debug("flowDelete")
490 if mod == nil {
491 return nil
492 }
493 agent.lockLogicalDevice.Lock()
494 defer agent.lockLogicalDevice.Unlock()
495
496 var lDevice *voltha.LogicalDevice
497 var err error
498 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
499 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
500 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
501 }
502 flows := lDevice.Flows.Items
503
504 //build a list of what to keep vs what to delete
505 toKeep := make([]*ofp.OfpFlowStats, 0)
506 for _, f := range flows {
507 if !fu.FlowMatchesMod(f, mod) {
508 toKeep = append(toKeep, f)
509 }
510 }
511
512 //Update flows
513 if len(toKeep) < len(flows) {
khenaidoo43c82122018-11-22 18:38:28 -0500514 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: toKeep}); err != nil {
515 log.Errorw("Cannot-update-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400516 return err
517 }
518 }
519
520 //TODO: send announcement on delete
521 return nil
522}
523
524//flowStatsDelete deletes a flow from the flow table of that logical device
525func (agent *LogicalDeviceAgent) flowStatsDelete(flow *ofp.OfpFlowStats) error {
526 log.Debug("flowStatsDelete")
527 if flow == nil {
528 return nil
529 }
530 agent.lockLogicalDevice.Lock()
531 defer agent.lockLogicalDevice.Unlock()
532
533 var lDevice *voltha.LogicalDevice
534 var err error
535 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
536 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
537 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
538 }
539 flows := lDevice.Flows.Items
540
541 //build a list of what to keep vs what to delete
542 toKeep := make([]*ofp.OfpFlowStats, 0)
543 for _, f := range flows {
544 if !fu.FlowMatch(f, flow) {
545 toKeep = append(toKeep, f)
546 }
547 }
548
549 //Update flows
550 if len(toKeep) < len(flows) {
khenaidoo43c82122018-11-22 18:38:28 -0500551 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: toKeep}); err != nil {
khenaidoo19d7b632018-10-30 10:49:50 -0400552 log.Errorw("Cannot-update-logical-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
553 return err
554 }
555 }
556 return nil
557}
558
559//flowDeleteStrict deletes a flow from the flow table of that logical device
560func (agent *LogicalDeviceAgent) flowDeleteStrict(mod *ofp.OfpFlowMod) error {
561 log.Debug("flowDeleteStrict")
562 if mod == nil {
563 return nil
564 }
565 agent.lockLogicalDevice.Lock()
566 defer agent.lockLogicalDevice.Unlock()
567
568 var lDevice *voltha.LogicalDevice
569 var err error
570 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
571 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
572 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
573 }
574 flows := lDevice.Flows.Items
575 changed := false
576 flow := fd.FlowStatsEntryFromFlowModMessage(mod)
577 idx := fu.FindFlows(flows, flow)
578 if idx >= 0 {
579 flows = append(flows[:idx], flows[idx+1:]...)
580 changed = true
581 } else {
582 return errors.New(fmt.Sprintf("Cannot delete flow - %s", flow))
583 }
584
585 if changed {
khenaidoo43c82122018-11-22 18:38:28 -0500586 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: flows}); err != nil {
khenaidoo19d7b632018-10-30 10:49:50 -0400587 log.Errorw("Cannot-update-logical-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
588 return err
589 }
590 }
591
592 return nil
593}
594
595//flowModify modifies a flow from the flow table of that logical device
596func (agent *LogicalDeviceAgent) flowModify(mod *ofp.OfpFlowMod) error {
597 return errors.New("flowModify not implemented")
598}
599
600//flowModifyStrict deletes a flow from the flow table of that logical device
601func (agent *LogicalDeviceAgent) flowModifyStrict(mod *ofp.OfpFlowMod) error {
602 return errors.New("flowModifyStrict not implemented")
603}
604
605func (agent *LogicalDeviceAgent) groupAdd(groupMod *ofp.OfpGroupMod) error {
606 log.Debug("groupAdd")
607 if groupMod == nil {
608 return nil
609 }
610 agent.lockLogicalDevice.Lock()
611 defer agent.lockLogicalDevice.Unlock()
612
613 var lDevice *voltha.LogicalDevice
614 var err error
615 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
616 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
617 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
618 }
619 groups := lDevice.FlowGroups.Items
khenaidoo19d7b632018-10-30 10:49:50 -0400620 if fu.FindGroup(groups, groupMod.GroupId) == -1 {
621 groups = append(groups, fd.GroupEntryFromGroupMod(groupMod))
khenaidoo43c82122018-11-22 18:38:28 -0500622 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(&ofp.FlowGroups{Items: groups}); err != nil {
623 log.Errorw("Cannot-update-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400624 return err
625 }
626 } else {
627 return errors.New(fmt.Sprintf("Groups %d already present", groupMod.GroupId))
628 }
khenaidoo19d7b632018-10-30 10:49:50 -0400629 return nil
630}
631
632func (agent *LogicalDeviceAgent) groupDelete(groupMod *ofp.OfpGroupMod) error {
633 log.Debug("groupDelete")
634 if groupMod == nil {
635 return nil
636 }
637 agent.lockLogicalDevice.Lock()
638 defer agent.lockLogicalDevice.Unlock()
639
640 var lDevice *voltha.LogicalDevice
641 var err error
642 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
643 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
644 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
645 }
646 groups := lDevice.FlowGroups.Items
647 flows := lDevice.Flows.Items
648 groupsChanged := false
649 flowsChanged := false
650 groupId := groupMod.GroupId
651 if groupId == uint32(ofp.OfpGroup_OFPG_ALL) {
652 //TODO we must delete all flows that point to this group and
653 //signal controller as requested by flow's flag
654 groups = []*ofp.OfpGroupEntry{}
655 groupsChanged = true
656 } else {
657 if idx := fu.FindGroup(groups, groupId); idx == -1 {
658 return nil // Valid case
659 } else {
660 flowsChanged, flows = fu.FlowsDeleteByGroupId(flows, groupId)
661 groups = append(groups[:idx], groups[idx+1:]...)
662 groupsChanged = true
663 }
664 }
khenaidoo43c82122018-11-22 18:38:28 -0500665 if groupsChanged {
666 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(&ofp.FlowGroups{Items: groups}); err != nil {
667 log.Errorw("Cannot-update-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400668 return err
669 }
670 }
khenaidoo43c82122018-11-22 18:38:28 -0500671 if flowsChanged {
672 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: flows}); err != nil {
673 log.Errorw("Cannot-update-flow", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
674 return err
675 }
676 }
677
khenaidoo19d7b632018-10-30 10:49:50 -0400678 return nil
679}
680
681func (agent *LogicalDeviceAgent) groupModify(groupMod *ofp.OfpGroupMod) error {
682 log.Debug("groupModify")
683 if groupMod == nil {
684 return nil
685 }
686 agent.lockLogicalDevice.Lock()
687 defer agent.lockLogicalDevice.Unlock()
688
689 var lDevice *voltha.LogicalDevice
690 var err error
691 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
692 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
693 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
694 }
695 groups := lDevice.FlowGroups.Items
696 groupsChanged := false
697 groupId := groupMod.GroupId
698 if idx := fu.FindGroup(groups, groupId); idx == -1 {
khenaidooca301322019-01-09 23:06:32 -0500699 return errors.New(fmt.Sprintf("group-absent:%d", groupId))
khenaidoo19d7b632018-10-30 10:49:50 -0400700 } else {
701 //replace existing group entry with new group definition
702 groupEntry := fd.GroupEntryFromGroupMod(groupMod)
703 groups[idx] = groupEntry
704 groupsChanged = true
705 }
706 if groupsChanged {
khenaidoo43c82122018-11-22 18:38:28 -0500707 //lDevice.FlowGroups.Items = groups
708 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(&ofp.FlowGroups{Items: groups}); err != nil {
khenaidoo19d7b632018-10-30 10:49:50 -0400709 log.Errorw("Cannot-update-logical-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
710 return err
711 }
712 }
713 return nil
714}
715
716// deleteLogicalPort removes the logical port
717func (agent *LogicalDeviceAgent) deleteLogicalPort(lPort *voltha.LogicalPort) error {
718 agent.lockLogicalDevice.Lock()
719 defer agent.lockLogicalDevice.Unlock()
720
khenaidoo92e62c52018-10-03 14:02:54 -0400721 // Get the most up to date logical device
722 var logicaldevice *voltha.LogicalDevice
723 if logicaldevice, _ = agent.getLogicalDeviceWithoutLock(); logicaldevice == nil {
khenaidoo19d7b632018-10-30 10:49:50 -0400724 log.Debugw("no-logical-device", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "logicalPortId": lPort.Id})
khenaidoob9203542018-09-17 22:56:37 -0400725 return nil
726 }
khenaidoo92e62c52018-10-03 14:02:54 -0400727 index := -1
728 for i, logicalPort := range logicaldevice.Ports {
khenaidoo19d7b632018-10-30 10:49:50 -0400729 if logicalPort.Id == lPort.Id {
khenaidoo92e62c52018-10-03 14:02:54 -0400730 index = i
731 break
732 }
733 }
734 if index >= 0 {
735 copy(logicaldevice.Ports[index:], logicaldevice.Ports[index+1:])
736 logicaldevice.Ports[len(logicaldevice.Ports)-1] = nil
737 logicaldevice.Ports = logicaldevice.Ports[:len(logicaldevice.Ports)-1]
738 log.Debugw("logical-port-deleted", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
739 return agent.updateLogicalDeviceWithoutLock(logicaldevice)
740 }
741 return nil
khenaidoob9203542018-09-17 22:56:37 -0400742}
743
khenaidoo19d7b632018-10-30 10:49:50 -0400744// enableLogicalPort enables the logical port
745func (agent *LogicalDeviceAgent) enableLogicalPort(lPort *voltha.LogicalPort) error {
746 agent.lockLogicalDevice.Lock()
747 defer agent.lockLogicalDevice.Unlock()
748
749 // Get the most up to date logical device
750 var logicaldevice *voltha.LogicalDevice
751 if logicaldevice, _ = agent.getLogicalDeviceWithoutLock(); logicaldevice == nil {
752 log.Debugw("no-logical-device", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "logicalPortId": lPort.Id})
753 return nil
754 }
755 index := -1
756 for i, logicalPort := range logicaldevice.Ports {
757 if logicalPort.Id == lPort.Id {
758 index = i
759 break
760 }
761 }
762 if index >= 0 {
763 logicaldevice.Ports[index].OfpPort.Config = logicaldevice.Ports[index].OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
764 return agent.updateLogicalDeviceWithoutLock(logicaldevice)
765 }
766 //TODO: Trigger subsequent actions on the device
767 return nil
768}
769
770// disableLogicalPort disabled the logical port
771func (agent *LogicalDeviceAgent) disableLogicalPort(lPort *voltha.LogicalPort) error {
772 agent.lockLogicalDevice.Lock()
773 defer agent.lockLogicalDevice.Unlock()
774
775 // Get the most up to date logical device
776 var logicaldevice *voltha.LogicalDevice
777 if logicaldevice, _ = agent.getLogicalDeviceWithoutLock(); logicaldevice == nil {
778 log.Debugw("no-logical-device", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "logicalPortId": lPort.Id})
779 return nil
780 }
781 index := -1
782 for i, logicalPort := range logicaldevice.Ports {
783 if logicalPort.Id == lPort.Id {
784 index = i
785 break
786 }
787 }
788 if index >= 0 {
789 logicaldevice.Ports[index].OfpPort.Config = (logicaldevice.Ports[index].OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)) | uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
790 return agent.updateLogicalDeviceWithoutLock(logicaldevice)
791 }
792 //TODO: Trigger subsequent actions on the device
793 return nil
794}
795
khenaidoo89b0e942018-10-21 21:11:33 -0400796func (agent *LogicalDeviceAgent) getPreCalculatedRoute(ingress, egress uint32) []graph.RouteHop {
khenaidoo19d7b632018-10-30 10:49:50 -0400797 log.Debugw("ROUTE", log.Fields{"len": len(agent.deviceGraph.Routes)})
khenaidoo89b0e942018-10-21 21:11:33 -0400798 for routeLink, route := range agent.deviceGraph.Routes {
khenaidoo19d7b632018-10-30 10:49:50 -0400799 log.Debugw("ROUTELINKS", log.Fields{"ingress": ingress, "egress": egress, "routelink": routeLink})
khenaidoo89b0e942018-10-21 21:11:33 -0400800 if ingress == routeLink.Ingress && egress == routeLink.Egress {
801 return route
802 }
803 }
804 log.Warnw("no-route", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "ingress": ingress, "egress": egress})
805 return nil
806}
807
khenaidoo19d7b632018-10-30 10:49:50 -0400808func (agent *LogicalDeviceAgent) GetRoute(ingressPortNo uint32, egressPortNo uint32) []graph.RouteHop {
khenaidoo89b0e942018-10-21 21:11:33 -0400809 log.Debugw("getting-route", log.Fields{"ingress-port": ingressPortNo, "egress-port": egressPortNo})
khenaidoo89b0e942018-10-21 21:11:33 -0400810 routes := make([]graph.RouteHop, 0)
khenaidoo2c6a0992019-04-29 13:46:56 -0400811
khenaidoo19d7b632018-10-30 10:49:50 -0400812 // Note: A port value of 0 is equivalent to a nil port
813
khenaidoo89b0e942018-10-21 21:11:33 -0400814 // Consider different possibilities
khenaidoo19d7b632018-10-30 10:49:50 -0400815 if egressPortNo != 0 && ((egressPortNo & 0x7fffffff) == uint32(ofp.OfpPortNo_OFPP_CONTROLLER)) {
khenaidoo2c6a0992019-04-29 13:46:56 -0400816 log.Debugw("controller-flow", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "logicalPortsNo": agent.logicalPortsNo})
817 if agent.isNNIPort(ingressPortNo) {
khenaidoo89b0e942018-10-21 21:11:33 -0400818 log.Debug("returning-half-route")
819 //This is a trap on the NNI Port
khenaidoo8f474192019-04-03 17:20:44 -0400820 if len(agent.deviceGraph.Routes) == 0 {
821 // If there are no routes set (usually when the logical device has only NNI port(s), then just return an
822 // internal route
khenaidoo2c6a0992019-04-29 13:46:56 -0400823 hop := graph.RouteHop{DeviceID: agent.rootDeviceId, Ingress: ingressPortNo, Egress: egressPortNo}
khenaidoo8f474192019-04-03 17:20:44 -0400824 routes = append(routes, hop)
825 routes = append(routes, hop)
826 return routes
827 }
khenaidoo89b0e942018-10-21 21:11:33 -0400828 //Return a 'half' route to make the flow decomposer logic happy
829 for routeLink, route := range agent.deviceGraph.Routes {
khenaidoo2c6a0992019-04-29 13:46:56 -0400830 if agent.isNNIPort(routeLink.Egress) {
khenaidoo89b0e942018-10-21 21:11:33 -0400831 routes = append(routes, graph.RouteHop{}) // first hop is set to empty
832 routes = append(routes, route[1])
833 return routes
834 }
835 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400836 log.Warnw("no-upstream-route", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "logicalPortsNo": agent.logicalPortsNo})
khenaidoo89b0e942018-10-21 21:11:33 -0400837 return nil
838 }
839 //treat it as if the output port is the first NNI of the OLT
khenaidoo2c6a0992019-04-29 13:46:56 -0400840 var err error
841 if egressPortNo, err = agent.getFirstNNIPort(); err != nil {
842 log.Warnw("no-nni-port", log.Fields{"error": err})
843 return nil
844 }
khenaidoo89b0e942018-10-21 21:11:33 -0400845 }
846 //If ingress port is not specified (nil), it may be a wildcarded
847 //route if egress port is OFPP_CONTROLLER or a nni logical port,
848 //in which case we need to create a half-route where only the egress
849 //hop is filled, the first hop is nil
khenaidoo2c6a0992019-04-29 13:46:56 -0400850 if ingressPortNo == 0 && agent.isNNIPort(egressPortNo) {
khenaidoo89b0e942018-10-21 21:11:33 -0400851 // We can use the 2nd hop of any upstream route, so just find the first upstream:
852 for routeLink, route := range agent.deviceGraph.Routes {
khenaidoo2c6a0992019-04-29 13:46:56 -0400853 if agent.isNNIPort(routeLink.Egress) {
khenaidoo89b0e942018-10-21 21:11:33 -0400854 routes = append(routes, graph.RouteHop{}) // first hop is set to empty
855 routes = append(routes, route[1])
856 return routes
857 }
858 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400859 log.Warnw("no-upstream-route", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "logicalPortsNo": agent.logicalPortsNo})
khenaidoo89b0e942018-10-21 21:11:33 -0400860 return nil
861 }
862 //If egress port is not specified (nil), we can also can return a "half" route
khenaidoo19d7b632018-10-30 10:49:50 -0400863 if egressPortNo == 0 {
khenaidoo89b0e942018-10-21 21:11:33 -0400864 for routeLink, route := range agent.deviceGraph.Routes {
khenaidoo19d7b632018-10-30 10:49:50 -0400865 if routeLink.Ingress == ingressPortNo {
khenaidoo89b0e942018-10-21 21:11:33 -0400866 routes = append(routes, route[0])
867 routes = append(routes, graph.RouteHop{})
868 return routes
869 }
870 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400871 log.Warnw("no-downstream-route", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "logicalPortsNo": agent.logicalPortsNo})
khenaidoo89b0e942018-10-21 21:11:33 -0400872 return nil
873 }
khenaidoo89b0e942018-10-21 21:11:33 -0400874 // Return the pre-calculated route
khenaidoo19d7b632018-10-30 10:49:50 -0400875 return agent.getPreCalculatedRoute(ingressPortNo, egressPortNo)
khenaidoo89b0e942018-10-21 21:11:33 -0400876}
877
khenaidoo89b0e942018-10-21 21:11:33 -0400878func (agent *LogicalDeviceAgent) rootDeviceDefaultRules() *fu.FlowsAndGroups {
879 return fu.NewFlowsAndGroups()
880}
881
882func (agent *LogicalDeviceAgent) leafDeviceDefaultRules(deviceId string) *fu.FlowsAndGroups {
883 fg := fu.NewFlowsAndGroups()
884 var device *voltha.Device
885 var err error
khenaidoo19d7b632018-10-30 10:49:50 -0400886 if device, err = agent.deviceMgr.GetDevice(deviceId); err != nil {
khenaidoo89b0e942018-10-21 21:11:33 -0400887 return fg
888 }
889 //set the upstream and downstream ports
890 upstreamPorts := make([]*voltha.Port, 0)
891 downstreamPorts := make([]*voltha.Port, 0)
892 for _, port := range device.Ports {
893 if port.Type == voltha.Port_PON_ONU || port.Type == voltha.Port_VENET_ONU {
894 upstreamPorts = append(upstreamPorts, port)
895 } else if port.Type == voltha.Port_ETHERNET_UNI {
896 downstreamPorts = append(downstreamPorts, port)
897 }
898 }
899 //it is possible that the downstream ports are not created, but the flow_decomposition has already
900 //kicked in. In such scenarios, cut short the processing and return.
khenaidoo910204f2019-04-08 17:56:40 -0400901 if len(downstreamPorts) == 0 || len(upstreamPorts) == 0 {
khenaidoo89b0e942018-10-21 21:11:33 -0400902 return fg
903 }
904 // set up the default flows
905 var fa *fu.FlowArgs
906 fa = &fu.FlowArgs{
907 KV: fu.OfpFlowModArgs{"priority": 500},
908 MatchFields: []*ofp.OfpOxmOfbField{
909 fd.InPort(downstreamPorts[0].PortNo),
910 fd.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 0),
911 },
912 Actions: []*ofp.OfpAction{
913 fd.SetField(fd.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | device.Vlan)),
khenaidoo19d7b632018-10-30 10:49:50 -0400914 fd.Output(upstreamPorts[0].PortNo),
khenaidoo89b0e942018-10-21 21:11:33 -0400915 },
916 }
917 fg.AddFlow(fd.MkFlowStat(fa))
918
919 fa = &fu.FlowArgs{
920 KV: fu.OfpFlowModArgs{"priority": 500},
921 MatchFields: []*ofp.OfpOxmOfbField{
922 fd.InPort(downstreamPorts[0].PortNo),
923 fd.VlanVid(0),
924 },
925 Actions: []*ofp.OfpAction{
926 fd.PushVlan(0x8100),
927 fd.SetField(fd.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | device.Vlan)),
928 fd.Output(upstreamPorts[0].PortNo),
929 },
930 }
931 fg.AddFlow(fd.MkFlowStat(fa))
932
933 fa = &fu.FlowArgs{
934 KV: fu.OfpFlowModArgs{"priority": 500},
935 MatchFields: []*ofp.OfpOxmOfbField{
936 fd.InPort(upstreamPorts[0].PortNo),
937 fd.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | device.Vlan),
938 },
939 Actions: []*ofp.OfpAction{
940 fd.SetField(fd.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 0)),
941 fd.Output(downstreamPorts[0].PortNo),
942 },
943 }
944 fg.AddFlow(fd.MkFlowStat(fa))
945
946 return fg
947}
948
949func (agent *LogicalDeviceAgent) generateDefaultRules() *fu.DeviceRules {
950 rules := fu.NewDeviceRules()
951 var ld *voltha.LogicalDevice
952 var err error
khenaidoo19d7b632018-10-30 10:49:50 -0400953 if ld, err = agent.GetLogicalDevice(); err != nil {
khenaidoo89b0e942018-10-21 21:11:33 -0400954 log.Warnw("no-logical-device", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
955 return rules
956 }
957
958 deviceNodeIds := agent.deviceGraph.GetDeviceNodeIds()
khenaidooca301322019-01-09 23:06:32 -0500959 for deviceId := range deviceNodeIds {
khenaidoo89b0e942018-10-21 21:11:33 -0400960 if deviceId == ld.RootDeviceId {
961 rules.AddFlowsAndGroup(deviceId, agent.rootDeviceDefaultRules())
962 } else {
963 rules.AddFlowsAndGroup(deviceId, agent.leafDeviceDefaultRules(deviceId))
964 }
965 }
966 return rules
967}
968
969func (agent *LogicalDeviceAgent) GetAllDefaultRules() *fu.DeviceRules {
khenaidoo89b0e942018-10-21 21:11:33 -0400970 return agent.DefaultFlowRules
971}
972
973func (agent *LogicalDeviceAgent) GetWildcardInputPorts(excludePort ...uint32) []uint32 {
974 lPorts := make([]uint32, 0)
975 var exclPort uint32
976 if len(excludePort) == 1 {
977 exclPort = excludePort[0]
978 }
khenaidoo19d7b632018-10-30 10:49:50 -0400979 if lDevice, _ := agent.GetLogicalDevice(); lDevice != nil {
khenaidoo89b0e942018-10-21 21:11:33 -0400980 for _, port := range lDevice.Ports {
981 if port.OfpPort.PortNo != exclPort {
982 lPorts = append(lPorts, port.OfpPort.PortNo)
983 }
984 }
985 }
986 return lPorts
987}
khenaidoo19d7b632018-10-30 10:49:50 -0400988
989func (agent *LogicalDeviceAgent) GetDeviceGraph() *graph.DeviceGraph {
990 return agent.deviceGraph
991}
992
khenaidoo2c6a0992019-04-29 13:46:56 -0400993//updateRoutes redo the device graph if not done already and setup the default rules as well
994func (agent *LogicalDeviceAgent) updateRoutes(device *voltha.Device, port *voltha.Port) error {
995 log.Debugf("updateRoutes", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "device": device.Id, "port": port})
khenaidoo910204f2019-04-08 17:56:40 -0400996 agent.lockLogicalDevice.Lock()
997 defer agent.lockLogicalDevice.Unlock()
khenaidoo2c6a0992019-04-29 13:46:56 -0400998 rules := fu.NewDeviceRules()
khenaidoo19d7b632018-10-30 10:49:50 -0400999 if agent.deviceGraph == nil {
khenaidoo910204f2019-04-08 17:56:40 -04001000 agent.deviceGraph = graph.NewDeviceGraph(agent.logicalDeviceId, agent.deviceMgr.GetDevice)
khenaidoo2c6a0992019-04-29 13:46:56 -04001001 }
1002 // Get all the logical ports on that logical device
1003 if lDevice, err := agent.getLogicalDeviceWithoutLock(); err != nil {
1004 log.Errorf("unknown-logical-device", log.Fields{"error": err, "logicalDeviceId": agent.logicalDeviceId})
1005 return err
1006 } else {
1007 //TODO: Find a better way to refresh only missing routes
1008 agent.deviceGraph.ComputeRoutes(lDevice.Ports)
1009 }
1010 deviceNodeIds := agent.deviceGraph.GetDeviceNodeIds()
1011 for deviceId := range deviceNodeIds {
1012 if deviceId == agent.rootDeviceId {
1013 rules.AddFlowsAndGroup(deviceId, agent.rootDeviceDefaultRules())
1014 } else {
1015 rules.AddFlowsAndGroup(deviceId, agent.leafDeviceDefaultRules(deviceId))
khenaidoo910204f2019-04-08 17:56:40 -04001016 }
khenaidoo19d7b632018-10-30 10:49:50 -04001017 }
khenaidoo2c6a0992019-04-29 13:46:56 -04001018 agent.DefaultFlowRules = rules
1019
1020 // Reset the default flows flag to ensure all default flows are sent to all devices, including the newly added
1021 // one when a flow request is received.
1022 agent.includeDefaultFlows = true
1023 agent.deviceGraph.Print()
1024 return nil
khenaidoo19d7b632018-10-30 10:49:50 -04001025}
1026
khenaidoo2c6a0992019-04-29 13:46:56 -04001027//updateDeviceGraph updates the device graph if not done already and setup the default rules as well
khenaidoo910204f2019-04-08 17:56:40 -04001028func (agent *LogicalDeviceAgent) updateDeviceGraph(lp *voltha.LogicalPort) {
khenaidoo2c6a0992019-04-29 13:46:56 -04001029 log.Debugf("updateDeviceGraph", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
1030 agent.lockLogicalDevice.Lock()
1031 defer agent.lockLogicalDevice.Unlock()
1032 rules := fu.NewDeviceRules()
khenaidoo910204f2019-04-08 17:56:40 -04001033 if agent.deviceGraph == nil {
1034 agent.deviceGraph = graph.NewDeviceGraph(agent.logicalDeviceId, agent.deviceMgr.GetDevice)
1035 }
1036 agent.deviceGraph.AddPort(lp)
khenaidoo2c6a0992019-04-29 13:46:56 -04001037 deviceNodeIds := agent.deviceGraph.GetDeviceNodeIds()
1038 for deviceId := range deviceNodeIds {
1039 if deviceId == agent.rootDeviceId {
1040 rules.AddFlowsAndGroup(deviceId, agent.rootDeviceDefaultRules())
1041 } else {
1042 rules.AddFlowsAndGroup(deviceId, agent.leafDeviceDefaultRules(deviceId))
khenaidooca301322019-01-09 23:06:32 -05001043 }
Stephane Barbarie1ab43272018-12-08 21:42:13 -05001044 }
khenaidoo2c6a0992019-04-29 13:46:56 -04001045 agent.DefaultFlowRules = rules
khenaidoo19d7b632018-10-30 10:49:50 -04001046
khenaidoo2c6a0992019-04-29 13:46:56 -04001047 // Reset the default flows flag to ensure all default flows are sent to all devices, including the newly added
1048 // one when a flow request is received.
1049 agent.includeDefaultFlows = true
1050 agent.deviceGraph.Print()
khenaidoo19d7b632018-10-30 10:49:50 -04001051}
khenaidoofdbad6e2018-11-06 22:26:38 -05001052
khenaidoofc1314d2019-03-14 09:34:21 -04001053// portAdded is a callback invoked when a port is added to the logical device.
1054// TODO: To use when POST_ADD is fixed.
1055func (agent *LogicalDeviceAgent) portAdded(args ...interface{}) interface{} {
1056 log.Debugw("portAdded-callback", log.Fields{"argsLen": len(args)})
1057
1058 var port *voltha.LogicalPort
1059
1060 // Sanity check
1061 if args[0] != nil {
1062 log.Warnw("previous-data-not-nil", log.Fields{"args0": args[0]})
1063 }
1064 var ok bool
1065 if port, ok = args[1].(*voltha.LogicalPort); !ok {
1066 log.Errorw("invalid-args", log.Fields{"args1": args[1]})
1067 return nil
1068 }
1069
1070 // Set the proxy and callback for that port
1071 agent.portProxiesLock.Lock()
Stephane Barbarie40fd3b22019-04-23 21:50:47 -04001072 agent.portProxies[port.Id] = agent.clusterDataProxy.CreateProxy(
khenaidoofc1314d2019-03-14 09:34:21 -04001073 fmt.Sprintf("/logical_devices/%s/ports/%s", agent.logicalDeviceId, port.Id),
1074 false)
1075 agent.portProxies[port.Id].RegisterCallback(model.POST_UPDATE, agent.portUpdated)
1076 agent.portProxiesLock.Unlock()
1077
1078 // Send the port change event to the OF controller
1079 agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceId,
khenaidoo910204f2019-04-08 17:56:40 -04001080 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_ADD, Desc: port.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001081
1082 return nil
1083}
1084
1085// portRemoved is a callback invoked when a port is removed from the logical device.
1086// TODO: To use when POST_ADD is fixed.
1087func (agent *LogicalDeviceAgent) portRemoved(args ...interface{}) interface{} {
1088 log.Debugw("portRemoved-callback", log.Fields{"argsLen": len(args)})
1089
1090 var port *voltha.LogicalPort
1091
1092 // Sanity check
1093 if args[1] != nil {
1094 log.Warnw("data-not-nil", log.Fields{"args1": args[1]})
1095 }
1096 var ok bool
1097 if port, ok = args[0].(*voltha.LogicalPort); !ok {
1098 log.Errorw("invalid-args", log.Fields{"args0": args[0]})
1099 return nil
1100 }
1101
1102 // Remove the proxy and callback for that port
1103 agent.portProxiesLock.Lock()
1104 agent.portProxies[port.Id].UnregisterCallback(model.POST_UPDATE, agent.portUpdated)
1105 delete(agent.portProxies, port.Id)
1106 agent.portProxiesLock.Unlock()
1107
1108 // Send the port change event to the OF controller
1109 agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceId,
khenaidoo910204f2019-04-08 17:56:40 -04001110 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_DELETE, Desc: port.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001111
1112 return nil
1113}
1114
1115// 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 -04001116func diff(oldList, newList []*voltha.LogicalPort) (newPorts, changedPorts, deletedPorts []*voltha.LogicalPort) {
khenaidoofc1314d2019-03-14 09:34:21 -04001117 newPorts = make([]*voltha.LogicalPort, 0)
1118 changedPorts = make([]*voltha.LogicalPort, 0)
1119 deletedPorts = make([]*voltha.LogicalPort, 0)
1120 for _, o := range oldList {
1121 found := false
1122 changed := false
1123 for _, n := range newList {
1124 if o.Id == n.Id {
1125 changed = !reflect.DeepEqual(o, n)
1126 found = true
1127 break
1128 }
1129 }
1130 if !found {
1131 deletedPorts = append(deletedPorts, o)
1132 }
1133 if changed {
1134 changedPorts = append(changedPorts, o)
1135 }
1136 }
1137 for _, n := range newList {
1138 found := false
1139 for _, o := range oldList {
1140 if o.Id == n.Id {
1141 found = true
1142 break
1143 }
1144 }
1145 if !found {
1146 newPorts = append(newPorts, n)
1147 }
1148 }
1149 return
1150}
1151
1152// portUpdated is invoked when a port is updated on the logical device. Until
1153// the POST_ADD notification is fixed, we will use the logical device to
1154// update that data.
1155func (agent *LogicalDeviceAgent) portUpdated(args ...interface{}) interface{} {
1156 log.Debugw("portUpdated-callback", log.Fields{"argsLen": len(args)})
1157
1158 var oldLD *voltha.LogicalDevice
1159 var newlD *voltha.LogicalDevice
1160
1161 var ok bool
1162 if oldLD, ok = args[0].(*voltha.LogicalDevice); !ok {
1163 log.Errorw("invalid-args", log.Fields{"args0": args[0]})
1164 return nil
1165 }
1166 if newlD, ok = args[1].(*voltha.LogicalDevice); !ok {
1167 log.Errorw("invalid-args", log.Fields{"args1": args[1]})
1168 return nil
1169 }
1170
1171 if reflect.DeepEqual(oldLD.Ports, newlD.Ports) {
1172 log.Debug("ports-have-not-changed")
1173 return nil
1174 }
1175
1176 // Get the difference between the two list
1177 newPorts, changedPorts, deletedPorts := diff(oldLD.Ports, newlD.Ports)
1178
1179 // Send the port change events to the OF controller
khenaidoo2c6a0992019-04-29 13:46:56 -04001180 for _, newP := range newPorts {
khenaidoofc1314d2019-03-14 09:34:21 -04001181 go agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceId,
khenaidoo2c6a0992019-04-29 13:46:56 -04001182 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_ADD, Desc: newP.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001183 }
1184 for _, change := range changedPorts {
1185 go agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceId,
khenaidoo910204f2019-04-08 17:56:40 -04001186 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_MODIFY, Desc: change.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001187 }
1188 for _, del := range deletedPorts {
1189 go agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceId,
khenaidoo910204f2019-04-08 17:56:40 -04001190 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_DELETE, Desc: del.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001191 }
1192
1193 return nil
1194}
1195
khenaidoo8f474192019-04-03 17:20:44 -04001196// addNNILogicalPort adds an NNI port to the logical device. It returns a bool representing whether a port has been
1197// added and an eror in case a valid error is encountered. If the port was successfully added it will return
1198// (true, nil). If the device is not in the correct state it will return (false, nil) as this is a valid
1199// scenario. This also applies to the case where the port was already added.
khenaidoo910204f2019-04-08 17:56:40 -04001200func (agent *LogicalDeviceAgent) addNNILogicalPort(device *voltha.Device, port *voltha.Port) (bool, error) {
khenaidoo1ce37ad2019-03-24 22:07:24 -04001201 log.Debugw("addNNILogicalPort", log.Fields{"NNI": port})
khenaidoo8f474192019-04-03 17:20:44 -04001202 if device.AdminState != voltha.AdminState_ENABLED || device.OperStatus != voltha.OperStatus_ACTIVE {
1203 log.Infow("device-not-ready", log.Fields{"deviceId": device.Id, "admin": device.AdminState, "oper": device.OperStatus})
1204 return false, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001205 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001206 agent.lockLogicalDevice.RLock()
1207 if agent.portExist(device, port) {
1208 log.Debugw("port-already-exist", log.Fields{"port": port})
1209 agent.lockLogicalDevice.RUnlock()
khenaidoo8f474192019-04-03 17:20:44 -04001210 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001211 }
1212 agent.lockLogicalDevice.RUnlock()
1213
khenaidoofc1314d2019-03-14 09:34:21 -04001214 var portCap *ic.PortCapability
1215 var err error
1216 // First get the port capability
1217 if portCap, err = agent.deviceMgr.getPortCapability(nil, device.Id, port.PortNo); err != nil {
1218 log.Errorw("error-retrieving-port-capabilities", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001219 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001220 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001221
1222 agent.lockLogicalDevice.Lock()
1223 defer agent.lockLogicalDevice.Unlock()
1224 // Double check again if this port has been already added since the getPortCapability could have taken a long time
1225 if agent.portExist(device, port) {
1226 log.Debugw("port-already-exist", log.Fields{"port": port})
khenaidoo8f474192019-04-03 17:20:44 -04001227 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001228 }
1229
khenaidoofc1314d2019-03-14 09:34:21 -04001230 portCap.Port.RootPort = true
1231 lp := (proto.Clone(portCap.Port)).(*voltha.LogicalPort)
1232 lp.DeviceId = device.Id
1233 lp.Id = fmt.Sprintf("nni-%d", port.PortNo)
1234 lp.OfpPort.PortNo = port.PortNo
1235 lp.OfpPort.Name = lp.Id
1236 lp.DevicePortNo = port.PortNo
1237
khenaidoofc1314d2019-03-14 09:34:21 -04001238 var ld *voltha.LogicalDevice
1239 if ld, err = agent.getLogicalDeviceWithoutLock(); err != nil {
1240 log.Errorw("error-retrieving-logical-device", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001241 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001242 }
1243 cloned := (proto.Clone(ld)).(*voltha.LogicalDevice)
1244 if cloned.Ports == nil {
1245 cloned.Ports = make([]*voltha.LogicalPort, 0)
1246 }
1247 cloned.Ports = append(cloned.Ports, lp)
1248
1249 if err = agent.updateLogicalDeviceWithoutLock(cloned); err != nil {
1250 log.Errorw("error-updating-logical-device", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001251 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001252 }
khenaidoo910204f2019-04-08 17:56:40 -04001253
1254 // Update the device graph with this new logical port
1255 clonedLP := (proto.Clone(lp)).(*voltha.LogicalPort)
1256 go agent.updateDeviceGraph(clonedLP)
1257
khenaidoo8f474192019-04-03 17:20:44 -04001258 return true, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001259}
1260
khenaidoo910204f2019-04-08 17:56:40 -04001261func (agent *LogicalDeviceAgent) portExist(device *voltha.Device, port *voltha.Port) bool {
khenaidoo54544ae2019-03-18 13:22:39 -04001262 if ldevice, _ := agent.getLogicalDeviceWithoutLock(); ldevice != nil {
khenaidoofc1314d2019-03-14 09:34:21 -04001263 for _, lPort := range ldevice.Ports {
khenaidoo54544ae2019-03-18 13:22:39 -04001264 if lPort.DeviceId == device.Id && lPort.DevicePortNo == port.PortNo && lPort.Id == port.Label {
khenaidoofc1314d2019-03-14 09:34:21 -04001265 return true
1266 }
1267 }
1268 }
1269 return false
1270}
1271
khenaidoo8f474192019-04-03 17:20:44 -04001272// addUNILogicalPort adds an UNI port to the logical device. It returns a bool representing whether a port has been
1273// added and an eror in case a valid error is encountered. If the port was successfully added it will return
1274// (true, nil). If the device is not in the correct state it will return (false, nil) as this is a valid
1275// scenario. This also applies to the case where the port was already added.
khenaidoo910204f2019-04-08 17:56:40 -04001276func (agent *LogicalDeviceAgent) addUNILogicalPort(childDevice *voltha.Device, port *voltha.Port) (bool, error) {
khenaidoofc1314d2019-03-14 09:34:21 -04001277 log.Debugw("addUNILogicalPort", log.Fields{"port": port})
khenaidoo8f474192019-04-03 17:20:44 -04001278 if childDevice.AdminState != voltha.AdminState_ENABLED || childDevice.OperStatus != voltha.OperStatus_ACTIVE {
1279 log.Infow("device-not-ready", log.Fields{"deviceId": childDevice.Id, "admin": childDevice.AdminState, "oper": childDevice.OperStatus})
1280 return false, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001281 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001282 agent.lockLogicalDevice.RLock()
1283 if agent.portExist(childDevice, port) {
1284 log.Debugw("port-already-exist", log.Fields{"port": port})
1285 agent.lockLogicalDevice.RUnlock()
khenaidoo8f474192019-04-03 17:20:44 -04001286 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001287 }
1288 agent.lockLogicalDevice.RUnlock()
khenaidoofc1314d2019-03-14 09:34:21 -04001289 var portCap *ic.PortCapability
1290 var err error
1291 // First get the port capability
1292 if portCap, err = agent.deviceMgr.getPortCapability(nil, childDevice.Id, port.PortNo); err != nil {
1293 log.Errorw("error-retrieving-port-capabilities", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001294 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001295 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001296 agent.lockLogicalDevice.Lock()
1297 defer agent.lockLogicalDevice.Unlock()
1298 // Double check again if this port has been already added since the getPortCapability could have taken a long time
1299 if agent.portExist(childDevice, port) {
1300 log.Debugw("port-already-exist", log.Fields{"port": port})
khenaidoo8f474192019-04-03 17:20:44 -04001301 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001302 }
khenaidoofc1314d2019-03-14 09:34:21 -04001303 // Get stored logical device
1304 if ldevice, err := agent.getLogicalDeviceWithoutLock(); err != nil {
khenaidoo8f474192019-04-03 17:20:44 -04001305 return false, status.Error(codes.NotFound, agent.logicalDeviceId)
khenaidoofc1314d2019-03-14 09:34:21 -04001306 } else {
1307 log.Debugw("adding-uni", log.Fields{"deviceId": childDevice.Id})
1308 portCap.Port.RootPort = false
Matt Jeanneret3815e322019-03-12 19:15:49 -04001309 portCap.Port.Id = port.Label
1310 portCap.Port.OfpPort.PortNo = port.PortNo
khenaidoofc1314d2019-03-14 09:34:21 -04001311 portCap.Port.DeviceId = childDevice.Id
1312 portCap.Port.DevicePortNo = port.PortNo
1313 cloned := (proto.Clone(ldevice)).(*voltha.LogicalDevice)
1314 if cloned.Ports == nil {
1315 cloned.Ports = make([]*voltha.LogicalPort, 0)
1316 }
1317 cloned.Ports = append(cloned.Ports, portCap.Port)
khenaidoo910204f2019-04-08 17:56:40 -04001318 if err := agent.updateLogicalDeviceWithoutLock(cloned); err != nil {
1319 return false, err
1320 }
khenaidoo910204f2019-04-08 17:56:40 -04001321 // Update the device graph with this new logical port
1322 clonedLP := (proto.Clone(portCap.Port)).(*voltha.LogicalPort)
1323 go agent.updateDeviceGraph(clonedLP)
1324 return true, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001325 }
1326}
1327
khenaidoo43c82122018-11-22 18:38:28 -05001328func (agent *LogicalDeviceAgent) packetOut(packet *ofp.OfpPacketOut) {
khenaidoofdbad6e2018-11-06 22:26:38 -05001329 log.Debugw("packet-out", log.Fields{"packet": packet.GetInPort()})
1330 outPort := fd.GetPacketOutPort(packet)
1331 //frame := packet.GetData()
1332 //TODO: Use a channel between the logical agent and the device agent
khenaidooca301322019-01-09 23:06:32 -05001333 if err := agent.deviceMgr.packetOut(agent.rootDeviceId, outPort, packet); err != nil {
khenaidoo910204f2019-04-08 17:56:40 -04001334 log.Error("packetout-failed", log.Fields{"logicalDeviceID": agent.rootDeviceId})
khenaidooca301322019-01-09 23:06:32 -05001335 }
khenaidoofdbad6e2018-11-06 22:26:38 -05001336}
1337
khenaidoo297cd252019-02-07 22:10:23 -05001338func (agent *LogicalDeviceAgent) packetIn(port uint32, transactionId string, packet []byte) {
1339 log.Debugw("packet-in", log.Fields{"port": port, "packet": packet, "transactionId": transactionId})
khenaidooca301322019-01-09 23:06:32 -05001340 packetIn := fd.MkPacketIn(port, packet)
khenaidoo297cd252019-02-07 22:10:23 -05001341 agent.ldeviceMgr.grpcNbiHdlr.sendPacketIn(agent.logicalDeviceId, transactionId, packetIn)
khenaidooca301322019-01-09 23:06:32 -05001342 log.Debugw("sending-packet-in", log.Fields{"packet-in": packetIn})
khenaidoofdbad6e2018-11-06 22:26:38 -05001343}
khenaidoo2c6a0992019-04-29 13:46:56 -04001344
1345func (agent *LogicalDeviceAgent) addLogicalPortToMap(portNo uint32, nniPort bool) {
1346 agent.lockLogicalPortsNo.Lock()
1347 defer agent.lockLogicalPortsNo.Unlock()
1348 if exist := agent.logicalPortsNo[portNo]; !exist {
1349 agent.logicalPortsNo[portNo] = nniPort
1350 }
1351}
1352
1353func (agent *LogicalDeviceAgent) deleteLogicalPortFromMap(portNo uint32) {
1354 agent.lockLogicalPortsNo.Lock()
1355 defer agent.lockLogicalPortsNo.Unlock()
1356 if exist := agent.logicalPortsNo[portNo]; exist {
1357 delete(agent.logicalPortsNo, portNo)
1358 }
1359}
1360
1361func (agent *LogicalDeviceAgent) isNNIPort(portNo uint32) bool {
1362 agent.lockLogicalPortsNo.RLock()
1363 defer agent.lockLogicalPortsNo.RUnlock()
1364 if exist := agent.logicalPortsNo[portNo]; exist {
1365 return agent.logicalPortsNo[portNo]
1366 }
1367 return false
1368}
1369
1370func (agent *LogicalDeviceAgent) getFirstNNIPort() (uint32, error) {
1371 agent.lockLogicalPortsNo.RLock()
1372 defer agent.lockLogicalPortsNo.RUnlock()
1373 for portNo, nni := range agent.logicalPortsNo {
1374 if nni {
1375 return portNo, nil
1376 }
1377 }
1378 return 0, status.Error(codes.NotFound, "No NNI port found")
1379}