blob: 0b34bfb446bb0d09a0b33df279962569b214d6d2 [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 {
1669 logger.Errorw(ctx, "Not-found", log.Fields{"device-id": deviceID})
1670 ch <- nil
1671 return
1672 }
1673
1674 resp, err := agent.downloadImageToDevice(ctx, req)
1675 if err != nil {
1676 logger.Errorw(ctx, "download-image-to-device-failed", log.Fields{"device-id": deviceID, "error": err})
1677 ch <- nil
1678 return
1679 }
1680
1681 err = dMgr.validateDeviceImageResponse(resp)
1682 if err != nil {
1683 logger.Errorw(ctx, "download-image-to-device-failed", log.Fields{"device-id": deviceID, "error": err})
1684 ch <- nil
1685 return
1686 }
1687 ch <- resp.GetDeviceImageStates()
1688 }(deviceID.GetId(), downloadReq, respCh)
1689
1690 }
1691
1692 return dMgr.waitForAllResponses(ctx, "download-image-to-device", respCh, len(request.GetDeviceId()))
1693}
1694
1695func (dMgr *Manager) GetImageStatus(ctx context.Context, request *voltha.DeviceImageRequest) (*voltha.DeviceImageResponse, error) {
1696 if err := dMgr.validateImageRequest(request); err != nil {
1697 return nil, err
1698 }
1699
1700 ctx = utils.WithRPCMetadataContext(ctx, "GetImageStatus")
1701
ssiddiquif076cb82021-04-23 10:47:04 +05301702 respCh := make(chan []*voltha.DeviceImageState, len(request.GetDeviceId()))
1703 for index, deviceID := range request.DeviceId {
ssiddiqui6bd4de02021-06-08 12:04:17 +05301704 // Create status request per device
1705 imageStatusReq := &voltha.DeviceImageRequest{
1706 Version: request.Version,
1707 CommitOnSuccess: request.CommitOnSuccess,
1708 }
1709
ssiddiquif076cb82021-04-23 10:47:04 +05301710 //slice-out only single deviceID from the request
1711 imageStatusReq.DeviceId = request.DeviceId[index : index+1]
1712
1713 go func(deviceID string, req *voltha.DeviceImageRequest, ch chan []*voltha.DeviceImageState) {
1714 agent := dMgr.getDeviceAgent(ctx, deviceID)
1715 if agent == nil {
1716 logger.Errorw(ctx, "Not-found", log.Fields{"device-id": deviceID})
1717 ch <- nil
1718 return
1719 }
1720
1721 resp, err := agent.getImageStatus(ctx, req)
1722 if err != nil {
1723 logger.Errorw(ctx, "get-image-status-failed", log.Fields{"device-id": deviceID, "error": err})
1724 ch <- nil
1725 return
1726 }
1727
1728 err = dMgr.validateDeviceImageResponse(resp)
1729 if err != nil {
1730 logger.Errorw(ctx, "get-image-status-failed", log.Fields{"device-id": deviceID, "error": err})
1731 ch <- nil
1732 return
1733 }
1734 ch <- resp.GetDeviceImageStates()
1735 }(deviceID.GetId(), imageStatusReq, respCh)
1736
1737 }
1738
1739 return dMgr.waitForAllResponses(ctx, "get-image-status", respCh, len(request.GetDeviceId()))
1740}
1741
1742func (dMgr *Manager) AbortImageUpgradeToDevice(ctx context.Context, request *voltha.DeviceImageRequest) (*voltha.DeviceImageResponse, error) {
1743 if err := dMgr.validateImageRequest(request); err != nil {
1744 return nil, err
1745 }
1746
1747 ctx = utils.WithRPCMetadataContext(ctx, "AbortImageUpgradeToDevice")
1748 respCh := make(chan []*voltha.DeviceImageState, len(request.GetDeviceId()))
1749
ssiddiquif076cb82021-04-23 10:47:04 +05301750 for index, deviceID := range request.DeviceId {
ssiddiqui6bd4de02021-06-08 12:04:17 +05301751 // Create abort request per device
1752 abortImageReq := &voltha.DeviceImageRequest{
1753 Version: request.Version,
1754 CommitOnSuccess: request.CommitOnSuccess,
1755 }
1756
ssiddiquif076cb82021-04-23 10:47:04 +05301757 //slice-out only single deviceID from the request
1758 abortImageReq.DeviceId = request.DeviceId[index : index+1]
1759
1760 go func(deviceID string, req *voltha.DeviceImageRequest, ch chan []*voltha.DeviceImageState) {
1761 agent := dMgr.getDeviceAgent(ctx, deviceID)
1762 if agent == nil {
1763 logger.Errorw(ctx, "Not-found", log.Fields{"device-id": deviceID})
1764 ch <- nil
1765 return
1766 }
1767
1768 resp, err := agent.abortImageUpgradeToDevice(ctx, req)
1769 if err != nil {
1770 logger.Errorw(ctx, "abort-image-upgrade-to-device-failed", log.Fields{"device-id": deviceID, "error": err})
1771 ch <- nil
1772 return
1773 }
1774
1775 err = dMgr.validateDeviceImageResponse(resp)
1776 if err != nil {
1777 logger.Errorw(ctx, "abort-image-upgrade-to-device-failed", log.Fields{"device-id": deviceID, "error": err})
1778 ch <- nil
1779 return
1780 }
1781 ch <- resp.GetDeviceImageStates()
1782 }(deviceID.GetId(), abortImageReq, respCh)
1783
1784 }
1785
1786 return dMgr.waitForAllResponses(ctx, "abort-image-upgrade-to-device", respCh, len(request.GetDeviceId()))
1787}
1788
1789func (dMgr *Manager) GetOnuImages(ctx context.Context, id *common.ID) (*voltha.OnuImages, error) {
1790 if id == nil || id.Id == "" {
1791 return nil, status.Errorf(codes.InvalidArgument, "empty device id")
1792 }
1793
1794 ctx = utils.WithRPCMetadataContext(ctx, "GetOnuImages")
1795 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
1796 agent := dMgr.getDeviceAgent(ctx, id.Id)
1797 if agent == nil {
1798 return nil, status.Errorf(codes.NotFound, "%s", id.Id)
1799 }
1800
1801 resp, err := agent.getOnuImages(ctx, id)
1802 if err != nil {
1803 return nil, err
1804 }
1805
1806 logger.Debugw(ctx, "get-onu-images-result", log.Fields{"onu-image": resp.Items})
1807
1808 return resp, nil
1809}
1810
1811func (dMgr *Manager) ActivateImage(ctx context.Context, request *voltha.DeviceImageRequest) (*voltha.DeviceImageResponse, error) {
1812 if err := dMgr.validateImageRequest(request); err != nil {
1813 return nil, err
1814 }
1815
1816 ctx = utils.WithRPCMetadataContext(ctx, "ActivateImage")
1817 respCh := make(chan []*voltha.DeviceImageState, len(request.GetDeviceId()))
1818
ssiddiquif076cb82021-04-23 10:47:04 +05301819 for index, deviceID := range request.DeviceId {
ssiddiqui6bd4de02021-06-08 12:04:17 +05301820 // Create activate request per device
1821 activateImageReq := &voltha.DeviceImageRequest{
1822 Version: request.Version,
1823 CommitOnSuccess: request.CommitOnSuccess,
1824 }
1825
ssiddiquif076cb82021-04-23 10:47:04 +05301826 //slice-out only single deviceID from the request
1827 activateImageReq.DeviceId = request.DeviceId[index : index+1]
1828
1829 go func(deviceID string, req *voltha.DeviceImageRequest, ch chan []*voltha.DeviceImageState) {
1830 agent := dMgr.getDeviceAgent(ctx, deviceID)
1831 if agent == nil {
1832 logger.Errorw(ctx, "Not-found", log.Fields{"device-id": deviceID})
1833 ch <- nil
1834 return
1835 }
1836
1837 resp, err := agent.activateImageOnDevice(ctx, req)
1838 if err != nil {
1839 logger.Errorw(ctx, "activate-image-failed", log.Fields{"device-id": deviceID, "error": err})
1840 ch <- nil
1841 return
1842 }
1843
1844 err = dMgr.validateDeviceImageResponse(resp)
1845 if err != nil {
1846 logger.Errorw(ctx, "activate-image-failed", log.Fields{"device-id": deviceID, "error": err})
1847 ch <- nil
1848 return
1849 }
1850
1851 ch <- resp.GetDeviceImageStates()
1852 }(deviceID.GetId(), activateImageReq, respCh)
1853
1854 }
1855
1856 return dMgr.waitForAllResponses(ctx, "activate-image", respCh, len(request.GetDeviceId()))
1857}
1858
1859func (dMgr *Manager) CommitImage(ctx context.Context, request *voltha.DeviceImageRequest) (*voltha.DeviceImageResponse, error) {
1860 if err := dMgr.validateImageRequest(request); err != nil {
1861 return nil, err
1862 }
1863
1864 ctx = utils.WithRPCMetadataContext(ctx, "CommitImage")
1865 respCh := make(chan []*voltha.DeviceImageState, len(request.GetDeviceId()))
1866
ssiddiquif076cb82021-04-23 10:47:04 +05301867 for index, deviceID := range request.DeviceId {
ssiddiqui6bd4de02021-06-08 12:04:17 +05301868 // Create commit request per device
1869 commitImageReq := &voltha.DeviceImageRequest{
1870 Version: request.Version,
1871 CommitOnSuccess: request.CommitOnSuccess,
1872 }
ssiddiquif076cb82021-04-23 10:47:04 +05301873 //slice-out only single deviceID from the request
1874 commitImageReq.DeviceId = request.DeviceId[index : index+1]
1875
1876 go func(deviceID string, req *voltha.DeviceImageRequest, ch chan []*voltha.DeviceImageState) {
1877 agent := dMgr.getDeviceAgent(ctx, deviceID)
1878 if agent == nil {
1879 logger.Errorw(ctx, "Not-found", log.Fields{"device-id": deviceID})
1880 ch <- nil
1881 return
1882 }
1883
1884 resp, err := agent.commitImage(ctx, req)
1885 if err != nil {
1886 logger.Errorw(ctx, "commit-image-failed", log.Fields{"device-id": deviceID, "error": err})
1887 ch <- nil
1888 return
1889 }
1890
1891 err = dMgr.validateDeviceImageResponse(resp)
1892 if err != nil {
1893 logger.Errorf(ctx, "commit-image-failed", log.Fields{"device-id": deviceID, "error": err})
1894 ch <- nil
1895 return
1896 }
1897 ch <- resp.GetDeviceImageStates()
1898 }(deviceID.GetId(), commitImageReq, respCh)
1899
1900 }
1901
1902 return dMgr.waitForAllResponses(ctx, "commit-image", respCh, len(request.GetDeviceId()))
1903}
1904
1905func (dMgr *Manager) validateImageDownloadRequest(request *voltha.DeviceImageDownloadRequest) error {
1906 if request == nil || request.Image == nil || len(request.DeviceId) == 0 {
1907 return status.Errorf(codes.InvalidArgument, "invalid argument")
1908 }
1909
1910 for _, deviceID := range request.DeviceId {
1911 if deviceID == nil {
1912 return status.Errorf(codes.InvalidArgument, "id is nil")
1913 }
1914 }
1915 return nil
1916}
1917
1918func (dMgr *Manager) validateImageRequest(request *voltha.DeviceImageRequest) error {
1919 if request == nil || len(request.DeviceId) == 0 || request.DeviceId[0] == nil {
1920 return status.Errorf(codes.InvalidArgument, "invalid argument")
1921 }
1922
1923 for _, deviceID := range request.DeviceId {
1924 if deviceID == nil {
1925 return status.Errorf(codes.InvalidArgument, "id is nil")
1926 }
1927 }
1928
1929 return nil
1930}
1931
1932func (dMgr *Manager) validateDeviceImageResponse(response *voltha.DeviceImageResponse) error {
1933 if response == nil || len(response.GetDeviceImageStates()) == 0 || response.GetDeviceImageStates()[0] == nil {
1934 return status.Errorf(codes.Internal, "invalid-response-from-adapter")
1935 }
1936
1937 return nil
1938}
1939
1940func (dMgr *Manager) waitForAllResponses(ctx context.Context, opName string, respCh chan []*voltha.DeviceImageState, expectedResps int) (*voltha.DeviceImageResponse, error) {
1941 response := &voltha.DeviceImageResponse{}
1942 respCount := 0
1943 for {
1944 select {
1945 case resp, ok := <-respCh:
1946 if !ok {
1947 logger.Errorw(ctx, opName+"-failed", log.Fields{"error": "channel-closed"})
1948 return response, status.Errorf(codes.Aborted, "channel-closed")
1949 }
1950
1951 if resp != nil {
1952 logger.Debugw(ctx, opName+"-result", log.Fields{"image-state": resp[0].GetImageState(), "device-id"