blob: c8322a2a9e559622528876d62b259a3ccea2388f [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
khenaidoob9203542018-09-17 22:56:37 -040061}
62
Mahir Gunyel03de0d32020-06-03 01:36:59 -070063//NewManagers creates the Manager and the Logical Manager.
khenaidood948f772021-08-11 17:49:24 -040064func NewManagers(dbPath *model.Path, adapterMgr *adapter.Manager, cf *config.RWCoreFlags, coreInstanceID string, eventProxy *events.EventProxy) (*Manager, *LogicalManager) {
Kent Hagerman2b216042020-04-03 18:28:56 -040065 deviceMgr := &Manager{
Kent Hagerman2b216042020-04-03 18:28:56 -040066 rootDevices: make(map[string]bool),
Kent Hagerman2b216042020-04-03 18:28:56 -040067 coreInstanceID: coreInstanceID,
Mahir Gunyel03de0d32020-06-03 01:36:59 -070068 dbPath: dbPath,
69 dProxy: dbPath.Proxy("devices"),
Kent Hagerman2b216042020-04-03 18:28:56 -040070 adapterMgr: adapterMgr,
khenaidood948f772021-08-11 17:49:24 -040071 internalTimeout: cf.InternalTimeout,
72 rpcTimeout: cf.RPCTimeout,
Himani Chawla4b4bd252021-11-08 15:59:40 +053073 flowTimeout: cf.FlowTimeout,
Maninder0aabf0c2021-03-17 14:55:14 +053074 Agent: event.NewAgent(eventProxy, coreInstanceID, cf.VolthaStackID),
Kent Hagerman2b216042020-04-03 18:28:56 -040075 deviceLoadingInProgress: make(map[string][]chan int),
Maninder0aabf0c2021-03-17 14:55:14 +053076 config: cf,
Kent Hagerman2b216042020-04-03 18:28:56 -040077 }
Kent Hagerman6031aad2020-07-29 16:36:33 -040078 deviceMgr.stateTransitions = state.NewTransitionMap(deviceMgr)
Kent Hagerman2f0d0552020-04-23 17:28:52 -040079
Kent Hagerman2b216042020-04-03 18:28:56 -040080 logicalDeviceMgr := &LogicalManager{
Maninder0aabf0c2021-03-17 14:55:14 +053081 Manager: event.NewManager(eventProxy, coreInstanceID, cf.VolthaStackID),
Kent Hagerman2b216042020-04-03 18:28:56 -040082 deviceMgr: deviceMgr,
Mahir Gunyel03de0d32020-06-03 01:36:59 -070083 dbPath: dbPath,
84 ldProxy: dbPath.Proxy("logical_devices"),
khenaidood948f772021-08-11 17:49:24 -040085 internalTimeout: cf.InternalTimeout,
Kent Hagerman2b216042020-04-03 18:28:56 -040086 logicalDeviceLoadingInProgress: make(map[string][]chan int),
87 }
88 deviceMgr.logicalDeviceMgr = logicalDeviceMgr
Matteo Scandolod525ae32020-04-02 17:27:29 -070089
khenaidood948f772021-08-11 17:49:24 -040090 adapterMgr.SetAdapterRestartedCallback(deviceMgr.adapterRestartedHandler)
Matteo Scandolod525ae32020-04-02 17:27:29 -070091
Kent Hagerman2b216042020-04-03 18:28:56 -040092 return deviceMgr, logicalDeviceMgr
khenaidoob9203542018-09-17 22:56:37 -040093}
94
khenaidood948f772021-08-11 17:49:24 -040095func (dMgr *Manager) Start(ctx context.Context, serviceName string) error {
khenaidoo7585a962021-06-10 16:15:38 -040096 logger.Info(ctx, "starting-device-manager")
khenaidood948f772021-08-11 17:49:24 -040097 probe.UpdateStatusFromContext(ctx, serviceName, probe.ServiceStatusPreparing)
khenaidoo7585a962021-06-10 16:15:38 -040098
99 // Load all the devices from the dB
100 var devices []*voltha.Device
101 if err := dMgr.dProxy.List(ctx, &devices); err != nil {
102 // Any error from the dB means if we proceed we may end up with corrupted data
khenaidood948f772021-08-11 17:49:24 -0400103 logger.Errorw(ctx, "failed-to-list-devices-from-KV", log.Fields{"error": err, "service-name": serviceName})
104 return err
105 }
106
107 defer probe.UpdateStatusFromContext(ctx, serviceName, probe.ServiceStatusRunning)
108
109 if len(devices) == 0 {
110 logger.Info(ctx, "no-device-to-load")
111 return nil
khenaidoo7585a962021-06-10 16:15:38 -0400112 }
113
114 for _, device := range devices {
115 // Create an agent for each device
Himani Chawla4b4bd252021-11-08 15:59:40 +0530116 agent := newAgent(device, dMgr, dMgr.dbPath, dMgr.dProxy, dMgr.internalTimeout, dMgr.rpcTimeout, dMgr.flowTimeout)
khenaidoo7585a962021-06-10 16:15:38 -0400117 if _, err := agent.start(ctx, true, device); err != nil {
118 logger.Warnw(ctx, "failure-starting-agent", log.Fields{"device-id": device.Id})
119 } else {
120 dMgr.addDeviceAgentToMap(agent)
121 }
122 }
123
124 // TODO: Need to trigger a reconcile at this point
125
khenaidoo7585a962021-06-10 16:15:38 -0400126 logger.Info(ctx, "device-manager-started")
khenaidood948f772021-08-11 17:49:24 -0400127
128 return nil
khenaidoo7585a962021-06-10 16:15:38 -0400129}
130
Kent Hagerman2b216042020-04-03 18:28:56 -0400131func (dMgr *Manager) addDeviceAgentToMap(agent *Agent) {
npujar1d86a522019-11-14 17:11:16 +0530132 if _, exist := dMgr.deviceAgents.Load(agent.deviceID); !exist {
133 dMgr.deviceAgents.Store(agent.deviceID, agent)
khenaidoob9203542018-09-17 22:56:37 -0400134 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400135 dMgr.lockRootDeviceMap.Lock()
136 defer dMgr.lockRootDeviceMap.Unlock()
Kent Hagerman2a07b862020-06-19 15:23:07 -0400137 dMgr.rootDevices[agent.deviceID] = agent.isRootDevice
khenaidoo2c6a0992019-04-29 13:46:56 -0400138
khenaidoob9203542018-09-17 22:56:37 -0400139}
140
Kent Hagerman2b216042020-04-03 18:28:56 -0400141func (dMgr *Manager) deleteDeviceAgentFromMap(agent *Agent) {
npujar1d86a522019-11-14 17:11:16 +0530142 dMgr.deviceAgents.Delete(agent.deviceID)
khenaidoo2c6a0992019-04-29 13:46:56 -0400143 dMgr.lockRootDeviceMap.Lock()
144 defer dMgr.lockRootDeviceMap.Unlock()
npujar1d86a522019-11-14 17:11:16 +0530145 delete(dMgr.rootDevices, agent.deviceID)
khenaidoo4d4802d2018-10-04 21:59:49 -0400146}
147
khenaidoo297cd252019-02-07 22:10:23 -0500148// 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 -0400149func (dMgr *Manager) getDeviceAgent(ctx context.Context, deviceID string) *Agent {
npujar1d86a522019-11-14 17:11:16 +0530150 agent, ok := dMgr.deviceAgents.Load(deviceID)
151 if ok {
Kent Hagerman2b216042020-04-03 18:28:56 -0400152 return agent.(*Agent)
khenaidoob9203542018-09-17 22:56:37 -0400153 }
khenaidoo442e7c72020-03-10 16:13:48 -0400154 // Try to load into memory - loading will also create the device agent and set the device ownership
npujar467fe752020-01-16 20:17:45 +0530155 err := dMgr.load(ctx, deviceID)
npujar1d86a522019-11-14 17:11:16 +0530156 if err == nil {
157 agent, ok = dMgr.deviceAgents.Load(deviceID)
158 if !ok {
159 return nil
160 }
Kent Hagerman2b216042020-04-03 18:28:56 -0400161 return agent.(*Agent)
npujar1d86a522019-11-14 17:11:16 +0530162 }
163 //TODO: Change the return params to return an error as well
divyadesaicb8b59d2020-08-18 09:55:47 +0000164 logger.Errorw(ctx, "loading-device-failed", log.Fields{"device-id": deviceID, "error": err})
khenaidoob9203542018-09-17 22:56:37 -0400165 return nil
166}
167
khenaidoo297cd252019-02-07 22:10:23 -0500168// listDeviceIdsFromMap returns the list of device IDs that are in memory
Kent Hagerman2b216042020-04-03 18:28:56 -0400169func (dMgr *Manager) listDeviceIdsFromMap() *voltha.IDs {
khenaidoo7ccedd52018-12-14 16:48:54 -0500170 result := &voltha.IDs{Items: make([]*voltha.ID, 0)}
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400171
172 dMgr.deviceAgents.Range(func(key, value interface{}) bool {
173 result.Items = append(result.Items, &voltha.ID{Id: key.(string)})
174 return true
175 })
176
khenaidoo7ccedd52018-12-14 16:48:54 -0500177 return result
178}
179
khenaidoo6d62c002019-05-15 21:57:03 -0400180// stopManagingDevice stops the management of the device as well as any of its reference device and logical device.
181// This function is called only in the Core that does not own this device. In the Core that owns this device then a
182// deletion deletion also includes removal of any reference of this device.
Kent Hagerman2b216042020-04-03 18:28:56 -0400183func (dMgr *Manager) stopManagingDevice(ctx context.Context, id string) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530184 logger.Infow(ctx, "stop-managing-device", log.Fields{"device-id": id})
khenaidoo6d62c002019-05-15 21:57:03 -0400185 if dMgr.IsDeviceInCache(id) { // Proceed only if an agent is present for this device
Kent Hagerman6031aad2020-07-29 16:36:33 -0400186 if device, err := dMgr.getDeviceReadOnly(ctx, id); err == nil && device.Root {
khenaidoo6d62c002019-05-15 21:57:03 -0400187 // stop managing the logical device
David Bainbridged1afd662020-03-26 18:27:41 -0700188 _ = dMgr.logicalDeviceMgr.stopManagingLogicalDeviceWithDeviceID(ctx, id)
khenaidoo6d62c002019-05-15 21:57:03 -0400189 }
npujar467fe752020-01-16 20:17:45 +0530190 if agent := dMgr.getDeviceAgent(ctx, id); agent != nil {
khenaidoo442e7c72020-03-10 16:13:48 -0400191 if err := agent.stop(ctx); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000192 logger.Warnw(ctx, "unable-to-stop-device-agent", log.Fields{"device-id": agent.deviceID, "error": err})
khenaidoo442e7c72020-03-10 16:13:48 -0400193 }
khenaidoo4c9e5592019-09-09 16:20:41 -0400194 dMgr.deleteDeviceAgentFromMap(agent)
khenaidoo6d62c002019-05-15 21:57:03 -0400195 }
196 }
197}
198
Kent Hagermancba2f302020-07-28 13:37:36 -0400199// getDeviceReadOnly will returns a device, either from memory or from the dB, if present
200func (dMgr *Manager) getDeviceReadOnly(ctx context.Context, id string) (*voltha.Device, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530201 logger.Debugw(ctx, "get-device-read-only", log.Fields{"device-id": id})
npujar467fe752020-01-16 20:17:45 +0530202 if agent := dMgr.getDeviceAgent(ctx, id); agent != nil {
Kent Hagermancba2f302020-07-28 13:37:36 -0400203 return agent.getDeviceReadOnly(ctx)
khenaidoo92e62c52018-10-03 14:02:54 -0400204 }
205 return nil, status.Errorf(codes.NotFound, "%s", id)
khenaidoob9203542018-09-17 22:56:37 -0400206}
207
Kent Hagerman2a07b862020-06-19 15:23:07 -0400208func (dMgr *Manager) listDevicePorts(ctx context.Context, id string) (map[uint32]*voltha.Port, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530209 logger.Debugw(ctx, "list-device-ports", log.Fields{"device-id": id})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400210 agent := dMgr.getDeviceAgent(ctx, id)
211 if agent == nil {
212 return nil, status.Errorf(codes.NotFound, "%s", id)
213 }
214 return agent.listDevicePorts(), nil
215}
216
npujar1d86a522019-11-14 17:11:16 +0530217// IsDeviceInCache returns true if device is found in the map
Kent Hagerman2b216042020-04-03 18:28:56 -0400218func (dMgr *Manager) IsDeviceInCache(id string) bool {
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400219 _, exist := dMgr.deviceAgents.Load(id)
khenaidoo297cd252019-02-07 22:10:23 -0500220 return exist
221}
222
Thomas Lee S51b5cb82019-10-14 14:49:34 +0530223//isParentDeviceExist checks whether device is already preprovisioned.
Kent Hagerman2b216042020-04-03 18:28:56 -0400224func (dMgr *Manager) isParentDeviceExist(ctx context.Context, newDevice *voltha.Device) (bool, error) {
Thomas Lee S51b5cb82019-10-14 14:49:34 +0530225 hostPort := newDevice.GetHostAndPort()
Kent Hagerman4f355f52020-03-30 16:01:33 -0400226 var devices []*voltha.Device
Kent Hagermanf5a67352020-04-30 15:15:26 -0400227 if err := dMgr.dProxy.List(ctx, &devices); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530228 logger.Errorw(ctx, "failed-to-list-devices-from-cluster-data-proxy", log.Fields{"error": err})
Thomas Lee Se5a44012019-11-07 20:32:24 +0530229 return false, err
230 }
Kent Hagerman4f355f52020-03-30 16:01:33 -0400231 for _, device := range devices {
232 if !device.Root {
233 continue
234 }
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530235
236 if hostPort != "" && hostPort == device.GetHostAndPort() {
Kent Hagerman4f355f52020-03-30 16:01:33 -0400237 return true, nil
238 }
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530239 if newDevice.MacAddress != "" && newDevice.MacAddress == device.MacAddress {
Kent Hagerman4f355f52020-03-30 16:01:33 -0400240 return true, nil
Thomas Lee S51b5cb82019-10-14 14:49:34 +0530241 }
242 }
Thomas Lee Se5a44012019-11-07 20:32:24 +0530243 return false, nil
Thomas Lee S51b5cb82019-10-14 14:49:34 +0530244}
245
khenaidoo6d62c002019-05-15 21:57:03 -0400246//getDeviceFromModelretrieves the device data from the model.
Kent Hagerman2b216042020-04-03 18:28:56 -0400247func (dMgr *Manager) getDeviceFromModel(ctx context.Context, deviceID string) (*voltha.Device, error) {
Kent Hagerman4f355f52020-03-30 16:01:33 -0400248 device := &voltha.Device{}
Kent Hagermanf5a67352020-04-30 15:15:26 -0400249 if have, err := dMgr.dProxy.Get(ctx, deviceID, device); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000250 logger.Errorw(ctx, "failed-to-get-device-info-from-cluster-proxy", log.Fields{"error": err})
Thomas Lee Se5a44012019-11-07 20:32:24 +0530251 return nil, err
Kent Hagerman4f355f52020-03-30 16:01:33 -0400252 } else if !have {
253 return nil, status.Error(codes.NotFound, deviceID)
Thomas Lee Se5a44012019-11-07 20:32:24 +0530254 }
Kent Hagerman4f355f52020-03-30 16:01:33 -0400255
256 return device, nil
khenaidoo6d62c002019-05-15 21:57:03 -0400257}
258
npujar1d86a522019-11-14 17:11:16 +0530259// loadDevice loads the deviceID in memory, if not present
Kent Hagerman2b216042020-04-03 18:28:56 -0400260func (dMgr *Manager) loadDevice(ctx context.Context, deviceID string) (*Agent, error) {
npujar1d86a522019-11-14 17:11:16 +0530261 if deviceID == "" {
khenaidoo297cd252019-02-07 22:10:23 -0500262 return nil, status.Error(codes.InvalidArgument, "deviceId empty")
263 }
khenaidoo4c9e5592019-09-09 16:20:41 -0400264 var err error
265 var device *voltha.Device
266 dMgr.devicesLoadingLock.Lock()
npujar1d86a522019-11-14 17:11:16 +0530267 if _, exist := dMgr.deviceLoadingInProgress[deviceID]; !exist {
268 if !dMgr.IsDeviceInCache(deviceID) {
269 dMgr.deviceLoadingInProgress[deviceID] = []chan int{make(chan int, 1)}
khenaidoo4c9e5592019-09-09 16:20:41 -0400270 dMgr.devicesLoadingLock.Unlock()
271 // Proceed with the loading only if the device exist in the Model (could have been deleted)
npujar467fe752020-01-16 20:17:45 +0530272 if device, err = dMgr.getDeviceFromModel(ctx, deviceID); err == nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000273 logger.Debugw(ctx, "loading-device", log.Fields{"device-id": deviceID})
Himani Chawla4b4bd252021-11-08 15:59:40 +0530274 agent := newAgent(device, dMgr, dMgr.dbPath, dMgr.dProxy, dMgr.internalTimeout, dMgr.rpcTimeout, dMgr.flowTimeout)
khenaidoo7585a962021-06-10 16:15:38 -0400275 if _, err = agent.start(ctx, true, device); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530276 logger.Warnw(ctx, "failure-loading-device", log.Fields{"device-id": deviceID, "error": err})
khenaidoo4c9e5592019-09-09 16:20:41 -0400277 } else {
278 dMgr.addDeviceAgentToMap(agent)
279 }
280 } else {
Himani Chawlab4c25912020-11-12 17:16:38 +0530281 logger.Debugw(ctx, "device-is-not-in-model", log.Fields{"device-id": deviceID})
khenaidoo6d62c002019-05-15 21:57:03 -0400282 }
khenaidoo4c9e5592019-09-09 16:20:41 -0400283 // announce completion of task to any number of waiting channels
284 dMgr.devicesLoadingLock.Lock()
npujar1d86a522019-11-14 17:11:16 +0530285 if v, ok := dMgr.deviceLoadingInProgress[deviceID]; ok {
khenaidoo4c9e5592019-09-09 16:20:41 -0400286 for _, ch := range v {
287 close(ch)
288 }
npujar1d86a522019-11-14 17:11:16 +0530289 delete(dMgr.deviceLoadingInProgress, deviceID)
khenaidoo4c9e5592019-09-09 16:20:41 -0400290 }
291 dMgr.devicesLoadingLock.Unlock()
khenaidoo6d62c002019-05-15 21:57:03 -0400292 } else {
khenaidoo4c9e5592019-09-09 16:20:41 -0400293 dMgr.devicesLoadingLock.Unlock()
khenaidoo297cd252019-02-07 22:10:23 -0500294 }
khenaidoo4c9e5592019-09-09 16:20:41 -0400295 } else {
296 ch := make(chan int, 1)
npujar1d86a522019-11-14 17:11:16 +0530297 dMgr.deviceLoadingInProgress[deviceID] = append(dMgr.deviceLoadingInProgress[deviceID], ch)
khenaidoo4c9e5592019-09-09 16:20:41 -0400298 dMgr.devicesLoadingLock.Unlock()
299 // Wait for the channel to be closed, implying the process loading this device is done.
300 <-ch
khenaidoo297cd252019-02-07 22:10:23 -0500301 }
npujar1d86a522019-11-14 17:11:16 +0530302 if agent, ok := dMgr.deviceAgents.Load(deviceID); ok {
Kent Hagerman2b216042020-04-03 18:28:56 -0400303 return agent.(*Agent), nil
khenaidoo297cd252019-02-07 22:10:23 -0500304 }
npujar1d86a522019-11-14 17:11:16 +0530305 return nil, status.Errorf(codes.Aborted, "Error loading device %s", deviceID)
khenaidoo297cd252019-02-07 22:10:23 -0500306}
307
308// loadRootDeviceParentAndChildren loads the children and parents of a root device in memory
Kent Hagerman2a07b862020-06-19 15:23:07 -0400309func (dMgr *Manager) loadRootDeviceParentAndChildren(ctx context.Context, device *voltha.Device, devicePorts map[uint32]*voltha.Port) error {
divyadesaicb8b59d2020-08-18 09:55:47 +0000310 logger.Debugw(ctx, "loading-parent-and-children", log.Fields{"device-id": device.Id})
khenaidoo297cd252019-02-07 22:10:23 -0500311 if device.Root {
312 // Scenario A
313 if device.ParentId != "" {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400314 // Load logical device if needed.
npujar467fe752020-01-16 20:17:45 +0530315 if err := dMgr.logicalDeviceMgr.load(ctx, device.ParentId); err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000316 logger.Warnw(ctx, "failure-loading-logical-device", log.Fields{"logical-device-id": device.ParentId})
khenaidoo297cd252019-02-07 22:10:23 -0500317 }
318 } else {
divyadesaicb8b59d2020-08-18 09:55:47 +0000319 logger.Debugw(ctx, "no-parent-to-load", log.Fields{"device-id": device.Id})
khenaidoo297cd252019-02-07 22:10:23 -0500320 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400321 // Load all child devices, if needed
322 childDeviceIds := dMgr.getAllChildDeviceIds(ctx, devicePorts)
323 for childDeviceID := range childDeviceIds {
324 if _, err := dMgr.loadDevice(ctx, childDeviceID); err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000325 logger.Warnw(ctx, "failure-loading-device", log.Fields{"device-id": childDeviceID, "error": err})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400326 return err
khenaidoo297cd252019-02-07 22:10:23 -0500327 }
khenaidoo297cd252019-02-07 22:10:23 -0500328 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530329 logger.Debugw(ctx, "loaded-children", log.Fields{"device-id": device.Id, "num-children": len(childDeviceIds)})
khenaidoo297cd252019-02-07 22:10:23 -0500330 }
331 return nil
332}
333
334// load loads the deviceId in memory, if not present, and also loads its accompanying parents and children. Loading
335// in memory is for improved performance. It is not imperative that a device needs to be in memory when a request
336// acting on the device is received by the core. In such a scenario, the Core will load the device in memory first
337// and the proceed with the request.
Kent Hagerman2b216042020-04-03 18:28:56 -0400338func (dMgr *Manager) load(ctx context.Context, deviceID string) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000339 logger.Debug(ctx, "load...")
khenaidoo297cd252019-02-07 22:10:23 -0500340 // 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 -0400341 var dAgent *Agent
khenaidoo297cd252019-02-07 22:10:23 -0500342 var err error
npujar467fe752020-01-16 20:17:45 +0530343 if dAgent, err = dMgr.loadDevice(ctx, deviceID); err != nil {
khenaidoo297cd252019-02-07 22:10:23 -0500344 return err
345 }
346 // Get the loaded device details
Kent Hagermancba2f302020-07-28 13:37:36 -0400347 device, err := dAgent.getDeviceReadOnly(ctx)
khenaidoo442e7c72020-03-10 16:13:48 -0400348 if err != nil {
349 return err
350 }
khenaidoo297cd252019-02-07 22:10:23 -0500351
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530352 // If the device is in Pre-provisioning or getting deleted state stop here
353 if device.AdminState == voltha.AdminState_PREPROVISIONED || dAgent.isDeletionInProgress() {
khenaidoo297cd252019-02-07 22:10:23 -0500354 return nil
355 }
356
357 // Now we face two scenarios
358 if device.Root {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400359 devicePorts := dAgent.listDevicePorts()
360
khenaidoo297cd252019-02-07 22:10:23 -0500361 // Load all children as well as the parent of this device (logical_device)
Kent Hagerman2a07b862020-06-19 15:23:07 -0400362 if err := dMgr.loadRootDeviceParentAndChildren(ctx, device, devicePorts); err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000363 logger.Warnw(ctx, "failure-loading-device-parent-and-children", log.Fields{"device-id": deviceID})
khenaidoo297cd252019-02-07 22:10:23 -0500364 return err
365 }
divyadesaicb8b59d2020-08-18 09:55:47 +0000366 logger.Debugw(ctx, "successfully-loaded-parent-and-children", log.Fields{"device-id": deviceID})
Andrey Pozolotin34dd63f2021-05-31 21:26:40 +0300367 } else if device.ParentId != "" {
khenaidoo297cd252019-02-07 22:10:23 -0500368 // Scenario B - use the parentId of that device (root device) to trigger the loading
Andrey Pozolotin34dd63f2021-05-31 21:26:40 +0300369 return dMgr.load(ctx, device.ParentId)
khenaidoo297cd252019-02-07 22:10:23 -0500370 }
Andrey Pozolotin34dd63f2021-05-31 21:26:40 +0300371
khenaidoo297cd252019-02-07 22:10:23 -0500372 return nil
373}
374
khenaidooba6b6c42019-08-02 09:11:56 -0400375// adapterRestarted is invoked whenever an adapter is restarted
Kent Hagerman2b216042020-04-03 18:28:56 -0400376func (dMgr *Manager) adapterRestarted(ctx context.Context, adapter *voltha.Adapter) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530377 logger.Debugw(ctx, "adapter-restarted", log.Fields{"adapter-id": adapter.Id, "vendor": adapter.Vendor,
khenaidood948f772021-08-11 17:49:24 -0400378 "current-replica": adapter.CurrentReplica, "total-replicas": adapter.TotalReplicas, "restarted-endpoint": adapter.Endpoint})
khenaidooba6b6c42019-08-02 09:11:56 -0400379
khenaidood948f772021-08-11 17:49:24 -0400380 numberOfDevicesToReconcile := 0
381 dMgr.deviceAgents.Range(func(key, value interface{}) bool {
382 deviceAgent, ok := value.(*Agent)
383 if ok && deviceAgent.adapterEndpoint == adapter.Endpoint {
384 // Before reconciling, abort in-process request
385 if err := deviceAgent.abortAllProcessing(utils.WithNewSpanAndRPCMetadataContext(ctx, "AbortProcessingOnRestart")); err == nil {
386 logger.Debugw(ctx, "reconciling-device",
387 log.Fields{
388 "device-id": deviceAgent.deviceID,
389 "root-device": deviceAgent.isRootDevice,
390 "restarted-endpoint": adapter.Endpoint,
391 "device-type": deviceAgent.deviceType,
392 "adapter-type": adapter.Type,
393 })
394 go deviceAgent.ReconcileDevice(utils.WithNewSpanAndRPCMetadataContext(ctx, "ReconcileDevice"))
395 numberOfDevicesToReconcile++
396 } else {
397 logger.Errorw(ctx, "failed-aborting-exisiting-processing", log.Fields{"error": err})
khenaidooba6b6c42019-08-02 09:11:56 -0400398 }
399 }
khenaidood948f772021-08-11 17:49:24 -0400400 return true
401 })
402 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 -0400403 return nil
404}
405
Kent Hagerman2b216042020-04-03 18:28:56 -0400406func (dMgr *Manager) UpdateDeviceUsingAdapterData(ctx context.Context, device *voltha.Device) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530407 logger.Debugw(ctx, "update-device-using-adapter-data", log.Fields{"device-id": device.Id, "device": device})
npujar467fe752020-01-16 20:17:45 +0530408 if agent := dMgr.getDeviceAgent(ctx, device.Id); agent != nil {
409 return agent.updateDeviceUsingAdapterData(ctx, device)
khenaidoob9203542018-09-17 22:56:37 -0400410 }
411 return status.Errorf(codes.NotFound, "%s", device.Id)
412}
413
khenaidoo0db4c812020-05-27 15:27:30 -0400414func (dMgr *Manager) addPeerPort(ctx context.Context, deviceID string, port *voltha.Port) error {
415 meAsPeer := &voltha.Port_PeerPort{DeviceId: deviceID, PortNo: port.PortNo}
416 for _, peerPort := range port.Peers {
417 if agent := dMgr.getDeviceAgent(ctx, peerPort.DeviceId); agent != nil {
418 if err := agent.addPeerPort(ctx, meAsPeer); err != nil {
419 return err
420 }
421 }
422 }
423 // Notify the logical device manager to setup a logical port, if needed. If the added port is an NNI or UNI
424 // then a logical port will be added to the logical device and the device route generated. If the port is a
425 // PON port then only the device graph will be generated.
Kent Hagermancba2f302020-07-28 13:37:36 -0400426 device, err := dMgr.getDeviceReadOnly(ctx, deviceID)
khenaidoo0db4c812020-05-27 15:27:30 -0400427 if err != nil {
428 return err
429 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400430 ports, err := dMgr.listDevicePorts(ctx, deviceID)
431 if err != nil {
432 return err
433 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530434 subCtx := utils.WithSpanAndRPCMetadataFromContext(ctx)
435
436 if err = dMgr.logicalDeviceMgr.updateLogicalPort(subCtx, device, ports, port); err != nil {
khenaidoo0db4c812020-05-27 15:27:30 -0400437 return err
438 }
439 return nil
440}
441
Kent Hagerman2b216042020-04-03 18:28:56 -0400442func (dMgr *Manager) AddPort(ctx context.Context, deviceID string, port *voltha.Port) error {
npujar467fe752020-01-16 20:17:45 +0530443 agent := dMgr.getDeviceAgent(ctx, deviceID)
npujar1d86a522019-11-14 17:11:16 +0530444 if agent != nil {
npujar467fe752020-01-16 20:17:45 +0530445 if err := agent.addPort(ctx, port); err != nil {
khenaidoo92e62c52018-10-03 14:02:54 -0400446 return err
447 }
khenaidoo0db4c812020-05-27 15:27:30 -0400448 // Setup peer ports in its own routine
449 go func() {
Himani Chawlab4c25912020-11-12 17:16:38 +0530450 subCtx := utils.WithSpanAndRPCMetadataFromContext(ctx)
451 if err := dMgr.addPeerPort(subCtx, deviceID, port); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000452 logger.Errorw(ctx, "unable-to-add-peer-port", log.Fields{"error": err, "device-id": deviceID})
khenaidoo92e62c52018-10-03 14:02:54 -0400453 }
khenaidoo0db4c812020-05-27 15:27:30 -0400454 }()
khenaidoo92e62c52018-10-03 14:02:54 -0400455 return nil
khenaidoob9203542018-09-17 22:56:37 -0400456 }
npujar1d86a522019-11-14 17:11:16 +0530457 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoob9203542018-09-17 22:56:37 -0400458}
459
khenaidood948f772021-08-11 17:49:24 -0400460func (dMgr *Manager) canMultipleAdapterRequestProceed(ctx context.Context, deviceIDs []string) error {
461 ready := len(deviceIDs) > 0
462 for _, deviceID := range deviceIDs {
463 agent := dMgr.getDeviceAgent(ctx, deviceID)
464 if agent == nil {
465 logger.Errorw(ctx, "adapter-nil", log.Fields{"device-id": deviceID})
466 return status.Errorf(codes.Unavailable, "adapter-nil-for-%s", deviceID)
467 }
468 ready = ready && agent.isAdapterConnectionUp(ctx)
469 if !ready {
470 return status.Errorf(codes.Unavailable, "adapter-connection-down-for-%s", deviceID)
471 }
472 if err := agent.canDeviceRequestProceed(ctx); err != nil {
473 return err
474 }
Himani Chawla4b4bd252021-11-08 15:59:40 +0530475 // Perform the same checks for parent device
476 if !agent.isRootDevice {
477 parentDeviceAgent := dMgr.getDeviceAgent(ctx, agent.parentID)
478 if parentDeviceAgent == nil {
479 logger.Errorw(ctx, "parent-device-adapter-nil", log.Fields{"parent-id": agent.parentID})
480 return status.Errorf(codes.Unavailable, "parent-device-adapter-nil-for-%s", deviceID)
481 }
482 if err := parentDeviceAgent.canDeviceRequestProceed(ctx); err != nil {
483 return err
484 }
485 }
486
khenaidood948f772021-08-11 17:49:24 -0400487 }
488 if !ready {
489 return status.Error(codes.Unavailable, "adapter(s)-not-ready")
490 }
491 return nil
492}
493
khenaidoo9beaaf12021-10-19 17:32:01 -0400494func (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 +0530495 logger.Debugw(ctx, "add-flows-and-groups", log.Fields{"device-id": deviceID, "groups:": groups, "flow-metadata": flowMetadata})
npujar467fe752020-01-16 20:17:45 +0530496 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
497 return agent.addFlowsAndGroups(ctx, flows, groups, flowMetadata)
khenaidoo0458db62019-06-20 08:50:36 -0400498 }
npujar1d86a522019-11-14 17:11:16 +0530499 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo0458db62019-06-20 08:50:36 -0400500}
501
khenaidoo787224a2020-04-16 18:08:47 -0400502// deleteParentFlows removes flows from the parent device based on specific attributes
khenaidoo9beaaf12021-10-19 17:32:01 -0400503func (dMgr *Manager) deleteParentFlows(ctx context.Context, deviceID string, uniPort uint32, metadata *ofp.FlowMetadata) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530504 logger.Debugw(ctx, "delete-parent-flows", log.Fields{"device-id": deviceID, "uni-port": uniPort, "metadata": metadata})
khenaidoo787224a2020-04-16 18:08:47 -0400505 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400506 if !agent.isRootDevice {
khenaidoo787224a2020-04-16 18:08:47 -0400507 return status.Errorf(codes.FailedPrecondition, "not-a-parent-device-%s", deviceID)
508 }
509 return agent.filterOutFlows(ctx, uniPort, metadata)
510 }
511 return status.Errorf(codes.NotFound, "%s", deviceID)
512}
513
khenaidoo9beaaf12021-10-19 17:32:01 -0400514func (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 +0530515 logger.Debugw(ctx, "delete-flows-and-groups", log.Fields{"device-id": deviceID})
npujar467fe752020-01-16 20:17:45 +0530516 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
517 return agent.deleteFlowsAndGroups(ctx, flows, groups, flowMetadata)
khenaidoo0458db62019-06-20 08:50:36 -0400518 }
npujar1d86a522019-11-14 17:11:16 +0530519 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo0458db62019-06-20 08:50:36 -0400520}
521
khenaidoo9beaaf12021-10-19 17:32:01 -0400522func (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 +0530523 logger.Debugw(ctx, "update-flows-and-groups", log.Fields{"device-id": deviceID})
npujar467fe752020-01-16 20:17:45 +0530524 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
525 return agent.updateFlowsAndGroups(ctx, flows, groups, flowMetadata)
khenaidoo19d7b632018-10-30 10:49:50 -0400526 }
npujar1d86a522019-11-14 17:11:16 +0530527 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo19d7b632018-10-30 10:49:50 -0400528}
529
Kent Hagerman2b216042020-04-03 18:28:56 -0400530// InitPmConfigs initialize the pm configs as defined by the adapter.
531func (dMgr *Manager) InitPmConfigs(ctx context.Context, deviceID string, pmConfigs *voltha.PmConfigs) error {
khenaidoob3127472019-07-24 21:04:55 -0400532 if pmConfigs.Id == "" {
533 return status.Errorf(codes.FailedPrecondition, "invalid-device-Id")
534 }
npujar467fe752020-01-16 20:17:45 +0530535 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
536 return agent.initPmConfigs(ctx, pmConfigs)
khenaidoob9203542018-09-17 22:56:37 -0400537 }
npujar1d86a522019-11-14 17:11:16 +0530538 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoob9203542018-09-17 22:56:37 -0400539}
540
khenaidoo9beaaf12021-10-19 17:32:01 -0400541func (dMgr *Manager) getSwitchCapability(ctx context.Context, deviceID string) (*ca.SwitchCapability, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530542 logger.Debugw(ctx, "get-switch-capability", log.Fields{"device-id": deviceID})
npujar467fe752020-01-16 20:17:45 +0530543 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
khenaidoob9203542018-09-17 22:56:37 -0400544 return agent.getSwitchCapability(ctx)
545 }
npujar1d86a522019-11-14 17:11:16 +0530546 return nil, status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoob9203542018-09-17 22:56:37 -0400547}
548
Kent Hagerman2b216042020-04-03 18:28:56 -0400549func (dMgr *Manager) UpdateDeviceStatus(ctx context.Context, deviceID string, operStatus voltha.OperStatus_Types, connStatus voltha.ConnectStatus_Types) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530550 logger.Debugw(ctx, "update-device-status", log.Fields{"device-id": deviceID, "oper-status": operStatus, "conn-status": connStatus})
npujar467fe752020-01-16 20:17:45 +0530551 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
552 return agent.updateDeviceStatus(ctx, operStatus, connStatus)
khenaidoo92e62c52018-10-03 14:02:54 -0400553 }
npujar1d86a522019-11-14 17:11:16 +0530554 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo92e62c52018-10-03 14:02:54 -0400555}
556
Kent Hagerman2b216042020-04-03 18:28:56 -0400557func (dMgr *Manager) UpdateChildrenStatus(ctx context.Context, deviceID string, operStatus voltha.OperStatus_Types, connStatus voltha.ConnectStatus_Types) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530558 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 -0400559 parentDevicePorts, err := dMgr.listDevicePorts(ctx, deviceID)
560 if err != nil {
khenaidoo4d4802d2018-10-04 21:59:49 -0400561 return status.Errorf(codes.Aborted, "%s", err.Error())
562 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400563 for childDeviceID := range dMgr.getAllChildDeviceIds(ctx, parentDevicePorts) {
npujar467fe752020-01-16 20:17:45 +0530564 if agent := dMgr.getDeviceAgent(ctx, childDeviceID); agent != nil {
565 if err = agent.updateDeviceStatus(ctx, operStatus, connStatus); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530566 return status.Errorf(codes.Aborted, "childDevice:%s, error:%s", childDeviceID, err.Error())
khenaidoo4d4802d2018-10-04 21:59:49 -0400567 }
568 }
569 }
570 return nil
571}
572
Kent Hagerman2b216042020-04-03 18:28:56 -0400573func (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 +0530574 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 +0530575 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
576 if err := agent.updatePortState(ctx, portType, portNo, operStatus); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530577 logger.Errorw(ctx, "updating-port-state-failed", log.Fields{"device-id": deviceID, "port-no": portNo, "error": err})
khenaidoo171b98e2019-10-31 11:48:15 -0400578 return err
579 }
580 // Notify the logical device manager to change the port state
Mahir Gunyel18fa0c92020-03-06 13:34:04 -0800581 // Do this for NNI and UNIs only. PON ports are not known by logical device
582 if portType == voltha.Port_ETHERNET_NNI || portType == voltha.Port_ETHERNET_UNI {
583 go func() {
Himani Chawlab4c25912020-11-12 17:16:38 +0530584 subCtx := utils.WithSpanAndRPCMetadataFromContext(ctx)
585 err := dMgr.logicalDeviceMgr.updatePortState(subCtx, deviceID, portNo, operStatus)
Mahir Gunyel18fa0c92020-03-06 13:34:04 -0800586 if err != nil {
587 // While we want to handle (catch) and log when
588 // an update to a port was not able to be
589 // propagated to the logical port, we can report
590 // it as a warning and not an error because it
591 // doesn't stop or modify processing.
592 // TODO: VOL-2707
Rohan Agrawal31f21802020-06-12 05:38:46 +0000593 logger.Warnw(ctx, "unable-to-update-logical-port-state", log.Fields{"error": err})
Mahir Gunyel18fa0c92020-03-06 13:34:04 -0800594 }
595 }()
596 }
khenaidoo442e7c72020-03-10 16:13:48 -0400597 return nil
khenaidoob9203542018-09-17 22:56:37 -0400598 }
npujar1d86a522019-11-14 17:11:16 +0530599 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoob9203542018-09-17 22:56:37 -0400600}
601
Kent Hagerman2b216042020-04-03 18:28:56 -0400602//UpdatePortsState updates all ports on the device
Kent Hagerman2a07b862020-06-19 15:23:07 -0400603func (dMgr *Manager) UpdatePortsState(ctx context.Context, deviceID string, portTypeFilter uint32, state voltha.OperStatus_Types) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530604 logger.Debugw(ctx, "update-ports-state", log.Fields{"device-id": deviceID})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400605 agent := dMgr.getDeviceAgent(ctx, deviceID)
606 if agent == nil {
607 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo3ab34882019-05-02 21:33:30 -0400608 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400609 if state != voltha.OperStatus_ACTIVE && state != voltha.OperStatus_UNKNOWN {
610 return status.Error(codes.Unimplemented, "state-change-not-implemented")
611 }
612 if err := agent.updatePortsOperState(ctx, portTypeFilter, state); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530613 logger.Warnw(ctx, "update-ports-state-failed", log.Fields{"device-id": deviceID, "error": err})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400614 return err
615 }
616 return nil
khenaidoo3ab34882019-05-02 21:33:30 -0400617}
618
Kent Hagerman2b216042020-04-03 18:28:56 -0400619func (dMgr *Manager) packetOut(ctx context.Context, deviceID string, outPort uint32, packet *ofp.OfpPacketOut) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530620 logger.Debugw(ctx, "packet-out", log.Fields{"device-id": deviceID, "out-port": outPort})
npujar467fe752020-01-16 20:17:45 +0530621 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
622 return agent.packetOut(ctx, outPort, packet)
khenaidoofdbad6e2018-11-06 22:26:38 -0500623 }
npujar1d86a522019-11-14 17:11:16 +0530624 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoofdbad6e2018-11-06 22:26:38 -0500625}
626
npujar1d86a522019-11-14 17:11:16 +0530627// PacketIn receives packet from adapter
Kent Hagerman2b216042020-04-03 18:28:56 -0400628func (dMgr *Manager) PacketIn(ctx context.Context, deviceID string, port uint32, transactionID string, packet []byte) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530629 logger.Debugw(ctx, "packet-in", log.Fields{"device-id": deviceID, "port": port})
khenaidoofdbad6e2018-11-06 22:26:38 -0500630 // Get the logical device Id based on the deviceId
631 var device *voltha.Device
632 var err error
Kent Hagermancba2f302020-07-28 13:37:36 -0400633 if device, err = dMgr.getDeviceReadOnly(ctx, deviceID); err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000634 logger.Errorw(ctx, "device-not-found", log.Fields{"device-id": deviceID})
khenaidoofdbad6e2018-11-06 22:26:38 -0500635 return err
636 }
khenaidoo43c82122018-11-22 18:38:28 -0500637 if !device.Root {
divyadesaicb8b59d2020-08-18 09:55:47 +0000638 logger.Errorw(ctx, "device-not-root", log.Fields{"device-id": deviceID})
npujar1d86a522019-11-14 17:11:16 +0530639 return status.Errorf(codes.FailedPrecondition, "%s", deviceID)
khenaidoofdbad6e2018-11-06 22:26:38 -0500640 }
641
khenaidood948f772021-08-11 17:49:24 -0400642 if err := dMgr.logicalDeviceMgr.packetIn(ctx, device.ParentId, port, packet); err != nil {
khenaidoofdbad6e2018-11-06 22:26:38 -0500643 return err
644 }
645 return nil
646}
647
Kent Hagerman2b216042020-04-03 18:28:56 -0400648func (dMgr *Manager) setParentID(ctx context.Context, device *voltha.Device, parentID string) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530649 logger.Debugw(ctx, "set-parent-id", log.Fields{"device-id": device.Id, "parent-id": parentID})
npujar467fe752020-01-16 20:17:45 +0530650 if agent := dMgr.getDeviceAgent(ctx, device.Id); agent != nil {
651 return agent.setParentID(ctx, device, parentID)
khenaidooad06fd72019-10-28 12:26:05 -0400652 }
653 return status.Errorf(codes.NotFound, "%s", device.Id)
654}
655
Kent Hagerman2b216042020-04-03 18:28:56 -0400656func (dMgr *Manager) getParentDevice(ctx context.Context, childDevice *voltha.Device) *voltha.Device {
khenaidoo92e62c52018-10-03 14:02:54 -0400657 // Sanity check
658 if childDevice.Root {
659 // childDevice is the parent device
660 return childDevice
661 }
Kent Hagermancba2f302020-07-28 13:37:36 -0400662 parentDevice, _ := dMgr.getDeviceReadOnly(ctx, childDevice.ParentId)
khenaidoo92e62c52018-10-03 14:02:54 -0400663 return parentDevice
664}
665
khenaidoo4d4802d2018-10-04 21:59:49 -0400666/*
667All the functions below are callback functions where they are invoked with the latest and previous data. We can
668therefore use the data as is without trying to get the latest from the model.
669*/
670
khenaidoo0a822f92019-05-08 15:15:57 -0400671//DisableAllChildDevices is invoked as a callback when the parent device is disabled
Kent Hagerman2b216042020-04-03 18:28:56 -0400672func (dMgr *Manager) DisableAllChildDevices(ctx context.Context, parentCurrDevice *voltha.Device) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530673 logger.Debug(ctx, "disable-all-child-devices")
Kent Hagerman2a07b862020-06-19 15:23:07 -0400674 ports, _ := dMgr.listDevicePorts(ctx, parentCurrDevice.Id)
675 for childDeviceID := range dMgr.getAllChildDeviceIds(ctx, ports) {
npujar467fe752020-01-16 20:17:45 +0530676 if agent := dMgr.getDeviceAgent(ctx, childDeviceID); agent != nil {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400677 if err := agent.disableDevice(ctx); err != nil {
khenaidooe132f522020-03-20 15:23:15 -0400678 // Just log the error - this error happens only if the child device was already in deleted state.
divyadesaicb8b59d2020-08-18 09:55:47 +0000679 logger.Errorw(ctx, "failure-disable-device", log.Fields{"device-id": childDeviceID, "error": err.Error()})
khenaidoo92e62c52018-10-03 14:02:54 -0400680 }
681 }
682 }
683 return nil
684}
685
khenaidoo4d4802d2018-10-04 21:59:49 -0400686//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 -0400687func (dMgr *Manager) getAllChildDeviceIds(ctx context.Context, parentDevicePorts map[uint32]*voltha.Port) map[string]struct{} {
Himani Chawlab4c25912020-11-12 17:16:38 +0530688 logger.Debug(ctx, "get-all-child-device-ids")
Kent Hagerman2a07b862020-06-19 15:23:07 -0400689 childDeviceIds := make(map[string]struct{}, len(parentDevicePorts))
690 for _, port := range parentDevicePorts {
691 for _, peer := range port.Peers {
692 childDeviceIds[peer.DeviceId] = struct{}{}
khenaidoo92e62c52018-10-03 14:02:54 -0400693 }
694 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400695 logger.Debugw(ctx, "returning-getAllChildDeviceIds", log.Fields{"childDeviceIds": childDeviceIds})
696 return childDeviceIds
khenaidoo92e62c52018-10-03 14:02:54 -0400697}
698
khenaidood948f772021-08-11 17:49:24 -0400699//GgtAllChildDevices is a helper method to get all the child device IDs from the device passed as parameter
700func (dMgr *Manager) getAllChildDevices(ctx context.Context, parentDeviceID string) (*voltha.Devices, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530701 logger.Debugw(ctx, "get-all-child-devices", log.Fields{"parent-device-id": parentDeviceID})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400702 if parentDevicePorts, err := dMgr.listDevicePorts(ctx, parentDeviceID); err == nil {
khenaidoo297cd252019-02-07 22:10:23 -0500703 childDevices := make([]*voltha.Device, 0)
Kent Hagerman2a07b862020-06-19 15:23:07 -0400704 for deviceID := range dMgr.getAllChildDeviceIds(ctx, parentDevicePorts) {
Kent Hagermancba2f302020-07-28 13:37:36 -0400705 if d, e := dMgr.getDeviceReadOnly(ctx, deviceID); e == nil && d != nil {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400706 childDevices = append(childDevices, d)
khenaidoo297cd252019-02-07 22:10:23 -0500707 }
708 }
709 return &voltha.Devices{Items: childDevices}, nil
710 }
npujar1d86a522019-11-14 17:11:16 +0530711 return nil, status.Errorf(codes.NotFound, "%s", parentDeviceID)
khenaidoo297cd252019-02-07 22:10:23 -0500712}
713
Rohan Agrawal31f21802020-06-12 05:38:46 +0000714func (dMgr *Manager) NotifyInvalidTransition(ctx context.Context, device *voltha.Device) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530715 logger.Errorw(ctx, "notify-invalid-transition", log.Fields{
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500716 "device": device.Id,
717 "curr-admin-state": device.AdminState,
718 "curr-oper-state": device.OperStatus,
719 "curr-conn-state": device.ConnectStatus,
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400720 })
khenaidoo0a822f92019-05-08 15:15:57 -0400721 //TODO: notify over kafka?
722 return nil
723}
724
npujar1d86a522019-11-14 17:11:16 +0530725// UpdateDeviceAttribute updates value of particular device attribute
Kent Hagerman2b216042020-04-03 18:28:56 -0400726func (dMgr *Manager) UpdateDeviceAttribute(ctx context.Context, deviceID string, attribute string, value interface{}) {
npujar1d86a522019-11-14 17:11:16 +0530727 if agent, ok := dMgr.deviceAgents.Load(deviceID); ok {
Kent Hagerman2b216042020-04-03 18:28:56 -0400728 agent.(*Agent).updateDeviceAttribute(ctx, attribute, value)
khenaidoob9203542018-09-17 22:56:37 -0400729 }
730}
731
npujar1d86a522019-11-14 17:11:16 +0530732// GetParentDeviceID returns parent device id, either from memory or from the dB, if present
Kent Hagerman2b216042020-04-03 18:28:56 -0400733func (dMgr *Manager) GetParentDeviceID(ctx context.Context, deviceID string) string {
Kent Hagermancba2f302020-07-28 13:37:36 -0400734 if device, _ := dMgr.getDeviceReadOnly(ctx, deviceID); device != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530735 logger.Infow(ctx, "get-parent-device-id", log.Fields{"device-id": device.Id, "parent-id": device.ParentId})
khenaidoo4c9e5592019-09-09 16:20:41 -0400736 return device.ParentId
khenaidoob9203542018-09-17 22:56:37 -0400737 }
khenaidoo4c9e5592019-09-09 16:20:41 -0400738 return ""
khenaidoob9203542018-09-17 22:56:37 -0400739}
serkant.uluderya334479d2019-04-10 08:26:15 -0700740
Kent Hagerman2b216042020-04-03 18:28:56 -0400741func (dMgr *Manager) UpdateDeviceReason(ctx context.Context, deviceID string, reason string) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530742 logger.Debugw(ctx, "update-device-reason", log.Fields{"device-id": deviceID, "reason": reason})
npujar467fe752020-01-16 20:17:45 +0530743 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
744 return agent.updateDeviceReason(ctx, reason)
Mahir Gunyelfdee9212019-10-16 16:52:21 -0700745 }
npujar1d86a522019-11-14 17:11:16 +0530746 return status.Errorf(codes.NotFound, "%s", deviceID)
Mahir Gunyelfdee9212019-10-16 16:52:21 -0700747}
kesavandbc2d1622020-01-21 00:42:01 -0500748
Himani Chawlab4c25912020-11-12 17:16:38 +0530749func (dMgr *Manager) SendRPCEvent(ctx context.Context, id string, rpcEvent *voltha.RPCEvent,
750 category voltha.EventCategory_Types, subCategory *voltha.EventSubCategory_Types, raisedTs int64) {
751 //TODO Instead of directly sending to the kafka bus, queue the message and send it asynchronously
Mahir Gunyelb0343bf2021-05-11 14:14:26 -0700752 dMgr.Agent.SendRPCEvent(ctx, id, rpcEvent, category, subCategory, raisedTs)
Himani Chawlab4c25912020-11-12 17:16:38 +0530753}
Manindera496f852021-02-22 09:57:56 +0530754
khenaidood948f772021-08-11 17:49:24 -0400755func (dMgr *Manager) GetTransientState(ctx context.Context, id string) (core.DeviceTransientState_Types, error) {
Manindera496f852021-02-22 09:57:56 +0530756 agent := dMgr.getDeviceAgent(ctx, id)
757 if agent == nil {
khenaidood948f772021-08-11 17:49:24 -0400758 return core.DeviceTransientState_NONE, status.Errorf(codes.NotFound, "%s", id)
Manindera496f852021-02-22 09:57:56 +0530759 }
760 return agent.getTransientState(), nil
761}
ssiddiquif076cb82021-04-23 10:47:04 +0530762
ssiddiquif076cb82021-04-23 10:47:04 +0530763func (dMgr *Manager) validateImageDownloadRequest(request *voltha.DeviceImageDownloadRequest) error {
764 if request == nil || request.Image == nil || len(request.DeviceId) == 0 {
765 return status.Errorf(codes.InvalidArgument, "invalid argument")
766 }
767
768 for _, deviceID := range request.DeviceId {
769 if deviceID == nil {
770 return status.Errorf(codes.InvalidArgument, "id is nil")
771 }
772 }
773 return nil
774}
775
776func (dMgr *Manager) validateImageRequest(request *voltha.DeviceImageRequest) error {
777 if request == nil || len(request.DeviceId) == 0 || request.DeviceId[0] == nil {
778 return status.Errorf(codes.InvalidArgument, "invalid argument")
779 }
780
781 for _, deviceID := range request.DeviceId {
782 if deviceID == nil {
783 return status.Errorf(codes.InvalidArgument, "id is nil")
784 }
785 }
786
787 return nil
788}
789
790func (dMgr *Manager) validateDeviceImageResponse(response *voltha.DeviceImageResponse) error {
791 if response == nil || len(response.GetDeviceImageStates()) == 0 || response.GetDeviceImageStates()[0] == nil {
792 return status.Errorf(codes.Internal, "invalid-response-from-adapter")
793 }
794
795 return nil
796}
797
798func (dMgr *Manager) waitForAllResponses(ctx context.Context, opName string, respCh chan []*voltha.DeviceImageState, expectedResps int) (*voltha.DeviceImageResponse, error) {
799 response := &voltha.DeviceImageResponse{}
800 respCount := 0
801 for {
802 select {
803 case resp, ok := <-respCh:
804 if !ok {
805 logger.Errorw(ctx, opName+"-failed", log.Fields{"error": "channel-closed"})
806 return response, status.Errorf(codes.Aborted, "channel-closed")
807 }
808
809 if resp != nil {
810 logger.Debugw(ctx, opName+"-result", log.Fields{"image-state": resp[0].GetImageState(), "device-id": resp[0].GetDeviceId()})
811 response.DeviceImageStates = append(response.DeviceImageStates, resp...)
812 }
813
814 respCount++
815
816 //check whether all responses received, if so, sent back the collated response
817 if respCount == expectedResps {
818 return response, nil
819 }
820 continue
821 case <-ctx.Done():
822 return nil, status.Errorf(codes.Aborted, opName+"-failed-%s", ctx.Err())
823 }
824 }
825}
Maninder0aabf0c2021-03-17 14:55:14 +0530826
827func (dMgr *Manager) ReconcilingCleanup(ctx context.Context, device *voltha.Device) error {
828 agent := dMgr.getDeviceAgent(ctx, device.Id)
829 if agent == nil {
830 logger.Errorf(ctx, "Not able to get device agent.")
831 return status.Errorf(codes.NotFound, "Not able to get device agent for device : %s", device.Id)
832 }
833 err := agent.reconcilingCleanup(ctx)
834 if err != nil {
835 logger.Errorf(ctx, err.Error())
836 return status.Errorf(codes.Internal, err.Error())
837 }
838 return nil
839}
khenaidood948f772021-08-11 17:49:24 -0400840
841func (dMgr *Manager) adapterRestartedHandler(ctx context.Context, endpoint string) error {
842 // Get the adapter corresponding to that endpoint
843 if a, _ := dMgr.adapterMgr.GetAdapterWithEndpoint(ctx, endpoint); a != nil {
844 return dMgr.adapterRestarted(ctx, a)
845 }
846 logger.Errorw(ctx, "restarted-adapter-not-found", log.Fields{"endpoint": endpoint})
847 return fmt.Errorf("restarted adapter at endpoint %s not found", endpoint)
848}