blob: ad20aac7471dfeb5fa0508d53e6c1e9c41bc1bd8 [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()
Kent Hagerman2a07b862020-06-19 15:23:07 -040099 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
Kent Hagerman2a07b862020-06-19 15:23:07 -0400214// GetDevicePort returns the port details for a specific device port entry
215func (dMgr *Manager) GetDevicePort(ctx context.Context, deviceID string, portID uint32) (*voltha.Port, error) {
216 logger.Debugw(ctx, "ListDevicePorts", log.Fields{"device-id": deviceID})
217 agent := dMgr.getDeviceAgent(ctx, deviceID)
218 if agent == nil {
219 return nil, status.Errorf(codes.NotFound, "device-%s", deviceID)
220 }
221 return agent.getDevicePort(portID)
222}
223
Kent Hagerman45a13e42020-04-13 12:23:50 -0400224// ListDevicePorts returns the ports details for a specific device entry
225func (dMgr *Manager) ListDevicePorts(ctx context.Context, id *voltha.ID) (*voltha.Ports, error) {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000226 logger.Debugw(ctx, "ListDevicePorts", log.Fields{"device-id": id.Id})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400227 agent := dMgr.getDeviceAgent(ctx, id.Id)
228 if agent == nil {
229 return nil, status.Errorf(codes.NotFound, "device-%s", id.Id)
Kent Hagerman45a13e42020-04-13 12:23:50 -0400230 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400231
232 ports := agent.listDevicePorts()
233 ctr, ret := 0, make([]*voltha.Port, len(ports))
234 for _, port := range ports {
235 ret[ctr] = port
236 ctr++
237 }
238 return &voltha.Ports{Items: ret}, nil
Kent Hagerman45a13e42020-04-13 12:23:50 -0400239}
240
241// ListDeviceFlows returns the flow details for a specific device entry
242func (dMgr *Manager) ListDeviceFlows(ctx context.Context, id *voltha.ID) (*ofp.Flows, error) {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000243 logger.Debugw(ctx, "ListDeviceFlows", 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 Hagerman2a07b862020-06-19 15:23:07 -0400246 return nil, status.Errorf(codes.NotFound, "device-%s", id.Id)
Kent Hagerman45a13e42020-04-13 12:23:50 -0400247 }
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700248
249 flows := agent.listDeviceFlows()
250 ctr, ret := 0, make([]*ofp.OfpFlowStats, len(flows))
251 for _, flow := range flows {
252 ret[ctr] = flow
253 ctr++
254 }
255 return &openflow_13.Flows{Items: ret}, nil
Kent Hagerman45a13e42020-04-13 12:23:50 -0400256}
257
258// ListDeviceFlowGroups returns the flow group details for a specific device entry
259func (dMgr *Manager) ListDeviceFlowGroups(ctx context.Context, id *voltha.ID) (*voltha.FlowGroups, error) {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000260 logger.Debugw(ctx, "ListDeviceFlowGroups", log.Fields{"device-id": id.Id})
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700261 agent := dMgr.getDeviceAgent(ctx, id.Id)
262 if agent == nil {
Kent Hagerman45a13e42020-04-13 12:23:50 -0400263 return nil, status.Errorf(codes.NotFound, "device-%s", id.Id)
264 }
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700265 groups := agent.listDeviceGroups()
266 ctr, ret := 0, make([]*openflow_13.OfpGroupEntry, len(groups))
267 for _, group := range groups {
268 ret[ctr] = group
269 ctr++
270 }
271 return &voltha.FlowGroups{Items: ret}, nil
khenaidoo4d4802d2018-10-04 21:59:49 -0400272}
273
khenaidoo6d62c002019-05-15 21:57:03 -0400274// stopManagingDevice stops the management of the device as well as any of its reference device and logical device.
275// This function is called only in the Core that does not own this device. In the Core that owns this device then a
276// deletion deletion also includes removal of any reference of this device.
Kent Hagerman2b216042020-04-03 18:28:56 -0400277func (dMgr *Manager) stopManagingDevice(ctx context.Context, id string) {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000278 logger.Infow(ctx, "stopManagingDevice", log.Fields{"deviceId": id})
khenaidoo6d62c002019-05-15 21:57:03 -0400279 if dMgr.IsDeviceInCache(id) { // Proceed only if an agent is present for this device
npujar1d86a522019-11-14 17:11:16 +0530280 if root, _ := dMgr.IsRootDevice(id); root {
khenaidoo6d62c002019-05-15 21:57:03 -0400281 // stop managing the logical device
David Bainbridged1afd662020-03-26 18:27:41 -0700282 _ = dMgr.logicalDeviceMgr.stopManagingLogicalDeviceWithDeviceID(ctx, id)
khenaidoo6d62c002019-05-15 21:57:03 -0400283 }
npujar467fe752020-01-16 20:17:45 +0530284 if agent := dMgr.getDeviceAgent(ctx, id); agent != nil {
khenaidoo442e7c72020-03-10 16:13:48 -0400285 if err := agent.stop(ctx); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000286 logger.Warnw(ctx, "unable-to-stop-device-agent", log.Fields{"device-id": agent.deviceID, "error": err})
khenaidoo442e7c72020-03-10 16:13:48 -0400287 }
khenaidoo4c9e5592019-09-09 16:20:41 -0400288 dMgr.deleteDeviceAgentFromMap(agent)
khenaidoo6d62c002019-05-15 21:57:03 -0400289 }
290 }
291}
292
npujar1d86a522019-11-14 17:11:16 +0530293// RunPostDeviceDelete removes any reference of this device
Kent Hagerman2b216042020-04-03 18:28:56 -0400294func (dMgr *Manager) RunPostDeviceDelete(ctx context.Context, cDevice *voltha.Device) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000295 logger.Infow(ctx, "RunPostDeviceDelete", log.Fields{"deviceId": cDevice.Id})
npujar467fe752020-01-16 20:17:45 +0530296 dMgr.stopManagingDevice(ctx, cDevice.Id)
khenaidoo6d62c002019-05-15 21:57:03 -0400297 return nil
khenaidoo0a822f92019-05-08 15:15:57 -0400298}
299
Kent Hagerman45a13e42020-04-13 12:23:50 -0400300func (dMgr *Manager) GetDevice(ctx context.Context, id *voltha.ID) (*voltha.Device, error) {
301 return dMgr.getDevice(ctx, id.Id)
302}
303
304// getDevice will returns a device, either from memory or from the dB, if present
305func (dMgr *Manager) getDevice(ctx context.Context, id string) (*voltha.Device, error) {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000306 logger.Debugw(ctx, "getDevice", log.Fields{"deviceid": id})
npujar467fe752020-01-16 20:17:45 +0530307 if agent := dMgr.getDeviceAgent(ctx, id); agent != nil {
khenaidoo442e7c72020-03-10 16:13:48 -0400308 return agent.getDevice(ctx)
khenaidoo92e62c52018-10-03 14:02:54 -0400309 }
310 return nil, status.Errorf(codes.NotFound, "%s", id)
khenaidoob9203542018-09-17 22:56:37 -0400311}
312
Kent Hagerman2a07b862020-06-19 15:23:07 -0400313func (dMgr *Manager) listDevicePorts(ctx context.Context, id string) (map[uint32]*voltha.Port, error) {
314 logger.Debugw(ctx, "listDevicePorts", log.Fields{"deviceid": id})
315 agent := dMgr.getDeviceAgent(ctx, id)
316 if agent == nil {
317 return nil, status.Errorf(codes.NotFound, "%s", id)
318 }
319 return agent.listDevicePorts(), nil
320}
321
npujar1d86a522019-11-14 17:11:16 +0530322// GetChildDevice will return a device, either from memory or from the dB, if present
Kent Hagerman2b216042020-04-03 18:28:56 -0400323func (dMgr *Manager) GetChildDevice(ctx context.Context, parentDeviceID string, serialNumber string, onuID int64, parentPortNo int64) (*voltha.Device, error) {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000324 logger.Debugw(ctx, "GetChildDevice", log.Fields{"parentDeviceid": parentDeviceID, "serialNumber": serialNumber,
npujar1d86a522019-11-14 17:11:16 +0530325 "parentPortNo": parentPortNo, "onuId": onuID})
Matt Jeanneret4e241952019-02-28 11:16:04 -0500326
Kent Hagerman2a07b862020-06-19 15:23:07 -0400327 parentDevicePorts, err := dMgr.listDevicePorts(ctx, parentDeviceID)
328 if err != nil {
Matt Jeanneret4e241952019-02-28 11:16:04 -0500329 return nil, status.Errorf(codes.Aborted, "%s", err.Error())
330 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400331 childDeviceIds := dMgr.getAllChildDeviceIds(ctx, parentDevicePorts)
Matt Jeanneret4e241952019-02-28 11:16:04 -0500332 if len(childDeviceIds) == 0 {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400333 logger.Debugw(ctx, "no-child-devices", log.Fields{"parentDeviceId": parentDeviceID, "serialNumber": serialNumber, "onuId": onuID})
npujar1d86a522019-11-14 17:11:16 +0530334 return nil, status.Errorf(codes.NotFound, "%s", parentDeviceID)
Matt Jeanneret4e241952019-02-28 11:16:04 -0500335 }
336
337 var foundChildDevice *voltha.Device
Kent Hagerman2a07b862020-06-19 15:23:07 -0400338 for childDeviceID := range childDeviceIds {
npujar1d86a522019-11-14 17:11:16 +0530339 var found bool
Kent Hagerman45a13e42020-04-13 12:23:50 -0400340 if searchDevice, err := dMgr.getDevice(ctx, childDeviceID); err == nil {
Matt Jeanneret4e241952019-02-28 11:16:04 -0500341
npujar1d86a522019-11-14 17:11:16 +0530342 foundOnuID := false
343 if searchDevice.ProxyAddress.OnuId == uint32(onuID) {
Matt Jeanneret4e241952019-02-28 11:16:04 -0500344 if searchDevice.ParentPortNo == uint32(parentPortNo) {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400345 logger.Debugw(ctx, "found-child-by-onuid", log.Fields{"parentDeviceId": parentDeviceID, "onuId": onuID})
npujar1d86a522019-11-14 17:11:16 +0530346 foundOnuID = true
Matt Jeanneret4e241952019-02-28 11:16:04 -0500347 }
348 }
349
350 foundSerialNumber := false
351 if searchDevice.SerialNumber == serialNumber {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400352 logger.Debugw(ctx, "found-child-by-serialnumber", log.Fields{"parentDeviceId": parentDeviceID, "serialNumber": serialNumber})
Matt Jeanneret4e241952019-02-28 11:16:04 -0500353 foundSerialNumber = true
354 }
355
356 // if both onuId and serialNumber are provided both must be true for the device to be found
357 // otherwise whichever one found a match is good enough
npujar1d86a522019-11-14 17:11:16 +0530358 if onuID > 0 && serialNumber != "" {
359 found = foundOnuID && foundSerialNumber
Matt Jeanneret4e241952019-02-28 11:16:04 -0500360 } else {
npujar1d86a522019-11-14 17:11:16 +0530361 found = foundOnuID || foundSerialNumber
Matt Jeanneret4e241952019-02-28 11:16:04 -0500362 }
363
npujar1d86a522019-11-14 17:11:16 +0530364 if found {
Matt Jeanneret4e241952019-02-28 11:16:04 -0500365 foundChildDevice = searchDevice
366 break
367 }
368 }
369 }
370
371 if foundChildDevice != nil {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400372 logger.Debugw(ctx, "child-device-found", log.Fields{"parentDeviceId": parentDeviceID, "foundChildDevice": foundChildDevice})
Matt Jeanneret4e241952019-02-28 11:16:04 -0500373 return foundChildDevice, nil
374 }
375
Kent Hagerman2a07b862020-06-19 15:23:07 -0400376 logger.Debugw(ctx, "child-device-not-found", log.Fields{"parentDeviceId": parentDeviceID,
npujar1d86a522019-11-14 17:11:16 +0530377 "serialNumber": serialNumber, "onuId": onuID, "parentPortNo": parentPortNo})
378 return nil, status.Errorf(codes.NotFound, "%s", parentDeviceID)
Matt Jeanneret4e241952019-02-28 11:16:04 -0500379}
380
npujar1d86a522019-11-14 17:11:16 +0530381// GetChildDeviceWithProxyAddress will return a device based on proxy address
Kent Hagerman2b216042020-04-03 18:28:56 -0400382func (dMgr *Manager) GetChildDeviceWithProxyAddress(ctx context.Context, proxyAddress *voltha.Device_ProxyAddress) (*voltha.Device, error) {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000383 logger.Debugw(ctx, "GetChildDeviceWithProxyAddress", log.Fields{"proxyAddress": proxyAddress})
Matt Jeanneret2a20aaa2019-03-05 21:04:02 -0500384
Kent Hagerman2a07b862020-06-19 15:23:07 -0400385 parentDevicePorts, err := dMgr.listDevicePorts(ctx, proxyAddress.DeviceId)
386 if err != nil {
Matt Jeanneret2a20aaa2019-03-05 21:04:02 -0500387 return nil, status.Errorf(codes.Aborted, "%s", err.Error())
388 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400389 childDeviceIds := dMgr.getAllChildDeviceIds(ctx, parentDevicePorts)
Matt Jeanneret2a20aaa2019-03-05 21:04:02 -0500390 if len(childDeviceIds) == 0 {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400391 logger.Debugw(ctx, "no-child-devices", log.Fields{"parentDeviceId": proxyAddress.DeviceId})
Matt Jeanneret2a20aaa2019-03-05 21:04:02 -0500392 return nil, status.Errorf(codes.NotFound, "%s", proxyAddress)
393 }
394
395 var foundChildDevice *voltha.Device
Kent Hagerman2a07b862020-06-19 15:23:07 -0400396 for childDeviceID := range childDeviceIds {
Kent Hagerman45a13e42020-04-13 12:23:50 -0400397 if searchDevice, err := dMgr.getDevice(ctx, childDeviceID); err == nil {
Matt Jeanneret2a20aaa2019-03-05 21:04:02 -0500398 if searchDevice.ProxyAddress == proxyAddress {
399 foundChildDevice = searchDevice
400 break
401 }
402 }
403 }
404
405 if foundChildDevice != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000406 logger.Debugw(ctx, "child-device-found", log.Fields{"proxyAddress": proxyAddress})
Matt Jeanneret2a20aaa2019-03-05 21:04:02 -0500407 return foundChildDevice, nil
408 }
409
Rohan Agrawal31f21802020-06-12 05:38:46 +0000410 logger.Warnw(ctx, "child-device-not-found", log.Fields{"proxyAddress": proxyAddress})
Matt Jeanneret2a20aaa2019-03-05 21:04:02 -0500411 return nil, status.Errorf(codes.NotFound, "%s", proxyAddress)
412}
413
npujar1d86a522019-11-14 17:11:16 +0530414// IsDeviceInCache returns true if device is found in the map
Kent Hagerman2b216042020-04-03 18:28:56 -0400415func (dMgr *Manager) IsDeviceInCache(id string) bool {
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400416 _, exist := dMgr.deviceAgents.Load(id)
khenaidoo297cd252019-02-07 22:10:23 -0500417 return exist
418}
419
npujar1d86a522019-11-14 17:11:16 +0530420// IsRootDevice returns true if root device is found in the map
Kent Hagerman2b216042020-04-03 18:28:56 -0400421func (dMgr *Manager) IsRootDevice(id string) (bool, error) {
khenaidoo2c6a0992019-04-29 13:46:56 -0400422 dMgr.lockRootDeviceMap.RLock()
423 defer dMgr.lockRootDeviceMap.RUnlock()
424 if exist := dMgr.rootDevices[id]; exist {
425 return dMgr.rootDevices[id], nil
khenaidoo19d7b632018-10-30 10:49:50 -0400426 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400427 return false, nil
khenaidoo19d7b632018-10-30 10:49:50 -0400428}
429
Stephane Barbarieaa467942019-02-06 14:09:44 -0500430// ListDevices retrieves the latest devices from the data model
Kent Hagerman45a13e42020-04-13 12:23:50 -0400431func (dMgr *Manager) ListDevices(ctx context.Context, _ *empty.Empty) (*voltha.Devices, error) {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000432 logger.Debug(ctx, "ListDevices")
khenaidoob9203542018-09-17 22:56:37 -0400433 result := &voltha.Devices{}
Kent Hagerman4f355f52020-03-30 16:01:33 -0400434
435 var devices []*voltha.Device
Kent Hagermanf5a67352020-04-30 15:15:26 -0400436 if err := dMgr.dProxy.List(ctx, &devices); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000437 logger.Errorw(ctx, "failed-to-list-devices-from-cluster-proxy", log.Fields{"error": err})
Thomas Lee Se5a44012019-11-07 20:32:24 +0530438 return nil, err
439 }
Kent Hagerman4f355f52020-03-30 16:01:33 -0400440
441 for _, device := range devices {
442 // If device is not in memory then set it up
443 if !dMgr.IsDeviceInCache(device.Id) {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000444 logger.Debugw(ctx, "loading-device-from-Model", log.Fields{"id": device.Id})
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700445 agent := newAgent(dMgr.adapterProxy, device, dMgr, dMgr.dbPath, dMgr.dProxy, dMgr.defaultTimeout)
Kent Hagerman4f355f52020-03-30 16:01:33 -0400446 if _, err := agent.start(ctx, nil); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000447 logger.Warnw(ctx, "failure-starting-agent", log.Fields{"deviceId": device.Id})
Kent Hagerman4f355f52020-03-30 16:01:33 -0400448 } else {
449 dMgr.addDeviceAgentToMap(agent)
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500450 }
khenaidoob9203542018-09-17 22:56:37 -0400451 }
Kent Hagerman4f355f52020-03-30 16:01:33 -0400452 result.Items = append(result.Items, device)
khenaidoob9203542018-09-17 22:56:37 -0400453 }
Rohan Agrawal31f21802020-06-12 05:38:46 +0000454 logger.Debugw(ctx, "ListDevices-end", log.Fields{"len": len(result.Items)})
khenaidoob9203542018-09-17 22:56:37 -0400455 return result, nil
456}
457
Thomas Lee S51b5cb82019-10-14 14:49:34 +0530458//isParentDeviceExist checks whether device is already preprovisioned.
Kent Hagerman2b216042020-04-03 18:28:56 -0400459func (dMgr *Manager) isParentDeviceExist(ctx context.Context, newDevice *voltha.Device) (bool, error) {
Thomas Lee S51b5cb82019-10-14 14:49:34 +0530460 hostPort := newDevice.GetHostAndPort()
Kent Hagerman4f355f52020-03-30 16:01:33 -0400461 var devices []*voltha.Device
Kent Hagermanf5a67352020-04-30 15:15:26 -0400462 if err := dMgr.dProxy.List(ctx, &devices); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000463 logger.Errorw(ctx, "Failed to list devices from cluster data proxy", log.Fields{"error": err})
Thomas Lee Se5a44012019-11-07 20:32:24 +0530464 return false, err
465 }
Kent Hagerman4f355f52020-03-30 16:01:33 -0400466 for _, device := range devices {
467 if !device.Root {
468 continue
469 }
470 if hostPort != "" && hostPort == device.GetHostAndPort() && device.AdminState != voltha.AdminState_DELETED {
471 return true, nil
472 }
473 if newDevice.MacAddress != "" && newDevice.MacAddress == device.MacAddress && device.AdminState != voltha.AdminState_DELETED {
474 return true, nil
Thomas Lee S51b5cb82019-10-14 14:49:34 +0530475 }
476 }
Thomas Lee Se5a44012019-11-07 20:32:24 +0530477 return false, nil
Thomas Lee S51b5cb82019-10-14 14:49:34 +0530478}
479
khenaidoo6d62c002019-05-15 21:57:03 -0400480//getDeviceFromModelretrieves the device data from the model.
Kent Hagerman2b216042020-04-03 18:28:56 -0400481func (dMgr *Manager) getDeviceFromModel(ctx context.Context, deviceID string) (*voltha.Device, error) {
Kent Hagerman4f355f52020-03-30 16:01:33 -0400482 device := &voltha.Device{}
Kent Hagermanf5a67352020-04-30 15:15:26 -0400483 if have, err := dMgr.dProxy.Get(ctx, deviceID, device); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000484 logger.Errorw(ctx, "failed-to-get-device-info-from-cluster-proxy", log.Fields{"error": err})
Thomas Lee Se5a44012019-11-07 20:32:24 +0530485 return nil, err
Kent Hagerman4f355f52020-03-30 16:01:33 -0400486 } else if !have {
487 return nil, status.Error(codes.NotFound, deviceID)
Thomas Lee Se5a44012019-11-07 20:32:24 +0530488 }
Kent Hagerman4f355f52020-03-30 16:01:33 -0400489
490 return device, nil
khenaidoo6d62c002019-05-15 21:57:03 -0400491}
492
npujar1d86a522019-11-14 17:11:16 +0530493// loadDevice loads the deviceID in memory, if not present
Kent Hagerman2b216042020-04-03 18:28:56 -0400494func (dMgr *Manager) loadDevice(ctx context.Context, deviceID string) (*Agent, error) {
npujar1d86a522019-11-14 17:11:16 +0530495 if deviceID == "" {
khenaidoo297cd252019-02-07 22:10:23 -0500496 return nil, status.Error(codes.InvalidArgument, "deviceId empty")
497 }
khenaidoo4c9e5592019-09-09 16:20:41 -0400498 var err error
499 var device *voltha.Device
500 dMgr.devicesLoadingLock.Lock()
npujar1d86a522019-11-14 17:11:16 +0530501 if _, exist := dMgr.deviceLoadingInProgress[deviceID]; !exist {
502 if !dMgr.IsDeviceInCache(deviceID) {
503 dMgr.deviceLoadingInProgress[deviceID] = []chan int{make(chan int, 1)}
khenaidoo4c9e5592019-09-09 16:20:41 -0400504 dMgr.devicesLoadingLock.Unlock()
505 // Proceed with the loading only if the device exist in the Model (could have been deleted)
npujar467fe752020-01-16 20:17:45 +0530506 if device, err = dMgr.getDeviceFromModel(ctx, deviceID); err == nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000507 logger.Debugw(ctx, "loading-device", log.Fields{"deviceId": deviceID})
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700508 agent := newAgent(dMgr.adapterProxy, device, dMgr, dMgr.dbPath, dMgr.dProxy, dMgr.defaultTimeout)
npujar467fe752020-01-16 20:17:45 +0530509 if _, err = agent.start(ctx, nil); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000510 logger.Warnw(ctx, "Failure loading device", log.Fields{"deviceId": deviceID, "error": err})
khenaidoo4c9e5592019-09-09 16:20:41 -0400511 } else {
512 dMgr.addDeviceAgentToMap(agent)
513 }
514 } else {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000515 logger.Debugw(ctx, "Device not in model", log.Fields{"deviceId": deviceID})
khenaidoo6d62c002019-05-15 21:57:03 -0400516 }
khenaidoo4c9e5592019-09-09 16:20:41 -0400517 // announce completion of task to any number of waiting channels
518 dMgr.devicesLoadingLock.Lock()
npujar1d86a522019-11-14 17:11:16 +0530519 if v, ok := dMgr.deviceLoadingInProgress[deviceID]; ok {
khenaidoo4c9e5592019-09-09 16:20:41 -0400520 for _, ch := range v {
521 close(ch)
522 }
npujar1d86a522019-11-14 17:11:16 +0530523 delete(dMgr.deviceLoadingInProgress, deviceID)
khenaidoo4c9e5592019-09-09 16:20:41 -0400524 }
525 dMgr.devicesLoadingLock.Unlock()
khenaidoo6d62c002019-05-15 21:57:03 -0400526 } else {
khenaidoo4c9e5592019-09-09 16:20:41 -0400527 dMgr.devicesLoadingLock.Unlock()
khenaidoo297cd252019-02-07 22:10:23 -0500528 }
khenaidoo4c9e5592019-09-09 16:20:41 -0400529 } else {
530 ch := make(chan int, 1)
npujar1d86a522019-11-14 17:11:16 +0530531 dMgr.deviceLoadingInProgress[deviceID] = append(dMgr.deviceLoadingInProgress[deviceID], ch)
khenaidoo4c9e5592019-09-09 16:20:41 -0400532 dMgr.devicesLoadingLock.Unlock()
533 // Wait for the channel to be closed, implying the process loading this device is done.
534 <-ch
khenaidoo297cd252019-02-07 22:10:23 -0500535 }
npujar1d86a522019-11-14 17:11:16 +0530536 if agent, ok := dMgr.deviceAgents.Load(deviceID); ok {
Kent Hagerman2b216042020-04-03 18:28:56 -0400537 return agent.(*Agent), nil
khenaidoo297cd252019-02-07 22:10:23 -0500538 }
npujar1d86a522019-11-14 17:11:16 +0530539 return nil, status.Errorf(codes.Aborted, "Error loading device %s", deviceID)
khenaidoo297cd252019-02-07 22:10:23 -0500540}
541
542// loadRootDeviceParentAndChildren loads the children and parents of a root device in memory
Kent Hagerman2a07b862020-06-19 15:23:07 -0400543func (dMgr *Manager) loadRootDeviceParentAndChildren(ctx context.Context, device *voltha.Device, devicePorts map[uint32]*voltha.Port) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000544 logger.Debugw(ctx, "loading-parent-and-children", log.Fields{"deviceId": device.Id})
khenaidoo297cd252019-02-07 22:10:23 -0500545 if device.Root {
546 // Scenario A
547 if device.ParentId != "" {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400548 // Load logical device if needed.
npujar467fe752020-01-16 20:17:45 +0530549 if err := dMgr.logicalDeviceMgr.load(ctx, device.ParentId); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000550 logger.Warnw(ctx, "failure-loading-logical-device", log.Fields{"lDeviceId": device.ParentId})
khenaidoo297cd252019-02-07 22:10:23 -0500551 }
552 } else {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000553 logger.Debugw(ctx, "no-parent-to-load", log.Fields{"deviceId": device.Id})
khenaidoo297cd252019-02-07 22:10:23 -0500554 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400555 // Load all child devices, if needed
556 childDeviceIds := dMgr.getAllChildDeviceIds(ctx, devicePorts)
557 for childDeviceID := range childDeviceIds {
558 if _, err := dMgr.loadDevice(ctx, childDeviceID); err != nil {
559 logger.Warnw(ctx, "failure-loading-device", log.Fields{"deviceId": childDeviceID, "error": err})
560 return err
khenaidoo297cd252019-02-07 22:10:23 -0500561 }
khenaidoo297cd252019-02-07 22:10:23 -0500562 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400563 logger.Debugw(ctx, "loaded-children", log.Fields{"deviceId": device.Id, "numChildren": len(childDeviceIds)})
khenaidoo297cd252019-02-07 22:10:23 -0500564 }
565 return nil
566}
567
568// load loads the deviceId in memory, if not present, and also loads its accompanying parents and children. Loading
569// in memory is for improved performance. It is not imperative that a device needs to be in memory when a request
570// acting on the device is received by the core. In such a scenario, the Core will load the device in memory first
571// and the proceed with the request.
Kent Hagerman2b216042020-04-03 18:28:56 -0400572func (dMgr *Manager) load(ctx context.Context, deviceID string) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000573 logger.Debug(ctx, "load...")
khenaidoo297cd252019-02-07 22:10:23 -0500574 // 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 -0400575 var dAgent *Agent
khenaidoo297cd252019-02-07 22:10:23 -0500576 var err error
npujar467fe752020-01-16 20:17:45 +0530577 if dAgent, err = dMgr.loadDevice(ctx, deviceID); err != nil {
khenaidoo297cd252019-02-07 22:10:23 -0500578 return err
579 }
580 // Get the loaded device details
khenaidoo442e7c72020-03-10 16:13:48 -0400581 device, err := dAgent.getDevice(ctx)
582 if err != nil {
583 return err
584 }
khenaidoo297cd252019-02-07 22:10:23 -0500585
586 // If the device is in Pre-provisioning or deleted state stop here
587 if device.AdminState == voltha.AdminState_PREPROVISIONED || device.AdminState == voltha.AdminState_DELETED {
588 return nil
589 }
590
591 // Now we face two scenarios
592 if device.Root {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400593 devicePorts := dAgent.listDevicePorts()
594
khenaidoo297cd252019-02-07 22:10:23 -0500595 // Load all children as well as the parent of this device (logical_device)
Kent Hagerman2a07b862020-06-19 15:23:07 -0400596 if err := dMgr.loadRootDeviceParentAndChildren(ctx, device, devicePorts); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000597 logger.Warnw(ctx, "failure-loading-device-parent-and-children", log.Fields{"deviceId": deviceID})
khenaidoo297cd252019-02-07 22:10:23 -0500598 return err
599 }
Rohan Agrawal31f21802020-06-12 05:38:46 +0000600 logger.Debugw(ctx, "successfully-loaded-parent-and-children", log.Fields{"deviceId": deviceID})
khenaidoo297cd252019-02-07 22:10:23 -0500601 } else {
602 // Scenario B - use the parentId of that device (root device) to trigger the loading
603 if device.ParentId != "" {
npujar467fe752020-01-16 20:17:45 +0530604 return dMgr.load(ctx, device.ParentId)
khenaidoo297cd252019-02-07 22:10:23 -0500605 }
606 }
607 return nil
608}
609
khenaidoo7ccedd52018-12-14 16:48:54 -0500610// ListDeviceIds retrieves the latest device IDs information from the data model (memory data only)
Rohan Agrawal31f21802020-06-12 05:38:46 +0000611func (dMgr *Manager) ListDeviceIds(ctx context.Context, _ *empty.Empty) (*voltha.IDs, error) {
612 logger.Debug(ctx, "ListDeviceIDs")
khenaidoo7ccedd52018-12-14 16:48:54 -0500613 // Report only device IDs that are in the device agent map
614 return dMgr.listDeviceIdsFromMap(), nil
615}
616
Kent Hagerman45a13e42020-04-13 12:23:50 -0400617// ReconcileDevices is a request to a voltha core to update its list of managed devices. This will
618// trigger loading the devices along with their children and parent in memory
619func (dMgr *Manager) ReconcileDevices(ctx context.Context, ids *voltha.IDs) (*empty.Empty, error) {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000620 logger.Debugw(ctx, "ReconcileDevices", log.Fields{"numDevices": len(ids.Items)})
khenaidoo4c9e5592019-09-09 16:20:41 -0400621 if ids != nil && len(ids.Items) != 0 {
khenaidoo7ccedd52018-12-14 16:48:54 -0500622 toReconcile := len(ids.Items)
623 reconciled := 0
khenaidoo4c9e5592019-09-09 16:20:41 -0400624 var err error
khenaidoo7ccedd52018-12-14 16:48:54 -0500625 for _, id := range ids.Items {
npujar467fe752020-01-16 20:17:45 +0530626 if err = dMgr.load(ctx, id.Id); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000627 logger.Warnw(ctx, "failure-reconciling-device", log.Fields{"deviceId": id.Id, "error": err})
khenaidoo4c9e5592019-09-09 16:20:41 -0400628 } else {
npujar1d86a522019-11-14 17:11:16 +0530629 reconciled++
khenaidoo7ccedd52018-12-14 16:48:54 -0500630 }
631 }
632 if toReconcile != reconciled {
Kent Hagerman45a13e42020-04-13 12:23:50 -0400633 return nil, status.Errorf(codes.DataLoss, "less-device-reconciled-than-requested:%d/%d", reconciled, toReconcile)
khenaidoo7ccedd52018-12-14 16:48:54 -0500634 }
635 } else {
Kent Hagerman45a13e42020-04-13 12:23:50 -0400636 return nil, status.Errorf(codes.InvalidArgument, "empty-list-of-ids")
khenaidoo7ccedd52018-12-14 16:48:54 -0500637 }
Kent Hagerman45a13e42020-04-13 12:23:50 -0400638 return &empty.Empty{}, nil
khenaidoo7ccedd52018-12-14 16:48:54 -0500639}
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500640
khenaidooba6b6c42019-08-02 09:11:56 -0400641// isOkToReconcile validates whether a device is in the correct status to be reconciled
642func isOkToReconcile(device *voltha.Device) bool {
643 if device == nil {
644 return false
645 }
646 return device.AdminState != voltha.AdminState_PREPROVISIONED && device.AdminState != voltha.AdminState_DELETED
647}
648
649// adapterRestarted is invoked whenever an adapter is restarted
Kent Hagerman2b216042020-04-03 18:28:56 -0400650func (dMgr *Manager) adapterRestarted(ctx context.Context, adapter *voltha.Adapter) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000651 logger.Debugw(ctx, "adapter-restarted", log.Fields{"adapterId": adapter.Id, "vendor": adapter.Vendor,
Matteo Scandolod525ae32020-04-02 17:27:29 -0700652 "currentReplica": adapter.CurrentReplica, "totalReplicas": adapter.TotalReplicas, "endpoint": adapter.Endpoint})
khenaidooba6b6c42019-08-02 09:11:56 -0400653
654 // Let's reconcile the device managed by this Core only
David Bainbridged1afd662020-03-26 18:27:41 -0700655 if len(dMgr.rootDevices) == 0 {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000656 logger.Debugw(ctx, "nothing-to-reconcile", log.Fields{"adapterId": adapter.Id})
khenaidooba6b6c42019-08-02 09:11:56 -0400657 return nil
658 }
659
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500660 responses := make([]utils.Response, 0)
David Bainbridged1afd662020-03-26 18:27:41 -0700661 for rootDeviceID := range dMgr.rootDevices {
npujar467fe752020-01-16 20:17:45 +0530662 if rootDevice, _ := dMgr.getDeviceFromModel(ctx, rootDeviceID); rootDevice != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000663 isDeviceOwnedByService, err := dMgr.adapterProxy.IsDeviceOwnedByService(ctx, rootDeviceID, 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, "root-device-id": rootDeviceID, "adapterType": adapter.Type, "replica-number": adapter.CurrentReplica})
serkant.uluderya7d545aa2020-04-09 13:38:45 -0700666 continue
667 }
668 if isDeviceOwnedByService {
khenaidooba6b6c42019-08-02 09:11:56 -0400669 if isOkToReconcile(rootDevice) {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000670 logger.Debugw(ctx, "reconciling-root-device", log.Fields{"rootId": rootDevice.Id})
npujar467fe752020-01-16 20:17:45 +0530671 responses = append(responses, dMgr.sendReconcileDeviceRequest(ctx, rootDevice))
khenaidooba6b6c42019-08-02 09:11:56 -0400672 } else {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000673 logger.Debugw(ctx, "not-reconciling-root-device", log.Fields{"rootId": rootDevice.Id, "state": rootDevice.AdminState})
khenaidooba6b6c42019-08-02 09:11:56 -0400674 }
675 } else { // Should we be reconciling the root's children instead?
Kent Hagerman2a07b862020-06-19 15:23:07 -0400676 rootDevicePorts, _ := dMgr.listDevicePorts(ctx, rootDeviceID)
khenaidooba6b6c42019-08-02 09:11:56 -0400677 childManagedByAdapter:
Kent Hagerman2a07b862020-06-19 15:23:07 -0400678 for _, port := range rootDevicePorts {
khenaidooba6b6c42019-08-02 09:11:56 -0400679 for _, peer := range port.Peers {
npujar467fe752020-01-16 20:17:45 +0530680 if childDevice, _ := dMgr.getDeviceFromModel(ctx, peer.DeviceId); childDevice != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000681 isDeviceOwnedByService, err := dMgr.adapterProxy.IsDeviceOwnedByService(ctx, childDevice.Id, adapter.Type, adapter.CurrentReplica)
serkant.uluderya7d545aa2020-04-09 13:38:45 -0700682 if err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000683 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 -0700684 }
685 if isDeviceOwnedByService {
khenaidooba6b6c42019-08-02 09:11:56 -0400686 if isOkToReconcile(childDevice) {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000687 logger.Debugw(ctx, "reconciling-child-device", log.Fields{"child-device-id": childDevice.Id})
npujar467fe752020-01-16 20:17:45 +0530688 responses = append(responses, dMgr.sendReconcileDeviceRequest(ctx, childDevice))
khenaidooba6b6c42019-08-02 09:11:56 -0400689 } else {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000690 logger.Debugw(ctx, "not-reconciling-child-device", log.Fields{"child-device-id": childDevice.Id, "state": childDevice.AdminState})
khenaidooba6b6c42019-08-02 09:11:56 -0400691 }
692 } else {
693 // All child devices under a parent device are typically managed by the same adapter type.
694 // Therefore we only need to check whether the first device we retrieved is managed by that adapter
695 break childManagedByAdapter
696 }
697 }
698 }
699 }
700 }
701 }
702 }
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500703 if len(responses) > 0 {
khenaidooba6b6c42019-08-02 09:11:56 -0400704 // Wait for completion
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500705 if res := utils.WaitForNilOrErrorResponses(dMgr.defaultTimeout, responses...); res != nil {
khenaidooba6b6c42019-08-02 09:11:56 -0400706 return status.Errorf(codes.Aborted, "errors-%s", res)
707 }
708 } else {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000709 logger.Debugw(ctx, "no-managed-device-to-reconcile", log.Fields{"adapterId": adapter.Id})
khenaidooba6b6c42019-08-02 09:11:56 -0400710 }
711 return nil
712}
713
Kent Hagerman2b216042020-04-03 18:28:56 -0400714func (dMgr *Manager) sendReconcileDeviceRequest(ctx context.Context, device *voltha.Device) utils.Response {
khenaidooba6b6c42019-08-02 09:11:56 -0400715 // Send a reconcile request to the adapter. Since this Core may not be managing this device then there is no
716 // 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 +0530717 // 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 -0400718 // the adapter proxy.
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500719 response := utils.NewResponse()
Kent Hagerman2b216042020-04-03 18:28:56 -0400720 ch, err := dMgr.adapterProxy.ReconcileDevice(ctx, device)
khenaidoo442e7c72020-03-10 16:13:48 -0400721 if err != nil {
722 response.Error(err)
723 }
724 // Wait for adapter response in its own routine
725 go func() {
726 resp, ok := <-ch
727 if !ok {
728 response.Error(status.Errorf(codes.Aborted, "channel-closed-device: %s", device.Id))
729 } else if resp.Err != nil {
730 response.Error(resp.Err)
khenaidooba6b6c42019-08-02 09:11:56 -0400731 }
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500732 response.Done()
khenaidoo442e7c72020-03-10 16:13:48 -0400733 }()
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500734 return response
khenaidooba6b6c42019-08-02 09:11:56 -0400735}
736
Kent Hagerman2b216042020-04-03 18:28:56 -0400737func (dMgr *Manager) ReconcileChildDevices(ctx context.Context, parentDeviceID string) error {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400738 if parentDevicePorts, err := dMgr.listDevicePorts(ctx, parentDeviceID); err == nil {
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500739 responses := make([]utils.Response, 0)
Kent Hagerman2a07b862020-06-19 15:23:07 -0400740 for _, port := range parentDevicePorts {
khenaidooba6b6c42019-08-02 09:11:56 -0400741 for _, peer := range port.Peers {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400742 if childDevice, err := dMgr.getDeviceFromModel(ctx, peer.DeviceId); err == nil {
npujar467fe752020-01-16 20:17:45 +0530743 responses = append(responses, dMgr.sendReconcileDeviceRequest(ctx, childDevice))
khenaidooba6b6c42019-08-02 09:11:56 -0400744 }
745 }
746 }
747 // Wait for completion
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500748 if res := utils.WaitForNilOrErrorResponses(dMgr.defaultTimeout, responses...); res != nil {
khenaidooba6b6c42019-08-02 09:11:56 -0400749 return status.Errorf(codes.Aborted, "errors-%s", res)
750 }
751 }
752 return nil
753}
754
Kent Hagerman2b216042020-04-03 18:28:56 -0400755func (dMgr *Manager) UpdateDeviceUsingAdapterData(ctx context.Context, device *voltha.Device) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000756 logger.Debugw(ctx, "UpdateDeviceUsingAdapterData", log.Fields{"deviceid": device.Id, "device": device})
npujar467fe752020-01-16 20:17:45 +0530757 if agent := dMgr.getDeviceAgent(ctx, device.Id); agent != nil {
758 return agent.updateDeviceUsingAdapterData(ctx, device)
khenaidoob9203542018-09-17 22:56:37 -0400759 }
760 return status.Errorf(codes.NotFound, "%s", device.Id)
761}
762
khenaidoo0db4c812020-05-27 15:27:30 -0400763func (dMgr *Manager) addPeerPort(ctx context.Context, deviceID string, port *voltha.Port) error {
764 meAsPeer := &voltha.Port_PeerPort{DeviceId: deviceID, PortNo: port.PortNo}
765 for _, peerPort := range port.Peers {
766 if agent := dMgr.getDeviceAgent(ctx, peerPort.DeviceId); agent != nil {
767 if err := agent.addPeerPort(ctx, meAsPeer); err != nil {
768 return err
769 }
770 }
771 }
772 // Notify the logical device manager to setup a logical port, if needed. If the added port is an NNI or UNI
773 // then a logical port will be added to the logical device and the device route generated. If the port is a
774 // PON port then only the device graph will be generated.
775 device, err := dMgr.getDevice(ctx, deviceID)
776 if err != nil {
777 return err
778 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400779 ports, err := dMgr.listDevicePorts(ctx, deviceID)
780 if err != nil {
781 return err
782 }
783 if err = dMgr.logicalDeviceMgr.updateLogicalPort(context.Background(), device, ports, port); err != nil {
khenaidoo0db4c812020-05-27 15:27:30 -0400784 return err
785 }
786 return nil
787}
788
Kent Hagerman2b216042020-04-03 18:28:56 -0400789func (dMgr *Manager) AddPort(ctx context.Context, deviceID string, port *voltha.Port) error {
npujar467fe752020-01-16 20:17:45 +0530790 agent := dMgr.getDeviceAgent(ctx, deviceID)
npujar1d86a522019-11-14 17:11:16 +0530791 if agent != nil {
npujar467fe752020-01-16 20:17:45 +0530792 if err := agent.addPort(ctx, port); err != nil {
khenaidoo92e62c52018-10-03 14:02:54 -0400793 return err
794 }
khenaidoo0db4c812020-05-27 15:27:30 -0400795 // Setup peer ports in its own routine
796 go func() {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000797 if err := dMgr.addPeerPort(context.Background(), deviceID, port); err != nil {
798 logger.Errorw(ctx, "unable-to-add-peer-port", log.Fields{"error": err, "device-id": deviceID})
khenaidoo92e62c52018-10-03 14:02:54 -0400799 }
khenaidoo0db4c812020-05-27 15:27:30 -0400800 }()
khenaidoo92e62c52018-10-03 14:02:54 -0400801 return nil
khenaidoob9203542018-09-17 22:56:37 -0400802 }
npujar1d86a522019-11-14 17:11:16 +0530803 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoob9203542018-09-17 22:56:37 -0400804}
805
Kent Hagerman2b216042020-04-03 18:28:56 -0400806func (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 +0000807 logger.Debugw(ctx, "addFlowsAndGroups", log.Fields{"deviceid": deviceID, "groups:": groups, "flowMetadata": flowMetadata})
npujar467fe752020-01-16 20:17:45 +0530808 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
809 return agent.addFlowsAndGroups(ctx, flows, groups, flowMetadata)
khenaidoo0458db62019-06-20 08:50:36 -0400810 }
npujar1d86a522019-11-14 17:11:16 +0530811 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo0458db62019-06-20 08:50:36 -0400812}
813
khenaidoo787224a2020-04-16 18:08:47 -0400814// deleteParentFlows removes flows from the parent device based on specific attributes
815func (dMgr *Manager) deleteParentFlows(ctx context.Context, deviceID string, uniPort uint32, metadata *voltha.FlowMetadata) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000816 logger.Debugw(ctx, "deleteParentFlows", log.Fields{"device-id": deviceID, "uni-port": uniPort, "metadata": metadata})
khenaidoo787224a2020-04-16 18:08:47 -0400817 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400818 if !agent.isRootDevice {
khenaidoo787224a2020-04-16 18:08:47 -0400819 return status.Errorf(codes.FailedPrecondition, "not-a-parent-device-%s", deviceID)
820 }
821 return agent.filterOutFlows(ctx, uniPort, metadata)
822 }
823 return status.Errorf(codes.NotFound, "%s", deviceID)
824}
825
Kent Hagerman2b216042020-04-03 18:28:56 -0400826func (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 +0000827 logger.Debugw(ctx, "deleteFlowsAndGroups", log.Fields{"deviceid": deviceID})
npujar467fe752020-01-16 20:17:45 +0530828 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
829 return agent.deleteFlowsAndGroups(ctx, flows, groups, flowMetadata)
khenaidoo0458db62019-06-20 08:50:36 -0400830 }
npujar1d86a522019-11-14 17:11:16 +0530831 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo0458db62019-06-20 08:50:36 -0400832}
833
Kent Hagerman2b216042020-04-03 18:28:56 -0400834func (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 +0000835 logger.Debugw(ctx, "updateFlowsAndGroups", log.Fields{"deviceid": deviceID})
npujar467fe752020-01-16 20:17:45 +0530836 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
837 return agent.updateFlowsAndGroups(ctx, flows, groups, flowMetadata)
khenaidoo19d7b632018-10-30 10:49:50 -0400838 }
npujar1d86a522019-11-14 17:11:16 +0530839 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo19d7b632018-10-30 10:49:50 -0400840}
841
Kent Hagerman45a13e42020-04-13 12:23:50 -0400842// UpdateDevicePmConfigs updates the PM configs. This is executed when the northbound gRPC API is invoked, typically
khenaidoob3127472019-07-24 21:04:55 -0400843// following a user action
Kent Hagerman45a13e42020-04-13 12:23:50 -0400844func (dMgr *Manager) UpdateDevicePmConfigs(ctx context.Context, configs *voltha.PmConfigs) (*empty.Empty, error) {
845 if configs.Id == "" {
846 return nil, status.Error(codes.FailedPrecondition, "invalid-device-Id")
khenaidoob3127472019-07-24 21:04:55 -0400847 }
Kent Hagerman45a13e42020-04-13 12:23:50 -0400848 agent := dMgr.getDeviceAgent(ctx, configs.Id)
849 if agent == nil {
850 return nil, status.Errorf(codes.NotFound, "%s", configs.Id)
851 }
852 return &empty.Empty{}, agent.updatePmConfigs(ctx, configs)
khenaidoob3127472019-07-24 21:04:55 -0400853}
854
Kent Hagerman2b216042020-04-03 18:28:56 -0400855// InitPmConfigs initialize the pm configs as defined by the adapter.
856func (dMgr *Manager) InitPmConfigs(ctx context.Context, deviceID string, pmConfigs *voltha.PmConfigs) error {
khenaidoob3127472019-07-24 21:04:55 -0400857 if pmConfigs.Id == "" {
858 return status.Errorf(codes.FailedPrecondition, "invalid-device-Id")
859 }
npujar467fe752020-01-16 20:17:45 +0530860 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
861 return agent.initPmConfigs(ctx, pmConfigs)
khenaidoob9203542018-09-17 22:56:37 -0400862 }
npujar1d86a522019-11-14 17:11:16 +0530863 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoob9203542018-09-17 22:56:37 -0400864}
865
Kent Hagerman45a13e42020-04-13 12:23:50 -0400866// ListDevicePmConfigs returns pm configs of device
867func (dMgr *Manager) ListDevicePmConfigs(ctx context.Context, id *voltha.ID) (*voltha.PmConfigs, error) {
868 agent := dMgr.getDeviceAgent(ctx, id.Id)
869 if agent == nil {
870 return nil, status.Errorf(codes.NotFound, "%s", id.Id)
khenaidoob3127472019-07-24 21:04:55 -0400871 }
Kent Hagerman45a13e42020-04-13 12:23:50 -0400872 return agent.listPmConfigs(ctx)
khenaidoob3127472019-07-24 21:04:55 -0400873}
874
Kent Hagerman2b216042020-04-03 18:28:56 -0400875func (dMgr *Manager) getSwitchCapability(ctx context.Context, deviceID string) (*ic.SwitchCapability, error) {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000876 logger.Debugw(ctx, "getSwitchCapability", log.Fields{"deviceid": deviceID})
npujar467fe752020-01-16 20:17:45 +0530877 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
khenaidoob9203542018-09-17 22:56:37 -0400878 return agent.getSwitchCapability(ctx)
879 }
npujar1d86a522019-11-14 17:11:16 +0530880 return nil, status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoob9203542018-09-17 22:56:37 -0400881}
882
Kent Hagerman2b216042020-04-03 18:28:56 -0400883func (dMgr *Manager) GetPorts(ctx context.Context, deviceID string, portType voltha.Port_PortType) (*voltha.Ports, error) {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000884 logger.Debugw(ctx, "GetPorts", log.Fields{"deviceid": deviceID, "portType": portType})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400885 agent := dMgr.getDeviceAgent(ctx, deviceID)
886 if agent == nil {
887 return nil, status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoob9203542018-09-17 22:56:37 -0400888 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400889 return agent.getPorts(ctx, portType), nil
khenaidoob9203542018-09-17 22:56:37 -0400890}
891
Kent Hagerman2b216042020-04-03 18:28:56 -0400892func (dMgr *Manager) UpdateDeviceStatus(ctx context.Context, deviceID string, operStatus voltha.OperStatus_Types, connStatus voltha.ConnectStatus_Types) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000893 logger.Debugw(ctx, "UpdateDeviceStatus", log.Fields{"deviceid": deviceID, "operStatus": operStatus, "connStatus": connStatus})
npujar467fe752020-01-16 20:17:45 +0530894 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
895 return agent.updateDeviceStatus(ctx, operStatus, connStatus)
khenaidoo92e62c52018-10-03 14:02:54 -0400896 }
npujar1d86a522019-11-14 17:11:16 +0530897 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo92e62c52018-10-03 14:02:54 -0400898}
899
Kent Hagerman2b216042020-04-03 18:28:56 -0400900func (dMgr *Manager) UpdateChildrenStatus(ctx context.Context, deviceID string, operStatus voltha.OperStatus_Types, connStatus voltha.ConnectStatus_Types) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000901 logger.Debugw(ctx, "UpdateChildrenStatus", log.Fields{"parentDeviceid": deviceID, "operStatus": operStatus, "connStatus": connStatus})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400902 parentDevicePorts, err := dMgr.listDevicePorts(ctx, deviceID)
903 if err != nil {
khenaidoo4d4802d2018-10-04 21:59:49 -0400904 return status.Errorf(codes.Aborted, "%s", err.Error())
905 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400906 for childDeviceID := range dMgr.getAllChildDeviceIds(ctx, parentDevicePorts) {
npujar467fe752020-01-16 20:17:45 +0530907 if agent := dMgr.getDeviceAgent(ctx, childDeviceID); agent != nil {
908 if err = agent.updateDeviceStatus(ctx, operStatus, connStatus); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530909 return status.Errorf(codes.Aborted, "childDevice:%s, error:%s", childDeviceID, err.Error())
khenaidoo4d4802d2018-10-04 21:59:49 -0400910 }
911 }
912 }
913 return nil
914}
915
Kent Hagerman2b216042020-04-03 18:28:56 -0400916func (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 +0000917 logger.Debugw(ctx, "UpdatePortState", log.Fields{"deviceid": deviceID, "portType": portType, "portNo": portNo, "operStatus": operStatus})
npujar467fe752020-01-16 20:17:45 +0530918 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
919 if err := agent.updatePortState(ctx, portType, portNo, operStatus); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000920 logger.Errorw(ctx, "updating-port-state-failed", log.Fields{"deviceid": deviceID, "portNo": portNo, "error": err})
khenaidoo171b98e2019-10-31 11:48:15 -0400921 return err
922 }
923 // Notify the logical device manager to change the port state
Mahir Gunyel18fa0c92020-03-06 13:34:04 -0800924 // Do this for NNI and UNIs only. PON ports are not known by logical device
925 if portType == voltha.Port_ETHERNET_NNI || portType == voltha.Port_ETHERNET_UNI {
926 go func() {
927 err := dMgr.logicalDeviceMgr.updatePortState(context.Background(), deviceID, portNo, operStatus)
928 if err != nil {
929 // While we want to handle (catch) and log when
930 // an update to a port was not able to be
931 // propagated to the logical port, we can report
932 // it as a warning and not an error because it
933 // doesn't stop or modify processing.
934 // TODO: VOL-2707
Rohan Agrawal31f21802020-06-12 05:38:46 +0000935 logger.Warnw(ctx, "unable-to-update-logical-port-state", log.Fields{"error": err})
Mahir Gunyel18fa0c92020-03-06 13:34:04 -0800936 }
937 }()
938 }
khenaidoo442e7c72020-03-10 16:13:48 -0400939 return nil
khenaidoob9203542018-09-17 22:56:37 -0400940 }
npujar1d86a522019-11-14 17:11:16 +0530941 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoob9203542018-09-17 22:56:37 -0400942}
943
Kent Hagerman2b216042020-04-03 18:28:56 -0400944func (dMgr *Manager) DeleteAllPorts(ctx context.Context, deviceID string) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000945 logger.Debugw(ctx, "DeleteAllPorts", log.Fields{"deviceid": deviceID})
npujar467fe752020-01-16 20:17:45 +0530946 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
947 if err := agent.deleteAllPorts(ctx); err != nil {
khenaidoo0a822f92019-05-08 15:15:57 -0400948 return err
949 }
950 // Notify the logical device manager to remove all logical ports, if needed.
Kent Hagerman2b216042020-04-03 18:28:56 -0400951 // At this stage the device itself may gave been deleted already at a DeleteAllPorts
khenaidoo0a822f92019-05-08 15:15:57 -0400952 // typically is part of a device deletion phase.
Kent Hagerman45a13e42020-04-13 12:23:50 -0400953 if device, err := dMgr.getDevice(ctx, deviceID); err == nil {
npujar1d86a522019-11-14 17:11:16 +0530954 go func() {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000955 err = dMgr.logicalDeviceMgr.deleteAllLogicalPorts(context.Background(), device)
npujar1d86a522019-11-14 17:11:16 +0530956 if err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000957 logger.Errorw(ctx, "unable-to-delete-logical-ports", log.Fields{"error": err})
npujar1d86a522019-11-14 17:11:16 +0530958 }
959 }()
khenaidoo0a822f92019-05-08 15:15:57 -0400960 } else {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000961 logger.Warnw(ctx, "failed-to-retrieve-device", log.Fields{"deviceId": deviceID})
khenaidoo0a822f92019-05-08 15:15:57 -0400962 return err
963 }
964 return nil
965 }
npujar1d86a522019-11-14 17:11:16 +0530966 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo0a822f92019-05-08 15:15:57 -0400967}
968
Kent Hagerman2b216042020-04-03 18:28:56 -0400969//UpdatePortsState updates all ports on the device
Kent Hagerman2a07b862020-06-19 15:23:07 -0400970func (dMgr *Manager) UpdatePortsState(ctx context.Context, deviceID string, portTypeFilter uint32, state voltha.OperStatus_Types) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000971 logger.Debugw(ctx, "UpdatePortsState", log.Fields{"deviceid": deviceID})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400972 agent := dMgr.getDeviceAgent(ctx, deviceID)
973 if agent == nil {
974 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo3ab34882019-05-02 21:33:30 -0400975 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400976 if state != voltha.OperStatus_ACTIVE && state != voltha.OperStatus_UNKNOWN {
977 return status.Error(codes.Unimplemented, "state-change-not-implemented")
978 }
979 if err := agent.updatePortsOperState(ctx, portTypeFilter, state); err != nil {
980 logger.Warnw(ctx, "updatePortsOperState-failed", log.Fields{"deviceId": deviceID, "error": err})
981 return err
982 }
983 return nil
khenaidoo3ab34882019-05-02 21:33:30 -0400984}
985
Kent Hagerman2b216042020-04-03 18:28:56 -0400986func (dMgr *Manager) ChildDeviceDetected(ctx context.Context, parentDeviceID string, parentPortNo int64, deviceType string,
npujar1d86a522019-11-14 17:11:16 +0530987 channelID int64, vendorID string, serialNumber string, onuID int64) (*voltha.Device, error) {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000988 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 -0700989
npujar1d86a522019-11-14 17:11:16 +0530990 if deviceType == "" && vendorID != "" {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000991 logger.Debug(ctx, "device-type-is-nil-fetching-device-type")
Kent Hagerman45a13e42020-04-13 12:23:50 -0400992 deviceTypes, err := dMgr.adapterMgr.ListDeviceTypes(ctx, nil)
993 if err != nil {
994 return nil, err
995 }
Kent Hagerman4f355f52020-03-30 16:01:33 -0400996 OLoop:
Kent Hagerman45a13e42020-04-13 12:23:50 -0400997 for _, dType := range deviceTypes.Items {
Kent Hagerman4f355f52020-03-30 16:01:33 -0400998 for _, v := range dType.VendorIds {
999 if v == vendorID {
1000 deviceType = dType.Adapter
1001 break OLoop
Chaitrashree G S4b3fada2019-07-28 23:55:25 -07001002 }
1003 }
1004 }
1005 }
1006 //if no match found for the vendorid,report adapter with the custom error message
1007 if deviceType == "" {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001008 logger.Errorw(ctx, "failed-to-fetch-adapter-name ", log.Fields{"vendorId": vendorID})
npujar1d86a522019-11-14 17:11:16 +05301009 return nil, status.Errorf(codes.NotFound, "%s", vendorID)
Chaitrashree G S4b3fada2019-07-28 23:55:25 -07001010 }
khenaidoob9203542018-09-17 22:56:37 -04001011
1012 // Create the ONU device
1013 childDevice := &voltha.Device{}
khenaidoob9203542018-09-17 22:56:37 -04001014 childDevice.Type = deviceType
npujar1d86a522019-11-14 17:11:16 +05301015 childDevice.ParentId = parentDeviceID
khenaidoob9203542018-09-17 22:56:37 -04001016 childDevice.ParentPortNo = uint32(parentPortNo)
npujar1d86a522019-11-14 17:11:16 +05301017 childDevice.VendorId = vendorID
Matt Jeanneret4e241952019-02-28 11:16:04 -05001018 childDevice.SerialNumber = serialNumber
khenaidoob9203542018-09-17 22:56:37 -04001019 childDevice.Root = false
khenaidoo6fdf0ba2018-11-02 14:38:33 -04001020
khenaidoo442e7c72020-03-10 16:13:48 -04001021 // Get parent device type
1022 pAgent := dMgr.getDeviceAgent(ctx, parentDeviceID)
1023 if pAgent == nil {
npujar1d86a522019-11-14 17:11:16 +05301024 return nil, status.Errorf(codes.NotFound, "%s", parentDeviceID)
khenaidoo6fdf0ba2018-11-02 14:38:33 -04001025 }
khenaidoo442e7c72020-03-10 16:13:48 -04001026 if pAgent.deviceType == "" {
1027 return nil, status.Errorf(codes.FailedPrecondition, "device Type not set %s", parentDeviceID)
1028 }
khenaidoo6fdf0ba2018-11-02 14:38:33 -04001029
npujar467fe752020-01-16 20:17:45 +05301030 if device, err := dMgr.GetChildDevice(ctx, parentDeviceID, serialNumber, onuID, parentPortNo); err == nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001031 logger.Warnw(ctx, "child-device-exists", log.Fields{"parentId": parentDeviceID, "serialNumber": serialNumber})
Mahir Gunyel6deaa242019-06-27 04:53:33 -07001032 return device, status.Errorf(codes.AlreadyExists, "%s", serialNumber)
Matt Jeanneret4e241952019-02-28 11:16:04 -05001033 }
1034
khenaidoo442e7c72020-03-10 16:13:48 -04001035 childDevice.ProxyAddress = &voltha.Device_ProxyAddress{DeviceId: parentDeviceID, DeviceType: pAgent.deviceType, ChannelId: uint32(channelID), OnuId: uint32(onuID)}
khenaidoob9203542018-09-17 22:56:37 -04001036
1037 // Create and start a device agent for that device
Mahir Gunyel03de0d32020-06-03 01:36:59 -07001038 agent := newAgent(dMgr.adapterProxy, childDevice, dMgr, dMgr.dbPath, dMgr.dProxy, dMgr.defaultTimeout)
khenaidoo442e7c72020-03-10 16:13:48 -04001039 childDevice, err := agent.start(ctx, childDevice)
Scott Baker80678602019-11-14 16:57:36 -08001040 if err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001041 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 -08001042 return nil, err
1043 }
khenaidoo442e7c72020-03-10 16:13:48 -04001044 dMgr.addDeviceAgentToMap(agent)
khenaidoob9203542018-09-17 22:56:37 -04001045
1046 // Activate the child device
npujar467fe752020-01-16 20:17:45 +05301047 if agent = dMgr.getDeviceAgent(ctx, agent.deviceID); agent != nil {
npujar1d86a522019-11-14 17:11:16 +05301048 go func() {
npujar467fe752020-01-16 20:17:45 +05301049 err := agent.enableDevice(context.Background())
npujar1d86a522019-11-14 17:11:16 +05301050 if err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001051 logger.Errorw(ctx, "unable-to-enable-device", log.Fields{"error": err})
npujar1d86a522019-11-14 17:11:16 +05301052 }
1053 }()
khenaidoob9203542018-09-17 22:56:37 -04001054 }
1055
Scott Baker80678602019-11-14 16:57:36 -08001056 return childDevice, nil
khenaidoob9203542018-09-17 22:56:37 -04001057}
1058
Kent Hagerman2b216042020-04-03 18:28:56 -04001059func (dMgr *Manager) processTransition(ctx context.Context, device *voltha.Device, previousState *deviceState) error {
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001060 // This will be triggered on every state update
Rohan Agrawal31f21802020-06-12 05:38:46 +00001061 logger.Debugw(ctx, "state-transition", log.Fields{
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001062 "device": device.Id,
1063 "prev-admin-state": previousState.Admin,
1064 "prev-oper-state": previousState.Operational,
1065 "prev-conn-state": previousState.Connection,
1066 "curr-admin-state": device.AdminState,
1067 "curr-oper-state": device.OperStatus,
1068 "curr-conn-state": device.ConnectStatus,
1069 })
Rohan Agrawal31f21802020-06-12 05:38:46 +00001070 handlers := dMgr.stateTransitions.GetTransitionHandler(ctx, device, previousState)
khenaidoo92e62c52018-10-03 14:02:54 -04001071 if handlers == nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001072 logger.Debugw(ctx, "no-op-transition", log.Fields{"deviceId": device.Id})
khenaidoo92e62c52018-10-03 14:02:54 -04001073 return nil
khenaidoob9203542018-09-17 22:56:37 -04001074 }
Rohan Agrawal31f21802020-06-12 05:38:46 +00001075 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 -04001076 for _, handler := range handlers {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001077 logger.Debugw(ctx, "running-handler", log.Fields{"handler": funcName(handler)})
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001078 if err := handler(ctx, device); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001079 logger.Warnw(ctx, "handler-failed", log.Fields{"handler": funcName(handler), "error": err})
khenaidoo92e62c52018-10-03 14:02:54 -04001080 return err
1081 }
1082 }
khenaidoob9203542018-09-17 22:56:37 -04001083 return nil
1084}
1085
Kent Hagerman2b216042020-04-03 18:28:56 -04001086func (dMgr *Manager) packetOut(ctx context.Context, deviceID string, outPort uint32, packet *ofp.OfpPacketOut) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001087 logger.Debugw(ctx, "packetOut", log.Fields{"deviceId": deviceID, "outPort": outPort})
npujar467fe752020-01-16 20:17:45 +05301088 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
1089 return agent.packetOut(ctx, outPort, packet)
khenaidoofdbad6e2018-11-06 22:26:38 -05001090 }
npujar1d86a522019-11-14 17:11:16 +05301091 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoofdbad6e2018-11-06 22:26:38 -05001092}
1093
npujar1d86a522019-11-14 17:11:16 +05301094// PacketIn receives packet from adapter
Kent Hagerman2b216042020-04-03 18:28:56 -04001095func (dMgr *Manager) PacketIn(ctx context.Context, deviceID string, port uint32, transactionID string, packet []byte) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001096 logger.Debugw(ctx, "PacketIn", log.Fields{"deviceId": deviceID, "port": port})
khenaidoofdbad6e2018-11-06 22:26:38 -05001097 // Get the logical device Id based on the deviceId
1098 var device *voltha.Device
1099 var err error
Kent Hagerman45a13e42020-04-13 12:23:50 -04001100 if device, err = dMgr.getDevice(ctx, deviceID); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001101 logger.Errorw(ctx, "device-not-found", log.Fields{"deviceId": deviceID})
khenaidoofdbad6e2018-11-06 22:26:38 -05001102 return err
1103 }
khenaidoo43c82122018-11-22 18:38:28 -05001104 if !device.Root {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001105 logger.Errorw(ctx, "device-not-root", log.Fields{"deviceId": deviceID})
npujar1d86a522019-11-14 17:11:16 +05301106 return status.Errorf(codes.FailedPrecondition, "%s", deviceID)
khenaidoofdbad6e2018-11-06 22:26:38 -05001107 }
1108
npujar467fe752020-01-16 20:17:45 +05301109 if err := dMgr.logicalDeviceMgr.packetIn(ctx, device.ParentId, port, transactionID, packet); err != nil {
khenaidoofdbad6e2018-11-06 22:26:38 -05001110 return err
1111 }
1112 return nil
1113}
1114
Kent Hagerman2b216042020-04-03 18:28:56 -04001115func (dMgr *Manager) setParentID(ctx context.Context, device *voltha.Device, parentID string) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001116 logger.Debugw(ctx, "setParentId", log.Fields{"deviceId": device.Id, "parentId": parentID})
npujar467fe752020-01-16 20:17:45 +05301117 if agent := dMgr.getDeviceAgent(ctx, device.Id); agent != nil {
1118 return agent.setParentID(ctx, device, parentID)
khenaidooad06fd72019-10-28 12:26:05 -04001119 }
1120 return status.Errorf(codes.NotFound, "%s", device.Id)
1121}
1122
npujar1d86a522019-11-14 17:11:16 +05301123// CreateLogicalDevice creates logical device in core
Kent Hagerman2b216042020-04-03 18:28:56 -04001124func (dMgr *Manager) CreateLogicalDevice(ctx context.Context, cDevice *voltha.Device) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001125 logger.Info(ctx, "CreateLogicalDevice")
khenaidoo59ef7be2019-06-21 12:40:28 -04001126 // Verify whether the logical device has already been created
1127 if cDevice.ParentId != "" {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001128 logger.Debugw(ctx, "Parent device already exist.", log.Fields{"deviceId": cDevice.Id, "logicalDeviceId": cDevice.Id})
khenaidoo59ef7be2019-06-21 12:40:28 -04001129 return nil
1130 }
khenaidoob9203542018-09-17 22:56:37 -04001131 var err error
npujar467fe752020-01-16 20:17:45 +05301132 if _, err = dMgr.logicalDeviceMgr.createLogicalDevice(ctx, cDevice); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001133 logger.Warnw(ctx, "createlogical-device-error", log.Fields{"device": cDevice})
khenaidoob9203542018-09-17 22:56:37 -04001134 return err
1135 }
khenaidoob9203542018-09-17 22:56:37 -04001136 return nil
1137}
1138
npujar1d86a522019-11-14 17:11:16 +05301139// DeleteLogicalDevice deletes logical device from core
Kent Hagerman2b216042020-04-03 18:28:56 -04001140func (dMgr *Manager) DeleteLogicalDevice(ctx context.Context, cDevice *voltha.Device) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001141 logger.Info(ctx, "DeleteLogicalDevice")
khenaidoo92e62c52018-10-03 14:02:54 -04001142 var err error
npujar467fe752020-01-16 20:17:45 +05301143 if err = dMgr.logicalDeviceMgr.deleteLogicalDevice(ctx, cDevice); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001144 logger.Warnw(ctx, "deleteLogical-device-error", log.Fields{"deviceId": cDevice.Id})
khenaidoo92e62c52018-10-03 14:02:54 -04001145 return err
1146 }
1147 // Remove the logical device Id from the parent device
npujar1d86a522019-11-14 17:11:16 +05301148 logicalID := ""
npujar467fe752020-01-16 20:17:45 +05301149 dMgr.UpdateDeviceAttribute(ctx, cDevice.Id, "ParentId", logicalID)
khenaidoo92e62c52018-10-03 14:02:54 -04001150 return nil
1151}
1152
npujar1d86a522019-11-14 17:11:16 +05301153// DeleteLogicalPorts removes the logical ports associated with that deviceId
Kent Hagerman2b216042020-04-03 18:28:56 -04001154func (dMgr *Manager) DeleteLogicalPorts(ctx context.Context, cDevice *voltha.Device) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001155 logger.Debugw(ctx, "delete-all-logical-ports", log.Fields{"device-id": cDevice.Id})
khenaidoo442e7c72020-03-10 16:13:48 -04001156 if err := dMgr.logicalDeviceMgr.deleteLogicalPorts(ctx, cDevice.Id); err != nil {
khenaidooe132f522020-03-20 15:23:15 -04001157 // 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 +00001158 logger.Warnw(ctx, "deleteLogical-ports-error", log.Fields{"device-id": cDevice.Id, "error": err})
khenaidoo0a822f92019-05-08 15:15:57 -04001159 }
1160 return nil
1161}
1162
Kent Hagerman2b216042020-04-03 18:28:56 -04001163func (dMgr *Manager) getParentDevice(ctx context.Context, childDevice *voltha.Device) *voltha.Device {
khenaidoo92e62c52018-10-03 14:02:54 -04001164 // Sanity check
1165 if childDevice.Root {
1166 // childDevice is the parent device
1167 return childDevice
1168 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001169 parentDevice, _ := dMgr.getDevice(ctx, childDevice.ParentId)
khenaidoo92e62c52018-10-03 14:02:54 -04001170 return parentDevice
1171}
1172
Kent Hagerman2b216042020-04-03 18:28:56 -04001173//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 -04001174//cannot manage the child devices. This will trigger the Core to disable all the child devices.
Kent Hagerman2b216042020-04-03 18:28:56 -04001175func (dMgr *Manager) ChildDevicesLost(ctx context.Context, parentDeviceID string) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001176 logger.Debug(ctx, "ChildDevicesLost")
Kent Hagerman2a07b862020-06-19 15:23:07 -04001177 parentDevice, err := dMgr.getDevice(ctx, parentDeviceID)
1178 if err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001179 logger.Warnw(ctx, "failed-getting-device", log.Fields{"deviceId": parentDeviceID, "error": err})
khenaidoo0a822f92019-05-08 15:15:57 -04001180 return err
1181 }
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001182 return dMgr.DisableAllChildDevices(ctx, parentDevice)
khenaidoo0a822f92019-05-08 15:15:57 -04001183}
1184
Kent Hagerman2b216042020-04-03 18:28:56 -04001185//ChildDevicesDetected is invoked by an adapter when child devices are found, typically after after a
khenaidoo0a822f92019-05-08 15:15:57 -04001186// disable/enable sequence. This will trigger the Core to Enable all the child devices of that parent.
Kent Hagerman2b216042020-04-03 18:28:56 -04001187func (dMgr *Manager) ChildDevicesDetected(ctx context.Context, parentDeviceID string) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001188 logger.Debug(ctx, "ChildDevicesDetected")
Kent Hagerman2a07b862020-06-19 15:23:07 -04001189 parentDevicePorts, err := dMgr.listDevicePorts(ctx, parentDeviceID)
1190 if err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001191 logger.Warnw(ctx, "failed-getting-device", log.Fields{"deviceId": parentDeviceID, "error": err})
khenaidoo0a822f92019-05-08 15:15:57 -04001192 return err
1193 }
Kent Hagerman2a07b862020-06-19 15:23:07 -04001194 childDeviceIds := dMgr.getAllChildDeviceIds(ctx, parentDevicePorts)
khenaidoo0a822f92019-05-08 15:15:57 -04001195 if len(childDeviceIds) == 0 {
Kent Hagerman2a07b862020-06-19 15:23:07 -04001196 logger.Debugw(ctx, "no-child-device", log.Fields{"parentDeviceId": parentDeviceID})
khenaidoo0a822f92019-05-08 15:15:57 -04001197 }
khenaidoo59ef7be2019-06-21 12:40:28 -04001198 allChildEnableRequestSent := true
Kent Hagerman2a07b862020-06-19 15:23:07 -04001199 for childDeviceID := range childDeviceIds {
npujar467fe752020-01-16 20:17:45 +05301200 if agent := dMgr.getDeviceAgent(ctx, childDeviceID); agent != nil {
khenaidoo59ef7be2019-06-21 12:40:28 -04001201 // Run the children re-registration in its own routine
Kent Hagerman2a07b862020-06-19 15:23:07 -04001202 go func(ctx context.Context) {
1203 err = agent.enableDevice(ctx)
npujar1d86a522019-11-14 17:11:16 +05301204 if err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001205 logger.Errorw(ctx, "unable-to-enable-device", log.Fields{"error": err})
npujar1d86a522019-11-14 17:11:16 +05301206 }
Kent Hagerman2a07b862020-06-19 15:23:07 -04001207 }(context.Background())
khenaidoo59ef7be2019-06-21 12:40:28 -04001208 } else {
npujar1d86a522019-11-14 17:11:16 +05301209 err = status.Errorf(codes.Unavailable, "no agent for child device %s", childDeviceID)
Kent Hagerman2a07b862020-06-19 15:23:07 -04001210 logger.Errorw(ctx, "no-child-device-agent", log.Fields{"parentDeviceId": parentDeviceID, "childId": childDeviceID})
khenaidoo59ef7be2019-06-21 12:40:28 -04001211 allChildEnableRequestSent = false
khenaidoo0a822f92019-05-08 15:15:57 -04001212 }
1213 }
khenaidoo59ef7be2019-06-21 12:40:28 -04001214 if !allChildEnableRequestSent {
khenaidoo0a822f92019-05-08 15:15:57 -04001215 return err
1216 }
1217 return nil
1218}
1219
khenaidoo4d4802d2018-10-04 21:59:49 -04001220/*
1221All the functions below are callback functions where they are invoked with the latest and previous data. We can
1222therefore use the data as is without trying to get the latest from the model.
1223*/
1224
khenaidoo0a822f92019-05-08 15:15:57 -04001225//DisableAllChildDevices is invoked as a callback when the parent device is disabled
Kent Hagerman2b216042020-04-03 18:28:56 -04001226func (dMgr *Manager) DisableAllChildDevices(ctx context.Context, parentCurrDevice *voltha.Device) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001227 logger.Debug(ctx, "DisableAllChildDevices")
Kent Hagerman2a07b862020-06-19 15:23:07 -04001228 ports, _ := dMgr.listDevicePorts(ctx, parentCurrDevice.Id)
1229 for childDeviceID := range dMgr.getAllChildDeviceIds(ctx, ports) {
npujar467fe752020-01-16 20:17:45 +05301230 if agent := dMgr.getDeviceAgent(ctx, childDeviceID); agent != nil {
Kent Hagerman2a07b862020-06-19 15:23:07 -04001231 if err := agent.disableDevice(ctx); err != nil {
khenaidooe132f522020-03-20 15:23:15 -04001232 // Just log the error - this error happens only if the child device was already in deleted state.
Rohan Agrawal31f21802020-06-12 05:38:46 +00001233 logger.Errorw(ctx, "failure-disable-device", log.Fields{"deviceId": childDeviceID, "error": err.Error()})
khenaidoo92e62c52018-10-03 14:02:54 -04001234 }
1235 }
1236 }
1237 return nil
1238}
1239
khenaidoo0a822f92019-05-08 15:15:57 -04001240//DeleteAllChildDevices is invoked as a callback when the parent device is deleted
Kent Hagerman2b216042020-04-03 18:28:56 -04001241func (dMgr *Manager) DeleteAllChildDevices(ctx context.Context, parentCurrDevice *voltha.Device) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001242 logger.Debug(ctx, "DeleteAllChildDevices")
Kent Hagerman2a07b862020-06-19 15:23:07 -04001243 ports, _ := dMgr.listDevicePorts(ctx, parentCurrDevice.Id)
1244 for childDeviceID := range dMgr.getAllChildDeviceIds(ctx, ports) {
npujar467fe752020-01-16 20:17:45 +05301245 if agent := dMgr.getDeviceAgent(ctx, childDeviceID); agent != nil {
Kent Hagerman2a07b862020-06-19 15:23:07 -04001246 if err := agent.deleteDevice(ctx); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001247 logger.Warnw(ctx, "failure-delete-device", log.Fields{"deviceId": childDeviceID, "error": err.Error()})
khenaidoo4d4802d2018-10-04 21:59:49 -04001248 }
khenaidoo49085352020-01-13 19:15:43 -05001249 // No further action is required here. The deleteDevice will change the device state where the resulting
1250 // callback will take care of cleaning the child device agent.
khenaidoo4d4802d2018-10-04 21:59:49 -04001251 }
1252 }
khenaidoo4d4802d2018-10-04 21:59:49 -04001253 return nil
1254}
1255
Girish Gowdra408cd962020-03-11 14:31:31 -07001256//DeleteAllLogicalPorts is invoked as a callback when the parent device's connection status moves to UNREACHABLE
Kent Hagerman2b216042020-04-03 18:28:56 -04001257func (dMgr *Manager) DeleteAllLogicalPorts(ctx context.Context, parentDevice *voltha.Device) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001258 logger.Debugw(ctx, "delete-all-logical-ports", log.Fields{"parent-device-id": parentDevice.Id})
Girish Gowdra408cd962020-03-11 14:31:31 -07001259 if err := dMgr.logicalDeviceMgr.deleteAllLogicalPorts(ctx, parentDevice); err != nil {
khenaidooe132f522020-03-20 15:23:15 -04001260 // Just log error as logical device may already have been deleted
Rohan Agrawal31f21802020-06-12 05:38:46 +00001261 logger.Warnw(ctx, "delete-all-logical-ports-fail", log.Fields{"parent-device-id": parentDevice.Id, "error": err})
Girish Gowdra408cd962020-03-11 14:31:31 -07001262 }
1263 return nil
1264}
1265
1266//DeleteAllDeviceFlows is invoked as a callback when the parent device's connection status moves to UNREACHABLE
Kent Hagerman2b216042020-04-03 18:28:56 -04001267func (dMgr *Manager) DeleteAllDeviceFlows(ctx context.Context, parentDevice *voltha.Device) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001268 logger.Debugw(ctx, "delete-all-device-flows", log.Fields{"parent-device-id": parentDevice.Id})
Girish Gowdra408cd962020-03-11 14:31:31 -07001269 if agent := dMgr.getDeviceAgent(ctx, parentDevice.Id); agent != nil {
1270 if err := agent.deleteAllFlows(ctx); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001271 logger.Errorw(ctx, "error-deleting-all-device-flows", log.Fields{"parent-device-id": parentDevice.Id})
Girish Gowdra408cd962020-03-11 14:31:31 -07001272 return err
1273 }
1274 return nil
1275 }
1276 return status.Errorf(codes.NotFound, "%s", parentDevice.Id)
1277}
1278
khenaidoo4d4802d2018-10-04 21:59:49 -04001279//getAllChildDeviceIds is a helper method to get all the child device IDs from the device passed as parameter
Kent Hagerman2a07b862020-06-19 15:23:07 -04001280func (dMgr *Manager) getAllChildDeviceIds(ctx context.Context, parentDevicePorts map[uint32]*voltha.Port) map[string]struct{} {
1281 logger.Debug(ctx, "getAllChildDeviceIds")
1282 childDeviceIds := make(map[string]struct{}, len(parentDevicePorts))
1283 for _, port := range parentDevicePorts {
1284 for _, peer := range port.Peers {
1285 childDeviceIds[peer.DeviceId] = struct{}{}
khenaidoo92e62c52018-10-03 14:02:54 -04001286 }
1287 }
Kent Hagerman2a07b862020-06-19 15:23:07 -04001288 logger.Debugw(ctx, "returning-getAllChildDeviceIds", log.Fields{"childDeviceIds": childDeviceIds})
1289 return childDeviceIds
khenaidoo92e62c52018-10-03 14:02:54 -04001290}
1291
Kent Hagerman2b216042020-04-03 18:28:56 -04001292//GetAllChildDevices is a helper method to get all the child device IDs from the device passed as parameter
1293func (dMgr *Manager) GetAllChildDevices(ctx context.Context, parentDeviceID string) (*voltha.Devices, error) {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001294 logger.Debugw(ctx, "GetAllChildDevices", log.Fields{"parentDeviceId": parentDeviceID})
Kent Hagerman2a07b862020-06-19 15:23:07 -04001295 if parentDevicePorts, err := dMgr.listDevicePorts(ctx, parentDeviceID); err == nil {
khenaidoo297cd252019-02-07 22:10:23 -05001296 childDevices := make([]*voltha.Device, 0)
Kent Hagerman2a07b862020-06-19 15:23:07 -04001297 for deviceID := range dMgr.getAllChildDeviceIds(ctx, parentDevicePorts) {
1298 if d, e := dMgr.getDevice(ctx, deviceID); e == nil && d != nil {
1299 childDevices = append(childDevices, d)
khenaidoo297cd252019-02-07 22:10:23 -05001300 }
1301 }
1302 return &voltha.Devices{Items: childDevices}, nil
1303 }
npujar1d86a522019-11-14 17:11:16 +05301304 return nil, status.Errorf(codes.NotFound, "%s", parentDeviceID)
khenaidoo297cd252019-02-07 22:10:23 -05001305}
1306
npujar1d86a522019-11-14 17:11:16 +05301307// SetupUNILogicalPorts creates UNI ports on the logical device that represents a child UNI interface
Kent Hagerman2b216042020-04-03 18:28:56 -04001308func (dMgr *Manager) SetupUNILogicalPorts(ctx context.Context, cDevice *voltha.Device) error {
Kent Hagermanf6db9f12020-07-22 17:16:19 -04001309 logger.Info(ctx, "SetupUNILogicalPorts")
Kent Hagerman2a07b862020-06-19 15:23:07 -04001310 cDevicePorts, err := dMgr.listDevicePorts(ctx, cDevice.Id)
1311 if err != nil {
1312 return err
1313 }
1314 if err := dMgr.logicalDeviceMgr.setupUNILogicalPorts(ctx, cDevice, cDevicePorts); err != nil {
Kent Hagermanf6db9f12020-07-22 17:16:19 -04001315 logger.Warnw(ctx, "setupUNILogicalPorts-error", log.Fields{"device": cDevice, "err": err})
khenaidoob9203542018-09-17 22:56:37 -04001316 return err
1317 }
1318 return nil
1319}
1320
Kent Hagerman45a13e42020-04-13 12:23:50 -04001321// convenience to avoid redefining
1322var operationFailureResp = &common.OperationResp{Code: voltha.OperationResp_OPERATION_FAILURE}
1323
1324// DownloadImage execute an image download request
1325func (dMgr *Manager) DownloadImage(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001326 logger.Debugw(ctx, "DownloadImage", log.Fields{"device-id": img.Id, "imageName": img.Name})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001327 agent := dMgr.getDeviceAgent(ctx, img.Id)
1328 if agent == nil {
1329 return operationFailureResp, status.Errorf(codes.NotFound, "%s", img.Id)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001330 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001331 resp, err := agent.downloadImage(ctx, img)
1332 if err != nil {
1333 return operationFailureResp, err
1334 }
1335 return resp, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001336}
1337
Kent Hagerman45a13e42020-04-13 12:23:50 -04001338// CancelImageDownload cancels image download request
1339func (dMgr *Manager) CancelImageDownload(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001340 logger.Debugw(ctx, "CancelImageDownload", log.Fields{"device-id": img.Id, "imageName": img.Name})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001341 agent := dMgr.getDeviceAgent(ctx, img.Id)
1342 if agent == nil {
1343 return operationFailureResp, status.Errorf(codes.NotFound, "%s", img.Id)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001344 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001345 resp, err := agent.cancelImageDownload(ctx, img)
1346 if err != nil {
1347 return operationFailureResp, err
1348 }
1349 return resp, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001350}
1351
Kent Hagerman45a13e42020-04-13 12:23:50 -04001352// ActivateImageUpdate activates image update request
1353func (dMgr *Manager) ActivateImageUpdate(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001354 logger.Debugw(ctx, "ActivateImageUpdate", log.Fields{"device-id": img.Id, "imageName": img.Name})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001355 agent := dMgr.getDeviceAgent(ctx, img.Id)
1356 if agent == nil {
1357 return operationFailureResp, status.Errorf(codes.NotFound, "%s", img.Id)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001358 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001359 resp, err := agent.activateImage(ctx, img)
1360 if err != nil {
1361 return operationFailureResp, err
1362 }
1363 return resp, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001364}
1365
Kent Hagerman45a13e42020-04-13 12:23:50 -04001366// RevertImageUpdate reverts image update
1367func (dMgr *Manager) RevertImageUpdate(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001368 logger.Debugw(ctx, "RevertImageUpdate", log.Fields{"device-id": img.Id, "imageName": img.Name})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001369 agent := dMgr.getDeviceAgent(ctx, img.Id)
1370 if agent == nil {
1371 return operationFailureResp, status.Errorf(codes.NotFound, "%s", img.Id)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001372 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001373 resp, err := agent.revertImage(ctx, img)
1374 if err != nil {
1375 return operationFailureResp, err
1376 }
1377 return resp, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001378}
1379
Kent Hagerman45a13e42020-04-13 12:23:50 -04001380// convenience to avoid redefining
1381var imageDownloadFailureResp = &voltha.ImageDownload{DownloadState: voltha.ImageDownload_DOWNLOAD_UNKNOWN}
1382
1383// GetImageDownloadStatus returns status of image download
1384func (dMgr *Manager) GetImageDownloadStatus(ctx context.Context, img *voltha.ImageDownload) (*voltha.ImageDownload, error) {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001385 logger.Debugw(ctx, "GetImageDownloadStatus", log.Fields{"device-id": img.Id, "imageName": img.Name})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001386 agent := dMgr.getDeviceAgent(ctx, img.Id)
1387 if agent == nil {
1388 return imageDownloadFailureResp, status.Errorf(codes.NotFound, "%s", img.Id)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001389 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001390 resp, err := agent.getImageDownloadStatus(ctx, img)
1391 if err != nil {
1392 return imageDownloadFailureResp, err
1393 }
1394 return resp, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001395}
1396
Kent Hagerman2b216042020-04-03 18:28:56 -04001397func (dMgr *Manager) UpdateImageDownload(ctx context.Context, deviceID string, img *voltha.ImageDownload) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001398 logger.Debugw(ctx, "UpdateImageDownload", log.Fields{"device-id": img.Id, "imageName": img.Name})
npujar467fe752020-01-16 20:17:45 +05301399 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
1400 if err := agent.updateImageDownload(ctx, img); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001401 logger.Debugw(ctx, "UpdateImageDownload-failed", log.Fields{"err": err, "imageName": img.Name})
khenaidoof5a5bfa2019-01-23 22:20:29 -05001402 return err
1403 }
1404 } else {
1405 return status.Errorf(codes.NotFound, "%s", img.Id)
1406 }
1407 return nil
1408}
1409
Kent Hagerman45a13e42020-04-13 12:23:50 -04001410// GetImageDownload returns image download
Kent Hagerman2b216042020-04-03 18:28:56 -04001411func (dMgr *Manager) GetImageDownload(ctx context.Context, img *voltha.ImageDownload) (*voltha.ImageDownload, error) {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001412 logger.Debugw(ctx, "GetImageDownload", log.Fields{"device-id": img.Id, "imageName": img.Name})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001413 agent := dMgr.getDeviceAgent(ctx, img.Id)
1414 if agent == nil {
1415 return imageDownloadFailureResp, status.Errorf(codes.NotFound, "%s", img.Id)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001416 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001417 resp, err := agent.getImageDownload(ctx, img)
1418 if err != nil {
1419 return imageDownloadFailureResp, err
1420 }
1421 return resp, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001422}
1423
Kent Hagerman45a13e42020-04-13 12:23:50 -04001424// ListImageDownloads returns image downloads
1425func (dMgr *Manager) ListImageDownloads(ctx context.Context, id *voltha.ID) (*voltha.ImageDownloads, error) {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001426 logger.Debugw(ctx, "ListImageDownloads", log.Fields{"device-id": id.Id})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001427 agent := dMgr.getDeviceAgent(ctx, id.Id)
1428 if agent == nil {
1429 return &voltha.ImageDownloads{Items: []*voltha.ImageDownload{imageDownloadFailureResp}}, status.Errorf(codes.NotFound, "%s", id.Id)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001430 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001431 resp, err := agent.listImageDownloads(ctx, id.Id)
1432 if err != nil {
1433 return &voltha.ImageDownloads{Items: []*voltha.ImageDownload{imageDownloadFailureResp}}, err
1434 }
1435 return resp, nil
1436}
1437
1438// GetImages returns all images for a specific device entry
1439func (dMgr *Manager) GetImages(ctx context.Context, id *voltha.ID) (*voltha.Images, error) {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001440 logger.Debugw(ctx, "GetImages", log.Fields{"device-id": id.Id})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001441 device, err := dMgr.getDevice(ctx, id.Id)
1442 if err != nil {
1443 return nil, err
1444 }
1445 return device.GetImages(), nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001446}
1447
Rohan Agrawal31f21802020-06-12 05:38:46 +00001448func (dMgr *Manager) NotifyInvalidTransition(ctx context.Context, device *voltha.Device) error {
1449 logger.Errorw(ctx, "NotifyInvalidTransition", log.Fields{
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001450 "device": device.Id,
1451 "curr-admin-state": device.AdminState,
1452 "curr-oper-state": device.OperStatus,
1453 "curr-conn-state": device.ConnectStatus,
Stephane Barbarieef6650d2019-07-18 12:15:09 -04001454 })
khenaidoo0a822f92019-05-08 15:15:57 -04001455 //TODO: notify over kafka?
1456 return nil
1457}
1458
khenaidoob9203542018-09-17 22:56:37 -04001459func funcName(f interface{}) string {
1460 p := reflect.ValueOf(f).Pointer()
1461 rf := runtime.FuncForPC(p)
1462 return rf.Name()
1463}
1464
npujar1d86a522019-11-14 17:11:16 +05301465// UpdateDeviceAttribute updates value of particular device attribute
Kent Hagerman2b216042020-04-03 18:28:56 -04001466func (dMgr *Manager) UpdateDeviceAttribute(ctx context.Context, deviceID string, attribute string, value interface{}) {
npujar1d86a522019-11-14 17:11:16 +05301467 if agent, ok := dMgr.deviceAgents.Load(deviceID); ok {
Kent Hagerman2b216042020-04-03 18:28:56 -04001468 agent.(*Agent).updateDeviceAttribute(ctx, attribute, value)
khenaidoob9203542018-09-17 22:56:37 -04001469 }
1470}
1471
npujar1d86a522019-11-14 17:11:16 +05301472// GetParentDeviceID returns parent device id, either from memory or from the dB, if present
Kent Hagerman2b216042020-04-03 18:28:56 -04001473func (dMgr *Manager) GetParentDeviceID(ctx context.Context, deviceID string) string {
Kent Hagerman45a13e42020-04-13 12:23:50 -04001474 if device, _ := dMgr.getDevice(ctx, deviceID); device != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001475 logger.Infow(ctx, "GetParentDeviceId", log.Fields{"deviceId": device.Id, "parentId": device.ParentId})
khenaidoo4c9e5592019-09-09 16:20:41 -04001476 return device.ParentId
khenaidoob9203542018-09-17 22:56:37 -04001477 }
khenaidoo4c9e5592019-09-09 16:20:41 -04001478 return ""
khenaidoob9203542018-09-17 22:56:37 -04001479}
serkant.uluderya334479d2019-04-10 08:26:15 -07001480
Kent Hagerman45a13e42020-04-13 12:23:50 -04001481func (dMgr *Manager) SimulateAlarm(ctx context.Context, simulateReq *voltha.SimulateAlarmRequest) (*common.OperationResp, error) {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001482 logger.Debugw(ctx, "SimulateAlarm", log.Fields{"id": simulateReq.Id, "Indicator": simulateReq.Indicator, "IntfId": simulateReq.IntfId,
Kent Hagerman45a13e42020-04-13 12:23:50 -04001483 "PortTypeName": simulateReq.PortTypeName, "OnuDeviceId": simulateReq.OnuDeviceId, "InverseBitErrorRate": simulateReq.InverseBitErrorRate,
1484 "Drift": simulateReq.Drift, "NewEqd": simulateReq.NewEqd, "OnuSerialNumber": simulateReq.OnuSerialNumber, "Operation": simulateReq.Operation})
1485 agent := dMgr.getDeviceAgent(ctx, simulateReq.Id)
1486 if agent == nil {
1487 return nil, status.Errorf(codes.NotFound, "%s", simulateReq.Id)
serkant.uluderya334479d2019-04-10 08:26:15 -07001488 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001489 if err := agent.simulateAlarm(ctx, simulateReq); err != nil {
1490 return nil, err
1491 }
1492 return &common.OperationResp{Code: common.OperationResp_OPERATION_SUCCESS}, nil
serkant.uluderya334479d2019-04-10 08:26:15 -07001493}
Mahir Gunyelfdee9212019-10-16 16:52:21 -07001494
Kent Hagerman2b216042020-04-03 18:28:56 -04001495func (dMgr *Manager) UpdateDeviceReason(ctx context.Context, deviceID string, reason string) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001496 logger.Debugw(ctx, "UpdateDeviceReason", log.Fields{"deviceid": deviceID, "reason": reason})
npujar467fe752020-01-16 20:17:45 +05301497 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
1498 return agent.updateDeviceReason(ctx, reason)
Mahir Gunyelfdee9212019-10-16 16:52:21 -07001499 }
npujar1d86a522019-11-14 17:11:16 +05301500 return status.Errorf(codes.NotFound, "%s", deviceID)
Mahir Gunyelfdee9212019-10-16 16:52:21 -07001501}
kesavandbc2d1622020-01-21 00:42:01 -05001502
Kent Hagerman45a13e42020-04-13 12:23:50 -04001503func (dMgr *Manager) EnablePort(ctx context.Context, port *voltha.Port) (*empty.Empty, error) {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001504 logger.Debugw(ctx, "EnablePort", log.Fields{"device-id": port.DeviceId, "port-no": port.PortNo})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001505 agent := dMgr.getDeviceAgent(ctx, port.DeviceId)
1506 if agent == nil {
1507 return nil, status.Errorf(codes.NotFound, "%s", port.DeviceId)
kesavandbc2d1622020-01-21 00:42:01 -05001508 }
Kent Hagerman2a07b862020-06-19 15:23:07 -04001509 return &empty.Empty{}, agent.enablePort(ctx, port.PortNo)
kesavandbc2d1622020-01-21 00:42:01 -05001510}
1511
Kent Hagerman45a13e42020-04-13 12:23:50 -04001512func (dMgr *Manager) DisablePort(ctx context.Context, port *voltha.Port) (*empty.Empty, error) {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001513 logger.Debugw(ctx, "DisablePort", log.Fields{"device-id": port.DeviceId, "port-no": port.PortNo})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001514 agent := dMgr.getDeviceAgent(ctx, port.DeviceId)
1515 if agent == nil {
1516 return nil, status.Errorf(codes.NotFound, "%s", port.DeviceId)
kesavandbc2d1622020-01-21 00:42:01 -05001517 }
Kent Hagerman2a07b862020-06-19 15:23:07 -04001518 return &empty.Empty{}, agent.disablePort(ctx, port.PortNo)
kesavandbc2d1622020-01-21 00:42:01 -05001519}
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001520
Kent Hagerman2b216042020-04-03 18:28:56 -04001521// ChildDeviceLost calls parent adapter to delete child device and all its references
1522func (dMgr *Manager) ChildDeviceLost(ctx context.Context, curr *voltha.Device) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001523 logger.Debugw(ctx, "childDeviceLost", log.Fields{"child-device-id": curr.Id, "parent-device-id": curr.ParentId})
khenaidoo442e7c72020-03-10 16:13:48 -04001524 if parentAgent := dMgr.getDeviceAgent(ctx, curr.ParentId); parentAgent != nil {
khenaidooe132f522020-03-20 15:23:15 -04001525 if err := parentAgent.ChildDeviceLost(ctx, curr); err != nil {
1526 // Just log the message and let the remaining pipeline proceed.
Rohan Agrawal31f21802020-06-12 05:38:46 +00001527 logger.Warnw(ctx, "childDeviceLost", log.Fields{"child-device-id": curr.Id, "parent-device-id": curr.ParentId, "error": err})
khenaidooe132f522020-03-20 15:23:15 -04001528 }
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001529 }
khenaidooe132f522020-03-20 15:23:15 -04001530 // Do not return an error as parent device may also have been deleted. Let the remaining pipeline proceed.
1531 return nil
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001532}
onkarkundargi87285252020-01-27 11:34:52 +05301533
Kent Hagerman45a13e42020-04-13 12:23:50 -04001534func (dMgr *Manager) StartOmciTestAction(ctx context.Context, request *voltha.OmciTestRequest) (*voltha.TestResponse, error) {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001535 logger.Debugw(ctx, "StartOmciTestAction", log.Fields{"device-id": request.Id, "uuid": request.Uuid})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001536 agent := dMgr.getDeviceAgent(ctx, request.Id)
1537 if agent == nil {
1538 return nil, status.Errorf(codes.NotFound, "%s", request.Id)
onkarkundargi87285252020-01-27 11:34:52 +05301539 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001540 return agent.startOmciTest(ctx, request)
onkarkundargi87285252020-01-27 11:34:52 +05301541}
Dinesh Belwalkarc1129f12020-02-27 10:41:33 -08001542
1543func (dMgr *Manager) GetExtValue(ctx context.Context, value *voltha.ValueSpecifier) (*voltha.ReturnValues, error) {
1544 log.Debugw("getExtValue", log.Fields{"onu-id": value.Id})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001545 cDevice, err := dMgr.getDevice(ctx, value.Id)
Dinesh Belwalkarc1129f12020-02-27 10:41:33 -08001546 if err != nil {
1547 return nil, status.Errorf(codes.Aborted, "%s", err.Error())
1548 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001549 pDevice, err := dMgr.getDevice(ctx, cDevice.ParentId)
Dinesh Belwalkarc1129f12020-02-27 10:41:33 -08001550 if err != nil {
1551 return nil, status.Errorf(codes.Aborted, "%s", err.Error())
1552 }
1553 if agent := dMgr.getDeviceAgent(ctx, cDevice.ParentId); agent != nil {
1554 resp, err := agent.getExtValue(ctx, pDevice, cDevice, value)
1555 if err != nil {
1556 return nil, err
1557 }
1558 log.Debugw("getExtValue-result", log.Fields{"result": resp})
1559 return resp, nil
1560 }
1561 return nil, status.Errorf(codes.NotFound, "%s", value.Id)
1562
1563}