blob: 1f6b59fe9d8bb3d797f16617cd1d41cb8de4ecf8 [file] [log] [blame]
khenaidoob9203542018-09-17 22:56:37 -04001/*
Joey Armstrong7a9af442024-01-03 19:26:36 -05002 * Copyright 2018-2024 Open Networking Foundation (ONF) and the ONF Contributors
khenaidoob9203542018-09-17 22:56:37 -04003
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"
nikesh.krishnanc8beca52023-12-07 13:45:03 +053022 "github.com/opencord/voltha-protos/v5/go/common"
David Bainbridged1afd662020-03-26 18:27:41 -070023 "sync"
24 "time"
25
khenaidood948f772021-08-11 17:49:24 -040026 "github.com/opencord/voltha-go/rw_core/config"
27 "github.com/opencord/voltha-lib-go/v7/pkg/probe"
28 "github.com/opencord/voltha-protos/v5/go/core"
29
sbarbari17d7e222019-11-05 10:02:29 -050030 "github.com/opencord/voltha-go/db/model"
Kent Hagerman2b216042020-04-03 18:28:56 -040031 "github.com/opencord/voltha-go/rw_core/core/adapter"
Kent Hagermanf5a67352020-04-30 15:15:26 -040032 "github.com/opencord/voltha-go/rw_core/core/device/event"
Kent Hagerman6031aad2020-07-29 16:36:33 -040033 "github.com/opencord/voltha-go/rw_core/core/device/state"
khenaidoo3d3b8c22019-05-22 18:10:39 -040034 "github.com/opencord/voltha-go/rw_core/utils"
khenaidood948f772021-08-11 17:49:24 -040035 "github.com/opencord/voltha-lib-go/v7/pkg/events"
36 "github.com/opencord/voltha-lib-go/v7/pkg/log"
khenaidoo9beaaf12021-10-19 17:32:01 -040037 ca "github.com/opencord/voltha-protos/v5/go/core_adapter"
khenaidood948f772021-08-11 17:49:24 -040038 ofp "github.com/opencord/voltha-protos/v5/go/openflow_13"
39 "github.com/opencord/voltha-protos/v5/go/voltha"
khenaidoob9203542018-09-17 22:56:37 -040040 "google.golang.org/grpc/codes"
41 "google.golang.org/grpc/status"
khenaidoob9203542018-09-17 22:56:37 -040042)
43
Kent Hagerman2b216042020-04-03 18:28:56 -040044// Manager represent device manager attributes
45type Manager struct {
Himani Chawlab4c25912020-11-12 17:16:38 +053046 deviceAgents sync.Map
47 rootDevices map[string]bool
48 lockRootDeviceMap sync.RWMutex
Mahir Gunyelb0343bf2021-05-11 14:14:26 -070049 *event.Agent
Kent Hagerman2b216042020-04-03 18:28:56 -040050 adapterMgr *adapter.Manager
51 logicalDeviceMgr *LogicalManager
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
khenaidood948f772021-08-11 17:49:24 -040056 internalTimeout time.Duration
57 rpcTimeout time.Duration
Himani Chawla4b4bd252021-11-08 15:59:40 +053058 flowTimeout time.Duration
khenaidoo4c9e5592019-09-09 16:20:41 -040059 devicesLoadingLock sync.RWMutex
60 deviceLoadingInProgress map[string][]chan int
Maninder0aabf0c2021-03-17 14:55:14 +053061 config *config.RWCoreFlags
khenaidooa46458b2021-12-15 16:50:44 -050062 doneCh chan struct{}
khenaidoob9203542018-09-17 22:56:37 -040063}
64
Joey Armstrong393daca2023-07-06 08:47:54 -040065// NewManagers creates the Manager and the Logical Manager.
khenaidood948f772021-08-11 17:49:24 -040066func NewManagers(dbPath *model.Path, adapterMgr *adapter.Manager, cf *config.RWCoreFlags, coreInstanceID string, eventProxy *events.EventProxy) (*Manager, *LogicalManager) {
Kent Hagerman2b216042020-04-03 18:28:56 -040067 deviceMgr := &Manager{
Kent Hagerman2b216042020-04-03 18:28:56 -040068 rootDevices: make(map[string]bool),
Kent Hagerman2b216042020-04-03 18:28:56 -040069 coreInstanceID: coreInstanceID,
Mahir Gunyel03de0d32020-06-03 01:36:59 -070070 dbPath: dbPath,
71 dProxy: dbPath.Proxy("devices"),
Kent Hagerman2b216042020-04-03 18:28:56 -040072 adapterMgr: adapterMgr,
khenaidood948f772021-08-11 17:49:24 -040073 internalTimeout: cf.InternalTimeout,
74 rpcTimeout: cf.RPCTimeout,
Himani Chawla4b4bd252021-11-08 15:59:40 +053075 flowTimeout: cf.FlowTimeout,
Maninder0aabf0c2021-03-17 14:55:14 +053076 Agent: event.NewAgent(eventProxy, coreInstanceID, cf.VolthaStackID),
Kent Hagerman2b216042020-04-03 18:28:56 -040077 deviceLoadingInProgress: make(map[string][]chan int),
Maninder0aabf0c2021-03-17 14:55:14 +053078 config: cf,
khenaidooa46458b2021-12-15 16:50:44 -050079 doneCh: make(chan struct{}),
Kent Hagerman2b216042020-04-03 18:28:56 -040080 }
Kent Hagerman6031aad2020-07-29 16:36:33 -040081 deviceMgr.stateTransitions = state.NewTransitionMap(deviceMgr)
Kent Hagerman2f0d0552020-04-23 17:28:52 -040082
Kent Hagerman2b216042020-04-03 18:28:56 -040083 logicalDeviceMgr := &LogicalManager{
Maninder0aabf0c2021-03-17 14:55:14 +053084 Manager: event.NewManager(eventProxy, coreInstanceID, cf.VolthaStackID),
Kent Hagerman2b216042020-04-03 18:28:56 -040085 deviceMgr: deviceMgr,
Mahir Gunyel03de0d32020-06-03 01:36:59 -070086 dbPath: dbPath,
87 ldProxy: dbPath.Proxy("logical_devices"),
khenaidood948f772021-08-11 17:49:24 -040088 internalTimeout: cf.InternalTimeout,
Kent Hagerman2b216042020-04-03 18:28:56 -040089 logicalDeviceLoadingInProgress: make(map[string][]chan int),
90 }
91 deviceMgr.logicalDeviceMgr = logicalDeviceMgr
Matteo Scandolod525ae32020-04-02 17:27:29 -070092
khenaidood948f772021-08-11 17:49:24 -040093 adapterMgr.SetAdapterRestartedCallback(deviceMgr.adapterRestartedHandler)
Matteo Scandolod525ae32020-04-02 17:27:29 -070094
Kent Hagerman2b216042020-04-03 18:28:56 -040095 return deviceMgr, logicalDeviceMgr
khenaidoob9203542018-09-17 22:56:37 -040096}
97
khenaidood948f772021-08-11 17:49:24 -040098func (dMgr *Manager) Start(ctx context.Context, serviceName string) error {
khenaidoo7585a962021-06-10 16:15:38 -040099 logger.Info(ctx, "starting-device-manager")
khenaidood948f772021-08-11 17:49:24 -0400100 probe.UpdateStatusFromContext(ctx, serviceName, probe.ServiceStatusPreparing)
khenaidoo7585a962021-06-10 16:15:38 -0400101
102 // Load all the devices from the dB
103 var devices []*voltha.Device
104 if err := dMgr.dProxy.List(ctx, &devices); err != nil {
105 // Any error from the dB means if we proceed we may end up with corrupted data
khenaidood948f772021-08-11 17:49:24 -0400106 logger.Errorw(ctx, "failed-to-list-devices-from-KV", log.Fields{"error": err, "service-name": serviceName})
107 return err
108 }
109
110 defer probe.UpdateStatusFromContext(ctx, serviceName, probe.ServiceStatusRunning)
111
112 if len(devices) == 0 {
113 logger.Info(ctx, "no-device-to-load")
114 return nil
khenaidoo7585a962021-06-10 16:15:38 -0400115 }
116
117 for _, device := range devices {
118 // Create an agent for each device
Himani Chawla4b4bd252021-11-08 15:59:40 +0530119 agent := newAgent(device, dMgr, dMgr.dbPath, dMgr.dProxy, dMgr.internalTimeout, dMgr.rpcTimeout, dMgr.flowTimeout)
khenaidoo7585a962021-06-10 16:15:38 -0400120 if _, err := agent.start(ctx, true, device); err != nil {
121 logger.Warnw(ctx, "failure-starting-agent", log.Fields{"device-id": device.Id})
122 } else {
123 dMgr.addDeviceAgentToMap(agent)
124 }
nikesh.krishnanc8beca52023-12-07 13:45:03 +0530125 // In case core goes down after it sets the transient state as reconciling but missed to fire the reconcile request to the adaptors, it should refire those reconcile requests on restart
126 if device.OperStatus != common.OperStatus_RECONCILING && (device.OperStatus == common.OperStatus_RECONCILING_FAILED || agent.matchTransientState(core.DeviceTransientState_RECONCILE_IN_PROGRESS)) {
127 go agent.ReconcileDevice(ctx)
128 }
khenaidoo7585a962021-06-10 16:15:38 -0400129 }
khenaidoo7585a962021-06-10 16:15:38 -0400130 logger.Info(ctx, "device-manager-started")
khenaidood948f772021-08-11 17:49:24 -0400131
132 return nil
khenaidoo7585a962021-06-10 16:15:38 -0400133}
134
khenaidooa46458b2021-12-15 16:50:44 -0500135func (dMgr *Manager) Stop(ctx context.Context, serviceName string) {
136 logger.Info(ctx, "stopping-device-manager")
137 close(dMgr.doneCh)
138 probe.UpdateStatusFromContext(ctx, serviceName, probe.ServiceStatusStopped)
139}
140
Kent Hagerman2b216042020-04-03 18:28:56 -0400141func (dMgr *Manager) addDeviceAgentToMap(agent *Agent) {
npujar1d86a522019-11-14 17:11:16 +0530142 if _, exist := dMgr.deviceAgents.Load(agent.deviceID); !exist {
143 dMgr.deviceAgents.Store(agent.deviceID, agent)
khenaidoob9203542018-09-17 22:56:37 -0400144 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400145 dMgr.lockRootDeviceMap.Lock()
146 defer dMgr.lockRootDeviceMap.Unlock()
Kent Hagerman2a07b862020-06-19 15:23:07 -0400147 dMgr.rootDevices[agent.deviceID] = agent.isRootDevice
khenaidoo2c6a0992019-04-29 13:46:56 -0400148
khenaidoob9203542018-09-17 22:56:37 -0400149}
150
Kent Hagerman2b216042020-04-03 18:28:56 -0400151func (dMgr *Manager) deleteDeviceAgentFromMap(agent *Agent) {
npujar1d86a522019-11-14 17:11:16 +0530152 dMgr.deviceAgents.Delete(agent.deviceID)
khenaidoo2c6a0992019-04-29 13:46:56 -0400153 dMgr.lockRootDeviceMap.Lock()
154 defer dMgr.lockRootDeviceMap.Unlock()
npujar1d86a522019-11-14 17:11:16 +0530155 delete(dMgr.rootDevices, agent.deviceID)
khenaidoo4d4802d2018-10-04 21:59:49 -0400156}
157
khenaidoo297cd252019-02-07 22:10:23 -0500158// 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 -0400159func (dMgr *Manager) getDeviceAgent(ctx context.Context, deviceID string) *Agent {
npujar1d86a522019-11-14 17:11:16 +0530160 agent, ok := dMgr.deviceAgents.Load(deviceID)
161 if ok {
Kent Hagerman2b216042020-04-03 18:28:56 -0400162 return agent.(*Agent)
khenaidoob9203542018-09-17 22:56:37 -0400163 }
khenaidoo442e7c72020-03-10 16:13:48 -0400164 // Try to load into memory - loading will also create the device agent and set the device ownership
npujar467fe752020-01-16 20:17:45 +0530165 err := dMgr.load(ctx, deviceID)
npujar1d86a522019-11-14 17:11:16 +0530166 if err == nil {
167 agent, ok = dMgr.deviceAgents.Load(deviceID)
168 if !ok {
169 return nil
170 }
Kent Hagerman2b216042020-04-03 18:28:56 -0400171 return agent.(*Agent)
npujar1d86a522019-11-14 17:11:16 +0530172 }
173 //TODO: Change the return params to return an error as well
divyadesaicb8b59d2020-08-18 09:55:47 +0000174 logger.Errorw(ctx, "loading-device-failed", log.Fields{"device-id": deviceID, "error": err})
khenaidoob9203542018-09-17 22:56:37 -0400175 return nil
176}
177
khenaidoo297cd252019-02-07 22:10:23 -0500178// listDeviceIdsFromMap returns the list of device IDs that are in memory
Kent Hagerman2b216042020-04-03 18:28:56 -0400179func (dMgr *Manager) listDeviceIdsFromMap() *voltha.IDs {
khenaidoo7ccedd52018-12-14 16:48:54 -0500180 result := &voltha.IDs{Items: make([]*voltha.ID, 0)}
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400181
182 dMgr.deviceAgents.Range(func(key, value interface{}) bool {
183 result.Items = append(result.Items, &voltha.ID{Id: key.(string)})
184 return true
185 })
186
khenaidoo7ccedd52018-12-14 16:48:54 -0500187 return result
188}
189
khenaidoo6d62c002019-05-15 21:57:03 -0400190// stopManagingDevice stops the management of the device as well as any of its reference device and logical device.
191// This function is called only in the Core that does not own this device. In the Core that owns this device then a
192// deletion deletion also includes removal of any reference of this device.
Kent Hagerman2b216042020-04-03 18:28:56 -0400193func (dMgr *Manager) stopManagingDevice(ctx context.Context, id string) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530194 logger.Infow(ctx, "stop-managing-device", log.Fields{"device-id": id})
khenaidoo6d62c002019-05-15 21:57:03 -0400195 if dMgr.IsDeviceInCache(id) { // Proceed only if an agent is present for this device
Kent Hagerman6031aad2020-07-29 16:36:33 -0400196 if device, err := dMgr.getDeviceReadOnly(ctx, id); err == nil && device.Root {
khenaidoo6d62c002019-05-15 21:57:03 -0400197 // stop managing the logical device
David Bainbridged1afd662020-03-26 18:27:41 -0700198 _ = dMgr.logicalDeviceMgr.stopManagingLogicalDeviceWithDeviceID(ctx, id)
khenaidoo6d62c002019-05-15 21:57:03 -0400199 }
npujar467fe752020-01-16 20:17:45 +0530200 if agent := dMgr.getDeviceAgent(ctx, id); agent != nil {
khenaidoo442e7c72020-03-10 16:13:48 -0400201 if err := agent.stop(ctx); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000202 logger.Warnw(ctx, "unable-to-stop-device-agent", log.Fields{"device-id": agent.deviceID, "error": err})
khenaidoo442e7c72020-03-10 16:13:48 -0400203 }
khenaidoo4c9e5592019-09-09 16:20:41 -0400204 dMgr.deleteDeviceAgentFromMap(agent)
khenaidoo6d62c002019-05-15 21:57:03 -0400205 }
206 }
207}
208
Kent Hagermancba2f302020-07-28 13:37:36 -0400209// getDeviceReadOnly will returns a device, either from memory or from the dB, if present
210func (dMgr *Manager) getDeviceReadOnly(ctx context.Context, id string) (*voltha.Device, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530211 logger.Debugw(ctx, "get-device-read-only", log.Fields{"device-id": id})
npujar467fe752020-01-16 20:17:45 +0530212 if agent := dMgr.getDeviceAgent(ctx, id); agent != nil {
Kent Hagermancba2f302020-07-28 13:37:36 -0400213 return agent.getDeviceReadOnly(ctx)
khenaidoo92e62c52018-10-03 14:02:54 -0400214 }
215 return nil, status.Errorf(codes.NotFound, "%s", id)
khenaidoob9203542018-09-17 22:56:37 -0400216}
217
Kent Hagerman2a07b862020-06-19 15:23:07 -0400218func (dMgr *Manager) listDevicePorts(ctx context.Context, id string) (map[uint32]*voltha.Port, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530219 logger.Debugw(ctx, "list-device-ports", log.Fields{"device-id": id})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400220 agent := dMgr.getDeviceAgent(ctx, id)
221 if agent == nil {
222 return nil, status.Errorf(codes.NotFound, "%s", id)
223 }
224 return agent.listDevicePorts(), nil
225}
226
npujar1d86a522019-11-14 17:11:16 +0530227// IsDeviceInCache returns true if device is found in the map
Kent Hagerman2b216042020-04-03 18:28:56 -0400228func (dMgr *Manager) IsDeviceInCache(id string) bool {
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400229 _, exist := dMgr.deviceAgents.Load(id)
khenaidoo297cd252019-02-07 22:10:23 -0500230 return exist
231}
232
Joey Armstrong393daca2023-07-06 08:47:54 -0400233// isParentDeviceExist checks whether device is already preprovisioned.
Kent Hagerman2b216042020-04-03 18:28:56 -0400234func (dMgr *Manager) isParentDeviceExist(ctx context.Context, newDevice *voltha.Device) (bool, error) {
Thomas Lee S51b5cb82019-10-14 14:49:34 +0530235 hostPort := newDevice.GetHostAndPort()
Kent Hagerman4f355f52020-03-30 16:01:33 -0400236 var devices []*voltha.Device
Kent Hagermanf5a67352020-04-30 15:15:26 -0400237 if err := dMgr.dProxy.List(ctx, &devices); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530238 logger.Errorw(ctx, "failed-to-list-devices-from-cluster-data-proxy", log.Fields{"error": err})
Thomas Lee Se5a44012019-11-07 20:32:24 +0530239 return false, err
240 }
Kent Hagerman4f355f52020-03-30 16:01:33 -0400241 for _, device := range devices {
242 if !device.Root {
243 continue
244 }
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530245
246 if hostPort != "" && hostPort == device.GetHostAndPort() {
Kent Hagerman4f355f52020-03-30 16:01:33 -0400247 return true, nil
248 }
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530249 if newDevice.MacAddress != "" && newDevice.MacAddress == device.MacAddress {
Kent Hagerman4f355f52020-03-30 16:01:33 -0400250 return true, nil
Thomas Lee S51b5cb82019-10-14 14:49:34 +0530251 }
252 }
Thomas Lee Se5a44012019-11-07 20:32:24 +0530253 return false, nil
Thomas Lee S51b5cb82019-10-14 14:49:34 +0530254}
255
Joey Armstrong393daca2023-07-06 08:47:54 -0400256// getDeviceFromModelretrieves the device data from the model.
Kent Hagerman2b216042020-04-03 18:28:56 -0400257func (dMgr *Manager) getDeviceFromModel(ctx context.Context, deviceID string) (*voltha.Device, error) {
Kent Hagerman4f355f52020-03-30 16:01:33 -0400258 device := &voltha.Device{}
Kent Hagermanf5a67352020-04-30 15:15:26 -0400259 if have, err := dMgr.dProxy.Get(ctx, deviceID, device); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000260 logger.Errorw(ctx, "failed-to-get-device-info-from-cluster-proxy", log.Fields{"error": err})
Thomas Lee Se5a44012019-11-07 20:32:24 +0530261 return nil, err
Kent Hagerman4f355f52020-03-30 16:01:33 -0400262 } else if !have {
263 return nil, status.Error(codes.NotFound, deviceID)
Thomas Lee Se5a44012019-11-07 20:32:24 +0530264 }
Kent Hagerman4f355f52020-03-30 16:01:33 -0400265
266 return device, nil
khenaidoo6d62c002019-05-15 21:57:03 -0400267}
268
npujar1d86a522019-11-14 17:11:16 +0530269// loadDevice loads the deviceID in memory, if not present
Kent Hagerman2b216042020-04-03 18:28:56 -0400270func (dMgr *Manager) loadDevice(ctx context.Context, deviceID string) (*Agent, error) {
npujar1d86a522019-11-14 17:11:16 +0530271 if deviceID == "" {
khenaidoo297cd252019-02-07 22:10:23 -0500272 return nil, status.Error(codes.InvalidArgument, "deviceId empty")
273 }
khenaidoo4c9e5592019-09-09 16:20:41 -0400274 var err error
275 var device *voltha.Device
276 dMgr.devicesLoadingLock.Lock()
npujar1d86a522019-11-14 17:11:16 +0530277 if _, exist := dMgr.deviceLoadingInProgress[deviceID]; !exist {
278 if !dMgr.IsDeviceInCache(deviceID) {
279 dMgr.deviceLoadingInProgress[deviceID] = []chan int{make(chan int, 1)}
khenaidoo4c9e5592019-09-09 16:20:41 -0400280 dMgr.devicesLoadingLock.Unlock()
281 // Proceed with the loading only if the device exist in the Model (could have been deleted)
npujar467fe752020-01-16 20:17:45 +0530282 if device, err = dMgr.getDeviceFromModel(ctx, deviceID); err == nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000283 logger.Debugw(ctx, "loading-device", log.Fields{"device-id": deviceID})
Himani Chawla4b4bd252021-11-08 15:59:40 +0530284 agent := newAgent(device, dMgr, dMgr.dbPath, dMgr.dProxy, dMgr.internalTimeout, dMgr.rpcTimeout, dMgr.flowTimeout)
khenaidoo7585a962021-06-10 16:15:38 -0400285 if _, err = agent.start(ctx, true, device); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530286 logger.Warnw(ctx, "failure-loading-device", log.Fields{"device-id": deviceID, "error": err})
khenaidoo4c9e5592019-09-09 16:20:41 -0400287 } else {
288 dMgr.addDeviceAgentToMap(agent)
289 }
290 } else {
Himani Chawlab4c25912020-11-12 17:16:38 +0530291 logger.Debugw(ctx, "device-is-not-in-model", log.Fields{"device-id": deviceID})
khenaidoo6d62c002019-05-15 21:57:03 -0400292 }
khenaidoo4c9e5592019-09-09 16:20:41 -0400293 // announce completion of task to any number of waiting channels
294 dMgr.devicesLoadingLock.Lock()
npujar1d86a522019-11-14 17:11:16 +0530295 if v, ok := dMgr.deviceLoadingInProgress[deviceID]; ok {
khenaidoo4c9e5592019-09-09 16:20:41 -0400296 for _, ch := range v {
297 close(ch)
298 }
npujar1d86a522019-11-14 17:11:16 +0530299 delete(dMgr.deviceLoadingInProgress, deviceID)
khenaidoo4c9e5592019-09-09 16:20:41 -0400300 }
301 dMgr.devicesLoadingLock.Unlock()
khenaidoo6d62c002019-05-15 21:57:03 -0400302 } else {
khenaidoo4c9e5592019-09-09 16:20:41 -0400303 dMgr.devicesLoadingLock.Unlock()
khenaidoo297cd252019-02-07 22:10:23 -0500304 }
khenaidoo4c9e5592019-09-09 16:20:41 -0400305 } else {
306 ch := make(chan int, 1)
npujar1d86a522019-11-14 17:11:16 +0530307 dMgr.deviceLoadingInProgress[deviceID] = append(dMgr.deviceLoadingInProgress[deviceID], ch)
khenaidoo4c9e5592019-09-09 16:20:41 -0400308 dMgr.devicesLoadingLock.Unlock()
309 // Wait for the channel to be closed, implying the process loading this device is done.
310 <-ch
khenaidoo297cd252019-02-07 22:10:23 -0500311 }
npujar1d86a522019-11-14 17:11:16 +0530312 if agent, ok := dMgr.deviceAgents.Load(deviceID); ok {
Kent Hagerman2b216042020-04-03 18:28:56 -0400313 return agent.(*Agent), nil
khenaidoo297cd252019-02-07 22:10:23 -0500314 }
npujar1d86a522019-11-14 17:11:16 +0530315 return nil, status.Errorf(codes.Aborted, "Error loading device %s", deviceID)
khenaidoo297cd252019-02-07 22:10:23 -0500316}
317
318// loadRootDeviceParentAndChildren loads the children and parents of a root device in memory
nikesh.krishnan1e3b98a2023-11-26 02:39:53 +0530319func (dMgr *Manager) loadRootDeviceParentAndChildren(ctx context.Context, device *voltha.Device) error {
divyadesaicb8b59d2020-08-18 09:55:47 +0000320 logger.Debugw(ctx, "loading-parent-and-children", log.Fields{"device-id": device.Id})
khenaidoo297cd252019-02-07 22:10:23 -0500321 if device.Root {
322 // Scenario A
323 if device.ParentId != "" {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400324 // Load logical device if needed.
npujar467fe752020-01-16 20:17:45 +0530325 if err := dMgr.logicalDeviceMgr.load(ctx, device.ParentId); err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000326 logger.Warnw(ctx, "failure-loading-logical-device", log.Fields{"logical-device-id": device.ParentId})
khenaidoo297cd252019-02-07 22:10:23 -0500327 }
328 } else {
divyadesaicb8b59d2020-08-18 09:55:47 +0000329 logger.Debugw(ctx, "no-parent-to-load", log.Fields{"device-id": device.Id})
khenaidoo297cd252019-02-07 22:10:23 -0500330 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400331 // Load all child devices, if needed
nikesh.krishnan1e3b98a2023-11-26 02:39:53 +0530332 childDeviceIds := dMgr.getAllChildDeviceIds(ctx, device.Id)
Kent Hagerman2a07b862020-06-19 15:23:07 -0400333 for childDeviceID := range childDeviceIds {
334 if _, err := dMgr.loadDevice(ctx, childDeviceID); err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000335 logger.Warnw(ctx, "failure-loading-device", log.Fields{"device-id": childDeviceID, "error": err})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400336 return err
khenaidoo297cd252019-02-07 22:10:23 -0500337 }
khenaidoo297cd252019-02-07 22:10:23 -0500338 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530339 logger.Debugw(ctx, "loaded-children", log.Fields{"device-id": device.Id, "num-children": len(childDeviceIds)})
khenaidoo297cd252019-02-07 22:10:23 -0500340 }
341 return nil
342}
343
344// load loads the deviceId in memory, if not present, and also loads its accompanying parents and children. Loading
345// in memory is for improved performance. It is not imperative that a device needs to be in memory when a request
346// acting on the device is received by the core. In such a scenario, the Core will load the device in memory first
347// and the proceed with the request.
Kent Hagerman2b216042020-04-03 18:28:56 -0400348func (dMgr *Manager) load(ctx context.Context, deviceID string) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000349 logger.Debug(ctx, "load...")
khenaidoo297cd252019-02-07 22:10:23 -0500350 // 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 -0400351 var dAgent *Agent
khenaidoo297cd252019-02-07 22:10:23 -0500352 var err error
npujar467fe752020-01-16 20:17:45 +0530353 if dAgent, err = dMgr.loadDevice(ctx, deviceID); err != nil {
khenaidoo297cd252019-02-07 22:10:23 -0500354 return err
355 }
356 // Get the loaded device details
Kent Hagermancba2f302020-07-28 13:37:36 -0400357 device, err := dAgent.getDeviceReadOnly(ctx)
khenaidoo442e7c72020-03-10 16:13:48 -0400358 if err != nil {
359 return err
360 }
khenaidoo297cd252019-02-07 22:10:23 -0500361
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530362 // If the device is in Pre-provisioning or getting deleted state stop here
363 if device.AdminState == voltha.AdminState_PREPROVISIONED || dAgent.isDeletionInProgress() {
khenaidoo297cd252019-02-07 22:10:23 -0500364 return nil
365 }
366
367 // Now we face two scenarios
368 if device.Root {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400369
khenaidoo297cd252019-02-07 22:10:23 -0500370 // Load all children as well as the parent of this device (logical_device)
nikesh.krishnan1e3b98a2023-11-26 02:39:53 +0530371 if err := dMgr.loadRootDeviceParentAndChildren(ctx, device); err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000372 logger.Warnw(ctx, "failure-loading-device-parent-and-children", log.Fields{"device-id": deviceID})
khenaidoo297cd252019-02-07 22:10:23 -0500373 return err
374 }
divyadesaicb8b59d2020-08-18 09:55:47 +0000375 logger.Debugw(ctx, "successfully-loaded-parent-and-children", log.Fields{"device-id": deviceID})
Andrey Pozolotin34dd63f2021-05-31 21:26:40 +0300376 } else if device.ParentId != "" {
khenaidoo297cd252019-02-07 22:10:23 -0500377 // Scenario B - use the parentId of that device (root device) to trigger the loading
Andrey Pozolotin34dd63f2021-05-31 21:26:40 +0300378 return dMgr.load(ctx, device.ParentId)
khenaidoo297cd252019-02-07 22:10:23 -0500379 }
Andrey Pozolotin34dd63f2021-05-31 21:26:40 +0300380
khenaidoo297cd252019-02-07 22:10:23 -0500381 return nil
382}
383
khenaidooba6b6c42019-08-02 09:11:56 -0400384// adapterRestarted is invoked whenever an adapter is restarted
Kent Hagerman2b216042020-04-03 18:28:56 -0400385func (dMgr *Manager) adapterRestarted(ctx context.Context, adapter *voltha.Adapter) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530386 logger.Debugw(ctx, "adapter-restarted", log.Fields{"adapter-id": adapter.Id, "vendor": adapter.Vendor,
Girish Gowdra11ddb232022-05-26 12:19:59 -0700387 "current-replica": adapter.CurrentReplica, "total-replicas": adapter.TotalReplicas,
388 "restarted-endpoint": adapter.Endpoint, "current-version": adapter.Version})
khenaidooba6b6c42019-08-02 09:11:56 -0400389
khenaidood948f772021-08-11 17:49:24 -0400390 numberOfDevicesToReconcile := 0
391 dMgr.deviceAgents.Range(func(key, value interface{}) bool {
392 deviceAgent, ok := value.(*Agent)
393 if ok && deviceAgent.adapterEndpoint == adapter.Endpoint {
394 // Before reconciling, abort in-process request
395 if err := deviceAgent.abortAllProcessing(utils.WithNewSpanAndRPCMetadataContext(ctx, "AbortProcessingOnRestart")); err == nil {
396 logger.Debugw(ctx, "reconciling-device",
397 log.Fields{
398 "device-id": deviceAgent.deviceID,
399 "root-device": deviceAgent.isRootDevice,
400 "restarted-endpoint": adapter.Endpoint,
401 "device-type": deviceAgent.deviceType,
402 "adapter-type": adapter.Type,
403 })
nikesh.krishnan95142d52023-02-24 15:32:11 +0530404 deviceAgent.ReconcileDevice(utils.WithNewSpanAndRPCMetadataContext(ctx, "ReconcileDevice"))
khenaidood948f772021-08-11 17:49:24 -0400405 numberOfDevicesToReconcile++
406 } else {
407 logger.Errorw(ctx, "failed-aborting-exisiting-processing", log.Fields{"error": err})
khenaidooba6b6c42019-08-02 09:11:56 -0400408 }
409 }
khenaidood948f772021-08-11 17:49:24 -0400410 return true
411 })
412 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 -0400413 return nil
414}
415
Kent Hagerman2b216042020-04-03 18:28:56 -0400416func (dMgr *Manager) UpdateDeviceUsingAdapterData(ctx context.Context, device *voltha.Device) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530417 logger.Debugw(ctx, "update-device-using-adapter-data", log.Fields{"device-id": device.Id, "device": device})
npujar467fe752020-01-16 20:17:45 +0530418 if agent := dMgr.getDeviceAgent(ctx, device.Id); agent != nil {
419 return agent.updateDeviceUsingAdapterData(ctx, device)
khenaidoob9203542018-09-17 22:56:37 -0400420 }
421 return status.Errorf(codes.NotFound, "%s", device.Id)
422}
423
khenaidoo0db4c812020-05-27 15:27:30 -0400424func (dMgr *Manager) addPeerPort(ctx context.Context, deviceID string, port *voltha.Port) error {
425 meAsPeer := &voltha.Port_PeerPort{DeviceId: deviceID, PortNo: port.PortNo}
426 for _, peerPort := range port.Peers {
427 if agent := dMgr.getDeviceAgent(ctx, peerPort.DeviceId); agent != nil {
428 if err := agent.addPeerPort(ctx, meAsPeer); err != nil {
429 return err
430 }
431 }
432 }
433 // Notify the logical device manager to setup a logical port, if needed. If the added port is an NNI or UNI
434 // then a logical port will be added to the logical device and the device route generated. If the port is a
435 // PON port then only the device graph will be generated.
Kent Hagermancba2f302020-07-28 13:37:36 -0400436 device, err := dMgr.getDeviceReadOnly(ctx, deviceID)
khenaidoo0db4c812020-05-27 15:27:30 -0400437 if err != nil {
438 return err
439 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400440 ports, err := dMgr.listDevicePorts(ctx, deviceID)
441 if err != nil {
442 return err
443 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530444 subCtx := utils.WithSpanAndRPCMetadataFromContext(ctx)
445
446 if err = dMgr.logicalDeviceMgr.updateLogicalPort(subCtx, device, ports, port); err != nil {
khenaidoo0db4c812020-05-27 15:27:30 -0400447 return err
448 }
449 return nil
450}
451
Kent Hagerman2b216042020-04-03 18:28:56 -0400452func (dMgr *Manager) AddPort(ctx context.Context, deviceID string, port *voltha.Port) error {
npujar467fe752020-01-16 20:17:45 +0530453 agent := dMgr.getDeviceAgent(ctx, deviceID)
npujar1d86a522019-11-14 17:11:16 +0530454 if agent != nil {
npujar467fe752020-01-16 20:17:45 +0530455 if err := agent.addPort(ctx, port); err != nil {
khenaidoo92e62c52018-10-03 14:02:54 -0400456 return err
457 }
khenaidoo0db4c812020-05-27 15:27:30 -0400458 // Setup peer ports in its own routine
nikesh.krishnan95142d52023-02-24 15:32:11 +0530459 if err := dMgr.addPeerPort(ctx, deviceID, port); err != nil {
460 logger.Errorw(ctx, "unable-to-add-peer-port", log.Fields{"error": err, "device-id": deviceID})
461 }
khenaidoo92e62c52018-10-03 14:02:54 -0400462 return nil
khenaidoob9203542018-09-17 22:56:37 -0400463 }
npujar1d86a522019-11-14 17:11:16 +0530464 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoob9203542018-09-17 22:56:37 -0400465}
466
Elia Battiston509fdc72022-01-04 13:28:09 +0100467func (dMgr *Manager) canAdapterRequestProceed(ctx context.Context, deviceID string) error {
468 agent := dMgr.getDeviceAgent(ctx, deviceID)
469 if agent == nil {
470 logger.Errorw(ctx, "device-nil", log.Fields{"device-id": deviceID})
471 return status.Errorf(codes.NotFound, "device-nil-for-%s", deviceID)
472 }
473 if !agent.isAdapterConnectionUp(ctx) {
474 return status.Errorf(codes.Unavailable, "adapter-connection-down-for-%s", deviceID)
475 }
476 if err := agent.canDeviceRequestProceed(ctx); err != nil {
477 return err
478 }
479 // Perform the same checks for parent device
480 if !agent.isRootDevice {
481 parentDeviceAgent := dMgr.getDeviceAgent(ctx, agent.parentID)
482 if parentDeviceAgent == nil {
483 logger.Errorw(ctx, "parent-device-adapter-nil", log.Fields{"parent-id": agent.parentID})
484 return status.Errorf(codes.NotFound, "parent-device-adapter-nil-for-%s", deviceID)
khenaidood948f772021-08-11 17:49:24 -0400485 }
Elia Battiston509fdc72022-01-04 13:28:09 +0100486 if err := parentDeviceAgent.canDeviceRequestProceed(ctx); err != nil {
khenaidood948f772021-08-11 17:49:24 -0400487 return err
488 }
489 }
Elia Battiston509fdc72022-01-04 13:28:09 +0100490
491 return nil
492}
493
494func (dMgr *Manager) canMultipleAdapterRequestProceed(ctx context.Context, deviceIDs []string) error {
495 if len(deviceIDs) == 0 {
khenaidood948f772021-08-11 17:49:24 -0400496 return status.Error(codes.Unavailable, "adapter(s)-not-ready")
497 }
Elia Battiston509fdc72022-01-04 13:28:09 +0100498
499 for _, deviceID := range deviceIDs {
500 if err := dMgr.canAdapterRequestProceed(ctx, deviceID); err != nil {
501 return err
502 }
503 }
504
khenaidood948f772021-08-11 17:49:24 -0400505 return nil
506}
507
khenaidoo9beaaf12021-10-19 17:32:01 -0400508func (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 +0530509 logger.Debugw(ctx, "add-flows-and-groups", log.Fields{"device-id": deviceID, "groups:": groups, "flow-metadata": flowMetadata})
npujar467fe752020-01-16 20:17:45 +0530510 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
511 return agent.addFlowsAndGroups(ctx, flows, groups, flowMetadata)
khenaidoo0458db62019-06-20 08:50:36 -0400512 }
npujar1d86a522019-11-14 17:11:16 +0530513 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo0458db62019-06-20 08:50:36 -0400514}
515
khenaidoo787224a2020-04-16 18:08:47 -0400516// deleteParentFlows removes flows from the parent device based on specific attributes
khenaidoo9beaaf12021-10-19 17:32:01 -0400517func (dMgr *Manager) deleteParentFlows(ctx context.Context, deviceID string, uniPort uint32, metadata *ofp.FlowMetadata) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530518 logger.Debugw(ctx, "delete-parent-flows", log.Fields{"device-id": deviceID, "uni-port": uniPort, "metadata": metadata})
khenaidoo787224a2020-04-16 18:08:47 -0400519 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400520 if !agent.isRootDevice {
khenaidoo787224a2020-04-16 18:08:47 -0400521 return status.Errorf(codes.FailedPrecondition, "not-a-parent-device-%s", deviceID)
522 }
523 return agent.filterOutFlows(ctx, uniPort, metadata)
524 }
525 return status.Errorf(codes.NotFound, "%s", deviceID)
526}
527
khenaidoo9beaaf12021-10-19 17:32:01 -0400528func (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 +0530529 logger.Debugw(ctx, "delete-flows-and-groups", log.Fields{"device-id": deviceID})
npujar467fe752020-01-16 20:17:45 +0530530 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
531 return agent.deleteFlowsAndGroups(ctx, flows, groups, flowMetadata)
khenaidoo0458db62019-06-20 08:50:36 -0400532 }
npujar1d86a522019-11-14 17:11:16 +0530533 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo0458db62019-06-20 08:50:36 -0400534}
535
khenaidoo9beaaf12021-10-19 17:32:01 -0400536func (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 +0530537 logger.Debugw(ctx, "update-flows-and-groups", log.Fields{"device-id": deviceID})
npujar467fe752020-01-16 20:17:45 +0530538 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
539 return agent.updateFlowsAndGroups(ctx, flows, groups, flowMetadata)
khenaidoo19d7b632018-10-30 10:49:50 -0400540 }
npujar1d86a522019-11-14 17:11:16 +0530541 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo19d7b632018-10-30 10:49:50 -0400542}
543
Kent Hagerman2b216042020-04-03 18:28:56 -0400544// InitPmConfigs initialize the pm configs as defined by the adapter.
545func (dMgr *Manager) InitPmConfigs(ctx context.Context, deviceID string, pmConfigs *voltha.PmConfigs) error {
khenaidoob3127472019-07-24 21:04:55 -0400546 if pmConfigs.Id == "" {
547 return status.Errorf(codes.FailedPrecondition, "invalid-device-Id")
548 }
npujar467fe752020-01-16 20:17:45 +0530549 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
550 return agent.initPmConfigs(ctx, pmConfigs)
khenaidoob9203542018-09-17 22:56:37 -0400551 }
npujar1d86a522019-11-14 17:11:16 +0530552 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoob9203542018-09-17 22:56:37 -0400553}
554
khenaidoo9beaaf12021-10-19 17:32:01 -0400555func (dMgr *Manager) getSwitchCapability(ctx context.Context, deviceID string) (*ca.SwitchCapability, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530556 logger.Debugw(ctx, "get-switch-capability", log.Fields{"device-id": deviceID})
npujar467fe752020-01-16 20:17:45 +0530557 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
khenaidoob9203542018-09-17 22:56:37 -0400558 return agent.getSwitchCapability(ctx)
559 }
npujar1d86a522019-11-14 17:11:16 +0530560 return nil, status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoob9203542018-09-17 22:56:37 -0400561}
562
Kent Hagerman2b216042020-04-03 18:28:56 -0400563func (dMgr *Manager) UpdateDeviceStatus(ctx context.Context, deviceID string, operStatus voltha.OperStatus_Types, connStatus voltha.ConnectStatus_Types) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530564 logger.Debugw(ctx, "update-device-status", log.Fields{"device-id": deviceID, "oper-status": operStatus, "conn-status": connStatus})
npujar467fe752020-01-16 20:17:45 +0530565 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
566 return agent.updateDeviceStatus(ctx, operStatus, connStatus)
khenaidoo92e62c52018-10-03 14:02:54 -0400567 }
npujar1d86a522019-11-14 17:11:16 +0530568 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo92e62c52018-10-03 14:02:54 -0400569}
570
Kent Hagerman2b216042020-04-03 18:28:56 -0400571func (dMgr *Manager) UpdateChildrenStatus(ctx context.Context, deviceID string, operStatus voltha.OperStatus_Types, connStatus voltha.ConnectStatus_Types) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530572 logger.Debugw(ctx, "update-children-status", log.Fields{"parent-device-id": deviceID, "oper-status": operStatus, "conn-status": connStatus})
nikesh.krishnan1e3b98a2023-11-26 02:39:53 +0530573 for childDeviceID := range dMgr.getAllChildDeviceIds(ctx, deviceID) {
npujar467fe752020-01-16 20:17:45 +0530574 if agent := dMgr.getDeviceAgent(ctx, childDeviceID); agent != nil {
nikesh.krishnan1e3b98a2023-11-26 02:39:53 +0530575 if err := agent.updateDeviceStatus(ctx, operStatus, connStatus); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530576 return status.Errorf(codes.Aborted, "childDevice:%s, error:%s", childDeviceID, err.Error())
khenaidoo4d4802d2018-10-04 21:59:49 -0400577 }
578 }
579 }
580 return nil
581}
582
Kent Hagerman2b216042020-04-03 18:28:56 -0400583func (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 +0530584 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 +0530585 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
586 if err := agent.updatePortState(ctx, portType, portNo, operStatus); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530587 logger.Errorw(ctx, "updating-port-state-failed", log.Fields{"device-id": deviceID, "port-no": portNo, "error": err})
khenaidoo171b98e2019-10-31 11:48:15 -0400588 return err
589 }
590 // Notify the logical device manager to change the port state
Mahir Gunyel18fa0c92020-03-06 13:34:04 -0800591 // Do this for NNI and UNIs only. PON ports are not known by logical device
592 if portType == voltha.Port_ETHERNET_NNI || portType == voltha.Port_ETHERNET_UNI {
nikesh.krishnan95142d52023-02-24 15:32:11 +0530593 err := dMgr.logicalDeviceMgr.updatePortState(ctx, deviceID, portNo, operStatus)
594 if err != nil {
595 // While we want to handle (catch) and log when
596 // an update to a port was not able to be
597 // propagated to the logical port, we can report
598 // it as a warning and not an error because it
599 // doesn't stop or modify processing.
600 // TODO: VOL-2707
601 logger.Warnw(ctx, "unable-to-update-logical-port-state", log.Fields{"error": err})
602 }
Mahir Gunyel18fa0c92020-03-06 13:34:04 -0800603 }
khenaidoo442e7c72020-03-10 16:13:48 -0400604 return nil
khenaidoob9203542018-09-17 22:56:37 -0400605 }
npujar1d86a522019-11-14 17:11:16 +0530606 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoob9203542018-09-17 22:56:37 -0400607}
608
Joey Armstrong393daca2023-07-06 08:47:54 -0400609// UpdatePortsState updates all ports on the device
Kent Hagerman2a07b862020-06-19 15:23:07 -0400610func (dMgr *Manager) UpdatePortsState(ctx context.Context, deviceID string, portTypeFilter uint32, state voltha.OperStatus_Types) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530611 logger.Debugw(ctx, "update-ports-state", log.Fields{"device-id": deviceID})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400612 agent := dMgr.getDeviceAgent(ctx, deviceID)
613 if agent == nil {
614 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo3ab34882019-05-02 21:33:30 -0400615 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400616 if state != voltha.OperStatus_ACTIVE && state != voltha.OperStatus_UNKNOWN {
617 return status.Error(codes.Unimplemented, "state-change-not-implemented")
618 }
619 if err := agent.updatePortsOperState(ctx, portTypeFilter, state); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530620 logger.Warnw(ctx, "update-ports-state-failed", log.Fields{"device-id": deviceID, "error": err})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400621 return err
622 }
623 return nil
khenaidoo3ab34882019-05-02 21:33:30 -0400624}
625
Kent Hagerman2b216042020-04-03 18:28:56 -0400626func (dMgr *Manager) packetOut(ctx context.Context, deviceID string, outPort uint32, packet *ofp.OfpPacketOut) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530627 logger.Debugw(ctx, "packet-out", log.Fields{"device-id": deviceID, "out-port": outPort})
npujar467fe752020-01-16 20:17:45 +0530628 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
629 return agent.packetOut(ctx, outPort, packet)
khenaidoofdbad6e2018-11-06 22:26:38 -0500630 }
npujar1d86a522019-11-14 17:11:16 +0530631 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoofdbad6e2018-11-06 22:26:38 -0500632}
633
npujar1d86a522019-11-14 17:11:16 +0530634// PacketIn receives packet from adapter
Kent Hagerman2b216042020-04-03 18:28:56 -0400635func (dMgr *Manager) PacketIn(ctx context.Context, deviceID string, port uint32, transactionID string, packet []byte) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530636 logger.Debugw(ctx, "packet-in", log.Fields{"device-id": deviceID, "port": port})
khenaidoofdbad6e2018-11-06 22:26:38 -0500637 // Get the logical device Id based on the deviceId
638 var device *voltha.Device
639 var err error
Kent Hagermancba2f302020-07-28 13:37:36 -0400640 if device, err = dMgr.getDeviceReadOnly(ctx, deviceID); err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000641 logger.Errorw(ctx, "device-not-found", log.Fields{"device-id": deviceID})
khenaidoofdbad6e2018-11-06 22:26:38 -0500642 return err
643 }
khenaidoo43c82122018-11-22 18:38:28 -0500644 if !device.Root {
divyadesaicb8b59d2020-08-18 09:55:47 +0000645 logger.Errorw(ctx, "device-not-root", log.Fields{"device-id": deviceID})
npujar1d86a522019-11-14 17:11:16 +0530646 return status.Errorf(codes.FailedPrecondition, "%s", deviceID)
khenaidoofdbad6e2018-11-06 22:26:38 -0500647 }
648
khenaidood948f772021-08-11 17:49:24 -0400649 if err := dMgr.logicalDeviceMgr.packetIn(ctx, device.ParentId, port, packet); err != nil {
khenaidoofdbad6e2018-11-06 22:26:38 -0500650 return err
651 }
652 return nil
653}
654
Kent Hagerman2b216042020-04-03 18:28:56 -0400655func (dMgr *Manager) setParentID(ctx context.Context, device *voltha.Device, parentID string) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530656 logger.Debugw(ctx, "set-parent-id", log.Fields{"device-id": device.Id, "parent-id": parentID})
npujar467fe752020-01-16 20:17:45 +0530657 if agent := dMgr.getDeviceAgent(ctx, device.Id); agent != nil {
658 return agent.setParentID(ctx, device, parentID)
khenaidooad06fd72019-10-28 12:26:05 -0400659 }
660 return status.Errorf(codes.NotFound, "%s", device.Id)
661}
662
Kent Hagerman2b216042020-04-03 18:28:56 -0400663func (dMgr *Manager) getParentDevice(ctx context.Context, childDevice *voltha.Device) *voltha.Device {
khenaidoo92e62c52018-10-03 14:02:54 -0400664 // Sanity check
665 if childDevice.Root {
666 // childDevice is the parent device
667 return childDevice
668 }
Kent Hagermancba2f302020-07-28 13:37:36 -0400669 parentDevice, _ := dMgr.getDeviceReadOnly(ctx, childDevice.ParentId)
khenaidoo92e62c52018-10-03 14:02:54 -0400670 return parentDevice
671}
672
khenaidoo4d4802d2018-10-04 21:59:49 -0400673/*
674All the functions below are callback functions where they are invoked with the latest and previous data. We can
675therefore use the data as is without trying to get the latest from the model.
676*/
677
Joey Armstrong393daca2023-07-06 08:47:54 -0400678// DisableAllChildDevices is invoked as a callback when the parent device is disabled
Kent Hagerman2b216042020-04-03 18:28:56 -0400679func (dMgr *Manager) DisableAllChildDevices(ctx context.Context, parentCurrDevice *voltha.Device) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530680 logger.Debug(ctx, "disable-all-child-devices")
nikesh.krishnan1e3b98a2023-11-26 02:39:53 +0530681 for childDeviceID := range dMgr.getAllChildDeviceIds(ctx, parentCurrDevice.Id) {
npujar467fe752020-01-16 20:17:45 +0530682 if agent := dMgr.getDeviceAgent(ctx, childDeviceID); agent != nil {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400683 if err := agent.disableDevice(ctx); err != nil {
khenaidooe132f522020-03-20 15:23:15 -0400684 // Just log the error - this error happens only if the child device was already in deleted state.
divyadesaicb8b59d2020-08-18 09:55:47 +0000685 logger.Errorw(ctx, "failure-disable-device", log.Fields{"device-id": childDeviceID, "error": err.Error()})
khenaidoo92e62c52018-10-03 14:02:54 -0400686 }
687 }
688 }
689 return nil
690}
691
Joey Armstrong393daca2023-07-06 08:47:54 -0400692// getAllChildDeviceIds is a helper method to get all the child device IDs from the device passed as parameter
nikesh.krishnan1e3b98a2023-11-26 02:39:53 +0530693func (dMgr *Manager) getAllChildDeviceIds(ctx context.Context, parentDeviceID string) map[string]struct{} {
Himani Chawlab4c25912020-11-12 17:16:38 +0530694 logger.Debug(ctx, "get-all-child-device-ids")
nikesh.krishnan1e3b98a2023-11-26 02:39:53 +0530695 childDeviceIds := make(map[string]struct{})
696 dMgr.deviceAgents.Range(func(_, value interface{}) bool {
697 if value.(*Agent).device.ParentId == parentDeviceID && !value.(*Agent).device.Root {
698 childDeviceIds[value.(*Agent).device.Id] = struct{}{}
khenaidoo92e62c52018-10-03 14:02:54 -0400699 }
nikesh.krishnan1e3b98a2023-11-26 02:39:53 +0530700 return true
701 })
702 logger.Debugw(ctx, "returning-getAllChildDeviceIds.", log.Fields{"childDeviceIds": childDeviceIds})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400703 return childDeviceIds
khenaidoo92e62c52018-10-03 14:02:54 -0400704}
705
Joey Armstrong393daca2023-07-06 08:47:54 -0400706// GgtAllChildDevices is a helper method to get all the child device IDs from the device passed as parameter
khenaidood948f772021-08-11 17:49:24 -0400707func (dMgr *Manager) getAllChildDevices(ctx context.Context, parentDeviceID string) (*voltha.Devices, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530708 logger.Debugw(ctx, "get-all-child-devices", log.Fields{"parent-device-id": parentDeviceID})
nikesh.krishnan1e3b98a2023-11-26 02:39:53 +0530709 childDevices := make([]*voltha.Device, 0)
710 for deviceID := range dMgr.getAllChildDeviceIds(ctx, parentDeviceID) {
711 if d, e := dMgr.getDeviceReadOnly(ctx, deviceID); e == nil && d != nil {
712 childDevices = append(childDevices, d)
khenaidoo297cd252019-02-07 22:10:23 -0500713 }
khenaidoo297cd252019-02-07 22:10:23 -0500714 }
nikesh.krishnan1e3b98a2023-11-26 02:39:53 +0530715 return &voltha.Devices{Items: childDevices}, nil
khenaidoo297cd252019-02-07 22:10:23 -0500716}
717
Rohan Agrawal31f21802020-06-12 05:38:46 +0000718func (dMgr *Manager) NotifyInvalidTransition(ctx context.Context, device *voltha.Device) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530719 logger.Errorw(ctx, "notify-invalid-transition", log.Fields{
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500720 "device": device.Id,
721 "curr-admin-state": device.AdminState,
722 "curr-oper-state": device.OperStatus,
723 "curr-conn-state": device.ConnectStatus,
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400724 })
khenaidoo0a822f92019-05-08 15:15:57 -0400725 //TODO: notify over kafka?
726 return nil
727}
728
npujar1d86a522019-11-14 17:11:16 +0530729// UpdateDeviceAttribute updates value of particular device attribute
Kent Hagerman2b216042020-04-03 18:28:56 -0400730func (dMgr *Manager) UpdateDeviceAttribute(ctx context.Context, deviceID string, attribute string, value interface{}) {
npujar1d86a522019-11-14 17:11:16 +0530731 if agent, ok := dMgr.deviceAgents.Load(deviceID); ok {
Kent Hagerman2b216042020-04-03 18:28:56 -0400732 agent.(*Agent).updateDeviceAttribute(ctx, attribute, value)
khenaidoob9203542018-09-17 22:56:37 -0400733 }
734}
735
npujar1d86a522019-11-14 17:11:16 +0530736// GetParentDeviceID returns parent device id, either from memory or from the dB, if present
Kent Hagerman2b216042020-04-03 18:28:56 -0400737func (dMgr *Manager) GetParentDeviceID(ctx context.Context, deviceID string) string {
Kent Hagermancba2f302020-07-28 13:37:36 -0400738 if device, _ := dMgr.getDeviceReadOnly(ctx, deviceID); device != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530739 logger.Infow(ctx, "get-parent-device-id", log.Fields{"device-id": device.Id, "parent-id": device.ParentId})
khenaidoo4c9e5592019-09-09 16:20:41 -0400740 return device.ParentId
khenaidoob9203542018-09-17 22:56:37 -0400741 }
khenaidoo4c9e5592019-09-09 16:20:41 -0400742 return ""
khenaidoob9203542018-09-17 22:56:37 -0400743}
serkant.uluderya334479d2019-04-10 08:26:15 -0700744
Kent Hagerman2b216042020-04-03 18:28:56 -0400745func (dMgr *Manager) UpdateDeviceReason(ctx context.Context, deviceID string, reason string) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530746 logger.Debugw(ctx, "update-device-reason", log.Fields{"device-id": deviceID, "reason": reason})
npujar467fe752020-01-16 20:17:45 +0530747 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
748 return agent.updateDeviceReason(ctx, reason)
Mahir Gunyelfdee9212019-10-16 16:52:21 -0700749 }
npujar1d86a522019-11-14 17:11:16 +0530750 return status.Errorf(codes.NotFound, "%s", deviceID)
Mahir Gunyelfdee9212019-10-16 16:52:21 -0700751}
kesavandbc2d1622020-01-21 00:42:01 -0500752
Himani Chawlab4c25912020-11-12 17:16:38 +0530753func (dMgr *Manager) SendRPCEvent(ctx context.Context, id string, rpcEvent *voltha.RPCEvent,
754 category voltha.EventCategory_Types, subCategory *voltha.EventSubCategory_Types, raisedTs int64) {
755 //TODO Instead of directly sending to the kafka bus, queue the message and send it asynchronously
Mahir Gunyelb0343bf2021-05-11 14:14:26 -0700756 dMgr.Agent.SendRPCEvent(ctx, id, rpcEvent, category, subCategory, raisedTs)
Himani Chawlab4c25912020-11-12 17:16:38 +0530757}
Manindera496f852021-02-22 09:57:56 +0530758
khenaidood948f772021-08-11 17:49:24 -0400759func (dMgr *Manager) GetTransientState(ctx context.Context, id string) (core.DeviceTransientState_Types, error) {
Manindera496f852021-02-22 09:57:56 +0530760 agent := dMgr.getDeviceAgent(ctx, id)
761 if agent == nil {
khenaidood948f772021-08-11 17:49:24 -0400762 return core.DeviceTransientState_NONE, status.Errorf(codes.NotFound, "%s", id)
Manindera496f852021-02-22 09:57:56 +0530763 }
764 return agent.getTransientState(), nil
765}
ssiddiquif076cb82021-04-23 10:47:04 +0530766
ssiddiquif076cb82021-04-23 10:47:04 +0530767func (dMgr *Manager) validateImageDownloadRequest(request *voltha.DeviceImageDownloadRequest) error {
768 if request == nil || request.Image == nil || len(request.DeviceId) == 0 {
769 return status.Errorf(codes.InvalidArgument, "invalid argument")
770 }
771
772 for _, deviceID := range request.DeviceId {
773 if deviceID == nil {
774 return status.Errorf(codes.InvalidArgument, "id is nil")
775 }
776 }
777 return nil
778}
779
780func (dMgr *Manager) validateImageRequest(request *voltha.DeviceImageRequest) error {
Elia Battiston58d1c062022-02-08 11:54:27 +0100781 if request == nil {
ssiddiquif076cb82021-04-23 10:47:04 +0530782 return status.Errorf(codes.InvalidArgument, "invalid argument")
783 }
784
785 for _, deviceID := range request.DeviceId {
786 if deviceID == nil {
787 return status.Errorf(codes.InvalidArgument, "id is nil")
788 }
789 }
790
791 return nil
792}
793
794func (dMgr *Manager) validateDeviceImageResponse(response *voltha.DeviceImageResponse) error {
795 if response == nil || len(response.GetDeviceImageStates()) == 0 || response.GetDeviceImageStates()[0] == nil {
796 return status.Errorf(codes.Internal, "invalid-response-from-adapter")
797 }
798
799 return nil
800}
801
802func (dMgr *Manager) waitForAllResponses(ctx context.Context, opName string, respCh chan []*voltha.DeviceImageState, expectedResps int) (*voltha.DeviceImageResponse, error) {
803 response := &voltha.DeviceImageResponse{}
804 respCount := 0
805 for {
806 select {
807 case resp, ok := <-respCh:
808 if !ok {
809 logger.Errorw(ctx, opName+"-failed", log.Fields{"error": "channel-closed"})
810 return response, status.Errorf(codes.Aborted, "channel-closed")
811 }
812
813 if resp != nil {
814 logger.Debugw(ctx, opName+"-result", log.Fields{"image-state": resp[0].GetImageState(), "device-id": resp[0].GetDeviceId()})
815 response.DeviceImageStates = append(response.DeviceImageStates, resp...)
816 }
817
818 respCount++
819
820 //check whether all responses received, if so, sent back the collated response
821 if respCount == expectedResps {
822 return response, nil
823 }
824 continue
825 case <-ctx.Done():
826 return nil, status.Errorf(codes.Aborted, opName+"-failed-%s", ctx.Err())
827 }
828 }
829}
Maninder0aabf0c2021-03-17 14:55:14 +0530830
831func (dMgr *Manager) ReconcilingCleanup(ctx context.Context, device *voltha.Device) error {
832 agent := dMgr.getDeviceAgent(ctx, device.Id)
833 if agent == nil {
834 logger.Errorf(ctx, "Not able to get device agent.")
835 return status.Errorf(codes.NotFound, "Not able to get device agent for device : %s", device.Id)
836 }
837 err := agent.reconcilingCleanup(ctx)
838 if err != nil {
839 logger.Errorf(ctx, err.Error())
840 return status.Errorf(codes.Internal, err.Error())
841 }
842 return nil
843}
khenaidood948f772021-08-11 17:49:24 -0400844
845func (dMgr *Manager) adapterRestartedHandler(ctx context.Context, endpoint string) error {
846 // Get the adapter corresponding to that endpoint
847 if a, _ := dMgr.adapterMgr.GetAdapterWithEndpoint(ctx, endpoint); a != nil {
Girish Gowdra11ddb232022-05-26 12:19:59 -0700848 if rollingUpdate, _ := dMgr.adapterMgr.GetRollingUpdate(ctx, endpoint); rollingUpdate {
849 dMgr.adapterMgr.RegisterOnRxStreamCloseChMap(ctx, endpoint)
850 // Blocking call. wait for the old adapters rx stream to close.
851 // That is a signal that the old adapter is completely down
852 dMgr.adapterMgr.WaitOnRxStreamCloseCh(ctx, endpoint)
853 dMgr.adapterMgr.DeleteRollingUpdate(ctx, endpoint)
854 // In case of rolling update we need to start the connection towards the new adapter instance now
855 if err := dMgr.adapterMgr.StartAdapterWithEndPoint(ctx, endpoint); err != nil {
856 return err
857 }
858 }
khenaidood948f772021-08-11 17:49:24 -0400859 return dMgr.adapterRestarted(ctx, a)
860 }
861 logger.Errorw(ctx, "restarted-adapter-not-found", log.Fields{"endpoint": endpoint})
862 return fmt.Errorf("restarted adapter at endpoint %s not found", endpoint)
863}