blob: 42cbc4ebbec9cc922c487187e5073c3bd059a84f [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 "reflect"
25 "sync"
26 "time"
27
khenaidoob9203542018-09-17 22:56:37 -040028 "github.com/gogo/protobuf/proto"
sbarbari17d7e222019-11-05 10:02:29 -050029 "github.com/opencord/voltha-go/db/model"
npujar1d86a522019-11-14 17:11:16 +053030 fd "github.com/opencord/voltha-go/rw_core/flowdecomposition"
khenaidoo442e7c72020-03-10 16:13:48 -040031 "github.com/opencord/voltha-go/rw_core/route"
Scott Bakerb671a862019-10-24 10:53:40 -070032 coreutils "github.com/opencord/voltha-go/rw_core/utils"
serkant.uluderya2ae470f2020-01-21 11:13:09 -080033 fu "github.com/opencord/voltha-lib-go/v3/pkg/flows"
34 "github.com/opencord/voltha-lib-go/v3/pkg/log"
35 ic "github.com/opencord/voltha-protos/v3/go/inter_container"
36 ofp "github.com/opencord/voltha-protos/v3/go/openflow_13"
37 "github.com/opencord/voltha-protos/v3/go/voltha"
khenaidoob9203542018-09-17 22:56:37 -040038 "google.golang.org/grpc/codes"
39 "google.golang.org/grpc/status"
khenaidoo442e7c72020-03-10 16:13:48 -040040)
41
Kent Hagerman2b216042020-04-03 18:28:56 -040042// LogicalAgent represent attributes of logical device agent
43type LogicalAgent struct {
npujar1d86a522019-11-14 17:11:16 +053044 logicalDeviceID string
David Bainbridged1afd662020-03-26 18:27:41 -070045 serialNumber string
npujar1d86a522019-11-14 17:11:16 +053046 rootDeviceID string
Kent Hagerman2b216042020-04-03 18:28:56 -040047 deviceMgr *Manager
48 ldeviceMgr *LogicalManager
khenaidoo3306c992019-05-24 16:57:35 -040049 clusterDataProxy *model.Proxy
Kent Hagerman4f355f52020-03-30 16:01:33 -040050 stopped bool
khenaidoo820197c2020-02-13 16:35:33 -050051 deviceRoutes *route.DeviceRoutes
khenaidoo820197c2020-02-13 16:35:33 -050052 lockDeviceRoutes sync.RWMutex
khenaidoo3306c992019-05-24 16:57:35 -040053 logicalPortsNo map[uint32]bool //value is true for NNI port
54 lockLogicalPortsNo sync.RWMutex
55 flowDecomposer *fd.FlowDecomposer
khenaidoo442e7c72020-03-10 16:13:48 -040056 defaultTimeout time.Duration
khenaidoo6e55d9e2019-12-12 18:26:26 -050057 logicalDevice *voltha.LogicalDevice
khenaidoo442e7c72020-03-10 16:13:48 -040058 requestQueue *coreutils.RequestQueue
59 startOnce sync.Once
60 stopOnce sync.Once
khenaidoob9203542018-09-17 22:56:37 -040061}
62
Kent Hagerman2b216042020-04-03 18:28:56 -040063func newLogicalDeviceAgent(id string, sn string, deviceID string, ldeviceMgr *LogicalManager,
64 deviceMgr *Manager, cdProxy *model.Proxy, timeout time.Duration) *LogicalAgent {
65 var agent LogicalAgent
npujar1d86a522019-11-14 17:11:16 +053066 agent.logicalDeviceID = id
David Bainbridged1afd662020-03-26 18:27:41 -070067 agent.serialNumber = sn
npujar1d86a522019-11-14 17:11:16 +053068 agent.rootDeviceID = deviceID
khenaidoob9203542018-09-17 22:56:37 -040069 agent.deviceMgr = deviceMgr
khenaidoo9a468962018-09-19 15:33:13 -040070 agent.clusterDataProxy = cdProxy
khenaidoob9203542018-09-17 22:56:37 -040071 agent.ldeviceMgr = ldeviceMgr
khenaidoo19d7b632018-10-30 10:49:50 -040072 agent.flowDecomposer = fd.NewFlowDecomposer(agent.deviceMgr)
khenaidoo2c6a0992019-04-29 13:46:56 -040073 agent.logicalPortsNo = make(map[uint32]bool)
khenaidoo2c6a0992019-04-29 13:46:56 -040074 agent.defaultTimeout = timeout
Kent Hagerman730cbdf2020-03-31 12:22:08 -040075 agent.requestQueue = coreutils.NewRequestQueue()
khenaidoob9203542018-09-17 22:56:37 -040076 return &agent
77}
78
khenaidoo4d4802d2018-10-04 21:59:49 -040079// start creates the logical device and add it to the data model
Kent Hagerman2b216042020-04-03 18:28:56 -040080func (agent *LogicalAgent) start(ctx context.Context, loadFromDB bool) error {
khenaidoo442e7c72020-03-10 16:13:48 -040081 needToStart := false
82 if agent.startOnce.Do(func() { needToStart = true }); !needToStart {
83 return nil
84 }
85
Girish Kumarf56a4682020-03-20 20:07:46 +000086 logger.Infow("starting-logical_device-agent", log.Fields{"logical-device-id": agent.logicalDeviceID, "load-from-db": loadFromDB})
khenaidoo442e7c72020-03-10 16:13:48 -040087
88 var startSucceeded bool
89 defer func() {
90 if !startSucceeded {
91 if err := agent.stop(ctx); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +000092 logger.Errorw("failed-to-cleanup-after-unsuccessful-start", log.Fields{"logical-device-id": agent.logicalDeviceID, "error": err})
khenaidoo442e7c72020-03-10 16:13:48 -040093 }
94 }
95 }()
96
khenaidoo297cd252019-02-07 22:10:23 -050097 var ld *voltha.LogicalDevice
khenaidoo442e7c72020-03-10 16:13:48 -040098 if !loadFromDB {
khenaidoo7e3d8f12019-08-02 16:06:30 -040099 //Build the logical device based on information retrieved from the device adapter
100 var switchCap *ic.SwitchCapability
khenaidoo297cd252019-02-07 22:10:23 -0500101 var err error
npujar1d86a522019-11-14 17:11:16 +0530102 if switchCap, err = agent.deviceMgr.getSwitchCapability(ctx, agent.rootDeviceID); err != nil {
khenaidoo7e3d8f12019-08-02 16:06:30 -0400103 return err
104 }
npujar1d86a522019-11-14 17:11:16 +0530105 ld = &voltha.LogicalDevice{Id: agent.logicalDeviceID, RootDeviceId: agent.rootDeviceID}
khenaidoo297cd252019-02-07 22:10:23 -0500106
107 // Create the datapath ID (uint64) using the logical device ID (based on the MAC Address)
108 var datapathID uint64
Kent Hagerman2b216042020-04-03 18:28:56 -0400109 if datapathID, err = coreutils.CreateDataPathID(agent.serialNumber); err != nil {
khenaidoo297cd252019-02-07 22:10:23 -0500110 return err
111 }
112 ld.DatapathId = datapathID
khenaidoo7e3d8f12019-08-02 16:06:30 -0400113 ld.Desc = (proto.Clone(switchCap.Desc)).(*ofp.OfpDesc)
Girish Kumarf56a4682020-03-20 20:07:46 +0000114 logger.Debugw("Switch-capability", log.Fields{"Desc": ld.Desc, "fromAd": switchCap.Desc})
khenaidoo7e3d8f12019-08-02 16:06:30 -0400115 ld.SwitchFeatures = (proto.Clone(switchCap.SwitchFeatures)).(*ofp.OfpSwitchFeatures)
khenaidoo297cd252019-02-07 22:10:23 -0500116 ld.Flows = &ofp.Flows{Items: nil}
117 ld.FlowGroups = &ofp.FlowGroups{Items: nil}
khenaidoo49085352020-01-13 19:15:43 -0500118 ld.Ports = []*voltha.LogicalPort{}
khenaidoo297cd252019-02-07 22:10:23 -0500119
khenaidoo297cd252019-02-07 22:10:23 -0500120 // Save the logical device
Kent Hagerman4f355f52020-03-30 16:01:33 -0400121 if err := agent.clusterDataProxy.AddWithID(ctx, "logical_devices", ld.Id, ld); err != nil {
122 logger.Errorw("failed-to-add-logical-device", log.Fields{"logical-device-id": agent.logicalDeviceID})
Thomas Lee Se5a44012019-11-07 20:32:24 +0530123 return err
124 }
Kent Hagerman4f355f52020-03-30 16:01:33 -0400125 logger.Debugw("logicaldevice-created", log.Fields{"logical-device-id": agent.logicalDeviceID, "root-id": ld.RootDeviceId})
khenaidoo6e55d9e2019-12-12 18:26:26 -0500126
127 agent.logicalDevice = proto.Clone(ld).(*voltha.LogicalDevice)
khenaidoofc1314d2019-03-14 09:34:21 -0400128
khenaidoo442e7c72020-03-10 16:13:48 -0400129 // Setup the logicalports - internal processing, no need to propagate the client context
npujar1d86a522019-11-14 17:11:16 +0530130 go func() {
khenaidoo442e7c72020-03-10 16:13:48 -0400131 err := agent.setupLogicalPorts(context.Background())
npujar1d86a522019-11-14 17:11:16 +0530132 if err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000133 logger.Errorw("unable-to-setup-logical-ports", log.Fields{"error": err})
npujar1d86a522019-11-14 17:11:16 +0530134 }
135 }()
khenaidoo297cd252019-02-07 22:10:23 -0500136 } else {
137 // load from dB - the logical may not exist at this time. On error, just return and the calling function
138 // will destroy this agent.
Kent Hagerman4f355f52020-03-30 16:01:33 -0400139 ld := &voltha.LogicalDevice{}
140 have, err := agent.clusterDataProxy.Get(ctx, "logical_devices/"+agent.logicalDeviceID, ld)
Thomas Lee Se5a44012019-11-07 20:32:24 +0530141 if err != nil {
khenaidoo442e7c72020-03-10 16:13:48 -0400142 return err
Kent Hagerman4f355f52020-03-30 16:01:33 -0400143 } else if !have {
khenaidoo6e55d9e2019-12-12 18:26:26 -0500144 return status.Errorf(codes.NotFound, "logical_device-%s", agent.logicalDeviceID)
khenaidoo297cd252019-02-07 22:10:23 -0500145 }
Kent Hagerman4f355f52020-03-30 16:01:33 -0400146
khenaidoo8c3303d2019-02-13 14:59:39 -0500147 // Update the root device Id
npujar1d86a522019-11-14 17:11:16 +0530148 agent.rootDeviceID = ld.RootDeviceId
khenaidoo3d3b8c22019-05-22 18:10:39 -0400149
khenaidoo6e55d9e2019-12-12 18:26:26 -0500150 // Update the last data
151 agent.logicalDevice = proto.Clone(ld).(*voltha.LogicalDevice)
152
khenaidoo3d3b8c22019-05-22 18:10:39 -0400153 // Setup the local list of logical ports
154 agent.addLogicalPortsToMap(ld.Ports)
khenaidoob9203542018-09-17 22:56:37 -0400155 }
khenaidoofc1314d2019-03-14 09:34:21 -0400156
khenaidoo820197c2020-02-13 16:35:33 -0500157 // 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 -0400158 if loadFromDB {
khenaidoo820197c2020-02-13 16:35:33 -0500159 go func() {
160 if err := agent.buildRoutes(context.Background()); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000161 logger.Warn("routes-not-ready", log.Fields{"logical-device-id": agent.logicalDeviceID, "error": err})
khenaidoo820197c2020-02-13 16:35:33 -0500162 }
163 }()
khenaidoo4c9e5592019-09-09 16:20:41 -0400164 }
khenaidoo442e7c72020-03-10 16:13:48 -0400165 startSucceeded = true
166
khenaidoob9203542018-09-17 22:56:37 -0400167 return nil
168}
169
khenaidoo442e7c72020-03-10 16:13:48 -0400170// stop stops the logical device agent. This removes the logical device from the data model.
Kent Hagerman2b216042020-04-03 18:28:56 -0400171func (agent *LogicalAgent) stop(ctx context.Context) error {
khenaidoo442e7c72020-03-10 16:13:48 -0400172 var returnErr error
173 agent.stopOnce.Do(func() {
Girish Kumarf56a4682020-03-20 20:07:46 +0000174 logger.Info("stopping-logical_device-agent")
khenaidoo8c3303d2019-02-13 14:59:39 -0500175
khenaidoo442e7c72020-03-10 16:13:48 -0400176 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
177 // This should never happen - an error is returned only if the agent is stopped and an agent is only stopped once.
178 returnErr = err
179 return
180 }
181 defer agent.requestQueue.RequestComplete()
182
183 //Remove the logical device from the model
Kent Hagerman4f355f52020-03-30 16:01:33 -0400184 if err := agent.clusterDataProxy.Remove(ctx, "logical_devices/"+agent.logicalDeviceID); err != nil {
khenaidoo442e7c72020-03-10 16:13:48 -0400185 returnErr = err
khenaidoo442e7c72020-03-10 16:13:48 -0400186 } else {
Girish Kumarf56a4682020-03-20 20:07:46 +0000187 logger.Debugw("logicaldevice-removed", log.Fields{"logicaldeviceId": agent.logicalDeviceID})
khenaidoo442e7c72020-03-10 16:13:48 -0400188 }
189
Kent Hagerman4f355f52020-03-30 16:01:33 -0400190 agent.stopped = true
khenaidoo442e7c72020-03-10 16:13:48 -0400191
Girish Kumarf56a4682020-03-20 20:07:46 +0000192 logger.Info("logical_device-agent-stopped")
khenaidoo442e7c72020-03-10 16:13:48 -0400193 })
194 return returnErr
khenaidoo4d4802d2018-10-04 21:59:49 -0400195}
196
khenaidoo6e55d9e2019-12-12 18:26:26 -0500197// GetLogicalDevice returns the latest logical device data
Kent Hagerman2b216042020-04-03 18:28:56 -0400198func (agent *LogicalAgent) GetLogicalDevice(ctx context.Context) (*voltha.LogicalDevice, error) {
khenaidoo442e7c72020-03-10 16:13:48 -0400199 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
200 return nil, err
201 }
202 defer agent.requestQueue.RequestComplete()
203 return proto.Clone(agent.logicalDevice).(*voltha.LogicalDevice), nil
khenaidoo92e62c52018-10-03 14:02:54 -0400204}
205
npujar1d86a522019-11-14 17:11:16 +0530206// ListLogicalDeviceFlows returns logical device flows
Kent Hagerman2b216042020-04-03 18:28:56 -0400207func (agent *LogicalAgent) ListLogicalDeviceFlows(ctx context.Context) (*ofp.Flows, error) {
Girish Kumarf56a4682020-03-20 20:07:46 +0000208 logger.Debug("ListLogicalDeviceFlows")
khenaidoo6e55d9e2019-12-12 18:26:26 -0500209
khenaidoo442e7c72020-03-10 16:13:48 -0400210 logicalDevice, err := agent.GetLogicalDevice(ctx)
211 if err != nil {
212 return nil, err
khenaidoodd237172019-05-27 16:37:17 -0400213 }
khenaidoo442e7c72020-03-10 16:13:48 -0400214 if logicalDevice.Flows == nil {
215 return &ofp.Flows{}, nil
216 }
217 return (proto.Clone(logicalDevice.Flows)).(*ofp.Flows), nil
khenaidoodd237172019-05-27 16:37:17 -0400218}
219
npujar1d86a522019-11-14 17:11:16 +0530220// ListLogicalDeviceMeters returns logical device meters
Kent Hagerman2b216042020-04-03 18:28:56 -0400221func (agent *LogicalAgent) ListLogicalDeviceMeters(ctx context.Context) (*ofp.Meters, error) {
Girish Kumarf56a4682020-03-20 20:07:46 +0000222 logger.Debug("ListLogicalDeviceMeters")
khenaidoo6e55d9e2019-12-12 18:26:26 -0500223
khenaidoo442e7c72020-03-10 16:13:48 -0400224 logicalDevice, err := agent.GetLogicalDevice(ctx)
225 if err != nil {
226 return nil, err
Manikkaraj kb1a10922019-07-29 12:10:34 -0400227 }
khenaidoo442e7c72020-03-10 16:13:48 -0400228 if logicalDevice.Meters == nil {
229 return &ofp.Meters{}, nil
230 }
231 return (proto.Clone(logicalDevice.Meters)).(*ofp.Meters), nil
Manikkaraj kb1a10922019-07-29 12:10:34 -0400232}
233
npujar1d86a522019-11-14 17:11:16 +0530234// ListLogicalDeviceFlowGroups returns logical device flow groups
Kent Hagerman2b216042020-04-03 18:28:56 -0400235func (agent *LogicalAgent) ListLogicalDeviceFlowGroups(ctx context.Context) (*ofp.FlowGroups, error) {
Girish Kumarf56a4682020-03-20 20:07:46 +0000236 logger.Debug("ListLogicalDeviceFlowGroups")
khenaidoo6e55d9e2019-12-12 18:26:26 -0500237
khenaidoo442e7c72020-03-10 16:13:48 -0400238 logicalDevice, err := agent.GetLogicalDevice(ctx)
239 if err != nil {
240 return nil, err
khenaidoodd237172019-05-27 16:37:17 -0400241 }
khenaidoo442e7c72020-03-10 16:13:48 -0400242 if logicalDevice.FlowGroups == nil {
243 return &ofp.FlowGroups{}, nil
244 }
245 return (proto.Clone(logicalDevice.FlowGroups)).(*ofp.FlowGroups), nil
khenaidoodd237172019-05-27 16:37:17 -0400246}
247
npujar1d86a522019-11-14 17:11:16 +0530248// ListLogicalDevicePorts returns logical device ports
Kent Hagerman2b216042020-04-03 18:28:56 -0400249func (agent *LogicalAgent) ListLogicalDevicePorts(ctx context.Context) (*voltha.LogicalPorts, error) {
Girish Kumarf56a4682020-03-20 20:07:46 +0000250 logger.Debug("ListLogicalDevicePorts")
khenaidoo442e7c72020-03-10 16:13:48 -0400251 logicalDevice, err := agent.GetLogicalDevice(ctx)
252 if err != nil {
253 return nil, err
254 }
255 if logicalDevice == nil {
256 return &voltha.LogicalPorts{}, nil
257 }
khenaidoo6e55d9e2019-12-12 18:26:26 -0500258 lPorts := make([]*voltha.LogicalPort, 0)
259 lPorts = append(lPorts, logicalDevice.Ports...)
khenaidoo442e7c72020-03-10 16:13:48 -0400260 return &voltha.LogicalPorts{Items: lPorts}, nil
khenaidoo19d7b632018-10-30 10:49:50 -0400261}
262
khenaidoo4c9e5592019-09-09 16:20:41 -0400263//updateLogicalDeviceFlowsWithoutLock updates the logical device with the latest flows in the model.
Kent Hagerman2b216042020-04-03 18:28:56 -0400264func (agent *LogicalAgent) updateLogicalDeviceFlowsWithoutLock(ctx context.Context, flows *ofp.Flows) error {
khenaidoo6e55d9e2019-12-12 18:26:26 -0500265 ld := agent.getLogicalDeviceWithoutLock()
khenaidoo4c9e5592019-09-09 16:20:41 -0400266
Girish Kumarf56a4682020-03-20 20:07:46 +0000267 logger.Debugw("logical-device-before", log.Fields{"lports": len(ld.Ports)})
khenaidoo6e55d9e2019-12-12 18:26:26 -0500268 ld.Flows = flows
269
npujar467fe752020-01-16 20:17:45 +0530270 if err := agent.updateLogicalDeviceWithoutLock(ctx, ld); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000271 logger.Errorw("error-updating-logical-device-with-flows", log.Fields{"error": err})
khenaidoo4c9e5592019-09-09 16:20:41 -0400272 return err
khenaidoo43c82122018-11-22 18:38:28 -0500273 }
khenaidoo43c82122018-11-22 18:38:28 -0500274 return nil
275}
276
khenaidoo4c9e5592019-09-09 16:20:41 -0400277//updateLogicalDeviceMetersWithoutLock updates the logical device with the meters info
Kent Hagerman2b216042020-04-03 18:28:56 -0400278func (agent *LogicalAgent) updateLogicalDeviceMetersWithoutLock(ctx context.Context, meters *ofp.Meters) error {
khenaidoo6e55d9e2019-12-12 18:26:26 -0500279 ld := agent.getLogicalDeviceWithoutLock()
khenaidoo4c9e5592019-09-09 16:20:41 -0400280
Girish Kumarf56a4682020-03-20 20:07:46 +0000281 logger.Debugw("logical-device-before", log.Fields{"lports": len(ld.Ports)})
khenaidoo6e55d9e2019-12-12 18:26:26 -0500282 ld.Meters = meters
283
npujar467fe752020-01-16 20:17:45 +0530284 if err := agent.updateLogicalDeviceWithoutLock(ctx, ld); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000285 logger.Errorw("error-updating-logical-device-with-meters", log.Fields{"error": err})
khenaidoo4c9e5592019-09-09 16:20:41 -0400286 return err
Manikkaraj kb1a10922019-07-29 12:10:34 -0400287 }
288 return nil
289}
290
khenaidoo4c9e5592019-09-09 16:20:41 -0400291//updateLogicalDeviceFlowGroupsWithoutLock updates the logical device with the flow groups
Kent Hagerman2b216042020-04-03 18:28:56 -0400292func (agent *LogicalAgent) updateLogicalDeviceFlowGroupsWithoutLock(ctx context.Context, flowGroups *ofp.FlowGroups) error {
khenaidoo6e55d9e2019-12-12 18:26:26 -0500293 ld := agent.getLogicalDeviceWithoutLock()
khenaidoo4c9e5592019-09-09 16:20:41 -0400294
Girish Kumarf56a4682020-03-20 20:07:46 +0000295 logger.Debugw("logical-device-before", log.Fields{"lports": len(ld.Ports)})
khenaidoo6e55d9e2019-12-12 18:26:26 -0500296 ld.FlowGroups = flowGroups
297
npujar467fe752020-01-16 20:17:45 +0530298 if err := agent.updateLogicalDeviceWithoutLock(ctx, ld); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000299 logger.Errorw("error-updating-logical-device-with-flowgroups", log.Fields{"error": err})
khenaidoo4c9e5592019-09-09 16:20:41 -0400300 return err
khenaidoo43c82122018-11-22 18:38:28 -0500301 }
khenaidoo43c82122018-11-22 18:38:28 -0500302 return nil
303}
304
khenaidoo6e55d9e2019-12-12 18:26:26 -0500305// getLogicalDeviceWithoutLock returns a cloned logical device to a function that already holds the agent lock.
Kent Hagerman2b216042020-04-03 18:28:56 -0400306func (agent *LogicalAgent) getLogicalDeviceWithoutLock() *voltha.LogicalDevice {
Girish Kumarf56a4682020-03-20 20:07:46 +0000307 logger.Debug("getLogicalDeviceWithoutLock")
khenaidoo6e55d9e2019-12-12 18:26:26 -0500308 return proto.Clone(agent.logicalDevice).(*voltha.LogicalDevice)
khenaidoo92e62c52018-10-03 14:02:54 -0400309}
310
Kent Hagerman2b216042020-04-03 18:28:56 -0400311func (agent *LogicalAgent) updateLogicalPort(ctx context.Context, device *voltha.Device, port *voltha.Port) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000312 logger.Debugw("updateLogicalPort", log.Fields{"deviceId": device.Id, "port": port})
khenaidoo2c6a0992019-04-29 13:46:56 -0400313 var err error
314 if port.Type == voltha.Port_ETHERNET_NNI {
npujar467fe752020-01-16 20:17:45 +0530315 if _, err = agent.addNNILogicalPort(ctx, device, port); err != nil {
khenaidoo2c6a0992019-04-29 13:46:56 -0400316 return err
317 }
318 agent.addLogicalPortToMap(port.PortNo, true)
319 } else if port.Type == voltha.Port_ETHERNET_UNI {
npujar467fe752020-01-16 20:17:45 +0530320 if _, err = agent.addUNILogicalPort(ctx, device, port); err != nil {
khenaidoo2c6a0992019-04-29 13:46:56 -0400321 return err
322 }
323 agent.addLogicalPortToMap(port.PortNo, false)
324 } else {
khenaidoo820197c2020-02-13 16:35:33 -0500325 // Update the device routes to ensure all routes on the logical device have been calculated
326 if err = agent.buildRoutes(ctx); err != nil {
327 // Not an error - temporary state
Girish Kumarf56a4682020-03-20 20:07:46 +0000328 logger.Warnw("failed-to-update-routes", log.Fields{"device-id": device.Id, "port": port, "error": err})
khenaidoo2c6a0992019-04-29 13:46:56 -0400329 }
330 }
331 return nil
332}
333
khenaidoo3d3b8c22019-05-22 18:10:39 -0400334// setupLogicalPorts is invoked once the logical device has been created and is ready to get ports
335// added to it. While the logical device was being created we could have received requests to add
336// NNI and UNI ports which were discarded. Now is the time to add them if needed
Kent Hagerman2b216042020-04-03 18:28:56 -0400337func (agent *LogicalAgent) setupLogicalPorts(ctx context.Context) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000338 logger.Infow("setupLogicalPorts", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo3d3b8c22019-05-22 18:10:39 -0400339 // First add any NNI ports which could have been missing
npujar467fe752020-01-16 20:17:45 +0530340 if err := agent.setupNNILogicalPorts(ctx, agent.rootDeviceID); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000341 logger.Errorw("error-setting-up-NNI-ports", log.Fields{"error": err, "deviceId": agent.rootDeviceID})
khenaidoo3d3b8c22019-05-22 18:10:39 -0400342 return err
343 }
344
345 // Now, set up the UNI ports if needed.
Kent Hagerman2b216042020-04-03 18:28:56 -0400346 children, err := agent.deviceMgr.GetAllChildDevices(ctx, agent.rootDeviceID)
npujar1d86a522019-11-14 17:11:16 +0530347 if err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000348 logger.Errorw("error-getting-child-devices", log.Fields{"error": err, "deviceId": agent.rootDeviceID})
khenaidoo3d3b8c22019-05-22 18:10:39 -0400349 return err
npujar1d86a522019-11-14 17:11:16 +0530350 }
351 responses := make([]coreutils.Response, 0)
352 for _, child := range children.Items {
353 response := coreutils.NewResponse()
354 responses = append(responses, response)
355 go func(child *voltha.Device) {
khenaidoo442e7c72020-03-10 16:13:48 -0400356 if err = agent.setupUNILogicalPorts(context.Background(), child); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000357 logger.Error("setting-up-UNI-ports-failed", log.Fields{"deviceID": child.Id})
npujar1d86a522019-11-14 17:11:16 +0530358 response.Error(status.Errorf(codes.Internal, "UNI-ports-setup-failed: %s", child.Id))
359 }
360 response.Done()
361 }(child)
362 }
363 // Wait for completion
364 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, responses...); res != nil {
365 return status.Errorf(codes.Aborted, "errors-%s", res)
khenaidoo3d3b8c22019-05-22 18:10:39 -0400366 }
367 return nil
368}
369
khenaidoofc1314d2019-03-14 09:34:21 -0400370// 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 -0400371func (agent *LogicalAgent) setupNNILogicalPorts(ctx context.Context, deviceID string) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000372 logger.Infow("setupNNILogicalPorts-start", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoob9203542018-09-17 22:56:37 -0400373 // Build the logical device based on information retrieved from the device adapter
khenaidoofc1314d2019-03-14 09:34:21 -0400374 var err error
375
376 var device *voltha.Device
npujar467fe752020-01-16 20:17:45 +0530377 if device, err = agent.deviceMgr.GetDevice(ctx, deviceID); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000378 logger.Errorw("error-retrieving-device", log.Fields{"error": err, "deviceId": deviceID})
khenaidoofc1314d2019-03-14 09:34:21 -0400379 return err
380 }
381
382 //Get UNI port number
khenaidoofc1314d2019-03-14 09:34:21 -0400383 for _, port := range device.Ports {
384 if port.Type == voltha.Port_ETHERNET_NNI {
npujar467fe752020-01-16 20:17:45 +0530385 if _, err = agent.addNNILogicalPort(ctx, device, port); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000386 logger.Errorw("error-adding-UNI-port", log.Fields{"error": err})
khenaidoofc1314d2019-03-14 09:34:21 -0400387 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400388 agent.addLogicalPortToMap(port.PortNo, true)
khenaidoofc1314d2019-03-14 09:34:21 -0400389 }
390 }
khenaidoofc1314d2019-03-14 09:34:21 -0400391 return err
392}
393
khenaidoo171b98e2019-10-31 11:48:15 -0400394// updatePortState updates the port state of the device
Kent Hagerman2b216042020-04-03 18:28:56 -0400395func (agent *LogicalAgent) updatePortState(ctx context.Context, deviceID string, portNo uint32, operStatus voltha.OperStatus_Types) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000396 logger.Infow("updatePortState-start", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "portNo": portNo, "state": operStatus})
khenaidoo442e7c72020-03-10 16:13:48 -0400397 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
398 return err
399 }
400 defer agent.requestQueue.RequestComplete()
khenaidoo171b98e2019-10-31 11:48:15 -0400401 // Get the latest logical device info
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500402 original := agent.getLogicalDeviceWithoutLock()
403 updatedPorts := clonePorts(original.Ports)
404 for _, port := range updatedPorts {
405 if port.DeviceId == deviceID && port.DevicePortNo == portNo {
npujar1d86a522019-11-14 17:11:16 +0530406 if operStatus == voltha.OperStatus_ACTIVE {
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500407 port.OfpPort.Config = port.OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
408 port.OfpPort.State = uint32(ofp.OfpPortState_OFPPS_LIVE)
npujar1d86a522019-11-14 17:11:16 +0530409 } else {
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500410 port.OfpPort.Config = port.OfpPort.Config | uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
411 port.OfpPort.State = uint32(ofp.OfpPortState_OFPPS_LINK_DOWN)
npujar1d86a522019-11-14 17:11:16 +0530412 }
413 // Update the logical device
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500414 if err := agent.updateLogicalDevicePortsWithoutLock(ctx, original, updatedPorts); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000415 logger.Errorw("error-updating-logical-device", log.Fields{"error": err})
npujar1d86a522019-11-14 17:11:16 +0530416 return err
417 }
418 return nil
419 }
420 }
421 return status.Errorf(codes.NotFound, "port-%d-not-exist", portNo)
khenaidoo171b98e2019-10-31 11:48:15 -0400422}
423
khenaidoo3ab34882019-05-02 21:33:30 -0400424// updatePortsState updates the ports state related to the device
Kent Hagerman2b216042020-04-03 18:28:56 -0400425func (agent *LogicalAgent) updatePortsState(ctx context.Context, device *voltha.Device, state voltha.OperStatus_Types) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000426 logger.Infow("updatePortsState-start", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo442e7c72020-03-10 16:13:48 -0400427 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
428 return err
429 }
430 defer agent.requestQueue.RequestComplete()
khenaidoo3ab34882019-05-02 21:33:30 -0400431 // Get the latest logical device info
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500432 original := agent.getLogicalDeviceWithoutLock()
433 updatedPorts := clonePorts(original.Ports)
434 for _, port := range updatedPorts {
435 if port.DeviceId == device.Id {
kesavandbc2d1622020-01-21 00:42:01 -0500436 if state == voltha.OperStatus_ACTIVE {
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500437 port.OfpPort.Config = port.OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
438 port.OfpPort.State = uint32(ofp.OfpPortState_OFPPS_LIVE)
kesavandbc2d1622020-01-21 00:42:01 -0500439 } else {
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500440 port.OfpPort.Config = port.OfpPort.Config | uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
441 port.OfpPort.State = uint32(ofp.OfpPortState_OFPPS_LINK_DOWN)
khenaidoo3ab34882019-05-02 21:33:30 -0400442 }
443 }
npujar1d86a522019-11-14 17:11:16 +0530444 }
445 // Updating the logical device will trigger the poprt change events to be populated to the controller
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500446 if err := agent.updateLogicalDevicePortsWithoutLock(ctx, original, updatedPorts); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000447 logger.Warnw("logical-device-update-failed", log.Fields{"ldeviceId": agent.logicalDeviceID, "error": err})
npujar1d86a522019-11-14 17:11:16 +0530448 return err
khenaidoo3ab34882019-05-02 21:33:30 -0400449 }
450 return nil
451}
452
khenaidoofc1314d2019-03-14 09:34:21 -0400453// setupUNILogicalPorts creates a UNI port on the logical device that represents a child UNI interface
Kent Hagerman2b216042020-04-03 18:28:56 -0400454func (agent *LogicalAgent) setupUNILogicalPorts(ctx context.Context, childDevice *voltha.Device) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000455 logger.Infow("setupUNILogicalPort", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoofc1314d2019-03-14 09:34:21 -0400456 // Build the logical device based on information retrieved from the device adapter
khenaidoob9203542018-09-17 22:56:37 -0400457 var err error
khenaidoo59ef7be2019-06-21 12:40:28 -0400458 var added bool
khenaidoo19d7b632018-10-30 10:49:50 -0400459 //Get UNI port number
khenaidoo19d7b632018-10-30 10:49:50 -0400460 for _, port := range childDevice.Ports {
461 if port.Type == voltha.Port_ETHERNET_UNI {
npujar467fe752020-01-16 20:17:45 +0530462 if added, err = agent.addUNILogicalPort(ctx, childDevice, port); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000463 logger.Errorw("error-adding-UNI-port", log.Fields{"error": err})
khenaidoofc1314d2019-03-14 09:34:21 -0400464 }
khenaidoo59ef7be2019-06-21 12:40:28 -0400465 if added {
466 agent.addLogicalPortToMap(port.PortNo, false)
467 }
khenaidoo19d7b632018-10-30 10:49:50 -0400468 }
469 }
khenaidoofc1314d2019-03-14 09:34:21 -0400470 return err
khenaidoo92e62c52018-10-03 14:02:54 -0400471}
472
Girish Gowdra408cd962020-03-11 14:31:31 -0700473// deleteAllLogicalPorts deletes all logical ports associated with this logical device
Kent Hagerman2b216042020-04-03 18:28:56 -0400474func (agent *LogicalAgent) deleteAllLogicalPorts(ctx context.Context) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000475 logger.Infow("updatePortsState-start", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo442e7c72020-03-10 16:13:48 -0400476 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
477 return err
478 }
479 defer agent.requestQueue.RequestComplete()
khenaidoo0a822f92019-05-08 15:15:57 -0400480 // Get the latest logical device info
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500481 cloned := agent.getLogicalDeviceWithoutLock()
khenaidoo6e55d9e2019-12-12 18:26:26 -0500482
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500483 if err := agent.updateLogicalDevicePortsWithoutLock(ctx, cloned, []*voltha.LogicalPort{}); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000484 logger.Warnw("logical-device-update-failed", log.Fields{"ldeviceId": agent.logicalDeviceID, "error": err})
Girish Gowdra408cd962020-03-11 14:31:31 -0700485 return err
khenaidoo0a822f92019-05-08 15:15:57 -0400486 }
487 return nil
488}
489
Hardik Windlassc704def2020-02-26 18:23:19 +0000490// deleteAllUNILogicalPorts deletes all UNI logical ports associated with this parent device
Kent Hagerman2b216042020-04-03 18:28:56 -0400491func (agent *LogicalAgent) deleteAllUNILogicalPorts(ctx context.Context, parentDevice *voltha.Device) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000492 logger.Debugw("delete-all-uni-logical-ports", log.Fields{"logical-device-id": agent.logicalDeviceID})
khenaidoo442e7c72020-03-10 16:13:48 -0400493 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
494 return err
495 }
496 defer agent.requestQueue.RequestComplete()
Hardik Windlassc704def2020-02-26 18:23:19 +0000497 // Get the latest logical device info
498 ld := agent.getLogicalDeviceWithoutLock()
499
Hardik Windlassc704def2020-02-26 18:23:19 +0000500 updateLogicalPorts := []*voltha.LogicalPort{}
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500501 for _, lport := range ld.Ports {
Hardik Windlassc704def2020-02-26 18:23:19 +0000502 // Save NNI ports only
503 if agent.isNNIPort(lport.DevicePortNo) {
504 updateLogicalPorts = append(updateLogicalPorts, lport)
505 }
506 }
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500507 if len(updateLogicalPorts) < len(ld.Ports) {
Hardik Windlassc704def2020-02-26 18:23:19 +0000508 // Updating the logical device will trigger the port change events to be populated to the controller
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500509 if err := agent.updateLogicalDevicePortsWithoutLock(ctx, ld, updateLogicalPorts); err != nil {
Hardik Windlassc704def2020-02-26 18:23:19 +0000510 return err
511 }
512 } else {
Girish Kumarf56a4682020-03-20 20:07:46 +0000513 logger.Debugw("no-change-required", log.Fields{"logical-device-id": agent.logicalDeviceID})
Hardik Windlassc704def2020-02-26 18:23:19 +0000514 }
515 return nil
516}
517
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500518func clonePorts(ports []*voltha.LogicalPort) []*voltha.LogicalPort {
519 return proto.Clone(&voltha.LogicalPorts{Items: ports}).(*voltha.LogicalPorts).Items
520}
521
522//updateLogicalDevicePortsWithoutLock updates the
Kent Hagerman2b216042020-04-03 18:28:56 -0400523func (agent *LogicalAgent) updateLogicalDevicePortsWithoutLock(ctx context.Context, device *voltha.LogicalDevice, newPorts []*voltha.LogicalPort) error {
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500524 oldPorts := device.Ports
525 device.Ports = newPorts
526 if err := agent.updateLogicalDeviceWithoutLock(ctx, device); err != nil {
527 return err
528 }
529 agent.portUpdated(oldPorts, newPorts)
530 return nil
531}
532
khenaidoo92e62c52018-10-03 14:02:54 -0400533//updateLogicalDeviceWithoutLock updates the model with the logical device. It clones the logicaldevice before saving it
Kent Hagerman2b216042020-04-03 18:28:56 -0400534func (agent *LogicalAgent) updateLogicalDeviceWithoutLock(ctx context.Context, logicalDevice *voltha.LogicalDevice) error {
Kent Hagerman4f355f52020-03-30 16:01:33 -0400535 if agent.stopped {
536 return errors.New("logical device agent stopped")
537 }
538
npujar467fe752020-01-16 20:17:45 +0530539 updateCtx := context.WithValue(ctx, model.RequestTimestamp, time.Now().UnixNano())
Kent Hagerman4f355f52020-03-30 16:01:33 -0400540 if err := agent.clusterDataProxy.Update(updateCtx, "logical_devices/"+agent.logicalDeviceID, logicalDevice); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000541 logger.Errorw("failed-to-update-logical-devices-to-cluster-proxy", log.Fields{"error": err})
Thomas Lee Se5a44012019-11-07 20:32:24 +0530542 return err
543 }
Kent Hagerman4f355f52020-03-30 16:01:33 -0400544
khenaidoo442e7c72020-03-10 16:13:48 -0400545 agent.logicalDevice = logicalDevice
546
khenaidoo92e62c52018-10-03 14:02:54 -0400547 return nil
548}
549
khenaidoo820197c2020-02-13 16:35:33 -0500550//generateDeviceRoutesIfNeeded generates the device routes if the logical device has been updated since the last time
khenaidoo4c9e5592019-09-09 16:20:41 -0400551//that device graph was generated.
Kent Hagerman2b216042020-04-03 18:28:56 -0400552func (agent *LogicalAgent) generateDeviceRoutesIfNeeded(ctx context.Context) error {
khenaidoo820197c2020-02-13 16:35:33 -0500553 agent.lockDeviceRoutes.Lock()
554 defer agent.lockDeviceRoutes.Unlock()
555
khenaidoo442e7c72020-03-10 16:13:48 -0400556 ld, err := agent.GetLogicalDevice(ctx)
557 if err != nil {
558 return err
559 }
khenaidoo820197c2020-02-13 16:35:33 -0500560
561 if agent.deviceRoutes != nil && agent.deviceRoutes.IsUpToDate(ld) {
npujar1d86a522019-11-14 17:11:16 +0530562 return nil
563 }
Girish Kumarf56a4682020-03-20 20:07:46 +0000564 logger.Debug("Generation of device route required")
khenaidoo820197c2020-02-13 16:35:33 -0500565 if err := agent.buildRoutes(ctx); err != nil {
khenaidoo787224a2020-04-16 18:08:47 -0400566 // No Route is not an error
567 if !errors.Is(err, route.ErrNoRoute) {
568 return err
569 }
khenaidoo820197c2020-02-13 16:35:33 -0500570 }
khenaidoo4c9e5592019-09-09 16:20:41 -0400571 return nil
572}
573
khenaidoo19d7b632018-10-30 10:49:50 -0400574//updateFlowTable updates the flow table of that logical device
Kent Hagerman2b216042020-04-03 18:28:56 -0400575func (agent *LogicalAgent) updateFlowTable(ctx context.Context, flow *ofp.OfpFlowMod) error {
576 logger.Debug("UpdateFlowTable")
khenaidoo19d7b632018-10-30 10:49:50 -0400577 if flow == nil {
578 return nil
579 }
khenaidoo820197c2020-02-13 16:35:33 -0500580 if err := agent.generateDeviceRoutesIfNeeded(ctx); err != nil {
khenaidoo4c9e5592019-09-09 16:20:41 -0400581 return err
582 }
khenaidoo19d7b632018-10-30 10:49:50 -0400583 switch flow.GetCommand() {
584 case ofp.OfpFlowModCommand_OFPFC_ADD:
npujar467fe752020-01-16 20:17:45 +0530585 return agent.flowAdd(ctx, flow)
khenaidoo19d7b632018-10-30 10:49:50 -0400586 case ofp.OfpFlowModCommand_OFPFC_DELETE:
npujar467fe752020-01-16 20:17:45 +0530587 return agent.flowDelete(ctx, flow)
khenaidoo19d7b632018-10-30 10:49:50 -0400588 case ofp.OfpFlowModCommand_OFPFC_DELETE_STRICT:
npujar467fe752020-01-16 20:17:45 +0530589 return agent.flowDeleteStrict(ctx, flow)
khenaidoo19d7b632018-10-30 10:49:50 -0400590 case ofp.OfpFlowModCommand_OFPFC_MODIFY:
591 return agent.flowModify(flow)
592 case ofp.OfpFlowModCommand_OFPFC_MODIFY_STRICT:
593 return agent.flowModifyStrict(flow)
594 }
595 return status.Errorf(codes.Internal,
npujar1d86a522019-11-14 17:11:16 +0530596 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceID, flow.GetCommand())
khenaidoo19d7b632018-10-30 10:49:50 -0400597}
598
599//updateGroupTable updates the group table of that logical device
Kent Hagerman2b216042020-04-03 18:28:56 -0400600func (agent *LogicalAgent) updateGroupTable(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000601 logger.Debug("updateGroupTable")
khenaidoo19d7b632018-10-30 10:49:50 -0400602 if groupMod == nil {
603 return nil
604 }
khenaidoo820197c2020-02-13 16:35:33 -0500605 if err := agent.generateDeviceRoutesIfNeeded(ctx); err != nil {
khenaidoo4c9e5592019-09-09 16:20:41 -0400606 return err
607 }
khenaidoo820197c2020-02-13 16:35:33 -0500608
khenaidoo19d7b632018-10-30 10:49:50 -0400609 switch groupMod.GetCommand() {
610 case ofp.OfpGroupModCommand_OFPGC_ADD:
npujar467fe752020-01-16 20:17:45 +0530611 return agent.groupAdd(ctx, groupMod)
khenaidoo19d7b632018-10-30 10:49:50 -0400612 case ofp.OfpGroupModCommand_OFPGC_DELETE:
npujar467fe752020-01-16 20:17:45 +0530613 return agent.groupDelete(ctx, groupMod)
khenaidoo19d7b632018-10-30 10:49:50 -0400614 case ofp.OfpGroupModCommand_OFPGC_MODIFY:
npujar467fe752020-01-16 20:17:45 +0530615 return agent.groupModify(ctx, groupMod)
khenaidoo19d7b632018-10-30 10:49:50 -0400616 }
617 return status.Errorf(codes.Internal,
npujar1d86a522019-11-14 17:11:16 +0530618 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceID, groupMod.GetCommand())
khenaidoo19d7b632018-10-30 10:49:50 -0400619}
620
Manikkaraj kb1a10922019-07-29 12:10:34 -0400621// updateMeterTable updates the meter table of that logical device
Kent Hagerman2b216042020-04-03 18:28:56 -0400622func (agent *LogicalAgent) updateMeterTable(ctx context.Context, meterMod *ofp.OfpMeterMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000623 logger.Debug("updateMeterTable")
Manikkaraj kb1a10922019-07-29 12:10:34 -0400624 if meterMod == nil {
625 return nil
626 }
627 switch meterMod.GetCommand() {
628 case ofp.OfpMeterModCommand_OFPMC_ADD:
npujar467fe752020-01-16 20:17:45 +0530629 return agent.meterAdd(ctx, meterMod)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400630 case ofp.OfpMeterModCommand_OFPMC_DELETE:
npujar467fe752020-01-16 20:17:45 +0530631 return agent.meterDelete(ctx, meterMod)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400632 case ofp.OfpMeterModCommand_OFPMC_MODIFY:
npujar467fe752020-01-16 20:17:45 +0530633 return agent.meterModify(ctx, meterMod)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400634 }
635 return status.Errorf(codes.Internal,
npujar1d86a522019-11-14 17:11:16 +0530636 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceID, meterMod.GetCommand())
Manikkaraj kb1a10922019-07-29 12:10:34 -0400637
638}
639
Kent Hagerman2b216042020-04-03 18:28:56 -0400640func (agent *LogicalAgent) meterAdd(ctx context.Context, meterMod *ofp.OfpMeterMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000641 logger.Debugw("meterAdd", log.Fields{"metermod": *meterMod})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400642 if meterMod == nil {
643 return nil
644 }
khenaidoo442e7c72020-03-10 16:13:48 -0400645 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
646 return err
647 }
648 defer agent.requestQueue.RequestComplete()
Girish Kumarf56a4682020-03-20 20:07:46 +0000649 logger.Debug("Acquired logical device lock")
khenaidoo6e55d9e2019-12-12 18:26:26 -0500650 lDevice := agent.getLogicalDeviceWithoutLock()
Manikkaraj kb1a10922019-07-29 12:10:34 -0400651
652 var meters []*ofp.OfpMeterEntry
653 if lDevice.Meters != nil && lDevice.Meters.Items != nil {
654 meters = lDevice.Meters.Items
655 }
Girish Kumarf56a4682020-03-20 20:07:46 +0000656 logger.Debugw("Available meters", log.Fields{"meters": meters})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400657
658 for _, meter := range meters {
659 if meterMod.MeterId == meter.Config.MeterId {
Girish Kumarf56a4682020-03-20 20:07:46 +0000660 logger.Infow("Meter-already-exists", log.Fields{"meter": *meterMod})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400661 return nil
662 }
663 }
664
665 meterEntry := fu.MeterEntryFromMeterMod(meterMod)
666 meters = append(meters, meterEntry)
667 //Update model
npujar467fe752020-01-16 20:17:45 +0530668 if err := agent.updateLogicalDeviceMetersWithoutLock(ctx, &ofp.Meters{Items: meters}); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000669 logger.Errorw("db-meter-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400670 return err
671 }
Girish Kumarf56a4682020-03-20 20:07:46 +0000672 logger.Debugw("Meter-added-successfully", log.Fields{"Added-meter": meterEntry, "updated-meters": lDevice.Meters})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400673 return nil
674}
675
Kent Hagerman2b216042020-04-03 18:28:56 -0400676func (agent *LogicalAgent) meterDelete(ctx context.Context, meterMod *ofp.OfpMeterMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000677 logger.Debug("meterDelete", log.Fields{"meterMod": *meterMod})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400678 if meterMod == nil {
679 return nil
680 }
khenaidoo442e7c72020-03-10 16:13:48 -0400681 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
682 return err
683 }
684 defer agent.requestQueue.RequestComplete()
Manikkaraj kb1a10922019-07-29 12:10:34 -0400685
khenaidoo6e55d9e2019-12-12 18:26:26 -0500686 lDevice := agent.getLogicalDeviceWithoutLock()
Manikkaraj kb1a10922019-07-29 12:10:34 -0400687
688 var meters []*ofp.OfpMeterEntry
689 var flows []*ofp.OfpFlowStats
690 updatedFlows := make([]*ofp.OfpFlowStats, 0)
691 if lDevice.Meters != nil && lDevice.Meters.Items != nil {
692 meters = lDevice.Meters.Items
693 }
Manikkaraj kb1a10922019-07-29 12:10:34 -0400694
695 changedMeter := false
696 changedFow := false
Girish Kumarf56a4682020-03-20 20:07:46 +0000697 logger.Debugw("Available meters", log.Fields{"meters": meters})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400698 for index, meter := range meters {
699 if meterMod.MeterId == meter.Config.MeterId {
700 flows = lDevice.Flows.Items
npujar1d86a522019-11-14 17:11:16 +0530701 changedFow, updatedFlows = agent.getUpdatedFlowsAfterDeletebyMeterID(flows, meterMod.MeterId)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400702 meters = append(meters[:index], meters[index+1:]...)
Girish Kumarf56a4682020-03-20 20:07:46 +0000703 logger.Debugw("Meter has been deleted", log.Fields{"meter": meter, "index": index})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400704 changedMeter = true
705 break
706 }
707 }
708 if changedMeter {
709 //Update model
710 metersToUpdate := &ofp.Meters{}
711 if lDevice.Meters != nil {
712 metersToUpdate = &ofp.Meters{Items: meters}
713 }
npujar467fe752020-01-16 20:17:45 +0530714 if err := agent.updateLogicalDeviceMetersWithoutLock(ctx, metersToUpdate); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000715 logger.Errorw("db-meter-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400716 return err
717 }
Girish Kumarf56a4682020-03-20 20:07:46 +0000718 logger.Debug("Meter-deleted-from-DB-successfully", log.Fields{"updatedMeters": metersToUpdate, "no-of-meter": len(metersToUpdate.Items)})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400719
720 }
721 if changedFow {
722 //Update model
npujar467fe752020-01-16 20:17:45 +0530723 if err := agent.updateLogicalDeviceFlowsWithoutLock(ctx, &ofp.Flows{Items: updatedFlows}); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000724 logger.Errorw("db-flow-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400725 return err
726 }
Girish Kumarf56a4682020-03-20 20:07:46 +0000727 logger.Debug("Flows-associated-with-meter-deleted-from-DB-successfully",
Manikkaraj kb1a10922019-07-29 12:10:34 -0400728 log.Fields{"updated-no-of-flows": len(updatedFlows), "meter": meterMod.MeterId})
729 }
Girish Kumarf56a4682020-03-20 20:07:46 +0000730 logger.Debugw("meterDelete success", log.Fields{"meterID": meterMod.MeterId})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400731 return nil
732}
733
Kent Hagerman2b216042020-04-03 18:28:56 -0400734func (agent *LogicalAgent) meterModify(ctx context.Context, meterMod *ofp.OfpMeterMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000735 logger.Debug("meterModify")
Manikkaraj kb1a10922019-07-29 12:10:34 -0400736 if meterMod == nil {
737 return nil
738 }
khenaidoo442e7c72020-03-10 16:13:48 -0400739 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
740 return err
741 }
742 defer agent.requestQueue.RequestComplete()
Manikkaraj kb1a10922019-07-29 12:10:34 -0400743
khenaidoo6e55d9e2019-12-12 18:26:26 -0500744 lDevice := agent.getLogicalDeviceWithoutLock()
Manikkaraj kb1a10922019-07-29 12:10:34 -0400745
746 var meters []*ofp.OfpMeterEntry
747 if lDevice.Meters != nil && lDevice.Meters.Items != nil {
748 meters = lDevice.Meters.Items
749 }
750 changedMeter := false
751 for index, meter := range meters {
752 if meterMod.MeterId == meter.Config.MeterId {
753 newmeterEntry := fu.MeterEntryFromMeterMod(meterMod)
754 newmeterEntry.Stats.FlowCount = meter.Stats.FlowCount
755 meters[index] = newmeterEntry
756 changedMeter = true
Girish Kumarf56a4682020-03-20 20:07:46 +0000757 logger.Debugw("Found meter, replaced with new meter", log.Fields{"old meter": meter, "new meter": newmeterEntry})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400758 break
759 }
760 }
761 if changedMeter {
762 //Update model
763 metersToUpdate := &ofp.Meters{}
764 if lDevice.Meters != nil {
765 metersToUpdate = &ofp.Meters{Items: meters}
766 }
npujar467fe752020-01-16 20:17:45 +0530767 if err := agent.updateLogicalDeviceMetersWithoutLock(ctx, metersToUpdate); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000768 logger.Errorw("db-meter-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400769 return err
770 }
Girish Kumarf56a4682020-03-20 20:07:46 +0000771 logger.Debugw("meter-updated-in-DB-successfully", log.Fields{"updated_meters": meters})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400772 return nil
773 }
774
Girish Kumarf56a4682020-03-20 20:07:46 +0000775 logger.Errorw("Meter not found ", log.Fields{"meter": meterMod})
npujar1d86a522019-11-14 17:11:16 +0530776 return fmt.Errorf("no-logical-device-present:%d", meterMod.MeterId)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400777
778}
779
Kent Hagerman2b216042020-04-03 18:28:56 -0400780func (agent *LogicalAgent) getUpdatedFlowsAfterDeletebyMeterID(flows []*ofp.OfpFlowStats, meterID uint32) (bool, []*ofp.OfpFlowStats) {
Girish Kumarf56a4682020-03-20 20:07:46 +0000781 logger.Infow("Delete flows matching meter", log.Fields{"meter": meterID})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400782 changed := false
783 //updatedFlows := make([]*ofp.OfpFlowStats, 0)
784 for index := len(flows) - 1; index >= 0; index-- {
npujar1d86a522019-11-14 17:11:16 +0530785 if mID := fu.GetMeterIdFromFlow(flows[index]); mID != 0 && mID == meterID {
Girish Kumarf56a4682020-03-20 20:07:46 +0000786 logger.Debugw("Flow to be deleted", log.Fields{"flow": flows[index], "index": index})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400787 flows = append(flows[:index], flows[index+1:]...)
788 changed = true
789 }
790 }
791 return changed, flows
792}
793
Kent Hagerman2b216042020-04-03 18:28:56 -0400794func (agent *LogicalAgent) updateFlowCountOfMeterStats(modCommand *ofp.OfpFlowMod, meters []*ofp.OfpMeterEntry, flow *ofp.OfpFlowStats) bool {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400795
796 flowCommand := modCommand.GetCommand()
npujar1d86a522019-11-14 17:11:16 +0530797 meterID := fu.GetMeterIdFromFlow(flow)
Girish Kumarf56a4682020-03-20 20:07:46 +0000798 logger.Debugw("Meter-id-in-flow-mod", log.Fields{"meterId": meterID})
npujar1d86a522019-11-14 17:11:16 +0530799 if meterID == 0 {
Girish Kumarf56a4682020-03-20 20:07:46 +0000800 logger.Debugw("No meter present in the flow", log.Fields{"flow": *flow})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400801 return false
802 }
803 if meters == nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000804 logger.Debug("No meters present in logical device")
Manikkaraj kb1a10922019-07-29 12:10:34 -0400805 return false
806 }
807 changedMeter := false
808 for _, meter := range meters {
npujar1d86a522019-11-14 17:11:16 +0530809 if meterID == meter.Config.MeterId { // Found meter in Logicaldevice
Manikkaraj kb1a10922019-07-29 12:10:34 -0400810 if flowCommand == ofp.OfpFlowModCommand_OFPFC_ADD {
npujar1d86a522019-11-14 17:11:16 +0530811 meter.Stats.FlowCount++
Manikkaraj kb1a10922019-07-29 12:10:34 -0400812 changedMeter = true
813 } else if flowCommand == ofp.OfpFlowModCommand_OFPFC_DELETE_STRICT {
npujar1d86a522019-11-14 17:11:16 +0530814 meter.Stats.FlowCount--
Manikkaraj kb1a10922019-07-29 12:10:34 -0400815 changedMeter = true
816 }
Girish Kumarf56a4682020-03-20 20:07:46 +0000817 logger.Debugw("Found meter, updated meter flow stats", log.Fields{" meterId": meterID})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400818 break
819 }
820 }
821 return changedMeter
822}
823
khenaidoo19d7b632018-10-30 10:49:50 -0400824//flowAdd adds a flow to the flow table of that logical device
Kent Hagerman2b216042020-04-03 18:28:56 -0400825func (agent *LogicalAgent) flowAdd(ctx context.Context, mod *ofp.OfpFlowMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000826 logger.Debugw("flowAdd", log.Fields{"flow": mod})
khenaidoo19d7b632018-10-30 10:49:50 -0400827 if mod == nil {
828 return nil
829 }
khenaidoo442e7c72020-03-10 16:13:48 -0400830 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
831 return err
832 }
833 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -0400834
khenaidoo6e55d9e2019-12-12 18:26:26 -0500835 lDevice := agent.getLogicalDeviceWithoutLock()
khenaidoo19d7b632018-10-30 10:49:50 -0400836
837 var flows []*ofp.OfpFlowStats
Manikkaraj kb1a10922019-07-29 12:10:34 -0400838 var meters []*ofp.OfpMeterEntry
839 var flow *ofp.OfpFlowStats
Scott Bakerfdea1e32020-02-21 15:35:41 -0800840 var err error
Manikkaraj kb1a10922019-07-29 12:10:34 -0400841
khenaidoo19d7b632018-10-30 10:49:50 -0400842 if lDevice.Flows != nil && lDevice.Flows.Items != nil {
843 flows = lDevice.Flows.Items
844 }
845
Manikkaraj kb1a10922019-07-29 12:10:34 -0400846 if lDevice.Meters != nil && lDevice.Meters.Items != nil {
847 meters = lDevice.Meters.Items
848 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400849 updatedFlows := make([]*ofp.OfpFlowStats, 0)
khenaidoo19d7b632018-10-30 10:49:50 -0400850 changed := false
Manikkaraj kb1a10922019-07-29 12:10:34 -0400851 updated := false
khenaidoo19d7b632018-10-30 10:49:50 -0400852 checkOverlap := (mod.Flags & uint32(ofp.OfpFlowModFlags_OFPFF_CHECK_OVERLAP)) != 0
853 if checkOverlap {
854 if overlapped := fu.FindOverlappingFlows(flows, mod); len(overlapped) != 0 {
855 // TODO: should this error be notified other than being logged?
Girish Kumarf56a4682020-03-20 20:07:46 +0000856 logger.Warnw("overlapped-flows", log.Fields{"logicaldeviceId": agent.logicalDeviceID})
khenaidoo19d7b632018-10-30 10:49:50 -0400857 } else {
Matt Jeanneret518b5a42019-10-29 10:30:46 -0400858 // Add flow
Scott Bakerfdea1e32020-02-21 15:35:41 -0800859 flow, err = fu.FlowStatsEntryFromFlowModMessage(mod)
860 if err != nil {
861 return err
862 }
khenaidoo19d7b632018-10-30 10:49:50 -0400863 flows = append(flows, flow)
khenaidoo2c6a0992019-04-29 13:46:56 -0400864 updatedFlows = append(updatedFlows, flow)
khenaidoo19d7b632018-10-30 10:49:50 -0400865 changed = true
866 }
867 } else {
Scott Bakerfdea1e32020-02-21 15:35:41 -0800868 flow, err = fu.FlowStatsEntryFromFlowModMessage(mod)
869 if err != nil {
870 return err
871 }
khenaidoo19d7b632018-10-30 10:49:50 -0400872 idx := fu.FindFlows(flows, flow)
873 if idx >= 0 {
874 oldFlow := flows[idx]
875 if (mod.Flags & uint32(ofp.OfpFlowModFlags_OFPFF_RESET_COUNTS)) != 0 {
876 flow.ByteCount = oldFlow.ByteCount
877 flow.PacketCount = oldFlow.PacketCount
878 }
Matt Jeanneret518b5a42019-10-29 10:30:46 -0400879 if !reflect.DeepEqual(oldFlow, flow) {
880 flows[idx] = flow
881 updatedFlows = append(updatedFlows, flow)
882 changed = true
883 updated = true
884 }
885 } else {
khenaidoo19d7b632018-10-30 10:49:50 -0400886 flows = append(flows, flow)
khenaidoo2c6a0992019-04-29 13:46:56 -0400887 updatedFlows = append(updatedFlows, flow)
888 changed = true
khenaidoo19d7b632018-10-30 10:49:50 -0400889 }
khenaidoo19d7b632018-10-30 10:49:50 -0400890 }
Girish Kumarf56a4682020-03-20 20:07:46 +0000891 logger.Debugw("flowAdd-changed", log.Fields{"changed": changed})
khenaidoo4c9e5592019-09-09 16:20:41 -0400892
khenaidoo19d7b632018-10-30 10:49:50 -0400893 if changed {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400894 var flowMetadata voltha.FlowMetadata
895 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 +0000896 logger.Error("Meter-referred-in-flows-not-present")
Manikkaraj kb1a10922019-07-29 12:10:34 -0400897 return err
898 }
khenaidoo820197c2020-02-13 16:35:33 -0500899 deviceRules, err := agent.flowDecomposer.DecomposeRules(ctx, agent, ofp.Flows{Items: updatedFlows}, *lDevice.FlowGroups)
900 if err != nil {
901 return err
902 }
Girish Kumarf56a4682020-03-20 20:07:46 +0000903 logger.Debugw("rules", log.Fields{"rules": deviceRules.String()})
khenaidoo0458db62019-06-20 08:50:36 -0400904
khenaidoo19d7b632018-10-30 10:49:50 -0400905 // Update model
npujar467fe752020-01-16 20:17:45 +0530906 if err := agent.updateLogicalDeviceFlowsWithoutLock(ctx, &ofp.Flows{Items: flows}); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000907 logger.Errorw("db-flow-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo19d7b632018-10-30 10:49:50 -0400908 return err
909 }
Matt Jeanneret518b5a42019-10-29 10:30:46 -0400910 if !updated {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400911 changedMeterStats := agent.updateFlowCountOfMeterStats(mod, meters, flow)
912 metersToUpdate := &ofp.Meters{}
913 if lDevice.Meters != nil {
914 metersToUpdate = &ofp.Meters{Items: meters}
915 }
916 if changedMeterStats {
917 //Update model
npujar467fe752020-01-16 20:17:45 +0530918 if err := agent.updateLogicalDeviceMetersWithoutLock(ctx, metersToUpdate); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000919 logger.Errorw("db-meter-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400920 return err
921 }
Girish Kumarf56a4682020-03-20 20:07:46 +0000922 logger.Debugw("meter-stats-updated-in-DB-successfully", log.Fields{"updated_meters": meters})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400923
924 }
925 }
khenaidoo442e7c72020-03-10 16:13:48 -0400926 // Send the flows to the devices
927 respChannels := agent.addFlowsAndGroupsToDevices(ctx, deviceRules, &flowMetadata)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400928
khenaidoo442e7c72020-03-10 16:13:48 -0400929 // Create the go routines to wait
930 go func() {
931 // Wait for completion
932 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChannels...); res != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000933 logger.Warnw("failure-to-add-flows", log.Fields{"errors": res, "logical-device-id": agent.logicalDeviceID})
khenaidoo442e7c72020-03-10 16:13:48 -0400934 // TODO : revert added flow
935 }
936 }()
khenaidoo19d7b632018-10-30 10:49:50 -0400937 }
khenaidoo19d7b632018-10-30 10:49:50 -0400938 return nil
939}
940
npujar1d86a522019-11-14 17:11:16 +0530941// GetMeterConfig returns meter config
Kent Hagerman2b216042020-04-03 18:28:56 -0400942func (agent *LogicalAgent) GetMeterConfig(flows []*ofp.OfpFlowStats, meters []*ofp.OfpMeterEntry, metadata *voltha.FlowMetadata) error {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400943 m := make(map[uint32]bool)
944 for _, flow := range flows {
npujar1d86a522019-11-14 17:11:16 +0530945 if flowMeterID := fu.GetMeterIdFromFlow(flow); flowMeterID != 0 && !m[flowMeterID] {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400946 foundMeter := false
947 // Meter is present in the flow , Get from logical device
948 for _, meter := range meters {
949 if flowMeterID == meter.Config.MeterId {
950 metadata.Meters = append(metadata.Meters, meter.Config)
Girish Kumarf56a4682020-03-20 20:07:46 +0000951 logger.Debugw("Found meter in logical device",
Manikkaraj kb1a10922019-07-29 12:10:34 -0400952 log.Fields{"meterID": flowMeterID, "meter-band": meter.Config})
953 m[flowMeterID] = true
954 foundMeter = true
955 break
956 }
957 }
958 if !foundMeter {
Girish Kumarf56a4682020-03-20 20:07:46 +0000959 logger.Errorw("Meter-referred-by-flow-is-not-found-in-logicaldevice",
npujar1d86a522019-11-14 17:11:16 +0530960 log.Fields{"meterID": flowMeterID, "Available-meters": meters, "flow": *flow})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400961 return errors.New("Meter-referred-by-flow-is-not-found-in-logicaldevice")
962 }
963 }
964 }
Girish Kumarf56a4682020-03-20 20:07:46 +0000965 logger.Debugw("meter-bands-for-flows", log.Fields{"flows": len(flows), "metadata": metadata})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400966 return nil
967
968}
969
khenaidoo19d7b632018-10-30 10:49:50 -0400970//flowDelete deletes a flow from the flow table of that logical device
Kent Hagerman2b216042020-04-03 18:28:56 -0400971func (agent *LogicalAgent) flowDelete(ctx context.Context, mod *ofp.OfpFlowMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000972 logger.Debug("flowDelete")
khenaidoo19d7b632018-10-30 10:49:50 -0400973 if mod == nil {
974 return nil
975 }
khenaidoo442e7c72020-03-10 16:13:48 -0400976 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
977 return err
978 }
979 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -0400980
khenaidoo6e55d9e2019-12-12 18:26:26 -0500981 lDevice := agent.getLogicalDeviceWithoutLock()
khenaidoo19d7b632018-10-30 10:49:50 -0400982
Manikkaraj kb1a10922019-07-29 12:10:34 -0400983 var meters []*ofp.OfpMeterEntry
984 var flows []*ofp.OfpFlowStats
Esin Karamanfc3b1af2020-01-29 16:52:00 +0000985 var flowGroups []*ofp.OfpGroupEntry
Manikkaraj kb1a10922019-07-29 12:10:34 -0400986
987 if lDevice.Flows != nil && lDevice.Flows.Items != nil {
988 flows = lDevice.Flows.Items
989 }
990
991 if lDevice.Meters != nil && lDevice.Meters.Items != nil {
992 meters = lDevice.Meters.Items
993 }
Esin Karamanfc3b1af2020-01-29 16:52:00 +0000994
995 if lDevice.FlowGroups != nil && lDevice.FlowGroups.Items != nil {
996 flowGroups = lDevice.FlowGroups.Items
997 }
998
khenaidoo19d7b632018-10-30 10:49:50 -0400999 //build a list of what to keep vs what to delete
1000 toKeep := make([]*ofp.OfpFlowStats, 0)
khenaidoo0458db62019-06-20 08:50:36 -04001001 toDelete := make([]*ofp.OfpFlowStats, 0)
khenaidoo19d7b632018-10-30 10:49:50 -04001002 for _, f := range flows {
khenaidoo0458db62019-06-20 08:50:36 -04001003 // Check whether the flow and the flowmod matches
Scott Bakerfdea1e32020-02-21 15:35:41 -08001004 fs, err := fu.FlowStatsEntryFromFlowModMessage(mod)
1005 if err != nil {
1006 return err
1007 }
1008 if fu.FlowMatch(f, fs) {
khenaidoo0458db62019-06-20 08:50:36 -04001009 toDelete = append(toDelete, f)
1010 continue
1011 }
1012 // Check wild card match
khenaidoo19d7b632018-10-30 10:49:50 -04001013 if !fu.FlowMatchesMod(f, mod) {
1014 toKeep = append(toKeep, f)
khenaidoo0458db62019-06-20 08:50:36 -04001015 } else {
1016 toDelete = append(toDelete, f)
khenaidoo19d7b632018-10-30 10:49:50 -04001017 }
1018 }
1019
Girish Kumarf56a4682020-03-20 20:07:46 +00001020 logger.Debugw("flowDelete", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "toKeep": len(toKeep), "toDelete": toDelete})
khenaidoo0458db62019-06-20 08:50:36 -04001021
khenaidoo19d7b632018-10-30 10:49:50 -04001022 //Update flows
khenaidoo0458db62019-06-20 08:50:36 -04001023 if len(toDelete) > 0 {
Manikkaraj kb1a10922019-07-29 12:10:34 -04001024 var flowMetadata voltha.FlowMetadata
1025 if err := agent.GetMeterConfig(toDelete, meters, &flowMetadata); err != nil { // This should never happen
Girish Kumarf56a4682020-03-20 20:07:46 +00001026 logger.Error("Meter-referred-in-flows-not-present")
Manikkaraj kb1a10922019-07-29 12:10:34 -04001027 return errors.New("Meter-referred-in-flows-not-present")
1028 }
khenaidoo787224a2020-04-16 18:08:47 -04001029
1030 var respChnls []coreutils.Response
1031 var partialRoute bool
khenaidoo820197c2020-02-13 16:35:33 -05001032 deviceRules, err := agent.flowDecomposer.DecomposeRules(ctx, agent, ofp.Flows{Items: toDelete}, ofp.FlowGroups{Items: flowGroups})
1033 if err != nil {
khenaidoo787224a2020-04-16 18:08:47 -04001034 // A no route error means no route exists between the ports specified in the flow. This can happen when the
1035 // child device is deleted and a request to delete flows from the parent device is received
1036 if !errors.Is(err, route.ErrNoRoute) {
1037 logger.Errorw("unexpected-error-received", log.Fields{"flows-to-delete": toDelete, "error": err})
1038 return err
1039 }
1040 partialRoute = true
khenaidoo820197c2020-02-13 16:35:33 -05001041 }
khenaidoo0458db62019-06-20 08:50:36 -04001042
khenaidoo787224a2020-04-16 18:08:47 -04001043 // Update the dB
npujar467fe752020-01-16 20:17:45 +05301044 if err := agent.updateLogicalDeviceFlowsWithoutLock(ctx, &ofp.Flows{Items: toKeep}); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001045 logger.Errorw("cannot-update-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo19d7b632018-10-30 10:49:50 -04001046 return err
1047 }
khenaidoo442e7c72020-03-10 16:13:48 -04001048
1049 // Update the devices
khenaidoo787224a2020-04-16 18:08:47 -04001050 if partialRoute {
1051 respChnls = agent.deleteFlowsFromParentDevice(ctx, ofp.Flows{Items: toDelete}, &flowMetadata)
1052 } else {
1053 respChnls = agent.deleteFlowsAndGroupsFromDevices(ctx, deviceRules, &flowMetadata)
1054 }
khenaidoo442e7c72020-03-10 16:13:48 -04001055
1056 // Wait for the responses
1057 go func() {
1058 // Wait for completion
1059 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001060 logger.Errorw("failure-updating-device-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "errors": res})
khenaidoo442e7c72020-03-10 16:13:48 -04001061 // TODO: Revert the flow deletion
1062 }
1063 }()
khenaidoo19d7b632018-10-30 10:49:50 -04001064 }
1065
1066 //TODO: send announcement on delete
1067 return nil
1068}
1069
Kent Hagerman2b216042020-04-03 18:28:56 -04001070func (agent *LogicalAgent) addFlowsAndGroupsToDevices(ctx context.Context, deviceRules *fu.DeviceRules, flowMetadata *voltha.FlowMetadata) []coreutils.Response {
Girish Kumarf56a4682020-03-20 20:07:46 +00001071 logger.Debugw("send-add-flows-to-device-manager", log.Fields{"logicalDeviceID": agent.logicalDeviceID, "deviceRules": deviceRules, "flowMetadata": flowMetadata})
khenaidoo19d7b632018-10-30 10:49:50 -04001072
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001073 responses := make([]coreutils.Response, 0)
npujar1d86a522019-11-14 17:11:16 +05301074 for deviceID, value := range deviceRules.GetRules() {
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001075 response := coreutils.NewResponse()
1076 responses = append(responses, response)
1077 go func(deviceId string, value *fu.FlowsAndGroups) {
khenaidoo442e7c72020-03-10 16:13:48 -04001078 ctx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
1079 defer cancel()
npujar467fe752020-01-16 20:17:45 +05301080 if err := agent.deviceMgr.addFlowsAndGroups(ctx, deviceId, value.ListFlows(), value.ListGroups(), flowMetadata); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001081 logger.Errorw("flow-add-failed", log.Fields{"deviceID": deviceId, "error": err})
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001082 response.Error(status.Errorf(codes.Internal, "flow-add-failed: %s", deviceId))
khenaidoo0458db62019-06-20 08:50:36 -04001083 }
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001084 response.Done()
npujar1d86a522019-11-14 17:11:16 +05301085 }(deviceID, value)
khenaidoo19d7b632018-10-30 10:49:50 -04001086 }
khenaidoo442e7c72020-03-10 16:13:48 -04001087 // Return responses (an array of channels) for the caller to wait for a response from the far end.
1088 return responses
khenaidoo0458db62019-06-20 08:50:36 -04001089}
khenaidoo19d7b632018-10-30 10:49:50 -04001090
Kent Hagerman2b216042020-04-03 18:28:56 -04001091func (agent *LogicalAgent) deleteFlowsAndGroupsFromDevices(ctx context.Context, deviceRules *fu.DeviceRules, flowMetadata *voltha.FlowMetadata) []coreutils.Response {
Girish Kumarf56a4682020-03-20 20:07:46 +00001092 logger.Debugw("send-delete-flows-to-device-manager", log.Fields{"logicalDeviceID": agent.logicalDeviceID})
khenaidoo0458db62019-06-20 08:50:36 -04001093
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001094 responses := make([]coreutils.Response, 0)
npujar1d86a522019-11-14 17:11:16 +05301095 for deviceID, value := range deviceRules.GetRules() {
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001096 response := coreutils.NewResponse()
1097 responses = append(responses, response)
1098 go func(deviceId string, value *fu.FlowsAndGroups) {
khenaidoo442e7c72020-03-10 16:13:48 -04001099 ctx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
1100 defer cancel()
npujar467fe752020-01-16 20:17:45 +05301101 if err := agent.deviceMgr.deleteFlowsAndGroups(ctx, deviceId, value.ListFlows(), value.ListGroups(), flowMetadata); err != nil {
khenaidoo787224a2020-04-16 18:08:47 -04001102 logger.Errorw("flow-delete-failed", log.Fields{"deviceID": deviceId, "error": err})
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001103 response.Error(status.Errorf(codes.Internal, "flow-delete-failed: %s", deviceId))
khenaidoo0458db62019-06-20 08:50:36 -04001104 }
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001105 response.Done()
npujar1d86a522019-11-14 17:11:16 +05301106 }(deviceID, value)
khenaidoo0458db62019-06-20 08:50:36 -04001107 }
khenaidoo442e7c72020-03-10 16:13:48 -04001108 return responses
khenaidoo0458db62019-06-20 08:50:36 -04001109}
1110
Kent Hagerman2b216042020-04-03 18:28:56 -04001111func (agent *LogicalAgent) updateFlowsAndGroupsOfDevice(ctx context.Context, deviceRules *fu.DeviceRules, flowMetadata *voltha.FlowMetadata) []coreutils.Response {
Girish Kumarf56a4682020-03-20 20:07:46 +00001112 logger.Debugw("send-update-flows-to-device-manager", log.Fields{"logicalDeviceID": agent.logicalDeviceID})
khenaidoo0458db62019-06-20 08:50:36 -04001113
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001114 responses := make([]coreutils.Response, 0)
npujar1d86a522019-11-14 17:11:16 +05301115 for deviceID, value := range deviceRules.GetRules() {
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001116 response := coreutils.NewResponse()
1117 responses = append(responses, response)
1118 go func(deviceId string, value *fu.FlowsAndGroups) {
khenaidoo442e7c72020-03-10 16:13:48 -04001119 ctx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
1120 defer cancel()
npujar467fe752020-01-16 20:17:45 +05301121 if err := agent.deviceMgr.updateFlowsAndGroups(ctx, deviceId, value.ListFlows(), value.ListGroups(), flowMetadata); err != nil {
khenaidoo787224a2020-04-16 18:08:47 -04001122 logger.Errorw("flow-update-failed", log.Fields{"deviceID": deviceId, "error": err})
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001123 response.Error(status.Errorf(codes.Internal, "flow-update-failed: %s", deviceId))
khenaidoo0458db62019-06-20 08:50:36 -04001124 }
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001125 response.Done()
npujar1d86a522019-11-14 17:11:16 +05301126 }(deviceID, value)
khenaidoo0458db62019-06-20 08:50:36 -04001127 }
khenaidoo442e7c72020-03-10 16:13:48 -04001128 return responses
khenaidoo19d7b632018-10-30 10:49:50 -04001129}
1130
khenaidoo787224a2020-04-16 18:08:47 -04001131// getUNILogicalPortNo returns the UNI logical port number specified in the flow
1132func (agent *LogicalAgent) getUNILogicalPortNo(flow *ofp.OfpFlowStats) (uint32, error) {
1133 var uniPort uint32
1134 inPortNo := fu.GetInPort(flow)
1135 outPortNo := fu.GetOutPort(flow)
1136 if agent.isNNIPort(inPortNo) {
1137 uniPort = outPortNo
1138 } else if agent.isNNIPort(outPortNo) {
1139 uniPort = inPortNo
1140 }
1141 if uniPort != 0 {
1142 return uniPort, nil
1143 }
1144 return 0, status.Errorf(codes.NotFound, "no-uni-port: %v", flow)
1145}
1146
1147func (agent *LogicalAgent) deleteFlowsFromParentDevice(ctx context.Context, flows ofp.Flows, metadata *voltha.FlowMetadata) []coreutils.Response {
1148 logger.Debugw("deleting-flows-from-parent-device", log.Fields{"logical-device-id": agent.logicalDeviceID, "flows": flows})
1149 responses := make([]coreutils.Response, 0)
1150 for _, flow := range flows.Items {
1151 response := coreutils.NewResponse()
1152 responses = append(responses, response)
1153 uniPort, err := agent.getUNILogicalPortNo(flow)
1154 if err != nil {
1155 logger.Error("no-uni-port-in-flow", log.Fields{"deviceID": agent.rootDeviceID, "flow": flow, "error": err})
1156 response.Error(err)
1157 response.Done()
1158 continue
1159 }
1160 logger.Debugw("uni-port", log.Fields{"flows": flows, "uni-port": uniPort})
1161 go func(uniPort uint32, metadata *voltha.FlowMetadata) {
1162 ctx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
1163 defer cancel()
1164 if err := agent.deviceMgr.deleteParentFlows(ctx, agent.rootDeviceID, uniPort, metadata); err != nil {
1165 logger.Error("flow-delete-failed", log.Fields{"device-id": agent.rootDeviceID, "error": err})
1166 response.Error(status.Errorf(codes.Internal, "flow-delete-failed: %s %v", agent.rootDeviceID, err))
1167 }
1168 response.Done()
1169 }(uniPort, metadata)
1170 }
1171 return responses
1172}
1173
khenaidoo19d7b632018-10-30 10:49:50 -04001174//flowDeleteStrict deletes a flow from the flow table of that logical device
Kent Hagerman2b216042020-04-03 18:28:56 -04001175func (agent *LogicalAgent) flowDeleteStrict(ctx context.Context, mod *ofp.OfpFlowMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +00001176 logger.Debug("flowDeleteStrict")
khenaidoo19d7b632018-10-30 10:49:50 -04001177 if mod == nil {
1178 return nil
1179 }
khenaidoo442e7c72020-03-10 16:13:48 -04001180 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1181 return err
1182 }
1183 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -04001184
khenaidoo6e55d9e2019-12-12 18:26:26 -05001185 lDevice := agent.getLogicalDeviceWithoutLock()
1186
Manikkaraj kb1a10922019-07-29 12:10:34 -04001187 var meters []*ofp.OfpMeterEntry
1188 var flows []*ofp.OfpFlowStats
Esin Karamanfc3b1af2020-01-29 16:52:00 +00001189 var flowGroups []*ofp.OfpGroupEntry
Manikkaraj kb1a10922019-07-29 12:10:34 -04001190 if lDevice.Meters != nil && lDevice.Meters.Items != nil {
1191 meters = lDevice.Meters.Items
1192 }
1193 if lDevice.Flows != nil && lDevice.Flows.Items != nil {
1194 flows = lDevice.Flows.Items
1195 }
Esin Karamanfc3b1af2020-01-29 16:52:00 +00001196 if lDevice.FlowGroups != nil && lDevice.FlowGroups.Items != nil {
1197 flowGroups = lDevice.FlowGroups.Items
1198 }
Manikkaraj kb1a10922019-07-29 12:10:34 -04001199
1200 changedFlow := false
1201 changedMeter := false
Scott Bakerfdea1e32020-02-21 15:35:41 -08001202 flow, err := fu.FlowStatsEntryFromFlowModMessage(mod)
1203 if err != nil {
1204 return err
1205 }
Manikkaraj kb1a10922019-07-29 12:10:34 -04001206 flowsToDelete := make([]*ofp.OfpFlowStats, 0)
khenaidoo19d7b632018-10-30 10:49:50 -04001207 idx := fu.FindFlows(flows, flow)
1208 if idx >= 0 {
Gamze Abaka6e4ac162019-10-21 11:10:10 +00001209 changedMeter = agent.updateFlowCountOfMeterStats(mod, meters, flows[idx])
Manikkaraj kb1a10922019-07-29 12:10:34 -04001210 flowsToDelete = append(flowsToDelete, flows[idx])
khenaidoo19d7b632018-10-30 10:49:50 -04001211 flows = append(flows[:idx], flows[idx+1:]...)
Manikkaraj kb1a10922019-07-29 12:10:34 -04001212 changedFlow = true
khenaidoo19d7b632018-10-30 10:49:50 -04001213 } else {
npujar1d86a522019-11-14 17:11:16 +05301214 return fmt.Errorf("Cannot delete flow - %s", flow)
khenaidoo19d7b632018-10-30 10:49:50 -04001215 }
Manikkaraj kb1a10922019-07-29 12:10:34 -04001216 if changedMeter {
1217 //Update model
1218 metersToUpdate := &ofp.Meters{}
1219 if lDevice.Meters != nil {
1220 metersToUpdate = &ofp.Meters{Items: meters}
1221 }
npujar467fe752020-01-16 20:17:45 +05301222 if err := agent.updateLogicalDeviceMetersWithoutLock(ctx, metersToUpdate); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001223 logger.Errorw("db-meter-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
Manikkaraj kb1a10922019-07-29 12:10:34 -04001224 return err
1225 }
khenaidoo19d7b632018-10-30 10:49:50 -04001226
Manikkaraj kb1a10922019-07-29 12:10:34 -04001227 }
1228 if changedFlow {
1229 var flowMetadata voltha.FlowMetadata
1230 if err := agent.GetMeterConfig(flowsToDelete, meters, &flowMetadata); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001231 logger.Error("meter-referred-in-flows-not-present")
Manikkaraj kb1a10922019-07-29 12:10:34 -04001232 return err
1233 }
khenaidoo787224a2020-04-16 18:08:47 -04001234 var respChnls []coreutils.Response
1235 var partialRoute bool
khenaidoo820197c2020-02-13 16:35:33 -05001236 deviceRules, err := agent.flowDecomposer.DecomposeRules(ctx, agent, ofp.Flows{Items: flowsToDelete}, ofp.FlowGroups{Items: flowGroups})
1237 if err != nil {
khenaidoo787224a2020-04-16 18:08:47 -04001238 // A no route error means no route exists between the ports specified in the flow. This can happen when the
1239 // child device is deleted and a request to delete flows from the parent device is received
1240 if !errors.Is(err, route.ErrNoRoute) {
1241 logger.Errorw("unexpected-error-received", log.Fields{"flows-to-delete": flowsToDelete, "error": err})
1242 return err
1243 }
1244 partialRoute = true
khenaidoo820197c2020-02-13 16:35:33 -05001245 }
khenaidoo0458db62019-06-20 08:50:36 -04001246
khenaidoo787224a2020-04-16 18:08:47 -04001247 // Update the dB
npujar467fe752020-01-16 20:17:45 +05301248 if err := agent.updateLogicalDeviceFlowsWithoutLock(ctx, &ofp.Flows{Items: flows}); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001249 logger.Errorw("cannot-update-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo19d7b632018-10-30 10:49:50 -04001250 return err
1251 }
khenaidoo442e7c72020-03-10 16:13:48 -04001252
1253 // Update the devices
khenaidoo787224a2020-04-16 18:08:47 -04001254 if partialRoute {
1255 respChnls = agent.deleteFlowsFromParentDevice(ctx, ofp.Flows{Items: flowsToDelete}, &flowMetadata)
1256 } else {
1257 respChnls = agent.deleteFlowsAndGroupsFromDevices(ctx, deviceRules, &flowMetadata)
1258 }
khenaidoo442e7c72020-03-10 16:13:48 -04001259
1260 // Wait for completion
1261 go func() {
1262 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001263 logger.Warnw("failure-deleting-device-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "errors": res})
khenaidoo442e7c72020-03-10 16:13:48 -04001264 //TODO: Revert flow changes
1265 }
1266 }()
khenaidoo19d7b632018-10-30 10:49:50 -04001267 }
khenaidoo19d7b632018-10-30 10:49:50 -04001268 return nil
1269}
1270
1271//flowModify modifies a flow from the flow table of that logical device
Kent Hagerman2b216042020-04-03 18:28:56 -04001272func (agent *LogicalAgent) flowModify(mod *ofp.OfpFlowMod) error {
khenaidoo19d7b632018-10-30 10:49:50 -04001273 return errors.New("flowModify not implemented")
1274}
1275
1276//flowModifyStrict deletes a flow from the flow table of that logical device
Kent Hagerman2b216042020-04-03 18:28:56 -04001277func (agent *LogicalAgent) flowModifyStrict(mod *ofp.OfpFlowMod) error {
khenaidoo19d7b632018-10-30 10:49:50 -04001278 return errors.New("flowModifyStrict not implemented")
1279}
1280
Kent Hagerman2b216042020-04-03 18:28:56 -04001281func (agent *LogicalAgent) groupAdd(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +00001282 logger.Debug("groupAdd")
khenaidoo19d7b632018-10-30 10:49:50 -04001283 if groupMod == nil {
1284 return nil
1285 }
khenaidoo442e7c72020-03-10 16:13:48 -04001286 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1287 return err
1288 }
1289 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -04001290
khenaidoo6e55d9e2019-12-12 18:26:26 -05001291 lDevice := agent.getLogicalDeviceWithoutLock()
1292
khenaidoo19d7b632018-10-30 10:49:50 -04001293 groups := lDevice.FlowGroups.Items
khenaidoo19d7b632018-10-30 10:49:50 -04001294 if fu.FindGroup(groups, groupMod.GroupId) == -1 {
khenaidoo68c930b2019-05-13 11:46:51 -04001295 groups = append(groups, fu.GroupEntryFromGroupMod(groupMod))
khenaidoo0458db62019-06-20 08:50:36 -04001296
Esin Karaman2ea59212019-12-06 11:41:58 +00001297 deviceRules := fu.NewDeviceRules()
1298 deviceRules.CreateEntryIfNotExist(agent.rootDeviceID)
1299 fg := fu.NewFlowsAndGroups()
1300 fg.AddGroup(fu.GroupEntryFromGroupMod(groupMod))
1301 deviceRules.AddFlowsAndGroup(agent.rootDeviceID, fg)
1302
Girish Kumarf56a4682020-03-20 20:07:46 +00001303 logger.Debugw("rules", log.Fields{"rules for group-add": deviceRules.String()})
khenaidoo0458db62019-06-20 08:50:36 -04001304
npujar467fe752020-01-16 20:17:45 +05301305 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(ctx, &ofp.FlowGroups{Items: groups}); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001306 logger.Errorw("cannot-update-group", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo19d7b632018-10-30 10:49:50 -04001307 return err
1308 }
khenaidoo442e7c72020-03-10 16:13:48 -04001309
1310 // Update the devices
1311 respChnls := agent.addFlowsAndGroupsToDevices(ctx, deviceRules, &voltha.FlowMetadata{})
1312
1313 // Wait for completion
1314 go func() {
1315 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001316 logger.Warnw("failure-updating-device-flows-groups", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "errors": res})
khenaidoo442e7c72020-03-10 16:13:48 -04001317 //TODO: Revert flow changes
1318 }
1319 }()
1320 return nil
khenaidoo19d7b632018-10-30 10:49:50 -04001321 }
khenaidoo442e7c72020-03-10 16:13:48 -04001322 return fmt.Errorf("Groups %d already present", groupMod.GroupId)
khenaidoo19d7b632018-10-30 10:49:50 -04001323}
1324
Kent Hagerman2b216042020-04-03 18:28:56 -04001325func (agent *LogicalAgent) groupDelete(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +00001326 logger.Debug("groupDelete")
khenaidoo19d7b632018-10-30 10:49:50 -04001327 if groupMod == nil {
1328 return nil
1329 }
khenaidoo442e7c72020-03-10 16:13:48 -04001330 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1331 return err
1332 }
1333 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -04001334
khenaidoo6e55d9e2019-12-12 18:26:26 -05001335 lDevice := agent.getLogicalDeviceWithoutLock()
khenaidoo19d7b632018-10-30 10:49:50 -04001336 groups := lDevice.FlowGroups.Items
1337 flows := lDevice.Flows.Items
npujar1d86a522019-11-14 17:11:16 +05301338 var groupsChanged bool
khenaidoo19d7b632018-10-30 10:49:50 -04001339 flowsChanged := false
npujar1d86a522019-11-14 17:11:16 +05301340 groupID := groupMod.GroupId
1341 if groupID == uint32(ofp.OfpGroup_OFPG_ALL) {
khenaidoo19d7b632018-10-30 10:49:50 -04001342 //TODO we must delete all flows that point to this group and
1343 //signal controller as requested by flow's flag
1344 groups = []*ofp.OfpGroupEntry{}
1345 groupsChanged = true
1346 } else {
npujar1d86a522019-11-14 17:11:16 +05301347 idx := fu.FindGroup(groups, groupID)
1348 if idx == -1 {
khenaidoo19d7b632018-10-30 10:49:50 -04001349 return nil // Valid case
khenaidoo19d7b632018-10-30 10:49:50 -04001350 }
npujar1d86a522019-11-14 17:11:16 +05301351 flowsChanged, flows = fu.FlowsDeleteByGroupId(flows, groupID)
1352 groups = append(groups[:idx], groups[idx+1:]...)
1353 groupsChanged = true
khenaidoo19d7b632018-10-30 10:49:50 -04001354 }
khenaidoo0458db62019-06-20 08:50:36 -04001355 if flowsChanged || groupsChanged {
khenaidoo820197c2020-02-13 16:35:33 -05001356 deviceRules, err := agent.flowDecomposer.DecomposeRules(ctx, agent, ofp.Flows{Items: flows}, ofp.FlowGroups{Items: groups})
1357 if err != nil {
1358 return err
1359 }
Girish Kumarf56a4682020-03-20 20:07:46 +00001360 logger.Debugw("rules", log.Fields{"rules": deviceRules.String()})
khenaidoo0458db62019-06-20 08:50:36 -04001361
khenaidoo442e7c72020-03-10 16:13:48 -04001362 if groupsChanged {
1363 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(ctx, &ofp.FlowGroups{Items: groups}); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001364 logger.Errorw("cannot-update-group", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo442e7c72020-03-10 16:13:48 -04001365 return err
1366 }
khenaidoo0458db62019-06-20 08:50:36 -04001367 }
khenaidoo442e7c72020-03-10 16:13:48 -04001368 if flowsChanged {
1369 if err := agent.updateLogicalDeviceFlowsWithoutLock(ctx, &ofp.Flows{Items: flows}); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001370 logger.Errorw("cannot-update-flow", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo442e7c72020-03-10 16:13:48 -04001371 return err
1372 }
1373 }
khenaidoo0458db62019-06-20 08:50:36 -04001374
khenaidoo442e7c72020-03-10 16:13:48 -04001375 // Update the devices
1376 respChnls := agent.updateFlowsAndGroupsOfDevice(ctx, deviceRules, nil)
1377
1378 // Wait for completion
1379 go func() {
1380 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001381 logger.Warnw("failure-updating-device-flows-groups", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "errors": res})
khenaidoo442e7c72020-03-10 16:13:48 -04001382 //TODO: Revert flow changes
1383 }
1384 }()
khenaidoo43c82122018-11-22 18:38:28 -05001385 }
khenaidoo19d7b632018-10-30 10:49:50 -04001386 return nil
1387}
1388
Kent Hagerman2b216042020-04-03 18:28:56 -04001389func (agent *LogicalAgent) groupModify(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +00001390 logger.Debug("groupModify")
khenaidoo19d7b632018-10-30 10:49:50 -04001391 if groupMod == nil {
1392 return nil
1393 }
khenaidoo442e7c72020-03-10 16:13:48 -04001394 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1395 return err
1396 }
1397 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -04001398
khenaidoo6e55d9e2019-12-12 18:26:26 -05001399 lDevice := agent.getLogicalDeviceWithoutLock()
khenaidoo19d7b632018-10-30 10:49:50 -04001400 groups := lDevice.FlowGroups.Items
npujar1d86a522019-11-14 17:11:16 +05301401 var groupsChanged bool
1402 groupID := groupMod.GroupId
1403 idx := fu.FindGroup(groups, groupID)
1404 if idx == -1 {
1405 return fmt.Errorf("group-absent:%d", groupID)
khenaidoo19d7b632018-10-30 10:49:50 -04001406 }
npujar1d86a522019-11-14 17:11:16 +05301407 //replace existing group entry with new group definition
1408 groupEntry := fu.GroupEntryFromGroupMod(groupMod)
1409 groups[idx] = groupEntry
1410 groupsChanged = true
khenaidoo19d7b632018-10-30 10:49:50 -04001411 if groupsChanged {
Esin Karaman2ea59212019-12-06 11:41:58 +00001412 deviceRules := fu.NewDeviceRules()
1413 deviceRules.CreateEntryIfNotExist(agent.rootDeviceID)
1414 fg := fu.NewFlowsAndGroups()
1415 fg.AddGroup(fu.GroupEntryFromGroupMod(groupMod))
1416 deviceRules.AddFlowsAndGroup(agent.rootDeviceID, fg)
khenaidoo0458db62019-06-20 08:50:36 -04001417
Girish Kumarf56a4682020-03-20 20:07:46 +00001418 logger.Debugw("rules", log.Fields{"rules for group-modify": deviceRules.String()})
khenaidoo0458db62019-06-20 08:50:36 -04001419
npujar467fe752020-01-16 20:17:45 +05301420 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(ctx, &ofp.FlowGroups{Items: groups}); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001421 logger.Errorw("Cannot-update-logical-group", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo19d7b632018-10-30 10:49:50 -04001422 return err
1423 }
khenaidoo442e7c72020-03-10 16:13:48 -04001424
1425 // Update the devices
1426 respChnls := agent.updateFlowsAndGroupsOfDevice(ctx, deviceRules, &voltha.FlowMetadata{})
1427
1428 // Wait for completion
1429 go func() {
1430 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001431 logger.Warnw("failure-updating-device-flows-groups", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "errors": res})
khenaidoo442e7c72020-03-10 16:13:48 -04001432 //TODO: Revert flow changes
1433 }
1434 }()
khenaidoo19d7b632018-10-30 10:49:50 -04001435 }
1436 return nil
1437}
1438
1439// deleteLogicalPort removes the logical port
Kent Hagerman2b216042020-04-03 18:28:56 -04001440func (agent *LogicalAgent) deleteLogicalPort(ctx context.Context, lPort *voltha.LogicalPort) error {
khenaidoo442e7c72020-03-10 16:13:48 -04001441 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1442 return err
1443 }
1444 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -04001445
khenaidoo6e55d9e2019-12-12 18:26:26 -05001446 logicalDevice := agent.getLogicalDeviceWithoutLock()
1447
khenaidoo92e62c52018-10-03 14:02:54 -04001448 index := -1
khenaidoo6e55d9e2019-12-12 18:26:26 -05001449 for i, logicalPort := range logicalDevice.Ports {
khenaidoo19d7b632018-10-30 10:49:50 -04001450 if logicalPort.Id == lPort.Id {
khenaidoo92e62c52018-10-03 14:02:54 -04001451 index = i
1452 break
1453 }
1454 }
1455 if index >= 0 {
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001456 clonedPorts := clonePorts(logicalDevice.Ports)
1457 if index < len(clonedPorts)-1 {
1458 copy(clonedPorts[index:], clonedPorts[index+1:])
1459 }
1460 clonedPorts[len(clonedPorts)-1] = nil
1461 clonedPorts = clonedPorts[:len(clonedPorts)-1]
Girish Kumarf56a4682020-03-20 20:07:46 +00001462 logger.Debugw("logical-port-deleted", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001463 if err := agent.updateLogicalDevicePortsWithoutLock(ctx, logicalDevice, clonedPorts); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001464 logger.Errorw("logical-device-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo0a822f92019-05-08 15:15:57 -04001465 return err
1466 }
khenaidoo820197c2020-02-13 16:35:33 -05001467
1468 // Remove the logical port from cache
1469 agent.deleteLogicalPortsFromMap([]uint32{lPort.DevicePortNo})
1470
1471 // Reset the logical device routes
1472 go func() {
1473 if err := agent.buildRoutes(context.Background()); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001474 logger.Warnw("device-routes-not-ready", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "error": err})
khenaidoo820197c2020-02-13 16:35:33 -05001475 }
1476 }()
khenaidoo92e62c52018-10-03 14:02:54 -04001477 }
1478 return nil
khenaidoob9203542018-09-17 22:56:37 -04001479}
1480
khenaidoo0a822f92019-05-08 15:15:57 -04001481// deleteLogicalPorts removes the logical ports associated with that deviceId
Kent Hagerman2b216042020-04-03 18:28:56 -04001482func (agent *LogicalAgent) deleteLogicalPorts(ctx context.Context, deviceID string) error {
Andrea Campanella09400bd2020-04-02 11:58:04 +02001483 logger.Debugw("deleting-logical-ports", log.Fields{"device-id": deviceID})
khenaidoo442e7c72020-03-10 16:13:48 -04001484 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1485 return err
1486 }
1487 defer agent.requestQueue.RequestComplete()
khenaidoo0a822f92019-05-08 15:15:57 -04001488
khenaidoo6e55d9e2019-12-12 18:26:26 -05001489 logicalDevice := agent.getLogicalDeviceWithoutLock()
khenaidoo820197c2020-02-13 16:35:33 -05001490 lPortstoKeep := []*voltha.LogicalPort{}
1491 lPortsNoToDelete := []uint32{}
khenaidoo6e55d9e2019-12-12 18:26:26 -05001492 for _, logicalPort := range logicalDevice.Ports {
npujar1d86a522019-11-14 17:11:16 +05301493 if logicalPort.DeviceId != deviceID {
khenaidoo820197c2020-02-13 16:35:33 -05001494 lPortstoKeep = append(lPortstoKeep, logicalPort)
1495 } else {
1496 lPortsNoToDelete = append(lPortsNoToDelete, logicalPort.DevicePortNo)
khenaidoo0a822f92019-05-08 15:15:57 -04001497 }
1498 }
Andrea Campanella09400bd2020-04-02 11:58:04 +02001499 logger.Debugw("deleted-logical-ports", log.Fields{"ports": lPortstoKeep})
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001500 if err := agent.updateLogicalDevicePortsWithoutLock(ctx, logicalDevice, lPortstoKeep); err != nil {
Andrea Campanella09400bd2020-04-02 11:58:04 +02001501 logger.Errorw("logical-device-update-failed", log.Fields{"logical-device-id": agent.logicalDeviceID})
khenaidoo0a822f92019-05-08 15:15:57 -04001502 return err
1503 }
khenaidoo820197c2020-02-13 16:35:33 -05001504 // Remove the port from the cached logical ports set
1505 agent.deleteLogicalPortsFromMap(lPortsNoToDelete)
1506
1507 // Reset the logical device routes
1508 go func() {
1509 if err := agent.buildRoutes(context.Background()); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001510 logger.Warnw("routes-not-ready", log.Fields{"logical-device-id": agent.logicalDeviceID, "error": err})
khenaidoo820197c2020-02-13 16:35:33 -05001511 }
1512 }()
khenaidoo0a822f92019-05-08 15:15:57 -04001513
1514 return nil
1515}
1516
khenaidoo19d7b632018-10-30 10:49:50 -04001517// enableLogicalPort enables the logical port
Kent Hagerman2b216042020-04-03 18:28:56 -04001518func (agent *LogicalAgent) enableLogicalPort(ctx context.Context, lPortID string) error {
khenaidoo442e7c72020-03-10 16:13:48 -04001519 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1520 return err
1521 }
1522 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -04001523
khenaidoo6e55d9e2019-12-12 18:26:26 -05001524 logicalDevice := agent.getLogicalDeviceWithoutLock()
1525
khenaidoo19d7b632018-10-30 10:49:50 -04001526 index := -1
khenaidoo6e55d9e2019-12-12 18:26:26 -05001527 for i, logicalPort := range logicalDevice.Ports {
npujar1d86a522019-11-14 17:11:16 +05301528 if logicalPort.Id == lPortID {
khenaidoo19d7b632018-10-30 10:49:50 -04001529 index = i
1530 break
1531 }
1532 }
1533 if index >= 0 {
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001534 clonedPorts := clonePorts(logicalDevice.Ports)
1535 clonedPorts[index].OfpPort.Config = clonedPorts[index].OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
1536 return agent.updateLogicalDevicePortsWithoutLock(ctx, logicalDevice, clonedPorts)
khenaidoo19d7b632018-10-30 10:49:50 -04001537 }
npujar1d86a522019-11-14 17:11:16 +05301538 return status.Errorf(codes.NotFound, "Port %s on Logical Device %s", lPortID, agent.logicalDeviceID)
khenaidoo19d7b632018-10-30 10:49:50 -04001539}
1540
1541// disableLogicalPort disabled the logical port
Kent Hagerman2b216042020-04-03 18:28:56 -04001542func (agent *LogicalAgent) disableLogicalPort(ctx context.Context, lPortID string) error {
khenaidoo442e7c72020-03-10 16:13:48 -04001543 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1544 return err
1545 }
1546 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -04001547
1548 // Get the most up to date logical device
khenaidoo6e55d9e2019-12-12 18:26:26 -05001549 logicalDevice := agent.getLogicalDeviceWithoutLock()
khenaidoo19d7b632018-10-30 10:49:50 -04001550 index := -1
khenaidoo6e55d9e2019-12-12 18:26:26 -05001551 for i, logicalPort := range logicalDevice.Ports {
npujar1d86a522019-11-14 17:11:16 +05301552 if logicalPort.Id == lPortID {
khenaidoo19d7b632018-10-30 10:49:50 -04001553 index = i
1554 break
1555 }
1556 }
1557 if index >= 0 {
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001558 clonedPorts := clonePorts(logicalDevice.Ports)
1559 clonedPorts[index].OfpPort.Config = (clonedPorts[index].OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)) | uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
1560 return agent.updateLogicalDevicePortsWithoutLock(ctx, logicalDevice, clonedPorts)
khenaidoo19d7b632018-10-30 10:49:50 -04001561 }
npujar1d86a522019-11-14 17:11:16 +05301562 return status.Errorf(codes.NotFound, "Port %s on Logical Device %s", lPortID, agent.logicalDeviceID)
khenaidoo19d7b632018-10-30 10:49:50 -04001563}
1564
Kent Hagerman2b216042020-04-03 18:28:56 -04001565func (agent *LogicalAgent) getPreCalculatedRoute(ingress, egress uint32) ([]route.Hop, error) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001566 logger.Debugw("ROUTE", log.Fields{"len": len(agent.deviceRoutes.Routes)})
khenaidoo820197c2020-02-13 16:35:33 -05001567 for routeLink, route := range agent.deviceRoutes.Routes {
Girish Kumarf56a4682020-03-20 20:07:46 +00001568 logger.Debugw("ROUTELINKS", log.Fields{"ingress": ingress, "egress": egress, "routelink": routeLink})
khenaidoo89b0e942018-10-21 21:11:33 -04001569 if ingress == routeLink.Ingress && egress == routeLink.Egress {
khenaidoo820197c2020-02-13 16:35:33 -05001570 return route, nil
khenaidoo89b0e942018-10-21 21:11:33 -04001571 }
1572 }
khenaidoo820197c2020-02-13 16:35:33 -05001573 return nil, status.Errorf(codes.FailedPrecondition, "no route from:%d to:%d", ingress, egress)
khenaidoo89b0e942018-10-21 21:11:33 -04001574}
1575
npujar1d86a522019-11-14 17:11:16 +05301576// GetRoute returns route
Kent Hagerman2b216042020-04-03 18:28:56 -04001577func (agent *LogicalAgent) GetRoute(ctx context.Context, ingressPortNo uint32, egressPortNo uint32) ([]route.Hop, error) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001578 logger.Debugw("getting-route", log.Fields{"ingress-port": ingressPortNo, "egress-port": egressPortNo})
khenaidoo820197c2020-02-13 16:35:33 -05001579 routes := make([]route.Hop, 0)
khenaidoo2c6a0992019-04-29 13:46:56 -04001580
khenaidoo19d7b632018-10-30 10:49:50 -04001581 // Note: A port value of 0 is equivalent to a nil port
1582
khenaidoo89b0e942018-10-21 21:11:33 -04001583 // Consider different possibilities
khenaidoo19d7b632018-10-30 10:49:50 -04001584 if egressPortNo != 0 && ((egressPortNo & 0x7fffffff) == uint32(ofp.OfpPortNo_OFPP_CONTROLLER)) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001585 logger.Debugw("controller-flow", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "logicalPortsNo": agent.logicalPortsNo})
khenaidoo2c6a0992019-04-29 13:46:56 -04001586 if agent.isNNIPort(ingressPortNo) {
khenaidoo89b0e942018-10-21 21:11:33 -04001587 //This is a trap on the NNI Port
khenaidoo820197c2020-02-13 16:35:33 -05001588 if len(agent.deviceRoutes.Routes) == 0 {
khenaidoo8f474192019-04-03 17:20:44 -04001589 // 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 -04001590 // route with same IngressHop and EgressHop
khenaidoo820197c2020-02-13 16:35:33 -05001591 hop := route.Hop{DeviceID: agent.rootDeviceID, Ingress: ingressPortNo, Egress: ingressPortNo}
khenaidoo8f474192019-04-03 17:20:44 -04001592 routes = append(routes, hop)
1593 routes = append(routes, hop)
khenaidoo820197c2020-02-13 16:35:33 -05001594 return routes, nil
khenaidoo8f474192019-04-03 17:20:44 -04001595 }
khenaidoo89b0e942018-10-21 21:11:33 -04001596 //Return a 'half' route to make the flow decomposer logic happy
khenaidoo820197c2020-02-13 16:35:33 -05001597 for routeLink, path := range agent.deviceRoutes.Routes {
khenaidoo2c6a0992019-04-29 13:46:56 -04001598 if agent.isNNIPort(routeLink.Egress) {
khenaidoo820197c2020-02-13 16:35:33 -05001599 routes = append(routes, route.Hop{}) // first hop is set to empty
1600 routes = append(routes, path[1])
1601 return routes, nil
khenaidoo89b0e942018-10-21 21:11:33 -04001602 }
1603 }
khenaidoo787224a2020-04-16 18:08:47 -04001604 return nil, fmt.Errorf("no upstream route from:%d to:%d :%w", ingressPortNo, egressPortNo, route.ErrNoRoute)
khenaidoo89b0e942018-10-21 21:11:33 -04001605 }
1606 //treat it as if the output port is the first NNI of the OLT
khenaidoo2c6a0992019-04-29 13:46:56 -04001607 var err error
1608 if egressPortNo, err = agent.getFirstNNIPort(); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001609 logger.Warnw("no-nni-port", log.Fields{"error": err})
khenaidoo820197c2020-02-13 16:35:33 -05001610 return nil, err
khenaidoo2c6a0992019-04-29 13:46:56 -04001611 }
khenaidoo89b0e942018-10-21 21:11:33 -04001612 }
1613 //If ingress port is not specified (nil), it may be a wildcarded
1614 //route if egress port is OFPP_CONTROLLER or a nni logical port,
1615 //in which case we need to create a half-route where only the egress
1616 //hop is filled, the first hop is nil
khenaidoo2c6a0992019-04-29 13:46:56 -04001617 if ingressPortNo == 0 && agent.isNNIPort(egressPortNo) {
khenaidoo89b0e942018-10-21 21:11:33 -04001618 // We can use the 2nd hop of any upstream route, so just find the first upstream:
khenaidoo820197c2020-02-13 16:35:33 -05001619 for routeLink, path := range agent.deviceRoutes.Routes {
khenaidoo2c6a0992019-04-29 13:46:56 -04001620 if agent.isNNIPort(routeLink.Egress) {
khenaidoo820197c2020-02-13 16:35:33 -05001621 routes = append(routes, route.Hop{}) // first hop is set to empty
1622 routes = append(routes, path[1])
1623 return routes, nil
khenaidoo89b0e942018-10-21 21:11:33 -04001624 }
1625 }
khenaidoo787224a2020-04-16 18:08:47 -04001626 return nil, fmt.Errorf("no upstream route from:%d to:%d :%w", ingressPortNo, egressPortNo, route.ErrNoRoute)
khenaidoo89b0e942018-10-21 21:11:33 -04001627 }
1628 //If egress port is not specified (nil), we can also can return a "half" route
khenaidoo19d7b632018-10-30 10:49:50 -04001629 if egressPortNo == 0 {
khenaidoo820197c2020-02-13 16:35:33 -05001630 for routeLink, path := range agent.deviceRoutes.Routes {
khenaidoo19d7b632018-10-30 10:49:50 -04001631 if routeLink.Ingress == ingressPortNo {
khenaidoo820197c2020-02-13 16:35:33 -05001632 routes = append(routes, path[0])
1633 routes = append(routes, route.Hop{})
1634 return routes, nil
khenaidoo89b0e942018-10-21 21:11:33 -04001635 }
1636 }
khenaidoo787224a2020-04-16 18:08:47 -04001637 return nil, fmt.Errorf("no downstream route from:%d to:%d :%w", ingressPortNo, egressPortNo, route.ErrNoRoute)
khenaidoo89b0e942018-10-21 21:11:33 -04001638 }
khenaidoo89b0e942018-10-21 21:11:33 -04001639 // Return the pre-calculated route
khenaidoo19d7b632018-10-30 10:49:50 -04001640 return agent.getPreCalculatedRoute(ingressPortNo, egressPortNo)
khenaidoo89b0e942018-10-21 21:11:33 -04001641}
1642
khenaidoo3d3b8c22019-05-22 18:10:39 -04001643//GetWildcardInputPorts filters out the logical port number from the set of logical ports on the device and
1644//returns their port numbers. This function is invoked only during flow decomposition where the lock on the logical
1645//device is already held. Therefore it is safe to retrieve the logical device without lock.
Kent Hagerman2b216042020-04-03 18:28:56 -04001646func (agent *LogicalAgent) GetWildcardInputPorts(excludePort ...uint32) []uint32 {
khenaidoo89b0e942018-10-21 21:11:33 -04001647 lPorts := make([]uint32, 0)
1648 var exclPort uint32
1649 if len(excludePort) == 1 {
1650 exclPort = excludePort[0]
1651 }
khenaidoo6e55d9e2019-12-12 18:26:26 -05001652 lDevice := agent.getLogicalDeviceWithoutLock()
1653 for _, port := range lDevice.Ports {
1654 if port.OfpPort.PortNo != exclPort {
1655 lPorts = append(lPorts, port.OfpPort.PortNo)
khenaidoo89b0e942018-10-21 21:11:33 -04001656 }
1657 }
1658 return lPorts
1659}
khenaidoo19d7b632018-10-30 10:49:50 -04001660
khenaidoo820197c2020-02-13 16:35:33 -05001661// GetDeviceRoutes returns device graph
Kent Hagerman2b216042020-04-03 18:28:56 -04001662func (agent *LogicalAgent) GetDeviceRoutes() *route.DeviceRoutes {
khenaidoo820197c2020-02-13 16:35:33 -05001663 return agent.deviceRoutes
khenaidoo19d7b632018-10-30 10:49:50 -04001664}
1665
khenaidoo820197c2020-02-13 16:35:33 -05001666//rebuildRoutes rebuilds the device routes
Kent Hagerman2b216042020-04-03 18:28:56 -04001667func (agent *LogicalAgent) buildRoutes(ctx context.Context) error {
Girish Kumarf56a4682020-03-20 20:07:46 +00001668 logger.Debugf("building-routes", log.Fields{"logical-device-id": agent.logicalDeviceID})
khenaidoo442e7c72020-03-10 16:13:48 -04001669 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1670 return err
1671 }
1672 defer agent.requestQueue.RequestComplete()
1673
khenaidoo820197c2020-02-13 16:35:33 -05001674 if agent.deviceRoutes == nil {
1675 agent.deviceRoutes = route.NewDeviceRoutes(agent.logicalDeviceID, agent.deviceMgr.GetDevice)
khenaidoo2c6a0992019-04-29 13:46:56 -04001676 }
1677 // Get all the logical ports on that logical device
khenaidoo6e55d9e2019-12-12 18:26:26 -05001678 lDevice := agent.getLogicalDeviceWithoutLock()
1679
khenaidoo820197c2020-02-13 16:35:33 -05001680 if err := agent.deviceRoutes.ComputeRoutes(ctx, lDevice.Ports); err != nil {
1681 return err
1682 }
1683 if err := agent.deviceRoutes.Print(); err != nil {
1684 return err
1685 }
1686
khenaidoo2c6a0992019-04-29 13:46:56 -04001687 return nil
khenaidoo19d7b632018-10-30 10:49:50 -04001688}
1689
khenaidoo820197c2020-02-13 16:35:33 -05001690//updateRoutes updates the device routes
Kent Hagerman2b216042020-04-03 18:28:56 -04001691func (agent *LogicalAgent) updateRoutes(ctx context.Context, lp *voltha.LogicalPort) error {
Girish Kumarf56a4682020-03-20 20:07:46 +00001692 logger.Debugw("updateRoutes", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo442e7c72020-03-10 16:13:48 -04001693 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1694 return err
1695 }
1696 defer agent.requestQueue.RequestComplete()
1697
khenaidoo820197c2020-02-13 16:35:33 -05001698 if agent.deviceRoutes == nil {
1699 agent.deviceRoutes = route.NewDeviceRoutes(agent.logicalDeviceID, agent.deviceMgr.GetDevice)
khenaidoo910204f2019-04-08 17:56:40 -04001700 }
khenaidoo820197c2020-02-13 16:35:33 -05001701 if err := agent.deviceRoutes.AddPort(ctx, lp, agent.logicalDevice.Ports); err != nil {
1702 return err
khenaidoo0a822f92019-05-08 15:15:57 -04001703 }
khenaidoo820197c2020-02-13 16:35:33 -05001704 if err := agent.deviceRoutes.Print(); err != nil {
1705 return err
1706 }
1707 return nil
khenaidoo0a822f92019-05-08 15:15:57 -04001708}
1709
khenaidoofc1314d2019-03-14 09:34:21 -04001710// diff go over two lists of logical ports and return what's new, what's changed and what's removed.
khenaidoo910204f2019-04-08 17:56:40 -04001711func diff(oldList, newList []*voltha.LogicalPort) (newPorts, changedPorts, deletedPorts []*voltha.LogicalPort) {
khenaidoofc1314d2019-03-14 09:34:21 -04001712 newPorts = make([]*voltha.LogicalPort, 0)
1713 changedPorts = make([]*voltha.LogicalPort, 0)
1714 deletedPorts = make([]*voltha.LogicalPort, 0)
1715 for _, o := range oldList {
1716 found := false
khenaidoofc1314d2019-03-14 09:34:21 -04001717 for _, n := range newList {
1718 if o.Id == n.Id {
khenaidoofc1314d2019-03-14 09:34:21 -04001719 found = true
1720 break
1721 }
1722 }
1723 if !found {
1724 deletedPorts = append(deletedPorts, o)
1725 }
khenaidoofc1314d2019-03-14 09:34:21 -04001726 }
1727 for _, n := range newList {
1728 found := false
khenaidoo2bc48282019-07-16 18:13:46 -04001729 changed := false
khenaidoofc1314d2019-03-14 09:34:21 -04001730 for _, o := range oldList {
1731 if o.Id == n.Id {
khenaidoo2bc48282019-07-16 18:13:46 -04001732 changed = !reflect.DeepEqual(o, n)
khenaidoofc1314d2019-03-14 09:34:21 -04001733 found = true
1734 break
1735 }
1736 }
1737 if !found {
1738 newPorts = append(newPorts, n)
1739 }
khenaidoo2bc48282019-07-16 18:13:46 -04001740 if changed {
1741 changedPorts = append(changedPorts, n)
1742 }
khenaidoofc1314d2019-03-14 09:34:21 -04001743 }
1744 return
1745}
1746
1747// portUpdated is invoked when a port is updated on the logical device. Until
1748// the POST_ADD notification is fixed, we will use the logical device to
1749// update that data.
Kent Hagerman2b216042020-04-03 18:28:56 -04001750func (agent *LogicalAgent) portUpdated(oldPorts, newPorts []*voltha.LogicalPort) interface{} {
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001751 if reflect.DeepEqual(oldPorts, newPorts) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001752 logger.Debug("ports-have-not-changed")
khenaidoofc1314d2019-03-14 09:34:21 -04001753 return nil
1754 }
1755
1756 // Get the difference between the two list
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001757 newPorts, changedPorts, deletedPorts := diff(oldPorts, newPorts)
khenaidoofc1314d2019-03-14 09:34:21 -04001758
1759 // Send the port change events to the OF controller
khenaidoo2c6a0992019-04-29 13:46:56 -04001760 for _, newP := range newPorts {
Kent Hagerman2b216042020-04-03 18:28:56 -04001761 go agent.ldeviceMgr.eventCallbacks.SendChangeEvent(agent.logicalDeviceID,
khenaidoo2c6a0992019-04-29 13:46:56 -04001762 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_ADD, Desc: newP.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001763 }
1764 for _, change := range changedPorts {
Kent Hagerman2b216042020-04-03 18:28:56 -04001765 go agent.ldeviceMgr.eventCallbacks.SendChangeEvent(agent.logicalDeviceID,
khenaidoo910204f2019-04-08 17:56:40 -04001766 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_MODIFY, Desc: change.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001767 }
1768 for _, del := range deletedPorts {
Kent Hagerman2b216042020-04-03 18:28:56 -04001769 go agent.ldeviceMgr.eventCallbacks.SendChangeEvent(agent.logicalDeviceID,
khenaidoo910204f2019-04-08 17:56:40 -04001770 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_DELETE, Desc: del.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001771 }
1772
1773 return nil
1774}
1775
khenaidoo8f474192019-04-03 17:20:44 -04001776// addNNILogicalPort adds an NNI port to the logical device. It returns a bool representing whether a port has been
1777// added and an eror in case a valid error is encountered. If the port was successfully added it will return
1778// (true, nil). If the device is not in the correct state it will return (false, nil) as this is a valid
1779// scenario. This also applies to the case where the port was already added.
Kent Hagerman2b216042020-04-03 18:28:56 -04001780func (agent *LogicalAgent) addNNILogicalPort(ctx context.Context, device *voltha.Device, port *voltha.Port) (bool, error) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001781 logger.Debugw("addNNILogicalPort", log.Fields{"NNI": port})
Chaitrashree G S7849b322020-03-29 19:25:49 -04001782
khenaidoo442e7c72020-03-10 16:13:48 -04001783 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1784 return false, err
1785 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001786 if agent.portExist(device, port) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001787 logger.Debugw("port-already-exist", log.Fields{"port": port})
khenaidoo442e7c72020-03-10 16:13:48 -04001788 agent.requestQueue.RequestComplete()
khenaidoo8f474192019-04-03 17:20:44 -04001789 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001790 }
khenaidoo442e7c72020-03-10 16:13:48 -04001791 agent.requestQueue.RequestComplete()
khenaidoo1ce37ad2019-03-24 22:07:24 -04001792
khenaidoofc1314d2019-03-14 09:34:21 -04001793 var portCap *ic.PortCapability
1794 var err error
1795 // First get the port capability
npujar467fe752020-01-16 20:17:45 +05301796 if portCap, err = agent.deviceMgr.getPortCapability(ctx, device.Id, port.PortNo); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001797 logger.Errorw("error-retrieving-port-capabilities", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001798 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001799 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001800
khenaidoo442e7c72020-03-10 16:13:48 -04001801 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1802 return false, err
1803 }
1804
1805 defer agent.requestQueue.RequestComplete()
khenaidoo1ce37ad2019-03-24 22:07:24 -04001806 // Double check again if this port has been already added since the getPortCapability could have taken a long time
1807 if agent.portExist(device, port) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001808 logger.Debugw("port-already-exist", log.Fields{"port": port})
khenaidoo8f474192019-04-03 17:20:44 -04001809 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001810 }
1811
khenaidoofc1314d2019-03-14 09:34:21 -04001812 portCap.Port.RootPort = true
1813 lp := (proto.Clone(portCap.Port)).(*voltha.LogicalPort)
1814 lp.DeviceId = device.Id
1815 lp.Id = fmt.Sprintf("nni-%d", port.PortNo)
1816 lp.OfpPort.PortNo = port.PortNo
1817 lp.OfpPort.Name = lp.Id
1818 lp.DevicePortNo = port.PortNo
1819
khenaidoo6e55d9e2019-12-12 18:26:26 -05001820 ld := agent.getLogicalDeviceWithoutLock()
1821
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001822 clonedPorts := clonePorts(ld.Ports)
1823 if clonedPorts == nil {
1824 clonedPorts = make([]*voltha.LogicalPort, 0)
khenaidoofc1314d2019-03-14 09:34:21 -04001825 }
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001826 clonedPorts = append(clonedPorts, lp)
khenaidoofc1314d2019-03-14 09:34:21 -04001827
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001828 if err = agent.updateLogicalDevicePortsWithoutLock(ctx, ld, clonedPorts); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001829 logger.Errorw("error-updating-logical-device", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001830 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001831 }
khenaidoo910204f2019-04-08 17:56:40 -04001832
khenaidoo820197c2020-02-13 16:35:33 -05001833 // Update the device routes with this new logical port
khenaidoo910204f2019-04-08 17:56:40 -04001834 clonedLP := (proto.Clone(lp)).(*voltha.LogicalPort)
khenaidoo820197c2020-02-13 16:35:33 -05001835 go func() {
1836 if err := agent.updateRoutes(context.Background(), clonedLP); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001837 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 -05001838 }
1839 }()
khenaidoo910204f2019-04-08 17:56:40 -04001840
khenaidoo8f474192019-04-03 17:20:44 -04001841 return true, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001842}
1843
Kent Hagerman2b216042020-04-03 18:28:56 -04001844func (agent *LogicalAgent) portExist(device *voltha.Device, port *voltha.Port) bool {
khenaidoo6e55d9e2019-12-12 18:26:26 -05001845 ldevice := agent.getLogicalDeviceWithoutLock()
1846 for _, lPort := range ldevice.Ports {
1847 if lPort.DeviceId == device.Id && lPort.DevicePortNo == port.PortNo && lPort.Id == port.Label {
1848 return true
khenaidoofc1314d2019-03-14 09:34:21 -04001849 }
1850 }
1851 return false
1852}
1853
khenaidoo8f474192019-04-03 17:20:44 -04001854// addUNILogicalPort adds an UNI port to the logical device. It returns a bool representing whether a port has been
1855// added and an eror in case a valid error is encountered. If the port was successfully added it will return
1856// (true, nil). If the device is not in the correct state it will return (false, nil) as this is a valid
1857// scenario. This also applies to the case where the port was already added.
Kent Hagerman2b216042020-04-03 18:28:56 -04001858func (agent *LogicalAgent) addUNILogicalPort(ctx context.Context, childDevice *voltha.Device, port *voltha.Port) (bool, error) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001859 logger.Debugw("addUNILogicalPort", log.Fields{"port": port})
khenaidoo8f474192019-04-03 17:20:44 -04001860 if childDevice.AdminState != voltha.AdminState_ENABLED || childDevice.OperStatus != voltha.OperStatus_ACTIVE {
Girish Kumarf56a4682020-03-20 20:07:46 +00001861 logger.Infow("device-not-ready", log.Fields{"deviceId": childDevice.Id, "admin": childDevice.AdminState, "oper": childDevice.OperStatus})
khenaidoo8f474192019-04-03 17:20:44 -04001862 return false, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001863 }
khenaidoo442e7c72020-03-10 16:13:48 -04001864 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1865 return false, err
1866 }
1867
khenaidoo1ce37ad2019-03-24 22:07:24 -04001868 if agent.portExist(childDevice, port) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001869 logger.Debugw("port-already-exist", log.Fields{"port": port})
khenaidoo442e7c72020-03-10 16:13:48 -04001870 agent.requestQueue.RequestComplete()
khenaidoo8f474192019-04-03 17:20:44 -04001871 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001872 }
khenaidoo442e7c72020-03-10 16:13:48 -04001873 agent.requestQueue.RequestComplete()
khenaidoofc1314d2019-03-14 09:34:21 -04001874 var portCap *ic.PortCapability
1875 var err error
1876 // First get the port capability
npujar467fe752020-01-16 20:17:45 +05301877 if portCap, err = agent.deviceMgr.getPortCapability(ctx, childDevice.Id, port.PortNo); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001878 logger.Errorw("error-retrieving-port-capabilities", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001879 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001880 }
khenaidoo442e7c72020-03-10 16:13:48 -04001881 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1882 return false, err
1883 }
1884 defer agent.requestQueue.RequestComplete()
khenaidoo1ce37ad2019-03-24 22:07:24 -04001885 // Double check again if this port has been already added since the getPortCapability could have taken a long time
1886 if agent.portExist(childDevice, port) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001887 logger.Debugw("port-already-exist", log.Fields{"port": port})
khenaidoo8f474192019-04-03 17:20:44 -04001888 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001889 }
khenaidoofc1314d2019-03-14 09:34:21 -04001890 // Get stored logical device
khenaidoo6e55d9e2019-12-12 18:26:26 -05001891 ldevice := agent.getLogicalDeviceWithoutLock()
1892
Girish Kumarf56a4682020-03-20 20:07:46 +00001893 logger.Debugw("adding-uni", log.Fields{"deviceId": childDevice.Id})
npujar1d86a522019-11-14 17:11:16 +05301894 portCap.Port.RootPort = false
1895 portCap.Port.Id = port.Label
1896 portCap.Port.OfpPort.PortNo = port.PortNo
1897 portCap.Port.DeviceId = childDevice.Id
1898 portCap.Port.DevicePortNo = port.PortNo
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001899 clonedPorts := clonePorts(ldevice.Ports)
1900 if clonedPorts == nil {
1901 clonedPorts = make([]*voltha.LogicalPort, 0)
npujar1d86a522019-11-14 17:11:16 +05301902 }
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001903 clonedPorts = append(clonedPorts, portCap.Port)
1904 if err := agent.updateLogicalDevicePortsWithoutLock(ctx, ldevice, clonedPorts); err != nil {
npujar1d86a522019-11-14 17:11:16 +05301905 return false, err
1906 }
1907 // Update the device graph with this new logical port
1908 clonedLP := (proto.Clone(portCap.Port)).(*voltha.LogicalPort)
khenaidoo820197c2020-02-13 16:35:33 -05001909
1910 go func() {
1911 if err := agent.updateRoutes(context.Background(), clonedLP); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001912 logger.Warn("routes-not-ready", log.Fields{"logical-device-id": agent.logicalDeviceID, "error": err})
khenaidoo820197c2020-02-13 16:35:33 -05001913 }
1914 }()
1915
npujar1d86a522019-11-14 17:11:16 +05301916 return true, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001917}
1918
Kent Hagerman2b216042020-04-03 18:28:56 -04001919func (agent *LogicalAgent) packetOut(ctx context.Context, packet *ofp.OfpPacketOut) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001920 logger.Debugw("packet-out", log.Fields{
Matteo Scandolo360605d2019-11-05 18:29:17 -08001921 "packet": hex.EncodeToString(packet.Data),
1922 "inPort": packet.GetInPort(),
1923 })
khenaidoo68c930b2019-05-13 11:46:51 -04001924 outPort := fu.GetPacketOutPort(packet)
khenaidoofdbad6e2018-11-06 22:26:38 -05001925 //frame := packet.GetData()
1926 //TODO: Use a channel between the logical agent and the device agent
npujar467fe752020-01-16 20:17:45 +05301927 if err := agent.deviceMgr.packetOut(ctx, agent.rootDeviceID, outPort, packet); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001928 logger.Error("packetout-failed", log.Fields{"logicalDeviceID": agent.rootDeviceID})
khenaidooca301322019-01-09 23:06:32 -05001929 }
khenaidoofdbad6e2018-11-06 22:26:38 -05001930}
1931
Kent Hagerman2b216042020-04-03 18:28:56 -04001932func (agent *LogicalAgent) packetIn(port uint32, transactionID string, packet []byte) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001933 logger.Debugw("packet-in", log.Fields{
Matteo Scandolo360605d2019-11-05 18:29:17 -08001934 "port": port,
1935 "packet": hex.EncodeToString(packet),
npujar1d86a522019-11-14 17:11:16 +05301936 "transactionId": transactionID,
Matteo Scandolo360605d2019-11-05 18:29:17 -08001937 })
khenaidoo68c930b2019-05-13 11:46:51 -04001938 packetIn := fu.MkPacketIn(port, packet)
Kent Hagerman2b216042020-04-03 18:28:56 -04001939 agent.ldeviceMgr.eventCallbacks.SendPacketIn(agent.logicalDeviceID, transactionID, packetIn)
Girish Kumarf56a4682020-03-20 20:07:46 +00001940 logger.Debugw("sending-packet-in", log.Fields{"packet": hex.EncodeToString(packetIn.Data)})
khenaidoofdbad6e2018-11-06 22:26:38 -05001941}
khenaidoo2c6a0992019-04-29 13:46:56 -04001942
Kent Hagerman2b216042020-04-03 18:28:56 -04001943func (agent *LogicalAgent) addLogicalPortToMap(portNo uint32, nniPort bool) {
khenaidoo2c6a0992019-04-29 13:46:56 -04001944 agent.lockLogicalPortsNo.Lock()
1945 defer agent.lockLogicalPortsNo.Unlock()
1946 if exist := agent.logicalPortsNo[portNo]; !exist {
1947 agent.logicalPortsNo[portNo] = nniPort
1948 }
1949}
1950
Kent Hagerman2b216042020-04-03 18:28:56 -04001951func (agent *LogicalAgent) deleteLogicalPortsFromMap(portsNo []uint32) {
khenaidoo820197c2020-02-13 16:35:33 -05001952 agent.lockLogicalPortsNo.Lock()
1953 defer agent.lockLogicalPortsNo.Unlock()
1954 for _, pNo := range portsNo {
1955 delete(agent.logicalPortsNo, pNo)
1956 }
1957}
1958
Kent Hagerman2b216042020-04-03 18:28:56 -04001959func (agent *LogicalAgent) addLogicalPortsToMap(lps []*voltha.LogicalPort) {
khenaidoo3d3b8c22019-05-22 18:10:39 -04001960 agent.lockLogicalPortsNo.Lock()
1961 defer agent.lockLogicalPortsNo.Unlock()
1962 for _, lp := range lps {
1963 if exist := agent.logicalPortsNo[lp.DevicePortNo]; !exist {
1964 agent.logicalPortsNo[lp.DevicePortNo] = lp.RootPort
1965 }
1966 }
1967}
1968
Kent Hagerman2b216042020-04-03 18:28:56 -04001969func (agent *LogicalAgent) isNNIPort(portNo uint32) bool {
khenaidoo2c6a0992019-04-29 13:46:56 -04001970 agent.lockLogicalPortsNo.RLock()
1971 defer agent.lockLogicalPortsNo.RUnlock()
1972 if exist := agent.logicalPortsNo[portNo]; exist {
1973 return agent.logicalPortsNo[portNo]
1974 }
1975 return false
1976}
1977
Kent Hagerman2b216042020-04-03 18:28:56 -04001978func (agent *LogicalAgent) getFirstNNIPort() (uint32, error) {
khenaidoo2c6a0992019-04-29 13:46:56 -04001979 agent.lockLogicalPortsNo.RLock()
1980 defer agent.lockLogicalPortsNo.RUnlock()
1981 for portNo, nni := range agent.logicalPortsNo {
1982 if nni {
1983 return portNo, nil
1984 }
1985 }
1986 return 0, status.Error(codes.NotFound, "No NNI port found")
1987}
Esin Karaman09959ae2019-11-29 13:59:58 +00001988
1989//GetNNIPorts returns NNI ports.
Kent Hagerman2b216042020-04-03 18:28:56 -04001990func (agent *LogicalAgent) GetNNIPorts() []uint32 {
Esin Karaman09959ae2019-11-29 13:59:58 +00001991 agent.lockLogicalPortsNo.RLock()
1992 defer agent.lockLogicalPortsNo.RUnlock()
1993 nniPorts := make([]uint32, 0)
1994 for portNo, nni := range agent.logicalPortsNo {
1995 if nni {
1996 nniPorts = append(nniPorts, portNo)
1997 }
1998 }
1999 return nniPorts
2000}