blob: c65178d7f93ec6db0992022e6979bbba7f05b7ec [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
khenaidoob6080322019-01-29 21:47:38 -050038//const MAX_RESPONSE_TIME = int64(500) // milliseconds
Richard Jankowskid42826e2018-11-02 16:06:37 -040039
khenaidoof5a5bfa2019-01-23 22:20:29 -050040const (
41 IMAGE_DOWNLOAD = iota
42 CANCEL_IMAGE_DOWNLOAD = iota
43 ACTIVATE_IMAGE = iota
44 REVERT_IMAGE = iota
45)
46
khenaidoobf6e7bb2018-08-14 22:27:29 -040047type APIHandler struct {
khenaidoob9203542018-09-17 22:56:37 -040048 deviceMgr *DeviceManager
49 logicalDeviceMgr *LogicalDeviceManager
khenaidood2b6df92018-12-13 16:37:20 -050050 packetInQueue *queue.Queue
khenaidoo9cdc1a62019-01-24 21:57:40 -050051 coreInCompetingMode bool
khenaidoob6080322019-01-29 21:47:38 -050052 longRunningRequestTimeout int64
53 defaultRequestTimeout int64
khenaidoobf6e7bb2018-08-14 22:27:29 -040054 da.DefaultAPIHandler
55}
56
khenaidoob6080322019-01-29 21:47:38 -050057func NewAPIHandler(deviceMgr *DeviceManager, lDeviceMgr *LogicalDeviceManager, inCompetingMode bool, longRunningRequestTimeout int64, defaultRequestTimeout int64 ) *APIHandler {
Stephane Barbarie6e1bd502018-11-05 22:44:45 -050058 handler := &APIHandler{
59 deviceMgr: deviceMgr,
60 logicalDeviceMgr: lDeviceMgr,
khenaidoo9cdc1a62019-01-24 21:57:40 -050061 coreInCompetingMode:inCompetingMode,
khenaidoob6080322019-01-29 21:47:38 -050062 longRunningRequestTimeout:longRunningRequestTimeout,
63 defaultRequestTimeout:defaultRequestTimeout,
Richard Jankowskidbab94a2018-12-06 16:20:25 -050064 // TODO: Figure out what the 'hint' parameter to queue.New does
khenaidood2b6df92018-12-13 16:37:20 -050065 packetInQueue: queue.New(10),
Stephane Barbarie6e1bd502018-11-05 22:44:45 -050066 }
khenaidoobf6e7bb2018-08-14 22:27:29 -040067 return handler
68}
khenaidoo4d4802d2018-10-04 21:59:49 -040069
70// isTestMode is a helper function to determine a function is invoked for testing only
khenaidoobf6e7bb2018-08-14 22:27:29 -040071func isTestMode(ctx context.Context) bool {
72 md, _ := metadata.FromIncomingContext(ctx)
73 _, exist := md[common.TestModeKeys_api_test.String()]
74 return exist
75}
76
Richard Jankowskid42826e2018-11-02 16:06:37 -040077// This function attempts to extract the serial number from the request metadata
78// and create a KV transaction for that serial number for the current core.
79func (handler *APIHandler) createKvTransaction(ctx context.Context) (*KVTransaction, error) {
80 var (
khenaidoo43c82122018-11-22 18:38:28 -050081 err error
82 ok bool
83 md metadata.MD
Richard Jankowskid42826e2018-11-02 16:06:37 -040084 serNum []string
85 )
86 if md, ok = metadata.FromIncomingContext(ctx); !ok {
87 err = errors.New("metadata-not-found")
88 } else if serNum, ok = md["voltha_serial_number"]; !ok {
89 err = errors.New("serial-number-not-found")
90 }
91 if !ok {
92 log.Error(err)
93 return nil, err
94 }
95 // Create KV transaction
96 txn := NewKVTransaction(serNum[0])
97 return txn, nil
98}
99
Richard Jankowski2755adf2019-01-17 17:16:48 -0500100// isOFControllerRequest is a helper function to determine if a request was initiated
101// from the OpenFlow controller (or its proxy, e.g. OFAgent)
102func isOFControllerRequest(ctx context.Context) bool {
khenaidoo9cdc1a62019-01-24 21:57:40 -0500103 if md, ok := metadata.FromIncomingContext(ctx); ok {
104 // Metadata in context
105 if _, ok = md[OF_CONTROLLER_TAG]; ok {
106 // OFAgent field in metadata
107 return true
108 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500109 }
khenaidoo9cdc1a62019-01-24 21:57:40 -0500110 return false
111}
112
113// competeForTransaction is a helper function to determine whether every request needs to compete with another
114// Core to execute the request
115func (handler *APIHandler) competeForTransaction() bool {
116 return handler.coreInCompetingMode
117}
118
119func (handler *APIHandler) acquireTransaction(ctx context.Context, maxTimeout ...int64) (*KVTransaction, error) {
khenaidoob6080322019-01-29 21:47:38 -0500120 timeout := handler.defaultRequestTimeout
khenaidoo9cdc1a62019-01-24 21:57:40 -0500121 if len(maxTimeout) > 0 {
122 timeout = maxTimeout[0]
Richard Jankowski2755adf2019-01-17 17:16:48 -0500123 }
khenaidoob6080322019-01-29 21:47:38 -0500124 log.Debugw("transaction-timeout", log.Fields{"timeout": timeout})
khenaidoo9cdc1a62019-01-24 21:57:40 -0500125 txn, err := handler.createKvTransaction(ctx)
126 if txn == nil {
127 return nil, err
128 } else if txn.Acquired(timeout) {
129 return txn, nil
130 } else {
131 return nil, errors.New("failed-to-seize-request")
Richard Jankowski2755adf2019-01-17 17:16:48 -0500132 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500133}
134
khenaidoo4d4802d2018-10-04 21:59:49 -0400135// waitForNilResponseOnSuccess is a helper function to wait for a response on channel ch where an nil
136// response is expected in a successful scenario
137func waitForNilResponseOnSuccess(ctx context.Context, ch chan interface{}) (*empty.Empty, error) {
138 select {
139 case res := <-ch:
140 if res == nil {
141 return new(empty.Empty), nil
142 } else if err, ok := res.(error); ok {
143 return new(empty.Empty), err
144 } else {
145 log.Warnw("unexpected-return-type", log.Fields{"result": res})
146 err = status.Errorf(codes.Internal, "%s", res)
147 return new(empty.Empty), err
148 }
149 case <-ctx.Done():
150 log.Debug("client-timeout")
151 return nil, ctx.Err()
152 }
153}
154
khenaidoobf6e7bb2018-08-14 22:27:29 -0400155func (handler *APIHandler) UpdateLogLevel(ctx context.Context, logging *voltha.Logging) (*empty.Empty, error) {
khenaidoo6f2fbe32019-01-18 16:16:50 -0500156 log.Debugw("UpdateLogLevel-request", log.Fields{"package": logging.PackageName, "intval": int(logging.Level)})
khenaidoo92e62c52018-10-03 14:02:54 -0400157 out := new(empty.Empty)
khenaidoo6f2fbe32019-01-18 16:16:50 -0500158 if logging.PackageName == "" {
159 log.SetAllLogLevel(int(logging.Level))
160 } else {
161 log.SetPackageLogLevel(logging.PackageName, int(logging.Level))
162 }
khenaidoo92e62c52018-10-03 14:02:54 -0400163 return out, nil
khenaidoobf6e7bb2018-08-14 22:27:29 -0400164}
165
166func (handler *APIHandler) EnableLogicalDevicePort(ctx context.Context, id *voltha.LogicalPortId) (*empty.Empty, error) {
167 log.Debugw("EnableLogicalDevicePort-request", log.Fields{"id": id, "test": common.TestModeKeys_api_test.String()})
168 if isTestMode(ctx) {
169 out := new(empty.Empty)
170 return out, nil
171 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500172
khenaidoo9cdc1a62019-01-24 21:57:40 -0500173 if handler.competeForTransaction() {
174 if txn, err := handler.acquireTransaction(ctx); err != nil {
Richard Jankowski2755adf2019-01-17 17:16:48 -0500175 return new(empty.Empty), err
Richard Jankowski2755adf2019-01-17 17:16:48 -0500176 } else {
khenaidoo9cdc1a62019-01-24 21:57:40 -0500177 defer txn.Close()
Richard Jankowski2755adf2019-01-17 17:16:48 -0500178 }
179 }
khenaidoo9cdc1a62019-01-24 21:57:40 -0500180
khenaidoo4d4802d2018-10-04 21:59:49 -0400181 ch := make(chan interface{})
182 defer close(ch)
khenaidoo19d7b632018-10-30 10:49:50 -0400183 go handler.logicalDeviceMgr.enableLogicalPort(ctx, id, ch)
khenaidoo4d4802d2018-10-04 21:59:49 -0400184 return waitForNilResponseOnSuccess(ctx, ch)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400185}
186
187func (handler *APIHandler) DisableLogicalDevicePort(ctx context.Context, id *voltha.LogicalPortId) (*empty.Empty, error) {
188 log.Debugw("DisableLogicalDevicePort-request", log.Fields{"id": id, "test": common.TestModeKeys_api_test.String()})
189 if isTestMode(ctx) {
190 out := new(empty.Empty)
191 return out, nil
192 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500193
khenaidoo9cdc1a62019-01-24 21:57:40 -0500194 if handler.competeForTransaction() {
195 if txn, err := handler.acquireTransaction(ctx); err != nil {
Richard Jankowski2755adf2019-01-17 17:16:48 -0500196 return new(empty.Empty), err
Richard Jankowski2755adf2019-01-17 17:16:48 -0500197 } else {
khenaidoo9cdc1a62019-01-24 21:57:40 -0500198 defer txn.Close()
Richard Jankowski2755adf2019-01-17 17:16:48 -0500199 }
200 }
khenaidoo9cdc1a62019-01-24 21:57:40 -0500201
khenaidoo19d7b632018-10-30 10:49:50 -0400202 ch := make(chan interface{})
203 defer close(ch)
204 go handler.logicalDeviceMgr.disableLogicalPort(ctx, id, ch)
205 return waitForNilResponseOnSuccess(ctx, ch)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400206}
207
208func (handler *APIHandler) UpdateLogicalDeviceFlowTable(ctx context.Context, flow *openflow_13.FlowTableUpdate) (*empty.Empty, error) {
209 log.Debugw("UpdateLogicalDeviceFlowTable-request", log.Fields{"flow": flow, "test": common.TestModeKeys_api_test.String()})
210 if isTestMode(ctx) {
211 out := new(empty.Empty)
212 return out, nil
213 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500214
khenaidoo9cdc1a62019-01-24 21:57:40 -0500215 if handler.competeForTransaction() {
216 if !isOFControllerRequest(ctx) { // No need to acquire the transaction as request is sent to one core only
217 if txn, err := handler.acquireTransaction(ctx); err != nil {
218 return new(empty.Empty), err
219 } else {
220 defer txn.Close()
221 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500222 }
223 }
khenaidoo9cdc1a62019-01-24 21:57:40 -0500224
khenaidoo19d7b632018-10-30 10:49:50 -0400225 ch := make(chan interface{})
226 defer close(ch)
227 go handler.logicalDeviceMgr.updateFlowTable(ctx, flow.Id, flow.FlowMod, ch)
228 return waitForNilResponseOnSuccess(ctx, ch)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400229}
230
231func (handler *APIHandler) UpdateLogicalDeviceFlowGroupTable(ctx context.Context, flow *openflow_13.FlowGroupTableUpdate) (*empty.Empty, error) {
232 log.Debugw("UpdateLogicalDeviceFlowGroupTable-request", log.Fields{"flow": flow, "test": common.TestModeKeys_api_test.String()})
233 if isTestMode(ctx) {
234 out := new(empty.Empty)
235 return out, nil
236 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500237
khenaidoo9cdc1a62019-01-24 21:57:40 -0500238 if handler.competeForTransaction() {
239 if !isOFControllerRequest(ctx) { // No need to acquire the transaction as request is sent to one core only
240 if txn, err := handler.acquireTransaction(ctx); err != nil {
241 return new(empty.Empty), err
242 } else {
243 defer txn.Close()
244 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500245 }
246 }
khenaidoo9cdc1a62019-01-24 21:57:40 -0500247
khenaidoo19d7b632018-10-30 10:49:50 -0400248 ch := make(chan interface{})
249 defer close(ch)
250 go handler.logicalDeviceMgr.updateGroupTable(ctx, flow.Id, flow.GroupMod, ch)
251 return waitForNilResponseOnSuccess(ctx, ch)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400252}
253
khenaidoob9203542018-09-17 22:56:37 -0400254// GetDevice must be implemented in the read-only containers - should it also be implemented here?
255func (handler *APIHandler) GetDevice(ctx context.Context, id *voltha.ID) (*voltha.Device, error) {
256 log.Debugw("GetDevice-request", log.Fields{"id": id})
khenaidoo19d7b632018-10-30 10:49:50 -0400257 return handler.deviceMgr.GetDevice(id.Id)
khenaidoob9203542018-09-17 22:56:37 -0400258}
259
260// GetDevice must be implemented in the read-only containers - should it also be implemented here?
261func (handler *APIHandler) ListDevices(ctx context.Context, empty *empty.Empty) (*voltha.Devices, error) {
262 log.Debug("ListDevices")
263 return handler.deviceMgr.ListDevices()
264}
265
khenaidoo7ccedd52018-12-14 16:48:54 -0500266// ListDeviceIds returns the list of device ids managed by a voltha core
267func (handler *APIHandler) ListDeviceIds(ctx context.Context, empty *empty.Empty) (*voltha.IDs, error) {
268 log.Debug("ListDeviceIDs")
269 if isTestMode(ctx) {
270 out := &voltha.IDs{Items: make([]*voltha.ID, 0)}
271 return out, nil
272 }
273 return handler.deviceMgr.ListDeviceIds()
274}
275
276//ReconcileDevices is a request to a voltha core to managed a list of devices based on their IDs
277func (handler *APIHandler) ReconcileDevices(ctx context.Context, ids *voltha.IDs) (*empty.Empty, error) {
278 log.Debug("ReconcileDevices")
279 if isTestMode(ctx) {
280 out := new(empty.Empty)
281 return out, nil
282 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500283
khenaidoo9cdc1a62019-01-24 21:57:40 -0500284 // No need to grab a transaction as this request is core specific
285
khenaidoo7ccedd52018-12-14 16:48:54 -0500286 ch := make(chan interface{})
287 defer close(ch)
288 go handler.deviceMgr.ReconcileDevices(ctx, ids, ch)
289 return waitForNilResponseOnSuccess(ctx, ch)
290}
291
khenaidoob9203542018-09-17 22:56:37 -0400292// GetLogicalDevice must be implemented in the read-only containers - should it also be implemented here?
293func (handler *APIHandler) GetLogicalDevice(ctx context.Context, id *voltha.ID) (*voltha.LogicalDevice, error) {
294 log.Debugw("GetLogicalDevice-request", log.Fields{"id": id})
295 return handler.logicalDeviceMgr.getLogicalDevice(id.Id)
296}
297
298// ListLogicalDevices must be implemented in the read-only containers - should it also be implemented here?
299func (handler *APIHandler) ListLogicalDevices(ctx context.Context, empty *empty.Empty) (*voltha.LogicalDevices, error) {
300 log.Debug("ListLogicalDevices")
301 return handler.logicalDeviceMgr.listLogicalDevices()
302}
303
khenaidoo19d7b632018-10-30 10:49:50 -0400304// ListLogicalDevicePorts must be implemented in the read-only containers - should it also be implemented here?
305func (handler *APIHandler) ListLogicalDevicePorts(ctx context.Context, id *voltha.ID) (*voltha.LogicalPorts, error) {
306 log.Debugw("ListLogicalDevicePorts", log.Fields{"logicaldeviceid": id})
307 return handler.logicalDeviceMgr.ListLogicalDevicePorts(ctx, id.Id)
308}
309
khenaidoo4d4802d2018-10-04 21:59:49 -0400310// CreateDevice creates a new parent device in the data model
khenaidoobf6e7bb2018-08-14 22:27:29 -0400311func (handler *APIHandler) CreateDevice(ctx context.Context, device *voltha.Device) (*voltha.Device, error) {
khenaidoob9203542018-09-17 22:56:37 -0400312 log.Debugw("createdevice", log.Fields{"device": *device})
khenaidoobf6e7bb2018-08-14 22:27:29 -0400313 if isTestMode(ctx) {
314 return &voltha.Device{Id: device.Id}, nil
315 }
Richard Jankowskid42826e2018-11-02 16:06:37 -0400316
khenaidoo9cdc1a62019-01-24 21:57:40 -0500317 if handler.competeForTransaction() {
318 if txn, err := handler.acquireTransaction(ctx); err != nil {
Richard Jankowski2755adf2019-01-17 17:16:48 -0500319 return &voltha.Device{}, err
Richard Jankowski2755adf2019-01-17 17:16:48 -0500320 } else {
khenaidoo9cdc1a62019-01-24 21:57:40 -0500321 defer txn.Close()
Richard Jankowski2755adf2019-01-17 17:16:48 -0500322 }
323 }
khenaidoo9cdc1a62019-01-24 21:57:40 -0500324
khenaidoob9203542018-09-17 22:56:37 -0400325 ch := make(chan interface{})
326 defer close(ch)
327 go handler.deviceMgr.createDevice(ctx, device, ch)
328 select {
329 case res := <-ch:
khenaidoo92e62c52018-10-03 14:02:54 -0400330 if res != nil {
331 if err, ok := res.(error); ok {
332 return &voltha.Device{}, err
333 }
334 if d, ok := res.(*voltha.Device); ok {
335 return d, nil
336 }
khenaidoob9203542018-09-17 22:56:37 -0400337 }
khenaidoo92e62c52018-10-03 14:02:54 -0400338 log.Warnw("create-device-unexpected-return-type", log.Fields{"result": res})
339 err := status.Errorf(codes.Internal, "%s", res)
340 return &voltha.Device{}, err
khenaidoob9203542018-09-17 22:56:37 -0400341 case <-ctx.Done():
342 log.Debug("createdevice-client-timeout")
343 return nil, ctx.Err()
344 }
khenaidoobf6e7bb2018-08-14 22:27:29 -0400345}
346
khenaidoo4d4802d2018-10-04 21:59:49 -0400347// EnableDevice activates a device by invoking the adopt_device API on the appropriate adapter
khenaidoobf6e7bb2018-08-14 22:27:29 -0400348func (handler *APIHandler) EnableDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
khenaidoob9203542018-09-17 22:56:37 -0400349 log.Debugw("enabledevice", log.Fields{"id": id})
khenaidoobf6e7bb2018-08-14 22:27:29 -0400350 if isTestMode(ctx) {
khenaidoo4d4802d2018-10-04 21:59:49 -0400351 return new(empty.Empty), nil
khenaidoobf6e7bb2018-08-14 22:27:29 -0400352 }
Richard Jankowskid42826e2018-11-02 16:06:37 -0400353
khenaidoo9cdc1a62019-01-24 21:57:40 -0500354 if handler.competeForTransaction() {
khenaidoob6080322019-01-29 21:47:38 -0500355 if txn, err := handler.acquireTransaction(ctx, handler.longRunningRequestTimeout); err != nil {
Richard Jankowski2755adf2019-01-17 17:16:48 -0500356 return new(empty.Empty), err
Richard Jankowski2755adf2019-01-17 17:16:48 -0500357 } else {
khenaidoo9cdc1a62019-01-24 21:57:40 -0500358 defer txn.Close()
Richard Jankowski2755adf2019-01-17 17:16:48 -0500359 }
360 }
khenaidoo9cdc1a62019-01-24 21:57:40 -0500361
khenaidoob9203542018-09-17 22:56:37 -0400362 ch := make(chan interface{})
363 defer close(ch)
364 go handler.deviceMgr.enableDevice(ctx, id, ch)
khenaidoo4d4802d2018-10-04 21:59:49 -0400365 return waitForNilResponseOnSuccess(ctx, ch)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400366}
367
khenaidoo4d4802d2018-10-04 21:59:49 -0400368// DisableDevice disables a device along with any child device it may have
khenaidoobf6e7bb2018-08-14 22:27:29 -0400369func (handler *APIHandler) DisableDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
370 log.Debugw("disabledevice-request", log.Fields{"id": id})
371 if isTestMode(ctx) {
khenaidoo4d4802d2018-10-04 21:59:49 -0400372 return new(empty.Empty), nil
khenaidoobf6e7bb2018-08-14 22:27:29 -0400373 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500374
khenaidoo9cdc1a62019-01-24 21:57:40 -0500375 if handler.competeForTransaction() {
376 if txn, err := handler.acquireTransaction(ctx); err != nil {
Richard Jankowski2755adf2019-01-17 17:16:48 -0500377 return new(empty.Empty), err
Richard Jankowski2755adf2019-01-17 17:16:48 -0500378 } else {
khenaidoo9cdc1a62019-01-24 21:57:40 -0500379 defer txn.Close()
Richard Jankowski2755adf2019-01-17 17:16:48 -0500380 }
381 }
khenaidoo9cdc1a62019-01-24 21:57:40 -0500382
khenaidoo92e62c52018-10-03 14:02:54 -0400383 ch := make(chan interface{})
384 defer close(ch)
385 go handler.deviceMgr.disableDevice(ctx, id, ch)
khenaidoo4d4802d2018-10-04 21:59:49 -0400386 return waitForNilResponseOnSuccess(ctx, ch)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400387}
388
khenaidoo4d4802d2018-10-04 21:59:49 -0400389//RebootDevice invoked the reboot API to the corresponding adapter
khenaidoobf6e7bb2018-08-14 22:27:29 -0400390func (handler *APIHandler) RebootDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
khenaidoo4d4802d2018-10-04 21:59:49 -0400391 log.Debugw("rebootDevice-request", log.Fields{"id": id})
khenaidoobf6e7bb2018-08-14 22:27:29 -0400392 if isTestMode(ctx) {
khenaidoo4d4802d2018-10-04 21:59:49 -0400393 return new(empty.Empty), nil
khenaidoobf6e7bb2018-08-14 22:27:29 -0400394 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500395
khenaidoo9cdc1a62019-01-24 21:57:40 -0500396 if handler.competeForTransaction() {
397 if txn, err := handler.acquireTransaction(ctx); err != nil {
Richard Jankowski2755adf2019-01-17 17:16:48 -0500398 return new(empty.Empty), err
Richard Jankowski2755adf2019-01-17 17:16:48 -0500399 } else {
khenaidoo9cdc1a62019-01-24 21:57:40 -0500400 defer txn.Close()
Richard Jankowski2755adf2019-01-17 17:16:48 -0500401 }
402 }
khenaidoo9cdc1a62019-01-24 21:57:40 -0500403
khenaidoo4d4802d2018-10-04 21:59:49 -0400404 ch := make(chan interface{})
405 defer close(ch)
406 go handler.deviceMgr.rebootDevice(ctx, id, ch)
407 return waitForNilResponseOnSuccess(ctx, ch)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400408}
409
khenaidoo4d4802d2018-10-04 21:59:49 -0400410// DeleteDevice removes a device from the data model
khenaidoobf6e7bb2018-08-14 22:27:29 -0400411func (handler *APIHandler) DeleteDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
412 log.Debugw("deletedevice-request", log.Fields{"id": id})
413 if isTestMode(ctx) {
khenaidoo4d4802d2018-10-04 21:59:49 -0400414 return new(empty.Empty), nil
khenaidoobf6e7bb2018-08-14 22:27:29 -0400415 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500416
khenaidoo9cdc1a62019-01-24 21:57:40 -0500417 if handler.competeForTransaction() {
418 if txn, err := handler.acquireTransaction(ctx); err != nil {
Richard Jankowski2755adf2019-01-17 17:16:48 -0500419 return new(empty.Empty), err
Richard Jankowski2755adf2019-01-17 17:16:48 -0500420 } else {
khenaidoo9cdc1a62019-01-24 21:57:40 -0500421 defer txn.Close()
Richard Jankowski2755adf2019-01-17 17:16:48 -0500422 }
423 }
khenaidoo9cdc1a62019-01-24 21:57:40 -0500424
khenaidoo4d4802d2018-10-04 21:59:49 -0400425 ch := make(chan interface{})
426 defer close(ch)
427 go handler.deviceMgr.deleteDevice(ctx, id, ch)
428 return waitForNilResponseOnSuccess(ctx, ch)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400429}
430
khenaidoof5a5bfa2019-01-23 22:20:29 -0500431// processImageRequest is a helper method to execute an image download request
432func (handler *APIHandler) processImageRequest(ctx context.Context, img *voltha.ImageDownload, requestType int) (*common.OperationResp, error) {
433 log.Debugw("processImageDownload", log.Fields{"img": *img, "requestType": requestType})
434 if isTestMode(ctx) {
435 resp := &common.OperationResp{Code: common.OperationResp_OPERATION_SUCCESS}
436 return resp, nil
437 }
438
khenaidoo9cdc1a62019-01-24 21:57:40 -0500439 if handler.competeForTransaction() {
440 if txn, err := handler.acquireTransaction(ctx); err != nil {
441 return &common.OperationResp{}, err
442 } else {
443 defer txn.Close()
444 }
khenaidoof5a5bfa2019-01-23 22:20:29 -0500445 }
446
447 failedresponse := &common.OperationResp{Code:voltha.OperationResp_OPERATION_FAILURE}
448
449 ch := make(chan interface{})
450 defer close(ch)
451 switch requestType {
452 case IMAGE_DOWNLOAD:
453 go handler.deviceMgr.downloadImage(ctx, img, ch)
454 case CANCEL_IMAGE_DOWNLOAD:
455 go handler.deviceMgr.cancelImageDownload(ctx, img, ch)
456 case ACTIVATE_IMAGE:
457 go handler.deviceMgr.activateImage(ctx, img, ch)
458 case REVERT_IMAGE:
459 go handler.deviceMgr.revertImage(ctx, img, ch)
460 default:
461 log.Warn("invalid-request-type", log.Fields{"requestType": requestType})
462 return failedresponse, status.Errorf(codes.InvalidArgument, "%d", requestType)
463 }
464 select {
465 case res := <-ch:
466 if res != nil {
467 if err, ok := res.(error); ok {
468 return failedresponse, err
469 }
470 if opResp, ok := res.(*common.OperationResp); ok {
471 return opResp, nil
472 }
473 }
474 log.Warnw("download-image-unexpected-return-type", log.Fields{"result": res})
475 return failedresponse, status.Errorf(codes.Internal, "%s", res)
476 case <-ctx.Done():
477 log.Debug("downloadImage-client-timeout")
478 return nil, ctx.Err()
479 }
480}
481
khenaidoobf6e7bb2018-08-14 22:27:29 -0400482func (handler *APIHandler) DownloadImage(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
483 log.Debugw("DownloadImage-request", log.Fields{"img": *img})
484 if isTestMode(ctx) {
485 resp := &common.OperationResp{Code: common.OperationResp_OPERATION_SUCCESS}
486 return resp, nil
487 }
488
khenaidoof5a5bfa2019-01-23 22:20:29 -0500489 return handler.processImageRequest(ctx, img, IMAGE_DOWNLOAD)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400490}
491
492func (handler *APIHandler) CancelImageDownload(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
khenaidoof5a5bfa2019-01-23 22:20:29 -0500493 log.Debugw("cancelImageDownload-request", log.Fields{"img": *img})
khenaidoobf6e7bb2018-08-14 22:27:29 -0400494 if isTestMode(ctx) {
495 resp := &common.OperationResp{Code: common.OperationResp_OPERATION_SUCCESS}
496 return resp, nil
497 }
khenaidoof5a5bfa2019-01-23 22:20:29 -0500498 return handler.processImageRequest(ctx, img, CANCEL_IMAGE_DOWNLOAD)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400499}
500
501func (handler *APIHandler) ActivateImageUpdate(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
khenaidoof5a5bfa2019-01-23 22:20:29 -0500502 log.Debugw("activateImageUpdate-request", log.Fields{"img": *img})
khenaidoobf6e7bb2018-08-14 22:27:29 -0400503 if isTestMode(ctx) {
504 resp := &common.OperationResp{Code: common.OperationResp_OPERATION_SUCCESS}
505 return resp, nil
506 }
khenaidoof5a5bfa2019-01-23 22:20:29 -0500507
508 return handler.processImageRequest(ctx, img, ACTIVATE_IMAGE)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400509}
510
511func (handler *APIHandler) RevertImageUpdate(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
khenaidoof5a5bfa2019-01-23 22:20:29 -0500512 log.Debugw("revertImageUpdate-request", log.Fields{"img": *img})
khenaidoobf6e7bb2018-08-14 22:27:29 -0400513 if isTestMode(ctx) {
514 resp := &common.OperationResp{Code: common.OperationResp_OPERATION_SUCCESS}
515 return resp, nil
516 }
khenaidoof5a5bfa2019-01-23 22:20:29 -0500517
518 return handler.processImageRequest(ctx, img, REVERT_IMAGE)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400519}
520
khenaidoof5a5bfa2019-01-23 22:20:29 -0500521func (handler *APIHandler) GetImageDownloadStatus(ctx context.Context, img *voltha.ImageDownload) (*voltha.ImageDownload, error) {
522 log.Debugw("getImageDownloadStatus-request", log.Fields{"img": *img})
523 if isTestMode(ctx) {
Stephane Barbariedf5479f2019-01-29 22:13:00 -0500524 resp := &voltha.ImageDownload{DownloadState: voltha.ImageDownload_DOWNLOAD_SUCCEEDED}
khenaidoof5a5bfa2019-01-23 22:20:29 -0500525 return resp, nil
526 }
527
Stephane Barbariedf5479f2019-01-29 22:13:00 -0500528 failedresponse := &voltha.ImageDownload{DownloadState: voltha.ImageDownload_DOWNLOAD_UNKNOWN}
khenaidoof5a5bfa2019-01-23 22:20:29 -0500529
khenaidoo9cdc1a62019-01-24 21:57:40 -0500530 if handler.competeForTransaction() {
531 if txn, err := handler.acquireTransaction(ctx); err != nil {
532 return failedresponse, err
533 } else {
534 defer txn.Close()
535 }
khenaidoof5a5bfa2019-01-23 22:20:29 -0500536 }
537
538 ch := make(chan interface{})
539 defer close(ch)
540 go handler.deviceMgr.getImageDownloadStatus(ctx, img, ch)
541
542 select {
543 case res := <-ch:
544 if res != nil {
545 if err, ok := res.(error); ok {
546 return failedresponse, err
547 }
548 if downloadResp, ok := res.(*voltha.ImageDownload); ok {
549 return downloadResp, nil
550 }
551 }
552 log.Warnw("download-image-status", log.Fields{"result": res})
553 return failedresponse, status.Errorf(codes.Internal, "%s", res)
554 case <-ctx.Done():
555 log.Debug("downloadImage-client-timeout")
556 return failedresponse, ctx.Err()
557 }
558}
559
560func (handler *APIHandler) GetImageDownload(ctx context.Context, img *voltha.ImageDownload) (*voltha.ImageDownload, error) {
561 log.Debugw("GetImageDownload-request", log.Fields{"img": *img})
562 if isTestMode(ctx) {
Stephane Barbariedf5479f2019-01-29 22:13:00 -0500563 resp := &voltha.ImageDownload{DownloadState: voltha.ImageDownload_DOWNLOAD_SUCCEEDED}
khenaidoof5a5bfa2019-01-23 22:20:29 -0500564 return resp, nil
565 }
566
567 if download, err := handler.deviceMgr.getImageDownload(ctx, img); err != nil {
Stephane Barbariedf5479f2019-01-29 22:13:00 -0500568 return &voltha.ImageDownload{DownloadState: voltha.ImageDownload_DOWNLOAD_UNKNOWN}, err
khenaidoof5a5bfa2019-01-23 22:20:29 -0500569 } else {
570 return download, nil
571 }
572}
573
574func (handler *APIHandler) ListImageDownloads(ctx context.Context, id *voltha.ID) (*voltha.ImageDownloads, error) {
575 log.Debugw("ListImageDownloads-request", log.Fields{"deviceId": id.Id})
576 if isTestMode(ctx) {
577 resp := &voltha.ImageDownloads{Items:[]*voltha.ImageDownload{}}
578 return resp, nil
579 }
580
581 if downloads, err := handler.deviceMgr.listImageDownloads(ctx, id.Id); err != nil {
582 failedResp := &voltha.ImageDownloads{
583 Items:[]*voltha.ImageDownload{
Stephane Barbariedf5479f2019-01-29 22:13:00 -0500584 &voltha.ImageDownload{DownloadState: voltha.ImageDownload_DOWNLOAD_UNKNOWN},
khenaidoof5a5bfa2019-01-23 22:20:29 -0500585 },
586 }
587 return failedResp, err
588 } else {
589 return downloads, nil
590 }
591}
592
593
khenaidoobf6e7bb2018-08-14 22:27:29 -0400594func (handler *APIHandler) UpdateDevicePmConfigs(ctx context.Context, configs *voltha.PmConfigs) (*empty.Empty, error) {
595 log.Debugw("UpdateDevicePmConfigs-request", log.Fields{"configs": *configs})
596 if isTestMode(ctx) {
597 out := new(empty.Empty)
598 return out, nil
599 }
600 return nil, errors.New("UnImplemented")
601}
602
603func (handler *APIHandler) CreateAlarmFilter(ctx context.Context, filter *voltha.AlarmFilter) (*voltha.AlarmFilter, error) {
604 log.Debugw("CreateAlarmFilter-request", log.Fields{"filter": *filter})
605 if isTestMode(ctx) {
606 f := &voltha.AlarmFilter{Id: filter.Id}
607 return f, nil
608 }
609 return nil, errors.New("UnImplemented")
610}
611
612func (handler *APIHandler) UpdateAlarmFilter(ctx context.Context, filter *voltha.AlarmFilter) (*voltha.AlarmFilter, error) {
613 log.Debugw("UpdateAlarmFilter-request", log.Fields{"filter": *filter})
614 if isTestMode(ctx) {
615 f := &voltha.AlarmFilter{Id: filter.Id}
616 return f, nil
617 }
618 return nil, errors.New("UnImplemented")
619}
620
621func (handler *APIHandler) DeleteAlarmFilter(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
622 log.Debugw("DeleteAlarmFilter-request", log.Fields{"id": *id})
623 if isTestMode(ctx) {
624 out := new(empty.Empty)
625 return out, nil
626 }
627 return nil, errors.New("UnImplemented")
628}
629
630func (handler *APIHandler) SelfTest(ctx context.Context, id *voltha.ID) (*voltha.SelfTestResponse, error) {
631 log.Debugw("SelfTest-request", log.Fields{"id": id})
632 if isTestMode(ctx) {
633 resp := &voltha.SelfTestResponse{Result: voltha.SelfTestResponse_SUCCESS}
634 return resp, nil
635 }
636 return nil, errors.New("UnImplemented")
637}
Stephane Barbarie6e1bd502018-11-05 22:44:45 -0500638
639func (handler *APIHandler) forwardPacketOut(packet *openflow_13.PacketOut) {
640 log.Debugw("forwardPacketOut-request", log.Fields{"packet": packet})
Richard Jankowski2755adf2019-01-17 17:16:48 -0500641 agent := handler.logicalDeviceMgr.getLogicalDeviceAgent(packet.Id)
642 agent.packetOut(packet.PacketOut)
Stephane Barbarie6e1bd502018-11-05 22:44:45 -0500643}
644func (handler *APIHandler) StreamPacketsOut(
645 packets voltha.VolthaService_StreamPacketsOutServer,
646) error {
647 log.Debugw("StreamPacketsOut-request", log.Fields{"packets": packets})
648 for {
649 packet, err := packets.Recv()
650
651 if err == io.EOF {
652 break
653 } else if err != nil {
654 log.Errorw("Failed to receive packet", log.Fields{"error": err})
655 }
656
657 handler.forwardPacketOut(packet)
658 }
659
660 log.Debugw("StreamPacketsOut-request-done", log.Fields{"packets": packets})
661 return nil
662}
663
664func (handler *APIHandler) sendPacketIn(deviceId string, packet *openflow_13.OfpPacketIn) {
665 packetIn := openflow_13.PacketIn{Id: deviceId, PacketIn: packet}
666 log.Debugw("sendPacketIn", log.Fields{"packetIn": packetIn})
Richard Jankowskidbab94a2018-12-06 16:20:25 -0500667 // Enqueue the packet
668 if err := handler.packetInQueue.Put(packetIn); err != nil {
669 log.Errorw("failed-to-enqueue-packet", log.Fields{"error": err})
670 }
Stephane Barbarie6e1bd502018-11-05 22:44:45 -0500671}
672
673func (handler *APIHandler) ReceivePacketsIn(
674 empty *empty.Empty,
675 packetsIn voltha.VolthaService_ReceivePacketsInServer,
676) error {
677 log.Debugw("ReceivePacketsIn-request", log.Fields{"packetsIn": packetsIn})
678
679 for {
Richard Jankowskidbab94a2018-12-06 16:20:25 -0500680 // Dequeue a packet
681 if packets, err := handler.packetInQueue.Get(1); err == nil {
682 log.Debugw("dequeued-packet", log.Fields{"packet": packets[0]})
683 if packet, ok := packets[0].(openflow_13.PacketIn); ok {
684 log.Debugw("sending-packet-in", log.Fields{"packet": packet})
685 if err := packetsIn.Send(&packet); err != nil {
686 log.Errorw("failed-to-send-packet", log.Fields{"error": err})
687 }
688 }
Stephane Barbarie6e1bd502018-11-05 22:44:45 -0500689 }
690 }
khenaidoof5a5bfa2019-01-23 22:20:29 -0500691 //TODO: FInd an elegant way to get out of the above loop when the Core is stopped
Stephane Barbarie6e1bd502018-11-05 22:44:45 -0500692}
693
694func (handler *APIHandler) sendChangeEvent(deviceId string, portStatus *openflow_13.OfpPortStatus) {
695 // TODO: validate the type of portStatus parameter
696 //if _, ok := portStatus.(*openflow_13.OfpPortStatus); ok {
697 //}
698 event := openflow_13.ChangeEvent{Id: deviceId, Event: &openflow_13.ChangeEvent_PortStatus{PortStatus: portStatus}}
699 log.Debugw("sendChangeEvent", log.Fields{"event": event})
700 // TODO: put the packet in the queue
701}
702
703func (handler *APIHandler) ReceiveChangeEvents(
704 empty *empty.Empty,
705 changeEvents voltha.VolthaService_ReceiveChangeEventsServer,
706) error {
707 log.Debugw("ReceiveChangeEvents-request", log.Fields{"changeEvents": changeEvents})
708 for {
709 // TODO: need to retrieve packet from queue
710 event := &openflow_13.ChangeEvent{}
711 time.Sleep(time.Duration(5) * time.Second)
712 err := changeEvents.Send(event)
713 if err != nil {
714 log.Errorw("Failed to send change event", log.Fields{"error": err})
715 }
716 }
khenaidoof5a5bfa2019-01-23 22:20:29 -0500717 // TODO: put the packet in the queue
718 }
Stephane Barbarie6e1bd502018-11-05 22:44:45 -0500719
720func (handler *APIHandler) Subscribe(
721 ctx context.Context,
722 ofAgent *voltha.OfAgentSubscriber,
723) (*voltha.OfAgentSubscriber, error) {
724 log.Debugw("Subscribe-request", log.Fields{"ofAgent": ofAgent})
725 return &voltha.OfAgentSubscriber{OfagentId: ofAgent.OfagentId, VolthaId: ofAgent.VolthaId}, nil
726}