blob: b48e6036be195fc68c7c60de566718d9b132b00f [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
Himani Chawla4b4bd252021-11-08 15:59:40 +053057 flowTimeout time.Duration
khenaidoo4c9e5592019-09-09 16:20:41 -040058 devicesLoadingLock sync.RWMutex
59 deviceLoadingInProgress map[string][]chan int
Maninder0aabf0c2021-03-17 14:55:14 +053060 config *config.RWCoreFlags
khenaidooa46458b2021-12-15 16:50:44 -050061 doneCh chan struct{}
khenaidoob9203542018-09-17 22:56:37 -040062}
63
Mahir Gunyel03de0d32020-06-03 01:36:59 -070064//NewManagers creates the Manager and the Logical Manager.
khenaidood948f772021-08-11 17:49:24 -040065func NewManagers(dbPath *model.Path, adapterMgr *adapter.Manager, cf *config.RWCoreFlags, coreInstanceID string, eventProxy *events.EventProxy) (*Manager, *LogicalManager) {
Kent Hagerman2b216042020-04-03 18:28:56 -040066 deviceMgr := &Manager{
Kent Hagerman2b216042020-04-03 18:28:56 -040067 rootDevices: make(map[string]bool),
Kent Hagerman2b216042020-04-03 18:28:56 -040068 coreInstanceID: coreInstanceID,
Mahir Gunyel03de0d32020-06-03 01:36:59 -070069 dbPath: dbPath,
70 dProxy: dbPath.Proxy("devices"),
Kent Hagerman2b216042020-04-03 18:28:56 -040071 adapterMgr: adapterMgr,
khenaidood948f772021-08-11 17:49:24 -040072 internalTimeout: cf.InternalTimeout,
73 rpcTimeout: cf.RPCTimeout,
Himani Chawla4b4bd252021-11-08 15:59:40 +053074 flowTimeout: cf.FlowTimeout,
Maninder0aabf0c2021-03-17 14:55:14 +053075 Agent: event.NewAgent(eventProxy, coreInstanceID, cf.VolthaStackID),
Kent Hagerman2b216042020-04-03 18:28:56 -040076 deviceLoadingInProgress: make(map[string][]chan int),
Maninder0aabf0c2021-03-17 14:55:14 +053077 config: cf,
khenaidooa46458b2021-12-15 16:50:44 -050078 doneCh: make(chan struct{}),
Kent Hagerman2b216042020-04-03 18:28:56 -040079 }
Kent Hagerman6031aad2020-07-29 16:36:33 -040080 deviceMgr.stateTransitions = state.NewTransitionMap(deviceMgr)
Kent Hagerman2f0d0552020-04-23 17:28:52 -040081
Kent Hagerman2b216042020-04-03 18:28:56 -040082 logicalDeviceMgr := &LogicalManager{
Maninder0aabf0c2021-03-17 14:55:14 +053083 Manager: event.NewManager(eventProxy, coreInstanceID, cf.VolthaStackID),
Kent Hagerman2b216042020-04-03 18:28:56 -040084 deviceMgr: deviceMgr,
Mahir Gunyel03de0d32020-06-03 01:36:59 -070085 dbPath: dbPath,
86 ldProxy: dbPath.Proxy("logical_devices"),
khenaidood948f772021-08-11 17:49:24 -040087 internalTimeout: cf.InternalTimeout,
Kent Hagerman2b216042020-04-03 18:28:56 -040088 logicalDeviceLoadingInProgress: make(map[string][]chan int),
89 }
90 deviceMgr.logicalDeviceMgr = logicalDeviceMgr
Matteo Scandolod525ae32020-04-02 17:27:29 -070091
khenaidood948f772021-08-11 17:49:24 -040092 adapterMgr.SetAdapterRestartedCallback(deviceMgr.adapterRestartedHandler)
Matteo Scandolod525ae32020-04-02 17:27:29 -070093
Kent Hagerman2b216042020-04-03 18:28:56 -040094 return deviceMgr, logicalDeviceMgr
khenaidoob9203542018-09-17 22:56:37 -040095}
96
khenaidood948f772021-08-11 17:49:24 -040097func (dMgr *Manager) Start(ctx context.Context, serviceName string) error {
khenaidoo7585a962021-06-10 16:15:38 -040098 logger.Info(ctx, "starting-device-manager")
khenaidood948f772021-08-11 17:49:24 -040099 probe.UpdateStatusFromContext(ctx, serviceName, probe.ServiceStatusPreparing)
khenaidoo7585a962021-06-10 16:15:38 -0400100
101 // Load all the devices from the dB
102 var devices []*voltha.Device
103 if err := dMgr.dProxy.List(ctx, &devices); err != nil {
104 // Any error from the dB means if we proceed we may end up with corrupted data
khenaidood948f772021-08-11 17:49:24 -0400105 logger.Errorw(ctx, "failed-to-list-devices-from-KV", log.Fields{"error": err, "service-name": serviceName})
106 return err
107 }
108
109 defer probe.UpdateStatusFromContext(ctx, serviceName, probe.ServiceStatusRunning)
110
111 if len(devices) == 0 {
112 logger.Info(ctx, "no-device-to-load")
113 return nil
khenaidoo7585a962021-06-10 16:15:38 -0400114 }
115
116 for _, device := range devices {
117 // Create an agent for each device
Himani Chawla4b4bd252021-11-08 15:59:40 +0530118 agent := newAgent(device, dMgr, dMgr.dbPath, dMgr.dProxy, dMgr.internalTimeout, dMgr.rpcTimeout, dMgr.flowTimeout)
khenaidoo7585a962021-06-10 16:15:38 -0400119 if _, err := agent.start(ctx, true, device); err != nil {
120 logger.Warnw(ctx, "failure-starting-agent", log.Fields{"device-id": device.Id})
121 } else {
122 dMgr.addDeviceAgentToMap(agent)
123 }
124 }
125
126 // TODO: Need to trigger a reconcile at this point
127
khenaidoo7585a962021-06-10 16:15:38 -0400128 logger.Info(ctx, "device-manager-started")
khenaidood948f772021-08-11 17:49:24 -0400129
130 return nil
khenaidoo7585a962021-06-10 16:15:38 -0400131}
132
khenaidooa46458b2021-12-15 16:50:44 -0500133func (dMgr *Manager) Stop(ctx context.Context, serviceName string) {
134 logger.Info(ctx, "stopping-device-manager")
135 close(dMgr.doneCh)
136 probe.UpdateStatusFromContext(ctx, serviceName, probe.ServiceStatusStopped)
137}
138
Kent Hagerman2b216042020-04-03 18:28:56 -0400139func (dMgr *Manager) addDeviceAgentToMap(agent *Agent) {
npujar1d86a522019-11-14 17:11:16 +0530140 if _, exist := dMgr.deviceAgents.Load(agent.deviceID); !exist {
141 dMgr.deviceAgents.Store(agent.deviceID, agent)
khenaidoob9203542018-09-17 22:56:37 -0400142 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400143 dMgr.lockRootDeviceMap.Lock()
144 defer dMgr.lockRootDeviceMap.Unlock()
Kent Hagerman2a07b862020-06-19 15:23:07 -0400145 dMgr.rootDevices[agent.deviceID] = agent.isRootDevice
khenaidoo2c6a0992019-04-29 13:46:56 -0400146
khenaidoob9203542018-09-17 22:56:37 -0400147}
148
Kent Hagerman2b216042020-04-03 18:28:56 -0400149func (dMgr *Manager) deleteDeviceAgentFromMap(agent *Agent) {
npujar1d86a522019-11-14 17:11:16 +0530150 dMgr.deviceAgents.Delete(agent.deviceID)
khenaidoo2c6a0992019-04-29 13:46:56 -0400151 dMgr.lockRootDeviceMap.Lock()
152 defer dMgr.lockRootDeviceMap.Unlock()
npujar1d86a522019-11-14 17:11:16 +0530153 delete(dMgr.rootDevices, agent.deviceID)
khenaidoo4d4802d2018-10-04 21:59:49 -0400154}
155
khenaidoo297cd252019-02-07 22:10:23 -0500156// 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 -0400157func (dMgr *Manager) getDeviceAgent(ctx context.Context, deviceID string) *Agent {
npujar1d86a522019-11-14 17:11:16 +0530158 agent, ok := dMgr.deviceAgents.Load(deviceID)
159 if ok {
Kent Hagerman2b216042020-04-03 18:28:56 -0400160 return agent.(*Agent)
khenaidoob9203542018-09-17 22:56:37 -0400161 }
khenaidoo442e7c72020-03-10 16:13:48 -0400162 // Try to load into memory - loading will also create the device agent and set the device ownership
npujar467fe752020-01-16 20:17:45 +0530163 err := dMgr.load(ctx, deviceID)
npujar1d86a522019-11-14 17:11:16 +0530164 if err == nil {
165 agent, ok = dMgr.deviceAgents.Load(deviceID)
166 if !ok {
167 return nil
168 }
Kent Hagerman2b216042020-04-03 18:28:56 -0400169 return agent.(*Agent)
npujar1d86a522019-11-14 17:11:16 +0530170 }
171 //TODO: Change the return params to return an error as well
divyadesaicb8b59d2020-08-18 09:55:47 +0000172 logger.Errorw(ctx, "loading-device-failed", log.Fields{"device-id": deviceID, "error": err})
khenaidoob9203542018-09-17 22:56:37 -0400173 return nil
174}
175
khenaidoo297cd252019-02-07 22:10:23 -0500176// listDeviceIdsFromMap returns the list of device IDs that are in memory
Kent Hagerman2b216042020-04-03 18:28:56 -0400177func (dMgr *Manager) listDeviceIdsFromMap() *voltha.IDs {
khenaidoo7ccedd52018-12-14 16:48:54 -0500178 result := &voltha.IDs{Items: make([]*voltha.ID, 0)}
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400179
180 dMgr.deviceAgents.Range(func(key, value interface{}) bool {
181 result.Items = append(result.Items, &voltha.ID{Id: key.(string)})
182 return true
183 })
184
khenaidoo7ccedd52018-12-14 16:48:54 -0500185 return result
186}
187
khenaidoo6d62c002019-05-15 21:57:03 -0400188// stopManagingDevice stops the management of the device as well as any of its reference device and logical device.
189// This function is called only in the Core that does not own this device. In the Core that owns this device then a
190// deletion deletion also includes removal of any reference of this device.
Kent Hagerman2b216042020-04-03 18:28:56 -0400191func (dMgr *Manager) stopManagingDevice(ctx context.Context, id string) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530192 logger.Infow(ctx, "stop-managing-device", log.Fields{"device-id": id})
khenaidoo6d62c002019-05-15 21:57:03 -0400193 if dMgr.IsDeviceInCache(id) { // Proceed only if an agent is present for this device
Kent Hagerman6031aad2020-07-29 16:36:33 -0400194 if device, err := dMgr.getDeviceReadOnly(ctx, id); err == nil && device.Root {
khenaidoo6d62c002019-05-15 21:57:03 -0400195 // stop managing the logical device
David Bainbridged1afd662020-03-26 18:27:41 -0700196 _ = dMgr.logicalDeviceMgr.stopManagingLogicalDeviceWithDeviceID(ctx, id)
khenaidoo6d62c002019-05-15 21:57:03 -0400197 }
npujar467fe752020-01-16 20:17:45 +0530198 if agent := dMgr.getDeviceAgent(ctx, id); agent != nil {
khenaidoo442e7c72020-03-10 16:13:48 -0400199 if err := agent.stop(ctx); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000200 logger.Warnw(ctx, "unable-to-stop-device-agent", log.Fields{"device-id": agent.deviceID, "error": err})
khenaidoo442e7c72020-03-10 16:13:48 -0400201 }
khenaidoo4c9e5592019-09-09 16:20:41 -0400202 dMgr.deleteDeviceAgentFromMap(agent)
khenaidoo6d62c002019-05-15 21:57:03 -0400203 }
204 }
205}
206
Kent Hagermancba2f302020-07-28 13:37:36 -0400207// getDeviceReadOnly will returns a device, either from memory or from the dB, if present
208func (dMgr *Manager) getDeviceReadOnly(ctx context.Context, id string) (*voltha.Device, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530209 logger.Debugw(ctx, "get-device-read-only", log.Fields{"device-id": id})
npujar467fe752020-01-16 20:17:45 +0530210 if agent := dMgr.getDeviceAgent(ctx, id); agent != nil {
Kent Hagermancba2f302020-07-28 13:37:36 -0400211 return agent.getDeviceReadOnly(ctx)
khenaidoo92e62c52018-10-03 14:02:54 -0400212 }
213 return nil, status.Errorf(codes.NotFound, "%s", id)
khenaidoob9203542018-09-17 22:56:37 -0400214}
215
Kent Hagerman2a07b862020-06-19 15:23:07 -0400216func (dMgr *Manager) listDevicePorts(ctx context.Context, id string) (map[uint32]*voltha.Port, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530217 logger.Debugw(ctx, "list-device-ports", log.Fields{"device-id": id})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400218 agent := dMgr.getDeviceAgent(ctx, id)
219 if agent == nil {
220 return nil, status.Errorf(codes.NotFound, "%s", id)
221 }
222 return agent.listDevicePorts(), nil
223}
224
npujar1d86a522019-11-14 17:11:16 +0530225// IsDeviceInCache returns true if device is found in the map
Kent Hagerman2b216042020-04-03 18:28:56 -0400226func (dMgr *Manager) IsDeviceInCache(id string) bool {
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400227 _, exist := dMgr.deviceAgents.Load(id)
khenaidoo297cd252019-02-07 22:10:23 -0500228 return exist
229}
230
Thomas Lee S51b5cb82019-10-14 14:49:34 +0530231//isParentDeviceExist checks whether device is already preprovisioned.
Kent Hagerman2b216042020-04-03 18:28:56 -0400232func (dMgr *Manager) isParentDeviceExist(ctx context.Context, newDevice *voltha.Device) (bool, error) {
Thomas Lee S51b5cb82019-10-14 14:49:34 +0530233 hostPort := newDevice.GetHostAndPort()
Kent Hagerman4f355f52020-03-30 16:01:33 -0400234 var devices []*voltha.Device
Kent Hagermanf5a67352020-04-30 15:15:26 -0400235 if err := dMgr.dProxy.List(ctx, &devices); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530236 logger.Errorw(ctx, "failed-to-list-devices-from-cluster-data-proxy", log.Fields{"error": err})
Thomas Lee Se5a44012019-11-07 20:32:24 +0530237 return false, err
238 }
Kent Hagerman4f355f52020-03-30 16:01:33 -0400239 for _, device := range devices {
240 if !device.Root {
241 continue
242 }
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530243
244 if hostPort != "" && hostPort == device.GetHostAndPort() {
Kent Hagerman4f355f52020-03-30 16:01:33 -0400245 return true, nil
246 }
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530247 if newDevice.MacAddress != "" && newDevice.MacAddress == device.MacAddress {
Kent Hagerman4f355f52020-03-30 16:01:33 -0400248 return true, nil
Thomas Lee S51b5cb82019-10-14 14:49:34 +0530249 }
250 }
Thomas Lee Se5a44012019-11-07 20:32:24 +0530251 return false, nil
Thomas Lee S51b5cb82019-10-14 14:49:34 +0530252}
253
khenaidoo6d62c002019-05-15 21:57:03 -0400254//getDeviceFromModelretrieves the device data from the model.
Kent Hagerman2b216042020-04-03 18:28:56 -0400255func (dMgr *Manager) getDeviceFromModel(ctx context.Context, deviceID string) (*voltha.Device, error) {
Kent Hagerman4f355f52020-03-30 16:01:33 -0400256 device := &voltha.Device{}
Kent Hagermanf5a67352020-04-30 15:15:26 -0400257 if have, err := dMgr.dProxy.Get(ctx, deviceID, device); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000258 logger.Errorw(ctx, "failed-to-get-device-info-from-cluster-proxy", log.Fields{"error": err})
Thomas Lee Se5a44012019-11-07 20:32:24 +0530259 return nil, err
Kent Hagerman4f355f52020-03-30 16:01:33 -0400260 } else if !have {
261 return nil, status.Error(codes.NotFound, deviceID)
Thomas Lee Se5a44012019-11-07 20:32:24 +0530262 }
Kent Hagerman4f355f52020-03-30 16:01:33 -0400263
264 return device, nil
khenaidoo6d62c002019-05-15 21:57:03 -0400265}
266
npujar1d86a522019-11-14 17:11:16 +0530267// loadDevice loads the deviceID in memory, if not present
Kent Hagerman2b216042020-04-03 18:28:56 -0400268func (dMgr *Manager) loadDevice(ctx context.Context, deviceID string) (*Agent, error) {
npujar1d86a522019-11-14 17:11:16 +0530269 if deviceID == "" {
khenaidoo297cd252019-02-07 22:10:23 -0500270 return nil, status.Error(codes.InvalidArgument, "deviceId empty")
271 }
khenaidoo4c9e5592019-09-09 16:20:41 -0400272 var err error
273 var device *voltha.Device
274 dMgr.devicesLoadingLock.Lock()
npujar1d86a522019-11-14 17:11:16 +0530275 if _, exist := dMgr.deviceLoadingInProgress[deviceID]; !exist {
276 if !dMgr.IsDeviceInCache(deviceID) {
277 dMgr.deviceLoadingInProgress[deviceID] = []chan int{make(chan int, 1)}
khenaidoo4c9e5592019-09-09 16:20:41 -0400278 dMgr.devicesLoadingLock.Unlock()
279 // Proceed with the loading only if the device exist in the Model (could have been deleted)
npujar467fe752020-01-16 20:17:45 +0530280 if device, err = dMgr.getDeviceFromModel(ctx, deviceID); err == nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000281 logger.Debugw(ctx, "loading-device", log.Fields{"device-id": deviceID})
Himani Chawla4b4bd252021-11-08 15:59:40 +0530282 agent := newAgent(device, dMgr, dMgr.dbPath, dMgr.dProxy, dMgr.internalTimeout, dMgr.rpcTimeout, dMgr.flowTimeout)
khenaidoo7585a962021-06-10 16:15:38 -0400283 if _, err = agent.start(ctx, true, device); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530284 logger.Warnw(ctx, "failure-loading-device", log.Fields{"device-id": deviceID, "error": err})
khenaidoo4c9e5592019-09-09 16:20:41 -0400285 } else {
286 dMgr.addDeviceAgentToMap(agent)
287 }
288 } else {
Himani Chawlab4c25912020-11-12 17:16:38 +0530289 logger.Debugw(ctx, "device-is-not-in-model", log.Fields{"device-id": deviceID})
khenaidoo6d62c002019-05-15 21:57:03 -0400290 }
khenaidoo4c9e5592019-09-09 16:20:41 -0400291 // announce completion of task to any number of waiting channels
292 dMgr.devicesLoadingLock.Lock()
npujar1d86a522019-11-14 17:11:16 +0530293 if v, ok := dMgr.deviceLoadingInProgress[deviceID]; ok {
khenaidoo4c9e5592019-09-09 16:20:41 -0400294 for _, ch := range v {
295 close(ch)
296 }
npujar1d86a522019-11-14 17:11:16 +0530297 delete(dMgr.deviceLoadingInProgress, deviceID)
khenaidoo4c9e5592019-09-09 16:20:41 -0400298 }
299 dMgr.devicesLoadingLock.Unlock()
khenaidoo6d62c002019-05-15 21:57:03 -0400300 } else {
khenaidoo4c9e5592019-09-09 16:20:41 -0400301 dMgr.devicesLoadingLock.Unlock()
khenaidoo297cd252019-02-07 22:10:23 -0500302 }
khenaidoo4c9e5592019-09-09 16:20:41 -0400303 } else {
304 ch := make(chan int, 1)
npujar1d86a522019-11-14 17:11:16 +0530305 dMgr.deviceLoadingInProgress[deviceID] = append(dMgr.deviceLoadingInProgress[deviceID], ch)
khenaidoo4c9e5592019-09-09 16:20:41 -0400306 dMgr.devicesLoadingLock.Unlock()
307 // Wait for the channel to be closed, implying the process loading this device is done.
308 <-ch
khenaidoo297cd252019-02-07 22:10:23 -0500309 }
npujar1d86a522019-11-14 17:11:16 +0530310 if agent, ok := dMgr.deviceAgents.Load(deviceID); ok {
Kent Hagerman2b216042020-04-03 18:28:56 -0400311 return agent.(*Agent), nil
khenaidoo297cd252019-02-07 22:10:23 -0500312 }
npujar1d86a522019-11-14 17:11:16 +0530313 return nil, status.Errorf(codes.Aborted, "Error loading device %s", deviceID)
khenaidoo297cd252019-02-07 22:10:23 -0500314}
315
316// loadRootDeviceParentAndChildren loads the children and parents of a root device in memory
Kent Hagerman2a07b862020-06-19 15:23:07 -0400317func (dMgr *Manager) loadRootDeviceParentAndChildren(ctx context.Context, device *voltha.Device, devicePorts map[uint32]*voltha.Port) error {
divyadesaicb8b59d2020-08-18 09:55:47 +0000318 logger.Debugw(ctx, "loading-parent-and-children", log.Fields{"device-id": device.Id})
khenaidoo297cd252019-02-07 22:10:23 -0500319 if device.Root {
320 // Scenario A
321 if device.ParentId != "" {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400322 // Load logical device if needed.
npujar467fe752020-01-16 20:17:45 +0530323 if err := dMgr.logicalDeviceMgr.load(ctx, device.ParentId); err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000324 logger.Warnw(ctx, "failure-loading-logical-device", log.Fields{"logical-device-id": device.ParentId})
khenaidoo297cd252019-02-07 22:10:23 -0500325 }
326 } else {
divyadesaicb8b59d2020-08-18 09:55:47 +0000327 logger.Debugw(ctx, "no-parent-to-load", log.Fields{"device-id": device.Id})
khenaidoo297cd252019-02-07 22:10:23 -0500328 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400329 // Load all child devices, if needed
330 childDeviceIds := dMgr.getAllChildDeviceIds(ctx, devicePorts)
331 for childDeviceID := range childDeviceIds {
332 if _, err := dMgr.loadDevice(ctx, childDeviceID); err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000333 logger.Warnw(ctx, "failure-loading-device", log.Fields{"device-id": childDeviceID, "error": err})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400334 return err
khenaidoo297cd252019-02-07 22:10:23 -0500335 }
khenaidoo297cd252019-02-07 22:10:23 -0500336 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530337 logger.Debugw(ctx, "loaded-children", log.Fields{"device-id": device.Id, "num-children": len(childDeviceIds)})
khenaidoo297cd252019-02-07 22:10:23 -0500338 }
339 return nil
340}
341
342// load loads the deviceId in memory, if not present, and also loads its accompanying parents and children. Loading
343// in memory is for improved performance. It is not imperative that a device needs to be in memory when a request
344// acting on the device is received by the core. In such a scenario, the Core will load the device in memory first
345// and the proceed with the request.
Kent Hagerman2b216042020-04-03 18:28:56 -0400346func (dMgr *Manager) load(ctx context.Context, deviceID string) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000347 logger.Debug(ctx, "load...")
khenaidoo297cd252019-02-07 22:10:23 -0500348 // 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 -0400349 var dAgent *Agent
khenaidoo297cd252019-02-07 22:10:23 -0500350 var err error
npujar467fe752020-01-16 20:17:45 +0530351 if dAgent, err = dMgr.loadDevice(ctx, deviceID); err != nil {
khenaidoo297cd252019-02-07 22:10:23 -0500352 return err
353 }
354 // Get the loaded device details
Kent Hagermancba2f302020-07-28 13:37:36 -0400355 device, err := dAgent.getDeviceReadOnly(ctx)
khenaidoo442e7c72020-03-10 16:13:48 -0400356 if err != nil {
357 return err
358 }
khenaidoo297cd252019-02-07 22:10:23 -0500359
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530360 // If the device is in Pre-provisioning or getting deleted state stop here
361 if device.AdminState == voltha.AdminState_PREPROVISIONED || dAgent.isDeletionInProgress() {
khenaidoo297cd252019-02-07 22:10:23 -0500362 return nil
363 }
364
365 // Now we face two scenarios
366 if device.Root {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400367 devicePorts := dAgent.listDevicePorts()
368
khenaidoo297cd252019-02-07 22:10:23 -0500369 // Load all children as well as the parent of this device (logical_device)
Kent Hagerman2a07b862020-06-19 15:23:07 -0400370 if err := dMgr.loadRootDeviceParentAndChildren(ctx, device, devicePorts); err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000371 logger.Warnw(ctx, "failure-loading-device-parent-and-children", log.Fields{"device-id": deviceID})
khenaidoo297cd252019-02-07 22:10:23 -0500372 return err
373 }
divyadesaicb8b59d2020-08-18 09:55:47 +0000374 logger.Debugw(ctx, "successfully-loaded-parent-and-children", log.Fields{"device-id": deviceID})
Andrey Pozolotin34dd63f2021-05-31 21:26:40 +0300375 } else if device.ParentId != "" {
khenaidoo297cd252019-02-07 22:10:23 -0500376 // Scenario B - use the parentId of that device (root device) to trigger the loading
Andrey Pozolotin34dd63f2021-05-31 21:26:40 +0300377 return dMgr.load(ctx, device.ParentId)
khenaidoo297cd252019-02-07 22:10:23 -0500378 }
Andrey Pozolotin34dd63f2021-05-31 21:26:40 +0300379
khenaidoo297cd252019-02-07 22:10:23 -0500380 return nil
381}
382
khenaidooba6b6c42019-08-02 09:11:56 -0400383// adapterRestarted is invoked whenever an adapter is restarted
Kent Hagerman2b216042020-04-03 18:28:56 -0400384func (dMgr *Manager) adapterRestarted(ctx context.Context, adapter *voltha.Adapter) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530385 logger.Debugw(ctx, "adapter-restarted", log.Fields{"adapter-id": adapter.Id, "vendor": adapter.Vendor,
Girish Gowdra11ddb232022-05-26 12:19:59 -0700386 "current-replica": adapter.CurrentReplica, "total-replicas": adapter.TotalReplicas,
387 "restarted-endpoint": adapter.Endpoint, "current-version": adapter.Version})
khenaidooba6b6c42019-08-02 09:11:56 -0400388
khenaidood948f772021-08-11 17:49:24 -0400389 numberOfDevicesToReconcile := 0
390 dMgr.deviceAgents.Range(func(key, value interface{}) bool {
391 deviceAgent, ok := value.(*Agent)
392 if ok && deviceAgent.adapterEndpoint == adapter.Endpoint {
393 // Before reconciling, abort in-process request
394 if err := deviceAgent.abortAllProcessing(utils.WithNewSpanAndRPCMetadataContext(ctx, "AbortProcessingOnRestart")); err == nil {
395 logger.Debugw(ctx, "reconciling-device",
396 log.Fields{
397 "device-id": deviceAgent.deviceID,
398 "root-device": deviceAgent.isRootDevice,
399 "restarted-endpoint": adapter.Endpoint,
400 "device-type": deviceAgent.deviceType,
401 "adapter-type": adapter.Type,
402 })
403 go deviceAgent.ReconcileDevice(utils.WithNewSpanAndRPCMetadataContext(ctx, "ReconcileDevice"))
404 numberOfDevicesToReconcile++
405 } else {
406 logger.Errorw(ctx, "failed-aborting-exisiting-processing", log.Fields{"error": err})
khenaidooba6b6c42019-08-02 09:11:56 -0400407 }
408 }
khenaidood948f772021-08-11 17:49:24 -0400409 return true
410 })
411 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 -0400412 return nil
413}
414
Kent Hagerman2b216042020-04-03 18:28:56 -0400415func (dMgr *Manager) UpdateDeviceUsingAdapterData(ctx context.Context, device *voltha.Device) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530416 logger.Debugw(ctx, "update-device-using-adapter-data", log.Fields{"device-id": device.Id, "device": device})
npujar467fe752020-01-16 20:17:45 +0530417 if agent := dMgr.getDeviceAgent(ctx, device.Id); agent != nil {
418 return agent.updateDeviceUsingAdapterData(ctx, device)
khenaidoob9203542018-09-17 22:56:37 -0400419 }
420 return status.Errorf(codes.NotFound, "%s", device.Id)
421}
422
khenaidoo0db4c812020-05-27 15:27:30 -0400423func (dMgr *Manager) addPeerPort(ctx context.Context, deviceID string, port *voltha.Port) error {
424 meAsPeer := &voltha.Port_PeerPort{DeviceId: deviceID, PortNo: port.PortNo}
425 for _, peerPort := range port.Peers {
426 if agent := dMgr.getDeviceAgent(ctx, peerPort.DeviceId); agent != nil {
427 if err := agent.addPeerPort(ctx, meAsPeer); err != nil {
428 return err
429 }
430 }
431 }
432 // Notify the logical device manager to setup a logical port, if needed. If the added port is an NNI or UNI
433 // then a logical port will be added to the logical device and the device route generated. If the port is a
434 // PON port then only the device graph will be generated.
Kent Hagermancba2f302020-07-28 13:37:36 -0400435 device, err := dMgr.getDeviceReadOnly(ctx, deviceID)
khenaidoo0db4c812020-05-27 15:27:30 -0400436 if err != nil {
437 return err
438 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400439 ports, err := dMgr.listDevicePorts(ctx, deviceID)
440 if err != nil {
441 return err
442 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530443 subCtx := utils.WithSpanAndRPCMetadataFromContext(ctx)
444
445 if err = dMgr.logicalDeviceMgr.updateLogicalPort(subCtx, device, ports, port); err != nil {
khenaidoo0db4c812020-05-27 15:27:30 -0400446 return err
447 }
448 return nil
449}
450
Kent Hagerman2b216042020-04-03 18:28:56 -0400451func (dMgr *Manager) AddPort(ctx context.Context, deviceID string, port *voltha.Port) error {
npujar467fe752020-01-16 20:17:45 +0530452 agent := dMgr.getDeviceAgent(ctx, deviceID)
npujar1d86a522019-11-14 17:11:16 +0530453 if agent != nil {
npujar467fe752020-01-16 20:17:45 +0530454 if err := agent.addPort(ctx, port); err != nil {
khenaidoo92e62c52018-10-03 14:02:54 -0400455 return err
456 }
khenaidoo0db4c812020-05-27 15:27:30 -0400457 // Setup peer ports in its own routine
458 go func() {
Himani Chawlab4c25912020-11-12 17:16:38 +0530459 subCtx := utils.WithSpanAndRPCMetadataFromContext(ctx)
460 if err := dMgr.addPeerPort(subCtx, deviceID, port); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000461 logger.Errorw(ctx, "unable-to-add-peer-port", log.Fields{"error": err, "device-id": deviceID})
khenaidoo92e62c52018-10-03 14:02:54 -0400462 }
khenaidoo0db4c812020-05-27 15:27:30 -0400463 }()
khenaidoo92e62c52018-10-03 14:02:54 -0400464 return nil
khenaidoob9203542018-09-17 22:56:37 -0400465 }
npujar1d86a522019-11-14 17:11:16 +0530466 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoob9203542018-09-17 22:56:37 -0400467}
468
Elia Battiston509fdc72022-01-04 13:28:09 +0100469func (dMgr *Manager) canAdapterRequestProceed(ctx context.Context, deviceID string) error {
470 agent := dMgr.getDeviceAgent(ctx, deviceID)
471 if agent == nil {
472 logger.Errorw(ctx, "device-nil", log.Fields{"device-id": deviceID})
473 return status.Errorf(codes.NotFound, "device-nil-for-%s", deviceID)
474 }
475 if !agent.isAdapterConnectionUp(ctx) {
476 return status.Errorf(codes.Unavailable, "adapter-connection-down-for-%s", deviceID)
477 }
478 if err := agent.canDeviceRequestProceed(ctx); err != nil {
479 return err
480 }
481 // Perform the same checks for parent device
482 if !agent.isRootDevice {
483 parentDeviceAgent := dMgr.getDeviceAgent(ctx, agent.parentID)
484 if parentDeviceAgent == nil {
485 logger.Errorw(ctx, "parent-device-adapter-nil", log.Fields{"parent-id": agent.parentID})
486 return status.Errorf(codes.NotFound, "parent-device-adapter-nil-for-%s", deviceID)
khenaidood948f772021-08-11 17:49:24 -0400487 }
Elia Battiston509fdc72022-01-04 13:28:09 +0100488 if err := parentDeviceAgent.canDeviceRequestProceed(ctx); err != nil {
khenaidood948f772021-08-11 17:49:24 -0400489 return err
490 }
491 }
Elia Battiston509fdc72022-01-04 13:28:09 +0100492
493 return nil
494}
495
496func (dMgr *Manager) canMultipleAdapterRequestProceed(ctx context.Context, deviceIDs []string) error {
497 if len(deviceIDs) == 0 {
khenaidood948f772021-08-11 17:49:24 -0400498 return status.Error(codes.Unavailable, "adapter(s)-not-ready")
499 }
Elia Battiston509fdc72022-01-04 13:28:09 +0100500
501 for _, deviceID := range deviceIDs {
502 if err := dMgr.canAdapterRequestProceed(ctx, deviceID); err != nil {
503 return err
504 }
505 }
506
khenaidood948f772021-08-11 17:49:24 -0400507 return nil
508}
509
khenaidoo9beaaf12021-10-19 17:32:01 -0400510func (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 +0530511 logger.Debugw(ctx, "add-flows-and-groups", log.Fields{"device-id": deviceID, "groups:": groups, "flow-metadata": flowMetadata})
npujar467fe752020-01-16 20:17:45 +0530512 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
513 return agent.addFlowsAndGroups(ctx, flows, groups, flowMetadata)
khenaidoo0458db62019-06-20 08:50:36 -0400514 }
npujar1d86a522019-11-14 17:11:16 +0530515 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo0458db62019-06-20 08:50:36 -0400516}
517
khenaidoo787224a2020-04-16 18:08:47 -0400518// deleteParentFlows removes flows from the parent device based on specific attributes
khenaidoo9beaaf12021-10-19 17:32:01 -0400519func (dMgr *Manager) deleteParentFlows(ctx context.Context, deviceID string, uniPort uint32, metadata *ofp.FlowMetadata) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530520 logger.Debugw(ctx, "delete-parent-flows", log.Fields{"device-id": deviceID, "uni-port": uniPort, "metadata": metadata})
khenaidoo787224a2020-04-16 18:08:47 -0400521 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400522 if !agent.isRootDevice {
khenaidoo787224a2020-04-16 18:08:47 -0400523 return status.Errorf(codes.FailedPrecondition, "not-a-parent-device-%s", deviceID)
524 }
525 return agent.filterOutFlows(ctx, uniPort, metadata)
526 }
527 return status.Errorf(codes.NotFound, "%s", deviceID)
528}
529
khenaidoo9beaaf12021-10-19 17:32:01 -0400530func (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 +0530531 logger.Debugw(ctx, "delete-flows-and-groups", log.Fields{"device-id": deviceID})
npujar467fe752020-01-16 20:17:45 +0530532 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
533 return agent.deleteFlowsAndGroups(ctx, flows, groups, flowMetadata)
khenaidoo0458db62019-06-20 08:50:36 -0400534 }
npujar1d86a522019-11-14 17:11:16 +0530535 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo0458db62019-06-20 08:50:36 -0400536}
537
khenaidoo9beaaf12021-10-19 17:32:01 -0400538func (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 +0530539 logger.Debugw(ctx, "update-flows-and-groups", log.Fields{"device-id": deviceID})
npujar467fe752020-01-16 20:17:45 +0530540 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
541 return agent.updateFlowsAndGroups(ctx, flows, groups, flowMetadata)
khenaidoo19d7b632018-10-30 10:49:50 -0400542 }
npujar1d86a522019-11-14 17:11:16 +0530543 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo19d7b632018-10-30 10:49:50 -0400544}
545
Kent Hagerman2b216042020-04-03 18:28:56 -0400546// InitPmConfigs initialize the pm configs as defined by the adapter.
547func (dMgr *Manager) InitPmConfigs(ctx context.Context, deviceID string, pmConfigs *voltha.PmConfigs) error {
khenaidoob3127472019-07-24 21:04:55 -0400548 if pmConfigs.Id == "" {
549 return status.Errorf(codes.FailedPrecondition, "invalid-device-Id")
550 }
npujar467fe752020-01-16 20:17:45 +0530551 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
552 return agent.initPmConfigs(ctx, pmConfigs)
khenaidoob9203542018-09-17 22:56:37 -0400553 }
npujar1d86a522019-11-14 17:11:16 +0530554 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoob9203542018-09-17 22:56:37 -0400555}
556
khenaidoo9beaaf12021-10-19 17:32:01 -0400557func (dMgr *Manager) getSwitchCapability(ctx context.Context, deviceID string) (*ca.SwitchCapability, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530558 logger.Debugw(ctx, "get-switch-capability", log.Fields{"device-id": deviceID})
npujar467fe752020-01-16 20:17:45 +0530559 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
khenaidoob9203542018-09-17 22:56:37 -0400560 return agent.getSwitchCapability(ctx)
561 }
npujar1d86a522019-11-14 17:11:16 +0530562 return nil, status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoob9203542018-09-17 22:56:37 -0400563}
564
Kent Hagerman2b216042020-04-03 18:28:56 -0400565func (dMgr *Manager) UpdateDeviceStatus(ctx context.Context, deviceID string, operStatus voltha.OperStatus_Types, connStatus voltha.ConnectStatus_Types) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530566 logger.Debugw(ctx, "update-device-status", log.Fields{"device-id": deviceID, "oper-status": operStatus, "conn-status": connStatus})
npujar467fe752020-01-16 20:17:45 +0530567 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
568 return agent.updateDeviceStatus(ctx, operStatus, connStatus)
khenaidoo92e62c52018-10-03 14:02:54 -0400569 }
npujar1d86a522019-11-14 17:11:16 +0530570 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo92e62c52018-10-03 14:02:54 -0400571}
572
Kent Hagerman2b216042020-04-03 18:28:56 -0400573func (dMgr *Manager) UpdateChildrenStatus(ctx context.Context, deviceID string, operStatus voltha.OperStatus_Types, connStatus voltha.ConnectStatus_Types) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530574 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 -0400575 parentDevicePorts, err := dMgr.listDevicePorts(ctx, deviceID)
576 if err != nil {
khenaidoo4d4802d2018-10-04 21:59:49 -0400577 return status.Errorf(codes.Aborted, "%s", err.Error())
578 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400579 for childDeviceID := range dMgr.getAllChildDeviceIds(ctx, parentDevicePorts) {
npujar467fe752020-01-16 20:17:45 +0530580 if agent := dMgr.getDeviceAgent(ctx, childDeviceID); agent != nil {
581 if err = agent.updateDeviceStatus(ctx, operStatus, connStatus); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530582 return status.Errorf(codes.Aborted, "childDevice:%s, error:%s", childDeviceID, err.Error())
khenaidoo4d4802d2018-10-04 21:59:49 -0400583 }
584 }
585 }
586 return nil
587}
588
Kent Hagerman2b216042020-04-03 18:28:56 -0400589func (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 +0530590 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 +0530591 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
592 if err := agent.updatePortState(ctx, portType, portNo, operStatus); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530593 logger.Errorw(ctx, "updating-port-state-failed", log.Fields{"device-id": deviceID, "port-no": portNo, "error": err})
khenaidoo171b98e2019-10-31 11:48:15 -0400594 return err
595 }
596 // Notify the logical device manager to change the port state
Mahir Gunyel18fa0c92020-03-06 13:34:04 -0800597 // Do this for NNI and UNIs only. PON ports are not known by logical device
598 if portType == voltha.Port_ETHERNET_NNI || portType == voltha.Port_ETHERNET_UNI {
599 go func() {
Himani Chawlab4c25912020-11-12 17:16:38 +0530600 subCtx := utils.WithSpanAndRPCMetadataFromContext(ctx)
601 err := dMgr.logicalDeviceMgr.updatePortState(subCtx, deviceID, portNo, operStatus)
Mahir Gunyel18fa0c92020-03-06 13:34:04 -0800602 if err != nil {
603 // While we want to handle (catch) and log when
604 // an update to a port was not able to be
605 // propagated to the logical port, we can report
606 // it as a warning and not an error because it
607 // doesn't stop or modify processing.
608 // TODO: VOL-2707
Rohan Agrawal31f21802020-06-12 05:38:46 +0000609 logger.Warnw(ctx, "unable-to-update-logical-port-state", log.Fields{"error": err})
Mahir Gunyel18fa0c92020-03-06 13:34:04 -0800610 }
611 }()
612 }
khenaidoo442e7c72020-03-10 16:13:48 -0400613 return nil
khenaidoob9203542018-09-17 22:56:37 -0400614 }
npujar1d86a522019-11-14 17:11:16 +0530615 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoob9203542018-09-17 22:56:37 -0400616}
617
Kent Hagerman2b216042020-04-03 18:28:56 -0400618//UpdatePortsState updates all ports on the device
Kent Hagerman2a07b862020-06-19 15:23:07 -0400619func (dMgr *Manager) UpdatePortsState(ctx context.Context, deviceID string, portTypeFilter uint32, state voltha.OperStatus_Types) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530620 logger.Debugw(ctx, "update-ports-state", log.Fields{"device-id": deviceID})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400621 agent := dMgr.getDeviceAgent(ctx, deviceID)
622 if agent == nil {
623 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo3ab34882019-05-02 21:33:30 -0400624 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400625 if state != voltha.OperStatus_ACTIVE && state != voltha.OperStatus_UNKNOWN {
626 return status.Error(codes.Unimplemented, "state-change-not-implemented")
627 }
628 if err := agent.updatePortsOperState(ctx, portTypeFilter, state); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530629 logger.Warnw(ctx, "update-ports-state-failed", log.Fields{"device-id": deviceID, "error": err})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400630 return err
631 }
632 return nil
khenaidoo3ab34882019-05-02 21:33:30 -0400633}
634
Kent Hagerman2b216042020-04-03 18:28:56 -0400635func (dMgr *Manager) packetOut(ctx context.Context, deviceID string, outPort uint32, packet *ofp.OfpPacketOut) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530636 logger.Debugw(ctx, "packet-out", log.Fields{"device-id": deviceID, "out-port": outPort})
npujar467fe752020-01-16 20:17:45 +0530637 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
638 return agent.packetOut(ctx, outPort, packet)
khenaidoofdbad6e2018-11-06 22:26:38 -0500639 }
npujar1d86a522019-11-14 17:11:16 +0530640 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoofdbad6e2018-11-06 22:26:38 -0500641}
642
npujar1d86a522019-11-14 17:11:16 +0530643// PacketIn receives packet from adapter
Kent Hagerman2b216042020-04-03 18:28:56 -0400644func (dMgr *Manager) PacketIn(ctx context.Context, deviceID string, port uint32, transactionID string, packet []byte) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530645 logger.Debugw(ctx, "packet-in", log.Fields{"device-id": deviceID, "port": port})
khenaidoofdbad6e2018-11-06 22:26:38 -0500646 // Get the logical device Id based on the deviceId
647 var device *voltha.Device
648 var err error
Kent Hagermancba2f302020-07-28 13:37:36 -0400649 if device, err = dMgr.getDeviceReadOnly(ctx, deviceID); err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000650 logger.Errorw(ctx, "device-not-found", log.Fields{"device-id": deviceID})
khenaidoofdbad6e2018-11-06 22:26:38 -0500651 return err
652 }
khenaidoo43c82122018-11-22 18:38:28 -0500653 if !device.Root {
divyadesaicb8b59d2020-08-18 09:55:47 +0000654 logger.Errorw(ctx, "device-not-root", log.Fields{"device-id": deviceID})
npujar1d86a522019-11-14 17:11:16 +0530655 return status.Errorf(codes.FailedPrecondition, "%s", deviceID)
khenaidoofdbad6e2018-11-06 22:26:38 -0500656 }
657
khenaidood948f772021-08-11 17:49:24 -0400658 if err := dMgr.logicalDeviceMgr.packetIn(ctx, device.ParentId, port, packet); err != nil {
khenaidoofdbad6e2018-11-06 22:26:38 -0500659 return err
660 }
661 return nil
662}
663
Kent Hagerman2b216042020-04-03 18:28:56 -0400664func (dMgr *Manager) setParentID(ctx context.Context, device *voltha.Device, parentID string) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530665 logger.Debugw(ctx, "set-parent-id", log.Fields{"device-id": device.Id, "parent-id": parentID})
npujar467fe752020-01-16 20:17:45 +0530666 if agent := dMgr.getDeviceAgent(ctx, device.Id); agent != nil {
667 return agent.setParentID(ctx, device, parentID)
khenaidooad06fd72019-10-28 12:26:05 -0400668 }
669 return status.Errorf(codes.NotFound, "%s", device.Id)
670}
671
Kent Hagerman2b216042020-04-03 18:28:56 -0400672func (dMgr *Manager) getParentDevice(ctx context.Context, childDevice *voltha.Device) *voltha.Device {
khenaidoo92e62c52018-10-03 14:02:54 -0400673 // Sanity check
674 if childDevice.Root {
675 // childDevice is the parent device
676 return childDevice
677 }
Kent Hagermancba2f302020-07-28 13:37:36 -0400678 parentDevice, _ := dMgr.getDeviceReadOnly(ctx, childDevice.ParentId)
khenaidoo92e62c52018-10-03 14:02:54 -0400679 return parentDevice
680}
681
khenaidoo4d4802d2018-10-04 21:59:49 -0400682/*
683All the functions below are callback functions where they are invoked with the latest and previous data. We can
684therefore use the data as is without trying to get the latest from the model.
685*/
686
khenaidoo0a822f92019-05-08 15:15:57 -0400687//DisableAllChildDevices is invoked as a callback when the parent device is disabled
Kent Hagerman2b216042020-04-03 18:28:56 -0400688func (dMgr *Manager) DisableAllChildDevices(ctx context.Context, parentCurrDevice *voltha.Device) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530689 logger.Debug(ctx, "disable-all-child-devices")
Kent Hagerman2a07b862020-06-19 15:23:07 -0400690 ports, _ := dMgr.listDevicePorts(ctx, parentCurrDevice.Id)
691 for childDeviceID := range dMgr.getAllChildDeviceIds(ctx, ports) {
npujar467fe752020-01-16 20:17:45 +0530692 if agent := dMgr.getDeviceAgent(ctx, childDeviceID); agent != nil {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400693 if err := agent.disableDevice(ctx); err != nil {
khenaidooe132f522020-03-20 15:23:15 -0400694 // Just log the error - this error happens only if the child device was already in deleted state.
divyadesaicb8b59d2020-08-18 09:55:47 +0000695 logger.Errorw(ctx, "failure-disable-device", log.Fields{"device-id": childDeviceID, "error": err.Error()})
khenaidoo92e62c52018-10-03 14:02:54 -0400696 }
697 }
698 }
699 return nil
700}
701
khenaidoo4d4802d2018-10-04 21:59:49 -0400702//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 -0400703func (dMgr *Manager) getAllChildDeviceIds(ctx context.Context, parentDevicePorts map[uint32]*voltha.Port) map[string]struct{} {
Himani Chawlab4c25912020-11-12 17:16:38 +0530704 logger.Debug(ctx, "get-all-child-device-ids")
Kent Hagerman2a07b862020-06-19 15:23:07 -0400705 childDeviceIds := make(map[string]struct{}, len(parentDevicePorts))
706 for _, port := range parentDevicePorts {
707 for _, peer := range port.Peers {
708 childDeviceIds[peer.DeviceId] = struct{}{}
khenaidoo92e62c52018-10-03 14:02:54 -0400709 }
710 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400711 logger.Debugw(ctx, "returning-getAllChildDeviceIds", log.Fields{"childDeviceIds": childDeviceIds})
712 return childDeviceIds
khenaidoo92e62c52018-10-03 14:02:54 -0400713}
714
khenaidood948f772021-08-11 17:49:24 -0400715//GgtAllChildDevices is a helper method to get all the child device IDs from the device passed as parameter
716func (dMgr *Manager) getAllChildDevices(ctx context.Context, parentDeviceID string) (*voltha.Devices, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530717 logger.Debugw(ctx, "get-all-child-devices", log.Fields{"parent-device-id": parentDeviceID})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400718 if parentDevicePorts, err := dMgr.listDevicePorts(ctx, parentDeviceID); err == nil {
khenaidoo297cd252019-02-07 22:10:23 -0500719 childDevices := make([]*voltha.Device, 0)
Kent Hagerman2a07b862020-06-19 15:23:07 -0400720 for deviceID := range dMgr.getAllChildDeviceIds(ctx, parentDevicePorts) {
Kent Hagermancba2f302020-07-28 13:37:36 -0400721 if d, e := dMgr.getDeviceReadOnly(ctx, deviceID); e == nil && d != nil {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400722 childDevices = append(childDevices, d)
khenaidoo297cd252019-02-07 22:10:23 -0500723 }
724 }
725 return &voltha.Devices{Items: childDevices}, nil
726 }
npujar1d86a522019-11-14 17:11:16 +0530727 return nil, status.Errorf(codes.NotFound, "%s", parentDeviceID)
khenaidoo297cd252019-02-07 22:10:23 -0500728}
729
Rohan Agrawal31f21802020-06-12 05:38:46 +0000730func (dMgr *Manager) NotifyInvalidTransition(ctx context.Context, device *voltha.Device) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530731 logger.Errorw(ctx, "notify-invalid-transition", log.Fields{
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500732 "device": device.Id,
733 "curr-admin-state": device.AdminState,
734 "curr-oper-state": device.OperStatus,
735 "curr-conn-state": device.ConnectStatus,
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400736 })
khenaidoo0a822f92019-05-08 15:15:57 -0400737 //TODO: notify over kafka?
738 return nil
739}
740
npujar1d86a522019-11-14 17:11:16 +0530741// UpdateDeviceAttribute updates value of particular device attribute
Kent Hagerman2b216042020-04-03 18:28:56 -0400742func (dMgr *Manager) UpdateDeviceAttribute(ctx context.Context, deviceID string, attribute string, value interface{}) {
npujar1d86a522019-11-14 17:11:16 +0530743 if agent, ok := dMgr.deviceAgents.Load(deviceID); ok {
Kent Hagerman2b216042020-04-03 18:28:56 -0400744 agent.(*Agent).updateDeviceAttribute(ctx, attribute, value)
khenaidoob9203542018-09-17 22:56:37 -0400745 }
746}
747
npujar1d86a522019-11-14 17:11:16 +0530748// GetParentDeviceID returns parent device id, either from memory or from the dB, if present
Kent Hagerman2b216042020-04-03 18:28:56 -0400749func (dMgr *Manager) GetParentDeviceID(ctx context.Context, deviceID string) string {
Kent Hagermancba2f302020-07-28 13:37:36 -0400750 if device, _ := dMgr.getDeviceReadOnly(ctx, deviceID); device != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530751 logger.Infow(ctx, "get-parent-device-id", log.Fields{"device-id": device.Id, "parent-id": device.ParentId})
khenaidoo4c9e5592019-09-09 16:20:41 -0400752 return device.ParentId
khenaidoob9203542018-09-17 22:56:37 -0400753 }
khenaidoo4c9e5592019-09-09 16:20:41 -0400754 return ""
khenaidoob9203542018-09-17 22:56:37 -0400755}
serkant.uluderya334479d2019-04-10 08:26:15 -0700756
Kent Hagerman2b216042020-04-03 18:28:56 -0400757func (dMgr *Manager) UpdateDeviceReason(ctx context.Context, deviceID string, reason string) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530758 logger.Debugw(ctx, "update-device-reason", log.Fields{"device-id": deviceID, "reason": reason})
npujar467fe752020-01-16 20:17:45 +0530759 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
760 return agent.updateDeviceReason(ctx, reason)
Mahir Gunyelfdee9212019-10-16 16:52:21 -0700761 }
npujar1d86a522019-11-14 17:11:16 +0530762 return status.Errorf(codes.NotFound, "%s", deviceID)
Mahir Gunyelfdee9212019-10-16 16:52:21 -0700763}
kesavandbc2d1622020-01-21 00:42:01 -0500764
Himani Chawlab4c25912020-11-12 17:16:38 +0530765func (dMgr *Manager) SendRPCEvent(ctx context.Context, id string, rpcEvent *voltha.RPCEvent,
766 category voltha.EventCategory_Types, subCategory *voltha.EventSubCategory_Types, raisedTs int64) {
767 //TODO Instead of directly sending to the kafka bus, queue the message and send it asynchronously
Mahir Gunyelb0343bf2021-05-11 14:14:26 -0700768 dMgr.Agent.SendRPCEvent(ctx, id, rpcEvent, category, subCategory, raisedTs)
Himani Chawlab4c25912020-11-12 17:16:38 +0530769}
Manindera496f852021-02-22 09:57:56 +0530770
khenaidood948f772021-08-11 17:49:24 -0400771func (dMgr *Manager) GetTransientState(ctx context.Context, id string) (core.DeviceTransientState_Types, error) {
Manindera496f852021-02-22 09:57:56 +0530772 agent := dMgr.getDeviceAgent(ctx, id)
773 if agent == nil {
khenaidood948f772021-08-11 17:49:24 -0400774 return core.DeviceTransientState_NONE, status.Errorf(codes.NotFound, "%s", id)
Manindera496f852021-02-22 09:57:56 +0530775 }
776 return agent.getTransientState(), nil
777}
ssiddiquif076cb82021-04-23 10:47:04 +0530778
ssiddiquif076cb82021-04-23 10:47:04 +0530779func (dMgr *Manager) validateImageDownloadRequest(request *voltha.DeviceImageDownloadRequest) error {
780 if request == nil || request.Image == nil || len(request.DeviceId) == 0 {
781 return status.Errorf(codes.InvalidArgument, "invalid argument")
782 }
783
784 for _, deviceID := range request.DeviceId {
785 if deviceID == nil {
786 return status.Errorf(codes.InvalidArgument, "id is nil")
787 }
788 }
789 return nil
790}
791
792func (dMgr *Manager) validateImageRequest(request *voltha.DeviceImageRequest) error {
Elia Battiston58d1c062022-02-08 11:54:27 +0100793 if request == nil {
ssiddiquif076cb82021-04-23 10:47:04 +0530794 return status.Errorf(codes.InvalidArgument, "invalid argument")
795 }
796
797 for _, deviceID := range request.DeviceId {
798 if deviceID == nil {
799 return status.Errorf(codes.InvalidArgument, "id is nil")
800 }
801 }
802
803 return nil
804}
805
806func (dMgr *Manager) validateDeviceImageResponse(response *voltha.DeviceImageResponse) error {
807 if response == nil || len(response.GetDeviceImageStates()) == 0 || response.GetDeviceImageStates()[0] == nil {
808 return status.Errorf(codes.Internal, "invalid-response-from-adapter")
809 }
810
811 return nil
812}
813
814func (dMgr *Manager) waitForAllResponses(ctx context.Context, opName string, respCh chan []*voltha.DeviceImageState, expectedResps int) (*voltha.DeviceImageResponse, error) {
815 response := &voltha.DeviceImageResponse{}
816 respCount := 0
817 for {
818 select {
819 case resp, ok := <-respCh:
820 if !ok {
821 logger.Errorw(ctx, opName+"-failed", log.Fields{"error": "channel-closed"})
822 return response, status.Errorf(codes.Aborted, "channel-closed")
823 }
824
825 if resp != nil {
826 logger.Debugw(ctx, opName+"-result", log.Fields{"image-state": resp[0].GetImageState(), "device-id": resp[0].GetDeviceId()})
827 response.DeviceImageStates = append(response.DeviceImageStates, resp...)
828 }
829
830 respCount++
831
832 //check whether all responses received, if so, sent back the collated response
833 if respCount == expectedResps {
834 return response, nil
835 }
836 continue
837 case <-ctx.Done():
838 return nil, status.Errorf(codes.Aborted, opName+"-failed-%s", ctx.Err())
839 }
840 }
841}
Maninder0aabf0c2021-03-17 14:55:14 +0530842
843func (dMgr *Manager) ReconcilingCleanup(ctx context.Context, device *voltha.Device) error {
844 agent := dMgr.getDeviceAgent(ctx, device.Id)
845 if agent == nil {
846 logger.Errorf(ctx, "Not able to get device agent.")
847 return status.Errorf(codes.NotFound, "Not able to get device agent for device : %s", device.Id)
848 }
849 err := agent.reconcilingCleanup(ctx)
850 if err != nil {
851 logger.Errorf(ctx, err.Error())
852 return status.Errorf(codes.Internal, err.Error())
853 }
854 return nil
855}
khenaidood948f772021-08-11 17:49:24 -0400856
857func (dMgr *Manager) adapterRestartedHandler(ctx context.Context, endpoint string) error {
858 // Get the adapter corresponding to that endpoint
859 if a, _ := dMgr.adapterMgr.GetAdapterWithEndpoint(ctx, endpoint); a != nil {
Girish Gowdra11ddb232022-05-26 12:19:59 -0700860 if rollingUpdate, _ := dMgr.adapterMgr.GetRollingUpdate(ctx, endpoint); rollingUpdate {
861 dMgr.adapterMgr.RegisterOnRxStreamCloseChMap(ctx, endpoint)
862 // Blocking call. wait for the old adapters rx stream to close.
863 // That is a signal that the old adapter is completely down
864 dMgr.adapterMgr.WaitOnRxStreamCloseCh(ctx, endpoint)
865 dMgr.adapterMgr.DeleteRollingUpdate(ctx, endpoint)
866 // In case of rolling update we need to start the connection towards the new adapter instance now
867 if err := dMgr.adapterMgr.StartAdapterWithEndPoint(ctx, endpoint); err != nil {
868 return err
869 }
870 }
khenaidood948f772021-08-11 17:49:24 -0400871 return dMgr.adapterRestarted(ctx, a)
872 }
873 logger.Errorw(ctx, "restarted-adapter-not-found", log.Fields{"endpoint": endpoint})
874 return fmt.Errorf("restarted adapter at endpoint %s not found", endpoint)
875}