blob: b87b81eb6bad90b9925e7e840c2d43c3a0d89307 [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
Kent Hagerman2b216042020-04-03 18:28:56 -040017package device
khenaidoob9203542018-09-17 22:56:37 -040018
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 "sync"
25 "time"
26
khenaidoob9203542018-09-17 22:56:37 -040027 "github.com/gogo/protobuf/proto"
sbarbari17d7e222019-11-05 10:02:29 -050028 "github.com/opencord/voltha-go/db/model"
npujar1d86a522019-11-14 17:11:16 +053029 fd "github.com/opencord/voltha-go/rw_core/flowdecomposition"
khenaidoo442e7c72020-03-10 16:13:48 -040030 "github.com/opencord/voltha-go/rw_core/route"
Scott Bakerb671a862019-10-24 10:53:40 -070031 coreutils "github.com/opencord/voltha-go/rw_core/utils"
serkant.uluderya2ae470f2020-01-21 11:13:09 -080032 fu "github.com/opencord/voltha-lib-go/v3/pkg/flows"
33 "github.com/opencord/voltha-lib-go/v3/pkg/log"
34 ic "github.com/opencord/voltha-protos/v3/go/inter_container"
35 ofp "github.com/opencord/voltha-protos/v3/go/openflow_13"
36 "github.com/opencord/voltha-protos/v3/go/voltha"
khenaidoob9203542018-09-17 22:56:37 -040037 "google.golang.org/grpc/codes"
38 "google.golang.org/grpc/status"
khenaidoo442e7c72020-03-10 16:13:48 -040039)
40
Kent Hagerman2b216042020-04-03 18:28:56 -040041// LogicalAgent represent attributes of logical device agent
42type LogicalAgent struct {
npujar1d86a522019-11-14 17:11:16 +053043 logicalDeviceID string
David Bainbridged1afd662020-03-26 18:27:41 -070044 serialNumber string
npujar1d86a522019-11-14 17:11:16 +053045 rootDeviceID string
Kent Hagerman2b216042020-04-03 18:28:56 -040046 deviceMgr *Manager
47 ldeviceMgr *LogicalManager
khenaidoo3306c992019-05-24 16:57:35 -040048 clusterDataProxy *model.Proxy
Kent Hagerman4f355f52020-03-30 16:01:33 -040049 stopped bool
khenaidoo820197c2020-02-13 16:35:33 -050050 deviceRoutes *route.DeviceRoutes
khenaidoo820197c2020-02-13 16:35:33 -050051 lockDeviceRoutes sync.RWMutex
khenaidoo3306c992019-05-24 16:57:35 -040052 logicalPortsNo map[uint32]bool //value is true for NNI port
53 lockLogicalPortsNo sync.RWMutex
54 flowDecomposer *fd.FlowDecomposer
khenaidoo442e7c72020-03-10 16:13:48 -040055 defaultTimeout time.Duration
khenaidoo6e55d9e2019-12-12 18:26:26 -050056 logicalDevice *voltha.LogicalDevice
khenaidoo442e7c72020-03-10 16:13:48 -040057 requestQueue *coreutils.RequestQueue
58 startOnce sync.Once
59 stopOnce sync.Once
khenaidoob9203542018-09-17 22:56:37 -040060}
61
Kent Hagerman2b216042020-04-03 18:28:56 -040062func newLogicalDeviceAgent(id string, sn string, deviceID string, ldeviceMgr *LogicalManager,
63 deviceMgr *Manager, cdProxy *model.Proxy, timeout time.Duration) *LogicalAgent {
64 var agent LogicalAgent
npujar1d86a522019-11-14 17:11:16 +053065 agent.logicalDeviceID = id
David Bainbridged1afd662020-03-26 18:27:41 -070066 agent.serialNumber = sn
npujar1d86a522019-11-14 17:11:16 +053067 agent.rootDeviceID = deviceID
khenaidoob9203542018-09-17 22:56:37 -040068 agent.deviceMgr = deviceMgr
khenaidoo9a468962018-09-19 15:33:13 -040069 agent.clusterDataProxy = cdProxy
khenaidoob9203542018-09-17 22:56:37 -040070 agent.ldeviceMgr = ldeviceMgr
khenaidoo19d7b632018-10-30 10:49:50 -040071 agent.flowDecomposer = fd.NewFlowDecomposer(agent.deviceMgr)
khenaidoo2c6a0992019-04-29 13:46:56 -040072 agent.logicalPortsNo = make(map[uint32]bool)
khenaidoo2c6a0992019-04-29 13:46:56 -040073 agent.defaultTimeout = timeout
Kent Hagerman730cbdf2020-03-31 12:22:08 -040074 agent.requestQueue = coreutils.NewRequestQueue()
khenaidoob9203542018-09-17 22:56:37 -040075 return &agent
76}
77
khenaidoo4d4802d2018-10-04 21:59:49 -040078// start creates the logical device and add it to the data model
Kent Hagerman2b216042020-04-03 18:28:56 -040079func (agent *LogicalAgent) start(ctx context.Context, loadFromDB bool) error {
khenaidoo442e7c72020-03-10 16:13:48 -040080 needToStart := false
81 if agent.startOnce.Do(func() { needToStart = true }); !needToStart {
82 return nil
83 }
84
Girish Kumarf56a4682020-03-20 20:07:46 +000085 logger.Infow("starting-logical_device-agent", log.Fields{"logical-device-id": agent.logicalDeviceID, "load-from-db": loadFromDB})
khenaidoo442e7c72020-03-10 16:13:48 -040086
87 var startSucceeded bool
88 defer func() {
89 if !startSucceeded {
90 if err := agent.stop(ctx); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +000091 logger.Errorw("failed-to-cleanup-after-unsuccessful-start", log.Fields{"logical-device-id": agent.logicalDeviceID, "error": err})
khenaidoo442e7c72020-03-10 16:13:48 -040092 }
93 }
94 }()
95
khenaidoo297cd252019-02-07 22:10:23 -050096 var ld *voltha.LogicalDevice
khenaidoo442e7c72020-03-10 16:13:48 -040097 if !loadFromDB {
khenaidoo7e3d8f12019-08-02 16:06:30 -040098 //Build the logical device based on information retrieved from the device adapter
99 var switchCap *ic.SwitchCapability
khenaidoo297cd252019-02-07 22:10:23 -0500100 var err error
npujar1d86a522019-11-14 17:11:16 +0530101 if switchCap, err = agent.deviceMgr.getSwitchCapability(ctx, agent.rootDeviceID); err != nil {
khenaidoo7e3d8f12019-08-02 16:06:30 -0400102 return err
103 }
npujar1d86a522019-11-14 17:11:16 +0530104 ld = &voltha.LogicalDevice{Id: agent.logicalDeviceID, RootDeviceId: agent.rootDeviceID}
khenaidoo297cd252019-02-07 22:10:23 -0500105
106 // Create the datapath ID (uint64) using the logical device ID (based on the MAC Address)
107 var datapathID uint64
Kent Hagerman2b216042020-04-03 18:28:56 -0400108 if datapathID, err = coreutils.CreateDataPathID(agent.serialNumber); err != nil {
khenaidoo297cd252019-02-07 22:10:23 -0500109 return err
110 }
111 ld.DatapathId = datapathID
khenaidoo7e3d8f12019-08-02 16:06:30 -0400112 ld.Desc = (proto.Clone(switchCap.Desc)).(*ofp.OfpDesc)
Girish Kumarf56a4682020-03-20 20:07:46 +0000113 logger.Debugw("Switch-capability", log.Fields{"Desc": ld.Desc, "fromAd": switchCap.Desc})
khenaidoo7e3d8f12019-08-02 16:06:30 -0400114 ld.SwitchFeatures = (proto.Clone(switchCap.SwitchFeatures)).(*ofp.OfpSwitchFeatures)
khenaidoo297cd252019-02-07 22:10:23 -0500115 ld.Flows = &ofp.Flows{Items: nil}
116 ld.FlowGroups = &ofp.FlowGroups{Items: nil}
khenaidoo49085352020-01-13 19:15:43 -0500117 ld.Ports = []*voltha.LogicalPort{}
khenaidoo297cd252019-02-07 22:10:23 -0500118
khenaidoo297cd252019-02-07 22:10:23 -0500119 // Save the logical device
Kent Hagerman4f355f52020-03-30 16:01:33 -0400120 if err := agent.clusterDataProxy.AddWithID(ctx, "logical_devices", ld.Id, ld); err != nil {
121 logger.Errorw("failed-to-add-logical-device", log.Fields{"logical-device-id": agent.logicalDeviceID})
Thomas Lee Se5a44012019-11-07 20:32:24 +0530122 return err
123 }
Kent Hagerman4f355f52020-03-30 16:01:33 -0400124 logger.Debugw("logicaldevice-created", log.Fields{"logical-device-id": agent.logicalDeviceID, "root-id": ld.RootDeviceId})
khenaidoo6e55d9e2019-12-12 18:26:26 -0500125
126 agent.logicalDevice = proto.Clone(ld).(*voltha.LogicalDevice)
khenaidoofc1314d2019-03-14 09:34:21 -0400127
khenaidoo442e7c72020-03-10 16:13:48 -0400128 // Setup the logicalports - internal processing, no need to propagate the client context
npujar1d86a522019-11-14 17:11:16 +0530129 go func() {
khenaidoo442e7c72020-03-10 16:13:48 -0400130 err := agent.setupLogicalPorts(context.Background())
npujar1d86a522019-11-14 17:11:16 +0530131 if err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000132 logger.Errorw("unable-to-setup-logical-ports", log.Fields{"error": err})
npujar1d86a522019-11-14 17:11:16 +0530133 }
134 }()
khenaidoo297cd252019-02-07 22:10:23 -0500135 } else {
136 // load from dB - the logical may not exist at this time. On error, just return and the calling function
137 // will destroy this agent.
Kent Hagerman4f355f52020-03-30 16:01:33 -0400138 ld := &voltha.LogicalDevice{}
139 have, err := agent.clusterDataProxy.Get(ctx, "logical_devices/"+agent.logicalDeviceID, ld)
Thomas Lee Se5a44012019-11-07 20:32:24 +0530140 if err != nil {
khenaidoo442e7c72020-03-10 16:13:48 -0400141 return err
Kent Hagerman4f355f52020-03-30 16:01:33 -0400142 } else if !have {
khenaidoo6e55d9e2019-12-12 18:26:26 -0500143 return status.Errorf(codes.NotFound, "logical_device-%s", agent.logicalDeviceID)
khenaidoo297cd252019-02-07 22:10:23 -0500144 }
Kent Hagerman4f355f52020-03-30 16:01:33 -0400145
khenaidoo8c3303d2019-02-13 14:59:39 -0500146 // Update the root device Id
npujar1d86a522019-11-14 17:11:16 +0530147 agent.rootDeviceID = ld.RootDeviceId
khenaidoo3d3b8c22019-05-22 18:10:39 -0400148
khenaidoo6e55d9e2019-12-12 18:26:26 -0500149 // Update the last data
150 agent.logicalDevice = proto.Clone(ld).(*voltha.LogicalDevice)
151
khenaidoo3d3b8c22019-05-22 18:10:39 -0400152 // Setup the local list of logical ports
153 agent.addLogicalPortsToMap(ld.Ports)
khenaidoob9203542018-09-17 22:56:37 -0400154 }
khenaidoofc1314d2019-03-14 09:34:21 -0400155
khenaidoo820197c2020-02-13 16:35:33 -0500156 // 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 -0400157 if loadFromDB {
khenaidoo820197c2020-02-13 16:35:33 -0500158 go func() {
159 if err := agent.buildRoutes(context.Background()); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000160 logger.Warn("routes-not-ready", log.Fields{"logical-device-id": agent.logicalDeviceID, "error": err})
khenaidoo820197c2020-02-13 16:35:33 -0500161 }
162 }()
khenaidoo4c9e5592019-09-09 16:20:41 -0400163 }
khenaidoo442e7c72020-03-10 16:13:48 -0400164 startSucceeded = true
165
khenaidoob9203542018-09-17 22:56:37 -0400166 return nil
167}
168
khenaidoo442e7c72020-03-10 16:13:48 -0400169// stop stops the logical device agent. This removes the logical device from the data model.
Kent Hagerman2b216042020-04-03 18:28:56 -0400170func (agent *LogicalAgent) stop(ctx context.Context) error {
khenaidoo442e7c72020-03-10 16:13:48 -0400171 var returnErr error
172 agent.stopOnce.Do(func() {
Girish Kumarf56a4682020-03-20 20:07:46 +0000173 logger.Info("stopping-logical_device-agent")
khenaidoo8c3303d2019-02-13 14:59:39 -0500174
khenaidoo442e7c72020-03-10 16:13:48 -0400175 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
176 // This should never happen - an error is returned only if the agent is stopped and an agent is only stopped once.
177 returnErr = err
178 return
179 }
180 defer agent.requestQueue.RequestComplete()
181
182 //Remove the logical device from the model
Kent Hagerman4f355f52020-03-30 16:01:33 -0400183 if err := agent.clusterDataProxy.Remove(ctx, "logical_devices/"+agent.logicalDeviceID); err != nil {
khenaidoo442e7c72020-03-10 16:13:48 -0400184 returnErr = err
khenaidoo442e7c72020-03-10 16:13:48 -0400185 } else {
Girish Kumarf56a4682020-03-20 20:07:46 +0000186 logger.Debugw("logicaldevice-removed", log.Fields{"logicaldeviceId": agent.logicalDeviceID})
khenaidoo442e7c72020-03-10 16:13:48 -0400187 }
188
Kent Hagerman4f355f52020-03-30 16:01:33 -0400189 agent.stopped = true
khenaidoo442e7c72020-03-10 16:13:48 -0400190
Girish Kumarf56a4682020-03-20 20:07:46 +0000191 logger.Info("logical_device-agent-stopped")
khenaidoo442e7c72020-03-10 16:13:48 -0400192 })
193 return returnErr
khenaidoo4d4802d2018-10-04 21:59:49 -0400194}
195
khenaidoo6e55d9e2019-12-12 18:26:26 -0500196// GetLogicalDevice returns the latest logical device data
Kent Hagerman2b216042020-04-03 18:28:56 -0400197func (agent *LogicalAgent) GetLogicalDevice(ctx context.Context) (*voltha.LogicalDevice, error) {
khenaidoo442e7c72020-03-10 16:13:48 -0400198 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
199 return nil, err
200 }
201 defer agent.requestQueue.RequestComplete()
202 return proto.Clone(agent.logicalDevice).(*voltha.LogicalDevice), nil
khenaidoo92e62c52018-10-03 14:02:54 -0400203}
204
npujar1d86a522019-11-14 17:11:16 +0530205// ListLogicalDeviceFlows returns logical device flows
Kent Hagerman2b216042020-04-03 18:28:56 -0400206func (agent *LogicalAgent) ListLogicalDeviceFlows(ctx context.Context) (*ofp.Flows, error) {
Girish Kumarf56a4682020-03-20 20:07:46 +0000207 logger.Debug("ListLogicalDeviceFlows")
khenaidoo6e55d9e2019-12-12 18:26:26 -0500208
khenaidoo442e7c72020-03-10 16:13:48 -0400209 logicalDevice, err := agent.GetLogicalDevice(ctx)
210 if err != nil {
211 return nil, err
khenaidoodd237172019-05-27 16:37:17 -0400212 }
khenaidoo442e7c72020-03-10 16:13:48 -0400213 if logicalDevice.Flows == nil {
214 return &ofp.Flows{}, nil
215 }
216 return (proto.Clone(logicalDevice.Flows)).(*ofp.Flows), nil
khenaidoodd237172019-05-27 16:37:17 -0400217}
218
npujar1d86a522019-11-14 17:11:16 +0530219// ListLogicalDeviceMeters returns logical device meters
Kent Hagerman2b216042020-04-03 18:28:56 -0400220func (agent *LogicalAgent) ListLogicalDeviceMeters(ctx context.Context) (*ofp.Meters, error) {
Girish Kumarf56a4682020-03-20 20:07:46 +0000221 logger.Debug("ListLogicalDeviceMeters")
khenaidoo6e55d9e2019-12-12 18:26:26 -0500222
khenaidoo442e7c72020-03-10 16:13:48 -0400223 logicalDevice, err := agent.GetLogicalDevice(ctx)
224 if err != nil {
225 return nil, err
Manikkaraj kb1a10922019-07-29 12:10:34 -0400226 }
khenaidoo442e7c72020-03-10 16:13:48 -0400227 if logicalDevice.Meters == nil {
228 return &ofp.Meters{}, nil
229 }
230 return (proto.Clone(logicalDevice.Meters)).(*ofp.Meters), nil
Manikkaraj kb1a10922019-07-29 12:10:34 -0400231}
232
npujar1d86a522019-11-14 17:11:16 +0530233// ListLogicalDeviceFlowGroups returns logical device flow groups
Kent Hagerman2b216042020-04-03 18:28:56 -0400234func (agent *LogicalAgent) ListLogicalDeviceFlowGroups(ctx context.Context) (*ofp.FlowGroups, error) {
Girish Kumarf56a4682020-03-20 20:07:46 +0000235 logger.Debug("ListLogicalDeviceFlowGroups")
khenaidoo6e55d9e2019-12-12 18:26:26 -0500236
khenaidoo442e7c72020-03-10 16:13:48 -0400237 logicalDevice, err := agent.GetLogicalDevice(ctx)
238 if err != nil {
239 return nil, err
khenaidoodd237172019-05-27 16:37:17 -0400240 }
khenaidoo442e7c72020-03-10 16:13:48 -0400241 if logicalDevice.FlowGroups == nil {
242 return &ofp.FlowGroups{}, nil
243 }
244 return (proto.Clone(logicalDevice.FlowGroups)).(*ofp.FlowGroups), nil
khenaidoodd237172019-05-27 16:37:17 -0400245}
246
npujar1d86a522019-11-14 17:11:16 +0530247// ListLogicalDevicePorts returns logical device ports
Kent Hagerman2b216042020-04-03 18:28:56 -0400248func (agent *LogicalAgent) ListLogicalDevicePorts(ctx context.Context) (*voltha.LogicalPorts, error) {
Girish Kumarf56a4682020-03-20 20:07:46 +0000249 logger.Debug("ListLogicalDevicePorts")
khenaidoo442e7c72020-03-10 16:13:48 -0400250 logicalDevice, err := agent.GetLogicalDevice(ctx)
251 if err != nil {
252 return nil, err
253 }
254 if logicalDevice == nil {
255 return &voltha.LogicalPorts{}, nil
256 }
khenaidoo6e55d9e2019-12-12 18:26:26 -0500257 lPorts := make([]*voltha.LogicalPort, 0)
258 lPorts = append(lPorts, logicalDevice.Ports...)
khenaidoo442e7c72020-03-10 16:13:48 -0400259 return &voltha.LogicalPorts{Items: lPorts}, nil
khenaidoo19d7b632018-10-30 10:49:50 -0400260}
261
khenaidoo4c9e5592019-09-09 16:20:41 -0400262//updateLogicalDeviceFlowsWithoutLock updates the logical device with the latest flows in the model.
Kent Hagerman2b216042020-04-03 18:28:56 -0400263func (agent *LogicalAgent) updateLogicalDeviceFlowsWithoutLock(ctx context.Context, flows *ofp.Flows) error {
khenaidoo6e55d9e2019-12-12 18:26:26 -0500264 ld := agent.getLogicalDeviceWithoutLock()
khenaidoo4c9e5592019-09-09 16:20:41 -0400265
Girish Kumarf56a4682020-03-20 20:07:46 +0000266 logger.Debugw("logical-device-before", log.Fields{"lports": len(ld.Ports)})
khenaidoo6e55d9e2019-12-12 18:26:26 -0500267 ld.Flows = flows
268
npujar467fe752020-01-16 20:17:45 +0530269 if err := agent.updateLogicalDeviceWithoutLock(ctx, ld); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000270 logger.Errorw("error-updating-logical-device-with-flows", log.Fields{"error": err})
khenaidoo4c9e5592019-09-09 16:20:41 -0400271 return err
khenaidoo43c82122018-11-22 18:38:28 -0500272 }
khenaidoo43c82122018-11-22 18:38:28 -0500273 return nil
274}
275
khenaidoo4c9e5592019-09-09 16:20:41 -0400276//updateLogicalDeviceMetersWithoutLock updates the logical device with the meters info
Kent Hagerman2b216042020-04-03 18:28:56 -0400277func (agent *LogicalAgent) updateLogicalDeviceMetersWithoutLock(ctx context.Context, meters *ofp.Meters) error {
khenaidoo6e55d9e2019-12-12 18:26:26 -0500278 ld := agent.getLogicalDeviceWithoutLock()
khenaidoo4c9e5592019-09-09 16:20:41 -0400279
Girish Kumarf56a4682020-03-20 20:07:46 +0000280 logger.Debugw("logical-device-before", log.Fields{"lports": len(ld.Ports)})
khenaidoo6e55d9e2019-12-12 18:26:26 -0500281 ld.Meters = meters
282
npujar467fe752020-01-16 20:17:45 +0530283 if err := agent.updateLogicalDeviceWithoutLock(ctx, ld); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000284 logger.Errorw("error-updating-logical-device-with-meters", log.Fields{"error": err})
khenaidoo4c9e5592019-09-09 16:20:41 -0400285 return err
Manikkaraj kb1a10922019-07-29 12:10:34 -0400286 }
287 return nil
288}
289
khenaidoo4c9e5592019-09-09 16:20:41 -0400290//updateLogicalDeviceFlowGroupsWithoutLock updates the logical device with the flow groups
Kent Hagerman2b216042020-04-03 18:28:56 -0400291func (agent *LogicalAgent) updateLogicalDeviceFlowGroupsWithoutLock(ctx context.Context, flowGroups *ofp.FlowGroups) error {
khenaidoo6e55d9e2019-12-12 18:26:26 -0500292 ld := agent.getLogicalDeviceWithoutLock()
khenaidoo4c9e5592019-09-09 16:20:41 -0400293
Girish Kumarf56a4682020-03-20 20:07:46 +0000294 logger.Debugw("logical-device-before", log.Fields{"lports": len(ld.Ports)})
khenaidoo6e55d9e2019-12-12 18:26:26 -0500295 ld.FlowGroups = flowGroups
296
npujar467fe752020-01-16 20:17:45 +0530297 if err := agent.updateLogicalDeviceWithoutLock(ctx, ld); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000298 logger.Errorw("error-updating-logical-device-with-flowgroups", log.Fields{"error": err})
khenaidoo4c9e5592019-09-09 16:20:41 -0400299 return err
khenaidoo43c82122018-11-22 18:38:28 -0500300 }
khenaidoo43c82122018-11-22 18:38:28 -0500301 return nil
302}
303
khenaidoo6e55d9e2019-12-12 18:26:26 -0500304// getLogicalDeviceWithoutLock returns a cloned logical device to a function that already holds the agent lock.
Kent Hagerman2b216042020-04-03 18:28:56 -0400305func (agent *LogicalAgent) getLogicalDeviceWithoutLock() *voltha.LogicalDevice {
Girish Kumarf56a4682020-03-20 20:07:46 +0000306 logger.Debug("getLogicalDeviceWithoutLock")
khenaidoo6e55d9e2019-12-12 18:26:26 -0500307 return proto.Clone(agent.logicalDevice).(*voltha.LogicalDevice)
khenaidoo92e62c52018-10-03 14:02:54 -0400308}
309
Kent Hagerman2b216042020-04-03 18:28:56 -0400310func (agent *LogicalAgent) updateLogicalPort(ctx context.Context, device *voltha.Device, port *voltha.Port) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000311 logger.Debugw("updateLogicalPort", log.Fields{"deviceId": device.Id, "port": port})
khenaidoo2c6a0992019-04-29 13:46:56 -0400312 var err error
313 if port.Type == voltha.Port_ETHERNET_NNI {
npujar467fe752020-01-16 20:17:45 +0530314 if _, err = agent.addNNILogicalPort(ctx, device, port); err != nil {
khenaidoo2c6a0992019-04-29 13:46:56 -0400315 return err
316 }
317 agent.addLogicalPortToMap(port.PortNo, true)
318 } else if port.Type == voltha.Port_ETHERNET_UNI {
npujar467fe752020-01-16 20:17:45 +0530319 if _, err = agent.addUNILogicalPort(ctx, device, port); err != nil {
khenaidoo2c6a0992019-04-29 13:46:56 -0400320 return err
321 }
322 agent.addLogicalPortToMap(port.PortNo, false)
323 } else {
khenaidoo820197c2020-02-13 16:35:33 -0500324 // Update the device routes to ensure all routes on the logical device have been calculated
325 if err = agent.buildRoutes(ctx); err != nil {
326 // Not an error - temporary state
Girish Kumarf56a4682020-03-20 20:07:46 +0000327 logger.Warnw("failed-to-update-routes", log.Fields{"device-id": device.Id, "port": port, "error": err})
khenaidoo2c6a0992019-04-29 13:46:56 -0400328 }
329 }
330 return nil
331}
332
khenaidoo3d3b8c22019-05-22 18:10:39 -0400333// setupLogicalPorts is invoked once the logical device has been created and is ready to get ports
334// added to it. While the logical device was being created we could have received requests to add
335// NNI and UNI ports which were discarded. Now is the time to add them if needed
Kent Hagerman2b216042020-04-03 18:28:56 -0400336func (agent *LogicalAgent) setupLogicalPorts(ctx context.Context) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000337 logger.Infow("setupLogicalPorts", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo3d3b8c22019-05-22 18:10:39 -0400338 // First add any NNI ports which could have been missing
npujar467fe752020-01-16 20:17:45 +0530339 if err := agent.setupNNILogicalPorts(ctx, agent.rootDeviceID); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000340 logger.Errorw("error-setting-up-NNI-ports", log.Fields{"error": err, "deviceId": agent.rootDeviceID})
khenaidoo3d3b8c22019-05-22 18:10:39 -0400341 return err
342 }
343
344 // Now, set up the UNI ports if needed.
Kent Hagerman2b216042020-04-03 18:28:56 -0400345 children, err := agent.deviceMgr.GetAllChildDevices(ctx, agent.rootDeviceID)
npujar1d86a522019-11-14 17:11:16 +0530346 if err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000347 logger.Errorw("error-getting-child-devices", log.Fields{"error": err, "deviceId": agent.rootDeviceID})
khenaidoo3d3b8c22019-05-22 18:10:39 -0400348 return err
npujar1d86a522019-11-14 17:11:16 +0530349 }
350 responses := make([]coreutils.Response, 0)
351 for _, child := range children.Items {
352 response := coreutils.NewResponse()
353 responses = append(responses, response)
354 go func(child *voltha.Device) {
khenaidoo442e7c72020-03-10 16:13:48 -0400355 if err = agent.setupUNILogicalPorts(context.Background(), child); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000356 logger.Error("setting-up-UNI-ports-failed", log.Fields{"deviceID": child.Id})
npujar1d86a522019-11-14 17:11:16 +0530357 response.Error(status.Errorf(codes.Internal, "UNI-ports-setup-failed: %s", child.Id))
358 }
359 response.Done()
360 }(child)
361 }
362 // Wait for completion
363 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, responses...); res != nil {
364 return status.Errorf(codes.Aborted, "errors-%s", res)
khenaidoo3d3b8c22019-05-22 18:10:39 -0400365 }
366 return nil
367}
368
khenaidoofc1314d2019-03-14 09:34:21 -0400369// setupNNILogicalPorts creates an NNI port on the logical device that represents an NNI interface on a root device
Kent Hagerman2b216042020-04-03 18:28:56 -0400370func (agent *LogicalAgent) setupNNILogicalPorts(ctx context.Context, deviceID string) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000371 logger.Infow("setupNNILogicalPorts-start", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoob9203542018-09-17 22:56:37 -0400372 // Build the logical device based on information retrieved from the device adapter
khenaidoofc1314d2019-03-14 09:34:21 -0400373 var err error
374
375 var device *voltha.Device
Kent Hagerman45a13e42020-04-13 12:23:50 -0400376 if device, err = agent.deviceMgr.getDevice(ctx, deviceID); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000377 logger.Errorw("error-retrieving-device", log.Fields{"error": err, "deviceId": deviceID})
khenaidoofc1314d2019-03-14 09:34:21 -0400378 return err
379 }
380
381 //Get UNI port number
khenaidoofc1314d2019-03-14 09:34:21 -0400382 for _, port := range device.Ports {
383 if port.Type == voltha.Port_ETHERNET_NNI {
npujar467fe752020-01-16 20:17:45 +0530384 if _, err = agent.addNNILogicalPort(ctx, device, port); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000385 logger.Errorw("error-adding-UNI-port", log.Fields{"error": err})
khenaidoofc1314d2019-03-14 09:34:21 -0400386 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400387 agent.addLogicalPortToMap(port.PortNo, true)
khenaidoofc1314d2019-03-14 09:34:21 -0400388 }
389 }
khenaidoofc1314d2019-03-14 09:34:21 -0400390 return err
391}
392
khenaidoo171b98e2019-10-31 11:48:15 -0400393// updatePortState updates the port state of the device
Kent Hagerman2b216042020-04-03 18:28:56 -0400394func (agent *LogicalAgent) updatePortState(ctx context.Context, deviceID string, portNo uint32, operStatus voltha.OperStatus_Types) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000395 logger.Infow("updatePortState-start", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "portNo": portNo, "state": operStatus})
khenaidoo442e7c72020-03-10 16:13:48 -0400396 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
397 return err
398 }
399 defer agent.requestQueue.RequestComplete()
khenaidoo171b98e2019-10-31 11:48:15 -0400400 // Get the latest logical device info
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500401 original := agent.getLogicalDeviceWithoutLock()
402 updatedPorts := clonePorts(original.Ports)
403 for _, port := range updatedPorts {
404 if port.DeviceId == deviceID && port.DevicePortNo == portNo {
npujar1d86a522019-11-14 17:11:16 +0530405 if operStatus == voltha.OperStatus_ACTIVE {
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500406 port.OfpPort.Config = port.OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
407 port.OfpPort.State = uint32(ofp.OfpPortState_OFPPS_LIVE)
npujar1d86a522019-11-14 17:11:16 +0530408 } else {
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500409 port.OfpPort.Config = port.OfpPort.Config | uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
410 port.OfpPort.State = uint32(ofp.OfpPortState_OFPPS_LINK_DOWN)
npujar1d86a522019-11-14 17:11:16 +0530411 }
412 // Update the logical device
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500413 if err := agent.updateLogicalDevicePortsWithoutLock(ctx, original, updatedPorts); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000414 logger.Errorw("error-updating-logical-device", log.Fields{"error": err})
npujar1d86a522019-11-14 17:11:16 +0530415 return err
416 }
417 return nil
418 }
419 }
420 return status.Errorf(codes.NotFound, "port-%d-not-exist", portNo)
khenaidoo171b98e2019-10-31 11:48:15 -0400421}
422
khenaidoo3ab34882019-05-02 21:33:30 -0400423// updatePortsState updates the ports state related to the device
Kent Hagerman2b216042020-04-03 18:28:56 -0400424func (agent *LogicalAgent) updatePortsState(ctx context.Context, device *voltha.Device, state voltha.OperStatus_Types) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000425 logger.Infow("updatePortsState-start", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo442e7c72020-03-10 16:13:48 -0400426 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
427 return err
428 }
429 defer agent.requestQueue.RequestComplete()
khenaidoo3ab34882019-05-02 21:33:30 -0400430 // Get the latest logical device info
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500431 original := agent.getLogicalDeviceWithoutLock()
432 updatedPorts := clonePorts(original.Ports)
433 for _, port := range updatedPorts {
434 if port.DeviceId == device.Id {
kesavandbc2d1622020-01-21 00:42:01 -0500435 if state == voltha.OperStatus_ACTIVE {
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500436 port.OfpPort.Config = port.OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
437 port.OfpPort.State = uint32(ofp.OfpPortState_OFPPS_LIVE)
kesavandbc2d1622020-01-21 00:42:01 -0500438 } else {
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500439 port.OfpPort.Config = port.OfpPort.Config | uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
440 port.OfpPort.State = uint32(ofp.OfpPortState_OFPPS_LINK_DOWN)
khenaidoo3ab34882019-05-02 21:33:30 -0400441 }
442 }
npujar1d86a522019-11-14 17:11:16 +0530443 }
444 // Updating the logical device will trigger the poprt change events to be populated to the controller
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500445 if err := agent.updateLogicalDevicePortsWithoutLock(ctx, original, updatedPorts); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000446 logger.Warnw("logical-device-update-failed", log.Fields{"ldeviceId": agent.logicalDeviceID, "error": err})
npujar1d86a522019-11-14 17:11:16 +0530447 return err
khenaidoo3ab34882019-05-02 21:33:30 -0400448 }
449 return nil
450}
451
khenaidoofc1314d2019-03-14 09:34:21 -0400452// setupUNILogicalPorts creates a UNI port on the logical device that represents a child UNI interface
Kent Hagerman2b216042020-04-03 18:28:56 -0400453func (agent *LogicalAgent) setupUNILogicalPorts(ctx context.Context, childDevice *voltha.Device) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000454 logger.Infow("setupUNILogicalPort", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoofc1314d2019-03-14 09:34:21 -0400455 // Build the logical device based on information retrieved from the device adapter
khenaidoob9203542018-09-17 22:56:37 -0400456 var err error
khenaidoo59ef7be2019-06-21 12:40:28 -0400457 var added bool
khenaidoo19d7b632018-10-30 10:49:50 -0400458 //Get UNI port number
khenaidoo19d7b632018-10-30 10:49:50 -0400459 for _, port := range childDevice.Ports {
460 if port.Type == voltha.Port_ETHERNET_UNI {
npujar467fe752020-01-16 20:17:45 +0530461 if added, err = agent.addUNILogicalPort(ctx, childDevice, port); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000462 logger.Errorw("error-adding-UNI-port", log.Fields{"error": err})
khenaidoofc1314d2019-03-14 09:34:21 -0400463 }
khenaidoo59ef7be2019-06-21 12:40:28 -0400464 if added {
465 agent.addLogicalPortToMap(port.PortNo, false)
466 }
khenaidoo19d7b632018-10-30 10:49:50 -0400467 }
468 }
khenaidoofc1314d2019-03-14 09:34:21 -0400469 return err
khenaidoo92e62c52018-10-03 14:02:54 -0400470}
471
Girish Gowdra408cd962020-03-11 14:31:31 -0700472// deleteAllLogicalPorts deletes all logical ports associated with this logical device
Kent Hagerman2b216042020-04-03 18:28:56 -0400473func (agent *LogicalAgent) deleteAllLogicalPorts(ctx context.Context) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000474 logger.Infow("updatePortsState-start", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo442e7c72020-03-10 16:13:48 -0400475 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
476 return err
477 }
478 defer agent.requestQueue.RequestComplete()
khenaidoo0a822f92019-05-08 15:15:57 -0400479 // Get the latest logical device info
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500480 cloned := agent.getLogicalDeviceWithoutLock()
khenaidoo6e55d9e2019-12-12 18:26:26 -0500481
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500482 if err := agent.updateLogicalDevicePortsWithoutLock(ctx, cloned, []*voltha.LogicalPort{}); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000483 logger.Warnw("logical-device-update-failed", log.Fields{"ldeviceId": agent.logicalDeviceID, "error": err})
Girish Gowdra408cd962020-03-11 14:31:31 -0700484 return err
khenaidoo0a822f92019-05-08 15:15:57 -0400485 }
486 return nil
487}
488
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500489func clonePorts(ports []*voltha.LogicalPort) []*voltha.LogicalPort {
490 return proto.Clone(&voltha.LogicalPorts{Items: ports}).(*voltha.LogicalPorts).Items
491}
492
khenaidoo8b4abbf2020-04-24 17:04:30 -0400493func cloneFlows(flows []*ofp.OfpFlowStats) []*ofp.OfpFlowStats {
494 return proto.Clone(&ofp.Flows{Items: flows}).(*ofp.Flows).Items
495}
496
497func cloneMeters(meters []*ofp.OfpMeterEntry) []*ofp.OfpMeterEntry {
498 return proto.Clone(&ofp.Meters{Items: meters}).(*ofp.Meters).Items
499}
500
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500501//updateLogicalDevicePortsWithoutLock updates the
Kent Hagerman2b216042020-04-03 18:28:56 -0400502func (agent *LogicalAgent) updateLogicalDevicePortsWithoutLock(ctx context.Context, device *voltha.LogicalDevice, newPorts []*voltha.LogicalPort) error {
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500503 oldPorts := device.Ports
504 device.Ports = newPorts
505 if err := agent.updateLogicalDeviceWithoutLock(ctx, device); err != nil {
506 return err
507 }
508 agent.portUpdated(oldPorts, newPorts)
509 return nil
510}
511
khenaidoo92e62c52018-10-03 14:02:54 -0400512//updateLogicalDeviceWithoutLock updates the model with the logical device. It clones the logicaldevice before saving it
Kent Hagerman2b216042020-04-03 18:28:56 -0400513func (agent *LogicalAgent) updateLogicalDeviceWithoutLock(ctx context.Context, logicalDevice *voltha.LogicalDevice) error {
Kent Hagerman4f355f52020-03-30 16:01:33 -0400514 if agent.stopped {
515 return errors.New("logical device agent stopped")
516 }
517
npujar467fe752020-01-16 20:17:45 +0530518 updateCtx := context.WithValue(ctx, model.RequestTimestamp, time.Now().UnixNano())
Kent Hagerman4f355f52020-03-30 16:01:33 -0400519 if err := agent.clusterDataProxy.Update(updateCtx, "logical_devices/"+agent.logicalDeviceID, logicalDevice); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000520 logger.Errorw("failed-to-update-logical-devices-to-cluster-proxy", log.Fields{"error": err})
Thomas Lee Se5a44012019-11-07 20:32:24 +0530521 return err
522 }
Kent Hagerman4f355f52020-03-30 16:01:33 -0400523
khenaidoo442e7c72020-03-10 16:13:48 -0400524 agent.logicalDevice = logicalDevice
525
khenaidoo92e62c52018-10-03 14:02:54 -0400526 return nil
527}
528
khenaidoo820197c2020-02-13 16:35:33 -0500529//generateDeviceRoutesIfNeeded generates the device routes if the logical device has been updated since the last time
khenaidoo4c9e5592019-09-09 16:20:41 -0400530//that device graph was generated.
Kent Hagerman2b216042020-04-03 18:28:56 -0400531func (agent *LogicalAgent) generateDeviceRoutesIfNeeded(ctx context.Context) error {
khenaidoo820197c2020-02-13 16:35:33 -0500532 agent.lockDeviceRoutes.Lock()
533 defer agent.lockDeviceRoutes.Unlock()
534
khenaidoo442e7c72020-03-10 16:13:48 -0400535 ld, err := agent.GetLogicalDevice(ctx)
536 if err != nil {
537 return err
538 }
khenaidoo820197c2020-02-13 16:35:33 -0500539
540 if agent.deviceRoutes != nil && agent.deviceRoutes.IsUpToDate(ld) {
npujar1d86a522019-11-14 17:11:16 +0530541 return nil
542 }
Girish Kumarf56a4682020-03-20 20:07:46 +0000543 logger.Debug("Generation of device route required")
khenaidoo820197c2020-02-13 16:35:33 -0500544 if err := agent.buildRoutes(ctx); err != nil {
khenaidoo787224a2020-04-16 18:08:47 -0400545 // No Route is not an error
546 if !errors.Is(err, route.ErrNoRoute) {
547 return err
548 }
khenaidoo820197c2020-02-13 16:35:33 -0500549 }
khenaidoo4c9e5592019-09-09 16:20:41 -0400550 return nil
551}
552
khenaidoo19d7b632018-10-30 10:49:50 -0400553//updateFlowTable updates the flow table of that logical device
Kent Hagerman2b216042020-04-03 18:28:56 -0400554func (agent *LogicalAgent) updateFlowTable(ctx context.Context, flow *ofp.OfpFlowMod) error {
555 logger.Debug("UpdateFlowTable")
khenaidoo19d7b632018-10-30 10:49:50 -0400556 if flow == nil {
557 return nil
558 }
khenaidoo820197c2020-02-13 16:35:33 -0500559 if err := agent.generateDeviceRoutesIfNeeded(ctx); err != nil {
khenaidoo4c9e5592019-09-09 16:20:41 -0400560 return err
561 }
khenaidoo19d7b632018-10-30 10:49:50 -0400562 switch flow.GetCommand() {
563 case ofp.OfpFlowModCommand_OFPFC_ADD:
npujar467fe752020-01-16 20:17:45 +0530564 return agent.flowAdd(ctx, flow)
khenaidoo19d7b632018-10-30 10:49:50 -0400565 case ofp.OfpFlowModCommand_OFPFC_DELETE:
npujar467fe752020-01-16 20:17:45 +0530566 return agent.flowDelete(ctx, flow)
khenaidoo19d7b632018-10-30 10:49:50 -0400567 case ofp.OfpFlowModCommand_OFPFC_DELETE_STRICT:
npujar467fe752020-01-16 20:17:45 +0530568 return agent.flowDeleteStrict(ctx, flow)
khenaidoo19d7b632018-10-30 10:49:50 -0400569 case ofp.OfpFlowModCommand_OFPFC_MODIFY:
570 return agent.flowModify(flow)
571 case ofp.OfpFlowModCommand_OFPFC_MODIFY_STRICT:
572 return agent.flowModifyStrict(flow)
573 }
574 return status.Errorf(codes.Internal,
npujar1d86a522019-11-14 17:11:16 +0530575 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceID, flow.GetCommand())
khenaidoo19d7b632018-10-30 10:49:50 -0400576}
577
578//updateGroupTable updates the group table of that logical device
Kent Hagerman2b216042020-04-03 18:28:56 -0400579func (agent *LogicalAgent) updateGroupTable(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000580 logger.Debug("updateGroupTable")
khenaidoo19d7b632018-10-30 10:49:50 -0400581 if groupMod == 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 }
khenaidoo820197c2020-02-13 16:35:33 -0500587
khenaidoo19d7b632018-10-30 10:49:50 -0400588 switch groupMod.GetCommand() {
589 case ofp.OfpGroupModCommand_OFPGC_ADD:
npujar467fe752020-01-16 20:17:45 +0530590 return agent.groupAdd(ctx, groupMod)
khenaidoo19d7b632018-10-30 10:49:50 -0400591 case ofp.OfpGroupModCommand_OFPGC_DELETE:
npujar467fe752020-01-16 20:17:45 +0530592 return agent.groupDelete(ctx, groupMod)
khenaidoo19d7b632018-10-30 10:49:50 -0400593 case ofp.OfpGroupModCommand_OFPGC_MODIFY:
npujar467fe752020-01-16 20:17:45 +0530594 return agent.groupModify(ctx, groupMod)
khenaidoo19d7b632018-10-30 10:49:50 -0400595 }
596 return status.Errorf(codes.Internal,
npujar1d86a522019-11-14 17:11:16 +0530597 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceID, groupMod.GetCommand())
khenaidoo19d7b632018-10-30 10:49:50 -0400598}
599
Manikkaraj kb1a10922019-07-29 12:10:34 -0400600// updateMeterTable updates the meter table of that logical device
Kent Hagerman2b216042020-04-03 18:28:56 -0400601func (agent *LogicalAgent) updateMeterTable(ctx context.Context, meterMod *ofp.OfpMeterMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000602 logger.Debug("updateMeterTable")
Manikkaraj kb1a10922019-07-29 12:10:34 -0400603 if meterMod == nil {
604 return nil
605 }
606 switch meterMod.GetCommand() {
607 case ofp.OfpMeterModCommand_OFPMC_ADD:
npujar467fe752020-01-16 20:17:45 +0530608 return agent.meterAdd(ctx, meterMod)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400609 case ofp.OfpMeterModCommand_OFPMC_DELETE:
npujar467fe752020-01-16 20:17:45 +0530610 return agent.meterDelete(ctx, meterMod)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400611 case ofp.OfpMeterModCommand_OFPMC_MODIFY:
npujar467fe752020-01-16 20:17:45 +0530612 return agent.meterModify(ctx, meterMod)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400613 }
614 return status.Errorf(codes.Internal,
npujar1d86a522019-11-14 17:11:16 +0530615 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceID, meterMod.GetCommand())
Manikkaraj kb1a10922019-07-29 12:10:34 -0400616
617}
618
Kent Hagerman2b216042020-04-03 18:28:56 -0400619func (agent *LogicalAgent) meterAdd(ctx context.Context, meterMod *ofp.OfpMeterMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000620 logger.Debugw("meterAdd", log.Fields{"metermod": *meterMod})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400621 if meterMod == nil {
622 return nil
623 }
khenaidoo442e7c72020-03-10 16:13:48 -0400624 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
625 return err
626 }
627 defer agent.requestQueue.RequestComplete()
Girish Kumarf56a4682020-03-20 20:07:46 +0000628 logger.Debug("Acquired logical device lock")
khenaidoo6e55d9e2019-12-12 18:26:26 -0500629 lDevice := agent.getLogicalDeviceWithoutLock()
Manikkaraj kb1a10922019-07-29 12:10:34 -0400630
631 var meters []*ofp.OfpMeterEntry
632 if lDevice.Meters != nil && lDevice.Meters.Items != nil {
633 meters = lDevice.Meters.Items
634 }
Girish Kumarf56a4682020-03-20 20:07:46 +0000635 logger.Debugw("Available meters", log.Fields{"meters": meters})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400636
637 for _, meter := range meters {
638 if meterMod.MeterId == meter.Config.MeterId {
Girish Kumarf56a4682020-03-20 20:07:46 +0000639 logger.Infow("Meter-already-exists", log.Fields{"meter": *meterMod})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400640 return nil
641 }
642 }
643
644 meterEntry := fu.MeterEntryFromMeterMod(meterMod)
645 meters = append(meters, meterEntry)
646 //Update model
npujar467fe752020-01-16 20:17:45 +0530647 if err := agent.updateLogicalDeviceMetersWithoutLock(ctx, &ofp.Meters{Items: meters}); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000648 logger.Errorw("db-meter-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400649 return err
650 }
Girish Kumarf56a4682020-03-20 20:07:46 +0000651 logger.Debugw("Meter-added-successfully", log.Fields{"Added-meter": meterEntry, "updated-meters": lDevice.Meters})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400652 return nil
653}
654
Kent Hagerman2b216042020-04-03 18:28:56 -0400655func (agent *LogicalAgent) meterDelete(ctx context.Context, meterMod *ofp.OfpMeterMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000656 logger.Debug("meterDelete", log.Fields{"meterMod": *meterMod})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400657 if meterMod == nil {
658 return nil
659 }
khenaidoo442e7c72020-03-10 16:13:48 -0400660 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
661 return err
662 }
663 defer agent.requestQueue.RequestComplete()
Manikkaraj kb1a10922019-07-29 12:10:34 -0400664
khenaidoo6e55d9e2019-12-12 18:26:26 -0500665 lDevice := agent.getLogicalDeviceWithoutLock()
Manikkaraj kb1a10922019-07-29 12:10:34 -0400666
667 var meters []*ofp.OfpMeterEntry
668 var flows []*ofp.OfpFlowStats
669 updatedFlows := make([]*ofp.OfpFlowStats, 0)
670 if lDevice.Meters != nil && lDevice.Meters.Items != nil {
671 meters = lDevice.Meters.Items
672 }
Manikkaraj kb1a10922019-07-29 12:10:34 -0400673
674 changedMeter := false
675 changedFow := false
Girish Kumarf56a4682020-03-20 20:07:46 +0000676 logger.Debugw("Available meters", log.Fields{"meters": meters})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400677 for index, meter := range meters {
678 if meterMod.MeterId == meter.Config.MeterId {
679 flows = lDevice.Flows.Items
npujar1d86a522019-11-14 17:11:16 +0530680 changedFow, updatedFlows = agent.getUpdatedFlowsAfterDeletebyMeterID(flows, meterMod.MeterId)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400681 meters = append(meters[:index], meters[index+1:]...)
Girish Kumarf56a4682020-03-20 20:07:46 +0000682 logger.Debugw("Meter has been deleted", log.Fields{"meter": meter, "index": index})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400683 changedMeter = true
684 break
685 }
686 }
687 if changedMeter {
688 //Update model
689 metersToUpdate := &ofp.Meters{}
690 if lDevice.Meters != nil {
691 metersToUpdate = &ofp.Meters{Items: meters}
692 }
npujar467fe752020-01-16 20:17:45 +0530693 if err := agent.updateLogicalDeviceMetersWithoutLock(ctx, metersToUpdate); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000694 logger.Errorw("db-meter-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400695 return err
696 }
Girish Kumarf56a4682020-03-20 20:07:46 +0000697 logger.Debug("Meter-deleted-from-DB-successfully", log.Fields{"updatedMeters": metersToUpdate, "no-of-meter": len(metersToUpdate.Items)})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400698
699 }
700 if changedFow {
701 //Update model
npujar467fe752020-01-16 20:17:45 +0530702 if err := agent.updateLogicalDeviceFlowsWithoutLock(ctx, &ofp.Flows{Items: updatedFlows}); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000703 logger.Errorw("db-flow-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400704 return err
705 }
Girish Kumarf56a4682020-03-20 20:07:46 +0000706 logger.Debug("Flows-associated-with-meter-deleted-from-DB-successfully",
Manikkaraj kb1a10922019-07-29 12:10:34 -0400707 log.Fields{"updated-no-of-flows": len(updatedFlows), "meter": meterMod.MeterId})
708 }
Girish Kumarf56a4682020-03-20 20:07:46 +0000709 logger.Debugw("meterDelete success", log.Fields{"meterID": meterMod.MeterId})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400710 return nil
711}
712
Kent Hagerman2b216042020-04-03 18:28:56 -0400713func (agent *LogicalAgent) meterModify(ctx context.Context, meterMod *ofp.OfpMeterMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000714 logger.Debug("meterModify")
Manikkaraj kb1a10922019-07-29 12:10:34 -0400715 if meterMod == nil {
716 return nil
717 }
khenaidoo442e7c72020-03-10 16:13:48 -0400718 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
719 return err
720 }
721 defer agent.requestQueue.RequestComplete()
Manikkaraj kb1a10922019-07-29 12:10:34 -0400722
khenaidoo6e55d9e2019-12-12 18:26:26 -0500723 lDevice := agent.getLogicalDeviceWithoutLock()
Manikkaraj kb1a10922019-07-29 12:10:34 -0400724
725 var meters []*ofp.OfpMeterEntry
726 if lDevice.Meters != nil && lDevice.Meters.Items != nil {
727 meters = lDevice.Meters.Items
728 }
729 changedMeter := false
730 for index, meter := range meters {
731 if meterMod.MeterId == meter.Config.MeterId {
732 newmeterEntry := fu.MeterEntryFromMeterMod(meterMod)
733 newmeterEntry.Stats.FlowCount = meter.Stats.FlowCount
734 meters[index] = newmeterEntry
735 changedMeter = true
Girish Kumarf56a4682020-03-20 20:07:46 +0000736 logger.Debugw("Found meter, replaced with new meter", log.Fields{"old meter": meter, "new meter": newmeterEntry})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400737 break
738 }
739 }
740 if changedMeter {
741 //Update model
742 metersToUpdate := &ofp.Meters{}
743 if lDevice.Meters != nil {
744 metersToUpdate = &ofp.Meters{Items: meters}
745 }
npujar467fe752020-01-16 20:17:45 +0530746 if err := agent.updateLogicalDeviceMetersWithoutLock(ctx, metersToUpdate); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000747 logger.Errorw("db-meter-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400748 return err
749 }
Girish Kumarf56a4682020-03-20 20:07:46 +0000750 logger.Debugw("meter-updated-in-DB-successfully", log.Fields{"updated_meters": meters})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400751 return nil
752 }
753
Girish Kumarf56a4682020-03-20 20:07:46 +0000754 logger.Errorw("Meter not found ", log.Fields{"meter": meterMod})
npujar1d86a522019-11-14 17:11:16 +0530755 return fmt.Errorf("no-logical-device-present:%d", meterMod.MeterId)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400756
757}
758
Kent Hagerman2b216042020-04-03 18:28:56 -0400759func (agent *LogicalAgent) getUpdatedFlowsAfterDeletebyMeterID(flows []*ofp.OfpFlowStats, meterID uint32) (bool, []*ofp.OfpFlowStats) {
Girish Kumarf56a4682020-03-20 20:07:46 +0000760 logger.Infow("Delete flows matching meter", log.Fields{"meter": meterID})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400761 changed := false
762 //updatedFlows := make([]*ofp.OfpFlowStats, 0)
763 for index := len(flows) - 1; index >= 0; index-- {
npujar1d86a522019-11-14 17:11:16 +0530764 if mID := fu.GetMeterIdFromFlow(flows[index]); mID != 0 && mID == meterID {
Girish Kumarf56a4682020-03-20 20:07:46 +0000765 logger.Debugw("Flow to be deleted", log.Fields{"flow": flows[index], "index": index})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400766 flows = append(flows[:index], flows[index+1:]...)
767 changed = true
768 }
769 }
770 return changed, flows
771}
772
khenaidoo8b4abbf2020-04-24 17:04:30 -0400773func (agent *LogicalAgent) updateFlowCountOfMeterStats(modCommand *ofp.OfpFlowMod, meters []*ofp.OfpMeterEntry, flow *ofp.OfpFlowStats, revertUpdate bool) bool {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400774
775 flowCommand := modCommand.GetCommand()
npujar1d86a522019-11-14 17:11:16 +0530776 meterID := fu.GetMeterIdFromFlow(flow)
Girish Kumarf56a4682020-03-20 20:07:46 +0000777 logger.Debugw("Meter-id-in-flow-mod", log.Fields{"meterId": meterID})
npujar1d86a522019-11-14 17:11:16 +0530778 if meterID == 0 {
Girish Kumarf56a4682020-03-20 20:07:46 +0000779 logger.Debugw("No meter present in the flow", log.Fields{"flow": *flow})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400780 return false
781 }
782 if meters == nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000783 logger.Debug("No meters present in logical device")
Manikkaraj kb1a10922019-07-29 12:10:34 -0400784 return false
785 }
786 changedMeter := false
787 for _, meter := range meters {
npujar1d86a522019-11-14 17:11:16 +0530788 if meterID == meter.Config.MeterId { // Found meter in Logicaldevice
Manikkaraj kb1a10922019-07-29 12:10:34 -0400789 if flowCommand == ofp.OfpFlowModCommand_OFPFC_ADD {
khenaidoo8b4abbf2020-04-24 17:04:30 -0400790 if revertUpdate {
791 meter.Stats.FlowCount--
792 } else {
793 meter.Stats.FlowCount++
794 }
Manikkaraj kb1a10922019-07-29 12:10:34 -0400795 changedMeter = true
796 } else if flowCommand == ofp.OfpFlowModCommand_OFPFC_DELETE_STRICT {
khenaidoo8b4abbf2020-04-24 17:04:30 -0400797 if revertUpdate {
798 meter.Stats.FlowCount++
799 } else {
800 meter.Stats.FlowCount--
801 }
Manikkaraj kb1a10922019-07-29 12:10:34 -0400802 changedMeter = true
803 }
Girish Kumarf56a4682020-03-20 20:07:46 +0000804 logger.Debugw("Found meter, updated meter flow stats", log.Fields{" meterId": meterID})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400805 break
806 }
807 }
808 return changedMeter
809}
810
khenaidoo19d7b632018-10-30 10:49:50 -0400811//flowAdd adds a flow to the flow table of that logical device
Kent Hagerman2b216042020-04-03 18:28:56 -0400812func (agent *LogicalAgent) flowAdd(ctx context.Context, mod *ofp.OfpFlowMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000813 logger.Debugw("flowAdd", log.Fields{"flow": mod})
khenaidoo19d7b632018-10-30 10:49:50 -0400814 if mod == nil {
815 return nil
816 }
khenaidoo442e7c72020-03-10 16:13:48 -0400817 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
818 return err
819 }
820 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -0400821
khenaidoo6e55d9e2019-12-12 18:26:26 -0500822 lDevice := agent.getLogicalDeviceWithoutLock()
khenaidoo19d7b632018-10-30 10:49:50 -0400823
824 var flows []*ofp.OfpFlowStats
Manikkaraj kb1a10922019-07-29 12:10:34 -0400825 var meters []*ofp.OfpMeterEntry
khenaidoo8b4abbf2020-04-24 17:04:30 -0400826 var flowToReplace *ofp.OfpFlowStats
Manikkaraj kb1a10922019-07-29 12:10:34 -0400827 var flow *ofp.OfpFlowStats
Scott Bakerfdea1e32020-02-21 15:35:41 -0800828 var err error
Manikkaraj kb1a10922019-07-29 12:10:34 -0400829
khenaidoo19d7b632018-10-30 10:49:50 -0400830 if lDevice.Flows != nil && lDevice.Flows.Items != nil {
831 flows = lDevice.Flows.Items
832 }
833
Manikkaraj kb1a10922019-07-29 12:10:34 -0400834 if lDevice.Meters != nil && lDevice.Meters.Items != nil {
835 meters = lDevice.Meters.Items
836 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400837 updatedFlows := make([]*ofp.OfpFlowStats, 0)
khenaidoo19d7b632018-10-30 10:49:50 -0400838 changed := false
Manikkaraj kb1a10922019-07-29 12:10:34 -0400839 updated := false
khenaidoo19d7b632018-10-30 10:49:50 -0400840 checkOverlap := (mod.Flags & uint32(ofp.OfpFlowModFlags_OFPFF_CHECK_OVERLAP)) != 0
841 if checkOverlap {
842 if overlapped := fu.FindOverlappingFlows(flows, mod); len(overlapped) != 0 {
843 // TODO: should this error be notified other than being logged?
Girish Kumarf56a4682020-03-20 20:07:46 +0000844 logger.Warnw("overlapped-flows", log.Fields{"logicaldeviceId": agent.logicalDeviceID})
khenaidoo19d7b632018-10-30 10:49:50 -0400845 } else {
Matt Jeanneret518b5a42019-10-29 10:30:46 -0400846 // Add flow
Scott Bakerfdea1e32020-02-21 15:35:41 -0800847 flow, err = fu.FlowStatsEntryFromFlowModMessage(mod)
848 if err != nil {
849 return err
850 }
khenaidoo19d7b632018-10-30 10:49:50 -0400851 flows = append(flows, flow)
khenaidoo2c6a0992019-04-29 13:46:56 -0400852 updatedFlows = append(updatedFlows, flow)
khenaidoo19d7b632018-10-30 10:49:50 -0400853 changed = true
854 }
855 } else {
Scott Bakerfdea1e32020-02-21 15:35:41 -0800856 flow, err = fu.FlowStatsEntryFromFlowModMessage(mod)
857 if err != nil {
858 return err
859 }
khenaidoo19d7b632018-10-30 10:49:50 -0400860 idx := fu.FindFlows(flows, flow)
861 if idx >= 0 {
khenaidoo8b4abbf2020-04-24 17:04:30 -0400862 flowToReplace = flows[idx]
khenaidoo19d7b632018-10-30 10:49:50 -0400863 if (mod.Flags & uint32(ofp.OfpFlowModFlags_OFPFF_RESET_COUNTS)) != 0 {
khenaidoo8b4abbf2020-04-24 17:04:30 -0400864 flow.ByteCount = flowToReplace.ByteCount
865 flow.PacketCount = flowToReplace.PacketCount
khenaidoo19d7b632018-10-30 10:49:50 -0400866 }
khenaidoo8b4abbf2020-04-24 17:04:30 -0400867 if !proto.Equal(flowToReplace, flow) {
Matt Jeanneret518b5a42019-10-29 10:30:46 -0400868 flows[idx] = flow
869 updatedFlows = append(updatedFlows, flow)
870 changed = true
871 updated = true
872 }
873 } else {
khenaidoo19d7b632018-10-30 10:49:50 -0400874 flows = append(flows, flow)
khenaidoo2c6a0992019-04-29 13:46:56 -0400875 updatedFlows = append(updatedFlows, flow)
876 changed = true
khenaidoo19d7b632018-10-30 10:49:50 -0400877 }
khenaidoo19d7b632018-10-30 10:49:50 -0400878 }
Girish Kumarf56a4682020-03-20 20:07:46 +0000879 logger.Debugw("flowAdd-changed", log.Fields{"changed": changed})
khenaidoo4c9e5592019-09-09 16:20:41 -0400880
khenaidoo19d7b632018-10-30 10:49:50 -0400881 if changed {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400882 var flowMetadata voltha.FlowMetadata
883 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 +0000884 logger.Error("Meter-referred-in-flows-not-present")
Manikkaraj kb1a10922019-07-29 12:10:34 -0400885 return err
886 }
khenaidoo820197c2020-02-13 16:35:33 -0500887 deviceRules, err := agent.flowDecomposer.DecomposeRules(ctx, agent, ofp.Flows{Items: updatedFlows}, *lDevice.FlowGroups)
888 if err != nil {
889 return err
890 }
Girish Kumarf56a4682020-03-20 20:07:46 +0000891 logger.Debugw("rules", log.Fields{"rules": deviceRules.String()})
khenaidoo0458db62019-06-20 08:50:36 -0400892
khenaidoo19d7b632018-10-30 10:49:50 -0400893 // Update model
npujar467fe752020-01-16 20:17:45 +0530894 if err := agent.updateLogicalDeviceFlowsWithoutLock(ctx, &ofp.Flows{Items: flows}); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000895 logger.Errorw("db-flow-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo19d7b632018-10-30 10:49:50 -0400896 return err
897 }
khenaidoo8b4abbf2020-04-24 17:04:30 -0400898
Matt Jeanneret518b5a42019-10-29 10:30:46 -0400899 if !updated {
khenaidoo8b4abbf2020-04-24 17:04:30 -0400900 changedMeterStats := agent.updateFlowCountOfMeterStats(mod, meters, flow, false)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400901 metersToUpdate := &ofp.Meters{}
902 if lDevice.Meters != nil {
903 metersToUpdate = &ofp.Meters{Items: meters}
904 }
905 if changedMeterStats {
906 //Update model
npujar467fe752020-01-16 20:17:45 +0530907 if err := agent.updateLogicalDeviceMetersWithoutLock(ctx, metersToUpdate); err != nil {
khenaidoo8b4abbf2020-04-24 17:04:30 -0400908 logger.Errorw("db-meter-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "error": err})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400909 return err
910 }
Girish Kumarf56a4682020-03-20 20:07:46 +0000911 logger.Debugw("meter-stats-updated-in-DB-successfully", log.Fields{"updated_meters": meters})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400912
913 }
914 }
khenaidoo442e7c72020-03-10 16:13:48 -0400915 // Send the flows to the devices
916 respChannels := agent.addFlowsAndGroupsToDevices(ctx, deviceRules, &flowMetadata)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400917
khenaidoo442e7c72020-03-10 16:13:48 -0400918 // Create the go routines to wait
919 go func() {
920 // Wait for completion
921 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChannels...); res != nil {
khenaidoo8b4abbf2020-04-24 17:04:30 -0400922 logger.Infow("failed-to-add-flows-will-attempt-deletion", log.Fields{"errors": res, "logical-device-id": agent.logicalDeviceID})
923 // Revert added flows
924 if err := agent.revertAddedFlows(context.Background(), mod, flow, flowToReplace, deviceRules, &flowMetadata); err != nil {
925 logger.Errorw("failure-to-delete-flows-after-failed-addition", log.Fields{"logical-device-id": agent.logicalDeviceID, "error": err})
926 }
khenaidoo442e7c72020-03-10 16:13:48 -0400927 }
928 }()
khenaidoo19d7b632018-10-30 10:49:50 -0400929 }
khenaidoo19d7b632018-10-30 10:49:50 -0400930 return nil
931}
932
khenaidoo8b4abbf2020-04-24 17:04:30 -0400933// revertAddedFlows reverts flows after the flowAdd request has failed. All flows corresponding to that flowAdd request
934// will be reverted, both from the logical devices and the devices.
935func (agent *LogicalAgent) revertAddedFlows(ctx context.Context, mod *ofp.OfpFlowMod, addedFlow *ofp.OfpFlowStats, replacedFlow *ofp.OfpFlowStats, deviceRules *fu.DeviceRules, metadata *voltha.FlowMetadata) error {
936 logger.Debugw("revertFlowAdd", log.Fields{"added-flow": addedFlow, "replaced-flow": replacedFlow, "device-rules": deviceRules, "metadata": metadata})
937 if err := agent.requestQueue.WaitForGreenLight(context.Background()); err != nil {
938 return err
939 }
940 defer agent.requestQueue.RequestComplete()
941
942 lDevice := agent.getLogicalDeviceWithoutLock()
943
944 // Revert flows
945 clonedFlows := cloneFlows(lDevice.Flows.Items)
946 idx := fu.FindFlows(clonedFlows, addedFlow)
947 if idx < 0 {
948 // Not found - do nothing
949 log.Debugw("flow-not-found", log.Fields{"added-flow": addedFlow})
950 return nil
951 }
952 if replacedFlow != nil {
953 clonedFlows[idx] = replacedFlow
954 } else {
955 clonedFlows = deleteFlowWithoutPreservingOrder(clonedFlows, idx)
956 }
957 lDevice.Flows = &ofp.Flows{Items: clonedFlows}
958
khenaidooa29a4712020-05-05 10:17:17 -0400959 // Revert meters, if necessary
960 if lDevice.Meters != nil && len(lDevice.Meters.Items) > 0 {
961 meters := cloneMeters(lDevice.Meters.Items)
962 changedMeterStats := agent.updateFlowCountOfMeterStats(mod, meters, addedFlow, true)
963 if changedMeterStats {
964 lDevice.Meters = &ofp.Meters{Items: meters}
965 }
khenaidoo8b4abbf2020-04-24 17:04:30 -0400966 }
967
968 // Update the model
969 if err := agent.updateLogicalDeviceWithoutLock(ctx, lDevice); err != nil {
970 logger.Errorw("db-flow-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "error": err})
971 return err
972 }
973
974 // Update the devices
975 respChnls := agent.deleteFlowsAndGroupsFromDevices(ctx, deviceRules, metadata)
976
977 // Wait for the responses
978 go func() {
979 // Since this action is taken following an add failure, we may also receive a failure for the revert
980 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil {
981 logger.Warnw("failure-reverting-added-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "errors": res})
982 }
983 }()
984
985 return nil
986}
987
npujar1d86a522019-11-14 17:11:16 +0530988// GetMeterConfig returns meter config
Kent Hagerman2b216042020-04-03 18:28:56 -0400989func (agent *LogicalAgent) GetMeterConfig(flows []*ofp.OfpFlowStats, meters []*ofp.OfpMeterEntry, metadata *voltha.FlowMetadata) error {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400990 m := make(map[uint32]bool)
991 for _, flow := range flows {
npujar1d86a522019-11-14 17:11:16 +0530992 if flowMeterID := fu.GetMeterIdFromFlow(flow); flowMeterID != 0 && !m[flowMeterID] {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400993 foundMeter := false
994 // Meter is present in the flow , Get from logical device
995 for _, meter := range meters {
996 if flowMeterID == meter.Config.MeterId {
997 metadata.Meters = append(metadata.Meters, meter.Config)
Girish Kumarf56a4682020-03-20 20:07:46 +0000998 logger.Debugw("Found meter in logical device",
Manikkaraj kb1a10922019-07-29 12:10:34 -0400999 log.Fields{"meterID": flowMeterID, "meter-band": meter.Config})
1000 m[flowMeterID] = true
1001 foundMeter = true
1002 break
1003 }
1004 }
1005 if !foundMeter {
Girish Kumarf56a4682020-03-20 20:07:46 +00001006 logger.Errorw("Meter-referred-by-flow-is-not-found-in-logicaldevice",
npujar1d86a522019-11-14 17:11:16 +05301007 log.Fields{"meterID": flowMeterID, "Available-meters": meters, "flow": *flow})
Manikkaraj kb1a10922019-07-29 12:10:34 -04001008 return errors.New("Meter-referred-by-flow-is-not-found-in-logicaldevice")
1009 }
1010 }
1011 }
Girish Kumarf56a4682020-03-20 20:07:46 +00001012 logger.Debugw("meter-bands-for-flows", log.Fields{"flows": len(flows), "metadata": metadata})
Manikkaraj kb1a10922019-07-29 12:10:34 -04001013 return nil
1014
1015}
1016
khenaidoo19d7b632018-10-30 10:49:50 -04001017//flowDelete deletes a flow from the flow table of that logical device
Kent Hagerman2b216042020-04-03 18:28:56 -04001018func (agent *LogicalAgent) flowDelete(ctx context.Context, mod *ofp.OfpFlowMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +00001019 logger.Debug("flowDelete")
khenaidoo19d7b632018-10-30 10:49:50 -04001020 if mod == nil {
1021 return nil
1022 }
khenaidoo442e7c72020-03-10 16:13:48 -04001023 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1024 return err
1025 }
1026 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -04001027
khenaidoo6e55d9e2019-12-12 18:26:26 -05001028 lDevice := agent.getLogicalDeviceWithoutLock()
khenaidoo19d7b632018-10-30 10:49:50 -04001029
Manikkaraj kb1a10922019-07-29 12:10:34 -04001030 var meters []*ofp.OfpMeterEntry
1031 var flows []*ofp.OfpFlowStats
Esin Karamanfc3b1af2020-01-29 16:52:00 +00001032 var flowGroups []*ofp.OfpGroupEntry
Manikkaraj kb1a10922019-07-29 12:10:34 -04001033
1034 if lDevice.Flows != nil && lDevice.Flows.Items != nil {
1035 flows = lDevice.Flows.Items
1036 }
1037
1038 if lDevice.Meters != nil && lDevice.Meters.Items != nil {
1039 meters = lDevice.Meters.Items
1040 }
Esin Karamanfc3b1af2020-01-29 16:52:00 +00001041
1042 if lDevice.FlowGroups != nil && lDevice.FlowGroups.Items != nil {
1043 flowGroups = lDevice.FlowGroups.Items
1044 }
1045
khenaidoo19d7b632018-10-30 10:49:50 -04001046 //build a list of what to keep vs what to delete
1047 toKeep := make([]*ofp.OfpFlowStats, 0)
khenaidoo0458db62019-06-20 08:50:36 -04001048 toDelete := make([]*ofp.OfpFlowStats, 0)
khenaidoo19d7b632018-10-30 10:49:50 -04001049 for _, f := range flows {
khenaidoo0458db62019-06-20 08:50:36 -04001050 // Check whether the flow and the flowmod matches
Scott Bakerfdea1e32020-02-21 15:35:41 -08001051 fs, err := fu.FlowStatsEntryFromFlowModMessage(mod)
1052 if err != nil {
1053 return err
1054 }
1055 if fu.FlowMatch(f, fs) {
khenaidoo0458db62019-06-20 08:50:36 -04001056 toDelete = append(toDelete, f)
1057 continue
1058 }
1059 // Check wild card match
khenaidoo19d7b632018-10-30 10:49:50 -04001060 if !fu.FlowMatchesMod(f, mod) {
1061 toKeep = append(toKeep, f)
khenaidoo0458db62019-06-20 08:50:36 -04001062 } else {
1063 toDelete = append(toDelete, f)
khenaidoo19d7b632018-10-30 10:49:50 -04001064 }
1065 }
1066
Girish Kumarf56a4682020-03-20 20:07:46 +00001067 logger.Debugw("flowDelete", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "toKeep": len(toKeep), "toDelete": toDelete})
khenaidoo0458db62019-06-20 08:50:36 -04001068
khenaidoo19d7b632018-10-30 10:49:50 -04001069 //Update flows
khenaidoo0458db62019-06-20 08:50:36 -04001070 if len(toDelete) > 0 {
Manikkaraj kb1a10922019-07-29 12:10:34 -04001071 var flowMetadata voltha.FlowMetadata
1072 if err := agent.GetMeterConfig(toDelete, meters, &flowMetadata); err != nil { // This should never happen
Girish Kumarf56a4682020-03-20 20:07:46 +00001073 logger.Error("Meter-referred-in-flows-not-present")
Manikkaraj kb1a10922019-07-29 12:10:34 -04001074 return errors.New("Meter-referred-in-flows-not-present")
1075 }
khenaidoo787224a2020-04-16 18:08:47 -04001076
1077 var respChnls []coreutils.Response
1078 var partialRoute bool
khenaidoo820197c2020-02-13 16:35:33 -05001079 deviceRules, err := agent.flowDecomposer.DecomposeRules(ctx, agent, ofp.Flows{Items: toDelete}, ofp.FlowGroups{Items: flowGroups})
1080 if err != nil {
khenaidoo787224a2020-04-16 18:08:47 -04001081 // A no route error means no route exists between the ports specified in the flow. This can happen when the
1082 // child device is deleted and a request to delete flows from the parent device is received
1083 if !errors.Is(err, route.ErrNoRoute) {
1084 logger.Errorw("unexpected-error-received", log.Fields{"flows-to-delete": toDelete, "error": err})
1085 return err
1086 }
1087 partialRoute = true
khenaidoo820197c2020-02-13 16:35:33 -05001088 }
khenaidoo0458db62019-06-20 08:50:36 -04001089
khenaidoo787224a2020-04-16 18:08:47 -04001090 // Update the dB
npujar467fe752020-01-16 20:17:45 +05301091 if err := agent.updateLogicalDeviceFlowsWithoutLock(ctx, &ofp.Flows{Items: toKeep}); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001092 logger.Errorw("cannot-update-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo19d7b632018-10-30 10:49:50 -04001093 return err
1094 }
khenaidoo442e7c72020-03-10 16:13:48 -04001095
1096 // Update the devices
khenaidoo787224a2020-04-16 18:08:47 -04001097 if partialRoute {
1098 respChnls = agent.deleteFlowsFromParentDevice(ctx, ofp.Flows{Items: toDelete}, &flowMetadata)
1099 } else {
1100 respChnls = agent.deleteFlowsAndGroupsFromDevices(ctx, deviceRules, &flowMetadata)
1101 }
khenaidoo442e7c72020-03-10 16:13:48 -04001102
1103 // Wait for the responses
1104 go func() {
1105 // Wait for completion
1106 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001107 logger.Errorw("failure-updating-device-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "errors": res})
khenaidoo442e7c72020-03-10 16:13:48 -04001108 // TODO: Revert the flow deletion
1109 }
1110 }()
khenaidoo19d7b632018-10-30 10:49:50 -04001111 }
1112
1113 //TODO: send announcement on delete
1114 return nil
1115}
1116
Kent Hagerman2b216042020-04-03 18:28:56 -04001117func (agent *LogicalAgent) addFlowsAndGroupsToDevices(ctx context.Context, deviceRules *fu.DeviceRules, flowMetadata *voltha.FlowMetadata) []coreutils.Response {
Girish Kumarf56a4682020-03-20 20:07:46 +00001118 logger.Debugw("send-add-flows-to-device-manager", log.Fields{"logicalDeviceID": agent.logicalDeviceID, "deviceRules": deviceRules, "flowMetadata": flowMetadata})
khenaidoo19d7b632018-10-30 10:49:50 -04001119
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001120 responses := make([]coreutils.Response, 0)
npujar1d86a522019-11-14 17:11:16 +05301121 for deviceID, value := range deviceRules.GetRules() {
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001122 response := coreutils.NewResponse()
1123 responses = append(responses, response)
1124 go func(deviceId string, value *fu.FlowsAndGroups) {
khenaidoo442e7c72020-03-10 16:13:48 -04001125 ctx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
1126 defer cancel()
npujar467fe752020-01-16 20:17:45 +05301127 if err := agent.deviceMgr.addFlowsAndGroups(ctx, deviceId, value.ListFlows(), value.ListGroups(), flowMetadata); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001128 logger.Errorw("flow-add-failed", log.Fields{"deviceID": deviceId, "error": err})
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001129 response.Error(status.Errorf(codes.Internal, "flow-add-failed: %s", deviceId))
khenaidoo0458db62019-06-20 08:50:36 -04001130 }
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001131 response.Done()
npujar1d86a522019-11-14 17:11:16 +05301132 }(deviceID, value)
khenaidoo19d7b632018-10-30 10:49:50 -04001133 }
khenaidoo442e7c72020-03-10 16:13:48 -04001134 // Return responses (an array of channels) for the caller to wait for a response from the far end.
1135 return responses
khenaidoo0458db62019-06-20 08:50:36 -04001136}
khenaidoo19d7b632018-10-30 10:49:50 -04001137
Kent Hagerman2b216042020-04-03 18:28:56 -04001138func (agent *LogicalAgent) deleteFlowsAndGroupsFromDevices(ctx context.Context, deviceRules *fu.DeviceRules, flowMetadata *voltha.FlowMetadata) []coreutils.Response {
Girish Kumarf56a4682020-03-20 20:07:46 +00001139 logger.Debugw("send-delete-flows-to-device-manager", log.Fields{"logicalDeviceID": agent.logicalDeviceID})
khenaidoo0458db62019-06-20 08:50:36 -04001140
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001141 responses := make([]coreutils.Response, 0)
npujar1d86a522019-11-14 17:11:16 +05301142 for deviceID, value := range deviceRules.GetRules() {
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001143 response := coreutils.NewResponse()
1144 responses = append(responses, response)
1145 go func(deviceId string, value *fu.FlowsAndGroups) {
khenaidoo442e7c72020-03-10 16:13:48 -04001146 ctx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
1147 defer cancel()
npujar467fe752020-01-16 20:17:45 +05301148 if err := agent.deviceMgr.deleteFlowsAndGroups(ctx, deviceId, value.ListFlows(), value.ListGroups(), flowMetadata); err != nil {
khenaidoo787224a2020-04-16 18:08:47 -04001149 logger.Errorw("flow-delete-failed", log.Fields{"deviceID": deviceId, "error": err})
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001150 response.Error(status.Errorf(codes.Internal, "flow-delete-failed: %s", deviceId))
khenaidoo0458db62019-06-20 08:50:36 -04001151 }
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001152 response.Done()
npujar1d86a522019-11-14 17:11:16 +05301153 }(deviceID, value)
khenaidoo0458db62019-06-20 08:50:36 -04001154 }
khenaidoo442e7c72020-03-10 16:13:48 -04001155 return responses
khenaidoo0458db62019-06-20 08:50:36 -04001156}
1157
Kent Hagerman2b216042020-04-03 18:28:56 -04001158func (agent *LogicalAgent) updateFlowsAndGroupsOfDevice(ctx context.Context, deviceRules *fu.DeviceRules, flowMetadata *voltha.FlowMetadata) []coreutils.Response {
Girish Kumarf56a4682020-03-20 20:07:46 +00001159 logger.Debugw("send-update-flows-to-device-manager", log.Fields{"logicalDeviceID": agent.logicalDeviceID})
khenaidoo0458db62019-06-20 08:50:36 -04001160
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001161 responses := make([]coreutils.Response, 0)
npujar1d86a522019-11-14 17:11:16 +05301162 for deviceID, value := range deviceRules.GetRules() {
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001163 response := coreutils.NewResponse()
1164 responses = append(responses, response)
1165 go func(deviceId string, value *fu.FlowsAndGroups) {
khenaidoo442e7c72020-03-10 16:13:48 -04001166 ctx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
1167 defer cancel()
npujar467fe752020-01-16 20:17:45 +05301168 if err := agent.deviceMgr.updateFlowsAndGroups(ctx, deviceId, value.ListFlows(), value.ListGroups(), flowMetadata); err != nil {
khenaidoo787224a2020-04-16 18:08:47 -04001169 logger.Errorw("flow-update-failed", log.Fields{"deviceID": deviceId, "error": err})
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001170 response.Error(status.Errorf(codes.Internal, "flow-update-failed: %s", deviceId))
khenaidoo0458db62019-06-20 08:50:36 -04001171 }
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001172 response.Done()
npujar1d86a522019-11-14 17:11:16 +05301173 }(deviceID, value)
khenaidoo0458db62019-06-20 08:50:36 -04001174 }
khenaidoo442e7c72020-03-10 16:13:48 -04001175 return responses
khenaidoo19d7b632018-10-30 10:49:50 -04001176}
1177
khenaidoo787224a2020-04-16 18:08:47 -04001178// getUNILogicalPortNo returns the UNI logical port number specified in the flow
1179func (agent *LogicalAgent) getUNILogicalPortNo(flow *ofp.OfpFlowStats) (uint32, error) {
1180 var uniPort uint32
1181 inPortNo := fu.GetInPort(flow)
1182 outPortNo := fu.GetOutPort(flow)
1183 if agent.isNNIPort(inPortNo) {
1184 uniPort = outPortNo
1185 } else if agent.isNNIPort(outPortNo) {
1186 uniPort = inPortNo
1187 }
1188 if uniPort != 0 {
1189 return uniPort, nil
1190 }
1191 return 0, status.Errorf(codes.NotFound, "no-uni-port: %v", flow)
1192}
1193
1194func (agent *LogicalAgent) deleteFlowsFromParentDevice(ctx context.Context, flows ofp.Flows, metadata *voltha.FlowMetadata) []coreutils.Response {
1195 logger.Debugw("deleting-flows-from-parent-device", log.Fields{"logical-device-id": agent.logicalDeviceID, "flows": flows})
1196 responses := make([]coreutils.Response, 0)
1197 for _, flow := range flows.Items {
1198 response := coreutils.NewResponse()
1199 responses = append(responses, response)
1200 uniPort, err := agent.getUNILogicalPortNo(flow)
1201 if err != nil {
1202 logger.Error("no-uni-port-in-flow", log.Fields{"deviceID": agent.rootDeviceID, "flow": flow, "error": err})
1203 response.Error(err)
1204 response.Done()
1205 continue
1206 }
1207 logger.Debugw("uni-port", log.Fields{"flows": flows, "uni-port": uniPort})
1208 go func(uniPort uint32, metadata *voltha.FlowMetadata) {
1209 ctx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
1210 defer cancel()
1211 if err := agent.deviceMgr.deleteParentFlows(ctx, agent.rootDeviceID, uniPort, metadata); err != nil {
1212 logger.Error("flow-delete-failed", log.Fields{"device-id": agent.rootDeviceID, "error": err})
1213 response.Error(status.Errorf(codes.Internal, "flow-delete-failed: %s %v", agent.rootDeviceID, err))
1214 }
1215 response.Done()
1216 }(uniPort, metadata)
1217 }
1218 return responses
1219}
1220
khenaidoo19d7b632018-10-30 10:49:50 -04001221//flowDeleteStrict deletes a flow from the flow table of that logical device
Kent Hagerman2b216042020-04-03 18:28:56 -04001222func (agent *LogicalAgent) flowDeleteStrict(ctx context.Context, mod *ofp.OfpFlowMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +00001223 logger.Debug("flowDeleteStrict")
khenaidoo19d7b632018-10-30 10:49:50 -04001224 if mod == nil {
1225 return nil
1226 }
khenaidoo442e7c72020-03-10 16:13:48 -04001227 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1228 return err
1229 }
1230 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -04001231
khenaidoo6e55d9e2019-12-12 18:26:26 -05001232 lDevice := agent.getLogicalDeviceWithoutLock()
1233
Manikkaraj kb1a10922019-07-29 12:10:34 -04001234 var meters []*ofp.OfpMeterEntry
1235 var flows []*ofp.OfpFlowStats
Esin Karamanfc3b1af2020-01-29 16:52:00 +00001236 var flowGroups []*ofp.OfpGroupEntry
Manikkaraj kb1a10922019-07-29 12:10:34 -04001237 if lDevice.Meters != nil && lDevice.Meters.Items != nil {
1238 meters = lDevice.Meters.Items
1239 }
1240 if lDevice.Flows != nil && lDevice.Flows.Items != nil {
1241 flows = lDevice.Flows.Items
1242 }
Esin Karamanfc3b1af2020-01-29 16:52:00 +00001243 if lDevice.FlowGroups != nil && lDevice.FlowGroups.Items != nil {
1244 flowGroups = lDevice.FlowGroups.Items
1245 }
Manikkaraj kb1a10922019-07-29 12:10:34 -04001246
1247 changedFlow := false
1248 changedMeter := false
Scott Bakerfdea1e32020-02-21 15:35:41 -08001249 flow, err := fu.FlowStatsEntryFromFlowModMessage(mod)
1250 if err != nil {
1251 return err
1252 }
Manikkaraj kb1a10922019-07-29 12:10:34 -04001253 flowsToDelete := make([]*ofp.OfpFlowStats, 0)
khenaidoo19d7b632018-10-30 10:49:50 -04001254 idx := fu.FindFlows(flows, flow)
1255 if idx >= 0 {
khenaidoo8b4abbf2020-04-24 17:04:30 -04001256 changedMeter = agent.updateFlowCountOfMeterStats(mod, meters, flows[idx], false)
Manikkaraj kb1a10922019-07-29 12:10:34 -04001257 flowsToDelete = append(flowsToDelete, flows[idx])
khenaidoo19d7b632018-10-30 10:49:50 -04001258 flows = append(flows[:idx], flows[idx+1:]...)
Manikkaraj kb1a10922019-07-29 12:10:34 -04001259 changedFlow = true
khenaidoo19d7b632018-10-30 10:49:50 -04001260 } else {
npujar1d86a522019-11-14 17:11:16 +05301261 return fmt.Errorf("Cannot delete flow - %s", flow)
khenaidoo19d7b632018-10-30 10:49:50 -04001262 }
Manikkaraj kb1a10922019-07-29 12:10:34 -04001263 if changedMeter {
1264 //Update model
1265 metersToUpdate := &ofp.Meters{}
1266 if lDevice.Meters != nil {
1267 metersToUpdate = &ofp.Meters{Items: meters}
1268 }
npujar467fe752020-01-16 20:17:45 +05301269 if err := agent.updateLogicalDeviceMetersWithoutLock(ctx, metersToUpdate); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001270 logger.Errorw("db-meter-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
Manikkaraj kb1a10922019-07-29 12:10:34 -04001271 return err
1272 }
khenaidoo19d7b632018-10-30 10:49:50 -04001273
Manikkaraj kb1a10922019-07-29 12:10:34 -04001274 }
1275 if changedFlow {
1276 var flowMetadata voltha.FlowMetadata
1277 if err := agent.GetMeterConfig(flowsToDelete, meters, &flowMetadata); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001278 logger.Error("meter-referred-in-flows-not-present")
Manikkaraj kb1a10922019-07-29 12:10:34 -04001279 return err
1280 }
khenaidoo787224a2020-04-16 18:08:47 -04001281 var respChnls []coreutils.Response
1282 var partialRoute bool
khenaidoo820197c2020-02-13 16:35:33 -05001283 deviceRules, err := agent.flowDecomposer.DecomposeRules(ctx, agent, ofp.Flows{Items: flowsToDelete}, ofp.FlowGroups{Items: flowGroups})
1284 if err != nil {
khenaidoo787224a2020-04-16 18:08:47 -04001285 // A no route error means no route exists between the ports specified in the flow. This can happen when the
1286 // child device is deleted and a request to delete flows from the parent device is received
1287 if !errors.Is(err, route.ErrNoRoute) {
1288 logger.Errorw("unexpected-error-received", log.Fields{"flows-to-delete": flowsToDelete, "error": err})
1289 return err
1290 }
1291 partialRoute = true
khenaidoo820197c2020-02-13 16:35:33 -05001292 }
khenaidoo0458db62019-06-20 08:50:36 -04001293
khenaidoo787224a2020-04-16 18:08:47 -04001294 // Update the dB
npujar467fe752020-01-16 20:17:45 +05301295 if err := agent.updateLogicalDeviceFlowsWithoutLock(ctx, &ofp.Flows{Items: flows}); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001296 logger.Errorw("cannot-update-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo19d7b632018-10-30 10:49:50 -04001297 return err
1298 }
khenaidoo442e7c72020-03-10 16:13:48 -04001299
1300 // Update the devices
khenaidoo787224a2020-04-16 18:08:47 -04001301 if partialRoute {
1302 respChnls = agent.deleteFlowsFromParentDevice(ctx, ofp.Flows{Items: flowsToDelete}, &flowMetadata)
1303 } else {
1304 respChnls = agent.deleteFlowsAndGroupsFromDevices(ctx, deviceRules, &flowMetadata)
1305 }
khenaidoo442e7c72020-03-10 16:13:48 -04001306
1307 // Wait for completion
1308 go func() {
1309 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001310 logger.Warnw("failure-deleting-device-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "errors": res})
khenaidoo442e7c72020-03-10 16:13:48 -04001311 //TODO: Revert flow changes
1312 }
1313 }()
khenaidoo19d7b632018-10-30 10:49:50 -04001314 }
khenaidoo19d7b632018-10-30 10:49:50 -04001315 return nil
1316}
1317
1318//flowModify modifies a flow from the flow table of that logical device
Kent Hagerman2b216042020-04-03 18:28:56 -04001319func (agent *LogicalAgent) flowModify(mod *ofp.OfpFlowMod) error {
khenaidoo19d7b632018-10-30 10:49:50 -04001320 return errors.New("flowModify not implemented")
1321}
1322
1323//flowModifyStrict deletes a flow from the flow table of that logical device
Kent Hagerman2b216042020-04-03 18:28:56 -04001324func (agent *LogicalAgent) flowModifyStrict(mod *ofp.OfpFlowMod) error {
khenaidoo19d7b632018-10-30 10:49:50 -04001325 return errors.New("flowModifyStrict not implemented")
1326}
1327
Kent Hagerman2b216042020-04-03 18:28:56 -04001328func (agent *LogicalAgent) groupAdd(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +00001329 logger.Debug("groupAdd")
khenaidoo19d7b632018-10-30 10:49:50 -04001330 if groupMod == nil {
1331 return nil
1332 }
khenaidoo442e7c72020-03-10 16:13:48 -04001333 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1334 return err
1335 }
1336 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -04001337
khenaidoo6e55d9e2019-12-12 18:26:26 -05001338 lDevice := agent.getLogicalDeviceWithoutLock()
1339
khenaidoo19d7b632018-10-30 10:49:50 -04001340 groups := lDevice.FlowGroups.Items
khenaidoo19d7b632018-10-30 10:49:50 -04001341 if fu.FindGroup(groups, groupMod.GroupId) == -1 {
khenaidoo68c930b2019-05-13 11:46:51 -04001342 groups = append(groups, fu.GroupEntryFromGroupMod(groupMod))
khenaidoo0458db62019-06-20 08:50:36 -04001343
Esin Karaman2ea59212019-12-06 11:41:58 +00001344 deviceRules := fu.NewDeviceRules()
1345 deviceRules.CreateEntryIfNotExist(agent.rootDeviceID)
1346 fg := fu.NewFlowsAndGroups()
1347 fg.AddGroup(fu.GroupEntryFromGroupMod(groupMod))
1348 deviceRules.AddFlowsAndGroup(agent.rootDeviceID, fg)
1349
Girish Kumarf56a4682020-03-20 20:07:46 +00001350 logger.Debugw("rules", log.Fields{"rules for group-add": deviceRules.String()})
khenaidoo0458db62019-06-20 08:50:36 -04001351
npujar467fe752020-01-16 20:17:45 +05301352 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(ctx, &ofp.FlowGroups{Items: groups}); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001353 logger.Errorw("cannot-update-group", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo19d7b632018-10-30 10:49:50 -04001354 return err
1355 }
khenaidoo442e7c72020-03-10 16:13:48 -04001356
1357 // Update the devices
1358 respChnls := agent.addFlowsAndGroupsToDevices(ctx, deviceRules, &voltha.FlowMetadata{})
1359
1360 // Wait for completion
1361 go func() {
1362 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001363 logger.Warnw("failure-updating-device-flows-groups", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "errors": res})
khenaidoo442e7c72020-03-10 16:13:48 -04001364 //TODO: Revert flow changes
1365 }
1366 }()
1367 return nil
khenaidoo19d7b632018-10-30 10:49:50 -04001368 }
khenaidoo442e7c72020-03-10 16:13:48 -04001369 return fmt.Errorf("Groups %d already present", groupMod.GroupId)
khenaidoo19d7b632018-10-30 10:49:50 -04001370}
1371
Kent Hagerman2b216042020-04-03 18:28:56 -04001372func (agent *LogicalAgent) groupDelete(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +00001373 logger.Debug("groupDelete")
khenaidoo19d7b632018-10-30 10:49:50 -04001374 if groupMod == nil {
1375 return nil
1376 }
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 lDevice := agent.getLogicalDeviceWithoutLock()
khenaidoo19d7b632018-10-30 10:49:50 -04001383 groups := lDevice.FlowGroups.Items
1384 flows := lDevice.Flows.Items
npujar1d86a522019-11-14 17:11:16 +05301385 var groupsChanged bool
khenaidoo19d7b632018-10-30 10:49:50 -04001386 flowsChanged := false
npujar1d86a522019-11-14 17:11:16 +05301387 groupID := groupMod.GroupId
1388 if groupID == uint32(ofp.OfpGroup_OFPG_ALL) {
khenaidoo19d7b632018-10-30 10:49:50 -04001389 //TODO we must delete all flows that point to this group and
1390 //signal controller as requested by flow's flag
1391 groups = []*ofp.OfpGroupEntry{}
1392 groupsChanged = true
1393 } else {
npujar1d86a522019-11-14 17:11:16 +05301394 idx := fu.FindGroup(groups, groupID)
1395 if idx == -1 {
khenaidoo19d7b632018-10-30 10:49:50 -04001396 return nil // Valid case
khenaidoo19d7b632018-10-30 10:49:50 -04001397 }
npujar1d86a522019-11-14 17:11:16 +05301398 flowsChanged, flows = fu.FlowsDeleteByGroupId(flows, groupID)
1399 groups = append(groups[:idx], groups[idx+1:]...)
1400 groupsChanged = true
khenaidoo19d7b632018-10-30 10:49:50 -04001401 }
khenaidoo0458db62019-06-20 08:50:36 -04001402 if flowsChanged || groupsChanged {
khenaidoo820197c2020-02-13 16:35:33 -05001403 deviceRules, err := agent.flowDecomposer.DecomposeRules(ctx, agent, ofp.Flows{Items: flows}, ofp.FlowGroups{Items: groups})
1404 if err != nil {
1405 return err
1406 }
Girish Kumarf56a4682020-03-20 20:07:46 +00001407 logger.Debugw("rules", log.Fields{"rules": deviceRules.String()})
khenaidoo0458db62019-06-20 08:50:36 -04001408
khenaidoo442e7c72020-03-10 16:13:48 -04001409 if groupsChanged {
1410 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(ctx, &ofp.FlowGroups{Items: groups}); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001411 logger.Errorw("cannot-update-group", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo442e7c72020-03-10 16:13:48 -04001412 return err
1413 }
khenaidoo0458db62019-06-20 08:50:36 -04001414 }
khenaidoo442e7c72020-03-10 16:13:48 -04001415 if flowsChanged {
1416 if err := agent.updateLogicalDeviceFlowsWithoutLock(ctx, &ofp.Flows{Items: flows}); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001417 logger.Errorw("cannot-update-flow", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo442e7c72020-03-10 16:13:48 -04001418 return err
1419 }
1420 }
khenaidoo0458db62019-06-20 08:50:36 -04001421
khenaidoo442e7c72020-03-10 16:13:48 -04001422 // Update the devices
1423 respChnls := agent.updateFlowsAndGroupsOfDevice(ctx, deviceRules, nil)
1424
1425 // Wait for completion
1426 go func() {
1427 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001428 logger.Warnw("failure-updating-device-flows-groups", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "errors": res})
khenaidoo442e7c72020-03-10 16:13:48 -04001429 //TODO: Revert flow changes
1430 }
1431 }()
khenaidoo43c82122018-11-22 18:38:28 -05001432 }
khenaidoo19d7b632018-10-30 10:49:50 -04001433 return nil
1434}
1435
Kent Hagerman2b216042020-04-03 18:28:56 -04001436func (agent *LogicalAgent) groupModify(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +00001437 logger.Debug("groupModify")
khenaidoo19d7b632018-10-30 10:49:50 -04001438 if groupMod == nil {
1439 return nil
1440 }
khenaidoo442e7c72020-03-10 16:13:48 -04001441 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1442 return err
1443 }
1444 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -04001445
khenaidoo6e55d9e2019-12-12 18:26:26 -05001446 lDevice := agent.getLogicalDeviceWithoutLock()
khenaidoo19d7b632018-10-30 10:49:50 -04001447 groups := lDevice.FlowGroups.Items
npujar1d86a522019-11-14 17:11:16 +05301448 var groupsChanged bool
1449 groupID := groupMod.GroupId
1450 idx := fu.FindGroup(groups, groupID)
1451 if idx == -1 {
1452 return fmt.Errorf("group-absent:%d", groupID)
khenaidoo19d7b632018-10-30 10:49:50 -04001453 }
npujar1d86a522019-11-14 17:11:16 +05301454 //replace existing group entry with new group definition
1455 groupEntry := fu.GroupEntryFromGroupMod(groupMod)
1456 groups[idx] = groupEntry
1457 groupsChanged = true
khenaidoo19d7b632018-10-30 10:49:50 -04001458 if groupsChanged {
Esin Karaman2ea59212019-12-06 11:41:58 +00001459 deviceRules := fu.NewDeviceRules()
1460 deviceRules.CreateEntryIfNotExist(agent.rootDeviceID)
1461 fg := fu.NewFlowsAndGroups()
1462 fg.AddGroup(fu.GroupEntryFromGroupMod(groupMod))
1463 deviceRules.AddFlowsAndGroup(agent.rootDeviceID, fg)
khenaidoo0458db62019-06-20 08:50:36 -04001464
Girish Kumarf56a4682020-03-20 20:07:46 +00001465 logger.Debugw("rules", log.Fields{"rules for group-modify": deviceRules.String()})
khenaidoo0458db62019-06-20 08:50:36 -04001466
npujar467fe752020-01-16 20:17:45 +05301467 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(ctx, &ofp.FlowGroups{Items: groups}); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001468 logger.Errorw("Cannot-update-logical-group", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo19d7b632018-10-30 10:49:50 -04001469 return err
1470 }
khenaidoo442e7c72020-03-10 16:13:48 -04001471
1472 // Update the devices
1473 respChnls := agent.updateFlowsAndGroupsOfDevice(ctx, deviceRules, &voltha.FlowMetadata{})
1474
1475 // Wait for completion
1476 go func() {
1477 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001478 logger.Warnw("failure-updating-device-flows-groups", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "errors": res})
khenaidoo442e7c72020-03-10 16:13:48 -04001479 //TODO: Revert flow changes
1480 }
1481 }()
khenaidoo19d7b632018-10-30 10:49:50 -04001482 }
1483 return nil
1484}
1485
1486// deleteLogicalPort removes the logical port
Kent Hagerman2b216042020-04-03 18:28:56 -04001487func (agent *LogicalAgent) deleteLogicalPort(ctx context.Context, lPort *voltha.LogicalPort) error {
khenaidoo442e7c72020-03-10 16:13:48 -04001488 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1489 return err
1490 }
1491 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -04001492
khenaidoo6e55d9e2019-12-12 18:26:26 -05001493 logicalDevice := agent.getLogicalDeviceWithoutLock()
1494
khenaidoo92e62c52018-10-03 14:02:54 -04001495 index := -1
khenaidoo6e55d9e2019-12-12 18:26:26 -05001496 for i, logicalPort := range logicalDevice.Ports {
khenaidoo19d7b632018-10-30 10:49:50 -04001497 if logicalPort.Id == lPort.Id {
khenaidoo92e62c52018-10-03 14:02:54 -04001498 index = i
1499 break
1500 }
1501 }
1502 if index >= 0 {
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001503 clonedPorts := clonePorts(logicalDevice.Ports)
1504 if index < len(clonedPorts)-1 {
1505 copy(clonedPorts[index:], clonedPorts[index+1:])
1506 }
1507 clonedPorts[len(clonedPorts)-1] = nil
1508 clonedPorts = clonedPorts[:len(clonedPorts)-1]
Girish Kumarf56a4682020-03-20 20:07:46 +00001509 logger.Debugw("logical-port-deleted", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001510 if err := agent.updateLogicalDevicePortsWithoutLock(ctx, logicalDevice, clonedPorts); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001511 logger.Errorw("logical-device-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo0a822f92019-05-08 15:15:57 -04001512 return err
1513 }
khenaidoo820197c2020-02-13 16:35:33 -05001514
1515 // Remove the logical port from cache
1516 agent.deleteLogicalPortsFromMap([]uint32{lPort.DevicePortNo})
1517
1518 // Reset the logical device routes
1519 go func() {
1520 if err := agent.buildRoutes(context.Background()); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001521 logger.Warnw("device-routes-not-ready", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "error": err})
khenaidoo820197c2020-02-13 16:35:33 -05001522 }
1523 }()
khenaidoo92e62c52018-10-03 14:02:54 -04001524 }
1525 return nil
khenaidoob9203542018-09-17 22:56:37 -04001526}
1527
khenaidoo0a822f92019-05-08 15:15:57 -04001528// deleteLogicalPorts removes the logical ports associated with that deviceId
Kent Hagerman2b216042020-04-03 18:28:56 -04001529func (agent *LogicalAgent) deleteLogicalPorts(ctx context.Context, deviceID string) error {
Andrea Campanella09400bd2020-04-02 11:58:04 +02001530 logger.Debugw("deleting-logical-ports", log.Fields{"device-id": deviceID})
khenaidoo442e7c72020-03-10 16:13:48 -04001531 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1532 return err
1533 }
1534 defer agent.requestQueue.RequestComplete()
khenaidoo0a822f92019-05-08 15:15:57 -04001535
khenaidoo6e55d9e2019-12-12 18:26:26 -05001536 logicalDevice := agent.getLogicalDeviceWithoutLock()
khenaidoo820197c2020-02-13 16:35:33 -05001537 lPortstoKeep := []*voltha.LogicalPort{}
1538 lPortsNoToDelete := []uint32{}
khenaidoo6e55d9e2019-12-12 18:26:26 -05001539 for _, logicalPort := range logicalDevice.Ports {
npujar1d86a522019-11-14 17:11:16 +05301540 if logicalPort.DeviceId != deviceID {
khenaidoo820197c2020-02-13 16:35:33 -05001541 lPortstoKeep = append(lPortstoKeep, logicalPort)
1542 } else {
1543 lPortsNoToDelete = append(lPortsNoToDelete, logicalPort.DevicePortNo)
khenaidoo0a822f92019-05-08 15:15:57 -04001544 }
1545 }
Andrea Campanella09400bd2020-04-02 11:58:04 +02001546 logger.Debugw("deleted-logical-ports", log.Fields{"ports": lPortstoKeep})
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001547 if err := agent.updateLogicalDevicePortsWithoutLock(ctx, logicalDevice, lPortstoKeep); err != nil {
Andrea Campanella09400bd2020-04-02 11:58:04 +02001548 logger.Errorw("logical-device-update-failed", log.Fields{"logical-device-id": agent.logicalDeviceID})
khenaidoo0a822f92019-05-08 15:15:57 -04001549 return err
1550 }
khenaidoo820197c2020-02-13 16:35:33 -05001551 // Remove the port from the cached logical ports set
1552 agent.deleteLogicalPortsFromMap(lPortsNoToDelete)
1553
1554 // Reset the logical device routes
1555 go func() {
1556 if err := agent.buildRoutes(context.Background()); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001557 logger.Warnw("routes-not-ready", log.Fields{"logical-device-id": agent.logicalDeviceID, "error": err})
khenaidoo820197c2020-02-13 16:35:33 -05001558 }
1559 }()
khenaidoo0a822f92019-05-08 15:15:57 -04001560
1561 return nil
1562}
1563
khenaidoo19d7b632018-10-30 10:49:50 -04001564// enableLogicalPort enables the logical port
Kent Hagerman2b216042020-04-03 18:28:56 -04001565func (agent *LogicalAgent) enableLogicalPort(ctx context.Context, lPortID string) error {
khenaidoo442e7c72020-03-10 16:13:48 -04001566 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1567 return err
1568 }
1569 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -04001570
khenaidoo6e55d9e2019-12-12 18:26:26 -05001571 logicalDevice := agent.getLogicalDeviceWithoutLock()
1572
khenaidoo19d7b632018-10-30 10:49:50 -04001573 index := -1
khenaidoo6e55d9e2019-12-12 18:26:26 -05001574 for i, logicalPort := range logicalDevice.Ports {
npujar1d86a522019-11-14 17:11:16 +05301575 if logicalPort.Id == lPortID {
khenaidoo19d7b632018-10-30 10:49:50 -04001576 index = i
1577 break
1578 }
1579 }
1580 if index >= 0 {
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001581 clonedPorts := clonePorts(logicalDevice.Ports)
1582 clonedPorts[index].OfpPort.Config = clonedPorts[index].OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
1583 return agent.updateLogicalDevicePortsWithoutLock(ctx, logicalDevice, clonedPorts)
khenaidoo19d7b632018-10-30 10:49:50 -04001584 }
npujar1d86a522019-11-14 17:11:16 +05301585 return status.Errorf(codes.NotFound, "Port %s on Logical Device %s", lPortID, agent.logicalDeviceID)
khenaidoo19d7b632018-10-30 10:49:50 -04001586}
1587
1588// disableLogicalPort disabled the logical port
Kent Hagerman2b216042020-04-03 18:28:56 -04001589func (agent *LogicalAgent) disableLogicalPort(ctx context.Context, lPortID string) error {
khenaidoo442e7c72020-03-10 16:13:48 -04001590 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1591 return err
1592 }
1593 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -04001594
1595 // Get the most up to date logical device
khenaidoo6e55d9e2019-12-12 18:26:26 -05001596 logicalDevice := agent.getLogicalDeviceWithoutLock()
khenaidoo19d7b632018-10-30 10:49:50 -04001597 index := -1
khenaidoo6e55d9e2019-12-12 18:26:26 -05001598 for i, logicalPort := range logicalDevice.Ports {
npujar1d86a522019-11-14 17:11:16 +05301599 if logicalPort.Id == lPortID {
khenaidoo19d7b632018-10-30 10:49:50 -04001600 index = i
1601 break
1602 }
1603 }
1604 if index >= 0 {
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001605 clonedPorts := clonePorts(logicalDevice.Ports)
1606 clonedPorts[index].OfpPort.Config = (clonedPorts[index].OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)) | uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
1607 return agent.updateLogicalDevicePortsWithoutLock(ctx, logicalDevice, clonedPorts)
khenaidoo19d7b632018-10-30 10:49:50 -04001608 }
npujar1d86a522019-11-14 17:11:16 +05301609 return status.Errorf(codes.NotFound, "Port %s on Logical Device %s", lPortID, agent.logicalDeviceID)
khenaidoo19d7b632018-10-30 10:49:50 -04001610}
1611
Kent Hagerman2b216042020-04-03 18:28:56 -04001612func (agent *LogicalAgent) getPreCalculatedRoute(ingress, egress uint32) ([]route.Hop, error) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001613 logger.Debugw("ROUTE", log.Fields{"len": len(agent.deviceRoutes.Routes)})
khenaidoo820197c2020-02-13 16:35:33 -05001614 for routeLink, route := range agent.deviceRoutes.Routes {
Girish Kumarf56a4682020-03-20 20:07:46 +00001615 logger.Debugw("ROUTELINKS", log.Fields{"ingress": ingress, "egress": egress, "routelink": routeLink})
khenaidoo89b0e942018-10-21 21:11:33 -04001616 if ingress == routeLink.Ingress && egress == routeLink.Egress {
khenaidoo820197c2020-02-13 16:35:33 -05001617 return route, nil
khenaidoo89b0e942018-10-21 21:11:33 -04001618 }
1619 }
khenaidoo820197c2020-02-13 16:35:33 -05001620 return nil, status.Errorf(codes.FailedPrecondition, "no route from:%d to:%d", ingress, egress)
khenaidoo89b0e942018-10-21 21:11:33 -04001621}
1622
npujar1d86a522019-11-14 17:11:16 +05301623// GetRoute returns route
Kent Hagerman2b216042020-04-03 18:28:56 -04001624func (agent *LogicalAgent) GetRoute(ctx context.Context, ingressPortNo uint32, egressPortNo uint32) ([]route.Hop, error) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001625 logger.Debugw("getting-route", log.Fields{"ingress-port": ingressPortNo, "egress-port": egressPortNo})
khenaidoo820197c2020-02-13 16:35:33 -05001626 routes := make([]route.Hop, 0)
khenaidoo2c6a0992019-04-29 13:46:56 -04001627
khenaidoo19d7b632018-10-30 10:49:50 -04001628 // Note: A port value of 0 is equivalent to a nil port
1629
khenaidoo89b0e942018-10-21 21:11:33 -04001630 // Consider different possibilities
khenaidoo19d7b632018-10-30 10:49:50 -04001631 if egressPortNo != 0 && ((egressPortNo & 0x7fffffff) == uint32(ofp.OfpPortNo_OFPP_CONTROLLER)) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001632 logger.Debugw("controller-flow", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "logicalPortsNo": agent.logicalPortsNo})
khenaidoo2c6a0992019-04-29 13:46:56 -04001633 if agent.isNNIPort(ingressPortNo) {
khenaidoo89b0e942018-10-21 21:11:33 -04001634 //This is a trap on the NNI Port
khenaidoo820197c2020-02-13 16:35:33 -05001635 if len(agent.deviceRoutes.Routes) == 0 {
khenaidoo8f474192019-04-03 17:20:44 -04001636 // 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 -04001637 // route with same IngressHop and EgressHop
khenaidoo820197c2020-02-13 16:35:33 -05001638 hop := route.Hop{DeviceID: agent.rootDeviceID, Ingress: ingressPortNo, Egress: ingressPortNo}
khenaidoo8f474192019-04-03 17:20:44 -04001639 routes = append(routes, hop)
1640 routes = append(routes, hop)
khenaidoo820197c2020-02-13 16:35:33 -05001641 return routes, nil
khenaidoo8f474192019-04-03 17:20:44 -04001642 }
khenaidoo89b0e942018-10-21 21:11:33 -04001643 //Return a 'half' route to make the flow decomposer logic happy
khenaidoo820197c2020-02-13 16:35:33 -05001644 for routeLink, path := range agent.deviceRoutes.Routes {
khenaidoo2c6a0992019-04-29 13:46:56 -04001645 if agent.isNNIPort(routeLink.Egress) {
khenaidoo820197c2020-02-13 16:35:33 -05001646 routes = append(routes, route.Hop{}) // first hop is set to empty
1647 routes = append(routes, path[1])
1648 return routes, nil
khenaidoo89b0e942018-10-21 21:11:33 -04001649 }
1650 }
khenaidoo787224a2020-04-16 18:08:47 -04001651 return nil, fmt.Errorf("no upstream route from:%d to:%d :%w", ingressPortNo, egressPortNo, route.ErrNoRoute)
khenaidoo89b0e942018-10-21 21:11:33 -04001652 }
1653 //treat it as if the output port is the first NNI of the OLT
khenaidoo2c6a0992019-04-29 13:46:56 -04001654 var err error
1655 if egressPortNo, err = agent.getFirstNNIPort(); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001656 logger.Warnw("no-nni-port", log.Fields{"error": err})
khenaidoo820197c2020-02-13 16:35:33 -05001657 return nil, err
khenaidoo2c6a0992019-04-29 13:46:56 -04001658 }
khenaidoo89b0e942018-10-21 21:11:33 -04001659 }
1660 //If ingress port is not specified (nil), it may be a wildcarded
1661 //route if egress port is OFPP_CONTROLLER or a nni logical port,
1662 //in which case we need to create a half-route where only the egress
1663 //hop is filled, the first hop is nil
khenaidoo2c6a0992019-04-29 13:46:56 -04001664 if ingressPortNo == 0 && agent.isNNIPort(egressPortNo) {
khenaidoo89b0e942018-10-21 21:11:33 -04001665 // We can use the 2nd hop of any upstream route, so just find the first upstream:
khenaidoo820197c2020-02-13 16:35:33 -05001666 for routeLink, path := range agent.deviceRoutes.Routes {
khenaidoo2c6a0992019-04-29 13:46:56 -04001667 if agent.isNNIPort(routeLink.Egress) {
khenaidoo820197c2020-02-13 16:35:33 -05001668 routes = append(routes, route.Hop{}) // first hop is set to empty
1669 routes = append(routes, path[1])
1670 return routes, nil
khenaidoo89b0e942018-10-21 21:11:33 -04001671 }
1672 }
khenaidoo787224a2020-04-16 18:08:47 -04001673 return nil, fmt.Errorf("no upstream route from:%d to:%d :%w", ingressPortNo, egressPortNo, route.ErrNoRoute)
khenaidoo89b0e942018-10-21 21:11:33 -04001674 }
1675 //If egress port is not specified (nil), we can also can return a "half" route
khenaidoo19d7b632018-10-30 10:49:50 -04001676 if egressPortNo == 0 {
khenaidoo820197c2020-02-13 16:35:33 -05001677 for routeLink, path := range agent.deviceRoutes.Routes {
khenaidoo19d7b632018-10-30 10:49:50 -04001678 if routeLink.Ingress == ingressPortNo {
khenaidoo820197c2020-02-13 16:35:33 -05001679 routes = append(routes, path[0])
1680 routes = append(routes, route.Hop{})
1681 return routes, nil
khenaidoo89b0e942018-10-21 21:11:33 -04001682 }
1683 }
khenaidoo787224a2020-04-16 18:08:47 -04001684 return nil, fmt.Errorf("no downstream route from:%d to:%d :%w", ingressPortNo, egressPortNo, route.ErrNoRoute)
khenaidoo89b0e942018-10-21 21:11:33 -04001685 }
khenaidoo89b0e942018-10-21 21:11:33 -04001686 // Return the pre-calculated route
khenaidoo19d7b632018-10-30 10:49:50 -04001687 return agent.getPreCalculatedRoute(ingressPortNo, egressPortNo)
khenaidoo89b0e942018-10-21 21:11:33 -04001688}
1689
khenaidoo3d3b8c22019-05-22 18:10:39 -04001690//GetWildcardInputPorts filters out the logical port number from the set of logical ports on the device and
1691//returns their port numbers. This function is invoked only during flow decomposition where the lock on the logical
1692//device is already held. Therefore it is safe to retrieve the logical device without lock.
Kent Hagerman2b216042020-04-03 18:28:56 -04001693func (agent *LogicalAgent) GetWildcardInputPorts(excludePort ...uint32) []uint32 {
khenaidoo89b0e942018-10-21 21:11:33 -04001694 lPorts := make([]uint32, 0)
1695 var exclPort uint32
1696 if len(excludePort) == 1 {
1697 exclPort = excludePort[0]
1698 }
khenaidoo6e55d9e2019-12-12 18:26:26 -05001699 lDevice := agent.getLogicalDeviceWithoutLock()
1700 for _, port := range lDevice.Ports {
1701 if port.OfpPort.PortNo != exclPort {
1702 lPorts = append(lPorts, port.OfpPort.PortNo)
khenaidoo89b0e942018-10-21 21:11:33 -04001703 }
1704 }
1705 return lPorts
1706}
khenaidoo19d7b632018-10-30 10:49:50 -04001707
khenaidoo820197c2020-02-13 16:35:33 -05001708// GetDeviceRoutes returns device graph
Kent Hagerman2b216042020-04-03 18:28:56 -04001709func (agent *LogicalAgent) GetDeviceRoutes() *route.DeviceRoutes {
khenaidoo820197c2020-02-13 16:35:33 -05001710 return agent.deviceRoutes
khenaidoo19d7b632018-10-30 10:49:50 -04001711}
1712
khenaidoo820197c2020-02-13 16:35:33 -05001713//rebuildRoutes rebuilds the device routes
Kent Hagerman2b216042020-04-03 18:28:56 -04001714func (agent *LogicalAgent) buildRoutes(ctx context.Context) error {
Girish Kumarf56a4682020-03-20 20:07:46 +00001715 logger.Debugf("building-routes", log.Fields{"logical-device-id": agent.logicalDeviceID})
khenaidoo442e7c72020-03-10 16:13:48 -04001716 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1717 return err
1718 }
1719 defer agent.requestQueue.RequestComplete()
1720
khenaidoo820197c2020-02-13 16:35:33 -05001721 if agent.deviceRoutes == nil {
Kent Hagerman45a13e42020-04-13 12:23:50 -04001722 agent.deviceRoutes = route.NewDeviceRoutes(agent.logicalDeviceID, agent.deviceMgr.getDevice)
khenaidoo2c6a0992019-04-29 13:46:56 -04001723 }
1724 // Get all the logical ports on that logical device
khenaidoo6e55d9e2019-12-12 18:26:26 -05001725 lDevice := agent.getLogicalDeviceWithoutLock()
1726
khenaidoo820197c2020-02-13 16:35:33 -05001727 if err := agent.deviceRoutes.ComputeRoutes(ctx, lDevice.Ports); err != nil {
1728 return err
1729 }
1730 if err := agent.deviceRoutes.Print(); err != nil {
1731 return err
1732 }
1733
khenaidoo2c6a0992019-04-29 13:46:56 -04001734 return nil
khenaidoo19d7b632018-10-30 10:49:50 -04001735}
1736
khenaidoo820197c2020-02-13 16:35:33 -05001737//updateRoutes updates the device routes
Kent Hagerman2b216042020-04-03 18:28:56 -04001738func (agent *LogicalAgent) updateRoutes(ctx context.Context, lp *voltha.LogicalPort) error {
Girish Kumarf56a4682020-03-20 20:07:46 +00001739 logger.Debugw("updateRoutes", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo442e7c72020-03-10 16:13:48 -04001740 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1741 return err
1742 }
1743 defer agent.requestQueue.RequestComplete()
1744
khenaidoo820197c2020-02-13 16:35:33 -05001745 if agent.deviceRoutes == nil {
Kent Hagerman45a13e42020-04-13 12:23:50 -04001746 agent.deviceRoutes = route.NewDeviceRoutes(agent.logicalDeviceID, agent.deviceMgr.getDevice)
khenaidoo910204f2019-04-08 17:56:40 -04001747 }
khenaidoo820197c2020-02-13 16:35:33 -05001748 if err := agent.deviceRoutes.AddPort(ctx, lp, agent.logicalDevice.Ports); err != nil {
1749 return err
khenaidoo0a822f92019-05-08 15:15:57 -04001750 }
khenaidoo820197c2020-02-13 16:35:33 -05001751 if err := agent.deviceRoutes.Print(); err != nil {
1752 return err
1753 }
1754 return nil
khenaidoo0a822f92019-05-08 15:15:57 -04001755}
1756
khenaidoofc1314d2019-03-14 09:34:21 -04001757// diff go over two lists of logical ports and return what's new, what's changed and what's removed.
Kent Hagerman8ad29952020-04-21 11:48:02 -04001758func diff(oldList, newList []*voltha.LogicalPort) (newPorts, changedPorts, deletedPorts map[string]*voltha.LogicalPort) {
1759 newPorts = make(map[string]*voltha.LogicalPort, len(newList))
1760 changedPorts = make(map[string]*voltha.LogicalPort, len(oldList))
1761 deletedPorts = make(map[string]*voltha.LogicalPort, len(oldList))
1762
khenaidoofc1314d2019-03-14 09:34:21 -04001763 for _, n := range newList {
Kent Hagerman8ad29952020-04-21 11:48:02 -04001764 newPorts[n.Id] = n
1765 }
1766
1767 for _, o := range oldList {
1768 if n, have := newPorts[o.Id]; have {
1769 delete(newPorts, o.Id) // not new
1770 if !proto.Equal(n, o) {
1771 changedPorts[n.Id] = n // changed
khenaidoofc1314d2019-03-14 09:34:21 -04001772 }
Kent Hagerman8ad29952020-04-21 11:48:02 -04001773 } else {
1774 deletedPorts[o.Id] = o // deleted
khenaidoo2bc48282019-07-16 18:13:46 -04001775 }
khenaidoofc1314d2019-03-14 09:34:21 -04001776 }
Kent Hagerman8ad29952020-04-21 11:48:02 -04001777
1778 return newPorts, changedPorts, deletedPorts
khenaidoofc1314d2019-03-14 09:34:21 -04001779}
1780
Kent Hagerman8ad29952020-04-21 11:48:02 -04001781// portUpdated is invoked when a port is updated on the logical device
1782func (agent *LogicalAgent) portUpdated(prevPorts, currPorts []*voltha.LogicalPort) interface{} {
khenaidoofc1314d2019-03-14 09:34:21 -04001783 // Get the difference between the two list
Kent Hagerman8ad29952020-04-21 11:48:02 -04001784 newPorts, changedPorts, deletedPorts := diff(prevPorts, currPorts)
1785
khenaidoofc1314d2019-03-14 09:34:21 -04001786 // Send the port change events to the OF controller
khenaidoo2c6a0992019-04-29 13:46:56 -04001787 for _, newP := range newPorts {
Kent Hagerman45a13e42020-04-13 12:23:50 -04001788 go agent.ldeviceMgr.SendChangeEvent(agent.logicalDeviceID,
khenaidoo2c6a0992019-04-29 13:46:56 -04001789 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_ADD, Desc: newP.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001790 }
1791 for _, change := range changedPorts {
Kent Hagerman45a13e42020-04-13 12:23:50 -04001792 go agent.ldeviceMgr.SendChangeEvent(agent.logicalDeviceID,
khenaidoo910204f2019-04-08 17:56:40 -04001793 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_MODIFY, Desc: change.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001794 }
1795 for _, del := range deletedPorts {
Kent Hagerman45a13e42020-04-13 12:23:50 -04001796 go agent.ldeviceMgr.SendChangeEvent(agent.logicalDeviceID,
khenaidoo910204f2019-04-08 17:56:40 -04001797 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_DELETE, Desc: del.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001798 }
1799
1800 return nil
1801}
1802
khenaidoo8f474192019-04-03 17:20:44 -04001803// addNNILogicalPort adds an NNI port to the logical device. It returns a bool representing whether a port has been
1804// added and an eror in case a valid error is encountered. If the port was successfully added it will return
1805// (true, nil). If the device is not in the correct state it will return (false, nil) as this is a valid
1806// scenario. This also applies to the case where the port was already added.
Kent Hagerman2b216042020-04-03 18:28:56 -04001807func (agent *LogicalAgent) addNNILogicalPort(ctx context.Context, device *voltha.Device, port *voltha.Port) (bool, error) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001808 logger.Debugw("addNNILogicalPort", log.Fields{"NNI": port})
Chaitrashree G S7849b322020-03-29 19:25:49 -04001809
khenaidoo442e7c72020-03-10 16:13:48 -04001810 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1811 return false, err
1812 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001813 if agent.portExist(device, port) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001814 logger.Debugw("port-already-exist", log.Fields{"port": port})
khenaidoo442e7c72020-03-10 16:13:48 -04001815 agent.requestQueue.RequestComplete()
khenaidoo8f474192019-04-03 17:20:44 -04001816 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001817 }
khenaidoo442e7c72020-03-10 16:13:48 -04001818 agent.requestQueue.RequestComplete()
khenaidoo1ce37ad2019-03-24 22:07:24 -04001819
khenaidoofc1314d2019-03-14 09:34:21 -04001820 var portCap *ic.PortCapability
1821 var err error
1822 // First get the port capability
npujar467fe752020-01-16 20:17:45 +05301823 if portCap, err = agent.deviceMgr.getPortCapability(ctx, device.Id, port.PortNo); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001824 logger.Errorw("error-retrieving-port-capabilities", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001825 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001826 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001827
khenaidoo442e7c72020-03-10 16:13:48 -04001828 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1829 return false, err
1830 }
1831
1832 defer agent.requestQueue.RequestComplete()
khenaidoo1ce37ad2019-03-24 22:07:24 -04001833 // Double check again if this port has been already added since the getPortCapability could have taken a long time
1834 if agent.portExist(device, port) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001835 logger.Debugw("port-already-exist", log.Fields{"port": port})
khenaidoo8f474192019-04-03 17:20:44 -04001836 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001837 }
1838
khenaidoofc1314d2019-03-14 09:34:21 -04001839 portCap.Port.RootPort = true
1840 lp := (proto.Clone(portCap.Port)).(*voltha.LogicalPort)
1841 lp.DeviceId = device.Id
1842 lp.Id = fmt.Sprintf("nni-%d", port.PortNo)
1843 lp.OfpPort.PortNo = port.PortNo
1844 lp.OfpPort.Name = lp.Id
1845 lp.DevicePortNo = port.PortNo
1846
khenaidoo6e55d9e2019-12-12 18:26:26 -05001847 ld := agent.getLogicalDeviceWithoutLock()
1848
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001849 clonedPorts := clonePorts(ld.Ports)
1850 if clonedPorts == nil {
1851 clonedPorts = make([]*voltha.LogicalPort, 0)
khenaidoofc1314d2019-03-14 09:34:21 -04001852 }
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001853 clonedPorts = append(clonedPorts, lp)
khenaidoofc1314d2019-03-14 09:34:21 -04001854
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001855 if err = agent.updateLogicalDevicePortsWithoutLock(ctx, ld, clonedPorts); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001856 logger.Errorw("error-updating-logical-device", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001857 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001858 }
khenaidoo910204f2019-04-08 17:56:40 -04001859
khenaidoo820197c2020-02-13 16:35:33 -05001860 // Update the device routes with this new logical port
khenaidoo910204f2019-04-08 17:56:40 -04001861 clonedLP := (proto.Clone(lp)).(*voltha.LogicalPort)
khenaidoo820197c2020-02-13 16:35:33 -05001862 go func() {
1863 if err := agent.updateRoutes(context.Background(), clonedLP); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001864 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 -05001865 }
1866 }()
khenaidoo910204f2019-04-08 17:56:40 -04001867
khenaidoo8f474192019-04-03 17:20:44 -04001868 return true, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001869}
1870
Kent Hagerman2b216042020-04-03 18:28:56 -04001871func (agent *LogicalAgent) portExist(device *voltha.Device, port *voltha.Port) bool {
khenaidoo6e55d9e2019-12-12 18:26:26 -05001872 ldevice := agent.getLogicalDeviceWithoutLock()
1873 for _, lPort := range ldevice.Ports {
1874 if lPort.DeviceId == device.Id && lPort.DevicePortNo == port.PortNo && lPort.Id == port.Label {
1875 return true
khenaidoofc1314d2019-03-14 09:34:21 -04001876 }
1877 }
1878 return false
1879}
1880
khenaidoo8f474192019-04-03 17:20:44 -04001881// addUNILogicalPort adds an UNI port to the logical device. It returns a bool representing whether a port has been
1882// added and an eror in case a valid error is encountered. If the port was successfully added it will return
1883// (true, nil). If the device is not in the correct state it will return (false, nil) as this is a valid
1884// scenario. This also applies to the case where the port was already added.
Kent Hagerman2b216042020-04-03 18:28:56 -04001885func (agent *LogicalAgent) addUNILogicalPort(ctx context.Context, childDevice *voltha.Device, port *voltha.Port) (bool, error) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001886 logger.Debugw("addUNILogicalPort", log.Fields{"port": port})
khenaidoo8f474192019-04-03 17:20:44 -04001887 if childDevice.AdminState != voltha.AdminState_ENABLED || childDevice.OperStatus != voltha.OperStatus_ACTIVE {
Girish Kumarf56a4682020-03-20 20:07:46 +00001888 logger.Infow("device-not-ready", log.Fields{"deviceId": childDevice.Id, "admin": childDevice.AdminState, "oper": childDevice.OperStatus})
khenaidoo8f474192019-04-03 17:20:44 -04001889 return false, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001890 }
khenaidoo442e7c72020-03-10 16:13:48 -04001891 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1892 return false, err
1893 }
1894
khenaidoo1ce37ad2019-03-24 22:07:24 -04001895 if agent.portExist(childDevice, port) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001896 logger.Debugw("port-already-exist", log.Fields{"port": port})
khenaidoo442e7c72020-03-10 16:13:48 -04001897 agent.requestQueue.RequestComplete()
khenaidoo8f474192019-04-03 17:20:44 -04001898 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001899 }
khenaidoo442e7c72020-03-10 16:13:48 -04001900 agent.requestQueue.RequestComplete()
khenaidoofc1314d2019-03-14 09:34:21 -04001901 var portCap *ic.PortCapability
1902 var err error
1903 // First get the port capability
npujar467fe752020-01-16 20:17:45 +05301904 if portCap, err = agent.deviceMgr.getPortCapability(ctx, childDevice.Id, port.PortNo); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001905 logger.Errorw("error-retrieving-port-capabilities", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001906 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001907 }
khenaidoo442e7c72020-03-10 16:13:48 -04001908 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1909 return false, err
1910 }
1911 defer agent.requestQueue.RequestComplete()
khenaidoo1ce37ad2019-03-24 22:07:24 -04001912 // Double check again if this port has been already added since the getPortCapability could have taken a long time
1913 if agent.portExist(childDevice, port) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001914 logger.Debugw("port-already-exist", log.Fields{"port": port})
khenaidoo8f474192019-04-03 17:20:44 -04001915 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001916 }
khenaidoofc1314d2019-03-14 09:34:21 -04001917 // Get stored logical device
khenaidoo6e55d9e2019-12-12 18:26:26 -05001918 ldevice := agent.getLogicalDeviceWithoutLock()
1919
Girish Kumarf56a4682020-03-20 20:07:46 +00001920 logger.Debugw("adding-uni", log.Fields{"deviceId": childDevice.Id})
npujar1d86a522019-11-14 17:11:16 +05301921 portCap.Port.RootPort = false
1922 portCap.Port.Id = port.Label
1923 portCap.Port.OfpPort.PortNo = port.PortNo
1924 portCap.Port.DeviceId = childDevice.Id
1925 portCap.Port.DevicePortNo = port.PortNo
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001926 clonedPorts := clonePorts(ldevice.Ports)
1927 if clonedPorts == nil {
1928 clonedPorts = make([]*voltha.LogicalPort, 0)
npujar1d86a522019-11-14 17:11:16 +05301929 }
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001930 clonedPorts = append(clonedPorts, portCap.Port)
1931 if err := agent.updateLogicalDevicePortsWithoutLock(ctx, ldevice, clonedPorts); err != nil {
npujar1d86a522019-11-14 17:11:16 +05301932 return false, err
1933 }
1934 // Update the device graph with this new logical port
1935 clonedLP := (proto.Clone(portCap.Port)).(*voltha.LogicalPort)
khenaidoo820197c2020-02-13 16:35:33 -05001936
1937 go func() {
1938 if err := agent.updateRoutes(context.Background(), clonedLP); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001939 logger.Warn("routes-not-ready", log.Fields{"logical-device-id": agent.logicalDeviceID, "error": err})
khenaidoo820197c2020-02-13 16:35:33 -05001940 }
1941 }()
1942
npujar1d86a522019-11-14 17:11:16 +05301943 return true, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001944}
1945
Kent Hagerman2b216042020-04-03 18:28:56 -04001946func (agent *LogicalAgent) packetOut(ctx context.Context, packet *ofp.OfpPacketOut) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001947 logger.Debugw("packet-out", log.Fields{
Matteo Scandolo360605d2019-11-05 18:29:17 -08001948 "packet": hex.EncodeToString(packet.Data),
1949 "inPort": packet.GetInPort(),
1950 })
khenaidoo68c930b2019-05-13 11:46:51 -04001951 outPort := fu.GetPacketOutPort(packet)
khenaidoofdbad6e2018-11-06 22:26:38 -05001952 //frame := packet.GetData()
1953 //TODO: Use a channel between the logical agent and the device agent
npujar467fe752020-01-16 20:17:45 +05301954 if err := agent.deviceMgr.packetOut(ctx, agent.rootDeviceID, outPort, packet); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001955 logger.Error("packetout-failed", log.Fields{"logicalDeviceID": agent.rootDeviceID})
khenaidooca301322019-01-09 23:06:32 -05001956 }
khenaidoofdbad6e2018-11-06 22:26:38 -05001957}
1958
Kent Hagerman2b216042020-04-03 18:28:56 -04001959func (agent *LogicalAgent) packetIn(port uint32, transactionID string, packet []byte) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001960 logger.Debugw("packet-in", log.Fields{
Matteo Scandolo360605d2019-11-05 18:29:17 -08001961 "port": port,
1962 "packet": hex.EncodeToString(packet),
npujar1d86a522019-11-14 17:11:16 +05301963 "transactionId": transactionID,
Matteo Scandolo360605d2019-11-05 18:29:17 -08001964 })
khenaidoo68c930b2019-05-13 11:46:51 -04001965 packetIn := fu.MkPacketIn(port, packet)
Kent Hagerman45a13e42020-04-13 12:23:50 -04001966 agent.ldeviceMgr.SendPacketIn(agent.logicalDeviceID, transactionID, packetIn)
Girish Kumarf56a4682020-03-20 20:07:46 +00001967 logger.Debugw("sending-packet-in", log.Fields{"packet": hex.EncodeToString(packetIn.Data)})
khenaidoofdbad6e2018-11-06 22:26:38 -05001968}
khenaidoo2c6a0992019-04-29 13:46:56 -04001969
Kent Hagerman2b216042020-04-03 18:28:56 -04001970func (agent *LogicalAgent) addLogicalPortToMap(portNo uint32, nniPort bool) {
khenaidoo2c6a0992019-04-29 13:46:56 -04001971 agent.lockLogicalPortsNo.Lock()
1972 defer agent.lockLogicalPortsNo.Unlock()
1973 if exist := agent.logicalPortsNo[portNo]; !exist {
1974 agent.logicalPortsNo[portNo] = nniPort
1975 }
1976}
1977
Kent Hagerman2b216042020-04-03 18:28:56 -04001978func (agent *LogicalAgent) deleteLogicalPortsFromMap(portsNo []uint32) {
khenaidoo820197c2020-02-13 16:35:33 -05001979 agent.lockLogicalPortsNo.Lock()
1980 defer agent.lockLogicalPortsNo.Unlock()
1981 for _, pNo := range portsNo {
1982 delete(agent.logicalPortsNo, pNo)
1983 }
1984}
1985
Kent Hagerman2b216042020-04-03 18:28:56 -04001986func (agent *LogicalAgent) addLogicalPortsToMap(lps []*voltha.LogicalPort) {
khenaidoo3d3b8c22019-05-22 18:10:39 -04001987 agent.lockLogicalPortsNo.Lock()
1988 defer agent.lockLogicalPortsNo.Unlock()
1989 for _, lp := range lps {
1990 if exist := agent.logicalPortsNo[lp.DevicePortNo]; !exist {
1991 agent.logicalPortsNo[lp.DevicePortNo] = lp.RootPort
1992 }
1993 }
1994}
1995
Kent Hagerman2b216042020-04-03 18:28:56 -04001996func (agent *LogicalAgent) isNNIPort(portNo uint32) bool {
khenaidoo2c6a0992019-04-29 13:46:56 -04001997 agent.lockLogicalPortsNo.RLock()
1998 defer agent.lockLogicalPortsNo.RUnlock()
1999 if exist := agent.logicalPortsNo[portNo]; exist {
2000 return agent.logicalPortsNo[portNo]
2001 }
2002 return false
2003}
2004
Kent Hagerman2b216042020-04-03 18:28:56 -04002005func (agent *LogicalAgent) getFirstNNIPort() (uint32, error) {
khenaidoo2c6a0992019-04-29 13:46:56 -04002006 agent.lockLogicalPortsNo.RLock()
2007 defer agent.lockLogicalPortsNo.RUnlock()
2008 for portNo, nni := range agent.logicalPortsNo {
2009 if nni {
2010 return portNo, nil
2011 }
2012 }
2013 return 0, status.Error(codes.NotFound, "No NNI port found")
2014}
Esin Karaman09959ae2019-11-29 13:59:58 +00002015
2016//GetNNIPorts returns NNI ports.
Kent Hagerman2b216042020-04-03 18:28:56 -04002017func (agent *LogicalAgent) GetNNIPorts() []uint32 {
Esin Karaman09959ae2019-11-29 13:59:58 +00002018 agent.lockLogicalPortsNo.RLock()
2019 defer agent.lockLogicalPortsNo.RUnlock()
2020 nniPorts := make([]uint32, 0)
2021 for portNo, nni := range agent.logicalPortsNo {
2022 if nni {
2023 nniPorts = append(nniPorts, portNo)
2024 }
2025 }
2026 return nniPorts
2027}