blob: 75435b1be0fb8bcf2da9ce1eb5ea455ebd2a996c [file] [log] [blame]
khenaidoob9203542018-09-17 22:56:37 -04001/*
2 * Copyright 2018-present Open Networking Foundation
3
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7
8 * http://www.apache.org/licenses/LICENSE-2.0
9
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
npujar1d86a522019-11-14 17:11:16 +053016
Kent Hagerman2b216042020-04-03 18:28:56 -040017package device
khenaidoob9203542018-09-17 22:56:37 -040018
19import (
20 "context"
21 "errors"
Maninder0aabf0c2021-03-17 14:55:14 +053022 "github.com/opencord/voltha-go/rw_core/config"
yasin sapli5458a1c2021-06-14 22:24:38 +000023 "github.com/opencord/voltha-lib-go/v5/pkg/probe"
David Bainbridged1afd662020-03-26 18:27:41 -070024 "sync"
25 "time"
26
Kent Hagerman45a13e42020-04-13 12:23:50 -040027 "github.com/golang/protobuf/ptypes/empty"
sbarbari17d7e222019-11-05 10:02:29 -050028 "github.com/opencord/voltha-go/db/model"
Kent Hagerman2b216042020-04-03 18:28:56 -040029 "github.com/opencord/voltha-go/rw_core/core/adapter"
Kent Hagermanf5a67352020-04-30 15:15:26 -040030 "github.com/opencord/voltha-go/rw_core/core/device/event"
Kent Hagerman2b216042020-04-03 18:28:56 -040031 "github.com/opencord/voltha-go/rw_core/core/device/remote"
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"
yasin sapli5458a1c2021-06-14 22:24:38 +000034 "github.com/opencord/voltha-lib-go/v5/pkg/events"
35 "github.com/opencord/voltha-lib-go/v5/pkg/kafka"
36 "github.com/opencord/voltha-lib-go/v5/pkg/log"
Maninderdfadc982020-10-28 14:04:33 +053037 "github.com/opencord/voltha-protos/v4/go/common"
38 ic "github.com/opencord/voltha-protos/v4/go/inter_container"
39 "github.com/opencord/voltha-protos/v4/go/openflow_13"
40 ofp "github.com/opencord/voltha-protos/v4/go/openflow_13"
41 "github.com/opencord/voltha-protos/v4/go/voltha"
khenaidoob9203542018-09-17 22:56:37 -040042 "google.golang.org/grpc/codes"
43 "google.golang.org/grpc/status"
khenaidoob9203542018-09-17 22:56:37 -040044)
45
Kent Hagerman2b216042020-04-03 18:28:56 -040046// Manager represent device manager attributes
47type Manager struct {
Himani Chawlab4c25912020-11-12 17:16:38 +053048 deviceAgents sync.Map
49 rootDevices map[string]bool
50 lockRootDeviceMap sync.RWMutex
51 adapterProxy *remote.AdapterProxy
Mahir Gunyelb0343bf2021-05-11 14:14:26 -070052 *event.Agent
Kent Hagerman2b216042020-04-03 18:28:56 -040053 adapterMgr *adapter.Manager
54 logicalDeviceMgr *LogicalManager
npujar467fe752020-01-16 20:17:45 +053055 kafkaICProxy kafka.InterContainerProxy
Kent Hagerman6031aad2020-07-29 16:36:33 -040056 stateTransitions *state.TransitionMap
Mahir Gunyel03de0d32020-06-03 01:36:59 -070057 dbPath *model.Path
Kent Hagermanf5a67352020-04-30 15:15:26 -040058 dProxy *model.Proxy
npujar1d86a522019-11-14 17:11:16 +053059 coreInstanceID string
khenaidoo442e7c72020-03-10 16:13:48 -040060 defaultTimeout time.Duration
khenaidoo4c9e5592019-09-09 16:20:41 -040061 devicesLoadingLock sync.RWMutex
62 deviceLoadingInProgress map[string][]chan int
Maninder0aabf0c2021-03-17 14:55:14 +053063 config *config.RWCoreFlags
khenaidoob9203542018-09-17 22:56:37 -040064}
65
Mahir Gunyel03de0d32020-06-03 01:36:59 -070066//NewManagers creates the Manager and the Logical Manager.
Maninder0aabf0c2021-03-17 14:55:14 +053067func NewManagers(dbPath *model.Path, adapterMgr *adapter.Manager, kmp kafka.InterContainerProxy, endpointMgr kafka.EndpointManager, cf *config.RWCoreFlags, coreInstanceID string, eventProxy *events.EventProxy) (*Manager, *LogicalManager) {
Kent Hagerman2b216042020-04-03 18:28:56 -040068 deviceMgr := &Manager{
Kent Hagerman2b216042020-04-03 18:28:56 -040069 rootDevices: make(map[string]bool),
70 kafkaICProxy: kmp,
Maninder0aabf0c2021-03-17 14:55:14 +053071 adapterProxy: remote.NewAdapterProxy(kmp, cf.CoreTopic, endpointMgr),
Kent Hagerman2b216042020-04-03 18:28:56 -040072 coreInstanceID: coreInstanceID,
Mahir Gunyel03de0d32020-06-03 01:36:59 -070073 dbPath: dbPath,
74 dProxy: dbPath.Proxy("devices"),
Kent Hagerman2b216042020-04-03 18:28:56 -040075 adapterMgr: adapterMgr,
Maninder0aabf0c2021-03-17 14:55:14 +053076 defaultTimeout: cf.DefaultCoreTimeout,
77 Agent: event.NewAgent(eventProxy, coreInstanceID, cf.VolthaStackID),
Kent Hagerman2b216042020-04-03 18:28:56 -040078 deviceLoadingInProgress: make(map[string][]chan int),
Maninder0aabf0c2021-03-17 14:55:14 +053079 config: cf,
Kent Hagerman2b216042020-04-03 18:28:56 -040080 }
Kent Hagerman6031aad2020-07-29 16:36:33 -040081 deviceMgr.stateTransitions = state.NewTransitionMap(deviceMgr)
Kent Hagerman2f0d0552020-04-23 17:28:52 -040082
Kent Hagerman2b216042020-04-03 18:28:56 -040083 logicalDeviceMgr := &LogicalManager{
Maninder0aabf0c2021-03-17 14:55:14 +053084 Manager: event.NewManager(eventProxy, coreInstanceID, cf.VolthaStackID),
Kent Hagerman2b216042020-04-03 18:28:56 -040085 deviceMgr: deviceMgr,
86 kafkaICProxy: kmp,
Mahir Gunyel03de0d32020-06-03 01:36:59 -070087 dbPath: dbPath,
88 ldProxy: dbPath.Proxy("logical_devices"),
Maninder0aabf0c2021-03-17 14:55:14 +053089 defaultTimeout: cf.DefaultCoreTimeout,
Kent Hagerman2b216042020-04-03 18:28:56 -040090 logicalDeviceLoadingInProgress: make(map[string][]chan int),
91 }
92 deviceMgr.logicalDeviceMgr = logicalDeviceMgr
Matteo Scandolod525ae32020-04-02 17:27:29 -070093
Kent Hagerman2b216042020-04-03 18:28:56 -040094 adapterMgr.SetAdapterRestartedCallback(deviceMgr.adapterRestarted)
Matteo Scandolod525ae32020-04-02 17:27:29 -070095
Kent Hagerman2b216042020-04-03 18:28:56 -040096 return deviceMgr, logicalDeviceMgr
khenaidoob9203542018-09-17 22:56:37 -040097}
98
khenaidoo7585a962021-06-10 16:15:38 -040099func (dMgr *Manager) Start(ctx context.Context) {
100 logger.Info(ctx, "starting-device-manager")
101 probe.UpdateStatusFromContext(ctx, "device-manager", probe.ServiceStatusPreparing)
102
103 // Load all the devices from the dB
104 var devices []*voltha.Device
105 if err := dMgr.dProxy.List(ctx, &devices); err != nil {
106 // Any error from the dB means if we proceed we may end up with corrupted data
107 logger.Fatalw(ctx, "failed-to-list-devices-from-KV", log.Fields{"error": err})
108 }
109
110 for _, device := range devices {
111 // Create an agent for each device
112 agent := newAgent(dMgr.adapterProxy, device, dMgr, dMgr.dbPath, dMgr.dProxy, dMgr.defaultTimeout)
113 if _, err := agent.start(ctx, true, device); err != nil {
114 logger.Warnw(ctx, "failure-starting-agent", log.Fields{"device-id": device.Id})
115 } else {
116 dMgr.addDeviceAgentToMap(agent)
117 }
118 }
119
120 // TODO: Need to trigger a reconcile at this point
121
122 probe.UpdateStatusFromContext(ctx, "device-manager", probe.ServiceStatusRunning)
123 logger.Info(ctx, "device-manager-started")
124}
125
Kent Hagerman2b216042020-04-03 18:28:56 -0400126func (dMgr *Manager) addDeviceAgentToMap(agent *Agent) {
npujar1d86a522019-11-14 17:11:16 +0530127 if _, exist := dMgr.deviceAgents.Load(agent.deviceID); !exist {
128 dMgr.deviceAgents.Store(agent.deviceID, agent)
khenaidoob9203542018-09-17 22:56:37 -0400129 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400130 dMgr.lockRootDeviceMap.Lock()
131 defer dMgr.lockRootDeviceMap.Unlock()
Kent Hagerman2a07b862020-06-19 15:23:07 -0400132 dMgr.rootDevices[agent.deviceID] = agent.isRootDevice
khenaidoo2c6a0992019-04-29 13:46:56 -0400133
khenaidoob9203542018-09-17 22:56:37 -0400134}
135
Kent Hagerman2b216042020-04-03 18:28:56 -0400136func (dMgr *Manager) deleteDeviceAgentFromMap(agent *Agent) {
npujar1d86a522019-11-14 17:11:16 +0530137 dMgr.deviceAgents.Delete(agent.deviceID)
khenaidoo2c6a0992019-04-29 13:46:56 -0400138 dMgr.lockRootDeviceMap.Lock()
139 defer dMgr.lockRootDeviceMap.Unlock()
npujar1d86a522019-11-14 17:11:16 +0530140 delete(dMgr.rootDevices, agent.deviceID)
khenaidoo4d4802d2018-10-04 21:59:49 -0400141}
142
khenaidoo297cd252019-02-07 22:10:23 -0500143// 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 -0400144func (dMgr *Manager) getDeviceAgent(ctx context.Context, deviceID string) *Agent {
npujar1d86a522019-11-14 17:11:16 +0530145 agent, ok := dMgr.deviceAgents.Load(deviceID)
146 if ok {
Kent Hagerman2b216042020-04-03 18:28:56 -0400147 return agent.(*Agent)
khenaidoob9203542018-09-17 22:56:37 -0400148 }
khenaidoo442e7c72020-03-10 16:13:48 -0400149 // Try to load into memory - loading will also create the device agent and set the device ownership
npujar467fe752020-01-16 20:17:45 +0530150 err := dMgr.load(ctx, deviceID)
npujar1d86a522019-11-14 17:11:16 +0530151 if err == nil {
152 agent, ok = dMgr.deviceAgents.Load(deviceID)
153 if !ok {
154 return nil
155 }
Kent Hagerman2b216042020-04-03 18:28:56 -0400156 return agent.(*Agent)
npujar1d86a522019-11-14 17:11:16 +0530157 }
158 //TODO: Change the return params to return an error as well
divyadesaicb8b59d2020-08-18 09:55:47 +0000159 logger.Errorw(ctx, "loading-device-failed", log.Fields{"device-id": deviceID, "error": err})
khenaidoob9203542018-09-17 22:56:37 -0400160 return nil
161}
162
khenaidoo297cd252019-02-07 22:10:23 -0500163// listDeviceIdsFromMap returns the list of device IDs that are in memory
Kent Hagerman2b216042020-04-03 18:28:56 -0400164func (dMgr *Manager) listDeviceIdsFromMap() *voltha.IDs {
khenaidoo7ccedd52018-12-14 16:48:54 -0500165 result := &voltha.IDs{Items: make([]*voltha.ID, 0)}
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400166
167 dMgr.deviceAgents.Range(func(key, value interface{}) bool {
168 result.Items = append(result.Items, &voltha.ID{Id: key.(string)})
169 return true
170 })
171
khenaidoo7ccedd52018-12-14 16:48:54 -0500172 return result
173}
174
Kent Hagerman45a13e42020-04-13 12:23:50 -0400175// CreateDevice creates a new parent device in the data model
176func (dMgr *Manager) CreateDevice(ctx context.Context, device *voltha.Device) (*voltha.Device, error) {
177 if device.MacAddress == "" && device.GetHostAndPort() == "" {
Himani Chawlab4c25912020-11-12 17:16:38 +0530178 logger.Errorf(ctx, "no-device-info-present")
Kent Hagerman45a13e42020-04-13 12:23:50 -0400179 return &voltha.Device{}, errors.New("no-device-info-present; MAC or HOSTIP&PORT")
180 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530181 ctx = utils.WithRPCMetadataContext(ctx, "CreateDevice")
Rohan Agrawal31f21802020-06-12 05:38:46 +0000182 logger.Debugw(ctx, "create-device", log.Fields{"device": *device})
Kent Hagerman45a13e42020-04-13 12:23:50 -0400183
npujar467fe752020-01-16 20:17:45 +0530184 deviceExist, err := dMgr.isParentDeviceExist(ctx, device)
Thomas Lee Se5a44012019-11-07 20:32:24 +0530185 if err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530186 logger.Errorf(ctx, "failed-to-fetch-parent-device-info")
Kent Hagerman45a13e42020-04-13 12:23:50 -0400187 return nil, err
Thomas Lee Se5a44012019-11-07 20:32:24 +0530188 }
189 if deviceExist {
Himani Chawlab4c25912020-11-12 17:16:38 +0530190 logger.Errorf(ctx, "device-is-pre-provisioned-already-with-same-ip-port-or-mac-address")
Kent Hagerman45a13e42020-04-13 12:23:50 -0400191 return nil, errors.New("device is already pre-provisioned")
Thomas Lee S51b5cb82019-10-14 14:49:34 +0530192 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530193 logger.Debugw(ctx, "create-device", log.Fields{"device": device, "aproxy": dMgr.adapterProxy})
khenaidoob9203542018-09-17 22:56:37 -0400194
khenaidoo5e677ae2019-02-28 17:26:29 -0500195 // Ensure this device is set as root
196 device.Root = true
khenaidoob9203542018-09-17 22:56:37 -0400197 // Create and start a device agent for that device
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700198 agent := newAgent(dMgr.adapterProxy, device, dMgr, dMgr.dbPath, dMgr.dProxy, dMgr.defaultTimeout)
khenaidoo7585a962021-06-10 16:15:38 -0400199 device, err = agent.start(ctx, false, device)
Scott Baker80678602019-11-14 16:57:36 -0800200 if err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530201 logger.Errorw(ctx, "fail-to-start-device", log.Fields{"device-id": agent.deviceID, "error": err})
Kent Hagerman45a13e42020-04-13 12:23:50 -0400202 return nil, err
Scott Baker80678602019-11-14 16:57:36 -0800203 }
khenaidoo442e7c72020-03-10 16:13:48 -0400204 dMgr.addDeviceAgentToMap(agent)
Kent Hagerman45a13e42020-04-13 12:23:50 -0400205 return device, nil
khenaidoob9203542018-09-17 22:56:37 -0400206}
207
Kent Hagerman45a13e42020-04-13 12:23:50 -0400208// EnableDevice activates a device by invoking the adopt_device API on the appropriate adapter
209func (dMgr *Manager) EnableDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530210 ctx = utils.WithRPCMetadataContext(ctx, "EnableDevice")
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000211 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +0530212 logger.Debugw(ctx, "enable-device", log.Fields{"device-id": id.Id})
Kent Hagerman45a13e42020-04-13 12:23:50 -0400213 agent := dMgr.getDeviceAgent(ctx, id.Id)
214 if agent == nil {
215 return nil, status.Errorf(codes.NotFound, "%s", id.Id)
khenaidoob9203542018-09-17 22:56:37 -0400216 }
Kent Hagerman45a13e42020-04-13 12:23:50 -0400217 return &empty.Empty{}, agent.enableDevice(ctx)
khenaidoob9203542018-09-17 22:56:37 -0400218}
219
Kent Hagerman45a13e42020-04-13 12:23:50 -0400220// DisableDevice disables a device along with any child device it may have
221func (dMgr *Manager) DisableDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530222 ctx = utils.WithRPCMetadataContext(ctx, "DisableDevice")
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000223 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +0530224 logger.Debugw(ctx, "disable-device", log.Fields{"device-id": id.Id})
Kent Hagerman45a13e42020-04-13 12:23:50 -0400225 agent := dMgr.getDeviceAgent(ctx, id.Id)
226 if agent == nil {
227 return nil, status.Errorf(codes.NotFound, "%s", id.Id)
khenaidoob9203542018-09-17 22:56:37 -0400228 }
Kent Hagerman45a13e42020-04-13 12:23:50 -0400229 return &empty.Empty{}, agent.disableDevice(ctx)
khenaidoo92e62c52018-10-03 14:02:54 -0400230}
231
Kent Hagerman45a13e42020-04-13 12:23:50 -0400232//RebootDevice invoked the reboot API to the corresponding adapter
233func (dMgr *Manager) RebootDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530234 ctx = utils.WithRPCMetadataContext(ctx, "RebootDevice")
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000235 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +0530236 logger.Debugw(ctx, "reboot-device", log.Fields{"device-id": id.Id})
Kent Hagerman45a13e42020-04-13 12:23:50 -0400237 agent := dMgr.getDeviceAgent(ctx, id.Id)
238 if agent == nil {
239 return nil, status.Errorf(codes.NotFound, "%s", id.Id)
khenaidoo4d4802d2018-10-04 21:59:49 -0400240 }
Kent Hagerman45a13e42020-04-13 12:23:50 -0400241 return &empty.Empty{}, agent.rebootDevice(ctx)
khenaidoo4d4802d2018-10-04 21:59:49 -0400242}
243
Kent Hagerman45a13e42020-04-13 12:23:50 -0400244// DeleteDevice removes a device from the data model
245func (dMgr *Manager) DeleteDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530246 ctx = utils.WithRPCMetadataContext(ctx, "DeleteDevice")
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000247 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +0530248 logger.Debugw(ctx, "delete-device", log.Fields{"device-id": id.Id})
Kent Hagerman45a13e42020-04-13 12:23:50 -0400249 agent := dMgr.getDeviceAgent(ctx, id.Id)
250 if agent == nil {
251 return nil, status.Errorf(codes.NotFound, "%s", id.Id)
khenaidoo4d4802d2018-10-04 21:59:49 -0400252 }
Kent Hagerman45a13e42020-04-13 12:23:50 -0400253 return &empty.Empty{}, agent.deleteDevice(ctx)
254}
255
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530256// ForceDeleteDevice removes a device from the data model forcefully without successfully waiting for the adapters.
257func (dMgr *Manager) ForceDeleteDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530258 ctx = utils.WithRPCMetadataContext(ctx, "ForceDeleteDevice")
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530259 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +0530260 logger.Debugw(ctx, "force-delete-device", log.Fields{"device-id": id.Id})
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530261 agent := dMgr.getDeviceAgent(ctx, id.Id)
262 if agent == nil {
263 return nil, status.Errorf(codes.NotFound, "%s", id.Id)
264 }
265 return &empty.Empty{}, agent.deleteDeviceForce(ctx)
266}
267
Kent Hagerman2a07b862020-06-19 15:23:07 -0400268// GetDevicePort returns the port details for a specific device port entry
269func (dMgr *Manager) GetDevicePort(ctx context.Context, deviceID string, portID uint32) (*voltha.Port, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530270 logger.Debugw(ctx, "get-device-port", log.Fields{"device-id": deviceID})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400271 agent := dMgr.getDeviceAgent(ctx, deviceID)
272 if agent == nil {
273 return nil, status.Errorf(codes.NotFound, "device-%s", deviceID)
274 }
275 return agent.getDevicePort(portID)
276}
277
Kent Hagerman45a13e42020-04-13 12:23:50 -0400278// ListDevicePorts returns the ports details for a specific device entry
279func (dMgr *Manager) ListDevicePorts(ctx context.Context, id *voltha.ID) (*voltha.Ports, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530280 ctx = utils.WithRPCMetadataContext(ctx, "ListDevicePorts")
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000281 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +0530282 logger.Debugw(ctx, "list-device-ports", log.Fields{"device-id": id.Id})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400283 agent := dMgr.getDeviceAgent(ctx, id.Id)
284 if agent == nil {
285 return nil, status.Errorf(codes.NotFound, "device-%s", id.Id)
Kent Hagerman45a13e42020-04-13 12:23:50 -0400286 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400287
288 ports := agent.listDevicePorts()
289 ctr, ret := 0, make([]*voltha.Port, len(ports))
290 for _, port := range ports {
291 ret[ctr] = port
292 ctr++
293 }
294 return &voltha.Ports{Items: ret}, nil
Kent Hagerman45a13e42020-04-13 12:23:50 -0400295}
296
297// ListDeviceFlows returns the flow details for a specific device entry
298func (dMgr *Manager) ListDeviceFlows(ctx context.Context, id *voltha.ID) (*ofp.Flows, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530299 ctx = utils.WithRPCMetadataContext(ctx, "ListDeviceFlows")
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000300 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +0530301 logger.Debugw(ctx, "list-device-flows", log.Fields{"device-id": id.Id})
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700302 agent := dMgr.getDeviceAgent(ctx, id.Id)
303 if agent == nil {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400304 return nil, status.Errorf(codes.NotFound, "device-%s", id.Id)
Kent Hagerman45a13e42020-04-13 12:23:50 -0400305 }
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700306
307 flows := agent.listDeviceFlows()
308 ctr, ret := 0, make([]*ofp.OfpFlowStats, len(flows))
309 for _, flow := range flows {
310 ret[ctr] = flow
311 ctr++
312 }
313 return &openflow_13.Flows{Items: ret}, nil
Kent Hagerman45a13e42020-04-13 12:23:50 -0400314}
315
316// ListDeviceFlowGroups returns the flow group details for a specific device entry
317func (dMgr *Manager) ListDeviceFlowGroups(ctx context.Context, id *voltha.ID) (*voltha.FlowGroups, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530318 ctx = utils.WithRPCMetadataContext(ctx, "ListDeviceFlowGroups")
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000319 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +0530320 logger.Debugw(ctx, "list-device-flow-groups", log.Fields{"device-id": id.Id})
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700321 agent := dMgr.getDeviceAgent(ctx, id.Id)
322 if agent == nil {
Kent Hagerman45a13e42020-04-13 12:23:50 -0400323 return nil, status.Errorf(codes.NotFound, "device-%s", id.Id)
324 }
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700325 groups := agent.listDeviceGroups()
326 ctr, ret := 0, make([]*openflow_13.OfpGroupEntry, len(groups))
327 for _, group := range groups {
328 ret[ctr] = group
329 ctr++
330 }
331 return &voltha.FlowGroups{Items: ret}, nil
khenaidoo4d4802d2018-10-04 21:59:49 -0400332}
333
khenaidoo6d62c002019-05-15 21:57:03 -0400334// stopManagingDevice stops the management of the device as well as any of its reference device and logical device.
335// This function is called only in the Core that does not own this device. In the Core that owns this device then a
336// deletion deletion also includes removal of any reference of this device.
Kent Hagerman2b216042020-04-03 18:28:56 -0400337func (dMgr *Manager) stopManagingDevice(ctx context.Context, id string) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530338 logger.Infow(ctx, "stop-managing-device", log.Fields{"device-id": id})
khenaidoo6d62c002019-05-15 21:57:03 -0400339 if dMgr.IsDeviceInCache(id) { // Proceed only if an agent is present for this device
Kent Hagerman6031aad2020-07-29 16:36:33 -0400340 if device, err := dMgr.getDeviceReadOnly(ctx, id); err == nil && device.Root {
khenaidoo6d62c002019-05-15 21:57:03 -0400341 // stop managing the logical device
David Bainbridged1afd662020-03-26 18:27:41 -0700342 _ = dMgr.logicalDeviceMgr.stopManagingLogicalDeviceWithDeviceID(ctx, id)
khenaidoo6d62c002019-05-15 21:57:03 -0400343 }
npujar467fe752020-01-16 20:17:45 +0530344 if agent := dMgr.getDeviceAgent(ctx, id); agent != nil {
khenaidoo442e7c72020-03-10 16:13:48 -0400345 if err := agent.stop(ctx); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000346 logger.Warnw(ctx, "unable-to-stop-device-agent", log.Fields{"device-id": agent.deviceID, "error": err})
khenaidoo442e7c72020-03-10 16:13:48 -0400347 }
khenaidoo4c9e5592019-09-09 16:20:41 -0400348 dMgr.deleteDeviceAgentFromMap(agent)
khenaidoo6d62c002019-05-15 21:57:03 -0400349 }
350 }
351}
352
npujar1d86a522019-11-14 17:11:16 +0530353// RunPostDeviceDelete removes any reference of this device
Kent Hagerman2b216042020-04-03 18:28:56 -0400354func (dMgr *Manager) RunPostDeviceDelete(ctx context.Context, cDevice *voltha.Device) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530355 logger.Infow(ctx, "run-post-device-delete", log.Fields{"device-id": cDevice.Id})
npujar467fe752020-01-16 20:17:45 +0530356 dMgr.stopManagingDevice(ctx, cDevice.Id)
khenaidoo6d62c002019-05-15 21:57:03 -0400357 return nil
khenaidoo0a822f92019-05-08 15:15:57 -0400358}
359
Kent Hagermancba2f302020-07-28 13:37:36 -0400360// GetDevice exists primarily to implement the gRPC interface.
361// Internal functions should call getDeviceReadOnly instead.
Kent Hagerman45a13e42020-04-13 12:23:50 -0400362func (dMgr *Manager) GetDevice(ctx context.Context, id *voltha.ID) (*voltha.Device, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530363 ctx = utils.WithRPCMetadataContext(ctx, "GetDevice")
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000364 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
Kent Hagermancba2f302020-07-28 13:37:36 -0400365 return dMgr.getDeviceReadOnly(ctx, id.Id)
Kent Hagerman45a13e42020-04-13 12:23:50 -0400366}
367
Kent Hagermancba2f302020-07-28 13:37:36 -0400368// getDeviceReadOnly will returns a device, either from memory or from the dB, if present
369func (dMgr *Manager) getDeviceReadOnly(ctx context.Context, id string) (*voltha.Device, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530370 logger.Debugw(ctx, "get-device-read-only", log.Fields{"device-id": id})
npujar467fe752020-01-16 20:17:45 +0530371 if agent := dMgr.getDeviceAgent(ctx, id); agent != nil {
Kent Hagermancba2f302020-07-28 13:37:36 -0400372 return agent.getDeviceReadOnly(ctx)
khenaidoo92e62c52018-10-03 14:02:54 -0400373 }
374 return nil, status.Errorf(codes.NotFound, "%s", id)
khenaidoob9203542018-09-17 22:56:37 -0400375}
376
Kent Hagerman2a07b862020-06-19 15:23:07 -0400377func (dMgr *Manager) listDevicePorts(ctx context.Context, id string) (map[uint32]*voltha.Port, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530378 logger.Debugw(ctx, "list-device-ports", log.Fields{"device-id": id})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400379 agent := dMgr.getDeviceAgent(ctx, id)
380 if agent == nil {
381 return nil, status.Errorf(codes.NotFound, "%s", id)
382 }
383 return agent.listDevicePorts(), nil
384}
385
npujar1d86a522019-11-14 17:11:16 +0530386// GetChildDevice will return a device, either from memory or from the dB, if present
Kent Hagerman2b216042020-04-03 18:28:56 -0400387func (dMgr *Manager) GetChildDevice(ctx context.Context, parentDeviceID string, serialNumber string, onuID int64, parentPortNo int64) (*voltha.Device, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530388 logger.Debugw(ctx, "get-child-device", log.Fields{"parent-device-id": parentDeviceID, "serialNumber": serialNumber,
389 "parent-port-no": parentPortNo, "onu-id": onuID})
Matt Jeanneret4e241952019-02-28 11:16:04 -0500390
Kent Hagerman2a07b862020-06-19 15:23:07 -0400391 parentDevicePorts, err := dMgr.listDevicePorts(ctx, parentDeviceID)
392 if err != nil {
Matt Jeanneret4e241952019-02-28 11:16:04 -0500393 return nil, status.Errorf(codes.Aborted, "%s", err.Error())
394 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400395 childDeviceIds := dMgr.getAllChildDeviceIds(ctx, parentDevicePorts)
Matt Jeanneret4e241952019-02-28 11:16:04 -0500396 if len(childDeviceIds) == 0 {
Himani Chawlab4c25912020-11-12 17:16:38 +0530397 logger.Debugw(ctx, "no-child-devices", log.Fields{"parent-device-id": parentDeviceID, "serial-number": serialNumber, "onu-id": onuID})
npujar1d86a522019-11-14 17:11:16 +0530398 return nil, status.Errorf(codes.NotFound, "%s", parentDeviceID)
Matt Jeanneret4e241952019-02-28 11:16:04 -0500399 }
400
401 var foundChildDevice *voltha.Device
Kent Hagerman2a07b862020-06-19 15:23:07 -0400402 for childDeviceID := range childDeviceIds {
npujar1d86a522019-11-14 17:11:16 +0530403 var found bool
Kent Hagermancba2f302020-07-28 13:37:36 -0400404 if searchDevice, err := dMgr.getDeviceReadOnly(ctx, childDeviceID); err == nil {
Matt Jeanneret4e241952019-02-28 11:16:04 -0500405
npujar1d86a522019-11-14 17:11:16 +0530406 foundOnuID := false
407 if searchDevice.ProxyAddress.OnuId == uint32(onuID) {
Matt Jeanneret4e241952019-02-28 11:16:04 -0500408 if searchDevice.ParentPortNo == uint32(parentPortNo) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530409 logger.Debugw(ctx, "found-child-by-onuid", log.Fields{"parent-device-id": parentDeviceID, "onu-id": onuID})
npujar1d86a522019-11-14 17:11:16 +0530410 foundOnuID = true
Matt Jeanneret4e241952019-02-28 11:16:04 -0500411 }
412 }
413
414 foundSerialNumber := false
415 if searchDevice.SerialNumber == serialNumber {
Himani Chawlab4c25912020-11-12 17:16:38 +0530416 logger.Debugw(ctx, "found-child-by-serial-number", log.Fields{"parent-device-id": parentDeviceID, "serial-number": serialNumber})
Matt Jeanneret4e241952019-02-28 11:16:04 -0500417 foundSerialNumber = true
418 }
419
420 // if both onuId and serialNumber are provided both must be true for the device to be found
421 // otherwise whichever one found a match is good enough
npujar1d86a522019-11-14 17:11:16 +0530422 if onuID > 0 && serialNumber != "" {
423 found = foundOnuID && foundSerialNumber
Matt Jeanneret4e241952019-02-28 11:16:04 -0500424 } else {
npujar1d86a522019-11-14 17:11:16 +0530425 found = foundOnuID || foundSerialNumber
Matt Jeanneret4e241952019-02-28 11:16:04 -0500426 }
427
npujar1d86a522019-11-14 17:11:16 +0530428 if found {
Matt Jeanneret4e241952019-02-28 11:16:04 -0500429 foundChildDevice = searchDevice
430 break
431 }
432 }
433 }
434
435 if foundChildDevice != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530436 logger.Debugw(ctx, "child-device-found", log.Fields{"parent-device-id": parentDeviceID, "found-child-device": foundChildDevice})
Matt Jeanneret4e241952019-02-28 11:16:04 -0500437 return foundChildDevice, nil
438 }
439
divyadesaicb8b59d2020-08-18 09:55:47 +0000440 logger.Debugw(ctx, "child-device-not-found", log.Fields{"parent-device-id": parentDeviceID,
Himani Chawlab4c25912020-11-12 17:16:38 +0530441 "serial-number": serialNumber, "onu-id": onuID, "parent-port-no": parentPortNo})
npujar1d86a522019-11-14 17:11:16 +0530442 return nil, status.Errorf(codes.NotFound, "%s", parentDeviceID)
Matt Jeanneret4e241952019-02-28 11:16:04 -0500443}
444
npujar1d86a522019-11-14 17:11:16 +0530445// GetChildDeviceWithProxyAddress will return a device based on proxy address
Kent Hagerman2b216042020-04-03 18:28:56 -0400446func (dMgr *Manager) GetChildDeviceWithProxyAddress(ctx context.Context, proxyAddress *voltha.Device_ProxyAddress) (*voltha.Device, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530447 logger.Debugw(ctx, "get-child-device-with-proxy-address", log.Fields{"proxy-address": proxyAddress})
Matt Jeanneret2a20aaa2019-03-05 21:04:02 -0500448
Kent Hagerman2a07b862020-06-19 15:23:07 -0400449 parentDevicePorts, err := dMgr.listDevicePorts(ctx, proxyAddress.DeviceId)
450 if err != nil {
Matt Jeanneret2a20aaa2019-03-05 21:04:02 -0500451 return nil, status.Errorf(codes.Aborted, "%s", err.Error())
452 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400453 childDeviceIds := dMgr.getAllChildDeviceIds(ctx, parentDevicePorts)
Matt Jeanneret2a20aaa2019-03-05 21:04:02 -0500454 if len(childDeviceIds) == 0 {
divyadesaicb8b59d2020-08-18 09:55:47 +0000455 logger.Debugw(ctx, "no-child-devices", log.Fields{"parent-device-id": proxyAddress.DeviceId})
Matt Jeanneret2a20aaa2019-03-05 21:04:02 -0500456 return nil, status.Errorf(codes.NotFound, "%s", proxyAddress)
457 }
458
459 var foundChildDevice *voltha.Device
Kent Hagerman2a07b862020-06-19 15:23:07 -0400460 for childDeviceID := range childDeviceIds {
Kent Hagermancba2f302020-07-28 13:37:36 -0400461 if searchDevice, err := dMgr.getDeviceReadOnly(ctx, childDeviceID); err == nil {
Matt Jeanneret2a20aaa2019-03-05 21:04:02 -0500462 if searchDevice.ProxyAddress == proxyAddress {
463 foundChildDevice = searchDevice
464 break
465 }
466 }
467 }
468
469 if foundChildDevice != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530470 logger.Debugw(ctx, "child-device-found", log.Fields{"proxy-address": proxyAddress})
Matt Jeanneret2a20aaa2019-03-05 21:04:02 -0500471 return foundChildDevice, nil
472 }
473
Himani Chawlab4c25912020-11-12 17:16:38 +0530474 logger.Warnw(ctx, "child-device-not-found", log.Fields{"proxy-address": proxyAddress})
Matt Jeanneret2a20aaa2019-03-05 21:04:02 -0500475 return nil, status.Errorf(codes.NotFound, "%s", proxyAddress)
476}
477
npujar1d86a522019-11-14 17:11:16 +0530478// IsDeviceInCache returns true if device is found in the map
Kent Hagerman2b216042020-04-03 18:28:56 -0400479func (dMgr *Manager) IsDeviceInCache(id string) bool {
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400480 _, exist := dMgr.deviceAgents.Load(id)
khenaidoo297cd252019-02-07 22:10:23 -0500481 return exist
482}
483
Stephane Barbarieaa467942019-02-06 14:09:44 -0500484// ListDevices retrieves the latest devices from the data model
Kent Hagerman45a13e42020-04-13 12:23:50 -0400485func (dMgr *Manager) ListDevices(ctx context.Context, _ *empty.Empty) (*voltha.Devices, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530486 ctx = utils.WithRPCMetadataContext(ctx, "ListDevices")
487 logger.Debug(ctx, "list-devices")
khenaidoob9203542018-09-17 22:56:37 -0400488 result := &voltha.Devices{}
Kent Hagerman4f355f52020-03-30 16:01:33 -0400489
Esin Karamana4e4e002021-03-02 10:42:16 +0000490 dMgr.deviceAgents.Range(func(key, value interface{}) bool {
491 result.Items = append(result.Items, value.(*Agent).device)
492 return true
493 })
Kent Hagerman4f355f52020-03-30 16:01:33 -0400494
Himani Chawlab4c25912020-11-12 17:16:38 +0530495 logger.Debugw(ctx, "list-devices-end", log.Fields{"len": len(result.Items)})
khenaidoob9203542018-09-17 22:56:37 -0400496 return result, nil
497}
498
Thomas Lee S51b5cb82019-10-14 14:49:34 +0530499//isParentDeviceExist checks whether device is already preprovisioned.
Kent Hagerman2b216042020-04-03 18:28:56 -0400500func (dMgr *Manager) isParentDeviceExist(ctx context.Context, newDevice *voltha.Device) (bool, error) {
Thomas Lee S51b5cb82019-10-14 14:49:34 +0530501 hostPort := newDevice.GetHostAndPort()
Kent Hagerman4f355f52020-03-30 16:01:33 -0400502 var devices []*voltha.Device
Kent Hagermanf5a67352020-04-30 15:15:26 -0400503 if err := dMgr.dProxy.List(ctx, &devices); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530504 logger.Errorw(ctx, "failed-to-list-devices-from-cluster-data-proxy", log.Fields{"error": err})
Thomas Lee Se5a44012019-11-07 20:32:24 +0530505 return false, err
506 }
Kent Hagerman4f355f52020-03-30 16:01:33 -0400507 for _, device := range devices {
508 if !device.Root {
509 continue
510 }
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530511
512 if hostPort != "" && hostPort == device.GetHostAndPort() {
Kent Hagerman4f355f52020-03-30 16:01:33 -0400513 return true, nil
514 }
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530515 if newDevice.MacAddress != "" && newDevice.MacAddress == device.MacAddress {
Kent Hagerman4f355f52020-03-30 16:01:33 -0400516 return true, nil
Thomas Lee S51b5cb82019-10-14 14:49:34 +0530517 }
518 }
Thomas Lee Se5a44012019-11-07 20:32:24 +0530519 return false, nil
Thomas Lee S51b5cb82019-10-14 14:49:34 +0530520}
521
khenaidoo6d62c002019-05-15 21:57:03 -0400522//getDeviceFromModelretrieves the device data from the model.
Kent Hagerman2b216042020-04-03 18:28:56 -0400523func (dMgr *Manager) getDeviceFromModel(ctx context.Context, deviceID string) (*voltha.Device, error) {
Kent Hagerman4f355f52020-03-30 16:01:33 -0400524 device := &voltha.Device{}
Kent Hagermanf5a67352020-04-30 15:15:26 -0400525 if have, err := dMgr.dProxy.Get(ctx, deviceID, device); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000526 logger.Errorw(ctx, "failed-to-get-device-info-from-cluster-proxy", log.Fields{"error": err})
Thomas Lee Se5a44012019-11-07 20:32:24 +0530527 return nil, err
Kent Hagerman4f355f52020-03-30 16:01:33 -0400528 } else if !have {
529 return nil, status.Error(codes.NotFound, deviceID)
Thomas Lee Se5a44012019-11-07 20:32:24 +0530530 }
Kent Hagerman4f355f52020-03-30 16:01:33 -0400531
532 return device, nil
khenaidoo6d62c002019-05-15 21:57:03 -0400533}
534
npujar1d86a522019-11-14 17:11:16 +0530535// loadDevice loads the deviceID in memory, if not present
Kent Hagerman2b216042020-04-03 18:28:56 -0400536func (dMgr *Manager) loadDevice(ctx context.Context, deviceID string) (*Agent, error) {
npujar1d86a522019-11-14 17:11:16 +0530537 if deviceID == "" {
khenaidoo297cd252019-02-07 22:10:23 -0500538 return nil, status.Error(codes.InvalidArgument, "deviceId empty")
539 }
khenaidoo4c9e5592019-09-09 16:20:41 -0400540 var err error
541 var device *voltha.Device
542 dMgr.devicesLoadingLock.Lock()
npujar1d86a522019-11-14 17:11:16 +0530543 if _, exist := dMgr.deviceLoadingInProgress[deviceID]; !exist {
544 if !dMgr.IsDeviceInCache(deviceID) {
545 dMgr.deviceLoadingInProgress[deviceID] = []chan int{make(chan int, 1)}
khenaidoo4c9e5592019-09-09 16:20:41 -0400546 dMgr.devicesLoadingLock.Unlock()
547 // Proceed with the loading only if the device exist in the Model (could have been deleted)
npujar467fe752020-01-16 20:17:45 +0530548 if device, err = dMgr.getDeviceFromModel(ctx, deviceID); err == nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000549 logger.Debugw(ctx, "loading-device", log.Fields{"device-id": deviceID})
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700550 agent := newAgent(dMgr.adapterProxy, device, dMgr, dMgr.dbPath, dMgr.dProxy, dMgr.defaultTimeout)
khenaidoo7585a962021-06-10 16:15:38 -0400551 if _, err = agent.start(ctx, true, device); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530552 logger.Warnw(ctx, "failure-loading-device", log.Fields{"device-id": deviceID, "error": err})
khenaidoo4c9e5592019-09-09 16:20:41 -0400553 } else {
554 dMgr.addDeviceAgentToMap(agent)
555 }
556 } else {
Himani Chawlab4c25912020-11-12 17:16:38 +0530557 logger.Debugw(ctx, "device-is-not-in-model", log.Fields{"device-id": deviceID})
khenaidoo6d62c002019-05-15 21:57:03 -0400558 }
khenaidoo4c9e5592019-09-09 16:20:41 -0400559 // announce completion of task to any number of waiting channels
560 dMgr.devicesLoadingLock.Lock()
npujar1d86a522019-11-14 17:11:16 +0530561 if v, ok := dMgr.deviceLoadingInProgress[deviceID]; ok {
khenaidoo4c9e5592019-09-09 16:20:41 -0400562 for _, ch := range v {
563 close(ch)
564 }
npujar1d86a522019-11-14 17:11:16 +0530565 delete(dMgr.deviceLoadingInProgress, deviceID)
khenaidoo4c9e5592019-09-09 16:20:41 -0400566 }
567 dMgr.devicesLoadingLock.Unlock()
khenaidoo6d62c002019-05-15 21:57:03 -0400568 } else {
khenaidoo4c9e5592019-09-09 16:20:41 -0400569 dMgr.devicesLoadingLock.Unlock()
khenaidoo297cd252019-02-07 22:10:23 -0500570 }
khenaidoo4c9e5592019-09-09 16:20:41 -0400571 } else {
572 ch := make(chan int, 1)
npujar1d86a522019-11-14 17:11:16 +0530573 dMgr.deviceLoadingInProgress[deviceID] = append(dMgr.deviceLoadingInProgress[deviceID], ch)
khenaidoo4c9e5592019-09-09 16:20:41 -0400574 dMgr.devicesLoadingLock.Unlock()
575 // Wait for the channel to be closed, implying the process loading this device is done.
576 <-ch
khenaidoo297cd252019-02-07 22:10:23 -0500577 }
npujar1d86a522019-11-14 17:11:16 +0530578 if agent, ok := dMgr.deviceAgents.Load(deviceID); ok {
Kent Hagerman2b216042020-04-03 18:28:56 -0400579 return agent.(*Agent), nil
khenaidoo297cd252019-02-07 22:10:23 -0500580 }
npujar1d86a522019-11-14 17:11:16 +0530581 return nil, status.Errorf(codes.Aborted, "Error loading device %s", deviceID)
khenaidoo297cd252019-02-07 22:10:23 -0500582}
583
584// loadRootDeviceParentAndChildren loads the children and parents of a root device in memory
Kent Hagerman2a07b862020-06-19 15:23:07 -0400585func (dMgr *Manager) loadRootDeviceParentAndChildren(ctx context.Context, device *voltha.Device, devicePorts map[uint32]*voltha.Port) error {
divyadesaicb8b59d2020-08-18 09:55:47 +0000586 logger.Debugw(ctx, "loading-parent-and-children", log.Fields{"device-id": device.Id})
khenaidoo297cd252019-02-07 22:10:23 -0500587 if device.Root {
588 // Scenario A
589 if device.ParentId != "" {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400590 // Load logical device if needed.
npujar467fe752020-01-16 20:17:45 +0530591 if err := dMgr.logicalDeviceMgr.load(ctx, device.ParentId); err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000592 logger.Warnw(ctx, "failure-loading-logical-device", log.Fields{"logical-device-id": device.ParentId})
khenaidoo297cd252019-02-07 22:10:23 -0500593 }
594 } else {
divyadesaicb8b59d2020-08-18 09:55:47 +0000595 logger.Debugw(ctx, "no-parent-to-load", log.Fields{"device-id": device.Id})
khenaidoo297cd252019-02-07 22:10:23 -0500596 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400597 // Load all child devices, if needed
598 childDeviceIds := dMgr.getAllChildDeviceIds(ctx, devicePorts)
599 for childDeviceID := range childDeviceIds {
600 if _, err := dMgr.loadDevice(ctx, childDeviceID); err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000601 logger.Warnw(ctx, "failure-loading-device", log.Fields{"device-id": childDeviceID, "error": err})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400602 return err
khenaidoo297cd252019-02-07 22:10:23 -0500603 }
khenaidoo297cd252019-02-07 22:10:23 -0500604 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530605 logger.Debugw(ctx, "loaded-children", log.Fields{"device-id": device.Id, "num-children": len(childDeviceIds)})
khenaidoo297cd252019-02-07 22:10:23 -0500606 }
607 return nil
608}
609
610// load loads the deviceId in memory, if not present, and also loads its accompanying parents and children. Loading
611// in memory is for improved performance. It is not imperative that a device needs to be in memory when a request
612// acting on the device is received by the core. In such a scenario, the Core will load the device in memory first
613// and the proceed with the request.
Kent Hagerman2b216042020-04-03 18:28:56 -0400614func (dMgr *Manager) load(ctx context.Context, deviceID string) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000615 logger.Debug(ctx, "load...")
khenaidoo297cd252019-02-07 22:10:23 -0500616 // 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 -0400617 var dAgent *Agent
khenaidoo297cd252019-02-07 22:10:23 -0500618 var err error
npujar467fe752020-01-16 20:17:45 +0530619 if dAgent, err = dMgr.loadDevice(ctx, deviceID); err != nil {
khenaidoo297cd252019-02-07 22:10:23 -0500620 return err
621 }
622 // Get the loaded device details
Kent Hagermancba2f302020-07-28 13:37:36 -0400623 device, err := dAgent.getDeviceReadOnly(ctx)
khenaidoo442e7c72020-03-10 16:13:48 -0400624 if err != nil {
625 return err
626 }
khenaidoo297cd252019-02-07 22:10:23 -0500627
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530628 // If the device is in Pre-provisioning or getting deleted state stop here
629 if device.AdminState == voltha.AdminState_PREPROVISIONED || dAgent.isDeletionInProgress() {
khenaidoo297cd252019-02-07 22:10:23 -0500630 return nil
631 }
632
633 // Now we face two scenarios
634 if device.Root {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400635 devicePorts := dAgent.listDevicePorts()
636
khenaidoo297cd252019-02-07 22:10:23 -0500637 // Load all children as well as the parent of this device (logical_device)
Kent Hagerman2a07b862020-06-19 15:23:07 -0400638 if err := dMgr.loadRootDeviceParentAndChildren(ctx, device, devicePorts); err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000639 logger.Warnw(ctx, "failure-loading-device-parent-and-children", log.Fields{"device-id": deviceID})
khenaidoo297cd252019-02-07 22:10:23 -0500640 return err
641 }
divyadesaicb8b59d2020-08-18 09:55:47 +0000642 logger.Debugw(ctx, "successfully-loaded-parent-and-children", log.Fields{"device-id": deviceID})
Andrey Pozolotin34dd63f2021-05-31 21:26:40 +0300643 } else if device.ParentId != "" {
khenaidoo297cd252019-02-07 22:10:23 -0500644 // Scenario B - use the parentId of that device (root device) to trigger the loading
Andrey Pozolotin34dd63f2021-05-31 21:26:40 +0300645 return dMgr.load(ctx, device.ParentId)
khenaidoo297cd252019-02-07 22:10:23 -0500646 }
Andrey Pozolotin34dd63f2021-05-31 21:26:40 +0300647
khenaidoo297cd252019-02-07 22:10:23 -0500648 return nil
649}
650
khenaidoo7ccedd52018-12-14 16:48:54 -0500651// ListDeviceIds retrieves the latest device IDs information from the data model (memory data only)
Rohan Agrawal31f21802020-06-12 05:38:46 +0000652func (dMgr *Manager) ListDeviceIds(ctx context.Context, _ *empty.Empty) (*voltha.IDs, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530653 ctx = utils.WithRPCMetadataContext(ctx, "ListDeviceIds")
654 logger.Debug(ctx, "list-device-ids")
khenaidoo7ccedd52018-12-14 16:48:54 -0500655 // Report only device IDs that are in the device agent map
656 return dMgr.listDeviceIdsFromMap(), nil
657}
658
Kent Hagerman45a13e42020-04-13 12:23:50 -0400659// ReconcileDevices is a request to a voltha core to update its list of managed devices. This will
660// trigger loading the devices along with their children and parent in memory
661func (dMgr *Manager) ReconcileDevices(ctx context.Context, ids *voltha.IDs) (*empty.Empty, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530662 ctx = utils.WithRPCMetadataContext(ctx, "ReconcileDevices")
Andrey Pozolotin34dd63f2021-05-31 21:26:40 +0300663
664 numDevices := 0
665 if ids != nil {
666 numDevices = len(ids.Items)
667 }
668
669 logger.Debugw(ctx, "reconcile-devices", log.Fields{"num-devices": numDevices})
khenaidoo4c9e5592019-09-09 16:20:41 -0400670 if ids != nil && len(ids.Items) != 0 {
khenaidoo7ccedd52018-12-14 16:48:54 -0500671 toReconcile := len(ids.Items)
672 reconciled := 0
khenaidoo4c9e5592019-09-09 16:20:41 -0400673 var err error
khenaidoo7ccedd52018-12-14 16:48:54 -0500674 for _, id := range ids.Items {
npujar467fe752020-01-16 20:17:45 +0530675 if err = dMgr.load(ctx, id.Id); err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000676 logger.Warnw(ctx, "failure-reconciling-device", log.Fields{"device-id": id.Id, "error": err})
khenaidoo4c9e5592019-09-09 16:20:41 -0400677 } else {
npujar1d86a522019-11-14 17:11:16 +0530678 reconciled++
khenaidoo7ccedd52018-12-14 16:48:54 -0500679 }
680 }
681 if toReconcile != reconciled {
Kent Hagerman45a13e42020-04-13 12:23:50 -0400682 return nil, status.Errorf(codes.DataLoss, "less-device-reconciled-than-requested:%d/%d", reconciled, toReconcile)
khenaidoo7ccedd52018-12-14 16:48:54 -0500683 }
684 } else {
Kent Hagerman45a13e42020-04-13 12:23:50 -0400685 return nil, status.Errorf(codes.InvalidArgument, "empty-list-of-ids")
khenaidoo7ccedd52018-12-14 16:48:54 -0500686 }
Kent Hagerman45a13e42020-04-13 12:23:50 -0400687 return &empty.Empty{}, nil
khenaidoo7ccedd52018-12-14 16:48:54 -0500688}
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500689
khenaidooba6b6c42019-08-02 09:11:56 -0400690// adapterRestarted is invoked whenever an adapter is restarted
Kent Hagerman2b216042020-04-03 18:28:56 -0400691func (dMgr *Manager) adapterRestarted(ctx context.Context, adapter *voltha.Adapter) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530692 logger.Debugw(ctx, "adapter-restarted", log.Fields{"adapter-id": adapter.Id, "vendor": adapter.Vendor,
693 "current-replica": adapter.CurrentReplica, "total-replicas": adapter.TotalReplicas, "endpoint": adapter.Endpoint})
khenaidooba6b6c42019-08-02 09:11:56 -0400694
695 // Let's reconcile the device managed by this Core only
David Bainbridged1afd662020-03-26 18:27:41 -0700696 if len(dMgr.rootDevices) == 0 {
Himani Chawlab4c25912020-11-12 17:16:38 +0530697 logger.Debugw(ctx, "nothing-to-reconcile", log.Fields{"adapter-id": adapter.Id})
khenaidooba6b6c42019-08-02 09:11:56 -0400698 return nil
699 }
700
Maninder0aabf0c2021-03-17 14:55:14 +0530701 if len(dMgr.rootDevices) == 0 {
702 logger.Debugw(ctx, "no-managed-device-to-reconcile", log.Fields{"adapter-id": adapter.Id})
703 return nil
704 }
705
David Bainbridged1afd662020-03-26 18:27:41 -0700706 for rootDeviceID := range dMgr.rootDevices {
Mahir Gunyel12cf55f2020-12-16 17:55:03 -0800707 dAgent := dMgr.getDeviceAgent(ctx, rootDeviceID)
708 if dAgent == nil {
709 continue
710 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530711 logger.Debugw(ctx, "checking-adapter-type", log.Fields{"agentType": dAgent.deviceType, "adapter-type": adapter.Type})
Mahir Gunyel12cf55f2020-12-16 17:55:03 -0800712 if dAgent.deviceType == adapter.Type {
713 rootDevice, _ := dAgent.getDeviceReadOnly(ctx)
714 if rootDevice == nil {
715 continue
716 }
Rohan Agrawal31f21802020-06-12 05:38:46 +0000717 isDeviceOwnedByService, err := dMgr.adapterProxy.IsDeviceOwnedByService(ctx, rootDeviceID, adapter.Type, adapter.CurrentReplica)
serkant.uluderya7d545aa2020-04-09 13:38:45 -0700718 if err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530719 logger.Warnw(ctx, "is-device-owned-by-service", log.Fields{"error": err, "root-device-id": rootDeviceID, "adapter-type": adapter.Type, "replica-number": adapter.CurrentReplica})
serkant.uluderya7d545aa2020-04-09 13:38:45 -0700720 continue
721 }
722 if isDeviceOwnedByService {
Maninder0aabf0c2021-03-17 14:55:14 +0530723 if rootDevice.AdminState != voltha.AdminState_PREPROVISIONED {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000724 logger.Debugw(ctx, "reconciling-root-device", log.Fields{"rootId": rootDevice.Id})
Maninder0aabf0c2021-03-17 14:55:14 +0530725 go dAgent.ReconcileDevice(ctx, rootDevice)
khenaidooba6b6c42019-08-02 09:11:56 -0400726 } else {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000727 logger.Debugw(ctx, "not-reconciling-root-device", log.Fields{"rootId": rootDevice.Id, "state": rootDevice.AdminState})
khenaidooba6b6c42019-08-02 09:11:56 -0400728 }
729 } else { // Should we be reconciling the root's children instead?
Kent Hagerman2a07b862020-06-19 15:23:07 -0400730 rootDevicePorts, _ := dMgr.listDevicePorts(ctx, rootDeviceID)
khenaidooba6b6c42019-08-02 09:11:56 -0400731 childManagedByAdapter:
Kent Hagerman2a07b862020-06-19 15:23:07 -0400732 for _, port := range rootDevicePorts {
khenaidooba6b6c42019-08-02 09:11:56 -0400733 for _, peer := range port.Peers {
npujar467fe752020-01-16 20:17:45 +0530734 if childDevice, _ := dMgr.getDeviceFromModel(ctx, peer.DeviceId); childDevice != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000735 isDeviceOwnedByService, err := dMgr.adapterProxy.IsDeviceOwnedByService(ctx, childDevice.Id, adapter.Type, adapter.CurrentReplica)
serkant.uluderya7d545aa2020-04-09 13:38:45 -0700736 if err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530737 logger.Warnw(ctx, "is-device-owned-by-service", log.Fields{"error": err, "child-device-id": childDevice.Id, "adapter-type": adapter.Type, "replica-number": adapter.CurrentReplica})
serkant.uluderya7d545aa2020-04-09 13:38:45 -0700738 }
739 if isDeviceOwnedByService {
Maninder0aabf0c2021-03-17 14:55:14 +0530740 if childDevice.AdminState != voltha.AdminState_PREPROVISIONED {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000741 logger.Debugw(ctx, "reconciling-child-device", log.Fields{"child-device-id": childDevice.Id})
Maninder0aabf0c2021-03-17 14:55:14 +0530742 go dAgent.ReconcileDevice(ctx, childDevice)
khenaidooba6b6c42019-08-02 09:11:56 -0400743 } else {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000744 logger.Debugw(ctx, "not-reconciling-child-device", log.Fields{"child-device-id": childDevice.Id, "state": childDevice.AdminState})
khenaidooba6b6c42019-08-02 09:11:56 -0400745 }
746 } else {
747 // All child devices under a parent device are typically managed by the same adapter type.
748 // Therefore we only need to check whether the first device we retrieved is managed by that adapter
749 break childManagedByAdapter
750 }
751 }
752 }
753 }
754 }
755 }
756 }
Maninder0aabf0c2021-03-17 14:55:14 +0530757 logger.Debugw(ctx, "Reconciling for device on adapter restart is initiated", log.Fields{"adapter-id": adapter.Id})
758
khenaidooba6b6c42019-08-02 09:11:56 -0400759 return nil
760}
761
Kent Hagerman2b216042020-04-03 18:28:56 -0400762func (dMgr *Manager) ReconcileChildDevices(ctx context.Context, parentDeviceID string) error {
Maninder0aabf0c2021-03-17 14:55:14 +0530763 dAgent := dMgr.getDeviceAgent(ctx, parentDeviceID)
764 if dAgent == nil {
765 return status.Errorf(codes.NotFound, "error-unable to get agent from device")
766 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400767 if parentDevicePorts, err := dMgr.listDevicePorts(ctx, parentDeviceID); err == nil {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400768 for _, port := range parentDevicePorts {
khenaidooba6b6c42019-08-02 09:11:56 -0400769 for _, peer := range port.Peers {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400770 if childDevice, err := dMgr.getDeviceFromModel(ctx, peer.DeviceId); err == nil {
Maninder0aabf0c2021-03-17 14:55:14 +0530771 go dAgent.ReconcileDevice(ctx, childDevice)
khenaidooba6b6c42019-08-02 09:11:56 -0400772 }
773 }
774 }
Maninder0aabf0c2021-03-17 14:55:14 +0530775 logger.Debugw(ctx, "Reconcile initiated for child devices", log.Fields{"parent-device-id": parentDeviceID})
khenaidooba6b6c42019-08-02 09:11:56 -0400776 }
777 return nil
778}
779
Kent Hagerman2b216042020-04-03 18:28:56 -0400780func (dMgr *Manager) UpdateDeviceUsingAdapterData(ctx context.Context, device *voltha.Device) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530781 logger.Debugw(ctx, "update-device-using-adapter-data", log.Fields{"device-id": device.Id, "device": device})
npujar467fe752020-01-16 20:17:45 +0530782 if agent := dMgr.getDeviceAgent(ctx, device.Id); agent != nil {
783 return agent.updateDeviceUsingAdapterData(ctx, device)
khenaidoob9203542018-09-17 22:56:37 -0400784 }
785 return status.Errorf(codes.NotFound, "%s", device.Id)
786}
787
khenaidoo0db4c812020-05-27 15:27:30 -0400788func (dMgr *Manager) addPeerPort(ctx context.Context, deviceID string, port *voltha.Port) error {
789 meAsPeer := &voltha.Port_PeerPort{DeviceId: deviceID, PortNo: port.PortNo}
790 for _, peerPort := range port.Peers {
791 if agent := dMgr.getDeviceAgent(ctx, peerPort.DeviceId); agent != nil {
792 if err := agent.addPeerPort(ctx, meAsPeer); err != nil {
793 return err
794 }
795 }
796 }
797 // Notify the logical device manager to setup a logical port, if needed. If the added port is an NNI or UNI
798 // then a logical port will be added to the logical device and the device route generated. If the port is a
799 // PON port then only the device graph will be generated.
Kent Hagermancba2f302020-07-28 13:37:36 -0400800 device, err := dMgr.getDeviceReadOnly(ctx, deviceID)
khenaidoo0db4c812020-05-27 15:27:30 -0400801 if err != nil {
802 return err
803 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400804 ports, err := dMgr.listDevicePorts(ctx, deviceID)
805 if err != nil {
806 return err
807 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530808 subCtx := utils.WithSpanAndRPCMetadataFromContext(ctx)
809
810 if err = dMgr.logicalDeviceMgr.updateLogicalPort(subCtx, device, ports, port); err != nil {
khenaidoo0db4c812020-05-27 15:27:30 -0400811 return err
812 }
813 return nil
814}
815
Kent Hagerman2b216042020-04-03 18:28:56 -0400816func (dMgr *Manager) AddPort(ctx context.Context, deviceID string, port *voltha.Port) error {
npujar467fe752020-01-16 20:17:45 +0530817 agent := dMgr.getDeviceAgent(ctx, deviceID)
npujar1d86a522019-11-14 17:11:16 +0530818 if agent != nil {
npujar467fe752020-01-16 20:17:45 +0530819 if err := agent.addPort(ctx, port); err != nil {
khenaidoo92e62c52018-10-03 14:02:54 -0400820 return err
821 }
khenaidoo0db4c812020-05-27 15:27:30 -0400822 // Setup peer ports in its own routine
823 go func() {
Himani Chawlab4c25912020-11-12 17:16:38 +0530824 subCtx := utils.WithSpanAndRPCMetadataFromContext(ctx)
825 if err := dMgr.addPeerPort(subCtx, deviceID, port); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000826 logger.Errorw(ctx, "unable-to-add-peer-port", log.Fields{"error": err, "device-id": deviceID})
khenaidoo92e62c52018-10-03 14:02:54 -0400827 }
khenaidoo0db4c812020-05-27 15:27:30 -0400828 }()
khenaidoo92e62c52018-10-03 14:02:54 -0400829 return nil
khenaidoob9203542018-09-17 22:56:37 -0400830 }
npujar1d86a522019-11-14 17:11:16 +0530831 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoob9203542018-09-17 22:56:37 -0400832}
833
Kent Hagerman2b216042020-04-03 18:28:56 -0400834func (dMgr *Manager) addFlowsAndGroups(ctx context.Context, deviceID string, flows []*ofp.OfpFlowStats, groups []*ofp.OfpGroupEntry, flowMetadata *voltha.FlowMetadata) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530835 logger.Debugw(ctx, "add-flows-and-groups", log.Fields{"device-id": deviceID, "groups:": groups, "flow-metadata": flowMetadata})
npujar467fe752020-01-16 20:17:45 +0530836 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
837 return agent.addFlowsAndGroups(ctx, flows, groups, flowMetadata)
khenaidoo0458db62019-06-20 08:50:36 -0400838 }
npujar1d86a522019-11-14 17:11:16 +0530839 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo0458db62019-06-20 08:50:36 -0400840}
841
khenaidoo787224a2020-04-16 18:08:47 -0400842// deleteParentFlows removes flows from the parent device based on specific attributes
843func (dMgr *Manager) deleteParentFlows(ctx context.Context, deviceID string, uniPort uint32, metadata *voltha.FlowMetadata) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530844 logger.Debugw(ctx, "delete-parent-flows", log.Fields{"device-id": deviceID, "uni-port": uniPort, "metadata": metadata})
khenaidoo787224a2020-04-16 18:08:47 -0400845 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400846 if !agent.isRootDevice {
khenaidoo787224a2020-04-16 18:08:47 -0400847 return status.Errorf(codes.FailedPrecondition, "not-a-parent-device-%s", deviceID)
848 }
849 return agent.filterOutFlows(ctx, uniPort, metadata)
850 }
851 return status.Errorf(codes.NotFound, "%s", deviceID)
852}
853
Kent Hagerman2b216042020-04-03 18:28:56 -0400854func (dMgr *Manager) deleteFlowsAndGroups(ctx context.Context, deviceID string, flows []*ofp.OfpFlowStats, groups []*ofp.OfpGroupEntry, flowMetadata *voltha.FlowMetadata) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530855 logger.Debugw(ctx, "delete-flows-and-groups", log.Fields{"device-id": deviceID})
npujar467fe752020-01-16 20:17:45 +0530856 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
857 return agent.deleteFlowsAndGroups(ctx, flows, groups, flowMetadata)
khenaidoo0458db62019-06-20 08:50:36 -0400858 }
npujar1d86a522019-11-14 17:11:16 +0530859 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo0458db62019-06-20 08:50:36 -0400860}
861
Kent Hagerman2b216042020-04-03 18:28:56 -0400862func (dMgr *Manager) updateFlowsAndGroups(ctx context.Context, deviceID string, flows []*ofp.OfpFlowStats, groups []*ofp.OfpGroupEntry, flowMetadata *voltha.FlowMetadata) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530863 logger.Debugw(ctx, "update-flows-and-groups", log.Fields{"device-id": deviceID})
npujar467fe752020-01-16 20:17:45 +0530864 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
865 return agent.updateFlowsAndGroups(ctx, flows, groups, flowMetadata)
khenaidoo19d7b632018-10-30 10:49:50 -0400866 }
npujar1d86a522019-11-14 17:11:16 +0530867 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo19d7b632018-10-30 10:49:50 -0400868}
869
Kent Hagerman45a13e42020-04-13 12:23:50 -0400870// UpdateDevicePmConfigs updates the PM configs. This is executed when the northbound gRPC API is invoked, typically
khenaidoob3127472019-07-24 21:04:55 -0400871// following a user action
Kent Hagerman45a13e42020-04-13 12:23:50 -0400872func (dMgr *Manager) UpdateDevicePmConfigs(ctx context.Context, configs *voltha.PmConfigs) (*empty.Empty, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530873 ctx = utils.WithRPCMetadataContext(ctx, "UpdateDevicePmConfigs")
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000874 log.EnrichSpan(ctx, log.Fields{"device-id": configs.Id})
Kent Hagerman45a13e42020-04-13 12:23:50 -0400875 if configs.Id == "" {
876 return nil, status.Error(codes.FailedPrecondition, "invalid-device-Id")
khenaidoob3127472019-07-24 21:04:55 -0400877 }
Kent Hagerman45a13e42020-04-13 12:23:50 -0400878 agent := dMgr.getDeviceAgent(ctx, configs.Id)
879 if agent == nil {
880 return nil, status.Errorf(codes.NotFound, "%s", configs.Id)
881 }
882 return &empty.Empty{}, agent.updatePmConfigs(ctx, configs)
khenaidoob3127472019-07-24 21:04:55 -0400883}
884
Kent Hagerman2b216042020-04-03 18:28:56 -0400885// InitPmConfigs initialize the pm configs as defined by the adapter.
886func (dMgr *Manager) InitPmConfigs(ctx context.Context, deviceID string, pmConfigs *voltha.PmConfigs) error {
khenaidoob3127472019-07-24 21:04:55 -0400887 if pmConfigs.Id == "" {
888 return status.Errorf(codes.FailedPrecondition, "invalid-device-Id")
889 }
npujar467fe752020-01-16 20:17:45 +0530890 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
891 return agent.initPmConfigs(ctx, pmConfigs)
khenaidoob9203542018-09-17 22:56:37 -0400892 }
npujar1d86a522019-11-14 17:11:16 +0530893 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoob9203542018-09-17 22:56:37 -0400894}
895
Kent Hagerman45a13e42020-04-13 12:23:50 -0400896// ListDevicePmConfigs returns pm configs of device
897func (dMgr *Manager) ListDevicePmConfigs(ctx context.Context, id *voltha.ID) (*voltha.PmConfigs, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530898 ctx = utils.WithRPCMetadataContext(ctx, "ListDevicePmConfigs")
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000899 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
Kent Hagerman45a13e42020-04-13 12:23:50 -0400900 agent := dMgr.getDeviceAgent(ctx, id.Id)
901 if agent == nil {
902 return nil, status.Errorf(codes.NotFound, "%s", id.Id)
khenaidoob3127472019-07-24 21:04:55 -0400903 }
Kent Hagerman45a13e42020-04-13 12:23:50 -0400904 return agent.listPmConfigs(ctx)
khenaidoob3127472019-07-24 21:04:55 -0400905}
906
Kent Hagerman2b216042020-04-03 18:28:56 -0400907func (dMgr *Manager) getSwitchCapability(ctx context.Context, deviceID string) (*ic.SwitchCapability, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530908 logger.Debugw(ctx, "get-switch-capability", log.Fields{"device-id": deviceID})
npujar467fe752020-01-16 20:17:45 +0530909 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
khenaidoob9203542018-09-17 22:56:37 -0400910 return agent.getSwitchCapability(ctx)
911 }
npujar1d86a522019-11-14 17:11:16 +0530912 return nil, status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoob9203542018-09-17 22:56:37 -0400913}
914
Kent Hagerman2b216042020-04-03 18:28:56 -0400915func (dMgr *Manager) GetPorts(ctx context.Context, deviceID string, portType voltha.Port_PortType) (*voltha.Ports, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530916 logger.Debugw(ctx, "get-ports", log.Fields{"device-id": deviceID, "port-type": portType})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400917 agent := dMgr.getDeviceAgent(ctx, deviceID)
918 if agent == nil {
919 return nil, status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoob9203542018-09-17 22:56:37 -0400920 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400921 return agent.getPorts(ctx, portType), nil
khenaidoob9203542018-09-17 22:56:37 -0400922}
923
Kent Hagerman2b216042020-04-03 18:28:56 -0400924func (dMgr *Manager) UpdateDeviceStatus(ctx context.Context, deviceID string, operStatus voltha.OperStatus_Types, connStatus voltha.ConnectStatus_Types) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530925 logger.Debugw(ctx, "update-device-status", log.Fields{"device-id": deviceID, "oper-status": operStatus, "conn-status": connStatus})
npujar467fe752020-01-16 20:17:45 +0530926 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
927 return agent.updateDeviceStatus(ctx, operStatus, connStatus)
khenaidoo92e62c52018-10-03 14:02:54 -0400928 }
npujar1d86a522019-11-14 17:11:16 +0530929 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo92e62c52018-10-03 14:02:54 -0400930}
931
Kent Hagerman2b216042020-04-03 18:28:56 -0400932func (dMgr *Manager) UpdateChildrenStatus(ctx context.Context, deviceID string, operStatus voltha.OperStatus_Types, connStatus voltha.ConnectStatus_Types) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530933 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 -0400934 parentDevicePorts, err := dMgr.listDevicePorts(ctx, deviceID)
935 if err != nil {
khenaidoo4d4802d2018-10-04 21:59:49 -0400936 return status.Errorf(codes.Aborted, "%s", err.Error())
937 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400938 for childDeviceID := range dMgr.getAllChildDeviceIds(ctx, parentDevicePorts) {
npujar467fe752020-01-16 20:17:45 +0530939 if agent := dMgr.getDeviceAgent(ctx, childDeviceID); agent != nil {
940 if err = agent.updateDeviceStatus(ctx, operStatus, connStatus); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530941 return status.Errorf(codes.Aborted, "childDevice:%s, error:%s", childDeviceID, err.Error())
khenaidoo4d4802d2018-10-04 21:59:49 -0400942 }
943 }
944 }
945 return nil
946}
947
Kent Hagerman2b216042020-04-03 18:28:56 -0400948func (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 +0530949 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 +0530950 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
951 if err := agent.updatePortState(ctx, portType, portNo, operStatus); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530952 logger.Errorw(ctx, "updating-port-state-failed", log.Fields{"device-id": deviceID, "port-no": portNo, "error": err})
khenaidoo171b98e2019-10-31 11:48:15 -0400953 return err
954 }
955 // Notify the logical device manager to change the port state
Mahir Gunyel18fa0c92020-03-06 13:34:04 -0800956 // Do this for NNI and UNIs only. PON ports are not known by logical device
957 if portType == voltha.Port_ETHERNET_NNI || portType == voltha.Port_ETHERNET_UNI {
958 go func() {
Himani Chawlab4c25912020-11-12 17:16:38 +0530959 subCtx := utils.WithSpanAndRPCMetadataFromContext(ctx)
960 err := dMgr.logicalDeviceMgr.updatePortState(subCtx, deviceID, portNo, operStatus)
Mahir Gunyel18fa0c92020-03-06 13:34:04 -0800961 if err != nil {
962 // While we want to handle (catch) and log when
963 // an update to a port was not able to be
964 // propagated to the logical port, we can report
965 // it as a warning and not an error because it
966 // doesn't stop or modify processing.
967 // TODO: VOL-2707
Rohan Agrawal31f21802020-06-12 05:38:46 +0000968 logger.Warnw(ctx, "unable-to-update-logical-port-state", log.Fields{"error": err})
Mahir Gunyel18fa0c92020-03-06 13:34:04 -0800969 }
970 }()
971 }
khenaidoo442e7c72020-03-10 16:13:48 -0400972 return nil
khenaidoob9203542018-09-17 22:56:37 -0400973 }
npujar1d86a522019-11-14 17:11:16 +0530974 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoob9203542018-09-17 22:56:37 -0400975}
976
Kent Hagerman2b216042020-04-03 18:28:56 -0400977func (dMgr *Manager) DeleteAllPorts(ctx context.Context, deviceID string) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530978 logger.Debugw(ctx, "delete-all-ports", log.Fields{"device-id": deviceID})
npujar467fe752020-01-16 20:17:45 +0530979 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
980 if err := agent.deleteAllPorts(ctx); err != nil {
khenaidoo0a822f92019-05-08 15:15:57 -0400981 return err
982 }
983 // Notify the logical device manager to remove all logical ports, if needed.
Kent Hagerman2b216042020-04-03 18:28:56 -0400984 // At this stage the device itself may gave been deleted already at a DeleteAllPorts
khenaidoo0a822f92019-05-08 15:15:57 -0400985 // typically is part of a device deletion phase.
Kent Hagermancba2f302020-07-28 13:37:36 -0400986 if device, err := dMgr.getDeviceReadOnly(ctx, deviceID); err == nil {
npujar1d86a522019-11-14 17:11:16 +0530987 go func() {
Himani Chawlab4c25912020-11-12 17:16:38 +0530988 subCtx := utils.WithSpanAndRPCMetadataFromContext(ctx)
989 if err := dMgr.logicalDeviceMgr.deleteAllLogicalPorts(subCtx, device); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000990 logger.Errorw(ctx, "unable-to-delete-logical-ports", log.Fields{"error": err})
npujar1d86a522019-11-14 17:11:16 +0530991 }
992 }()
khenaidoo0a822f92019-05-08 15:15:57 -0400993 } else {
divyadesaicb8b59d2020-08-18 09:55:47 +0000994 logger.Warnw(ctx, "failed-to-retrieve-device", log.Fields{"device-id": deviceID})
khenaidoo0a822f92019-05-08 15:15:57 -0400995 return err
996 }
997 return nil
998 }
npujar1d86a522019-11-14 17:11:16 +0530999 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo0a822f92019-05-08 15:15:57 -04001000}
1001
Kent Hagerman2b216042020-04-03 18:28:56 -04001002//UpdatePortsState updates all ports on the device
Kent Hagerman2a07b862020-06-19 15:23:07 -04001003func (dMgr *Manager) UpdatePortsState(ctx context.Context, deviceID string, portTypeFilter uint32, state voltha.OperStatus_Types) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301004 logger.Debugw(ctx, "update-ports-state", log.Fields{"device-id": deviceID})
Kent Hagerman2a07b862020-06-19 15:23:07 -04001005 agent := dMgr.getDeviceAgent(ctx, deviceID)
1006 if agent == nil {
1007 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo3ab34882019-05-02 21:33:30 -04001008 }
Kent Hagerman2a07b862020-06-19 15:23:07 -04001009 if state != voltha.OperStatus_ACTIVE && state != voltha.OperStatus_UNKNOWN {
1010 return status.Error(codes.Unimplemented, "state-change-not-implemented")
1011 }
1012 if err := agent.updatePortsOperState(ctx, portTypeFilter, state); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +05301013 logger.Warnw(ctx, "update-ports-state-failed", log.Fields{"device-id": deviceID, "error": err})
Kent Hagerman2a07b862020-06-19 15:23:07 -04001014 return err
1015 }
1016 return nil
khenaidoo3ab34882019-05-02 21:33:30 -04001017}
1018
Kent Hagerman2b216042020-04-03 18:28:56 -04001019func (dMgr *Manager) ChildDeviceDetected(ctx context.Context, parentDeviceID string, parentPortNo int64, deviceType string,
npujar1d86a522019-11-14 17:11:16 +05301020 channelID int64, vendorID string, serialNumber string, onuID int64) (*voltha.Device, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301021 logger.Debugw(ctx, "child-device-detected", log.Fields{"parent-device-id": parentDeviceID, "parent-port-no": parentPortNo, "device-type": deviceType, "channel-id": channelID, "vendor-id": vendorID, "serial-number": serialNumber, "onu-id": onuID})
Chaitrashree G S4b3fada2019-07-28 23:55:25 -07001022
npujar1d86a522019-11-14 17:11:16 +05301023 if deviceType == "" && vendorID != "" {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001024 logger.Debug(ctx, "device-type-is-nil-fetching-device-type")
Kent Hagerman45a13e42020-04-13 12:23:50 -04001025 deviceTypes, err := dMgr.adapterMgr.ListDeviceTypes(ctx, nil)
1026 if err != nil {
1027 return nil, err
1028 }
Kent Hagerman4f355f52020-03-30 16:01:33 -04001029 OLoop:
Kent Hagerman45a13e42020-04-13 12:23:50 -04001030 for _, dType := range deviceTypes.Items {
Kent Hagerman4f355f52020-03-30 16:01:33 -04001031 for _, v := range dType.VendorIds {
1032 if v == vendorID {
1033 deviceType = dType.Adapter
1034 break OLoop
Chaitrashree G S4b3fada2019-07-28 23:55:25 -07001035 }
1036 }
1037 }
1038 }
1039 //if no match found for the vendorid,report adapter with the custom error message
1040 if deviceType == "" {
Himani Chawlab4c25912020-11-12 17:16:38 +05301041 logger.Errorw(ctx, "failed-to-fetch-adapter-name ", log.Fields{"vendor-id": vendorID})
npujar1d86a522019-11-14 17:11:16 +05301042 return nil, status.Errorf(codes.NotFound, "%s", vendorID)
Chaitrashree G S4b3fada2019-07-28 23:55:25 -07001043 }
khenaidoob9203542018-09-17 22:56:37 -04001044
1045 // Create the ONU device
1046 childDevice := &voltha.Device{}
khenaidoob9203542018-09-17 22:56:37 -04001047 childDevice.Type = deviceType
npujar1d86a522019-11-14 17:11:16 +05301048 childDevice.ParentId = parentDeviceID
khenaidoob9203542018-09-17 22:56:37 -04001049 childDevice.ParentPortNo = uint32(parentPortNo)
npujar1d86a522019-11-14 17:11:16 +05301050 childDevice.VendorId = vendorID
Matt Jeanneret4e241952019-02-28 11:16:04 -05001051 childDevice.SerialNumber = serialNumber
khenaidoob9203542018-09-17 22:56:37 -04001052 childDevice.Root = false
khenaidoo6fdf0ba2018-11-02 14:38:33 -04001053
khenaidoo442e7c72020-03-10 16:13:48 -04001054 // Get parent device type
1055 pAgent := dMgr.getDeviceAgent(ctx, parentDeviceID)
1056 if pAgent == nil {
npujar1d86a522019-11-14 17:11:16 +05301057 return nil, status.Errorf(codes.NotFound, "%s", parentDeviceID)
khenaidoo6fdf0ba2018-11-02 14:38:33 -04001058 }
khenaidoo442e7c72020-03-10 16:13:48 -04001059 if pAgent.deviceType == "" {
1060 return nil, status.Errorf(codes.FailedPrecondition, "device Type not set %s", parentDeviceID)
1061 }
khenaidoo6fdf0ba2018-11-02 14:38:33 -04001062
npujar467fe752020-01-16 20:17:45 +05301063 if device, err := dMgr.GetChildDevice(ctx, parentDeviceID, serialNumber, onuID, parentPortNo); err == nil {
Himani Chawlab4c25912020-11-12 17:16:38 +05301064 logger.Warnw(ctx, "child-device-exists", log.Fields{"parent-device-id": parentDeviceID, "serial-number": serialNumber})
Mahir Gunyel6deaa242019-06-27 04:53:33 -07001065 return device, status.Errorf(codes.AlreadyExists, "%s", serialNumber)
Matt Jeanneret4e241952019-02-28 11:16:04 -05001066 }
1067
khenaidoo442e7c72020-03-10 16:13:48 -04001068 childDevice.ProxyAddress = &voltha.Device_ProxyAddress{DeviceId: parentDeviceID, DeviceType: pAgent.deviceType, ChannelId: uint32(channelID), OnuId: uint32(onuID)}
khenaidoob9203542018-09-17 22:56:37 -04001069
1070 // Create and start a device agent for that device
Mahir Gunyel03de0d32020-06-03 01:36:59 -07001071 agent := newAgent(dMgr.adapterProxy, childDevice, dMgr, dMgr.dbPath, dMgr.dProxy, dMgr.defaultTimeout)
khenaidoo7585a962021-06-10 16:15:38 -04001072 insertedChildDevice, err := agent.start(ctx, false, childDevice)
Scott Baker80678602019-11-14 16:57:36 -08001073 if err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001074 logger.Errorw(ctx, "error-starting-child-device", log.Fields{"parent-device-id": childDevice.ParentId, "child-device-id": agent.deviceID, "error": err})
Scott Baker80678602019-11-14 16:57:36 -08001075 return nil, err
1076 }
khenaidoo442e7c72020-03-10 16:13:48 -04001077 dMgr.addDeviceAgentToMap(agent)
khenaidoob9203542018-09-17 22:56:37 -04001078
1079 // Activate the child device
npujar467fe752020-01-16 20:17:45 +05301080 if agent = dMgr.getDeviceAgent(ctx, agent.deviceID); agent != nil {
npujar1d86a522019-11-14 17:11:16 +05301081 go func() {
Maninder9a1bc0d2020-10-26 11:34:02 +05301082 subCtx := utils.WithFromTopicMetadataFromContext(utils.WithSpanAndRPCMetadataFromContext(ctx), ctx)
Himani Chawlab4c25912020-11-12 17:16:38 +05301083 err := agent.enableDevice(subCtx)
npujar1d86a522019-11-14 17:11:16 +05301084 if err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001085 logger.Errorw(ctx, "unable-to-enable-device", log.Fields{"error": err})
npujar1d86a522019-11-14 17:11:16 +05301086 }
1087 }()
khenaidoob9203542018-09-17 22:56:37 -04001088 }
1089
Mahir Gunyel23bd8c72020-09-21 23:20:43 -07001090 return insertedChildDevice, nil
khenaidoob9203542018-09-17 22:56:37 -04001091}
1092
Kent Hagerman2b216042020-04-03 18:28:56 -04001093func (dMgr *Manager) packetOut(ctx context.Context, deviceID string, outPort uint32, packet *ofp.OfpPacketOut) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301094 logger.Debugw(ctx, "packet-out", log.Fields{"device-id": deviceID, "out-port": outPort})
npujar467fe752020-01-16 20:17:45 +05301095 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
1096 return agent.packetOut(ctx, outPort, packet)
khenaidoofdbad6e2018-11-06 22:26:38 -05001097 }
npujar1d86a522019-11-14 17:11:16 +05301098 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoofdbad6e2018-11-06 22:26:38 -05001099}
1100
npujar1d86a522019-11-14 17:11:16 +05301101// PacketIn receives packet from adapter
Kent Hagerman2b216042020-04-03 18:28:56 -04001102func (dMgr *Manager) PacketIn(ctx context.Context, deviceID string, port uint32, transactionID string, packet []byte) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301103 logger.Debugw(ctx, "packet-in", log.Fields{"device-id": deviceID, "port": port})
khenaidoofdbad6e2018-11-06 22:26:38 -05001104 // Get the logical device Id based on the deviceId
1105 var device *voltha.Device
1106 var err error
Kent Hagermancba2f302020-07-28 13:37:36 -04001107 if device, err = dMgr.getDeviceReadOnly(ctx, deviceID); err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +00001108 logger.Errorw(ctx, "device-not-found", log.Fields{"device-id": deviceID})
khenaidoofdbad6e2018-11-06 22:26:38 -05001109 return err
1110 }
khenaidoo43c82122018-11-22 18:38:28 -05001111 if !device.Root {
divyadesaicb8b59d2020-08-18 09:55:47 +00001112 logger.Errorw(ctx, "device-not-root", log.Fields{"device-id": deviceID})
npujar1d86a522019-11-14 17:11:16 +05301113 return status.Errorf(codes.FailedPrecondition, "%s", deviceID)
khenaidoofdbad6e2018-11-06 22:26:38 -05001114 }
1115
npujar467fe752020-01-16 20:17:45 +05301116 if err := dMgr.logicalDeviceMgr.packetIn(ctx, device.ParentId, port, transactionID, packet); err != nil {
khenaidoofdbad6e2018-11-06 22:26:38 -05001117 return err
1118 }
1119 return nil
1120}
1121
Kent Hagerman2b216042020-04-03 18:28:56 -04001122func (dMgr *Manager) setParentID(ctx context.Context, device *voltha.Device, parentID string) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301123 logger.Debugw(ctx, "set-parent-id", log.Fields{"device-id": device.Id, "parent-id": parentID})
npujar467fe752020-01-16 20:17:45 +05301124 if agent := dMgr.getDeviceAgent(ctx, device.Id); agent != nil {
1125 return agent.setParentID(ctx, device, parentID)
khenaidooad06fd72019-10-28 12:26:05 -04001126 }
1127 return status.Errorf(codes.NotFound, "%s", device.Id)
1128}
1129
Himani Chawlab4c25912020-11-12 17:16:38 +05301130//
1131//CreateLogicalDevice creates logical device in core
Kent Hagerman2b216042020-04-03 18:28:56 -04001132func (dMgr *Manager) CreateLogicalDevice(ctx context.Context, cDevice *voltha.Device) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301133 logger.Info(ctx, "create-logical-device")
khenaidoo59ef7be2019-06-21 12:40:28 -04001134 // Verify whether the logical device has already been created
1135 if cDevice.ParentId != "" {
Himani Chawlab4c25912020-11-12 17:16:38 +05301136 logger.Debugw(ctx, "parent-device-already-exist", log.Fields{"device-id": cDevice.Id, "logical-device-id": cDevice.Id})
khenaidoo59ef7be2019-06-21 12:40:28 -04001137 return nil
1138 }
khenaidoob9203542018-09-17 22:56:37 -04001139 var err error
npujar467fe752020-01-16 20:17:45 +05301140 if _, err = dMgr.logicalDeviceMgr.createLogicalDevice(ctx, cDevice); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +05301141 logger.Warnw(ctx, "create-logical-device-error", log.Fields{"device": cDevice})
khenaidoob9203542018-09-17 22:56:37 -04001142 return err
1143 }
khenaidoob9203542018-09-17 22:56:37 -04001144 return nil
1145}
1146
npujar1d86a522019-11-14 17:11:16 +05301147// DeleteLogicalDevice deletes logical device from core
Kent Hagerman2b216042020-04-03 18:28:56 -04001148func (dMgr *Manager) DeleteLogicalDevice(ctx context.Context, cDevice *voltha.Device) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301149 logger.Info(ctx, "delete-logical-device")
khenaidoo92e62c52018-10-03 14:02:54 -04001150 var err error
npujar467fe752020-01-16 20:17:45 +05301151 if err = dMgr.logicalDeviceMgr.deleteLogicalDevice(ctx, cDevice); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +05301152 logger.Warnw(ctx, "delete-logical-device-error", log.Fields{"device-id": cDevice.Id})
khenaidoo92e62c52018-10-03 14:02:54 -04001153 return err
1154 }
1155 // Remove the logical device Id from the parent device
npujar1d86a522019-11-14 17:11:16 +05301156 logicalID := ""
npujar467fe752020-01-16 20:17:45 +05301157 dMgr.UpdateDeviceAttribute(ctx, cDevice.Id, "ParentId", logicalID)
khenaidoo92e62c52018-10-03 14:02:54 -04001158 return nil
1159}
1160
npujar1d86a522019-11-14 17:11:16 +05301161// DeleteLogicalPorts removes the logical ports associated with that deviceId
Kent Hagerman2b216042020-04-03 18:28:56 -04001162func (dMgr *Manager) DeleteLogicalPorts(ctx context.Context, cDevice *voltha.Device) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001163 logger.Debugw(ctx, "delete-all-logical-ports", log.Fields{"device-id": cDevice.Id})
khenaidoo442e7c72020-03-10 16:13:48 -04001164 if err := dMgr.logicalDeviceMgr.deleteLogicalPorts(ctx, cDevice.Id); err != nil {
khenaidooe132f522020-03-20 15:23:15 -04001165 // Just log the error. The logical device or port may already have been deleted before this callback is invoked.
Himani Chawlab4c25912020-11-12 17:16:38 +05301166 logger.Warnw(ctx, "delete-logical-ports-error", log.Fields{"device-id": cDevice.Id, "error": err})
khenaidoo0a822f92019-05-08 15:15:57 -04001167 }
1168 return nil
1169}
1170
Kent Hagerman2b216042020-04-03 18:28:56 -04001171func (dMgr *Manager) getParentDevice(ctx context.Context, childDevice *voltha.Device) *voltha.Device {
khenaidoo92e62c52018-10-03 14:02:54 -04001172 // Sanity check
1173 if childDevice.Root {
1174 // childDevice is the parent device
1175 return childDevice
1176 }
Kent Hagermancba2f302020-07-28 13:37:36 -04001177 parentDevice, _ := dMgr.getDeviceReadOnly(ctx, childDevice.ParentId)
khenaidoo92e62c52018-10-03 14:02:54 -04001178 return parentDevice
1179}
1180
Kent Hagerman2b216042020-04-03 18:28:56 -04001181//ChildDevicesLost is invoked by an adapter to indicate that a parent device is in a state (Disabled) where it
khenaidoo0a822f92019-05-08 15:15:57 -04001182//cannot manage the child devices. This will trigger the Core to disable all the child devices.
Kent Hagerman2b216042020-04-03 18:28:56 -04001183func (dMgr *Manager) ChildDevicesLost(ctx context.Context, parentDeviceID string) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301184 logger.Debug(ctx, "child-devices-lost")
Kent Hagermancba2f302020-07-28 13:37:36 -04001185 parentDevice, err := dMgr.getDeviceReadOnly(ctx, parentDeviceID)
Kent Hagerman2a07b862020-06-19 15:23:07 -04001186 if err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +00001187 logger.Warnw(ctx, "failed-getting-device", log.Fields{"parent-device-id": parentDeviceID, "error": err})
khenaidoo0a822f92019-05-08 15:15:57 -04001188 return err
1189 }
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001190 return dMgr.DisableAllChildDevices(ctx, parentDevice)
khenaidoo0a822f92019-05-08 15:15:57 -04001191}
1192
Kent Hagerman2b216042020-04-03 18:28:56 -04001193//ChildDevicesDetected is invoked by an adapter when child devices are found, typically after after a
khenaidoo0a822f92019-05-08 15:15:57 -04001194// disable/enable sequence. This will trigger the Core to Enable all the child devices of that parent.
Kent Hagerman2b216042020-04-03 18:28:56 -04001195func (dMgr *Manager) ChildDevicesDetected(ctx context.Context, parentDeviceID string) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301196 logger.Debug(ctx, "child-devices-detected")
Kent Hagerman2a07b862020-06-19 15:23:07 -04001197 parentDevicePorts, err := dMgr.listDevicePorts(ctx, parentDeviceID)
1198 if err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +00001199 logger.Warnw(ctx, "failed-getting-device", log.Fields{"device-id": parentDeviceID, "error": err})
khenaidoo0a822f92019-05-08 15:15:57 -04001200 return err
1201 }
Kent Hagerman2a07b862020-06-19 15:23:07 -04001202 childDeviceIds := dMgr.getAllChildDeviceIds(ctx, parentDevicePorts)
khenaidoo0a822f92019-05-08 15:15:57 -04001203 if len(childDeviceIds) == 0 {
divyadesaicb8b59d2020-08-18 09:55:47 +00001204 logger.Debugw(ctx, "no-child-device", log.Fields{"parent-device-id": parentDeviceID})
khenaidoo0a822f92019-05-08 15:15:57 -04001205 }
khenaidoo59ef7be2019-06-21 12:40:28 -04001206 allChildEnableRequestSent := true
Kent Hagerman2a07b862020-06-19 15:23:07 -04001207 for childDeviceID := range childDeviceIds {
npujar467fe752020-01-16 20:17:45 +05301208 if agent := dMgr.getDeviceAgent(ctx, childDeviceID); agent != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +05301209 subCtx := utils.WithSpanAndRPCMetadataFromContext(ctx)
khenaidoo59ef7be2019-06-21 12:40:28 -04001210 // Run the children re-registration in its own routine
Kent Hagerman2a07b862020-06-19 15:23:07 -04001211 go func(ctx context.Context) {
1212 err = agent.enableDevice(ctx)
npujar1d86a522019-11-14 17:11:16 +05301213 if err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001214 logger.Errorw(ctx, "unable-to-enable-device", log.Fields{"error": err})
npujar1d86a522019-11-14 17:11:16 +05301215 }
Himani Chawlab4c25912020-11-12 17:16:38 +05301216 }(subCtx)
khenaidoo59ef7be2019-06-21 12:40:28 -04001217 } else {
npujar1d86a522019-11-14 17:11:16 +05301218 err = status.Errorf(codes.Unavailable, "no agent for child device %s", childDeviceID)
Himani Chawlab4c25912020-11-12 17:16:38 +05301219 logger.Errorw(ctx, "no-child-device-agent", log.Fields{"parent-device-id": parentDeviceID, "child-id": childDeviceID})
khenaidoo59ef7be2019-06-21 12:40:28 -04001220 allChildEnableRequestSent = false
khenaidoo0a822f92019-05-08 15:15:57 -04001221 }
1222 }
khenaidoo59ef7be2019-06-21 12:40:28 -04001223 if !allChildEnableRequestSent {
khenaidoo0a822f92019-05-08 15:15:57 -04001224 return err
1225 }
1226 return nil
1227}
1228
khenaidoo4d4802d2018-10-04 21:59:49 -04001229/*
1230All the functions below are callback functions where they are invoked with the latest and previous data. We can
1231therefore use the data as is without trying to get the latest from the model.
1232*/
1233
khenaidoo0a822f92019-05-08 15:15:57 -04001234//DisableAllChildDevices is invoked as a callback when the parent device is disabled
Kent Hagerman2b216042020-04-03 18:28:56 -04001235func (dMgr *Manager) DisableAllChildDevices(ctx context.Context, parentCurrDevice *voltha.Device) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301236 logger.Debug(ctx, "disable-all-child-devices")
Kent Hagerman2a07b862020-06-19 15:23:07 -04001237 ports, _ := dMgr.listDevicePorts(ctx, parentCurrDevice.Id)
1238 for childDeviceID := range dMgr.getAllChildDeviceIds(ctx, ports) {
npujar467fe752020-01-16 20:17:45 +05301239 if agent := dMgr.getDeviceAgent(ctx, childDeviceID); agent != nil {
Kent Hagerman2a07b862020-06-19 15:23:07 -04001240 if err := agent.disableDevice(ctx); err != nil {
khenaidooe132f522020-03-20 15:23:15 -04001241 // Just log the error - this error happens only if the child device was already in deleted state.
divyadesaicb8b59d2020-08-18 09:55:47 +00001242 logger.Errorw(ctx, "failure-disable-device", log.Fields{"device-id": childDeviceID, "error": err.Error()})
khenaidoo92e62c52018-10-03 14:02:54 -04001243 }
1244 }
1245 }
1246 return nil
1247}
1248
khenaidoo0a822f92019-05-08 15:15:57 -04001249//DeleteAllChildDevices is invoked as a callback when the parent device is deleted
Kent Hagerman2b216042020-04-03 18:28:56 -04001250func (dMgr *Manager) DeleteAllChildDevices(ctx context.Context, parentCurrDevice *voltha.Device) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301251 logger.Debug(ctx, "delete-all-child-devices")
Himani Chawla2ba1c9c2020-10-07 13:19:03 +05301252 force := false
1253 // Get the parent device Transient state, if its FORCE_DELETED(go for force delete for child devices)
1254 // So in cases when this handler is getting called other than DELETE operation, no force option would be used.
1255 agent := dMgr.getDeviceAgent(ctx, parentCurrDevice.Id)
1256 if agent == nil {
1257 return status.Errorf(codes.NotFound, "%s", parentCurrDevice.Id)
1258 }
1259
1260 force = agent.getTransientState() == voltha.DeviceTransientState_FORCE_DELETING
1261
Kent Hagerman2a07b862020-06-19 15:23:07 -04001262 ports, _ := dMgr.listDevicePorts(ctx, parentCurrDevice.Id)
1263 for childDeviceID := range dMgr.getAllChildDeviceIds(ctx, ports) {
npujar467fe752020-01-16 20:17:45 +05301264 if agent := dMgr.getDeviceAgent(ctx, childDeviceID); agent != nil {
Himani Chawla2ba1c9c2020-10-07 13:19:03 +05301265 if force {
1266 if err := agent.deleteDeviceForce(ctx); err != nil {
1267 logger.Warnw(ctx, "failure-delete-device-force", log.Fields{"device-id": childDeviceID,
1268 "error": err.Error()})
1269 }
1270 } else {
1271 if err := agent.deleteDevice(ctx); err != nil {
1272 logger.Warnw(ctx, "failure-delete-device", log.Fields{"device-id": childDeviceID,
1273 "error": err.Error()})
1274 }
khenaidoo4d4802d2018-10-04 21:59:49 -04001275 }
khenaidoo49085352020-01-13 19:15:43 -05001276 // No further action is required here. The deleteDevice will change the device state where the resulting
1277 // callback will take care of cleaning the child device agent.
khenaidoo4d4802d2018-10-04 21:59:49 -04001278 }
1279 }
khenaidoo4d4802d2018-10-04 21:59:49 -04001280 return nil
1281}
1282
Girish Gowdra408cd962020-03-11 14:31:31 -07001283//DeleteAllLogicalPorts is invoked as a callback when the parent device's connection status moves to UNREACHABLE
Kent Hagerman2b216042020-04-03 18:28:56 -04001284func (dMgr *Manager) DeleteAllLogicalPorts(ctx context.Context, parentDevice *voltha.Device) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001285 logger.Debugw(ctx, "delete-all-logical-ports", log.Fields{"parent-device-id": parentDevice.Id})
Girish Gowdra408cd962020-03-11 14:31:31 -07001286 if err := dMgr.logicalDeviceMgr.deleteAllLogicalPorts(ctx, parentDevice); err != nil {
khenaidooe132f522020-03-20 15:23:15 -04001287 // Just log error as logical device may already have been deleted
Rohan Agrawal31f21802020-06-12 05:38:46 +00001288 logger.Warnw(ctx, "delete-all-logical-ports-fail", log.Fields{"parent-device-id": parentDevice.Id, "error": err})
Girish Gowdra408cd962020-03-11 14:31:31 -07001289 }
1290 return nil
1291}
1292
1293//DeleteAllDeviceFlows is invoked as a callback when the parent device's connection status moves to UNREACHABLE
Kent Hagerman2b216042020-04-03 18:28:56 -04001294func (dMgr *Manager) DeleteAllDeviceFlows(ctx context.Context, parentDevice *voltha.Device) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001295 logger.Debugw(ctx, "delete-all-device-flows", log.Fields{"parent-device-id": parentDevice.Id})
Girish Gowdra408cd962020-03-11 14:31:31 -07001296 if agent := dMgr.getDeviceAgent(ctx, parentDevice.Id); agent != nil {
1297 if err := agent.deleteAllFlows(ctx); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001298 logger.Errorw(ctx, "error-deleting-all-device-flows", log.Fields{"parent-device-id": parentDevice.Id})
Girish Gowdra408cd962020-03-11 14:31:31 -07001299 return err
1300 }
1301 return nil
1302 }
1303 return status.Errorf(codes.NotFound, "%s", parentDevice.Id)
1304}
1305
khenaidoo4d4802d2018-10-04 21:59:49 -04001306//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 -04001307func (dMgr *Manager) getAllChildDeviceIds(ctx context.Context, parentDevicePorts map[uint32]*voltha.Port) map[string]struct{} {
Himani Chawlab4c25912020-11-12 17:16:38 +05301308 logger.Debug(ctx, "get-all-child-device-ids")
Kent Hagerman2a07b862020-06-19 15:23:07 -04001309 childDeviceIds := make(map[string]struct{}, len(parentDevicePorts))
1310 for _, port := range parentDevicePorts {
1311 for _, peer := range port.Peers {
1312 childDeviceIds[peer.DeviceId] = struct{}{}
khenaidoo92e62c52018-10-03 14:02:54 -04001313 }
1314 }
Kent Hagerman2a07b862020-06-19 15:23:07 -04001315 logger.Debugw(ctx, "returning-getAllChildDeviceIds", log.Fields{"childDeviceIds": childDeviceIds})
1316 return childDeviceIds
khenaidoo92e62c52018-10-03 14:02:54 -04001317}
1318
Kent Hagerman2b216042020-04-03 18:28:56 -04001319//GetAllChildDevices is a helper method to get all the child device IDs from the device passed as parameter
1320func (dMgr *Manager) GetAllChildDevices(ctx context.Context, parentDeviceID string) (*voltha.Devices, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301321 logger.Debugw(ctx, "get-all-child-devices", log.Fields{"parent-device-id": parentDeviceID})
Kent Hagerman2a07b862020-06-19 15:23:07 -04001322 if parentDevicePorts, err := dMgr.listDevicePorts(ctx, parentDeviceID); err == nil {
khenaidoo297cd252019-02-07 22:10:23 -05001323 childDevices := make([]*voltha.Device, 0)
Kent Hagerman2a07b862020-06-19 15:23:07 -04001324 for deviceID := range dMgr.getAllChildDeviceIds(ctx, parentDevicePorts) {
Kent Hagermancba2f302020-07-28 13:37:36 -04001325 if d, e := dMgr.getDeviceReadOnly(ctx, deviceID); e == nil && d != nil {
Kent Hagerman2a07b862020-06-19 15:23:07 -04001326 childDevices = append(childDevices, d)
khenaidoo297cd252019-02-07 22:10:23 -05001327 }
1328 }
1329 return &voltha.Devices{Items: childDevices}, nil
1330 }
npujar1d86a522019-11-14 17:11:16 +05301331 return nil, status.Errorf(codes.NotFound, "%s", parentDeviceID)
khenaidoo297cd252019-02-07 22:10:23 -05001332}
1333
npujar1d86a522019-11-14 17:11:16 +05301334// SetupUNILogicalPorts creates UNI ports on the logical device that represents a child UNI interface
Kent Hagerman2b216042020-04-03 18:28:56 -04001335func (dMgr *Manager) SetupUNILogicalPorts(ctx context.Context, cDevice *voltha.Device) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301336 logger.Info(ctx, "setup-uni-logical-ports")
Kent Hagerman2a07b862020-06-19 15:23:07 -04001337 cDevicePorts, err := dMgr.listDevicePorts(ctx, cDevice.Id)
1338 if err != nil {
1339 return err
1340 }
1341 if err := dMgr.logicalDeviceMgr.setupUNILogicalPorts(ctx, cDevice, cDevicePorts); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +05301342 logger.Warnw(ctx, "setup-uni-logical-ports-error", log.Fields{"device": cDevice, "err": err})
khenaidoob9203542018-09-17 22:56:37 -04001343 return err
1344 }
1345 return nil
1346}
1347
Kent Hagerman45a13e42020-04-13 12:23:50 -04001348// convenience to avoid redefining
1349var operationFailureResp = &common.OperationResp{Code: voltha.OperationResp_OPERATION_FAILURE}
1350
1351// DownloadImage execute an image download request
1352func (dMgr *Manager) DownloadImage(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301353 ctx = utils.WithRPCMetadataContext(ctx, "DownloadImage")
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001354 log.EnrichSpan(ctx, log.Fields{"device-id": img.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +05301355 logger.Debugw(ctx, "download-image", log.Fields{"device-id": img.Id, "image-name": img.Name})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001356 agent := dMgr.getDeviceAgent(ctx, img.Id)
1357 if agent == nil {
1358 return operationFailureResp, status.Errorf(codes.NotFound, "%s", img.Id)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001359 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001360 resp, err := agent.downloadImage(ctx, img)
1361 if err != nil {
1362 return operationFailureResp, err
1363 }
1364 return resp, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001365}
1366
Kent Hagerman45a13e42020-04-13 12:23:50 -04001367// CancelImageDownload cancels image download request
1368func (dMgr *Manager) CancelImageDownload(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301369 ctx = utils.WithRPCMetadataContext(ctx, "CancelImageDownload")
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001370 log.EnrichSpan(ctx, log.Fields{"device-id": img.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +05301371 logger.Debugw(ctx, "cancel-image-download", log.Fields{"device-id": img.Id, "image-name": img.Name})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001372 agent := dMgr.getDeviceAgent(ctx, img.Id)
1373 if agent == nil {
1374 return operationFailureResp, status.Errorf(codes.NotFound, "%s", img.Id)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001375 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001376 resp, err := agent.cancelImageDownload(ctx, img)
1377 if err != nil {
1378 return operationFailureResp, err
1379 }
1380 return resp, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001381}
1382
Kent Hagerman45a13e42020-04-13 12:23:50 -04001383// ActivateImageUpdate activates image update request
1384func (dMgr *Manager) ActivateImageUpdate(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301385 ctx = utils.WithRPCMetadataContext(ctx, "ActivateImageUpdate")
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001386 log.EnrichSpan(ctx, log.Fields{"device-id": img.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +05301387 logger.Debugw(ctx, "activate-image-update", log.Fields{"device-id": img.Id, "image-name": img.Name})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001388 agent := dMgr.getDeviceAgent(ctx, img.Id)
1389 if agent == nil {
1390 return operationFailureResp, status.Errorf(codes.NotFound, "%s", img.Id)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001391 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001392 resp, err := agent.activateImage(ctx, img)
1393 if err != nil {
1394 return operationFailureResp, err
1395 }
1396 return resp, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001397}
1398
Kent Hagerman45a13e42020-04-13 12:23:50 -04001399// RevertImageUpdate reverts image update
1400func (dMgr *Manager) RevertImageUpdate(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301401 ctx = utils.WithRPCMetadataContext(ctx, "RevertImageUpdate")
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001402 log.EnrichSpan(ctx, log.Fields{"device-id": img.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +05301403 logger.Debugw(ctx, "rever-image-update", log.Fields{"device-id": img.Id, "image-name": img.Name})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001404 agent := dMgr.getDeviceAgent(ctx, img.Id)
1405 if agent == nil {
1406 return operationFailureResp, status.Errorf(codes.NotFound, "%s", img.Id)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001407 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001408 resp, err := agent.revertImage(ctx, img)
1409 if err != nil {
1410 return operationFailureResp, err
1411 }
1412 return resp, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001413}
1414
Kent Hagerman45a13e42020-04-13 12:23:50 -04001415// convenience to avoid redefining
1416var imageDownloadFailureResp = &voltha.ImageDownload{DownloadState: voltha.ImageDownload_DOWNLOAD_UNKNOWN}
1417
1418// GetImageDownloadStatus returns status of image download
1419func (dMgr *Manager) GetImageDownloadStatus(ctx context.Context, img *voltha.ImageDownload) (*voltha.ImageDownload, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301420 ctx = utils.WithRPCMetadataContext(ctx, "GetImageDownloadStatus")
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001421 log.EnrichSpan(ctx, log.Fields{"device-id": img.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +05301422 logger.Debugw(ctx, "get-image-download-status", log.Fields{"device-id": img.Id, "image-name": img.Name})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001423 agent := dMgr.getDeviceAgent(ctx, img.Id)
1424 if agent == nil {
1425 return imageDownloadFailureResp, status.Errorf(codes.NotFound, "%s", img.Id)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001426 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001427 resp, err := agent.getImageDownloadStatus(ctx, img)
1428 if err != nil {
1429 return imageDownloadFailureResp, err
1430 }
1431 return resp, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001432}
1433
Kent Hagerman2b216042020-04-03 18:28:56 -04001434func (dMgr *Manager) UpdateImageDownload(ctx context.Context, deviceID string, img *voltha.ImageDownload) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301435 ctx = utils.WithRPCMetadataContext(ctx, "UpdateImageDownload")
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001436 log.EnrichSpan(ctx, log.Fields{"device-id": img.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +05301437 logger.Debugw(ctx, "update-image-download", log.Fields{"device-id": img.Id, "image-name": img.Name})
npujar467fe752020-01-16 20:17:45 +05301438 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
1439 if err := agent.updateImageDownload(ctx, img); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +05301440 logger.Debugw(ctx, "update-image-download-failed", log.Fields{"err": err, "image-name": img.Name})
khenaidoof5a5bfa2019-01-23 22:20:29 -05001441 return err
1442 }
1443 } else {
1444 return status.Errorf(codes.NotFound, "%s", img.Id)
1445 }
1446 return nil
1447}
1448
Kent Hagerman45a13e42020-04-13 12:23:50 -04001449// GetImageDownload returns image download
Kent Hagerman2b216042020-04-03 18:28:56 -04001450func (dMgr *Manager) GetImageDownload(ctx context.Context, img *voltha.ImageDownload) (*voltha.ImageDownload, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301451 ctx = utils.WithRPCMetadataContext(ctx, "GetImageDownload")
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001452 log.EnrichSpan(ctx, log.Fields{"device-id": img.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +05301453 logger.Debugw(ctx, "get-image-download", log.Fields{"device-id": img.Id, "image-name": img.Name})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001454 agent := dMgr.getDeviceAgent(ctx, img.Id)
1455 if agent == nil {
1456 return imageDownloadFailureResp, status.Errorf(codes.NotFound, "%s", img.Id)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001457 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001458 resp, err := agent.getImageDownload(ctx, img)
1459 if err != nil {
1460 return imageDownloadFailureResp, err
1461 }
1462 return resp, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001463}
1464
Kent Hagerman45a13e42020-04-13 12:23:50 -04001465// ListImageDownloads returns image downloads
1466func (dMgr *Manager) ListImageDownloads(ctx context.Context, id *voltha.ID) (*voltha.ImageDownloads, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301467 ctx = utils.WithRPCMetadataContext(ctx, "ListImageDownloads")
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001468 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +05301469 logger.Debugw(ctx, "list-image-downloads", log.Fields{"device-id": id.Id})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001470 agent := dMgr.getDeviceAgent(ctx, id.Id)
1471 if agent == nil {
1472 return &voltha.ImageDownloads{Items: []*voltha.ImageDownload{imageDownloadFailureResp}}, status.Errorf(codes.NotFound, "%s", id.Id)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001473 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001474 resp, err := agent.listImageDownloads(ctx, id.Id)
1475 if err != nil {
1476 return &voltha.ImageDownloads{Items: []*voltha.ImageDownload{imageDownloadFailureResp}}, err
1477 }
1478 return resp, nil
1479}
1480
1481// GetImages returns all images for a specific device entry
1482func (dMgr *Manager) GetImages(ctx context.Context, id *voltha.ID) (*voltha.Images, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301483 ctx = utils.WithRPCMetadataContext(ctx, "GetImages")
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001484 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +05301485 logger.Debugw(ctx, "get-images", log.Fields{"device-id": id.Id})
Kent Hagermancba2f302020-07-28 13:37:36 -04001486 device, err := dMgr.getDeviceReadOnly(ctx, id.Id)
Kent Hagerman45a13e42020-04-13 12:23:50 -04001487 if err != nil {
1488 return nil, err
1489 }
Kent Hagermancba2f302020-07-28 13:37:36 -04001490 return device.Images, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001491}
1492
Rohan Agrawal31f21802020-06-12 05:38:46 +00001493func (dMgr *Manager) NotifyInvalidTransition(ctx context.Context, device *voltha.Device) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301494 logger.Errorw(ctx, "notify-invalid-transition", log.Fields{
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001495 "device": device.Id,
1496 "curr-admin-state": device.AdminState,
1497 "curr-oper-state": device.OperStatus,
1498 "curr-conn-state": device.ConnectStatus,
Stephane Barbarieef6650d2019-07-18 12:15:09 -04001499 })
khenaidoo0a822f92019-05-08 15:15:57 -04001500 //TODO: notify over kafka?
1501 return nil
1502}
1503
npujar1d86a522019-11-14 17:11:16 +05301504// UpdateDeviceAttribute updates value of particular device attribute
Kent Hagerman2b216042020-04-03 18:28:56 -04001505func (dMgr *Manager) UpdateDeviceAttribute(ctx context.Context, deviceID string, attribute string, value interface{}) {
npujar1d86a522019-11-14 17:11:16 +05301506 if agent, ok := dMgr.deviceAgents.Load(deviceID); ok {
Kent Hagerman2b216042020-04-03 18:28:56 -04001507 agent.(*Agent).updateDeviceAttribute(ctx, attribute, value)
khenaidoob9203542018-09-17 22:56:37 -04001508 }
1509}
1510
npujar1d86a522019-11-14 17:11:16 +05301511// GetParentDeviceID returns parent device id, either from memory or from the dB, if present
Kent Hagerman2b216042020-04-03 18:28:56 -04001512func (dMgr *Manager) GetParentDeviceID(ctx context.Context, deviceID string) string {
Kent Hagermancba2f302020-07-28 13:37:36 -04001513 if device, _ := dMgr.getDeviceReadOnly(ctx, deviceID); device != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +05301514 logger.Infow(ctx, "get-parent-device-id", log.Fields{"device-id": device.Id, "parent-id": device.ParentId})
khenaidoo4c9e5592019-09-09 16:20:41 -04001515 return device.ParentId
khenaidoob9203542018-09-17 22:56:37 -04001516 }
khenaidoo4c9e5592019-09-09 16:20:41 -04001517 return ""
khenaidoob9203542018-09-17 22:56:37 -04001518}
serkant.uluderya334479d2019-04-10 08:26:15 -07001519
Kent Hagerman45a13e42020-04-13 12:23:50 -04001520func (dMgr *Manager) SimulateAlarm(ctx context.Context, simulateReq *voltha.SimulateAlarmRequest) (*common.OperationResp, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301521 ctx = utils.WithRPCMetadataContext(ctx, "SimulateAlarm")
1522 logger.Debugw(ctx, "simulate-alarm", log.Fields{"id": simulateReq.Id, "indicator": simulateReq.Indicator, "intf-id": simulateReq.IntfId,
1523 "port-type-name": simulateReq.PortTypeName, "onu-device-id": simulateReq.OnuDeviceId, "inverse-bit-error-rate": simulateReq.InverseBitErrorRate,
1524 "drift": simulateReq.Drift, "new-eqd": simulateReq.NewEqd, "onu-serial-number": simulateReq.OnuSerialNumber, "operation": simulateReq.Operation})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001525 agent := dMgr.getDeviceAgent(ctx, simulateReq.Id)
1526 if agent == nil {
1527 return nil, status.Errorf(codes.NotFound, "%s", simulateReq.Id)
serkant.uluderya334479d2019-04-10 08:26:15 -07001528 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001529 if err := agent.simulateAlarm(ctx, simulateReq); err != nil {
1530 return nil, err
1531 }
1532 return &common.OperationResp{Code: common.OperationResp_OPERATION_SUCCESS}, nil
serkant.uluderya334479d2019-04-10 08:26:15 -07001533}
Mahir Gunyelfdee9212019-10-16 16:52:21 -07001534
Kent Hagerman2b216042020-04-03 18:28:56 -04001535func (dMgr *Manager) UpdateDeviceReason(ctx context.Context, deviceID string, reason string) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301536 logger.Debugw(ctx, "update-device-reason", log.Fields{"device-id": deviceID, "reason": reason})
npujar467fe752020-01-16 20:17:45 +05301537 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
1538 return agent.updateDeviceReason(ctx, reason)
Mahir Gunyelfdee9212019-10-16 16:52:21 -07001539 }
npujar1d86a522019-11-14 17:11:16 +05301540 return status.Errorf(codes.NotFound, "%s", deviceID)
Mahir Gunyelfdee9212019-10-16 16:52:21 -07001541}
kesavandbc2d1622020-01-21 00:42:01 -05001542
Kent Hagerman45a13e42020-04-13 12:23:50 -04001543func (dMgr *Manager) EnablePort(ctx context.Context, port *voltha.Port) (*empty.Empty, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301544 ctx = utils.WithRPCMetadataContext(ctx, "EnablePort")
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001545 log.EnrichSpan(ctx, log.Fields{"device-id": port.DeviceId})
Himani Chawlab4c25912020-11-12 17:16:38 +05301546 logger.Debugw(ctx, "enable-port", log.Fields{"device-id": port.DeviceId, "port-no": port.PortNo})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001547 agent := dMgr.getDeviceAgent(ctx, port.DeviceId)
1548 if agent == nil {
1549 return nil, status.Errorf(codes.NotFound, "%s", port.DeviceId)
kesavandbc2d1622020-01-21 00:42:01 -05001550 }
Kent Hagerman2a07b862020-06-19 15:23:07 -04001551 return &empty.Empty{}, agent.enablePort(ctx, port.PortNo)
kesavandbc2d1622020-01-21 00:42:01 -05001552}
1553
Kent Hagerman45a13e42020-04-13 12:23:50 -04001554func (dMgr *Manager) DisablePort(ctx context.Context, port *voltha.Port) (*empty.Empty, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301555 ctx = utils.WithRPCMetadataContext(ctx, "DisablePort")
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001556 log.EnrichSpan(ctx, log.Fields{"device-id": port.DeviceId})
Himani Chawlab4c25912020-11-12 17:16:38 +05301557 logger.Debugw(ctx, "disable-port", log.Fields{"device-id": port.DeviceId, "port-no": port.PortNo})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001558 agent := dMgr.getDeviceAgent(ctx, port.DeviceId)
1559 if agent == nil {
1560 return nil, status.Errorf(codes.NotFound, "%s", port.DeviceId)
kesavandbc2d1622020-01-21 00:42:01 -05001561 }
Kent Hagerman2a07b862020-06-19 15:23:07 -04001562 return &empty.Empty{}, agent.disablePort(ctx, port.PortNo)
kesavandbc2d1622020-01-21 00:42:01 -05001563}
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001564
Kent Hagerman2b216042020-04-03 18:28:56 -04001565// ChildDeviceLost calls parent adapter to delete child device and all its references
1566func (dMgr *Manager) ChildDeviceLost(ctx context.Context, curr *voltha.Device) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301567 logger.Debugw(ctx, "child-device-lost", log.Fields{"child-device-id": curr.Id, "parent-device-id": curr.ParentId})
khenaidoo442e7c72020-03-10 16:13:48 -04001568 if parentAgent := dMgr.getDeviceAgent(ctx, curr.ParentId); parentAgent != nil {
khenaidooe132f522020-03-20 15:23:15 -04001569 if err := parentAgent.ChildDeviceLost(ctx, curr); err != nil {
1570 // Just log the message and let the remaining pipeline proceed.
Rohan Agrawal31f21802020-06-12 05:38:46 +00001571 logger.Warnw(ctx, "childDeviceLost", log.Fields{"child-device-id": curr.Id, "parent-device-id": curr.ParentId, "error": err})
khenaidooe132f522020-03-20 15:23:15 -04001572 }
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001573 }
khenaidooe132f522020-03-20 15:23:15 -04001574 // Do not return an error as parent device may also have been deleted. Let the remaining pipeline proceed.
1575 return nil
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001576}
onkarkundargi87285252020-01-27 11:34:52 +05301577
Kent Hagerman45a13e42020-04-13 12:23:50 -04001578func (dMgr *Manager) StartOmciTestAction(ctx context.Context, request *voltha.OmciTestRequest) (*voltha.TestResponse, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301579 ctx = utils.WithRPCMetadataContext(ctx, "StartOmciTestAction")
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001580 log.EnrichSpan(ctx, log.Fields{"device-id": request.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +05301581 logger.Debugw(ctx, "start-omci-test-action", log.Fields{"device-id": request.Id, "uuid": request.Uuid})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001582 agent := dMgr.getDeviceAgent(ctx, request.Id)
1583 if agent == nil {
1584 return nil, status.Errorf(codes.NotFound, "%s", request.Id)
onkarkundargi87285252020-01-27 11:34:52 +05301585 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001586 return agent.startOmciTest(ctx, request)
onkarkundargi87285252020-01-27 11:34:52 +05301587}
Dinesh Belwalkarc1129f12020-02-27 10:41:33 -08001588
1589func (dMgr *Manager) GetExtValue(ctx context.Context, value *voltha.ValueSpecifier) (*voltha.ReturnValues, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301590 ctx = utils.WithRPCMetadataContext(ctx, "GetExtValue")
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001591 log.EnrichSpan(ctx, log.Fields{"device-id": value.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +05301592 logger.Debugw(ctx, "get-ext-value", log.Fields{"onu-id": value.Id})
Kent Hagermancba2f302020-07-28 13:37:36 -04001593 cDevice, err := dMgr.getDeviceReadOnly(ctx, value.Id)
Dinesh Belwalkarc1129f12020-02-27 10:41:33 -08001594 if err != nil {
1595 return nil, status.Errorf(codes.Aborted, "%s", err.Error())
1596 }
Kent Hagermancba2f302020-07-28 13:37:36 -04001597 pDevice, err := dMgr.getDeviceReadOnly(ctx, cDevice.ParentId)
Dinesh Belwalkarc1129f12020-02-27 10:41:33 -08001598 if err != nil {
1599 return nil, status.Errorf(codes.Aborted, "%s", err.Error())
1600 }
1601 if agent := dMgr.getDeviceAgent(ctx, cDevice.ParentId); agent != nil {
1602 resp, err := agent.getExtValue(ctx, pDevice, cDevice, value)
1603 if err != nil {
1604 return nil, err
1605 }
Himani Chawlab4c25912020-11-12 17:16:38 +05301606 logger.Debugw(ctx, "get-ext-value-result", log.Fields{"result": resp})
Dinesh Belwalkarc1129f12020-02-27 10:41:33 -08001607 return resp, nil
1608 }
1609 return nil, status.Errorf(codes.NotFound, "%s", value.Id)
1610
1611}
dpaul62686312020-06-23 14:17:36 +05301612
1613// SetExtValue set some given configs or value
1614func (dMgr *Manager) SetExtValue(ctx context.Context, value *voltha.ValueSet) (*empty.Empty, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301615 ctx = utils.WithRPCMetadataContext(ctx, "SetExtValue")
1616 logger.Debugw(ctx, "set-ext-value", log.Fields{"onu-id": value.Id})
dpaul62686312020-06-23 14:17:36 +05301617 device, err := dMgr.getDeviceReadOnly(ctx, value.Id)
1618 if err != nil {
1619 return nil, status.Errorf(codes.Aborted, "%s", err.Error())
1620 }
1621 if agent := dMgr.getDeviceAgent(ctx, device.Id); agent != nil {
1622 resp, err := agent.setExtValue(ctx, device, value)
1623 if err != nil {
1624 return nil, err
1625 }
Himani Chawlab4c25912020-11-12 17:16:38 +05301626 logger.Debugw(ctx, "set-ext-value-result", log.Fields{"result": resp})
dpaul62686312020-06-23 14:17:36 +05301627 return resp, nil
1628 }
1629 return nil, status.Errorf(codes.NotFound, "%s", value.Id)
1630
1631}
Himani Chawlab4c25912020-11-12 17:16:38 +05301632
1633func (dMgr *Manager) SendRPCEvent(ctx context.Context, id string, rpcEvent *voltha.RPCEvent,
1634 category voltha.EventCategory_Types, subCategory *voltha.EventSubCategory_Types, raisedTs int64) {
1635 //TODO Instead of directly sending to the kafka bus, queue the message and send it asynchronously
Mahir Gunyelb0343bf2021-05-11 14:14:26 -07001636 dMgr.Agent.SendRPCEvent(ctx, id, rpcEvent, category, subCategory, raisedTs)
Himani Chawlab4c25912020-11-12 17:16:38 +05301637}
Manindera496f852021-02-22 09:57:56 +05301638
1639func (dMgr *Manager) GetTransientState(ctx context.Context, id string) (voltha.DeviceTransientState_Types, error) {
1640 agent := dMgr.getDeviceAgent(ctx, id)
1641 if agent == nil {
1642 return voltha.DeviceTransientState_NONE, status.Errorf(codes.NotFound, "%s", id)
1643 }
1644 return agent.getTransientState(), nil
1645}
ssiddiquif076cb82021-04-23 10:47:04 +05301646
1647func (dMgr *Manager) DownloadImageToDevice(ctx context.Context, request *voltha.DeviceImageDownloadRequest) (*voltha.DeviceImageResponse, error) {
1648 if err := dMgr.validateImageDownloadRequest(request); err != nil {
1649 return nil, err
1650 }
1651
1652 ctx = utils.WithRPCMetadataContext(ctx, "DownloadImageToDevice")
1653 respCh := make(chan []*voltha.DeviceImageState, len(request.GetDeviceId()))
1654
ssiddiquif076cb82021-04-23 10:47:04 +05301655 for index, deviceID := range request.DeviceId {
ssiddiqui6bd4de02021-06-08 12:04:17 +05301656 // Create download request per device
1657 downloadReq := &voltha.DeviceImageDownloadRequest{
1658 Image: request.Image,
1659 ActivateOnSuccess: request.ActivateOnSuccess,
1660 CommitOnSuccess: request.CommitOnSuccess,
1661 }
1662
ssiddiquif076cb82021-04-23 10:47:04 +05301663 //slice-out only single deviceID from the request
1664 downloadReq.DeviceId = request.DeviceId[index : index+1]
1665
1666 go func(deviceID string, req *voltha.DeviceImageDownloadRequest, ch chan []*voltha.DeviceImageState) {
1667 agent := dMgr.getDeviceAgent(ctx, deviceID)
1668 if agent == nil {
ssiddiquib2f526c2021-10-11 17:11:25 +05301669 logger.Errorw(ctx, "Device-agent-not-found", log.Fields{"device-id": deviceID})
1670 ch <- []*voltha.DeviceImageState{{
1671 DeviceId: deviceID,
1672 ImageState: &voltha.ImageState{
1673 Version: req.GetImage().GetVersion(),
1674 DownloadState: voltha.ImageState_DOWNLOAD_FAILED,
1675 Reason: voltha.ImageState_UNKNOWN_ERROR,
1676 ImageState: voltha.ImageState_IMAGE_UNKNOWN,
1677 },
1678 }}
ssiddiquif076cb82021-04-23 10:47:04 +05301679 return
1680 }
1681
1682 resp, err := agent.downloadImageToDevice(ctx, req)
1683 if err != nil {
1684 logger.Errorw(ctx, "download-image-to-device-failed", log.Fields{"device-id": deviceID, "error": err})
ssiddiquib2f526c2021-10-11 17:11:25 +05301685 ch <- []*voltha.DeviceImageState{{
1686 DeviceId: deviceID,
1687 ImageState: &voltha.ImageState{
1688 Version: req.GetImage().GetVersion(),
1689 DownloadState: voltha.ImageState_DOWNLOAD_FAILED,
1690 Reason: voltha.ImageState_UNKNOWN_ERROR,
1691 ImageState: voltha.ImageState_IMAGE_UNKNOWN,
1692 },
1693 }}
ssiddiquif076cb82021-04-23 10:47:04 +05301694 return
1695 }
1696
1697 err = dMgr.validateDeviceImageResponse(resp)
1698 if err != nil {
1699 logger.Errorw(ctx, "download-image-to-device-failed", log.Fields{"device-id": deviceID, "error": err})
ssiddiquib2f526c2021-10-11 17:11:25 +05301700 ch <- []*voltha.DeviceImageState{{
1701 DeviceId: deviceID,
1702 ImageState: &voltha.ImageState{
1703 Version: req.GetImage().GetVersion(),
1704 DownloadState: voltha.ImageState_DOWNLOAD_FAILED,
1705 Reason: voltha.ImageState_UNKNOWN_ERROR,
1706 ImageState: voltha.ImageState_IMAGE_UNKNOWN,
1707 },
1708 }}
ssiddiquif076cb82021-04-23 10:47:04 +05301709 return
1710 }
1711 ch <- resp.GetDeviceImageStates()
1712 }(deviceID.GetId(), downloadReq, respCh)
1713
1714 }
1715
1716 return dMgr.waitForAllResponses(ctx, "download-image-to-device", respCh, len(request.GetDeviceId()))
1717}
1718
1719func (dMgr *Manager) GetImageStatus(ctx context.Context, request *voltha.DeviceImageRequest) (*voltha.DeviceImageResponse, error) {
1720 if err := dMgr.validateImageRequest(request); err != nil {
1721 return nil, err
1722 }
1723
1724 ctx = utils.WithRPCMetadataContext(ctx, "GetImageStatus")
1725
ssiddiquif076cb82021-04-23 10:47:04 +05301726 respCh := make(chan []*voltha.DeviceImageState, len(request.GetDeviceId()))
1727 for index, deviceID := range request.DeviceId {
ssiddiqui6bd4de02021-06-08 12:04:17 +05301728 // Create status request per device
1729 imageStatusReq := &voltha.DeviceImageRequest{
1730 Version: request.Version,
1731 CommitOnSuccess: request.CommitOnSuccess,
1732 }
1733
ssiddiquif076cb82021-04-23 10:47:04 +05301734 //slice-out only single deviceID from the request
1735 imageStatusReq.DeviceId = request.DeviceId[index : index+1]
1736
1737 go func(deviceID string, req *voltha.DeviceImageRequest, ch chan []*voltha.DeviceImageState) {
1738 agent := dMgr.getDeviceAgent(ctx, deviceID)
1739 if agent == nil {
ssiddiquib2f526c2021-10-11 17:11:25 +05301740 logger.Errorw(ctx, "Device-agent-not-found", log.Fields{"device-id": deviceID})
1741 ch <- []*voltha.DeviceImageState{{
1742 DeviceId: deviceID,
1743 ImageState: &voltha.ImageState{
1744 Version: request.GetVersion(),
1745 DownloadState: voltha.ImageState_DOWNLOAD_UNKNOWN,
1746 Reason: voltha.ImageState_UNKNOWN_ERROR,
1747 ImageState: voltha.ImageState_IMAGE_UNKNOWN,
1748 },
1749 }}
ssiddiquif076cb82021-04-23 10:47:04 +05301750 return
1751 }
1752
1753 resp, err := agent.getImageStatus(ctx, req)
1754 if err != nil {
1755 logger.Errorw(ctx, "get-image-status-failed", log.Fields{"device-id": deviceID, "error": err})
ssiddiquib2f526c2021-10-11 17:11:25 +05301756 ch <- []*voltha.DeviceImageState{{
1757 DeviceId: deviceID,
1758 ImageState: &voltha.ImageState{
1759 Version: request.GetVersion(),
1760 DownloadState: voltha.ImageState_DOWNLOAD_UNKNOWN,
1761 Reason: voltha.ImageState_UNKNOWN_ERROR,
1762 ImageState: voltha.ImageState_IMAGE_UNKNOWN,
1763 },
1764 }}
ssiddiquif076cb82021-04-23 10:47:04 +05301765 return
1766 }
1767
1768 err = dMgr.validateDeviceImageResponse(resp)
1769 if err != nil {
1770 logger.Errorw(ctx, "get-image-status-failed", log.Fields{"device-id": deviceID, "error": err})
ssiddiquib2f526c2021-10-11 17:11:25 +05301771 ch <- []*voltha.DeviceImageState{{
1772 DeviceId: deviceID,
1773 ImageState: &voltha.ImageState{
1774 Version: request.GetVersion(),
1775 DownloadState: voltha.ImageState_DOWNLOAD_UNKNOWN,
1776 Reason: voltha.ImageState_UNKNOWN_ERROR,
1777 ImageState: voltha.ImageState_IMAGE_UNKNOWN,
1778 },
1779 }}
ssiddiquif076cb82021-04-23 10:47:04 +05301780 return
1781 }
1782 ch <- resp.GetDeviceImageStates()
1783 }(deviceID.GetId(), imageStatusReq, respCh)
1784
1785 }
1786
1787 return dMgr.waitForAllResponses(ctx, "get-image-status", respCh, len(request.GetDeviceId()))
1788}
1789
1790func (dMgr *Manager) AbortImageUpgradeToDevice(ctx context.Context, request *voltha.DeviceImageRequest) (*voltha.DeviceImageResponse, error) {
1791 if err := dMgr.validateImageRequest(request); err != nil {
1792 return nil, err
1793 }
1794
1795 ctx = utils.WithRPCMetadataContext(ctx, "AbortImageUpgradeToDevice")
1796 respCh := make(chan []*voltha.DeviceImageState, len(request.GetDeviceId()))
1797
ssiddiquif076cb82021-04-23 10:47:04 +05301798 for index, deviceID := range request.DeviceId {
ssiddiqui6bd4de02021-06-08 12:04:17 +05301799 // Create abort request per device
1800 abortImageReq := &voltha.DeviceImageRequest{
1801 Version: request.Version,
1802 CommitOnSuccess: request.CommitOnSuccess,
1803 }
1804
ssiddiquif076cb82021-04-23 10:47:04 +05301805 //slice-out only single deviceID from the request
1806 abortImageReq.DeviceId = request.DeviceId[index : index+1]
1807
1808 go func(deviceID string, req *voltha.DeviceImageRequest, ch chan []*voltha.DeviceImageState) {
1809 agent := dMgr.getDeviceAgent(ctx, deviceID)
1810 if agent == nil {
ssiddiquib2f526c2021-10-11 17:11:25 +05301811 logger.Errorw(ctx, "Device-agent-not-found", log.Fields{"device-id": deviceID})
1812 ch <- []*voltha.DeviceImageState{{
1813 DeviceId: deviceID,
1814 ImageState: &voltha.ImageState{
1815 Version: request.GetVersion(),
1816 DownloadState: voltha.ImageState_DOWNLOAD_UNKNOWN,
1817 Reason: voltha.ImageState_UNKNOWN_ERROR,
1818 ImageState: voltha.ImageState_IMAGE_UNKNOWN,
1819 },
1820 }}
ssiddiquif076cb82021-04-23 10:47:04 +05301821 return
1822 }
1823
1824 resp, err := agent.abortImageUpgradeToDevice(ctx, req)
1825 if err != nil {
1826 logger.Errorw(ctx, "abort-image-upgrade-to-device-failed", log.Fields{"device-id": deviceID, "error": err})
ssiddiquib2f526c2021-10-11 17:11:25 +05301827 ch <- []*voltha.DeviceImageState{{
1828 DeviceId: deviceID,
1829 ImageState: &voltha.ImageState{
1830 Version: request.GetVersion(),
1831 DownloadState: voltha.ImageState_DOWNLOAD_UNKNOWN,
1832 Reason: voltha.ImageState_UNKNOWN_ERROR,
1833 ImageState: voltha.ImageState_IMAGE_UNKNOWN,
1834 },
1835 }}
ssiddiquif076cb82021-04-23 10:47:04 +05301836 return
1837 }
1838
1839 err = dMgr.validateDeviceImageResponse(resp)
1840 if err != nil {
1841 logger.Errorw(ctx, "abort-image-upgrade-to-device-failed", log.Fields{"device-id": deviceID, "error": err})
ssiddiquib2f526c2021-10-11 17:11:25 +05301842 ch <- []*voltha.DeviceImageState{{
1843 DeviceId: deviceID,
1844 ImageState: &voltha.ImageState{
1845 Version: request.GetVersion(),
1846 DownloadState: voltha.ImageState_DOWNLOAD_UNKNOWN,
1847 Reason: voltha.ImageState_UNKNOWN_ERROR,
1848 ImageState: voltha.ImageState_IMAGE_UNKNOWN,
1849 },
1850 }}
ssiddiquif076cb82021-04-23 10:47:04 +05301851 return
1852 }
1853 ch <- resp.GetDeviceImageStates()
1854 }(deviceID.GetId(), abortImageReq, respCh)
1855
1856 }
1857
1858 return dMgr.waitForAllResponses(ctx, "abort-image-upgrade-to-device", respCh, len(request.GetDeviceId()))
1859}
1860
1861func (dMgr *Manager) GetOnuImages(ctx context.Context, id *common.ID) (*voltha.OnuImages, error) {
1862 if id == nil || id.Id == "" {
1863 return nil, status.Errorf(codes.InvalidArgument, "empty device id")
1864 }
1865
1866 ctx = utils.WithRPCMetadataContext(ctx, "GetOnuImages")
1867 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
1868 agent := dMgr.getDeviceAgent(ctx, id.Id)
1869 if agent == nil {
1870 return nil, status.Errorf(codes.NotFound, "%s", id.Id)
1871 }
1872
1873 resp, err := agent.getOnuImages(ctx, id)
1874 if err != nil {
1875 return nil, err
1876 }
1877
1878 logger.Debugw(ctx, "get-onu-images-result", log.Fields{"onu-image": resp.Items})
1879
1880 return resp, nil
1881}
1882
1883func (dMgr *Manager) ActivateImage(ctx context.Context, request *voltha.DeviceImageRequest) (*voltha.DeviceImageResponse, error) {
1884 if err := dMgr.validateImageRequest(request); err != nil {
1885 return nil, err
1886 }
1887
1888 ctx = utils.WithRPCMetadataContext(ctx, "ActivateImage")
1889 respCh := make(chan []*voltha.DeviceImageState, len(request.GetDeviceId()))
1890
ssiddiquif076cb82021-04-23 10:47:04 +05301891 for index, deviceID := range request.DeviceId {
ssiddiqui6bd4de02021-06-08 12:04:17 +05301892 // Create activate request per device
1893 activateImageReq := &voltha.DeviceImageRequest{
1894 Version: request.Version,
1895 CommitOnSuccess: request.CommitOnSuccess,
1896 }
1897
ssiddiquif076cb82021-04-23 10:47:04 +05301898 //slice-out only single deviceID from the request
1899 activateImageReq.DeviceId = request.DeviceId[index : index+1]
1900
1901 go func(deviceID string, req *voltha.DeviceImageRequest, ch chan []*voltha.DeviceImageState) {
1902 agent := dMgr.getDeviceAgent(ctx, deviceID)
1903 if agent == nil {
ssiddiquib2f526c2021-10-11 17:11:25 +05301904 logger.Errorw(ctx, "Device-agent-not-found", log.Fields{"device-id": deviceID})
1905 ch <- []*voltha.DeviceImageState{{
1906 DeviceId: deviceID,
1907 ImageState: &voltha.ImageState{
1908 Version: request.GetVersion(),
1909 DownloadState: voltha.ImageState_DOWNLOAD_UNKNOWN,
1910 Reason: voltha.ImageState_UNKNOWN_ERROR,
1911 ImageState: voltha.ImageState_IMAGE_ACTIVATION_ABORTED,
1912 },
1913 }}
ssiddiquif076cb82021-04-23 10:47:04 +05301914 return
1915 }
1916
1917 resp, err := agent.activateImageOnDevice(ctx, req)
1918 if err != nil {
1919 logger.Errorw(ctx, "activate-image-failed", log.Fields{"device-id": deviceID, "error": err})
ssiddiquib2f526c2021-10-11 17:11:25 +05301920 ch <- []*voltha.DeviceImageState{{
1921 DeviceId: deviceID,
1922 ImageState: &voltha.ImageState{
1923 Version: request.GetVersion(),
1924 DownloadState: voltha.ImageState_DOWNLOAD_UNKNOWN,
1925 Reason: voltha.ImageState_UNKNOWN_ERROR,
1926 ImageState: voltha.ImageState_IMAGE_ACTIVATION_ABORTED,
1927 },
1928 }}
ssiddiquif076cb82021-04-23 10:47:04 +05301929 return
1930 }
1931
1932 err = dMgr.validateDeviceImageResponse(resp)
1933 if err != nil {
1934 logger.Errorw(ctx, "activate-image-failed", log.Fields{"device-id": deviceID, "error": err})
ssiddiquib2f526c2021-10-11 17:11:25 +05301935 ch <- []*voltha.DeviceImageState{{
1936 DeviceId: deviceID,
1937 ImageState: &voltha.ImageState{
1938 Version: request.GetVersion(),
1939 DownloadState: voltha.ImageState_DOWNLOAD_UNKNOWN,
1940 Reason: voltha.ImageState_UNKNOWN_ERROR,
1941 ImageState: voltha.ImageState_IMAGE_UNKNOWN,
1942 },
1943 }}
ssiddiquif076cb82021-04-23 10:47:04 +05301944 return
1945 }
1946
1947 ch <- resp.GetDeviceImageStates()
1948 }(deviceID.GetId(), activateImageReq, respCh)
1949
1950 }
1951
1952 return dMgr.waitForAllResponses(ctx, "activate-image", respCh, len(request.GetDeviceId()))
1953}
1954
1955func (dMgr *Manager) CommitImage(ctx context.Context, request *voltha.DeviceImageRequest) (*voltha.DeviceImageResponse, error) {
1956 if err := dMgr.validateImageRequest(request); err != nil {
1957 return nil, err
1958 }
1959
1960 ctx = utils.WithRPCMetadataContext(ctx, "CommitImage")
1961 respCh := make(chan []*voltha.DeviceImageState, len(request.GetDeviceId()))
1962
ssiddiquif076cb82021-04-23 10:47:04 +05301963 for index, deviceID := range request.DeviceId {
ssiddiqui6bd4de02021-06-08 12:04:17 +05301964 // Create commit request per device
1965 commitImageReq := &voltha.DeviceImageRequest{
1966 Version: request.Version,
1967 CommitOnSuccess: request.CommitOnSuccess,
1968 }
ssiddiquif076cb82021-04-23 10:47:04 +05301969 //slice-out only single deviceID from the request
1970 commitImageReq.DeviceId = request.DeviceId[index : index+1]
1971
1972 go func(deviceID string, req *voltha.DeviceImageRequest, ch chan []*voltha.DeviceImageState) {
1973 agent := dMgr.getDeviceAgent(ctx, deviceID)
1974 if agent == nil {
ssiddiquib2f526c2021-10-11 17:11:25 +05301975 logger.Errorw(ctx, "Device-agent-not-found", log.Fields{"device-id": deviceID})
1976 ch <- []*voltha.DeviceImageState{{
1977 DeviceId: deviceID,
1978 ImageState: &voltha.ImageState{
1979 Version: request.GetVersion(),
1980 DownloadState: voltha.ImageState_DOWNLOAD_UNKNOWN,
1981 Reason: voltha.ImageState_UNKNOWN_ERROR,
1982 ImageState: voltha.ImageState_IMAGE_COMMIT_ABORTED,
1983 },
1984 }}
ssiddiquif076cb82021-04-23 10:47:04 +05301985 return
1986 }
1987
1988 resp, err := agent.commitImage(ctx, req)
1989 if err != nil {
1990 logger.Errorw(ctx, "commit-image-failed", log.Fields{"device-id": deviceID, "error": err})
ssiddiquib2f526c2021-10-11 17:11:25 +05301991 ch <- []*voltha.DeviceImageState{{
1992 DeviceId: deviceID,
1993 ImageState: &voltha.ImageState{
1994 Version: request.GetVersion(),
1995 DownloadState: voltha.ImageState_DOWNLOAD_UNKNOWN,
1996 Reason: voltha.ImageState_UNKNOWN_ERROR,
1997 ImageState: voltha.ImageState_IMAGE_COMMIT_ABORTED,
1998 },
1999 }}
ssiddiquif076cb82021-04-23 10:47:04 +05302000 return
2001 }
2002
2003 err = dMgr.validateDeviceImageResponse(resp)
2004 if err != nil {
2005 logger.Errorf(ctx, "commit-image-failed", log.Fields{"device-id": deviceID, "error": err})
ssiddiquib2f526c2021-10-11 17:11:25 +05302006 ch <- []*voltha.DeviceImageState{{
2007 DeviceId: deviceID,
2008 ImageState: &voltha.ImageState{
2009 Version: request.GetVersion(),
2010 DownloadState: voltha.ImageState_DOWNLOAD_UNKNOWN,
2011 Reason: voltha.ImageState_UNKNOWN_ERROR,
2012 ImageState: voltha.ImageState_IMAGE_UNKNOWN,
2013 },
2014 }}
ssiddiquif076cb82021-04-23 10:47:04 +05302015 return
2016 }
2017 ch <- resp.GetDeviceImageStates()
2018 }(deviceID.GetId(), commitImageReq, respCh)
2019
2020 }
2021
2022 return dMgr.waitForAllResponses(ctx, "commit-image", respCh, len(request.GetDeviceId()))
2023}
2024
2025func (dMgr *Manager) validateImageDownloadRequest(request *voltha.DeviceImageDownloadRequest) error {
2026 if request == nil || request.Image == nil || len(request.DeviceId) == 0 {
2027 return status.Errorf(codes.InvalidArgument, "invalid argument")
2028 }
2029
2030 for _, deviceID := range request.DeviceId {
2031 if deviceID == nil {
2032 return status.Errorf(codes.InvalidArgument, "id is nil")
2033 }
2034 }
2035 return nil
2036}
2037
2038func (dMgr *Manager) validateImageRequest(request *voltha.DeviceImageRequest) error {
2039 if request == nil || len(request.DeviceId) == 0 || request.DeviceId[0] == nil {
2040 return status.Errorf(codes.InvalidArgument, "invalid argument")
2041 }
2042
2043 for _, deviceID := range request.DeviceId {
2044 if deviceID == nil {
2045 return status.Errorf(codes.InvalidArgument, "id is nil")
2046 }
2047 }
2048
2049 return nil
2050}
2051
2052func (dMgr *Manager) validateDeviceImageResponse(response *voltha.DeviceImageResponse) error {
2053 if response == nil || len(response.GetDeviceImageStates()) == 0 || response.GetDeviceImageStates()[0] == nil {
2054 return status.Errorf(codes.Internal, "invalid-response-from-adapter")
2055 }
2056
2057 return nil
2058}
2059
2060func (dMgr *Manager) waitForAllResponses(ctx context.Context, opName string, respCh chan []*voltha.DeviceImageState, expectedResps int) (*voltha.DeviceImageResponse, error) {
2061 response := &voltha.DeviceImageResponse{}
2062 respCount := 0
2063 for {
2064 select {
2065 case resp, ok := <-respCh:
2066 if !ok {
2067 logger.Errorw(ctx, opName+"-failed", log.Fields{"error": "channel-closed"})
2068 return response, status.Errorf(codes.Aborted, "channel-closed")
2069 }
2070
2071 if resp != nil {
2072 logger.Debugw(ctx, opName+"-result", log.Fields{"image-state": resp[0].GetImageState(), "device-id": resp[0].GetDeviceId()})
2073 response.DeviceImageStates = append(response.DeviceImageStates, resp...)
2074 }
2075
2076 respCount++
2077
2078 //check whether all responses received, if so, sent back the collated response
2079 if respCount == expectedResps {
2080 return response, nil
2081 }
2082 continue
2083 case <-ctx.Done():
2084 return nil, status.Errorf(codes.Aborted, opName+"-failed-%s", ctx.Err())
2085 }
2086 }
2087}
Maninder0aabf0c2021-03-17 14:55:14 +05302088
2089func (dMgr *Manager) ReconcilingCleanup(ctx context.Context, device *voltha.Device) error {
2090 agent := dMgr.getDeviceAgent(ctx, device.Id)
2091 if agent == nil {
2092 logger.Errorf(ctx, "Not able to get device agent.")
2093 return status.Errorf(codes.NotFound, "Not able to get device agent for device : %s", device.Id)
2094 }
2095 err := agent.reconcilingCleanup(ctx)
2096 if err != nil {
2097 logger.Errorf(ctx, err.Error())
2098 return status.Errorf(codes.Internal, err.Error())
2099 }
2100 return nil
2101}