blob: 7b486bd5923d7e68d1baf2218778bf3bd490ea75 [file] [log] [blame]
khenaidoobf6e7bb2018-08-14 22:27:29 -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 */
khenaidoob9203542018-09-17 22:56:37 -040016package core
khenaidoobf6e7bb2018-08-14 22:27:29 -040017
18import (
19 "context"
20 "errors"
Richard Jankowskidbab94a2018-12-06 16:20:25 -050021 "github.com/golang-collections/go-datastructures/queue"
khenaidoobf6e7bb2018-08-14 22:27:29 -040022 "github.com/golang/protobuf/ptypes/empty"
23 da "github.com/opencord/voltha-go/common/core/northbound/grpc"
24 "github.com/opencord/voltha-go/common/log"
25 "github.com/opencord/voltha-go/protos/common"
26 "github.com/opencord/voltha-go/protos/openflow_13"
27 "github.com/opencord/voltha-go/protos/voltha"
khenaidoob9203542018-09-17 22:56:37 -040028 "google.golang.org/grpc/codes"
khenaidoobf6e7bb2018-08-14 22:27:29 -040029 "google.golang.org/grpc/metadata"
khenaidoob9203542018-09-17 22:56:37 -040030 "google.golang.org/grpc/status"
Stephane Barbarie6e1bd502018-11-05 22:44:45 -050031 "io"
32 "time"
khenaidoobf6e7bb2018-08-14 22:27:29 -040033)
34
khenaidoof5a5bfa2019-01-23 22:20:29 -050035const (
36 IMAGE_DOWNLOAD = iota
37 CANCEL_IMAGE_DOWNLOAD = iota
38 ACTIVATE_IMAGE = iota
39 REVERT_IMAGE = iota
40)
41
khenaidoo297cd252019-02-07 22:10:23 -050042
43type deviceID struct {
44 id string
45}
46
47type logicalDeviceID struct {
48 id string
49}
50
khenaidoobf6e7bb2018-08-14 22:27:29 -040051type APIHandler struct {
khenaidoob9203542018-09-17 22:56:37 -040052 deviceMgr *DeviceManager
53 logicalDeviceMgr *LogicalDeviceManager
khenaidoo21d51152019-02-01 13:48:37 -050054 adapterMgr *AdapterManager
khenaidood2b6df92018-12-13 16:37:20 -050055 packetInQueue *queue.Queue
khenaidoo9cdc1a62019-01-24 21:57:40 -050056 coreInCompetingMode bool
khenaidoob6080322019-01-29 21:47:38 -050057 longRunningRequestTimeout int64
58 defaultRequestTimeout int64
khenaidoobf6e7bb2018-08-14 22:27:29 -040059 da.DefaultAPIHandler
khenaidoo54e0ddf2019-02-27 16:21:33 -050060 core *Core
khenaidoobf6e7bb2018-08-14 22:27:29 -040061}
62
khenaidoo54e0ddf2019-02-27 16:21:33 -050063//func NewAPIHandler(deviceMgr *DeviceManager, lDeviceMgr *LogicalDeviceManager, adapterMgr *AdapterManager, inCompetingMode bool, longRunningRequestTimeout int64, defaultRequestTimeout int64 ) *APIHandler {
64// handler := &APIHandler{
65// deviceMgr: deviceMgr,
66// logicalDeviceMgr: lDeviceMgr,
67// adapterMgr:adapterMgr,
68// coreInCompetingMode:inCompetingMode,
69// longRunningRequestTimeout:longRunningRequestTimeout,
70// defaultRequestTimeout:defaultRequestTimeout,
71// // TODO: Figure out what the 'hint' parameter to queue.New does
72// packetInQueue: queue.New(10),
73// }
74// return handler
75//}
76
77func NewAPIHandler(core *Core) *APIHandler {
Stephane Barbarie6e1bd502018-11-05 22:44:45 -050078 handler := &APIHandler{
khenaidoo54e0ddf2019-02-27 16:21:33 -050079 deviceMgr: core.deviceMgr,
80 logicalDeviceMgr: core.logicalDeviceMgr,
81 adapterMgr: core.adapterMgr,
82 coreInCompetingMode: core.config.InCompetingMode,
83 longRunningRequestTimeout:core.config.LongRunningRequestTimeout,
84 defaultRequestTimeout:core.config.DefaultRequestTimeout,
Richard Jankowskidbab94a2018-12-06 16:20:25 -050085 // TODO: Figure out what the 'hint' parameter to queue.New does
khenaidood2b6df92018-12-13 16:37:20 -050086 packetInQueue: queue.New(10),
khenaidoo54e0ddf2019-02-27 16:21:33 -050087 core: core,
Stephane Barbarie6e1bd502018-11-05 22:44:45 -050088 }
khenaidoobf6e7bb2018-08-14 22:27:29 -040089 return handler
90}
khenaidoo4d4802d2018-10-04 21:59:49 -040091
92// isTestMode is a helper function to determine a function is invoked for testing only
khenaidoobf6e7bb2018-08-14 22:27:29 -040093func isTestMode(ctx context.Context) bool {
94 md, _ := metadata.FromIncomingContext(ctx)
95 _, exist := md[common.TestModeKeys_api_test.String()]
96 return exist
97}
98
Richard Jankowskid42826e2018-11-02 16:06:37 -040099// This function attempts to extract the serial number from the request metadata
100// and create a KV transaction for that serial number for the current core.
101func (handler *APIHandler) createKvTransaction(ctx context.Context) (*KVTransaction, error) {
102 var (
khenaidoo43c82122018-11-22 18:38:28 -0500103 err error
104 ok bool
105 md metadata.MD
Richard Jankowskid42826e2018-11-02 16:06:37 -0400106 serNum []string
107 )
108 if md, ok = metadata.FromIncomingContext(ctx); !ok {
109 err = errors.New("metadata-not-found")
110 } else if serNum, ok = md["voltha_serial_number"]; !ok {
111 err = errors.New("serial-number-not-found")
112 }
113 if !ok {
114 log.Error(err)
115 return nil, err
116 }
117 // Create KV transaction
118 txn := NewKVTransaction(serNum[0])
119 return txn, nil
120}
121
Richard Jankowski2755adf2019-01-17 17:16:48 -0500122// isOFControllerRequest is a helper function to determine if a request was initiated
123// from the OpenFlow controller (or its proxy, e.g. OFAgent)
Richard Jankowski46464e92019-03-05 11:53:55 -0500124func (handler *APIHandler) isOFControllerRequest(ctx context.Context) bool {
khenaidoo9cdc1a62019-01-24 21:57:40 -0500125 if md, ok := metadata.FromIncomingContext(ctx); ok {
126 // Metadata in context
Richard Jankowski46464e92019-03-05 11:53:55 -0500127 if _, ok = md[handler.core.config.CoreBindingKey]; ok {
khenaidoo9cdc1a62019-01-24 21:57:40 -0500128 // OFAgent field in metadata
129 return true
130 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500131 }
khenaidoo9cdc1a62019-01-24 21:57:40 -0500132 return false
133}
134
135// competeForTransaction is a helper function to determine whether every request needs to compete with another
136// Core to execute the request
137func (handler *APIHandler) competeForTransaction() bool {
138 return handler.coreInCompetingMode
139}
140
khenaidoo297cd252019-02-07 22:10:23 -0500141func (handler *APIHandler) acquireTransaction(ctx context.Context, id interface{}, maxTimeout ...int64) (*KVTransaction, error) {
khenaidoob6080322019-01-29 21:47:38 -0500142 timeout := handler.defaultRequestTimeout
khenaidoo9cdc1a62019-01-24 21:57:40 -0500143 if len(maxTimeout) > 0 {
144 timeout = maxTimeout[0]
Richard Jankowski2755adf2019-01-17 17:16:48 -0500145 }
khenaidoob6080322019-01-29 21:47:38 -0500146 log.Debugw("transaction-timeout", log.Fields{"timeout": timeout})
khenaidoo9cdc1a62019-01-24 21:57:40 -0500147 txn, err := handler.createKvTransaction(ctx)
148 if txn == nil {
149 return nil, err
150 } else if txn.Acquired(timeout) {
151 return txn, nil
152 } else {
khenaidoo297cd252019-02-07 22:10:23 -0500153 if id != nil {
154 // The id can either be a device Id or a logical device id.
155 if dId, ok := id.(*deviceID); ok {
156 // Since this core has not processed this request, let's load the device, along with its extended
157 // family (parents and children) in memory. This will keep this core in-sync with its paired core as
158 // much as possible. The watch feature in the core model will ensure that the contents of those objects in
159 // memory are in sync.
160 time.Sleep(2 * time.Second)
161 go handler.deviceMgr.load(dId.id)
162 } else if ldId, ok := id.(*logicalDeviceID); ok {
163 // This will load the logical device along with its children and grandchildren
164 go handler.logicalDeviceMgr.load(ldId.id)
165 }
166 }
khenaidoo9cdc1a62019-01-24 21:57:40 -0500167 return nil, errors.New("failed-to-seize-request")
Richard Jankowski2755adf2019-01-17 17:16:48 -0500168 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500169}
170
khenaidoo4d4802d2018-10-04 21:59:49 -0400171// waitForNilResponseOnSuccess is a helper function to wait for a response on channel ch where an nil
172// response is expected in a successful scenario
173func waitForNilResponseOnSuccess(ctx context.Context, ch chan interface{}) (*empty.Empty, error) {
174 select {
175 case res := <-ch:
176 if res == nil {
177 return new(empty.Empty), nil
178 } else if err, ok := res.(error); ok {
179 return new(empty.Empty), err
180 } else {
181 log.Warnw("unexpected-return-type", log.Fields{"result": res})
182 err = status.Errorf(codes.Internal, "%s", res)
183 return new(empty.Empty), err
184 }
185 case <-ctx.Done():
186 log.Debug("client-timeout")
187 return nil, ctx.Err()
188 }
189}
190
khenaidoobf6e7bb2018-08-14 22:27:29 -0400191func (handler *APIHandler) UpdateLogLevel(ctx context.Context, logging *voltha.Logging) (*empty.Empty, error) {
khenaidoo6f2fbe32019-01-18 16:16:50 -0500192 log.Debugw("UpdateLogLevel-request", log.Fields{"package": logging.PackageName, "intval": int(logging.Level)})
khenaidoo92e62c52018-10-03 14:02:54 -0400193 out := new(empty.Empty)
khenaidoo6f2fbe32019-01-18 16:16:50 -0500194 if logging.PackageName == "" {
195 log.SetAllLogLevel(int(logging.Level))
196 } else {
197 log.SetPackageLogLevel(logging.PackageName, int(logging.Level))
198 }
khenaidoo92e62c52018-10-03 14:02:54 -0400199 return out, nil
khenaidoobf6e7bb2018-08-14 22:27:29 -0400200}
201
khenaidoo54e0ddf2019-02-27 16:21:33 -0500202
203func (handler *APIHandler) UpdateMembership(ctx context.Context, membership *voltha.Membership) (*empty.Empty, error) {
204 log.Debugw("UpdateMembership-request", log.Fields{"membership": membership})
205 out := new(empty.Empty)
khenaidoo6417b6c2019-03-01 18:18:01 -0500206 if err := handler.core.updateCoreMembership(ctx, membership); err != nil {
khenaidoo54e0ddf2019-02-27 16:21:33 -0500207 return out, err
208 }
209 return out, nil
210}
211
khenaidoo6417b6c2019-03-01 18:18:01 -0500212func (handler *APIHandler) GetMembership(ctx context.Context, empty *empty.Empty) (*voltha.Membership, error) {
213 log.Debug("GetMembership-request")
214 if membership := handler.core.getCoreMembership(ctx); membership != nil {
215 return membership, nil
216 }
217 return &voltha.Membership{}, nil
218}
219
220
khenaidoobf6e7bb2018-08-14 22:27:29 -0400221func (handler *APIHandler) EnableLogicalDevicePort(ctx context.Context, id *voltha.LogicalPortId) (*empty.Empty, error) {
222 log.Debugw("EnableLogicalDevicePort-request", log.Fields{"id": id, "test": common.TestModeKeys_api_test.String()})
223 if isTestMode(ctx) {
224 out := new(empty.Empty)
225 return out, nil
226 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500227
khenaidoo9cdc1a62019-01-24 21:57:40 -0500228 if handler.competeForTransaction() {
khenaidoo297cd252019-02-07 22:10:23 -0500229 if txn, err := handler.acquireTransaction(ctx, &logicalDeviceID{id:id.Id}); err != nil {
Richard Jankowski2755adf2019-01-17 17:16:48 -0500230 return new(empty.Empty), err
Richard Jankowski2755adf2019-01-17 17:16:48 -0500231 } else {
khenaidoo9cdc1a62019-01-24 21:57:40 -0500232 defer txn.Close()
Richard Jankowski2755adf2019-01-17 17:16:48 -0500233 }
234 }
khenaidoo9cdc1a62019-01-24 21:57:40 -0500235
khenaidoo4d4802d2018-10-04 21:59:49 -0400236 ch := make(chan interface{})
237 defer close(ch)
khenaidoo19d7b632018-10-30 10:49:50 -0400238 go handler.logicalDeviceMgr.enableLogicalPort(ctx, id, ch)
khenaidoo4d4802d2018-10-04 21:59:49 -0400239 return waitForNilResponseOnSuccess(ctx, ch)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400240}
241
242func (handler *APIHandler) DisableLogicalDevicePort(ctx context.Context, id *voltha.LogicalPortId) (*empty.Empty, error) {
243 log.Debugw("DisableLogicalDevicePort-request", log.Fields{"id": id, "test": common.TestModeKeys_api_test.String()})
244 if isTestMode(ctx) {
245 out := new(empty.Empty)
246 return out, nil
247 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500248
khenaidoo9cdc1a62019-01-24 21:57:40 -0500249 if handler.competeForTransaction() {
khenaidoo297cd252019-02-07 22:10:23 -0500250 if txn, err := handler.acquireTransaction(ctx, &logicalDeviceID{id:id.Id}); err != nil {
Richard Jankowski2755adf2019-01-17 17:16:48 -0500251 return new(empty.Empty), err
Richard Jankowski2755adf2019-01-17 17:16:48 -0500252 } else {
khenaidoo9cdc1a62019-01-24 21:57:40 -0500253 defer txn.Close()
Richard Jankowski2755adf2019-01-17 17:16:48 -0500254 }
255 }
khenaidoo9cdc1a62019-01-24 21:57:40 -0500256
khenaidoo19d7b632018-10-30 10:49:50 -0400257 ch := make(chan interface{})
258 defer close(ch)
259 go handler.logicalDeviceMgr.disableLogicalPort(ctx, id, ch)
260 return waitForNilResponseOnSuccess(ctx, ch)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400261}
262
263func (handler *APIHandler) UpdateLogicalDeviceFlowTable(ctx context.Context, flow *openflow_13.FlowTableUpdate) (*empty.Empty, error) {
264 log.Debugw("UpdateLogicalDeviceFlowTable-request", log.Fields{"flow": flow, "test": common.TestModeKeys_api_test.String()})
265 if isTestMode(ctx) {
266 out := new(empty.Empty)
267 return out, nil
268 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500269
khenaidoo9cdc1a62019-01-24 21:57:40 -0500270 if handler.competeForTransaction() {
Richard Jankowski46464e92019-03-05 11:53:55 -0500271 if !handler.isOFControllerRequest(ctx) { // No need to acquire the transaction as request is sent to one core only
khenaidoo297cd252019-02-07 22:10:23 -0500272 if txn, err := handler.acquireTransaction(ctx, &logicalDeviceID{id:flow.Id}); err != nil {
khenaidoo9cdc1a62019-01-24 21:57:40 -0500273 return new(empty.Empty), err
274 } else {
275 defer txn.Close()
276 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500277 }
278 }
khenaidoo9cdc1a62019-01-24 21:57:40 -0500279
khenaidoo19d7b632018-10-30 10:49:50 -0400280 ch := make(chan interface{})
281 defer close(ch)
282 go handler.logicalDeviceMgr.updateFlowTable(ctx, flow.Id, flow.FlowMod, ch)
283 return waitForNilResponseOnSuccess(ctx, ch)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400284}
285
286func (handler *APIHandler) UpdateLogicalDeviceFlowGroupTable(ctx context.Context, flow *openflow_13.FlowGroupTableUpdate) (*empty.Empty, error) {
287 log.Debugw("UpdateLogicalDeviceFlowGroupTable-request", log.Fields{"flow": flow, "test": common.TestModeKeys_api_test.String()})
288 if isTestMode(ctx) {
289 out := new(empty.Empty)
290 return out, nil
291 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500292
khenaidoo9cdc1a62019-01-24 21:57:40 -0500293 if handler.competeForTransaction() {
Richard Jankowski46464e92019-03-05 11:53:55 -0500294 if !handler.isOFControllerRequest(ctx) { // No need to acquire the transaction as request is sent to one core only
khenaidoo297cd252019-02-07 22:10:23 -0500295 if txn, err := handler.acquireTransaction(ctx, &logicalDeviceID{id:flow.Id}); err != nil {
khenaidoo9cdc1a62019-01-24 21:57:40 -0500296 return new(empty.Empty), err
297 } else {
298 defer txn.Close()
299 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500300 }
301 }
khenaidoo9cdc1a62019-01-24 21:57:40 -0500302
khenaidoo19d7b632018-10-30 10:49:50 -0400303 ch := make(chan interface{})
304 defer close(ch)
305 go handler.logicalDeviceMgr.updateGroupTable(ctx, flow.Id, flow.GroupMod, ch)
306 return waitForNilResponseOnSuccess(ctx, ch)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400307}
308
khenaidoob9203542018-09-17 22:56:37 -0400309// GetDevice must be implemented in the read-only containers - should it also be implemented here?
310func (handler *APIHandler) GetDevice(ctx context.Context, id *voltha.ID) (*voltha.Device, error) {
311 log.Debugw("GetDevice-request", log.Fields{"id": id})
khenaidoo19d7b632018-10-30 10:49:50 -0400312 return handler.deviceMgr.GetDevice(id.Id)
khenaidoob9203542018-09-17 22:56:37 -0400313}
314
315// GetDevice must be implemented in the read-only containers - should it also be implemented here?
316func (handler *APIHandler) ListDevices(ctx context.Context, empty *empty.Empty) (*voltha.Devices, error) {
317 log.Debug("ListDevices")
318 return handler.deviceMgr.ListDevices()
319}
320
khenaidoo7ccedd52018-12-14 16:48:54 -0500321// ListDeviceIds returns the list of device ids managed by a voltha core
322func (handler *APIHandler) ListDeviceIds(ctx context.Context, empty *empty.Empty) (*voltha.IDs, error) {
323 log.Debug("ListDeviceIDs")
324 if isTestMode(ctx) {
325 out := &voltha.IDs{Items: make([]*voltha.ID, 0)}
326 return out, nil
327 }
328 return handler.deviceMgr.ListDeviceIds()
329}
330
331//ReconcileDevices is a request to a voltha core to managed a list of devices based on their IDs
332func (handler *APIHandler) ReconcileDevices(ctx context.Context, ids *voltha.IDs) (*empty.Empty, error) {
333 log.Debug("ReconcileDevices")
334 if isTestMode(ctx) {
335 out := new(empty.Empty)
336 return out, nil
337 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500338
khenaidoo9cdc1a62019-01-24 21:57:40 -0500339 // No need to grab a transaction as this request is core specific
340
khenaidoo7ccedd52018-12-14 16:48:54 -0500341 ch := make(chan interface{})
342 defer close(ch)
343 go handler.deviceMgr.ReconcileDevices(ctx, ids, ch)
344 return waitForNilResponseOnSuccess(ctx, ch)
345}
346
khenaidoob9203542018-09-17 22:56:37 -0400347// GetLogicalDevice must be implemented in the read-only containers - should it also be implemented here?
348func (handler *APIHandler) GetLogicalDevice(ctx context.Context, id *voltha.ID) (*voltha.LogicalDevice, error) {
349 log.Debugw("GetLogicalDevice-request", log.Fields{"id": id})
350 return handler.logicalDeviceMgr.getLogicalDevice(id.Id)
351}
352
353// ListLogicalDevices must be implemented in the read-only containers - should it also be implemented here?
354func (handler *APIHandler) ListLogicalDevices(ctx context.Context, empty *empty.Empty) (*voltha.LogicalDevices, error) {
355 log.Debug("ListLogicalDevices")
356 return handler.logicalDeviceMgr.listLogicalDevices()
357}
358
khenaidoo21d51152019-02-01 13:48:37 -0500359
360// ListAdapters returns the contents of all adapters known to the system
361func (handler *APIHandler) ListAdapters(ctx context.Context, empty *empty.Empty) (*voltha.Adapters, error) {
362 log.Debug("ListDevices")
363 return handler.adapterMgr.listAdapters(ctx)
364}
365
khenaidoo19d7b632018-10-30 10:49:50 -0400366// ListLogicalDevicePorts must be implemented in the read-only containers - should it also be implemented here?
367func (handler *APIHandler) ListLogicalDevicePorts(ctx context.Context, id *voltha.ID) (*voltha.LogicalPorts, error) {
368 log.Debugw("ListLogicalDevicePorts", log.Fields{"logicaldeviceid": id})
369 return handler.logicalDeviceMgr.ListLogicalDevicePorts(ctx, id.Id)
370}
371
khenaidoo4d4802d2018-10-04 21:59:49 -0400372// CreateDevice creates a new parent device in the data model
khenaidoobf6e7bb2018-08-14 22:27:29 -0400373func (handler *APIHandler) CreateDevice(ctx context.Context, device *voltha.Device) (*voltha.Device, error) {
khenaidoob9203542018-09-17 22:56:37 -0400374 log.Debugw("createdevice", log.Fields{"device": *device})
khenaidoobf6e7bb2018-08-14 22:27:29 -0400375 if isTestMode(ctx) {
376 return &voltha.Device{Id: device.Id}, nil
377 }
Richard Jankowskid42826e2018-11-02 16:06:37 -0400378
khenaidoo9cdc1a62019-01-24 21:57:40 -0500379 if handler.competeForTransaction() {
khenaidoo297cd252019-02-07 22:10:23 -0500380 if txn, err := handler.acquireTransaction(ctx, nil); err != nil {
Richard Jankowski2755adf2019-01-17 17:16:48 -0500381 return &voltha.Device{}, err
Richard Jankowski2755adf2019-01-17 17:16:48 -0500382 } else {
khenaidoo9cdc1a62019-01-24 21:57:40 -0500383 defer txn.Close()
Richard Jankowski2755adf2019-01-17 17:16:48 -0500384 }
385 }
khenaidoo9cdc1a62019-01-24 21:57:40 -0500386
khenaidoob9203542018-09-17 22:56:37 -0400387 ch := make(chan interface{})
388 defer close(ch)
389 go handler.deviceMgr.createDevice(ctx, device, ch)
390 select {
391 case res := <-ch:
khenaidoo92e62c52018-10-03 14:02:54 -0400392 if res != nil {
393 if err, ok := res.(error); ok {
394 return &voltha.Device{}, err
395 }
396 if d, ok := res.(*voltha.Device); ok {
397 return d, nil
398 }
khenaidoob9203542018-09-17 22:56:37 -0400399 }
khenaidoo92e62c52018-10-03 14:02:54 -0400400 log.Warnw("create-device-unexpected-return-type", log.Fields{"result": res})
401 err := status.Errorf(codes.Internal, "%s", res)
402 return &voltha.Device{}, err
khenaidoob9203542018-09-17 22:56:37 -0400403 case <-ctx.Done():
404 log.Debug("createdevice-client-timeout")
405 return nil, ctx.Err()
406 }
khenaidoobf6e7bb2018-08-14 22:27:29 -0400407}
408
khenaidoo4d4802d2018-10-04 21:59:49 -0400409// EnableDevice activates a device by invoking the adopt_device API on the appropriate adapter
khenaidoobf6e7bb2018-08-14 22:27:29 -0400410func (handler *APIHandler) EnableDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
khenaidoob9203542018-09-17 22:56:37 -0400411 log.Debugw("enabledevice", log.Fields{"id": id})
khenaidoobf6e7bb2018-08-14 22:27:29 -0400412 if isTestMode(ctx) {
khenaidoo4d4802d2018-10-04 21:59:49 -0400413 return new(empty.Empty), nil
khenaidoobf6e7bb2018-08-14 22:27:29 -0400414 }
Richard Jankowskid42826e2018-11-02 16:06:37 -0400415
khenaidoo9cdc1a62019-01-24 21:57:40 -0500416 if handler.competeForTransaction() {
khenaidoo297cd252019-02-07 22:10:23 -0500417 if txn, err := handler.acquireTransaction(ctx, &deviceID{id:id.Id}, handler.longRunningRequestTimeout); err != nil {
Richard Jankowski2755adf2019-01-17 17:16:48 -0500418 return new(empty.Empty), err
Richard Jankowski2755adf2019-01-17 17:16:48 -0500419 } else {
khenaidoo9cdc1a62019-01-24 21:57:40 -0500420 defer txn.Close()
Richard Jankowski2755adf2019-01-17 17:16:48 -0500421 }
422 }
khenaidoo9cdc1a62019-01-24 21:57:40 -0500423
khenaidoob9203542018-09-17 22:56:37 -0400424 ch := make(chan interface{})
425 defer close(ch)
426 go handler.deviceMgr.enableDevice(ctx, id, ch)
khenaidoo4d4802d2018-10-04 21:59:49 -0400427 return waitForNilResponseOnSuccess(ctx, ch)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400428}
429
khenaidoo4d4802d2018-10-04 21:59:49 -0400430// DisableDevice disables a device along with any child device it may have
khenaidoobf6e7bb2018-08-14 22:27:29 -0400431func (handler *APIHandler) DisableDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
432 log.Debugw("disabledevice-request", log.Fields{"id": id})
433 if isTestMode(ctx) {
khenaidoo4d4802d2018-10-04 21:59:49 -0400434 return new(empty.Empty), nil
khenaidoobf6e7bb2018-08-14 22:27:29 -0400435 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500436
khenaidoo9cdc1a62019-01-24 21:57:40 -0500437 if handler.competeForTransaction() {
khenaidoo297cd252019-02-07 22:10:23 -0500438 if txn, err := handler.acquireTransaction(ctx, &deviceID{id:id.Id}); err != nil {
Richard Jankowski2755adf2019-01-17 17:16:48 -0500439 return new(empty.Empty), err
Richard Jankowski2755adf2019-01-17 17:16:48 -0500440 } else {
khenaidoo9cdc1a62019-01-24 21:57:40 -0500441 defer txn.Close()
Richard Jankowski2755adf2019-01-17 17:16:48 -0500442 }
443 }
khenaidoo9cdc1a62019-01-24 21:57:40 -0500444
khenaidoo92e62c52018-10-03 14:02:54 -0400445 ch := make(chan interface{})
446 defer close(ch)
447 go handler.deviceMgr.disableDevice(ctx, id, ch)
khenaidoo4d4802d2018-10-04 21:59:49 -0400448 return waitForNilResponseOnSuccess(ctx, ch)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400449}
450
khenaidoo4d4802d2018-10-04 21:59:49 -0400451//RebootDevice invoked the reboot API to the corresponding adapter
khenaidoobf6e7bb2018-08-14 22:27:29 -0400452func (handler *APIHandler) RebootDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
khenaidoo4d4802d2018-10-04 21:59:49 -0400453 log.Debugw("rebootDevice-request", log.Fields{"id": id})
khenaidoobf6e7bb2018-08-14 22:27:29 -0400454 if isTestMode(ctx) {
khenaidoo4d4802d2018-10-04 21:59:49 -0400455 return new(empty.Empty), nil
khenaidoobf6e7bb2018-08-14 22:27:29 -0400456 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500457
khenaidoo9cdc1a62019-01-24 21:57:40 -0500458 if handler.competeForTransaction() {
khenaidoo297cd252019-02-07 22:10:23 -0500459 if txn, err := handler.acquireTransaction(ctx, &deviceID{id:id.Id}); err != nil {
Richard Jankowski2755adf2019-01-17 17:16:48 -0500460 return new(empty.Empty), err
Richard Jankowski2755adf2019-01-17 17:16:48 -0500461 } else {
khenaidoo9cdc1a62019-01-24 21:57:40 -0500462 defer txn.Close()
Richard Jankowski2755adf2019-01-17 17:16:48 -0500463 }
464 }
khenaidoo9cdc1a62019-01-24 21:57:40 -0500465
khenaidoo4d4802d2018-10-04 21:59:49 -0400466 ch := make(chan interface{})
467 defer close(ch)
468 go handler.deviceMgr.rebootDevice(ctx, id, ch)
469 return waitForNilResponseOnSuccess(ctx, ch)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400470}
471
khenaidoo4d4802d2018-10-04 21:59:49 -0400472// DeleteDevice removes a device from the data model
khenaidoobf6e7bb2018-08-14 22:27:29 -0400473func (handler *APIHandler) DeleteDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
474 log.Debugw("deletedevice-request", log.Fields{"id": id})
475 if isTestMode(ctx) {
khenaidoo4d4802d2018-10-04 21:59:49 -0400476 return new(empty.Empty), nil
khenaidoobf6e7bb2018-08-14 22:27:29 -0400477 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500478
khenaidoo9cdc1a62019-01-24 21:57:40 -0500479 if handler.competeForTransaction() {
khenaidoo297cd252019-02-07 22:10:23 -0500480 if txn, err := handler.acquireTransaction(ctx, nil); err != nil {
Richard Jankowski2755adf2019-01-17 17:16:48 -0500481 return new(empty.Empty), err
Richard Jankowski2755adf2019-01-17 17:16:48 -0500482 } else {
khenaidoo9cdc1a62019-01-24 21:57:40 -0500483 defer txn.Close()
Richard Jankowski2755adf2019-01-17 17:16:48 -0500484 }
485 }
khenaidoo9cdc1a62019-01-24 21:57:40 -0500486
khenaidoo4d4802d2018-10-04 21:59:49 -0400487 ch := make(chan interface{})
488 defer close(ch)
489 go handler.deviceMgr.deleteDevice(ctx, id, ch)
490 return waitForNilResponseOnSuccess(ctx, ch)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400491}
492
khenaidoof5a5bfa2019-01-23 22:20:29 -0500493// processImageRequest is a helper method to execute an image download request
494func (handler *APIHandler) processImageRequest(ctx context.Context, img *voltha.ImageDownload, requestType int) (*common.OperationResp, error) {
495 log.Debugw("processImageDownload", log.Fields{"img": *img, "requestType": requestType})
496 if isTestMode(ctx) {
497 resp := &common.OperationResp{Code: common.OperationResp_OPERATION_SUCCESS}
498 return resp, nil
499 }
500
khenaidoo9cdc1a62019-01-24 21:57:40 -0500501 if handler.competeForTransaction() {
khenaidoo297cd252019-02-07 22:10:23 -0500502 if txn, err := handler.acquireTransaction(ctx, &deviceID{id:img.Id}); err != nil {
khenaidoo9cdc1a62019-01-24 21:57:40 -0500503 return &common.OperationResp{}, err
504 } else {
505 defer txn.Close()
506 }
khenaidoof5a5bfa2019-01-23 22:20:29 -0500507 }
508
509 failedresponse := &common.OperationResp{Code:voltha.OperationResp_OPERATION_FAILURE}
510
511 ch := make(chan interface{})
512 defer close(ch)
513 switch requestType {
514 case IMAGE_DOWNLOAD:
515 go handler.deviceMgr.downloadImage(ctx, img, ch)
516 case CANCEL_IMAGE_DOWNLOAD:
517 go handler.deviceMgr.cancelImageDownload(ctx, img, ch)
518 case ACTIVATE_IMAGE:
519 go handler.deviceMgr.activateImage(ctx, img, ch)
520 case REVERT_IMAGE:
521 go handler.deviceMgr.revertImage(ctx, img, ch)
522 default:
523 log.Warn("invalid-request-type", log.Fields{"requestType": requestType})
524 return failedresponse, status.Errorf(codes.InvalidArgument, "%d", requestType)
525 }
526 select {
527 case res := <-ch:
528 if res != nil {
529 if err, ok := res.(error); ok {
530 return failedresponse, err
531 }
532 if opResp, ok := res.(*common.OperationResp); ok {
533 return opResp, nil
534 }
535 }
536 log.Warnw("download-image-unexpected-return-type", log.Fields{"result": res})
537 return failedresponse, status.Errorf(codes.Internal, "%s", res)
538 case <-ctx.Done():
539 log.Debug("downloadImage-client-timeout")
540 return nil, ctx.Err()
541 }
542}
543
khenaidoobf6e7bb2018-08-14 22:27:29 -0400544func (handler *APIHandler) DownloadImage(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
545 log.Debugw("DownloadImage-request", log.Fields{"img": *img})
546 if isTestMode(ctx) {
547 resp := &common.OperationResp{Code: common.OperationResp_OPERATION_SUCCESS}
548 return resp, nil
549 }
550
khenaidoof5a5bfa2019-01-23 22:20:29 -0500551 return handler.processImageRequest(ctx, img, IMAGE_DOWNLOAD)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400552}
553
554func (handler *APIHandler) CancelImageDownload(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
khenaidoof5a5bfa2019-01-23 22:20:29 -0500555 log.Debugw("cancelImageDownload-request", log.Fields{"img": *img})
khenaidoobf6e7bb2018-08-14 22:27:29 -0400556 if isTestMode(ctx) {
557 resp := &common.OperationResp{Code: common.OperationResp_OPERATION_SUCCESS}
558 return resp, nil
559 }
khenaidoof5a5bfa2019-01-23 22:20:29 -0500560 return handler.processImageRequest(ctx, img, CANCEL_IMAGE_DOWNLOAD)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400561}
562
563func (handler *APIHandler) ActivateImageUpdate(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
khenaidoof5a5bfa2019-01-23 22:20:29 -0500564 log.Debugw("activateImageUpdate-request", log.Fields{"img": *img})
khenaidoobf6e7bb2018-08-14 22:27:29 -0400565 if isTestMode(ctx) {
566 resp := &common.OperationResp{Code: common.OperationResp_OPERATION_SUCCESS}
567 return resp, nil
568 }
khenaidoof5a5bfa2019-01-23 22:20:29 -0500569
570 return handler.processImageRequest(ctx, img, ACTIVATE_IMAGE)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400571}
572
573func (handler *APIHandler) RevertImageUpdate(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
khenaidoof5a5bfa2019-01-23 22:20:29 -0500574 log.Debugw("revertImageUpdate-request", log.Fields{"img": *img})
khenaidoobf6e7bb2018-08-14 22:27:29 -0400575 if isTestMode(ctx) {
576 resp := &common.OperationResp{Code: common.OperationResp_OPERATION_SUCCESS}
577 return resp, nil
578 }
khenaidoof5a5bfa2019-01-23 22:20:29 -0500579
580 return handler.processImageRequest(ctx, img, REVERT_IMAGE)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400581}
582
khenaidoof5a5bfa2019-01-23 22:20:29 -0500583func (handler *APIHandler) GetImageDownloadStatus(ctx context.Context, img *voltha.ImageDownload) (*voltha.ImageDownload, error) {
584 log.Debugw("getImageDownloadStatus-request", log.Fields{"img": *img})
585 if isTestMode(ctx) {
Stephane Barbariedf5479f2019-01-29 22:13:00 -0500586 resp := &voltha.ImageDownload{DownloadState: voltha.ImageDownload_DOWNLOAD_SUCCEEDED}
khenaidoof5a5bfa2019-01-23 22:20:29 -0500587 return resp, nil
588 }
589
Stephane Barbariedf5479f2019-01-29 22:13:00 -0500590 failedresponse := &voltha.ImageDownload{DownloadState: voltha.ImageDownload_DOWNLOAD_UNKNOWN}
khenaidoof5a5bfa2019-01-23 22:20:29 -0500591
khenaidoo9cdc1a62019-01-24 21:57:40 -0500592 if handler.competeForTransaction() {
khenaidoo297cd252019-02-07 22:10:23 -0500593 if txn, err := handler.acquireTransaction(ctx, &deviceID{id:img.Id}); err != nil {
khenaidoo9cdc1a62019-01-24 21:57:40 -0500594 return failedresponse, err
595 } else {
596 defer txn.Close()
597 }
khenaidoof5a5bfa2019-01-23 22:20:29 -0500598 }
599
600 ch := make(chan interface{})
601 defer close(ch)
602 go handler.deviceMgr.getImageDownloadStatus(ctx, img, ch)
603
604 select {
605 case res := <-ch:
606 if res != nil {
607 if err, ok := res.(error); ok {
608 return failedresponse, err
609 }
610 if downloadResp, ok := res.(*voltha.ImageDownload); ok {
611 return downloadResp, nil
612 }
613 }
614 log.Warnw("download-image-status", log.Fields{"result": res})
615 return failedresponse, status.Errorf(codes.Internal, "%s", res)
616 case <-ctx.Done():
617 log.Debug("downloadImage-client-timeout")
618 return failedresponse, ctx.Err()
619 }
620}
621
622func (handler *APIHandler) GetImageDownload(ctx context.Context, img *voltha.ImageDownload) (*voltha.ImageDownload, error) {
623 log.Debugw("GetImageDownload-request", log.Fields{"img": *img})
624 if isTestMode(ctx) {
Stephane Barbariedf5479f2019-01-29 22:13:00 -0500625 resp := &voltha.ImageDownload{DownloadState: voltha.ImageDownload_DOWNLOAD_SUCCEEDED}
khenaidoof5a5bfa2019-01-23 22:20:29 -0500626 return resp, nil
627 }
628
629 if download, err := handler.deviceMgr.getImageDownload(ctx, img); err != nil {
Stephane Barbariedf5479f2019-01-29 22:13:00 -0500630 return &voltha.ImageDownload{DownloadState: voltha.ImageDownload_DOWNLOAD_UNKNOWN}, err
khenaidoof5a5bfa2019-01-23 22:20:29 -0500631 } else {
632 return download, nil
633 }
634}
635
636func (handler *APIHandler) ListImageDownloads(ctx context.Context, id *voltha.ID) (*voltha.ImageDownloads, error) {
637 log.Debugw("ListImageDownloads-request", log.Fields{"deviceId": id.Id})
638 if isTestMode(ctx) {
639 resp := &voltha.ImageDownloads{Items:[]*voltha.ImageDownload{}}
640 return resp, nil
641 }
642
643 if downloads, err := handler.deviceMgr.listImageDownloads(ctx, id.Id); err != nil {
644 failedResp := &voltha.ImageDownloads{
645 Items:[]*voltha.ImageDownload{
Stephane Barbariedf5479f2019-01-29 22:13:00 -0500646 &voltha.ImageDownload{DownloadState: voltha.ImageDownload_DOWNLOAD_UNKNOWN},
khenaidoof5a5bfa2019-01-23 22:20:29 -0500647 },
648 }
649 return failedResp, err
650 } else {
651 return downloads, nil
652 }
653}
654
655
khenaidoobf6e7bb2018-08-14 22:27:29 -0400656func (handler *APIHandler) UpdateDevicePmConfigs(ctx context.Context, configs *voltha.PmConfigs) (*empty.Empty, error) {
657 log.Debugw("UpdateDevicePmConfigs-request", log.Fields{"configs": *configs})
658 if isTestMode(ctx) {
659 out := new(empty.Empty)
660 return out, nil
661 }
662 return nil, errors.New("UnImplemented")
663}
664
665func (handler *APIHandler) CreateAlarmFilter(ctx context.Context, filter *voltha.AlarmFilter) (*voltha.AlarmFilter, error) {
666 log.Debugw("CreateAlarmFilter-request", log.Fields{"filter": *filter})
667 if isTestMode(ctx) {
668 f := &voltha.AlarmFilter{Id: filter.Id}
669 return f, nil
670 }
671 return nil, errors.New("UnImplemented")
672}
673
674func (handler *APIHandler) UpdateAlarmFilter(ctx context.Context, filter *voltha.AlarmFilter) (*voltha.AlarmFilter, error) {
675 log.Debugw("UpdateAlarmFilter-request", log.Fields{"filter": *filter})
676 if isTestMode(ctx) {
677 f := &voltha.AlarmFilter{Id: filter.Id}
678 return f, nil
679 }
680 return nil, errors.New("UnImplemented")
681}
682
683func (handler *APIHandler) DeleteAlarmFilter(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
684 log.Debugw("DeleteAlarmFilter-request", log.Fields{"id": *id})
685 if isTestMode(ctx) {
686 out := new(empty.Empty)
687 return out, nil
688 }
689 return nil, errors.New("UnImplemented")
690}
691
692func (handler *APIHandler) SelfTest(ctx context.Context, id *voltha.ID) (*voltha.SelfTestResponse, error) {
693 log.Debugw("SelfTest-request", log.Fields{"id": id})
694 if isTestMode(ctx) {
695 resp := &voltha.SelfTestResponse{Result: voltha.SelfTestResponse_SUCCESS}
696 return resp, nil
697 }
698 return nil, errors.New("UnImplemented")
699}
Stephane Barbarie6e1bd502018-11-05 22:44:45 -0500700
701func (handler *APIHandler) forwardPacketOut(packet *openflow_13.PacketOut) {
702 log.Debugw("forwardPacketOut-request", log.Fields{"packet": packet})
Richard Jankowski2755adf2019-01-17 17:16:48 -0500703 agent := handler.logicalDeviceMgr.getLogicalDeviceAgent(packet.Id)
704 agent.packetOut(packet.PacketOut)
Stephane Barbarie6e1bd502018-11-05 22:44:45 -0500705}
706func (handler *APIHandler) StreamPacketsOut(
707 packets voltha.VolthaService_StreamPacketsOutServer,
708) error {
709 log.Debugw("StreamPacketsOut-request", log.Fields{"packets": packets})
710 for {
711 packet, err := packets.Recv()
712
713 if err == io.EOF {
714 break
715 } else if err != nil {
716 log.Errorw("Failed to receive packet", log.Fields{"error": err})
717 }
718
719 handler.forwardPacketOut(packet)
720 }
721
722 log.Debugw("StreamPacketsOut-request-done", log.Fields{"packets": packets})
723 return nil
724}
725
khenaidoo297cd252019-02-07 22:10:23 -0500726func (handler *APIHandler) sendPacketIn(deviceId string, transationId string, packet *openflow_13.OfpPacketIn) {
727 // TODO: Augment the OF PacketIn to include the transactionId
Stephane Barbarie6e1bd502018-11-05 22:44:45 -0500728 packetIn := openflow_13.PacketIn{Id: deviceId, PacketIn: packet}
729 log.Debugw("sendPacketIn", log.Fields{"packetIn": packetIn})
Richard Jankowskidbab94a2018-12-06 16:20:25 -0500730 // Enqueue the packet
731 if err := handler.packetInQueue.Put(packetIn); err != nil {
732 log.Errorw("failed-to-enqueue-packet", log.Fields{"error": err})
733 }
Stephane Barbarie6e1bd502018-11-05 22:44:45 -0500734}
735
736func (handler *APIHandler) ReceivePacketsIn(
737 empty *empty.Empty,
738 packetsIn voltha.VolthaService_ReceivePacketsInServer,
739) error {
740 log.Debugw("ReceivePacketsIn-request", log.Fields{"packetsIn": packetsIn})
741
742 for {
Richard Jankowskidbab94a2018-12-06 16:20:25 -0500743 // Dequeue a packet
744 if packets, err := handler.packetInQueue.Get(1); err == nil {
745 log.Debugw("dequeued-packet", log.Fields{"packet": packets[0]})
746 if packet, ok := packets[0].(openflow_13.PacketIn); ok {
747 log.Debugw("sending-packet-in", log.Fields{"packet": packet})
748 if err := packetsIn.Send(&packet); err != nil {
749 log.Errorw("failed-to-send-packet", log.Fields{"error": err})
750 }
751 }
Stephane Barbarie6e1bd502018-11-05 22:44:45 -0500752 }
753 }
khenaidoof5a5bfa2019-01-23 22:20:29 -0500754 //TODO: FInd an elegant way to get out of the above loop when the Core is stopped
Stephane Barbarie6e1bd502018-11-05 22:44:45 -0500755}
756
757func (handler *APIHandler) sendChangeEvent(deviceId string, portStatus *openflow_13.OfpPortStatus) {
758 // TODO: validate the type of portStatus parameter
759 //if _, ok := portStatus.(*openflow_13.OfpPortStatus); ok {
760 //}
761 event := openflow_13.ChangeEvent{Id: deviceId, Event: &openflow_13.ChangeEvent_PortStatus{PortStatus: portStatus}}
762 log.Debugw("sendChangeEvent", log.Fields{"event": event})
763 // TODO: put the packet in the queue
764}
765
766func (handler *APIHandler) ReceiveChangeEvents(
767 empty *empty.Empty,
768 changeEvents voltha.VolthaService_ReceiveChangeEventsServer,
769) error {
770 log.Debugw("ReceiveChangeEvents-request", log.Fields{"changeEvents": changeEvents})
771 for {
772 // TODO: need to retrieve packet from queue
773 event := &openflow_13.ChangeEvent{}
774 time.Sleep(time.Duration(5) * time.Second)
775 err := changeEvents.Send(event)
776 if err != nil {
777 log.Errorw("Failed to send change event", log.Fields{"error": err})
778 }
779 }
khenaidoof5a5bfa2019-01-23 22:20:29 -0500780 // TODO: put the packet in the queue
781 }
Stephane Barbarie6e1bd502018-11-05 22:44:45 -0500782
783func (handler *APIHandler) Subscribe(
784 ctx context.Context,
785 ofAgent *voltha.OfAgentSubscriber,
786) (*voltha.OfAgentSubscriber, error) {
787 log.Debugw("Subscribe-request", log.Fields{"ofAgent": ofAgent})
788 return &voltha.OfAgentSubscriber{OfagentId: ofAgent.OfagentId, VolthaId: ofAgent.VolthaId}, nil
789}