blob: 4e029c87ba092e49fc6ae0cc9264c61ef645f54a [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"
khenaidoob9203542018-09-17 22:56:37 -040024 "github.com/gogo/protobuf/proto"
sbarbari17d7e222019-11-05 10:02:29 -050025 "github.com/opencord/voltha-go/db/model"
npujar1d86a522019-11-14 17:11:16 +053026 fd "github.com/opencord/voltha-go/rw_core/flowdecomposition"
khenaidoo442e7c72020-03-10 16:13:48 -040027 "github.com/opencord/voltha-go/rw_core/route"
Scott Bakerb671a862019-10-24 10:53:40 -070028 coreutils "github.com/opencord/voltha-go/rw_core/utils"
serkant.uluderya2ae470f2020-01-21 11:13:09 -080029 fu "github.com/opencord/voltha-lib-go/v3/pkg/flows"
30 "github.com/opencord/voltha-lib-go/v3/pkg/log"
31 ic "github.com/opencord/voltha-protos/v3/go/inter_container"
32 ofp "github.com/opencord/voltha-protos/v3/go/openflow_13"
33 "github.com/opencord/voltha-protos/v3/go/voltha"
khenaidoob9203542018-09-17 22:56:37 -040034 "google.golang.org/grpc/codes"
35 "google.golang.org/grpc/status"
khenaidoo442e7c72020-03-10 16:13:48 -040036 "reflect"
37 "sync"
38 "time"
39)
40
41const (
42 maxOrderedLogicalDeviceRequestQueueSize = 1000
khenaidoob9203542018-09-17 22:56:37 -040043)
44
npujar1d86a522019-11-14 17:11:16 +053045// LogicalDeviceAgent represent attributes of logical device agent
khenaidoob9203542018-09-17 22:56:37 -040046type LogicalDeviceAgent struct {
npujar1d86a522019-11-14 17:11:16 +053047 logicalDeviceID string
48 rootDeviceID string
khenaidoo3306c992019-05-24 16:57:35 -040049 deviceMgr *DeviceManager
50 ldeviceMgr *LogicalDeviceManager
51 clusterDataProxy *model.Proxy
52 exitChannel chan int
khenaidoo820197c2020-02-13 16:35:33 -050053 deviceRoutes *route.DeviceRoutes
khenaidoo3306c992019-05-24 16:57:35 -040054 flowProxy *model.Proxy
55 groupProxy *model.Proxy
Manikkaraj kb1a10922019-07-29 12:10:34 -040056 meterProxy *model.Proxy
khenaidoo3306c992019-05-24 16:57:35 -040057 ldProxy *model.Proxy
58 portProxies map[string]*model.Proxy
khenaidoo820197c2020-02-13 16:35:33 -050059 lockDeviceRoutes sync.RWMutex
khenaidoo3306c992019-05-24 16:57:35 -040060 logicalPortsNo map[uint32]bool //value is true for NNI port
61 lockLogicalPortsNo sync.RWMutex
62 flowDecomposer *fd.FlowDecomposer
khenaidoo442e7c72020-03-10 16:13:48 -040063 defaultTimeout time.Duration
khenaidoo6e55d9e2019-12-12 18:26:26 -050064 logicalDevice *voltha.LogicalDevice
khenaidoo442e7c72020-03-10 16:13:48 -040065 requestQueue *coreutils.RequestQueue
66 startOnce sync.Once
67 stopOnce sync.Once
khenaidoob9203542018-09-17 22:56:37 -040068}
69
npujar1d86a522019-11-14 17:11:16 +053070func newLogicalDeviceAgent(id string, deviceID string, ldeviceMgr *LogicalDeviceManager,
Stephane Barbarie1ab43272018-12-08 21:42:13 -050071 deviceMgr *DeviceManager,
khenaidoo442e7c72020-03-10 16:13:48 -040072 cdProxy *model.Proxy, timeout time.Duration) *LogicalDeviceAgent {
khenaidoob9203542018-09-17 22:56:37 -040073 var agent LogicalDeviceAgent
74 agent.exitChannel = make(chan int, 1)
npujar1d86a522019-11-14 17:11:16 +053075 agent.logicalDeviceID = id
76 agent.rootDeviceID = deviceID
khenaidoob9203542018-09-17 22:56:37 -040077 agent.deviceMgr = deviceMgr
khenaidoo9a468962018-09-19 15:33:13 -040078 agent.clusterDataProxy = cdProxy
khenaidoob9203542018-09-17 22:56:37 -040079 agent.ldeviceMgr = ldeviceMgr
khenaidoo19d7b632018-10-30 10:49:50 -040080 agent.flowDecomposer = fd.NewFlowDecomposer(agent.deviceMgr)
khenaidoofc1314d2019-03-14 09:34:21 -040081 agent.portProxies = make(map[string]*model.Proxy)
khenaidoo2c6a0992019-04-29 13:46:56 -040082 agent.logicalPortsNo = make(map[uint32]bool)
khenaidoo2c6a0992019-04-29 13:46:56 -040083 agent.defaultTimeout = timeout
khenaidoo442e7c72020-03-10 16:13:48 -040084 agent.requestQueue = coreutils.NewRequestQueue(agent.logicalDeviceID, maxOrderedLogicalDeviceRequestQueueSize)
khenaidoob9203542018-09-17 22:56:37 -040085 return &agent
86}
87
khenaidoo4d4802d2018-10-04 21:59:49 -040088// start creates the logical device and add it to the data model
khenaidoo442e7c72020-03-10 16:13:48 -040089func (agent *LogicalDeviceAgent) start(ctx context.Context, loadFromDB bool) error {
90 needToStart := false
91 if agent.startOnce.Do(func() { needToStart = true }); !needToStart {
92 return nil
93 }
94
95 log.Infow("starting-logical_device-agent", log.Fields{"logical-device-id": agent.logicalDeviceID, "load-from-db": loadFromDB})
96
97 var startSucceeded bool
98 defer func() {
99 if !startSucceeded {
100 if err := agent.stop(ctx); err != nil {
101 log.Errorw("failed-to-cleanup-after-unsuccessful-start", log.Fields{"logical-device-id": agent.logicalDeviceID, "error": err})
102 }
103 }
104 }()
105
106 // Launch the request queue - it will launch a go routine
107 agent.requestQueue.Start()
108
khenaidoo297cd252019-02-07 22:10:23 -0500109 var ld *voltha.LogicalDevice
khenaidoo442e7c72020-03-10 16:13:48 -0400110 if !loadFromDB {
khenaidoo7e3d8f12019-08-02 16:06:30 -0400111 //Build the logical device based on information retrieved from the device adapter
112 var switchCap *ic.SwitchCapability
khenaidoo297cd252019-02-07 22:10:23 -0500113 var err error
npujar1d86a522019-11-14 17:11:16 +0530114 if switchCap, err = agent.deviceMgr.getSwitchCapability(ctx, agent.rootDeviceID); err != nil {
khenaidoo7e3d8f12019-08-02 16:06:30 -0400115 return err
116 }
npujar1d86a522019-11-14 17:11:16 +0530117 ld = &voltha.LogicalDevice{Id: agent.logicalDeviceID, RootDeviceId: agent.rootDeviceID}
khenaidoo297cd252019-02-07 22:10:23 -0500118
119 // Create the datapath ID (uint64) using the logical device ID (based on the MAC Address)
120 var datapathID uint64
npujar1d86a522019-11-14 17:11:16 +0530121 if datapathID, err = CreateDataPathID(agent.logicalDeviceID); err != nil {
khenaidoo297cd252019-02-07 22:10:23 -0500122 return err
123 }
124 ld.DatapathId = datapathID
khenaidoo7e3d8f12019-08-02 16:06:30 -0400125 ld.Desc = (proto.Clone(switchCap.Desc)).(*ofp.OfpDesc)
126 log.Debugw("Switch-capability", log.Fields{"Desc": ld.Desc, "fromAd": switchCap.Desc})
127 ld.SwitchFeatures = (proto.Clone(switchCap.SwitchFeatures)).(*ofp.OfpSwitchFeatures)
khenaidoo297cd252019-02-07 22:10:23 -0500128 ld.Flows = &ofp.Flows{Items: nil}
129 ld.FlowGroups = &ofp.FlowGroups{Items: nil}
khenaidoo49085352020-01-13 19:15:43 -0500130 ld.Ports = []*voltha.LogicalPort{}
khenaidoo297cd252019-02-07 22:10:23 -0500131
khenaidoo297cd252019-02-07 22:10:23 -0500132 // Save the logical device
Thomas Lee Se5a44012019-11-07 20:32:24 +0530133 added, err := agent.clusterDataProxy.AddWithID(ctx, "/logical_devices", ld.Id, ld, "")
134 if err != nil {
Thomas Lee Se5a44012019-11-07 20:32:24 +0530135 return err
136 }
137 if added == nil {
khenaidoo442e7c72020-03-10 16:13:48 -0400138 log.Errorw("failed-to-add-logical-device", log.Fields{"logical-device-id": agent.logicalDeviceID})
khenaidoo297cd252019-02-07 22:10:23 -0500139 } else {
khenaidoo442e7c72020-03-10 16:13:48 -0400140 log.Debugw("logicaldevice-created", log.Fields{"logical-device-id": agent.logicalDeviceID, "root-id": ld.RootDeviceId})
khenaidoo297cd252019-02-07 22:10:23 -0500141 }
khenaidoo6e55d9e2019-12-12 18:26:26 -0500142
143 agent.logicalDevice = proto.Clone(ld).(*voltha.LogicalDevice)
khenaidoofc1314d2019-03-14 09:34:21 -0400144
khenaidoo442e7c72020-03-10 16:13:48 -0400145 // Setup the logicalports - internal processing, no need to propagate the client context
npujar1d86a522019-11-14 17:11:16 +0530146 go func() {
khenaidoo442e7c72020-03-10 16:13:48 -0400147 err := agent.setupLogicalPorts(context.Background())
npujar1d86a522019-11-14 17:11:16 +0530148 if err != nil {
149 log.Errorw("unable-to-setup-logical-ports", log.Fields{"error": err})
150 }
151 }()
khenaidoo297cd252019-02-07 22:10:23 -0500152 } else {
153 // load from dB - the logical may not exist at this time. On error, just return and the calling function
154 // will destroy this agent.
npujar467fe752020-01-16 20:17:45 +0530155 logicalDevice, err := agent.clusterDataProxy.Get(ctx, "/logical_devices/"+agent.logicalDeviceID, 0, true, "")
Thomas Lee Se5a44012019-11-07 20:32:24 +0530156 if err != nil {
khenaidoo442e7c72020-03-10 16:13:48 -0400157 return err
Thomas Lee Se5a44012019-11-07 20:32:24 +0530158 }
khenaidoo6e55d9e2019-12-12 18:26:26 -0500159 ld, ok := logicalDevice.(*voltha.LogicalDevice)
160 if !ok {
khenaidoo6e55d9e2019-12-12 18:26:26 -0500161 return status.Errorf(codes.NotFound, "logical_device-%s", agent.logicalDeviceID)
khenaidoo297cd252019-02-07 22:10:23 -0500162 }
khenaidoo8c3303d2019-02-13 14:59:39 -0500163 // Update the root device Id
npujar1d86a522019-11-14 17:11:16 +0530164 agent.rootDeviceID = ld.RootDeviceId
khenaidoo3d3b8c22019-05-22 18:10:39 -0400165
khenaidoo6e55d9e2019-12-12 18:26:26 -0500166 // Update the last data
167 agent.logicalDevice = proto.Clone(ld).(*voltha.LogicalDevice)
168
khenaidoo3d3b8c22019-05-22 18:10:39 -0400169 // Setup the local list of logical ports
170 agent.addLogicalPortsToMap(ld.Ports)
khenaidoob9203542018-09-17 22:56:37 -0400171 }
khenaidoofc1314d2019-03-14 09:34:21 -0400172
khenaidoo442e7c72020-03-10 16:13:48 -0400173 var err error
Thomas Lee Se5a44012019-11-07 20:32:24 +0530174 agent.flowProxy, err = agent.clusterDataProxy.CreateProxy(
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400175 ctx,
npujar1d86a522019-11-14 17:11:16 +0530176 fmt.Sprintf("/logical_devices/%s/flows", agent.logicalDeviceID),
khenaidoo19d7b632018-10-30 10:49:50 -0400177 false)
Thomas Lee Se5a44012019-11-07 20:32:24 +0530178 if err != nil {
Thomas Lee Se5a44012019-11-07 20:32:24 +0530179 return err
180 }
181 agent.meterProxy, err = agent.clusterDataProxy.CreateProxy(
Manikkaraj kb1a10922019-07-29 12:10:34 -0400182 ctx,
npujar1d86a522019-11-14 17:11:16 +0530183 fmt.Sprintf("/logical_devices/%s/meters", agent.logicalDeviceID),
Manikkaraj kb1a10922019-07-29 12:10:34 -0400184 false)
Thomas Lee Se5a44012019-11-07 20:32:24 +0530185 if err != nil {
186 log.Errorw("failed-to-create-meter-proxy", log.Fields{"error": err})
187 return err
188 }
189 agent.groupProxy, err = agent.clusterDataProxy.CreateProxy(
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400190 ctx,
npujar1d86a522019-11-14 17:11:16 +0530191 fmt.Sprintf("/logical_devices/%s/flow_groups", agent.logicalDeviceID),
khenaidoo19d7b632018-10-30 10:49:50 -0400192 false)
Thomas Lee Se5a44012019-11-07 20:32:24 +0530193 if err != nil {
194 log.Errorw("failed-to-create-group-proxy", log.Fields{"error": err})
195 return err
196 }
197 agent.ldProxy, err = agent.clusterDataProxy.CreateProxy(
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400198 ctx,
npujar1d86a522019-11-14 17:11:16 +0530199 fmt.Sprintf("/logical_devices/%s", agent.logicalDeviceID),
khenaidoofc1314d2019-03-14 09:34:21 -0400200 false)
Thomas Lee Se5a44012019-11-07 20:32:24 +0530201 if err != nil {
202 log.Errorw("failed-to-create-logical-device-proxy", log.Fields{"error": err})
203 return err
204 }
khenaidoofc1314d2019-03-14 09:34:21 -0400205 // TODO: Use a port proxy once the POST_ADD is fixed
khenaidoo3d3b8c22019-05-22 18:10:39 -0400206 if agent.ldProxy != nil {
npujar9a30c702019-11-14 17:06:39 +0530207 agent.ldProxy.RegisterCallback(model.PostUpdate, agent.portUpdated)
khenaidoo3d3b8c22019-05-22 18:10:39 -0400208 } else {
khenaidoo3d3b8c22019-05-22 18:10:39 -0400209 return status.Error(codes.Internal, "logical-device-proxy-null")
210 }
khenaidoobcf205b2019-01-25 22:21:14 -0500211
khenaidoo820197c2020-02-13 16:35:33 -0500212 // 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 -0400213 if loadFromDB {
khenaidoo820197c2020-02-13 16:35:33 -0500214 go func() {
215 if err := agent.buildRoutes(context.Background()); err != nil {
khenaidoo442e7c72020-03-10 16:13:48 -0400216 log.Warn("routes-not-ready", log.Fields{"logical-device-id": agent.logicalDeviceID, "error": err})
khenaidoo820197c2020-02-13 16:35:33 -0500217 }
218 }()
khenaidoo4c9e5592019-09-09 16:20:41 -0400219 }
khenaidoo442e7c72020-03-10 16:13:48 -0400220 startSucceeded = true
221
khenaidoob9203542018-09-17 22:56:37 -0400222 return nil
223}
224
khenaidoo442e7c72020-03-10 16:13:48 -0400225// stop stops the logical device agent. This removes the logical device from the data model.
Thomas Lee Se5a44012019-11-07 20:32:24 +0530226func (agent *LogicalDeviceAgent) stop(ctx context.Context) error {
khenaidoo442e7c72020-03-10 16:13:48 -0400227 var returnErr error
228 agent.stopOnce.Do(func() {
229 log.Info("stopping-logical_device-agent")
khenaidoo8c3303d2019-02-13 14:59:39 -0500230
khenaidoo442e7c72020-03-10 16:13:48 -0400231 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
232 // This should never happen - an error is returned only if the agent is stopped and an agent is only stopped once.
233 returnErr = err
234 return
235 }
236 defer agent.requestQueue.RequestComplete()
237
238 //Remove the logical device from the model
239 if removed, err := agent.clusterDataProxy.Remove(ctx, "/logical_devices/"+agent.logicalDeviceID, ""); err != nil {
240 returnErr = err
241 } else if removed == nil {
242 returnErr = status.Errorf(codes.Aborted, "failed-to-remove-logical-ldevice-%s", agent.logicalDeviceID)
243 } else {
244 log.Debugw("logicaldevice-removed", log.Fields{"logicaldeviceId": agent.logicalDeviceID})
245 }
246
247 // Stop the request queue and request complete indication
248 agent.requestQueue.Stop()
249
250 close(agent.exitChannel)
251
252 log.Info("logical_device-agent-stopped")
253 })
254 return returnErr
khenaidoo4d4802d2018-10-04 21:59:49 -0400255}
256
khenaidoo6e55d9e2019-12-12 18:26:26 -0500257// GetLogicalDevice returns the latest logical device data
khenaidoo442e7c72020-03-10 16:13:48 -0400258func (agent *LogicalDeviceAgent) GetLogicalDevice(ctx context.Context) (*voltha.LogicalDevice, error) {
259 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
260 return nil, err
261 }
262 defer agent.requestQueue.RequestComplete()
263 return proto.Clone(agent.logicalDevice).(*voltha.LogicalDevice), nil
khenaidoo92e62c52018-10-03 14:02:54 -0400264}
265
npujar1d86a522019-11-14 17:11:16 +0530266// ListLogicalDeviceFlows returns logical device flows
khenaidoo442e7c72020-03-10 16:13:48 -0400267func (agent *LogicalDeviceAgent) ListLogicalDeviceFlows(ctx context.Context) (*ofp.Flows, error) {
khenaidoodd237172019-05-27 16:37:17 -0400268 log.Debug("ListLogicalDeviceFlows")
khenaidoo6e55d9e2019-12-12 18:26:26 -0500269
khenaidoo442e7c72020-03-10 16:13:48 -0400270 logicalDevice, err := agent.GetLogicalDevice(ctx)
271 if err != nil {
272 return nil, err
khenaidoodd237172019-05-27 16:37:17 -0400273 }
khenaidoo442e7c72020-03-10 16:13:48 -0400274 if logicalDevice.Flows == nil {
275 return &ofp.Flows{}, nil
276 }
277 return (proto.Clone(logicalDevice.Flows)).(*ofp.Flows), nil
khenaidoodd237172019-05-27 16:37:17 -0400278}
279
npujar1d86a522019-11-14 17:11:16 +0530280// ListLogicalDeviceMeters returns logical device meters
khenaidoo442e7c72020-03-10 16:13:48 -0400281func (agent *LogicalDeviceAgent) ListLogicalDeviceMeters(ctx context.Context) (*ofp.Meters, error) {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400282 log.Debug("ListLogicalDeviceMeters")
khenaidoo6e55d9e2019-12-12 18:26:26 -0500283
khenaidoo442e7c72020-03-10 16:13:48 -0400284 logicalDevice, err := agent.GetLogicalDevice(ctx)
285 if err != nil {
286 return nil, err
Manikkaraj kb1a10922019-07-29 12:10:34 -0400287 }
khenaidoo442e7c72020-03-10 16:13:48 -0400288 if logicalDevice.Meters == nil {
289 return &ofp.Meters{}, nil
290 }
291 return (proto.Clone(logicalDevice.Meters)).(*ofp.Meters), nil
Manikkaraj kb1a10922019-07-29 12:10:34 -0400292}
293
npujar1d86a522019-11-14 17:11:16 +0530294// ListLogicalDeviceFlowGroups returns logical device flow groups
khenaidoo442e7c72020-03-10 16:13:48 -0400295func (agent *LogicalDeviceAgent) ListLogicalDeviceFlowGroups(ctx context.Context) (*ofp.FlowGroups, error) {
khenaidoodd237172019-05-27 16:37:17 -0400296 log.Debug("ListLogicalDeviceFlowGroups")
khenaidoo6e55d9e2019-12-12 18:26:26 -0500297
khenaidoo442e7c72020-03-10 16:13:48 -0400298 logicalDevice, err := agent.GetLogicalDevice(ctx)
299 if err != nil {
300 return nil, err
khenaidoodd237172019-05-27 16:37:17 -0400301 }
khenaidoo442e7c72020-03-10 16:13:48 -0400302 if logicalDevice.FlowGroups == nil {
303 return &ofp.FlowGroups{}, nil
304 }
305 return (proto.Clone(logicalDevice.FlowGroups)).(*ofp.FlowGroups), nil
khenaidoodd237172019-05-27 16:37:17 -0400306}
307
npujar1d86a522019-11-14 17:11:16 +0530308// ListLogicalDevicePorts returns logical device ports
khenaidoo442e7c72020-03-10 16:13:48 -0400309func (agent *LogicalDeviceAgent) ListLogicalDevicePorts(ctx context.Context) (*voltha.LogicalPorts, error) {
khenaidoo1ce37ad2019-03-24 22:07:24 -0400310 log.Debug("ListLogicalDevicePorts")
khenaidoo442e7c72020-03-10 16:13:48 -0400311 logicalDevice, err := agent.GetLogicalDevice(ctx)
312 if err != nil {
313 return nil, err
314 }
315 if logicalDevice == nil {
316 return &voltha.LogicalPorts{}, nil
317 }
khenaidoo6e55d9e2019-12-12 18:26:26 -0500318 lPorts := make([]*voltha.LogicalPort, 0)
319 lPorts = append(lPorts, logicalDevice.Ports...)
khenaidoo442e7c72020-03-10 16:13:48 -0400320 return &voltha.LogicalPorts{Items: lPorts}, nil
khenaidoo19d7b632018-10-30 10:49:50 -0400321}
322
khenaidoo4c9e5592019-09-09 16:20:41 -0400323//updateLogicalDeviceFlowsWithoutLock updates the logical device with the latest flows in the model.
npujar467fe752020-01-16 20:17:45 +0530324func (agent *LogicalDeviceAgent) updateLogicalDeviceFlowsWithoutLock(ctx context.Context, flows *ofp.Flows) error {
khenaidoo6e55d9e2019-12-12 18:26:26 -0500325 ld := agent.getLogicalDeviceWithoutLock()
khenaidoo4c9e5592019-09-09 16:20:41 -0400326
khenaidoo6e55d9e2019-12-12 18:26:26 -0500327 log.Debugw("logical-device-before", log.Fields{"lports": len(ld.Ports)})
328 ld.Flows = flows
329
npujar467fe752020-01-16 20:17:45 +0530330 if err := agent.updateLogicalDeviceWithoutLock(ctx, ld); err != nil {
khenaidoo4c9e5592019-09-09 16:20:41 -0400331 log.Errorw("error-updating-logical-device-with-flows", log.Fields{"error": err})
332 return err
khenaidoo43c82122018-11-22 18:38:28 -0500333 }
khenaidoo43c82122018-11-22 18:38:28 -0500334 return nil
335}
336
khenaidoo4c9e5592019-09-09 16:20:41 -0400337//updateLogicalDeviceMetersWithoutLock updates the logical device with the meters info
npujar467fe752020-01-16 20:17:45 +0530338func (agent *LogicalDeviceAgent) updateLogicalDeviceMetersWithoutLock(ctx context.Context, meters *ofp.Meters) error {
khenaidoo6e55d9e2019-12-12 18:26:26 -0500339 ld := agent.getLogicalDeviceWithoutLock()
khenaidoo4c9e5592019-09-09 16:20:41 -0400340
khenaidoo6e55d9e2019-12-12 18:26:26 -0500341 log.Debugw("logical-device-before", log.Fields{"lports": len(ld.Ports)})
342 ld.Meters = meters
343
npujar467fe752020-01-16 20:17:45 +0530344 if err := agent.updateLogicalDeviceWithoutLock(ctx, ld); err != nil {
khenaidoo4c9e5592019-09-09 16:20:41 -0400345 log.Errorw("error-updating-logical-device-with-meters", log.Fields{"error": err})
346 return err
Manikkaraj kb1a10922019-07-29 12:10:34 -0400347 }
348 return nil
349}
350
khenaidoo4c9e5592019-09-09 16:20:41 -0400351//updateLogicalDeviceFlowGroupsWithoutLock updates the logical device with the flow groups
npujar467fe752020-01-16 20:17:45 +0530352func (agent *LogicalDeviceAgent) updateLogicalDeviceFlowGroupsWithoutLock(ctx context.Context, flowGroups *ofp.FlowGroups) error {
khenaidoo6e55d9e2019-12-12 18:26:26 -0500353 ld := agent.getLogicalDeviceWithoutLock()
khenaidoo4c9e5592019-09-09 16:20:41 -0400354
khenaidoo6e55d9e2019-12-12 18:26:26 -0500355 log.Debugw("logical-device-before", log.Fields{"lports": len(ld.Ports)})
356 ld.FlowGroups = flowGroups
357
npujar467fe752020-01-16 20:17:45 +0530358 if err := agent.updateLogicalDeviceWithoutLock(ctx, ld); err != nil {
khenaidoo4c9e5592019-09-09 16:20:41 -0400359 log.Errorw("error-updating-logical-device-with-flowgroups", log.Fields{"error": err})
360 return err
khenaidoo43c82122018-11-22 18:38:28 -0500361 }
khenaidoo43c82122018-11-22 18:38:28 -0500362 return nil
363}
364
khenaidoo6e55d9e2019-12-12 18:26:26 -0500365// getLogicalDeviceWithoutLock returns a cloned logical device to a function that already holds the agent lock.
366func (agent *LogicalDeviceAgent) getLogicalDeviceWithoutLock() *voltha.LogicalDevice {
khenaidoo92e62c52018-10-03 14:02:54 -0400367 log.Debug("getLogicalDeviceWithoutLock")
khenaidoo6e55d9e2019-12-12 18:26:26 -0500368 return proto.Clone(agent.logicalDevice).(*voltha.LogicalDevice)
khenaidoo92e62c52018-10-03 14:02:54 -0400369}
370
npujar467fe752020-01-16 20:17:45 +0530371func (agent *LogicalDeviceAgent) updateLogicalPort(ctx context.Context, device *voltha.Device, port *voltha.Port) error {
khenaidoo2c6a0992019-04-29 13:46:56 -0400372 log.Debugw("updateLogicalPort", log.Fields{"deviceId": device.Id, "port": port})
373 var err error
374 if port.Type == voltha.Port_ETHERNET_NNI {
npujar467fe752020-01-16 20:17:45 +0530375 if _, err = agent.addNNILogicalPort(ctx, device, port); err != nil {
khenaidoo2c6a0992019-04-29 13:46:56 -0400376 return err
377 }
378 agent.addLogicalPortToMap(port.PortNo, true)
379 } else if port.Type == voltha.Port_ETHERNET_UNI {
npujar467fe752020-01-16 20:17:45 +0530380 if _, err = agent.addUNILogicalPort(ctx, device, port); err != nil {
khenaidoo2c6a0992019-04-29 13:46:56 -0400381 return err
382 }
383 agent.addLogicalPortToMap(port.PortNo, false)
384 } else {
khenaidoo820197c2020-02-13 16:35:33 -0500385 // Update the device routes to ensure all routes on the logical device have been calculated
386 if err = agent.buildRoutes(ctx); err != nil {
387 // Not an error - temporary state
388 log.Warnw("failed-to-update-routes", log.Fields{"device-id": device.Id, "port": port, "error": err})
khenaidoo2c6a0992019-04-29 13:46:56 -0400389 }
390 }
391 return nil
392}
393
khenaidoo3d3b8c22019-05-22 18:10:39 -0400394// setupLogicalPorts is invoked once the logical device has been created and is ready to get ports
395// added to it. While the logical device was being created we could have received requests to add
396// NNI and UNI ports which were discarded. Now is the time to add them if needed
397func (agent *LogicalDeviceAgent) setupLogicalPorts(ctx context.Context) error {
npujar1d86a522019-11-14 17:11:16 +0530398 log.Infow("setupLogicalPorts", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo3d3b8c22019-05-22 18:10:39 -0400399 // First add any NNI ports which could have been missing
npujar467fe752020-01-16 20:17:45 +0530400 if err := agent.setupNNILogicalPorts(ctx, agent.rootDeviceID); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530401 log.Errorw("error-setting-up-NNI-ports", log.Fields{"error": err, "deviceId": agent.rootDeviceID})
khenaidoo3d3b8c22019-05-22 18:10:39 -0400402 return err
403 }
404
405 // Now, set up the UNI ports if needed.
npujar467fe752020-01-16 20:17:45 +0530406 children, err := agent.deviceMgr.getAllChildDevices(ctx, agent.rootDeviceID)
npujar1d86a522019-11-14 17:11:16 +0530407 if err != nil {
408 log.Errorw("error-getting-child-devices", log.Fields{"error": err, "deviceId": agent.rootDeviceID})
khenaidoo3d3b8c22019-05-22 18:10:39 -0400409 return err
npujar1d86a522019-11-14 17:11:16 +0530410 }
411 responses := make([]coreutils.Response, 0)
412 for _, child := range children.Items {
413 response := coreutils.NewResponse()
414 responses = append(responses, response)
415 go func(child *voltha.Device) {
khenaidoo442e7c72020-03-10 16:13:48 -0400416 if err = agent.setupUNILogicalPorts(context.Background(), child); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530417 log.Error("setting-up-UNI-ports-failed", log.Fields{"deviceID": child.Id})
418 response.Error(status.Errorf(codes.Internal, "UNI-ports-setup-failed: %s", child.Id))
419 }
420 response.Done()
421 }(child)
422 }
423 // Wait for completion
424 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, responses...); res != nil {
425 return status.Errorf(codes.Aborted, "errors-%s", res)
khenaidoo3d3b8c22019-05-22 18:10:39 -0400426 }
427 return nil
428}
429
khenaidoofc1314d2019-03-14 09:34:21 -0400430// setupNNILogicalPorts creates an NNI port on the logical device that represents an NNI interface on a root device
npujar1d86a522019-11-14 17:11:16 +0530431func (agent *LogicalDeviceAgent) setupNNILogicalPorts(ctx context.Context, deviceID string) error {
432 log.Infow("setupNNILogicalPorts-start", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoob9203542018-09-17 22:56:37 -0400433 // Build the logical device based on information retrieved from the device adapter
khenaidoofc1314d2019-03-14 09:34:21 -0400434 var err error
435
436 var device *voltha.Device
npujar467fe752020-01-16 20:17:45 +0530437 if device, err = agent.deviceMgr.GetDevice(ctx, deviceID); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530438 log.Errorw("error-retrieving-device", log.Fields{"error": err, "deviceId": deviceID})
khenaidoofc1314d2019-03-14 09:34:21 -0400439 return err
440 }
441
442 //Get UNI port number
khenaidoofc1314d2019-03-14 09:34:21 -0400443 for _, port := range device.Ports {
444 if port.Type == voltha.Port_ETHERNET_NNI {
npujar467fe752020-01-16 20:17:45 +0530445 if _, err = agent.addNNILogicalPort(ctx, device, port); err != nil {
khenaidoofc1314d2019-03-14 09:34:21 -0400446 log.Errorw("error-adding-UNI-port", log.Fields{"error": err})
khenaidoofc1314d2019-03-14 09:34:21 -0400447 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400448 agent.addLogicalPortToMap(port.PortNo, true)
khenaidoofc1314d2019-03-14 09:34:21 -0400449 }
450 }
khenaidoofc1314d2019-03-14 09:34:21 -0400451 return err
452}
453
khenaidoo171b98e2019-10-31 11:48:15 -0400454// updatePortState updates the port state of the device
npujar467fe752020-01-16 20:17:45 +0530455func (agent *LogicalDeviceAgent) updatePortState(ctx context.Context, deviceID string, portNo uint32, operStatus voltha.OperStatus_Types) error {
npujar1d86a522019-11-14 17:11:16 +0530456 log.Infow("updatePortState-start", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "portNo": portNo, "state": operStatus})
khenaidoo442e7c72020-03-10 16:13:48 -0400457 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
458 return err
459 }
460 defer agent.requestQueue.RequestComplete()
khenaidoo171b98e2019-10-31 11:48:15 -0400461 // Get the latest logical device info
khenaidoo6e55d9e2019-12-12 18:26:26 -0500462 cloned := agent.getLogicalDeviceWithoutLock()
463 for idx, lPort := range cloned.Ports {
npujar1d86a522019-11-14 17:11:16 +0530464 if lPort.DeviceId == deviceID && lPort.DevicePortNo == portNo {
npujar1d86a522019-11-14 17:11:16 +0530465 if operStatus == voltha.OperStatus_ACTIVE {
466 cloned.Ports[idx].OfpPort.Config = cloned.Ports[idx].OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
467 cloned.Ports[idx].OfpPort.State = uint32(ofp.OfpPortState_OFPPS_LIVE)
468 } else {
469 cloned.Ports[idx].OfpPort.Config = cloned.Ports[idx].OfpPort.Config | uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
470 cloned.Ports[idx].OfpPort.State = uint32(ofp.OfpPortState_OFPPS_LINK_DOWN)
471 }
472 // Update the logical device
npujar467fe752020-01-16 20:17:45 +0530473 if err := agent.updateLogicalDeviceWithoutLock(ctx, cloned); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530474 log.Errorw("error-updating-logical-device", log.Fields{"error": err})
475 return err
476 }
477 return nil
478 }
479 }
480 return status.Errorf(codes.NotFound, "port-%d-not-exist", portNo)
khenaidoo171b98e2019-10-31 11:48:15 -0400481}
482
khenaidoo3ab34882019-05-02 21:33:30 -0400483// updatePortsState updates the ports state related to the device
kesavandbc2d1622020-01-21 00:42:01 -0500484func (agent *LogicalDeviceAgent) updatePortsState(ctx context.Context, device *voltha.Device, state voltha.OperStatus_Types) error {
npujar1d86a522019-11-14 17:11:16 +0530485 log.Infow("updatePortsState-start", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo442e7c72020-03-10 16:13:48 -0400486 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
487 return err
488 }
489 defer agent.requestQueue.RequestComplete()
khenaidoo3ab34882019-05-02 21:33:30 -0400490 // Get the latest logical device info
khenaidoo6e55d9e2019-12-12 18:26:26 -0500491 cloned := agent.getLogicalDeviceWithoutLock()
npujar1d86a522019-11-14 17:11:16 +0530492 for _, lport := range cloned.Ports {
493 if lport.DeviceId == device.Id {
kesavandbc2d1622020-01-21 00:42:01 -0500494 if state == voltha.OperStatus_ACTIVE {
npujar1d86a522019-11-14 17:11:16 +0530495 lport.OfpPort.Config = lport.OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
496 lport.OfpPort.State = uint32(ofp.OfpPortState_OFPPS_LIVE)
kesavandbc2d1622020-01-21 00:42:01 -0500497 } else {
npujar1d86a522019-11-14 17:11:16 +0530498 lport.OfpPort.Config = lport.OfpPort.Config | uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
499 lport.OfpPort.State = uint32(ofp.OfpPortState_OFPPS_LINK_DOWN)
khenaidoo3ab34882019-05-02 21:33:30 -0400500 }
kesavandbc2d1622020-01-21 00:42:01 -0500501
khenaidoo3ab34882019-05-02 21:33:30 -0400502 }
npujar1d86a522019-11-14 17:11:16 +0530503 }
504 // Updating the logical device will trigger the poprt change events to be populated to the controller
npujar467fe752020-01-16 20:17:45 +0530505 if err := agent.updateLogicalDeviceWithoutLock(ctx, cloned); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530506 log.Warnw("logical-device-update-failed", log.Fields{"ldeviceId": agent.logicalDeviceID, "error": err})
507 return err
khenaidoo3ab34882019-05-02 21:33:30 -0400508 }
509 return nil
510}
511
khenaidoofc1314d2019-03-14 09:34:21 -0400512// setupUNILogicalPorts creates a UNI port on the logical device that represents a child UNI interface
513func (agent *LogicalDeviceAgent) setupUNILogicalPorts(ctx context.Context, childDevice *voltha.Device) error {
npujar1d86a522019-11-14 17:11:16 +0530514 log.Infow("setupUNILogicalPort", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoofc1314d2019-03-14 09:34:21 -0400515 // Build the logical device based on information retrieved from the device adapter
khenaidoob9203542018-09-17 22:56:37 -0400516 var err error
khenaidoo59ef7be2019-06-21 12:40:28 -0400517 var added bool
khenaidoo19d7b632018-10-30 10:49:50 -0400518 //Get UNI port number
khenaidoo19d7b632018-10-30 10:49:50 -0400519 for _, port := range childDevice.Ports {
520 if port.Type == voltha.Port_ETHERNET_UNI {
npujar467fe752020-01-16 20:17:45 +0530521 if added, err = agent.addUNILogicalPort(ctx, childDevice, port); err != nil {
khenaidoofc1314d2019-03-14 09:34:21 -0400522 log.Errorw("error-adding-UNI-port", log.Fields{"error": err})
khenaidoofc1314d2019-03-14 09:34:21 -0400523 }
khenaidoo59ef7be2019-06-21 12:40:28 -0400524 if added {
525 agent.addLogicalPortToMap(port.PortNo, false)
526 }
khenaidoo19d7b632018-10-30 10:49:50 -0400527 }
528 }
khenaidoofc1314d2019-03-14 09:34:21 -0400529 return err
khenaidoo92e62c52018-10-03 14:02:54 -0400530}
531
khenaidoo0a822f92019-05-08 15:15:57 -0400532// deleteAllLogicalPorts deletes all logical ports associated with this device
npujar467fe752020-01-16 20:17:45 +0530533func (agent *LogicalDeviceAgent) deleteAllLogicalPorts(ctx context.Context, device *voltha.Device) error {
npujar1d86a522019-11-14 17:11:16 +0530534 log.Infow("updatePortsState-start", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo442e7c72020-03-10 16:13:48 -0400535 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
536 return err
537 }
538 defer agent.requestQueue.RequestComplete()
khenaidoo0a822f92019-05-08 15:15:57 -0400539 // Get the latest logical device info
khenaidoo6e55d9e2019-12-12 18:26:26 -0500540 ld := agent.getLogicalDeviceWithoutLock()
541
npujar1d86a522019-11-14 17:11:16 +0530542 cloned := (proto.Clone(ld)).(*voltha.LogicalDevice)
543 updateLogicalPorts := []*voltha.LogicalPort{}
544 for _, lport := range cloned.Ports {
545 if lport.DeviceId != device.Id {
546 updateLogicalPorts = append(updateLogicalPorts, lport)
547 }
548 }
549 if len(updateLogicalPorts) < len(cloned.Ports) {
550 cloned.Ports = updateLogicalPorts
551 // Updating the logical device will trigger the poprt change events to be populated to the controller
npujar467fe752020-01-16 20:17:45 +0530552 if err := agent.updateLogicalDeviceWithoutLock(ctx, cloned); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530553 log.Warnw("logical-device-update-failed", log.Fields{"ldeviceId": agent.logicalDeviceID, "error": err})
554 return err
555 }
khenaidoo0a822f92019-05-08 15:15:57 -0400556 } else {
npujar1d86a522019-11-14 17:11:16 +0530557 log.Debugw("no-change-required", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo0a822f92019-05-08 15:15:57 -0400558 }
559 return nil
560}
561
Hardik Windlassc704def2020-02-26 18:23:19 +0000562// deleteAllUNILogicalPorts deletes all UNI logical ports associated with this parent device
563func (agent *LogicalDeviceAgent) deleteAllUNILogicalPorts(ctx context.Context, parentDevice *voltha.Device) error {
564 log.Debugw("delete-all-uni-logical-ports", log.Fields{"logical-device-id": agent.logicalDeviceID})
khenaidoo442e7c72020-03-10 16:13:48 -0400565 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
566 return err
567 }
568 defer agent.requestQueue.RequestComplete()
Hardik Windlassc704def2020-02-26 18:23:19 +0000569 // Get the latest logical device info
570 ld := agent.getLogicalDeviceWithoutLock()
571
572 cloned := (proto.Clone(ld)).(*voltha.LogicalDevice)
573 updateLogicalPorts := []*voltha.LogicalPort{}
574 for _, lport := range cloned.Ports {
575 // Save NNI ports only
576 if agent.isNNIPort(lport.DevicePortNo) {
577 updateLogicalPorts = append(updateLogicalPorts, lport)
578 }
579 }
580 if len(updateLogicalPorts) < len(cloned.Ports) {
581 cloned.Ports = updateLogicalPorts
582 // Updating the logical device will trigger the port change events to be populated to the controller
583 if err := agent.updateLogicalDeviceWithoutLock(ctx, cloned); err != nil {
584 return err
585 }
586 } else {
587 log.Debugw("no-change-required", log.Fields{"logical-device-id": agent.logicalDeviceID})
588 }
589 return nil
590}
591
khenaidoo92e62c52018-10-03 14:02:54 -0400592//updateLogicalDeviceWithoutLock updates the model with the logical device. It clones the logicaldevice before saving it
npujar467fe752020-01-16 20:17:45 +0530593func (agent *LogicalDeviceAgent) updateLogicalDeviceWithoutLock(ctx context.Context, logicalDevice *voltha.LogicalDevice) error {
594 updateCtx := context.WithValue(ctx, model.RequestTimestamp, time.Now().UnixNano())
Thomas Lee Se5a44012019-11-07 20:32:24 +0530595 afterUpdate, err := agent.clusterDataProxy.Update(updateCtx, "/logical_devices/"+agent.logicalDeviceID, logicalDevice, false, "")
596 if err != nil {
597 log.Errorw("failed-to-update-logical-devices-to-cluster-proxy", log.Fields{"error": err})
598 return err
599 }
khenaidoo92e62c52018-10-03 14:02:54 -0400600 if afterUpdate == nil {
npujar1d86a522019-11-14 17:11:16 +0530601 return status.Errorf(codes.Internal, "failed-updating-logical-device:%s", agent.logicalDeviceID)
khenaidoo92e62c52018-10-03 14:02:54 -0400602 }
khenaidoo442e7c72020-03-10 16:13:48 -0400603 //agent.logicalDevice = (proto.Clone(logicalDevice)).(*voltha.LogicalDevice)
604 agent.logicalDevice = logicalDevice
605
khenaidoo92e62c52018-10-03 14:02:54 -0400606 return nil
607}
608
khenaidoo820197c2020-02-13 16:35:33 -0500609//generateDeviceRoutesIfNeeded generates the device routes if the logical device has been updated since the last time
khenaidoo4c9e5592019-09-09 16:20:41 -0400610//that device graph was generated.
khenaidoo820197c2020-02-13 16:35:33 -0500611func (agent *LogicalDeviceAgent) generateDeviceRoutesIfNeeded(ctx context.Context) error {
612 agent.lockDeviceRoutes.Lock()
613 defer agent.lockDeviceRoutes.Unlock()
614
khenaidoo442e7c72020-03-10 16:13:48 -0400615 ld, err := agent.GetLogicalDevice(ctx)
616 if err != nil {
617 return err
618 }
khenaidoo820197c2020-02-13 16:35:33 -0500619
620 if agent.deviceRoutes != nil && agent.deviceRoutes.IsUpToDate(ld) {
npujar1d86a522019-11-14 17:11:16 +0530621 return nil
622 }
khenaidoo442e7c72020-03-10 16:13:48 -0400623 log.Debug("Generation of device route required")
khenaidoo820197c2020-02-13 16:35:33 -0500624 if err := agent.buildRoutes(ctx); err != nil {
625 return err
626 }
khenaidoo4c9e5592019-09-09 16:20:41 -0400627 return nil
628}
629
khenaidoo19d7b632018-10-30 10:49:50 -0400630//updateFlowTable updates the flow table of that logical device
631func (agent *LogicalDeviceAgent) updateFlowTable(ctx context.Context, flow *ofp.OfpFlowMod) error {
632 log.Debug("updateFlowTable")
633 if flow == nil {
634 return nil
635 }
khenaidoo820197c2020-02-13 16:35:33 -0500636 if err := agent.generateDeviceRoutesIfNeeded(ctx); err != nil {
khenaidoo4c9e5592019-09-09 16:20:41 -0400637 return err
638 }
khenaidoo19d7b632018-10-30 10:49:50 -0400639 switch flow.GetCommand() {
640 case ofp.OfpFlowModCommand_OFPFC_ADD:
npujar467fe752020-01-16 20:17:45 +0530641 return agent.flowAdd(ctx, flow)
khenaidoo19d7b632018-10-30 10:49:50 -0400642 case ofp.OfpFlowModCommand_OFPFC_DELETE:
npujar467fe752020-01-16 20:17:45 +0530643 return agent.flowDelete(ctx, flow)
khenaidoo19d7b632018-10-30 10:49:50 -0400644 case ofp.OfpFlowModCommand_OFPFC_DELETE_STRICT:
npujar467fe752020-01-16 20:17:45 +0530645 return agent.flowDeleteStrict(ctx, flow)
khenaidoo19d7b632018-10-30 10:49:50 -0400646 case ofp.OfpFlowModCommand_OFPFC_MODIFY:
647 return agent.flowModify(flow)
648 case ofp.OfpFlowModCommand_OFPFC_MODIFY_STRICT:
649 return agent.flowModifyStrict(flow)
650 }
651 return status.Errorf(codes.Internal,
npujar1d86a522019-11-14 17:11:16 +0530652 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceID, flow.GetCommand())
khenaidoo19d7b632018-10-30 10:49:50 -0400653}
654
655//updateGroupTable updates the group table of that logical device
656func (agent *LogicalDeviceAgent) updateGroupTable(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
657 log.Debug("updateGroupTable")
658 if groupMod == nil {
659 return nil
660 }
khenaidoo820197c2020-02-13 16:35:33 -0500661 if err := agent.generateDeviceRoutesIfNeeded(ctx); err != nil {
khenaidoo4c9e5592019-09-09 16:20:41 -0400662 return err
663 }
khenaidoo820197c2020-02-13 16:35:33 -0500664
khenaidoo19d7b632018-10-30 10:49:50 -0400665 switch groupMod.GetCommand() {
666 case ofp.OfpGroupModCommand_OFPGC_ADD:
npujar467fe752020-01-16 20:17:45 +0530667 return agent.groupAdd(ctx, groupMod)
khenaidoo19d7b632018-10-30 10:49:50 -0400668 case ofp.OfpGroupModCommand_OFPGC_DELETE:
npujar467fe752020-01-16 20:17:45 +0530669 return agent.groupDelete(ctx, groupMod)
khenaidoo19d7b632018-10-30 10:49:50 -0400670 case ofp.OfpGroupModCommand_OFPGC_MODIFY:
npujar467fe752020-01-16 20:17:45 +0530671 return agent.groupModify(ctx, groupMod)
khenaidoo19d7b632018-10-30 10:49:50 -0400672 }
673 return status.Errorf(codes.Internal,
npujar1d86a522019-11-14 17:11:16 +0530674 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceID, groupMod.GetCommand())
khenaidoo19d7b632018-10-30 10:49:50 -0400675}
676
Manikkaraj kb1a10922019-07-29 12:10:34 -0400677// updateMeterTable updates the meter table of that logical device
678func (agent *LogicalDeviceAgent) updateMeterTable(ctx context.Context, meterMod *ofp.OfpMeterMod) error {
679 log.Debug("updateMeterTable")
680 if meterMod == nil {
681 return nil
682 }
683 switch meterMod.GetCommand() {
684 case ofp.OfpMeterModCommand_OFPMC_ADD:
npujar467fe752020-01-16 20:17:45 +0530685 return agent.meterAdd(ctx, meterMod)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400686 case ofp.OfpMeterModCommand_OFPMC_DELETE:
npujar467fe752020-01-16 20:17:45 +0530687 return agent.meterDelete(ctx, meterMod)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400688 case ofp.OfpMeterModCommand_OFPMC_MODIFY:
npujar467fe752020-01-16 20:17:45 +0530689 return agent.meterModify(ctx, meterMod)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400690 }
691 return status.Errorf(codes.Internal,
npujar1d86a522019-11-14 17:11:16 +0530692 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceID, meterMod.GetCommand())
Manikkaraj kb1a10922019-07-29 12:10:34 -0400693
694}
695
npujar467fe752020-01-16 20:17:45 +0530696func (agent *LogicalDeviceAgent) meterAdd(ctx context.Context, meterMod *ofp.OfpMeterMod) error {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400697 log.Debugw("meterAdd", log.Fields{"metermod": *meterMod})
698 if meterMod == nil {
699 return nil
700 }
khenaidoo442e7c72020-03-10 16:13:48 -0400701 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
702 return err
703 }
704 defer agent.requestQueue.RequestComplete()
Manikkaraj kb1a10922019-07-29 12:10:34 -0400705 log.Debug("Acquired logical device lock")
khenaidoo6e55d9e2019-12-12 18:26:26 -0500706 lDevice := agent.getLogicalDeviceWithoutLock()
Manikkaraj kb1a10922019-07-29 12:10:34 -0400707
708 var meters []*ofp.OfpMeterEntry
709 if lDevice.Meters != nil && lDevice.Meters.Items != nil {
710 meters = lDevice.Meters.Items
711 }
712 log.Debugw("Available meters", log.Fields{"meters": meters})
713
714 for _, meter := range meters {
715 if meterMod.MeterId == meter.Config.MeterId {
716 log.Infow("Meter-already-exists", log.Fields{"meter": *meterMod})
717 return nil
718 }
719 }
720
721 meterEntry := fu.MeterEntryFromMeterMod(meterMod)
722 meters = append(meters, meterEntry)
723 //Update model
npujar467fe752020-01-16 20:17:45 +0530724 if err := agent.updateLogicalDeviceMetersWithoutLock(ctx, &ofp.Meters{Items: meters}); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530725 log.Errorw("db-meter-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400726 return err
727 }
728 log.Debugw("Meter-added-successfully", log.Fields{"Added-meter": meterEntry, "updated-meters": lDevice.Meters})
729 return nil
730}
731
npujar467fe752020-01-16 20:17:45 +0530732func (agent *LogicalDeviceAgent) meterDelete(ctx context.Context, meterMod *ofp.OfpMeterMod) error {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400733 log.Debug("meterDelete", log.Fields{"meterMod": *meterMod})
734 if meterMod == nil {
735 return nil
736 }
khenaidoo442e7c72020-03-10 16:13:48 -0400737 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
738 return err
739 }
740 defer agent.requestQueue.RequestComplete()
Manikkaraj kb1a10922019-07-29 12:10:34 -0400741
khenaidoo6e55d9e2019-12-12 18:26:26 -0500742 lDevice := agent.getLogicalDeviceWithoutLock()
Manikkaraj kb1a10922019-07-29 12:10:34 -0400743
744 var meters []*ofp.OfpMeterEntry
745 var flows []*ofp.OfpFlowStats
746 updatedFlows := make([]*ofp.OfpFlowStats, 0)
747 if lDevice.Meters != nil && lDevice.Meters.Items != nil {
748 meters = lDevice.Meters.Items
749 }
Manikkaraj kb1a10922019-07-29 12:10:34 -0400750
751 changedMeter := false
752 changedFow := false
753 log.Debugw("Available meters", log.Fields{"meters": meters})
754 for index, meter := range meters {
755 if meterMod.MeterId == meter.Config.MeterId {
756 flows = lDevice.Flows.Items
npujar1d86a522019-11-14 17:11:16 +0530757 changedFow, updatedFlows = agent.getUpdatedFlowsAfterDeletebyMeterID(flows, meterMod.MeterId)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400758 meters = append(meters[:index], meters[index+1:]...)
759 log.Debugw("Meter has been deleted", log.Fields{"meter": meter, "index": index})
760 changedMeter = true
761 break
762 }
763 }
764 if changedMeter {
765 //Update model
766 metersToUpdate := &ofp.Meters{}
767 if lDevice.Meters != nil {
768 metersToUpdate = &ofp.Meters{Items: meters}
769 }
npujar467fe752020-01-16 20:17:45 +0530770 if err := agent.updateLogicalDeviceMetersWithoutLock(ctx, metersToUpdate); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530771 log.Errorw("db-meter-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400772 return err
773 }
774 log.Debug("Meter-deleted-from-DB-successfully", log.Fields{"updatedMeters": metersToUpdate, "no-of-meter": len(metersToUpdate.Items)})
775
776 }
777 if changedFow {
778 //Update model
npujar467fe752020-01-16 20:17:45 +0530779 if err := agent.updateLogicalDeviceFlowsWithoutLock(ctx, &ofp.Flows{Items: updatedFlows}); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530780 log.Errorw("db-flow-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400781 return err
782 }
783 log.Debug("Flows-associated-with-meter-deleted-from-DB-successfully",
784 log.Fields{"updated-no-of-flows": len(updatedFlows), "meter": meterMod.MeterId})
785 }
786 log.Debugw("meterDelete success", log.Fields{"meterID": meterMod.MeterId})
787 return nil
788}
789
npujar467fe752020-01-16 20:17:45 +0530790func (agent *LogicalDeviceAgent) meterModify(ctx context.Context, meterMod *ofp.OfpMeterMod) error {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400791 log.Debug("meterModify")
792 if meterMod == nil {
793 return nil
794 }
khenaidoo442e7c72020-03-10 16:13:48 -0400795 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
796 return err
797 }
798 defer agent.requestQueue.RequestComplete()
Manikkaraj kb1a10922019-07-29 12:10:34 -0400799
khenaidoo6e55d9e2019-12-12 18:26:26 -0500800 lDevice := agent.getLogicalDeviceWithoutLock()
Manikkaraj kb1a10922019-07-29 12:10:34 -0400801
802 var meters []*ofp.OfpMeterEntry
803 if lDevice.Meters != nil && lDevice.Meters.Items != nil {
804 meters = lDevice.Meters.Items
805 }
806 changedMeter := false
807 for index, meter := range meters {
808 if meterMod.MeterId == meter.Config.MeterId {
809 newmeterEntry := fu.MeterEntryFromMeterMod(meterMod)
810 newmeterEntry.Stats.FlowCount = meter.Stats.FlowCount
811 meters[index] = newmeterEntry
812 changedMeter = true
813 log.Debugw("Found meter, replaced with new meter", log.Fields{"old meter": meter, "new meter": newmeterEntry})
814 break
815 }
816 }
817 if changedMeter {
818 //Update model
819 metersToUpdate := &ofp.Meters{}
820 if lDevice.Meters != nil {
821 metersToUpdate = &ofp.Meters{Items: meters}
822 }
npujar467fe752020-01-16 20:17:45 +0530823 if err := agent.updateLogicalDeviceMetersWithoutLock(ctx, metersToUpdate); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530824 log.Errorw("db-meter-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400825 return err
826 }
827 log.Debugw("meter-updated-in-DB-successfully", log.Fields{"updated_meters": meters})
828 return nil
829 }
830
831 log.Errorw("Meter not found ", log.Fields{"meter": meterMod})
npujar1d86a522019-11-14 17:11:16 +0530832 return fmt.Errorf("no-logical-device-present:%d", meterMod.MeterId)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400833
834}
835
npujar1d86a522019-11-14 17:11:16 +0530836func (agent *LogicalDeviceAgent) getUpdatedFlowsAfterDeletebyMeterID(flows []*ofp.OfpFlowStats, meterID uint32) (bool, []*ofp.OfpFlowStats) {
837 log.Infow("Delete flows matching meter", log.Fields{"meter": meterID})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400838 changed := false
839 //updatedFlows := make([]*ofp.OfpFlowStats, 0)
840 for index := len(flows) - 1; index >= 0; index-- {
npujar1d86a522019-11-14 17:11:16 +0530841 if mID := fu.GetMeterIdFromFlow(flows[index]); mID != 0 && mID == meterID {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400842 log.Debugw("Flow to be deleted", log.Fields{"flow": flows[index], "index": index})
843 flows = append(flows[:index], flows[index+1:]...)
844 changed = true
845 }
846 }
847 return changed, flows
848}
849
850func (agent *LogicalDeviceAgent) updateFlowCountOfMeterStats(modCommand *ofp.OfpFlowMod, meters []*ofp.OfpMeterEntry, flow *ofp.OfpFlowStats) bool {
851
852 flowCommand := modCommand.GetCommand()
npujar1d86a522019-11-14 17:11:16 +0530853 meterID := fu.GetMeterIdFromFlow(flow)
854 log.Debugw("Meter-id-in-flow-mod", log.Fields{"meterId": meterID})
855 if meterID == 0 {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400856 log.Debugw("No meter present in the flow", log.Fields{"flow": *flow})
857 return false
858 }
859 if meters == nil {
860 log.Debug("No meters present in logical device")
861 return false
862 }
863 changedMeter := false
864 for _, meter := range meters {
npujar1d86a522019-11-14 17:11:16 +0530865 if meterID == meter.Config.MeterId { // Found meter in Logicaldevice
Manikkaraj kb1a10922019-07-29 12:10:34 -0400866 if flowCommand == ofp.OfpFlowModCommand_OFPFC_ADD {
npujar1d86a522019-11-14 17:11:16 +0530867 meter.Stats.FlowCount++
Manikkaraj kb1a10922019-07-29 12:10:34 -0400868 changedMeter = true
869 } else if flowCommand == ofp.OfpFlowModCommand_OFPFC_DELETE_STRICT {
npujar1d86a522019-11-14 17:11:16 +0530870 meter.Stats.FlowCount--
Manikkaraj kb1a10922019-07-29 12:10:34 -0400871 changedMeter = true
872 }
npujar1d86a522019-11-14 17:11:16 +0530873 log.Debugw("Found meter, updated meter flow stats", log.Fields{" meterId": meterID})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400874 break
875 }
876 }
877 return changedMeter
878}
879
khenaidoo19d7b632018-10-30 10:49:50 -0400880//flowAdd adds a flow to the flow table of that logical device
npujar467fe752020-01-16 20:17:45 +0530881func (agent *LogicalDeviceAgent) flowAdd(ctx context.Context, mod *ofp.OfpFlowMod) error {
khenaidoo4c9e5592019-09-09 16:20:41 -0400882 log.Debugw("flowAdd", log.Fields{"flow": mod})
khenaidoo19d7b632018-10-30 10:49:50 -0400883 if mod == nil {
884 return nil
885 }
khenaidoo442e7c72020-03-10 16:13:48 -0400886 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
887 return err
888 }
889 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -0400890
khenaidoo6e55d9e2019-12-12 18:26:26 -0500891 lDevice := agent.getLogicalDeviceWithoutLock()
khenaidoo19d7b632018-10-30 10:49:50 -0400892
893 var flows []*ofp.OfpFlowStats
Manikkaraj kb1a10922019-07-29 12:10:34 -0400894 var meters []*ofp.OfpMeterEntry
895 var flow *ofp.OfpFlowStats
Scott Bakerfdea1e32020-02-21 15:35:41 -0800896 var err error
Manikkaraj kb1a10922019-07-29 12:10:34 -0400897
khenaidoo19d7b632018-10-30 10:49:50 -0400898 if lDevice.Flows != nil && lDevice.Flows.Items != nil {
899 flows = lDevice.Flows.Items
900 }
901
Manikkaraj kb1a10922019-07-29 12:10:34 -0400902 if lDevice.Meters != nil && lDevice.Meters.Items != nil {
903 meters = lDevice.Meters.Items
904 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400905 updatedFlows := make([]*ofp.OfpFlowStats, 0)
khenaidoo19d7b632018-10-30 10:49:50 -0400906 changed := false
Manikkaraj kb1a10922019-07-29 12:10:34 -0400907 updated := false
khenaidoo19d7b632018-10-30 10:49:50 -0400908 checkOverlap := (mod.Flags & uint32(ofp.OfpFlowModFlags_OFPFF_CHECK_OVERLAP)) != 0
909 if checkOverlap {
910 if overlapped := fu.FindOverlappingFlows(flows, mod); len(overlapped) != 0 {
911 // TODO: should this error be notified other than being logged?
npujar1d86a522019-11-14 17:11:16 +0530912 log.Warnw("overlapped-flows", log.Fields{"logicaldeviceId": agent.logicalDeviceID})
khenaidoo19d7b632018-10-30 10:49:50 -0400913 } else {
Matt Jeanneret518b5a42019-10-29 10:30:46 -0400914 // Add flow
Scott Bakerfdea1e32020-02-21 15:35:41 -0800915 flow, err = fu.FlowStatsEntryFromFlowModMessage(mod)
916 if err != nil {
917 return err
918 }
khenaidoo19d7b632018-10-30 10:49:50 -0400919 flows = append(flows, flow)
khenaidoo2c6a0992019-04-29 13:46:56 -0400920 updatedFlows = append(updatedFlows, flow)
khenaidoo19d7b632018-10-30 10:49:50 -0400921 changed = true
922 }
923 } else {
Scott Bakerfdea1e32020-02-21 15:35:41 -0800924 flow, err = fu.FlowStatsEntryFromFlowModMessage(mod)
925 if err != nil {
926 return err
927 }
khenaidoo19d7b632018-10-30 10:49:50 -0400928 idx := fu.FindFlows(flows, flow)
929 if idx >= 0 {
930 oldFlow := flows[idx]
931 if (mod.Flags & uint32(ofp.OfpFlowModFlags_OFPFF_RESET_COUNTS)) != 0 {
932 flow.ByteCount = oldFlow.ByteCount
933 flow.PacketCount = oldFlow.PacketCount
934 }
Matt Jeanneret518b5a42019-10-29 10:30:46 -0400935 if !reflect.DeepEqual(oldFlow, flow) {
936 flows[idx] = flow
937 updatedFlows = append(updatedFlows, flow)
938 changed = true
939 updated = true
940 }
941 } else {
khenaidoo19d7b632018-10-30 10:49:50 -0400942 flows = append(flows, flow)
khenaidoo2c6a0992019-04-29 13:46:56 -0400943 updatedFlows = append(updatedFlows, flow)
944 changed = true
khenaidoo19d7b632018-10-30 10:49:50 -0400945 }
khenaidoo19d7b632018-10-30 10:49:50 -0400946 }
khenaidoo4c9e5592019-09-09 16:20:41 -0400947 log.Debugw("flowAdd-changed", log.Fields{"changed": changed})
948
khenaidoo19d7b632018-10-30 10:49:50 -0400949 if changed {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400950 var flowMetadata voltha.FlowMetadata
951 if err := agent.GetMeterConfig(updatedFlows, meters, &flowMetadata); err != nil { // This should never happen,meters should be installed before flow arrives
952 log.Error("Meter-referred-in-flows-not-present")
953 return err
954 }
khenaidoo820197c2020-02-13 16:35:33 -0500955 deviceRules, err := agent.flowDecomposer.DecomposeRules(ctx, agent, ofp.Flows{Items: updatedFlows}, *lDevice.FlowGroups)
956 if err != nil {
957 return err
958 }
khenaidoo0458db62019-06-20 08:50:36 -0400959 log.Debugw("rules", log.Fields{"rules": deviceRules.String()})
960
khenaidoo19d7b632018-10-30 10:49:50 -0400961 // Update model
npujar467fe752020-01-16 20:17:45 +0530962 if err := agent.updateLogicalDeviceFlowsWithoutLock(ctx, &ofp.Flows{Items: flows}); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530963 log.Errorw("db-flow-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo19d7b632018-10-30 10:49:50 -0400964 return err
965 }
Matt Jeanneret518b5a42019-10-29 10:30:46 -0400966 if !updated {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400967 changedMeterStats := agent.updateFlowCountOfMeterStats(mod, meters, flow)
968 metersToUpdate := &ofp.Meters{}
969 if lDevice.Meters != nil {
970 metersToUpdate = &ofp.Meters{Items: meters}
971 }
972 if changedMeterStats {
973 //Update model
npujar467fe752020-01-16 20:17:45 +0530974 if err := agent.updateLogicalDeviceMetersWithoutLock(ctx, metersToUpdate); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530975 log.Errorw("db-meter-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400976 return err
977 }
978 log.Debugw("meter-stats-updated-in-DB-successfully", log.Fields{"updated_meters": meters})
979
980 }
981 }
khenaidoo442e7c72020-03-10 16:13:48 -0400982 // Send the flows to the devices
983 respChannels := agent.addFlowsAndGroupsToDevices(ctx, deviceRules, &flowMetadata)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400984
khenaidoo442e7c72020-03-10 16:13:48 -0400985 // Create the go routines to wait
986 go func() {
987 // Wait for completion
988 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChannels...); res != nil {
989 log.Warnw("failure-to-add-flows", log.Fields{"errors": res, "logical-device-id": agent.logicalDeviceID})
990 // TODO : revert added flow
991 }
992 }()
khenaidoo19d7b632018-10-30 10:49:50 -0400993 }
khenaidoo19d7b632018-10-30 10:49:50 -0400994 return nil
995}
996
npujar1d86a522019-11-14 17:11:16 +0530997// GetMeterConfig returns meter config
Manikkaraj kb1a10922019-07-29 12:10:34 -0400998func (agent *LogicalDeviceAgent) GetMeterConfig(flows []*ofp.OfpFlowStats, meters []*ofp.OfpMeterEntry, metadata *voltha.FlowMetadata) error {
999 m := make(map[uint32]bool)
1000 for _, flow := range flows {
npujar1d86a522019-11-14 17:11:16 +05301001 if flowMeterID := fu.GetMeterIdFromFlow(flow); flowMeterID != 0 && !m[flowMeterID] {
Manikkaraj kb1a10922019-07-29 12:10:34 -04001002 foundMeter := false
1003 // Meter is present in the flow , Get from logical device
1004 for _, meter := range meters {
1005 if flowMeterID == meter.Config.MeterId {
1006 metadata.Meters = append(metadata.Meters, meter.Config)
1007 log.Debugw("Found meter in logical device",
1008 log.Fields{"meterID": flowMeterID, "meter-band": meter.Config})
1009 m[flowMeterID] = true
1010 foundMeter = true
1011 break
1012 }
1013 }
1014 if !foundMeter {
1015 log.Errorw("Meter-referred-by-flow-is-not-found-in-logicaldevice",
npujar1d86a522019-11-14 17:11:16 +05301016 log.Fields{"meterID": flowMeterID, "Available-meters": meters, "flow": *flow})
Manikkaraj kb1a10922019-07-29 12:10:34 -04001017 return errors.New("Meter-referred-by-flow-is-not-found-in-logicaldevice")
1018 }
1019 }
1020 }
1021 log.Debugw("meter-bands-for-flows", log.Fields{"flows": len(flows), "metadata": metadata})
1022 return nil
1023
1024}
1025
khenaidoo19d7b632018-10-30 10:49:50 -04001026//flowDelete deletes a flow from the flow table of that logical device
npujar467fe752020-01-16 20:17:45 +05301027func (agent *LogicalDeviceAgent) flowDelete(ctx context.Context, mod *ofp.OfpFlowMod) error {
khenaidoo19d7b632018-10-30 10:49:50 -04001028 log.Debug("flowDelete")
1029 if mod == nil {
1030 return nil
1031 }
khenaidoo442e7c72020-03-10 16:13:48 -04001032 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1033 return err
1034 }
1035 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -04001036
khenaidoo6e55d9e2019-12-12 18:26:26 -05001037 lDevice := agent.getLogicalDeviceWithoutLock()
khenaidoo19d7b632018-10-30 10:49:50 -04001038
Manikkaraj kb1a10922019-07-29 12:10:34 -04001039 var meters []*ofp.OfpMeterEntry
1040 var flows []*ofp.OfpFlowStats
Esin Karamanfc3b1af2020-01-29 16:52:00 +00001041 var flowGroups []*ofp.OfpGroupEntry
Manikkaraj kb1a10922019-07-29 12:10:34 -04001042
1043 if lDevice.Flows != nil && lDevice.Flows.Items != nil {
1044 flows = lDevice.Flows.Items
1045 }
1046
1047 if lDevice.Meters != nil && lDevice.Meters.Items != nil {
1048 meters = lDevice.Meters.Items
1049 }
Esin Karamanfc3b1af2020-01-29 16:52:00 +00001050
1051 if lDevice.FlowGroups != nil && lDevice.FlowGroups.Items != nil {
1052 flowGroups = lDevice.FlowGroups.Items
1053 }
1054
khenaidoo19d7b632018-10-30 10:49:50 -04001055 //build a list of what to keep vs what to delete
1056 toKeep := make([]*ofp.OfpFlowStats, 0)
khenaidoo0458db62019-06-20 08:50:36 -04001057 toDelete := make([]*ofp.OfpFlowStats, 0)
khenaidoo19d7b632018-10-30 10:49:50 -04001058 for _, f := range flows {
khenaidoo0458db62019-06-20 08:50:36 -04001059 // Check whether the flow and the flowmod matches
Scott Bakerfdea1e32020-02-21 15:35:41 -08001060 fs, err := fu.FlowStatsEntryFromFlowModMessage(mod)
1061 if err != nil {
1062 return err
1063 }
1064 if fu.FlowMatch(f, fs) {
khenaidoo0458db62019-06-20 08:50:36 -04001065 toDelete = append(toDelete, f)
1066 continue
1067 }
1068 // Check wild card match
khenaidoo19d7b632018-10-30 10:49:50 -04001069 if !fu.FlowMatchesMod(f, mod) {
1070 toKeep = append(toKeep, f)
khenaidoo0458db62019-06-20 08:50:36 -04001071 } else {
1072 toDelete = append(toDelete, f)
khenaidoo19d7b632018-10-30 10:49:50 -04001073 }
1074 }
1075
npujar1d86a522019-11-14 17:11:16 +05301076 log.Debugw("flowDelete", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "toKeep": len(toKeep), "toDelete": toDelete})
khenaidoo0458db62019-06-20 08:50:36 -04001077
khenaidoo19d7b632018-10-30 10:49:50 -04001078 //Update flows
khenaidoo0458db62019-06-20 08:50:36 -04001079 if len(toDelete) > 0 {
Manikkaraj kb1a10922019-07-29 12:10:34 -04001080 var flowMetadata voltha.FlowMetadata
1081 if err := agent.GetMeterConfig(toDelete, meters, &flowMetadata); err != nil { // This should never happen
1082 log.Error("Meter-referred-in-flows-not-present")
1083 return errors.New("Meter-referred-in-flows-not-present")
1084 }
khenaidoo820197c2020-02-13 16:35:33 -05001085 deviceRules, err := agent.flowDecomposer.DecomposeRules(ctx, agent, ofp.Flows{Items: toDelete}, ofp.FlowGroups{Items: flowGroups})
1086 if err != nil {
1087 return err
1088 }
khenaidoo0458db62019-06-20 08:50:36 -04001089 log.Debugw("rules", log.Fields{"rules": deviceRules.String()})
1090
npujar467fe752020-01-16 20:17:45 +05301091 if err := agent.updateLogicalDeviceFlowsWithoutLock(ctx, &ofp.Flows{Items: toKeep}); err != nil {
Thomas Lee Se5a44012019-11-07 20:32:24 +05301092 log.Errorw("cannot-update-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo19d7b632018-10-30 10:49:50 -04001093 return err
1094 }
khenaidoo442e7c72020-03-10 16:13:48 -04001095
1096 // Update the devices
1097 respChnls := agent.deleteFlowsAndGroupsFromDevices(ctx, deviceRules, &flowMetadata)
1098
1099 // Wait for the responses
1100 go func() {
1101 // Wait for completion
1102 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil {
1103 log.Errorw("failure-updating-device-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "errors": res})
1104 // TODO: Revert the flow deletion
1105 }
1106 }()
khenaidoo19d7b632018-10-30 10:49:50 -04001107 }
1108
1109 //TODO: send announcement on delete
1110 return nil
1111}
1112
khenaidoo442e7c72020-03-10 16:13:48 -04001113func (agent *LogicalDeviceAgent) addFlowsAndGroupsToDevices(ctx context.Context, deviceRules *fu.DeviceRules, flowMetadata *voltha.FlowMetadata) []coreutils.Response {
1114 log.Debugw("send-add-flows-to-device-manager", log.Fields{"logicalDeviceID": agent.logicalDeviceID, "deviceRules": deviceRules, "flowMetadata": flowMetadata})
khenaidoo19d7b632018-10-30 10:49:50 -04001115
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001116 responses := make([]coreutils.Response, 0)
npujar1d86a522019-11-14 17:11:16 +05301117 for deviceID, value := range deviceRules.GetRules() {
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001118 response := coreutils.NewResponse()
1119 responses = append(responses, response)
1120 go func(deviceId string, value *fu.FlowsAndGroups) {
khenaidoo442e7c72020-03-10 16:13:48 -04001121 ctx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
1122 defer cancel()
npujar467fe752020-01-16 20:17:45 +05301123 if err := agent.deviceMgr.addFlowsAndGroups(ctx, deviceId, value.ListFlows(), value.ListGroups(), flowMetadata); err != nil {
khenaidoo0458db62019-06-20 08:50:36 -04001124 log.Errorw("flow-add-failed", log.Fields{"deviceID": deviceId, "error": err})
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001125 response.Error(status.Errorf(codes.Internal, "flow-add-failed: %s", deviceId))
khenaidoo0458db62019-06-20 08:50:36 -04001126 }
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001127 response.Done()
npujar1d86a522019-11-14 17:11:16 +05301128 }(deviceID, value)
khenaidoo19d7b632018-10-30 10:49:50 -04001129 }
khenaidoo442e7c72020-03-10 16:13:48 -04001130 // Return responses (an array of channels) for the caller to wait for a response from the far end.
1131 return responses
khenaidoo0458db62019-06-20 08:50:36 -04001132}
khenaidoo19d7b632018-10-30 10:49:50 -04001133
khenaidoo442e7c72020-03-10 16:13:48 -04001134func (agent *LogicalDeviceAgent) deleteFlowsAndGroupsFromDevices(ctx context.Context, deviceRules *fu.DeviceRules, flowMetadata *voltha.FlowMetadata) []coreutils.Response {
1135 log.Debugw("send-delete-flows-to-device-manager", log.Fields{"logicalDeviceID": agent.logicalDeviceID})
khenaidoo0458db62019-06-20 08:50:36 -04001136
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001137 responses := make([]coreutils.Response, 0)
npujar1d86a522019-11-14 17:11:16 +05301138 for deviceID, value := range deviceRules.GetRules() {
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001139 response := coreutils.NewResponse()
1140 responses = append(responses, response)
1141 go func(deviceId string, value *fu.FlowsAndGroups) {
khenaidoo442e7c72020-03-10 16:13:48 -04001142 ctx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
1143 defer cancel()
npujar467fe752020-01-16 20:17:45 +05301144 if err := agent.deviceMgr.deleteFlowsAndGroups(ctx, deviceId, value.ListFlows(), value.ListGroups(), flowMetadata); err != nil {
khenaidoo0458db62019-06-20 08:50:36 -04001145 log.Error("flow-delete-failed", log.Fields{"deviceID": deviceId, "error": err})
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001146 response.Error(status.Errorf(codes.Internal, "flow-delete-failed: %s", deviceId))
khenaidoo0458db62019-06-20 08:50:36 -04001147 }
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001148 response.Done()
npujar1d86a522019-11-14 17:11:16 +05301149 }(deviceID, value)
khenaidoo0458db62019-06-20 08:50:36 -04001150 }
khenaidoo442e7c72020-03-10 16:13:48 -04001151 return responses
khenaidoo0458db62019-06-20 08:50:36 -04001152}
1153
khenaidoo442e7c72020-03-10 16:13:48 -04001154func (agent *LogicalDeviceAgent) updateFlowsAndGroupsOfDevice(ctx context.Context, deviceRules *fu.DeviceRules, flowMetadata *voltha.FlowMetadata) []coreutils.Response {
1155 log.Debugw("send-update-flows-to-device-manager", log.Fields{"logicalDeviceID": agent.logicalDeviceID})
khenaidoo0458db62019-06-20 08:50:36 -04001156
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001157 responses := make([]coreutils.Response, 0)
npujar1d86a522019-11-14 17:11:16 +05301158 for deviceID, value := range deviceRules.GetRules() {
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001159 response := coreutils.NewResponse()
1160 responses = append(responses, response)
1161 go func(deviceId string, value *fu.FlowsAndGroups) {
khenaidoo442e7c72020-03-10 16:13:48 -04001162 ctx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
1163 defer cancel()
npujar467fe752020-01-16 20:17:45 +05301164 if err := agent.deviceMgr.updateFlowsAndGroups(ctx, deviceId, value.ListFlows(), value.ListGroups(), flowMetadata); err != nil {
khenaidoo0458db62019-06-20 08:50:36 -04001165 log.Error("flow-update-failed", log.Fields{"deviceID": deviceId, "error": err})
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001166 response.Error(status.Errorf(codes.Internal, "flow-update-failed: %s", deviceId))
khenaidoo0458db62019-06-20 08:50:36 -04001167 }
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001168 response.Done()
npujar1d86a522019-11-14 17:11:16 +05301169 }(deviceID, value)
khenaidoo0458db62019-06-20 08:50:36 -04001170 }
khenaidoo442e7c72020-03-10 16:13:48 -04001171 return responses
khenaidoo19d7b632018-10-30 10:49:50 -04001172}
1173
1174//flowDeleteStrict deletes a flow from the flow table of that logical device
npujar467fe752020-01-16 20:17:45 +05301175func (agent *LogicalDeviceAgent) flowDeleteStrict(ctx context.Context, mod *ofp.OfpFlowMod) error {
khenaidoo19d7b632018-10-30 10:49:50 -04001176 log.Debug("flowDeleteStrict")
1177 if mod == nil {
1178 return nil
1179 }
khenaidoo442e7c72020-03-10 16:13:48 -04001180 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1181 return err
1182 }
1183 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -04001184
khenaidoo6e55d9e2019-12-12 18:26:26 -05001185 lDevice := agent.getLogicalDeviceWithoutLock()
1186
Manikkaraj kb1a10922019-07-29 12:10:34 -04001187 var meters []*ofp.OfpMeterEntry
1188 var flows []*ofp.OfpFlowStats
Esin Karamanfc3b1af2020-01-29 16:52:00 +00001189 var flowGroups []*ofp.OfpGroupEntry
Manikkaraj kb1a10922019-07-29 12:10:34 -04001190 if lDevice.Meters != nil && lDevice.Meters.Items != nil {
1191 meters = lDevice.Meters.Items
1192 }
1193 if lDevice.Flows != nil && lDevice.Flows.Items != nil {
1194 flows = lDevice.Flows.Items
1195 }
Esin Karamanfc3b1af2020-01-29 16:52:00 +00001196 if lDevice.FlowGroups != nil && lDevice.FlowGroups.Items != nil {
1197 flowGroups = lDevice.FlowGroups.Items
1198 }
Manikkaraj kb1a10922019-07-29 12:10:34 -04001199
1200 changedFlow := false
1201 changedMeter := false
Scott Bakerfdea1e32020-02-21 15:35:41 -08001202 flow, err := fu.FlowStatsEntryFromFlowModMessage(mod)
1203 if err != nil {
1204 return err
1205 }
Manikkaraj kb1a10922019-07-29 12:10:34 -04001206 flowsToDelete := make([]*ofp.OfpFlowStats, 0)
khenaidoo19d7b632018-10-30 10:49:50 -04001207 idx := fu.FindFlows(flows, flow)
1208 if idx >= 0 {
Gamze Abaka6e4ac162019-10-21 11:10:10 +00001209 changedMeter = agent.updateFlowCountOfMeterStats(mod, meters, flows[idx])
Manikkaraj kb1a10922019-07-29 12:10:34 -04001210 flowsToDelete = append(flowsToDelete, flows[idx])
khenaidoo19d7b632018-10-30 10:49:50 -04001211 flows = append(flows[:idx], flows[idx+1:]...)
Manikkaraj kb1a10922019-07-29 12:10:34 -04001212 changedFlow = true
khenaidoo19d7b632018-10-30 10:49:50 -04001213 } else {
npujar1d86a522019-11-14 17:11:16 +05301214 return fmt.Errorf("Cannot delete flow - %s", flow)
khenaidoo19d7b632018-10-30 10:49:50 -04001215 }
Manikkaraj kb1a10922019-07-29 12:10:34 -04001216 if changedMeter {
1217 //Update model
1218 metersToUpdate := &ofp.Meters{}
1219 if lDevice.Meters != nil {
1220 metersToUpdate = &ofp.Meters{Items: meters}
1221 }
npujar467fe752020-01-16 20:17:45 +05301222 if err := agent.updateLogicalDeviceMetersWithoutLock(ctx, metersToUpdate); err != nil {
npujar1d86a522019-11-14 17:11:16 +05301223 log.Errorw("db-meter-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
Manikkaraj kb1a10922019-07-29 12:10:34 -04001224 return err
1225 }
khenaidoo19d7b632018-10-30 10:49:50 -04001226
Manikkaraj kb1a10922019-07-29 12:10:34 -04001227 }
1228 if changedFlow {
1229 var flowMetadata voltha.FlowMetadata
1230 if err := agent.GetMeterConfig(flowsToDelete, meters, &flowMetadata); err != nil {
Thomas Lee Se5a44012019-11-07 20:32:24 +05301231 log.Error("meter-referred-in-flows-not-present")
Manikkaraj kb1a10922019-07-29 12:10:34 -04001232 return err
1233 }
khenaidoo820197c2020-02-13 16:35:33 -05001234 deviceRules, err := agent.flowDecomposer.DecomposeRules(ctx, agent, ofp.Flows{Items: flowsToDelete}, ofp.FlowGroups{Items: flowGroups})
1235 if err != nil {
1236 return err
1237 }
khenaidoo0458db62019-06-20 08:50:36 -04001238 log.Debugw("rules", log.Fields{"rules": deviceRules.String()})
1239
npujar467fe752020-01-16 20:17:45 +05301240 if err := agent.updateLogicalDeviceFlowsWithoutLock(ctx, &ofp.Flows{Items: flows}); err != nil {
Thomas Lee Se5a44012019-11-07 20:32:24 +05301241 log.Errorw("cannot-update-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo19d7b632018-10-30 10:49:50 -04001242 return err
1243 }
khenaidoo442e7c72020-03-10 16:13:48 -04001244
1245 // Update the devices
1246 respChnls := agent.deleteFlowsAndGroupsFromDevices(ctx, deviceRules, &flowMetadata)
1247
1248 // Wait for completion
1249 go func() {
1250 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil {
1251 log.Warnw("failure-deleting-device-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "errors": res})
1252 //TODO: Revert flow changes
1253 }
1254 }()
khenaidoo19d7b632018-10-30 10:49:50 -04001255 }
khenaidoo19d7b632018-10-30 10:49:50 -04001256 return nil
1257}
1258
1259//flowModify modifies a flow from the flow table of that logical device
1260func (agent *LogicalDeviceAgent) flowModify(mod *ofp.OfpFlowMod) error {
1261 return errors.New("flowModify not implemented")
1262}
1263
1264//flowModifyStrict deletes a flow from the flow table of that logical device
1265func (agent *LogicalDeviceAgent) flowModifyStrict(mod *ofp.OfpFlowMod) error {
1266 return errors.New("flowModifyStrict not implemented")
1267}
1268
npujar467fe752020-01-16 20:17:45 +05301269func (agent *LogicalDeviceAgent) groupAdd(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
khenaidoo19d7b632018-10-30 10:49:50 -04001270 log.Debug("groupAdd")
1271 if groupMod == nil {
1272 return nil
1273 }
khenaidoo442e7c72020-03-10 16:13:48 -04001274 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1275 return err
1276 }
1277 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -04001278
khenaidoo6e55d9e2019-12-12 18:26:26 -05001279 lDevice := agent.getLogicalDeviceWithoutLock()
1280
khenaidoo19d7b632018-10-30 10:49:50 -04001281 groups := lDevice.FlowGroups.Items
khenaidoo19d7b632018-10-30 10:49:50 -04001282 if fu.FindGroup(groups, groupMod.GroupId) == -1 {
khenaidoo68c930b2019-05-13 11:46:51 -04001283 groups = append(groups, fu.GroupEntryFromGroupMod(groupMod))
khenaidoo0458db62019-06-20 08:50:36 -04001284
Esin Karaman2ea59212019-12-06 11:41:58 +00001285 deviceRules := fu.NewDeviceRules()
1286 deviceRules.CreateEntryIfNotExist(agent.rootDeviceID)
1287 fg := fu.NewFlowsAndGroups()
1288 fg.AddGroup(fu.GroupEntryFromGroupMod(groupMod))
1289 deviceRules.AddFlowsAndGroup(agent.rootDeviceID, fg)
1290
1291 log.Debugw("rules", log.Fields{"rules for group-add": deviceRules.String()})
khenaidoo0458db62019-06-20 08:50:36 -04001292
npujar467fe752020-01-16 20:17:45 +05301293 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(ctx, &ofp.FlowGroups{Items: groups}); err != nil {
Thomas Lee Se5a44012019-11-07 20:32:24 +05301294 log.Errorw("cannot-update-group", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo19d7b632018-10-30 10:49:50 -04001295 return err
1296 }
khenaidoo442e7c72020-03-10 16:13:48 -04001297
1298 // Update the devices
1299 respChnls := agent.addFlowsAndGroupsToDevices(ctx, deviceRules, &voltha.FlowMetadata{})
1300
1301 // Wait for completion
1302 go func() {
1303 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil {
1304 log.Warnw("failure-updating-device-flows-groups", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "errors": res})
1305 //TODO: Revert flow changes
1306 }
1307 }()
1308 return nil
khenaidoo19d7b632018-10-30 10:49:50 -04001309 }
khenaidoo442e7c72020-03-10 16:13:48 -04001310 return fmt.Errorf("Groups %d already present", groupMod.GroupId)
khenaidoo19d7b632018-10-30 10:49:50 -04001311}
1312
npujar467fe752020-01-16 20:17:45 +05301313func (agent *LogicalDeviceAgent) groupDelete(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
khenaidoo19d7b632018-10-30 10:49:50 -04001314 log.Debug("groupDelete")
1315 if groupMod == nil {
1316 return nil
1317 }
khenaidoo442e7c72020-03-10 16:13:48 -04001318 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1319 return err
1320 }
1321 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -04001322
khenaidoo6e55d9e2019-12-12 18:26:26 -05001323 lDevice := agent.getLogicalDeviceWithoutLock()
khenaidoo19d7b632018-10-30 10:49:50 -04001324 groups := lDevice.FlowGroups.Items
1325 flows := lDevice.Flows.Items
npujar1d86a522019-11-14 17:11:16 +05301326 var groupsChanged bool
khenaidoo19d7b632018-10-30 10:49:50 -04001327 flowsChanged := false
npujar1d86a522019-11-14 17:11:16 +05301328 groupID := groupMod.GroupId
1329 if groupID == uint32(ofp.OfpGroup_OFPG_ALL) {
khenaidoo19d7b632018-10-30 10:49:50 -04001330 //TODO we must delete all flows that point to this group and
1331 //signal controller as requested by flow's flag
1332 groups = []*ofp.OfpGroupEntry{}
1333 groupsChanged = true
1334 } else {
npujar1d86a522019-11-14 17:11:16 +05301335 idx := fu.FindGroup(groups, groupID)
1336 if idx == -1 {
khenaidoo19d7b632018-10-30 10:49:50 -04001337 return nil // Valid case
khenaidoo19d7b632018-10-30 10:49:50 -04001338 }
npujar1d86a522019-11-14 17:11:16 +05301339 flowsChanged, flows = fu.FlowsDeleteByGroupId(flows, groupID)
1340 groups = append(groups[:idx], groups[idx+1:]...)
1341 groupsChanged = true
khenaidoo19d7b632018-10-30 10:49:50 -04001342 }
khenaidoo0458db62019-06-20 08:50:36 -04001343 if flowsChanged || groupsChanged {
khenaidoo820197c2020-02-13 16:35:33 -05001344 deviceRules, err := agent.flowDecomposer.DecomposeRules(ctx, agent, ofp.Flows{Items: flows}, ofp.FlowGroups{Items: groups})
1345 if err != nil {
1346 return err
1347 }
khenaidoo0458db62019-06-20 08:50:36 -04001348 log.Debugw("rules", log.Fields{"rules": deviceRules.String()})
1349
khenaidoo442e7c72020-03-10 16:13:48 -04001350 if groupsChanged {
1351 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(ctx, &ofp.FlowGroups{Items: groups}); err != nil {
1352 log.Errorw("cannot-update-group", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
1353 return err
1354 }
khenaidoo0458db62019-06-20 08:50:36 -04001355 }
khenaidoo442e7c72020-03-10 16:13:48 -04001356 if flowsChanged {
1357 if err := agent.updateLogicalDeviceFlowsWithoutLock(ctx, &ofp.Flows{Items: flows}); err != nil {
1358 log.Errorw("cannot-update-flow", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
1359 return err
1360 }
1361 }
khenaidoo0458db62019-06-20 08:50:36 -04001362
khenaidoo442e7c72020-03-10 16:13:48 -04001363 // Update the devices
1364 respChnls := agent.updateFlowsAndGroupsOfDevice(ctx, deviceRules, nil)
1365
1366 // Wait for completion
1367 go func() {
1368 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil {
1369 log.Warnw("failure-updating-device-flows-groups", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "errors": res})
1370 //TODO: Revert flow changes
1371 }
1372 }()
khenaidoo43c82122018-11-22 18:38:28 -05001373 }
khenaidoo19d7b632018-10-30 10:49:50 -04001374 return nil
1375}
1376
npujar467fe752020-01-16 20:17:45 +05301377func (agent *LogicalDeviceAgent) groupModify(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
khenaidoo19d7b632018-10-30 10:49:50 -04001378 log.Debug("groupModify")
1379 if groupMod == nil {
1380 return nil
1381 }
khenaidoo442e7c72020-03-10 16:13:48 -04001382 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1383 return err
1384 }
1385 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -04001386
khenaidoo6e55d9e2019-12-12 18:26:26 -05001387 lDevice := agent.getLogicalDeviceWithoutLock()
khenaidoo19d7b632018-10-30 10:49:50 -04001388 groups := lDevice.FlowGroups.Items
npujar1d86a522019-11-14 17:11:16 +05301389 var groupsChanged bool
1390 groupID := groupMod.GroupId
1391 idx := fu.FindGroup(groups, groupID)
1392 if idx == -1 {
1393 return fmt.Errorf("group-absent:%d", groupID)
khenaidoo19d7b632018-10-30 10:49:50 -04001394 }
npujar1d86a522019-11-14 17:11:16 +05301395 //replace existing group entry with new group definition
1396 groupEntry := fu.GroupEntryFromGroupMod(groupMod)
1397 groups[idx] = groupEntry
1398 groupsChanged = true
khenaidoo19d7b632018-10-30 10:49:50 -04001399 if groupsChanged {
Esin Karaman2ea59212019-12-06 11:41:58 +00001400 deviceRules := fu.NewDeviceRules()
1401 deviceRules.CreateEntryIfNotExist(agent.rootDeviceID)
1402 fg := fu.NewFlowsAndGroups()
1403 fg.AddGroup(fu.GroupEntryFromGroupMod(groupMod))
1404 deviceRules.AddFlowsAndGroup(agent.rootDeviceID, fg)
khenaidoo0458db62019-06-20 08:50:36 -04001405
Esin Karaman2ea59212019-12-06 11:41:58 +00001406 log.Debugw("rules", log.Fields{"rules for group-modify": deviceRules.String()})
khenaidoo0458db62019-06-20 08:50:36 -04001407
npujar467fe752020-01-16 20:17:45 +05301408 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(ctx, &ofp.FlowGroups{Items: groups}); err != nil {
npujar1d86a522019-11-14 17:11:16 +05301409 log.Errorw("Cannot-update-logical-group", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo19d7b632018-10-30 10:49:50 -04001410 return err
1411 }
khenaidoo442e7c72020-03-10 16:13:48 -04001412
1413 // Update the devices
1414 respChnls := agent.updateFlowsAndGroupsOfDevice(ctx, deviceRules, &voltha.FlowMetadata{})
1415
1416 // Wait for completion
1417 go func() {
1418 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil {
1419 log.Warnw("failure-updating-device-flows-groups", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "errors": res})
1420 //TODO: Revert flow changes
1421 }
1422 }()
khenaidoo19d7b632018-10-30 10:49:50 -04001423 }
1424 return nil
1425}
1426
1427// deleteLogicalPort removes the logical port
npujar467fe752020-01-16 20:17:45 +05301428func (agent *LogicalDeviceAgent) deleteLogicalPort(ctx context.Context, lPort *voltha.LogicalPort) error {
khenaidoo442e7c72020-03-10 16:13:48 -04001429 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1430 return err
1431 }
1432 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -04001433
khenaidoo6e55d9e2019-12-12 18:26:26 -05001434 logicalDevice := agent.getLogicalDeviceWithoutLock()
1435
khenaidoo92e62c52018-10-03 14:02:54 -04001436 index := -1
khenaidoo6e55d9e2019-12-12 18:26:26 -05001437 for i, logicalPort := range logicalDevice.Ports {
khenaidoo19d7b632018-10-30 10:49:50 -04001438 if logicalPort.Id == lPort.Id {
khenaidoo92e62c52018-10-03 14:02:54 -04001439 index = i
1440 break
1441 }
1442 }
1443 if index >= 0 {
khenaidoo6e55d9e2019-12-12 18:26:26 -05001444 copy(logicalDevice.Ports[index:], logicalDevice.Ports[index+1:])
1445 logicalDevice.Ports[len(logicalDevice.Ports)-1] = nil
1446 logicalDevice.Ports = logicalDevice.Ports[:len(logicalDevice.Ports)-1]
npujar1d86a522019-11-14 17:11:16 +05301447 log.Debugw("logical-port-deleted", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
npujar467fe752020-01-16 20:17:45 +05301448 if err := agent.updateLogicalDeviceWithoutLock(ctx, logicalDevice); err != nil {
npujar1d86a522019-11-14 17:11:16 +05301449 log.Errorw("logical-device-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo0a822f92019-05-08 15:15:57 -04001450 return err
1451 }
khenaidoo820197c2020-02-13 16:35:33 -05001452
1453 // Remove the logical port from cache
1454 agent.deleteLogicalPortsFromMap([]uint32{lPort.DevicePortNo})
1455
1456 // Reset the logical device routes
1457 go func() {
1458 if err := agent.buildRoutes(context.Background()); err != nil {
khenaidoo80b987d2020-02-20 10:52:52 -05001459 log.Warnw("device-routes-not-ready", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "error": err})
khenaidoo820197c2020-02-13 16:35:33 -05001460 }
1461 }()
khenaidoo92e62c52018-10-03 14:02:54 -04001462 }
1463 return nil
khenaidoob9203542018-09-17 22:56:37 -04001464}
1465
khenaidoo0a822f92019-05-08 15:15:57 -04001466// deleteLogicalPorts removes the logical ports associated with that deviceId
npujar467fe752020-01-16 20:17:45 +05301467func (agent *LogicalDeviceAgent) deleteLogicalPorts(ctx context.Context, deviceID string) error {
khenaidoo442e7c72020-03-10 16:13:48 -04001468 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1469 return err
1470 }
1471 defer agent.requestQueue.RequestComplete()
khenaidoo0a822f92019-05-08 15:15:57 -04001472
khenaidoo6e55d9e2019-12-12 18:26:26 -05001473 logicalDevice := agent.getLogicalDeviceWithoutLock()
khenaidoo820197c2020-02-13 16:35:33 -05001474 lPortstoKeep := []*voltha.LogicalPort{}
1475 lPortsNoToDelete := []uint32{}
khenaidoo6e55d9e2019-12-12 18:26:26 -05001476 for _, logicalPort := range logicalDevice.Ports {
npujar1d86a522019-11-14 17:11:16 +05301477 if logicalPort.DeviceId != deviceID {
khenaidoo820197c2020-02-13 16:35:33 -05001478 lPortstoKeep = append(lPortstoKeep, logicalPort)
1479 } else {
1480 lPortsNoToDelete = append(lPortsNoToDelete, logicalPort.DevicePortNo)
khenaidoo0a822f92019-05-08 15:15:57 -04001481 }
1482 }
khenaidoo820197c2020-02-13 16:35:33 -05001483 logicalDevice.Ports = lPortstoKeep
1484
1485 log.Debugw("updated-logical-ports", log.Fields{"ports": lPortstoKeep})
npujar467fe752020-01-16 20:17:45 +05301486 if err := agent.updateLogicalDeviceWithoutLock(ctx, logicalDevice); err != nil {
npujar1d86a522019-11-14 17:11:16 +05301487 log.Errorw("logical-device-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo0a822f92019-05-08 15:15:57 -04001488 return err
1489 }
khenaidoo820197c2020-02-13 16:35:33 -05001490 // Remove the port from the cached logical ports set
1491 agent.deleteLogicalPortsFromMap(lPortsNoToDelete)
1492
1493 // Reset the logical device routes
1494 go func() {
1495 if err := agent.buildRoutes(context.Background()); err != nil {
khenaidoo80b987d2020-02-20 10:52:52 -05001496 log.Warnw("routes-not-ready", log.Fields{"logical-device-id": agent.logicalDeviceID, "error": err})
khenaidoo820197c2020-02-13 16:35:33 -05001497 }
1498 }()
khenaidoo0a822f92019-05-08 15:15:57 -04001499
1500 return nil
1501}
1502
khenaidoo19d7b632018-10-30 10:49:50 -04001503// enableLogicalPort enables the logical port
npujar467fe752020-01-16 20:17:45 +05301504func (agent *LogicalDeviceAgent) enableLogicalPort(ctx context.Context, lPortID string) error {
khenaidoo442e7c72020-03-10 16:13:48 -04001505 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1506 return err
1507 }
1508 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -04001509
khenaidoo6e55d9e2019-12-12 18:26:26 -05001510 logicalDevice := agent.getLogicalDeviceWithoutLock()
1511
khenaidoo19d7b632018-10-30 10:49:50 -04001512 index := -1
khenaidoo6e55d9e2019-12-12 18:26:26 -05001513 for i, logicalPort := range logicalDevice.Ports {
npujar1d86a522019-11-14 17:11:16 +05301514 if logicalPort.Id == lPortID {
khenaidoo19d7b632018-10-30 10:49:50 -04001515 index = i
1516 break
1517 }
1518 }
1519 if index >= 0 {
khenaidoo6e55d9e2019-12-12 18:26:26 -05001520 logicalDevice.Ports[index].OfpPort.Config = logicalDevice.Ports[index].OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
npujar467fe752020-01-16 20:17:45 +05301521 return agent.updateLogicalDeviceWithoutLock(ctx, logicalDevice)
khenaidoo19d7b632018-10-30 10:49:50 -04001522 }
npujar1d86a522019-11-14 17:11:16 +05301523 return status.Errorf(codes.NotFound, "Port %s on Logical Device %s", lPortID, agent.logicalDeviceID)
khenaidoo19d7b632018-10-30 10:49:50 -04001524}
1525
1526// disableLogicalPort disabled the logical port
npujar467fe752020-01-16 20:17:45 +05301527func (agent *LogicalDeviceAgent) disableLogicalPort(ctx context.Context, lPortID string) error {
khenaidoo442e7c72020-03-10 16:13:48 -04001528 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1529 return err
1530 }
1531 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -04001532
1533 // Get the most up to date logical device
khenaidoo6e55d9e2019-12-12 18:26:26 -05001534 logicalDevice := agent.getLogicalDeviceWithoutLock()
khenaidoo19d7b632018-10-30 10:49:50 -04001535 index := -1
khenaidoo6e55d9e2019-12-12 18:26:26 -05001536 for i, logicalPort := range logicalDevice.Ports {
npujar1d86a522019-11-14 17:11:16 +05301537 if logicalPort.Id == lPortID {
khenaidoo19d7b632018-10-30 10:49:50 -04001538 index = i
1539 break
1540 }
1541 }
1542 if index >= 0 {
khenaidoo6e55d9e2019-12-12 18:26:26 -05001543 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 +05301544 return agent.updateLogicalDeviceWithoutLock(ctx, logicalDevice)
khenaidoo19d7b632018-10-30 10:49:50 -04001545 }
npujar1d86a522019-11-14 17:11:16 +05301546 return status.Errorf(codes.NotFound, "Port %s on Logical Device %s", lPortID, agent.logicalDeviceID)
khenaidoo19d7b632018-10-30 10:49:50 -04001547}
1548
khenaidoo820197c2020-02-13 16:35:33 -05001549func (agent *LogicalDeviceAgent) getPreCalculatedRoute(ingress, egress uint32) ([]route.Hop, error) {
1550 log.Debugw("ROUTE", log.Fields{"len": len(agent.deviceRoutes.Routes)})
1551 for routeLink, route := range agent.deviceRoutes.Routes {
khenaidoo19d7b632018-10-30 10:49:50 -04001552 log.Debugw("ROUTELINKS", log.Fields{"ingress": ingress, "egress": egress, "routelink": routeLink})
khenaidoo89b0e942018-10-21 21:11:33 -04001553 if ingress == routeLink.Ingress && egress == routeLink.Egress {
khenaidoo820197c2020-02-13 16:35:33 -05001554 return route, nil
khenaidoo89b0e942018-10-21 21:11:33 -04001555 }
1556 }
khenaidoo820197c2020-02-13 16:35:33 -05001557 return nil, status.Errorf(codes.FailedPrecondition, "no route from:%d to:%d", ingress, egress)
khenaidoo89b0e942018-10-21 21:11:33 -04001558}
1559
npujar1d86a522019-11-14 17:11:16 +05301560// GetRoute returns route
khenaidoo820197c2020-02-13 16:35:33 -05001561func (agent *LogicalDeviceAgent) GetRoute(ctx context.Context, ingressPortNo uint32, egressPortNo uint32) ([]route.Hop, error) {
khenaidoo89b0e942018-10-21 21:11:33 -04001562 log.Debugw("getting-route", log.Fields{"ingress-port": ingressPortNo, "egress-port": egressPortNo})
khenaidoo820197c2020-02-13 16:35:33 -05001563 routes := make([]route.Hop, 0)
khenaidoo2c6a0992019-04-29 13:46:56 -04001564
khenaidoo19d7b632018-10-30 10:49:50 -04001565 // Note: A port value of 0 is equivalent to a nil port
1566
khenaidoo89b0e942018-10-21 21:11:33 -04001567 // Consider different possibilities
khenaidoo19d7b632018-10-30 10:49:50 -04001568 if egressPortNo != 0 && ((egressPortNo & 0x7fffffff) == uint32(ofp.OfpPortNo_OFPP_CONTROLLER)) {
khenaidoo2c6a0992019-04-29 13:46:56 -04001569 log.Debugw("controller-flow", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "logicalPortsNo": agent.logicalPortsNo})
1570 if agent.isNNIPort(ingressPortNo) {
khenaidoo89b0e942018-10-21 21:11:33 -04001571 //This is a trap on the NNI Port
khenaidoo820197c2020-02-13 16:35:33 -05001572 if len(agent.deviceRoutes.Routes) == 0 {
khenaidoo8f474192019-04-03 17:20:44 -04001573 // 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 -04001574 // route with same IngressHop and EgressHop
khenaidoo820197c2020-02-13 16:35:33 -05001575 hop := route.Hop{DeviceID: agent.rootDeviceID, Ingress: ingressPortNo, Egress: ingressPortNo}
khenaidoo8f474192019-04-03 17:20:44 -04001576 routes = append(routes, hop)
1577 routes = append(routes, hop)
khenaidoo820197c2020-02-13 16:35:33 -05001578 return routes, nil
khenaidoo8f474192019-04-03 17:20:44 -04001579 }
khenaidoo89b0e942018-10-21 21:11:33 -04001580 //Return a 'half' route to make the flow decomposer logic happy
khenaidoo820197c2020-02-13 16:35:33 -05001581 for routeLink, path := range agent.deviceRoutes.Routes {
khenaidoo2c6a0992019-04-29 13:46:56 -04001582 if agent.isNNIPort(routeLink.Egress) {
khenaidoo820197c2020-02-13 16:35:33 -05001583 routes = append(routes, route.Hop{}) // first hop is set to empty
1584 routes = append(routes, path[1])
1585 return routes, nil
khenaidoo89b0e942018-10-21 21:11:33 -04001586 }
1587 }
khenaidoo820197c2020-02-13 16:35:33 -05001588 return nil, status.Errorf(codes.FailedPrecondition, "no upstream route from:%d to:%d", ingressPortNo, egressPortNo)
khenaidoo89b0e942018-10-21 21:11:33 -04001589 }
1590 //treat it as if the output port is the first NNI of the OLT
khenaidoo2c6a0992019-04-29 13:46:56 -04001591 var err error
1592 if egressPortNo, err = agent.getFirstNNIPort(); err != nil {
1593 log.Warnw("no-nni-port", log.Fields{"error": err})
khenaidoo820197c2020-02-13 16:35:33 -05001594 return nil, err
khenaidoo2c6a0992019-04-29 13:46:56 -04001595 }
khenaidoo89b0e942018-10-21 21:11:33 -04001596 }
1597 //If ingress port is not specified (nil), it may be a wildcarded
1598 //route if egress port is OFPP_CONTROLLER or a nni logical port,
1599 //in which case we need to create a half-route where only the egress
1600 //hop is filled, the first hop is nil
khenaidoo2c6a0992019-04-29 13:46:56 -04001601 if ingressPortNo == 0 && agent.isNNIPort(egressPortNo) {
khenaidoo89b0e942018-10-21 21:11:33 -04001602 // We can use the 2nd hop of any upstream route, so just find the first upstream:
khenaidoo820197c2020-02-13 16:35:33 -05001603 for routeLink, path := range agent.deviceRoutes.Routes {
khenaidoo2c6a0992019-04-29 13:46:56 -04001604 if agent.isNNIPort(routeLink.Egress) {
khenaidoo820197c2020-02-13 16:35:33 -05001605 routes = append(routes, route.Hop{}) // first hop is set to empty
1606 routes = append(routes, path[1])
1607 return routes, nil
khenaidoo89b0e942018-10-21 21:11:33 -04001608 }
1609 }
khenaidoo820197c2020-02-13 16:35:33 -05001610 return nil, status.Errorf(codes.FailedPrecondition, "no upstream route from:%d to:%d", ingressPortNo, egressPortNo)
khenaidoo89b0e942018-10-21 21:11:33 -04001611 }
1612 //If egress port is not specified (nil), we can also can return a "half" route
khenaidoo19d7b632018-10-30 10:49:50 -04001613 if egressPortNo == 0 {
khenaidoo820197c2020-02-13 16:35:33 -05001614 for routeLink, path := range agent.deviceRoutes.Routes {
khenaidoo19d7b632018-10-30 10:49:50 -04001615 if routeLink.Ingress == ingressPortNo {
khenaidoo820197c2020-02-13 16:35:33 -05001616 routes = append(routes, path[0])
1617 routes = append(routes, route.Hop{})
1618 return routes, nil
khenaidoo89b0e942018-10-21 21:11:33 -04001619 }
1620 }
khenaidoo820197c2020-02-13 16:35:33 -05001621 return nil, status.Errorf(codes.FailedPrecondition, "no downstream route from:%d to:%d", ingressPortNo, egressPortNo)
khenaidoo89b0e942018-10-21 21:11:33 -04001622 }
khenaidoo89b0e942018-10-21 21:11:33 -04001623 // Return the pre-calculated route
khenaidoo19d7b632018-10-30 10:49:50 -04001624 return agent.getPreCalculatedRoute(ingressPortNo, egressPortNo)
khenaidoo89b0e942018-10-21 21:11:33 -04001625}
1626
khenaidoo3d3b8c22019-05-22 18:10:39 -04001627//GetWildcardInputPorts filters out the logical port number from the set of logical ports on the device and
1628//returns their port numbers. This function is invoked only during flow decomposition where the lock on the logical
1629//device is already held. Therefore it is safe to retrieve the logical device without lock.
khenaidoo89b0e942018-10-21 21:11:33 -04001630func (agent *LogicalDeviceAgent) GetWildcardInputPorts(excludePort ...uint32) []uint32 {
1631 lPorts := make([]uint32, 0)
1632 var exclPort uint32
1633 if len(excludePort) == 1 {
1634 exclPort = excludePort[0]
1635 }
khenaidoo6e55d9e2019-12-12 18:26:26 -05001636 lDevice := agent.getLogicalDeviceWithoutLock()
1637 for _, port := range lDevice.Ports {
1638 if port.OfpPort.PortNo != exclPort {
1639 lPorts = append(lPorts, port.OfpPort.PortNo)
khenaidoo89b0e942018-10-21 21:11:33 -04001640 }
1641 }
1642 return lPorts
1643}
khenaidoo19d7b632018-10-30 10:49:50 -04001644
khenaidoo820197c2020-02-13 16:35:33 -05001645// GetDeviceRoutes returns device graph
1646func (agent *LogicalDeviceAgent) GetDeviceRoutes() *route.DeviceRoutes {
1647 return agent.deviceRoutes
khenaidoo19d7b632018-10-30 10:49:50 -04001648}
1649
khenaidoo820197c2020-02-13 16:35:33 -05001650//rebuildRoutes rebuilds the device routes
1651func (agent *LogicalDeviceAgent) buildRoutes(ctx context.Context) error {
khenaidoo442e7c72020-03-10 16:13:48 -04001652 log.Debugf("building-routes", log.Fields{"logical-device-id": agent.logicalDeviceID})
1653 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1654 return err
1655 }
1656 defer agent.requestQueue.RequestComplete()
1657
khenaidoo820197c2020-02-13 16:35:33 -05001658 if agent.deviceRoutes == nil {
1659 agent.deviceRoutes = route.NewDeviceRoutes(agent.logicalDeviceID, agent.deviceMgr.GetDevice)
khenaidoo2c6a0992019-04-29 13:46:56 -04001660 }
1661 // Get all the logical ports on that logical device
khenaidoo6e55d9e2019-12-12 18:26:26 -05001662 lDevice := agent.getLogicalDeviceWithoutLock()
1663
khenaidoo820197c2020-02-13 16:35:33 -05001664 if err := agent.deviceRoutes.ComputeRoutes(ctx, lDevice.Ports); err != nil {
1665 return err
1666 }
1667 if err := agent.deviceRoutes.Print(); err != nil {
1668 return err
1669 }
1670
khenaidoo2c6a0992019-04-29 13:46:56 -04001671 return nil
khenaidoo19d7b632018-10-30 10:49:50 -04001672}
1673
khenaidoo820197c2020-02-13 16:35:33 -05001674//updateRoutes updates the device routes
1675func (agent *LogicalDeviceAgent) updateRoutes(ctx context.Context, lp *voltha.LogicalPort) error {
1676 log.Debugw("updateRoutes", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo442e7c72020-03-10 16:13:48 -04001677 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1678 return err
1679 }
1680 defer agent.requestQueue.RequestComplete()
1681
khenaidoo820197c2020-02-13 16:35:33 -05001682 if agent.deviceRoutes == nil {
1683 agent.deviceRoutes = route.NewDeviceRoutes(agent.logicalDeviceID, agent.deviceMgr.GetDevice)
khenaidoo910204f2019-04-08 17:56:40 -04001684 }
khenaidoo820197c2020-02-13 16:35:33 -05001685 if err := agent.deviceRoutes.AddPort(ctx, lp, agent.logicalDevice.Ports); err != nil {
1686 return err
khenaidoo0a822f92019-05-08 15:15:57 -04001687 }
khenaidoo820197c2020-02-13 16:35:33 -05001688 if err := agent.deviceRoutes.Print(); err != nil {
1689 return err
1690 }
1691 return nil
khenaidoo0a822f92019-05-08 15:15:57 -04001692}
1693
khenaidoofc1314d2019-03-14 09:34:21 -04001694// 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 -04001695func diff(oldList, newList []*voltha.LogicalPort) (newPorts, changedPorts, deletedPorts []*voltha.LogicalPort) {
khenaidoofc1314d2019-03-14 09:34:21 -04001696 newPorts = make([]*voltha.LogicalPort, 0)
1697 changedPorts = make([]*voltha.LogicalPort, 0)
1698 deletedPorts = make([]*voltha.LogicalPort, 0)
1699 for _, o := range oldList {
1700 found := false
khenaidoofc1314d2019-03-14 09:34:21 -04001701 for _, n := range newList {
1702 if o.Id == n.Id {
khenaidoofc1314d2019-03-14 09:34:21 -04001703 found = true
1704 break
1705 }
1706 }
1707 if !found {
1708 deletedPorts = append(deletedPorts, o)
1709 }
khenaidoofc1314d2019-03-14 09:34:21 -04001710 }
1711 for _, n := range newList {
1712 found := false
khenaidoo2bc48282019-07-16 18:13:46 -04001713 changed := false
khenaidoofc1314d2019-03-14 09:34:21 -04001714 for _, o := range oldList {
1715 if o.Id == n.Id {
khenaidoo2bc48282019-07-16 18:13:46 -04001716 changed = !reflect.DeepEqual(o, n)
khenaidoofc1314d2019-03-14 09:34:21 -04001717 found = true
1718 break
1719 }
1720 }
1721 if !found {
1722 newPorts = append(newPorts, n)
1723 }
khenaidoo2bc48282019-07-16 18:13:46 -04001724 if changed {
1725 changedPorts = append(changedPorts, n)
1726 }
khenaidoofc1314d2019-03-14 09:34:21 -04001727 }
1728 return
1729}
1730
1731// portUpdated is invoked when a port is updated on the logical device. Until
1732// the POST_ADD notification is fixed, we will use the logical device to
1733// update that data.
npujar467fe752020-01-16 20:17:45 +05301734func (agent *LogicalDeviceAgent) portUpdated(ctx context.Context, args ...interface{}) interface{} {
khenaidoofc1314d2019-03-14 09:34:21 -04001735 log.Debugw("portUpdated-callback", log.Fields{"argsLen": len(args)})
1736
1737 var oldLD *voltha.LogicalDevice
1738 var newlD *voltha.LogicalDevice
1739
1740 var ok bool
1741 if oldLD, ok = args[0].(*voltha.LogicalDevice); !ok {
1742 log.Errorw("invalid-args", log.Fields{"args0": args[0]})
1743 return nil
1744 }
1745 if newlD, ok = args[1].(*voltha.LogicalDevice); !ok {
1746 log.Errorw("invalid-args", log.Fields{"args1": args[1]})
1747 return nil
1748 }
1749
1750 if reflect.DeepEqual(oldLD.Ports, newlD.Ports) {
1751 log.Debug("ports-have-not-changed")
1752 return nil
1753 }
1754
1755 // Get the difference between the two list
1756 newPorts, changedPorts, deletedPorts := diff(oldLD.Ports, newlD.Ports)
1757
1758 // Send the port change events to the OF controller
khenaidoo2c6a0992019-04-29 13:46:56 -04001759 for _, newP := range newPorts {
npujar1d86a522019-11-14 17:11:16 +05301760 go agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceID,
khenaidoo2c6a0992019-04-29 13:46:56 -04001761 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_ADD, Desc: newP.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001762 }
1763 for _, change := range changedPorts {
npujar1d86a522019-11-14 17:11:16 +05301764 go agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceID,
khenaidoo910204f2019-04-08 17:56:40 -04001765 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_MODIFY, Desc: change.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001766 }
1767 for _, del := range deletedPorts {
npujar1d86a522019-11-14 17:11:16 +05301768 go agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceID,
khenaidoo910204f2019-04-08 17:56:40 -04001769 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_DELETE, Desc: del.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001770 }
1771
1772 return nil
1773}
1774
khenaidoo8f474192019-04-03 17:20:44 -04001775// addNNILogicalPort adds an NNI port to the logical device. It returns a bool representing whether a port has been
1776// added and an eror in case a valid error is encountered. If the port was successfully added it will return
1777// (true, nil). If the device is not in the correct state it will return (false, nil) as this is a valid
1778// scenario. This also applies to the case where the port was already added.
npujar467fe752020-01-16 20:17:45 +05301779func (agent *LogicalDeviceAgent) addNNILogicalPort(ctx context.Context, device *voltha.Device, port *voltha.Port) (bool, error) {
khenaidoo1ce37ad2019-03-24 22:07:24 -04001780 log.Debugw("addNNILogicalPort", log.Fields{"NNI": port})
khenaidoo8f474192019-04-03 17:20:44 -04001781 if device.AdminState != voltha.AdminState_ENABLED || device.OperStatus != voltha.OperStatus_ACTIVE {
1782 log.Infow("device-not-ready", log.Fields{"deviceId": device.Id, "admin": device.AdminState, "oper": device.OperStatus})
1783 return false, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001784 }
khenaidoo442e7c72020-03-10 16:13:48 -04001785 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1786 return false, err
1787 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001788 if agent.portExist(device, port) {
1789 log.Debugw("port-already-exist", log.Fields{"port": port})
khenaidoo442e7c72020-03-10 16:13:48 -04001790 agent.requestQueue.RequestComplete()
khenaidoo8f474192019-04-03 17:20:44 -04001791 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001792 }
khenaidoo442e7c72020-03-10 16:13:48 -04001793 agent.requestQueue.RequestComplete()
khenaidoo1ce37ad2019-03-24 22:07:24 -04001794
khenaidoofc1314d2019-03-14 09:34:21 -04001795 var portCap *ic.PortCapability
1796 var err error
1797 // First get the port capability
npujar467fe752020-01-16 20:17:45 +05301798 if portCap, err = agent.deviceMgr.getPortCapability(ctx, device.Id, port.PortNo); err != nil {
khenaidoofc1314d2019-03-14 09:34:21 -04001799 log.Errorw("error-retrieving-port-capabilities", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001800 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001801 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001802
khenaidoo442e7c72020-03-10 16:13:48 -04001803 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1804 return false, err
1805 }
1806
1807 defer agent.requestQueue.RequestComplete()
khenaidoo1ce37ad2019-03-24 22:07:24 -04001808 // Double check again if this port has been already added since the getPortCapability could have taken a long time
1809 if agent.portExist(device, port) {
1810 log.Debugw("port-already-exist", log.Fields{"port": port})
khenaidoo8f474192019-04-03 17:20:44 -04001811 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001812 }
1813
khenaidoofc1314d2019-03-14 09:34:21 -04001814 portCap.Port.RootPort = true
1815 lp := (proto.Clone(portCap.Port)).(*voltha.LogicalPort)
1816 lp.DeviceId = device.Id
1817 lp.Id = fmt.Sprintf("nni-%d", port.PortNo)
1818 lp.OfpPort.PortNo = port.PortNo
1819 lp.OfpPort.Name = lp.Id
1820 lp.DevicePortNo = port.PortNo
1821
khenaidoo6e55d9e2019-12-12 18:26:26 -05001822 ld := agent.getLogicalDeviceWithoutLock()
1823
khenaidoofc1314d2019-03-14 09:34:21 -04001824 cloned := (proto.Clone(ld)).(*voltha.LogicalDevice)
1825 if cloned.Ports == nil {
1826 cloned.Ports = make([]*voltha.LogicalPort, 0)
1827 }
1828 cloned.Ports = append(cloned.Ports, lp)
1829
npujar467fe752020-01-16 20:17:45 +05301830 if err = agent.updateLogicalDeviceWithoutLock(ctx, cloned); err != nil {
khenaidoofc1314d2019-03-14 09:34:21 -04001831 log.Errorw("error-updating-logical-device", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001832 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001833 }
khenaidoo910204f2019-04-08 17:56:40 -04001834
khenaidoo820197c2020-02-13 16:35:33 -05001835 // Update the device routes with this new logical port
khenaidoo910204f2019-04-08 17:56:40 -04001836 clonedLP := (proto.Clone(lp)).(*voltha.LogicalPort)
khenaidoo820197c2020-02-13 16:35:33 -05001837 go func() {
1838 if err := agent.updateRoutes(context.Background(), clonedLP); err != nil {
khenaidoo442e7c72020-03-10 16:13:48 -04001839 log.Warnw("routes-not-ready", log.Fields{"logical-device-id": agent.logicalDeviceID, "logical-port": lp.OfpPort.PortNo, "error": err})
khenaidoo820197c2020-02-13 16:35:33 -05001840 }
1841 }()
khenaidoo910204f2019-04-08 17:56:40 -04001842
khenaidoo8f474192019-04-03 17:20:44 -04001843 return true, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001844}
1845
khenaidoo910204f2019-04-08 17:56:40 -04001846func (agent *LogicalDeviceAgent) portExist(device *voltha.Device, port *voltha.Port) bool {
khenaidoo6e55d9e2019-12-12 18:26:26 -05001847 ldevice := agent.getLogicalDeviceWithoutLock()
1848 for _, lPort := range ldevice.Ports {
1849 if lPort.DeviceId == device.Id && lPort.DevicePortNo == port.PortNo && lPort.Id == port.Label {
1850 return true
khenaidoofc1314d2019-03-14 09:34:21 -04001851 }
1852 }
1853 return false
1854}
1855
khenaidoo8f474192019-04-03 17:20:44 -04001856// addUNILogicalPort adds an UNI port to the logical device. It returns a bool representing whether a port has been
1857// added and an eror in case a valid error is encountered. If the port was successfully added it will return
1858// (true, nil). If the device is not in the correct state it will return (false, nil) as this is a valid
1859// scenario. This also applies to the case where the port was already added.
npujar467fe752020-01-16 20:17:45 +05301860func (agent *LogicalDeviceAgent) addUNILogicalPort(ctx context.Context, childDevice *voltha.Device, port *voltha.Port) (bool, error) {
khenaidoofc1314d2019-03-14 09:34:21 -04001861 log.Debugw("addUNILogicalPort", log.Fields{"port": port})
khenaidoo8f474192019-04-03 17:20:44 -04001862 if childDevice.AdminState != voltha.AdminState_ENABLED || childDevice.OperStatus != voltha.OperStatus_ACTIVE {
1863 log.Infow("device-not-ready", log.Fields{"deviceId": childDevice.Id, "admin": childDevice.AdminState, "oper": childDevice.OperStatus})
1864 return false, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001865 }
khenaidoo442e7c72020-03-10 16:13:48 -04001866 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1867 return false, err
1868 }
1869
khenaidoo1ce37ad2019-03-24 22:07:24 -04001870 if agent.portExist(childDevice, port) {
1871 log.Debugw("port-already-exist", log.Fields{"port": port})
khenaidoo442e7c72020-03-10 16:13:48 -04001872 agent.requestQueue.RequestComplete()
khenaidoo8f474192019-04-03 17:20:44 -04001873 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001874 }
khenaidoo442e7c72020-03-10 16:13:48 -04001875 agent.requestQueue.RequestComplete()
khenaidoofc1314d2019-03-14 09:34:21 -04001876 var portCap *ic.PortCapability
1877 var err error
1878 // First get the port capability
npujar467fe752020-01-16 20:17:45 +05301879 if portCap, err = agent.deviceMgr.getPortCapability(ctx, childDevice.Id, port.PortNo); err != nil {
khenaidoofc1314d2019-03-14 09:34:21 -04001880 log.Errorw("error-retrieving-port-capabilities", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001881 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001882 }
khenaidoo442e7c72020-03-10 16:13:48 -04001883 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1884 return false, err
1885 }
1886 defer agent.requestQueue.RequestComplete()
khenaidoo1ce37ad2019-03-24 22:07:24 -04001887 // Double check again if this port has been already added since the getPortCapability could have taken a long time
1888 if agent.portExist(childDevice, port) {
1889 log.Debugw("port-already-exist", log.Fields{"port": port})
khenaidoo8f474192019-04-03 17:20:44 -04001890 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001891 }
khenaidoofc1314d2019-03-14 09:34:21 -04001892 // Get stored logical device
khenaidoo6e55d9e2019-12-12 18:26:26 -05001893 ldevice := agent.getLogicalDeviceWithoutLock()
1894
npujar1d86a522019-11-14 17:11:16 +05301895 log.Debugw("adding-uni", log.Fields{"deviceId": childDevice.Id})
1896 portCap.Port.RootPort = false
1897 portCap.Port.Id = port.Label
1898 portCap.Port.OfpPort.PortNo = port.PortNo
1899 portCap.Port.DeviceId = childDevice.Id
1900 portCap.Port.DevicePortNo = port.PortNo
1901 cloned := (proto.Clone(ldevice)).(*voltha.LogicalDevice)
1902 if cloned.Ports == nil {
1903 cloned.Ports = make([]*voltha.LogicalPort, 0)
1904 }
1905 cloned.Ports = append(cloned.Ports, portCap.Port)
npujar467fe752020-01-16 20:17:45 +05301906 if err := agent.updateLogicalDeviceWithoutLock(ctx, cloned); err != nil {
npujar1d86a522019-11-14 17:11:16 +05301907 return false, err
1908 }
1909 // Update the device graph with this new logical port
1910 clonedLP := (proto.Clone(portCap.Port)).(*voltha.LogicalPort)
khenaidoo820197c2020-02-13 16:35:33 -05001911
1912 go func() {
1913 if err := agent.updateRoutes(context.Background(), clonedLP); err != nil {
1914 log.Warn("routes-not-ready", log.Fields{"logical-device-id": agent.logicalDeviceID, "error": err})
1915 }
1916 }()
1917
npujar1d86a522019-11-14 17:11:16 +05301918 return true, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001919}
1920
npujar467fe752020-01-16 20:17:45 +05301921func (agent *LogicalDeviceAgent) packetOut(ctx context.Context, packet *ofp.OfpPacketOut) {
Matteo Scandolo360605d2019-11-05 18:29:17 -08001922 log.Debugw("packet-out", log.Fields{
1923 "packet": hex.EncodeToString(packet.Data),
1924 "inPort": packet.GetInPort(),
1925 })
khenaidoo68c930b2019-05-13 11:46:51 -04001926 outPort := fu.GetPacketOutPort(packet)
khenaidoofdbad6e2018-11-06 22:26:38 -05001927 //frame := packet.GetData()
1928 //TODO: Use a channel between the logical agent and the device agent
npujar467fe752020-01-16 20:17:45 +05301929 if err := agent.deviceMgr.packetOut(ctx, agent.rootDeviceID, outPort, packet); err != nil {
npujar1d86a522019-11-14 17:11:16 +05301930 log.Error("packetout-failed", log.Fields{"logicalDeviceID": agent.rootDeviceID})
khenaidooca301322019-01-09 23:06:32 -05001931 }
khenaidoofdbad6e2018-11-06 22:26:38 -05001932}
1933
npujar1d86a522019-11-14 17:11:16 +05301934func (agent *LogicalDeviceAgent) packetIn(port uint32, transactionID string, packet []byte) {
Matteo Scandolo360605d2019-11-05 18:29:17 -08001935 log.Debugw("packet-in", log.Fields{
1936 "port": port,
1937 "packet": hex.EncodeToString(packet),
npujar1d86a522019-11-14 17:11:16 +05301938 "transactionId": transactionID,
Matteo Scandolo360605d2019-11-05 18:29:17 -08001939 })
khenaidoo68c930b2019-05-13 11:46:51 -04001940 packetIn := fu.MkPacketIn(port, packet)
npujar1d86a522019-11-14 17:11:16 +05301941 agent.ldeviceMgr.grpcNbiHdlr.sendPacketIn(agent.logicalDeviceID, transactionID, packetIn)
Matteo Scandolo360605d2019-11-05 18:29:17 -08001942 log.Debugw("sending-packet-in", log.Fields{"packet": hex.EncodeToString(packetIn.Data)})
khenaidoofdbad6e2018-11-06 22:26:38 -05001943}
khenaidoo2c6a0992019-04-29 13:46:56 -04001944
1945func (agent *LogicalDeviceAgent) addLogicalPortToMap(portNo uint32, nniPort bool) {
1946 agent.lockLogicalPortsNo.Lock()
1947 defer agent.lockLogicalPortsNo.Unlock()
1948 if exist := agent.logicalPortsNo[portNo]; !exist {
1949 agent.logicalPortsNo[portNo] = nniPort
1950 }
1951}
1952
khenaidoo820197c2020-02-13 16:35:33 -05001953func (agent *LogicalDeviceAgent) deleteLogicalPortsFromMap(portsNo []uint32) {
1954 agent.lockLogicalPortsNo.Lock()
1955 defer agent.lockLogicalPortsNo.Unlock()
1956 for _, pNo := range portsNo {
1957 delete(agent.logicalPortsNo, pNo)
1958 }
1959}
1960
khenaidoo3d3b8c22019-05-22 18:10:39 -04001961func (agent *LogicalDeviceAgent) addLogicalPortsToMap(lps []*voltha.LogicalPort) {
1962 agent.lockLogicalPortsNo.Lock()
1963 defer agent.lockLogicalPortsNo.Unlock()
1964 for _, lp := range lps {
1965 if exist := agent.logicalPortsNo[lp.DevicePortNo]; !exist {
1966 agent.logicalPortsNo[lp.DevicePortNo] = lp.RootPort
1967 }
1968 }
1969}
1970
khenaidoo2c6a0992019-04-29 13:46:56 -04001971func (agent *LogicalDeviceAgent) isNNIPort(portNo uint32) bool {
1972 agent.lockLogicalPortsNo.RLock()
1973 defer agent.lockLogicalPortsNo.RUnlock()
1974 if exist := agent.logicalPortsNo[portNo]; exist {
1975 return agent.logicalPortsNo[portNo]
1976 }
1977 return false
1978}
1979
1980func (agent *LogicalDeviceAgent) getFirstNNIPort() (uint32, error) {
1981 agent.lockLogicalPortsNo.RLock()
1982 defer agent.lockLogicalPortsNo.RUnlock()
1983 for portNo, nni := range agent.logicalPortsNo {
1984 if nni {
1985 return portNo, nil
1986 }
1987 }
1988 return 0, status.Error(codes.NotFound, "No NNI port found")
1989}
Esin Karaman09959ae2019-11-29 13:59:58 +00001990
1991//GetNNIPorts returns NNI ports.
1992func (agent *LogicalDeviceAgent) GetNNIPorts() []uint32 {
1993 agent.lockLogicalPortsNo.RLock()
1994 defer agent.lockLogicalPortsNo.RUnlock()
1995 nniPorts := make([]uint32, 0)
1996 for portNo, nni := range agent.logicalPortsNo {
1997 if nni {
1998 nniPorts = append(nniPorts, portNo)
1999 }
2000 }
2001 return nniPorts
2002}