blob: f72d61515e223b7efe4f0529d8a251b8d3633e73 [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
63}
64
khenaidoo21d51152019-02-01 13:48:37 -050065func NewAPIHandler(deviceMgr *DeviceManager, lDeviceMgr *LogicalDeviceManager, adapterMgr *AdapterManager, inCompetingMode bool, longRunningRequestTimeout int64, defaultRequestTimeout int64 ) *APIHandler {
Stephane Barbarie6e1bd502018-11-05 22:44:45 -050066 handler := &APIHandler{
67 deviceMgr: deviceMgr,
68 logicalDeviceMgr: lDeviceMgr,
khenaidoo21d51152019-02-01 13:48:37 -050069 adapterMgr:adapterMgr,
khenaidoo9cdc1a62019-01-24 21:57:40 -050070 coreInCompetingMode:inCompetingMode,
khenaidoob6080322019-01-29 21:47:38 -050071 longRunningRequestTimeout:longRunningRequestTimeout,
72 defaultRequestTimeout:defaultRequestTimeout,
Richard Jankowskidbab94a2018-12-06 16:20:25 -050073 // TODO: Figure out what the 'hint' parameter to queue.New does
khenaidood2b6df92018-12-13 16:37:20 -050074 packetInQueue: queue.New(10),
Stephane Barbarie6e1bd502018-11-05 22:44:45 -050075 }
khenaidoobf6e7bb2018-08-14 22:27:29 -040076 return handler
77}
khenaidoo4d4802d2018-10-04 21:59:49 -040078
79// isTestMode is a helper function to determine a function is invoked for testing only
khenaidoobf6e7bb2018-08-14 22:27:29 -040080func isTestMode(ctx context.Context) bool {
81 md, _ := metadata.FromIncomingContext(ctx)
82 _, exist := md[common.TestModeKeys_api_test.String()]
83 return exist
84}
85
Richard Jankowskid42826e2018-11-02 16:06:37 -040086// This function attempts to extract the serial number from the request metadata
87// and create a KV transaction for that serial number for the current core.
88func (handler *APIHandler) createKvTransaction(ctx context.Context) (*KVTransaction, error) {
89 var (
khenaidoo43c82122018-11-22 18:38:28 -050090 err error
91 ok bool
92 md metadata.MD
Richard Jankowskid42826e2018-11-02 16:06:37 -040093 serNum []string
94 )
95 if md, ok = metadata.FromIncomingContext(ctx); !ok {
96 err = errors.New("metadata-not-found")
97 } else if serNum, ok = md["voltha_serial_number"]; !ok {
98 err = errors.New("serial-number-not-found")
99 }
100 if !ok {
101 log.Error(err)
102 return nil, err
103 }
104 // Create KV transaction
105 txn := NewKVTransaction(serNum[0])
106 return txn, nil
107}
108
Richard Jankowski2755adf2019-01-17 17:16:48 -0500109// isOFControllerRequest is a helper function to determine if a request was initiated
110// from the OpenFlow controller (or its proxy, e.g. OFAgent)
111func isOFControllerRequest(ctx context.Context) bool {
khenaidoo9cdc1a62019-01-24 21:57:40 -0500112 if md, ok := metadata.FromIncomingContext(ctx); ok {
113 // Metadata in context
114 if _, ok = md[OF_CONTROLLER_TAG]; ok {
115 // OFAgent field in metadata
116 return true
117 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500118 }
khenaidoo9cdc1a62019-01-24 21:57:40 -0500119 return false
120}
121
122// competeForTransaction is a helper function to determine whether every request needs to compete with another
123// Core to execute the request
124func (handler *APIHandler) competeForTransaction() bool {
125 return handler.coreInCompetingMode
126}
127
khenaidoo297cd252019-02-07 22:10:23 -0500128func (handler *APIHandler) acquireTransaction(ctx context.Context, id interface{}, maxTimeout ...int64) (*KVTransaction, error) {
khenaidoob6080322019-01-29 21:47:38 -0500129 timeout := handler.defaultRequestTimeout
khenaidoo9cdc1a62019-01-24 21:57:40 -0500130 if len(maxTimeout) > 0 {
131 timeout = maxTimeout[0]
Richard Jankowski2755adf2019-01-17 17:16:48 -0500132 }
khenaidoob6080322019-01-29 21:47:38 -0500133 log.Debugw("transaction-timeout", log.Fields{"timeout": timeout})
khenaidoo9cdc1a62019-01-24 21:57:40 -0500134 txn, err := handler.createKvTransaction(ctx)
135 if txn == nil {
136 return nil, err
137 } else if txn.Acquired(timeout) {
138 return txn, nil
139 } else {
khenaidoo297cd252019-02-07 22:10:23 -0500140 if id != nil {
141 // The id can either be a device Id or a logical device id.
142 if dId, ok := id.(*deviceID); ok {
143 // Since this core has not processed this request, let's load the device, along with its extended
144 // family (parents and children) in memory. This will keep this core in-sync with its paired core as
145 // much as possible. The watch feature in the core model will ensure that the contents of those objects in
146 // memory are in sync.
147 time.Sleep(2 * time.Second)
148 go handler.deviceMgr.load(dId.id)
149 } else if ldId, ok := id.(*logicalDeviceID); ok {
150 // This will load the logical device along with its children and grandchildren
151 go handler.logicalDeviceMgr.load(ldId.id)
152 }
153 }
khenaidoo9cdc1a62019-01-24 21:57:40 -0500154 return nil, errors.New("failed-to-seize-request")
Richard Jankowski2755adf2019-01-17 17:16:48 -0500155 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500156}
157
khenaidoo4d4802d2018-10-04 21:59:49 -0400158// waitForNilResponseOnSuccess is a helper function to wait for a response on channel ch where an nil
159// response is expected in a successful scenario
160func waitForNilResponseOnSuccess(ctx context.Context, ch chan interface{}) (*empty.Empty, error) {
161 select {
162 case res := <-ch:
163 if res == nil {
164 return new(empty.Empty), nil
165 } else if err, ok := res.(error); ok {
166 return new(empty.Empty), err
167 } else {
168 log.Warnw("unexpected-return-type", log.Fields{"result": res})
169 err = status.Errorf(codes.Internal, "%s", res)
170 return new(empty.Empty), err
171 }
172 case <-ctx.Done():
173 log.Debug("client-timeout")
174 return nil, ctx.Err()
175 }
176}
177
khenaidoobf6e7bb2018-08-14 22:27:29 -0400178func (handler *APIHandler) UpdateLogLevel(ctx context.Context, logging *voltha.Logging) (*empty.Empty, error) {
khenaidoo6f2fbe32019-01-18 16:16:50 -0500179 log.Debugw("UpdateLogLevel-request", log.Fields{"package": logging.PackageName, "intval": int(logging.Level)})
khenaidoo92e62c52018-10-03 14:02:54 -0400180 out := new(empty.Empty)
khenaidoo6f2fbe32019-01-18 16:16:50 -0500181 if logging.PackageName == "" {
182 log.SetAllLogLevel(int(logging.Level))
183 } else {
184 log.SetPackageLogLevel(logging.PackageName, int(logging.Level))
185 }
khenaidoo92e62c52018-10-03 14:02:54 -0400186 return out, nil
khenaidoobf6e7bb2018-08-14 22:27:29 -0400187}
188
189func (handler *APIHandler) EnableLogicalDevicePort(ctx context.Context, id *voltha.LogicalPortId) (*empty.Empty, error) {
190 log.Debugw("EnableLogicalDevicePort-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() {
khenaidoo297cd252019-02-07 22:10:23 -0500197 if txn, err := handler.acquireTransaction(ctx, &logicalDeviceID{id:id.Id}); 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
khenaidoo4d4802d2018-10-04 21:59:49 -0400204 ch := make(chan interface{})
205 defer close(ch)
khenaidoo19d7b632018-10-30 10:49:50 -0400206 go handler.logicalDeviceMgr.enableLogicalPort(ctx, id, ch)
khenaidoo4d4802d2018-10-04 21:59:49 -0400207 return waitForNilResponseOnSuccess(ctx, ch)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400208}
209
210func (handler *APIHandler) DisableLogicalDevicePort(ctx context.Context, id *voltha.LogicalPortId) (*empty.Empty, error) {
211 log.Debugw("DisableLogicalDevicePort-request", log.Fields{"id": id, "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() {
khenaidoo297cd252019-02-07 22:10:23 -0500218 if txn, err := handler.acquireTransaction(ctx, &logicalDeviceID{id:id.Id}); err != nil {
Richard Jankowski2755adf2019-01-17 17:16:48 -0500219 return new(empty.Empty), err
Richard Jankowski2755adf2019-01-17 17:16:48 -0500220 } else {
khenaidoo9cdc1a62019-01-24 21:57:40 -0500221 defer txn.Close()
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.disableLogicalPort(ctx, id, ch)
228 return waitForNilResponseOnSuccess(ctx, ch)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400229}
230
231func (handler *APIHandler) UpdateLogicalDeviceFlowTable(ctx context.Context, flow *openflow_13.FlowTableUpdate) (*empty.Empty, error) {
232 log.Debugw("UpdateLogicalDeviceFlowTable-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
khenaidoo297cd252019-02-07 22:10:23 -0500240 if txn, err := handler.acquireTransaction(ctx, &logicalDeviceID{id:flow.Id}); err != nil {
khenaidoo9cdc1a62019-01-24 21:57:40 -0500241 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.updateFlowTable(ctx, flow.Id, flow.FlowMod, ch)
251 return waitForNilResponseOnSuccess(ctx, ch)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400252}
253
254func (handler *APIHandler) UpdateLogicalDeviceFlowGroupTable(ctx context.Context, flow *openflow_13.FlowGroupTableUpdate) (*empty.Empty, error) {
255 log.Debugw("UpdateLogicalDeviceFlowGroupTable-request", log.Fields{"flow": flow, "test": common.TestModeKeys_api_test.String()})
256 if isTestMode(ctx) {
257 out := new(empty.Empty)
258 return out, nil
259 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500260
khenaidoo9cdc1a62019-01-24 21:57:40 -0500261 if handler.competeForTransaction() {
262 if !isOFControllerRequest(ctx) { // No need to acquire the transaction as request is sent to one core only
khenaidoo297cd252019-02-07 22:10:23 -0500263 if txn, err := handler.acquireTransaction(ctx, &logicalDeviceID{id:flow.Id}); err != nil {
khenaidoo9cdc1a62019-01-24 21:57:40 -0500264 return new(empty.Empty), err
265 } else {
266 defer txn.Close()
267 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500268 }
269 }
khenaidoo9cdc1a62019-01-24 21:57:40 -0500270
khenaidoo19d7b632018-10-30 10:49:50 -0400271 ch := make(chan interface{})
272 defer close(ch)
273 go handler.logicalDeviceMgr.updateGroupTable(ctx, flow.Id, flow.GroupMod, ch)
274 return waitForNilResponseOnSuccess(ctx, ch)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400275}
276
khenaidoob9203542018-09-17 22:56:37 -0400277// GetDevice must be implemented in the read-only containers - should it also be implemented here?
278func (handler *APIHandler) GetDevice(ctx context.Context, id *voltha.ID) (*voltha.Device, error) {
279 log.Debugw("GetDevice-request", log.Fields{"id": id})
khenaidoo19d7b632018-10-30 10:49:50 -0400280 return handler.deviceMgr.GetDevice(id.Id)
khenaidoob9203542018-09-17 22:56:37 -0400281}
282
283// GetDevice must be implemented in the read-only containers - should it also be implemented here?
284func (handler *APIHandler) ListDevices(ctx context.Context, empty *empty.Empty) (*voltha.Devices, error) {
285 log.Debug("ListDevices")
286 return handler.deviceMgr.ListDevices()
287}
288
khenaidoo7ccedd52018-12-14 16:48:54 -0500289// ListDeviceIds returns the list of device ids managed by a voltha core
290func (handler *APIHandler) ListDeviceIds(ctx context.Context, empty *empty.Empty) (*voltha.IDs, error) {
291 log.Debug("ListDeviceIDs")
292 if isTestMode(ctx) {
293 out := &voltha.IDs{Items: make([]*voltha.ID, 0)}
294 return out, nil
295 }
296 return handler.deviceMgr.ListDeviceIds()
297}
298
299//ReconcileDevices is a request to a voltha core to managed a list of devices based on their IDs
300func (handler *APIHandler) ReconcileDevices(ctx context.Context, ids *voltha.IDs) (*empty.Empty, error) {
301 log.Debug("ReconcileDevices")
302 if isTestMode(ctx) {
303 out := new(empty.Empty)
304 return out, nil
305 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500306
khenaidoo9cdc1a62019-01-24 21:57:40 -0500307 // No need to grab a transaction as this request is core specific
308
khenaidoo7ccedd52018-12-14 16:48:54 -0500309 ch := make(chan interface{})
310 defer close(ch)
311 go handler.deviceMgr.ReconcileDevices(ctx, ids, ch)
312 return waitForNilResponseOnSuccess(ctx, ch)
313}
314
khenaidoob9203542018-09-17 22:56:37 -0400315// GetLogicalDevice must be implemented in the read-only containers - should it also be implemented here?
316func (handler *APIHandler) GetLogicalDevice(ctx context.Context, id *voltha.ID) (*voltha.LogicalDevice, error) {
317 log.Debugw("GetLogicalDevice-request", log.Fields{"id": id})
318 return handler.logicalDeviceMgr.getLogicalDevice(id.Id)
319}
320
321// ListLogicalDevices must be implemented in the read-only containers - should it also be implemented here?
322func (handler *APIHandler) ListLogicalDevices(ctx context.Context, empty *empty.Empty) (*voltha.LogicalDevices, error) {
323 log.Debug("ListLogicalDevices")
324 return handler.logicalDeviceMgr.listLogicalDevices()
325}
326
khenaidoo21d51152019-02-01 13:48:37 -0500327
328// ListAdapters returns the contents of all adapters known to the system
329func (handler *APIHandler) ListAdapters(ctx context.Context, empty *empty.Empty) (*voltha.Adapters, error) {
330 log.Debug("ListDevices")
331 return handler.adapterMgr.listAdapters(ctx)
332}
333
khenaidoo19d7b632018-10-30 10:49:50 -0400334// ListLogicalDevicePorts must be implemented in the read-only containers - should it also be implemented here?
335func (handler *APIHandler) ListLogicalDevicePorts(ctx context.Context, id *voltha.ID) (*voltha.LogicalPorts, error) {
336 log.Debugw("ListLogicalDevicePorts", log.Fields{"logicaldeviceid": id})
337 return handler.logicalDeviceMgr.ListLogicalDevicePorts(ctx, id.Id)
338}
339
khenaidoo4d4802d2018-10-04 21:59:49 -0400340// CreateDevice creates a new parent device in the data model
khenaidoobf6e7bb2018-08-14 22:27:29 -0400341func (handler *APIHandler) CreateDevice(ctx context.Context, device *voltha.Device) (*voltha.Device, error) {
khenaidoob9203542018-09-17 22:56:37 -0400342 log.Debugw("createdevice", log.Fields{"device": *device})
khenaidoobf6e7bb2018-08-14 22:27:29 -0400343 if isTestMode(ctx) {
344 return &voltha.Device{Id: device.Id}, nil
345 }
Richard Jankowskid42826e2018-11-02 16:06:37 -0400346
khenaidoo9cdc1a62019-01-24 21:57:40 -0500347 if handler.competeForTransaction() {
khenaidoo297cd252019-02-07 22:10:23 -0500348 if txn, err := handler.acquireTransaction(ctx, nil); err != nil {
Richard Jankowski2755adf2019-01-17 17:16:48 -0500349 return &voltha.Device{}, err
Richard Jankowski2755adf2019-01-17 17:16:48 -0500350 } else {
khenaidoo9cdc1a62019-01-24 21:57:40 -0500351 defer txn.Close()
Richard Jankowski2755adf2019-01-17 17:16:48 -0500352 }
353 }
khenaidoo9cdc1a62019-01-24 21:57:40 -0500354
khenaidoob9203542018-09-17 22:56:37 -0400355 ch := make(chan interface{})
356 defer close(ch)
357 go handler.deviceMgr.createDevice(ctx, device, ch)
358 select {
359 case res := <-ch:
khenaidoo92e62c52018-10-03 14:02:54 -0400360 if res != nil {
361 if err, ok := res.(error); ok {
362 return &voltha.Device{}, err
363 }
364 if d, ok := res.(*voltha.Device); ok {
365 return d, nil
366 }
khenaidoob9203542018-09-17 22:56:37 -0400367 }
khenaidoo92e62c52018-10-03 14:02:54 -0400368 log.Warnw("create-device-unexpected-return-type", log.Fields{"result": res})
369 err := status.Errorf(codes.Internal, "%s", res)
370 return &voltha.Device{}, err
khenaidoob9203542018-09-17 22:56:37 -0400371 case <-ctx.Done():
372 log.Debug("createdevice-client-timeout")
373 return nil, ctx.Err()
374 }
khenaidoobf6e7bb2018-08-14 22:27:29 -0400375}
376
khenaidoo4d4802d2018-10-04 21:59:49 -0400377// EnableDevice activates a device by invoking the adopt_device API on the appropriate adapter
khenaidoobf6e7bb2018-08-14 22:27:29 -0400378func (handler *APIHandler) EnableDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
khenaidoob9203542018-09-17 22:56:37 -0400379 log.Debugw("enabledevice", log.Fields{"id": id})
khenaidoobf6e7bb2018-08-14 22:27:29 -0400380 if isTestMode(ctx) {
khenaidoo4d4802d2018-10-04 21:59:49 -0400381 return new(empty.Empty), nil
khenaidoobf6e7bb2018-08-14 22:27:29 -0400382 }
Richard Jankowskid42826e2018-11-02 16:06:37 -0400383
khenaidoo9cdc1a62019-01-24 21:57:40 -0500384 if handler.competeForTransaction() {
khenaidoo297cd252019-02-07 22:10:23 -0500385 if txn, err := handler.acquireTransaction(ctx, &deviceID{id:id.Id}, handler.longRunningRequestTimeout); 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
khenaidoob9203542018-09-17 22:56:37 -0400392 ch := make(chan interface{})
393 defer close(ch)
394 go handler.deviceMgr.enableDevice(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// DisableDevice disables a device along with any child device it may have
khenaidoobf6e7bb2018-08-14 22:27:29 -0400399func (handler *APIHandler) DisableDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
400 log.Debugw("disabledevice-request", log.Fields{"id": id})
401 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() {
khenaidoo297cd252019-02-07 22:10:23 -0500406 if txn, err := handler.acquireTransaction(ctx, &deviceID{id:id.Id}); 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
khenaidoo92e62c52018-10-03 14:02:54 -0400413 ch := make(chan interface{})
414 defer close(ch)
415 go handler.deviceMgr.disableDevice(ctx, id, ch)
khenaidoo4d4802d2018-10-04 21:59:49 -0400416 return waitForNilResponseOnSuccess(ctx, ch)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400417}
418
khenaidoo4d4802d2018-10-04 21:59:49 -0400419//RebootDevice invoked the reboot API to the corresponding adapter
khenaidoobf6e7bb2018-08-14 22:27:29 -0400420func (handler *APIHandler) RebootDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
khenaidoo4d4802d2018-10-04 21:59:49 -0400421 log.Debugw("rebootDevice-request", log.Fields{"id": id})
khenaidoobf6e7bb2018-08-14 22:27:29 -0400422 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() {
khenaidoo297cd252019-02-07 22:10:23 -0500427 if txn, err := handler.acquireTransaction(ctx, &deviceID{id:id.Id}); 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.rebootDevice(ctx, id, ch)
437 return waitForNilResponseOnSuccess(ctx, ch)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400438}
439
khenaidoo4d4802d2018-10-04 21:59:49 -0400440// DeleteDevice removes a device from the data model
khenaidoobf6e7bb2018-08-14 22:27:29 -0400441func (handler *APIHandler) DeleteDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
442 log.Debugw("deletedevice-request", log.Fields{"id": id})
443 if isTestMode(ctx) {
khenaidoo4d4802d2018-10-04 21:59:49 -0400444 return new(empty.Empty), nil
khenaidoobf6e7bb2018-08-14 22:27:29 -0400445 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500446
khenaidoo9cdc1a62019-01-24 21:57:40 -0500447 if handler.competeForTransaction() {
khenaidoo297cd252019-02-07 22:10:23 -0500448 if txn, err := handler.acquireTransaction(ctx, nil); err != nil {
Richard Jankowski2755adf2019-01-17 17:16:48 -0500449 return new(empty.Empty), err
Richard Jankowski2755adf2019-01-17 17:16:48 -0500450 } else {
khenaidoo9cdc1a62019-01-24 21:57:40 -0500451 defer txn.Close()
Richard Jankowski2755adf2019-01-17 17:16:48 -0500452 }
453 }
khenaidoo9cdc1a62019-01-24 21:57:40 -0500454
khenaidoo4d4802d2018-10-04 21:59:49 -0400455 ch := make(chan interface{})
456 defer close(ch)
457 go handler.deviceMgr.deleteDevice(ctx, id, ch)
458 return waitForNilResponseOnSuccess(ctx, ch)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400459}
460
khenaidoof5a5bfa2019-01-23 22:20:29 -0500461// processImageRequest is a helper method to execute an image download request
462func (handler *APIHandler) processImageRequest(ctx context.Context, img *voltha.ImageDownload, requestType int) (*common.OperationResp, error) {
463 log.Debugw("processImageDownload", log.Fields{"img": *img, "requestType": requestType})
464 if isTestMode(ctx) {
465 resp := &common.OperationResp{Code: common.OperationResp_OPERATION_SUCCESS}
466 return resp, nil
467 }
468
khenaidoo9cdc1a62019-01-24 21:57:40 -0500469 if handler.competeForTransaction() {
khenaidoo297cd252019-02-07 22:10:23 -0500470 if txn, err := handler.acquireTransaction(ctx, &deviceID{id:img.Id}); err != nil {
khenaidoo9cdc1a62019-01-24 21:57:40 -0500471 return &common.OperationResp{}, err
472 } else {
473 defer txn.Close()
474 }
khenaidoof5a5bfa2019-01-23 22:20:29 -0500475 }
476
477 failedresponse := &common.OperationResp{Code:voltha.OperationResp_OPERATION_FAILURE}
478
479 ch := make(chan interface{})
480 defer close(ch)
481 switch requestType {
482 case IMAGE_DOWNLOAD:
483 go handler.deviceMgr.downloadImage(ctx, img, ch)
484 case CANCEL_IMAGE_DOWNLOAD:
485 go handler.deviceMgr.cancelImageDownload(ctx, img, ch)
486 case ACTIVATE_IMAGE:
487 go handler.deviceMgr.activateImage(ctx, img, ch)
488 case REVERT_IMAGE:
489 go handler.deviceMgr.revertImage(ctx, img, ch)
490 default:
491 log.Warn("invalid-request-type", log.Fields{"requestType": requestType})
492 return failedresponse, status.Errorf(codes.InvalidArgument, "%d", requestType)
493 }
494 select {
495 case res := <-ch:
496 if res != nil {
497 if err, ok := res.(error); ok {
498 return failedresponse, err
499 }
500 if opResp, ok := res.(*common.OperationResp); ok {
501 return opResp, nil
502 }
503 }
504 log.Warnw("download-image-unexpected-return-type", log.Fields{"result": res})
505 return failedresponse, status.Errorf(codes.Internal, "%s", res)
506 case <-ctx.Done():
507 log.Debug("downloadImage-client-timeout")
508 return nil, ctx.Err()
509 }
510}
511
khenaidoobf6e7bb2018-08-14 22:27:29 -0400512func (handler *APIHandler) DownloadImage(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
513 log.Debugw("DownloadImage-request", log.Fields{"img": *img})
514 if isTestMode(ctx) {
515 resp := &common.OperationResp{Code: common.OperationResp_OPERATION_SUCCESS}
516 return resp, nil
517 }
518
khenaidoof5a5bfa2019-01-23 22:20:29 -0500519 return handler.processImageRequest(ctx, img, IMAGE_DOWNLOAD)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400520}
521
522func (handler *APIHandler) CancelImageDownload(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
khenaidoof5a5bfa2019-01-23 22:20:29 -0500523 log.Debugw("cancelImageDownload-request", log.Fields{"img": *img})
khenaidoobf6e7bb2018-08-14 22:27:29 -0400524 if isTestMode(ctx) {
525 resp := &common.OperationResp{Code: common.OperationResp_OPERATION_SUCCESS}
526 return resp, nil
527 }
khenaidoof5a5bfa2019-01-23 22:20:29 -0500528 return handler.processImageRequest(ctx, img, CANCEL_IMAGE_DOWNLOAD)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400529}
530
531func (handler *APIHandler) ActivateImageUpdate(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
khenaidoof5a5bfa2019-01-23 22:20:29 -0500532 log.Debugw("activateImageUpdate-request", log.Fields{"img": *img})
khenaidoobf6e7bb2018-08-14 22:27:29 -0400533 if isTestMode(ctx) {
534 resp := &common.OperationResp{Code: common.OperationResp_OPERATION_SUCCESS}
535 return resp, nil
536 }
khenaidoof5a5bfa2019-01-23 22:20:29 -0500537
538 return handler.processImageRequest(ctx, img, ACTIVATE_IMAGE)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400539}
540
541func (handler *APIHandler) RevertImageUpdate(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
khenaidoof5a5bfa2019-01-23 22:20:29 -0500542 log.Debugw("revertImageUpdate-request", log.Fields{"img": *img})
khenaidoobf6e7bb2018-08-14 22:27:29 -0400543 if isTestMode(ctx) {
544 resp := &common.OperationResp{Code: common.OperationResp_OPERATION_SUCCESS}
545 return resp, nil
546 }
khenaidoof5a5bfa2019-01-23 22:20:29 -0500547
548 return handler.processImageRequest(ctx, img, REVERT_IMAGE)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400549}
550
khenaidoof5a5bfa2019-01-23 22:20:29 -0500551func (handler *APIHandler) GetImageDownloadStatus(ctx context.Context, img *voltha.ImageDownload) (*voltha.ImageDownload, error) {
552 log.Debugw("getImageDownloadStatus-request", log.Fields{"img": *img})
553 if isTestMode(ctx) {
Stephane Barbariedf5479f2019-01-29 22:13:00 -0500554 resp := &voltha.ImageDownload{DownloadState: voltha.ImageDownload_DOWNLOAD_SUCCEEDED}
khenaidoof5a5bfa2019-01-23 22:20:29 -0500555 return resp, nil
556 }
557
Stephane Barbariedf5479f2019-01-29 22:13:00 -0500558 failedresponse := &voltha.ImageDownload{DownloadState: voltha.ImageDownload_DOWNLOAD_UNKNOWN}
khenaidoof5a5bfa2019-01-23 22:20:29 -0500559
khenaidoo9cdc1a62019-01-24 21:57:40 -0500560 if handler.competeForTransaction() {
khenaidoo297cd252019-02-07 22:10:23 -0500561 if txn, err := handler.acquireTransaction(ctx, &deviceID{id:img.Id}); err != nil {
khenaidoo9cdc1a62019-01-24 21:57:40 -0500562 return failedresponse, err
563 } else {
564 defer txn.Close()
565 }
khenaidoof5a5bfa2019-01-23 22:20:29 -0500566 }
567
568 ch := make(chan interface{})
569 defer close(ch)
570 go handler.deviceMgr.getImageDownloadStatus(ctx, img, ch)
571
572 select {
573 case res := <-ch:
574 if res != nil {
575 if err, ok := res.(error); ok {
576 return failedresponse, err
577 }
578 if downloadResp, ok := res.(*voltha.ImageDownload); ok {
579 return downloadResp, nil
580 }
581 }
582 log.Warnw("download-image-status", log.Fields{"result": res})
583 return failedresponse, status.Errorf(codes.Internal, "%s", res)
584 case <-ctx.Done():
585 log.Debug("downloadImage-client-timeout")
586 return failedresponse, ctx.Err()
587 }
588}
589
590func (handler *APIHandler) GetImageDownload(ctx context.Context, img *voltha.ImageDownload) (*voltha.ImageDownload, error) {
591 log.Debugw("GetImageDownload-request", log.Fields{"img": *img})
592 if isTestMode(ctx) {
Stephane Barbariedf5479f2019-01-29 22:13:00 -0500593 resp := &voltha.ImageDownload{DownloadState: voltha.ImageDownload_DOWNLOAD_SUCCEEDED}
khenaidoof5a5bfa2019-01-23 22:20:29 -0500594 return resp, nil
595 }
596
597 if download, err := handler.deviceMgr.getImageDownload(ctx, img); err != nil {
Stephane Barbariedf5479f2019-01-29 22:13:00 -0500598 return &voltha.ImageDownload{DownloadState: voltha.ImageDownload_DOWNLOAD_UNKNOWN}, err
khenaidoof5a5bfa2019-01-23 22:20:29 -0500599 } else {
600 return download, nil
601 }
602}
603
604func (handler *APIHandler) ListImageDownloads(ctx context.Context, id *voltha.ID) (*voltha.ImageDownloads, error) {
605 log.Debugw("ListImageDownloads-request", log.Fields{"deviceId": id.Id})
606 if isTestMode(ctx) {
607 resp := &voltha.ImageDownloads{Items:[]*voltha.ImageDownload{}}
608 return resp, nil
609 }
610
611 if downloads, err := handler.deviceMgr.listImageDownloads(ctx, id.Id); err != nil {
612 failedResp := &voltha.ImageDownloads{
613 Items:[]*voltha.ImageDownload{
Stephane Barbariedf5479f2019-01-29 22:13:00 -0500614 &voltha.ImageDownload{DownloadState: voltha.ImageDownload_DOWNLOAD_UNKNOWN},
khenaidoof5a5bfa2019-01-23 22:20:29 -0500615 },
616 }
617 return failedResp, err
618 } else {
619 return downloads, nil
620 }
621}
622
623
khenaidoobf6e7bb2018-08-14 22:27:29 -0400624func (handler *APIHandler) UpdateDevicePmConfigs(ctx context.Context, configs *voltha.PmConfigs) (*empty.Empty, error) {
625 log.Debugw("UpdateDevicePmConfigs-request", log.Fields{"configs": *configs})
626 if isTestMode(ctx) {
627 out := new(empty.Empty)
628 return out, nil
629 }
630 return nil, errors.New("UnImplemented")
631}
632
633func (handler *APIHandler) CreateAlarmFilter(ctx context.Context, filter *voltha.AlarmFilter) (*voltha.AlarmFilter, error) {
634 log.Debugw("CreateAlarmFilter-request", log.Fields{"filter": *filter})
635 if isTestMode(ctx) {
636 f := &voltha.AlarmFilter{Id: filter.Id}
637 return f, nil
638 }
639 return nil, errors.New("UnImplemented")
640}
641
642func (handler *APIHandler) UpdateAlarmFilter(ctx context.Context, filter *voltha.AlarmFilter) (*voltha.AlarmFilter, error) {
643 log.Debugw("UpdateAlarmFilter-request", log.Fields{"filter": *filter})
644 if isTestMode(ctx) {
645 f := &voltha.AlarmFilter{Id: filter.Id}
646 return f, nil
647 }
648 return nil, errors.New("UnImplemented")
649}
650
651func (handler *APIHandler) DeleteAlarmFilter(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
652 log.Debugw("DeleteAlarmFilter-request", log.Fields{"id": *id})
653 if isTestMode(ctx) {
654 out := new(empty.Empty)
655 return out, nil
656 }
657 return nil, errors.New("UnImplemented")
658}
659
660func (handler *APIHandler) SelfTest(ctx context.Context, id *voltha.ID) (*voltha.SelfTestResponse, error) {
661 log.Debugw("SelfTest-request", log.Fields{"id": id})
662 if isTestMode(ctx) {
663 resp := &voltha.SelfTestResponse{Result: voltha.SelfTestResponse_SUCCESS}
664 return resp, nil
665 }
666 return nil, errors.New("UnImplemented")
667}
Stephane Barbarie6e1bd502018-11-05 22:44:45 -0500668
669func (handler *APIHandler) forwardPacketOut(packet *openflow_13.PacketOut) {
670 log.Debugw("forwardPacketOut-request", log.Fields{"packet": packet})
Richard Jankowski2755adf2019-01-17 17:16:48 -0500671 agent := handler.logicalDeviceMgr.getLogicalDeviceAgent(packet.Id)
672 agent.packetOut(packet.PacketOut)
Stephane Barbarie6e1bd502018-11-05 22:44:45 -0500673}
674func (handler *APIHandler) StreamPacketsOut(
675 packets voltha.VolthaService_StreamPacketsOutServer,
676) error {
677 log.Debugw("StreamPacketsOut-request", log.Fields{"packets": packets})
678 for {
679 packet, err := packets.Recv()
680
681 if err == io.EOF {
682 break
683 } else if err != nil {
684 log.Errorw("Failed to receive packet", log.Fields{"error": err})
685 }
686
687 handler.forwardPacketOut(packet)
688 }
689
690 log.Debugw("StreamPacketsOut-request-done", log.Fields{"packets": packets})
691 return nil
692}
693
khenaidoo297cd252019-02-07 22:10:23 -0500694func (handler *APIHandler) sendPacketIn(deviceId string, transationId string, packet *openflow_13.OfpPacketIn) {
695 // TODO: Augment the OF PacketIn to include the transactionId
Stephane Barbarie6e1bd502018-11-05 22:44:45 -0500696 packetIn := openflow_13.PacketIn{Id: deviceId, PacketIn: packet}
697 log.Debugw("sendPacketIn", log.Fields{"packetIn": packetIn})
Richard Jankowskidbab94a2018-12-06 16:20:25 -0500698 // Enqueue the packet
699 if err := handler.packetInQueue.Put(packetIn); err != nil {
700 log.Errorw("failed-to-enqueue-packet", log.Fields{"error": err})
701 }
Stephane Barbarie6e1bd502018-11-05 22:44:45 -0500702}
703
704func (handler *APIHandler) ReceivePacketsIn(
705 empty *empty.Empty,
706 packetsIn voltha.VolthaService_ReceivePacketsInServer,
707) error {
708 log.Debugw("ReceivePacketsIn-request", log.Fields{"packetsIn": packetsIn})
709
710 for {
Richard Jankowskidbab94a2018-12-06 16:20:25 -0500711 // Dequeue a packet
712 if packets, err := handler.packetInQueue.Get(1); err == nil {
713 log.Debugw("dequeued-packet", log.Fields{"packet": packets[0]})
714 if packet, ok := packets[0].(openflow_13.PacketIn); ok {
715 log.Debugw("sending-packet-in", log.Fields{"packet": packet})
716 if err := packetsIn.Send(&packet); err != nil {
717 log.Errorw("failed-to-send-packet", log.Fields{"error": err})
718 }
719 }
Stephane Barbarie6e1bd502018-11-05 22:44:45 -0500720 }
721 }
khenaidoof5a5bfa2019-01-23 22:20:29 -0500722 //TODO: FInd an elegant way to get out of the above loop when the Core is stopped
Stephane Barbarie6e1bd502018-11-05 22:44:45 -0500723}
724
725func (handler *APIHandler) sendChangeEvent(deviceId string, portStatus *openflow_13.OfpPortStatus) {
726 // TODO: validate the type of portStatus parameter
727 //if _, ok := portStatus.(*openflow_13.OfpPortStatus); ok {
728 //}
729 event := openflow_13.ChangeEvent{Id: deviceId, Event: &openflow_13.ChangeEvent_PortStatus{PortStatus: portStatus}}
730 log.Debugw("sendChangeEvent", log.Fields{"event": event})
731 // TODO: put the packet in the queue
732}
733
734func (handler *APIHandler) ReceiveChangeEvents(
735 empty *empty.Empty,
736 changeEvents voltha.VolthaService_ReceiveChangeEventsServer,
737) error {
738 log.Debugw("ReceiveChangeEvents-request", log.Fields{"changeEvents": changeEvents})
739 for {
740 // TODO: need to retrieve packet from queue
741 event := &openflow_13.ChangeEvent{}
742 time.Sleep(time.Duration(5) * time.Second)
743 err := changeEvents.Send(event)
744 if err != nil {
745 log.Errorw("Failed to send change event", log.Fields{"error": err})
746 }
747 }
khenaidoof5a5bfa2019-01-23 22:20:29 -0500748 // TODO: put the packet in the queue
749 }
Stephane Barbarie6e1bd502018-11-05 22:44:45 -0500750
751func (handler *APIHandler) Subscribe(
752 ctx context.Context,
753 ofAgent *voltha.OfAgentSubscriber,
754) (*voltha.OfAgentSubscriber, error) {
755 log.Debugw("Subscribe-request", log.Fields{"ofAgent": ofAgent})
756 return &voltha.OfAgentSubscriber{OfagentId: ofAgent.OfagentId, VolthaId: ofAgent.VolthaId}, nil
757}