blob: 25a073aaba46ae92bcf95e29f4d25468c39df3e6 [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 */
npujar1d86a522019-11-14 17:11:16 +053016
khenaidoob9203542018-09-17 22:56:37 -040017package core
18
19import (
20 "context"
Matteo Scandolo360605d2019-11-05 18:29:17 -080021 "encoding/hex"
khenaidoo19d7b632018-10-30 10:49:50 -040022 "errors"
23 "fmt"
khenaidoo820197c2020-02-13 16:35:33 -050024 "github.com/opencord/voltha-go/rw_core/route"
npujar1d86a522019-11-14 17:11:16 +053025 "reflect"
26 "sync"
27 "time"
28
khenaidoob9203542018-09-17 22:56:37 -040029 "github.com/gogo/protobuf/proto"
sbarbari17d7e222019-11-05 10:02:29 -050030 "github.com/opencord/voltha-go/db/model"
npujar1d86a522019-11-14 17:11:16 +053031 fd "github.com/opencord/voltha-go/rw_core/flowdecomposition"
Scott Bakerb671a862019-10-24 10:53:40 -070032 coreutils "github.com/opencord/voltha-go/rw_core/utils"
serkant.uluderya2ae470f2020-01-21 11:13:09 -080033 fu "github.com/opencord/voltha-lib-go/v3/pkg/flows"
34 "github.com/opencord/voltha-lib-go/v3/pkg/log"
35 ic "github.com/opencord/voltha-protos/v3/go/inter_container"
36 ofp "github.com/opencord/voltha-protos/v3/go/openflow_13"
37 "github.com/opencord/voltha-protos/v3/go/voltha"
khenaidoob9203542018-09-17 22:56:37 -040038 "google.golang.org/grpc/codes"
39 "google.golang.org/grpc/status"
khenaidoob9203542018-09-17 22:56:37 -040040)
41
npujar1d86a522019-11-14 17:11:16 +053042// LogicalDeviceAgent represent attributes of logical device agent
khenaidoob9203542018-09-17 22:56:37 -040043type LogicalDeviceAgent struct {
npujar1d86a522019-11-14 17:11:16 +053044 logicalDeviceID string
45 rootDeviceID string
khenaidoo3306c992019-05-24 16:57:35 -040046 deviceMgr *DeviceManager
47 ldeviceMgr *LogicalDeviceManager
48 clusterDataProxy *model.Proxy
49 exitChannel chan int
khenaidoo820197c2020-02-13 16:35:33 -050050 deviceRoutes *route.DeviceRoutes
khenaidoo3306c992019-05-24 16:57:35 -040051 flowProxy *model.Proxy
52 groupProxy *model.Proxy
Manikkaraj kb1a10922019-07-29 12:10:34 -040053 meterProxy *model.Proxy
khenaidoo3306c992019-05-24 16:57:35 -040054 ldProxy *model.Proxy
55 portProxies map[string]*model.Proxy
56 portProxiesLock sync.RWMutex
57 lockLogicalDevice sync.RWMutex
khenaidoo820197c2020-02-13 16:35:33 -050058 lockDeviceRoutes sync.RWMutex
khenaidoo3306c992019-05-24 16:57:35 -040059 logicalPortsNo map[uint32]bool //value is true for NNI port
60 lockLogicalPortsNo sync.RWMutex
61 flowDecomposer *fd.FlowDecomposer
62 defaultTimeout int64
khenaidoo6e55d9e2019-12-12 18:26:26 -050063 logicalDevice *voltha.LogicalDevice
khenaidoob9203542018-09-17 22:56:37 -040064}
65
npujar1d86a522019-11-14 17:11:16 +053066func newLogicalDeviceAgent(id string, deviceID string, ldeviceMgr *LogicalDeviceManager,
Stephane Barbarie1ab43272018-12-08 21:42:13 -050067 deviceMgr *DeviceManager,
khenaidoo2c6a0992019-04-29 13:46:56 -040068 cdProxy *model.Proxy, timeout int64) *LogicalDeviceAgent {
khenaidoob9203542018-09-17 22:56:37 -040069 var agent LogicalDeviceAgent
70 agent.exitChannel = make(chan int, 1)
npujar1d86a522019-11-14 17:11:16 +053071 agent.logicalDeviceID = id
72 agent.rootDeviceID = deviceID
khenaidoob9203542018-09-17 22:56:37 -040073 agent.deviceMgr = deviceMgr
khenaidoo9a468962018-09-19 15:33:13 -040074 agent.clusterDataProxy = cdProxy
khenaidoob9203542018-09-17 22:56:37 -040075 agent.ldeviceMgr = ldeviceMgr
khenaidoo19d7b632018-10-30 10:49:50 -040076 agent.flowDecomposer = fd.NewFlowDecomposer(agent.deviceMgr)
khenaidoo92e62c52018-10-03 14:02:54 -040077 agent.lockLogicalDevice = sync.RWMutex{}
khenaidoofc1314d2019-03-14 09:34:21 -040078 agent.portProxies = make(map[string]*model.Proxy)
79 agent.portProxiesLock = sync.RWMutex{}
khenaidoo2c6a0992019-04-29 13:46:56 -040080 agent.lockLogicalPortsNo = sync.RWMutex{}
khenaidoo820197c2020-02-13 16:35:33 -050081 agent.lockDeviceRoutes = sync.RWMutex{}
khenaidoo2c6a0992019-04-29 13:46:56 -040082 agent.logicalPortsNo = make(map[uint32]bool)
khenaidoo2c6a0992019-04-29 13:46:56 -040083 agent.defaultTimeout = timeout
khenaidoob9203542018-09-17 22:56:37 -040084 return &agent
85}
86
khenaidoo4d4802d2018-10-04 21:59:49 -040087// start creates the logical device and add it to the data model
khenaidoo297cd252019-02-07 22:10:23 -050088func (agent *LogicalDeviceAgent) start(ctx context.Context, loadFromdB bool) error {
npujar1d86a522019-11-14 17:11:16 +053089 log.Infow("starting-logical_device-agent", log.Fields{"logicaldeviceId": agent.logicalDeviceID, "loadFromdB": loadFromdB})
khenaidoo297cd252019-02-07 22:10:23 -050090 var ld *voltha.LogicalDevice
Thomas Lee Se5a44012019-11-07 20:32:24 +053091 var err error
khenaidoo297cd252019-02-07 22:10:23 -050092 if !loadFromdB {
khenaidoo7e3d8f12019-08-02 16:06:30 -040093 //Build the logical device based on information retrieved from the device adapter
94 var switchCap *ic.SwitchCapability
khenaidoo297cd252019-02-07 22:10:23 -050095 var err error
npujar1d86a522019-11-14 17:11:16 +053096 if switchCap, err = agent.deviceMgr.getSwitchCapability(ctx, agent.rootDeviceID); err != nil {
khenaidoo7e3d8f12019-08-02 16:06:30 -040097 log.Errorw("error-creating-logical-device", log.Fields{"error": err})
98 return err
99 }
npujar1d86a522019-11-14 17:11:16 +0530100 ld = &voltha.LogicalDevice{Id: agent.logicalDeviceID, RootDeviceId: agent.rootDeviceID}
khenaidoo297cd252019-02-07 22:10:23 -0500101
102 // Create the datapath ID (uint64) using the logical device ID (based on the MAC Address)
103 var datapathID uint64
npujar1d86a522019-11-14 17:11:16 +0530104 if datapathID, err = CreateDataPathID(agent.logicalDeviceID); err != nil {
khenaidoo297cd252019-02-07 22:10:23 -0500105 log.Errorw("error-creating-datapath-id", log.Fields{"error": err})
106 return err
107 }
108 ld.DatapathId = datapathID
khenaidoo7e3d8f12019-08-02 16:06:30 -0400109 ld.Desc = (proto.Clone(switchCap.Desc)).(*ofp.OfpDesc)
110 log.Debugw("Switch-capability", log.Fields{"Desc": ld.Desc, "fromAd": switchCap.Desc})
111 ld.SwitchFeatures = (proto.Clone(switchCap.SwitchFeatures)).(*ofp.OfpSwitchFeatures)
khenaidoo297cd252019-02-07 22:10:23 -0500112 ld.Flows = &ofp.Flows{Items: nil}
113 ld.FlowGroups = &ofp.FlowGroups{Items: nil}
khenaidoo49085352020-01-13 19:15:43 -0500114 ld.Ports = []*voltha.LogicalPort{}
khenaidoo297cd252019-02-07 22:10:23 -0500115
khenaidoo297cd252019-02-07 22:10:23 -0500116 agent.lockLogicalDevice.Lock()
khenaidoo297cd252019-02-07 22:10:23 -0500117 // Save the logical device
Thomas Lee Se5a44012019-11-07 20:32:24 +0530118 added, err := agent.clusterDataProxy.AddWithID(ctx, "/logical_devices", ld.Id, ld, "")
119 if err != nil {
120 log.Errorw("failed-to-save-logical-devices-to-cluster-proxy", log.Fields{"error": err})
121 agent.lockLogicalDevice.Unlock()
122 return err
123 }
124 if added == nil {
npujar1d86a522019-11-14 17:11:16 +0530125 log.Errorw("failed-to-add-logical-device", log.Fields{"logicaldeviceId": agent.logicalDeviceID})
khenaidoo297cd252019-02-07 22:10:23 -0500126 } else {
npujar1d86a522019-11-14 17:11:16 +0530127 log.Debugw("logicaldevice-created", log.Fields{"logicaldeviceId": agent.logicalDeviceID})
khenaidoo297cd252019-02-07 22:10:23 -0500128 }
khenaidoo6e55d9e2019-12-12 18:26:26 -0500129
130 agent.logicalDevice = proto.Clone(ld).(*voltha.LogicalDevice)
khenaidoo297cd252019-02-07 22:10:23 -0500131 agent.lockLogicalDevice.Unlock()
khenaidoofc1314d2019-03-14 09:34:21 -0400132
khenaidoo3d3b8c22019-05-22 18:10:39 -0400133 // TODO: Set the logical ports in a separate call once the port update issue is fixed.
npujar1d86a522019-11-14 17:11:16 +0530134 go func() {
135 err := agent.setupLogicalPorts(ctx)
136 if err != nil {
137 log.Errorw("unable-to-setup-logical-ports", log.Fields{"error": err})
138 }
139 }()
khenaidoo3d3b8c22019-05-22 18:10:39 -0400140
khenaidoo297cd252019-02-07 22:10:23 -0500141 } else {
142 // load from dB - the logical may not exist at this time. On error, just return and the calling function
143 // will destroy this agent.
khenaidoo6e55d9e2019-12-12 18:26:26 -0500144 agent.lockLogicalDevice.Lock()
npujar467fe752020-01-16 20:17:45 +0530145 logicalDevice, err := agent.clusterDataProxy.Get(ctx, "/logical_devices/"+agent.logicalDeviceID, 0, true, "")
Thomas Lee Se5a44012019-11-07 20:32:24 +0530146 if err != nil {
147 return status.Errorf(codes.NotFound, "logical_device-%s", agent.logicalDeviceID)
148 }
khenaidoo6e55d9e2019-12-12 18:26:26 -0500149 ld, ok := logicalDevice.(*voltha.LogicalDevice)
150 if !ok {
151 agent.lockLogicalDevice.Unlock()
152 return status.Errorf(codes.NotFound, "logical_device-%s", agent.logicalDeviceID)
khenaidoo297cd252019-02-07 22:10:23 -0500153 }
khenaidoo8c3303d2019-02-13 14:59:39 -0500154 // Update the root device Id
npujar1d86a522019-11-14 17:11:16 +0530155 agent.rootDeviceID = ld.RootDeviceId
khenaidoo3d3b8c22019-05-22 18:10:39 -0400156
khenaidoo6e55d9e2019-12-12 18:26:26 -0500157 // Update the last data
158 agent.logicalDevice = proto.Clone(ld).(*voltha.LogicalDevice)
159
160 agent.lockLogicalDevice.Unlock()
161
khenaidoo3d3b8c22019-05-22 18:10:39 -0400162 // Setup the local list of logical ports
163 agent.addLogicalPortsToMap(ld.Ports)
khenaidoob9203542018-09-17 22:56:37 -0400164 }
khenaidoo92e62c52018-10-03 14:02:54 -0400165 agent.lockLogicalDevice.Lock()
khenaidoo3d3b8c22019-05-22 18:10:39 -0400166 defer agent.lockLogicalDevice.Unlock()
khenaidoofc1314d2019-03-14 09:34:21 -0400167
Thomas Lee Se5a44012019-11-07 20:32:24 +0530168 agent.flowProxy, err = agent.clusterDataProxy.CreateProxy(
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400169 ctx,
npujar1d86a522019-11-14 17:11:16 +0530170 fmt.Sprintf("/logical_devices/%s/flows", agent.logicalDeviceID),
khenaidoo19d7b632018-10-30 10:49:50 -0400171 false)
Thomas Lee Se5a44012019-11-07 20:32:24 +0530172 if err != nil {
173 log.Errorw("failed-to-create-flow-proxy", log.Fields{"error": err})
174 return err
175 }
176 agent.meterProxy, err = agent.clusterDataProxy.CreateProxy(
Manikkaraj kb1a10922019-07-29 12:10:34 -0400177 ctx,
npujar1d86a522019-11-14 17:11:16 +0530178 fmt.Sprintf("/logical_devices/%s/meters", agent.logicalDeviceID),
Manikkaraj kb1a10922019-07-29 12:10:34 -0400179 false)
Thomas Lee Se5a44012019-11-07 20:32:24 +0530180 if err != nil {
181 log.Errorw("failed-to-create-meter-proxy", log.Fields{"error": err})
182 return err
183 }
184 agent.groupProxy, err = agent.clusterDataProxy.CreateProxy(
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400185 ctx,
npujar1d86a522019-11-14 17:11:16 +0530186 fmt.Sprintf("/logical_devices/%s/flow_groups", agent.logicalDeviceID),
khenaidoo19d7b632018-10-30 10:49:50 -0400187 false)
Thomas Lee Se5a44012019-11-07 20:32:24 +0530188 if err != nil {
189 log.Errorw("failed-to-create-group-proxy", log.Fields{"error": err})
190 return err
191 }
192 agent.ldProxy, err = agent.clusterDataProxy.CreateProxy(
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400193 ctx,
npujar1d86a522019-11-14 17:11:16 +0530194 fmt.Sprintf("/logical_devices/%s", agent.logicalDeviceID),
khenaidoofc1314d2019-03-14 09:34:21 -0400195 false)
Thomas Lee Se5a44012019-11-07 20:32:24 +0530196 if err != nil {
197 log.Errorw("failed-to-create-logical-device-proxy", log.Fields{"error": err})
198 return err
199 }
khenaidoofc1314d2019-03-14 09:34:21 -0400200 // TODO: Use a port proxy once the POST_ADD is fixed
khenaidoo3d3b8c22019-05-22 18:10:39 -0400201 if agent.ldProxy != nil {
npujar9a30c702019-11-14 17:06:39 +0530202 agent.ldProxy.RegisterCallback(model.PostUpdate, agent.portUpdated)
khenaidoo3d3b8c22019-05-22 18:10:39 -0400203 } else {
npujar1d86a522019-11-14 17:11:16 +0530204 log.Errorw("logical-device-proxy-null", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo3d3b8c22019-05-22 18:10:39 -0400205 return status.Error(codes.Internal, "logical-device-proxy-null")
206 }
khenaidoobcf205b2019-01-25 22:21:14 -0500207
khenaidoo820197c2020-02-13 16:35:33 -0500208 // Setup the device routes. Building routes may fail if the pre-conditions are not satisfied (e.g. no PON ports present)
khenaidoo4c9e5592019-09-09 16:20:41 -0400209 if loadFromdB {
khenaidoo820197c2020-02-13 16:35:33 -0500210 go func() {
211 if err := agent.buildRoutes(context.Background()); err != nil {
khenaidoo80b987d2020-02-20 10:52:52 -0500212 log.Warnw("routes-not-ready", log.Fields{"logical-device-id": agent.logicalDeviceID, "error": err})
khenaidoo820197c2020-02-13 16:35:33 -0500213 }
214 }()
khenaidoo4c9e5592019-09-09 16:20:41 -0400215 }
khenaidoob9203542018-09-17 22:56:37 -0400216 return nil
217}
218
khenaidoo4d4802d2018-10-04 21:59:49 -0400219// stop stops the logical devuce agent. This removes the logical device from the data model.
Thomas Lee Se5a44012019-11-07 20:32:24 +0530220func (agent *LogicalDeviceAgent) stop(ctx context.Context) error {
khenaidoo4d4802d2018-10-04 21:59:49 -0400221 log.Info("stopping-logical_device-agent")
222 agent.lockLogicalDevice.Lock()
223 defer agent.lockLogicalDevice.Unlock()
khenaidoo8c3303d2019-02-13 14:59:39 -0500224
khenaidoo4d4802d2018-10-04 21:59:49 -0400225 //Remove the logical device from the model
Thomas Lee Se5a44012019-11-07 20:32:24 +0530226 if removed, err := agent.clusterDataProxy.Remove(ctx, "/logical_devices/"+agent.logicalDeviceID, ""); err != nil {
227 log.Errorw("failed-to-remove-device", log.Fields{"error": err})
228 return err
229 } else if removed == nil {
npujar1d86a522019-11-14 17:11:16 +0530230 log.Errorw("failed-to-remove-logical-device", log.Fields{"logicaldeviceId": agent.logicalDeviceID})
khenaidoo4d4802d2018-10-04 21:59:49 -0400231 } else {
npujar1d86a522019-11-14 17:11:16 +0530232 log.Debugw("logicaldevice-removed", log.Fields{"logicaldeviceId": agent.logicalDeviceID})
khenaidoo4d4802d2018-10-04 21:59:49 -0400233 }
234 agent.exitChannel <- 1
235 log.Info("logical_device-agent-stopped")
Thomas Lee Se5a44012019-11-07 20:32:24 +0530236 return nil
khenaidoo4d4802d2018-10-04 21:59:49 -0400237}
238
khenaidoo6e55d9e2019-12-12 18:26:26 -0500239// GetLogicalDevice returns the latest logical device data
240func (agent *LogicalDeviceAgent) GetLogicalDevice() *voltha.LogicalDevice {
khenaidoo1ce37ad2019-03-24 22:07:24 -0400241 agent.lockLogicalDevice.RLock()
242 defer agent.lockLogicalDevice.RUnlock()
khenaidoo6e55d9e2019-12-12 18:26:26 -0500243
244 return proto.Clone(agent.logicalDevice).(*voltha.LogicalDevice)
khenaidoo92e62c52018-10-03 14:02:54 -0400245}
246
npujar1d86a522019-11-14 17:11:16 +0530247// ListLogicalDeviceFlows returns logical device flows
khenaidoo6e55d9e2019-12-12 18:26:26 -0500248func (agent *LogicalDeviceAgent) ListLogicalDeviceFlows() *ofp.Flows {
khenaidoodd237172019-05-27 16:37:17 -0400249 log.Debug("ListLogicalDeviceFlows")
khenaidoo6e55d9e2019-12-12 18:26:26 -0500250
251 logicalDevice := agent.GetLogicalDevice()
252 if logicalDevice.Flows == nil {
253 return &ofp.Flows{}
khenaidoodd237172019-05-27 16:37:17 -0400254 }
khenaidoo6e55d9e2019-12-12 18:26:26 -0500255 return (proto.Clone(logicalDevice.Flows)).(*ofp.Flows)
khenaidoodd237172019-05-27 16:37:17 -0400256}
257
npujar1d86a522019-11-14 17:11:16 +0530258// ListLogicalDeviceMeters returns logical device meters
khenaidoo6e55d9e2019-12-12 18:26:26 -0500259func (agent *LogicalDeviceAgent) ListLogicalDeviceMeters() *ofp.Meters {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400260 log.Debug("ListLogicalDeviceMeters")
khenaidoo6e55d9e2019-12-12 18:26:26 -0500261
262 logicalDevice := agent.GetLogicalDevice()
263 if logicalDevice.Meters == nil {
264 return &ofp.Meters{}
Manikkaraj kb1a10922019-07-29 12:10:34 -0400265 }
khenaidoo6e55d9e2019-12-12 18:26:26 -0500266 return (proto.Clone(logicalDevice.Meters)).(*ofp.Meters)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400267}
268
npujar1d86a522019-11-14 17:11:16 +0530269// ListLogicalDeviceFlowGroups returns logical device flow groups
khenaidoo6e55d9e2019-12-12 18:26:26 -0500270func (agent *LogicalDeviceAgent) ListLogicalDeviceFlowGroups() *ofp.FlowGroups {
khenaidoodd237172019-05-27 16:37:17 -0400271 log.Debug("ListLogicalDeviceFlowGroups")
khenaidoo6e55d9e2019-12-12 18:26:26 -0500272
273 logicalDevice := agent.GetLogicalDevice()
274 if logicalDevice.FlowGroups == nil {
275 return &ofp.FlowGroups{}
khenaidoodd237172019-05-27 16:37:17 -0400276 }
khenaidoo6e55d9e2019-12-12 18:26:26 -0500277 return (proto.Clone(logicalDevice.FlowGroups)).(*ofp.FlowGroups)
khenaidoodd237172019-05-27 16:37:17 -0400278}
279
npujar1d86a522019-11-14 17:11:16 +0530280// ListLogicalDevicePorts returns logical device ports
khenaidoo6e55d9e2019-12-12 18:26:26 -0500281func (agent *LogicalDeviceAgent) ListLogicalDevicePorts() *voltha.LogicalPorts {
khenaidoo1ce37ad2019-03-24 22:07:24 -0400282 log.Debug("ListLogicalDevicePorts")
khenaidoo6e55d9e2019-12-12 18:26:26 -0500283 logicalDevice := agent.GetLogicalDevice()
284 lPorts := make([]*voltha.LogicalPort, 0)
285 lPorts = append(lPorts, logicalDevice.Ports...)
286 return &voltha.LogicalPorts{Items: lPorts}
khenaidoo19d7b632018-10-30 10:49:50 -0400287}
288
khenaidoo4c9e5592019-09-09 16:20:41 -0400289//updateLogicalDeviceFlowsWithoutLock updates the logical device with the latest flows in the model.
npujar467fe752020-01-16 20:17:45 +0530290func (agent *LogicalDeviceAgent) updateLogicalDeviceFlowsWithoutLock(ctx context.Context, flows *ofp.Flows) error {
khenaidoo6e55d9e2019-12-12 18:26:26 -0500291 ld := agent.getLogicalDeviceWithoutLock()
khenaidoo4c9e5592019-09-09 16:20:41 -0400292
khenaidoo6e55d9e2019-12-12 18:26:26 -0500293 log.Debugw("logical-device-before", log.Fields{"lports": len(ld.Ports)})
294 ld.Flows = flows
295
npujar467fe752020-01-16 20:17:45 +0530296 if err := agent.updateLogicalDeviceWithoutLock(ctx, ld); err != nil {
khenaidoo4c9e5592019-09-09 16:20:41 -0400297 log.Errorw("error-updating-logical-device-with-flows", log.Fields{"error": err})
298 return err
khenaidoo43c82122018-11-22 18:38:28 -0500299 }
khenaidoo43c82122018-11-22 18:38:28 -0500300 return nil
301}
302
khenaidoo4c9e5592019-09-09 16:20:41 -0400303//updateLogicalDeviceMetersWithoutLock updates the logical device with the meters info
npujar467fe752020-01-16 20:17:45 +0530304func (agent *LogicalDeviceAgent) updateLogicalDeviceMetersWithoutLock(ctx context.Context, meters *ofp.Meters) error {
khenaidoo6e55d9e2019-12-12 18:26:26 -0500305 ld := agent.getLogicalDeviceWithoutLock()
khenaidoo4c9e5592019-09-09 16:20:41 -0400306
khenaidoo6e55d9e2019-12-12 18:26:26 -0500307 log.Debugw("logical-device-before", log.Fields{"lports": len(ld.Ports)})
308 ld.Meters = meters
309
npujar467fe752020-01-16 20:17:45 +0530310 if err := agent.updateLogicalDeviceWithoutLock(ctx, ld); err != nil {
khenaidoo4c9e5592019-09-09 16:20:41 -0400311 log.Errorw("error-updating-logical-device-with-meters", log.Fields{"error": err})
312 return err
Manikkaraj kb1a10922019-07-29 12:10:34 -0400313 }
314 return nil
315}
316
khenaidoo4c9e5592019-09-09 16:20:41 -0400317//updateLogicalDeviceFlowGroupsWithoutLock updates the logical device with the flow groups
npujar467fe752020-01-16 20:17:45 +0530318func (agent *LogicalDeviceAgent) updateLogicalDeviceFlowGroupsWithoutLock(ctx context.Context, flowGroups *ofp.FlowGroups) error {
khenaidoo6e55d9e2019-12-12 18:26:26 -0500319 ld := agent.getLogicalDeviceWithoutLock()
khenaidoo4c9e5592019-09-09 16:20:41 -0400320
khenaidoo6e55d9e2019-12-12 18:26:26 -0500321 log.Debugw("logical-device-before", log.Fields{"lports": len(ld.Ports)})
322 ld.FlowGroups = flowGroups
323
npujar467fe752020-01-16 20:17:45 +0530324 if err := agent.updateLogicalDeviceWithoutLock(ctx, ld); err != nil {
khenaidoo4c9e5592019-09-09 16:20:41 -0400325 log.Errorw("error-updating-logical-device-with-flowgroups", log.Fields{"error": err})
326 return err
khenaidoo43c82122018-11-22 18:38:28 -0500327 }
khenaidoo43c82122018-11-22 18:38:28 -0500328 return nil
329}
330
khenaidoo6e55d9e2019-12-12 18:26:26 -0500331// getLogicalDeviceWithoutLock returns a cloned logical device to a function that already holds the agent lock.
332func (agent *LogicalDeviceAgent) getLogicalDeviceWithoutLock() *voltha.LogicalDevice {
khenaidoo92e62c52018-10-03 14:02:54 -0400333 log.Debug("getLogicalDeviceWithoutLock")
khenaidoo6e55d9e2019-12-12 18:26:26 -0500334 return proto.Clone(agent.logicalDevice).(*voltha.LogicalDevice)
khenaidoo92e62c52018-10-03 14:02:54 -0400335}
336
npujar467fe752020-01-16 20:17:45 +0530337func (agent *LogicalDeviceAgent) updateLogicalPort(ctx context.Context, device *voltha.Device, port *voltha.Port) error {
khenaidoo2c6a0992019-04-29 13:46:56 -0400338 log.Debugw("updateLogicalPort", log.Fields{"deviceId": device.Id, "port": port})
339 var err error
340 if port.Type == voltha.Port_ETHERNET_NNI {
npujar467fe752020-01-16 20:17:45 +0530341 if _, err = agent.addNNILogicalPort(ctx, device, port); err != nil {
khenaidoo2c6a0992019-04-29 13:46:56 -0400342 return err
343 }
344 agent.addLogicalPortToMap(port.PortNo, true)
345 } else if port.Type == voltha.Port_ETHERNET_UNI {
npujar467fe752020-01-16 20:17:45 +0530346 if _, err = agent.addUNILogicalPort(ctx, device, port); err != nil {
khenaidoo2c6a0992019-04-29 13:46:56 -0400347 return err
348 }
349 agent.addLogicalPortToMap(port.PortNo, false)
350 } else {
khenaidoo820197c2020-02-13 16:35:33 -0500351 // Update the device routes to ensure all routes on the logical device have been calculated
352 if err = agent.buildRoutes(ctx); err != nil {
353 // Not an error - temporary state
354 log.Warnw("failed-to-update-routes", log.Fields{"device-id": device.Id, "port": port, "error": err})
khenaidoo2c6a0992019-04-29 13:46:56 -0400355 }
356 }
357 return nil
358}
359
khenaidoo3d3b8c22019-05-22 18:10:39 -0400360// setupLogicalPorts is invoked once the logical device has been created and is ready to get ports
361// added to it. While the logical device was being created we could have received requests to add
362// NNI and UNI ports which were discarded. Now is the time to add them if needed
363func (agent *LogicalDeviceAgent) setupLogicalPorts(ctx context.Context) error {
npujar1d86a522019-11-14 17:11:16 +0530364 log.Infow("setupLogicalPorts", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo3d3b8c22019-05-22 18:10:39 -0400365 // First add any NNI ports which could have been missing
npujar467fe752020-01-16 20:17:45 +0530366 if err := agent.setupNNILogicalPorts(ctx, agent.rootDeviceID); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530367 log.Errorw("error-setting-up-NNI-ports", log.Fields{"error": err, "deviceId": agent.rootDeviceID})
khenaidoo3d3b8c22019-05-22 18:10:39 -0400368 return err
369 }
370
371 // Now, set up the UNI ports if needed.
npujar467fe752020-01-16 20:17:45 +0530372 children, err := agent.deviceMgr.getAllChildDevices(ctx, agent.rootDeviceID)
npujar1d86a522019-11-14 17:11:16 +0530373 if err != nil {
374 log.Errorw("error-getting-child-devices", log.Fields{"error": err, "deviceId": agent.rootDeviceID})
khenaidoo3d3b8c22019-05-22 18:10:39 -0400375 return err
npujar1d86a522019-11-14 17:11:16 +0530376 }
377 responses := make([]coreutils.Response, 0)
378 for _, child := range children.Items {
379 response := coreutils.NewResponse()
380 responses = append(responses, response)
381 go func(child *voltha.Device) {
npujar467fe752020-01-16 20:17:45 +0530382 if err = agent.setupUNILogicalPorts(ctx, child); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530383 log.Error("setting-up-UNI-ports-failed", log.Fields{"deviceID": child.Id})
384 response.Error(status.Errorf(codes.Internal, "UNI-ports-setup-failed: %s", child.Id))
385 }
386 response.Done()
387 }(child)
388 }
389 // Wait for completion
390 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, responses...); res != nil {
391 return status.Errorf(codes.Aborted, "errors-%s", res)
khenaidoo3d3b8c22019-05-22 18:10:39 -0400392 }
393 return nil
394}
395
khenaidoofc1314d2019-03-14 09:34:21 -0400396// setupNNILogicalPorts creates an NNI port on the logical device that represents an NNI interface on a root device
npujar1d86a522019-11-14 17:11:16 +0530397func (agent *LogicalDeviceAgent) setupNNILogicalPorts(ctx context.Context, deviceID string) error {
398 log.Infow("setupNNILogicalPorts-start", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoob9203542018-09-17 22:56:37 -0400399 // Build the logical device based on information retrieved from the device adapter
khenaidoofc1314d2019-03-14 09:34:21 -0400400 var err error
401
402 var device *voltha.Device
npujar467fe752020-01-16 20:17:45 +0530403 if device, err = agent.deviceMgr.GetDevice(ctx, deviceID); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530404 log.Errorw("error-retrieving-device", log.Fields{"error": err, "deviceId": deviceID})
khenaidoofc1314d2019-03-14 09:34:21 -0400405 return err
406 }
407
408 //Get UNI port number
khenaidoofc1314d2019-03-14 09:34:21 -0400409 for _, port := range device.Ports {
410 if port.Type == voltha.Port_ETHERNET_NNI {
npujar467fe752020-01-16 20:17:45 +0530411 if _, err = agent.addNNILogicalPort(ctx, device, port); err != nil {
khenaidoofc1314d2019-03-14 09:34:21 -0400412 log.Errorw("error-adding-UNI-port", log.Fields{"error": err})
khenaidoofc1314d2019-03-14 09:34:21 -0400413 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400414 agent.addLogicalPortToMap(port.PortNo, true)
khenaidoofc1314d2019-03-14 09:34:21 -0400415 }
416 }
khenaidoofc1314d2019-03-14 09:34:21 -0400417 return err
418}
419
khenaidoo171b98e2019-10-31 11:48:15 -0400420// updatePortState updates the port state of the device
npujar467fe752020-01-16 20:17:45 +0530421func (agent *LogicalDeviceAgent) updatePortState(ctx context.Context, deviceID string, portNo uint32, operStatus voltha.OperStatus_Types) error {
npujar1d86a522019-11-14 17:11:16 +0530422 log.Infow("updatePortState-start", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "portNo": portNo, "state": operStatus})
khenaidoo171b98e2019-10-31 11:48:15 -0400423 agent.lockLogicalDevice.Lock()
424 defer agent.lockLogicalDevice.Unlock()
425 // Get the latest logical device info
khenaidoo6e55d9e2019-12-12 18:26:26 -0500426 cloned := agent.getLogicalDeviceWithoutLock()
427 for idx, lPort := range cloned.Ports {
npujar1d86a522019-11-14 17:11:16 +0530428 if lPort.DeviceId == deviceID && lPort.DevicePortNo == portNo {
npujar1d86a522019-11-14 17:11:16 +0530429 if operStatus == voltha.OperStatus_ACTIVE {
430 cloned.Ports[idx].OfpPort.Config = cloned.Ports[idx].OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
431 cloned.Ports[idx].OfpPort.State = uint32(ofp.OfpPortState_OFPPS_LIVE)
432 } else {
433 cloned.Ports[idx].OfpPort.Config = cloned.Ports[idx].OfpPort.Config | uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
434 cloned.Ports[idx].OfpPort.State = uint32(ofp.OfpPortState_OFPPS_LINK_DOWN)
435 }
436 // Update the logical device
npujar467fe752020-01-16 20:17:45 +0530437 if err := agent.updateLogicalDeviceWithoutLock(ctx, cloned); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530438 log.Errorw("error-updating-logical-device", log.Fields{"error": err})
439 return err
440 }
441 return nil
442 }
443 }
444 return status.Errorf(codes.NotFound, "port-%d-not-exist", portNo)
khenaidoo171b98e2019-10-31 11:48:15 -0400445}
446
khenaidoo3ab34882019-05-02 21:33:30 -0400447// updatePortsState updates the ports state related to the device
kesavandbc2d1622020-01-21 00:42:01 -0500448func (agent *LogicalDeviceAgent) updatePortsState(ctx context.Context, device *voltha.Device, state voltha.OperStatus_Types) error {
npujar1d86a522019-11-14 17:11:16 +0530449 log.Infow("updatePortsState-start", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo3ab34882019-05-02 21:33:30 -0400450 agent.lockLogicalDevice.Lock()
451 defer agent.lockLogicalDevice.Unlock()
452 // Get the latest logical device info
khenaidoo6e55d9e2019-12-12 18:26:26 -0500453 cloned := agent.getLogicalDeviceWithoutLock()
npujar1d86a522019-11-14 17:11:16 +0530454 for _, lport := range cloned.Ports {
455 if lport.DeviceId == device.Id {
kesavandbc2d1622020-01-21 00:42:01 -0500456 if state == voltha.OperStatus_ACTIVE {
npujar1d86a522019-11-14 17:11:16 +0530457 lport.OfpPort.Config = lport.OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
458 lport.OfpPort.State = uint32(ofp.OfpPortState_OFPPS_LIVE)
kesavandbc2d1622020-01-21 00:42:01 -0500459 } else {
npujar1d86a522019-11-14 17:11:16 +0530460 lport.OfpPort.Config = lport.OfpPort.Config | uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
461 lport.OfpPort.State = uint32(ofp.OfpPortState_OFPPS_LINK_DOWN)
khenaidoo3ab34882019-05-02 21:33:30 -0400462 }
kesavandbc2d1622020-01-21 00:42:01 -0500463
khenaidoo3ab34882019-05-02 21:33:30 -0400464 }
npujar1d86a522019-11-14 17:11:16 +0530465 }
466 // Updating the logical device will trigger the poprt change events to be populated to the controller
npujar467fe752020-01-16 20:17:45 +0530467 if err := agent.updateLogicalDeviceWithoutLock(ctx, cloned); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530468 log.Warnw("logical-device-update-failed", log.Fields{"ldeviceId": agent.logicalDeviceID, "error": err})
469 return err
khenaidoo3ab34882019-05-02 21:33:30 -0400470 }
471 return nil
472}
473
khenaidoofc1314d2019-03-14 09:34:21 -0400474// setupUNILogicalPorts creates a UNI port on the logical device that represents a child UNI interface
475func (agent *LogicalDeviceAgent) setupUNILogicalPorts(ctx context.Context, childDevice *voltha.Device) error {
npujar1d86a522019-11-14 17:11:16 +0530476 log.Infow("setupUNILogicalPort", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoofc1314d2019-03-14 09:34:21 -0400477 // Build the logical device based on information retrieved from the device adapter
khenaidoob9203542018-09-17 22:56:37 -0400478 var err error
khenaidoo59ef7be2019-06-21 12:40:28 -0400479 var added bool
khenaidoo19d7b632018-10-30 10:49:50 -0400480 //Get UNI port number
khenaidoo19d7b632018-10-30 10:49:50 -0400481 for _, port := range childDevice.Ports {
482 if port.Type == voltha.Port_ETHERNET_UNI {
npujar467fe752020-01-16 20:17:45 +0530483 if added, err = agent.addUNILogicalPort(ctx, childDevice, port); err != nil {
khenaidoofc1314d2019-03-14 09:34:21 -0400484 log.Errorw("error-adding-UNI-port", log.Fields{"error": err})
khenaidoofc1314d2019-03-14 09:34:21 -0400485 }
khenaidoo59ef7be2019-06-21 12:40:28 -0400486 if added {
487 agent.addLogicalPortToMap(port.PortNo, false)
488 }
khenaidoo19d7b632018-10-30 10:49:50 -0400489 }
490 }
khenaidoofc1314d2019-03-14 09:34:21 -0400491 return err
khenaidoo92e62c52018-10-03 14:02:54 -0400492}
493
khenaidoo0a822f92019-05-08 15:15:57 -0400494// deleteAllLogicalPorts deletes all logical ports associated with this device
npujar467fe752020-01-16 20:17:45 +0530495func (agent *LogicalDeviceAgent) deleteAllLogicalPorts(ctx context.Context, device *voltha.Device) error {
npujar1d86a522019-11-14 17:11:16 +0530496 log.Infow("updatePortsState-start", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo0a822f92019-05-08 15:15:57 -0400497 agent.lockLogicalDevice.Lock()
498 defer agent.lockLogicalDevice.Unlock()
499 // Get the latest logical device info
khenaidoo6e55d9e2019-12-12 18:26:26 -0500500 ld := agent.getLogicalDeviceWithoutLock()
501
npujar1d86a522019-11-14 17:11:16 +0530502 cloned := (proto.Clone(ld)).(*voltha.LogicalDevice)
503 updateLogicalPorts := []*voltha.LogicalPort{}
504 for _, lport := range cloned.Ports {
505 if lport.DeviceId != device.Id {
506 updateLogicalPorts = append(updateLogicalPorts, lport)
507 }
508 }
509 if len(updateLogicalPorts) < len(cloned.Ports) {
510 cloned.Ports = updateLogicalPorts
511 // Updating the logical device will trigger the poprt change events to be populated to the controller
npujar467fe752020-01-16 20:17:45 +0530512 if err := agent.updateLogicalDeviceWithoutLock(ctx, cloned); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530513 log.Warnw("logical-device-update-failed", log.Fields{"ldeviceId": agent.logicalDeviceID, "error": err})
514 return err
515 }
khenaidoo0a822f92019-05-08 15:15:57 -0400516 } else {
npujar1d86a522019-11-14 17:11:16 +0530517 log.Debugw("no-change-required", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo0a822f92019-05-08 15:15:57 -0400518 }
519 return nil
520}
521
Hardik Windlassc704def2020-02-26 18:23:19 +0000522// deleteAllUNILogicalPorts deletes all UNI logical ports associated with this parent device
523func (agent *LogicalDeviceAgent) deleteAllUNILogicalPorts(ctx context.Context, parentDevice *voltha.Device) error {
524 log.Debugw("delete-all-uni-logical-ports", log.Fields{"logical-device-id": agent.logicalDeviceID})
525 agent.lockLogicalDevice.Lock()
526 defer agent.lockLogicalDevice.Unlock()
527 // Get the latest logical device info
528 ld := agent.getLogicalDeviceWithoutLock()
529
530 cloned := (proto.Clone(ld)).(*voltha.LogicalDevice)
531 updateLogicalPorts := []*voltha.LogicalPort{}
532 for _, lport := range cloned.Ports {
533 // Save NNI ports only
534 if agent.isNNIPort(lport.DevicePortNo) {
535 updateLogicalPorts = append(updateLogicalPorts, lport)
536 }
537 }
538 if len(updateLogicalPorts) < len(cloned.Ports) {
539 cloned.Ports = updateLogicalPorts
540 // Updating the logical device will trigger the port change events to be populated to the controller
541 if err := agent.updateLogicalDeviceWithoutLock(ctx, cloned); err != nil {
542 return err
543 }
544 } else {
545 log.Debugw("no-change-required", log.Fields{"logical-device-id": agent.logicalDeviceID})
546 }
547 return nil
548}
549
khenaidoo92e62c52018-10-03 14:02:54 -0400550//updateLogicalDeviceWithoutLock updates the model with the logical device. It clones the logicaldevice before saving it
npujar467fe752020-01-16 20:17:45 +0530551func (agent *LogicalDeviceAgent) updateLogicalDeviceWithoutLock(ctx context.Context, logicalDevice *voltha.LogicalDevice) error {
552 updateCtx := context.WithValue(ctx, model.RequestTimestamp, time.Now().UnixNano())
Thomas Lee Se5a44012019-11-07 20:32:24 +0530553 afterUpdate, err := agent.clusterDataProxy.Update(updateCtx, "/logical_devices/"+agent.logicalDeviceID, logicalDevice, false, "")
554 if err != nil {
555 log.Errorw("failed-to-update-logical-devices-to-cluster-proxy", log.Fields{"error": err})
556 return err
557 }
khenaidoo92e62c52018-10-03 14:02:54 -0400558 if afterUpdate == nil {
npujar1d86a522019-11-14 17:11:16 +0530559 return status.Errorf(codes.Internal, "failed-updating-logical-device:%s", agent.logicalDeviceID)
khenaidoo92e62c52018-10-03 14:02:54 -0400560 }
khenaidoo6e55d9e2019-12-12 18:26:26 -0500561 agent.logicalDevice = (proto.Clone(logicalDevice)).(*voltha.LogicalDevice)
khenaidoo92e62c52018-10-03 14:02:54 -0400562 return nil
563}
564
khenaidoo820197c2020-02-13 16:35:33 -0500565//generateDeviceRoutesIfNeeded generates the device routes if the logical device has been updated since the last time
khenaidoo4c9e5592019-09-09 16:20:41 -0400566//that device graph was generated.
khenaidoo820197c2020-02-13 16:35:33 -0500567func (agent *LogicalDeviceAgent) generateDeviceRoutesIfNeeded(ctx context.Context) error {
568 agent.lockDeviceRoutes.Lock()
569 defer agent.lockDeviceRoutes.Unlock()
570
khenaidoo6e55d9e2019-12-12 18:26:26 -0500571 ld := agent.GetLogicalDevice()
khenaidoo820197c2020-02-13 16:35:33 -0500572
573 if agent.deviceRoutes != nil && agent.deviceRoutes.IsUpToDate(ld) {
npujar1d86a522019-11-14 17:11:16 +0530574 return nil
575 }
576 log.Debug("Generation of device graph required")
khenaidoo820197c2020-02-13 16:35:33 -0500577 if err := agent.buildRoutes(ctx); err != nil {
578 return err
579 }
khenaidoo4c9e5592019-09-09 16:20:41 -0400580 return nil
581}
582
khenaidoo19d7b632018-10-30 10:49:50 -0400583//updateFlowTable updates the flow table of that logical device
584func (agent *LogicalDeviceAgent) updateFlowTable(ctx context.Context, flow *ofp.OfpFlowMod) error {
585 log.Debug("updateFlowTable")
586 if flow == nil {
587 return nil
588 }
khenaidoo820197c2020-02-13 16:35:33 -0500589 if err := agent.generateDeviceRoutesIfNeeded(ctx); err != nil {
khenaidoo4c9e5592019-09-09 16:20:41 -0400590 return err
591 }
khenaidoo19d7b632018-10-30 10:49:50 -0400592 switch flow.GetCommand() {
593 case ofp.OfpFlowModCommand_OFPFC_ADD:
npujar467fe752020-01-16 20:17:45 +0530594 return agent.flowAdd(ctx, flow)
khenaidoo19d7b632018-10-30 10:49:50 -0400595 case ofp.OfpFlowModCommand_OFPFC_DELETE:
npujar467fe752020-01-16 20:17:45 +0530596 return agent.flowDelete(ctx, flow)
khenaidoo19d7b632018-10-30 10:49:50 -0400597 case ofp.OfpFlowModCommand_OFPFC_DELETE_STRICT:
npujar467fe752020-01-16 20:17:45 +0530598 return agent.flowDeleteStrict(ctx, flow)
khenaidoo19d7b632018-10-30 10:49:50 -0400599 case ofp.OfpFlowModCommand_OFPFC_MODIFY:
600 return agent.flowModify(flow)
601 case ofp.OfpFlowModCommand_OFPFC_MODIFY_STRICT:
602 return agent.flowModifyStrict(flow)
603 }
604 return status.Errorf(codes.Internal,
npujar1d86a522019-11-14 17:11:16 +0530605 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceID, flow.GetCommand())
khenaidoo19d7b632018-10-30 10:49:50 -0400606}
607
608//updateGroupTable updates the group table of that logical device
609func (agent *LogicalDeviceAgent) updateGroupTable(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
610 log.Debug("updateGroupTable")
611 if groupMod == nil {
612 return nil
613 }
khenaidoo820197c2020-02-13 16:35:33 -0500614 if err := agent.generateDeviceRoutesIfNeeded(ctx); err != nil {
khenaidoo4c9e5592019-09-09 16:20:41 -0400615 return err
616 }
khenaidoo820197c2020-02-13 16:35:33 -0500617
khenaidoo19d7b632018-10-30 10:49:50 -0400618 switch groupMod.GetCommand() {
619 case ofp.OfpGroupModCommand_OFPGC_ADD:
npujar467fe752020-01-16 20:17:45 +0530620 return agent.groupAdd(ctx, groupMod)
khenaidoo19d7b632018-10-30 10:49:50 -0400621 case ofp.OfpGroupModCommand_OFPGC_DELETE:
npujar467fe752020-01-16 20:17:45 +0530622 return agent.groupDelete(ctx, groupMod)
khenaidoo19d7b632018-10-30 10:49:50 -0400623 case ofp.OfpGroupModCommand_OFPGC_MODIFY:
npujar467fe752020-01-16 20:17:45 +0530624 return agent.groupModify(ctx, groupMod)
khenaidoo19d7b632018-10-30 10:49:50 -0400625 }
626 return status.Errorf(codes.Internal,
npujar1d86a522019-11-14 17:11:16 +0530627 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceID, groupMod.GetCommand())
khenaidoo19d7b632018-10-30 10:49:50 -0400628}
629
Manikkaraj kb1a10922019-07-29 12:10:34 -0400630// updateMeterTable updates the meter table of that logical device
631func (agent *LogicalDeviceAgent) updateMeterTable(ctx context.Context, meterMod *ofp.OfpMeterMod) error {
632 log.Debug("updateMeterTable")
633 if meterMod == nil {
634 return nil
635 }
khenaidoo820197c2020-02-13 16:35:33 -0500636 if err := agent.generateDeviceRoutesIfNeeded(ctx); err != nil {
khenaidoo4c9e5592019-09-09 16:20:41 -0400637 return err
638 }
Manikkaraj kb1a10922019-07-29 12:10:34 -0400639 switch meterMod.GetCommand() {
640 case ofp.OfpMeterModCommand_OFPMC_ADD:
npujar467fe752020-01-16 20:17:45 +0530641 return agent.meterAdd(ctx, meterMod)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400642 case ofp.OfpMeterModCommand_OFPMC_DELETE:
npujar467fe752020-01-16 20:17:45 +0530643 return agent.meterDelete(ctx, meterMod)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400644 case ofp.OfpMeterModCommand_OFPMC_MODIFY:
npujar467fe752020-01-16 20:17:45 +0530645 return agent.meterModify(ctx, meterMod)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400646 }
647 return status.Errorf(codes.Internal,
npujar1d86a522019-11-14 17:11:16 +0530648 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceID, meterMod.GetCommand())
Manikkaraj kb1a10922019-07-29 12:10:34 -0400649
650}
651
npujar467fe752020-01-16 20:17:45 +0530652func (agent *LogicalDeviceAgent) meterAdd(ctx context.Context, meterMod *ofp.OfpMeterMod) error {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400653 log.Debugw("meterAdd", log.Fields{"metermod": *meterMod})
654 if meterMod == nil {
655 return nil
656 }
657 log.Debug("Waiting for logical device lock!!")
658 agent.lockLogicalDevice.Lock()
659 defer agent.lockLogicalDevice.Unlock()
660 log.Debug("Acquired logical device lock")
khenaidoo6e55d9e2019-12-12 18:26:26 -0500661 lDevice := agent.getLogicalDeviceWithoutLock()
Manikkaraj kb1a10922019-07-29 12:10:34 -0400662
663 var meters []*ofp.OfpMeterEntry
664 if lDevice.Meters != nil && lDevice.Meters.Items != nil {
665 meters = lDevice.Meters.Items
666 }
667 log.Debugw("Available meters", log.Fields{"meters": meters})
668
669 for _, meter := range meters {
670 if meterMod.MeterId == meter.Config.MeterId {
671 log.Infow("Meter-already-exists", log.Fields{"meter": *meterMod})
672 return nil
673 }
674 }
675
676 meterEntry := fu.MeterEntryFromMeterMod(meterMod)
677 meters = append(meters, meterEntry)
678 //Update model
npujar467fe752020-01-16 20:17:45 +0530679 if err := agent.updateLogicalDeviceMetersWithoutLock(ctx, &ofp.Meters{Items: meters}); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530680 log.Errorw("db-meter-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400681 return err
682 }
683 log.Debugw("Meter-added-successfully", log.Fields{"Added-meter": meterEntry, "updated-meters": lDevice.Meters})
684 return nil
685}
686
npujar467fe752020-01-16 20:17:45 +0530687func (agent *LogicalDeviceAgent) meterDelete(ctx context.Context, meterMod *ofp.OfpMeterMod) error {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400688 log.Debug("meterDelete", log.Fields{"meterMod": *meterMod})
689 if meterMod == nil {
690 return nil
691 }
692 agent.lockLogicalDevice.Lock()
693 defer agent.lockLogicalDevice.Unlock()
694
khenaidoo6e55d9e2019-12-12 18:26:26 -0500695 lDevice := agent.getLogicalDeviceWithoutLock()
Manikkaraj kb1a10922019-07-29 12:10:34 -0400696
697 var meters []*ofp.OfpMeterEntry
698 var flows []*ofp.OfpFlowStats
699 updatedFlows := make([]*ofp.OfpFlowStats, 0)
700 if lDevice.Meters != nil && lDevice.Meters.Items != nil {
701 meters = lDevice.Meters.Items
702 }
Manikkaraj kb1a10922019-07-29 12:10:34 -0400703
704 changedMeter := false
705 changedFow := false
706 log.Debugw("Available meters", log.Fields{"meters": meters})
707 for index, meter := range meters {
708 if meterMod.MeterId == meter.Config.MeterId {
709 flows = lDevice.Flows.Items
npujar1d86a522019-11-14 17:11:16 +0530710 changedFow, updatedFlows = agent.getUpdatedFlowsAfterDeletebyMeterID(flows, meterMod.MeterId)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400711 meters = append(meters[:index], meters[index+1:]...)
712 log.Debugw("Meter has been deleted", log.Fields{"meter": meter, "index": index})
713 changedMeter = true
714 break
715 }
716 }
717 if changedMeter {
718 //Update model
719 metersToUpdate := &ofp.Meters{}
720 if lDevice.Meters != nil {
721 metersToUpdate = &ofp.Meters{Items: meters}
722 }
npujar467fe752020-01-16 20:17:45 +0530723 if err := agent.updateLogicalDeviceMetersWithoutLock(ctx, metersToUpdate); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530724 log.Errorw("db-meter-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400725 return err
726 }
727 log.Debug("Meter-deleted-from-DB-successfully", log.Fields{"updatedMeters": metersToUpdate, "no-of-meter": len(metersToUpdate.Items)})
728
729 }
730 if changedFow {
731 //Update model
npujar467fe752020-01-16 20:17:45 +0530732 if err := agent.updateLogicalDeviceFlowsWithoutLock(ctx, &ofp.Flows{Items: updatedFlows}); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530733 log.Errorw("db-flow-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400734 return err
735 }
736 log.Debug("Flows-associated-with-meter-deleted-from-DB-successfully",
737 log.Fields{"updated-no-of-flows": len(updatedFlows), "meter": meterMod.MeterId})
738 }
739 log.Debugw("meterDelete success", log.Fields{"meterID": meterMod.MeterId})
740 return nil
741}
742
npujar467fe752020-01-16 20:17:45 +0530743func (agent *LogicalDeviceAgent) meterModify(ctx context.Context, meterMod *ofp.OfpMeterMod) error {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400744 log.Debug("meterModify")
745 if meterMod == nil {
746 return nil
747 }
748 agent.lockLogicalDevice.Lock()
749 defer agent.lockLogicalDevice.Unlock()
750
khenaidoo6e55d9e2019-12-12 18:26:26 -0500751 lDevice := agent.getLogicalDeviceWithoutLock()
Manikkaraj kb1a10922019-07-29 12:10:34 -0400752
753 var meters []*ofp.OfpMeterEntry
754 if lDevice.Meters != nil && lDevice.Meters.Items != nil {
755 meters = lDevice.Meters.Items
756 }
757 changedMeter := false
758 for index, meter := range meters {
759 if meterMod.MeterId == meter.Config.MeterId {
760 newmeterEntry := fu.MeterEntryFromMeterMod(meterMod)
761 newmeterEntry.Stats.FlowCount = meter.Stats.FlowCount
762 meters[index] = newmeterEntry
763 changedMeter = true
764 log.Debugw("Found meter, replaced with new meter", log.Fields{"old meter": meter, "new meter": newmeterEntry})
765 break
766 }
767 }
768 if changedMeter {
769 //Update model
770 metersToUpdate := &ofp.Meters{}
771 if lDevice.Meters != nil {
772 metersToUpdate = &ofp.Meters{Items: meters}
773 }
npujar467fe752020-01-16 20:17:45 +0530774 if err := agent.updateLogicalDeviceMetersWithoutLock(ctx, metersToUpdate); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530775 log.Errorw("db-meter-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400776 return err
777 }
778 log.Debugw("meter-updated-in-DB-successfully", log.Fields{"updated_meters": meters})
779 return nil
780 }
781
782 log.Errorw("Meter not found ", log.Fields{"meter": meterMod})
npujar1d86a522019-11-14 17:11:16 +0530783 return fmt.Errorf("no-logical-device-present:%d", meterMod.MeterId)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400784
785}
786
npujar1d86a522019-11-14 17:11:16 +0530787func (agent *LogicalDeviceAgent) getUpdatedFlowsAfterDeletebyMeterID(flows []*ofp.OfpFlowStats, meterID uint32) (bool, []*ofp.OfpFlowStats) {
788 log.Infow("Delete flows matching meter", log.Fields{"meter": meterID})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400789 changed := false
790 //updatedFlows := make([]*ofp.OfpFlowStats, 0)
791 for index := len(flows) - 1; index >= 0; index-- {
npujar1d86a522019-11-14 17:11:16 +0530792 if mID := fu.GetMeterIdFromFlow(flows[index]); mID != 0 && mID == meterID {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400793 log.Debugw("Flow to be deleted", log.Fields{"flow": flows[index], "index": index})
794 flows = append(flows[:index], flows[index+1:]...)
795 changed = true
796 }
797 }
798 return changed, flows
799}
800
801func (agent *LogicalDeviceAgent) updateFlowCountOfMeterStats(modCommand *ofp.OfpFlowMod, meters []*ofp.OfpMeterEntry, flow *ofp.OfpFlowStats) bool {
802
803 flowCommand := modCommand.GetCommand()
npujar1d86a522019-11-14 17:11:16 +0530804 meterID := fu.GetMeterIdFromFlow(flow)
805 log.Debugw("Meter-id-in-flow-mod", log.Fields{"meterId": meterID})
806 if meterID == 0 {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400807 log.Debugw("No meter present in the flow", log.Fields{"flow": *flow})
808 return false
809 }
810 if meters == nil {
811 log.Debug("No meters present in logical device")
812 return false
813 }
814 changedMeter := false
815 for _, meter := range meters {
npujar1d86a522019-11-14 17:11:16 +0530816 if meterID == meter.Config.MeterId { // Found meter in Logicaldevice
Manikkaraj kb1a10922019-07-29 12:10:34 -0400817 if flowCommand == ofp.OfpFlowModCommand_OFPFC_ADD {
npujar1d86a522019-11-14 17:11:16 +0530818 meter.Stats.FlowCount++
Manikkaraj kb1a10922019-07-29 12:10:34 -0400819 changedMeter = true
820 } else if flowCommand == ofp.OfpFlowModCommand_OFPFC_DELETE_STRICT {
npujar1d86a522019-11-14 17:11:16 +0530821 meter.Stats.FlowCount--
Manikkaraj kb1a10922019-07-29 12:10:34 -0400822 changedMeter = true
823 }
npujar1d86a522019-11-14 17:11:16 +0530824 log.Debugw("Found meter, updated meter flow stats", log.Fields{" meterId": meterID})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400825 break
826 }
827 }
828 return changedMeter
829}
830
khenaidoo19d7b632018-10-30 10:49:50 -0400831//flowAdd adds a flow to the flow table of that logical device
npujar467fe752020-01-16 20:17:45 +0530832func (agent *LogicalDeviceAgent) flowAdd(ctx context.Context, mod *ofp.OfpFlowMod) error {
khenaidoo4c9e5592019-09-09 16:20:41 -0400833 log.Debugw("flowAdd", log.Fields{"flow": mod})
khenaidoo19d7b632018-10-30 10:49:50 -0400834 if mod == nil {
835 return nil
836 }
khenaidoo92e62c52018-10-03 14:02:54 -0400837 agent.lockLogicalDevice.Lock()
838 defer agent.lockLogicalDevice.Unlock()
khenaidoo19d7b632018-10-30 10:49:50 -0400839
khenaidoo6e55d9e2019-12-12 18:26:26 -0500840 lDevice := agent.getLogicalDeviceWithoutLock()
khenaidoo19d7b632018-10-30 10:49:50 -0400841
842 var flows []*ofp.OfpFlowStats
Manikkaraj kb1a10922019-07-29 12:10:34 -0400843 var meters []*ofp.OfpMeterEntry
844 var flow *ofp.OfpFlowStats
Scott Bakerfdea1e32020-02-21 15:35:41 -0800845 var err error
Manikkaraj kb1a10922019-07-29 12:10:34 -0400846
khenaidoo19d7b632018-10-30 10:49:50 -0400847 if lDevice.Flows != nil && lDevice.Flows.Items != nil {
848 flows = lDevice.Flows.Items
849 }
850
Manikkaraj kb1a10922019-07-29 12:10:34 -0400851 if lDevice.Meters != nil && lDevice.Meters.Items != nil {
852 meters = lDevice.Meters.Items
853 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400854 updatedFlows := make([]*ofp.OfpFlowStats, 0)
khenaidoo19d7b632018-10-30 10:49:50 -0400855 changed := false
Manikkaraj kb1a10922019-07-29 12:10:34 -0400856 updated := false
khenaidoo19d7b632018-10-30 10:49:50 -0400857 checkOverlap := (mod.Flags & uint32(ofp.OfpFlowModFlags_OFPFF_CHECK_OVERLAP)) != 0
858 if checkOverlap {
859 if overlapped := fu.FindOverlappingFlows(flows, mod); len(overlapped) != 0 {
860 // TODO: should this error be notified other than being logged?
npujar1d86a522019-11-14 17:11:16 +0530861 log.Warnw("overlapped-flows", log.Fields{"logicaldeviceId": agent.logicalDeviceID})
khenaidoo19d7b632018-10-30 10:49:50 -0400862 } else {
Matt Jeanneret518b5a42019-10-29 10:30:46 -0400863 // Add flow
Scott Bakerfdea1e32020-02-21 15:35:41 -0800864 flow, err = fu.FlowStatsEntryFromFlowModMessage(mod)
865 if err != nil {
866 return err
867 }
khenaidoo19d7b632018-10-30 10:49:50 -0400868 flows = append(flows, flow)
khenaidoo2c6a0992019-04-29 13:46:56 -0400869 updatedFlows = append(updatedFlows, flow)
khenaidoo19d7b632018-10-30 10:49:50 -0400870 changed = true
871 }
872 } else {
Scott Bakerfdea1e32020-02-21 15:35:41 -0800873 flow, err = fu.FlowStatsEntryFromFlowModMessage(mod)
874 if err != nil {
875 return err
876 }
khenaidoo19d7b632018-10-30 10:49:50 -0400877 idx := fu.FindFlows(flows, flow)
878 if idx >= 0 {
879 oldFlow := flows[idx]
880 if (mod.Flags & uint32(ofp.OfpFlowModFlags_OFPFF_RESET_COUNTS)) != 0 {
881 flow.ByteCount = oldFlow.ByteCount
882 flow.PacketCount = oldFlow.PacketCount
883 }
Matt Jeanneret518b5a42019-10-29 10:30:46 -0400884 if !reflect.DeepEqual(oldFlow, flow) {
885 flows[idx] = flow
886 updatedFlows = append(updatedFlows, flow)
887 changed = true
888 updated = true
889 }
890 } else {
khenaidoo19d7b632018-10-30 10:49:50 -0400891 flows = append(flows, flow)
khenaidoo2c6a0992019-04-29 13:46:56 -0400892 updatedFlows = append(updatedFlows, flow)
893 changed = true
khenaidoo19d7b632018-10-30 10:49:50 -0400894 }
khenaidoo19d7b632018-10-30 10:49:50 -0400895 }
khenaidoo4c9e5592019-09-09 16:20:41 -0400896 log.Debugw("flowAdd-changed", log.Fields{"changed": changed})
897
khenaidoo19d7b632018-10-30 10:49:50 -0400898 if changed {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400899 var flowMetadata voltha.FlowMetadata
900 if err := agent.GetMeterConfig(updatedFlows, meters, &flowMetadata); err != nil { // This should never happen,meters should be installed before flow arrives
901 log.Error("Meter-referred-in-flows-not-present")
902 return err
903 }
khenaidoo820197c2020-02-13 16:35:33 -0500904 deviceRules, err := agent.flowDecomposer.DecomposeRules(ctx, agent, ofp.Flows{Items: updatedFlows}, *lDevice.FlowGroups)
905 if err != nil {
906 return err
907 }
khenaidoo0458db62019-06-20 08:50:36 -0400908 log.Debugw("rules", log.Fields{"rules": deviceRules.String()})
909
npujar467fe752020-01-16 20:17:45 +0530910 if err := agent.addDeviceFlowsAndGroups(ctx, deviceRules, &flowMetadata); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530911 log.Errorw("failure-updating-device-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "error": err})
khenaidoo2c6a0992019-04-29 13:46:56 -0400912 return err
913 }
914
khenaidoo19d7b632018-10-30 10:49:50 -0400915 // Update model
npujar467fe752020-01-16 20:17:45 +0530916 if err := agent.updateLogicalDeviceFlowsWithoutLock(ctx, &ofp.Flows{Items: flows}); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530917 log.Errorw("db-flow-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo19d7b632018-10-30 10:49:50 -0400918 return err
919 }
Matt Jeanneret518b5a42019-10-29 10:30:46 -0400920 if !updated {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400921 changedMeterStats := agent.updateFlowCountOfMeterStats(mod, meters, flow)
922 metersToUpdate := &ofp.Meters{}
923 if lDevice.Meters != nil {
924 metersToUpdate = &ofp.Meters{Items: meters}
925 }
926 if changedMeterStats {
927 //Update model
npujar467fe752020-01-16 20:17:45 +0530928 if err := agent.updateLogicalDeviceMetersWithoutLock(ctx, metersToUpdate); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530929 log.Errorw("db-meter-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400930 return err
931 }
932 log.Debugw("meter-stats-updated-in-DB-successfully", log.Fields{"updated_meters": meters})
933
934 }
935 }
936
khenaidoo19d7b632018-10-30 10:49:50 -0400937 }
khenaidoo19d7b632018-10-30 10:49:50 -0400938 return nil
939}
940
npujar1d86a522019-11-14 17:11:16 +0530941// GetMeterConfig returns meter config
Manikkaraj kb1a10922019-07-29 12:10:34 -0400942func (agent *LogicalDeviceAgent) GetMeterConfig(flows []*ofp.OfpFlowStats, meters []*ofp.OfpMeterEntry, metadata *voltha.FlowMetadata) error {
943 m := make(map[uint32]bool)
944 for _, flow := range flows {
npujar1d86a522019-11-14 17:11:16 +0530945 if flowMeterID := fu.GetMeterIdFromFlow(flow); flowMeterID != 0 && !m[flowMeterID] {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400946 foundMeter := false
947 // Meter is present in the flow , Get from logical device
948 for _, meter := range meters {
949 if flowMeterID == meter.Config.MeterId {
950 metadata.Meters = append(metadata.Meters, meter.Config)
951 log.Debugw("Found meter in logical device",
952 log.Fields{"meterID": flowMeterID, "meter-band": meter.Config})
953 m[flowMeterID] = true
954 foundMeter = true
955 break
956 }
957 }
958 if !foundMeter {
959 log.Errorw("Meter-referred-by-flow-is-not-found-in-logicaldevice",
npujar1d86a522019-11-14 17:11:16 +0530960 log.Fields{"meterID": flowMeterID, "Available-meters": meters, "flow": *flow})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400961 return errors.New("Meter-referred-by-flow-is-not-found-in-logicaldevice")
962 }
963 }
964 }
965 log.Debugw("meter-bands-for-flows", log.Fields{"flows": len(flows), "metadata": metadata})
966 return nil
967
968}
969
khenaidoo19d7b632018-10-30 10:49:50 -0400970//flowDelete deletes a flow from the flow table of that logical device
npujar467fe752020-01-16 20:17:45 +0530971func (agent *LogicalDeviceAgent) flowDelete(ctx context.Context, mod *ofp.OfpFlowMod) error {
khenaidoo19d7b632018-10-30 10:49:50 -0400972 log.Debug("flowDelete")
973 if mod == nil {
974 return nil
975 }
976 agent.lockLogicalDevice.Lock()
977 defer agent.lockLogicalDevice.Unlock()
978
khenaidoo6e55d9e2019-12-12 18:26:26 -0500979 lDevice := agent.getLogicalDeviceWithoutLock()
khenaidoo19d7b632018-10-30 10:49:50 -0400980
Manikkaraj kb1a10922019-07-29 12:10:34 -0400981 var meters []*ofp.OfpMeterEntry
982 var flows []*ofp.OfpFlowStats
Esin Karamanfc3b1af2020-01-29 16:52:00 +0000983 var flowGroups []*ofp.OfpGroupEntry
Manikkaraj kb1a10922019-07-29 12:10:34 -0400984
985 if lDevice.Flows != nil && lDevice.Flows.Items != nil {
986 flows = lDevice.Flows.Items
987 }
988
989 if lDevice.Meters != nil && lDevice.Meters.Items != nil {
990 meters = lDevice.Meters.Items
991 }
Esin Karamanfc3b1af2020-01-29 16:52:00 +0000992
993 if lDevice.FlowGroups != nil && lDevice.FlowGroups.Items != nil {
994 flowGroups = lDevice.FlowGroups.Items
995 }
996
khenaidoo19d7b632018-10-30 10:49:50 -0400997 //build a list of what to keep vs what to delete
998 toKeep := make([]*ofp.OfpFlowStats, 0)
khenaidoo0458db62019-06-20 08:50:36 -0400999 toDelete := make([]*ofp.OfpFlowStats, 0)
khenaidoo19d7b632018-10-30 10:49:50 -04001000 for _, f := range flows {
khenaidoo0458db62019-06-20 08:50:36 -04001001 // Check whether the flow and the flowmod matches
Scott Bakerfdea1e32020-02-21 15:35:41 -08001002 fs, err := fu.FlowStatsEntryFromFlowModMessage(mod)
1003 if err != nil {
1004 return err
1005 }
1006 if fu.FlowMatch(f, fs) {
khenaidoo0458db62019-06-20 08:50:36 -04001007 toDelete = append(toDelete, f)
1008 continue
1009 }
1010 // Check wild card match
khenaidoo19d7b632018-10-30 10:49:50 -04001011 if !fu.FlowMatchesMod(f, mod) {
1012 toKeep = append(toKeep, f)
khenaidoo0458db62019-06-20 08:50:36 -04001013 } else {
1014 toDelete = append(toDelete, f)
khenaidoo19d7b632018-10-30 10:49:50 -04001015 }
1016 }
1017
npujar1d86a522019-11-14 17:11:16 +05301018 log.Debugw("flowDelete", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "toKeep": len(toKeep), "toDelete": toDelete})
khenaidoo0458db62019-06-20 08:50:36 -04001019
khenaidoo19d7b632018-10-30 10:49:50 -04001020 //Update flows
khenaidoo0458db62019-06-20 08:50:36 -04001021 if len(toDelete) > 0 {
Manikkaraj kb1a10922019-07-29 12:10:34 -04001022 var flowMetadata voltha.FlowMetadata
1023 if err := agent.GetMeterConfig(toDelete, meters, &flowMetadata); err != nil { // This should never happen
1024 log.Error("Meter-referred-in-flows-not-present")
1025 return errors.New("Meter-referred-in-flows-not-present")
1026 }
khenaidoo820197c2020-02-13 16:35:33 -05001027 deviceRules, err := agent.flowDecomposer.DecomposeRules(ctx, agent, ofp.Flows{Items: toDelete}, ofp.FlowGroups{Items: flowGroups})
1028 if err != nil {
1029 return err
1030 }
khenaidoo0458db62019-06-20 08:50:36 -04001031 log.Debugw("rules", log.Fields{"rules": deviceRules.String()})
1032
npujar467fe752020-01-16 20:17:45 +05301033 if err := agent.deleteDeviceFlowsAndGroups(ctx, deviceRules, &flowMetadata); err != nil {
npujar1d86a522019-11-14 17:11:16 +05301034 log.Errorw("failure-updating-device-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "error": err})
khenaidoo0458db62019-06-20 08:50:36 -04001035 return err
1036 }
1037
npujar467fe752020-01-16 20:17:45 +05301038 if err := agent.updateLogicalDeviceFlowsWithoutLock(ctx, &ofp.Flows{Items: toKeep}); err != nil {
Thomas Lee Se5a44012019-11-07 20:32:24 +05301039 log.Errorw("cannot-update-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo19d7b632018-10-30 10:49:50 -04001040 return err
1041 }
1042 }
1043
1044 //TODO: send announcement on delete
1045 return nil
1046}
1047
npujar467fe752020-01-16 20:17:45 +05301048func (agent *LogicalDeviceAgent) addDeviceFlowsAndGroups(ctx context.Context, deviceRules *fu.DeviceRules, flowMetadata *voltha.FlowMetadata) error {
npujar1d86a522019-11-14 17:11:16 +05301049 log.Debugw("addDeviceFlowsAndGroups", log.Fields{"logicalDeviceID": agent.logicalDeviceID, "deviceRules": deviceRules, "flowMetadata": flowMetadata})
khenaidoo19d7b632018-10-30 10:49:50 -04001050
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001051 responses := make([]coreutils.Response, 0)
npujar1d86a522019-11-14 17:11:16 +05301052 for deviceID, value := range deviceRules.GetRules() {
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001053 response := coreutils.NewResponse()
1054 responses = append(responses, response)
1055 go func(deviceId string, value *fu.FlowsAndGroups) {
npujar467fe752020-01-16 20:17:45 +05301056 if err := agent.deviceMgr.addFlowsAndGroups(ctx, deviceId, value.ListFlows(), value.ListGroups(), flowMetadata); err != nil {
khenaidoo0458db62019-06-20 08:50:36 -04001057 log.Errorw("flow-add-failed", log.Fields{"deviceID": deviceId, "error": err})
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001058 response.Error(status.Errorf(codes.Internal, "flow-add-failed: %s", deviceId))
khenaidoo0458db62019-06-20 08:50:36 -04001059 }
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001060 response.Done()
npujar1d86a522019-11-14 17:11:16 +05301061 }(deviceID, value)
khenaidoo19d7b632018-10-30 10:49:50 -04001062 }
khenaidoo0458db62019-06-20 08:50:36 -04001063 // Wait for completion
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001064 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, responses...); res != nil {
khenaidoo0458db62019-06-20 08:50:36 -04001065 return status.Errorf(codes.Aborted, "errors-%s", res)
khenaidoo19d7b632018-10-30 10:49:50 -04001066 }
khenaidoo0458db62019-06-20 08:50:36 -04001067 return nil
1068}
khenaidoo19d7b632018-10-30 10:49:50 -04001069
npujar467fe752020-01-16 20:17:45 +05301070func (agent *LogicalDeviceAgent) deleteDeviceFlowsAndGroups(ctx context.Context, deviceRules *fu.DeviceRules, flowMetadata *voltha.FlowMetadata) error {
npujar1d86a522019-11-14 17:11:16 +05301071 log.Debugw("deleteDeviceFlowsAndGroups", log.Fields{"logicalDeviceID": agent.logicalDeviceID})
khenaidoo0458db62019-06-20 08:50:36 -04001072
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001073 responses := make([]coreutils.Response, 0)
npujar1d86a522019-11-14 17:11:16 +05301074 for deviceID, value := range deviceRules.GetRules() {
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001075 response := coreutils.NewResponse()
1076 responses = append(responses, response)
1077 go func(deviceId string, value *fu.FlowsAndGroups) {
npujar467fe752020-01-16 20:17:45 +05301078 if err := agent.deviceMgr.deleteFlowsAndGroups(ctx, deviceId, value.ListFlows(), value.ListGroups(), flowMetadata); err != nil {
khenaidoo0458db62019-06-20 08:50:36 -04001079 log.Error("flow-delete-failed", log.Fields{"deviceID": deviceId, "error": err})
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001080 response.Error(status.Errorf(codes.Internal, "flow-delete-failed: %s", deviceId))
khenaidoo0458db62019-06-20 08:50:36 -04001081 }
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001082 response.Done()
npujar1d86a522019-11-14 17:11:16 +05301083 }(deviceID, value)
khenaidoo0458db62019-06-20 08:50:36 -04001084 }
1085 // Wait for completion
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001086 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, responses...); res != nil {
khenaidoo0458db62019-06-20 08:50:36 -04001087 return status.Errorf(codes.Aborted, "errors-%s", res)
1088 }
1089 return nil
1090}
1091
npujar467fe752020-01-16 20:17:45 +05301092func (agent *LogicalDeviceAgent) updateDeviceFlowsAndGroups(ctx context.Context, deviceRules *fu.DeviceRules, flowMetadata *voltha.FlowMetadata) error {
npujar1d86a522019-11-14 17:11:16 +05301093 log.Debugw("updateDeviceFlowsAndGroups", log.Fields{"logicalDeviceID": agent.logicalDeviceID})
khenaidoo0458db62019-06-20 08:50:36 -04001094
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001095 responses := make([]coreutils.Response, 0)
npujar1d86a522019-11-14 17:11:16 +05301096 for deviceID, value := range deviceRules.GetRules() {
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001097 response := coreutils.NewResponse()
1098 responses = append(responses, response)
1099 go func(deviceId string, value *fu.FlowsAndGroups) {
npujar467fe752020-01-16 20:17:45 +05301100 if err := agent.deviceMgr.updateFlowsAndGroups(ctx, deviceId, value.ListFlows(), value.ListGroups(), flowMetadata); err != nil {
khenaidoo0458db62019-06-20 08:50:36 -04001101 log.Error("flow-update-failed", log.Fields{"deviceID": deviceId, "error": err})
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001102 response.Error(status.Errorf(codes.Internal, "flow-update-failed: %s", deviceId))
khenaidoo0458db62019-06-20 08:50:36 -04001103 }
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001104 response.Done()
npujar1d86a522019-11-14 17:11:16 +05301105 }(deviceID, value)
khenaidoo0458db62019-06-20 08:50:36 -04001106 }
1107 // Wait for completion
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001108 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, responses...); res != nil {
khenaidoo0458db62019-06-20 08:50:36 -04001109 return status.Errorf(codes.Aborted, "errors-%s", res)
khenaidoo19d7b632018-10-30 10:49:50 -04001110 }
1111 return nil
1112}
1113
1114//flowDeleteStrict deletes a flow from the flow table of that logical device
npujar467fe752020-01-16 20:17:45 +05301115func (agent *LogicalDeviceAgent) flowDeleteStrict(ctx context.Context, mod *ofp.OfpFlowMod) error {
khenaidoo19d7b632018-10-30 10:49:50 -04001116 log.Debug("flowDeleteStrict")
1117 if mod == nil {
1118 return nil
1119 }
1120 agent.lockLogicalDevice.Lock()
1121 defer agent.lockLogicalDevice.Unlock()
1122
khenaidoo6e55d9e2019-12-12 18:26:26 -05001123 lDevice := agent.getLogicalDeviceWithoutLock()
1124
Manikkaraj kb1a10922019-07-29 12:10:34 -04001125 var meters []*ofp.OfpMeterEntry
1126 var flows []*ofp.OfpFlowStats
Esin Karamanfc3b1af2020-01-29 16:52:00 +00001127 var flowGroups []*ofp.OfpGroupEntry
Manikkaraj kb1a10922019-07-29 12:10:34 -04001128 if lDevice.Meters != nil && lDevice.Meters.Items != nil {
1129 meters = lDevice.Meters.Items
1130 }
1131 if lDevice.Flows != nil && lDevice.Flows.Items != nil {
1132 flows = lDevice.Flows.Items
1133 }
Esin Karamanfc3b1af2020-01-29 16:52:00 +00001134 if lDevice.FlowGroups != nil && lDevice.FlowGroups.Items != nil {
1135 flowGroups = lDevice.FlowGroups.Items
1136 }
Manikkaraj kb1a10922019-07-29 12:10:34 -04001137
1138 changedFlow := false
1139 changedMeter := false
Scott Bakerfdea1e32020-02-21 15:35:41 -08001140 flow, err := fu.FlowStatsEntryFromFlowModMessage(mod)
1141 if err != nil {
1142 return err
1143 }
Manikkaraj kb1a10922019-07-29 12:10:34 -04001144 flowsToDelete := make([]*ofp.OfpFlowStats, 0)
khenaidoo19d7b632018-10-30 10:49:50 -04001145 idx := fu.FindFlows(flows, flow)
1146 if idx >= 0 {
Gamze Abaka6e4ac162019-10-21 11:10:10 +00001147 changedMeter = agent.updateFlowCountOfMeterStats(mod, meters, flows[idx])
Manikkaraj kb1a10922019-07-29 12:10:34 -04001148 flowsToDelete = append(flowsToDelete, flows[idx])
khenaidoo19d7b632018-10-30 10:49:50 -04001149 flows = append(flows[:idx], flows[idx+1:]...)
Manikkaraj kb1a10922019-07-29 12:10:34 -04001150 changedFlow = true
khenaidoo19d7b632018-10-30 10:49:50 -04001151 } else {
npujar1d86a522019-11-14 17:11:16 +05301152 return fmt.Errorf("Cannot delete flow - %s", flow)
khenaidoo19d7b632018-10-30 10:49:50 -04001153 }
Manikkaraj kb1a10922019-07-29 12:10:34 -04001154 if changedMeter {
1155 //Update model
1156 metersToUpdate := &ofp.Meters{}
1157 if lDevice.Meters != nil {
1158 metersToUpdate = &ofp.Meters{Items: meters}
1159 }
npujar467fe752020-01-16 20:17:45 +05301160 if err := agent.updateLogicalDeviceMetersWithoutLock(ctx, metersToUpdate); err != nil {
npujar1d86a522019-11-14 17:11:16 +05301161 log.Errorw("db-meter-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
Manikkaraj kb1a10922019-07-29 12:10:34 -04001162 return err
1163 }
khenaidoo19d7b632018-10-30 10:49:50 -04001164
Manikkaraj kb1a10922019-07-29 12:10:34 -04001165 }
1166 if changedFlow {
1167 var flowMetadata voltha.FlowMetadata
1168 if err := agent.GetMeterConfig(flowsToDelete, meters, &flowMetadata); err != nil {
Thomas Lee Se5a44012019-11-07 20:32:24 +05301169 log.Error("meter-referred-in-flows-not-present")
Manikkaraj kb1a10922019-07-29 12:10:34 -04001170 return err
1171 }
khenaidoo820197c2020-02-13 16:35:33 -05001172 deviceRules, err := agent.flowDecomposer.DecomposeRules(ctx, agent, ofp.Flows{Items: flowsToDelete}, ofp.FlowGroups{Items: flowGroups})
1173 if err != nil {
1174 return err
1175 }
khenaidoo0458db62019-06-20 08:50:36 -04001176 log.Debugw("rules", log.Fields{"rules": deviceRules.String()})
1177
npujar467fe752020-01-16 20:17:45 +05301178 if err := agent.deleteDeviceFlowsAndGroups(ctx, deviceRules, &flowMetadata); err != nil {
npujar1d86a522019-11-14 17:11:16 +05301179 log.Errorw("failure-deleting-device-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "error": err})
khenaidoo0458db62019-06-20 08:50:36 -04001180 return err
1181 }
1182
npujar467fe752020-01-16 20:17:45 +05301183 if err := agent.updateLogicalDeviceFlowsWithoutLock(ctx, &ofp.Flows{Items: flows}); err != nil {
Thomas Lee Se5a44012019-11-07 20:32:24 +05301184 log.Errorw("cannot-update-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo19d7b632018-10-30 10:49:50 -04001185 return err
1186 }
1187 }
khenaidoo19d7b632018-10-30 10:49:50 -04001188 return nil
1189}
1190
1191//flowModify modifies a flow from the flow table of that logical device
1192func (agent *LogicalDeviceAgent) flowModify(mod *ofp.OfpFlowMod) error {
1193 return errors.New("flowModify not implemented")
1194}
1195
1196//flowModifyStrict deletes a flow from the flow table of that logical device
1197func (agent *LogicalDeviceAgent) flowModifyStrict(mod *ofp.OfpFlowMod) error {
1198 return errors.New("flowModifyStrict not implemented")
1199}
1200
npujar467fe752020-01-16 20:17:45 +05301201func (agent *LogicalDeviceAgent) groupAdd(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
khenaidoo19d7b632018-10-30 10:49:50 -04001202 log.Debug("groupAdd")
1203 if groupMod == nil {
1204 return nil
1205 }
1206 agent.lockLogicalDevice.Lock()
1207 defer agent.lockLogicalDevice.Unlock()
1208
khenaidoo6e55d9e2019-12-12 18:26:26 -05001209 lDevice := agent.getLogicalDeviceWithoutLock()
1210
khenaidoo19d7b632018-10-30 10:49:50 -04001211 groups := lDevice.FlowGroups.Items
khenaidoo19d7b632018-10-30 10:49:50 -04001212 if fu.FindGroup(groups, groupMod.GroupId) == -1 {
khenaidoo68c930b2019-05-13 11:46:51 -04001213 groups = append(groups, fu.GroupEntryFromGroupMod(groupMod))
khenaidoo0458db62019-06-20 08:50:36 -04001214
Esin Karaman2ea59212019-12-06 11:41:58 +00001215 deviceRules := fu.NewDeviceRules()
1216 deviceRules.CreateEntryIfNotExist(agent.rootDeviceID)
1217 fg := fu.NewFlowsAndGroups()
1218 fg.AddGroup(fu.GroupEntryFromGroupMod(groupMod))
1219 deviceRules.AddFlowsAndGroup(agent.rootDeviceID, fg)
1220
1221 log.Debugw("rules", log.Fields{"rules for group-add": deviceRules.String()})
npujar467fe752020-01-16 20:17:45 +05301222 if err := agent.addDeviceFlowsAndGroups(ctx, deviceRules, &voltha.FlowMetadata{}); err != nil {
npujar1d86a522019-11-14 17:11:16 +05301223 log.Errorw("failure-updating-device-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "error": err})
khenaidoo0458db62019-06-20 08:50:36 -04001224 return err
1225 }
1226
npujar467fe752020-01-16 20:17:45 +05301227 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(ctx, &ofp.FlowGroups{Items: groups}); err != nil {
Thomas Lee Se5a44012019-11-07 20:32:24 +05301228 log.Errorw("cannot-update-group", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo19d7b632018-10-30 10:49:50 -04001229 return err
1230 }
1231 } else {
npujar1d86a522019-11-14 17:11:16 +05301232 return fmt.Errorf("Groups %d already present", groupMod.GroupId)
khenaidoo19d7b632018-10-30 10:49:50 -04001233 }
khenaidoo19d7b632018-10-30 10:49:50 -04001234 return nil
1235}
1236
npujar467fe752020-01-16 20:17:45 +05301237func (agent *LogicalDeviceAgent) groupDelete(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
khenaidoo19d7b632018-10-30 10:49:50 -04001238 log.Debug("groupDelete")
1239 if groupMod == nil {
1240 return nil
1241 }
1242 agent.lockLogicalDevice.Lock()
1243 defer agent.lockLogicalDevice.Unlock()
1244
khenaidoo6e55d9e2019-12-12 18:26:26 -05001245 lDevice := agent.getLogicalDeviceWithoutLock()
khenaidoo19d7b632018-10-30 10:49:50 -04001246 groups := lDevice.FlowGroups.Items
1247 flows := lDevice.Flows.Items
npujar1d86a522019-11-14 17:11:16 +05301248 var groupsChanged bool
khenaidoo19d7b632018-10-30 10:49:50 -04001249 flowsChanged := false
npujar1d86a522019-11-14 17:11:16 +05301250 groupID := groupMod.GroupId
1251 if groupID == uint32(ofp.OfpGroup_OFPG_ALL) {
khenaidoo19d7b632018-10-30 10:49:50 -04001252 //TODO we must delete all flows that point to this group and
1253 //signal controller as requested by flow's flag
1254 groups = []*ofp.OfpGroupEntry{}
1255 groupsChanged = true
1256 } else {
npujar1d86a522019-11-14 17:11:16 +05301257 idx := fu.FindGroup(groups, groupID)
1258 if idx == -1 {
khenaidoo19d7b632018-10-30 10:49:50 -04001259 return nil // Valid case
khenaidoo19d7b632018-10-30 10:49:50 -04001260 }
npujar1d86a522019-11-14 17:11:16 +05301261 flowsChanged, flows = fu.FlowsDeleteByGroupId(flows, groupID)
1262 groups = append(groups[:idx], groups[idx+1:]...)
1263 groupsChanged = true
khenaidoo19d7b632018-10-30 10:49:50 -04001264 }
khenaidoo0458db62019-06-20 08:50:36 -04001265 if flowsChanged || groupsChanged {
khenaidoo820197c2020-02-13 16:35:33 -05001266 deviceRules, err := agent.flowDecomposer.DecomposeRules(ctx, agent, ofp.Flows{Items: flows}, ofp.FlowGroups{Items: groups})
1267 if err != nil {
1268 return err
1269 }
khenaidoo0458db62019-06-20 08:50:36 -04001270 log.Debugw("rules", log.Fields{"rules": deviceRules.String()})
1271
npujar467fe752020-01-16 20:17:45 +05301272 if err := agent.updateDeviceFlowsAndGroups(ctx, deviceRules, nil); err != nil {
npujar1d86a522019-11-14 17:11:16 +05301273 log.Errorw("failure-updating-device-flows-groups", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "error": err})
khenaidoo0458db62019-06-20 08:50:36 -04001274 return err
1275 }
1276 }
1277
khenaidoo43c82122018-11-22 18:38:28 -05001278 if groupsChanged {
npujar467fe752020-01-16 20:17:45 +05301279 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(ctx, &ofp.FlowGroups{Items: groups}); err != nil {
Thomas Lee Se5a44012019-11-07 20:32:24 +05301280 log.Errorw("cannot-update-group", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo19d7b632018-10-30 10:49:50 -04001281 return err
1282 }
1283 }
khenaidoo43c82122018-11-22 18:38:28 -05001284 if flowsChanged {
npujar467fe752020-01-16 20:17:45 +05301285 if err := agent.updateLogicalDeviceFlowsWithoutLock(ctx, &ofp.Flows{Items: flows}); err != nil {
Thomas Lee Se5a44012019-11-07 20:32:24 +05301286 log.Errorw("cannot-update-flow", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo43c82122018-11-22 18:38:28 -05001287 return err
1288 }
1289 }
khenaidoo19d7b632018-10-30 10:49:50 -04001290 return nil
1291}
1292
npujar467fe752020-01-16 20:17:45 +05301293func (agent *LogicalDeviceAgent) groupModify(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
khenaidoo19d7b632018-10-30 10:49:50 -04001294 log.Debug("groupModify")
1295 if groupMod == nil {
1296 return nil
1297 }
1298 agent.lockLogicalDevice.Lock()
1299 defer agent.lockLogicalDevice.Unlock()
1300
khenaidoo6e55d9e2019-12-12 18:26:26 -05001301 lDevice := agent.getLogicalDeviceWithoutLock()
khenaidoo19d7b632018-10-30 10:49:50 -04001302 groups := lDevice.FlowGroups.Items
npujar1d86a522019-11-14 17:11:16 +05301303 var groupsChanged bool
1304 groupID := groupMod.GroupId
1305 idx := fu.FindGroup(groups, groupID)
1306 if idx == -1 {
1307 return fmt.Errorf("group-absent:%d", groupID)
khenaidoo19d7b632018-10-30 10:49:50 -04001308 }
npujar1d86a522019-11-14 17:11:16 +05301309 //replace existing group entry with new group definition
1310 groupEntry := fu.GroupEntryFromGroupMod(groupMod)
1311 groups[idx] = groupEntry
1312 groupsChanged = true
khenaidoo19d7b632018-10-30 10:49:50 -04001313 if groupsChanged {
Esin Karaman2ea59212019-12-06 11:41:58 +00001314 deviceRules := fu.NewDeviceRules()
1315 deviceRules.CreateEntryIfNotExist(agent.rootDeviceID)
1316 fg := fu.NewFlowsAndGroups()
1317 fg.AddGroup(fu.GroupEntryFromGroupMod(groupMod))
1318 deviceRules.AddFlowsAndGroup(agent.rootDeviceID, fg)
khenaidoo0458db62019-06-20 08:50:36 -04001319
Esin Karaman2ea59212019-12-06 11:41:58 +00001320 log.Debugw("rules", log.Fields{"rules for group-modify": deviceRules.String()})
npujar467fe752020-01-16 20:17:45 +05301321 if err := agent.updateDeviceFlowsAndGroups(ctx, deviceRules, &voltha.FlowMetadata{}); err != nil {
npujar1d86a522019-11-14 17:11:16 +05301322 log.Errorw("failure-updating-device-flows-groups", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "error": err})
khenaidoo0458db62019-06-20 08:50:36 -04001323 return err
1324 }
1325
khenaidoo43c82122018-11-22 18:38:28 -05001326 //lDevice.FlowGroups.Items = groups
npujar467fe752020-01-16 20:17:45 +05301327 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(ctx, &ofp.FlowGroups{Items: groups}); err != nil {
npujar1d86a522019-11-14 17:11:16 +05301328 log.Errorw("Cannot-update-logical-group", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo19d7b632018-10-30 10:49:50 -04001329 return err
1330 }
1331 }
1332 return nil
1333}
1334
1335// deleteLogicalPort removes the logical port
npujar467fe752020-01-16 20:17:45 +05301336func (agent *LogicalDeviceAgent) deleteLogicalPort(ctx context.Context, lPort *voltha.LogicalPort) error {
khenaidoo19d7b632018-10-30 10:49:50 -04001337 agent.lockLogicalDevice.Lock()
1338 defer agent.lockLogicalDevice.Unlock()
1339
khenaidoo6e55d9e2019-12-12 18:26:26 -05001340 logicalDevice := agent.getLogicalDeviceWithoutLock()
1341
khenaidoo92e62c52018-10-03 14:02:54 -04001342 index := -1
khenaidoo6e55d9e2019-12-12 18:26:26 -05001343 for i, logicalPort := range logicalDevice.Ports {
khenaidoo19d7b632018-10-30 10:49:50 -04001344 if logicalPort.Id == lPort.Id {
khenaidoo92e62c52018-10-03 14:02:54 -04001345 index = i
1346 break
1347 }
1348 }
1349 if index >= 0 {
khenaidoo6e55d9e2019-12-12 18:26:26 -05001350 copy(logicalDevice.Ports[index:], logicalDevice.Ports[index+1:])
1351 logicalDevice.Ports[len(logicalDevice.Ports)-1] = nil
1352 logicalDevice.Ports = logicalDevice.Ports[:len(logicalDevice.Ports)-1]
npujar1d86a522019-11-14 17:11:16 +05301353 log.Debugw("logical-port-deleted", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
npujar467fe752020-01-16 20:17:45 +05301354 if err := agent.updateLogicalDeviceWithoutLock(ctx, logicalDevice); err != nil {
npujar1d86a522019-11-14 17:11:16 +05301355 log.Errorw("logical-device-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo0a822f92019-05-08 15:15:57 -04001356 return err
1357 }
khenaidoo820197c2020-02-13 16:35:33 -05001358
1359 // Remove the logical port from cache
1360 agent.deleteLogicalPortsFromMap([]uint32{lPort.DevicePortNo})
1361
1362 // Reset the logical device routes
1363 go func() {
1364 if err := agent.buildRoutes(context.Background()); err != nil {
khenaidoo80b987d2020-02-20 10:52:52 -05001365 log.Warnw("device-routes-not-ready", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "error": err})
khenaidoo820197c2020-02-13 16:35:33 -05001366 }
1367 }()
khenaidoo92e62c52018-10-03 14:02:54 -04001368 }
1369 return nil
khenaidoob9203542018-09-17 22:56:37 -04001370}
1371
khenaidoo0a822f92019-05-08 15:15:57 -04001372// deleteLogicalPorts removes the logical ports associated with that deviceId
npujar467fe752020-01-16 20:17:45 +05301373func (agent *LogicalDeviceAgent) deleteLogicalPorts(ctx context.Context, deviceID string) error {
khenaidoo0a822f92019-05-08 15:15:57 -04001374 agent.lockLogicalDevice.Lock()
1375 defer agent.lockLogicalDevice.Unlock()
1376
khenaidoo6e55d9e2019-12-12 18:26:26 -05001377 logicalDevice := agent.getLogicalDeviceWithoutLock()
khenaidoo820197c2020-02-13 16:35:33 -05001378 lPortstoKeep := []*voltha.LogicalPort{}
1379 lPortsNoToDelete := []uint32{}
khenaidoo6e55d9e2019-12-12 18:26:26 -05001380 for _, logicalPort := range logicalDevice.Ports {
npujar1d86a522019-11-14 17:11:16 +05301381 if logicalPort.DeviceId != deviceID {
khenaidoo820197c2020-02-13 16:35:33 -05001382 lPortstoKeep = append(lPortstoKeep, logicalPort)
1383 } else {
1384 lPortsNoToDelete = append(lPortsNoToDelete, logicalPort.DevicePortNo)
khenaidoo0a822f92019-05-08 15:15:57 -04001385 }
1386 }
khenaidoo820197c2020-02-13 16:35:33 -05001387 logicalDevice.Ports = lPortstoKeep
1388
1389 log.Debugw("updated-logical-ports", log.Fields{"ports": lPortstoKeep})
npujar467fe752020-01-16 20:17:45 +05301390 if err := agent.updateLogicalDeviceWithoutLock(ctx, logicalDevice); err != nil {
npujar1d86a522019-11-14 17:11:16 +05301391 log.Errorw("logical-device-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo0a822f92019-05-08 15:15:57 -04001392 return err
1393 }
khenaidoo820197c2020-02-13 16:35:33 -05001394 // Remove the port from the cached logical ports set
1395 agent.deleteLogicalPortsFromMap(lPortsNoToDelete)
1396
1397 // Reset the logical device routes
1398 go func() {
1399 if err := agent.buildRoutes(context.Background()); err != nil {
khenaidoo80b987d2020-02-20 10:52:52 -05001400 log.Warnw("routes-not-ready", log.Fields{"logical-device-id": agent.logicalDeviceID, "error": err})
khenaidoo820197c2020-02-13 16:35:33 -05001401 }
1402 }()
khenaidoo0a822f92019-05-08 15:15:57 -04001403
1404 return nil
1405}
1406
khenaidoo19d7b632018-10-30 10:49:50 -04001407// enableLogicalPort enables the logical port
npujar467fe752020-01-16 20:17:45 +05301408func (agent *LogicalDeviceAgent) enableLogicalPort(ctx context.Context, lPortID string) error {
khenaidoo19d7b632018-10-30 10:49:50 -04001409 agent.lockLogicalDevice.Lock()
1410 defer agent.lockLogicalDevice.Unlock()
1411
khenaidoo6e55d9e2019-12-12 18:26:26 -05001412 logicalDevice := agent.getLogicalDeviceWithoutLock()
1413
khenaidoo19d7b632018-10-30 10:49:50 -04001414 index := -1
khenaidoo6e55d9e2019-12-12 18:26:26 -05001415 for i, logicalPort := range logicalDevice.Ports {
npujar1d86a522019-11-14 17:11:16 +05301416 if logicalPort.Id == lPortID {
khenaidoo19d7b632018-10-30 10:49:50 -04001417 index = i
1418 break
1419 }
1420 }
1421 if index >= 0 {
khenaidoo6e55d9e2019-12-12 18:26:26 -05001422 logicalDevice.Ports[index].OfpPort.Config = logicalDevice.Ports[index].OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
npujar467fe752020-01-16 20:17:45 +05301423 return agent.updateLogicalDeviceWithoutLock(ctx, logicalDevice)
khenaidoo19d7b632018-10-30 10:49:50 -04001424 }
npujar1d86a522019-11-14 17:11:16 +05301425 return status.Errorf(codes.NotFound, "Port %s on Logical Device %s", lPortID, agent.logicalDeviceID)
khenaidoo19d7b632018-10-30 10:49:50 -04001426}
1427
1428// disableLogicalPort disabled the logical port
npujar467fe752020-01-16 20:17:45 +05301429func (agent *LogicalDeviceAgent) disableLogicalPort(ctx context.Context, lPortID string) error {
khenaidoo19d7b632018-10-30 10:49:50 -04001430 agent.lockLogicalDevice.Lock()
1431 defer agent.lockLogicalDevice.Unlock()
1432
1433 // Get the most up to date logical device
khenaidoo6e55d9e2019-12-12 18:26:26 -05001434 logicalDevice := agent.getLogicalDeviceWithoutLock()
khenaidoo19d7b632018-10-30 10:49:50 -04001435 index := -1
khenaidoo6e55d9e2019-12-12 18:26:26 -05001436 for i, logicalPort := range logicalDevice.Ports {
npujar1d86a522019-11-14 17:11:16 +05301437 if logicalPort.Id == lPortID {
khenaidoo19d7b632018-10-30 10:49:50 -04001438 index = i
1439 break
1440 }
1441 }
1442 if index >= 0 {
khenaidoo6e55d9e2019-12-12 18:26:26 -05001443 logicalDevice.Ports[index].OfpPort.Config = (logicalDevice.Ports[index].OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)) | uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
npujar467fe752020-01-16 20:17:45 +05301444 return agent.updateLogicalDeviceWithoutLock(ctx, logicalDevice)
khenaidoo19d7b632018-10-30 10:49:50 -04001445 }
npujar1d86a522019-11-14 17:11:16 +05301446 return status.Errorf(codes.NotFound, "Port %s on Logical Device %s", lPortID, agent.logicalDeviceID)
khenaidoo19d7b632018-10-30 10:49:50 -04001447}
1448
khenaidoo820197c2020-02-13 16:35:33 -05001449func (agent *LogicalDeviceAgent) getPreCalculatedRoute(ingress, egress uint32) ([]route.Hop, error) {
1450 log.Debugw("ROUTE", log.Fields{"len": len(agent.deviceRoutes.Routes)})
1451 for routeLink, route := range agent.deviceRoutes.Routes {
khenaidoo19d7b632018-10-30 10:49:50 -04001452 log.Debugw("ROUTELINKS", log.Fields{"ingress": ingress, "egress": egress, "routelink": routeLink})
khenaidoo89b0e942018-10-21 21:11:33 -04001453 if ingress == routeLink.Ingress && egress == routeLink.Egress {
khenaidoo820197c2020-02-13 16:35:33 -05001454 return route, nil
khenaidoo89b0e942018-10-21 21:11:33 -04001455 }
1456 }
khenaidoo820197c2020-02-13 16:35:33 -05001457 return nil, status.Errorf(codes.FailedPrecondition, "no route from:%d to:%d", ingress, egress)
khenaidoo89b0e942018-10-21 21:11:33 -04001458}
1459
npujar1d86a522019-11-14 17:11:16 +05301460// GetRoute returns route
khenaidoo820197c2020-02-13 16:35:33 -05001461func (agent *LogicalDeviceAgent) GetRoute(ctx context.Context, ingressPortNo uint32, egressPortNo uint32) ([]route.Hop, error) {
khenaidoo89b0e942018-10-21 21:11:33 -04001462 log.Debugw("getting-route", log.Fields{"ingress-port": ingressPortNo, "egress-port": egressPortNo})
khenaidoo820197c2020-02-13 16:35:33 -05001463 routes := make([]route.Hop, 0)
khenaidoo2c6a0992019-04-29 13:46:56 -04001464
khenaidoo19d7b632018-10-30 10:49:50 -04001465 // Note: A port value of 0 is equivalent to a nil port
1466
khenaidoo89b0e942018-10-21 21:11:33 -04001467 // Consider different possibilities
khenaidoo19d7b632018-10-30 10:49:50 -04001468 if egressPortNo != 0 && ((egressPortNo & 0x7fffffff) == uint32(ofp.OfpPortNo_OFPP_CONTROLLER)) {
khenaidoo2c6a0992019-04-29 13:46:56 -04001469 log.Debugw("controller-flow", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "logicalPortsNo": agent.logicalPortsNo})
1470 if agent.isNNIPort(ingressPortNo) {
khenaidoo89b0e942018-10-21 21:11:33 -04001471 //This is a trap on the NNI Port
khenaidoo820197c2020-02-13 16:35:33 -05001472 if len(agent.deviceRoutes.Routes) == 0 {
khenaidoo8f474192019-04-03 17:20:44 -04001473 // 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 -04001474 // route with same IngressHop and EgressHop
khenaidoo820197c2020-02-13 16:35:33 -05001475 hop := route.Hop{DeviceID: agent.rootDeviceID, Ingress: ingressPortNo, Egress: ingressPortNo}
khenaidoo8f474192019-04-03 17:20:44 -04001476 routes = append(routes, hop)
1477 routes = append(routes, hop)
khenaidoo820197c2020-02-13 16:35:33 -05001478 return routes, nil
khenaidoo8f474192019-04-03 17:20:44 -04001479 }
khenaidoo89b0e942018-10-21 21:11:33 -04001480 //Return a 'half' route to make the flow decomposer logic happy
khenaidoo820197c2020-02-13 16:35:33 -05001481 for routeLink, path := range agent.deviceRoutes.Routes {
khenaidoo2c6a0992019-04-29 13:46:56 -04001482 if agent.isNNIPort(routeLink.Egress) {
khenaidoo820197c2020-02-13 16:35:33 -05001483 routes = append(routes, route.Hop{}) // first hop is set to empty
1484 routes = append(routes, path[1])
1485 return routes, nil
khenaidoo89b0e942018-10-21 21:11:33 -04001486 }
1487 }
khenaidoo820197c2020-02-13 16:35:33 -05001488 return nil, status.Errorf(codes.FailedPrecondition, "no upstream route from:%d to:%d", ingressPortNo, egressPortNo)
khenaidoo89b0e942018-10-21 21:11:33 -04001489 }
1490 //treat it as if the output port is the first NNI of the OLT
khenaidoo2c6a0992019-04-29 13:46:56 -04001491 var err error
1492 if egressPortNo, err = agent.getFirstNNIPort(); err != nil {
1493 log.Warnw("no-nni-port", log.Fields{"error": err})
khenaidoo820197c2020-02-13 16:35:33 -05001494 return nil, err
khenaidoo2c6a0992019-04-29 13:46:56 -04001495 }
khenaidoo89b0e942018-10-21 21:11:33 -04001496 }
1497 //If ingress port is not specified (nil), it may be a wildcarded
1498 //route if egress port is OFPP_CONTROLLER or a nni logical port,
1499 //in which case we need to create a half-route where only the egress
1500 //hop is filled, the first hop is nil
khenaidoo2c6a0992019-04-29 13:46:56 -04001501 if ingressPortNo == 0 && agent.isNNIPort(egressPortNo) {
khenaidoo89b0e942018-10-21 21:11:33 -04001502 // We can use the 2nd hop of any upstream route, so just find the first upstream:
khenaidoo820197c2020-02-13 16:35:33 -05001503 for routeLink, path := range agent.deviceRoutes.Routes {
khenaidoo2c6a0992019-04-29 13:46:56 -04001504 if agent.isNNIPort(routeLink.Egress) {
khenaidoo820197c2020-02-13 16:35:33 -05001505 routes = append(routes, route.Hop{}) // first hop is set to empty
1506 routes = append(routes, path[1])
1507 return routes, nil
khenaidoo89b0e942018-10-21 21:11:33 -04001508 }
1509 }
khenaidoo820197c2020-02-13 16:35:33 -05001510 return nil, status.Errorf(codes.FailedPrecondition, "no upstream route from:%d to:%d", ingressPortNo, egressPortNo)
khenaidoo89b0e942018-10-21 21:11:33 -04001511 }
1512 //If egress port is not specified (nil), we can also can return a "half" route
khenaidoo19d7b632018-10-30 10:49:50 -04001513 if egressPortNo == 0 {
khenaidoo820197c2020-02-13 16:35:33 -05001514 for routeLink, path := range agent.deviceRoutes.Routes {
khenaidoo19d7b632018-10-30 10:49:50 -04001515 if routeLink.Ingress == ingressPortNo {
khenaidoo820197c2020-02-13 16:35:33 -05001516 routes = append(routes, path[0])
1517 routes = append(routes, route.Hop{})
1518 return routes, nil
khenaidoo89b0e942018-10-21 21:11:33 -04001519 }
1520 }
khenaidoo820197c2020-02-13 16:35:33 -05001521 return nil, status.Errorf(codes.FailedPrecondition, "no downstream route from:%d to:%d", ingressPortNo, egressPortNo)
khenaidoo89b0e942018-10-21 21:11:33 -04001522 }
khenaidoo89b0e942018-10-21 21:11:33 -04001523 // Return the pre-calculated route
khenaidoo19d7b632018-10-30 10:49:50 -04001524 return agent.getPreCalculatedRoute(ingressPortNo, egressPortNo)
khenaidoo89b0e942018-10-21 21:11:33 -04001525}
1526
khenaidoo3d3b8c22019-05-22 18:10:39 -04001527//GetWildcardInputPorts filters out the logical port number from the set of logical ports on the device and
1528//returns their port numbers. This function is invoked only during flow decomposition where the lock on the logical
1529//device is already held. Therefore it is safe to retrieve the logical device without lock.
khenaidoo89b0e942018-10-21 21:11:33 -04001530func (agent *LogicalDeviceAgent) GetWildcardInputPorts(excludePort ...uint32) []uint32 {
1531 lPorts := make([]uint32, 0)
1532 var exclPort uint32
1533 if len(excludePort) == 1 {
1534 exclPort = excludePort[0]
1535 }
khenaidoo6e55d9e2019-12-12 18:26:26 -05001536 lDevice := agent.getLogicalDeviceWithoutLock()
1537 for _, port := range lDevice.Ports {
1538 if port.OfpPort.PortNo != exclPort {
1539 lPorts = append(lPorts, port.OfpPort.PortNo)
khenaidoo89b0e942018-10-21 21:11:33 -04001540 }
1541 }
1542 return lPorts
1543}
khenaidoo19d7b632018-10-30 10:49:50 -04001544
khenaidoo820197c2020-02-13 16:35:33 -05001545// GetDeviceRoutes returns device graph
1546func (agent *LogicalDeviceAgent) GetDeviceRoutes() *route.DeviceRoutes {
1547 return agent.deviceRoutes
khenaidoo19d7b632018-10-30 10:49:50 -04001548}
1549
khenaidoo820197c2020-02-13 16:35:33 -05001550//rebuildRoutes rebuilds the device routes
1551func (agent *LogicalDeviceAgent) buildRoutes(ctx context.Context) error {
khenaidoo80b987d2020-02-20 10:52:52 -05001552 log.Debugw("building-routes", log.Fields{"logical-device-id": agent.logicalDeviceID})
khenaidoo910204f2019-04-08 17:56:40 -04001553 agent.lockLogicalDevice.Lock()
1554 defer agent.lockLogicalDevice.Unlock()
khenaidoo820197c2020-02-13 16:35:33 -05001555 if agent.deviceRoutes == nil {
1556 agent.deviceRoutes = route.NewDeviceRoutes(agent.logicalDeviceID, agent.deviceMgr.GetDevice)
khenaidoo2c6a0992019-04-29 13:46:56 -04001557 }
1558 // Get all the logical ports on that logical device
khenaidoo6e55d9e2019-12-12 18:26:26 -05001559 lDevice := agent.getLogicalDeviceWithoutLock()
1560
khenaidoo820197c2020-02-13 16:35:33 -05001561 if err := agent.deviceRoutes.ComputeRoutes(ctx, lDevice.Ports); err != nil {
1562 return err
1563 }
1564 if err := agent.deviceRoutes.Print(); err != nil {
1565 return err
1566 }
1567
khenaidoo2c6a0992019-04-29 13:46:56 -04001568 return nil
khenaidoo19d7b632018-10-30 10:49:50 -04001569}
1570
khenaidoo820197c2020-02-13 16:35:33 -05001571//updateRoutes updates the device routes
1572func (agent *LogicalDeviceAgent) updateRoutes(ctx context.Context, lp *voltha.LogicalPort) error {
1573 log.Debugw("updateRoutes", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo2c6a0992019-04-29 13:46:56 -04001574 agent.lockLogicalDevice.Lock()
1575 defer agent.lockLogicalDevice.Unlock()
khenaidoo820197c2020-02-13 16:35:33 -05001576 if agent.deviceRoutes == nil {
1577 agent.deviceRoutes = route.NewDeviceRoutes(agent.logicalDeviceID, agent.deviceMgr.GetDevice)
khenaidoo910204f2019-04-08 17:56:40 -04001578 }
khenaidoo820197c2020-02-13 16:35:33 -05001579 if err := agent.deviceRoutes.AddPort(ctx, lp, agent.logicalDevice.Ports); err != nil {
1580 return err
khenaidoo0a822f92019-05-08 15:15:57 -04001581 }
khenaidoo820197c2020-02-13 16:35:33 -05001582 if err := agent.deviceRoutes.Print(); err != nil {
1583 return err
1584 }
1585 return nil
khenaidoo0a822f92019-05-08 15:15:57 -04001586}
1587
khenaidoofc1314d2019-03-14 09:34:21 -04001588// 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 -04001589func diff(oldList, newList []*voltha.LogicalPort) (newPorts, changedPorts, deletedPorts []*voltha.LogicalPort) {
khenaidoofc1314d2019-03-14 09:34:21 -04001590 newPorts = make([]*voltha.LogicalPort, 0)
1591 changedPorts = make([]*voltha.LogicalPort, 0)
1592 deletedPorts = make([]*voltha.LogicalPort, 0)
1593 for _, o := range oldList {
1594 found := false
khenaidoofc1314d2019-03-14 09:34:21 -04001595 for _, n := range newList {
1596 if o.Id == n.Id {
khenaidoofc1314d2019-03-14 09:34:21 -04001597 found = true
1598 break
1599 }
1600 }
1601 if !found {
1602 deletedPorts = append(deletedPorts, o)
1603 }
khenaidoofc1314d2019-03-14 09:34:21 -04001604 }
1605 for _, n := range newList {
1606 found := false
khenaidoo2bc48282019-07-16 18:13:46 -04001607 changed := false
khenaidoofc1314d2019-03-14 09:34:21 -04001608 for _, o := range oldList {
1609 if o.Id == n.Id {
khenaidoo2bc48282019-07-16 18:13:46 -04001610 changed = !reflect.DeepEqual(o, n)
khenaidoofc1314d2019-03-14 09:34:21 -04001611 found = true
1612 break
1613 }
1614 }
1615 if !found {
1616 newPorts = append(newPorts, n)
1617 }
khenaidoo2bc48282019-07-16 18:13:46 -04001618 if changed {
1619 changedPorts = append(changedPorts, n)
1620 }
khenaidoofc1314d2019-03-14 09:34:21 -04001621 }
1622 return
1623}
1624
1625// portUpdated is invoked when a port is updated on the logical device. Until
1626// the POST_ADD notification is fixed, we will use the logical device to
1627// update that data.
npujar467fe752020-01-16 20:17:45 +05301628func (agent *LogicalDeviceAgent) portUpdated(ctx context.Context, args ...interface{}) interface{} {
khenaidoofc1314d2019-03-14 09:34:21 -04001629 log.Debugw("portUpdated-callback", log.Fields{"argsLen": len(args)})
1630
1631 var oldLD *voltha.LogicalDevice
1632 var newlD *voltha.LogicalDevice
1633
1634 var ok bool
1635 if oldLD, ok = args[0].(*voltha.LogicalDevice); !ok {
1636 log.Errorw("invalid-args", log.Fields{"args0": args[0]})
1637 return nil
1638 }
1639 if newlD, ok = args[1].(*voltha.LogicalDevice); !ok {
1640 log.Errorw("invalid-args", log.Fields{"args1": args[1]})
1641 return nil
1642 }
1643
1644 if reflect.DeepEqual(oldLD.Ports, newlD.Ports) {
1645 log.Debug("ports-have-not-changed")
1646 return nil
1647 }
1648
1649 // Get the difference between the two list
1650 newPorts, changedPorts, deletedPorts := diff(oldLD.Ports, newlD.Ports)
1651
1652 // Send the port change events to the OF controller
khenaidoo2c6a0992019-04-29 13:46:56 -04001653 for _, newP := range newPorts {
npujar1d86a522019-11-14 17:11:16 +05301654 go agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceID,
khenaidoo2c6a0992019-04-29 13:46:56 -04001655 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_ADD, Desc: newP.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001656 }
1657 for _, change := range changedPorts {
npujar1d86a522019-11-14 17:11:16 +05301658 go agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceID,
khenaidoo910204f2019-04-08 17:56:40 -04001659 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_MODIFY, Desc: change.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001660 }
1661 for _, del := range deletedPorts {
npujar1d86a522019-11-14 17:11:16 +05301662 go agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceID,
khenaidoo910204f2019-04-08 17:56:40 -04001663 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_DELETE, Desc: del.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001664 }
1665
1666 return nil
1667}
1668
khenaidoo8f474192019-04-03 17:20:44 -04001669// addNNILogicalPort adds an NNI port to the logical device. It returns a bool representing whether a port has been
1670// added and an eror in case a valid error is encountered. If the port was successfully added it will return
1671// (true, nil). If the device is not in the correct state it will return (false, nil) as this is a valid
1672// scenario. This also applies to the case where the port was already added.
npujar467fe752020-01-16 20:17:45 +05301673func (agent *LogicalDeviceAgent) addNNILogicalPort(ctx context.Context, device *voltha.Device, port *voltha.Port) (bool, error) {
khenaidoo1ce37ad2019-03-24 22:07:24 -04001674 log.Debugw("addNNILogicalPort", log.Fields{"NNI": port})
khenaidoo8f474192019-04-03 17:20:44 -04001675 if device.AdminState != voltha.AdminState_ENABLED || device.OperStatus != voltha.OperStatus_ACTIVE {
1676 log.Infow("device-not-ready", log.Fields{"deviceId": device.Id, "admin": device.AdminState, "oper": device.OperStatus})
1677 return false, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001678 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001679 agent.lockLogicalDevice.RLock()
1680 if agent.portExist(device, port) {
1681 log.Debugw("port-already-exist", log.Fields{"port": port})
1682 agent.lockLogicalDevice.RUnlock()
khenaidoo8f474192019-04-03 17:20:44 -04001683 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001684 }
1685 agent.lockLogicalDevice.RUnlock()
1686
khenaidoofc1314d2019-03-14 09:34:21 -04001687 var portCap *ic.PortCapability
1688 var err error
1689 // First get the port capability
npujar467fe752020-01-16 20:17:45 +05301690 if portCap, err = agent.deviceMgr.getPortCapability(ctx, device.Id, port.PortNo); err != nil {
khenaidoofc1314d2019-03-14 09:34:21 -04001691 log.Errorw("error-retrieving-port-capabilities", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001692 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001693 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001694
1695 agent.lockLogicalDevice.Lock()
1696 defer agent.lockLogicalDevice.Unlock()
1697 // Double check again if this port has been already added since the getPortCapability could have taken a long time
1698 if agent.portExist(device, port) {
1699 log.Debugw("port-already-exist", log.Fields{"port": port})
khenaidoo8f474192019-04-03 17:20:44 -04001700 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001701 }
1702
khenaidoofc1314d2019-03-14 09:34:21 -04001703 portCap.Port.RootPort = true
1704 lp := (proto.Clone(portCap.Port)).(*voltha.LogicalPort)
1705 lp.DeviceId = device.Id
1706 lp.Id = fmt.Sprintf("nni-%d", port.PortNo)
1707 lp.OfpPort.PortNo = port.PortNo
1708 lp.OfpPort.Name = lp.Id
1709 lp.DevicePortNo = port.PortNo
1710
khenaidoo6e55d9e2019-12-12 18:26:26 -05001711 ld := agent.getLogicalDeviceWithoutLock()
1712
khenaidoofc1314d2019-03-14 09:34:21 -04001713 cloned := (proto.Clone(ld)).(*voltha.LogicalDevice)
1714 if cloned.Ports == nil {
1715 cloned.Ports = make([]*voltha.LogicalPort, 0)
1716 }
1717 cloned.Ports = append(cloned.Ports, lp)
1718
npujar467fe752020-01-16 20:17:45 +05301719 if err = agent.updateLogicalDeviceWithoutLock(ctx, cloned); err != nil {
khenaidoofc1314d2019-03-14 09:34:21 -04001720 log.Errorw("error-updating-logical-device", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001721 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001722 }
khenaidoo910204f2019-04-08 17:56:40 -04001723
khenaidoo820197c2020-02-13 16:35:33 -05001724 // Update the device routes with this new logical port
khenaidoo910204f2019-04-08 17:56:40 -04001725 clonedLP := (proto.Clone(lp)).(*voltha.LogicalPort)
khenaidoo820197c2020-02-13 16:35:33 -05001726 go func() {
1727 if err := agent.updateRoutes(context.Background(), clonedLP); err != nil {
1728 log.Warn("routes-not-ready", log.Fields{"logical-device-id": agent.logicalDeviceID, "logical-port": lp.OfpPort.PortNo, "error": err})
1729 }
1730 }()
khenaidoo910204f2019-04-08 17:56:40 -04001731
khenaidoo8f474192019-04-03 17:20:44 -04001732 return true, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001733}
1734
khenaidoo910204f2019-04-08 17:56:40 -04001735func (agent *LogicalDeviceAgent) portExist(device *voltha.Device, port *voltha.Port) bool {
khenaidoo6e55d9e2019-12-12 18:26:26 -05001736 ldevice := agent.getLogicalDeviceWithoutLock()
1737 for _, lPort := range ldevice.Ports {
1738 if lPort.DeviceId == device.Id && lPort.DevicePortNo == port.PortNo && lPort.Id == port.Label {
1739 return true
khenaidoofc1314d2019-03-14 09:34:21 -04001740 }
1741 }
1742 return false
1743}
1744
khenaidoo8f474192019-04-03 17:20:44 -04001745// addUNILogicalPort adds an UNI port to the logical device. It returns a bool representing whether a port has been
1746// added and an eror in case a valid error is encountered. If the port was successfully added it will return
1747// (true, nil). If the device is not in the correct state it will return (false, nil) as this is a valid
1748// scenario. This also applies to the case where the port was already added.
npujar467fe752020-01-16 20:17:45 +05301749func (agent *LogicalDeviceAgent) addUNILogicalPort(ctx context.Context, childDevice *voltha.Device, port *voltha.Port) (bool, error) {
khenaidoofc1314d2019-03-14 09:34:21 -04001750 log.Debugw("addUNILogicalPort", log.Fields{"port": port})
khenaidoo8f474192019-04-03 17:20:44 -04001751 if childDevice.AdminState != voltha.AdminState_ENABLED || childDevice.OperStatus != voltha.OperStatus_ACTIVE {
1752 log.Infow("device-not-ready", log.Fields{"deviceId": childDevice.Id, "admin": childDevice.AdminState, "oper": childDevice.OperStatus})
1753 return false, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001754 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001755 agent.lockLogicalDevice.RLock()
1756 if agent.portExist(childDevice, port) {
1757 log.Debugw("port-already-exist", log.Fields{"port": port})
1758 agent.lockLogicalDevice.RUnlock()
khenaidoo8f474192019-04-03 17:20:44 -04001759 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001760 }
1761 agent.lockLogicalDevice.RUnlock()
khenaidoofc1314d2019-03-14 09:34:21 -04001762 var portCap *ic.PortCapability
1763 var err error
1764 // First get the port capability
npujar467fe752020-01-16 20:17:45 +05301765 if portCap, err = agent.deviceMgr.getPortCapability(ctx, childDevice.Id, port.PortNo); err != nil {
khenaidoofc1314d2019-03-14 09:34:21 -04001766 log.Errorw("error-retrieving-port-capabilities", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001767 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001768 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001769 agent.lockLogicalDevice.Lock()
1770 defer agent.lockLogicalDevice.Unlock()
1771 // Double check again if this port has been already added since the getPortCapability could have taken a long time
1772 if agent.portExist(childDevice, port) {
1773 log.Debugw("port-already-exist", log.Fields{"port": port})
khenaidoo8f474192019-04-03 17:20:44 -04001774 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001775 }
khenaidoofc1314d2019-03-14 09:34:21 -04001776 // Get stored logical device
khenaidoo6e55d9e2019-12-12 18:26:26 -05001777 ldevice := agent.getLogicalDeviceWithoutLock()
1778
npujar1d86a522019-11-14 17:11:16 +05301779 log.Debugw("adding-uni", log.Fields{"deviceId": childDevice.Id})
1780 portCap.Port.RootPort = false
1781 portCap.Port.Id = port.Label
1782 portCap.Port.OfpPort.PortNo = port.PortNo
1783 portCap.Port.DeviceId = childDevice.Id
1784 portCap.Port.DevicePortNo = port.PortNo
1785 cloned := (proto.Clone(ldevice)).(*voltha.LogicalDevice)
1786 if cloned.Ports == nil {
1787 cloned.Ports = make([]*voltha.LogicalPort, 0)
1788 }
1789 cloned.Ports = append(cloned.Ports, portCap.Port)
npujar467fe752020-01-16 20:17:45 +05301790 if err := agent.updateLogicalDeviceWithoutLock(ctx, cloned); err != nil {
npujar1d86a522019-11-14 17:11:16 +05301791 return false, err
1792 }
1793 // Update the device graph with this new logical port
1794 clonedLP := (proto.Clone(portCap.Port)).(*voltha.LogicalPort)
khenaidoo820197c2020-02-13 16:35:33 -05001795
1796 go func() {
1797 if err := agent.updateRoutes(context.Background(), clonedLP); err != nil {
1798 log.Warn("routes-not-ready", log.Fields{"logical-device-id": agent.logicalDeviceID, "error": err})
1799 }
1800 }()
1801
npujar1d86a522019-11-14 17:11:16 +05301802 return true, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001803}
1804
npujar467fe752020-01-16 20:17:45 +05301805func (agent *LogicalDeviceAgent) packetOut(ctx context.Context, packet *ofp.OfpPacketOut) {
Matteo Scandolo360605d2019-11-05 18:29:17 -08001806 log.Debugw("packet-out", log.Fields{
1807 "packet": hex.EncodeToString(packet.Data),
1808 "inPort": packet.GetInPort(),
1809 })
khenaidoo68c930b2019-05-13 11:46:51 -04001810 outPort := fu.GetPacketOutPort(packet)
khenaidoofdbad6e2018-11-06 22:26:38 -05001811 //frame := packet.GetData()
1812 //TODO: Use a channel between the logical agent and the device agent
npujar467fe752020-01-16 20:17:45 +05301813 if err := agent.deviceMgr.packetOut(ctx, agent.rootDeviceID, outPort, packet); err != nil {
npujar1d86a522019-11-14 17:11:16 +05301814 log.Error("packetout-failed", log.Fields{"logicalDeviceID": agent.rootDeviceID})
khenaidooca301322019-01-09 23:06:32 -05001815 }
khenaidoofdbad6e2018-11-06 22:26:38 -05001816}
1817
npujar1d86a522019-11-14 17:11:16 +05301818func (agent *LogicalDeviceAgent) packetIn(port uint32, transactionID string, packet []byte) {
Matteo Scandolo360605d2019-11-05 18:29:17 -08001819 log.Debugw("packet-in", log.Fields{
1820 "port": port,
1821 "packet": hex.EncodeToString(packet),
npujar1d86a522019-11-14 17:11:16 +05301822 "transactionId": transactionID,
Matteo Scandolo360605d2019-11-05 18:29:17 -08001823 })
khenaidoo68c930b2019-05-13 11:46:51 -04001824 packetIn := fu.MkPacketIn(port, packet)
npujar1d86a522019-11-14 17:11:16 +05301825 agent.ldeviceMgr.grpcNbiHdlr.sendPacketIn(agent.logicalDeviceID, transactionID, packetIn)
Matteo Scandolo360605d2019-11-05 18:29:17 -08001826 log.Debugw("sending-packet-in", log.Fields{"packet": hex.EncodeToString(packetIn.Data)})
khenaidoofdbad6e2018-11-06 22:26:38 -05001827}
khenaidoo2c6a0992019-04-29 13:46:56 -04001828
1829func (agent *LogicalDeviceAgent) addLogicalPortToMap(portNo uint32, nniPort bool) {
1830 agent.lockLogicalPortsNo.Lock()
1831 defer agent.lockLogicalPortsNo.Unlock()
1832 if exist := agent.logicalPortsNo[portNo]; !exist {
1833 agent.logicalPortsNo[portNo] = nniPort
1834 }
1835}
1836
khenaidoo820197c2020-02-13 16:35:33 -05001837func (agent *LogicalDeviceAgent) deleteLogicalPortsFromMap(portsNo []uint32) {
1838 agent.lockLogicalPortsNo.Lock()
1839 defer agent.lockLogicalPortsNo.Unlock()
1840 for _, pNo := range portsNo {
1841 delete(agent.logicalPortsNo, pNo)
1842 }
1843}
1844
khenaidoo3d3b8c22019-05-22 18:10:39 -04001845func (agent *LogicalDeviceAgent) addLogicalPortsToMap(lps []*voltha.LogicalPort) {
1846 agent.lockLogicalPortsNo.Lock()
1847 defer agent.lockLogicalPortsNo.Unlock()
1848 for _, lp := range lps {
1849 if exist := agent.logicalPortsNo[lp.DevicePortNo]; !exist {
1850 agent.logicalPortsNo[lp.DevicePortNo] = lp.RootPort
1851 }
1852 }
1853}
1854
khenaidoo2c6a0992019-04-29 13:46:56 -04001855func (agent *LogicalDeviceAgent) isNNIPort(portNo uint32) bool {
1856 agent.lockLogicalPortsNo.RLock()
1857 defer agent.lockLogicalPortsNo.RUnlock()
1858 if exist := agent.logicalPortsNo[portNo]; exist {
1859 return agent.logicalPortsNo[portNo]
1860 }
1861 return false
1862}
1863
1864func (agent *LogicalDeviceAgent) getFirstNNIPort() (uint32, error) {
1865 agent.lockLogicalPortsNo.RLock()
1866 defer agent.lockLogicalPortsNo.RUnlock()
1867 for portNo, nni := range agent.logicalPortsNo {
1868 if nni {
1869 return portNo, nil
1870 }
1871 }
1872 return 0, status.Error(codes.NotFound, "No NNI port found")
1873}
Esin Karaman09959ae2019-11-29 13:59:58 +00001874
1875//GetNNIPorts returns NNI ports.
1876func (agent *LogicalDeviceAgent) GetNNIPorts() []uint32 {
1877 agent.lockLogicalPortsNo.RLock()
1878 defer agent.lockLogicalPortsNo.RUnlock()
1879 nniPorts := make([]uint32, 0)
1880 for portNo, nni := range agent.logicalPortsNo {
1881 if nni {
1882 nniPorts = append(nniPorts, portNo)
1883 }
1884 }
1885 return nniPorts
1886}