blob: c36e1a2e249bfb87fcd0a7bbe2e32de797927ac9 [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"
khenaidoo89b0e942018-10-21 21:11:33 -040023 fd "github.com/opencord/voltha-go/rw_core/flow_decomposition"
24 "github.com/opencord/voltha-go/rw_core/graph"
Scott Bakerb671a862019-10-24 10:53:40 -070025 coreutils "github.com/opencord/voltha-go/rw_core/utils"
Scott Bakercb7c88a2019-10-16 18:32:48 -070026 "github.com/opencord/voltha-lib-go/pkg/db/model"
Scott Bakerb671a862019-10-24 10:53:40 -070027 fu "github.com/opencord/voltha-lib-go/pkg/flows"
Scott Bakercb7c88a2019-10-16 18:32:48 -070028 "github.com/opencord/voltha-lib-go/pkg/log"
khenaidoo8f474192019-04-03 17:20:44 -040029 ic "github.com/opencord/voltha-protos/go/inter_container"
30 ofp "github.com/opencord/voltha-protos/go/openflow_13"
31 "github.com/opencord/voltha-protos/go/voltha"
khenaidoob9203542018-09-17 22:56:37 -040032 "google.golang.org/grpc/codes"
33 "google.golang.org/grpc/status"
khenaidoo19d7b632018-10-30 10:49:50 -040034 "reflect"
khenaidoo92e62c52018-10-03 14:02:54 -040035 "sync"
Stephane Barbarieef6650d2019-07-18 12:15:09 -040036 "time"
khenaidoob9203542018-09-17 22:56:37 -040037)
38
39type LogicalDeviceAgent struct {
khenaidoo3306c992019-05-24 16:57:35 -040040 logicalDeviceId string
41 rootDeviceId string
42 deviceMgr *DeviceManager
43 ldeviceMgr *LogicalDeviceManager
44 clusterDataProxy *model.Proxy
45 exitChannel chan int
46 deviceGraph *graph.DeviceGraph
47 flowProxy *model.Proxy
48 groupProxy *model.Proxy
Manikkaraj kb1a10922019-07-29 12:10:34 -040049 meterProxy *model.Proxy
khenaidoo3306c992019-05-24 16:57:35 -040050 ldProxy *model.Proxy
51 portProxies map[string]*model.Proxy
52 portProxiesLock sync.RWMutex
53 lockLogicalDevice sync.RWMutex
khenaidoo4c9e5592019-09-09 16:20:41 -040054 lockDeviceGraph sync.RWMutex
khenaidoo3306c992019-05-24 16:57:35 -040055 logicalPortsNo map[uint32]bool //value is true for NNI port
56 lockLogicalPortsNo sync.RWMutex
57 flowDecomposer *fd.FlowDecomposer
58 defaultTimeout int64
khenaidoob9203542018-09-17 22:56:37 -040059}
60
Stephane Barbarie1ab43272018-12-08 21:42:13 -050061func newLogicalDeviceAgent(id string, deviceId string, ldeviceMgr *LogicalDeviceManager,
62 deviceMgr *DeviceManager,
khenaidoo2c6a0992019-04-29 13:46:56 -040063 cdProxy *model.Proxy, timeout int64) *LogicalDeviceAgent {
khenaidoob9203542018-09-17 22:56:37 -040064 var agent LogicalDeviceAgent
65 agent.exitChannel = make(chan int, 1)
66 agent.logicalDeviceId = id
Stephane Barbarie1ab43272018-12-08 21:42:13 -050067 agent.rootDeviceId = deviceId
khenaidoob9203542018-09-17 22:56:37 -040068 agent.deviceMgr = deviceMgr
khenaidoo9a468962018-09-19 15:33:13 -040069 agent.clusterDataProxy = cdProxy
khenaidoob9203542018-09-17 22:56:37 -040070 agent.ldeviceMgr = ldeviceMgr
khenaidoo19d7b632018-10-30 10:49:50 -040071 agent.flowDecomposer = fd.NewFlowDecomposer(agent.deviceMgr)
khenaidoo92e62c52018-10-03 14:02:54 -040072 agent.lockLogicalDevice = sync.RWMutex{}
khenaidoofc1314d2019-03-14 09:34:21 -040073 agent.portProxies = make(map[string]*model.Proxy)
74 agent.portProxiesLock = sync.RWMutex{}
khenaidoo2c6a0992019-04-29 13:46:56 -040075 agent.lockLogicalPortsNo = sync.RWMutex{}
khenaidoo4c9e5592019-09-09 16:20:41 -040076 agent.lockDeviceGraph = sync.RWMutex{}
khenaidoo2c6a0992019-04-29 13:46:56 -040077 agent.logicalPortsNo = make(map[uint32]bool)
khenaidoo2c6a0992019-04-29 13:46:56 -040078 agent.defaultTimeout = timeout
khenaidoob9203542018-09-17 22:56:37 -040079 return &agent
80}
81
khenaidoo4d4802d2018-10-04 21:59:49 -040082// start creates the logical device and add it to the data model
khenaidoo297cd252019-02-07 22:10:23 -050083func (agent *LogicalDeviceAgent) start(ctx context.Context, loadFromdB bool) error {
84 log.Infow("starting-logical_device-agent", log.Fields{"logicaldeviceId": agent.logicalDeviceId, "loadFromdB": loadFromdB})
85 var ld *voltha.LogicalDevice
86 if !loadFromdB {
khenaidoo7e3d8f12019-08-02 16:06:30 -040087 //Build the logical device based on information retrieved from the device adapter
88 var switchCap *ic.SwitchCapability
khenaidoo297cd252019-02-07 22:10:23 -050089 var err error
khenaidoo7e3d8f12019-08-02 16:06:30 -040090 if switchCap, err = agent.deviceMgr.getSwitchCapability(ctx, agent.rootDeviceId); err != nil {
91 log.Errorw("error-creating-logical-device", log.Fields{"error": err})
92 return err
93 }
khenaidoo297cd252019-02-07 22:10:23 -050094 ld = &voltha.LogicalDevice{Id: agent.logicalDeviceId, RootDeviceId: agent.rootDeviceId}
95
96 // Create the datapath ID (uint64) using the logical device ID (based on the MAC Address)
97 var datapathID uint64
98 if datapathID, err = CreateDataPathId(agent.logicalDeviceId); err != nil {
99 log.Errorw("error-creating-datapath-id", log.Fields{"error": err})
100 return err
101 }
102 ld.DatapathId = datapathID
khenaidoo7e3d8f12019-08-02 16:06:30 -0400103 ld.Desc = (proto.Clone(switchCap.Desc)).(*ofp.OfpDesc)
104 log.Debugw("Switch-capability", log.Fields{"Desc": ld.Desc, "fromAd": switchCap.Desc})
105 ld.SwitchFeatures = (proto.Clone(switchCap.SwitchFeatures)).(*ofp.OfpSwitchFeatures)
khenaidoo297cd252019-02-07 22:10:23 -0500106 ld.Flows = &ofp.Flows{Items: nil}
107 ld.FlowGroups = &ofp.FlowGroups{Items: nil}
108
khenaidoo297cd252019-02-07 22:10:23 -0500109 agent.lockLogicalDevice.Lock()
khenaidoo297cd252019-02-07 22:10:23 -0500110 // Save the logical device
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400111 if added := agent.clusterDataProxy.AddWithID(ctx, "/logical_devices", ld.Id, ld, ""); added == nil {
khenaidoo297cd252019-02-07 22:10:23 -0500112 log.Errorw("failed-to-add-logical-device", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
113 } else {
114 log.Debugw("logicaldevice-created", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
115 }
116 agent.lockLogicalDevice.Unlock()
khenaidoofc1314d2019-03-14 09:34:21 -0400117
khenaidoo3d3b8c22019-05-22 18:10:39 -0400118 // TODO: Set the logical ports in a separate call once the port update issue is fixed.
119 go agent.setupLogicalPorts(ctx)
120
khenaidoo297cd252019-02-07 22:10:23 -0500121 } else {
122 // load from dB - the logical may not exist at this time. On error, just return and the calling function
123 // will destroy this agent.
124 var err error
125 if ld, err = agent.GetLogicalDevice(); err != nil {
126 log.Warnw("failed-to-load-logical-device", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
127 return err
128 }
khenaidoo3d3b8c22019-05-22 18:10:39 -0400129
khenaidoo8c3303d2019-02-13 14:59:39 -0500130 // Update the root device Id
131 agent.rootDeviceId = ld.RootDeviceId
khenaidoo3d3b8c22019-05-22 18:10:39 -0400132
133 // Setup the local list of logical ports
134 agent.addLogicalPortsToMap(ld.Ports)
135
khenaidoob9203542018-09-17 22:56:37 -0400136 }
khenaidoo92e62c52018-10-03 14:02:54 -0400137 agent.lockLogicalDevice.Lock()
khenaidoo3d3b8c22019-05-22 18:10:39 -0400138 defer agent.lockLogicalDevice.Unlock()
khenaidoofc1314d2019-03-14 09:34:21 -0400139
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400140 agent.flowProxy = agent.clusterDataProxy.CreateProxy(
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400141 ctx,
khenaidoo19d7b632018-10-30 10:49:50 -0400142 fmt.Sprintf("/logical_devices/%s/flows", agent.logicalDeviceId),
143 false)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400144 agent.meterProxy = agent.clusterDataProxy.CreateProxy(
145 ctx,
146 fmt.Sprintf("/logical_devices/%s/meters", agent.logicalDeviceId),
147 false)
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400148 agent.groupProxy = agent.clusterDataProxy.CreateProxy(
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400149 ctx,
khenaidoo19d7b632018-10-30 10:49:50 -0400150 fmt.Sprintf("/logical_devices/%s/flow_groups", agent.logicalDeviceId),
151 false)
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400152 agent.ldProxy = agent.clusterDataProxy.CreateProxy(
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400153 ctx,
khenaidoofc1314d2019-03-14 09:34:21 -0400154 fmt.Sprintf("/logical_devices/%s", agent.logicalDeviceId),
155 false)
khenaidoo19d7b632018-10-30 10:49:50 -0400156
khenaidoofc1314d2019-03-14 09:34:21 -0400157 // TODO: Use a port proxy once the POST_ADD is fixed
khenaidoo3d3b8c22019-05-22 18:10:39 -0400158 if agent.ldProxy != nil {
159 agent.ldProxy.RegisterCallback(model.POST_UPDATE, agent.portUpdated)
160 } else {
161 log.Errorw("logical-device-proxy-null", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
162 return status.Error(codes.Internal, "logical-device-proxy-null")
163 }
khenaidoobcf205b2019-01-25 22:21:14 -0500164
khenaidoo4c9e5592019-09-09 16:20:41 -0400165 // Setup the device graph - run it in its own routine
166 if loadFromdB {
167 go agent.generateDeviceGraph()
168 }
khenaidoob9203542018-09-17 22:56:37 -0400169 return nil
170}
171
khenaidoo4d4802d2018-10-04 21:59:49 -0400172// stop stops the logical devuce agent. This removes the logical device from the data model.
173func (agent *LogicalDeviceAgent) stop(ctx context.Context) {
174 log.Info("stopping-logical_device-agent")
175 agent.lockLogicalDevice.Lock()
176 defer agent.lockLogicalDevice.Unlock()
khenaidoo8c3303d2019-02-13 14:59:39 -0500177
khenaidoo4d4802d2018-10-04 21:59:49 -0400178 //Remove the logical device from the model
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400179 if removed := agent.clusterDataProxy.Remove(ctx, "/logical_devices/"+agent.logicalDeviceId, ""); removed == nil {
khenaidoo4d4802d2018-10-04 21:59:49 -0400180 log.Errorw("failed-to-remove-logical-device", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
181 } else {
182 log.Debugw("logicaldevice-removed", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
183 }
184 agent.exitChannel <- 1
185 log.Info("logical_device-agent-stopped")
186}
187
khenaidoo19d7b632018-10-30 10:49:50 -0400188// GetLogicalDevice locks the logical device model and then retrieves the latest logical device information
189func (agent *LogicalDeviceAgent) GetLogicalDevice() (*voltha.LogicalDevice, error) {
190 log.Debug("GetLogicalDevice")
khenaidoo1ce37ad2019-03-24 22:07:24 -0400191 agent.lockLogicalDevice.RLock()
192 defer agent.lockLogicalDevice.RUnlock()
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400193 logicalDevice := agent.clusterDataProxy.Get(context.Background(), "/logical_devices/"+agent.logicalDeviceId, 0, false, "")
khenaidoo92e62c52018-10-03 14:02:54 -0400194 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500195 return lDevice, nil
khenaidoo92e62c52018-10-03 14:02:54 -0400196 }
197 return nil, status.Errorf(codes.NotFound, "logical_device-%s", agent.logicalDeviceId)
198}
199
khenaidoodd237172019-05-27 16:37:17 -0400200func (agent *LogicalDeviceAgent) ListLogicalDeviceFlows() (*ofp.Flows, error) {
201 log.Debug("ListLogicalDeviceFlows")
202 agent.lockLogicalDevice.RLock()
203 defer agent.lockLogicalDevice.RUnlock()
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400204 logicalDevice := agent.clusterDataProxy.Get(context.Background(), "/logical_devices/"+agent.logicalDeviceId, 0, false, "")
khenaidoodd237172019-05-27 16:37:17 -0400205 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
206 cFlows := (proto.Clone(lDevice.Flows)).(*ofp.Flows)
207 return cFlows, nil
208 }
209 return nil, status.Errorf(codes.NotFound, "logical_device-%s", agent.logicalDeviceId)
210}
211
Manikkaraj kb1a10922019-07-29 12:10:34 -0400212func (agent *LogicalDeviceAgent) ListLogicalDeviceMeters() (*ofp.Meters, error) {
213 log.Debug("ListLogicalDeviceMeters")
214 agent.lockLogicalDevice.RLock()
215 defer agent.lockLogicalDevice.RUnlock()
216 logicalDevice := agent.clusterDataProxy.Get(context.Background(), "/logical_devices/"+agent.logicalDeviceId, 0, false, "")
217 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
218 cMeters := (proto.Clone(lDevice.Meters)).(*ofp.Meters)
219 return cMeters, nil
220 }
221 return nil, status.Errorf(codes.NotFound, "logical_device-%s", agent.logicalDeviceId)
222}
223
khenaidoodd237172019-05-27 16:37:17 -0400224func (agent *LogicalDeviceAgent) ListLogicalDeviceFlowGroups() (*ofp.FlowGroups, error) {
225 log.Debug("ListLogicalDeviceFlowGroups")
226 agent.lockLogicalDevice.RLock()
227 defer agent.lockLogicalDevice.RUnlock()
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400228 logicalDevice := agent.clusterDataProxy.Get(context.Background(), "/logical_devices/"+agent.logicalDeviceId, 0, false, "")
khenaidoodd237172019-05-27 16:37:17 -0400229 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
230 cFlowGroups := (proto.Clone(lDevice.FlowGroups)).(*ofp.FlowGroups)
231 return cFlowGroups, nil
232 }
233 return nil, status.Errorf(codes.NotFound, "logical_device-%s", agent.logicalDeviceId)
234}
235
khenaidoo19d7b632018-10-30 10:49:50 -0400236func (agent *LogicalDeviceAgent) ListLogicalDevicePorts() (*voltha.LogicalPorts, error) {
khenaidoo1ce37ad2019-03-24 22:07:24 -0400237 log.Debug("ListLogicalDevicePorts")
238 agent.lockLogicalDevice.RLock()
239 defer agent.lockLogicalDevice.RUnlock()
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400240 logicalDevice := agent.clusterDataProxy.Get(context.Background(), "/logical_devices/"+agent.logicalDeviceId, 0, false, "")
khenaidoo19d7b632018-10-30 10:49:50 -0400241 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
242 lPorts := make([]*voltha.LogicalPort, 0)
243 for _, port := range lDevice.Ports {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500244 lPorts = append(lPorts, port)
khenaidoo19d7b632018-10-30 10:49:50 -0400245 }
246 return &voltha.LogicalPorts{Items: lPorts}, nil
247 }
248 return nil, status.Errorf(codes.NotFound, "logical_device-%s", agent.logicalDeviceId)
249}
250
251// listFlows locks the logical device model and then retrieves the latest flow information
252func (agent *LogicalDeviceAgent) listFlows() []*ofp.OfpFlowStats {
253 log.Debug("listFlows")
khenaidoo1ce37ad2019-03-24 22:07:24 -0400254 agent.lockLogicalDevice.RLock()
255 defer agent.lockLogicalDevice.RUnlock()
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400256 logicalDevice := agent.clusterDataProxy.Get(context.Background(), "/logical_devices/"+agent.logicalDeviceId, 0, false, "")
khenaidoo19d7b632018-10-30 10:49:50 -0400257 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
258 return lDevice.Flows.Items
259 }
260 return nil
261}
262
263// listFlowGroups locks the logical device model and then retrieves the latest flow groups information
264func (agent *LogicalDeviceAgent) listFlowGroups() []*ofp.OfpGroupEntry {
265 log.Debug("listFlowGroups")
khenaidoo1ce37ad2019-03-24 22:07:24 -0400266 agent.lockLogicalDevice.RLock()
267 defer agent.lockLogicalDevice.RUnlock()
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400268 logicalDevice := agent.clusterDataProxy.Get(context.Background(), "/logical_devices/"+agent.logicalDeviceId, 0, false, "")
khenaidoo19d7b632018-10-30 10:49:50 -0400269 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
270 return lDevice.FlowGroups.Items
271 }
272 return nil
273}
274
khenaidoo4c9e5592019-09-09 16:20:41 -0400275//updateLogicalDeviceFlowsWithoutLock updates the logical device with the latest flows in the model.
khenaidoo43c82122018-11-22 18:38:28 -0500276func (agent *LogicalDeviceAgent) updateLogicalDeviceFlowsWithoutLock(flows *ofp.Flows) error {
khenaidoo4c9e5592019-09-09 16:20:41 -0400277 ld, err := agent.getLogicalDeviceWithoutLock()
278 if err != nil {
279 return status.Errorf(codes.Internal, "logical-device-absent:%s", agent.logicalDeviceId)
280 }
281 log.Debugw("logical-device-before", log.Fields{"lports": len(ld.Ports)})
282 cloned := (proto.Clone(ld)).(*voltha.LogicalDevice)
283 cloned.Flows = flows
284
285 if err = agent.updateLogicalDeviceWithoutLock(cloned); err != nil {
286 log.Errorw("error-updating-logical-device-with-flows", log.Fields{"error": err})
287 return err
khenaidoo43c82122018-11-22 18:38:28 -0500288 }
khenaidoo43c82122018-11-22 18:38:28 -0500289 return nil
290}
291
khenaidoo4c9e5592019-09-09 16:20:41 -0400292//updateLogicalDeviceMetersWithoutLock updates the logical device with the meters info
Manikkaraj kb1a10922019-07-29 12:10:34 -0400293func (agent *LogicalDeviceAgent) updateLogicalDeviceMetersWithoutLock(meters *ofp.Meters) error {
khenaidoo4c9e5592019-09-09 16:20:41 -0400294 ld, err := agent.getLogicalDeviceWithoutLock()
295 if err != nil {
296 return status.Errorf(codes.Internal, "logical-device-absent:%s", agent.logicalDeviceId)
297 }
298 log.Debugw("logical-device-before", log.Fields{"lports": len(ld.Ports)})
299 cloned := (proto.Clone(ld)).(*voltha.LogicalDevice)
300 cloned.Meters = meters
301
302 if err = agent.updateLogicalDeviceWithoutLock(cloned); err != nil {
303 log.Errorw("error-updating-logical-device-with-meters", log.Fields{"error": err})
304 return err
Manikkaraj kb1a10922019-07-29 12:10:34 -0400305 }
306 return nil
307}
308
khenaidoo4c9e5592019-09-09 16:20:41 -0400309//updateLogicalDeviceFlowGroupsWithoutLock updates the logical device with the flow groups
khenaidoo43c82122018-11-22 18:38:28 -0500310func (agent *LogicalDeviceAgent) updateLogicalDeviceFlowGroupsWithoutLock(flowGroups *ofp.FlowGroups) error {
khenaidoo4c9e5592019-09-09 16:20:41 -0400311 ld, err := agent.getLogicalDeviceWithoutLock()
312 if err != nil {
313 return status.Errorf(codes.Internal, "logical-device-absent:%s", agent.logicalDeviceId)
314 }
315 log.Debugw("logical-device-before", log.Fields{"lports": len(ld.Ports)})
316 cloned := (proto.Clone(ld)).(*voltha.LogicalDevice)
317 cloned.FlowGroups = flowGroups
318
319 if err = agent.updateLogicalDeviceWithoutLock(cloned); err != nil {
320 log.Errorw("error-updating-logical-device-with-flowgroups", log.Fields{"error": err})
321 return err
khenaidoo43c82122018-11-22 18:38:28 -0500322 }
khenaidoo43c82122018-11-22 18:38:28 -0500323 return nil
324}
325
khenaidoo4d4802d2018-10-04 21:59:49 -0400326// getLogicalDeviceWithoutLock retrieves a logical device from the model without locking it. This is used only by
327// functions that have already acquired the logical device lock to the model
khenaidoo92e62c52018-10-03 14:02:54 -0400328func (agent *LogicalDeviceAgent) getLogicalDeviceWithoutLock() (*voltha.LogicalDevice, error) {
329 log.Debug("getLogicalDeviceWithoutLock")
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400330 logicalDevice := agent.clusterDataProxy.Get(context.Background(), "/logical_devices/"+agent.logicalDeviceId, 0, false, "")
khenaidoo92e62c52018-10-03 14:02:54 -0400331 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
khenaidoo1ce37ad2019-03-24 22:07:24 -0400332 //log.Debug("getLogicalDeviceWithoutLock", log.Fields{"ldevice": lDevice})
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500333 return lDevice, nil
khenaidoo92e62c52018-10-03 14:02:54 -0400334 }
335 return nil, status.Errorf(codes.NotFound, "logical_device-%s", agent.logicalDeviceId)
336}
337
khenaidoo2c6a0992019-04-29 13:46:56 -0400338func (agent *LogicalDeviceAgent) updateLogicalPort(device *voltha.Device, port *voltha.Port) error {
339 log.Debugw("updateLogicalPort", log.Fields{"deviceId": device.Id, "port": port})
340 var err error
341 if port.Type == voltha.Port_ETHERNET_NNI {
342 if _, err = agent.addNNILogicalPort(device, port); err != nil {
343 return err
344 }
345 agent.addLogicalPortToMap(port.PortNo, true)
346 } else if port.Type == voltha.Port_ETHERNET_UNI {
347 if _, err = agent.addUNILogicalPort(device, port); err != nil {
348 return err
349 }
350 agent.addLogicalPortToMap(port.PortNo, false)
351 } else {
352 // Update the device graph to ensure all routes on the logical device have been calculated
353 if err = agent.updateRoutes(device, port); err != nil {
354 log.Errorw("failed-to-update-routes", log.Fields{"deviceId": device.Id, "port": port, "error": err})
355 return err
356 }
357 }
358 return nil
359}
360
khenaidoo910204f2019-04-08 17:56:40 -0400361func (agent *LogicalDeviceAgent) addLogicalPort(device *voltha.Device, port *voltha.Port) error {
khenaidoo8f474192019-04-03 17:20:44 -0400362 log.Debugw("addLogicalPort", log.Fields{"deviceId": device.Id, "port": port})
khenaidoo8f474192019-04-03 17:20:44 -0400363 var err error
khenaidoofc1314d2019-03-14 09:34:21 -0400364 if port.Type == voltha.Port_ETHERNET_NNI {
khenaidoo910204f2019-04-08 17:56:40 -0400365 if _, err = agent.addNNILogicalPort(device, port); err != nil {
khenaidoofc1314d2019-03-14 09:34:21 -0400366 return err
367 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400368 agent.addLogicalPortToMap(port.PortNo, true)
khenaidoofc1314d2019-03-14 09:34:21 -0400369 } else if port.Type == voltha.Port_ETHERNET_UNI {
khenaidoo910204f2019-04-08 17:56:40 -0400370 if _, err = agent.addUNILogicalPort(device, port); err != nil {
khenaidoofc1314d2019-03-14 09:34:21 -0400371 return err
372 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400373 agent.addLogicalPortToMap(port.PortNo, false)
khenaidoofc1314d2019-03-14 09:34:21 -0400374 } else {
375 log.Debugw("invalid-port-type", log.Fields{"deviceId": device.Id, "port": port})
376 return nil
377 }
khenaidoofc1314d2019-03-14 09:34:21 -0400378 return nil
379}
380
khenaidoo3d3b8c22019-05-22 18:10:39 -0400381// setupLogicalPorts is invoked once the logical device has been created and is ready to get ports
382// added to it. While the logical device was being created we could have received requests to add
383// NNI and UNI ports which were discarded. Now is the time to add them if needed
384func (agent *LogicalDeviceAgent) setupLogicalPorts(ctx context.Context) error {
385 log.Infow("setupLogicalPorts", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
386 // First add any NNI ports which could have been missing
387 if err := agent.setupNNILogicalPorts(nil, agent.rootDeviceId); err != nil {
388 log.Errorw("error-setting-up-NNI-ports", log.Fields{"error": err, "deviceId": agent.rootDeviceId})
389 return err
390 }
391
392 // Now, set up the UNI ports if needed.
393 if children, err := agent.deviceMgr.getAllChildDevices(agent.rootDeviceId); err != nil {
394 log.Errorw("error-getting-child-devices", log.Fields{"error": err, "deviceId": agent.rootDeviceId})
395 return err
396 } else {
397 chnlsList := make([]chan interface{}, 0)
398 for _, child := range children.Items {
399 ch := make(chan interface{})
400 chnlsList = append(chnlsList, ch)
401 go func(device *voltha.Device, ch chan interface{}) {
402 if err = agent.setupUNILogicalPorts(nil, device); err != nil {
403 log.Error("setting-up-UNI-ports-failed", log.Fields{"deviceID": device.Id})
404 ch <- status.Errorf(codes.Internal, "UNI-ports-setup-failed: %s", device.Id)
405 }
406 ch <- nil
407 }(child, ch)
408 }
409 // Wait for completion
Scott Bakerb671a862019-10-24 10:53:40 -0700410 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, chnlsList...); res != nil {
khenaidoo3d3b8c22019-05-22 18:10:39 -0400411 return status.Errorf(codes.Aborted, "errors-%s", res)
412 }
413 }
414 return nil
415}
416
khenaidoofc1314d2019-03-14 09:34:21 -0400417// setupNNILogicalPorts creates an NNI port on the logical device that represents an NNI interface on a root device
418func (agent *LogicalDeviceAgent) setupNNILogicalPorts(ctx context.Context, deviceId string) error {
419 log.Infow("setupNNILogicalPorts-start", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoob9203542018-09-17 22:56:37 -0400420 // Build the logical device based on information retrieved from the device adapter
khenaidoofc1314d2019-03-14 09:34:21 -0400421 var err error
422
423 var device *voltha.Device
424 if device, err = agent.deviceMgr.GetDevice(deviceId); err != nil {
khenaidoo2c6a0992019-04-29 13:46:56 -0400425 log.Errorw("error-retrieving-device", log.Fields{"error": err, "deviceId": deviceId})
khenaidoofc1314d2019-03-14 09:34:21 -0400426 return err
427 }
428
429 //Get UNI port number
khenaidoofc1314d2019-03-14 09:34:21 -0400430 for _, port := range device.Ports {
431 if port.Type == voltha.Port_ETHERNET_NNI {
khenaidoo910204f2019-04-08 17:56:40 -0400432 if _, err = agent.addNNILogicalPort(device, port); err != nil {
khenaidoofc1314d2019-03-14 09:34:21 -0400433 log.Errorw("error-adding-UNI-port", log.Fields{"error": err})
khenaidoofc1314d2019-03-14 09:34:21 -0400434 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400435 agent.addLogicalPortToMap(port.PortNo, true)
khenaidoofc1314d2019-03-14 09:34:21 -0400436 }
437 }
khenaidoofc1314d2019-03-14 09:34:21 -0400438 return err
439}
440
khenaidoo3ab34882019-05-02 21:33:30 -0400441// updatePortsState updates the ports state related to the device
442func (agent *LogicalDeviceAgent) updatePortsState(device *voltha.Device, state voltha.AdminState_AdminState) error {
443 log.Infow("updatePortsState-start", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
444 agent.lockLogicalDevice.Lock()
445 defer agent.lockLogicalDevice.Unlock()
446 // Get the latest logical device info
447 if ld, err := agent.getLogicalDeviceWithoutLock(); err != nil {
448 log.Warnw("logical-device-unknown", log.Fields{"ldeviceId": agent.logicalDeviceId, "error": err})
449 return err
450 } else {
451 cloned := (proto.Clone(ld)).(*voltha.LogicalDevice)
452 for _, lport := range cloned.Ports {
453 if lport.DeviceId == device.Id {
454 switch state {
455 case voltha.AdminState_ENABLED:
456 lport.OfpPort.Config = lport.OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
khenaidoo0a822f92019-05-08 15:15:57 -0400457 lport.OfpPort.State = uint32(ofp.OfpPortState_OFPPS_LIVE)
khenaidoo3ab34882019-05-02 21:33:30 -0400458 case voltha.AdminState_DISABLED:
459 lport.OfpPort.Config = lport.OfpPort.Config | uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
khenaidoo0a822f92019-05-08 15:15:57 -0400460 lport.OfpPort.State = uint32(ofp.OfpPortState_OFPPS_LINK_DOWN)
khenaidoo3ab34882019-05-02 21:33:30 -0400461 default:
462 log.Warnw("unsupported-state-change", log.Fields{"deviceId": device.Id, "state": state})
463 }
464 }
465 }
466 // Updating the logical device will trigger the poprt change events to be populated to the controller
467 if err := agent.updateLogicalDeviceWithoutLock(cloned); err != nil {
468 log.Warnw("logical-device-update-failed", log.Fields{"ldeviceId": agent.logicalDeviceId, "error": err})
469 return err
470 }
471 }
472 return nil
473}
474
khenaidoofc1314d2019-03-14 09:34:21 -0400475// setupUNILogicalPorts creates a UNI port on the logical device that represents a child UNI interface
476func (agent *LogicalDeviceAgent) setupUNILogicalPorts(ctx context.Context, childDevice *voltha.Device) error {
khenaidoo3d3b8c22019-05-22 18:10:39 -0400477 log.Infow("setupUNILogicalPort", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoofc1314d2019-03-14 09:34:21 -0400478 // Build the logical device based on information retrieved from the device adapter
khenaidoob9203542018-09-17 22:56:37 -0400479 var err error
khenaidoo59ef7be2019-06-21 12:40:28 -0400480 var added bool
khenaidoo19d7b632018-10-30 10:49:50 -0400481 //Get UNI port number
khenaidoo19d7b632018-10-30 10:49:50 -0400482 for _, port := range childDevice.Ports {
483 if port.Type == voltha.Port_ETHERNET_UNI {
khenaidoo59ef7be2019-06-21 12:40:28 -0400484 if added, err = agent.addUNILogicalPort(childDevice, port); err != nil {
khenaidoofc1314d2019-03-14 09:34:21 -0400485 log.Errorw("error-adding-UNI-port", log.Fields{"error": err})
khenaidoofc1314d2019-03-14 09:34:21 -0400486 }
khenaidoo59ef7be2019-06-21 12:40:28 -0400487 if added {
488 agent.addLogicalPortToMap(port.PortNo, false)
489 }
khenaidoo19d7b632018-10-30 10:49:50 -0400490 }
491 }
khenaidoofc1314d2019-03-14 09:34:21 -0400492 return err
khenaidoo92e62c52018-10-03 14:02:54 -0400493}
494
khenaidoo0a822f92019-05-08 15:15:57 -0400495// deleteAllLogicalPorts deletes all logical ports associated with this device
496func (agent *LogicalDeviceAgent) deleteAllLogicalPorts(device *voltha.Device) error {
497 log.Infow("updatePortsState-start", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
498 agent.lockLogicalDevice.Lock()
499 defer agent.lockLogicalDevice.Unlock()
500 // Get the latest logical device info
501 if ld, err := agent.getLogicalDeviceWithoutLock(); err != nil {
502 log.Warnw("logical-device-unknown", log.Fields{"ldeviceId": agent.logicalDeviceId, "error": err})
503 return err
504 } else {
505 cloned := (proto.Clone(ld)).(*voltha.LogicalDevice)
506 updateLogicalPorts := []*voltha.LogicalPort{}
507 for _, lport := range cloned.Ports {
508 if lport.DeviceId != device.Id {
509 updateLogicalPorts = append(updateLogicalPorts, lport)
510 }
511 }
512 if len(updateLogicalPorts) < len(cloned.Ports) {
513 cloned.Ports = updateLogicalPorts
514 // Updating the logical device will trigger the poprt change events to be populated to the controller
515 if err := agent.updateLogicalDeviceWithoutLock(cloned); err != nil {
516 log.Warnw("logical-device-update-failed", log.Fields{"ldeviceId": agent.logicalDeviceId, "error": err})
517 return err
518 }
519 } else {
520 log.Debugw("no-change-required", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
521 }
522 }
523 return nil
524}
525
khenaidoo92e62c52018-10-03 14:02:54 -0400526//updateLogicalDeviceWithoutLock updates the model with the logical device. It clones the logicaldevice before saving it
527func (agent *LogicalDeviceAgent) updateLogicalDeviceWithoutLock(logicalDevice *voltha.LogicalDevice) error {
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400528 updateCtx := context.WithValue(context.Background(), model.RequestTimestamp, time.Now().UnixNano())
529 afterUpdate := agent.clusterDataProxy.Update(updateCtx, "/logical_devices/"+agent.logicalDeviceId, logicalDevice, false, "")
khenaidoo92e62c52018-10-03 14:02:54 -0400530 if afterUpdate == nil {
531 return status.Errorf(codes.Internal, "failed-updating-logical-device:%s", agent.logicalDeviceId)
532 }
533 return nil
534}
535
khenaidoo4c9e5592019-09-09 16:20:41 -0400536//generateDeviceGraphIfNeeded generates the device graph if the logical device has been updated since the last time
537//that device graph was generated.
538func (agent *LogicalDeviceAgent) generateDeviceGraphIfNeeded() error {
539 if ld, err := agent.GetLogicalDevice(); err != nil {
540 log.Errorw("get-logical-device-error", log.Fields{"error": err})
541 return err
542 } else {
543 agent.lockDeviceGraph.Lock()
544 defer agent.lockDeviceGraph.Unlock()
545 if agent.deviceGraph != nil && agent.deviceGraph.IsUpToDate(ld) {
546 return nil
547 }
548 log.Debug("Generation of device graph required")
549 agent.generateDeviceGraph()
550 }
551 return nil
552}
553
khenaidoo19d7b632018-10-30 10:49:50 -0400554//updateFlowTable updates the flow table of that logical device
555func (agent *LogicalDeviceAgent) updateFlowTable(ctx context.Context, flow *ofp.OfpFlowMod) error {
556 log.Debug("updateFlowTable")
557 if flow == nil {
558 return nil
559 }
khenaidoo4c9e5592019-09-09 16:20:41 -0400560 if err := agent.generateDeviceGraphIfNeeded(); err != nil {
561 return err
562 }
khenaidoo19d7b632018-10-30 10:49:50 -0400563 switch flow.GetCommand() {
564 case ofp.OfpFlowModCommand_OFPFC_ADD:
565 return agent.flowAdd(flow)
566 case ofp.OfpFlowModCommand_OFPFC_DELETE:
567 return agent.flowDelete(flow)
568 case ofp.OfpFlowModCommand_OFPFC_DELETE_STRICT:
569 return agent.flowDeleteStrict(flow)
570 case ofp.OfpFlowModCommand_OFPFC_MODIFY:
571 return agent.flowModify(flow)
572 case ofp.OfpFlowModCommand_OFPFC_MODIFY_STRICT:
573 return agent.flowModifyStrict(flow)
574 }
575 return status.Errorf(codes.Internal,
576 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceId, flow.GetCommand())
577}
578
579//updateGroupTable updates the group table of that logical device
580func (agent *LogicalDeviceAgent) updateGroupTable(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
581 log.Debug("updateGroupTable")
582 if groupMod == nil {
583 return nil
584 }
khenaidoo4c9e5592019-09-09 16:20:41 -0400585 if err := agent.generateDeviceGraphIfNeeded(); err != nil {
586 return err
587 }
khenaidoo19d7b632018-10-30 10:49:50 -0400588 switch groupMod.GetCommand() {
589 case ofp.OfpGroupModCommand_OFPGC_ADD:
590 return agent.groupAdd(groupMod)
591 case ofp.OfpGroupModCommand_OFPGC_DELETE:
592 return agent.groupDelete(groupMod)
593 case ofp.OfpGroupModCommand_OFPGC_MODIFY:
594 return agent.groupModify(groupMod)
595 }
596 return status.Errorf(codes.Internal,
597 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceId, groupMod.GetCommand())
598}
599
Manikkaraj kb1a10922019-07-29 12:10:34 -0400600// updateMeterTable updates the meter table of that logical device
601func (agent *LogicalDeviceAgent) updateMeterTable(ctx context.Context, meterMod *ofp.OfpMeterMod) error {
602 log.Debug("updateMeterTable")
603 if meterMod == nil {
604 return nil
605 }
khenaidoo4c9e5592019-09-09 16:20:41 -0400606 if err := agent.generateDeviceGraphIfNeeded(); err != nil {
607 return err
608 }
Manikkaraj kb1a10922019-07-29 12:10:34 -0400609 switch meterMod.GetCommand() {
610 case ofp.OfpMeterModCommand_OFPMC_ADD:
611 return agent.meterAdd(meterMod)
612 case ofp.OfpMeterModCommand_OFPMC_DELETE:
613 return agent.meterDelete(meterMod)
614 case ofp.OfpMeterModCommand_OFPMC_MODIFY:
615 return agent.meterModify(meterMod)
616 }
617 return status.Errorf(codes.Internal,
618 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceId, meterMod.GetCommand())
619
620}
621
622func (agent *LogicalDeviceAgent) meterAdd(meterMod *ofp.OfpMeterMod) error {
623 log.Debugw("meterAdd", log.Fields{"metermod": *meterMod})
624 if meterMod == nil {
625 return nil
626 }
627 log.Debug("Waiting for logical device lock!!")
628 agent.lockLogicalDevice.Lock()
629 defer agent.lockLogicalDevice.Unlock()
630 log.Debug("Acquired logical device lock")
631 var lDevice *voltha.LogicalDevice
632 var err error
633 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
634 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
635 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
636 }
637
638 var meters []*ofp.OfpMeterEntry
639 if lDevice.Meters != nil && lDevice.Meters.Items != nil {
640 meters = lDevice.Meters.Items
641 }
642 log.Debugw("Available meters", log.Fields{"meters": meters})
643
644 for _, meter := range meters {
645 if meterMod.MeterId == meter.Config.MeterId {
646 log.Infow("Meter-already-exists", log.Fields{"meter": *meterMod})
647 return nil
648 }
649 }
650
651 meterEntry := fu.MeterEntryFromMeterMod(meterMod)
652 meters = append(meters, meterEntry)
653 //Update model
654 if err := agent.updateLogicalDeviceMetersWithoutLock(&ofp.Meters{Items: meters}); err != nil {
655 log.Errorw("db-meter-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
656 return err
657 }
658 log.Debugw("Meter-added-successfully", log.Fields{"Added-meter": meterEntry, "updated-meters": lDevice.Meters})
659 return nil
660}
661
662func (agent *LogicalDeviceAgent) meterDelete(meterMod *ofp.OfpMeterMod) error {
663 log.Debug("meterDelete", log.Fields{"meterMod": *meterMod})
664 if meterMod == nil {
665 return nil
666 }
667 agent.lockLogicalDevice.Lock()
668 defer agent.lockLogicalDevice.Unlock()
669
670 var lDevice *voltha.LogicalDevice
671 var err error
672 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
673 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
674 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
675 }
676
677 var meters []*ofp.OfpMeterEntry
678 var flows []*ofp.OfpFlowStats
679 updatedFlows := make([]*ofp.OfpFlowStats, 0)
680 if lDevice.Meters != nil && lDevice.Meters.Items != nil {
681 meters = lDevice.Meters.Items
682 }
683 if lDevice.Flows != nil && lDevice.Flows.Items != nil {
684 flows = lDevice.Flows.Items
685 }
686
687 changedMeter := false
688 changedFow := false
689 log.Debugw("Available meters", log.Fields{"meters": meters})
690 for index, meter := range meters {
691 if meterMod.MeterId == meter.Config.MeterId {
692 flows = lDevice.Flows.Items
693 changedFow, updatedFlows = agent.getUpdatedFlowsAfterDeletebyMeterId(flows, meterMod.MeterId)
694 meters = append(meters[:index], meters[index+1:]...)
695 log.Debugw("Meter has been deleted", log.Fields{"meter": meter, "index": index})
696 changedMeter = true
697 break
698 }
699 }
700 if changedMeter {
701 //Update model
702 metersToUpdate := &ofp.Meters{}
703 if lDevice.Meters != nil {
704 metersToUpdate = &ofp.Meters{Items: meters}
705 }
706 if err := agent.updateLogicalDeviceMetersWithoutLock(metersToUpdate); err != nil {
707 log.Errorw("db-meter-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
708 return err
709 }
710 log.Debug("Meter-deleted-from-DB-successfully", log.Fields{"updatedMeters": metersToUpdate, "no-of-meter": len(metersToUpdate.Items)})
711
712 }
713 if changedFow {
714 //Update model
715 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: updatedFlows}); err != nil {
716 log.Errorw("db-flow-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
717 return err
718 }
719 log.Debug("Flows-associated-with-meter-deleted-from-DB-successfully",
720 log.Fields{"updated-no-of-flows": len(updatedFlows), "meter": meterMod.MeterId})
721 }
722 log.Debugw("meterDelete success", log.Fields{"meterID": meterMod.MeterId})
723 return nil
724}
725
726func (agent *LogicalDeviceAgent) meterModify(meterMod *ofp.OfpMeterMod) error {
727 log.Debug("meterModify")
728 if meterMod == nil {
729 return nil
730 }
731 agent.lockLogicalDevice.Lock()
732 defer agent.lockLogicalDevice.Unlock()
733
734 var lDevice *voltha.LogicalDevice
735 var err error
736 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
737 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
738 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
739 }
740
741 var meters []*ofp.OfpMeterEntry
742 if lDevice.Meters != nil && lDevice.Meters.Items != nil {
743 meters = lDevice.Meters.Items
744 }
745 changedMeter := false
746 for index, meter := range meters {
747 if meterMod.MeterId == meter.Config.MeterId {
748 newmeterEntry := fu.MeterEntryFromMeterMod(meterMod)
749 newmeterEntry.Stats.FlowCount = meter.Stats.FlowCount
750 meters[index] = newmeterEntry
751 changedMeter = true
752 log.Debugw("Found meter, replaced with new meter", log.Fields{"old meter": meter, "new meter": newmeterEntry})
753 break
754 }
755 }
756 if changedMeter {
757 //Update model
758 metersToUpdate := &ofp.Meters{}
759 if lDevice.Meters != nil {
760 metersToUpdate = &ofp.Meters{Items: meters}
761 }
762 if err := agent.updateLogicalDeviceMetersWithoutLock(metersToUpdate); err != nil {
763 log.Errorw("db-meter-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
764 return err
765 }
766 log.Debugw("meter-updated-in-DB-successfully", log.Fields{"updated_meters": meters})
767 return nil
768 }
769
770 log.Errorw("Meter not found ", log.Fields{"meter": meterMod})
771 return errors.New(fmt.Sprintf("no-logical-device-present:%d", meterMod.MeterId))
772
773}
774
775func (agent *LogicalDeviceAgent) getUpdatedFlowsAfterDeletebyMeterId(flows []*ofp.OfpFlowStats, meterId uint32) (bool, []*ofp.OfpFlowStats) {
776 log.Infow("Delete flows matching meter", log.Fields{"meter": meterId})
777 changed := false
778 //updatedFlows := make([]*ofp.OfpFlowStats, 0)
779 for index := len(flows) - 1; index >= 0; index-- {
780 if mId := fu.GetMeterIdFromFlow(flows[index]); mId != 0 && mId == meterId {
781 log.Debugw("Flow to be deleted", log.Fields{"flow": flows[index], "index": index})
782 flows = append(flows[:index], flows[index+1:]...)
783 changed = true
784 }
785 }
786 return changed, flows
787}
788
789func (agent *LogicalDeviceAgent) updateFlowCountOfMeterStats(modCommand *ofp.OfpFlowMod, meters []*ofp.OfpMeterEntry, flow *ofp.OfpFlowStats) bool {
790
791 flowCommand := modCommand.GetCommand()
792 meterId := fu.GetMeterIdFromFlow(flow)
793 log.Debugw("Meter-id-in-flow-mod", log.Fields{"meterId": meterId})
794 if meterId == 0 {
795 log.Debugw("No meter present in the flow", log.Fields{"flow": *flow})
796 return false
797 }
798 if meters == nil {
799 log.Debug("No meters present in logical device")
800 return false
801 }
802 changedMeter := false
803 for _, meter := range meters {
804 if meterId == meter.Config.MeterId { // Found meter in Logicaldevice
805 if flowCommand == ofp.OfpFlowModCommand_OFPFC_ADD {
806 meter.Stats.FlowCount += 1
807 changedMeter = true
808 } else if flowCommand == ofp.OfpFlowModCommand_OFPFC_DELETE_STRICT {
809 meter.Stats.FlowCount -= 1
810 changedMeter = true
811 }
812 log.Debugw("Found meter, updated meter flow stats", log.Fields{" meterId": meterId})
813 break
814 }
815 }
816 return changedMeter
817}
818
khenaidoo19d7b632018-10-30 10:49:50 -0400819//flowAdd adds a flow to the flow table of that logical device
820func (agent *LogicalDeviceAgent) flowAdd(mod *ofp.OfpFlowMod) error {
khenaidoo4c9e5592019-09-09 16:20:41 -0400821 log.Debugw("flowAdd", log.Fields{"flow": mod})
khenaidoo19d7b632018-10-30 10:49:50 -0400822 if mod == nil {
823 return nil
824 }
khenaidoo92e62c52018-10-03 14:02:54 -0400825 agent.lockLogicalDevice.Lock()
826 defer agent.lockLogicalDevice.Unlock()
khenaidoo19d7b632018-10-30 10:49:50 -0400827
828 var lDevice *voltha.LogicalDevice
829 var err error
830 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
831 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
832 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
833 }
834
835 var flows []*ofp.OfpFlowStats
Manikkaraj kb1a10922019-07-29 12:10:34 -0400836 var meters []*ofp.OfpMeterEntry
837 var flow *ofp.OfpFlowStats
838
khenaidoo19d7b632018-10-30 10:49:50 -0400839 if lDevice.Flows != nil && lDevice.Flows.Items != nil {
840 flows = lDevice.Flows.Items
841 }
842
Manikkaraj kb1a10922019-07-29 12:10:34 -0400843 if lDevice.Meters != nil && lDevice.Meters.Items != nil {
844 meters = lDevice.Meters.Items
845 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400846 updatedFlows := make([]*ofp.OfpFlowStats, 0)
khenaidoo19d7b632018-10-30 10:49:50 -0400847 changed := false
Manikkaraj kb1a10922019-07-29 12:10:34 -0400848 updated := false
khenaidoo19d7b632018-10-30 10:49:50 -0400849 checkOverlap := (mod.Flags & uint32(ofp.OfpFlowModFlags_OFPFF_CHECK_OVERLAP)) != 0
850 if checkOverlap {
851 if overlapped := fu.FindOverlappingFlows(flows, mod); len(overlapped) != 0 {
852 // TODO: should this error be notified other than being logged?
853 log.Warnw("overlapped-flows", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
854 } else {
855 // Add flow
Manikkaraj kb1a10922019-07-29 12:10:34 -0400856 flow = fu.FlowStatsEntryFromFlowModMessage(mod)
khenaidoo19d7b632018-10-30 10:49:50 -0400857 flows = append(flows, flow)
khenaidoo2c6a0992019-04-29 13:46:56 -0400858 updatedFlows = append(updatedFlows, flow)
khenaidoo19d7b632018-10-30 10:49:50 -0400859 changed = true
860 }
861 } else {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400862 flow = fu.FlowStatsEntryFromFlowModMessage(mod)
khenaidoo19d7b632018-10-30 10:49:50 -0400863 idx := fu.FindFlows(flows, flow)
864 if idx >= 0 {
865 oldFlow := flows[idx]
866 if (mod.Flags & uint32(ofp.OfpFlowModFlags_OFPFF_RESET_COUNTS)) != 0 {
867 flow.ByteCount = oldFlow.ByteCount
868 flow.PacketCount = oldFlow.PacketCount
869 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400870 if !reflect.DeepEqual(oldFlow, flow) {
871 flows[idx] = flow
872 updatedFlows = append(updatedFlows, flow)
873 changed = true
Manikkaraj kb1a10922019-07-29 12:10:34 -0400874 updated = true
khenaidoo2c6a0992019-04-29 13:46:56 -0400875 }
khenaidoo19d7b632018-10-30 10:49:50 -0400876 } else {
877 flows = append(flows, flow)
khenaidoo2c6a0992019-04-29 13:46:56 -0400878 updatedFlows = append(updatedFlows, flow)
879 changed = true
khenaidoo19d7b632018-10-30 10:49:50 -0400880 }
khenaidoo19d7b632018-10-30 10:49:50 -0400881 }
khenaidoo4c9e5592019-09-09 16:20:41 -0400882 log.Debugw("flowAdd-changed", log.Fields{"changed": changed})
883
khenaidoo19d7b632018-10-30 10:49:50 -0400884 if changed {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400885 var flowMetadata voltha.FlowMetadata
886 if err := agent.GetMeterConfig(updatedFlows, meters, &flowMetadata); err != nil { // This should never happen,meters should be installed before flow arrives
887 log.Error("Meter-referred-in-flows-not-present")
888 return err
889 }
khenaidoo0458db62019-06-20 08:50:36 -0400890 deviceRules := agent.flowDecomposer.DecomposeRules(agent, ofp.Flows{Items: updatedFlows}, *lDevice.FlowGroups)
891 log.Debugw("rules", log.Fields{"rules": deviceRules.String()})
892
Manikkaraj kb1a10922019-07-29 12:10:34 -0400893 if err := agent.addDeviceFlowsAndGroups(deviceRules, &flowMetadata); err != nil {
khenaidoo0458db62019-06-20 08:50:36 -0400894 log.Errorw("failure-updating-device-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "error": err})
khenaidoo2c6a0992019-04-29 13:46:56 -0400895 return err
896 }
897
khenaidoo19d7b632018-10-30 10:49:50 -0400898 // Update model
khenaidoo0458db62019-06-20 08:50:36 -0400899 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: flows}); err != nil {
khenaidoo2c6a0992019-04-29 13:46:56 -0400900 log.Errorw("db-flow-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400901 return err
902 }
Manikkaraj kb1a10922019-07-29 12:10:34 -0400903 if !updated {
904 changedMeterStats := agent.updateFlowCountOfMeterStats(mod, meters, flow)
905 metersToUpdate := &ofp.Meters{}
906 if lDevice.Meters != nil {
907 metersToUpdate = &ofp.Meters{Items: meters}
908 }
909 if changedMeterStats {
910 //Update model
911 if err := agent.updateLogicalDeviceMetersWithoutLock(metersToUpdate); err != nil {
912 log.Errorw("db-meter-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
913 return err
914 }
915 log.Debugw("meter-stats-updated-in-DB-successfully", log.Fields{"updated_meters": meters})
916
917 }
918 }
919
khenaidoo19d7b632018-10-30 10:49:50 -0400920 }
khenaidoo19d7b632018-10-30 10:49:50 -0400921 return nil
922}
923
Manikkaraj kb1a10922019-07-29 12:10:34 -0400924func (agent *LogicalDeviceAgent) GetMeterConfig(flows []*ofp.OfpFlowStats, meters []*ofp.OfpMeterEntry, metadata *voltha.FlowMetadata) error {
925 m := make(map[uint32]bool)
926 for _, flow := range flows {
927 if flowMeterID := fu.GetMeterIdFromFlow(flow); flowMeterID != 0 && m[flowMeterID] == false {
928 foundMeter := false
929 // Meter is present in the flow , Get from logical device
930 for _, meter := range meters {
931 if flowMeterID == meter.Config.MeterId {
932 metadata.Meters = append(metadata.Meters, meter.Config)
933 log.Debugw("Found meter in logical device",
934 log.Fields{"meterID": flowMeterID, "meter-band": meter.Config})
935 m[flowMeterID] = true
936 foundMeter = true
937 break
938 }
939 }
940 if !foundMeter {
941 log.Errorw("Meter-referred-by-flow-is-not-found-in-logicaldevice",
942 log.Fields{"meterID": flowMeterID, "Avaliable-meters": meters, "flow": *flow})
943 return errors.New("Meter-referred-by-flow-is-not-found-in-logicaldevice")
944 }
945 }
946 }
947 log.Debugw("meter-bands-for-flows", log.Fields{"flows": len(flows), "metadata": metadata})
948 return nil
949
950}
951
khenaidoo19d7b632018-10-30 10:49:50 -0400952//flowDelete deletes a flow from the flow table of that logical device
953func (agent *LogicalDeviceAgent) flowDelete(mod *ofp.OfpFlowMod) error {
954 log.Debug("flowDelete")
955 if mod == nil {
956 return nil
957 }
958 agent.lockLogicalDevice.Lock()
959 defer agent.lockLogicalDevice.Unlock()
960
961 var lDevice *voltha.LogicalDevice
962 var err error
963 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
964 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
965 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
966 }
khenaidoo19d7b632018-10-30 10:49:50 -0400967
Manikkaraj kb1a10922019-07-29 12:10:34 -0400968 var meters []*ofp.OfpMeterEntry
969 var flows []*ofp.OfpFlowStats
970
971 if lDevice.Flows != nil && lDevice.Flows.Items != nil {
972 flows = lDevice.Flows.Items
973 }
974
975 if lDevice.Meters != nil && lDevice.Meters.Items != nil {
976 meters = lDevice.Meters.Items
977 }
khenaidoo19d7b632018-10-30 10:49:50 -0400978 //build a list of what to keep vs what to delete
979 toKeep := make([]*ofp.OfpFlowStats, 0)
khenaidoo0458db62019-06-20 08:50:36 -0400980 toDelete := make([]*ofp.OfpFlowStats, 0)
khenaidoo19d7b632018-10-30 10:49:50 -0400981 for _, f := range flows {
khenaidoo0458db62019-06-20 08:50:36 -0400982 // Check whether the flow and the flowmod matches
983 if fu.FlowMatch(f, fu.FlowStatsEntryFromFlowModMessage(mod)) {
984 toDelete = append(toDelete, f)
985 continue
986 }
987 // Check wild card match
khenaidoo19d7b632018-10-30 10:49:50 -0400988 if !fu.FlowMatchesMod(f, mod) {
989 toKeep = append(toKeep, f)
khenaidoo0458db62019-06-20 08:50:36 -0400990 } else {
991 toDelete = append(toDelete, f)
khenaidoo19d7b632018-10-30 10:49:50 -0400992 }
993 }
994
khenaidoo0458db62019-06-20 08:50:36 -0400995 log.Debugw("flowDelete", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "toKeep": len(toKeep), "toDelete": toDelete})
996
khenaidoo19d7b632018-10-30 10:49:50 -0400997 //Update flows
khenaidoo0458db62019-06-20 08:50:36 -0400998 if len(toDelete) > 0 {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400999 var flowMetadata voltha.FlowMetadata
1000 if err := agent.GetMeterConfig(toDelete, meters, &flowMetadata); err != nil { // This should never happen
1001 log.Error("Meter-referred-in-flows-not-present")
1002 return errors.New("Meter-referred-in-flows-not-present")
1003 }
khenaidoo0458db62019-06-20 08:50:36 -04001004 deviceRules := agent.flowDecomposer.DecomposeRules(agent, ofp.Flows{Items: toDelete}, ofp.FlowGroups{})
1005 log.Debugw("rules", log.Fields{"rules": deviceRules.String()})
1006
Manikkaraj kb1a10922019-07-29 12:10:34 -04001007 if err := agent.deleteDeviceFlowsAndGroups(deviceRules, &flowMetadata); err != nil {
khenaidoo0458db62019-06-20 08:50:36 -04001008 log.Errorw("failure-updating-device-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "error": err})
1009 return err
1010 }
1011
khenaidoo43c82122018-11-22 18:38:28 -05001012 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: toKeep}); err != nil {
1013 log.Errorw("Cannot-update-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -04001014 return err
1015 }
1016 }
1017
1018 //TODO: send announcement on delete
1019 return nil
1020}
1021
Manikkaraj kb1a10922019-07-29 12:10:34 -04001022func (agent *LogicalDeviceAgent) addDeviceFlowsAndGroups(deviceRules *fu.DeviceRules, flowMetadata *voltha.FlowMetadata) error {
1023 log.Debugw("addDeviceFlowsAndGroups", log.Fields{"logicalDeviceID": agent.logicalDeviceId, "deviceRules": deviceRules, "flowMetadata": flowMetadata})
khenaidoo19d7b632018-10-30 10:49:50 -04001024
khenaidoo0458db62019-06-20 08:50:36 -04001025 chnlsList := make([]chan interface{}, 0)
1026 for deviceId, value := range deviceRules.GetRules() {
1027 ch := make(chan interface{})
1028 chnlsList = append(chnlsList, ch)
1029 go func(deviceId string, flows []*ofp.OfpFlowStats, groups []*ofp.OfpGroupEntry) {
Manikkaraj kb1a10922019-07-29 12:10:34 -04001030 if err := agent.deviceMgr.addFlowsAndGroups(deviceId, flows, groups, flowMetadata); err != nil {
khenaidoo0458db62019-06-20 08:50:36 -04001031 log.Errorw("flow-add-failed", log.Fields{"deviceID": deviceId, "error": err})
1032 ch <- status.Errorf(codes.Internal, "flow-add-failed: %s", deviceId)
1033 }
1034 ch <- nil
1035 }(deviceId, value.ListFlows(), value.ListGroups())
khenaidoo19d7b632018-10-30 10:49:50 -04001036 }
khenaidoo0458db62019-06-20 08:50:36 -04001037 // Wait for completion
Scott Bakerb671a862019-10-24 10:53:40 -07001038 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, chnlsList...); res != nil {
khenaidoo0458db62019-06-20 08:50:36 -04001039 return status.Errorf(codes.Aborted, "errors-%s", res)
khenaidoo19d7b632018-10-30 10:49:50 -04001040 }
khenaidoo0458db62019-06-20 08:50:36 -04001041 return nil
1042}
khenaidoo19d7b632018-10-30 10:49:50 -04001043
Manikkaraj kb1a10922019-07-29 12:10:34 -04001044func (agent *LogicalDeviceAgent) deleteDeviceFlowsAndGroups(deviceRules *fu.DeviceRules, flowMetadata *voltha.FlowMetadata) error {
khenaidoo0458db62019-06-20 08:50:36 -04001045 log.Debugw("deleteDeviceFlowsAndGroups", log.Fields{"logicalDeviceID": agent.logicalDeviceId})
1046
1047 chnlsList := make([]chan interface{}, 0)
1048 for deviceId, value := range deviceRules.GetRules() {
1049 ch := make(chan interface{})
1050 chnlsList = append(chnlsList, ch)
1051 go func(deviceId string, flows []*ofp.OfpFlowStats, groups []*ofp.OfpGroupEntry) {
Manikkaraj kb1a10922019-07-29 12:10:34 -04001052 if err := agent.deviceMgr.deleteFlowsAndGroups(deviceId, flows, groups, flowMetadata); err != nil {
khenaidoo0458db62019-06-20 08:50:36 -04001053 log.Error("flow-delete-failed", log.Fields{"deviceID": deviceId, "error": err})
1054 ch <- status.Errorf(codes.Internal, "flow-delete-failed: %s", deviceId)
1055 }
1056 ch <- nil
1057 }(deviceId, value.ListFlows(), value.ListGroups())
1058 }
1059 // Wait for completion
Scott Bakerb671a862019-10-24 10:53:40 -07001060 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, chnlsList...); res != nil {
khenaidoo0458db62019-06-20 08:50:36 -04001061 return status.Errorf(codes.Aborted, "errors-%s", res)
1062 }
1063 return nil
1064}
1065
Manikkaraj kb1a10922019-07-29 12:10:34 -04001066func (agent *LogicalDeviceAgent) updateDeviceFlowsAndGroups(deviceRules *fu.DeviceRules, flowMetadata *voltha.FlowMetadata) error {
khenaidoo0458db62019-06-20 08:50:36 -04001067 log.Debugw("updateDeviceFlowsAndGroups", log.Fields{"logicalDeviceID": agent.logicalDeviceId})
1068
1069 chnlsList := make([]chan interface{}, 0)
1070 for deviceId, value := range deviceRules.GetRules() {
1071 ch := make(chan interface{})
1072 chnlsList = append(chnlsList, ch)
1073 go func(deviceId string, flows []*ofp.OfpFlowStats, groups []*ofp.OfpGroupEntry) {
Manikkaraj kb1a10922019-07-29 12:10:34 -04001074 if err := agent.deviceMgr.updateFlowsAndGroups(deviceId, flows, groups, flowMetadata); err != nil {
khenaidoo0458db62019-06-20 08:50:36 -04001075 log.Error("flow-update-failed", log.Fields{"deviceID": deviceId, "error": err})
1076 ch <- status.Errorf(codes.Internal, "flow-update-failed: %s", deviceId)
1077 }
1078 ch <- nil
1079 }(deviceId, value.ListFlows(), value.ListGroups())
1080 }
1081 // Wait for completion
Scott Bakerb671a862019-10-24 10:53:40 -07001082 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, chnlsList...); res != nil {
khenaidoo0458db62019-06-20 08:50:36 -04001083 return status.Errorf(codes.Aborted, "errors-%s", res)
khenaidoo19d7b632018-10-30 10:49:50 -04001084 }
1085 return nil
1086}
1087
1088//flowDeleteStrict deletes a flow from the flow table of that logical device
1089func (agent *LogicalDeviceAgent) flowDeleteStrict(mod *ofp.OfpFlowMod) error {
1090 log.Debug("flowDeleteStrict")
1091 if mod == nil {
1092 return nil
1093 }
1094 agent.lockLogicalDevice.Lock()
1095 defer agent.lockLogicalDevice.Unlock()
1096
1097 var lDevice *voltha.LogicalDevice
1098 var err error
1099 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
1100 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
1101 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
1102 }
Manikkaraj kb1a10922019-07-29 12:10:34 -04001103 var meters []*ofp.OfpMeterEntry
1104 var flows []*ofp.OfpFlowStats
1105 if lDevice.Meters != nil && lDevice.Meters.Items != nil {
1106 meters = lDevice.Meters.Items
1107 }
1108 if lDevice.Flows != nil && lDevice.Flows.Items != nil {
1109 flows = lDevice.Flows.Items
1110 }
1111
1112 changedFlow := false
1113 changedMeter := false
khenaidoo68c930b2019-05-13 11:46:51 -04001114 flow := fu.FlowStatsEntryFromFlowModMessage(mod)
Manikkaraj kb1a10922019-07-29 12:10:34 -04001115 flowsToDelete := make([]*ofp.OfpFlowStats, 0)
khenaidoo19d7b632018-10-30 10:49:50 -04001116 idx := fu.FindFlows(flows, flow)
1117 if idx >= 0 {
Manikkaraj kb1a10922019-07-29 12:10:34 -04001118 changedMeter = agent.updateFlowCountOfMeterStats(mod, meters, flow)
1119 flowsToDelete = append(flowsToDelete, flows[idx])
khenaidoo19d7b632018-10-30 10:49:50 -04001120 flows = append(flows[:idx], flows[idx+1:]...)
Manikkaraj kb1a10922019-07-29 12:10:34 -04001121 changedFlow = true
khenaidoo19d7b632018-10-30 10:49:50 -04001122 } else {
1123 return errors.New(fmt.Sprintf("Cannot delete flow - %s", flow))
1124 }
Manikkaraj kb1a10922019-07-29 12:10:34 -04001125 if changedMeter {
1126 //Update model
1127 metersToUpdate := &ofp.Meters{}
1128 if lDevice.Meters != nil {
1129 metersToUpdate = &ofp.Meters{Items: meters}
1130 }
1131 if err := agent.updateLogicalDeviceMetersWithoutLock(metersToUpdate); err != nil {
1132 log.Errorw("db-meter-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
1133 return err
1134 }
khenaidoo19d7b632018-10-30 10:49:50 -04001135
Manikkaraj kb1a10922019-07-29 12:10:34 -04001136 }
1137 if changedFlow {
1138 var flowMetadata voltha.FlowMetadata
1139 if err := agent.GetMeterConfig(flowsToDelete, meters, &flowMetadata); err != nil {
1140 log.Error("Meter-referred-in-flows-not-present")
1141 return err
1142 }
1143 deviceRules := agent.flowDecomposer.DecomposeRules(agent, ofp.Flows{Items: flowsToDelete}, ofp.FlowGroups{})
khenaidoo0458db62019-06-20 08:50:36 -04001144 log.Debugw("rules", log.Fields{"rules": deviceRules.String()})
1145
Manikkaraj kb1a10922019-07-29 12:10:34 -04001146 if err := agent.deleteDeviceFlowsAndGroups(deviceRules, &flowMetadata); err != nil {
khenaidoo0458db62019-06-20 08:50:36 -04001147 log.Errorw("failure-deleting-device-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "error": err})
1148 return err
1149 }
1150
khenaidoo43c82122018-11-22 18:38:28 -05001151 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: flows}); err != nil {
khenaidoo0458db62019-06-20 08:50:36 -04001152 log.Errorw("Cannot-update-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -04001153 return err
1154 }
1155 }
khenaidoo19d7b632018-10-30 10:49:50 -04001156 return nil
1157}
1158
1159//flowModify modifies a flow from the flow table of that logical device
1160func (agent *LogicalDeviceAgent) flowModify(mod *ofp.OfpFlowMod) error {
1161 return errors.New("flowModify not implemented")
1162}
1163
1164//flowModifyStrict deletes a flow from the flow table of that logical device
1165func (agent *LogicalDeviceAgent) flowModifyStrict(mod *ofp.OfpFlowMod) error {
1166 return errors.New("flowModifyStrict not implemented")
1167}
1168
1169func (agent *LogicalDeviceAgent) groupAdd(groupMod *ofp.OfpGroupMod) error {
1170 log.Debug("groupAdd")
1171 if groupMod == nil {
1172 return nil
1173 }
1174 agent.lockLogicalDevice.Lock()
1175 defer agent.lockLogicalDevice.Unlock()
1176
1177 var lDevice *voltha.LogicalDevice
1178 var err error
1179 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
1180 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
1181 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
1182 }
1183 groups := lDevice.FlowGroups.Items
khenaidoo19d7b632018-10-30 10:49:50 -04001184 if fu.FindGroup(groups, groupMod.GroupId) == -1 {
khenaidoo68c930b2019-05-13 11:46:51 -04001185 groups = append(groups, fu.GroupEntryFromGroupMod(groupMod))
khenaidoo0458db62019-06-20 08:50:36 -04001186
1187 deviceRules := agent.flowDecomposer.DecomposeRules(agent, *lDevice.Flows, ofp.FlowGroups{Items: groups})
1188 log.Debugw("rules", log.Fields{"rules": deviceRules.String()})
Manikkaraj kb1a10922019-07-29 12:10:34 -04001189 if err := agent.addDeviceFlowsAndGroups(deviceRules, nil); err != nil {
khenaidoo0458db62019-06-20 08:50:36 -04001190 log.Errorw("failure-updating-device-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "error": err})
1191 return err
1192 }
1193
khenaidoo43c82122018-11-22 18:38:28 -05001194 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(&ofp.FlowGroups{Items: groups}); err != nil {
1195 log.Errorw("Cannot-update-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -04001196 return err
1197 }
1198 } else {
1199 return errors.New(fmt.Sprintf("Groups %d already present", groupMod.GroupId))
1200 }
khenaidoo19d7b632018-10-30 10:49:50 -04001201 return nil
1202}
1203
1204func (agent *LogicalDeviceAgent) groupDelete(groupMod *ofp.OfpGroupMod) error {
1205 log.Debug("groupDelete")
1206 if groupMod == nil {
1207 return nil
1208 }
1209 agent.lockLogicalDevice.Lock()
1210 defer agent.lockLogicalDevice.Unlock()
1211
1212 var lDevice *voltha.LogicalDevice
1213 var err error
1214 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
1215 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
1216 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
1217 }
1218 groups := lDevice.FlowGroups.Items
1219 flows := lDevice.Flows.Items
1220 groupsChanged := false
1221 flowsChanged := false
1222 groupId := groupMod.GroupId
1223 if groupId == uint32(ofp.OfpGroup_OFPG_ALL) {
1224 //TODO we must delete all flows that point to this group and
1225 //signal controller as requested by flow's flag
1226 groups = []*ofp.OfpGroupEntry{}
1227 groupsChanged = true
1228 } else {
1229 if idx := fu.FindGroup(groups, groupId); idx == -1 {
1230 return nil // Valid case
1231 } else {
1232 flowsChanged, flows = fu.FlowsDeleteByGroupId(flows, groupId)
1233 groups = append(groups[:idx], groups[idx+1:]...)
1234 groupsChanged = true
1235 }
1236 }
khenaidoo0458db62019-06-20 08:50:36 -04001237 if flowsChanged || groupsChanged {
1238 deviceRules := agent.flowDecomposer.DecomposeRules(agent, ofp.Flows{Items: flows}, ofp.FlowGroups{Items: groups})
1239 log.Debugw("rules", log.Fields{"rules": deviceRules.String()})
1240
Manikkaraj kb1a10922019-07-29 12:10:34 -04001241 if err := agent.updateDeviceFlowsAndGroups(deviceRules, nil); err != nil {
khenaidoo0458db62019-06-20 08:50:36 -04001242 log.Errorw("failure-updating-device-flows-groups", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "error": err})
1243 return err
1244 }
1245 }
1246
khenaidoo43c82122018-11-22 18:38:28 -05001247 if groupsChanged {
1248 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(&ofp.FlowGroups{Items: groups}); err != nil {
1249 log.Errorw("Cannot-update-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -04001250 return err
1251 }
1252 }
khenaidoo43c82122018-11-22 18:38:28 -05001253 if flowsChanged {
1254 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: flows}); err != nil {
1255 log.Errorw("Cannot-update-flow", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
1256 return err
1257 }
1258 }
khenaidoo19d7b632018-10-30 10:49:50 -04001259 return nil
1260}
1261
1262func (agent *LogicalDeviceAgent) groupModify(groupMod *ofp.OfpGroupMod) error {
1263 log.Debug("groupModify")
1264 if groupMod == nil {
1265 return nil
1266 }
1267 agent.lockLogicalDevice.Lock()
1268 defer agent.lockLogicalDevice.Unlock()
1269
1270 var lDevice *voltha.LogicalDevice
1271 var err error
1272 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
1273 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
1274 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
1275 }
1276 groups := lDevice.FlowGroups.Items
1277 groupsChanged := false
1278 groupId := groupMod.GroupId
1279 if idx := fu.FindGroup(groups, groupId); idx == -1 {
khenaidooca301322019-01-09 23:06:32 -05001280 return errors.New(fmt.Sprintf("group-absent:%d", groupId))
khenaidoo19d7b632018-10-30 10:49:50 -04001281 } else {
1282 //replace existing group entry with new group definition
khenaidoo68c930b2019-05-13 11:46:51 -04001283 groupEntry := fu.GroupEntryFromGroupMod(groupMod)
khenaidoo19d7b632018-10-30 10:49:50 -04001284 groups[idx] = groupEntry
1285 groupsChanged = true
1286 }
1287 if groupsChanged {
khenaidoo0458db62019-06-20 08:50:36 -04001288 deviceRules := agent.flowDecomposer.DecomposeRules(agent, ofp.Flows{Items: lDevice.Flows.Items}, ofp.FlowGroups{Items: groups})
1289 log.Debugw("rules", log.Fields{"rules": deviceRules.String()})
1290
Manikkaraj kb1a10922019-07-29 12:10:34 -04001291 if err := agent.updateDeviceFlowsAndGroups(deviceRules, nil); err != nil {
khenaidoo0458db62019-06-20 08:50:36 -04001292 log.Errorw("failure-updating-device-flows-groups", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "error": err})
1293 return err
1294 }
1295
khenaidoo43c82122018-11-22 18:38:28 -05001296 //lDevice.FlowGroups.Items = groups
1297 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(&ofp.FlowGroups{Items: groups}); err != nil {
khenaidoo19d7b632018-10-30 10:49:50 -04001298 log.Errorw("Cannot-update-logical-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
1299 return err
1300 }
1301 }
1302 return nil
1303}
1304
1305// deleteLogicalPort removes the logical port
1306func (agent *LogicalDeviceAgent) deleteLogicalPort(lPort *voltha.LogicalPort) error {
1307 agent.lockLogicalDevice.Lock()
1308 defer agent.lockLogicalDevice.Unlock()
1309
khenaidoo92e62c52018-10-03 14:02:54 -04001310 // Get the most up to date logical device
1311 var logicaldevice *voltha.LogicalDevice
1312 if logicaldevice, _ = agent.getLogicalDeviceWithoutLock(); logicaldevice == nil {
khenaidoo19d7b632018-10-30 10:49:50 -04001313 log.Debugw("no-logical-device", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "logicalPortId": lPort.Id})
khenaidoob9203542018-09-17 22:56:37 -04001314 return nil
1315 }
khenaidoo92e62c52018-10-03 14:02:54 -04001316 index := -1
1317 for i, logicalPort := range logicaldevice.Ports {
khenaidoo19d7b632018-10-30 10:49:50 -04001318 if logicalPort.Id == lPort.Id {
khenaidoo92e62c52018-10-03 14:02:54 -04001319 index = i
1320 break
1321 }
1322 }
1323 if index >= 0 {
1324 copy(logicaldevice.Ports[index:], logicaldevice.Ports[index+1:])
1325 logicaldevice.Ports[len(logicaldevice.Ports)-1] = nil
1326 logicaldevice.Ports = logicaldevice.Ports[:len(logicaldevice.Ports)-1]
1327 log.Debugw("logical-port-deleted", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo0a822f92019-05-08 15:15:57 -04001328 if err := agent.updateLogicalDeviceWithoutLock(logicaldevice); err != nil {
1329 log.Errorw("logical-device-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
1330 return err
1331 }
1332 // Reset the logical device graph
khenaidoo3d3b8c22019-05-22 18:10:39 -04001333 go agent.generateDeviceGraph()
khenaidoo92e62c52018-10-03 14:02:54 -04001334 }
1335 return nil
khenaidoob9203542018-09-17 22:56:37 -04001336}
1337
khenaidoo0a822f92019-05-08 15:15:57 -04001338// deleteLogicalPorts removes the logical ports associated with that deviceId
1339func (agent *LogicalDeviceAgent) deleteLogicalPorts(deviceId string) 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})
1347 return nil
1348 }
1349 updatedLPorts := []*voltha.LogicalPort{}
1350 for _, logicalPort := range logicaldevice.Ports {
1351 if logicalPort.DeviceId != deviceId {
1352 updatedLPorts = append(updatedLPorts, logicalPort)
1353 }
1354 }
1355 logicaldevice.Ports = updatedLPorts
1356 log.Debugw("updated-logical-ports", log.Fields{"ports": updatedLPorts})
1357 if err := agent.updateLogicalDeviceWithoutLock(logicaldevice); err != nil {
1358 log.Errorw("logical-device-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
1359 return err
1360 }
1361 // Reset the logical device graph
khenaidoo3d3b8c22019-05-22 18:10:39 -04001362 go agent.generateDeviceGraph()
khenaidoo0a822f92019-05-08 15:15:57 -04001363
1364 return nil
1365}
1366
khenaidoo19d7b632018-10-30 10:49:50 -04001367// enableLogicalPort enables the logical port
1368func (agent *LogicalDeviceAgent) enableLogicalPort(lPort *voltha.LogicalPort) error {
1369 agent.lockLogicalDevice.Lock()
1370 defer agent.lockLogicalDevice.Unlock()
1371
1372 // Get the most up to date logical device
1373 var logicaldevice *voltha.LogicalDevice
1374 if logicaldevice, _ = agent.getLogicalDeviceWithoutLock(); logicaldevice == nil {
1375 log.Debugw("no-logical-device", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "logicalPortId": lPort.Id})
1376 return nil
1377 }
1378 index := -1
1379 for i, logicalPort := range logicaldevice.Ports {
1380 if logicalPort.Id == lPort.Id {
1381 index = i
1382 break
1383 }
1384 }
1385 if index >= 0 {
1386 logicaldevice.Ports[index].OfpPort.Config = logicaldevice.Ports[index].OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
1387 return agent.updateLogicalDeviceWithoutLock(logicaldevice)
1388 }
1389 //TODO: Trigger subsequent actions on the device
1390 return nil
1391}
1392
1393// disableLogicalPort disabled the logical port
1394func (agent *LogicalDeviceAgent) disableLogicalPort(lPort *voltha.LogicalPort) error {
1395 agent.lockLogicalDevice.Lock()
1396 defer agent.lockLogicalDevice.Unlock()
1397
1398 // Get the most up to date logical device
1399 var logicaldevice *voltha.LogicalDevice
1400 if logicaldevice, _ = agent.getLogicalDeviceWithoutLock(); logicaldevice == nil {
1401 log.Debugw("no-logical-device", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "logicalPortId": lPort.Id})
1402 return nil
1403 }
1404 index := -1
1405 for i, logicalPort := range logicaldevice.Ports {
1406 if logicalPort.Id == lPort.Id {
1407 index = i
1408 break
1409 }
1410 }
1411 if index >= 0 {
1412 logicaldevice.Ports[index].OfpPort.Config = (logicaldevice.Ports[index].OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)) | uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
1413 return agent.updateLogicalDeviceWithoutLock(logicaldevice)
1414 }
1415 //TODO: Trigger subsequent actions on the device
1416 return nil
1417}
1418
khenaidoo89b0e942018-10-21 21:11:33 -04001419func (agent *LogicalDeviceAgent) getPreCalculatedRoute(ingress, egress uint32) []graph.RouteHop {
khenaidoo19d7b632018-10-30 10:49:50 -04001420 log.Debugw("ROUTE", log.Fields{"len": len(agent.deviceGraph.Routes)})
khenaidoo89b0e942018-10-21 21:11:33 -04001421 for routeLink, route := range agent.deviceGraph.Routes {
khenaidoo19d7b632018-10-30 10:49:50 -04001422 log.Debugw("ROUTELINKS", log.Fields{"ingress": ingress, "egress": egress, "routelink": routeLink})
khenaidoo89b0e942018-10-21 21:11:33 -04001423 if ingress == routeLink.Ingress && egress == routeLink.Egress {
1424 return route
1425 }
1426 }
1427 log.Warnw("no-route", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "ingress": ingress, "egress": egress})
1428 return nil
1429}
1430
khenaidoo19d7b632018-10-30 10:49:50 -04001431func (agent *LogicalDeviceAgent) GetRoute(ingressPortNo uint32, egressPortNo uint32) []graph.RouteHop {
khenaidoo89b0e942018-10-21 21:11:33 -04001432 log.Debugw("getting-route", log.Fields{"ingress-port": ingressPortNo, "egress-port": egressPortNo})
khenaidoo89b0e942018-10-21 21:11:33 -04001433 routes := make([]graph.RouteHop, 0)
khenaidoo2c6a0992019-04-29 13:46:56 -04001434
khenaidoo19d7b632018-10-30 10:49:50 -04001435 // Note: A port value of 0 is equivalent to a nil port
1436
khenaidoo89b0e942018-10-21 21:11:33 -04001437 // Consider different possibilities
khenaidoo19d7b632018-10-30 10:49:50 -04001438 if egressPortNo != 0 && ((egressPortNo & 0x7fffffff) == uint32(ofp.OfpPortNo_OFPP_CONTROLLER)) {
khenaidoo2c6a0992019-04-29 13:46:56 -04001439 log.Debugw("controller-flow", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "logicalPortsNo": agent.logicalPortsNo})
1440 if agent.isNNIPort(ingressPortNo) {
khenaidoo89b0e942018-10-21 21:11:33 -04001441 //This is a trap on the NNI Port
khenaidoo8f474192019-04-03 17:20:44 -04001442 if len(agent.deviceGraph.Routes) == 0 {
1443 // If there are no routes set (usually when the logical device has only NNI port(s), then just return an
Humera Kouser4ff89012019-08-25 19:01:51 -04001444 // route with same IngressHop and EgressHop
1445 hop := graph.RouteHop{DeviceID: agent.rootDeviceId, Ingress: ingressPortNo, Egress: ingressPortNo}
khenaidoo8f474192019-04-03 17:20:44 -04001446 routes = append(routes, hop)
1447 routes = append(routes, hop)
1448 return routes
1449 }
khenaidoo89b0e942018-10-21 21:11:33 -04001450 //Return a 'half' route to make the flow decomposer logic happy
1451 for routeLink, route := range agent.deviceGraph.Routes {
khenaidoo2c6a0992019-04-29 13:46:56 -04001452 if agent.isNNIPort(routeLink.Egress) {
khenaidoo89b0e942018-10-21 21:11:33 -04001453 routes = append(routes, graph.RouteHop{}) // first hop is set to empty
1454 routes = append(routes, route[1])
1455 return routes
1456 }
1457 }
khenaidoo2c6a0992019-04-29 13:46:56 -04001458 log.Warnw("no-upstream-route", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "logicalPortsNo": agent.logicalPortsNo})
khenaidoo89b0e942018-10-21 21:11:33 -04001459 return nil
1460 }
1461 //treat it as if the output port is the first NNI of the OLT
khenaidoo2c6a0992019-04-29 13:46:56 -04001462 var err error
1463 if egressPortNo, err = agent.getFirstNNIPort(); err != nil {
1464 log.Warnw("no-nni-port", log.Fields{"error": err})
1465 return nil
1466 }
khenaidoo89b0e942018-10-21 21:11:33 -04001467 }
1468 //If ingress port is not specified (nil), it may be a wildcarded
1469 //route if egress port is OFPP_CONTROLLER or a nni logical port,
1470 //in which case we need to create a half-route where only the egress
1471 //hop is filled, the first hop is nil
khenaidoo2c6a0992019-04-29 13:46:56 -04001472 if ingressPortNo == 0 && agent.isNNIPort(egressPortNo) {
khenaidoo89b0e942018-10-21 21:11:33 -04001473 // We can use the 2nd hop of any upstream route, so just find the first upstream:
1474 for routeLink, route := range agent.deviceGraph.Routes {
khenaidoo2c6a0992019-04-29 13:46:56 -04001475 if agent.isNNIPort(routeLink.Egress) {
khenaidoo89b0e942018-10-21 21:11:33 -04001476 routes = append(routes, graph.RouteHop{}) // first hop is set to empty
1477 routes = append(routes, route[1])
1478 return routes
1479 }
1480 }
khenaidoo2c6a0992019-04-29 13:46:56 -04001481 log.Warnw("no-upstream-route", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "logicalPortsNo": agent.logicalPortsNo})
khenaidoo89b0e942018-10-21 21:11:33 -04001482 return nil
1483 }
1484 //If egress port is not specified (nil), we can also can return a "half" route
khenaidoo19d7b632018-10-30 10:49:50 -04001485 if egressPortNo == 0 {
khenaidoo89b0e942018-10-21 21:11:33 -04001486 for routeLink, route := range agent.deviceGraph.Routes {
khenaidoo19d7b632018-10-30 10:49:50 -04001487 if routeLink.Ingress == ingressPortNo {
khenaidoo89b0e942018-10-21 21:11:33 -04001488 routes = append(routes, route[0])
1489 routes = append(routes, graph.RouteHop{})
1490 return routes
1491 }
1492 }
khenaidoo2c6a0992019-04-29 13:46:56 -04001493 log.Warnw("no-downstream-route", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "logicalPortsNo": agent.logicalPortsNo})
khenaidoo89b0e942018-10-21 21:11:33 -04001494 return nil
1495 }
khenaidoo89b0e942018-10-21 21:11:33 -04001496 // Return the pre-calculated route
khenaidoo19d7b632018-10-30 10:49:50 -04001497 return agent.getPreCalculatedRoute(ingressPortNo, egressPortNo)
khenaidoo89b0e942018-10-21 21:11:33 -04001498}
1499
khenaidoo3d3b8c22019-05-22 18:10:39 -04001500//GetWildcardInputPorts filters out the logical port number from the set of logical ports on the device and
1501//returns their port numbers. This function is invoked only during flow decomposition where the lock on the logical
1502//device is already held. Therefore it is safe to retrieve the logical device without lock.
khenaidoo89b0e942018-10-21 21:11:33 -04001503func (agent *LogicalDeviceAgent) GetWildcardInputPorts(excludePort ...uint32) []uint32 {
1504 lPorts := make([]uint32, 0)
1505 var exclPort uint32
1506 if len(excludePort) == 1 {
1507 exclPort = excludePort[0]
1508 }
khenaidoo3d3b8c22019-05-22 18:10:39 -04001509 if lDevice, _ := agent.getLogicalDeviceWithoutLock(); lDevice != nil {
khenaidoo89b0e942018-10-21 21:11:33 -04001510 for _, port := range lDevice.Ports {
1511 if port.OfpPort.PortNo != exclPort {
1512 lPorts = append(lPorts, port.OfpPort.PortNo)
1513 }
1514 }
1515 }
1516 return lPorts
1517}
khenaidoo19d7b632018-10-30 10:49:50 -04001518
1519func (agent *LogicalDeviceAgent) GetDeviceGraph() *graph.DeviceGraph {
1520 return agent.deviceGraph
1521}
1522
khenaidoo3306c992019-05-24 16:57:35 -04001523//updateRoutes rebuilds the device graph if not done already
khenaidoo2c6a0992019-04-29 13:46:56 -04001524func (agent *LogicalDeviceAgent) updateRoutes(device *voltha.Device, port *voltha.Port) error {
1525 log.Debugf("updateRoutes", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "device": device.Id, "port": port})
khenaidoo910204f2019-04-08 17:56:40 -04001526 agent.lockLogicalDevice.Lock()
1527 defer agent.lockLogicalDevice.Unlock()
khenaidoo19d7b632018-10-30 10:49:50 -04001528 if agent.deviceGraph == nil {
khenaidoo910204f2019-04-08 17:56:40 -04001529 agent.deviceGraph = graph.NewDeviceGraph(agent.logicalDeviceId, agent.deviceMgr.GetDevice)
khenaidoo2c6a0992019-04-29 13:46:56 -04001530 }
1531 // Get all the logical ports on that logical device
1532 if lDevice, err := agent.getLogicalDeviceWithoutLock(); err != nil {
manikkaraj k259a6f72019-05-06 09:55:44 -04001533 log.Errorw("unknown-logical-device", log.Fields{"error": err, "logicalDeviceId": agent.logicalDeviceId})
khenaidoo2c6a0992019-04-29 13:46:56 -04001534 return err
1535 } else {
1536 //TODO: Find a better way to refresh only missing routes
1537 agent.deviceGraph.ComputeRoutes(lDevice.Ports)
1538 }
khenaidoo2c6a0992019-04-29 13:46:56 -04001539 agent.deviceGraph.Print()
1540 return nil
khenaidoo19d7b632018-10-30 10:49:50 -04001541}
1542
khenaidoo2c6a0992019-04-29 13:46:56 -04001543//updateDeviceGraph updates the device graph if not done already and setup the default rules as well
khenaidoo910204f2019-04-08 17:56:40 -04001544func (agent *LogicalDeviceAgent) updateDeviceGraph(lp *voltha.LogicalPort) {
khenaidoo2c6a0992019-04-29 13:46:56 -04001545 log.Debugf("updateDeviceGraph", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
1546 agent.lockLogicalDevice.Lock()
1547 defer agent.lockLogicalDevice.Unlock()
khenaidoo910204f2019-04-08 17:56:40 -04001548 if agent.deviceGraph == nil {
1549 agent.deviceGraph = graph.NewDeviceGraph(agent.logicalDeviceId, agent.deviceMgr.GetDevice)
1550 }
1551 agent.deviceGraph.AddPort(lp)
khenaidoo2c6a0992019-04-29 13:46:56 -04001552 agent.deviceGraph.Print()
khenaidoo19d7b632018-10-30 10:49:50 -04001553}
khenaidoofdbad6e2018-11-06 22:26:38 -05001554
khenaidoo3d3b8c22019-05-22 18:10:39 -04001555//generateDeviceGraph regenerates the device graph
1556func (agent *LogicalDeviceAgent) generateDeviceGraph() {
khenaidoo4c9e5592019-09-09 16:20:41 -04001557 log.Debugw("generateDeviceGraph", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo0a822f92019-05-08 15:15:57 -04001558 agent.lockLogicalDevice.Lock()
1559 defer agent.lockLogicalDevice.Unlock()
1560 // Get the latest logical device
1561 if ld, err := agent.getLogicalDeviceWithoutLock(); err != nil {
1562 log.Errorw("logical-device-not-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "error": err})
1563 } else {
khenaidoo4c9e5592019-09-09 16:20:41 -04001564 log.Debugw("generating-graph", log.Fields{"lDeviceId": agent.logicalDeviceId, "lPorts": len(ld.Ports)})
khenaidoo3d3b8c22019-05-22 18:10:39 -04001565 if agent.deviceGraph == nil {
1566 agent.deviceGraph = graph.NewDeviceGraph(agent.logicalDeviceId, agent.deviceMgr.GetDevice)
1567 }
khenaidoo0a822f92019-05-08 15:15:57 -04001568 agent.deviceGraph.ComputeRoutes(ld.Ports)
khenaidoo3d3b8c22019-05-22 18:10:39 -04001569 agent.deviceGraph.Print()
khenaidoo0a822f92019-05-08 15:15:57 -04001570 }
1571}
1572
khenaidoofc1314d2019-03-14 09:34:21 -04001573// portAdded is a callback invoked when a port is added to the logical device.
1574// TODO: To use when POST_ADD is fixed.
1575func (agent *LogicalDeviceAgent) portAdded(args ...interface{}) interface{} {
1576 log.Debugw("portAdded-callback", log.Fields{"argsLen": len(args)})
1577
1578 var port *voltha.LogicalPort
1579
1580 // Sanity check
1581 if args[0] != nil {
1582 log.Warnw("previous-data-not-nil", log.Fields{"args0": args[0]})
1583 }
1584 var ok bool
1585 if port, ok = args[1].(*voltha.LogicalPort); !ok {
1586 log.Errorw("invalid-args", log.Fields{"args1": args[1]})
1587 return nil
1588 }
1589
1590 // Set the proxy and callback for that port
1591 agent.portProxiesLock.Lock()
Stephane Barbarie40fd3b22019-04-23 21:50:47 -04001592 agent.portProxies[port.Id] = agent.clusterDataProxy.CreateProxy(
Stephane Barbarieef6650d2019-07-18 12:15:09 -04001593 context.Background(),
khenaidoofc1314d2019-03-14 09:34:21 -04001594 fmt.Sprintf("/logical_devices/%s/ports/%s", agent.logicalDeviceId, port.Id),
1595 false)
1596 agent.portProxies[port.Id].RegisterCallback(model.POST_UPDATE, agent.portUpdated)
1597 agent.portProxiesLock.Unlock()
1598
1599 // Send the port change event to the OF controller
1600 agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceId,
khenaidoo910204f2019-04-08 17:56:40 -04001601 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_ADD, Desc: port.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001602
1603 return nil
1604}
1605
1606// portRemoved is a callback invoked when a port is removed from the logical device.
1607// TODO: To use when POST_ADD is fixed.
1608func (agent *LogicalDeviceAgent) portRemoved(args ...interface{}) interface{} {
1609 log.Debugw("portRemoved-callback", log.Fields{"argsLen": len(args)})
1610
1611 var port *voltha.LogicalPort
1612
1613 // Sanity check
1614 if args[1] != nil {
1615 log.Warnw("data-not-nil", log.Fields{"args1": args[1]})
1616 }
1617 var ok bool
1618 if port, ok = args[0].(*voltha.LogicalPort); !ok {
1619 log.Errorw("invalid-args", log.Fields{"args0": args[0]})
1620 return nil
1621 }
1622
1623 // Remove the proxy and callback for that port
1624 agent.portProxiesLock.Lock()
1625 agent.portProxies[port.Id].UnregisterCallback(model.POST_UPDATE, agent.portUpdated)
1626 delete(agent.portProxies, port.Id)
1627 agent.portProxiesLock.Unlock()
1628
1629 // Send the port change event to the OF controller
1630 agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceId,
khenaidoo910204f2019-04-08 17:56:40 -04001631 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_DELETE, Desc: port.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001632
1633 return nil
1634}
1635
1636// 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 -04001637func diff(oldList, newList []*voltha.LogicalPort) (newPorts, changedPorts, deletedPorts []*voltha.LogicalPort) {
khenaidoofc1314d2019-03-14 09:34:21 -04001638 newPorts = make([]*voltha.LogicalPort, 0)
1639 changedPorts = make([]*voltha.LogicalPort, 0)
1640 deletedPorts = make([]*voltha.LogicalPort, 0)
1641 for _, o := range oldList {
1642 found := false
khenaidoofc1314d2019-03-14 09:34:21 -04001643 for _, n := range newList {
1644 if o.Id == n.Id {
khenaidoofc1314d2019-03-14 09:34:21 -04001645 found = true
1646 break
1647 }
1648 }
1649 if !found {
1650 deletedPorts = append(deletedPorts, o)
1651 }
khenaidoofc1314d2019-03-14 09:34:21 -04001652 }
1653 for _, n := range newList {
1654 found := false
khenaidoo2bc48282019-07-16 18:13:46 -04001655 changed := false
khenaidoofc1314d2019-03-14 09:34:21 -04001656 for _, o := range oldList {
1657 if o.Id == n.Id {
khenaidoo2bc48282019-07-16 18:13:46 -04001658 changed = !reflect.DeepEqual(o, n)
khenaidoofc1314d2019-03-14 09:34:21 -04001659 found = true
1660 break
1661 }
1662 }
1663 if !found {
1664 newPorts = append(newPorts, n)
1665 }
khenaidoo2bc48282019-07-16 18:13:46 -04001666 if changed {
1667 changedPorts = append(changedPorts, n)
1668 }
khenaidoofc1314d2019-03-14 09:34:21 -04001669 }
1670 return
1671}
1672
1673// portUpdated is invoked when a port is updated on the logical device. Until
1674// the POST_ADD notification is fixed, we will use the logical device to
1675// update that data.
1676func (agent *LogicalDeviceAgent) portUpdated(args ...interface{}) interface{} {
1677 log.Debugw("portUpdated-callback", log.Fields{"argsLen": len(args)})
1678
1679 var oldLD *voltha.LogicalDevice
1680 var newlD *voltha.LogicalDevice
1681
1682 var ok bool
1683 if oldLD, ok = args[0].(*voltha.LogicalDevice); !ok {
1684 log.Errorw("invalid-args", log.Fields{"args0": args[0]})
1685 return nil
1686 }
1687 if newlD, ok = args[1].(*voltha.LogicalDevice); !ok {
1688 log.Errorw("invalid-args", log.Fields{"args1": args[1]})
1689 return nil
1690 }
1691
1692 if reflect.DeepEqual(oldLD.Ports, newlD.Ports) {
1693 log.Debug("ports-have-not-changed")
1694 return nil
1695 }
1696
1697 // Get the difference between the two list
1698 newPorts, changedPorts, deletedPorts := diff(oldLD.Ports, newlD.Ports)
1699
1700 // Send the port change events to the OF controller
khenaidoo2c6a0992019-04-29 13:46:56 -04001701 for _, newP := range newPorts {
khenaidoofc1314d2019-03-14 09:34:21 -04001702 go agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceId,
khenaidoo2c6a0992019-04-29 13:46:56 -04001703 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_ADD, Desc: newP.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001704 }
1705 for _, change := range changedPorts {
1706 go agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceId,
khenaidoo910204f2019-04-08 17:56:40 -04001707 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_MODIFY, Desc: change.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001708 }
1709 for _, del := range deletedPorts {
1710 go agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceId,
khenaidoo910204f2019-04-08 17:56:40 -04001711 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_DELETE, Desc: del.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001712 }
1713
1714 return nil
1715}
1716
khenaidoo8f474192019-04-03 17:20:44 -04001717// addNNILogicalPort adds an NNI port to the logical device. It returns a bool representing whether a port has been
1718// added and an eror in case a valid error is encountered. If the port was successfully added it will return
1719// (true, nil). If the device is not in the correct state it will return (false, nil) as this is a valid
1720// scenario. This also applies to the case where the port was already added.
khenaidoo910204f2019-04-08 17:56:40 -04001721func (agent *LogicalDeviceAgent) addNNILogicalPort(device *voltha.Device, port *voltha.Port) (bool, error) {
khenaidoo1ce37ad2019-03-24 22:07:24 -04001722 log.Debugw("addNNILogicalPort", log.Fields{"NNI": port})
khenaidoo8f474192019-04-03 17:20:44 -04001723 if device.AdminState != voltha.AdminState_ENABLED || device.OperStatus != voltha.OperStatus_ACTIVE {
1724 log.Infow("device-not-ready", log.Fields{"deviceId": device.Id, "admin": device.AdminState, "oper": device.OperStatus})
1725 return false, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001726 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001727 agent.lockLogicalDevice.RLock()
1728 if agent.portExist(device, port) {
1729 log.Debugw("port-already-exist", log.Fields{"port": port})
1730 agent.lockLogicalDevice.RUnlock()
khenaidoo8f474192019-04-03 17:20:44 -04001731 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001732 }
1733 agent.lockLogicalDevice.RUnlock()
1734
khenaidoofc1314d2019-03-14 09:34:21 -04001735 var portCap *ic.PortCapability
1736 var err error
1737 // First get the port capability
1738 if portCap, err = agent.deviceMgr.getPortCapability(nil, device.Id, port.PortNo); err != nil {
1739 log.Errorw("error-retrieving-port-capabilities", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001740 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001741 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001742
1743 agent.lockLogicalDevice.Lock()
1744 defer agent.lockLogicalDevice.Unlock()
1745 // Double check again if this port has been already added since the getPortCapability could have taken a long time
1746 if agent.portExist(device, port) {
1747 log.Debugw("port-already-exist", log.Fields{"port": port})
khenaidoo8f474192019-04-03 17:20:44 -04001748 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001749 }
1750
khenaidoofc1314d2019-03-14 09:34:21 -04001751 portCap.Port.RootPort = true
1752 lp := (proto.Clone(portCap.Port)).(*voltha.LogicalPort)
1753 lp.DeviceId = device.Id
1754 lp.Id = fmt.Sprintf("nni-%d", port.PortNo)
1755 lp.OfpPort.PortNo = port.PortNo
1756 lp.OfpPort.Name = lp.Id
1757 lp.DevicePortNo = port.PortNo
1758
khenaidoofc1314d2019-03-14 09:34:21 -04001759 var ld *voltha.LogicalDevice
1760 if ld, err = agent.getLogicalDeviceWithoutLock(); err != nil {
1761 log.Errorw("error-retrieving-logical-device", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001762 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001763 }
1764 cloned := (proto.Clone(ld)).(*voltha.LogicalDevice)
1765 if cloned.Ports == nil {
1766 cloned.Ports = make([]*voltha.LogicalPort, 0)
1767 }
1768 cloned.Ports = append(cloned.Ports, lp)
1769
1770 if err = agent.updateLogicalDeviceWithoutLock(cloned); err != nil {
1771 log.Errorw("error-updating-logical-device", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001772 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001773 }
khenaidoo910204f2019-04-08 17:56:40 -04001774
1775 // Update the device graph with this new logical port
1776 clonedLP := (proto.Clone(lp)).(*voltha.LogicalPort)
1777 go agent.updateDeviceGraph(clonedLP)
1778
khenaidoo8f474192019-04-03 17:20:44 -04001779 return true, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001780}
1781
khenaidoo910204f2019-04-08 17:56:40 -04001782func (agent *LogicalDeviceAgent) portExist(device *voltha.Device, port *voltha.Port) bool {
khenaidoo54544ae2019-03-18 13:22:39 -04001783 if ldevice, _ := agent.getLogicalDeviceWithoutLock(); ldevice != nil {
khenaidoofc1314d2019-03-14 09:34:21 -04001784 for _, lPort := range ldevice.Ports {
khenaidoo54544ae2019-03-18 13:22:39 -04001785 if lPort.DeviceId == device.Id && lPort.DevicePortNo == port.PortNo && lPort.Id == port.Label {
khenaidoofc1314d2019-03-14 09:34:21 -04001786 return true
1787 }
1788 }
1789 }
1790 return false
1791}
1792
khenaidoo8f474192019-04-03 17:20:44 -04001793// addUNILogicalPort adds an UNI port to the logical device. It returns a bool representing whether a port has been
1794// added and an eror in case a valid error is encountered. If the port was successfully added it will return
1795// (true, nil). If the device is not in the correct state it will return (false, nil) as this is a valid
1796// scenario. This also applies to the case where the port was already added.
khenaidoo910204f2019-04-08 17:56:40 -04001797func (agent *LogicalDeviceAgent) addUNILogicalPort(childDevice *voltha.Device, port *voltha.Port) (bool, error) {
khenaidoofc1314d2019-03-14 09:34:21 -04001798 log.Debugw("addUNILogicalPort", log.Fields{"port": port})
khenaidoo8f474192019-04-03 17:20:44 -04001799 if childDevice.AdminState != voltha.AdminState_ENABLED || childDevice.OperStatus != voltha.OperStatus_ACTIVE {
1800 log.Infow("device-not-ready", log.Fields{"deviceId": childDevice.Id, "admin": childDevice.AdminState, "oper": childDevice.OperStatus})
1801 return false, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001802 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001803 agent.lockLogicalDevice.RLock()
1804 if agent.portExist(childDevice, port) {
1805 log.Debugw("port-already-exist", log.Fields{"port": port})
1806 agent.lockLogicalDevice.RUnlock()
khenaidoo8f474192019-04-03 17:20:44 -04001807 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001808 }
1809 agent.lockLogicalDevice.RUnlock()
khenaidoofc1314d2019-03-14 09:34:21 -04001810 var portCap *ic.PortCapability
1811 var err error
1812 // First get the port capability
1813 if portCap, err = agent.deviceMgr.getPortCapability(nil, childDevice.Id, port.PortNo); err != nil {
1814 log.Errorw("error-retrieving-port-capabilities", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001815 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001816 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001817 agent.lockLogicalDevice.Lock()
1818 defer agent.lockLogicalDevice.Unlock()
1819 // Double check again if this port has been already added since the getPortCapability could have taken a long time
1820 if agent.portExist(childDevice, port) {
1821 log.Debugw("port-already-exist", log.Fields{"port": port})
khenaidoo8f474192019-04-03 17:20:44 -04001822 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001823 }
khenaidoofc1314d2019-03-14 09:34:21 -04001824 // Get stored logical device
1825 if ldevice, err := agent.getLogicalDeviceWithoutLock(); err != nil {
khenaidoo8f474192019-04-03 17:20:44 -04001826 return false, status.Error(codes.NotFound, agent.logicalDeviceId)
khenaidoofc1314d2019-03-14 09:34:21 -04001827 } else {
1828 log.Debugw("adding-uni", log.Fields{"deviceId": childDevice.Id})
1829 portCap.Port.RootPort = false
Matt Jeanneret3815e322019-03-12 19:15:49 -04001830 portCap.Port.Id = port.Label
1831 portCap.Port.OfpPort.PortNo = port.PortNo
khenaidoofc1314d2019-03-14 09:34:21 -04001832 portCap.Port.DeviceId = childDevice.Id
1833 portCap.Port.DevicePortNo = port.PortNo
1834 cloned := (proto.Clone(ldevice)).(*voltha.LogicalDevice)
1835 if cloned.Ports == nil {
1836 cloned.Ports = make([]*voltha.LogicalPort, 0)
1837 }
1838 cloned.Ports = append(cloned.Ports, portCap.Port)
khenaidoo910204f2019-04-08 17:56:40 -04001839 if err := agent.updateLogicalDeviceWithoutLock(cloned); err != nil {
1840 return false, err
1841 }
khenaidoo910204f2019-04-08 17:56:40 -04001842 // Update the device graph with this new logical port
1843 clonedLP := (proto.Clone(portCap.Port)).(*voltha.LogicalPort)
1844 go agent.updateDeviceGraph(clonedLP)
1845 return true, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001846 }
1847}
1848
khenaidoo43c82122018-11-22 18:38:28 -05001849func (agent *LogicalDeviceAgent) packetOut(packet *ofp.OfpPacketOut) {
khenaidoofdbad6e2018-11-06 22:26:38 -05001850 log.Debugw("packet-out", log.Fields{"packet": packet.GetInPort()})
khenaidoo68c930b2019-05-13 11:46:51 -04001851 outPort := fu.GetPacketOutPort(packet)
khenaidoofdbad6e2018-11-06 22:26:38 -05001852 //frame := packet.GetData()
1853 //TODO: Use a channel between the logical agent and the device agent
khenaidooca301322019-01-09 23:06:32 -05001854 if err := agent.deviceMgr.packetOut(agent.rootDeviceId, outPort, packet); err != nil {
khenaidoo910204f2019-04-08 17:56:40 -04001855 log.Error("packetout-failed", log.Fields{"logicalDeviceID": agent.rootDeviceId})
khenaidooca301322019-01-09 23:06:32 -05001856 }
khenaidoofdbad6e2018-11-06 22:26:38 -05001857}
1858
khenaidoo297cd252019-02-07 22:10:23 -05001859func (agent *LogicalDeviceAgent) packetIn(port uint32, transactionId string, packet []byte) {
1860 log.Debugw("packet-in", log.Fields{"port": port, "packet": packet, "transactionId": transactionId})
khenaidoo68c930b2019-05-13 11:46:51 -04001861 packetIn := fu.MkPacketIn(port, packet)
khenaidoo297cd252019-02-07 22:10:23 -05001862 agent.ldeviceMgr.grpcNbiHdlr.sendPacketIn(agent.logicalDeviceId, transactionId, packetIn)
khenaidooca301322019-01-09 23:06:32 -05001863 log.Debugw("sending-packet-in", log.Fields{"packet-in": packetIn})
khenaidoofdbad6e2018-11-06 22:26:38 -05001864}
khenaidoo2c6a0992019-04-29 13:46:56 -04001865
1866func (agent *LogicalDeviceAgent) addLogicalPortToMap(portNo uint32, nniPort bool) {
1867 agent.lockLogicalPortsNo.Lock()
1868 defer agent.lockLogicalPortsNo.Unlock()
1869 if exist := agent.logicalPortsNo[portNo]; !exist {
1870 agent.logicalPortsNo[portNo] = nniPort
1871 }
1872}
1873
khenaidoo3d3b8c22019-05-22 18:10:39 -04001874func (agent *LogicalDeviceAgent) addLogicalPortsToMap(lps []*voltha.LogicalPort) {
1875 agent.lockLogicalPortsNo.Lock()
1876 defer agent.lockLogicalPortsNo.Unlock()
1877 for _, lp := range lps {
1878 if exist := agent.logicalPortsNo[lp.DevicePortNo]; !exist {
1879 agent.logicalPortsNo[lp.DevicePortNo] = lp.RootPort
1880 }
1881 }
1882}
1883
khenaidoo2c6a0992019-04-29 13:46:56 -04001884func (agent *LogicalDeviceAgent) deleteLogicalPortFromMap(portNo uint32) {
1885 agent.lockLogicalPortsNo.Lock()
1886 defer agent.lockLogicalPortsNo.Unlock()
1887 if exist := agent.logicalPortsNo[portNo]; exist {
1888 delete(agent.logicalPortsNo, portNo)
1889 }
1890}
1891
1892func (agent *LogicalDeviceAgent) isNNIPort(portNo uint32) bool {
1893 agent.lockLogicalPortsNo.RLock()
1894 defer agent.lockLogicalPortsNo.RUnlock()
1895 if exist := agent.logicalPortsNo[portNo]; exist {
1896 return agent.logicalPortsNo[portNo]
1897 }
1898 return false
1899}
1900
1901func (agent *LogicalDeviceAgent) getFirstNNIPort() (uint32, error) {
1902 agent.lockLogicalPortsNo.RLock()
1903 defer agent.lockLogicalPortsNo.RUnlock()
1904 for portNo, nni := range agent.logicalPortsNo {
1905 if nni {
1906 return portNo, nil
1907 }
1908 }
1909 return 0, status.Error(codes.NotFound, "No NNI port found")
1910}