blob: f92f2e5bc1ee602894518644359794df958a897a [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 {
Mahir Gunyel12cf55f2020-12-16 17:55:03 -0800682 dAgent := dMgr.getDeviceAgent(ctx, rootDeviceID)
683 if dAgent == nil {
684 continue
685 }
686 logger.Debugw(ctx, "checking-adapter-type", log.Fields{"agentType": dAgent.deviceType, "adapterType": adapter.Type})
687 if dAgent.deviceType == adapter.Type {
688 rootDevice, _ := dAgent.getDeviceReadOnly(ctx)
689 if rootDevice == nil {
690 continue
691 }
Rohan Agrawal31f21802020-06-12 05:38:46 +0000692 isDeviceOwnedByService, err := dMgr.adapterProxy.IsDeviceOwnedByService(ctx, rootDeviceID, adapter.Type, adapter.CurrentReplica)
serkant.uluderya7d545aa2020-04-09 13:38:45 -0700693 if err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000694 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 -0700695 continue
696 }
697 if isDeviceOwnedByService {
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530698 if dMgr.isOkToReconcile(ctx, rootDevice) {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000699 logger.Debugw(ctx, "reconciling-root-device", log.Fields{"rootId": rootDevice.Id})
npujar467fe752020-01-16 20:17:45 +0530700 responses = append(responses, dMgr.sendReconcileDeviceRequest(ctx, rootDevice))
khenaidooba6b6c42019-08-02 09:11:56 -0400701 } else {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000702 logger.Debugw(ctx, "not-reconciling-root-device", log.Fields{"rootId": rootDevice.Id, "state": rootDevice.AdminState})
khenaidooba6b6c42019-08-02 09:11:56 -0400703 }
704 } else { // Should we be reconciling the root's children instead?
Kent Hagerman2a07b862020-06-19 15:23:07 -0400705 rootDevicePorts, _ := dMgr.listDevicePorts(ctx, rootDeviceID)
khenaidooba6b6c42019-08-02 09:11:56 -0400706 childManagedByAdapter:
Kent Hagerman2a07b862020-06-19 15:23:07 -0400707 for _, port := range rootDevicePorts {
khenaidooba6b6c42019-08-02 09:11:56 -0400708 for _, peer := range port.Peers {
npujar467fe752020-01-16 20:17:45 +0530709 if childDevice, _ := dMgr.getDeviceFromModel(ctx, peer.DeviceId); childDevice != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000710 isDeviceOwnedByService, err := dMgr.adapterProxy.IsDeviceOwnedByService(ctx, childDevice.Id, adapter.Type, adapter.CurrentReplica)
serkant.uluderya7d545aa2020-04-09 13:38:45 -0700711 if err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000712 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 -0700713 }
714 if isDeviceOwnedByService {
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530715 if dMgr.isOkToReconcile(ctx, childDevice) {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000716 logger.Debugw(ctx, "reconciling-child-device", log.Fields{"child-device-id": childDevice.Id})
npujar467fe752020-01-16 20:17:45 +0530717 responses = append(responses, dMgr.sendReconcileDeviceRequest(ctx, childDevice))
khenaidooba6b6c42019-08-02 09:11:56 -0400718 } else {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000719 logger.Debugw(ctx, "not-reconciling-child-device", log.Fields{"child-device-id": childDevice.Id, "state": childDevice.AdminState})
khenaidooba6b6c42019-08-02 09:11:56 -0400720 }
721 } else {
722 // All child devices under a parent device are typically managed by the same adapter type.
723 // Therefore we only need to check whether the first device we retrieved is managed by that adapter
724 break childManagedByAdapter
725 }
726 }
727 }
728 }
729 }
730 }
731 }
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500732 if len(responses) > 0 {
khenaidooba6b6c42019-08-02 09:11:56 -0400733 // Wait for completion
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500734 if res := utils.WaitForNilOrErrorResponses(dMgr.defaultTimeout, responses...); res != nil {
khenaidooba6b6c42019-08-02 09:11:56 -0400735 return status.Errorf(codes.Aborted, "errors-%s", res)
736 }
737 } else {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000738 logger.Debugw(ctx, "no-managed-device-to-reconcile", log.Fields{"adapterId": adapter.Id})
khenaidooba6b6c42019-08-02 09:11:56 -0400739 }
740 return nil
741}
742
Kent Hagerman2b216042020-04-03 18:28:56 -0400743func (dMgr *Manager) sendReconcileDeviceRequest(ctx context.Context, device *voltha.Device) utils.Response {
khenaidooba6b6c42019-08-02 09:11:56 -0400744 // Send a reconcile request to the adapter. Since this Core may not be managing this device then there is no
745 // 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 +0530746 // 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 -0400747 // the adapter proxy.
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500748 response := utils.NewResponse()
Kent Hagerman2b216042020-04-03 18:28:56 -0400749 ch, err := dMgr.adapterProxy.ReconcileDevice(ctx, device)
khenaidoo442e7c72020-03-10 16:13:48 -0400750 if err != nil {
751 response.Error(err)
752 }
753 // Wait for adapter response in its own routine
754 go func() {
755 resp, ok := <-ch
756 if !ok {
757 response.Error(status.Errorf(codes.Aborted, "channel-closed-device: %s", device.Id))
758 } else if resp.Err != nil {
759 response.Error(resp.Err)
khenaidooba6b6c42019-08-02 09:11:56 -0400760 }
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500761 response.Done()
khenaidoo442e7c72020-03-10 16:13:48 -0400762 }()
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500763 return response
khenaidooba6b6c42019-08-02 09:11:56 -0400764}
765
Kent Hagerman2b216042020-04-03 18:28:56 -0400766func (dMgr *Manager) ReconcileChildDevices(ctx context.Context, parentDeviceID string) error {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400767 if parentDevicePorts, err := dMgr.listDevicePorts(ctx, parentDeviceID); err == nil {
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500768 responses := make([]utils.Response, 0)
Kent Hagerman2a07b862020-06-19 15:23:07 -0400769 for _, port := range parentDevicePorts {
khenaidooba6b6c42019-08-02 09:11:56 -0400770 for _, peer := range port.Peers {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400771 if childDevice, err := dMgr.getDeviceFromModel(ctx, peer.DeviceId); err == nil {
npujar467fe752020-01-16 20:17:45 +0530772 responses = append(responses, dMgr.sendReconcileDeviceRequest(ctx, childDevice))
khenaidooba6b6c42019-08-02 09:11:56 -0400773 }
774 }
775 }
776 // Wait for completion
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500777 if res := utils.WaitForNilOrErrorResponses(dMgr.defaultTimeout, responses...); res != nil {
khenaidooba6b6c42019-08-02 09:11:56 -0400778 return status.Errorf(codes.Aborted, "errors-%s", res)
779 }
780 }
781 return nil
782}
783
Kent Hagerman2b216042020-04-03 18:28:56 -0400784func (dMgr *Manager) UpdateDeviceUsingAdapterData(ctx context.Context, device *voltha.Device) error {
divyadesaicb8b59d2020-08-18 09:55:47 +0000785 logger.Debugw(ctx, "UpdateDeviceUsingAdapterData", log.Fields{"device-id": device.Id, "device": device})
npujar467fe752020-01-16 20:17:45 +0530786 if agent := dMgr.getDeviceAgent(ctx, device.Id); agent != nil {
787 return agent.updateDeviceUsingAdapterData(ctx, device)
khenaidoob9203542018-09-17 22:56:37 -0400788 }
789 return status.Errorf(codes.NotFound, "%s", device.Id)
790}
791
khenaidoo0db4c812020-05-27 15:27:30 -0400792func (dMgr *Manager) addPeerPort(ctx context.Context, deviceID string, port *voltha.Port) error {
793 meAsPeer := &voltha.Port_PeerPort{DeviceId: deviceID, PortNo: port.PortNo}
794 for _, peerPort := range port.Peers {
795 if agent := dMgr.getDeviceAgent(ctx, peerPort.DeviceId); agent != nil {
796 if err := agent.addPeerPort(ctx, meAsPeer); err != nil {
797 return err
798 }
799 }
800 }
801 // Notify the logical device manager to setup a logical port, if needed. If the added port is an NNI or UNI
802 // then a logical port will be added to the logical device and the device route generated. If the port is a
803 // PON port then only the device graph will be generated.
Kent Hagermancba2f302020-07-28 13:37:36 -0400804 device, err := dMgr.getDeviceReadOnly(ctx, deviceID)
khenaidoo0db4c812020-05-27 15:27:30 -0400805 if err != nil {
806 return err
807 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400808 ports, err := dMgr.listDevicePorts(ctx, deviceID)
809 if err != nil {
810 return err
811 }
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000812 if err = dMgr.logicalDeviceMgr.updateLogicalPort(log.WithSpanFromContext(context.Background(), ctx), device, ports, port); err != nil {
khenaidoo0db4c812020-05-27 15:27:30 -0400813 return err
814 }
815 return nil
816}
817
Kent Hagerman2b216042020-04-03 18:28:56 -0400818func (dMgr *Manager) AddPort(ctx context.Context, deviceID string, port *voltha.Port) error {
npujar467fe752020-01-16 20:17:45 +0530819 agent := dMgr.getDeviceAgent(ctx, deviceID)
npujar1d86a522019-11-14 17:11:16 +0530820 if agent != nil {
npujar467fe752020-01-16 20:17:45 +0530821 if err := agent.addPort(ctx, port); err != nil {
khenaidoo92e62c52018-10-03 14:02:54 -0400822 return err
823 }
khenaidoo0db4c812020-05-27 15:27:30 -0400824 // Setup peer ports in its own routine
825 go func() {
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000826 if err := dMgr.addPeerPort(log.WithSpanFromContext(context.Background(), ctx), deviceID, port); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000827 logger.Errorw(ctx, "unable-to-add-peer-port", log.Fields{"error": err, "device-id": deviceID})
khenaidoo92e62c52018-10-03 14:02:54 -0400828 }
khenaidoo0db4c812020-05-27 15:27:30 -0400829 }()
khenaidoo92e62c52018-10-03 14:02:54 -0400830 return nil
khenaidoob9203542018-09-17 22:56:37 -0400831 }
npujar1d86a522019-11-14 17:11:16 +0530832 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoob9203542018-09-17 22:56:37 -0400833}
834
Kent Hagerman2b216042020-04-03 18:28:56 -0400835func (dMgr *Manager) addFlowsAndGroups(ctx context.Context, deviceID string, flows []*ofp.OfpFlowStats, groups []*ofp.OfpGroupEntry, flowMetadata *voltha.FlowMetadata) error {
divyadesaicb8b59d2020-08-18 09:55:47 +0000836 logger.Debugw(ctx, "addFlowsAndGroups", log.Fields{"device-id": deviceID, "groups:": groups, "flowMetadata": flowMetadata})
npujar467fe752020-01-16 20:17:45 +0530837 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
838 return agent.addFlowsAndGroups(ctx, flows, groups, flowMetadata)
khenaidoo0458db62019-06-20 08:50:36 -0400839 }
npujar1d86a522019-11-14 17:11:16 +0530840 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo0458db62019-06-20 08:50:36 -0400841}
842
khenaidoo787224a2020-04-16 18:08:47 -0400843// deleteParentFlows removes flows from the parent device based on specific attributes
844func (dMgr *Manager) deleteParentFlows(ctx context.Context, deviceID string, uniPort uint32, metadata *voltha.FlowMetadata) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000845 logger.Debugw(ctx, "deleteParentFlows", log.Fields{"device-id": deviceID, "uni-port": uniPort, "metadata": metadata})
khenaidoo787224a2020-04-16 18:08:47 -0400846 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400847 if !agent.isRootDevice {
khenaidoo787224a2020-04-16 18:08:47 -0400848 return status.Errorf(codes.FailedPrecondition, "not-a-parent-device-%s", deviceID)
849 }
850 return agent.filterOutFlows(ctx, uniPort, metadata)
851 }
852 return status.Errorf(codes.NotFound, "%s", deviceID)
853}
854
Kent Hagerman2b216042020-04-03 18:28:56 -0400855func (dMgr *Manager) deleteFlowsAndGroups(ctx context.Context, deviceID string, flows []*ofp.OfpFlowStats, groups []*ofp.OfpGroupEntry, flowMetadata *voltha.FlowMetadata) error {
divyadesaicb8b59d2020-08-18 09:55:47 +0000856 logger.Debugw(ctx, "deleteFlowsAndGroups", log.Fields{"device-id": deviceID})
npujar467fe752020-01-16 20:17:45 +0530857 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
858 return agent.deleteFlowsAndGroups(ctx, flows, groups, flowMetadata)
khenaidoo0458db62019-06-20 08:50:36 -0400859 }
npujar1d86a522019-11-14 17:11:16 +0530860 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo0458db62019-06-20 08:50:36 -0400861}
862
Kent Hagerman2b216042020-04-03 18:28:56 -0400863func (dMgr *Manager) updateFlowsAndGroups(ctx context.Context, deviceID string, flows []*ofp.OfpFlowStats, groups []*ofp.OfpGroupEntry, flowMetadata *voltha.FlowMetadata) error {
divyadesaicb8b59d2020-08-18 09:55:47 +0000864 logger.Debugw(ctx, "updateFlowsAndGroups", log.Fields{"device-id": deviceID})
npujar467fe752020-01-16 20:17:45 +0530865 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
866 return agent.updateFlowsAndGroups(ctx, flows, groups, flowMetadata)
khenaidoo19d7b632018-10-30 10:49:50 -0400867 }
npujar1d86a522019-11-14 17:11:16 +0530868 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo19d7b632018-10-30 10:49:50 -0400869}
870
Kent Hagerman45a13e42020-04-13 12:23:50 -0400871// UpdateDevicePmConfigs updates the PM configs. This is executed when the northbound gRPC API is invoked, typically
khenaidoob3127472019-07-24 21:04:55 -0400872// following a user action
Kent Hagerman45a13e42020-04-13 12:23:50 -0400873func (dMgr *Manager) UpdateDevicePmConfigs(ctx context.Context, configs *voltha.PmConfigs) (*empty.Empty, error) {
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000874 log.EnrichSpan(ctx, log.Fields{"device-id": configs.Id})
875
Kent Hagerman45a13e42020-04-13 12:23:50 -0400876 if configs.Id == "" {
877 return nil, status.Error(codes.FailedPrecondition, "invalid-device-Id")
khenaidoob3127472019-07-24 21:04:55 -0400878 }
Kent Hagerman45a13e42020-04-13 12:23:50 -0400879 agent := dMgr.getDeviceAgent(ctx, configs.Id)
880 if agent == nil {
881 return nil, status.Errorf(codes.NotFound, "%s", configs.Id)
882 }
883 return &empty.Empty{}, agent.updatePmConfigs(ctx, configs)
khenaidoob3127472019-07-24 21:04:55 -0400884}
885
Kent Hagerman2b216042020-04-03 18:28:56 -0400886// InitPmConfigs initialize the pm configs as defined by the adapter.
887func (dMgr *Manager) InitPmConfigs(ctx context.Context, deviceID string, pmConfigs *voltha.PmConfigs) error {
khenaidoob3127472019-07-24 21:04:55 -0400888 if pmConfigs.Id == "" {
889 return status.Errorf(codes.FailedPrecondition, "invalid-device-Id")
890 }
npujar467fe752020-01-16 20:17:45 +0530891 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
892 return agent.initPmConfigs(ctx, pmConfigs)
khenaidoob9203542018-09-17 22:56:37 -0400893 }
npujar1d86a522019-11-14 17:11:16 +0530894 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoob9203542018-09-17 22:56:37 -0400895}
896
Kent Hagerman45a13e42020-04-13 12:23:50 -0400897// ListDevicePmConfigs returns pm configs of device
898func (dMgr *Manager) ListDevicePmConfigs(ctx context.Context, id *voltha.ID) (*voltha.PmConfigs, error) {
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000899 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
900
Kent Hagerman45a13e42020-04-13 12:23:50 -0400901 agent := dMgr.getDeviceAgent(ctx, id.Id)
902 if agent == nil {
903 return nil, status.Errorf(codes.NotFound, "%s", id.Id)
khenaidoob3127472019-07-24 21:04:55 -0400904 }
Kent Hagerman45a13e42020-04-13 12:23:50 -0400905 return agent.listPmConfigs(ctx)
khenaidoob3127472019-07-24 21:04:55 -0400906}
907
Kent Hagerman2b216042020-04-03 18:28:56 -0400908func (dMgr *Manager) getSwitchCapability(ctx context.Context, deviceID string) (*ic.SwitchCapability, error) {
divyadesaicb8b59d2020-08-18 09:55:47 +0000909 logger.Debugw(ctx, "getSwitchCapability", log.Fields{"device-id": deviceID})
npujar467fe752020-01-16 20:17:45 +0530910 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
khenaidoob9203542018-09-17 22:56:37 -0400911 return agent.getSwitchCapability(ctx)
912 }
npujar1d86a522019-11-14 17:11:16 +0530913 return nil, status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoob9203542018-09-17 22:56:37 -0400914}
915
Kent Hagerman2b216042020-04-03 18:28:56 -0400916func (dMgr *Manager) GetPorts(ctx context.Context, deviceID string, portType voltha.Port_PortType) (*voltha.Ports, error) {
divyadesaicb8b59d2020-08-18 09:55:47 +0000917 logger.Debugw(ctx, "GetPorts", log.Fields{"device-id": deviceID, "portType": portType})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400918 agent := dMgr.getDeviceAgent(ctx, deviceID)
919 if agent == nil {
920 return nil, status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoob9203542018-09-17 22:56:37 -0400921 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400922 return agent.getPorts(ctx, portType), nil
khenaidoob9203542018-09-17 22:56:37 -0400923}
924
Kent Hagerman2b216042020-04-03 18:28:56 -0400925func (dMgr *Manager) UpdateDeviceStatus(ctx context.Context, deviceID string, operStatus voltha.OperStatus_Types, connStatus voltha.ConnectStatus_Types) error {
divyadesaicb8b59d2020-08-18 09:55:47 +0000926 logger.Debugw(ctx, "UpdateDeviceStatus", log.Fields{"device-id": deviceID, "operStatus": operStatus, "connStatus": connStatus})
npujar467fe752020-01-16 20:17:45 +0530927 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
928 return agent.updateDeviceStatus(ctx, operStatus, connStatus)
khenaidoo92e62c52018-10-03 14:02:54 -0400929 }
npujar1d86a522019-11-14 17:11:16 +0530930 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo92e62c52018-10-03 14:02:54 -0400931}
932
Kent Hagerman2b216042020-04-03 18:28:56 -0400933func (dMgr *Manager) UpdateChildrenStatus(ctx context.Context, deviceID string, operStatus voltha.OperStatus_Types, connStatus voltha.ConnectStatus_Types) error {
divyadesaicb8b59d2020-08-18 09:55:47 +0000934 logger.Debugw(ctx, "UpdateChildrenStatus", log.Fields{"parent-device-id": deviceID, "operStatus": operStatus, "connStatus": connStatus})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400935 parentDevicePorts, err := dMgr.listDevicePorts(ctx, deviceID)
936 if err != nil {
khenaidoo4d4802d2018-10-04 21:59:49 -0400937 return status.Errorf(codes.Aborted, "%s", err.Error())
938 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400939 for childDeviceID := range dMgr.getAllChildDeviceIds(ctx, parentDevicePorts) {
npujar467fe752020-01-16 20:17:45 +0530940 if agent := dMgr.getDeviceAgent(ctx, childDeviceID); agent != nil {
941 if err = agent.updateDeviceStatus(ctx, operStatus, connStatus); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530942 return status.Errorf(codes.Aborted, "childDevice:%s, error:%s", childDeviceID, err.Error())
khenaidoo4d4802d2018-10-04 21:59:49 -0400943 }
944 }
945 }
946 return nil
947}
948
Kent Hagerman2b216042020-04-03 18:28:56 -0400949func (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 +0000950 logger.Debugw(ctx, "UpdatePortState", log.Fields{"device-id": deviceID, "portType": portType, "portNo": portNo, "operStatus": operStatus})
npujar467fe752020-01-16 20:17:45 +0530951 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
952 if err := agent.updatePortState(ctx, portType, portNo, operStatus); err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000953 logger.Errorw(ctx, "updating-port-state-failed", log.Fields{"device-id": deviceID, "portNo": portNo, "error": err})
khenaidoo171b98e2019-10-31 11:48:15 -0400954 return err
955 }
956 // Notify the logical device manager to change the port state
Mahir Gunyel18fa0c92020-03-06 13:34:04 -0800957 // Do this for NNI and UNIs only. PON ports are not known by logical device
958 if portType == voltha.Port_ETHERNET_NNI || portType == voltha.Port_ETHERNET_UNI {
959 go func() {
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000960 err := dMgr.logicalDeviceMgr.updatePortState(log.WithSpanFromContext(context.Background(), ctx), deviceID, portNo, operStatus)
Mahir Gunyel18fa0c92020-03-06 13:34:04 -0800961 if err != nil {
962 // While we want to handle (catch) and log when
963 // an update to a port was not able to be
964 // propagated to the logical port, we can report
965 // it as a warning and not an error because it
966 // doesn't stop or modify processing.
967 // TODO: VOL-2707
Rohan Agrawal31f21802020-06-12 05:38:46 +0000968 logger.Warnw(ctx, "unable-to-update-logical-port-state", log.Fields{"error": err})
Mahir Gunyel18fa0c92020-03-06 13:34:04 -0800969 }
970 }()
971 }
khenaidoo442e7c72020-03-10 16:13:48 -0400972 return nil
khenaidoob9203542018-09-17 22:56:37 -0400973 }
npujar1d86a522019-11-14 17:11:16 +0530974 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoob9203542018-09-17 22:56:37 -0400975}
976
Kent Hagerman2b216042020-04-03 18:28:56 -0400977func (dMgr *Manager) DeleteAllPorts(ctx context.Context, deviceID string) error {
divyadesaicb8b59d2020-08-18 09:55:47 +0000978 logger.Debugw(ctx, "DeleteAllPorts", log.Fields{"device-id": deviceID})
npujar467fe752020-01-16 20:17:45 +0530979 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
980 if err := agent.deleteAllPorts(ctx); err != nil {
khenaidoo0a822f92019-05-08 15:15:57 -0400981 return err
982 }
983 // Notify the logical device manager to remove all logical ports, if needed.
Kent Hagerman2b216042020-04-03 18:28:56 -0400984 // At this stage the device itself may gave been deleted already at a DeleteAllPorts
khenaidoo0a822f92019-05-08 15:15:57 -0400985 // typically is part of a device deletion phase.
Kent Hagermancba2f302020-07-28 13:37:36 -0400986 if device, err := dMgr.getDeviceReadOnly(ctx, deviceID); err == nil {
npujar1d86a522019-11-14 17:11:16 +0530987 go func() {
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000988 if err := dMgr.logicalDeviceMgr.deleteAllLogicalPorts(log.WithSpanFromContext(context.Background(), ctx), device); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000989 logger.Errorw(ctx, "unable-to-delete-logical-ports", log.Fields{"error": err})
npujar1d86a522019-11-14 17:11:16 +0530990 }
991 }()
khenaidoo0a822f92019-05-08 15:15:57 -0400992 } else {
divyadesaicb8b59d2020-08-18 09:55:47 +0000993 logger.Warnw(ctx, "failed-to-retrieve-device", log.Fields{"device-id": deviceID})
khenaidoo0a822f92019-05-08 15:15:57 -0400994 return err
995 }
996 return nil
997 }
npujar1d86a522019-11-14 17:11:16 +0530998 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo0a822f92019-05-08 15:15:57 -0400999}
1000
Kent Hagerman2b216042020-04-03 18:28:56 -04001001//UpdatePortsState updates all ports on the device
Kent Hagerman2a07b862020-06-19 15:23:07 -04001002func (dMgr *Manager) UpdatePortsState(ctx context.Context, deviceID string, portTypeFilter uint32, state voltha.OperStatus_Types) error {
divyadesaicb8b59d2020-08-18 09:55:47 +00001003 logger.Debugw(ctx, "UpdatePortsState", log.Fields{"device-id": deviceID})
Kent Hagerman2a07b862020-06-19 15:23:07 -04001004 agent := dMgr.getDeviceAgent(ctx, deviceID)
1005 if agent == nil {
1006 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo3ab34882019-05-02 21:33:30 -04001007 }
Kent Hagerman2a07b862020-06-19 15:23:07 -04001008 if state != voltha.OperStatus_ACTIVE && state != voltha.OperStatus_UNKNOWN {
1009 return status.Error(codes.Unimplemented, "state-change-not-implemented")
1010 }
1011 if err := agent.updatePortsOperState(ctx, portTypeFilter, state); err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +00001012 logger.Warnw(ctx, "updatePortsOperState-failed", log.Fields{"device-id": deviceID, "error": err})
Kent Hagerman2a07b862020-06-19 15:23:07 -04001013 return err
1014 }
1015 return nil
khenaidoo3ab34882019-05-02 21:33:30 -04001016}
1017
Kent Hagerman2b216042020-04-03 18:28:56 -04001018func (dMgr *Manager) ChildDeviceDetected(ctx context.Context, parentDeviceID string, parentPortNo int64, deviceType string,
npujar1d86a522019-11-14 17:11:16 +05301019 channelID int64, vendorID string, serialNumber string, onuID int64) (*voltha.Device, error) {
divyadesaicb8b59d2020-08-18 09:55:47 +00001020 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 -07001021
npujar1d86a522019-11-14 17:11:16 +05301022 if deviceType == "" && vendorID != "" {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001023 logger.Debug(ctx, "device-type-is-nil-fetching-device-type")
Kent Hagerman45a13e42020-04-13 12:23:50 -04001024 deviceTypes, err := dMgr.adapterMgr.ListDeviceTypes(ctx, nil)
1025 if err != nil {
1026 return nil, err
1027 }
Kent Hagerman4f355f52020-03-30 16:01:33 -04001028 OLoop:
Kent Hagerman45a13e42020-04-13 12:23:50 -04001029 for _, dType := range deviceTypes.Items {
Kent Hagerman4f355f52020-03-30 16:01:33 -04001030 for _, v := range dType.VendorIds {
1031 if v == vendorID {
1032 deviceType = dType.Adapter
1033 break OLoop
Chaitrashree G S4b3fada2019-07-28 23:55:25 -07001034 }
1035 }
1036 }
1037 }
1038 //if no match found for the vendorid,report adapter with the custom error message
1039 if deviceType == "" {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001040 logger.Errorw(ctx, "failed-to-fetch-adapter-name ", log.Fields{"vendorId": vendorID})
npujar1d86a522019-11-14 17:11:16 +05301041 return nil, status.Errorf(codes.NotFound, "%s", vendorID)
Chaitrashree G S4b3fada2019-07-28 23:55:25 -07001042 }
khenaidoob9203542018-09-17 22:56:37 -04001043
1044 // Create the ONU device
1045 childDevice := &voltha.Device{}
khenaidoob9203542018-09-17 22:56:37 -04001046 childDevice.Type = deviceType
npujar1d86a522019-11-14 17:11:16 +05301047 childDevice.ParentId = parentDeviceID
khenaidoob9203542018-09-17 22:56:37 -04001048 childDevice.ParentPortNo = uint32(parentPortNo)
npujar1d86a522019-11-14 17:11:16 +05301049 childDevice.VendorId = vendorID
Matt Jeanneret4e241952019-02-28 11:16:04 -05001050 childDevice.SerialNumber = serialNumber
khenaidoob9203542018-09-17 22:56:37 -04001051 childDevice.Root = false
khenaidoo6fdf0ba2018-11-02 14:38:33 -04001052
khenaidoo442e7c72020-03-10 16:13:48 -04001053 // Get parent device type
1054 pAgent := dMgr.getDeviceAgent(ctx, parentDeviceID)
1055 if pAgent == nil {
npujar1d86a522019-11-14 17:11:16 +05301056 return nil, status.Errorf(codes.NotFound, "%s", parentDeviceID)
khenaidoo6fdf0ba2018-11-02 14:38:33 -04001057 }
khenaidoo442e7c72020-03-10 16:13:48 -04001058 if pAgent.deviceType == "" {
1059 return nil, status.Errorf(codes.FailedPrecondition, "device Type not set %s", parentDeviceID)
1060 }
khenaidoo6fdf0ba2018-11-02 14:38:33 -04001061
npujar467fe752020-01-16 20:17:45 +05301062 if device, err := dMgr.GetChildDevice(ctx, parentDeviceID, serialNumber, onuID, parentPortNo); err == nil {
divyadesaicb8b59d2020-08-18 09:55:47 +00001063 logger.Warnw(ctx, "child-device-exists", log.Fields{"parent-device-id": parentDeviceID, "serialNumber": serialNumber})
Mahir Gunyel6deaa242019-06-27 04:53:33 -07001064 return device, status.Errorf(codes.AlreadyExists, "%s", serialNumber)
Matt Jeanneret4e241952019-02-28 11:16:04 -05001065 }
1066
khenaidoo442e7c72020-03-10 16:13:48 -04001067 childDevice.ProxyAddress = &voltha.Device_ProxyAddress{DeviceId: parentDeviceID, DeviceType: pAgent.deviceType, ChannelId: uint32(channelID), OnuId: uint32(onuID)}
khenaidoob9203542018-09-17 22:56:37 -04001068
1069 // Create and start a device agent for that device
Mahir Gunyel03de0d32020-06-03 01:36:59 -07001070 agent := newAgent(dMgr.adapterProxy, childDevice, dMgr, dMgr.dbPath, dMgr.dProxy, dMgr.defaultTimeout)
Mahir Gunyel23bd8c72020-09-21 23:20:43 -07001071 insertedChildDevice, err := agent.start(ctx, childDevice)
Scott Baker80678602019-11-14 16:57:36 -08001072 if err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001073 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 -08001074 return nil, err
1075 }
khenaidoo442e7c72020-03-10 16:13:48 -04001076 dMgr.addDeviceAgentToMap(agent)
khenaidoob9203542018-09-17 22:56:37 -04001077
1078 // Activate the child device
npujar467fe752020-01-16 20:17:45 +05301079 if agent = dMgr.getDeviceAgent(ctx, agent.deviceID); agent != nil {
npujar1d86a522019-11-14 17:11:16 +05301080 go func() {
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001081 err := agent.enableDevice(log.WithSpanFromContext(context.Background(), ctx))
npujar1d86a522019-11-14 17:11:16 +05301082 if err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001083 logger.Errorw(ctx, "unable-to-enable-device", log.Fields{"error": err})
npujar1d86a522019-11-14 17:11:16 +05301084 }
1085 }()
khenaidoob9203542018-09-17 22:56:37 -04001086 }
1087
Mahir Gunyel23bd8c72020-09-21 23:20:43 -07001088 return insertedChildDevice, nil
khenaidoob9203542018-09-17 22:56:37 -04001089}
1090
Kent Hagerman2b216042020-04-03 18:28:56 -04001091func (dMgr *Manager) packetOut(ctx context.Context, deviceID string, outPort uint32, packet *ofp.OfpPacketOut) error {
divyadesaicb8b59d2020-08-18 09:55:47 +00001092 logger.Debugw(ctx, "packetOut", log.Fields{"device-id": deviceID, "outPort": outPort})
npujar467fe752020-01-16 20:17:45 +05301093 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
1094 return agent.packetOut(ctx, outPort, packet)
khenaidoofdbad6e2018-11-06 22:26:38 -05001095 }
npujar1d86a522019-11-14 17:11:16 +05301096 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoofdbad6e2018-11-06 22:26:38 -05001097}
1098
npujar1d86a522019-11-14 17:11:16 +05301099// PacketIn receives packet from adapter
Kent Hagerman2b216042020-04-03 18:28:56 -04001100func (dMgr *Manager) PacketIn(ctx context.Context, deviceID string, port uint32, transactionID string, packet []byte) error {
divyadesaicb8b59d2020-08-18 09:55:47 +00001101 logger.Debugw(ctx, "PacketIn", log.Fields{"device-id": deviceID, "port": port})
khenaidoofdbad6e2018-11-06 22:26:38 -05001102 // Get the logical device Id based on the deviceId
1103 var device *voltha.Device
1104 var err error
Kent Hagermancba2f302020-07-28 13:37:36 -04001105 if device, err = dMgr.getDeviceReadOnly(ctx, deviceID); err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +00001106 logger.Errorw(ctx, "device-not-found", log.Fields{"device-id": deviceID})
khenaidoofdbad6e2018-11-06 22:26:38 -05001107 return err
1108 }
khenaidoo43c82122018-11-22 18:38:28 -05001109 if !device.Root {
divyadesaicb8b59d2020-08-18 09:55:47 +00001110 logger.Errorw(ctx, "device-not-root", log.Fields{"device-id": deviceID})
npujar1d86a522019-11-14 17:11:16 +05301111 return status.Errorf(codes.FailedPrecondition, "%s", deviceID)
khenaidoofdbad6e2018-11-06 22:26:38 -05001112 }
1113
npujar467fe752020-01-16 20:17:45 +05301114 if err := dMgr.logicalDeviceMgr.packetIn(ctx, device.ParentId, port, transactionID, packet); err != nil {
khenaidoofdbad6e2018-11-06 22:26:38 -05001115 return err
1116 }
1117 return nil
1118}
1119
Kent Hagerman2b216042020-04-03 18:28:56 -04001120func (dMgr *Manager) setParentID(ctx context.Context, device *voltha.Device, parentID string) error {
divyadesaicb8b59d2020-08-18 09:55:47 +00001121 logger.Debugw(ctx, "setParentId", log.Fields{"device-id": device.Id, "parentId": parentID})
npujar467fe752020-01-16 20:17:45 +05301122 if agent := dMgr.getDeviceAgent(ctx, device.Id); agent != nil {
1123 return agent.setParentID(ctx, device, parentID)
khenaidooad06fd72019-10-28 12:26:05 -04001124 }
1125 return status.Errorf(codes.NotFound, "%s", device.Id)
1126}
1127
npujar1d86a522019-11-14 17:11:16 +05301128// CreateLogicalDevice creates logical device in core
Kent Hagerman2b216042020-04-03 18:28:56 -04001129func (dMgr *Manager) CreateLogicalDevice(ctx context.Context, cDevice *voltha.Device) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001130 logger.Info(ctx, "CreateLogicalDevice")
khenaidoo59ef7be2019-06-21 12:40:28 -04001131 // Verify whether the logical device has already been created
1132 if cDevice.ParentId != "" {
divyadesaicb8b59d2020-08-18 09:55:47 +00001133 logger.Debugw(ctx, "Parent device already exist.", log.Fields{"device-id": cDevice.Id, "logical-device-id": cDevice.Id})
khenaidoo59ef7be2019-06-21 12:40:28 -04001134 return nil
1135 }
khenaidoob9203542018-09-17 22:56:37 -04001136 var err error
npujar467fe752020-01-16 20:17:45 +05301137 if _, err = dMgr.logicalDeviceMgr.createLogicalDevice(ctx, cDevice); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001138 logger.Warnw(ctx, "createlogical-device-error", log.Fields{"device": cDevice})
khenaidoob9203542018-09-17 22:56:37 -04001139 return err
1140 }
khenaidoob9203542018-09-17 22:56:37 -04001141 return nil
1142}
1143
npujar1d86a522019-11-14 17:11:16 +05301144// DeleteLogicalDevice deletes logical device from core
Kent Hagerman2b216042020-04-03 18:28:56 -04001145func (dMgr *Manager) DeleteLogicalDevice(ctx context.Context, cDevice *voltha.Device) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001146 logger.Info(ctx, "DeleteLogicalDevice")
khenaidoo92e62c52018-10-03 14:02:54 -04001147 var err error
npujar467fe752020-01-16 20:17:45 +05301148 if err = dMgr.logicalDeviceMgr.deleteLogicalDevice(ctx, cDevice); err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +00001149 logger.Warnw(ctx, "deleteLogical-device-error", log.Fields{"device-id": cDevice.Id})
khenaidoo92e62c52018-10-03 14:02:54 -04001150 return err
1151 }
1152 // Remove the logical device Id from the parent device
npujar1d86a522019-11-14 17:11:16 +05301153 logicalID := ""
npujar467fe752020-01-16 20:17:45 +05301154 dMgr.UpdateDeviceAttribute(ctx, cDevice.Id, "ParentId", logicalID)
khenaidoo92e62c52018-10-03 14:02:54 -04001155 return nil
1156}
1157
npujar1d86a522019-11-14 17:11:16 +05301158// DeleteLogicalPorts removes the logical ports associated with that deviceId
Kent Hagerman2b216042020-04-03 18:28:56 -04001159func (dMgr *Manager) DeleteLogicalPorts(ctx context.Context, cDevice *voltha.Device) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001160 logger.Debugw(ctx, "delete-all-logical-ports", log.Fields{"device-id": cDevice.Id})
khenaidoo442e7c72020-03-10 16:13:48 -04001161 if err := dMgr.logicalDeviceMgr.deleteLogicalPorts(ctx, cDevice.Id); err != nil {
khenaidooe132f522020-03-20 15:23:15 -04001162 // 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 +00001163 logger.Warnw(ctx, "deleteLogical-ports-error", log.Fields{"device-id": cDevice.Id, "error": err})
khenaidoo0a822f92019-05-08 15:15:57 -04001164 }
1165 return nil
1166}
1167
Kent Hagerman2b216042020-04-03 18:28:56 -04001168func (dMgr *Manager) getParentDevice(ctx context.Context, childDevice *voltha.Device) *voltha.Device {
khenaidoo92e62c52018-10-03 14:02:54 -04001169 // Sanity check
1170 if childDevice.Root {
1171 // childDevice is the parent device
1172 return childDevice
1173 }
Kent Hagermancba2f302020-07-28 13:37:36 -04001174 parentDevice, _ := dMgr.getDeviceReadOnly(ctx, childDevice.ParentId)
khenaidoo92e62c52018-10-03 14:02:54 -04001175 return parentDevice
1176}
1177
Kent Hagerman2b216042020-04-03 18:28:56 -04001178//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 -04001179//cannot manage the child devices. This will trigger the Core to disable all the child devices.
Kent Hagerman2b216042020-04-03 18:28:56 -04001180func (dMgr *Manager) ChildDevicesLost(ctx context.Context, parentDeviceID string) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001181 logger.Debug(ctx, "ChildDevicesLost")
Kent Hagermancba2f302020-07-28 13:37:36 -04001182 parentDevice, err := dMgr.getDeviceReadOnly(ctx, parentDeviceID)
Kent Hagerman2a07b862020-06-19 15:23:07 -04001183 if err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +00001184 logger.Warnw(ctx, "failed-getting-device", log.Fields{"parent-device-id": parentDeviceID, "error": err})
khenaidoo0a822f92019-05-08 15:15:57 -04001185 return err
1186 }
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001187 return dMgr.DisableAllChildDevices(ctx, parentDevice)
khenaidoo0a822f92019-05-08 15:15:57 -04001188}
1189
Kent Hagerman2b216042020-04-03 18:28:56 -04001190//ChildDevicesDetected is invoked by an adapter when child devices are found, typically after after a
khenaidoo0a822f92019-05-08 15:15:57 -04001191// disable/enable sequence. This will trigger the Core to Enable all the child devices of that parent.
Kent Hagerman2b216042020-04-03 18:28:56 -04001192func (dMgr *Manager) ChildDevicesDetected(ctx context.Context, parentDeviceID string) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001193 logger.Debug(ctx, "ChildDevicesDetected")
Kent Hagerman2a07b862020-06-19 15:23:07 -04001194 parentDevicePorts, err := dMgr.listDevicePorts(ctx, parentDeviceID)
1195 if err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +00001196 logger.Warnw(ctx, "failed-getting-device", log.Fields{"device-id": parentDeviceID, "error": err})
khenaidoo0a822f92019-05-08 15:15:57 -04001197 return err
1198 }
Kent Hagerman2a07b862020-06-19 15:23:07 -04001199 childDeviceIds := dMgr.getAllChildDeviceIds(ctx, parentDevicePorts)
khenaidoo0a822f92019-05-08 15:15:57 -04001200 if len(childDeviceIds) == 0 {
divyadesaicb8b59d2020-08-18 09:55:47 +00001201 logger.Debugw(ctx, "no-child-device", log.Fields{"parent-device-id": parentDeviceID})
khenaidoo0a822f92019-05-08 15:15:57 -04001202 }
khenaidoo59ef7be2019-06-21 12:40:28 -04001203 allChildEnableRequestSent := true
Kent Hagerman2a07b862020-06-19 15:23:07 -04001204 for childDeviceID := range childDeviceIds {
npujar467fe752020-01-16 20:17:45 +05301205 if agent := dMgr.getDeviceAgent(ctx, childDeviceID); agent != nil {
khenaidoo59ef7be2019-06-21 12:40:28 -04001206 // Run the children re-registration in its own routine
Kent Hagerman2a07b862020-06-19 15:23:07 -04001207 go func(ctx context.Context) {
1208 err = agent.enableDevice(ctx)
npujar1d86a522019-11-14 17:11:16 +05301209 if err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001210 logger.Errorw(ctx, "unable-to-enable-device", log.Fields{"error": err})
npujar1d86a522019-11-14 17:11:16 +05301211 }
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001212 }(log.WithSpanFromContext(context.Background(), ctx))
khenaidoo59ef7be2019-06-21 12:40:28 -04001213 } else {
npujar1d86a522019-11-14 17:11:16 +05301214 err = status.Errorf(codes.Unavailable, "no agent for child device %s", childDeviceID)
divyadesaicb8b59d2020-08-18 09:55:47 +00001215 logger.Errorw(ctx, "no-child-device-agent", log.Fields{"parent-device-id": parentDeviceID, "childId": childDeviceID})
khenaidoo59ef7be2019-06-21 12:40:28 -04001216 allChildEnableRequestSent = false
khenaidoo0a822f92019-05-08 15:15:57 -04001217 }
1218 }
khenaidoo59ef7be2019-06-21 12:40:28 -04001219 if !allChildEnableRequestSent {
khenaidoo0a822f92019-05-08 15:15:57 -04001220 return err
1221 }
1222 return nil
1223}
1224
khenaidoo4d4802d2018-10-04 21:59:49 -04001225/*
1226All the functions below are callback functions where they are invoked with the latest and previous data. We can
1227therefore use the data as is without trying to get the latest from the model.
1228*/
1229
khenaidoo0a822f92019-05-08 15:15:57 -04001230//DisableAllChildDevices is invoked as a callback when the parent device is disabled
Kent Hagerman2b216042020-04-03 18:28:56 -04001231func (dMgr *Manager) DisableAllChildDevices(ctx context.Context, parentCurrDevice *voltha.Device) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001232 logger.Debug(ctx, "DisableAllChildDevices")
Kent Hagerman2a07b862020-06-19 15:23:07 -04001233 ports, _ := dMgr.listDevicePorts(ctx, parentCurrDevice.Id)
1234 for childDeviceID := range dMgr.getAllChildDeviceIds(ctx, ports) {
npujar467fe752020-01-16 20:17:45 +05301235 if agent := dMgr.getDeviceAgent(ctx, childDeviceID); agent != nil {
Kent Hagerman2a07b862020-06-19 15:23:07 -04001236 if err := agent.disableDevice(ctx); err != nil {
khenaidooe132f522020-03-20 15:23:15 -04001237 // Just log the error - this error happens only if the child device was already in deleted state.
divyadesaicb8b59d2020-08-18 09:55:47 +00001238 logger.Errorw(ctx, "failure-disable-device", log.Fields{"device-id": childDeviceID, "error": err.Error()})
khenaidoo92e62c52018-10-03 14:02:54 -04001239 }
1240 }
1241 }
1242 return nil
1243}
1244
khenaidoo0a822f92019-05-08 15:15:57 -04001245//DeleteAllChildDevices is invoked as a callback when the parent device is deleted
Kent Hagerman2b216042020-04-03 18:28:56 -04001246func (dMgr *Manager) DeleteAllChildDevices(ctx context.Context, parentCurrDevice *voltha.Device) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001247 logger.Debug(ctx, "DeleteAllChildDevices")
Himani Chawla2ba1c9c2020-10-07 13:19:03 +05301248 force := false
1249 // Get the parent device Transient state, if its FORCE_DELETED(go for force delete for child devices)
1250 // So in cases when this handler is getting called other than DELETE operation, no force option would be used.
1251 agent := dMgr.getDeviceAgent(ctx, parentCurrDevice.Id)
1252 if agent == nil {
1253 return status.Errorf(codes.NotFound, "%s", parentCurrDevice.Id)
1254 }
1255
1256 force = agent.getTransientState() == voltha.DeviceTransientState_FORCE_DELETING
1257
Kent Hagerman2a07b862020-06-19 15:23:07 -04001258 ports, _ := dMgr.listDevicePorts(ctx, parentCurrDevice.Id)
1259 for childDeviceID := range dMgr.getAllChildDeviceIds(ctx, ports) {
npujar467fe752020-01-16 20:17:45 +05301260 if agent := dMgr.getDeviceAgent(ctx, childDeviceID); agent != nil {
Himani Chawla2ba1c9c2020-10-07 13:19:03 +05301261 if force {
1262 if err := agent.deleteDeviceForce(ctx); err != nil {
1263 logger.Warnw(ctx, "failure-delete-device-force", log.Fields{"device-id": childDeviceID,
1264 "error": err.Error()})
1265 }
1266 } else {
1267 if err := agent.deleteDevice(ctx); err != nil {
1268 logger.Warnw(ctx, "failure-delete-device", log.Fields{"device-id": childDeviceID,
1269 "error": err.Error()})
1270 }
khenaidoo4d4802d2018-10-04 21:59:49 -04001271 }
khenaidoo49085352020-01-13 19:15:43 -05001272 // No further action is required here. The deleteDevice will change the device state where the resulting
1273 // callback will take care of cleaning the child device agent.
khenaidoo4d4802d2018-10-04 21:59:49 -04001274 }
1275 }
khenaidoo4d4802d2018-10-04 21:59:49 -04001276 return nil
1277}
1278
Girish Gowdra408cd962020-03-11 14:31:31 -07001279//DeleteAllLogicalPorts is invoked as a callback when the parent device's connection status moves to UNREACHABLE
Kent Hagerman2b216042020-04-03 18:28:56 -04001280func (dMgr *Manager) DeleteAllLogicalPorts(ctx context.Context, parentDevice *voltha.Device) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001281 logger.Debugw(ctx, "delete-all-logical-ports", log.Fields{"parent-device-id": parentDevice.Id})
Girish Gowdra408cd962020-03-11 14:31:31 -07001282 if err := dMgr.logicalDeviceMgr.deleteAllLogicalPorts(ctx, parentDevice); err != nil {
khenaidooe132f522020-03-20 15:23:15 -04001283 // Just log error as logical device may already have been deleted
Rohan Agrawal31f21802020-06-12 05:38:46 +00001284 logger.Warnw(ctx, "delete-all-logical-ports-fail", log.Fields{"parent-device-id": parentDevice.Id, "error": err})
Girish Gowdra408cd962020-03-11 14:31:31 -07001285 }
1286 return nil
1287}
1288
1289//DeleteAllDeviceFlows is invoked as a callback when the parent device's connection status moves to UNREACHABLE
Kent Hagerman2b216042020-04-03 18:28:56 -04001290func (dMgr *Manager) DeleteAllDeviceFlows(ctx context.Context, parentDevice *voltha.Device) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001291 logger.Debugw(ctx, "delete-all-device-flows", log.Fields{"parent-device-id": parentDevice.Id})
Girish Gowdra408cd962020-03-11 14:31:31 -07001292 if agent := dMgr.getDeviceAgent(ctx, parentDevice.Id); agent != nil {
1293 if err := agent.deleteAllFlows(ctx); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001294 logger.Errorw(ctx, "error-deleting-all-device-flows", log.Fields{"parent-device-id": parentDevice.Id})
Girish Gowdra408cd962020-03-11 14:31:31 -07001295 return err
1296 }
1297 return nil
1298 }
1299 return status.Errorf(codes.NotFound, "%s", parentDevice.Id)
1300}
1301
khenaidoo4d4802d2018-10-04 21:59:49 -04001302//getAllChildDeviceIds is a helper method to get all the child device IDs from the device passed as parameter
Kent Hagerman2a07b862020-06-19 15:23:07 -04001303func (dMgr *Manager) getAllChildDeviceIds(ctx context.Context, parentDevicePorts map[uint32]*voltha.Port) map[string]struct{} {
1304 logger.Debug(ctx, "getAllChildDeviceIds")
1305 childDeviceIds := make(map[string]struct{}, len(parentDevicePorts))
1306 for _, port := range parentDevicePorts {
1307 for _, peer := range port.Peers {
1308 childDeviceIds[peer.DeviceId] = struct{}{}
khenaidoo92e62c52018-10-03 14:02:54 -04001309 }
1310 }
Kent Hagerman2a07b862020-06-19 15:23:07 -04001311 logger.Debugw(ctx, "returning-getAllChildDeviceIds", log.Fields{"childDeviceIds": childDeviceIds})
1312 return childDeviceIds
khenaidoo92e62c52018-10-03 14:02:54 -04001313}
1314
Kent Hagerman2b216042020-04-03 18:28:56 -04001315//GetAllChildDevices is a helper method to get all the child device IDs from the device passed as parameter
1316func (dMgr *Manager) GetAllChildDevices(ctx context.Context, parentDeviceID string) (*voltha.Devices, error) {
divyadesaicb8b59d2020-08-18 09:55:47 +00001317 logger.Debugw(ctx, "GetAllChildDevices", log.Fields{"parent-device-id": parentDeviceID})
Kent Hagerman2a07b862020-06-19 15:23:07 -04001318 if parentDevicePorts, err := dMgr.listDevicePorts(ctx, parentDeviceID); err == nil {
khenaidoo297cd252019-02-07 22:10:23 -05001319 childDevices := make([]*voltha.Device, 0)
Kent Hagerman2a07b862020-06-19 15:23:07 -04001320 for deviceID := range dMgr.getAllChildDeviceIds(ctx, parentDevicePorts) {
Kent Hagermancba2f302020-07-28 13:37:36 -04001321 if d, e := dMgr.getDeviceReadOnly(ctx, deviceID); e == nil && d != nil {
Kent Hagerman2a07b862020-06-19 15:23:07 -04001322 childDevices = append(childDevices, d)
khenaidoo297cd252019-02-07 22:10:23 -05001323 }
1324 }
1325 return &voltha.Devices{Items: childDevices}, nil
1326 }
npujar1d86a522019-11-14 17:11:16 +05301327 return nil, status.Errorf(codes.NotFound, "%s", parentDeviceID)
khenaidoo297cd252019-02-07 22:10:23 -05001328}
1329
npujar1d86a522019-11-14 17:11:16 +05301330// SetupUNILogicalPorts creates UNI ports on the logical device that represents a child UNI interface
Kent Hagerman2b216042020-04-03 18:28:56 -04001331func (dMgr *Manager) SetupUNILogicalPorts(ctx context.Context, cDevice *voltha.Device) error {
Kent Hagermanf6db9f12020-07-22 17:16:19 -04001332 logger.Info(ctx, "SetupUNILogicalPorts")
Kent Hagerman2a07b862020-06-19 15:23:07 -04001333 cDevicePorts, err := dMgr.listDevicePorts(ctx, cDevice.Id)
1334 if err != nil {
1335 return err
1336 }
1337 if err := dMgr.logicalDeviceMgr.setupUNILogicalPorts(ctx, cDevice, cDevicePorts); err != nil {
Kent Hagermanf6db9f12020-07-22 17:16:19 -04001338 logger.Warnw(ctx, "setupUNILogicalPorts-error", log.Fields{"device": cDevice, "err": err})
khenaidoob9203542018-09-17 22:56:37 -04001339 return err
1340 }
1341 return nil
1342}
1343
Kent Hagerman45a13e42020-04-13 12:23:50 -04001344// convenience to avoid redefining
1345var operationFailureResp = &common.OperationResp{Code: voltha.OperationResp_OPERATION_FAILURE}
1346
1347// DownloadImage execute an image download request
1348func (dMgr *Manager) DownloadImage(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001349 log.EnrichSpan(ctx, log.Fields{"device-id": img.Id})
1350
Rohan Agrawal31f21802020-06-12 05:38:46 +00001351 logger.Debugw(ctx, "DownloadImage", log.Fields{"device-id": img.Id, "imageName": img.Name})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001352 agent := dMgr.getDeviceAgent(ctx, img.Id)
1353 if agent == nil {
1354 return operationFailureResp, status.Errorf(codes.NotFound, "%s", img.Id)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001355 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001356 resp, err := agent.downloadImage(ctx, img)
1357 if err != nil {
1358 return operationFailureResp, err
1359 }
1360 return resp, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001361}
1362
Kent Hagerman45a13e42020-04-13 12:23:50 -04001363// CancelImageDownload cancels image download request
1364func (dMgr *Manager) CancelImageDownload(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001365 log.EnrichSpan(ctx, log.Fields{"device-id": img.Id})
1366
Rohan Agrawal31f21802020-06-12 05:38:46 +00001367 logger.Debugw(ctx, "CancelImageDownload", log.Fields{"device-id": img.Id, "imageName": img.Name})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001368 agent := dMgr.getDeviceAgent(ctx, img.Id)
1369 if agent == nil {
1370 return operationFailureResp, status.Errorf(codes.NotFound, "%s", img.Id)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001371 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001372 resp, err := agent.cancelImageDownload(ctx, img)
1373 if err != nil {
1374 return operationFailureResp, err
1375 }
1376 return resp, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001377}
1378
Kent Hagerman45a13e42020-04-13 12:23:50 -04001379// ActivateImageUpdate activates image update request
1380func (dMgr *Manager) ActivateImageUpdate(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001381 log.EnrichSpan(ctx, log.Fields{"device-id": img.Id})
1382
Rohan Agrawal31f21802020-06-12 05:38:46 +00001383 logger.Debugw(ctx, "ActivateImageUpdate", log.Fields{"device-id": img.Id, "imageName": img.Name})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001384 agent := dMgr.getDeviceAgent(ctx, img.Id)
1385 if agent == nil {
1386 return operationFailureResp, status.Errorf(codes.NotFound, "%s", img.Id)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001387 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001388 resp, err := agent.activateImage(ctx, img)
1389 if err != nil {
1390 return operationFailureResp, err
1391 }
1392 return resp, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001393}
1394
Kent Hagerman45a13e42020-04-13 12:23:50 -04001395// RevertImageUpdate reverts image update
1396func (dMgr *Manager) RevertImageUpdate(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001397 log.EnrichSpan(ctx, log.Fields{"device-id": img.Id})
1398
Rohan Agrawal31f21802020-06-12 05:38:46 +00001399 logger.Debugw(ctx, "RevertImageUpdate", log.Fields{"device-id": img.Id, "imageName": img.Name})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001400 agent := dMgr.getDeviceAgent(ctx, img.Id)
1401 if agent == nil {
1402 return operationFailureResp, status.Errorf(codes.NotFound, "%s", img.Id)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001403 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001404 resp, err := agent.revertImage(ctx, img)
1405 if err != nil {
1406 return operationFailureResp, err
1407 }
1408 return resp, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001409}
1410
Kent Hagerman45a13e42020-04-13 12:23:50 -04001411// convenience to avoid redefining
1412var imageDownloadFailureResp = &voltha.ImageDownload{DownloadState: voltha.ImageDownload_DOWNLOAD_UNKNOWN}
1413
1414// GetImageDownloadStatus returns status of image download
1415func (dMgr *Manager) GetImageDownloadStatus(ctx context.Context, img *voltha.ImageDownload) (*voltha.ImageDownload, error) {
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001416 log.EnrichSpan(ctx, log.Fields{"device-id": img.Id})
1417
Rohan Agrawal31f21802020-06-12 05:38:46 +00001418 logger.Debugw(ctx, "GetImageDownloadStatus", log.Fields{"device-id": img.Id, "imageName": img.Name})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001419 agent := dMgr.getDeviceAgent(ctx, img.Id)
1420 if agent == nil {
1421 return imageDownloadFailureResp, status.Errorf(codes.NotFound, "%s", img.Id)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001422 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001423 resp, err := agent.getImageDownloadStatus(ctx, img)
1424 if err != nil {
1425 return imageDownloadFailureResp, err
1426 }
1427 return resp, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001428}
1429
Kent Hagerman2b216042020-04-03 18:28:56 -04001430func (dMgr *Manager) UpdateImageDownload(ctx context.Context, deviceID string, img *voltha.ImageDownload) error {
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001431 log.EnrichSpan(ctx, log.Fields{"device-id": img.Id})
1432
Rohan Agrawal31f21802020-06-12 05:38:46 +00001433 logger.Debugw(ctx, "UpdateImageDownload", log.Fields{"device-id": img.Id, "imageName": img.Name})
npujar467fe752020-01-16 20:17:45 +05301434 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
1435 if err := agent.updateImageDownload(ctx, img); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001436 logger.Debugw(ctx, "UpdateImageDownload-failed", log.Fields{"err": err, "imageName": img.Name})
khenaidoof5a5bfa2019-01-23 22:20:29 -05001437 return err
1438 }
1439 } else {
1440 return status.Errorf(codes.NotFound, "%s", img.Id)
1441 }
1442 return nil
1443}
1444
Kent Hagerman45a13e42020-04-13 12:23:50 -04001445// GetImageDownload returns image download
Kent Hagerman2b216042020-04-03 18:28:56 -04001446func (dMgr *Manager) GetImageDownload(ctx context.Context, img *voltha.ImageDownload) (*voltha.ImageDownload, error) {
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001447 log.EnrichSpan(ctx, log.Fields{"device-id": img.Id})
1448
Rohan Agrawal31f21802020-06-12 05:38:46 +00001449 logger.Debugw(ctx, "GetImageDownload", log.Fields{"device-id": img.Id, "imageName": img.Name})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001450 agent := dMgr.getDeviceAgent(ctx, img.Id)
1451 if agent == nil {
1452 return imageDownloadFailureResp, status.Errorf(codes.NotFound, "%s", img.Id)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001453 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001454 resp, err := agent.getImageDownload(ctx, img)
1455 if err != nil {
1456 return imageDownloadFailureResp, err
1457 }
1458 return resp, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001459}
1460
Kent Hagerman45a13e42020-04-13 12:23:50 -04001461// ListImageDownloads returns image downloads
1462func (dMgr *Manager) ListImageDownloads(ctx context.Context, id *voltha.ID) (*voltha.ImageDownloads, error) {
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001463 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
1464
Rohan Agrawal31f21802020-06-12 05:38:46 +00001465 logger.Debugw(ctx, "ListImageDownloads", log.Fields{"device-id": id.Id})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001466 agent := dMgr.getDeviceAgent(ctx, id.Id)
1467 if agent == nil {
1468 return &voltha.ImageDownloads{Items: []*voltha.ImageDownload{imageDownloadFailureResp}}, status.Errorf(codes.NotFound, "%s", id.Id)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001469 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001470 resp, err := agent.listImageDownloads(ctx, id.Id)
1471 if err != nil {
1472 return &voltha.ImageDownloads{Items: []*voltha.ImageDownload{imageDownloadFailureResp}}, err
1473 }
1474 return resp, nil
1475}
1476
1477// GetImages returns all images for a specific device entry
1478func (dMgr *Manager) GetImages(ctx context.Context, id *voltha.ID) (*voltha.Images, error) {
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001479 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
1480
Rohan Agrawal31f21802020-06-12 05:38:46 +00001481 logger.Debugw(ctx, "GetImages", log.Fields{"device-id": id.Id})
Kent Hagermancba2f302020-07-28 13:37:36 -04001482 device, err := dMgr.getDeviceReadOnly(ctx, id.Id)
Kent Hagerman45a13e42020-04-13 12:23:50 -04001483 if err != nil {
1484 return nil, err
1485 }
Kent Hagermancba2f302020-07-28 13:37:36 -04001486 return device.Images, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001487}
1488
Rohan Agrawal31f21802020-06-12 05:38:46 +00001489func (dMgr *Manager) NotifyInvalidTransition(ctx context.Context, device *voltha.Device) error {
1490 logger.Errorw(ctx, "NotifyInvalidTransition", log.Fields{
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001491 "device": device.Id,
1492 "curr-admin-state": device.AdminState,
1493 "curr-oper-state": device.OperStatus,
1494 "curr-conn-state": device.ConnectStatus,
Stephane Barbarieef6650d2019-07-18 12:15:09 -04001495 })
khenaidoo0a822f92019-05-08 15:15:57 -04001496 //TODO: notify over kafka?
1497 return nil
1498}
1499
npujar1d86a522019-11-14 17:11:16 +05301500// UpdateDeviceAttribute updates value of particular device attribute
Kent Hagerman2b216042020-04-03 18:28:56 -04001501func (dMgr *Manager) UpdateDeviceAttribute(ctx context.Context, deviceID string, attribute string, value interface{}) {
npujar1d86a522019-11-14 17:11:16 +05301502 if agent, ok := dMgr.deviceAgents.Load(deviceID); ok {
Kent Hagerman2b216042020-04-03 18:28:56 -04001503 agent.(*Agent).updateDeviceAttribute(ctx, attribute, value)
khenaidoob9203542018-09-17 22:56:37 -04001504 }
1505}
1506
npujar1d86a522019-11-14 17:11:16 +05301507// GetParentDeviceID returns parent device id, either from memory or from the dB, if present
Kent Hagerman2b216042020-04-03 18:28:56 -04001508func (dMgr *Manager) GetParentDeviceID(ctx context.Context, deviceID string) string {
Kent Hagermancba2f302020-07-28 13:37:36 -04001509 if device, _ := dMgr.getDeviceReadOnly(ctx, deviceID); device != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +00001510 logger.Infow(ctx, "GetParentDeviceId", log.Fields{"device-id": device.Id, "parentId": device.ParentId})
khenaidoo4c9e5592019-09-09 16:20:41 -04001511 return device.ParentId
khenaidoob9203542018-09-17 22:56:37 -04001512 }
khenaidoo4c9e5592019-09-09 16:20:41 -04001513 return ""
khenaidoob9203542018-09-17 22:56:37 -04001514}
serkant.uluderya334479d2019-04-10 08:26:15 -07001515
Kent Hagerman45a13e42020-04-13 12:23:50 -04001516func (dMgr *Manager) SimulateAlarm(ctx context.Context, simulateReq *voltha.SimulateAlarmRequest) (*common.OperationResp, error) {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001517 logger.Debugw(ctx, "SimulateAlarm", log.Fields{"id": simulateReq.Id, "Indicator": simulateReq.Indicator, "IntfId": simulateReq.IntfId,
Kent Hagerman45a13e42020-04-13 12:23:50 -04001518 "PortTypeName": simulateReq.PortTypeName, "OnuDeviceId": simulateReq.OnuDeviceId, "InverseBitErrorRate": simulateReq.InverseBitErrorRate,
1519 "Drift": simulateReq.Drift, "NewEqd": simulateReq.NewEqd, "OnuSerialNumber": simulateReq.OnuSerialNumber, "Operation": simulateReq.Operation})
1520 agent := dMgr.getDeviceAgent(ctx, simulateReq.Id)
1521 if agent == nil {
1522 return nil, status.Errorf(codes.NotFound, "%s", simulateReq.Id)
serkant.uluderya334479d2019-04-10 08:26:15 -07001523 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001524 if err := agent.simulateAlarm(ctx, simulateReq); err != nil {
1525 return nil, err
1526 }
1527 return &common.OperationResp{Code: common.OperationResp_OPERATION_SUCCESS}, nil
serkant.uluderya334479d2019-04-10 08:26:15 -07001528}
Mahir Gunyelfdee9212019-10-16 16:52:21 -07001529
Kent Hagerman2b216042020-04-03 18:28:56 -04001530func (dMgr *Manager) UpdateDeviceReason(ctx context.Context, deviceID string, reason string) error {
divyadesaicb8b59d2020-08-18 09:55:47 +00001531 logger.Debugw(ctx, "UpdateDeviceReason", log.Fields{"device-id": deviceID, "reason": reason})
npujar467fe752020-01-16 20:17:45 +05301532 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
1533 return agent.updateDeviceReason(ctx, reason)
Mahir Gunyelfdee9212019-10-16 16:52:21 -07001534 }
npujar1d86a522019-11-14 17:11:16 +05301535 return status.Errorf(codes.NotFound, "%s", deviceID)
Mahir Gunyelfdee9212019-10-16 16:52:21 -07001536}
kesavandbc2d1622020-01-21 00:42:01 -05001537
Kent Hagerman45a13e42020-04-13 12:23:50 -04001538func (dMgr *Manager) EnablePort(ctx context.Context, port *voltha.Port) (*empty.Empty, error) {
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001539 log.EnrichSpan(ctx, log.Fields{"device-id": port.DeviceId})
1540
Rohan Agrawal31f21802020-06-12 05:38:46 +00001541 logger.Debugw(ctx, "EnablePort", log.Fields{"device-id": port.DeviceId, "port-no": port.PortNo})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001542 agent := dMgr.getDeviceAgent(ctx, port.DeviceId)
1543 if agent == nil {
1544 return nil, status.Errorf(codes.NotFound, "%s", port.DeviceId)
kesavandbc2d1622020-01-21 00:42:01 -05001545 }
Kent Hagerman2a07b862020-06-19 15:23:07 -04001546 return &empty.Empty{}, agent.enablePort(ctx, port.PortNo)
kesavandbc2d1622020-01-21 00:42:01 -05001547}
1548
Kent Hagerman45a13e42020-04-13 12:23:50 -04001549func (dMgr *Manager) DisablePort(ctx context.Context, port *voltha.Port) (*empty.Empty, error) {
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001550 log.EnrichSpan(ctx, log.Fields{"device-id": port.DeviceId})
1551
Rohan Agrawal31f21802020-06-12 05:38:46 +00001552 logger.Debugw(ctx, "DisablePort", log.Fields{"device-id": port.DeviceId, "port-no": port.PortNo})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001553 agent := dMgr.getDeviceAgent(ctx, port.DeviceId)
1554 if agent == nil {
1555 return nil, status.Errorf(codes.NotFound, "%s", port.DeviceId)
kesavandbc2d1622020-01-21 00:42:01 -05001556 }
Kent Hagerman2a07b862020-06-19 15:23:07 -04001557 return &empty.Empty{}, agent.disablePort(ctx, port.PortNo)
kesavandbc2d1622020-01-21 00:42:01 -05001558}
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001559
Kent Hagerman2b216042020-04-03 18:28:56 -04001560// ChildDeviceLost calls parent adapter to delete child device and all its references
1561func (dMgr *Manager) ChildDeviceLost(ctx context.Context, curr *voltha.Device) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001562 logger.Debugw(ctx, "childDeviceLost", log.Fields{"child-device-id": curr.Id, "parent-device-id": curr.ParentId})
khenaidoo442e7c72020-03-10 16:13:48 -04001563 if parentAgent := dMgr.getDeviceAgent(ctx, curr.ParentId); parentAgent != nil {
khenaidooe132f522020-03-20 15:23:15 -04001564 if err := parentAgent.ChildDeviceLost(ctx, curr); err != nil {
1565 // Just log the message and let the remaining pipeline proceed.
Rohan Agrawal31f21802020-06-12 05:38:46 +00001566 logger.Warnw(ctx, "childDeviceLost", log.Fields{"child-device-id": curr.Id, "parent-device-id": curr.ParentId, "error": err})
khenaidooe132f522020-03-20 15:23:15 -04001567 }
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001568 }
khenaidooe132f522020-03-20 15:23:15 -04001569 // Do not return an error as parent device may also have been deleted. Let the remaining pipeline proceed.
1570 return nil
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001571}
onkarkundargi87285252020-01-27 11:34:52 +05301572
Kent Hagerman45a13e42020-04-13 12:23:50 -04001573func (dMgr *Manager) StartOmciTestAction(ctx context.Context, request *voltha.OmciTestRequest) (*voltha.TestResponse, error) {
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001574 log.EnrichSpan(ctx, log.Fields{"device-id": request.Id})
1575
Rohan Agrawal31f21802020-06-12 05:38:46 +00001576 logger.Debugw(ctx, "StartOmciTestAction", log.Fields{"device-id": request.Id, "uuid": request.Uuid})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001577 agent := dMgr.getDeviceAgent(ctx, request.Id)
1578 if agent == nil {
1579 return nil, status.Errorf(codes.NotFound, "%s", request.Id)
onkarkundargi87285252020-01-27 11:34:52 +05301580 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001581 return agent.startOmciTest(ctx, request)
onkarkundargi87285252020-01-27 11:34:52 +05301582}
Dinesh Belwalkarc1129f12020-02-27 10:41:33 -08001583
1584func (dMgr *Manager) GetExtValue(ctx context.Context, value *voltha.ValueSpecifier) (*voltha.ReturnValues, error) {
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001585 log.EnrichSpan(ctx, log.Fields{"device-id": value.Id})
1586
Girish Kumar3e8ee212020-08-19 17:50:11 +00001587 logger.Debugw(ctx, "getExtValue", log.Fields{"onu-id": value.Id})
Kent Hagermancba2f302020-07-28 13:37:36 -04001588 cDevice, err := dMgr.getDeviceReadOnly(ctx, value.Id)
Dinesh Belwalkarc1129f12020-02-27 10:41:33 -08001589 if err != nil {
1590 return nil, status.Errorf(codes.Aborted, "%s", err.Error())
1591 }
Kent Hagermancba2f302020-07-28 13:37:36 -04001592 pDevice, err := dMgr.getDeviceReadOnly(ctx, cDevice.ParentId)
Dinesh Belwalkarc1129f12020-02-27 10:41:33 -08001593 if err != nil {
1594 return nil, status.Errorf(codes.Aborted, "%s", err.Error())
1595 }
1596 if agent := dMgr.getDeviceAgent(ctx, cDevice.ParentId); agent != nil {
1597 resp, err := agent.getExtValue(ctx, pDevice, cDevice, value)
1598 if err != nil {
1599 return nil, err
1600 }
Girish Kumar3e8ee212020-08-19 17:50:11 +00001601 logger.Debugw(ctx, "getExtValue-result", log.Fields{"result": resp})
Dinesh Belwalkarc1129f12020-02-27 10:41:33 -08001602 return resp, nil
1603 }
1604 return nil, status.Errorf(codes.NotFound, "%s", value.Id)
1605
1606}
dpaul62686312020-06-23 14:17:36 +05301607
1608// SetExtValue set some given configs or value
1609func (dMgr *Manager) SetExtValue(ctx context.Context, value *voltha.ValueSet) (*empty.Empty, error) {
1610 logger.Debugw(ctx, "setExtValue", log.Fields{"onu-id": value.Id})
1611 device, err := dMgr.getDeviceReadOnly(ctx, value.Id)
1612 if err != nil {
1613 return nil, status.Errorf(codes.Aborted, "%s", err.Error())
1614 }
1615 if agent := dMgr.getDeviceAgent(ctx, device.Id); agent != nil {
1616 resp, err := agent.setExtValue(ctx, device, value)
1617 if err != nil {
1618 return nil, err
1619 }
1620 logger.Debugw(ctx, "setExtValue-result", log.Fields{"result": resp})
1621 return resp, nil
1622 }
1623 return nil, status.Errorf(codes.NotFound, "%s", value.Id)
1624
1625}