blob: dd777c02c5dbc46521d0e2d8b5f65b36dd6e83f4 [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
khenaidoo43c82122018-11-22 18:38:28 -050038const MAX_RESPONSE_TIME = 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
khenaidoobf6e7bb2018-08-14 22:27:29 -040051 da.DefaultAPIHandler
52}
53
khenaidoo9a468962018-09-19 15:33:13 -040054func NewAPIHandler(deviceMgr *DeviceManager, lDeviceMgr *LogicalDeviceManager) *APIHandler {
Stephane Barbarie6e1bd502018-11-05 22:44:45 -050055 handler := &APIHandler{
56 deviceMgr: deviceMgr,
57 logicalDeviceMgr: lDeviceMgr,
Richard Jankowskidbab94a2018-12-06 16:20:25 -050058 // TODO: Figure out what the 'hint' parameter to queue.New does
khenaidood2b6df92018-12-13 16:37:20 -050059 packetInQueue: queue.New(10),
Stephane Barbarie6e1bd502018-11-05 22:44:45 -050060 }
khenaidoobf6e7bb2018-08-14 22:27:29 -040061 return handler
62}
khenaidoo4d4802d2018-10-04 21:59:49 -040063
64// isTestMode is a helper function to determine a function is invoked for testing only
khenaidoobf6e7bb2018-08-14 22:27:29 -040065func isTestMode(ctx context.Context) bool {
66 md, _ := metadata.FromIncomingContext(ctx)
67 _, exist := md[common.TestModeKeys_api_test.String()]
68 return exist
69}
70
Richard Jankowskid42826e2018-11-02 16:06:37 -040071// This function attempts to extract the serial number from the request metadata
72// and create a KV transaction for that serial number for the current core.
73func (handler *APIHandler) createKvTransaction(ctx context.Context) (*KVTransaction, error) {
74 var (
khenaidoo43c82122018-11-22 18:38:28 -050075 err error
76 ok bool
77 md metadata.MD
Richard Jankowskid42826e2018-11-02 16:06:37 -040078 serNum []string
79 )
80 if md, ok = metadata.FromIncomingContext(ctx); !ok {
81 err = errors.New("metadata-not-found")
82 } else if serNum, ok = md["voltha_serial_number"]; !ok {
83 err = errors.New("serial-number-not-found")
84 }
85 if !ok {
86 log.Error(err)
87 return nil, err
88 }
89 // Create KV transaction
90 txn := NewKVTransaction(serNum[0])
91 return txn, nil
92}
93
Richard Jankowski2755adf2019-01-17 17:16:48 -050094// isOFControllerRequest is a helper function to determine if a request was initiated
95// from the OpenFlow controller (or its proxy, e.g. OFAgent)
96func isOFControllerRequest(ctx context.Context) bool {
97 var (
98 ok bool
99 md metadata.MD
100 value []string
101 )
102 if md, ok = metadata.FromIncomingContext(ctx); !ok {
103 // No metadata
104 return false
105 }
106 if value, ok = md[OF_CONTROLLER_TAG]; !ok {
107 // No OFAgent field in metadata
108 return false
109 }
110 if value[0] == "" {
111 // OFAgent has not set a field value
112 return false
113 }
114 return true
115}
116
khenaidoo4d4802d2018-10-04 21:59:49 -0400117// waitForNilResponseOnSuccess is a helper function to wait for a response on channel ch where an nil
118// response is expected in a successful scenario
119func waitForNilResponseOnSuccess(ctx context.Context, ch chan interface{}) (*empty.Empty, error) {
120 select {
121 case res := <-ch:
122 if res == nil {
123 return new(empty.Empty), nil
124 } else if err, ok := res.(error); ok {
125 return new(empty.Empty), err
126 } else {
127 log.Warnw("unexpected-return-type", log.Fields{"result": res})
128 err = status.Errorf(codes.Internal, "%s", res)
129 return new(empty.Empty), err
130 }
131 case <-ctx.Done():
132 log.Debug("client-timeout")
133 return nil, ctx.Err()
134 }
135}
136
khenaidoobf6e7bb2018-08-14 22:27:29 -0400137func (handler *APIHandler) UpdateLogLevel(ctx context.Context, logging *voltha.Logging) (*empty.Empty, error) {
khenaidoo6f2fbe32019-01-18 16:16:50 -0500138 log.Debugw("UpdateLogLevel-request", log.Fields{"package": logging.PackageName, "intval": int(logging.Level)})
khenaidoo92e62c52018-10-03 14:02:54 -0400139 out := new(empty.Empty)
khenaidoo6f2fbe32019-01-18 16:16:50 -0500140 if logging.PackageName == "" {
141 log.SetAllLogLevel(int(logging.Level))
142 } else {
143 log.SetPackageLogLevel(logging.PackageName, int(logging.Level))
144 }
khenaidoo92e62c52018-10-03 14:02:54 -0400145 return out, nil
khenaidoobf6e7bb2018-08-14 22:27:29 -0400146}
147
148func (handler *APIHandler) EnableLogicalDevicePort(ctx context.Context, id *voltha.LogicalPortId) (*empty.Empty, error) {
149 log.Debugw("EnableLogicalDevicePort-request", log.Fields{"id": id, "test": common.TestModeKeys_api_test.String()})
150 if isTestMode(ctx) {
151 out := new(empty.Empty)
152 return out, nil
153 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500154
155 if isOFControllerRequest(ctx) {
156 txn, err := handler.createKvTransaction(ctx)
157 if txn == nil {
158 return new(empty.Empty), err
159 } else if txn.Acquired(MAX_RESPONSE_TIME) {
160 defer txn.Close() // Ensure active core signals "done" to standby
161 } else {
162 return new(empty.Empty), errors.New("failed-to-seize-request")
163 }
164 }
khenaidoo4d4802d2018-10-04 21:59:49 -0400165 ch := make(chan interface{})
166 defer close(ch)
khenaidoo19d7b632018-10-30 10:49:50 -0400167 go handler.logicalDeviceMgr.enableLogicalPort(ctx, id, ch)
khenaidoo4d4802d2018-10-04 21:59:49 -0400168 return waitForNilResponseOnSuccess(ctx, ch)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400169}
170
171func (handler *APIHandler) DisableLogicalDevicePort(ctx context.Context, id *voltha.LogicalPortId) (*empty.Empty, error) {
172 log.Debugw("DisableLogicalDevicePort-request", log.Fields{"id": id, "test": common.TestModeKeys_api_test.String()})
173 if isTestMode(ctx) {
174 out := new(empty.Empty)
175 return out, nil
176 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500177
178 if isOFControllerRequest(ctx) {
179 txn, err := handler.createKvTransaction(ctx)
180 if txn == nil {
181 return new(empty.Empty), err
182 } else if txn.Acquired(MAX_RESPONSE_TIME) {
183 defer txn.Close() // Ensure active core signals "done" to standby
184 } else {
185 return new(empty.Empty), errors.New("failed-to-seize-request")
186 }
187 }
khenaidoo19d7b632018-10-30 10:49:50 -0400188 ch := make(chan interface{})
189 defer close(ch)
190 go handler.logicalDeviceMgr.disableLogicalPort(ctx, id, ch)
191 return waitForNilResponseOnSuccess(ctx, ch)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400192}
193
194func (handler *APIHandler) UpdateLogicalDeviceFlowTable(ctx context.Context, flow *openflow_13.FlowTableUpdate) (*empty.Empty, error) {
195 log.Debugw("UpdateLogicalDeviceFlowTable-request", log.Fields{"flow": flow, "test": common.TestModeKeys_api_test.String()})
196 if isTestMode(ctx) {
197 out := new(empty.Empty)
198 return out, nil
199 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500200
201 if isOFControllerRequest(ctx) {
202 txn, err := handler.createKvTransaction(ctx)
203 if txn == nil {
204 return new(empty.Empty), err
205 } else if txn.Acquired(MAX_RESPONSE_TIME) {
206 defer txn.Close() // Ensure active core signals "done" to standby
207 } else {
208 return new(empty.Empty), errors.New("failed-to-seize-request")
209 }
210 }
khenaidoo19d7b632018-10-30 10:49:50 -0400211 ch := make(chan interface{})
212 defer close(ch)
213 go handler.logicalDeviceMgr.updateFlowTable(ctx, flow.Id, flow.FlowMod, ch)
214 return waitForNilResponseOnSuccess(ctx, ch)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400215}
216
217func (handler *APIHandler) UpdateLogicalDeviceFlowGroupTable(ctx context.Context, flow *openflow_13.FlowGroupTableUpdate) (*empty.Empty, error) {
218 log.Debugw("UpdateLogicalDeviceFlowGroupTable-request", log.Fields{"flow": flow, "test": common.TestModeKeys_api_test.String()})
219 if isTestMode(ctx) {
220 out := new(empty.Empty)
221 return out, nil
222 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500223
224 if isOFControllerRequest(ctx) {
225 txn, err := handler.createKvTransaction(ctx)
226 if txn == nil {
227 return new(empty.Empty), err
228 } else if txn.Acquired(MAX_RESPONSE_TIME) {
229 defer txn.Close() // Ensure active core signals "done" to standby
230 } else {
231 return new(empty.Empty), errors.New("failed-to-seize-request")
232 }
233 }
khenaidoo19d7b632018-10-30 10:49:50 -0400234 ch := make(chan interface{})
235 defer close(ch)
236 go handler.logicalDeviceMgr.updateGroupTable(ctx, flow.Id, flow.GroupMod, ch)
237 return waitForNilResponseOnSuccess(ctx, ch)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400238}
239
khenaidoob9203542018-09-17 22:56:37 -0400240// GetDevice must be implemented in the read-only containers - should it also be implemented here?
241func (handler *APIHandler) GetDevice(ctx context.Context, id *voltha.ID) (*voltha.Device, error) {
242 log.Debugw("GetDevice-request", log.Fields{"id": id})
khenaidoo19d7b632018-10-30 10:49:50 -0400243 return handler.deviceMgr.GetDevice(id.Id)
khenaidoob9203542018-09-17 22:56:37 -0400244}
245
246// GetDevice must be implemented in the read-only containers - should it also be implemented here?
247func (handler *APIHandler) ListDevices(ctx context.Context, empty *empty.Empty) (*voltha.Devices, error) {
248 log.Debug("ListDevices")
249 return handler.deviceMgr.ListDevices()
250}
251
khenaidoo7ccedd52018-12-14 16:48:54 -0500252// ListDeviceIds returns the list of device ids managed by a voltha core
253func (handler *APIHandler) ListDeviceIds(ctx context.Context, empty *empty.Empty) (*voltha.IDs, error) {
254 log.Debug("ListDeviceIDs")
255 if isTestMode(ctx) {
256 out := &voltha.IDs{Items: make([]*voltha.ID, 0)}
257 return out, nil
258 }
259 return handler.deviceMgr.ListDeviceIds()
260}
261
262//ReconcileDevices is a request to a voltha core to managed a list of devices based on their IDs
263func (handler *APIHandler) ReconcileDevices(ctx context.Context, ids *voltha.IDs) (*empty.Empty, error) {
264 log.Debug("ReconcileDevices")
265 if isTestMode(ctx) {
266 out := new(empty.Empty)
267 return out, nil
268 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500269
270 if isOFControllerRequest(ctx) {
271 txn, err := handler.createKvTransaction(ctx)
272 if txn == nil {
273 return new(empty.Empty), err
274 } else if txn.Acquired(MAX_RESPONSE_TIME) {
275 defer txn.Close() // Ensure active core signals "done" to standby
276 } else {
277 return new(empty.Empty), errors.New("failed-to-seize-request")
278 }
279 }
khenaidoo7ccedd52018-12-14 16:48:54 -0500280 ch := make(chan interface{})
281 defer close(ch)
282 go handler.deviceMgr.ReconcileDevices(ctx, ids, ch)
283 return waitForNilResponseOnSuccess(ctx, ch)
284}
285
khenaidoob9203542018-09-17 22:56:37 -0400286// GetLogicalDevice must be implemented in the read-only containers - should it also be implemented here?
287func (handler *APIHandler) GetLogicalDevice(ctx context.Context, id *voltha.ID) (*voltha.LogicalDevice, error) {
288 log.Debugw("GetLogicalDevice-request", log.Fields{"id": id})
289 return handler.logicalDeviceMgr.getLogicalDevice(id.Id)
290}
291
292// ListLogicalDevices must be implemented in the read-only containers - should it also be implemented here?
293func (handler *APIHandler) ListLogicalDevices(ctx context.Context, empty *empty.Empty) (*voltha.LogicalDevices, error) {
294 log.Debug("ListLogicalDevices")
295 return handler.logicalDeviceMgr.listLogicalDevices()
296}
297
khenaidoo19d7b632018-10-30 10:49:50 -0400298// ListLogicalDevicePorts must be implemented in the read-only containers - should it also be implemented here?
299func (handler *APIHandler) ListLogicalDevicePorts(ctx context.Context, id *voltha.ID) (*voltha.LogicalPorts, error) {
300 log.Debugw("ListLogicalDevicePorts", log.Fields{"logicaldeviceid": id})
301 return handler.logicalDeviceMgr.ListLogicalDevicePorts(ctx, id.Id)
302}
303
khenaidoo4d4802d2018-10-04 21:59:49 -0400304// CreateDevice creates a new parent device in the data model
khenaidoobf6e7bb2018-08-14 22:27:29 -0400305func (handler *APIHandler) CreateDevice(ctx context.Context, device *voltha.Device) (*voltha.Device, error) {
khenaidoob9203542018-09-17 22:56:37 -0400306 log.Debugw("createdevice", log.Fields{"device": *device})
khenaidoobf6e7bb2018-08-14 22:27:29 -0400307 if isTestMode(ctx) {
308 return &voltha.Device{Id: device.Id}, nil
309 }
Richard Jankowskid42826e2018-11-02 16:06:37 -0400310
Richard Jankowski2755adf2019-01-17 17:16:48 -0500311 if isOFControllerRequest(ctx) {
312 txn, err := handler.createKvTransaction(ctx)
313 if txn == nil {
314 return &voltha.Device{}, err
315 } else if txn.Acquired(MAX_RESPONSE_TIME) {
316 defer txn.Close() // Ensure active core signals "done" to standby
317 } else {
318 return &voltha.Device{}, errors.New("failed-to-seize-request")
319 }
320 }
khenaidoob9203542018-09-17 22:56:37 -0400321 ch := make(chan interface{})
322 defer close(ch)
323 go handler.deviceMgr.createDevice(ctx, device, ch)
324 select {
325 case res := <-ch:
khenaidoo92e62c52018-10-03 14:02:54 -0400326 if res != nil {
327 if err, ok := res.(error); ok {
328 return &voltha.Device{}, err
329 }
330 if d, ok := res.(*voltha.Device); ok {
331 return d, nil
332 }
khenaidoob9203542018-09-17 22:56:37 -0400333 }
khenaidoo92e62c52018-10-03 14:02:54 -0400334 log.Warnw("create-device-unexpected-return-type", log.Fields{"result": res})
335 err := status.Errorf(codes.Internal, "%s", res)
336 return &voltha.Device{}, err
khenaidoob9203542018-09-17 22:56:37 -0400337 case <-ctx.Done():
338 log.Debug("createdevice-client-timeout")
339 return nil, ctx.Err()
340 }
khenaidoobf6e7bb2018-08-14 22:27:29 -0400341}
342
khenaidoo4d4802d2018-10-04 21:59:49 -0400343// EnableDevice activates a device by invoking the adopt_device API on the appropriate adapter
khenaidoobf6e7bb2018-08-14 22:27:29 -0400344func (handler *APIHandler) EnableDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
khenaidoob9203542018-09-17 22:56:37 -0400345 log.Debugw("enabledevice", log.Fields{"id": id})
khenaidoobf6e7bb2018-08-14 22:27:29 -0400346 if isTestMode(ctx) {
khenaidoo4d4802d2018-10-04 21:59:49 -0400347 return new(empty.Empty), nil
khenaidoobf6e7bb2018-08-14 22:27:29 -0400348 }
Richard Jankowskid42826e2018-11-02 16:06:37 -0400349
Richard Jankowski2755adf2019-01-17 17:16:48 -0500350 if isOFControllerRequest(ctx) {
351 txn, err := handler.createKvTransaction(ctx)
352 if txn == nil {
353 return new(empty.Empty), err
354 } else if txn.Acquired(MAX_RESPONSE_TIME) {
355 defer txn.Close() // Ensure active core signals "done" to standby
356 } else {
357 return new(empty.Empty), errors.New("failed-to-seize-request")
358 }
359 }
khenaidoob9203542018-09-17 22:56:37 -0400360 ch := make(chan interface{})
361 defer close(ch)
362 go handler.deviceMgr.enableDevice(ctx, id, ch)
khenaidoo4d4802d2018-10-04 21:59:49 -0400363 return waitForNilResponseOnSuccess(ctx, ch)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400364}
365
khenaidoo4d4802d2018-10-04 21:59:49 -0400366// DisableDevice disables a device along with any child device it may have
khenaidoobf6e7bb2018-08-14 22:27:29 -0400367func (handler *APIHandler) DisableDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
368 log.Debugw("disabledevice-request", log.Fields{"id": id})
369 if isTestMode(ctx) {
khenaidoo4d4802d2018-10-04 21:59:49 -0400370 return new(empty.Empty), nil
khenaidoobf6e7bb2018-08-14 22:27:29 -0400371 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500372
373 if isOFControllerRequest(ctx) {
374 txn, err := handler.createKvTransaction(ctx)
375 if txn == nil {
376 return new(empty.Empty), err
377 } else if txn.Acquired(MAX_RESPONSE_TIME) {
378 defer txn.Close() // Ensure active core signals "done" to standby
379 } else {
380 return new(empty.Empty), errors.New("failed-to-seize-request")
381 }
382 }
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
396 if isOFControllerRequest(ctx) {
397 txn, err := handler.createKvTransaction(ctx)
398 if txn == nil {
399 return new(empty.Empty), err
400 } else if txn.Acquired(MAX_RESPONSE_TIME) {
401 defer txn.Close() // Ensure active core signals "done" to standby
402 } else {
403 return new(empty.Empty), errors.New("failed-to-seize-request")
404 }
405 }
khenaidoo4d4802d2018-10-04 21:59:49 -0400406 ch := make(chan interface{})
407 defer close(ch)
408 go handler.deviceMgr.rebootDevice(ctx, id, ch)
409 return waitForNilResponseOnSuccess(ctx, ch)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400410}
411
khenaidoo4d4802d2018-10-04 21:59:49 -0400412// DeleteDevice removes a device from the data model
khenaidoobf6e7bb2018-08-14 22:27:29 -0400413func (handler *APIHandler) DeleteDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
414 log.Debugw("deletedevice-request", log.Fields{"id": id})
415 if isTestMode(ctx) {
khenaidoo4d4802d2018-10-04 21:59:49 -0400416 return new(empty.Empty), nil
khenaidoobf6e7bb2018-08-14 22:27:29 -0400417 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500418
419 if isOFControllerRequest(ctx) {
420 txn, err := handler.createKvTransaction(ctx)
421 if txn == nil {
422 return new(empty.Empty), err
423 } else if txn.Acquired(MAX_RESPONSE_TIME) {
424 defer txn.Close() // Ensure active core signals "done" to standby
425 } else {
426 return new(empty.Empty), errors.New("failed-to-seize-request")
427 }
428 }
khenaidoo4d4802d2018-10-04 21:59:49 -0400429 ch := make(chan interface{})
430 defer close(ch)
431 go handler.deviceMgr.deleteDevice(ctx, id, ch)
432 return waitForNilResponseOnSuccess(ctx, ch)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400433}
434
khenaidoof5a5bfa2019-01-23 22:20:29 -0500435func (handler *APIHandler) acquireTransaction(ctx context.Context) (*KVTransaction, error) {
436 txn, err := handler.createKvTransaction(ctx)
437 if txn == nil {
438 return nil, err
439 } else if txn.Acquired(MAX_RESPONSE_TIME) {
440 return txn, nil
441 } else {
442 txn.Close()
443 return nil, errors.New("failed-to-seize-request")
444 }
445}
446
447// processImageRequest is a helper method to execute an image download request
448func (handler *APIHandler) processImageRequest(ctx context.Context, img *voltha.ImageDownload, requestType int) (*common.OperationResp, error) {
449 log.Debugw("processImageDownload", log.Fields{"img": *img, "requestType": requestType})
450 if isTestMode(ctx) {
451 resp := &common.OperationResp{Code: common.OperationResp_OPERATION_SUCCESS}
452 return resp, nil
453 }
454
455 if txn, err := handler.acquireTransaction(ctx); err != nil {
456 return &common.OperationResp{}, err
457 } else {
458 defer txn.Close()
459 }
460
461 failedresponse := &common.OperationResp{Code:voltha.OperationResp_OPERATION_FAILURE}
462
463 ch := make(chan interface{})
464 defer close(ch)
465 switch requestType {
466 case IMAGE_DOWNLOAD:
467 go handler.deviceMgr.downloadImage(ctx, img, ch)
468 case CANCEL_IMAGE_DOWNLOAD:
469 go handler.deviceMgr.cancelImageDownload(ctx, img, ch)
470 case ACTIVATE_IMAGE:
471 go handler.deviceMgr.activateImage(ctx, img, ch)
472 case REVERT_IMAGE:
473 go handler.deviceMgr.revertImage(ctx, img, ch)
474 default:
475 log.Warn("invalid-request-type", log.Fields{"requestType": requestType})
476 return failedresponse, status.Errorf(codes.InvalidArgument, "%d", requestType)
477 }
478 select {
479 case res := <-ch:
480 if res != nil {
481 if err, ok := res.(error); ok {
482 return failedresponse, err
483 }
484 if opResp, ok := res.(*common.OperationResp); ok {
485 return opResp, nil
486 }
487 }
488 log.Warnw("download-image-unexpected-return-type", log.Fields{"result": res})
489 return failedresponse, status.Errorf(codes.Internal, "%s", res)
490 case <-ctx.Done():
491 log.Debug("downloadImage-client-timeout")
492 return nil, ctx.Err()
493 }
494}
495
khenaidoobf6e7bb2018-08-14 22:27:29 -0400496func (handler *APIHandler) DownloadImage(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
497 log.Debugw("DownloadImage-request", log.Fields{"img": *img})
498 if isTestMode(ctx) {
499 resp := &common.OperationResp{Code: common.OperationResp_OPERATION_SUCCESS}
500 return resp, nil
501 }
502
khenaidoof5a5bfa2019-01-23 22:20:29 -0500503 return handler.processImageRequest(ctx, img, IMAGE_DOWNLOAD)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400504}
505
506func (handler *APIHandler) CancelImageDownload(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
khenaidoof5a5bfa2019-01-23 22:20:29 -0500507 log.Debugw("cancelImageDownload-request", log.Fields{"img": *img})
khenaidoobf6e7bb2018-08-14 22:27:29 -0400508 if isTestMode(ctx) {
509 resp := &common.OperationResp{Code: common.OperationResp_OPERATION_SUCCESS}
510 return resp, nil
511 }
khenaidoof5a5bfa2019-01-23 22:20:29 -0500512 return handler.processImageRequest(ctx, img, CANCEL_IMAGE_DOWNLOAD)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400513}
514
515func (handler *APIHandler) ActivateImageUpdate(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
khenaidoof5a5bfa2019-01-23 22:20:29 -0500516 log.Debugw("activateImageUpdate-request", log.Fields{"img": *img})
khenaidoobf6e7bb2018-08-14 22:27:29 -0400517 if isTestMode(ctx) {
518 resp := &common.OperationResp{Code: common.OperationResp_OPERATION_SUCCESS}
519 return resp, nil
520 }
khenaidoof5a5bfa2019-01-23 22:20:29 -0500521
522 return handler.processImageRequest(ctx, img, ACTIVATE_IMAGE)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400523}
524
525func (handler *APIHandler) RevertImageUpdate(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
khenaidoof5a5bfa2019-01-23 22:20:29 -0500526 log.Debugw("revertImageUpdate-request", log.Fields{"img": *img})
khenaidoobf6e7bb2018-08-14 22:27:29 -0400527 if isTestMode(ctx) {
528 resp := &common.OperationResp{Code: common.OperationResp_OPERATION_SUCCESS}
529 return resp, nil
530 }
khenaidoof5a5bfa2019-01-23 22:20:29 -0500531
532 return handler.processImageRequest(ctx, img, REVERT_IMAGE)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400533}
534
khenaidoof5a5bfa2019-01-23 22:20:29 -0500535func (handler *APIHandler) GetImageDownloadStatus(ctx context.Context, img *voltha.ImageDownload) (*voltha.ImageDownload, error) {
536 log.Debugw("getImageDownloadStatus-request", log.Fields{"img": *img})
537 if isTestMode(ctx) {
538 resp := &voltha.ImageDownload{State: voltha.ImageDownload_DOWNLOAD_SUCCEEDED}
539 return resp, nil
540 }
541
542 failedresponse := &voltha.ImageDownload{State: voltha.ImageDownload_DOWNLOAD_UNKNOWN}
543
544 if txn, err := handler.acquireTransaction(ctx); err != nil {
545 return failedresponse, err
546 } else {
547 defer txn.Close()
548 }
549
550 ch := make(chan interface{})
551 defer close(ch)
552 go handler.deviceMgr.getImageDownloadStatus(ctx, img, ch)
553
554 select {
555 case res := <-ch:
556 if res != nil {
557 if err, ok := res.(error); ok {
558 return failedresponse, err
559 }
560 if downloadResp, ok := res.(*voltha.ImageDownload); ok {
561 return downloadResp, nil
562 }
563 }
564 log.Warnw("download-image-status", log.Fields{"result": res})
565 return failedresponse, status.Errorf(codes.Internal, "%s", res)
566 case <-ctx.Done():
567 log.Debug("downloadImage-client-timeout")
568 return failedresponse, ctx.Err()
569 }
570}
571
572func (handler *APIHandler) GetImageDownload(ctx context.Context, img *voltha.ImageDownload) (*voltha.ImageDownload, error) {
573 log.Debugw("GetImageDownload-request", log.Fields{"img": *img})
574 if isTestMode(ctx) {
575 resp := &voltha.ImageDownload{State: voltha.ImageDownload_DOWNLOAD_SUCCEEDED}
576 return resp, nil
577 }
578
579 if download, err := handler.deviceMgr.getImageDownload(ctx, img); err != nil {
580 return &voltha.ImageDownload{State: voltha.ImageDownload_DOWNLOAD_UNKNOWN}, err
581 } else {
582 return download, nil
583 }
584}
585
586func (handler *APIHandler) ListImageDownloads(ctx context.Context, id *voltha.ID) (*voltha.ImageDownloads, error) {
587 log.Debugw("ListImageDownloads-request", log.Fields{"deviceId": id.Id})
588 if isTestMode(ctx) {
589 resp := &voltha.ImageDownloads{Items:[]*voltha.ImageDownload{}}
590 return resp, nil
591 }
592
593 if downloads, err := handler.deviceMgr.listImageDownloads(ctx, id.Id); err != nil {
594 failedResp := &voltha.ImageDownloads{
595 Items:[]*voltha.ImageDownload{
596 &voltha.ImageDownload{State: voltha.ImageDownload_DOWNLOAD_UNKNOWN},
597 },
598 }
599 return failedResp, err
600 } else {
601 return downloads, nil
602 }
603}
604
605
khenaidoobf6e7bb2018-08-14 22:27:29 -0400606func (handler *APIHandler) UpdateDevicePmConfigs(ctx context.Context, configs *voltha.PmConfigs) (*empty.Empty, error) {
607 log.Debugw("UpdateDevicePmConfigs-request", log.Fields{"configs": *configs})
608 if isTestMode(ctx) {
609 out := new(empty.Empty)
610 return out, nil
611 }
612 return nil, errors.New("UnImplemented")
613}
614
615func (handler *APIHandler) CreateAlarmFilter(ctx context.Context, filter *voltha.AlarmFilter) (*voltha.AlarmFilter, error) {
616 log.Debugw("CreateAlarmFilter-request", log.Fields{"filter": *filter})
617 if isTestMode(ctx) {
618 f := &voltha.AlarmFilter{Id: filter.Id}
619 return f, nil
620 }
621 return nil, errors.New("UnImplemented")
622}
623
624func (handler *APIHandler) UpdateAlarmFilter(ctx context.Context, filter *voltha.AlarmFilter) (*voltha.AlarmFilter, error) {
625 log.Debugw("UpdateAlarmFilter-request", log.Fields{"filter": *filter})
626 if isTestMode(ctx) {
627 f := &voltha.AlarmFilter{Id: filter.Id}
628 return f, nil
629 }
630 return nil, errors.New("UnImplemented")
631}
632
633func (handler *APIHandler) DeleteAlarmFilter(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
634 log.Debugw("DeleteAlarmFilter-request", log.Fields{"id": *id})
635 if isTestMode(ctx) {
636 out := new(empty.Empty)
637 return out, nil
638 }
639 return nil, errors.New("UnImplemented")
640}
641
642func (handler *APIHandler) SelfTest(ctx context.Context, id *voltha.ID) (*voltha.SelfTestResponse, error) {
643 log.Debugw("SelfTest-request", log.Fields{"id": id})
644 if isTestMode(ctx) {
645 resp := &voltha.SelfTestResponse{Result: voltha.SelfTestResponse_SUCCESS}
646 return resp, nil
647 }
648 return nil, errors.New("UnImplemented")
649}
Stephane Barbarie6e1bd502018-11-05 22:44:45 -0500650
651func (handler *APIHandler) forwardPacketOut(packet *openflow_13.PacketOut) {
652 log.Debugw("forwardPacketOut-request", log.Fields{"packet": packet})
Richard Jankowski2755adf2019-01-17 17:16:48 -0500653 agent := handler.logicalDeviceMgr.getLogicalDeviceAgent(packet.Id)
654 agent.packetOut(packet.PacketOut)
Stephane Barbarie6e1bd502018-11-05 22:44:45 -0500655}
656func (handler *APIHandler) StreamPacketsOut(
657 packets voltha.VolthaService_StreamPacketsOutServer,
658) error {
659 log.Debugw("StreamPacketsOut-request", log.Fields{"packets": packets})
660 for {
661 packet, err := packets.Recv()
662
663 if err == io.EOF {
664 break
665 } else if err != nil {
666 log.Errorw("Failed to receive packet", log.Fields{"error": err})
667 }
668
669 handler.forwardPacketOut(packet)
670 }
671
672 log.Debugw("StreamPacketsOut-request-done", log.Fields{"packets": packets})
673 return nil
674}
675
676func (handler *APIHandler) sendPacketIn(deviceId string, packet *openflow_13.OfpPacketIn) {
677 packetIn := openflow_13.PacketIn{Id: deviceId, PacketIn: packet}
678 log.Debugw("sendPacketIn", log.Fields{"packetIn": packetIn})
Richard Jankowskidbab94a2018-12-06 16:20:25 -0500679 // Enqueue the packet
680 if err := handler.packetInQueue.Put(packetIn); err != nil {
681 log.Errorw("failed-to-enqueue-packet", log.Fields{"error": err})
682 }
Stephane Barbarie6e1bd502018-11-05 22:44:45 -0500683}
684
685func (handler *APIHandler) ReceivePacketsIn(
686 empty *empty.Empty,
687 packetsIn voltha.VolthaService_ReceivePacketsInServer,
688) error {
689 log.Debugw("ReceivePacketsIn-request", log.Fields{"packetsIn": packetsIn})
690
691 for {
Richard Jankowskidbab94a2018-12-06 16:20:25 -0500692 // Dequeue a packet
693 if packets, err := handler.packetInQueue.Get(1); err == nil {
694 log.Debugw("dequeued-packet", log.Fields{"packet": packets[0]})
695 if packet, ok := packets[0].(openflow_13.PacketIn); ok {
696 log.Debugw("sending-packet-in", log.Fields{"packet": packet})
697 if err := packetsIn.Send(&packet); err != nil {
698 log.Errorw("failed-to-send-packet", log.Fields{"error": err})
699 }
700 }
Stephane Barbarie6e1bd502018-11-05 22:44:45 -0500701 }
702 }
khenaidoof5a5bfa2019-01-23 22:20:29 -0500703 //TODO: FInd an elegant way to get out of the above loop when the Core is stopped
Stephane Barbarie6e1bd502018-11-05 22:44:45 -0500704}
705
706func (handler *APIHandler) sendChangeEvent(deviceId string, portStatus *openflow_13.OfpPortStatus) {
707 // TODO: validate the type of portStatus parameter
708 //if _, ok := portStatus.(*openflow_13.OfpPortStatus); ok {
709 //}
710 event := openflow_13.ChangeEvent{Id: deviceId, Event: &openflow_13.ChangeEvent_PortStatus{PortStatus: portStatus}}
711 log.Debugw("sendChangeEvent", log.Fields{"event": event})
712 // TODO: put the packet in the queue
713}
714
715func (handler *APIHandler) ReceiveChangeEvents(
716 empty *empty.Empty,
717 changeEvents voltha.VolthaService_ReceiveChangeEventsServer,
718) error {
719 log.Debugw("ReceiveChangeEvents-request", log.Fields{"changeEvents": changeEvents})
720 for {
721 // TODO: need to retrieve packet from queue
722 event := &openflow_13.ChangeEvent{}
723 time.Sleep(time.Duration(5) * time.Second)
724 err := changeEvents.Send(event)
725 if err != nil {
726 log.Errorw("Failed to send change event", log.Fields{"error": err})
727 }
728 }
khenaidoof5a5bfa2019-01-23 22:20:29 -0500729 // TODO: put the packet in the queue
730 }
Stephane Barbarie6e1bd502018-11-05 22:44:45 -0500731
732func (handler *APIHandler) Subscribe(
733 ctx context.Context,
734 ofAgent *voltha.OfAgentSubscriber,
735) (*voltha.OfAgentSubscriber, error) {
736 log.Debugw("Subscribe-request", log.Fields{"ofAgent": ofAgent})
737 return &voltha.OfAgentSubscriber{OfagentId: ofAgent.OfagentId, VolthaId: ofAgent.VolthaId}, nil
738}