blob: 0bbe5de8de222356ce0c39e963bb7d7fb95accfd [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
Richard Jankowski2755adf2019-01-17 17:16:48 -050035//TODO: Move this Tag into the proto file
36const OF_CONTROLLER_TAG= "voltha_backend_name"
37
khenaidoof5a5bfa2019-01-23 22:20:29 -050038const (
39 IMAGE_DOWNLOAD = iota
40 CANCEL_IMAGE_DOWNLOAD = iota
41 ACTIVATE_IMAGE = iota
42 REVERT_IMAGE = iota
43)
44
khenaidoo297cd252019-02-07 22:10:23 -050045
46type deviceID struct {
47 id string
48}
49
50type logicalDeviceID struct {
51 id string
52}
53
khenaidoobf6e7bb2018-08-14 22:27:29 -040054type APIHandler struct {
khenaidoob9203542018-09-17 22:56:37 -040055 deviceMgr *DeviceManager
56 logicalDeviceMgr *LogicalDeviceManager
khenaidoo21d51152019-02-01 13:48:37 -050057 adapterMgr *AdapterManager
khenaidood2b6df92018-12-13 16:37:20 -050058 packetInQueue *queue.Queue
khenaidoo9cdc1a62019-01-24 21:57:40 -050059 coreInCompetingMode bool
khenaidoob6080322019-01-29 21:47:38 -050060 longRunningRequestTimeout int64
61 defaultRequestTimeout int64
khenaidoobf6e7bb2018-08-14 22:27:29 -040062 da.DefaultAPIHandler
khenaidoo54e0ddf2019-02-27 16:21:33 -050063 core *Core
khenaidoobf6e7bb2018-08-14 22:27:29 -040064}
65
khenaidoo54e0ddf2019-02-27 16:21:33 -050066//func NewAPIHandler(deviceMgr *DeviceManager, lDeviceMgr *LogicalDeviceManager, adapterMgr *AdapterManager, inCompetingMode bool, longRunningRequestTimeout int64, defaultRequestTimeout int64 ) *APIHandler {
67// handler := &APIHandler{
68// deviceMgr: deviceMgr,
69// logicalDeviceMgr: lDeviceMgr,
70// adapterMgr:adapterMgr,
71// coreInCompetingMode:inCompetingMode,
72// longRunningRequestTimeout:longRunningRequestTimeout,
73// defaultRequestTimeout:defaultRequestTimeout,
74// // TODO: Figure out what the 'hint' parameter to queue.New does
75// packetInQueue: queue.New(10),
76// }
77// return handler
78//}
79
80func NewAPIHandler(core *Core) *APIHandler {
Stephane Barbarie6e1bd502018-11-05 22:44:45 -050081 handler := &APIHandler{
khenaidoo54e0ddf2019-02-27 16:21:33 -050082 deviceMgr: core.deviceMgr,
83 logicalDeviceMgr: core.logicalDeviceMgr,
84 adapterMgr: core.adapterMgr,
85 coreInCompetingMode: core.config.InCompetingMode,
86 longRunningRequestTimeout:core.config.LongRunningRequestTimeout,
87 defaultRequestTimeout:core.config.DefaultRequestTimeout,
Richard Jankowskidbab94a2018-12-06 16:20:25 -050088 // TODO: Figure out what the 'hint' parameter to queue.New does
khenaidood2b6df92018-12-13 16:37:20 -050089 packetInQueue: queue.New(10),
khenaidoo54e0ddf2019-02-27 16:21:33 -050090 core: core,
Stephane Barbarie6e1bd502018-11-05 22:44:45 -050091 }
khenaidoobf6e7bb2018-08-14 22:27:29 -040092 return handler
93}
khenaidoo4d4802d2018-10-04 21:59:49 -040094
95// isTestMode is a helper function to determine a function is invoked for testing only
khenaidoobf6e7bb2018-08-14 22:27:29 -040096func isTestMode(ctx context.Context) bool {
97 md, _ := metadata.FromIncomingContext(ctx)
98 _, exist := md[common.TestModeKeys_api_test.String()]
99 return exist
100}
101
Richard Jankowskid42826e2018-11-02 16:06:37 -0400102// This function attempts to extract the serial number from the request metadata
103// and create a KV transaction for that serial number for the current core.
104func (handler *APIHandler) createKvTransaction(ctx context.Context) (*KVTransaction, error) {
105 var (
khenaidoo43c82122018-11-22 18:38:28 -0500106 err error
107 ok bool
108 md metadata.MD
Richard Jankowskid42826e2018-11-02 16:06:37 -0400109 serNum []string
110 )
111 if md, ok = metadata.FromIncomingContext(ctx); !ok {
112 err = errors.New("metadata-not-found")
113 } else if serNum, ok = md["voltha_serial_number"]; !ok {
114 err = errors.New("serial-number-not-found")
115 }
116 if !ok {
117 log.Error(err)
118 return nil, err
119 }
120 // Create KV transaction
121 txn := NewKVTransaction(serNum[0])
122 return txn, nil
123}
124
Richard Jankowski2755adf2019-01-17 17:16:48 -0500125// isOFControllerRequest is a helper function to determine if a request was initiated
126// from the OpenFlow controller (or its proxy, e.g. OFAgent)
127func isOFControllerRequest(ctx context.Context) bool {
khenaidoo9cdc1a62019-01-24 21:57:40 -0500128 if md, ok := metadata.FromIncomingContext(ctx); ok {
129 // Metadata in context
130 if _, ok = md[OF_CONTROLLER_TAG]; ok {
131 // OFAgent field in metadata
132 return true
133 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500134 }
khenaidoo9cdc1a62019-01-24 21:57:40 -0500135 return false
136}
137
138// competeForTransaction is a helper function to determine whether every request needs to compete with another
139// Core to execute the request
140func (handler *APIHandler) competeForTransaction() bool {
141 return handler.coreInCompetingMode
142}
143
khenaidoo297cd252019-02-07 22:10:23 -0500144func (handler *APIHandler) acquireTransaction(ctx context.Context, id interface{}, maxTimeout ...int64) (*KVTransaction, error) {
khenaidoob6080322019-01-29 21:47:38 -0500145 timeout := handler.defaultRequestTimeout
khenaidoo9cdc1a62019-01-24 21:57:40 -0500146 if len(maxTimeout) > 0 {
147 timeout = maxTimeout[0]
Richard Jankowski2755adf2019-01-17 17:16:48 -0500148 }
khenaidoob6080322019-01-29 21:47:38 -0500149 log.Debugw("transaction-timeout", log.Fields{"timeout": timeout})
khenaidoo9cdc1a62019-01-24 21:57:40 -0500150 txn, err := handler.createKvTransaction(ctx)
151 if txn == nil {
152 return nil, err
153 } else if txn.Acquired(timeout) {
154 return txn, nil
155 } else {
khenaidoo297cd252019-02-07 22:10:23 -0500156 if id != nil {
157 // The id can either be a device Id or a logical device id.
158 if dId, ok := id.(*deviceID); ok {
159 // Since this core has not processed this request, let's load the device, along with its extended
160 // family (parents and children) in memory. This will keep this core in-sync with its paired core as
161 // much as possible. The watch feature in the core model will ensure that the contents of those objects in
162 // memory are in sync.
163 time.Sleep(2 * time.Second)
164 go handler.deviceMgr.load(dId.id)
165 } else if ldId, ok := id.(*logicalDeviceID); ok {
166 // This will load the logical device along with its children and grandchildren
167 go handler.logicalDeviceMgr.load(ldId.id)
168 }
169 }
khenaidoo9cdc1a62019-01-24 21:57:40 -0500170 return nil, errors.New("failed-to-seize-request")
Richard Jankowski2755adf2019-01-17 17:16:48 -0500171 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500172}
173
khenaidoo4d4802d2018-10-04 21:59:49 -0400174// waitForNilResponseOnSuccess is a helper function to wait for a response on channel ch where an nil
175// response is expected in a successful scenario
176func waitForNilResponseOnSuccess(ctx context.Context, ch chan interface{}) (*empty.Empty, error) {
177 select {
178 case res := <-ch:
179 if res == nil {
180 return new(empty.Empty), nil
181 } else if err, ok := res.(error); ok {
182 return new(empty.Empty), err
183 } else {
184 log.Warnw("unexpected-return-type", log.Fields{"result": res})
185 err = status.Errorf(codes.Internal, "%s", res)
186 return new(empty.Empty), err
187 }
188 case <-ctx.Done():
189 log.Debug("client-timeout")
190 return nil, ctx.Err()
191 }
192}
193
khenaidoobf6e7bb2018-08-14 22:27:29 -0400194func (handler *APIHandler) UpdateLogLevel(ctx context.Context, logging *voltha.Logging) (*empty.Empty, error) {
khenaidoo6f2fbe32019-01-18 16:16:50 -0500195 log.Debugw("UpdateLogLevel-request", log.Fields{"package": logging.PackageName, "intval": int(logging.Level)})
khenaidoo92e62c52018-10-03 14:02:54 -0400196 out := new(empty.Empty)
khenaidoo6f2fbe32019-01-18 16:16:50 -0500197 if logging.PackageName == "" {
198 log.SetAllLogLevel(int(logging.Level))
199 } else {
200 log.SetPackageLogLevel(logging.PackageName, int(logging.Level))
201 }
khenaidoo92e62c52018-10-03 14:02:54 -0400202 return out, nil
khenaidoobf6e7bb2018-08-14 22:27:29 -0400203}
204
khenaidoo54e0ddf2019-02-27 16:21:33 -0500205
206func (handler *APIHandler) UpdateMembership(ctx context.Context, membership *voltha.Membership) (*empty.Empty, error) {
207 log.Debugw("UpdateMembership-request", log.Fields{"membership": membership})
208 out := new(empty.Empty)
khenaidoo6417b6c2019-03-01 18:18:01 -0500209 if err := handler.core.updateCoreMembership(ctx, membership); err != nil {
khenaidoo54e0ddf2019-02-27 16:21:33 -0500210 return out, err
211 }
212 return out, nil
213}
214
khenaidoo6417b6c2019-03-01 18:18:01 -0500215func (handler *APIHandler) GetMembership(ctx context.Context, empty *empty.Empty) (*voltha.Membership, error) {
216 log.Debug("GetMembership-request")
217 if membership := handler.core.getCoreMembership(ctx); membership != nil {
218 return membership, nil
219 }
220 return &voltha.Membership{}, nil
221}
222
223
khenaidoobf6e7bb2018-08-14 22:27:29 -0400224func (handler *APIHandler) EnableLogicalDevicePort(ctx context.Context, id *voltha.LogicalPortId) (*empty.Empty, error) {
225 log.Debugw("EnableLogicalDevicePort-request", log.Fields{"id": id, "test": common.TestModeKeys_api_test.String()})
226 if isTestMode(ctx) {
227 out := new(empty.Empty)
228 return out, nil
229 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500230
khenaidoo9cdc1a62019-01-24 21:57:40 -0500231 if handler.competeForTransaction() {
khenaidoo297cd252019-02-07 22:10:23 -0500232 if txn, err := handler.acquireTransaction(ctx, &logicalDeviceID{id:id.Id}); err != nil {
Richard Jankowski2755adf2019-01-17 17:16:48 -0500233 return new(empty.Empty), err
Richard Jankowski2755adf2019-01-17 17:16:48 -0500234 } else {
khenaidoo9cdc1a62019-01-24 21:57:40 -0500235 defer txn.Close()
Richard Jankowski2755adf2019-01-17 17:16:48 -0500236 }
237 }
khenaidoo9cdc1a62019-01-24 21:57:40 -0500238
khenaidoo4d4802d2018-10-04 21:59:49 -0400239 ch := make(chan interface{})
240 defer close(ch)
khenaidoo19d7b632018-10-30 10:49:50 -0400241 go handler.logicalDeviceMgr.enableLogicalPort(ctx, id, ch)
khenaidoo4d4802d2018-10-04 21:59:49 -0400242 return waitForNilResponseOnSuccess(ctx, ch)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400243}
244
245func (handler *APIHandler) DisableLogicalDevicePort(ctx context.Context, id *voltha.LogicalPortId) (*empty.Empty, error) {
246 log.Debugw("DisableLogicalDevicePort-request", log.Fields{"id": id, "test": common.TestModeKeys_api_test.String()})
247 if isTestMode(ctx) {
248 out := new(empty.Empty)
249 return out, nil
250 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500251
khenaidoo9cdc1a62019-01-24 21:57:40 -0500252 if handler.competeForTransaction() {
khenaidoo297cd252019-02-07 22:10:23 -0500253 if txn, err := handler.acquireTransaction(ctx, &logicalDeviceID{id:id.Id}); err != nil {
Richard Jankowski2755adf2019-01-17 17:16:48 -0500254 return new(empty.Empty), err
Richard Jankowski2755adf2019-01-17 17:16:48 -0500255 } else {
khenaidoo9cdc1a62019-01-24 21:57:40 -0500256 defer txn.Close()
Richard Jankowski2755adf2019-01-17 17:16:48 -0500257 }
258 }
khenaidoo9cdc1a62019-01-24 21:57:40 -0500259
khenaidoo19d7b632018-10-30 10:49:50 -0400260 ch := make(chan interface{})
261 defer close(ch)
262 go handler.logicalDeviceMgr.disableLogicalPort(ctx, id, ch)
263 return waitForNilResponseOnSuccess(ctx, ch)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400264}
265
266func (handler *APIHandler) UpdateLogicalDeviceFlowTable(ctx context.Context, flow *openflow_13.FlowTableUpdate) (*empty.Empty, error) {
267 log.Debugw("UpdateLogicalDeviceFlowTable-request", log.Fields{"flow": flow, "test": common.TestModeKeys_api_test.String()})
268 if isTestMode(ctx) {
269 out := new(empty.Empty)
270 return out, nil
271 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500272
khenaidoo9cdc1a62019-01-24 21:57:40 -0500273 if handler.competeForTransaction() {
274 if !isOFControllerRequest(ctx) { // No need to acquire the transaction as request is sent to one core only
khenaidoo297cd252019-02-07 22:10:23 -0500275 if txn, err := handler.acquireTransaction(ctx, &logicalDeviceID{id:flow.Id}); err != nil {
khenaidoo9cdc1a62019-01-24 21:57:40 -0500276 return new(empty.Empty), err
277 } else {
278 defer txn.Close()
279 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500280 }
281 }
khenaidoo9cdc1a62019-01-24 21:57:40 -0500282
khenaidoo19d7b632018-10-30 10:49:50 -0400283 ch := make(chan interface{})
284 defer close(ch)
285 go handler.logicalDeviceMgr.updateFlowTable(ctx, flow.Id, flow.FlowMod, ch)
286 return waitForNilResponseOnSuccess(ctx, ch)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400287}
288
289func (handler *APIHandler) UpdateLogicalDeviceFlowGroupTable(ctx context.Context, flow *openflow_13.FlowGroupTableUpdate) (*empty.Empty, error) {
290 log.Debugw("UpdateLogicalDeviceFlowGroupTable-request", log.Fields{"flow": flow, "test": common.TestModeKeys_api_test.String()})
291 if isTestMode(ctx) {
292 out := new(empty.Empty)
293 return out, nil
294 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500295
khenaidoo9cdc1a62019-01-24 21:57:40 -0500296 if handler.competeForTransaction() {
297 if !isOFControllerRequest(ctx) { // No need to acquire the transaction as request is sent to one core only
khenaidoo297cd252019-02-07 22:10:23 -0500298 if txn, err := handler.acquireTransaction(ctx, &logicalDeviceID{id:flow.Id}); err != nil {
khenaidoo9cdc1a62019-01-24 21:57:40 -0500299 return new(empty.Empty), err
300 } else {
301 defer txn.Close()
302 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500303 }
304 }
khenaidoo9cdc1a62019-01-24 21:57:40 -0500305
khenaidoo19d7b632018-10-30 10:49:50 -0400306 ch := make(chan interface{})
307 defer close(ch)
308 go handler.logicalDeviceMgr.updateGroupTable(ctx, flow.Id, flow.GroupMod, ch)
309 return waitForNilResponseOnSuccess(ctx, ch)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400310}
311
khenaidoob9203542018-09-17 22:56:37 -0400312// GetDevice must be implemented in the read-only containers - should it also be implemented here?
313func (handler *APIHandler) GetDevice(ctx context.Context, id *voltha.ID) (*voltha.Device, error) {
314 log.Debugw("GetDevice-request", log.Fields{"id": id})
khenaidoo19d7b632018-10-30 10:49:50 -0400315 return handler.deviceMgr.GetDevice(id.Id)
khenaidoob9203542018-09-17 22:56:37 -0400316}
317
318// GetDevice must be implemented in the read-only containers - should it also be implemented here?
319func (handler *APIHandler) ListDevices(ctx context.Context, empty *empty.Empty) (*voltha.Devices, error) {
320 log.Debug("ListDevices")
321 return handler.deviceMgr.ListDevices()
322}
323
khenaidoo7ccedd52018-12-14 16:48:54 -0500324// ListDeviceIds returns the list of device ids managed by a voltha core
325func (handler *APIHandler) ListDeviceIds(ctx context.Context, empty *empty.Empty) (*voltha.IDs, error) {
326 log.Debug("ListDeviceIDs")
327 if isTestMode(ctx) {
328 out := &voltha.IDs{Items: make([]*voltha.ID, 0)}
329 return out, nil
330 }
331 return handler.deviceMgr.ListDeviceIds()
332}
333
334//ReconcileDevices is a request to a voltha core to managed a list of devices based on their IDs
335func (handler *APIHandler) ReconcileDevices(ctx context.Context, ids *voltha.IDs) (*empty.Empty, error) {
336 log.Debug("ReconcileDevices")
337 if isTestMode(ctx) {
338 out := new(empty.Empty)
339 return out, nil
340 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500341
khenaidoo9cdc1a62019-01-24 21:57:40 -0500342 // No need to grab a transaction as this request is core specific
343
khenaidoo7ccedd52018-12-14 16:48:54 -0500344 ch := make(chan interface{})
345 defer close(ch)
346 go handler.deviceMgr.ReconcileDevices(ctx, ids, ch)
347 return waitForNilResponseOnSuccess(ctx, ch)
348}
349
khenaidoob9203542018-09-17 22:56:37 -0400350// GetLogicalDevice must be implemented in the read-only containers - should it also be implemented here?
351func (handler *APIHandler) GetLogicalDevice(ctx context.Context, id *voltha.ID) (*voltha.LogicalDevice, error) {
352 log.Debugw("GetLogicalDevice-request", log.Fields{"id": id})
353 return handler.logicalDeviceMgr.getLogicalDevice(id.Id)
354}
355
356// ListLogicalDevices must be implemented in the read-only containers - should it also be implemented here?
357func (handler *APIHandler) ListLogicalDevices(ctx context.Context, empty *empty.Empty) (*voltha.LogicalDevices, error) {
358 log.Debug("ListLogicalDevices")
359 return handler.logicalDeviceMgr.listLogicalDevices()
360}
361
khenaidoo21d51152019-02-01 13:48:37 -0500362
363// ListAdapters returns the contents of all adapters known to the system
364func (handler *APIHandler) ListAdapters(ctx context.Context, empty *empty.Empty) (*voltha.Adapters, error) {
365 log.Debug("ListDevices")
366 return handler.adapterMgr.listAdapters(ctx)
367}
368
khenaidoo19d7b632018-10-30 10:49:50 -0400369// ListLogicalDevicePorts must be implemented in the read-only containers - should it also be implemented here?
370func (handler *APIHandler) ListLogicalDevicePorts(ctx context.Context, id *voltha.ID) (*voltha.LogicalPorts, error) {
371 log.Debugw("ListLogicalDevicePorts", log.Fields{"logicaldeviceid": id})
372 return handler.logicalDeviceMgr.ListLogicalDevicePorts(ctx, id.Id)
373}
374
khenaidoo4d4802d2018-10-04 21:59:49 -0400375// CreateDevice creates a new parent device in the data model
khenaidoobf6e7bb2018-08-14 22:27:29 -0400376func (handler *APIHandler) CreateDevice(ctx context.Context, device *voltha.Device) (*voltha.Device, error) {
khenaidoob9203542018-09-17 22:56:37 -0400377 log.Debugw("createdevice", log.Fields{"device": *device})
khenaidoobf6e7bb2018-08-14 22:27:29 -0400378 if isTestMode(ctx) {
379 return &voltha.Device{Id: device.Id}, nil
380 }
Richard Jankowskid42826e2018-11-02 16:06:37 -0400381
khenaidoo9cdc1a62019-01-24 21:57:40 -0500382 if handler.competeForTransaction() {
khenaidoo297cd252019-02-07 22:10:23 -0500383 if txn, err := handler.acquireTransaction(ctx, nil); err != nil {
Richard Jankowski2755adf2019-01-17 17:16:48 -0500384 return &voltha.Device{}, err
Richard Jankowski2755adf2019-01-17 17:16:48 -0500385 } else {
khenaidoo9cdc1a62019-01-24 21:57:40 -0500386 defer txn.Close()
Richard Jankowski2755adf2019-01-17 17:16:48 -0500387 }
388 }
khenaidoo9cdc1a62019-01-24 21:57:40 -0500389
khenaidoob9203542018-09-17 22:56:37 -0400390 ch := make(chan interface{})
391 defer close(ch)
392 go handler.deviceMgr.createDevice(ctx, device, ch)
393 select {
394 case res := <-ch:
khenaidoo92e62c52018-10-03 14:02:54 -0400395 if res != nil {
396 if err, ok := res.(error); ok {
397 return &voltha.Device{}, err
398 }
399 if d, ok := res.(*voltha.Device); ok {
400 return d, nil
401 }
khenaidoob9203542018-09-17 22:56:37 -0400402 }
khenaidoo92e62c52018-10-03 14:02:54 -0400403 log.Warnw("create-device-unexpected-return-type", log.Fields{"result": res})
404 err := status.Errorf(codes.Internal, "%s", res)
405 return &voltha.Device{}, err
khenaidoob9203542018-09-17 22:56:37 -0400406 case <-ctx.Done():
407 log.Debug("createdevice-client-timeout")
408 return nil, ctx.Err()
409 }
khenaidoobf6e7bb2018-08-14 22:27:29 -0400410}
411
khenaidoo4d4802d2018-10-04 21:59:49 -0400412// EnableDevice activates a device by invoking the adopt_device API on the appropriate adapter
khenaidoobf6e7bb2018-08-14 22:27:29 -0400413func (handler *APIHandler) EnableDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
khenaidoob9203542018-09-17 22:56:37 -0400414 log.Debugw("enabledevice", log.Fields{"id": id})
khenaidoobf6e7bb2018-08-14 22:27:29 -0400415 if isTestMode(ctx) {
khenaidoo4d4802d2018-10-04 21:59:49 -0400416 return new(empty.Empty), nil
khenaidoobf6e7bb2018-08-14 22:27:29 -0400417 }
Richard Jankowskid42826e2018-11-02 16:06:37 -0400418
khenaidoo9cdc1a62019-01-24 21:57:40 -0500419 if handler.competeForTransaction() {
khenaidoo297cd252019-02-07 22:10:23 -0500420 if txn, err := handler.acquireTransaction(ctx, &deviceID{id:id.Id}, handler.longRunningRequestTimeout); err != nil {
Richard Jankowski2755adf2019-01-17 17:16:48 -0500421 return new(empty.Empty), err
Richard Jankowski2755adf2019-01-17 17:16:48 -0500422 } else {
khenaidoo9cdc1a62019-01-24 21:57:40 -0500423 defer txn.Close()
Richard Jankowski2755adf2019-01-17 17:16:48 -0500424 }
425 }
khenaidoo9cdc1a62019-01-24 21:57:40 -0500426
khenaidoob9203542018-09-17 22:56:37 -0400427 ch := make(chan interface{})
428 defer close(ch)
429 go handler.deviceMgr.enableDevice(ctx, id, ch)
khenaidoo4d4802d2018-10-04 21:59:49 -0400430 return waitForNilResponseOnSuccess(ctx, ch)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400431}
432
khenaidoo4d4802d2018-10-04 21:59:49 -0400433// DisableDevice disables a device along with any child device it may have
khenaidoobf6e7bb2018-08-14 22:27:29 -0400434func (handler *APIHandler) DisableDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
435 log.Debugw("disabledevice-request", log.Fields{"id": id})
436 if isTestMode(ctx) {
khenaidoo4d4802d2018-10-04 21:59:49 -0400437 return new(empty.Empty), nil
khenaidoobf6e7bb2018-08-14 22:27:29 -0400438 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500439
khenaidoo9cdc1a62019-01-24 21:57:40 -0500440 if handler.competeForTransaction() {
khenaidoo297cd252019-02-07 22:10:23 -0500441 if txn, err := handler.acquireTransaction(ctx, &deviceID{id:id.Id}); err != nil {
Richard Jankowski2755adf2019-01-17 17:16:48 -0500442 return new(empty.Empty), err
Richard Jankowski2755adf2019-01-17 17:16:48 -0500443 } else {
khenaidoo9cdc1a62019-01-24 21:57:40 -0500444 defer txn.Close()
Richard Jankowski2755adf2019-01-17 17:16:48 -0500445 }
446 }
khenaidoo9cdc1a62019-01-24 21:57:40 -0500447
khenaidoo92e62c52018-10-03 14:02:54 -0400448 ch := make(chan interface{})
449 defer close(ch)
450 go handler.deviceMgr.disableDevice(ctx, id, ch)
khenaidoo4d4802d2018-10-04 21:59:49 -0400451 return waitForNilResponseOnSuccess(ctx, ch)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400452}
453
khenaidoo4d4802d2018-10-04 21:59:49 -0400454//RebootDevice invoked the reboot API to the corresponding adapter
khenaidoobf6e7bb2018-08-14 22:27:29 -0400455func (handler *APIHandler) RebootDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
khenaidoo4d4802d2018-10-04 21:59:49 -0400456 log.Debugw("rebootDevice-request", log.Fields{"id": id})
khenaidoobf6e7bb2018-08-14 22:27:29 -0400457 if isTestMode(ctx) {
khenaidoo4d4802d2018-10-04 21:59:49 -0400458 return new(empty.Empty), nil
khenaidoobf6e7bb2018-08-14 22:27:29 -0400459 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500460
khenaidoo9cdc1a62019-01-24 21:57:40 -0500461 if handler.competeForTransaction() {
khenaidoo297cd252019-02-07 22:10:23 -0500462 if txn, err := handler.acquireTransaction(ctx, &deviceID{id:id.Id}); err != nil {
Richard Jankowski2755adf2019-01-17 17:16:48 -0500463 return new(empty.Empty), err
Richard Jankowski2755adf2019-01-17 17:16:48 -0500464 } else {
khenaidoo9cdc1a62019-01-24 21:57:40 -0500465 defer txn.Close()
Richard Jankowski2755adf2019-01-17 17:16:48 -0500466 }
467 }
khenaidoo9cdc1a62019-01-24 21:57:40 -0500468
khenaidoo4d4802d2018-10-04 21:59:49 -0400469 ch := make(chan interface{})
470 defer close(ch)
471 go handler.deviceMgr.rebootDevice(ctx, id, ch)
472 return waitForNilResponseOnSuccess(ctx, ch)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400473}
474
khenaidoo4d4802d2018-10-04 21:59:49 -0400475// DeleteDevice removes a device from the data model
khenaidoobf6e7bb2018-08-14 22:27:29 -0400476func (handler *APIHandler) DeleteDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
477 log.Debugw("deletedevice-request", log.Fields{"id": id})
478 if isTestMode(ctx) {
khenaidoo4d4802d2018-10-04 21:59:49 -0400479 return new(empty.Empty), nil
khenaidoobf6e7bb2018-08-14 22:27:29 -0400480 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500481
khenaidoo9cdc1a62019-01-24 21:57:40 -0500482 if handler.competeForTransaction() {
khenaidoo297cd252019-02-07 22:10:23 -0500483 if txn, err := handler.acquireTransaction(ctx, nil); err != nil {
Richard Jankowski2755adf2019-01-17 17:16:48 -0500484 return new(empty.Empty), err
Richard Jankowski2755adf2019-01-17 17:16:48 -0500485 } else {
khenaidoo9cdc1a62019-01-24 21:57:40 -0500486 defer txn.Close()
Richard Jankowski2755adf2019-01-17 17:16:48 -0500487 }
488 }
khenaidoo9cdc1a62019-01-24 21:57:40 -0500489
khenaidoo4d4802d2018-10-04 21:59:49 -0400490 ch := make(chan interface{})
491 defer close(ch)
492 go handler.deviceMgr.deleteDevice(ctx, id, ch)
493 return waitForNilResponseOnSuccess(ctx, ch)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400494}
495
khenaidoof5a5bfa2019-01-23 22:20:29 -0500496// processImageRequest is a helper method to execute an image download request
497func (handler *APIHandler) processImageRequest(ctx context.Context, img *voltha.ImageDownload, requestType int) (*common.OperationResp, error) {
498 log.Debugw("processImageDownload", log.Fields{"img": *img, "requestType": requestType})
499 if isTestMode(ctx) {
500 resp := &common.OperationResp{Code: common.OperationResp_OPERATION_SUCCESS}
501 return resp, nil
502 }
503
khenaidoo9cdc1a62019-01-24 21:57:40 -0500504 if handler.competeForTransaction() {
khenaidoo297cd252019-02-07 22:10:23 -0500505 if txn, err := handler.acquireTransaction(ctx, &deviceID{id:img.Id}); err != nil {
khenaidoo9cdc1a62019-01-24 21:57:40 -0500506 return &common.OperationResp{}, err
507 } else {
508 defer txn.Close()
509 }
khenaidoof5a5bfa2019-01-23 22:20:29 -0500510 }
511
512 failedresponse := &common.OperationResp{Code:voltha.OperationResp_OPERATION_FAILURE}
513
514 ch := make(chan interface{})
515 defer close(ch)
516 switch requestType {
517 case IMAGE_DOWNLOAD:
518 go handler.deviceMgr.downloadImage(ctx, img, ch)
519 case CANCEL_IMAGE_DOWNLOAD:
520 go handler.deviceMgr.cancelImageDownload(ctx, img, ch)
521 case ACTIVATE_IMAGE:
522 go handler.deviceMgr.activateImage(ctx, img, ch)
523 case REVERT_IMAGE:
524 go handler.deviceMgr.revertImage(ctx, img, ch)
525 default:
526 log.Warn("invalid-request-type", log.Fields{"requestType": requestType})
527 return failedresponse, status.Errorf(codes.InvalidArgument, "%d", requestType)
528 }
529 select {
530 case res := <-ch:
531 if res != nil {
532 if err, ok := res.(error); ok {
533 return failedresponse, err
534 }
535 if opResp, ok := res.(*common.OperationResp); ok {
536 return opResp, nil
537 }
538 }
539 log.Warnw("download-image-unexpected-return-type", log.Fields{"result": res})
540 return failedresponse, status.Errorf(codes.Internal, "%s", res)
541 case <-ctx.Done():
542 log.Debug("downloadImage-client-timeout")
543 return nil, ctx.Err()
544 }
545}
546
khenaidoobf6e7bb2018-08-14 22:27:29 -0400547func (handler *APIHandler) DownloadImage(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
548 log.Debugw("DownloadImage-request", log.Fields{"img": *img})
549 if isTestMode(ctx) {
550 resp := &common.OperationResp{Code: common.OperationResp_OPERATION_SUCCESS}
551 return resp, nil
552 }
553
khenaidoof5a5bfa2019-01-23 22:20:29 -0500554 return handler.processImageRequest(ctx, img, IMAGE_DOWNLOAD)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400555}
556
557func (handler *APIHandler) CancelImageDownload(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
khenaidoof5a5bfa2019-01-23 22:20:29 -0500558 log.Debugw("cancelImageDownload-request", log.Fields{"img": *img})
khenaidoobf6e7bb2018-08-14 22:27:29 -0400559 if isTestMode(ctx) {
560 resp := &common.OperationResp{Code: common.OperationResp_OPERATION_SUCCESS}
561 return resp, nil
562 }
khenaidoof5a5bfa2019-01-23 22:20:29 -0500563 return handler.processImageRequest(ctx, img, CANCEL_IMAGE_DOWNLOAD)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400564}
565
566func (handler *APIHandler) ActivateImageUpdate(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
khenaidoof5a5bfa2019-01-23 22:20:29 -0500567 log.Debugw("activateImageUpdate-request", log.Fields{"img": *img})
khenaidoobf6e7bb2018-08-14 22:27:29 -0400568 if isTestMode(ctx) {
569 resp := &common.OperationResp{Code: common.OperationResp_OPERATION_SUCCESS}
570 return resp, nil
571 }
khenaidoof5a5bfa2019-01-23 22:20:29 -0500572
573 return handler.processImageRequest(ctx, img, ACTIVATE_IMAGE)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400574}
575
576func (handler *APIHandler) RevertImageUpdate(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
khenaidoof5a5bfa2019-01-23 22:20:29 -0500577 log.Debugw("revertImageUpdate-request", log.Fields{"img": *img})
khenaidoobf6e7bb2018-08-14 22:27:29 -0400578 if isTestMode(ctx) {
579 resp := &common.OperationResp{Code: common.OperationResp_OPERATION_SUCCESS}
580 return resp, nil
581 }
khenaidoof5a5bfa2019-01-23 22:20:29 -0500582
583 return handler.processImageRequest(ctx, img, REVERT_IMAGE)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400584}
585
khenaidoof5a5bfa2019-01-23 22:20:29 -0500586func (handler *APIHandler) GetImageDownloadStatus(ctx context.Context, img *voltha.ImageDownload) (*voltha.ImageDownload, error) {
587 log.Debugw("getImageDownloadStatus-request", log.Fields{"img": *img})
588 if isTestMode(ctx) {
Stephane Barbariedf5479f2019-01-29 22:13:00 -0500589 resp := &voltha.ImageDownload{DownloadState: voltha.ImageDownload_DOWNLOAD_SUCCEEDED}
khenaidoof5a5bfa2019-01-23 22:20:29 -0500590 return resp, nil
591 }
592
Stephane Barbariedf5479f2019-01-29 22:13:00 -0500593 failedresponse := &voltha.ImageDownload{DownloadState: voltha.ImageDownload_DOWNLOAD_UNKNOWN}
khenaidoof5a5bfa2019-01-23 22:20:29 -0500594
khenaidoo9cdc1a62019-01-24 21:57:40 -0500595 if handler.competeForTransaction() {
khenaidoo297cd252019-02-07 22:10:23 -0500596 if txn, err := handler.acquireTransaction(ctx, &deviceID{id:img.Id}); err != nil {
khenaidoo9cdc1a62019-01-24 21:57:40 -0500597 return failedresponse, err
598 } else {
599 defer txn.Close()
600 }
khenaidoof5a5bfa2019-01-23 22:20:29 -0500601 }
602
603 ch := make(chan interface{})
604 defer close(ch)
605 go handler.deviceMgr.getImageDownloadStatus(ctx, img, ch)
606
607 select {
608 case res := <-ch:
609 if res != nil {
610 if err, ok := res.(error); ok {
611 return failedresponse, err
612 }
613 if downloadResp, ok := res.(*voltha.ImageDownload); ok {
614 return downloadResp, nil
615 }
616 }
617 log.Warnw("download-image-status", log.Fields{"result": res})
618 return failedresponse, status.Errorf(codes.Internal, "%s", res)
619 case <-ctx.Done():
620 log.Debug("downloadImage-client-timeout")
621 return failedresponse, ctx.Err()
622 }
623}
624
625func (handler *APIHandler) GetImageDownload(ctx context.Context, img *voltha.ImageDownload) (*voltha.ImageDownload, error) {
626 log.Debugw("GetImageDownload-request", log.Fields{"img": *img})
627 if isTestMode(ctx) {
Stephane Barbariedf5479f2019-01-29 22:13:00 -0500628 resp := &voltha.ImageDownload{DownloadState: voltha.ImageDownload_DOWNLOAD_SUCCEEDED}
khenaidoof5a5bfa2019-01-23 22:20:29 -0500629 return resp, nil
630 }
631
632 if download, err := handler.deviceMgr.getImageDownload(ctx, img); err != nil {
Stephane Barbariedf5479f2019-01-29 22:13:00 -0500633 return &voltha.ImageDownload{DownloadState: voltha.ImageDownload_DOWNLOAD_UNKNOWN}, err
khenaidoof5a5bfa2019-01-23 22:20:29 -0500634 } else {
635 return download, nil
636 }
637}
638
639func (handler *APIHandler) ListImageDownloads(ctx context.Context, id *voltha.ID) (*voltha.ImageDownloads, error) {
640 log.Debugw("ListImageDownloads-request", log.Fields{"deviceId": id.Id})
641 if isTestMode(ctx) {
642 resp := &voltha.ImageDownloads{Items:[]*voltha.ImageDownload{}}
643 return resp, nil
644 }
645
646 if downloads, err := handler.deviceMgr.listImageDownloads(ctx, id.Id); err != nil {
647 failedResp := &voltha.ImageDownloads{
648 Items:[]*voltha.ImageDownload{
Stephane Barbariedf5479f2019-01-29 22:13:00 -0500649 &voltha.ImageDownload{DownloadState: voltha.ImageDownload_DOWNLOAD_UNKNOWN},
khenaidoof5a5bfa2019-01-23 22:20:29 -0500650 },
651 }
652 return failedResp, err
653 } else {
654 return downloads, nil
655 }
656}
657
658
khenaidoobf6e7bb2018-08-14 22:27:29 -0400659func (handler *APIHandler) UpdateDevicePmConfigs(ctx context.Context, configs *voltha.PmConfigs) (*empty.Empty, error) {
660 log.Debugw("UpdateDevicePmConfigs-request", log.Fields{"configs": *configs})
661 if isTestMode(ctx) {
662 out := new(empty.Empty)
663 return out, nil
664 }
665 return nil, errors.New("UnImplemented")
666}
667
668func (handler *APIHandler) CreateAlarmFilter(ctx context.Context, filter *voltha.AlarmFilter) (*voltha.AlarmFilter, error) {
669 log.Debugw("CreateAlarmFilter-request", log.Fields{"filter": *filter})
670 if isTestMode(ctx) {
671 f := &voltha.AlarmFilter{Id: filter.Id}
672 return f, nil
673 }
674 return nil, errors.New("UnImplemented")
675}
676
677func (handler *APIHandler) UpdateAlarmFilter(ctx context.Context, filter *voltha.AlarmFilter) (*voltha.AlarmFilter, error) {
678 log.Debugw("UpdateAlarmFilter-request", log.Fields{"filter": *filter})
679 if isTestMode(ctx) {
680 f := &voltha.AlarmFilter{Id: filter.Id}
681 return f, nil
682 }
683 return nil, errors.New("UnImplemented")
684}
685
686func (handler *APIHandler) DeleteAlarmFilter(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
687 log.Debugw("DeleteAlarmFilter-request", log.Fields{"id": *id})
688 if isTestMode(ctx) {
689 out := new(empty.Empty)
690 return out, nil
691 }
692 return nil, errors.New("UnImplemented")
693}
694
695func (handler *APIHandler) SelfTest(ctx context.Context, id *voltha.ID) (*voltha.SelfTestResponse, error) {
696 log.Debugw("SelfTest-request", log.Fields{"id": id})
697 if isTestMode(ctx) {
698 resp := &voltha.SelfTestResponse{Result: voltha.SelfTestResponse_SUCCESS}
699 return resp, nil
700 }
701 return nil, errors.New("UnImplemented")
702}
Stephane Barbarie6e1bd502018-11-05 22:44:45 -0500703
704func (handler *APIHandler) forwardPacketOut(packet *openflow_13.PacketOut) {
705 log.Debugw("forwardPacketOut-request", log.Fields{"packet": packet})
Richard Jankowski2755adf2019-01-17 17:16:48 -0500706 agent := handler.logicalDeviceMgr.getLogicalDeviceAgent(packet.Id)
707 agent.packetOut(packet.PacketOut)
Stephane Barbarie6e1bd502018-11-05 22:44:45 -0500708}
709func (handler *APIHandler) StreamPacketsOut(
710 packets voltha.VolthaService_StreamPacketsOutServer,
711) error {
712 log.Debugw("StreamPacketsOut-request", log.Fields{"packets": packets})
713 for {
714 packet, err := packets.Recv()
715
716 if err == io.EOF {
717 break
718 } else if err != nil {
719 log.Errorw("Failed to receive packet", log.Fields{"error": err})
720 }
721
722 handler.forwardPacketOut(packet)
723 }
724
725 log.Debugw("StreamPacketsOut-request-done", log.Fields{"packets": packets})
726 return nil
727}
728
khenaidoo297cd252019-02-07 22:10:23 -0500729func (handler *APIHandler) sendPacketIn(deviceId string, transationId string, packet *openflow_13.OfpPacketIn) {
730 // TODO: Augment the OF PacketIn to include the transactionId
Stephane Barbarie6e1bd502018-11-05 22:44:45 -0500731 packetIn := openflow_13.PacketIn{Id: deviceId, PacketIn: packet}
732 log.Debugw("sendPacketIn", log.Fields{"packetIn": packetIn})
Richard Jankowskidbab94a2018-12-06 16:20:25 -0500733 // Enqueue the packet
734 if err := handler.packetInQueue.Put(packetIn); err != nil {
735 log.Errorw("failed-to-enqueue-packet", log.Fields{"error": err})
736 }
Stephane Barbarie6e1bd502018-11-05 22:44:45 -0500737}
738
739func (handler *APIHandler) ReceivePacketsIn(
740 empty *empty.Empty,
741 packetsIn voltha.VolthaService_ReceivePacketsInServer,
742) error {
743 log.Debugw("ReceivePacketsIn-request", log.Fields{"packetsIn": packetsIn})
744
745 for {
Richard Jankowskidbab94a2018-12-06 16:20:25 -0500746 // Dequeue a packet
747 if packets, err := handler.packetInQueue.Get(1); err == nil {
748 log.Debugw("dequeued-packet", log.Fields{"packet": packets[0]})
749 if packet, ok := packets[0].(openflow_13.PacketIn); ok {
750 log.Debugw("sending-packet-in", log.Fields{"packet": packet})
751 if err := packetsIn.Send(&packet); err != nil {
752 log.Errorw("failed-to-send-packet", log.Fields{"error": err})
753 }
754 }
Stephane Barbarie6e1bd502018-11-05 22:44:45 -0500755 }
756 }
khenaidoof5a5bfa2019-01-23 22:20:29 -0500757 //TODO: FInd an elegant way to get out of the above loop when the Core is stopped
Stephane Barbarie6e1bd502018-11-05 22:44:45 -0500758}
759
760func (handler *APIHandler) sendChangeEvent(deviceId string, portStatus *openflow_13.OfpPortStatus) {
761 // TODO: validate the type of portStatus parameter
762 //if _, ok := portStatus.(*openflow_13.OfpPortStatus); ok {
763 //}
764 event := openflow_13.ChangeEvent{Id: deviceId, Event: &openflow_13.ChangeEvent_PortStatus{PortStatus: portStatus}}
765 log.Debugw("sendChangeEvent", log.Fields{"event": event})
766 // TODO: put the packet in the queue
767}
768
769func (handler *APIHandler) ReceiveChangeEvents(
770 empty *empty.Empty,
771 changeEvents voltha.VolthaService_ReceiveChangeEventsServer,
772) error {
773 log.Debugw("ReceiveChangeEvents-request", log.Fields{"changeEvents": changeEvents})
774 for {
775 // TODO: need to retrieve packet from queue
776 event := &openflow_13.ChangeEvent{}
777 time.Sleep(time.Duration(5) * time.Second)
778 err := changeEvents.Send(event)
779 if err != nil {
780 log.Errorw("Failed to send change event", log.Fields{"error": err})
781 }
782 }
khenaidoof5a5bfa2019-01-23 22:20:29 -0500783 // TODO: put the packet in the queue
784 }
Stephane Barbarie6e1bd502018-11-05 22:44:45 -0500785
786func (handler *APIHandler) Subscribe(
787 ctx context.Context,
788 ofAgent *voltha.OfAgentSubscriber,
789) (*voltha.OfAgentSubscriber, error) {
790 log.Debugw("Subscribe-request", log.Fields{"ofAgent": ofAgent})
791 return &voltha.OfAgentSubscriber{OfagentId: ofAgent.OfagentId, VolthaId: ofAgent.VolthaId}, nil
792}