blob: 261654084e7709b9cea5b7b34160205b6fda9283 [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"
David Bainbridged1afd662020-03-26 18:27:41 -070024 "reflect"
25 "sync"
26 "time"
27
khenaidoob9203542018-09-17 22:56:37 -040028 "github.com/gogo/protobuf/proto"
sbarbari17d7e222019-11-05 10:02:29 -050029 "github.com/opencord/voltha-go/db/model"
npujar1d86a522019-11-14 17:11:16 +053030 fd "github.com/opencord/voltha-go/rw_core/flowdecomposition"
khenaidoo442e7c72020-03-10 16:13:48 -040031 "github.com/opencord/voltha-go/rw_core/route"
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"
khenaidoo442e7c72020-03-10 16:13:48 -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
David Bainbridged1afd662020-03-26 18:27:41 -070045 serialNumber string
npujar1d86a522019-11-14 17:11:16 +053046 rootDeviceID string
khenaidoo3306c992019-05-24 16:57:35 -040047 deviceMgr *DeviceManager
48 ldeviceMgr *LogicalDeviceManager
49 clusterDataProxy *model.Proxy
50 exitChannel chan int
khenaidoo820197c2020-02-13 16:35:33 -050051 deviceRoutes *route.DeviceRoutes
khenaidoo820197c2020-02-13 16:35:33 -050052 lockDeviceRoutes sync.RWMutex
khenaidoo3306c992019-05-24 16:57:35 -040053 logicalPortsNo map[uint32]bool //value is true for NNI port
54 lockLogicalPortsNo sync.RWMutex
55 flowDecomposer *fd.FlowDecomposer
khenaidoo442e7c72020-03-10 16:13:48 -040056 defaultTimeout time.Duration
khenaidoo6e55d9e2019-12-12 18:26:26 -050057 logicalDevice *voltha.LogicalDevice
khenaidoo442e7c72020-03-10 16:13:48 -040058 requestQueue *coreutils.RequestQueue
59 startOnce sync.Once
60 stopOnce sync.Once
khenaidoob9203542018-09-17 22:56:37 -040061}
62
David Bainbridged1afd662020-03-26 18:27:41 -070063func newLogicalDeviceAgent(id string, sn string, deviceID string, ldeviceMgr *LogicalDeviceManager,
64 deviceMgr *DeviceManager, cdProxy *model.Proxy, timeout time.Duration) *LogicalDeviceAgent {
khenaidoob9203542018-09-17 22:56:37 -040065 var agent LogicalDeviceAgent
66 agent.exitChannel = make(chan int, 1)
npujar1d86a522019-11-14 17:11:16 +053067 agent.logicalDeviceID = id
David Bainbridged1afd662020-03-26 18:27:41 -070068 agent.serialNumber = sn
npujar1d86a522019-11-14 17:11:16 +053069 agent.rootDeviceID = deviceID
khenaidoob9203542018-09-17 22:56:37 -040070 agent.deviceMgr = deviceMgr
khenaidoo9a468962018-09-19 15:33:13 -040071 agent.clusterDataProxy = cdProxy
khenaidoob9203542018-09-17 22:56:37 -040072 agent.ldeviceMgr = ldeviceMgr
khenaidoo19d7b632018-10-30 10:49:50 -040073 agent.flowDecomposer = fd.NewFlowDecomposer(agent.deviceMgr)
khenaidoo2c6a0992019-04-29 13:46:56 -040074 agent.logicalPortsNo = make(map[uint32]bool)
khenaidoo2c6a0992019-04-29 13:46:56 -040075 agent.defaultTimeout = timeout
Kent Hagerman730cbdf2020-03-31 12:22:08 -040076 agent.requestQueue = coreutils.NewRequestQueue()
khenaidoob9203542018-09-17 22:56:37 -040077 return &agent
78}
79
khenaidoo4d4802d2018-10-04 21:59:49 -040080// start creates the logical device and add it to the data model
khenaidoo442e7c72020-03-10 16:13:48 -040081func (agent *LogicalDeviceAgent) start(ctx context.Context, loadFromDB bool) error {
82 needToStart := false
83 if agent.startOnce.Do(func() { needToStart = true }); !needToStart {
84 return nil
85 }
86
Girish Kumarf56a4682020-03-20 20:07:46 +000087 logger.Infow("starting-logical_device-agent", log.Fields{"logical-device-id": agent.logicalDeviceID, "load-from-db": loadFromDB})
khenaidoo442e7c72020-03-10 16:13:48 -040088
89 var startSucceeded bool
90 defer func() {
91 if !startSucceeded {
92 if err := agent.stop(ctx); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +000093 logger.Errorw("failed-to-cleanup-after-unsuccessful-start", log.Fields{"logical-device-id": agent.logicalDeviceID, "error": err})
khenaidoo442e7c72020-03-10 16:13:48 -040094 }
95 }
96 }()
97
khenaidoo297cd252019-02-07 22:10:23 -050098 var ld *voltha.LogicalDevice
khenaidoo442e7c72020-03-10 16:13:48 -040099 if !loadFromDB {
khenaidoo7e3d8f12019-08-02 16:06:30 -0400100 //Build the logical device based on information retrieved from the device adapter
101 var switchCap *ic.SwitchCapability
khenaidoo297cd252019-02-07 22:10:23 -0500102 var err error
npujar1d86a522019-11-14 17:11:16 +0530103 if switchCap, err = agent.deviceMgr.getSwitchCapability(ctx, agent.rootDeviceID); err != nil {
khenaidoo7e3d8f12019-08-02 16:06:30 -0400104 return err
105 }
npujar1d86a522019-11-14 17:11:16 +0530106 ld = &voltha.LogicalDevice{Id: agent.logicalDeviceID, RootDeviceId: agent.rootDeviceID}
khenaidoo297cd252019-02-07 22:10:23 -0500107
108 // Create the datapath ID (uint64) using the logical device ID (based on the MAC Address)
109 var datapathID uint64
David Bainbridged1afd662020-03-26 18:27:41 -0700110 if datapathID, err = CreateDataPathID(agent.serialNumber); err != nil {
khenaidoo297cd252019-02-07 22:10:23 -0500111 return err
112 }
113 ld.DatapathId = datapathID
khenaidoo7e3d8f12019-08-02 16:06:30 -0400114 ld.Desc = (proto.Clone(switchCap.Desc)).(*ofp.OfpDesc)
Girish Kumarf56a4682020-03-20 20:07:46 +0000115 logger.Debugw("Switch-capability", log.Fields{"Desc": ld.Desc, "fromAd": switchCap.Desc})
khenaidoo7e3d8f12019-08-02 16:06:30 -0400116 ld.SwitchFeatures = (proto.Clone(switchCap.SwitchFeatures)).(*ofp.OfpSwitchFeatures)
khenaidoo297cd252019-02-07 22:10:23 -0500117 ld.Flows = &ofp.Flows{Items: nil}
118 ld.FlowGroups = &ofp.FlowGroups{Items: nil}
khenaidoo49085352020-01-13 19:15:43 -0500119 ld.Ports = []*voltha.LogicalPort{}
khenaidoo297cd252019-02-07 22:10:23 -0500120
khenaidoo297cd252019-02-07 22:10:23 -0500121 // Save the logical device
Thomas Lee Se5a44012019-11-07 20:32:24 +0530122 added, err := agent.clusterDataProxy.AddWithID(ctx, "/logical_devices", ld.Id, ld, "")
123 if err != nil {
Thomas Lee Se5a44012019-11-07 20:32:24 +0530124 return err
125 }
126 if added == nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000127 logger.Errorw("failed-to-add-logical-device", log.Fields{"logical-device-id": agent.logicalDeviceID})
khenaidoo297cd252019-02-07 22:10:23 -0500128 } else {
Girish Kumarf56a4682020-03-20 20:07:46 +0000129 logger.Debugw("logicaldevice-created", log.Fields{"logical-device-id": agent.logicalDeviceID, "root-id": ld.RootDeviceId})
khenaidoo297cd252019-02-07 22:10:23 -0500130 }
khenaidoo6e55d9e2019-12-12 18:26:26 -0500131
132 agent.logicalDevice = proto.Clone(ld).(*voltha.LogicalDevice)
khenaidoofc1314d2019-03-14 09:34:21 -0400133
khenaidoo442e7c72020-03-10 16:13:48 -0400134 // Setup the logicalports - internal processing, no need to propagate the client context
npujar1d86a522019-11-14 17:11:16 +0530135 go func() {
khenaidoo442e7c72020-03-10 16:13:48 -0400136 err := agent.setupLogicalPorts(context.Background())
npujar1d86a522019-11-14 17:11:16 +0530137 if err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000138 logger.Errorw("unable-to-setup-logical-ports", log.Fields{"error": err})
npujar1d86a522019-11-14 17:11:16 +0530139 }
140 }()
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.
npujar467fe752020-01-16 20:17:45 +0530144 logicalDevice, err := agent.clusterDataProxy.Get(ctx, "/logical_devices/"+agent.logicalDeviceID, 0, true, "")
Thomas Lee Se5a44012019-11-07 20:32:24 +0530145 if err != nil {
khenaidoo442e7c72020-03-10 16:13:48 -0400146 return err
Thomas Lee Se5a44012019-11-07 20:32:24 +0530147 }
khenaidoo6e55d9e2019-12-12 18:26:26 -0500148 ld, ok := logicalDevice.(*voltha.LogicalDevice)
149 if !ok {
khenaidoo6e55d9e2019-12-12 18:26:26 -0500150 return status.Errorf(codes.NotFound, "logical_device-%s", agent.logicalDeviceID)
khenaidoo297cd252019-02-07 22:10:23 -0500151 }
khenaidoo8c3303d2019-02-13 14:59:39 -0500152 // Update the root device Id
npujar1d86a522019-11-14 17:11:16 +0530153 agent.rootDeviceID = ld.RootDeviceId
khenaidoo3d3b8c22019-05-22 18:10:39 -0400154
khenaidoo6e55d9e2019-12-12 18:26:26 -0500155 // Update the last data
156 agent.logicalDevice = proto.Clone(ld).(*voltha.LogicalDevice)
157
khenaidoo3d3b8c22019-05-22 18:10:39 -0400158 // Setup the local list of logical ports
159 agent.addLogicalPortsToMap(ld.Ports)
khenaidoob9203542018-09-17 22:56:37 -0400160 }
khenaidoofc1314d2019-03-14 09:34:21 -0400161
khenaidoo820197c2020-02-13 16:35:33 -0500162 // Setup the device routes. Building routes may fail if the pre-conditions are not satisfied (e.g. no PON ports present)
khenaidoo442e7c72020-03-10 16:13:48 -0400163 if loadFromDB {
khenaidoo820197c2020-02-13 16:35:33 -0500164 go func() {
165 if err := agent.buildRoutes(context.Background()); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000166 logger.Warn("routes-not-ready", log.Fields{"logical-device-id": agent.logicalDeviceID, "error": err})
khenaidoo820197c2020-02-13 16:35:33 -0500167 }
168 }()
khenaidoo4c9e5592019-09-09 16:20:41 -0400169 }
khenaidoo442e7c72020-03-10 16:13:48 -0400170 startSucceeded = true
171
khenaidoob9203542018-09-17 22:56:37 -0400172 return nil
173}
174
khenaidoo442e7c72020-03-10 16:13:48 -0400175// stop stops the logical device agent. This removes the logical device from the data model.
Thomas Lee Se5a44012019-11-07 20:32:24 +0530176func (agent *LogicalDeviceAgent) stop(ctx context.Context) error {
khenaidoo442e7c72020-03-10 16:13:48 -0400177 var returnErr error
178 agent.stopOnce.Do(func() {
Girish Kumarf56a4682020-03-20 20:07:46 +0000179 logger.Info("stopping-logical_device-agent")
khenaidoo8c3303d2019-02-13 14:59:39 -0500180
khenaidoo442e7c72020-03-10 16:13:48 -0400181 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
182 // This should never happen - an error is returned only if the agent is stopped and an agent is only stopped once.
183 returnErr = err
184 return
185 }
186 defer agent.requestQueue.RequestComplete()
187
188 //Remove the logical device from the model
189 if removed, err := agent.clusterDataProxy.Remove(ctx, "/logical_devices/"+agent.logicalDeviceID, ""); err != nil {
190 returnErr = err
191 } else if removed == nil {
192 returnErr = status.Errorf(codes.Aborted, "failed-to-remove-logical-ldevice-%s", agent.logicalDeviceID)
193 } else {
Girish Kumarf56a4682020-03-20 20:07:46 +0000194 logger.Debugw("logicaldevice-removed", log.Fields{"logicaldeviceId": agent.logicalDeviceID})
khenaidoo442e7c72020-03-10 16:13:48 -0400195 }
196
khenaidoo442e7c72020-03-10 16:13:48 -0400197 close(agent.exitChannel)
198
Girish Kumarf56a4682020-03-20 20:07:46 +0000199 logger.Info("logical_device-agent-stopped")
khenaidoo442e7c72020-03-10 16:13:48 -0400200 })
201 return returnErr
khenaidoo4d4802d2018-10-04 21:59:49 -0400202}
203
khenaidoo6e55d9e2019-12-12 18:26:26 -0500204// GetLogicalDevice returns the latest logical device data
khenaidoo442e7c72020-03-10 16:13:48 -0400205func (agent *LogicalDeviceAgent) GetLogicalDevice(ctx context.Context) (*voltha.LogicalDevice, error) {
206 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
207 return nil, err
208 }
209 defer agent.requestQueue.RequestComplete()
210 return proto.Clone(agent.logicalDevice).(*voltha.LogicalDevice), nil
khenaidoo92e62c52018-10-03 14:02:54 -0400211}
212
npujar1d86a522019-11-14 17:11:16 +0530213// ListLogicalDeviceFlows returns logical device flows
khenaidoo442e7c72020-03-10 16:13:48 -0400214func (agent *LogicalDeviceAgent) ListLogicalDeviceFlows(ctx context.Context) (*ofp.Flows, error) {
Girish Kumarf56a4682020-03-20 20:07:46 +0000215 logger.Debug("ListLogicalDeviceFlows")
khenaidoo6e55d9e2019-12-12 18:26:26 -0500216
khenaidoo442e7c72020-03-10 16:13:48 -0400217 logicalDevice, err := agent.GetLogicalDevice(ctx)
218 if err != nil {
219 return nil, err
khenaidoodd237172019-05-27 16:37:17 -0400220 }
khenaidoo442e7c72020-03-10 16:13:48 -0400221 if logicalDevice.Flows == nil {
222 return &ofp.Flows{}, nil
223 }
224 return (proto.Clone(logicalDevice.Flows)).(*ofp.Flows), nil
khenaidoodd237172019-05-27 16:37:17 -0400225}
226
npujar1d86a522019-11-14 17:11:16 +0530227// ListLogicalDeviceMeters returns logical device meters
khenaidoo442e7c72020-03-10 16:13:48 -0400228func (agent *LogicalDeviceAgent) ListLogicalDeviceMeters(ctx context.Context) (*ofp.Meters, error) {
Girish Kumarf56a4682020-03-20 20:07:46 +0000229 logger.Debug("ListLogicalDeviceMeters")
khenaidoo6e55d9e2019-12-12 18:26:26 -0500230
khenaidoo442e7c72020-03-10 16:13:48 -0400231 logicalDevice, err := agent.GetLogicalDevice(ctx)
232 if err != nil {
233 return nil, err
Manikkaraj kb1a10922019-07-29 12:10:34 -0400234 }
khenaidoo442e7c72020-03-10 16:13:48 -0400235 if logicalDevice.Meters == nil {
236 return &ofp.Meters{}, nil
237 }
238 return (proto.Clone(logicalDevice.Meters)).(*ofp.Meters), nil
Manikkaraj kb1a10922019-07-29 12:10:34 -0400239}
240
npujar1d86a522019-11-14 17:11:16 +0530241// ListLogicalDeviceFlowGroups returns logical device flow groups
khenaidoo442e7c72020-03-10 16:13:48 -0400242func (agent *LogicalDeviceAgent) ListLogicalDeviceFlowGroups(ctx context.Context) (*ofp.FlowGroups, error) {
Girish Kumarf56a4682020-03-20 20:07:46 +0000243 logger.Debug("ListLogicalDeviceFlowGroups")
khenaidoo6e55d9e2019-12-12 18:26:26 -0500244
khenaidoo442e7c72020-03-10 16:13:48 -0400245 logicalDevice, err := agent.GetLogicalDevice(ctx)
246 if err != nil {
247 return nil, err
khenaidoodd237172019-05-27 16:37:17 -0400248 }
khenaidoo442e7c72020-03-10 16:13:48 -0400249 if logicalDevice.FlowGroups == nil {
250 return &ofp.FlowGroups{}, nil
251 }
252 return (proto.Clone(logicalDevice.FlowGroups)).(*ofp.FlowGroups), nil
khenaidoodd237172019-05-27 16:37:17 -0400253}
254
npujar1d86a522019-11-14 17:11:16 +0530255// ListLogicalDevicePorts returns logical device ports
khenaidoo442e7c72020-03-10 16:13:48 -0400256func (agent *LogicalDeviceAgent) ListLogicalDevicePorts(ctx context.Context) (*voltha.LogicalPorts, error) {
Girish Kumarf56a4682020-03-20 20:07:46 +0000257 logger.Debug("ListLogicalDevicePorts")
khenaidoo442e7c72020-03-10 16:13:48 -0400258 logicalDevice, err := agent.GetLogicalDevice(ctx)
259 if err != nil {
260 return nil, err
261 }
262 if logicalDevice == nil {
263 return &voltha.LogicalPorts{}, nil
264 }
khenaidoo6e55d9e2019-12-12 18:26:26 -0500265 lPorts := make([]*voltha.LogicalPort, 0)
266 lPorts = append(lPorts, logicalDevice.Ports...)
khenaidoo442e7c72020-03-10 16:13:48 -0400267 return &voltha.LogicalPorts{Items: lPorts}, nil
khenaidoo19d7b632018-10-30 10:49:50 -0400268}
269
khenaidoo4c9e5592019-09-09 16:20:41 -0400270//updateLogicalDeviceFlowsWithoutLock updates the logical device with the latest flows in the model.
npujar467fe752020-01-16 20:17:45 +0530271func (agent *LogicalDeviceAgent) updateLogicalDeviceFlowsWithoutLock(ctx context.Context, flows *ofp.Flows) error {
khenaidoo6e55d9e2019-12-12 18:26:26 -0500272 ld := agent.getLogicalDeviceWithoutLock()
khenaidoo4c9e5592019-09-09 16:20:41 -0400273
Girish Kumarf56a4682020-03-20 20:07:46 +0000274 logger.Debugw("logical-device-before", log.Fields{"lports": len(ld.Ports)})
khenaidoo6e55d9e2019-12-12 18:26:26 -0500275 ld.Flows = flows
276
npujar467fe752020-01-16 20:17:45 +0530277 if err := agent.updateLogicalDeviceWithoutLock(ctx, ld); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000278 logger.Errorw("error-updating-logical-device-with-flows", log.Fields{"error": err})
khenaidoo4c9e5592019-09-09 16:20:41 -0400279 return err
khenaidoo43c82122018-11-22 18:38:28 -0500280 }
khenaidoo43c82122018-11-22 18:38:28 -0500281 return nil
282}
283
khenaidoo4c9e5592019-09-09 16:20:41 -0400284//updateLogicalDeviceMetersWithoutLock updates the logical device with the meters info
npujar467fe752020-01-16 20:17:45 +0530285func (agent *LogicalDeviceAgent) updateLogicalDeviceMetersWithoutLock(ctx context.Context, meters *ofp.Meters) error {
khenaidoo6e55d9e2019-12-12 18:26:26 -0500286 ld := agent.getLogicalDeviceWithoutLock()
khenaidoo4c9e5592019-09-09 16:20:41 -0400287
Girish Kumarf56a4682020-03-20 20:07:46 +0000288 logger.Debugw("logical-device-before", log.Fields{"lports": len(ld.Ports)})
khenaidoo6e55d9e2019-12-12 18:26:26 -0500289 ld.Meters = meters
290
npujar467fe752020-01-16 20:17:45 +0530291 if err := agent.updateLogicalDeviceWithoutLock(ctx, ld); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000292 logger.Errorw("error-updating-logical-device-with-meters", log.Fields{"error": err})
khenaidoo4c9e5592019-09-09 16:20:41 -0400293 return err
Manikkaraj kb1a10922019-07-29 12:10:34 -0400294 }
295 return nil
296}
297
khenaidoo4c9e5592019-09-09 16:20:41 -0400298//updateLogicalDeviceFlowGroupsWithoutLock updates the logical device with the flow groups
npujar467fe752020-01-16 20:17:45 +0530299func (agent *LogicalDeviceAgent) updateLogicalDeviceFlowGroupsWithoutLock(ctx context.Context, flowGroups *ofp.FlowGroups) error {
khenaidoo6e55d9e2019-12-12 18:26:26 -0500300 ld := agent.getLogicalDeviceWithoutLock()
khenaidoo4c9e5592019-09-09 16:20:41 -0400301
Girish Kumarf56a4682020-03-20 20:07:46 +0000302 logger.Debugw("logical-device-before", log.Fields{"lports": len(ld.Ports)})
khenaidoo6e55d9e2019-12-12 18:26:26 -0500303 ld.FlowGroups = flowGroups
304
npujar467fe752020-01-16 20:17:45 +0530305 if err := agent.updateLogicalDeviceWithoutLock(ctx, ld); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000306 logger.Errorw("error-updating-logical-device-with-flowgroups", log.Fields{"error": err})
khenaidoo4c9e5592019-09-09 16:20:41 -0400307 return err
khenaidoo43c82122018-11-22 18:38:28 -0500308 }
khenaidoo43c82122018-11-22 18:38:28 -0500309 return nil
310}
311
khenaidoo6e55d9e2019-12-12 18:26:26 -0500312// getLogicalDeviceWithoutLock returns a cloned logical device to a function that already holds the agent lock.
313func (agent *LogicalDeviceAgent) getLogicalDeviceWithoutLock() *voltha.LogicalDevice {
Girish Kumarf56a4682020-03-20 20:07:46 +0000314 logger.Debug("getLogicalDeviceWithoutLock")
khenaidoo6e55d9e2019-12-12 18:26:26 -0500315 return proto.Clone(agent.logicalDevice).(*voltha.LogicalDevice)
khenaidoo92e62c52018-10-03 14:02:54 -0400316}
317
npujar467fe752020-01-16 20:17:45 +0530318func (agent *LogicalDeviceAgent) updateLogicalPort(ctx context.Context, device *voltha.Device, port *voltha.Port) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000319 logger.Debugw("updateLogicalPort", log.Fields{"deviceId": device.Id, "port": port})
khenaidoo2c6a0992019-04-29 13:46:56 -0400320 var err error
321 if port.Type == voltha.Port_ETHERNET_NNI {
npujar467fe752020-01-16 20:17:45 +0530322 if _, err = agent.addNNILogicalPort(ctx, device, port); err != nil {
khenaidoo2c6a0992019-04-29 13:46:56 -0400323 return err
324 }
325 agent.addLogicalPortToMap(port.PortNo, true)
326 } else if port.Type == voltha.Port_ETHERNET_UNI {
npujar467fe752020-01-16 20:17:45 +0530327 if _, err = agent.addUNILogicalPort(ctx, device, port); err != nil {
khenaidoo2c6a0992019-04-29 13:46:56 -0400328 return err
329 }
330 agent.addLogicalPortToMap(port.PortNo, false)
331 } else {
khenaidoo820197c2020-02-13 16:35:33 -0500332 // Update the device routes to ensure all routes on the logical device have been calculated
333 if err = agent.buildRoutes(ctx); err != nil {
334 // Not an error - temporary state
Girish Kumarf56a4682020-03-20 20:07:46 +0000335 logger.Warnw("failed-to-update-routes", log.Fields{"device-id": device.Id, "port": port, "error": err})
khenaidoo2c6a0992019-04-29 13:46:56 -0400336 }
337 }
338 return nil
339}
340
khenaidoo3d3b8c22019-05-22 18:10:39 -0400341// setupLogicalPorts is invoked once the logical device has been created and is ready to get ports
342// added to it. While the logical device was being created we could have received requests to add
343// NNI and UNI ports which were discarded. Now is the time to add them if needed
344func (agent *LogicalDeviceAgent) setupLogicalPorts(ctx context.Context) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000345 logger.Infow("setupLogicalPorts", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo3d3b8c22019-05-22 18:10:39 -0400346 // First add any NNI ports which could have been missing
npujar467fe752020-01-16 20:17:45 +0530347 if err := agent.setupNNILogicalPorts(ctx, agent.rootDeviceID); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000348 logger.Errorw("error-setting-up-NNI-ports", log.Fields{"error": err, "deviceId": agent.rootDeviceID})
khenaidoo3d3b8c22019-05-22 18:10:39 -0400349 return err
350 }
351
352 // Now, set up the UNI ports if needed.
npujar467fe752020-01-16 20:17:45 +0530353 children, err := agent.deviceMgr.getAllChildDevices(ctx, agent.rootDeviceID)
npujar1d86a522019-11-14 17:11:16 +0530354 if err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000355 logger.Errorw("error-getting-child-devices", log.Fields{"error": err, "deviceId": agent.rootDeviceID})
khenaidoo3d3b8c22019-05-22 18:10:39 -0400356 return err
npujar1d86a522019-11-14 17:11:16 +0530357 }
358 responses := make([]coreutils.Response, 0)
359 for _, child := range children.Items {
360 response := coreutils.NewResponse()
361 responses = append(responses, response)
362 go func(child *voltha.Device) {
khenaidoo442e7c72020-03-10 16:13:48 -0400363 if err = agent.setupUNILogicalPorts(context.Background(), child); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000364 logger.Error("setting-up-UNI-ports-failed", log.Fields{"deviceID": child.Id})
npujar1d86a522019-11-14 17:11:16 +0530365 response.Error(status.Errorf(codes.Internal, "UNI-ports-setup-failed: %s", child.Id))
366 }
367 response.Done()
368 }(child)
369 }
370 // Wait for completion
371 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, responses...); res != nil {
372 return status.Errorf(codes.Aborted, "errors-%s", res)
khenaidoo3d3b8c22019-05-22 18:10:39 -0400373 }
374 return nil
375}
376
khenaidoofc1314d2019-03-14 09:34:21 -0400377// setupNNILogicalPorts creates an NNI port on the logical device that represents an NNI interface on a root device
npujar1d86a522019-11-14 17:11:16 +0530378func (agent *LogicalDeviceAgent) setupNNILogicalPorts(ctx context.Context, deviceID string) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000379 logger.Infow("setupNNILogicalPorts-start", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoob9203542018-09-17 22:56:37 -0400380 // Build the logical device based on information retrieved from the device adapter
khenaidoofc1314d2019-03-14 09:34:21 -0400381 var err error
382
383 var device *voltha.Device
npujar467fe752020-01-16 20:17:45 +0530384 if device, err = agent.deviceMgr.GetDevice(ctx, deviceID); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000385 logger.Errorw("error-retrieving-device", log.Fields{"error": err, "deviceId": deviceID})
khenaidoofc1314d2019-03-14 09:34:21 -0400386 return err
387 }
388
389 //Get UNI port number
khenaidoofc1314d2019-03-14 09:34:21 -0400390 for _, port := range device.Ports {
391 if port.Type == voltha.Port_ETHERNET_NNI {
npujar467fe752020-01-16 20:17:45 +0530392 if _, err = agent.addNNILogicalPort(ctx, device, port); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000393 logger.Errorw("error-adding-UNI-port", log.Fields{"error": err})
khenaidoofc1314d2019-03-14 09:34:21 -0400394 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400395 agent.addLogicalPortToMap(port.PortNo, true)
khenaidoofc1314d2019-03-14 09:34:21 -0400396 }
397 }
khenaidoofc1314d2019-03-14 09:34:21 -0400398 return err
399}
400
khenaidoo171b98e2019-10-31 11:48:15 -0400401// updatePortState updates the port state of the device
npujar467fe752020-01-16 20:17:45 +0530402func (agent *LogicalDeviceAgent) updatePortState(ctx context.Context, deviceID string, portNo uint32, operStatus voltha.OperStatus_Types) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000403 logger.Infow("updatePortState-start", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "portNo": portNo, "state": operStatus})
khenaidoo442e7c72020-03-10 16:13:48 -0400404 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
405 return err
406 }
407 defer agent.requestQueue.RequestComplete()
khenaidoo171b98e2019-10-31 11:48:15 -0400408 // Get the latest logical device info
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500409 original := agent.getLogicalDeviceWithoutLock()
410 updatedPorts := clonePorts(original.Ports)
411 for _, port := range updatedPorts {
412 if port.DeviceId == deviceID && port.DevicePortNo == portNo {
npujar1d86a522019-11-14 17:11:16 +0530413 if operStatus == voltha.OperStatus_ACTIVE {
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500414 port.OfpPort.Config = port.OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
415 port.OfpPort.State = uint32(ofp.OfpPortState_OFPPS_LIVE)
npujar1d86a522019-11-14 17:11:16 +0530416 } else {
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500417 port.OfpPort.Config = port.OfpPort.Config | uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
418 port.OfpPort.State = uint32(ofp.OfpPortState_OFPPS_LINK_DOWN)
npujar1d86a522019-11-14 17:11:16 +0530419 }
420 // Update the logical device
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500421 if err := agent.updateLogicalDevicePortsWithoutLock(ctx, original, updatedPorts); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000422 logger.Errorw("error-updating-logical-device", log.Fields{"error": err})
npujar1d86a522019-11-14 17:11:16 +0530423 return err
424 }
425 return nil
426 }
427 }
428 return status.Errorf(codes.NotFound, "port-%d-not-exist", portNo)
khenaidoo171b98e2019-10-31 11:48:15 -0400429}
430
khenaidoo3ab34882019-05-02 21:33:30 -0400431// updatePortsState updates the ports state related to the device
kesavandbc2d1622020-01-21 00:42:01 -0500432func (agent *LogicalDeviceAgent) updatePortsState(ctx context.Context, device *voltha.Device, state voltha.OperStatus_Types) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000433 logger.Infow("updatePortsState-start", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo442e7c72020-03-10 16:13:48 -0400434 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
435 return err
436 }
437 defer agent.requestQueue.RequestComplete()
khenaidoo3ab34882019-05-02 21:33:30 -0400438 // Get the latest logical device info
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500439 original := agent.getLogicalDeviceWithoutLock()
440 updatedPorts := clonePorts(original.Ports)
441 for _, port := range updatedPorts {
442 if port.DeviceId == device.Id {
kesavandbc2d1622020-01-21 00:42:01 -0500443 if state == voltha.OperStatus_ACTIVE {
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500444 port.OfpPort.Config = port.OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
445 port.OfpPort.State = uint32(ofp.OfpPortState_OFPPS_LIVE)
kesavandbc2d1622020-01-21 00:42:01 -0500446 } else {
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500447 port.OfpPort.Config = port.OfpPort.Config | uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
448 port.OfpPort.State = uint32(ofp.OfpPortState_OFPPS_LINK_DOWN)
khenaidoo3ab34882019-05-02 21:33:30 -0400449 }
450 }
npujar1d86a522019-11-14 17:11:16 +0530451 }
452 // Updating the logical device will trigger the poprt change events to be populated to the controller
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500453 if err := agent.updateLogicalDevicePortsWithoutLock(ctx, original, updatedPorts); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000454 logger.Warnw("logical-device-update-failed", log.Fields{"ldeviceId": agent.logicalDeviceID, "error": err})
npujar1d86a522019-11-14 17:11:16 +0530455 return err
khenaidoo3ab34882019-05-02 21:33:30 -0400456 }
457 return nil
458}
459
khenaidoofc1314d2019-03-14 09:34:21 -0400460// setupUNILogicalPorts creates a UNI port on the logical device that represents a child UNI interface
461func (agent *LogicalDeviceAgent) setupUNILogicalPorts(ctx context.Context, childDevice *voltha.Device) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000462 logger.Infow("setupUNILogicalPort", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoofc1314d2019-03-14 09:34:21 -0400463 // Build the logical device based on information retrieved from the device adapter
khenaidoob9203542018-09-17 22:56:37 -0400464 var err error
khenaidoo59ef7be2019-06-21 12:40:28 -0400465 var added bool
khenaidoo19d7b632018-10-30 10:49:50 -0400466 //Get UNI port number
khenaidoo19d7b632018-10-30 10:49:50 -0400467 for _, port := range childDevice.Ports {
468 if port.Type == voltha.Port_ETHERNET_UNI {
npujar467fe752020-01-16 20:17:45 +0530469 if added, err = agent.addUNILogicalPort(ctx, childDevice, port); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000470 logger.Errorw("error-adding-UNI-port", log.Fields{"error": err})
khenaidoofc1314d2019-03-14 09:34:21 -0400471 }
khenaidoo59ef7be2019-06-21 12:40:28 -0400472 if added {
473 agent.addLogicalPortToMap(port.PortNo, false)
474 }
khenaidoo19d7b632018-10-30 10:49:50 -0400475 }
476 }
khenaidoofc1314d2019-03-14 09:34:21 -0400477 return err
khenaidoo92e62c52018-10-03 14:02:54 -0400478}
479
Girish Gowdra408cd962020-03-11 14:31:31 -0700480// deleteAllLogicalPorts deletes all logical ports associated with this logical device
481func (agent *LogicalDeviceAgent) deleteAllLogicalPorts(ctx context.Context) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000482 logger.Infow("updatePortsState-start", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo442e7c72020-03-10 16:13:48 -0400483 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
484 return err
485 }
486 defer agent.requestQueue.RequestComplete()
khenaidoo0a822f92019-05-08 15:15:57 -0400487 // Get the latest logical device info
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500488 cloned := agent.getLogicalDeviceWithoutLock()
khenaidoo6e55d9e2019-12-12 18:26:26 -0500489
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500490 if err := agent.updateLogicalDevicePortsWithoutLock(ctx, cloned, []*voltha.LogicalPort{}); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000491 logger.Warnw("logical-device-update-failed", log.Fields{"ldeviceId": agent.logicalDeviceID, "error": err})
Girish Gowdra408cd962020-03-11 14:31:31 -0700492 return err
khenaidoo0a822f92019-05-08 15:15:57 -0400493 }
494 return nil
495}
496
Hardik Windlassc704def2020-02-26 18:23:19 +0000497// deleteAllUNILogicalPorts deletes all UNI logical ports associated with this parent device
498func (agent *LogicalDeviceAgent) deleteAllUNILogicalPorts(ctx context.Context, parentDevice *voltha.Device) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000499 logger.Debugw("delete-all-uni-logical-ports", log.Fields{"logical-device-id": agent.logicalDeviceID})
khenaidoo442e7c72020-03-10 16:13:48 -0400500 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
501 return err
502 }
503 defer agent.requestQueue.RequestComplete()
Hardik Windlassc704def2020-02-26 18:23:19 +0000504 // Get the latest logical device info
505 ld := agent.getLogicalDeviceWithoutLock()
506
Hardik Windlassc704def2020-02-26 18:23:19 +0000507 updateLogicalPorts := []*voltha.LogicalPort{}
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500508 for _, lport := range ld.Ports {
Hardik Windlassc704def2020-02-26 18:23:19 +0000509 // Save NNI ports only
510 if agent.isNNIPort(lport.DevicePortNo) {
511 updateLogicalPorts = append(updateLogicalPorts, lport)
512 }
513 }
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500514 if len(updateLogicalPorts) < len(ld.Ports) {
Hardik Windlassc704def2020-02-26 18:23:19 +0000515 // Updating the logical device will trigger the port change events to be populated to the controller
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500516 if err := agent.updateLogicalDevicePortsWithoutLock(ctx, ld, updateLogicalPorts); err != nil {
Hardik Windlassc704def2020-02-26 18:23:19 +0000517 return err
518 }
519 } else {
Girish Kumarf56a4682020-03-20 20:07:46 +0000520 logger.Debugw("no-change-required", log.Fields{"logical-device-id": agent.logicalDeviceID})
Hardik Windlassc704def2020-02-26 18:23:19 +0000521 }
522 return nil
523}
524
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500525func clonePorts(ports []*voltha.LogicalPort) []*voltha.LogicalPort {
526 return proto.Clone(&voltha.LogicalPorts{Items: ports}).(*voltha.LogicalPorts).Items
527}
528
529//updateLogicalDevicePortsWithoutLock updates the
530func (agent *LogicalDeviceAgent) updateLogicalDevicePortsWithoutLock(ctx context.Context, device *voltha.LogicalDevice, newPorts []*voltha.LogicalPort) error {
531 oldPorts := device.Ports
532 device.Ports = newPorts
533 if err := agent.updateLogicalDeviceWithoutLock(ctx, device); err != nil {
534 return err
535 }
536 agent.portUpdated(oldPorts, newPorts)
537 return nil
538}
539
khenaidoo92e62c52018-10-03 14:02:54 -0400540//updateLogicalDeviceWithoutLock updates the model with the logical device. It clones the logicaldevice before saving it
npujar467fe752020-01-16 20:17:45 +0530541func (agent *LogicalDeviceAgent) updateLogicalDeviceWithoutLock(ctx context.Context, logicalDevice *voltha.LogicalDevice) error {
542 updateCtx := context.WithValue(ctx, model.RequestTimestamp, time.Now().UnixNano())
Thomas Lee Se5a44012019-11-07 20:32:24 +0530543 afterUpdate, err := agent.clusterDataProxy.Update(updateCtx, "/logical_devices/"+agent.logicalDeviceID, logicalDevice, false, "")
544 if err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000545 logger.Errorw("failed-to-update-logical-devices-to-cluster-proxy", log.Fields{"error": err})
Thomas Lee Se5a44012019-11-07 20:32:24 +0530546 return err
547 }
khenaidoo92e62c52018-10-03 14:02:54 -0400548 if afterUpdate == nil {
npujar1d86a522019-11-14 17:11:16 +0530549 return status.Errorf(codes.Internal, "failed-updating-logical-device:%s", agent.logicalDeviceID)
khenaidoo92e62c52018-10-03 14:02:54 -0400550 }
khenaidoo442e7c72020-03-10 16:13:48 -0400551 //agent.logicalDevice = (proto.Clone(logicalDevice)).(*voltha.LogicalDevice)
552 agent.logicalDevice = logicalDevice
553
khenaidoo92e62c52018-10-03 14:02:54 -0400554 return nil
555}
556
khenaidoo820197c2020-02-13 16:35:33 -0500557//generateDeviceRoutesIfNeeded generates the device routes if the logical device has been updated since the last time
khenaidoo4c9e5592019-09-09 16:20:41 -0400558//that device graph was generated.
khenaidoo820197c2020-02-13 16:35:33 -0500559func (agent *LogicalDeviceAgent) generateDeviceRoutesIfNeeded(ctx context.Context) error {
560 agent.lockDeviceRoutes.Lock()
561 defer agent.lockDeviceRoutes.Unlock()
562
khenaidoo442e7c72020-03-10 16:13:48 -0400563 ld, err := agent.GetLogicalDevice(ctx)
564 if err != nil {
565 return err
566 }
khenaidoo820197c2020-02-13 16:35:33 -0500567
568 if agent.deviceRoutes != nil && agent.deviceRoutes.IsUpToDate(ld) {
npujar1d86a522019-11-14 17:11:16 +0530569 return nil
570 }
Girish Kumarf56a4682020-03-20 20:07:46 +0000571 logger.Debug("Generation of device route required")
khenaidoo820197c2020-02-13 16:35:33 -0500572 if err := agent.buildRoutes(ctx); err != nil {
573 return err
574 }
khenaidoo4c9e5592019-09-09 16:20:41 -0400575 return nil
576}
577
khenaidoo19d7b632018-10-30 10:49:50 -0400578//updateFlowTable updates the flow table of that logical device
579func (agent *LogicalDeviceAgent) updateFlowTable(ctx context.Context, flow *ofp.OfpFlowMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000580 logger.Debug("updateFlowTable")
khenaidoo19d7b632018-10-30 10:49:50 -0400581 if flow == nil {
582 return nil
583 }
khenaidoo820197c2020-02-13 16:35:33 -0500584 if err := agent.generateDeviceRoutesIfNeeded(ctx); err != nil {
khenaidoo4c9e5592019-09-09 16:20:41 -0400585 return err
586 }
khenaidoo19d7b632018-10-30 10:49:50 -0400587 switch flow.GetCommand() {
588 case ofp.OfpFlowModCommand_OFPFC_ADD:
npujar467fe752020-01-16 20:17:45 +0530589 return agent.flowAdd(ctx, flow)
khenaidoo19d7b632018-10-30 10:49:50 -0400590 case ofp.OfpFlowModCommand_OFPFC_DELETE:
npujar467fe752020-01-16 20:17:45 +0530591 return agent.flowDelete(ctx, flow)
khenaidoo19d7b632018-10-30 10:49:50 -0400592 case ofp.OfpFlowModCommand_OFPFC_DELETE_STRICT:
npujar467fe752020-01-16 20:17:45 +0530593 return agent.flowDeleteStrict(ctx, flow)
khenaidoo19d7b632018-10-30 10:49:50 -0400594 case ofp.OfpFlowModCommand_OFPFC_MODIFY:
595 return agent.flowModify(flow)
596 case ofp.OfpFlowModCommand_OFPFC_MODIFY_STRICT:
597 return agent.flowModifyStrict(flow)
598 }
599 return status.Errorf(codes.Internal,
npujar1d86a522019-11-14 17:11:16 +0530600 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceID, flow.GetCommand())
khenaidoo19d7b632018-10-30 10:49:50 -0400601}
602
603//updateGroupTable updates the group table of that logical device
604func (agent *LogicalDeviceAgent) updateGroupTable(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000605 logger.Debug("updateGroupTable")
khenaidoo19d7b632018-10-30 10:49:50 -0400606 if groupMod == nil {
607 return nil
608 }
khenaidoo820197c2020-02-13 16:35:33 -0500609 if err := agent.generateDeviceRoutesIfNeeded(ctx); err != nil {
khenaidoo4c9e5592019-09-09 16:20:41 -0400610 return err
611 }
khenaidoo820197c2020-02-13 16:35:33 -0500612
khenaidoo19d7b632018-10-30 10:49:50 -0400613 switch groupMod.GetCommand() {
614 case ofp.OfpGroupModCommand_OFPGC_ADD:
npujar467fe752020-01-16 20:17:45 +0530615 return agent.groupAdd(ctx, groupMod)
khenaidoo19d7b632018-10-30 10:49:50 -0400616 case ofp.OfpGroupModCommand_OFPGC_DELETE:
npujar467fe752020-01-16 20:17:45 +0530617 return agent.groupDelete(ctx, groupMod)
khenaidoo19d7b632018-10-30 10:49:50 -0400618 case ofp.OfpGroupModCommand_OFPGC_MODIFY:
npujar467fe752020-01-16 20:17:45 +0530619 return agent.groupModify(ctx, groupMod)
khenaidoo19d7b632018-10-30 10:49:50 -0400620 }
621 return status.Errorf(codes.Internal,
npujar1d86a522019-11-14 17:11:16 +0530622 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceID, groupMod.GetCommand())
khenaidoo19d7b632018-10-30 10:49:50 -0400623}
624
Manikkaraj kb1a10922019-07-29 12:10:34 -0400625// updateMeterTable updates the meter table of that logical device
626func (agent *LogicalDeviceAgent) updateMeterTable(ctx context.Context, meterMod *ofp.OfpMeterMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000627 logger.Debug("updateMeterTable")
Manikkaraj kb1a10922019-07-29 12:10:34 -0400628 if meterMod == nil {
629 return nil
630 }
631 switch meterMod.GetCommand() {
632 case ofp.OfpMeterModCommand_OFPMC_ADD:
npujar467fe752020-01-16 20:17:45 +0530633 return agent.meterAdd(ctx, meterMod)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400634 case ofp.OfpMeterModCommand_OFPMC_DELETE:
npujar467fe752020-01-16 20:17:45 +0530635 return agent.meterDelete(ctx, meterMod)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400636 case ofp.OfpMeterModCommand_OFPMC_MODIFY:
npujar467fe752020-01-16 20:17:45 +0530637 return agent.meterModify(ctx, meterMod)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400638 }
639 return status.Errorf(codes.Internal,
npujar1d86a522019-11-14 17:11:16 +0530640 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceID, meterMod.GetCommand())
Manikkaraj kb1a10922019-07-29 12:10:34 -0400641
642}
643
npujar467fe752020-01-16 20:17:45 +0530644func (agent *LogicalDeviceAgent) meterAdd(ctx context.Context, meterMod *ofp.OfpMeterMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000645 logger.Debugw("meterAdd", log.Fields{"metermod": *meterMod})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400646 if meterMod == nil {
647 return nil
648 }
khenaidoo442e7c72020-03-10 16:13:48 -0400649 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
650 return err
651 }
652 defer agent.requestQueue.RequestComplete()
Girish Kumarf56a4682020-03-20 20:07:46 +0000653 logger.Debug("Acquired logical device lock")
khenaidoo6e55d9e2019-12-12 18:26:26 -0500654 lDevice := agent.getLogicalDeviceWithoutLock()
Manikkaraj kb1a10922019-07-29 12:10:34 -0400655
656 var meters []*ofp.OfpMeterEntry
657 if lDevice.Meters != nil && lDevice.Meters.Items != nil {
658 meters = lDevice.Meters.Items
659 }
Girish Kumarf56a4682020-03-20 20:07:46 +0000660 logger.Debugw("Available meters", log.Fields{"meters": meters})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400661
662 for _, meter := range meters {
663 if meterMod.MeterId == meter.Config.MeterId {
Girish Kumarf56a4682020-03-20 20:07:46 +0000664 logger.Infow("Meter-already-exists", log.Fields{"meter": *meterMod})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400665 return nil
666 }
667 }
668
669 meterEntry := fu.MeterEntryFromMeterMod(meterMod)
670 meters = append(meters, meterEntry)
671 //Update model
npujar467fe752020-01-16 20:17:45 +0530672 if err := agent.updateLogicalDeviceMetersWithoutLock(ctx, &ofp.Meters{Items: meters}); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000673 logger.Errorw("db-meter-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400674 return err
675 }
Girish Kumarf56a4682020-03-20 20:07:46 +0000676 logger.Debugw("Meter-added-successfully", log.Fields{"Added-meter": meterEntry, "updated-meters": lDevice.Meters})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400677 return nil
678}
679
npujar467fe752020-01-16 20:17:45 +0530680func (agent *LogicalDeviceAgent) meterDelete(ctx context.Context, meterMod *ofp.OfpMeterMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000681 logger.Debug("meterDelete", log.Fields{"meterMod": *meterMod})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400682 if meterMod == nil {
683 return nil
684 }
khenaidoo442e7c72020-03-10 16:13:48 -0400685 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
686 return err
687 }
688 defer agent.requestQueue.RequestComplete()
Manikkaraj kb1a10922019-07-29 12:10:34 -0400689
khenaidoo6e55d9e2019-12-12 18:26:26 -0500690 lDevice := agent.getLogicalDeviceWithoutLock()
Manikkaraj kb1a10922019-07-29 12:10:34 -0400691
692 var meters []*ofp.OfpMeterEntry
693 var flows []*ofp.OfpFlowStats
694 updatedFlows := make([]*ofp.OfpFlowStats, 0)
695 if lDevice.Meters != nil && lDevice.Meters.Items != nil {
696 meters = lDevice.Meters.Items
697 }
Manikkaraj kb1a10922019-07-29 12:10:34 -0400698
699 changedMeter := false
700 changedFow := false
Girish Kumarf56a4682020-03-20 20:07:46 +0000701 logger.Debugw("Available meters", log.Fields{"meters": meters})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400702 for index, meter := range meters {
703 if meterMod.MeterId == meter.Config.MeterId {
704 flows = lDevice.Flows.Items
npujar1d86a522019-11-14 17:11:16 +0530705 changedFow, updatedFlows = agent.getUpdatedFlowsAfterDeletebyMeterID(flows, meterMod.MeterId)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400706 meters = append(meters[:index], meters[index+1:]...)
Girish Kumarf56a4682020-03-20 20:07:46 +0000707 logger.Debugw("Meter has been deleted", log.Fields{"meter": meter, "index": index})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400708 changedMeter = true
709 break
710 }
711 }
712 if changedMeter {
713 //Update model
714 metersToUpdate := &ofp.Meters{}
715 if lDevice.Meters != nil {
716 metersToUpdate = &ofp.Meters{Items: meters}
717 }
npujar467fe752020-01-16 20:17:45 +0530718 if err := agent.updateLogicalDeviceMetersWithoutLock(ctx, metersToUpdate); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000719 logger.Errorw("db-meter-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400720 return err
721 }
Girish Kumarf56a4682020-03-20 20:07:46 +0000722 logger.Debug("Meter-deleted-from-DB-successfully", log.Fields{"updatedMeters": metersToUpdate, "no-of-meter": len(metersToUpdate.Items)})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400723
724 }
725 if changedFow {
726 //Update model
npujar467fe752020-01-16 20:17:45 +0530727 if err := agent.updateLogicalDeviceFlowsWithoutLock(ctx, &ofp.Flows{Items: updatedFlows}); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000728 logger.Errorw("db-flow-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400729 return err
730 }
Girish Kumarf56a4682020-03-20 20:07:46 +0000731 logger.Debug("Flows-associated-with-meter-deleted-from-DB-successfully",
Manikkaraj kb1a10922019-07-29 12:10:34 -0400732 log.Fields{"updated-no-of-flows": len(updatedFlows), "meter": meterMod.MeterId})
733 }
Girish Kumarf56a4682020-03-20 20:07:46 +0000734 logger.Debugw("meterDelete success", log.Fields{"meterID": meterMod.MeterId})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400735 return nil
736}
737
npujar467fe752020-01-16 20:17:45 +0530738func (agent *LogicalDeviceAgent) meterModify(ctx context.Context, meterMod *ofp.OfpMeterMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000739 logger.Debug("meterModify")
Manikkaraj kb1a10922019-07-29 12:10:34 -0400740 if meterMod == nil {
741 return nil
742 }
khenaidoo442e7c72020-03-10 16:13:48 -0400743 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
744 return err
745 }
746 defer agent.requestQueue.RequestComplete()
Manikkaraj kb1a10922019-07-29 12:10:34 -0400747
khenaidoo6e55d9e2019-12-12 18:26:26 -0500748 lDevice := agent.getLogicalDeviceWithoutLock()
Manikkaraj kb1a10922019-07-29 12:10:34 -0400749
750 var meters []*ofp.OfpMeterEntry
751 if lDevice.Meters != nil && lDevice.Meters.Items != nil {
752 meters = lDevice.Meters.Items
753 }
754 changedMeter := false
755 for index, meter := range meters {
756 if meterMod.MeterId == meter.Config.MeterId {
757 newmeterEntry := fu.MeterEntryFromMeterMod(meterMod)
758 newmeterEntry.Stats.FlowCount = meter.Stats.FlowCount
759 meters[index] = newmeterEntry
760 changedMeter = true
Girish Kumarf56a4682020-03-20 20:07:46 +0000761 logger.Debugw("Found meter, replaced with new meter", log.Fields{"old meter": meter, "new meter": newmeterEntry})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400762 break
763 }
764 }
765 if changedMeter {
766 //Update model
767 metersToUpdate := &ofp.Meters{}
768 if lDevice.Meters != nil {
769 metersToUpdate = &ofp.Meters{Items: meters}
770 }
npujar467fe752020-01-16 20:17:45 +0530771 if err := agent.updateLogicalDeviceMetersWithoutLock(ctx, metersToUpdate); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000772 logger.Errorw("db-meter-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400773 return err
774 }
Girish Kumarf56a4682020-03-20 20:07:46 +0000775 logger.Debugw("meter-updated-in-DB-successfully", log.Fields{"updated_meters": meters})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400776 return nil
777 }
778
Girish Kumarf56a4682020-03-20 20:07:46 +0000779 logger.Errorw("Meter not found ", log.Fields{"meter": meterMod})
npujar1d86a522019-11-14 17:11:16 +0530780 return fmt.Errorf("no-logical-device-present:%d", meterMod.MeterId)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400781
782}
783
npujar1d86a522019-11-14 17:11:16 +0530784func (agent *LogicalDeviceAgent) getUpdatedFlowsAfterDeletebyMeterID(flows []*ofp.OfpFlowStats, meterID uint32) (bool, []*ofp.OfpFlowStats) {
Girish Kumarf56a4682020-03-20 20:07:46 +0000785 logger.Infow("Delete flows matching meter", log.Fields{"meter": meterID})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400786 changed := false
787 //updatedFlows := make([]*ofp.OfpFlowStats, 0)
788 for index := len(flows) - 1; index >= 0; index-- {
npujar1d86a522019-11-14 17:11:16 +0530789 if mID := fu.GetMeterIdFromFlow(flows[index]); mID != 0 && mID == meterID {
Girish Kumarf56a4682020-03-20 20:07:46 +0000790 logger.Debugw("Flow to be deleted", log.Fields{"flow": flows[index], "index": index})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400791 flows = append(flows[:index], flows[index+1:]...)
792 changed = true
793 }
794 }
795 return changed, flows
796}
797
798func (agent *LogicalDeviceAgent) updateFlowCountOfMeterStats(modCommand *ofp.OfpFlowMod, meters []*ofp.OfpMeterEntry, flow *ofp.OfpFlowStats) bool {
799
800 flowCommand := modCommand.GetCommand()
npujar1d86a522019-11-14 17:11:16 +0530801 meterID := fu.GetMeterIdFromFlow(flow)
Girish Kumarf56a4682020-03-20 20:07:46 +0000802 logger.Debugw("Meter-id-in-flow-mod", log.Fields{"meterId": meterID})
npujar1d86a522019-11-14 17:11:16 +0530803 if meterID == 0 {
Girish Kumarf56a4682020-03-20 20:07:46 +0000804 logger.Debugw("No meter present in the flow", log.Fields{"flow": *flow})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400805 return false
806 }
807 if meters == nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000808 logger.Debug("No meters present in logical device")
Manikkaraj kb1a10922019-07-29 12:10:34 -0400809 return false
810 }
811 changedMeter := false
812 for _, meter := range meters {
npujar1d86a522019-11-14 17:11:16 +0530813 if meterID == meter.Config.MeterId { // Found meter in Logicaldevice
Manikkaraj kb1a10922019-07-29 12:10:34 -0400814 if flowCommand == ofp.OfpFlowModCommand_OFPFC_ADD {
npujar1d86a522019-11-14 17:11:16 +0530815 meter.Stats.FlowCount++
Manikkaraj kb1a10922019-07-29 12:10:34 -0400816 changedMeter = true
817 } else if flowCommand == ofp.OfpFlowModCommand_OFPFC_DELETE_STRICT {
npujar1d86a522019-11-14 17:11:16 +0530818 meter.Stats.FlowCount--
Manikkaraj kb1a10922019-07-29 12:10:34 -0400819 changedMeter = true
820 }
Girish Kumarf56a4682020-03-20 20:07:46 +0000821 logger.Debugw("Found meter, updated meter flow stats", log.Fields{" meterId": meterID})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400822 break
823 }
824 }
825 return changedMeter
826}
827
khenaidoo19d7b632018-10-30 10:49:50 -0400828//flowAdd adds a flow to the flow table of that logical device
npujar467fe752020-01-16 20:17:45 +0530829func (agent *LogicalDeviceAgent) flowAdd(ctx context.Context, mod *ofp.OfpFlowMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000830 logger.Debugw("flowAdd", log.Fields{"flow": mod})
khenaidoo19d7b632018-10-30 10:49:50 -0400831 if mod == nil {
832 return nil
833 }
khenaidoo442e7c72020-03-10 16:13:48 -0400834 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
835 return err
836 }
837 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -0400838
khenaidoo6e55d9e2019-12-12 18:26:26 -0500839 lDevice := agent.getLogicalDeviceWithoutLock()
khenaidoo19d7b632018-10-30 10:49:50 -0400840
841 var flows []*ofp.OfpFlowStats
Manikkaraj kb1a10922019-07-29 12:10:34 -0400842 var meters []*ofp.OfpMeterEntry
843 var flow *ofp.OfpFlowStats
Scott Bakerfdea1e32020-02-21 15:35:41 -0800844 var err error
Manikkaraj kb1a10922019-07-29 12:10:34 -0400845
khenaidoo19d7b632018-10-30 10:49:50 -0400846 if lDevice.Flows != nil && lDevice.Flows.Items != nil {
847 flows = lDevice.Flows.Items
848 }
849
Manikkaraj kb1a10922019-07-29 12:10:34 -0400850 if lDevice.Meters != nil && lDevice.Meters.Items != nil {
851 meters = lDevice.Meters.Items
852 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400853 updatedFlows := make([]*ofp.OfpFlowStats, 0)
khenaidoo19d7b632018-10-30 10:49:50 -0400854 changed := false
Manikkaraj kb1a10922019-07-29 12:10:34 -0400855 updated := false
khenaidoo19d7b632018-10-30 10:49:50 -0400856 checkOverlap := (mod.Flags & uint32(ofp.OfpFlowModFlags_OFPFF_CHECK_OVERLAP)) != 0
857 if checkOverlap {
858 if overlapped := fu.FindOverlappingFlows(flows, mod); len(overlapped) != 0 {
859 // TODO: should this error be notified other than being logged?
Girish Kumarf56a4682020-03-20 20:07:46 +0000860 logger.Warnw("overlapped-flows", log.Fields{"logicaldeviceId": agent.logicalDeviceID})
khenaidoo19d7b632018-10-30 10:49:50 -0400861 } else {
Matt Jeanneret518b5a42019-10-29 10:30:46 -0400862 // Add flow
Scott Bakerfdea1e32020-02-21 15:35:41 -0800863 flow, err = fu.FlowStatsEntryFromFlowModMessage(mod)
864 if err != nil {
865 return err
866 }
khenaidoo19d7b632018-10-30 10:49:50 -0400867 flows = append(flows, flow)
khenaidoo2c6a0992019-04-29 13:46:56 -0400868 updatedFlows = append(updatedFlows, flow)
khenaidoo19d7b632018-10-30 10:49:50 -0400869 changed = true
870 }
871 } else {
Scott Bakerfdea1e32020-02-21 15:35:41 -0800872 flow, err = fu.FlowStatsEntryFromFlowModMessage(mod)
873 if err != nil {
874 return err
875 }
khenaidoo19d7b632018-10-30 10:49:50 -0400876 idx := fu.FindFlows(flows, flow)
877 if idx >= 0 {
878 oldFlow := flows[idx]
879 if (mod.Flags & uint32(ofp.OfpFlowModFlags_OFPFF_RESET_COUNTS)) != 0 {
880 flow.ByteCount = oldFlow.ByteCount
881 flow.PacketCount = oldFlow.PacketCount
882 }
Matt Jeanneret518b5a42019-10-29 10:30:46 -0400883 if !reflect.DeepEqual(oldFlow, flow) {
884 flows[idx] = flow
885 updatedFlows = append(updatedFlows, flow)
886 changed = true
887 updated = true
888 }
889 } else {
khenaidoo19d7b632018-10-30 10:49:50 -0400890 flows = append(flows, flow)
khenaidoo2c6a0992019-04-29 13:46:56 -0400891 updatedFlows = append(updatedFlows, flow)
892 changed = true
khenaidoo19d7b632018-10-30 10:49:50 -0400893 }
khenaidoo19d7b632018-10-30 10:49:50 -0400894 }
Girish Kumarf56a4682020-03-20 20:07:46 +0000895 logger.Debugw("flowAdd-changed", log.Fields{"changed": changed})
khenaidoo4c9e5592019-09-09 16:20:41 -0400896
khenaidoo19d7b632018-10-30 10:49:50 -0400897 if changed {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400898 var flowMetadata voltha.FlowMetadata
899 if err := agent.GetMeterConfig(updatedFlows, meters, &flowMetadata); err != nil { // This should never happen,meters should be installed before flow arrives
Girish Kumarf56a4682020-03-20 20:07:46 +0000900 logger.Error("Meter-referred-in-flows-not-present")
Manikkaraj kb1a10922019-07-29 12:10:34 -0400901 return err
902 }
khenaidoo820197c2020-02-13 16:35:33 -0500903 deviceRules, err := agent.flowDecomposer.DecomposeRules(ctx, agent, ofp.Flows{Items: updatedFlows}, *lDevice.FlowGroups)
904 if err != nil {
905 return err
906 }
Girish Kumarf56a4682020-03-20 20:07:46 +0000907 logger.Debugw("rules", log.Fields{"rules": deviceRules.String()})
khenaidoo0458db62019-06-20 08:50:36 -0400908
khenaidoo19d7b632018-10-30 10:49:50 -0400909 // Update model
npujar467fe752020-01-16 20:17:45 +0530910 if err := agent.updateLogicalDeviceFlowsWithoutLock(ctx, &ofp.Flows{Items: flows}); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000911 logger.Errorw("db-flow-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo19d7b632018-10-30 10:49:50 -0400912 return err
913 }
Matt Jeanneret518b5a42019-10-29 10:30:46 -0400914 if !updated {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400915 changedMeterStats := agent.updateFlowCountOfMeterStats(mod, meters, flow)
916 metersToUpdate := &ofp.Meters{}
917 if lDevice.Meters != nil {
918 metersToUpdate = &ofp.Meters{Items: meters}
919 }
920 if changedMeterStats {
921 //Update model
npujar467fe752020-01-16 20:17:45 +0530922 if err := agent.updateLogicalDeviceMetersWithoutLock(ctx, metersToUpdate); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000923 logger.Errorw("db-meter-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400924 return err
925 }
Girish Kumarf56a4682020-03-20 20:07:46 +0000926 logger.Debugw("meter-stats-updated-in-DB-successfully", log.Fields{"updated_meters": meters})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400927
928 }
929 }
khenaidoo442e7c72020-03-10 16:13:48 -0400930 // Send the flows to the devices
931 respChannels := agent.addFlowsAndGroupsToDevices(ctx, deviceRules, &flowMetadata)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400932
khenaidoo442e7c72020-03-10 16:13:48 -0400933 // Create the go routines to wait
934 go func() {
935 // Wait for completion
936 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChannels...); res != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000937 logger.Warnw("failure-to-add-flows", log.Fields{"errors": res, "logical-device-id": agent.logicalDeviceID})
khenaidoo442e7c72020-03-10 16:13:48 -0400938 // TODO : revert added flow
939 }
940 }()
khenaidoo19d7b632018-10-30 10:49:50 -0400941 }
khenaidoo19d7b632018-10-30 10:49:50 -0400942 return nil
943}
944
npujar1d86a522019-11-14 17:11:16 +0530945// GetMeterConfig returns meter config
Manikkaraj kb1a10922019-07-29 12:10:34 -0400946func (agent *LogicalDeviceAgent) GetMeterConfig(flows []*ofp.OfpFlowStats, meters []*ofp.OfpMeterEntry, metadata *voltha.FlowMetadata) error {
947 m := make(map[uint32]bool)
948 for _, flow := range flows {
npujar1d86a522019-11-14 17:11:16 +0530949 if flowMeterID := fu.GetMeterIdFromFlow(flow); flowMeterID != 0 && !m[flowMeterID] {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400950 foundMeter := false
951 // Meter is present in the flow , Get from logical device
952 for _, meter := range meters {
953 if flowMeterID == meter.Config.MeterId {
954 metadata.Meters = append(metadata.Meters, meter.Config)
Girish Kumarf56a4682020-03-20 20:07:46 +0000955 logger.Debugw("Found meter in logical device",
Manikkaraj kb1a10922019-07-29 12:10:34 -0400956 log.Fields{"meterID": flowMeterID, "meter-band": meter.Config})
957 m[flowMeterID] = true
958 foundMeter = true
959 break
960 }
961 }
962 if !foundMeter {
Girish Kumarf56a4682020-03-20 20:07:46 +0000963 logger.Errorw("Meter-referred-by-flow-is-not-found-in-logicaldevice",
npujar1d86a522019-11-14 17:11:16 +0530964 log.Fields{"meterID": flowMeterID, "Available-meters": meters, "flow": *flow})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400965 return errors.New("Meter-referred-by-flow-is-not-found-in-logicaldevice")
966 }
967 }
968 }
Girish Kumarf56a4682020-03-20 20:07:46 +0000969 logger.Debugw("meter-bands-for-flows", log.Fields{"flows": len(flows), "metadata": metadata})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400970 return nil
971
972}
973
khenaidoo19d7b632018-10-30 10:49:50 -0400974//flowDelete deletes a flow from the flow table of that logical device
npujar467fe752020-01-16 20:17:45 +0530975func (agent *LogicalDeviceAgent) flowDelete(ctx context.Context, mod *ofp.OfpFlowMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000976 logger.Debug("flowDelete")
khenaidoo19d7b632018-10-30 10:49:50 -0400977 if mod == nil {
978 return nil
979 }
khenaidoo442e7c72020-03-10 16:13:48 -0400980 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
981 return err
982 }
983 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -0400984
khenaidoo6e55d9e2019-12-12 18:26:26 -0500985 lDevice := agent.getLogicalDeviceWithoutLock()
khenaidoo19d7b632018-10-30 10:49:50 -0400986
Manikkaraj kb1a10922019-07-29 12:10:34 -0400987 var meters []*ofp.OfpMeterEntry
988 var flows []*ofp.OfpFlowStats
Esin Karamanfc3b1af2020-01-29 16:52:00 +0000989 var flowGroups []*ofp.OfpGroupEntry
Manikkaraj kb1a10922019-07-29 12:10:34 -0400990
991 if lDevice.Flows != nil && lDevice.Flows.Items != nil {
992 flows = lDevice.Flows.Items
993 }
994
995 if lDevice.Meters != nil && lDevice.Meters.Items != nil {
996 meters = lDevice.Meters.Items
997 }
Esin Karamanfc3b1af2020-01-29 16:52:00 +0000998
999 if lDevice.FlowGroups != nil && lDevice.FlowGroups.Items != nil {
1000 flowGroups = lDevice.FlowGroups.Items
1001 }
1002
khenaidoo19d7b632018-10-30 10:49:50 -04001003 //build a list of what to keep vs what to delete
1004 toKeep := make([]*ofp.OfpFlowStats, 0)
khenaidoo0458db62019-06-20 08:50:36 -04001005 toDelete := make([]*ofp.OfpFlowStats, 0)
khenaidoo19d7b632018-10-30 10:49:50 -04001006 for _, f := range flows {
khenaidoo0458db62019-06-20 08:50:36 -04001007 // Check whether the flow and the flowmod matches
Scott Bakerfdea1e32020-02-21 15:35:41 -08001008 fs, err := fu.FlowStatsEntryFromFlowModMessage(mod)
1009 if err != nil {
1010 return err
1011 }
1012 if fu.FlowMatch(f, fs) {
khenaidoo0458db62019-06-20 08:50:36 -04001013 toDelete = append(toDelete, f)
1014 continue
1015 }
1016 // Check wild card match
khenaidoo19d7b632018-10-30 10:49:50 -04001017 if !fu.FlowMatchesMod(f, mod) {
1018 toKeep = append(toKeep, f)
khenaidoo0458db62019-06-20 08:50:36 -04001019 } else {
1020 toDelete = append(toDelete, f)
khenaidoo19d7b632018-10-30 10:49:50 -04001021 }
1022 }
1023
Girish Kumarf56a4682020-03-20 20:07:46 +00001024 logger.Debugw("flowDelete", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "toKeep": len(toKeep), "toDelete": toDelete})
khenaidoo0458db62019-06-20 08:50:36 -04001025
khenaidoo19d7b632018-10-30 10:49:50 -04001026 //Update flows
khenaidoo0458db62019-06-20 08:50:36 -04001027 if len(toDelete) > 0 {
Manikkaraj kb1a10922019-07-29 12:10:34 -04001028 var flowMetadata voltha.FlowMetadata
1029 if err := agent.GetMeterConfig(toDelete, meters, &flowMetadata); err != nil { // This should never happen
Girish Kumarf56a4682020-03-20 20:07:46 +00001030 logger.Error("Meter-referred-in-flows-not-present")
Manikkaraj kb1a10922019-07-29 12:10:34 -04001031 return errors.New("Meter-referred-in-flows-not-present")
1032 }
khenaidoo820197c2020-02-13 16:35:33 -05001033 deviceRules, err := agent.flowDecomposer.DecomposeRules(ctx, agent, ofp.Flows{Items: toDelete}, ofp.FlowGroups{Items: flowGroups})
1034 if err != nil {
1035 return err
1036 }
Girish Kumarf56a4682020-03-20 20:07:46 +00001037 logger.Debugw("rules", log.Fields{"rules": deviceRules.String()})
khenaidoo0458db62019-06-20 08:50:36 -04001038
npujar467fe752020-01-16 20:17:45 +05301039 if err := agent.updateLogicalDeviceFlowsWithoutLock(ctx, &ofp.Flows{Items: toKeep}); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001040 logger.Errorw("cannot-update-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo19d7b632018-10-30 10:49:50 -04001041 return err
1042 }
khenaidoo442e7c72020-03-10 16:13:48 -04001043
1044 // Update the devices
1045 respChnls := agent.deleteFlowsAndGroupsFromDevices(ctx, deviceRules, &flowMetadata)
1046
1047 // Wait for the responses
1048 go func() {
1049 // Wait for completion
1050 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001051 logger.Errorw("failure-updating-device-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "errors": res})
khenaidoo442e7c72020-03-10 16:13:48 -04001052 // TODO: Revert the flow deletion
1053 }
1054 }()
khenaidoo19d7b632018-10-30 10:49:50 -04001055 }
1056
1057 //TODO: send announcement on delete
1058 return nil
1059}
1060
khenaidoo442e7c72020-03-10 16:13:48 -04001061func (agent *LogicalDeviceAgent) addFlowsAndGroupsToDevices(ctx context.Context, deviceRules *fu.DeviceRules, flowMetadata *voltha.FlowMetadata) []coreutils.Response {
Girish Kumarf56a4682020-03-20 20:07:46 +00001062 logger.Debugw("send-add-flows-to-device-manager", log.Fields{"logicalDeviceID": agent.logicalDeviceID, "deviceRules": deviceRules, "flowMetadata": flowMetadata})
khenaidoo19d7b632018-10-30 10:49:50 -04001063
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001064 responses := make([]coreutils.Response, 0)
npujar1d86a522019-11-14 17:11:16 +05301065 for deviceID, value := range deviceRules.GetRules() {
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001066 response := coreutils.NewResponse()
1067 responses = append(responses, response)
1068 go func(deviceId string, value *fu.FlowsAndGroups) {
khenaidoo442e7c72020-03-10 16:13:48 -04001069 ctx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
1070 defer cancel()
npujar467fe752020-01-16 20:17:45 +05301071 if err := agent.deviceMgr.addFlowsAndGroups(ctx, deviceId, value.ListFlows(), value.ListGroups(), flowMetadata); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001072 logger.Errorw("flow-add-failed", log.Fields{"deviceID": deviceId, "error": err})
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001073 response.Error(status.Errorf(codes.Internal, "flow-add-failed: %s", deviceId))
khenaidoo0458db62019-06-20 08:50:36 -04001074 }
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001075 response.Done()
npujar1d86a522019-11-14 17:11:16 +05301076 }(deviceID, value)
khenaidoo19d7b632018-10-30 10:49:50 -04001077 }
khenaidoo442e7c72020-03-10 16:13:48 -04001078 // Return responses (an array of channels) for the caller to wait for a response from the far end.
1079 return responses
khenaidoo0458db62019-06-20 08:50:36 -04001080}
khenaidoo19d7b632018-10-30 10:49:50 -04001081
khenaidoo442e7c72020-03-10 16:13:48 -04001082func (agent *LogicalDeviceAgent) deleteFlowsAndGroupsFromDevices(ctx context.Context, deviceRules *fu.DeviceRules, flowMetadata *voltha.FlowMetadata) []coreutils.Response {
Girish Kumarf56a4682020-03-20 20:07:46 +00001083 logger.Debugw("send-delete-flows-to-device-manager", log.Fields{"logicalDeviceID": agent.logicalDeviceID})
khenaidoo0458db62019-06-20 08:50:36 -04001084
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001085 responses := make([]coreutils.Response, 0)
npujar1d86a522019-11-14 17:11:16 +05301086 for deviceID, value := range deviceRules.GetRules() {
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001087 response := coreutils.NewResponse()
1088 responses = append(responses, response)
1089 go func(deviceId string, value *fu.FlowsAndGroups) {
khenaidoo442e7c72020-03-10 16:13:48 -04001090 ctx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
1091 defer cancel()
npujar467fe752020-01-16 20:17:45 +05301092 if err := agent.deviceMgr.deleteFlowsAndGroups(ctx, deviceId, value.ListFlows(), value.ListGroups(), flowMetadata); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001093 logger.Error("flow-delete-failed", log.Fields{"deviceID": deviceId, "error": err})
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001094 response.Error(status.Errorf(codes.Internal, "flow-delete-failed: %s", deviceId))
khenaidoo0458db62019-06-20 08:50:36 -04001095 }
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001096 response.Done()
npujar1d86a522019-11-14 17:11:16 +05301097 }(deviceID, value)
khenaidoo0458db62019-06-20 08:50:36 -04001098 }
khenaidoo442e7c72020-03-10 16:13:48 -04001099 return responses
khenaidoo0458db62019-06-20 08:50:36 -04001100}
1101
khenaidoo442e7c72020-03-10 16:13:48 -04001102func (agent *LogicalDeviceAgent) updateFlowsAndGroupsOfDevice(ctx context.Context, deviceRules *fu.DeviceRules, flowMetadata *voltha.FlowMetadata) []coreutils.Response {
Girish Kumarf56a4682020-03-20 20:07:46 +00001103 logger.Debugw("send-update-flows-to-device-manager", log.Fields{"logicalDeviceID": agent.logicalDeviceID})
khenaidoo0458db62019-06-20 08:50:36 -04001104
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001105 responses := make([]coreutils.Response, 0)
npujar1d86a522019-11-14 17:11:16 +05301106 for deviceID, value := range deviceRules.GetRules() {
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001107 response := coreutils.NewResponse()
1108 responses = append(responses, response)
1109 go func(deviceId string, value *fu.FlowsAndGroups) {
khenaidoo442e7c72020-03-10 16:13:48 -04001110 ctx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
1111 defer cancel()
npujar467fe752020-01-16 20:17:45 +05301112 if err := agent.deviceMgr.updateFlowsAndGroups(ctx, deviceId, value.ListFlows(), value.ListGroups(), flowMetadata); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001113 logger.Error("flow-update-failed", log.Fields{"deviceID": deviceId, "error": err})
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001114 response.Error(status.Errorf(codes.Internal, "flow-update-failed: %s", deviceId))
khenaidoo0458db62019-06-20 08:50:36 -04001115 }
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001116 response.Done()
npujar1d86a522019-11-14 17:11:16 +05301117 }(deviceID, value)
khenaidoo0458db62019-06-20 08:50:36 -04001118 }
khenaidoo442e7c72020-03-10 16:13:48 -04001119 return responses
khenaidoo19d7b632018-10-30 10:49:50 -04001120}
1121
1122//flowDeleteStrict deletes a flow from the flow table of that logical device
npujar467fe752020-01-16 20:17:45 +05301123func (agent *LogicalDeviceAgent) flowDeleteStrict(ctx context.Context, mod *ofp.OfpFlowMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +00001124 logger.Debug("flowDeleteStrict")
khenaidoo19d7b632018-10-30 10:49:50 -04001125 if mod == nil {
1126 return nil
1127 }
khenaidoo442e7c72020-03-10 16:13:48 -04001128 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1129 return err
1130 }
1131 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -04001132
khenaidoo6e55d9e2019-12-12 18:26:26 -05001133 lDevice := agent.getLogicalDeviceWithoutLock()
1134
Manikkaraj kb1a10922019-07-29 12:10:34 -04001135 var meters []*ofp.OfpMeterEntry
1136 var flows []*ofp.OfpFlowStats
Esin Karamanfc3b1af2020-01-29 16:52:00 +00001137 var flowGroups []*ofp.OfpGroupEntry
Manikkaraj kb1a10922019-07-29 12:10:34 -04001138 if lDevice.Meters != nil && lDevice.Meters.Items != nil {
1139 meters = lDevice.Meters.Items
1140 }
1141 if lDevice.Flows != nil && lDevice.Flows.Items != nil {
1142 flows = lDevice.Flows.Items
1143 }
Esin Karamanfc3b1af2020-01-29 16:52:00 +00001144 if lDevice.FlowGroups != nil && lDevice.FlowGroups.Items != nil {
1145 flowGroups = lDevice.FlowGroups.Items
1146 }
Manikkaraj kb1a10922019-07-29 12:10:34 -04001147
1148 changedFlow := false
1149 changedMeter := false
Scott Bakerfdea1e32020-02-21 15:35:41 -08001150 flow, err := fu.FlowStatsEntryFromFlowModMessage(mod)
1151 if err != nil {
1152 return err
1153 }
Manikkaraj kb1a10922019-07-29 12:10:34 -04001154 flowsToDelete := make([]*ofp.OfpFlowStats, 0)
khenaidoo19d7b632018-10-30 10:49:50 -04001155 idx := fu.FindFlows(flows, flow)
1156 if idx >= 0 {
Gamze Abaka6e4ac162019-10-21 11:10:10 +00001157 changedMeter = agent.updateFlowCountOfMeterStats(mod, meters, flows[idx])
Manikkaraj kb1a10922019-07-29 12:10:34 -04001158 flowsToDelete = append(flowsToDelete, flows[idx])
khenaidoo19d7b632018-10-30 10:49:50 -04001159 flows = append(flows[:idx], flows[idx+1:]...)
Manikkaraj kb1a10922019-07-29 12:10:34 -04001160 changedFlow = true
khenaidoo19d7b632018-10-30 10:49:50 -04001161 } else {
npujar1d86a522019-11-14 17:11:16 +05301162 return fmt.Errorf("Cannot delete flow - %s", flow)
khenaidoo19d7b632018-10-30 10:49:50 -04001163 }
Manikkaraj kb1a10922019-07-29 12:10:34 -04001164 if changedMeter {
1165 //Update model
1166 metersToUpdate := &ofp.Meters{}
1167 if lDevice.Meters != nil {
1168 metersToUpdate = &ofp.Meters{Items: meters}
1169 }
npujar467fe752020-01-16 20:17:45 +05301170 if err := agent.updateLogicalDeviceMetersWithoutLock(ctx, metersToUpdate); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001171 logger.Errorw("db-meter-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
Manikkaraj kb1a10922019-07-29 12:10:34 -04001172 return err
1173 }
khenaidoo19d7b632018-10-30 10:49:50 -04001174
Manikkaraj kb1a10922019-07-29 12:10:34 -04001175 }
1176 if changedFlow {
1177 var flowMetadata voltha.FlowMetadata
1178 if err := agent.GetMeterConfig(flowsToDelete, meters, &flowMetadata); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001179 logger.Error("meter-referred-in-flows-not-present")
Manikkaraj kb1a10922019-07-29 12:10:34 -04001180 return err
1181 }
khenaidoo820197c2020-02-13 16:35:33 -05001182 deviceRules, err := agent.flowDecomposer.DecomposeRules(ctx, agent, ofp.Flows{Items: flowsToDelete}, ofp.FlowGroups{Items: flowGroups})
1183 if err != nil {
1184 return err
1185 }
Girish Kumarf56a4682020-03-20 20:07:46 +00001186 logger.Debugw("rules", log.Fields{"rules": deviceRules.String()})
khenaidoo0458db62019-06-20 08:50:36 -04001187
npujar467fe752020-01-16 20:17:45 +05301188 if err := agent.updateLogicalDeviceFlowsWithoutLock(ctx, &ofp.Flows{Items: flows}); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001189 logger.Errorw("cannot-update-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo19d7b632018-10-30 10:49:50 -04001190 return err
1191 }
khenaidoo442e7c72020-03-10 16:13:48 -04001192
1193 // Update the devices
1194 respChnls := agent.deleteFlowsAndGroupsFromDevices(ctx, deviceRules, &flowMetadata)
1195
1196 // Wait for completion
1197 go func() {
1198 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001199 logger.Warnw("failure-deleting-device-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "errors": res})
khenaidoo442e7c72020-03-10 16:13:48 -04001200 //TODO: Revert flow changes
1201 }
1202 }()
khenaidoo19d7b632018-10-30 10:49:50 -04001203 }
khenaidoo19d7b632018-10-30 10:49:50 -04001204 return nil
1205}
1206
1207//flowModify modifies a flow from the flow table of that logical device
1208func (agent *LogicalDeviceAgent) flowModify(mod *ofp.OfpFlowMod) error {
1209 return errors.New("flowModify not implemented")
1210}
1211
1212//flowModifyStrict deletes a flow from the flow table of that logical device
1213func (agent *LogicalDeviceAgent) flowModifyStrict(mod *ofp.OfpFlowMod) error {
1214 return errors.New("flowModifyStrict not implemented")
1215}
1216
npujar467fe752020-01-16 20:17:45 +05301217func (agent *LogicalDeviceAgent) groupAdd(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +00001218 logger.Debug("groupAdd")
khenaidoo19d7b632018-10-30 10:49:50 -04001219 if groupMod == nil {
1220 return nil
1221 }
khenaidoo442e7c72020-03-10 16:13:48 -04001222 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1223 return err
1224 }
1225 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -04001226
khenaidoo6e55d9e2019-12-12 18:26:26 -05001227 lDevice := agent.getLogicalDeviceWithoutLock()
1228
khenaidoo19d7b632018-10-30 10:49:50 -04001229 groups := lDevice.FlowGroups.Items
khenaidoo19d7b632018-10-30 10:49:50 -04001230 if fu.FindGroup(groups, groupMod.GroupId) == -1 {
khenaidoo68c930b2019-05-13 11:46:51 -04001231 groups = append(groups, fu.GroupEntryFromGroupMod(groupMod))
khenaidoo0458db62019-06-20 08:50:36 -04001232
Esin Karaman2ea59212019-12-06 11:41:58 +00001233 deviceRules := fu.NewDeviceRules()
1234 deviceRules.CreateEntryIfNotExist(agent.rootDeviceID)
1235 fg := fu.NewFlowsAndGroups()
1236 fg.AddGroup(fu.GroupEntryFromGroupMod(groupMod))
1237 deviceRules.AddFlowsAndGroup(agent.rootDeviceID, fg)
1238
Girish Kumarf56a4682020-03-20 20:07:46 +00001239 logger.Debugw("rules", log.Fields{"rules for group-add": deviceRules.String()})
khenaidoo0458db62019-06-20 08:50:36 -04001240
npujar467fe752020-01-16 20:17:45 +05301241 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(ctx, &ofp.FlowGroups{Items: groups}); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001242 logger.Errorw("cannot-update-group", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo19d7b632018-10-30 10:49:50 -04001243 return err
1244 }
khenaidoo442e7c72020-03-10 16:13:48 -04001245
1246 // Update the devices
1247 respChnls := agent.addFlowsAndGroupsToDevices(ctx, deviceRules, &voltha.FlowMetadata{})
1248
1249 // Wait for completion
1250 go func() {
1251 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001252 logger.Warnw("failure-updating-device-flows-groups", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "errors": res})
khenaidoo442e7c72020-03-10 16:13:48 -04001253 //TODO: Revert flow changes
1254 }
1255 }()
1256 return nil
khenaidoo19d7b632018-10-30 10:49:50 -04001257 }
khenaidoo442e7c72020-03-10 16:13:48 -04001258 return fmt.Errorf("Groups %d already present", groupMod.GroupId)
khenaidoo19d7b632018-10-30 10:49:50 -04001259}
1260
npujar467fe752020-01-16 20:17:45 +05301261func (agent *LogicalDeviceAgent) groupDelete(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +00001262 logger.Debug("groupDelete")
khenaidoo19d7b632018-10-30 10:49:50 -04001263 if groupMod == nil {
1264 return nil
1265 }
khenaidoo442e7c72020-03-10 16:13:48 -04001266 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1267 return err
1268 }
1269 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -04001270
khenaidoo6e55d9e2019-12-12 18:26:26 -05001271 lDevice := agent.getLogicalDeviceWithoutLock()
khenaidoo19d7b632018-10-30 10:49:50 -04001272 groups := lDevice.FlowGroups.Items
1273 flows := lDevice.Flows.Items
npujar1d86a522019-11-14 17:11:16 +05301274 var groupsChanged bool
khenaidoo19d7b632018-10-30 10:49:50 -04001275 flowsChanged := false
npujar1d86a522019-11-14 17:11:16 +05301276 groupID := groupMod.GroupId
1277 if groupID == uint32(ofp.OfpGroup_OFPG_ALL) {
khenaidoo19d7b632018-10-30 10:49:50 -04001278 //TODO we must delete all flows that point to this group and
1279 //signal controller as requested by flow's flag
1280 groups = []*ofp.OfpGroupEntry{}
1281 groupsChanged = true
1282 } else {
npujar1d86a522019-11-14 17:11:16 +05301283 idx := fu.FindGroup(groups, groupID)
1284 if idx == -1 {
khenaidoo19d7b632018-10-30 10:49:50 -04001285 return nil // Valid case
khenaidoo19d7b632018-10-30 10:49:50 -04001286 }
npujar1d86a522019-11-14 17:11:16 +05301287 flowsChanged, flows = fu.FlowsDeleteByGroupId(flows, groupID)
1288 groups = append(groups[:idx], groups[idx+1:]...)
1289 groupsChanged = true
khenaidoo19d7b632018-10-30 10:49:50 -04001290 }
khenaidoo0458db62019-06-20 08:50:36 -04001291 if flowsChanged || groupsChanged {
khenaidoo820197c2020-02-13 16:35:33 -05001292 deviceRules, err := agent.flowDecomposer.DecomposeRules(ctx, agent, ofp.Flows{Items: flows}, ofp.FlowGroups{Items: groups})
1293 if err != nil {
1294 return err
1295 }
Girish Kumarf56a4682020-03-20 20:07:46 +00001296 logger.Debugw("rules", log.Fields{"rules": deviceRules.String()})
khenaidoo0458db62019-06-20 08:50:36 -04001297
khenaidoo442e7c72020-03-10 16:13:48 -04001298 if groupsChanged {
1299 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(ctx, &ofp.FlowGroups{Items: groups}); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001300 logger.Errorw("cannot-update-group", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo442e7c72020-03-10 16:13:48 -04001301 return err
1302 }
khenaidoo0458db62019-06-20 08:50:36 -04001303 }
khenaidoo442e7c72020-03-10 16:13:48 -04001304 if flowsChanged {
1305 if err := agent.updateLogicalDeviceFlowsWithoutLock(ctx, &ofp.Flows{Items: flows}); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001306 logger.Errorw("cannot-update-flow", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo442e7c72020-03-10 16:13:48 -04001307 return err
1308 }
1309 }
khenaidoo0458db62019-06-20 08:50:36 -04001310
khenaidoo442e7c72020-03-10 16:13:48 -04001311 // Update the devices
1312 respChnls := agent.updateFlowsAndGroupsOfDevice(ctx, deviceRules, nil)
1313
1314 // Wait for completion
1315 go func() {
1316 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001317 logger.Warnw("failure-updating-device-flows-groups", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "errors": res})
khenaidoo442e7c72020-03-10 16:13:48 -04001318 //TODO: Revert flow changes
1319 }
1320 }()
khenaidoo43c82122018-11-22 18:38:28 -05001321 }
khenaidoo19d7b632018-10-30 10:49:50 -04001322 return nil
1323}
1324
npujar467fe752020-01-16 20:17:45 +05301325func (agent *LogicalDeviceAgent) groupModify(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +00001326 logger.Debug("groupModify")
khenaidoo19d7b632018-10-30 10:49:50 -04001327 if groupMod == nil {
1328 return nil
1329 }
khenaidoo442e7c72020-03-10 16:13:48 -04001330 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1331 return err
1332 }
1333 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -04001334
khenaidoo6e55d9e2019-12-12 18:26:26 -05001335 lDevice := agent.getLogicalDeviceWithoutLock()
khenaidoo19d7b632018-10-30 10:49:50 -04001336 groups := lDevice.FlowGroups.Items
npujar1d86a522019-11-14 17:11:16 +05301337 var groupsChanged bool
1338 groupID := groupMod.GroupId
1339 idx := fu.FindGroup(groups, groupID)
1340 if idx == -1 {
1341 return fmt.Errorf("group-absent:%d", groupID)
khenaidoo19d7b632018-10-30 10:49:50 -04001342 }
npujar1d86a522019-11-14 17:11:16 +05301343 //replace existing group entry with new group definition
1344 groupEntry := fu.GroupEntryFromGroupMod(groupMod)
1345 groups[idx] = groupEntry
1346 groupsChanged = true
khenaidoo19d7b632018-10-30 10:49:50 -04001347 if groupsChanged {
Esin Karaman2ea59212019-12-06 11:41:58 +00001348 deviceRules := fu.NewDeviceRules()
1349 deviceRules.CreateEntryIfNotExist(agent.rootDeviceID)
1350 fg := fu.NewFlowsAndGroups()
1351 fg.AddGroup(fu.GroupEntryFromGroupMod(groupMod))
1352 deviceRules.AddFlowsAndGroup(agent.rootDeviceID, fg)
khenaidoo0458db62019-06-20 08:50:36 -04001353
Girish Kumarf56a4682020-03-20 20:07:46 +00001354 logger.Debugw("rules", log.Fields{"rules for group-modify": deviceRules.String()})
khenaidoo0458db62019-06-20 08:50:36 -04001355
npujar467fe752020-01-16 20:17:45 +05301356 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(ctx, &ofp.FlowGroups{Items: groups}); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001357 logger.Errorw("Cannot-update-logical-group", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo19d7b632018-10-30 10:49:50 -04001358 return err
1359 }
khenaidoo442e7c72020-03-10 16:13:48 -04001360
1361 // Update the devices
1362 respChnls := agent.updateFlowsAndGroupsOfDevice(ctx, deviceRules, &voltha.FlowMetadata{})
1363
1364 // Wait for completion
1365 go func() {
1366 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001367 logger.Warnw("failure-updating-device-flows-groups", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "errors": res})
khenaidoo442e7c72020-03-10 16:13:48 -04001368 //TODO: Revert flow changes
1369 }
1370 }()
khenaidoo19d7b632018-10-30 10:49:50 -04001371 }
1372 return nil
1373}
1374
1375// deleteLogicalPort removes the logical port
npujar467fe752020-01-16 20:17:45 +05301376func (agent *LogicalDeviceAgent) deleteLogicalPort(ctx context.Context, lPort *voltha.LogicalPort) error {
khenaidoo442e7c72020-03-10 16:13:48 -04001377 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1378 return err
1379 }
1380 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -04001381
khenaidoo6e55d9e2019-12-12 18:26:26 -05001382 logicalDevice := agent.getLogicalDeviceWithoutLock()
1383
khenaidoo92e62c52018-10-03 14:02:54 -04001384 index := -1
khenaidoo6e55d9e2019-12-12 18:26:26 -05001385 for i, logicalPort := range logicalDevice.Ports {
khenaidoo19d7b632018-10-30 10:49:50 -04001386 if logicalPort.Id == lPort.Id {
khenaidoo92e62c52018-10-03 14:02:54 -04001387 index = i
1388 break
1389 }
1390 }
1391 if index >= 0 {
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001392 clonedPorts := clonePorts(logicalDevice.Ports)
1393 if index < len(clonedPorts)-1 {
1394 copy(clonedPorts[index:], clonedPorts[index+1:])
1395 }
1396 clonedPorts[len(clonedPorts)-1] = nil
1397 clonedPorts = clonedPorts[:len(clonedPorts)-1]
Girish Kumarf56a4682020-03-20 20:07:46 +00001398 logger.Debugw("logical-port-deleted", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001399 if err := agent.updateLogicalDevicePortsWithoutLock(ctx, logicalDevice, clonedPorts); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001400 logger.Errorw("logical-device-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo0a822f92019-05-08 15:15:57 -04001401 return err
1402 }
khenaidoo820197c2020-02-13 16:35:33 -05001403
1404 // Remove the logical port from cache
1405 agent.deleteLogicalPortsFromMap([]uint32{lPort.DevicePortNo})
1406
1407 // Reset the logical device routes
1408 go func() {
1409 if err := agent.buildRoutes(context.Background()); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001410 logger.Warnw("device-routes-not-ready", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "error": err})
khenaidoo820197c2020-02-13 16:35:33 -05001411 }
1412 }()
khenaidoo92e62c52018-10-03 14:02:54 -04001413 }
1414 return nil
khenaidoob9203542018-09-17 22:56:37 -04001415}
1416
khenaidoo0a822f92019-05-08 15:15:57 -04001417// deleteLogicalPorts removes the logical ports associated with that deviceId
npujar467fe752020-01-16 20:17:45 +05301418func (agent *LogicalDeviceAgent) deleteLogicalPorts(ctx context.Context, deviceID string) error {
Andrea Campanella09400bd2020-04-02 11:58:04 +02001419 logger.Debugw("deleting-logical-ports", log.Fields{"device-id": deviceID})
khenaidoo442e7c72020-03-10 16:13:48 -04001420 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1421 return err
1422 }
1423 defer agent.requestQueue.RequestComplete()
khenaidoo0a822f92019-05-08 15:15:57 -04001424
khenaidoo6e55d9e2019-12-12 18:26:26 -05001425 logicalDevice := agent.getLogicalDeviceWithoutLock()
khenaidoo820197c2020-02-13 16:35:33 -05001426 lPortstoKeep := []*voltha.LogicalPort{}
1427 lPortsNoToDelete := []uint32{}
khenaidoo6e55d9e2019-12-12 18:26:26 -05001428 for _, logicalPort := range logicalDevice.Ports {
npujar1d86a522019-11-14 17:11:16 +05301429 if logicalPort.DeviceId != deviceID {
khenaidoo820197c2020-02-13 16:35:33 -05001430 lPortstoKeep = append(lPortstoKeep, logicalPort)
1431 } else {
1432 lPortsNoToDelete = append(lPortsNoToDelete, logicalPort.DevicePortNo)
khenaidoo0a822f92019-05-08 15:15:57 -04001433 }
1434 }
Andrea Campanella09400bd2020-04-02 11:58:04 +02001435 logger.Debugw("deleted-logical-ports", log.Fields{"ports": lPortstoKeep})
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001436 if err := agent.updateLogicalDevicePortsWithoutLock(ctx, logicalDevice, lPortstoKeep); err != nil {
Andrea Campanella09400bd2020-04-02 11:58:04 +02001437 logger.Errorw("logical-device-update-failed", log.Fields{"logical-device-id": agent.logicalDeviceID})
khenaidoo0a822f92019-05-08 15:15:57 -04001438 return err
1439 }
khenaidoo820197c2020-02-13 16:35:33 -05001440 // Remove the port from the cached logical ports set
1441 agent.deleteLogicalPortsFromMap(lPortsNoToDelete)
1442
1443 // Reset the logical device routes
1444 go func() {
1445 if err := agent.buildRoutes(context.Background()); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001446 logger.Warnw("routes-not-ready", log.Fields{"logical-device-id": agent.logicalDeviceID, "error": err})
khenaidoo820197c2020-02-13 16:35:33 -05001447 }
1448 }()
khenaidoo0a822f92019-05-08 15:15:57 -04001449
1450 return nil
1451}
1452
khenaidoo19d7b632018-10-30 10:49:50 -04001453// enableLogicalPort enables the logical port
npujar467fe752020-01-16 20:17:45 +05301454func (agent *LogicalDeviceAgent) enableLogicalPort(ctx context.Context, lPortID string) error {
khenaidoo442e7c72020-03-10 16:13:48 -04001455 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1456 return err
1457 }
1458 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -04001459
khenaidoo6e55d9e2019-12-12 18:26:26 -05001460 logicalDevice := agent.getLogicalDeviceWithoutLock()
1461
khenaidoo19d7b632018-10-30 10:49:50 -04001462 index := -1
khenaidoo6e55d9e2019-12-12 18:26:26 -05001463 for i, logicalPort := range logicalDevice.Ports {
npujar1d86a522019-11-14 17:11:16 +05301464 if logicalPort.Id == lPortID {
khenaidoo19d7b632018-10-30 10:49:50 -04001465 index = i
1466 break
1467 }
1468 }
1469 if index >= 0 {
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001470 clonedPorts := clonePorts(logicalDevice.Ports)
1471 clonedPorts[index].OfpPort.Config = clonedPorts[index].OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
1472 return agent.updateLogicalDevicePortsWithoutLock(ctx, logicalDevice, clonedPorts)
khenaidoo19d7b632018-10-30 10:49:50 -04001473 }
npujar1d86a522019-11-14 17:11:16 +05301474 return status.Errorf(codes.NotFound, "Port %s on Logical Device %s", lPortID, agent.logicalDeviceID)
khenaidoo19d7b632018-10-30 10:49:50 -04001475}
1476
1477// disableLogicalPort disabled the logical port
npujar467fe752020-01-16 20:17:45 +05301478func (agent *LogicalDeviceAgent) disableLogicalPort(ctx context.Context, lPortID string) error {
khenaidoo442e7c72020-03-10 16:13:48 -04001479 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1480 return err
1481 }
1482 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -04001483
1484 // Get the most up to date logical device
khenaidoo6e55d9e2019-12-12 18:26:26 -05001485 logicalDevice := agent.getLogicalDeviceWithoutLock()
khenaidoo19d7b632018-10-30 10:49:50 -04001486 index := -1
khenaidoo6e55d9e2019-12-12 18:26:26 -05001487 for i, logicalPort := range logicalDevice.Ports {
npujar1d86a522019-11-14 17:11:16 +05301488 if logicalPort.Id == lPortID {
khenaidoo19d7b632018-10-30 10:49:50 -04001489 index = i
1490 break
1491 }
1492 }
1493 if index >= 0 {
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001494 clonedPorts := clonePorts(logicalDevice.Ports)
1495 clonedPorts[index].OfpPort.Config = (clonedPorts[index].OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)) | uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
1496 return agent.updateLogicalDevicePortsWithoutLock(ctx, logicalDevice, clonedPorts)
khenaidoo19d7b632018-10-30 10:49:50 -04001497 }
npujar1d86a522019-11-14 17:11:16 +05301498 return status.Errorf(codes.NotFound, "Port %s on Logical Device %s", lPortID, agent.logicalDeviceID)
khenaidoo19d7b632018-10-30 10:49:50 -04001499}
1500
khenaidoo820197c2020-02-13 16:35:33 -05001501func (agent *LogicalDeviceAgent) getPreCalculatedRoute(ingress, egress uint32) ([]route.Hop, error) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001502 logger.Debugw("ROUTE", log.Fields{"len": len(agent.deviceRoutes.Routes)})
khenaidoo820197c2020-02-13 16:35:33 -05001503 for routeLink, route := range agent.deviceRoutes.Routes {
Girish Kumarf56a4682020-03-20 20:07:46 +00001504 logger.Debugw("ROUTELINKS", log.Fields{"ingress": ingress, "egress": egress, "routelink": routeLink})
khenaidoo89b0e942018-10-21 21:11:33 -04001505 if ingress == routeLink.Ingress && egress == routeLink.Egress {
khenaidoo820197c2020-02-13 16:35:33 -05001506 return route, nil
khenaidoo89b0e942018-10-21 21:11:33 -04001507 }
1508 }
khenaidoo820197c2020-02-13 16:35:33 -05001509 return nil, status.Errorf(codes.FailedPrecondition, "no route from:%d to:%d", ingress, egress)
khenaidoo89b0e942018-10-21 21:11:33 -04001510}
1511
npujar1d86a522019-11-14 17:11:16 +05301512// GetRoute returns route
khenaidoo820197c2020-02-13 16:35:33 -05001513func (agent *LogicalDeviceAgent) GetRoute(ctx context.Context, ingressPortNo uint32, egressPortNo uint32) ([]route.Hop, error) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001514 logger.Debugw("getting-route", log.Fields{"ingress-port": ingressPortNo, "egress-port": egressPortNo})
khenaidoo820197c2020-02-13 16:35:33 -05001515 routes := make([]route.Hop, 0)
khenaidoo2c6a0992019-04-29 13:46:56 -04001516
khenaidoo19d7b632018-10-30 10:49:50 -04001517 // Note: A port value of 0 is equivalent to a nil port
1518
khenaidoo89b0e942018-10-21 21:11:33 -04001519 // Consider different possibilities
khenaidoo19d7b632018-10-30 10:49:50 -04001520 if egressPortNo != 0 && ((egressPortNo & 0x7fffffff) == uint32(ofp.OfpPortNo_OFPP_CONTROLLER)) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001521 logger.Debugw("controller-flow", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "logicalPortsNo": agent.logicalPortsNo})
khenaidoo2c6a0992019-04-29 13:46:56 -04001522 if agent.isNNIPort(ingressPortNo) {
khenaidoo89b0e942018-10-21 21:11:33 -04001523 //This is a trap on the NNI Port
khenaidoo820197c2020-02-13 16:35:33 -05001524 if len(agent.deviceRoutes.Routes) == 0 {
khenaidoo8f474192019-04-03 17:20:44 -04001525 // 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 -04001526 // route with same IngressHop and EgressHop
khenaidoo820197c2020-02-13 16:35:33 -05001527 hop := route.Hop{DeviceID: agent.rootDeviceID, Ingress: ingressPortNo, Egress: ingressPortNo}
khenaidoo8f474192019-04-03 17:20:44 -04001528 routes = append(routes, hop)
1529 routes = append(routes, hop)
khenaidoo820197c2020-02-13 16:35:33 -05001530 return routes, nil
khenaidoo8f474192019-04-03 17:20:44 -04001531 }
khenaidoo89b0e942018-10-21 21:11:33 -04001532 //Return a 'half' route to make the flow decomposer logic happy
khenaidoo820197c2020-02-13 16:35:33 -05001533 for routeLink, path := range agent.deviceRoutes.Routes {
khenaidoo2c6a0992019-04-29 13:46:56 -04001534 if agent.isNNIPort(routeLink.Egress) {
khenaidoo820197c2020-02-13 16:35:33 -05001535 routes = append(routes, route.Hop{}) // first hop is set to empty
1536 routes = append(routes, path[1])
1537 return routes, nil
khenaidoo89b0e942018-10-21 21:11:33 -04001538 }
1539 }
khenaidoo820197c2020-02-13 16:35:33 -05001540 return nil, status.Errorf(codes.FailedPrecondition, "no upstream route from:%d to:%d", ingressPortNo, egressPortNo)
khenaidoo89b0e942018-10-21 21:11:33 -04001541 }
1542 //treat it as if the output port is the first NNI of the OLT
khenaidoo2c6a0992019-04-29 13:46:56 -04001543 var err error
1544 if egressPortNo, err = agent.getFirstNNIPort(); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001545 logger.Warnw("no-nni-port", log.Fields{"error": err})
khenaidoo820197c2020-02-13 16:35:33 -05001546 return nil, err
khenaidoo2c6a0992019-04-29 13:46:56 -04001547 }
khenaidoo89b0e942018-10-21 21:11:33 -04001548 }
1549 //If ingress port is not specified (nil), it may be a wildcarded
1550 //route if egress port is OFPP_CONTROLLER or a nni logical port,
1551 //in which case we need to create a half-route where only the egress
1552 //hop is filled, the first hop is nil
khenaidoo2c6a0992019-04-29 13:46:56 -04001553 if ingressPortNo == 0 && agent.isNNIPort(egressPortNo) {
khenaidoo89b0e942018-10-21 21:11:33 -04001554 // We can use the 2nd hop of any upstream route, so just find the first upstream:
khenaidoo820197c2020-02-13 16:35:33 -05001555 for routeLink, path := range agent.deviceRoutes.Routes {
khenaidoo2c6a0992019-04-29 13:46:56 -04001556 if agent.isNNIPort(routeLink.Egress) {
khenaidoo820197c2020-02-13 16:35:33 -05001557 routes = append(routes, route.Hop{}) // first hop is set to empty
1558 routes = append(routes, path[1])
1559 return routes, nil
khenaidoo89b0e942018-10-21 21:11:33 -04001560 }
1561 }
khenaidoo820197c2020-02-13 16:35:33 -05001562 return nil, status.Errorf(codes.FailedPrecondition, "no upstream route from:%d to:%d", ingressPortNo, egressPortNo)
khenaidoo89b0e942018-10-21 21:11:33 -04001563 }
1564 //If egress port is not specified (nil), we can also can return a "half" route
khenaidoo19d7b632018-10-30 10:49:50 -04001565 if egressPortNo == 0 {
khenaidoo820197c2020-02-13 16:35:33 -05001566 for routeLink, path := range agent.deviceRoutes.Routes {
khenaidoo19d7b632018-10-30 10:49:50 -04001567 if routeLink.Ingress == ingressPortNo {
khenaidoo820197c2020-02-13 16:35:33 -05001568 routes = append(routes, path[0])
1569 routes = append(routes, route.Hop{})
1570 return routes, nil
khenaidoo89b0e942018-10-21 21:11:33 -04001571 }
1572 }
khenaidoo820197c2020-02-13 16:35:33 -05001573 return nil, status.Errorf(codes.FailedPrecondition, "no downstream route from:%d to:%d", ingressPortNo, egressPortNo)
khenaidoo89b0e942018-10-21 21:11:33 -04001574 }
khenaidoo89b0e942018-10-21 21:11:33 -04001575 // Return the pre-calculated route
khenaidoo19d7b632018-10-30 10:49:50 -04001576 return agent.getPreCalculatedRoute(ingressPortNo, egressPortNo)
khenaidoo89b0e942018-10-21 21:11:33 -04001577}
1578
khenaidoo3d3b8c22019-05-22 18:10:39 -04001579//GetWildcardInputPorts filters out the logical port number from the set of logical ports on the device and
1580//returns their port numbers. This function is invoked only during flow decomposition where the lock on the logical
1581//device is already held. Therefore it is safe to retrieve the logical device without lock.
khenaidoo89b0e942018-10-21 21:11:33 -04001582func (agent *LogicalDeviceAgent) GetWildcardInputPorts(excludePort ...uint32) []uint32 {
1583 lPorts := make([]uint32, 0)
1584 var exclPort uint32
1585 if len(excludePort) == 1 {
1586 exclPort = excludePort[0]
1587 }
khenaidoo6e55d9e2019-12-12 18:26:26 -05001588 lDevice := agent.getLogicalDeviceWithoutLock()
1589 for _, port := range lDevice.Ports {
1590 if port.OfpPort.PortNo != exclPort {
1591 lPorts = append(lPorts, port.OfpPort.PortNo)
khenaidoo89b0e942018-10-21 21:11:33 -04001592 }
1593 }
1594 return lPorts
1595}
khenaidoo19d7b632018-10-30 10:49:50 -04001596
khenaidoo820197c2020-02-13 16:35:33 -05001597// GetDeviceRoutes returns device graph
1598func (agent *LogicalDeviceAgent) GetDeviceRoutes() *route.DeviceRoutes {
1599 return agent.deviceRoutes
khenaidoo19d7b632018-10-30 10:49:50 -04001600}
1601
khenaidoo820197c2020-02-13 16:35:33 -05001602//rebuildRoutes rebuilds the device routes
1603func (agent *LogicalDeviceAgent) buildRoutes(ctx context.Context) error {
Girish Kumarf56a4682020-03-20 20:07:46 +00001604 logger.Debugf("building-routes", log.Fields{"logical-device-id": agent.logicalDeviceID})
khenaidoo442e7c72020-03-10 16:13:48 -04001605 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1606 return err
1607 }
1608 defer agent.requestQueue.RequestComplete()
1609
khenaidoo820197c2020-02-13 16:35:33 -05001610 if agent.deviceRoutes == nil {
1611 agent.deviceRoutes = route.NewDeviceRoutes(agent.logicalDeviceID, agent.deviceMgr.GetDevice)
khenaidoo2c6a0992019-04-29 13:46:56 -04001612 }
1613 // Get all the logical ports on that logical device
khenaidoo6e55d9e2019-12-12 18:26:26 -05001614 lDevice := agent.getLogicalDeviceWithoutLock()
1615
khenaidoo820197c2020-02-13 16:35:33 -05001616 if err := agent.deviceRoutes.ComputeRoutes(ctx, lDevice.Ports); err != nil {
1617 return err
1618 }
1619 if err := agent.deviceRoutes.Print(); err != nil {
1620 return err
1621 }
1622
khenaidoo2c6a0992019-04-29 13:46:56 -04001623 return nil
khenaidoo19d7b632018-10-30 10:49:50 -04001624}
1625
khenaidoo820197c2020-02-13 16:35:33 -05001626//updateRoutes updates the device routes
1627func (agent *LogicalDeviceAgent) updateRoutes(ctx context.Context, lp *voltha.LogicalPort) error {
Girish Kumarf56a4682020-03-20 20:07:46 +00001628 logger.Debugw("updateRoutes", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo442e7c72020-03-10 16:13:48 -04001629 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1630 return err
1631 }
1632 defer agent.requestQueue.RequestComplete()
1633
khenaidoo820197c2020-02-13 16:35:33 -05001634 if agent.deviceRoutes == nil {
1635 agent.deviceRoutes = route.NewDeviceRoutes(agent.logicalDeviceID, agent.deviceMgr.GetDevice)
khenaidoo910204f2019-04-08 17:56:40 -04001636 }
khenaidoo820197c2020-02-13 16:35:33 -05001637 if err := agent.deviceRoutes.AddPort(ctx, lp, agent.logicalDevice.Ports); err != nil {
1638 return err
khenaidoo0a822f92019-05-08 15:15:57 -04001639 }
khenaidoo820197c2020-02-13 16:35:33 -05001640 if err := agent.deviceRoutes.Print(); err != nil {
1641 return err
1642 }
1643 return nil
khenaidoo0a822f92019-05-08 15:15:57 -04001644}
1645
khenaidoofc1314d2019-03-14 09:34:21 -04001646// 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 -04001647func diff(oldList, newList []*voltha.LogicalPort) (newPorts, changedPorts, deletedPorts []*voltha.LogicalPort) {
khenaidoofc1314d2019-03-14 09:34:21 -04001648 newPorts = make([]*voltha.LogicalPort, 0)
1649 changedPorts = make([]*voltha.LogicalPort, 0)
1650 deletedPorts = make([]*voltha.LogicalPort, 0)
1651 for _, o := range oldList {
1652 found := false
khenaidoofc1314d2019-03-14 09:34:21 -04001653 for _, n := range newList {
1654 if o.Id == n.Id {
khenaidoofc1314d2019-03-14 09:34:21 -04001655 found = true
1656 break
1657 }
1658 }
1659 if !found {
1660 deletedPorts = append(deletedPorts, o)
1661 }
khenaidoofc1314d2019-03-14 09:34:21 -04001662 }
1663 for _, n := range newList {
1664 found := false
khenaidoo2bc48282019-07-16 18:13:46 -04001665 changed := false
khenaidoofc1314d2019-03-14 09:34:21 -04001666 for _, o := range oldList {
1667 if o.Id == n.Id {
khenaidoo2bc48282019-07-16 18:13:46 -04001668 changed = !reflect.DeepEqual(o, n)
khenaidoofc1314d2019-03-14 09:34:21 -04001669 found = true
1670 break
1671 }
1672 }
1673 if !found {
1674 newPorts = append(newPorts, n)
1675 }
khenaidoo2bc48282019-07-16 18:13:46 -04001676 if changed {
1677 changedPorts = append(changedPorts, n)
1678 }
khenaidoofc1314d2019-03-14 09:34:21 -04001679 }
1680 return
1681}
1682
1683// portUpdated is invoked when a port is updated on the logical device. Until
1684// the POST_ADD notification is fixed, we will use the logical device to
1685// update that data.
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001686func (agent *LogicalDeviceAgent) portUpdated(oldPorts, newPorts []*voltha.LogicalPort) interface{} {
1687 if reflect.DeepEqual(oldPorts, newPorts) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001688 logger.Debug("ports-have-not-changed")
khenaidoofc1314d2019-03-14 09:34:21 -04001689 return nil
1690 }
1691
1692 // Get the difference between the two list
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001693 newPorts, changedPorts, deletedPorts := diff(oldPorts, newPorts)
khenaidoofc1314d2019-03-14 09:34:21 -04001694
1695 // Send the port change events to the OF controller
khenaidoo2c6a0992019-04-29 13:46:56 -04001696 for _, newP := range newPorts {
npujar1d86a522019-11-14 17:11:16 +05301697 go agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceID,
khenaidoo2c6a0992019-04-29 13:46:56 -04001698 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_ADD, Desc: newP.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001699 }
1700 for _, change := range changedPorts {
npujar1d86a522019-11-14 17:11:16 +05301701 go agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceID,
khenaidoo910204f2019-04-08 17:56:40 -04001702 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_MODIFY, Desc: change.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001703 }
1704 for _, del := range deletedPorts {
npujar1d86a522019-11-14 17:11:16 +05301705 go agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceID,
khenaidoo910204f2019-04-08 17:56:40 -04001706 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_DELETE, Desc: del.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001707 }
1708
1709 return nil
1710}
1711
khenaidoo8f474192019-04-03 17:20:44 -04001712// addNNILogicalPort adds an NNI port to the logical device. It returns a bool representing whether a port has been
1713// added and an eror in case a valid error is encountered. If the port was successfully added it will return
1714// (true, nil). If the device is not in the correct state it will return (false, nil) as this is a valid
1715// scenario. This also applies to the case where the port was already added.
npujar467fe752020-01-16 20:17:45 +05301716func (agent *LogicalDeviceAgent) addNNILogicalPort(ctx context.Context, device *voltha.Device, port *voltha.Port) (bool, error) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001717 logger.Debugw("addNNILogicalPort", log.Fields{"NNI": port})
khenaidoo8f474192019-04-03 17:20:44 -04001718 if device.AdminState != voltha.AdminState_ENABLED || device.OperStatus != voltha.OperStatus_ACTIVE {
Girish Kumarf56a4682020-03-20 20:07:46 +00001719 logger.Infow("device-not-ready", log.Fields{"deviceId": device.Id, "admin": device.AdminState, "oper": device.OperStatus})
khenaidoo8f474192019-04-03 17:20:44 -04001720 return false, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001721 }
khenaidoo442e7c72020-03-10 16:13:48 -04001722 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1723 return false, err
1724 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001725 if agent.portExist(device, port) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001726 logger.Debugw("port-already-exist", log.Fields{"port": port})
khenaidoo442e7c72020-03-10 16:13:48 -04001727 agent.requestQueue.RequestComplete()
khenaidoo8f474192019-04-03 17:20:44 -04001728 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001729 }
khenaidoo442e7c72020-03-10 16:13:48 -04001730 agent.requestQueue.RequestComplete()
khenaidoo1ce37ad2019-03-24 22:07:24 -04001731
khenaidoofc1314d2019-03-14 09:34:21 -04001732 var portCap *ic.PortCapability
1733 var err error
1734 // First get the port capability
npujar467fe752020-01-16 20:17:45 +05301735 if portCap, err = agent.deviceMgr.getPortCapability(ctx, device.Id, port.PortNo); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001736 logger.Errorw("error-retrieving-port-capabilities", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001737 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001738 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001739
khenaidoo442e7c72020-03-10 16:13:48 -04001740 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1741 return false, err
1742 }
1743
1744 defer agent.requestQueue.RequestComplete()
khenaidoo1ce37ad2019-03-24 22:07:24 -04001745 // Double check again if this port has been already added since the getPortCapability could have taken a long time
1746 if agent.portExist(device, port) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001747 logger.Debugw("port-already-exist", log.Fields{"port": port})
khenaidoo8f474192019-04-03 17:20:44 -04001748 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001749 }
1750
khenaidoofc1314d2019-03-14 09:34:21 -04001751 portCap.Port.RootPort = true
1752 lp := (proto.Clone(portCap.Port)).(*voltha.LogicalPort)
1753 lp.DeviceId = device.Id
1754 lp.Id = fmt.Sprintf("nni-%d", port.PortNo)
1755 lp.OfpPort.PortNo = port.PortNo
1756 lp.OfpPort.Name = lp.Id
1757 lp.DevicePortNo = port.PortNo
1758
khenaidoo6e55d9e2019-12-12 18:26:26 -05001759 ld := agent.getLogicalDeviceWithoutLock()
1760
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001761 clonedPorts := clonePorts(ld.Ports)
1762 if clonedPorts == nil {
1763 clonedPorts = make([]*voltha.LogicalPort, 0)
khenaidoofc1314d2019-03-14 09:34:21 -04001764 }
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001765 clonedPorts = append(clonedPorts, lp)
khenaidoofc1314d2019-03-14 09:34:21 -04001766
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001767 if err = agent.updateLogicalDevicePortsWithoutLock(ctx, ld, clonedPorts); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001768 logger.Errorw("error-updating-logical-device", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001769 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001770 }
khenaidoo910204f2019-04-08 17:56:40 -04001771
khenaidoo820197c2020-02-13 16:35:33 -05001772 // Update the device routes with this new logical port
khenaidoo910204f2019-04-08 17:56:40 -04001773 clonedLP := (proto.Clone(lp)).(*voltha.LogicalPort)
khenaidoo820197c2020-02-13 16:35:33 -05001774 go func() {
1775 if err := agent.updateRoutes(context.Background(), clonedLP); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001776 logger.Warnw("routes-not-ready", log.Fields{"logical-device-id": agent.logicalDeviceID, "logical-port": lp.OfpPort.PortNo, "error": err})
khenaidoo820197c2020-02-13 16:35:33 -05001777 }
1778 }()
khenaidoo910204f2019-04-08 17:56:40 -04001779
khenaidoo8f474192019-04-03 17:20:44 -04001780 return true, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001781}
1782
khenaidoo910204f2019-04-08 17:56:40 -04001783func (agent *LogicalDeviceAgent) portExist(device *voltha.Device, port *voltha.Port) bool {
khenaidoo6e55d9e2019-12-12 18:26:26 -05001784 ldevice := agent.getLogicalDeviceWithoutLock()
1785 for _, lPort := range ldevice.Ports {
1786 if lPort.DeviceId == device.Id && lPort.DevicePortNo == port.PortNo && lPort.Id == port.Label {
1787 return true
khenaidoofc1314d2019-03-14 09:34:21 -04001788 }
1789 }
1790 return false
1791}
1792
khenaidoo8f474192019-04-03 17:20:44 -04001793// addUNILogicalPort adds an UNI port to the logical device. It returns a bool representing whether a port has been
1794// added and an eror in case a valid error is encountered. If the port was successfully added it will return
1795// (true, nil). If the device is not in the correct state it will return (false, nil) as this is a valid
1796// scenario. This also applies to the case where the port was already added.
npujar467fe752020-01-16 20:17:45 +05301797func (agent *LogicalDeviceAgent) addUNILogicalPort(ctx context.Context, childDevice *voltha.Device, port *voltha.Port) (bool, error) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001798 logger.Debugw("addUNILogicalPort", log.Fields{"port": port})
khenaidoo8f474192019-04-03 17:20:44 -04001799 if childDevice.AdminState != voltha.AdminState_ENABLED || childDevice.OperStatus != voltha.OperStatus_ACTIVE {
Girish Kumarf56a4682020-03-20 20:07:46 +00001800 logger.Infow("device-not-ready", log.Fields{"deviceId": childDevice.Id, "admin": childDevice.AdminState, "oper": childDevice.OperStatus})
khenaidoo8f474192019-04-03 17:20:44 -04001801 return false, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001802 }
khenaidoo442e7c72020-03-10 16:13:48 -04001803 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1804 return false, err
1805 }
1806
khenaidoo1ce37ad2019-03-24 22:07:24 -04001807 if agent.portExist(childDevice, port) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001808 logger.Debugw("port-already-exist", log.Fields{"port": port})
khenaidoo442e7c72020-03-10 16:13:48 -04001809 agent.requestQueue.RequestComplete()
khenaidoo8f474192019-04-03 17:20:44 -04001810 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001811 }
khenaidoo442e7c72020-03-10 16:13:48 -04001812 agent.requestQueue.RequestComplete()
khenaidoofc1314d2019-03-14 09:34:21 -04001813 var portCap *ic.PortCapability
1814 var err error
1815 // First get the port capability
npujar467fe752020-01-16 20:17:45 +05301816 if portCap, err = agent.deviceMgr.getPortCapability(ctx, childDevice.Id, port.PortNo); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001817 logger.Errorw("error-retrieving-port-capabilities", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001818 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001819 }
khenaidoo442e7c72020-03-10 16:13:48 -04001820 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1821 return false, err
1822 }
1823 defer agent.requestQueue.RequestComplete()
khenaidoo1ce37ad2019-03-24 22:07:24 -04001824 // Double check again if this port has been already added since the getPortCapability could have taken a long time
1825 if agent.portExist(childDevice, port) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001826 logger.Debugw("port-already-exist", log.Fields{"port": port})
khenaidoo8f474192019-04-03 17:20:44 -04001827 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001828 }
khenaidoofc1314d2019-03-14 09:34:21 -04001829 // Get stored logical device
khenaidoo6e55d9e2019-12-12 18:26:26 -05001830 ldevice := agent.getLogicalDeviceWithoutLock()
1831
Girish Kumarf56a4682020-03-20 20:07:46 +00001832 logger.Debugw("adding-uni", log.Fields{"deviceId": childDevice.Id})
npujar1d86a522019-11-14 17:11:16 +05301833 portCap.Port.RootPort = false
1834 portCap.Port.Id = port.Label
1835 portCap.Port.OfpPort.PortNo = port.PortNo
1836 portCap.Port.DeviceId = childDevice.Id
1837 portCap.Port.DevicePortNo = port.PortNo
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001838 clonedPorts := clonePorts(ldevice.Ports)
1839 if clonedPorts == nil {
1840 clonedPorts = make([]*voltha.LogicalPort, 0)
npujar1d86a522019-11-14 17:11:16 +05301841 }
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001842 clonedPorts = append(clonedPorts, portCap.Port)
1843 if err := agent.updateLogicalDevicePortsWithoutLock(ctx, ldevice, clonedPorts); err != nil {
npujar1d86a522019-11-14 17:11:16 +05301844 return false, err
1845 }
1846 // Update the device graph with this new logical port
1847 clonedLP := (proto.Clone(portCap.Port)).(*voltha.LogicalPort)
khenaidoo820197c2020-02-13 16:35:33 -05001848
1849 go func() {
1850 if err := agent.updateRoutes(context.Background(), clonedLP); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001851 logger.Warn("routes-not-ready", log.Fields{"logical-device-id": agent.logicalDeviceID, "error": err})
khenaidoo820197c2020-02-13 16:35:33 -05001852 }
1853 }()
1854
npujar1d86a522019-11-14 17:11:16 +05301855 return true, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001856}
1857
npujar467fe752020-01-16 20:17:45 +05301858func (agent *LogicalDeviceAgent) packetOut(ctx context.Context, packet *ofp.OfpPacketOut) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001859 logger.Debugw("packet-out", log.Fields{
Matteo Scandolo360605d2019-11-05 18:29:17 -08001860 "packet": hex.EncodeToString(packet.Data),
1861 "inPort": packet.GetInPort(),
1862 })
khenaidoo68c930b2019-05-13 11:46:51 -04001863 outPort := fu.GetPacketOutPort(packet)
khenaidoofdbad6e2018-11-06 22:26:38 -05001864 //frame := packet.GetData()
1865 //TODO: Use a channel between the logical agent and the device agent
npujar467fe752020-01-16 20:17:45 +05301866 if err := agent.deviceMgr.packetOut(ctx, agent.rootDeviceID, outPort, packet); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001867 logger.Error("packetout-failed", log.Fields{"logicalDeviceID": agent.rootDeviceID})
khenaidooca301322019-01-09 23:06:32 -05001868 }
khenaidoofdbad6e2018-11-06 22:26:38 -05001869}
1870
npujar1d86a522019-11-14 17:11:16 +05301871func (agent *LogicalDeviceAgent) packetIn(port uint32, transactionID string, packet []byte) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001872 logger.Debugw("packet-in", log.Fields{
Matteo Scandolo360605d2019-11-05 18:29:17 -08001873 "port": port,
1874 "packet": hex.EncodeToString(packet),
npujar1d86a522019-11-14 17:11:16 +05301875 "transactionId": transactionID,
Matteo Scandolo360605d2019-11-05 18:29:17 -08001876 })
khenaidoo68c930b2019-05-13 11:46:51 -04001877 packetIn := fu.MkPacketIn(port, packet)
npujar1d86a522019-11-14 17:11:16 +05301878 agent.ldeviceMgr.grpcNbiHdlr.sendPacketIn(agent.logicalDeviceID, transactionID, packetIn)
Girish Kumarf56a4682020-03-20 20:07:46 +00001879 logger.Debugw("sending-packet-in", log.Fields{"packet": hex.EncodeToString(packetIn.Data)})
khenaidoofdbad6e2018-11-06 22:26:38 -05001880}
khenaidoo2c6a0992019-04-29 13:46:56 -04001881
1882func (agent *LogicalDeviceAgent) addLogicalPortToMap(portNo uint32, nniPort bool) {
1883 agent.lockLogicalPortsNo.Lock()
1884 defer agent.lockLogicalPortsNo.Unlock()
1885 if exist := agent.logicalPortsNo[portNo]; !exist {
1886 agent.logicalPortsNo[portNo] = nniPort
1887 }
1888}
1889
khenaidoo820197c2020-02-13 16:35:33 -05001890func (agent *LogicalDeviceAgent) deleteLogicalPortsFromMap(portsNo []uint32) {
1891 agent.lockLogicalPortsNo.Lock()
1892 defer agent.lockLogicalPortsNo.Unlock()