blob: 0afddbe389539bd6a20709f60377a59c7e5e4204 [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
divyadesaicb8b59d2020-08-18 09:55:47 +0000126 logger.Errorw(ctx, "loading-device-failed", log.Fields{"device-id": 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 Agrawalcf12f202020-08-03 04:42:01 +0000176 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
177
Rohan Agrawal31f21802020-06-12 05:38:46 +0000178 logger.Debugw(ctx, "EnableDevice", log.Fields{"device-id": id.Id})
Kent Hagerman45a13e42020-04-13 12:23:50 -0400179 agent := dMgr.getDeviceAgent(ctx, id.Id)
180 if agent == nil {
181 return nil, status.Errorf(codes.NotFound, "%s", id.Id)
khenaidoob9203542018-09-17 22:56:37 -0400182 }
Kent Hagerman45a13e42020-04-13 12:23:50 -0400183 return &empty.Empty{}, agent.enableDevice(ctx)
khenaidoob9203542018-09-17 22:56:37 -0400184}
185
Kent Hagerman45a13e42020-04-13 12:23:50 -0400186// DisableDevice disables a device along with any child device it may have
187func (dMgr *Manager) DisableDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000188 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
189
Rohan Agrawal31f21802020-06-12 05:38:46 +0000190 logger.Debugw(ctx, "DisableDevice", log.Fields{"device-id": id.Id})
Kent Hagerman45a13e42020-04-13 12:23:50 -0400191 agent := dMgr.getDeviceAgent(ctx, id.Id)
192 if agent == nil {
193 return nil, status.Errorf(codes.NotFound, "%s", id.Id)
khenaidoob9203542018-09-17 22:56:37 -0400194 }
Kent Hagerman45a13e42020-04-13 12:23:50 -0400195 return &empty.Empty{}, agent.disableDevice(ctx)
khenaidoo92e62c52018-10-03 14:02:54 -0400196}
197
Kent Hagerman45a13e42020-04-13 12:23:50 -0400198//RebootDevice invoked the reboot API to the corresponding adapter
199func (dMgr *Manager) RebootDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000200 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
201
Rohan Agrawal31f21802020-06-12 05:38:46 +0000202 logger.Debugw(ctx, "RebootDevice", log.Fields{"device-id": id.Id})
Kent Hagerman45a13e42020-04-13 12:23:50 -0400203 agent := dMgr.getDeviceAgent(ctx, id.Id)
204 if agent == nil {
205 return nil, status.Errorf(codes.NotFound, "%s", id.Id)
khenaidoo4d4802d2018-10-04 21:59:49 -0400206 }
Kent Hagerman45a13e42020-04-13 12:23:50 -0400207 return &empty.Empty{}, agent.rebootDevice(ctx)
khenaidoo4d4802d2018-10-04 21:59:49 -0400208}
209
Kent Hagerman45a13e42020-04-13 12:23:50 -0400210// DeleteDevice removes a device from the data model
211func (dMgr *Manager) DeleteDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000212 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
213
Rohan Agrawal31f21802020-06-12 05:38:46 +0000214 logger.Debugw(ctx, "DeleteDevice", log.Fields{"device-id": id.Id})
Kent Hagerman45a13e42020-04-13 12:23:50 -0400215 agent := dMgr.getDeviceAgent(ctx, id.Id)
216 if agent == nil {
217 return nil, status.Errorf(codes.NotFound, "%s", id.Id)
khenaidoo4d4802d2018-10-04 21:59:49 -0400218 }
Kent Hagerman45a13e42020-04-13 12:23:50 -0400219 return &empty.Empty{}, agent.deleteDevice(ctx)
220}
221
Kent Hagerman2a07b862020-06-19 15:23:07 -0400222// GetDevicePort returns the port details for a specific device port entry
223func (dMgr *Manager) GetDevicePort(ctx context.Context, deviceID string, portID uint32) (*voltha.Port, error) {
224 logger.Debugw(ctx, "ListDevicePorts", log.Fields{"device-id": deviceID})
225 agent := dMgr.getDeviceAgent(ctx, deviceID)
226 if agent == nil {
227 return nil, status.Errorf(codes.NotFound, "device-%s", deviceID)
228 }
229 return agent.getDevicePort(portID)
230}
231
Kent Hagerman45a13e42020-04-13 12:23:50 -0400232// ListDevicePorts returns the ports details for a specific device entry
233func (dMgr *Manager) ListDevicePorts(ctx context.Context, id *voltha.ID) (*voltha.Ports, error) {
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000234 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
235
Rohan Agrawal31f21802020-06-12 05:38:46 +0000236 logger.Debugw(ctx, "ListDevicePorts", log.Fields{"device-id": id.Id})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400237 agent := dMgr.getDeviceAgent(ctx, id.Id)
238 if agent == nil {
239 return nil, status.Errorf(codes.NotFound, "device-%s", id.Id)
Kent Hagerman45a13e42020-04-13 12:23:50 -0400240 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400241
242 ports := agent.listDevicePorts()
243 ctr, ret := 0, make([]*voltha.Port, len(ports))
244 for _, port := range ports {
245 ret[ctr] = port
246 ctr++
247 }
248 return &voltha.Ports{Items: ret}, nil
Kent Hagerman45a13e42020-04-13 12:23:50 -0400249}
250
251// ListDeviceFlows returns the flow details for a specific device entry
252func (dMgr *Manager) ListDeviceFlows(ctx context.Context, id *voltha.ID) (*ofp.Flows, error) {
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000253 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
254
Rohan Agrawal31f21802020-06-12 05:38:46 +0000255 logger.Debugw(ctx, "ListDeviceFlows", log.Fields{"device-id": id.Id})
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700256 agent := dMgr.getDeviceAgent(ctx, id.Id)
257 if agent == nil {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400258 return nil, status.Errorf(codes.NotFound, "device-%s", id.Id)
Kent Hagerman45a13e42020-04-13 12:23:50 -0400259 }
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700260
261 flows := agent.listDeviceFlows()
262 ctr, ret := 0, make([]*ofp.OfpFlowStats, len(flows))
263 for _, flow := range flows {
264 ret[ctr] = flow
265 ctr++
266 }
267 return &openflow_13.Flows{Items: ret}, nil
Kent Hagerman45a13e42020-04-13 12:23:50 -0400268}
269
270// ListDeviceFlowGroups returns the flow group details for a specific device entry
271func (dMgr *Manager) ListDeviceFlowGroups(ctx context.Context, id *voltha.ID) (*voltha.FlowGroups, error) {
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000272 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
273
Rohan Agrawal31f21802020-06-12 05:38:46 +0000274 logger.Debugw(ctx, "ListDeviceFlowGroups", log.Fields{"device-id": id.Id})
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700275 agent := dMgr.getDeviceAgent(ctx, id.Id)
276 if agent == nil {
Kent Hagerman45a13e42020-04-13 12:23:50 -0400277 return nil, status.Errorf(codes.NotFound, "device-%s", id.Id)
278 }
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700279 groups := agent.listDeviceGroups()
280 ctr, ret := 0, make([]*openflow_13.OfpGroupEntry, len(groups))
281 for _, group := range groups {
282 ret[ctr] = group
283 ctr++
284 }
285 return &voltha.FlowGroups{Items: ret}, nil
khenaidoo4d4802d2018-10-04 21:59:49 -0400286}
287
khenaidoo6d62c002019-05-15 21:57:03 -0400288// stopManagingDevice stops the management of the device as well as any of its reference device and logical device.
289// This function is called only in the Core that does not own this device. In the Core that owns this device then a
290// deletion deletion also includes removal of any reference of this device.
Kent Hagerman2b216042020-04-03 18:28:56 -0400291func (dMgr *Manager) stopManagingDevice(ctx context.Context, id string) {
divyadesaicb8b59d2020-08-18 09:55:47 +0000292 logger.Infow(ctx, "stopManagingDevice", log.Fields{"device-id": id})
khenaidoo6d62c002019-05-15 21:57:03 -0400293 if dMgr.IsDeviceInCache(id) { // Proceed only if an agent is present for this device
npujar1d86a522019-11-14 17:11:16 +0530294 if root, _ := dMgr.IsRootDevice(id); root {
khenaidoo6d62c002019-05-15 21:57:03 -0400295 // stop managing the logical device
David Bainbridged1afd662020-03-26 18:27:41 -0700296 _ = dMgr.logicalDeviceMgr.stopManagingLogicalDeviceWithDeviceID(ctx, id)
khenaidoo6d62c002019-05-15 21:57:03 -0400297 }
npujar467fe752020-01-16 20:17:45 +0530298 if agent := dMgr.getDeviceAgent(ctx, id); agent != nil {
khenaidoo442e7c72020-03-10 16:13:48 -0400299 if err := agent.stop(ctx); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000300 logger.Warnw(ctx, "unable-to-stop-device-agent", log.Fields{"device-id": agent.deviceID, "error": err})
khenaidoo442e7c72020-03-10 16:13:48 -0400301 }
khenaidoo4c9e5592019-09-09 16:20:41 -0400302 dMgr.deleteDeviceAgentFromMap(agent)
khenaidoo6d62c002019-05-15 21:57:03 -0400303 }
304 }
305}
306
npujar1d86a522019-11-14 17:11:16 +0530307// RunPostDeviceDelete removes any reference of this device
Kent Hagerman2b216042020-04-03 18:28:56 -0400308func (dMgr *Manager) RunPostDeviceDelete(ctx context.Context, cDevice *voltha.Device) error {
divyadesaicb8b59d2020-08-18 09:55:47 +0000309 logger.Infow(ctx, "RunPostDeviceDelete", log.Fields{"device-id": cDevice.Id})
npujar467fe752020-01-16 20:17:45 +0530310 dMgr.stopManagingDevice(ctx, cDevice.Id)
khenaidoo6d62c002019-05-15 21:57:03 -0400311 return nil
khenaidoo0a822f92019-05-08 15:15:57 -0400312}
313
Kent Hagermancba2f302020-07-28 13:37:36 -0400314// GetDevice exists primarily to implement the gRPC interface.
315// Internal functions should call getDeviceReadOnly instead.
Kent Hagerman45a13e42020-04-13 12:23:50 -0400316func (dMgr *Manager) GetDevice(ctx context.Context, id *voltha.ID) (*voltha.Device, error) {
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000317 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
Kent Hagermancba2f302020-07-28 13:37:36 -0400318 return dMgr.getDeviceReadOnly(ctx, id.Id)
Kent Hagerman45a13e42020-04-13 12:23:50 -0400319}
320
Kent Hagermancba2f302020-07-28 13:37:36 -0400321// getDeviceReadOnly will returns a device, either from memory or from the dB, if present
322func (dMgr *Manager) getDeviceReadOnly(ctx context.Context, id string) (*voltha.Device, error) {
divyadesaicb8b59d2020-08-18 09:55:47 +0000323 logger.Debugw(ctx, "getDeviceReadOnly", log.Fields{"device-id": id})
npujar467fe752020-01-16 20:17:45 +0530324 if agent := dMgr.getDeviceAgent(ctx, id); agent != nil {
Kent Hagermancba2f302020-07-28 13:37:36 -0400325 return agent.getDeviceReadOnly(ctx)
khenaidoo92e62c52018-10-03 14:02:54 -0400326 }
327 return nil, status.Errorf(codes.NotFound, "%s", id)
khenaidoob9203542018-09-17 22:56:37 -0400328}
329
Kent Hagerman2a07b862020-06-19 15:23:07 -0400330func (dMgr *Manager) listDevicePorts(ctx context.Context, id string) (map[uint32]*voltha.Port, error) {
divyadesaicb8b59d2020-08-18 09:55:47 +0000331 logger.Debugw(ctx, "listDevicePorts", log.Fields{"device-id": id})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400332 agent := dMgr.getDeviceAgent(ctx, id)
333 if agent == nil {
334 return nil, status.Errorf(codes.NotFound, "%s", id)
335 }
336 return agent.listDevicePorts(), nil
337}
338
npujar1d86a522019-11-14 17:11:16 +0530339// GetChildDevice will return a device, either from memory or from the dB, if present
Kent Hagerman2b216042020-04-03 18:28:56 -0400340func (dMgr *Manager) GetChildDevice(ctx context.Context, parentDeviceID string, serialNumber string, onuID int64, parentPortNo int64) (*voltha.Device, error) {
divyadesaicb8b59d2020-08-18 09:55:47 +0000341 logger.Debugw(ctx, "GetChildDevice", log.Fields{"parent-device-id": parentDeviceID, "serialNumber": serialNumber,
npujar1d86a522019-11-14 17:11:16 +0530342 "parentPortNo": parentPortNo, "onuId": onuID})
Matt Jeanneret4e241952019-02-28 11:16:04 -0500343
Kent Hagerman2a07b862020-06-19 15:23:07 -0400344 parentDevicePorts, err := dMgr.listDevicePorts(ctx, parentDeviceID)
345 if err != nil {
Matt Jeanneret4e241952019-02-28 11:16:04 -0500346 return nil, status.Errorf(codes.Aborted, "%s", err.Error())
347 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400348 childDeviceIds := dMgr.getAllChildDeviceIds(ctx, parentDevicePorts)
Matt Jeanneret4e241952019-02-28 11:16:04 -0500349 if len(childDeviceIds) == 0 {
divyadesaicb8b59d2020-08-18 09:55:47 +0000350 logger.Debugw(ctx, "no-child-devices", log.Fields{"parent-device-id": parentDeviceID, "serialNumber": serialNumber, "onuId": onuID})
npujar1d86a522019-11-14 17:11:16 +0530351 return nil, status.Errorf(codes.NotFound, "%s", parentDeviceID)
Matt Jeanneret4e241952019-02-28 11:16:04 -0500352 }
353
354 var foundChildDevice *voltha.Device
Kent Hagerman2a07b862020-06-19 15:23:07 -0400355 for childDeviceID := range childDeviceIds {
npujar1d86a522019-11-14 17:11:16 +0530356 var found bool
Kent Hagermancba2f302020-07-28 13:37:36 -0400357 if searchDevice, err := dMgr.getDeviceReadOnly(ctx, childDeviceID); err == nil {
Matt Jeanneret4e241952019-02-28 11:16:04 -0500358
npujar1d86a522019-11-14 17:11:16 +0530359 foundOnuID := false
360 if searchDevice.ProxyAddress.OnuId == uint32(onuID) {
Matt Jeanneret4e241952019-02-28 11:16:04 -0500361 if searchDevice.ParentPortNo == uint32(parentPortNo) {
divyadesaicb8b59d2020-08-18 09:55:47 +0000362 logger.Debugw(ctx, "found-child-by-onuid", log.Fields{"parent-device-id": parentDeviceID, "onuId": onuID})
npujar1d86a522019-11-14 17:11:16 +0530363 foundOnuID = true
Matt Jeanneret4e241952019-02-28 11:16:04 -0500364 }
365 }
366
367 foundSerialNumber := false
368 if searchDevice.SerialNumber == serialNumber {
divyadesaicb8b59d2020-08-18 09:55:47 +0000369 logger.Debugw(ctx, "found-child-by-serialnumber", log.Fields{"parent-device-id": parentDeviceID, "serialNumber": serialNumber})
Matt Jeanneret4e241952019-02-28 11:16:04 -0500370 foundSerialNumber = true
371 }
372
373 // if both onuId and serialNumber are provided both must be true for the device to be found
374 // otherwise whichever one found a match is good enough
npujar1d86a522019-11-14 17:11:16 +0530375 if onuID > 0 && serialNumber != "" {
376 found = foundOnuID && foundSerialNumber
Matt Jeanneret4e241952019-02-28 11:16:04 -0500377 } else {
npujar1d86a522019-11-14 17:11:16 +0530378 found = foundOnuID || foundSerialNumber
Matt Jeanneret4e241952019-02-28 11:16:04 -0500379 }
380
npujar1d86a522019-11-14 17:11:16 +0530381 if found {
Matt Jeanneret4e241952019-02-28 11:16:04 -0500382 foundChildDevice = searchDevice
383 break
384 }
385 }
386 }
387
388 if foundChildDevice != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000389 logger.Debugw(ctx, "child-device-found", log.Fields{"parent-device-id": parentDeviceID, "foundChildDevice": foundChildDevice})
Matt Jeanneret4e241952019-02-28 11:16:04 -0500390 return foundChildDevice, nil
391 }
392
divyadesaicb8b59d2020-08-18 09:55:47 +0000393 logger.Debugw(ctx, "child-device-not-found", log.Fields{"parent-device-id": parentDeviceID,
npujar1d86a522019-11-14 17:11:16 +0530394 "serialNumber": serialNumber, "onuId": onuID, "parentPortNo": parentPortNo})
395 return nil, status.Errorf(codes.NotFound, "%s", parentDeviceID)
Matt Jeanneret4e241952019-02-28 11:16:04 -0500396}
397
npujar1d86a522019-11-14 17:11:16 +0530398// GetChildDeviceWithProxyAddress will return a device based on proxy address
Kent Hagerman2b216042020-04-03 18:28:56 -0400399func (dMgr *Manager) GetChildDeviceWithProxyAddress(ctx context.Context, proxyAddress *voltha.Device_ProxyAddress) (*voltha.Device, error) {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000400 logger.Debugw(ctx, "GetChildDeviceWithProxyAddress", log.Fields{"proxyAddress": proxyAddress})
Matt Jeanneret2a20aaa2019-03-05 21:04:02 -0500401
Kent Hagerman2a07b862020-06-19 15:23:07 -0400402 parentDevicePorts, err := dMgr.listDevicePorts(ctx, proxyAddress.DeviceId)
403 if err != nil {
Matt Jeanneret2a20aaa2019-03-05 21:04:02 -0500404 return nil, status.Errorf(codes.Aborted, "%s", err.Error())
405 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400406 childDeviceIds := dMgr.getAllChildDeviceIds(ctx, parentDevicePorts)
Matt Jeanneret2a20aaa2019-03-05 21:04:02 -0500407 if len(childDeviceIds) == 0 {
divyadesaicb8b59d2020-08-18 09:55:47 +0000408 logger.Debugw(ctx, "no-child-devices", log.Fields{"parent-device-id": proxyAddress.DeviceId})
Matt Jeanneret2a20aaa2019-03-05 21:04:02 -0500409 return nil, status.Errorf(codes.NotFound, "%s", proxyAddress)
410 }
411
412 var foundChildDevice *voltha.Device
Kent Hagerman2a07b862020-06-19 15:23:07 -0400413 for childDeviceID := range childDeviceIds {
Kent Hagermancba2f302020-07-28 13:37:36 -0400414 if searchDevice, err := dMgr.getDeviceReadOnly(ctx, childDeviceID); err == nil {
Matt Jeanneret2a20aaa2019-03-05 21:04:02 -0500415 if searchDevice.ProxyAddress == proxyAddress {
416 foundChildDevice = searchDevice
417 break
418 }
419 }
420 }
421
422 if foundChildDevice != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000423 logger.Debugw(ctx, "child-device-found", log.Fields{"proxyAddress": proxyAddress})
Matt Jeanneret2a20aaa2019-03-05 21:04:02 -0500424 return foundChildDevice, nil
425 }
426
Rohan Agrawal31f21802020-06-12 05:38:46 +0000427 logger.Warnw(ctx, "child-device-not-found", log.Fields{"proxyAddress": proxyAddress})
Matt Jeanneret2a20aaa2019-03-05 21:04:02 -0500428 return nil, status.Errorf(codes.NotFound, "%s", proxyAddress)
429}
430
npujar1d86a522019-11-14 17:11:16 +0530431// IsDeviceInCache returns true if device is found in the map
Kent Hagerman2b216042020-04-03 18:28:56 -0400432func (dMgr *Manager) IsDeviceInCache(id string) bool {
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400433 _, exist := dMgr.deviceAgents.Load(id)
khenaidoo297cd252019-02-07 22:10:23 -0500434 return exist
435}
436
npujar1d86a522019-11-14 17:11:16 +0530437// IsRootDevice returns true if root device is found in the map
Kent Hagerman2b216042020-04-03 18:28:56 -0400438func (dMgr *Manager) IsRootDevice(id string) (bool, error) {
khenaidoo2c6a0992019-04-29 13:46:56 -0400439 dMgr.lockRootDeviceMap.RLock()
440 defer dMgr.lockRootDeviceMap.RUnlock()
441 if exist := dMgr.rootDevices[id]; exist {
442 return dMgr.rootDevices[id], nil
khenaidoo19d7b632018-10-30 10:49:50 -0400443 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400444 return false, nil
khenaidoo19d7b632018-10-30 10:49:50 -0400445}
446
Stephane Barbarieaa467942019-02-06 14:09:44 -0500447// ListDevices retrieves the latest devices from the data model
Kent Hagerman45a13e42020-04-13 12:23:50 -0400448func (dMgr *Manager) ListDevices(ctx context.Context, _ *empty.Empty) (*voltha.Devices, error) {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000449 logger.Debug(ctx, "ListDevices")
khenaidoob9203542018-09-17 22:56:37 -0400450 result := &voltha.Devices{}
Kent Hagerman4f355f52020-03-30 16:01:33 -0400451
452 var devices []*voltha.Device
Kent Hagermanf5a67352020-04-30 15:15:26 -0400453 if err := dMgr.dProxy.List(ctx, &devices); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000454 logger.Errorw(ctx, "failed-to-list-devices-from-cluster-proxy", log.Fields{"error": err})
Thomas Lee Se5a44012019-11-07 20:32:24 +0530455 return nil, err
456 }
Kent Hagerman4f355f52020-03-30 16:01:33 -0400457
458 for _, device := range devices {
459 // If device is not in memory then set it up
460 if !dMgr.IsDeviceInCache(device.Id) {
divyadesaicb8b59d2020-08-18 09:55:47 +0000461 logger.Debugw(ctx, "loading-device-from-Model", log.Fields{"device-id": device.Id})
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700462 agent := newAgent(dMgr.adapterProxy, device, dMgr, dMgr.dbPath, dMgr.dProxy, dMgr.defaultTimeout)
Kent Hagerman4f355f52020-03-30 16:01:33 -0400463 if _, err := agent.start(ctx, nil); err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000464 logger.Warnw(ctx, "failure-starting-agent", log.Fields{"device-id": device.Id})
Kent Hagerman4f355f52020-03-30 16:01:33 -0400465 } else {
466 dMgr.addDeviceAgentToMap(agent)
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500467 }
khenaidoob9203542018-09-17 22:56:37 -0400468 }
Kent Hagerman4f355f52020-03-30 16:01:33 -0400469 result.Items = append(result.Items, device)
khenaidoob9203542018-09-17 22:56:37 -0400470 }
Rohan Agrawal31f21802020-06-12 05:38:46 +0000471 logger.Debugw(ctx, "ListDevices-end", log.Fields{"len": len(result.Items)})
khenaidoob9203542018-09-17 22:56:37 -0400472 return result, nil
473}
474
Thomas Lee S51b5cb82019-10-14 14:49:34 +0530475//isParentDeviceExist checks whether device is already preprovisioned.
Kent Hagerman2b216042020-04-03 18:28:56 -0400476func (dMgr *Manager) isParentDeviceExist(ctx context.Context, newDevice *voltha.Device) (bool, error) {
Thomas Lee S51b5cb82019-10-14 14:49:34 +0530477 hostPort := newDevice.GetHostAndPort()
Kent Hagerman4f355f52020-03-30 16:01:33 -0400478 var devices []*voltha.Device
Kent Hagermanf5a67352020-04-30 15:15:26 -0400479 if err := dMgr.dProxy.List(ctx, &devices); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000480 logger.Errorw(ctx, "Failed to list devices from cluster data proxy", log.Fields{"error": err})
Thomas Lee Se5a44012019-11-07 20:32:24 +0530481 return false, err
482 }
Kent Hagerman4f355f52020-03-30 16:01:33 -0400483 for _, device := range devices {
484 if !device.Root {
485 continue
486 }
487 if hostPort != "" && hostPort == device.GetHostAndPort() && device.AdminState != voltha.AdminState_DELETED {
488 return true, nil
489 }
490 if newDevice.MacAddress != "" && newDevice.MacAddress == device.MacAddress && device.AdminState != voltha.AdminState_DELETED {
491 return true, nil
Thomas Lee S51b5cb82019-10-14 14:49:34 +0530492 }
493 }
Thomas Lee Se5a44012019-11-07 20:32:24 +0530494 return false, nil
Thomas Lee S51b5cb82019-10-14 14:49:34 +0530495}
496
khenaidoo6d62c002019-05-15 21:57:03 -0400497//getDeviceFromModelretrieves the device data from the model.
Kent Hagerman2b216042020-04-03 18:28:56 -0400498func (dMgr *Manager) getDeviceFromModel(ctx context.Context, deviceID string) (*voltha.Device, error) {
Kent Hagerman4f355f52020-03-30 16:01:33 -0400499 device := &voltha.Device{}
Kent Hagermanf5a67352020-04-30 15:15:26 -0400500 if have, err := dMgr.dProxy.Get(ctx, deviceID, device); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000501 logger.Errorw(ctx, "failed-to-get-device-info-from-cluster-proxy", log.Fields{"error": err})
Thomas Lee Se5a44012019-11-07 20:32:24 +0530502 return nil, err
Kent Hagerman4f355f52020-03-30 16:01:33 -0400503 } else if !have {
504 return nil, status.Error(codes.NotFound, deviceID)
Thomas Lee Se5a44012019-11-07 20:32:24 +0530505 }
Kent Hagerman4f355f52020-03-30 16:01:33 -0400506
507 return device, nil
khenaidoo6d62c002019-05-15 21:57:03 -0400508}
509
npujar1d86a522019-11-14 17:11:16 +0530510// loadDevice loads the deviceID in memory, if not present
Kent Hagerman2b216042020-04-03 18:28:56 -0400511func (dMgr *Manager) loadDevice(ctx context.Context, deviceID string) (*Agent, error) {
npujar1d86a522019-11-14 17:11:16 +0530512 if deviceID == "" {
khenaidoo297cd252019-02-07 22:10:23 -0500513 return nil, status.Error(codes.InvalidArgument, "deviceId empty")
514 }
khenaidoo4c9e5592019-09-09 16:20:41 -0400515 var err error
516 var device *voltha.Device
517 dMgr.devicesLoadingLock.Lock()
npujar1d86a522019-11-14 17:11:16 +0530518 if _, exist := dMgr.deviceLoadingInProgress[deviceID]; !exist {
519 if !dMgr.IsDeviceInCache(deviceID) {
520 dMgr.deviceLoadingInProgress[deviceID] = []chan int{make(chan int, 1)}
khenaidoo4c9e5592019-09-09 16:20:41 -0400521 dMgr.devicesLoadingLock.Unlock()
522 // Proceed with the loading only if the device exist in the Model (could have been deleted)
npujar467fe752020-01-16 20:17:45 +0530523 if device, err = dMgr.getDeviceFromModel(ctx, deviceID); err == nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000524 logger.Debugw(ctx, "loading-device", log.Fields{"device-id": deviceID})
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700525 agent := newAgent(dMgr.adapterProxy, device, dMgr, dMgr.dbPath, dMgr.dProxy, dMgr.defaultTimeout)
npujar467fe752020-01-16 20:17:45 +0530526 if _, err = agent.start(ctx, nil); err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000527 logger.Warnw(ctx, "Failure loading device", log.Fields{"device-id": deviceID, "error": err})
khenaidoo4c9e5592019-09-09 16:20:41 -0400528 } else {
529 dMgr.addDeviceAgentToMap(agent)
530 }
531 } else {
divyadesaicb8b59d2020-08-18 09:55:47 +0000532 logger.Debugw(ctx, "Device not in model", log.Fields{"device-id": deviceID})
khenaidoo6d62c002019-05-15 21:57:03 -0400533 }
khenaidoo4c9e5592019-09-09 16:20:41 -0400534 // announce completion of task to any number of waiting channels
535 dMgr.devicesLoadingLock.Lock()
npujar1d86a522019-11-14 17:11:16 +0530536 if v, ok := dMgr.deviceLoadingInProgress[deviceID]; ok {
khenaidoo4c9e5592019-09-09 16:20:41 -0400537 for _, ch := range v {
538 close(ch)
539 }
npujar1d86a522019-11-14 17:11:16 +0530540 delete(dMgr.deviceLoadingInProgress, deviceID)
khenaidoo4c9e5592019-09-09 16:20:41 -0400541 }
542 dMgr.devicesLoadingLock.Unlock()
khenaidoo6d62c002019-05-15 21:57:03 -0400543 } else {
khenaidoo4c9e5592019-09-09 16:20:41 -0400544 dMgr.devicesLoadingLock.Unlock()
khenaidoo297cd252019-02-07 22:10:23 -0500545 }
khenaidoo4c9e5592019-09-09 16:20:41 -0400546 } else {
547 ch := make(chan int, 1)
npujar1d86a522019-11-14 17:11:16 +0530548 dMgr.deviceLoadingInProgress[deviceID] = append(dMgr.deviceLoadingInProgress[deviceID], ch)
khenaidoo4c9e5592019-09-09 16:20:41 -0400549 dMgr.devicesLoadingLock.Unlock()
550 // Wait for the channel to be closed, implying the process loading this device is done.
551 <-ch
khenaidoo297cd252019-02-07 22:10:23 -0500552 }
npujar1d86a522019-11-14 17:11:16 +0530553 if agent, ok := dMgr.deviceAgents.Load(deviceID); ok {
Kent Hagerman2b216042020-04-03 18:28:56 -0400554 return agent.(*Agent), nil
khenaidoo297cd252019-02-07 22:10:23 -0500555 }
npujar1d86a522019-11-14 17:11:16 +0530556 return nil, status.Errorf(codes.Aborted, "Error loading device %s", deviceID)
khenaidoo297cd252019-02-07 22:10:23 -0500557}
558
559// loadRootDeviceParentAndChildren loads the children and parents of a root device in memory
Kent Hagerman2a07b862020-06-19 15:23:07 -0400560func (dMgr *Manager) loadRootDeviceParentAndChildren(ctx context.Context, device *voltha.Device, devicePorts map[uint32]*voltha.Port) error {
divyadesaicb8b59d2020-08-18 09:55:47 +0000561 logger.Debugw(ctx, "loading-parent-and-children", log.Fields{"device-id": device.Id})
khenaidoo297cd252019-02-07 22:10:23 -0500562 if device.Root {
563 // Scenario A
564 if device.ParentId != "" {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400565 // Load logical device if needed.
npujar467fe752020-01-16 20:17:45 +0530566 if err := dMgr.logicalDeviceMgr.load(ctx, device.ParentId); err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000567 logger.Warnw(ctx, "failure-loading-logical-device", log.Fields{"logical-device-id": device.ParentId})
khenaidoo297cd252019-02-07 22:10:23 -0500568 }
569 } else {
divyadesaicb8b59d2020-08-18 09:55:47 +0000570 logger.Debugw(ctx, "no-parent-to-load", log.Fields{"device-id": device.Id})
khenaidoo297cd252019-02-07 22:10:23 -0500571 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400572 // Load all child devices, if needed
573 childDeviceIds := dMgr.getAllChildDeviceIds(ctx, devicePorts)
574 for childDeviceID := range childDeviceIds {
575 if _, err := dMgr.loadDevice(ctx, childDeviceID); err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000576 logger.Warnw(ctx, "failure-loading-device", log.Fields{"device-id": childDeviceID, "error": err})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400577 return err
khenaidoo297cd252019-02-07 22:10:23 -0500578 }
khenaidoo297cd252019-02-07 22:10:23 -0500579 }
divyadesaicb8b59d2020-08-18 09:55:47 +0000580 logger.Debugw(ctx, "loaded-children", log.Fields{"device-id": device.Id, "numChildren": len(childDeviceIds)})
khenaidoo297cd252019-02-07 22:10:23 -0500581 }
582 return nil
583}
584
585// load loads the deviceId in memory, if not present, and also loads its accompanying parents and children. Loading
586// in memory is for improved performance. It is not imperative that a device needs to be in memory when a request
587// acting on the device is received by the core. In such a scenario, the Core will load the device in memory first
588// and the proceed with the request.
Kent Hagerman2b216042020-04-03 18:28:56 -0400589func (dMgr *Manager) load(ctx context.Context, deviceID string) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000590 logger.Debug(ctx, "load...")
khenaidoo297cd252019-02-07 22:10:23 -0500591 // 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 -0400592 var dAgent *Agent
khenaidoo297cd252019-02-07 22:10:23 -0500593 var err error
npujar467fe752020-01-16 20:17:45 +0530594 if dAgent, err = dMgr.loadDevice(ctx, deviceID); err != nil {
khenaidoo297cd252019-02-07 22:10:23 -0500595 return err
596 }
597 // Get the loaded device details
Kent Hagermancba2f302020-07-28 13:37:36 -0400598 device, err := dAgent.getDeviceReadOnly(ctx)
khenaidoo442e7c72020-03-10 16:13:48 -0400599 if err != nil {
600 return err
601 }
khenaidoo297cd252019-02-07 22:10:23 -0500602
603 // If the device is in Pre-provisioning or deleted state stop here
604 if device.AdminState == voltha.AdminState_PREPROVISIONED || device.AdminState == voltha.AdminState_DELETED {
605 return nil
606 }
607
608 // Now we face two scenarios
609 if device.Root {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400610 devicePorts := dAgent.listDevicePorts()
611
khenaidoo297cd252019-02-07 22:10:23 -0500612 // Load all children as well as the parent of this device (logical_device)
Kent Hagerman2a07b862020-06-19 15:23:07 -0400613 if err := dMgr.loadRootDeviceParentAndChildren(ctx, device, devicePorts); err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000614 logger.Warnw(ctx, "failure-loading-device-parent-and-children", log.Fields{"device-id": deviceID})
khenaidoo297cd252019-02-07 22:10:23 -0500615 return err
616 }
divyadesaicb8b59d2020-08-18 09:55:47 +0000617 logger.Debugw(ctx, "successfully-loaded-parent-and-children", log.Fields{"device-id": deviceID})
khenaidoo297cd252019-02-07 22:10:23 -0500618 } else {
619 // Scenario B - use the parentId of that device (root device) to trigger the loading
620 if device.ParentId != "" {
npujar467fe752020-01-16 20:17:45 +0530621 return dMgr.load(ctx, device.ParentId)
khenaidoo297cd252019-02-07 22:10:23 -0500622 }
623 }
624 return nil
625}
626
khenaidoo7ccedd52018-12-14 16:48:54 -0500627// ListDeviceIds retrieves the latest device IDs information from the data model (memory data only)
Rohan Agrawal31f21802020-06-12 05:38:46 +0000628func (dMgr *Manager) ListDeviceIds(ctx context.Context, _ *empty.Empty) (*voltha.IDs, error) {
629 logger.Debug(ctx, "ListDeviceIDs")
khenaidoo7ccedd52018-12-14 16:48:54 -0500630 // Report only device IDs that are in the device agent map
631 return dMgr.listDeviceIdsFromMap(), nil
632}
633
Kent Hagerman45a13e42020-04-13 12:23:50 -0400634// ReconcileDevices is a request to a voltha core to update its list of managed devices. This will
635// trigger loading the devices along with their children and parent in memory
636func (dMgr *Manager) ReconcileDevices(ctx context.Context, ids *voltha.IDs) (*empty.Empty, error) {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000637 logger.Debugw(ctx, "ReconcileDevices", log.Fields{"numDevices": len(ids.Items)})
khenaidoo4c9e5592019-09-09 16:20:41 -0400638 if ids != nil && len(ids.Items) != 0 {
khenaidoo7ccedd52018-12-14 16:48:54 -0500639 toReconcile := len(ids.Items)
640 reconciled := 0
khenaidoo4c9e5592019-09-09 16:20:41 -0400641 var err error
khenaidoo7ccedd52018-12-14 16:48:54 -0500642 for _, id := range ids.Items {
npujar467fe752020-01-16 20:17:45 +0530643 if err = dMgr.load(ctx, id.Id); err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000644 logger.Warnw(ctx, "failure-reconciling-device", log.Fields{"device-id": id.Id, "error": err})
khenaidoo4c9e5592019-09-09 16:20:41 -0400645 } else {
npujar1d86a522019-11-14 17:11:16 +0530646 reconciled++
khenaidoo7ccedd52018-12-14 16:48:54 -0500647 }
648 }
649 if toReconcile != reconciled {
Kent Hagerman45a13e42020-04-13 12:23:50 -0400650 return nil, status.Errorf(codes.DataLoss, "less-device-reconciled-than-requested:%d/%d", reconciled, toReconcile)
khenaidoo7ccedd52018-12-14 16:48:54 -0500651 }
652 } else {
Kent Hagerman45a13e42020-04-13 12:23:50 -0400653 return nil, status.Errorf(codes.InvalidArgument, "empty-list-of-ids")
khenaidoo7ccedd52018-12-14 16:48:54 -0500654 }
Kent Hagerman45a13e42020-04-13 12:23:50 -0400655 return &empty.Empty{}, nil
khenaidoo7ccedd52018-12-14 16:48:54 -0500656}
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500657
khenaidooba6b6c42019-08-02 09:11:56 -0400658// isOkToReconcile validates whether a device is in the correct status to be reconciled
659func isOkToReconcile(device *voltha.Device) bool {
660 if device == nil {
661 return false
662 }
663 return device.AdminState != voltha.AdminState_PREPROVISIONED && device.AdminState != voltha.AdminState_DELETED
664}
665
666// adapterRestarted is invoked whenever an adapter is restarted
Kent Hagerman2b216042020-04-03 18:28:56 -0400667func (dMgr *Manager) adapterRestarted(ctx context.Context, adapter *voltha.Adapter) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000668 logger.Debugw(ctx, "adapter-restarted", log.Fields{"adapterId": adapter.Id, "vendor": adapter.Vendor,
Matteo Scandolod525ae32020-04-02 17:27:29 -0700669 "currentReplica": adapter.CurrentReplica, "totalReplicas": adapter.TotalReplicas, "endpoint": adapter.Endpoint})
khenaidooba6b6c42019-08-02 09:11:56 -0400670
671 // Let's reconcile the device managed by this Core only
David Bainbridged1afd662020-03-26 18:27:41 -0700672 if len(dMgr.rootDevices) == 0 {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000673 logger.Debugw(ctx, "nothing-to-reconcile", log.Fields{"adapterId": adapter.Id})
khenaidooba6b6c42019-08-02 09:11:56 -0400674 return nil
675 }
676
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500677 responses := make([]utils.Response, 0)
David Bainbridged1afd662020-03-26 18:27:41 -0700678 for rootDeviceID := range dMgr.rootDevices {
npujar467fe752020-01-16 20:17:45 +0530679 if rootDevice, _ := dMgr.getDeviceFromModel(ctx, rootDeviceID); rootDevice != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000680 isDeviceOwnedByService, err := dMgr.adapterProxy.IsDeviceOwnedByService(ctx, rootDeviceID, adapter.Type, adapter.CurrentReplica)
serkant.uluderya7d545aa2020-04-09 13:38:45 -0700681 if err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000682 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 -0700683 continue
684 }
685 if isDeviceOwnedByService {
khenaidooba6b6c42019-08-02 09:11:56 -0400686 if isOkToReconcile(rootDevice) {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000687 logger.Debugw(ctx, "reconciling-root-device", log.Fields{"rootId": rootDevice.Id})
npujar467fe752020-01-16 20:17:45 +0530688 responses = append(responses, dMgr.sendReconcileDeviceRequest(ctx, rootDevice))
khenaidooba6b6c42019-08-02 09:11:56 -0400689 } else {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000690 logger.Debugw(ctx, "not-reconciling-root-device", log.Fields{"rootId": rootDevice.Id, "state": rootDevice.AdminState})
khenaidooba6b6c42019-08-02 09:11:56 -0400691 }
692 } else { // Should we be reconciling the root's children instead?
Kent Hagerman2a07b862020-06-19 15:23:07 -0400693 rootDevicePorts, _ := dMgr.listDevicePorts(ctx, rootDeviceID)
khenaidooba6b6c42019-08-02 09:11:56 -0400694 childManagedByAdapter:
Kent Hagerman2a07b862020-06-19 15:23:07 -0400695 for _, port := range rootDevicePorts {
khenaidooba6b6c42019-08-02 09:11:56 -0400696 for _, peer := range port.Peers {
npujar467fe752020-01-16 20:17:45 +0530697 if childDevice, _ := dMgr.getDeviceFromModel(ctx, peer.DeviceId); childDevice != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000698 isDeviceOwnedByService, err := dMgr.adapterProxy.IsDeviceOwnedByService(ctx, childDevice.Id, adapter.Type, adapter.CurrentReplica)
serkant.uluderya7d545aa2020-04-09 13:38:45 -0700699 if err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000700 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 -0700701 }
702 if isDeviceOwnedByService {
khenaidooba6b6c42019-08-02 09:11:56 -0400703 if isOkToReconcile(childDevice) {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000704 logger.Debugw(ctx, "reconciling-child-device", log.Fields{"child-device-id": childDevice.Id})
npujar467fe752020-01-16 20:17:45 +0530705 responses = append(responses, dMgr.sendReconcileDeviceRequest(ctx, childDevice))
khenaidooba6b6c42019-08-02 09:11:56 -0400706 } else {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000707 logger.Debugw(ctx, "not-reconciling-child-device", log.Fields{"child-device-id": childDevice.Id, "state": childDevice.AdminState})
khenaidooba6b6c42019-08-02 09:11:56 -0400708 }
709 } else {
710 // All child devices under a parent device are typically managed by the same adapter type.
711 // Therefore we only need to check whether the first device we retrieved is managed by that adapter
712 break childManagedByAdapter
713 }
714 }
715 }
716 }
717 }
718 }
719 }
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500720 if len(responses) > 0 {
khenaidooba6b6c42019-08-02 09:11:56 -0400721 // Wait for completion
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500722 if res := utils.WaitForNilOrErrorResponses(dMgr.defaultTimeout, responses...); res != nil {
khenaidooba6b6c42019-08-02 09:11:56 -0400723 return status.Errorf(codes.Aborted, "errors-%s", res)
724 }
725 } else {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000726 logger.Debugw(ctx, "no-managed-device-to-reconcile", log.Fields{"adapterId": adapter.Id})
khenaidooba6b6c42019-08-02 09:11:56 -0400727 }
728 return nil
729}
730
Kent Hagerman2b216042020-04-03 18:28:56 -0400731func (dMgr *Manager) sendReconcileDeviceRequest(ctx context.Context, device *voltha.Device) utils.Response {
khenaidooba6b6c42019-08-02 09:11:56 -0400732 // Send a reconcile request to the adapter. Since this Core may not be managing this device then there is no
733 // 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 +0530734 // 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 -0400735 // the adapter proxy.
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500736 response := utils.NewResponse()
Kent Hagerman2b216042020-04-03 18:28:56 -0400737 ch, err := dMgr.adapterProxy.ReconcileDevice(ctx, device)
khenaidoo442e7c72020-03-10 16:13:48 -0400738 if err != nil {
739 response.Error(err)
740 }
741 // Wait for adapter response in its own routine
742 go func() {
743 resp, ok := <-ch
744 if !ok {
745 response.Error(status.Errorf(codes.Aborted, "channel-closed-device: %s", device.Id))
746 } else if resp.Err != nil {
747 response.Error(resp.Err)
khenaidooba6b6c42019-08-02 09:11:56 -0400748 }
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500749 response.Done()
khenaidoo442e7c72020-03-10 16:13:48 -0400750 }()
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500751 return response
khenaidooba6b6c42019-08-02 09:11:56 -0400752}
753
Kent Hagerman2b216042020-04-03 18:28:56 -0400754func (dMgr *Manager) ReconcileChildDevices(ctx context.Context, parentDeviceID string) error {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400755 if parentDevicePorts, err := dMgr.listDevicePorts(ctx, parentDeviceID); err == nil {
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500756 responses := make([]utils.Response, 0)
Kent Hagerman2a07b862020-06-19 15:23:07 -0400757 for _, port := range parentDevicePorts {
khenaidooba6b6c42019-08-02 09:11:56 -0400758 for _, peer := range port.Peers {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400759 if childDevice, err := dMgr.getDeviceFromModel(ctx, peer.DeviceId); err == nil {
npujar467fe752020-01-16 20:17:45 +0530760 responses = append(responses, dMgr.sendReconcileDeviceRequest(ctx, childDevice))
khenaidooba6b6c42019-08-02 09:11:56 -0400761 }
762 }
763 }
764 // Wait for completion
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500765 if res := utils.WaitForNilOrErrorResponses(dMgr.defaultTimeout, responses...); res != nil {
khenaidooba6b6c42019-08-02 09:11:56 -0400766 return status.Errorf(codes.Aborted, "errors-%s", res)
767 }
768 }
769 return nil
770}
771
Kent Hagerman2b216042020-04-03 18:28:56 -0400772func (dMgr *Manager) UpdateDeviceUsingAdapterData(ctx context.Context, device *voltha.Device) error {
divyadesaicb8b59d2020-08-18 09:55:47 +0000773 logger.Debugw(ctx, "UpdateDeviceUsingAdapterData", log.Fields{"device-id": device.Id, "device": device})
npujar467fe752020-01-16 20:17:45 +0530774 if agent := dMgr.getDeviceAgent(ctx, device.Id); agent != nil {
775 return agent.updateDeviceUsingAdapterData(ctx, device)
khenaidoob9203542018-09-17 22:56:37 -0400776 }
777 return status.Errorf(codes.NotFound, "%s", device.Id)
778}
779
khenaidoo0db4c812020-05-27 15:27:30 -0400780func (dMgr *Manager) addPeerPort(ctx context.Context, deviceID string, port *voltha.Port) error {
781 meAsPeer := &voltha.Port_PeerPort{DeviceId: deviceID, PortNo: port.PortNo}
782 for _, peerPort := range port.Peers {
783 if agent := dMgr.getDeviceAgent(ctx, peerPort.DeviceId); agent != nil {
784 if err := agent.addPeerPort(ctx, meAsPeer); err != nil {
785 return err
786 }
787 }
788 }
789 // Notify the logical device manager to setup a logical port, if needed. If the added port is an NNI or UNI
790 // then a logical port will be added to the logical device and the device route generated. If the port is a
791 // PON port then only the device graph will be generated.
Kent Hagermancba2f302020-07-28 13:37:36 -0400792 device, err := dMgr.getDeviceReadOnly(ctx, deviceID)
khenaidoo0db4c812020-05-27 15:27:30 -0400793 if err != nil {
794 return err
795 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400796 ports, err := dMgr.listDevicePorts(ctx, deviceID)
797 if err != nil {
798 return err
799 }
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000800 if err = dMgr.logicalDeviceMgr.updateLogicalPort(log.WithSpanFromContext(context.Background(), ctx), device, ports, port); err != nil {
khenaidoo0db4c812020-05-27 15:27:30 -0400801 return err
802 }
803 return nil
804}
805
Kent Hagerman2b216042020-04-03 18:28:56 -0400806func (dMgr *Manager) AddPort(ctx context.Context, deviceID string, port *voltha.Port) error {
npujar467fe752020-01-16 20:17:45 +0530807 agent := dMgr.getDeviceAgent(ctx, deviceID)
npujar1d86a522019-11-14 17:11:16 +0530808 if agent != nil {
npujar467fe752020-01-16 20:17:45 +0530809 if err := agent.addPort(ctx, port); err != nil {
khenaidoo92e62c52018-10-03 14:02:54 -0400810 return err
811 }
khenaidoo0db4c812020-05-27 15:27:30 -0400812 // Setup peer ports in its own routine
813 go func() {
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000814 if err := dMgr.addPeerPort(log.WithSpanFromContext(context.Background(), ctx), deviceID, port); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000815 logger.Errorw(ctx, "unable-to-add-peer-port", log.Fields{"error": err, "device-id": deviceID})
khenaidoo92e62c52018-10-03 14:02:54 -0400816 }
khenaidoo0db4c812020-05-27 15:27:30 -0400817 }()
khenaidoo92e62c52018-10-03 14:02:54 -0400818 return nil
khenaidoob9203542018-09-17 22:56:37 -0400819 }
npujar1d86a522019-11-14 17:11:16 +0530820 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoob9203542018-09-17 22:56:37 -0400821}
822
Kent Hagerman2b216042020-04-03 18:28:56 -0400823func (dMgr *Manager) addFlowsAndGroups(ctx context.Context, deviceID string, flows []*ofp.OfpFlowStats, groups []*ofp.OfpGroupEntry, flowMetadata *voltha.FlowMetadata) error {
divyadesaicb8b59d2020-08-18 09:55:47 +0000824 logger.Debugw(ctx, "addFlowsAndGroups", log.Fields{"device-id": deviceID, "groups:": groups, "flowMetadata": flowMetadata})
npujar467fe752020-01-16 20:17:45 +0530825 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
826 return agent.addFlowsAndGroups(ctx, flows, groups, flowMetadata)
khenaidoo0458db62019-06-20 08:50:36 -0400827 }
npujar1d86a522019-11-14 17:11:16 +0530828 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo0458db62019-06-20 08:50:36 -0400829}
830
khenaidoo787224a2020-04-16 18:08:47 -0400831// deleteParentFlows removes flows from the parent device based on specific attributes
832func (dMgr *Manager) deleteParentFlows(ctx context.Context, deviceID string, uniPort uint32, metadata *voltha.FlowMetadata) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000833 logger.Debugw(ctx, "deleteParentFlows", log.Fields{"device-id": deviceID, "uni-port": uniPort, "metadata": metadata})
khenaidoo787224a2020-04-16 18:08:47 -0400834 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400835 if !agent.isRootDevice {
khenaidoo787224a2020-04-16 18:08:47 -0400836 return status.Errorf(codes.FailedPrecondition, "not-a-parent-device-%s", deviceID)
837 }
838 return agent.filterOutFlows(ctx, uniPort, metadata)
839 }
840 return status.Errorf(codes.NotFound, "%s", deviceID)
841}
842
Kent Hagerman2b216042020-04-03 18:28:56 -0400843func (dMgr *Manager) deleteFlowsAndGroups(ctx context.Context, deviceID string, flows []*ofp.OfpFlowStats, groups []*ofp.OfpGroupEntry, flowMetadata *voltha.FlowMetadata) error {
divyadesaicb8b59d2020-08-18 09:55:47 +0000844 logger.Debugw(ctx, "deleteFlowsAndGroups", log.Fields{"device-id": deviceID})
npujar467fe752020-01-16 20:17:45 +0530845 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
846 return agent.deleteFlowsAndGroups(ctx, flows, groups, flowMetadata)
khenaidoo0458db62019-06-20 08:50:36 -0400847 }
npujar1d86a522019-11-14 17:11:16 +0530848 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo0458db62019-06-20 08:50:36 -0400849}
850
Kent Hagerman2b216042020-04-03 18:28:56 -0400851func (dMgr *Manager) updateFlowsAndGroups(ctx context.Context, deviceID string, flows []*ofp.OfpFlowStats, groups []*ofp.OfpGroupEntry, flowMetadata *voltha.FlowMetadata) error {
divyadesaicb8b59d2020-08-18 09:55:47 +0000852 logger.Debugw(ctx, "updateFlowsAndGroups", log.Fields{"device-id": deviceID})
npujar467fe752020-01-16 20:17:45 +0530853 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
854 return agent.updateFlowsAndGroups(ctx, flows, groups, flowMetadata)
khenaidoo19d7b632018-10-30 10:49:50 -0400855 }
npujar1d86a522019-11-14 17:11:16 +0530856 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo19d7b632018-10-30 10:49:50 -0400857}
858
Kent Hagerman45a13e42020-04-13 12:23:50 -0400859// UpdateDevicePmConfigs updates the PM configs. This is executed when the northbound gRPC API is invoked, typically
khenaidoob3127472019-07-24 21:04:55 -0400860// following a user action
Kent Hagerman45a13e42020-04-13 12:23:50 -0400861func (dMgr *Manager) UpdateDevicePmConfigs(ctx context.Context, configs *voltha.PmConfigs) (*empty.Empty, error) {
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000862 log.EnrichSpan(ctx, log.Fields{"device-id": configs.Id})
863
Kent Hagerman45a13e42020-04-13 12:23:50 -0400864 if configs.Id == "" {
865 return nil, status.Error(codes.FailedPrecondition, "invalid-device-Id")
khenaidoob3127472019-07-24 21:04:55 -0400866 }
Kent Hagerman45a13e42020-04-13 12:23:50 -0400867 agent := dMgr.getDeviceAgent(ctx, configs.Id)
868 if agent == nil {
869 return nil, status.Errorf(codes.NotFound, "%s", configs.Id)
870 }
871 return &empty.Empty{}, agent.updatePmConfigs(ctx, configs)
khenaidoob3127472019-07-24 21:04:55 -0400872}
873
Kent Hagerman2b216042020-04-03 18:28:56 -0400874// InitPmConfigs initialize the pm configs as defined by the adapter.
875func (dMgr *Manager) InitPmConfigs(ctx context.Context, deviceID string, pmConfigs *voltha.PmConfigs) error {
khenaidoob3127472019-07-24 21:04:55 -0400876 if pmConfigs.Id == "" {
877 return status.Errorf(codes.FailedPrecondition, "invalid-device-Id")
878 }
npujar467fe752020-01-16 20:17:45 +0530879 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
880 return agent.initPmConfigs(ctx, pmConfigs)
khenaidoob9203542018-09-17 22:56:37 -0400881 }
npujar1d86a522019-11-14 17:11:16 +0530882 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoob9203542018-09-17 22:56:37 -0400883}
884
Kent Hagerman45a13e42020-04-13 12:23:50 -0400885// ListDevicePmConfigs returns pm configs of device
886func (dMgr *Manager) ListDevicePmConfigs(ctx context.Context, id *voltha.ID) (*voltha.PmConfigs, error) {
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000887 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
888
Kent Hagerman45a13e42020-04-13 12:23:50 -0400889 agent := dMgr.getDeviceAgent(ctx, id.Id)
890 if agent == nil {
891 return nil, status.Errorf(codes.NotFound, "%s", id.Id)
khenaidoob3127472019-07-24 21:04:55 -0400892 }
Kent Hagerman45a13e42020-04-13 12:23:50 -0400893 return agent.listPmConfigs(ctx)
khenaidoob3127472019-07-24 21:04:55 -0400894}
895
Kent Hagerman2b216042020-04-03 18:28:56 -0400896func (dMgr *Manager) getSwitchCapability(ctx context.Context, deviceID string) (*ic.SwitchCapability, error) {
divyadesaicb8b59d2020-08-18 09:55:47 +0000897 logger.Debugw(ctx, "getSwitchCapability", log.Fields{"device-id": deviceID})
npujar467fe752020-01-16 20:17:45 +0530898 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
khenaidoob9203542018-09-17 22:56:37 -0400899 return agent.getSwitchCapability(ctx)
900 }
npujar1d86a522019-11-14 17:11:16 +0530901 return nil, status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoob9203542018-09-17 22:56:37 -0400902}
903
Kent Hagerman2b216042020-04-03 18:28:56 -0400904func (dMgr *Manager) GetPorts(ctx context.Context, deviceID string, portType voltha.Port_PortType) (*voltha.Ports, error) {
divyadesaicb8b59d2020-08-18 09:55:47 +0000905 logger.Debugw(ctx, "GetPorts", log.Fields{"device-id": deviceID, "portType": portType})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400906 agent := dMgr.getDeviceAgent(ctx, deviceID)
907 if agent == nil {
908 return nil, status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoob9203542018-09-17 22:56:37 -0400909 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400910 return agent.getPorts(ctx, portType), nil
khenaidoob9203542018-09-17 22:56:37 -0400911}
912
Kent Hagerman2b216042020-04-03 18:28:56 -0400913func (dMgr *Manager) UpdateDeviceStatus(ctx context.Context, deviceID string, operStatus voltha.OperStatus_Types, connStatus voltha.ConnectStatus_Types) error {
divyadesaicb8b59d2020-08-18 09:55:47 +0000914 logger.Debugw(ctx, "UpdateDeviceStatus", log.Fields{"device-id": deviceID, "operStatus": operStatus, "connStatus": connStatus})
npujar467fe752020-01-16 20:17:45 +0530915 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
916 return agent.updateDeviceStatus(ctx, operStatus, connStatus)
khenaidoo92e62c52018-10-03 14:02:54 -0400917 }
npujar1d86a522019-11-14 17:11:16 +0530918 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo92e62c52018-10-03 14:02:54 -0400919}
920
Kent Hagerman2b216042020-04-03 18:28:56 -0400921func (dMgr *Manager) UpdateChildrenStatus(ctx context.Context, deviceID string, operStatus voltha.OperStatus_Types, connStatus voltha.ConnectStatus_Types) error {
divyadesaicb8b59d2020-08-18 09:55:47 +0000922 logger.Debugw(ctx, "UpdateChildrenStatus", log.Fields{"parent-device-id": deviceID, "operStatus": operStatus, "connStatus": connStatus})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400923 parentDevicePorts, err := dMgr.listDevicePorts(ctx, deviceID)
924 if err != nil {
khenaidoo4d4802d2018-10-04 21:59:49 -0400925 return status.Errorf(codes.Aborted, "%s", err.Error())
926 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400927 for childDeviceID := range dMgr.getAllChildDeviceIds(ctx, parentDevicePorts) {
npujar467fe752020-01-16 20:17:45 +0530928 if agent := dMgr.getDeviceAgent(ctx, childDeviceID); agent != nil {
929 if err = agent.updateDeviceStatus(ctx, operStatus, connStatus); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530930 return status.Errorf(codes.Aborted, "childDevice:%s, error:%s", childDeviceID, err.Error())
khenaidoo4d4802d2018-10-04 21:59:49 -0400931 }
932 }
933 }
934 return nil
935}
936
Kent Hagerman2b216042020-04-03 18:28:56 -0400937func (dMgr *Manager) UpdatePortState(ctx context.Context, deviceID string, portType voltha.Port_PortType, portNo uint32, operStatus voltha.OperStatus_Types) error {
divyadesaicb8b59d2020-08-18 09:55:47 +0000938 logger.Debugw(ctx, "UpdatePortState", log.Fields{"device-id": deviceID, "portType": portType, "portNo": portNo, "operStatus": operStatus})
npujar467fe752020-01-16 20:17:45 +0530939 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
940 if err := agent.updatePortState(ctx, portType, portNo, operStatus); err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000941 logger.Errorw(ctx, "updating-port-state-failed", log.Fields{"device-id": deviceID, "portNo": portNo, "error": err})
khenaidoo171b98e2019-10-31 11:48:15 -0400942 return err
943 }
944 // Notify the logical device manager to change the port state
Mahir Gunyel18fa0c92020-03-06 13:34:04 -0800945 // Do this for NNI and UNIs only. PON ports are not known by logical device
946 if portType == voltha.Port_ETHERNET_NNI || portType == voltha.Port_ETHERNET_UNI {
947 go func() {
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000948 err := dMgr.logicalDeviceMgr.updatePortState(log.WithSpanFromContext(context.Background(), ctx), deviceID, portNo, operStatus)
Mahir Gunyel18fa0c92020-03-06 13:34:04 -0800949 if err != nil {
950 // While we want to handle (catch) and log when
951 // an update to a port was not able to be
952 // propagated to the logical port, we can report
953 // it as a warning and not an error because it
954 // doesn't stop or modify processing.
955 // TODO: VOL-2707
Rohan Agrawal31f21802020-06-12 05:38:46 +0000956 logger.Warnw(ctx, "unable-to-update-logical-port-state", log.Fields{"error": err})
Mahir Gunyel18fa0c92020-03-06 13:34:04 -0800957 }
958 }()
959 }
khenaidoo442e7c72020-03-10 16:13:48 -0400960 return nil
khenaidoob9203542018-09-17 22:56:37 -0400961 }
npujar1d86a522019-11-14 17:11:16 +0530962 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoob9203542018-09-17 22:56:37 -0400963}
964
Kent Hagerman2b216042020-04-03 18:28:56 -0400965func (dMgr *Manager) DeleteAllPorts(ctx context.Context, deviceID string) error {
divyadesaicb8b59d2020-08-18 09:55:47 +0000966 logger.Debugw(ctx, "DeleteAllPorts", log.Fields{"device-id": deviceID})
npujar467fe752020-01-16 20:17:45 +0530967 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
968 if err := agent.deleteAllPorts(ctx); err != nil {
khenaidoo0a822f92019-05-08 15:15:57 -0400969 return err
970 }
971 // Notify the logical device manager to remove all logical ports, if needed.
Kent Hagerman2b216042020-04-03 18:28:56 -0400972 // At this stage the device itself may gave been deleted already at a DeleteAllPorts
khenaidoo0a822f92019-05-08 15:15:57 -0400973 // typically is part of a device deletion phase.
Kent Hagermancba2f302020-07-28 13:37:36 -0400974 if device, err := dMgr.getDeviceReadOnly(ctx, deviceID); err == nil {
npujar1d86a522019-11-14 17:11:16 +0530975 go func() {
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000976 if err := dMgr.logicalDeviceMgr.deleteAllLogicalPorts(log.WithSpanFromContext(context.Background(), ctx), device); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000977 logger.Errorw(ctx, "unable-to-delete-logical-ports", log.Fields{"error": err})
npujar1d86a522019-11-14 17:11:16 +0530978 }
979 }()
khenaidoo0a822f92019-05-08 15:15:57 -0400980 } else {
divyadesaicb8b59d2020-08-18 09:55:47 +0000981 logger.Warnw(ctx, "failed-to-retrieve-device", log.Fields{"device-id": deviceID})
khenaidoo0a822f92019-05-08 15:15:57 -0400982 return err
983 }
984 return nil
985 }
npujar1d86a522019-11-14 17:11:16 +0530986 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo0a822f92019-05-08 15:15:57 -0400987}
988
Kent Hagerman2b216042020-04-03 18:28:56 -0400989//UpdatePortsState updates all ports on the device
Kent Hagerman2a07b862020-06-19 15:23:07 -0400990func (dMgr *Manager) UpdatePortsState(ctx context.Context, deviceID string, portTypeFilter uint32, state voltha.OperStatus_Types) error {
divyadesaicb8b59d2020-08-18 09:55:47 +0000991 logger.Debugw(ctx, "UpdatePortsState", log.Fields{"device-id": deviceID})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400992 agent := dMgr.getDeviceAgent(ctx, deviceID)
993 if agent == nil {
994 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo3ab34882019-05-02 21:33:30 -0400995 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400996 if state != voltha.OperStatus_ACTIVE && state != voltha.OperStatus_UNKNOWN {
997 return status.Error(codes.Unimplemented, "state-change-not-implemented")
998 }
999 if err := agent.updatePortsOperState(ctx, portTypeFilter, state); err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +00001000 logger.Warnw(ctx, "updatePortsOperState-failed", log.Fields{"device-id": deviceID, "error": err})
Kent Hagerman2a07b862020-06-19 15:23:07 -04001001 return err
1002 }
1003 return nil
khenaidoo3ab34882019-05-02 21:33:30 -04001004}
1005
Kent Hagerman2b216042020-04-03 18:28:56 -04001006func (dMgr *Manager) ChildDeviceDetected(ctx context.Context, parentDeviceID string, parentPortNo int64, deviceType string,
npujar1d86a522019-11-14 17:11:16 +05301007 channelID int64, vendorID string, serialNumber string, onuID int64) (*voltha.Device, error) {
divyadesaicb8b59d2020-08-18 09:55:47 +00001008 logger.Debugw(ctx, "ChildDeviceDetected", log.Fields{"parent-device-id": parentDeviceID, "parentPortNo": parentPortNo, "deviceType": deviceType, "channelId": channelID, "vendorId": vendorID, "serialNumber": serialNumber, "onuId": onuID})
Chaitrashree G S4b3fada2019-07-28 23:55:25 -07001009
npujar1d86a522019-11-14 17:11:16 +05301010 if deviceType == "" && vendorID != "" {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001011 logger.Debug(ctx, "device-type-is-nil-fetching-device-type")
Kent Hagerman45a13e42020-04-13 12:23:50 -04001012 deviceTypes, err := dMgr.adapterMgr.ListDeviceTypes(ctx, nil)
1013 if err != nil {
1014 return nil, err
1015 }
Kent Hagerman4f355f52020-03-30 16:01:33 -04001016 OLoop:
Kent Hagerman45a13e42020-04-13 12:23:50 -04001017 for _, dType := range deviceTypes.Items {
Kent Hagerman4f355f52020-03-30 16:01:33 -04001018 for _, v := range dType.VendorIds {
1019 if v == vendorID {
1020 deviceType = dType.Adapter
1021 break OLoop
Chaitrashree G S4b3fada2019-07-28 23:55:25 -07001022 }
1023 }
1024 }
1025 }
1026 //if no match found for the vendorid,report adapter with the custom error message
1027 if deviceType == "" {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001028 logger.Errorw(ctx, "failed-to-fetch-adapter-name ", log.Fields{"vendorId": vendorID})
npujar1d86a522019-11-14 17:11:16 +05301029 return nil, status.Errorf(codes.NotFound, "%s", vendorID)
Chaitrashree G S4b3fada2019-07-28 23:55:25 -07001030 }
khenaidoob9203542018-09-17 22:56:37 -04001031
1032 // Create the ONU device
1033 childDevice := &voltha.Device{}
khenaidoob9203542018-09-17 22:56:37 -04001034 childDevice.Type = deviceType
npujar1d86a522019-11-14 17:11:16 +05301035 childDevice.ParentId = parentDeviceID
khenaidoob9203542018-09-17 22:56:37 -04001036 childDevice.ParentPortNo = uint32(parentPortNo)
npujar1d86a522019-11-14 17:11:16 +05301037 childDevice.VendorId = vendorID
Matt Jeanneret4e241952019-02-28 11:16:04 -05001038 childDevice.SerialNumber = serialNumber
khenaidoob9203542018-09-17 22:56:37 -04001039 childDevice.Root = false
khenaidoo6fdf0ba2018-11-02 14:38:33 -04001040
khenaidoo442e7c72020-03-10 16:13:48 -04001041 // Get parent device type
1042 pAgent := dMgr.getDeviceAgent(ctx, parentDeviceID)
1043 if pAgent == nil {
npujar1d86a522019-11-14 17:11:16 +05301044 return nil, status.Errorf(codes.NotFound, "%s", parentDeviceID)
khenaidoo6fdf0ba2018-11-02 14:38:33 -04001045 }
khenaidoo442e7c72020-03-10 16:13:48 -04001046 if pAgent.deviceType == "" {
1047 return nil, status.Errorf(codes.FailedPrecondition, "device Type not set %s", parentDeviceID)
1048 }
khenaidoo6fdf0ba2018-11-02 14:38:33 -04001049
npujar467fe752020-01-16 20:17:45 +05301050 if device, err := dMgr.GetChildDevice(ctx, parentDeviceID, serialNumber, onuID, parentPortNo); err == nil {
divyadesaicb8b59d2020-08-18 09:55:47 +00001051 logger.Warnw(ctx, "child-device-exists", log.Fields{"parent-device-id": parentDeviceID, "serialNumber": serialNumber})
Mahir Gunyel6deaa242019-06-27 04:53:33 -07001052 return device, status.Errorf(codes.AlreadyExists, "%s", serialNumber)
Matt Jeanneret4e241952019-02-28 11:16:04 -05001053 }
1054
khenaidoo442e7c72020-03-10 16:13:48 -04001055 childDevice.ProxyAddress = &voltha.Device_ProxyAddress{DeviceId: parentDeviceID, DeviceType: pAgent.deviceType, ChannelId: uint32(channelID), OnuId: uint32(onuID)}
khenaidoob9203542018-09-17 22:56:37 -04001056
1057 // Create and start a device agent for that device
Mahir Gunyel03de0d32020-06-03 01:36:59 -07001058 agent := newAgent(dMgr.adapterProxy, childDevice, dMgr, dMgr.dbPath, dMgr.dProxy, dMgr.defaultTimeout)
khenaidoo442e7c72020-03-10 16:13:48 -04001059 childDevice, err := agent.start(ctx, childDevice)
Scott Baker80678602019-11-14 16:57:36 -08001060 if err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001061 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 -08001062 return nil, err
1063 }
khenaidoo442e7c72020-03-10 16:13:48 -04001064 dMgr.addDeviceAgentToMap(agent)
khenaidoob9203542018-09-17 22:56:37 -04001065
1066 // Activate the child device
npujar467fe752020-01-16 20:17:45 +05301067 if agent = dMgr.getDeviceAgent(ctx, agent.deviceID); agent != nil {
npujar1d86a522019-11-14 17:11:16 +05301068 go func() {
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001069 err := agent.enableDevice(log.WithSpanFromContext(context.Background(), ctx))
npujar1d86a522019-11-14 17:11:16 +05301070 if err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001071 logger.Errorw(ctx, "unable-to-enable-device", log.Fields{"error": err})
npujar1d86a522019-11-14 17:11:16 +05301072 }
1073 }()
khenaidoob9203542018-09-17 22:56:37 -04001074 }
1075
Scott Baker80678602019-11-14 16:57:36 -08001076 return childDevice, nil
khenaidoob9203542018-09-17 22:56:37 -04001077}
1078
Kent Hagerman2b216042020-04-03 18:28:56 -04001079func (dMgr *Manager) processTransition(ctx context.Context, device *voltha.Device, previousState *deviceState) error {
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001080 // This will be triggered on every state update
Rohan Agrawal31f21802020-06-12 05:38:46 +00001081 logger.Debugw(ctx, "state-transition", log.Fields{
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001082 "device": device.Id,
1083 "prev-admin-state": previousState.Admin,
1084 "prev-oper-state": previousState.Operational,
1085 "prev-conn-state": previousState.Connection,
1086 "curr-admin-state": device.AdminState,
1087 "curr-oper-state": device.OperStatus,
1088 "curr-conn-state": device.ConnectStatus,
1089 })
Rohan Agrawal31f21802020-06-12 05:38:46 +00001090 handlers := dMgr.stateTransitions.GetTransitionHandler(ctx, device, previousState)
khenaidoo92e62c52018-10-03 14:02:54 -04001091 if handlers == nil {
divyadesaicb8b59d2020-08-18 09:55:47 +00001092 logger.Debugw(ctx, "no-op-transition", log.Fields{"device-id": device.Id})
khenaidoo92e62c52018-10-03 14:02:54 -04001093 return nil
khenaidoob9203542018-09-17 22:56:37 -04001094 }
Rohan Agrawal31f21802020-06-12 05:38:46 +00001095 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 -04001096 for _, handler := range handlers {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001097 logger.Debugw(ctx, "running-handler", log.Fields{"handler": funcName(handler)})
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001098 if err := handler(ctx, device); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001099 logger.Warnw(ctx, "handler-failed", log.Fields{"handler": funcName(handler), "error": err})
khenaidoo92e62c52018-10-03 14:02:54 -04001100 return err
1101 }
1102 }
khenaidoob9203542018-09-17 22:56:37 -04001103 return nil
1104}
1105
Kent Hagerman2b216042020-04-03 18:28:56 -04001106func (dMgr *Manager) packetOut(ctx context.Context, deviceID string, outPort uint32, packet *ofp.OfpPacketOut) error {
divyadesaicb8b59d2020-08-18 09:55:47 +00001107 logger.Debugw(ctx, "packetOut", log.Fields{"device-id": deviceID, "outPort": outPort})
npujar467fe752020-01-16 20:17:45 +05301108 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
1109 return agent.packetOut(ctx, outPort, packet)
khenaidoofdbad6e2018-11-06 22:26:38 -05001110 }
npujar1d86a522019-11-14 17:11:16 +05301111 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoofdbad6e2018-11-06 22:26:38 -05001112}
1113
npujar1d86a522019-11-14 17:11:16 +05301114// PacketIn receives packet from adapter
Kent Hagerman2b216042020-04-03 18:28:56 -04001115func (dMgr *Manager) PacketIn(ctx context.Context, deviceID string, port uint32, transactionID string, packet []byte) error {
divyadesaicb8b59d2020-08-18 09:55:47 +00001116 logger.Debugw(ctx, "PacketIn", log.Fields{"device-id": deviceID, "port": port})
khenaidoofdbad6e2018-11-06 22:26:38 -05001117 // Get the logical device Id based on the deviceId
1118 var device *voltha.Device
1119 var err error
Kent Hagermancba2f302020-07-28 13:37:36 -04001120 if device, err = dMgr.getDeviceReadOnly(ctx, deviceID); err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +00001121 logger.Errorw(ctx, "device-not-found", log.Fields{"device-id": deviceID})
khenaidoofdbad6e2018-11-06 22:26:38 -05001122 return err
1123 }
khenaidoo43c82122018-11-22 18:38:28 -05001124 if !device.Root {
divyadesaicb8b59d2020-08-18 09:55:47 +00001125 logger.Errorw(ctx, "device-not-root", log.Fields{"device-id": deviceID})
npujar1d86a522019-11-14 17:11:16 +05301126 return status.Errorf(codes.FailedPrecondition, "%s", deviceID)
khenaidoofdbad6e2018-11-06 22:26:38 -05001127 }
1128
npujar467fe752020-01-16 20:17:45 +05301129 if err := dMgr.logicalDeviceMgr.packetIn(ctx, device.ParentId, port, transactionID, packet); err != nil {
khenaidoofdbad6e2018-11-06 22:26:38 -05001130 return err
1131 }
1132 return nil
1133}
1134
Kent Hagerman2b216042020-04-03 18:28:56 -04001135func (dMgr *Manager) setParentID(ctx context.Context, device *voltha.Device, parentID string) error {
divyadesaicb8b59d2020-08-18 09:55:47 +00001136 logger.Debugw(ctx, "setParentId", log.Fields{"device-id": device.Id, "parentId": parentID})
npujar467fe752020-01-16 20:17:45 +05301137 if agent := dMgr.getDeviceAgent(ctx, device.Id); agent != nil {
1138 return agent.setParentID(ctx, device, parentID)
khenaidooad06fd72019-10-28 12:26:05 -04001139 }
1140 return status.Errorf(codes.NotFound, "%s", device.Id)
1141}
1142
npujar1d86a522019-11-14 17:11:16 +05301143// CreateLogicalDevice creates logical device in core
Kent Hagerman2b216042020-04-03 18:28:56 -04001144func (dMgr *Manager) CreateLogicalDevice(ctx context.Context, cDevice *voltha.Device) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001145 logger.Info(ctx, "CreateLogicalDevice")
khenaidoo59ef7be2019-06-21 12:40:28 -04001146 // Verify whether the logical device has already been created
1147 if cDevice.ParentId != "" {
divyadesaicb8b59d2020-08-18 09:55:47 +00001148 logger.Debugw(ctx, "Parent device already exist.", log.Fields{"device-id": cDevice.Id, "logical-device-id": cDevice.Id})
khenaidoo59ef7be2019-06-21 12:40:28 -04001149 return nil
1150 }
khenaidoob9203542018-09-17 22:56:37 -04001151 var err error
npujar467fe752020-01-16 20:17:45 +05301152 if _, err = dMgr.logicalDeviceMgr.createLogicalDevice(ctx, cDevice); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001153 logger.Warnw(ctx, "createlogical-device-error", log.Fields{"device": cDevice})
khenaidoob9203542018-09-17 22:56:37 -04001154 return err
1155 }
khenaidoob9203542018-09-17 22:56:37 -04001156 return nil
1157}
1158
npujar1d86a522019-11-14 17:11:16 +05301159// DeleteLogicalDevice deletes logical device from core
Kent Hagerman2b216042020-04-03 18:28:56 -04001160func (dMgr *Manager) DeleteLogicalDevice(ctx context.Context, cDevice *voltha.Device) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001161 logger.Info(ctx, "DeleteLogicalDevice")
khenaidoo92e62c52018-10-03 14:02:54 -04001162 var err error
npujar467fe752020-01-16 20:17:45 +05301163 if err = dMgr.logicalDeviceMgr.deleteLogicalDevice(ctx, cDevice); err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +00001164 logger.Warnw(ctx, "deleteLogical-device-error", log.Fields{"device-id": cDevice.Id})
khenaidoo92e62c52018-10-03 14:02:54 -04001165 return err
1166 }
1167 // Remove the logical device Id from the parent device
npujar1d86a522019-11-14 17:11:16 +05301168 logicalID := ""
npujar467fe752020-01-16 20:17:45 +05301169 dMgr.UpdateDeviceAttribute(ctx, cDevice.Id, "ParentId", logicalID)
khenaidoo92e62c52018-10-03 14:02:54 -04001170 return nil
1171}
1172
npujar1d86a522019-11-14 17:11:16 +05301173// DeleteLogicalPorts removes the logical ports associated with that deviceId
Kent Hagerman2b216042020-04-03 18:28:56 -04001174func (dMgr *Manager) DeleteLogicalPorts(ctx context.Context, cDevice *voltha.Device) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001175 logger.Debugw(ctx, "delete-all-logical-ports", log.Fields{"device-id": cDevice.Id})
khenaidoo442e7c72020-03-10 16:13:48 -04001176 if err := dMgr.logicalDeviceMgr.deleteLogicalPorts(ctx, cDevice.Id); err != nil {
khenaidooe132f522020-03-20 15:23:15 -04001177 // 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 +00001178 logger.Warnw(ctx, "deleteLogical-ports-error", log.Fields{"device-id": cDevice.Id, "error": err})
khenaidoo0a822f92019-05-08 15:15:57 -04001179 }
1180 return nil
1181}
1182
Kent Hagerman2b216042020-04-03 18:28:56 -04001183func (dMgr *Manager) getParentDevice(ctx context.Context, childDevice *voltha.Device) *voltha.Device {
khenaidoo92e62c52018-10-03 14:02:54 -04001184 // Sanity check
1185 if childDevice.Root {
1186 // childDevice is the parent device
1187 return childDevice
1188 }
Kent Hagermancba2f302020-07-28 13:37:36 -04001189 parentDevice, _ := dMgr.getDeviceReadOnly(ctx, childDevice.ParentId)
khenaidoo92e62c52018-10-03 14:02:54 -04001190 return parentDevice
1191}
1192
Kent Hagerman2b216042020-04-03 18:28:56 -04001193//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 -04001194//cannot manage the child devices. This will trigger the Core to disable all the child devices.
Kent Hagerman2b216042020-04-03 18:28:56 -04001195func (dMgr *Manager) ChildDevicesLost(ctx context.Context, parentDeviceID string) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001196 logger.Debug(ctx, "ChildDevicesLost")
Kent Hagermancba2f302020-07-28 13:37:36 -04001197 parentDevice, err := dMgr.getDeviceReadOnly(ctx, parentDeviceID)
Kent Hagerman2a07b862020-06-19 15:23:07 -04001198 if err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +00001199 logger.Warnw(ctx, "failed-getting-device", log.Fields{"parent-device-id": parentDeviceID, "error": err})
khenaidoo0a822f92019-05-08 15:15:57 -04001200 return err
1201 }
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001202 return dMgr.DisableAllChildDevices(ctx, parentDevice)
khenaidoo0a822f92019-05-08 15:15:57 -04001203}
1204
Kent Hagerman2b216042020-04-03 18:28:56 -04001205//ChildDevicesDetected is invoked by an adapter when child devices are found, typically after after a
khenaidoo0a822f92019-05-08 15:15:57 -04001206// disable/enable sequence. This will trigger the Core to Enable all the child devices of that parent.
Kent Hagerman2b216042020-04-03 18:28:56 -04001207func (dMgr *Manager) ChildDevicesDetected(ctx context.Context, parentDeviceID string) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001208 logger.Debug(ctx, "ChildDevicesDetected")
Kent Hagerman2a07b862020-06-19 15:23:07 -04001209 parentDevicePorts, err := dMgr.listDevicePorts(ctx, parentDeviceID)
1210 if err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +00001211 logger.Warnw(ctx, "failed-getting-device", log.Fields{"device-id": parentDeviceID, "error": err})
khenaidoo0a822f92019-05-08 15:15:57 -04001212 return err
1213 }
Kent Hagerman2a07b862020-06-19 15:23:07 -04001214 childDeviceIds := dMgr.getAllChildDeviceIds(ctx, parentDevicePorts)
khenaidoo0a822f92019-05-08 15:15:57 -04001215 if len(childDeviceIds) == 0 {
divyadesaicb8b59d2020-08-18 09:55:47 +00001216 logger.Debugw(ctx, "no-child-device", log.Fields{"parent-device-id": parentDeviceID})
khenaidoo0a822f92019-05-08 15:15:57 -04001217 }
khenaidoo59ef7be2019-06-21 12:40:28 -04001218 allChildEnableRequestSent := true
Kent Hagerman2a07b862020-06-19 15:23:07 -04001219 for childDeviceID := range childDeviceIds {
npujar467fe752020-01-16 20:17:45 +05301220 if agent := dMgr.getDeviceAgent(ctx, childDeviceID); agent != nil {
khenaidoo59ef7be2019-06-21 12:40:28 -04001221 // Run the children re-registration in its own routine
Kent Hagerman2a07b862020-06-19 15:23:07 -04001222 go func(ctx context.Context) {
1223 err = agent.enableDevice(ctx)
npujar1d86a522019-11-14 17:11:16 +05301224 if err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001225 logger.Errorw(ctx, "unable-to-enable-device", log.Fields{"error": err})
npujar1d86a522019-11-14 17:11:16 +05301226 }
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001227 }(log.WithSpanFromContext(context.Background(), ctx))
khenaidoo59ef7be2019-06-21 12:40:28 -04001228 } else {
npujar1d86a522019-11-14 17:11:16 +05301229 err = status.Errorf(codes.Unavailable, "no agent for child device %s", childDeviceID)
divyadesaicb8b59d2020-08-18 09:55:47 +00001230 logger.Errorw(ctx, "no-child-device-agent", log.Fields{"parent-device-id": parentDeviceID, "childId": childDeviceID})
khenaidoo59ef7be2019-06-21 12:40:28 -04001231 allChildEnableRequestSent = false
khenaidoo0a822f92019-05-08 15:15:57 -04001232 }
1233 }
khenaidoo59ef7be2019-06-21 12:40:28 -04001234 if !allChildEnableRequestSent {
khenaidoo0a822f92019-05-08 15:15:57 -04001235 return err
1236 }
1237 return nil
1238}
1239
khenaidoo4d4802d2018-10-04 21:59:49 -04001240/*
1241All the functions below are callback functions where they are invoked with the latest and previous data. We can
1242therefore use the data as is without trying to get the latest from the model.
1243*/
1244
khenaidoo0a822f92019-05-08 15:15:57 -04001245//DisableAllChildDevices is invoked as a callback when the parent device is disabled
Kent Hagerman2b216042020-04-03 18:28:56 -04001246func (dMgr *Manager) DisableAllChildDevices(ctx context.Context, parentCurrDevice *voltha.Device) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001247 logger.Debug(ctx, "DisableAllChildDevices")
Kent Hagerman2a07b862020-06-19 15:23:07 -04001248 ports, _ := dMgr.listDevicePorts(ctx, parentCurrDevice.Id)
1249 for childDeviceID := range dMgr.getAllChildDeviceIds(ctx, ports) {
npujar467fe752020-01-16 20:17:45 +05301250 if agent := dMgr.getDeviceAgent(ctx, childDeviceID); agent != nil {
Kent Hagerman2a07b862020-06-19 15:23:07 -04001251 if err := agent.disableDevice(ctx); err != nil {
khenaidooe132f522020-03-20 15:23:15 -04001252 // Just log the error - this error happens only if the child device was already in deleted state.
divyadesaicb8b59d2020-08-18 09:55:47 +00001253 logger.Errorw(ctx, "failure-disable-device", log.Fields{"device-id": childDeviceID, "error": err.Error()})
khenaidoo92e62c52018-10-03 14:02:54 -04001254 }
1255 }
1256 }
1257 return nil
1258}
1259
khenaidoo0a822f92019-05-08 15:15:57 -04001260//DeleteAllChildDevices is invoked as a callback when the parent device is deleted
Kent Hagerman2b216042020-04-03 18:28:56 -04001261func (dMgr *Manager) DeleteAllChildDevices(ctx context.Context, parentCurrDevice *voltha.Device) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001262 logger.Debug(ctx, "DeleteAllChildDevices")
Kent Hagerman2a07b862020-06-19 15:23:07 -04001263 ports, _ := dMgr.listDevicePorts(ctx, parentCurrDevice.Id)
1264 for childDeviceID := range dMgr.getAllChildDeviceIds(ctx, ports) {
npujar467fe752020-01-16 20:17:45 +05301265 if agent := dMgr.getDeviceAgent(ctx, childDeviceID); agent != nil {
Kent Hagerman2a07b862020-06-19 15:23:07 -04001266 if err := agent.deleteDevice(ctx); err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +00001267 logger.Warnw(ctx, "failure-delete-device", log.Fields{"device-id": childDeviceID, "error": err.Error()})
khenaidoo4d4802d2018-10-04 21:59:49 -04001268 }
khenaidoo49085352020-01-13 19:15:43 -05001269 // No further action is required here. The deleteDevice will change the device state where the resulting
1270 // callback will take care of cleaning the child device agent.
khenaidoo4d4802d2018-10-04 21:59:49 -04001271 }
1272 }
khenaidoo4d4802d2018-10-04 21:59:49 -04001273 return nil
1274}
1275
Girish Gowdra408cd962020-03-11 14:31:31 -07001276//DeleteAllLogicalPorts is invoked as a callback when the parent device's connection status moves to UNREACHABLE
Kent Hagerman2b216042020-04-03 18:28:56 -04001277func (dMgr *Manager) DeleteAllLogicalPorts(ctx context.Context, parentDevice *voltha.Device) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001278 logger.Debugw(ctx, "delete-all-logical-ports", log.Fields{"parent-device-id": parentDevice.Id})
Girish Gowdra408cd962020-03-11 14:31:31 -07001279 if err := dMgr.logicalDeviceMgr.deleteAllLogicalPorts(ctx, parentDevice); err != nil {
khenaidooe132f522020-03-20 15:23:15 -04001280 // Just log error as logical device may already have been deleted
Rohan Agrawal31f21802020-06-12 05:38:46 +00001281 logger.Warnw(ctx, "delete-all-logical-ports-fail", log.Fields{"parent-device-id": parentDevice.Id, "error": err})
Girish Gowdra408cd962020-03-11 14:31:31 -07001282 }
1283 return nil
1284}
1285
1286//DeleteAllDeviceFlows is invoked as a callback when the parent device's connection status moves to UNREACHABLE
Kent Hagerman2b216042020-04-03 18:28:56 -04001287func (dMgr *Manager) DeleteAllDeviceFlows(ctx context.Context, parentDevice *voltha.Device) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001288 logger.Debugw(ctx, "delete-all-device-flows", log.Fields{"parent-device-id": parentDevice.Id})
Girish Gowdra408cd962020-03-11 14:31:31 -07001289 if agent := dMgr.getDeviceAgent(ctx, parentDevice.Id); agent != nil {
1290 if err := agent.deleteAllFlows(ctx); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001291 logger.Errorw(ctx, "error-deleting-all-device-flows", log.Fields{"parent-device-id": parentDevice.Id})
Girish Gowdra408cd962020-03-11 14:31:31 -07001292 return err
1293 }
1294 return nil
1295 }
1296 return status.Errorf(codes.NotFound, "%s", parentDevice.Id)
1297}
1298
khenaidoo4d4802d2018-10-04 21:59:49 -04001299//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 -04001300func (dMgr *Manager) getAllChildDeviceIds(ctx context.Context, parentDevicePorts map[uint32]*voltha.Port) map[string]struct{} {
1301 logger.Debug(ctx, "getAllChildDeviceIds")
1302 childDeviceIds := make(map[string]struct{}, len(parentDevicePorts))
1303 for _, port := range parentDevicePorts {
1304 for _, peer := range port.Peers {
1305 childDeviceIds[peer.DeviceId] = struct{}{}
khenaidoo92e62c52018-10-03 14:02:54 -04001306 }
1307 }
Kent Hagerman2a07b862020-06-19 15:23:07 -04001308 logger.Debugw(ctx, "returning-getAllChildDeviceIds", log.Fields{"childDeviceIds": childDeviceIds})
1309 return childDeviceIds
khenaidoo92e62c52018-10-03 14:02:54 -04001310}
1311
Kent Hagerman2b216042020-04-03 18:28:56 -04001312//GetAllChildDevices is a helper method to get all the child device IDs from the device passed as parameter
1313func (dMgr *Manager) GetAllChildDevices(ctx context.Context, parentDeviceID string) (*voltha.Devices, error) {
divyadesaicb8b59d2020-08-18 09:55:47 +00001314 logger.Debugw(ctx, "GetAllChildDevices", log.Fields{"parent-device-id": parentDeviceID})
Kent Hagerman2a07b862020-06-19 15:23:07 -04001315 if parentDevicePorts, err := dMgr.listDevicePorts(ctx, parentDeviceID); err == nil {
khenaidoo297cd252019-02-07 22:10:23 -05001316 childDevices := make([]*voltha.Device, 0)
Kent Hagerman2a07b862020-06-19 15:23:07 -04001317 for deviceID := range dMgr.getAllChildDeviceIds(ctx, parentDevicePorts) {
Kent Hagermancba2f302020-07-28 13:37:36 -04001318 if d, e := dMgr.getDeviceReadOnly(ctx, deviceID); e == nil && d != nil {
Kent Hagerman2a07b862020-06-19 15:23:07 -04001319 childDevices = append(childDevices, d)
khenaidoo297cd252019-02-07 22:10:23 -05001320 }
1321 }
1322 return &voltha.Devices{Items: childDevices}, nil
1323 }
npujar1d86a522019-11-14 17:11:16 +05301324 return nil, status.Errorf(codes.NotFound, "%s", parentDeviceID)
khenaidoo297cd252019-02-07 22:10:23 -05001325}
1326
npujar1d86a522019-11-14 17:11:16 +05301327// SetupUNILogicalPorts creates UNI ports on the logical device that represents a child UNI interface
Kent Hagerman2b216042020-04-03 18:28:56 -04001328func (dMgr *Manager) SetupUNILogicalPorts(ctx context.Context, cDevice *voltha.Device) error {
Kent Hagermanf6db9f12020-07-22 17:16:19 -04001329 logger.Info(ctx, "SetupUNILogicalPorts")
Kent Hagerman2a07b862020-06-19 15:23:07 -04001330 cDevicePorts, err := dMgr.listDevicePorts(ctx, cDevice.Id)
1331 if err != nil {
1332 return err
1333 }
1334 if err := dMgr.logicalDeviceMgr.setupUNILogicalPorts(ctx, cDevice, cDevicePorts); err != nil {
Kent Hagermanf6db9f12020-07-22 17:16:19 -04001335 logger.Warnw(ctx, "setupUNILogicalPorts-error", log.Fields{"device": cDevice, "err": err})
khenaidoob9203542018-09-17 22:56:37 -04001336 return err
1337 }
1338 return nil
1339}
1340
Kent Hagerman45a13e42020-04-13 12:23:50 -04001341// convenience to avoid redefining
1342var operationFailureResp = &common.OperationResp{Code: voltha.OperationResp_OPERATION_FAILURE}
1343
1344// DownloadImage execute an image download request
1345func (dMgr *Manager) DownloadImage(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001346 log.EnrichSpan(ctx, log.Fields{"device-id": img.Id})
1347
Rohan Agrawal31f21802020-06-12 05:38:46 +00001348 logger.Debugw(ctx, "DownloadImage", log.Fields{"device-id": img.Id, "imageName": img.Name})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001349 agent := dMgr.getDeviceAgent(ctx, img.Id)
1350 if agent == nil {
1351 return operationFailureResp, status.Errorf(codes.NotFound, "%s", img.Id)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001352 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001353 resp, err := agent.downloadImage(ctx, img)
1354 if err != nil {
1355 return operationFailureResp, err
1356 }
1357 return resp, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001358}
1359
Kent Hagerman45a13e42020-04-13 12:23:50 -04001360// CancelImageDownload cancels image download request
1361func (dMgr *Manager) CancelImageDownload(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001362 log.EnrichSpan(ctx, log.Fields{"device-id": img.Id})
1363
Rohan Agrawal31f21802020-06-12 05:38:46 +00001364 logger.Debugw(ctx, "CancelImageDownload", log.Fields{"device-id": img.Id, "imageName": img.Name})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001365 agent := dMgr.getDeviceAgent(ctx, img.Id)
1366 if agent == nil {
1367 return operationFailureResp, status.Errorf(codes.NotFound, "%s", img.Id)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001368 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001369 resp, err := agent.cancelImageDownload(ctx, img)
1370 if err != nil {
1371 return operationFailureResp, err
1372 }
1373 return resp, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001374}
1375
Kent Hagerman45a13e42020-04-13 12:23:50 -04001376// ActivateImageUpdate activates image update request
1377func (dMgr *Manager) ActivateImageUpdate(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001378 log.EnrichSpan(ctx, log.Fields{"device-id": img.Id})
1379
Rohan Agrawal31f21802020-06-12 05:38:46 +00001380 logger.Debugw(ctx, "ActivateImageUpdate", log.Fields{"device-id": img.Id, "imageName": img.Name})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001381 agent := dMgr.getDeviceAgent(ctx, img.Id)
1382 if agent == nil {
1383 return operationFailureResp, status.Errorf(codes.NotFound, "%s", img.Id)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001384 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001385 resp, err := agent.activateImage(ctx, img)
1386 if err != nil {
1387 return operationFailureResp, err
1388 }
1389 return resp, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001390}
1391
Kent Hagerman45a13e42020-04-13 12:23:50 -04001392// RevertImageUpdate reverts image update
1393func (dMgr *Manager) RevertImageUpdate(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001394 log.EnrichSpan(ctx, log.Fields{"device-id": img.Id})
1395
Rohan Agrawal31f21802020-06-12 05:38:46 +00001396 logger.Debugw(ctx, "RevertImageUpdate", log.Fields{"device-id": img.Id, "imageName": img.Name})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001397 agent := dMgr.getDeviceAgent(ctx, img.Id)
1398 if agent == nil {
1399 return operationFailureResp, status.Errorf(codes.NotFound, "%s", img.Id)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001400 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001401 resp, err := agent.revertImage(ctx, img)
1402 if err != nil {
1403 return operationFailureResp, err
1404 }
1405 return resp, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001406}
1407
Kent Hagerman45a13e42020-04-13 12:23:50 -04001408// convenience to avoid redefining
1409var imageDownloadFailureResp = &voltha.ImageDownload{DownloadState: voltha.ImageDownload_DOWNLOAD_UNKNOWN}
1410
1411// GetImageDownloadStatus returns status of image download
1412func (dMgr *Manager) GetImageDownloadStatus(ctx context.Context, img *voltha.ImageDownload) (*voltha.ImageDownload, error) {
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001413 log.EnrichSpan(ctx, log.Fields{"device-id": img.Id})
1414
Rohan Agrawal31f21802020-06-12 05:38:46 +00001415 logger.Debugw(ctx, "GetImageDownloadStatus", log.Fields{"device-id": img.Id, "imageName": img.Name})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001416 agent := dMgr.getDeviceAgent(ctx, img.Id)
1417 if agent == nil {
1418 return imageDownloadFailureResp, status.Errorf(codes.NotFound, "%s", img.Id)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001419 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001420 resp, err := agent.getImageDownloadStatus(ctx, img)
1421 if err != nil {
1422 return imageDownloadFailureResp, err
1423 }
1424 return resp, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001425}
1426
Kent Hagerman2b216042020-04-03 18:28:56 -04001427func (dMgr *Manager) UpdateImageDownload(ctx context.Context, deviceID string, img *voltha.ImageDownload) error {
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001428 log.EnrichSpan(ctx, log.Fields{"device-id": img.Id})
1429
Rohan Agrawal31f21802020-06-12 05:38:46 +00001430 logger.Debugw(ctx, "UpdateImageDownload", log.Fields{"device-id": img.Id, "imageName": img.Name})
npujar467fe752020-01-16 20:17:45 +05301431 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
1432 if err := agent.updateImageDownload(ctx, img); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001433 logger.Debugw(ctx, "UpdateImageDownload-failed", log.Fields{"err": err, "imageName": img.Name})
khenaidoof5a5bfa2019-01-23 22:20:29 -05001434 return err
1435 }
1436 } else {
1437 return status.Errorf(codes.NotFound, "%s", img.Id)
1438 }
1439 return nil
1440}
1441
Kent Hagerman45a13e42020-04-13 12:23:50 -04001442// GetImageDownload returns image download
Kent Hagerman2b216042020-04-03 18:28:56 -04001443func (dMgr *Manager) GetImageDownload(ctx context.Context, img *voltha.ImageDownload) (*voltha.ImageDownload, error) {
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001444 log.EnrichSpan(ctx, log.Fields{"device-id": img.Id})
1445
Rohan Agrawal31f21802020-06-12 05:38:46 +00001446 logger.Debugw(ctx, "GetImageDownload", log.Fields{"device-id": img.Id, "imageName": img.Name})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001447 agent := dMgr.getDeviceAgent(ctx, img.Id)
1448 if agent == nil {
1449 return imageDownloadFailureResp, status.Errorf(codes.NotFound, "%s", img.Id)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001450 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001451 resp, err := agent.getImageDownload(ctx, img)
1452 if err != nil {
1453 return imageDownloadFailureResp, err
1454 }
1455 return resp, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001456}
1457
Kent Hagerman45a13e42020-04-13 12:23:50 -04001458// ListImageDownloads returns image downloads
1459func (dMgr *Manager) ListImageDownloads(ctx context.Context, id *voltha.ID) (*voltha.ImageDownloads, error) {
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001460 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
1461
Rohan Agrawal31f21802020-06-12 05:38:46 +00001462 logger.Debugw(ctx, "ListImageDownloads", log.Fields{"device-id": id.Id})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001463 agent := dMgr.getDeviceAgent(ctx, id.Id)
1464 if agent == nil {
1465 return &voltha.ImageDownloads{Items: []*voltha.ImageDownload{imageDownloadFailureResp}}, status.Errorf(codes.NotFound, "%s", id.Id)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001466 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001467 resp, err := agent.listImageDownloads(ctx, id.Id)
1468 if err != nil {
1469 return &voltha.ImageDownloads{Items: []*voltha.ImageDownload{imageDownloadFailureResp}}, err
1470 }
1471 return resp, nil
1472}
1473
1474// GetImages returns all images for a specific device entry
1475func (dMgr *Manager) GetImages(ctx context.Context, id *voltha.ID) (*voltha.Images, error) {
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001476 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
1477
Rohan Agrawal31f21802020-06-12 05:38:46 +00001478 logger.Debugw(ctx, "GetImages", log.Fields{"device-id": id.Id})
Kent Hagermancba2f302020-07-28 13:37:36 -04001479 device, err := dMgr.getDeviceReadOnly(ctx, id.Id)
Kent Hagerman45a13e42020-04-13 12:23:50 -04001480 if err != nil {
1481 return nil, err
1482 }
Kent Hagermancba2f302020-07-28 13:37:36 -04001483 return device.Images, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001484}
1485
Rohan Agrawal31f21802020-06-12 05:38:46 +00001486func (dMgr *Manager) NotifyInvalidTransition(ctx context.Context, device *voltha.Device) error {
1487 logger.Errorw(ctx, "NotifyInvalidTransition", log.Fields{
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001488 "device": device.Id,
1489 "curr-admin-state": device.AdminState,
1490 "curr-oper-state": device.OperStatus,
1491 "curr-conn-state": device.ConnectStatus,
Stephane Barbarieef6650d2019-07-18 12:15:09 -04001492 })
khenaidoo0a822f92019-05-08 15:15:57 -04001493 //TODO: notify over kafka?
1494 return nil
1495}
1496
khenaidoob9203542018-09-17 22:56:37 -04001497func funcName(f interface{}) string {
1498 p := reflect.ValueOf(f).Pointer()
1499 rf := runtime.FuncForPC(p)
1500 return rf.Name()
1501}
1502
npujar1d86a522019-11-14 17:11:16 +05301503// UpdateDeviceAttribute updates value of particular device attribute
Kent Hagerman2b216042020-04-03 18:28:56 -04001504func (dMgr *Manager) UpdateDeviceAttribute(ctx context.Context, deviceID string, attribute string, value interface{}) {
npujar1d86a522019-11-14 17:11:16 +05301505 if agent, ok := dMgr.deviceAgents.Load(deviceID); ok {
Kent Hagerman2b216042020-04-03 18:28:56 -04001506 agent.(*Agent).updateDeviceAttribute(ctx, attribute, value)
khenaidoob9203542018-09-17 22:56:37 -04001507 }
1508}
1509
npujar1d86a522019-11-14 17:11:16 +05301510// GetParentDeviceID returns parent device id, either from memory or from the dB, if present
Kent Hagerman2b216042020-04-03 18:28:56 -04001511func (dMgr *Manager) GetParentDeviceID(ctx context.Context, deviceID string) string {
Kent Hagermancba2f302020-07-28 13:37:36 -04001512 if device, _ := dMgr.getDeviceReadOnly(ctx, deviceID); device != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +00001513 logger.Infow(ctx, "GetParentDeviceId", log.Fields{"device-id": device.Id, "parentId": device.ParentId})
khenaidoo4c9e5592019-09-09 16:20:41 -04001514 return device.ParentId
khenaidoob9203542018-09-17 22:56:37 -04001515 }
khenaidoo4c9e5592019-09-09 16:20:41 -04001516 return ""
khenaidoob9203542018-09-17 22:56:37 -04001517}
serkant.uluderya334479d2019-04-10 08:26:15 -07001518
Kent Hagerman45a13e42020-04-13 12:23:50 -04001519func (dMgr *Manager) SimulateAlarm(ctx context.Context, simulateReq *voltha.SimulateAlarmRequest) (*common.OperationResp, error) {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001520 logger.Debugw(ctx, "SimulateAlarm", log.Fields{"id": simulateReq.Id, "Indicator": simulateReq.Indicator, "IntfId": simulateReq.IntfId,
Kent Hagerman45a13e42020-04-13 12:23:50 -04001521 "PortTypeName": simulateReq.PortTypeName, "OnuDeviceId": simulateReq.OnuDeviceId, "InverseBitErrorRate": simulateReq.InverseBitErrorRate,
1522 "Drift": simulateReq.Drift, "NewEqd": simulateReq.NewEqd, "OnuSerialNumber": simulateReq.OnuSerialNumber, "Operation": simulateReq.Operation})
1523 agent := dMgr.getDeviceAgent(ctx, simulateReq.Id)
1524 if agent == nil {
1525 return nil, status.Errorf(codes.NotFound, "%s", simulateReq.Id)
serkant.uluderya334479d2019-04-10 08:26:15 -07001526 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001527 if err := agent.simulateAlarm(ctx, simulateReq); err != nil {
1528 return nil, err
1529 }
1530 return &common.OperationResp{Code: common.OperationResp_OPERATION_SUCCESS}, nil
serkant.uluderya334479d2019-04-10 08:26:15 -07001531}
Mahir Gunyelfdee9212019-10-16 16:52:21 -07001532
Kent Hagerman2b216042020-04-03 18:28:56 -04001533func (dMgr *Manager) UpdateDeviceReason(ctx context.Context, deviceID string, reason string) error {
divyadesaicb8b59d2020-08-18 09:55:47 +00001534 logger.Debugw(ctx, "UpdateDeviceReason", log.Fields{"device-id": deviceID, "reason": reason})
npujar467fe752020-01-16 20:17:45 +05301535 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
1536 return agent.updateDeviceReason(ctx, reason)
Mahir Gunyelfdee9212019-10-16 16:52:21 -07001537 }
npujar1d86a522019-11-14 17:11:16 +05301538 return status.Errorf(codes.NotFound, "%s", deviceID)
Mahir Gunyelfdee9212019-10-16 16:52:21 -07001539}
kesavandbc2d1622020-01-21 00:42:01 -05001540
Kent Hagerman45a13e42020-04-13 12:23:50 -04001541func (dMgr *Manager) EnablePort(ctx context.Context, port *voltha.Port) (*empty.Empty, error) {
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001542 log.EnrichSpan(ctx, log.Fields{"device-id": port.DeviceId})
1543
Rohan Agrawal31f21802020-06-12 05:38:46 +00001544 logger.Debugw(ctx, "EnablePort", log.Fields{"device-id": port.DeviceId, "port-no": port.PortNo})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001545 agent := dMgr.getDeviceAgent(ctx, port.DeviceId)
1546 if agent == nil {
1547 return nil, status.Errorf(codes.NotFound, "%s", port.DeviceId)
kesavandbc2d1622020-01-21 00:42:01 -05001548 }
Kent Hagerman2a07b862020-06-19 15:23:07 -04001549 return &empty.Empty{}, agent.enablePort(ctx, port.PortNo)
kesavandbc2d1622020-01-21 00:42:01 -05001550}
1551
Kent Hagerman45a13e42020-04-13 12:23:50 -04001552func (dMgr *Manager) DisablePort(ctx context.Context, port *voltha.Port) (*empty.Empty, error) {
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001553 log.EnrichSpan(ctx, log.Fields{"device-id": port.DeviceId})
1554
Rohan Agrawal31f21802020-06-12 05:38:46 +00001555 logger.Debugw(ctx, "DisablePort", log.Fields{"device-id": port.DeviceId, "port-no": port.PortNo})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001556 agent := dMgr.getDeviceAgent(ctx, port.DeviceId)
1557 if agent == nil {
1558 return nil, status.Errorf(codes.NotFound, "%s", port.DeviceId)
kesavandbc2d1622020-01-21 00:42:01 -05001559 }
Kent Hagerman2a07b862020-06-19 15:23:07 -04001560 return &empty.Empty{}, agent.disablePort(ctx, port.PortNo)
kesavandbc2d1622020-01-21 00:42:01 -05001561}
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001562
Kent Hagerman2b216042020-04-03 18:28:56 -04001563// ChildDeviceLost calls parent adapter to delete child device and all its references
1564func (dMgr *Manager) ChildDeviceLost(ctx context.Context, curr *voltha.Device) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001565 logger.Debugw(ctx, "childDeviceLost", log.Fields{"child-device-id": curr.Id, "parent-device-id": curr.ParentId})
khenaidoo442e7c72020-03-10 16:13:48 -04001566 if parentAgent := dMgr.getDeviceAgent(ctx, curr.ParentId); parentAgent != nil {
khenaidooe132f522020-03-20 15:23:15 -04001567 if err := parentAgent.ChildDeviceLost(ctx, curr); err != nil {
1568 // Just log the message and let the remaining pipeline proceed.
Rohan Agrawal31f21802020-06-12 05:38:46 +00001569 logger.Warnw(ctx, "childDeviceLost", log.Fields{"child-device-id": curr.Id, "parent-device-id": curr.ParentId, "error": err})
khenaidooe132f522020-03-20 15:23:15 -04001570 }
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001571 }
khenaidooe132f522020-03-20 15:23:15 -04001572 // Do not return an error as parent device may also have been deleted. Let the remaining pipeline proceed.
1573 return nil
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001574}
onkarkundargi87285252020-01-27 11:34:52 +05301575
Kent Hagerman45a13e42020-04-13 12:23:50 -04001576func (dMgr *Manager) StartOmciTestAction(ctx context.Context, request *voltha.OmciTestRequest) (*voltha.TestResponse, error) {
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001577 log.EnrichSpan(ctx, log.Fields{"device-id": request.Id})
1578
Rohan Agrawal31f21802020-06-12 05:38:46 +00001579 logger.Debugw(ctx, "StartOmciTestAction", log.Fields{"device-id": request.Id, "uuid": request.Uuid})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001580 agent := dMgr.getDeviceAgent(ctx, request.Id)
1581 if agent == nil {
1582 return nil, status.Errorf(codes.NotFound, "%s", request.Id)
onkarkundargi87285252020-01-27 11:34:52 +05301583 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001584 return agent.startOmciTest(ctx, request)
onkarkundargi87285252020-01-27 11:34:52 +05301585}
Dinesh Belwalkarc1129f12020-02-27 10:41:33 -08001586
1587func (dMgr *Manager) GetExtValue(ctx context.Context, value *voltha.ValueSpecifier) (*voltha.ReturnValues, error) {
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001588 log.EnrichSpan(ctx, log.Fields{"device-id": value.Id})
1589
Girish Kumar3e8ee212020-08-19 17:50:11 +00001590 logger.Debugw(ctx, "getExtValue", log.Fields{"onu-id": value.Id})
Kent Hagermancba2f302020-07-28 13:37:36 -04001591 cDevice, err := dMgr.getDeviceReadOnly(ctx, value.Id)
Dinesh Belwalkarc1129f12020-02-27 10:41:33 -08001592 if err != nil {
1593 return nil, status.Errorf(codes.Aborted, "%s", err.Error())
1594 }
Kent Hagermancba2f302020-07-28 13:37:36 -04001595 pDevice, err := dMgr.getDeviceReadOnly(ctx, cDevice.ParentId)
Dinesh Belwalkarc1129f12020-02-27 10:41:33 -08001596 if err != nil {
1597 return nil, status.Errorf(codes.Aborted, "%s", err.Error())
1598 }
1599 if agent := dMgr.getDeviceAgent(ctx, cDevice.ParentId); agent != nil {
1600 resp, err := agent.getExtValue(ctx, pDevice, cDevice, value)
1601 if err != nil {
1602 return nil, err
1603 }
Girish Kumar3e8ee212020-08-19 17:50:11 +00001604 logger.Debugw(ctx, "getExtValue-result", log.Fields{"result": resp})
Dinesh Belwalkarc1129f12020-02-27 10:41:33 -08001605 return resp, nil
1606 }
1607 return nil, status.Errorf(codes.NotFound, "%s", value.Id)
1608
1609}