blob: 877fcb4bf2a4ac6639e6ffed4cf31fddacee0369 [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
khenaidoo21d51152019-02-01 13:48:37 -050050 adapterMgr *AdapterManager
khenaidood2b6df92018-12-13 16:37:20 -050051 packetInQueue *queue.Queue
khenaidoo9cdc1a62019-01-24 21:57:40 -050052 coreInCompetingMode bool
khenaidoob6080322019-01-29 21:47:38 -050053 longRunningRequestTimeout int64
54 defaultRequestTimeout int64
khenaidoobf6e7bb2018-08-14 22:27:29 -040055 da.DefaultAPIHandler
56}
57
khenaidoo21d51152019-02-01 13:48:37 -050058func NewAPIHandler(deviceMgr *DeviceManager, lDeviceMgr *LogicalDeviceManager, adapterMgr *AdapterManager, inCompetingMode bool, longRunningRequestTimeout int64, defaultRequestTimeout int64 ) *APIHandler {
Stephane Barbarie6e1bd502018-11-05 22:44:45 -050059 handler := &APIHandler{
60 deviceMgr: deviceMgr,
61 logicalDeviceMgr: lDeviceMgr,
khenaidoo21d51152019-02-01 13:48:37 -050062 adapterMgr:adapterMgr,
khenaidoo9cdc1a62019-01-24 21:57:40 -050063 coreInCompetingMode:inCompetingMode,
khenaidoob6080322019-01-29 21:47:38 -050064 longRunningRequestTimeout:longRunningRequestTimeout,
65 defaultRequestTimeout:defaultRequestTimeout,
Richard Jankowskidbab94a2018-12-06 16:20:25 -050066 // TODO: Figure out what the 'hint' parameter to queue.New does
khenaidood2b6df92018-12-13 16:37:20 -050067 packetInQueue: queue.New(10),
Stephane Barbarie6e1bd502018-11-05 22:44:45 -050068 }
khenaidoobf6e7bb2018-08-14 22:27:29 -040069 return handler
70}
khenaidoo4d4802d2018-10-04 21:59:49 -040071
72// isTestMode is a helper function to determine a function is invoked for testing only
khenaidoobf6e7bb2018-08-14 22:27:29 -040073func isTestMode(ctx context.Context) bool {
74 md, _ := metadata.FromIncomingContext(ctx)
75 _, exist := md[common.TestModeKeys_api_test.String()]
76 return exist
77}
78
Richard Jankowskid42826e2018-11-02 16:06:37 -040079// This function attempts to extract the serial number from the request metadata
80// and create a KV transaction for that serial number for the current core.
81func (handler *APIHandler) createKvTransaction(ctx context.Context) (*KVTransaction, error) {
82 var (
khenaidoo43c82122018-11-22 18:38:28 -050083 err error
84 ok bool
85 md metadata.MD
Richard Jankowskid42826e2018-11-02 16:06:37 -040086 serNum []string
87 )
88 if md, ok = metadata.FromIncomingContext(ctx); !ok {
89 err = errors.New("metadata-not-found")
90 } else if serNum, ok = md["voltha_serial_number"]; !ok {
91 err = errors.New("serial-number-not-found")
92 }
93 if !ok {
94 log.Error(err)
95 return nil, err
96 }
97 // Create KV transaction
98 txn := NewKVTransaction(serNum[0])
99 return txn, nil
100}
101
Richard Jankowski2755adf2019-01-17 17:16:48 -0500102// isOFControllerRequest is a helper function to determine if a request was initiated
103// from the OpenFlow controller (or its proxy, e.g. OFAgent)
104func isOFControllerRequest(ctx context.Context) bool {
khenaidoo9cdc1a62019-01-24 21:57:40 -0500105 if md, ok := metadata.FromIncomingContext(ctx); ok {
106 // Metadata in context
107 if _, ok = md[OF_CONTROLLER_TAG]; ok {
108 // OFAgent field in metadata
109 return true
110 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500111 }
khenaidoo9cdc1a62019-01-24 21:57:40 -0500112 return false
113}
114
115// competeForTransaction is a helper function to determine whether every request needs to compete with another
116// Core to execute the request
117func (handler *APIHandler) competeForTransaction() bool {
118 return handler.coreInCompetingMode
119}
120
121func (handler *APIHandler) acquireTransaction(ctx context.Context, maxTimeout ...int64) (*KVTransaction, error) {
khenaidoob6080322019-01-29 21:47:38 -0500122 timeout := handler.defaultRequestTimeout
khenaidoo9cdc1a62019-01-24 21:57:40 -0500123 if len(maxTimeout) > 0 {
124 timeout = maxTimeout[0]
Richard Jankowski2755adf2019-01-17 17:16:48 -0500125 }
khenaidoob6080322019-01-29 21:47:38 -0500126 log.Debugw("transaction-timeout", log.Fields{"timeout": timeout})
khenaidoo9cdc1a62019-01-24 21:57:40 -0500127 txn, err := handler.createKvTransaction(ctx)
128 if txn == nil {
129 return nil, err
130 } else if txn.Acquired(timeout) {
131 return txn, nil
132 } else {
133 return nil, errors.New("failed-to-seize-request")
Richard Jankowski2755adf2019-01-17 17:16:48 -0500134 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500135}
136
khenaidoo4d4802d2018-10-04 21:59:49 -0400137// waitForNilResponseOnSuccess is a helper function to wait for a response on channel ch where an nil
138// response is expected in a successful scenario
139func waitForNilResponseOnSuccess(ctx context.Context, ch chan interface{}) (*empty.Empty, error) {
140 select {
141 case res := <-ch:
142 if res == nil {
143 return new(empty.Empty), nil
144 } else if err, ok := res.(error); ok {
145 return new(empty.Empty), err
146 } else {
147 log.Warnw("unexpected-return-type", log.Fields{"result": res})
148 err = status.Errorf(codes.Internal, "%s", res)
149 return new(empty.Empty), err
150 }
151 case <-ctx.Done():
152 log.Debug("client-timeout")
153 return nil, ctx.Err()
154 }
155}
156
khenaidoobf6e7bb2018-08-14 22:27:29 -0400157func (handler *APIHandler) UpdateLogLevel(ctx context.Context, logging *voltha.Logging) (*empty.Empty, error) {
khenaidoo6f2fbe32019-01-18 16:16:50 -0500158 log.Debugw("UpdateLogLevel-request", log.Fields{"package": logging.PackageName, "intval": int(logging.Level)})
khenaidoo92e62c52018-10-03 14:02:54 -0400159 out := new(empty.Empty)
khenaidoo6f2fbe32019-01-18 16:16:50 -0500160 if logging.PackageName == "" {
161 log.SetAllLogLevel(int(logging.Level))
162 } else {
163 log.SetPackageLogLevel(logging.PackageName, int(logging.Level))
164 }
khenaidoo92e62c52018-10-03 14:02:54 -0400165 return out, nil
khenaidoobf6e7bb2018-08-14 22:27:29 -0400166}
167
168func (handler *APIHandler) EnableLogicalDevicePort(ctx context.Context, id *voltha.LogicalPortId) (*empty.Empty, error) {
169 log.Debugw("EnableLogicalDevicePort-request", log.Fields{"id": id, "test": common.TestModeKeys_api_test.String()})
170 if isTestMode(ctx) {
171 out := new(empty.Empty)
172 return out, nil
173 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500174
khenaidoo9cdc1a62019-01-24 21:57:40 -0500175 if handler.competeForTransaction() {
176 if txn, err := handler.acquireTransaction(ctx); err != nil {
Richard Jankowski2755adf2019-01-17 17:16:48 -0500177 return new(empty.Empty), err
Richard Jankowski2755adf2019-01-17 17:16:48 -0500178 } else {
khenaidoo9cdc1a62019-01-24 21:57:40 -0500179 defer txn.Close()
Richard Jankowski2755adf2019-01-17 17:16:48 -0500180 }
181 }
khenaidoo9cdc1a62019-01-24 21:57:40 -0500182
khenaidoo4d4802d2018-10-04 21:59:49 -0400183 ch := make(chan interface{})
184 defer close(ch)
khenaidoo19d7b632018-10-30 10:49:50 -0400185 go handler.logicalDeviceMgr.enableLogicalPort(ctx, id, ch)
khenaidoo4d4802d2018-10-04 21:59:49 -0400186 return waitForNilResponseOnSuccess(ctx, ch)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400187}
188
189func (handler *APIHandler) DisableLogicalDevicePort(ctx context.Context, id *voltha.LogicalPortId) (*empty.Empty, error) {
190 log.Debugw("DisableLogicalDevicePort-request", log.Fields{"id": id, "test": common.TestModeKeys_api_test.String()})
191 if isTestMode(ctx) {
192 out := new(empty.Empty)
193 return out, nil
194 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500195
khenaidoo9cdc1a62019-01-24 21:57:40 -0500196 if handler.competeForTransaction() {
197 if txn, err := handler.acquireTransaction(ctx); err != nil {
Richard Jankowski2755adf2019-01-17 17:16:48 -0500198 return new(empty.Empty), err
Richard Jankowski2755adf2019-01-17 17:16:48 -0500199 } else {
khenaidoo9cdc1a62019-01-24 21:57:40 -0500200 defer txn.Close()
Richard Jankowski2755adf2019-01-17 17:16:48 -0500201 }
202 }
khenaidoo9cdc1a62019-01-24 21:57:40 -0500203
khenaidoo19d7b632018-10-30 10:49:50 -0400204 ch := make(chan interface{})
205 defer close(ch)
206 go handler.logicalDeviceMgr.disableLogicalPort(ctx, id, ch)
207 return waitForNilResponseOnSuccess(ctx, ch)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400208}
209
210func (handler *APIHandler) UpdateLogicalDeviceFlowTable(ctx context.Context, flow *openflow_13.FlowTableUpdate) (*empty.Empty, error) {
211 log.Debugw("UpdateLogicalDeviceFlowTable-request", log.Fields{"flow": flow, "test": common.TestModeKeys_api_test.String()})
212 if isTestMode(ctx) {
213 out := new(empty.Empty)
214 return out, nil
215 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500216
khenaidoo9cdc1a62019-01-24 21:57:40 -0500217 if handler.competeForTransaction() {
218 if !isOFControllerRequest(ctx) { // No need to acquire the transaction as request is sent to one core only
219 if txn, err := handler.acquireTransaction(ctx); err != nil {
220 return new(empty.Empty), err
221 } else {
222 defer txn.Close()
223 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500224 }
225 }
khenaidoo9cdc1a62019-01-24 21:57:40 -0500226
khenaidoo19d7b632018-10-30 10:49:50 -0400227 ch := make(chan interface{})
228 defer close(ch)
229 go handler.logicalDeviceMgr.updateFlowTable(ctx, flow.Id, flow.FlowMod, ch)
230 return waitForNilResponseOnSuccess(ctx, ch)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400231}
232
233func (handler *APIHandler) UpdateLogicalDeviceFlowGroupTable(ctx context.Context, flow *openflow_13.FlowGroupTableUpdate) (*empty.Empty, error) {
234 log.Debugw("UpdateLogicalDeviceFlowGroupTable-request", log.Fields{"flow": flow, "test": common.TestModeKeys_api_test.String()})
235 if isTestMode(ctx) {
236 out := new(empty.Empty)
237 return out, nil
238 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500239
khenaidoo9cdc1a62019-01-24 21:57:40 -0500240 if handler.competeForTransaction() {
241 if !isOFControllerRequest(ctx) { // No need to acquire the transaction as request is sent to one core only
242 if txn, err := handler.acquireTransaction(ctx); err != nil {
243 return new(empty.Empty), err
244 } else {
245 defer txn.Close()
246 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500247 }
248 }
khenaidoo9cdc1a62019-01-24 21:57:40 -0500249
khenaidoo19d7b632018-10-30 10:49:50 -0400250 ch := make(chan interface{})
251 defer close(ch)
252 go handler.logicalDeviceMgr.updateGroupTable(ctx, flow.Id, flow.GroupMod, ch)
253 return waitForNilResponseOnSuccess(ctx, ch)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400254}
255
khenaidoob9203542018-09-17 22:56:37 -0400256// GetDevice must be implemented in the read-only containers - should it also be implemented here?
257func (handler *APIHandler) GetDevice(ctx context.Context, id *voltha.ID) (*voltha.Device, error) {
258 log.Debugw("GetDevice-request", log.Fields{"id": id})
khenaidoo19d7b632018-10-30 10:49:50 -0400259 return handler.deviceMgr.GetDevice(id.Id)
khenaidoob9203542018-09-17 22:56:37 -0400260}
261
262// GetDevice must be implemented in the read-only containers - should it also be implemented here?
263func (handler *APIHandler) ListDevices(ctx context.Context, empty *empty.Empty) (*voltha.Devices, error) {
264 log.Debug("ListDevices")
265 return handler.deviceMgr.ListDevices()
266}
267
khenaidoo7ccedd52018-12-14 16:48:54 -0500268// ListDeviceIds returns the list of device ids managed by a voltha core
269func (handler *APIHandler) ListDeviceIds(ctx context.Context, empty *empty.Empty) (*voltha.IDs, error) {
270 log.Debug("ListDeviceIDs")
271 if isTestMode(ctx) {
272 out := &voltha.IDs{Items: make([]*voltha.ID, 0)}
273 return out, nil
274 }
275 return handler.deviceMgr.ListDeviceIds()
276}
277
278//ReconcileDevices is a request to a voltha core to managed a list of devices based on their IDs
279func (handler *APIHandler) ReconcileDevices(ctx context.Context, ids *voltha.IDs) (*empty.Empty, error) {
280 log.Debug("ReconcileDevices")
281 if isTestMode(ctx) {
282 out := new(empty.Empty)
283 return out, nil
284 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500285
khenaidoo9cdc1a62019-01-24 21:57:40 -0500286 // No need to grab a transaction as this request is core specific
287
khenaidoo7ccedd52018-12-14 16:48:54 -0500288 ch := make(chan interface{})
289 defer close(ch)
290 go handler.deviceMgr.ReconcileDevices(ctx, ids, ch)
291 return waitForNilResponseOnSuccess(ctx, ch)
292}
293
khenaidoob9203542018-09-17 22:56:37 -0400294// GetLogicalDevice must be implemented in the read-only containers - should it also be implemented here?
295func (handler *APIHandler) GetLogicalDevice(ctx context.Context, id *voltha.ID) (*voltha.LogicalDevice, error) {
296 log.Debugw("GetLogicalDevice-request", log.Fields{"id": id})
297 return handler.logicalDeviceMgr.getLogicalDevice(id.Id)
298}
299
300// ListLogicalDevices must be implemented in the read-only containers - should it also be implemented here?
301func (handler *APIHandler) ListLogicalDevices(ctx context.Context, empty *empty.Empty) (*voltha.LogicalDevices, error) {
302 log.Debug("ListLogicalDevices")
303 return handler.logicalDeviceMgr.listLogicalDevices()
304}
305
khenaidoo21d51152019-02-01 13:48:37 -0500306
307// ListAdapters returns the contents of all adapters known to the system
308func (handler *APIHandler) ListAdapters(ctx context.Context, empty *empty.Empty) (*voltha.Adapters, error) {
309 log.Debug("ListDevices")
310 return handler.adapterMgr.listAdapters(ctx)
311}
312
khenaidoo19d7b632018-10-30 10:49:50 -0400313// ListLogicalDevicePorts must be implemented in the read-only containers - should it also be implemented here?
314func (handler *APIHandler) ListLogicalDevicePorts(ctx context.Context, id *voltha.ID) (*voltha.LogicalPorts, error) {
315 log.Debugw("ListLogicalDevicePorts", log.Fields{"logicaldeviceid": id})
316 return handler.logicalDeviceMgr.ListLogicalDevicePorts(ctx, id.Id)
317}
318
khenaidoo4d4802d2018-10-04 21:59:49 -0400319// CreateDevice creates a new parent device in the data model
khenaidoobf6e7bb2018-08-14 22:27:29 -0400320func (handler *APIHandler) CreateDevice(ctx context.Context, device *voltha.Device) (*voltha.Device, error) {
khenaidoob9203542018-09-17 22:56:37 -0400321 log.Debugw("createdevice", log.Fields{"device": *device})
khenaidoobf6e7bb2018-08-14 22:27:29 -0400322 if isTestMode(ctx) {
323 return &voltha.Device{Id: device.Id}, nil
324 }
Richard Jankowskid42826e2018-11-02 16:06:37 -0400325
khenaidoo9cdc1a62019-01-24 21:57:40 -0500326 if handler.competeForTransaction() {
327 if txn, err := handler.acquireTransaction(ctx); err != nil {
Richard Jankowski2755adf2019-01-17 17:16:48 -0500328 return &voltha.Device{}, err
Richard Jankowski2755adf2019-01-17 17:16:48 -0500329 } else {
khenaidoo9cdc1a62019-01-24 21:57:40 -0500330 defer txn.Close()
Richard Jankowski2755adf2019-01-17 17:16:48 -0500331 }
332 }
khenaidoo9cdc1a62019-01-24 21:57:40 -0500333
khenaidoob9203542018-09-17 22:56:37 -0400334 ch := make(chan interface{})
335 defer close(ch)
336 go handler.deviceMgr.createDevice(ctx, device, ch)
337 select {
338 case res := <-ch:
khenaidoo92e62c52018-10-03 14:02:54 -0400339 if res != nil {
340 if err, ok := res.(error); ok {
341 return &voltha.Device{}, err
342 }
343 if d, ok := res.(*voltha.Device); ok {
344 return d, nil
345 }
khenaidoob9203542018-09-17 22:56:37 -0400346 }
khenaidoo92e62c52018-10-03 14:02:54 -0400347 log.Warnw("create-device-unexpected-return-type", log.Fields{"result": res})
348 err := status.Errorf(codes.Internal, "%s", res)
349 return &voltha.Device{}, err
khenaidoob9203542018-09-17 22:56:37 -0400350 case <-ctx.Done():
351 log.Debug("createdevice-client-timeout")
352 return nil, ctx.Err()
353 }
khenaidoobf6e7bb2018-08-14 22:27:29 -0400354}
355
khenaidoo4d4802d2018-10-04 21:59:49 -0400356// EnableDevice activates a device by invoking the adopt_device API on the appropriate adapter
khenaidoobf6e7bb2018-08-14 22:27:29 -0400357func (handler *APIHandler) EnableDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
khenaidoob9203542018-09-17 22:56:37 -0400358 log.Debugw("enabledevice", log.Fields{"id": id})
khenaidoobf6e7bb2018-08-14 22:27:29 -0400359 if isTestMode(ctx) {
khenaidoo4d4802d2018-10-04 21:59:49 -0400360 return new(empty.Empty), nil
khenaidoobf6e7bb2018-08-14 22:27:29 -0400361 }
Richard Jankowskid42826e2018-11-02 16:06:37 -0400362
khenaidoo9cdc1a62019-01-24 21:57:40 -0500363 if handler.competeForTransaction() {
khenaidoob6080322019-01-29 21:47:38 -0500364 if txn, err := handler.acquireTransaction(ctx, handler.longRunningRequestTimeout); err != nil {
Richard Jankowski2755adf2019-01-17 17:16:48 -0500365 return new(empty.Empty), err
Richard Jankowski2755adf2019-01-17 17:16:48 -0500366 } else {
khenaidoo9cdc1a62019-01-24 21:57:40 -0500367 defer txn.Close()
Richard Jankowski2755adf2019-01-17 17:16:48 -0500368 }
369 }
khenaidoo9cdc1a62019-01-24 21:57:40 -0500370
khenaidoob9203542018-09-17 22:56:37 -0400371 ch := make(chan interface{})
372 defer close(ch)
373 go handler.deviceMgr.enableDevice(ctx, id, ch)
khenaidoo4d4802d2018-10-04 21:59:49 -0400374 return waitForNilResponseOnSuccess(ctx, ch)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400375}
376
khenaidoo4d4802d2018-10-04 21:59:49 -0400377// DisableDevice disables a device along with any child device it may have
khenaidoobf6e7bb2018-08-14 22:27:29 -0400378func (handler *APIHandler) DisableDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
379 log.Debugw("disabledevice-request", log.Fields{"id": id})
380 if isTestMode(ctx) {
khenaidoo4d4802d2018-10-04 21:59:49 -0400381 return new(empty.Empty), nil
khenaidoobf6e7bb2018-08-14 22:27:29 -0400382 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500383
khenaidoo9cdc1a62019-01-24 21:57:40 -0500384 if handler.competeForTransaction() {
385 if txn, err := handler.acquireTransaction(ctx); err != nil {
Richard Jankowski2755adf2019-01-17 17:16:48 -0500386 return new(empty.Empty), err
Richard Jankowski2755adf2019-01-17 17:16:48 -0500387 } else {
khenaidoo9cdc1a62019-01-24 21:57:40 -0500388 defer txn.Close()
Richard Jankowski2755adf2019-01-17 17:16:48 -0500389 }
390 }
khenaidoo9cdc1a62019-01-24 21:57:40 -0500391
khenaidoo92e62c52018-10-03 14:02:54 -0400392 ch := make(chan interface{})
393 defer close(ch)
394 go handler.deviceMgr.disableDevice(ctx, id, ch)
khenaidoo4d4802d2018-10-04 21:59:49 -0400395 return waitForNilResponseOnSuccess(ctx, ch)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400396}
397
khenaidoo4d4802d2018-10-04 21:59:49 -0400398//RebootDevice invoked the reboot API to the corresponding adapter
khenaidoobf6e7bb2018-08-14 22:27:29 -0400399func (handler *APIHandler) RebootDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
khenaidoo4d4802d2018-10-04 21:59:49 -0400400 log.Debugw("rebootDevice-request", log.Fields{"id": id})
khenaidoobf6e7bb2018-08-14 22:27:29 -0400401 if isTestMode(ctx) {
khenaidoo4d4802d2018-10-04 21:59:49 -0400402 return new(empty.Empty), nil
khenaidoobf6e7bb2018-08-14 22:27:29 -0400403 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500404
khenaidoo9cdc1a62019-01-24 21:57:40 -0500405 if handler.competeForTransaction() {
406 if txn, err := handler.acquireTransaction(ctx); err != nil {
Richard Jankowski2755adf2019-01-17 17:16:48 -0500407 return new(empty.Empty), err
Richard Jankowski2755adf2019-01-17 17:16:48 -0500408 } else {
khenaidoo9cdc1a62019-01-24 21:57:40 -0500409 defer txn.Close()
Richard Jankowski2755adf2019-01-17 17:16:48 -0500410 }
411 }
khenaidoo9cdc1a62019-01-24 21:57:40 -0500412
khenaidoo4d4802d2018-10-04 21:59:49 -0400413 ch := make(chan interface{})
414 defer close(ch)
415 go handler.deviceMgr.rebootDevice(ctx, id, ch)
416 return waitForNilResponseOnSuccess(ctx, ch)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400417}
418
khenaidoo4d4802d2018-10-04 21:59:49 -0400419// DeleteDevice removes a device from the data model
khenaidoobf6e7bb2018-08-14 22:27:29 -0400420func (handler *APIHandler) DeleteDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
421 log.Debugw("deletedevice-request", log.Fields{"id": id})
422 if isTestMode(ctx) {
khenaidoo4d4802d2018-10-04 21:59:49 -0400423 return new(empty.Empty), nil
khenaidoobf6e7bb2018-08-14 22:27:29 -0400424 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500425
khenaidoo9cdc1a62019-01-24 21:57:40 -0500426 if handler.competeForTransaction() {
427 if txn, err := handler.acquireTransaction(ctx); err != nil {
Richard Jankowski2755adf2019-01-17 17:16:48 -0500428 return new(empty.Empty), err
Richard Jankowski2755adf2019-01-17 17:16:48 -0500429 } else {
khenaidoo9cdc1a62019-01-24 21:57:40 -0500430 defer txn.Close()
Richard Jankowski2755adf2019-01-17 17:16:48 -0500431 }
432 }
khenaidoo9cdc1a62019-01-24 21:57:40 -0500433
khenaidoo4d4802d2018-10-04 21:59:49 -0400434 ch := make(chan interface{})
435 defer close(ch)
436 go handler.deviceMgr.deleteDevice(ctx, id, ch)
437 return waitForNilResponseOnSuccess(ctx, ch)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400438}
439
khenaidoof5a5bfa2019-01-23 22:20:29 -0500440// processImageRequest is a helper method to execute an image download request
441func (handler *APIHandler) processImageRequest(ctx context.Context, img *voltha.ImageDownload, requestType int) (*common.OperationResp, error) {
442 log.Debugw("processImageDownload", log.Fields{"img": *img, "requestType": requestType})
443 if isTestMode(ctx) {
444 resp := &common.OperationResp{Code: common.OperationResp_OPERATION_SUCCESS}
445 return resp, nil
446 }
447
khenaidoo9cdc1a62019-01-24 21:57:40 -0500448 if handler.competeForTransaction() {
449 if txn, err := handler.acquireTransaction(ctx); err != nil {
450 return &common.OperationResp{}, err
451 } else {
452 defer txn.Close()
453 }
khenaidoof5a5bfa2019-01-23 22:20:29 -0500454 }
455
456 failedresponse := &common.OperationResp{Code:voltha.OperationResp_OPERATION_FAILURE}
457
458 ch := make(chan interface{})
459 defer close(ch)
460 switch requestType {
461 case IMAGE_DOWNLOAD:
462 go handler.deviceMgr.downloadImage(ctx, img, ch)
463 case CANCEL_IMAGE_DOWNLOAD:
464 go handler.deviceMgr.cancelImageDownload(ctx, img, ch)
465 case ACTIVATE_IMAGE:
466 go handler.deviceMgr.activateImage(ctx, img, ch)
467 case REVERT_IMAGE:
468 go handler.deviceMgr.revertImage(ctx, img, ch)
469 default:
470 log.Warn("invalid-request-type", log.Fields{"requestType": requestType})
471 return failedresponse, status.Errorf(codes.InvalidArgument, "%d", requestType)
472 }
473 select {
474 case res := <-ch:
475 if res != nil {
476 if err, ok := res.(error); ok {
477 return failedresponse, err
478 }
479 if opResp, ok := res.(*common.OperationResp); ok {
480 return opResp, nil
481 }
482 }
483 log.Warnw("download-image-unexpected-return-type", log.Fields{"result": res})
484 return failedresponse, status.Errorf(codes.Internal, "%s", res)
485 case <-ctx.Done():
486 log.Debug("downloadImage-client-timeout")
487 return nil, ctx.Err()
488 }
489}
490
khenaidoobf6e7bb2018-08-14 22:27:29 -0400491func (handler *APIHandler) DownloadImage(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
492 log.Debugw("DownloadImage-request", log.Fields{"img": *img})
493 if isTestMode(ctx) {
494 resp := &common.OperationResp{Code: common.OperationResp_OPERATION_SUCCESS}
495 return resp, nil
496 }
497
khenaidoof5a5bfa2019-01-23 22:20:29 -0500498 return handler.processImageRequest(ctx, img, IMAGE_DOWNLOAD)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400499}
500
501func (handler *APIHandler) CancelImageDownload(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
khenaidoof5a5bfa2019-01-23 22:20:29 -0500502 log.Debugw("cancelImageDownload-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 return handler.processImageRequest(ctx, img, CANCEL_IMAGE_DOWNLOAD)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400508}
509
510func (handler *APIHandler) ActivateImageUpdate(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
khenaidoof5a5bfa2019-01-23 22:20:29 -0500511 log.Debugw("activateImageUpdate-request", log.Fields{"img": *img})
khenaidoobf6e7bb2018-08-14 22:27:29 -0400512 if isTestMode(ctx) {
513 resp := &common.OperationResp{Code: common.OperationResp_OPERATION_SUCCESS}
514 return resp, nil
515 }
khenaidoof5a5bfa2019-01-23 22:20:29 -0500516
517 return handler.processImageRequest(ctx, img, ACTIVATE_IMAGE)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400518}
519
520func (handler *APIHandler) RevertImageUpdate(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
khenaidoof5a5bfa2019-01-23 22:20:29 -0500521 log.Debugw("revertImageUpdate-request", log.Fields{"img": *img})
khenaidoobf6e7bb2018-08-14 22:27:29 -0400522 if isTestMode(ctx) {
523 resp := &common.OperationResp{Code: common.OperationResp_OPERATION_SUCCESS}
524 return resp, nil
525 }
khenaidoof5a5bfa2019-01-23 22:20:29 -0500526
527 return handler.processImageRequest(ctx, img, REVERT_IMAGE)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400528}
529
khenaidoof5a5bfa2019-01-23 22:20:29 -0500530func (handler *APIHandler) GetImageDownloadStatus(ctx context.Context, img *voltha.ImageDownload) (*voltha.ImageDownload, error) {
531 log.Debugw("getImageDownloadStatus-request", log.Fields{"img": *img})
532 if isTestMode(ctx) {
Stephane Barbariedf5479f2019-01-29 22:13:00 -0500533 resp := &voltha.ImageDownload{DownloadState: voltha.ImageDownload_DOWNLOAD_SUCCEEDED}
khenaidoof5a5bfa2019-01-23 22:20:29 -0500534 return resp, nil
535 }
536
Stephane Barbariedf5479f2019-01-29 22:13:00 -0500537 failedresponse := &voltha.ImageDownload{DownloadState: voltha.ImageDownload_DOWNLOAD_UNKNOWN}
khenaidoof5a5bfa2019-01-23 22:20:29 -0500538
khenaidoo9cdc1a62019-01-24 21:57:40 -0500539 if handler.competeForTransaction() {
540 if txn, err := handler.acquireTransaction(ctx); err != nil {
541 return failedresponse, err
542 } else {
543 defer txn.Close()
544 }
khenaidoof5a5bfa2019-01-23 22:20:29 -0500545 }
546
547 ch := make(chan interface{})
548 defer close(ch)
549 go handler.deviceMgr.getImageDownloadStatus(ctx, img, ch)
550
551 select {
552 case res := <-ch:
553 if res != nil {
554 if err, ok := res.(error); ok {
555 return failedresponse, err
556 }
557 if downloadResp, ok := res.(*voltha.ImageDownload); ok {
558 return downloadResp, nil
559 }
560 }
561 log.Warnw("download-image-status", log.Fields{"result": res})
562 return failedresponse, status.Errorf(codes.Internal, "%s", res)
563 case <-ctx.Done():
564 log.Debug("downloadImage-client-timeout")
565 return failedresponse, ctx.Err()
566 }
567}
568
569func (handler *APIHandler) GetImageDownload(ctx context.Context, img *voltha.ImageDownload) (*voltha.ImageDownload, error) {
570 log.Debugw("GetImageDownload-request", log.Fields{"img": *img})
571 if isTestMode(ctx) {
Stephane Barbariedf5479f2019-01-29 22:13:00 -0500572 resp := &voltha.ImageDownload{DownloadState: voltha.ImageDownload_DOWNLOAD_SUCCEEDED}
khenaidoof5a5bfa2019-01-23 22:20:29 -0500573 return resp, nil
574 }
575
576 if download, err := handler.deviceMgr.getImageDownload(ctx, img); err != nil {
Stephane Barbariedf5479f2019-01-29 22:13:00 -0500577 return &voltha.ImageDownload{DownloadState: voltha.ImageDownload_DOWNLOAD_UNKNOWN}, err
khenaidoof5a5bfa2019-01-23 22:20:29 -0500578 } else {
579 return download, nil
580 }
581}
582
583func (handler *APIHandler) ListImageDownloads(ctx context.Context, id *voltha.ID) (*voltha.ImageDownloads, error) {
584 log.Debugw("ListImageDownloads-request", log.Fields{"deviceId": id.Id})
585 if isTestMode(ctx) {
586 resp := &voltha.ImageDownloads{Items:[]*voltha.ImageDownload{}}
587 return resp, nil
588 }
589
590 if downloads, err := handler.deviceMgr.listImageDownloads(ctx, id.Id); err != nil {
591 failedResp := &voltha.ImageDownloads{
592 Items:[]*voltha.ImageDownload{
Stephane Barbariedf5479f2019-01-29 22:13:00 -0500593 &voltha.ImageDownload{DownloadState: voltha.ImageDownload_DOWNLOAD_UNKNOWN},
khenaidoof5a5bfa2019-01-23 22:20:29 -0500594 },
595 }
596 return failedResp, err
597 } else {
598 return downloads, nil
599 }
600}
601
602
khenaidoobf6e7bb2018-08-14 22:27:29 -0400603func (handler *APIHandler) UpdateDevicePmConfigs(ctx context.Context, configs *voltha.PmConfigs) (*empty.Empty, error) {
604 log.Debugw("UpdateDevicePmConfigs-request", log.Fields{"configs": *configs})
605 if isTestMode(ctx) {
606 out := new(empty.Empty)
607 return out, nil
608 }
609 return nil, errors.New("UnImplemented")
610}
611
612func (handler *APIHandler) CreateAlarmFilter(ctx context.Context, filter *voltha.AlarmFilter) (*voltha.AlarmFilter, error) {
613 log.Debugw("CreateAlarmFilter-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) UpdateAlarmFilter(ctx context.Context, filter *voltha.AlarmFilter) (*voltha.AlarmFilter, error) {
622 log.Debugw("UpdateAlarmFilter-request", log.Fields{"filter": *filter})
623 if isTestMode(ctx) {
624 f := &voltha.AlarmFilter{Id: filter.Id}
625 return f, nil
626 }
627 return nil, errors.New("UnImplemented")
628}
629
630func (handler *APIHandler) DeleteAlarmFilter(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
631 log.Debugw("DeleteAlarmFilter-request", log.Fields{"id": *id})
632 if isTestMode(ctx) {
633 out := new(empty.Empty)
634 return out, nil
635 }
636 return nil, errors.New("UnImplemented")
637}
638
639func (handler *APIHandler) SelfTest(ctx context.Context, id *voltha.ID) (*voltha.SelfTestResponse, error) {
640 log.Debugw("SelfTest-request", log.Fields{"id": id})
641 if isTestMode(ctx) {
642 resp := &voltha.SelfTestResponse{Result: voltha.SelfTestResponse_SUCCESS}
643 return resp, nil
644 }
645 return nil, errors.New("UnImplemented")
646}
Stephane Barbarie6e1bd502018-11-05 22:44:45 -0500647
648func (handler *APIHandler) forwardPacketOut(packet *openflow_13.PacketOut) {
649 log.Debugw("forwardPacketOut-request", log.Fields{"packet": packet})
Richard Jankowski2755adf2019-01-17 17:16:48 -0500650 agent := handler.logicalDeviceMgr.getLogicalDeviceAgent(packet.Id)
651 agent.packetOut(packet.PacketOut)
Stephane Barbarie6e1bd502018-11-05 22:44:45 -0500652}
653func (handler *APIHandler) StreamPacketsOut(
654 packets voltha.VolthaService_StreamPacketsOutServer,
655) error {
656 log.Debugw("StreamPacketsOut-request", log.Fields{"packets": packets})
657 for {
658 packet, err := packets.Recv()
659
660 if err == io.EOF {
661 break
662 } else if err != nil {
663 log.Errorw("Failed to receive packet", log.Fields{"error": err})
664 }
665
666 handler.forwardPacketOut(packet)
667 }
668
669 log.Debugw("StreamPacketsOut-request-done", log.Fields{"packets": packets})
670 return nil
671}
672
673func (handler *APIHandler) sendPacketIn(deviceId string, packet *openflow_13.OfpPacketIn) {
674 packetIn := openflow_13.PacketIn{Id: deviceId, PacketIn: packet}
675 log.Debugw("sendPacketIn", log.Fields{"packetIn": packetIn})
Richard Jankowskidbab94a2018-12-06 16:20:25 -0500676 // Enqueue the packet
677 if err := handler.packetInQueue.Put(packetIn); err != nil {
678 log.Errorw("failed-to-enqueue-packet", log.Fields{"error": err})
679 }
Stephane Barbarie6e1bd502018-11-05 22:44:45 -0500680}
681
682func (handler *APIHandler) ReceivePacketsIn(
683 empty *empty.Empty,
684 packetsIn voltha.VolthaService_ReceivePacketsInServer,
685) error {
686 log.Debugw("ReceivePacketsIn-request", log.Fields{"packetsIn": packetsIn})
687
688 for {
Richard Jankowskidbab94a2018-12-06 16:20:25 -0500689 // Dequeue a packet
690 if packets, err := handler.packetInQueue.Get(1); err == nil {
691 log.Debugw("dequeued-packet", log.Fields{"packet": packets[0]})
692 if packet, ok := packets[0].(openflow_13.PacketIn); ok {
693 log.Debugw("sending-packet-in", log.Fields{"packet": packet})
694 if err := packetsIn.Send(&packet); err != nil {
695 log.Errorw("failed-to-send-packet", log.Fields{"error": err})
696 }
697 }
Stephane Barbarie6e1bd502018-11-05 22:44:45 -0500698 }
699 }
khenaidoof5a5bfa2019-01-23 22:20:29 -0500700 //TODO: FInd an elegant way to get out of the above loop when the Core is stopped
Stephane Barbarie6e1bd502018-11-05 22:44:45 -0500701}
702
703func (handler *APIHandler) sendChangeEvent(deviceId string, portStatus *openflow_13.OfpPortStatus) {
704 // TODO: validate the type of portStatus parameter
705 //if _, ok := portStatus.(*openflow_13.OfpPortStatus); ok {
706 //}
707 event := openflow_13.ChangeEvent{Id: deviceId, Event: &openflow_13.ChangeEvent_PortStatus{PortStatus: portStatus}}
708 log.Debugw("sendChangeEvent", log.Fields{"event": event})
709 // TODO: put the packet in the queue
710}
711
712func (handler *APIHandler) ReceiveChangeEvents(
713 empty *empty.Empty,
714 changeEvents voltha.VolthaService_ReceiveChangeEventsServer,
715) error {
716 log.Debugw("ReceiveChangeEvents-request", log.Fields{"changeEvents": changeEvents})
717 for {
718 // TODO: need to retrieve packet from queue
719 event := &openflow_13.ChangeEvent{}
720 time.Sleep(time.Duration(5) * time.Second)
721 err := changeEvents.Send(event)
722 if err != nil {
723 log.Errorw("Failed to send change event", log.Fields{"error": err})
724 }
725 }
khenaidoof5a5bfa2019-01-23 22:20:29 -0500726 // TODO: put the packet in the queue
727 }
Stephane Barbarie6e1bd502018-11-05 22:44:45 -0500728
729func (handler *APIHandler) Subscribe(
730 ctx context.Context,
731 ofAgent *voltha.OfAgentSubscriber,
732) (*voltha.OfAgentSubscriber, error) {
733 log.Debugw("Subscribe-request", log.Fields{"ofAgent": ofAgent})
734 return &voltha.OfAgentSubscriber{OfagentId: ofAgent.OfagentId, VolthaId: ofAgent.VolthaId}, nil
735}