blob: 9220fe5195866b797b7382f9351212b3dded5bdf [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 "sync"
23 "time"
24
Kent Hagerman45a13e42020-04-13 12:23:50 -040025 "github.com/golang/protobuf/ptypes/empty"
sbarbari17d7e222019-11-05 10:02:29 -050026 "github.com/opencord/voltha-go/db/model"
Kent Hagerman2b216042020-04-03 18:28:56 -040027 "github.com/opencord/voltha-go/rw_core/core/adapter"
Kent Hagermanf5a67352020-04-30 15:15:26 -040028 "github.com/opencord/voltha-go/rw_core/core/device/event"
Kent Hagerman2b216042020-04-03 18:28:56 -040029 "github.com/opencord/voltha-go/rw_core/core/device/remote"
Kent Hagerman6031aad2020-07-29 16:36:33 -040030 "github.com/opencord/voltha-go/rw_core/core/device/state"
khenaidoo3d3b8c22019-05-22 18:10:39 -040031 "github.com/opencord/voltha-go/rw_core/utils"
Maninderdfadc982020-10-28 14:04:33 +053032 "github.com/opencord/voltha-lib-go/v4/pkg/kafka"
33 "github.com/opencord/voltha-lib-go/v4/pkg/log"
34 "github.com/opencord/voltha-protos/v4/go/common"
35 ic "github.com/opencord/voltha-protos/v4/go/inter_container"
36 "github.com/opencord/voltha-protos/v4/go/openflow_13"
37 ofp "github.com/opencord/voltha-protos/v4/go/openflow_13"
38 "github.com/opencord/voltha-protos/v4/go/voltha"
khenaidoob9203542018-09-17 22:56:37 -040039 "google.golang.org/grpc/codes"
40 "google.golang.org/grpc/status"
khenaidoob9203542018-09-17 22:56:37 -040041)
42
Kent Hagerman2b216042020-04-03 18:28:56 -040043// Manager represent device manager attributes
44type Manager struct {
khenaidoo4c9e5592019-09-09 16:20:41 -040045 deviceAgents sync.Map
46 rootDevices map[string]bool
47 lockRootDeviceMap sync.RWMutex
Kent Hagerman2b216042020-04-03 18:28:56 -040048 adapterProxy *remote.AdapterProxy
49 adapterMgr *adapter.Manager
50 logicalDeviceMgr *LogicalManager
npujar467fe752020-01-16 20:17:45 +053051 kafkaICProxy kafka.InterContainerProxy
Kent Hagerman6031aad2020-07-29 16:36:33 -040052 stateTransitions *state.TransitionMap
Mahir Gunyel03de0d32020-06-03 01:36:59 -070053 dbPath *model.Path
Kent Hagermanf5a67352020-04-30 15:15:26 -040054 dProxy *model.Proxy
npujar1d86a522019-11-14 17:11:16 +053055 coreInstanceID string
khenaidoo442e7c72020-03-10 16:13:48 -040056 defaultTimeout time.Duration
khenaidoo4c9e5592019-09-09 16:20:41 -040057 devicesLoadingLock sync.RWMutex
58 deviceLoadingInProgress map[string][]chan int
khenaidoob9203542018-09-17 22:56:37 -040059}
60
Mahir Gunyel03de0d32020-06-03 01:36:59 -070061//NewManagers creates the Manager and the Logical Manager.
serkant.uluderya8ff291d2020-05-20 00:58:00 -070062func 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 -040063 deviceMgr := &Manager{
Kent Hagerman2b216042020-04-03 18:28:56 -040064 rootDevices: make(map[string]bool),
65 kafkaICProxy: kmp,
serkant.uluderya8ff291d2020-05-20 00:58:00 -070066 adapterProxy: remote.NewAdapterProxy(kmp, coreTopic, endpointMgr),
Kent Hagerman2b216042020-04-03 18:28:56 -040067 coreInstanceID: coreInstanceID,
Mahir Gunyel03de0d32020-06-03 01:36:59 -070068 dbPath: dbPath,
69 dProxy: dbPath.Proxy("devices"),
Kent Hagerman2b216042020-04-03 18:28:56 -040070 adapterMgr: adapterMgr,
Kent Hagermanf4151de2020-06-19 15:58:47 -040071 defaultTimeout: defaultCoreTimeout,
Kent Hagerman2b216042020-04-03 18:28:56 -040072 deviceLoadingInProgress: make(map[string][]chan int),
73 }
Kent Hagerman6031aad2020-07-29 16:36:33 -040074 deviceMgr.stateTransitions = state.NewTransitionMap(deviceMgr)
Kent Hagerman2f0d0552020-04-23 17:28:52 -040075
Kent Hagerman2b216042020-04-03 18:28:56 -040076 logicalDeviceMgr := &LogicalManager{
Kent Hagerman45a13e42020-04-13 12:23:50 -040077 Manager: event.NewManager(),
Kent Hagerman2b216042020-04-03 18:28:56 -040078 deviceMgr: deviceMgr,
79 kafkaICProxy: kmp,
Mahir Gunyel03de0d32020-06-03 01:36:59 -070080 dbPath: dbPath,
81 ldProxy: dbPath.Proxy("logical_devices"),
Kent Hagerman2b216042020-04-03 18:28:56 -040082 defaultTimeout: defaultCoreTimeout,
83 logicalDeviceLoadingInProgress: make(map[string][]chan int),
84 }
85 deviceMgr.logicalDeviceMgr = logicalDeviceMgr
Matteo Scandolod525ae32020-04-02 17:27:29 -070086
Kent Hagerman2b216042020-04-03 18:28:56 -040087 adapterMgr.SetAdapterRestartedCallback(deviceMgr.adapterRestarted)
Matteo Scandolod525ae32020-04-02 17:27:29 -070088
Kent Hagerman2b216042020-04-03 18:28:56 -040089 return deviceMgr, logicalDeviceMgr
khenaidoob9203542018-09-17 22:56:37 -040090}
91
Kent Hagerman2b216042020-04-03 18:28:56 -040092func (dMgr *Manager) addDeviceAgentToMap(agent *Agent) {
npujar1d86a522019-11-14 17:11:16 +053093 if _, exist := dMgr.deviceAgents.Load(agent.deviceID); !exist {
94 dMgr.deviceAgents.Store(agent.deviceID, agent)
khenaidoob9203542018-09-17 22:56:37 -040095 }
khenaidoo2c6a0992019-04-29 13:46:56 -040096 dMgr.lockRootDeviceMap.Lock()
97 defer dMgr.lockRootDeviceMap.Unlock()
Kent Hagerman2a07b862020-06-19 15:23:07 -040098 dMgr.rootDevices[agent.deviceID] = agent.isRootDevice
khenaidoo2c6a0992019-04-29 13:46:56 -040099
khenaidoob9203542018-09-17 22:56:37 -0400100}
101
Kent Hagerman2b216042020-04-03 18:28:56 -0400102func (dMgr *Manager) deleteDeviceAgentFromMap(agent *Agent) {
npujar1d86a522019-11-14 17:11:16 +0530103 dMgr.deviceAgents.Delete(agent.deviceID)
khenaidoo2c6a0992019-04-29 13:46:56 -0400104 dMgr.lockRootDeviceMap.Lock()
105 defer dMgr.lockRootDeviceMap.Unlock()
npujar1d86a522019-11-14 17:11:16 +0530106 delete(dMgr.rootDevices, agent.deviceID)
khenaidoo4d4802d2018-10-04 21:59:49 -0400107}
108
khenaidoo297cd252019-02-07 22:10:23 -0500109// 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 -0400110func (dMgr *Manager) getDeviceAgent(ctx context.Context, deviceID string) *Agent {
npujar1d86a522019-11-14 17:11:16 +0530111 agent, ok := dMgr.deviceAgents.Load(deviceID)
112 if ok {
Kent Hagerman2b216042020-04-03 18:28:56 -0400113 return agent.(*Agent)
khenaidoob9203542018-09-17 22:56:37 -0400114 }
khenaidoo442e7c72020-03-10 16:13:48 -0400115 // Try to load into memory - loading will also create the device agent and set the device ownership
npujar467fe752020-01-16 20:17:45 +0530116 err := dMgr.load(ctx, deviceID)
npujar1d86a522019-11-14 17:11:16 +0530117 if err == nil {
118 agent, ok = dMgr.deviceAgents.Load(deviceID)
119 if !ok {
120 return nil
121 }
Kent Hagerman2b216042020-04-03 18:28:56 -0400122 return agent.(*Agent)
npujar1d86a522019-11-14 17:11:16 +0530123 }
124 //TODO: Change the return params to return an error as well
divyadesaicb8b59d2020-08-18 09:55:47 +0000125 logger.Errorw(ctx, "loading-device-failed", log.Fields{"device-id": deviceID, "error": err})
khenaidoob9203542018-09-17 22:56:37 -0400126 return nil
127}
128
khenaidoo297cd252019-02-07 22:10:23 -0500129// listDeviceIdsFromMap returns the list of device IDs that are in memory
Kent Hagerman2b216042020-04-03 18:28:56 -0400130func (dMgr *Manager) listDeviceIdsFromMap() *voltha.IDs {
khenaidoo7ccedd52018-12-14 16:48:54 -0500131 result := &voltha.IDs{Items: make([]*voltha.ID, 0)}
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400132
133 dMgr.deviceAgents.Range(func(key, value interface{}) bool {
134 result.Items = append(result.Items, &voltha.ID{Id: key.(string)})
135 return true
136 })
137
khenaidoo7ccedd52018-12-14 16:48:54 -0500138 return result
139}
140
Kent Hagerman45a13e42020-04-13 12:23:50 -0400141// CreateDevice creates a new parent device in the data model
142func (dMgr *Manager) CreateDevice(ctx context.Context, device *voltha.Device) (*voltha.Device, error) {
143 if device.MacAddress == "" && device.GetHostAndPort() == "" {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000144 logger.Errorf(ctx, "No Device Info Present")
Kent Hagerman45a13e42020-04-13 12:23:50 -0400145 return &voltha.Device{}, errors.New("no-device-info-present; MAC or HOSTIP&PORT")
146 }
Rohan Agrawal31f21802020-06-12 05:38:46 +0000147 logger.Debugw(ctx, "create-device", log.Fields{"device": *device})
Kent Hagerman45a13e42020-04-13 12:23:50 -0400148
npujar467fe752020-01-16 20:17:45 +0530149 deviceExist, err := dMgr.isParentDeviceExist(ctx, device)
Thomas Lee Se5a44012019-11-07 20:32:24 +0530150 if err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000151 logger.Errorf(ctx, "Failed to fetch parent device info")
Kent Hagerman45a13e42020-04-13 12:23:50 -0400152 return nil, err
Thomas Lee Se5a44012019-11-07 20:32:24 +0530153 }
154 if deviceExist {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000155 logger.Errorf(ctx, "Device is Pre-provisioned already with same IP-Port or MAC Address")
Kent Hagerman45a13e42020-04-13 12:23:50 -0400156 return nil, errors.New("device is already pre-provisioned")
Thomas Lee S51b5cb82019-10-14 14:49:34 +0530157 }
Rohan Agrawal31f21802020-06-12 05:38:46 +0000158 logger.Debugw(ctx, "CreateDevice", log.Fields{"device": device, "aproxy": dMgr.adapterProxy})
khenaidoob9203542018-09-17 22:56:37 -0400159
khenaidoo5e677ae2019-02-28 17:26:29 -0500160 // Ensure this device is set as root
161 device.Root = true
khenaidoob9203542018-09-17 22:56:37 -0400162 // Create and start a device agent for that device
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700163 agent := newAgent(dMgr.adapterProxy, device, dMgr, dMgr.dbPath, dMgr.dProxy, dMgr.defaultTimeout)
Thomas Lee Se5a44012019-11-07 20:32:24 +0530164 device, err = agent.start(ctx, device)
Scott Baker80678602019-11-14 16:57:36 -0800165 if err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000166 logger.Errorw(ctx, "Fail-to-start-device", log.Fields{"device-id": agent.deviceID, "error": err})
Kent Hagerman45a13e42020-04-13 12:23:50 -0400167 return nil, err
Scott Baker80678602019-11-14 16:57:36 -0800168 }
khenaidoo442e7c72020-03-10 16:13:48 -0400169 dMgr.addDeviceAgentToMap(agent)
Kent Hagerman45a13e42020-04-13 12:23:50 -0400170 return device, nil
khenaidoob9203542018-09-17 22:56:37 -0400171}
172
Kent Hagerman45a13e42020-04-13 12:23:50 -0400173// EnableDevice activates a device by invoking the adopt_device API on the appropriate adapter
174func (dMgr *Manager) EnableDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000175 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
176
Rohan Agrawal31f21802020-06-12 05:38:46 +0000177 logger.Debugw(ctx, "EnableDevice", log.Fields{"device-id": id.Id})
Kent Hagerman45a13e42020-04-13 12:23:50 -0400178 agent := dMgr.getDeviceAgent(ctx, id.Id)
179 if agent == nil {
180 return nil, status.Errorf(codes.NotFound, "%s", id.Id)
khenaidoob9203542018-09-17 22:56:37 -0400181 }
Kent Hagerman45a13e42020-04-13 12:23:50 -0400182 return &empty.Empty{}, agent.enableDevice(ctx)
khenaidoob9203542018-09-17 22:56:37 -0400183}
184
Kent Hagerman45a13e42020-04-13 12:23:50 -0400185// DisableDevice disables a device along with any child device it may have
186func (dMgr *Manager) DisableDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000187 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
188
Rohan Agrawal31f21802020-06-12 05:38:46 +0000189 logger.Debugw(ctx, "DisableDevice", log.Fields{"device-id": id.Id})
Kent Hagerman45a13e42020-04-13 12:23:50 -0400190 agent := dMgr.getDeviceAgent(ctx, id.Id)
191 if agent == nil {
192 return nil, status.Errorf(codes.NotFound, "%s", id.Id)
khenaidoob9203542018-09-17 22:56:37 -0400193 }
Kent Hagerman45a13e42020-04-13 12:23:50 -0400194 return &empty.Empty{}, agent.disableDevice(ctx)
khenaidoo92e62c52018-10-03 14:02:54 -0400195}
196
Kent Hagerman45a13e42020-04-13 12:23:50 -0400197//RebootDevice invoked the reboot API to the corresponding adapter
198func (dMgr *Manager) RebootDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000199 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
200
Rohan Agrawal31f21802020-06-12 05:38:46 +0000201 logger.Debugw(ctx, "RebootDevice", log.Fields{"device-id": id.Id})
Kent Hagerman45a13e42020-04-13 12:23:50 -0400202 agent := dMgr.getDeviceAgent(ctx, id.Id)
203 if agent == nil {
204 return nil, status.Errorf(codes.NotFound, "%s", id.Id)
khenaidoo4d4802d2018-10-04 21:59:49 -0400205 }
Kent Hagerman45a13e42020-04-13 12:23:50 -0400206 return &empty.Empty{}, agent.rebootDevice(ctx)
khenaidoo4d4802d2018-10-04 21:59:49 -0400207}
208
Kent Hagerman45a13e42020-04-13 12:23:50 -0400209// DeleteDevice removes a device from the data model
210func (dMgr *Manager) DeleteDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000211 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
Rohan Agrawal31f21802020-06-12 05:38:46 +0000212 logger.Debugw(ctx, "DeleteDevice", log.Fields{"device-id": id.Id})
Kent Hagerman45a13e42020-04-13 12:23:50 -0400213 agent := dMgr.getDeviceAgent(ctx, id.Id)
214 if agent == nil {
215 return nil, status.Errorf(codes.NotFound, "%s", id.Id)
khenaidoo4d4802d2018-10-04 21:59:49 -0400216 }
Kent Hagerman45a13e42020-04-13 12:23:50 -0400217 return &empty.Empty{}, agent.deleteDevice(ctx)
218}
219
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530220// ForceDeleteDevice removes a device from the data model forcefully without successfully waiting for the adapters.
221func (dMgr *Manager) ForceDeleteDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
222 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
223 logger.Debugw(ctx, "ForceDeleteDevice", log.Fields{"device-id": id.Id})
224 agent := dMgr.getDeviceAgent(ctx, id.Id)
225 if agent == nil {
226 return nil, status.Errorf(codes.NotFound, "%s", id.Id)
227 }
228 return &empty.Empty{}, agent.deleteDeviceForce(ctx)
229}
230
Kent Hagerman2a07b862020-06-19 15:23:07 -0400231// GetDevicePort returns the port details for a specific device port entry
232func (dMgr *Manager) GetDevicePort(ctx context.Context, deviceID string, portID uint32) (*voltha.Port, error) {
233 logger.Debugw(ctx, "ListDevicePorts", log.Fields{"device-id": deviceID})
234 agent := dMgr.getDeviceAgent(ctx, deviceID)
235 if agent == nil {
236 return nil, status.Errorf(codes.NotFound, "device-%s", deviceID)
237 }
238 return agent.getDevicePort(portID)
239}
240
Kent Hagerman45a13e42020-04-13 12:23:50 -0400241// ListDevicePorts returns the ports details for a specific device entry
242func (dMgr *Manager) ListDevicePorts(ctx context.Context, id *voltha.ID) (*voltha.Ports, error) {
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000243 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
244
Rohan Agrawal31f21802020-06-12 05:38:46 +0000245 logger.Debugw(ctx, "ListDevicePorts", log.Fields{"device-id": id.Id})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400246 agent := dMgr.getDeviceAgent(ctx, id.Id)
247 if agent == nil {
248 return nil, status.Errorf(codes.NotFound, "device-%s", id.Id)
Kent Hagerman45a13e42020-04-13 12:23:50 -0400249 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400250
251 ports := agent.listDevicePorts()
252 ctr, ret := 0, make([]*voltha.Port, len(ports))
253 for _, port := range ports {
254 ret[ctr] = port
255 ctr++
256 }
257 return &voltha.Ports{Items: ret}, nil
Kent Hagerman45a13e42020-04-13 12:23:50 -0400258}
259
260// ListDeviceFlows returns the flow details for a specific device entry
261func (dMgr *Manager) ListDeviceFlows(ctx context.Context, id *voltha.ID) (*ofp.Flows, error) {
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000262 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
263
Rohan Agrawal31f21802020-06-12 05:38:46 +0000264 logger.Debugw(ctx, "ListDeviceFlows", log.Fields{"device-id": id.Id})
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700265 agent := dMgr.getDeviceAgent(ctx, id.Id)
266 if agent == nil {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400267 return nil, status.Errorf(codes.NotFound, "device-%s", id.Id)
Kent Hagerman45a13e42020-04-13 12:23:50 -0400268 }
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700269
270 flows := agent.listDeviceFlows()
271 ctr, ret := 0, make([]*ofp.OfpFlowStats, len(flows))
272 for _, flow := range flows {
273 ret[ctr] = flow
274 ctr++
275 }
276 return &openflow_13.Flows{Items: ret}, nil
Kent Hagerman45a13e42020-04-13 12:23:50 -0400277}
278
279// ListDeviceFlowGroups returns the flow group details for a specific device entry
280func (dMgr *Manager) ListDeviceFlowGroups(ctx context.Context, id *voltha.ID) (*voltha.FlowGroups, error) {
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000281 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
282
Rohan Agrawal31f21802020-06-12 05:38:46 +0000283 logger.Debugw(ctx, "ListDeviceFlowGroups", log.Fields{"device-id": id.Id})
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700284 agent := dMgr.getDeviceAgent(ctx, id.Id)
285 if agent == nil {
Kent Hagerman45a13e42020-04-13 12:23:50 -0400286 return nil, status.Errorf(codes.NotFound, "device-%s", id.Id)
287 }
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700288 groups := agent.listDeviceGroups()
289 ctr, ret := 0, make([]*openflow_13.OfpGroupEntry, len(groups))
290 for _, group := range groups {
291 ret[ctr] = group
292 ctr++
293 }
294 return &voltha.FlowGroups{Items: ret}, nil
khenaidoo4d4802d2018-10-04 21:59:49 -0400295}
296
khenaidoo6d62c002019-05-15 21:57:03 -0400297// stopManagingDevice stops the management of the device as well as any of its reference device and logical device.
298// This function is called only in the Core that does not own this device. In the Core that owns this device then a
299// deletion deletion also includes removal of any reference of this device.
Kent Hagerman2b216042020-04-03 18:28:56 -0400300func (dMgr *Manager) stopManagingDevice(ctx context.Context, id string) {
divyadesaicb8b59d2020-08-18 09:55:47 +0000301 logger.Infow(ctx, "stopManagingDevice", log.Fields{"device-id": id})
khenaidoo6d62c002019-05-15 21:57:03 -0400302 if dMgr.IsDeviceInCache(id) { // Proceed only if an agent is present for this device
Kent Hagerman6031aad2020-07-29 16:36:33 -0400303 if device, err := dMgr.getDeviceReadOnly(ctx, id); err == nil && device.Root {
khenaidoo6d62c002019-05-15 21:57:03 -0400304 // stop managing the logical device
David Bainbridged1afd662020-03-26 18:27:41 -0700305 _ = dMgr.logicalDeviceMgr.stopManagingLogicalDeviceWithDeviceID(ctx, id)
khenaidoo6d62c002019-05-15 21:57:03 -0400306 }
npujar467fe752020-01-16 20:17:45 +0530307 if agent := dMgr.getDeviceAgent(ctx, id); agent != nil {
khenaidoo442e7c72020-03-10 16:13:48 -0400308 if err := agent.stop(ctx); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000309 logger.Warnw(ctx, "unable-to-stop-device-agent", log.Fields{"device-id": agent.deviceID, "error": err})
khenaidoo442e7c72020-03-10 16:13:48 -0400310 }
khenaidoo4c9e5592019-09-09 16:20:41 -0400311 dMgr.deleteDeviceAgentFromMap(agent)
khenaidoo6d62c002019-05-15 21:57:03 -0400312 }
313 }
314}
315
npujar1d86a522019-11-14 17:11:16 +0530316// RunPostDeviceDelete removes any reference of this device
Kent Hagerman2b216042020-04-03 18:28:56 -0400317func (dMgr *Manager) RunPostDeviceDelete(ctx context.Context, cDevice *voltha.Device) error {
divyadesaicb8b59d2020-08-18 09:55:47 +0000318 logger.Infow(ctx, "RunPostDeviceDelete", log.Fields{"device-id": cDevice.Id})
npujar467fe752020-01-16 20:17:45 +0530319 dMgr.stopManagingDevice(ctx, cDevice.Id)
khenaidoo6d62c002019-05-15 21:57:03 -0400320 return nil
khenaidoo0a822f92019-05-08 15:15:57 -0400321}
322
Kent Hagermancba2f302020-07-28 13:37:36 -0400323// GetDevice exists primarily to implement the gRPC interface.
324// Internal functions should call getDeviceReadOnly instead.
Kent Hagerman45a13e42020-04-13 12:23:50 -0400325func (dMgr *Manager) GetDevice(ctx context.Context, id *voltha.ID) (*voltha.Device, error) {
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000326 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
Kent Hagermancba2f302020-07-28 13:37:36 -0400327 return dMgr.getDeviceReadOnly(ctx, id.Id)
Kent Hagerman45a13e42020-04-13 12:23:50 -0400328}
329
Kent Hagermancba2f302020-07-28 13:37:36 -0400330// getDeviceReadOnly will returns a device, either from memory or from the dB, if present
331func (dMgr *Manager) getDeviceReadOnly(ctx context.Context, id string) (*voltha.Device, error) {
divyadesaicb8b59d2020-08-18 09:55:47 +0000332 logger.Debugw(ctx, "getDeviceReadOnly", log.Fields{"device-id": id})
npujar467fe752020-01-16 20:17:45 +0530333 if agent := dMgr.getDeviceAgent(ctx, id); agent != nil {
Kent Hagermancba2f302020-07-28 13:37:36 -0400334 return agent.getDeviceReadOnly(ctx)
khenaidoo92e62c52018-10-03 14:02:54 -0400335 }
336 return nil, status.Errorf(codes.NotFound, "%s", id)
khenaidoob9203542018-09-17 22:56:37 -0400337}
338
Kent Hagerman2a07b862020-06-19 15:23:07 -0400339func (dMgr *Manager) listDevicePorts(ctx context.Context, id string) (map[uint32]*voltha.Port, error) {
divyadesaicb8b59d2020-08-18 09:55:47 +0000340 logger.Debugw(ctx, "listDevicePorts", log.Fields{"device-id": id})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400341 agent := dMgr.getDeviceAgent(ctx, id)
342 if agent == nil {
343 return nil, status.Errorf(codes.NotFound, "%s", id)
344 }
345 return agent.listDevicePorts(), nil
346}
347
npujar1d86a522019-11-14 17:11:16 +0530348// GetChildDevice will return a device, either from memory or from the dB, if present
Kent Hagerman2b216042020-04-03 18:28:56 -0400349func (dMgr *Manager) GetChildDevice(ctx context.Context, parentDeviceID string, serialNumber string, onuID int64, parentPortNo int64) (*voltha.Device, error) {
divyadesaicb8b59d2020-08-18 09:55:47 +0000350 logger.Debugw(ctx, "GetChildDevice", log.Fields{"parent-device-id": parentDeviceID, "serialNumber": serialNumber,
npujar1d86a522019-11-14 17:11:16 +0530351 "parentPortNo": parentPortNo, "onuId": onuID})
Matt Jeanneret4e241952019-02-28 11:16:04 -0500352
Kent Hagerman2a07b862020-06-19 15:23:07 -0400353 parentDevicePorts, err := dMgr.listDevicePorts(ctx, parentDeviceID)
354 if err != nil {
Matt Jeanneret4e241952019-02-28 11:16:04 -0500355 return nil, status.Errorf(codes.Aborted, "%s", err.Error())
356 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400357 childDeviceIds := dMgr.getAllChildDeviceIds(ctx, parentDevicePorts)
Matt Jeanneret4e241952019-02-28 11:16:04 -0500358 if len(childDeviceIds) == 0 {
divyadesaicb8b59d2020-08-18 09:55:47 +0000359 logger.Debugw(ctx, "no-child-devices", log.Fields{"parent-device-id": parentDeviceID, "serialNumber": serialNumber, "onuId": onuID})
npujar1d86a522019-11-14 17:11:16 +0530360 return nil, status.Errorf(codes.NotFound, "%s", parentDeviceID)
Matt Jeanneret4e241952019-02-28 11:16:04 -0500361 }
362
363 var foundChildDevice *voltha.Device
Kent Hagerman2a07b862020-06-19 15:23:07 -0400364 for childDeviceID := range childDeviceIds {
npujar1d86a522019-11-14 17:11:16 +0530365 var found bool
Kent Hagermancba2f302020-07-28 13:37:36 -0400366 if searchDevice, err := dMgr.getDeviceReadOnly(ctx, childDeviceID); err == nil {
Matt Jeanneret4e241952019-02-28 11:16:04 -0500367
npujar1d86a522019-11-14 17:11:16 +0530368 foundOnuID := false
369 if searchDevice.ProxyAddress.OnuId == uint32(onuID) {
Matt Jeanneret4e241952019-02-28 11:16:04 -0500370 if searchDevice.ParentPortNo == uint32(parentPortNo) {
divyadesaicb8b59d2020-08-18 09:55:47 +0000371 logger.Debugw(ctx, "found-child-by-onuid", log.Fields{"parent-device-id": parentDeviceID, "onuId": onuID})
npujar1d86a522019-11-14 17:11:16 +0530372 foundOnuID = true
Matt Jeanneret4e241952019-02-28 11:16:04 -0500373 }
374 }
375
376 foundSerialNumber := false
377 if searchDevice.SerialNumber == serialNumber {
divyadesaicb8b59d2020-08-18 09:55:47 +0000378 logger.Debugw(ctx, "found-child-by-serialnumber", log.Fields{"parent-device-id": parentDeviceID, "serialNumber": serialNumber})
Matt Jeanneret4e241952019-02-28 11:16:04 -0500379 foundSerialNumber = true
380 }
381
382 // if both onuId and serialNumber are provided both must be true for the device to be found
383 // otherwise whichever one found a match is good enough
npujar1d86a522019-11-14 17:11:16 +0530384 if onuID > 0 && serialNumber != "" {
385 found = foundOnuID && foundSerialNumber
Matt Jeanneret4e241952019-02-28 11:16:04 -0500386 } else {
npujar1d86a522019-11-14 17:11:16 +0530387 found = foundOnuID || foundSerialNumber
Matt Jeanneret4e241952019-02-28 11:16:04 -0500388 }
389
npujar1d86a522019-11-14 17:11:16 +0530390 if found {
Matt Jeanneret4e241952019-02-28 11:16:04 -0500391 foundChildDevice = searchDevice
392 break
393 }
394 }
395 }
396
397 if foundChildDevice != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000398 logger.Debugw(ctx, "child-device-found", log.Fields{"parent-device-id": parentDeviceID, "foundChildDevice": foundChildDevice})
Matt Jeanneret4e241952019-02-28 11:16:04 -0500399 return foundChildDevice, nil
400 }
401
divyadesaicb8b59d2020-08-18 09:55:47 +0000402 logger.Debugw(ctx, "child-device-not-found", log.Fields{"parent-device-id": parentDeviceID,
npujar1d86a522019-11-14 17:11:16 +0530403 "serialNumber": serialNumber, "onuId": onuID, "parentPortNo": parentPortNo})
404 return nil, status.Errorf(codes.NotFound, "%s", parentDeviceID)
Matt Jeanneret4e241952019-02-28 11:16:04 -0500405}
406
npujar1d86a522019-11-14 17:11:16 +0530407// GetChildDeviceWithProxyAddress will return a device based on proxy address
Kent Hagerman2b216042020-04-03 18:28:56 -0400408func (dMgr *Manager) GetChildDeviceWithProxyAddress(ctx context.Context, proxyAddress *voltha.Device_ProxyAddress) (*voltha.Device, error) {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000409 logger.Debugw(ctx, "GetChildDeviceWithProxyAddress", log.Fields{"proxyAddress": proxyAddress})
Matt Jeanneret2a20aaa2019-03-05 21:04:02 -0500410
Kent Hagerman2a07b862020-06-19 15:23:07 -0400411 parentDevicePorts, err := dMgr.listDevicePorts(ctx, proxyAddress.DeviceId)
412 if err != nil {
Matt Jeanneret2a20aaa2019-03-05 21:04:02 -0500413 return nil, status.Errorf(codes.Aborted, "%s", err.Error())
414 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400415 childDeviceIds := dMgr.getAllChildDeviceIds(ctx, parentDevicePorts)
Matt Jeanneret2a20aaa2019-03-05 21:04:02 -0500416 if len(childDeviceIds) == 0 {
divyadesaicb8b59d2020-08-18 09:55:47 +0000417 logger.Debugw(ctx, "no-child-devices", log.Fields{"parent-device-id": proxyAddress.DeviceId})
Matt Jeanneret2a20aaa2019-03-05 21:04:02 -0500418 return nil, status.Errorf(codes.NotFound, "%s", proxyAddress)
419 }
420
421 var foundChildDevice *voltha.Device
Kent Hagerman2a07b862020-06-19 15:23:07 -0400422 for childDeviceID := range childDeviceIds {
Kent Hagermancba2f302020-07-28 13:37:36 -0400423 if searchDevice, err := dMgr.getDeviceReadOnly(ctx, childDeviceID); err == nil {
Matt Jeanneret2a20aaa2019-03-05 21:04:02 -0500424 if searchDevice.ProxyAddress == proxyAddress {
425 foundChildDevice = searchDevice
426 break
427 }
428 }
429 }
430
431 if foundChildDevice != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000432 logger.Debugw(ctx, "child-device-found", log.Fields{"proxyAddress": proxyAddress})
Matt Jeanneret2a20aaa2019-03-05 21:04:02 -0500433 return foundChildDevice, nil
434 }
435
Rohan Agrawal31f21802020-06-12 05:38:46 +0000436 logger.Warnw(ctx, "child-device-not-found", log.Fields{"proxyAddress": proxyAddress})
Matt Jeanneret2a20aaa2019-03-05 21:04:02 -0500437 return nil, status.Errorf(codes.NotFound, "%s", proxyAddress)
438}
439
npujar1d86a522019-11-14 17:11:16 +0530440// IsDeviceInCache returns true if device is found in the map
Kent Hagerman2b216042020-04-03 18:28:56 -0400441func (dMgr *Manager) IsDeviceInCache(id string) bool {
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400442 _, exist := dMgr.deviceAgents.Load(id)
khenaidoo297cd252019-02-07 22:10:23 -0500443 return exist
444}
445
Stephane Barbarieaa467942019-02-06 14:09:44 -0500446// ListDevices retrieves the latest devices from the data model
Kent Hagerman45a13e42020-04-13 12:23:50 -0400447func (dMgr *Manager) ListDevices(ctx context.Context, _ *empty.Empty) (*voltha.Devices, error) {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000448 logger.Debug(ctx, "ListDevices")
khenaidoob9203542018-09-17 22:56:37 -0400449 result := &voltha.Devices{}
Kent Hagerman4f355f52020-03-30 16:01:33 -0400450
451 var devices []*voltha.Device
Kent Hagermanf5a67352020-04-30 15:15:26 -0400452 if err := dMgr.dProxy.List(ctx, &devices); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000453 logger.Errorw(ctx, "failed-to-list-devices-from-cluster-proxy", log.Fields{"error": err})
Thomas Lee Se5a44012019-11-07 20:32:24 +0530454 return nil, err
455 }
Kent Hagerman4f355f52020-03-30 16:01:33 -0400456
457 for _, device := range devices {
458 // If device is not in memory then set it up
459 if !dMgr.IsDeviceInCache(device.Id) {
divyadesaicb8b59d2020-08-18 09:55:47 +0000460 logger.Debugw(ctx, "loading-device-from-Model", log.Fields{"device-id": device.Id})
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700461 agent := newAgent(dMgr.adapterProxy, device, dMgr, dMgr.dbPath, dMgr.dProxy, dMgr.defaultTimeout)
Kent Hagerman4f355f52020-03-30 16:01:33 -0400462 if _, err := agent.start(ctx, nil); err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000463 logger.Warnw(ctx, "failure-starting-agent", log.Fields{"device-id": device.Id})
Kent Hagerman4f355f52020-03-30 16:01:33 -0400464 } else {
465 dMgr.addDeviceAgentToMap(agent)
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500466 }
khenaidoob9203542018-09-17 22:56:37 -0400467 }
Kent Hagerman4f355f52020-03-30 16:01:33 -0400468 result.Items = append(result.Items, device)
khenaidoob9203542018-09-17 22:56:37 -0400469 }
Rohan Agrawal31f21802020-06-12 05:38:46 +0000470 logger.Debugw(ctx, "ListDevices-end", log.Fields{"len": len(result.Items)})
khenaidoob9203542018-09-17 22:56:37 -0400471 return result, nil
472}
473
Thomas Lee S51b5cb82019-10-14 14:49:34 +0530474//isParentDeviceExist checks whether device is already preprovisioned.
Kent Hagerman2b216042020-04-03 18:28:56 -0400475func (dMgr *Manager) isParentDeviceExist(ctx context.Context, newDevice *voltha.Device) (bool, error) {
Thomas Lee S51b5cb82019-10-14 14:49:34 +0530476 hostPort := newDevice.GetHostAndPort()
Kent Hagerman4f355f52020-03-30 16:01:33 -0400477 var devices []*voltha.Device
Kent Hagermanf5a67352020-04-30 15:15:26 -0400478 if err := dMgr.dProxy.List(ctx, &devices); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000479 logger.Errorw(ctx, "Failed to list devices from cluster data proxy", log.Fields{"error": err})
Thomas Lee Se5a44012019-11-07 20:32:24 +0530480 return false, err
481 }
Kent Hagerman4f355f52020-03-30 16:01:33 -0400482 for _, device := range devices {
483 if !device.Root {
484 continue
485 }
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530486
487 if hostPort != "" && hostPort == device.GetHostAndPort() {
Kent Hagerman4f355f52020-03-30 16:01:33 -0400488 return true, nil
489 }
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530490 if newDevice.MacAddress != "" && newDevice.MacAddress == device.MacAddress {
Kent Hagerman4f355f52020-03-30 16:01:33 -0400491 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
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530603 // If the device is in Pre-provisioning or getting deleted state stop here
604 if device.AdminState == voltha.AdminState_PREPROVISIONED || dAgent.isDeletionInProgress() {
khenaidoo297cd252019-02-07 22:10:23 -0500605 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
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530659func (dMgr *Manager) isOkToReconcile(ctx context.Context, device *voltha.Device) bool {
khenaidooba6b6c42019-08-02 09:11:56 -0400660 if device == nil {
661 return false
662 }
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530663 if agent := dMgr.getDeviceAgent(ctx, device.Id); agent != nil {
664 return device.AdminState != voltha.AdminState_PREPROVISIONED && (!agent.isDeletionInProgress())
665 }
666 return false
khenaidooba6b6c42019-08-02 09:11:56 -0400667}
668
669// adapterRestarted is invoked whenever an adapter is restarted
Kent Hagerman2b216042020-04-03 18:28:56 -0400670func (dMgr *Manager) adapterRestarted(ctx context.Context, adapter *voltha.Adapter) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000671 logger.Debugw(ctx, "adapter-restarted", log.Fields{"adapterId": adapter.Id, "vendor": adapter.Vendor,
Matteo Scandolod525ae32020-04-02 17:27:29 -0700672 "currentReplica": adapter.CurrentReplica, "totalReplicas": adapter.TotalReplicas, "endpoint": adapter.Endpoint})
khenaidooba6b6c42019-08-02 09:11:56 -0400673
674 // Let's reconcile the device managed by this Core only
David Bainbridged1afd662020-03-26 18:27:41 -0700675 if len(dMgr.rootDevices) == 0 {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000676 logger.Debugw(ctx, "nothing-to-reconcile", log.Fields{"adapterId": adapter.Id})
khenaidooba6b6c42019-08-02 09:11:56 -0400677 return nil
678 }
679
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500680 responses := make([]utils.Response, 0)
David Bainbridged1afd662020-03-26 18:27:41 -0700681 for rootDeviceID := range dMgr.rootDevices {
npujar467fe752020-01-16 20:17:45 +0530682 if rootDevice, _ := dMgr.getDeviceFromModel(ctx, rootDeviceID); rootDevice != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000683 isDeviceOwnedByService, err := dMgr.adapterProxy.IsDeviceOwnedByService(ctx, rootDeviceID, adapter.Type, adapter.CurrentReplica)
serkant.uluderya7d545aa2020-04-09 13:38:45 -0700684 if err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000685 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 -0700686 continue
687 }
688 if isDeviceOwnedByService {
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530689 if dMgr.isOkToReconcile(ctx, rootDevice) {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000690 logger.Debugw(ctx, "reconciling-root-device", log.Fields{"rootId": rootDevice.Id})
npujar467fe752020-01-16 20:17:45 +0530691 responses = append(responses, dMgr.sendReconcileDeviceRequest(ctx, rootDevice))
khenaidooba6b6c42019-08-02 09:11:56 -0400692 } else {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000693 logger.Debugw(ctx, "not-reconciling-root-device", log.Fields{"rootId": rootDevice.Id, "state": rootDevice.AdminState})
khenaidooba6b6c42019-08-02 09:11:56 -0400694 }
695 } else { // Should we be reconciling the root's children instead?
Kent Hagerman2a07b862020-06-19 15:23:07 -0400696 rootDevicePorts, _ := dMgr.listDevicePorts(ctx, rootDeviceID)
khenaidooba6b6c42019-08-02 09:11:56 -0400697 childManagedByAdapter:
Kent Hagerman2a07b862020-06-19 15:23:07 -0400698 for _, port := range rootDevicePorts {
khenaidooba6b6c42019-08-02 09:11:56 -0400699 for _, peer := range port.Peers {
npujar467fe752020-01-16 20:17:45 +0530700 if childDevice, _ := dMgr.getDeviceFromModel(ctx, peer.DeviceId); childDevice != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000701 isDeviceOwnedByService, err := dMgr.adapterProxy.IsDeviceOwnedByService(ctx, childDevice.Id, adapter.Type, adapter.CurrentReplica)
serkant.uluderya7d545aa2020-04-09 13:38:45 -0700702 if err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000703 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 -0700704 }
705 if isDeviceOwnedByService {
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530706 if dMgr.isOkToReconcile(ctx, childDevice) {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000707 logger.Debugw(ctx, "reconciling-child-device", log.Fields{"child-device-id": childDevice.Id})
npujar467fe752020-01-16 20:17:45 +0530708 responses = append(responses, dMgr.sendReconcileDeviceRequest(ctx, childDevice))
khenaidooba6b6c42019-08-02 09:11:56 -0400709 } else {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000710 logger.Debugw(ctx, "not-reconciling-child-device", log.Fields{"child-device-id": childDevice.Id, "state": childDevice.AdminState})
khenaidooba6b6c42019-08-02 09:11:56 -0400711 }
712 } else {
713 // All child devices under a parent device are typically managed by the same adapter type.
714 // Therefore we only need to check whether the first device we retrieved is managed by that adapter
715 break childManagedByAdapter
716 }
717 }
718 }
719 }
720 }
721 }
722 }
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500723 if len(responses) > 0 {
khenaidooba6b6c42019-08-02 09:11:56 -0400724 // Wait for completion
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500725 if res := utils.WaitForNilOrErrorResponses(dMgr.defaultTimeout, responses...); res != nil {
khenaidooba6b6c42019-08-02 09:11:56 -0400726 return status.Errorf(codes.Aborted, "errors-%s", res)
727 }
728 } else {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000729 logger.Debugw(ctx, "no-managed-device-to-reconcile", log.Fields{"adapterId": adapter.Id})
khenaidooba6b6c42019-08-02 09:11:56 -0400730 }
731 return nil
732}
733
Kent Hagerman2b216042020-04-03 18:28:56 -0400734func (dMgr *Manager) sendReconcileDeviceRequest(ctx context.Context, device *voltha.Device) utils.Response {
khenaidooba6b6c42019-08-02 09:11:56 -0400735 // Send a reconcile request to the adapter. Since this Core may not be managing this device then there is no
736 // 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 +0530737 // 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 -0400738 // the adapter proxy.
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500739 response := utils.NewResponse()
Kent Hagerman2b216042020-04-03 18:28:56 -0400740 ch, err := dMgr.adapterProxy.ReconcileDevice(ctx, device)
khenaidoo442e7c72020-03-10 16:13:48 -0400741 if err != nil {
742 response.Error(err)
743 }
744 // Wait for adapter response in its own routine
745 go func() {
746 resp, ok := <-ch
747 if !ok {
748 response.Error(status.Errorf(codes.Aborted, "channel-closed-device: %s", device.Id))
749 } else if resp.Err != nil {
750 response.Error(resp.Err)
khenaidooba6b6c42019-08-02 09:11:56 -0400751 }
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500752 response.Done()
khenaidoo442e7c72020-03-10 16:13:48 -0400753 }()
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500754 return response
khenaidooba6b6c42019-08-02 09:11:56 -0400755}
756
Kent Hagerman2b216042020-04-03 18:28:56 -0400757func (dMgr *Manager) ReconcileChildDevices(ctx context.Context, parentDeviceID string) error {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400758 if parentDevicePorts, err := dMgr.listDevicePorts(ctx, parentDeviceID); err == nil {
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500759 responses := make([]utils.Response, 0)
Kent Hagerman2a07b862020-06-19 15:23:07 -0400760 for _, port := range parentDevicePorts {
khenaidooba6b6c42019-08-02 09:11:56 -0400761 for _, peer := range port.Peers {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400762 if childDevice, err := dMgr.getDeviceFromModel(ctx, peer.DeviceId); err == nil {
npujar467fe752020-01-16 20:17:45 +0530763 responses = append(responses, dMgr.sendReconcileDeviceRequest(ctx, childDevice))
khenaidooba6b6c42019-08-02 09:11:56 -0400764 }
765 }
766 }
767 // Wait for completion
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500768 if res := utils.WaitForNilOrErrorResponses(dMgr.defaultTimeout, responses...); res != nil {
khenaidooba6b6c42019-08-02 09:11:56 -0400769 return status.Errorf(codes.Aborted, "errors-%s", res)
770 }
771 }
772 return nil
773}
774
Kent Hagerman2b216042020-04-03 18:28:56 -0400775func (dMgr *Manager) UpdateDeviceUsingAdapterData(ctx context.Context, device *voltha.Device) error {
divyadesaicb8b59d2020-08-18 09:55:47 +0000776 logger.Debugw(ctx, "UpdateDeviceUsingAdapterData", log.Fields{"device-id": device.Id, "device": device})
npujar467fe752020-01-16 20:17:45 +0530777 if agent := dMgr.getDeviceAgent(ctx, device.Id); agent != nil {
778 return agent.updateDeviceUsingAdapterData(ctx, device)
khenaidoob9203542018-09-17 22:56:37 -0400779 }
780 return status.Errorf(codes.NotFound, "%s", device.Id)
781}
782
khenaidoo0db4c812020-05-27 15:27:30 -0400783func (dMgr *Manager) addPeerPort(ctx context.Context, deviceID string, port *voltha.Port) error {
784 meAsPeer := &voltha.Port_PeerPort{DeviceId: deviceID, PortNo: port.PortNo}
785 for _, peerPort := range port.Peers {
786 if agent := dMgr.getDeviceAgent(ctx, peerPort.DeviceId); agent != nil {
787 if err := agent.addPeerPort(ctx, meAsPeer); err != nil {
788 return err
789 }
790 }
791 }
792 // Notify the logical device manager to setup a logical port, if needed. If the added port is an NNI or UNI
793 // then a logical port will be added to the logical device and the device route generated. If the port is a
794 // PON port then only the device graph will be generated.
Kent Hagermancba2f302020-07-28 13:37:36 -0400795 device, err := dMgr.getDeviceReadOnly(ctx, deviceID)
khenaidoo0db4c812020-05-27 15:27:30 -0400796 if err != nil {
797 return err
798 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400799 ports, err := dMgr.listDevicePorts(ctx, deviceID)
800 if err != nil {
801 return err
802 }
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000803 if err = dMgr.logicalDeviceMgr.updateLogicalPort(log.WithSpanFromContext(context.Background(), ctx), device, ports, port); err != nil {
khenaidoo0db4c812020-05-27 15:27:30 -0400804 return err
805 }
806 return nil
807}
808
Kent Hagerman2b216042020-04-03 18:28:56 -0400809func (dMgr *Manager) AddPort(ctx context.Context, deviceID string, port *voltha.Port) error {
npujar467fe752020-01-16 20:17:45 +0530810 agent := dMgr.getDeviceAgent(ctx, deviceID)
npujar1d86a522019-11-14 17:11:16 +0530811 if agent != nil {
npujar467fe752020-01-16 20:17:45 +0530812 if err := agent.addPort(ctx, port); err != nil {
khenaidoo92e62c52018-10-03 14:02:54 -0400813 return err
814 }
khenaidoo0db4c812020-05-27 15:27:30 -0400815 // Setup peer ports in its own routine
816 go func() {
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000817 if err := dMgr.addPeerPort(log.WithSpanFromContext(context.Background(), ctx), deviceID, port); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000818 logger.Errorw(ctx, "unable-to-add-peer-port", log.Fields{"error": err, "device-id": deviceID})
khenaidoo92e62c52018-10-03 14:02:54 -0400819 }
khenaidoo0db4c812020-05-27 15:27:30 -0400820 }()
khenaidoo92e62c52018-10-03 14:02:54 -0400821 return nil
khenaidoob9203542018-09-17 22:56:37 -0400822 }
npujar1d86a522019-11-14 17:11:16 +0530823 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoob9203542018-09-17 22:56:37 -0400824}
825
Kent Hagerman2b216042020-04-03 18:28:56 -0400826func (dMgr *Manager) addFlowsAndGroups(ctx context.Context, deviceID string, flows []*ofp.OfpFlowStats, groups []*ofp.OfpGroupEntry, flowMetadata *voltha.FlowMetadata) error {
divyadesaicb8b59d2020-08-18 09:55:47 +0000827 logger.Debugw(ctx, "addFlowsAndGroups", log.Fields{"device-id": deviceID, "groups:": groups, "flowMetadata": flowMetadata})
npujar467fe752020-01-16 20:17:45 +0530828 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
829 return agent.addFlowsAndGroups(ctx, flows, groups, flowMetadata)
khenaidoo0458db62019-06-20 08:50:36 -0400830 }
npujar1d86a522019-11-14 17:11:16 +0530831 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo0458db62019-06-20 08:50:36 -0400832}
833
khenaidoo787224a2020-04-16 18:08:47 -0400834// deleteParentFlows removes flows from the parent device based on specific attributes
835func (dMgr *Manager) deleteParentFlows(ctx context.Context, deviceID string, uniPort uint32, metadata *voltha.FlowMetadata) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000836 logger.Debugw(ctx, "deleteParentFlows", log.Fields{"device-id": deviceID, "uni-port": uniPort, "metadata": metadata})
khenaidoo787224a2020-04-16 18:08:47 -0400837 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400838 if !agent.isRootDevice {
khenaidoo787224a2020-04-16 18:08:47 -0400839 return status.Errorf(codes.FailedPrecondition, "not-a-parent-device-%s", deviceID)
840 }
841 return agent.filterOutFlows(ctx, uniPort, metadata)
842 }
843 return status.Errorf(codes.NotFound, "%s", deviceID)
844}
845
Kent Hagerman2b216042020-04-03 18:28:56 -0400846func (dMgr *Manager) deleteFlowsAndGroups(ctx context.Context, deviceID string, flows []*ofp.OfpFlowStats, groups []*ofp.OfpGroupEntry, flowMetadata *voltha.FlowMetadata) error {
divyadesaicb8b59d2020-08-18 09:55:47 +0000847 logger.Debugw(ctx, "deleteFlowsAndGroups", log.Fields{"device-id": deviceID})
npujar467fe752020-01-16 20:17:45 +0530848 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
849 return agent.deleteFlowsAndGroups(ctx, flows, groups, flowMetadata)
khenaidoo0458db62019-06-20 08:50:36 -0400850 }
npujar1d86a522019-11-14 17:11:16 +0530851 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo0458db62019-06-20 08:50:36 -0400852}
853
Kent Hagerman2b216042020-04-03 18:28:56 -0400854func (dMgr *Manager) updateFlowsAndGroups(ctx context.Context, deviceID string, flows []*ofp.OfpFlowStats, groups []*ofp.OfpGroupEntry, flowMetadata *voltha.FlowMetadata) error {
divyadesaicb8b59d2020-08-18 09:55:47 +0000855 logger.Debugw(ctx, "updateFlowsAndGroups", log.Fields{"device-id": deviceID})
npujar467fe752020-01-16 20:17:45 +0530856 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
857 return agent.updateFlowsAndGroups(ctx, flows, groups, flowMetadata)
khenaidoo19d7b632018-10-30 10:49:50 -0400858 }
npujar1d86a522019-11-14 17:11:16 +0530859 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo19d7b632018-10-30 10:49:50 -0400860}
861
Kent Hagerman45a13e42020-04-13 12:23:50 -0400862// UpdateDevicePmConfigs updates the PM configs. This is executed when the northbound gRPC API is invoked, typically
khenaidoob3127472019-07-24 21:04:55 -0400863// following a user action
Kent Hagerman45a13e42020-04-13 12:23:50 -0400864func (dMgr *Manager) UpdateDevicePmConfigs(ctx context.Context, configs *voltha.PmConfigs) (*empty.Empty, error) {
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000865 log.EnrichSpan(ctx, log.Fields{"device-id": configs.Id})
866
Kent Hagerman45a13e42020-04-13 12:23:50 -0400867 if configs.Id == "" {
868 return nil, status.Error(codes.FailedPrecondition, "invalid-device-Id")
khenaidoob3127472019-07-24 21:04:55 -0400869 }
Kent Hagerman45a13e42020-04-13 12:23:50 -0400870 agent := dMgr.getDeviceAgent(ctx, configs.Id)
871 if agent == nil {
872 return nil, status.Errorf(codes.NotFound, "%s", configs.Id)
873 }
874 return &empty.Empty{}, agent.updatePmConfigs(ctx, configs)
khenaidoob3127472019-07-24 21:04:55 -0400875}
876
Kent Hagerman2b216042020-04-03 18:28:56 -0400877// InitPmConfigs initialize the pm configs as defined by the adapter.
878func (dMgr *Manager) InitPmConfigs(ctx context.Context, deviceID string, pmConfigs *voltha.PmConfigs) error {
khenaidoob3127472019-07-24 21:04:55 -0400879 if pmConfigs.Id == "" {
880 return status.Errorf(codes.FailedPrecondition, "invalid-device-Id")
881 }
npujar467fe752020-01-16 20:17:45 +0530882 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
883 return agent.initPmConfigs(ctx, pmConfigs)
khenaidoob9203542018-09-17 22:56:37 -0400884 }
npujar1d86a522019-11-14 17:11:16 +0530885 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoob9203542018-09-17 22:56:37 -0400886}
887
Kent Hagerman45a13e42020-04-13 12:23:50 -0400888// ListDevicePmConfigs returns pm configs of device
889func (dMgr *Manager) ListDevicePmConfigs(ctx context.Context, id *voltha.ID) (*voltha.PmConfigs, error) {
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000890 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
891
Kent Hagerman45a13e42020-04-13 12:23:50 -0400892 agent := dMgr.getDeviceAgent(ctx, id.Id)
893 if agent == nil {
894 return nil, status.Errorf(codes.NotFound, "%s", id.Id)
khenaidoob3127472019-07-24 21:04:55 -0400895 }
Kent Hagerman45a13e42020-04-13 12:23:50 -0400896 return agent.listPmConfigs(ctx)
khenaidoob3127472019-07-24 21:04:55 -0400897}
898
Kent Hagerman2b216042020-04-03 18:28:56 -0400899func (dMgr *Manager) getSwitchCapability(ctx context.Context, deviceID string) (*ic.SwitchCapability, error) {
divyadesaicb8b59d2020-08-18 09:55:47 +0000900 logger.Debugw(ctx, "getSwitchCapability", log.Fields{"device-id": deviceID})
npujar467fe752020-01-16 20:17:45 +0530901 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
khenaidoob9203542018-09-17 22:56:37 -0400902 return agent.getSwitchCapability(ctx)
903 }
npujar1d86a522019-11-14 17:11:16 +0530904 return nil, status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoob9203542018-09-17 22:56:37 -0400905}
906
Kent Hagerman2b216042020-04-03 18:28:56 -0400907func (dMgr *Manager) GetPorts(ctx context.Context, deviceID string, portType voltha.Port_PortType) (*voltha.Ports, error) {
divyadesaicb8b59d2020-08-18 09:55:47 +0000908 logger.Debugw(ctx, "GetPorts", log.Fields{"device-id": deviceID, "portType": portType})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400909 agent := dMgr.getDeviceAgent(ctx, deviceID)
910 if agent == nil {
911 return nil, status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoob9203542018-09-17 22:56:37 -0400912 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400913 return agent.getPorts(ctx, portType), nil
khenaidoob9203542018-09-17 22:56:37 -0400914}
915
Kent Hagerman2b216042020-04-03 18:28:56 -0400916func (dMgr *Manager) UpdateDeviceStatus(ctx context.Context, deviceID string, operStatus voltha.OperStatus_Types, connStatus voltha.ConnectStatus_Types) error {
divyadesaicb8b59d2020-08-18 09:55:47 +0000917 logger.Debugw(ctx, "UpdateDeviceStatus", log.Fields{"device-id": deviceID, "operStatus": operStatus, "connStatus": connStatus})
npujar467fe752020-01-16 20:17:45 +0530918 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
919 return agent.updateDeviceStatus(ctx, operStatus, connStatus)
khenaidoo92e62c52018-10-03 14:02:54 -0400920 }
npujar1d86a522019-11-14 17:11:16 +0530921 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo92e62c52018-10-03 14:02:54 -0400922}
923
Kent Hagerman2b216042020-04-03 18:28:56 -0400924func (dMgr *Manager) UpdateChildrenStatus(ctx context.Context, deviceID string, operStatus voltha.OperStatus_Types, connStatus voltha.ConnectStatus_Types) error {
divyadesaicb8b59d2020-08-18 09:55:47 +0000925 logger.Debugw(ctx, "UpdateChildrenStatus", log.Fields{"parent-device-id": deviceID, "operStatus": operStatus, "connStatus": connStatus})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400926 parentDevicePorts, err := dMgr.listDevicePorts(ctx, deviceID)
927 if err != nil {
khenaidoo4d4802d2018-10-04 21:59:49 -0400928 return status.Errorf(codes.Aborted, "%s", err.Error())
929 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400930 for childDeviceID := range dMgr.getAllChildDeviceIds(ctx, parentDevicePorts) {
npujar467fe752020-01-16 20:17:45 +0530931 if agent := dMgr.getDeviceAgent(ctx, childDeviceID); agent != nil {
932 if err = agent.updateDeviceStatus(ctx, operStatus, connStatus); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530933 return status.Errorf(codes.Aborted, "childDevice:%s, error:%s", childDeviceID, err.Error())
khenaidoo4d4802d2018-10-04 21:59:49 -0400934 }
935 }
936 }
937 return nil
938}
939
Kent Hagerman2b216042020-04-03 18:28:56 -0400940func (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 +0000941 logger.Debugw(ctx, "UpdatePortState", log.Fields{"device-id": deviceID, "portType": portType, "portNo": portNo, "operStatus": operStatus})
npujar467fe752020-01-16 20:17:45 +0530942 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
943 if err := agent.updatePortState(ctx, portType, portNo, operStatus); err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000944 logger.Errorw(ctx, "updating-port-state-failed", log.Fields{"device-id": deviceID, "portNo": portNo, "error": err})
khenaidoo171b98e2019-10-31 11:48:15 -0400945 return err
946 }
947 // Notify the logical device manager to change the port state
Mahir Gunyel18fa0c92020-03-06 13:34:04 -0800948 // Do this for NNI and UNIs only. PON ports are not known by logical device
949 if portType == voltha.Port_ETHERNET_NNI || portType == voltha.Port_ETHERNET_UNI {
950 go func() {
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000951 err := dMgr.logicalDeviceMgr.updatePortState(log.WithSpanFromContext(context.Background(), ctx), deviceID, portNo, operStatus)
Mahir Gunyel18fa0c92020-03-06 13:34:04 -0800952 if err != nil {
953 // While we want to handle (catch) and log when
954 // an update to a port was not able to be
955 // propagated to the logical port, we can report
956 // it as a warning and not an error because it
957 // doesn't stop or modify processing.
958 // TODO: VOL-2707
Rohan Agrawal31f21802020-06-12 05:38:46 +0000959 logger.Warnw(ctx, "unable-to-update-logical-port-state", log.Fields{"error": err})
Mahir Gunyel18fa0c92020-03-06 13:34:04 -0800960 }
961 }()
962 }
khenaidoo442e7c72020-03-10 16:13:48 -0400963 return nil
khenaidoob9203542018-09-17 22:56:37 -0400964 }
npujar1d86a522019-11-14 17:11:16 +0530965 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoob9203542018-09-17 22:56:37 -0400966}
967
Kent Hagerman2b216042020-04-03 18:28:56 -0400968func (dMgr *Manager) DeleteAllPorts(ctx context.Context, deviceID string) error {
divyadesaicb8b59d2020-08-18 09:55:47 +0000969 logger.Debugw(ctx, "DeleteAllPorts", log.Fields{"device-id": deviceID})
npujar467fe752020-01-16 20:17:45 +0530970 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
971 if err := agent.deleteAllPorts(ctx); err != nil {
khenaidoo0a822f92019-05-08 15:15:57 -0400972 return err
973 }
974 // Notify the logical device manager to remove all logical ports, if needed.
Kent Hagerman2b216042020-04-03 18:28:56 -0400975 // At this stage the device itself may gave been deleted already at a DeleteAllPorts
khenaidoo0a822f92019-05-08 15:15:57 -0400976 // typically is part of a device deletion phase.
Kent Hagermancba2f302020-07-28 13:37:36 -0400977 if device, err := dMgr.getDeviceReadOnly(ctx, deviceID); err == nil {
npujar1d86a522019-11-14 17:11:16 +0530978 go func() {
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000979 if err := dMgr.logicalDeviceMgr.deleteAllLogicalPorts(log.WithSpanFromContext(context.Background(), ctx), device); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000980 logger.Errorw(ctx, "unable-to-delete-logical-ports", log.Fields{"error": err})
npujar1d86a522019-11-14 17:11:16 +0530981 }
982 }()
khenaidoo0a822f92019-05-08 15:15:57 -0400983 } else {
divyadesaicb8b59d2020-08-18 09:55:47 +0000984 logger.Warnw(ctx, "failed-to-retrieve-device", log.Fields{"device-id": deviceID})
khenaidoo0a822f92019-05-08 15:15:57 -0400985 return err
986 }
987 return nil
988 }
npujar1d86a522019-11-14 17:11:16 +0530989 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo0a822f92019-05-08 15:15:57 -0400990}
991
Kent Hagerman2b216042020-04-03 18:28:56 -0400992//UpdatePortsState updates all ports on the device
Kent Hagerman2a07b862020-06-19 15:23:07 -0400993func (dMgr *Manager) UpdatePortsState(ctx context.Context, deviceID string, portTypeFilter uint32, state voltha.OperStatus_Types) error {
divyadesaicb8b59d2020-08-18 09:55:47 +0000994 logger.Debugw(ctx, "UpdatePortsState", log.Fields{"device-id": deviceID})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400995 agent := dMgr.getDeviceAgent(ctx, deviceID)
996 if agent == nil {
997 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo3ab34882019-05-02 21:33:30 -0400998 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400999 if state != voltha.OperStatus_ACTIVE && state != voltha.OperStatus_UNKNOWN {
1000 return status.Error(codes.Unimplemented, "state-change-not-implemented")
1001 }
1002 if err := agent.updatePortsOperState(ctx, portTypeFilter, state); err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +00001003 logger.Warnw(ctx, "updatePortsOperState-failed", log.Fields{"device-id": deviceID, "error": err})
Kent Hagerman2a07b862020-06-19 15:23:07 -04001004 return err
1005 }
1006 return nil
khenaidoo3ab34882019-05-02 21:33:30 -04001007}
1008
Kent Hagerman2b216042020-04-03 18:28:56 -04001009func (dMgr *Manager) ChildDeviceDetected(ctx context.Context, parentDeviceID string, parentPortNo int64, deviceType string,
npujar1d86a522019-11-14 17:11:16 +05301010 channelID int64, vendorID string, serialNumber string, onuID int64) (*voltha.Device, error) {
divyadesaicb8b59d2020-08-18 09:55:47 +00001011 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 -07001012
npujar1d86a522019-11-14 17:11:16 +05301013 if deviceType == "" && vendorID != "" {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001014 logger.Debug(ctx, "device-type-is-nil-fetching-device-type")
Kent Hagerman45a13e42020-04-13 12:23:50 -04001015 deviceTypes, err := dMgr.adapterMgr.ListDeviceTypes(ctx, nil)
1016 if err != nil {
1017 return nil, err
1018 }
Kent Hagerman4f355f52020-03-30 16:01:33 -04001019 OLoop:
Kent Hagerman45a13e42020-04-13 12:23:50 -04001020 for _, dType := range deviceTypes.Items {
Kent Hagerman4f355f52020-03-30 16:01:33 -04001021 for _, v := range dType.VendorIds {
1022 if v == vendorID {
1023 deviceType = dType.Adapter
1024 break OLoop
Chaitrashree G S4b3fada2019-07-28 23:55:25 -07001025 }
1026 }
1027 }
1028 }
1029 //if no match found for the vendorid,report adapter with the custom error message
1030 if deviceType == "" {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001031 logger.Errorw(ctx, "failed-to-fetch-adapter-name ", log.Fields{"vendorId": vendorID})
npujar1d86a522019-11-14 17:11:16 +05301032 return nil, status.Errorf(codes.NotFound, "%s", vendorID)
Chaitrashree G S4b3fada2019-07-28 23:55:25 -07001033 }
khenaidoob9203542018-09-17 22:56:37 -04001034
1035 // Create the ONU device
1036 childDevice := &voltha.Device{}
khenaidoob9203542018-09-17 22:56:37 -04001037 childDevice.Type = deviceType
npujar1d86a522019-11-14 17:11:16 +05301038 childDevice.ParentId = parentDeviceID
khenaidoob9203542018-09-17 22:56:37 -04001039 childDevice.ParentPortNo = uint32(parentPortNo)
npujar1d86a522019-11-14 17:11:16 +05301040 childDevice.VendorId = vendorID
Matt Jeanneret4e241952019-02-28 11:16:04 -05001041 childDevice.SerialNumber = serialNumber
khenaidoob9203542018-09-17 22:56:37 -04001042 childDevice.Root = false
khenaidoo6fdf0ba2018-11-02 14:38:33 -04001043
khenaidoo442e7c72020-03-10 16:13:48 -04001044 // Get parent device type
1045 pAgent := dMgr.getDeviceAgent(ctx, parentDeviceID)
1046 if pAgent == nil {
npujar1d86a522019-11-14 17:11:16 +05301047 return nil, status.Errorf(codes.NotFound, "%s", parentDeviceID)
khenaidoo6fdf0ba2018-11-02 14:38:33 -04001048 }
khenaidoo442e7c72020-03-10 16:13:48 -04001049 if pAgent.deviceType == "" {
1050 return nil, status.Errorf(codes.FailedPrecondition, "device Type not set %s", parentDeviceID)
1051 }
khenaidoo6fdf0ba2018-11-02 14:38:33 -04001052
npujar467fe752020-01-16 20:17:45 +05301053 if device, err := dMgr.GetChildDevice(ctx, parentDeviceID, serialNumber, onuID, parentPortNo); err == nil {
divyadesaicb8b59d2020-08-18 09:55:47 +00001054 logger.Warnw(ctx, "child-device-exists", log.Fields{"parent-device-id": parentDeviceID, "serialNumber": serialNumber})
Mahir Gunyel6deaa242019-06-27 04:53:33 -07001055 return device, status.Errorf(codes.AlreadyExists, "%s", serialNumber)
Matt Jeanneret4e241952019-02-28 11:16:04 -05001056 }
1057
khenaidoo442e7c72020-03-10 16:13:48 -04001058 childDevice.ProxyAddress = &voltha.Device_ProxyAddress{DeviceId: parentDeviceID, DeviceType: pAgent.deviceType, ChannelId: uint32(channelID), OnuId: uint32(onuID)}
khenaidoob9203542018-09-17 22:56:37 -04001059
1060 // Create and start a device agent for that device
Mahir Gunyel03de0d32020-06-03 01:36:59 -07001061 agent := newAgent(dMgr.adapterProxy, childDevice, dMgr, dMgr.dbPath, dMgr.dProxy, dMgr.defaultTimeout)
Mahir Gunyel23bd8c72020-09-21 23:20:43 -07001062 insertedChildDevice, err := agent.start(ctx, childDevice)
Scott Baker80678602019-11-14 16:57:36 -08001063 if err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001064 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 -08001065 return nil, err
1066 }
khenaidoo442e7c72020-03-10 16:13:48 -04001067 dMgr.addDeviceAgentToMap(agent)
khenaidoob9203542018-09-17 22:56:37 -04001068
1069 // Activate the child device
npujar467fe752020-01-16 20:17:45 +05301070 if agent = dMgr.getDeviceAgent(ctx, agent.deviceID); agent != nil {
npujar1d86a522019-11-14 17:11:16 +05301071 go func() {
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001072 err := agent.enableDevice(log.WithSpanFromContext(context.Background(), ctx))
npujar1d86a522019-11-14 17:11:16 +05301073 if err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001074 logger.Errorw(ctx, "unable-to-enable-device", log.Fields{"error": err})
npujar1d86a522019-11-14 17:11:16 +05301075 }
1076 }()
khenaidoob9203542018-09-17 22:56:37 -04001077 }
1078
Mahir Gunyel23bd8c72020-09-21 23:20:43 -07001079 return insertedChildDevice, nil
khenaidoob9203542018-09-17 22:56:37 -04001080}
1081
Kent Hagerman2b216042020-04-03 18:28:56 -04001082func (dMgr *Manager) packetOut(ctx context.Context, deviceID string, outPort uint32, packet *ofp.OfpPacketOut) error {
divyadesaicb8b59d2020-08-18 09:55:47 +00001083 logger.Debugw(ctx, "packetOut", log.Fields{"device-id": deviceID, "outPort": outPort})
npujar467fe752020-01-16 20:17:45 +05301084 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
1085 return agent.packetOut(ctx, outPort, packet)
khenaidoofdbad6e2018-11-06 22:26:38 -05001086 }
npujar1d86a522019-11-14 17:11:16 +05301087 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoofdbad6e2018-11-06 22:26:38 -05001088}
1089
npujar1d86a522019-11-14 17:11:16 +05301090// PacketIn receives packet from adapter
Kent Hagerman2b216042020-04-03 18:28:56 -04001091func (dMgr *Manager) PacketIn(ctx context.Context, deviceID string, port uint32, transactionID string, packet []byte) error {
divyadesaicb8b59d2020-08-18 09:55:47 +00001092 logger.Debugw(ctx, "PacketIn", log.Fields{"device-id": deviceID, "port": port})
khenaidoofdbad6e2018-11-06 22:26:38 -05001093 // Get the logical device Id based on the deviceId
1094 var device *voltha.Device
1095 var err error
Kent Hagermancba2f302020-07-28 13:37:36 -04001096 if device, err = dMgr.getDeviceReadOnly(ctx, deviceID); err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +00001097 logger.Errorw(ctx, "device-not-found", log.Fields{"device-id": deviceID})
khenaidoofdbad6e2018-11-06 22:26:38 -05001098 return err
1099 }
khenaidoo43c82122018-11-22 18:38:28 -05001100 if !device.Root {
divyadesaicb8b59d2020-08-18 09:55:47 +00001101 logger.Errorw(ctx, "device-not-root", log.Fields{"device-id": deviceID})
npujar1d86a522019-11-14 17:11:16 +05301102 return status.Errorf(codes.FailedPrecondition, "%s", deviceID)
khenaidoofdbad6e2018-11-06 22:26:38 -05001103 }
1104
npujar467fe752020-01-16 20:17:45 +05301105 if err := dMgr.logicalDeviceMgr.packetIn(ctx, device.ParentId, port, transactionID, packet); err != nil {
khenaidoofdbad6e2018-11-06 22:26:38 -05001106 return err
1107 }
1108 return nil
1109}
1110
Kent Hagerman2b216042020-04-03 18:28:56 -04001111func (dMgr *Manager) setParentID(ctx context.Context, device *voltha.Device, parentID string) error {
divyadesaicb8b59d2020-08-18 09:55:47 +00001112 logger.Debugw(ctx, "setParentId", log.Fields{"device-id": device.Id, "parentId": parentID})
npujar467fe752020-01-16 20:17:45 +05301113 if agent := dMgr.getDeviceAgent(ctx, device.Id); agent != nil {
1114 return agent.setParentID(ctx, device, parentID)
khenaidooad06fd72019-10-28 12:26:05 -04001115 }
1116 return status.Errorf(codes.NotFound, "%s", device.Id)
1117}
1118
npujar1d86a522019-11-14 17:11:16 +05301119// CreateLogicalDevice creates logical device in core
Kent Hagerman2b216042020-04-03 18:28:56 -04001120func (dMgr *Manager) CreateLogicalDevice(ctx context.Context, cDevice *voltha.Device) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001121 logger.Info(ctx, "CreateLogicalDevice")
khenaidoo59ef7be2019-06-21 12:40:28 -04001122 // Verify whether the logical device has already been created
1123 if cDevice.ParentId != "" {
divyadesaicb8b59d2020-08-18 09:55:47 +00001124 logger.Debugw(ctx, "Parent device already exist.", log.Fields{"device-id": cDevice.Id, "logical-device-id": cDevice.Id})
khenaidoo59ef7be2019-06-21 12:40:28 -04001125 return nil
1126 }
khenaidoob9203542018-09-17 22:56:37 -04001127 var err error
npujar467fe752020-01-16 20:17:45 +05301128 if _, err = dMgr.logicalDeviceMgr.createLogicalDevice(ctx, cDevice); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001129 logger.Warnw(ctx, "createlogical-device-error", log.Fields{"device": cDevice})
khenaidoob9203542018-09-17 22:56:37 -04001130 return err
1131 }
khenaidoob9203542018-09-17 22:56:37 -04001132 return nil
1133}
1134
npujar1d86a522019-11-14 17:11:16 +05301135// DeleteLogicalDevice deletes logical device from core
Kent Hagerman2b216042020-04-03 18:28:56 -04001136func (dMgr *Manager) DeleteLogicalDevice(ctx context.Context, cDevice *voltha.Device) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001137 logger.Info(ctx, "DeleteLogicalDevice")
khenaidoo92e62c52018-10-03 14:02:54 -04001138 var err error
npujar467fe752020-01-16 20:17:45 +05301139 if err = dMgr.logicalDeviceMgr.deleteLogicalDevice(ctx, cDevice); err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +00001140 logger.Warnw(ctx, "deleteLogical-device-error", log.Fields{"device-id": cDevice.Id})
khenaidoo92e62c52018-10-03 14:02:54 -04001141 return err
1142 }
1143 // Remove the logical device Id from the parent device
npujar1d86a522019-11-14 17:11:16 +05301144 logicalID := ""
npujar467fe752020-01-16 20:17:45 +05301145 dMgr.UpdateDeviceAttribute(ctx, cDevice.Id, "ParentId", logicalID)
khenaidoo92e62c52018-10-03 14:02:54 -04001146 return nil
1147}
1148
npujar1d86a522019-11-14 17:11:16 +05301149// DeleteLogicalPorts removes the logical ports associated with that deviceId
Kent Hagerman2b216042020-04-03 18:28:56 -04001150func (dMgr *Manager) DeleteLogicalPorts(ctx context.Context, cDevice *voltha.Device) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001151 logger.Debugw(ctx, "delete-all-logical-ports", log.Fields{"device-id": cDevice.Id})
khenaidoo442e7c72020-03-10 16:13:48 -04001152 if err := dMgr.logicalDeviceMgr.deleteLogicalPorts(ctx, cDevice.Id); err != nil {
khenaidooe132f522020-03-20 15:23:15 -04001153 // 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 +00001154 logger.Warnw(ctx, "deleteLogical-ports-error", log.Fields{"device-id": cDevice.Id, "error": err})
khenaidoo0a822f92019-05-08 15:15:57 -04001155 }
1156 return nil
1157}
1158
Kent Hagerman2b216042020-04-03 18:28:56 -04001159func (dMgr *Manager) getParentDevice(ctx context.Context, childDevice *voltha.Device) *voltha.Device {
khenaidoo92e62c52018-10-03 14:02:54 -04001160 // Sanity check
1161 if childDevice.Root {
1162 // childDevice is the parent device
1163 return childDevice
1164 }
Kent Hagermancba2f302020-07-28 13:37:36 -04001165 parentDevice, _ := dMgr.getDeviceReadOnly(ctx, childDevice.ParentId)
khenaidoo92e62c52018-10-03 14:02:54 -04001166 return parentDevice
1167}
1168
Kent Hagerman2b216042020-04-03 18:28:56 -04001169//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 -04001170//cannot manage the child devices. This will trigger the Core to disable all the child devices.
Kent Hagerman2b216042020-04-03 18:28:56 -04001171func (dMgr *Manager) ChildDevicesLost(ctx context.Context, parentDeviceID string) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001172 logger.Debug(ctx, "ChildDevicesLost")
Kent Hagermancba2f302020-07-28 13:37:36 -04001173 parentDevice, err := dMgr.getDeviceReadOnly(ctx, parentDeviceID)
Kent Hagerman2a07b862020-06-19 15:23:07 -04001174 if err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +00001175 logger.Warnw(ctx, "failed-getting-device", log.Fields{"parent-device-id": parentDeviceID, "error": err})
khenaidoo0a822f92019-05-08 15:15:57 -04001176 return err
1177 }
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001178 return dMgr.DisableAllChildDevices(ctx, parentDevice)
khenaidoo0a822f92019-05-08 15:15:57 -04001179}
1180
Kent Hagerman2b216042020-04-03 18:28:56 -04001181//ChildDevicesDetected is invoked by an adapter when child devices are found, typically after after a
khenaidoo0a822f92019-05-08 15:15:57 -04001182// disable/enable sequence. This will trigger the Core to Enable all the child devices of that parent.
Kent Hagerman2b216042020-04-03 18:28:56 -04001183func (dMgr *Manager) ChildDevicesDetected(ctx context.Context, parentDeviceID string) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001184 logger.Debug(ctx, "ChildDevicesDetected")
Kent Hagerman2a07b862020-06-19 15:23:07 -04001185 parentDevicePorts, err := dMgr.listDevicePorts(ctx, parentDeviceID)
1186 if err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +00001187 logger.Warnw(ctx, "failed-getting-device", log.Fields{"device-id": parentDeviceID, "error": err})
khenaidoo0a822f92019-05-08 15:15:57 -04001188 return err
1189 }
Kent Hagerman2a07b862020-06-19 15:23:07 -04001190 childDeviceIds := dMgr.getAllChildDeviceIds(ctx, parentDevicePorts)
khenaidoo0a822f92019-05-08 15:15:57 -04001191 if len(childDeviceIds) == 0 {
divyadesaicb8b59d2020-08-18 09:55:47 +00001192 logger.Debugw(ctx, "no-child-device", log.Fields{"parent-device-id": parentDeviceID})
khenaidoo0a822f92019-05-08 15:15:57 -04001193 }
khenaidoo59ef7be2019-06-21 12:40:28 -04001194 allChildEnableRequestSent := true
Kent Hagerman2a07b862020-06-19 15:23:07 -04001195 for childDeviceID := range childDeviceIds {
npujar467fe752020-01-16 20:17:45 +05301196 if agent := dMgr.getDeviceAgent(ctx, childDeviceID); agent != nil {
khenaidoo59ef7be2019-06-21 12:40:28 -04001197 // Run the children re-registration in its own routine
Kent Hagerman2a07b862020-06-19 15:23:07 -04001198 go func(ctx context.Context) {
1199 err = agent.enableDevice(ctx)
npujar1d86a522019-11-14 17:11:16 +05301200 if err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001201 logger.Errorw(ctx, "unable-to-enable-device", log.Fields{"error": err})
npujar1d86a522019-11-14 17:11:16 +05301202 }
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001203 }(log.WithSpanFromContext(context.Background(), ctx))
khenaidoo59ef7be2019-06-21 12:40:28 -04001204 } else {
npujar1d86a522019-11-14 17:11:16 +05301205 err = status.Errorf(codes.Unavailable, "no agent for child device %s", childDeviceID)
divyadesaicb8b59d2020-08-18 09:55:47 +00001206 logger.Errorw(ctx, "no-child-device-agent", log.Fields{"parent-device-id": parentDeviceID, "childId": childDeviceID})
khenaidoo59ef7be2019-06-21 12:40:28 -04001207 allChildEnableRequestSent = false
khenaidoo0a822f92019-05-08 15:15:57 -04001208 }
1209 }
khenaidoo59ef7be2019-06-21 12:40:28 -04001210 if !allChildEnableRequestSent {
khenaidoo0a822f92019-05-08 15:15:57 -04001211 return err
1212 }
1213 return nil
1214}
1215
khenaidoo4d4802d2018-10-04 21:59:49 -04001216/*
1217All the functions below are callback functions where they are invoked with the latest and previous data. We can
1218therefore use the data as is without trying to get the latest from the model.
1219*/
1220
khenaidoo0a822f92019-05-08 15:15:57 -04001221//DisableAllChildDevices is invoked as a callback when the parent device is disabled
Kent Hagerman2b216042020-04-03 18:28:56 -04001222func (dMgr *Manager) DisableAllChildDevices(ctx context.Context, parentCurrDevice *voltha.Device) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001223 logger.Debug(ctx, "DisableAllChildDevices")
Kent Hagerman2a07b862020-06-19 15:23:07 -04001224 ports, _ := dMgr.listDevicePorts(ctx, parentCurrDevice.Id)
1225 for childDeviceID := range dMgr.getAllChildDeviceIds(ctx, ports) {
npujar467fe752020-01-16 20:17:45 +05301226 if agent := dMgr.getDeviceAgent(ctx, childDeviceID); agent != nil {
Kent Hagerman2a07b862020-06-19 15:23:07 -04001227 if err := agent.disableDevice(ctx); err != nil {
khenaidooe132f522020-03-20 15:23:15 -04001228 // Just log the error - this error happens only if the child device was already in deleted state.
divyadesaicb8b59d2020-08-18 09:55:47 +00001229 logger.Errorw(ctx, "failure-disable-device", log.Fields{"device-id": childDeviceID, "error": err.Error()})
khenaidoo92e62c52018-10-03 14:02:54 -04001230 }
1231 }
1232 }
1233 return nil
1234}
1235
khenaidoo0a822f92019-05-08 15:15:57 -04001236//DeleteAllChildDevices is invoked as a callback when the parent device is deleted
Kent Hagerman2b216042020-04-03 18:28:56 -04001237func (dMgr *Manager) DeleteAllChildDevices(ctx context.Context, parentCurrDevice *voltha.Device) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001238 logger.Debug(ctx, "DeleteAllChildDevices")
Himani Chawla2ba1c9c2020-10-07 13:19:03 +05301239 force := false
1240 // Get the parent device Transient state, if its FORCE_DELETED(go for force delete for child devices)
1241 // So in cases when this handler is getting called other than DELETE operation, no force option would be used.
1242 agent := dMgr.getDeviceAgent(ctx, parentCurrDevice.Id)
1243 if agent == nil {
1244 return status.Errorf(codes.NotFound, "%s", parentCurrDevice.Id)
1245 }
1246
1247 force = agent.getTransientState() == voltha.DeviceTransientState_FORCE_DELETING
1248
Kent Hagerman2a07b862020-06-19 15:23:07 -04001249 ports, _ := dMgr.listDevicePorts(ctx, parentCurrDevice.Id)
1250 for childDeviceID := range dMgr.getAllChildDeviceIds(ctx, ports) {
npujar467fe752020-01-16 20:17:45 +05301251 if agent := dMgr.getDeviceAgent(ctx, childDeviceID); agent != nil {
Himani Chawla2ba1c9c2020-10-07 13:19:03 +05301252 if force {
1253 if err := agent.deleteDeviceForce(ctx); err != nil {
1254 logger.Warnw(ctx, "failure-delete-device-force", log.Fields{"device-id": childDeviceID,
1255 "error": err.Error()})
1256 }
1257 } else {
1258 if err := agent.deleteDevice(ctx); err != nil {
1259 logger.Warnw(ctx, "failure-delete-device", log.Fields{"device-id": childDeviceID,
1260 "error": err.Error()})
1261 }
khenaidoo4d4802d2018-10-04 21:59:49 -04001262 }
khenaidoo49085352020-01-13 19:15:43 -05001263 // No further action is required here. The deleteDevice will change the device state where the resulting
1264 // callback will take care of cleaning the child device agent.
khenaidoo4d4802d2018-10-04 21:59:49 -04001265 }
1266 }
khenaidoo4d4802d2018-10-04 21:59:49 -04001267 return nil
1268}
1269
Girish Gowdra408cd962020-03-11 14:31:31 -07001270//DeleteAllLogicalPorts is invoked as a callback when the parent device's connection status moves to UNREACHABLE
Kent Hagerman2b216042020-04-03 18:28:56 -04001271func (dMgr *Manager) DeleteAllLogicalPorts(ctx context.Context, parentDevice *voltha.Device) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001272 logger.Debugw(ctx, "delete-all-logical-ports", log.Fields{"parent-device-id": parentDevice.Id})
Girish Gowdra408cd962020-03-11 14:31:31 -07001273 if err := dMgr.logicalDeviceMgr.deleteAllLogicalPorts(ctx, parentDevice); err != nil {
khenaidooe132f522020-03-20 15:23:15 -04001274 // Just log error as logical device may already have been deleted
Rohan Agrawal31f21802020-06-12 05:38:46 +00001275 logger.Warnw(ctx, "delete-all-logical-ports-fail", log.Fields{"parent-device-id": parentDevice.Id, "error": err})
Girish Gowdra408cd962020-03-11 14:31:31 -07001276 }
1277 return nil
1278}
1279
1280//DeleteAllDeviceFlows is invoked as a callback when the parent device's connection status moves to UNREACHABLE
Kent Hagerman2b216042020-04-03 18:28:56 -04001281func (dMgr *Manager) DeleteAllDeviceFlows(ctx context.Context, parentDevice *voltha.Device) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001282 logger.Debugw(ctx, "delete-all-device-flows", log.Fields{"parent-device-id": parentDevice.Id})
Girish Gowdra408cd962020-03-11 14:31:31 -07001283 if agent := dMgr.getDeviceAgent(ctx, parentDevice.Id); agent != nil {
1284 if err := agent.deleteAllFlows(ctx); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001285 logger.Errorw(ctx, "error-deleting-all-device-flows", log.Fields{"parent-device-id": parentDevice.Id})
Girish Gowdra408cd962020-03-11 14:31:31 -07001286 return err
1287 }
1288 return nil
1289 }
1290 return status.Errorf(codes.NotFound, "%s", parentDevice.Id)
1291}
1292
khenaidoo4d4802d2018-10-04 21:59:49 -04001293//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 -04001294func (dMgr *Manager) getAllChildDeviceIds(ctx context.Context, parentDevicePorts map[uint32]*voltha.Port) map[string]struct{} {
1295 logger.Debug(ctx, "getAllChildDeviceIds")
1296 childDeviceIds := make(map[string]struct{}, len(parentDevicePorts))
1297 for _, port := range parentDevicePorts {
1298 for _, peer := range port.Peers {
1299 childDeviceIds[peer.DeviceId] = struct{}{}
khenaidoo92e62c52018-10-03 14:02:54 -04001300 }
1301 }
Kent Hagerman2a07b862020-06-19 15:23:07 -04001302 logger.Debugw(ctx, "returning-getAllChildDeviceIds", log.Fields{"childDeviceIds": childDeviceIds})
1303 return childDeviceIds
khenaidoo92e62c52018-10-03 14:02:54 -04001304}
1305
Kent Hagerman2b216042020-04-03 18:28:56 -04001306//GetAllChildDevices is a helper method to get all the child device IDs from the device passed as parameter
1307func (dMgr *Manager) GetAllChildDevices(ctx context.Context, parentDeviceID string) (*voltha.Devices, error) {
divyadesaicb8b59d2020-08-18 09:55:47 +00001308 logger.Debugw(ctx, "GetAllChildDevices", log.Fields{"parent-device-id": parentDeviceID})
Kent Hagerman2a07b862020-06-19 15:23:07 -04001309 if parentDevicePorts, err := dMgr.listDevicePorts(ctx, parentDeviceID); err == nil {
khenaidoo297cd252019-02-07 22:10:23 -05001310 childDevices := make([]*voltha.Device, 0)
Kent Hagerman2a07b862020-06-19 15:23:07 -04001311 for deviceID := range dMgr.getAllChildDeviceIds(ctx, parentDevicePorts) {
Kent Hagermancba2f302020-07-28 13:37:36 -04001312 if d, e := dMgr.getDeviceReadOnly(ctx, deviceID); e == nil && d != nil {
Kent Hagerman2a07b862020-06-19 15:23:07 -04001313 childDevices = append(childDevices, d)
khenaidoo297cd252019-02-07 22:10:23 -05001314 }
1315 }
1316 return &voltha.Devices{Items: childDevices}, nil
1317 }
npujar1d86a522019-11-14 17:11:16 +05301318 return nil, status.Errorf(codes.NotFound, "%s", parentDeviceID)
khenaidoo297cd252019-02-07 22:10:23 -05001319}
1320
npujar1d86a522019-11-14 17:11:16 +05301321// SetupUNILogicalPorts creates UNI ports on the logical device that represents a child UNI interface
Kent Hagerman2b216042020-04-03 18:28:56 -04001322func (dMgr *Manager) SetupUNILogicalPorts(ctx context.Context, cDevice *voltha.Device) error {
Kent Hagermanf6db9f12020-07-22 17:16:19 -04001323 logger.Info(ctx, "SetupUNILogicalPorts")
Kent Hagerman2a07b862020-06-19 15:23:07 -04001324 cDevicePorts, err := dMgr.listDevicePorts(ctx, cDevice.Id)
1325 if err != nil {
1326 return err
1327 }
1328 if err := dMgr.logicalDeviceMgr.setupUNILogicalPorts(ctx, cDevice, cDevicePorts); err != nil {
Kent Hagermanf6db9f12020-07-22 17:16:19 -04001329 logger.Warnw(ctx, "setupUNILogicalPorts-error", log.Fields{"device": cDevice, "err": err})
khenaidoob9203542018-09-17 22:56:37 -04001330 return err
1331 }
1332 return nil
1333}
1334
Kent Hagerman45a13e42020-04-13 12:23:50 -04001335// convenience to avoid redefining
1336var operationFailureResp = &common.OperationResp{Code: voltha.OperationResp_OPERATION_FAILURE}
1337
1338// DownloadImage execute an image download request
1339func (dMgr *Manager) DownloadImage(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001340 log.EnrichSpan(ctx, log.Fields{"device-id": img.Id})
1341
Rohan Agrawal31f21802020-06-12 05:38:46 +00001342 logger.Debugw(ctx, "DownloadImage", log.Fields{"device-id": img.Id, "imageName": img.Name})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001343 agent := dMgr.getDeviceAgent(ctx, img.Id)
1344 if agent == nil {
1345 return operationFailureResp, status.Errorf(codes.NotFound, "%s", img.Id)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001346 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001347 resp, err := agent.downloadImage(ctx, img)
1348 if err != nil {
1349 return operationFailureResp, err
1350 }
1351 return resp, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001352}
1353
Kent Hagerman45a13e42020-04-13 12:23:50 -04001354// CancelImageDownload cancels image download request
1355func (dMgr *Manager) CancelImageDownload(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001356 log.EnrichSpan(ctx, log.Fields{"device-id": img.Id})
1357
Rohan Agrawal31f21802020-06-12 05:38:46 +00001358 logger.Debugw(ctx, "CancelImageDownload", log.Fields{"device-id": img.Id, "imageName": img.Name})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001359 agent := dMgr.getDeviceAgent(ctx, img.Id)
1360 if agent == nil {
1361 return operationFailureResp, status.Errorf(codes.NotFound, "%s", img.Id)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001362 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001363 resp, err := agent.cancelImageDownload(ctx, img)
1364 if err != nil {
1365 return operationFailureResp, err
1366 }
1367 return resp, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001368}
1369
Kent Hagerman45a13e42020-04-13 12:23:50 -04001370// ActivateImageUpdate activates image update request
1371func (dMgr *Manager) ActivateImageUpdate(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001372 log.EnrichSpan(ctx, log.Fields{"device-id": img.Id})
1373
Rohan Agrawal31f21802020-06-12 05:38:46 +00001374 logger.Debugw(ctx, "ActivateImageUpdate", log.Fields{"device-id": img.Id, "imageName": img.Name})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001375 agent := dMgr.getDeviceAgent(ctx, img.Id)
1376 if agent == nil {
1377 return operationFailureResp, status.Errorf(codes.NotFound, "%s", img.Id)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001378 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001379 resp, err := agent.activateImage(ctx, img)
1380 if err != nil {
1381 return operationFailureResp, err
1382 }
1383 return resp, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001384}
1385
Kent Hagerman45a13e42020-04-13 12:23:50 -04001386// RevertImageUpdate reverts image update
1387func (dMgr *Manager) RevertImageUpdate(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001388 log.EnrichSpan(ctx, log.Fields{"device-id": img.Id})
1389
Rohan Agrawal31f21802020-06-12 05:38:46 +00001390 logger.Debugw(ctx, "RevertImageUpdate", log.Fields{"device-id": img.Id, "imageName": img.Name})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001391 agent := dMgr.getDeviceAgent(ctx, img.Id)
1392 if agent == nil {
1393 return operationFailureResp, status.Errorf(codes.NotFound, "%s", img.Id)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001394 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001395 resp, err := agent.revertImage(ctx, img)
1396 if err != nil {
1397 return operationFailureResp, err
1398 }
1399 return resp, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001400}
1401
Kent Hagerman45a13e42020-04-13 12:23:50 -04001402// convenience to avoid redefining
1403var imageDownloadFailureResp = &voltha.ImageDownload{DownloadState: voltha.ImageDownload_DOWNLOAD_UNKNOWN}
1404
1405// GetImageDownloadStatus returns status of image download
1406func (dMgr *Manager) GetImageDownloadStatus(ctx context.Context, img *voltha.ImageDownload) (*voltha.ImageDownload, error) {
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001407 log.EnrichSpan(ctx, log.Fields{"device-id": img.Id})
1408
Rohan Agrawal31f21802020-06-12 05:38:46 +00001409 logger.Debugw(ctx, "GetImageDownloadStatus", log.Fields{"device-id": img.Id, "imageName": img.Name})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001410 agent := dMgr.getDeviceAgent(ctx, img.Id)
1411 if agent == nil {
1412 return imageDownloadFailureResp, status.Errorf(codes.NotFound, "%s", img.Id)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001413 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001414 resp, err := agent.getImageDownloadStatus(ctx, img)
1415 if err != nil {
1416 return imageDownloadFailureResp, err
1417 }
1418 return resp, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001419}
1420
Kent Hagerman2b216042020-04-03 18:28:56 -04001421func (dMgr *Manager) UpdateImageDownload(ctx context.Context, deviceID string, img *voltha.ImageDownload) error {
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001422 log.EnrichSpan(ctx, log.Fields{"device-id": img.Id})
1423
Rohan Agrawal31f21802020-06-12 05:38:46 +00001424 logger.Debugw(ctx, "UpdateImageDownload", log.Fields{"device-id": img.Id, "imageName": img.Name})
npujar467fe752020-01-16 20:17:45 +05301425 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
1426 if err := agent.updateImageDownload(ctx, img); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001427 logger.Debugw(ctx, "UpdateImageDownload-failed", log.Fields{"err": err, "imageName": img.Name})
khenaidoof5a5bfa2019-01-23 22:20:29 -05001428 return err
1429 }
1430 } else {
1431 return status.Errorf(codes.NotFound, "%s", img.Id)
1432 }
1433 return nil
1434}
1435
Kent Hagerman45a13e42020-04-13 12:23:50 -04001436// GetImageDownload returns image download
Kent Hagerman2b216042020-04-03 18:28:56 -04001437func (dMgr *Manager) GetImageDownload(ctx context.Context, img *voltha.ImageDownload) (*voltha.ImageDownload, error) {
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001438 log.EnrichSpan(ctx, log.Fields{"device-id": img.Id})
1439
Rohan Agrawal31f21802020-06-12 05:38:46 +00001440 logger.Debugw(ctx, "GetImageDownload", log.Fields{"device-id": img.Id, "imageName": img.Name})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001441 agent := dMgr.getDeviceAgent(ctx, img.Id)
1442 if agent == nil {
1443 return imageDownloadFailureResp, status.Errorf(codes.NotFound, "%s", img.Id)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001444 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001445 resp, err := agent.getImageDownload(ctx, img)
1446 if err != nil {
1447 return imageDownloadFailureResp, err
1448 }
1449 return resp, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001450}
1451
Kent Hagerman45a13e42020-04-13 12:23:50 -04001452// ListImageDownloads returns image downloads
1453func (dMgr *Manager) ListImageDownloads(ctx context.Context, id *voltha.ID) (*voltha.ImageDownloads, error) {
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001454 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
1455
Rohan Agrawal31f21802020-06-12 05:38:46 +00001456 logger.Debugw(ctx, "ListImageDownloads", log.Fields{"device-id": id.Id})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001457 agent := dMgr.getDeviceAgent(ctx, id.Id)
1458 if agent == nil {
1459 return &voltha.ImageDownloads{Items: []*voltha.ImageDownload{imageDownloadFailureResp}}, status.Errorf(codes.NotFound, "%s", id.Id)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001460 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001461 resp, err := agent.listImageDownloads(ctx, id.Id)
1462 if err != nil {
1463 return &voltha.ImageDownloads{Items: []*voltha.ImageDownload{imageDownloadFailureResp}}, err
1464 }
1465 return resp, nil
1466}
1467
1468// GetImages returns all images for a specific device entry
1469func (dMgr *Manager) GetImages(ctx context.Context, id *voltha.ID) (*voltha.Images, error) {
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001470 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
1471
Rohan Agrawal31f21802020-06-12 05:38:46 +00001472 logger.Debugw(ctx, "GetImages", log.Fields{"device-id": id.Id})
Kent Hagermancba2f302020-07-28 13:37:36 -04001473 device, err := dMgr.getDeviceReadOnly(ctx, id.Id)
Kent Hagerman45a13e42020-04-13 12:23:50 -04001474 if err != nil {
1475 return nil, err
1476 }
Kent Hagermancba2f302020-07-28 13:37:36 -04001477 return device.Images, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001478}
1479
Rohan Agrawal31f21802020-06-12 05:38:46 +00001480func (dMgr *Manager) NotifyInvalidTransition(ctx context.Context, device *voltha.Device) error {
1481 logger.Errorw(ctx, "NotifyInvalidTransition", log.Fields{
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001482 "device": device.Id,
1483 "curr-admin-state": device.AdminState,
1484 "curr-oper-state": device.OperStatus,
1485 "curr-conn-state": device.ConnectStatus,
Stephane Barbarieef6650d2019-07-18 12:15:09 -04001486 })
khenaidoo0a822f92019-05-08 15:15:57 -04001487 //TODO: notify over kafka?
1488 return nil
1489}
1490
npujar1d86a522019-11-14 17:11:16 +05301491// UpdateDeviceAttribute updates value of particular device attribute
Kent Hagerman2b216042020-04-03 18:28:56 -04001492func (dMgr *Manager) UpdateDeviceAttribute(ctx context.Context, deviceID string, attribute string, value interface{}) {
npujar1d86a522019-11-14 17:11:16 +05301493 if agent, ok := dMgr.deviceAgents.Load(deviceID); ok {
Kent Hagerman2b216042020-04-03 18:28:56 -04001494 agent.(*Agent).updateDeviceAttribute(ctx, attribute, value)
khenaidoob9203542018-09-17 22:56:37 -04001495 }
1496}
1497
npujar1d86a522019-11-14 17:11:16 +05301498// GetParentDeviceID returns parent device id, either from memory or from the dB, if present
Kent Hagerman2b216042020-04-03 18:28:56 -04001499func (dMgr *Manager) GetParentDeviceID(ctx context.Context, deviceID string) string {
Kent Hagermancba2f302020-07-28 13:37:36 -04001500 if device, _ := dMgr.getDeviceReadOnly(ctx, deviceID); device != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +00001501 logger.Infow(ctx, "GetParentDeviceId", log.Fields{"device-id": device.Id, "parentId": device.ParentId})
khenaidoo4c9e5592019-09-09 16:20:41 -04001502 return device.ParentId
khenaidoob9203542018-09-17 22:56:37 -04001503 }
khenaidoo4c9e5592019-09-09 16:20:41 -04001504 return ""
khenaidoob9203542018-09-17 22:56:37 -04001505}
serkant.uluderya334479d2019-04-10 08:26:15 -07001506
Kent Hagerman45a13e42020-04-13 12:23:50 -04001507func (dMgr *Manager) SimulateAlarm(ctx context.Context, simulateReq *voltha.SimulateAlarmRequest) (*common.OperationResp, error) {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001508 logger.Debugw(ctx, "SimulateAlarm", log.Fields{"id": simulateReq.Id, "Indicator": simulateReq.Indicator, "IntfId": simulateReq.IntfId,
Kent Hagerman45a13e42020-04-13 12:23:50 -04001509 "PortTypeName": simulateReq.PortTypeName, "OnuDeviceId": simulateReq.OnuDeviceId, "InverseBitErrorRate": simulateReq.InverseBitErrorRate,
1510 "Drift": simulateReq.Drift, "NewEqd": simulateReq.NewEqd, "OnuSerialNumber": simulateReq.OnuSerialNumber, "Operation": simulateReq.Operation})
1511 agent := dMgr.getDeviceAgent(ctx, simulateReq.Id)
1512 if agent == nil {
1513 return nil, status.Errorf(codes.NotFound, "%s", simulateReq.Id)
serkant.uluderya334479d2019-04-10 08:26:15 -07001514 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001515 if err := agent.simulateAlarm(ctx, simulateReq); err != nil {
1516 return nil, err
1517 }
1518 return &common.OperationResp{Code: common.OperationResp_OPERATION_SUCCESS}, nil
serkant.uluderya334479d2019-04-10 08:26:15 -07001519}
Mahir Gunyelfdee9212019-10-16 16:52:21 -07001520
Kent Hagerman2b216042020-04-03 18:28:56 -04001521func (dMgr *Manager) UpdateDeviceReason(ctx context.Context, deviceID string, reason string) error {
divyadesaicb8b59d2020-08-18 09:55:47 +00001522 logger.Debugw(ctx, "UpdateDeviceReason", log.Fields{"device-id": deviceID, "reason": reason})
npujar467fe752020-01-16 20:17:45 +05301523 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
1524 return agent.updateDeviceReason(ctx, reason)
Mahir Gunyelfdee9212019-10-16 16:52:21 -07001525 }
npujar1d86a522019-11-14 17:11:16 +05301526 return status.Errorf(codes.NotFound, "%s", deviceID)
Mahir Gunyelfdee9212019-10-16 16:52:21 -07001527}
kesavandbc2d1622020-01-21 00:42:01 -05001528
Kent Hagerman45a13e42020-04-13 12:23:50 -04001529func (dMgr *Manager) EnablePort(ctx context.Context, port *voltha.Port) (*empty.Empty, error) {
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001530 log.EnrichSpan(ctx, log.Fields{"device-id": port.DeviceId})
1531
Rohan Agrawal31f21802020-06-12 05:38:46 +00001532 logger.Debugw(ctx, "EnablePort", log.Fields{"device-id": port.DeviceId, "port-no": port.PortNo})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001533 agent := dMgr.getDeviceAgent(ctx, port.DeviceId)
1534 if agent == nil {
1535 return nil, status.Errorf(codes.NotFound, "%s", port.DeviceId)
kesavandbc2d1622020-01-21 00:42:01 -05001536 }
Kent Hagerman2a07b862020-06-19 15:23:07 -04001537 return &empty.Empty{}, agent.enablePort(ctx, port.PortNo)
kesavandbc2d1622020-01-21 00:42:01 -05001538}
1539
Kent Hagerman45a13e42020-04-13 12:23:50 -04001540func (dMgr *Manager) DisablePort(ctx context.Context, port *voltha.Port) (*empty.Empty, error) {
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001541 log.EnrichSpan(ctx, log.Fields{"device-id": port.DeviceId})
1542
Rohan Agrawal31f21802020-06-12 05:38:46 +00001543 logger.Debugw(ctx, "DisablePort", log.Fields{"device-id": port.DeviceId, "port-no": port.PortNo})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001544 agent := dMgr.getDeviceAgent(ctx, port.DeviceId)
1545 if agent == nil {
1546 return nil, status.Errorf(codes.NotFound, "%s", port.DeviceId)
kesavandbc2d1622020-01-21 00:42:01 -05001547 }
Kent Hagerman2a07b862020-06-19 15:23:07 -04001548 return &empty.Empty{}, agent.disablePort(ctx, port.PortNo)
kesavandbc2d1622020-01-21 00:42:01 -05001549}
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001550
Kent Hagerman2b216042020-04-03 18:28:56 -04001551// ChildDeviceLost calls parent adapter to delete child device and all its references
1552func (dMgr *Manager) ChildDeviceLost(ctx context.Context, curr *voltha.Device) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001553 logger.Debugw(ctx, "childDeviceLost", log.Fields{"child-device-id": curr.Id, "parent-device-id": curr.ParentId})
khenaidoo442e7c72020-03-10 16:13:48 -04001554 if parentAgent := dMgr.getDeviceAgent(ctx, curr.ParentId); parentAgent != nil {
khenaidooe132f522020-03-20 15:23:15 -04001555 if err := parentAgent.ChildDeviceLost(ctx, curr); err != nil {
1556 // Just log the message and let the remaining pipeline proceed.
Rohan Agrawal31f21802020-06-12 05:38:46 +00001557 logger.Warnw(ctx, "childDeviceLost", log.Fields{"child-device-id": curr.Id, "parent-device-id": curr.ParentId, "error": err})
khenaidooe132f522020-03-20 15:23:15 -04001558 }
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001559 }
khenaidooe132f522020-03-20 15:23:15 -04001560 // Do not return an error as parent device may also have been deleted. Let the remaining pipeline proceed.
1561 return nil
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001562}
onkarkundargi87285252020-01-27 11:34:52 +05301563
Kent Hagerman45a13e42020-04-13 12:23:50 -04001564func (dMgr *Manager) StartOmciTestAction(ctx context.Context, request *voltha.OmciTestRequest) (*voltha.TestResponse, error) {
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001565 log.EnrichSpan(ctx, log.Fields{"device-id": request.Id})
1566
Rohan Agrawal31f21802020-06-12 05:38:46 +00001567 logger.Debugw(ctx, "StartOmciTestAction", log.Fields{"device-id": request.Id, "uuid": request.Uuid})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001568 agent := dMgr.getDeviceAgent(ctx, request.Id)
1569 if agent == nil {
1570 return nil, status.Errorf(codes.NotFound, "%s", request.Id)
onkarkundargi87285252020-01-27 11:34:52 +05301571 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001572 return agent.startOmciTest(ctx, request)
onkarkundargi87285252020-01-27 11:34:52 +05301573}
Dinesh Belwalkarc1129f12020-02-27 10:41:33 -08001574
1575func (dMgr *Manager) GetExtValue(ctx context.Context, value *voltha.ValueSpecifier) (*voltha.ReturnValues, error) {
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001576 log.EnrichSpan(ctx, log.Fields{"device-id": value.Id})
1577
Girish Kumar3e8ee212020-08-19 17:50:11 +00001578 logger.Debugw(ctx, "getExtValue", log.Fields{"onu-id": value.Id})
Kent Hagermancba2f302020-07-28 13:37:36 -04001579 cDevice, err := dMgr.getDeviceReadOnly(ctx, value.Id)
Dinesh Belwalkarc1129f12020-02-27 10:41:33 -08001580 if err != nil {
1581 return nil, status.Errorf(codes.Aborted, "%s", err.Error())
1582 }
Kent Hagermancba2f302020-07-28 13:37:36 -04001583 pDevice, err := dMgr.getDeviceReadOnly(ctx, cDevice.ParentId)
Dinesh Belwalkarc1129f12020-02-27 10:41:33 -08001584 if err != nil {
1585 return nil, status.Errorf(codes.Aborted, "%s", err.Error())
1586 }
1587 if agent := dMgr.getDeviceAgent(ctx, cDevice.ParentId); agent != nil {
1588 resp, err := agent.getExtValue(ctx, pDevice, cDevice, value)
1589 if err != nil {
1590 return nil, err
1591 }
Girish Kumar3e8ee212020-08-19 17:50:11 +00001592 logger.Debugw(ctx, "getExtValue-result", log.Fields{"result": resp})
Dinesh Belwalkarc1129f12020-02-27 10:41:33 -08001593 return resp, nil
1594 }
1595 return nil, status.Errorf(codes.NotFound, "%s", value.Id)
1596
1597}
dpaul62686312020-06-23 14:17:36 +05301598
1599// SetExtValue set some given configs or value
1600func (dMgr *Manager) SetExtValue(ctx context.Context, value *voltha.ValueSet) (*empty.Empty, error) {
1601 logger.Debugw(ctx, "setExtValue", log.Fields{"onu-id": value.Id})
1602 device, err := dMgr.getDeviceReadOnly(ctx, value.Id)
1603 if err != nil {
1604 return nil, status.Errorf(codes.Aborted, "%s", err.Error())
1605 }
1606 if agent := dMgr.getDeviceAgent(ctx, device.Id); agent != nil {
1607 resp, err := agent.setExtValue(ctx, device, value)
1608 if err != nil {
1609 return nil, err
1610 }
1611 logger.Debugw(ctx, "setExtValue-result", log.Fields{"result": resp})
1612 return resp, nil
1613 }
1614 return nil, status.Errorf(codes.NotFound, "%s", value.Id)
1615
1616}