blob: 49e14638dae27e16e2b2f747b8ec773b0752d887 [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
Manikkaraj kb1a10922019-07-29 12:10:34 -040048 meterProxy *model.Proxy
khenaidoo3306c992019-05-24 16:57:35 -040049 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 defaultTimeout int64
khenaidoob9203542018-09-17 22:56:37 -040057}
58
Stephane Barbarie1ab43272018-12-08 21:42:13 -050059func newLogicalDeviceAgent(id string, deviceId string, ldeviceMgr *LogicalDeviceManager,
60 deviceMgr *DeviceManager,
khenaidoo2c6a0992019-04-29 13:46:56 -040061 cdProxy *model.Proxy, timeout int64) *LogicalDeviceAgent {
khenaidoob9203542018-09-17 22:56:37 -040062 var agent LogicalDeviceAgent
63 agent.exitChannel = make(chan int, 1)
64 agent.logicalDeviceId = id
Stephane Barbarie1ab43272018-12-08 21:42:13 -050065 agent.rootDeviceId = deviceId
khenaidoob9203542018-09-17 22:56:37 -040066 agent.deviceMgr = deviceMgr
khenaidoo9a468962018-09-19 15:33:13 -040067 agent.clusterDataProxy = cdProxy
khenaidoob9203542018-09-17 22:56:37 -040068 agent.ldeviceMgr = ldeviceMgr
khenaidoo19d7b632018-10-30 10:49:50 -040069 agent.flowDecomposer = fd.NewFlowDecomposer(agent.deviceMgr)
khenaidoo92e62c52018-10-03 14:02:54 -040070 agent.lockLogicalDevice = sync.RWMutex{}
khenaidoofc1314d2019-03-14 09:34:21 -040071 agent.portProxies = make(map[string]*model.Proxy)
72 agent.portProxiesLock = sync.RWMutex{}
khenaidoo2c6a0992019-04-29 13:46:56 -040073 agent.lockLogicalPortsNo = sync.RWMutex{}
74 agent.logicalPortsNo = make(map[uint32]bool)
khenaidoo2c6a0992019-04-29 13:46:56 -040075 agent.defaultTimeout = timeout
khenaidoob9203542018-09-17 22:56:37 -040076 return &agent
77}
78
khenaidoo4d4802d2018-10-04 21:59:49 -040079// start creates the logical device and add it to the data model
khenaidoo297cd252019-02-07 22:10:23 -050080func (agent *LogicalDeviceAgent) start(ctx context.Context, loadFromdB bool) error {
81 log.Infow("starting-logical_device-agent", log.Fields{"logicaldeviceId": agent.logicalDeviceId, "loadFromdB": loadFromdB})
82 var ld *voltha.LogicalDevice
83 if !loadFromdB {
khenaidoo7e3d8f12019-08-02 16:06:30 -040084 //Build the logical device based on information retrieved from the device adapter
85 var switchCap *ic.SwitchCapability
khenaidoo297cd252019-02-07 22:10:23 -050086 var err error
khenaidoo7e3d8f12019-08-02 16:06:30 -040087 if switchCap, err = agent.deviceMgr.getSwitchCapability(ctx, agent.rootDeviceId); err != nil {
88 log.Errorw("error-creating-logical-device", log.Fields{"error": err})
89 return err
90 }
khenaidoo297cd252019-02-07 22:10:23 -050091 ld = &voltha.LogicalDevice{Id: agent.logicalDeviceId, RootDeviceId: agent.rootDeviceId}
92
93 // Create the datapath ID (uint64) using the logical device ID (based on the MAC Address)
94 var datapathID uint64
95 if datapathID, err = CreateDataPathId(agent.logicalDeviceId); err != nil {
96 log.Errorw("error-creating-datapath-id", log.Fields{"error": err})
97 return err
98 }
99 ld.DatapathId = datapathID
khenaidoo7e3d8f12019-08-02 16:06:30 -0400100 ld.Desc = (proto.Clone(switchCap.Desc)).(*ofp.OfpDesc)
101 log.Debugw("Switch-capability", log.Fields{"Desc": ld.Desc, "fromAd": switchCap.Desc})
102 ld.SwitchFeatures = (proto.Clone(switchCap.SwitchFeatures)).(*ofp.OfpSwitchFeatures)
khenaidoo297cd252019-02-07 22:10:23 -0500103 ld.Flows = &ofp.Flows{Items: nil}
104 ld.FlowGroups = &ofp.FlowGroups{Items: nil}
105
khenaidoo297cd252019-02-07 22:10:23 -0500106 agent.lockLogicalDevice.Lock()
khenaidoo297cd252019-02-07 22:10:23 -0500107 // Save the logical device
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400108 if added := agent.clusterDataProxy.AddWithID(ctx, "/logical_devices", ld.Id, ld, ""); added == nil {
khenaidoo297cd252019-02-07 22:10:23 -0500109 log.Errorw("failed-to-add-logical-device", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
110 } else {
111 log.Debugw("logicaldevice-created", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
112 }
113 agent.lockLogicalDevice.Unlock()
khenaidoofc1314d2019-03-14 09:34:21 -0400114
khenaidoo3d3b8c22019-05-22 18:10:39 -0400115 // TODO: Set the logical ports in a separate call once the port update issue is fixed.
116 go agent.setupLogicalPorts(ctx)
117
khenaidoo297cd252019-02-07 22:10:23 -0500118 } else {
119 // load from dB - the logical may not exist at this time. On error, just return and the calling function
120 // will destroy this agent.
121 var err error
122 if ld, err = agent.GetLogicalDevice(); err != nil {
123 log.Warnw("failed-to-load-logical-device", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
124 return err
125 }
khenaidoo3d3b8c22019-05-22 18:10:39 -0400126
khenaidoo8c3303d2019-02-13 14:59:39 -0500127 // Update the root device Id
128 agent.rootDeviceId = ld.RootDeviceId
khenaidoo3d3b8c22019-05-22 18:10:39 -0400129
130 // Setup the local list of logical ports
131 agent.addLogicalPortsToMap(ld.Ports)
132
133 // Setup the device graph
134 agent.generateDeviceGraph()
khenaidoob9203542018-09-17 22:56:37 -0400135 }
khenaidoo92e62c52018-10-03 14:02:54 -0400136 agent.lockLogicalDevice.Lock()
khenaidoo3d3b8c22019-05-22 18:10:39 -0400137 defer agent.lockLogicalDevice.Unlock()
khenaidoofc1314d2019-03-14 09:34:21 -0400138
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400139 agent.flowProxy = agent.clusterDataProxy.CreateProxy(
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400140 ctx,
khenaidoo19d7b632018-10-30 10:49:50 -0400141 fmt.Sprintf("/logical_devices/%s/flows", agent.logicalDeviceId),
142 false)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400143 agent.meterProxy = agent.clusterDataProxy.CreateProxy(
144 ctx,
145 fmt.Sprintf("/logical_devices/%s/meters", agent.logicalDeviceId),
146 false)
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400147 agent.groupProxy = agent.clusterDataProxy.CreateProxy(
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400148 ctx,
khenaidoo19d7b632018-10-30 10:49:50 -0400149 fmt.Sprintf("/logical_devices/%s/flow_groups", agent.logicalDeviceId),
150 false)
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400151 agent.ldProxy = agent.clusterDataProxy.CreateProxy(
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400152 ctx,
khenaidoofc1314d2019-03-14 09:34:21 -0400153 fmt.Sprintf("/logical_devices/%s", agent.logicalDeviceId),
154 false)
khenaidoo19d7b632018-10-30 10:49:50 -0400155
khenaidoofc1314d2019-03-14 09:34:21 -0400156 // TODO: Use a port proxy once the POST_ADD is fixed
khenaidoo3d3b8c22019-05-22 18:10:39 -0400157 if agent.ldProxy != nil {
158 agent.ldProxy.RegisterCallback(model.POST_UPDATE, agent.portUpdated)
159 } else {
160 log.Errorw("logical-device-proxy-null", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
161 return status.Error(codes.Internal, "logical-device-proxy-null")
162 }
khenaidoobcf205b2019-01-25 22:21:14 -0500163
khenaidoob9203542018-09-17 22:56:37 -0400164 return nil
165}
166
khenaidoo4d4802d2018-10-04 21:59:49 -0400167// stop stops the logical devuce agent. This removes the logical device from the data model.
168func (agent *LogicalDeviceAgent) stop(ctx context.Context) {
169 log.Info("stopping-logical_device-agent")
170 agent.lockLogicalDevice.Lock()
171 defer agent.lockLogicalDevice.Unlock()
khenaidoo8c3303d2019-02-13 14:59:39 -0500172
khenaidoo4d4802d2018-10-04 21:59:49 -0400173 //Remove the logical device from the model
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400174 if removed := agent.clusterDataProxy.Remove(ctx, "/logical_devices/"+agent.logicalDeviceId, ""); removed == nil {
khenaidoo4d4802d2018-10-04 21:59:49 -0400175 log.Errorw("failed-to-remove-logical-device", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
176 } else {
177 log.Debugw("logicaldevice-removed", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
178 }
179 agent.exitChannel <- 1
180 log.Info("logical_device-agent-stopped")
181}
182
khenaidoo19d7b632018-10-30 10:49:50 -0400183// GetLogicalDevice locks the logical device model and then retrieves the latest logical device information
184func (agent *LogicalDeviceAgent) GetLogicalDevice() (*voltha.LogicalDevice, error) {
185 log.Debug("GetLogicalDevice")
khenaidoo1ce37ad2019-03-24 22:07:24 -0400186 agent.lockLogicalDevice.RLock()
187 defer agent.lockLogicalDevice.RUnlock()
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400188 logicalDevice := agent.clusterDataProxy.Get(context.Background(), "/logical_devices/"+agent.logicalDeviceId, 0, false, "")
khenaidoo92e62c52018-10-03 14:02:54 -0400189 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500190 return lDevice, nil
khenaidoo92e62c52018-10-03 14:02:54 -0400191 }
192 return nil, status.Errorf(codes.NotFound, "logical_device-%s", agent.logicalDeviceId)
193}
194
khenaidoodd237172019-05-27 16:37:17 -0400195func (agent *LogicalDeviceAgent) ListLogicalDeviceFlows() (*ofp.Flows, error) {
196 log.Debug("ListLogicalDeviceFlows")
197 agent.lockLogicalDevice.RLock()
198 defer agent.lockLogicalDevice.RUnlock()
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400199 logicalDevice := agent.clusterDataProxy.Get(context.Background(), "/logical_devices/"+agent.logicalDeviceId, 0, false, "")
khenaidoodd237172019-05-27 16:37:17 -0400200 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
201 cFlows := (proto.Clone(lDevice.Flows)).(*ofp.Flows)
202 return cFlows, nil
203 }
204 return nil, status.Errorf(codes.NotFound, "logical_device-%s", agent.logicalDeviceId)
205}
206
Manikkaraj kb1a10922019-07-29 12:10:34 -0400207func (agent *LogicalDeviceAgent) ListLogicalDeviceMeters() (*ofp.Meters, error) {
208 log.Debug("ListLogicalDeviceMeters")
209 agent.lockLogicalDevice.RLock()
210 defer agent.lockLogicalDevice.RUnlock()
211 logicalDevice := agent.clusterDataProxy.Get(context.Background(), "/logical_devices/"+agent.logicalDeviceId, 0, false, "")
212 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
213 cMeters := (proto.Clone(lDevice.Meters)).(*ofp.Meters)
214 return cMeters, nil
215 }
216 return nil, status.Errorf(codes.NotFound, "logical_device-%s", agent.logicalDeviceId)
217}
218
khenaidoodd237172019-05-27 16:37:17 -0400219func (agent *LogicalDeviceAgent) ListLogicalDeviceFlowGroups() (*ofp.FlowGroups, error) {
220 log.Debug("ListLogicalDeviceFlowGroups")
221 agent.lockLogicalDevice.RLock()
222 defer agent.lockLogicalDevice.RUnlock()
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400223 logicalDevice := agent.clusterDataProxy.Get(context.Background(), "/logical_devices/"+agent.logicalDeviceId, 0, false, "")
khenaidoodd237172019-05-27 16:37:17 -0400224 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
225 cFlowGroups := (proto.Clone(lDevice.FlowGroups)).(*ofp.FlowGroups)
226 return cFlowGroups, nil
227 }
228 return nil, status.Errorf(codes.NotFound, "logical_device-%s", agent.logicalDeviceId)
229}
230
khenaidoo19d7b632018-10-30 10:49:50 -0400231func (agent *LogicalDeviceAgent) ListLogicalDevicePorts() (*voltha.LogicalPorts, error) {
khenaidoo1ce37ad2019-03-24 22:07:24 -0400232 log.Debug("ListLogicalDevicePorts")
233 agent.lockLogicalDevice.RLock()
234 defer agent.lockLogicalDevice.RUnlock()
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400235 logicalDevice := agent.clusterDataProxy.Get(context.Background(), "/logical_devices/"+agent.logicalDeviceId, 0, false, "")
khenaidoo19d7b632018-10-30 10:49:50 -0400236 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
237 lPorts := make([]*voltha.LogicalPort, 0)
238 for _, port := range lDevice.Ports {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500239 lPorts = append(lPorts, port)
khenaidoo19d7b632018-10-30 10:49:50 -0400240 }
241 return &voltha.LogicalPorts{Items: lPorts}, nil
242 }
243 return nil, status.Errorf(codes.NotFound, "logical_device-%s", agent.logicalDeviceId)
244}
245
246// listFlows locks the logical device model and then retrieves the latest flow information
247func (agent *LogicalDeviceAgent) listFlows() []*ofp.OfpFlowStats {
248 log.Debug("listFlows")
khenaidoo1ce37ad2019-03-24 22:07:24 -0400249 agent.lockLogicalDevice.RLock()
250 defer agent.lockLogicalDevice.RUnlock()
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400251 logicalDevice := agent.clusterDataProxy.Get(context.Background(), "/logical_devices/"+agent.logicalDeviceId, 0, false, "")
khenaidoo19d7b632018-10-30 10:49:50 -0400252 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
253 return lDevice.Flows.Items
254 }
255 return nil
256}
257
258// listFlowGroups locks the logical device model and then retrieves the latest flow groups information
259func (agent *LogicalDeviceAgent) listFlowGroups() []*ofp.OfpGroupEntry {
260 log.Debug("listFlowGroups")
khenaidoo1ce37ad2019-03-24 22:07:24 -0400261 agent.lockLogicalDevice.RLock()
262 defer agent.lockLogicalDevice.RUnlock()
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400263 logicalDevice := agent.clusterDataProxy.Get(context.Background(), "/logical_devices/"+agent.logicalDeviceId, 0, false, "")
khenaidoo19d7b632018-10-30 10:49:50 -0400264 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
265 return lDevice.FlowGroups.Items
266 }
267 return nil
268}
269
khenaidoo43c82122018-11-22 18:38:28 -0500270//updateLogicalDeviceWithoutLock updates the model with the logical device. It clones the logicaldevice before saving it
271func (agent *LogicalDeviceAgent) updateLogicalDeviceFlowsWithoutLock(flows *ofp.Flows) error {
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400272 updateCtx := context.WithValue(context.Background(), model.RequestTimestamp, time.Now().UnixNano())
273 afterUpdate := agent.flowProxy.Update(updateCtx, "/", flows, false, "")
khenaidoo43c82122018-11-22 18:38:28 -0500274 if afterUpdate == nil {
275 return status.Errorf(codes.Internal, "failed-updating-logical-device-flows:%s", agent.logicalDeviceId)
276 }
khenaidoo43c82122018-11-22 18:38:28 -0500277 return nil
278}
279
280//updateLogicalDeviceWithoutLock updates the model with the logical device. It clones the logicaldevice before saving it
Manikkaraj kb1a10922019-07-29 12:10:34 -0400281func (agent *LogicalDeviceAgent) updateLogicalDeviceMetersWithoutLock(meters *ofp.Meters) error {
282 updateCtx := context.WithValue(context.Background(), model.RequestTimestamp, time.Now().UnixNano())
283 afterUpdate := agent.meterProxy.Update(updateCtx, "/", meters, false, "")
284 if afterUpdate == nil {
285 return status.Errorf(codes.Internal, "failed-updating-logical-device-meters:%s", agent.logicalDeviceId)
286 }
287 return nil
288}
289
290//updateLogicalDeviceWithoutLock updates the model with the logical device. It clones the logicaldevice before saving it
khenaidoo43c82122018-11-22 18:38:28 -0500291func (agent *LogicalDeviceAgent) updateLogicalDeviceFlowGroupsWithoutLock(flowGroups *ofp.FlowGroups) error {
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400292 updateCtx := context.WithValue(context.Background(), model.RequestTimestamp, time.Now().UnixNano())
293 afterUpdate := agent.groupProxy.Update(updateCtx, "/", flowGroups, false, "")
khenaidoo43c82122018-11-22 18:38:28 -0500294 if afterUpdate == nil {
295 return status.Errorf(codes.Internal, "failed-updating-logical-device-flow-groups:%s", agent.logicalDeviceId)
296 }
khenaidoo43c82122018-11-22 18:38:28 -0500297 return nil
298}
299
khenaidoo4d4802d2018-10-04 21:59:49 -0400300// getLogicalDeviceWithoutLock retrieves a logical device from the model without locking it. This is used only by
301// functions that have already acquired the logical device lock to the model
khenaidoo92e62c52018-10-03 14:02:54 -0400302func (agent *LogicalDeviceAgent) getLogicalDeviceWithoutLock() (*voltha.LogicalDevice, error) {
303 log.Debug("getLogicalDeviceWithoutLock")
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400304 logicalDevice := agent.clusterDataProxy.Get(context.Background(), "/logical_devices/"+agent.logicalDeviceId, 0, false, "")
khenaidoo92e62c52018-10-03 14:02:54 -0400305 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
khenaidoo1ce37ad2019-03-24 22:07:24 -0400306 //log.Debug("getLogicalDeviceWithoutLock", log.Fields{"ldevice": lDevice})
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500307 return lDevice, nil
khenaidoo92e62c52018-10-03 14:02:54 -0400308 }
309 return nil, status.Errorf(codes.NotFound, "logical_device-%s", agent.logicalDeviceId)
310}
311
khenaidoo2c6a0992019-04-29 13:46:56 -0400312func (agent *LogicalDeviceAgent) updateLogicalPort(device *voltha.Device, port *voltha.Port) error {
313 log.Debugw("updateLogicalPort", log.Fields{"deviceId": device.Id, "port": port})
314 var err error
315 if port.Type == voltha.Port_ETHERNET_NNI {
316 if _, err = agent.addNNILogicalPort(device, port); err != nil {
317 return err
318 }
319 agent.addLogicalPortToMap(port.PortNo, true)
320 } else if port.Type == voltha.Port_ETHERNET_UNI {
321 if _, err = agent.addUNILogicalPort(device, port); err != nil {
322 return err
323 }
324 agent.addLogicalPortToMap(port.PortNo, false)
325 } else {
326 // Update the device graph to ensure all routes on the logical device have been calculated
327 if err = agent.updateRoutes(device, port); err != nil {
328 log.Errorw("failed-to-update-routes", log.Fields{"deviceId": device.Id, "port": port, "error": err})
329 return err
330 }
331 }
332 return nil
333}
334
khenaidoo910204f2019-04-08 17:56:40 -0400335func (agent *LogicalDeviceAgent) addLogicalPort(device *voltha.Device, port *voltha.Port) error {
khenaidoo8f474192019-04-03 17:20:44 -0400336 log.Debugw("addLogicalPort", log.Fields{"deviceId": device.Id, "port": port})
khenaidoo8f474192019-04-03 17:20:44 -0400337 var err error
khenaidoofc1314d2019-03-14 09:34:21 -0400338 if port.Type == voltha.Port_ETHERNET_NNI {
khenaidoo910204f2019-04-08 17:56:40 -0400339 if _, err = agent.addNNILogicalPort(device, port); err != nil {
khenaidoofc1314d2019-03-14 09:34:21 -0400340 return err
341 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400342 agent.addLogicalPortToMap(port.PortNo, true)
khenaidoofc1314d2019-03-14 09:34:21 -0400343 } else if port.Type == voltha.Port_ETHERNET_UNI {
khenaidoo910204f2019-04-08 17:56:40 -0400344 if _, err = agent.addUNILogicalPort(device, port); err != nil {
khenaidoofc1314d2019-03-14 09:34:21 -0400345 return err
346 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400347 agent.addLogicalPortToMap(port.PortNo, false)
khenaidoofc1314d2019-03-14 09:34:21 -0400348 } else {
349 log.Debugw("invalid-port-type", log.Fields{"deviceId": device.Id, "port": port})
350 return nil
351 }
khenaidoofc1314d2019-03-14 09:34:21 -0400352 return nil
353}
354
khenaidoo3d3b8c22019-05-22 18:10:39 -0400355// setupLogicalPorts is invoked once the logical device has been created and is ready to get ports
356// added to it. While the logical device was being created we could have received requests to add
357// NNI and UNI ports which were discarded. Now is the time to add them if needed
358func (agent *LogicalDeviceAgent) setupLogicalPorts(ctx context.Context) error {
359 log.Infow("setupLogicalPorts", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
360 // First add any NNI ports which could have been missing
361 if err := agent.setupNNILogicalPorts(nil, agent.rootDeviceId); err != nil {
362 log.Errorw("error-setting-up-NNI-ports", log.Fields{"error": err, "deviceId": agent.rootDeviceId})
363 return err
364 }
365
366 // Now, set up the UNI ports if needed.
367 if children, err := agent.deviceMgr.getAllChildDevices(agent.rootDeviceId); err != nil {
368 log.Errorw("error-getting-child-devices", log.Fields{"error": err, "deviceId": agent.rootDeviceId})
369 return err
370 } else {
371 chnlsList := make([]chan interface{}, 0)
372 for _, child := range children.Items {
373 ch := make(chan interface{})
374 chnlsList = append(chnlsList, ch)
375 go func(device *voltha.Device, ch chan interface{}) {
376 if err = agent.setupUNILogicalPorts(nil, device); err != nil {
377 log.Error("setting-up-UNI-ports-failed", log.Fields{"deviceID": device.Id})
378 ch <- status.Errorf(codes.Internal, "UNI-ports-setup-failed: %s", device.Id)
379 }
380 ch <- nil
381 }(child, ch)
382 }
383 // Wait for completion
384 if res := fu.WaitForNilOrErrorResponses(agent.defaultTimeout, chnlsList...); res != nil {
385 return status.Errorf(codes.Aborted, "errors-%s", res)
386 }
387 }
388 return nil
389}
390
khenaidoofc1314d2019-03-14 09:34:21 -0400391// setupNNILogicalPorts creates an NNI port on the logical device that represents an NNI interface on a root device
392func (agent *LogicalDeviceAgent) setupNNILogicalPorts(ctx context.Context, deviceId string) error {
393 log.Infow("setupNNILogicalPorts-start", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoob9203542018-09-17 22:56:37 -0400394 // Build the logical device based on information retrieved from the device adapter
khenaidoofc1314d2019-03-14 09:34:21 -0400395 var err error
396
397 var device *voltha.Device
398 if device, err = agent.deviceMgr.GetDevice(deviceId); err != nil {
khenaidoo2c6a0992019-04-29 13:46:56 -0400399 log.Errorw("error-retrieving-device", log.Fields{"error": err, "deviceId": deviceId})
khenaidoofc1314d2019-03-14 09:34:21 -0400400 return err
401 }
402
403 //Get UNI port number
khenaidoofc1314d2019-03-14 09:34:21 -0400404 for _, port := range device.Ports {
405 if port.Type == voltha.Port_ETHERNET_NNI {
khenaidoo910204f2019-04-08 17:56:40 -0400406 if _, err = agent.addNNILogicalPort(device, port); err != nil {
khenaidoofc1314d2019-03-14 09:34:21 -0400407 log.Errorw("error-adding-UNI-port", log.Fields{"error": err})
khenaidoofc1314d2019-03-14 09:34:21 -0400408 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400409 agent.addLogicalPortToMap(port.PortNo, true)
khenaidoofc1314d2019-03-14 09:34:21 -0400410 }
411 }
khenaidoofc1314d2019-03-14 09:34:21 -0400412 return err
413}
414
khenaidoo3ab34882019-05-02 21:33:30 -0400415// updatePortsState updates the ports state related to the device
416func (agent *LogicalDeviceAgent) updatePortsState(device *voltha.Device, state voltha.AdminState_AdminState) error {
417 log.Infow("updatePortsState-start", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
418 agent.lockLogicalDevice.Lock()
419 defer agent.lockLogicalDevice.Unlock()
420 // Get the latest logical device info
421 if ld, err := agent.getLogicalDeviceWithoutLock(); err != nil {
422 log.Warnw("logical-device-unknown", log.Fields{"ldeviceId": agent.logicalDeviceId, "error": err})
423 return err
424 } else {
425 cloned := (proto.Clone(ld)).(*voltha.LogicalDevice)
426 for _, lport := range cloned.Ports {
427 if lport.DeviceId == device.Id {
428 switch state {
429 case voltha.AdminState_ENABLED:
430 lport.OfpPort.Config = lport.OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
khenaidoo0a822f92019-05-08 15:15:57 -0400431 lport.OfpPort.State = uint32(ofp.OfpPortState_OFPPS_LIVE)
khenaidoo3ab34882019-05-02 21:33:30 -0400432 case voltha.AdminState_DISABLED:
433 lport.OfpPort.Config = lport.OfpPort.Config | uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
khenaidoo0a822f92019-05-08 15:15:57 -0400434 lport.OfpPort.State = uint32(ofp.OfpPortState_OFPPS_LINK_DOWN)
khenaidoo3ab34882019-05-02 21:33:30 -0400435 default:
436 log.Warnw("unsupported-state-change", log.Fields{"deviceId": device.Id, "state": state})
437 }
438 }
439 }
440 // Updating the logical device will trigger the poprt change events to be populated to the controller
441 if err := agent.updateLogicalDeviceWithoutLock(cloned); err != nil {
442 log.Warnw("logical-device-update-failed", log.Fields{"ldeviceId": agent.logicalDeviceId, "error": err})
443 return err
444 }
445 }
446 return nil
447}
448
khenaidoofc1314d2019-03-14 09:34:21 -0400449// setupUNILogicalPorts creates a UNI port on the logical device that represents a child UNI interface
450func (agent *LogicalDeviceAgent) setupUNILogicalPorts(ctx context.Context, childDevice *voltha.Device) error {
khenaidoo3d3b8c22019-05-22 18:10:39 -0400451 log.Infow("setupUNILogicalPort", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoofc1314d2019-03-14 09:34:21 -0400452 // Build the logical device based on information retrieved from the device adapter
khenaidoob9203542018-09-17 22:56:37 -0400453 var err error
khenaidoo59ef7be2019-06-21 12:40:28 -0400454 var added bool
khenaidoo19d7b632018-10-30 10:49:50 -0400455 //Get UNI port number
khenaidoo19d7b632018-10-30 10:49:50 -0400456 for _, port := range childDevice.Ports {
457 if port.Type == voltha.Port_ETHERNET_UNI {
khenaidoo59ef7be2019-06-21 12:40:28 -0400458 if added, err = agent.addUNILogicalPort(childDevice, port); err != nil {
khenaidoofc1314d2019-03-14 09:34:21 -0400459 log.Errorw("error-adding-UNI-port", log.Fields{"error": err})
khenaidoofc1314d2019-03-14 09:34:21 -0400460 }
khenaidoo59ef7be2019-06-21 12:40:28 -0400461 if added {
462 agent.addLogicalPortToMap(port.PortNo, false)
463 }
khenaidoo19d7b632018-10-30 10:49:50 -0400464 }
465 }
khenaidoofc1314d2019-03-14 09:34:21 -0400466 return err
khenaidoo92e62c52018-10-03 14:02:54 -0400467}
468
khenaidoo0a822f92019-05-08 15:15:57 -0400469// deleteAllLogicalPorts deletes all logical ports associated with this device
470func (agent *LogicalDeviceAgent) deleteAllLogicalPorts(device *voltha.Device) error {
471 log.Infow("updatePortsState-start", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
472 agent.lockLogicalDevice.Lock()
473 defer agent.lockLogicalDevice.Unlock()
474 // Get the latest logical device info
475 if ld, err := agent.getLogicalDeviceWithoutLock(); err != nil {
476 log.Warnw("logical-device-unknown", log.Fields{"ldeviceId": agent.logicalDeviceId, "error": err})
477 return err
478 } else {
479 cloned := (proto.Clone(ld)).(*voltha.LogicalDevice)
480 updateLogicalPorts := []*voltha.LogicalPort{}
481 for _, lport := range cloned.Ports {
482 if lport.DeviceId != device.Id {
483 updateLogicalPorts = append(updateLogicalPorts, lport)
484 }
485 }
486 if len(updateLogicalPorts) < len(cloned.Ports) {
487 cloned.Ports = updateLogicalPorts
488 // Updating the logical device will trigger the poprt change events to be populated to the controller
489 if err := agent.updateLogicalDeviceWithoutLock(cloned); err != nil {
490 log.Warnw("logical-device-update-failed", log.Fields{"ldeviceId": agent.logicalDeviceId, "error": err})
491 return err
492 }
493 } else {
494 log.Debugw("no-change-required", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
495 }
496 }
497 return nil
498}
499
khenaidoo92e62c52018-10-03 14:02:54 -0400500//updateLogicalDeviceWithoutLock updates the model with the logical device. It clones the logicaldevice before saving it
501func (agent *LogicalDeviceAgent) updateLogicalDeviceWithoutLock(logicalDevice *voltha.LogicalDevice) error {
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400502 updateCtx := context.WithValue(context.Background(), model.RequestTimestamp, time.Now().UnixNano())
503 afterUpdate := agent.clusterDataProxy.Update(updateCtx, "/logical_devices/"+agent.logicalDeviceId, logicalDevice, false, "")
khenaidoo92e62c52018-10-03 14:02:54 -0400504 if afterUpdate == nil {
505 return status.Errorf(codes.Internal, "failed-updating-logical-device:%s", agent.logicalDeviceId)
506 }
507 return nil
508}
509
khenaidoo19d7b632018-10-30 10:49:50 -0400510//updateFlowTable updates the flow table of that logical device
511func (agent *LogicalDeviceAgent) updateFlowTable(ctx context.Context, flow *ofp.OfpFlowMod) error {
512 log.Debug("updateFlowTable")
513 if flow == nil {
514 return nil
515 }
516 switch flow.GetCommand() {
517 case ofp.OfpFlowModCommand_OFPFC_ADD:
518 return agent.flowAdd(flow)
519 case ofp.OfpFlowModCommand_OFPFC_DELETE:
520 return agent.flowDelete(flow)
521 case ofp.OfpFlowModCommand_OFPFC_DELETE_STRICT:
522 return agent.flowDeleteStrict(flow)
523 case ofp.OfpFlowModCommand_OFPFC_MODIFY:
524 return agent.flowModify(flow)
525 case ofp.OfpFlowModCommand_OFPFC_MODIFY_STRICT:
526 return agent.flowModifyStrict(flow)
527 }
528 return status.Errorf(codes.Internal,
529 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceId, flow.GetCommand())
530}
531
532//updateGroupTable updates the group table of that logical device
533func (agent *LogicalDeviceAgent) updateGroupTable(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
534 log.Debug("updateGroupTable")
535 if groupMod == nil {
536 return nil
537 }
538 switch groupMod.GetCommand() {
539 case ofp.OfpGroupModCommand_OFPGC_ADD:
540 return agent.groupAdd(groupMod)
541 case ofp.OfpGroupModCommand_OFPGC_DELETE:
542 return agent.groupDelete(groupMod)
543 case ofp.OfpGroupModCommand_OFPGC_MODIFY:
544 return agent.groupModify(groupMod)
545 }
546 return status.Errorf(codes.Internal,
547 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceId, groupMod.GetCommand())
548}
549
Manikkaraj kb1a10922019-07-29 12:10:34 -0400550// updateMeterTable updates the meter table of that logical device
551func (agent *LogicalDeviceAgent) updateMeterTable(ctx context.Context, meterMod *ofp.OfpMeterMod) error {
552 log.Debug("updateMeterTable")
553 if meterMod == nil {
554 return nil
555 }
556 switch meterMod.GetCommand() {
557 case ofp.OfpMeterModCommand_OFPMC_ADD:
558 return agent.meterAdd(meterMod)
559 case ofp.OfpMeterModCommand_OFPMC_DELETE:
560 return agent.meterDelete(meterMod)
561 case ofp.OfpMeterModCommand_OFPMC_MODIFY:
562 return agent.meterModify(meterMod)
563 }
564 return status.Errorf(codes.Internal,
565 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceId, meterMod.GetCommand())
566
567}
568
569func (agent *LogicalDeviceAgent) meterAdd(meterMod *ofp.OfpMeterMod) error {
570 log.Debugw("meterAdd", log.Fields{"metermod": *meterMod})
571 if meterMod == nil {
572 return nil
573 }
574 log.Debug("Waiting for logical device lock!!")
575 agent.lockLogicalDevice.Lock()
576 defer agent.lockLogicalDevice.Unlock()
577 log.Debug("Acquired logical device lock")
578 var lDevice *voltha.LogicalDevice
579 var err error
580 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
581 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
582 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
583 }
584
585 var meters []*ofp.OfpMeterEntry
586 if lDevice.Meters != nil && lDevice.Meters.Items != nil {
587 meters = lDevice.Meters.Items
588 }
589 log.Debugw("Available meters", log.Fields{"meters": meters})
590
591 for _, meter := range meters {
592 if meterMod.MeterId == meter.Config.MeterId {
593 log.Infow("Meter-already-exists", log.Fields{"meter": *meterMod})
594 return nil
595 }
596 }
597
598 meterEntry := fu.MeterEntryFromMeterMod(meterMod)
599 meters = append(meters, meterEntry)
600 //Update model
601 if err := agent.updateLogicalDeviceMetersWithoutLock(&ofp.Meters{Items: meters}); err != nil {
602 log.Errorw("db-meter-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
603 return err
604 }
605 log.Debugw("Meter-added-successfully", log.Fields{"Added-meter": meterEntry, "updated-meters": lDevice.Meters})
606 return nil
607}
608
609func (agent *LogicalDeviceAgent) meterDelete(meterMod *ofp.OfpMeterMod) error {
610 log.Debug("meterDelete", log.Fields{"meterMod": *meterMod})
611 if meterMod == nil {
612 return nil
613 }
614 agent.lockLogicalDevice.Lock()
615 defer agent.lockLogicalDevice.Unlock()
616
617 var lDevice *voltha.LogicalDevice
618 var err error
619 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
620 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
621 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
622 }
623
624 var meters []*ofp.OfpMeterEntry
625 var flows []*ofp.OfpFlowStats
626 updatedFlows := make([]*ofp.OfpFlowStats, 0)
627 if lDevice.Meters != nil && lDevice.Meters.Items != nil {
628 meters = lDevice.Meters.Items
629 }
630 if lDevice.Flows != nil && lDevice.Flows.Items != nil {
631 flows = lDevice.Flows.Items
632 }
633
634 changedMeter := false
635 changedFow := false
636 log.Debugw("Available meters", log.Fields{"meters": meters})
637 for index, meter := range meters {
638 if meterMod.MeterId == meter.Config.MeterId {
639 flows = lDevice.Flows.Items
640 changedFow, updatedFlows = agent.getUpdatedFlowsAfterDeletebyMeterId(flows, meterMod.MeterId)
641 meters = append(meters[:index], meters[index+1:]...)
642 log.Debugw("Meter has been deleted", log.Fields{"meter": meter, "index": index})
643 changedMeter = true
644 break
645 }
646 }
647 if changedMeter {
648 //Update model
649 metersToUpdate := &ofp.Meters{}
650 if lDevice.Meters != nil {
651 metersToUpdate = &ofp.Meters{Items: meters}
652 }
653 if err := agent.updateLogicalDeviceMetersWithoutLock(metersToUpdate); err != nil {
654 log.Errorw("db-meter-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
655 return err
656 }
657 log.Debug("Meter-deleted-from-DB-successfully", log.Fields{"updatedMeters": metersToUpdate, "no-of-meter": len(metersToUpdate.Items)})
658
659 }
660 if changedFow {
661 //Update model
662 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: updatedFlows}); err != nil {
663 log.Errorw("db-flow-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
664 return err
665 }
666 log.Debug("Flows-associated-with-meter-deleted-from-DB-successfully",
667 log.Fields{"updated-no-of-flows": len(updatedFlows), "meter": meterMod.MeterId})
668 }
669 log.Debugw("meterDelete success", log.Fields{"meterID": meterMod.MeterId})
670 return nil
671}
672
673func (agent *LogicalDeviceAgent) meterModify(meterMod *ofp.OfpMeterMod) error {
674 log.Debug("meterModify")
675 if meterMod == nil {
676 return nil
677 }
678 agent.lockLogicalDevice.Lock()
679 defer agent.lockLogicalDevice.Unlock()
680
681 var lDevice *voltha.LogicalDevice
682 var err error
683 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
684 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
685 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
686 }
687
688 var meters []*ofp.OfpMeterEntry
689 if lDevice.Meters != nil && lDevice.Meters.Items != nil {
690 meters = lDevice.Meters.Items
691 }
692 changedMeter := false
693 for index, meter := range meters {
694 if meterMod.MeterId == meter.Config.MeterId {
695 newmeterEntry := fu.MeterEntryFromMeterMod(meterMod)
696 newmeterEntry.Stats.FlowCount = meter.Stats.FlowCount
697 meters[index] = newmeterEntry
698 changedMeter = true
699 log.Debugw("Found meter, replaced with new meter", log.Fields{"old meter": meter, "new meter": newmeterEntry})
700 break
701 }
702 }
703 if changedMeter {
704 //Update model
705 metersToUpdate := &ofp.Meters{}
706 if lDevice.Meters != nil {
707 metersToUpdate = &ofp.Meters{Items: meters}
708 }
709 if err := agent.updateLogicalDeviceMetersWithoutLock(metersToUpdate); err != nil {
710 log.Errorw("db-meter-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
711 return err
712 }
713 log.Debugw("meter-updated-in-DB-successfully", log.Fields{"updated_meters": meters})
714 return nil
715 }
716
717 log.Errorw("Meter not found ", log.Fields{"meter": meterMod})
718 return errors.New(fmt.Sprintf("no-logical-device-present:%d", meterMod.MeterId))
719
720}
721
722func (agent *LogicalDeviceAgent) getUpdatedFlowsAfterDeletebyMeterId(flows []*ofp.OfpFlowStats, meterId uint32) (bool, []*ofp.OfpFlowStats) {
723 log.Infow("Delete flows matching meter", log.Fields{"meter": meterId})
724 changed := false
725 //updatedFlows := make([]*ofp.OfpFlowStats, 0)
726 for index := len(flows) - 1; index >= 0; index-- {
727 if mId := fu.GetMeterIdFromFlow(flows[index]); mId != 0 && mId == meterId {
728 log.Debugw("Flow to be deleted", log.Fields{"flow": flows[index], "index": index})
729 flows = append(flows[:index], flows[index+1:]...)
730 changed = true
731 }
732 }
733 return changed, flows
734}
735
736func (agent *LogicalDeviceAgent) updateFlowCountOfMeterStats(modCommand *ofp.OfpFlowMod, meters []*ofp.OfpMeterEntry, flow *ofp.OfpFlowStats) bool {
737
738 flowCommand := modCommand.GetCommand()
739 meterId := fu.GetMeterIdFromFlow(flow)
740 log.Debugw("Meter-id-in-flow-mod", log.Fields{"meterId": meterId})
741 if meterId == 0 {
742 log.Debugw("No meter present in the flow", log.Fields{"flow": *flow})
743 return false
744 }
745 if meters == nil {
746 log.Debug("No meters present in logical device")
747 return false
748 }
749 changedMeter := false
750 for _, meter := range meters {
751 if meterId == meter.Config.MeterId { // Found meter in Logicaldevice
752 if flowCommand == ofp.OfpFlowModCommand_OFPFC_ADD {
753 meter.Stats.FlowCount += 1
754 changedMeter = true
755 } else if flowCommand == ofp.OfpFlowModCommand_OFPFC_DELETE_STRICT {
756 meter.Stats.FlowCount -= 1
757 changedMeter = true
758 }
759 log.Debugw("Found meter, updated meter flow stats", log.Fields{" meterId": meterId})
760 break
761 }
762 }
763 return changedMeter
764}
765
khenaidoo19d7b632018-10-30 10:49:50 -0400766//flowAdd adds a flow to the flow table of that logical device
767func (agent *LogicalDeviceAgent) flowAdd(mod *ofp.OfpFlowMod) error {
768 log.Debug("flowAdd")
769 if mod == nil {
770 return nil
771 }
khenaidoo92e62c52018-10-03 14:02:54 -0400772 agent.lockLogicalDevice.Lock()
773 defer agent.lockLogicalDevice.Unlock()
khenaidoo19d7b632018-10-30 10:49:50 -0400774
775 var lDevice *voltha.LogicalDevice
776 var err error
777 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
778 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
779 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
780 }
781
782 var flows []*ofp.OfpFlowStats
Manikkaraj kb1a10922019-07-29 12:10:34 -0400783 var meters []*ofp.OfpMeterEntry
784 var flow *ofp.OfpFlowStats
785
khenaidoo19d7b632018-10-30 10:49:50 -0400786 if lDevice.Flows != nil && lDevice.Flows.Items != nil {
787 flows = lDevice.Flows.Items
788 }
789
Manikkaraj kb1a10922019-07-29 12:10:34 -0400790 if lDevice.Meters != nil && lDevice.Meters.Items != nil {
791 meters = lDevice.Meters.Items
792 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400793 updatedFlows := make([]*ofp.OfpFlowStats, 0)
khenaidoo19d7b632018-10-30 10:49:50 -0400794 changed := false
Manikkaraj kb1a10922019-07-29 12:10:34 -0400795 updated := false
khenaidoo19d7b632018-10-30 10:49:50 -0400796 checkOverlap := (mod.Flags & uint32(ofp.OfpFlowModFlags_OFPFF_CHECK_OVERLAP)) != 0
797 if checkOverlap {
798 if overlapped := fu.FindOverlappingFlows(flows, mod); len(overlapped) != 0 {
799 // TODO: should this error be notified other than being logged?
800 log.Warnw("overlapped-flows", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
801 } else {
802 // Add flow
Manikkaraj kb1a10922019-07-29 12:10:34 -0400803 flow = fu.FlowStatsEntryFromFlowModMessage(mod)
khenaidoo19d7b632018-10-30 10:49:50 -0400804 flows = append(flows, flow)
khenaidoo2c6a0992019-04-29 13:46:56 -0400805 updatedFlows = append(updatedFlows, flow)
khenaidoo19d7b632018-10-30 10:49:50 -0400806 changed = true
807 }
808 } else {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400809 flow = fu.FlowStatsEntryFromFlowModMessage(mod)
khenaidoo19d7b632018-10-30 10:49:50 -0400810 idx := fu.FindFlows(flows, flow)
811 if idx >= 0 {
812 oldFlow := flows[idx]
813 if (mod.Flags & uint32(ofp.OfpFlowModFlags_OFPFF_RESET_COUNTS)) != 0 {
814 flow.ByteCount = oldFlow.ByteCount
815 flow.PacketCount = oldFlow.PacketCount
816 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400817 if !reflect.DeepEqual(oldFlow, flow) {
818 flows[idx] = flow
819 updatedFlows = append(updatedFlows, flow)
820 changed = true
Manikkaraj kb1a10922019-07-29 12:10:34 -0400821 updated = true
khenaidoo2c6a0992019-04-29 13:46:56 -0400822 }
khenaidoo19d7b632018-10-30 10:49:50 -0400823 } else {
824 flows = append(flows, flow)
khenaidoo2c6a0992019-04-29 13:46:56 -0400825 updatedFlows = append(updatedFlows, flow)
826 changed = true
khenaidoo19d7b632018-10-30 10:49:50 -0400827 }
khenaidoo19d7b632018-10-30 10:49:50 -0400828 }
829 if changed {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400830 var flowMetadata voltha.FlowMetadata
831 if err := agent.GetMeterConfig(updatedFlows, meters, &flowMetadata); err != nil { // This should never happen,meters should be installed before flow arrives
832 log.Error("Meter-referred-in-flows-not-present")
833 return err
834 }
khenaidoo0458db62019-06-20 08:50:36 -0400835 deviceRules := agent.flowDecomposer.DecomposeRules(agent, ofp.Flows{Items: updatedFlows}, *lDevice.FlowGroups)
836 log.Debugw("rules", log.Fields{"rules": deviceRules.String()})
837
Manikkaraj kb1a10922019-07-29 12:10:34 -0400838 if err := agent.addDeviceFlowsAndGroups(deviceRules, &flowMetadata); err != nil {
khenaidoo0458db62019-06-20 08:50:36 -0400839 log.Errorw("failure-updating-device-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "error": err})
khenaidoo2c6a0992019-04-29 13:46:56 -0400840 return err
841 }
842
khenaidoo19d7b632018-10-30 10:49:50 -0400843 // Update model
khenaidoo0458db62019-06-20 08:50:36 -0400844 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: flows}); err != nil {
khenaidoo2c6a0992019-04-29 13:46:56 -0400845 log.Errorw("db-flow-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400846 return err
847 }
Manikkaraj kb1a10922019-07-29 12:10:34 -0400848 if !updated {
849 changedMeterStats := agent.updateFlowCountOfMeterStats(mod, meters, flow)
850 metersToUpdate := &ofp.Meters{}
851 if lDevice.Meters != nil {
852 metersToUpdate = &ofp.Meters{Items: meters}
853 }
854 if changedMeterStats {
855 //Update model
856 if err := agent.updateLogicalDeviceMetersWithoutLock(metersToUpdate); err != nil {
857 log.Errorw("db-meter-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
858 return err
859 }
860 log.Debugw("meter-stats-updated-in-DB-successfully", log.Fields{"updated_meters": meters})
861
862 }
863 }
864
khenaidoo19d7b632018-10-30 10:49:50 -0400865 }
khenaidoo19d7b632018-10-30 10:49:50 -0400866 return nil
867}
868
Manikkaraj kb1a10922019-07-29 12:10:34 -0400869func (agent *LogicalDeviceAgent) GetMeterConfig(flows []*ofp.OfpFlowStats, meters []*ofp.OfpMeterEntry, metadata *voltha.FlowMetadata) error {
870 m := make(map[uint32]bool)
871 for _, flow := range flows {
872 if flowMeterID := fu.GetMeterIdFromFlow(flow); flowMeterID != 0 && m[flowMeterID] == false {
873 foundMeter := false
874 // Meter is present in the flow , Get from logical device
875 for _, meter := range meters {
876 if flowMeterID == meter.Config.MeterId {
877 metadata.Meters = append(metadata.Meters, meter.Config)
878 log.Debugw("Found meter in logical device",
879 log.Fields{"meterID": flowMeterID, "meter-band": meter.Config})
880 m[flowMeterID] = true
881 foundMeter = true
882 break
883 }
884 }
885 if !foundMeter {
886 log.Errorw("Meter-referred-by-flow-is-not-found-in-logicaldevice",
887 log.Fields{"meterID": flowMeterID, "Avaliable-meters": meters, "flow": *flow})
888 return errors.New("Meter-referred-by-flow-is-not-found-in-logicaldevice")
889 }
890 }
891 }
892 log.Debugw("meter-bands-for-flows", log.Fields{"flows": len(flows), "metadata": metadata})
893 return nil
894
895}
896
khenaidoo19d7b632018-10-30 10:49:50 -0400897//flowDelete deletes a flow from the flow table of that logical device
898func (agent *LogicalDeviceAgent) flowDelete(mod *ofp.OfpFlowMod) error {
899 log.Debug("flowDelete")
900 if mod == nil {
901 return nil
902 }
903 agent.lockLogicalDevice.Lock()
904 defer agent.lockLogicalDevice.Unlock()
905
906 var lDevice *voltha.LogicalDevice
907 var err error
908 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
909 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
910 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
911 }
khenaidoo19d7b632018-10-30 10:49:50 -0400912
Manikkaraj kb1a10922019-07-29 12:10:34 -0400913 var meters []*ofp.OfpMeterEntry
914 var flows []*ofp.OfpFlowStats
915
916 if lDevice.Flows != nil && lDevice.Flows.Items != nil {
917 flows = lDevice.Flows.Items
918 }
919
920 if lDevice.Meters != nil && lDevice.Meters.Items != nil {
921 meters = lDevice.Meters.Items
922 }
khenaidoo19d7b632018-10-30 10:49:50 -0400923 //build a list of what to keep vs what to delete
924 toKeep := make([]*ofp.OfpFlowStats, 0)
khenaidoo0458db62019-06-20 08:50:36 -0400925 toDelete := make([]*ofp.OfpFlowStats, 0)
khenaidoo19d7b632018-10-30 10:49:50 -0400926 for _, f := range flows {
khenaidoo0458db62019-06-20 08:50:36 -0400927 // Check whether the flow and the flowmod matches
928 if fu.FlowMatch(f, fu.FlowStatsEntryFromFlowModMessage(mod)) {
929 toDelete = append(toDelete, f)
930 continue
931 }
932 // Check wild card match
khenaidoo19d7b632018-10-30 10:49:50 -0400933 if !fu.FlowMatchesMod(f, mod) {
934 toKeep = append(toKeep, f)
khenaidoo0458db62019-06-20 08:50:36 -0400935 } else {
936 toDelete = append(toDelete, f)
khenaidoo19d7b632018-10-30 10:49:50 -0400937 }
938 }
939
khenaidoo0458db62019-06-20 08:50:36 -0400940 log.Debugw("flowDelete", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "toKeep": len(toKeep), "toDelete": toDelete})
941
khenaidoo19d7b632018-10-30 10:49:50 -0400942 //Update flows
khenaidoo0458db62019-06-20 08:50:36 -0400943 if len(toDelete) > 0 {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400944 var flowMetadata voltha.FlowMetadata
945 if err := agent.GetMeterConfig(toDelete, meters, &flowMetadata); err != nil { // This should never happen
946 log.Error("Meter-referred-in-flows-not-present")
947 return errors.New("Meter-referred-in-flows-not-present")
948 }
khenaidoo0458db62019-06-20 08:50:36 -0400949 deviceRules := agent.flowDecomposer.DecomposeRules(agent, ofp.Flows{Items: toDelete}, ofp.FlowGroups{})
950 log.Debugw("rules", log.Fields{"rules": deviceRules.String()})
951
Manikkaraj kb1a10922019-07-29 12:10:34 -0400952 if err := agent.deleteDeviceFlowsAndGroups(deviceRules, &flowMetadata); err != nil {
khenaidoo0458db62019-06-20 08:50:36 -0400953 log.Errorw("failure-updating-device-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "error": err})
954 return err
955 }
956
khenaidoo43c82122018-11-22 18:38:28 -0500957 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: toKeep}); err != nil {
958 log.Errorw("Cannot-update-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400959 return err
960 }
961 }
962
963 //TODO: send announcement on delete
964 return nil
965}
966
Manikkaraj kb1a10922019-07-29 12:10:34 -0400967func (agent *LogicalDeviceAgent) addDeviceFlowsAndGroups(deviceRules *fu.DeviceRules, flowMetadata *voltha.FlowMetadata) error {
968 log.Debugw("addDeviceFlowsAndGroups", log.Fields{"logicalDeviceID": agent.logicalDeviceId, "deviceRules": deviceRules, "flowMetadata": flowMetadata})
khenaidoo19d7b632018-10-30 10:49:50 -0400969
khenaidoo0458db62019-06-20 08:50:36 -0400970 chnlsList := make([]chan interface{}, 0)
971 for deviceId, value := range deviceRules.GetRules() {
972 ch := make(chan interface{})
973 chnlsList = append(chnlsList, ch)
974 go func(deviceId string, flows []*ofp.OfpFlowStats, groups []*ofp.OfpGroupEntry) {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400975 if err := agent.deviceMgr.addFlowsAndGroups(deviceId, flows, groups, flowMetadata); err != nil {
khenaidoo0458db62019-06-20 08:50:36 -0400976 log.Errorw("flow-add-failed", log.Fields{"deviceID": deviceId, "error": err})
977 ch <- status.Errorf(codes.Internal, "flow-add-failed: %s", deviceId)
978 }
979 ch <- nil
980 }(deviceId, value.ListFlows(), value.ListGroups())
khenaidoo19d7b632018-10-30 10:49:50 -0400981 }
khenaidoo0458db62019-06-20 08:50:36 -0400982 // Wait for completion
983 if res := fu.WaitForNilOrErrorResponses(agent.defaultTimeout, chnlsList...); res != nil {
984 return status.Errorf(codes.Aborted, "errors-%s", res)
khenaidoo19d7b632018-10-30 10:49:50 -0400985 }
khenaidoo0458db62019-06-20 08:50:36 -0400986 return nil
987}
khenaidoo19d7b632018-10-30 10:49:50 -0400988
Manikkaraj kb1a10922019-07-29 12:10:34 -0400989func (agent *LogicalDeviceAgent) deleteDeviceFlowsAndGroups(deviceRules *fu.DeviceRules, flowMetadata *voltha.FlowMetadata) error {
khenaidoo0458db62019-06-20 08:50:36 -0400990 log.Debugw("deleteDeviceFlowsAndGroups", log.Fields{"logicalDeviceID": agent.logicalDeviceId})
991
992 chnlsList := make([]chan interface{}, 0)
993 for deviceId, value := range deviceRules.GetRules() {
994 ch := make(chan interface{})
995 chnlsList = append(chnlsList, ch)
996 go func(deviceId string, flows []*ofp.OfpFlowStats, groups []*ofp.OfpGroupEntry) {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400997 if err := agent.deviceMgr.deleteFlowsAndGroups(deviceId, flows, groups, flowMetadata); err != nil {
khenaidoo0458db62019-06-20 08:50:36 -0400998 log.Error("flow-delete-failed", log.Fields{"deviceID": deviceId, "error": err})
999 ch <- status.Errorf(codes.Internal, "flow-delete-failed: %s", deviceId)
1000 }
1001 ch <- nil
1002 }(deviceId, value.ListFlows(), value.ListGroups())
1003 }
1004 // Wait for completion
1005 if res := fu.WaitForNilOrErrorResponses(agent.defaultTimeout, chnlsList...); res != nil {
1006 return status.Errorf(codes.Aborted, "errors-%s", res)
1007 }
1008 return nil
1009}
1010
Manikkaraj kb1a10922019-07-29 12:10:34 -04001011func (agent *LogicalDeviceAgent) updateDeviceFlowsAndGroups(deviceRules *fu.DeviceRules, flowMetadata *voltha.FlowMetadata) error {
khenaidoo0458db62019-06-20 08:50:36 -04001012 log.Debugw("updateDeviceFlowsAndGroups", log.Fields{"logicalDeviceID": agent.logicalDeviceId})
1013
1014 chnlsList := make([]chan interface{}, 0)
1015 for deviceId, value := range deviceRules.GetRules() {
1016 ch := make(chan interface{})
1017 chnlsList = append(chnlsList, ch)
1018 go func(deviceId string, flows []*ofp.OfpFlowStats, groups []*ofp.OfpGroupEntry) {
Manikkaraj kb1a10922019-07-29 12:10:34 -04001019 if err := agent.deviceMgr.updateFlowsAndGroups(deviceId, flows, groups, flowMetadata); err != nil {
khenaidoo0458db62019-06-20 08:50:36 -04001020 log.Error("flow-update-failed", log.Fields{"deviceID": deviceId, "error": err})
1021 ch <- status.Errorf(codes.Internal, "flow-update-failed: %s", deviceId)
1022 }
1023 ch <- nil
1024 }(deviceId, value.ListFlows(), value.ListGroups())
1025 }
1026 // Wait for completion
1027 if res := fu.WaitForNilOrErrorResponses(agent.defaultTimeout, chnlsList...); res != nil {
1028 return status.Errorf(codes.Aborted, "errors-%s", res)
khenaidoo19d7b632018-10-30 10:49:50 -04001029 }
1030 return nil
1031}
1032
1033//flowDeleteStrict deletes a flow from the flow table of that logical device
1034func (agent *LogicalDeviceAgent) flowDeleteStrict(mod *ofp.OfpFlowMod) error {
1035 log.Debug("flowDeleteStrict")
1036 if mod == nil {
1037 return nil
1038 }
1039 agent.lockLogicalDevice.Lock()
1040 defer agent.lockLogicalDevice.Unlock()
1041
1042 var lDevice *voltha.LogicalDevice
1043 var err error
1044 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
1045 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
1046 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
1047 }
Manikkaraj kb1a10922019-07-29 12:10:34 -04001048 var meters []*ofp.OfpMeterEntry
1049 var flows []*ofp.OfpFlowStats
1050 if lDevice.Meters != nil && lDevice.Meters.Items != nil {
1051 meters = lDevice.Meters.Items
1052 }
1053 if lDevice.Flows != nil && lDevice.Flows.Items != nil {
1054 flows = lDevice.Flows.Items
1055 }
1056
1057 changedFlow := false
1058 changedMeter := false
khenaidoo68c930b2019-05-13 11:46:51 -04001059 flow := fu.FlowStatsEntryFromFlowModMessage(mod)
Manikkaraj kb1a10922019-07-29 12:10:34 -04001060 flowsToDelete := make([]*ofp.OfpFlowStats, 0)
khenaidoo19d7b632018-10-30 10:49:50 -04001061 idx := fu.FindFlows(flows, flow)
1062 if idx >= 0 {
Manikkaraj kb1a10922019-07-29 12:10:34 -04001063 changedMeter = agent.updateFlowCountOfMeterStats(mod, meters, flow)
1064 flowsToDelete = append(flowsToDelete, flows[idx])
khenaidoo19d7b632018-10-30 10:49:50 -04001065 flows = append(flows[:idx], flows[idx+1:]...)
Manikkaraj kb1a10922019-07-29 12:10:34 -04001066 changedFlow = true
khenaidoo19d7b632018-10-30 10:49:50 -04001067 } else {
1068 return errors.New(fmt.Sprintf("Cannot delete flow - %s", flow))
1069 }
Manikkaraj kb1a10922019-07-29 12:10:34 -04001070 if changedMeter {
1071 //Update model
1072 metersToUpdate := &ofp.Meters{}
1073 if lDevice.Meters != nil {
1074 metersToUpdate = &ofp.Meters{Items: meters}
1075 }
1076 if err := agent.updateLogicalDeviceMetersWithoutLock(metersToUpdate); err != nil {
1077 log.Errorw("db-meter-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
1078 return err
1079 }
khenaidoo19d7b632018-10-30 10:49:50 -04001080
Manikkaraj kb1a10922019-07-29 12:10:34 -04001081 }
1082 if changedFlow {
1083 var flowMetadata voltha.FlowMetadata
1084 if err := agent.GetMeterConfig(flowsToDelete, meters, &flowMetadata); err != nil {
1085 log.Error("Meter-referred-in-flows-not-present")
1086 return err
1087 }
1088 deviceRules := agent.flowDecomposer.DecomposeRules(agent, ofp.Flows{Items: flowsToDelete}, ofp.FlowGroups{})
khenaidoo0458db62019-06-20 08:50:36 -04001089 log.Debugw("rules", log.Fields{"rules": deviceRules.String()})
1090
Manikkaraj kb1a10922019-07-29 12:10:34 -04001091 if err := agent.deleteDeviceFlowsAndGroups(deviceRules, &flowMetadata); err != nil {
khenaidoo0458db62019-06-20 08:50:36 -04001092 log.Errorw("failure-deleting-device-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "error": err})
1093 return err
1094 }
1095
khenaidoo43c82122018-11-22 18:38:28 -05001096 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: flows}); err != nil {
khenaidoo0458db62019-06-20 08:50:36 -04001097 log.Errorw("Cannot-update-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -04001098 return err
1099 }
1100 }
khenaidoo19d7b632018-10-30 10:49:50 -04001101 return nil
1102}
1103
1104//flowModify modifies a flow from the flow table of that logical device
1105func (agent *LogicalDeviceAgent) flowModify(mod *ofp.OfpFlowMod) error {
1106 return errors.New("flowModify not implemented")
1107}
1108
1109//flowModifyStrict deletes a flow from the flow table of that logical device
1110func (agent *LogicalDeviceAgent) flowModifyStrict(mod *ofp.OfpFlowMod) error {
1111 return errors.New("flowModifyStrict not implemented")
1112}
1113
1114func (agent *LogicalDeviceAgent) groupAdd(groupMod *ofp.OfpGroupMod) error {
1115 log.Debug("groupAdd")
1116 if groupMod == nil {
1117 return nil
1118 }
1119 agent.lockLogicalDevice.Lock()
1120 defer agent.lockLogicalDevice.Unlock()
1121
1122 var lDevice *voltha.LogicalDevice
1123 var err error
1124 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
1125 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
1126 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
1127 }
1128 groups := lDevice.FlowGroups.Items
khenaidoo19d7b632018-10-30 10:49:50 -04001129 if fu.FindGroup(groups, groupMod.GroupId) == -1 {
khenaidoo68c930b2019-05-13 11:46:51 -04001130 groups = append(groups, fu.GroupEntryFromGroupMod(groupMod))
khenaidoo0458db62019-06-20 08:50:36 -04001131
1132 deviceRules := agent.flowDecomposer.DecomposeRules(agent, *lDevice.Flows, ofp.FlowGroups{Items: groups})
1133 log.Debugw("rules", log.Fields{"rules": deviceRules.String()})
Manikkaraj kb1a10922019-07-29 12:10:34 -04001134 if err := agent.addDeviceFlowsAndGroups(deviceRules, nil); err != nil {
khenaidoo0458db62019-06-20 08:50:36 -04001135 log.Errorw("failure-updating-device-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "error": err})
1136 return err
1137 }
1138
khenaidoo43c82122018-11-22 18:38:28 -05001139 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(&ofp.FlowGroups{Items: groups}); err != nil {
1140 log.Errorw("Cannot-update-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -04001141 return err
1142 }
1143 } else {
1144 return errors.New(fmt.Sprintf("Groups %d already present", groupMod.GroupId))
1145 }
khenaidoo19d7b632018-10-30 10:49:50 -04001146 return nil
1147}
1148
1149func (agent *LogicalDeviceAgent) groupDelete(groupMod *ofp.OfpGroupMod) error {
1150 log.Debug("groupDelete")
1151 if groupMod == nil {
1152 return nil
1153 }
1154 agent.lockLogicalDevice.Lock()
1155 defer agent.lockLogicalDevice.Unlock()
1156
1157 var lDevice *voltha.LogicalDevice
1158 var err error
1159 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
1160 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
1161 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
1162 }
1163 groups := lDevice.FlowGroups.Items
1164 flows := lDevice.Flows.Items
1165 groupsChanged := false
1166 flowsChanged := false
1167 groupId := groupMod.GroupId
1168 if groupId == uint32(ofp.OfpGroup_OFPG_ALL) {
1169 //TODO we must delete all flows that point to this group and
1170 //signal controller as requested by flow's flag
1171 groups = []*ofp.OfpGroupEntry{}
1172 groupsChanged = true
1173 } else {
1174 if idx := fu.FindGroup(groups, groupId); idx == -1 {
1175 return nil // Valid case
1176 } else {
1177 flowsChanged, flows = fu.FlowsDeleteByGroupId(flows, groupId)
1178 groups = append(groups[:idx], groups[idx+1:]...)
1179 groupsChanged = true
1180 }
1181 }
khenaidoo0458db62019-06-20 08:50:36 -04001182 if flowsChanged || groupsChanged {
1183 deviceRules := agent.flowDecomposer.DecomposeRules(agent, ofp.Flows{Items: flows}, ofp.FlowGroups{Items: groups})
1184 log.Debugw("rules", log.Fields{"rules": deviceRules.String()})
1185
Manikkaraj kb1a10922019-07-29 12:10:34 -04001186 if err := agent.updateDeviceFlowsAndGroups(deviceRules, nil); err != nil {
khenaidoo0458db62019-06-20 08:50:36 -04001187 log.Errorw("failure-updating-device-flows-groups", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "error": err})
1188 return err
1189 }
1190 }
1191
khenaidoo43c82122018-11-22 18:38:28 -05001192 if groupsChanged {
1193 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(&ofp.FlowGroups{Items: groups}); err != nil {
1194 log.Errorw("Cannot-update-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -04001195 return err
1196 }
1197 }
khenaidoo43c82122018-11-22 18:38:28 -05001198 if flowsChanged {
1199 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: flows}); err != nil {
1200 log.Errorw("Cannot-update-flow", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
1201 return err
1202 }
1203 }
khenaidoo19d7b632018-10-30 10:49:50 -04001204 return nil
1205}
1206
1207func (agent *LogicalDeviceAgent) groupModify(groupMod *ofp.OfpGroupMod) error {
1208 log.Debug("groupModify")
1209 if groupMod == nil {
1210 return nil
1211 }
1212 agent.lockLogicalDevice.Lock()
1213 defer agent.lockLogicalDevice.Unlock()
1214
1215 var lDevice *voltha.LogicalDevice
1216 var err error
1217 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
1218 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
1219 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
1220 }
1221 groups := lDevice.FlowGroups.Items
1222 groupsChanged := false
1223 groupId := groupMod.GroupId
1224 if idx := fu.FindGroup(groups, groupId); idx == -1 {
khenaidooca301322019-01-09 23:06:32 -05001225 return errors.New(fmt.Sprintf("group-absent:%d", groupId))
khenaidoo19d7b632018-10-30 10:49:50 -04001226 } else {
1227 //replace existing group entry with new group definition
khenaidoo68c930b2019-05-13 11:46:51 -04001228 groupEntry := fu.GroupEntryFromGroupMod(groupMod)
khenaidoo19d7b632018-10-30 10:49:50 -04001229 groups[idx] = groupEntry
1230 groupsChanged = true
1231 }
1232 if groupsChanged {
khenaidoo0458db62019-06-20 08:50:36 -04001233 deviceRules := agent.flowDecomposer.DecomposeRules(agent, ofp.Flows{Items: lDevice.Flows.Items}, ofp.FlowGroups{Items: groups})
1234 log.Debugw("rules", log.Fields{"rules": deviceRules.String()})
1235
Manikkaraj kb1a10922019-07-29 12:10:34 -04001236 if err := agent.updateDeviceFlowsAndGroups(deviceRules, nil); err != nil {
khenaidoo0458db62019-06-20 08:50:36 -04001237 log.Errorw("failure-updating-device-flows-groups", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "error": err})
1238 return err
1239 }
1240
khenaidoo43c82122018-11-22 18:38:28 -05001241 //lDevice.FlowGroups.Items = groups
1242 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(&ofp.FlowGroups{Items: groups}); err != nil {
khenaidoo19d7b632018-10-30 10:49:50 -04001243 log.Errorw("Cannot-update-logical-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
1244 return err
1245 }
1246 }
1247 return nil
1248}
1249
1250// deleteLogicalPort removes the logical port
1251func (agent *LogicalDeviceAgent) deleteLogicalPort(lPort *voltha.LogicalPort) error {
1252 agent.lockLogicalDevice.Lock()
1253 defer agent.lockLogicalDevice.Unlock()
1254
khenaidoo92e62c52018-10-03 14:02:54 -04001255 // Get the most up to date logical device
1256 var logicaldevice *voltha.LogicalDevice
1257 if logicaldevice, _ = agent.getLogicalDeviceWithoutLock(); logicaldevice == nil {
khenaidoo19d7b632018-10-30 10:49:50 -04001258 log.Debugw("no-logical-device", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "logicalPortId": lPort.Id})
khenaidoob9203542018-09-17 22:56:37 -04001259 return nil
1260 }
khenaidoo92e62c52018-10-03 14:02:54 -04001261 index := -1
1262 for i, logicalPort := range logicaldevice.Ports {
khenaidoo19d7b632018-10-30 10:49:50 -04001263 if logicalPort.Id == lPort.Id {
khenaidoo92e62c52018-10-03 14:02:54 -04001264 index = i
1265 break
1266 }
1267 }
1268 if index >= 0 {
1269 copy(logicaldevice.Ports[index:], logicaldevice.Ports[index+1:])
1270 logicaldevice.Ports[len(logicaldevice.Ports)-1] = nil
1271 logicaldevice.Ports = logicaldevice.Ports[:len(logicaldevice.Ports)-1]
1272 log.Debugw("logical-port-deleted", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo0a822f92019-05-08 15:15:57 -04001273 if err := agent.updateLogicalDeviceWithoutLock(logicaldevice); err != nil {
1274 log.Errorw("logical-device-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
1275 return err
1276 }
1277 // Reset the logical device graph
khenaidoo3d3b8c22019-05-22 18:10:39 -04001278 go agent.generateDeviceGraph()
khenaidoo92e62c52018-10-03 14:02:54 -04001279 }
1280 return nil
khenaidoob9203542018-09-17 22:56:37 -04001281}
1282
khenaidoo0a822f92019-05-08 15:15:57 -04001283// deleteLogicalPorts removes the logical ports associated with that deviceId
1284func (agent *LogicalDeviceAgent) deleteLogicalPorts(deviceId string) error {
1285 agent.lockLogicalDevice.Lock()
1286 defer agent.lockLogicalDevice.Unlock()
1287
1288 // Get the most up to date logical device
1289 var logicaldevice *voltha.LogicalDevice
1290 if logicaldevice, _ = agent.getLogicalDeviceWithoutLock(); logicaldevice == nil {
1291 log.Debugw("no-logical-device", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
1292 return nil
1293 }
1294 updatedLPorts := []*voltha.LogicalPort{}
1295 for _, logicalPort := range logicaldevice.Ports {
1296 if logicalPort.DeviceId != deviceId {
1297 updatedLPorts = append(updatedLPorts, logicalPort)
1298 }
1299 }
1300 logicaldevice.Ports = updatedLPorts
1301 log.Debugw("updated-logical-ports", log.Fields{"ports": updatedLPorts})
1302 if err := agent.updateLogicalDeviceWithoutLock(logicaldevice); err != nil {
1303 log.Errorw("logical-device-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
1304 return err
1305 }
1306 // Reset the logical device graph
khenaidoo3d3b8c22019-05-22 18:10:39 -04001307 go agent.generateDeviceGraph()
khenaidoo0a822f92019-05-08 15:15:57 -04001308
1309 return nil
1310}
1311
khenaidoo19d7b632018-10-30 10:49:50 -04001312// enableLogicalPort enables the logical port
1313func (agent *LogicalDeviceAgent) enableLogicalPort(lPort *voltha.LogicalPort) error {
1314 agent.lockLogicalDevice.Lock()
1315 defer agent.lockLogicalDevice.Unlock()
1316
1317 // Get the most up to date logical device
1318 var logicaldevice *voltha.LogicalDevice
1319 if logicaldevice, _ = agent.getLogicalDeviceWithoutLock(); logicaldevice == nil {
1320 log.Debugw("no-logical-device", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "logicalPortId": lPort.Id})
1321 return nil
1322 }
1323 index := -1
1324 for i, logicalPort := range logicaldevice.Ports {
1325 if logicalPort.Id == lPort.Id {
1326 index = i
1327 break
1328 }
1329 }
1330 if index >= 0 {
1331 logicaldevice.Ports[index].OfpPort.Config = logicaldevice.Ports[index].OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
1332 return agent.updateLogicalDeviceWithoutLock(logicaldevice)
1333 }
1334 //TODO: Trigger subsequent actions on the device
1335 return nil
1336}
1337
1338// disableLogicalPort disabled the logical port
1339func (agent *LogicalDeviceAgent) disableLogicalPort(lPort *voltha.LogicalPort) error {
1340 agent.lockLogicalDevice.Lock()
1341 defer agent.lockLogicalDevice.Unlock()
1342
1343 // Get the most up to date logical device
1344 var logicaldevice *voltha.LogicalDevice
1345 if logicaldevice, _ = agent.getLogicalDeviceWithoutLock(); logicaldevice == nil {
1346 log.Debugw("no-logical-device", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "logicalPortId": lPort.Id})
1347 return nil
1348 }
1349 index := -1
1350 for i, logicalPort := range logicaldevice.Ports {
1351 if logicalPort.Id == lPort.Id {
1352 index = i
1353 break
1354 }
1355 }
1356 if index >= 0 {
1357 logicaldevice.Ports[index].OfpPort.Config = (logicaldevice.Ports[index].OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)) | uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
1358 return agent.updateLogicalDeviceWithoutLock(logicaldevice)
1359 }
1360 //TODO: Trigger subsequent actions on the device
1361 return nil
1362}
1363
khenaidoo89b0e942018-10-21 21:11:33 -04001364func (agent *LogicalDeviceAgent) getPreCalculatedRoute(ingress, egress uint32) []graph.RouteHop {
khenaidoo19d7b632018-10-30 10:49:50 -04001365 log.Debugw("ROUTE", log.Fields{"len": len(agent.deviceGraph.Routes)})
khenaidoo89b0e942018-10-21 21:11:33 -04001366 for routeLink, route := range agent.deviceGraph.Routes {
khenaidoo19d7b632018-10-30 10:49:50 -04001367 log.Debugw("ROUTELINKS", log.Fields{"ingress": ingress, "egress": egress, "routelink": routeLink})
khenaidoo89b0e942018-10-21 21:11:33 -04001368 if ingress == routeLink.Ingress && egress == routeLink.Egress {
1369 return route
1370 }
1371 }
1372 log.Warnw("no-route", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "ingress": ingress, "egress": egress})
1373 return nil
1374}
1375
khenaidoo19d7b632018-10-30 10:49:50 -04001376func (agent *LogicalDeviceAgent) GetRoute(ingressPortNo uint32, egressPortNo uint32) []graph.RouteHop {
khenaidoo89b0e942018-10-21 21:11:33 -04001377 log.Debugw("getting-route", log.Fields{"ingress-port": ingressPortNo, "egress-port": egressPortNo})
khenaidoo89b0e942018-10-21 21:11:33 -04001378 routes := make([]graph.RouteHop, 0)
khenaidoo2c6a0992019-04-29 13:46:56 -04001379
khenaidoo19d7b632018-10-30 10:49:50 -04001380 // Note: A port value of 0 is equivalent to a nil port
1381
khenaidoo89b0e942018-10-21 21:11:33 -04001382 // Consider different possibilities
khenaidoo19d7b632018-10-30 10:49:50 -04001383 if egressPortNo != 0 && ((egressPortNo & 0x7fffffff) == uint32(ofp.OfpPortNo_OFPP_CONTROLLER)) {
khenaidoo2c6a0992019-04-29 13:46:56 -04001384 log.Debugw("controller-flow", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "logicalPortsNo": agent.logicalPortsNo})
1385 if agent.isNNIPort(ingressPortNo) {
khenaidoo89b0e942018-10-21 21:11:33 -04001386 log.Debug("returning-half-route")
1387 //This is a trap on the NNI Port
khenaidoo8f474192019-04-03 17:20:44 -04001388 if len(agent.deviceGraph.Routes) == 0 {
1389 // If there are no routes set (usually when the logical device has only NNI port(s), then just return an
1390 // internal route
khenaidoo2c6a0992019-04-29 13:46:56 -04001391 hop := graph.RouteHop{DeviceID: agent.rootDeviceId, Ingress: ingressPortNo, Egress: egressPortNo}
khenaidoo8f474192019-04-03 17:20:44 -04001392 routes = append(routes, hop)
1393 routes = append(routes, hop)
1394 return routes
1395 }
khenaidoo89b0e942018-10-21 21:11:33 -04001396 //Return a 'half' route to make the flow decomposer logic happy
1397 for routeLink, route := range agent.deviceGraph.Routes {
khenaidoo2c6a0992019-04-29 13:46:56 -04001398 if agent.isNNIPort(routeLink.Egress) {
khenaidoo89b0e942018-10-21 21:11:33 -04001399 routes = append(routes, graph.RouteHop{}) // first hop is set to empty
1400 routes = append(routes, route[1])
1401 return routes
1402 }
1403 }
khenaidoo2c6a0992019-04-29 13:46:56 -04001404 log.Warnw("no-upstream-route", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "logicalPortsNo": agent.logicalPortsNo})
khenaidoo89b0e942018-10-21 21:11:33 -04001405 return nil
1406 }
1407 //treat it as if the output port is the first NNI of the OLT
khenaidoo2c6a0992019-04-29 13:46:56 -04001408 var err error
1409 if egressPortNo, err = agent.getFirstNNIPort(); err != nil {
1410 log.Warnw("no-nni-port", log.Fields{"error": err})
1411 return nil
1412 }
khenaidoo89b0e942018-10-21 21:11:33 -04001413 }
1414 //If ingress port is not specified (nil), it may be a wildcarded
1415 //route if egress port is OFPP_CONTROLLER or a nni logical port,
1416 //in which case we need to create a half-route where only the egress
1417 //hop is filled, the first hop is nil
khenaidoo2c6a0992019-04-29 13:46:56 -04001418 if ingressPortNo == 0 && agent.isNNIPort(egressPortNo) {
khenaidoo89b0e942018-10-21 21:11:33 -04001419 // We can use the 2nd hop of any upstream route, so just find the first upstream:
1420 for routeLink, route := range agent.deviceGraph.Routes {
khenaidoo2c6a0992019-04-29 13:46:56 -04001421 if agent.isNNIPort(routeLink.Egress) {
khenaidoo89b0e942018-10-21 21:11:33 -04001422 routes = append(routes, graph.RouteHop{}) // first hop is set to empty
1423 routes = append(routes, route[1])
1424 return routes
1425 }
1426 }
khenaidoo2c6a0992019-04-29 13:46:56 -04001427 log.Warnw("no-upstream-route", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "logicalPortsNo": agent.logicalPortsNo})
khenaidoo89b0e942018-10-21 21:11:33 -04001428 return nil
1429 }
1430 //If egress port is not specified (nil), we can also can return a "half" route
khenaidoo19d7b632018-10-30 10:49:50 -04001431 if egressPortNo == 0 {
khenaidoo89b0e942018-10-21 21:11:33 -04001432 for routeLink, route := range agent.deviceGraph.Routes {
khenaidoo19d7b632018-10-30 10:49:50 -04001433 if routeLink.Ingress == ingressPortNo {
khenaidoo89b0e942018-10-21 21:11:33 -04001434 routes = append(routes, route[0])
1435 routes = append(routes, graph.RouteHop{})
1436 return routes
1437 }
1438 }
khenaidoo2c6a0992019-04-29 13:46:56 -04001439 log.Warnw("no-downstream-route", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "logicalPortsNo": agent.logicalPortsNo})
khenaidoo89b0e942018-10-21 21:11:33 -04001440 return nil
1441 }
khenaidoo89b0e942018-10-21 21:11:33 -04001442 // Return the pre-calculated route
khenaidoo19d7b632018-10-30 10:49:50 -04001443 return agent.getPreCalculatedRoute(ingressPortNo, egressPortNo)
khenaidoo89b0e942018-10-21 21:11:33 -04001444}
1445
khenaidoo3d3b8c22019-05-22 18:10:39 -04001446//GetWildcardInputPorts filters out the logical port number from the set of logical ports on the device and
1447//returns their port numbers. This function is invoked only during flow decomposition where the lock on the logical
1448//device is already held. Therefore it is safe to retrieve the logical device without lock.
khenaidoo89b0e942018-10-21 21:11:33 -04001449func (agent *LogicalDeviceAgent) GetWildcardInputPorts(excludePort ...uint32) []uint32 {
1450 lPorts := make([]uint32, 0)
1451 var exclPort uint32
1452 if len(excludePort) == 1 {
1453 exclPort = excludePort[0]
1454 }
khenaidoo3d3b8c22019-05-22 18:10:39 -04001455 if lDevice, _ := agent.getLogicalDeviceWithoutLock(); lDevice != nil {
khenaidoo89b0e942018-10-21 21:11:33 -04001456 for _, port := range lDevice.Ports {
1457 if port.OfpPort.PortNo != exclPort {
1458 lPorts = append(lPorts, port.OfpPort.PortNo)
1459 }
1460 }
1461 }
1462 return lPorts
1463}
khenaidoo19d7b632018-10-30 10:49:50 -04001464
1465func (agent *LogicalDeviceAgent) GetDeviceGraph() *graph.DeviceGraph {
1466 return agent.deviceGraph
1467}
1468
khenaidoo3306c992019-05-24 16:57:35 -04001469//updateRoutes rebuilds the device graph if not done already
khenaidoo2c6a0992019-04-29 13:46:56 -04001470func (agent *LogicalDeviceAgent) updateRoutes(device *voltha.Device, port *voltha.Port) error {
1471 log.Debugf("updateRoutes", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "device": device.Id, "port": port})
khenaidoo910204f2019-04-08 17:56:40 -04001472 agent.lockLogicalDevice.Lock()
1473 defer agent.lockLogicalDevice.Unlock()
khenaidoo19d7b632018-10-30 10:49:50 -04001474 if agent.deviceGraph == nil {
khenaidoo910204f2019-04-08 17:56:40 -04001475 agent.deviceGraph = graph.NewDeviceGraph(agent.logicalDeviceId, agent.deviceMgr.GetDevice)
khenaidoo2c6a0992019-04-29 13:46:56 -04001476 }
1477 // Get all the logical ports on that logical device
1478 if lDevice, err := agent.getLogicalDeviceWithoutLock(); err != nil {
manikkaraj k259a6f72019-05-06 09:55:44 -04001479 log.Errorw("unknown-logical-device", log.Fields{"error": err, "logicalDeviceId": agent.logicalDeviceId})
khenaidoo2c6a0992019-04-29 13:46:56 -04001480 return err
1481 } else {
1482 //TODO: Find a better way to refresh only missing routes
1483 agent.deviceGraph.ComputeRoutes(lDevice.Ports)
1484 }
khenaidoo2c6a0992019-04-29 13:46:56 -04001485 agent.deviceGraph.Print()
1486 return nil
khenaidoo19d7b632018-10-30 10:49:50 -04001487}
1488
khenaidoo2c6a0992019-04-29 13:46:56 -04001489//updateDeviceGraph updates the device graph if not done already and setup the default rules as well
khenaidoo910204f2019-04-08 17:56:40 -04001490func (agent *LogicalDeviceAgent) updateDeviceGraph(lp *voltha.LogicalPort) {
khenaidoo2c6a0992019-04-29 13:46:56 -04001491 log.Debugf("updateDeviceGraph", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
1492 agent.lockLogicalDevice.Lock()
1493 defer agent.lockLogicalDevice.Unlock()
khenaidoo910204f2019-04-08 17:56:40 -04001494 if agent.deviceGraph == nil {
1495 agent.deviceGraph = graph.NewDeviceGraph(agent.logicalDeviceId, agent.deviceMgr.GetDevice)
1496 }
1497 agent.deviceGraph.AddPort(lp)
khenaidoo2c6a0992019-04-29 13:46:56 -04001498 agent.deviceGraph.Print()
khenaidoo19d7b632018-10-30 10:49:50 -04001499}
khenaidoofdbad6e2018-11-06 22:26:38 -05001500
khenaidoo3d3b8c22019-05-22 18:10:39 -04001501//generateDeviceGraph regenerates the device graph
1502func (agent *LogicalDeviceAgent) generateDeviceGraph() {
1503 log.Debugf("generateDeviceGraph", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo0a822f92019-05-08 15:15:57 -04001504 agent.lockLogicalDevice.Lock()
1505 defer agent.lockLogicalDevice.Unlock()
1506 // Get the latest logical device
1507 if ld, err := agent.getLogicalDeviceWithoutLock(); err != nil {
1508 log.Errorw("logical-device-not-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "error": err})
1509 } else {
khenaidoo3d3b8c22019-05-22 18:10:39 -04001510 log.Debugw("generating-graph", log.Fields{"lDeviceId": agent.logicalDeviceId, "deviceGraph": agent.deviceGraph, "lPorts": len(ld.Ports)})
1511 if agent.deviceGraph == nil {
1512 agent.deviceGraph = graph.NewDeviceGraph(agent.logicalDeviceId, agent.deviceMgr.GetDevice)
1513 }
khenaidoo0a822f92019-05-08 15:15:57 -04001514 agent.deviceGraph.ComputeRoutes(ld.Ports)
khenaidoo3d3b8c22019-05-22 18:10:39 -04001515 agent.deviceGraph.Print()
khenaidoo0a822f92019-05-08 15:15:57 -04001516 }
1517}
1518
khenaidoofc1314d2019-03-14 09:34:21 -04001519// portAdded is a callback invoked when a port is added to the logical device.
1520// TODO: To use when POST_ADD is fixed.
1521func (agent *LogicalDeviceAgent) portAdded(args ...interface{}) interface{} {
1522 log.Debugw("portAdded-callback", log.Fields{"argsLen": len(args)})
1523
1524 var port *voltha.LogicalPort
1525
1526 // Sanity check
1527 if args[0] != nil {
1528 log.Warnw("previous-data-not-nil", log.Fields{"args0": args[0]})
1529 }
1530 var ok bool
1531 if port, ok = args[1].(*voltha.LogicalPort); !ok {
1532 log.Errorw("invalid-args", log.Fields{"args1": args[1]})
1533 return nil
1534 }
1535
1536 // Set the proxy and callback for that port
1537 agent.portProxiesLock.Lock()
Stephane Barbarie40fd3b22019-04-23 21:50:47 -04001538 agent.portProxies[port.Id] = agent.clusterDataProxy.CreateProxy(
Stephane Barbarieef6650d2019-07-18 12:15:09 -04001539 context.Background(),
khenaidoofc1314d2019-03-14 09:34:21 -04001540 fmt.Sprintf("/logical_devices/%s/ports/%s", agent.logicalDeviceId, port.Id),
1541 false)
1542 agent.portProxies[port.Id].RegisterCallback(model.POST_UPDATE, agent.portUpdated)
1543 agent.portProxiesLock.Unlock()
1544
1545 // Send the port change event to the OF controller
1546 agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceId,
khenaidoo910204f2019-04-08 17:56:40 -04001547 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_ADD, Desc: port.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001548
1549 return nil
1550}
1551
1552// portRemoved is a callback invoked when a port is removed from the logical device.
1553// TODO: To use when POST_ADD is fixed.
1554func (agent *LogicalDeviceAgent) portRemoved(args ...interface{}) interface{} {
1555 log.Debugw("portRemoved-callback", log.Fields{"argsLen": len(args)})
1556
1557 var port *voltha.LogicalPort
1558
1559 // Sanity check
1560 if args[1] != nil {
1561 log.Warnw("data-not-nil", log.Fields{"args1": args[1]})
1562 }
1563 var ok bool
1564 if port, ok = args[0].(*voltha.LogicalPort); !ok {
1565 log.Errorw("invalid-args", log.Fields{"args0": args[0]})
1566 return nil
1567 }
1568
1569 // Remove the proxy and callback for that port
1570 agent.portProxiesLock.Lock()
1571 agent.portProxies[port.Id].UnregisterCallback(model.POST_UPDATE, agent.portUpdated)
1572 delete(agent.portProxies, port.Id)
1573 agent.portProxiesLock.Unlock()
1574
1575 // Send the port change event to the OF controller
1576 agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceId,
khenaidoo910204f2019-04-08 17:56:40 -04001577 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_DELETE, Desc: port.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001578
1579 return nil
1580}
1581
1582// 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 -04001583func diff(oldList, newList []*voltha.LogicalPort) (newPorts, changedPorts, deletedPorts []*voltha.LogicalPort) {
khenaidoofc1314d2019-03-14 09:34:21 -04001584 newPorts = make([]*voltha.LogicalPort, 0)
1585 changedPorts = make([]*voltha.LogicalPort, 0)
1586 deletedPorts = make([]*voltha.LogicalPort, 0)
1587 for _, o := range oldList {
1588 found := false
khenaidoofc1314d2019-03-14 09:34:21 -04001589 for _, n := range newList {
1590 if o.Id == n.Id {
khenaidoofc1314d2019-03-14 09:34:21 -04001591 found = true
1592 break
1593 }
1594 }
1595 if !found {
1596 deletedPorts = append(deletedPorts, o)
1597 }
khenaidoofc1314d2019-03-14 09:34:21 -04001598 }
1599 for _, n := range newList {
1600 found := false
khenaidoo2bc48282019-07-16 18:13:46 -04001601 changed := false
khenaidoofc1314d2019-03-14 09:34:21 -04001602 for _, o := range oldList {
1603 if o.Id == n.Id {
khenaidoo2bc48282019-07-16 18:13:46 -04001604 changed = !reflect.DeepEqual(o, n)
khenaidoofc1314d2019-03-14 09:34:21 -04001605 found = true
1606 break
1607 }
1608 }
1609 if !found {
1610 newPorts = append(newPorts, n)
1611 }
khenaidoo2bc48282019-07-16 18:13:46 -04001612 if changed {
1613 changedPorts = append(changedPorts, n)
1614 }
khenaidoofc1314d2019-03-14 09:34:21 -04001615 }
1616 return
1617}
1618
1619// portUpdated is invoked when a port is updated on the logical device. Until
1620// the POST_ADD notification is fixed, we will use the logical device to
1621// update that data.
1622func (agent *LogicalDeviceAgent) portUpdated(args ...interface{}) interface{} {
1623 log.Debugw("portUpdated-callback", log.Fields{"argsLen": len(args)})
1624
1625 var oldLD *voltha.LogicalDevice
1626 var newlD *voltha.LogicalDevice
1627
1628 var ok bool
1629 if oldLD, ok = args[0].(*voltha.LogicalDevice); !ok {
1630 log.Errorw("invalid-args", log.Fields{"args0": args[0]})
1631 return nil
1632 }
1633 if newlD, ok = args[1].(*voltha.LogicalDevice); !ok {
1634 log.Errorw("invalid-args", log.Fields{"args1": args[1]})
1635 return nil
1636 }
1637
1638 if reflect.DeepEqual(oldLD.Ports, newlD.Ports) {
1639 log.Debug("ports-have-not-changed")
1640 return nil
1641 }
1642
1643 // Get the difference between the two list
1644 newPorts, changedPorts, deletedPorts := diff(oldLD.Ports, newlD.Ports)
1645
1646 // Send the port change events to the OF controller
khenaidoo2c6a0992019-04-29 13:46:56 -04001647 for _, newP := range newPorts {
khenaidoofc1314d2019-03-14 09:34:21 -04001648 go agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceId,
khenaidoo2c6a0992019-04-29 13:46:56 -04001649 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_ADD, Desc: newP.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001650 }
1651 for _, change := range changedPorts {
1652 go agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceId,
khenaidoo910204f2019-04-08 17:56:40 -04001653 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_MODIFY, Desc: change.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001654 }
1655 for _, del := range deletedPorts {
1656 go agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceId,
khenaidoo910204f2019-04-08 17:56:40 -04001657 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_DELETE, Desc: del.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001658 }
1659
1660 return nil
1661}
1662
khenaidoo8f474192019-04-03 17:20:44 -04001663// addNNILogicalPort adds an NNI port to the logical device. It returns a bool representing whether a port has been
1664// added and an eror in case a valid error is encountered. If the port was successfully added it will return
1665// (true, nil). If the device is not in the correct state it will return (false, nil) as this is a valid
1666// scenario. This also applies to the case where the port was already added.
khenaidoo910204f2019-04-08 17:56:40 -04001667func (agent *LogicalDeviceAgent) addNNILogicalPort(device *voltha.Device, port *voltha.Port) (bool, error) {
khenaidoo1ce37ad2019-03-24 22:07:24 -04001668 log.Debugw("addNNILogicalPort", log.Fields{"NNI": port})
khenaidoo8f474192019-04-03 17:20:44 -04001669 if device.AdminState != voltha.AdminState_ENABLED || device.OperStatus != voltha.OperStatus_ACTIVE {
1670 log.Infow("device-not-ready", log.Fields{"deviceId": device.Id, "admin": device.AdminState, "oper": device.OperStatus})
1671 return false, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001672 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001673 agent.lockLogicalDevice.RLock()
1674 if agent.portExist(device, port) {
1675 log.Debugw("port-already-exist", log.Fields{"port": port})
1676 agent.lockLogicalDevice.RUnlock()
khenaidoo8f474192019-04-03 17:20:44 -04001677 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001678 }
1679 agent.lockLogicalDevice.RUnlock()
1680
khenaidoofc1314d2019-03-14 09:34:21 -04001681 var portCap *ic.PortCapability
1682 var err error
1683 // First get the port capability
1684 if portCap, err = agent.deviceMgr.getPortCapability(nil, device.Id, port.PortNo); err != nil {
1685 log.Errorw("error-retrieving-port-capabilities", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001686 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001687 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001688
1689 agent.lockLogicalDevice.Lock()
1690 defer agent.lockLogicalDevice.Unlock()
1691 // Double check again if this port has been already added since the getPortCapability could have taken a long time
1692 if agent.portExist(device, port) {
1693 log.Debugw("port-already-exist", log.Fields{"port": port})
khenaidoo8f474192019-04-03 17:20:44 -04001694 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001695 }
1696
khenaidoofc1314d2019-03-14 09:34:21 -04001697 portCap.Port.RootPort = true
1698 lp := (proto.Clone(portCap.Port)).(*voltha.LogicalPort)
1699 lp.DeviceId = device.Id
1700 lp.Id = fmt.Sprintf("nni-%d", port.PortNo)
1701 lp.OfpPort.PortNo = port.PortNo
1702 lp.OfpPort.Name = lp.Id
1703 lp.DevicePortNo = port.PortNo
1704
khenaidoofc1314d2019-03-14 09:34:21 -04001705 var ld *voltha.LogicalDevice
1706 if ld, err = agent.getLogicalDeviceWithoutLock(); err != nil {
1707 log.Errorw("error-retrieving-logical-device", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001708 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001709 }
1710 cloned := (proto.Clone(ld)).(*voltha.LogicalDevice)
1711 if cloned.Ports == nil {
1712 cloned.Ports = make([]*voltha.LogicalPort, 0)
1713 }
1714 cloned.Ports = append(cloned.Ports, lp)
1715
1716 if err = agent.updateLogicalDeviceWithoutLock(cloned); err != nil {
1717 log.Errorw("error-updating-logical-device", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001718 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001719 }
khenaidoo910204f2019-04-08 17:56:40 -04001720
1721 // Update the device graph with this new logical port
1722 clonedLP := (proto.Clone(lp)).(*voltha.LogicalPort)
1723 go agent.updateDeviceGraph(clonedLP)
1724
khenaidoo8f474192019-04-03 17:20:44 -04001725 return true, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001726}
1727
khenaidoo910204f2019-04-08 17:56:40 -04001728func (agent *LogicalDeviceAgent) portExist(device *voltha.Device, port *voltha.Port) bool {
khenaidoo54544ae2019-03-18 13:22:39 -04001729 if ldevice, _ := agent.getLogicalDeviceWithoutLock(); ldevice != nil {
khenaidoofc1314d2019-03-14 09:34:21 -04001730 for _, lPort := range ldevice.Ports {
khenaidoo54544ae2019-03-18 13:22:39 -04001731 if lPort.DeviceId == device.Id && lPort.DevicePortNo == port.PortNo && lPort.Id == port.Label {
khenaidoofc1314d2019-03-14 09:34:21 -04001732 return true
1733 }
1734 }
1735 }
1736 return false
1737}
1738
khenaidoo8f474192019-04-03 17:20:44 -04001739// addUNILogicalPort adds an UNI port to the logical device. It returns a bool representing whether a port has been
1740// added and an eror in case a valid error is encountered. If the port was successfully added it will return
1741// (true, nil). If the device is not in the correct state it will return (false, nil) as this is a valid
1742// scenario. This also applies to the case where the port was already added.
khenaidoo910204f2019-04-08 17:56:40 -04001743func (agent *LogicalDeviceAgent) addUNILogicalPort(childDevice *voltha.Device, port *voltha.Port) (bool, error) {
khenaidoofc1314d2019-03-14 09:34:21 -04001744 log.Debugw("addUNILogicalPort", log.Fields{"port": port})
khenaidoo8f474192019-04-03 17:20:44 -04001745 if childDevice.AdminState != voltha.AdminState_ENABLED || childDevice.OperStatus != voltha.OperStatus_ACTIVE {
1746 log.Infow("device-not-ready", log.Fields{"deviceId": childDevice.Id, "admin": childDevice.AdminState, "oper": childDevice.OperStatus})
1747 return false, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001748 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001749 agent.lockLogicalDevice.RLock()
1750 if agent.portExist(childDevice, port) {
1751 log.Debugw("port-already-exist", log.Fields{"port": port})
1752 agent.lockLogicalDevice.RUnlock()
khenaidoo8f474192019-04-03 17:20:44 -04001753 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001754 }
1755 agent.lockLogicalDevice.RUnlock()
khenaidoofc1314d2019-03-14 09:34:21 -04001756 var portCap *ic.PortCapability
1757 var err error
1758 // First get the port capability
1759 if portCap, err = agent.deviceMgr.getPortCapability(nil, childDevice.Id, port.PortNo); err != nil {
1760 log.Errorw("error-retrieving-port-capabilities", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001761 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001762 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001763 agent.lockLogicalDevice.Lock()
1764 defer agent.lockLogicalDevice.Unlock()
1765 // Double check again if this port has been already added since the getPortCapability could have taken a long time
1766 if agent.portExist(childDevice, port) {
1767 log.Debugw("port-already-exist", log.Fields{"port": port})
khenaidoo8f474192019-04-03 17:20:44 -04001768 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001769 }
khenaidoofc1314d2019-03-14 09:34:21 -04001770 // Get stored logical device
1771 if ldevice, err := agent.getLogicalDeviceWithoutLock(); err != nil {
khenaidoo8f474192019-04-03 17:20:44 -04001772 return false, status.Error(codes.NotFound, agent.logicalDeviceId)
khenaidoofc1314d2019-03-14 09:34:21 -04001773 } else {
1774 log.Debugw("adding-uni", log.Fields{"deviceId": childDevice.Id})
1775 portCap.Port.RootPort = false
Matt Jeanneret3815e322019-03-12 19:15:49 -04001776 portCap.Port.Id = port.Label
1777 portCap.Port.OfpPort.PortNo = port.PortNo
khenaidoofc1314d2019-03-14 09:34:21 -04001778 portCap.Port.DeviceId = childDevice.Id
1779 portCap.Port.DevicePortNo = port.PortNo
1780 cloned := (proto.Clone(ldevice)).(*voltha.LogicalDevice)
1781 if cloned.Ports == nil {
1782 cloned.Ports = make([]*voltha.LogicalPort, 0)
1783 }
1784 cloned.Ports = append(cloned.Ports, portCap.Port)
khenaidoo910204f2019-04-08 17:56:40 -04001785 if err := agent.updateLogicalDeviceWithoutLock(cloned); err != nil {
1786 return false, err
1787 }
khenaidoo910204f2019-04-08 17:56:40 -04001788 // Update the device graph with this new logical port
1789 clonedLP := (proto.Clone(portCap.Port)).(*voltha.LogicalPort)
1790 go agent.updateDeviceGraph(clonedLP)
1791 return true, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001792 }
1793}
1794
khenaidoo43c82122018-11-22 18:38:28 -05001795func (agent *LogicalDeviceAgent) packetOut(packet *ofp.OfpPacketOut) {
khenaidoofdbad6e2018-11-06 22:26:38 -05001796 log.Debugw("packet-out", log.Fields{"packet": packet.GetInPort()})
khenaidoo68c930b2019-05-13 11:46:51 -04001797 outPort := fu.GetPacketOutPort(packet)
khenaidoofdbad6e2018-11-06 22:26:38 -05001798 //frame := packet.GetData()
1799 //TODO: Use a channel between the logical agent and the device agent
khenaidooca301322019-01-09 23:06:32 -05001800 if err := agent.deviceMgr.packetOut(agent.rootDeviceId, outPort, packet); err != nil {
khenaidoo910204f2019-04-08 17:56:40 -04001801 log.Error("packetout-failed", log.Fields{"logicalDeviceID": agent.rootDeviceId})
khenaidooca301322019-01-09 23:06:32 -05001802 }
khenaidoofdbad6e2018-11-06 22:26:38 -05001803}
1804
khenaidoo297cd252019-02-07 22:10:23 -05001805func (agent *LogicalDeviceAgent) packetIn(port uint32, transactionId string, packet []byte) {
1806 log.Debugw("packet-in", log.Fields{"port": port, "packet": packet, "transactionId": transactionId})
khenaidoo68c930b2019-05-13 11:46:51 -04001807 packetIn := fu.MkPacketIn(port, packet)
khenaidoo297cd252019-02-07 22:10:23 -05001808 agent.ldeviceMgr.grpcNbiHdlr.sendPacketIn(agent.logicalDeviceId, transactionId, packetIn)
khenaidooca301322019-01-09 23:06:32 -05001809 log.Debugw("sending-packet-in", log.Fields{"packet-in": packetIn})
khenaidoofdbad6e2018-11-06 22:26:38 -05001810}
khenaidoo2c6a0992019-04-29 13:46:56 -04001811
1812func (agent *LogicalDeviceAgent) addLogicalPortToMap(portNo uint32, nniPort bool) {
1813 agent.lockLogicalPortsNo.Lock()
1814 defer agent.lockLogicalPortsNo.Unlock()
1815 if exist := agent.logicalPortsNo[portNo]; !exist {
1816 agent.logicalPortsNo[portNo] = nniPort
1817 }
1818}
1819
khenaidoo3d3b8c22019-05-22 18:10:39 -04001820func (agent *LogicalDeviceAgent) addLogicalPortsToMap(lps []*voltha.LogicalPort) {
1821 agent.lockLogicalPortsNo.Lock()
1822 defer agent.lockLogicalPortsNo.Unlock()
1823 for _, lp := range lps {
1824 if exist := agent.logicalPortsNo[lp.DevicePortNo]; !exist {
1825 agent.logicalPortsNo[lp.DevicePortNo] = lp.RootPort
1826 }
1827 }
1828}
1829
khenaidoo2c6a0992019-04-29 13:46:56 -04001830func (agent *LogicalDeviceAgent) deleteLogicalPortFromMap(portNo uint32) {
1831 agent.lockLogicalPortsNo.Lock()
1832 defer agent.lockLogicalPortsNo.Unlock()
1833 if exist := agent.logicalPortsNo[portNo]; exist {
1834 delete(agent.logicalPortsNo, portNo)
1835 }
1836}
1837
1838func (agent *LogicalDeviceAgent) isNNIPort(portNo uint32) bool {
1839 agent.lockLogicalPortsNo.RLock()
1840 defer agent.lockLogicalPortsNo.RUnlock()
1841 if exist := agent.logicalPortsNo[portNo]; exist {
1842 return agent.logicalPortsNo[portNo]
1843 }
1844 return false
1845}
1846
1847func (agent *LogicalDeviceAgent) getFirstNNIPort() (uint32, error) {
1848 agent.lockLogicalPortsNo.RLock()
1849 defer agent.lockLogicalPortsNo.RUnlock()
1850 for portNo, nni := range agent.logicalPortsNo {
1851 if nni {
1852 return portNo, nil
1853 }
1854 }
1855 return 0, status.Error(codes.NotFound, "No NNI port found")
1856}