blob: 7bc8e4d2929d92ecf5d3d961f02afcd490380864 [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
521//updateLogicalDevicePortsWithoutLock updates the
Kent Hagerman2b216042020-04-03 18:28:56 -0400522func (agent *LogicalAgent) updateLogicalDevicePortsWithoutLock(ctx context.Context, device *voltha.LogicalDevice, newPorts []*voltha.LogicalPort) error {
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500523 oldPorts := device.Ports
524 device.Ports = newPorts
525 if err := agent.updateLogicalDeviceWithoutLock(ctx, device); err != nil {
526 return err
527 }
528 agent.portUpdated(oldPorts, newPorts)
529 return nil
530}
531
khenaidoo92e62c52018-10-03 14:02:54 -0400532//updateLogicalDeviceWithoutLock updates the model with the logical device. It clones the logicaldevice before saving it
Kent Hagerman2b216042020-04-03 18:28:56 -0400533func (agent *LogicalAgent) updateLogicalDeviceWithoutLock(ctx context.Context, logicalDevice *voltha.LogicalDevice) error {
Kent Hagerman4f355f52020-03-30 16:01:33 -0400534 if agent.stopped {
535 return errors.New("logical device agent stopped")
536 }
537
npujar467fe752020-01-16 20:17:45 +0530538 updateCtx := context.WithValue(ctx, model.RequestTimestamp, time.Now().UnixNano())
Kent Hagerman4f355f52020-03-30 16:01:33 -0400539 if err := agent.clusterDataProxy.Update(updateCtx, "logical_devices/"+agent.logicalDeviceID, logicalDevice); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000540 logger.Errorw("failed-to-update-logical-devices-to-cluster-proxy", log.Fields{"error": err})
Thomas Lee Se5a44012019-11-07 20:32:24 +0530541 return err
542 }
Kent Hagerman4f355f52020-03-30 16:01:33 -0400543
khenaidoo442e7c72020-03-10 16:13:48 -0400544 agent.logicalDevice = logicalDevice
545
khenaidoo92e62c52018-10-03 14:02:54 -0400546 return nil
547}
548
khenaidoo820197c2020-02-13 16:35:33 -0500549//generateDeviceRoutesIfNeeded generates the device routes if the logical device has been updated since the last time
khenaidoo4c9e5592019-09-09 16:20:41 -0400550//that device graph was generated.
Kent Hagerman2b216042020-04-03 18:28:56 -0400551func (agent *LogicalAgent) generateDeviceRoutesIfNeeded(ctx context.Context) error {
khenaidoo820197c2020-02-13 16:35:33 -0500552 agent.lockDeviceRoutes.Lock()
553 defer agent.lockDeviceRoutes.Unlock()
554
khenaidoo442e7c72020-03-10 16:13:48 -0400555 ld, err := agent.GetLogicalDevice(ctx)
556 if err != nil {
557 return err
558 }
khenaidoo820197c2020-02-13 16:35:33 -0500559
560 if agent.deviceRoutes != nil && agent.deviceRoutes.IsUpToDate(ld) {
npujar1d86a522019-11-14 17:11:16 +0530561 return nil
562 }
Girish Kumarf56a4682020-03-20 20:07:46 +0000563 logger.Debug("Generation of device route required")
khenaidoo820197c2020-02-13 16:35:33 -0500564 if err := agent.buildRoutes(ctx); err != nil {
khenaidoo787224a2020-04-16 18:08:47 -0400565 // No Route is not an error
566 if !errors.Is(err, route.ErrNoRoute) {
567 return err
568 }
khenaidoo820197c2020-02-13 16:35:33 -0500569 }
khenaidoo4c9e5592019-09-09 16:20:41 -0400570 return nil
571}
572
khenaidoo19d7b632018-10-30 10:49:50 -0400573//updateFlowTable updates the flow table of that logical device
Kent Hagerman2b216042020-04-03 18:28:56 -0400574func (agent *LogicalAgent) updateFlowTable(ctx context.Context, flow *ofp.OfpFlowMod) error {
575 logger.Debug("UpdateFlowTable")
khenaidoo19d7b632018-10-30 10:49:50 -0400576 if flow == nil {
577 return nil
578 }
khenaidoo820197c2020-02-13 16:35:33 -0500579 if err := agent.generateDeviceRoutesIfNeeded(ctx); err != nil {
khenaidoo4c9e5592019-09-09 16:20:41 -0400580 return err
581 }
khenaidoo19d7b632018-10-30 10:49:50 -0400582 switch flow.GetCommand() {
583 case ofp.OfpFlowModCommand_OFPFC_ADD:
npujar467fe752020-01-16 20:17:45 +0530584 return agent.flowAdd(ctx, flow)
khenaidoo19d7b632018-10-30 10:49:50 -0400585 case ofp.OfpFlowModCommand_OFPFC_DELETE:
npujar467fe752020-01-16 20:17:45 +0530586 return agent.flowDelete(ctx, flow)
khenaidoo19d7b632018-10-30 10:49:50 -0400587 case ofp.OfpFlowModCommand_OFPFC_DELETE_STRICT:
npujar467fe752020-01-16 20:17:45 +0530588 return agent.flowDeleteStrict(ctx, flow)
khenaidoo19d7b632018-10-30 10:49:50 -0400589 case ofp.OfpFlowModCommand_OFPFC_MODIFY:
590 return agent.flowModify(flow)
591 case ofp.OfpFlowModCommand_OFPFC_MODIFY_STRICT:
592 return agent.flowModifyStrict(flow)
593 }
594 return status.Errorf(codes.Internal,
npujar1d86a522019-11-14 17:11:16 +0530595 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceID, flow.GetCommand())
khenaidoo19d7b632018-10-30 10:49:50 -0400596}
597
598//updateGroupTable updates the group table of that logical device
Kent Hagerman2b216042020-04-03 18:28:56 -0400599func (agent *LogicalAgent) updateGroupTable(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000600 logger.Debug("updateGroupTable")
khenaidoo19d7b632018-10-30 10:49:50 -0400601 if groupMod == nil {
602 return nil
603 }
khenaidoo820197c2020-02-13 16:35:33 -0500604 if err := agent.generateDeviceRoutesIfNeeded(ctx); err != nil {
khenaidoo4c9e5592019-09-09 16:20:41 -0400605 return err
606 }
khenaidoo820197c2020-02-13 16:35:33 -0500607
khenaidoo19d7b632018-10-30 10:49:50 -0400608 switch groupMod.GetCommand() {
609 case ofp.OfpGroupModCommand_OFPGC_ADD:
npujar467fe752020-01-16 20:17:45 +0530610 return agent.groupAdd(ctx, groupMod)
khenaidoo19d7b632018-10-30 10:49:50 -0400611 case ofp.OfpGroupModCommand_OFPGC_DELETE:
npujar467fe752020-01-16 20:17:45 +0530612 return agent.groupDelete(ctx, groupMod)
khenaidoo19d7b632018-10-30 10:49:50 -0400613 case ofp.OfpGroupModCommand_OFPGC_MODIFY:
npujar467fe752020-01-16 20:17:45 +0530614 return agent.groupModify(ctx, groupMod)
khenaidoo19d7b632018-10-30 10:49:50 -0400615 }
616 return status.Errorf(codes.Internal,
npujar1d86a522019-11-14 17:11:16 +0530617 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceID, groupMod.GetCommand())
khenaidoo19d7b632018-10-30 10:49:50 -0400618}
619
Manikkaraj kb1a10922019-07-29 12:10:34 -0400620// updateMeterTable updates the meter table of that logical device
Kent Hagerman2b216042020-04-03 18:28:56 -0400621func (agent *LogicalAgent) updateMeterTable(ctx context.Context, meterMod *ofp.OfpMeterMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000622 logger.Debug("updateMeterTable")
Manikkaraj kb1a10922019-07-29 12:10:34 -0400623 if meterMod == nil {
624 return nil
625 }
626 switch meterMod.GetCommand() {
627 case ofp.OfpMeterModCommand_OFPMC_ADD:
npujar467fe752020-01-16 20:17:45 +0530628 return agent.meterAdd(ctx, meterMod)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400629 case ofp.OfpMeterModCommand_OFPMC_DELETE:
npujar467fe752020-01-16 20:17:45 +0530630 return agent.meterDelete(ctx, meterMod)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400631 case ofp.OfpMeterModCommand_OFPMC_MODIFY:
npujar467fe752020-01-16 20:17:45 +0530632 return agent.meterModify(ctx, meterMod)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400633 }
634 return status.Errorf(codes.Internal,
npujar1d86a522019-11-14 17:11:16 +0530635 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceID, meterMod.GetCommand())
Manikkaraj kb1a10922019-07-29 12:10:34 -0400636
637}
638
Kent Hagerman2b216042020-04-03 18:28:56 -0400639func (agent *LogicalAgent) meterAdd(ctx context.Context, meterMod *ofp.OfpMeterMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000640 logger.Debugw("meterAdd", log.Fields{"metermod": *meterMod})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400641 if meterMod == nil {
642 return nil
643 }
khenaidoo442e7c72020-03-10 16:13:48 -0400644 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
645 return err
646 }
647 defer agent.requestQueue.RequestComplete()
Girish Kumarf56a4682020-03-20 20:07:46 +0000648 logger.Debug("Acquired logical device lock")
khenaidoo6e55d9e2019-12-12 18:26:26 -0500649 lDevice := agent.getLogicalDeviceWithoutLock()
Manikkaraj kb1a10922019-07-29 12:10:34 -0400650
651 var meters []*ofp.OfpMeterEntry
652 if lDevice.Meters != nil && lDevice.Meters.Items != nil {
653 meters = lDevice.Meters.Items
654 }
Girish Kumarf56a4682020-03-20 20:07:46 +0000655 logger.Debugw("Available meters", log.Fields{"meters": meters})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400656
657 for _, meter := range meters {
658 if meterMod.MeterId == meter.Config.MeterId {
Girish Kumarf56a4682020-03-20 20:07:46 +0000659 logger.Infow("Meter-already-exists", log.Fields{"meter": *meterMod})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400660 return nil
661 }
662 }
663
664 meterEntry := fu.MeterEntryFromMeterMod(meterMod)
665 meters = append(meters, meterEntry)
666 //Update model
npujar467fe752020-01-16 20:17:45 +0530667 if err := agent.updateLogicalDeviceMetersWithoutLock(ctx, &ofp.Meters{Items: meters}); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000668 logger.Errorw("db-meter-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400669 return err
670 }
Girish Kumarf56a4682020-03-20 20:07:46 +0000671 logger.Debugw("Meter-added-successfully", log.Fields{"Added-meter": meterEntry, "updated-meters": lDevice.Meters})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400672 return nil
673}
674
Kent Hagerman2b216042020-04-03 18:28:56 -0400675func (agent *LogicalAgent) meterDelete(ctx context.Context, meterMod *ofp.OfpMeterMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000676 logger.Debug("meterDelete", log.Fields{"meterMod": *meterMod})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400677 if meterMod == nil {
678 return nil
679 }
khenaidoo442e7c72020-03-10 16:13:48 -0400680 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
681 return err
682 }
683 defer agent.requestQueue.RequestComplete()
Manikkaraj kb1a10922019-07-29 12:10:34 -0400684
khenaidoo6e55d9e2019-12-12 18:26:26 -0500685 lDevice := agent.getLogicalDeviceWithoutLock()
Manikkaraj kb1a10922019-07-29 12:10:34 -0400686
687 var meters []*ofp.OfpMeterEntry
688 var flows []*ofp.OfpFlowStats
689 updatedFlows := make([]*ofp.OfpFlowStats, 0)
690 if lDevice.Meters != nil && lDevice.Meters.Items != nil {
691 meters = lDevice.Meters.Items
692 }
Manikkaraj kb1a10922019-07-29 12:10:34 -0400693
694 changedMeter := false
695 changedFow := false
Girish Kumarf56a4682020-03-20 20:07:46 +0000696 logger.Debugw("Available meters", log.Fields{"meters": meters})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400697 for index, meter := range meters {
698 if meterMod.MeterId == meter.Config.MeterId {
699 flows = lDevice.Flows.Items
npujar1d86a522019-11-14 17:11:16 +0530700 changedFow, updatedFlows = agent.getUpdatedFlowsAfterDeletebyMeterID(flows, meterMod.MeterId)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400701 meters = append(meters[:index], meters[index+1:]...)
Girish Kumarf56a4682020-03-20 20:07:46 +0000702 logger.Debugw("Meter has been deleted", log.Fields{"meter": meter, "index": index})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400703 changedMeter = true
704 break
705 }
706 }
707 if changedMeter {
708 //Update model
709 metersToUpdate := &ofp.Meters{}
710 if lDevice.Meters != nil {
711 metersToUpdate = &ofp.Meters{Items: meters}
712 }
npujar467fe752020-01-16 20:17:45 +0530713 if err := agent.updateLogicalDeviceMetersWithoutLock(ctx, metersToUpdate); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000714 logger.Errorw("db-meter-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400715 return err
716 }
Girish Kumarf56a4682020-03-20 20:07:46 +0000717 logger.Debug("Meter-deleted-from-DB-successfully", log.Fields{"updatedMeters": metersToUpdate, "no-of-meter": len(metersToUpdate.Items)})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400718
719 }
720 if changedFow {
721 //Update model
npujar467fe752020-01-16 20:17:45 +0530722 if err := agent.updateLogicalDeviceFlowsWithoutLock(ctx, &ofp.Flows{Items: updatedFlows}); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000723 logger.Errorw("db-flow-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400724 return err
725 }
Girish Kumarf56a4682020-03-20 20:07:46 +0000726 logger.Debug("Flows-associated-with-meter-deleted-from-DB-successfully",
Manikkaraj kb1a10922019-07-29 12:10:34 -0400727 log.Fields{"updated-no-of-flows": len(updatedFlows), "meter": meterMod.MeterId})
728 }
Girish Kumarf56a4682020-03-20 20:07:46 +0000729 logger.Debugw("meterDelete success", log.Fields{"meterID": meterMod.MeterId})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400730 return nil
731}
732
Kent Hagerman2b216042020-04-03 18:28:56 -0400733func (agent *LogicalAgent) meterModify(ctx context.Context, meterMod *ofp.OfpMeterMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000734 logger.Debug("meterModify")
Manikkaraj kb1a10922019-07-29 12:10:34 -0400735 if meterMod == nil {
736 return nil
737 }
khenaidoo442e7c72020-03-10 16:13:48 -0400738 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
739 return err
740 }
741 defer agent.requestQueue.RequestComplete()
Manikkaraj kb1a10922019-07-29 12:10:34 -0400742
khenaidoo6e55d9e2019-12-12 18:26:26 -0500743 lDevice := agent.getLogicalDeviceWithoutLock()
Manikkaraj kb1a10922019-07-29 12:10:34 -0400744
745 var meters []*ofp.OfpMeterEntry
746 if lDevice.Meters != nil && lDevice.Meters.Items != nil {
747 meters = lDevice.Meters.Items
748 }
749 changedMeter := false
750 for index, meter := range meters {
751 if meterMod.MeterId == meter.Config.MeterId {
752 newmeterEntry := fu.MeterEntryFromMeterMod(meterMod)
753 newmeterEntry.Stats.FlowCount = meter.Stats.FlowCount
754 meters[index] = newmeterEntry
755 changedMeter = true
Girish Kumarf56a4682020-03-20 20:07:46 +0000756 logger.Debugw("Found meter, replaced with new meter", log.Fields{"old meter": meter, "new meter": newmeterEntry})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400757 break
758 }
759 }
760 if changedMeter {
761 //Update model
762 metersToUpdate := &ofp.Meters{}
763 if lDevice.Meters != nil {
764 metersToUpdate = &ofp.Meters{Items: meters}
765 }
npujar467fe752020-01-16 20:17:45 +0530766 if err := agent.updateLogicalDeviceMetersWithoutLock(ctx, metersToUpdate); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000767 logger.Errorw("db-meter-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400768 return err
769 }
Girish Kumarf56a4682020-03-20 20:07:46 +0000770 logger.Debugw("meter-updated-in-DB-successfully", log.Fields{"updated_meters": meters})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400771 return nil
772 }
773
Girish Kumarf56a4682020-03-20 20:07:46 +0000774 logger.Errorw("Meter not found ", log.Fields{"meter": meterMod})
npujar1d86a522019-11-14 17:11:16 +0530775 return fmt.Errorf("no-logical-device-present:%d", meterMod.MeterId)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400776
777}
778
Kent Hagerman2b216042020-04-03 18:28:56 -0400779func (agent *LogicalAgent) getUpdatedFlowsAfterDeletebyMeterID(flows []*ofp.OfpFlowStats, meterID uint32) (bool, []*ofp.OfpFlowStats) {
Girish Kumarf56a4682020-03-20 20:07:46 +0000780 logger.Infow("Delete flows matching meter", log.Fields{"meter": meterID})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400781 changed := false
782 //updatedFlows := make([]*ofp.OfpFlowStats, 0)
783 for index := len(flows) - 1; index >= 0; index-- {
npujar1d86a522019-11-14 17:11:16 +0530784 if mID := fu.GetMeterIdFromFlow(flows[index]); mID != 0 && mID == meterID {
Girish Kumarf56a4682020-03-20 20:07:46 +0000785 logger.Debugw("Flow to be deleted", log.Fields{"flow": flows[index], "index": index})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400786 flows = append(flows[:index], flows[index+1:]...)
787 changed = true
788 }
789 }
790 return changed, flows
791}
792
Kent Hagerman2b216042020-04-03 18:28:56 -0400793func (agent *LogicalAgent) updateFlowCountOfMeterStats(modCommand *ofp.OfpFlowMod, meters []*ofp.OfpMeterEntry, flow *ofp.OfpFlowStats) bool {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400794
795 flowCommand := modCommand.GetCommand()
npujar1d86a522019-11-14 17:11:16 +0530796 meterID := fu.GetMeterIdFromFlow(flow)
Girish Kumarf56a4682020-03-20 20:07:46 +0000797 logger.Debugw("Meter-id-in-flow-mod", log.Fields{"meterId": meterID})
npujar1d86a522019-11-14 17:11:16 +0530798 if meterID == 0 {
Girish Kumarf56a4682020-03-20 20:07:46 +0000799 logger.Debugw("No meter present in the flow", log.Fields{"flow": *flow})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400800 return false
801 }
802 if meters == nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000803 logger.Debug("No meters present in logical device")
Manikkaraj kb1a10922019-07-29 12:10:34 -0400804 return false
805 }
806 changedMeter := false
807 for _, meter := range meters {
npujar1d86a522019-11-14 17:11:16 +0530808 if meterID == meter.Config.MeterId { // Found meter in Logicaldevice
Manikkaraj kb1a10922019-07-29 12:10:34 -0400809 if flowCommand == ofp.OfpFlowModCommand_OFPFC_ADD {
npujar1d86a522019-11-14 17:11:16 +0530810 meter.Stats.FlowCount++
Manikkaraj kb1a10922019-07-29 12:10:34 -0400811 changedMeter = true
812 } else if flowCommand == ofp.OfpFlowModCommand_OFPFC_DELETE_STRICT {
npujar1d86a522019-11-14 17:11:16 +0530813 meter.Stats.FlowCount--
Manikkaraj kb1a10922019-07-29 12:10:34 -0400814 changedMeter = true
815 }
Girish Kumarf56a4682020-03-20 20:07:46 +0000816 logger.Debugw("Found meter, updated meter flow stats", log.Fields{" meterId": meterID})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400817 break
818 }
819 }
820 return changedMeter
821}
822
khenaidoo19d7b632018-10-30 10:49:50 -0400823//flowAdd adds a flow to the flow table of that logical device
Kent Hagerman2b216042020-04-03 18:28:56 -0400824func (agent *LogicalAgent) flowAdd(ctx context.Context, mod *ofp.OfpFlowMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000825 logger.Debugw("flowAdd", log.Fields{"flow": mod})
khenaidoo19d7b632018-10-30 10:49:50 -0400826 if mod == nil {
827 return nil
828 }
khenaidoo442e7c72020-03-10 16:13:48 -0400829 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
830 return err
831 }
832 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -0400833
khenaidoo6e55d9e2019-12-12 18:26:26 -0500834 lDevice := agent.getLogicalDeviceWithoutLock()
khenaidoo19d7b632018-10-30 10:49:50 -0400835
836 var flows []*ofp.OfpFlowStats
Manikkaraj kb1a10922019-07-29 12:10:34 -0400837 var meters []*ofp.OfpMeterEntry
838 var flow *ofp.OfpFlowStats
Scott Bakerfdea1e32020-02-21 15:35:41 -0800839 var err error
Manikkaraj kb1a10922019-07-29 12:10:34 -0400840
khenaidoo19d7b632018-10-30 10:49:50 -0400841 if lDevice.Flows != nil && lDevice.Flows.Items != nil {
842 flows = lDevice.Flows.Items
843 }
844
Manikkaraj kb1a10922019-07-29 12:10:34 -0400845 if lDevice.Meters != nil && lDevice.Meters.Items != nil {
846 meters = lDevice.Meters.Items
847 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400848 updatedFlows := make([]*ofp.OfpFlowStats, 0)
khenaidoo19d7b632018-10-30 10:49:50 -0400849 changed := false
Manikkaraj kb1a10922019-07-29 12:10:34 -0400850 updated := false
khenaidoo19d7b632018-10-30 10:49:50 -0400851 checkOverlap := (mod.Flags & uint32(ofp.OfpFlowModFlags_OFPFF_CHECK_OVERLAP)) != 0
852 if checkOverlap {
853 if overlapped := fu.FindOverlappingFlows(flows, mod); len(overlapped) != 0 {
854 // TODO: should this error be notified other than being logged?
Girish Kumarf56a4682020-03-20 20:07:46 +0000855 logger.Warnw("overlapped-flows", log.Fields{"logicaldeviceId": agent.logicalDeviceID})
khenaidoo19d7b632018-10-30 10:49:50 -0400856 } else {
Matt Jeanneret518b5a42019-10-29 10:30:46 -0400857 // Add flow
Scott Bakerfdea1e32020-02-21 15:35:41 -0800858 flow, err = fu.FlowStatsEntryFromFlowModMessage(mod)
859 if err != nil {
860 return err
861 }
khenaidoo19d7b632018-10-30 10:49:50 -0400862 flows = append(flows, flow)
khenaidoo2c6a0992019-04-29 13:46:56 -0400863 updatedFlows = append(updatedFlows, flow)
khenaidoo19d7b632018-10-30 10:49:50 -0400864 changed = true
865 }
866 } else {
Scott Bakerfdea1e32020-02-21 15:35:41 -0800867 flow, err = fu.FlowStatsEntryFromFlowModMessage(mod)
868 if err != nil {
869 return err
870 }
khenaidoo19d7b632018-10-30 10:49:50 -0400871 idx := fu.FindFlows(flows, flow)
872 if idx >= 0 {
873 oldFlow := flows[idx]
874 if (mod.Flags & uint32(ofp.OfpFlowModFlags_OFPFF_RESET_COUNTS)) != 0 {
875 flow.ByteCount = oldFlow.ByteCount
876 flow.PacketCount = oldFlow.PacketCount
877 }
Mahir Gunyel5e98c782020-04-13 15:08:29 -0700878 if !proto.Equal(oldFlow, flow) {
Matt Jeanneret518b5a42019-10-29 10:30:46 -0400879 flows[idx] = flow
880 updatedFlows = append(updatedFlows, flow)
881 changed = true
882 updated = true
883 }
884 } else {
khenaidoo19d7b632018-10-30 10:49:50 -0400885 flows = append(flows, flow)
khenaidoo2c6a0992019-04-29 13:46:56 -0400886 updatedFlows = append(updatedFlows, flow)
887 changed = true
khenaidoo19d7b632018-10-30 10:49:50 -0400888 }
khenaidoo19d7b632018-10-30 10:49:50 -0400889 }
Girish Kumarf56a4682020-03-20 20:07:46 +0000890 logger.Debugw("flowAdd-changed", log.Fields{"changed": changed})
khenaidoo4c9e5592019-09-09 16:20:41 -0400891
khenaidoo19d7b632018-10-30 10:49:50 -0400892 if changed {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400893 var flowMetadata voltha.FlowMetadata
894 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 +0000895 logger.Error("Meter-referred-in-flows-not-present")
Manikkaraj kb1a10922019-07-29 12:10:34 -0400896 return err
897 }
khenaidoo820197c2020-02-13 16:35:33 -0500898 deviceRules, err := agent.flowDecomposer.DecomposeRules(ctx, agent, ofp.Flows{Items: updatedFlows}, *lDevice.FlowGroups)
899 if err != nil {
900 return err
901 }
Girish Kumarf56a4682020-03-20 20:07:46 +0000902 logger.Debugw("rules", log.Fields{"rules": deviceRules.String()})
khenaidoo0458db62019-06-20 08:50:36 -0400903
khenaidoo19d7b632018-10-30 10:49:50 -0400904 // Update model
npujar467fe752020-01-16 20:17:45 +0530905 if err := agent.updateLogicalDeviceFlowsWithoutLock(ctx, &ofp.Flows{Items: flows}); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000906 logger.Errorw("db-flow-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo19d7b632018-10-30 10:49:50 -0400907 return err
908 }
Matt Jeanneret518b5a42019-10-29 10:30:46 -0400909 if !updated {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400910 changedMeterStats := agent.updateFlowCountOfMeterStats(mod, meters, flow)
911 metersToUpdate := &ofp.Meters{}
912 if lDevice.Meters != nil {
913 metersToUpdate = &ofp.Meters{Items: meters}
914 }
915 if changedMeterStats {
916 //Update model
npujar467fe752020-01-16 20:17:45 +0530917 if err := agent.updateLogicalDeviceMetersWithoutLock(ctx, metersToUpdate); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000918 logger.Errorw("db-meter-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400919 return err
920 }
Girish Kumarf56a4682020-03-20 20:07:46 +0000921 logger.Debugw("meter-stats-updated-in-DB-successfully", log.Fields{"updated_meters": meters})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400922
923 }
924 }
khenaidoo442e7c72020-03-10 16:13:48 -0400925 // Send the flows to the devices
926 respChannels := agent.addFlowsAndGroupsToDevices(ctx, deviceRules, &flowMetadata)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400927
khenaidoo442e7c72020-03-10 16:13:48 -0400928 // Create the go routines to wait
929 go func() {
930 // Wait for completion
931 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChannels...); res != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000932 logger.Warnw("failure-to-add-flows", log.Fields{"errors": res, "logical-device-id": agent.logicalDeviceID})
khenaidoo442e7c72020-03-10 16:13:48 -0400933 // TODO : revert added flow
934 }
935 }()
khenaidoo19d7b632018-10-30 10:49:50 -0400936 }
khenaidoo19d7b632018-10-30 10:49:50 -0400937 return nil
938}
939
npujar1d86a522019-11-14 17:11:16 +0530940// GetMeterConfig returns meter config
Kent Hagerman2b216042020-04-03 18:28:56 -0400941func (agent *LogicalAgent) GetMeterConfig(flows []*ofp.OfpFlowStats, meters []*ofp.OfpMeterEntry, metadata *voltha.FlowMetadata) error {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400942 m := make(map[uint32]bool)
943 for _, flow := range flows {
npujar1d86a522019-11-14 17:11:16 +0530944 if flowMeterID := fu.GetMeterIdFromFlow(flow); flowMeterID != 0 && !m[flowMeterID] {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400945 foundMeter := false
946 // Meter is present in the flow , Get from logical device
947 for _, meter := range meters {
948 if flowMeterID == meter.Config.MeterId {
949 metadata.Meters = append(metadata.Meters, meter.Config)
Girish Kumarf56a4682020-03-20 20:07:46 +0000950 logger.Debugw("Found meter in logical device",
Manikkaraj kb1a10922019-07-29 12:10:34 -0400951 log.Fields{"meterID": flowMeterID, "meter-band": meter.Config})
952 m[flowMeterID] = true
953 foundMeter = true
954 break
955 }
956 }
957 if !foundMeter {
Girish Kumarf56a4682020-03-20 20:07:46 +0000958 logger.Errorw("Meter-referred-by-flow-is-not-found-in-logicaldevice",
npujar1d86a522019-11-14 17:11:16 +0530959 log.Fields{"meterID": flowMeterID, "Available-meters": meters, "flow": *flow})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400960 return errors.New("Meter-referred-by-flow-is-not-found-in-logicaldevice")
961 }
962 }
963 }
Girish Kumarf56a4682020-03-20 20:07:46 +0000964 logger.Debugw("meter-bands-for-flows", log.Fields{"flows": len(flows), "metadata": metadata})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400965 return nil
966
967}
968
khenaidoo19d7b632018-10-30 10:49:50 -0400969//flowDelete deletes a flow from the flow table of that logical device
Kent Hagerman2b216042020-04-03 18:28:56 -0400970func (agent *LogicalAgent) flowDelete(ctx context.Context, mod *ofp.OfpFlowMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000971 logger.Debug("flowDelete")
khenaidoo19d7b632018-10-30 10:49:50 -0400972 if mod == nil {
973 return nil
974 }
khenaidoo442e7c72020-03-10 16:13:48 -0400975 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
976 return err
977 }
978 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -0400979
khenaidoo6e55d9e2019-12-12 18:26:26 -0500980 lDevice := agent.getLogicalDeviceWithoutLock()
khenaidoo19d7b632018-10-30 10:49:50 -0400981
Manikkaraj kb1a10922019-07-29 12:10:34 -0400982 var meters []*ofp.OfpMeterEntry
983 var flows []*ofp.OfpFlowStats
Esin Karamanfc3b1af2020-01-29 16:52:00 +0000984 var flowGroups []*ofp.OfpGroupEntry
Manikkaraj kb1a10922019-07-29 12:10:34 -0400985
986 if lDevice.Flows != nil && lDevice.Flows.Items != nil {
987 flows = lDevice.Flows.Items
988 }
989
990 if lDevice.Meters != nil && lDevice.Meters.Items != nil {
991 meters = lDevice.Meters.Items
992 }
Esin Karamanfc3b1af2020-01-29 16:52:00 +0000993
994 if lDevice.FlowGroups != nil && lDevice.FlowGroups.Items != nil {
995 flowGroups = lDevice.FlowGroups.Items
996 }
997
khenaidoo19d7b632018-10-30 10:49:50 -0400998 //build a list of what to keep vs what to delete
999 toKeep := make([]*ofp.OfpFlowStats, 0)
khenaidoo0458db62019-06-20 08:50:36 -04001000 toDelete := make([]*ofp.OfpFlowStats, 0)
khenaidoo19d7b632018-10-30 10:49:50 -04001001 for _, f := range flows {
khenaidoo0458db62019-06-20 08:50:36 -04001002 // Check whether the flow and the flowmod matches
Scott Bakerfdea1e32020-02-21 15:35:41 -08001003 fs, err := fu.FlowStatsEntryFromFlowModMessage(mod)
1004 if err != nil {
1005 return err
1006 }
1007 if fu.FlowMatch(f, fs) {
khenaidoo0458db62019-06-20 08:50:36 -04001008 toDelete = append(toDelete, f)
1009 continue
1010 }
1011 // Check wild card match
khenaidoo19d7b632018-10-30 10:49:50 -04001012 if !fu.FlowMatchesMod(f, mod) {
1013 toKeep = append(toKeep, f)
khenaidoo0458db62019-06-20 08:50:36 -04001014 } else {
1015 toDelete = append(toDelete, f)
khenaidoo19d7b632018-10-30 10:49:50 -04001016 }
1017 }
1018
Girish Kumarf56a4682020-03-20 20:07:46 +00001019 logger.Debugw("flowDelete", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "toKeep": len(toKeep), "toDelete": toDelete})
khenaidoo0458db62019-06-20 08:50:36 -04001020
khenaidoo19d7b632018-10-30 10:49:50 -04001021 //Update flows
khenaidoo0458db62019-06-20 08:50:36 -04001022 if len(toDelete) > 0 {
Manikkaraj kb1a10922019-07-29 12:10:34 -04001023 var flowMetadata voltha.FlowMetadata
1024 if err := agent.GetMeterConfig(toDelete, meters, &flowMetadata); err != nil { // This should never happen
Girish Kumarf56a4682020-03-20 20:07:46 +00001025 logger.Error("Meter-referred-in-flows-not-present")
Manikkaraj kb1a10922019-07-29 12:10:34 -04001026 return errors.New("Meter-referred-in-flows-not-present")
1027 }
khenaidoo787224a2020-04-16 18:08:47 -04001028
1029 var respChnls []coreutils.Response
1030 var partialRoute bool
khenaidoo820197c2020-02-13 16:35:33 -05001031 deviceRules, err := agent.flowDecomposer.DecomposeRules(ctx, agent, ofp.Flows{Items: toDelete}, ofp.FlowGroups{Items: flowGroups})
1032 if err != nil {
khenaidoo787224a2020-04-16 18:08:47 -04001033 // A no route error means no route exists between the ports specified in the flow. This can happen when the
1034 // child device is deleted and a request to delete flows from the parent device is received
1035 if !errors.Is(err, route.ErrNoRoute) {
1036 logger.Errorw("unexpected-error-received", log.Fields{"flows-to-delete": toDelete, "error": err})
1037 return err
1038 }
1039 partialRoute = true
khenaidoo820197c2020-02-13 16:35:33 -05001040 }
khenaidoo0458db62019-06-20 08:50:36 -04001041
khenaidoo787224a2020-04-16 18:08:47 -04001042 // Update the dB
npujar467fe752020-01-16 20:17:45 +05301043 if err := agent.updateLogicalDeviceFlowsWithoutLock(ctx, &ofp.Flows{Items: toKeep}); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001044 logger.Errorw("cannot-update-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo19d7b632018-10-30 10:49:50 -04001045 return err
1046 }
khenaidoo442e7c72020-03-10 16:13:48 -04001047
1048 // Update the devices
khenaidoo787224a2020-04-16 18:08:47 -04001049 if partialRoute {
1050 respChnls = agent.deleteFlowsFromParentDevice(ctx, ofp.Flows{Items: toDelete}, &flowMetadata)
1051 } else {
1052 respChnls = agent.deleteFlowsAndGroupsFromDevices(ctx, deviceRules, &flowMetadata)
1053 }
khenaidoo442e7c72020-03-10 16:13:48 -04001054
1055 // Wait for the responses
1056 go func() {
1057 // Wait for completion
1058 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001059 logger.Errorw("failure-updating-device-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "errors": res})
khenaidoo442e7c72020-03-10 16:13:48 -04001060 // TODO: Revert the flow deletion
1061 }
1062 }()
khenaidoo19d7b632018-10-30 10:49:50 -04001063 }
1064
1065 //TODO: send announcement on delete
1066 return nil
1067}
1068
Kent Hagerman2b216042020-04-03 18:28:56 -04001069func (agent *LogicalAgent) addFlowsAndGroupsToDevices(ctx context.Context, deviceRules *fu.DeviceRules, flowMetadata *voltha.FlowMetadata) []coreutils.Response {
Girish Kumarf56a4682020-03-20 20:07:46 +00001070 logger.Debugw("send-add-flows-to-device-manager", log.Fields{"logicalDeviceID": agent.logicalDeviceID, "deviceRules": deviceRules, "flowMetadata": flowMetadata})
khenaidoo19d7b632018-10-30 10:49:50 -04001071
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001072 responses := make([]coreutils.Response, 0)
npujar1d86a522019-11-14 17:11:16 +05301073 for deviceID, value := range deviceRules.GetRules() {
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001074 response := coreutils.NewResponse()
1075 responses = append(responses, response)
1076 go func(deviceId string, value *fu.FlowsAndGroups) {
khenaidoo442e7c72020-03-10 16:13:48 -04001077 ctx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
1078 defer cancel()
npujar467fe752020-01-16 20:17:45 +05301079 if err := agent.deviceMgr.addFlowsAndGroups(ctx, deviceId, value.ListFlows(), value.ListGroups(), flowMetadata); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001080 logger.Errorw("flow-add-failed", log.Fields{"deviceID": deviceId, "error": err})
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001081 response.Error(status.Errorf(codes.Internal, "flow-add-failed: %s", deviceId))
khenaidoo0458db62019-06-20 08:50:36 -04001082 }
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001083 response.Done()
npujar1d86a522019-11-14 17:11:16 +05301084 }(deviceID, value)
khenaidoo19d7b632018-10-30 10:49:50 -04001085 }
khenaidoo442e7c72020-03-10 16:13:48 -04001086 // Return responses (an array of channels) for the caller to wait for a response from the far end.
1087 return responses
khenaidoo0458db62019-06-20 08:50:36 -04001088}
khenaidoo19d7b632018-10-30 10:49:50 -04001089
Kent Hagerman2b216042020-04-03 18:28:56 -04001090func (agent *LogicalAgent) deleteFlowsAndGroupsFromDevices(ctx context.Context, deviceRules *fu.DeviceRules, flowMetadata *voltha.FlowMetadata) []coreutils.Response {
Girish Kumarf56a4682020-03-20 20:07:46 +00001091 logger.Debugw("send-delete-flows-to-device-manager", log.Fields{"logicalDeviceID": agent.logicalDeviceID})
khenaidoo0458db62019-06-20 08:50:36 -04001092
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001093 responses := make([]coreutils.Response, 0)
npujar1d86a522019-11-14 17:11:16 +05301094 for deviceID, value := range deviceRules.GetRules() {
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001095 response := coreutils.NewResponse()
1096 responses = append(responses, response)
1097 go func(deviceId string, value *fu.FlowsAndGroups) {
khenaidoo442e7c72020-03-10 16:13:48 -04001098 ctx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
1099 defer cancel()
npujar467fe752020-01-16 20:17:45 +05301100 if err := agent.deviceMgr.deleteFlowsAndGroups(ctx, deviceId, value.ListFlows(), value.ListGroups(), flowMetadata); err != nil {
khenaidoo787224a2020-04-16 18:08:47 -04001101 logger.Errorw("flow-delete-failed", log.Fields{"deviceID": deviceId, "error": err})
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001102 response.Error(status.Errorf(codes.Internal, "flow-delete-failed: %s", deviceId))
khenaidoo0458db62019-06-20 08:50:36 -04001103 }
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001104 response.Done()
npujar1d86a522019-11-14 17:11:16 +05301105 }(deviceID, value)
khenaidoo0458db62019-06-20 08:50:36 -04001106 }
khenaidoo442e7c72020-03-10 16:13:48 -04001107 return responses
khenaidoo0458db62019-06-20 08:50:36 -04001108}
1109
Kent Hagerman2b216042020-04-03 18:28:56 -04001110func (agent *LogicalAgent) updateFlowsAndGroupsOfDevice(ctx context.Context, deviceRules *fu.DeviceRules, flowMetadata *voltha.FlowMetadata) []coreutils.Response {
Girish Kumarf56a4682020-03-20 20:07:46 +00001111 logger.Debugw("send-update-flows-to-device-manager", log.Fields{"logicalDeviceID": agent.logicalDeviceID})
khenaidoo0458db62019-06-20 08:50:36 -04001112
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001113 responses := make([]coreutils.Response, 0)
npujar1d86a522019-11-14 17:11:16 +05301114 for deviceID, value := range deviceRules.GetRules() {
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001115 response := coreutils.NewResponse()
1116 responses = append(responses, response)
1117 go func(deviceId string, value *fu.FlowsAndGroups) {
khenaidoo442e7c72020-03-10 16:13:48 -04001118 ctx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
1119 defer cancel()
npujar467fe752020-01-16 20:17:45 +05301120 if err := agent.deviceMgr.updateFlowsAndGroups(ctx, deviceId, value.ListFlows(), value.ListGroups(), flowMetadata); err != nil {
khenaidoo787224a2020-04-16 18:08:47 -04001121 logger.Errorw("flow-update-failed", log.Fields{"deviceID": deviceId, "error": err})
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001122 response.Error(status.Errorf(codes.Internal, "flow-update-failed: %s", deviceId))
khenaidoo0458db62019-06-20 08:50:36 -04001123 }
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001124 response.Done()
npujar1d86a522019-11-14 17:11:16 +05301125 }(deviceID, value)
khenaidoo0458db62019-06-20 08:50:36 -04001126 }
khenaidoo442e7c72020-03-10 16:13:48 -04001127 return responses
khenaidoo19d7b632018-10-30 10:49:50 -04001128}
1129
khenaidoo787224a2020-04-16 18:08:47 -04001130// getUNILogicalPortNo returns the UNI logical port number specified in the flow
1131func (agent *LogicalAgent) getUNILogicalPortNo(flow *ofp.OfpFlowStats) (uint32, error) {
1132 var uniPort uint32
1133 inPortNo := fu.GetInPort(flow)
1134 outPortNo := fu.GetOutPort(flow)
1135 if agent.isNNIPort(inPortNo) {
1136 uniPort = outPortNo
1137 } else if agent.isNNIPort(outPortNo) {
1138 uniPort = inPortNo
1139 }
1140 if uniPort != 0 {
1141 return uniPort, nil
1142 }
1143 return 0, status.Errorf(codes.NotFound, "no-uni-port: %v", flow)
1144}
1145
1146func (agent *LogicalAgent) deleteFlowsFromParentDevice(ctx context.Context, flows ofp.Flows, metadata *voltha.FlowMetadata) []coreutils.Response {
1147 logger.Debugw("deleting-flows-from-parent-device", log.Fields{"logical-device-id": agent.logicalDeviceID, "flows": flows})
1148 responses := make([]coreutils.Response, 0)
1149 for _, flow := range flows.Items {
1150 response := coreutils.NewResponse()
1151 responses = append(responses, response)
1152 uniPort, err := agent.getUNILogicalPortNo(flow)
1153 if err != nil {
1154 logger.Error("no-uni-port-in-flow", log.Fields{"deviceID": agent.rootDeviceID, "flow": flow, "error": err})
1155 response.Error(err)
1156 response.Done()
1157 continue
1158 }
1159 logger.Debugw("uni-port", log.Fields{"flows": flows, "uni-port": uniPort})
1160 go func(uniPort uint32, metadata *voltha.FlowMetadata) {
1161 ctx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
1162 defer cancel()
1163 if err := agent.deviceMgr.deleteParentFlows(ctx, agent.rootDeviceID, uniPort, metadata); err != nil {
1164 logger.Error("flow-delete-failed", log.Fields{"device-id": agent.rootDeviceID, "error": err})
1165 response.Error(status.Errorf(codes.Internal, "flow-delete-failed: %s %v", agent.rootDeviceID, err))
1166 }
1167 response.Done()
1168 }(uniPort, metadata)
1169 }
1170 return responses
1171}
1172
khenaidoo19d7b632018-10-30 10:49:50 -04001173//flowDeleteStrict deletes a flow from the flow table of that logical device
Kent Hagerman2b216042020-04-03 18:28:56 -04001174func (agent *LogicalAgent) flowDeleteStrict(ctx context.Context, mod *ofp.OfpFlowMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +00001175 logger.Debug("flowDeleteStrict")
khenaidoo19d7b632018-10-30 10:49:50 -04001176 if mod == nil {
1177 return nil
1178 }
khenaidoo442e7c72020-03-10 16:13:48 -04001179 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1180 return err
1181 }
1182 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -04001183
khenaidoo6e55d9e2019-12-12 18:26:26 -05001184 lDevice := agent.getLogicalDeviceWithoutLock()
1185
Manikkaraj kb1a10922019-07-29 12:10:34 -04001186 var meters []*ofp.OfpMeterEntry
1187 var flows []*ofp.OfpFlowStats
Esin Karamanfc3b1af2020-01-29 16:52:00 +00001188 var flowGroups []*ofp.OfpGroupEntry
Manikkaraj kb1a10922019-07-29 12:10:34 -04001189 if lDevice.Meters != nil && lDevice.Meters.Items != nil {
1190 meters = lDevice.Meters.Items
1191 }
1192 if lDevice.Flows != nil && lDevice.Flows.Items != nil {
1193 flows = lDevice.Flows.Items
1194 }
Esin Karamanfc3b1af2020-01-29 16:52:00 +00001195 if lDevice.FlowGroups != nil && lDevice.FlowGroups.Items != nil {
1196 flowGroups = lDevice.FlowGroups.Items
1197 }
Manikkaraj kb1a10922019-07-29 12:10:34 -04001198
1199 changedFlow := false
1200 changedMeter := false
Scott Bakerfdea1e32020-02-21 15:35:41 -08001201 flow, err := fu.FlowStatsEntryFromFlowModMessage(mod)
1202 if err != nil {
1203 return err
1204 }
Manikkaraj kb1a10922019-07-29 12:10:34 -04001205 flowsToDelete := make([]*ofp.OfpFlowStats, 0)
khenaidoo19d7b632018-10-30 10:49:50 -04001206 idx := fu.FindFlows(flows, flow)
1207 if idx >= 0 {
Gamze Abaka6e4ac162019-10-21 11:10:10 +00001208 changedMeter = agent.updateFlowCountOfMeterStats(mod, meters, flows[idx])
Manikkaraj kb1a10922019-07-29 12:10:34 -04001209 flowsToDelete = append(flowsToDelete, flows[idx])
khenaidoo19d7b632018-10-30 10:49:50 -04001210 flows = append(flows[:idx], flows[idx+1:]...)
Manikkaraj kb1a10922019-07-29 12:10:34 -04001211 changedFlow = true
khenaidoo19d7b632018-10-30 10:49:50 -04001212 } else {
npujar1d86a522019-11-14 17:11:16 +05301213 return fmt.Errorf("Cannot delete flow - %s", flow)
khenaidoo19d7b632018-10-30 10:49:50 -04001214 }
Manikkaraj kb1a10922019-07-29 12:10:34 -04001215 if changedMeter {
1216 //Update model
1217 metersToUpdate := &ofp.Meters{}
1218 if lDevice.Meters != nil {
1219 metersToUpdate = &ofp.Meters{Items: meters}
1220 }
npujar467fe752020-01-16 20:17:45 +05301221 if err := agent.updateLogicalDeviceMetersWithoutLock(ctx, metersToUpdate); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001222 logger.Errorw("db-meter-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
Manikkaraj kb1a10922019-07-29 12:10:34 -04001223 return err
1224 }
khenaidoo19d7b632018-10-30 10:49:50 -04001225
Manikkaraj kb1a10922019-07-29 12:10:34 -04001226 }
1227 if changedFlow {
1228 var flowMetadata voltha.FlowMetadata
1229 if err := agent.GetMeterConfig(flowsToDelete, meters, &flowMetadata); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001230 logger.Error("meter-referred-in-flows-not-present")
Manikkaraj kb1a10922019-07-29 12:10:34 -04001231 return err
1232 }
khenaidoo787224a2020-04-16 18:08:47 -04001233 var respChnls []coreutils.Response
1234 var partialRoute bool
khenaidoo820197c2020-02-13 16:35:33 -05001235 deviceRules, err := agent.flowDecomposer.DecomposeRules(ctx, agent, ofp.Flows{Items: flowsToDelete}, ofp.FlowGroups{Items: flowGroups})
1236 if err != nil {
khenaidoo787224a2020-04-16 18:08:47 -04001237 // A no route error means no route exists between the ports specified in the flow. This can happen when the
1238 // child device is deleted and a request to delete flows from the parent device is received
1239 if !errors.Is(err, route.ErrNoRoute) {
1240 logger.Errorw("unexpected-error-received", log.Fields{"flows-to-delete": flowsToDelete, "error": err})
1241 return err
1242 }
1243 partialRoute = true
khenaidoo820197c2020-02-13 16:35:33 -05001244 }
khenaidoo0458db62019-06-20 08:50:36 -04001245
khenaidoo787224a2020-04-16 18:08:47 -04001246 // Update the dB
npujar467fe752020-01-16 20:17:45 +05301247 if err := agent.updateLogicalDeviceFlowsWithoutLock(ctx, &ofp.Flows{Items: flows}); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001248 logger.Errorw("cannot-update-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo19d7b632018-10-30 10:49:50 -04001249 return err
1250 }
khenaidoo442e7c72020-03-10 16:13:48 -04001251
1252 // Update the devices
khenaidoo787224a2020-04-16 18:08:47 -04001253 if partialRoute {
1254 respChnls = agent.deleteFlowsFromParentDevice(ctx, ofp.Flows{Items: flowsToDelete}, &flowMetadata)
1255 } else {
1256 respChnls = agent.deleteFlowsAndGroupsFromDevices(ctx, deviceRules, &flowMetadata)
1257 }
khenaidoo442e7c72020-03-10 16:13:48 -04001258
1259 // Wait for completion
1260 go func() {
1261 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001262 logger.Warnw("failure-deleting-device-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "errors": res})
khenaidoo442e7c72020-03-10 16:13:48 -04001263 //TODO: Revert flow changes
1264 }
1265 }()
khenaidoo19d7b632018-10-30 10:49:50 -04001266 }
khenaidoo19d7b632018-10-30 10:49:50 -04001267 return nil
1268}
1269
1270//flowModify modifies a flow from the flow table of that logical device
Kent Hagerman2b216042020-04-03 18:28:56 -04001271func (agent *LogicalAgent) flowModify(mod *ofp.OfpFlowMod) error {
khenaidoo19d7b632018-10-30 10:49:50 -04001272 return errors.New("flowModify not implemented")
1273}
1274
1275//flowModifyStrict deletes a flow from the flow table of that logical device
Kent Hagerman2b216042020-04-03 18:28:56 -04001276func (agent *LogicalAgent) flowModifyStrict(mod *ofp.OfpFlowMod) error {
khenaidoo19d7b632018-10-30 10:49:50 -04001277 return errors.New("flowModifyStrict not implemented")
1278}
1279
Kent Hagerman2b216042020-04-03 18:28:56 -04001280func (agent *LogicalAgent) groupAdd(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +00001281 logger.Debug("groupAdd")
khenaidoo19d7b632018-10-30 10:49:50 -04001282 if groupMod == nil {
1283 return nil
1284 }
khenaidoo442e7c72020-03-10 16:13:48 -04001285 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1286 return err
1287 }
1288 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -04001289
khenaidoo6e55d9e2019-12-12 18:26:26 -05001290 lDevice := agent.getLogicalDeviceWithoutLock()
1291
khenaidoo19d7b632018-10-30 10:49:50 -04001292 groups := lDevice.FlowGroups.Items
khenaidoo19d7b632018-10-30 10:49:50 -04001293 if fu.FindGroup(groups, groupMod.GroupId) == -1 {
khenaidoo68c930b2019-05-13 11:46:51 -04001294 groups = append(groups, fu.GroupEntryFromGroupMod(groupMod))
khenaidoo0458db62019-06-20 08:50:36 -04001295
Esin Karaman2ea59212019-12-06 11:41:58 +00001296 deviceRules := fu.NewDeviceRules()
1297 deviceRules.CreateEntryIfNotExist(agent.rootDeviceID)
1298 fg := fu.NewFlowsAndGroups()
1299 fg.AddGroup(fu.GroupEntryFromGroupMod(groupMod))
1300 deviceRules.AddFlowsAndGroup(agent.rootDeviceID, fg)
1301
Girish Kumarf56a4682020-03-20 20:07:46 +00001302 logger.Debugw("rules", log.Fields{"rules for group-add": deviceRules.String()})
khenaidoo0458db62019-06-20 08:50:36 -04001303
npujar467fe752020-01-16 20:17:45 +05301304 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(ctx, &ofp.FlowGroups{Items: groups}); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001305 logger.Errorw("cannot-update-group", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo19d7b632018-10-30 10:49:50 -04001306 return err
1307 }
khenaidoo442e7c72020-03-10 16:13:48 -04001308
1309 // Update the devices
1310 respChnls := agent.addFlowsAndGroupsToDevices(ctx, deviceRules, &voltha.FlowMetadata{})
1311
1312 // Wait for completion
1313 go func() {
1314 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001315 logger.Warnw("failure-updating-device-flows-groups", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "errors": res})
khenaidoo442e7c72020-03-10 16:13:48 -04001316 //TODO: Revert flow changes
1317 }
1318 }()
1319 return nil
khenaidoo19d7b632018-10-30 10:49:50 -04001320 }
khenaidoo442e7c72020-03-10 16:13:48 -04001321 return fmt.Errorf("Groups %d already present", groupMod.GroupId)
khenaidoo19d7b632018-10-30 10:49:50 -04001322}
1323
Kent Hagerman2b216042020-04-03 18:28:56 -04001324func (agent *LogicalAgent) groupDelete(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +00001325 logger.Debug("groupDelete")
khenaidoo19d7b632018-10-30 10:49:50 -04001326 if groupMod == nil {
1327 return nil
1328 }
khenaidoo442e7c72020-03-10 16:13:48 -04001329 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1330 return err
1331 }
1332 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -04001333
khenaidoo6e55d9e2019-12-12 18:26:26 -05001334 lDevice := agent.getLogicalDeviceWithoutLock()
khenaidoo19d7b632018-10-30 10:49:50 -04001335 groups := lDevice.FlowGroups.Items
1336 flows := lDevice.Flows.Items
npujar1d86a522019-11-14 17:11:16 +05301337 var groupsChanged bool
khenaidoo19d7b632018-10-30 10:49:50 -04001338 flowsChanged := false
npujar1d86a522019-11-14 17:11:16 +05301339 groupID := groupMod.GroupId
1340 if groupID == uint32(ofp.OfpGroup_OFPG_ALL) {
khenaidoo19d7b632018-10-30 10:49:50 -04001341 //TODO we must delete all flows that point to this group and
1342 //signal controller as requested by flow's flag
1343 groups = []*ofp.OfpGroupEntry{}
1344 groupsChanged = true
1345 } else {
npujar1d86a522019-11-14 17:11:16 +05301346 idx := fu.FindGroup(groups, groupID)
1347 if idx == -1 {
khenaidoo19d7b632018-10-30 10:49:50 -04001348 return nil // Valid case
khenaidoo19d7b632018-10-30 10:49:50 -04001349 }
npujar1d86a522019-11-14 17:11:16 +05301350 flowsChanged, flows = fu.FlowsDeleteByGroupId(flows, groupID)
1351 groups = append(groups[:idx], groups[idx+1:]...)
1352 groupsChanged = true
khenaidoo19d7b632018-10-30 10:49:50 -04001353 }
khenaidoo0458db62019-06-20 08:50:36 -04001354 if flowsChanged || groupsChanged {
khenaidoo820197c2020-02-13 16:35:33 -05001355 deviceRules, err := agent.flowDecomposer.DecomposeRules(ctx, agent, ofp.Flows{Items: flows}, ofp.FlowGroups{Items: groups})
1356 if err != nil {
1357 return err
1358 }
Girish Kumarf56a4682020-03-20 20:07:46 +00001359 logger.Debugw("rules", log.Fields{"rules": deviceRules.String()})
khenaidoo0458db62019-06-20 08:50:36 -04001360
khenaidoo442e7c72020-03-10 16:13:48 -04001361 if groupsChanged {
1362 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(ctx, &ofp.FlowGroups{Items: groups}); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001363 logger.Errorw("cannot-update-group", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo442e7c72020-03-10 16:13:48 -04001364 return err
1365 }
khenaidoo0458db62019-06-20 08:50:36 -04001366 }
khenaidoo442e7c72020-03-10 16:13:48 -04001367 if flowsChanged {
1368 if err := agent.updateLogicalDeviceFlowsWithoutLock(ctx, &ofp.Flows{Items: flows}); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001369 logger.Errorw("cannot-update-flow", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo442e7c72020-03-10 16:13:48 -04001370 return err
1371 }
1372 }
khenaidoo0458db62019-06-20 08:50:36 -04001373
khenaidoo442e7c72020-03-10 16:13:48 -04001374 // Update the devices
1375 respChnls := agent.updateFlowsAndGroupsOfDevice(ctx, deviceRules, nil)
1376
1377 // Wait for completion
1378 go func() {
1379 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001380 logger.Warnw("failure-updating-device-flows-groups", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "errors": res})
khenaidoo442e7c72020-03-10 16:13:48 -04001381 //TODO: Revert flow changes
1382 }
1383 }()
khenaidoo43c82122018-11-22 18:38:28 -05001384 }
khenaidoo19d7b632018-10-30 10:49:50 -04001385 return nil
1386}
1387
Kent Hagerman2b216042020-04-03 18:28:56 -04001388func (agent *LogicalAgent) groupModify(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +00001389 logger.Debug("groupModify")
khenaidoo19d7b632018-10-30 10:49:50 -04001390 if groupMod == nil {
1391 return nil
1392 }
khenaidoo442e7c72020-03-10 16:13:48 -04001393 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1394 return err
1395 }
1396 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -04001397
khenaidoo6e55d9e2019-12-12 18:26:26 -05001398 lDevice := agent.getLogicalDeviceWithoutLock()
khenaidoo19d7b632018-10-30 10:49:50 -04001399 groups := lDevice.FlowGroups.Items
npujar1d86a522019-11-14 17:11:16 +05301400 var groupsChanged bool
1401 groupID := groupMod.GroupId
1402 idx := fu.FindGroup(groups, groupID)
1403 if idx == -1 {
1404 return fmt.Errorf("group-absent:%d", groupID)
khenaidoo19d7b632018-10-30 10:49:50 -04001405 }
npujar1d86a522019-11-14 17:11:16 +05301406 //replace existing group entry with new group definition
1407 groupEntry := fu.GroupEntryFromGroupMod(groupMod)
1408 groups[idx] = groupEntry
1409 groupsChanged = true
khenaidoo19d7b632018-10-30 10:49:50 -04001410 if groupsChanged {
Esin Karaman2ea59212019-12-06 11:41:58 +00001411 deviceRules := fu.NewDeviceRules()
1412 deviceRules.CreateEntryIfNotExist(agent.rootDeviceID)
1413 fg := fu.NewFlowsAndGroups()
1414 fg.AddGroup(fu.GroupEntryFromGroupMod(groupMod))
1415 deviceRules.AddFlowsAndGroup(agent.rootDeviceID, fg)
khenaidoo0458db62019-06-20 08:50:36 -04001416
Girish Kumarf56a4682020-03-20 20:07:46 +00001417 logger.Debugw("rules", log.Fields{"rules for group-modify": deviceRules.String()})
khenaidoo0458db62019-06-20 08:50:36 -04001418
npujar467fe752020-01-16 20:17:45 +05301419 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(ctx, &ofp.FlowGroups{Items: groups}); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001420 logger.Errorw("Cannot-update-logical-group", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo19d7b632018-10-30 10:49:50 -04001421 return err
1422 }
khenaidoo442e7c72020-03-10 16:13:48 -04001423
1424 // Update the devices
1425 respChnls := agent.updateFlowsAndGroupsOfDevice(ctx, deviceRules, &voltha.FlowMetadata{})
1426
1427 // Wait for completion
1428 go func() {
1429 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001430 logger.Warnw("failure-updating-device-flows-groups", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "errors": res})
khenaidoo442e7c72020-03-10 16:13:48 -04001431 //TODO: Revert flow changes
1432 }
1433 }()
khenaidoo19d7b632018-10-30 10:49:50 -04001434 }
1435 return nil
1436}
1437
1438// deleteLogicalPort removes the logical port
Kent Hagerman2b216042020-04-03 18:28:56 -04001439func (agent *LogicalAgent) deleteLogicalPort(ctx context.Context, lPort *voltha.LogicalPort) error {
khenaidoo442e7c72020-03-10 16:13:48 -04001440 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1441 return err
1442 }
1443 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -04001444
khenaidoo6e55d9e2019-12-12 18:26:26 -05001445 logicalDevice := agent.getLogicalDeviceWithoutLock()
1446
khenaidoo92e62c52018-10-03 14:02:54 -04001447 index := -1
khenaidoo6e55d9e2019-12-12 18:26:26 -05001448 for i, logicalPort := range logicalDevice.Ports {
khenaidoo19d7b632018-10-30 10:49:50 -04001449 if logicalPort.Id == lPort.Id {
khenaidoo92e62c52018-10-03 14:02:54 -04001450 index = i
1451 break
1452 }
1453 }
1454 if index >= 0 {
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001455 clonedPorts := clonePorts(logicalDevice.Ports)
1456 if index < len(clonedPorts)-1 {
1457 copy(clonedPorts[index:], clonedPorts[index+1:])
1458 }
1459 clonedPorts[len(clonedPorts)-1] = nil
1460 clonedPorts = clonedPorts[:len(clonedPorts)-1]
Girish Kumarf56a4682020-03-20 20:07:46 +00001461 logger.Debugw("logical-port-deleted", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001462 if err := agent.updateLogicalDevicePortsWithoutLock(ctx, logicalDevice, clonedPorts); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001463 logger.Errorw("logical-device-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo0a822f92019-05-08 15:15:57 -04001464 return err
1465 }
khenaidoo820197c2020-02-13 16:35:33 -05001466
1467 // Remove the logical port from cache
1468 agent.deleteLogicalPortsFromMap([]uint32{lPort.DevicePortNo})
1469
1470 // Reset the logical device routes
1471 go func() {
1472 if err := agent.buildRoutes(context.Background()); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001473 logger.Warnw("device-routes-not-ready", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "error": err})
khenaidoo820197c2020-02-13 16:35:33 -05001474 }
1475 }()
khenaidoo92e62c52018-10-03 14:02:54 -04001476 }
1477 return nil
khenaidoob9203542018-09-17 22:56:37 -04001478}
1479
khenaidoo0a822f92019-05-08 15:15:57 -04001480// deleteLogicalPorts removes the logical ports associated with that deviceId
Kent Hagerman2b216042020-04-03 18:28:56 -04001481func (agent *LogicalAgent) deleteLogicalPorts(ctx context.Context, deviceID string) error {
Andrea Campanella09400bd2020-04-02 11:58:04 +02001482 logger.Debugw("deleting-logical-ports", log.Fields{"device-id": deviceID})
khenaidoo442e7c72020-03-10 16:13:48 -04001483 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1484 return err
1485 }
1486 defer agent.requestQueue.RequestComplete()
khenaidoo0a822f92019-05-08 15:15:57 -04001487
khenaidoo6e55d9e2019-12-12 18:26:26 -05001488 logicalDevice := agent.getLogicalDeviceWithoutLock()
khenaidoo820197c2020-02-13 16:35:33 -05001489 lPortstoKeep := []*voltha.LogicalPort{}
1490 lPortsNoToDelete := []uint32{}
khenaidoo6e55d9e2019-12-12 18:26:26 -05001491 for _, logicalPort := range logicalDevice.Ports {
npujar1d86a522019-11-14 17:11:16 +05301492 if logicalPort.DeviceId != deviceID {
khenaidoo820197c2020-02-13 16:35:33 -05001493 lPortstoKeep = append(lPortstoKeep, logicalPort)
1494 } else {
1495 lPortsNoToDelete = append(lPortsNoToDelete, logicalPort.DevicePortNo)
khenaidoo0a822f92019-05-08 15:15:57 -04001496 }
1497 }
Andrea Campanella09400bd2020-04-02 11:58:04 +02001498 logger.Debugw("deleted-logical-ports", log.Fields{"ports": lPortstoKeep})
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001499 if err := agent.updateLogicalDevicePortsWithoutLock(ctx, logicalDevice, lPortstoKeep); err != nil {
Andrea Campanella09400bd2020-04-02 11:58:04 +02001500 logger.Errorw("logical-device-update-failed", log.Fields{"logical-device-id": agent.logicalDeviceID})
khenaidoo0a822f92019-05-08 15:15:57 -04001501 return err
1502 }
khenaidoo820197c2020-02-13 16:35:33 -05001503 // Remove the port from the cached logical ports set
1504 agent.deleteLogicalPortsFromMap(lPortsNoToDelete)
1505
1506 // Reset the logical device routes
1507 go func() {
1508 if err := agent.buildRoutes(context.Background()); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001509 logger.Warnw("routes-not-ready", log.Fields{"logical-device-id": agent.logicalDeviceID, "error": err})
khenaidoo820197c2020-02-13 16:35:33 -05001510 }
1511 }()
khenaidoo0a822f92019-05-08 15:15:57 -04001512
1513 return nil
1514}
1515
khenaidoo19d7b632018-10-30 10:49:50 -04001516// enableLogicalPort enables the logical port
Kent Hagerman2b216042020-04-03 18:28:56 -04001517func (agent *LogicalAgent) enableLogicalPort(ctx context.Context, lPortID string) error {
khenaidoo442e7c72020-03-10 16:13:48 -04001518 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1519 return err
1520 }
1521 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -04001522
khenaidoo6e55d9e2019-12-12 18:26:26 -05001523 logicalDevice := agent.getLogicalDeviceWithoutLock()
1524
khenaidoo19d7b632018-10-30 10:49:50 -04001525 index := -1
khenaidoo6e55d9e2019-12-12 18:26:26 -05001526 for i, logicalPort := range logicalDevice.Ports {
npujar1d86a522019-11-14 17:11:16 +05301527 if logicalPort.Id == lPortID {
khenaidoo19d7b632018-10-30 10:49:50 -04001528 index = i
1529 break
1530 }
1531 }
1532 if index >= 0 {
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001533 clonedPorts := clonePorts(logicalDevice.Ports)
1534 clonedPorts[index].OfpPort.Config = clonedPorts[index].OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
1535 return agent.updateLogicalDevicePortsWithoutLock(ctx, logicalDevice, clonedPorts)
khenaidoo19d7b632018-10-30 10:49:50 -04001536 }
npujar1d86a522019-11-14 17:11:16 +05301537 return status.Errorf(codes.NotFound, "Port %s on Logical Device %s", lPortID, agent.logicalDeviceID)
khenaidoo19d7b632018-10-30 10:49:50 -04001538}
1539
1540// disableLogicalPort disabled the logical port
Kent Hagerman2b216042020-04-03 18:28:56 -04001541func (agent *LogicalAgent) disableLogicalPort(ctx context.Context, lPortID string) error {
khenaidoo442e7c72020-03-10 16:13:48 -04001542 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1543 return err
1544 }
1545 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -04001546
1547 // Get the most up to date logical device
khenaidoo6e55d9e2019-12-12 18:26:26 -05001548 logicalDevice := agent.getLogicalDeviceWithoutLock()
khenaidoo19d7b632018-10-30 10:49:50 -04001549 index := -1
khenaidoo6e55d9e2019-12-12 18:26:26 -05001550 for i, logicalPort := range logicalDevice.Ports {
npujar1d86a522019-11-14 17:11:16 +05301551 if logicalPort.Id == lPortID {
khenaidoo19d7b632018-10-30 10:49:50 -04001552 index = i
1553 break
1554 }
1555 }
1556 if index >= 0 {
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001557 clonedPorts := clonePorts(logicalDevice.Ports)
1558 clonedPorts[index].OfpPort.Config = (clonedPorts[index].OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)) | uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
1559 return agent.updateLogicalDevicePortsWithoutLock(ctx, logicalDevice, clonedPorts)
khenaidoo19d7b632018-10-30 10:49:50 -04001560 }
npujar1d86a522019-11-14 17:11:16 +05301561 return status.Errorf(codes.NotFound, "Port %s on Logical Device %s", lPortID, agent.logicalDeviceID)
khenaidoo19d7b632018-10-30 10:49:50 -04001562}
1563
Kent Hagerman2b216042020-04-03 18:28:56 -04001564func (agent *LogicalAgent) getPreCalculatedRoute(ingress, egress uint32) ([]route.Hop, error) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001565 logger.Debugw("ROUTE", log.Fields{"len": len(agent.deviceRoutes.Routes)})
khenaidoo820197c2020-02-13 16:35:33 -05001566 for routeLink, route := range agent.deviceRoutes.Routes {
Girish Kumarf56a4682020-03-20 20:07:46 +00001567 logger.Debugw("ROUTELINKS", log.Fields{"ingress": ingress, "egress": egress, "routelink": routeLink})
khenaidoo89b0e942018-10-21 21:11:33 -04001568 if ingress == routeLink.Ingress && egress == routeLink.Egress {
khenaidoo820197c2020-02-13 16:35:33 -05001569 return route, nil
khenaidoo89b0e942018-10-21 21:11:33 -04001570 }
1571 }
khenaidoo820197c2020-02-13 16:35:33 -05001572 return nil, status.Errorf(codes.FailedPrecondition, "no route from:%d to:%d", ingress, egress)
khenaidoo89b0e942018-10-21 21:11:33 -04001573}
1574
npujar1d86a522019-11-14 17:11:16 +05301575// GetRoute returns route
Kent Hagerman2b216042020-04-03 18:28:56 -04001576func (agent *LogicalAgent) GetRoute(ctx context.Context, ingressPortNo uint32, egressPortNo uint32) ([]route.Hop, error) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001577 logger.Debugw("getting-route", log.Fields{"ingress-port": ingressPortNo, "egress-port": egressPortNo})
khenaidoo820197c2020-02-13 16:35:33 -05001578 routes := make([]route.Hop, 0)
khenaidoo2c6a0992019-04-29 13:46:56 -04001579
khenaidoo19d7b632018-10-30 10:49:50 -04001580 // Note: A port value of 0 is equivalent to a nil port
1581
khenaidoo89b0e942018-10-21 21:11:33 -04001582 // Consider different possibilities
khenaidoo19d7b632018-10-30 10:49:50 -04001583 if egressPortNo != 0 && ((egressPortNo & 0x7fffffff) == uint32(ofp.OfpPortNo_OFPP_CONTROLLER)) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001584 logger.Debugw("controller-flow", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "logicalPortsNo": agent.logicalPortsNo})
khenaidoo2c6a0992019-04-29 13:46:56 -04001585 if agent.isNNIPort(ingressPortNo) {
khenaidoo89b0e942018-10-21 21:11:33 -04001586 //This is a trap on the NNI Port
khenaidoo820197c2020-02-13 16:35:33 -05001587 if len(agent.deviceRoutes.Routes) == 0 {
khenaidoo8f474192019-04-03 17:20:44 -04001588 // 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 -04001589 // route with same IngressHop and EgressHop
khenaidoo820197c2020-02-13 16:35:33 -05001590 hop := route.Hop{DeviceID: agent.rootDeviceID, Ingress: ingressPortNo, Egress: ingressPortNo}
khenaidoo8f474192019-04-03 17:20:44 -04001591 routes = append(routes, hop)
1592 routes = append(routes, hop)
khenaidoo820197c2020-02-13 16:35:33 -05001593 return routes, nil
khenaidoo8f474192019-04-03 17:20:44 -04001594 }
khenaidoo89b0e942018-10-21 21:11:33 -04001595 //Return a 'half' route to make the flow decomposer logic happy
khenaidoo820197c2020-02-13 16:35:33 -05001596 for routeLink, path := range agent.deviceRoutes.Routes {
khenaidoo2c6a0992019-04-29 13:46:56 -04001597 if agent.isNNIPort(routeLink.Egress) {
khenaidoo820197c2020-02-13 16:35:33 -05001598 routes = append(routes, route.Hop{}) // first hop is set to empty
1599 routes = append(routes, path[1])
1600 return routes, nil
khenaidoo89b0e942018-10-21 21:11:33 -04001601 }
1602 }
khenaidoo787224a2020-04-16 18:08:47 -04001603 return nil, fmt.Errorf("no upstream route from:%d to:%d :%w", ingressPortNo, egressPortNo, route.ErrNoRoute)
khenaidoo89b0e942018-10-21 21:11:33 -04001604 }
1605 //treat it as if the output port is the first NNI of the OLT
khenaidoo2c6a0992019-04-29 13:46:56 -04001606 var err error
1607 if egressPortNo, err = agent.getFirstNNIPort(); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001608 logger.Warnw("no-nni-port", log.Fields{"error": err})
khenaidoo820197c2020-02-13 16:35:33 -05001609 return nil, err
khenaidoo2c6a0992019-04-29 13:46:56 -04001610 }
khenaidoo89b0e942018-10-21 21:11:33 -04001611 }
1612 //If ingress port is not specified (nil), it may be a wildcarded
1613 //route if egress port is OFPP_CONTROLLER or a nni logical port,
1614 //in which case we need to create a half-route where only the egress
1615 //hop is filled, the first hop is nil
khenaidoo2c6a0992019-04-29 13:46:56 -04001616 if ingressPortNo == 0 && agent.isNNIPort(egressPortNo) {
khenaidoo89b0e942018-10-21 21:11:33 -04001617 // We can use the 2nd hop of any upstream route, so just find the first upstream:
khenaidoo820197c2020-02-13 16:35:33 -05001618 for routeLink, path := range agent.deviceRoutes.Routes {
khenaidoo2c6a0992019-04-29 13:46:56 -04001619 if agent.isNNIPort(routeLink.Egress) {
khenaidoo820197c2020-02-13 16:35:33 -05001620 routes = append(routes, route.Hop{}) // first hop is set to empty
1621 routes = append(routes, path[1])
1622 return routes, nil
khenaidoo89b0e942018-10-21 21:11:33 -04001623 }
1624 }
khenaidoo787224a2020-04-16 18:08:47 -04001625 return nil, fmt.Errorf("no upstream route from:%d to:%d :%w", ingressPortNo, egressPortNo, route.ErrNoRoute)
khenaidoo89b0e942018-10-21 21:11:33 -04001626 }
1627 //If egress port is not specified (nil), we can also can return a "half" route
khenaidoo19d7b632018-10-30 10:49:50 -04001628 if egressPortNo == 0 {
khenaidoo820197c2020-02-13 16:35:33 -05001629 for routeLink, path := range agent.deviceRoutes.Routes {
khenaidoo19d7b632018-10-30 10:49:50 -04001630 if routeLink.Ingress == ingressPortNo {
khenaidoo820197c2020-02-13 16:35:33 -05001631 routes = append(routes, path[0])
1632 routes = append(routes, route.Hop{})
1633 return routes, nil
khenaidoo89b0e942018-10-21 21:11:33 -04001634 }
1635 }
khenaidoo787224a2020-04-16 18:08:47 -04001636 return nil, fmt.Errorf("no downstream route from:%d to:%d :%w", ingressPortNo, egressPortNo, route.ErrNoRoute)
khenaidoo89b0e942018-10-21 21:11:33 -04001637 }
khenaidoo89b0e942018-10-21 21:11:33 -04001638 // Return the pre-calculated route
khenaidoo19d7b632018-10-30 10:49:50 -04001639 return agent.getPreCalculatedRoute(ingressPortNo, egressPortNo)
khenaidoo89b0e942018-10-21 21:11:33 -04001640}
1641
khenaidoo3d3b8c22019-05-22 18:10:39 -04001642//GetWildcardInputPorts filters out the logical port number from the set of logical ports on the device and
1643//returns their port numbers. This function is invoked only during flow decomposition where the lock on the logical
1644//device is already held. Therefore it is safe to retrieve the logical device without lock.
Kent Hagerman2b216042020-04-03 18:28:56 -04001645func (agent *LogicalAgent) GetWildcardInputPorts(excludePort ...uint32) []uint32 {
khenaidoo89b0e942018-10-21 21:11:33 -04001646 lPorts := make([]uint32, 0)
1647 var exclPort uint32
1648 if len(excludePort) == 1 {
1649 exclPort = excludePort[0]
1650 }
khenaidoo6e55d9e2019-12-12 18:26:26 -05001651 lDevice := agent.getLogicalDeviceWithoutLock()
1652 for _, port := range lDevice.Ports {
1653 if port.OfpPort.PortNo != exclPort {
1654 lPorts = append(lPorts, port.OfpPort.PortNo)
khenaidoo89b0e942018-10-21 21:11:33 -04001655 }
1656 }
1657 return lPorts
1658}
khenaidoo19d7b632018-10-30 10:49:50 -04001659
khenaidoo820197c2020-02-13 16:35:33 -05001660// GetDeviceRoutes returns device graph
Kent Hagerman2b216042020-04-03 18:28:56 -04001661func (agent *LogicalAgent) GetDeviceRoutes() *route.DeviceRoutes {
khenaidoo820197c2020-02-13 16:35:33 -05001662 return agent.deviceRoutes
khenaidoo19d7b632018-10-30 10:49:50 -04001663}
1664
khenaidoo820197c2020-02-13 16:35:33 -05001665//rebuildRoutes rebuilds the device routes
Kent Hagerman2b216042020-04-03 18:28:56 -04001666func (agent *LogicalAgent) buildRoutes(ctx context.Context) error {
Girish Kumarf56a4682020-03-20 20:07:46 +00001667 logger.Debugf("building-routes", log.Fields{"logical-device-id": agent.logicalDeviceID})
khenaidoo442e7c72020-03-10 16:13:48 -04001668 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1669 return err
1670 }
1671 defer agent.requestQueue.RequestComplete()
1672
khenaidoo820197c2020-02-13 16:35:33 -05001673 if agent.deviceRoutes == nil {
Kent Hagerman45a13e42020-04-13 12:23:50 -04001674 agent.deviceRoutes = route.NewDeviceRoutes(agent.logicalDeviceID, agent.deviceMgr.getDevice)
khenaidoo2c6a0992019-04-29 13:46:56 -04001675 }
1676 // Get all the logical ports on that logical device
khenaidoo6e55d9e2019-12-12 18:26:26 -05001677 lDevice := agent.getLogicalDeviceWithoutLock()
1678
khenaidoo820197c2020-02-13 16:35:33 -05001679 if err := agent.deviceRoutes.ComputeRoutes(ctx, lDevice.Ports); err != nil {
1680 return err
1681 }
1682 if err := agent.deviceRoutes.Print(); err != nil {
1683 return err
1684 }
1685
khenaidoo2c6a0992019-04-29 13:46:56 -04001686 return nil
khenaidoo19d7b632018-10-30 10:49:50 -04001687}
1688
khenaidoo820197c2020-02-13 16:35:33 -05001689//updateRoutes updates the device routes
Kent Hagerman2b216042020-04-03 18:28:56 -04001690func (agent *LogicalAgent) updateRoutes(ctx context.Context, lp *voltha.LogicalPort) error {
Girish Kumarf56a4682020-03-20 20:07:46 +00001691 logger.Debugw("updateRoutes", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo442e7c72020-03-10 16:13:48 -04001692 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1693 return err
1694 }
1695 defer agent.requestQueue.RequestComplete()
1696
khenaidoo820197c2020-02-13 16:35:33 -05001697 if agent.deviceRoutes == nil {
Kent Hagerman45a13e42020-04-13 12:23:50 -04001698 agent.deviceRoutes = route.NewDeviceRoutes(agent.logicalDeviceID, agent.deviceMgr.getDevice)
khenaidoo910204f2019-04-08 17:56:40 -04001699 }
khenaidoo820197c2020-02-13 16:35:33 -05001700 if err := agent.deviceRoutes.AddPort(ctx, lp, agent.logicalDevice.Ports); err != nil {
1701 return err
khenaidoo0a822f92019-05-08 15:15:57 -04001702 }
khenaidoo820197c2020-02-13 16:35:33 -05001703 if err := agent.deviceRoutes.Print(); err != nil {
1704 return err
1705 }
1706 return nil
khenaidoo0a822f92019-05-08 15:15:57 -04001707}
1708
khenaidoofc1314d2019-03-14 09:34:21 -04001709// 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 -04001710func diff(oldList, newList []*voltha.LogicalPort) (newPorts, changedPorts, deletedPorts map[string]*voltha.LogicalPort) {
1711 newPorts = make(map[string]*voltha.LogicalPort, len(newList))
1712 changedPorts = make(map[string]*voltha.LogicalPort, len(oldList))
1713 deletedPorts = make(map[string]*voltha.LogicalPort, len(oldList))
1714
khenaidoofc1314d2019-03-14 09:34:21 -04001715 for _, n := range newList {
Kent Hagerman8ad29952020-04-21 11:48:02 -04001716 newPorts[n.Id] = n
1717 }
1718
1719 for _, o := range oldList {
1720 if n, have := newPorts[o.Id]; have {
1721 delete(newPorts, o.Id) // not new
1722 if !proto.Equal(n, o) {
1723 changedPorts[n.Id] = n // changed
khenaidoofc1314d2019-03-14 09:34:21 -04001724 }
Kent Hagerman8ad29952020-04-21 11:48:02 -04001725 } else {
1726 deletedPorts[o.Id] = o // deleted
khenaidoo2bc48282019-07-16 18:13:46 -04001727 }
khenaidoofc1314d2019-03-14 09:34:21 -04001728 }
Kent Hagerman8ad29952020-04-21 11:48:02 -04001729
1730 return newPorts, changedPorts, deletedPorts
khenaidoofc1314d2019-03-14 09:34:21 -04001731}
1732
Kent Hagerman8ad29952020-04-21 11:48:02 -04001733// portUpdated is invoked when a port is updated on the logical device
1734func (agent *LogicalAgent) portUpdated(prevPorts, currPorts []*voltha.LogicalPort) interface{} {
khenaidoofc1314d2019-03-14 09:34:21 -04001735 // Get the difference between the two list
Kent Hagerman8ad29952020-04-21 11:48:02 -04001736 newPorts, changedPorts, deletedPorts := diff(prevPorts, currPorts)
1737
khenaidoofc1314d2019-03-14 09:34:21 -04001738 // Send the port change events to the OF controller
khenaidoo2c6a0992019-04-29 13:46:56 -04001739 for _, newP := range newPorts {
Kent Hagerman45a13e42020-04-13 12:23:50 -04001740 go agent.ldeviceMgr.SendChangeEvent(agent.logicalDeviceID,
khenaidoo2c6a0992019-04-29 13:46:56 -04001741 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_ADD, Desc: newP.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001742 }
1743 for _, change := range changedPorts {
Kent Hagerman45a13e42020-04-13 12:23:50 -04001744 go agent.ldeviceMgr.SendChangeEvent(agent.logicalDeviceID,
khenaidoo910204f2019-04-08 17:56:40 -04001745 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_MODIFY, Desc: change.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001746 }
1747 for _, del := range deletedPorts {
Kent Hagerman45a13e42020-04-13 12:23:50 -04001748 go agent.ldeviceMgr.SendChangeEvent(agent.logicalDeviceID,
khenaidoo910204f2019-04-08 17:56:40 -04001749 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_DELETE, Desc: del.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001750 }
1751
1752 return nil
1753}
1754
khenaidoo8f474192019-04-03 17:20:44 -04001755// addNNILogicalPort adds an NNI port to the logical device. It returns a bool representing whether a port has been
1756// added and an eror in case a valid error is encountered. If the port was successfully added it will return
1757// (true, nil). If the device is not in the correct state it will return (false, nil) as this is a valid
1758// scenario. This also applies to the case where the port was already added.
Kent Hagerman2b216042020-04-03 18:28:56 -04001759func (agent *LogicalAgent) addNNILogicalPort(ctx context.Context, device *voltha.Device, port *voltha.Port) (bool, error) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001760 logger.Debugw("addNNILogicalPort", log.Fields{"NNI": port})
Chaitrashree G S7849b322020-03-29 19:25:49 -04001761
khenaidoo442e7c72020-03-10 16:13:48 -04001762 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1763 return false, err
1764 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001765 if agent.portExist(device, port) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001766 logger.Debugw("port-already-exist", log.Fields{"port": port})
khenaidoo442e7c72020-03-10 16:13:48 -04001767 agent.requestQueue.RequestComplete()
khenaidoo8f474192019-04-03 17:20:44 -04001768 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001769 }
khenaidoo442e7c72020-03-10 16:13:48 -04001770 agent.requestQueue.RequestComplete()
khenaidoo1ce37ad2019-03-24 22:07:24 -04001771
khenaidoofc1314d2019-03-14 09:34:21 -04001772 var portCap *ic.PortCapability
1773 var err error
1774 // First get the port capability
npujar467fe752020-01-16 20:17:45 +05301775 if portCap, err = agent.deviceMgr.getPortCapability(ctx, device.Id, port.PortNo); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001776 logger.Errorw("error-retrieving-port-capabilities", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001777 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001778 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001779
khenaidoo442e7c72020-03-10 16:13:48 -04001780 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1781 return false, err
1782 }
1783
1784 defer agent.requestQueue.RequestComplete()
khenaidoo1ce37ad2019-03-24 22:07:24 -04001785 // Double check again if this port has been already added since the getPortCapability could have taken a long time
1786 if agent.portExist(device, port) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001787 logger.Debugw("port-already-exist", log.Fields{"port": port})
khenaidoo8f474192019-04-03 17:20:44 -04001788 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001789 }
1790
khenaidoofc1314d2019-03-14 09:34:21 -04001791 portCap.Port.RootPort = true
1792 lp := (proto.Clone(portCap.Port)).(*voltha.LogicalPort)
1793 lp.DeviceId = device.Id
1794 lp.Id = fmt.Sprintf("nni-%d", port.PortNo)
1795 lp.OfpPort.PortNo = port.PortNo
1796 lp.OfpPort.Name = lp.Id
1797 lp.DevicePortNo = port.PortNo
1798
khenaidoo6e55d9e2019-12-12 18:26:26 -05001799 ld := agent.getLogicalDeviceWithoutLock()
1800
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001801 clonedPorts := clonePorts(ld.Ports)
1802 if clonedPorts == nil {
1803 clonedPorts = make([]*voltha.LogicalPort, 0)
khenaidoofc1314d2019-03-14 09:34:21 -04001804 }
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001805 clonedPorts = append(clonedPorts, lp)
khenaidoofc1314d2019-03-14 09:34:21 -04001806
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001807 if err = agent.updateLogicalDevicePortsWithoutLock(ctx, ld, clonedPorts); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001808 logger.Errorw("error-updating-logical-device", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001809 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001810 }
khenaidoo910204f2019-04-08 17:56:40 -04001811
khenaidoo820197c2020-02-13 16:35:33 -05001812 // Update the device routes with this new logical port
khenaidoo910204f2019-04-08 17:56:40 -04001813 clonedLP := (proto.Clone(lp)).(*voltha.LogicalPort)
khenaidoo820197c2020-02-13 16:35:33 -05001814 go func() {
1815 if err := agent.updateRoutes(context.Background(), clonedLP); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001816 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 -05001817 }
1818 }()
khenaidoo910204f2019-04-08 17:56:40 -04001819
khenaidoo8f474192019-04-03 17:20:44 -04001820 return true, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001821}
1822
Kent Hagerman2b216042020-04-03 18:28:56 -04001823func (agent *LogicalAgent) portExist(device *voltha.Device, port *voltha.Port) bool {
khenaidoo6e55d9e2019-12-12 18:26:26 -05001824 ldevice := agent.getLogicalDeviceWithoutLock()
1825 for _, lPort := range ldevice.Ports {
1826 if lPort.DeviceId == device.Id && lPort.DevicePortNo == port.PortNo && lPort.Id == port.Label {
1827 return true
khenaidoofc1314d2019-03-14 09:34:21 -04001828 }
1829 }
1830 return false
1831}
1832
khenaidoo8f474192019-04-03 17:20:44 -04001833// addUNILogicalPort adds an UNI port to the logical device. It returns a bool representing whether a port has been
1834// added and an eror in case a valid error is encountered. If the port was successfully added it will return
1835// (true, nil). If the device is not in the correct state it will return (false, nil) as this is a valid
1836// scenario. This also applies to the case where the port was already added.
Kent Hagerman2b216042020-04-03 18:28:56 -04001837func (agent *LogicalAgent) addUNILogicalPort(ctx context.Context, childDevice *voltha.Device, port *voltha.Port) (bool, error) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001838 logger.Debugw("addUNILogicalPort", log.Fields{"port": port})
khenaidoo8f474192019-04-03 17:20:44 -04001839 if childDevice.AdminState != voltha.AdminState_ENABLED || childDevice.OperStatus != voltha.OperStatus_ACTIVE {
Girish Kumarf56a4682020-03-20 20:07:46 +00001840 logger.Infow("device-not-ready", log.Fields{"deviceId": childDevice.Id, "admin": childDevice.AdminState, "oper": childDevice.OperStatus})
khenaidoo8f474192019-04-03 17:20:44 -04001841 return false, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001842 }
khenaidoo442e7c72020-03-10 16:13:48 -04001843 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1844 return false, err
1845 }
1846
khenaidoo1ce37ad2019-03-24 22:07:24 -04001847 if agent.portExist(childDevice, port) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001848 logger.Debugw("port-already-exist", log.Fields{"port": port})
khenaidoo442e7c72020-03-10 16:13:48 -04001849 agent.requestQueue.RequestComplete()
khenaidoo8f474192019-04-03 17:20:44 -04001850 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001851 }
khenaidoo442e7c72020-03-10 16:13:48 -04001852 agent.requestQueue.RequestComplete()
khenaidoofc1314d2019-03-14 09:34:21 -04001853 var portCap *ic.PortCapability
1854 var err error
1855 // First get the port capability
npujar467fe752020-01-16 20:17:45 +05301856 if portCap, err = agent.deviceMgr.getPortCapability(ctx, childDevice.Id, port.PortNo); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001857 logger.Errorw("error-retrieving-port-capabilities", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001858 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001859 }
khenaidoo442e7c72020-03-10 16:13:48 -04001860 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1861 return false, err
1862 }
1863 defer agent.requestQueue.RequestComplete()
khenaidoo1ce37ad2019-03-24 22:07:24 -04001864 // Double check again if this port has been already added since the getPortCapability could have taken a long time
1865 if agent.portExist(childDevice, port) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001866 logger.Debugw("port-already-exist", log.Fields{"port": port})
khenaidoo8f474192019-04-03 17:20:44 -04001867 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001868 }
khenaidoofc1314d2019-03-14 09:34:21 -04001869 // Get stored logical device
khenaidoo6e55d9e2019-12-12 18:26:26 -05001870 ldevice := agent.getLogicalDeviceWithoutLock()
1871
Girish Kumarf56a4682020-03-20 20:07:46 +00001872 logger.Debugw("adding-uni", log.Fields{"deviceId": childDevice.Id})
npujar1d86a522019-11-14 17:11:16 +05301873 portCap.Port.RootPort = false
1874 portCap.Port.Id = port.Label
1875 portCap.Port.OfpPort.PortNo = port.PortNo
1876 portCap.Port.DeviceId = childDevice.Id
1877 portCap.Port.DevicePortNo = port.PortNo
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001878 clonedPorts := clonePorts(ldevice.Ports)
1879 if clonedPorts == nil {
1880 clonedPorts = make([]*voltha.LogicalPort, 0)
npujar1d86a522019-11-14 17:11:16 +05301881 }
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001882 clonedPorts = append(clonedPorts, portCap.Port)
1883 if err := agent.updateLogicalDevicePortsWithoutLock(ctx, ldevice, clonedPorts); err != nil {
npujar1d86a522019-11-14 17:11:16 +05301884 return false, err
1885 }
1886 // Update the device graph with this new logical port
1887 clonedLP := (proto.Clone(portCap.Port)).(*voltha.LogicalPort)
khenaidoo820197c2020-02-13 16:35:33 -05001888
1889 go func() {
1890 if err := agent.updateRoutes(context.Background(), clonedLP); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001891 logger.Warn("routes-not-ready", log.Fields{"logical-device-id": agent.logicalDeviceID, "error": err})
khenaidoo820197c2020-02-13 16:35:33 -05001892 }
1893 }()
1894
npujar1d86a522019-11-14 17:11:16 +05301895 return true, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001896}
1897
Kent Hagerman2b216042020-04-03 18:28:56 -04001898func (agent *LogicalAgent) packetOut(ctx context.Context, packet *ofp.OfpPacketOut) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001899 logger.Debugw("packet-out", log.Fields{
Matteo Scandolo360605d2019-11-05 18:29:17 -08001900 "packet": hex.EncodeToString(packet.Data),
1901 "inPort": packet.GetInPort(),
1902 })
khenaidoo68c930b2019-05-13 11:46:51 -04001903 outPort := fu.GetPacketOutPort(packet)
khenaidoofdbad6e2018-11-06 22:26:38 -05001904 //frame := packet.GetData()
1905 //TODO: Use a channel between the logical agent and the device agent
npujar467fe752020-01-16 20:17:45 +05301906 if err := agent.deviceMgr.packetOut(ctx, agent.rootDeviceID, outPort, packet); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001907 logger.Error("packetout-failed", log.Fields{"logicalDeviceID": agent.rootDeviceID})
khenaidooca301322019-01-09 23:06:32 -05001908 }
khenaidoofdbad6e2018-11-06 22:26:38 -05001909}
1910
Kent Hagerman2b216042020-04-03 18:28:56 -04001911func (agent *LogicalAgent) packetIn(port uint32, transactionID string, packet []byte) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001912 logger.Debugw("packet-in", log.Fields{
Matteo Scandolo360605d2019-11-05 18:29:17 -08001913 "port": port,
1914 "packet": hex.EncodeToString(packet),
npujar1d86a522019-11-14 17:11:16 +05301915 "transactionId": transactionID,
Matteo Scandolo360605d2019-11-05 18:29:17 -08001916 })
khenaidoo68c930b2019-05-13 11:46:51 -04001917 packetIn := fu.MkPacketIn(port, packet)
Kent Hagerman45a13e42020-04-13 12:23:50 -04001918 agent.ldeviceMgr.SendPacketIn(agent.logicalDeviceID, transactionID, packetIn)
Girish Kumarf56a4682020-03-20 20:07:46 +00001919 logger.Debugw("sending-packet-in", log.Fields{"packet": hex.EncodeToString(packetIn.Data)})
khenaidoofdbad6e2018-11-06 22:26:38 -05001920}
khenaidoo2c6a0992019-04-29 13:46:56 -04001921
Kent Hagerman2b216042020-04-03 18:28:56 -04001922func (agent *LogicalAgent) addLogicalPortToMap(portNo uint32, nniPort bool) {
khenaidoo2c6a0992019-04-29 13:46:56 -04001923 agent.lockLogicalPortsNo.Lock()
1924 defer agent.lockLogicalPortsNo.Unlock()
1925 if exist := agent.logicalPortsNo[portNo]; !exist {
1926 agent.logicalPortsNo[portNo] = nniPort
1927 }
1928}
1929
Kent Hagerman2b216042020-04-03 18:28:56 -04001930func (agent *LogicalAgent) deleteLogicalPortsFromMap(portsNo []uint32) {
khenaidoo820197c2020-02-13 16:35:33 -05001931 agent.lockLogicalPortsNo.Lock()
1932 defer agent.lockLogicalPortsNo.Unlock()
1933 for _, pNo := range portsNo {
1934 delete(agent.logicalPortsNo, pNo)
1935 }
1936}
1937
Kent Hagerman2b216042020-04-03 18:28:56 -04001938func (agent *LogicalAgent) addLogicalPortsToMap(lps []*voltha.LogicalPort) {
khenaidoo3d3b8c22019-05-22 18:10:39 -04001939 agent.lockLogicalPortsNo.Lock()
1940 defer agent.lockLogicalPortsNo.Unlock()
1941 for _, lp := range lps {
1942 if exist := agent.logicalPortsNo[lp.DevicePortNo]; !exist {
1943 agent.logicalPortsNo[lp.DevicePortNo] = lp.RootPort
1944 }
1945 }
1946}
1947
Kent Hagerman2b216042020-04-03 18:28:56 -04001948func (agent *LogicalAgent) isNNIPort(portNo uint32) bool {
khenaidoo2c6a0992019-04-29 13:46:56 -04001949 agent.lockLogicalPortsNo.RLock()
1950 defer agent.lockLogicalPortsNo.RUnlock()
1951 if exist := agent.logicalPortsNo[portNo]; exist {
1952 return agent.logicalPortsNo[portNo]
1953 }
1954 return false
1955}
1956
Kent Hagerman2b216042020-04-03 18:28:56 -04001957func (agent *LogicalAgent) getFirstNNIPort() (uint32, error) {
khenaidoo2c6a0992019-04-29 13:46:56 -04001958 agent.lockLogicalPortsNo.RLock()
1959 defer agent.lockLogicalPortsNo.RUnlock()
1960 for portNo, nni := range agent.logicalPortsNo {
1961 if nni {
1962 return portNo, nil
1963 }
1964 }
1965 return 0, status.Error(codes.NotFound, "No NNI port found")
1966}
Esin Karaman09959ae2019-11-29 13:59:58 +00001967
1968//GetNNIPorts returns NNI ports.
Kent Hagerman2b216042020-04-03 18:28:56 -04001969func (agent *LogicalAgent) GetNNIPorts() []uint32 {
Esin Karaman09959ae2019-11-29 13:59:58 +00001970 agent.lockLogicalPortsNo.RLock()
1971 defer agent.lockLogicalPortsNo.RUnlock()
1972 nniPorts := make([]uint32, 0)
1973 for portNo, nni := range agent.logicalPortsNo {
1974 if nni {
1975 nniPorts = append(nniPorts, portNo)
1976 }
1977 }
1978 return nniPorts
1979}