blob: fecfd45c12ee26c0d06928774b3cf10935b83105 [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"
21 "github.com/golang/protobuf/ptypes/empty"
22 da "github.com/opencord/voltha-go/common/core/northbound/grpc"
khenaidoo1ce37ad2019-03-24 22:07:24 -040023 "github.com/opencord/voltha-go/rw_core/utils"
Scott Baker807addd2019-10-24 15:16:21 -070024 "github.com/opencord/voltha-lib-go/v2/pkg/log"
Scott Baker555307d2019-11-04 08:58:01 -080025 "github.com/opencord/voltha-protos/v2/go/common"
26 "github.com/opencord/voltha-protos/v2/go/omci"
27 "github.com/opencord/voltha-protos/v2/go/openflow_13"
28 "github.com/opencord/voltha-protos/v2/go/voltha"
khenaidoob9203542018-09-17 22:56:37 -040029 "google.golang.org/grpc/codes"
khenaidoobf6e7bb2018-08-14 22:27:29 -040030 "google.golang.org/grpc/metadata"
khenaidoob9203542018-09-17 22:56:37 -040031 "google.golang.org/grpc/status"
Stephane Barbarie6e1bd502018-11-05 22:44:45 -050032 "io"
A R Karthick881e7ea2019-08-19 19:44:02 +000033 "sync"
khenaidoobf6e7bb2018-08-14 22:27:29 -040034)
35
khenaidoof684e1b2019-10-28 19:00:37 -040036var errorIdNotFound = status.Error(codes.NotFound, "id-not-found")
37
khenaidoof5a5bfa2019-01-23 22:20:29 -050038const (
khenaidoo2c6a0992019-04-29 13:46:56 -040039 IMAGE_DOWNLOAD = iota
40 CANCEL_IMAGE_DOWNLOAD = iota
41 ACTIVATE_IMAGE = iota
42 REVERT_IMAGE = iota
khenaidoof5a5bfa2019-01-23 22:20:29 -050043)
44
khenaidoobf6e7bb2018-08-14 22:27:29 -040045type APIHandler struct {
khenaidoo2c6a0992019-04-29 13:46:56 -040046 deviceMgr *DeviceManager
47 logicalDeviceMgr *LogicalDeviceManager
48 adapterMgr *AdapterManager
A R Karthick881e7ea2019-08-19 19:44:02 +000049 packetInQueue chan openflow_13.PacketIn
50 changeEventQueue chan openflow_13.ChangeEvent
51 packetInQueueDone chan bool
52 changeEventQueueDone chan bool
khenaidoo2c6a0992019-04-29 13:46:56 -040053 coreInCompetingMode bool
khenaidoob6080322019-01-29 21:47:38 -050054 longRunningRequestTimeout int64
khenaidoo2c6a0992019-04-29 13:46:56 -040055 defaultRequestTimeout int64
khenaidoobf6e7bb2018-08-14 22:27:29 -040056 da.DefaultAPIHandler
khenaidoo54e0ddf2019-02-27 16:21:33 -050057 core *Core
khenaidoobf6e7bb2018-08-14 22:27:29 -040058}
59
khenaidoo54e0ddf2019-02-27 16:21:33 -050060func NewAPIHandler(core *Core) *APIHandler {
Stephane Barbarie6e1bd502018-11-05 22:44:45 -050061 handler := &APIHandler{
khenaidoo2c6a0992019-04-29 13:46:56 -040062 deviceMgr: core.deviceMgr,
63 logicalDeviceMgr: core.logicalDeviceMgr,
64 adapterMgr: core.adapterMgr,
65 coreInCompetingMode: core.config.InCompetingMode,
66 longRunningRequestTimeout: core.config.LongRunningRequestTimeout,
67 defaultRequestTimeout: core.config.DefaultRequestTimeout,
A R Karthick881e7ea2019-08-19 19:44:02 +000068 packetInQueue: make(chan openflow_13.PacketIn, 100),
69 changeEventQueue: make(chan openflow_13.ChangeEvent, 100),
70 packetInQueueDone: make(chan bool, 1),
71 changeEventQueueDone: make(chan bool, 1),
72 core: core,
Stephane Barbarie6e1bd502018-11-05 22:44:45 -050073 }
khenaidoobf6e7bb2018-08-14 22:27:29 -040074 return handler
75}
khenaidoo4d4802d2018-10-04 21:59:49 -040076
77// isTestMode is a helper function to determine a function is invoked for testing only
khenaidoobf6e7bb2018-08-14 22:27:29 -040078func isTestMode(ctx context.Context) bool {
79 md, _ := metadata.FromIncomingContext(ctx)
80 _, exist := md[common.TestModeKeys_api_test.String()]
81 return exist
82}
83
Richard Jankowskid42826e2018-11-02 16:06:37 -040084// This function attempts to extract the serial number from the request metadata
85// and create a KV transaction for that serial number for the current core.
86func (handler *APIHandler) createKvTransaction(ctx context.Context) (*KVTransaction, error) {
87 var (
khenaidoo43c82122018-11-22 18:38:28 -050088 err error
89 ok bool
90 md metadata.MD
Richard Jankowskid42826e2018-11-02 16:06:37 -040091 serNum []string
92 )
93 if md, ok = metadata.FromIncomingContext(ctx); !ok {
94 err = errors.New("metadata-not-found")
95 } else if serNum, ok = md["voltha_serial_number"]; !ok {
96 err = errors.New("serial-number-not-found")
97 }
khenaidoo2c6a0992019-04-29 13:46:56 -040098 if !ok || serNum == nil {
Richard Jankowskid42826e2018-11-02 16:06:37 -040099 log.Error(err)
100 return nil, err
101 }
102 // Create KV transaction
103 txn := NewKVTransaction(serNum[0])
104 return txn, nil
105}
106
Richard Jankowski2755adf2019-01-17 17:16:48 -0500107// isOFControllerRequest is a helper function to determine if a request was initiated
108// from the OpenFlow controller (or its proxy, e.g. OFAgent)
Richard Jankowski46464e92019-03-05 11:53:55 -0500109func (handler *APIHandler) isOFControllerRequest(ctx context.Context) bool {
khenaidoo9cdc1a62019-01-24 21:57:40 -0500110 if md, ok := metadata.FromIncomingContext(ctx); ok {
111 // Metadata in context
Richard Jankowski46464e92019-03-05 11:53:55 -0500112 if _, ok = md[handler.core.config.CoreBindingKey]; ok {
khenaidoo9cdc1a62019-01-24 21:57:40 -0500113 // OFAgent field in metadata
khenaidoo3d3b8c22019-05-22 18:10:39 -0400114 log.Debug("OFController-request")
khenaidoo9cdc1a62019-01-24 21:57:40 -0500115 return true
116 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500117 }
khenaidoo3d3b8c22019-05-22 18:10:39 -0400118 log.Debug("not-OFController-request")
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
khenaidoo09771ef2019-10-11 14:25:02 -0400128// takeRequestOwnership creates a transaction in the dB for this request and handles the logic of transaction
129// acquisition. If the device is owned by this Core (in a core-pair) then acquire the transaction with a
130// timeout value (in the event this Core dies the transaction times out in the dB causing the other Core in the
131// core-pair to proceed with the it). If the device is not owned then this Core will just monitor the transaction
132// for potential timeouts.
133func (handler *APIHandler) takeRequestOwnership(ctx context.Context, id interface{}, maxTimeout ...int64) (*KVTransaction, error) {
khenaidoo43aa6bd2019-05-29 13:35:13 -0400134 timeout := handler.defaultRequestTimeout
135 if len(maxTimeout) > 0 {
136 timeout = maxTimeout[0]
137 }
khenaidoo43aa6bd2019-05-29 13:35:13 -0400138 txn, err := handler.createKvTransaction(ctx)
139 if txn == nil {
140 return nil, err
khenaidoo09771ef2019-10-11 14:25:02 -0400141 }
142 var acquired bool
143 if id != nil {
144 var ownedByMe bool
145 if ownedByMe, err = handler.core.deviceOwnership.OwnedByMe(id); err != nil {
146 log.Warnw("getting-ownership-failed", log.Fields{"deviceId": id, "error": err})
khenaidoof684e1b2019-10-28 19:00:37 -0400147 return nil, errorIdNotFound
khenaidoo09771ef2019-10-11 14:25:02 -0400148 }
149 acquired, err = txn.Acquired(timeout, ownedByMe)
150 } else {
151 acquired, err = txn.Acquired(timeout)
152 }
153 if err == nil && acquired {
154 log.Debugw("transaction-acquired", log.Fields{"transactionId": txn.txnId})
khenaidoo43aa6bd2019-05-29 13:35:13 -0400155 return txn, nil
156 } else {
khenaidoo09771ef2019-10-11 14:25:02 -0400157 log.Debugw("transaction-not-acquired", log.Fields{"transactionId": txn.txnId, "error": err})
Kent Hagerman46dcd9d2019-09-18 16:42:59 -0400158 return nil, errorTransactionNotAcquired
khenaidoo43aa6bd2019-05-29 13:35:13 -0400159 }
160}
161
khenaidoo09771ef2019-10-11 14:25:02 -0400162// waitForNilResponseOnSuccess is a helper function to wait for a response on channel monitorCh where an nil
khenaidoo4d4802d2018-10-04 21:59:49 -0400163// response is expected in a successful scenario
164func waitForNilResponseOnSuccess(ctx context.Context, ch chan interface{}) (*empty.Empty, error) {
165 select {
166 case res := <-ch:
167 if res == nil {
168 return new(empty.Empty), nil
169 } else if err, ok := res.(error); ok {
170 return new(empty.Empty), err
171 } else {
172 log.Warnw("unexpected-return-type", log.Fields{"result": res})
173 err = status.Errorf(codes.Internal, "%s", res)
174 return new(empty.Empty), err
175 }
176 case <-ctx.Done():
177 log.Debug("client-timeout")
178 return nil, ctx.Err()
179 }
180}
181
khenaidoobf6e7bb2018-08-14 22:27:29 -0400182func (handler *APIHandler) UpdateLogLevel(ctx context.Context, logging *voltha.Logging) (*empty.Empty, error) {
khenaidoo6f2fbe32019-01-18 16:16:50 -0500183 log.Debugw("UpdateLogLevel-request", log.Fields{"package": logging.PackageName, "intval": int(logging.Level)})
khenaidoo92e62c52018-10-03 14:02:54 -0400184 out := new(empty.Empty)
khenaidoo6f2fbe32019-01-18 16:16:50 -0500185 if logging.PackageName == "" {
186 log.SetAllLogLevel(int(logging.Level))
Scott Baker5f401472019-08-22 08:32:26 -0700187 log.SetDefaultLogLevel(int(logging.Level))
188 } else if logging.PackageName == "default" {
189 log.SetDefaultLogLevel(int(logging.Level))
khenaidoo6f2fbe32019-01-18 16:16:50 -0500190 } else {
191 log.SetPackageLogLevel(logging.PackageName, int(logging.Level))
192 }
Scott Baker5f401472019-08-22 08:32:26 -0700193
khenaidoo92e62c52018-10-03 14:02:54 -0400194 return out, nil
khenaidoobf6e7bb2018-08-14 22:27:29 -0400195}
196
Scott Baker5f401472019-08-22 08:32:26 -0700197func (aa APIHandler) GetLogLevels(ctx context.Context, in *voltha.LoggingComponent) (*voltha.Loggings, error) {
198 logLevels := &voltha.Loggings{}
199
200 // do the per-package log levels
201 for _, packageName := range log.GetPackageNames() {
202 level, err := log.GetPackageLogLevel(packageName)
203 if err != nil {
204 return nil, err
205 }
206 logLevel := &voltha.Logging{
207 ComponentName: in.ComponentName,
208 PackageName: packageName,
209 Level: voltha.LogLevel_LogLevel(level)}
210 logLevels.Items = append(logLevels.Items, logLevel)
211 }
212
213 // now do the default log level
214 logLevel := &voltha.Logging{
215 ComponentName: in.ComponentName,
216 PackageName: "default",
217 Level: voltha.LogLevel_LogLevel(log.GetDefaultLogLevel())}
218 logLevels.Items = append(logLevels.Items, logLevel)
219
220 return logLevels, nil
221}
222
khenaidoo43aa6bd2019-05-29 13:35:13 -0400223func (handler *APIHandler) GetLogicalDevicePort(ctx context.Context, id *voltha.LogicalPortId) (*voltha.LogicalPort, error) {
224 log.Debugw("GetLogicalDevicePort-request", log.Fields{"id": *id})
225
226 if handler.competeForTransaction() {
227 if txn, err := handler.takeRequestOwnership(ctx, &utils.LogicalDeviceID{Id: id.Id}); err != nil {
228 return &voltha.LogicalPort{}, err
229 } else {
230 defer txn.Close()
231 }
232 }
233 return handler.logicalDeviceMgr.getLogicalPort(id)
234}
235
khenaidoobf6e7bb2018-08-14 22:27:29 -0400236func (handler *APIHandler) EnableLogicalDevicePort(ctx context.Context, id *voltha.LogicalPortId) (*empty.Empty, error) {
237 log.Debugw("EnableLogicalDevicePort-request", log.Fields{"id": id, "test": common.TestModeKeys_api_test.String()})
238 if isTestMode(ctx) {
239 out := new(empty.Empty)
240 return out, nil
241 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500242
khenaidoo9cdc1a62019-01-24 21:57:40 -0500243 if handler.competeForTransaction() {
khenaidoo2c6a0992019-04-29 13:46:56 -0400244 if txn, err := handler.takeRequestOwnership(ctx, &utils.LogicalDeviceID{Id: id.Id}); err != nil {
Richard Jankowski2755adf2019-01-17 17:16:48 -0500245 return new(empty.Empty), err
Richard Jankowski2755adf2019-01-17 17:16:48 -0500246 } else {
khenaidoo9cdc1a62019-01-24 21:57:40 -0500247 defer txn.Close()
Richard Jankowski2755adf2019-01-17 17:16:48 -0500248 }
249 }
khenaidoo9cdc1a62019-01-24 21:57:40 -0500250
khenaidoo4d4802d2018-10-04 21:59:49 -0400251 ch := make(chan interface{})
252 defer close(ch)
khenaidoo19d7b632018-10-30 10:49:50 -0400253 go handler.logicalDeviceMgr.enableLogicalPort(ctx, id, ch)
khenaidoo4d4802d2018-10-04 21:59:49 -0400254 return waitForNilResponseOnSuccess(ctx, ch)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400255}
256
257func (handler *APIHandler) DisableLogicalDevicePort(ctx context.Context, id *voltha.LogicalPortId) (*empty.Empty, error) {
258 log.Debugw("DisableLogicalDevicePort-request", log.Fields{"id": id, "test": common.TestModeKeys_api_test.String()})
259 if isTestMode(ctx) {
260 out := new(empty.Empty)
261 return out, nil
262 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500263
khenaidoo9cdc1a62019-01-24 21:57:40 -0500264 if handler.competeForTransaction() {
khenaidoo2c6a0992019-04-29 13:46:56 -0400265 if txn, err := handler.takeRequestOwnership(ctx, &utils.LogicalDeviceID{Id: id.Id}); err != nil {
Richard Jankowski2755adf2019-01-17 17:16:48 -0500266 return new(empty.Empty), err
Richard Jankowski2755adf2019-01-17 17:16:48 -0500267 } else {
khenaidoo9cdc1a62019-01-24 21:57:40 -0500268 defer txn.Close()
Richard Jankowski2755adf2019-01-17 17:16:48 -0500269 }
270 }
khenaidoo9cdc1a62019-01-24 21:57:40 -0500271
khenaidoo19d7b632018-10-30 10:49:50 -0400272 ch := make(chan interface{})
273 defer close(ch)
274 go handler.logicalDeviceMgr.disableLogicalPort(ctx, id, ch)
275 return waitForNilResponseOnSuccess(ctx, ch)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400276}
277
278func (handler *APIHandler) UpdateLogicalDeviceFlowTable(ctx context.Context, flow *openflow_13.FlowTableUpdate) (*empty.Empty, error) {
279 log.Debugw("UpdateLogicalDeviceFlowTable-request", log.Fields{"flow": flow, "test": common.TestModeKeys_api_test.String()})
280 if isTestMode(ctx) {
281 out := new(empty.Empty)
282 return out, nil
283 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500284
khenaidoo9cdc1a62019-01-24 21:57:40 -0500285 if handler.competeForTransaction() {
khenaidoo43aa6bd2019-05-29 13:35:13 -0400286 if txn, err := handler.takeRequestOwnership(ctx, &utils.LogicalDeviceID{Id: flow.Id}); err != nil {
287 return new(empty.Empty), err
288 } else {
289 defer txn.Close()
Richard Jankowski2755adf2019-01-17 17:16:48 -0500290 }
291 }
khenaidoo9cdc1a62019-01-24 21:57:40 -0500292
khenaidoo19d7b632018-10-30 10:49:50 -0400293 ch := make(chan interface{})
294 defer close(ch)
295 go handler.logicalDeviceMgr.updateFlowTable(ctx, flow.Id, flow.FlowMod, ch)
296 return waitForNilResponseOnSuccess(ctx, ch)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400297}
298
299func (handler *APIHandler) UpdateLogicalDeviceFlowGroupTable(ctx context.Context, flow *openflow_13.FlowGroupTableUpdate) (*empty.Empty, error) {
300 log.Debugw("UpdateLogicalDeviceFlowGroupTable-request", log.Fields{"flow": flow, "test": common.TestModeKeys_api_test.String()})
301 if isTestMode(ctx) {
302 out := new(empty.Empty)
303 return out, nil
304 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500305
khenaidoo9cdc1a62019-01-24 21:57:40 -0500306 if handler.competeForTransaction() {
khenaidoo43aa6bd2019-05-29 13:35:13 -0400307 if txn, err := handler.takeRequestOwnership(ctx, &utils.LogicalDeviceID{Id: flow.Id}); err != nil {
308 return new(empty.Empty), err
309 } else {
310 defer txn.Close()
Richard Jankowski2755adf2019-01-17 17:16:48 -0500311 }
312 }
khenaidoo9cdc1a62019-01-24 21:57:40 -0500313
khenaidoo19d7b632018-10-30 10:49:50 -0400314 ch := make(chan interface{})
315 defer close(ch)
316 go handler.logicalDeviceMgr.updateGroupTable(ctx, flow.Id, flow.GroupMod, ch)
317 return waitForNilResponseOnSuccess(ctx, ch)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400318}
319
khenaidoob9203542018-09-17 22:56:37 -0400320// GetDevice must be implemented in the read-only containers - should it also be implemented here?
321func (handler *APIHandler) GetDevice(ctx context.Context, id *voltha.ID) (*voltha.Device, error) {
322 log.Debugw("GetDevice-request", log.Fields{"id": id})
khenaidoo19d7b632018-10-30 10:49:50 -0400323 return handler.deviceMgr.GetDevice(id.Id)
khenaidoob9203542018-09-17 22:56:37 -0400324}
325
326// GetDevice must be implemented in the read-only containers - should it also be implemented here?
327func (handler *APIHandler) ListDevices(ctx context.Context, empty *empty.Empty) (*voltha.Devices, error) {
328 log.Debug("ListDevices")
329 return handler.deviceMgr.ListDevices()
330}
331
khenaidoo7ccedd52018-12-14 16:48:54 -0500332// ListDeviceIds returns the list of device ids managed by a voltha core
333func (handler *APIHandler) ListDeviceIds(ctx context.Context, empty *empty.Empty) (*voltha.IDs, error) {
334 log.Debug("ListDeviceIDs")
335 if isTestMode(ctx) {
336 out := &voltha.IDs{Items: make([]*voltha.ID, 0)}
337 return out, nil
338 }
339 return handler.deviceMgr.ListDeviceIds()
340}
341
342//ReconcileDevices is a request to a voltha core to managed a list of devices based on their IDs
343func (handler *APIHandler) ReconcileDevices(ctx context.Context, ids *voltha.IDs) (*empty.Empty, error) {
344 log.Debug("ReconcileDevices")
345 if isTestMode(ctx) {
346 out := new(empty.Empty)
347 return out, nil
348 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500349
khenaidoo9cdc1a62019-01-24 21:57:40 -0500350 // No need to grab a transaction as this request is core specific
351
khenaidoo7ccedd52018-12-14 16:48:54 -0500352 ch := make(chan interface{})
353 defer close(ch)
354 go handler.deviceMgr.ReconcileDevices(ctx, ids, ch)
355 return waitForNilResponseOnSuccess(ctx, ch)
356}
357
khenaidoob9203542018-09-17 22:56:37 -0400358func (handler *APIHandler) GetLogicalDevice(ctx context.Context, id *voltha.ID) (*voltha.LogicalDevice, error) {
359 log.Debugw("GetLogicalDevice-request", log.Fields{"id": id})
khenaidoo43aa6bd2019-05-29 13:35:13 -0400360 if handler.competeForTransaction() {
361 if txn, err := handler.takeRequestOwnership(ctx, &utils.LogicalDeviceID{Id: id.Id}); err != nil {
362 return &voltha.LogicalDevice{}, err
363 } else {
364 defer txn.Close()
365 }
366 }
khenaidoob9203542018-09-17 22:56:37 -0400367 return handler.logicalDeviceMgr.getLogicalDevice(id.Id)
368}
369
khenaidoob9203542018-09-17 22:56:37 -0400370func (handler *APIHandler) ListLogicalDevices(ctx context.Context, empty *empty.Empty) (*voltha.LogicalDevices, error) {
khenaidoo43aa6bd2019-05-29 13:35:13 -0400371 log.Debug("ListLogicalDevices-request")
372 if handler.competeForTransaction() {
khenaidoo09771ef2019-10-11 14:25:02 -0400373 if txn, err := handler.takeRequestOwnership(ctx, nil); err != nil {
khenaidoo43aa6bd2019-05-29 13:35:13 -0400374 return &voltha.LogicalDevices{}, err
375 } else {
376 defer txn.Close()
377 }
378 }
379 if handler.isOFControllerRequest(ctx) {
380 // Since an OF controller is only interested in the set of logical devices managed by thgis Core then return
381 // only logical devices managed/monitored by this Core.
382 return handler.logicalDeviceMgr.listManagedLogicalDevices()
383 }
khenaidoob9203542018-09-17 22:56:37 -0400384 return handler.logicalDeviceMgr.listLogicalDevices()
385}
386
khenaidoo21d51152019-02-01 13:48:37 -0500387// ListAdapters returns the contents of all adapters known to the system
388func (handler *APIHandler) ListAdapters(ctx context.Context, empty *empty.Empty) (*voltha.Adapters, error) {
389 log.Debug("ListDevices")
390 return handler.adapterMgr.listAdapters(ctx)
391}
392
khenaidoodd237172019-05-27 16:37:17 -0400393func (handler *APIHandler) ListLogicalDeviceFlows(ctx context.Context, id *voltha.ID) (*openflow_13.Flows, error) {
394 log.Debugw("ListLogicalDeviceFlows", log.Fields{"id": *id})
khenaidoo43aa6bd2019-05-29 13:35:13 -0400395 if handler.competeForTransaction() {
396 if txn, err := handler.takeRequestOwnership(ctx, &utils.LogicalDeviceID{Id: id.Id}); err != nil {
397 return &openflow_13.Flows{}, err
398 } else {
399 defer txn.Close()
400 }
401 }
khenaidoodd237172019-05-27 16:37:17 -0400402 return handler.logicalDeviceMgr.ListLogicalDeviceFlows(ctx, id.Id)
403}
404
405func (handler *APIHandler) ListLogicalDeviceFlowGroups(ctx context.Context, id *voltha.ID) (*openflow_13.FlowGroups, error) {
406 log.Debugw("ListLogicalDeviceFlowGroups", log.Fields{"id": *id})
khenaidoo43aa6bd2019-05-29 13:35:13 -0400407 if handler.competeForTransaction() {
408 if txn, err := handler.takeRequestOwnership(ctx, &utils.LogicalDeviceID{Id: id.Id}); err != nil {
409 return &openflow_13.FlowGroups{}, err
410 } else {
411 defer txn.Close()
412 }
413 }
khenaidoodd237172019-05-27 16:37:17 -0400414 return handler.logicalDeviceMgr.ListLogicalDeviceFlowGroups(ctx, id.Id)
415}
416
khenaidoo19d7b632018-10-30 10:49:50 -0400417func (handler *APIHandler) ListLogicalDevicePorts(ctx context.Context, id *voltha.ID) (*voltha.LogicalPorts, error) {
418 log.Debugw("ListLogicalDevicePorts", log.Fields{"logicaldeviceid": id})
khenaidoo43aa6bd2019-05-29 13:35:13 -0400419 if handler.competeForTransaction() {
420 if txn, err := handler.takeRequestOwnership(ctx, &utils.LogicalDeviceID{Id: id.Id}); err != nil {
421 return &voltha.LogicalPorts{}, err
422 } else {
423 defer txn.Close()
424 }
425 }
khenaidoo19d7b632018-10-30 10:49:50 -0400426 return handler.logicalDeviceMgr.ListLogicalDevicePorts(ctx, id.Id)
427}
428
khenaidoo4d4802d2018-10-04 21:59:49 -0400429// CreateDevice creates a new parent device in the data model
khenaidoobf6e7bb2018-08-14 22:27:29 -0400430func (handler *APIHandler) CreateDevice(ctx context.Context, device *voltha.Device) (*voltha.Device, error) {
Thomas Lee S51b5cb82019-10-14 14:49:34 +0530431 if device.MacAddress == "" && device.GetHostAndPort() == "" {
432 log.Errorf("No Device Info Present")
433 return nil, errors.New("No Device Info Present; MAC or HOSTIP&PORT")
434 }
435 log.Debugw("create-device", log.Fields{"device": *device})
khenaidoobf6e7bb2018-08-14 22:27:29 -0400436 if isTestMode(ctx) {
437 return &voltha.Device{Id: device.Id}, nil
438 }
Richard Jankowskid42826e2018-11-02 16:06:37 -0400439
khenaidoo9cdc1a62019-01-24 21:57:40 -0500440 if handler.competeForTransaction() {
khenaidoo631fe542019-05-31 15:44:43 -0400441 // There are no device Id present in this function.
khenaidoo09771ef2019-10-11 14:25:02 -0400442 if txn, err := handler.takeRequestOwnership(ctx, nil); err != nil {
Richard Jankowski2755adf2019-01-17 17:16:48 -0500443 return &voltha.Device{}, err
Richard Jankowski2755adf2019-01-17 17:16:48 -0500444 } else {
khenaidoo9cdc1a62019-01-24 21:57:40 -0500445 defer txn.Close()
Richard Jankowski2755adf2019-01-17 17:16:48 -0500446 }
447 }
khenaidoo9cdc1a62019-01-24 21:57:40 -0500448
khenaidoob9203542018-09-17 22:56:37 -0400449 ch := make(chan interface{})
450 defer close(ch)
451 go handler.deviceMgr.createDevice(ctx, device, ch)
452 select {
453 case res := <-ch:
khenaidoo92e62c52018-10-03 14:02:54 -0400454 if res != nil {
455 if err, ok := res.(error); ok {
456 return &voltha.Device{}, err
457 }
458 if d, ok := res.(*voltha.Device); ok {
khenaidoo2c6a0992019-04-29 13:46:56 -0400459 handler.core.deviceOwnership.OwnedByMe(&utils.DeviceID{Id: d.Id})
khenaidoo92e62c52018-10-03 14:02:54 -0400460 return d, nil
461 }
khenaidoob9203542018-09-17 22:56:37 -0400462 }
khenaidoo92e62c52018-10-03 14:02:54 -0400463 log.Warnw("create-device-unexpected-return-type", log.Fields{"result": res})
464 err := status.Errorf(codes.Internal, "%s", res)
465 return &voltha.Device{}, err
khenaidoob9203542018-09-17 22:56:37 -0400466 case <-ctx.Done():
467 log.Debug("createdevice-client-timeout")
468 return nil, ctx.Err()
469 }
khenaidoobf6e7bb2018-08-14 22:27:29 -0400470}
471
khenaidoo4d4802d2018-10-04 21:59:49 -0400472// EnableDevice activates a device by invoking the adopt_device API on the appropriate adapter
khenaidoobf6e7bb2018-08-14 22:27:29 -0400473func (handler *APIHandler) EnableDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
khenaidoob9203542018-09-17 22:56:37 -0400474 log.Debugw("enabledevice", log.Fields{"id": id})
khenaidoobf6e7bb2018-08-14 22:27:29 -0400475 if isTestMode(ctx) {
khenaidoo4d4802d2018-10-04 21:59:49 -0400476 return new(empty.Empty), nil
khenaidoobf6e7bb2018-08-14 22:27:29 -0400477 }
Richard Jankowskid42826e2018-11-02 16:06:37 -0400478
khenaidoo9cdc1a62019-01-24 21:57:40 -0500479 if handler.competeForTransaction() {
khenaidoo2c6a0992019-04-29 13:46:56 -0400480 if txn, err := handler.takeRequestOwnership(ctx, &utils.DeviceID{Id: id.Id}, handler.longRunningRequestTimeout); err != nil {
Richard Jankowski2755adf2019-01-17 17:16:48 -0500481 return new(empty.Empty), err
Richard Jankowski2755adf2019-01-17 17:16:48 -0500482 } else {
khenaidoo9cdc1a62019-01-24 21:57:40 -0500483 defer txn.Close()
Richard Jankowski2755adf2019-01-17 17:16:48 -0500484 }
485 }
khenaidoo9cdc1a62019-01-24 21:57:40 -0500486
khenaidoob9203542018-09-17 22:56:37 -0400487 ch := make(chan interface{})
488 defer close(ch)
489 go handler.deviceMgr.enableDevice(ctx, id, ch)
khenaidoo4d4802d2018-10-04 21:59:49 -0400490 return waitForNilResponseOnSuccess(ctx, ch)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400491}
492
khenaidoo4d4802d2018-10-04 21:59:49 -0400493// DisableDevice disables a device along with any child device it may have
khenaidoobf6e7bb2018-08-14 22:27:29 -0400494func (handler *APIHandler) DisableDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
495 log.Debugw("disabledevice-request", log.Fields{"id": id})
496 if isTestMode(ctx) {
khenaidoo4d4802d2018-10-04 21:59:49 -0400497 return new(empty.Empty), nil
khenaidoobf6e7bb2018-08-14 22:27:29 -0400498 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500499
khenaidoo9cdc1a62019-01-24 21:57:40 -0500500 if handler.competeForTransaction() {
khenaidoo2c6a0992019-04-29 13:46:56 -0400501 if txn, err := handler.takeRequestOwnership(ctx, &utils.DeviceID{Id: id.Id}); err != nil {
Richard Jankowski2755adf2019-01-17 17:16:48 -0500502 return new(empty.Empty), err
Richard Jankowski2755adf2019-01-17 17:16:48 -0500503 } else {
khenaidoo9cdc1a62019-01-24 21:57:40 -0500504 defer txn.Close()
Richard Jankowski2755adf2019-01-17 17:16:48 -0500505 }
506 }
khenaidoo9cdc1a62019-01-24 21:57:40 -0500507
khenaidoo92e62c52018-10-03 14:02:54 -0400508 ch := make(chan interface{})
509 defer close(ch)
510 go handler.deviceMgr.disableDevice(ctx, id, ch)
khenaidoo4d4802d2018-10-04 21:59:49 -0400511 return waitForNilResponseOnSuccess(ctx, ch)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400512}
513
khenaidoo4d4802d2018-10-04 21:59:49 -0400514//RebootDevice invoked the reboot API to the corresponding adapter
khenaidoobf6e7bb2018-08-14 22:27:29 -0400515func (handler *APIHandler) RebootDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
khenaidoo4d4802d2018-10-04 21:59:49 -0400516 log.Debugw("rebootDevice-request", log.Fields{"id": id})
khenaidoobf6e7bb2018-08-14 22:27:29 -0400517 if isTestMode(ctx) {
khenaidoo4d4802d2018-10-04 21:59:49 -0400518 return new(empty.Empty), nil
khenaidoobf6e7bb2018-08-14 22:27:29 -0400519 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500520
khenaidoo9cdc1a62019-01-24 21:57:40 -0500521 if handler.competeForTransaction() {
khenaidoo2c6a0992019-04-29 13:46:56 -0400522 if txn, err := handler.takeRequestOwnership(ctx, &utils.DeviceID{Id: id.Id}); err != nil {
Richard Jankowski2755adf2019-01-17 17:16:48 -0500523 return new(empty.Empty), err
Richard Jankowski2755adf2019-01-17 17:16:48 -0500524 } else {
khenaidoo9cdc1a62019-01-24 21:57:40 -0500525 defer txn.Close()
Richard Jankowski2755adf2019-01-17 17:16:48 -0500526 }
527 }
khenaidoo9cdc1a62019-01-24 21:57:40 -0500528
khenaidoo4d4802d2018-10-04 21:59:49 -0400529 ch := make(chan interface{})
530 defer close(ch)
531 go handler.deviceMgr.rebootDevice(ctx, id, ch)
532 return waitForNilResponseOnSuccess(ctx, ch)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400533}
534
khenaidoo4d4802d2018-10-04 21:59:49 -0400535// DeleteDevice removes a device from the data model
khenaidoobf6e7bb2018-08-14 22:27:29 -0400536func (handler *APIHandler) DeleteDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
537 log.Debugw("deletedevice-request", log.Fields{"id": id})
538 if isTestMode(ctx) {
khenaidoo4d4802d2018-10-04 21:59:49 -0400539 return new(empty.Empty), nil
khenaidoobf6e7bb2018-08-14 22:27:29 -0400540 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500541
khenaidoo9cdc1a62019-01-24 21:57:40 -0500542 if handler.competeForTransaction() {
khenaidoo6d62c002019-05-15 21:57:03 -0400543 if txn, err := handler.takeRequestOwnership(ctx, &utils.DeviceID{Id: id.Id}); err != nil {
khenaidoo09771ef2019-10-11 14:25:02 -0400544 if err == errorTransactionNotAcquired {
545 if ownedByMe, err := handler.core.deviceOwnership.OwnedByMe(&utils.DeviceID{Id: id.Id}); !ownedByMe && err == nil {
546 // Remove the device in memory
547 handler.deviceMgr.stopManagingDevice(id.Id)
548 }
khenaidoo6d62c002019-05-15 21:57:03 -0400549 }
Richard Jankowski2755adf2019-01-17 17:16:48 -0500550 return new(empty.Empty), err
Richard Jankowski2755adf2019-01-17 17:16:48 -0500551 } else {
khenaidoo9cdc1a62019-01-24 21:57:40 -0500552 defer txn.Close()
Richard Jankowski2755adf2019-01-17 17:16:48 -0500553 }
554 }
khenaidoo9cdc1a62019-01-24 21:57:40 -0500555
khenaidoo4d4802d2018-10-04 21:59:49 -0400556 ch := make(chan interface{})
557 defer close(ch)
558 go handler.deviceMgr.deleteDevice(ctx, id, ch)
559 return waitForNilResponseOnSuccess(ctx, ch)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400560}
561
khenaidoof5a5bfa2019-01-23 22:20:29 -0500562// processImageRequest is a helper method to execute an image download request
563func (handler *APIHandler) processImageRequest(ctx context.Context, img *voltha.ImageDownload, requestType int) (*common.OperationResp, error) {
564 log.Debugw("processImageDownload", log.Fields{"img": *img, "requestType": requestType})
565 if isTestMode(ctx) {
566 resp := &common.OperationResp{Code: common.OperationResp_OPERATION_SUCCESS}
567 return resp, nil
568 }
569
khenaidoo9cdc1a62019-01-24 21:57:40 -0500570 if handler.competeForTransaction() {
khenaidoo2c6a0992019-04-29 13:46:56 -0400571 if txn, err := handler.takeRequestOwnership(ctx, &utils.DeviceID{Id: img.Id}); err != nil {
khenaidoo9cdc1a62019-01-24 21:57:40 -0500572 return &common.OperationResp{}, err
573 } else {
574 defer txn.Close()
575 }
khenaidoof5a5bfa2019-01-23 22:20:29 -0500576 }
577
khenaidoo2c6a0992019-04-29 13:46:56 -0400578 failedresponse := &common.OperationResp{Code: voltha.OperationResp_OPERATION_FAILURE}
khenaidoof5a5bfa2019-01-23 22:20:29 -0500579
580 ch := make(chan interface{})
581 defer close(ch)
582 switch requestType {
583 case IMAGE_DOWNLOAD:
584 go handler.deviceMgr.downloadImage(ctx, img, ch)
585 case CANCEL_IMAGE_DOWNLOAD:
586 go handler.deviceMgr.cancelImageDownload(ctx, img, ch)
587 case ACTIVATE_IMAGE:
588 go handler.deviceMgr.activateImage(ctx, img, ch)
589 case REVERT_IMAGE:
590 go handler.deviceMgr.revertImage(ctx, img, ch)
591 default:
592 log.Warn("invalid-request-type", log.Fields{"requestType": requestType})
593 return failedresponse, status.Errorf(codes.InvalidArgument, "%d", requestType)
594 }
595 select {
596 case res := <-ch:
597 if res != nil {
598 if err, ok := res.(error); ok {
599 return failedresponse, err
600 }
601 if opResp, ok := res.(*common.OperationResp); ok {
602 return opResp, nil
603 }
604 }
605 log.Warnw("download-image-unexpected-return-type", log.Fields{"result": res})
606 return failedresponse, status.Errorf(codes.Internal, "%s", res)
607 case <-ctx.Done():
608 log.Debug("downloadImage-client-timeout")
609 return nil, ctx.Err()
610 }
611}
612
khenaidoobf6e7bb2018-08-14 22:27:29 -0400613func (handler *APIHandler) DownloadImage(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
614 log.Debugw("DownloadImage-request", log.Fields{"img": *img})
615 if isTestMode(ctx) {
616 resp := &common.OperationResp{Code: common.OperationResp_OPERATION_SUCCESS}
617 return resp, nil
618 }
619
khenaidoof5a5bfa2019-01-23 22:20:29 -0500620 return handler.processImageRequest(ctx, img, IMAGE_DOWNLOAD)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400621}
622
623func (handler *APIHandler) CancelImageDownload(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
khenaidoof5a5bfa2019-01-23 22:20:29 -0500624 log.Debugw("cancelImageDownload-request", log.Fields{"img": *img})
khenaidoobf6e7bb2018-08-14 22:27:29 -0400625 if isTestMode(ctx) {
626 resp := &common.OperationResp{Code: common.OperationResp_OPERATION_SUCCESS}
627 return resp, nil
628 }
khenaidoof5a5bfa2019-01-23 22:20:29 -0500629 return handler.processImageRequest(ctx, img, CANCEL_IMAGE_DOWNLOAD)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400630}
631
632func (handler *APIHandler) ActivateImageUpdate(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
khenaidoof5a5bfa2019-01-23 22:20:29 -0500633 log.Debugw("activateImageUpdate-request", log.Fields{"img": *img})
khenaidoobf6e7bb2018-08-14 22:27:29 -0400634 if isTestMode(ctx) {
635 resp := &common.OperationResp{Code: common.OperationResp_OPERATION_SUCCESS}
636 return resp, nil
637 }
khenaidoof5a5bfa2019-01-23 22:20:29 -0500638
639 return handler.processImageRequest(ctx, img, ACTIVATE_IMAGE)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400640}
641
642func (handler *APIHandler) RevertImageUpdate(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
khenaidoof5a5bfa2019-01-23 22:20:29 -0500643 log.Debugw("revertImageUpdate-request", log.Fields{"img": *img})
khenaidoobf6e7bb2018-08-14 22:27:29 -0400644 if isTestMode(ctx) {
645 resp := &common.OperationResp{Code: common.OperationResp_OPERATION_SUCCESS}
646 return resp, nil
647 }
khenaidoof5a5bfa2019-01-23 22:20:29 -0500648
649 return handler.processImageRequest(ctx, img, REVERT_IMAGE)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400650}
651
khenaidoof5a5bfa2019-01-23 22:20:29 -0500652func (handler *APIHandler) GetImageDownloadStatus(ctx context.Context, img *voltha.ImageDownload) (*voltha.ImageDownload, error) {
653 log.Debugw("getImageDownloadStatus-request", log.Fields{"img": *img})
654 if isTestMode(ctx) {
Stephane Barbariedf5479f2019-01-29 22:13:00 -0500655 resp := &voltha.ImageDownload{DownloadState: voltha.ImageDownload_DOWNLOAD_SUCCEEDED}
khenaidoof5a5bfa2019-01-23 22:20:29 -0500656 return resp, nil
657 }
658
Stephane Barbariedf5479f2019-01-29 22:13:00 -0500659 failedresponse := &voltha.ImageDownload{DownloadState: voltha.ImageDownload_DOWNLOAD_UNKNOWN}
khenaidoof5a5bfa2019-01-23 22:20:29 -0500660
khenaidoo9cdc1a62019-01-24 21:57:40 -0500661 if handler.competeForTransaction() {
khenaidoo2c6a0992019-04-29 13:46:56 -0400662 if txn, err := handler.takeRequestOwnership(ctx, &utils.DeviceID{Id: img.Id}); err != nil {
khenaidoo9cdc1a62019-01-24 21:57:40 -0500663 return failedresponse, err
664 } else {
665 defer txn.Close()
666 }
khenaidoof5a5bfa2019-01-23 22:20:29 -0500667 }
668
669 ch := make(chan interface{})
670 defer close(ch)
671 go handler.deviceMgr.getImageDownloadStatus(ctx, img, ch)
672
673 select {
674 case res := <-ch:
675 if res != nil {
676 if err, ok := res.(error); ok {
677 return failedresponse, err
678 }
679 if downloadResp, ok := res.(*voltha.ImageDownload); ok {
680 return downloadResp, nil
681 }
682 }
683 log.Warnw("download-image-status", log.Fields{"result": res})
684 return failedresponse, status.Errorf(codes.Internal, "%s", res)
685 case <-ctx.Done():
686 log.Debug("downloadImage-client-timeout")
687 return failedresponse, ctx.Err()
688 }
689}
690
691func (handler *APIHandler) GetImageDownload(ctx context.Context, img *voltha.ImageDownload) (*voltha.ImageDownload, error) {
692 log.Debugw("GetImageDownload-request", log.Fields{"img": *img})
693 if isTestMode(ctx) {
Stephane Barbariedf5479f2019-01-29 22:13:00 -0500694 resp := &voltha.ImageDownload{DownloadState: voltha.ImageDownload_DOWNLOAD_SUCCEEDED}
khenaidoof5a5bfa2019-01-23 22:20:29 -0500695 return resp, nil
696 }
697
698 if download, err := handler.deviceMgr.getImageDownload(ctx, img); err != nil {
Stephane Barbariedf5479f2019-01-29 22:13:00 -0500699 return &voltha.ImageDownload{DownloadState: voltha.ImageDownload_DOWNLOAD_UNKNOWN}, err
khenaidoof5a5bfa2019-01-23 22:20:29 -0500700 } else {
701 return download, nil
702 }
703}
704
705func (handler *APIHandler) ListImageDownloads(ctx context.Context, id *voltha.ID) (*voltha.ImageDownloads, error) {
706 log.Debugw("ListImageDownloads-request", log.Fields{"deviceId": id.Id})
707 if isTestMode(ctx) {
khenaidoo2c6a0992019-04-29 13:46:56 -0400708 resp := &voltha.ImageDownloads{Items: []*voltha.ImageDownload{}}
khenaidoof5a5bfa2019-01-23 22:20:29 -0500709 return resp, nil
710 }
711
712 if downloads, err := handler.deviceMgr.listImageDownloads(ctx, id.Id); err != nil {
713 failedResp := &voltha.ImageDownloads{
khenaidoo2c6a0992019-04-29 13:46:56 -0400714 Items: []*voltha.ImageDownload{
715 {DownloadState: voltha.ImageDownload_DOWNLOAD_UNKNOWN},
716 },
khenaidoof5a5bfa2019-01-23 22:20:29 -0500717 }
718 return failedResp, err
719 } else {
720 return downloads, nil
721 }
722}
723
khenaidoobf6e7bb2018-08-14 22:27:29 -0400724func (handler *APIHandler) UpdateDevicePmConfigs(ctx context.Context, configs *voltha.PmConfigs) (*empty.Empty, error) {
725 log.Debugw("UpdateDevicePmConfigs-request", log.Fields{"configs": *configs})
726 if isTestMode(ctx) {
727 out := new(empty.Empty)
728 return out, nil
729 }
khenaidoob3127472019-07-24 21:04:55 -0400730 if handler.competeForTransaction() {
731 if txn, err := handler.takeRequestOwnership(ctx, &utils.DeviceID{Id: configs.Id}); err != nil {
732 return new(empty.Empty), err
733 } else {
734 defer txn.Close()
735 }
736 }
737
738 ch := make(chan interface{})
739 defer close(ch)
740 go handler.deviceMgr.updatePmConfigs(ctx, configs, ch)
741 return waitForNilResponseOnSuccess(ctx, ch)
742}
743
744func (handler *APIHandler) ListDevicePmConfigs(ctx context.Context, id *voltha.ID) (*voltha.PmConfigs, error) {
745 log.Debugw("ListDevicePmConfigs-request", log.Fields{"deviceId": *id})
746 if handler.competeForTransaction() {
747 if txn, err := handler.takeRequestOwnership(ctx, &utils.LogicalDeviceID{Id: id.Id}); err != nil {
748 return &voltha.PmConfigs{}, err
749 } else {
750 defer txn.Close()
751 }
752 }
753 return handler.deviceMgr.listPmConfigs(ctx, id.Id)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400754}
755
756func (handler *APIHandler) CreateAlarmFilter(ctx context.Context, filter *voltha.AlarmFilter) (*voltha.AlarmFilter, error) {
757 log.Debugw("CreateAlarmFilter-request", log.Fields{"filter": *filter})
758 if isTestMode(ctx) {
759 f := &voltha.AlarmFilter{Id: filter.Id}
760 return f, nil
761 }
762 return nil, errors.New("UnImplemented")
763}
764
765func (handler *APIHandler) UpdateAlarmFilter(ctx context.Context, filter *voltha.AlarmFilter) (*voltha.AlarmFilter, error) {
766 log.Debugw("UpdateAlarmFilter-request", log.Fields{"filter": *filter})
767 if isTestMode(ctx) {
768 f := &voltha.AlarmFilter{Id: filter.Id}
769 return f, nil
770 }
771 return nil, errors.New("UnImplemented")
772}
773
774func (handler *APIHandler) DeleteAlarmFilter(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
775 log.Debugw("DeleteAlarmFilter-request", log.Fields{"id": *id})
776 if isTestMode(ctx) {
777 out := new(empty.Empty)
778 return out, nil
779 }
780 return nil, errors.New("UnImplemented")
781}
782
783func (handler *APIHandler) SelfTest(ctx context.Context, id *voltha.ID) (*voltha.SelfTestResponse, error) {
784 log.Debugw("SelfTest-request", log.Fields{"id": id})
785 if isTestMode(ctx) {
786 resp := &voltha.SelfTestResponse{Result: voltha.SelfTestResponse_SUCCESS}
787 return resp, nil
788 }
789 return nil, errors.New("UnImplemented")
790}
Stephane Barbarie6e1bd502018-11-05 22:44:45 -0500791
792func (handler *APIHandler) forwardPacketOut(packet *openflow_13.PacketOut) {
793 log.Debugw("forwardPacketOut-request", log.Fields{"packet": packet})
khenaidoo3d3b8c22019-05-22 18:10:39 -0400794 //TODO: Update this logic once the OF Controller (OFAgent in this case) can include a transaction Id in its
795 // request. For performance reason we can let both Cores in a Core-Pair forward the Packet to the adapters and
796 // let once of the shim layer (kafka proxy or adapter request handler filters out the duplicate packet)
khenaidoo09771ef2019-10-11 14:25:02 -0400797 if ownedByMe, err := handler.core.deviceOwnership.OwnedByMe(&utils.LogicalDeviceID{Id: packet.Id}); ownedByMe && err == nil {
khenaidoo3d3b8c22019-05-22 18:10:39 -0400798 agent := handler.logicalDeviceMgr.getLogicalDeviceAgent(packet.Id)
799 agent.packetOut(packet.PacketOut)
800 }
Stephane Barbarie6e1bd502018-11-05 22:44:45 -0500801}
khenaidoo3d3b8c22019-05-22 18:10:39 -0400802
Stephane Barbarie6e1bd502018-11-05 22:44:45 -0500803func (handler *APIHandler) StreamPacketsOut(
804 packets voltha.VolthaService_StreamPacketsOutServer,
805) error {
806 log.Debugw("StreamPacketsOut-request", log.Fields{"packets": packets})
khenaidoo5e250692019-08-30 14:46:21 -0400807loop:
Stephane Barbarie6e1bd502018-11-05 22:44:45 -0500808 for {
khenaidoo5e250692019-08-30 14:46:21 -0400809 select {
810 case <-packets.Context().Done():
811 log.Infow("StreamPacketsOut-context-done", log.Fields{"packets": packets, "error": packets.Context().Err()})
812 break loop
813 default:
814 }
815
Stephane Barbarie6e1bd502018-11-05 22:44:45 -0500816 packet, err := packets.Recv()
817
818 if err == io.EOF {
khenaidoo5e250692019-08-30 14:46:21 -0400819 log.Debugw("Received-EOF", log.Fields{"packets": packets})
820 break loop
821 }
822
823 if err != nil {
824 log.Errorw("Failed to receive packet out", log.Fields{"error": err})
825 continue
Stephane Barbarie6e1bd502018-11-05 22:44:45 -0500826 }
827
828 handler.forwardPacketOut(packet)
829 }
830
831 log.Debugw("StreamPacketsOut-request-done", log.Fields{"packets": packets})
832 return nil
833}
834
khenaidoo297cd252019-02-07 22:10:23 -0500835func (handler *APIHandler) sendPacketIn(deviceId string, transationId string, packet *openflow_13.OfpPacketIn) {
836 // TODO: Augment the OF PacketIn to include the transactionId
Stephane Barbarie6e1bd502018-11-05 22:44:45 -0500837 packetIn := openflow_13.PacketIn{Id: deviceId, PacketIn: packet}
838 log.Debugw("sendPacketIn", log.Fields{"packetIn": packetIn})
A R Karthick881e7ea2019-08-19 19:44:02 +0000839 handler.packetInQueue <- packetIn
840}
841
842type callTracker struct {
843 failedPacket interface{}
844}
845type streamTracker struct {
846 calls map[string]*callTracker
847 sync.Mutex
848}
849
850var streamingTracker = &streamTracker{calls: make(map[string]*callTracker)}
851
852func (handler *APIHandler) getStreamingTracker(method string, done chan<- bool) *callTracker {
853 streamingTracker.Lock()
854 defer streamingTracker.Unlock()
855 if _, ok := streamingTracker.calls[method]; ok {
856 // bail out the other packet in thread
857 log.Debugf("%s streaming call already running. Exiting it", method)
858 done <- true
859 log.Debugf("Last %s exited. Continuing ...", method)
860 } else {
861 streamingTracker.calls[method] = &callTracker{failedPacket: nil}
Richard Jankowskidbab94a2018-12-06 16:20:25 -0500862 }
A R Karthick881e7ea2019-08-19 19:44:02 +0000863 return streamingTracker.calls[method]
864}
865
866func (handler *APIHandler) flushFailedPackets(tracker *callTracker) error {
867 if tracker.failedPacket != nil {
868 switch tracker.failedPacket.(type) {
869 case openflow_13.PacketIn:
870 log.Debug("Enqueueing last failed packetIn")
871 handler.packetInQueue <- tracker.failedPacket.(openflow_13.PacketIn)
872 case openflow_13.ChangeEvent:
873 log.Debug("Enqueueing last failed changeEvent")
874 handler.changeEventQueue <- tracker.failedPacket.(openflow_13.ChangeEvent)
875 }
876 }
877 return nil
Stephane Barbarie6e1bd502018-11-05 22:44:45 -0500878}
879
880func (handler *APIHandler) ReceivePacketsIn(
881 empty *empty.Empty,
882 packetsIn voltha.VolthaService_ReceivePacketsInServer,
883) error {
A R Karthick881e7ea2019-08-19 19:44:02 +0000884 var streamingTracker = handler.getStreamingTracker("ReceivePacketsIn", handler.packetInQueueDone)
Stephane Barbarie6e1bd502018-11-05 22:44:45 -0500885 log.Debugw("ReceivePacketsIn-request", log.Fields{"packetsIn": packetsIn})
886
A R Karthick881e7ea2019-08-19 19:44:02 +0000887 handler.flushFailedPackets(streamingTracker)
888
889loop:
Stephane Barbarie6e1bd502018-11-05 22:44:45 -0500890 for {
A R Karthick881e7ea2019-08-19 19:44:02 +0000891 select {
892 case packet := <-handler.packetInQueue:
893 log.Debugw("sending-packet-in", log.Fields{"packet": packet})
894 if err := packetsIn.Send(&packet); err != nil {
895 log.Errorw("failed-to-send-packet", log.Fields{"error": err})
896 // save the last failed packet in
897 streamingTracker.failedPacket = packet
898 } else {
899 if streamingTracker.failedPacket != nil {
900 // reset last failed packet saved to avoid flush
901 streamingTracker.failedPacket = nil
Richard Jankowskidbab94a2018-12-06 16:20:25 -0500902 }
903 }
A R Karthick881e7ea2019-08-19 19:44:02 +0000904 case <-handler.packetInQueueDone:
905 log.Debug("Another ReceivePacketsIn running. Bailing out ...")
906 break loop
Stephane Barbarie6e1bd502018-11-05 22:44:45 -0500907 }
908 }
A R Karthick881e7ea2019-08-19 19:44:02 +0000909
910 //TODO: Find an elegant way to get out of the above loop when the Core is stopped
911 return nil
Stephane Barbarie6e1bd502018-11-05 22:44:45 -0500912}
913
914func (handler *APIHandler) sendChangeEvent(deviceId string, portStatus *openflow_13.OfpPortStatus) {
915 // TODO: validate the type of portStatus parameter
916 //if _, ok := portStatus.(*openflow_13.OfpPortStatus); ok {
917 //}
918 event := openflow_13.ChangeEvent{Id: deviceId, Event: &openflow_13.ChangeEvent_PortStatus{PortStatus: portStatus}}
919 log.Debugw("sendChangeEvent", log.Fields{"event": event})
A R Karthick881e7ea2019-08-19 19:44:02 +0000920 handler.changeEventQueue <- event
Stephane Barbarie6e1bd502018-11-05 22:44:45 -0500921}
922
923func (handler *APIHandler) ReceiveChangeEvents(
924 empty *empty.Empty,
925 changeEvents voltha.VolthaService_ReceiveChangeEventsServer,
926) error {
A R Karthick881e7ea2019-08-19 19:44:02 +0000927 var streamingTracker = handler.getStreamingTracker("ReceiveChangeEvents", handler.changeEventQueueDone)
Stephane Barbarie6e1bd502018-11-05 22:44:45 -0500928 log.Debugw("ReceiveChangeEvents-request", log.Fields{"changeEvents": changeEvents})
A R Karthick881e7ea2019-08-19 19:44:02 +0000929
930 handler.flushFailedPackets(streamingTracker)
931
932loop:
Stephane Barbarie6e1bd502018-11-05 22:44:45 -0500933 for {
A R Karthick881e7ea2019-08-19 19:44:02 +0000934 select {
Richard Jankowski199fd862019-03-18 14:49:51 -0400935 // Dequeue a change event
A R Karthick881e7ea2019-08-19 19:44:02 +0000936 case event := <-handler.changeEventQueue:
937 log.Debugw("sending-change-event", log.Fields{"event": event})
938 if err := changeEvents.Send(&event); err != nil {
939 log.Errorw("failed-to-send-change-event", log.Fields{"error": err})
940 // save last failed changeevent
941 streamingTracker.failedPacket = event
942 } else {
943 if streamingTracker.failedPacket != nil {
944 // reset last failed event saved on success to avoid flushing
945 streamingTracker.failedPacket = nil
Richard Jankowski199fd862019-03-18 14:49:51 -0400946 }
947 }
A R Karthick881e7ea2019-08-19 19:44:02 +0000948 case <-handler.changeEventQueueDone:
949 log.Debug("Another ReceiveChangeEvents already running. Bailing out ...")
950 break loop
Stephane Barbarie6e1bd502018-11-05 22:44:45 -0500951 }
952 }
A R Karthick881e7ea2019-08-19 19:44:02 +0000953
954 return nil
Richard Jankowski199fd862019-03-18 14:49:51 -0400955}
Stephane Barbarie6e1bd502018-11-05 22:44:45 -0500956
957func (handler *APIHandler) Subscribe(
958 ctx context.Context,
959 ofAgent *voltha.OfAgentSubscriber,
960) (*voltha.OfAgentSubscriber, error) {
961 log.Debugw("Subscribe-request", log.Fields{"ofAgent": ofAgent})
962 return &voltha.OfAgentSubscriber{OfagentId: ofAgent.OfagentId, VolthaId: ofAgent.VolthaId}, nil
963}
William Kurkiandaa6bb22019-03-07 12:26:28 -0500964
965//@TODO useless stub, what should this actually do?
966func (handler *APIHandler) GetAlarmDeviceData(
967 ctx context.Context,
968 in *common.ID,
969) (*omci.AlarmDeviceData, error) {
970 log.Debug("GetAlarmDeviceData-stub")
971 return nil, nil
972}
973
Manikkaraj kb1a10922019-07-29 12:10:34 -0400974func (handler *APIHandler) ListLogicalDeviceMeters(ctx context.Context, id *voltha.ID) (*openflow_13.Meters, error) {
975
976 log.Debugw("ListLogicalDeviceMeters", log.Fields{"id": *id})
977 if handler.competeForTransaction() {
978 if txn, err := handler.takeRequestOwnership(ctx, &utils.LogicalDeviceID{Id: id.Id}); err != nil {
979 return nil, err // TODO: Return empty meter entry
980 } else {
981 defer txn.Close()
982 }
983 }
984 return handler.logicalDeviceMgr.ListLogicalDeviceMeters(ctx, id.Id)
William Kurkiandaa6bb22019-03-07 12:26:28 -0500985}
986
987//@TODO useless stub, what should this actually do?
988func (handler *APIHandler) GetMibDeviceData(
khenaidoo2c6a0992019-04-29 13:46:56 -0400989 ctx context.Context,
990 in *common.ID,
William Kurkiandaa6bb22019-03-07 12:26:28 -0500991) (*omci.MibDeviceData, error) {
992 log.Debug("GetMibDeviceData-stub")
993 return nil, nil
994}
995
William Kurkiandaa6bb22019-03-07 12:26:28 -0500996func (handler *APIHandler) SimulateAlarm(
997 ctx context.Context,
998 in *voltha.SimulateAlarmRequest,
999) (*common.OperationResp, error) {
serkant.uluderya334479d2019-04-10 08:26:15 -07001000 log.Debugw("SimulateAlarm-request", log.Fields{"id": in.Id})
1001 successResp := &common.OperationResp{Code: common.OperationResp_OPERATION_SUCCESS}
1002 if isTestMode(ctx) {
1003 return successResp, nil
1004 }
1005
1006 if handler.competeForTransaction() {
Kent Hagerman0ab4cb22019-04-24 13:13:35 -04001007 if txn, err := handler.takeRequestOwnership(ctx, &utils.DeviceID{Id: in.Id}, handler.longRunningRequestTimeout); err != nil {
1008 failedresponse := &common.OperationResp{Code: voltha.OperationResp_OPERATION_FAILURE}
serkant.uluderya334479d2019-04-10 08:26:15 -07001009 return failedresponse, err
1010 } else {
1011 defer txn.Close()
1012 }
1013 }
1014
1015 ch := make(chan interface{})
1016 defer close(ch)
1017 go handler.deviceMgr.simulateAlarm(ctx, in, ch)
1018 return successResp, nil
William Kurkiandaa6bb22019-03-07 12:26:28 -05001019}
1020
Manikkaraj kb1a10922019-07-29 12:10:34 -04001021// This function sends meter mod request to logical device manager and waits for response
1022func (handler *APIHandler) UpdateLogicalDeviceMeterTable(ctx context.Context, meter *openflow_13.MeterModUpdate) (*empty.Empty, error) {
1023 log.Debugw("UpdateLogicalDeviceMeterTable-request",
1024 log.Fields{"meter": meter, "test": common.TestModeKeys_api_test.String()})
1025 if isTestMode(ctx) {
1026 out := new(empty.Empty)
1027 return out, nil
1028 }
1029
1030 if handler.competeForTransaction() {
1031 if txn, err := handler.takeRequestOwnership(ctx, &utils.LogicalDeviceID{Id: meter.Id}); err != nil {
1032 return new(empty.Empty), err
1033 } else {
1034 defer txn.Close()
1035 }
1036 }
1037
1038 ch := make(chan interface{})
1039 defer close(ch)
1040 go handler.logicalDeviceMgr.updateMeterTable(ctx, meter.Id, meter.MeterMod, ch)
1041 return waitForNilResponseOnSuccess(ctx, ch)
William Kurkiandaa6bb22019-03-07 12:26:28 -05001042}