blob: d11c42000c974460a3340205bc1803759d02b316 [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
khenaidoobf6e7bb2018-08-14 22:27:29 -040040type APIHandler struct {
khenaidoob9203542018-09-17 22:56:37 -040041 deviceMgr *DeviceManager
42 logicalDeviceMgr *LogicalDeviceManager
khenaidood2b6df92018-12-13 16:37:20 -050043 packetInQueue *queue.Queue
khenaidoobf6e7bb2018-08-14 22:27:29 -040044 da.DefaultAPIHandler
45}
46
khenaidoo9a468962018-09-19 15:33:13 -040047func NewAPIHandler(deviceMgr *DeviceManager, lDeviceMgr *LogicalDeviceManager) *APIHandler {
Stephane Barbarie6e1bd502018-11-05 22:44:45 -050048 handler := &APIHandler{
49 deviceMgr: deviceMgr,
50 logicalDeviceMgr: lDeviceMgr,
Richard Jankowskidbab94a2018-12-06 16:20:25 -050051 // TODO: Figure out what the 'hint' parameter to queue.New does
khenaidood2b6df92018-12-13 16:37:20 -050052 packetInQueue: queue.New(10),
Stephane Barbarie6e1bd502018-11-05 22:44:45 -050053 }
khenaidoobf6e7bb2018-08-14 22:27:29 -040054 return handler
55}
khenaidoo4d4802d2018-10-04 21:59:49 -040056
57// isTestMode is a helper function to determine a function is invoked for testing only
khenaidoobf6e7bb2018-08-14 22:27:29 -040058func isTestMode(ctx context.Context) bool {
59 md, _ := metadata.FromIncomingContext(ctx)
60 _, exist := md[common.TestModeKeys_api_test.String()]
61 return exist
62}
63
Richard Jankowskid42826e2018-11-02 16:06:37 -040064// This function attempts to extract the serial number from the request metadata
65// and create a KV transaction for that serial number for the current core.
66func (handler *APIHandler) createKvTransaction(ctx context.Context) (*KVTransaction, error) {
67 var (
khenaidoo43c82122018-11-22 18:38:28 -050068 err error
69 ok bool
70 md metadata.MD
Richard Jankowskid42826e2018-11-02 16:06:37 -040071 serNum []string
72 )
73 if md, ok = metadata.FromIncomingContext(ctx); !ok {
74 err = errors.New("metadata-not-found")
75 } else if serNum, ok = md["voltha_serial_number"]; !ok {
76 err = errors.New("serial-number-not-found")
77 }
78 if !ok {
79 log.Error(err)
80 return nil, err
81 }
82 // Create KV transaction
83 txn := NewKVTransaction(serNum[0])
84 return txn, nil
85}
86
Richard Jankowski2755adf2019-01-17 17:16:48 -050087// isOFControllerRequest is a helper function to determine if a request was initiated
88// from the OpenFlow controller (or its proxy, e.g. OFAgent)
89func isOFControllerRequest(ctx context.Context) bool {
90 var (
91 ok bool
92 md metadata.MD
93 value []string
94 )
95 if md, ok = metadata.FromIncomingContext(ctx); !ok {
96 // No metadata
97 return false
98 }
99 if value, ok = md[OF_CONTROLLER_TAG]; !ok {
100 // No OFAgent field in metadata
101 return false
102 }
103 if value[0] == "" {
104 // OFAgent has not set a field value
105 return false
106 }
107 return true
108}
109
khenaidoo4d4802d2018-10-04 21:59:49 -0400110// waitForNilResponseOnSuccess is a helper function to wait for a response on channel ch where an nil
111// response is expected in a successful scenario
112func waitForNilResponseOnSuccess(ctx context.Context, ch chan interface{}) (*empty.Empty, error) {
113 select {
114 case res := <-ch:
115 if res == nil {
116 return new(empty.Empty), nil
117 } else if err, ok := res.(error); ok {
118 return new(empty.Empty), err
119 } else {
120 log.Warnw("unexpected-return-type", log.Fields{"result": res})
121 err = status.Errorf(codes.Internal, "%s", res)
122 return new(empty.Empty), err
123 }
124 case <-ctx.Done():
125 log.Debug("client-timeout")
126 return nil, ctx.Err()
127 }
128}
129
khenaidoobf6e7bb2018-08-14 22:27:29 -0400130func (handler *APIHandler) UpdateLogLevel(ctx context.Context, logging *voltha.Logging) (*empty.Empty, error) {
khenaidoo6f2fbe32019-01-18 16:16:50 -0500131 log.Debugw("UpdateLogLevel-request", log.Fields{"package": logging.PackageName, "intval": int(logging.Level)})
khenaidoo92e62c52018-10-03 14:02:54 -0400132 out := new(empty.Empty)
khenaidoo6f2fbe32019-01-18 16:16:50 -0500133 if logging.PackageName == "" {
134 log.SetAllLogLevel(int(logging.Level))
135 } else {
136 log.SetPackageLogLevel(logging.PackageName, int(logging.Level))
137 }
khenaidoo92e62c52018-10-03 14:02:54 -0400138 return out, nil
khenaidoobf6e7bb2018-08-14 22:27:29 -0400139}
140
141func (handler *APIHandler) EnableLogicalDevicePort(ctx context.Context, id *voltha.LogicalPortId) (*empty.Empty, error) {
142 log.Debugw("EnableLogicalDevicePort-request", log.Fields{"id": id, "test": common.TestModeKeys_api_test.String()})
143 if isTestMode(ctx) {
144 out := new(empty.Empty)
145 return out, nil
146 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500147
148 if isOFControllerRequest(ctx) {
149 txn, err := handler.createKvTransaction(ctx)
150 if txn == nil {
151 return new(empty.Empty), err
152 } else if txn.Acquired(MAX_RESPONSE_TIME) {
153 defer txn.Close() // Ensure active core signals "done" to standby
154 } else {
155 return new(empty.Empty), errors.New("failed-to-seize-request")
156 }
157 }
khenaidoo4d4802d2018-10-04 21:59:49 -0400158 ch := make(chan interface{})
159 defer close(ch)
khenaidoo19d7b632018-10-30 10:49:50 -0400160 go handler.logicalDeviceMgr.enableLogicalPort(ctx, id, ch)
khenaidoo4d4802d2018-10-04 21:59:49 -0400161 return waitForNilResponseOnSuccess(ctx, ch)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400162}
163
164func (handler *APIHandler) DisableLogicalDevicePort(ctx context.Context, id *voltha.LogicalPortId) (*empty.Empty, error) {
165 log.Debugw("DisableLogicalDevicePort-request", log.Fields{"id": id, "test": common.TestModeKeys_api_test.String()})
166 if isTestMode(ctx) {
167 out := new(empty.Empty)
168 return out, nil
169 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500170
171 if isOFControllerRequest(ctx) {
172 txn, err := handler.createKvTransaction(ctx)
173 if txn == nil {
174 return new(empty.Empty), err
175 } else if txn.Acquired(MAX_RESPONSE_TIME) {
176 defer txn.Close() // Ensure active core signals "done" to standby
177 } else {
178 return new(empty.Empty), errors.New("failed-to-seize-request")
179 }
180 }
khenaidoo19d7b632018-10-30 10:49:50 -0400181 ch := make(chan interface{})
182 defer close(ch)
183 go handler.logicalDeviceMgr.disableLogicalPort(ctx, id, ch)
184 return waitForNilResponseOnSuccess(ctx, ch)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400185}
186
187func (handler *APIHandler) UpdateLogicalDeviceFlowTable(ctx context.Context, flow *openflow_13.FlowTableUpdate) (*empty.Empty, error) {
188 log.Debugw("UpdateLogicalDeviceFlowTable-request", log.Fields{"flow": flow, "test": common.TestModeKeys_api_test.String()})
189 if isTestMode(ctx) {
190 out := new(empty.Empty)
191 return out, nil
192 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500193
194 if isOFControllerRequest(ctx) {
195 txn, err := handler.createKvTransaction(ctx)
196 if txn == nil {
197 return new(empty.Empty), err
198 } else if txn.Acquired(MAX_RESPONSE_TIME) {
199 defer txn.Close() // Ensure active core signals "done" to standby
200 } else {
201 return new(empty.Empty), errors.New("failed-to-seize-request")
202 }
203 }
khenaidoo19d7b632018-10-30 10:49:50 -0400204 ch := make(chan interface{})
205 defer close(ch)
206 go handler.logicalDeviceMgr.updateFlowTable(ctx, flow.Id, flow.FlowMod, ch)
207 return waitForNilResponseOnSuccess(ctx, ch)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400208}
209
210func (handler *APIHandler) UpdateLogicalDeviceFlowGroupTable(ctx context.Context, flow *openflow_13.FlowGroupTableUpdate) (*empty.Empty, error) {
211 log.Debugw("UpdateLogicalDeviceFlowGroupTable-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
217 if isOFControllerRequest(ctx) {
218 txn, err := handler.createKvTransaction(ctx)
219 if txn == nil {
220 return new(empty.Empty), err
221 } else if txn.Acquired(MAX_RESPONSE_TIME) {
222 defer txn.Close() // Ensure active core signals "done" to standby
223 } else {
224 return new(empty.Empty), errors.New("failed-to-seize-request")
225 }
226 }
khenaidoo19d7b632018-10-30 10:49:50 -0400227 ch := make(chan interface{})
228 defer close(ch)
229 go handler.logicalDeviceMgr.updateGroupTable(ctx, flow.Id, flow.GroupMod, ch)
230 return waitForNilResponseOnSuccess(ctx, ch)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400231}
232
khenaidoob9203542018-09-17 22:56:37 -0400233// GetDevice must be implemented in the read-only containers - should it also be implemented here?
234func (handler *APIHandler) GetDevice(ctx context.Context, id *voltha.ID) (*voltha.Device, error) {
235 log.Debugw("GetDevice-request", log.Fields{"id": id})
khenaidoo19d7b632018-10-30 10:49:50 -0400236 return handler.deviceMgr.GetDevice(id.Id)
khenaidoob9203542018-09-17 22:56:37 -0400237}
238
239// GetDevice must be implemented in the read-only containers - should it also be implemented here?
240func (handler *APIHandler) ListDevices(ctx context.Context, empty *empty.Empty) (*voltha.Devices, error) {
241 log.Debug("ListDevices")
242 return handler.deviceMgr.ListDevices()
243}
244
khenaidoo7ccedd52018-12-14 16:48:54 -0500245// ListDeviceIds returns the list of device ids managed by a voltha core
246func (handler *APIHandler) ListDeviceIds(ctx context.Context, empty *empty.Empty) (*voltha.IDs, error) {
247 log.Debug("ListDeviceIDs")
248 if isTestMode(ctx) {
249 out := &voltha.IDs{Items: make([]*voltha.ID, 0)}
250 return out, nil
251 }
252 return handler.deviceMgr.ListDeviceIds()
253}
254
255//ReconcileDevices is a request to a voltha core to managed a list of devices based on their IDs
256func (handler *APIHandler) ReconcileDevices(ctx context.Context, ids *voltha.IDs) (*empty.Empty, error) {
257 log.Debug("ReconcileDevices")
258 if isTestMode(ctx) {
259 out := new(empty.Empty)
260 return out, nil
261 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500262
263 if isOFControllerRequest(ctx) {
264 txn, err := handler.createKvTransaction(ctx)
265 if txn == nil {
266 return new(empty.Empty), err
267 } else if txn.Acquired(MAX_RESPONSE_TIME) {
268 defer txn.Close() // Ensure active core signals "done" to standby
269 } else {
270 return new(empty.Empty), errors.New("failed-to-seize-request")
271 }
272 }
khenaidoo7ccedd52018-12-14 16:48:54 -0500273 ch := make(chan interface{})
274 defer close(ch)
275 go handler.deviceMgr.ReconcileDevices(ctx, ids, ch)
276 return waitForNilResponseOnSuccess(ctx, ch)
277}
278
khenaidoob9203542018-09-17 22:56:37 -0400279// GetLogicalDevice must be implemented in the read-only containers - should it also be implemented here?
280func (handler *APIHandler) GetLogicalDevice(ctx context.Context, id *voltha.ID) (*voltha.LogicalDevice, error) {
281 log.Debugw("GetLogicalDevice-request", log.Fields{"id": id})
282 return handler.logicalDeviceMgr.getLogicalDevice(id.Id)
283}
284
285// ListLogicalDevices must be implemented in the read-only containers - should it also be implemented here?
286func (handler *APIHandler) ListLogicalDevices(ctx context.Context, empty *empty.Empty) (*voltha.LogicalDevices, error) {
287 log.Debug("ListLogicalDevices")
288 return handler.logicalDeviceMgr.listLogicalDevices()
289}
290
khenaidoo19d7b632018-10-30 10:49:50 -0400291// ListLogicalDevicePorts must be implemented in the read-only containers - should it also be implemented here?
292func (handler *APIHandler) ListLogicalDevicePorts(ctx context.Context, id *voltha.ID) (*voltha.LogicalPorts, error) {
293 log.Debugw("ListLogicalDevicePorts", log.Fields{"logicaldeviceid": id})
294 return handler.logicalDeviceMgr.ListLogicalDevicePorts(ctx, id.Id)
295}
296
khenaidoo4d4802d2018-10-04 21:59:49 -0400297// CreateDevice creates a new parent device in the data model
khenaidoobf6e7bb2018-08-14 22:27:29 -0400298func (handler *APIHandler) CreateDevice(ctx context.Context, device *voltha.Device) (*voltha.Device, error) {
khenaidoob9203542018-09-17 22:56:37 -0400299 log.Debugw("createdevice", log.Fields{"device": *device})
khenaidoobf6e7bb2018-08-14 22:27:29 -0400300 if isTestMode(ctx) {
301 return &voltha.Device{Id: device.Id}, nil
302 }
Richard Jankowskid42826e2018-11-02 16:06:37 -0400303
Richard Jankowski2755adf2019-01-17 17:16:48 -0500304 if isOFControllerRequest(ctx) {
305 txn, err := handler.createKvTransaction(ctx)
306 if txn == nil {
307 return &voltha.Device{}, err
308 } else if txn.Acquired(MAX_RESPONSE_TIME) {
309 defer txn.Close() // Ensure active core signals "done" to standby
310 } else {
311 return &voltha.Device{}, errors.New("failed-to-seize-request")
312 }
313 }
khenaidoob9203542018-09-17 22:56:37 -0400314 ch := make(chan interface{})
315 defer close(ch)
316 go handler.deviceMgr.createDevice(ctx, device, ch)
317 select {
318 case res := <-ch:
khenaidoo92e62c52018-10-03 14:02:54 -0400319 if res != nil {
320 if err, ok := res.(error); ok {
321 return &voltha.Device{}, err
322 }
323 if d, ok := res.(*voltha.Device); ok {
324 return d, nil
325 }
khenaidoob9203542018-09-17 22:56:37 -0400326 }
khenaidoo92e62c52018-10-03 14:02:54 -0400327 log.Warnw("create-device-unexpected-return-type", log.Fields{"result": res})
328 err := status.Errorf(codes.Internal, "%s", res)
329 return &voltha.Device{}, err
khenaidoob9203542018-09-17 22:56:37 -0400330 case <-ctx.Done():
331 log.Debug("createdevice-client-timeout")
332 return nil, ctx.Err()
333 }
khenaidoobf6e7bb2018-08-14 22:27:29 -0400334}
335
khenaidoo4d4802d2018-10-04 21:59:49 -0400336// EnableDevice activates a device by invoking the adopt_device API on the appropriate adapter
khenaidoobf6e7bb2018-08-14 22:27:29 -0400337func (handler *APIHandler) EnableDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
khenaidoob9203542018-09-17 22:56:37 -0400338 log.Debugw("enabledevice", log.Fields{"id": id})
khenaidoobf6e7bb2018-08-14 22:27:29 -0400339 if isTestMode(ctx) {
khenaidoo4d4802d2018-10-04 21:59:49 -0400340 return new(empty.Empty), nil
khenaidoobf6e7bb2018-08-14 22:27:29 -0400341 }
Richard Jankowskid42826e2018-11-02 16:06:37 -0400342
Richard Jankowski2755adf2019-01-17 17:16:48 -0500343 if isOFControllerRequest(ctx) {
344 txn, err := handler.createKvTransaction(ctx)
345 if txn == nil {
346 return new(empty.Empty), err
347 } else if txn.Acquired(MAX_RESPONSE_TIME) {
348 defer txn.Close() // Ensure active core signals "done" to standby
349 } else {
350 return new(empty.Empty), errors.New("failed-to-seize-request")
351 }
352 }
khenaidoob9203542018-09-17 22:56:37 -0400353 ch := make(chan interface{})
354 defer close(ch)
355 go handler.deviceMgr.enableDevice(ctx, id, ch)
khenaidoo4d4802d2018-10-04 21:59:49 -0400356 return waitForNilResponseOnSuccess(ctx, ch)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400357}
358
khenaidoo4d4802d2018-10-04 21:59:49 -0400359// DisableDevice disables a device along with any child device it may have
khenaidoobf6e7bb2018-08-14 22:27:29 -0400360func (handler *APIHandler) DisableDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
361 log.Debugw("disabledevice-request", log.Fields{"id": id})
362 if isTestMode(ctx) {
khenaidoo4d4802d2018-10-04 21:59:49 -0400363 return new(empty.Empty), nil
khenaidoobf6e7bb2018-08-14 22:27:29 -0400364 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500365
366 if isOFControllerRequest(ctx) {
367 txn, err := handler.createKvTransaction(ctx)
368 if txn == nil {
369 return new(empty.Empty), err
370 } else if txn.Acquired(MAX_RESPONSE_TIME) {
371 defer txn.Close() // Ensure active core signals "done" to standby
372 } else {
373 return new(empty.Empty), errors.New("failed-to-seize-request")
374 }
375 }
khenaidoo92e62c52018-10-03 14:02:54 -0400376 ch := make(chan interface{})
377 defer close(ch)
378 go handler.deviceMgr.disableDevice(ctx, id, ch)
khenaidoo4d4802d2018-10-04 21:59:49 -0400379 return waitForNilResponseOnSuccess(ctx, ch)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400380}
381
khenaidoo4d4802d2018-10-04 21:59:49 -0400382//RebootDevice invoked the reboot API to the corresponding adapter
khenaidoobf6e7bb2018-08-14 22:27:29 -0400383func (handler *APIHandler) RebootDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
khenaidoo4d4802d2018-10-04 21:59:49 -0400384 log.Debugw("rebootDevice-request", log.Fields{"id": id})
khenaidoobf6e7bb2018-08-14 22:27:29 -0400385 if isTestMode(ctx) {
khenaidoo4d4802d2018-10-04 21:59:49 -0400386 return new(empty.Empty), nil
khenaidoobf6e7bb2018-08-14 22:27:29 -0400387 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500388
389 if isOFControllerRequest(ctx) {
390 txn, err := handler.createKvTransaction(ctx)
391 if txn == nil {
392 return new(empty.Empty), err
393 } else if txn.Acquired(MAX_RESPONSE_TIME) {
394 defer txn.Close() // Ensure active core signals "done" to standby
395 } else {
396 return new(empty.Empty), errors.New("failed-to-seize-request")
397 }
398 }
khenaidoo4d4802d2018-10-04 21:59:49 -0400399 ch := make(chan interface{})
400 defer close(ch)
401 go handler.deviceMgr.rebootDevice(ctx, id, ch)
402 return waitForNilResponseOnSuccess(ctx, ch)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400403}
404
khenaidoo4d4802d2018-10-04 21:59:49 -0400405// DeleteDevice removes a device from the data model
khenaidoobf6e7bb2018-08-14 22:27:29 -0400406func (handler *APIHandler) DeleteDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
407 log.Debugw("deletedevice-request", log.Fields{"id": id})
408 if isTestMode(ctx) {
khenaidoo4d4802d2018-10-04 21:59:49 -0400409 return new(empty.Empty), nil
khenaidoobf6e7bb2018-08-14 22:27:29 -0400410 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500411
412 if isOFControllerRequest(ctx) {
413 txn, err := handler.createKvTransaction(ctx)
414 if txn == nil {
415 return new(empty.Empty), err
416 } else if txn.Acquired(MAX_RESPONSE_TIME) {
417 defer txn.Close() // Ensure active core signals "done" to standby
418 } else {
419 return new(empty.Empty), errors.New("failed-to-seize-request")
420 }
421 }
khenaidoo4d4802d2018-10-04 21:59:49 -0400422 ch := make(chan interface{})
423 defer close(ch)
424 go handler.deviceMgr.deleteDevice(ctx, id, ch)
425 return waitForNilResponseOnSuccess(ctx, ch)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400426}
427
428func (handler *APIHandler) DownloadImage(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
429 log.Debugw("DownloadImage-request", log.Fields{"img": *img})
430 if isTestMode(ctx) {
431 resp := &common.OperationResp{Code: common.OperationResp_OPERATION_SUCCESS}
432 return resp, nil
433 }
434
435 return nil, errors.New("UnImplemented")
436}
437
438func (handler *APIHandler) CancelImageDownload(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
439 log.Debugw("CancelImageDownload-request", log.Fields{"img": *img})
440 if isTestMode(ctx) {
441 resp := &common.OperationResp{Code: common.OperationResp_OPERATION_SUCCESS}
442 return resp, nil
443 }
444 return nil, errors.New("UnImplemented")
445}
446
447func (handler *APIHandler) ActivateImageUpdate(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
448 log.Debugw("ActivateImageUpdate-request", log.Fields{"img": *img})
449 if isTestMode(ctx) {
450 resp := &common.OperationResp{Code: common.OperationResp_OPERATION_SUCCESS}
451 return resp, nil
452 }
453 return nil, errors.New("UnImplemented")
454}
455
456func (handler *APIHandler) RevertImageUpdate(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
457 log.Debugw("RevertImageUpdate-request", log.Fields{"img": *img})
458 if isTestMode(ctx) {
459 resp := &common.OperationResp{Code: common.OperationResp_OPERATION_SUCCESS}
460 return resp, nil
461 }
462 return nil, errors.New("UnImplemented")
463}
464
465func (handler *APIHandler) UpdateDevicePmConfigs(ctx context.Context, configs *voltha.PmConfigs) (*empty.Empty, error) {
466 log.Debugw("UpdateDevicePmConfigs-request", log.Fields{"configs": *configs})
467 if isTestMode(ctx) {
468 out := new(empty.Empty)
469 return out, nil
470 }
471 return nil, errors.New("UnImplemented")
472}
473
474func (handler *APIHandler) CreateAlarmFilter(ctx context.Context, filter *voltha.AlarmFilter) (*voltha.AlarmFilter, error) {
475 log.Debugw("CreateAlarmFilter-request", log.Fields{"filter": *filter})
476 if isTestMode(ctx) {
477 f := &voltha.AlarmFilter{Id: filter.Id}
478 return f, nil
479 }
480 return nil, errors.New("UnImplemented")
481}
482
483func (handler *APIHandler) UpdateAlarmFilter(ctx context.Context, filter *voltha.AlarmFilter) (*voltha.AlarmFilter, error) {
484 log.Debugw("UpdateAlarmFilter-request", log.Fields{"filter": *filter})
485 if isTestMode(ctx) {
486 f := &voltha.AlarmFilter{Id: filter.Id}
487 return f, nil
488 }
489 return nil, errors.New("UnImplemented")
490}
491
492func (handler *APIHandler) DeleteAlarmFilter(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
493 log.Debugw("DeleteAlarmFilter-request", log.Fields{"id": *id})
494 if isTestMode(ctx) {
495 out := new(empty.Empty)
496 return out, nil
497 }
498 return nil, errors.New("UnImplemented")
499}
500
501func (handler *APIHandler) SelfTest(ctx context.Context, id *voltha.ID) (*voltha.SelfTestResponse, error) {
502 log.Debugw("SelfTest-request", log.Fields{"id": id})
503 if isTestMode(ctx) {
504 resp := &voltha.SelfTestResponse{Result: voltha.SelfTestResponse_SUCCESS}
505 return resp, nil
506 }
507 return nil, errors.New("UnImplemented")
508}
Stephane Barbarie6e1bd502018-11-05 22:44:45 -0500509
510func (handler *APIHandler) forwardPacketOut(packet *openflow_13.PacketOut) {
511 log.Debugw("forwardPacketOut-request", log.Fields{"packet": packet})
Richard Jankowski2755adf2019-01-17 17:16:48 -0500512 agent := handler.logicalDeviceMgr.getLogicalDeviceAgent(packet.Id)
513 agent.packetOut(packet.PacketOut)
Stephane Barbarie6e1bd502018-11-05 22:44:45 -0500514}
515func (handler *APIHandler) StreamPacketsOut(
516 packets voltha.VolthaService_StreamPacketsOutServer,
517) error {
518 log.Debugw("StreamPacketsOut-request", log.Fields{"packets": packets})
519 for {
520 packet, err := packets.Recv()
521
522 if err == io.EOF {
523 break
524 } else if err != nil {
525 log.Errorw("Failed to receive packet", log.Fields{"error": err})
526 }
527
528 handler.forwardPacketOut(packet)
529 }
530
531 log.Debugw("StreamPacketsOut-request-done", log.Fields{"packets": packets})
532 return nil
533}
534
535func (handler *APIHandler) sendPacketIn(deviceId string, packet *openflow_13.OfpPacketIn) {
536 packetIn := openflow_13.PacketIn{Id: deviceId, PacketIn: packet}
537 log.Debugw("sendPacketIn", log.Fields{"packetIn": packetIn})
Richard Jankowskidbab94a2018-12-06 16:20:25 -0500538 // Enqueue the packet
539 if err := handler.packetInQueue.Put(packetIn); err != nil {
540 log.Errorw("failed-to-enqueue-packet", log.Fields{"error": err})
541 }
Stephane Barbarie6e1bd502018-11-05 22:44:45 -0500542}
543
544func (handler *APIHandler) ReceivePacketsIn(
545 empty *empty.Empty,
546 packetsIn voltha.VolthaService_ReceivePacketsInServer,
547) error {
548 log.Debugw("ReceivePacketsIn-request", log.Fields{"packetsIn": packetsIn})
549
550 for {
Richard Jankowskidbab94a2018-12-06 16:20:25 -0500551 // Dequeue a packet
552 if packets, err := handler.packetInQueue.Get(1); err == nil {
553 log.Debugw("dequeued-packet", log.Fields{"packet": packets[0]})
554 if packet, ok := packets[0].(openflow_13.PacketIn); ok {
555 log.Debugw("sending-packet-in", log.Fields{"packet": packet})
556 if err := packetsIn.Send(&packet); err != nil {
557 log.Errorw("failed-to-send-packet", log.Fields{"error": err})
558 }
559 }
Stephane Barbarie6e1bd502018-11-05 22:44:45 -0500560 }
561 }
562 log.Debugw("ReceivePacketsIn-request-done", log.Fields{"packetsIn": packetsIn})
563 return nil
564}
565
566func (handler *APIHandler) sendChangeEvent(deviceId string, portStatus *openflow_13.OfpPortStatus) {
567 // TODO: validate the type of portStatus parameter
568 //if _, ok := portStatus.(*openflow_13.OfpPortStatus); ok {
569 //}
570 event := openflow_13.ChangeEvent{Id: deviceId, Event: &openflow_13.ChangeEvent_PortStatus{PortStatus: portStatus}}
571 log.Debugw("sendChangeEvent", log.Fields{"event": event})
572 // TODO: put the packet in the queue
573}
574
575func (handler *APIHandler) ReceiveChangeEvents(
576 empty *empty.Empty,
577 changeEvents voltha.VolthaService_ReceiveChangeEventsServer,
578) error {
579 log.Debugw("ReceiveChangeEvents-request", log.Fields{"changeEvents": changeEvents})
580 for {
581 // TODO: need to retrieve packet from queue
582 event := &openflow_13.ChangeEvent{}
583 time.Sleep(time.Duration(5) * time.Second)
584 err := changeEvents.Send(event)
585 if err != nil {
586 log.Errorw("Failed to send change event", log.Fields{"error": err})
587 }
588 }
589 return nil
590}
591
592func (handler *APIHandler) Subscribe(
593 ctx context.Context,
594 ofAgent *voltha.OfAgentSubscriber,
595) (*voltha.OfAgentSubscriber, error) {
596 log.Debugw("Subscribe-request", log.Fields{"ofAgent": ofAgent})
597 return &voltha.OfAgentSubscriber{OfagentId: ofAgent.OfagentId, VolthaId: ofAgent.VolthaId}, nil
598}