blob: 70349d88e6816de004fd4001d2fcf99c4542d232 [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"
Stephane Barbarieef6650d2019-07-18 12:15:09 -040035 "time"
khenaidoob9203542018-09-17 22:56:37 -040036)
37
38type LogicalDeviceAgent struct {
khenaidoo3306c992019-05-24 16:57:35 -040039 logicalDeviceId string
40 rootDeviceId string
41 deviceMgr *DeviceManager
42 ldeviceMgr *LogicalDeviceManager
43 clusterDataProxy *model.Proxy
44 exitChannel chan int
45 deviceGraph *graph.DeviceGraph
46 flowProxy *model.Proxy
47 groupProxy *model.Proxy
48 ldProxy *model.Proxy
49 portProxies map[string]*model.Proxy
50 portProxiesLock sync.RWMutex
51 lockLogicalDevice sync.RWMutex
52 logicalPortsNo map[uint32]bool //value is true for NNI port
53 lockLogicalPortsNo sync.RWMutex
54 flowDecomposer *fd.FlowDecomposer
55 defaultTimeout int64
khenaidoob9203542018-09-17 22:56:37 -040056}
57
Stephane Barbarie1ab43272018-12-08 21:42:13 -050058func newLogicalDeviceAgent(id string, deviceId string, ldeviceMgr *LogicalDeviceManager,
59 deviceMgr *DeviceManager,
khenaidoo2c6a0992019-04-29 13:46:56 -040060 cdProxy *model.Proxy, timeout int64) *LogicalDeviceAgent {
khenaidoob9203542018-09-17 22:56:37 -040061 var agent LogicalDeviceAgent
62 agent.exitChannel = make(chan int, 1)
63 agent.logicalDeviceId = id
Stephane Barbarie1ab43272018-12-08 21:42:13 -050064 agent.rootDeviceId = deviceId
khenaidoob9203542018-09-17 22:56:37 -040065 agent.deviceMgr = deviceMgr
khenaidoo9a468962018-09-19 15:33:13 -040066 agent.clusterDataProxy = cdProxy
khenaidoob9203542018-09-17 22:56:37 -040067 agent.ldeviceMgr = ldeviceMgr
khenaidoo19d7b632018-10-30 10:49:50 -040068 agent.flowDecomposer = fd.NewFlowDecomposer(agent.deviceMgr)
khenaidoo92e62c52018-10-03 14:02:54 -040069 agent.lockLogicalDevice = sync.RWMutex{}
khenaidoofc1314d2019-03-14 09:34:21 -040070 agent.portProxies = make(map[string]*model.Proxy)
71 agent.portProxiesLock = sync.RWMutex{}
khenaidoo2c6a0992019-04-29 13:46:56 -040072 agent.lockLogicalPortsNo = sync.RWMutex{}
73 agent.logicalPortsNo = make(map[uint32]bool)
khenaidoo2c6a0992019-04-29 13:46:56 -040074 agent.defaultTimeout = timeout
khenaidoob9203542018-09-17 22:56:37 -040075 return &agent
76}
77
khenaidoo4d4802d2018-10-04 21:59:49 -040078// start creates the logical device and add it to the data model
khenaidoo297cd252019-02-07 22:10:23 -050079func (agent *LogicalDeviceAgent) start(ctx context.Context, loadFromdB bool) error {
80 log.Infow("starting-logical_device-agent", log.Fields{"logicaldeviceId": agent.logicalDeviceId, "loadFromdB": loadFromdB})
81 var ld *voltha.LogicalDevice
82 if !loadFromdB {
khenaidoo7e3d8f12019-08-02 16:06:30 -040083 //Build the logical device based on information retrieved from the device adapter
84 var switchCap *ic.SwitchCapability
khenaidoo297cd252019-02-07 22:10:23 -050085 var err error
khenaidoo7e3d8f12019-08-02 16:06:30 -040086 if switchCap, err = agent.deviceMgr.getSwitchCapability(ctx, agent.rootDeviceId); err != nil {
87 log.Errorw("error-creating-logical-device", log.Fields{"error": err})
88 return err
89 }
khenaidoo297cd252019-02-07 22:10:23 -050090 ld = &voltha.LogicalDevice{Id: agent.logicalDeviceId, RootDeviceId: agent.rootDeviceId}
91
92 // Create the datapath ID (uint64) using the logical device ID (based on the MAC Address)
93 var datapathID uint64
94 if datapathID, err = CreateDataPathId(agent.logicalDeviceId); err != nil {
95 log.Errorw("error-creating-datapath-id", log.Fields{"error": err})
96 return err
97 }
98 ld.DatapathId = datapathID
khenaidoo7e3d8f12019-08-02 16:06:30 -040099 ld.Desc = (proto.Clone(switchCap.Desc)).(*ofp.OfpDesc)
100 log.Debugw("Switch-capability", log.Fields{"Desc": ld.Desc, "fromAd": switchCap.Desc})
101 ld.SwitchFeatures = (proto.Clone(switchCap.SwitchFeatures)).(*ofp.OfpSwitchFeatures)
khenaidoo297cd252019-02-07 22:10:23 -0500102 ld.Flows = &ofp.Flows{Items: nil}
103 ld.FlowGroups = &ofp.FlowGroups{Items: nil}
104
khenaidoo297cd252019-02-07 22:10:23 -0500105 agent.lockLogicalDevice.Lock()
khenaidoo297cd252019-02-07 22:10:23 -0500106 // Save the logical device
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400107 if added := agent.clusterDataProxy.AddWithID(ctx, "/logical_devices", ld.Id, ld, ""); added == nil {
khenaidoo297cd252019-02-07 22:10:23 -0500108 log.Errorw("failed-to-add-logical-device", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
109 } else {
110 log.Debugw("logicaldevice-created", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
111 }
112 agent.lockLogicalDevice.Unlock()
khenaidoofc1314d2019-03-14 09:34:21 -0400113
khenaidoo3d3b8c22019-05-22 18:10:39 -0400114 // TODO: Set the logical ports in a separate call once the port update issue is fixed.
115 go agent.setupLogicalPorts(ctx)
116
khenaidoo297cd252019-02-07 22:10:23 -0500117 } else {
118 // load from dB - the logical may not exist at this time. On error, just return and the calling function
119 // will destroy this agent.
120 var err error
121 if ld, err = agent.GetLogicalDevice(); err != nil {
122 log.Warnw("failed-to-load-logical-device", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
123 return err
124 }
khenaidoo3d3b8c22019-05-22 18:10:39 -0400125
khenaidoo8c3303d2019-02-13 14:59:39 -0500126 // Update the root device Id
127 agent.rootDeviceId = ld.RootDeviceId
khenaidoo3d3b8c22019-05-22 18:10:39 -0400128
129 // Setup the local list of logical ports
130 agent.addLogicalPortsToMap(ld.Ports)
131
132 // Setup the device graph
133 agent.generateDeviceGraph()
khenaidoob9203542018-09-17 22:56:37 -0400134 }
khenaidoo92e62c52018-10-03 14:02:54 -0400135 agent.lockLogicalDevice.Lock()
khenaidoo3d3b8c22019-05-22 18:10:39 -0400136 defer agent.lockLogicalDevice.Unlock()
khenaidoofc1314d2019-03-14 09:34:21 -0400137
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400138 agent.flowProxy = agent.clusterDataProxy.CreateProxy(
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400139 ctx,
khenaidoo19d7b632018-10-30 10:49:50 -0400140 fmt.Sprintf("/logical_devices/%s/flows", agent.logicalDeviceId),
141 false)
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400142 agent.groupProxy = agent.clusterDataProxy.CreateProxy(
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400143 ctx,
khenaidoo19d7b632018-10-30 10:49:50 -0400144 fmt.Sprintf("/logical_devices/%s/flow_groups", agent.logicalDeviceId),
145 false)
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400146 agent.ldProxy = agent.clusterDataProxy.CreateProxy(
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400147 ctx,
khenaidoofc1314d2019-03-14 09:34:21 -0400148 fmt.Sprintf("/logical_devices/%s", agent.logicalDeviceId),
149 false)
khenaidoo19d7b632018-10-30 10:49:50 -0400150
khenaidoofc1314d2019-03-14 09:34:21 -0400151 // TODO: Use a port proxy once the POST_ADD is fixed
khenaidoo3d3b8c22019-05-22 18:10:39 -0400152 if agent.ldProxy != nil {
153 agent.ldProxy.RegisterCallback(model.POST_UPDATE, agent.portUpdated)
154 } else {
155 log.Errorw("logical-device-proxy-null", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
156 return status.Error(codes.Internal, "logical-device-proxy-null")
157 }
khenaidoobcf205b2019-01-25 22:21:14 -0500158
khenaidoob9203542018-09-17 22:56:37 -0400159 return nil
160}
161
khenaidoo4d4802d2018-10-04 21:59:49 -0400162// stop stops the logical devuce agent. This removes the logical device from the data model.
163func (agent *LogicalDeviceAgent) stop(ctx context.Context) {
164 log.Info("stopping-logical_device-agent")
165 agent.lockLogicalDevice.Lock()
166 defer agent.lockLogicalDevice.Unlock()
khenaidoo8c3303d2019-02-13 14:59:39 -0500167
khenaidoo4d4802d2018-10-04 21:59:49 -0400168 //Remove the logical device from the model
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400169 if removed := agent.clusterDataProxy.Remove(ctx, "/logical_devices/"+agent.logicalDeviceId, ""); removed == nil {
khenaidoo4d4802d2018-10-04 21:59:49 -0400170 log.Errorw("failed-to-remove-logical-device", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
171 } else {
172 log.Debugw("logicaldevice-removed", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
173 }
174 agent.exitChannel <- 1
175 log.Info("logical_device-agent-stopped")
176}
177
khenaidoo19d7b632018-10-30 10:49:50 -0400178// GetLogicalDevice locks the logical device model and then retrieves the latest logical device information
179func (agent *LogicalDeviceAgent) GetLogicalDevice() (*voltha.LogicalDevice, error) {
180 log.Debug("GetLogicalDevice")
khenaidoo1ce37ad2019-03-24 22:07:24 -0400181 agent.lockLogicalDevice.RLock()
182 defer agent.lockLogicalDevice.RUnlock()
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400183 logicalDevice := agent.clusterDataProxy.Get(context.Background(), "/logical_devices/"+agent.logicalDeviceId, 0, false, "")
khenaidoo92e62c52018-10-03 14:02:54 -0400184 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500185 return lDevice, nil
khenaidoo92e62c52018-10-03 14:02:54 -0400186 }
187 return nil, status.Errorf(codes.NotFound, "logical_device-%s", agent.logicalDeviceId)
188}
189
khenaidoodd237172019-05-27 16:37:17 -0400190func (agent *LogicalDeviceAgent) ListLogicalDeviceFlows() (*ofp.Flows, error) {
191 log.Debug("ListLogicalDeviceFlows")
192 agent.lockLogicalDevice.RLock()
193 defer agent.lockLogicalDevice.RUnlock()
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400194 logicalDevice := agent.clusterDataProxy.Get(context.Background(), "/logical_devices/"+agent.logicalDeviceId, 0, false, "")
khenaidoodd237172019-05-27 16:37:17 -0400195 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
196 cFlows := (proto.Clone(lDevice.Flows)).(*ofp.Flows)
197 return cFlows, nil
198 }
199 return nil, status.Errorf(codes.NotFound, "logical_device-%s", agent.logicalDeviceId)
200}
201
202func (agent *LogicalDeviceAgent) ListLogicalDeviceFlowGroups() (*ofp.FlowGroups, error) {
203 log.Debug("ListLogicalDeviceFlowGroups")
204 agent.lockLogicalDevice.RLock()
205 defer agent.lockLogicalDevice.RUnlock()
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400206 logicalDevice := agent.clusterDataProxy.Get(context.Background(), "/logical_devices/"+agent.logicalDeviceId, 0, false, "")
khenaidoodd237172019-05-27 16:37:17 -0400207 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
208 cFlowGroups := (proto.Clone(lDevice.FlowGroups)).(*ofp.FlowGroups)
209 return cFlowGroups, nil
210 }
211 return nil, status.Errorf(codes.NotFound, "logical_device-%s", agent.logicalDeviceId)
212}
213
khenaidoo19d7b632018-10-30 10:49:50 -0400214func (agent *LogicalDeviceAgent) ListLogicalDevicePorts() (*voltha.LogicalPorts, error) {
khenaidoo1ce37ad2019-03-24 22:07:24 -0400215 log.Debug("ListLogicalDevicePorts")
216 agent.lockLogicalDevice.RLock()
217 defer agent.lockLogicalDevice.RUnlock()
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400218 logicalDevice := agent.clusterDataProxy.Get(context.Background(), "/logical_devices/"+agent.logicalDeviceId, 0, false, "")
khenaidoo19d7b632018-10-30 10:49:50 -0400219 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
220 lPorts := make([]*voltha.LogicalPort, 0)
221 for _, port := range lDevice.Ports {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500222 lPorts = append(lPorts, port)
khenaidoo19d7b632018-10-30 10:49:50 -0400223 }
224 return &voltha.LogicalPorts{Items: lPorts}, nil
225 }
226 return nil, status.Errorf(codes.NotFound, "logical_device-%s", agent.logicalDeviceId)
227}
228
229// listFlows locks the logical device model and then retrieves the latest flow information
230func (agent *LogicalDeviceAgent) listFlows() []*ofp.OfpFlowStats {
231 log.Debug("listFlows")
khenaidoo1ce37ad2019-03-24 22:07:24 -0400232 agent.lockLogicalDevice.RLock()
233 defer agent.lockLogicalDevice.RUnlock()
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400234 logicalDevice := agent.clusterDataProxy.Get(context.Background(), "/logical_devices/"+agent.logicalDeviceId, 0, false, "")
khenaidoo19d7b632018-10-30 10:49:50 -0400235 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
236 return lDevice.Flows.Items
237 }
238 return nil
239}
240
241// listFlowGroups locks the logical device model and then retrieves the latest flow groups information
242func (agent *LogicalDeviceAgent) listFlowGroups() []*ofp.OfpGroupEntry {
243 log.Debug("listFlowGroups")
khenaidoo1ce37ad2019-03-24 22:07:24 -0400244 agent.lockLogicalDevice.RLock()
245 defer agent.lockLogicalDevice.RUnlock()
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400246 logicalDevice := agent.clusterDataProxy.Get(context.Background(), "/logical_devices/"+agent.logicalDeviceId, 0, false, "")
khenaidoo19d7b632018-10-30 10:49:50 -0400247 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
248 return lDevice.FlowGroups.Items
249 }
250 return nil
251}
252
khenaidoo43c82122018-11-22 18:38:28 -0500253//updateLogicalDeviceWithoutLock updates the model with the logical device. It clones the logicaldevice before saving it
254func (agent *LogicalDeviceAgent) updateLogicalDeviceFlowsWithoutLock(flows *ofp.Flows) error {
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400255 updateCtx := context.WithValue(context.Background(), model.RequestTimestamp, time.Now().UnixNano())
256 afterUpdate := agent.flowProxy.Update(updateCtx, "/", flows, false, "")
khenaidoo43c82122018-11-22 18:38:28 -0500257 if afterUpdate == nil {
258 return status.Errorf(codes.Internal, "failed-updating-logical-device-flows:%s", agent.logicalDeviceId)
259 }
khenaidoo43c82122018-11-22 18:38:28 -0500260 return nil
261}
262
263//updateLogicalDeviceWithoutLock updates the model with the logical device. It clones the logicaldevice before saving it
264func (agent *LogicalDeviceAgent) updateLogicalDeviceFlowGroupsWithoutLock(flowGroups *ofp.FlowGroups) error {
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400265 updateCtx := context.WithValue(context.Background(), model.RequestTimestamp, time.Now().UnixNano())
266 afterUpdate := agent.groupProxy.Update(updateCtx, "/", flowGroups, false, "")
khenaidoo43c82122018-11-22 18:38:28 -0500267 if afterUpdate == nil {
268 return status.Errorf(codes.Internal, "failed-updating-logical-device-flow-groups:%s", agent.logicalDeviceId)
269 }
khenaidoo43c82122018-11-22 18:38:28 -0500270 return nil
271}
272
khenaidoo4d4802d2018-10-04 21:59:49 -0400273// getLogicalDeviceWithoutLock retrieves a logical device from the model without locking it. This is used only by
274// functions that have already acquired the logical device lock to the model
khenaidoo92e62c52018-10-03 14:02:54 -0400275func (agent *LogicalDeviceAgent) getLogicalDeviceWithoutLock() (*voltha.LogicalDevice, error) {
276 log.Debug("getLogicalDeviceWithoutLock")
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400277 logicalDevice := agent.clusterDataProxy.Get(context.Background(), "/logical_devices/"+agent.logicalDeviceId, 0, false, "")
khenaidoo92e62c52018-10-03 14:02:54 -0400278 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
khenaidoo1ce37ad2019-03-24 22:07:24 -0400279 //log.Debug("getLogicalDeviceWithoutLock", log.Fields{"ldevice": lDevice})
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500280 return lDevice, nil
khenaidoo92e62c52018-10-03 14:02:54 -0400281 }
282 return nil, status.Errorf(codes.NotFound, "logical_device-%s", agent.logicalDeviceId)
283}
284
khenaidoo2c6a0992019-04-29 13:46:56 -0400285func (agent *LogicalDeviceAgent) updateLogicalPort(device *voltha.Device, port *voltha.Port) error {
286 log.Debugw("updateLogicalPort", log.Fields{"deviceId": device.Id, "port": port})
287 var err error
288 if port.Type == voltha.Port_ETHERNET_NNI {
289 if _, err = agent.addNNILogicalPort(device, port); err != nil {
290 return err
291 }
292 agent.addLogicalPortToMap(port.PortNo, true)
293 } else if port.Type == voltha.Port_ETHERNET_UNI {
294 if _, err = agent.addUNILogicalPort(device, port); err != nil {
295 return err
296 }
297 agent.addLogicalPortToMap(port.PortNo, false)
298 } else {
299 // Update the device graph to ensure all routes on the logical device have been calculated
300 if err = agent.updateRoutes(device, port); err != nil {
301 log.Errorw("failed-to-update-routes", log.Fields{"deviceId": device.Id, "port": port, "error": err})
302 return err
303 }
304 }
305 return nil
306}
307
khenaidoo910204f2019-04-08 17:56:40 -0400308func (agent *LogicalDeviceAgent) addLogicalPort(device *voltha.Device, port *voltha.Port) error {
khenaidoo8f474192019-04-03 17:20:44 -0400309 log.Debugw("addLogicalPort", log.Fields{"deviceId": device.Id, "port": port})
khenaidoo8f474192019-04-03 17:20:44 -0400310 var err error
khenaidoofc1314d2019-03-14 09:34:21 -0400311 if port.Type == voltha.Port_ETHERNET_NNI {
khenaidoo910204f2019-04-08 17:56:40 -0400312 if _, err = agent.addNNILogicalPort(device, port); err != nil {
khenaidoofc1314d2019-03-14 09:34:21 -0400313 return err
314 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400315 agent.addLogicalPortToMap(port.PortNo, true)
khenaidoofc1314d2019-03-14 09:34:21 -0400316 } else if port.Type == voltha.Port_ETHERNET_UNI {
khenaidoo910204f2019-04-08 17:56:40 -0400317 if _, err = agent.addUNILogicalPort(device, port); err != nil {
khenaidoofc1314d2019-03-14 09:34:21 -0400318 return err
319 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400320 agent.addLogicalPortToMap(port.PortNo, false)
khenaidoofc1314d2019-03-14 09:34:21 -0400321 } else {
322 log.Debugw("invalid-port-type", log.Fields{"deviceId": device.Id, "port": port})
323 return nil
324 }
khenaidoofc1314d2019-03-14 09:34:21 -0400325 return nil
326}
327
khenaidoo3d3b8c22019-05-22 18:10:39 -0400328// setupLogicalPorts is invoked once the logical device has been created and is ready to get ports
329// added to it. While the logical device was being created we could have received requests to add
330// NNI and UNI ports which were discarded. Now is the time to add them if needed
331func (agent *LogicalDeviceAgent) setupLogicalPorts(ctx context.Context) error {
332 log.Infow("setupLogicalPorts", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
333 // First add any NNI ports which could have been missing
334 if err := agent.setupNNILogicalPorts(nil, agent.rootDeviceId); err != nil {
335 log.Errorw("error-setting-up-NNI-ports", log.Fields{"error": err, "deviceId": agent.rootDeviceId})
336 return err
337 }
338
339 // Now, set up the UNI ports if needed.
340 if children, err := agent.deviceMgr.getAllChildDevices(agent.rootDeviceId); err != nil {
341 log.Errorw("error-getting-child-devices", log.Fields{"error": err, "deviceId": agent.rootDeviceId})
342 return err
343 } else {
344 chnlsList := make([]chan interface{}, 0)
345 for _, child := range children.Items {
346 ch := make(chan interface{})
347 chnlsList = append(chnlsList, ch)
348 go func(device *voltha.Device, ch chan interface{}) {
349 if err = agent.setupUNILogicalPorts(nil, device); err != nil {
350 log.Error("setting-up-UNI-ports-failed", log.Fields{"deviceID": device.Id})
351 ch <- status.Errorf(codes.Internal, "UNI-ports-setup-failed: %s", device.Id)
352 }
353 ch <- nil
354 }(child, ch)
355 }
356 // Wait for completion
357 if res := fu.WaitForNilOrErrorResponses(agent.defaultTimeout, chnlsList...); res != nil {
358 return status.Errorf(codes.Aborted, "errors-%s", res)
359 }
360 }
361 return nil
362}
363
khenaidoofc1314d2019-03-14 09:34:21 -0400364// setupNNILogicalPorts creates an NNI port on the logical device that represents an NNI interface on a root device
365func (agent *LogicalDeviceAgent) setupNNILogicalPorts(ctx context.Context, deviceId string) error {
366 log.Infow("setupNNILogicalPorts-start", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoob9203542018-09-17 22:56:37 -0400367 // Build the logical device based on information retrieved from the device adapter
khenaidoofc1314d2019-03-14 09:34:21 -0400368 var err error
369
370 var device *voltha.Device
371 if device, err = agent.deviceMgr.GetDevice(deviceId); err != nil {
khenaidoo2c6a0992019-04-29 13:46:56 -0400372 log.Errorw("error-retrieving-device", log.Fields{"error": err, "deviceId": deviceId})
khenaidoofc1314d2019-03-14 09:34:21 -0400373 return err
374 }
375
376 //Get UNI port number
khenaidoofc1314d2019-03-14 09:34:21 -0400377 for _, port := range device.Ports {
378 if port.Type == voltha.Port_ETHERNET_NNI {
khenaidoo910204f2019-04-08 17:56:40 -0400379 if _, err = agent.addNNILogicalPort(device, port); err != nil {
khenaidoofc1314d2019-03-14 09:34:21 -0400380 log.Errorw("error-adding-UNI-port", log.Fields{"error": err})
khenaidoofc1314d2019-03-14 09:34:21 -0400381 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400382 agent.addLogicalPortToMap(port.PortNo, true)
khenaidoofc1314d2019-03-14 09:34:21 -0400383 }
384 }
khenaidoofc1314d2019-03-14 09:34:21 -0400385 return err
386}
387
khenaidoo3ab34882019-05-02 21:33:30 -0400388// updatePortsState updates the ports state related to the device
389func (agent *LogicalDeviceAgent) updatePortsState(device *voltha.Device, state voltha.AdminState_AdminState) error {
390 log.Infow("updatePortsState-start", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
391 agent.lockLogicalDevice.Lock()
392 defer agent.lockLogicalDevice.Unlock()
393 // Get the latest logical device info
394 if ld, err := agent.getLogicalDeviceWithoutLock(); err != nil {
395 log.Warnw("logical-device-unknown", log.Fields{"ldeviceId": agent.logicalDeviceId, "error": err})
396 return err
397 } else {
398 cloned := (proto.Clone(ld)).(*voltha.LogicalDevice)
399 for _, lport := range cloned.Ports {
400 if lport.DeviceId == device.Id {
401 switch state {
402 case voltha.AdminState_ENABLED:
403 lport.OfpPort.Config = lport.OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
khenaidoo0a822f92019-05-08 15:15:57 -0400404 lport.OfpPort.State = uint32(ofp.OfpPortState_OFPPS_LIVE)
khenaidoo3ab34882019-05-02 21:33:30 -0400405 case voltha.AdminState_DISABLED:
406 lport.OfpPort.Config = lport.OfpPort.Config | uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
khenaidoo0a822f92019-05-08 15:15:57 -0400407 lport.OfpPort.State = uint32(ofp.OfpPortState_OFPPS_LINK_DOWN)
khenaidoo3ab34882019-05-02 21:33:30 -0400408 default:
409 log.Warnw("unsupported-state-change", log.Fields{"deviceId": device.Id, "state": state})
410 }
411 }
412 }
413 // Updating the logical device will trigger the poprt change events to be populated to the controller
414 if err := agent.updateLogicalDeviceWithoutLock(cloned); err != nil {
415 log.Warnw("logical-device-update-failed", log.Fields{"ldeviceId": agent.logicalDeviceId, "error": err})
416 return err
417 }
418 }
419 return nil
420}
421
khenaidoofc1314d2019-03-14 09:34:21 -0400422// setupUNILogicalPorts creates a UNI port on the logical device that represents a child UNI interface
423func (agent *LogicalDeviceAgent) setupUNILogicalPorts(ctx context.Context, childDevice *voltha.Device) error {
khenaidoo3d3b8c22019-05-22 18:10:39 -0400424 log.Infow("setupUNILogicalPort", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoofc1314d2019-03-14 09:34:21 -0400425 // Build the logical device based on information retrieved from the device adapter
khenaidoob9203542018-09-17 22:56:37 -0400426 var err error
khenaidoo59ef7be2019-06-21 12:40:28 -0400427 var added bool
khenaidoo19d7b632018-10-30 10:49:50 -0400428 //Get UNI port number
khenaidoo19d7b632018-10-30 10:49:50 -0400429 for _, port := range childDevice.Ports {
430 if port.Type == voltha.Port_ETHERNET_UNI {
khenaidoo59ef7be2019-06-21 12:40:28 -0400431 if added, err = agent.addUNILogicalPort(childDevice, port); err != nil {
khenaidoofc1314d2019-03-14 09:34:21 -0400432 log.Errorw("error-adding-UNI-port", log.Fields{"error": err})
khenaidoofc1314d2019-03-14 09:34:21 -0400433 }
khenaidoo59ef7be2019-06-21 12:40:28 -0400434 if added {
435 agent.addLogicalPortToMap(port.PortNo, false)
436 }
khenaidoo19d7b632018-10-30 10:49:50 -0400437 }
438 }
khenaidoofc1314d2019-03-14 09:34:21 -0400439 return err
khenaidoo92e62c52018-10-03 14:02:54 -0400440}
441
khenaidoo0a822f92019-05-08 15:15:57 -0400442// deleteAllLogicalPorts deletes all logical ports associated with this device
443func (agent *LogicalDeviceAgent) deleteAllLogicalPorts(device *voltha.Device) error {
444 log.Infow("updatePortsState-start", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
445 agent.lockLogicalDevice.Lock()
446 defer agent.lockLogicalDevice.Unlock()
447 // Get the latest logical device info
448 if ld, err := agent.getLogicalDeviceWithoutLock(); err != nil {
449 log.Warnw("logical-device-unknown", log.Fields{"ldeviceId": agent.logicalDeviceId, "error": err})
450 return err
451 } else {
452 cloned := (proto.Clone(ld)).(*voltha.LogicalDevice)
453 updateLogicalPorts := []*voltha.LogicalPort{}
454 for _, lport := range cloned.Ports {
455 if lport.DeviceId != device.Id {
456 updateLogicalPorts = append(updateLogicalPorts, lport)
457 }
458 }
459 if len(updateLogicalPorts) < len(cloned.Ports) {
460 cloned.Ports = updateLogicalPorts
461 // Updating the logical device will trigger the poprt change events to be populated to the controller
462 if err := agent.updateLogicalDeviceWithoutLock(cloned); err != nil {
463 log.Warnw("logical-device-update-failed", log.Fields{"ldeviceId": agent.logicalDeviceId, "error": err})
464 return err
465 }
466 } else {
467 log.Debugw("no-change-required", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
468 }
469 }
470 return nil
471}
472
khenaidoo92e62c52018-10-03 14:02:54 -0400473//updateLogicalDeviceWithoutLock updates the model with the logical device. It clones the logicaldevice before saving it
474func (agent *LogicalDeviceAgent) updateLogicalDeviceWithoutLock(logicalDevice *voltha.LogicalDevice) error {
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400475 updateCtx := context.WithValue(context.Background(), model.RequestTimestamp, time.Now().UnixNano())
476 afterUpdate := agent.clusterDataProxy.Update(updateCtx, "/logical_devices/"+agent.logicalDeviceId, logicalDevice, false, "")
khenaidoo92e62c52018-10-03 14:02:54 -0400477 if afterUpdate == nil {
478 return status.Errorf(codes.Internal, "failed-updating-logical-device:%s", agent.logicalDeviceId)
479 }
480 return nil
481}
482
khenaidoo19d7b632018-10-30 10:49:50 -0400483//updateFlowTable updates the flow table of that logical device
484func (agent *LogicalDeviceAgent) updateFlowTable(ctx context.Context, flow *ofp.OfpFlowMod) error {
485 log.Debug("updateFlowTable")
486 if flow == nil {
487 return nil
488 }
489 switch flow.GetCommand() {
490 case ofp.OfpFlowModCommand_OFPFC_ADD:
491 return agent.flowAdd(flow)
492 case ofp.OfpFlowModCommand_OFPFC_DELETE:
493 return agent.flowDelete(flow)
494 case ofp.OfpFlowModCommand_OFPFC_DELETE_STRICT:
495 return agent.flowDeleteStrict(flow)
496 case ofp.OfpFlowModCommand_OFPFC_MODIFY:
497 return agent.flowModify(flow)
498 case ofp.OfpFlowModCommand_OFPFC_MODIFY_STRICT:
499 return agent.flowModifyStrict(flow)
500 }
501 return status.Errorf(codes.Internal,
502 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceId, flow.GetCommand())
503}
504
505//updateGroupTable updates the group table of that logical device
506func (agent *LogicalDeviceAgent) updateGroupTable(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
507 log.Debug("updateGroupTable")
508 if groupMod == nil {
509 return nil
510 }
511 switch groupMod.GetCommand() {
512 case ofp.OfpGroupModCommand_OFPGC_ADD:
513 return agent.groupAdd(groupMod)
514 case ofp.OfpGroupModCommand_OFPGC_DELETE:
515 return agent.groupDelete(groupMod)
516 case ofp.OfpGroupModCommand_OFPGC_MODIFY:
517 return agent.groupModify(groupMod)
518 }
519 return status.Errorf(codes.Internal,
520 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceId, groupMod.GetCommand())
521}
522
khenaidoo19d7b632018-10-30 10:49:50 -0400523//flowAdd adds a flow to the flow table of that logical device
524func (agent *LogicalDeviceAgent) flowAdd(mod *ofp.OfpFlowMod) error {
525 log.Debug("flowAdd")
526 if mod == nil {
527 return nil
528 }
khenaidoo92e62c52018-10-03 14:02:54 -0400529 agent.lockLogicalDevice.Lock()
530 defer agent.lockLogicalDevice.Unlock()
khenaidoo19d7b632018-10-30 10:49:50 -0400531
532 var lDevice *voltha.LogicalDevice
533 var err error
534 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
535 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
536 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
537 }
538
539 var flows []*ofp.OfpFlowStats
540 if lDevice.Flows != nil && lDevice.Flows.Items != nil {
541 flows = lDevice.Flows.Items
542 }
543
khenaidoo2c6a0992019-04-29 13:46:56 -0400544 updatedFlows := make([]*ofp.OfpFlowStats, 0)
khenaidoo19d7b632018-10-30 10:49:50 -0400545 changed := false
546 checkOverlap := (mod.Flags & uint32(ofp.OfpFlowModFlags_OFPFF_CHECK_OVERLAP)) != 0
547 if checkOverlap {
548 if overlapped := fu.FindOverlappingFlows(flows, mod); len(overlapped) != 0 {
549 // TODO: should this error be notified other than being logged?
550 log.Warnw("overlapped-flows", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
551 } else {
552 // Add flow
khenaidoo68c930b2019-05-13 11:46:51 -0400553 flow := fu.FlowStatsEntryFromFlowModMessage(mod)
khenaidoo19d7b632018-10-30 10:49:50 -0400554 flows = append(flows, flow)
khenaidoo2c6a0992019-04-29 13:46:56 -0400555 updatedFlows = append(updatedFlows, flow)
khenaidoo19d7b632018-10-30 10:49:50 -0400556 changed = true
557 }
558 } else {
khenaidoo68c930b2019-05-13 11:46:51 -0400559 flow := fu.FlowStatsEntryFromFlowModMessage(mod)
khenaidoo19d7b632018-10-30 10:49:50 -0400560 idx := fu.FindFlows(flows, flow)
561 if idx >= 0 {
562 oldFlow := flows[idx]
563 if (mod.Flags & uint32(ofp.OfpFlowModFlags_OFPFF_RESET_COUNTS)) != 0 {
564 flow.ByteCount = oldFlow.ByteCount
565 flow.PacketCount = oldFlow.PacketCount
566 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400567 if !reflect.DeepEqual(oldFlow, flow) {
568 flows[idx] = flow
569 updatedFlows = append(updatedFlows, flow)
570 changed = true
571 }
khenaidoo19d7b632018-10-30 10:49:50 -0400572 } else {
573 flows = append(flows, flow)
khenaidoo2c6a0992019-04-29 13:46:56 -0400574 updatedFlows = append(updatedFlows, flow)
575 changed = true
khenaidoo19d7b632018-10-30 10:49:50 -0400576 }
khenaidoo19d7b632018-10-30 10:49:50 -0400577 }
578 if changed {
khenaidoo0458db62019-06-20 08:50:36 -0400579 deviceRules := agent.flowDecomposer.DecomposeRules(agent, ofp.Flows{Items: updatedFlows}, *lDevice.FlowGroups)
580 log.Debugw("rules", log.Fields{"rules": deviceRules.String()})
581
582 if err := agent.addDeviceFlowsAndGroups(deviceRules); err != nil {
583 log.Errorw("failure-updating-device-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "error": err})
khenaidoo2c6a0992019-04-29 13:46:56 -0400584 return err
585 }
586
khenaidoo19d7b632018-10-30 10:49:50 -0400587 // Update model
khenaidoo0458db62019-06-20 08:50:36 -0400588 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: flows}); err != nil {
khenaidoo2c6a0992019-04-29 13:46:56 -0400589 log.Errorw("db-flow-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400590 return err
591 }
592 }
khenaidoo19d7b632018-10-30 10:49:50 -0400593 return nil
594}
595
596//flowDelete deletes a flow from the flow table of that logical device
597func (agent *LogicalDeviceAgent) flowDelete(mod *ofp.OfpFlowMod) error {
598 log.Debug("flowDelete")
599 if mod == nil {
600 return nil
601 }
602 agent.lockLogicalDevice.Lock()
603 defer agent.lockLogicalDevice.Unlock()
604
605 var lDevice *voltha.LogicalDevice
606 var err error
607 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
608 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
609 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
610 }
611 flows := lDevice.Flows.Items
612
613 //build a list of what to keep vs what to delete
614 toKeep := make([]*ofp.OfpFlowStats, 0)
khenaidoo0458db62019-06-20 08:50:36 -0400615 toDelete := make([]*ofp.OfpFlowStats, 0)
khenaidoo19d7b632018-10-30 10:49:50 -0400616 for _, f := range flows {
khenaidoo0458db62019-06-20 08:50:36 -0400617 // Check whether the flow and the flowmod matches
618 if fu.FlowMatch(f, fu.FlowStatsEntryFromFlowModMessage(mod)) {
619 toDelete = append(toDelete, f)
620 continue
621 }
622 // Check wild card match
khenaidoo19d7b632018-10-30 10:49:50 -0400623 if !fu.FlowMatchesMod(f, mod) {
624 toKeep = append(toKeep, f)
khenaidoo0458db62019-06-20 08:50:36 -0400625 } else {
626 toDelete = append(toDelete, f)
khenaidoo19d7b632018-10-30 10:49:50 -0400627 }
628 }
629
khenaidoo0458db62019-06-20 08:50:36 -0400630 log.Debugw("flowDelete", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "toKeep": len(toKeep), "toDelete": toDelete})
631
khenaidoo19d7b632018-10-30 10:49:50 -0400632 //Update flows
khenaidoo0458db62019-06-20 08:50:36 -0400633 if len(toDelete) > 0 {
634 deviceRules := agent.flowDecomposer.DecomposeRules(agent, ofp.Flows{Items: toDelete}, ofp.FlowGroups{})
635 log.Debugw("rules", log.Fields{"rules": deviceRules.String()})
636
637 if err := agent.deleteDeviceFlowsAndGroups(deviceRules); err != nil {
638 log.Errorw("failure-updating-device-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "error": err})
639 return err
640 }
641
khenaidoo43c82122018-11-22 18:38:28 -0500642 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: toKeep}); err != nil {
643 log.Errorw("Cannot-update-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400644 return err
645 }
646 }
647
648 //TODO: send announcement on delete
649 return nil
650}
651
khenaidoo0458db62019-06-20 08:50:36 -0400652func (agent *LogicalDeviceAgent) addDeviceFlowsAndGroups(deviceRules *fu.DeviceRules) error {
653 log.Debugw("addDeviceFlowsAndGroups", log.Fields{"logicalDeviceID": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400654
khenaidoo0458db62019-06-20 08:50:36 -0400655 chnlsList := make([]chan interface{}, 0)
656 for deviceId, value := range deviceRules.GetRules() {
657 ch := make(chan interface{})
658 chnlsList = append(chnlsList, ch)
659 go func(deviceId string, flows []*ofp.OfpFlowStats, groups []*ofp.OfpGroupEntry) {
660 if err := agent.deviceMgr.addFlowsAndGroups(deviceId, flows, groups); err != nil {
661 log.Errorw("flow-add-failed", log.Fields{"deviceID": deviceId, "error": err})
662 ch <- status.Errorf(codes.Internal, "flow-add-failed: %s", deviceId)
663 }
664 ch <- nil
665 }(deviceId, value.ListFlows(), value.ListGroups())
khenaidoo19d7b632018-10-30 10:49:50 -0400666 }
khenaidoo0458db62019-06-20 08:50:36 -0400667 // Wait for completion
668 if res := fu.WaitForNilOrErrorResponses(agent.defaultTimeout, chnlsList...); res != nil {
669 return status.Errorf(codes.Aborted, "errors-%s", res)
khenaidoo19d7b632018-10-30 10:49:50 -0400670 }
khenaidoo0458db62019-06-20 08:50:36 -0400671 return nil
672}
khenaidoo19d7b632018-10-30 10:49:50 -0400673
khenaidoo0458db62019-06-20 08:50:36 -0400674func (agent *LogicalDeviceAgent) deleteDeviceFlowsAndGroups(deviceRules *fu.DeviceRules) error {
675 log.Debugw("deleteDeviceFlowsAndGroups", log.Fields{"logicalDeviceID": agent.logicalDeviceId})
676
677 chnlsList := make([]chan interface{}, 0)
678 for deviceId, value := range deviceRules.GetRules() {
679 ch := make(chan interface{})
680 chnlsList = append(chnlsList, ch)
681 go func(deviceId string, flows []*ofp.OfpFlowStats, groups []*ofp.OfpGroupEntry) {
682 if err := agent.deviceMgr.deleteFlowsAndGroups(deviceId, flows, groups); err != nil {
683 log.Error("flow-delete-failed", log.Fields{"deviceID": deviceId, "error": err})
684 ch <- status.Errorf(codes.Internal, "flow-delete-failed: %s", deviceId)
685 }
686 ch <- nil
687 }(deviceId, value.ListFlows(), value.ListGroups())
688 }
689 // Wait for completion
690 if res := fu.WaitForNilOrErrorResponses(agent.defaultTimeout, chnlsList...); res != nil {
691 return status.Errorf(codes.Aborted, "errors-%s", res)
692 }
693 return nil
694}
695
696func (agent *LogicalDeviceAgent) updateDeviceFlowsAndGroups(deviceRules *fu.DeviceRules) error {
697 log.Debugw("updateDeviceFlowsAndGroups", log.Fields{"logicalDeviceID": agent.logicalDeviceId})
698
699 chnlsList := make([]chan interface{}, 0)
700 for deviceId, value := range deviceRules.GetRules() {
701 ch := make(chan interface{})
702 chnlsList = append(chnlsList, ch)
703 go func(deviceId string, flows []*ofp.OfpFlowStats, groups []*ofp.OfpGroupEntry) {
704 if err := agent.deviceMgr.updateFlowsAndGroups(deviceId, flows, groups); err != nil {
705 log.Error("flow-update-failed", log.Fields{"deviceID": deviceId, "error": err})
706 ch <- status.Errorf(codes.Internal, "flow-update-failed: %s", deviceId)
707 }
708 ch <- nil
709 }(deviceId, value.ListFlows(), value.ListGroups())
710 }
711 // Wait for completion
712 if res := fu.WaitForNilOrErrorResponses(agent.defaultTimeout, chnlsList...); res != nil {
713 return status.Errorf(codes.Aborted, "errors-%s", res)
khenaidoo19d7b632018-10-30 10:49:50 -0400714 }
715 return nil
716}
717
718//flowDeleteStrict deletes a flow from the flow table of that logical device
719func (agent *LogicalDeviceAgent) flowDeleteStrict(mod *ofp.OfpFlowMod) error {
720 log.Debug("flowDeleteStrict")
721 if mod == nil {
722 return nil
723 }
724 agent.lockLogicalDevice.Lock()
725 defer agent.lockLogicalDevice.Unlock()
726
727 var lDevice *voltha.LogicalDevice
728 var err error
729 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
730 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
731 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
732 }
733 flows := lDevice.Flows.Items
734 changed := false
khenaidoo68c930b2019-05-13 11:46:51 -0400735 flow := fu.FlowStatsEntryFromFlowModMessage(mod)
khenaidoo19d7b632018-10-30 10:49:50 -0400736 idx := fu.FindFlows(flows, flow)
737 if idx >= 0 {
738 flows = append(flows[:idx], flows[idx+1:]...)
739 changed = true
740 } else {
741 return errors.New(fmt.Sprintf("Cannot delete flow - %s", flow))
742 }
743
744 if changed {
khenaidoo0458db62019-06-20 08:50:36 -0400745 deviceRules := agent.flowDecomposer.DecomposeRules(agent, ofp.Flows{Items: []*ofp.OfpFlowStats{flow}}, ofp.FlowGroups{})
746 log.Debugw("rules", log.Fields{"rules": deviceRules.String()})
747
748 if err := agent.deleteDeviceFlowsAndGroups(deviceRules); err != nil {
749 log.Errorw("failure-deleting-device-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "error": err})
750 return err
751 }
752
khenaidoo43c82122018-11-22 18:38:28 -0500753 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: flows}); err != nil {
khenaidoo0458db62019-06-20 08:50:36 -0400754 log.Errorw("Cannot-update-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400755 return err
756 }
757 }
khenaidoo19d7b632018-10-30 10:49:50 -0400758 return nil
759}
760
761//flowModify modifies a flow from the flow table of that logical device
762func (agent *LogicalDeviceAgent) flowModify(mod *ofp.OfpFlowMod) error {
763 return errors.New("flowModify not implemented")
764}
765
766//flowModifyStrict deletes a flow from the flow table of that logical device
767func (agent *LogicalDeviceAgent) flowModifyStrict(mod *ofp.OfpFlowMod) error {
768 return errors.New("flowModifyStrict not implemented")
769}
770
771func (agent *LogicalDeviceAgent) groupAdd(groupMod *ofp.OfpGroupMod) error {
772 log.Debug("groupAdd")
773 if groupMod == nil {
774 return nil
775 }
776 agent.lockLogicalDevice.Lock()
777 defer agent.lockLogicalDevice.Unlock()
778
779 var lDevice *voltha.LogicalDevice
780 var err error
781 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
782 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
783 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
784 }
785 groups := lDevice.FlowGroups.Items
khenaidoo19d7b632018-10-30 10:49:50 -0400786 if fu.FindGroup(groups, groupMod.GroupId) == -1 {
khenaidoo68c930b2019-05-13 11:46:51 -0400787 groups = append(groups, fu.GroupEntryFromGroupMod(groupMod))
khenaidoo0458db62019-06-20 08:50:36 -0400788
789 deviceRules := agent.flowDecomposer.DecomposeRules(agent, *lDevice.Flows, ofp.FlowGroups{Items: groups})
790 log.Debugw("rules", log.Fields{"rules": deviceRules.String()})
791
792 if err := agent.addDeviceFlowsAndGroups(deviceRules); err != nil {
793 log.Errorw("failure-updating-device-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "error": err})
794 return err
795 }
796
khenaidoo43c82122018-11-22 18:38:28 -0500797 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(&ofp.FlowGroups{Items: groups}); err != nil {
798 log.Errorw("Cannot-update-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400799 return err
800 }
801 } else {
802 return errors.New(fmt.Sprintf("Groups %d already present", groupMod.GroupId))
803 }
khenaidoo19d7b632018-10-30 10:49:50 -0400804 return nil
805}
806
807func (agent *LogicalDeviceAgent) groupDelete(groupMod *ofp.OfpGroupMod) error {
808 log.Debug("groupDelete")
809 if groupMod == nil {
810 return nil
811 }
812 agent.lockLogicalDevice.Lock()
813 defer agent.lockLogicalDevice.Unlock()
814
815 var lDevice *voltha.LogicalDevice
816 var err error
817 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
818 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
819 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
820 }
821 groups := lDevice.FlowGroups.Items
822 flows := lDevice.Flows.Items
823 groupsChanged := false
824 flowsChanged := false
825 groupId := groupMod.GroupId
826 if groupId == uint32(ofp.OfpGroup_OFPG_ALL) {
827 //TODO we must delete all flows that point to this group and
828 //signal controller as requested by flow's flag
829 groups = []*ofp.OfpGroupEntry{}
830 groupsChanged = true
831 } else {
832 if idx := fu.FindGroup(groups, groupId); idx == -1 {
833 return nil // Valid case
834 } else {
835 flowsChanged, flows = fu.FlowsDeleteByGroupId(flows, groupId)
836 groups = append(groups[:idx], groups[idx+1:]...)
837 groupsChanged = true
838 }
839 }
khenaidoo0458db62019-06-20 08:50:36 -0400840 if flowsChanged || groupsChanged {
841 deviceRules := agent.flowDecomposer.DecomposeRules(agent, ofp.Flows{Items: flows}, ofp.FlowGroups{Items: groups})
842 log.Debugw("rules", log.Fields{"rules": deviceRules.String()})
843
844 if err := agent.updateDeviceFlowsAndGroups(deviceRules); err != nil {
845 log.Errorw("failure-updating-device-flows-groups", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "error": err})
846 return err
847 }
848 }
849
khenaidoo43c82122018-11-22 18:38:28 -0500850 if groupsChanged {
851 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(&ofp.FlowGroups{Items: groups}); err != nil {
852 log.Errorw("Cannot-update-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400853 return err
854 }
855 }
khenaidoo43c82122018-11-22 18:38:28 -0500856 if flowsChanged {
857 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: flows}); err != nil {
858 log.Errorw("Cannot-update-flow", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
859 return err
860 }
861 }
khenaidoo19d7b632018-10-30 10:49:50 -0400862 return nil
863}
864
865func (agent *LogicalDeviceAgent) groupModify(groupMod *ofp.OfpGroupMod) error {
866 log.Debug("groupModify")
867 if groupMod == nil {
868 return nil
869 }
870 agent.lockLogicalDevice.Lock()
871 defer agent.lockLogicalDevice.Unlock()
872
873 var lDevice *voltha.LogicalDevice
874 var err error
875 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
876 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
877 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
878 }
879 groups := lDevice.FlowGroups.Items
880 groupsChanged := false
881 groupId := groupMod.GroupId
882 if idx := fu.FindGroup(groups, groupId); idx == -1 {
khenaidooca301322019-01-09 23:06:32 -0500883 return errors.New(fmt.Sprintf("group-absent:%d", groupId))
khenaidoo19d7b632018-10-30 10:49:50 -0400884 } else {
885 //replace existing group entry with new group definition
khenaidoo68c930b2019-05-13 11:46:51 -0400886 groupEntry := fu.GroupEntryFromGroupMod(groupMod)
khenaidoo19d7b632018-10-30 10:49:50 -0400887 groups[idx] = groupEntry
888 groupsChanged = true
889 }
890 if groupsChanged {
khenaidoo0458db62019-06-20 08:50:36 -0400891 deviceRules := agent.flowDecomposer.DecomposeRules(agent, ofp.Flows{Items: lDevice.Flows.Items}, ofp.FlowGroups{Items: groups})
892 log.Debugw("rules", log.Fields{"rules": deviceRules.String()})
893
894 if err := agent.updateDeviceFlowsAndGroups(deviceRules); err != nil {
895 log.Errorw("failure-updating-device-flows-groups", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "error": err})
896 return err
897 }
898
khenaidoo43c82122018-11-22 18:38:28 -0500899 //lDevice.FlowGroups.Items = groups
900 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(&ofp.FlowGroups{Items: groups}); err != nil {
khenaidoo19d7b632018-10-30 10:49:50 -0400901 log.Errorw("Cannot-update-logical-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
902 return err
903 }
904 }
905 return nil
906}
907
908// deleteLogicalPort removes the logical port
909func (agent *LogicalDeviceAgent) deleteLogicalPort(lPort *voltha.LogicalPort) error {
910 agent.lockLogicalDevice.Lock()
911 defer agent.lockLogicalDevice.Unlock()
912
khenaidoo92e62c52018-10-03 14:02:54 -0400913 // Get the most up to date logical device
914 var logicaldevice *voltha.LogicalDevice
915 if logicaldevice, _ = agent.getLogicalDeviceWithoutLock(); logicaldevice == nil {
khenaidoo19d7b632018-10-30 10:49:50 -0400916 log.Debugw("no-logical-device", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "logicalPortId": lPort.Id})
khenaidoob9203542018-09-17 22:56:37 -0400917 return nil
918 }
khenaidoo92e62c52018-10-03 14:02:54 -0400919 index := -1
920 for i, logicalPort := range logicaldevice.Ports {
khenaidoo19d7b632018-10-30 10:49:50 -0400921 if logicalPort.Id == lPort.Id {
khenaidoo92e62c52018-10-03 14:02:54 -0400922 index = i
923 break
924 }
925 }
926 if index >= 0 {
927 copy(logicaldevice.Ports[index:], logicaldevice.Ports[index+1:])
928 logicaldevice.Ports[len(logicaldevice.Ports)-1] = nil
929 logicaldevice.Ports = logicaldevice.Ports[:len(logicaldevice.Ports)-1]
930 log.Debugw("logical-port-deleted", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo0a822f92019-05-08 15:15:57 -0400931 if err := agent.updateLogicalDeviceWithoutLock(logicaldevice); err != nil {
932 log.Errorw("logical-device-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
933 return err
934 }
935 // Reset the logical device graph
khenaidoo3d3b8c22019-05-22 18:10:39 -0400936 go agent.generateDeviceGraph()
khenaidoo92e62c52018-10-03 14:02:54 -0400937 }
938 return nil
khenaidoob9203542018-09-17 22:56:37 -0400939}
940
khenaidoo0a822f92019-05-08 15:15:57 -0400941// deleteLogicalPorts removes the logical ports associated with that deviceId
942func (agent *LogicalDeviceAgent) deleteLogicalPorts(deviceId string) error {
943 agent.lockLogicalDevice.Lock()
944 defer agent.lockLogicalDevice.Unlock()
945
946 // Get the most up to date logical device
947 var logicaldevice *voltha.LogicalDevice
948 if logicaldevice, _ = agent.getLogicalDeviceWithoutLock(); logicaldevice == nil {
949 log.Debugw("no-logical-device", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
950 return nil
951 }
952 updatedLPorts := []*voltha.LogicalPort{}
953 for _, logicalPort := range logicaldevice.Ports {
954 if logicalPort.DeviceId != deviceId {
955 updatedLPorts = append(updatedLPorts, logicalPort)
956 }
957 }
958 logicaldevice.Ports = updatedLPorts
959 log.Debugw("updated-logical-ports", log.Fields{"ports": updatedLPorts})
960 if err := agent.updateLogicalDeviceWithoutLock(logicaldevice); err != nil {
961 log.Errorw("logical-device-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
962 return err
963 }
964 // Reset the logical device graph
khenaidoo3d3b8c22019-05-22 18:10:39 -0400965 go agent.generateDeviceGraph()
khenaidoo0a822f92019-05-08 15:15:57 -0400966
967 return nil
968}
969
khenaidoo19d7b632018-10-30 10:49:50 -0400970// enableLogicalPort enables the logical port
971func (agent *LogicalDeviceAgent) enableLogicalPort(lPort *voltha.LogicalPort) error {
972 agent.lockLogicalDevice.Lock()
973 defer agent.lockLogicalDevice.Unlock()
974
975 // Get the most up to date logical device
976 var logicaldevice *voltha.LogicalDevice
977 if logicaldevice, _ = agent.getLogicalDeviceWithoutLock(); logicaldevice == nil {
978 log.Debugw("no-logical-device", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "logicalPortId": lPort.Id})
979 return nil
980 }
981 index := -1
982 for i, logicalPort := range logicaldevice.Ports {
983 if logicalPort.Id == lPort.Id {
984 index = i
985 break
986 }
987 }
988 if index >= 0 {
989 logicaldevice.Ports[index].OfpPort.Config = logicaldevice.Ports[index].OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
990 return agent.updateLogicalDeviceWithoutLock(logicaldevice)
991 }
992 //TODO: Trigger subsequent actions on the device
993 return nil
994}
995
996// disableLogicalPort disabled the logical port
997func (agent *LogicalDeviceAgent) disableLogicalPort(lPort *voltha.LogicalPort) error {
998 agent.lockLogicalDevice.Lock()
999 defer agent.lockLogicalDevice.Unlock()
1000
1001 // Get the most up to date logical device
1002 var logicaldevice *voltha.LogicalDevice
1003 if logicaldevice, _ = agent.getLogicalDeviceWithoutLock(); logicaldevice == nil {
1004 log.Debugw("no-logical-device", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "logicalPortId": lPort.Id})
1005 return nil
1006 }
1007 index := -1
1008 for i, logicalPort := range logicaldevice.Ports {
1009 if logicalPort.Id == lPort.Id {
1010 index = i
1011 break
1012 }
1013 }
1014 if index >= 0 {
1015 logicaldevice.Ports[index].OfpPort.Config = (logicaldevice.Ports[index].OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)) | uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
1016 return agent.updateLogicalDeviceWithoutLock(logicaldevice)
1017 }
1018 //TODO: Trigger subsequent actions on the device
1019 return nil
1020}
1021
khenaidoo89b0e942018-10-21 21:11:33 -04001022func (agent *LogicalDeviceAgent) getPreCalculatedRoute(ingress, egress uint32) []graph.RouteHop {
khenaidoo19d7b632018-10-30 10:49:50 -04001023 log.Debugw("ROUTE", log.Fields{"len": len(agent.deviceGraph.Routes)})
khenaidoo89b0e942018-10-21 21:11:33 -04001024 for routeLink, route := range agent.deviceGraph.Routes {
khenaidoo19d7b632018-10-30 10:49:50 -04001025 log.Debugw("ROUTELINKS", log.Fields{"ingress": ingress, "egress": egress, "routelink": routeLink})
khenaidoo89b0e942018-10-21 21:11:33 -04001026 if ingress == routeLink.Ingress && egress == routeLink.Egress {
1027 return route
1028 }
1029 }
1030 log.Warnw("no-route", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "ingress": ingress, "egress": egress})
1031 return nil
1032}
1033
khenaidoo19d7b632018-10-30 10:49:50 -04001034func (agent *LogicalDeviceAgent) GetRoute(ingressPortNo uint32, egressPortNo uint32) []graph.RouteHop {
khenaidoo89b0e942018-10-21 21:11:33 -04001035 log.Debugw("getting-route", log.Fields{"ingress-port": ingressPortNo, "egress-port": egressPortNo})
khenaidoo89b0e942018-10-21 21:11:33 -04001036 routes := make([]graph.RouteHop, 0)
khenaidoo2c6a0992019-04-29 13:46:56 -04001037
khenaidoo19d7b632018-10-30 10:49:50 -04001038 // Note: A port value of 0 is equivalent to a nil port
1039
khenaidoo89b0e942018-10-21 21:11:33 -04001040 // Consider different possibilities
khenaidoo19d7b632018-10-30 10:49:50 -04001041 if egressPortNo != 0 && ((egressPortNo & 0x7fffffff) == uint32(ofp.OfpPortNo_OFPP_CONTROLLER)) {
khenaidoo2c6a0992019-04-29 13:46:56 -04001042 log.Debugw("controller-flow", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "logicalPortsNo": agent.logicalPortsNo})
1043 if agent.isNNIPort(ingressPortNo) {
khenaidoo89b0e942018-10-21 21:11:33 -04001044 log.Debug("returning-half-route")
1045 //This is a trap on the NNI Port
khenaidoo8f474192019-04-03 17:20:44 -04001046 if len(agent.deviceGraph.Routes) == 0 {
1047 // If there are no routes set (usually when the logical device has only NNI port(s), then just return an
1048 // internal route
khenaidoo2c6a0992019-04-29 13:46:56 -04001049 hop := graph.RouteHop{DeviceID: agent.rootDeviceId, Ingress: ingressPortNo, Egress: egressPortNo}
khenaidoo8f474192019-04-03 17:20:44 -04001050 routes = append(routes, hop)
1051 routes = append(routes, hop)
1052 return routes
1053 }
khenaidoo89b0e942018-10-21 21:11:33 -04001054 //Return a 'half' route to make the flow decomposer logic happy
1055 for routeLink, route := range agent.deviceGraph.Routes {
khenaidoo2c6a0992019-04-29 13:46:56 -04001056 if agent.isNNIPort(routeLink.Egress) {
khenaidoo89b0e942018-10-21 21:11:33 -04001057 routes = append(routes, graph.RouteHop{}) // first hop is set to empty
1058 routes = append(routes, route[1])
1059 return routes
1060 }
1061 }
khenaidoo2c6a0992019-04-29 13:46:56 -04001062 log.Warnw("no-upstream-route", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "logicalPortsNo": agent.logicalPortsNo})
khenaidoo89b0e942018-10-21 21:11:33 -04001063 return nil
1064 }
1065 //treat it as if the output port is the first NNI of the OLT
khenaidoo2c6a0992019-04-29 13:46:56 -04001066 var err error
1067 if egressPortNo, err = agent.getFirstNNIPort(); err != nil {
1068 log.Warnw("no-nni-port", log.Fields{"error": err})
1069 return nil
1070 }
khenaidoo89b0e942018-10-21 21:11:33 -04001071 }
1072 //If ingress port is not specified (nil), it may be a wildcarded
1073 //route if egress port is OFPP_CONTROLLER or a nni logical port,
1074 //in which case we need to create a half-route where only the egress
1075 //hop is filled, the first hop is nil
khenaidoo2c6a0992019-04-29 13:46:56 -04001076 if ingressPortNo == 0 && agent.isNNIPort(egressPortNo) {
khenaidoo89b0e942018-10-21 21:11:33 -04001077 // We can use the 2nd hop of any upstream route, so just find the first upstream:
1078 for routeLink, route := range agent.deviceGraph.Routes {
khenaidoo2c6a0992019-04-29 13:46:56 -04001079 if agent.isNNIPort(routeLink.Egress) {
khenaidoo89b0e942018-10-21 21:11:33 -04001080 routes = append(routes, graph.RouteHop{}) // first hop is set to empty
1081 routes = append(routes, route[1])
1082 return routes
1083 }
1084 }
khenaidoo2c6a0992019-04-29 13:46:56 -04001085 log.Warnw("no-upstream-route", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "logicalPortsNo": agent.logicalPortsNo})
khenaidoo89b0e942018-10-21 21:11:33 -04001086 return nil
1087 }
1088 //If egress port is not specified (nil), we can also can return a "half" route
khenaidoo19d7b632018-10-30 10:49:50 -04001089 if egressPortNo == 0 {
khenaidoo89b0e942018-10-21 21:11:33 -04001090 for routeLink, route := range agent.deviceGraph.Routes {
khenaidoo19d7b632018-10-30 10:49:50 -04001091 if routeLink.Ingress == ingressPortNo {
khenaidoo89b0e942018-10-21 21:11:33 -04001092 routes = append(routes, route[0])
1093 routes = append(routes, graph.RouteHop{})
1094 return routes
1095 }
1096 }
khenaidoo2c6a0992019-04-29 13:46:56 -04001097 log.Warnw("no-downstream-route", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "logicalPortsNo": agent.logicalPortsNo})
khenaidoo89b0e942018-10-21 21:11:33 -04001098 return nil
1099 }
khenaidoo89b0e942018-10-21 21:11:33 -04001100 // Return the pre-calculated route
khenaidoo19d7b632018-10-30 10:49:50 -04001101 return agent.getPreCalculatedRoute(ingressPortNo, egressPortNo)
khenaidoo89b0e942018-10-21 21:11:33 -04001102}
1103
khenaidoo3d3b8c22019-05-22 18:10:39 -04001104//GetWildcardInputPorts filters out the logical port number from the set of logical ports on the device and
1105//returns their port numbers. This function is invoked only during flow decomposition where the lock on the logical
1106//device is already held. Therefore it is safe to retrieve the logical device without lock.
khenaidoo89b0e942018-10-21 21:11:33 -04001107func (agent *LogicalDeviceAgent) GetWildcardInputPorts(excludePort ...uint32) []uint32 {
1108 lPorts := make([]uint32, 0)
1109 var exclPort uint32
1110 if len(excludePort) == 1 {
1111 exclPort = excludePort[0]
1112 }
khenaidoo3d3b8c22019-05-22 18:10:39 -04001113 if lDevice, _ := agent.getLogicalDeviceWithoutLock(); lDevice != nil {
khenaidoo89b0e942018-10-21 21:11:33 -04001114 for _, port := range lDevice.Ports {
1115 if port.OfpPort.PortNo != exclPort {
1116 lPorts = append(lPorts, port.OfpPort.PortNo)
1117 }
1118 }
1119 }
1120 return lPorts
1121}
khenaidoo19d7b632018-10-30 10:49:50 -04001122
1123func (agent *LogicalDeviceAgent) GetDeviceGraph() *graph.DeviceGraph {
1124 return agent.deviceGraph
1125}
1126
khenaidoo3306c992019-05-24 16:57:35 -04001127//updateRoutes rebuilds the device graph if not done already
khenaidoo2c6a0992019-04-29 13:46:56 -04001128func (agent *LogicalDeviceAgent) updateRoutes(device *voltha.Device, port *voltha.Port) error {
1129 log.Debugf("updateRoutes", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "device": device.Id, "port": port})
khenaidoo910204f2019-04-08 17:56:40 -04001130 agent.lockLogicalDevice.Lock()
1131 defer agent.lockLogicalDevice.Unlock()
khenaidoo19d7b632018-10-30 10:49:50 -04001132 if agent.deviceGraph == nil {
khenaidoo910204f2019-04-08 17:56:40 -04001133 agent.deviceGraph = graph.NewDeviceGraph(agent.logicalDeviceId, agent.deviceMgr.GetDevice)
khenaidoo2c6a0992019-04-29 13:46:56 -04001134 }
1135 // Get all the logical ports on that logical device
1136 if lDevice, err := agent.getLogicalDeviceWithoutLock(); err != nil {
manikkaraj k259a6f72019-05-06 09:55:44 -04001137 log.Errorw("unknown-logical-device", log.Fields{"error": err, "logicalDeviceId": agent.logicalDeviceId})
khenaidoo2c6a0992019-04-29 13:46:56 -04001138 return err
1139 } else {
1140 //TODO: Find a better way to refresh only missing routes
1141 agent.deviceGraph.ComputeRoutes(lDevice.Ports)
1142 }
khenaidoo2c6a0992019-04-29 13:46:56 -04001143 agent.deviceGraph.Print()
1144 return nil
khenaidoo19d7b632018-10-30 10:49:50 -04001145}
1146
khenaidoo2c6a0992019-04-29 13:46:56 -04001147//updateDeviceGraph updates the device graph if not done already and setup the default rules as well
khenaidoo910204f2019-04-08 17:56:40 -04001148func (agent *LogicalDeviceAgent) updateDeviceGraph(lp *voltha.LogicalPort) {
khenaidoo2c6a0992019-04-29 13:46:56 -04001149 log.Debugf("updateDeviceGraph", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
1150 agent.lockLogicalDevice.Lock()
1151 defer agent.lockLogicalDevice.Unlock()
khenaidoo910204f2019-04-08 17:56:40 -04001152 if agent.deviceGraph == nil {
1153 agent.deviceGraph = graph.NewDeviceGraph(agent.logicalDeviceId, agent.deviceMgr.GetDevice)
1154 }
1155 agent.deviceGraph.AddPort(lp)
khenaidoo2c6a0992019-04-29 13:46:56 -04001156 agent.deviceGraph.Print()
khenaidoo19d7b632018-10-30 10:49:50 -04001157}
khenaidoofdbad6e2018-11-06 22:26:38 -05001158
khenaidoo3d3b8c22019-05-22 18:10:39 -04001159//generateDeviceGraph regenerates the device graph
1160func (agent *LogicalDeviceAgent) generateDeviceGraph() {
1161 log.Debugf("generateDeviceGraph", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo0a822f92019-05-08 15:15:57 -04001162 agent.lockLogicalDevice.Lock()
1163 defer agent.lockLogicalDevice.Unlock()
1164 // Get the latest logical device
1165 if ld, err := agent.getLogicalDeviceWithoutLock(); err != nil {
1166 log.Errorw("logical-device-not-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "error": err})
1167 } else {
khenaidoo3d3b8c22019-05-22 18:10:39 -04001168 log.Debugw("generating-graph", log.Fields{"lDeviceId": agent.logicalDeviceId, "deviceGraph": agent.deviceGraph, "lPorts": len(ld.Ports)})
1169 if agent.deviceGraph == nil {
1170 agent.deviceGraph = graph.NewDeviceGraph(agent.logicalDeviceId, agent.deviceMgr.GetDevice)
1171 }
khenaidoo0a822f92019-05-08 15:15:57 -04001172 agent.deviceGraph.ComputeRoutes(ld.Ports)
khenaidoo3d3b8c22019-05-22 18:10:39 -04001173 agent.deviceGraph.Print()
khenaidoo0a822f92019-05-08 15:15:57 -04001174 }
1175}
1176
khenaidoofc1314d2019-03-14 09:34:21 -04001177// portAdded is a callback invoked when a port is added to the logical device.
1178// TODO: To use when POST_ADD is fixed.
1179func (agent *LogicalDeviceAgent) portAdded(args ...interface{}) interface{} {
1180 log.Debugw("portAdded-callback", log.Fields{"argsLen": len(args)})
1181
1182 var port *voltha.LogicalPort
1183
1184 // Sanity check
1185 if args[0] != nil {
1186 log.Warnw("previous-data-not-nil", log.Fields{"args0": args[0]})
1187 }
1188 var ok bool
1189 if port, ok = args[1].(*voltha.LogicalPort); !ok {
1190 log.Errorw("invalid-args", log.Fields{"args1": args[1]})
1191 return nil
1192 }
1193
1194 // Set the proxy and callback for that port
1195 agent.portProxiesLock.Lock()
Stephane Barbarie40fd3b22019-04-23 21:50:47 -04001196 agent.portProxies[port.Id] = agent.clusterDataProxy.CreateProxy(
Stephane Barbarieef6650d2019-07-18 12:15:09 -04001197 context.Background(),
khenaidoofc1314d2019-03-14 09:34:21 -04001198 fmt.Sprintf("/logical_devices/%s/ports/%s", agent.logicalDeviceId, port.Id),
1199 false)
1200 agent.portProxies[port.Id].RegisterCallback(model.POST_UPDATE, agent.portUpdated)
1201 agent.portProxiesLock.Unlock()
1202
1203 // Send the port change event to the OF controller
1204 agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceId,
khenaidoo910204f2019-04-08 17:56:40 -04001205 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_ADD, Desc: port.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001206
1207 return nil
1208}
1209
1210// portRemoved is a callback invoked when a port is removed from the logical device.
1211// TODO: To use when POST_ADD is fixed.
1212func (agent *LogicalDeviceAgent) portRemoved(args ...interface{}) interface{} {
1213 log.Debugw("portRemoved-callback", log.Fields{"argsLen": len(args)})
1214
1215 var port *voltha.LogicalPort
1216
1217 // Sanity check
1218 if args[1] != nil {
1219 log.Warnw("data-not-nil", log.Fields{"args1": args[1]})
1220 }
1221 var ok bool
1222 if port, ok = args[0].(*voltha.LogicalPort); !ok {
1223 log.Errorw("invalid-args", log.Fields{"args0": args[0]})
1224 return nil
1225 }
1226
1227 // Remove the proxy and callback for that port
1228 agent.portProxiesLock.Lock()
1229 agent.portProxies[port.Id].UnregisterCallback(model.POST_UPDATE, agent.portUpdated)
1230 delete(agent.portProxies, port.Id)
1231 agent.portProxiesLock.Unlock()
1232
1233 // Send the port change event to the OF controller
1234 agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceId,
khenaidoo910204f2019-04-08 17:56:40 -04001235 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_DELETE, Desc: port.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001236
1237 return nil
1238}
1239
1240// 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 -04001241func diff(oldList, newList []*voltha.LogicalPort) (newPorts, changedPorts, deletedPorts []*voltha.LogicalPort) {
khenaidoofc1314d2019-03-14 09:34:21 -04001242 newPorts = make([]*voltha.LogicalPort, 0)
1243 changedPorts = make([]*voltha.LogicalPort, 0)
1244 deletedPorts = make([]*voltha.LogicalPort, 0)
1245 for _, o := range oldList {
1246 found := false
khenaidoofc1314d2019-03-14 09:34:21 -04001247 for _, n := range newList {
1248 if o.Id == n.Id {
khenaidoofc1314d2019-03-14 09:34:21 -04001249 found = true
1250 break
1251 }
1252 }
1253 if !found {
1254 deletedPorts = append(deletedPorts, o)
1255 }
khenaidoofc1314d2019-03-14 09:34:21 -04001256 }
1257 for _, n := range newList {
1258 found := false
khenaidoo2bc48282019-07-16 18:13:46 -04001259 changed := false
khenaidoofc1314d2019-03-14 09:34:21 -04001260 for _, o := range oldList {
1261 if o.Id == n.Id {
khenaidoo2bc48282019-07-16 18:13:46 -04001262 changed = !reflect.DeepEqual(o, n)
khenaidoofc1314d2019-03-14 09:34:21 -04001263 found = true
1264 break
1265 }
1266 }
1267 if !found {
1268 newPorts = append(newPorts, n)
1269 }
khenaidoo2bc48282019-07-16 18:13:46 -04001270 if changed {
1271 changedPorts = append(changedPorts, n)
1272 }
khenaidoofc1314d2019-03-14 09:34:21 -04001273 }
1274 return
1275}
1276
1277// portUpdated is invoked when a port is updated on the logical device. Until
1278// the POST_ADD notification is fixed, we will use the logical device to
1279// update that data.
1280func (agent *LogicalDeviceAgent) portUpdated(args ...interface{}) interface{} {
1281 log.Debugw("portUpdated-callback", log.Fields{"argsLen": len(args)})
1282
1283 var oldLD *voltha.LogicalDevice
1284 var newlD *voltha.LogicalDevice
1285
1286 var ok bool
1287 if oldLD, ok = args[0].(*voltha.LogicalDevice); !ok {
1288 log.Errorw("invalid-args", log.Fields{"args0": args[0]})
1289 return nil
1290 }
1291 if newlD, ok = args[1].(*voltha.LogicalDevice); !ok {
1292 log.Errorw("invalid-args", log.Fields{"args1": args[1]})
1293 return nil
1294 }
1295
1296 if reflect.DeepEqual(oldLD.Ports, newlD.Ports) {
1297 log.Debug("ports-have-not-changed")
1298 return nil
1299 }
1300
1301 // Get the difference between the two list
1302 newPorts, changedPorts, deletedPorts := diff(oldLD.Ports, newlD.Ports)
1303
1304 // Send the port change events to the OF controller
khenaidoo2c6a0992019-04-29 13:46:56 -04001305 for _, newP := range newPorts {
khenaidoofc1314d2019-03-14 09:34:21 -04001306 go agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceId,
khenaidoo2c6a0992019-04-29 13:46:56 -04001307 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_ADD, Desc: newP.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001308 }
1309 for _, change := range changedPorts {
1310 go agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceId,
khenaidoo910204f2019-04-08 17:56:40 -04001311 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_MODIFY, Desc: change.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001312 }
1313 for _, del := range deletedPorts {
1314 go agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceId,
khenaidoo910204f2019-04-08 17:56:40 -04001315 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_DELETE, Desc: del.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001316 }
1317
1318 return nil
1319}
1320
khenaidoo8f474192019-04-03 17:20:44 -04001321// addNNILogicalPort adds an NNI port to the logical device. It returns a bool representing whether a port has been
1322// added and an eror in case a valid error is encountered. If the port was successfully added it will return
1323// (true, nil). If the device is not in the correct state it will return (false, nil) as this is a valid
1324// scenario. This also applies to the case where the port was already added.
khenaidoo910204f2019-04-08 17:56:40 -04001325func (agent *LogicalDeviceAgent) addNNILogicalPort(device *voltha.Device, port *voltha.Port) (bool, error) {
khenaidoo1ce37ad2019-03-24 22:07:24 -04001326 log.Debugw("addNNILogicalPort", log.Fields{"NNI": port})
khenaidoo8f474192019-04-03 17:20:44 -04001327 if device.AdminState != voltha.AdminState_ENABLED || device.OperStatus != voltha.OperStatus_ACTIVE {
1328 log.Infow("device-not-ready", log.Fields{"deviceId": device.Id, "admin": device.AdminState, "oper": device.OperStatus})
1329 return false, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001330 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001331 agent.lockLogicalDevice.RLock()
1332 if agent.portExist(device, port) {
1333 log.Debugw("port-already-exist", log.Fields{"port": port})
1334 agent.lockLogicalDevice.RUnlock()
khenaidoo8f474192019-04-03 17:20:44 -04001335 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001336 }
1337 agent.lockLogicalDevice.RUnlock()
1338
khenaidoofc1314d2019-03-14 09:34:21 -04001339 var portCap *ic.PortCapability
1340 var err error
1341 // First get the port capability
1342 if portCap, err = agent.deviceMgr.getPortCapability(nil, device.Id, port.PortNo); err != nil {
1343 log.Errorw("error-retrieving-port-capabilities", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001344 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001345 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001346
1347 agent.lockLogicalDevice.Lock()
1348 defer agent.lockLogicalDevice.Unlock()
1349 // Double check again if this port has been already added since the getPortCapability could have taken a long time
1350 if agent.portExist(device, port) {
1351 log.Debugw("port-already-exist", log.Fields{"port": port})
khenaidoo8f474192019-04-03 17:20:44 -04001352 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001353 }
1354
khenaidoofc1314d2019-03-14 09:34:21 -04001355 portCap.Port.RootPort = true
1356 lp := (proto.Clone(portCap.Port)).(*voltha.LogicalPort)
1357 lp.DeviceId = device.Id
1358 lp.Id = fmt.Sprintf("nni-%d", port.PortNo)
1359 lp.OfpPort.PortNo = port.PortNo
1360 lp.OfpPort.Name = lp.Id
1361 lp.DevicePortNo = port.PortNo
1362
khenaidoofc1314d2019-03-14 09:34:21 -04001363 var ld *voltha.LogicalDevice
1364 if ld, err = agent.getLogicalDeviceWithoutLock(); err != nil {
1365 log.Errorw("error-retrieving-logical-device", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001366 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001367 }
1368 cloned := (proto.Clone(ld)).(*voltha.LogicalDevice)
1369 if cloned.Ports == nil {
1370 cloned.Ports = make([]*voltha.LogicalPort, 0)
1371 }
1372 cloned.Ports = append(cloned.Ports, lp)
1373
1374 if err = agent.updateLogicalDeviceWithoutLock(cloned); err != nil {
1375 log.Errorw("error-updating-logical-device", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001376 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001377 }
khenaidoo910204f2019-04-08 17:56:40 -04001378
1379 // Update the device graph with this new logical port
1380 clonedLP := (proto.Clone(lp)).(*voltha.LogicalPort)
1381 go agent.updateDeviceGraph(clonedLP)
1382
khenaidoo8f474192019-04-03 17:20:44 -04001383 return true, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001384}
1385
khenaidoo910204f2019-04-08 17:56:40 -04001386func (agent *LogicalDeviceAgent) portExist(device *voltha.Device, port *voltha.Port) bool {
khenaidoo54544ae2019-03-18 13:22:39 -04001387 if ldevice, _ := agent.getLogicalDeviceWithoutLock(); ldevice != nil {
khenaidoofc1314d2019-03-14 09:34:21 -04001388 for _, lPort := range ldevice.Ports {
khenaidoo54544ae2019-03-18 13:22:39 -04001389 if lPort.DeviceId == device.Id && lPort.DevicePortNo == port.PortNo && lPort.Id == port.Label {
khenaidoofc1314d2019-03-14 09:34:21 -04001390 return true
1391 }
1392 }
1393 }
1394 return false
1395}
1396
khenaidoo8f474192019-04-03 17:20:44 -04001397// addUNILogicalPort adds an UNI port to the logical device. It returns a bool representing whether a port has been
1398// added and an eror in case a valid error is encountered. If the port was successfully added it will return
1399// (true, nil). If the device is not in the correct state it will return (false, nil) as this is a valid
1400// scenario. This also applies to the case where the port was already added.
khenaidoo910204f2019-04-08 17:56:40 -04001401func (agent *LogicalDeviceAgent) addUNILogicalPort(childDevice *voltha.Device, port *voltha.Port) (bool, error) {
khenaidoofc1314d2019-03-14 09:34:21 -04001402 log.Debugw("addUNILogicalPort", log.Fields{"port": port})
khenaidoo8f474192019-04-03 17:20:44 -04001403 if childDevice.AdminState != voltha.AdminState_ENABLED || childDevice.OperStatus != voltha.OperStatus_ACTIVE {
1404 log.Infow("device-not-ready", log.Fields{"deviceId": childDevice.Id, "admin": childDevice.AdminState, "oper": childDevice.OperStatus})
1405 return false, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001406 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001407 agent.lockLogicalDevice.RLock()
1408 if agent.portExist(childDevice, port) {
1409 log.Debugw("port-already-exist", log.Fields{"port": port})
1410 agent.lockLogicalDevice.RUnlock()
khenaidoo8f474192019-04-03 17:20:44 -04001411 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001412 }
1413 agent.lockLogicalDevice.RUnlock()
khenaidoofc1314d2019-03-14 09:34:21 -04001414 var portCap *ic.PortCapability
1415 var err error
1416 // First get the port capability
1417 if portCap, err = agent.deviceMgr.getPortCapability(nil, childDevice.Id, port.PortNo); err != nil {
1418 log.Errorw("error-retrieving-port-capabilities", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001419 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001420 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001421 agent.lockLogicalDevice.Lock()
1422 defer agent.lockLogicalDevice.Unlock()
1423 // Double check again if this port has been already added since the getPortCapability could have taken a long time
1424 if agent.portExist(childDevice, port) {
1425 log.Debugw("port-already-exist", log.Fields{"port": port})
khenaidoo8f474192019-04-03 17:20:44 -04001426 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001427 }
khenaidoofc1314d2019-03-14 09:34:21 -04001428 // Get stored logical device
1429 if ldevice, err := agent.getLogicalDeviceWithoutLock(); err != nil {
khenaidoo8f474192019-04-03 17:20:44 -04001430 return false, status.Error(codes.NotFound, agent.logicalDeviceId)
khenaidoofc1314d2019-03-14 09:34:21 -04001431 } else {
1432 log.Debugw("adding-uni", log.Fields{"deviceId": childDevice.Id})
1433 portCap.Port.RootPort = false
Matt Jeanneret3815e322019-03-12 19:15:49 -04001434 portCap.Port.Id = port.Label
1435 portCap.Port.OfpPort.PortNo = port.PortNo
khenaidoofc1314d2019-03-14 09:34:21 -04001436 portCap.Port.DeviceId = childDevice.Id
1437 portCap.Port.DevicePortNo = port.PortNo
1438 cloned := (proto.Clone(ldevice)).(*voltha.LogicalDevice)
1439 if cloned.Ports == nil {
1440 cloned.Ports = make([]*voltha.LogicalPort, 0)
1441 }
1442 cloned.Ports = append(cloned.Ports, portCap.Port)
khenaidoo910204f2019-04-08 17:56:40 -04001443 if err := agent.updateLogicalDeviceWithoutLock(cloned); err != nil {
1444 return false, err
1445 }
khenaidoo910204f2019-04-08 17:56:40 -04001446 // Update the device graph with this new logical port
1447 clonedLP := (proto.Clone(portCap.Port)).(*voltha.LogicalPort)
1448 go agent.updateDeviceGraph(clonedLP)
1449 return true, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001450 }
1451}
1452
khenaidoo43c82122018-11-22 18:38:28 -05001453func (agent *LogicalDeviceAgent) packetOut(packet *ofp.OfpPacketOut) {
khenaidoofdbad6e2018-11-06 22:26:38 -05001454 log.Debugw("packet-out", log.Fields{"packet": packet.GetInPort()})
khenaidoo68c930b2019-05-13 11:46:51 -04001455 outPort := fu.GetPacketOutPort(packet)
khenaidoofdbad6e2018-11-06 22:26:38 -05001456 //frame := packet.GetData()
1457 //TODO: Use a channel between the logical agent and the device agent
khenaidooca301322019-01-09 23:06:32 -05001458 if err := agent.deviceMgr.packetOut(agent.rootDeviceId, outPort, packet); err != nil {
khenaidoo910204f2019-04-08 17:56:40 -04001459 log.Error("packetout-failed", log.Fields{"logicalDeviceID": agent.rootDeviceId})
khenaidooca301322019-01-09 23:06:32 -05001460 }
khenaidoofdbad6e2018-11-06 22:26:38 -05001461}
1462
khenaidoo297cd252019-02-07 22:10:23 -05001463func (agent *LogicalDeviceAgent) packetIn(port uint32, transactionId string, packet []byte) {
1464 log.Debugw("packet-in", log.Fields{"port": port, "packet": packet, "transactionId": transactionId})
khenaidoo68c930b2019-05-13 11:46:51 -04001465 packetIn := fu.MkPacketIn(port, packet)
khenaidoo297cd252019-02-07 22:10:23 -05001466 agent.ldeviceMgr.grpcNbiHdlr.sendPacketIn(agent.logicalDeviceId, transactionId, packetIn)
khenaidooca301322019-01-09 23:06:32 -05001467 log.Debugw("sending-packet-in", log.Fields{"packet-in": packetIn})
khenaidoofdbad6e2018-11-06 22:26:38 -05001468}
khenaidoo2c6a0992019-04-29 13:46:56 -04001469
1470func (agent *LogicalDeviceAgent) addLogicalPortToMap(portNo uint32, nniPort bool) {
1471 agent.lockLogicalPortsNo.Lock()
1472 defer agent.lockLogicalPortsNo.Unlock()
1473 if exist := agent.logicalPortsNo[portNo]; !exist {
1474 agent.logicalPortsNo[portNo] = nniPort
1475 }
1476}
1477
khenaidoo3d3b8c22019-05-22 18:10:39 -04001478func (agent *LogicalDeviceAgent) addLogicalPortsToMap(lps []*voltha.LogicalPort) {
1479 agent.lockLogicalPortsNo.Lock()
1480 defer agent.lockLogicalPortsNo.Unlock()
1481 for _, lp := range lps {
1482 if exist := agent.logicalPortsNo[lp.DevicePortNo]; !exist {
1483 agent.logicalPortsNo[lp.DevicePortNo] = lp.RootPort
1484 }
1485 }
1486}
1487
khenaidoo2c6a0992019-04-29 13:46:56 -04001488func (agent *LogicalDeviceAgent) deleteLogicalPortFromMap(portNo uint32) {
1489 agent.lockLogicalPortsNo.Lock()
1490 defer agent.lockLogicalPortsNo.Unlock()
1491 if exist := agent.logicalPortsNo[portNo]; exist {
1492 delete(agent.logicalPortsNo, portNo)
1493 }
1494}
1495
1496func (agent *LogicalDeviceAgent) isNNIPort(portNo uint32) bool {
1497 agent.lockLogicalPortsNo.RLock()
1498 defer agent.lockLogicalPortsNo.RUnlock()
1499 if exist := agent.logicalPortsNo[portNo]; exist {
1500 return agent.logicalPortsNo[portNo]
1501 }
1502 return false
1503}
1504
1505func (agent *LogicalDeviceAgent) getFirstNNIPort() (uint32, error) {
1506 agent.lockLogicalPortsNo.RLock()
1507 defer agent.lockLogicalPortsNo.RUnlock()
1508 for portNo, nni := range agent.logicalPortsNo {
1509 if nni {
1510 return portNo, nil
1511 }
1512 }
1513 return 0, status.Error(codes.NotFound, "No NNI port found")
1514}