blob: 9f7e656a757b04cb8964c43b8c18bd4b59a06ce7 [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"
khenaidood948f772021-08-11 17:49:24 -040021 "fmt"
David Bainbridged1afd662020-03-26 18:27:41 -070022 "sync"
23 "time"
24
khenaidood948f772021-08-11 17:49:24 -040025 "github.com/opencord/voltha-go/rw_core/config"
26 "github.com/opencord/voltha-lib-go/v7/pkg/probe"
27 "github.com/opencord/voltha-protos/v5/go/core"
28
sbarbari17d7e222019-11-05 10:02:29 -050029 "github.com/opencord/voltha-go/db/model"
Kent Hagerman2b216042020-04-03 18:28:56 -040030 "github.com/opencord/voltha-go/rw_core/core/adapter"
Kent Hagermanf5a67352020-04-30 15:15:26 -040031 "github.com/opencord/voltha-go/rw_core/core/device/event"
Kent Hagerman6031aad2020-07-29 16:36:33 -040032 "github.com/opencord/voltha-go/rw_core/core/device/state"
khenaidoo3d3b8c22019-05-22 18:10:39 -040033 "github.com/opencord/voltha-go/rw_core/utils"
khenaidood948f772021-08-11 17:49:24 -040034 "github.com/opencord/voltha-lib-go/v7/pkg/events"
35 "github.com/opencord/voltha-lib-go/v7/pkg/log"
khenaidoo9beaaf12021-10-19 17:32:01 -040036 ca "github.com/opencord/voltha-protos/v5/go/core_adapter"
khenaidood948f772021-08-11 17:49:24 -040037 ofp "github.com/opencord/voltha-protos/v5/go/openflow_13"
38 "github.com/opencord/voltha-protos/v5/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 {
Himani Chawlab4c25912020-11-12 17:16:38 +053045 deviceAgents sync.Map
46 rootDevices map[string]bool
47 lockRootDeviceMap sync.RWMutex
Mahir Gunyelb0343bf2021-05-11 14:14:26 -070048 *event.Agent
Kent Hagerman2b216042020-04-03 18:28:56 -040049 adapterMgr *adapter.Manager
50 logicalDeviceMgr *LogicalManager
Kent Hagerman6031aad2020-07-29 16:36:33 -040051 stateTransitions *state.TransitionMap
Mahir Gunyel03de0d32020-06-03 01:36:59 -070052 dbPath *model.Path
Kent Hagermanf5a67352020-04-30 15:15:26 -040053 dProxy *model.Proxy
npujar1d86a522019-11-14 17:11:16 +053054 coreInstanceID string
khenaidood948f772021-08-11 17:49:24 -040055 internalTimeout time.Duration
56 rpcTimeout time.Duration
khenaidoo4c9e5592019-09-09 16:20:41 -040057 devicesLoadingLock sync.RWMutex
58 deviceLoadingInProgress map[string][]chan int
Maninder0aabf0c2021-03-17 14:55:14 +053059 config *config.RWCoreFlags
khenaidoob9203542018-09-17 22:56:37 -040060}
61
Mahir Gunyel03de0d32020-06-03 01:36:59 -070062//NewManagers creates the Manager and the Logical Manager.
khenaidood948f772021-08-11 17:49:24 -040063func NewManagers(dbPath *model.Path, adapterMgr *adapter.Manager, cf *config.RWCoreFlags, coreInstanceID string, eventProxy *events.EventProxy) (*Manager, *LogicalManager) {
Kent Hagerman2b216042020-04-03 18:28:56 -040064 deviceMgr := &Manager{
Kent Hagerman2b216042020-04-03 18:28:56 -040065 rootDevices: make(map[string]bool),
Kent Hagerman2b216042020-04-03 18:28:56 -040066 coreInstanceID: coreInstanceID,
Mahir Gunyel03de0d32020-06-03 01:36:59 -070067 dbPath: dbPath,
68 dProxy: dbPath.Proxy("devices"),
Kent Hagerman2b216042020-04-03 18:28:56 -040069 adapterMgr: adapterMgr,
khenaidood948f772021-08-11 17:49:24 -040070 internalTimeout: cf.InternalTimeout,
71 rpcTimeout: cf.RPCTimeout,
Maninder0aabf0c2021-03-17 14:55:14 +053072 Agent: event.NewAgent(eventProxy, coreInstanceID, cf.VolthaStackID),
Kent Hagerman2b216042020-04-03 18:28:56 -040073 deviceLoadingInProgress: make(map[string][]chan int),
Maninder0aabf0c2021-03-17 14:55:14 +053074 config: cf,
Kent Hagerman2b216042020-04-03 18:28:56 -040075 }
Kent Hagerman6031aad2020-07-29 16:36:33 -040076 deviceMgr.stateTransitions = state.NewTransitionMap(deviceMgr)
Kent Hagerman2f0d0552020-04-23 17:28:52 -040077
Kent Hagerman2b216042020-04-03 18:28:56 -040078 logicalDeviceMgr := &LogicalManager{
Maninder0aabf0c2021-03-17 14:55:14 +053079 Manager: event.NewManager(eventProxy, coreInstanceID, cf.VolthaStackID),
Kent Hagerman2b216042020-04-03 18:28:56 -040080 deviceMgr: deviceMgr,
Mahir Gunyel03de0d32020-06-03 01:36:59 -070081 dbPath: dbPath,
82 ldProxy: dbPath.Proxy("logical_devices"),
khenaidood948f772021-08-11 17:49:24 -040083 internalTimeout: cf.InternalTimeout,
Kent Hagerman2b216042020-04-03 18:28:56 -040084 logicalDeviceLoadingInProgress: make(map[string][]chan int),
85 }
86 deviceMgr.logicalDeviceMgr = logicalDeviceMgr
Matteo Scandolod525ae32020-04-02 17:27:29 -070087
khenaidood948f772021-08-11 17:49:24 -040088 adapterMgr.SetAdapterRestartedCallback(deviceMgr.adapterRestartedHandler)
Matteo Scandolod525ae32020-04-02 17:27:29 -070089
Kent Hagerman2b216042020-04-03 18:28:56 -040090 return deviceMgr, logicalDeviceMgr
khenaidoob9203542018-09-17 22:56:37 -040091}
92
khenaidood948f772021-08-11 17:49:24 -040093func (dMgr *Manager) Start(ctx context.Context, serviceName string) error {
khenaidoo7585a962021-06-10 16:15:38 -040094 logger.Info(ctx, "starting-device-manager")
khenaidood948f772021-08-11 17:49:24 -040095 probe.UpdateStatusFromContext(ctx, serviceName, probe.ServiceStatusPreparing)
khenaidoo7585a962021-06-10 16:15:38 -040096
97 // Load all the devices from the dB
98 var devices []*voltha.Device
99 if err := dMgr.dProxy.List(ctx, &devices); err != nil {
100 // Any error from the dB means if we proceed we may end up with corrupted data
khenaidood948f772021-08-11 17:49:24 -0400101 logger.Errorw(ctx, "failed-to-list-devices-from-KV", log.Fields{"error": err, "service-name": serviceName})
102 return err
103 }
104
105 defer probe.UpdateStatusFromContext(ctx, serviceName, probe.ServiceStatusRunning)
106
107 if len(devices) == 0 {
108 logger.Info(ctx, "no-device-to-load")
109 return nil
khenaidoo7585a962021-06-10 16:15:38 -0400110 }
111
112 for _, device := range devices {
113 // Create an agent for each device
khenaidood948f772021-08-11 17:49:24 -0400114 agent := newAgent(device, dMgr, dMgr.dbPath, dMgr.dProxy, dMgr.internalTimeout, dMgr.rpcTimeout)
khenaidoo7585a962021-06-10 16:15:38 -0400115 if _, err := agent.start(ctx, true, device); err != nil {
116 logger.Warnw(ctx, "failure-starting-agent", log.Fields{"device-id": device.Id})
117 } else {
118 dMgr.addDeviceAgentToMap(agent)
119 }
120 }
121
122 // TODO: Need to trigger a reconcile at this point
123
khenaidoo7585a962021-06-10 16:15:38 -0400124 logger.Info(ctx, "device-manager-started")
khenaidood948f772021-08-11 17:49:24 -0400125
126 return nil
khenaidoo7585a962021-06-10 16:15:38 -0400127}
128
Kent Hagerman2b216042020-04-03 18:28:56 -0400129func (dMgr *Manager) addDeviceAgentToMap(agent *Agent) {
npujar1d86a522019-11-14 17:11:16 +0530130 if _, exist := dMgr.deviceAgents.Load(agent.deviceID); !exist {
131 dMgr.deviceAgents.Store(agent.deviceID, agent)
khenaidoob9203542018-09-17 22:56:37 -0400132 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400133 dMgr.lockRootDeviceMap.Lock()
134 defer dMgr.lockRootDeviceMap.Unlock()
Kent Hagerman2a07b862020-06-19 15:23:07 -0400135 dMgr.rootDevices[agent.deviceID] = agent.isRootDevice
khenaidoo2c6a0992019-04-29 13:46:56 -0400136
khenaidoob9203542018-09-17 22:56:37 -0400137}
138
Kent Hagerman2b216042020-04-03 18:28:56 -0400139func (dMgr *Manager) deleteDeviceAgentFromMap(agent *Agent) {
npujar1d86a522019-11-14 17:11:16 +0530140 dMgr.deviceAgents.Delete(agent.deviceID)
khenaidoo2c6a0992019-04-29 13:46:56 -0400141 dMgr.lockRootDeviceMap.Lock()
142 defer dMgr.lockRootDeviceMap.Unlock()
npujar1d86a522019-11-14 17:11:16 +0530143 delete(dMgr.rootDevices, agent.deviceID)
khenaidoo4d4802d2018-10-04 21:59:49 -0400144}
145
khenaidoo297cd252019-02-07 22:10:23 -0500146// 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 -0400147func (dMgr *Manager) getDeviceAgent(ctx context.Context, deviceID string) *Agent {
npujar1d86a522019-11-14 17:11:16 +0530148 agent, ok := dMgr.deviceAgents.Load(deviceID)
149 if ok {
Kent Hagerman2b216042020-04-03 18:28:56 -0400150 return agent.(*Agent)
khenaidoob9203542018-09-17 22:56:37 -0400151 }
khenaidoo442e7c72020-03-10 16:13:48 -0400152 // Try to load into memory - loading will also create the device agent and set the device ownership
npujar467fe752020-01-16 20:17:45 +0530153 err := dMgr.load(ctx, deviceID)
npujar1d86a522019-11-14 17:11:16 +0530154 if err == nil {
155 agent, ok = dMgr.deviceAgents.Load(deviceID)
156 if !ok {
157 return nil
158 }
Kent Hagerman2b216042020-04-03 18:28:56 -0400159 return agent.(*Agent)
npujar1d86a522019-11-14 17:11:16 +0530160 }
161 //TODO: Change the return params to return an error as well
divyadesaicb8b59d2020-08-18 09:55:47 +0000162 logger.Errorw(ctx, "loading-device-failed", log.Fields{"device-id": deviceID, "error": err})
khenaidoob9203542018-09-17 22:56:37 -0400163 return nil
164}
165
khenaidoo297cd252019-02-07 22:10:23 -0500166// listDeviceIdsFromMap returns the list of device IDs that are in memory
Kent Hagerman2b216042020-04-03 18:28:56 -0400167func (dMgr *Manager) listDeviceIdsFromMap() *voltha.IDs {
khenaidoo7ccedd52018-12-14 16:48:54 -0500168 result := &voltha.IDs{Items: make([]*voltha.ID, 0)}
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400169
170 dMgr.deviceAgents.Range(func(key, value interface{}) bool {
171 result.Items = append(result.Items, &voltha.ID{Id: key.(string)})
172 return true
173 })
174
khenaidoo7ccedd52018-12-14 16:48:54 -0500175 return result
176}
177
khenaidoo6d62c002019-05-15 21:57:03 -0400178// stopManagingDevice stops the management of the device as well as any of its reference device and logical device.
179// This function is called only in the Core that does not own this device. In the Core that owns this device then a
180// deletion deletion also includes removal of any reference of this device.
Kent Hagerman2b216042020-04-03 18:28:56 -0400181func (dMgr *Manager) stopManagingDevice(ctx context.Context, id string) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530182 logger.Infow(ctx, "stop-managing-device", log.Fields{"device-id": id})
khenaidoo6d62c002019-05-15 21:57:03 -0400183 if dMgr.IsDeviceInCache(id) { // Proceed only if an agent is present for this device
Kent Hagerman6031aad2020-07-29 16:36:33 -0400184 if device, err := dMgr.getDeviceReadOnly(ctx, id); err == nil && device.Root {
khenaidoo6d62c002019-05-15 21:57:03 -0400185 // stop managing the logical device
David Bainbridged1afd662020-03-26 18:27:41 -0700186 _ = dMgr.logicalDeviceMgr.stopManagingLogicalDeviceWithDeviceID(ctx, id)
khenaidoo6d62c002019-05-15 21:57:03 -0400187 }
npujar467fe752020-01-16 20:17:45 +0530188 if agent := dMgr.getDeviceAgent(ctx, id); agent != nil {
khenaidoo442e7c72020-03-10 16:13:48 -0400189 if err := agent.stop(ctx); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000190 logger.Warnw(ctx, "unable-to-stop-device-agent", log.Fields{"device-id": agent.deviceID, "error": err})
khenaidoo442e7c72020-03-10 16:13:48 -0400191 }
khenaidoo4c9e5592019-09-09 16:20:41 -0400192 dMgr.deleteDeviceAgentFromMap(agent)
khenaidoo6d62c002019-05-15 21:57:03 -0400193 }
194 }
195}
196
Kent Hagermancba2f302020-07-28 13:37:36 -0400197// getDeviceReadOnly will returns a device, either from memory or from the dB, if present
198func (dMgr *Manager) getDeviceReadOnly(ctx context.Context, id string) (*voltha.Device, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530199 logger.Debugw(ctx, "get-device-read-only", log.Fields{"device-id": id})
npujar467fe752020-01-16 20:17:45 +0530200 if agent := dMgr.getDeviceAgent(ctx, id); agent != nil {
Kent Hagermancba2f302020-07-28 13:37:36 -0400201 return agent.getDeviceReadOnly(ctx)
khenaidoo92e62c52018-10-03 14:02:54 -0400202 }
203 return nil, status.Errorf(codes.NotFound, "%s", id)
khenaidoob9203542018-09-17 22:56:37 -0400204}
205
Kent Hagerman2a07b862020-06-19 15:23:07 -0400206func (dMgr *Manager) listDevicePorts(ctx context.Context, id string) (map[uint32]*voltha.Port, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530207 logger.Debugw(ctx, "list-device-ports", log.Fields{"device-id": id})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400208 agent := dMgr.getDeviceAgent(ctx, id)
209 if agent == nil {
210 return nil, status.Errorf(codes.NotFound, "%s", id)
211 }
212 return agent.listDevicePorts(), nil
213}
214
npujar1d86a522019-11-14 17:11:16 +0530215// IsDeviceInCache returns true if device is found in the map
Kent Hagerman2b216042020-04-03 18:28:56 -0400216func (dMgr *Manager) IsDeviceInCache(id string) bool {
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400217 _, exist := dMgr.deviceAgents.Load(id)
khenaidoo297cd252019-02-07 22:10:23 -0500218 return exist
219}
220
Thomas Lee S51b5cb82019-10-14 14:49:34 +0530221//isParentDeviceExist checks whether device is already preprovisioned.
Kent Hagerman2b216042020-04-03 18:28:56 -0400222func (dMgr *Manager) isParentDeviceExist(ctx context.Context, newDevice *voltha.Device) (bool, error) {
Thomas Lee S51b5cb82019-10-14 14:49:34 +0530223 hostPort := newDevice.GetHostAndPort()
Kent Hagerman4f355f52020-03-30 16:01:33 -0400224 var devices []*voltha.Device
Kent Hagermanf5a67352020-04-30 15:15:26 -0400225 if err := dMgr.dProxy.List(ctx, &devices); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530226 logger.Errorw(ctx, "failed-to-list-devices-from-cluster-data-proxy", log.Fields{"error": err})
Thomas Lee Se5a44012019-11-07 20:32:24 +0530227 return false, err
228 }
Kent Hagerman4f355f52020-03-30 16:01:33 -0400229 for _, device := range devices {
230 if !device.Root {
231 continue
232 }
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530233
234 if hostPort != "" && hostPort == device.GetHostAndPort() {
Kent Hagerman4f355f52020-03-30 16:01:33 -0400235 return true, nil
236 }
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530237 if newDevice.MacAddress != "" && newDevice.MacAddress == device.MacAddress {
Kent Hagerman4f355f52020-03-30 16:01:33 -0400238 return true, nil
Thomas Lee S51b5cb82019-10-14 14:49:34 +0530239 }
240 }
Thomas Lee Se5a44012019-11-07 20:32:24 +0530241 return false, nil
Thomas Lee S51b5cb82019-10-14 14:49:34 +0530242}
243
khenaidoo6d62c002019-05-15 21:57:03 -0400244//getDeviceFromModelretrieves the device data from the model.
Kent Hagerman2b216042020-04-03 18:28:56 -0400245func (dMgr *Manager) getDeviceFromModel(ctx context.Context, deviceID string) (*voltha.Device, error) {
Kent Hagerman4f355f52020-03-30 16:01:33 -0400246 device := &voltha.Device{}
Kent Hagermanf5a67352020-04-30 15:15:26 -0400247 if have, err := dMgr.dProxy.Get(ctx, deviceID, device); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000248 logger.Errorw(ctx, "failed-to-get-device-info-from-cluster-proxy", log.Fields{"error": err})
Thomas Lee Se5a44012019-11-07 20:32:24 +0530249 return nil, err
Kent Hagerman4f355f52020-03-30 16:01:33 -0400250 } else if !have {
251 return nil, status.Error(codes.NotFound, deviceID)
Thomas Lee Se5a44012019-11-07 20:32:24 +0530252 }
Kent Hagerman4f355f52020-03-30 16:01:33 -0400253
254 return device, nil
khenaidoo6d62c002019-05-15 21:57:03 -0400255}
256
npujar1d86a522019-11-14 17:11:16 +0530257// loadDevice loads the deviceID in memory, if not present
Kent Hagerman2b216042020-04-03 18:28:56 -0400258func (dMgr *Manager) loadDevice(ctx context.Context, deviceID string) (*Agent, error) {
npujar1d86a522019-11-14 17:11:16 +0530259 if deviceID == "" {
khenaidoo297cd252019-02-07 22:10:23 -0500260 return nil, status.Error(codes.InvalidArgument, "deviceId empty")
261 }
khenaidoo4c9e5592019-09-09 16:20:41 -0400262 var err error
263 var device *voltha.Device
264 dMgr.devicesLoadingLock.Lock()
npujar1d86a522019-11-14 17:11:16 +0530265 if _, exist := dMgr.deviceLoadingInProgress[deviceID]; !exist {
266 if !dMgr.IsDeviceInCache(deviceID) {
267 dMgr.deviceLoadingInProgress[deviceID] = []chan int{make(chan int, 1)}
khenaidoo4c9e5592019-09-09 16:20:41 -0400268 dMgr.devicesLoadingLock.Unlock()
269 // Proceed with the loading only if the device exist in the Model (could have been deleted)
npujar467fe752020-01-16 20:17:45 +0530270 if device, err = dMgr.getDeviceFromModel(ctx, deviceID); err == nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000271 logger.Debugw(ctx, "loading-device", log.Fields{"device-id": deviceID})
khenaidood948f772021-08-11 17:49:24 -0400272 agent := newAgent(device, dMgr, dMgr.dbPath, dMgr.dProxy, dMgr.internalTimeout, dMgr.rpcTimeout)
khenaidoo7585a962021-06-10 16:15:38 -0400273 if _, err = agent.start(ctx, true, device); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530274 logger.Warnw(ctx, "failure-loading-device", log.Fields{"device-id": deviceID, "error": err})
khenaidoo4c9e5592019-09-09 16:20:41 -0400275 } else {
276 dMgr.addDeviceAgentToMap(agent)
277 }
278 } else {
Himani Chawlab4c25912020-11-12 17:16:38 +0530279 logger.Debugw(ctx, "device-is-not-in-model", log.Fields{"device-id": deviceID})
khenaidoo6d62c002019-05-15 21:57:03 -0400280 }
khenaidoo4c9e5592019-09-09 16:20:41 -0400281 // announce completion of task to any number of waiting channels
282 dMgr.devicesLoadingLock.Lock()
npujar1d86a522019-11-14 17:11:16 +0530283 if v, ok := dMgr.deviceLoadingInProgress[deviceID]; ok {
khenaidoo4c9e5592019-09-09 16:20:41 -0400284 for _, ch := range v {
285 close(ch)
286 }
npujar1d86a522019-11-14 17:11:16 +0530287 delete(dMgr.deviceLoadingInProgress, deviceID)
khenaidoo4c9e5592019-09-09 16:20:41 -0400288 }
289 dMgr.devicesLoadingLock.Unlock()
khenaidoo6d62c002019-05-15 21:57:03 -0400290 } else {
khenaidoo4c9e5592019-09-09 16:20:41 -0400291 dMgr.devicesLoadingLock.Unlock()
khenaidoo297cd252019-02-07 22:10:23 -0500292 }
khenaidoo4c9e5592019-09-09 16:20:41 -0400293 } else {
294 ch := make(chan int, 1)
npujar1d86a522019-11-14 17:11:16 +0530295 dMgr.deviceLoadingInProgress[deviceID] = append(dMgr.deviceLoadingInProgress[deviceID], ch)
khenaidoo4c9e5592019-09-09 16:20:41 -0400296 dMgr.devicesLoadingLock.Unlock()
297 // Wait for the channel to be closed, implying the process loading this device is done.
298 <-ch
khenaidoo297cd252019-02-07 22:10:23 -0500299 }
npujar1d86a522019-11-14 17:11:16 +0530300 if agent, ok := dMgr.deviceAgents.Load(deviceID); ok {
Kent Hagerman2b216042020-04-03 18:28:56 -0400301 return agent.(*Agent), nil
khenaidoo297cd252019-02-07 22:10:23 -0500302 }
npujar1d86a522019-11-14 17:11:16 +0530303 return nil, status.Errorf(codes.Aborted, "Error loading device %s", deviceID)
khenaidoo297cd252019-02-07 22:10:23 -0500304}
305
306// loadRootDeviceParentAndChildren loads the children and parents of a root device in memory
Kent Hagerman2a07b862020-06-19 15:23:07 -0400307func (dMgr *Manager) loadRootDeviceParentAndChildren(ctx context.Context, device *voltha.Device, devicePorts map[uint32]*voltha.Port) error {
divyadesaicb8b59d2020-08-18 09:55:47 +0000308 logger.Debugw(ctx, "loading-parent-and-children", log.Fields{"device-id": device.Id})
khenaidoo297cd252019-02-07 22:10:23 -0500309 if device.Root {
310 // Scenario A
311 if device.ParentId != "" {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400312 // Load logical device if needed.
npujar467fe752020-01-16 20:17:45 +0530313 if err := dMgr.logicalDeviceMgr.load(ctx, device.ParentId); err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000314 logger.Warnw(ctx, "failure-loading-logical-device", log.Fields{"logical-device-id": device.ParentId})
khenaidoo297cd252019-02-07 22:10:23 -0500315 }
316 } else {
divyadesaicb8b59d2020-08-18 09:55:47 +0000317 logger.Debugw(ctx, "no-parent-to-load", log.Fields{"device-id": device.Id})
khenaidoo297cd252019-02-07 22:10:23 -0500318 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400319 // Load all child devices, if needed
320 childDeviceIds := dMgr.getAllChildDeviceIds(ctx, devicePorts)
321 for childDeviceID := range childDeviceIds {
322 if _, err := dMgr.loadDevice(ctx, childDeviceID); err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000323 logger.Warnw(ctx, "failure-loading-device", log.Fields{"device-id": childDeviceID, "error": err})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400324 return err
khenaidoo297cd252019-02-07 22:10:23 -0500325 }
khenaidoo297cd252019-02-07 22:10:23 -0500326 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530327 logger.Debugw(ctx, "loaded-children", log.Fields{"device-id": device.Id, "num-children": len(childDeviceIds)})
khenaidoo297cd252019-02-07 22:10:23 -0500328 }
329 return nil
330}
331
332// load loads the deviceId in memory, if not present, and also loads its accompanying parents and children. Loading
333// in memory is for improved performance. It is not imperative that a device needs to be in memory when a request
334// acting on the device is received by the core. In such a scenario, the Core will load the device in memory first
335// and the proceed with the request.
Kent Hagerman2b216042020-04-03 18:28:56 -0400336func (dMgr *Manager) load(ctx context.Context, deviceID string) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000337 logger.Debug(ctx, "load...")
khenaidoo297cd252019-02-07 22:10:23 -0500338 // 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 -0400339 var dAgent *Agent
khenaidoo297cd252019-02-07 22:10:23 -0500340 var err error
npujar467fe752020-01-16 20:17:45 +0530341 if dAgent, err = dMgr.loadDevice(ctx, deviceID); err != nil {
khenaidoo297cd252019-02-07 22:10:23 -0500342 return err
343 }
344 // Get the loaded device details
Kent Hagermancba2f302020-07-28 13:37:36 -0400345 device, err := dAgent.getDeviceReadOnly(ctx)
khenaidoo442e7c72020-03-10 16:13:48 -0400346 if err != nil {
347 return err
348 }
khenaidoo297cd252019-02-07 22:10:23 -0500349
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530350 // If the device is in Pre-provisioning or getting deleted state stop here
351 if device.AdminState == voltha.AdminState_PREPROVISIONED || dAgent.isDeletionInProgress() {
khenaidoo297cd252019-02-07 22:10:23 -0500352 return nil
353 }
354
355 // Now we face two scenarios
356 if device.Root {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400357 devicePorts := dAgent.listDevicePorts()
358
khenaidoo297cd252019-02-07 22:10:23 -0500359 // Load all children as well as the parent of this device (logical_device)
Kent Hagerman2a07b862020-06-19 15:23:07 -0400360 if err := dMgr.loadRootDeviceParentAndChildren(ctx, device, devicePorts); err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000361 logger.Warnw(ctx, "failure-loading-device-parent-and-children", log.Fields{"device-id": deviceID})
khenaidoo297cd252019-02-07 22:10:23 -0500362 return err
363 }
divyadesaicb8b59d2020-08-18 09:55:47 +0000364 logger.Debugw(ctx, "successfully-loaded-parent-and-children", log.Fields{"device-id": deviceID})
Andrey Pozolotin34dd63f2021-05-31 21:26:40 +0300365 } else if device.ParentId != "" {
khenaidoo297cd252019-02-07 22:10:23 -0500366 // Scenario B - use the parentId of that device (root device) to trigger the loading
Andrey Pozolotin34dd63f2021-05-31 21:26:40 +0300367 return dMgr.load(ctx, device.ParentId)
khenaidoo297cd252019-02-07 22:10:23 -0500368 }
Andrey Pozolotin34dd63f2021-05-31 21:26:40 +0300369
khenaidoo297cd252019-02-07 22:10:23 -0500370 return nil
371}
372
khenaidooba6b6c42019-08-02 09:11:56 -0400373// adapterRestarted is invoked whenever an adapter is restarted
Kent Hagerman2b216042020-04-03 18:28:56 -0400374func (dMgr *Manager) adapterRestarted(ctx context.Context, adapter *voltha.Adapter) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530375 logger.Debugw(ctx, "adapter-restarted", log.Fields{"adapter-id": adapter.Id, "vendor": adapter.Vendor,
khenaidood948f772021-08-11 17:49:24 -0400376 "current-replica": adapter.CurrentReplica, "total-replicas": adapter.TotalReplicas, "restarted-endpoint": adapter.Endpoint})
khenaidooba6b6c42019-08-02 09:11:56 -0400377
khenaidood948f772021-08-11 17:49:24 -0400378 numberOfDevicesToReconcile := 0
379 dMgr.deviceAgents.Range(func(key, value interface{}) bool {
380 deviceAgent, ok := value.(*Agent)
381 if ok && deviceAgent.adapterEndpoint == adapter.Endpoint {
382 // Before reconciling, abort in-process request
383 if err := deviceAgent.abortAllProcessing(utils.WithNewSpanAndRPCMetadataContext(ctx, "AbortProcessingOnRestart")); err == nil {
384 logger.Debugw(ctx, "reconciling-device",
385 log.Fields{
386 "device-id": deviceAgent.deviceID,
387 "root-device": deviceAgent.isRootDevice,
388 "restarted-endpoint": adapter.Endpoint,
389 "device-type": deviceAgent.deviceType,
390 "adapter-type": adapter.Type,
391 })
392 go deviceAgent.ReconcileDevice(utils.WithNewSpanAndRPCMetadataContext(ctx, "ReconcileDevice"))
393 numberOfDevicesToReconcile++
394 } else {
395 logger.Errorw(ctx, "failed-aborting-exisiting-processing", log.Fields{"error": err})
khenaidooba6b6c42019-08-02 09:11:56 -0400396 }
397 }
khenaidood948f772021-08-11 17:49:24 -0400398 return true
399 })
400 logger.Debugw(ctx, "reconciling-on-adapter-restart-initiated", log.Fields{"adapter-endpoint": adapter.Endpoint, "number-of-devices-to-reconcile": numberOfDevicesToReconcile})
khenaidooba6b6c42019-08-02 09:11:56 -0400401 return nil
402}
403
Kent Hagerman2b216042020-04-03 18:28:56 -0400404func (dMgr *Manager) UpdateDeviceUsingAdapterData(ctx context.Context, device *voltha.Device) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530405 logger.Debugw(ctx, "update-device-using-adapter-data", log.Fields{"device-id": device.Id, "device": device})
npujar467fe752020-01-16 20:17:45 +0530406 if agent := dMgr.getDeviceAgent(ctx, device.Id); agent != nil {
407 return agent.updateDeviceUsingAdapterData(ctx, device)
khenaidoob9203542018-09-17 22:56:37 -0400408 }
409 return status.Errorf(codes.NotFound, "%s", device.Id)
410}
411
khenaidoo0db4c812020-05-27 15:27:30 -0400412func (dMgr *Manager) addPeerPort(ctx context.Context, deviceID string, port *voltha.Port) error {
413 meAsPeer := &voltha.Port_PeerPort{DeviceId: deviceID, PortNo: port.PortNo}
414 for _, peerPort := range port.Peers {
415 if agent := dMgr.getDeviceAgent(ctx, peerPort.DeviceId); agent != nil {
416 if err := agent.addPeerPort(ctx, meAsPeer); err != nil {
417 return err
418 }
419 }
420 }
421 // Notify the logical device manager to setup a logical port, if needed. If the added port is an NNI or UNI
422 // then a logical port will be added to the logical device and the device route generated. If the port is a
423 // PON port then only the device graph will be generated.
Kent Hagermancba2f302020-07-28 13:37:36 -0400424 device, err := dMgr.getDeviceReadOnly(ctx, deviceID)
khenaidoo0db4c812020-05-27 15:27:30 -0400425 if err != nil {
426 return err
427 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400428 ports, err := dMgr.listDevicePorts(ctx, deviceID)
429 if err != nil {
430 return err
431 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530432 subCtx := utils.WithSpanAndRPCMetadataFromContext(ctx)
433
434 if err = dMgr.logicalDeviceMgr.updateLogicalPort(subCtx, device, ports, port); err != nil {
khenaidoo0db4c812020-05-27 15:27:30 -0400435 return err
436 }
437 return nil
438}
439
Kent Hagerman2b216042020-04-03 18:28:56 -0400440func (dMgr *Manager) AddPort(ctx context.Context, deviceID string, port *voltha.Port) error {
npujar467fe752020-01-16 20:17:45 +0530441 agent := dMgr.getDeviceAgent(ctx, deviceID)
npujar1d86a522019-11-14 17:11:16 +0530442 if agent != nil {
npujar467fe752020-01-16 20:17:45 +0530443 if err := agent.addPort(ctx, port); err != nil {
khenaidoo92e62c52018-10-03 14:02:54 -0400444 return err
445 }
khenaidoo0db4c812020-05-27 15:27:30 -0400446 // Setup peer ports in its own routine
447 go func() {
Himani Chawlab4c25912020-11-12 17:16:38 +0530448 subCtx := utils.WithSpanAndRPCMetadataFromContext(ctx)
449 if err := dMgr.addPeerPort(subCtx, deviceID, port); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000450 logger.Errorw(ctx, "unable-to-add-peer-port", log.Fields{"error": err, "device-id": deviceID})
khenaidoo92e62c52018-10-03 14:02:54 -0400451 }
khenaidoo0db4c812020-05-27 15:27:30 -0400452 }()
khenaidoo92e62c52018-10-03 14:02:54 -0400453 return nil
khenaidoob9203542018-09-17 22:56:37 -0400454 }
npujar1d86a522019-11-14 17:11:16 +0530455 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoob9203542018-09-17 22:56:37 -0400456}
457
khenaidood948f772021-08-11 17:49:24 -0400458func (dMgr *Manager) canMultipleAdapterRequestProceed(ctx context.Context, deviceIDs []string) error {
459 ready := len(deviceIDs) > 0
460 for _, deviceID := range deviceIDs {
461 agent := dMgr.getDeviceAgent(ctx, deviceID)
462 if agent == nil {
463 logger.Errorw(ctx, "adapter-nil", log.Fields{"device-id": deviceID})
464 return status.Errorf(codes.Unavailable, "adapter-nil-for-%s", deviceID)
465 }
466 ready = ready && agent.isAdapterConnectionUp(ctx)
467 if !ready {
468 return status.Errorf(codes.Unavailable, "adapter-connection-down-for-%s", deviceID)
469 }
470 if err := agent.canDeviceRequestProceed(ctx); err != nil {
471 return err
472 }
473 }
474 if !ready {
475 return status.Error(codes.Unavailable, "adapter(s)-not-ready")
476 }
477 return nil
478}
479
khenaidoo9beaaf12021-10-19 17:32:01 -0400480func (dMgr *Manager) addFlowsAndGroups(ctx context.Context, deviceID string, flows []*ofp.OfpFlowStats, groups []*ofp.OfpGroupEntry, flowMetadata *ofp.FlowMetadata) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530481 logger.Debugw(ctx, "add-flows-and-groups", log.Fields{"device-id": deviceID, "groups:": groups, "flow-metadata": flowMetadata})
npujar467fe752020-01-16 20:17:45 +0530482 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
483 return agent.addFlowsAndGroups(ctx, flows, groups, flowMetadata)
khenaidoo0458db62019-06-20 08:50:36 -0400484 }
npujar1d86a522019-11-14 17:11:16 +0530485 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo0458db62019-06-20 08:50:36 -0400486}
487
khenaidoo787224a2020-04-16 18:08:47 -0400488// deleteParentFlows removes flows from the parent device based on specific attributes
khenaidoo9beaaf12021-10-19 17:32:01 -0400489func (dMgr *Manager) deleteParentFlows(ctx context.Context, deviceID string, uniPort uint32, metadata *ofp.FlowMetadata) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530490 logger.Debugw(ctx, "delete-parent-flows", log.Fields{"device-id": deviceID, "uni-port": uniPort, "metadata": metadata})
khenaidoo787224a2020-04-16 18:08:47 -0400491 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400492 if !agent.isRootDevice {
khenaidoo787224a2020-04-16 18:08:47 -0400493 return status.Errorf(codes.FailedPrecondition, "not-a-parent-device-%s", deviceID)
494 }
495 return agent.filterOutFlows(ctx, uniPort, metadata)
496 }
497 return status.Errorf(codes.NotFound, "%s", deviceID)
498}
499
khenaidoo9beaaf12021-10-19 17:32:01 -0400500func (dMgr *Manager) deleteFlowsAndGroups(ctx context.Context, deviceID string, flows []*ofp.OfpFlowStats, groups []*ofp.OfpGroupEntry, flowMetadata *ofp.FlowMetadata) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530501 logger.Debugw(ctx, "delete-flows-and-groups", log.Fields{"device-id": deviceID})
npujar467fe752020-01-16 20:17:45 +0530502 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
503 return agent.deleteFlowsAndGroups(ctx, flows, groups, flowMetadata)
khenaidoo0458db62019-06-20 08:50:36 -0400504 }
npujar1d86a522019-11-14 17:11:16 +0530505 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo0458db62019-06-20 08:50:36 -0400506}
507
khenaidoo9beaaf12021-10-19 17:32:01 -0400508func (dMgr *Manager) updateFlowsAndGroups(ctx context.Context, deviceID string, flows []*ofp.OfpFlowStats, groups []*ofp.OfpGroupEntry, flowMetadata *ofp.FlowMetadata) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530509 logger.Debugw(ctx, "update-flows-and-groups", log.Fields{"device-id": deviceID})
npujar467fe752020-01-16 20:17:45 +0530510 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
511 return agent.updateFlowsAndGroups(ctx, flows, groups, flowMetadata)
khenaidoo19d7b632018-10-30 10:49:50 -0400512 }
npujar1d86a522019-11-14 17:11:16 +0530513 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo19d7b632018-10-30 10:49:50 -0400514}
515
Kent Hagerman2b216042020-04-03 18:28:56 -0400516// InitPmConfigs initialize the pm configs as defined by the adapter.
517func (dMgr *Manager) InitPmConfigs(ctx context.Context, deviceID string, pmConfigs *voltha.PmConfigs) error {
khenaidoob3127472019-07-24 21:04:55 -0400518 if pmConfigs.Id == "" {
519 return status.Errorf(codes.FailedPrecondition, "invalid-device-Id")
520 }
npujar467fe752020-01-16 20:17:45 +0530521 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
522 return agent.initPmConfigs(ctx, pmConfigs)
khenaidoob9203542018-09-17 22:56:37 -0400523 }
npujar1d86a522019-11-14 17:11:16 +0530524 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoob9203542018-09-17 22:56:37 -0400525}
526
khenaidoo9beaaf12021-10-19 17:32:01 -0400527func (dMgr *Manager) getSwitchCapability(ctx context.Context, deviceID string) (*ca.SwitchCapability, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530528 logger.Debugw(ctx, "get-switch-capability", log.Fields{"device-id": deviceID})
npujar467fe752020-01-16 20:17:45 +0530529 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
khenaidoob9203542018-09-17 22:56:37 -0400530 return agent.getSwitchCapability(ctx)
531 }
npujar1d86a522019-11-14 17:11:16 +0530532 return nil, status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoob9203542018-09-17 22:56:37 -0400533}
534
Kent Hagerman2b216042020-04-03 18:28:56 -0400535func (dMgr *Manager) UpdateDeviceStatus(ctx context.Context, deviceID string, operStatus voltha.OperStatus_Types, connStatus voltha.ConnectStatus_Types) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530536 logger.Debugw(ctx, "update-device-status", log.Fields{"device-id": deviceID, "oper-status": operStatus, "conn-status": connStatus})
npujar467fe752020-01-16 20:17:45 +0530537 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
538 return agent.updateDeviceStatus(ctx, operStatus, connStatus)
khenaidoo92e62c52018-10-03 14:02:54 -0400539 }
npujar1d86a522019-11-14 17:11:16 +0530540 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo92e62c52018-10-03 14:02:54 -0400541}
542
Kent Hagerman2b216042020-04-03 18:28:56 -0400543func (dMgr *Manager) UpdateChildrenStatus(ctx context.Context, deviceID string, operStatus voltha.OperStatus_Types, connStatus voltha.ConnectStatus_Types) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530544 logger.Debugw(ctx, "update-children-status", log.Fields{"parent-device-id": deviceID, "oper-status": operStatus, "conn-status": connStatus})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400545 parentDevicePorts, err := dMgr.listDevicePorts(ctx, deviceID)
546 if err != nil {
khenaidoo4d4802d2018-10-04 21:59:49 -0400547 return status.Errorf(codes.Aborted, "%s", err.Error())
548 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400549 for childDeviceID := range dMgr.getAllChildDeviceIds(ctx, parentDevicePorts) {
npujar467fe752020-01-16 20:17:45 +0530550 if agent := dMgr.getDeviceAgent(ctx, childDeviceID); agent != nil {
551 if err = agent.updateDeviceStatus(ctx, operStatus, connStatus); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530552 return status.Errorf(codes.Aborted, "childDevice:%s, error:%s", childDeviceID, err.Error())
khenaidoo4d4802d2018-10-04 21:59:49 -0400553 }
554 }
555 }
556 return nil
557}
558
Kent Hagerman2b216042020-04-03 18:28:56 -0400559func (dMgr *Manager) UpdatePortState(ctx context.Context, deviceID string, portType voltha.Port_PortType, portNo uint32, operStatus voltha.OperStatus_Types) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530560 logger.Debugw(ctx, "update-port-state", log.Fields{"device-id": deviceID, "port-type": portType, "port-no": portNo, "oper-status": operStatus})
npujar467fe752020-01-16 20:17:45 +0530561 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
562 if err := agent.updatePortState(ctx, portType, portNo, operStatus); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530563 logger.Errorw(ctx, "updating-port-state-failed", log.Fields{"device-id": deviceID, "port-no": portNo, "error": err})
khenaidoo171b98e2019-10-31 11:48:15 -0400564 return err
565 }
566 // Notify the logical device manager to change the port state
Mahir Gunyel18fa0c92020-03-06 13:34:04 -0800567 // Do this for NNI and UNIs only. PON ports are not known by logical device
568 if portType == voltha.Port_ETHERNET_NNI || portType == voltha.Port_ETHERNET_UNI {
569 go func() {
Himani Chawlab4c25912020-11-12 17:16:38 +0530570 subCtx := utils.WithSpanAndRPCMetadataFromContext(ctx)
571 err := dMgr.logicalDeviceMgr.updatePortState(subCtx, deviceID, portNo, operStatus)
Mahir Gunyel18fa0c92020-03-06 13:34:04 -0800572 if err != nil {
573 // While we want to handle (catch) and log when
574 // an update to a port was not able to be
575 // propagated to the logical port, we can report
576 // it as a warning and not an error because it
577 // doesn't stop or modify processing.
578 // TODO: VOL-2707
Rohan Agrawal31f21802020-06-12 05:38:46 +0000579 logger.Warnw(ctx, "unable-to-update-logical-port-state", log.Fields{"error": err})
Mahir Gunyel18fa0c92020-03-06 13:34:04 -0800580 }
581 }()
582 }
khenaidoo442e7c72020-03-10 16:13:48 -0400583 return nil
khenaidoob9203542018-09-17 22:56:37 -0400584 }
npujar1d86a522019-11-14 17:11:16 +0530585 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoob9203542018-09-17 22:56:37 -0400586}
587
Kent Hagerman2b216042020-04-03 18:28:56 -0400588//UpdatePortsState updates all ports on the device
Kent Hagerman2a07b862020-06-19 15:23:07 -0400589func (dMgr *Manager) UpdatePortsState(ctx context.Context, deviceID string, portTypeFilter uint32, state voltha.OperStatus_Types) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530590 logger.Debugw(ctx, "update-ports-state", log.Fields{"device-id": deviceID})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400591 agent := dMgr.getDeviceAgent(ctx, deviceID)
592 if agent == nil {
593 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo3ab34882019-05-02 21:33:30 -0400594 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400595 if state != voltha.OperStatus_ACTIVE && state != voltha.OperStatus_UNKNOWN {
596 return status.Error(codes.Unimplemented, "state-change-not-implemented")
597 }
598 if err := agent.updatePortsOperState(ctx, portTypeFilter, state); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530599 logger.Warnw(ctx, "update-ports-state-failed", log.Fields{"device-id": deviceID, "error": err})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400600 return err
601 }
602 return nil
khenaidoo3ab34882019-05-02 21:33:30 -0400603}
604
Kent Hagerman2b216042020-04-03 18:28:56 -0400605func (dMgr *Manager) packetOut(ctx context.Context, deviceID string, outPort uint32, packet *ofp.OfpPacketOut) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530606 logger.Debugw(ctx, "packet-out", log.Fields{"device-id": deviceID, "out-port": outPort})
npujar467fe752020-01-16 20:17:45 +0530607 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
608 return agent.packetOut(ctx, outPort, packet)
khenaidoofdbad6e2018-11-06 22:26:38 -0500609 }
npujar1d86a522019-11-14 17:11:16 +0530610 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoofdbad6e2018-11-06 22:26:38 -0500611}
612
npujar1d86a522019-11-14 17:11:16 +0530613// PacketIn receives packet from adapter
Kent Hagerman2b216042020-04-03 18:28:56 -0400614func (dMgr *Manager) PacketIn(ctx context.Context, deviceID string, port uint32, transactionID string, packet []byte) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530615 logger.Debugw(ctx, "packet-in", log.Fields{"device-id": deviceID, "port": port})
khenaidoofdbad6e2018-11-06 22:26:38 -0500616 // Get the logical device Id based on the deviceId
617 var device *voltha.Device
618 var err error
Kent Hagermancba2f302020-07-28 13:37:36 -0400619 if device, err = dMgr.getDeviceReadOnly(ctx, deviceID); err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000620 logger.Errorw(ctx, "device-not-found", log.Fields{"device-id": deviceID})
khenaidoofdbad6e2018-11-06 22:26:38 -0500621 return err
622 }
khenaidoo43c82122018-11-22 18:38:28 -0500623 if !device.Root {
divyadesaicb8b59d2020-08-18 09:55:47 +0000624 logger.Errorw(ctx, "device-not-root", log.Fields{"device-id": deviceID})
npujar1d86a522019-11-14 17:11:16 +0530625 return status.Errorf(codes.FailedPrecondition, "%s", deviceID)
khenaidoofdbad6e2018-11-06 22:26:38 -0500626 }
627
khenaidood948f772021-08-11 17:49:24 -0400628 if err := dMgr.logicalDeviceMgr.packetIn(ctx, device.ParentId, port, packet); err != nil {
khenaidoofdbad6e2018-11-06 22:26:38 -0500629 return err
630 }
631 return nil
632}
633
Kent Hagerman2b216042020-04-03 18:28:56 -0400634func (dMgr *Manager) setParentID(ctx context.Context, device *voltha.Device, parentID string) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530635 logger.Debugw(ctx, "set-parent-id", log.Fields{"device-id": device.Id, "parent-id": parentID})
npujar467fe752020-01-16 20:17:45 +0530636 if agent := dMgr.getDeviceAgent(ctx, device.Id); agent != nil {
637 return agent.setParentID(ctx, device, parentID)
khenaidooad06fd72019-10-28 12:26:05 -0400638 }
639 return status.Errorf(codes.NotFound, "%s", device.Id)
640}
641
Kent Hagerman2b216042020-04-03 18:28:56 -0400642func (dMgr *Manager) getParentDevice(ctx context.Context, childDevice *voltha.Device) *voltha.Device {
khenaidoo92e62c52018-10-03 14:02:54 -0400643 // Sanity check
644 if childDevice.Root {
645 // childDevice is the parent device
646 return childDevice
647 }
Kent Hagermancba2f302020-07-28 13:37:36 -0400648 parentDevice, _ := dMgr.getDeviceReadOnly(ctx, childDevice.ParentId)
khenaidoo92e62c52018-10-03 14:02:54 -0400649 return parentDevice
650}
651
khenaidoo4d4802d2018-10-04 21:59:49 -0400652/*
653All the functions below are callback functions where they are invoked with the latest and previous data. We can
654therefore use the data as is without trying to get the latest from the model.
655*/
656
khenaidoo0a822f92019-05-08 15:15:57 -0400657//DisableAllChildDevices is invoked as a callback when the parent device is disabled
Kent Hagerman2b216042020-04-03 18:28:56 -0400658func (dMgr *Manager) DisableAllChildDevices(ctx context.Context, parentCurrDevice *voltha.Device) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530659 logger.Debug(ctx, "disable-all-child-devices")
Kent Hagerman2a07b862020-06-19 15:23:07 -0400660 ports, _ := dMgr.listDevicePorts(ctx, parentCurrDevice.Id)
661 for childDeviceID := range dMgr.getAllChildDeviceIds(ctx, ports) {
npujar467fe752020-01-16 20:17:45 +0530662 if agent := dMgr.getDeviceAgent(ctx, childDeviceID); agent != nil {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400663 if err := agent.disableDevice(ctx); err != nil {
khenaidooe132f522020-03-20 15:23:15 -0400664 // Just log the error - this error happens only if the child device was already in deleted state.
divyadesaicb8b59d2020-08-18 09:55:47 +0000665 logger.Errorw(ctx, "failure-disable-device", log.Fields{"device-id": childDeviceID, "error": err.Error()})
khenaidoo92e62c52018-10-03 14:02:54 -0400666 }
667 }
668 }
669 return nil
670}
671
khenaidoo4d4802d2018-10-04 21:59:49 -0400672//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 -0400673func (dMgr *Manager) getAllChildDeviceIds(ctx context.Context, parentDevicePorts map[uint32]*voltha.Port) map[string]struct{} {
Himani Chawlab4c25912020-11-12 17:16:38 +0530674 logger.Debug(ctx, "get-all-child-device-ids")
Kent Hagerman2a07b862020-06-19 15:23:07 -0400675 childDeviceIds := make(map[string]struct{}, len(parentDevicePorts))
676 for _, port := range parentDevicePorts {
677 for _, peer := range port.Peers {
678 childDeviceIds[peer.DeviceId] = struct{}{}
khenaidoo92e62c52018-10-03 14:02:54 -0400679 }
680 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400681 logger.Debugw(ctx, "returning-getAllChildDeviceIds", log.Fields{"childDeviceIds": childDeviceIds})
682 return childDeviceIds
khenaidoo92e62c52018-10-03 14:02:54 -0400683}
684
khenaidood948f772021-08-11 17:49:24 -0400685//GgtAllChildDevices is a helper method to get all the child device IDs from the device passed as parameter
686func (dMgr *Manager) getAllChildDevices(ctx context.Context, parentDeviceID string) (*voltha.Devices, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530687 logger.Debugw(ctx, "get-all-child-devices", log.Fields{"parent-device-id": parentDeviceID})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400688 if parentDevicePorts, err := dMgr.listDevicePorts(ctx, parentDeviceID); err == nil {
khenaidoo297cd252019-02-07 22:10:23 -0500689 childDevices := make([]*voltha.Device, 0)
Kent Hagerman2a07b862020-06-19 15:23:07 -0400690 for deviceID := range dMgr.getAllChildDeviceIds(ctx, parentDevicePorts) {
Kent Hagermancba2f302020-07-28 13:37:36 -0400691 if d, e := dMgr.getDeviceReadOnly(ctx, deviceID); e == nil && d != nil {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400692 childDevices = append(childDevices, d)
khenaidoo297cd252019-02-07 22:10:23 -0500693 }
694 }
695 return &voltha.Devices{Items: childDevices}, nil
696 }
npujar1d86a522019-11-14 17:11:16 +0530697 return nil, status.Errorf(codes.NotFound, "%s", parentDeviceID)
khenaidoo297cd252019-02-07 22:10:23 -0500698}
699
Rohan Agrawal31f21802020-06-12 05:38:46 +0000700func (dMgr *Manager) NotifyInvalidTransition(ctx context.Context, device *voltha.Device) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530701 logger.Errorw(ctx, "notify-invalid-transition", log.Fields{
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500702 "device": device.Id,
703 "curr-admin-state": device.AdminState,
704 "curr-oper-state": device.OperStatus,
705 "curr-conn-state": device.ConnectStatus,
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400706 })
khenaidoo0a822f92019-05-08 15:15:57 -0400707 //TODO: notify over kafka?
708 return nil
709}
710
npujar1d86a522019-11-14 17:11:16 +0530711// UpdateDeviceAttribute updates value of particular device attribute
Kent Hagerman2b216042020-04-03 18:28:56 -0400712func (dMgr *Manager) UpdateDeviceAttribute(ctx context.Context, deviceID string, attribute string, value interface{}) {
npujar1d86a522019-11-14 17:11:16 +0530713 if agent, ok := dMgr.deviceAgents.Load(deviceID); ok {
Kent Hagerman2b216042020-04-03 18:28:56 -0400714 agent.(*Agent).updateDeviceAttribute(ctx, attribute, value)
khenaidoob9203542018-09-17 22:56:37 -0400715 }
716}
717
npujar1d86a522019-11-14 17:11:16 +0530718// GetParentDeviceID returns parent device id, either from memory or from the dB, if present
Kent Hagerman2b216042020-04-03 18:28:56 -0400719func (dMgr *Manager) GetParentDeviceID(ctx context.Context, deviceID string) string {
Kent Hagermancba2f302020-07-28 13:37:36 -0400720 if device, _ := dMgr.getDeviceReadOnly(ctx, deviceID); device != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530721 logger.Infow(ctx, "get-parent-device-id", log.Fields{"device-id": device.Id, "parent-id": device.ParentId})
khenaidoo4c9e5592019-09-09 16:20:41 -0400722 return device.ParentId
khenaidoob9203542018-09-17 22:56:37 -0400723 }
khenaidoo4c9e5592019-09-09 16:20:41 -0400724 return ""
khenaidoob9203542018-09-17 22:56:37 -0400725}
serkant.uluderya334479d2019-04-10 08:26:15 -0700726
Kent Hagerman2b216042020-04-03 18:28:56 -0400727func (dMgr *Manager) UpdateDeviceReason(ctx context.Context, deviceID string, reason string) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530728 logger.Debugw(ctx, "update-device-reason", log.Fields{"device-id": deviceID, "reason": reason})
npujar467fe752020-01-16 20:17:45 +0530729 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
730 return agent.updateDeviceReason(ctx, reason)
Mahir Gunyelfdee9212019-10-16 16:52:21 -0700731 }
npujar1d86a522019-11-14 17:11:16 +0530732 return status.Errorf(codes.NotFound, "%s", deviceID)
Mahir Gunyelfdee9212019-10-16 16:52:21 -0700733}
kesavandbc2d1622020-01-21 00:42:01 -0500734
Himani Chawlab4c25912020-11-12 17:16:38 +0530735func (dMgr *Manager) SendRPCEvent(ctx context.Context, id string, rpcEvent *voltha.RPCEvent,
736 category voltha.EventCategory_Types, subCategory *voltha.EventSubCategory_Types, raisedTs int64) {
737 //TODO Instead of directly sending to the kafka bus, queue the message and send it asynchronously
Mahir Gunyelb0343bf2021-05-11 14:14:26 -0700738 dMgr.Agent.SendRPCEvent(ctx, id, rpcEvent, category, subCategory, raisedTs)
Himani Chawlab4c25912020-11-12 17:16:38 +0530739}
Manindera496f852021-02-22 09:57:56 +0530740
khenaidood948f772021-08-11 17:49:24 -0400741func (dMgr *Manager) GetTransientState(ctx context.Context, id string) (core.DeviceTransientState_Types, error) {
Manindera496f852021-02-22 09:57:56 +0530742 agent := dMgr.getDeviceAgent(ctx, id)
743 if agent == nil {
khenaidood948f772021-08-11 17:49:24 -0400744 return core.DeviceTransientState_NONE, status.Errorf(codes.NotFound, "%s", id)
Manindera496f852021-02-22 09:57:56 +0530745 }
746 return agent.getTransientState(), nil
747}
ssiddiquif076cb82021-04-23 10:47:04 +0530748
ssiddiquif076cb82021-04-23 10:47:04 +0530749func (dMgr *Manager) validateImageDownloadRequest(request *voltha.DeviceImageDownloadRequest) error {
750 if request == nil || request.Image == nil || len(request.DeviceId) == 0 {
751 return status.Errorf(codes.InvalidArgument, "invalid argument")
752 }
753
754 for _, deviceID := range request.DeviceId {
755 if deviceID == nil {
756 return status.Errorf(codes.InvalidArgument, "id is nil")
757 }
758 }
759 return nil
760}
761
762func (dMgr *Manager) validateImageRequest(request *voltha.DeviceImageRequest) error {
763 if request == nil || len(request.DeviceId) == 0 || request.DeviceId[0] == nil {
764 return status.Errorf(codes.InvalidArgument, "invalid argument")
765 }
766
767 for _, deviceID := range request.DeviceId {
768 if deviceID == nil {
769 return status.Errorf(codes.InvalidArgument, "id is nil")
770 }
771 }
772
773 return nil
774}
775
776func (dMgr *Manager) validateDeviceImageResponse(response *voltha.DeviceImageResponse) error {
777 if response == nil || len(response.GetDeviceImageStates()) == 0 || response.GetDeviceImageStates()[0] == nil {
778 return status.Errorf(codes.Internal, "invalid-response-from-adapter")
779 }
780
781 return nil
782}
783
784func (dMgr *Manager) waitForAllResponses(ctx context.Context, opName string, respCh chan []*voltha.DeviceImageState, expectedResps int) (*voltha.DeviceImageResponse, error) {
785 response := &voltha.DeviceImageResponse{}
786 respCount := 0
787 for {
788 select {
789 case resp, ok := <-respCh:
790 if !ok {
791 logger.Errorw(ctx, opName+"-failed", log.Fields{"error": "channel-closed"})
792 return response, status.Errorf(codes.Aborted, "channel-closed")
793 }
794
795 if resp != nil {
796 logger.Debugw(ctx, opName+"-result", log.Fields{"image-state": resp[0].GetImageState(), "device-id": resp[0].GetDeviceId()})
797 response.DeviceImageStates = append(response.DeviceImageStates, resp...)
798 }
799
800 respCount++
801
802 //check whether all responses received, if so, sent back the collated response
803 if respCount == expectedResps {
804 return response, nil
805 }
806 continue
807 case <-ctx.Done():
808 return nil, status.Errorf(codes.Aborted, opName+"-failed-%s", ctx.Err())
809 }
810 }
811}
Maninder0aabf0c2021-03-17 14:55:14 +0530812
813func (dMgr *Manager) ReconcilingCleanup(ctx context.Context, device *voltha.Device) error {
814 agent := dMgr.getDeviceAgent(ctx, device.Id)
815 if agent == nil {
816 logger.Errorf(ctx, "Not able to get device agent.")
817 return status.Errorf(codes.NotFound, "Not able to get device agent for device : %s", device.Id)
818 }
819 err := agent.reconcilingCleanup(ctx)
820 if err != nil {
821 logger.Errorf(ctx, err.Error())
822 return status.Errorf(codes.Internal, err.Error())
823 }
824 return nil
825}
khenaidood948f772021-08-11 17:49:24 -0400826
827func (dMgr *Manager) adapterRestartedHandler(ctx context.Context, endpoint string) error {
828 // Get the adapter corresponding to that endpoint
829 if a, _ := dMgr.adapterMgr.GetAdapterWithEndpoint(ctx, endpoint); a != nil {
830 return dMgr.adapterRestarted(ctx, a)
831 }
832 logger.Errorw(ctx, "restarted-adapter-not-found", log.Fields{"endpoint": endpoint})
833 return fmt.Errorf("restarted adapter at endpoint %s not found", endpoint)
834}