blob: 6a977b1cc89a39ee6a02af506355c91e55ae47af [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
987 // Revert meters
988 meters := cloneMeters(lDevice.Meters.Items)
989 changedMeterStats := agent.updateFlowCountOfMeterStats(mod, meters, addedFlow, true)
990 if changedMeterStats {
991 lDevice.Meters = &ofp.Meters{Items: meters}
992 }
993
994 // Update the model
995 if err := agent.updateLogicalDeviceWithoutLock(ctx, lDevice); err != nil {
996 logger.Errorw("db-flow-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "error": err})
997 return err
998 }
999
1000 // Update the devices
1001 respChnls := agent.deleteFlowsAndGroupsFromDevices(ctx, deviceRules, metadata)
1002
1003 // Wait for the responses
1004 go func() {
1005 // Since this action is taken following an add failure, we may also receive a failure for the revert
1006 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil {
1007 logger.Warnw("failure-reverting-added-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "errors": res})
1008 }
1009 }()
1010
1011 return nil
1012}
1013
npujar1d86a522019-11-14 17:11:16 +05301014// GetMeterConfig returns meter config
Kent Hagerman2b216042020-04-03 18:28:56 -04001015func (agent *LogicalAgent) GetMeterConfig(flows []*ofp.OfpFlowStats, meters []*ofp.OfpMeterEntry, metadata *voltha.FlowMetadata) error {
Manikkaraj kb1a10922019-07-29 12:10:34 -04001016 m := make(map[uint32]bool)
1017 for _, flow := range flows {
npujar1d86a522019-11-14 17:11:16 +05301018 if flowMeterID := fu.GetMeterIdFromFlow(flow); flowMeterID != 0 && !m[flowMeterID] {
Manikkaraj kb1a10922019-07-29 12:10:34 -04001019 foundMeter := false
1020 // Meter is present in the flow , Get from logical device
1021 for _, meter := range meters {
1022 if flowMeterID == meter.Config.MeterId {
1023 metadata.Meters = append(metadata.Meters, meter.Config)
Girish Kumarf56a4682020-03-20 20:07:46 +00001024 logger.Debugw("Found meter in logical device",
Manikkaraj kb1a10922019-07-29 12:10:34 -04001025 log.Fields{"meterID": flowMeterID, "meter-band": meter.Config})
1026 m[flowMeterID] = true
1027 foundMeter = true
1028 break
1029 }
1030 }
1031 if !foundMeter {
Girish Kumarf56a4682020-03-20 20:07:46 +00001032 logger.Errorw("Meter-referred-by-flow-is-not-found-in-logicaldevice",
npujar1d86a522019-11-14 17:11:16 +05301033 log.Fields{"meterID": flowMeterID, "Available-meters": meters, "flow": *flow})
Manikkaraj kb1a10922019-07-29 12:10:34 -04001034 return errors.New("Meter-referred-by-flow-is-not-found-in-logicaldevice")
1035 }
1036 }
1037 }
Girish Kumarf56a4682020-03-20 20:07:46 +00001038 logger.Debugw("meter-bands-for-flows", log.Fields{"flows": len(flows), "metadata": metadata})
Manikkaraj kb1a10922019-07-29 12:10:34 -04001039 return nil
1040
1041}
1042
khenaidoo19d7b632018-10-30 10:49:50 -04001043//flowDelete deletes a flow from the flow table of that logical device
Kent Hagerman2b216042020-04-03 18:28:56 -04001044func (agent *LogicalAgent) flowDelete(ctx context.Context, mod *ofp.OfpFlowMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +00001045 logger.Debug("flowDelete")
khenaidoo19d7b632018-10-30 10:49:50 -04001046 if mod == nil {
1047 return nil
1048 }
khenaidoo442e7c72020-03-10 16:13:48 -04001049 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1050 return err
1051 }
1052 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -04001053
khenaidoo6e55d9e2019-12-12 18:26:26 -05001054 lDevice := agent.getLogicalDeviceWithoutLock()
khenaidoo19d7b632018-10-30 10:49:50 -04001055
Manikkaraj kb1a10922019-07-29 12:10:34 -04001056 var meters []*ofp.OfpMeterEntry
1057 var flows []*ofp.OfpFlowStats
Esin Karamanfc3b1af2020-01-29 16:52:00 +00001058 var flowGroups []*ofp.OfpGroupEntry
Manikkaraj kb1a10922019-07-29 12:10:34 -04001059
1060 if lDevice.Flows != nil && lDevice.Flows.Items != nil {
1061 flows = lDevice.Flows.Items
1062 }
1063
1064 if lDevice.Meters != nil && lDevice.Meters.Items != nil {
1065 meters = lDevice.Meters.Items
1066 }
Esin Karamanfc3b1af2020-01-29 16:52:00 +00001067
1068 if lDevice.FlowGroups != nil && lDevice.FlowGroups.Items != nil {
1069 flowGroups = lDevice.FlowGroups.Items
1070 }
1071
khenaidoo19d7b632018-10-30 10:49:50 -04001072 //build a list of what to keep vs what to delete
1073 toKeep := make([]*ofp.OfpFlowStats, 0)
khenaidoo0458db62019-06-20 08:50:36 -04001074 toDelete := make([]*ofp.OfpFlowStats, 0)
khenaidoo19d7b632018-10-30 10:49:50 -04001075 for _, f := range flows {
khenaidoo0458db62019-06-20 08:50:36 -04001076 // Check whether the flow and the flowmod matches
Scott Bakerfdea1e32020-02-21 15:35:41 -08001077 fs, err := fu.FlowStatsEntryFromFlowModMessage(mod)
1078 if err != nil {
1079 return err
1080 }
1081 if fu.FlowMatch(f, fs) {
khenaidoo0458db62019-06-20 08:50:36 -04001082 toDelete = append(toDelete, f)
1083 continue
1084 }
1085 // Check wild card match
khenaidoo19d7b632018-10-30 10:49:50 -04001086 if !fu.FlowMatchesMod(f, mod) {
1087 toKeep = append(toKeep, f)
khenaidoo0458db62019-06-20 08:50:36 -04001088 } else {
1089 toDelete = append(toDelete, f)
khenaidoo19d7b632018-10-30 10:49:50 -04001090 }
1091 }
1092
Girish Kumarf56a4682020-03-20 20:07:46 +00001093 logger.Debugw("flowDelete", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "toKeep": len(toKeep), "toDelete": toDelete})
khenaidoo0458db62019-06-20 08:50:36 -04001094
khenaidoo19d7b632018-10-30 10:49:50 -04001095 //Update flows
khenaidoo0458db62019-06-20 08:50:36 -04001096 if len(toDelete) > 0 {
Manikkaraj kb1a10922019-07-29 12:10:34 -04001097 var flowMetadata voltha.FlowMetadata
1098 if err := agent.GetMeterConfig(toDelete, meters, &flowMetadata); err != nil { // This should never happen
Girish Kumarf56a4682020-03-20 20:07:46 +00001099 logger.Error("Meter-referred-in-flows-not-present")
Manikkaraj kb1a10922019-07-29 12:10:34 -04001100 return errors.New("Meter-referred-in-flows-not-present")
1101 }
khenaidoo787224a2020-04-16 18:08:47 -04001102
1103 var respChnls []coreutils.Response
1104 var partialRoute bool
khenaidoo820197c2020-02-13 16:35:33 -05001105 deviceRules, err := agent.flowDecomposer.DecomposeRules(ctx, agent, ofp.Flows{Items: toDelete}, ofp.FlowGroups{Items: flowGroups})
1106 if err != nil {
khenaidoo787224a2020-04-16 18:08:47 -04001107 // A no route error means no route exists between the ports specified in the flow. This can happen when the
1108 // child device is deleted and a request to delete flows from the parent device is received
1109 if !errors.Is(err, route.ErrNoRoute) {
1110 logger.Errorw("unexpected-error-received", log.Fields{"flows-to-delete": toDelete, "error": err})
1111 return err
1112 }
1113 partialRoute = true
khenaidoo820197c2020-02-13 16:35:33 -05001114 }
khenaidoo0458db62019-06-20 08:50:36 -04001115
khenaidoo787224a2020-04-16 18:08:47 -04001116 // Update the dB
npujar467fe752020-01-16 20:17:45 +05301117 if err := agent.updateLogicalDeviceFlowsWithoutLock(ctx, &ofp.Flows{Items: toKeep}); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001118 logger.Errorw("cannot-update-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo19d7b632018-10-30 10:49:50 -04001119 return err
1120 }
khenaidoo442e7c72020-03-10 16:13:48 -04001121
1122 // Update the devices
khenaidoo787224a2020-04-16 18:08:47 -04001123 if partialRoute {
1124 respChnls = agent.deleteFlowsFromParentDevice(ctx, ofp.Flows{Items: toDelete}, &flowMetadata)
1125 } else {
1126 respChnls = agent.deleteFlowsAndGroupsFromDevices(ctx, deviceRules, &flowMetadata)
1127 }
khenaidoo442e7c72020-03-10 16:13:48 -04001128
1129 // Wait for the responses
1130 go func() {
1131 // Wait for completion
1132 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001133 logger.Errorw("failure-updating-device-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "errors": res})
khenaidoo442e7c72020-03-10 16:13:48 -04001134 // TODO: Revert the flow deletion
1135 }
1136 }()
khenaidoo19d7b632018-10-30 10:49:50 -04001137 }
1138
1139 //TODO: send announcement on delete
1140 return nil
1141}
1142
Kent Hagerman2b216042020-04-03 18:28:56 -04001143func (agent *LogicalAgent) addFlowsAndGroupsToDevices(ctx context.Context, deviceRules *fu.DeviceRules, flowMetadata *voltha.FlowMetadata) []coreutils.Response {
Girish Kumarf56a4682020-03-20 20:07:46 +00001144 logger.Debugw("send-add-flows-to-device-manager", log.Fields{"logicalDeviceID": agent.logicalDeviceID, "deviceRules": deviceRules, "flowMetadata": flowMetadata})
khenaidoo19d7b632018-10-30 10:49:50 -04001145
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001146 responses := make([]coreutils.Response, 0)
npujar1d86a522019-11-14 17:11:16 +05301147 for deviceID, value := range deviceRules.GetRules() {
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001148 response := coreutils.NewResponse()
1149 responses = append(responses, response)
1150 go func(deviceId string, value *fu.FlowsAndGroups) {
khenaidoo442e7c72020-03-10 16:13:48 -04001151 ctx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
1152 defer cancel()
npujar467fe752020-01-16 20:17:45 +05301153 if err := agent.deviceMgr.addFlowsAndGroups(ctx, deviceId, value.ListFlows(), value.ListGroups(), flowMetadata); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001154 logger.Errorw("flow-add-failed", log.Fields{"deviceID": deviceId, "error": err})
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001155 response.Error(status.Errorf(codes.Internal, "flow-add-failed: %s", deviceId))
khenaidoo0458db62019-06-20 08:50:36 -04001156 }
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001157 response.Done()
npujar1d86a522019-11-14 17:11:16 +05301158 }(deviceID, value)
khenaidoo19d7b632018-10-30 10:49:50 -04001159 }
khenaidoo442e7c72020-03-10 16:13:48 -04001160 // Return responses (an array of channels) for the caller to wait for a response from the far end.
1161 return responses
khenaidoo0458db62019-06-20 08:50:36 -04001162}
khenaidoo19d7b632018-10-30 10:49:50 -04001163
Kent Hagerman2b216042020-04-03 18:28:56 -04001164func (agent *LogicalAgent) deleteFlowsAndGroupsFromDevices(ctx context.Context, deviceRules *fu.DeviceRules, flowMetadata *voltha.FlowMetadata) []coreutils.Response {
Girish Kumarf56a4682020-03-20 20:07:46 +00001165 logger.Debugw("send-delete-flows-to-device-manager", log.Fields{"logicalDeviceID": agent.logicalDeviceID})
khenaidoo0458db62019-06-20 08:50:36 -04001166
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001167 responses := make([]coreutils.Response, 0)
npujar1d86a522019-11-14 17:11:16 +05301168 for deviceID, value := range deviceRules.GetRules() {
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001169 response := coreutils.NewResponse()
1170 responses = append(responses, response)
1171 go func(deviceId string, value *fu.FlowsAndGroups) {
khenaidoo442e7c72020-03-10 16:13:48 -04001172 ctx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
1173 defer cancel()
npujar467fe752020-01-16 20:17:45 +05301174 if err := agent.deviceMgr.deleteFlowsAndGroups(ctx, deviceId, value.ListFlows(), value.ListGroups(), flowMetadata); err != nil {
khenaidoo787224a2020-04-16 18:08:47 -04001175 logger.Errorw("flow-delete-failed", log.Fields{"deviceID": deviceId, "error": err})
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001176 response.Error(status.Errorf(codes.Internal, "flow-delete-failed: %s", deviceId))
khenaidoo0458db62019-06-20 08:50:36 -04001177 }
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001178 response.Done()
npujar1d86a522019-11-14 17:11:16 +05301179 }(deviceID, value)
khenaidoo0458db62019-06-20 08:50:36 -04001180 }
khenaidoo442e7c72020-03-10 16:13:48 -04001181 return responses
khenaidoo0458db62019-06-20 08:50:36 -04001182}
1183
Kent Hagerman2b216042020-04-03 18:28:56 -04001184func (agent *LogicalAgent) updateFlowsAndGroupsOfDevice(ctx context.Context, deviceRules *fu.DeviceRules, flowMetadata *voltha.FlowMetadata) []coreutils.Response {
Girish Kumarf56a4682020-03-20 20:07:46 +00001185 logger.Debugw("send-update-flows-to-device-manager", log.Fields{"logicalDeviceID": agent.logicalDeviceID})
khenaidoo0458db62019-06-20 08:50:36 -04001186
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001187 responses := make([]coreutils.Response, 0)
npujar1d86a522019-11-14 17:11:16 +05301188 for deviceID, value := range deviceRules.GetRules() {
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001189 response := coreutils.NewResponse()
1190 responses = append(responses, response)
1191 go func(deviceId string, value *fu.FlowsAndGroups) {
khenaidoo442e7c72020-03-10 16:13:48 -04001192 ctx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
1193 defer cancel()
npujar467fe752020-01-16 20:17:45 +05301194 if err := agent.deviceMgr.updateFlowsAndGroups(ctx, deviceId, value.ListFlows(), value.ListGroups(), flowMetadata); err != nil {
khenaidoo787224a2020-04-16 18:08:47 -04001195 logger.Errorw("flow-update-failed", log.Fields{"deviceID": deviceId, "error": err})
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001196 response.Error(status.Errorf(codes.Internal, "flow-update-failed: %s", deviceId))
khenaidoo0458db62019-06-20 08:50:36 -04001197 }
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001198 response.Done()
npujar1d86a522019-11-14 17:11:16 +05301199 }(deviceID, value)
khenaidoo0458db62019-06-20 08:50:36 -04001200 }
khenaidoo442e7c72020-03-10 16:13:48 -04001201 return responses
khenaidoo19d7b632018-10-30 10:49:50 -04001202}
1203
khenaidoo787224a2020-04-16 18:08:47 -04001204// getUNILogicalPortNo returns the UNI logical port number specified in the flow
1205func (agent *LogicalAgent) getUNILogicalPortNo(flow *ofp.OfpFlowStats) (uint32, error) {
1206 var uniPort uint32
1207 inPortNo := fu.GetInPort(flow)
1208 outPortNo := fu.GetOutPort(flow)
1209 if agent.isNNIPort(inPortNo) {
1210 uniPort = outPortNo
1211 } else if agent.isNNIPort(outPortNo) {
1212 uniPort = inPortNo
1213 }
1214 if uniPort != 0 {
1215 return uniPort, nil
1216 }
1217 return 0, status.Errorf(codes.NotFound, "no-uni-port: %v", flow)
1218}
1219
1220func (agent *LogicalAgent) deleteFlowsFromParentDevice(ctx context.Context, flows ofp.Flows, metadata *voltha.FlowMetadata) []coreutils.Response {
1221 logger.Debugw("deleting-flows-from-parent-device", log.Fields{"logical-device-id": agent.logicalDeviceID, "flows": flows})
1222 responses := make([]coreutils.Response, 0)
1223 for _, flow := range flows.Items {
1224 response := coreutils.NewResponse()
1225 responses = append(responses, response)
1226 uniPort, err := agent.getUNILogicalPortNo(flow)
1227 if err != nil {
1228 logger.Error("no-uni-port-in-flow", log.Fields{"deviceID": agent.rootDeviceID, "flow": flow, "error": err})
1229 response.Error(err)
1230 response.Done()
1231 continue
1232 }
1233 logger.Debugw("uni-port", log.Fields{"flows": flows, "uni-port": uniPort})
1234 go func(uniPort uint32, metadata *voltha.FlowMetadata) {
1235 ctx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
1236 defer cancel()
1237 if err := agent.deviceMgr.deleteParentFlows(ctx, agent.rootDeviceID, uniPort, metadata); err != nil {
1238 logger.Error("flow-delete-failed", log.Fields{"device-id": agent.rootDeviceID, "error": err})
1239 response.Error(status.Errorf(codes.Internal, "flow-delete-failed: %s %v", agent.rootDeviceID, err))
1240 }
1241 response.Done()
1242 }(uniPort, metadata)
1243 }
1244 return responses
1245}
1246
khenaidoo19d7b632018-10-30 10:49:50 -04001247//flowDeleteStrict deletes a flow from the flow table of that logical device
Kent Hagerman2b216042020-04-03 18:28:56 -04001248func (agent *LogicalAgent) flowDeleteStrict(ctx context.Context, mod *ofp.OfpFlowMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +00001249 logger.Debug("flowDeleteStrict")
khenaidoo19d7b632018-10-30 10:49:50 -04001250 if mod == nil {
1251 return nil
1252 }
khenaidoo442e7c72020-03-10 16:13:48 -04001253 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1254 return err
1255 }
1256 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -04001257
khenaidoo6e55d9e2019-12-12 18:26:26 -05001258 lDevice := agent.getLogicalDeviceWithoutLock()
1259
Manikkaraj kb1a10922019-07-29 12:10:34 -04001260 var meters []*ofp.OfpMeterEntry
1261 var flows []*ofp.OfpFlowStats
Esin Karamanfc3b1af2020-01-29 16:52:00 +00001262 var flowGroups []*ofp.OfpGroupEntry
Manikkaraj kb1a10922019-07-29 12:10:34 -04001263 if lDevice.Meters != nil && lDevice.Meters.Items != nil {
1264 meters = lDevice.Meters.Items
1265 }
1266 if lDevice.Flows != nil && lDevice.Flows.Items != nil {
1267 flows = lDevice.Flows.Items
1268 }
Esin Karamanfc3b1af2020-01-29 16:52:00 +00001269 if lDevice.FlowGroups != nil && lDevice.FlowGroups.Items != nil {
1270 flowGroups = lDevice.FlowGroups.Items
1271 }
Manikkaraj kb1a10922019-07-29 12:10:34 -04001272
1273 changedFlow := false
1274 changedMeter := false
Scott Bakerfdea1e32020-02-21 15:35:41 -08001275 flow, err := fu.FlowStatsEntryFromFlowModMessage(mod)
1276 if err != nil {
1277 return err
1278 }
Manikkaraj kb1a10922019-07-29 12:10:34 -04001279 flowsToDelete := make([]*ofp.OfpFlowStats, 0)
khenaidoo19d7b632018-10-30 10:49:50 -04001280 idx := fu.FindFlows(flows, flow)
1281 if idx >= 0 {
khenaidoo8b4abbf2020-04-24 17:04:30 -04001282 changedMeter = agent.updateFlowCountOfMeterStats(mod, meters, flows[idx], false)
Manikkaraj kb1a10922019-07-29 12:10:34 -04001283 flowsToDelete = append(flowsToDelete, flows[idx])
khenaidoo19d7b632018-10-30 10:49:50 -04001284 flows = append(flows[:idx], flows[idx+1:]...)
Manikkaraj kb1a10922019-07-29 12:10:34 -04001285 changedFlow = true
khenaidoo19d7b632018-10-30 10:49:50 -04001286 } else {
npujar1d86a522019-11-14 17:11:16 +05301287 return fmt.Errorf("Cannot delete flow - %s", flow)
khenaidoo19d7b632018-10-30 10:49:50 -04001288 }
Manikkaraj kb1a10922019-07-29 12:10:34 -04001289 if changedMeter {
1290 //Update model
1291 metersToUpdate := &ofp.Meters{}
1292 if lDevice.Meters != nil {
1293 metersToUpdate = &ofp.Meters{Items: meters}
1294 }
npujar467fe752020-01-16 20:17:45 +05301295 if err := agent.updateLogicalDeviceMetersWithoutLock(ctx, metersToUpdate); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001296 logger.Errorw("db-meter-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
Manikkaraj kb1a10922019-07-29 12:10:34 -04001297 return err
1298 }
khenaidoo19d7b632018-10-30 10:49:50 -04001299
Manikkaraj kb1a10922019-07-29 12:10:34 -04001300 }
1301 if changedFlow {
1302 var flowMetadata voltha.FlowMetadata
1303 if err := agent.GetMeterConfig(flowsToDelete, meters, &flowMetadata); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001304 logger.Error("meter-referred-in-flows-not-present")
Manikkaraj kb1a10922019-07-29 12:10:34 -04001305 return err
1306 }
khenaidoo787224a2020-04-16 18:08:47 -04001307 var respChnls []coreutils.Response
1308 var partialRoute bool
khenaidoo820197c2020-02-13 16:35:33 -05001309 deviceRules, err := agent.flowDecomposer.DecomposeRules(ctx, agent, ofp.Flows{Items: flowsToDelete}, ofp.FlowGroups{Items: flowGroups})
1310 if err != nil {
khenaidoo787224a2020-04-16 18:08:47 -04001311 // A no route error means no route exists between the ports specified in the flow. This can happen when the
1312 // child device is deleted and a request to delete flows from the parent device is received
1313 if !errors.Is(err, route.ErrNoRoute) {
1314 logger.Errorw("unexpected-error-received", log.Fields{"flows-to-delete": flowsToDelete, "error": err})
1315 return err
1316 }
1317 partialRoute = true
khenaidoo820197c2020-02-13 16:35:33 -05001318 }
khenaidoo0458db62019-06-20 08:50:36 -04001319
khenaidoo787224a2020-04-16 18:08:47 -04001320 // Update the dB
npujar467fe752020-01-16 20:17:45 +05301321 if err := agent.updateLogicalDeviceFlowsWithoutLock(ctx, &ofp.Flows{Items: flows}); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001322 logger.Errorw("cannot-update-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo19d7b632018-10-30 10:49:50 -04001323 return err
1324 }
khenaidoo442e7c72020-03-10 16:13:48 -04001325
1326 // Update the devices
khenaidoo787224a2020-04-16 18:08:47 -04001327 if partialRoute {
1328 respChnls = agent.deleteFlowsFromParentDevice(ctx, ofp.Flows{Items: flowsToDelete}, &flowMetadata)
1329 } else {
1330 respChnls = agent.deleteFlowsAndGroupsFromDevices(ctx, deviceRules, &flowMetadata)
1331 }
khenaidoo442e7c72020-03-10 16:13:48 -04001332
1333 // Wait for completion
1334 go func() {
1335 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001336 logger.Warnw("failure-deleting-device-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "errors": res})
khenaidoo442e7c72020-03-10 16:13:48 -04001337 //TODO: Revert flow changes
1338 }
1339 }()
khenaidoo19d7b632018-10-30 10:49:50 -04001340 }
khenaidoo19d7b632018-10-30 10:49:50 -04001341 return nil
1342}
1343
1344//flowModify modifies a flow from the flow table of that logical device
Kent Hagerman2b216042020-04-03 18:28:56 -04001345func (agent *LogicalAgent) flowModify(mod *ofp.OfpFlowMod) error {
khenaidoo19d7b632018-10-30 10:49:50 -04001346 return errors.New("flowModify not implemented")
1347}
1348
1349//flowModifyStrict deletes a flow from the flow table of that logical device
Kent Hagerman2b216042020-04-03 18:28:56 -04001350func (agent *LogicalAgent) flowModifyStrict(mod *ofp.OfpFlowMod) error {
khenaidoo19d7b632018-10-30 10:49:50 -04001351 return errors.New("flowModifyStrict not implemented")
1352}
1353
Kent Hagerman2b216042020-04-03 18:28:56 -04001354func (agent *LogicalAgent) groupAdd(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +00001355 logger.Debug("groupAdd")
khenaidoo19d7b632018-10-30 10:49:50 -04001356 if groupMod == nil {
1357 return nil
1358 }
khenaidoo442e7c72020-03-10 16:13:48 -04001359 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1360 return err
1361 }
1362 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -04001363
khenaidoo6e55d9e2019-12-12 18:26:26 -05001364 lDevice := agent.getLogicalDeviceWithoutLock()
1365
khenaidoo19d7b632018-10-30 10:49:50 -04001366 groups := lDevice.FlowGroups.Items
khenaidoo19d7b632018-10-30 10:49:50 -04001367 if fu.FindGroup(groups, groupMod.GroupId) == -1 {
khenaidoo68c930b2019-05-13 11:46:51 -04001368 groups = append(groups, fu.GroupEntryFromGroupMod(groupMod))
khenaidoo0458db62019-06-20 08:50:36 -04001369
Esin Karaman2ea59212019-12-06 11:41:58 +00001370 deviceRules := fu.NewDeviceRules()
1371 deviceRules.CreateEntryIfNotExist(agent.rootDeviceID)
1372 fg := fu.NewFlowsAndGroups()
1373 fg.AddGroup(fu.GroupEntryFromGroupMod(groupMod))
1374 deviceRules.AddFlowsAndGroup(agent.rootDeviceID, fg)
1375
Girish Kumarf56a4682020-03-20 20:07:46 +00001376 logger.Debugw("rules", log.Fields{"rules for group-add": deviceRules.String()})
khenaidoo0458db62019-06-20 08:50:36 -04001377
npujar467fe752020-01-16 20:17:45 +05301378 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(ctx, &ofp.FlowGroups{Items: groups}); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001379 logger.Errorw("cannot-update-group", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo19d7b632018-10-30 10:49:50 -04001380 return err
1381 }
khenaidoo442e7c72020-03-10 16:13:48 -04001382
1383 // Update the devices
1384 respChnls := agent.addFlowsAndGroupsToDevices(ctx, deviceRules, &voltha.FlowMetadata{})
1385
1386 // Wait for completion
1387 go func() {
1388 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001389 logger.Warnw("failure-updating-device-flows-groups", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "errors": res})
khenaidoo442e7c72020-03-10 16:13:48 -04001390 //TODO: Revert flow changes
1391 }
1392 }()
1393 return nil
khenaidoo19d7b632018-10-30 10:49:50 -04001394 }
khenaidoo442e7c72020-03-10 16:13:48 -04001395 return fmt.Errorf("Groups %d already present", groupMod.GroupId)
khenaidoo19d7b632018-10-30 10:49:50 -04001396}
1397
Kent Hagerman2b216042020-04-03 18:28:56 -04001398func (agent *LogicalAgent) groupDelete(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +00001399 logger.Debug("groupDelete")
khenaidoo19d7b632018-10-30 10:49:50 -04001400 if groupMod == nil {
1401 return nil
1402 }
khenaidoo442e7c72020-03-10 16:13:48 -04001403 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1404 return err
1405 }
1406 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -04001407
khenaidoo6e55d9e2019-12-12 18:26:26 -05001408 lDevice := agent.getLogicalDeviceWithoutLock()
khenaidoo19d7b632018-10-30 10:49:50 -04001409 groups := lDevice.FlowGroups.Items
1410 flows := lDevice.Flows.Items
npujar1d86a522019-11-14 17:11:16 +05301411 var groupsChanged bool
khenaidoo19d7b632018-10-30 10:49:50 -04001412 flowsChanged := false
npujar1d86a522019-11-14 17:11:16 +05301413 groupID := groupMod.GroupId
1414 if groupID == uint32(ofp.OfpGroup_OFPG_ALL) {
khenaidoo19d7b632018-10-30 10:49:50 -04001415 //TODO we must delete all flows that point to this group and
1416 //signal controller as requested by flow's flag
1417 groups = []*ofp.OfpGroupEntry{}
1418 groupsChanged = true
1419 } else {
npujar1d86a522019-11-14 17:11:16 +05301420 idx := fu.FindGroup(groups, groupID)
1421 if idx == -1 {
khenaidoo19d7b632018-10-30 10:49:50 -04001422 return nil // Valid case
khenaidoo19d7b632018-10-30 10:49:50 -04001423 }
npujar1d86a522019-11-14 17:11:16 +05301424 flowsChanged, flows = fu.FlowsDeleteByGroupId(flows, groupID)
1425 groups = append(groups[:idx], groups[idx+1:]...)
1426 groupsChanged = true
khenaidoo19d7b632018-10-30 10:49:50 -04001427 }
khenaidoo0458db62019-06-20 08:50:36 -04001428 if flowsChanged || groupsChanged {
khenaidoo820197c2020-02-13 16:35:33 -05001429 deviceRules, err := agent.flowDecomposer.DecomposeRules(ctx, agent, ofp.Flows{Items: flows}, ofp.FlowGroups{Items: groups})
1430 if err != nil {
1431 return err
1432 }
Girish Kumarf56a4682020-03-20 20:07:46 +00001433 logger.Debugw("rules", log.Fields{"rules": deviceRules.String()})
khenaidoo0458db62019-06-20 08:50:36 -04001434
khenaidoo442e7c72020-03-10 16:13:48 -04001435 if groupsChanged {
1436 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(ctx, &ofp.FlowGroups{Items: groups}); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001437 logger.Errorw("cannot-update-group", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo442e7c72020-03-10 16:13:48 -04001438 return err
1439 }
khenaidoo0458db62019-06-20 08:50:36 -04001440 }
khenaidoo442e7c72020-03-10 16:13:48 -04001441 if flowsChanged {
1442 if err := agent.updateLogicalDeviceFlowsWithoutLock(ctx, &ofp.Flows{Items: flows}); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001443 logger.Errorw("cannot-update-flow", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo442e7c72020-03-10 16:13:48 -04001444 return err
1445 }
1446 }
khenaidoo0458db62019-06-20 08:50:36 -04001447
khenaidoo442e7c72020-03-10 16:13:48 -04001448 // Update the devices
1449 respChnls := agent.updateFlowsAndGroupsOfDevice(ctx, deviceRules, nil)
1450
1451 // Wait for completion
1452 go func() {
1453 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001454 logger.Warnw("failure-updating-device-flows-groups", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "errors": res})
khenaidoo442e7c72020-03-10 16:13:48 -04001455 //TODO: Revert flow changes
1456 }
1457 }()
khenaidoo43c82122018-11-22 18:38:28 -05001458 }
khenaidoo19d7b632018-10-30 10:49:50 -04001459 return nil
1460}
1461
Kent Hagerman2b216042020-04-03 18:28:56 -04001462func (agent *LogicalAgent) groupModify(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +00001463 logger.Debug("groupModify")
khenaidoo19d7b632018-10-30 10:49:50 -04001464 if groupMod == nil {
1465 return nil
1466 }
khenaidoo442e7c72020-03-10 16:13:48 -04001467 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1468 return err
1469 }
1470 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -04001471
khenaidoo6e55d9e2019-12-12 18:26:26 -05001472 lDevice := agent.getLogicalDeviceWithoutLock()
khenaidoo19d7b632018-10-30 10:49:50 -04001473 groups := lDevice.FlowGroups.Items
npujar1d86a522019-11-14 17:11:16 +05301474 var groupsChanged bool
1475 groupID := groupMod.GroupId
1476 idx := fu.FindGroup(groups, groupID)
1477 if idx == -1 {
1478 return fmt.Errorf("group-absent:%d", groupID)
khenaidoo19d7b632018-10-30 10:49:50 -04001479 }
npujar1d86a522019-11-14 17:11:16 +05301480 //replace existing group entry with new group definition
1481 groupEntry := fu.GroupEntryFromGroupMod(groupMod)
1482 groups[idx] = groupEntry
1483 groupsChanged = true
khenaidoo19d7b632018-10-30 10:49:50 -04001484 if groupsChanged {
Esin Karaman2ea59212019-12-06 11:41:58 +00001485 deviceRules := fu.NewDeviceRules()
1486 deviceRules.CreateEntryIfNotExist(agent.rootDeviceID)
1487 fg := fu.NewFlowsAndGroups()
1488 fg.AddGroup(fu.GroupEntryFromGroupMod(groupMod))
1489 deviceRules.AddFlowsAndGroup(agent.rootDeviceID, fg)
khenaidoo0458db62019-06-20 08:50:36 -04001490
Girish Kumarf56a4682020-03-20 20:07:46 +00001491 logger.Debugw("rules", log.Fields{"rules for group-modify": deviceRules.String()})
khenaidoo0458db62019-06-20 08:50:36 -04001492
npujar467fe752020-01-16 20:17:45 +05301493 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(ctx, &ofp.FlowGroups{Items: groups}); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001494 logger.Errorw("Cannot-update-logical-group", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo19d7b632018-10-30 10:49:50 -04001495 return err
1496 }
khenaidoo442e7c72020-03-10 16:13:48 -04001497
1498 // Update the devices
1499 respChnls := agent.updateFlowsAndGroupsOfDevice(ctx, deviceRules, &voltha.FlowMetadata{})
1500
1501 // Wait for completion
1502 go func() {
1503 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001504 logger.Warnw("failure-updating-device-flows-groups", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "errors": res})
khenaidoo442e7c72020-03-10 16:13:48 -04001505 //TODO: Revert flow changes
1506 }
1507 }()
khenaidoo19d7b632018-10-30 10:49:50 -04001508 }
1509 return nil
1510}
1511
1512// deleteLogicalPort removes the logical port
Kent Hagerman2b216042020-04-03 18:28:56 -04001513func (agent *LogicalAgent) deleteLogicalPort(ctx context.Context, lPort *voltha.LogicalPort) error {
khenaidoo442e7c72020-03-10 16:13:48 -04001514 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1515 return err
1516 }
1517 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -04001518
khenaidoo6e55d9e2019-12-12 18:26:26 -05001519 logicalDevice := agent.getLogicalDeviceWithoutLock()
1520
khenaidoo92e62c52018-10-03 14:02:54 -04001521 index := -1
khenaidoo6e55d9e2019-12-12 18:26:26 -05001522 for i, logicalPort := range logicalDevice.Ports {
khenaidoo19d7b632018-10-30 10:49:50 -04001523 if logicalPort.Id == lPort.Id {
khenaidoo92e62c52018-10-03 14:02:54 -04001524 index = i
1525 break
1526 }
1527 }
1528 if index >= 0 {
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001529 clonedPorts := clonePorts(logicalDevice.Ports)
1530 if index < len(clonedPorts)-1 {
1531 copy(clonedPorts[index:], clonedPorts[index+1:])
1532 }
1533 clonedPorts[len(clonedPorts)-1] = nil
1534 clonedPorts = clonedPorts[:len(clonedPorts)-1]
Girish Kumarf56a4682020-03-20 20:07:46 +00001535 logger.Debugw("logical-port-deleted", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001536 if err := agent.updateLogicalDevicePortsWithoutLock(ctx, logicalDevice, clonedPorts); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001537 logger.Errorw("logical-device-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo0a822f92019-05-08 15:15:57 -04001538 return err
1539 }
khenaidoo820197c2020-02-13 16:35:33 -05001540
1541 // Remove the logical port from cache
1542 agent.deleteLogicalPortsFromMap([]uint32{lPort.DevicePortNo})
1543
1544 // Reset the logical device routes
1545 go func() {
1546 if err := agent.buildRoutes(context.Background()); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001547 logger.Warnw("device-routes-not-ready", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "error": err})
khenaidoo820197c2020-02-13 16:35:33 -05001548 }
1549 }()
khenaidoo92e62c52018-10-03 14:02:54 -04001550 }
1551 return nil
khenaidoob9203542018-09-17 22:56:37 -04001552}
1553
khenaidoo0a822f92019-05-08 15:15:57 -04001554// deleteLogicalPorts removes the logical ports associated with that deviceId
Kent Hagerman2b216042020-04-03 18:28:56 -04001555func (agent *LogicalAgent) deleteLogicalPorts(ctx context.Context, deviceID string) error {
Andrea Campanella09400bd2020-04-02 11:58:04 +02001556 logger.Debugw("deleting-logical-ports", log.Fields{"device-id": deviceID})
khenaidoo442e7c72020-03-10 16:13:48 -04001557 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1558 return err
1559 }
1560 defer agent.requestQueue.RequestComplete()
khenaidoo0a822f92019-05-08 15:15:57 -04001561
khenaidoo6e55d9e2019-12-12 18:26:26 -05001562 logicalDevice := agent.getLogicalDeviceWithoutLock()
khenaidoo820197c2020-02-13 16:35:33 -05001563 lPortstoKeep := []*voltha.LogicalPort{}
1564 lPortsNoToDelete := []uint32{}
khenaidoo6e55d9e2019-12-12 18:26:26 -05001565 for _, logicalPort := range logicalDevice.Ports {
npujar1d86a522019-11-14 17:11:16 +05301566 if logicalPort.DeviceId != deviceID {
khenaidoo820197c2020-02-13 16:35:33 -05001567 lPortstoKeep = append(lPortstoKeep, logicalPort)
1568 } else {
1569 lPortsNoToDelete = append(lPortsNoToDelete, logicalPort.DevicePortNo)
khenaidoo0a822f92019-05-08 15:15:57 -04001570 }
1571 }
Andrea Campanella09400bd2020-04-02 11:58:04 +02001572 logger.Debugw("deleted-logical-ports", log.Fields{"ports": lPortstoKeep})
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001573 if err := agent.updateLogicalDevicePortsWithoutLock(ctx, logicalDevice, lPortstoKeep); err != nil {
Andrea Campanella09400bd2020-04-02 11:58:04 +02001574 logger.Errorw("logical-device-update-failed", log.Fields{"logical-device-id": agent.logicalDeviceID})
khenaidoo0a822f92019-05-08 15:15:57 -04001575 return err
1576 }
khenaidoo820197c2020-02-13 16:35:33 -05001577 // Remove the port from the cached logical ports set
1578 agent.deleteLogicalPortsFromMap(lPortsNoToDelete)
1579
1580 // Reset the logical device routes
1581 go func() {
1582 if err := agent.buildRoutes(context.Background()); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001583 logger.Warnw("routes-not-ready", log.Fields{"logical-device-id": agent.logicalDeviceID, "error": err})
khenaidoo820197c2020-02-13 16:35:33 -05001584 }
1585 }()
khenaidoo0a822f92019-05-08 15:15:57 -04001586
1587 return nil
1588}
1589
khenaidoo19d7b632018-10-30 10:49:50 -04001590// enableLogicalPort enables the logical port
Kent Hagerman2b216042020-04-03 18:28:56 -04001591func (agent *LogicalAgent) enableLogicalPort(ctx context.Context, lPortID string) error {
khenaidoo442e7c72020-03-10 16:13:48 -04001592 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1593 return err
1594 }
1595 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -04001596
khenaidoo6e55d9e2019-12-12 18:26:26 -05001597 logicalDevice := agent.getLogicalDeviceWithoutLock()
1598
khenaidoo19d7b632018-10-30 10:49:50 -04001599 index := -1
khenaidoo6e55d9e2019-12-12 18:26:26 -05001600 for i, logicalPort := range logicalDevice.Ports {
npujar1d86a522019-11-14 17:11:16 +05301601 if logicalPort.Id == lPortID {
khenaidoo19d7b632018-10-30 10:49:50 -04001602 index = i
1603 break
1604 }
1605 }
1606 if index >= 0 {
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001607 clonedPorts := clonePorts(logicalDevice.Ports)
1608 clonedPorts[index].OfpPort.Config = clonedPorts[index].OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
1609 return agent.updateLogicalDevicePortsWithoutLock(ctx, logicalDevice, clonedPorts)
khenaidoo19d7b632018-10-30 10:49:50 -04001610 }
npujar1d86a522019-11-14 17:11:16 +05301611 return status.Errorf(codes.NotFound, "Port %s on Logical Device %s", lPortID, agent.logicalDeviceID)
khenaidoo19d7b632018-10-30 10:49:50 -04001612}
1613
1614// disableLogicalPort disabled the logical port
Kent Hagerman2b216042020-04-03 18:28:56 -04001615func (agent *LogicalAgent) disableLogicalPort(ctx context.Context, lPortID string) error {
khenaidoo442e7c72020-03-10 16:13:48 -04001616 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1617 return err
1618 }
1619 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -04001620
1621 // Get the most up to date logical device
khenaidoo6e55d9e2019-12-12 18:26:26 -05001622 logicalDevice := agent.getLogicalDeviceWithoutLock()
khenaidoo19d7b632018-10-30 10:49:50 -04001623 index := -1
khenaidoo6e55d9e2019-12-12 18:26:26 -05001624 for i, logicalPort := range logicalDevice.Ports {
npujar1d86a522019-11-14 17:11:16 +05301625 if logicalPort.Id == lPortID {
khenaidoo19d7b632018-10-30 10:49:50 -04001626 index = i
1627 break
1628 }
1629 }
1630 if index >= 0 {
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001631 clonedPorts := clonePorts(logicalDevice.Ports)
1632 clonedPorts[index].OfpPort.Config = (clonedPorts[index].OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)) | uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
1633 return agent.updateLogicalDevicePortsWithoutLock(ctx, logicalDevice, clonedPorts)
khenaidoo19d7b632018-10-30 10:49:50 -04001634 }
npujar1d86a522019-11-14 17:11:16 +05301635 return status.Errorf(codes.NotFound, "Port %s on Logical Device %s", lPortID, agent.logicalDeviceID)
khenaidoo19d7b632018-10-30 10:49:50 -04001636}
1637
Kent Hagerman2b216042020-04-03 18:28:56 -04001638func (agent *LogicalAgent) getPreCalculatedRoute(ingress, egress uint32) ([]route.Hop, error) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001639 logger.Debugw("ROUTE", log.Fields{"len": len(agent.deviceRoutes.Routes)})
khenaidoo820197c2020-02-13 16:35:33 -05001640 for routeLink, route := range agent.deviceRoutes.Routes {
Girish Kumarf56a4682020-03-20 20:07:46 +00001641 logger.Debugw("ROUTELINKS", log.Fields{"ingress": ingress, "egress": egress, "routelink": routeLink})
khenaidoo89b0e942018-10-21 21:11:33 -04001642 if ingress == routeLink.Ingress && egress == routeLink.Egress {
khenaidoo820197c2020-02-13 16:35:33 -05001643 return route, nil
khenaidoo89b0e942018-10-21 21:11:33 -04001644 }
1645 }
khenaidoo820197c2020-02-13 16:35:33 -05001646 return nil, status.Errorf(codes.FailedPrecondition, "no route from:%d to:%d", ingress, egress)
khenaidoo89b0e942018-10-21 21:11:33 -04001647}
1648
npujar1d86a522019-11-14 17:11:16 +05301649// GetRoute returns route
Kent Hagerman2b216042020-04-03 18:28:56 -04001650func (agent *LogicalAgent) GetRoute(ctx context.Context, ingressPortNo uint32, egressPortNo uint32) ([]route.Hop, error) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001651 logger.Debugw("getting-route", log.Fields{"ingress-port": ingressPortNo, "egress-port": egressPortNo})
khenaidoo820197c2020-02-13 16:35:33 -05001652 routes := make([]route.Hop, 0)
khenaidoo2c6a0992019-04-29 13:46:56 -04001653
khenaidoo19d7b632018-10-30 10:49:50 -04001654 // Note: A port value of 0 is equivalent to a nil port
1655
khenaidoo89b0e942018-10-21 21:11:33 -04001656 // Consider different possibilities
khenaidoo19d7b632018-10-30 10:49:50 -04001657 if egressPortNo != 0 && ((egressPortNo & 0x7fffffff) == uint32(ofp.OfpPortNo_OFPP_CONTROLLER)) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001658 logger.Debugw("controller-flow", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "logicalPortsNo": agent.logicalPortsNo})
khenaidoo2c6a0992019-04-29 13:46:56 -04001659 if agent.isNNIPort(ingressPortNo) {
khenaidoo89b0e942018-10-21 21:11:33 -04001660 //This is a trap on the NNI Port
khenaidoo820197c2020-02-13 16:35:33 -05001661 if len(agent.deviceRoutes.Routes) == 0 {
khenaidoo8f474192019-04-03 17:20:44 -04001662 // 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 -04001663 // route with same IngressHop and EgressHop
khenaidoo820197c2020-02-13 16:35:33 -05001664 hop := route.Hop{DeviceID: agent.rootDeviceID, Ingress: ingressPortNo, Egress: ingressPortNo}
khenaidoo8f474192019-04-03 17:20:44 -04001665 routes = append(routes, hop)
1666 routes = append(routes, hop)
khenaidoo820197c2020-02-13 16:35:33 -05001667 return routes, nil
khenaidoo8f474192019-04-03 17:20:44 -04001668 }
khenaidoo89b0e942018-10-21 21:11:33 -04001669 //Return a 'half' route to make the flow decomposer logic happy
khenaidoo820197c2020-02-13 16:35:33 -05001670 for routeLink, path := range agent.deviceRoutes.Routes {
khenaidoo2c6a0992019-04-29 13:46:56 -04001671 if agent.isNNIPort(routeLink.Egress) {
khenaidoo820197c2020-02-13 16:35:33 -05001672 routes = append(routes, route.Hop{}) // first hop is set to empty
1673 routes = append(routes, path[1])
1674 return routes, nil
khenaidoo89b0e942018-10-21 21:11:33 -04001675 }
1676 }
khenaidoo787224a2020-04-16 18:08:47 -04001677 return nil, fmt.Errorf("no upstream route from:%d to:%d :%w", ingressPortNo, egressPortNo, route.ErrNoRoute)
khenaidoo89b0e942018-10-21 21:11:33 -04001678 }
1679 //treat it as if the output port is the first NNI of the OLT
khenaidoo2c6a0992019-04-29 13:46:56 -04001680 var err error
1681 if egressPortNo, err = agent.getFirstNNIPort(); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001682 logger.Warnw("no-nni-port", log.Fields{"error": err})
khenaidoo820197c2020-02-13 16:35:33 -05001683 return nil, err
khenaidoo2c6a0992019-04-29 13:46:56 -04001684 }
khenaidoo89b0e942018-10-21 21:11:33 -04001685 }
1686 //If ingress port is not specified (nil), it may be a wildcarded
1687 //route if egress port is OFPP_CONTROLLER or a nni logical port,
1688 //in which case we need to create a half-route where only the egress
1689 //hop is filled, the first hop is nil
khenaidoo2c6a0992019-04-29 13:46:56 -04001690 if ingressPortNo == 0 && agent.isNNIPort(egressPortNo) {
khenaidoo89b0e942018-10-21 21:11:33 -04001691 // We can use the 2nd hop of any upstream route, so just find the first upstream:
khenaidoo820197c2020-02-13 16:35:33 -05001692 for routeLink, path := range agent.deviceRoutes.Routes {
khenaidoo2c6a0992019-04-29 13:46:56 -04001693 if agent.isNNIPort(routeLink.Egress) {
khenaidoo820197c2020-02-13 16:35:33 -05001694 routes = append(routes, route.Hop{}) // first hop is set to empty
1695 routes = append(routes, path[1])
1696 return routes, nil
khenaidoo89b0e942018-10-21 21:11:33 -04001697 }
1698 }
khenaidoo787224a2020-04-16 18:08:47 -04001699 return nil, fmt.Errorf("no upstream route from:%d to:%d :%w", ingressPortNo, egressPortNo, route.ErrNoRoute)
khenaidoo89b0e942018-10-21 21:11:33 -04001700 }
1701 //If egress port is not specified (nil), we can also can return a "half" route
khenaidoo19d7b632018-10-30 10:49:50 -04001702 if egressPortNo == 0 {
khenaidoo820197c2020-02-13 16:35:33 -05001703 for routeLink, path := range agent.deviceRoutes.Routes {
khenaidoo19d7b632018-10-30 10:49:50 -04001704 if routeLink.Ingress == ingressPortNo {
khenaidoo820197c2020-02-13 16:35:33 -05001705 routes = append(routes, path[0])
1706 routes = append(routes, route.Hop{})
1707 return routes, nil
khenaidoo89b0e942018-10-21 21:11:33 -04001708 }
1709 }
khenaidoo787224a2020-04-16 18:08:47 -04001710 return nil, fmt.Errorf("no downstream route from:%d to:%d :%w", ingressPortNo, egressPortNo, route.ErrNoRoute)
khenaidoo89b0e942018-10-21 21:11:33 -04001711 }
khenaidoo89b0e942018-10-21 21:11:33 -04001712 // Return the pre-calculated route
khenaidoo19d7b632018-10-30 10:49:50 -04001713 return agent.getPreCalculatedRoute(ingressPortNo, egressPortNo)
khenaidoo89b0e942018-10-21 21:11:33 -04001714}
1715
khenaidoo3d3b8c22019-05-22 18:10:39 -04001716//GetWildcardInputPorts filters out the logical port number from the set of logical ports on the device and
1717//returns their port numbers. This function is invoked only during flow decomposition where the lock on the logical
1718//device is already held. Therefore it is safe to retrieve the logical device without lock.
Kent Hagerman2b216042020-04-03 18:28:56 -04001719func (agent *LogicalAgent) GetWildcardInputPorts(excludePort ...uint32) []uint32 {
khenaidoo89b0e942018-10-21 21:11:33 -04001720 lPorts := make([]uint32, 0)
1721 var exclPort uint32
1722 if len(excludePort) == 1 {
1723 exclPort = excludePort[0]
1724 }
khenaidoo6e55d9e2019-12-12 18:26:26 -05001725 lDevice := agent.getLogicalDeviceWithoutLock()
1726 for _, port := range lDevice.Ports {
1727 if port.OfpPort.PortNo != exclPort {
1728 lPorts = append(lPorts, port.OfpPort.PortNo)
khenaidoo89b0e942018-10-21 21:11:33 -04001729 }
1730 }
1731 return lPorts
1732}
khenaidoo19d7b632018-10-30 10:49:50 -04001733
khenaidoo820197c2020-02-13 16:35:33 -05001734// GetDeviceRoutes returns device graph
Kent Hagerman2b216042020-04-03 18:28:56 -04001735func (agent *LogicalAgent) GetDeviceRoutes() *route.DeviceRoutes {
khenaidoo820197c2020-02-13 16:35:33 -05001736 return agent.deviceRoutes
khenaidoo19d7b632018-10-30 10:49:50 -04001737}
1738
khenaidoo820197c2020-02-13 16:35:33 -05001739//rebuildRoutes rebuilds the device routes
Kent Hagerman2b216042020-04-03 18:28:56 -04001740func (agent *LogicalAgent) buildRoutes(ctx context.Context) error {
Girish Kumarf56a4682020-03-20 20:07:46 +00001741 logger.Debugf("building-routes", log.Fields{"logical-device-id": agent.logicalDeviceID})
khenaidoo442e7c72020-03-10 16:13:48 -04001742 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1743 return err
1744 }
1745 defer agent.requestQueue.RequestComplete()
1746
khenaidoo820197c2020-02-13 16:35:33 -05001747 if agent.deviceRoutes == nil {
Kent Hagerman45a13e42020-04-13 12:23:50 -04001748 agent.deviceRoutes = route.NewDeviceRoutes(agent.logicalDeviceID, agent.deviceMgr.getDevice)
khenaidoo2c6a0992019-04-29 13:46:56 -04001749 }
1750 // Get all the logical ports on that logical device
khenaidoo6e55d9e2019-12-12 18:26:26 -05001751 lDevice := agent.getLogicalDeviceWithoutLock()
1752
khenaidoo820197c2020-02-13 16:35:33 -05001753 if err := agent.deviceRoutes.ComputeRoutes(ctx, lDevice.Ports); err != nil {
1754 return err
1755 }
1756 if err := agent.deviceRoutes.Print(); err != nil {
1757 return err
1758 }
1759
khenaidoo2c6a0992019-04-29 13:46:56 -04001760 return nil
khenaidoo19d7b632018-10-30 10:49:50 -04001761}
1762
khenaidoo820197c2020-02-13 16:35:33 -05001763//updateRoutes updates the device routes
Kent Hagerman2b216042020-04-03 18:28:56 -04001764func (agent *LogicalAgent) updateRoutes(ctx context.Context, lp *voltha.LogicalPort) error {
Girish Kumarf56a4682020-03-20 20:07:46 +00001765 logger.Debugw("updateRoutes", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo442e7c72020-03-10 16:13:48 -04001766 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1767 return err
1768 }
1769 defer agent.requestQueue.RequestComplete()
1770
khenaidoo820197c2020-02-13 16:35:33 -05001771 if agent.deviceRoutes == nil {
Kent Hagerman45a13e42020-04-13 12:23:50 -04001772 agent.deviceRoutes = route.NewDeviceRoutes(agent.logicalDeviceID, agent.deviceMgr.getDevice)
khenaidoo910204f2019-04-08 17:56:40 -04001773 }
khenaidoo820197c2020-02-13 16:35:33 -05001774 if err := agent.deviceRoutes.AddPort(ctx, lp, agent.logicalDevice.Ports); err != nil {
1775 return err
khenaidoo0a822f92019-05-08 15:15:57 -04001776 }
khenaidoo820197c2020-02-13 16:35:33 -05001777 if err := agent.deviceRoutes.Print(); err != nil {
1778 return err
1779 }
1780 return nil
khenaidoo0a822f92019-05-08 15:15:57 -04001781}
1782
khenaidoofc1314d2019-03-14 09:34:21 -04001783// 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 -04001784func diff(oldList, newList []*voltha.LogicalPort) (newPorts, changedPorts, deletedPorts map[string]*voltha.LogicalPort) {
1785 newPorts = make(map[string]*voltha.LogicalPort, len(newList))
1786 changedPorts = make(map[string]*voltha.LogicalPort, len(oldList))
1787 deletedPorts = make(map[string]*voltha.LogicalPort, len(oldList))
1788
khenaidoofc1314d2019-03-14 09:34:21 -04001789 for _, n := range newList {
Kent Hagerman8ad29952020-04-21 11:48:02 -04001790 newPorts[n.Id] = n
1791 }
1792
1793 for _, o := range oldList {
1794 if n, have := newPorts[o.Id]; have {
1795 delete(newPorts, o.Id) // not new
1796 if !proto.Equal(n, o) {
1797 changedPorts[n.Id] = n // changed
khenaidoofc1314d2019-03-14 09:34:21 -04001798 }
Kent Hagerman8ad29952020-04-21 11:48:02 -04001799 } else {
1800 deletedPorts[o.Id] = o // deleted
khenaidoo2bc48282019-07-16 18:13:46 -04001801 }
khenaidoofc1314d2019-03-14 09:34:21 -04001802 }
Kent Hagerman8ad29952020-04-21 11:48:02 -04001803
1804 return newPorts, changedPorts, deletedPorts
khenaidoofc1314d2019-03-14 09:34:21 -04001805}
1806
Kent Hagerman8ad29952020-04-21 11:48:02 -04001807// portUpdated is invoked when a port is updated on the logical device
1808func (agent *LogicalAgent) portUpdated(prevPorts, currPorts []*voltha.LogicalPort) interface{} {
khenaidoofc1314d2019-03-14 09:34:21 -04001809 // Get the difference between the two list
Kent Hagerman8ad29952020-04-21 11:48:02 -04001810 newPorts, changedPorts, deletedPorts := diff(prevPorts, currPorts)
1811
khenaidoofc1314d2019-03-14 09:34:21 -04001812 // Send the port change events to the OF controller
khenaidoo2c6a0992019-04-29 13:46:56 -04001813 for _, newP := range newPorts {
Kent Hagerman45a13e42020-04-13 12:23:50 -04001814 go agent.ldeviceMgr.SendChangeEvent(agent.logicalDeviceID,
khenaidoo2c6a0992019-04-29 13:46:56 -04001815 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_ADD, Desc: newP.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001816 }
1817 for _, change := range changedPorts {
Kent Hagerman45a13e42020-04-13 12:23:50 -04001818 go agent.ldeviceMgr.SendChangeEvent(agent.logicalDeviceID,
khenaidoo910204f2019-04-08 17:56:40 -04001819 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_MODIFY, Desc: change.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001820 }
1821 for _, del := range deletedPorts {
Kent Hagerman45a13e42020-04-13 12:23:50 -04001822 go agent.ldeviceMgr.SendChangeEvent(agent.logicalDeviceID,
khenaidoo910204f2019-04-08 17:56:40 -04001823 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_DELETE, Desc: del.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001824 }
1825
1826 return nil
1827}
1828
khenaidoo8f474192019-04-03 17:20:44 -04001829// addNNILogicalPort adds an NNI port to the logical device. It returns a bool representing whether a port has been
1830// added and an eror in case a valid error is encountered. If the port was successfully added it will return
1831// (true, nil). If the device is not in the correct state it will return (false, nil) as this is a valid
1832// scenario. This also applies to the case where the port was already added.
Kent Hagerman2b216042020-04-03 18:28:56 -04001833func (agent *LogicalAgent) addNNILogicalPort(ctx context.Context, device *voltha.Device, port *voltha.Port) (bool, error) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001834 logger.Debugw("addNNILogicalPort", log.Fields{"NNI": port})
Chaitrashree G S7849b322020-03-29 19:25:49 -04001835
khenaidoo442e7c72020-03-10 16:13:48 -04001836 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1837 return false, err
1838 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001839 if agent.portExist(device, port) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001840 logger.Debugw("port-already-exist", log.Fields{"port": port})
khenaidoo442e7c72020-03-10 16:13:48 -04001841 agent.requestQueue.RequestComplete()
khenaidoo8f474192019-04-03 17:20:44 -04001842 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001843 }
khenaidoo442e7c72020-03-10 16:13:48 -04001844 agent.requestQueue.RequestComplete()
khenaidoo1ce37ad2019-03-24 22:07:24 -04001845
khenaidoofc1314d2019-03-14 09:34:21 -04001846 var portCap *ic.PortCapability
1847 var err error
1848 // First get the port capability
npujar467fe752020-01-16 20:17:45 +05301849 if portCap, err = agent.deviceMgr.getPortCapability(ctx, device.Id, port.PortNo); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001850 logger.Errorw("error-retrieving-port-capabilities", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001851 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001852 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001853
khenaidoo442e7c72020-03-10 16:13:48 -04001854 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1855 return false, err
1856 }
1857
1858 defer agent.requestQueue.RequestComplete()
khenaidoo1ce37ad2019-03-24 22:07:24 -04001859 // Double check again if this port has been already added since the getPortCapability could have taken a long time
1860 if agent.portExist(device, port) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001861 logger.Debugw("port-already-exist", log.Fields{"port": port})
khenaidoo8f474192019-04-03 17:20:44 -04001862 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001863 }
1864
khenaidoofc1314d2019-03-14 09:34:21 -04001865 portCap.Port.RootPort = true
1866 lp := (proto.Clone(portCap.Port)).(*voltha.LogicalPort)
1867 lp.DeviceId = device.Id
1868 lp.Id = fmt.Sprintf("nni-%d", port.PortNo)
1869 lp.OfpPort.PortNo = port.PortNo
1870 lp.OfpPort.Name = lp.Id
1871 lp.DevicePortNo = port.PortNo
1872
khenaidoo6e55d9e2019-12-12 18:26:26 -05001873 ld := agent.getLogicalDeviceWithoutLock()
1874
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001875 clonedPorts := clonePorts(ld.Ports)
1876 if clonedPorts == nil {
1877 clonedPorts = make([]*voltha.LogicalPort, 0)
khenaidoofc1314d2019-03-14 09:34:21 -04001878 }
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001879 clonedPorts = append(clonedPorts, lp)
khenaidoofc1314d2019-03-14 09:34:21 -04001880
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001881 if err = agent.updateLogicalDevicePortsWithoutLock(ctx, ld, clonedPorts); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001882 logger.Errorw("error-updating-logical-device", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001883 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001884 }
khenaidoo910204f2019-04-08 17:56:40 -04001885
khenaidoo820197c2020-02-13 16:35:33 -05001886 // Update the device routes with this new logical port
khenaidoo910204f2019-04-08 17:56:40 -04001887 clonedLP := (proto.Clone(lp)).(*voltha.LogicalPort)
khenaidoo820197c2020-02-13 16:35:33 -05001888 go func() {
1889 if err := agent.updateRoutes(context.Background(), clonedLP); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001890 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 -05001891 }
1892 }()
khenaidoo910204f2019-04-08 17:56:40 -04001893
khenaidoo8f474192019-04-03 17:20:44 -04001894 return true, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001895}
1896
Kent Hagerman2b216042020-04-03 18:28:56 -04001897func (agent *LogicalAgent) portExist(device *voltha.Device, port *voltha.Port) bool {
khenaidoo6e55d9e2019-12-12 18:26:26 -05001898 ldevice := agent.getLogicalDeviceWithoutLock()
1899 for _, lPort := range ldevice.Ports {
1900 if lPort.DeviceId == device.Id && lPort.DevicePortNo == port.PortNo && lPort.Id == port.Label {
1901 return true
khenaidoofc1314d2019-03-14 09:34:21 -04001902 }
1903 }
1904 return false
1905}
1906
khenaidoo8f474192019-04-03 17:20:44 -04001907// addUNILogicalPort adds an UNI port to the logical device. It returns a bool representing whether a port has been
1908// added and an eror in case a valid error is encountered. If the port was successfully added it will return
1909// (true, nil). If the device is not in the correct state it will return (false, nil) as this is a valid
1910// scenario. This also applies to the case where the port was already added.
Kent Hagerman2b216042020-04-03 18:28:56 -04001911func (agent *LogicalAgent) addUNILogicalPort(ctx context.Context, childDevice *voltha.Device, port *voltha.Port) (bool, error) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001912 logger.Debugw("addUNILogicalPort", log.Fields{"port": port})
khenaidoo8f474192019-04-03 17:20:44 -04001913 if childDevice.AdminState != voltha.AdminState_ENABLED || childDevice.OperStatus != voltha.OperStatus_ACTIVE {
Girish Kumarf56a4682020-03-20 20:07:46 +00001914 logger.Infow("device-not-ready", log.Fields{"deviceId": childDevice.Id, "admin": childDevice.AdminState, "oper": childDevice.OperStatus})
khenaidoo8f474192019-04-03 17:20:44 -04001915 return false, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001916 }
khenaidoo442e7c72020-03-10 16:13:48 -04001917 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1918 return false, err
1919 }
1920
khenaidoo1ce37ad2019-03-24 22:07:24 -04001921 if agent.portExist(childDevice, port) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001922 logger.Debugw("port-already-exist", log.Fields{"port": port})
khenaidoo442e7c72020-03-10 16:13:48 -04001923 agent.requestQueue.RequestComplete()
khenaidoo8f474192019-04-03 17:20:44 -04001924 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001925 }
khenaidoo442e7c72020-03-10 16:13:48 -04001926 agent.requestQueue.RequestComplete()
khenaidoofc1314d2019-03-14 09:34:21 -04001927 var portCap *ic.PortCapability
1928 var err error
1929 // First get the port capability
npujar467fe752020-01-16 20:17:45 +05301930 if portCap, err = agent.deviceMgr.getPortCapability(ctx, childDevice.Id, port.PortNo); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001931 logger.Errorw("error-retrieving-port-capabilities", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001932 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001933 }
khenaidoo442e7c72020-03-10 16:13:48 -04001934 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1935 return false, err
1936 }
1937 defer agent.requestQueue.RequestComplete()
khenaidoo1ce37ad2019-03-24 22:07:24 -04001938 // Double check again if this port has been already added since the getPortCapability could have taken a long time
1939 if agent.portExist(childDevice, port) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001940 logger.Debugw("port-already-exist", log.Fields{"port": port})
khenaidoo8f474192019-04-03 17:20:44 -04001941 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001942 }
khenaidoofc1314d2019-03-14 09:34:21 -04001943 // Get stored logical device
khenaidoo6e55d9e2019-12-12 18:26:26 -05001944 ldevice := agent.getLogicalDeviceWithoutLock()
1945
Girish Kumarf56a4682020-03-20 20:07:46 +00001946 logger.Debugw("adding-uni", log.Fields{"deviceId": childDevice.Id})
npujar1d86a522019-11-14 17:11:16 +05301947 portCap.Port.RootPort = false
1948 portCap.Port.Id = port.Label
1949 portCap.Port.OfpPort.PortNo = port.PortNo
1950 portCap.Port.DeviceId = childDevice.Id
1951 portCap.Port.DevicePortNo = port.PortNo
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001952 clonedPorts := clonePorts(ldevice.Ports)
1953 if clonedPorts == nil {
1954 clonedPorts = make([]*voltha.LogicalPort, 0)
npujar1d86a522019-11-14 17:11:16 +05301955 }
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001956 clonedPorts = append(clonedPorts, portCap.Port)
1957 if err := agent.updateLogicalDevicePortsWithoutLock(ctx, ldevice, clonedPorts); err != nil {
npujar1d86a522019-11-14 17:11:16 +05301958 return false, err
1959 }
1960 // Update the device graph with this new logical port
1961 clonedLP := (proto.Clone(portCap.Port)).(*voltha.LogicalPort)
khenaidoo820197c2020-02-13 16:35:33 -05001962
1963 go func() {
1964 if err := agent.updateRoutes(context.Background(), clonedLP); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001965 logger.Warn("routes-not-ready", log.Fields{"logical-device-id": agent.logicalDeviceID, "error": err})
khenaidoo820197c2020-02-13 16:35:33 -05001966 }
1967 }()
1968
npujar1d86a522019-11-14 17:11:16 +05301969 return true, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001970}
1971
Kent Hagerman2b216042020-04-03 18:28:56 -04001972func (agent *LogicalAgent) packetOut(ctx context.Context, packet *ofp.OfpPacketOut) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001973 logger.Debugw("packet-out", log.Fields{
Matteo Scandolo360605d2019-11-05 18:29:17 -08001974 "packet": hex.EncodeToString(packet.Data),
1975 "inPort": packet.GetInPort(),
1976 })
khenaidoo68c930b2019-05-13 11:46:51 -04001977 outPort := fu.GetPacketOutPort(packet)
khenaidoofdbad6e2018-11-06 22:26:38 -05001978 //frame := packet.GetData()
1979 //TODO: Use a channel between the logical agent and the device agent
npujar467fe752020-01-16 20:17:45 +05301980 if err := agent.deviceMgr.packetOut(ctx, agent.rootDeviceID, outPort, packet); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001981 logger.Error("packetout-failed", log.Fields{"logicalDeviceID": agent.rootDeviceID})
khenaidooca301322019-01-09 23:06:32 -05001982 }
khenaidoofdbad6e2018-11-06 22:26:38 -05001983}
1984
Kent Hagerman2b216042020-04-03 18:28:56 -04001985func (agent *LogicalAgent) packetIn(port uint32, transactionID string, packet []byte) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001986 logger.Debugw("packet-in", log.Fields{
Matteo Scandolo360605d2019-11-05 18:29:17 -08001987 "port": port,
1988 "packet": hex.EncodeToString(packet),
npujar1d86a522019-11-14 17:11:16 +05301989 "transactionId": transactionID,
Matteo Scandolo360605d2019-11-05 18:29:17 -08001990 })
khenaidoo68c930b2019-05-13 11:46:51 -04001991 packetIn := fu.MkPacketIn(port, packet)
Kent Hagerman45a13e42020-04-13 12:23:50 -04001992 agent.ldeviceMgr.SendPacketIn(agent.logicalDeviceID, transactionID, packetIn)
Girish Kumarf56a4682020-03-20 20:07:46 +00001993 logger.Debugw("sending-packet-in", log.Fields{"packet": hex.EncodeToString(packetIn.Data)})
khenaidoofdbad6e2018-11-06 22:26:38 -05001994}
khenaidoo2c6a0992019-04-29 13:46:56 -04001995
Kent Hagerman2b216042020-04-03 18:28:56 -04001996func (agent *LogicalAgent) addLogicalPortToMap(portNo uint32, nniPort bool) {
khenaidoo2c6a0992019-04-29 13:46:56 -04001997 agent.lockLogicalPortsNo.Lock()
1998 defer agent.lockLogicalPortsNo.Unlock()
1999 if exist := agent.logicalPortsNo[portNo]; !exist {
2000 agent.logicalPortsNo[portNo] = nniPort
2001 }
2002}
2003
Kent Hagerman2b216042020-04-03 18:28:56 -04002004func (agent *LogicalAgent) deleteLogicalPortsFromMap(portsNo []uint32) {
khenaidoo820197c2020-02-13 16:35:33 -05002005 agent.lockLogicalPortsNo.Lock()
2006 defer agent.lockLogicalPortsNo.Unlock()
2007 for _, pNo := range portsNo {
2008 delete(agent.logicalPortsNo, pNo)
2009 }
2010}
2011
Kent Hagerman2b216042020-04-03 18:28:56 -04002012func (agent *LogicalAgent) addLogicalPortsToMap(lps []*voltha.LogicalPort) {
khenaidoo3d3b8c22019-05-22 18:10:39 -04002013 agent.lockLogicalPortsNo.Lock()
2014 defer agent.lockLogicalPortsNo.Unlock()
2015 for _, lp := range lps {
2016 if exist := agent.logicalPortsNo[lp.DevicePortNo]; !exist {
2017 agent.logicalPortsNo[lp.DevicePortNo] = lp.RootPort
2018 }
2019 }
2020}
2021
Kent Hagerman2b216042020-04-03 18:28:56 -04002022func (agent *LogicalAgent) isNNIPort(portNo uint32) bool {
khenaidoo2c6a0992019-04-29 13:46:56 -04002023 agent.lockLogicalPortsNo.RLock()
2024 defer agent.lockLogicalPortsNo.RUnlock()
2025 if exist := agent.logicalPortsNo[portNo]; exist {
2026 return agent.logicalPortsNo[portNo]
2027 }
2028 return false
2029}
2030
Kent Hagerman2b216042020-04-03 18:28:56 -04002031func (agent *LogicalAgent) getFirstNNIPort() (uint32, error) {
khenaidoo2c6a0992019-04-29 13:46:56 -04002032 agent.lockLogicalPortsNo.RLock()
2033 defer agent.lockLogicalPortsNo.RUnlock()
2034 for portNo, nni := range agent.logicalPortsNo {
2035 if nni {
2036 return portNo, nil
2037 }
2038 }
2039 return 0, status.Error(codes.NotFound, "No NNI port found")
2040}
Esin Karaman09959ae2019-11-29 13:59:58 +00002041
2042//GetNNIPorts returns NNI ports.
Kent Hagerman2b216042020-04-03 18:28:56 -04002043func (agent *LogicalAgent) GetNNIPorts() []uint32 {
Esin Karaman09959ae2019-11-29 13:59:58 +00002044 agent.lockLogicalPortsNo.RLock()
2045 defer agent.lockLogicalPortsNo.RUnlock()
2046 nniPorts := make([]uint32, 0)
2047 for portNo, nni := range agent.logicalPortsNo {
2048 if nni {
2049 nniPorts = append(nniPorts, portNo)
2050 }
2051 }
2052 return nniPorts
2053}