blob: 9dc873b5af960b6ef91998ddde7870cf05f34f02 [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
khenaidoob9203542018-09-17 22:56:37 -040017package core
18
19import (
20 "context"
Matteo Scandolo360605d2019-11-05 18:29:17 -080021 "encoding/hex"
khenaidoo19d7b632018-10-30 10:49:50 -040022 "errors"
23 "fmt"
David Bainbridgefd27f4b2020-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
42const (
43 maxOrderedLogicalDeviceRequestQueueSize = 1000
khenaidoob9203542018-09-17 22:56:37 -040044)
45
npujar1d86a522019-11-14 17:11:16 +053046// LogicalDeviceAgent represent attributes of logical device agent
khenaidoob9203542018-09-17 22:56:37 -040047type LogicalDeviceAgent struct {
npujar1d86a522019-11-14 17:11:16 +053048 logicalDeviceID string
David Bainbridgefd27f4b2020-03-26 18:27:41 -070049 serialNumber string
npujar1d86a522019-11-14 17:11:16 +053050 rootDeviceID string
khenaidoo3306c992019-05-24 16:57:35 -040051 deviceMgr *DeviceManager
52 ldeviceMgr *LogicalDeviceManager
53 clusterDataProxy *model.Proxy
54 exitChannel chan int
khenaidoo820197c2020-02-13 16:35:33 -050055 deviceRoutes *route.DeviceRoutes
khenaidoo3306c992019-05-24 16:57:35 -040056 flowProxy *model.Proxy
57 groupProxy *model.Proxy
Manikkaraj kb1a10922019-07-29 12:10:34 -040058 meterProxy *model.Proxy
khenaidoo3306c992019-05-24 16:57:35 -040059 ldProxy *model.Proxy
60 portProxies map[string]*model.Proxy
khenaidoo820197c2020-02-13 16:35:33 -050061 lockDeviceRoutes sync.RWMutex
khenaidoo3306c992019-05-24 16:57:35 -040062 logicalPortsNo map[uint32]bool //value is true for NNI port
63 lockLogicalPortsNo sync.RWMutex
64 flowDecomposer *fd.FlowDecomposer
khenaidoo442e7c72020-03-10 16:13:48 -040065 defaultTimeout time.Duration
khenaidoo6e55d9e2019-12-12 18:26:26 -050066 logicalDevice *voltha.LogicalDevice
khenaidoo442e7c72020-03-10 16:13:48 -040067 requestQueue *coreutils.RequestQueue
68 startOnce sync.Once
69 stopOnce sync.Once
khenaidoob9203542018-09-17 22:56:37 -040070}
71
David Bainbridgefd27f4b2020-03-26 18:27:41 -070072func newLogicalDeviceAgent(id string, sn string, deviceID string, ldeviceMgr *LogicalDeviceManager,
73 deviceMgr *DeviceManager, cdProxy *model.Proxy, timeout time.Duration) *LogicalDeviceAgent {
khenaidoob9203542018-09-17 22:56:37 -040074 var agent LogicalDeviceAgent
75 agent.exitChannel = make(chan int, 1)
npujar1d86a522019-11-14 17:11:16 +053076 agent.logicalDeviceID = id
David Bainbridgefd27f4b2020-03-26 18:27:41 -070077 agent.serialNumber = sn
npujar1d86a522019-11-14 17:11:16 +053078 agent.rootDeviceID = deviceID
khenaidoob9203542018-09-17 22:56:37 -040079 agent.deviceMgr = deviceMgr
khenaidoo9a468962018-09-19 15:33:13 -040080 agent.clusterDataProxy = cdProxy
khenaidoob9203542018-09-17 22:56:37 -040081 agent.ldeviceMgr = ldeviceMgr
khenaidoo19d7b632018-10-30 10:49:50 -040082 agent.flowDecomposer = fd.NewFlowDecomposer(agent.deviceMgr)
khenaidoofc1314d2019-03-14 09:34:21 -040083 agent.portProxies = make(map[string]*model.Proxy)
khenaidoo2c6a0992019-04-29 13:46:56 -040084 agent.logicalPortsNo = make(map[uint32]bool)
khenaidoo2c6a0992019-04-29 13:46:56 -040085 agent.defaultTimeout = timeout
David Bainbridgefd27f4b2020-03-26 18:27:41 -070086 agent.requestQueue = coreutils.NewRequestQueue(agent.serialNumber, maxOrderedLogicalDeviceRequestQueueSize)
khenaidoob9203542018-09-17 22:56:37 -040087 return &agent
88}
89
khenaidoo4d4802d2018-10-04 21:59:49 -040090// start creates the logical device and add it to the data model
khenaidoo442e7c72020-03-10 16:13:48 -040091func (agent *LogicalDeviceAgent) start(ctx context.Context, loadFromDB bool) error {
92 needToStart := false
93 if agent.startOnce.Do(func() { needToStart = true }); !needToStart {
94 return nil
95 }
96
Girish Kumarf56a4682020-03-20 20:07:46 +000097 logger.Infow("starting-logical_device-agent", log.Fields{"logical-device-id": agent.logicalDeviceID, "load-from-db": loadFromDB})
khenaidoo442e7c72020-03-10 16:13:48 -040098
99 var startSucceeded bool
100 defer func() {
101 if !startSucceeded {
102 if err := agent.stop(ctx); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000103 logger.Errorw("failed-to-cleanup-after-unsuccessful-start", log.Fields{"logical-device-id": agent.logicalDeviceID, "error": err})
khenaidoo442e7c72020-03-10 16:13:48 -0400104 }
105 }
106 }()
107
108 // Launch the request queue - it will launch a go routine
109 agent.requestQueue.Start()
110
khenaidoo297cd252019-02-07 22:10:23 -0500111 var ld *voltha.LogicalDevice
khenaidoo442e7c72020-03-10 16:13:48 -0400112 if !loadFromDB {
khenaidoo7e3d8f12019-08-02 16:06:30 -0400113 //Build the logical device based on information retrieved from the device adapter
114 var switchCap *ic.SwitchCapability
khenaidoo297cd252019-02-07 22:10:23 -0500115 var err error
npujar1d86a522019-11-14 17:11:16 +0530116 if switchCap, err = agent.deviceMgr.getSwitchCapability(ctx, agent.rootDeviceID); err != nil {
khenaidoo7e3d8f12019-08-02 16:06:30 -0400117 return err
118 }
npujar1d86a522019-11-14 17:11:16 +0530119 ld = &voltha.LogicalDevice{Id: agent.logicalDeviceID, RootDeviceId: agent.rootDeviceID}
khenaidoo297cd252019-02-07 22:10:23 -0500120
121 // Create the datapath ID (uint64) using the logical device ID (based on the MAC Address)
122 var datapathID uint64
David Bainbridgefd27f4b2020-03-26 18:27:41 -0700123 if datapathID, err = CreateDataPathID(agent.serialNumber); err != nil {
khenaidoo297cd252019-02-07 22:10:23 -0500124 return err
125 }
126 ld.DatapathId = datapathID
khenaidoo7e3d8f12019-08-02 16:06:30 -0400127 ld.Desc = (proto.Clone(switchCap.Desc)).(*ofp.OfpDesc)
Girish Kumarf56a4682020-03-20 20:07:46 +0000128 logger.Debugw("Switch-capability", log.Fields{"Desc": ld.Desc, "fromAd": switchCap.Desc})
khenaidoo7e3d8f12019-08-02 16:06:30 -0400129 ld.SwitchFeatures = (proto.Clone(switchCap.SwitchFeatures)).(*ofp.OfpSwitchFeatures)
khenaidoo297cd252019-02-07 22:10:23 -0500130 ld.Flows = &ofp.Flows{Items: nil}
131 ld.FlowGroups = &ofp.FlowGroups{Items: nil}
khenaidoo49085352020-01-13 19:15:43 -0500132 ld.Ports = []*voltha.LogicalPort{}
khenaidoo297cd252019-02-07 22:10:23 -0500133
khenaidoo297cd252019-02-07 22:10:23 -0500134 // Save the logical device
Thomas Lee Se5a44012019-11-07 20:32:24 +0530135 added, err := agent.clusterDataProxy.AddWithID(ctx, "/logical_devices", ld.Id, ld, "")
136 if err != nil {
Thomas Lee Se5a44012019-11-07 20:32:24 +0530137 return err
138 }
139 if added == nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000140 logger.Errorw("failed-to-add-logical-device", log.Fields{"logical-device-id": agent.logicalDeviceID})
khenaidoo297cd252019-02-07 22:10:23 -0500141 } else {
Girish Kumarf56a4682020-03-20 20:07:46 +0000142 logger.Debugw("logicaldevice-created", log.Fields{"logical-device-id": agent.logicalDeviceID, "root-id": ld.RootDeviceId})
khenaidoo297cd252019-02-07 22:10:23 -0500143 }
khenaidoo6e55d9e2019-12-12 18:26:26 -0500144
145 agent.logicalDevice = proto.Clone(ld).(*voltha.LogicalDevice)
khenaidoofc1314d2019-03-14 09:34:21 -0400146
khenaidoo442e7c72020-03-10 16:13:48 -0400147 // Setup the logicalports - internal processing, no need to propagate the client context
npujar1d86a522019-11-14 17:11:16 +0530148 go func() {
khenaidoo442e7c72020-03-10 16:13:48 -0400149 err := agent.setupLogicalPorts(context.Background())
npujar1d86a522019-11-14 17:11:16 +0530150 if err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000151 logger.Errorw("unable-to-setup-logical-ports", log.Fields{"error": err})
npujar1d86a522019-11-14 17:11:16 +0530152 }
153 }()
khenaidoo297cd252019-02-07 22:10:23 -0500154 } else {
155 // load from dB - the logical may not exist at this time. On error, just return and the calling function
156 // will destroy this agent.
npujar467fe752020-01-16 20:17:45 +0530157 logicalDevice, err := agent.clusterDataProxy.Get(ctx, "/logical_devices/"+agent.logicalDeviceID, 0, true, "")
Thomas Lee Se5a44012019-11-07 20:32:24 +0530158 if err != nil {
khenaidoo442e7c72020-03-10 16:13:48 -0400159 return err
Thomas Lee Se5a44012019-11-07 20:32:24 +0530160 }
khenaidoo6e55d9e2019-12-12 18:26:26 -0500161 ld, ok := logicalDevice.(*voltha.LogicalDevice)
162 if !ok {
khenaidoo6e55d9e2019-12-12 18:26:26 -0500163 return status.Errorf(codes.NotFound, "logical_device-%s", agent.logicalDeviceID)
khenaidoo297cd252019-02-07 22:10:23 -0500164 }
khenaidoo8c3303d2019-02-13 14:59:39 -0500165 // Update the root device Id
npujar1d86a522019-11-14 17:11:16 +0530166 agent.rootDeviceID = ld.RootDeviceId
khenaidoo3d3b8c22019-05-22 18:10:39 -0400167
khenaidoo6e55d9e2019-12-12 18:26:26 -0500168 // Update the last data
169 agent.logicalDevice = proto.Clone(ld).(*voltha.LogicalDevice)
170
khenaidoo3d3b8c22019-05-22 18:10:39 -0400171 // Setup the local list of logical ports
172 agent.addLogicalPortsToMap(ld.Ports)
khenaidoob9203542018-09-17 22:56:37 -0400173 }
khenaidoofc1314d2019-03-14 09:34:21 -0400174
khenaidoo442e7c72020-03-10 16:13:48 -0400175 var err error
Thomas Lee Se5a44012019-11-07 20:32:24 +0530176 agent.flowProxy, err = agent.clusterDataProxy.CreateProxy(
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400177 ctx,
npujar1d86a522019-11-14 17:11:16 +0530178 fmt.Sprintf("/logical_devices/%s/flows", agent.logicalDeviceID),
khenaidoo19d7b632018-10-30 10:49:50 -0400179 false)
Thomas Lee Se5a44012019-11-07 20:32:24 +0530180 if err != nil {
Thomas Lee Se5a44012019-11-07 20:32:24 +0530181 return err
182 }
183 agent.meterProxy, err = agent.clusterDataProxy.CreateProxy(
Manikkaraj kb1a10922019-07-29 12:10:34 -0400184 ctx,
npujar1d86a522019-11-14 17:11:16 +0530185 fmt.Sprintf("/logical_devices/%s/meters", agent.logicalDeviceID),
Manikkaraj kb1a10922019-07-29 12:10:34 -0400186 false)
Thomas Lee Se5a44012019-11-07 20:32:24 +0530187 if err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000188 logger.Errorw("failed-to-create-meter-proxy", log.Fields{"error": err})
Thomas Lee Se5a44012019-11-07 20:32:24 +0530189 return err
190 }
191 agent.groupProxy, err = agent.clusterDataProxy.CreateProxy(
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400192 ctx,
npujar1d86a522019-11-14 17:11:16 +0530193 fmt.Sprintf("/logical_devices/%s/flow_groups", agent.logicalDeviceID),
khenaidoo19d7b632018-10-30 10:49:50 -0400194 false)
Thomas Lee Se5a44012019-11-07 20:32:24 +0530195 if err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000196 logger.Errorw("failed-to-create-group-proxy", log.Fields{"error": err})
Thomas Lee Se5a44012019-11-07 20:32:24 +0530197 return err
198 }
199 agent.ldProxy, err = agent.clusterDataProxy.CreateProxy(
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400200 ctx,
npujar1d86a522019-11-14 17:11:16 +0530201 fmt.Sprintf("/logical_devices/%s", agent.logicalDeviceID),
khenaidoofc1314d2019-03-14 09:34:21 -0400202 false)
Thomas Lee Se5a44012019-11-07 20:32:24 +0530203 if err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000204 logger.Errorw("failed-to-create-logical-device-proxy", log.Fields{"error": err})
Thomas Lee Se5a44012019-11-07 20:32:24 +0530205 return err
206 }
khenaidoofc1314d2019-03-14 09:34:21 -0400207 // TODO: Use a port proxy once the POST_ADD is fixed
khenaidoo3d3b8c22019-05-22 18:10:39 -0400208 if agent.ldProxy != nil {
npujar9a30c702019-11-14 17:06:39 +0530209 agent.ldProxy.RegisterCallback(model.PostUpdate, agent.portUpdated)
khenaidoo3d3b8c22019-05-22 18:10:39 -0400210 } else {
khenaidoo3d3b8c22019-05-22 18:10:39 -0400211 return status.Error(codes.Internal, "logical-device-proxy-null")
212 }
khenaidoobcf205b2019-01-25 22:21:14 -0500213
khenaidoo820197c2020-02-13 16:35:33 -0500214 // 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 -0400215 if loadFromDB {
khenaidoo820197c2020-02-13 16:35:33 -0500216 go func() {
217 if err := agent.buildRoutes(context.Background()); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000218 logger.Warn("routes-not-ready", log.Fields{"logical-device-id": agent.logicalDeviceID, "error": err})
khenaidoo820197c2020-02-13 16:35:33 -0500219 }
220 }()
khenaidoo4c9e5592019-09-09 16:20:41 -0400221 }
khenaidoo442e7c72020-03-10 16:13:48 -0400222 startSucceeded = true
223
khenaidoob9203542018-09-17 22:56:37 -0400224 return nil
225}
226
khenaidoo442e7c72020-03-10 16:13:48 -0400227// stop stops the logical device agent. This removes the logical device from the data model.
Thomas Lee Se5a44012019-11-07 20:32:24 +0530228func (agent *LogicalDeviceAgent) stop(ctx context.Context) error {
khenaidoo442e7c72020-03-10 16:13:48 -0400229 var returnErr error
230 agent.stopOnce.Do(func() {
Girish Kumarf56a4682020-03-20 20:07:46 +0000231 logger.Info("stopping-logical_device-agent")
khenaidoo8c3303d2019-02-13 14:59:39 -0500232
khenaidoo442e7c72020-03-10 16:13:48 -0400233 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
234 // This should never happen - an error is returned only if the agent is stopped and an agent is only stopped once.
235 returnErr = err
236 return
237 }
238 defer agent.requestQueue.RequestComplete()
239
240 //Remove the logical device from the model
241 if removed, err := agent.clusterDataProxy.Remove(ctx, "/logical_devices/"+agent.logicalDeviceID, ""); err != nil {
242 returnErr = err
243 } else if removed == nil {
244 returnErr = status.Errorf(codes.Aborted, "failed-to-remove-logical-ldevice-%s", agent.logicalDeviceID)
245 } else {
Girish Kumarf56a4682020-03-20 20:07:46 +0000246 logger.Debugw("logicaldevice-removed", log.Fields{"logicaldeviceId": agent.logicalDeviceID})
khenaidoo442e7c72020-03-10 16:13:48 -0400247 }
248
249 // Stop the request queue and request complete indication
250 agent.requestQueue.Stop()
251
252 close(agent.exitChannel)
253
Girish Kumarf56a4682020-03-20 20:07:46 +0000254 logger.Info("logical_device-agent-stopped")
khenaidoo442e7c72020-03-10 16:13:48 -0400255 })
256 return returnErr
khenaidoo4d4802d2018-10-04 21:59:49 -0400257}
258
khenaidoo6e55d9e2019-12-12 18:26:26 -0500259// GetLogicalDevice returns the latest logical device data
khenaidoo442e7c72020-03-10 16:13:48 -0400260func (agent *LogicalDeviceAgent) GetLogicalDevice(ctx context.Context) (*voltha.LogicalDevice, error) {
261 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
262 return nil, err
263 }
264 defer agent.requestQueue.RequestComplete()
265 return proto.Clone(agent.logicalDevice).(*voltha.LogicalDevice), nil
khenaidoo92e62c52018-10-03 14:02:54 -0400266}
267
npujar1d86a522019-11-14 17:11:16 +0530268// ListLogicalDeviceFlows returns logical device flows
khenaidoo442e7c72020-03-10 16:13:48 -0400269func (agent *LogicalDeviceAgent) ListLogicalDeviceFlows(ctx context.Context) (*ofp.Flows, error) {
Girish Kumarf56a4682020-03-20 20:07:46 +0000270 logger.Debug("ListLogicalDeviceFlows")
khenaidoo6e55d9e2019-12-12 18:26:26 -0500271
khenaidoo442e7c72020-03-10 16:13:48 -0400272 logicalDevice, err := agent.GetLogicalDevice(ctx)
273 if err != nil {
274 return nil, err
khenaidoodd237172019-05-27 16:37:17 -0400275 }
khenaidoo442e7c72020-03-10 16:13:48 -0400276 if logicalDevice.Flows == nil {
277 return &ofp.Flows{}, nil
278 }
279 return (proto.Clone(logicalDevice.Flows)).(*ofp.Flows), nil
khenaidoodd237172019-05-27 16:37:17 -0400280}
281
npujar1d86a522019-11-14 17:11:16 +0530282// ListLogicalDeviceMeters returns logical device meters
khenaidoo442e7c72020-03-10 16:13:48 -0400283func (agent *LogicalDeviceAgent) ListLogicalDeviceMeters(ctx context.Context) (*ofp.Meters, error) {
Girish Kumarf56a4682020-03-20 20:07:46 +0000284 logger.Debug("ListLogicalDeviceMeters")
khenaidoo6e55d9e2019-12-12 18:26:26 -0500285
khenaidoo442e7c72020-03-10 16:13:48 -0400286 logicalDevice, err := agent.GetLogicalDevice(ctx)
287 if err != nil {
288 return nil, err
Manikkaraj kb1a10922019-07-29 12:10:34 -0400289 }
khenaidoo442e7c72020-03-10 16:13:48 -0400290 if logicalDevice.Meters == nil {
291 return &ofp.Meters{}, nil
292 }
293 return (proto.Clone(logicalDevice.Meters)).(*ofp.Meters), nil
Manikkaraj kb1a10922019-07-29 12:10:34 -0400294}
295
npujar1d86a522019-11-14 17:11:16 +0530296// ListLogicalDeviceFlowGroups returns logical device flow groups
khenaidoo442e7c72020-03-10 16:13:48 -0400297func (agent *LogicalDeviceAgent) ListLogicalDeviceFlowGroups(ctx context.Context) (*ofp.FlowGroups, error) {
Girish Kumarf56a4682020-03-20 20:07:46 +0000298 logger.Debug("ListLogicalDeviceFlowGroups")
khenaidoo6e55d9e2019-12-12 18:26:26 -0500299
khenaidoo442e7c72020-03-10 16:13:48 -0400300 logicalDevice, err := agent.GetLogicalDevice(ctx)
301 if err != nil {
302 return nil, err
khenaidoodd237172019-05-27 16:37:17 -0400303 }
khenaidoo442e7c72020-03-10 16:13:48 -0400304 if logicalDevice.FlowGroups == nil {
305 return &ofp.FlowGroups{}, nil
306 }
307 return (proto.Clone(logicalDevice.FlowGroups)).(*ofp.FlowGroups), nil
khenaidoodd237172019-05-27 16:37:17 -0400308}
309
npujar1d86a522019-11-14 17:11:16 +0530310// ListLogicalDevicePorts returns logical device ports
khenaidoo442e7c72020-03-10 16:13:48 -0400311func (agent *LogicalDeviceAgent) ListLogicalDevicePorts(ctx context.Context) (*voltha.LogicalPorts, error) {
Girish Kumarf56a4682020-03-20 20:07:46 +0000312 logger.Debug("ListLogicalDevicePorts")
khenaidoo442e7c72020-03-10 16:13:48 -0400313 logicalDevice, err := agent.GetLogicalDevice(ctx)
314 if err != nil {
315 return nil, err
316 }
317 if logicalDevice == nil {
318 return &voltha.LogicalPorts{}, nil
319 }
khenaidoo6e55d9e2019-12-12 18:26:26 -0500320 lPorts := make([]*voltha.LogicalPort, 0)
321 lPorts = append(lPorts, logicalDevice.Ports...)
khenaidoo442e7c72020-03-10 16:13:48 -0400322 return &voltha.LogicalPorts{Items: lPorts}, nil
khenaidoo19d7b632018-10-30 10:49:50 -0400323}
324
khenaidoo4c9e5592019-09-09 16:20:41 -0400325//updateLogicalDeviceFlowsWithoutLock updates the logical device with the latest flows in the model.
npujar467fe752020-01-16 20:17:45 +0530326func (agent *LogicalDeviceAgent) updateLogicalDeviceFlowsWithoutLock(ctx context.Context, flows *ofp.Flows) error {
khenaidoo6e55d9e2019-12-12 18:26:26 -0500327 ld := agent.getLogicalDeviceWithoutLock()
khenaidoo4c9e5592019-09-09 16:20:41 -0400328
Girish Kumarf56a4682020-03-20 20:07:46 +0000329 logger.Debugw("logical-device-before", log.Fields{"lports": len(ld.Ports)})
khenaidoo6e55d9e2019-12-12 18:26:26 -0500330 ld.Flows = flows
331
npujar467fe752020-01-16 20:17:45 +0530332 if err := agent.updateLogicalDeviceWithoutLock(ctx, ld); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000333 logger.Errorw("error-updating-logical-device-with-flows", log.Fields{"error": err})
khenaidoo4c9e5592019-09-09 16:20:41 -0400334 return err
khenaidoo43c82122018-11-22 18:38:28 -0500335 }
khenaidoo43c82122018-11-22 18:38:28 -0500336 return nil
337}
338
khenaidoo4c9e5592019-09-09 16:20:41 -0400339//updateLogicalDeviceMetersWithoutLock updates the logical device with the meters info
npujar467fe752020-01-16 20:17:45 +0530340func (agent *LogicalDeviceAgent) updateLogicalDeviceMetersWithoutLock(ctx context.Context, meters *ofp.Meters) error {
khenaidoo6e55d9e2019-12-12 18:26:26 -0500341 ld := agent.getLogicalDeviceWithoutLock()
khenaidoo4c9e5592019-09-09 16:20:41 -0400342
Girish Kumarf56a4682020-03-20 20:07:46 +0000343 logger.Debugw("logical-device-before", log.Fields{"lports": len(ld.Ports)})
khenaidoo6e55d9e2019-12-12 18:26:26 -0500344 ld.Meters = meters
345
npujar467fe752020-01-16 20:17:45 +0530346 if err := agent.updateLogicalDeviceWithoutLock(ctx, ld); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000347 logger.Errorw("error-updating-logical-device-with-meters", log.Fields{"error": err})
khenaidoo4c9e5592019-09-09 16:20:41 -0400348 return err
Manikkaraj kb1a10922019-07-29 12:10:34 -0400349 }
350 return nil
351}
352
khenaidoo4c9e5592019-09-09 16:20:41 -0400353//updateLogicalDeviceFlowGroupsWithoutLock updates the logical device with the flow groups
npujar467fe752020-01-16 20:17:45 +0530354func (agent *LogicalDeviceAgent) updateLogicalDeviceFlowGroupsWithoutLock(ctx context.Context, flowGroups *ofp.FlowGroups) error {
khenaidoo6e55d9e2019-12-12 18:26:26 -0500355 ld := agent.getLogicalDeviceWithoutLock()
khenaidoo4c9e5592019-09-09 16:20:41 -0400356
Girish Kumarf56a4682020-03-20 20:07:46 +0000357 logger.Debugw("logical-device-before", log.Fields{"lports": len(ld.Ports)})
khenaidoo6e55d9e2019-12-12 18:26:26 -0500358 ld.FlowGroups = flowGroups
359
npujar467fe752020-01-16 20:17:45 +0530360 if err := agent.updateLogicalDeviceWithoutLock(ctx, ld); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000361 logger.Errorw("error-updating-logical-device-with-flowgroups", log.Fields{"error": err})
khenaidoo4c9e5592019-09-09 16:20:41 -0400362 return err
khenaidoo43c82122018-11-22 18:38:28 -0500363 }
khenaidoo43c82122018-11-22 18:38:28 -0500364 return nil
365}
366
khenaidoo6e55d9e2019-12-12 18:26:26 -0500367// getLogicalDeviceWithoutLock returns a cloned logical device to a function that already holds the agent lock.
368func (agent *LogicalDeviceAgent) getLogicalDeviceWithoutLock() *voltha.LogicalDevice {
Girish Kumarf56a4682020-03-20 20:07:46 +0000369 logger.Debug("getLogicalDeviceWithoutLock")
khenaidoo6e55d9e2019-12-12 18:26:26 -0500370 return proto.Clone(agent.logicalDevice).(*voltha.LogicalDevice)
khenaidoo92e62c52018-10-03 14:02:54 -0400371}
372
npujar467fe752020-01-16 20:17:45 +0530373func (agent *LogicalDeviceAgent) updateLogicalPort(ctx context.Context, device *voltha.Device, port *voltha.Port) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000374 logger.Debugw("updateLogicalPort", log.Fields{"deviceId": device.Id, "port": port})
khenaidoo2c6a0992019-04-29 13:46:56 -0400375 var err error
376 if port.Type == voltha.Port_ETHERNET_NNI {
npujar467fe752020-01-16 20:17:45 +0530377 if _, err = agent.addNNILogicalPort(ctx, device, port); err != nil {
khenaidoo2c6a0992019-04-29 13:46:56 -0400378 return err
379 }
380 agent.addLogicalPortToMap(port.PortNo, true)
381 } else if port.Type == voltha.Port_ETHERNET_UNI {
npujar467fe752020-01-16 20:17:45 +0530382 if _, err = agent.addUNILogicalPort(ctx, device, port); err != nil {
khenaidoo2c6a0992019-04-29 13:46:56 -0400383 return err
384 }
385 agent.addLogicalPortToMap(port.PortNo, false)
386 } else {
khenaidoo820197c2020-02-13 16:35:33 -0500387 // Update the device routes to ensure all routes on the logical device have been calculated
388 if err = agent.buildRoutes(ctx); err != nil {
389 // Not an error - temporary state
Girish Kumarf56a4682020-03-20 20:07:46 +0000390 logger.Warnw("failed-to-update-routes", log.Fields{"device-id": device.Id, "port": port, "error": err})
khenaidoo2c6a0992019-04-29 13:46:56 -0400391 }
392 }
393 return nil
394}
395
khenaidoo3d3b8c22019-05-22 18:10:39 -0400396// setupLogicalPorts is invoked once the logical device has been created and is ready to get ports
397// added to it. While the logical device was being created we could have received requests to add
398// NNI and UNI ports which were discarded. Now is the time to add them if needed
399func (agent *LogicalDeviceAgent) setupLogicalPorts(ctx context.Context) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000400 logger.Infow("setupLogicalPorts", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo3d3b8c22019-05-22 18:10:39 -0400401 // First add any NNI ports which could have been missing
npujar467fe752020-01-16 20:17:45 +0530402 if err := agent.setupNNILogicalPorts(ctx, agent.rootDeviceID); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000403 logger.Errorw("error-setting-up-NNI-ports", log.Fields{"error": err, "deviceId": agent.rootDeviceID})
khenaidoo3d3b8c22019-05-22 18:10:39 -0400404 return err
405 }
406
407 // Now, set up the UNI ports if needed.
npujar467fe752020-01-16 20:17:45 +0530408 children, err := agent.deviceMgr.getAllChildDevices(ctx, agent.rootDeviceID)
npujar1d86a522019-11-14 17:11:16 +0530409 if err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000410 logger.Errorw("error-getting-child-devices", log.Fields{"error": err, "deviceId": agent.rootDeviceID})
khenaidoo3d3b8c22019-05-22 18:10:39 -0400411 return err
npujar1d86a522019-11-14 17:11:16 +0530412 }
413 responses := make([]coreutils.Response, 0)
414 for _, child := range children.Items {
415 response := coreutils.NewResponse()
416 responses = append(responses, response)
417 go func(child *voltha.Device) {
khenaidoo442e7c72020-03-10 16:13:48 -0400418 if err = agent.setupUNILogicalPorts(context.Background(), child); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000419 logger.Error("setting-up-UNI-ports-failed", log.Fields{"deviceID": child.Id})
npujar1d86a522019-11-14 17:11:16 +0530420 response.Error(status.Errorf(codes.Internal, "UNI-ports-setup-failed: %s", child.Id))
421 }
422 response.Done()
423 }(child)
424 }
425 // Wait for completion
426 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, responses...); res != nil {
427 return status.Errorf(codes.Aborted, "errors-%s", res)
khenaidoo3d3b8c22019-05-22 18:10:39 -0400428 }
429 return nil
430}
431
khenaidoofc1314d2019-03-14 09:34:21 -0400432// setupNNILogicalPorts creates an NNI port on the logical device that represents an NNI interface on a root device
npujar1d86a522019-11-14 17:11:16 +0530433func (agent *LogicalDeviceAgent) setupNNILogicalPorts(ctx context.Context, deviceID string) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000434 logger.Infow("setupNNILogicalPorts-start", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoob9203542018-09-17 22:56:37 -0400435 // Build the logical device based on information retrieved from the device adapter
khenaidoofc1314d2019-03-14 09:34:21 -0400436 var err error
437
438 var device *voltha.Device
npujar467fe752020-01-16 20:17:45 +0530439 if device, err = agent.deviceMgr.GetDevice(ctx, deviceID); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000440 logger.Errorw("error-retrieving-device", log.Fields{"error": err, "deviceId": deviceID})
khenaidoofc1314d2019-03-14 09:34:21 -0400441 return err
442 }
443
444 //Get UNI port number
khenaidoofc1314d2019-03-14 09:34:21 -0400445 for _, port := range device.Ports {
446 if port.Type == voltha.Port_ETHERNET_NNI {
npujar467fe752020-01-16 20:17:45 +0530447 if _, err = agent.addNNILogicalPort(ctx, device, port); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000448 logger.Errorw("error-adding-UNI-port", log.Fields{"error": err})
khenaidoofc1314d2019-03-14 09:34:21 -0400449 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400450 agent.addLogicalPortToMap(port.PortNo, true)
khenaidoofc1314d2019-03-14 09:34:21 -0400451 }
452 }
khenaidoofc1314d2019-03-14 09:34:21 -0400453 return err
454}
455
khenaidoo171b98e2019-10-31 11:48:15 -0400456// updatePortState updates the port state of the device
npujar467fe752020-01-16 20:17:45 +0530457func (agent *LogicalDeviceAgent) updatePortState(ctx context.Context, deviceID string, portNo uint32, operStatus voltha.OperStatus_Types) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000458 logger.Infow("updatePortState-start", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "portNo": portNo, "state": operStatus})
khenaidoo442e7c72020-03-10 16:13:48 -0400459 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
460 return err
461 }
462 defer agent.requestQueue.RequestComplete()
khenaidoo171b98e2019-10-31 11:48:15 -0400463 // Get the latest logical device info
khenaidoo6e55d9e2019-12-12 18:26:26 -0500464 cloned := agent.getLogicalDeviceWithoutLock()
465 for idx, lPort := range cloned.Ports {
npujar1d86a522019-11-14 17:11:16 +0530466 if lPort.DeviceId == deviceID && lPort.DevicePortNo == portNo {
npujar1d86a522019-11-14 17:11:16 +0530467 if operStatus == voltha.OperStatus_ACTIVE {
468 cloned.Ports[idx].OfpPort.Config = cloned.Ports[idx].OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
469 cloned.Ports[idx].OfpPort.State = uint32(ofp.OfpPortState_OFPPS_LIVE)
470 } else {
471 cloned.Ports[idx].OfpPort.Config = cloned.Ports[idx].OfpPort.Config | uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
472 cloned.Ports[idx].OfpPort.State = uint32(ofp.OfpPortState_OFPPS_LINK_DOWN)
473 }
474 // Update the logical device
npujar467fe752020-01-16 20:17:45 +0530475 if err := agent.updateLogicalDeviceWithoutLock(ctx, cloned); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000476 logger.Errorw("error-updating-logical-device", log.Fields{"error": err})
npujar1d86a522019-11-14 17:11:16 +0530477 return err
478 }
479 return nil
480 }
481 }
482 return status.Errorf(codes.NotFound, "port-%d-not-exist", portNo)
khenaidoo171b98e2019-10-31 11:48:15 -0400483}
484
khenaidoo3ab34882019-05-02 21:33:30 -0400485// updatePortsState updates the ports state related to the device
kesavandbc2d1622020-01-21 00:42:01 -0500486func (agent *LogicalDeviceAgent) updatePortsState(ctx context.Context, device *voltha.Device, state voltha.OperStatus_Types) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000487 logger.Infow("updatePortsState-start", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo442e7c72020-03-10 16:13:48 -0400488 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
489 return err
490 }
491 defer agent.requestQueue.RequestComplete()
khenaidoo3ab34882019-05-02 21:33:30 -0400492 // Get the latest logical device info
khenaidoo6e55d9e2019-12-12 18:26:26 -0500493 cloned := agent.getLogicalDeviceWithoutLock()
npujar1d86a522019-11-14 17:11:16 +0530494 for _, lport := range cloned.Ports {
495 if lport.DeviceId == device.Id {
kesavandbc2d1622020-01-21 00:42:01 -0500496 if state == voltha.OperStatus_ACTIVE {
npujar1d86a522019-11-14 17:11:16 +0530497 lport.OfpPort.Config = lport.OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
498 lport.OfpPort.State = uint32(ofp.OfpPortState_OFPPS_LIVE)
kesavandbc2d1622020-01-21 00:42:01 -0500499 } else {
npujar1d86a522019-11-14 17:11:16 +0530500 lport.OfpPort.Config = lport.OfpPort.Config | uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
501 lport.OfpPort.State = uint32(ofp.OfpPortState_OFPPS_LINK_DOWN)
khenaidoo3ab34882019-05-02 21:33:30 -0400502 }
kesavandbc2d1622020-01-21 00:42:01 -0500503
khenaidoo3ab34882019-05-02 21:33:30 -0400504 }
npujar1d86a522019-11-14 17:11:16 +0530505 }
506 // Updating the logical device will trigger the poprt change events to be populated to the controller
npujar467fe752020-01-16 20:17:45 +0530507 if err := agent.updateLogicalDeviceWithoutLock(ctx, cloned); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000508 logger.Warnw("logical-device-update-failed", log.Fields{"ldeviceId": agent.logicalDeviceID, "error": err})
npujar1d86a522019-11-14 17:11:16 +0530509 return err
khenaidoo3ab34882019-05-02 21:33:30 -0400510 }
511 return nil
512}
513
khenaidoofc1314d2019-03-14 09:34:21 -0400514// setupUNILogicalPorts creates a UNI port on the logical device that represents a child UNI interface
515func (agent *LogicalDeviceAgent) setupUNILogicalPorts(ctx context.Context, childDevice *voltha.Device) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000516 logger.Infow("setupUNILogicalPort", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoofc1314d2019-03-14 09:34:21 -0400517 // Build the logical device based on information retrieved from the device adapter
khenaidoob9203542018-09-17 22:56:37 -0400518 var err error
khenaidoo59ef7be2019-06-21 12:40:28 -0400519 var added bool
khenaidoo19d7b632018-10-30 10:49:50 -0400520 //Get UNI port number
khenaidoo19d7b632018-10-30 10:49:50 -0400521 for _, port := range childDevice.Ports {
522 if port.Type == voltha.Port_ETHERNET_UNI {
npujar467fe752020-01-16 20:17:45 +0530523 if added, err = agent.addUNILogicalPort(ctx, childDevice, port); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000524 logger.Errorw("error-adding-UNI-port", log.Fields{"error": err})
khenaidoofc1314d2019-03-14 09:34:21 -0400525 }
khenaidoo59ef7be2019-06-21 12:40:28 -0400526 if added {
527 agent.addLogicalPortToMap(port.PortNo, false)
528 }
khenaidoo19d7b632018-10-30 10:49:50 -0400529 }
530 }
khenaidoofc1314d2019-03-14 09:34:21 -0400531 return err
khenaidoo92e62c52018-10-03 14:02:54 -0400532}
533
Girish Gowdra408cd962020-03-11 14:31:31 -0700534// deleteAllLogicalPorts deletes all logical ports associated with this logical device
535func (agent *LogicalDeviceAgent) deleteAllLogicalPorts(ctx context.Context) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000536 logger.Infow("updatePortsState-start", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo442e7c72020-03-10 16:13:48 -0400537 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
538 return err
539 }
540 defer agent.requestQueue.RequestComplete()
khenaidoo0a822f92019-05-08 15:15:57 -0400541 // Get the latest logical device info
khenaidoo6e55d9e2019-12-12 18:26:26 -0500542 ld := agent.getLogicalDeviceWithoutLock()
543
npujar1d86a522019-11-14 17:11:16 +0530544 cloned := (proto.Clone(ld)).(*voltha.LogicalDevice)
Girish Gowdra408cd962020-03-11 14:31:31 -0700545 var updateLogicalPorts []*voltha.LogicalPort
546 // Update an empty ports slice to remove all the ports
547 cloned.Ports = updateLogicalPorts
548
549 if err := agent.updateLogicalDeviceWithoutLock(ctx, cloned); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000550 logger.Warnw("logical-device-update-failed", log.Fields{"ldeviceId": agent.logicalDeviceID, "error": err})
Girish Gowdra408cd962020-03-11 14:31:31 -0700551 return err
khenaidoo0a822f92019-05-08 15:15:57 -0400552 }
553 return nil
554}
555
Hardik Windlassc704def2020-02-26 18:23:19 +0000556// deleteAllUNILogicalPorts deletes all UNI logical ports associated with this parent device
557func (agent *LogicalDeviceAgent) deleteAllUNILogicalPorts(ctx context.Context, parentDevice *voltha.Device) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000558 logger.Debugw("delete-all-uni-logical-ports", log.Fields{"logical-device-id": agent.logicalDeviceID})
khenaidoo442e7c72020-03-10 16:13:48 -0400559 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
560 return err
561 }
562 defer agent.requestQueue.RequestComplete()
Hardik Windlassc704def2020-02-26 18:23:19 +0000563 // Get the latest logical device info
564 ld := agent.getLogicalDeviceWithoutLock()
565
566 cloned := (proto.Clone(ld)).(*voltha.LogicalDevice)
567 updateLogicalPorts := []*voltha.LogicalPort{}
568 for _, lport := range cloned.Ports {
569 // Save NNI ports only
570 if agent.isNNIPort(lport.DevicePortNo) {
571 updateLogicalPorts = append(updateLogicalPorts, lport)
572 }
573 }
574 if len(updateLogicalPorts) < len(cloned.Ports) {
575 cloned.Ports = updateLogicalPorts
576 // Updating the logical device will trigger the port change events to be populated to the controller
577 if err := agent.updateLogicalDeviceWithoutLock(ctx, cloned); err != nil {
578 return err
579 }
580 } else {
Girish Kumarf56a4682020-03-20 20:07:46 +0000581 logger.Debugw("no-change-required", log.Fields{"logical-device-id": agent.logicalDeviceID})
Hardik Windlassc704def2020-02-26 18:23:19 +0000582 }
583 return nil
584}
585
khenaidoo92e62c52018-10-03 14:02:54 -0400586//updateLogicalDeviceWithoutLock updates the model with the logical device. It clones the logicaldevice before saving it
npujar467fe752020-01-16 20:17:45 +0530587func (agent *LogicalDeviceAgent) updateLogicalDeviceWithoutLock(ctx context.Context, logicalDevice *voltha.LogicalDevice) error {
588 updateCtx := context.WithValue(ctx, model.RequestTimestamp, time.Now().UnixNano())
Thomas Lee Se5a44012019-11-07 20:32:24 +0530589 afterUpdate, err := agent.clusterDataProxy.Update(updateCtx, "/logical_devices/"+agent.logicalDeviceID, logicalDevice, false, "")
590 if err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000591 logger.Errorw("failed-to-update-logical-devices-to-cluster-proxy", log.Fields{"error": err})
Thomas Lee Se5a44012019-11-07 20:32:24 +0530592 return err
593 }
khenaidoo92e62c52018-10-03 14:02:54 -0400594 if afterUpdate == nil {
npujar1d86a522019-11-14 17:11:16 +0530595 return status.Errorf(codes.Internal, "failed-updating-logical-device:%s", agent.logicalDeviceID)
khenaidoo92e62c52018-10-03 14:02:54 -0400596 }
khenaidoo442e7c72020-03-10 16:13:48 -0400597 //agent.logicalDevice = (proto.Clone(logicalDevice)).(*voltha.LogicalDevice)
598 agent.logicalDevice = logicalDevice
599
khenaidoo92e62c52018-10-03 14:02:54 -0400600 return nil
601}
602
khenaidoo820197c2020-02-13 16:35:33 -0500603//generateDeviceRoutesIfNeeded generates the device routes if the logical device has been updated since the last time
khenaidoo4c9e5592019-09-09 16:20:41 -0400604//that device graph was generated.
khenaidoo820197c2020-02-13 16:35:33 -0500605func (agent *LogicalDeviceAgent) generateDeviceRoutesIfNeeded(ctx context.Context) error {
606 agent.lockDeviceRoutes.Lock()
607 defer agent.lockDeviceRoutes.Unlock()
608
khenaidoo442e7c72020-03-10 16:13:48 -0400609 ld, err := agent.GetLogicalDevice(ctx)
610 if err != nil {
611 return err
612 }
khenaidoo820197c2020-02-13 16:35:33 -0500613
614 if agent.deviceRoutes != nil && agent.deviceRoutes.IsUpToDate(ld) {
npujar1d86a522019-11-14 17:11:16 +0530615 return nil
616 }
Girish Kumarf56a4682020-03-20 20:07:46 +0000617 logger.Debug("Generation of device route required")
khenaidoo820197c2020-02-13 16:35:33 -0500618 if err := agent.buildRoutes(ctx); err != nil {
619 return err
620 }
khenaidoo4c9e5592019-09-09 16:20:41 -0400621 return nil
622}
623
khenaidoo19d7b632018-10-30 10:49:50 -0400624//updateFlowTable updates the flow table of that logical device
625func (agent *LogicalDeviceAgent) updateFlowTable(ctx context.Context, flow *ofp.OfpFlowMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000626 logger.Debug("updateFlowTable")
khenaidoo19d7b632018-10-30 10:49:50 -0400627 if flow == nil {
628 return nil
629 }
khenaidoo820197c2020-02-13 16:35:33 -0500630 if err := agent.generateDeviceRoutesIfNeeded(ctx); err != nil {
khenaidoo4c9e5592019-09-09 16:20:41 -0400631 return err
632 }
khenaidoo19d7b632018-10-30 10:49:50 -0400633 switch flow.GetCommand() {
634 case ofp.OfpFlowModCommand_OFPFC_ADD:
npujar467fe752020-01-16 20:17:45 +0530635 return agent.flowAdd(ctx, flow)
khenaidoo19d7b632018-10-30 10:49:50 -0400636 case ofp.OfpFlowModCommand_OFPFC_DELETE:
npujar467fe752020-01-16 20:17:45 +0530637 return agent.flowDelete(ctx, flow)
khenaidoo19d7b632018-10-30 10:49:50 -0400638 case ofp.OfpFlowModCommand_OFPFC_DELETE_STRICT:
npujar467fe752020-01-16 20:17:45 +0530639 return agent.flowDeleteStrict(ctx, flow)
khenaidoo19d7b632018-10-30 10:49:50 -0400640 case ofp.OfpFlowModCommand_OFPFC_MODIFY:
641 return agent.flowModify(flow)
642 case ofp.OfpFlowModCommand_OFPFC_MODIFY_STRICT:
643 return agent.flowModifyStrict(flow)
644 }
645 return status.Errorf(codes.Internal,
npujar1d86a522019-11-14 17:11:16 +0530646 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceID, flow.GetCommand())
khenaidoo19d7b632018-10-30 10:49:50 -0400647}
648
649//updateGroupTable updates the group table of that logical device
650func (agent *LogicalDeviceAgent) updateGroupTable(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000651 logger.Debug("updateGroupTable")
khenaidoo19d7b632018-10-30 10:49:50 -0400652 if groupMod == nil {
653 return nil
654 }
khenaidoo820197c2020-02-13 16:35:33 -0500655 if err := agent.generateDeviceRoutesIfNeeded(ctx); err != nil {
khenaidoo4c9e5592019-09-09 16:20:41 -0400656 return err
657 }
khenaidoo820197c2020-02-13 16:35:33 -0500658
khenaidoo19d7b632018-10-30 10:49:50 -0400659 switch groupMod.GetCommand() {
660 case ofp.OfpGroupModCommand_OFPGC_ADD:
npujar467fe752020-01-16 20:17:45 +0530661 return agent.groupAdd(ctx, groupMod)
khenaidoo19d7b632018-10-30 10:49:50 -0400662 case ofp.OfpGroupModCommand_OFPGC_DELETE:
npujar467fe752020-01-16 20:17:45 +0530663 return agent.groupDelete(ctx, groupMod)
khenaidoo19d7b632018-10-30 10:49:50 -0400664 case ofp.OfpGroupModCommand_OFPGC_MODIFY:
npujar467fe752020-01-16 20:17:45 +0530665 return agent.groupModify(ctx, groupMod)
khenaidoo19d7b632018-10-30 10:49:50 -0400666 }
667 return status.Errorf(codes.Internal,
npujar1d86a522019-11-14 17:11:16 +0530668 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceID, groupMod.GetCommand())
khenaidoo19d7b632018-10-30 10:49:50 -0400669}
670
Manikkaraj kb1a10922019-07-29 12:10:34 -0400671// updateMeterTable updates the meter table of that logical device
672func (agent *LogicalDeviceAgent) updateMeterTable(ctx context.Context, meterMod *ofp.OfpMeterMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000673 logger.Debug("updateMeterTable")
Manikkaraj kb1a10922019-07-29 12:10:34 -0400674 if meterMod == nil {
675 return nil
676 }
677 switch meterMod.GetCommand() {
678 case ofp.OfpMeterModCommand_OFPMC_ADD:
npujar467fe752020-01-16 20:17:45 +0530679 return agent.meterAdd(ctx, meterMod)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400680 case ofp.OfpMeterModCommand_OFPMC_DELETE:
npujar467fe752020-01-16 20:17:45 +0530681 return agent.meterDelete(ctx, meterMod)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400682 case ofp.OfpMeterModCommand_OFPMC_MODIFY:
npujar467fe752020-01-16 20:17:45 +0530683 return agent.meterModify(ctx, meterMod)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400684 }
685 return status.Errorf(codes.Internal,
npujar1d86a522019-11-14 17:11:16 +0530686 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceID, meterMod.GetCommand())
Manikkaraj kb1a10922019-07-29 12:10:34 -0400687
688}
689
npujar467fe752020-01-16 20:17:45 +0530690func (agent *LogicalDeviceAgent) meterAdd(ctx context.Context, meterMod *ofp.OfpMeterMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000691 logger.Debugw("meterAdd", log.Fields{"metermod": *meterMod})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400692 if meterMod == nil {
693 return nil
694 }
khenaidoo442e7c72020-03-10 16:13:48 -0400695 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
696 return err
697 }
698 defer agent.requestQueue.RequestComplete()
Girish Kumarf56a4682020-03-20 20:07:46 +0000699 logger.Debug("Acquired logical device lock")
khenaidoo6e55d9e2019-12-12 18:26:26 -0500700 lDevice := agent.getLogicalDeviceWithoutLock()
Manikkaraj kb1a10922019-07-29 12:10:34 -0400701
702 var meters []*ofp.OfpMeterEntry
703 if lDevice.Meters != nil && lDevice.Meters.Items != nil {
704 meters = lDevice.Meters.Items
705 }
Girish Kumarf56a4682020-03-20 20:07:46 +0000706 logger.Debugw("Available meters", log.Fields{"meters": meters})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400707
708 for _, meter := range meters {
709 if meterMod.MeterId == meter.Config.MeterId {
Girish Kumarf56a4682020-03-20 20:07:46 +0000710 logger.Infow("Meter-already-exists", log.Fields{"meter": *meterMod})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400711 return nil
712 }
713 }
714
715 meterEntry := fu.MeterEntryFromMeterMod(meterMod)
716 meters = append(meters, meterEntry)
717 //Update model
npujar467fe752020-01-16 20:17:45 +0530718 if err := agent.updateLogicalDeviceMetersWithoutLock(ctx, &ofp.Meters{Items: meters}); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000719 logger.Errorw("db-meter-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400720 return err
721 }
Girish Kumarf56a4682020-03-20 20:07:46 +0000722 logger.Debugw("Meter-added-successfully", log.Fields{"Added-meter": meterEntry, "updated-meters": lDevice.Meters})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400723 return nil
724}
725
npujar467fe752020-01-16 20:17:45 +0530726func (agent *LogicalDeviceAgent) meterDelete(ctx context.Context, meterMod *ofp.OfpMeterMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000727 logger.Debug("meterDelete", log.Fields{"meterMod": *meterMod})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400728 if meterMod == nil {
729 return nil
730 }
khenaidoo442e7c72020-03-10 16:13:48 -0400731 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
732 return err
733 }
734 defer agent.requestQueue.RequestComplete()
Manikkaraj kb1a10922019-07-29 12:10:34 -0400735
khenaidoo6e55d9e2019-12-12 18:26:26 -0500736 lDevice := agent.getLogicalDeviceWithoutLock()
Manikkaraj kb1a10922019-07-29 12:10:34 -0400737
738 var meters []*ofp.OfpMeterEntry
739 var flows []*ofp.OfpFlowStats
740 updatedFlows := make([]*ofp.OfpFlowStats, 0)
741 if lDevice.Meters != nil && lDevice.Meters.Items != nil {
742 meters = lDevice.Meters.Items
743 }
Manikkaraj kb1a10922019-07-29 12:10:34 -0400744
745 changedMeter := false
746 changedFow := false
Girish Kumarf56a4682020-03-20 20:07:46 +0000747 logger.Debugw("Available meters", log.Fields{"meters": meters})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400748 for index, meter := range meters {
749 if meterMod.MeterId == meter.Config.MeterId {
750 flows = lDevice.Flows.Items
npujar1d86a522019-11-14 17:11:16 +0530751 changedFow, updatedFlows = agent.getUpdatedFlowsAfterDeletebyMeterID(flows, meterMod.MeterId)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400752 meters = append(meters[:index], meters[index+1:]...)
Girish Kumarf56a4682020-03-20 20:07:46 +0000753 logger.Debugw("Meter has been deleted", log.Fields{"meter": meter, "index": index})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400754 changedMeter = true
755 break
756 }
757 }
758 if changedMeter {
759 //Update model
760 metersToUpdate := &ofp.Meters{}
761 if lDevice.Meters != nil {
762 metersToUpdate = &ofp.Meters{Items: meters}
763 }
npujar467fe752020-01-16 20:17:45 +0530764 if err := agent.updateLogicalDeviceMetersWithoutLock(ctx, metersToUpdate); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000765 logger.Errorw("db-meter-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400766 return err
767 }
Girish Kumarf56a4682020-03-20 20:07:46 +0000768 logger.Debug("Meter-deleted-from-DB-successfully", log.Fields{"updatedMeters": metersToUpdate, "no-of-meter": len(metersToUpdate.Items)})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400769
770 }
771 if changedFow {
772 //Update model
npujar467fe752020-01-16 20:17:45 +0530773 if err := agent.updateLogicalDeviceFlowsWithoutLock(ctx, &ofp.Flows{Items: updatedFlows}); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000774 logger.Errorw("db-flow-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400775 return err
776 }
Girish Kumarf56a4682020-03-20 20:07:46 +0000777 logger.Debug("Flows-associated-with-meter-deleted-from-DB-successfully",
Manikkaraj kb1a10922019-07-29 12:10:34 -0400778 log.Fields{"updated-no-of-flows": len(updatedFlows), "meter": meterMod.MeterId})
779 }
Girish Kumarf56a4682020-03-20 20:07:46 +0000780 logger.Debugw("meterDelete success", log.Fields{"meterID": meterMod.MeterId})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400781 return nil
782}
783
npujar467fe752020-01-16 20:17:45 +0530784func (agent *LogicalDeviceAgent) meterModify(ctx context.Context, meterMod *ofp.OfpMeterMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000785 logger.Debug("meterModify")
Manikkaraj kb1a10922019-07-29 12:10:34 -0400786 if meterMod == nil {
787 return nil
788 }
khenaidoo442e7c72020-03-10 16:13:48 -0400789 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
790 return err
791 }
792 defer agent.requestQueue.RequestComplete()
Manikkaraj kb1a10922019-07-29 12:10:34 -0400793
khenaidoo6e55d9e2019-12-12 18:26:26 -0500794 lDevice := agent.getLogicalDeviceWithoutLock()
Manikkaraj kb1a10922019-07-29 12:10:34 -0400795
796 var meters []*ofp.OfpMeterEntry
797 if lDevice.Meters != nil && lDevice.Meters.Items != nil {
798 meters = lDevice.Meters.Items
799 }
800 changedMeter := false
801 for index, meter := range meters {
802 if meterMod.MeterId == meter.Config.MeterId {
803 newmeterEntry := fu.MeterEntryFromMeterMod(meterMod)
804 newmeterEntry.Stats.FlowCount = meter.Stats.FlowCount
805 meters[index] = newmeterEntry
806 changedMeter = true
Girish Kumarf56a4682020-03-20 20:07:46 +0000807 logger.Debugw("Found meter, replaced with new meter", log.Fields{"old meter": meter, "new meter": newmeterEntry})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400808 break
809 }
810 }
811 if changedMeter {
812 //Update model
813 metersToUpdate := &ofp.Meters{}
814 if lDevice.Meters != nil {
815 metersToUpdate = &ofp.Meters{Items: meters}
816 }
npujar467fe752020-01-16 20:17:45 +0530817 if err := agent.updateLogicalDeviceMetersWithoutLock(ctx, metersToUpdate); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000818 logger.Errorw("db-meter-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400819 return err
820 }
Girish Kumarf56a4682020-03-20 20:07:46 +0000821 logger.Debugw("meter-updated-in-DB-successfully", log.Fields{"updated_meters": meters})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400822 return nil
823 }
824
Girish Kumarf56a4682020-03-20 20:07:46 +0000825 logger.Errorw("Meter not found ", log.Fields{"meter": meterMod})
npujar1d86a522019-11-14 17:11:16 +0530826 return fmt.Errorf("no-logical-device-present:%d", meterMod.MeterId)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400827
828}
829
npujar1d86a522019-11-14 17:11:16 +0530830func (agent *LogicalDeviceAgent) getUpdatedFlowsAfterDeletebyMeterID(flows []*ofp.OfpFlowStats, meterID uint32) (bool, []*ofp.OfpFlowStats) {
Girish Kumarf56a4682020-03-20 20:07:46 +0000831 logger.Infow("Delete flows matching meter", log.Fields{"meter": meterID})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400832 changed := false
833 //updatedFlows := make([]*ofp.OfpFlowStats, 0)
834 for index := len(flows) - 1; index >= 0; index-- {
npujar1d86a522019-11-14 17:11:16 +0530835 if mID := fu.GetMeterIdFromFlow(flows[index]); mID != 0 && mID == meterID {
Girish Kumarf56a4682020-03-20 20:07:46 +0000836 logger.Debugw("Flow to be deleted", log.Fields{"flow": flows[index], "index": index})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400837 flows = append(flows[:index], flows[index+1:]...)
838 changed = true
839 }
840 }
841 return changed, flows
842}
843
844func (agent *LogicalDeviceAgent) updateFlowCountOfMeterStats(modCommand *ofp.OfpFlowMod, meters []*ofp.OfpMeterEntry, flow *ofp.OfpFlowStats) bool {
845
846 flowCommand := modCommand.GetCommand()
npujar1d86a522019-11-14 17:11:16 +0530847 meterID := fu.GetMeterIdFromFlow(flow)
Girish Kumarf56a4682020-03-20 20:07:46 +0000848 logger.Debugw("Meter-id-in-flow-mod", log.Fields{"meterId": meterID})
npujar1d86a522019-11-14 17:11:16 +0530849 if meterID == 0 {
Girish Kumarf56a4682020-03-20 20:07:46 +0000850 logger.Debugw("No meter present in the flow", log.Fields{"flow": *flow})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400851 return false
852 }
853 if meters == nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000854 logger.Debug("No meters present in logical device")
Manikkaraj kb1a10922019-07-29 12:10:34 -0400855 return false
856 }
857 changedMeter := false
858 for _, meter := range meters {
npujar1d86a522019-11-14 17:11:16 +0530859 if meterID == meter.Config.MeterId { // Found meter in Logicaldevice
Manikkaraj kb1a10922019-07-29 12:10:34 -0400860 if flowCommand == ofp.OfpFlowModCommand_OFPFC_ADD {
npujar1d86a522019-11-14 17:11:16 +0530861 meter.Stats.FlowCount++
Manikkaraj kb1a10922019-07-29 12:10:34 -0400862 changedMeter = true
863 } else if flowCommand == ofp.OfpFlowModCommand_OFPFC_DELETE_STRICT {
npujar1d86a522019-11-14 17:11:16 +0530864 meter.Stats.FlowCount--
Manikkaraj kb1a10922019-07-29 12:10:34 -0400865 changedMeter = true
866 }
Girish Kumarf56a4682020-03-20 20:07:46 +0000867 logger.Debugw("Found meter, updated meter flow stats", log.Fields{" meterId": meterID})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400868 break
869 }
870 }
871 return changedMeter
872}
873
khenaidoo19d7b632018-10-30 10:49:50 -0400874//flowAdd adds a flow to the flow table of that logical device
npujar467fe752020-01-16 20:17:45 +0530875func (agent *LogicalDeviceAgent) flowAdd(ctx context.Context, mod *ofp.OfpFlowMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000876 logger.Debugw("flowAdd", log.Fields{"flow": mod})
khenaidoo19d7b632018-10-30 10:49:50 -0400877 if mod == nil {
878 return nil
879 }
khenaidoo442e7c72020-03-10 16:13:48 -0400880 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
881 return err
882 }
883 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -0400884
khenaidoo6e55d9e2019-12-12 18:26:26 -0500885 lDevice := agent.getLogicalDeviceWithoutLock()
khenaidoo19d7b632018-10-30 10:49:50 -0400886
887 var flows []*ofp.OfpFlowStats
Manikkaraj kb1a10922019-07-29 12:10:34 -0400888 var meters []*ofp.OfpMeterEntry
889 var flow *ofp.OfpFlowStats
Scott Bakerfdea1e32020-02-21 15:35:41 -0800890 var err error
Manikkaraj kb1a10922019-07-29 12:10:34 -0400891
khenaidoo19d7b632018-10-30 10:49:50 -0400892 if lDevice.Flows != nil && lDevice.Flows.Items != nil {
893 flows = lDevice.Flows.Items
894 }
895
Manikkaraj kb1a10922019-07-29 12:10:34 -0400896 if lDevice.Meters != nil && lDevice.Meters.Items != nil {
897 meters = lDevice.Meters.Items
898 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400899 updatedFlows := make([]*ofp.OfpFlowStats, 0)
khenaidoo19d7b632018-10-30 10:49:50 -0400900 changed := false
Manikkaraj kb1a10922019-07-29 12:10:34 -0400901 updated := false
khenaidoo19d7b632018-10-30 10:49:50 -0400902 checkOverlap := (mod.Flags & uint32(ofp.OfpFlowModFlags_OFPFF_CHECK_OVERLAP)) != 0
903 if checkOverlap {
904 if overlapped := fu.FindOverlappingFlows(flows, mod); len(overlapped) != 0 {
905 // TODO: should this error be notified other than being logged?
Girish Kumarf56a4682020-03-20 20:07:46 +0000906 logger.Warnw("overlapped-flows", log.Fields{"logicaldeviceId": agent.logicalDeviceID})
khenaidoo19d7b632018-10-30 10:49:50 -0400907 } else {
Matt Jeanneret518b5a42019-10-29 10:30:46 -0400908 // Add flow
Scott Bakerfdea1e32020-02-21 15:35:41 -0800909 flow, err = fu.FlowStatsEntryFromFlowModMessage(mod)
910 if err != nil {
911 return err
912 }
khenaidoo19d7b632018-10-30 10:49:50 -0400913 flows = append(flows, flow)
khenaidoo2c6a0992019-04-29 13:46:56 -0400914 updatedFlows = append(updatedFlows, flow)
khenaidoo19d7b632018-10-30 10:49:50 -0400915 changed = true
916 }
917 } else {
Scott Bakerfdea1e32020-02-21 15:35:41 -0800918 flow, err = fu.FlowStatsEntryFromFlowModMessage(mod)
919 if err != nil {
920 return err
921 }
khenaidoo19d7b632018-10-30 10:49:50 -0400922 idx := fu.FindFlows(flows, flow)
923 if idx >= 0 {
924 oldFlow := flows[idx]
925 if (mod.Flags & uint32(ofp.OfpFlowModFlags_OFPFF_RESET_COUNTS)) != 0 {
926 flow.ByteCount = oldFlow.ByteCount
927 flow.PacketCount = oldFlow.PacketCount
928 }
Matt Jeanneret518b5a42019-10-29 10:30:46 -0400929 if !reflect.DeepEqual(oldFlow, flow) {
930 flows[idx] = flow
931 updatedFlows = append(updatedFlows, flow)
932 changed = true
933 updated = true
934 }
935 } else {
khenaidoo19d7b632018-10-30 10:49:50 -0400936 flows = append(flows, flow)
khenaidoo2c6a0992019-04-29 13:46:56 -0400937 updatedFlows = append(updatedFlows, flow)
938 changed = true
khenaidoo19d7b632018-10-30 10:49:50 -0400939 }
khenaidoo19d7b632018-10-30 10:49:50 -0400940 }
Girish Kumarf56a4682020-03-20 20:07:46 +0000941 logger.Debugw("flowAdd-changed", log.Fields{"changed": changed})
khenaidoo4c9e5592019-09-09 16:20:41 -0400942
khenaidoo19d7b632018-10-30 10:49:50 -0400943 if changed {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400944 var flowMetadata voltha.FlowMetadata
945 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 +0000946 logger.Error("Meter-referred-in-flows-not-present")
Manikkaraj kb1a10922019-07-29 12:10:34 -0400947 return err
948 }
khenaidoo820197c2020-02-13 16:35:33 -0500949 deviceRules, err := agent.flowDecomposer.DecomposeRules(ctx, agent, ofp.Flows{Items: updatedFlows}, *lDevice.FlowGroups)
950 if err != nil {
951 return err
952 }
Girish Kumarf56a4682020-03-20 20:07:46 +0000953 logger.Debugw("rules", log.Fields{"rules": deviceRules.String()})
khenaidoo0458db62019-06-20 08:50:36 -0400954
khenaidoo19d7b632018-10-30 10:49:50 -0400955 // Update model
npujar467fe752020-01-16 20:17:45 +0530956 if err := agent.updateLogicalDeviceFlowsWithoutLock(ctx, &ofp.Flows{Items: flows}); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000957 logger.Errorw("db-flow-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo19d7b632018-10-30 10:49:50 -0400958 return err
959 }
Matt Jeanneret518b5a42019-10-29 10:30:46 -0400960 if !updated {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400961 changedMeterStats := agent.updateFlowCountOfMeterStats(mod, meters, flow)
962 metersToUpdate := &ofp.Meters{}
963 if lDevice.Meters != nil {
964 metersToUpdate = &ofp.Meters{Items: meters}
965 }
966 if changedMeterStats {
967 //Update model
npujar467fe752020-01-16 20:17:45 +0530968 if err := agent.updateLogicalDeviceMetersWithoutLock(ctx, metersToUpdate); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000969 logger.Errorw("db-meter-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400970 return err
971 }
Girish Kumarf56a4682020-03-20 20:07:46 +0000972 logger.Debugw("meter-stats-updated-in-DB-successfully", log.Fields{"updated_meters": meters})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400973
974 }
975 }
khenaidoo442e7c72020-03-10 16:13:48 -0400976 // Send the flows to the devices
977 respChannels := agent.addFlowsAndGroupsToDevices(ctx, deviceRules, &flowMetadata)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400978
khenaidoo442e7c72020-03-10 16:13:48 -0400979 // Create the go routines to wait
980 go func() {
981 // Wait for completion
982 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChannels...); res != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000983 logger.Warnw("failure-to-add-flows", log.Fields{"errors": res, "logical-device-id": agent.logicalDeviceID})
khenaidoo442e7c72020-03-10 16:13:48 -0400984 // TODO : revert added flow
985 }
986 }()
khenaidoo19d7b632018-10-30 10:49:50 -0400987 }
khenaidoo19d7b632018-10-30 10:49:50 -0400988 return nil
989}
990
npujar1d86a522019-11-14 17:11:16 +0530991// GetMeterConfig returns meter config
Manikkaraj kb1a10922019-07-29 12:10:34 -0400992func (agent *LogicalDeviceAgent) GetMeterConfig(flows []*ofp.OfpFlowStats, meters []*ofp.OfpMeterEntry, metadata *voltha.FlowMetadata) error {
993 m := make(map[uint32]bool)
994 for _, flow := range flows {
npujar1d86a522019-11-14 17:11:16 +0530995 if flowMeterID := fu.GetMeterIdFromFlow(flow); flowMeterID != 0 && !m[flowMeterID] {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400996 foundMeter := false
997 // Meter is present in the flow , Get from logical device
998 for _, meter := range meters {
999 if flowMeterID == meter.Config.MeterId {
1000 metadata.Meters = append(metadata.Meters, meter.Config)
Girish Kumarf56a4682020-03-20 20:07:46 +00001001 logger.Debugw("Found meter in logical device",
Manikkaraj kb1a10922019-07-29 12:10:34 -04001002 log.Fields{"meterID": flowMeterID, "meter-band": meter.Config})
1003 m[flowMeterID] = true
1004 foundMeter = true
1005 break
1006 }
1007 }
1008 if !foundMeter {
Girish Kumarf56a4682020-03-20 20:07:46 +00001009 logger.Errorw("Meter-referred-by-flow-is-not-found-in-logicaldevice",
npujar1d86a522019-11-14 17:11:16 +05301010 log.Fields{"meterID": flowMeterID, "Available-meters": meters, "flow": *flow})
Manikkaraj kb1a10922019-07-29 12:10:34 -04001011 return errors.New("Meter-referred-by-flow-is-not-found-in-logicaldevice")
1012 }
1013 }
1014 }
Girish Kumarf56a4682020-03-20 20:07:46 +00001015 logger.Debugw("meter-bands-for-flows", log.Fields{"flows": len(flows), "metadata": metadata})
Manikkaraj kb1a10922019-07-29 12:10:34 -04001016 return nil
1017
1018}
1019
khenaidoo19d7b632018-10-30 10:49:50 -04001020//flowDelete deletes a flow from the flow table of that logical device
npujar467fe752020-01-16 20:17:45 +05301021func (agent *LogicalDeviceAgent) flowDelete(ctx context.Context, mod *ofp.OfpFlowMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +00001022 logger.Debug("flowDelete")
khenaidoo19d7b632018-10-30 10:49:50 -04001023 if mod == nil {
1024 return nil
1025 }
khenaidoo442e7c72020-03-10 16:13:48 -04001026 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1027 return err
1028 }
1029 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -04001030
khenaidoo6e55d9e2019-12-12 18:26:26 -05001031 lDevice := agent.getLogicalDeviceWithoutLock()
khenaidoo19d7b632018-10-30 10:49:50 -04001032
Manikkaraj kb1a10922019-07-29 12:10:34 -04001033 var meters []*ofp.OfpMeterEntry
1034 var flows []*ofp.OfpFlowStats
Esin Karamanfc3b1af2020-01-29 16:52:00 +00001035 var flowGroups []*ofp.OfpGroupEntry
Manikkaraj kb1a10922019-07-29 12:10:34 -04001036
1037 if lDevice.Flows != nil && lDevice.Flows.Items != nil {
1038 flows = lDevice.Flows.Items
1039 }
1040
1041 if lDevice.Meters != nil && lDevice.Meters.Items != nil {
1042 meters = lDevice.Meters.Items
1043 }
Esin Karamanfc3b1af2020-01-29 16:52:00 +00001044
1045 if lDevice.FlowGroups != nil && lDevice.FlowGroups.Items != nil {
1046 flowGroups = lDevice.FlowGroups.Items
1047 }
1048
khenaidoo19d7b632018-10-30 10:49:50 -04001049 //build a list of what to keep vs what to delete
1050 toKeep := make([]*ofp.OfpFlowStats, 0)
khenaidoo0458db62019-06-20 08:50:36 -04001051 toDelete := make([]*ofp.OfpFlowStats, 0)
khenaidoo19d7b632018-10-30 10:49:50 -04001052 for _, f := range flows {
khenaidoo0458db62019-06-20 08:50:36 -04001053 // Check whether the flow and the flowmod matches
Scott Bakerfdea1e32020-02-21 15:35:41 -08001054 fs, err := fu.FlowStatsEntryFromFlowModMessage(mod)
1055 if err != nil {
1056 return err
1057 }
1058 if fu.FlowMatch(f, fs) {
khenaidoo0458db62019-06-20 08:50:36 -04001059 toDelete = append(toDelete, f)
1060 continue
1061 }
1062 // Check wild card match
khenaidoo19d7b632018-10-30 10:49:50 -04001063 if !fu.FlowMatchesMod(f, mod) {
1064 toKeep = append(toKeep, f)
khenaidoo0458db62019-06-20 08:50:36 -04001065 } else {
1066 toDelete = append(toDelete, f)
khenaidoo19d7b632018-10-30 10:49:50 -04001067 }
1068 }
1069
Girish Kumarf56a4682020-03-20 20:07:46 +00001070 logger.Debugw("flowDelete", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "toKeep": len(toKeep), "toDelete": toDelete})
khenaidoo0458db62019-06-20 08:50:36 -04001071
khenaidoo19d7b632018-10-30 10:49:50 -04001072 //Update flows
khenaidoo0458db62019-06-20 08:50:36 -04001073 if len(toDelete) > 0 {
Manikkaraj kb1a10922019-07-29 12:10:34 -04001074 var flowMetadata voltha.FlowMetadata
1075 if err := agent.GetMeterConfig(toDelete, meters, &flowMetadata); err != nil { // This should never happen
Girish Kumarf56a4682020-03-20 20:07:46 +00001076 logger.Error("Meter-referred-in-flows-not-present")
Manikkaraj kb1a10922019-07-29 12:10:34 -04001077 return errors.New("Meter-referred-in-flows-not-present")
1078 }
khenaidoo820197c2020-02-13 16:35:33 -05001079 deviceRules, err := agent.flowDecomposer.DecomposeRules(ctx, agent, ofp.Flows{Items: toDelete}, ofp.FlowGroups{Items: flowGroups})
1080 if err != nil {
1081 return err
1082 }
Girish Kumarf56a4682020-03-20 20:07:46 +00001083 logger.Debugw("rules", log.Fields{"rules": deviceRules.String()})
khenaidoo0458db62019-06-20 08:50:36 -04001084
npujar467fe752020-01-16 20:17:45 +05301085 if err := agent.updateLogicalDeviceFlowsWithoutLock(ctx, &ofp.Flows{Items: toKeep}); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001086 logger.Errorw("cannot-update-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo19d7b632018-10-30 10:49:50 -04001087 return err
1088 }
khenaidoo442e7c72020-03-10 16:13:48 -04001089
1090 // Update the devices
1091 respChnls := agent.deleteFlowsAndGroupsFromDevices(ctx, deviceRules, &flowMetadata)
1092
1093 // Wait for the responses
1094 go func() {
1095 // Wait for completion
1096 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001097 logger.Errorw("failure-updating-device-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "errors": res})
khenaidoo442e7c72020-03-10 16:13:48 -04001098 // TODO: Revert the flow deletion
1099 }
1100 }()
khenaidoo19d7b632018-10-30 10:49:50 -04001101 }
1102
1103 //TODO: send announcement on delete
1104 return nil
1105}
1106
khenaidoo442e7c72020-03-10 16:13:48 -04001107func (agent *LogicalDeviceAgent) addFlowsAndGroupsToDevices(ctx context.Context, deviceRules *fu.DeviceRules, flowMetadata *voltha.FlowMetadata) []coreutils.Response {
Girish Kumarf56a4682020-03-20 20:07:46 +00001108 logger.Debugw("send-add-flows-to-device-manager", log.Fields{"logicalDeviceID": agent.logicalDeviceID, "deviceRules": deviceRules, "flowMetadata": flowMetadata})
khenaidoo19d7b632018-10-30 10:49:50 -04001109
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001110 responses := make([]coreutils.Response, 0)
npujar1d86a522019-11-14 17:11:16 +05301111 for deviceID, value := range deviceRules.GetRules() {
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001112 response := coreutils.NewResponse()
1113 responses = append(responses, response)
1114 go func(deviceId string, value *fu.FlowsAndGroups) {
khenaidoo442e7c72020-03-10 16:13:48 -04001115 ctx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
1116 defer cancel()
npujar467fe752020-01-16 20:17:45 +05301117 if err := agent.deviceMgr.addFlowsAndGroups(ctx, deviceId, value.ListFlows(), value.ListGroups(), flowMetadata); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001118 logger.Errorw("flow-add-failed", log.Fields{"deviceID": deviceId, "error": err})
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001119 response.Error(status.Errorf(codes.Internal, "flow-add-failed: %s", deviceId))
khenaidoo0458db62019-06-20 08:50:36 -04001120 }
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001121 response.Done()
npujar1d86a522019-11-14 17:11:16 +05301122 }(deviceID, value)
khenaidoo19d7b632018-10-30 10:49:50 -04001123 }
khenaidoo442e7c72020-03-10 16:13:48 -04001124 // Return responses (an array of channels) for the caller to wait for a response from the far end.
1125 return responses
khenaidoo0458db62019-06-20 08:50:36 -04001126}
khenaidoo19d7b632018-10-30 10:49:50 -04001127
khenaidoo442e7c72020-03-10 16:13:48 -04001128func (agent *LogicalDeviceAgent) deleteFlowsAndGroupsFromDevices(ctx context.Context, deviceRules *fu.DeviceRules, flowMetadata *voltha.FlowMetadata) []coreutils.Response {
Girish Kumarf56a4682020-03-20 20:07:46 +00001129 logger.Debugw("send-delete-flows-to-device-manager", log.Fields{"logicalDeviceID": agent.logicalDeviceID})
khenaidoo0458db62019-06-20 08:50:36 -04001130
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001131 responses := make([]coreutils.Response, 0)
npujar1d86a522019-11-14 17:11:16 +05301132 for deviceID, value := range deviceRules.GetRules() {
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001133 response := coreutils.NewResponse()
1134 responses = append(responses, response)
1135 go func(deviceId string, value *fu.FlowsAndGroups) {
khenaidoo442e7c72020-03-10 16:13:48 -04001136 ctx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
1137 defer cancel()
npujar467fe752020-01-16 20:17:45 +05301138 if err := agent.deviceMgr.deleteFlowsAndGroups(ctx, deviceId, value.ListFlows(), value.ListGroups(), flowMetadata); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001139 logger.Error("flow-delete-failed", log.Fields{"deviceID": deviceId, "error": err})
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001140 response.Error(status.Errorf(codes.Internal, "flow-delete-failed: %s", deviceId))
khenaidoo0458db62019-06-20 08:50:36 -04001141 }
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001142 response.Done()
npujar1d86a522019-11-14 17:11:16 +05301143 }(deviceID, value)
khenaidoo0458db62019-06-20 08:50:36 -04001144 }
khenaidoo442e7c72020-03-10 16:13:48 -04001145 return responses
khenaidoo0458db62019-06-20 08:50:36 -04001146}
1147
khenaidoo442e7c72020-03-10 16:13:48 -04001148func (agent *LogicalDeviceAgent) updateFlowsAndGroupsOfDevice(ctx context.Context, deviceRules *fu.DeviceRules, flowMetadata *voltha.FlowMetadata) []coreutils.Response {
Girish Kumarf56a4682020-03-20 20:07:46 +00001149 logger.Debugw("send-update-flows-to-device-manager", log.Fields{"logicalDeviceID": agent.logicalDeviceID})
khenaidoo0458db62019-06-20 08:50:36 -04001150
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001151 responses := make([]coreutils.Response, 0)
npujar1d86a522019-11-14 17:11:16 +05301152 for deviceID, value := range deviceRules.GetRules() {
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001153 response := coreutils.NewResponse()
1154 responses = append(responses, response)
1155 go func(deviceId string, value *fu.FlowsAndGroups) {
khenaidoo442e7c72020-03-10 16:13:48 -04001156 ctx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
1157 defer cancel()
npujar467fe752020-01-16 20:17:45 +05301158 if err := agent.deviceMgr.updateFlowsAndGroups(ctx, deviceId, value.ListFlows(), value.ListGroups(), flowMetadata); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001159 logger.Error("flow-update-failed", log.Fields{"deviceID": deviceId, "error": err})
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001160 response.Error(status.Errorf(codes.Internal, "flow-update-failed: %s", deviceId))
khenaidoo0458db62019-06-20 08:50:36 -04001161 }
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001162 response.Done()
npujar1d86a522019-11-14 17:11:16 +05301163 }(deviceID, value)
khenaidoo0458db62019-06-20 08:50:36 -04001164 }
khenaidoo442e7c72020-03-10 16:13:48 -04001165 return responses
khenaidoo19d7b632018-10-30 10:49:50 -04001166}
1167
1168//flowDeleteStrict deletes a flow from the flow table of that logical device
npujar467fe752020-01-16 20:17:45 +05301169func (agent *LogicalDeviceAgent) flowDeleteStrict(ctx context.Context, mod *ofp.OfpFlowMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +00001170 logger.Debug("flowDeleteStrict")
khenaidoo19d7b632018-10-30 10:49:50 -04001171 if mod == nil {
1172 return nil
1173 }
khenaidoo442e7c72020-03-10 16:13:48 -04001174 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1175 return err
1176 }
1177 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -04001178
khenaidoo6e55d9e2019-12-12 18:26:26 -05001179 lDevice := agent.getLogicalDeviceWithoutLock()
1180
Manikkaraj kb1a10922019-07-29 12:10:34 -04001181 var meters []*ofp.OfpMeterEntry
1182 var flows []*ofp.OfpFlowStats
Esin Karamanfc3b1af2020-01-29 16:52:00 +00001183 var flowGroups []*ofp.OfpGroupEntry
Manikkaraj kb1a10922019-07-29 12:10:34 -04001184 if lDevice.Meters != nil && lDevice.Meters.Items != nil {
1185 meters = lDevice.Meters.Items
1186 }
1187 if lDevice.Flows != nil && lDevice.Flows.Items != nil {
1188 flows = lDevice.Flows.Items
1189 }
Esin Karamanfc3b1af2020-01-29 16:52:00 +00001190 if lDevice.FlowGroups != nil && lDevice.FlowGroups.Items != nil {
1191 flowGroups = lDevice.FlowGroups.Items
1192 }
Manikkaraj kb1a10922019-07-29 12:10:34 -04001193
1194 changedFlow := false
1195 changedMeter := false
Scott Bakerfdea1e32020-02-21 15:35:41 -08001196 flow, err := fu.FlowStatsEntryFromFlowModMessage(mod)
1197 if err != nil {
1198 return err
1199 }
Manikkaraj kb1a10922019-07-29 12:10:34 -04001200 flowsToDelete := make([]*ofp.OfpFlowStats, 0)
khenaidoo19d7b632018-10-30 10:49:50 -04001201 idx := fu.FindFlows(flows, flow)
1202 if idx >= 0 {
Gamze Abaka6e4ac162019-10-21 11:10:10 +00001203 changedMeter = agent.updateFlowCountOfMeterStats(mod, meters, flows[idx])
Manikkaraj kb1a10922019-07-29 12:10:34 -04001204 flowsToDelete = append(flowsToDelete, flows[idx])
khenaidoo19d7b632018-10-30 10:49:50 -04001205 flows = append(flows[:idx], flows[idx+1:]...)
Manikkaraj kb1a10922019-07-29 12:10:34 -04001206 changedFlow = true
khenaidoo19d7b632018-10-30 10:49:50 -04001207 } else {
npujar1d86a522019-11-14 17:11:16 +05301208 return fmt.Errorf("Cannot delete flow - %s", flow)
khenaidoo19d7b632018-10-30 10:49:50 -04001209 }
Manikkaraj kb1a10922019-07-29 12:10:34 -04001210 if changedMeter {
1211 //Update model
1212 metersToUpdate := &ofp.Meters{}
1213 if lDevice.Meters != nil {
1214 metersToUpdate = &ofp.Meters{Items: meters}
1215 }
npujar467fe752020-01-16 20:17:45 +05301216 if err := agent.updateLogicalDeviceMetersWithoutLock(ctx, metersToUpdate); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001217 logger.Errorw("db-meter-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
Manikkaraj kb1a10922019-07-29 12:10:34 -04001218 return err
1219 }
khenaidoo19d7b632018-10-30 10:49:50 -04001220
Manikkaraj kb1a10922019-07-29 12:10:34 -04001221 }
1222 if changedFlow {
1223 var flowMetadata voltha.FlowMetadata
1224 if err := agent.GetMeterConfig(flowsToDelete, meters, &flowMetadata); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001225 logger.Error("meter-referred-in-flows-not-present")
Manikkaraj kb1a10922019-07-29 12:10:34 -04001226 return err
1227 }
khenaidoo820197c2020-02-13 16:35:33 -05001228 deviceRules, err := agent.flowDecomposer.DecomposeRules(ctx, agent, ofp.Flows{Items: flowsToDelete}, ofp.FlowGroups{Items: flowGroups})
1229 if err != nil {
1230 return err
1231 }
Girish Kumarf56a4682020-03-20 20:07:46 +00001232 logger.Debugw("rules", log.Fields{"rules": deviceRules.String()})
khenaidoo0458db62019-06-20 08:50:36 -04001233
npujar467fe752020-01-16 20:17:45 +05301234 if err := agent.updateLogicalDeviceFlowsWithoutLock(ctx, &ofp.Flows{Items: flows}); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001235 logger.Errorw("cannot-update-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo19d7b632018-10-30 10:49:50 -04001236 return err
1237 }
khenaidoo442e7c72020-03-10 16:13:48 -04001238
1239 // Update the devices
1240 respChnls := agent.deleteFlowsAndGroupsFromDevices(ctx, deviceRules, &flowMetadata)
1241
1242 // Wait for completion
1243 go func() {
1244 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001245 logger.Warnw("failure-deleting-device-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "errors": res})
khenaidoo442e7c72020-03-10 16:13:48 -04001246 //TODO: Revert flow changes
1247 }
1248 }()
khenaidoo19d7b632018-10-30 10:49:50 -04001249 }
khenaidoo19d7b632018-10-30 10:49:50 -04001250 return nil
1251}
1252
1253//flowModify modifies a flow from the flow table of that logical device
1254func (agent *LogicalDeviceAgent) flowModify(mod *ofp.OfpFlowMod) error {
1255 return errors.New("flowModify not implemented")
1256}
1257
1258//flowModifyStrict deletes a flow from the flow table of that logical device
1259func (agent *LogicalDeviceAgent) flowModifyStrict(mod *ofp.OfpFlowMod) error {
1260 return errors.New("flowModifyStrict not implemented")
1261}
1262
npujar467fe752020-01-16 20:17:45 +05301263func (agent *LogicalDeviceAgent) groupAdd(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +00001264 logger.Debug("groupAdd")
khenaidoo19d7b632018-10-30 10:49:50 -04001265 if groupMod == nil {
1266 return nil
1267 }
khenaidoo442e7c72020-03-10 16:13:48 -04001268 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1269 return err
1270 }
1271 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -04001272
khenaidoo6e55d9e2019-12-12 18:26:26 -05001273 lDevice := agent.getLogicalDeviceWithoutLock()
1274
khenaidoo19d7b632018-10-30 10:49:50 -04001275 groups := lDevice.FlowGroups.Items
khenaidoo19d7b632018-10-30 10:49:50 -04001276 if fu.FindGroup(groups, groupMod.GroupId) == -1 {
khenaidoo68c930b2019-05-13 11:46:51 -04001277 groups = append(groups, fu.GroupEntryFromGroupMod(groupMod))
khenaidoo0458db62019-06-20 08:50:36 -04001278
Esin Karaman2ea59212019-12-06 11:41:58 +00001279 deviceRules := fu.NewDeviceRules()
1280 deviceRules.CreateEntryIfNotExist(agent.rootDeviceID)
1281 fg := fu.NewFlowsAndGroups()
1282 fg.AddGroup(fu.GroupEntryFromGroupMod(groupMod))
1283 deviceRules.AddFlowsAndGroup(agent.rootDeviceID, fg)
1284
Girish Kumarf56a4682020-03-20 20:07:46 +00001285 logger.Debugw("rules", log.Fields{"rules for group-add": deviceRules.String()})
khenaidoo0458db62019-06-20 08:50:36 -04001286
npujar467fe752020-01-16 20:17:45 +05301287 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(ctx, &ofp.FlowGroups{Items: groups}); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001288 logger.Errorw("cannot-update-group", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo19d7b632018-10-30 10:49:50 -04001289 return err
1290 }
khenaidoo442e7c72020-03-10 16:13:48 -04001291
1292 // Update the devices
1293 respChnls := agent.addFlowsAndGroupsToDevices(ctx, deviceRules, &voltha.FlowMetadata{})
1294
1295 // Wait for completion
1296 go func() {
1297 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001298 logger.Warnw("failure-updating-device-flows-groups", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "errors": res})
khenaidoo442e7c72020-03-10 16:13:48 -04001299 //TODO: Revert flow changes
1300 }
1301 }()
1302 return nil
khenaidoo19d7b632018-10-30 10:49:50 -04001303 }
khenaidoo442e7c72020-03-10 16:13:48 -04001304 return fmt.Errorf("Groups %d already present", groupMod.GroupId)
khenaidoo19d7b632018-10-30 10:49:50 -04001305}
1306
npujar467fe752020-01-16 20:17:45 +05301307func (agent *LogicalDeviceAgent) groupDelete(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +00001308 logger.Debug("groupDelete")
khenaidoo19d7b632018-10-30 10:49:50 -04001309 if groupMod == nil {
1310 return nil
1311 }
khenaidoo442e7c72020-03-10 16:13:48 -04001312 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1313 return err
1314 }
1315 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -04001316
khenaidoo6e55d9e2019-12-12 18:26:26 -05001317 lDevice := agent.getLogicalDeviceWithoutLock()
khenaidoo19d7b632018-10-30 10:49:50 -04001318 groups := lDevice.FlowGroups.Items
1319 flows := lDevice.Flows.Items
npujar1d86a522019-11-14 17:11:16 +05301320 var groupsChanged bool
khenaidoo19d7b632018-10-30 10:49:50 -04001321 flowsChanged := false
npujar1d86a522019-11-14 17:11:16 +05301322 groupID := groupMod.GroupId
1323 if groupID == uint32(ofp.OfpGroup_OFPG_ALL) {
khenaidoo19d7b632018-10-30 10:49:50 -04001324 //TODO we must delete all flows that point to this group and
1325 //signal controller as requested by flow's flag
1326 groups = []*ofp.OfpGroupEntry{}
1327 groupsChanged = true
1328 } else {
npujar1d86a522019-11-14 17:11:16 +05301329 idx := fu.FindGroup(groups, groupID)
1330 if idx == -1 {
khenaidoo19d7b632018-10-30 10:49:50 -04001331 return nil // Valid case
khenaidoo19d7b632018-10-30 10:49:50 -04001332 }
npujar1d86a522019-11-14 17:11:16 +05301333 flowsChanged, flows = fu.FlowsDeleteByGroupId(flows, groupID)
1334 groups = append(groups[:idx], groups[idx+1:]...)
1335 groupsChanged = true
khenaidoo19d7b632018-10-30 10:49:50 -04001336 }
khenaidoo0458db62019-06-20 08:50:36 -04001337 if flowsChanged || groupsChanged {
khenaidoo820197c2020-02-13 16:35:33 -05001338 deviceRules, err := agent.flowDecomposer.DecomposeRules(ctx, agent, ofp.Flows{Items: flows}, ofp.FlowGroups{Items: groups})
1339 if err != nil {
1340 return err
1341 }
Girish Kumarf56a4682020-03-20 20:07:46 +00001342 logger.Debugw("rules", log.Fields{"rules": deviceRules.String()})
khenaidoo0458db62019-06-20 08:50:36 -04001343
khenaidoo442e7c72020-03-10 16:13:48 -04001344 if groupsChanged {
1345 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(ctx, &ofp.FlowGroups{Items: groups}); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001346 logger.Errorw("cannot-update-group", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo442e7c72020-03-10 16:13:48 -04001347 return err
1348 }
khenaidoo0458db62019-06-20 08:50:36 -04001349 }
khenaidoo442e7c72020-03-10 16:13:48 -04001350 if flowsChanged {
1351 if err := agent.updateLogicalDeviceFlowsWithoutLock(ctx, &ofp.Flows{Items: flows}); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001352 logger.Errorw("cannot-update-flow", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo442e7c72020-03-10 16:13:48 -04001353 return err
1354 }
1355 }
khenaidoo0458db62019-06-20 08:50:36 -04001356
khenaidoo442e7c72020-03-10 16:13:48 -04001357 // Update the devices
1358 respChnls := agent.updateFlowsAndGroupsOfDevice(ctx, deviceRules, nil)
1359
1360 // Wait for completion
1361 go func() {
1362 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001363 logger.Warnw("failure-updating-device-flows-groups", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "errors": res})
khenaidoo442e7c72020-03-10 16:13:48 -04001364 //TODO: Revert flow changes
1365 }
1366 }()
khenaidoo43c82122018-11-22 18:38:28 -05001367 }
khenaidoo19d7b632018-10-30 10:49:50 -04001368 return nil
1369}
1370
npujar467fe752020-01-16 20:17:45 +05301371func (agent *LogicalDeviceAgent) groupModify(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +00001372 logger.Debug("groupModify")
khenaidoo19d7b632018-10-30 10:49:50 -04001373 if groupMod == nil {
1374 return nil
1375 }
khenaidoo442e7c72020-03-10 16:13:48 -04001376 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1377 return err
1378 }
1379 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -04001380
khenaidoo6e55d9e2019-12-12 18:26:26 -05001381 lDevice := agent.getLogicalDeviceWithoutLock()
khenaidoo19d7b632018-10-30 10:49:50 -04001382 groups := lDevice.FlowGroups.Items
npujar1d86a522019-11-14 17:11:16 +05301383 var groupsChanged bool
1384 groupID := groupMod.GroupId
1385 idx := fu.FindGroup(groups, groupID)
1386 if idx == -1 {
1387 return fmt.Errorf("group-absent:%d", groupID)
khenaidoo19d7b632018-10-30 10:49:50 -04001388 }
npujar1d86a522019-11-14 17:11:16 +05301389 //replace existing group entry with new group definition
1390 groupEntry := fu.GroupEntryFromGroupMod(groupMod)
1391 groups[idx] = groupEntry
1392 groupsChanged = true
khenaidoo19d7b632018-10-30 10:49:50 -04001393 if groupsChanged {
Esin Karaman2ea59212019-12-06 11:41:58 +00001394 deviceRules := fu.NewDeviceRules()
1395 deviceRules.CreateEntryIfNotExist(agent.rootDeviceID)
1396 fg := fu.NewFlowsAndGroups()
1397 fg.AddGroup(fu.GroupEntryFromGroupMod(groupMod))
1398 deviceRules.AddFlowsAndGroup(agent.rootDeviceID, fg)
khenaidoo0458db62019-06-20 08:50:36 -04001399
Girish Kumarf56a4682020-03-20 20:07:46 +00001400 logger.Debugw("rules", log.Fields{"rules for group-modify": deviceRules.String()})
khenaidoo0458db62019-06-20 08:50:36 -04001401
npujar467fe752020-01-16 20:17:45 +05301402 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(ctx, &ofp.FlowGroups{Items: groups}); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001403 logger.Errorw("Cannot-update-logical-group", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo19d7b632018-10-30 10:49:50 -04001404 return err
1405 }
khenaidoo442e7c72020-03-10 16:13:48 -04001406
1407 // Update the devices
1408 respChnls := agent.updateFlowsAndGroupsOfDevice(ctx, deviceRules, &voltha.FlowMetadata{})
1409
1410 // Wait for completion
1411 go func() {
1412 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001413 logger.Warnw("failure-updating-device-flows-groups", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "errors": res})
khenaidoo442e7c72020-03-10 16:13:48 -04001414 //TODO: Revert flow changes
1415 }
1416 }()
khenaidoo19d7b632018-10-30 10:49:50 -04001417 }
1418 return nil
1419}
1420
1421// deleteLogicalPort removes the logical port
npujar467fe752020-01-16 20:17:45 +05301422func (agent *LogicalDeviceAgent) deleteLogicalPort(ctx context.Context, lPort *voltha.LogicalPort) error {
khenaidoo442e7c72020-03-10 16:13:48 -04001423 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1424 return err
1425 }
1426 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -04001427
khenaidoo6e55d9e2019-12-12 18:26:26 -05001428 logicalDevice := agent.getLogicalDeviceWithoutLock()
1429
khenaidoo92e62c52018-10-03 14:02:54 -04001430 index := -1
khenaidoo6e55d9e2019-12-12 18:26:26 -05001431 for i, logicalPort := range logicalDevice.Ports {
khenaidoo19d7b632018-10-30 10:49:50 -04001432 if logicalPort.Id == lPort.Id {
khenaidoo92e62c52018-10-03 14:02:54 -04001433 index = i
1434 break
1435 }
1436 }
1437 if index >= 0 {
khenaidoo6e55d9e2019-12-12 18:26:26 -05001438 copy(logicalDevice.Ports[index:], logicalDevice.Ports[index+1:])
1439 logicalDevice.Ports[len(logicalDevice.Ports)-1] = nil
1440 logicalDevice.Ports = logicalDevice.Ports[:len(logicalDevice.Ports)-1]
Girish Kumarf56a4682020-03-20 20:07:46 +00001441 logger.Debugw("logical-port-deleted", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
npujar467fe752020-01-16 20:17:45 +05301442 if err := agent.updateLogicalDeviceWithoutLock(ctx, logicalDevice); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001443 logger.Errorw("logical-device-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo0a822f92019-05-08 15:15:57 -04001444 return err
1445 }
khenaidoo820197c2020-02-13 16:35:33 -05001446
1447 // Remove the logical port from cache
1448 agent.deleteLogicalPortsFromMap([]uint32{lPort.DevicePortNo})
1449
1450 // Reset the logical device routes
1451 go func() {
1452 if err := agent.buildRoutes(context.Background()); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001453 logger.Warnw("device-routes-not-ready", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "error": err})
khenaidoo820197c2020-02-13 16:35:33 -05001454 }
1455 }()
khenaidoo92e62c52018-10-03 14:02:54 -04001456 }
1457 return nil
khenaidoob9203542018-09-17 22:56:37 -04001458}
1459
khenaidoo0a822f92019-05-08 15:15:57 -04001460// deleteLogicalPorts removes the logical ports associated with that deviceId
npujar467fe752020-01-16 20:17:45 +05301461func (agent *LogicalDeviceAgent) deleteLogicalPorts(ctx context.Context, deviceID string) error {
khenaidoo442e7c72020-03-10 16:13:48 -04001462 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1463 return err
1464 }
1465 defer agent.requestQueue.RequestComplete()
khenaidoo0a822f92019-05-08 15:15:57 -04001466
khenaidoo6e55d9e2019-12-12 18:26:26 -05001467 logicalDevice := agent.getLogicalDeviceWithoutLock()
khenaidoo820197c2020-02-13 16:35:33 -05001468 lPortstoKeep := []*voltha.LogicalPort{}
1469 lPortsNoToDelete := []uint32{}
khenaidoo6e55d9e2019-12-12 18:26:26 -05001470 for _, logicalPort := range logicalDevice.Ports {
npujar1d86a522019-11-14 17:11:16 +05301471 if logicalPort.DeviceId != deviceID {
khenaidoo820197c2020-02-13 16:35:33 -05001472 lPortstoKeep = append(lPortstoKeep, logicalPort)
1473 } else {
1474 lPortsNoToDelete = append(lPortsNoToDelete, logicalPort.DevicePortNo)
khenaidoo0a822f92019-05-08 15:15:57 -04001475 }
1476 }
khenaidoo820197c2020-02-13 16:35:33 -05001477 logicalDevice.Ports = lPortstoKeep
1478
Girish Kumarf56a4682020-03-20 20:07:46 +00001479 logger.Debugw("updated-logical-ports", log.Fields{"ports": lPortstoKeep})
npujar467fe752020-01-16 20:17:45 +05301480 if err := agent.updateLogicalDeviceWithoutLock(ctx, logicalDevice); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001481 logger.Errorw("logical-device-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo0a822f92019-05-08 15:15:57 -04001482 return err
1483 }
khenaidoo820197c2020-02-13 16:35:33 -05001484 // Remove the port from the cached logical ports set
1485 agent.deleteLogicalPortsFromMap(lPortsNoToDelete)
1486
1487 // Reset the logical device routes
1488 go func() {
1489 if err := agent.buildRoutes(context.Background()); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001490 logger.Warnw("routes-not-ready", log.Fields{"logical-device-id": agent.logicalDeviceID, "error": err})
khenaidoo820197c2020-02-13 16:35:33 -05001491 }
1492 }()
khenaidoo0a822f92019-05-08 15:15:57 -04001493
1494 return nil
1495}
1496
khenaidoo19d7b632018-10-30 10:49:50 -04001497// enableLogicalPort enables the logical port
npujar467fe752020-01-16 20:17:45 +05301498func (agent *LogicalDeviceAgent) enableLogicalPort(ctx context.Context, lPortID string) error {
khenaidoo442e7c72020-03-10 16:13:48 -04001499 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1500 return err
1501 }
1502 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -04001503
khenaidoo6e55d9e2019-12-12 18:26:26 -05001504 logicalDevice := agent.getLogicalDeviceWithoutLock()
1505
khenaidoo19d7b632018-10-30 10:49:50 -04001506 index := -1
khenaidoo6e55d9e2019-12-12 18:26:26 -05001507 for i, logicalPort := range logicalDevice.Ports {
npujar1d86a522019-11-14 17:11:16 +05301508 if logicalPort.Id == lPortID {
khenaidoo19d7b632018-10-30 10:49:50 -04001509 index = i
1510 break
1511 }
1512 }
1513 if index >= 0 {
khenaidoo6e55d9e2019-12-12 18:26:26 -05001514 logicalDevice.Ports[index].OfpPort.Config = logicalDevice.Ports[index].OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
npujar467fe752020-01-16 20:17:45 +05301515 return agent.updateLogicalDeviceWithoutLock(ctx, logicalDevice)
khenaidoo19d7b632018-10-30 10:49:50 -04001516 }
npujar1d86a522019-11-14 17:11:16 +05301517 return status.Errorf(codes.NotFound, "Port %s on Logical Device %s", lPortID, agent.logicalDeviceID)
khenaidoo19d7b632018-10-30 10:49:50 -04001518}
1519
1520// disableLogicalPort disabled the logical port
npujar467fe752020-01-16 20:17:45 +05301521func (agent *LogicalDeviceAgent) disableLogicalPort(ctx context.Context, lPortID string) error {
khenaidoo442e7c72020-03-10 16:13:48 -04001522 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1523 return err
1524 }
1525 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -04001526
1527 // Get the most up to date logical device
khenaidoo6e55d9e2019-12-12 18:26:26 -05001528 logicalDevice := agent.getLogicalDeviceWithoutLock()
khenaidoo19d7b632018-10-30 10:49:50 -04001529 index := -1
khenaidoo6e55d9e2019-12-12 18:26:26 -05001530 for i, logicalPort := range logicalDevice.Ports {
npujar1d86a522019-11-14 17:11:16 +05301531 if logicalPort.Id == lPortID {
khenaidoo19d7b632018-10-30 10:49:50 -04001532 index = i
1533 break
1534 }
1535 }
1536 if index >= 0 {
khenaidoo6e55d9e2019-12-12 18:26:26 -05001537 logicalDevice.Ports[index].OfpPort.Config = (logicalDevice.Ports[index].OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)) | uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
npujar467fe752020-01-16 20:17:45 +05301538 return agent.updateLogicalDeviceWithoutLock(ctx, logicalDevice)
khenaidoo19d7b632018-10-30 10:49:50 -04001539 }
npujar1d86a522019-11-14 17:11:16 +05301540 return status.Errorf(codes.NotFound, "Port %s on Logical Device %s", lPortID, agent.logicalDeviceID)
khenaidoo19d7b632018-10-30 10:49:50 -04001541}
1542
khenaidoo820197c2020-02-13 16:35:33 -05001543func (agent *LogicalDeviceAgent) getPreCalculatedRoute(ingress, egress uint32) ([]route.Hop, error) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001544 logger.Debugw("ROUTE", log.Fields{"len": len(agent.deviceRoutes.Routes)})
khenaidoo820197c2020-02-13 16:35:33 -05001545 for routeLink, route := range agent.deviceRoutes.Routes {
Girish Kumarf56a4682020-03-20 20:07:46 +00001546 logger.Debugw("ROUTELINKS", log.Fields{"ingress": ingress, "egress": egress, "routelink": routeLink})
khenaidoo89b0e942018-10-21 21:11:33 -04001547 if ingress == routeLink.Ingress && egress == routeLink.Egress {
khenaidoo820197c2020-02-13 16:35:33 -05001548 return route, nil
khenaidoo89b0e942018-10-21 21:11:33 -04001549 }
1550 }
khenaidoo820197c2020-02-13 16:35:33 -05001551 return nil, status.Errorf(codes.FailedPrecondition, "no route from:%d to:%d", ingress, egress)
khenaidoo89b0e942018-10-21 21:11:33 -04001552}
1553
npujar1d86a522019-11-14 17:11:16 +05301554// GetRoute returns route
khenaidoo820197c2020-02-13 16:35:33 -05001555func (agent *LogicalDeviceAgent) GetRoute(ctx context.Context, ingressPortNo uint32, egressPortNo uint32) ([]route.Hop, error) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001556 logger.Debugw("getting-route", log.Fields{"ingress-port": ingressPortNo, "egress-port": egressPortNo})
khenaidoo820197c2020-02-13 16:35:33 -05001557 routes := make([]route.Hop, 0)
khenaidoo2c6a0992019-04-29 13:46:56 -04001558
khenaidoo19d7b632018-10-30 10:49:50 -04001559 // Note: A port value of 0 is equivalent to a nil port
1560
khenaidoo89b0e942018-10-21 21:11:33 -04001561 // Consider different possibilities
khenaidoo19d7b632018-10-30 10:49:50 -04001562 if egressPortNo != 0 && ((egressPortNo & 0x7fffffff) == uint32(ofp.OfpPortNo_OFPP_CONTROLLER)) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001563 logger.Debugw("controller-flow", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "logicalPortsNo": agent.logicalPortsNo})
khenaidoo2c6a0992019-04-29 13:46:56 -04001564 if agent.isNNIPort(ingressPortNo) {
khenaidoo89b0e942018-10-21 21:11:33 -04001565 //This is a trap on the NNI Port
khenaidoo820197c2020-02-13 16:35:33 -05001566 if len(agent.deviceRoutes.Routes) == 0 {
khenaidoo8f474192019-04-03 17:20:44 -04001567 // 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 -04001568 // route with same IngressHop and EgressHop
khenaidoo820197c2020-02-13 16:35:33 -05001569 hop := route.Hop{DeviceID: agent.rootDeviceID, Ingress: ingressPortNo, Egress: ingressPortNo}
khenaidoo8f474192019-04-03 17:20:44 -04001570 routes = append(routes, hop)
1571 routes = append(routes, hop)
khenaidoo820197c2020-02-13 16:35:33 -05001572 return routes, nil
khenaidoo8f474192019-04-03 17:20:44 -04001573 }
khenaidoo89b0e942018-10-21 21:11:33 -04001574 //Return a 'half' route to make the flow decomposer logic happy
khenaidoo820197c2020-02-13 16:35:33 -05001575 for routeLink, path := range agent.deviceRoutes.Routes {
khenaidoo2c6a0992019-04-29 13:46:56 -04001576 if agent.isNNIPort(routeLink.Egress) {
khenaidoo820197c2020-02-13 16:35:33 -05001577 routes = append(routes, route.Hop{}) // first hop is set to empty
1578 routes = append(routes, path[1])
1579 return routes, nil
khenaidoo89b0e942018-10-21 21:11:33 -04001580 }
1581 }
khenaidoo820197c2020-02-13 16:35:33 -05001582 return nil, status.Errorf(codes.FailedPrecondition, "no upstream route from:%d to:%d", ingressPortNo, egressPortNo)
khenaidoo89b0e942018-10-21 21:11:33 -04001583 }
1584 //treat it as if the output port is the first NNI of the OLT
khenaidoo2c6a0992019-04-29 13:46:56 -04001585 var err error
1586 if egressPortNo, err = agent.getFirstNNIPort(); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001587 logger.Warnw("no-nni-port", log.Fields{"error": err})
khenaidoo820197c2020-02-13 16:35:33 -05001588 return nil, err
khenaidoo2c6a0992019-04-29 13:46:56 -04001589 }
khenaidoo89b0e942018-10-21 21:11:33 -04001590 }
1591 //If ingress port is not specified (nil), it may be a wildcarded
1592 //route if egress port is OFPP_CONTROLLER or a nni logical port,
1593 //in which case we need to create a half-route where only the egress
1594 //hop is filled, the first hop is nil
khenaidoo2c6a0992019-04-29 13:46:56 -04001595 if ingressPortNo == 0 && agent.isNNIPort(egressPortNo) {
khenaidoo89b0e942018-10-21 21:11:33 -04001596 // We can use the 2nd hop of any upstream route, so just find the first upstream:
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 }
khenaidoo820197c2020-02-13 16:35:33 -05001604 return nil, status.Errorf(codes.FailedPrecondition, "no upstream route from:%d to:%d", ingressPortNo, egressPortNo)
khenaidoo89b0e942018-10-21 21:11:33 -04001605 }
1606 //If egress port is not specified (nil), we can also can return a "half" route
khenaidoo19d7b632018-10-30 10:49:50 -04001607 if egressPortNo == 0 {
khenaidoo820197c2020-02-13 16:35:33 -05001608 for routeLink, path := range agent.deviceRoutes.Routes {
khenaidoo19d7b632018-10-30 10:49:50 -04001609 if routeLink.Ingress == ingressPortNo {
khenaidoo820197c2020-02-13 16:35:33 -05001610 routes = append(routes, path[0])
1611 routes = append(routes, route.Hop{})
1612 return routes, nil
khenaidoo89b0e942018-10-21 21:11:33 -04001613 }
1614 }
khenaidoo820197c2020-02-13 16:35:33 -05001615 return nil, status.Errorf(codes.FailedPrecondition, "no downstream route from:%d to:%d", ingressPortNo, egressPortNo)
khenaidoo89b0e942018-10-21 21:11:33 -04001616 }
khenaidoo89b0e942018-10-21 21:11:33 -04001617 // Return the pre-calculated route
khenaidoo19d7b632018-10-30 10:49:50 -04001618 return agent.getPreCalculatedRoute(ingressPortNo, egressPortNo)
khenaidoo89b0e942018-10-21 21:11:33 -04001619}
1620
khenaidoo3d3b8c22019-05-22 18:10:39 -04001621//GetWildcardInputPorts filters out the logical port number from the set of logical ports on the device and
1622//returns their port numbers. This function is invoked only during flow decomposition where the lock on the logical
1623//device is already held. Therefore it is safe to retrieve the logical device without lock.
khenaidoo89b0e942018-10-21 21:11:33 -04001624func (agent *LogicalDeviceAgent) GetWildcardInputPorts(excludePort ...uint32) []uint32 {
1625 lPorts := make([]uint32, 0)
1626 var exclPort uint32
1627 if len(excludePort) == 1 {
1628 exclPort = excludePort[0]
1629 }
khenaidoo6e55d9e2019-12-12 18:26:26 -05001630 lDevice := agent.getLogicalDeviceWithoutLock()
1631 for _, port := range lDevice.Ports {
1632 if port.OfpPort.PortNo != exclPort {
1633 lPorts = append(lPorts, port.OfpPort.PortNo)
khenaidoo89b0e942018-10-21 21:11:33 -04001634 }
1635 }
1636 return lPorts
1637}
khenaidoo19d7b632018-10-30 10:49:50 -04001638
khenaidoo820197c2020-02-13 16:35:33 -05001639// GetDeviceRoutes returns device graph
1640func (agent *LogicalDeviceAgent) GetDeviceRoutes() *route.DeviceRoutes {
1641 return agent.deviceRoutes
khenaidoo19d7b632018-10-30 10:49:50 -04001642}
1643
khenaidoo820197c2020-02-13 16:35:33 -05001644//rebuildRoutes rebuilds the device routes
1645func (agent *LogicalDeviceAgent) buildRoutes(ctx context.Context) error {
Girish Kumarf56a4682020-03-20 20:07:46 +00001646 logger.Debugf("building-routes", log.Fields{"logical-device-id": agent.logicalDeviceID})
khenaidoo442e7c72020-03-10 16:13:48 -04001647 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1648 return err
1649 }
1650 defer agent.requestQueue.RequestComplete()
1651
khenaidoo820197c2020-02-13 16:35:33 -05001652 if agent.deviceRoutes == nil {
1653 agent.deviceRoutes = route.NewDeviceRoutes(agent.logicalDeviceID, agent.deviceMgr.GetDevice)
khenaidoo2c6a0992019-04-29 13:46:56 -04001654 }
1655 // Get all the logical ports on that logical device
khenaidoo6e55d9e2019-12-12 18:26:26 -05001656 lDevice := agent.getLogicalDeviceWithoutLock()
1657
khenaidoo820197c2020-02-13 16:35:33 -05001658 if err := agent.deviceRoutes.ComputeRoutes(ctx, lDevice.Ports); err != nil {
1659 return err
1660 }
1661 if err := agent.deviceRoutes.Print(); err != nil {
1662 return err
1663 }
1664
khenaidoo2c6a0992019-04-29 13:46:56 -04001665 return nil
khenaidoo19d7b632018-10-30 10:49:50 -04001666}
1667
khenaidoo820197c2020-02-13 16:35:33 -05001668//updateRoutes updates the device routes
1669func (agent *LogicalDeviceAgent) updateRoutes(ctx context.Context, lp *voltha.LogicalPort) error {
Girish Kumarf56a4682020-03-20 20:07:46 +00001670 logger.Debugw("updateRoutes", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo442e7c72020-03-10 16:13:48 -04001671 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1672 return err
1673 }
1674 defer agent.requestQueue.RequestComplete()
1675
khenaidoo820197c2020-02-13 16:35:33 -05001676 if agent.deviceRoutes == nil {
1677 agent.deviceRoutes = route.NewDeviceRoutes(agent.logicalDeviceID, agent.deviceMgr.GetDevice)
khenaidoo910204f2019-04-08 17:56:40 -04001678 }
khenaidoo820197c2020-02-13 16:35:33 -05001679 if err := agent.deviceRoutes.AddPort(ctx, lp, agent.logicalDevice.Ports); err != nil {
1680 return err
khenaidoo0a822f92019-05-08 15:15:57 -04001681 }
khenaidoo820197c2020-02-13 16:35:33 -05001682 if err := agent.deviceRoutes.Print(); err != nil {
1683 return err
1684 }
1685 return nil
khenaidoo0a822f92019-05-08 15:15:57 -04001686}
1687
khenaidoofc1314d2019-03-14 09:34:21 -04001688// 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 -04001689func diff(oldList, newList []*voltha.LogicalPort) (newPorts, changedPorts, deletedPorts []*voltha.LogicalPort) {
khenaidoofc1314d2019-03-14 09:34:21 -04001690 newPorts = make([]*voltha.LogicalPort, 0)
1691 changedPorts = make([]*voltha.LogicalPort, 0)
1692 deletedPorts = make([]*voltha.LogicalPort, 0)
1693 for _, o := range oldList {
1694 found := false
khenaidoofc1314d2019-03-14 09:34:21 -04001695 for _, n := range newList {
1696 if o.Id == n.Id {
khenaidoofc1314d2019-03-14 09:34:21 -04001697 found = true
1698 break
1699 }
1700 }
1701 if !found {
1702 deletedPorts = append(deletedPorts, o)
1703 }
khenaidoofc1314d2019-03-14 09:34:21 -04001704 }
1705 for _, n := range newList {
1706 found := false
khenaidoo2bc48282019-07-16 18:13:46 -04001707 changed := false
khenaidoofc1314d2019-03-14 09:34:21 -04001708 for _, o := range oldList {
1709 if o.Id == n.Id {
khenaidoo2bc48282019-07-16 18:13:46 -04001710 changed = !reflect.DeepEqual(o, n)
khenaidoofc1314d2019-03-14 09:34:21 -04001711 found = true
1712 break
1713 }
1714 }
1715 if !found {
1716 newPorts = append(newPorts, n)
1717 }
khenaidoo2bc48282019-07-16 18:13:46 -04001718 if changed {
1719 changedPorts = append(changedPorts, n)
1720 }
khenaidoofc1314d2019-03-14 09:34:21 -04001721 }
1722 return
1723}
1724
1725// portUpdated is invoked when a port is updated on the logical device. Until
1726// the POST_ADD notification is fixed, we will use the logical device to
1727// update that data.
npujar467fe752020-01-16 20:17:45 +05301728func (agent *LogicalDeviceAgent) portUpdated(ctx context.Context, args ...interface{}) interface{} {
Girish Kumarf56a4682020-03-20 20:07:46 +00001729 logger.Debugw("portUpdated-callback", log.Fields{"argsLen": len(args)})
khenaidoofc1314d2019-03-14 09:34:21 -04001730
1731 var oldLD *voltha.LogicalDevice
1732 var newlD *voltha.LogicalDevice
1733
1734 var ok bool
1735 if oldLD, ok = args[0].(*voltha.LogicalDevice); !ok {
Girish Kumarf56a4682020-03-20 20:07:46 +00001736 logger.Errorw("invalid-args", log.Fields{"args0": args[0]})
khenaidoofc1314d2019-03-14 09:34:21 -04001737 return nil
1738 }
1739 if newlD, ok = args[1].(*voltha.LogicalDevice); !ok {
Girish Kumarf56a4682020-03-20 20:07:46 +00001740 logger.Errorw("invalid-args", log.Fields{"args1": args[1]})
khenaidoofc1314d2019-03-14 09:34:21 -04001741 return nil
1742 }
1743
1744 if reflect.DeepEqual(oldLD.Ports, newlD.Ports) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001745 logger.Debug("ports-have-not-changed")
khenaidoofc1314d2019-03-14 09:34:21 -04001746 return nil
1747 }
1748
1749 // Get the difference between the two list
1750 newPorts, changedPorts, deletedPorts := diff(oldLD.Ports, newlD.Ports)
1751
1752 // Send the port change events to the OF controller
khenaidoo2c6a0992019-04-29 13:46:56 -04001753 for _, newP := range newPorts {
npujar1d86a522019-11-14 17:11:16 +05301754 go agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceID,
khenaidoo2c6a0992019-04-29 13:46:56 -04001755 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_ADD, Desc: newP.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001756 }
1757 for _, change := range changedPorts {
npujar1d86a522019-11-14 17:11:16 +05301758 go agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceID,
khenaidoo910204f2019-04-08 17:56:40 -04001759 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_MODIFY, Desc: change.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001760 }
1761 for _, del := range deletedPorts {
npujar1d86a522019-11-14 17:11:16 +05301762 go agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceID,
khenaidoo910204f2019-04-08 17:56:40 -04001763 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_DELETE, Desc: del.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001764 }
1765
1766 return nil
1767}
1768
khenaidoo8f474192019-04-03 17:20:44 -04001769// addNNILogicalPort adds an NNI port to the logical device. It returns a bool representing whether a port has been
1770// added and an eror in case a valid error is encountered. If the port was successfully added it will return
1771// (true, nil). If the device is not in the correct state it will return (false, nil) as this is a valid
1772// scenario. This also applies to the case where the port was already added.
npujar467fe752020-01-16 20:17:45 +05301773func (agent *LogicalDeviceAgent) addNNILogicalPort(ctx context.Context, device *voltha.Device, port *voltha.Port) (bool, error) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001774 logger.Debugw("addNNILogicalPort", log.Fields{"NNI": port})
khenaidoo8f474192019-04-03 17:20:44 -04001775 if device.AdminState != voltha.AdminState_ENABLED || device.OperStatus != voltha.OperStatus_ACTIVE {
Girish Kumarf56a4682020-03-20 20:07:46 +00001776 logger.Infow("device-not-ready", log.Fields{"deviceId": device.Id, "admin": device.AdminState, "oper": device.OperStatus})
khenaidoo8f474192019-04-03 17:20:44 -04001777 return false, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001778 }
khenaidoo442e7c72020-03-10 16:13:48 -04001779 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1780 return false, err
1781 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001782 if agent.portExist(device, port) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001783 logger.Debugw("port-already-exist", log.Fields{"port": port})
khenaidoo442e7c72020-03-10 16:13:48 -04001784 agent.requestQueue.RequestComplete()
khenaidoo8f474192019-04-03 17:20:44 -04001785 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001786 }
khenaidoo442e7c72020-03-10 16:13:48 -04001787 agent.requestQueue.RequestComplete()
khenaidoo1ce37ad2019-03-24 22:07:24 -04001788
khenaidoofc1314d2019-03-14 09:34:21 -04001789 var portCap *ic.PortCapability
1790 var err error
1791 // First get the port capability
npujar467fe752020-01-16 20:17:45 +05301792 if portCap, err = agent.deviceMgr.getPortCapability(ctx, device.Id, port.PortNo); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001793 logger.Errorw("error-retrieving-port-capabilities", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001794 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001795 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001796
khenaidoo442e7c72020-03-10 16:13:48 -04001797 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1798 return false, err
1799 }
1800
1801 defer agent.requestQueue.RequestComplete()
khenaidoo1ce37ad2019-03-24 22:07:24 -04001802 // Double check again if this port has been already added since the getPortCapability could have taken a long time
1803 if agent.portExist(device, port) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001804 logger.Debugw("port-already-exist", log.Fields{"port": port})
khenaidoo8f474192019-04-03 17:20:44 -04001805 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001806 }
1807
khenaidoofc1314d2019-03-14 09:34:21 -04001808 portCap.Port.RootPort = true
1809 lp := (proto.Clone(portCap.Port)).(*voltha.LogicalPort)
1810 lp.DeviceId = device.Id
1811 lp.Id = fmt.Sprintf("nni-%d", port.PortNo)
1812 lp.OfpPort.PortNo = port.PortNo
1813 lp.OfpPort.Name = lp.Id
1814 lp.DevicePortNo = port.PortNo
1815
khenaidoo6e55d9e2019-12-12 18:26:26 -05001816 ld := agent.getLogicalDeviceWithoutLock()
1817
khenaidoofc1314d2019-03-14 09:34:21 -04001818 cloned := (proto.Clone(ld)).(*voltha.LogicalDevice)
1819 if cloned.Ports == nil {
1820 cloned.Ports = make([]*voltha.LogicalPort, 0)
1821 }
1822 cloned.Ports = append(cloned.Ports, lp)
1823
npujar467fe752020-01-16 20:17:45 +05301824 if err = agent.updateLogicalDeviceWithoutLock(ctx, cloned); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001825 logger.Errorw("error-updating-logical-device", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001826 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001827 }
khenaidoo910204f2019-04-08 17:56:40 -04001828
khenaidoo820197c2020-02-13 16:35:33 -05001829 // Update the device routes with this new logical port
khenaidoo910204f2019-04-08 17:56:40 -04001830 clonedLP := (proto.Clone(lp)).(*voltha.LogicalPort)
khenaidoo820197c2020-02-13 16:35:33 -05001831 go func() {
1832 if err := agent.updateRoutes(context.Background(), clonedLP); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001833 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 -05001834 }
1835 }()
khenaidoo910204f2019-04-08 17:56:40 -04001836
khenaidoo8f474192019-04-03 17:20:44 -04001837 return true, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001838}
1839
khenaidoo910204f2019-04-08 17:56:40 -04001840func (agent *LogicalDeviceAgent) portExist(device *voltha.Device, port *voltha.Port) bool {
khenaidoo6e55d9e2019-12-12 18:26:26 -05001841 ldevice := agent.getLogicalDeviceWithoutLock()
1842 for _, lPort := range ldevice.Ports {
1843 if lPort.DeviceId == device.Id && lPort.DevicePortNo == port.PortNo && lPort.Id == port.Label {
1844 return true
khenaidoofc1314d2019-03-14 09:34:21 -04001845 }
1846 }
1847 return false
1848}
1849
khenaidoo8f474192019-04-03 17:20:44 -04001850// addUNILogicalPort adds an UNI port to the logical device. It returns a bool representing whether a port has been
1851// added and an eror in case a valid error is encountered. If the port was successfully added it will return
1852// (true, nil). If the device is not in the correct state it will return (false, nil) as this is a valid
1853// scenario. This also applies to the case where the port was already added.
npujar467fe752020-01-16 20:17:45 +05301854func (agent *LogicalDeviceAgent) addUNILogicalPort(ctx context.Context, childDevice *voltha.Device, port *voltha.Port) (bool, error) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001855 logger.Debugw("addUNILogicalPort", log.Fields{"port": port})
khenaidoo8f474192019-04-03 17:20:44 -04001856 if childDevice.AdminState != voltha.AdminState_ENABLED || childDevice.OperStatus != voltha.OperStatus_ACTIVE {
Girish Kumarf56a4682020-03-20 20:07:46 +00001857 logger.Infow("device-not-ready", log.Fields{"deviceId": childDevice.Id, "admin": childDevice.AdminState, "oper": childDevice.OperStatus})
khenaidoo8f474192019-04-03 17:20:44 -04001858 return false, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001859 }
khenaidoo442e7c72020-03-10 16:13:48 -04001860 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1861 return false, err
1862 }
1863
khenaidoo1ce37ad2019-03-24 22:07:24 -04001864 if agent.portExist(childDevice, port) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001865 logger.Debugw("port-already-exist", log.Fields{"port": port})
khenaidoo442e7c72020-03-10 16:13:48 -04001866 agent.requestQueue.RequestComplete()
khenaidoo8f474192019-04-03 17:20:44 -04001867 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001868 }
khenaidoo442e7c72020-03-10 16:13:48 -04001869 agent.requestQueue.RequestComplete()
khenaidoofc1314d2019-03-14 09:34:21 -04001870 var portCap *ic.PortCapability
1871 var err error
1872 // First get the port capability
npujar467fe752020-01-16 20:17:45 +05301873 if portCap, err = agent.deviceMgr.getPortCapability(ctx, childDevice.Id, port.PortNo); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001874 logger.Errorw("error-retrieving-port-capabilities", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001875 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001876 }
khenaidoo442e7c72020-03-10 16:13:48 -04001877 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1878 return false, err
1879 }
1880 defer agent.requestQueue.RequestComplete()
khenaidoo1ce37ad2019-03-24 22:07:24 -04001881 // Double check again if this port has been already added since the getPortCapability could have taken a long time
1882 if agent.portExist(childDevice, port) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001883 logger.Debugw("port-already-exist", log.Fields{"port": port})
khenaidoo8f474192019-04-03 17:20:44 -04001884 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001885 }
khenaidoofc1314d2019-03-14 09:34:21 -04001886 // Get stored logical device
khenaidoo6e55d9e2019-12-12 18:26:26 -05001887 ldevice := agent.getLogicalDeviceWithoutLock()
1888
Girish Kumarf56a4682020-03-20 20:07:46 +00001889 logger.Debugw("adding-uni", log.Fields{"deviceId": childDevice.Id})
npujar1d86a522019-11-14 17:11:16 +05301890 portCap.Port.RootPort = false
1891 portCap.Port.Id = port.Label
1892 portCap.Port.OfpPort.PortNo = port.PortNo
1893 portCap.Port.Device