blob: 015c8a31d2543363c7f96f1adf28d63a2e08a542 [file] [log] [blame]
khenaidoob9203542018-09-17 22:56:37 -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 */
npujar1d86a522019-11-14 17:11:16 +053016
Kent Hagerman2b216042020-04-03 18:28:56 -040017package device
khenaidoob9203542018-09-17 22:56:37 -040018
19import (
20 "context"
21 "errors"
David Bainbridged1afd662020-03-26 18:27:41 -070022 "reflect"
23 "runtime"
24 "sync"
25 "time"
26
Kent Hagerman45a13e42020-04-13 12:23:50 -040027 "github.com/golang/protobuf/ptypes/empty"
sbarbari17d7e222019-11-05 10:02:29 -050028 "github.com/opencord/voltha-go/db/model"
Kent Hagerman2b216042020-04-03 18:28:56 -040029 "github.com/opencord/voltha-go/rw_core/core/adapter"
Kent Hagermanf5a67352020-04-30 15:15:26 -040030 "github.com/opencord/voltha-go/rw_core/core/device/event"
Kent Hagerman2b216042020-04-03 18:28:56 -040031 "github.com/opencord/voltha-go/rw_core/core/device/remote"
khenaidoo3d3b8c22019-05-22 18:10:39 -040032 "github.com/opencord/voltha-go/rw_core/utils"
serkant.uluderya2ae470f2020-01-21 11:13:09 -080033 "github.com/opencord/voltha-lib-go/v3/pkg/kafka"
34 "github.com/opencord/voltha-lib-go/v3/pkg/log"
Kent Hagerman45a13e42020-04-13 12:23:50 -040035 "github.com/opencord/voltha-protos/v3/go/common"
serkant.uluderya2ae470f2020-01-21 11:13:09 -080036 ic "github.com/opencord/voltha-protos/v3/go/inter_container"
Mahir Gunyel03de0d32020-06-03 01:36:59 -070037 "github.com/opencord/voltha-protos/v3/go/openflow_13"
serkant.uluderya2ae470f2020-01-21 11:13:09 -080038 ofp "github.com/opencord/voltha-protos/v3/go/openflow_13"
39 "github.com/opencord/voltha-protos/v3/go/voltha"
khenaidoob9203542018-09-17 22:56:37 -040040 "google.golang.org/grpc/codes"
41 "google.golang.org/grpc/status"
khenaidoob9203542018-09-17 22:56:37 -040042)
43
Kent Hagerman2b216042020-04-03 18:28:56 -040044// Manager represent device manager attributes
45type Manager struct {
khenaidoo4c9e5592019-09-09 16:20:41 -040046 deviceAgents sync.Map
47 rootDevices map[string]bool
48 lockRootDeviceMap sync.RWMutex
Kent Hagerman2b216042020-04-03 18:28:56 -040049 adapterProxy *remote.AdapterProxy
50 adapterMgr *adapter.Manager
51 logicalDeviceMgr *LogicalManager
npujar467fe752020-01-16 20:17:45 +053052 kafkaICProxy kafka.InterContainerProxy
khenaidoo4c9e5592019-09-09 16:20:41 -040053 stateTransitions *TransitionMap
Mahir Gunyel03de0d32020-06-03 01:36:59 -070054 dbPath *model.Path
Kent Hagermanf5a67352020-04-30 15:15:26 -040055 dProxy *model.Proxy
npujar1d86a522019-11-14 17:11:16 +053056 coreInstanceID string
khenaidoo442e7c72020-03-10 16:13:48 -040057 defaultTimeout time.Duration
khenaidoo4c9e5592019-09-09 16:20:41 -040058 devicesLoadingLock sync.RWMutex
59 deviceLoadingInProgress map[string][]chan int
khenaidoob9203542018-09-17 22:56:37 -040060}
61
Mahir Gunyel03de0d32020-06-03 01:36:59 -070062//NewManagers creates the Manager and the Logical Manager.
serkant.uluderya8ff291d2020-05-20 00:58:00 -070063func NewManagers(dbPath *model.Path, adapterMgr *adapter.Manager, kmp kafka.InterContainerProxy, endpointMgr kafka.EndpointManager, coreTopic, coreInstanceID string, defaultCoreTimeout time.Duration) (*Manager, *LogicalManager) {
Kent Hagerman2b216042020-04-03 18:28:56 -040064 deviceMgr := &Manager{
Kent Hagerman2b216042020-04-03 18:28:56 -040065 rootDevices: make(map[string]bool),
66 kafkaICProxy: kmp,
serkant.uluderya8ff291d2020-05-20 00:58:00 -070067 adapterProxy: remote.NewAdapterProxy(kmp, coreTopic, endpointMgr),
Kent Hagerman2b216042020-04-03 18:28:56 -040068 coreInstanceID: coreInstanceID,
Mahir Gunyel03de0d32020-06-03 01:36:59 -070069 dbPath: dbPath,
70 dProxy: dbPath.Proxy("devices"),
Kent Hagerman2b216042020-04-03 18:28:56 -040071 adapterMgr: adapterMgr,
Kent Hagermanf4151de2020-06-19 15:58:47 -040072 defaultTimeout: defaultCoreTimeout,
Kent Hagerman2b216042020-04-03 18:28:56 -040073 deviceLoadingInProgress: make(map[string][]chan int),
74 }
Kent Hagerman2f0d0552020-04-23 17:28:52 -040075 deviceMgr.stateTransitions = NewTransitionMap(deviceMgr)
76
Kent Hagerman2b216042020-04-03 18:28:56 -040077 logicalDeviceMgr := &LogicalManager{
Kent Hagerman45a13e42020-04-13 12:23:50 -040078 Manager: event.NewManager(),
Kent Hagerman2b216042020-04-03 18:28:56 -040079 deviceMgr: deviceMgr,
80 kafkaICProxy: kmp,
Mahir Gunyel03de0d32020-06-03 01:36:59 -070081 dbPath: dbPath,
82 ldProxy: dbPath.Proxy("logical_devices"),
Kent Hagerman2b216042020-04-03 18:28:56 -040083 defaultTimeout: defaultCoreTimeout,
84 logicalDeviceLoadingInProgress: make(map[string][]chan int),
85 }
86 deviceMgr.logicalDeviceMgr = logicalDeviceMgr
Matteo Scandolod525ae32020-04-02 17:27:29 -070087
Kent Hagerman2b216042020-04-03 18:28:56 -040088 adapterMgr.SetAdapterRestartedCallback(deviceMgr.adapterRestarted)
Matteo Scandolod525ae32020-04-02 17:27:29 -070089
Kent Hagerman2b216042020-04-03 18:28:56 -040090 return deviceMgr, logicalDeviceMgr
khenaidoob9203542018-09-17 22:56:37 -040091}
92
Kent Hagerman2b216042020-04-03 18:28:56 -040093func (dMgr *Manager) addDeviceAgentToMap(agent *Agent) {
npujar1d86a522019-11-14 17:11:16 +053094 if _, exist := dMgr.deviceAgents.Load(agent.deviceID); !exist {
95 dMgr.deviceAgents.Store(agent.deviceID, agent)
khenaidoob9203542018-09-17 22:56:37 -040096 }
khenaidoo2c6a0992019-04-29 13:46:56 -040097 dMgr.lockRootDeviceMap.Lock()
98 defer dMgr.lockRootDeviceMap.Unlock()
npujar1d86a522019-11-14 17:11:16 +053099 dMgr.rootDevices[agent.deviceID] = agent.isRootdevice
khenaidoo2c6a0992019-04-29 13:46:56 -0400100
khenaidoob9203542018-09-17 22:56:37 -0400101}
102
Kent Hagerman2b216042020-04-03 18:28:56 -0400103func (dMgr *Manager) deleteDeviceAgentFromMap(agent *Agent) {
npujar1d86a522019-11-14 17:11:16 +0530104 dMgr.deviceAgents.Delete(agent.deviceID)
khenaidoo2c6a0992019-04-29 13:46:56 -0400105 dMgr.lockRootDeviceMap.Lock()
106 defer dMgr.lockRootDeviceMap.Unlock()
npujar1d86a522019-11-14 17:11:16 +0530107 delete(dMgr.rootDevices, agent.deviceID)
khenaidoo4d4802d2018-10-04 21:59:49 -0400108}
109
khenaidoo297cd252019-02-07 22:10:23 -0500110// getDeviceAgent returns the agent managing the device. If the device is not in memory, it will loads it, if it exists
Kent Hagerman2b216042020-04-03 18:28:56 -0400111func (dMgr *Manager) getDeviceAgent(ctx context.Context, deviceID string) *Agent {
npujar1d86a522019-11-14 17:11:16 +0530112 agent, ok := dMgr.deviceAgents.Load(deviceID)
113 if ok {
Kent Hagerman2b216042020-04-03 18:28:56 -0400114 return agent.(*Agent)
khenaidoob9203542018-09-17 22:56:37 -0400115 }
khenaidoo442e7c72020-03-10 16:13:48 -0400116 // Try to load into memory - loading will also create the device agent and set the device ownership
npujar467fe752020-01-16 20:17:45 +0530117 err := dMgr.load(ctx, deviceID)
npujar1d86a522019-11-14 17:11:16 +0530118 if err == nil {
119 agent, ok = dMgr.deviceAgents.Load(deviceID)
120 if !ok {
121 return nil
122 }
Kent Hagerman2b216042020-04-03 18:28:56 -0400123 return agent.(*Agent)
npujar1d86a522019-11-14 17:11:16 +0530124 }
125 //TODO: Change the return params to return an error as well
Rohan Agrawal31f21802020-06-12 05:38:46 +0000126 logger.Errorw(ctx, "loading-device-failed", log.Fields{"deviceId": deviceID, "error": err})
khenaidoob9203542018-09-17 22:56:37 -0400127 return nil
128}
129
khenaidoo297cd252019-02-07 22:10:23 -0500130// listDeviceIdsFromMap returns the list of device IDs that are in memory
Kent Hagerman2b216042020-04-03 18:28:56 -0400131func (dMgr *Manager) listDeviceIdsFromMap() *voltha.IDs {
khenaidoo7ccedd52018-12-14 16:48:54 -0500132 result := &voltha.IDs{Items: make([]*voltha.ID, 0)}
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400133
134 dMgr.deviceAgents.Range(func(key, value interface{}) bool {
135 result.Items = append(result.Items, &voltha.ID{Id: key.(string)})
136 return true
137 })
138
khenaidoo7ccedd52018-12-14 16:48:54 -0500139 return result
140}
141
Kent Hagerman45a13e42020-04-13 12:23:50 -0400142// CreateDevice creates a new parent device in the data model
143func (dMgr *Manager) CreateDevice(ctx context.Context, device *voltha.Device) (*voltha.Device, error) {
144 if device.MacAddress == "" && device.GetHostAndPort() == "" {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000145 logger.Errorf(ctx, "No Device Info Present")
Kent Hagerman45a13e42020-04-13 12:23:50 -0400146 return &voltha.Device{}, errors.New("no-device-info-present; MAC or HOSTIP&PORT")
147 }
Rohan Agrawal31f21802020-06-12 05:38:46 +0000148 logger.Debugw(ctx, "create-device", log.Fields{"device": *device})
Kent Hagerman45a13e42020-04-13 12:23:50 -0400149
npujar467fe752020-01-16 20:17:45 +0530150 deviceExist, err := dMgr.isParentDeviceExist(ctx, device)
Thomas Lee Se5a44012019-11-07 20:32:24 +0530151 if err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000152 logger.Errorf(ctx, "Failed to fetch parent device info")
Kent Hagerman45a13e42020-04-13 12:23:50 -0400153 return nil, err
Thomas Lee Se5a44012019-11-07 20:32:24 +0530154 }
155 if deviceExist {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000156 logger.Errorf(ctx, "Device is Pre-provisioned already with same IP-Port or MAC Address")
Kent Hagerman45a13e42020-04-13 12:23:50 -0400157 return nil, errors.New("device is already pre-provisioned")
Thomas Lee S51b5cb82019-10-14 14:49:34 +0530158 }
Rohan Agrawal31f21802020-06-12 05:38:46 +0000159 logger.Debugw(ctx, "CreateDevice", log.Fields{"device": device, "aproxy": dMgr.adapterProxy})
khenaidoob9203542018-09-17 22:56:37 -0400160
khenaidoo5e677ae2019-02-28 17:26:29 -0500161 // Ensure this device is set as root
162 device.Root = true
khenaidoob9203542018-09-17 22:56:37 -0400163 // Create and start a device agent for that device
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700164 agent := newAgent(dMgr.adapterProxy, device, dMgr, dMgr.dbPath, dMgr.dProxy, dMgr.defaultTimeout)
Thomas Lee Se5a44012019-11-07 20:32:24 +0530165 device, err = agent.start(ctx, device)
Scott Baker80678602019-11-14 16:57:36 -0800166 if err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000167 logger.Errorw(ctx, "Fail-to-start-device", log.Fields{"device-id": agent.deviceID, "error": err})
Kent Hagerman45a13e42020-04-13 12:23:50 -0400168 return nil, err
Scott Baker80678602019-11-14 16:57:36 -0800169 }
khenaidoo442e7c72020-03-10 16:13:48 -0400170 dMgr.addDeviceAgentToMap(agent)
Kent Hagerman45a13e42020-04-13 12:23:50 -0400171 return device, nil
khenaidoob9203542018-09-17 22:56:37 -0400172}
173
Kent Hagerman45a13e42020-04-13 12:23:50 -0400174// EnableDevice activates a device by invoking the adopt_device API on the appropriate adapter
175func (dMgr *Manager) EnableDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000176 logger.Debugw(ctx, "EnableDevice", log.Fields{"device-id": id.Id})
Kent Hagerman45a13e42020-04-13 12:23:50 -0400177 agent := dMgr.getDeviceAgent(ctx, id.Id)
178 if agent == nil {
179 return nil, status.Errorf(codes.NotFound, "%s", id.Id)
khenaidoob9203542018-09-17 22:56:37 -0400180 }
Kent Hagerman45a13e42020-04-13 12:23:50 -0400181 return &empty.Empty{}, agent.enableDevice(ctx)
khenaidoob9203542018-09-17 22:56:37 -0400182}
183
Kent Hagerman45a13e42020-04-13 12:23:50 -0400184// DisableDevice disables a device along with any child device it may have
185func (dMgr *Manager) DisableDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000186 logger.Debugw(ctx, "DisableDevice", log.Fields{"device-id": id.Id})
Kent Hagerman45a13e42020-04-13 12:23:50 -0400187 agent := dMgr.getDeviceAgent(ctx, id.Id)
188 if agent == nil {
189 return nil, status.Errorf(codes.NotFound, "%s", id.Id)
khenaidoob9203542018-09-17 22:56:37 -0400190 }
Kent Hagerman45a13e42020-04-13 12:23:50 -0400191 return &empty.Empty{}, agent.disableDevice(ctx)
khenaidoo92e62c52018-10-03 14:02:54 -0400192}
193
Kent Hagerman45a13e42020-04-13 12:23:50 -0400194//RebootDevice invoked the reboot API to the corresponding adapter
195func (dMgr *Manager) RebootDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000196 logger.Debugw(ctx, "RebootDevice", log.Fields{"device-id": id.Id})
Kent Hagerman45a13e42020-04-13 12:23:50 -0400197 agent := dMgr.getDeviceAgent(ctx, id.Id)
198 if agent == nil {
199 return nil, status.Errorf(codes.NotFound, "%s", id.Id)
khenaidoo4d4802d2018-10-04 21:59:49 -0400200 }
Kent Hagerman45a13e42020-04-13 12:23:50 -0400201 return &empty.Empty{}, agent.rebootDevice(ctx)
khenaidoo4d4802d2018-10-04 21:59:49 -0400202}
203
Kent Hagerman45a13e42020-04-13 12:23:50 -0400204// DeleteDevice removes a device from the data model
205func (dMgr *Manager) DeleteDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000206 logger.Debugw(ctx, "DeleteDevice", log.Fields{"device-id": id.Id})
Kent Hagerman45a13e42020-04-13 12:23:50 -0400207 agent := dMgr.getDeviceAgent(ctx, id.Id)
208 if agent == nil {
209 return nil, status.Errorf(codes.NotFound, "%s", id.Id)
khenaidoo4d4802d2018-10-04 21:59:49 -0400210 }
Kent Hagerman45a13e42020-04-13 12:23:50 -0400211 return &empty.Empty{}, agent.deleteDevice(ctx)
212}
213
214// ListDevicePorts returns the ports details for a specific device entry
215func (dMgr *Manager) ListDevicePorts(ctx context.Context, id *voltha.ID) (*voltha.Ports, error) {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000216 logger.Debugw(ctx, "ListDevicePorts", log.Fields{"device-id": id.Id})
Kent Hagerman45a13e42020-04-13 12:23:50 -0400217 device, err := dMgr.getDevice(ctx, id.Id)
218 if err != nil {
219 return &voltha.Ports{}, err
220 }
221 return &voltha.Ports{Items: device.Ports}, nil
222}
223
224// ListDeviceFlows returns the flow details for a specific device entry
225func (dMgr *Manager) ListDeviceFlows(ctx context.Context, id *voltha.ID) (*ofp.Flows, error) {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000226 logger.Debugw(ctx, "ListDeviceFlows", log.Fields{"device-id": id.Id})
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700227 agent := dMgr.getDeviceAgent(ctx, id.Id)
228 if agent == nil {
229 return &ofp.Flows{}, status.Errorf(codes.NotFound, "device-%s", id.Id)
Kent Hagerman45a13e42020-04-13 12:23:50 -0400230 }
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700231
232 flows := agent.listDeviceFlows()
233 ctr, ret := 0, make([]*ofp.OfpFlowStats, len(flows))
234 for _, flow := range flows {
235 ret[ctr] = flow
236 ctr++
237 }
238 return &openflow_13.Flows{Items: ret}, nil
Kent Hagerman45a13e42020-04-13 12:23:50 -0400239}
240
241// ListDeviceFlowGroups returns the flow group details for a specific device entry
242func (dMgr *Manager) ListDeviceFlowGroups(ctx context.Context, id *voltha.ID) (*voltha.FlowGroups, error) {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000243 logger.Debugw(ctx, "ListDeviceFlowGroups", log.Fields{"device-id": id.Id})
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700244 agent := dMgr.getDeviceAgent(ctx, id.Id)
245 if agent == nil {
Kent Hagerman45a13e42020-04-13 12:23:50 -0400246 return nil, status.Errorf(codes.NotFound, "device-%s", id.Id)
247 }
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700248 groups := agent.listDeviceGroups()
249 ctr, ret := 0, make([]*openflow_13.OfpGroupEntry, len(groups))
250 for _, group := range groups {
251 ret[ctr] = group
252 ctr++
253 }
254 return &voltha.FlowGroups{Items: ret}, nil
khenaidoo4d4802d2018-10-04 21:59:49 -0400255}
256
khenaidoo6d62c002019-05-15 21:57:03 -0400257// stopManagingDevice stops the management of the device as well as any of its reference device and logical device.
258// This function is called only in the Core that does not own this device. In the Core that owns this device then a
259// deletion deletion also includes removal of any reference of this device.
Kent Hagerman2b216042020-04-03 18:28:56 -0400260func (dMgr *Manager) stopManagingDevice(ctx context.Context, id string) {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000261 logger.Infow(ctx, "stopManagingDevice", log.Fields{"deviceId": id})
khenaidoo6d62c002019-05-15 21:57:03 -0400262 if dMgr.IsDeviceInCache(id) { // Proceed only if an agent is present for this device
npujar1d86a522019-11-14 17:11:16 +0530263 if root, _ := dMgr.IsRootDevice(id); root {
khenaidoo6d62c002019-05-15 21:57:03 -0400264 // stop managing the logical device
David Bainbridged1afd662020-03-26 18:27:41 -0700265 _ = dMgr.logicalDeviceMgr.stopManagingLogicalDeviceWithDeviceID(ctx, id)
khenaidoo6d62c002019-05-15 21:57:03 -0400266 }
npujar467fe752020-01-16 20:17:45 +0530267 if agent := dMgr.getDeviceAgent(ctx, id); agent != nil {
khenaidoo442e7c72020-03-10 16:13:48 -0400268 if err := agent.stop(ctx); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000269 logger.Warnw(ctx, "unable-to-stop-device-agent", log.Fields{"device-id": agent.deviceID, "error": err})
khenaidoo442e7c72020-03-10 16:13:48 -0400270 }
khenaidoo4c9e5592019-09-09 16:20:41 -0400271 dMgr.deleteDeviceAgentFromMap(agent)
khenaidoo6d62c002019-05-15 21:57:03 -0400272 }
273 }
274}
275
npujar1d86a522019-11-14 17:11:16 +0530276// RunPostDeviceDelete removes any reference of this device
Kent Hagerman2b216042020-04-03 18:28:56 -0400277func (dMgr *Manager) RunPostDeviceDelete(ctx context.Context, cDevice *voltha.Device) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000278 logger.Infow(ctx, "RunPostDeviceDelete", log.Fields{"deviceId": cDevice.Id})
npujar467fe752020-01-16 20:17:45 +0530279 dMgr.stopManagingDevice(ctx, cDevice.Id)
khenaidoo6d62c002019-05-15 21:57:03 -0400280 return nil
khenaidoo0a822f92019-05-08 15:15:57 -0400281}
282
Kent Hagerman45a13e42020-04-13 12:23:50 -0400283func (dMgr *Manager) GetDevice(ctx context.Context, id *voltha.ID) (*voltha.Device, error) {
284 return dMgr.getDevice(ctx, id.Id)
285}
286
287// getDevice will returns a device, either from memory or from the dB, if present
288func (dMgr *Manager) getDevice(ctx context.Context, id string) (*voltha.Device, error) {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000289 logger.Debugw(ctx, "getDevice", log.Fields{"deviceid": id})
npujar467fe752020-01-16 20:17:45 +0530290 if agent := dMgr.getDeviceAgent(ctx, id); agent != nil {
khenaidoo442e7c72020-03-10 16:13:48 -0400291 return agent.getDevice(ctx)
khenaidoo92e62c52018-10-03 14:02:54 -0400292 }
293 return nil, status.Errorf(codes.NotFound, "%s", id)
khenaidoob9203542018-09-17 22:56:37 -0400294}
295
npujar1d86a522019-11-14 17:11:16 +0530296// GetChildDevice will return a device, either from memory or from the dB, if present
Kent Hagerman2b216042020-04-03 18:28:56 -0400297func (dMgr *Manager) GetChildDevice(ctx context.Context, parentDeviceID string, serialNumber string, onuID int64, parentPortNo int64) (*voltha.Device, error) {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000298 logger.Debugw(ctx, "GetChildDevice", log.Fields{"parentDeviceid": parentDeviceID, "serialNumber": serialNumber,
npujar1d86a522019-11-14 17:11:16 +0530299 "parentPortNo": parentPortNo, "onuId": onuID})
Matt Jeanneret4e241952019-02-28 11:16:04 -0500300
301 var parentDevice *voltha.Device
302 var err error
Kent Hagerman45a13e42020-04-13 12:23:50 -0400303 if parentDevice, err = dMgr.getDevice(ctx, parentDeviceID); err != nil {
Matt Jeanneret4e241952019-02-28 11:16:04 -0500304 return nil, status.Errorf(codes.Aborted, "%s", err.Error())
305 }
306 var childDeviceIds []string
Rohan Agrawal31f21802020-06-12 05:38:46 +0000307 if childDeviceIds, err = dMgr.getAllChildDeviceIds(ctx, parentDevice); err != nil {
Matt Jeanneret4e241952019-02-28 11:16:04 -0500308 return nil, status.Errorf(codes.Aborted, "%s", err.Error())
309 }
310 if len(childDeviceIds) == 0 {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000311 logger.Debugw(ctx, "no-child-devices", log.Fields{"parentDeviceId": parentDevice.Id, "serialNumber": serialNumber, "onuId": onuID})
npujar1d86a522019-11-14 17:11:16 +0530312 return nil, status.Errorf(codes.NotFound, "%s", parentDeviceID)
Matt Jeanneret4e241952019-02-28 11:16:04 -0500313 }
314
315 var foundChildDevice *voltha.Device
npujar1d86a522019-11-14 17:11:16 +0530316 for _, childDeviceID := range childDeviceIds {
317 var found bool
Kent Hagerman45a13e42020-04-13 12:23:50 -0400318 if searchDevice, err := dMgr.getDevice(ctx, childDeviceID); err == nil {
Matt Jeanneret4e241952019-02-28 11:16:04 -0500319
npujar1d86a522019-11-14 17:11:16 +0530320 foundOnuID := false
321 if searchDevice.ProxyAddress.OnuId == uint32(onuID) {
Matt Jeanneret4e241952019-02-28 11:16:04 -0500322 if searchDevice.ParentPortNo == uint32(parentPortNo) {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000323 logger.Debugw(ctx, "found-child-by-onuid", log.Fields{"parentDeviceId": parentDevice.Id, "onuId": onuID})
npujar1d86a522019-11-14 17:11:16 +0530324 foundOnuID = true
Matt Jeanneret4e241952019-02-28 11:16:04 -0500325 }
326 }
327
328 foundSerialNumber := false
329 if searchDevice.SerialNumber == serialNumber {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000330 logger.Debugw(ctx, "found-child-by-serialnumber", log.Fields{"parentDeviceId": parentDevice.Id, "serialNumber": serialNumber})
Matt Jeanneret4e241952019-02-28 11:16:04 -0500331 foundSerialNumber = true
332 }
333
334 // if both onuId and serialNumber are provided both must be true for the device to be found
335 // otherwise whichever one found a match is good enough
npujar1d86a522019-11-14 17:11:16 +0530336 if onuID > 0 && serialNumber != "" {
337 found = foundOnuID && foundSerialNumber
Matt Jeanneret4e241952019-02-28 11:16:04 -0500338 } else {
npujar1d86a522019-11-14 17:11:16 +0530339 found = foundOnuID || foundSerialNumber
Matt Jeanneret4e241952019-02-28 11:16:04 -0500340 }
341
npujar1d86a522019-11-14 17:11:16 +0530342 if found {
Matt Jeanneret4e241952019-02-28 11:16:04 -0500343 foundChildDevice = searchDevice
344 break
345 }
346 }
347 }
348
349 if foundChildDevice != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000350 logger.Debugw(ctx, "child-device-found", log.Fields{"parentDeviceId": parentDevice.Id, "foundChildDevice": foundChildDevice})
Matt Jeanneret4e241952019-02-28 11:16:04 -0500351 return foundChildDevice, nil
352 }
353
Rohan Agrawal31f21802020-06-12 05:38:46 +0000354 logger.Debugw(ctx, "child-device-not-found", log.Fields{"parentDeviceId": parentDevice.Id,
npujar1d86a522019-11-14 17:11:16 +0530355 "serialNumber": serialNumber, "onuId": onuID, "parentPortNo": parentPortNo})
356 return nil, status.Errorf(codes.NotFound, "%s", parentDeviceID)
Matt Jeanneret4e241952019-02-28 11:16:04 -0500357}
358
npujar1d86a522019-11-14 17:11:16 +0530359// GetChildDeviceWithProxyAddress will return a device based on proxy address
Kent Hagerman2b216042020-04-03 18:28:56 -0400360func (dMgr *Manager) GetChildDeviceWithProxyAddress(ctx context.Context, proxyAddress *voltha.Device_ProxyAddress) (*voltha.Device, error) {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000361 logger.Debugw(ctx, "GetChildDeviceWithProxyAddress", log.Fields{"proxyAddress": proxyAddress})
Matt Jeanneret2a20aaa2019-03-05 21:04:02 -0500362
363 var parentDevice *voltha.Device
364 var err error
Kent Hagerman45a13e42020-04-13 12:23:50 -0400365 if parentDevice, err = dMgr.getDevice(ctx, proxyAddress.DeviceId); err != nil {
Matt Jeanneret2a20aaa2019-03-05 21:04:02 -0500366 return nil, status.Errorf(codes.Aborted, "%s", err.Error())
367 }
368 var childDeviceIds []string
Rohan Agrawal31f21802020-06-12 05:38:46 +0000369 if childDeviceIds, err = dMgr.getAllChildDeviceIds(ctx, parentDevice); err != nil {
Matt Jeanneret2a20aaa2019-03-05 21:04:02 -0500370 return nil, status.Errorf(codes.Aborted, "%s", err.Error())
371 }
372 if len(childDeviceIds) == 0 {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000373 logger.Debugw(ctx, "no-child-devices", log.Fields{"parentDeviceId": parentDevice.Id})
Matt Jeanneret2a20aaa2019-03-05 21:04:02 -0500374 return nil, status.Errorf(codes.NotFound, "%s", proxyAddress)
375 }
376
377 var foundChildDevice *voltha.Device
npujar1d86a522019-11-14 17:11:16 +0530378 for _, childDeviceID := range childDeviceIds {
Kent Hagerman45a13e42020-04-13 12:23:50 -0400379 if searchDevice, err := dMgr.getDevice(ctx, childDeviceID); err == nil {
Matt Jeanneret2a20aaa2019-03-05 21:04:02 -0500380 if searchDevice.ProxyAddress == proxyAddress {
381 foundChildDevice = searchDevice
382 break
383 }
384 }
385 }
386
387 if foundChildDevice != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000388 logger.Debugw(ctx, "child-device-found", log.Fields{"proxyAddress": proxyAddress})
Matt Jeanneret2a20aaa2019-03-05 21:04:02 -0500389 return foundChildDevice, nil
390 }
391
Rohan Agrawal31f21802020-06-12 05:38:46 +0000392 logger.Warnw(ctx, "child-device-not-found", log.Fields{"proxyAddress": proxyAddress})
Matt Jeanneret2a20aaa2019-03-05 21:04:02 -0500393 return nil, status.Errorf(codes.NotFound, "%s", proxyAddress)
394}
395
npujar1d86a522019-11-14 17:11:16 +0530396// IsDeviceInCache returns true if device is found in the map
Kent Hagerman2b216042020-04-03 18:28:56 -0400397func (dMgr *Manager) IsDeviceInCache(id string) bool {
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400398 _, exist := dMgr.deviceAgents.Load(id)
khenaidoo297cd252019-02-07 22:10:23 -0500399 return exist
400}
401
npujar1d86a522019-11-14 17:11:16 +0530402// IsRootDevice returns true if root device is found in the map
Kent Hagerman2b216042020-04-03 18:28:56 -0400403func (dMgr *Manager) IsRootDevice(id string) (bool, error) {
khenaidoo2c6a0992019-04-29 13:46:56 -0400404 dMgr.lockRootDeviceMap.RLock()
405 defer dMgr.lockRootDeviceMap.RUnlock()
406 if exist := dMgr.rootDevices[id]; exist {
407 return dMgr.rootDevices[id], nil
khenaidoo19d7b632018-10-30 10:49:50 -0400408 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400409 return false, nil
khenaidoo19d7b632018-10-30 10:49:50 -0400410}
411
Stephane Barbarieaa467942019-02-06 14:09:44 -0500412// ListDevices retrieves the latest devices from the data model
Kent Hagerman45a13e42020-04-13 12:23:50 -0400413func (dMgr *Manager) ListDevices(ctx context.Context, _ *empty.Empty) (*voltha.Devices, error) {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000414 logger.Debug(ctx, "ListDevices")
khenaidoob9203542018-09-17 22:56:37 -0400415 result := &voltha.Devices{}
Kent Hagerman4f355f52020-03-30 16:01:33 -0400416
417 var devices []*voltha.Device
Kent Hagermanf5a67352020-04-30 15:15:26 -0400418 if err := dMgr.dProxy.List(ctx, &devices); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000419 logger.Errorw(ctx, "failed-to-list-devices-from-cluster-proxy", log.Fields{"error": err})
Thomas Lee Se5a44012019-11-07 20:32:24 +0530420 return nil, err
421 }
Kent Hagerman4f355f52020-03-30 16:01:33 -0400422
423 for _, device := range devices {
424 // If device is not in memory then set it up
425 if !dMgr.IsDeviceInCache(device.Id) {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000426 logger.Debugw(ctx, "loading-device-from-Model", log.Fields{"id": device.Id})
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700427 agent := newAgent(dMgr.adapterProxy, device, dMgr, dMgr.dbPath, dMgr.dProxy, dMgr.defaultTimeout)
Kent Hagerman4f355f52020-03-30 16:01:33 -0400428 if _, err := agent.start(ctx, nil); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000429 logger.Warnw(ctx, "failure-starting-agent", log.Fields{"deviceId": device.Id})
Kent Hagerman4f355f52020-03-30 16:01:33 -0400430 } else {
431 dMgr.addDeviceAgentToMap(agent)
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500432 }
khenaidoob9203542018-09-17 22:56:37 -0400433 }
Kent Hagerman4f355f52020-03-30 16:01:33 -0400434 result.Items = append(result.Items, device)
khenaidoob9203542018-09-17 22:56:37 -0400435 }
Rohan Agrawal31f21802020-06-12 05:38:46 +0000436 logger.Debugw(ctx, "ListDevices-end", log.Fields{"len": len(result.Items)})
khenaidoob9203542018-09-17 22:56:37 -0400437 return result, nil
438}
439
Thomas Lee S51b5cb82019-10-14 14:49:34 +0530440//isParentDeviceExist checks whether device is already preprovisioned.
Kent Hagerman2b216042020-04-03 18:28:56 -0400441func (dMgr *Manager) isParentDeviceExist(ctx context.Context, newDevice *voltha.Device) (bool, error) {
Thomas Lee S51b5cb82019-10-14 14:49:34 +0530442 hostPort := newDevice.GetHostAndPort()
Kent Hagerman4f355f52020-03-30 16:01:33 -0400443 var devices []*voltha.Device
Kent Hagermanf5a67352020-04-30 15:15:26 -0400444 if err := dMgr.dProxy.List(ctx, &devices); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000445 logger.Errorw(ctx, "Failed to list devices from cluster data proxy", log.Fields{"error": err})
Thomas Lee Se5a44012019-11-07 20:32:24 +0530446 return false, err
447 }
Kent Hagerman4f355f52020-03-30 16:01:33 -0400448 for _, device := range devices {
449 if !device.Root {
450 continue
451 }
452 if hostPort != "" && hostPort == device.GetHostAndPort() && device.AdminState != voltha.AdminState_DELETED {
453 return true, nil
454 }
455 if newDevice.MacAddress != "" && newDevice.MacAddress == device.MacAddress && device.AdminState != voltha.AdminState_DELETED {
456 return true, nil
Thomas Lee S51b5cb82019-10-14 14:49:34 +0530457 }
458 }
Thomas Lee Se5a44012019-11-07 20:32:24 +0530459 return false, nil
Thomas Lee S51b5cb82019-10-14 14:49:34 +0530460}
461
khenaidoo6d62c002019-05-15 21:57:03 -0400462//getDeviceFromModelretrieves the device data from the model.
Kent Hagerman2b216042020-04-03 18:28:56 -0400463func (dMgr *Manager) getDeviceFromModel(ctx context.Context, deviceID string) (*voltha.Device, error) {
Kent Hagerman4f355f52020-03-30 16:01:33 -0400464 device := &voltha.Device{}
Kent Hagermanf5a67352020-04-30 15:15:26 -0400465 if have, err := dMgr.dProxy.Get(ctx, deviceID, device); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000466 logger.Errorw(ctx, "failed-to-get-device-info-from-cluster-proxy", log.Fields{"error": err})
Thomas Lee Se5a44012019-11-07 20:32:24 +0530467 return nil, err
Kent Hagerman4f355f52020-03-30 16:01:33 -0400468 } else if !have {
469 return nil, status.Error(codes.NotFound, deviceID)
Thomas Lee Se5a44012019-11-07 20:32:24 +0530470 }
Kent Hagerman4f355f52020-03-30 16:01:33 -0400471
472 return device, nil
khenaidoo6d62c002019-05-15 21:57:03 -0400473}
474
npujar1d86a522019-11-14 17:11:16 +0530475// loadDevice loads the deviceID in memory, if not present
Kent Hagerman2b216042020-04-03 18:28:56 -0400476func (dMgr *Manager) loadDevice(ctx context.Context, deviceID string) (*Agent, error) {
npujar1d86a522019-11-14 17:11:16 +0530477 if deviceID == "" {
khenaidoo297cd252019-02-07 22:10:23 -0500478 return nil, status.Error(codes.InvalidArgument, "deviceId empty")
479 }
khenaidoo4c9e5592019-09-09 16:20:41 -0400480 var err error
481 var device *voltha.Device
482 dMgr.devicesLoadingLock.Lock()
npujar1d86a522019-11-14 17:11:16 +0530483 if _, exist := dMgr.deviceLoadingInProgress[deviceID]; !exist {
484 if !dMgr.IsDeviceInCache(deviceID) {
485 dMgr.deviceLoadingInProgress[deviceID] = []chan int{make(chan int, 1)}
khenaidoo4c9e5592019-09-09 16:20:41 -0400486 dMgr.devicesLoadingLock.Unlock()
487 // Proceed with the loading only if the device exist in the Model (could have been deleted)
npujar467fe752020-01-16 20:17:45 +0530488 if device, err = dMgr.getDeviceFromModel(ctx, deviceID); err == nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000489 logger.Debugw(ctx, "loading-device", log.Fields{"deviceId": deviceID})
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700490 agent := newAgent(dMgr.adapterProxy, device, dMgr, dMgr.dbPath, dMgr.dProxy, dMgr.defaultTimeout)
npujar467fe752020-01-16 20:17:45 +0530491 if _, err = agent.start(ctx, nil); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000492 logger.Warnw(ctx, "Failure loading device", log.Fields{"deviceId": deviceID, "error": err})
khenaidoo4c9e5592019-09-09 16:20:41 -0400493 } else {
494 dMgr.addDeviceAgentToMap(agent)
495 }
496 } else {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000497 logger.Debugw(ctx, "Device not in model", log.Fields{"deviceId": deviceID})
khenaidoo6d62c002019-05-15 21:57:03 -0400498 }
khenaidoo4c9e5592019-09-09 16:20:41 -0400499 // announce completion of task to any number of waiting channels
500 dMgr.devicesLoadingLock.Lock()
npujar1d86a522019-11-14 17:11:16 +0530501 if v, ok := dMgr.deviceLoadingInProgress[deviceID]; ok {
khenaidoo4c9e5592019-09-09 16:20:41 -0400502 for _, ch := range v {
503 close(ch)
504 }
npujar1d86a522019-11-14 17:11:16 +0530505 delete(dMgr.deviceLoadingInProgress, deviceID)
khenaidoo4c9e5592019-09-09 16:20:41 -0400506 }
507 dMgr.devicesLoadingLock.Unlock()
khenaidoo6d62c002019-05-15 21:57:03 -0400508 } else {
khenaidoo4c9e5592019-09-09 16:20:41 -0400509 dMgr.devicesLoadingLock.Unlock()
khenaidoo297cd252019-02-07 22:10:23 -0500510 }
khenaidoo4c9e5592019-09-09 16:20:41 -0400511 } else {
512 ch := make(chan int, 1)
npujar1d86a522019-11-14 17:11:16 +0530513 dMgr.deviceLoadingInProgress[deviceID] = append(dMgr.deviceLoadingInProgress[deviceID], ch)
khenaidoo4c9e5592019-09-09 16:20:41 -0400514 dMgr.devicesLoadingLock.Unlock()
515 // Wait for the channel to be closed, implying the process loading this device is done.
516 <-ch
khenaidoo297cd252019-02-07 22:10:23 -0500517 }
npujar1d86a522019-11-14 17:11:16 +0530518 if agent, ok := dMgr.deviceAgents.Load(deviceID); ok {
Kent Hagerman2b216042020-04-03 18:28:56 -0400519 return agent.(*Agent), nil
khenaidoo297cd252019-02-07 22:10:23 -0500520 }
npujar1d86a522019-11-14 17:11:16 +0530521 return nil, status.Errorf(codes.Aborted, "Error loading device %s", deviceID)
khenaidoo297cd252019-02-07 22:10:23 -0500522}
523
524// loadRootDeviceParentAndChildren loads the children and parents of a root device in memory
Kent Hagerman2b216042020-04-03 18:28:56 -0400525func (dMgr *Manager) loadRootDeviceParentAndChildren(ctx context.Context, device *voltha.Device) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000526 logger.Debugw(ctx, "loading-parent-and-children", log.Fields{"deviceId": device.Id})
khenaidoo297cd252019-02-07 22:10:23 -0500527 if device.Root {
528 // Scenario A
529 if device.ParentId != "" {
530 // Load logical device if needed.
npujar467fe752020-01-16 20:17:45 +0530531 if err := dMgr.logicalDeviceMgr.load(ctx, device.ParentId); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000532 logger.Warnw(ctx, "failure-loading-logical-device", log.Fields{"lDeviceId": device.ParentId})
khenaidoo297cd252019-02-07 22:10:23 -0500533 }
534 } else {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000535 logger.Debugw(ctx, "no-parent-to-load", log.Fields{"deviceId": device.Id})
khenaidoo297cd252019-02-07 22:10:23 -0500536 }
537 // Load all child devices, if needed
Rohan Agrawal31f21802020-06-12 05:38:46 +0000538 if childDeviceIds, err := dMgr.getAllChildDeviceIds(ctx, device); err == nil {
npujar1d86a522019-11-14 17:11:16 +0530539 for _, childDeviceID := range childDeviceIds {
npujar467fe752020-01-16 20:17:45 +0530540 if _, err := dMgr.loadDevice(ctx, childDeviceID); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000541 logger.Warnw(ctx, "failure-loading-device", log.Fields{"deviceId": childDeviceID, "error": err})
khenaidoo297cd252019-02-07 22:10:23 -0500542 return err
543 }
544 }
Rohan Agrawal31f21802020-06-12 05:38:46 +0000545 logger.Debugw(ctx, "loaded-children", log.Fields{"deviceId": device.Id, "numChildren": len(childDeviceIds)})
khenaidoo297cd252019-02-07 22:10:23 -0500546 } else {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000547 logger.Debugw(ctx, "no-child-to-load", log.Fields{"deviceId": device.Id})
khenaidoo297cd252019-02-07 22:10:23 -0500548 }
549 }
550 return nil
551}
552
553// load loads the deviceId in memory, if not present, and also loads its accompanying parents and children. Loading
554// in memory is for improved performance. It is not imperative that a device needs to be in memory when a request
555// acting on the device is received by the core. In such a scenario, the Core will load the device in memory first
556// and the proceed with the request.
Kent Hagerman2b216042020-04-03 18:28:56 -0400557func (dMgr *Manager) load(ctx context.Context, deviceID string) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000558 logger.Debug(ctx, "load...")
khenaidoo297cd252019-02-07 22:10:23 -0500559 // First load the device - this may fail in case the device was deleted intentionally by the other core
Kent Hagerman2b216042020-04-03 18:28:56 -0400560 var dAgent *Agent
khenaidoo297cd252019-02-07 22:10:23 -0500561 var err error
npujar467fe752020-01-16 20:17:45 +0530562 if dAgent, err = dMgr.loadDevice(ctx, deviceID); err != nil {
khenaidoo297cd252019-02-07 22:10:23 -0500563 return err
564 }
565 // Get the loaded device details
khenaidoo442e7c72020-03-10 16:13:48 -0400566 device, err := dAgent.getDevice(ctx)
567 if err != nil {
568 return err
569 }
khenaidoo297cd252019-02-07 22:10:23 -0500570
571 // If the device is in Pre-provisioning or deleted state stop here
572 if device.AdminState == voltha.AdminState_PREPROVISIONED || device.AdminState == voltha.AdminState_DELETED {
573 return nil
574 }
575
576 // Now we face two scenarios
577 if device.Root {
578 // Load all children as well as the parent of this device (logical_device)
npujar467fe752020-01-16 20:17:45 +0530579 if err := dMgr.loadRootDeviceParentAndChildren(ctx, device); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000580 logger.Warnw(ctx, "failure-loading-device-parent-and-children", log.Fields{"deviceId": deviceID})
khenaidoo297cd252019-02-07 22:10:23 -0500581 return err
582 }
Rohan Agrawal31f21802020-06-12 05:38:46 +0000583 logger.Debugw(ctx, "successfully-loaded-parent-and-children", log.Fields{"deviceId": deviceID})
khenaidoo297cd252019-02-07 22:10:23 -0500584 } else {
585 // Scenario B - use the parentId of that device (root device) to trigger the loading
586 if device.ParentId != "" {
npujar467fe752020-01-16 20:17:45 +0530587 return dMgr.load(ctx, device.ParentId)
khenaidoo297cd252019-02-07 22:10:23 -0500588 }
589 }
590 return nil
591}
592
khenaidoo7ccedd52018-12-14 16:48:54 -0500593// ListDeviceIds retrieves the latest device IDs information from the data model (memory data only)
Rohan Agrawal31f21802020-06-12 05:38:46 +0000594func (dMgr *Manager) ListDeviceIds(ctx context.Context, _ *empty.Empty) (*voltha.IDs, error) {
595 logger.Debug(ctx, "ListDeviceIDs")
khenaidoo7ccedd52018-12-14 16:48:54 -0500596 // Report only device IDs that are in the device agent map
597 return dMgr.listDeviceIdsFromMap(), nil
598}
599
Kent Hagerman45a13e42020-04-13 12:23:50 -0400600// ReconcileDevices is a request to a voltha core to update its list of managed devices. This will
601// trigger loading the devices along with their children and parent in memory
602func (dMgr *Manager) ReconcileDevices(ctx context.Context, ids *voltha.IDs) (*empty.Empty, error) {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000603 logger.Debugw(ctx, "ReconcileDevices", log.Fields{"numDevices": len(ids.Items)})
khenaidoo4c9e5592019-09-09 16:20:41 -0400604 if ids != nil && len(ids.Items) != 0 {
khenaidoo7ccedd52018-12-14 16:48:54 -0500605 toReconcile := len(ids.Items)
606 reconciled := 0
khenaidoo4c9e5592019-09-09 16:20:41 -0400607 var err error
khenaidoo7ccedd52018-12-14 16:48:54 -0500608 for _, id := range ids.Items {
npujar467fe752020-01-16 20:17:45 +0530609 if err = dMgr.load(ctx, id.Id); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000610 logger.Warnw(ctx, "failure-reconciling-device", log.Fields{"deviceId": id.Id, "error": err})
khenaidoo4c9e5592019-09-09 16:20:41 -0400611 } else {
npujar1d86a522019-11-14 17:11:16 +0530612 reconciled++
khenaidoo7ccedd52018-12-14 16:48:54 -0500613 }
614 }
615 if toReconcile != reconciled {
Kent Hagerman45a13e42020-04-13 12:23:50 -0400616 return nil, status.Errorf(codes.DataLoss, "less-device-reconciled-than-requested:%d/%d", reconciled, toReconcile)
khenaidoo7ccedd52018-12-14 16:48:54 -0500617 }
618 } else {
Kent Hagerman45a13e42020-04-13 12:23:50 -0400619 return nil, status.Errorf(codes.InvalidArgument, "empty-list-of-ids")
khenaidoo7ccedd52018-12-14 16:48:54 -0500620 }
Kent Hagerman45a13e42020-04-13 12:23:50 -0400621 return &empty.Empty{}, nil
khenaidoo7ccedd52018-12-14 16:48:54 -0500622}
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500623
khenaidooba6b6c42019-08-02 09:11:56 -0400624// isOkToReconcile validates whether a device is in the correct status to be reconciled
625func isOkToReconcile(device *voltha.Device) bool {
626 if device == nil {
627 return false
628 }
629 return device.AdminState != voltha.AdminState_PREPROVISIONED && device.AdminState != voltha.AdminState_DELETED
630}
631
632// adapterRestarted is invoked whenever an adapter is restarted
Kent Hagerman2b216042020-04-03 18:28:56 -0400633func (dMgr *Manager) adapterRestarted(ctx context.Context, adapter *voltha.Adapter) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000634 logger.Debugw(ctx, "adapter-restarted", log.Fields{"adapterId": adapter.Id, "vendor": adapter.Vendor,
Matteo Scandolod525ae32020-04-02 17:27:29 -0700635 "currentReplica": adapter.CurrentReplica, "totalReplicas": adapter.TotalReplicas, "endpoint": adapter.Endpoint})
khenaidooba6b6c42019-08-02 09:11:56 -0400636
637 // Let's reconcile the device managed by this Core only
David Bainbridged1afd662020-03-26 18:27:41 -0700638 if len(dMgr.rootDevices) == 0 {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000639 logger.Debugw(ctx, "nothing-to-reconcile", log.Fields{"adapterId": adapter.Id})
khenaidooba6b6c42019-08-02 09:11:56 -0400640 return nil
641 }
642
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500643 responses := make([]utils.Response, 0)
David Bainbridged1afd662020-03-26 18:27:41 -0700644 for rootDeviceID := range dMgr.rootDevices {
npujar467fe752020-01-16 20:17:45 +0530645 if rootDevice, _ := dMgr.getDeviceFromModel(ctx, rootDeviceID); rootDevice != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000646 isDeviceOwnedByService, err := dMgr.adapterProxy.IsDeviceOwnedByService(ctx, rootDeviceID, adapter.Type, adapter.CurrentReplica)
serkant.uluderya7d545aa2020-04-09 13:38:45 -0700647 if err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000648 logger.Warnw(ctx, "is-device-owned-by-service", log.Fields{"error": err, "root-device-id": rootDeviceID, "adapterType": adapter.Type, "replica-number": adapter.CurrentReplica})
serkant.uluderya7d545aa2020-04-09 13:38:45 -0700649 continue
650 }
651 if isDeviceOwnedByService {
khenaidooba6b6c42019-08-02 09:11:56 -0400652 if isOkToReconcile(rootDevice) {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000653 logger.Debugw(ctx, "reconciling-root-device", log.Fields{"rootId": rootDevice.Id})
npujar467fe752020-01-16 20:17:45 +0530654 responses = append(responses, dMgr.sendReconcileDeviceRequest(ctx, rootDevice))
khenaidooba6b6c42019-08-02 09:11:56 -0400655 } else {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000656 logger.Debugw(ctx, "not-reconciling-root-device", log.Fields{"rootId": rootDevice.Id, "state": rootDevice.AdminState})
khenaidooba6b6c42019-08-02 09:11:56 -0400657 }
658 } else { // Should we be reconciling the root's children instead?
659 childManagedByAdapter:
660 for _, port := range rootDevice.Ports {
661 for _, peer := range port.Peers {
npujar467fe752020-01-16 20:17:45 +0530662 if childDevice, _ := dMgr.getDeviceFromModel(ctx, peer.DeviceId); childDevice != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000663 isDeviceOwnedByService, err := dMgr.adapterProxy.IsDeviceOwnedByService(ctx, childDevice.Id, adapter.Type, adapter.CurrentReplica)
serkant.uluderya7d545aa2020-04-09 13:38:45 -0700664 if err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000665 logger.Warnw(ctx, "is-device-owned-by-service", log.Fields{"error": err, "child-device-id": childDevice.Id, "adapterType": adapter.Type, "replica-number": adapter.CurrentReplica})
serkant.uluderya7d545aa2020-04-09 13:38:45 -0700666 }
667 if isDeviceOwnedByService {
khenaidooba6b6c42019-08-02 09:11:56 -0400668 if isOkToReconcile(childDevice) {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000669 logger.Debugw(ctx, "reconciling-child-device", log.Fields{"child-device-id": childDevice.Id})
npujar467fe752020-01-16 20:17:45 +0530670 responses = append(responses, dMgr.sendReconcileDeviceRequest(ctx, childDevice))
khenaidooba6b6c42019-08-02 09:11:56 -0400671 } else {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000672 logger.Debugw(ctx, "not-reconciling-child-device", log.Fields{"child-device-id": childDevice.Id, "state": childDevice.AdminState})
khenaidooba6b6c42019-08-02 09:11:56 -0400673 }
674 } else {
675 // All child devices under a parent device are typically managed by the same adapter type.
676 // Therefore we only need to check whether the first device we retrieved is managed by that adapter
677 break childManagedByAdapter
678 }
679 }
680 }
681 }
682 }
683 }
684 }
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500685 if len(responses) > 0 {
khenaidooba6b6c42019-08-02 09:11:56 -0400686 // Wait for completion
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500687 if res := utils.WaitForNilOrErrorResponses(dMgr.defaultTimeout, responses...); res != nil {
khenaidooba6b6c42019-08-02 09:11:56 -0400688 return status.Errorf(codes.Aborted, "errors-%s", res)
689 }
690 } else {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000691 logger.Debugw(ctx, "no-managed-device-to-reconcile", log.Fields{"adapterId": adapter.Id})
khenaidooba6b6c42019-08-02 09:11:56 -0400692 }
693 return nil
694}
695
Kent Hagerman2b216042020-04-03 18:28:56 -0400696func (dMgr *Manager) sendReconcileDeviceRequest(ctx context.Context, device *voltha.Device) utils.Response {
khenaidooba6b6c42019-08-02 09:11:56 -0400697 // Send a reconcile request to the adapter. Since this Core may not be managing this device then there is no
698 // point of creating a device agent (if the device is not being managed by this Core) before sending the request
npujar1d86a522019-11-14 17:11:16 +0530699 // to the adapter. We will therefore bypass the adapter adapter and send the request directly to the adapter via
Kent Hagerman2b216042020-04-03 18:28:56 -0400700 // the adapter proxy.
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500701 response := utils.NewResponse()
Kent Hagerman2b216042020-04-03 18:28:56 -0400702 ch, err := dMgr.adapterProxy.ReconcileDevice(ctx, device)
khenaidoo442e7c72020-03-10 16:13:48 -0400703 if err != nil {
704 response.Error(err)
705 }
706 // Wait for adapter response in its own routine
707 go func() {
708 resp, ok := <-ch
709 if !ok {
710 response.Error(status.Errorf(codes.Aborted, "channel-closed-device: %s", device.Id))
711 } else if resp.Err != nil {
712 response.Error(resp.Err)
khenaidooba6b6c42019-08-02 09:11:56 -0400713 }
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500714 response.Done()
khenaidoo442e7c72020-03-10 16:13:48 -0400715 }()
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500716 return response
khenaidooba6b6c42019-08-02 09:11:56 -0400717}
718
Kent Hagerman2b216042020-04-03 18:28:56 -0400719func (dMgr *Manager) ReconcileChildDevices(ctx context.Context, parentDeviceID string) error {
npujar467fe752020-01-16 20:17:45 +0530720 if parentDevice, _ := dMgr.getDeviceFromModel(ctx, parentDeviceID); parentDevice != nil {
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500721 responses := make([]utils.Response, 0)
khenaidooba6b6c42019-08-02 09:11:56 -0400722 for _, port := range parentDevice.Ports {
723 for _, peer := range port.Peers {
npujar467fe752020-01-16 20:17:45 +0530724 if childDevice, _ := dMgr.getDeviceFromModel(ctx, peer.DeviceId); childDevice != nil {
725 responses = append(responses, dMgr.sendReconcileDeviceRequest(ctx, childDevice))
khenaidooba6b6c42019-08-02 09:11:56 -0400726 }
727 }
728 }
729 // Wait for completion
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500730 if res := utils.WaitForNilOrErrorResponses(dMgr.defaultTimeout, responses...); res != nil {
khenaidooba6b6c42019-08-02 09:11:56 -0400731 return status.Errorf(codes.Aborted, "errors-%s", res)
732 }
733 }
734 return nil
735}
736
Kent Hagerman2b216042020-04-03 18:28:56 -0400737func (dMgr *Manager) UpdateDeviceUsingAdapterData(ctx context.Context, device *voltha.Device) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000738 logger.Debugw(ctx, "UpdateDeviceUsingAdapterData", log.Fields{"deviceid": device.Id, "device": device})
npujar467fe752020-01-16 20:17:45 +0530739 if agent := dMgr.getDeviceAgent(ctx, device.Id); agent != nil {
740 return agent.updateDeviceUsingAdapterData(ctx, device)
khenaidoob9203542018-09-17 22:56:37 -0400741 }
742 return status.Errorf(codes.NotFound, "%s", device.Id)
743}
744
khenaidoo0db4c812020-05-27 15:27:30 -0400745func (dMgr *Manager) addPeerPort(ctx context.Context, deviceID string, port *voltha.Port) error {
746 meAsPeer := &voltha.Port_PeerPort{DeviceId: deviceID, PortNo: port.PortNo}
747 for _, peerPort := range port.Peers {
748 if agent := dMgr.getDeviceAgent(ctx, peerPort.DeviceId); agent != nil {
749 if err := agent.addPeerPort(ctx, meAsPeer); err != nil {
750 return err
751 }
752 }
753 }
754 // Notify the logical device manager to setup a logical port, if needed. If the added port is an NNI or UNI
755 // then a logical port will be added to the logical device and the device route generated. If the port is a
756 // PON port then only the device graph will be generated.
757 device, err := dMgr.getDevice(ctx, deviceID)
758 if err != nil {
759 return err
760 }
761 if err = dMgr.logicalDeviceMgr.updateLogicalPort(context.Background(), device, port); err != nil {
762 return err
763 }
764 return nil
765}
766
Kent Hagerman2b216042020-04-03 18:28:56 -0400767func (dMgr *Manager) AddPort(ctx context.Context, deviceID string, port *voltha.Port) error {
npujar467fe752020-01-16 20:17:45 +0530768 agent := dMgr.getDeviceAgent(ctx, deviceID)
npujar1d86a522019-11-14 17:11:16 +0530769 if agent != nil {
npujar467fe752020-01-16 20:17:45 +0530770 if err := agent.addPort(ctx, port); err != nil {
khenaidoo92e62c52018-10-03 14:02:54 -0400771 return err
772 }
khenaidoo0db4c812020-05-27 15:27:30 -0400773 // Setup peer ports in its own routine
774 go func() {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000775 if err := dMgr.addPeerPort(context.Background(), deviceID, port); err != nil {
776 logger.Errorw(ctx, "unable-to-add-peer-port", log.Fields{"error": err, "device-id": deviceID})
khenaidoo92e62c52018-10-03 14:02:54 -0400777 }
khenaidoo0db4c812020-05-27 15:27:30 -0400778 }()
khenaidoo92e62c52018-10-03 14:02:54 -0400779 return nil
khenaidoob9203542018-09-17 22:56:37 -0400780 }
npujar1d86a522019-11-14 17:11:16 +0530781 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoob9203542018-09-17 22:56:37 -0400782}
783
Kent Hagerman2b216042020-04-03 18:28:56 -0400784func (dMgr *Manager) addFlowsAndGroups(ctx context.Context, deviceID string, flows []*ofp.OfpFlowStats, groups []*ofp.OfpGroupEntry, flowMetadata *voltha.FlowMetadata) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000785 logger.Debugw(ctx, "addFlowsAndGroups", log.Fields{"deviceid": deviceID, "groups:": groups, "flowMetadata": flowMetadata})
npujar467fe752020-01-16 20:17:45 +0530786 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
787 return agent.addFlowsAndGroups(ctx, flows, groups, flowMetadata)
khenaidoo0458db62019-06-20 08:50:36 -0400788 }
npujar1d86a522019-11-14 17:11:16 +0530789 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo0458db62019-06-20 08:50:36 -0400790}
791
khenaidoo787224a2020-04-16 18:08:47 -0400792// deleteParentFlows removes flows from the parent device based on specific attributes
793func (dMgr *Manager) deleteParentFlows(ctx context.Context, deviceID string, uniPort uint32, metadata *voltha.FlowMetadata) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000794 logger.Debugw(ctx, "deleteParentFlows", log.Fields{"device-id": deviceID, "uni-port": uniPort, "metadata": metadata})
khenaidoo787224a2020-04-16 18:08:47 -0400795 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
796 if !agent.isRootdevice {
797 return status.Errorf(codes.FailedPrecondition, "not-a-parent-device-%s", deviceID)
798 }
799 return agent.filterOutFlows(ctx, uniPort, metadata)
800 }
801 return status.Errorf(codes.NotFound, "%s", deviceID)
802}
803
Kent Hagerman2b216042020-04-03 18:28:56 -0400804func (dMgr *Manager) deleteFlowsAndGroups(ctx context.Context, deviceID string, flows []*ofp.OfpFlowStats, groups []*ofp.OfpGroupEntry, flowMetadata *voltha.FlowMetadata) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000805 logger.Debugw(ctx, "deleteFlowsAndGroups", log.Fields{"deviceid": deviceID})
npujar467fe752020-01-16 20:17:45 +0530806 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
807 return agent.deleteFlowsAndGroups(ctx, flows, groups, flowMetadata)
khenaidoo0458db62019-06-20 08:50:36 -0400808 }
npujar1d86a522019-11-14 17:11:16 +0530809 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo0458db62019-06-20 08:50:36 -0400810}
811
Kent Hagerman2b216042020-04-03 18:28:56 -0400812func (dMgr *Manager) updateFlowsAndGroups(ctx context.Context, deviceID string, flows []*ofp.OfpFlowStats, groups []*ofp.OfpGroupEntry, flowMetadata *voltha.FlowMetadata) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000813 logger.Debugw(ctx, "updateFlowsAndGroups", log.Fields{"deviceid": deviceID})
npujar467fe752020-01-16 20:17:45 +0530814 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
815 return agent.updateFlowsAndGroups(ctx, flows, groups, flowMetadata)
khenaidoo19d7b632018-10-30 10:49:50 -0400816 }
npujar1d86a522019-11-14 17:11:16 +0530817 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo19d7b632018-10-30 10:49:50 -0400818}
819
Kent Hagerman45a13e42020-04-13 12:23:50 -0400820// UpdateDevicePmConfigs updates the PM configs. This is executed when the northbound gRPC API is invoked, typically
khenaidoob3127472019-07-24 21:04:55 -0400821// following a user action
Kent Hagerman45a13e42020-04-13 12:23:50 -0400822func (dMgr *Manager) UpdateDevicePmConfigs(ctx context.Context, configs *voltha.PmConfigs) (*empty.Empty, error) {
823 if configs.Id == "" {
824 return nil, status.Error(codes.FailedPrecondition, "invalid-device-Id")
khenaidoob3127472019-07-24 21:04:55 -0400825 }
Kent Hagerman45a13e42020-04-13 12:23:50 -0400826 agent := dMgr.getDeviceAgent(ctx, configs.Id)
827 if agent == nil {
828 return nil, status.Errorf(codes.NotFound, "%s", configs.Id)
829 }
830 return &empty.Empty{}, agent.updatePmConfigs(ctx, configs)
khenaidoob3127472019-07-24 21:04:55 -0400831}
832
Kent Hagerman2b216042020-04-03 18:28:56 -0400833// InitPmConfigs initialize the pm configs as defined by the adapter.
834func (dMgr *Manager) InitPmConfigs(ctx context.Context, deviceID string, pmConfigs *voltha.PmConfigs) error {
khenaidoob3127472019-07-24 21:04:55 -0400835 if pmConfigs.Id == "" {
836 return status.Errorf(codes.FailedPrecondition, "invalid-device-Id")
837 }
npujar467fe752020-01-16 20:17:45 +0530838 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
839 return agent.initPmConfigs(ctx, pmConfigs)
khenaidoob9203542018-09-17 22:56:37 -0400840 }
npujar1d86a522019-11-14 17:11:16 +0530841 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoob9203542018-09-17 22:56:37 -0400842}
843
Kent Hagerman45a13e42020-04-13 12:23:50 -0400844// ListDevicePmConfigs returns pm configs of device
845func (dMgr *Manager) ListDevicePmConfigs(ctx context.Context, id *voltha.ID) (*voltha.PmConfigs, error) {
846 agent := dMgr.getDeviceAgent(ctx, id.Id)
847 if agent == nil {
848 return nil, status.Errorf(codes.NotFound, "%s", id.Id)
khenaidoob3127472019-07-24 21:04:55 -0400849 }
Kent Hagerman45a13e42020-04-13 12:23:50 -0400850 return agent.listPmConfigs(ctx)
khenaidoob3127472019-07-24 21:04:55 -0400851}
852
Kent Hagerman2b216042020-04-03 18:28:56 -0400853func (dMgr *Manager) getSwitchCapability(ctx context.Context, deviceID string) (*ic.SwitchCapability, error) {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000854 logger.Debugw(ctx, "getSwitchCapability", log.Fields{"deviceid": deviceID})
npujar467fe752020-01-16 20:17:45 +0530855 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
khenaidoob9203542018-09-17 22:56:37 -0400856 return agent.getSwitchCapability(ctx)
857 }
npujar1d86a522019-11-14 17:11:16 +0530858 return nil, status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoob9203542018-09-17 22:56:37 -0400859}
860
Kent Hagerman2b216042020-04-03 18:28:56 -0400861func (dMgr *Manager) GetPorts(ctx context.Context, deviceID string, portType voltha.Port_PortType) (*voltha.Ports, error) {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000862 logger.Debugw(ctx, "GetPorts", log.Fields{"deviceid": deviceID, "portType": portType})
npujar467fe752020-01-16 20:17:45 +0530863 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
khenaidoo92e62c52018-10-03 14:02:54 -0400864 return agent.getPorts(ctx, portType), nil
khenaidoob9203542018-09-17 22:56:37 -0400865 }
npujar1d86a522019-11-14 17:11:16 +0530866 return nil, status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoob9203542018-09-17 22:56:37 -0400867}
868
Kent Hagerman2b216042020-04-03 18:28:56 -0400869func (dMgr *Manager) UpdateDeviceStatus(ctx context.Context, deviceID string, operStatus voltha.OperStatus_Types, connStatus voltha.ConnectStatus_Types) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000870 logger.Debugw(ctx, "UpdateDeviceStatus", log.Fields{"deviceid": deviceID, "operStatus": operStatus, "connStatus": connStatus})
npujar467fe752020-01-16 20:17:45 +0530871 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
872 return agent.updateDeviceStatus(ctx, operStatus, connStatus)
khenaidoo92e62c52018-10-03 14:02:54 -0400873 }
npujar1d86a522019-11-14 17:11:16 +0530874 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo92e62c52018-10-03 14:02:54 -0400875}
876
Kent Hagerman2b216042020-04-03 18:28:56 -0400877func (dMgr *Manager) UpdateChildrenStatus(ctx context.Context, deviceID string, operStatus voltha.OperStatus_Types, connStatus voltha.ConnectStatus_Types) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000878 logger.Debugw(ctx, "UpdateChildrenStatus", log.Fields{"parentDeviceid": deviceID, "operStatus": operStatus, "connStatus": connStatus})
khenaidoo4d4802d2018-10-04 21:59:49 -0400879 var parentDevice *voltha.Device
880 var err error
Kent Hagerman45a13e42020-04-13 12:23:50 -0400881 if parentDevice, err = dMgr.getDevice(ctx, deviceID); err != nil {
khenaidoo4d4802d2018-10-04 21:59:49 -0400882 return status.Errorf(codes.Aborted, "%s", err.Error())
883 }
884 var childDeviceIds []string
Rohan Agrawal31f21802020-06-12 05:38:46 +0000885 if childDeviceIds, err = dMgr.getAllChildDeviceIds(ctx, parentDevice); err != nil {
khenaidoo4d4802d2018-10-04 21:59:49 -0400886 return status.Errorf(codes.Aborted, "%s", err.Error())
887 }
888 if len(childDeviceIds) == 0 {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000889 logger.Debugw(ctx, "no-child-device", log.Fields{"parentDeviceId": parentDevice.Id})
khenaidoo4d4802d2018-10-04 21:59:49 -0400890 }
npujar1d86a522019-11-14 17:11:16 +0530891 for _, childDeviceID := range childDeviceIds {
npujar467fe752020-01-16 20:17:45 +0530892 if agent := dMgr.getDeviceAgent(ctx, childDeviceID); agent != nil {
893 if err = agent.updateDeviceStatus(ctx, operStatus, connStatus); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530894 return status.Errorf(codes.Aborted, "childDevice:%s, error:%s", childDeviceID, err.Error())
khenaidoo4d4802d2018-10-04 21:59:49 -0400895 }
896 }
897 }
898 return nil
899}
900
Kent Hagerman2b216042020-04-03 18:28:56 -0400901func (dMgr *Manager) UpdatePortState(ctx context.Context, deviceID string, portType voltha.Port_PortType, portNo uint32, operStatus voltha.OperStatus_Types) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000902 logger.Debugw(ctx, "UpdatePortState", log.Fields{"deviceid": deviceID, "portType": portType, "portNo": portNo, "operStatus": operStatus})
npujar467fe752020-01-16 20:17:45 +0530903 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
904 if err := agent.updatePortState(ctx, portType, portNo, operStatus); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000905 logger.Errorw(ctx, "updating-port-state-failed", log.Fields{"deviceid": deviceID, "portNo": portNo, "error": err})
khenaidoo171b98e2019-10-31 11:48:15 -0400906 return err
907 }
908 // Notify the logical device manager to change the port state
Mahir Gunyel18fa0c92020-03-06 13:34:04 -0800909 // Do this for NNI and UNIs only. PON ports are not known by logical device
910 if portType == voltha.Port_ETHERNET_NNI || portType == voltha.Port_ETHERNET_UNI {
911 go func() {
912 err := dMgr.logicalDeviceMgr.updatePortState(context.Background(), deviceID, portNo, operStatus)
913 if err != nil {
914 // While we want to handle (catch) and log when
915 // an update to a port was not able to be
916 // propagated to the logical port, we can report
917 // it as a warning and not an error because it
918 // doesn't stop or modify processing.
919 // TODO: VOL-2707
Rohan Agrawal31f21802020-06-12 05:38:46 +0000920 logger.Warnw(ctx, "unable-to-update-logical-port-state", log.Fields{"error": err})
Mahir Gunyel18fa0c92020-03-06 13:34:04 -0800921 }
922 }()
923 }
khenaidoo442e7c72020-03-10 16:13:48 -0400924 return nil
khenaidoob9203542018-09-17 22:56:37 -0400925 }
npujar1d86a522019-11-14 17:11:16 +0530926 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoob9203542018-09-17 22:56:37 -0400927}
928
Kent Hagerman2b216042020-04-03 18:28:56 -0400929func (dMgr *Manager) DeleteAllPorts(ctx context.Context, deviceID string) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000930 logger.Debugw(ctx, "DeleteAllPorts", log.Fields{"deviceid": deviceID})
npujar467fe752020-01-16 20:17:45 +0530931 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
932 if err := agent.deleteAllPorts(ctx); err != nil {
khenaidoo0a822f92019-05-08 15:15:57 -0400933 return err
934 }
935 // Notify the logical device manager to remove all logical ports, if needed.
Kent Hagerman2b216042020-04-03 18:28:56 -0400936 // At this stage the device itself may gave been deleted already at a DeleteAllPorts
khenaidoo0a822f92019-05-08 15:15:57 -0400937 // typically is part of a device deletion phase.
Kent Hagerman45a13e42020-04-13 12:23:50 -0400938 if device, err := dMgr.getDevice(ctx, deviceID); err == nil {
npujar1d86a522019-11-14 17:11:16 +0530939 go func() {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000940 err = dMgr.logicalDeviceMgr.deleteAllLogicalPorts(context.Background(), device)
npujar1d86a522019-11-14 17:11:16 +0530941 if err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000942 logger.Errorw(ctx, "unable-to-delete-logical-ports", log.Fields{"error": err})
npujar1d86a522019-11-14 17:11:16 +0530943 }
944 }()
khenaidoo0a822f92019-05-08 15:15:57 -0400945 } else {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000946 logger.Warnw(ctx, "failed-to-retrieve-device", log.Fields{"deviceId": deviceID})
khenaidoo0a822f92019-05-08 15:15:57 -0400947 return err
948 }
949 return nil
950 }
npujar1d86a522019-11-14 17:11:16 +0530951 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo0a822f92019-05-08 15:15:57 -0400952}
953
Kent Hagerman2b216042020-04-03 18:28:56 -0400954//UpdatePortsState updates all ports on the device
955func (dMgr *Manager) UpdatePortsState(ctx context.Context, deviceID string, state voltha.OperStatus_Types) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000956 logger.Debugw(ctx, "UpdatePortsState", log.Fields{"deviceid": deviceID})
khenaidoo3ab34882019-05-02 21:33:30 -0400957
npujar467fe752020-01-16 20:17:45 +0530958 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
khenaidoo3ab34882019-05-02 21:33:30 -0400959 switch state {
960 case voltha.OperStatus_ACTIVE:
kesavandbc2d1622020-01-21 00:42:01 -0500961 if err := agent.updatePortsOperState(ctx, state); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000962 logger.Warnw(ctx, "updatePortsOperState-failed", log.Fields{"deviceId": deviceID, "error": err})
khenaidoo3ab34882019-05-02 21:33:30 -0400963 return err
964 }
965 case voltha.OperStatus_UNKNOWN:
kesavandbc2d1622020-01-21 00:42:01 -0500966 if err := agent.updatePortsOperState(ctx, state); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000967 logger.Warnw(ctx, "updatePortsOperState-failed", log.Fields{"deviceId": deviceID, "error": err})
khenaidoo3ab34882019-05-02 21:33:30 -0400968 return err
969 }
970 default:
971 return status.Error(codes.Unimplemented, "state-change-not-implemented")
972 }
973 // Notify the logical device about the state change
Kent Hagerman45a13e42020-04-13 12:23:50 -0400974 device, err := dMgr.getDevice(ctx, deviceID)
npujar1d86a522019-11-14 17:11:16 +0530975 if err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000976 logger.Warnw(ctx, "non-existent-device", log.Fields{"deviceId": deviceID, "error": err})
khenaidoo3ab34882019-05-02 21:33:30 -0400977 return err
khenaidoo3ab34882019-05-02 21:33:30 -0400978 }
kesavandbc2d1622020-01-21 00:42:01 -0500979 if err := dMgr.logicalDeviceMgr.updatePortsState(ctx, device, state); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000980 logger.Warnw(ctx, "failed-updating-ports-state", log.Fields{"deviceId": deviceID, "error": err})
npujar1d86a522019-11-14 17:11:16 +0530981 return err
982 }
983 return nil
khenaidoo3ab34882019-05-02 21:33:30 -0400984 }
npujar1d86a522019-11-14 17:11:16 +0530985 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo3ab34882019-05-02 21:33:30 -0400986}
987
Kent Hagerman2b216042020-04-03 18:28:56 -0400988func (dMgr *Manager) ChildDeviceDetected(ctx context.Context, parentDeviceID string, parentPortNo int64, deviceType string,
npujar1d86a522019-11-14 17:11:16 +0530989 channelID int64, vendorID string, serialNumber string, onuID int64) (*voltha.Device, error) {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000990 logger.Debugw(ctx, "ChildDeviceDetected", log.Fields{"parentDeviceId": parentDeviceID, "parentPortNo": parentPortNo, "deviceType": deviceType, "channelId": channelID, "vendorId": vendorID, "serialNumber": serialNumber, "onuId": onuID})
Chaitrashree G S4b3fada2019-07-28 23:55:25 -0700991
npujar1d86a522019-11-14 17:11:16 +0530992 if deviceType == "" && vendorID != "" {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000993 logger.Debug(ctx, "device-type-is-nil-fetching-device-type")
Kent Hagerman45a13e42020-04-13 12:23:50 -0400994 deviceTypes, err := dMgr.adapterMgr.ListDeviceTypes(ctx, nil)
995 if err != nil {
996 return nil, err
997 }
Kent Hagerman4f355f52020-03-30 16:01:33 -0400998 OLoop:
Kent Hagerman45a13e42020-04-13 12:23:50 -0400999 for _, dType := range deviceTypes.Items {
Kent Hagerman4f355f52020-03-30 16:01:33 -04001000 for _, v := range dType.VendorIds {
1001 if v == vendorID {
1002 deviceType = dType.Adapter
1003 break OLoop
Chaitrashree G S4b3fada2019-07-28 23:55:25 -07001004 }
1005 }
1006 }
1007 }
1008 //if no match found for the vendorid,report adapter with the custom error message
1009 if deviceType == "" {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001010 logger.Errorw(ctx, "failed-to-fetch-adapter-name ", log.Fields{"vendorId": vendorID})
npujar1d86a522019-11-14 17:11:16 +05301011 return nil, status.Errorf(codes.NotFound, "%s", vendorID)
Chaitrashree G S4b3fada2019-07-28 23:55:25 -07001012 }
khenaidoob9203542018-09-17 22:56:37 -04001013
1014 // Create the ONU device
1015 childDevice := &voltha.Device{}
khenaidoob9203542018-09-17 22:56:37 -04001016 childDevice.Type = deviceType
npujar1d86a522019-11-14 17:11:16 +05301017 childDevice.ParentId = parentDeviceID
khenaidoob9203542018-09-17 22:56:37 -04001018 childDevice.ParentPortNo = uint32(parentPortNo)
npujar1d86a522019-11-14 17:11:16 +05301019 childDevice.VendorId = vendorID
Matt Jeanneret4e241952019-02-28 11:16:04 -05001020 childDevice.SerialNumber = serialNumber
khenaidoob9203542018-09-17 22:56:37 -04001021 childDevice.Root = false
khenaidoo6fdf0ba2018-11-02 14:38:33 -04001022
khenaidoo442e7c72020-03-10 16:13:48 -04001023 // Get parent device type
1024 pAgent := dMgr.getDeviceAgent(ctx, parentDeviceID)
1025 if pAgent == nil {
npujar1d86a522019-11-14 17:11:16 +05301026 return nil, status.Errorf(codes.NotFound, "%s", parentDeviceID)
khenaidoo6fdf0ba2018-11-02 14:38:33 -04001027 }
khenaidoo442e7c72020-03-10 16:13:48 -04001028 if pAgent.deviceType == "" {
1029 return nil, status.Errorf(codes.FailedPrecondition, "device Type not set %s", parentDeviceID)
1030 }
khenaidoo6fdf0ba2018-11-02 14:38:33 -04001031
npujar467fe752020-01-16 20:17:45 +05301032 if device, err := dMgr.GetChildDevice(ctx, parentDeviceID, serialNumber, onuID, parentPortNo); err == nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001033 logger.Warnw(ctx, "child-device-exists", log.Fields{"parentId": parentDeviceID, "serialNumber": serialNumber})
Mahir Gunyel6deaa242019-06-27 04:53:33 -07001034 return device, status.Errorf(codes.AlreadyExists, "%s", serialNumber)
Matt Jeanneret4e241952019-02-28 11:16:04 -05001035 }
1036
khenaidoo442e7c72020-03-10 16:13:48 -04001037 childDevice.ProxyAddress = &voltha.Device_ProxyAddress{DeviceId: parentDeviceID, DeviceType: pAgent.deviceType, ChannelId: uint32(channelID), OnuId: uint32(onuID)}
khenaidoob9203542018-09-17 22:56:37 -04001038
1039 // Create and start a device agent for that device
Mahir Gunyel03de0d32020-06-03 01:36:59 -07001040 agent := newAgent(dMgr.adapterProxy, childDevice, dMgr, dMgr.dbPath, dMgr.dProxy, dMgr.defaultTimeout)
khenaidoo442e7c72020-03-10 16:13:48 -04001041 childDevice, err := agent.start(ctx, childDevice)
Scott Baker80678602019-11-14 16:57:36 -08001042 if err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001043 logger.Errorw(ctx, "error-starting-child-device", log.Fields{"parent-device-id": childDevice.ParentId, "child-device-id": agent.deviceID, "error": err})
Scott Baker80678602019-11-14 16:57:36 -08001044 return nil, err
1045 }
khenaidoo442e7c72020-03-10 16:13:48 -04001046 dMgr.addDeviceAgentToMap(agent)
khenaidoob9203542018-09-17 22:56:37 -04001047
1048 // Activate the child device
npujar467fe752020-01-16 20:17:45 +05301049 if agent = dMgr.getDeviceAgent(ctx, agent.deviceID); agent != nil {
npujar1d86a522019-11-14 17:11:16 +05301050 go func() {
npujar467fe752020-01-16 20:17:45 +05301051 err := agent.enableDevice(context.Background())
npujar1d86a522019-11-14 17:11:16 +05301052 if err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001053 logger.Errorw(ctx, "unable-to-enable-device", log.Fields{"error": err})
npujar1d86a522019-11-14 17:11:16 +05301054 }
1055 }()
khenaidoob9203542018-09-17 22:56:37 -04001056 }
1057
Scott Baker80678602019-11-14 16:57:36 -08001058 return childDevice, nil
khenaidoob9203542018-09-17 22:56:37 -04001059}
1060
Kent Hagerman2b216042020-04-03 18:28:56 -04001061func (dMgr *Manager) processTransition(ctx context.Context, device *voltha.Device, previousState *deviceState) error {
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001062 // This will be triggered on every state update
Rohan Agrawal31f21802020-06-12 05:38:46 +00001063 logger.Debugw(ctx, "state-transition", log.Fields{
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001064 "device": device.Id,
1065 "prev-admin-state": previousState.Admin,
1066 "prev-oper-state": previousState.Operational,
1067 "prev-conn-state": previousState.Connection,
1068 "curr-admin-state": device.AdminState,
1069 "curr-oper-state": device.OperStatus,
1070 "curr-conn-state": device.ConnectStatus,
1071 })
Rohan Agrawal31f21802020-06-12 05:38:46 +00001072 handlers := dMgr.stateTransitions.GetTransitionHandler(ctx, device, previousState)
khenaidoo92e62c52018-10-03 14:02:54 -04001073 if handlers == nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001074 logger.Debugw(ctx, "no-op-transition", log.Fields{"deviceId": device.Id})
khenaidoo92e62c52018-10-03 14:02:54 -04001075 return nil
khenaidoob9203542018-09-17 22:56:37 -04001076 }
Rohan Agrawal31f21802020-06-12 05:38:46 +00001077 logger.Debugw(ctx, "handler-found", log.Fields{"num-expectedHandlers": len(handlers), "isParent": device.Root, "current-data": device, "previous-state": previousState})
khenaidoo92e62c52018-10-03 14:02:54 -04001078 for _, handler := range handlers {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001079 logger.Debugw(ctx, "running-handler", log.Fields{"handler": funcName(handler)})
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001080 if err := handler(ctx, device); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001081 logger.Warnw(ctx, "handler-failed", log.Fields{"handler": funcName(handler), "error": err})
khenaidoo92e62c52018-10-03 14:02:54 -04001082 return err
1083 }
1084 }
khenaidoob9203542018-09-17 22:56:37 -04001085 return nil
1086}
1087
Kent Hagerman2b216042020-04-03 18:28:56 -04001088func (dMgr *Manager) packetOut(ctx context.Context, deviceID string, outPort uint32, packet *ofp.OfpPacketOut) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001089 logger.Debugw(ctx, "packetOut", log.Fields{"deviceId": deviceID, "outPort": outPort})
npujar467fe752020-01-16 20:17:45 +05301090 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
1091 return agent.packetOut(ctx, outPort, packet)
khenaidoofdbad6e2018-11-06 22:26:38 -05001092 }
npujar1d86a522019-11-14 17:11:16 +05301093 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoofdbad6e2018-11-06 22:26:38 -05001094}
1095
npujar1d86a522019-11-14 17:11:16 +05301096// PacketIn receives packet from adapter
Kent Hagerman2b216042020-04-03 18:28:56 -04001097func (dMgr *Manager) PacketIn(ctx context.Context, deviceID string, port uint32, transactionID string, packet []byte) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001098 logger.Debugw(ctx, "PacketIn", log.Fields{"deviceId": deviceID, "port": port})
khenaidoofdbad6e2018-11-06 22:26:38 -05001099 // Get the logical device Id based on the deviceId
1100 var device *voltha.Device
1101 var err error
Kent Hagerman45a13e42020-04-13 12:23:50 -04001102 if device, err = dMgr.getDevice(ctx, deviceID); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001103 logger.Errorw(ctx, "device-not-found", log.Fields{"deviceId": deviceID})
khenaidoofdbad6e2018-11-06 22:26:38 -05001104 return err
1105 }
khenaidoo43c82122018-11-22 18:38:28 -05001106 if !device.Root {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001107 logger.Errorw(ctx, "device-not-root", log.Fields{"deviceId": deviceID})
npujar1d86a522019-11-14 17:11:16 +05301108 return status.Errorf(codes.FailedPrecondition, "%s", deviceID)
khenaidoofdbad6e2018-11-06 22:26:38 -05001109 }
1110
npujar467fe752020-01-16 20:17:45 +05301111 if err := dMgr.logicalDeviceMgr.packetIn(ctx, device.ParentId, port, transactionID, packet); err != nil {
khenaidoofdbad6e2018-11-06 22:26:38 -05001112 return err
1113 }
1114 return nil
1115}
1116
Kent Hagerman2b216042020-04-03 18:28:56 -04001117func (dMgr *Manager) setParentID(ctx context.Context, device *voltha.Device, parentID string) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001118 logger.Debugw(ctx, "setParentId", log.Fields{"deviceId": device.Id, "parentId": parentID})
npujar467fe752020-01-16 20:17:45 +05301119 if agent := dMgr.getDeviceAgent(ctx, device.Id); agent != nil {
1120 return agent.setParentID(ctx, device, parentID)
khenaidooad06fd72019-10-28 12:26:05 -04001121 }
1122 return status.Errorf(codes.NotFound, "%s", device.Id)
1123}
1124
npujar1d86a522019-11-14 17:11:16 +05301125// CreateLogicalDevice creates logical device in core
Kent Hagerman2b216042020-04-03 18:28:56 -04001126func (dMgr *Manager) CreateLogicalDevice(ctx context.Context, cDevice *voltha.Device) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001127 logger.Info(ctx, "CreateLogicalDevice")
khenaidoo59ef7be2019-06-21 12:40:28 -04001128 // Verify whether the logical device has already been created
1129 if cDevice.ParentId != "" {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001130 logger.Debugw(ctx, "Parent device already exist.", log.Fields{"deviceId": cDevice.Id, "logicalDeviceId": cDevice.Id})
khenaidoo59ef7be2019-06-21 12:40:28 -04001131 return nil
1132 }
khenaidoob9203542018-09-17 22:56:37 -04001133 var err error
npujar467fe752020-01-16 20:17:45 +05301134 if _, err = dMgr.logicalDeviceMgr.createLogicalDevice(ctx, cDevice); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001135 logger.Warnw(ctx, "createlogical-device-error", log.Fields{"device": cDevice})
khenaidoob9203542018-09-17 22:56:37 -04001136 return err
1137 }
khenaidoob9203542018-09-17 22:56:37 -04001138 return nil
1139}
1140
npujar1d86a522019-11-14 17:11:16 +05301141// DeleteLogicalDevice deletes logical device from core
Kent Hagerman2b216042020-04-03 18:28:56 -04001142func (dMgr *Manager) DeleteLogicalDevice(ctx context.Context, cDevice *voltha.Device) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001143 logger.Info(ctx, "DeleteLogicalDevice")
khenaidoo92e62c52018-10-03 14:02:54 -04001144 var err error
npujar467fe752020-01-16 20:17:45 +05301145 if err = dMgr.logicalDeviceMgr.deleteLogicalDevice(ctx, cDevice); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001146 logger.Warnw(ctx, "deleteLogical-device-error", log.Fields{"deviceId": cDevice.Id})
khenaidoo92e62c52018-10-03 14:02:54 -04001147 return err
1148 }
1149 // Remove the logical device Id from the parent device
npujar1d86a522019-11-14 17:11:16 +05301150 logicalID := ""
npujar467fe752020-01-16 20:17:45 +05301151 dMgr.UpdateDeviceAttribute(ctx, cDevice.Id, "ParentId", logicalID)
khenaidoo92e62c52018-10-03 14:02:54 -04001152 return nil
1153}
1154
npujar1d86a522019-11-14 17:11:16 +05301155// DeleteLogicalPorts removes the logical ports associated with that deviceId
Kent Hagerman2b216042020-04-03 18:28:56 -04001156func (dMgr *Manager) DeleteLogicalPorts(ctx context.Context, cDevice *voltha.Device) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001157 logger.Debugw(ctx, "delete-all-logical-ports", log.Fields{"device-id": cDevice.Id})
khenaidoo442e7c72020-03-10 16:13:48 -04001158 if err := dMgr.logicalDeviceMgr.deleteLogicalPorts(ctx, cDevice.Id); err != nil {
khenaidooe132f522020-03-20 15:23:15 -04001159 // Just log the error. The logical device or port may already have been deleted before this callback is invoked.
Rohan Agrawal31f21802020-06-12 05:38:46 +00001160 logger.Warnw(ctx, "deleteLogical-ports-error", log.Fields{"device-id": cDevice.Id, "error": err})
khenaidoo0a822f92019-05-08 15:15:57 -04001161 }
1162 return nil
1163}
1164
Kent Hagerman2b216042020-04-03 18:28:56 -04001165func (dMgr *Manager) getParentDevice(ctx context.Context, childDevice *voltha.Device) *voltha.Device {
khenaidoo92e62c52018-10-03 14:02:54 -04001166 // Sanity check
1167 if childDevice.Root {
1168 // childDevice is the parent device
1169 return childDevice
1170 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001171 parentDevice, _ := dMgr.getDevice(ctx, childDevice.ParentId)
khenaidoo92e62c52018-10-03 14:02:54 -04001172 return parentDevice
1173}
1174
Kent Hagerman2b216042020-04-03 18:28:56 -04001175//ChildDevicesLost is invoked by an adapter to indicate that a parent device is in a state (Disabled) where it
khenaidoo0a822f92019-05-08 15:15:57 -04001176//cannot manage the child devices. This will trigger the Core to disable all the child devices.
Kent Hagerman2b216042020-04-03 18:28:56 -04001177func (dMgr *Manager) ChildDevicesLost(ctx context.Context, parentDeviceID string) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001178 logger.Debug(ctx, "ChildDevicesLost")
khenaidoo0a822f92019-05-08 15:15:57 -04001179 var err error
1180 var parentDevice *voltha.Device
Kent Hagerman45a13e42020-04-13 12:23:50 -04001181 if parentDevice, err = dMgr.getDevice(ctx, parentDeviceID); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001182 logger.Warnw(ctx, "failed-getting-device", log.Fields{"deviceId": parentDeviceID, "error": err})
khenaidoo0a822f92019-05-08 15:15:57 -04001183 return err
1184 }
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001185 return dMgr.DisableAllChildDevices(ctx, parentDevice)
khenaidoo0a822f92019-05-08 15:15:57 -04001186}
1187
Kent Hagerman2b216042020-04-03 18:28:56 -04001188//ChildDevicesDetected is invoked by an adapter when child devices are found, typically after after a
khenaidoo0a822f92019-05-08 15:15:57 -04001189// disable/enable sequence. This will trigger the Core to Enable all the child devices of that parent.
Kent Hagerman2b216042020-04-03 18:28:56 -04001190func (dMgr *Manager) ChildDevicesDetected(ctx context.Context, parentDeviceID string) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001191 logger.Debug(ctx, "ChildDevicesDetected")
khenaidoo0a822f92019-05-08 15:15:57 -04001192 var err error
1193 var parentDevice *voltha.Device
1194 var childDeviceIds []string
1195
Kent Hagerman45a13e42020-04-13 12:23:50 -04001196 if parentDevice, err = dMgr.getDevice(ctx, parentDeviceID); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001197 logger.Warnw(ctx, "failed-getting-device", log.Fields{"deviceId": parentDeviceID, "error": err})
khenaidoo0a822f92019-05-08 15:15:57 -04001198 return err
1199 }
1200
Rohan Agrawal31f21802020-06-12 05:38:46 +00001201 if childDeviceIds, err = dMgr.getAllChildDeviceIds(ctx, parentDevice); err != nil {
khenaidoo0a822f92019-05-08 15:15:57 -04001202 return status.Errorf(codes.NotFound, "%s", parentDevice.Id)
1203 }
1204 if len(childDeviceIds) == 0 {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001205 logger.Debugw(ctx, "no-child-device", log.Fields{"parentDeviceId": parentDevice.Id})
khenaidoo0a822f92019-05-08 15:15:57 -04001206 }
khenaidoo59ef7be2019-06-21 12:40:28 -04001207 allChildEnableRequestSent := true
npujar1d86a522019-11-14 17:11:16 +05301208 for _, childDeviceID := range childDeviceIds {
npujar467fe752020-01-16 20:17:45 +05301209 if agent := dMgr.getDeviceAgent(ctx, childDeviceID); agent != nil {
khenaidoo59ef7be2019-06-21 12:40:28 -04001210 // Run the children re-registration in its own routine
npujar1d86a522019-11-14 17:11:16 +05301211 go func() {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001212 err = agent.enableDevice(context.Background())
npujar1d86a522019-11-14 17:11:16 +05301213 if err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001214 logger.Errorw(ctx, "unable-to-enable-device", log.Fields{"error": err})
npujar1d86a522019-11-14 17:11:16 +05301215 }
1216 }()
khenaidoo59ef7be2019-06-21 12:40:28 -04001217 } else {
npujar1d86a522019-11-14 17:11:16 +05301218 err = status.Errorf(codes.Unavailable, "no agent for child device %s", childDeviceID)
Rohan Agrawal31f21802020-06-12 05:38:46 +00001219 logger.Errorw(ctx, "no-child-device-agent", log.Fields{"parentDeviceId": parentDevice.Id, "childId": childDeviceID})
khenaidoo59ef7be2019-06-21 12:40:28 -04001220 allChildEnableRequestSent = false
khenaidoo0a822f92019-05-08 15:15:57 -04001221 }
1222 }
khenaidoo59ef7be2019-06-21 12:40:28 -04001223 if !allChildEnableRequestSent {
khenaidoo0a822f92019-05-08 15:15:57 -04001224 return err
1225 }
1226 return nil
1227}
1228
khenaidoo4d4802d2018-10-04 21:59:49 -04001229/*
1230All the functions below are callback functions where they are invoked with the latest and previous data. We can
1231therefore use the data as is without trying to get the latest from the model.
1232*/
1233
khenaidoo0a822f92019-05-08 15:15:57 -04001234//DisableAllChildDevices is invoked as a callback when the parent device is disabled
Kent Hagerman2b216042020-04-03 18:28:56 -04001235func (dMgr *Manager) DisableAllChildDevices(ctx context.Context, parentCurrDevice *voltha.Device) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001236 logger.Debug(ctx, "DisableAllChildDevices")
khenaidoo92e62c52018-10-03 14:02:54 -04001237 var childDeviceIds []string
1238 var err error
Rohan Agrawal31f21802020-06-12 05:38:46 +00001239 if childDeviceIds, err = dMgr.getAllChildDeviceIds(ctx, parentCurrDevice); err != nil {
khenaidoo442e7c72020-03-10 16:13:48 -04001240 return status.Errorf(codes.NotFound, "%s", parentCurrDevice.Id)
khenaidoo92e62c52018-10-03 14:02:54 -04001241 }
1242 if len(childDeviceIds) == 0 {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001243 logger.Debugw(ctx, "no-child-device", log.Fields{"parentDeviceId": parentCurrDevice.Id})
khenaidoo92e62c52018-10-03 14:02:54 -04001244 }
npujar1d86a522019-11-14 17:11:16 +05301245 for _, childDeviceID := range childDeviceIds {
npujar467fe752020-01-16 20:17:45 +05301246 if agent := dMgr.getDeviceAgent(ctx, childDeviceID); agent != nil {
1247 if err = agent.disableDevice(ctx); err != nil {
khenaidooe132f522020-03-20 15:23:15 -04001248 // Just log the error - this error happens only if the child device was already in deleted state.
Rohan Agrawal31f21802020-06-12 05:38:46 +00001249 logger.Errorw(ctx, "failure-disable-device", log.Fields{"deviceId": childDeviceID, "error": err.Error()})
khenaidoo92e62c52018-10-03 14:02:54 -04001250 }
1251 }
1252 }
1253 return nil
1254}
1255
khenaidoo0a822f92019-05-08 15:15:57 -04001256//DeleteAllChildDevices is invoked as a callback when the parent device is deleted
Kent Hagerman2b216042020-04-03 18:28:56 -04001257func (dMgr *Manager) DeleteAllChildDevices(ctx context.Context, parentCurrDevice *voltha.Device) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001258 logger.Debug(ctx, "DeleteAllChildDevices")
khenaidoo4d4802d2018-10-04 21:59:49 -04001259 var childDeviceIds []string
khenaidoo92e62c52018-10-03 14:02:54 -04001260 var err error
Rohan Agrawal31f21802020-06-12 05:38:46 +00001261 if childDeviceIds, err = dMgr.getAllChildDeviceIds(ctx, parentCurrDevice); err != nil {
khenaidoo442e7c72020-03-10 16:13:48 -04001262 return status.Errorf(codes.NotFound, "%s", parentCurrDevice.Id)
khenaidoo92e62c52018-10-03 14:02:54 -04001263 }
khenaidoo4d4802d2018-10-04 21:59:49 -04001264 if len(childDeviceIds) == 0 {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001265 logger.Debugw(ctx, "no-child-device", log.Fields{"parentDeviceId": parentCurrDevice.Id})
khenaidoo4d4802d2018-10-04 21:59:49 -04001266 }
npujar1d86a522019-11-14 17:11:16 +05301267 for _, childDeviceID := range childDeviceIds {
npujar467fe752020-01-16 20:17:45 +05301268 if agent := dMgr.getDeviceAgent(ctx, childDeviceID); agent != nil {
1269 if err = agent.deleteDevice(ctx); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001270 logger.Warnw(ctx, "failure-delete-device", log.Fields{"deviceId": childDeviceID, "error": err.Error()})
khenaidoo4d4802d2018-10-04 21:59:49 -04001271 }
khenaidoo49085352020-01-13 19:15:43 -05001272 // No further action is required here. The deleteDevice will change the device state where the resulting
1273 // callback will take care of cleaning the child device agent.
khenaidoo4d4802d2018-10-04 21:59:49 -04001274 }
1275 }
khenaidoo4d4802d2018-10-04 21:59:49 -04001276 return nil
1277}
1278
Girish Gowdra408cd962020-03-11 14:31:31 -07001279//DeleteAllLogicalPorts is invoked as a callback when the parent device's connection status moves to UNREACHABLE
Kent Hagerman2b216042020-04-03 18:28:56 -04001280func (dMgr *Manager) DeleteAllLogicalPorts(ctx context.Context, parentDevice *voltha.Device) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001281 logger.Debugw(ctx, "delete-all-logical-ports", log.Fields{"parent-device-id": parentDevice.Id})
Girish Gowdra408cd962020-03-11 14:31:31 -07001282 if err := dMgr.logicalDeviceMgr.deleteAllLogicalPorts(ctx, parentDevice); err != nil {
khenaidooe132f522020-03-20 15:23:15 -04001283 // Just log error as logical device may already have been deleted
Rohan Agrawal31f21802020-06-12 05:38:46 +00001284 logger.Warnw(ctx, "delete-all-logical-ports-fail", log.Fields{"parent-device-id": parentDevice.Id, "error": err})
Girish Gowdra408cd962020-03-11 14:31:31 -07001285 }
1286 return nil
1287}
1288
1289//DeleteAllDeviceFlows is invoked as a callback when the parent device's connection status moves to UNREACHABLE
Kent Hagerman2b216042020-04-03 18:28:56 -04001290func (dMgr *Manager) DeleteAllDeviceFlows(ctx context.Context, parentDevice *voltha.Device) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001291 logger.Debugw(ctx, "delete-all-device-flows", log.Fields{"parent-device-id": parentDevice.Id})
Girish Gowdra408cd962020-03-11 14:31:31 -07001292 if agent := dMgr.getDeviceAgent(ctx, parentDevice.Id); agent != nil {
1293 if err := agent.deleteAllFlows(ctx); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001294 logger.Errorw(ctx, "error-deleting-all-device-flows", log.Fields{"parent-device-id": parentDevice.Id})
Girish Gowdra408cd962020-03-11 14:31:31 -07001295 return err
1296 }
1297 return nil
1298 }
1299 return status.Errorf(codes.NotFound, "%s", parentDevice.Id)
1300}
1301
khenaidoo4d4802d2018-10-04 21:59:49 -04001302//getAllChildDeviceIds is a helper method to get all the child device IDs from the device passed as parameter
Rohan Agrawal31f21802020-06-12 05:38:46 +00001303func (dMgr *Manager) getAllChildDeviceIds(ctx context.Context, parentDevice *voltha.Device) ([]string, error) {
1304 logger.Debugw(ctx, "getAllChildDeviceIds", log.Fields{"parentDeviceId": parentDevice.Id})
khenaidoo92e62c52018-10-03 14:02:54 -04001305 childDeviceIds := make([]string, 0)
khenaidoo4d4802d2018-10-04 21:59:49 -04001306 if parentDevice != nil {
1307 for _, port := range parentDevice.Ports {
1308 for _, peer := range port.Peers {
1309 childDeviceIds = append(childDeviceIds, peer.DeviceId)
1310 }
khenaidoo92e62c52018-10-03 14:02:54 -04001311 }
Rohan Agrawal31f21802020-06-12 05:38:46 +00001312 logger.Debugw(ctx, "returning-getAllChildDeviceIds", log.Fields{"parentDeviceId": parentDevice.Id, "childDeviceIds": childDeviceIds})
khenaidoo92e62c52018-10-03 14:02:54 -04001313 }
1314 return childDeviceIds, nil
1315}
1316
Kent Hagerman2b216042020-04-03 18:28:56 -04001317//GetAllChildDevices is a helper method to get all the child device IDs from the device passed as parameter
1318func (dMgr *Manager) GetAllChildDevices(ctx context.Context, parentDeviceID string) (*voltha.Devices, error) {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001319 logger.Debugw(ctx, "GetAllChildDevices", log.Fields{"parentDeviceId": parentDeviceID})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001320 if parentDevice, err := dMgr.getDevice(ctx, parentDeviceID); err == nil {
khenaidoo297cd252019-02-07 22:10:23 -05001321 childDevices := make([]*voltha.Device, 0)
Rohan Agrawal31f21802020-06-12 05:38:46 +00001322 if childDeviceIds, er := dMgr.getAllChildDeviceIds(ctx, parentDevice); er == nil {
npujar1d86a522019-11-14 17:11:16 +05301323 for _, deviceID := range childDeviceIds {
Kent Hagerman45a13e42020-04-13 12:23:50 -04001324 if d, e := dMgr.getDevice(ctx, deviceID); e == nil && d != nil {
khenaidoo297cd252019-02-07 22:10:23 -05001325 childDevices = append(childDevices, d)
1326 }
1327 }
1328 }
1329 return &voltha.Devices{Items: childDevices}, nil
1330 }
npujar1d86a522019-11-14 17:11:16 +05301331 return nil, status.Errorf(codes.NotFound, "%s", parentDeviceID)
khenaidoo297cd252019-02-07 22:10:23 -05001332}
1333
npujar1d86a522019-11-14 17:11:16 +05301334// SetupUNILogicalPorts creates UNI ports on the logical device that represents a child UNI interface
Kent Hagerman2b216042020-04-03 18:28:56 -04001335func (dMgr *Manager) SetupUNILogicalPorts(ctx context.Context, cDevice *voltha.Device) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001336 logger.Info(ctx, "addUNILogicalPort")
npujar467fe752020-01-16 20:17:45 +05301337 if err := dMgr.logicalDeviceMgr.setupUNILogicalPorts(ctx, cDevice); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001338 logger.Warnw(ctx, "addUNILogicalPort-error", log.Fields{"device": cDevice, "err": err})
khenaidoob9203542018-09-17 22:56:37 -04001339 return err
1340 }
1341 return nil
1342}
1343
Kent Hagerman45a13e42020-04-13 12:23:50 -04001344// convenience to avoid redefining
1345var operationFailureResp = &common.OperationResp{Code: voltha.OperationResp_OPERATION_FAILURE}
1346
1347// DownloadImage execute an image download request
1348func (dMgr *Manager) DownloadImage(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001349 logger.Debugw(ctx, "DownloadImage", log.Fields{"device-id": img.Id, "imageName": img.Name})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001350 agent := dMgr.getDeviceAgent(ctx, img.Id)
1351 if agent == nil {
1352 return operationFailureResp, status.Errorf(codes.NotFound, "%s", img.Id)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001353 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001354 resp, err := agent.downloadImage(ctx, img)
1355 if err != nil {
1356 return operationFailureResp, err
1357 }
1358 return resp, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001359}
1360
Kent Hagerman45a13e42020-04-13 12:23:50 -04001361// CancelImageDownload cancels image download request
1362func (dMgr *Manager) CancelImageDownload(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001363 logger.Debugw(ctx, "CancelImageDownload", log.Fields{"device-id": img.Id, "imageName": img.Name})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001364 agent := dMgr.getDeviceAgent(ctx, img.Id)
1365 if agent == nil {
1366 return operationFailureResp, status.Errorf(codes.NotFound, "%s", img.Id)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001367 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001368 resp, err := agent.cancelImageDownload(ctx, img)
1369 if err != nil {
1370 return operationFailureResp, err
1371 }
1372 return resp, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001373}
1374
Kent Hagerman45a13e42020-04-13 12:23:50 -04001375// ActivateImageUpdate activates image update request
1376func (dMgr *Manager) ActivateImageUpdate(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001377 logger.Debugw(ctx, "ActivateImageUpdate", log.Fields{"device-id": img.Id, "imageName": img.Name})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001378 agent := dMgr.getDeviceAgent(ctx, img.Id)
1379 if agent == nil {
1380 return operationFailureResp, status.Errorf(codes.NotFound, "%s", img.Id)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001381 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001382 resp, err := agent.activateImage(ctx, img)
1383 if err != nil {
1384 return operationFailureResp, err
1385 }
1386 return resp, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001387}
1388
Kent Hagerman45a13e42020-04-13 12:23:50 -04001389// RevertImageUpdate reverts image update
1390func (dMgr *Manager) RevertImageUpdate(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001391 logger.Debugw(ctx, "RevertImageUpdate", log.Fields{"device-id": img.Id, "imageName": img.Name})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001392 agent := dMgr.getDeviceAgent(ctx, img.Id)
1393 if agent == nil {
1394 return operationFailureResp, status.Errorf(codes.NotFound, "%s", img.Id)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001395 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001396 resp, err := agent.revertImage(ctx, img)
1397 if err != nil {
1398 return operationFailureResp, err
1399 }
1400 return resp, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001401}
1402
Kent Hagerman45a13e42020-04-13 12:23:50 -04001403// convenience to avoid redefining
1404var imageDownloadFailureResp = &voltha.ImageDownload{DownloadState: voltha.ImageDownload_DOWNLOAD_UNKNOWN}
1405
1406// GetImageDownloadStatus returns status of image download
1407func (dMgr *Manager) GetImageDownloadStatus(ctx context.Context, img *voltha.ImageDownload) (*voltha.ImageDownload, error) {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001408 logger.Debugw(ctx, "GetImageDownloadStatus", log.Fields{"device-id": img.Id, "imageName": img.Name})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001409 agent := dMgr.getDeviceAgent(ctx, img.Id)
1410 if agent == nil {
1411 return imageDownloadFailureResp, status.Errorf(codes.NotFound, "%s", img.Id)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001412 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001413 resp, err := agent.getImageDownloadStatus(ctx, img)
1414 if err != nil {
1415 return imageDownloadFailureResp, err
1416 }
1417 return resp, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001418}
1419
Kent Hagerman2b216042020-04-03 18:28:56 -04001420func (dMgr *Manager) UpdateImageDownload(ctx context.Context, deviceID string, img *voltha.ImageDownload) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001421 logger.Debugw(ctx, "UpdateImageDownload", log.Fields{"device-id": img.Id, "imageName": img.Name})
npujar467fe752020-01-16 20:17:45 +05301422 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
1423 if err := agent.updateImageDownload(ctx, img); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001424 logger.Debugw(ctx, "UpdateImageDownload-failed", log.Fields{"err": err, "imageName": img.Name})
khenaidoof5a5bfa2019-01-23 22:20:29 -05001425 return err
1426 }
1427 } else {
1428 return status.Errorf(codes.NotFound, "%s", img.Id)
1429 }
1430 return nil
1431}
1432
Kent Hagerman45a13e42020-04-13 12:23:50 -04001433// GetImageDownload returns image download
Kent Hagerman2b216042020-04-03 18:28:56 -04001434func (dMgr *Manager) GetImageDownload(ctx context.Context, img *voltha.ImageDownload) (*voltha.ImageDownload, error) {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001435 logger.Debugw(ctx, "GetImageDownload", log.Fields{"device-id": img.Id, "imageName": img.Name})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001436 agent := dMgr.getDeviceAgent(ctx, img.Id)
1437 if agent == nil {
1438 return imageDownloadFailureResp, status.Errorf(codes.NotFound, "%s", img.Id)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001439 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001440 resp, err := agent.getImageDownload(ctx, img)
1441 if err != nil {
1442 return imageDownloadFailureResp, err
1443 }
1444 return resp, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001445}
1446
Kent Hagerman45a13e42020-04-13 12:23:50 -04001447// ListImageDownloads returns image downloads
1448func (dMgr *Manager) ListImageDownloads(ctx context.Context, id *voltha.ID) (*voltha.ImageDownloads, error) {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001449 logger.Debugw(ctx, "ListImageDownloads", log.Fields{"device-id": id.Id})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001450 agent := dMgr.getDeviceAgent(ctx, id.Id)
1451 if agent == nil {
1452 return &voltha.ImageDownloads{Items: []*voltha.ImageDownload{imageDownloadFailureResp}}, status.Errorf(codes.NotFound, "%s", id.Id)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001453 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001454 resp, err := agent.listImageDownloads(ctx, id.Id)
1455 if err != nil {
1456 return &voltha.ImageDownloads{Items: []*voltha.ImageDownload{imageDownloadFailureResp}}, err
1457 }
1458 return resp, nil
1459}
1460
1461// GetImages returns all images for a specific device entry
1462func (dMgr *Manager) GetImages(ctx context.Context, id *voltha.ID) (*voltha.Images, error) {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001463 logger.Debugw(ctx, "GetImages", log.Fields{"device-id": id.Id})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001464 device, err := dMgr.getDevice(ctx, id.Id)
1465 if err != nil {
1466 return nil, err
1467 }
1468 return device.GetImages(), nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001469}
1470
Rohan Agrawal31f21802020-06-12 05:38:46 +00001471func (dMgr *Manager) NotifyInvalidTransition(ctx context.Context, device *voltha.Device) error {
1472 logger.Errorw(ctx, "NotifyInvalidTransition", log.Fields{
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001473 "device": device.Id,
1474 "curr-admin-state": device.AdminState,
1475 "curr-oper-state": device.OperStatus,
1476 "curr-conn-state": device.ConnectStatus,
Stephane Barbarieef6650d2019-07-18 12:15:09 -04001477 })
khenaidoo0a822f92019-05-08 15:15:57 -04001478 //TODO: notify over kafka?
1479 return nil
1480}
1481
khenaidoob9203542018-09-17 22:56:37 -04001482func funcName(f interface{}) string {
1483 p := reflect.ValueOf(f).Pointer()
1484 rf := runtime.FuncForPC(p)
1485 return rf.Name()
1486}
1487
npujar1d86a522019-11-14 17:11:16 +05301488// UpdateDeviceAttribute updates value of particular device attribute
Kent Hagerman2b216042020-04-03 18:28:56 -04001489func (dMgr *Manager) UpdateDeviceAttribute(ctx context.Context, deviceID string, attribute string, value interface{}) {
npujar1d86a522019-11-14 17:11:16 +05301490 if agent, ok := dMgr.deviceAgents.Load(deviceID); ok {
Kent Hagerman2b216042020-04-03 18:28:56 -04001491 agent.(*Agent).updateDeviceAttribute(ctx, attribute, value)
khenaidoob9203542018-09-17 22:56:37 -04001492 }
1493}
1494
npujar1d86a522019-11-14 17:11:16 +05301495// GetParentDeviceID returns parent device id, either from memory or from the dB, if present
Kent Hagerman2b216042020-04-03 18:28:56 -04001496func (dMgr *Manager) GetParentDeviceID(ctx context.Context, deviceID string) string {
Kent Hagerman45a13e42020-04-13 12:23:50 -04001497 if device, _ := dMgr.getDevice(ctx, deviceID); device != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001498 logger.Infow(ctx, "GetParentDeviceId", log.Fields{"deviceId": device.Id, "parentId": device.ParentId})
khenaidoo4c9e5592019-09-09 16:20:41 -04001499 return device.ParentId
khenaidoob9203542018-09-17 22:56:37 -04001500 }
khenaidoo4c9e5592019-09-09 16:20:41 -04001501 return ""
khenaidoob9203542018-09-17 22:56:37 -04001502}
serkant.uluderya334479d2019-04-10 08:26:15 -07001503
Kent Hagerman45a13e42020-04-13 12:23:50 -04001504func (dMgr *Manager) SimulateAlarm(ctx context.Context, simulateReq *voltha.SimulateAlarmRequest) (*common.OperationResp, error) {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001505 logger.Debugw(ctx, "SimulateAlarm", log.Fields{"id": simulateReq.Id, "Indicator": simulateReq.Indicator, "IntfId": simulateReq.IntfId,
Kent Hagerman45a13e42020-04-13 12:23:50 -04001506 "PortTypeName": simulateReq.PortTypeName, "OnuDeviceId": simulateReq.OnuDeviceId, "InverseBitErrorRate": simulateReq.InverseBitErrorRate,
1507 "Drift": simulateReq.Drift, "NewEqd": simulateReq.NewEqd, "OnuSerialNumber": simulateReq.OnuSerialNumber, "Operation": simulateReq.Operation})
1508 agent := dMgr.getDeviceAgent(ctx, simulateReq.Id)
1509 if agent == nil {
1510 return nil, status.Errorf(codes.NotFound, "%s", simulateReq.Id)
serkant.uluderya334479d2019-04-10 08:26:15 -07001511 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001512 if err := agent.simulateAlarm(ctx, simulateReq); err != nil {
1513 return nil, err
1514 }
1515 return &common.OperationResp{Code: common.OperationResp_OPERATION_SUCCESS}, nil
serkant.uluderya334479d2019-04-10 08:26:15 -07001516}
Mahir Gunyelfdee9212019-10-16 16:52:21 -07001517
Kent Hagerman2b216042020-04-03 18:28:56 -04001518func (dMgr *Manager) UpdateDeviceReason(ctx context.Context, deviceID string, reason string) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001519 logger.Debugw(ctx, "UpdateDeviceReason", log.Fields{"deviceid": deviceID, "reason": reason})
npujar467fe752020-01-16 20:17:45 +05301520 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
1521 return agent.updateDeviceReason(ctx, reason)
Mahir Gunyelfdee9212019-10-16 16:52:21 -07001522 }
npujar1d86a522019-11-14 17:11:16 +05301523 return status.Errorf(codes.NotFound, "%s", deviceID)
Mahir Gunyelfdee9212019-10-16 16:52:21 -07001524}
kesavandbc2d1622020-01-21 00:42:01 -05001525
Kent Hagerman45a13e42020-04-13 12:23:50 -04001526func (dMgr *Manager) EnablePort(ctx context.Context, port *voltha.Port) (*empty.Empty, error) {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001527 logger.Debugw(ctx, "EnablePort", log.Fields{"device-id": port.DeviceId, "port-no": port.PortNo})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001528 agent := dMgr.getDeviceAgent(ctx, port.DeviceId)
1529 if agent == nil {
1530 return nil, status.Errorf(codes.NotFound, "%s", port.DeviceId)
kesavandbc2d1622020-01-21 00:42:01 -05001531 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001532 return &empty.Empty{}, agent.enablePort(ctx, port)
kesavandbc2d1622020-01-21 00:42:01 -05001533}
1534
Kent Hagerman45a13e42020-04-13 12:23:50 -04001535func (dMgr *Manager) DisablePort(ctx context.Context, port *voltha.Port) (*empty.Empty, error) {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001536 logger.Debugw(ctx, "DisablePort", log.Fields{"device-id": port.DeviceId, "port-no": port.PortNo})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001537 agent := dMgr.getDeviceAgent(ctx, port.DeviceId)
1538 if agent == nil {
1539 return nil, status.Errorf(codes.NotFound, "%s", port.DeviceId)
kesavandbc2d1622020-01-21 00:42:01 -05001540 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001541 return &empty.Empty{}, agent.disablePort(ctx, port)
kesavandbc2d1622020-01-21 00:42:01 -05001542}
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001543
Kent Hagerman2b216042020-04-03 18:28:56 -04001544// ChildDeviceLost calls parent adapter to delete child device and all its references
1545func (dMgr *Manager) ChildDeviceLost(ctx context.Context, curr *voltha.Device) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001546 logger.Debugw(ctx, "childDeviceLost", log.Fields{"child-device-id": curr.Id, "parent-device-id": curr.ParentId})
khenaidoo442e7c72020-03-10 16:13:48 -04001547 if parentAgent := dMgr.getDeviceAgent(ctx, curr.ParentId); parentAgent != nil {
khenaidooe132f522020-03-20 15:23:15 -04001548 if err := parentAgent.ChildDeviceLost(ctx, curr); err != nil {
1549 // Just log the message and let the remaining pipeline proceed.
Rohan Agrawal31f21802020-06-12 05:38:46 +00001550 logger.Warnw(ctx, "childDeviceLost", log.Fields{"child-device-id": curr.Id, "parent-device-id": curr.ParentId, "error": err})
khenaidooe132f522020-03-20 15:23:15 -04001551 }
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001552 }
khenaidooe132f522020-03-20 15:23:15 -04001553 // Do not return an error as parent device may also have been deleted. Let the remaining pipeline proceed.
1554 return nil
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001555}
onkarkundargi87285252020-01-27 11:34:52 +05301556
Kent Hagerman45a13e42020-04-13 12:23:50 -04001557func (dMgr *Manager) StartOmciTestAction(ctx context.Context, request *voltha.OmciTestRequest) (*voltha.TestResponse, error) {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001558 logger.Debugw(ctx, "StartOmciTestAction", log.Fields{"device-id": request.Id, "uuid": request.Uuid})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001559 agent := dMgr.getDeviceAgent(ctx, request.Id)
1560 if agent == nil {
1561 return nil, status.Errorf(codes.NotFound, "%s", request.Id)
onkarkundargi87285252020-01-27 11:34:52 +05301562 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001563 return agent.startOmciTest(ctx, request)
onkarkundargi87285252020-01-27 11:34:52 +05301564}
Dinesh Belwalkarc1129f12020-02-27 10:41:33 -08001565
1566func (dMgr *Manager) GetExtValue(ctx context.Context, value *voltha.ValueSpecifier) (*voltha.ReturnValues, error) {
1567 log.Debugw("getExtValue", log.Fields{"onu-id": value.Id})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001568 cDevice, err := dMgr.getDevice(ctx, value.Id)
Dinesh Belwalkarc1129f12020-02-27 10:41:33 -08001569 if err != nil {
1570 return nil, status.Errorf(codes.Aborted, "%s", err.Error())
1571 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001572 pDevice, err := dMgr.getDevice(ctx, cDevice.ParentId)
Dinesh Belwalkarc1129f12020-02-27 10:41:33 -08001573 if err != nil {
1574 return nil, status.Errorf(codes.Aborted, "%s", err.Error())
1575 }
1576 if agent := dMgr.getDeviceAgent(ctx, cDevice.ParentId); agent != nil {
1577 resp, err := agent.getExtValue(ctx, pDevice, cDevice, value)
1578 if err != nil {
1579 return nil, err
1580 }
1581 log.Debugw("getExtValue-result", log.Fields{"result": resp})
1582 return resp, nil
1583 }
1584 return nil, status.Errorf(codes.NotFound, "%s", value.Id)
1585
1586}