blob: dd40863c4a53b4989826931bd31792fb41dfc02f [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
Hardik Windlassc704def2020-02-26 18:23:19 +0000489// deleteAllUNILogicalPorts deletes all UNI logical ports associated with this parent device
Kent Hagerman2b216042020-04-03 18:28:56 -0400490func (agent *LogicalAgent) deleteAllUNILogicalPorts(ctx context.Context, parentDevice *voltha.Device) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000491 logger.Debugw("delete-all-uni-logical-ports", log.Fields{"logical-device-id": agent.logicalDeviceID})
khenaidoo442e7c72020-03-10 16:13:48 -0400492 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
493 return err
494 }
495 defer agent.requestQueue.RequestComplete()
Hardik Windlassc704def2020-02-26 18:23:19 +0000496 // Get the latest logical device info
497 ld := agent.getLogicalDeviceWithoutLock()
498
Hardik Windlassc704def2020-02-26 18:23:19 +0000499 updateLogicalPorts := []*voltha.LogicalPort{}
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500500 for _, lport := range ld.Ports {
Hardik Windlassc704def2020-02-26 18:23:19 +0000501 // Save NNI ports only
502 if agent.isNNIPort(lport.DevicePortNo) {
503 updateLogicalPorts = append(updateLogicalPorts, lport)
504 }
505 }
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500506 if len(updateLogicalPorts) < len(ld.Ports) {
Hardik Windlassc704def2020-02-26 18:23:19 +0000507 // Updating the logical device will trigger the port change events to be populated to the controller
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500508 if err := agent.updateLogicalDevicePortsWithoutLock(ctx, ld, updateLogicalPorts); err != nil {
Hardik Windlassc704def2020-02-26 18:23:19 +0000509 return err
510 }
511 } else {
Girish Kumarf56a4682020-03-20 20:07:46 +0000512 logger.Debugw("no-change-required", log.Fields{"logical-device-id": agent.logicalDeviceID})
Hardik Windlassc704def2020-02-26 18:23:19 +0000513 }
514 return nil
515}
516
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500517func clonePorts(ports []*voltha.LogicalPort) []*voltha.LogicalPort {
518 return proto.Clone(&voltha.LogicalPorts{Items: ports}).(*voltha.LogicalPorts).Items
519}
520
khenaidoo8b4abbf2020-04-24 17:04:30 -0400521func cloneFlows(flows []*ofp.OfpFlowStats) []*ofp.OfpFlowStats {
522 return proto.Clone(&ofp.Flows{Items: flows}).(*ofp.Flows).Items
523}
524
525func cloneMeters(meters []*ofp.OfpMeterEntry) []*ofp.OfpMeterEntry {
526 return proto.Clone(&ofp.Meters{Items: meters}).(*ofp.Meters).Items
527}
528
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500529//updateLogicalDevicePortsWithoutLock updates the
Kent Hagerman2b216042020-04-03 18:28:56 -0400530func (agent *LogicalAgent) updateLogicalDevicePortsWithoutLock(ctx context.Context, device *voltha.LogicalDevice, newPorts []*voltha.LogicalPort) error {
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500531 oldPorts := device.Ports
532 device.Ports = newPorts
533 if err := agent.updateLogicalDeviceWithoutLock(ctx, device); err != nil {
534 return err
535 }
536 agent.portUpdated(oldPorts, newPorts)
537 return nil
538}
539
khenaidoo92e62c52018-10-03 14:02:54 -0400540//updateLogicalDeviceWithoutLock updates the model with the logical device. It clones the logicaldevice before saving it
Kent Hagerman2b216042020-04-03 18:28:56 -0400541func (agent *LogicalAgent) updateLogicalDeviceWithoutLock(ctx context.Context, logicalDevice *voltha.LogicalDevice) error {
Kent Hagerman4f355f52020-03-30 16:01:33 -0400542 if agent.stopped {
543 return errors.New("logical device agent stopped")
544 }
545
npujar467fe752020-01-16 20:17:45 +0530546 updateCtx := context.WithValue(ctx, model.RequestTimestamp, time.Now().UnixNano())
Kent Hagerman4f355f52020-03-30 16:01:33 -0400547 if err := agent.clusterDataProxy.Update(updateCtx, "logical_devices/"+agent.logicalDeviceID, logicalDevice); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000548 logger.Errorw("failed-to-update-logical-devices-to-cluster-proxy", log.Fields{"error": err})
Thomas Lee Se5a44012019-11-07 20:32:24 +0530549 return err
550 }
Kent Hagerman4f355f52020-03-30 16:01:33 -0400551
khenaidoo442e7c72020-03-10 16:13:48 -0400552 agent.logicalDevice = logicalDevice
553
khenaidoo92e62c52018-10-03 14:02:54 -0400554 return nil
555}
556
khenaidoo820197c2020-02-13 16:35:33 -0500557//generateDeviceRoutesIfNeeded generates the device routes if the logical device has been updated since the last time
khenaidoo4c9e5592019-09-09 16:20:41 -0400558//that device graph was generated.
Kent Hagerman2b216042020-04-03 18:28:56 -0400559func (agent *LogicalAgent) generateDeviceRoutesIfNeeded(ctx context.Context) error {
khenaidoo820197c2020-02-13 16:35:33 -0500560 agent.lockDeviceRoutes.Lock()
561 defer agent.lockDeviceRoutes.Unlock()
562
khenaidoo442e7c72020-03-10 16:13:48 -0400563 ld, err := agent.GetLogicalDevice(ctx)
564 if err != nil {
565 return err
566 }
khenaidoo820197c2020-02-13 16:35:33 -0500567
568 if agent.deviceRoutes != nil && agent.deviceRoutes.IsUpToDate(ld) {
npujar1d86a522019-11-14 17:11:16 +0530569 return nil
570 }
Girish Kumarf56a4682020-03-20 20:07:46 +0000571 logger.Debug("Generation of device route required")
khenaidoo820197c2020-02-13 16:35:33 -0500572 if err := agent.buildRoutes(ctx); err != nil {
khenaidoo787224a2020-04-16 18:08:47 -0400573 // No Route is not an error
574 if !errors.Is(err, route.ErrNoRoute) {
575 return err
576 }
khenaidoo820197c2020-02-13 16:35:33 -0500577 }
khenaidoo4c9e5592019-09-09 16:20:41 -0400578 return nil
579}
580
khenaidoo19d7b632018-10-30 10:49:50 -0400581//updateFlowTable updates the flow table of that logical device
Kent Hagerman2b216042020-04-03 18:28:56 -0400582func (agent *LogicalAgent) updateFlowTable(ctx context.Context, flow *ofp.OfpFlowMod) error {
583 logger.Debug("UpdateFlowTable")
khenaidoo19d7b632018-10-30 10:49:50 -0400584 if flow == nil {
585 return nil
586 }
khenaidoo820197c2020-02-13 16:35:33 -0500587 if err := agent.generateDeviceRoutesIfNeeded(ctx); err != nil {
khenaidoo4c9e5592019-09-09 16:20:41 -0400588 return err
589 }
khenaidoo19d7b632018-10-30 10:49:50 -0400590 switch flow.GetCommand() {
591 case ofp.OfpFlowModCommand_OFPFC_ADD:
npujar467fe752020-01-16 20:17:45 +0530592 return agent.flowAdd(ctx, flow)
khenaidoo19d7b632018-10-30 10:49:50 -0400593 case ofp.OfpFlowModCommand_OFPFC_DELETE:
npujar467fe752020-01-16 20:17:45 +0530594 return agent.flowDelete(ctx, flow)
khenaidoo19d7b632018-10-30 10:49:50 -0400595 case ofp.OfpFlowModCommand_OFPFC_DELETE_STRICT:
npujar467fe752020-01-16 20:17:45 +0530596 return agent.flowDeleteStrict(ctx, flow)
khenaidoo19d7b632018-10-30 10:49:50 -0400597 case ofp.OfpFlowModCommand_OFPFC_MODIFY:
598 return agent.flowModify(flow)
599 case ofp.OfpFlowModCommand_OFPFC_MODIFY_STRICT:
600 return agent.flowModifyStrict(flow)
601 }
602 return status.Errorf(codes.Internal,
npujar1d86a522019-11-14 17:11:16 +0530603 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceID, flow.GetCommand())
khenaidoo19d7b632018-10-30 10:49:50 -0400604}
605
606//updateGroupTable updates the group table of that logical device
Kent Hagerman2b216042020-04-03 18:28:56 -0400607func (agent *LogicalAgent) updateGroupTable(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000608 logger.Debug("updateGroupTable")
khenaidoo19d7b632018-10-30 10:49:50 -0400609 if groupMod == nil {
610 return nil
611 }
khenaidoo820197c2020-02-13 16:35:33 -0500612 if err := agent.generateDeviceRoutesIfNeeded(ctx); err != nil {
khenaidoo4c9e5592019-09-09 16:20:41 -0400613 return err
614 }
khenaidoo820197c2020-02-13 16:35:33 -0500615
khenaidoo19d7b632018-10-30 10:49:50 -0400616 switch groupMod.GetCommand() {
617 case ofp.OfpGroupModCommand_OFPGC_ADD:
npujar467fe752020-01-16 20:17:45 +0530618 return agent.groupAdd(ctx, groupMod)
khenaidoo19d7b632018-10-30 10:49:50 -0400619 case ofp.OfpGroupModCommand_OFPGC_DELETE:
npujar467fe752020-01-16 20:17:45 +0530620 return agent.groupDelete(ctx, groupMod)
khenaidoo19d7b632018-10-30 10:49:50 -0400621 case ofp.OfpGroupModCommand_OFPGC_MODIFY:
npujar467fe752020-01-16 20:17:45 +0530622 return agent.groupModify(ctx, groupMod)
khenaidoo19d7b632018-10-30 10:49:50 -0400623 }
624 return status.Errorf(codes.Internal,
npujar1d86a522019-11-14 17:11:16 +0530625 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceID, groupMod.GetCommand())
khenaidoo19d7b632018-10-30 10:49:50 -0400626}
627
Manikkaraj kb1a10922019-07-29 12:10:34 -0400628// updateMeterTable updates the meter table of that logical device
Kent Hagerman2b216042020-04-03 18:28:56 -0400629func (agent *LogicalAgent) updateMeterTable(ctx context.Context, meterMod *ofp.OfpMeterMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000630 logger.Debug("updateMeterTable")
Manikkaraj kb1a10922019-07-29 12:10:34 -0400631 if meterMod == nil {
632 return nil
633 }
634 switch meterMod.GetCommand() {
635 case ofp.OfpMeterModCommand_OFPMC_ADD:
npujar467fe752020-01-16 20:17:45 +0530636 return agent.meterAdd(ctx, meterMod)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400637 case ofp.OfpMeterModCommand_OFPMC_DELETE:
npujar467fe752020-01-16 20:17:45 +0530638 return agent.meterDelete(ctx, meterMod)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400639 case ofp.OfpMeterModCommand_OFPMC_MODIFY:
npujar467fe752020-01-16 20:17:45 +0530640 return agent.meterModify(ctx, meterMod)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400641 }
642 return status.Errorf(codes.Internal,
npujar1d86a522019-11-14 17:11:16 +0530643 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceID, meterMod.GetCommand())
Manikkaraj kb1a10922019-07-29 12:10:34 -0400644
645}
646
Kent Hagerman2b216042020-04-03 18:28:56 -0400647func (agent *LogicalAgent) meterAdd(ctx context.Context, meterMod *ofp.OfpMeterMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000648 logger.Debugw("meterAdd", log.Fields{"metermod": *meterMod})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400649 if meterMod == nil {
650 return nil
651 }
khenaidoo442e7c72020-03-10 16:13:48 -0400652 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
653 return err
654 }
655 defer agent.requestQueue.RequestComplete()
Girish Kumarf56a4682020-03-20 20:07:46 +0000656 logger.Debug("Acquired logical device lock")
khenaidoo6e55d9e2019-12-12 18:26:26 -0500657 lDevice := agent.getLogicalDeviceWithoutLock()
Manikkaraj kb1a10922019-07-29 12:10:34 -0400658
659 var meters []*ofp.OfpMeterEntry
660 if lDevice.Meters != nil && lDevice.Meters.Items != nil {
661 meters = lDevice.Meters.Items
662 }
Girish Kumarf56a4682020-03-20 20:07:46 +0000663 logger.Debugw("Available meters", log.Fields{"meters": meters})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400664
665 for _, meter := range meters {
666 if meterMod.MeterId == meter.Config.MeterId {
Girish Kumarf56a4682020-03-20 20:07:46 +0000667 logger.Infow("Meter-already-exists", log.Fields{"meter": *meterMod})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400668 return nil
669 }
670 }
671
672 meterEntry := fu.MeterEntryFromMeterMod(meterMod)
673 meters = append(meters, meterEntry)
674 //Update model
npujar467fe752020-01-16 20:17:45 +0530675 if err := agent.updateLogicalDeviceMetersWithoutLock(ctx, &ofp.Meters{Items: meters}); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000676 logger.Errorw("db-meter-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400677 return err
678 }
Girish Kumarf56a4682020-03-20 20:07:46 +0000679 logger.Debugw("Meter-added-successfully", log.Fields{"Added-meter": meterEntry, "updated-meters": lDevice.Meters})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400680 return nil
681}
682
Kent Hagerman2b216042020-04-03 18:28:56 -0400683func (agent *LogicalAgent) meterDelete(ctx context.Context, meterMod *ofp.OfpMeterMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000684 logger.Debug("meterDelete", log.Fields{"meterMod": *meterMod})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400685 if meterMod == nil {
686 return nil
687 }
khenaidoo442e7c72020-03-10 16:13:48 -0400688 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
689 return err
690 }
691 defer agent.requestQueue.RequestComplete()
Manikkaraj kb1a10922019-07-29 12:10:34 -0400692
khenaidoo6e55d9e2019-12-12 18:26:26 -0500693 lDevice := agent.getLogicalDeviceWithoutLock()
Manikkaraj kb1a10922019-07-29 12:10:34 -0400694
695 var meters []*ofp.OfpMeterEntry
696 var flows []*ofp.OfpFlowStats
697 updatedFlows := make([]*ofp.OfpFlowStats, 0)
698 if lDevice.Meters != nil && lDevice.Meters.Items != nil {
699 meters = lDevice.Meters.Items
700 }
Manikkaraj kb1a10922019-07-29 12:10:34 -0400701
702 changedMeter := false
703 changedFow := false
Girish Kumarf56a4682020-03-20 20:07:46 +0000704 logger.Debugw("Available meters", log.Fields{"meters": meters})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400705 for index, meter := range meters {
706 if meterMod.MeterId == meter.Config.MeterId {
707 flows = lDevice.Flows.Items
npujar1d86a522019-11-14 17:11:16 +0530708 changedFow, updatedFlows = agent.getUpdatedFlowsAfterDeletebyMeterID(flows, meterMod.MeterId)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400709 meters = append(meters[:index], meters[index+1:]...)
Girish Kumarf56a4682020-03-20 20:07:46 +0000710 logger.Debugw("Meter has been deleted", log.Fields{"meter": meter, "index": index})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400711 changedMeter = true
712 break
713 }
714 }
715 if changedMeter {
716 //Update model
717 metersToUpdate := &ofp.Meters{}
718 if lDevice.Meters != nil {
719 metersToUpdate = &ofp.Meters{Items: meters}
720 }
npujar467fe752020-01-16 20:17:45 +0530721 if err := agent.updateLogicalDeviceMetersWithoutLock(ctx, metersToUpdate); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000722 logger.Errorw("db-meter-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400723 return err
724 }
Girish Kumarf56a4682020-03-20 20:07:46 +0000725 logger.Debug("Meter-deleted-from-DB-successfully", log.Fields{"updatedMeters": metersToUpdate, "no-of-meter": len(metersToUpdate.Items)})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400726
727 }
728 if changedFow {
729 //Update model
npujar467fe752020-01-16 20:17:45 +0530730 if err := agent.updateLogicalDeviceFlowsWithoutLock(ctx, &ofp.Flows{Items: updatedFlows}); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000731 logger.Errorw("db-flow-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400732 return err
733 }
Girish Kumarf56a4682020-03-20 20:07:46 +0000734 logger.Debug("Flows-associated-with-meter-deleted-from-DB-successfully",
Manikkaraj kb1a10922019-07-29 12:10:34 -0400735 log.Fields{"updated-no-of-flows": len(updatedFlows), "meter": meterMod.MeterId})
736 }
Girish Kumarf56a4682020-03-20 20:07:46 +0000737 logger.Debugw("meterDelete success", log.Fields{"meterID": meterMod.MeterId})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400738 return nil
739}
740
Kent Hagerman2b216042020-04-03 18:28:56 -0400741func (agent *LogicalAgent) meterModify(ctx context.Context, meterMod *ofp.OfpMeterMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000742 logger.Debug("meterModify")
Manikkaraj kb1a10922019-07-29 12:10:34 -0400743 if meterMod == nil {
744 return nil
745 }
khenaidoo442e7c72020-03-10 16:13:48 -0400746 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
747 return err
748 }
749 defer agent.requestQueue.RequestComplete()
Manikkaraj kb1a10922019-07-29 12:10:34 -0400750
khenaidoo6e55d9e2019-12-12 18:26:26 -0500751 lDevice := agent.getLogicalDeviceWithoutLock()
Manikkaraj kb1a10922019-07-29 12:10:34 -0400752
753 var meters []*ofp.OfpMeterEntry
754 if lDevice.Meters != nil && lDevice.Meters.Items != nil {
755 meters = lDevice.Meters.Items
756 }
757 changedMeter := false
758 for index, meter := range meters {
759 if meterMod.MeterId == meter.Config.MeterId {
760 newmeterEntry := fu.MeterEntryFromMeterMod(meterMod)
761 newmeterEntry.Stats.FlowCount = meter.Stats.FlowCount
762 meters[index] = newmeterEntry
763 changedMeter = true
Girish Kumarf56a4682020-03-20 20:07:46 +0000764 logger.Debugw("Found meter, replaced with new meter", log.Fields{"old meter": meter, "new meter": newmeterEntry})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400765 break
766 }
767 }
768 if changedMeter {
769 //Update model
770 metersToUpdate := &ofp.Meters{}
771 if lDevice.Meters != nil {
772 metersToUpdate = &ofp.Meters{Items: meters}
773 }
npujar467fe752020-01-16 20:17:45 +0530774 if err := agent.updateLogicalDeviceMetersWithoutLock(ctx, metersToUpdate); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000775 logger.Errorw("db-meter-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400776 return err
777 }
Girish Kumarf56a4682020-03-20 20:07:46 +0000778 logger.Debugw("meter-updated-in-DB-successfully", log.Fields{"updated_meters": meters})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400779 return nil
780 }
781
Girish Kumarf56a4682020-03-20 20:07:46 +0000782 logger.Errorw("Meter not found ", log.Fields{"meter": meterMod})
npujar1d86a522019-11-14 17:11:16 +0530783 return fmt.Errorf("no-logical-device-present:%d", meterMod.MeterId)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400784
785}
786
Kent Hagerman2b216042020-04-03 18:28:56 -0400787func (agent *LogicalAgent) getUpdatedFlowsAfterDeletebyMeterID(flows []*ofp.OfpFlowStats, meterID uint32) (bool, []*ofp.OfpFlowStats) {
Girish Kumarf56a4682020-03-20 20:07:46 +0000788 logger.Infow("Delete flows matching meter", log.Fields{"meter": meterID})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400789 changed := false
790 //updatedFlows := make([]*ofp.OfpFlowStats, 0)
791 for index := len(flows) - 1; index >= 0; index-- {
npujar1d86a522019-11-14 17:11:16 +0530792 if mID := fu.GetMeterIdFromFlow(flows[index]); mID != 0 && mID == meterID {
Girish Kumarf56a4682020-03-20 20:07:46 +0000793 logger.Debugw("Flow to be deleted", log.Fields{"flow": flows[index], "index": index})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400794 flows = append(flows[:index], flows[index+1:]...)
795 changed = true
796 }
797 }
798 return changed, flows
799}
800
khenaidoo8b4abbf2020-04-24 17:04:30 -0400801func (agent *LogicalAgent) updateFlowCountOfMeterStats(modCommand *ofp.OfpFlowMod, meters []*ofp.OfpMeterEntry, flow *ofp.OfpFlowStats, revertUpdate bool) bool {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400802
803 flowCommand := modCommand.GetCommand()
npujar1d86a522019-11-14 17:11:16 +0530804 meterID := fu.GetMeterIdFromFlow(flow)
Girish Kumarf56a4682020-03-20 20:07:46 +0000805 logger.Debugw("Meter-id-in-flow-mod", log.Fields{"meterId": meterID})
npujar1d86a522019-11-14 17:11:16 +0530806 if meterID == 0 {
Girish Kumarf56a4682020-03-20 20:07:46 +0000807 logger.Debugw("No meter present in the flow", log.Fields{"flow": *flow})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400808 return false
809 }
810 if meters == nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000811 logger.Debug("No meters present in logical device")
Manikkaraj kb1a10922019-07-29 12:10:34 -0400812 return false
813 }
814 changedMeter := false
815 for _, meter := range meters {
npujar1d86a522019-11-14 17:11:16 +0530816 if meterID == meter.Config.MeterId { // Found meter in Logicaldevice
Manikkaraj kb1a10922019-07-29 12:10:34 -0400817 if flowCommand == ofp.OfpFlowModCommand_OFPFC_ADD {
khenaidoo8b4abbf2020-04-24 17:04:30 -0400818 if revertUpdate {
819 meter.Stats.FlowCount--
820 } else {
821 meter.Stats.FlowCount++
822 }
Manikkaraj kb1a10922019-07-29 12:10:34 -0400823 changedMeter = true
824 } else if flowCommand == ofp.OfpFlowModCommand_OFPFC_DELETE_STRICT {
khenaidoo8b4abbf2020-04-24 17:04:30 -0400825 if revertUpdate {
826 meter.Stats.FlowCount++
827 } else {
828 meter.Stats.FlowCount--
829 }
Manikkaraj kb1a10922019-07-29 12:10:34 -0400830 changedMeter = true
831 }
Girish Kumarf56a4682020-03-20 20:07:46 +0000832 logger.Debugw("Found meter, updated meter flow stats", log.Fields{" meterId": meterID})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400833 break
834 }
835 }
836 return changedMeter
837}
838
khenaidoo19d7b632018-10-30 10:49:50 -0400839//flowAdd adds a flow to the flow table of that logical device
Kent Hagerman2b216042020-04-03 18:28:56 -0400840func (agent *LogicalAgent) flowAdd(ctx context.Context, mod *ofp.OfpFlowMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000841 logger.Debugw("flowAdd", log.Fields{"flow": mod})
khenaidoo19d7b632018-10-30 10:49:50 -0400842 if mod == nil {
843 return nil
844 }
khenaidoo442e7c72020-03-10 16:13:48 -0400845 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
846 return err
847 }
848 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -0400849
khenaidoo6e55d9e2019-12-12 18:26:26 -0500850 lDevice := agent.getLogicalDeviceWithoutLock()
khenaidoo19d7b632018-10-30 10:49:50 -0400851
852 var flows []*ofp.OfpFlowStats
Manikkaraj kb1a10922019-07-29 12:10:34 -0400853 var meters []*ofp.OfpMeterEntry
khenaidoo8b4abbf2020-04-24 17:04:30 -0400854 var flowToReplace *ofp.OfpFlowStats
Manikkaraj kb1a10922019-07-29 12:10:34 -0400855 var flow *ofp.OfpFlowStats
Scott Bakerfdea1e32020-02-21 15:35:41 -0800856 var err error
Manikkaraj kb1a10922019-07-29 12:10:34 -0400857
khenaidoo19d7b632018-10-30 10:49:50 -0400858 if lDevice.Flows != nil && lDevice.Flows.Items != nil {
859 flows = lDevice.Flows.Items
860 }
861
Manikkaraj kb1a10922019-07-29 12:10:34 -0400862 if lDevice.Meters != nil && lDevice.Meters.Items != nil {
863 meters = lDevice.Meters.Items
864 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400865 updatedFlows := make([]*ofp.OfpFlowStats, 0)
khenaidoo19d7b632018-10-30 10:49:50 -0400866 changed := false
Manikkaraj kb1a10922019-07-29 12:10:34 -0400867 updated := false
khenaidoo19d7b632018-10-30 10:49:50 -0400868 checkOverlap := (mod.Flags & uint32(ofp.OfpFlowModFlags_OFPFF_CHECK_OVERLAP)) != 0
869 if checkOverlap {
870 if overlapped := fu.FindOverlappingFlows(flows, mod); len(overlapped) != 0 {
871 // TODO: should this error be notified other than being logged?
Girish Kumarf56a4682020-03-20 20:07:46 +0000872 logger.Warnw("overlapped-flows", log.Fields{"logicaldeviceId": agent.logicalDeviceID})
khenaidoo19d7b632018-10-30 10:49:50 -0400873 } else {
Matt Jeanneret518b5a42019-10-29 10:30:46 -0400874 // Add flow
Scott Bakerfdea1e32020-02-21 15:35:41 -0800875 flow, err = fu.FlowStatsEntryFromFlowModMessage(mod)
876 if err != nil {
877 return err
878 }
khenaidoo19d7b632018-10-30 10:49:50 -0400879 flows = append(flows, flow)
khenaidoo2c6a0992019-04-29 13:46:56 -0400880 updatedFlows = append(updatedFlows, flow)
khenaidoo19d7b632018-10-30 10:49:50 -0400881 changed = true
882 }
883 } else {
Scott Bakerfdea1e32020-02-21 15:35:41 -0800884 flow, err = fu.FlowStatsEntryFromFlowModMessage(mod)
885 if err != nil {
886 return err
887 }
khenaidoo19d7b632018-10-30 10:49:50 -0400888 idx := fu.FindFlows(flows, flow)
889 if idx >= 0 {
khenaidoo8b4abbf2020-04-24 17:04:30 -0400890 flowToReplace = flows[idx]
khenaidoo19d7b632018-10-30 10:49:50 -0400891 if (mod.Flags & uint32(ofp.OfpFlowModFlags_OFPFF_RESET_COUNTS)) != 0 {
khenaidoo8b4abbf2020-04-24 17:04:30 -0400892 flow.ByteCount = flowToReplace.ByteCount
893 flow.PacketCount = flowToReplace.PacketCount
khenaidoo19d7b632018-10-30 10:49:50 -0400894 }
khenaidoo8b4abbf2020-04-24 17:04:30 -0400895 if !proto.Equal(flowToReplace, flow) {
Matt Jeanneret518b5a42019-10-29 10:30:46 -0400896 flows[idx] = flow
897 updatedFlows = append(updatedFlows, flow)
898 changed = true
899 updated = true
900 }
901 } else {
khenaidoo19d7b632018-10-30 10:49:50 -0400902 flows = append(flows, flow)
khenaidoo2c6a0992019-04-29 13:46:56 -0400903 updatedFlows = append(updatedFlows, flow)
904 changed = true
khenaidoo19d7b632018-10-30 10:49:50 -0400905 }
khenaidoo19d7b632018-10-30 10:49:50 -0400906 }
Girish Kumarf56a4682020-03-20 20:07:46 +0000907 logger.Debugw("flowAdd-changed", log.Fields{"changed": changed})
khenaidoo4c9e5592019-09-09 16:20:41 -0400908
khenaidoo19d7b632018-10-30 10:49:50 -0400909 if changed {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400910 var flowMetadata voltha.FlowMetadata
911 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 +0000912 logger.Error("Meter-referred-in-flows-not-present")
Manikkaraj kb1a10922019-07-29 12:10:34 -0400913 return err
914 }
khenaidoo820197c2020-02-13 16:35:33 -0500915 deviceRules, err := agent.flowDecomposer.DecomposeRules(ctx, agent, ofp.Flows{Items: updatedFlows}, *lDevice.FlowGroups)
916 if err != nil {
917 return err
918 }
Girish Kumarf56a4682020-03-20 20:07:46 +0000919 logger.Debugw("rules", log.Fields{"rules": deviceRules.String()})
khenaidoo0458db62019-06-20 08:50:36 -0400920
khenaidoo19d7b632018-10-30 10:49:50 -0400921 // Update model
npujar467fe752020-01-16 20:17:45 +0530922 if err := agent.updateLogicalDeviceFlowsWithoutLock(ctx, &ofp.Flows{Items: flows}); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000923 logger.Errorw("db-flow-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo19d7b632018-10-30 10:49:50 -0400924 return err
925 }
khenaidoo8b4abbf2020-04-24 17:04:30 -0400926
Matt Jeanneret518b5a42019-10-29 10:30:46 -0400927 if !updated {
khenaidoo8b4abbf2020-04-24 17:04:30 -0400928 changedMeterStats := agent.updateFlowCountOfMeterStats(mod, meters, flow, false)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400929 metersToUpdate := &ofp.Meters{}
930 if lDevice.Meters != nil {
931 metersToUpdate = &ofp.Meters{Items: meters}
932 }
933 if changedMeterStats {
934 //Update model
npujar467fe752020-01-16 20:17:45 +0530935 if err := agent.updateLogicalDeviceMetersWithoutLock(ctx, metersToUpdate); err != nil {
khenaidoo8b4abbf2020-04-24 17:04:30 -0400936 logger.Errorw("db-meter-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "error": err})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400937 return err
938 }
Girish Kumarf56a4682020-03-20 20:07:46 +0000939 logger.Debugw("meter-stats-updated-in-DB-successfully", log.Fields{"updated_meters": meters})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400940
941 }
942 }
khenaidoo442e7c72020-03-10 16:13:48 -0400943 // Send the flows to the devices
944 respChannels := agent.addFlowsAndGroupsToDevices(ctx, deviceRules, &flowMetadata)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400945
khenaidoo442e7c72020-03-10 16:13:48 -0400946 // Create the go routines to wait
947 go func() {
948 // Wait for completion
949 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChannels...); res != nil {
khenaidoo8b4abbf2020-04-24 17:04:30 -0400950 logger.Infow("failed-to-add-flows-will-attempt-deletion", log.Fields{"errors": res, "logical-device-id": agent.logicalDeviceID})
951 // Revert added flows
952 if err := agent.revertAddedFlows(context.Background(), mod, flow, flowToReplace, deviceRules, &flowMetadata); err != nil {
953 logger.Errorw("failure-to-delete-flows-after-failed-addition", log.Fields{"logical-device-id": agent.logicalDeviceID, "error": err})
954 }
khenaidoo442e7c72020-03-10 16:13:48 -0400955 }
956 }()
khenaidoo19d7b632018-10-30 10:49:50 -0400957 }
khenaidoo19d7b632018-10-30 10:49:50 -0400958 return nil
959}
960
khenaidoo8b4abbf2020-04-24 17:04:30 -0400961// revertAddedFlows reverts flows after the flowAdd request has failed. All flows corresponding to that flowAdd request
962// will be reverted, both from the logical devices and the devices.
963func (agent *LogicalAgent) revertAddedFlows(ctx context.Context, mod *ofp.OfpFlowMod, addedFlow *ofp.OfpFlowStats, replacedFlow *ofp.OfpFlowStats, deviceRules *fu.DeviceRules, metadata *voltha.FlowMetadata) error {
964 logger.Debugw("revertFlowAdd", log.Fields{"added-flow": addedFlow, "replaced-flow": replacedFlow, "device-rules": deviceRules, "metadata": metadata})
965 if err := agent.requestQueue.WaitForGreenLight(context.Background()); err != nil {
966 return err
967 }
968 defer agent.requestQueue.RequestComplete()
969
970 lDevice := agent.getLogicalDeviceWithoutLock()
971
972 // Revert flows
973 clonedFlows := cloneFlows(lDevice.Flows.Items)
974 idx := fu.FindFlows(clonedFlows, addedFlow)
975 if idx < 0 {
976 // Not found - do nothing
977 log.Debugw("flow-not-found", log.Fields{"added-flow": addedFlow})
978 return nil
979 }
980 if replacedFlow != nil {
981 clonedFlows[idx] = replacedFlow
982 } else {
983 clonedFlows = deleteFlowWithoutPreservingOrder(clonedFlows, idx)
984 }
985 lDevice.Flows = &ofp.Flows{Items: clonedFlows}
986
khenaidooa29a4712020-05-05 10:17:17 -0400987 // Revert meters, if necessary
988 if lDevice.Meters != nil && len(lDevice.Meters.Items) > 0 {
989 meters := cloneMeters(lDevice.Meters.Items)
990 changedMeterStats := agent.updateFlowCountOfMeterStats(mod, meters, addedFlow, true)
991 if changedMeterStats {
992 lDevice.Meters = &ofp.Meters{Items: meters}
993 }
khenaidoo8b4abbf2020-04-24 17:04:30 -0400994 }
995
996 // Update the model
997 if err := agent.updateLogicalDeviceWithoutLock(ctx, lDevice); err != nil {
998 logger.Errorw("db-flow-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "error": err})
999 return err
1000 }
1001
1002 // Update the devices
1003 respChnls := agent.deleteFlowsAndGroupsFromDevices(ctx, deviceRules, metadata)
1004
1005 // Wait for the responses
1006 go func() {
1007 // Since this action is taken following an add failure, we may also receive a failure for the revert
1008 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil {
1009 logger.Warnw("failure-reverting-added-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "errors": res})
1010 }
1011 }()
1012
1013 return nil
1014}
1015
npujar1d86a522019-11-14 17:11:16 +05301016// GetMeterConfig returns meter config
Kent Hagerman2b216042020-04-03 18:28:56 -04001017func (agent *LogicalAgent) GetMeterConfig(flows []*ofp.OfpFlowStats, meters []*ofp.OfpMeterEntry, metadata *voltha.FlowMetadata) error {
Manikkaraj kb1a10922019-07-29 12:10:34 -04001018 m := make(map[uint32]bool)
1019 for _, flow := range flows {
npujar1d86a522019-11-14 17:11:16 +05301020 if flowMeterID := fu.GetMeterIdFromFlow(flow); flowMeterID != 0 && !m[flowMeterID] {
Manikkaraj kb1a10922019-07-29 12:10:34 -04001021 foundMeter := false
1022 // Meter is present in the flow , Get from logical device
1023 for _, meter := range meters {
1024 if flowMeterID == meter.Config.MeterId {
1025 metadata.Meters = append(metadata.Meters, meter.Config)
Girish Kumarf56a4682020-03-20 20:07:46 +00001026 logger.Debugw("Found meter in logical device",
Manikkaraj kb1a10922019-07-29 12:10:34 -04001027 log.Fields{"meterID": flowMeterID, "meter-band": meter.Config})
1028 m[flowMeterID] = true
1029 foundMeter = true
1030 break
1031 }
1032 }
1033 if !foundMeter {
Girish Kumarf56a4682020-03-20 20:07:46 +00001034 logger.Errorw("Meter-referred-by-flow-is-not-found-in-logicaldevice",
npujar1d86a522019-11-14 17:11:16 +05301035 log.Fields{"meterID": flowMeterID, "Available-meters": meters, "flow": *flow})
Manikkaraj kb1a10922019-07-29 12:10:34 -04001036 return errors.New("Meter-referred-by-flow-is-not-found-in-logicaldevice")
1037 }
1038 }
1039 }
Girish Kumarf56a4682020-03-20 20:07:46 +00001040 logger.Debugw("meter-bands-for-flows", log.Fields{"flows": len(flows), "metadata": metadata})
Manikkaraj kb1a10922019-07-29 12:10:34 -04001041 return nil
1042
1043}
1044
khenaidoo19d7b632018-10-30 10:49:50 -04001045//flowDelete deletes a flow from the flow table of that logical device
Kent Hagerman2b216042020-04-03 18:28:56 -04001046func (agent *LogicalAgent) flowDelete(ctx context.Context, mod *ofp.OfpFlowMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +00001047 logger.Debug("flowDelete")
khenaidoo19d7b632018-10-30 10:49:50 -04001048 if mod == nil {
1049 return nil
1050 }
khenaidoo442e7c72020-03-10 16:13:48 -04001051 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1052 return err
1053 }
1054 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -04001055
khenaidoo6e55d9e2019-12-12 18:26:26 -05001056 lDevice := agent.getLogicalDeviceWithoutLock()
khenaidoo19d7b632018-10-30 10:49:50 -04001057
Manikkaraj kb1a10922019-07-29 12:10:34 -04001058 var meters []*ofp.OfpMeterEntry
1059 var flows []*ofp.OfpFlowStats
Esin Karamanfc3b1af2020-01-29 16:52:00 +00001060 var flowGroups []*ofp.OfpGroupEntry
Manikkaraj kb1a10922019-07-29 12:10:34 -04001061
1062 if lDevice.Flows != nil && lDevice.Flows.Items != nil {
1063 flows = lDevice.Flows.Items
1064 }
1065
1066 if lDevice.Meters != nil && lDevice.Meters.Items != nil {
1067 meters = lDevice.Meters.Items
1068 }
Esin Karamanfc3b1af2020-01-29 16:52:00 +00001069
1070 if lDevice.FlowGroups != nil && lDevice.FlowGroups.Items != nil {
1071 flowGroups = lDevice.FlowGroups.Items
1072 }
1073
khenaidoo19d7b632018-10-30 10:49:50 -04001074 //build a list of what to keep vs what to delete
1075 toKeep := make([]*ofp.OfpFlowStats, 0)
khenaidoo0458db62019-06-20 08:50:36 -04001076 toDelete := make([]*ofp.OfpFlowStats, 0)
khenaidoo19d7b632018-10-30 10:49:50 -04001077 for _, f := range flows {
khenaidoo0458db62019-06-20 08:50:36 -04001078 // Check whether the flow and the flowmod matches
Scott Bakerfdea1e32020-02-21 15:35:41 -08001079 fs, err := fu.FlowStatsEntryFromFlowModMessage(mod)
1080 if err != nil {
1081 return err
1082 }
1083 if fu.FlowMatch(f, fs) {
khenaidoo0458db62019-06-20 08:50:36 -04001084 toDelete = append(toDelete, f)
1085 continue
1086 }
1087 // Check wild card match
khenaidoo19d7b632018-10-30 10:49:50 -04001088 if !fu.FlowMatchesMod(f, mod) {
1089 toKeep = append(toKeep, f)
khenaidoo0458db62019-06-20 08:50:36 -04001090 } else {
1091 toDelete = append(toDelete, f)
khenaidoo19d7b632018-10-30 10:49:50 -04001092 }
1093 }
1094
Girish Kumarf56a4682020-03-20 20:07:46 +00001095 logger.Debugw("flowDelete", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "toKeep": len(toKeep), "toDelete": toDelete})
khenaidoo0458db62019-06-20 08:50:36 -04001096
khenaidoo19d7b632018-10-30 10:49:50 -04001097 //Update flows
khenaidoo0458db62019-06-20 08:50:36 -04001098 if len(toDelete) > 0 {
Manikkaraj kb1a10922019-07-29 12:10:34 -04001099 var flowMetadata voltha.FlowMetadata
1100 if err := agent.GetMeterConfig(toDelete, meters, &flowMetadata); err != nil { // This should never happen
Girish Kumarf56a4682020-03-20 20:07:46 +00001101 logger.Error("Meter-referred-in-flows-not-present")
Manikkaraj kb1a10922019-07-29 12:10:34 -04001102 return errors.New("Meter-referred-in-flows-not-present")
1103 }
khenaidoo787224a2020-04-16 18:08:47 -04001104
1105 var respChnls []coreutils.Response
1106 var partialRoute bool
khenaidoo820197c2020-02-13 16:35:33 -05001107 deviceRules, err := agent.flowDecomposer.DecomposeRules(ctx, agent, ofp.Flows{Items: toDelete}, ofp.FlowGroups{Items: flowGroups})
1108 if err != nil {
khenaidoo787224a2020-04-16 18:08:47 -04001109 // A no route error means no route exists between the ports specified in the flow. This can happen when the
1110 // child device is deleted and a request to delete flows from the parent device is received
1111 if !errors.Is(err, route.ErrNoRoute) {
1112 logger.Errorw("unexpected-error-received", log.Fields{"flows-to-delete": toDelete, "error": err})
1113 return err
1114 }
1115 partialRoute = true
khenaidoo820197c2020-02-13 16:35:33 -05001116 }
khenaidoo0458db62019-06-20 08:50:36 -04001117
khenaidoo787224a2020-04-16 18:08:47 -04001118 // Update the dB
npujar467fe752020-01-16 20:17:45 +05301119 if err := agent.updateLogicalDeviceFlowsWithoutLock(ctx, &ofp.Flows{Items: toKeep}); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001120 logger.Errorw("cannot-update-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo19d7b632018-10-30 10:49:50 -04001121 return err
1122 }
khenaidoo442e7c72020-03-10 16:13:48 -04001123
1124 // Update the devices
khenaidoo787224a2020-04-16 18:08:47 -04001125 if partialRoute {
1126 respChnls = agent.deleteFlowsFromParentDevice(ctx, ofp.Flows{Items: toDelete}, &flowMetadata)
1127 } else {
1128 respChnls = agent.deleteFlowsAndGroupsFromDevices(ctx, deviceRules, &flowMetadata)
1129 }
khenaidoo442e7c72020-03-10 16:13:48 -04001130
1131 // Wait for the responses
1132 go func() {
1133 // Wait for completion
1134 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001135 logger.Errorw("failure-updating-device-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "errors": res})
khenaidoo442e7c72020-03-10 16:13:48 -04001136 // TODO: Revert the flow deletion
1137 }
1138 }()
khenaidoo19d7b632018-10-30 10:49:50 -04001139 }
1140
1141 //TODO: send announcement on delete
1142 return nil
1143}
1144
Kent Hagerman2b216042020-04-03 18:28:56 -04001145func (agent *LogicalAgent) addFlowsAndGroupsToDevices(ctx context.Context, deviceRules *fu.DeviceRules, flowMetadata *voltha.FlowMetadata) []coreutils.Response {
Girish Kumarf56a4682020-03-20 20:07:46 +00001146 logger.Debugw("send-add-flows-to-device-manager", log.Fields{"logicalDeviceID": agent.logicalDeviceID, "deviceRules": deviceRules, "flowMetadata": flowMetadata})
khenaidoo19d7b632018-10-30 10:49:50 -04001147
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001148 responses := make([]coreutils.Response, 0)
npujar1d86a522019-11-14 17:11:16 +05301149 for deviceID, value := range deviceRules.GetRules() {
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001150 response := coreutils.NewResponse()
1151 responses = append(responses, response)
1152 go func(deviceId string, value *fu.FlowsAndGroups) {
khenaidoo442e7c72020-03-10 16:13:48 -04001153 ctx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
1154 defer cancel()
npujar467fe752020-01-16 20:17:45 +05301155 if err := agent.deviceMgr.addFlowsAndGroups(ctx, deviceId, value.ListFlows(), value.ListGroups(), flowMetadata); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001156 logger.Errorw("flow-add-failed", log.Fields{"deviceID": deviceId, "error": err})
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001157 response.Error(status.Errorf(codes.Internal, "flow-add-failed: %s", deviceId))
khenaidoo0458db62019-06-20 08:50:36 -04001158 }
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001159 response.Done()
npujar1d86a522019-11-14 17:11:16 +05301160 }(deviceID, value)
khenaidoo19d7b632018-10-30 10:49:50 -04001161 }
khenaidoo442e7c72020-03-10 16:13:48 -04001162 // Return responses (an array of channels) for the caller to wait for a response from the far end.
1163 return responses
khenaidoo0458db62019-06-20 08:50:36 -04001164}
khenaidoo19d7b632018-10-30 10:49:50 -04001165
Kent Hagerman2b216042020-04-03 18:28:56 -04001166func (agent *LogicalAgent) deleteFlowsAndGroupsFromDevices(ctx context.Context, deviceRules *fu.DeviceRules, flowMetadata *voltha.FlowMetadata) []coreutils.Response {
Girish Kumarf56a4682020-03-20 20:07:46 +00001167 logger.Debugw("send-delete-flows-to-device-manager", log.Fields{"logicalDeviceID": agent.logicalDeviceID})
khenaidoo0458db62019-06-20 08:50:36 -04001168
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001169 responses := make([]coreutils.Response, 0)
npujar1d86a522019-11-14 17:11:16 +05301170 for deviceID, value := range deviceRules.GetRules() {
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001171 response := coreutils.NewResponse()
1172 responses = append(responses, response)
1173 go func(deviceId string, value *fu.FlowsAndGroups) {
khenaidoo442e7c72020-03-10 16:13:48 -04001174 ctx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
1175 defer cancel()
npujar467fe752020-01-16 20:17:45 +05301176 if err := agent.deviceMgr.deleteFlowsAndGroups(ctx, deviceId, value.ListFlows(), value.ListGroups(), flowMetadata); err != nil {
khenaidoo787224a2020-04-16 18:08:47 -04001177 logger.Errorw("flow-delete-failed", log.Fields{"deviceID": deviceId, "error": err})
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001178 response.Error(status.Errorf(codes.Internal, "flow-delete-failed: %s", deviceId))
khenaidoo0458db62019-06-20 08:50:36 -04001179 }
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001180 response.Done()
npujar1d86a522019-11-14 17:11:16 +05301181 }(deviceID, value)
khenaidoo0458db62019-06-20 08:50:36 -04001182 }
khenaidoo442e7c72020-03-10 16:13:48 -04001183 return responses
khenaidoo0458db62019-06-20 08:50:36 -04001184}
1185
Kent Hagerman2b216042020-04-03 18:28:56 -04001186func (agent *LogicalAgent) updateFlowsAndGroupsOfDevice(ctx context.Context, deviceRules *fu.DeviceRules, flowMetadata *voltha.FlowMetadata) []coreutils.Response {
Girish Kumarf56a4682020-03-20 20:07:46 +00001187 logger.Debugw("send-update-flows-to-device-manager", log.Fields{"logicalDeviceID": agent.logicalDeviceID})
khenaidoo0458db62019-06-20 08:50:36 -04001188
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001189 responses := make([]coreutils.Response, 0)
npujar1d86a522019-11-14 17:11:16 +05301190 for deviceID, value := range deviceRules.GetRules() {
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001191 response := coreutils.NewResponse()
1192 responses = append(responses, response)
1193 go func(deviceId string, value *fu.FlowsAndGroups) {
khenaidoo442e7c72020-03-10 16:13:48 -04001194 ctx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
1195 defer cancel()
npujar467fe752020-01-16 20:17:45 +05301196 if err := agent.deviceMgr.updateFlowsAndGroups(ctx, deviceId, value.ListFlows(), value.ListGroups(), flowMetadata); err != nil {
khenaidoo787224a2020-04-16 18:08:47 -04001197 logger.Errorw("flow-update-failed", log.Fields{"deviceID": deviceId, "error": err})
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001198 response.Error(status.Errorf(codes.Internal, "flow-update-failed: %s", deviceId))
khenaidoo0458db62019-06-20 08:50:36 -04001199 }
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001200 response.Done()
npujar1d86a522019-11-14 17:11:16 +05301201 }(deviceID, value)
khenaidoo0458db62019-06-20 08:50:36 -04001202 }
khenaidoo442e7c72020-03-10 16:13:48 -04001203 return responses
khenaidoo19d7b632018-10-30 10:49:50 -04001204}
1205
khenaidoo787224a2020-04-16 18:08:47 -04001206// getUNILogicalPortNo returns the UNI logical port number specified in the flow
1207func (agent *LogicalAgent) getUNILogicalPortNo(flow *ofp.OfpFlowStats) (uint32, error) {
1208 var uniPort uint32
1209 inPortNo := fu.GetInPort(flow)
1210 outPortNo := fu.GetOutPort(flow)
1211 if agent.isNNIPort(inPortNo) {
1212 uniPort = outPortNo
1213 } else if agent.isNNIPort(outPortNo) {
1214 uniPort = inPortNo
1215 }
1216 if uniPort != 0 {
1217 return uniPort, nil
1218 }
1219 return 0, status.Errorf(codes.NotFound, "no-uni-port: %v", flow)
1220}
1221
1222func (agent *LogicalAgent) deleteFlowsFromParentDevice(ctx context.Context, flows ofp.Flows, metadata *voltha.FlowMetadata) []coreutils.Response {
1223 logger.Debugw("deleting-flows-from-parent-device", log.Fields{"logical-device-id": agent.logicalDeviceID, "flows": flows})
1224 responses := make([]coreutils.Response, 0)
1225 for _, flow := range flows.Items {
1226 response := coreutils.NewResponse()
1227 responses = append(responses, response)
1228 uniPort, err := agent.getUNILogicalPortNo(flow)
1229 if err != nil {
1230 logger.Error("no-uni-port-in-flow", log.Fields{"deviceID": agent.rootDeviceID, "flow": flow, "error": err})
1231 response.Error(err)
1232 response.Done()
1233 continue
1234 }
1235 logger.Debugw("uni-port", log.Fields{"flows": flows, "uni-port": uniPort})
1236 go func(uniPort uint32, metadata *voltha.FlowMetadata) {
1237 ctx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
1238 defer cancel()
1239 if err := agent.deviceMgr.deleteParentFlows(ctx, agent.rootDeviceID, uniPort, metadata); err != nil {
1240 logger.Error("flow-delete-failed", log.Fields{"device-id": agent.rootDeviceID, "error": err})
1241 response.Error(status.Errorf(codes.Internal, "flow-delete-failed: %s %v", agent.rootDeviceID, err))
1242 }
1243 response.Done()
1244 }(uniPort, metadata)
1245 }
1246 return responses
1247}
1248
khenaidoo19d7b632018-10-30 10:49:50 -04001249//flowDeleteStrict deletes a flow from the flow table of that logical device
Kent Hagerman2b216042020-04-03 18:28:56 -04001250func (agent *LogicalAgent) flowDeleteStrict(ctx context.Context, mod *ofp.OfpFlowMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +00001251 logger.Debug("flowDeleteStrict")
khenaidoo19d7b632018-10-30 10:49:50 -04001252 if mod == nil {
1253 return nil
1254 }
khenaidoo442e7c72020-03-10 16:13:48 -04001255 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1256 return err
1257 }
1258 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -04001259
khenaidoo6e55d9e2019-12-12 18:26:26 -05001260 lDevice := agent.getLogicalDeviceWithoutLock()
1261
Manikkaraj kb1a10922019-07-29 12:10:34 -04001262 var meters []*ofp.OfpMeterEntry
1263 var flows []*ofp.OfpFlowStats
Esin Karamanfc3b1af2020-01-29 16:52:00 +00001264 var flowGroups []*ofp.OfpGroupEntry
Manikkaraj kb1a10922019-07-29 12:10:34 -04001265 if lDevice.Meters != nil && lDevice.Meters.Items != nil {
1266 meters = lDevice.Meters.Items
1267 }
1268 if lDevice.Flows != nil && lDevice.Flows.Items != nil {
1269 flows = lDevice.Flows.Items
1270 }
Esin Karamanfc3b1af2020-01-29 16:52:00 +00001271 if lDevice.FlowGroups != nil && lDevice.FlowGroups.Items != nil {
1272 flowGroups = lDevice.FlowGroups.Items
1273 }
Manikkaraj kb1a10922019-07-29 12:10:34 -04001274
1275 changedFlow := false
1276 changedMeter := false
Scott Bakerfdea1e32020-02-21 15:35:41 -08001277 flow, err := fu.FlowStatsEntryFromFlowModMessage(mod)
1278 if err != nil {
1279 return err
1280 }
Manikkaraj kb1a10922019-07-29 12:10:34 -04001281 flowsToDelete := make([]*ofp.OfpFlowStats, 0)
khenaidoo19d7b632018-10-30 10:49:50 -04001282 idx := fu.FindFlows(flows, flow)
1283 if idx >= 0 {
khenaidoo8b4abbf2020-04-24 17:04:30 -04001284 changedMeter = agent.updateFlowCountOfMeterStats(mod, meters, flows[idx], false)
Manikkaraj kb1a10922019-07-29 12:10:34 -04001285 flowsToDelete = append(flowsToDelete, flows[idx])
khenaidoo19d7b632018-10-30 10:49:50 -04001286 flows = append(flows[:idx], flows[idx+1:]...)
Manikkaraj kb1a10922019-07-29 12:10:34 -04001287 changedFlow = true
khenaidoo19d7b632018-10-30 10:49:50 -04001288 } else {
npujar1d86a522019-11-14 17:11:16 +05301289 return fmt.Errorf("Cannot delete flow - %s", flow)
khenaidoo19d7b632018-10-30 10:49:50 -04001290 }
Manikkaraj kb1a10922019-07-29 12:10:34 -04001291 if changedMeter {
1292 //Update model
1293 metersToUpdate := &ofp.Meters{}
1294 if lDevice.Meters != nil {
1295 metersToUpdate = &ofp.Meters{Items: meters}
1296 }
npujar467fe752020-01-16 20:17:45 +05301297 if err := agent.updateLogicalDeviceMetersWithoutLock(ctx, metersToUpdate); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001298 logger.Errorw("db-meter-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
Manikkaraj kb1a10922019-07-29 12:10:34 -04001299 return err
1300 }
khenaidoo19d7b632018-10-30 10:49:50 -04001301
Manikkaraj kb1a10922019-07-29 12:10:34 -04001302 }
1303 if changedFlow {
1304 var flowMetadata voltha.FlowMetadata
1305 if err := agent.GetMeterConfig(flowsToDelete, meters, &flowMetadata); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001306 logger.Error("meter-referred-in-flows-not-present")
Manikkaraj kb1a10922019-07-29 12:10:34 -04001307 return err
1308 }
khenaidoo787224a2020-04-16 18:08:47 -04001309 var respChnls []coreutils.Response
1310 var partialRoute bool
khenaidoo820197c2020-02-13 16:35:33 -05001311 deviceRules, err := agent.flowDecomposer.DecomposeRules(ctx, agent, ofp.Flows{Items: flowsToDelete}, ofp.FlowGroups{Items: flowGroups})
1312 if err != nil {
khenaidoo787224a2020-04-16 18:08:47 -04001313 // A no route error means no route exists between the ports specified in the flow. This can happen when the
1314 // child device is deleted and a request to delete flows from the parent device is received
1315 if !errors.Is(err, route.ErrNoRoute) {
1316 logger.Errorw("unexpected-error-received", log.Fields{"flows-to-delete": flowsToDelete, "error": err})
1317 return err
1318 }
1319 partialRoute = true
khenaidoo820197c2020-02-13 16:35:33 -05001320 }
khenaidoo0458db62019-06-20 08:50:36 -04001321
khenaidoo787224a2020-04-16 18:08:47 -04001322 // Update the dB
npujar467fe752020-01-16 20:17:45 +05301323 if err := agent.updateLogicalDeviceFlowsWithoutLock(ctx, &ofp.Flows{Items: flows}); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001324 logger.Errorw("cannot-update-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo19d7b632018-10-30 10:49:50 -04001325 return err
1326 }
khenaidoo442e7c72020-03-10 16:13:48 -04001327
1328 // Update the devices
khenaidoo787224a2020-04-16 18:08:47 -04001329 if partialRoute {
1330 respChnls = agent.deleteFlowsFromParentDevice(ctx, ofp.Flows{Items: flowsToDelete}, &flowMetadata)
1331 } else {
1332 respChnls = agent.deleteFlowsAndGroupsFromDevices(ctx, deviceRules, &flowMetadata)
1333 }
khenaidoo442e7c72020-03-10 16:13:48 -04001334
1335 // Wait for completion
1336 go func() {
1337 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001338 logger.Warnw("failure-deleting-device-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "errors": res})
khenaidoo442e7c72020-03-10 16:13:48 -04001339 //TODO: Revert flow changes
1340 }
1341 }()
khenaidoo19d7b632018-10-30 10:49:50 -04001342 }
khenaidoo19d7b632018-10-30 10:49:50 -04001343 return nil
1344}
1345
1346//flowModify modifies a flow from the flow table of that logical device
Kent Hagerman2b216042020-04-03 18:28:56 -04001347func (agent *LogicalAgent) flowModify(mod *ofp.OfpFlowMod) error {
khenaidoo19d7b632018-10-30 10:49:50 -04001348 return errors.New("flowModify not implemented")
1349}
1350
1351//flowModifyStrict deletes a flow from the flow table of that logical device
Kent Hagerman2b216042020-04-03 18:28:56 -04001352func (agent *LogicalAgent) flowModifyStrict(mod *ofp.OfpFlowMod) error {
khenaidoo19d7b632018-10-30 10:49:50 -04001353 return errors.New("flowModifyStrict not implemented")
1354}
1355
Kent Hagerman2b216042020-04-03 18:28:56 -04001356func (agent *LogicalAgent) groupAdd(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +00001357 logger.Debug("groupAdd")
khenaidoo19d7b632018-10-30 10:49:50 -04001358 if groupMod == nil {
1359 return nil
1360 }
khenaidoo442e7c72020-03-10 16:13:48 -04001361 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1362 return err
1363 }
1364 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -04001365
khenaidoo6e55d9e2019-12-12 18:26:26 -05001366 lDevice := agent.getLogicalDeviceWithoutLock()
1367
khenaidoo19d7b632018-10-30 10:49:50 -04001368 groups := lDevice.FlowGroups.Items
khenaidoo19d7b632018-10-30 10:49:50 -04001369 if fu.FindGroup(groups, groupMod.GroupId) == -1 {
khenaidoo68c930b2019-05-13 11:46:51 -04001370 groups = append(groups, fu.GroupEntryFromGroupMod(groupMod))
khenaidoo0458db62019-06-20 08:50:36 -04001371
Esin Karaman2ea59212019-12-06 11:41:58 +00001372 deviceRules := fu.NewDeviceRules()
1373 deviceRules.CreateEntryIfNotExist(agent.rootDeviceID)
1374 fg := fu.NewFlowsAndGroups()
1375 fg.AddGroup(fu.GroupEntryFromGroupMod(groupMod))
1376 deviceRules.AddFlowsAndGroup(agent.rootDeviceID, fg)
1377
Girish Kumarf56a4682020-03-20 20:07:46 +00001378 logger.Debugw("rules", log.Fields{"rules for group-add": deviceRules.String()})
khenaidoo0458db62019-06-20 08:50:36 -04001379
npujar467fe752020-01-16 20:17:45 +05301380 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(ctx, &ofp.FlowGroups{Items: groups}); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001381 logger.Errorw("cannot-update-group", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo19d7b632018-10-30 10:49:50 -04001382 return err
1383 }
khenaidoo442e7c72020-03-10 16:13:48 -04001384
1385 // Update the devices
1386 respChnls := agent.addFlowsAndGroupsToDevices(ctx, deviceRules, &voltha.FlowMetadata{})
1387
1388 // Wait for completion
1389 go func() {
1390 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001391 logger.Warnw("failure-updating-device-flows-groups", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "errors": res})
khenaidoo442e7c72020-03-10 16:13:48 -04001392 //TODO: Revert flow changes
1393 }
1394 }()
1395 return nil
khenaidoo19d7b632018-10-30 10:49:50 -04001396 }
khenaidoo442e7c72020-03-10 16:13:48 -04001397 return fmt.Errorf("Groups %d already present", groupMod.GroupId)
khenaidoo19d7b632018-10-30 10:49:50 -04001398}
1399
Kent Hagerman2b216042020-04-03 18:28:56 -04001400func (agent *LogicalAgent) groupDelete(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +00001401 logger.Debug("groupDelete")
khenaidoo19d7b632018-10-30 10:49:50 -04001402 if groupMod == nil {
1403 return nil
1404 }
khenaidoo442e7c72020-03-10 16:13:48 -04001405 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1406 return err
1407 }
1408 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -04001409
khenaidoo6e55d9e2019-12-12 18:26:26 -05001410 lDevice := agent.getLogicalDeviceWithoutLock()
khenaidoo19d7b632018-10-30 10:49:50 -04001411 groups := lDevice.FlowGroups.Items
1412 flows := lDevice.Flows.Items
npujar1d86a522019-11-14 17:11:16 +05301413 var groupsChanged bool
khenaidoo19d7b632018-10-30 10:49:50 -04001414 flowsChanged := false
npujar1d86a522019-11-14 17:11:16 +05301415 groupID := groupMod.GroupId
1416 if groupID == uint32(ofp.OfpGroup_OFPG_ALL) {
khenaidoo19d7b632018-10-30 10:49:50 -04001417 //TODO we must delete all flows that point to this group and
1418 //signal controller as requested by flow's flag
1419 groups = []*ofp.OfpGroupEntry{}
1420 groupsChanged = true
1421 } else {
npujar1d86a522019-11-14 17:11:16 +05301422 idx := fu.FindGroup(groups, groupID)
1423 if idx == -1 {
khenaidoo19d7b632018-10-30 10:49:50 -04001424 return nil // Valid case
khenaidoo19d7b632018-10-30 10:49:50 -04001425 }
npujar1d86a522019-11-14 17:11:16 +05301426 flowsChanged, flows = fu.FlowsDeleteByGroupId(flows, groupID)
1427 groups = append(groups[:idx], groups[idx+1:]...)
1428 groupsChanged = true
khenaidoo19d7b632018-10-30 10:49:50 -04001429 }
khenaidoo0458db62019-06-20 08:50:36 -04001430 if flowsChanged || groupsChanged {
khenaidoo820197c2020-02-13 16:35:33 -05001431 deviceRules, err := agent.flowDecomposer.DecomposeRules(ctx, agent, ofp.Flows{Items: flows}, ofp.FlowGroups{Items: groups})
1432 if err != nil {
1433 return err
1434 }
Girish Kumarf56a4682020-03-20 20:07:46 +00001435 logger.Debugw("rules", log.Fields{"rules": deviceRules.String()})
khenaidoo0458db62019-06-20 08:50:36 -04001436
khenaidoo442e7c72020-03-10 16:13:48 -04001437 if groupsChanged {
1438 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(ctx, &ofp.FlowGroups{Items: groups}); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001439 logger.Errorw("cannot-update-group", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo442e7c72020-03-10 16:13:48 -04001440 return err
1441 }
khenaidoo0458db62019-06-20 08:50:36 -04001442 }
khenaidoo442e7c72020-03-10 16:13:48 -04001443 if flowsChanged {
1444 if err := agent.updateLogicalDeviceFlowsWithoutLock(ctx, &ofp.Flows{Items: flows}); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001445 logger.Errorw("cannot-update-flow", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo442e7c72020-03-10 16:13:48 -04001446 return err
1447 }
1448 }
khenaidoo0458db62019-06-20 08:50:36 -04001449
khenaidoo442e7c72020-03-10 16:13:48 -04001450 // Update the devices
1451 respChnls := agent.updateFlowsAndGroupsOfDevice(ctx, deviceRules, nil)
1452
1453 // Wait for completion
1454 go func() {
1455 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001456 logger.Warnw("failure-updating-device-flows-groups", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "errors": res})
khenaidoo442e7c72020-03-10 16:13:48 -04001457 //TODO: Revert flow changes
1458 }
1459 }()
khenaidoo43c82122018-11-22 18:38:28 -05001460 }
khenaidoo19d7b632018-10-30 10:49:50 -04001461 return nil
1462}
1463
Kent Hagerman2b216042020-04-03 18:28:56 -04001464func (agent *LogicalAgent) groupModify(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +00001465 logger.Debug("groupModify")
khenaidoo19d7b632018-10-30 10:49:50 -04001466 if groupMod == nil {
1467 return nil
1468 }
khenaidoo442e7c72020-03-10 16:13:48 -04001469 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1470 return err
1471 }
1472 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -04001473
khenaidoo6e55d9e2019-12-12 18:26:26 -05001474 lDevice := agent.getLogicalDeviceWithoutLock()
khenaidoo19d7b632018-10-30 10:49:50 -04001475 groups := lDevice.FlowGroups.Items
npujar1d86a522019-11-14 17:11:16 +05301476 var groupsChanged bool
1477 groupID := groupMod.GroupId
1478 idx := fu.FindGroup(groups, groupID)
1479 if idx == -1 {
1480 return fmt.Errorf("group-absent:%d", groupID)
khenaidoo19d7b632018-10-30 10:49:50 -04001481 }
npujar1d86a522019-11-14 17:11:16 +05301482 //replace existing group entry with new group definition
1483 groupEntry := fu.GroupEntryFromGroupMod(groupMod)
1484 groups[idx] = groupEntry
1485 groupsChanged = true
khenaidoo19d7b632018-10-30 10:49:50 -04001486 if groupsChanged {
Esin Karaman2ea59212019-12-06 11:41:58 +00001487 deviceRules := fu.NewDeviceRules()
1488 deviceRules.CreateEntryIfNotExist(agent.rootDeviceID)
1489 fg := fu.NewFlowsAndGroups()
1490 fg.AddGroup(fu.GroupEntryFromGroupMod(groupMod))
1491 deviceRules.AddFlowsAndGroup(agent.rootDeviceID, fg)
khenaidoo0458db62019-06-20 08:50:36 -04001492
Girish Kumarf56a4682020-03-20 20:07:46 +00001493 logger.Debugw("rules", log.Fields{"rules for group-modify": deviceRules.String()})
khenaidoo0458db62019-06-20 08:50:36 -04001494
npujar467fe752020-01-16 20:17:45 +05301495 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(ctx, &ofp.FlowGroups{Items: groups}); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001496 logger.Errorw("Cannot-update-logical-group", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo19d7b632018-10-30 10:49:50 -04001497 return err
1498 }
khenaidoo442e7c72020-03-10 16:13:48 -04001499
1500 // Update the devices
1501 respChnls := agent.updateFlowsAndGroupsOfDevice(ctx, deviceRules, &voltha.FlowMetadata{})
1502
1503 // Wait for completion
1504 go func() {
1505 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001506 logger.Warnw("failure-updating-device-flows-groups", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "errors": res})
khenaidoo442e7c72020-03-10 16:13:48 -04001507 //TODO: Revert flow changes
1508 }
1509 }()
khenaidoo19d7b632018-10-30 10:49:50 -04001510 }
1511 return nil
1512}
1513
1514// deleteLogicalPort removes the logical port
Kent Hagerman2b216042020-04-03 18:28:56 -04001515func (agent *LogicalAgent) deleteLogicalPort(ctx context.Context, lPort *voltha.LogicalPort) error {
khenaidoo442e7c72020-03-10 16:13:48 -04001516 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1517 return err
1518 }
1519 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -04001520
khenaidoo6e55d9e2019-12-12 18:26:26 -05001521 logicalDevice := agent.getLogicalDeviceWithoutLock()
1522
khenaidoo92e62c52018-10-03 14:02:54 -04001523 index := -1
khenaidoo6e55d9e2019-12-12 18:26:26 -05001524 for i, logicalPort := range logicalDevice.Ports {
khenaidoo19d7b632018-10-30 10:49:50 -04001525 if logicalPort.Id == lPort.Id {
khenaidoo92e62c52018-10-03 14:02:54 -04001526 index = i
1527 break
1528 }
1529 }
1530 if index >= 0 {
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001531 clonedPorts := clonePorts(logicalDevice.Ports)
1532 if index < len(clonedPorts)-1 {
1533 copy(clonedPorts[index:], clonedPorts[index+1:])
1534 }
1535 clonedPorts[len(clonedPorts)-1] = nil
1536 clonedPorts = clonedPorts[:len(clonedPorts)-1]
Girish Kumarf56a4682020-03-20 20:07:46 +00001537 logger.Debugw("logical-port-deleted", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001538 if err := agent.updateLogicalDevicePortsWithoutLock(ctx, logicalDevice, clonedPorts); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001539 logger.Errorw("logical-device-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo0a822f92019-05-08 15:15:57 -04001540 return err
1541 }
khenaidoo820197c2020-02-13 16:35:33 -05001542
1543 // Remove the logical port from cache
1544 agent.deleteLogicalPortsFromMap([]uint32{lPort.DevicePortNo})
1545
1546 // Reset the logical device routes
1547 go func() {
1548 if err := agent.buildRoutes(context.Background()); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001549 logger.Warnw("device-routes-not-ready", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "error": err})
khenaidoo820197c2020-02-13 16:35:33 -05001550 }
1551 }()
khenaidoo92e62c52018-10-03 14:02:54 -04001552 }
1553 return nil
khenaidoob9203542018-09-17 22:56:37 -04001554}
1555
khenaidoo0a822f92019-05-08 15:15:57 -04001556// deleteLogicalPorts removes the logical ports associated with that deviceId
Kent Hagerman2b216042020-04-03 18:28:56 -04001557func (agent *LogicalAgent) deleteLogicalPorts(ctx context.Context, deviceID string) error {
Andrea Campanella09400bd2020-04-02 11:58:04 +02001558 logger.Debugw("deleting-logical-ports", log.Fields{"device-id": deviceID})
khenaidoo442e7c72020-03-10 16:13:48 -04001559 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1560 return err
1561 }
1562 defer agent.requestQueue.RequestComplete()
khenaidoo0a822f92019-05-08 15:15:57 -04001563
khenaidoo6e55d9e2019-12-12 18:26:26 -05001564 logicalDevice := agent.getLogicalDeviceWithoutLock()
khenaidoo820197c2020-02-13 16:35:33 -05001565 lPortstoKeep := []*voltha.LogicalPort{}
1566 lPortsNoToDelete := []uint32{}
khenaidoo6e55d9e2019-12-12 18:26:26 -05001567 for _, logicalPort := range logicalDevice.Ports {
npujar1d86a522019-11-14 17:11:16 +05301568 if logicalPort.DeviceId != deviceID {
khenaidoo820197c2020-02-13 16:35:33 -05001569 lPortstoKeep = append(lPortstoKeep, logicalPort)
1570 } else {
1571 lPortsNoToDelete = append(lPortsNoToDelete, logicalPort.DevicePortNo)
khenaidoo0a822f92019-05-08 15:15:57 -04001572 }
1573 }
Andrea Campanella09400bd2020-04-02 11:58:04 +02001574 logger.Debugw("deleted-logical-ports", log.Fields{"ports": lPortstoKeep})
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001575 if err := agent.updateLogicalDevicePortsWithoutLock(ctx, logicalDevice, lPortstoKeep); err != nil {
Andrea Campanella09400bd2020-04-02 11:58:04 +02001576 logger.Errorw("logical-device-update-failed", log.Fields{"logical-device-id": agent.logicalDeviceID})
khenaidoo0a822f92019-05-08 15:15:57 -04001577 return err
1578 }
khenaidoo820197c2020-02-13 16:35:33 -05001579 // Remove the port from the cached logical ports set
1580 agent.deleteLogicalPortsFromMap(lPortsNoToDelete)
1581
1582 // Reset the logical device routes
1583 go func() {
1584 if err := agent.buildRoutes(context.Background()); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001585 logger.Warnw("routes-not-ready", log.Fields{"logical-device-id": agent.logicalDeviceID, "error": err})
khenaidoo820197c2020-02-13 16:35:33 -05001586 }
1587 }()
khenaidoo0a822f92019-05-08 15:15:57 -04001588
1589 return nil
1590}
1591
khenaidoo19d7b632018-10-30 10:49:50 -04001592// enableLogicalPort enables the logical port
Kent Hagerman2b216042020-04-03 18:28:56 -04001593func (agent *LogicalAgent) enableLogicalPort(ctx context.Context, lPortID string) error {
khenaidoo442e7c72020-03-10 16:13:48 -04001594 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1595 return err
1596 }
1597 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -04001598
khenaidoo6e55d9e2019-12-12 18:26:26 -05001599 logicalDevice := agent.getLogicalDeviceWithoutLock()
1600
khenaidoo19d7b632018-10-30 10:49:50 -04001601 index := -1
khenaidoo6e55d9e2019-12-12 18:26:26 -05001602 for i, logicalPort := range logicalDevice.Ports {
npujar1d86a522019-11-14 17:11:16 +05301603 if logicalPort.Id == lPortID {
khenaidoo19d7b632018-10-30 10:49:50 -04001604 index = i
1605 break
1606 }
1607 }
1608 if index >= 0 {
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001609 clonedPorts := clonePorts(logicalDevice.Ports)
1610 clonedPorts[index].OfpPort.Config = clonedPorts[index].OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
1611 return agent.updateLogicalDevicePortsWithoutLock(ctx, logicalDevice, clonedPorts)
khenaidoo19d7b632018-10-30 10:49:50 -04001612 }
npujar1d86a522019-11-14 17:11:16 +05301613 return status.Errorf(codes.NotFound, "Port %s on Logical Device %s", lPortID, agent.logicalDeviceID)
khenaidoo19d7b632018-10-30 10:49:50 -04001614}
1615
1616// disableLogicalPort disabled the logical port
Kent Hagerman2b216042020-04-03 18:28:56 -04001617func (agent *LogicalAgent) disableLogicalPort(ctx context.Context, lPortID string) error {
khenaidoo442e7c72020-03-10 16:13:48 -04001618 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1619 return err
1620 }
1621 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -04001622
1623 // Get the most up to date logical device
khenaidoo6e55d9e2019-12-12 18:26:26 -05001624 logicalDevice := agent.getLogicalDeviceWithoutLock()
khenaidoo19d7b632018-10-30 10:49:50 -04001625 index := -1
khenaidoo6e55d9e2019-12-12 18:26:26 -05001626 for i, logicalPort := range logicalDevice.Ports {
npujar1d86a522019-11-14 17:11:16 +05301627 if logicalPort.Id == lPortID {
khenaidoo19d7b632018-10-30 10:49:50 -04001628 index = i
1629 break
1630 }
1631 }
1632 if index >= 0 {
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001633 clonedPorts := clonePorts(logicalDevice.Ports)
1634 clonedPorts[index].OfpPort.Config = (clonedPorts[index].OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)) | uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
1635 return agent.updateLogicalDevicePortsWithoutLock(ctx, logicalDevice, clonedPorts)
khenaidoo19d7b632018-10-30 10:49:50 -04001636 }
npujar1d86a522019-11-14 17:11:16 +05301637 return status.Errorf(codes.NotFound, "Port %s on Logical Device %s", lPortID, agent.logicalDeviceID)
khenaidoo19d7b632018-10-30 10:49:50 -04001638}
1639
Kent Hagerman2b216042020-04-03 18:28:56 -04001640func (agent *LogicalAgent) getPreCalculatedRoute(ingress, egress uint32) ([]route.Hop, error) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001641 logger.Debugw("ROUTE", log.Fields{"len": len(agent.deviceRoutes.Routes)})
khenaidoo820197c2020-02-13 16:35:33 -05001642 for routeLink, route := range agent.deviceRoutes.Routes {
Girish Kumarf56a4682020-03-20 20:07:46 +00001643 logger.Debugw("ROUTELINKS", log.Fields{"ingress": ingress, "egress": egress, "routelink": routeLink})
khenaidoo89b0e942018-10-21 21:11:33 -04001644 if ingress == routeLink.Ingress && egress == routeLink.Egress {
khenaidoo820197c2020-02-13 16:35:33 -05001645 return route, nil
khenaidoo89b0e942018-10-21 21:11:33 -04001646 }
1647 }
khenaidoo820197c2020-02-13 16:35:33 -05001648 return nil, status.Errorf(codes.FailedPrecondition, "no route from:%d to:%d", ingress, egress)
khenaidoo89b0e942018-10-21 21:11:33 -04001649}
1650
npujar1d86a522019-11-14 17:11:16 +05301651// GetRoute returns route
Kent Hagerman2b216042020-04-03 18:28:56 -04001652func (agent *LogicalAgent) GetRoute(ctx context.Context, ingressPortNo uint32, egressPortNo uint32) ([]route.Hop, error) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001653 logger.Debugw("getting-route", log.Fields{"ingress-port": ingressPortNo, "egress-port": egressPortNo})
khenaidoo820197c2020-02-13 16:35:33 -05001654 routes := make([]route.Hop, 0)
khenaidoo2c6a0992019-04-29 13:46:56 -04001655
khenaidoo19d7b632018-10-30 10:49:50 -04001656 // Note: A port value of 0 is equivalent to a nil port
1657
khenaidoo89b0e942018-10-21 21:11:33 -04001658 // Consider different possibilities
khenaidoo19d7b632018-10-30 10:49:50 -04001659 if egressPortNo != 0 && ((egressPortNo & 0x7fffffff) == uint32(ofp.OfpPortNo_OFPP_CONTROLLER)) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001660 logger.Debugw("controller-flow", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "logicalPortsNo": agent.logicalPortsNo})
khenaidoo2c6a0992019-04-29 13:46:56 -04001661 if agent.isNNIPort(ingressPortNo) {
khenaidoo89b0e942018-10-21 21:11:33 -04001662 //This is a trap on the NNI Port
khenaidoo820197c2020-02-13 16:35:33 -05001663 if len(agent.deviceRoutes.Routes) == 0 {
khenaidoo8f474192019-04-03 17:20:44 -04001664 // 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 -04001665 // route with same IngressHop and EgressHop
khenaidoo820197c2020-02-13 16:35:33 -05001666 hop := route.Hop{DeviceID: agent.rootDeviceID, Ingress: ingressPortNo, Egress: ingressPortNo}
khenaidoo8f474192019-04-03 17:20:44 -04001667 routes = append(routes, hop)
1668 routes = append(routes, hop)
khenaidoo820197c2020-02-13 16:35:33 -05001669 return routes, nil
khenaidoo8f474192019-04-03 17:20:44 -04001670 }
khenaidoo89b0e942018-10-21 21:11:33 -04001671 //Return a 'half' route to make the flow decomposer logic happy
khenaidoo820197c2020-02-13 16:35:33 -05001672 for routeLink, path := range agent.deviceRoutes.Routes {
khenaidoo2c6a0992019-04-29 13:46:56 -04001673 if agent.isNNIPort(routeLink.Egress) {
khenaidoo820197c2020-02-13 16:35:33 -05001674 routes = append(routes, route.Hop{}) // first hop is set to empty
1675 routes = append(routes, path[1])
1676 return routes, nil
khenaidoo89b0e942018-10-21 21:11:33 -04001677 }
1678 }
khenaidoo787224a2020-04-16 18:08:47 -04001679 return nil, fmt.Errorf("no upstream route from:%d to:%d :%w", ingressPortNo, egressPortNo, route.ErrNoRoute)
khenaidoo89b0e942018-10-21 21:11:33 -04001680 }
1681 //treat it as if the output port is the first NNI of the OLT
khenaidoo2c6a0992019-04-29 13:46:56 -04001682 var err error
1683 if egressPortNo, err = agent.getFirstNNIPort(); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001684 logger.Warnw("no-nni-port", log.Fields{"error": err})
khenaidoo820197c2020-02-13 16:35:33 -05001685 return nil, err
khenaidoo2c6a0992019-04-29 13:46:56 -04001686 }
khenaidoo89b0e942018-10-21 21:11:33 -04001687 }
1688 //If ingress port is not specified (nil), it may be a wildcarded
1689 //route if egress port is OFPP_CONTROLLER or a nni logical port,
1690 //in which case we need to create a half-route where only the egress
1691 //hop is filled, the first hop is nil
khenaidoo2c6a0992019-04-29 13:46:56 -04001692 if ingressPortNo == 0 && agent.isNNIPort(egressPortNo) {
khenaidoo89b0e942018-10-21 21:11:33 -04001693 // We can use the 2nd hop of any upstream route, so just find the first upstream:
khenaidoo820197c2020-02-13 16:35:33 -05001694 for routeLink, path := range agent.deviceRoutes.Routes {
khenaidoo2c6a0992019-04-29 13:46:56 -04001695 if agent.isNNIPort(routeLink.Egress) {
khenaidoo820197c2020-02-13 16:35:33 -05001696 routes = append(routes, route.Hop{}) // first hop is set to empty
1697 routes = append(routes, path[1])
1698 return routes, nil
khenaidoo89b0e942018-10-21 21:11:33 -04001699 }
1700 }
khenaidoo787224a2020-04-16 18:08:47 -04001701 return nil, fmt.Errorf("no upstream route from:%d to:%d :%w", ingressPortNo, egressPortNo, route.ErrNoRoute)
khenaidoo89b0e942018-10-21 21:11:33 -04001702 }
1703 //If egress port is not specified (nil), we can also can return a "half" route
khenaidoo19d7b632018-10-30 10:49:50 -04001704 if egressPortNo == 0 {
khenaidoo820197c2020-02-13 16:35:33 -05001705 for routeLink, path := range agent.deviceRoutes.Routes {
khenaidoo19d7b632018-10-30 10:49:50 -04001706 if routeLink.Ingress == ingressPortNo {
khenaidoo820197c2020-02-13 16:35:33 -05001707 routes = append(routes, path[0])
1708 routes = append(routes, route.Hop{})
1709 return routes, nil
khenaidoo89b0e942018-10-21 21:11:33 -04001710 }
1711 }
khenaidoo787224a2020-04-16 18:08:47 -04001712 return nil, fmt.Errorf("no downstream route from:%d to:%d :%w", ingressPortNo, egressPortNo, route.ErrNoRoute)
khenaidoo89b0e942018-10-21 21:11:33 -04001713 }
khenaidoo89b0e942018-10-21 21:11:33 -04001714 // Return the pre-calculated route
khenaidoo19d7b632018-10-30 10:49:50 -04001715 return agent.getPreCalculatedRoute(ingressPortNo, egressPortNo)
khenaidoo89b0e942018-10-21 21:11:33 -04001716}
1717
khenaidoo3d3b8c22019-05-22 18:10:39 -04001718//GetWildcardInputPorts filters out the logical port number from the set of logical ports on the device and
1719//returns their port numbers. This function is invoked only during flow decomposition where the lock on the logical
1720//device is already held. Therefore it is safe to retrieve the logical device without lock.
Kent Hagerman2b216042020-04-03 18:28:56 -04001721func (agent *LogicalAgent) GetWildcardInputPorts(excludePort ...uint32) []uint32 {
khenaidoo89b0e942018-10-21 21:11:33 -04001722 lPorts := make([]uint32, 0)
1723 var exclPort uint32
1724 if len(excludePort) == 1 {
1725 exclPort = excludePort[0]
1726 }
khenaidoo6e55d9e2019-12-12 18:26:26 -05001727 lDevice := agent.getLogicalDeviceWithoutLock()
1728 for _, port := range lDevice.Ports {
1729 if port.OfpPort.PortNo != exclPort {
1730 lPorts = append(lPorts, port.OfpPort.PortNo)
khenaidoo89b0e942018-10-21 21:11:33 -04001731 }
1732 }
1733 return lPorts
1734}
khenaidoo19d7b632018-10-30 10:49:50 -04001735
khenaidoo820197c2020-02-13 16:35:33 -05001736// GetDeviceRoutes returns device graph
Kent Hagerman2b216042020-04-03 18:28:56 -04001737func (agent *LogicalAgent) GetDeviceRoutes() *route.DeviceRoutes {
khenaidoo820197c2020-02-13 16:35:33 -05001738 return agent.deviceRoutes
khenaidoo19d7b632018-10-30 10:49:50 -04001739}
1740
khenaidoo820197c2020-02-13 16:35:33 -05001741//rebuildRoutes rebuilds the device routes
Kent Hagerman2b216042020-04-03 18:28:56 -04001742func (agent *LogicalAgent) buildRoutes(ctx context.Context) error {
Girish Kumarf56a4682020-03-20 20:07:46 +00001743 logger.Debugf("building-routes", log.Fields{"logical-device-id": agent.logicalDeviceID})
khenaidoo442e7c72020-03-10 16:13:48 -04001744 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1745 return err
1746 }
1747 defer agent.requestQueue.RequestComplete()
1748
khenaidoo820197c2020-02-13 16:35:33 -05001749 if agent.deviceRoutes == nil {
Kent Hagerman45a13e42020-04-13 12:23:50 -04001750 agent.deviceRoutes = route.NewDeviceRoutes(agent.logicalDeviceID, agent.deviceMgr.getDevice)
khenaidoo2c6a0992019-04-29 13:46:56 -04001751 }
1752 // Get all the logical ports on that logical device
khenaidoo6e55d9e2019-12-12 18:26:26 -05001753 lDevice := agent.getLogicalDeviceWithoutLock()
1754
khenaidoo820197c2020-02-13 16:35:33 -05001755 if err := agent.deviceRoutes.ComputeRoutes(ctx, lDevice.Ports); err != nil {
1756 return err
1757 }
1758 if err := agent.deviceRoutes.Print(); err != nil {
1759 return err
1760 }
1761
khenaidoo2c6a0992019-04-29 13:46:56 -04001762 return nil
khenaidoo19d7b632018-10-30 10:49:50 -04001763}
1764
khenaidoo820197c2020-02-13 16:35:33 -05001765//updateRoutes updates the device routes
Kent Hagerman2b216042020-04-03 18:28:56 -04001766func (agent *LogicalAgent) updateRoutes(ctx context.Context, lp *voltha.LogicalPort) error {
Girish Kumarf56a4682020-03-20 20:07:46 +00001767 logger.Debugw("updateRoutes", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo442e7c72020-03-10 16:13:48 -04001768 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1769 return err
1770 }
1771 defer agent.requestQueue.RequestComplete()
1772
khenaidoo820197c2020-02-13 16:35:33 -05001773 if agent.deviceRoutes == nil {
Kent Hagerman45a13e42020-04-13 12:23:50 -04001774 agent.deviceRoutes = route.NewDeviceRoutes(agent.logicalDeviceID, agent.deviceMgr.getDevice)
khenaidoo910204f2019-04-08 17:56:40 -04001775 }
khenaidoo820197c2020-02-13 16:35:33 -05001776 if err := agent.deviceRoutes.AddPort(ctx, lp, agent.logicalDevice.Ports); err != nil {
1777 return err
khenaidoo0a822f92019-05-08 15:15:57 -04001778 }
khenaidoo820197c2020-02-13 16:35:33 -05001779 if err := agent.deviceRoutes.Print(); err != nil {
1780 return err
1781 }
1782 return nil
khenaidoo0a822f92019-05-08 15:15:57 -04001783}
1784
khenaidoofc1314d2019-03-14 09:34:21 -04001785// 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 -04001786func diff(oldList, newList []*voltha.LogicalPort) (newPorts, changedPorts, deletedPorts map[string]*voltha.LogicalPort) {
1787 newPorts = make(map[string]*voltha.LogicalPort, len(newList))
1788 changedPorts = make(map[string]*voltha.LogicalPort, len(oldList))
1789 deletedPorts = make(map[string]*voltha.LogicalPort, len(oldList))
1790
khenaidoofc1314d2019-03-14 09:34:21 -04001791 for _, n := range newList {
Kent Hagerman8ad29952020-04-21 11:48:02 -04001792 newPorts[n.Id] = n
1793 }
1794
1795 for _, o := range oldList {
1796 if n, have := newPorts[o.Id]; have {
1797 delete(newPorts, o.Id) // not new
1798 if !proto.Equal(n, o) {
1799 changedPorts[n.Id] = n // changed
khenaidoofc1314d2019-03-14 09:34:21 -04001800 }
Kent Hagerman8ad29952020-04-21 11:48:02 -04001801 } else {
1802 deletedPorts[o.Id] = o // deleted
khenaidoo2bc48282019-07-16 18:13:46 -04001803 }
khenaidoofc1314d2019-03-14 09:34:21 -04001804 }
Kent Hagerman8ad29952020-04-21 11:48:02 -04001805
1806 return newPorts, changedPorts, deletedPorts
khenaidoofc1314d2019-03-14 09:34:21 -04001807}
1808
Kent Hagerman8ad29952020-04-21 11:48:02 -04001809// portUpdated is invoked when a port is updated on the logical device
1810func (agent *LogicalAgent) portUpdated(prevPorts, currPorts []*voltha.LogicalPort) interface{} {
khenaidoofc1314d2019-03-14 09:34:21 -04001811 // Get the difference between the two list
Kent Hagerman8ad29952020-04-21 11:48:02 -04001812 newPorts, changedPorts, deletedPorts := diff(prevPorts, currPorts)
1813
khenaidoofc1314d2019-03-14 09:34:21 -04001814 // Send the port change events to the OF controller
khenaidoo2c6a0992019-04-29 13:46:56 -04001815 for _, newP := range newPorts {
Kent Hagerman45a13e42020-04-13 12:23:50 -04001816 go agent.ldeviceMgr.SendChangeEvent(agent.logicalDeviceID,
khenaidoo2c6a0992019-04-29 13:46:56 -04001817 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_ADD, Desc: newP.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001818 }
1819 for _, change := range changedPorts {
Kent Hagerman45a13e42020-04-13 12:23:50 -04001820 go agent.ldeviceMgr.SendChangeEvent(agent.logicalDeviceID,
khenaidoo910204f2019-04-08 17:56:40 -04001821 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_MODIFY, Desc: change.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001822 }
1823 for _, del := range deletedPorts {
Kent Hagerman45a13e42020-04-13 12:23:50 -04001824 go agent.ldeviceMgr.SendChangeEvent(agent.logicalDeviceID,
khenaidoo910204f2019-04-08 17:56:40 -04001825 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_DELETE, Desc: del.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001826 }
1827
1828 return nil
1829}
1830
khenaidoo8f474192019-04-03 17:20:44 -04001831// addNNILogicalPort adds an NNI port to the logical device. It returns a bool representing whether a port has been
1832// added and an eror in case a valid error is encountered. If the port was successfully added it will return
1833// (true, nil). If the device is not in the correct state it will return (false, nil) as this is a valid
1834// scenario. This also applies to the case where the port was already added.
Kent Hagerman2b216042020-04-03 18:28:56 -04001835func (agent *LogicalAgent) addNNILogicalPort(ctx context.Context, device *voltha.Device, port *voltha.Port) (bool, error) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001836 logger.Debugw("addNNILogicalPort", log.Fields{"NNI": port})
Chaitrashree G S7849b322020-03-29 19:25:49 -04001837
khenaidoo442e7c72020-03-10 16:13:48 -04001838 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1839 return false, err
1840 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001841 if agent.portExist(device, port) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001842 logger.Debugw("port-already-exist", log.Fields{"port": port})
khenaidoo442e7c72020-03-10 16:13:48 -04001843 agent.requestQueue.RequestComplete()
khenaidoo8f474192019-04-03 17:20:44 -04001844 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001845 }
khenaidoo442e7c72020-03-10 16:13:48 -04001846 agent.requestQueue.RequestComplete()
khenaidoo1ce37ad2019-03-24 22:07:24 -04001847
khenaidoofc1314d2019-03-14 09:34:21 -04001848 var portCap *ic.PortCapability
1849 var err error
1850 // First get the port capability
npujar467fe752020-01-16 20:17:45 +05301851 if portCap, err = agent.deviceMgr.getPortCapability(ctx, device.Id, port.PortNo); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001852 logger.Errorw("error-retrieving-port-capabilities", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001853 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001854 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001855
khenaidoo442e7c72020-03-10 16:13:48 -04001856 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1857 return false, err
1858 }
1859
1860 defer agent.requestQueue.RequestComplete()
khenaidoo1ce37ad2019-03-24 22:07:24 -04001861 // Double check again if this port has been already added since the getPortCapability could have taken a long time
1862 if agent.portExist(device, port) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001863 logger.Debugw("port-already-exist", log.Fields{"port": port})
khenaidoo8f474192019-04-03 17:20:44 -04001864 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001865 }
1866
khenaidoofc1314d2019-03-14 09:34:21 -04001867 portCap.Port.RootPort = true
1868 lp := (proto.Clone(portCap.Port)).(*voltha.LogicalPort)
1869 lp.DeviceId = device.Id
1870 lp.Id = fmt.Sprintf("nni-%d", port.PortNo)
1871 lp.OfpPort.PortNo = port.PortNo
1872 lp.OfpPort.Name = lp.Id
1873 lp.DevicePortNo = port.PortNo
1874
khenaidoo6e55d9e2019-12-12 18:26:26 -05001875 ld := agent.getLogicalDeviceWithoutLock()
1876
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001877 clonedPorts := clonePorts(ld.Ports)
1878 if clonedPorts == nil {
1879 clonedPorts = make([]*voltha.LogicalPort, 0)
khenaidoofc1314d2019-03-14 09:34:21 -04001880 }
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001881 clonedPorts = append(clonedPorts, lp)
khenaidoofc1314d2019-03-14 09:34:21 -04001882
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001883 if err = agent.updateLogicalDevicePortsWithoutLock(ctx, ld, clonedPorts); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001884 logger.Errorw("error-updating-logical-device", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001885 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001886 }
khenaidoo910204f2019-04-08 17:56:40 -04001887
khenaidoo820197c2020-02-13 16:35:33 -05001888 // Update the device routes with this new logical port
khenaidoo910204f2019-04-08 17:56:40 -04001889 clonedLP := (proto.Clone(lp)).(*voltha.LogicalPort)
khenaidoo820197c2020-02-13 16:35:33 -05001890 go func() {
1891 if err := agent.updateRoutes(context.Background(), clonedLP); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001892 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 -05001893 }
1894 }()
khenaidoo910204f2019-04-08 17:56:40 -04001895
khenaidoo8f474192019-04-03 17:20:44 -04001896 return true, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001897}
1898
Kent Hagerman2b216042020-04-03 18:28:56 -04001899func (agent *LogicalAgent) portExist(device *voltha.Device, port *voltha.Port) bool {
khenaidoo6e55d9e2019-12-12 18:26:26 -05001900 ldevice := agent.getLogicalDeviceWithoutLock()
1901 for _, lPort := range ldevice.Ports {
1902 if lPort.DeviceId == device.Id && lPort.DevicePortNo == port.PortNo && lPort.Id == port.Label {
1903 return true
khenaidoofc1314d2019-03-14 09:34:21 -04001904 }
1905 }
1906 return false
1907}
1908
khenaidoo8f474192019-04-03 17:20:44 -04001909// addUNILogicalPort adds an UNI port to the logical device. It returns a bool representing whether a port has been
1910// added and an eror in case a valid error is encountered. If the port was successfully added it will return
1911// (true, nil). If the device is not in the correct state it will return (false, nil) as this is a valid
1912// scenario. This also applies to the case where the port was already added.
Kent Hagerman2b216042020-04-03 18:28:56 -04001913func (agent *LogicalAgent) addUNILogicalPort(ctx context.Context, childDevice *voltha.Device, port *voltha.Port) (bool, error) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001914 logger.Debugw("addUNILogicalPort", log.Fields{"port": port})
khenaidoo8f474192019-04-03 17:20:44 -04001915 if childDevice.AdminState != voltha.AdminState_ENABLED || childDevice.OperStatus != voltha.OperStatus_ACTIVE {
Girish Kumarf56a4682020-03-20 20:07:46 +00001916 logger.Infow("device-not-ready", log.Fields{"deviceId": childDevice.Id, "admin": childDevice.AdminState, "oper": childDevice.OperStatus})
khenaidoo8f474192019-04-03 17:20:44 -04001917 return false, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001918 }
khenaidoo442e7c72020-03-10 16:13:48 -04001919 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1920 return false, err
1921 }
1922
khenaidoo1ce37ad2019-03-24 22:07:24 -04001923 if agent.portExist(childDevice, port) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001924 logger.Debugw("port-already-exist", log.Fields{"port": port})
khenaidoo442e7c72020-03-10 16:13:48 -04001925 agent.requestQueue.RequestComplete()
khenaidoo8f474192019-04-03 17:20:44 -04001926 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001927 }
khenaidoo442e7c72020-03-10 16:13:48 -04001928 agent.requestQueue.RequestComplete()
khenaidoofc1314d2019-03-14 09:34:21 -04001929 var portCap *ic.PortCapability
1930 var err error
1931 // First get the port capability
npujar467fe752020-01-16 20:17:45 +05301932 if portCap, err = agent.deviceMgr.getPortCapability(ctx, childDevice.Id, port.PortNo); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001933 logger.Errorw("error-retrieving-port-capabilities", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001934 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001935 }
khenaidoo442e7c72020-03-10 16:13:48 -04001936 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1937 return false, err
1938 }
1939 defer agent.requestQueue.RequestComplete()
khenaidoo1ce37ad2019-03-24 22:07:24 -04001940 // Double check again if this port has been already added since the getPortCapability could have taken a long time
1941 if agent.portExist(childDevice, port) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001942 logger.Debugw("port-already-exist", log.Fields{"port": port})
khenaidoo8f474192019-04-03 17:20:44 -04001943 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001944 }
khenaidoofc1314d2019-03-14 09:34:21 -04001945 // Get stored logical device
khenaidoo6e55d9e2019-12-12 18:26:26 -05001946 ldevice := agent.getLogicalDeviceWithoutLock()
1947
Girish Kumarf56a4682020-03-20 20:07:46 +00001948 logger.Debugw("adding-uni", log.Fields{"deviceId": childDevice.Id})
npujar1d86a522019-11-14 17:11:16 +05301949 portCap.Port.RootPort = false
1950 portCap.Port.Id = port.Label
1951 portCap.Port.OfpPort.PortNo = port.PortNo
1952 portCap.Port.DeviceId = childDevice.Id
1953 portCap.Port.DevicePortNo = port.PortNo
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001954 clonedPorts := clonePorts(ldevice.Ports)
1955 if clonedPorts == nil {
1956 clonedPorts = make([]*voltha.LogicalPort, 0)
npujar1d86a522019-11-14 17:11:16 +05301957 }
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001958 clonedPorts = append(clonedPorts, portCap.Port)
1959 if err := agent.updateLogicalDevicePortsWithoutLock(ctx, ldevice, clonedPorts); err != nil {
npujar1d86a522019-11-14 17:11:16 +05301960 return false, err
1961 }
1962 // Update the device graph with this new logical port
1963 clonedLP := (proto.Clone(portCap.Port)).(*voltha.LogicalPort)
khenaidoo820197c2020-02-13 16:35:33 -05001964
1965 go func() {
1966 if err := agent.updateRoutes(context.Background(), clonedLP); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001967 logger.Warn("routes-not-ready", log.Fields{"logical-device-id": agent.logicalDeviceID, "error": err})
khenaidoo820197c2020-02-13 16:35:33 -05001968 }
1969 }()
1970
npujar1d86a522019-11-14 17:11:16 +05301971 return true, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001972}
1973
Kent Hagerman2b216042020-04-03 18:28:56 -04001974func (agent *LogicalAgent) packetOut(ctx context.Context, packet *ofp.OfpPacketOut) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001975 logger.Debugw("packet-out", log.Fields{
Matteo Scandolo360605d2019-11-05 18:29:17 -08001976 "packet": hex.EncodeToString(packet.Data),
1977 "inPort": packet.GetInPort(),
1978 })
khenaidoo68c930b2019-05-13 11:46:51 -04001979 outPort := fu.GetPacketOutPort(packet)
khenaidoofdbad6e2018-11-06 22:26:38 -05001980 //frame := packet.GetData()
1981 //TODO: Use a channel between the logical agent and the device agent
npujar467fe752020-01-16 20:17:45 +05301982 if err := agent.deviceMgr.packetOut(ctx, agent.rootDeviceID, outPort, packet); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001983 logger.Error("packetout-failed", log.Fields{"logicalDeviceID": agent.rootDeviceID})
khenaidooca301322019-01-09 23:06:32 -05001984 }
khenaidoofdbad6e2018-11-06 22:26:38 -05001985}
1986
Kent Hagerman2b216042020-04-03 18:28:56 -04001987func (agent *LogicalAgent) packetIn(port uint32, transactionID string, packet []byte) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001988 logger.Debugw("packet-in", log.Fields{
Matteo Scandolo360605d2019-11-05 18:29:17 -08001989 "port": port,
1990 "packet": hex.EncodeToString(packet),
npujar1d86a522019-11-14 17:11:16 +05301991 "transactionId": transactionID,
Matteo Scandolo360605d2019-11-05 18:29:17 -08001992 })
khenaidoo68c930b2019-05-13 11:46:51 -04001993 packetIn := fu.MkPacketIn(port, packet)
Kent Hagerman45a13e42020-04-13 12:23:50 -04001994 agent.ldeviceMgr.SendPacketIn(agent.logicalDeviceID, transactionID, packetIn)
Girish Kumarf56a4682020-03-20 20:07:46 +00001995 logger.Debugw("sending-packet-in", log.Fields{"packet": hex.EncodeToString(packetIn.Data)})
khenaidoofdbad6e2018-11-06 22:26:38 -05001996}
khenaidoo2c6a0992019-04-29 13:46:56 -04001997
Kent Hagerman2b216042020-04-03 18:28:56 -04001998func (agent *LogicalAgent) addLogicalPortToMap(portNo uint32, nniPort bool) {
khenaidoo2c6a0992019-04-29 13:46:56 -04001999 agent.lockLogicalPortsNo.Lock()
2000 defer agent.lockLogicalPortsNo.Unlock()
2001 if exist := agent.logicalPortsNo[portNo]; !exist {
2002 agent.logicalPortsNo[portNo] = nniPort
2003 }
2004}
2005
Kent Hagerman2b216042020-04-03 18:28:56 -04002006func (agent *LogicalAgent) deleteLogicalPortsFromMap(portsNo []uint32) {
khenaidoo820197c2020-02-13 16:35:33 -05002007 agent.lockLogicalPortsNo.Lock()
2008 defer agent.lockLogicalPortsNo.Unlock()
2009 for _, pNo := range portsNo {
2010 delete(agent.logicalPortsNo, pNo)
2011 }
2012}
2013
Kent Hagerman2b216042020-04-03 18:28:56 -04002014func (agent *LogicalAgent) addLogicalPortsToMap(lps []*voltha.LogicalPort) {
khenaidoo3d3b8c22019-05-22 18:10:39 -04002015 agent.lockLogicalPortsNo.Lock()
2016 defer agent.lockLogicalPortsNo.Unlock()
2017 for _, lp := range lps {
2018 if exist := agent.logicalPortsNo[lp.DevicePortNo]; !exist {
2019 agent.logicalPortsNo[lp.DevicePortNo] = lp.RootPort
2020 }
2021 }
2022}
2023
Kent Hagerman2b216042020-04-03 18:28:56 -04002024func (agent *LogicalAgent) isNNIPort(portNo uint32) bool {
khenaidoo2c6a0992019-04-29 13:46:56 -04002025 agent.lockLogicalPortsNo.RLock()
2026 defer agent.lockLogicalPortsNo.RUnlock()
2027 if exist := agent.logicalPortsNo[portNo]; exist {
2028 return agent.logicalPortsNo[portNo]
2029 }
2030 return false
2031}
2032
Kent Hagerman2b216042020-04-03 18:28:56 -04002033func (agent *LogicalAgent) getFirstNNIPort() (uint32, error) {
khenaidoo2c6a0992019-04-29 13:46:56 -04002034 agent.lockLogicalPortsNo.RLock()
2035 defer agent.lockLogicalPortsNo.RUnlock()
2036 for portNo, nni := range agent.logicalPortsNo {
2037 if nni {
2038 return portNo, nil
2039 }
2040 }
2041 return 0, status.Error(codes.NotFound, "No NNI port found")
2042}
Esin Karaman09959ae2019-11-29 13:59:58 +00002043
2044//GetNNIPorts returns NNI ports.
Kent Hagerman2b216042020-04-03 18:28:56 -04002045func (agent *LogicalAgent) GetNNIPorts() []uint32 {
Esin Karaman09959ae2019-11-29 13:59:58 +00002046 agent.lockLogicalPortsNo.RLock()
2047 defer agent.lockLogicalPortsNo.RUnlock()
2048 nniPorts := make([]uint32, 0)
2049 for portNo, nni := range agent.logicalPortsNo {
2050 if nni {
2051 nniPorts = append(nniPorts, portNo)
2052 }
2053 }
2054 return nniPorts
2055}