blob: fe379d656c5d754ef439b2d4132cb8996b7c5dcd [file] [log] [blame]
khenaidoob9203542018-09-17 22:56:37 -04001/*
2 * Copyright 2018-present Open Networking Foundation
3
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7
8 * http://www.apache.org/licenses/LICENSE-2.0
9
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
npujar1d86a522019-11-14 17:11:16 +053016
Kent Hagerman2b216042020-04-03 18:28:56 -040017package device
khenaidoob9203542018-09-17 22:56:37 -040018
19import (
20 "context"
Matteo Scandolo360605d2019-11-05 18:29:17 -080021 "encoding/hex"
Kent Hagerman4f355f52020-03-30 16:01:33 -040022 "errors"
khenaidoo3ab34882019-05-02 21:33:30 -040023 "fmt"
Mahir Gunyeladdb66a2020-04-29 18:08:50 -070024 "reflect"
Mahir Gunyel03de0d32020-06-03 01:36:59 -070025 "strconv"
Mahir Gunyeladdb66a2020-04-29 18:08:50 -070026 "sync"
27 "time"
28
khenaidoo442e7c72020-03-10 16:13:48 -040029 "github.com/golang/protobuf/ptypes"
Kent Hagerman2b216042020-04-03 18:28:56 -040030 "github.com/opencord/voltha-go/rw_core/core/adapter"
Mahir Gunyel03de0d32020-06-03 01:36:59 -070031 "github.com/opencord/voltha-go/rw_core/core/device/flow"
32 "github.com/opencord/voltha-go/rw_core/core/device/group"
Kent Hagerman2b216042020-04-03 18:28:56 -040033 "github.com/opencord/voltha-go/rw_core/core/device/remote"
Mahir Gunyel03de0d32020-06-03 01:36:59 -070034 fu "github.com/opencord/voltha-lib-go/v3/pkg/flows"
khenaidoo442e7c72020-03-10 16:13:48 -040035 "github.com/opencord/voltha-lib-go/v3/pkg/kafka"
Chaitrashree G Sa773e992019-09-09 21:04:15 -040036
khenaidoob9203542018-09-17 22:56:37 -040037 "github.com/gogo/protobuf/proto"
sbarbari17d7e222019-11-05 10:02:29 -050038 "github.com/opencord/voltha-go/db/model"
Scott Bakerb671a862019-10-24 10:53:40 -070039 coreutils "github.com/opencord/voltha-go/rw_core/utils"
serkant.uluderya2ae470f2020-01-21 11:13:09 -080040 "github.com/opencord/voltha-lib-go/v3/pkg/log"
41 ic "github.com/opencord/voltha-protos/v3/go/inter_container"
42 ofp "github.com/opencord/voltha-protos/v3/go/openflow_13"
43 "github.com/opencord/voltha-protos/v3/go/voltha"
khenaidoob9203542018-09-17 22:56:37 -040044 "google.golang.org/grpc/codes"
45 "google.golang.org/grpc/status"
khenaidoob9203542018-09-17 22:56:37 -040046)
47
Kent Hagerman2b216042020-04-03 18:28:56 -040048// Agent represents device agent attributes
49type Agent struct {
Kent Hagermanf5a67352020-04-30 15:15:26 -040050 deviceID string
51 parentID string
52 deviceType string
53 isRootdevice bool
54 adapterProxy *remote.AdapterProxy
55 adapterMgr *adapter.Manager
56 deviceMgr *Manager
57 dbProxy *model.Proxy
58 exitChannel chan int
59 device *voltha.Device
60 requestQueue *coreutils.RequestQueue
61 defaultTimeout time.Duration
62 startOnce sync.Once
63 stopOnce sync.Once
64 stopped bool
Mahir Gunyel03de0d32020-06-03 01:36:59 -070065
66 flowLoader *flow.Loader
67 groupLoader *group.Loader
khenaidoob9203542018-09-17 22:56:37 -040068}
69
Kent Hagerman2b216042020-04-03 18:28:56 -040070//newAgent creates a new device agent. The device will be initialized when start() is called.
Mahir Gunyel03de0d32020-06-03 01:36:59 -070071func newAgent(ap *remote.AdapterProxy, device *voltha.Device, deviceMgr *Manager, dbProxy *model.Path, deviceProxy *model.Proxy, timeout time.Duration) *Agent {
Kent Hagerman2b216042020-04-03 18:28:56 -040072 var agent Agent
khenaidoob9203542018-09-17 22:56:37 -040073 agent.adapterProxy = ap
Scott Baker80678602019-11-14 16:57:36 -080074 if device.Id == "" {
Kent Hagerman2b216042020-04-03 18:28:56 -040075 agent.deviceID = coreutils.CreateDeviceID()
Scott Baker80678602019-11-14 16:57:36 -080076 } else {
npujar1d86a522019-11-14 17:11:16 +053077 agent.deviceID = device.Id
Stephane Barbarie1ab43272018-12-08 21:42:13 -050078 }
Scott Baker80678602019-11-14 16:57:36 -080079
khenaidoo2c6a0992019-04-29 13:46:56 -040080 agent.isRootdevice = device.Root
npujar1d86a522019-11-14 17:11:16 +053081 agent.parentID = device.ParentId
Scott Baker80678602019-11-14 16:57:36 -080082 agent.deviceType = device.Type
khenaidoob9203542018-09-17 22:56:37 -040083 agent.deviceMgr = deviceMgr
khenaidoo21d51152019-02-01 13:48:37 -050084 agent.adapterMgr = deviceMgr.adapterMgr
khenaidoob9203542018-09-17 22:56:37 -040085 agent.exitChannel = make(chan int, 1)
Kent Hagermanf5a67352020-04-30 15:15:26 -040086 agent.dbProxy = deviceProxy
khenaidoo2c6a0992019-04-29 13:46:56 -040087 agent.defaultTimeout = timeout
khenaidoo6e55d9e2019-12-12 18:26:26 -050088 agent.device = proto.Clone(device).(*voltha.Device)
Kent Hagerman730cbdf2020-03-31 12:22:08 -040089 agent.requestQueue = coreutils.NewRequestQueue()
Mahir Gunyel03de0d32020-06-03 01:36:59 -070090 agent.flowLoader = flow.NewLoader(dbProxy.SubPath("flows").Proxy(device.Id))
91 agent.groupLoader = group.NewLoader(dbProxy.SubPath("groups").Proxy(device.Id))
92
khenaidoob9203542018-09-17 22:56:37 -040093 return &agent
94}
95
khenaidoo442e7c72020-03-10 16:13:48 -040096// start() saves the device to the data model and registers for callbacks on that device if deviceToCreate!=nil.
97// Otherwise, it will load the data from the dB and setup the necessary callbacks and proxies. Returns the device that
Scott Baker80678602019-11-14 16:57:36 -080098// was started.
Kent Hagerman2b216042020-04-03 18:28:56 -040099func (agent *Agent) start(ctx context.Context, deviceToCreate *voltha.Device) (*voltha.Device, error) {
khenaidoo442e7c72020-03-10 16:13:48 -0400100 needToStart := false
101 if agent.startOnce.Do(func() { needToStart = true }); !needToStart {
102 return agent.getDevice(ctx)
103 }
104 var startSucceeded bool
105 defer func() {
106 if !startSucceeded {
107 if err := agent.stop(ctx); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000108 logger.Errorw("failed-to-cleanup-after-unsuccessful-start", log.Fields{"device-id": agent.deviceID, "error": err})
khenaidoo442e7c72020-03-10 16:13:48 -0400109 }
110 }
111 }()
Scott Baker80678602019-11-14 16:57:36 -0800112
khenaidoo442e7c72020-03-10 16:13:48 -0400113 var device *voltha.Device
Scott Baker80678602019-11-14 16:57:36 -0800114 if deviceToCreate == nil {
115 // Load the existing device
Kent Hagerman4f355f52020-03-30 16:01:33 -0400116 device := &voltha.Device{}
Kent Hagermanf5a67352020-04-30 15:15:26 -0400117 have, err := agent.dbProxy.Get(ctx, agent.deviceID, device)
Thomas Lee Se5a44012019-11-07 20:32:24 +0530118 if err != nil {
Thomas Lee Se5a44012019-11-07 20:32:24 +0530119 return nil, err
Kent Hagerman4f355f52020-03-30 16:01:33 -0400120 } else if !have {
121 return nil, status.Errorf(codes.NotFound, "device-%s", agent.deviceID)
Thomas Lee Se5a44012019-11-07 20:32:24 +0530122 }
Kent Hagerman4f355f52020-03-30 16:01:33 -0400123
124 agent.deviceType = device.Adapter
125 agent.device = proto.Clone(device).(*voltha.Device)
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700126 // load the flows and groups from KV to cache
127 agent.flowLoader.Load(ctx)
128 agent.groupLoader.Load(ctx)
Kent Hagerman4f355f52020-03-30 16:01:33 -0400129
Girish Kumarf56a4682020-03-20 20:07:46 +0000130 logger.Infow("device-loaded-from-dB", log.Fields{"device-id": agent.deviceID})
khenaidoo297cd252019-02-07 22:10:23 -0500131 } else {
Scott Baker80678602019-11-14 16:57:36 -0800132 // Create a new device
Kent Hagermanf5a67352020-04-30 15:15:26 -0400133 // Assumption is that AdminState, FlowGroups, and Flows are uninitialized since this
134 // is a new device, so populate them here before passing the device to ldProxy.Set.
Kent Hagerman2b216042020-04-03 18:28:56 -0400135 // agent.deviceId will also have been set during newAgent().
Scott Baker80678602019-11-14 16:57:36 -0800136 device = (proto.Clone(deviceToCreate)).(*voltha.Device)
npujar1d86a522019-11-14 17:11:16 +0530137 device.Id = agent.deviceID
Scott Baker80678602019-11-14 16:57:36 -0800138 device.AdminState = voltha.AdminState_PREPROVISIONED
139 device.FlowGroups = &ofp.FlowGroups{Items: nil}
140 device.Flows = &ofp.Flows{Items: nil}
141 if !deviceToCreate.GetRoot() && deviceToCreate.ProxyAddress != nil {
142 // Set the default vlan ID to the one specified by the parent adapter. It can be
143 // overwritten by the child adapter during a device update request
144 device.Vlan = deviceToCreate.ProxyAddress.ChannelId
145 }
146
khenaidoo297cd252019-02-07 22:10:23 -0500147 // Add the initial device to the local model
Kent Hagermanf5a67352020-04-30 15:15:26 -0400148 if err := agent.dbProxy.Set(ctx, agent.deviceID, device); err != nil {
Kent Hagerman4f355f52020-03-30 16:01:33 -0400149 return nil, status.Errorf(codes.Aborted, "failed-adding-device-%s: %s", agent.deviceID, err)
khenaidoo297cd252019-02-07 22:10:23 -0500150 }
khenaidoo442e7c72020-03-10 16:13:48 -0400151 agent.device = device
khenaidoob9203542018-09-17 22:56:37 -0400152 }
khenaidoo442e7c72020-03-10 16:13:48 -0400153 startSucceeded = true
Girish Kumarf56a4682020-03-20 20:07:46 +0000154 logger.Debugw("device-agent-started", log.Fields{"device-id": agent.deviceID})
khenaidoo442e7c72020-03-10 16:13:48 -0400155
156 return agent.getDevice(ctx)
khenaidoob9203542018-09-17 22:56:37 -0400157}
158
khenaidoo4d4802d2018-10-04 21:59:49 -0400159// stop stops the device agent. Not much to do for now
Kent Hagerman2b216042020-04-03 18:28:56 -0400160func (agent *Agent) stop(ctx context.Context) error {
khenaidoo442e7c72020-03-10 16:13:48 -0400161 needToStop := false
162 if agent.stopOnce.Do(func() { needToStop = true }); !needToStop {
163 return nil
164 }
165 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
166 return err
167 }
168 defer agent.requestQueue.RequestComplete()
khenaidoo49085352020-01-13 19:15:43 -0500169
Girish Kumarf56a4682020-03-20 20:07:46 +0000170 logger.Infow("stopping-device-agent", log.Fields{"deviceId": agent.deviceID, "parentId": agent.parentID})
khenaidoo6e55d9e2019-12-12 18:26:26 -0500171
khenaidoo0a822f92019-05-08 15:15:57 -0400172 // Remove the device from the KV store
Kent Hagermanf5a67352020-04-30 15:15:26 -0400173 if err := agent.dbProxy.Remove(ctx, agent.deviceID); err != nil {
khenaidoo442e7c72020-03-10 16:13:48 -0400174 return err
Thomas Lee Se5a44012019-11-07 20:32:24 +0530175 }
khenaidoo442e7c72020-03-10 16:13:48 -0400176
khenaidoo442e7c72020-03-10 16:13:48 -0400177 close(agent.exitChannel)
178
179 agent.stopped = true
180
Girish Kumarf56a4682020-03-20 20:07:46 +0000181 logger.Infow("device-agent-stopped", log.Fields{"device-id": agent.deviceID, "parent-id": agent.parentID})
khenaidoo442e7c72020-03-10 16:13:48 -0400182
183 return nil
khenaidoob9203542018-09-17 22:56:37 -0400184}
185
Scott Baker80678602019-11-14 16:57:36 -0800186// Load the most recent state from the KVStore for the device.
Kent Hagerman2b216042020-04-03 18:28:56 -0400187func (agent *Agent) reconcileWithKVStore(ctx context.Context) {
khenaidoo442e7c72020-03-10 16:13:48 -0400188 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000189 logger.Warnw("request-aborted", log.Fields{"device-id": agent.deviceID, "error": err})
khenaidoo442e7c72020-03-10 16:13:48 -0400190 return
191 }
192 defer agent.requestQueue.RequestComplete()
Girish Kumarf56a4682020-03-20 20:07:46 +0000193 logger.Debug("reconciling-device-agent-devicetype")
Scott Baker80678602019-11-14 16:57:36 -0800194 // TODO: context timeout
Kent Hagerman4f355f52020-03-30 16:01:33 -0400195 device := &voltha.Device{}
Kent Hagermanf5a67352020-04-30 15:15:26 -0400196 if have, err := agent.dbProxy.Get(ctx, agent.deviceID, device); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000197 logger.Errorw("kv-get-failed", log.Fields{"device-id": agent.deviceID, "error": err})
Thomas Lee Se5a44012019-11-07 20:32:24 +0530198 return
Kent Hagerman4f355f52020-03-30 16:01:33 -0400199 } else if !have {
200 return // not found in kv
Thomas Lee Se5a44012019-11-07 20:32:24 +0530201 }
Kent Hagerman4f355f52020-03-30 16:01:33 -0400202
203 agent.deviceType = device.Adapter
204 agent.device = device
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700205 agent.flowLoader.Load(ctx)
206 agent.groupLoader.Load(ctx)
Kent Hagerman4f355f52020-03-30 16:01:33 -0400207 logger.Debugw("reconciled-device-agent-devicetype", log.Fields{"device-id": agent.deviceID, "type": agent.deviceType})
Scott Baker80678602019-11-14 16:57:36 -0800208}
209
khenaidoo442e7c72020-03-10 16:13:48 -0400210// onSuccess is a common callback for scenarios where we receive a nil response following a request to an adapter
211// and the only action required is to publish a successful result on kafka
Kent Hagerman2b216042020-04-03 18:28:56 -0400212func (agent *Agent) onSuccess(rpc string, response interface{}, reqArgs ...interface{}) {
Girish Kumarf56a4682020-03-20 20:07:46 +0000213 logger.Debugw("response successful", log.Fields{"rpc": rpc, "device-id": agent.deviceID})
khenaidoo442e7c72020-03-10 16:13:48 -0400214 // TODO: Post success message onto kafka
215}
216
217// onFailure is a common callback for scenarios where we receive an error response following a request to an adapter
218// and the only action required is to publish the failed result on kafka
Kent Hagerman2b216042020-04-03 18:28:56 -0400219func (agent *Agent) onFailure(rpc string, response interface{}, reqArgs ...interface{}) {
khenaidoo442e7c72020-03-10 16:13:48 -0400220 if res, ok := response.(error); ok {
Girish Kumarf56a4682020-03-20 20:07:46 +0000221 logger.Errorw("rpc-failed", log.Fields{"rpc": rpc, "device-id": agent.deviceID, "error": res, "args": reqArgs})
khenaidoo442e7c72020-03-10 16:13:48 -0400222 } else {
Girish Kumarf56a4682020-03-20 20:07:46 +0000223 logger.Errorw("rpc-failed-invalid-error", log.Fields{"rpc": rpc, "device-id": agent.deviceID, "args": reqArgs})
khenaidoo442e7c72020-03-10 16:13:48 -0400224 }
225 // TODO: Post failure message onto kafka
226}
227
Kent Hagerman2b216042020-04-03 18:28:56 -0400228func (agent *Agent) waitForAdapterResponse(ctx context.Context, cancel context.CancelFunc, rpc string, ch chan *kafka.RpcResponse,
khenaidoo442e7c72020-03-10 16:13:48 -0400229 onSuccess coreutils.ResponseCallback, onFailure coreutils.ResponseCallback, reqArgs ...interface{}) {
230 defer cancel()
231 select {
232 case rpcResponse, ok := <-ch:
233 if !ok {
234 onFailure(rpc, status.Errorf(codes.Aborted, "channel-closed"), reqArgs)
235 } else if rpcResponse.Err != nil {
236 onFailure(rpc, rpcResponse.Err, reqArgs)
237 } else {
238 onSuccess(rpc, rpcResponse.Reply, reqArgs)
239 }
240 case <-ctx.Done():
241 onFailure(rpc, ctx.Err(), reqArgs)
242 }
243}
244
khenaidoo6e55d9e2019-12-12 18:26:26 -0500245// getDevice returns the device data from cache
Kent Hagerman2b216042020-04-03 18:28:56 -0400246func (agent *Agent) getDevice(ctx context.Context) (*voltha.Device, error) {
khenaidoo442e7c72020-03-10 16:13:48 -0400247 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
248 return nil, err
249 }
250 defer agent.requestQueue.RequestComplete()
251 return proto.Clone(agent.device).(*voltha.Device), nil
khenaidoo92e62c52018-10-03 14:02:54 -0400252}
253
khenaidoo4d4802d2018-10-04 21:59:49 -0400254// getDeviceWithoutLock is a helper function to be used ONLY by any device agent function AFTER it has acquired the device lock.
Kent Hagerman2b216042020-04-03 18:28:56 -0400255func (agent *Agent) getDeviceWithoutLock() *voltha.Device {
khenaidoo0db4c812020-05-27 15:27:30 -0400256 return agent.device
khenaidoo92e62c52018-10-03 14:02:54 -0400257}
258
khenaidoo3ab34882019-05-02 21:33:30 -0400259// enableDevice activates a preprovisioned or a disable device
Kent Hagerman2b216042020-04-03 18:28:56 -0400260func (agent *Agent) enableDevice(ctx context.Context) error {
khenaidoo442e7c72020-03-10 16:13:48 -0400261 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
262 return err
263 }
264 defer agent.requestQueue.RequestComplete()
265
Girish Kumarf56a4682020-03-20 20:07:46 +0000266 logger.Debugw("enableDevice", log.Fields{"device-id": agent.deviceID})
khenaidoo21d51152019-02-01 13:48:37 -0500267
khenaidoo6e55d9e2019-12-12 18:26:26 -0500268 cloned := agent.getDeviceWithoutLock()
269
npujar1d86a522019-11-14 17:11:16 +0530270 // First figure out which adapter will handle this device type. We do it at this stage as allow devices to be
khenaidoo442e7c72020-03-10 16:13:48 -0400271 // pre-provisioned with the required adapter not registered. At this stage, since we need to communicate
npujar1d86a522019-11-14 17:11:16 +0530272 // with the adapter then we need to know the adapter that will handle this request
Kent Hagerman2b216042020-04-03 18:28:56 -0400273 adapterName, err := agent.adapterMgr.GetAdapterType(cloned.Type)
npujar1d86a522019-11-14 17:11:16 +0530274 if err != nil {
npujar1d86a522019-11-14 17:11:16 +0530275 return err
276 }
khenaidoo6e55d9e2019-12-12 18:26:26 -0500277 cloned.Adapter = adapterName
npujar1d86a522019-11-14 17:11:16 +0530278
khenaidoo6e55d9e2019-12-12 18:26:26 -0500279 if cloned.AdminState == voltha.AdminState_ENABLED {
Matteo Scandolod525ae32020-04-02 17:27:29 -0700280 logger.Warnw("device-already-enabled", log.Fields{"device-id": agent.deviceID})
281 err = status.Error(codes.FailedPrecondition, fmt.Sprintf("cannot-enable-an-already-enabled-device: %s ", cloned.Id))
282 return err
npujar1d86a522019-11-14 17:11:16 +0530283 }
284
khenaidoo6e55d9e2019-12-12 18:26:26 -0500285 if cloned.AdminState == voltha.AdminState_DELETED {
npujar1d86a522019-11-14 17:11:16 +0530286 // This is a temporary state when a device is deleted before it gets removed from the model.
khenaidoo6e55d9e2019-12-12 18:26:26 -0500287 err = status.Error(codes.FailedPrecondition, fmt.Sprintf("cannot-enable-a-deleted-device: %s ", cloned.Id))
npujar1d86a522019-11-14 17:11:16 +0530288 return err
289 }
290
khenaidoo6e55d9e2019-12-12 18:26:26 -0500291 previousAdminState := cloned.AdminState
npujar1d86a522019-11-14 17:11:16 +0530292
293 // Update the Admin State and set the operational state to activating before sending the request to the
294 // Adapters
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500295 if err := agent.updateDeviceStateInStoreWithoutLock(ctx, cloned, voltha.AdminState_ENABLED, cloned.ConnectStatus, voltha.OperStatus_ACTIVATING); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530296 return err
297 }
298
khenaidoo442e7c72020-03-10 16:13:48 -0400299 // Adopt the device if it was in pre-provision state. In all other cases, try to re-enable it.
khenaidoo6e55d9e2019-12-12 18:26:26 -0500300 device := proto.Clone(cloned).(*voltha.Device)
khenaidoo442e7c72020-03-10 16:13:48 -0400301 var ch chan *kafka.RpcResponse
302 subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
npujar1d86a522019-11-14 17:11:16 +0530303 if previousAdminState == voltha.AdminState_PREPROVISIONED {
Kent Hagerman2b216042020-04-03 18:28:56 -0400304 ch, err = agent.adapterProxy.AdoptDevice(subCtx, device)
khenaidoob9203542018-09-17 22:56:37 -0400305 } else {
Kent Hagerman2b216042020-04-03 18:28:56 -0400306 ch, err = agent.adapterProxy.ReEnableDevice(subCtx, device)
khenaidoob9203542018-09-17 22:56:37 -0400307 }
khenaidoo442e7c72020-03-10 16:13:48 -0400308 if err != nil {
309 cancel()
310 return err
311 }
312 // Wait for response
313 go agent.waitForAdapterResponse(subCtx, cancel, "enableDevice", ch, agent.onSuccess, agent.onFailure)
khenaidoob9203542018-09-17 22:56:37 -0400314 return nil
315}
316
Kent Hagerman2b216042020-04-03 18:28:56 -0400317func (agent *Agent) waitForAdapterFlowResponse(ctx context.Context, cancel context.CancelFunc, ch chan *kafka.RpcResponse, response coreutils.Response) {
khenaidoo442e7c72020-03-10 16:13:48 -0400318 defer cancel()
319 select {
320 case rpcResponse, ok := <-ch:
321 if !ok {
322 response.Error(status.Errorf(codes.Aborted, "channel-closed"))
323 } else if rpcResponse.Err != nil {
324 response.Error(rpcResponse.Err)
325 } else {
326 response.Done()
327 }
328 case <-ctx.Done():
329 response.Error(ctx.Err())
khenaidoo2c6a0992019-04-29 13:46:56 -0400330 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400331}
332
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700333//replaceFlowInList removes the old flow from list and adds the new one.
334func replaceFlowInList(flowList []*ofp.OfpFlowStats, oldFlow *ofp.OfpFlowStats, newFlow *ofp.OfpFlowStats) []*ofp.OfpFlowStats {
335 if idx := fu.FindFlows(flowList, oldFlow); idx != -1 {
336 flowList = deleteFlowWithoutPreservingOrder(flowList, idx)
337 }
338 flowList = append(flowList, newFlow)
339 return flowList
340}
341
khenaidoob2121e52019-12-16 17:17:22 -0500342//deleteFlowWithoutPreservingOrder removes a flow specified by index from the flows slice. This function will
343//panic if the index is out of range.
344func deleteFlowWithoutPreservingOrder(flows []*ofp.OfpFlowStats, index int) []*ofp.OfpFlowStats {
345 flows[index] = flows[len(flows)-1]
346 flows[len(flows)-1] = nil
347 return flows[:len(flows)-1]
348}
349
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700350//replaceGroupInList removes the old group from list and adds the new one.
351func replaceGroupInList(groupList []*ofp.OfpGroupEntry, oldGroup *ofp.OfpGroupEntry, newGroup *ofp.OfpGroupEntry) []*ofp.OfpGroupEntry {
352 if idx := fu.FindGroup(groupList, oldGroup.Desc.GroupId); idx != -1 {
353 groupList = deleteGroupWithoutPreservingOrder(groupList, idx)
354 }
355 groupList = append(groupList, newGroup)
356 return groupList
357}
358
khenaidoob2121e52019-12-16 17:17:22 -0500359//deleteGroupWithoutPreservingOrder removes a group specified by index from the groups slice. This function will
360//panic if the index is out of range.
361func deleteGroupWithoutPreservingOrder(groups []*ofp.OfpGroupEntry, index int) []*ofp.OfpGroupEntry {
362 groups[index] = groups[len(groups)-1]
363 groups[len(groups)-1] = nil
364 return groups[:len(groups)-1]
365}
366
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700367func (agent *Agent) addFlowsToAdapter(ctx context.Context, newFlows []*ofp.OfpFlowStats, flowMetadata *voltha.FlowMetadata) (coreutils.Response, error) {
368 logger.Debugw("add-flows-to-adapters", log.Fields{"device-id": agent.deviceID, "flows": newFlows, "flow-metadata": flowMetadata})
khenaidoob2121e52019-12-16 17:17:22 -0500369
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700370 if (len(newFlows)) == 0 {
371 logger.Debugw("nothing-to-update", log.Fields{"device-id": agent.deviceID, "flows": newFlows})
A R Karthick5c28f552019-12-11 22:47:44 -0800372 return coreutils.DoneResponse(), nil
khenaidoo2c6a0992019-04-29 13:46:56 -0400373 }
khenaidoo6e55d9e2019-12-12 18:26:26 -0500374 device := agent.getDeviceWithoutLock()
Kent Hagerman45a13e42020-04-13 12:23:50 -0400375 dType, err := agent.adapterMgr.GetDeviceType(ctx, &voltha.ID{Id: device.Type})
376 if err != nil {
khenaidoo442e7c72020-03-10 16:13:48 -0400377 return coreutils.DoneResponse(), status.Errorf(codes.FailedPrecondition, "non-existent-device-type-%s", device.Type)
378 }
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700379 updatedAllFlows := make([]*ofp.OfpFlowStats, 0)
380 if !dType.AcceptsAddRemoveFlowUpdates {
381 flowIDs := agent.flowLoader.List()
382 for flowID := range flowIDs {
383 if flowHandle, have := agent.flowLoader.Lock(flowID); have {
384 updatedAllFlows = append(updatedAllFlows, flowHandle.GetReadOnly())
385 flowHandle.Unlock()
386 }
387 }
388 }
389 flowsToAdd := make([]*ofp.OfpFlowStats, 0)
390 flowsToDelete := make([]*ofp.OfpFlowStats, 0)
391 for _, flow := range newFlows {
392 flowHandle, created, err := agent.flowLoader.LockOrCreate(ctx, flow)
393 if err != nil {
394 return coreutils.DoneResponse(), err
395 }
khenaidoo442e7c72020-03-10 16:13:48 -0400396
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700397 if created {
398 flowsToAdd = append(flowsToAdd, flow)
399 updatedAllFlows = append(updatedAllFlows, flow)
400 } else {
401 flowToReplace := flowHandle.GetReadOnly()
402 if !proto.Equal(flowToReplace, flow) {
403 //Flow needs to be updated.
404 if err := flowHandle.Update(ctx, flow); err != nil {
405 flowHandle.Unlock()
406 return coreutils.DoneResponse(), status.Errorf(codes.Internal, "failure-updating-flow-%d-to-device-%s", flow.Id, agent.deviceID)
407 }
408 flowsToDelete = append(flowsToDelete, flowToReplace)
409 flowsToAdd = append(flowsToAdd, flow)
410 updatedAllFlows = replaceFlowInList(updatedAllFlows, flowToReplace, flow)
411 } else {
412 //No need to change the flow. It is already exist.
413 logger.Debugw("No-need-to-change-already-existing-flow", log.Fields{"device-id": agent.deviceID, "flows": newFlows, "flow-metadata": flowMetadata})
414 }
415 }
khenaidoo0458db62019-06-20 08:50:36 -0400416
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700417 flowHandle.Unlock()
khenaidoo0458db62019-06-20 08:50:36 -0400418 }
419
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700420 // Sanity check
421 if (len(flowsToAdd)) == 0 {
422 logger.Debugw("no-flows-to-update", log.Fields{"device-id": agent.deviceID, "flows": newFlows})
423 return coreutils.DoneResponse(), nil
khenaidooe7be1332020-01-24 18:58:33 -0500424 }
khenaidoo0458db62019-06-20 08:50:36 -0400425
khenaidoo442e7c72020-03-10 16:13:48 -0400426 // Send update to adapters
427 subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
428 response := coreutils.NewResponse()
429 if !dType.AcceptsAddRemoveFlowUpdates {
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700430 rpcResponse, err := agent.adapterProxy.UpdateFlowsBulk(subCtx, device, &ofp.Flows{Items: updatedAllFlows}, &voltha.FlowGroups{Items: []*ofp.OfpGroupEntry{}}, flowMetadata)
khenaidoo442e7c72020-03-10 16:13:48 -0400431 if err != nil {
432 cancel()
433 return coreutils.DoneResponse(), err
434 }
435 go agent.waitForAdapterFlowResponse(subCtx, cancel, rpcResponse, response)
khenaidoo0458db62019-06-20 08:50:36 -0400436 } else {
437 flowChanges := &ofp.FlowChanges{
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700438 ToAdd: &voltha.Flows{Items: flowsToAdd},
khenaidoo0458db62019-06-20 08:50:36 -0400439 ToRemove: &voltha.Flows{Items: flowsToDelete},
440 }
441 groupChanges := &ofp.FlowGroupChanges{
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700442 ToAdd: &voltha.FlowGroups{Items: []*ofp.OfpGroupEntry{}},
443 ToRemove: &voltha.FlowGroups{Items: []*ofp.OfpGroupEntry{}},
444 ToUpdate: &voltha.FlowGroups{Items: []*ofp.OfpGroupEntry{}},
445 }
446 rpcResponse, err := agent.adapterProxy.UpdateFlowsIncremental(subCtx, device, flowChanges, groupChanges, flowMetadata)
447 if err != nil {
448 cancel()
449 return coreutils.DoneResponse(), err
450 }
451 go agent.waitForAdapterFlowResponse(subCtx, cancel, rpcResponse, response)
452 }
453 return response, nil
454}
455
456func (agent *Agent) addGroupsToAdapter(ctx context.Context, newGroups []*ofp.OfpGroupEntry, flowMetadata *voltha.FlowMetadata) (coreutils.Response, error) {
457 logger.Debugw("add-groups-to-adapters", log.Fields{"device-id": agent.deviceID, "groups": newGroups, "flow-metadata": flowMetadata})
458
459 if (len(newGroups)) == 0 {
460 logger.Debugw("nothing-to-update", log.Fields{"device-id": agent.deviceID, "groups": newGroups})
461 return coreutils.DoneResponse(), nil
462 }
463
464 device := agent.getDeviceWithoutLock()
465 dType, err := agent.adapterMgr.GetDeviceType(ctx, &voltha.ID{Id: device.Type})
466 if err != nil {
467 return coreutils.DoneResponse(), status.Errorf(codes.FailedPrecondition, "non-existent-device-type-%s", device.Type)
468 }
469 updatedAllGroups := make([]*ofp.OfpGroupEntry, 0)
470 if !dType.AcceptsAddRemoveFlowUpdates {
471 groupIDs := agent.groupLoader.List()
472 for groupID := range groupIDs {
473 if grpHandle, have := agent.groupLoader.Lock(groupID); have {
474 updatedAllGroups = append(updatedAllGroups, grpHandle.GetReadOnly())
475 grpHandle.Unlock()
476 }
477 }
478 }
479
480 groupsToAdd := make([]*ofp.OfpGroupEntry, 0)
481 groupsToDelete := make([]*ofp.OfpGroupEntry, 0)
482 for _, group := range newGroups {
483
484 groupHandle, created, err := agent.groupLoader.LockOrCreate(ctx, group)
485 if err != nil {
486 return coreutils.DoneResponse(), err
487 }
488
489 if created {
490 groupsToAdd = append(groupsToAdd, group)
491 updatedAllGroups = append(updatedAllGroups, group)
492 } else {
493 groupToChange := groupHandle.GetReadOnly()
494 if !proto.Equal(groupToChange, group) {
495 //Group needs to be updated.
496 if err := groupHandle.Update(ctx, group); err != nil {
497 groupHandle.Unlock()
498 return coreutils.DoneResponse(), status.Errorf(codes.Internal, "failure-updating-group-%s-to-device-%s", strconv.Itoa(int(group.Desc.GroupId)), agent.deviceID)
499 }
500 groupsToDelete = append(groupsToDelete, groupToChange)
501 groupsToAdd = append(groupsToAdd, group)
502 updatedAllGroups = replaceGroupInList(updatedAllGroups, groupToChange, group)
503 } else {
504 //No need to change the group. It is already exist.
505 logger.Debugw("No-need-to-change-already-existing-group", log.Fields{"device-id": agent.deviceID, "group": newGroups, "flow-metadata": flowMetadata})
506 }
507 }
508
509 groupHandle.Unlock()
510 }
511 // Sanity check
512 if (len(groupsToAdd)) == 0 {
513 logger.Debugw("no-groups-to-update", log.Fields{"device-id": agent.deviceID, "groups": newGroups})
514 return coreutils.DoneResponse(), nil
515 }
516
517 // Send update to adapters
518 subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
519 response := coreutils.NewResponse()
520 if !dType.AcceptsAddRemoveFlowUpdates {
521 rpcResponse, err := agent.adapterProxy.UpdateFlowsBulk(subCtx, device, &voltha.Flows{Items: []*ofp.OfpFlowStats{}}, &voltha.FlowGroups{Items: updatedAllGroups}, flowMetadata)
522 if err != nil {
523 cancel()
524 return coreutils.DoneResponse(), err
525 }
526 go agent.waitForAdapterFlowResponse(subCtx, cancel, rpcResponse, response)
527 } else {
528 flowChanges := &ofp.FlowChanges{
529 ToAdd: &voltha.Flows{Items: []*ofp.OfpFlowStats{}},
530 ToRemove: &voltha.Flows{Items: []*ofp.OfpFlowStats{}},
531 }
532 groupChanges := &ofp.FlowGroupChanges{
533 ToAdd: &voltha.FlowGroups{Items: groupsToAdd},
Matt Jeanneret518b5a42019-10-29 10:30:46 -0400534 ToRemove: &voltha.FlowGroups{Items: groupsToDelete},
khenaidoo0458db62019-06-20 08:50:36 -0400535 ToUpdate: &voltha.FlowGroups{Items: []*ofp.OfpGroupEntry{}},
536 }
Kent Hagerman2b216042020-04-03 18:28:56 -0400537 rpcResponse, err := agent.adapterProxy.UpdateFlowsIncremental(subCtx, device, flowChanges, groupChanges, flowMetadata)
khenaidoo442e7c72020-03-10 16:13:48 -0400538 if err != nil {
539 cancel()
540 return coreutils.DoneResponse(), err
541 }
542 go agent.waitForAdapterFlowResponse(subCtx, cancel, rpcResponse, response)
khenaidoo0458db62019-06-20 08:50:36 -0400543 }
A R Karthick5c28f552019-12-11 22:47:44 -0800544 return response, nil
545}
546
547//addFlowsAndGroups adds the "newFlows" and "newGroups" from the existing flows/groups and sends the update to the
548//adapters
Kent Hagerman2b216042020-04-03 18:28:56 -0400549func (agent *Agent) addFlowsAndGroups(ctx context.Context, newFlows []*ofp.OfpFlowStats, newGroups []*ofp.OfpGroupEntry, flowMetadata *voltha.FlowMetadata) error {
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700550 var flwResponse, grpResponse coreutils.Response
551 var err error
552 //if new flow list is empty then the called function returns quickly
553 if flwResponse, err = agent.addFlowsToAdapter(ctx, newFlows, flowMetadata); err != nil {
A R Karthick5c28f552019-12-11 22:47:44 -0800554 return err
555 }
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700556 //if new group list is empty then the called function returns quickly
557 if grpResponse, err = agent.addGroupsToAdapter(ctx, newGroups, flowMetadata); err != nil {
558 return err
559 }
560 if errs := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, flwResponse, grpResponse); errs != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000561 logger.Warnw("no-adapter-response", log.Fields{"device-id": agent.deviceID, "result": errs})
khenaidoo442e7c72020-03-10 16:13:48 -0400562 return status.Errorf(codes.Aborted, "flow-failure-device-%s", agent.deviceID)
khenaidoo0458db62019-06-20 08:50:36 -0400563 }
khenaidoo0458db62019-06-20 08:50:36 -0400564 return nil
565}
566
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700567func (agent *Agent) deleteFlowsFromAdapter(ctx context.Context, flowsToDel []*ofp.OfpFlowStats, flowMetadata *voltha.FlowMetadata) (coreutils.Response, error) {
568 logger.Debugw("delete-flows-from-adapter", log.Fields{"device-id": agent.deviceID, "flows": flowsToDel})
khenaidoo0458db62019-06-20 08:50:36 -0400569
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700570 if (len(flowsToDel)) == 0 {
571 logger.Debugw("nothing-to-delete", log.Fields{"device-id": agent.deviceID, "flows": flowsToDel})
A R Karthick5c28f552019-12-11 22:47:44 -0800572 return coreutils.DoneResponse(), nil
khenaidoo0458db62019-06-20 08:50:36 -0400573 }
574
khenaidoo6e55d9e2019-12-12 18:26:26 -0500575 device := agent.getDeviceWithoutLock()
Kent Hagerman45a13e42020-04-13 12:23:50 -0400576 dType, err := agent.adapterMgr.GetDeviceType(ctx, &voltha.ID{Id: device.Type})
577 if err != nil {
khenaidoo442e7c72020-03-10 16:13:48 -0400578 return coreutils.DoneResponse(), status.Errorf(codes.FailedPrecondition, "non-existent-device-type-%s", device.Type)
579 }
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700580 updatedAllFlows := make([]*ofp.OfpFlowStats, 0)
581 if !dType.AcceptsAddRemoveFlowUpdates {
582 flowIDs := agent.flowLoader.List()
583 for flowID := range flowIDs {
584 if flowHandle, have := agent.flowLoader.Lock(flowID); have {
585 updatedAllFlows = append(updatedAllFlows, flowHandle.GetReadOnly())
586 flowHandle.Unlock()
587 }
khenaidoo0458db62019-06-20 08:50:36 -0400588 }
589 }
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700590 for _, flow := range flowsToDel {
591 if flowHandle, have := agent.flowLoader.Lock(flow.Id); have {
592 // Update the store and cache
593 flowToDelete := flowHandle.GetReadOnly()
594 if err := flowHandle.Delete(ctx); err != nil {
595 flowHandle.Unlock()
596 return coreutils.DoneResponse(), err
597 }
598 if idx := fu.FindFlows(updatedAllFlows, flowToDelete); idx != -1 {
599 updatedAllFlows = deleteFlowWithoutPreservingOrder(updatedAllFlows, idx)
600 }
601 flowHandle.Unlock()
khenaidoo0458db62019-06-20 08:50:36 -0400602 }
603 }
604
khenaidoo442e7c72020-03-10 16:13:48 -0400605 // Send update to adapters
606 subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
607 response := coreutils.NewResponse()
khenaidoo0458db62019-06-20 08:50:36 -0400608 if !dType.AcceptsAddRemoveFlowUpdates {
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700609 rpcResponse, err := agent.adapterProxy.UpdateFlowsBulk(subCtx, device, &voltha.Flows{Items: updatedAllFlows}, &voltha.FlowGroups{Items: []*ofp.OfpGroupEntry{}}, flowMetadata)
khenaidoo442e7c72020-03-10 16:13:48 -0400610 if err != nil {
611 cancel()
612 return coreutils.DoneResponse(), err
613 }
614 go agent.waitForAdapterFlowResponse(subCtx, cancel, rpcResponse, response)
khenaidoo0458db62019-06-20 08:50:36 -0400615 } else {
616 flowChanges := &ofp.FlowChanges{
617 ToAdd: &voltha.Flows{Items: []*ofp.OfpFlowStats{}},
618 ToRemove: &voltha.Flows{Items: flowsToDel},
619 }
620 groupChanges := &ofp.FlowGroupChanges{
621 ToAdd: &voltha.FlowGroups{Items: []*ofp.OfpGroupEntry{}},
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700622 ToRemove: &voltha.FlowGroups{Items: []*ofp.OfpGroupEntry{}},
623 ToUpdate: &voltha.FlowGroups{Items: []*ofp.OfpGroupEntry{}},
624 }
625 rpcResponse, err := agent.adapterProxy.UpdateFlowsIncremental(subCtx, device, flowChanges, groupChanges, flowMetadata)
626 if err != nil {
627 cancel()
628 return coreutils.DoneResponse(), err
629 }
630 go agent.waitForAdapterFlowResponse(subCtx, cancel, rpcResponse, response)
631 }
632 return response, nil
633}
634
635func (agent *Agent) deleteGroupsFromAdapter(ctx context.Context, groupsToDel []*ofp.OfpGroupEntry, flowMetadata *voltha.FlowMetadata) (coreutils.Response, error) {
636 logger.Debugw("delete-groups-from-adapter", log.Fields{"device-id": agent.deviceID, "groups": groupsToDel})
637
638 if (len(groupsToDel)) == 0 {
639 logger.Debugw("nothing-to-delete", log.Fields{"device-id": agent.deviceID})
640 return coreutils.DoneResponse(), nil
641 }
642 device := agent.getDeviceWithoutLock()
643 dType, err := agent.adapterMgr.GetDeviceType(ctx, &voltha.ID{Id: device.Type})
644 if err != nil {
645 return coreutils.DoneResponse(), status.Errorf(codes.FailedPrecondition, "non-existent-device-type-%s", device.Type)
646 }
647 updatedAllGroups := make([]*ofp.OfpGroupEntry, 0)
648 if !dType.AcceptsAddRemoveFlowUpdates {
649 groupIDs := agent.groupLoader.List()
650 for groupID := range groupIDs {
651 if grpHandle, have := agent.groupLoader.Lock(groupID); have {
652 updatedAllGroups = append(updatedAllGroups, grpHandle.GetReadOnly())
653 grpHandle.Unlock()
654 }
655 }
656 }
657
658 for _, group := range groupsToDel {
659 if groupHandle, have := agent.groupLoader.Lock(group.Desc.GroupId); have {
660 // Update the store and cache
661 if err := groupHandle.Delete(ctx); err != nil {
662 groupHandle.Unlock()
663 return coreutils.DoneResponse(), err
664 }
665 if idx := fu.FindGroup(updatedAllGroups, group.Desc.GroupId); idx != -1 {
666 updatedAllGroups = deleteGroupWithoutPreservingOrder(updatedAllGroups, idx)
667 }
668 groupHandle.Unlock()
669 }
670 }
671
672 // Send update to adapters
673 subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
674 response := coreutils.NewResponse()
675 if !dType.AcceptsAddRemoveFlowUpdates {
676 rpcResponse, err := agent.adapterProxy.UpdateFlowsBulk(subCtx, device, &voltha.Flows{Items: []*ofp.OfpFlowStats{}}, &voltha.FlowGroups{Items: updatedAllGroups}, flowMetadata)
677 if err != nil {
678 cancel()
679 return coreutils.DoneResponse(), err
680 }
681 go agent.waitForAdapterFlowResponse(subCtx, cancel, rpcResponse, response)
682 } else {
683 flowChanges := &ofp.FlowChanges{
684 ToAdd: &voltha.Flows{Items: []*ofp.OfpFlowStats{}},
685 ToRemove: &voltha.Flows{Items: []*ofp.OfpFlowStats{}},
686 }
687 groupChanges := &ofp.FlowGroupChanges{
688 ToAdd: &voltha.FlowGroups{Items: []*ofp.OfpGroupEntry{}},
khenaidoo0458db62019-06-20 08:50:36 -0400689 ToRemove: &voltha.FlowGroups{Items: groupsToDel},
690 ToUpdate: &voltha.FlowGroups{Items: []*ofp.OfpGroupEntry{}},
691 }
Kent Hagerman2b216042020-04-03 18:28:56 -0400692 rpcResponse, err := agent.adapterProxy.UpdateFlowsIncremental(subCtx, device, flowChanges, groupChanges, flowMetadata)
khenaidoo442e7c72020-03-10 16:13:48 -0400693 if err != nil {
694 cancel()
695 return coreutils.DoneResponse(), err
696 }
697 go agent.waitForAdapterFlowResponse(subCtx, cancel, rpcResponse, response)
khenaidoo0458db62019-06-20 08:50:36 -0400698 }
A R Karthick5c28f552019-12-11 22:47:44 -0800699 return response, nil
A R Karthick5c28f552019-12-11 22:47:44 -0800700}
701
702//deleteFlowsAndGroups removes the "flowsToDel" and "groupsToDel" from the existing flows/groups and sends the update to the
703//adapters
Kent Hagerman2b216042020-04-03 18:28:56 -0400704func (agent *Agent) deleteFlowsAndGroups(ctx context.Context, flowsToDel []*ofp.OfpFlowStats, groupsToDel []*ofp.OfpGroupEntry, flowMetadata *voltha.FlowMetadata) error {
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700705 var flwResponse, grpResponse coreutils.Response
706 var err error
707 if flwResponse, err = agent.deleteFlowsFromAdapter(ctx, flowsToDel, flowMetadata); err != nil {
A R Karthick5c28f552019-12-11 22:47:44 -0800708 return err
709 }
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700710 if grpResponse, err = agent.deleteGroupsFromAdapter(ctx, groupsToDel, flowMetadata); err != nil {
711 return err
712 }
713
714 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, flwResponse, grpResponse); res != nil {
khenaidoo0458db62019-06-20 08:50:36 -0400715 return status.Errorf(codes.Aborted, "errors-%s", res)
716 }
717 return nil
khenaidoo0458db62019-06-20 08:50:36 -0400718}
719
khenaidoo787224a2020-04-16 18:08:47 -0400720//filterOutFlows removes flows from a device using the uni-port as filter
721func (agent *Agent) filterOutFlows(ctx context.Context, uniPort uint32, flowMetadata *voltha.FlowMetadata) error {
khenaidoo787224a2020-04-16 18:08:47 -0400722 var flowsToDelete []*ofp.OfpFlowStats
khenaidoo787224a2020-04-16 18:08:47 -0400723 // If an existing flow has the uniPort as an InPort or OutPort or as a Tunnel ID then it needs to be removed
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700724 for flowID := range agent.flowLoader.List() {
725 if flowHandle, have := agent.flowLoader.Lock(flowID); have {
726 flow := flowHandle.GetReadOnly()
727 if flow != nil && (fu.GetInPort(flow) == uniPort || fu.GetOutPort(flow) == uniPort || fu.GetTunnelId(flow) == uint64(uniPort)) {
728 flowsToDelete = append(flowsToDelete, flow)
729 }
730 flowHandle.Unlock()
khenaidoo787224a2020-04-16 18:08:47 -0400731 }
732 }
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700733
khenaidoo787224a2020-04-16 18:08:47 -0400734 logger.Debugw("flows-to-delete", log.Fields{"device-id": agent.deviceID, "uni-port": uniPort, "flows": flowsToDelete})
735 if len(flowsToDelete) == 0 {
736 return nil
737 }
738
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700739 response, err := agent.deleteFlowsFromAdapter(ctx, flowsToDelete, flowMetadata)
khenaidoo787224a2020-04-16 18:08:47 -0400740 if err != nil {
741 return err
742 }
743 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, response); res != nil {
744 return status.Errorf(codes.Aborted, "errors-%s", res)
745 }
746 return nil
747}
748
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700749func (agent *Agent) updateFlowsToAdapter(ctx context.Context, updatedFlows []*ofp.OfpFlowStats, flowMetadata *voltha.FlowMetadata) (coreutils.Response, error) {
750 logger.Debugw("updateFlowsToAdapter", log.Fields{"device-id": agent.deviceID, "flows": updatedFlows})
khenaidoo0458db62019-06-20 08:50:36 -0400751
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700752 if (len(updatedFlows)) == 0 {
753 logger.Debugw("nothing-to-update", log.Fields{"device-id": agent.deviceID, "flows": updatedFlows})
A R Karthick5c28f552019-12-11 22:47:44 -0800754 return coreutils.DoneResponse(), nil
khenaidoo0458db62019-06-20 08:50:36 -0400755 }
756
khenaidoo6e55d9e2019-12-12 18:26:26 -0500757 device := agent.getDeviceWithoutLock()
khenaidoo442e7c72020-03-10 16:13:48 -0400758 if device.OperStatus != voltha.OperStatus_ACTIVE || device.ConnectStatus != voltha.ConnectStatus_REACHABLE || device.AdminState != voltha.AdminState_ENABLED {
759 return coreutils.DoneResponse(), status.Errorf(codes.FailedPrecondition, "invalid device states")
760 }
Kent Hagerman45a13e42020-04-13 12:23:50 -0400761 dType, err := agent.adapterMgr.GetDeviceType(ctx, &voltha.ID{Id: device.Type})
762 if err != nil {
khenaidoo442e7c72020-03-10 16:13:48 -0400763 return coreutils.DoneResponse(), status.Errorf(codes.FailedPrecondition, "non-existent-device-type-%s", device.Type)
764 }
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700765 updatedAllFlows := make([]*ofp.OfpFlowStats, 0)
766 if !dType.AcceptsAddRemoveFlowUpdates {
767 flowIDs := agent.flowLoader.List()
768 for flowID := range flowIDs {
769 if flowHandle, have := agent.flowLoader.Lock(flowID); have {
770 updatedAllFlows = append(updatedAllFlows, flowHandle.GetReadOnly())
771 flowHandle.Unlock()
772 }
773 }
khenaidoo0458db62019-06-20 08:50:36 -0400774 }
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700775 flowsToAdd := make([]*ofp.OfpFlowStats, 0)
776 flowsToDelete := make([]*ofp.OfpFlowStats, 0)
khenaidoo0458db62019-06-20 08:50:36 -0400777
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700778 for _, flow := range updatedFlows {
779 if flowHandle, have := agent.flowLoader.Lock(flow.Id); have {
780 flowToDelete := flowHandle.GetReadOnly()
781 // Update the store and cache
782 if err := flowHandle.Update(ctx, flow); err != nil {
783 flowHandle.Unlock()
784 return coreutils.DoneResponse(), err
785 }
khenaidoo0458db62019-06-20 08:50:36 -0400786
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700787 flowsToDelete = append(flowsToDelete, flowToDelete)
788 flowsToAdd = append(flowsToAdd, flow)
789 updatedAllFlows = replaceFlowInList(updatedAllFlows, flowToDelete, flow)
790 flowHandle.Unlock()
791 }
khenaidooe7be1332020-01-24 18:58:33 -0500792 }
khenaidoo0458db62019-06-20 08:50:36 -0400793
khenaidoo442e7c72020-03-10 16:13:48 -0400794 subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
795 response := coreutils.NewResponse()
khenaidoo0458db62019-06-20 08:50:36 -0400796 // Process bulk flow update differently than incremental update
797 if !dType.AcceptsAddRemoveFlowUpdates {
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700798 rpcResponse, err := agent.adapterProxy.UpdateFlowsBulk(subCtx, device, &voltha.Flows{Items: updatedAllFlows}, &voltha.FlowGroups{Items: []*ofp.OfpGroupEntry{}}, nil)
khenaidoo442e7c72020-03-10 16:13:48 -0400799 if err != nil {
800 cancel()
801 return coreutils.DoneResponse(), err
802 }
803 go agent.waitForAdapterFlowResponse(subCtx, cancel, rpcResponse, response)
khenaidoo0458db62019-06-20 08:50:36 -0400804 } else {
Girish Kumarf56a4682020-03-20 20:07:46 +0000805 logger.Debugw("updating-flows-and-groups",
khenaidoo0458db62019-06-20 08:50:36 -0400806 log.Fields{
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700807 "device-id": agent.deviceID,
808 "flows-to-add": flowsToAdd,
809 "flows-to-delete": flowsToDelete,
khenaidoo0458db62019-06-20 08:50:36 -0400810 })
khenaidoo2c6a0992019-04-29 13:46:56 -0400811 // Sanity check
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700812 if (len(flowsToAdd) | len(flowsToDelete)) == 0 {
813 logger.Debugw("nothing-to-update", log.Fields{"device-id": agent.deviceID, "flows": updatedFlows})
khenaidoo442e7c72020-03-10 16:13:48 -0400814 cancel()
A R Karthick5c28f552019-12-11 22:47:44 -0800815 return coreutils.DoneResponse(), nil
khenaidoo2c6a0992019-04-29 13:46:56 -0400816 }
817
khenaidoo0458db62019-06-20 08:50:36 -0400818 flowChanges := &ofp.FlowChanges{
819 ToAdd: &voltha.Flows{Items: flowsToAdd},
820 ToRemove: &voltha.Flows{Items: flowsToDelete},
khenaidoo19d7b632018-10-30 10:49:50 -0400821 }
khenaidoo0458db62019-06-20 08:50:36 -0400822 groupChanges := &ofp.FlowGroupChanges{
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700823 ToAdd: &voltha.FlowGroups{Items: []*ofp.OfpGroupEntry{}},
824 ToRemove: &voltha.FlowGroups{Items: []*ofp.OfpGroupEntry{}},
825 ToUpdate: &voltha.FlowGroups{Items: []*ofp.OfpGroupEntry{}},
826 }
827 rpcResponse, err := agent.adapterProxy.UpdateFlowsIncremental(subCtx, device, flowChanges, groupChanges, flowMetadata)
828 if err != nil {
829 cancel()
830 return coreutils.DoneResponse(), err
831 }
832 go agent.waitForAdapterFlowResponse(subCtx, cancel, rpcResponse, response)
833 }
834
835 return response, nil
836}
837
838func (agent *Agent) updateGroupsToAdapter(ctx context.Context, updatedGroups []*ofp.OfpGroupEntry, flowMetadata *voltha.FlowMetadata) (coreutils.Response, error) {
839 logger.Debugw("updateGroupsToAdapter", log.Fields{"device-id": agent.deviceID, "groups": updatedGroups})
840
841 if (len(updatedGroups)) == 0 {
842 logger.Debugw("nothing-to-update", log.Fields{"device-id": agent.deviceID, "groups": updatedGroups})
843 return coreutils.DoneResponse(), nil
844 }
845
846 device := agent.getDeviceWithoutLock()
847 if device.OperStatus != voltha.OperStatus_ACTIVE || device.ConnectStatus != voltha.ConnectStatus_REACHABLE || device.AdminState != voltha.AdminState_ENABLED {
848 return coreutils.DoneResponse(), status.Errorf(codes.FailedPrecondition, "invalid device states-oper-%s-connect-%s-admin-%s", device.OperStatus, device.ConnectStatus, device.AdminState)
849 }
850 dType, err := agent.adapterMgr.GetDeviceType(ctx, &voltha.ID{Id: device.Type})
851 if err != nil {
852 return coreutils.DoneResponse(), status.Errorf(codes.FailedPrecondition, "non-existent-device-type-%s", device.Type)
853 }
854 updatedAllGroups := make([]*ofp.OfpGroupEntry, 0)
855 if !dType.AcceptsAddRemoveFlowUpdates {
856 groupIDs := agent.groupLoader.List()
857 for groupID := range groupIDs {
858 if grpHandle, have := agent.groupLoader.Lock(groupID); have {
859 updatedAllGroups = append(updatedAllGroups, grpHandle.GetReadOnly())
860 grpHandle.Unlock()
861 }
862 }
863 }
864 groupsToUpdate := make([]*ofp.OfpGroupEntry, 0)
865
866 for _, group := range updatedGroups {
867 if groupHandle, have := agent.groupLoader.Lock(group.Desc.GroupId); have {
868 // Update the store and cache
869 if err := groupHandle.Update(ctx, group); err != nil {
870 groupHandle.Unlock()
871 return coreutils.DoneResponse(), err
872 }
873 groupsToUpdate = append(groupsToUpdate, group)
874 updatedAllGroups = replaceGroupInList(updatedAllGroups, groupHandle.GetReadOnly(), group)
875 groupHandle.Unlock()
876 }
877 }
878
879 subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
880 response := coreutils.NewResponse()
881 // Process bulk flow update differently than incremental update
882 if !dType.AcceptsAddRemoveFlowUpdates {
883 rpcResponse, err := agent.adapterProxy.UpdateFlowsBulk(subCtx, device, &voltha.Flows{Items: []*ofp.OfpFlowStats{}}, &voltha.FlowGroups{Items: updatedAllGroups}, nil)
884 if err != nil {
885 cancel()
886 return coreutils.DoneResponse(), err
887 }
888 go agent.waitForAdapterFlowResponse(subCtx, cancel, rpcResponse, response)
889 } else {
890 logger.Debugw("updating-groups",
891 log.Fields{
892 "device-id": agent.deviceID,
893 "groups-to-update": groupsToUpdate,
894 })
895
896 // Sanity check
897 if (len(groupsToUpdate)) == 0 {
898 logger.Debugw("nothing-to-update", log.Fields{"device-id": agent.deviceID, "groups": groupsToUpdate})
899 cancel()
900 return coreutils.DoneResponse(), nil
901 }
902
903 flowChanges := &ofp.FlowChanges{
904 ToAdd: &voltha.Flows{Items: []*ofp.OfpFlowStats{}},
905 ToRemove: &voltha.Flows{Items: []*ofp.OfpFlowStats{}},
906 }
907 groupChanges := &ofp.FlowGroupChanges{
908 ToAdd: &voltha.FlowGroups{Items: []*ofp.OfpGroupEntry{}},
909 ToRemove: &voltha.FlowGroups{Items: []*ofp.OfpGroupEntry{}},
910 ToUpdate: &voltha.FlowGroups{Items: groupsToUpdate},
khenaidoo0458db62019-06-20 08:50:36 -0400911 }
Kent Hagerman2b216042020-04-03 18:28:56 -0400912 rpcResponse, err := agent.adapterProxy.UpdateFlowsIncremental(subCtx, device, flowChanges, groupChanges, flowMetadata)
khenaidoo442e7c72020-03-10 16:13:48 -0400913 if err != nil {
914 cancel()
915 return coreutils.DoneResponse(), err
916 }
917 go agent.waitForAdapterFlowResponse(subCtx, cancel, rpcResponse, response)
Kent Hagerman3c513972019-11-25 13:49:41 -0500918 }
khenaidoo0458db62019-06-20 08:50:36 -0400919
A R Karthick5c28f552019-12-11 22:47:44 -0800920 return response, nil
921}
922
923//updateFlowsAndGroups replaces the existing flows and groups with "updatedFlows" and "updatedGroups" respectively. It
924//also sends the updates to the adapters
Kent Hagerman2b216042020-04-03 18:28:56 -0400925func (agent *Agent) updateFlowsAndGroups(ctx context.Context, updatedFlows []*ofp.OfpFlowStats, updatedGroups []*ofp.OfpGroupEntry, flowMetadata *voltha.FlowMetadata) error {
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700926 var flwResponse, grpResponse coreutils.Response
927 var err error
928 if flwResponse, err = agent.updateFlowsToAdapter(ctx, updatedFlows, flowMetadata); err != nil {
A R Karthick5c28f552019-12-11 22:47:44 -0800929 return err
930 }
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700931 if grpResponse, err = agent.updateGroupsToAdapter(ctx, updatedGroups, flowMetadata); err != nil {
932 return err
933 }
934
935 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, flwResponse, grpResponse); res != nil {
khenaidoo0458db62019-06-20 08:50:36 -0400936 return status.Errorf(codes.Aborted, "errors-%s", res)
937 }
938 return nil
khenaidoo19d7b632018-10-30 10:49:50 -0400939}
940
Girish Gowdra408cd962020-03-11 14:31:31 -0700941//deleteAllFlows deletes all flows in the device table
Kent Hagerman2b216042020-04-03 18:28:56 -0400942func (agent *Agent) deleteAllFlows(ctx context.Context) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000943 logger.Debugw("deleteAllFlows", log.Fields{"deviceId": agent.deviceID})
Girish Gowdra408cd962020-03-11 14:31:31 -0700944
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700945 for flowID := range agent.flowLoader.List() {
946 if flowHandle, have := agent.flowLoader.Lock(flowID); have {
947 // Update the store and cache
948 if err := flowHandle.Delete(ctx); err != nil {
949 flowHandle.Unlock()
950 logger.Errorw("unable-to-delete-flow", log.Fields{"device-id": agent.deviceID, "flowID": flowID})
951 continue
952 }
953 flowHandle.Unlock()
954 }
Girish Gowdra408cd962020-03-11 14:31:31 -0700955 }
956 return nil
957}
958
khenaidoo4d4802d2018-10-04 21:59:49 -0400959//disableDevice disable a device
Kent Hagerman2b216042020-04-03 18:28:56 -0400960func (agent *Agent) disableDevice(ctx context.Context) error {
khenaidoo442e7c72020-03-10 16:13:48 -0400961 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
962 return err
963 }
964 defer agent.requestQueue.RequestComplete()
Girish Kumarf56a4682020-03-20 20:07:46 +0000965 logger.Debugw("disableDevice", log.Fields{"device-id": agent.deviceID})
khenaidoo6e55d9e2019-12-12 18:26:26 -0500966
967 cloned := agent.getDeviceWithoutLock()
968
969 if cloned.AdminState == voltha.AdminState_DISABLED {
Girish Kumarf56a4682020-03-20 20:07:46 +0000970 logger.Debugw("device-already-disabled", log.Fields{"id": agent.deviceID})
npujar1d86a522019-11-14 17:11:16 +0530971 return nil
972 }
khenaidoo6e55d9e2019-12-12 18:26:26 -0500973 if cloned.AdminState == voltha.AdminState_PREPROVISIONED ||
974 cloned.AdminState == voltha.AdminState_DELETED {
khenaidoo6e55d9e2019-12-12 18:26:26 -0500975 return status.Errorf(codes.FailedPrecondition, "deviceId:%s, invalid-admin-state:%s", agent.deviceID, cloned.AdminState)
npujar1d86a522019-11-14 17:11:16 +0530976 }
khenaidoo4554f7c2019-05-29 22:13:15 -0400977
npujar1d86a522019-11-14 17:11:16 +0530978 // Update the Admin State and operational state before sending the request out
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500979 if err := agent.updateDeviceStateInStoreWithoutLock(ctx, cloned, voltha.AdminState_DISABLED, cloned.ConnectStatus, voltha.OperStatus_UNKNOWN); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530980 return err
981 }
khenaidoo442e7c72020-03-10 16:13:48 -0400982
983 subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
Kent Hagerman2b216042020-04-03 18:28:56 -0400984 ch, err := agent.adapterProxy.DisableDevice(subCtx, proto.Clone(cloned).(*voltha.Device))
khenaidoo442e7c72020-03-10 16:13:48 -0400985 if err != nil {
986 cancel()
npujar1d86a522019-11-14 17:11:16 +0530987 return err
khenaidoo0a822f92019-05-08 15:15:57 -0400988 }
khenaidoo442e7c72020-03-10 16:13:48 -0400989 go agent.waitForAdapterResponse(subCtx, cancel, "disableDevice", ch, agent.onSuccess, agent.onFailure)
khenaidoo0a822f92019-05-08 15:15:57 -0400990
khenaidoo92e62c52018-10-03 14:02:54 -0400991 return nil
992}
993
Kent Hagerman2b216042020-04-03 18:28:56 -0400994func (agent *Agent) rebootDevice(ctx context.Context) error {
khenaidoo442e7c72020-03-10 16:13:48 -0400995 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530996 return err
khenaidoo4d4802d2018-10-04 21:59:49 -0400997 }
khenaidoo442e7c72020-03-10 16:13:48 -0400998 defer agent.requestQueue.RequestComplete()
Girish Kumarf56a4682020-03-20 20:07:46 +0000999 logger.Debugw("rebootDevice", log.Fields{"device-id": agent.deviceID})
khenaidoo442e7c72020-03-10 16:13:48 -04001000
1001 device := agent.getDeviceWithoutLock()
1002 subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
Kent Hagerman2b216042020-04-03 18:28:56 -04001003 ch, err := agent.adapterProxy.RebootDevice(subCtx, device)
khenaidoo442e7c72020-03-10 16:13:48 -04001004 if err != nil {
1005 cancel()
1006 return err
1007 }
1008 go agent.waitForAdapterResponse(subCtx, cancel, "rebootDevice", ch, agent.onSuccess, agent.onFailure)
khenaidoo4d4802d2018-10-04 21:59:49 -04001009 return nil
1010}
1011
Kent Hagerman2b216042020-04-03 18:28:56 -04001012func (agent *Agent) deleteDevice(ctx context.Context) error {
Girish Kumarf56a4682020-03-20 20:07:46 +00001013 logger.Debugw("deleteDevice", log.Fields{"device-id": agent.deviceID})
khenaidoo442e7c72020-03-10 16:13:48 -04001014 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1015 return err
1016 }
1017 defer agent.requestQueue.RequestComplete()
khenaidoo6e55d9e2019-12-12 18:26:26 -05001018
1019 cloned := agent.getDeviceWithoutLock()
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001020
khenaidoo442e7c72020-03-10 16:13:48 -04001021 previousState := cloned.AdminState
1022
1023 // No check is required when deleting a device. Changing the state to DELETE will trigger the removal of this
1024 // device by the state machine
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001025 if err := agent.updateDeviceStateInStoreWithoutLock(ctx, cloned, voltha.AdminState_DELETED, cloned.ConnectStatus, cloned.OperStatus); err != nil {
npujar1d86a522019-11-14 17:11:16 +05301026 return err
1027 }
khenaidoo442e7c72020-03-10 16:13:48 -04001028
1029 // If the device was in pre-prov state (only parent device are in that state) then do not send the request to the
1030 // adapter
1031 if previousState != ic.AdminState_PREPROVISIONED {
1032 subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
Kent Hagerman2b216042020-04-03 18:28:56 -04001033 ch, err := agent.adapterProxy.DeleteDevice(subCtx, cloned)
khenaidoo442e7c72020-03-10 16:13:48 -04001034 if err != nil {
1035 cancel()
1036 return err
1037 }
1038 go agent.waitForAdapterResponse(subCtx, cancel, "deleteDevice", ch, agent.onSuccess, agent.onFailure)
1039 }
khenaidoo4d4802d2018-10-04 21:59:49 -04001040 return nil
1041}
1042
Kent Hagerman2b216042020-04-03 18:28:56 -04001043func (agent *Agent) setParentID(ctx context.Context, device *voltha.Device, parentID string) error {
khenaidoo442e7c72020-03-10 16:13:48 -04001044 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1045 return err
1046 }
1047 defer agent.requestQueue.RequestComplete()
1048
Girish Kumarf56a4682020-03-20 20:07:46 +00001049 logger.Debugw("setParentId", log.Fields{"device-id": device.Id, "parent-id": parentID})
khenaidoo6e55d9e2019-12-12 18:26:26 -05001050
1051 cloned := agent.getDeviceWithoutLock()
npujar1d86a522019-11-14 17:11:16 +05301052 cloned.ParentId = parentID
1053 // Store the device
npujar467fe752020-01-16 20:17:45 +05301054 if err := agent.updateDeviceInStoreWithoutLock(ctx, cloned, false, ""); err != nil {
npujar1d86a522019-11-14 17:11:16 +05301055 return err
1056 }
khenaidoo442e7c72020-03-10 16:13:48 -04001057
npujar1d86a522019-11-14 17:11:16 +05301058 return nil
khenaidooad06fd72019-10-28 12:26:05 -04001059}
1060
Kent Hagerman2b216042020-04-03 18:28:56 -04001061func (agent *Agent) updatePmConfigs(ctx context.Context, pmConfigs *voltha.PmConfigs) error {
khenaidoo442e7c72020-03-10 16:13:48 -04001062 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1063 return err
1064 }
1065 defer agent.requestQueue.RequestComplete()
Girish Kumarf56a4682020-03-20 20:07:46 +00001066 logger.Debugw("updatePmConfigs", log.Fields{"device-id": pmConfigs.Id})
khenaidoo6e55d9e2019-12-12 18:26:26 -05001067
1068 cloned := agent.getDeviceWithoutLock()
npujar1d86a522019-11-14 17:11:16 +05301069 cloned.PmConfigs = proto.Clone(pmConfigs).(*voltha.PmConfigs)
1070 // Store the device
npujar467fe752020-01-16 20:17:45 +05301071 if err := agent.updateDeviceInStoreWithoutLock(ctx, cloned, false, ""); err != nil {
npujar1d86a522019-11-14 17:11:16 +05301072 return err
1073 }
1074 // Send the request to the adapter
khenaidoo442e7c72020-03-10 16:13:48 -04001075 subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
Kent Hagerman2b216042020-04-03 18:28:56 -04001076 ch, err := agent.adapterProxy.UpdatePmConfigs(subCtx, cloned, pmConfigs)
khenaidoo442e7c72020-03-10 16:13:48 -04001077 if err != nil {
1078 cancel()
npujar1d86a522019-11-14 17:11:16 +05301079 return err
1080 }
khenaidoo442e7c72020-03-10 16:13:48 -04001081 go agent.waitForAdapterResponse(subCtx, cancel, "updatePmConfigs", ch, agent.onSuccess, agent.onFailure)
npujar1d86a522019-11-14 17:11:16 +05301082 return nil
khenaidoob3127472019-07-24 21:04:55 -04001083}
1084
Kent Hagerman2b216042020-04-03 18:28:56 -04001085func (agent *Agent) initPmConfigs(ctx context.Context, pmConfigs *voltha.PmConfigs) error {
khenaidoo442e7c72020-03-10 16:13:48 -04001086 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1087 return err
1088 }
1089 defer agent.requestQueue.RequestComplete()
Girish Kumarf56a4682020-03-20 20:07:46 +00001090 logger.Debugw("initPmConfigs", log.Fields{"device-id": pmConfigs.Id})
khenaidoo6e55d9e2019-12-12 18:26:26 -05001091
1092 cloned := agent.getDeviceWithoutLock()
npujar1d86a522019-11-14 17:11:16 +05301093 cloned.PmConfigs = proto.Clone(pmConfigs).(*voltha.PmConfigs)
khenaidoo0db4c812020-05-27 15:27:30 -04001094 return agent.updateDeviceInStoreWithoutLock(ctx, cloned, false, "")
khenaidoob3127472019-07-24 21:04:55 -04001095}
1096
Kent Hagerman2b216042020-04-03 18:28:56 -04001097func (agent *Agent) listPmConfigs(ctx context.Context) (*voltha.PmConfigs, error) {
khenaidoo442e7c72020-03-10 16:13:48 -04001098 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1099 return nil, err
1100 }
1101 defer agent.requestQueue.RequestComplete()
Girish Kumarf56a4682020-03-20 20:07:46 +00001102 logger.Debugw("listPmConfigs", log.Fields{"device-id": agent.deviceID})
khenaidoo6e55d9e2019-12-12 18:26:26 -05001103
1104 return agent.getDeviceWithoutLock().PmConfigs, nil
khenaidoob3127472019-07-24 21:04:55 -04001105}
1106
Kent Hagerman2b216042020-04-03 18:28:56 -04001107func (agent *Agent) downloadImage(ctx context.Context, img *voltha.ImageDownload) (*voltha.OperationResp, error) {
khenaidoo442e7c72020-03-10 16:13:48 -04001108 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1109 return nil, err
1110 }
1111 defer agent.requestQueue.RequestComplete()
1112
Girish Kumarf56a4682020-03-20 20:07:46 +00001113 logger.Debugw("downloadImage", log.Fields{"device-id": agent.deviceID})
khenaidoo6e55d9e2019-12-12 18:26:26 -05001114
1115 device := agent.getDeviceWithoutLock()
1116
npujar1d86a522019-11-14 17:11:16 +05301117 if device.AdminState != voltha.AdminState_ENABLED {
khenaidoo442e7c72020-03-10 16:13:48 -04001118 return nil, status.Errorf(codes.FailedPrecondition, "device-id:%s, expected-admin-state:%s", agent.deviceID, voltha.AdminState_ENABLED)
npujar1d86a522019-11-14 17:11:16 +05301119 }
1120 // Save the image
1121 clonedImg := proto.Clone(img).(*voltha.ImageDownload)
1122 clonedImg.DownloadState = voltha.ImageDownload_DOWNLOAD_REQUESTED
1123 cloned := proto.Clone(device).(*voltha.Device)
1124 if cloned.ImageDownloads == nil {
1125 cloned.ImageDownloads = []*voltha.ImageDownload{clonedImg}
khenaidoof5a5bfa2019-01-23 22:20:29 -05001126 } else {
1127 if device.AdminState != voltha.AdminState_ENABLED {
Girish Kumarf56a4682020-03-20 20:07:46 +00001128 logger.Debugw("device-not-enabled", log.Fields{"id": agent.deviceID})
npujar1d86a522019-11-14 17:11:16 +05301129 return nil, status.Errorf(codes.FailedPrecondition, "deviceId:%s, expected-admin-state:%s", agent.deviceID, voltha.AdminState_ENABLED)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001130 }
1131 // Save the image
1132 clonedImg := proto.Clone(img).(*voltha.ImageDownload)
Stephane Barbariedf5479f2019-01-29 22:13:00 -05001133 clonedImg.DownloadState = voltha.ImageDownload_DOWNLOAD_REQUESTED
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001134 if device.ImageDownloads == nil {
1135 device.ImageDownloads = []*voltha.ImageDownload{clonedImg}
khenaidoof5a5bfa2019-01-23 22:20:29 -05001136 } else {
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001137 device.ImageDownloads = append(device.ImageDownloads, clonedImg)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001138 }
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001139 if err := agent.updateDeviceStateInStoreWithoutLock(ctx, cloned, voltha.AdminState_DOWNLOADING_IMAGE, device.ConnectStatus, device.OperStatus); err != nil {
Mahir Gunyelb5851672019-07-24 10:46:26 +03001140 return nil, err
khenaidoof5a5bfa2019-01-23 22:20:29 -05001141 }
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001142
khenaidoof5a5bfa2019-01-23 22:20:29 -05001143 // Send the request to the adapter
khenaidoo442e7c72020-03-10 16:13:48 -04001144 subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
Kent Hagerman2b216042020-04-03 18:28:56 -04001145 ch, err := agent.adapterProxy.DownloadImage(ctx, cloned, clonedImg)
khenaidoo442e7c72020-03-10 16:13:48 -04001146 if err != nil {
1147 cancel()
khenaidoof5a5bfa2019-01-23 22:20:29 -05001148 return nil, err
1149 }
khenaidoo442e7c72020-03-10 16:13:48 -04001150 go agent.waitForAdapterResponse(subCtx, cancel, "downloadImage", ch, agent.onSuccess, agent.onFailure)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001151 }
1152 return &voltha.OperationResp{Code: voltha.OperationResp_OPERATION_SUCCESS}, nil
1153}
1154
1155// isImageRegistered is a helper method to figure out if an image is already registered
1156func isImageRegistered(img *voltha.ImageDownload, device *voltha.Device) bool {
1157 for _, image := range device.ImageDownloads {
1158 if image.Id == img.Id && image.Name == img.Name {
1159 return true
1160 }
1161 }
1162 return false
1163}
1164
Kent Hagerman2b216042020-04-03 18:28:56 -04001165func (agent *Agent) cancelImageDownload(ctx context.Context, img *voltha.ImageDownload) (*voltha.OperationResp, error) {
khenaidoo442e7c72020-03-10 16:13:48 -04001166 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1167 return nil, err
1168 }
1169 defer agent.requestQueue.RequestComplete()
1170
Girish Kumarf56a4682020-03-20 20:07:46 +00001171 logger.Debugw("cancelImageDownload", log.Fields{"device-id": agent.deviceID})
khenaidoo6e55d9e2019-12-12 18:26:26 -05001172
1173 device := agent.getDeviceWithoutLock()
1174
npujar1d86a522019-11-14 17:11:16 +05301175 // Verify whether the Image is in the list of image being downloaded
1176 if !isImageRegistered(img, device) {
khenaidoo442e7c72020-03-10 16:13:48 -04001177 return nil, status.Errorf(codes.FailedPrecondition, "device-id:%s, image-not-registered:%s", agent.deviceID, img.Name)
npujar1d86a522019-11-14 17:11:16 +05301178 }
khenaidoof5a5bfa2019-01-23 22:20:29 -05001179
npujar1d86a522019-11-14 17:11:16 +05301180 // Update image download state
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001181 for _, image := range device.ImageDownloads {
npujar1d86a522019-11-14 17:11:16 +05301182 if image.Id == img.Id && image.Name == img.Name {
1183 image.DownloadState = voltha.ImageDownload_DOWNLOAD_CANCELLED
khenaidoof5a5bfa2019-01-23 22:20:29 -05001184 }
npujar1d86a522019-11-14 17:11:16 +05301185 }
khenaidoof5a5bfa2019-01-23 22:20:29 -05001186
npujar1d86a522019-11-14 17:11:16 +05301187 if device.AdminState == voltha.AdminState_DOWNLOADING_IMAGE {
1188 // Set the device to Enabled
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001189 if err := agent.updateDeviceStateInStoreWithoutLock(ctx, device, voltha.AdminState_ENABLED, device.ConnectStatus, device.OperStatus); err != nil {
npujar1d86a522019-11-14 17:11:16 +05301190 return nil, err
1191 }
khenaidoo442e7c72020-03-10 16:13:48 -04001192 subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
Kent Hagerman2b216042020-04-03 18:28:56 -04001193 ch, err := agent.adapterProxy.CancelImageDownload(subCtx, device, img)
khenaidoo442e7c72020-03-10 16:13:48 -04001194 if err != nil {
1195 cancel()
npujar1d86a522019-11-14 17:11:16 +05301196 return nil, err
khenaidoof5a5bfa2019-01-23 22:20:29 -05001197 }
khenaidoo442e7c72020-03-10 16:13:48 -04001198 go agent.waitForAdapterResponse(subCtx, cancel, "cancelImageDownload", ch, agent.onSuccess, agent.onFailure)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001199 }
1200 return &voltha.OperationResp{Code: voltha.OperationResp_OPERATION_SUCCESS}, nil
serkant.uluderya334479d2019-04-10 08:26:15 -07001201}
khenaidoof5a5bfa2019-01-23 22:20:29 -05001202
Kent Hagerman2b216042020-04-03 18:28:56 -04001203func (agent *Agent) activateImage(ctx context.Context, img *voltha.ImageDownload) (*voltha.OperationResp, error) {
khenaidoo442e7c72020-03-10 16:13:48 -04001204 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1205 return nil, err
1206 }
1207 defer agent.requestQueue.RequestComplete()
Girish Kumarf56a4682020-03-20 20:07:46 +00001208 logger.Debugw("activateImage", log.Fields{"device-id": agent.deviceID})
khenaidoo6e55d9e2019-12-12 18:26:26 -05001209 cloned := agent.getDeviceWithoutLock()
1210
npujar1d86a522019-11-14 17:11:16 +05301211 // Verify whether the Image is in the list of image being downloaded
khenaidoo6e55d9e2019-12-12 18:26:26 -05001212 if !isImageRegistered(img, cloned) {
khenaidoo442e7c72020-03-10 16:13:48 -04001213 return nil, status.Errorf(codes.FailedPrecondition, "device-id:%s, image-not-registered:%s", agent.deviceID, img.Name)
npujar1d86a522019-11-14 17:11:16 +05301214 }
1215
khenaidoo6e55d9e2019-12-12 18:26:26 -05001216 if cloned.AdminState == voltha.AdminState_DOWNLOADING_IMAGE {
khenaidoo442e7c72020-03-10 16:13:48 -04001217 return nil, status.Errorf(codes.FailedPrecondition, "device-id:%s, device-in-downloading-state:%s", agent.deviceID, img.Name)
npujar1d86a522019-11-14 17:11:16 +05301218 }
1219 // Update image download state
npujar1d86a522019-11-14 17:11:16 +05301220 for _, image := range cloned.ImageDownloads {
1221 if image.Id == img.Id && image.Name == img.Name {
1222 image.ImageState = voltha.ImageDownload_IMAGE_ACTIVATING
1223 }
1224 }
1225 // Set the device to downloading_image
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001226 if err := agent.updateDeviceStateInStoreWithoutLock(ctx, cloned, voltha.AdminState_DOWNLOADING_IMAGE, cloned.ConnectStatus, cloned.OperStatus); err != nil {
npujar1d86a522019-11-14 17:11:16 +05301227 return nil, err
1228 }
1229
khenaidoo442e7c72020-03-10 16:13:48 -04001230 subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
Kent Hagerman2b216042020-04-03 18:28:56 -04001231 ch, err := agent.adapterProxy.ActivateImageUpdate(subCtx, proto.Clone(cloned).(*voltha.Device), img)
khenaidoo442e7c72020-03-10 16:13:48 -04001232 if err != nil {
1233 cancel()
npujar1d86a522019-11-14 17:11:16 +05301234 return nil, err
1235 }
khenaidoo442e7c72020-03-10 16:13:48 -04001236 go agent.waitForAdapterResponse(subCtx, cancel, "activateImageUpdate", ch, agent.onSuccess, agent.onFailure)
1237
npujar1d86a522019-11-14 17:11:16 +05301238 // The status of the AdminState will be changed following the update_download_status response from the adapter
1239 // The image name will also be removed from the device list
serkant.uluderya334479d2019-04-10 08:26:15 -07001240 return &voltha.OperationResp{Code: voltha.OperationResp_OPERATION_SUCCESS}, nil
1241}
khenaidoof5a5bfa2019-01-23 22:20:29 -05001242
Kent Hagerman2b216042020-04-03 18:28:56 -04001243func (agent *Agent) revertImage(ctx context.Context, img *voltha.ImageDownload) (*voltha.OperationResp, error) {
khenaidoo442e7c72020-03-10 16:13:48 -04001244 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1245 return nil, err
1246 }
1247 defer agent.requestQueue.RequestComplete()
Girish Kumarf56a4682020-03-20 20:07:46 +00001248 logger.Debugw("revertImage", log.Fields{"device-id": agent.deviceID})
khenaidoo6e55d9e2019-12-12 18:26:26 -05001249
1250 cloned := agent.getDeviceWithoutLock()
1251
npujar1d86a522019-11-14 17:11:16 +05301252 // Verify whether the Image is in the list of image being downloaded
khenaidoo6e55d9e2019-12-12 18:26:26 -05001253 if !isImageRegistered(img, cloned) {
npujar1d86a522019-11-14 17:11:16 +05301254 return nil, status.Errorf(codes.FailedPrecondition, "deviceId:%s, image-not-registered:%s", agent.deviceID, img.Name)
1255 }
khenaidoof5a5bfa2019-01-23 22:20:29 -05001256
khenaidoo6e55d9e2019-12-12 18:26:26 -05001257 if cloned.AdminState != voltha.AdminState_ENABLED {
npujar1d86a522019-11-14 17:11:16 +05301258 return nil, status.Errorf(codes.FailedPrecondition, "deviceId:%s, device-not-enabled-state:%s", agent.deviceID, img.Name)
1259 }
1260 // Update image download state
npujar1d86a522019-11-14 17:11:16 +05301261 for _, image := range cloned.ImageDownloads {
1262 if image.Id == img.Id && image.Name == img.Name {
1263 image.ImageState = voltha.ImageDownload_IMAGE_REVERTING
khenaidoof5a5bfa2019-01-23 22:20:29 -05001264 }
npujar1d86a522019-11-14 17:11:16 +05301265 }
Mahir Gunyelb5851672019-07-24 10:46:26 +03001266
npujar467fe752020-01-16 20:17:45 +05301267 if err := agent.updateDeviceInStoreWithoutLock(ctx, cloned, false, ""); err != nil {
npujar1d86a522019-11-14 17:11:16 +05301268 return nil, err
1269 }
khenaidoof5a5bfa2019-01-23 22:20:29 -05001270
khenaidoo442e7c72020-03-10 16:13:48 -04001271 subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
Kent Hagerman2b216042020-04-03 18:28:56 -04001272 ch, err := agent.adapterProxy.RevertImageUpdate(subCtx, proto.Clone(cloned).(*voltha.Device), img)
khenaidoo442e7c72020-03-10 16:13:48 -04001273 if err != nil {
1274 cancel()
npujar1d86a522019-11-14 17:11:16 +05301275 return nil, err
khenaidoof5a5bfa2019-01-23 22:20:29 -05001276 }
khenaidoo442e7c72020-03-10 16:13:48 -04001277 go agent.waitForAdapterResponse(subCtx, cancel, "revertImageUpdate", ch, agent.onSuccess, agent.onFailure)
1278
khenaidoof5a5bfa2019-01-23 22:20:29 -05001279 return &voltha.OperationResp{Code: voltha.OperationResp_OPERATION_SUCCESS}, nil
serkant.uluderya334479d2019-04-10 08:26:15 -07001280}
khenaidoof5a5bfa2019-01-23 22:20:29 -05001281
Kent Hagerman2b216042020-04-03 18:28:56 -04001282func (agent *Agent) getImageDownloadStatus(ctx context.Context, img *voltha.ImageDownload) (*voltha.ImageDownload, error) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001283 logger.Debugw("getImageDownloadStatus", log.Fields{"device-id": agent.deviceID})
khenaidoo6e55d9e2019-12-12 18:26:26 -05001284
khenaidoo442e7c72020-03-10 16:13:48 -04001285 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
npujar1d86a522019-11-14 17:11:16 +05301286 return nil, err
1287 }
khenaidoo442e7c72020-03-10 16:13:48 -04001288 device := agent.getDeviceWithoutLock()
Kent Hagerman2b216042020-04-03 18:28:56 -04001289 ch, err := agent.adapterProxy.GetImageDownloadStatus(ctx, device, img)
khenaidoo442e7c72020-03-10 16:13:48 -04001290 agent.requestQueue.RequestComplete()
1291 if err != nil {
1292 return nil, err
1293 }
1294 // Wait for the adapter response
1295 rpcResponse, ok := <-ch
1296 if !ok {
1297 return nil, status.Errorf(codes.Aborted, "channel-closed-device-id-%s", agent.deviceID)
1298 }
1299 if rpcResponse.Err != nil {
1300 return nil, rpcResponse.Err
1301 }
1302 // Successful response
1303 imgDownload := &voltha.ImageDownload{}
1304 if err := ptypes.UnmarshalAny(rpcResponse.Reply, imgDownload); err != nil {
1305 return nil, status.Errorf(codes.InvalidArgument, "%s", err.Error())
1306 }
1307 return imgDownload, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001308}
1309
Kent Hagerman2b216042020-04-03 18:28:56 -04001310func (agent *Agent) updateImageDownload(ctx context.Context, img *voltha.ImageDownload) error {
khenaidoo442e7c72020-03-10 16:13:48 -04001311 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1312 return err
1313 }
1314 defer agent.requestQueue.RequestComplete()
Girish Kumarf56a4682020-03-20 20:07:46 +00001315 logger.Debugw("updating-image-download", log.Fields{"device-id": agent.deviceID, "img": img})
khenaidoo6e55d9e2019-12-12 18:26:26 -05001316
1317 cloned := agent.getDeviceWithoutLock()
1318
npujar1d86a522019-11-14 17:11:16 +05301319 // Update the image as well as remove it if the download was cancelled
npujar1d86a522019-11-14 17:11:16 +05301320 clonedImages := make([]*voltha.ImageDownload, len(cloned.ImageDownloads))
1321 for _, image := range cloned.ImageDownloads {
1322 if image.Id == img.Id && image.Name == img.Name {
1323 if image.DownloadState != voltha.ImageDownload_DOWNLOAD_CANCELLED {
1324 clonedImages = append(clonedImages, img)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001325 }
1326 }
npujar1d86a522019-11-14 17:11:16 +05301327 }
1328 cloned.ImageDownloads = clonedImages
1329 // Set the Admin state to enabled if required
1330 if (img.DownloadState != voltha.ImageDownload_DOWNLOAD_REQUESTED &&
1331 img.DownloadState != voltha.ImageDownload_DOWNLOAD_STARTED) ||
1332 (img.ImageState != voltha.ImageDownload_IMAGE_ACTIVATING) {
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001333 return agent.updateDeviceStateInStoreWithoutLock(ctx, cloned, voltha.AdminState_ENABLED, cloned.ConnectStatus, cloned.OperStatus)
npujar1d86a522019-11-14 17:11:16 +05301334 }
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001335 return agent.updateDeviceInStoreWithoutLock(ctx, cloned, false, "")
khenaidoof5a5bfa2019-01-23 22:20:29 -05001336}
1337
Kent Hagerman2b216042020-04-03 18:28:56 -04001338func (agent *Agent) getImageDownload(ctx context.Context, img *voltha.ImageDownload) (*voltha.ImageDownload, error) {
khenaidoo442e7c72020-03-10 16:13:48 -04001339 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1340 return nil, err
1341 }
1342 defer agent.requestQueue.RequestComplete()
Girish Kumarf56a4682020-03-20 20:07:46 +00001343 logger.Debugw("getImageDownload", log.Fields{"device-id": agent.deviceID})
khenaidoo6e55d9e2019-12-12 18:26:26 -05001344
1345 cloned := agent.getDeviceWithoutLock()
1346 for _, image := range cloned.ImageDownloads {
npujar1d86a522019-11-14 17:11:16 +05301347 if image.Id == img.Id && image.Name == img.Name {
1348 return image, nil
1349 }
1350 }
1351 return nil, status.Errorf(codes.NotFound, "image-not-found:%s", img.Name)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001352}
1353
Kent Hagerman2b216042020-04-03 18:28:56 -04001354func (agent *Agent) listImageDownloads(ctx context.Context, deviceID string) (*voltha.ImageDownloads, error) {
khenaidoo442e7c72020-03-10 16:13:48 -04001355 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1356 return nil, err
1357 }
1358 defer agent.requestQueue.RequestComplete()
Girish Kumarf56a4682020-03-20 20:07:46 +00001359 logger.Debugw("listImageDownloads", log.Fields{"device-id": agent.deviceID})
khenaidoo6e55d9e2019-12-12 18:26:26 -05001360
1361 return &voltha.ImageDownloads{Items: agent.getDeviceWithoutLock().ImageDownloads}, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001362}
1363
khenaidoo4d4802d2018-10-04 21:59:49 -04001364// getPorts retrieves the ports information of the device based on the port type.
Kent Hagerman2b216042020-04-03 18:28:56 -04001365func (agent *Agent) getPorts(ctx context.Context, portType voltha.Port_PortType) *voltha.Ports {
Girish Kumarf56a4682020-03-20 20:07:46 +00001366 logger.Debugw("getPorts", log.Fields{"device-id": agent.deviceID, "port-type": portType})
khenaidoob9203542018-09-17 22:56:37 -04001367 ports := &voltha.Ports{}
Kent Hagerman45a13e42020-04-13 12:23:50 -04001368 if device, _ := agent.deviceMgr.getDevice(ctx, agent.deviceID); device != nil {
khenaidoob9203542018-09-17 22:56:37 -04001369 for _, port := range device.Ports {
khenaidoo92e62c52018-10-03 14:02:54 -04001370 if port.Type == portType {
khenaidoob9203542018-09-17 22:56:37 -04001371 ports.Items = append(ports.Items, port)
1372 }
1373 }
1374 }
1375 return ports
1376}
1377
khenaidoo442e7c72020-03-10 16:13:48 -04001378// getSwitchCapability retrieves the switch capability of a parent device
Kent Hagerman2b216042020-04-03 18:28:56 -04001379func (agent *Agent) getSwitchCapability(ctx context.Context) (*ic.SwitchCapability, error) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001380 logger.Debugw("getSwitchCapability", log.Fields{"device-id": agent.deviceID})
khenaidoo442e7c72020-03-10 16:13:48 -04001381
1382 cloned, err := agent.getDevice(ctx)
1383 if err != nil {
khenaidoob9203542018-09-17 22:56:37 -04001384 return nil, err
khenaidoob9203542018-09-17 22:56:37 -04001385 }
Kent Hagerman2b216042020-04-03 18:28:56 -04001386 ch, err := agent.adapterProxy.GetOfpDeviceInfo(ctx, cloned)
khenaidoo442e7c72020-03-10 16:13:48 -04001387 if err != nil {
1388 return nil, err
1389 }
1390
1391 // Wait for adapter response
1392 rpcResponse, ok := <-ch
1393 if !ok {
1394 return nil, status.Errorf(codes.Aborted, "channel-closed")
1395 }
1396 if rpcResponse.Err != nil {
1397 return nil, rpcResponse.Err
1398 }
1399 // Successful response
1400 switchCap := &ic.SwitchCapability{}
1401 if err := ptypes.UnmarshalAny(rpcResponse.Reply, switchCap); err != nil {
npujar1d86a522019-11-14 17:11:16 +05301402 return nil, err
1403 }
1404 return switchCap, nil
khenaidoob9203542018-09-17 22:56:37 -04001405}
1406
khenaidoo442e7c72020-03-10 16:13:48 -04001407// getPortCapability retrieves the port capability of a device
Kent Hagerman2b216042020-04-03 18:28:56 -04001408func (agent *Agent) getPortCapability(ctx context.Context, portNo uint32) (*ic.PortCapability, error) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001409 logger.Debugw("getPortCapability", log.Fields{"device-id": agent.deviceID})
khenaidoo442e7c72020-03-10 16:13:48 -04001410 device, err := agent.getDevice(ctx)
1411 if err != nil {
khenaidoob9203542018-09-17 22:56:37 -04001412 return nil, err
khenaidoob9203542018-09-17 22:56:37 -04001413 }
Kent Hagerman2b216042020-04-03 18:28:56 -04001414 ch, err := agent.adapterProxy.GetOfpPortInfo(ctx, device, portNo)
khenaidoo442e7c72020-03-10 16:13:48 -04001415 if err != nil {
npujar1d86a522019-11-14 17:11:16 +05301416 return nil, err
1417 }
khenaidoo442e7c72020-03-10 16:13:48 -04001418 // Wait for adapter response
1419 rpcResponse, ok := <-ch
1420 if !ok {
1421 return nil, status.Errorf(codes.Aborted, "channel-closed")
1422 }
1423 if rpcResponse.Err != nil {
1424 return nil, rpcResponse.Err
1425 }
1426 // Successful response
1427 portCap := &ic.PortCapability{}
1428 if err := ptypes.UnmarshalAny(rpcResponse.Reply, portCap); err != nil {
1429 return nil, status.Errorf(codes.InvalidArgument, "%s", err.Error())
1430 }
npujar1d86a522019-11-14 17:11:16 +05301431 return portCap, nil
khenaidoob9203542018-09-17 22:56:37 -04001432}
1433
Kent Hagerman2b216042020-04-03 18:28:56 -04001434func (agent *Agent) onPacketFailure(rpc string, response interface{}, args ...interface{}) {
khenaidoo442e7c72020-03-10 16:13:48 -04001435 // packet data is encoded in the args param as the first parameter
1436 var packet []byte
1437 if len(args) >= 1 {
1438 if pkt, ok := args[0].([]byte); ok {
1439 packet = pkt
1440 }
1441 }
1442 var errResp error
1443 if err, ok := response.(error); ok {
1444 errResp = err
1445 }
Girish Kumarf56a4682020-03-20 20:07:46 +00001446 logger.Warnw("packet-out-error", log.Fields{
khenaidoo442e7c72020-03-10 16:13:48 -04001447 "device-id": agent.deviceID,
1448 "error": errResp,
1449 "packet": hex.EncodeToString(packet),
1450 })
1451}
1452
Kent Hagerman2b216042020-04-03 18:28:56 -04001453func (agent *Agent) packetOut(ctx context.Context, outPort uint32, packet *ofp.OfpPacketOut) error {
Scott Baker80678602019-11-14 16:57:36 -08001454 // If deviceType=="" then we must have taken ownership of this device.
1455 // Fixes VOL-2226 where a core would take ownership and have stale data
1456 if agent.deviceType == "" {
npujar467fe752020-01-16 20:17:45 +05301457 agent.reconcileWithKVStore(ctx)
Scott Baker80678602019-11-14 16:57:36 -08001458 }
khenaidoofdbad6e2018-11-06 22:26:38 -05001459 // Send packet to adapter
khenaidoo442e7c72020-03-10 16:13:48 -04001460 subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
Kent Hagerman2b216042020-04-03 18:28:56 -04001461 ch, err := agent.adapterProxy.PacketOut(subCtx, agent.deviceType, agent.deviceID, outPort, packet)
khenaidoo442e7c72020-03-10 16:13:48 -04001462 if err != nil {
1463 cancel()
1464 return nil
khenaidoofdbad6e2018-11-06 22:26:38 -05001465 }
khenaidoo442e7c72020-03-10 16:13:48 -04001466 go agent.waitForAdapterResponse(subCtx, cancel, "packetOut", ch, agent.onSuccess, agent.onPacketFailure, packet.Data)
khenaidoofdbad6e2018-11-06 22:26:38 -05001467 return nil
1468}
1469
Mahir Gunyel8e2707d2019-07-25 00:36:21 -07001470// updatePartialDeviceData updates a subset of a device that an Adapter can update.
1471// TODO: May need a specific proto to handle only a subset of a device that can be changed by an adapter
Kent Hagerman2b216042020-04-03 18:28:56 -04001472func (agent *Agent) mergeDeviceInfoFromAdapter(device *voltha.Device) (*voltha.Device, error) {
khenaidoo6e55d9e2019-12-12 18:26:26 -05001473 cloned := agent.getDeviceWithoutLock()
Mahir Gunyel8e2707d2019-07-25 00:36:21 -07001474 cloned.Root = device.Root
1475 cloned.Vendor = device.Vendor
1476 cloned.Model = device.Model
1477 cloned.SerialNumber = device.SerialNumber
1478 cloned.MacAddress = device.MacAddress
1479 cloned.Vlan = device.Vlan
1480 cloned.Reason = device.Reason
1481 return cloned, nil
1482}
khenaidoo442e7c72020-03-10 16:13:48 -04001483
Kent Hagerman2b216042020-04-03 18:28:56 -04001484func (agent *Agent) updateDeviceUsingAdapterData(ctx context.Context, device *voltha.Device) error {
khenaidoo442e7c72020-03-10 16:13:48 -04001485 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1486 return err
1487 }
1488 defer agent.requestQueue.RequestComplete()
Girish Kumarf56a4682020-03-20 20:07:46 +00001489 logger.Debugw("updateDeviceUsingAdapterData", log.Fields{"device-id": device.Id})
khenaidoo442e7c72020-03-10 16:13:48 -04001490
npujar1d86a522019-11-14 17:11:16 +05301491 updatedDevice, err := agent.mergeDeviceInfoFromAdapter(device)
1492 if err != nil {
Mahir Gunyel8e2707d2019-07-25 00:36:21 -07001493 return status.Errorf(codes.Internal, "%s", err.Error())
Mahir Gunyel8e2707d2019-07-25 00:36:21 -07001494 }
npujar1d86a522019-11-14 17:11:16 +05301495 cloned := proto.Clone(updatedDevice).(*voltha.Device)
npujar467fe752020-01-16 20:17:45 +05301496 return agent.updateDeviceInStoreWithoutLock(ctx, cloned, false, "")
khenaidoo43c82122018-11-22 18:38:28 -05001497}
1498
Kent Hagerman2b216042020-04-03 18:28:56 -04001499func (agent *Agent) updateDeviceStatus(ctx context.Context, operStatus voltha.OperStatus_Types, connStatus voltha.ConnectStatus_Types) error {
khenaidoo442e7c72020-03-10 16:13:48 -04001500 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1501 return err
1502 }
1503 defer agent.requestQueue.RequestComplete()
khenaidoo6e55d9e2019-12-12 18:26:26 -05001504
1505 cloned := agent.getDeviceWithoutLock()
1506
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001507 newConnStatus, newOperStatus := cloned.ConnectStatus, cloned.OperStatus
npujar1d86a522019-11-14 17:11:16 +05301508 // Ensure the enums passed in are valid - they will be invalid if they are not set when this function is invoked
serkant.uluderya2ae470f2020-01-21 11:13:09 -08001509 if s, ok := voltha.ConnectStatus_Types_value[connStatus.String()]; ok {
Girish Kumarf56a4682020-03-20 20:07:46 +00001510 logger.Debugw("updateDeviceStatus-conn", log.Fields{"ok": ok, "val": s})
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001511 newConnStatus = connStatus
npujar1d86a522019-11-14 17:11:16 +05301512 }
serkant.uluderya2ae470f2020-01-21 11:13:09 -08001513 if s, ok := voltha.OperStatus_Types_value[operStatus.String()]; ok {
Girish Kumarf56a4682020-03-20 20:07:46 +00001514 logger.Debugw("updateDeviceStatus-oper", log.Fields{"ok": ok, "val": s})
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001515 newOperStatus = operStatus
npujar1d86a522019-11-14 17:11:16 +05301516 }
Girish Kumarf56a4682020-03-20 20:07:46 +00001517 logger.Debugw("updateDeviceStatus", log.Fields{"deviceId": cloned.Id, "operStatus": cloned.OperStatus, "connectStatus": cloned.ConnectStatus})
npujar1d86a522019-11-14 17:11:16 +05301518 // Store the device
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001519 return agent.updateDeviceStateInStoreWithoutLock(ctx, cloned, cloned.AdminState, newConnStatus, newOperStatus)
khenaidoo92e62c52018-10-03 14:02:54 -04001520}
1521
Kent Hagerman2b216042020-04-03 18:28:56 -04001522func (agent *Agent) updatePortsOperState(ctx context.Context, operStatus voltha.OperStatus_Types) error {
Girish Kumarf56a4682020-03-20 20:07:46 +00001523 logger.Debugw("updatePortsOperState", log.Fields{"device-id": agent.deviceID})
khenaidoo442e7c72020-03-10 16:13:48 -04001524 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1525 return err
1526 }
1527 defer agent.requestQueue.RequestComplete()
khenaidoo6e55d9e2019-12-12 18:26:26 -05001528 cloned := agent.getDeviceWithoutLock()
npujar1d86a522019-11-14 17:11:16 +05301529 for _, port := range cloned.Ports {
kesavandbc2d1622020-01-21 00:42:01 -05001530 port.OperStatus = operStatus
npujar1d86a522019-11-14 17:11:16 +05301531 }
1532 // Store the device
npujar467fe752020-01-16 20:17:45 +05301533 return agent.updateDeviceInStoreWithoutLock(ctx, cloned, false, "")
khenaidoo3ab34882019-05-02 21:33:30 -04001534}
1535
Kent Hagerman2b216042020-04-03 18:28:56 -04001536func (agent *Agent) updatePortState(ctx context.Context, portType voltha.Port_PortType, portNo uint32, operStatus voltha.OperStatus_Types) error {
khenaidoo442e7c72020-03-10 16:13:48 -04001537 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1538 return err
1539 }
1540 defer agent.requestQueue.RequestComplete()
khenaidoo92e62c52018-10-03 14:02:54 -04001541 // Work only on latest data
1542 // TODO: Get list of ports from device directly instead of the entire device
khenaidoo6e55d9e2019-12-12 18:26:26 -05001543 cloned := agent.getDeviceWithoutLock()
1544
npujar1d86a522019-11-14 17:11:16 +05301545 // Ensure the enums passed in are valid - they will be invalid if they are not set when this function is invoked
1546 if _, ok := voltha.Port_PortType_value[portType.String()]; !ok {
1547 return status.Errorf(codes.InvalidArgument, "%s", portType)
1548 }
1549 for _, port := range cloned.Ports {
1550 if port.Type == portType && port.PortNo == portNo {
1551 port.OperStatus = operStatus
npujar1d86a522019-11-14 17:11:16 +05301552 }
1553 }
Girish Kumarf56a4682020-03-20 20:07:46 +00001554 logger.Debugw("portStatusUpdate", log.Fields{"deviceId": cloned.Id})
npujar1d86a522019-11-14 17:11:16 +05301555 // Store the device
npujar467fe752020-01-16 20:17:45 +05301556 return agent.updateDeviceInStoreWithoutLock(ctx, cloned, false, "")
khenaidoob9203542018-09-17 22:56:37 -04001557}
1558
Kent Hagerman2b216042020-04-03 18:28:56 -04001559func (agent *Agent) deleteAllPorts(ctx context.Context) error {
Girish Kumarf56a4682020-03-20 20:07:46 +00001560 logger.Debugw("deleteAllPorts", log.Fields{"deviceId": agent.deviceID})
khenaidoo442e7c72020-03-10 16:13:48 -04001561 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1562 return err
1563 }
1564 defer agent.requestQueue.RequestComplete()
khenaidoo6e55d9e2019-12-12 18:26:26 -05001565
1566 cloned := agent.getDeviceWithoutLock()
1567
1568 if cloned.AdminState != voltha.AdminState_DISABLED && cloned.AdminState != voltha.AdminState_DELETED {
1569 err := status.Error(codes.FailedPrecondition, fmt.Sprintf("invalid-state-%v", cloned.AdminState))
Girish Kumarf56a4682020-03-20 20:07:46 +00001570 logger.Warnw("invalid-state-removing-ports", log.Fields{"state": cloned.AdminState, "error": err})
npujar1d86a522019-11-14 17:11:16 +05301571 return err
1572 }
khenaidoo6e55d9e2019-12-12 18:26:26 -05001573 if len(cloned.Ports) == 0 {
Girish Kumarf56a4682020-03-20 20:07:46 +00001574 logger.Debugw("no-ports-present", log.Fields{"deviceId": agent.deviceID})
npujar1d86a522019-11-14 17:11:16 +05301575 return nil
1576 }
khenaidoo6e55d9e2019-12-12 18:26:26 -05001577
npujar1d86a522019-11-14 17:11:16 +05301578 cloned.Ports = []*voltha.Port{}
Girish Kumarf56a4682020-03-20 20:07:46 +00001579 logger.Debugw("portStatusUpdate", log.Fields{"deviceId": cloned.Id})
npujar1d86a522019-11-14 17:11:16 +05301580 // Store the device
npujar467fe752020-01-16 20:17:45 +05301581 return agent.updateDeviceInStoreWithoutLock(ctx, cloned, false, "")
khenaidoo0a822f92019-05-08 15:15:57 -04001582}
1583
Kent Hagerman2b216042020-04-03 18:28:56 -04001584func (agent *Agent) addPort(ctx context.Context, port *voltha.Port) error {
khenaidoo442e7c72020-03-10 16:13:48 -04001585 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1586 return err
1587 }
1588 defer agent.requestQueue.RequestComplete()
Girish Kumarf56a4682020-03-20 20:07:46 +00001589 logger.Debugw("addPort", log.Fields{"deviceId": agent.deviceID})
khenaidoo6e55d9e2019-12-12 18:26:26 -05001590
1591 cloned := agent.getDeviceWithoutLock()
khenaidoo80b987d2020-02-20 10:52:52 -05001592 updatePort := false
npujar1d86a522019-11-14 17:11:16 +05301593 if cloned.Ports == nil {
1594 // First port
Girish Kumarf56a4682020-03-20 20:07:46 +00001595 logger.Debugw("addPort-first-port-to-add", log.Fields{"deviceId": agent.deviceID})
npujar1d86a522019-11-14 17:11:16 +05301596 cloned.Ports = make([]*voltha.Port, 0)
khenaidoob9203542018-09-17 22:56:37 -04001597 } else {
npujar1d86a522019-11-14 17:11:16 +05301598 for _, p := range cloned.Ports {
1599 if p.Type == port.Type && p.PortNo == port.PortNo {
khenaidoo80b987d2020-02-20 10:52:52 -05001600 if p.Label == "" && p.Type == voltha.Port_PON_OLT {
1601 //Creation of OLT PON port is being processed after a default PON port was created. Just update it.
Girish Kumarf56a4682020-03-20 20:07:46 +00001602 logger.Infow("update-pon-port-created-by-default", log.Fields{"default-port": p, "port-to-add": port})
khenaidoo80b987d2020-02-20 10:52:52 -05001603 p.Label = port.Label
1604 p.OperStatus = port.OperStatus
1605 updatePort = true
1606 break
1607 }
Girish Kumarf56a4682020-03-20 20:07:46 +00001608 logger.Debugw("port already exists", log.Fields{"port": port})
npujar1d86a522019-11-14 17:11:16 +05301609 return nil
manikkaraj k259a6f72019-05-06 09:55:44 -04001610 }
khenaidoob9203542018-09-17 22:56:37 -04001611 }
khenaidoo92e62c52018-10-03 14:02:54 -04001612 }
khenaidoo80b987d2020-02-20 10:52:52 -05001613 if !updatePort {
1614 cp := proto.Clone(port).(*voltha.Port)
1615 // Set the admin state of the port to ENABLE
1616 cp.AdminState = voltha.AdminState_ENABLED
1617 cloned.Ports = append(cloned.Ports, cp)
1618 }
npujar1d86a522019-11-14 17:11:16 +05301619 // Store the device
npujar467fe752020-01-16 20:17:45 +05301620 return agent.updateDeviceInStoreWithoutLock(ctx, cloned, false, "")
khenaidoo92e62c52018-10-03 14:02:54 -04001621}
1622
Kent Hagerman2b216042020-04-03 18:28:56 -04001623func (agent *Agent) addPeerPort(ctx context.Context, peerPort *voltha.Port_PeerPort) error {
khenaidoo442e7c72020-03-10 16:13:48 -04001624 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1625 return err
1626 }
1627 defer agent.requestQueue.RequestComplete()
Girish Kumarf56a4682020-03-20 20:07:46 +00001628 logger.Debugw("adding-peer-peerPort", log.Fields{"device-id": agent.deviceID, "peer-peerPort": peerPort})
khenaidoo6e55d9e2019-12-12 18:26:26 -05001629
1630 cloned := agent.getDeviceWithoutLock()
1631
khenaidoo80b987d2020-02-20 10:52:52 -05001632 // Get the peer port on the device based on the peerPort no
1633 found := false
1634 for _, port := range cloned.Ports {
1635 if port.PortNo == peerPort.PortNo { // found peerPort
1636 cp := proto.Clone(peerPort).(*voltha.Port_PeerPort)
1637 port.Peers = append(port.Peers, cp)
Girish Kumarf56a4682020-03-20 20:07:46 +00001638 logger.Debugw("found-peer", log.Fields{"device-id": agent.deviceID, "portNo": peerPort.PortNo, "deviceId": agent.deviceID})
khenaidoo80b987d2020-02-20 10:52:52 -05001639 found = true
npujar1d86a522019-11-14 17:11:16 +05301640 break
1641 }
1642 }
khenaidoo80b987d2020-02-20 10:52:52 -05001643 if !found && agent.isRootdevice {
1644 // An ONU PON port has been created before the corresponding creation of the OLT PON port. Create the OLT PON port
1645 // with default values which will be updated once the OLT PON port creation is processed.
1646 ponPort := &voltha.Port{
1647 PortNo: peerPort.PortNo,
1648 Type: voltha.Port_PON_OLT,
1649 AdminState: voltha.AdminState_ENABLED,
1650 DeviceId: agent.deviceID,
1651 Peers: []*voltha.Port_PeerPort{proto.Clone(peerPort).(*voltha.Port_PeerPort)},
1652 }
1653 cloned.Ports = append(cloned.Ports, ponPort)
Girish Kumarf56a4682020-03-20 20:07:46 +00001654 logger.Infow("adding-default-pon-port", log.Fields{"device-id": agent.deviceID, "peer": peerPort, "pon-port": ponPort})
khenaidoo80b987d2020-02-20 10:52:52 -05001655 }
khenaidoo0db4c812020-05-27 15:27:30 -04001656
npujar1d86a522019-11-14 17:11:16 +05301657 // Store the device
npujar467fe752020-01-16 20:17:45 +05301658 return agent.updateDeviceInStoreWithoutLock(ctx, cloned, false, "")
khenaidoob9203542018-09-17 22:56:37 -04001659}
1660
1661// TODO: A generic device update by attribute
Kent Hagerman2b216042020-04-03 18:28:56 -04001662func (agent *Agent) updateDeviceAttribute(ctx context.Context, name string, value interface{}) {
khenaidoo442e7c72020-03-10 16:13:48 -04001663 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001664 logger.Warnw("request-aborted", log.Fields{"device-id": agent.deviceID, "name": name, "error": err})
khenaidoo442e7c72020-03-10 16:13:48 -04001665 return
1666 }
1667 defer agent.requestQueue.RequestComplete()
khenaidoob9203542018-09-17 22:56:37 -04001668 if value == nil {
1669 return
1670 }
khenaidoo6e55d9e2019-12-12 18:26:26 -05001671
1672 cloned := agent.getDeviceWithoutLock()
khenaidoob9203542018-09-17 22:56:37 -04001673 updated := false
khenaidoo6e55d9e2019-12-12 18:26:26 -05001674 s := reflect.ValueOf(cloned).Elem()
khenaidoob9203542018-09-17 22:56:37 -04001675 if s.Kind() == reflect.Struct {
1676 // exported field
1677 f := s.FieldByName(name)
1678 if f.IsValid() && f.CanSet() {
1679 switch f.Kind() {
1680 case reflect.String:
1681 f.SetString(value.(string))
1682 updated = true
1683 case reflect.Uint32:
1684 f.SetUint(uint64(value.(uint32)))
1685 updated = true
1686 case reflect.Bool:
1687 f.SetBool(value.(bool))
1688 updated = true
1689 }
1690 }
1691 }
Girish Kumarf56a4682020-03-20 20:07:46 +00001692 logger.Debugw("update-field-status", log.Fields{"deviceId": cloned.Id, "name": name, "updated": updated})
khenaidoob9203542018-09-17 22:56:37 -04001693 // Save the data
khenaidoo6e55d9e2019-12-12 18:26:26 -05001694
npujar467fe752020-01-16 20:17:45 +05301695 if err := agent.updateDeviceInStoreWithoutLock(ctx, cloned, false, ""); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001696 logger.Warnw("attribute-update-failed", log.Fields{"attribute": name, "value": value})
khenaidoob9203542018-09-17 22:56:37 -04001697 }
khenaidoob9203542018-09-17 22:56:37 -04001698}
serkant.uluderya334479d2019-04-10 08:26:15 -07001699
Kent Hagerman45a13e42020-04-13 12:23:50 -04001700func (agent *Agent) simulateAlarm(ctx context.Context, simulateReq *voltha.SimulateAlarmRequest) error {
khenaidoo442e7c72020-03-10 16:13:48 -04001701 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1702 return err
1703 }
1704 defer agent.requestQueue.RequestComplete()
Girish Kumarf56a4682020-03-20 20:07:46 +00001705 logger.Debugw("simulateAlarm", log.Fields{"id": agent.deviceID})
khenaidoo6e55d9e2019-12-12 18:26:26 -05001706
1707 cloned := agent.getDeviceWithoutLock()
1708
khenaidoo442e7c72020-03-10 16:13:48 -04001709 subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
Kent Hagerman45a13e42020-04-13 12:23:50 -04001710 ch, err := agent.adapterProxy.SimulateAlarm(subCtx, cloned, simulateReq)
khenaidoo442e7c72020-03-10 16:13:48 -04001711 if err != nil {
1712 cancel()
npujar1d86a522019-11-14 17:11:16 +05301713 return err
serkant.uluderya334479d2019-04-10 08:26:15 -07001714 }
khenaidoo442e7c72020-03-10 16:13:48 -04001715 go agent.waitForAdapterResponse(subCtx, cancel, "simulateAlarm", ch, agent.onSuccess, agent.onFailure)
serkant.uluderya334479d2019-04-10 08:26:15 -07001716 return nil
1717}
Mahir Gunyelb5851672019-07-24 10:46:26 +03001718
Kent Hagerman2b216042020-04-03 18:28:56 -04001719func (agent *Agent) updateDeviceStateInStoreWithoutLock(
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001720 ctx context.Context,
1721 device *voltha.Device,
1722 adminState voltha.AdminState_Types,
1723 connectStatus voltha.ConnectStatus_Types,
1724 operStatus voltha.OperStatus_Types,
1725) error {
1726 previousState := getDeviceStates(device)
1727 device.AdminState, device.ConnectStatus, device.OperStatus = adminState, connectStatus, operStatus
1728
1729 if err := agent.updateDeviceInStoreWithoutLock(ctx, device, false, ""); err != nil {
1730 return err
1731 }
1732
1733 // process state transition in its own thread
1734 go func() {
1735 if err := agent.deviceMgr.processTransition(context.Background(), device, previousState); err != nil {
1736 log.Errorw("failed-process-transition", log.Fields{"deviceId": device.Id, "previousAdminState": previousState.Admin, "currentAdminState": device.AdminState})
1737 }
1738 }()
1739 return nil
1740}
1741
Mahir Gunyelb5851672019-07-24 10:46:26 +03001742//This is an update operation to model without Lock.This function must never be invoked by another function unless the latter holds a lock on the device.
1743// It is an internal helper function.
Kent Hagerman2b216042020-04-03 18:28:56 -04001744func (agent *Agent) updateDeviceInStoreWithoutLock(ctx context.Context, device *voltha.Device, strict bool, txid string) error {
Kent Hagerman4f355f52020-03-30 16:01:33 -04001745 if agent.stopped {
1746 return errors.New("device agent stopped")
Thomas Lee Se5a44012019-11-07 20:32:24 +05301747 }
Kent Hagerman4f355f52020-03-30 16:01:33 -04001748
Kent Hagermanf5a67352020-04-30 15:15:26 -04001749 if err := agent.dbProxy.Set(ctx, agent.deviceID, device); err != nil {
Kent Hagerman4f355f52020-03-30 16:01:33 -04001750 return status.Errorf(codes.Internal, "failed-update-device:%s: %s", agent.deviceID, err)
Mahir Gunyelb5851672019-07-24 10:46:26 +03001751 }
Girish Kumarf56a4682020-03-20 20:07:46 +00001752 logger.Debugw("updated-device-in-store", log.Fields{"deviceId: ": agent.deviceID})
Mahir Gunyelb5851672019-07-24 10:46:26 +03001753
khenaidoo0db4c812020-05-27 15:27:30 -04001754 agent.device = device
Mahir Gunyelb5851672019-07-24 10:46:26 +03001755 return nil
1756}
Mahir Gunyelfdee9212019-10-16 16:52:21 -07001757
Kent Hagerman2b216042020-04-03 18:28:56 -04001758func (agent *Agent) updateDeviceReason(ctx context.Context, reason string) error {
khenaidoo442e7c72020-03-10 16:13:48 -04001759 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1760 return err
1761 }
1762 defer agent.requestQueue.RequestComplete()
khenaidoo6e55d9e2019-12-12 18:26:26 -05001763
1764 cloned := agent.getDeviceWithoutLock()
npujar1d86a522019-11-14 17:11:16 +05301765 cloned.Reason = reason
Girish Kumarf56a4682020-03-20 20:07:46 +00001766 logger.Debugw("updateDeviceReason", log.Fields{"deviceId": cloned.Id, "reason": cloned.Reason})
npujar1d86a522019-11-14 17:11:16 +05301767 // Store the device
npujar467fe752020-01-16 20:17:45 +05301768 return agent.updateDeviceInStoreWithoutLock(ctx, cloned, false, "")
Mahir Gunyelfdee9212019-10-16 16:52:21 -07001769}
kesavandbc2d1622020-01-21 00:42:01 -05001770
Kent Hagerman2b216042020-04-03 18:28:56 -04001771func (agent *Agent) disablePort(ctx context.Context, Port *voltha.Port) error {
khenaidoo442e7c72020-03-10 16:13:48 -04001772 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1773 return err
1774 }
1775 defer agent.requestQueue.RequestComplete()
Girish Kumarf56a4682020-03-20 20:07:46 +00001776 logger.Debugw("disablePort", log.Fields{"device-id": agent.deviceID, "port-no": Port.PortNo})
khenaidoo442e7c72020-03-10 16:13:48 -04001777 var cp *voltha.Port
kesavandbc2d1622020-01-21 00:42:01 -05001778 // Get the most up to date the device info
1779 device := agent.getDeviceWithoutLock()
1780 for _, port := range device.Ports {
1781 if port.PortNo == Port.PortNo {
1782 port.AdminState = voltha.AdminState_DISABLED
1783 cp = proto.Clone(port).(*voltha.Port)
1784 break
1785
1786 }
1787 }
1788 if cp == nil {
1789 return status.Errorf(codes.InvalidArgument, "%v", Port.PortNo)
1790 }
1791
1792 if cp.Type != voltha.Port_PON_OLT {
1793 return status.Errorf(codes.InvalidArgument, "Disabling of Port Type %v unimplemented", cp.Type)
1794 }
1795 // Store the device
1796 if err := agent.updateDeviceInStoreWithoutLock(ctx, device, false, ""); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001797 logger.Debugw("updateDeviceInStoreWithoutLock error ", log.Fields{"device-id": agent.deviceID, "port-no": Port.PortNo, "error": err})
kesavandbc2d1622020-01-21 00:42:01 -05001798 return err
1799 }
khenaidoo442e7c72020-03-10 16:13:48 -04001800
kesavandbc2d1622020-01-21 00:42:01 -05001801 //send request to adapter
khenaidoo442e7c72020-03-10 16:13:48 -04001802 subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
Kent Hagerman2b216042020-04-03 18:28:56 -04001803 ch, err := agent.adapterProxy.DisablePort(ctx, device, cp)
khenaidoo442e7c72020-03-10 16:13:48 -04001804 if err != nil {
1805 cancel()
kesavandbc2d1622020-01-21 00:42:01 -05001806 return err
1807 }
khenaidoo442e7c72020-03-10 16:13:48 -04001808 go agent.waitForAdapterResponse(subCtx, cancel, "disablePort", ch, agent.onSuccess, agent.onFailure)
kesavandbc2d1622020-01-21 00:42:01 -05001809 return nil
1810}
1811
Kent Hagerman2b216042020-04-03 18:28:56 -04001812func (agent *Agent) enablePort(ctx context.Context, Port *voltha.Port) error {
khenaidoo442e7c72020-03-10 16:13:48 -04001813 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1814 return err
1815 }
1816 defer agent.requestQueue.RequestComplete()
Girish Kumarf56a4682020-03-20 20:07:46 +00001817 logger.Debugw("enablePort", log.Fields{"device-id": agent.deviceID, "port-no": Port.PortNo})
khenaidoo442e7c72020-03-10 16:13:48 -04001818
1819 var cp *voltha.Port
kesavandbc2d1622020-01-21 00:42:01 -05001820 // Get the most up to date the device info
1821 device := agent.getDeviceWithoutLock()
1822 for _, port := range device.Ports {
1823 if port.PortNo == Port.PortNo {
1824 port.AdminState = voltha.AdminState_ENABLED
1825 cp = proto.Clone(port).(*voltha.Port)
1826 break
1827 }
1828 }
1829
1830 if cp == nil {
1831 return status.Errorf(codes.InvalidArgument, "%v", Port.PortNo)
1832 }
1833
1834 if cp.Type != voltha.Port_PON_OLT {
1835 return status.Errorf(codes.InvalidArgument, "Enabling of Port Type %v unimplemented", cp.Type)
1836 }
1837 // Store the device
1838 if err := agent.updateDeviceInStoreWithoutLock(ctx, device, false, ""); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001839 logger.Debugw("updateDeviceInStoreWithoutLock error ", log.Fields{"device-id": agent.deviceID, "port-no": Port.PortNo, "error": err})
kesavandbc2d1622020-01-21 00:42:01 -05001840 return err
1841 }
1842 //send request to adapter
khenaidoo442e7c72020-03-10 16:13:48 -04001843 subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
Kent Hagerman2b216042020-04-03 18:28:56 -04001844 ch, err := agent.adapterProxy.EnablePort(ctx, device, cp)
khenaidoo442e7c72020-03-10 16:13:48 -04001845 if err != nil {
1846 cancel()
kesavandbc2d1622020-01-21 00:42:01 -05001847 return err
1848 }
khenaidoo442e7c72020-03-10 16:13:48 -04001849 go agent.waitForAdapterResponse(subCtx, cancel, "enablePort", ch, agent.onSuccess, agent.onFailure)
kesavandbc2d1622020-01-21 00:42:01 -05001850 return nil
1851}
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001852
Kent Hagerman2b216042020-04-03 18:28:56 -04001853func (agent *Agent) ChildDeviceLost(ctx context.Context, device *voltha.Device) error {
khenaidoo442e7c72020-03-10 16:13:48 -04001854 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1855 return err
1856 }
1857 defer agent.requestQueue.RequestComplete()
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001858
Girish Kumarf56a4682020-03-20 20:07:46 +00001859 logger.Debugw("childDeviceLost", log.Fields{"child-device-id": device.Id, "parent-device-ud": agent.deviceID})
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001860
1861 //Remove the associated peer ports on the parent device
khenaidoo442e7c72020-03-10 16:13:48 -04001862 parentDevice := agent.getDeviceWithoutLock()
1863 var updatedPeers []*voltha.Port_PeerPort
1864 for _, port := range parentDevice.Ports {
1865 updatedPeers = make([]*voltha.Port_PeerPort, 0)
1866 for _, peerPort := range port.Peers {
1867 if peerPort.DeviceId != device.Id {
1868 updatedPeers = append(updatedPeers, peerPort)
1869 }
1870 }
1871 port.Peers = updatedPeers
1872 }
1873 if err := agent.updateDeviceInStoreWithoutLock(ctx, parentDevice, false, ""); err != nil {
1874 return err
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001875 }
1876
khenaidoo442e7c72020-03-10 16:13:48 -04001877 //send request to adapter
1878 subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
Kent Hagerman2b216042020-04-03 18:28:56 -04001879 ch, err := agent.adapterProxy.ChildDeviceLost(ctx, agent.deviceType, agent.deviceID, device.ParentPortNo, device.ProxyAddress.OnuId)
khenaidoo442e7c72020-03-10 16:13:48 -04001880 if err != nil {
1881 cancel()
1882 return err
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001883 }
khenaidoo442e7c72020-03-10 16:13:48 -04001884 go agent.waitForAdapterResponse(subCtx, cancel, "childDeviceLost", ch, agent.onSuccess, agent.onFailure)
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001885 return nil
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001886}
onkarkundargi87285252020-01-27 11:34:52 +05301887
Kent Hagerman2b216042020-04-03 18:28:56 -04001888func (agent *Agent) startOmciTest(ctx context.Context, omcitestrequest *voltha.OmciTestRequest) (*voltha.TestResponse, error) {
onkarkundargi87285252020-01-27 11:34:52 +05301889 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1890 return nil, err
1891 }
1892
1893 device := agent.getDeviceWithoutLock()
Matteo Scandolod525ae32020-04-02 17:27:29 -07001894
1895 if device.Adapter == "" {
Kent Hagerman2b216042020-04-03 18:28:56 -04001896 adapterName, err := agent.adapterMgr.GetAdapterType(device.Type)
Matteo Scandolod525ae32020-04-02 17:27:29 -07001897 if err != nil {
1898 agent.requestQueue.RequestComplete()
1899 return nil, err
1900 }
Matteo Scandolod525ae32020-04-02 17:27:29 -07001901 device.Adapter = adapterName
onkarkundargi87285252020-01-27 11:34:52 +05301902 }
1903
1904 // Send request to the adapter
Kent Hagerman2b216042020-04-03 18:28:56 -04001905 ch, err := agent.adapterProxy.StartOmciTest(ctx, device, omcitestrequest)
onkarkundargi87285252020-01-27 11:34:52 +05301906 agent.requestQueue.RequestComplete()
1907 if err != nil {
1908 return nil, err
1909 }
1910
1911 // Wait for the adapter response
1912 rpcResponse, ok := <-ch
1913 if !ok {
1914 return nil, status.Errorf(codes.Aborted, "channel-closed-device-id-%s", agent.deviceID)
1915 }
1916 if rpcResponse.Err != nil {
1917 return nil, rpcResponse.Err
1918 }
1919
1920 // Unmarshal and return the response
1921 testResp := &voltha.TestResponse{}
1922 if err := ptypes.UnmarshalAny(rpcResponse.Reply, testResp); err != nil {
1923 return nil, status.Errorf(codes.InvalidArgument, "%s", err.Error())
1924 }
Girish Kumarf56a4682020-03-20 20:07:46 +00001925 logger.Debugw("Omci_test_Request-Success-device-agent", log.Fields{"testResp": testResp})
onkarkundargi87285252020-01-27 11:34:52 +05301926 return testResp, nil
1927}
Dinesh Belwalkarc1129f12020-02-27 10:41:33 -08001928
1929func (agent *Agent) getExtValue(ctx context.Context, pdevice *voltha.Device, cdevice *voltha.Device, valueparam *voltha.ValueSpecifier) (*voltha.ReturnValues, error) {
1930 log.Debugw("getExtValue", log.Fields{"device-id": agent.deviceID, "onuid": valueparam.Id, "valuetype": valueparam.Value})
1931 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1932 return nil, err
1933 }
1934
1935 //send request to adapter
1936 ch, err := agent.adapterProxy.GetExtValue(ctx, pdevice, cdevice, valueparam.Id, valueparam.Value)
1937 agent.requestQueue.RequestComplete()
1938 if err != nil {
1939 return nil, err
1940 }
1941
1942 // Wait for the adapter response
1943 rpcResponse, ok := <-ch
1944 if !ok {
1945 return nil, status.Errorf(codes.Aborted, "channel-closed-device-id-%s", agent.deviceID)
1946 }
1947 if rpcResponse.Err != nil {
1948 return nil, rpcResponse.Err
1949 }
1950
1951 // Unmarshal and return the response
1952 Resp := &voltha.ReturnValues{}
1953 if err := ptypes.UnmarshalAny(rpcResponse.Reply, Resp); err != nil {
1954 return nil, status.Errorf(codes.InvalidArgument, "%s", err.Error())
1955 }
1956 logger.Debugw("getExtValue-Success-device-agent", log.Fields{"Resp": Resp})
1957 return Resp, nil
1958}