blob: 869191e9cd0e1339223cd79e1b3643cb115d286a [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"
David Bainbridged1afd662020-03-26 18:27:41 -070022 "sync"
23 "time"
24
serkant.uluderyae25f6482020-12-17 21:08:38 +030025 "github.com/opencord/voltha-go/rw_core/config"
26 "github.com/opencord/voltha-lib-go/v5/pkg/probe"
27
Kent Hagerman45a13e42020-04-13 12:23:50 -040028 "github.com/golang/protobuf/ptypes/empty"
sbarbari17d7e222019-11-05 10:02:29 -050029 "github.com/opencord/voltha-go/db/model"
Kent Hagerman2b216042020-04-03 18:28:56 -040030 "github.com/opencord/voltha-go/rw_core/core/adapter"
Kent Hagermanf5a67352020-04-30 15:15:26 -040031 "github.com/opencord/voltha-go/rw_core/core/device/event"
Kent Hagerman2b216042020-04-03 18:28:56 -040032 "github.com/opencord/voltha-go/rw_core/core/device/remote"
Kent Hagerman6031aad2020-07-29 16:36:33 -040033 "github.com/opencord/voltha-go/rw_core/core/device/state"
khenaidoo3d3b8c22019-05-22 18:10:39 -040034 "github.com/opencord/voltha-go/rw_core/utils"
yasin sapli5458a1c2021-06-14 22:24:38 +000035 "github.com/opencord/voltha-lib-go/v5/pkg/events"
36 "github.com/opencord/voltha-lib-go/v5/pkg/kafka"
37 "github.com/opencord/voltha-lib-go/v5/pkg/log"
Maninderdfadc982020-10-28 14:04:33 +053038 "github.com/opencord/voltha-protos/v4/go/common"
39 ic "github.com/opencord/voltha-protos/v4/go/inter_container"
40 "github.com/opencord/voltha-protos/v4/go/openflow_13"
41 ofp "github.com/opencord/voltha-protos/v4/go/openflow_13"
42 "github.com/opencord/voltha-protos/v4/go/voltha"
khenaidoob9203542018-09-17 22:56:37 -040043 "google.golang.org/grpc/codes"
44 "google.golang.org/grpc/status"
khenaidoob9203542018-09-17 22:56:37 -040045)
46
Kent Hagerman2b216042020-04-03 18:28:56 -040047// Manager represent device manager attributes
48type Manager struct {
Himani Chawlab4c25912020-11-12 17:16:38 +053049 deviceAgents sync.Map
50 rootDevices map[string]bool
51 lockRootDeviceMap sync.RWMutex
52 adapterProxy *remote.AdapterProxy
Mahir Gunyelb0343bf2021-05-11 14:14:26 -070053 *event.Agent
Kent Hagerman2b216042020-04-03 18:28:56 -040054 adapterMgr *adapter.Manager
55 logicalDeviceMgr *LogicalManager
npujar467fe752020-01-16 20:17:45 +053056 kafkaICProxy kafka.InterContainerProxy
Kent Hagerman6031aad2020-07-29 16:36:33 -040057 stateTransitions *state.TransitionMap
Mahir Gunyel03de0d32020-06-03 01:36:59 -070058 dbPath *model.Path
Kent Hagermanf5a67352020-04-30 15:15:26 -040059 dProxy *model.Proxy
npujar1d86a522019-11-14 17:11:16 +053060 coreInstanceID string
khenaidoo442e7c72020-03-10 16:13:48 -040061 defaultTimeout time.Duration
khenaidoo4c9e5592019-09-09 16:20:41 -040062 devicesLoadingLock sync.RWMutex
63 deviceLoadingInProgress map[string][]chan int
Maninder0aabf0c2021-03-17 14:55:14 +053064 config *config.RWCoreFlags
khenaidoob9203542018-09-17 22:56:37 -040065}
66
Mahir Gunyel03de0d32020-06-03 01:36:59 -070067//NewManagers creates the Manager and the Logical Manager.
Maninder0aabf0c2021-03-17 14:55:14 +053068func 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 -040069 deviceMgr := &Manager{
Kent Hagerman2b216042020-04-03 18:28:56 -040070 rootDevices: make(map[string]bool),
71 kafkaICProxy: kmp,
Maninder0aabf0c2021-03-17 14:55:14 +053072 adapterProxy: remote.NewAdapterProxy(kmp, cf.CoreTopic, endpointMgr),
Kent Hagerman2b216042020-04-03 18:28:56 -040073 coreInstanceID: coreInstanceID,
Mahir Gunyel03de0d32020-06-03 01:36:59 -070074 dbPath: dbPath,
75 dProxy: dbPath.Proxy("devices"),
Kent Hagerman2b216042020-04-03 18:28:56 -040076 adapterMgr: adapterMgr,
Maninder0aabf0c2021-03-17 14:55:14 +053077 defaultTimeout: cf.DefaultCoreTimeout,
78 Agent: event.NewAgent(eventProxy, coreInstanceID, cf.VolthaStackID),
Kent Hagerman2b216042020-04-03 18:28:56 -040079 deviceLoadingInProgress: make(map[string][]chan int),
Maninder0aabf0c2021-03-17 14:55:14 +053080 config: cf,
Kent Hagerman2b216042020-04-03 18:28:56 -040081 }
Kent Hagerman6031aad2020-07-29 16:36:33 -040082 deviceMgr.stateTransitions = state.NewTransitionMap(deviceMgr)
Kent Hagerman2f0d0552020-04-23 17:28:52 -040083
Kent Hagerman2b216042020-04-03 18:28:56 -040084 logicalDeviceMgr := &LogicalManager{
Maninder0aabf0c2021-03-17 14:55:14 +053085 Manager: event.NewManager(eventProxy, coreInstanceID, cf.VolthaStackID),
Kent Hagerman2b216042020-04-03 18:28:56 -040086 deviceMgr: deviceMgr,
87 kafkaICProxy: kmp,
Mahir Gunyel03de0d32020-06-03 01:36:59 -070088 dbPath: dbPath,
89 ldProxy: dbPath.Proxy("logical_devices"),
Maninder0aabf0c2021-03-17 14:55:14 +053090 defaultTimeout: cf.DefaultCoreTimeout,
Kent Hagerman2b216042020-04-03 18:28:56 -040091 logicalDeviceLoadingInProgress: make(map[string][]chan int),
92 }
93 deviceMgr.logicalDeviceMgr = logicalDeviceMgr
Matteo Scandolod525ae32020-04-02 17:27:29 -070094
Kent Hagerman2b216042020-04-03 18:28:56 -040095 adapterMgr.SetAdapterRestartedCallback(deviceMgr.adapterRestarted)
Matteo Scandolod525ae32020-04-02 17:27:29 -070096
Kent Hagerman2b216042020-04-03 18:28:56 -040097 return deviceMgr, logicalDeviceMgr
khenaidoob9203542018-09-17 22:56:37 -040098}
99
khenaidoo7585a962021-06-10 16:15:38 -0400100func (dMgr *Manager) Start(ctx context.Context) {
101 logger.Info(ctx, "starting-device-manager")
102 probe.UpdateStatusFromContext(ctx, "device-manager", probe.ServiceStatusPreparing)
103
104 // Load all the devices from the dB
105 var devices []*voltha.Device
106 if err := dMgr.dProxy.List(ctx, &devices); err != nil {
107 // Any error from the dB means if we proceed we may end up with corrupted data
108 logger.Fatalw(ctx, "failed-to-list-devices-from-KV", log.Fields{"error": err})
109 }
110
111 for _, device := range devices {
112 // Create an agent for each device
113 agent := newAgent(dMgr.adapterProxy, device, dMgr, dMgr.dbPath, dMgr.dProxy, dMgr.defaultTimeout)
114 if _, err := agent.start(ctx, true, device); err != nil {
115 logger.Warnw(ctx, "failure-starting-agent", log.Fields{"device-id": device.Id})
116 } else {
117 dMgr.addDeviceAgentToMap(agent)
118 }
119 }
120
121 // TODO: Need to trigger a reconcile at this point
122
123 probe.UpdateStatusFromContext(ctx, "device-manager", probe.ServiceStatusRunning)
124 logger.Info(ctx, "device-manager-started")
125}
126
Kent Hagerman2b216042020-04-03 18:28:56 -0400127func (dMgr *Manager) addDeviceAgentToMap(agent *Agent) {
npujar1d86a522019-11-14 17:11:16 +0530128 if _, exist := dMgr.deviceAgents.Load(agent.deviceID); !exist {
129 dMgr.deviceAgents.Store(agent.deviceID, agent)
khenaidoob9203542018-09-17 22:56:37 -0400130 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400131 dMgr.lockRootDeviceMap.Lock()
132 defer dMgr.lockRootDeviceMap.Unlock()
Kent Hagerman2a07b862020-06-19 15:23:07 -0400133 dMgr.rootDevices[agent.deviceID] = agent.isRootDevice
khenaidoo2c6a0992019-04-29 13:46:56 -0400134
khenaidoob9203542018-09-17 22:56:37 -0400135}
136
Kent Hagerman2b216042020-04-03 18:28:56 -0400137func (dMgr *Manager) deleteDeviceAgentFromMap(agent *Agent) {
npujar1d86a522019-11-14 17:11:16 +0530138 dMgr.deviceAgents.Delete(agent.deviceID)
khenaidoo2c6a0992019-04-29 13:46:56 -0400139 dMgr.lockRootDeviceMap.Lock()
140 defer dMgr.lockRootDeviceMap.Unlock()
npujar1d86a522019-11-14 17:11:16 +0530141 delete(dMgr.rootDevices, agent.deviceID)
khenaidoo4d4802d2018-10-04 21:59:49 -0400142}
143
khenaidoo297cd252019-02-07 22:10:23 -0500144// 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 -0400145func (dMgr *Manager) getDeviceAgent(ctx context.Context, deviceID string) *Agent {
npujar1d86a522019-11-14 17:11:16 +0530146 agent, ok := dMgr.deviceAgents.Load(deviceID)
147 if ok {
Kent Hagerman2b216042020-04-03 18:28:56 -0400148 return agent.(*Agent)
khenaidoob9203542018-09-17 22:56:37 -0400149 }
khenaidoo442e7c72020-03-10 16:13:48 -0400150 // Try to load into memory - loading will also create the device agent and set the device ownership
npujar467fe752020-01-16 20:17:45 +0530151 err := dMgr.load(ctx, deviceID)
npujar1d86a522019-11-14 17:11:16 +0530152 if err == nil {
153 agent, ok = dMgr.deviceAgents.Load(deviceID)
154 if !ok {
155 return nil
156 }
Kent Hagerman2b216042020-04-03 18:28:56 -0400157 return agent.(*Agent)
npujar1d86a522019-11-14 17:11:16 +0530158 }
159 //TODO: Change the return params to return an error as well
divyadesaicb8b59d2020-08-18 09:55:47 +0000160 logger.Errorw(ctx, "loading-device-failed", log.Fields{"device-id": deviceID, "error": err})
khenaidoob9203542018-09-17 22:56:37 -0400161 return nil
162}
163
khenaidoo297cd252019-02-07 22:10:23 -0500164// listDeviceIdsFromMap returns the list of device IDs that are in memory
Kent Hagerman2b216042020-04-03 18:28:56 -0400165func (dMgr *Manager) listDeviceIdsFromMap() *voltha.IDs {
khenaidoo7ccedd52018-12-14 16:48:54 -0500166 result := &voltha.IDs{Items: make([]*voltha.ID, 0)}
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400167
168 dMgr.deviceAgents.Range(func(key, value interface{}) bool {
169 result.Items = append(result.Items, &voltha.ID{Id: key.(string)})
170 return true
171 })
172
khenaidoo7ccedd52018-12-14 16:48:54 -0500173 return result
174}
175
Kent Hagerman45a13e42020-04-13 12:23:50 -0400176// CreateDevice creates a new parent device in the data model
177func (dMgr *Manager) CreateDevice(ctx context.Context, device *voltha.Device) (*voltha.Device, error) {
178 if device.MacAddress == "" && device.GetHostAndPort() == "" {
Himani Chawlab4c25912020-11-12 17:16:38 +0530179 logger.Errorf(ctx, "no-device-info-present")
Kent Hagerman45a13e42020-04-13 12:23:50 -0400180 return &voltha.Device{}, errors.New("no-device-info-present; MAC or HOSTIP&PORT")
181 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530182 ctx = utils.WithRPCMetadataContext(ctx, "CreateDevice")
Rohan Agrawal31f21802020-06-12 05:38:46 +0000183 logger.Debugw(ctx, "create-device", log.Fields{"device": *device})
Kent Hagerman45a13e42020-04-13 12:23:50 -0400184
npujar467fe752020-01-16 20:17:45 +0530185 deviceExist, err := dMgr.isParentDeviceExist(ctx, device)
Thomas Lee Se5a44012019-11-07 20:32:24 +0530186 if err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530187 logger.Errorf(ctx, "failed-to-fetch-parent-device-info")
Kent Hagerman45a13e42020-04-13 12:23:50 -0400188 return nil, err
Thomas Lee Se5a44012019-11-07 20:32:24 +0530189 }
190 if deviceExist {
Himani Chawlab4c25912020-11-12 17:16:38 +0530191 logger.Errorf(ctx, "device-is-pre-provisioned-already-with-same-ip-port-or-mac-address")
Kent Hagerman45a13e42020-04-13 12:23:50 -0400192 return nil, errors.New("device is already pre-provisioned")
Thomas Lee S51b5cb82019-10-14 14:49:34 +0530193 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530194 logger.Debugw(ctx, "create-device", log.Fields{"device": device, "aproxy": dMgr.adapterProxy})
khenaidoob9203542018-09-17 22:56:37 -0400195
khenaidoo5e677ae2019-02-28 17:26:29 -0500196 // Ensure this device is set as root
197 device.Root = true
khenaidoob9203542018-09-17 22:56:37 -0400198 // Create and start a device agent for that device
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700199 agent := newAgent(dMgr.adapterProxy, device, dMgr, dMgr.dbPath, dMgr.dProxy, dMgr.defaultTimeout)
khenaidoo7585a962021-06-10 16:15:38 -0400200 device, err = agent.start(ctx, false, device)
Scott Baker80678602019-11-14 16:57:36 -0800201 if err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530202 logger.Errorw(ctx, "fail-to-start-device", log.Fields{"device-id": agent.deviceID, "error": err})
Kent Hagerman45a13e42020-04-13 12:23:50 -0400203 return nil, err
Scott Baker80678602019-11-14 16:57:36 -0800204 }
khenaidoo442e7c72020-03-10 16:13:48 -0400205 dMgr.addDeviceAgentToMap(agent)
Kent Hagerman45a13e42020-04-13 12:23:50 -0400206 return device, nil
khenaidoob9203542018-09-17 22:56:37 -0400207}
208
Kent Hagerman45a13e42020-04-13 12:23:50 -0400209// EnableDevice activates a device by invoking the adopt_device API on the appropriate adapter
210func (dMgr *Manager) EnableDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530211 ctx = utils.WithRPCMetadataContext(ctx, "EnableDevice")
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000212 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +0530213 logger.Debugw(ctx, "enable-device", log.Fields{"device-id": id.Id})
Kent Hagerman45a13e42020-04-13 12:23:50 -0400214 agent := dMgr.getDeviceAgent(ctx, id.Id)
215 if agent == nil {
216 return nil, status.Errorf(codes.NotFound, "%s", id.Id)
khenaidoob9203542018-09-17 22:56:37 -0400217 }
Kent Hagerman45a13e42020-04-13 12:23:50 -0400218 return &empty.Empty{}, agent.enableDevice(ctx)
khenaidoob9203542018-09-17 22:56:37 -0400219}
220
Kent Hagerman45a13e42020-04-13 12:23:50 -0400221// DisableDevice disables a device along with any child device it may have
222func (dMgr *Manager) DisableDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530223 ctx = utils.WithRPCMetadataContext(ctx, "DisableDevice")
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000224 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +0530225 logger.Debugw(ctx, "disable-device", log.Fields{"device-id": id.Id})
Kent Hagerman45a13e42020-04-13 12:23:50 -0400226 agent := dMgr.getDeviceAgent(ctx, id.Id)
227 if agent == nil {
228 return nil, status.Errorf(codes.NotFound, "%s", id.Id)
khenaidoob9203542018-09-17 22:56:37 -0400229 }
Kent Hagerman45a13e42020-04-13 12:23:50 -0400230 return &empty.Empty{}, agent.disableDevice(ctx)
khenaidoo92e62c52018-10-03 14:02:54 -0400231}
232
Kent Hagerman45a13e42020-04-13 12:23:50 -0400233//RebootDevice invoked the reboot API to the corresponding adapter
234func (dMgr *Manager) RebootDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530235 ctx = utils.WithRPCMetadataContext(ctx, "RebootDevice")
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000236 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +0530237 logger.Debugw(ctx, "reboot-device", log.Fields{"device-id": id.Id})
Kent Hagerman45a13e42020-04-13 12:23:50 -0400238 agent := dMgr.getDeviceAgent(ctx, id.Id)
239 if agent == nil {
240 return nil, status.Errorf(codes.NotFound, "%s", id.Id)
khenaidoo4d4802d2018-10-04 21:59:49 -0400241 }
Kent Hagerman45a13e42020-04-13 12:23:50 -0400242 return &empty.Empty{}, agent.rebootDevice(ctx)
khenaidoo4d4802d2018-10-04 21:59:49 -0400243}
244
Kent Hagerman45a13e42020-04-13 12:23:50 -0400245// DeleteDevice removes a device from the data model
246func (dMgr *Manager) DeleteDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530247 ctx = utils.WithRPCMetadataContext(ctx, "DeleteDevice")
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000248 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +0530249 logger.Debugw(ctx, "delete-device", log.Fields{"device-id": id.Id})
Kent Hagerman45a13e42020-04-13 12:23:50 -0400250 agent := dMgr.getDeviceAgent(ctx, id.Id)
251 if agent == nil {
252 return nil, status.Errorf(codes.NotFound, "%s", id.Id)
khenaidoo4d4802d2018-10-04 21:59:49 -0400253 }
Kent Hagerman45a13e42020-04-13 12:23:50 -0400254 return &empty.Empty{}, agent.deleteDevice(ctx)
255}
256
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530257// ForceDeleteDevice removes a device from the data model forcefully without successfully waiting for the adapters.
258func (dMgr *Manager) ForceDeleteDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530259 ctx = utils.WithRPCMetadataContext(ctx, "ForceDeleteDevice")
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530260 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +0530261 logger.Debugw(ctx, "force-delete-device", log.Fields{"device-id": id.Id})
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530262 agent := dMgr.getDeviceAgent(ctx, id.Id)
263 if agent == nil {
264 return nil, status.Errorf(codes.NotFound, "%s", id.Id)
265 }
266 return &empty.Empty{}, agent.deleteDeviceForce(ctx)
267}
268
Kent Hagerman2a07b862020-06-19 15:23:07 -0400269// GetDevicePort returns the port details for a specific device port entry
270func (dMgr *Manager) GetDevicePort(ctx context.Context, deviceID string, portID uint32) (*voltha.Port, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530271 logger.Debugw(ctx, "get-device-port", log.Fields{"device-id": deviceID})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400272 agent := dMgr.getDeviceAgent(ctx, deviceID)
273 if agent == nil {
274 return nil, status.Errorf(codes.NotFound, "device-%s", deviceID)
275 }
276 return agent.getDevicePort(portID)
277}
278
Kent Hagerman45a13e42020-04-13 12:23:50 -0400279// ListDevicePorts returns the ports details for a specific device entry
280func (dMgr *Manager) ListDevicePorts(ctx context.Context, id *voltha.ID) (*voltha.Ports, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530281 ctx = utils.WithRPCMetadataContext(ctx, "ListDevicePorts")
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000282 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +0530283 logger.Debugw(ctx, "list-device-ports", log.Fields{"device-id": id.Id})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400284 agent := dMgr.getDeviceAgent(ctx, id.Id)
285 if agent == nil {
286 return nil, status.Errorf(codes.NotFound, "device-%s", id.Id)
Kent Hagerman45a13e42020-04-13 12:23:50 -0400287 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400288
289 ports := agent.listDevicePorts()
290 ctr, ret := 0, make([]*voltha.Port, len(ports))
291 for _, port := range ports {
292 ret[ctr] = port
293 ctr++
294 }
295 return &voltha.Ports{Items: ret}, nil
Kent Hagerman45a13e42020-04-13 12:23:50 -0400296}
297
298// ListDeviceFlows returns the flow details for a specific device entry
299func (dMgr *Manager) ListDeviceFlows(ctx context.Context, id *voltha.ID) (*ofp.Flows, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530300 ctx = utils.WithRPCMetadataContext(ctx, "ListDeviceFlows")
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000301 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +0530302 logger.Debugw(ctx, "list-device-flows", log.Fields{"device-id": id.Id})
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700303 agent := dMgr.getDeviceAgent(ctx, id.Id)
304 if agent == nil {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400305 return nil, status.Errorf(codes.NotFound, "device-%s", id.Id)
Kent Hagerman45a13e42020-04-13 12:23:50 -0400306 }
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700307
308 flows := agent.listDeviceFlows()
309 ctr, ret := 0, make([]*ofp.OfpFlowStats, len(flows))
310 for _, flow := range flows {
311 ret[ctr] = flow
312 ctr++
313 }
314 return &openflow_13.Flows{Items: ret}, nil
Kent Hagerman45a13e42020-04-13 12:23:50 -0400315}
316
317// ListDeviceFlowGroups returns the flow group details for a specific device entry
318func (dMgr *Manager) ListDeviceFlowGroups(ctx context.Context, id *voltha.ID) (*voltha.FlowGroups, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530319 ctx = utils.WithRPCMetadataContext(ctx, "ListDeviceFlowGroups")
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000320 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +0530321 logger.Debugw(ctx, "list-device-flow-groups", log.Fields{"device-id": id.Id})
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700322 agent := dMgr.getDeviceAgent(ctx, id.Id)
323 if agent == nil {
Kent Hagerman45a13e42020-04-13 12:23:50 -0400324 return nil, status.Errorf(codes.NotFound, "device-%s", id.Id)
325 }
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700326 groups := agent.listDeviceGroups()
327 ctr, ret := 0, make([]*openflow_13.OfpGroupEntry, len(groups))
328 for _, group := range groups {
329 ret[ctr] = group
330 ctr++
331 }
332 return &voltha.FlowGroups{Items: ret}, nil
khenaidoo4d4802d2018-10-04 21:59:49 -0400333}
334
khenaidoo6d62c002019-05-15 21:57:03 -0400335// stopManagingDevice stops the management of the device as well as any of its reference device and logical device.
336// This function is called only in the Core that does not own this device. In the Core that owns this device then a
337// deletion deletion also includes removal of any reference of this device.
Kent Hagerman2b216042020-04-03 18:28:56 -0400338func (dMgr *Manager) stopManagingDevice(ctx context.Context, id string) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530339 logger.Infow(ctx, "stop-managing-device", log.Fields{"device-id": id})
khenaidoo6d62c002019-05-15 21:57:03 -0400340 if dMgr.IsDeviceInCache(id) { // Proceed only if an agent is present for this device
Kent Hagerman6031aad2020-07-29 16:36:33 -0400341 if device, err := dMgr.getDeviceReadOnly(ctx, id); err == nil && device.Root {
khenaidoo6d62c002019-05-15 21:57:03 -0400342 // stop managing the logical device
David Bainbridged1afd662020-03-26 18:27:41 -0700343 _ = dMgr.logicalDeviceMgr.stopManagingLogicalDeviceWithDeviceID(ctx, id)
khenaidoo6d62c002019-05-15 21:57:03 -0400344 }
npujar467fe752020-01-16 20:17:45 +0530345 if agent := dMgr.getDeviceAgent(ctx, id); agent != nil {
khenaidoo442e7c72020-03-10 16:13:48 -0400346 if err := agent.stop(ctx); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000347 logger.Warnw(ctx, "unable-to-stop-device-agent", log.Fields{"device-id": agent.deviceID, "error": err})
khenaidoo442e7c72020-03-10 16:13:48 -0400348 }
khenaidoo4c9e5592019-09-09 16:20:41 -0400349 dMgr.deleteDeviceAgentFromMap(agent)
khenaidoo6d62c002019-05-15 21:57:03 -0400350 }
351 }
352}
353
npujar1d86a522019-11-14 17:11:16 +0530354// RunPostDeviceDelete removes any reference of this device
Kent Hagerman2b216042020-04-03 18:28:56 -0400355func (dMgr *Manager) RunPostDeviceDelete(ctx context.Context, cDevice *voltha.Device) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530356 logger.Infow(ctx, "run-post-device-delete", log.Fields{"device-id": cDevice.Id})
serkant.uluderyae25f6482020-12-17 21:08:38 +0300357 if agent := dMgr.getDeviceAgent(ctx, cDevice.Id); agent != nil {
358 logger.Debugw(ctx, "invoking-delete-device-ports", log.Fields{"device-id": cDevice.Id})
359 //delete ports
360 if err := agent.deleteAllPorts(ctx); err != nil {
361 logger.Warnw(ctx, "failure-delete-device-ports", log.Fields{"device-id": cDevice.Id, "error": err.Error()})
362 }
363 }
npujar467fe752020-01-16 20:17:45 +0530364 dMgr.stopManagingDevice(ctx, cDevice.Id)
khenaidoo6d62c002019-05-15 21:57:03 -0400365 return nil
khenaidoo0a822f92019-05-08 15:15:57 -0400366}
367
Kent Hagermancba2f302020-07-28 13:37:36 -0400368// GetDevice exists primarily to implement the gRPC interface.
369// Internal functions should call getDeviceReadOnly instead.
Kent Hagerman45a13e42020-04-13 12:23:50 -0400370func (dMgr *Manager) GetDevice(ctx context.Context, id *voltha.ID) (*voltha.Device, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530371 ctx = utils.WithRPCMetadataContext(ctx, "GetDevice")
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000372 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
Kent Hagermancba2f302020-07-28 13:37:36 -0400373 return dMgr.getDeviceReadOnly(ctx, id.Id)
Kent Hagerman45a13e42020-04-13 12:23:50 -0400374}
375
Kent Hagermancba2f302020-07-28 13:37:36 -0400376// getDeviceReadOnly will returns a device, either from memory or from the dB, if present
377func (dMgr *Manager) getDeviceReadOnly(ctx context.Context, id string) (*voltha.Device, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530378 logger.Debugw(ctx, "get-device-read-only", log.Fields{"device-id": id})
npujar467fe752020-01-16 20:17:45 +0530379 if agent := dMgr.getDeviceAgent(ctx, id); agent != nil {
Kent Hagermancba2f302020-07-28 13:37:36 -0400380 return agent.getDeviceReadOnly(ctx)
khenaidoo92e62c52018-10-03 14:02:54 -0400381 }
382 return nil, status.Errorf(codes.NotFound, "%s", id)
khenaidoob9203542018-09-17 22:56:37 -0400383}
384
Kent Hagerman2a07b862020-06-19 15:23:07 -0400385func (dMgr *Manager) listDevicePorts(ctx context.Context, id string) (map[uint32]*voltha.Port, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530386 logger.Debugw(ctx, "list-device-ports", log.Fields{"device-id": id})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400387 agent := dMgr.getDeviceAgent(ctx, id)
388 if agent == nil {
389 return nil, status.Errorf(codes.NotFound, "%s", id)
390 }
391 return agent.listDevicePorts(), nil
392}
393
npujar1d86a522019-11-14 17:11:16 +0530394// GetChildDevice will return a device, either from memory or from the dB, if present
Kent Hagerman2b216042020-04-03 18:28:56 -0400395func (dMgr *Manager) GetChildDevice(ctx context.Context, parentDeviceID string, serialNumber string, onuID int64, parentPortNo int64) (*voltha.Device, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530396 logger.Debugw(ctx, "get-child-device", log.Fields{"parent-device-id": parentDeviceID, "serialNumber": serialNumber,
397 "parent-port-no": parentPortNo, "onu-id": onuID})
Matt Jeanneret4e241952019-02-28 11:16:04 -0500398
Kent Hagerman2a07b862020-06-19 15:23:07 -0400399 parentDevicePorts, err := dMgr.listDevicePorts(ctx, parentDeviceID)
400 if err != nil {
Matt Jeanneret4e241952019-02-28 11:16:04 -0500401 return nil, status.Errorf(codes.Aborted, "%s", err.Error())
402 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400403 childDeviceIds := dMgr.getAllChildDeviceIds(ctx, parentDevicePorts)
Matt Jeanneret4e241952019-02-28 11:16:04 -0500404 if len(childDeviceIds) == 0 {
Himani Chawlab4c25912020-11-12 17:16:38 +0530405 logger.Debugw(ctx, "no-child-devices", log.Fields{"parent-device-id": parentDeviceID, "serial-number": serialNumber, "onu-id": onuID})
npujar1d86a522019-11-14 17:11:16 +0530406 return nil, status.Errorf(codes.NotFound, "%s", parentDeviceID)
Matt Jeanneret4e241952019-02-28 11:16:04 -0500407 }
408
409 var foundChildDevice *voltha.Device
Kent Hagerman2a07b862020-06-19 15:23:07 -0400410 for childDeviceID := range childDeviceIds {
npujar1d86a522019-11-14 17:11:16 +0530411 var found bool
Kent Hagermancba2f302020-07-28 13:37:36 -0400412 if searchDevice, err := dMgr.getDeviceReadOnly(ctx, childDeviceID); err == nil {
Matt Jeanneret4e241952019-02-28 11:16:04 -0500413
npujar1d86a522019-11-14 17:11:16 +0530414 foundOnuID := false
415 if searchDevice.ProxyAddress.OnuId == uint32(onuID) {
Matt Jeanneret4e241952019-02-28 11:16:04 -0500416 if searchDevice.ParentPortNo == uint32(parentPortNo) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530417 logger.Debugw(ctx, "found-child-by-onuid", log.Fields{"parent-device-id": parentDeviceID, "onu-id": onuID})
npujar1d86a522019-11-14 17:11:16 +0530418 foundOnuID = true
Matt Jeanneret4e241952019-02-28 11:16:04 -0500419 }
420 }
421
422 foundSerialNumber := false
423 if searchDevice.SerialNumber == serialNumber {
Himani Chawlab4c25912020-11-12 17:16:38 +0530424 logger.Debugw(ctx, "found-child-by-serial-number", log.Fields{"parent-device-id": parentDeviceID, "serial-number": serialNumber})
Matt Jeanneret4e241952019-02-28 11:16:04 -0500425 foundSerialNumber = true
426 }
427
428 // if both onuId and serialNumber are provided both must be true for the device to be found
429 // otherwise whichever one found a match is good enough
npujar1d86a522019-11-14 17:11:16 +0530430 if onuID > 0 && serialNumber != "" {
431 found = foundOnuID && foundSerialNumber
Matt Jeanneret4e241952019-02-28 11:16:04 -0500432 } else {
npujar1d86a522019-11-14 17:11:16 +0530433 found = foundOnuID || foundSerialNumber
Matt Jeanneret4e241952019-02-28 11:16:04 -0500434 }
435
npujar1d86a522019-11-14 17:11:16 +0530436 if found {
Matt Jeanneret4e241952019-02-28 11:16:04 -0500437 foundChildDevice = searchDevice
438 break
439 }
440 }
441 }
442
443 if foundChildDevice != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530444 logger.Debugw(ctx, "child-device-found", log.Fields{"parent-device-id": parentDeviceID, "found-child-device": foundChildDevice})
Matt Jeanneret4e241952019-02-28 11:16:04 -0500445 return foundChildDevice, nil
446 }
447
divyadesaicb8b59d2020-08-18 09:55:47 +0000448 logger.Debugw(ctx, "child-device-not-found", log.Fields{"parent-device-id": parentDeviceID,
Himani Chawlab4c25912020-11-12 17:16:38 +0530449 "serial-number": serialNumber, "onu-id": onuID, "parent-port-no": parentPortNo})
npujar1d86a522019-11-14 17:11:16 +0530450 return nil, status.Errorf(codes.NotFound, "%s", parentDeviceID)
Matt Jeanneret4e241952019-02-28 11:16:04 -0500451}
452
npujar1d86a522019-11-14 17:11:16 +0530453// GetChildDeviceWithProxyAddress will return a device based on proxy address
Kent Hagerman2b216042020-04-03 18:28:56 -0400454func (dMgr *Manager) GetChildDeviceWithProxyAddress(ctx context.Context, proxyAddress *voltha.Device_ProxyAddress) (*voltha.Device, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530455 logger.Debugw(ctx, "get-child-device-with-proxy-address", log.Fields{"proxy-address": proxyAddress})
Matt Jeanneret2a20aaa2019-03-05 21:04:02 -0500456
Kent Hagerman2a07b862020-06-19 15:23:07 -0400457 parentDevicePorts, err := dMgr.listDevicePorts(ctx, proxyAddress.DeviceId)
458 if err != nil {
Matt Jeanneret2a20aaa2019-03-05 21:04:02 -0500459 return nil, status.Errorf(codes.Aborted, "%s", err.Error())
460 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400461 childDeviceIds := dMgr.getAllChildDeviceIds(ctx, parentDevicePorts)
Matt Jeanneret2a20aaa2019-03-05 21:04:02 -0500462 if len(childDeviceIds) == 0 {
divyadesaicb8b59d2020-08-18 09:55:47 +0000463 logger.Debugw(ctx, "no-child-devices", log.Fields{"parent-device-id": proxyAddress.DeviceId})
Matt Jeanneret2a20aaa2019-03-05 21:04:02 -0500464 return nil, status.Errorf(codes.NotFound, "%s", proxyAddress)
465 }
466
467 var foundChildDevice *voltha.Device
Kent Hagerman2a07b862020-06-19 15:23:07 -0400468 for childDeviceID := range childDeviceIds {
Kent Hagermancba2f302020-07-28 13:37:36 -0400469 if searchDevice, err := dMgr.getDeviceReadOnly(ctx, childDeviceID); err == nil {
Matt Jeanneret2a20aaa2019-03-05 21:04:02 -0500470 if searchDevice.ProxyAddress == proxyAddress {
471 foundChildDevice = searchDevice
472 break
473 }
474 }
475 }
476
477 if foundChildDevice != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530478 logger.Debugw(ctx, "child-device-found", log.Fields{"proxy-address": proxyAddress})
Matt Jeanneret2a20aaa2019-03-05 21:04:02 -0500479 return foundChildDevice, nil
480 }
481
Himani Chawlab4c25912020-11-12 17:16:38 +0530482 logger.Warnw(ctx, "child-device-not-found", log.Fields{"proxy-address": proxyAddress})
Matt Jeanneret2a20aaa2019-03-05 21:04:02 -0500483 return nil, status.Errorf(codes.NotFound, "%s", proxyAddress)
484}
485
npujar1d86a522019-11-14 17:11:16 +0530486// IsDeviceInCache returns true if device is found in the map
Kent Hagerman2b216042020-04-03 18:28:56 -0400487func (dMgr *Manager) IsDeviceInCache(id string) bool {
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400488 _, exist := dMgr.deviceAgents.Load(id)
khenaidoo297cd252019-02-07 22:10:23 -0500489 return exist
490}
491
Stephane Barbarieaa467942019-02-06 14:09:44 -0500492// ListDevices retrieves the latest devices from the data model
Kent Hagerman45a13e42020-04-13 12:23:50 -0400493func (dMgr *Manager) ListDevices(ctx context.Context, _ *empty.Empty) (*voltha.Devices, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530494 ctx = utils.WithRPCMetadataContext(ctx, "ListDevices")
495 logger.Debug(ctx, "list-devices")
khenaidoob9203542018-09-17 22:56:37 -0400496 result := &voltha.Devices{}
Kent Hagerman4f355f52020-03-30 16:01:33 -0400497
Esin Karamana4e4e002021-03-02 10:42:16 +0000498 dMgr.deviceAgents.Range(func(key, value interface{}) bool {
499 result.Items = append(result.Items, value.(*Agent).device)
500 return true
501 })
Kent Hagerman4f355f52020-03-30 16:01:33 -0400502
Himani Chawlab4c25912020-11-12 17:16:38 +0530503 logger.Debugw(ctx, "list-devices-end", log.Fields{"len": len(result.Items)})
khenaidoob9203542018-09-17 22:56:37 -0400504 return result, nil
505}
506
Thomas Lee S51b5cb82019-10-14 14:49:34 +0530507//isParentDeviceExist checks whether device is already preprovisioned.
Kent Hagerman2b216042020-04-03 18:28:56 -0400508func (dMgr *Manager) isParentDeviceExist(ctx context.Context, newDevice *voltha.Device) (bool, error) {
Thomas Lee S51b5cb82019-10-14 14:49:34 +0530509 hostPort := newDevice.GetHostAndPort()
Kent Hagerman4f355f52020-03-30 16:01:33 -0400510 var devices []*voltha.Device
Kent Hagermanf5a67352020-04-30 15:15:26 -0400511 if err := dMgr.dProxy.List(ctx, &devices); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530512 logger.Errorw(ctx, "failed-to-list-devices-from-cluster-data-proxy", log.Fields{"error": err})
Thomas Lee Se5a44012019-11-07 20:32:24 +0530513 return false, err
514 }
Kent Hagerman4f355f52020-03-30 16:01:33 -0400515 for _, device := range devices {
516 if !device.Root {
517 continue
518 }
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530519
520 if hostPort != "" && hostPort == device.GetHostAndPort() {
Kent Hagerman4f355f52020-03-30 16:01:33 -0400521 return true, nil
522 }
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530523 if newDevice.MacAddress != "" && newDevice.MacAddress == device.MacAddress {
Kent Hagerman4f355f52020-03-30 16:01:33 -0400524 return true, nil
Thomas Lee S51b5cb82019-10-14 14:49:34 +0530525 }
526 }
Thomas Lee Se5a44012019-11-07 20:32:24 +0530527 return false, nil
Thomas Lee S51b5cb82019-10-14 14:49:34 +0530528}
529
khenaidoo6d62c002019-05-15 21:57:03 -0400530//getDeviceFromModelretrieves the device data from the model.
Kent Hagerman2b216042020-04-03 18:28:56 -0400531func (dMgr *Manager) getDeviceFromModel(ctx context.Context, deviceID string) (*voltha.Device, error) {
Kent Hagerman4f355f52020-03-30 16:01:33 -0400532 device := &voltha.Device{}
Kent Hagermanf5a67352020-04-30 15:15:26 -0400533 if have, err := dMgr.dProxy.Get(ctx, deviceID, device); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000534 logger.Errorw(ctx, "failed-to-get-device-info-from-cluster-proxy", log.Fields{"error": err})
Thomas Lee Se5a44012019-11-07 20:32:24 +0530535 return nil, err
Kent Hagerman4f355f52020-03-30 16:01:33 -0400536 } else if !have {
537 return nil, status.Error(codes.NotFound, deviceID)
Thomas Lee Se5a44012019-11-07 20:32:24 +0530538 }
Kent Hagerman4f355f52020-03-30 16:01:33 -0400539
540 return device, nil
khenaidoo6d62c002019-05-15 21:57:03 -0400541}
542
npujar1d86a522019-11-14 17:11:16 +0530543// loadDevice loads the deviceID in memory, if not present
Kent Hagerman2b216042020-04-03 18:28:56 -0400544func (dMgr *Manager) loadDevice(ctx context.Context, deviceID string) (*Agent, error) {
npujar1d86a522019-11-14 17:11:16 +0530545 if deviceID == "" {
khenaidoo297cd252019-02-07 22:10:23 -0500546 return nil, status.Error(codes.InvalidArgument, "deviceId empty")
547 }
khenaidoo4c9e5592019-09-09 16:20:41 -0400548 var err error
549 var device *voltha.Device
550 dMgr.devicesLoadingLock.Lock()
npujar1d86a522019-11-14 17:11:16 +0530551 if _, exist := dMgr.deviceLoadingInProgress[deviceID]; !exist {
552 if !dMgr.IsDeviceInCache(deviceID) {
553 dMgr.deviceLoadingInProgress[deviceID] = []chan int{make(chan int, 1)}
khenaidoo4c9e5592019-09-09 16:20:41 -0400554 dMgr.devicesLoadingLock.Unlock()
555 // Proceed with the loading only if the device exist in the Model (could have been deleted)
npujar467fe752020-01-16 20:17:45 +0530556 if device, err = dMgr.getDeviceFromModel(ctx, deviceID); err == nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000557 logger.Debugw(ctx, "loading-device", log.Fields{"device-id": deviceID})
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700558 agent := newAgent(dMgr.adapterProxy, device, dMgr, dMgr.dbPath, dMgr.dProxy, dMgr.defaultTimeout)
khenaidoo7585a962021-06-10 16:15:38 -0400559 if _, err = agent.start(ctx, true, device); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530560 logger.Warnw(ctx, "failure-loading-device", log.Fields{"device-id": deviceID, "error": err})
khenaidoo4c9e5592019-09-09 16:20:41 -0400561 } else {
562 dMgr.addDeviceAgentToMap(agent)
563 }
564 } else {
Himani Chawlab4c25912020-11-12 17:16:38 +0530565 logger.Debugw(ctx, "device-is-not-in-model", log.Fields{"device-id": deviceID})
khenaidoo6d62c002019-05-15 21:57:03 -0400566 }
khenaidoo4c9e5592019-09-09 16:20:41 -0400567 // announce completion of task to any number of waiting channels
568 dMgr.devicesLoadingLock.Lock()
npujar1d86a522019-11-14 17:11:16 +0530569 if v, ok := dMgr.deviceLoadingInProgress[deviceID]; ok {
khenaidoo4c9e5592019-09-09 16:20:41 -0400570 for _, ch := range v {
571 close(ch)
572 }
npujar1d86a522019-11-14 17:11:16 +0530573 delete(dMgr.deviceLoadingInProgress, deviceID)
khenaidoo4c9e5592019-09-09 16:20:41 -0400574 }
575 dMgr.devicesLoadingLock.Unlock()
khenaidoo6d62c002019-05-15 21:57:03 -0400576 } else {
khenaidoo4c9e5592019-09-09 16:20:41 -0400577 dMgr.devicesLoadingLock.Unlock()
khenaidoo297cd252019-02-07 22:10:23 -0500578 }
khenaidoo4c9e5592019-09-09 16:20:41 -0400579 } else {
580 ch := make(chan int, 1)
npujar1d86a522019-11-14 17:11:16 +0530581 dMgr.deviceLoadingInProgress[deviceID] = append(dMgr.deviceLoadingInProgress[deviceID], ch)
khenaidoo4c9e5592019-09-09 16:20:41 -0400582 dMgr.devicesLoadingLock.Unlock()
583 // Wait for the channel to be closed, implying the process loading this device is done.
584 <-ch
khenaidoo297cd252019-02-07 22:10:23 -0500585 }
npujar1d86a522019-11-14 17:11:16 +0530586 if agent, ok := dMgr.deviceAgents.Load(deviceID); ok {
Kent Hagerman2b216042020-04-03 18:28:56 -0400587 return agent.(*Agent), nil
khenaidoo297cd252019-02-07 22:10:23 -0500588 }
npujar1d86a522019-11-14 17:11:16 +0530589 return nil, status.Errorf(codes.Aborted, "Error loading device %s", deviceID)
khenaidoo297cd252019-02-07 22:10:23 -0500590}
591
592// loadRootDeviceParentAndChildren loads the children and parents of a root device in memory
Kent Hagerman2a07b862020-06-19 15:23:07 -0400593func (dMgr *Manager) loadRootDeviceParentAndChildren(ctx context.Context, device *voltha.Device, devicePorts map[uint32]*voltha.Port) error {
divyadesaicb8b59d2020-08-18 09:55:47 +0000594 logger.Debugw(ctx, "loading-parent-and-children", log.Fields{"device-id": device.Id})
khenaidoo297cd252019-02-07 22:10:23 -0500595 if device.Root {
596 // Scenario A
597 if device.ParentId != "" {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400598 // Load logical device if needed.
npujar467fe752020-01-16 20:17:45 +0530599 if err := dMgr.logicalDeviceMgr.load(ctx, device.ParentId); err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000600 logger.Warnw(ctx, "failure-loading-logical-device", log.Fields{"logical-device-id": device.ParentId})
khenaidoo297cd252019-02-07 22:10:23 -0500601 }
602 } else {
divyadesaicb8b59d2020-08-18 09:55:47 +0000603 logger.Debugw(ctx, "no-parent-to-load", log.Fields{"device-id": device.Id})
khenaidoo297cd252019-02-07 22:10:23 -0500604 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400605 // Load all child devices, if needed
606 childDeviceIds := dMgr.getAllChildDeviceIds(ctx, devicePorts)
607 for childDeviceID := range childDeviceIds {
608 if _, err := dMgr.loadDevice(ctx, childDeviceID); err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000609 logger.Warnw(ctx, "failure-loading-device", log.Fields{"device-id": childDeviceID, "error": err})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400610 return err
khenaidoo297cd252019-02-07 22:10:23 -0500611 }
khenaidoo297cd252019-02-07 22:10:23 -0500612 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530613 logger.Debugw(ctx, "loaded-children", log.Fields{"device-id": device.Id, "num-children": len(childDeviceIds)})
khenaidoo297cd252019-02-07 22:10:23 -0500614 }
615 return nil
616}
617
618// load loads the deviceId in memory, if not present, and also loads its accompanying parents and children. Loading
619// in memory is for improved performance. It is not imperative that a device needs to be in memory when a request
620// acting on the device is received by the core. In such a scenario, the Core will load the device in memory first
621// and the proceed with the request.
Kent Hagerman2b216042020-04-03 18:28:56 -0400622func (dMgr *Manager) load(ctx context.Context, deviceID string) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000623 logger.Debug(ctx, "load...")
khenaidoo297cd252019-02-07 22:10:23 -0500624 // 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 -0400625 var dAgent *Agent
khenaidoo297cd252019-02-07 22:10:23 -0500626 var err error
npujar467fe752020-01-16 20:17:45 +0530627 if dAgent, err = dMgr.loadDevice(ctx, deviceID); err != nil {
khenaidoo297cd252019-02-07 22:10:23 -0500628 return err
629 }
630 // Get the loaded device details
Kent Hagermancba2f302020-07-28 13:37:36 -0400631 device, err := dAgent.getDeviceReadOnly(ctx)
khenaidoo442e7c72020-03-10 16:13:48 -0400632 if err != nil {
633 return err
634 }
khenaidoo297cd252019-02-07 22:10:23 -0500635
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530636 // If the device is in Pre-provisioning or getting deleted state stop here
637 if device.AdminState == voltha.AdminState_PREPROVISIONED || dAgent.isDeletionInProgress() {
khenaidoo297cd252019-02-07 22:10:23 -0500638 return nil
639 }
640
641 // Now we face two scenarios
642 if device.Root {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400643 devicePorts := dAgent.listDevicePorts()
644
khenaidoo297cd252019-02-07 22:10:23 -0500645 // Load all children as well as the parent of this device (logical_device)
Kent Hagerman2a07b862020-06-19 15:23:07 -0400646 if err := dMgr.loadRootDeviceParentAndChildren(ctx, device, devicePorts); err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000647 logger.Warnw(ctx, "failure-loading-device-parent-and-children", log.Fields{"device-id": deviceID})
khenaidoo297cd252019-02-07 22:10:23 -0500648 return err
649 }
divyadesaicb8b59d2020-08-18 09:55:47 +0000650 logger.Debugw(ctx, "successfully-loaded-parent-and-children", log.Fields{"device-id": deviceID})
Andrey Pozolotin34dd63f2021-05-31 21:26:40 +0300651 } else if device.ParentId != "" {
khenaidoo297cd252019-02-07 22:10:23 -0500652 // Scenario B - use the parentId of that device (root device) to trigger the loading
Andrey Pozolotin34dd63f2021-05-31 21:26:40 +0300653 return dMgr.load(ctx, device.ParentId)
khenaidoo297cd252019-02-07 22:10:23 -0500654 }
Andrey Pozolotin34dd63f2021-05-31 21:26:40 +0300655
khenaidoo297cd252019-02-07 22:10:23 -0500656 return nil
657}
658
khenaidoo7ccedd52018-12-14 16:48:54 -0500659// ListDeviceIds retrieves the latest device IDs information from the data model (memory data only)
Rohan Agrawal31f21802020-06-12 05:38:46 +0000660func (dMgr *Manager) ListDeviceIds(ctx context.Context, _ *empty.Empty) (*voltha.IDs, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530661 ctx = utils.WithRPCMetadataContext(ctx, "ListDeviceIds")
662 logger.Debug(ctx, "list-device-ids")
khenaidoo7ccedd52018-12-14 16:48:54 -0500663 // Report only device IDs that are in the device agent map
664 return dMgr.listDeviceIdsFromMap(), nil
665}
666
Kent Hagerman45a13e42020-04-13 12:23:50 -0400667// ReconcileDevices is a request to a voltha core to update its list of managed devices. This will
668// trigger loading the devices along with their children and parent in memory
669func (dMgr *Manager) ReconcileDevices(ctx context.Context, ids *voltha.IDs) (*empty.Empty, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530670 ctx = utils.WithRPCMetadataContext(ctx, "ReconcileDevices")
Andrey Pozolotin34dd63f2021-05-31 21:26:40 +0300671
672 numDevices := 0
673 if ids != nil {
674 numDevices = len(ids.Items)
675 }
676
677 logger.Debugw(ctx, "reconcile-devices", log.Fields{"num-devices": numDevices})
khenaidoo4c9e5592019-09-09 16:20:41 -0400678 if ids != nil && len(ids.Items) != 0 {
khenaidoo7ccedd52018-12-14 16:48:54 -0500679 toReconcile := len(ids.Items)
680 reconciled := 0
khenaidoo4c9e5592019-09-09 16:20:41 -0400681 var err error
khenaidoo7ccedd52018-12-14 16:48:54 -0500682 for _, id := range ids.Items {
npujar467fe752020-01-16 20:17:45 +0530683 if err = dMgr.load(ctx, id.Id); err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000684 logger.Warnw(ctx, "failure-reconciling-device", log.Fields{"device-id": id.Id, "error": err})
khenaidoo4c9e5592019-09-09 16:20:41 -0400685 } else {
npujar1d86a522019-11-14 17:11:16 +0530686 reconciled++
khenaidoo7ccedd52018-12-14 16:48:54 -0500687 }
688 }
689 if toReconcile != reconciled {
Kent Hagerman45a13e42020-04-13 12:23:50 -0400690 return nil, status.Errorf(codes.DataLoss, "less-device-reconciled-than-requested:%d/%d", reconciled, toReconcile)
khenaidoo7ccedd52018-12-14 16:48:54 -0500691 }
692 } else {
Kent Hagerman45a13e42020-04-13 12:23:50 -0400693 return nil, status.Errorf(codes.InvalidArgument, "empty-list-of-ids")
khenaidoo7ccedd52018-12-14 16:48:54 -0500694 }
Kent Hagerman45a13e42020-04-13 12:23:50 -0400695 return &empty.Empty{}, nil
khenaidoo7ccedd52018-12-14 16:48:54 -0500696}
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500697
khenaidooba6b6c42019-08-02 09:11:56 -0400698// adapterRestarted is invoked whenever an adapter is restarted
Kent Hagerman2b216042020-04-03 18:28:56 -0400699func (dMgr *Manager) adapterRestarted(ctx context.Context, adapter *voltha.Adapter) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530700 logger.Debugw(ctx, "adapter-restarted", log.Fields{"adapter-id": adapter.Id, "vendor": adapter.Vendor,
701 "current-replica": adapter.CurrentReplica, "total-replicas": adapter.TotalReplicas, "endpoint": adapter.Endpoint})
khenaidooba6b6c42019-08-02 09:11:56 -0400702
703 // Let's reconcile the device managed by this Core only
David Bainbridged1afd662020-03-26 18:27:41 -0700704 if len(dMgr.rootDevices) == 0 {
Himani Chawlab4c25912020-11-12 17:16:38 +0530705 logger.Debugw(ctx, "nothing-to-reconcile", log.Fields{"adapter-id": adapter.Id})
khenaidooba6b6c42019-08-02 09:11:56 -0400706 return nil
707 }
708
Maninder0aabf0c2021-03-17 14:55:14 +0530709 if len(dMgr.rootDevices) == 0 {
710 logger.Debugw(ctx, "no-managed-device-to-reconcile", log.Fields{"adapter-id": adapter.Id})
711 return nil
712 }
713
David Bainbridged1afd662020-03-26 18:27:41 -0700714 for rootDeviceID := range dMgr.rootDevices {
Mahir Gunyel12cf55f2020-12-16 17:55:03 -0800715 dAgent := dMgr.getDeviceAgent(ctx, rootDeviceID)
716 if dAgent == nil {
717 continue
718 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530719 logger.Debugw(ctx, "checking-adapter-type", log.Fields{"agentType": dAgent.deviceType, "adapter-type": adapter.Type})
Mahir Gunyel12cf55f2020-12-16 17:55:03 -0800720 if dAgent.deviceType == adapter.Type {
721 rootDevice, _ := dAgent.getDeviceReadOnly(ctx)
722 if rootDevice == nil {
723 continue
724 }
Rohan Agrawal31f21802020-06-12 05:38:46 +0000725 isDeviceOwnedByService, err := dMgr.adapterProxy.IsDeviceOwnedByService(ctx, rootDeviceID, adapter.Type, adapter.CurrentReplica)
serkant.uluderya7d545aa2020-04-09 13:38:45 -0700726 if err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530727 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 -0700728 continue
729 }
730 if isDeviceOwnedByService {
Maninder0aabf0c2021-03-17 14:55:14 +0530731 if rootDevice.AdminState != voltha.AdminState_PREPROVISIONED {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000732 logger.Debugw(ctx, "reconciling-root-device", log.Fields{"rootId": rootDevice.Id})
Maninder0aabf0c2021-03-17 14:55:14 +0530733 go dAgent.ReconcileDevice(ctx, rootDevice)
khenaidooba6b6c42019-08-02 09:11:56 -0400734 } else {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000735 logger.Debugw(ctx, "not-reconciling-root-device", log.Fields{"rootId": rootDevice.Id, "state": rootDevice.AdminState})
khenaidooba6b6c42019-08-02 09:11:56 -0400736 }
737 } else { // Should we be reconciling the root's children instead?
Kent Hagerman2a07b862020-06-19 15:23:07 -0400738 rootDevicePorts, _ := dMgr.listDevicePorts(ctx, rootDeviceID)
khenaidooba6b6c42019-08-02 09:11:56 -0400739 childManagedByAdapter:
Kent Hagerman2a07b862020-06-19 15:23:07 -0400740 for _, port := range rootDevicePorts {
khenaidooba6b6c42019-08-02 09:11:56 -0400741 for _, peer := range port.Peers {
npujar467fe752020-01-16 20:17:45 +0530742 if childDevice, _ := dMgr.getDeviceFromModel(ctx, peer.DeviceId); childDevice != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000743 isDeviceOwnedByService, err := dMgr.adapterProxy.IsDeviceOwnedByService(ctx, childDevice.Id, adapter.Type, adapter.CurrentReplica)
serkant.uluderya7d545aa2020-04-09 13:38:45 -0700744 if err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530745 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 -0700746 }
747 if isDeviceOwnedByService {
Maninder0aabf0c2021-03-17 14:55:14 +0530748 if childDevice.AdminState != voltha.AdminState_PREPROVISIONED {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000749 logger.Debugw(ctx, "reconciling-child-device", log.Fields{"child-device-id": childDevice.Id})
Maninder0aabf0c2021-03-17 14:55:14 +0530750 go dAgent.ReconcileDevice(ctx, childDevice)
khenaidooba6b6c42019-08-02 09:11:56 -0400751 } else {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000752 logger.Debugw(ctx, "not-reconciling-child-device", log.Fields{"child-device-id": childDevice.Id, "state": childDevice.AdminState})
khenaidooba6b6c42019-08-02 09:11:56 -0400753 }
754 } else {
755 // All child devices under a parent device are typically managed by the same adapter type.
756 // Therefore we only need to check whether the first device we retrieved is managed by that adapter
757 break childManagedByAdapter
758 }
759 }
760 }
761 }
762 }
763 }
764 }
Maninder0aabf0c2021-03-17 14:55:14 +0530765 logger.Debugw(ctx, "Reconciling for device on adapter restart is initiated", log.Fields{"adapter-id": adapter.Id})
766
khenaidooba6b6c42019-08-02 09:11:56 -0400767 return nil
768}
769
Kent Hagerman2b216042020-04-03 18:28:56 -0400770func (dMgr *Manager) ReconcileChildDevices(ctx context.Context, parentDeviceID string) error {
Maninder0aabf0c2021-03-17 14:55:14 +0530771 dAgent := dMgr.getDeviceAgent(ctx, parentDeviceID)
772 if dAgent == nil {
773 return status.Errorf(codes.NotFound, "error-unable to get agent from device")
774 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400775 if parentDevicePorts, err := dMgr.listDevicePorts(ctx, parentDeviceID); err == nil {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400776 for _, port := range parentDevicePorts {
khenaidooba6b6c42019-08-02 09:11:56 -0400777 for _, peer := range port.Peers {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400778 if childDevice, err := dMgr.getDeviceFromModel(ctx, peer.DeviceId); err == nil {
Maninder0aabf0c2021-03-17 14:55:14 +0530779 go dAgent.ReconcileDevice(ctx, childDevice)
khenaidooba6b6c42019-08-02 09:11:56 -0400780 }
781 }
782 }
Maninder0aabf0c2021-03-17 14:55:14 +0530783 logger.Debugw(ctx, "Reconcile initiated for child devices", log.Fields{"parent-device-id": parentDeviceID})
khenaidooba6b6c42019-08-02 09:11:56 -0400784 }
785 return nil
786}
787
Kent Hagerman2b216042020-04-03 18:28:56 -0400788func (dMgr *Manager) UpdateDeviceUsingAdapterData(ctx context.Context, device *voltha.Device) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530789 logger.Debugw(ctx, "update-device-using-adapter-data", log.Fields{"device-id": device.Id, "device": device})
npujar467fe752020-01-16 20:17:45 +0530790 if agent := dMgr.getDeviceAgent(ctx, device.Id); agent != nil {
791 return agent.updateDeviceUsingAdapterData(ctx, device)
khenaidoob9203542018-09-17 22:56:37 -0400792 }
793 return status.Errorf(codes.NotFound, "%s", device.Id)
794}
795
khenaidoo0db4c812020-05-27 15:27:30 -0400796func (dMgr *Manager) addPeerPort(ctx context.Context, deviceID string, port *voltha.Port) error {
797 meAsPeer := &voltha.Port_PeerPort{DeviceId: deviceID, PortNo: port.PortNo}
798 for _, peerPort := range port.Peers {
799 if agent := dMgr.getDeviceAgent(ctx, peerPort.DeviceId); agent != nil {
800 if err := agent.addPeerPort(ctx, meAsPeer); err != nil {
801 return err
802 }
803 }
804 }
805 // Notify the logical device manager to setup a logical port, if needed. If the added port is an NNI or UNI
806 // then a logical port will be added to the logical device and the device route generated. If the port is a
807 // PON port then only the device graph will be generated.
Kent Hagermancba2f302020-07-28 13:37:36 -0400808 device, err := dMgr.getDeviceReadOnly(ctx, deviceID)
khenaidoo0db4c812020-05-27 15:27:30 -0400809 if err != nil {
810 return err
811 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400812 ports, err := dMgr.listDevicePorts(ctx, deviceID)
813 if err != nil {
814 return err
815 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530816 subCtx := utils.WithSpanAndRPCMetadataFromContext(ctx)
817
818 if err = dMgr.logicalDeviceMgr.updateLogicalPort(subCtx, device, ports, port); err != nil {
khenaidoo0db4c812020-05-27 15:27:30 -0400819 return err
820 }
821 return nil
822}
823
Kent Hagerman2b216042020-04-03 18:28:56 -0400824func (dMgr *Manager) AddPort(ctx context.Context, deviceID string, port *voltha.Port) error {
npujar467fe752020-01-16 20:17:45 +0530825 agent := dMgr.getDeviceAgent(ctx, deviceID)
npujar1d86a522019-11-14 17:11:16 +0530826 if agent != nil {
npujar467fe752020-01-16 20:17:45 +0530827 if err := agent.addPort(ctx, port); err != nil {
khenaidoo92e62c52018-10-03 14:02:54 -0400828 return err
829 }
khenaidoo0db4c812020-05-27 15:27:30 -0400830 // Setup peer ports in its own routine
831 go func() {
Himani Chawlab4c25912020-11-12 17:16:38 +0530832 subCtx := utils.WithSpanAndRPCMetadataFromContext(ctx)
833 if err := dMgr.addPeerPort(subCtx, deviceID, port); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000834 logger.Errorw(ctx, "unable-to-add-peer-port", log.Fields{"error": err, "device-id": deviceID})
khenaidoo92e62c52018-10-03 14:02:54 -0400835 }
khenaidoo0db4c812020-05-27 15:27:30 -0400836 }()
khenaidoo92e62c52018-10-03 14:02:54 -0400837 return nil
khenaidoob9203542018-09-17 22:56:37 -0400838 }
npujar1d86a522019-11-14 17:11:16 +0530839 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoob9203542018-09-17 22:56:37 -0400840}
841
Kent Hagerman2b216042020-04-03 18:28:56 -0400842func (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 +0530843 logger.Debugw(ctx, "add-flows-and-groups", log.Fields{"device-id": deviceID, "groups:": groups, "flow-metadata": flowMetadata})
npujar467fe752020-01-16 20:17:45 +0530844 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
845 return agent.addFlowsAndGroups(ctx, flows, groups, flowMetadata)
khenaidoo0458db62019-06-20 08:50:36 -0400846 }
npujar1d86a522019-11-14 17:11:16 +0530847 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo0458db62019-06-20 08:50:36 -0400848}
849
khenaidoo787224a2020-04-16 18:08:47 -0400850// deleteParentFlows removes flows from the parent device based on specific attributes
851func (dMgr *Manager) deleteParentFlows(ctx context.Context, deviceID string, uniPort uint32, metadata *voltha.FlowMetadata) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530852 logger.Debugw(ctx, "delete-parent-flows", log.Fields{"device-id": deviceID, "uni-port": uniPort, "metadata": metadata})
khenaidoo787224a2020-04-16 18:08:47 -0400853 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400854 if !agent.isRootDevice {
khenaidoo787224a2020-04-16 18:08:47 -0400855 return status.Errorf(codes.FailedPrecondition, "not-a-parent-device-%s", deviceID)
856 }
857 return agent.filterOutFlows(ctx, uniPort, metadata)
858 }
859 return status.Errorf(codes.NotFound, "%s", deviceID)
860}
861
Kent Hagerman2b216042020-04-03 18:28:56 -0400862func (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 +0530863 logger.Debugw(ctx, "delete-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.deleteFlowsAndGroups(ctx, flows, groups, flowMetadata)
khenaidoo0458db62019-06-20 08:50:36 -0400866 }
npujar1d86a522019-11-14 17:11:16 +0530867 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo0458db62019-06-20 08:50:36 -0400868}
869
Kent Hagerman2b216042020-04-03 18:28:56 -0400870func (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 +0530871 logger.Debugw(ctx, "update-flows-and-groups", log.Fields{"device-id": deviceID})
npujar467fe752020-01-16 20:17:45 +0530872 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
873 return agent.updateFlowsAndGroups(ctx, flows, groups, flowMetadata)
khenaidoo19d7b632018-10-30 10:49:50 -0400874 }
npujar1d86a522019-11-14 17:11:16 +0530875 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo19d7b632018-10-30 10:49:50 -0400876}
877
Kent Hagerman45a13e42020-04-13 12:23:50 -0400878// UpdateDevicePmConfigs updates the PM configs. This is executed when the northbound gRPC API is invoked, typically
khenaidoob3127472019-07-24 21:04:55 -0400879// following a user action
Kent Hagerman45a13e42020-04-13 12:23:50 -0400880func (dMgr *Manager) UpdateDevicePmConfigs(ctx context.Context, configs *voltha.PmConfigs) (*empty.Empty, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530881 ctx = utils.WithRPCMetadataContext(ctx, "UpdateDevicePmConfigs")
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000882 log.EnrichSpan(ctx, log.Fields{"device-id": configs.Id})
Kent Hagerman45a13e42020-04-13 12:23:50 -0400883 if configs.Id == "" {
884 return nil, status.Error(codes.FailedPrecondition, "invalid-device-Id")
khenaidoob3127472019-07-24 21:04:55 -0400885 }
Kent Hagerman45a13e42020-04-13 12:23:50 -0400886 agent := dMgr.getDeviceAgent(ctx, configs.Id)
887 if agent == nil {
888 return nil, status.Errorf(codes.NotFound, "%s", configs.Id)
889 }
890 return &empty.Empty{}, agent.updatePmConfigs(ctx, configs)
khenaidoob3127472019-07-24 21:04:55 -0400891}
892
Kent Hagerman2b216042020-04-03 18:28:56 -0400893// InitPmConfigs initialize the pm configs as defined by the adapter.
894func (dMgr *Manager) InitPmConfigs(ctx context.Context, deviceID string, pmConfigs *voltha.PmConfigs) error {
khenaidoob3127472019-07-24 21:04:55 -0400895 if pmConfigs.Id == "" {
896 return status.Errorf(codes.FailedPrecondition, "invalid-device-Id")
897 }
npujar467fe752020-01-16 20:17:45 +0530898 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
899 return agent.initPmConfigs(ctx, pmConfigs)
khenaidoob9203542018-09-17 22:56:37 -0400900 }
npujar1d86a522019-11-14 17:11:16 +0530901 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoob9203542018-09-17 22:56:37 -0400902}
903
Kent Hagerman45a13e42020-04-13 12:23:50 -0400904// ListDevicePmConfigs returns pm configs of device
905func (dMgr *Manager) ListDevicePmConfigs(ctx context.Context, id *voltha.ID) (*voltha.PmConfigs, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530906 ctx = utils.WithRPCMetadataContext(ctx, "ListDevicePmConfigs")
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000907 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
Kent Hagerman45a13e42020-04-13 12:23:50 -0400908 agent := dMgr.getDeviceAgent(ctx, id.Id)
909 if agent == nil {
910 return nil, status.Errorf(codes.NotFound, "%s", id.Id)
khenaidoob3127472019-07-24 21:04:55 -0400911 }
Kent Hagerman45a13e42020-04-13 12:23:50 -0400912 return agent.listPmConfigs(ctx)
khenaidoob3127472019-07-24 21:04:55 -0400913}
914
Kent Hagerman2b216042020-04-03 18:28:56 -0400915func (dMgr *Manager) getSwitchCapability(ctx context.Context, deviceID string) (*ic.SwitchCapability, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530916 logger.Debugw(ctx, "get-switch-capability", log.Fields{"device-id": deviceID})
npujar467fe752020-01-16 20:17:45 +0530917 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
khenaidoob9203542018-09-17 22:56:37 -0400918 return agent.getSwitchCapability(ctx)
919 }
npujar1d86a522019-11-14 17:11:16 +0530920 return nil, status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoob9203542018-09-17 22:56:37 -0400921}
922
Kent Hagerman2b216042020-04-03 18:28:56 -0400923func (dMgr *Manager) GetPorts(ctx context.Context, deviceID string, portType voltha.Port_PortType) (*voltha.Ports, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530924 logger.Debugw(ctx, "get-ports", log.Fields{"device-id": deviceID, "port-type": portType})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400925 agent := dMgr.getDeviceAgent(ctx, deviceID)
926 if agent == nil {
927 return nil, status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoob9203542018-09-17 22:56:37 -0400928 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400929 return agent.getPorts(ctx, portType), nil
khenaidoob9203542018-09-17 22:56:37 -0400930}
931
Kent Hagerman2b216042020-04-03 18:28:56 -0400932func (dMgr *Manager) UpdateDeviceStatus(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-device-status", log.Fields{"device-id": deviceID, "oper-status": operStatus, "conn-status": connStatus})
npujar467fe752020-01-16 20:17:45 +0530934 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
935 return agent.updateDeviceStatus(ctx, operStatus, connStatus)
khenaidoo92e62c52018-10-03 14:02:54 -0400936 }
npujar1d86a522019-11-14 17:11:16 +0530937 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo92e62c52018-10-03 14:02:54 -0400938}
939
Kent Hagerman2b216042020-04-03 18:28:56 -0400940func (dMgr *Manager) UpdateChildrenStatus(ctx context.Context, deviceID string, operStatus voltha.OperStatus_Types, connStatus voltha.ConnectStatus_Types) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530941 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 -0400942 parentDevicePorts, err := dMgr.listDevicePorts(ctx, deviceID)
943 if err != nil {
khenaidoo4d4802d2018-10-04 21:59:49 -0400944 return status.Errorf(codes.Aborted, "%s", err.Error())
945 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400946 for childDeviceID := range dMgr.getAllChildDeviceIds(ctx, parentDevicePorts) {
npujar467fe752020-01-16 20:17:45 +0530947 if agent := dMgr.getDeviceAgent(ctx, childDeviceID); agent != nil {
948 if err = agent.updateDeviceStatus(ctx, operStatus, connStatus); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530949 return status.Errorf(codes.Aborted, "childDevice:%s, error:%s", childDeviceID, err.Error())
khenaidoo4d4802d2018-10-04 21:59:49 -0400950 }
951 }
952 }
953 return nil
954}
955
Kent Hagerman2b216042020-04-03 18:28:56 -0400956func (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 +0530957 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 +0530958 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
959 if err := agent.updatePortState(ctx, portType, portNo, operStatus); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530960 logger.Errorw(ctx, "updating-port-state-failed", log.Fields{"device-id": deviceID, "port-no": portNo, "error": err})
khenaidoo171b98e2019-10-31 11:48:15 -0400961 return err
962 }
963 // Notify the logical device manager to change the port state
Mahir Gunyel18fa0c92020-03-06 13:34:04 -0800964 // Do this for NNI and UNIs only. PON ports are not known by logical device
965 if portType == voltha.Port_ETHERNET_NNI || portType == voltha.Port_ETHERNET_UNI {
966 go func() {
Himani Chawlab4c25912020-11-12 17:16:38 +0530967 subCtx := utils.WithSpanAndRPCMetadataFromContext(ctx)
968 err := dMgr.logicalDeviceMgr.updatePortState(subCtx, deviceID, portNo, operStatus)
Mahir Gunyel18fa0c92020-03-06 13:34:04 -0800969 if err != nil {
970 // While we want to handle (catch) and log when
971 // an update to a port was not able to be
972 // propagated to the logical port, we can report
973 // it as a warning and not an error because it
974 // doesn't stop or modify processing.
975 // TODO: VOL-2707
Rohan Agrawal31f21802020-06-12 05:38:46 +0000976 logger.Warnw(ctx, "unable-to-update-logical-port-state", log.Fields{"error": err})
Mahir Gunyel18fa0c92020-03-06 13:34:04 -0800977 }
978 }()
979 }
khenaidoo442e7c72020-03-10 16:13:48 -0400980 return nil
khenaidoob9203542018-09-17 22:56:37 -0400981 }
npujar1d86a522019-11-14 17:11:16 +0530982 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoob9203542018-09-17 22:56:37 -0400983}
984
Kent Hagerman2b216042020-04-03 18:28:56 -0400985func (dMgr *Manager) DeleteAllPorts(ctx context.Context, deviceID string) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530986 logger.Debugw(ctx, "delete-all-ports", log.Fields{"device-id": deviceID})
npujar467fe752020-01-16 20:17:45 +0530987 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
988 if err := agent.deleteAllPorts(ctx); err != nil {
khenaidoo0a822f92019-05-08 15:15:57 -0400989 return err
990 }
991 // Notify the logical device manager to remove all logical ports, if needed.
Kent Hagerman2b216042020-04-03 18:28:56 -0400992 // At this stage the device itself may gave been deleted already at a DeleteAllPorts
khenaidoo0a822f92019-05-08 15:15:57 -0400993 // typically is part of a device deletion phase.
Kent Hagermancba2f302020-07-28 13:37:36 -0400994 if device, err := dMgr.getDeviceReadOnly(ctx, deviceID); err == nil {
npujar1d86a522019-11-14 17:11:16 +0530995 go func() {
Himani Chawlab4c25912020-11-12 17:16:38 +0530996 subCtx := utils.WithSpanAndRPCMetadataFromContext(ctx)
997 if err := dMgr.logicalDeviceMgr.deleteAllLogicalPorts(subCtx, device); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000998 logger.Errorw(ctx, "unable-to-delete-logical-ports", log.Fields{"error": err})
npujar1d86a522019-11-14 17:11:16 +0530999 }
1000 }()
khenaidoo0a822f92019-05-08 15:15:57 -04001001 } else {
divyadesaicb8b59d2020-08-18 09:55:47 +00001002 logger.Warnw(ctx, "failed-to-retrieve-device", log.Fields{"device-id": deviceID})
khenaidoo0a822f92019-05-08 15:15:57 -04001003 return err
1004 }
1005 return nil
1006 }
npujar1d86a522019-11-14 17:11:16 +05301007 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo0a822f92019-05-08 15:15:57 -04001008}
1009
Kent Hagerman2b216042020-04-03 18:28:56 -04001010//UpdatePortsState updates all ports on the device
Kent Hagerman2a07b862020-06-19 15:23:07 -04001011func (dMgr *Manager) UpdatePortsState(ctx context.Context, deviceID string, portTypeFilter uint32, state voltha.OperStatus_Types) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301012 logger.Debugw(ctx, "update-ports-state", log.Fields{"device-id": deviceID})
Kent Hagerman2a07b862020-06-19 15:23:07 -04001013 agent := dMgr.getDeviceAgent(ctx, deviceID)
1014 if agent == nil {
1015 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo3ab34882019-05-02 21:33:30 -04001016 }
Kent Hagerman2a07b862020-06-19 15:23:07 -04001017 if state != voltha.OperStatus_ACTIVE && state != voltha.OperStatus_UNKNOWN {
1018 return status.Error(codes.Unimplemented, "state-change-not-implemented")
1019 }
1020 if err := agent.updatePortsOperState(ctx, portTypeFilter, state); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +05301021 logger.Warnw(ctx, "update-ports-state-failed", log.Fields{"device-id": deviceID, "error": err})
Kent Hagerman2a07b862020-06-19 15:23:07 -04001022 return err
1023 }
1024 return nil
khenaidoo3ab34882019-05-02 21:33:30 -04001025}
1026
Kent Hagerman2b216042020-04-03 18:28:56 -04001027func (dMgr *Manager) ChildDeviceDetected(ctx context.Context, parentDeviceID string, parentPortNo int64, deviceType string,
npujar1d86a522019-11-14 17:11:16 +05301028 channelID int64, vendorID string, serialNumber string, onuID int64) (*voltha.Device, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301029 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 -07001030
npujar1d86a522019-11-14 17:11:16 +05301031 if deviceType == "" && vendorID != "" {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001032 logger.Debug(ctx, "device-type-is-nil-fetching-device-type")
Kent Hagerman45a13e42020-04-13 12:23:50 -04001033 deviceTypes, err := dMgr.adapterMgr.ListDeviceTypes(ctx, nil)
1034 if err != nil {
1035 return nil, err
1036 }
Kent Hagerman4f355f52020-03-30 16:01:33 -04001037 OLoop:
Kent Hagerman45a13e42020-04-13 12:23:50 -04001038 for _, dType := range deviceTypes.Items {
Kent Hagerman4f355f52020-03-30 16:01:33 -04001039 for _, v := range dType.VendorIds {
1040 if v == vendorID {
1041 deviceType = dType.Adapter
1042 break OLoop
Chaitrashree G S4b3fada2019-07-28 23:55:25 -07001043 }
1044 }
1045 }
1046 }
1047 //if no match found for the vendorid,report adapter with the custom error message
1048 if deviceType == "" {
Himani Chawlab4c25912020-11-12 17:16:38 +05301049 logger.Errorw(ctx, "failed-to-fetch-adapter-name ", log.Fields{"vendor-id": vendorID})
npujar1d86a522019-11-14 17:11:16 +05301050 return nil, status.Errorf(codes.NotFound, "%s", vendorID)
Chaitrashree G S4b3fada2019-07-28 23:55:25 -07001051 }
khenaidoob9203542018-09-17 22:56:37 -04001052
1053 // Create the ONU device
1054 childDevice := &voltha.Device{}
khenaidoob9203542018-09-17 22:56:37 -04001055 childDevice.Type = deviceType
npujar1d86a522019-11-14 17:11:16 +05301056 childDevice.ParentId = parentDeviceID
khenaidoob9203542018-09-17 22:56:37 -04001057 childDevice.ParentPortNo = uint32(parentPortNo)
npujar1d86a522019-11-14 17:11:16 +05301058 childDevice.VendorId = vendorID
Matt Jeanneret4e241952019-02-28 11:16:04 -05001059 childDevice.SerialNumber = serialNumber
khenaidoob9203542018-09-17 22:56:37 -04001060 childDevice.Root = false
khenaidoo6fdf0ba2018-11-02 14:38:33 -04001061
khenaidoo442e7c72020-03-10 16:13:48 -04001062 // Get parent device type
1063 pAgent := dMgr.getDeviceAgent(ctx, parentDeviceID)
1064 if pAgent == nil {
npujar1d86a522019-11-14 17:11:16 +05301065 return nil, status.Errorf(codes.NotFound, "%s", parentDeviceID)
khenaidoo6fdf0ba2018-11-02 14:38:33 -04001066 }
khenaidoo442e7c72020-03-10 16:13:48 -04001067 if pAgent.deviceType == "" {
1068 return nil, status.Errorf(codes.FailedPrecondition, "device Type not set %s", parentDeviceID)
1069 }
khenaidoo6fdf0ba2018-11-02 14:38:33 -04001070
npujar467fe752020-01-16 20:17:45 +05301071 if device, err := dMgr.GetChildDevice(ctx, parentDeviceID, serialNumber, onuID, parentPortNo); err == nil {
Himani Chawlab4c25912020-11-12 17:16:38 +05301072 logger.Warnw(ctx, "child-device-exists", log.Fields{"parent-device-id": parentDeviceID, "serial-number": serialNumber})
Mahir Gunyel6deaa242019-06-27 04:53:33 -07001073 return device, status.Errorf(codes.AlreadyExists, "%s", serialNumber)
Matt Jeanneret4e241952019-02-28 11:16:04 -05001074 }
1075
khenaidoo442e7c72020-03-10 16:13:48 -04001076 childDevice.ProxyAddress = &voltha.Device_ProxyAddress{DeviceId: parentDeviceID, DeviceType: pAgent.deviceType, ChannelId: uint32(channelID), OnuId: uint32(onuID)}
khenaidoob9203542018-09-17 22:56:37 -04001077
1078 // Create and start a device agent for that device
Mahir Gunyel03de0d32020-06-03 01:36:59 -07001079 agent := newAgent(dMgr.adapterProxy, childDevice, dMgr, dMgr.dbPath, dMgr.dProxy, dMgr.defaultTimeout)
khenaidoo7585a962021-06-10 16:15:38 -04001080 insertedChildDevice, err := agent.start(ctx, false, childDevice)
Scott Baker80678602019-11-14 16:57:36 -08001081 if err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001082 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 -08001083 return nil, err
1084 }
khenaidoo442e7c72020-03-10 16:13:48 -04001085 dMgr.addDeviceAgentToMap(agent)
khenaidoob9203542018-09-17 22:56:37 -04001086
1087 // Activate the child device
npujar467fe752020-01-16 20:17:45 +05301088 if agent = dMgr.getDeviceAgent(ctx, agent.deviceID); agent != nil {
npujar1d86a522019-11-14 17:11:16 +05301089 go func() {
Maninder9a1bc0d2020-10-26 11:34:02 +05301090 subCtx := utils.WithFromTopicMetadataFromContext(utils.WithSpanAndRPCMetadataFromContext(ctx), ctx)
Himani Chawlab4c25912020-11-12 17:16:38 +05301091 err := agent.enableDevice(subCtx)
npujar1d86a522019-11-14 17:11:16 +05301092 if err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001093 logger.Errorw(ctx, "unable-to-enable-device", log.Fields{"error": err})
npujar1d86a522019-11-14 17:11:16 +05301094 }
1095 }()
khenaidoob9203542018-09-17 22:56:37 -04001096 }
1097
Mahir Gunyel23bd8c72020-09-21 23:20:43 -07001098 return insertedChildDevice, nil
khenaidoob9203542018-09-17 22:56:37 -04001099}
1100
Kent Hagerman2b216042020-04-03 18:28:56 -04001101func (dMgr *Manager) packetOut(ctx context.Context, deviceID string, outPort uint32, packet *ofp.OfpPacketOut) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301102 logger.Debugw(ctx, "packet-out", log.Fields{"device-id": deviceID, "out-port": outPort})
npujar467fe752020-01-16 20:17:45 +05301103 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
1104 return agent.packetOut(ctx, outPort, packet)
khenaidoofdbad6e2018-11-06 22:26:38 -05001105 }
npujar1d86a522019-11-14 17:11:16 +05301106 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoofdbad6e2018-11-06 22:26:38 -05001107}
1108
npujar1d86a522019-11-14 17:11:16 +05301109// PacketIn receives packet from adapter
Kent Hagerman2b216042020-04-03 18:28:56 -04001110func (dMgr *Manager) PacketIn(ctx context.Context, deviceID string, port uint32, transactionID string, packet []byte) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301111 logger.Debugw(ctx, "packet-in", log.Fields{"device-id": deviceID, "port": port})
khenaidoofdbad6e2018-11-06 22:26:38 -05001112 // Get the logical device Id based on the deviceId
1113 var device *voltha.Device
1114 var err error
Kent Hagermancba2f302020-07-28 13:37:36 -04001115 if device, err = dMgr.getDeviceReadOnly(ctx, deviceID); err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +00001116 logger.Errorw(ctx, "device-not-found", log.Fields{"device-id": deviceID})
khenaidoofdbad6e2018-11-06 22:26:38 -05001117 return err
1118 }
khenaidoo43c82122018-11-22 18:38:28 -05001119 if !device.Root {
divyadesaicb8b59d2020-08-18 09:55:47 +00001120 logger.Errorw(ctx, "device-not-root", log.Fields{"device-id": deviceID})
npujar1d86a522019-11-14 17:11:16 +05301121 return status.Errorf(codes.FailedPrecondition, "%s", deviceID)
khenaidoofdbad6e2018-11-06 22:26:38 -05001122 }
1123
npujar467fe752020-01-16 20:17:45 +05301124 if err := dMgr.logicalDeviceMgr.packetIn(ctx, device.ParentId, port, transactionID, packet); err != nil {
khenaidoofdbad6e2018-11-06 22:26:38 -05001125 return err
1126 }
1127 return nil
1128}
1129
Kent Hagerman2b216042020-04-03 18:28:56 -04001130func (dMgr *Manager) setParentID(ctx context.Context, device *voltha.Device, parentID string) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301131 logger.Debugw(ctx, "set-parent-id", log.Fields{"device-id": device.Id, "parent-id": parentID})
npujar467fe752020-01-16 20:17:45 +05301132 if agent := dMgr.getDeviceAgent(ctx, device.Id); agent != nil {
1133 return agent.setParentID(ctx, device, parentID)
khenaidooad06fd72019-10-28 12:26:05 -04001134 }
1135 return status.Errorf(codes.NotFound, "%s", device.Id)
1136}
1137
Himani Chawlab4c25912020-11-12 17:16:38 +05301138//
1139//CreateLogicalDevice creates logical device in core
Kent Hagerman2b216042020-04-03 18:28:56 -04001140func (dMgr *Manager) CreateLogicalDevice(ctx context.Context, cDevice *voltha.Device) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301141 logger.Info(ctx, "create-logical-device")
khenaidoo59ef7be2019-06-21 12:40:28 -04001142 // Verify whether the logical device has already been created
1143 if cDevice.ParentId != "" {
Himani Chawlab4c25912020-11-12 17:16:38 +05301144 logger.Debugw(ctx, "parent-device-already-exist", log.Fields{"device-id": cDevice.Id, "logical-device-id": cDevice.Id})
khenaidoo59ef7be2019-06-21 12:40:28 -04001145 return nil
1146 }
khenaidoob9203542018-09-17 22:56:37 -04001147 var err error
npujar467fe752020-01-16 20:17:45 +05301148 if _, err = dMgr.logicalDeviceMgr.createLogicalDevice(ctx, cDevice); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +05301149 logger.Warnw(ctx, "create-logical-device-error", log.Fields{"device": cDevice})
khenaidoob9203542018-09-17 22:56:37 -04001150 return err
1151 }
khenaidoob9203542018-09-17 22:56:37 -04001152 return nil
1153}
1154
npujar1d86a522019-11-14 17:11:16 +05301155// DeleteLogicalDevice deletes logical device from core
Kent Hagerman2b216042020-04-03 18:28:56 -04001156func (dMgr *Manager) DeleteLogicalDevice(ctx context.Context, cDevice *voltha.Device) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301157 logger.Info(ctx, "delete-logical-device")
serkant.uluderyae25f6482020-12-17 21:08:38 +03001158 if err := dMgr.logicalDeviceMgr.deleteLogicalDevice(ctx, cDevice); err != nil {
khenaidoo92e62c52018-10-03 14:02:54 -04001159 return err
1160 }
1161 // Remove the logical device Id from the parent device
npujar1d86a522019-11-14 17:11:16 +05301162 logicalID := ""
npujar467fe752020-01-16 20:17:45 +05301163 dMgr.UpdateDeviceAttribute(ctx, cDevice.Id, "ParentId", logicalID)
khenaidoo92e62c52018-10-03 14:02:54 -04001164 return nil
1165}
1166
npujar1d86a522019-11-14 17:11:16 +05301167// DeleteLogicalPorts removes the logical ports associated with that deviceId
Kent Hagerman2b216042020-04-03 18:28:56 -04001168func (dMgr *Manager) DeleteLogicalPorts(ctx context.Context, cDevice *voltha.Device) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001169 logger.Debugw(ctx, "delete-all-logical-ports", log.Fields{"device-id": cDevice.Id})
khenaidoo442e7c72020-03-10 16:13:48 -04001170 if err := dMgr.logicalDeviceMgr.deleteLogicalPorts(ctx, cDevice.Id); err != nil {
khenaidooe132f522020-03-20 15:23:15 -04001171 // 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 +05301172 logger.Warnw(ctx, "delete-logical-ports-error", log.Fields{"device-id": cDevice.Id, "error": err})
khenaidoo0a822f92019-05-08 15:15:57 -04001173 }
1174 return nil
1175}
1176
Kent Hagerman2b216042020-04-03 18:28:56 -04001177func (dMgr *Manager) getParentDevice(ctx context.Context, childDevice *voltha.Device) *voltha.Device {
khenaidoo92e62c52018-10-03 14:02:54 -04001178 // Sanity check
1179 if childDevice.Root {
1180 // childDevice is the parent device
1181 return childDevice
1182 }
Kent Hagermancba2f302020-07-28 13:37:36 -04001183 parentDevice, _ := dMgr.getDeviceReadOnly(ctx, childDevice.ParentId)
khenaidoo92e62c52018-10-03 14:02:54 -04001184 return parentDevice
1185}
1186
Kent Hagerman2b216042020-04-03 18:28:56 -04001187//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 -04001188//cannot manage the child devices. This will trigger the Core to disable all the child devices.
Kent Hagerman2b216042020-04-03 18:28:56 -04001189func (dMgr *Manager) ChildDevicesLost(ctx context.Context, parentDeviceID string) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301190 logger.Debug(ctx, "child-devices-lost")
Kent Hagermancba2f302020-07-28 13:37:36 -04001191 parentDevice, err := dMgr.getDeviceReadOnly(ctx, parentDeviceID)
Kent Hagerman2a07b862020-06-19 15:23:07 -04001192 if err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +00001193 logger.Warnw(ctx, "failed-getting-device", log.Fields{"parent-device-id": parentDeviceID, "error": err})
khenaidoo0a822f92019-05-08 15:15:57 -04001194 return err
1195 }
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001196 return dMgr.DisableAllChildDevices(ctx, parentDevice)
khenaidoo0a822f92019-05-08 15:15:57 -04001197}
1198
Kent Hagerman2b216042020-04-03 18:28:56 -04001199//ChildDevicesDetected is invoked by an adapter when child devices are found, typically after after a
khenaidoo0a822f92019-05-08 15:15:57 -04001200// disable/enable sequence. This will trigger the Core to Enable all the child devices of that parent.
Kent Hagerman2b216042020-04-03 18:28:56 -04001201func (dMgr *Manager) ChildDevicesDetected(ctx context.Context, parentDeviceID string) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301202 logger.Debug(ctx, "child-devices-detected")
Kent Hagerman2a07b862020-06-19 15:23:07 -04001203 parentDevicePorts, err := dMgr.listDevicePorts(ctx, parentDeviceID)
1204 if err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +00001205 logger.Warnw(ctx, "failed-getting-device", log.Fields{"device-id": parentDeviceID, "error": err})
khenaidoo0a822f92019-05-08 15:15:57 -04001206 return err
1207 }
Kent Hagerman2a07b862020-06-19 15:23:07 -04001208 childDeviceIds := dMgr.getAllChildDeviceIds(ctx, parentDevicePorts)
khenaidoo0a822f92019-05-08 15:15:57 -04001209 if len(childDeviceIds) == 0 {
divyadesaicb8b59d2020-08-18 09:55:47 +00001210 logger.Debugw(ctx, "no-child-device", log.Fields{"parent-device-id": parentDeviceID})
khenaidoo0a822f92019-05-08 15:15:57 -04001211 }
khenaidoo59ef7be2019-06-21 12:40:28 -04001212 allChildEnableRequestSent := true
Kent Hagerman2a07b862020-06-19 15:23:07 -04001213 for childDeviceID := range childDeviceIds {
npujar467fe752020-01-16 20:17:45 +05301214 if agent := dMgr.getDeviceAgent(ctx, childDeviceID); agent != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +05301215 subCtx := utils.WithSpanAndRPCMetadataFromContext(ctx)
khenaidoo59ef7be2019-06-21 12:40:28 -04001216 // Run the children re-registration in its own routine
Kent Hagerman2a07b862020-06-19 15:23:07 -04001217 go func(ctx context.Context) {
1218 err = agent.enableDevice(ctx)
npujar1d86a522019-11-14 17:11:16 +05301219 if err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001220 logger.Errorw(ctx, "unable-to-enable-device", log.Fields{"error": err})
npujar1d86a522019-11-14 17:11:16 +05301221 }
Himani Chawlab4c25912020-11-12 17:16:38 +05301222 }(subCtx)
khenaidoo59ef7be2019-06-21 12:40:28 -04001223 } else {
npujar1d86a522019-11-14 17:11:16 +05301224 err = status.Errorf(codes.Unavailable, "no agent for child device %s", childDeviceID)
Himani Chawlab4c25912020-11-12 17:16:38 +05301225 logger.Errorw(ctx, "no-child-device-agent", log.Fields{"parent-device-id": parentDeviceID, "child-id": childDeviceID})
khenaidoo59ef7be2019-06-21 12:40:28 -04001226 allChildEnableRequestSent = false
khenaidoo0a822f92019-05-08 15:15:57 -04001227 }
1228 }
khenaidoo59ef7be2019-06-21 12:40:28 -04001229 if !allChildEnableRequestSent {
khenaidoo0a822f92019-05-08 15:15:57 -04001230 return err
1231 }
1232 return nil
1233}
1234
khenaidoo4d4802d2018-10-04 21:59:49 -04001235/*
1236All the functions below are callback functions where they are invoked with the latest and previous data. We can
1237therefore use the data as is without trying to get the latest from the model.
1238*/
1239
khenaidoo0a822f92019-05-08 15:15:57 -04001240//DisableAllChildDevices is invoked as a callback when the parent device is disabled
Kent Hagerman2b216042020-04-03 18:28:56 -04001241func (dMgr *Manager) DisableAllChildDevices(ctx context.Context, parentCurrDevice *voltha.Device) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301242 logger.Debug(ctx, "disable-all-child-devices")
Kent Hagerman2a07b862020-06-19 15:23:07 -04001243 ports, _ := dMgr.listDevicePorts(ctx, parentCurrDevice.Id)
1244 for childDeviceID := range dMgr.getAllChildDeviceIds(ctx, ports) {
npujar467fe752020-01-16 20:17:45 +05301245 if agent := dMgr.getDeviceAgent(ctx, childDeviceID); agent != nil {
Kent Hagerman2a07b862020-06-19 15:23:07 -04001246 if err := agent.disableDevice(ctx); err != nil {
khenaidooe132f522020-03-20 15:23:15 -04001247 // Just log the error - this error happens only if the child device was already in deleted state.
divyadesaicb8b59d2020-08-18 09:55:47 +00001248 logger.Errorw(ctx, "failure-disable-device", log.Fields{"device-id": childDeviceID, "error": err.Error()})
khenaidoo92e62c52018-10-03 14:02:54 -04001249 }
1250 }
1251 }
1252 return nil
1253}
1254
khenaidoo0a822f92019-05-08 15:15:57 -04001255//DeleteAllChildDevices is invoked as a callback when the parent device is deleted
Kent Hagerman2b216042020-04-03 18:28:56 -04001256func (dMgr *Manager) DeleteAllChildDevices(ctx context.Context, parentCurrDevice *voltha.Device) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301257 logger.Debug(ctx, "delete-all-child-devices")
Himani Chawla2ba1c9c2020-10-07 13:19:03 +05301258 force := false
1259 // Get the parent device Transient state, if its FORCE_DELETED(go for force delete for child devices)
1260 // So in cases when this handler is getting called other than DELETE operation, no force option would be used.
1261 agent := dMgr.getDeviceAgent(ctx, parentCurrDevice.Id)
1262 if agent == nil {
1263 return status.Errorf(codes.NotFound, "%s", parentCurrDevice.Id)
1264 }
1265
1266 force = agent.getTransientState() == voltha.DeviceTransientState_FORCE_DELETING
1267
Kent Hagerman2a07b862020-06-19 15:23:07 -04001268 ports, _ := dMgr.listDevicePorts(ctx, parentCurrDevice.Id)
1269 for childDeviceID := range dMgr.getAllChildDeviceIds(ctx, ports) {
npujar467fe752020-01-16 20:17:45 +05301270 if agent := dMgr.getDeviceAgent(ctx, childDeviceID); agent != nil {
Himani Chawla2ba1c9c2020-10-07 13:19:03 +05301271 if force {
1272 if err := agent.deleteDeviceForce(ctx); err != nil {
1273 logger.Warnw(ctx, "failure-delete-device-force", log.Fields{"device-id": childDeviceID,
1274 "error": err.Error()})
1275 }
1276 } else {
1277 if err := agent.deleteDevice(ctx); err != nil {
1278 logger.Warnw(ctx, "failure-delete-device", log.Fields{"device-id": childDeviceID,
1279 "error": err.Error()})
1280 }
khenaidoo4d4802d2018-10-04 21:59:49 -04001281 }
khenaidoo49085352020-01-13 19:15:43 -05001282 // No further action is required here. The deleteDevice will change the device state where the resulting
1283 // callback will take care of cleaning the child device agent.
khenaidoo4d4802d2018-10-04 21:59:49 -04001284 }
1285 }
khenaidoo4d4802d2018-10-04 21:59:49 -04001286 return nil
1287}
1288
Girish Gowdra408cd962020-03-11 14:31:31 -07001289//DeleteAllLogicalPorts is invoked as a callback when the parent device's connection status moves to UNREACHABLE
Kent Hagerman2b216042020-04-03 18:28:56 -04001290func (dMgr *Manager) DeleteAllLogicalPorts(ctx context.Context, parentDevice *voltha.Device) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001291 logger.Debugw(ctx, "delete-all-logical-ports", log.Fields{"parent-device-id": parentDevice.Id})
Girish Gowdra408cd962020-03-11 14:31:31 -07001292 if err := dMgr.logicalDeviceMgr.deleteAllLogicalPorts(ctx, parentDevice); err != nil {
khenaidooe132f522020-03-20 15:23:15 -04001293 // Just log error as logical device may already have been deleted
Rohan Agrawal31f21802020-06-12 05:38:46 +00001294 logger.Warnw(ctx, "delete-all-logical-ports-fail", log.Fields{"parent-device-id": parentDevice.Id, "error": err})
Girish Gowdra408cd962020-03-11 14:31:31 -07001295 }
1296 return nil
1297}
1298
1299//DeleteAllDeviceFlows is invoked as a callback when the parent device's connection status moves to UNREACHABLE
Kent Hagerman2b216042020-04-03 18:28:56 -04001300func (dMgr *Manager) DeleteAllDeviceFlows(ctx context.Context, parentDevice *voltha.Device) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001301 logger.Debugw(ctx, "delete-all-device-flows", log.Fields{"parent-device-id": parentDevice.Id})
Girish Gowdra408cd962020-03-11 14:31:31 -07001302 if agent := dMgr.getDeviceAgent(ctx, parentDevice.Id); agent != nil {
1303 if err := agent.deleteAllFlows(ctx); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001304 logger.Errorw(ctx, "error-deleting-all-device-flows", log.Fields{"parent-device-id": parentDevice.Id})
Girish Gowdra408cd962020-03-11 14:31:31 -07001305 return err
1306 }
1307 return nil
1308 }
1309 return status.Errorf(codes.NotFound, "%s", parentDevice.Id)
1310}
1311
khenaidoo4d4802d2018-10-04 21:59:49 -04001312//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 -04001313func (dMgr *Manager) getAllChildDeviceIds(ctx context.Context, parentDevicePorts map[uint32]*voltha.Port) map[string]struct{} {
Himani Chawlab4c25912020-11-12 17:16:38 +05301314 logger.Debug(ctx, "get-all-child-device-ids")
Kent Hagerman2a07b862020-06-19 15:23:07 -04001315 childDeviceIds := make(map[string]struct{}, len(parentDevicePorts))
1316 for _, port := range parentDevicePorts {
1317 for _, peer := range port.Peers {
1318 childDeviceIds[peer.DeviceId] = struct{}{}
khenaidoo92e62c52018-10-03 14:02:54 -04001319 }
1320 }
Kent Hagerman2a07b862020-06-19 15:23:07 -04001321 logger.Debugw(ctx, "returning-getAllChildDeviceIds", log.Fields{"childDeviceIds": childDeviceIds})
1322 return childDeviceIds
khenaidoo92e62c52018-10-03 14:02:54 -04001323}
1324
Kent Hagerman2b216042020-04-03 18:28:56 -04001325//GetAllChildDevices is a helper method to get all the child device IDs from the device passed as parameter
1326func (dMgr *Manager) GetAllChildDevices(ctx context.Context, parentDeviceID string) (*voltha.Devices, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301327 logger.Debugw(ctx, "get-all-child-devices", log.Fields{"parent-device-id": parentDeviceID})
Kent Hagerman2a07b862020-06-19 15:23:07 -04001328 if parentDevicePorts, err := dMgr.listDevicePorts(ctx, parentDeviceID); err == nil {
khenaidoo297cd252019-02-07 22:10:23 -05001329 childDevices := make([]*voltha.Device, 0)
Kent Hagerman2a07b862020-06-19 15:23:07 -04001330 for deviceID := range dMgr.getAllChildDeviceIds(ctx, parentDevicePorts) {
Kent Hagermancba2f302020-07-28 13:37:36 -04001331 if d, e := dMgr.getDeviceReadOnly(ctx, deviceID); e == nil && d != nil {
Kent Hagerman2a07b862020-06-19 15:23:07 -04001332 childDevices = append(childDevices, d)
khenaidoo297cd252019-02-07 22:10:23 -05001333 }
1334 }
1335 return &voltha.Devices{Items: childDevices}, nil
1336 }
npujar1d86a522019-11-14 17:11:16 +05301337 return nil, status.Errorf(codes.NotFound, "%s", parentDeviceID)
khenaidoo297cd252019-02-07 22:10:23 -05001338}
1339
npujar1d86a522019-11-14 17:11:16 +05301340// SetupUNILogicalPorts creates UNI ports on the logical device that represents a child UNI interface
Kent Hagerman2b216042020-04-03 18:28:56 -04001341func (dMgr *Manager) SetupUNILogicalPorts(ctx context.Context, cDevice *voltha.Device) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301342 logger.Info(ctx, "setup-uni-logical-ports")
Kent Hagerman2a07b862020-06-19 15:23:07 -04001343 cDevicePorts, err := dMgr.listDevicePorts(ctx, cDevice.Id)
1344 if err != nil {
1345 return err
1346 }
1347 if err := dMgr.logicalDeviceMgr.setupUNILogicalPorts(ctx, cDevice, cDevicePorts); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +05301348 logger.Warnw(ctx, "setup-uni-logical-ports-error", log.Fields{"device": cDevice, "err": err})
khenaidoob9203542018-09-17 22:56:37 -04001349 return err
1350 }
1351 return nil
1352}
1353
Kent Hagerman45a13e42020-04-13 12:23:50 -04001354// convenience to avoid redefining
1355var operationFailureResp = &common.OperationResp{Code: voltha.OperationResp_OPERATION_FAILURE}
1356
1357// DownloadImage execute an image download request
1358func (dMgr *Manager) DownloadImage(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301359 ctx = utils.WithRPCMetadataContext(ctx, "DownloadImage")
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001360 log.EnrichSpan(ctx, log.Fields{"device-id": img.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +05301361 logger.Debugw(ctx, "download-image", log.Fields{"device-id": img.Id, "image-name": img.Name})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001362 agent := dMgr.getDeviceAgent(ctx, img.Id)
1363 if agent == nil {
1364 return operationFailureResp, status.Errorf(codes.NotFound, "%s", img.Id)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001365 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001366 resp, err := agent.downloadImage(ctx, img)
1367 if err != nil {
1368 return operationFailureResp, err
1369 }
1370 return resp, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001371}
1372
Kent Hagerman45a13e42020-04-13 12:23:50 -04001373// CancelImageDownload cancels image download request
1374func (dMgr *Manager) CancelImageDownload(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301375 ctx = utils.WithRPCMetadataContext(ctx, "CancelImageDownload")
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001376 log.EnrichSpan(ctx, log.Fields{"device-id": img.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +05301377 logger.Debugw(ctx, "cancel-image-download", log.Fields{"device-id": img.Id, "image-name": img.Name})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001378 agent := dMgr.getDeviceAgent(ctx, img.Id)
1379 if agent == nil {
1380 return operationFailureResp, status.Errorf(codes.NotFound, "%s", img.Id)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001381 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001382 resp, err := agent.cancelImageDownload(ctx, img)
1383 if err != nil {
1384 return operationFailureResp, err
1385 }
1386 return resp, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001387}
1388
Kent Hagerman45a13e42020-04-13 12:23:50 -04001389// ActivateImageUpdate activates image update request
1390func (dMgr *Manager) ActivateImageUpdate(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301391 ctx = utils.WithRPCMetadataContext(ctx, "ActivateImageUpdate")
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001392 log.EnrichSpan(ctx, log.Fields{"device-id": img.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +05301393 logger.Debugw(ctx, "activate-image-update", log.Fields{"device-id": img.Id, "image-name": img.Name})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001394 agent := dMgr.getDeviceAgent(ctx, img.Id)
1395 if agent == nil {
1396 return operationFailureResp, status.Errorf(codes.NotFound, "%s", img.Id)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001397 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001398 resp, err := agent.activateImage(ctx, img)
1399 if err != nil {
1400 return operationFailureResp, err
1401 }
1402 return resp, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001403}
1404
Kent Hagerman45a13e42020-04-13 12:23:50 -04001405// RevertImageUpdate reverts image update
1406func (dMgr *Manager) RevertImageUpdate(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301407 ctx = utils.WithRPCMetadataContext(ctx, "RevertImageUpdate")
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001408 log.EnrichSpan(ctx, log.Fields{"device-id": img.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +05301409 logger.Debugw(ctx, "rever-image-update", log.Fields{"device-id": img.Id, "image-name": img.Name})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001410 agent := dMgr.getDeviceAgent(ctx, img.Id)
1411 if agent == nil {
1412 return operationFailureResp, status.Errorf(codes.NotFound, "%s", img.Id)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001413 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001414 resp, err := agent.revertImage(ctx, img)
1415 if err != nil {
1416 return operationFailureResp, err
1417 }
1418 return resp, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001419}
1420
Kent Hagerman45a13e42020-04-13 12:23:50 -04001421// convenience to avoid redefining
1422var imageDownloadFailureResp = &voltha.ImageDownload{DownloadState: voltha.ImageDownload_DOWNLOAD_UNKNOWN}
1423
1424// GetImageDownloadStatus returns status of image download
1425func (dMgr *Manager) GetImageDownloadStatus(ctx context.Context, img *voltha.ImageDownload) (*voltha.ImageDownload, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301426 ctx = utils.WithRPCMetadataContext(ctx, "GetImageDownloadStatus")
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001427 log.EnrichSpan(ctx, log.Fields{"device-id": img.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +05301428 logger.Debugw(ctx, "get-image-download-status", log.Fields{"device-id": img.Id, "image-name": img.Name})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001429 agent := dMgr.getDeviceAgent(ctx, img.Id)
1430 if agent == nil {
1431 return imageDownloadFailureResp, status.Errorf(codes.NotFound, "%s", img.Id)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001432 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001433 resp, err := agent.getImageDownloadStatus(ctx, img)
1434 if err != nil {
1435 return imageDownloadFailureResp, err
1436 }
1437 return resp, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001438}
1439
Kent Hagerman2b216042020-04-03 18:28:56 -04001440func (dMgr *Manager) UpdateImageDownload(ctx context.Context, deviceID string, img *voltha.ImageDownload) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301441 ctx = utils.WithRPCMetadataContext(ctx, "UpdateImageDownload")
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001442 log.EnrichSpan(ctx, log.Fields{"device-id": img.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +05301443 logger.Debugw(ctx, "update-image-download", log.Fields{"device-id": img.Id, "image-name": img.Name})
npujar467fe752020-01-16 20:17:45 +05301444 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
1445 if err := agent.updateImageDownload(ctx, img); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +05301446 logger.Debugw(ctx, "update-image-download-failed", log.Fields{"err": err, "image-name": img.Name})
khenaidoof5a5bfa2019-01-23 22:20:29 -05001447 return err
1448 }
1449 } else {
1450 return status.Errorf(codes.NotFound, "%s", img.Id)
1451 }
1452 return nil
1453}
1454
Kent Hagerman45a13e42020-04-13 12:23:50 -04001455// GetImageDownload returns image download
Kent Hagerman2b216042020-04-03 18:28:56 -04001456func (dMgr *Manager) GetImageDownload(ctx context.Context, img *voltha.ImageDownload) (*voltha.ImageDownload, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301457 ctx = utils.WithRPCMetadataContext(ctx, "GetImageDownload")
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001458 log.EnrichSpan(ctx, log.Fields{"device-id": img.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +05301459 logger.Debugw(ctx, "get-image-download", log.Fields{"device-id": img.Id, "image-name": img.Name})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001460 agent := dMgr.getDeviceAgent(ctx, img.Id)
1461 if agent == nil {
1462 return imageDownloadFailureResp, status.Errorf(codes.NotFound, "%s", img.Id)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001463 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001464 resp, err := agent.getImageDownload(ctx, img)
1465 if err != nil {
1466 return imageDownloadFailureResp, err
1467 }
1468 return resp, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001469}
1470
Kent Hagerman45a13e42020-04-13 12:23:50 -04001471// ListImageDownloads returns image downloads
1472func (dMgr *Manager) ListImageDownloads(ctx context.Context, id *voltha.ID) (*voltha.ImageDownloads, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301473 ctx = utils.WithRPCMetadataContext(ctx, "ListImageDownloads")
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001474 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +05301475 logger.Debugw(ctx, "list-image-downloads", log.Fields{"device-id": id.Id})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001476 agent := dMgr.getDeviceAgent(ctx, id.Id)
1477 if agent == nil {
1478 return &voltha.ImageDownloads{Items: []*voltha.ImageDownload{imageDownloadFailureResp}}, status.Errorf(codes.NotFound, "%s", id.Id)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001479 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001480 resp, err := agent.listImageDownloads(ctx, id.Id)
1481 if err != nil {
1482 return &voltha.ImageDownloads{Items: []*voltha.ImageDownload{imageDownloadFailureResp}}, err
1483 }
1484 return resp, nil
1485}
1486
1487// GetImages returns all images for a specific device entry
1488func (dMgr *Manager) GetImages(ctx context.Context, id *voltha.ID) (*voltha.Images, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301489 ctx = utils.WithRPCMetadataContext(ctx, "GetImages")
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001490 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +05301491 logger.Debugw(ctx, "get-images", log.Fields{"device-id": id.Id})
Kent Hagermancba2f302020-07-28 13:37:36 -04001492 device, err := dMgr.getDeviceReadOnly(ctx, id.Id)
Kent Hagerman45a13e42020-04-13 12:23:50 -04001493 if err != nil {
1494 return nil, err
1495 }
Kent Hagermancba2f302020-07-28 13:37:36 -04001496 return device.Images, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001497}
1498
Rohan Agrawal31f21802020-06-12 05:38:46 +00001499func (dMgr *Manager) NotifyInvalidTransition(ctx context.Context, device *voltha.Device) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301500 logger.Errorw(ctx, "notify-invalid-transition", log.Fields{
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001501 "device": device.Id,
1502 "curr-admin-state": device.AdminState,
1503 "curr-oper-state": device.OperStatus,
1504 "curr-conn-state": device.ConnectStatus,
Stephane Barbarieef6650d2019-07-18 12:15:09 -04001505 })
khenaidoo0a822f92019-05-08 15:15:57 -04001506 //TODO: notify over kafka?
1507 return nil
1508}
1509
npujar1d86a522019-11-14 17:11:16 +05301510// UpdateDeviceAttribute updates value of particular device attribute
Kent Hagerman2b216042020-04-03 18:28:56 -04001511func (dMgr *Manager) UpdateDeviceAttribute(ctx context.Context, deviceID string, attribute string, value interface{}) {
npujar1d86a522019-11-14 17:11:16 +05301512 if agent, ok := dMgr.deviceAgents.Load(deviceID); ok {
Kent Hagerman2b216042020-04-03 18:28:56 -04001513 agent.(*Agent).updateDeviceAttribute(ctx, attribute, value)
khenaidoob9203542018-09-17 22:56:37 -04001514 }
1515}
1516
npujar1d86a522019-11-14 17:11:16 +05301517// GetParentDeviceID returns parent device id, either from memory or from the dB, if present
Kent Hagerman2b216042020-04-03 18:28:56 -04001518func (dMgr *Manager) GetParentDeviceID(ctx context.Context, deviceID string) string {
Kent Hagermancba2f302020-07-28 13:37:36 -04001519 if device, _ := dMgr.getDeviceReadOnly(ctx, deviceID); device != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +05301520 logger.Infow(ctx, "get-parent-device-id", log.Fields{"device-id": device.Id, "parent-id": device.ParentId})
khenaidoo4c9e5592019-09-09 16:20:41 -04001521 return device.ParentId
khenaidoob9203542018-09-17 22:56:37 -04001522 }
khenaidoo4c9e5592019-09-09 16:20:41 -04001523 return ""
khenaidoob9203542018-09-17 22:56:37 -04001524}
serkant.uluderya334479d2019-04-10 08:26:15 -07001525
Kent Hagerman45a13e42020-04-13 12:23:50 -04001526func (dMgr *Manager) SimulateAlarm(ctx context.Context, simulateReq *voltha.SimulateAlarmRequest) (*common.OperationResp, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301527 ctx = utils.WithRPCMetadataContext(ctx, "SimulateAlarm")
1528 logger.Debugw(ctx, "simulate-alarm", log.Fields{"id": simulateReq.Id, "indicator": simulateReq.Indicator, "intf-id": simulateReq.IntfId,
1529 "port-type-name": simulateReq.PortTypeName, "onu-device-id": simulateReq.OnuDeviceId, "inverse-bit-error-rate": simulateReq.InverseBitErrorRate,
1530 "drift": simulateReq.Drift, "new-eqd": simulateReq.NewEqd, "onu-serial-number": simulateReq.OnuSerialNumber, "operation": simulateReq.Operation})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001531 agent := dMgr.getDeviceAgent(ctx, simulateReq.Id)
1532 if agent == nil {
1533 return nil, status.Errorf(codes.NotFound, "%s", simulateReq.Id)
serkant.uluderya334479d2019-04-10 08:26:15 -07001534 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001535 if err := agent.simulateAlarm(ctx, simulateReq); err != nil {
1536 return nil, err
1537 }
1538 return &common.OperationResp{Code: common.OperationResp_OPERATION_SUCCESS}, nil
serkant.uluderya334479d2019-04-10 08:26:15 -07001539}
Mahir Gunyelfdee9212019-10-16 16:52:21 -07001540
Kent Hagerman2b216042020-04-03 18:28:56 -04001541func (dMgr *Manager) UpdateDeviceReason(ctx context.Context, deviceID string, reason string) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301542 logger.Debugw(ctx, "update-device-reason", log.Fields{"device-id": deviceID, "reason": reason})
npujar467fe752020-01-16 20:17:45 +05301543 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
1544 return agent.updateDeviceReason(ctx, reason)
Mahir Gunyelfdee9212019-10-16 16:52:21 -07001545 }
npujar1d86a522019-11-14 17:11:16 +05301546 return status.Errorf(codes.NotFound, "%s", deviceID)
Mahir Gunyelfdee9212019-10-16 16:52:21 -07001547}
kesavandbc2d1622020-01-21 00:42:01 -05001548
Kent Hagerman45a13e42020-04-13 12:23:50 -04001549func (dMgr *Manager) EnablePort(ctx context.Context, port *voltha.Port) (*empty.Empty, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301550 ctx = utils.WithRPCMetadataContext(ctx, "EnablePort")
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001551 log.EnrichSpan(ctx, log.Fields{"device-id": port.DeviceId})
Himani Chawlab4c25912020-11-12 17:16:38 +05301552 logger.Debugw(ctx, "enable-port", log.Fields{"device-id": port.DeviceId, "port-no": port.PortNo})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001553 agent := dMgr.getDeviceAgent(ctx, port.DeviceId)
1554 if agent == nil {
1555 return nil, status.Errorf(codes.NotFound, "%s", port.DeviceId)
kesavandbc2d1622020-01-21 00:42:01 -05001556 }
Kent Hagerman2a07b862020-06-19 15:23:07 -04001557 return &empty.Empty{}, agent.enablePort(ctx, port.PortNo)
kesavandbc2d1622020-01-21 00:42:01 -05001558}
1559
Kent Hagerman45a13e42020-04-13 12:23:50 -04001560func (dMgr *Manager) DisablePort(ctx context.Context, port *voltha.Port) (*empty.Empty, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301561 ctx = utils.WithRPCMetadataContext(ctx, "DisablePort")
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001562 log.EnrichSpan(ctx, log.Fields{"device-id": port.DeviceId})
Himani Chawlab4c25912020-11-12 17:16:38 +05301563 logger.Debugw(ctx, "disable-port", log.Fields{"device-id": port.DeviceId, "port-no": port.PortNo})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001564 agent := dMgr.getDeviceAgent(ctx, port.DeviceId)
1565 if agent == nil {
1566 return nil, status.Errorf(codes.NotFound, "%s", port.DeviceId)
kesavandbc2d1622020-01-21 00:42:01 -05001567 }
Kent Hagerman2a07b862020-06-19 15:23:07 -04001568 return &empty.Empty{}, agent.disablePort(ctx, port.PortNo)
kesavandbc2d1622020-01-21 00:42:01 -05001569}
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001570
Kent Hagerman2b216042020-04-03 18:28:56 -04001571// ChildDeviceLost calls parent adapter to delete child device and all its references
1572func (dMgr *Manager) ChildDeviceLost(ctx context.Context, curr *voltha.Device) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301573 logger.Debugw(ctx, "child-device-lost", log.Fields{"child-device-id": curr.Id, "parent-device-id": curr.ParentId})
khenaidoo442e7c72020-03-10 16:13:48 -04001574 if parentAgent := dMgr.getDeviceAgent(ctx, curr.ParentId); parentAgent != nil {
khenaidooe132f522020-03-20 15:23:15 -04001575 if err := parentAgent.ChildDeviceLost(ctx, curr); err != nil {
1576 // Just log the message and let the remaining pipeline proceed.
Rohan Agrawal31f21802020-06-12 05:38:46 +00001577 logger.Warnw(ctx, "childDeviceLost", log.Fields{"child-device-id": curr.Id, "parent-device-id": curr.ParentId, "error": err})
khenaidooe132f522020-03-20 15:23:15 -04001578 }
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001579 }
khenaidooe132f522020-03-20 15:23:15 -04001580 // Do not return an error as parent device may also have been deleted. Let the remaining pipeline proceed.
1581 return nil
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001582}
onkarkundargi87285252020-01-27 11:34:52 +05301583
Kent Hagerman45a13e42020-04-13 12:23:50 -04001584func (dMgr *Manager) StartOmciTestAction(ctx context.Context, request *voltha.OmciTestRequest) (*voltha.TestResponse, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301585 ctx = utils.WithRPCMetadataContext(ctx, "StartOmciTestAction")
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001586 log.EnrichSpan(ctx, log.Fields{"device-id": request.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +05301587 logger.Debugw(ctx, "start-omci-test-action", log.Fields{"device-id": request.Id, "uuid": request.Uuid})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001588 agent := dMgr.getDeviceAgent(ctx, request.Id)
1589 if agent == nil {
1590 return nil, status.Errorf(codes.NotFound, "%s", request.Id)
onkarkundargi87285252020-01-27 11:34:52 +05301591 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001592 return agent.startOmciTest(ctx, request)
onkarkundargi87285252020-01-27 11:34:52 +05301593}
Dinesh Belwalkarc1129f12020-02-27 10:41:33 -08001594
1595func (dMgr *Manager) GetExtValue(ctx context.Context, value *voltha.ValueSpecifier) (*voltha.ReturnValues, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301596 ctx = utils.WithRPCMetadataContext(ctx, "GetExtValue")
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001597 log.EnrichSpan(ctx, log.Fields{"device-id": value.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +05301598 logger.Debugw(ctx, "get-ext-value", log.Fields{"onu-id": value.Id})
Kent Hagermancba2f302020-07-28 13:37:36 -04001599 cDevice, err := dMgr.getDeviceReadOnly(ctx, value.Id)
Dinesh Belwalkarc1129f12020-02-27 10:41:33 -08001600 if err != nil {
1601 return nil, status.Errorf(codes.Aborted, "%s", err.Error())
1602 }
Kent Hagermancba2f302020-07-28 13:37:36 -04001603 pDevice, err := dMgr.getDeviceReadOnly(ctx, cDevice.ParentId)
Dinesh Belwalkarc1129f12020-02-27 10:41:33 -08001604 if err != nil {
1605 return nil, status.Errorf(codes.Aborted, "%s", err.Error())
1606 }
1607 if agent := dMgr.getDeviceAgent(ctx, cDevice.ParentId); agent != nil {
1608 resp, err := agent.getExtValue(ctx, pDevice, cDevice, value)
1609 if err != nil {
1610 return nil, err
1611 }
Himani Chawlab4c25912020-11-12 17:16:38 +05301612 logger.Debugw(ctx, "get-ext-value-result", log.Fields{"result": resp})
Dinesh Belwalkarc1129f12020-02-27 10:41:33 -08001613 return resp, nil
1614 }
1615 return nil, status.Errorf(codes.NotFound, "%s", value.Id)
1616
1617}
dpaul62686312020-06-23 14:17:36 +05301618
1619// SetExtValue set some given configs or value
1620func (dMgr *Manager) SetExtValue(ctx context.Context, value *voltha.ValueSet) (*empty.Empty, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301621 ctx = utils.WithRPCMetadataContext(ctx, "SetExtValue")
1622 logger.Debugw(ctx, "set-ext-value", log.Fields{"onu-id": value.Id})
dpaul62686312020-06-23 14:17:36 +05301623 device, err := dMgr.getDeviceReadOnly(ctx, value.Id)
1624 if err != nil {
1625 return nil, status.Errorf(codes.Aborted, "%s", err.Error())
1626 }
1627 if agent := dMgr.getDeviceAgent(ctx, device.Id); agent != nil {
1628 resp, err := agent.setExtValue(ctx, device, value)
1629 if err != nil {
1630 return nil, err
1631 }
Himani Chawlab4c25912020-11-12 17:16:38 +05301632 logger.Debugw(ctx, "set-ext-value-result", log.Fields{"result": resp})
dpaul62686312020-06-23 14:17:36 +05301633 return resp, nil
1634 }
1635 return nil, status.Errorf(codes.NotFound, "%s", value.Id)
1636
1637}
Himani Chawlab4c25912020-11-12 17:16:38 +05301638
1639func (dMgr *Manager) SendRPCEvent(ctx context.Context, id string, rpcEvent *voltha.RPCEvent,
1640 category voltha.EventCategory_Types, subCategory *voltha.EventSubCategory_Types, raisedTs int64) {
1641 //TODO Instead of directly sending to the kafka bus, queue the message and send it asynchronously
Mahir Gunyelb0343bf2021-05-11 14:14:26 -07001642 dMgr.Agent.SendRPCEvent(ctx, id, rpcEvent, category, subCategory, raisedTs)
Himani Chawlab4c25912020-11-12 17:16:38 +05301643}
Manindera496f852021-02-22 09:57:56 +05301644
1645func (dMgr *Manager) GetTransientState(ctx context.Context, id string) (voltha.DeviceTransientState_Types, error) {
1646 agent := dMgr.getDeviceAgent(ctx, id)
1647 if agent == nil {
1648 return voltha.DeviceTransientState_NONE, status.Errorf(codes.NotFound, "%s", id)
1649 }
1650 return agent.getTransientState(), nil
1651}
ssiddiquif076cb82021-04-23 10:47:04 +05301652
1653func (dMgr *Manager) DownloadImageToDevice(ctx context.Context, request *voltha.DeviceImageDownloadRequest) (*voltha.DeviceImageResponse, error) {
1654 if err := dMgr.validateImageDownloadRequest(request); err != nil {
1655 return nil, err
1656 }
1657
1658 ctx = utils.WithRPCMetadataContext(ctx, "DownloadImageToDevice")
1659 respCh := make(chan []*voltha.DeviceImageState, len(request.GetDeviceId()))
1660
ssiddiquif076cb82021-04-23 10:47:04 +05301661 for index, deviceID := range request.DeviceId {
ssiddiqui6bd4de02021-06-08 12:04:17 +05301662 // Create download request per device
1663 downloadReq := &voltha.DeviceImageDownloadRequest{
1664 Image: request.Image,
1665 ActivateOnSuccess: request.ActivateOnSuccess,
1666 CommitOnSuccess: request.CommitOnSuccess,
1667 }
1668
ssiddiquif076cb82021-04-23 10:47:04 +05301669 //slice-out only single deviceID from the request
1670 downloadReq.DeviceId = request.DeviceId[index : index+1]
1671
1672 go func(deviceID string, req *voltha.DeviceImageDownloadRequest, ch chan []*voltha.DeviceImageState) {
1673 agent := dMgr.getDeviceAgent(ctx, deviceID)
1674 if agent == nil {
ssiddiquib2f526c2021-10-11 17:11:25 +05301675 logger.Errorw(ctx, "Device-agent-not-found", log.Fields{"device-id": deviceID})
1676 ch <- []*voltha.DeviceImageState{{
1677 DeviceId: deviceID,
1678 ImageState: &voltha.ImageState{
1679 Version: req.GetImage().GetVersion(),
1680 DownloadState: voltha.ImageState_DOWNLOAD_FAILED,
1681 Reason: voltha.ImageState_UNKNOWN_ERROR,
1682 ImageState: voltha.ImageState_IMAGE_UNKNOWN,
1683 },
1684 }}
ssiddiquif076cb82021-04-23 10:47:04 +05301685 return
1686 }
1687
1688 resp, err := agent.downloadImageToDevice(ctx, req)
1689 if err != nil {
1690 logger.Errorw(ctx, "download-image-to-device-failed", log.Fields{"device-id": deviceID, "error": err})
ssiddiquib2f526c2021-10-11 17:11:25 +05301691 ch <- []*voltha.DeviceImageState{{
1692 DeviceId: deviceID,
1693 ImageState: &voltha.ImageState{
1694 Version: req.GetImage().GetVersion(),
1695 DownloadState: voltha.ImageState_DOWNLOAD_FAILED,
1696 Reason: voltha.ImageState_UNKNOWN_ERROR,
1697 ImageState: voltha.ImageState_IMAGE_UNKNOWN,
1698 },
1699 }}
ssiddiquif076cb82021-04-23 10:47:04 +05301700 return
1701 }
1702
1703 err = dMgr.validateDeviceImageResponse(resp)
1704 if err != nil {
1705 logger.Errorw(ctx, "download-image-to-device-failed", log.Fields{"device-id": deviceID, "error": err})
ssiddiquib2f526c2021-10-11 17:11:25 +05301706 ch <- []*voltha.DeviceImageState{{
1707 DeviceId: deviceID,
1708 ImageState: &voltha.ImageState{
1709 Version: req.GetImage().GetVersion(),
1710 DownloadState: voltha.ImageState_DOWNLOAD_FAILED,
1711 Reason: voltha.ImageState_UNKNOWN_ERROR,
1712 ImageState: voltha.ImageState_IMAGE_UNKNOWN,
1713 },
1714 }}
ssiddiquif076cb82021-04-23 10:47:04 +05301715 return
1716 }
1717 ch <- resp.GetDeviceImageStates()
1718 }(deviceID.GetId(), downloadReq, respCh)
1719
1720 }
1721
1722 return dMgr.waitForAllResponses(ctx, "download-image-to-device", respCh, len(request.GetDeviceId()))
1723}
1724
1725func (dMgr *Manager) GetImageStatus(ctx context.Context, request *voltha.DeviceImageRequest) (*voltha.DeviceImageResponse, error) {
1726 if err := dMgr.validateImageRequest(request); err != nil {
1727 return nil, err
1728 }
1729
1730 ctx = utils.WithRPCMetadataContext(ctx, "GetImageStatus")
1731
ssiddiquif076cb82021-04-23 10:47:04 +05301732 respCh := make(chan []*voltha.DeviceImageState, len(request.GetDeviceId()))
1733 for index, deviceID := range request.DeviceId {
ssiddiqui6bd4de02021-06-08 12:04:17 +05301734 // Create status request per device
1735 imageStatusReq := &voltha.DeviceImageRequest{
1736 Version: request.Version,
1737 CommitOnSuccess: request.CommitOnSuccess,
1738 }
1739
ssiddiquif076cb82021-04-23 10:47:04 +05301740 //slice-out only single deviceID from the request
1741 imageStatusReq.DeviceId = request.DeviceId[index : index+1]
1742
1743 go func(deviceID string, req *voltha.DeviceImageRequest, ch chan []*voltha.DeviceImageState) {
1744 agent := dMgr.getDeviceAgent(ctx, deviceID)
1745 if agent == nil {
ssiddiquib2f526c2021-10-11 17:11:25 +05301746 logger.Errorw(ctx, "Device-agent-not-found", log.Fields{"device-id": deviceID})
1747 ch <- []*voltha.DeviceImageState{{
1748 DeviceId: deviceID,
1749 ImageState: &voltha.ImageState{
1750 Version: request.GetVersion(),
1751 DownloadState: voltha.ImageState_DOWNLOAD_UNKNOWN,
1752 Reason: voltha.ImageState_UNKNOWN_ERROR,
1753 ImageState: voltha.ImageState_IMAGE_UNKNOWN,
1754 },
1755 }}
ssiddiquif076cb82021-04-23 10:47:04 +05301756 return
1757 }
1758
1759 resp, err := agent.getImageStatus(ctx, req)
1760 if err != nil {
1761 logger.Errorw(ctx, "get-image-status-failed", log.Fields{"device-id": deviceID, "error": err})
ssiddiquib2f526c2021-10-11 17:11:25 +05301762 ch <- []*voltha.DeviceImageState{{
1763 DeviceId: deviceID,
1764 ImageState: &voltha.ImageState{
1765 Version: request.GetVersion(),
1766 DownloadState: voltha.ImageState_DOWNLOAD_UNKNOWN,
1767 Reason: voltha.ImageState_UNKNOWN_ERROR,
1768 ImageState: voltha.ImageState_IMAGE_UNKNOWN,
1769 },
1770 }}
ssiddiquif076cb82021-04-23 10:47:04 +05301771 return
1772 }
1773
1774 err = dMgr.validateDeviceImageResponse(resp)
1775 if err != nil {
1776 logger.Errorw(ctx, "get-image-status-failed", log.Fields{"device-id": deviceID, "error": err})
ssiddiquib2f526c2021-10-11 17:11:25 +05301777 ch <- []*voltha.DeviceImageState{{
1778 DeviceId: deviceID,
1779 ImageState: &voltha.ImageState{
1780 Version: request.GetVersion(),
1781 DownloadState: voltha.ImageState_DOWNLOAD_UNKNOWN,
1782 Reason: voltha.ImageState_UNKNOWN_ERROR,
1783 ImageState: voltha.ImageState_IMAGE_UNKNOWN,
1784 },
1785 }}
ssiddiquif076cb82021-04-23 10:47:04 +05301786 return
1787 }
1788 ch <- resp.GetDeviceImageStates()
1789 }(deviceID.GetId(), imageStatusReq, respCh)
1790
1791 }
1792
1793 return dMgr.waitForAllResponses(ctx, "get-image-status", respCh, len(request.GetDeviceId()))
1794}
1795
1796func (dMgr *Manager) AbortImageUpgradeToDevice(ctx context.Context, request *voltha.DeviceImageRequest) (*voltha.DeviceImageResponse, error) {
1797 if err := dMgr.validateImageRequest(request); err != nil {
1798 return nil, err
1799 }
1800
1801 ctx = utils.WithRPCMetadataContext(ctx, "AbortImageUpgradeToDevice")
1802 respCh := make(chan []*voltha.DeviceImageState, len(request.GetDeviceId()))
1803
ssiddiquif076cb82021-04-23 10:47:04 +05301804 for index, deviceID := range request.DeviceId {
ssiddiqui6bd4de02021-06-08 12:04:17 +05301805 // Create abort request per device
1806 abortImageReq := &voltha.DeviceImageRequest{
1807 Version: request.Version,
1808 CommitOnSuccess: request.CommitOnSuccess,
1809 }
1810
ssiddiquif076cb82021-04-23 10:47:04 +05301811 //slice-out only single deviceID from the request
1812 abortImageReq.DeviceId = request.DeviceId[index : index+1]
1813
1814 go func(deviceID string, req *voltha.DeviceImageRequest, ch chan []*voltha.DeviceImageState) {
1815 agent := dMgr.getDeviceAgent(ctx, deviceID)
1816 if agent == nil {
ssiddiquib2f526c2021-10-11 17:11:25 +05301817 logger.Errorw(ctx, "Device-agent-not-found", log.Fields{"device-id": deviceID})
1818 ch <- []*voltha.DeviceImageState{{
1819 DeviceId: deviceID,
1820 ImageState: &voltha.ImageState{
1821 Version: request.GetVersion(),
1822 DownloadState: voltha.ImageState_DOWNLOAD_UNKNOWN,
1823 Reason: voltha.ImageState_UNKNOWN_ERROR,
1824 ImageState: voltha.ImageState_IMAGE_UNKNOWN,
1825 },
1826 }}
ssiddiquif076cb82021-04-23 10:47:04 +05301827 return
1828 }
1829
1830 resp, err := agent.abortImageUpgradeToDevice(ctx, req)
1831 if err != nil {
1832 logger.Errorw(ctx, "abort-image-upgrade-to-device-failed", log.Fields{"device-id": deviceID, "error": err})
ssiddiquib2f526c2021-10-11 17:11:25 +05301833 ch <- []*voltha.DeviceImageState{{
1834 DeviceId: deviceID,
1835 ImageState: &voltha.ImageState{
1836 Version: request.GetVersion(),
1837 DownloadState: voltha.ImageState_DOWNLOAD_UNKNOWN,
1838 Reason: voltha.ImageState_UNKNOWN_ERROR,
1839 ImageState: voltha.ImageState_IMAGE_UNKNOWN,
1840 },
1841 }}
ssiddiquif076cb82021-04-23 10:47:04 +05301842 return
1843 }
1844
1845 err = dMgr.validateDeviceImageResponse(resp)
1846 if err != nil {
1847 logger.Errorw(ctx, "abort-image-upgrade-to-device-failed", log.Fields{"device-id": deviceID, "error": err})
ssiddiquib2f526c2021-10-11 17:11:25 +05301848 ch <- []*voltha.DeviceImageState{{
1849 DeviceId: deviceID,
1850 ImageState: &voltha.ImageState{
1851 Version: request.GetVersion(),
1852 DownloadState: voltha.ImageState_DOWNLOAD_UNKNOWN,
1853 Reason: voltha.ImageState_UNKNOWN_ERROR,
1854 ImageState: voltha.ImageState_IMAGE_UNKNOWN,
1855 },
1856 }}
ssiddiquif076cb82021-04-23 10:47:04 +05301857 return
1858 }
1859 ch <- resp.GetDeviceImageStates()
1860 }(deviceID.GetId(), abortImageReq, respCh)
1861
1862 }
1863
1864 return dMgr.waitForAllResponses(ctx, "abort-image-upgrade-to-device", respCh, len(request.GetDeviceId()))
1865}
1866
1867func (dMgr *Manager) GetOnuImages(ctx context.Context, id *common.ID) (*voltha.OnuImages, error) {
1868 if id == nil || id.Id == "" {
1869 return nil, status.Errorf(codes.InvalidArgument, "empty device id")
1870 }
1871
1872 ctx = utils.WithRPCMetadataContext(ctx, "GetOnuImages")
1873 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
1874 agent := dMgr.getDeviceAgent(ctx, id.Id)
1875 if agent == nil {
1876 return nil, status.Errorf(codes.NotFound, "%s", id.Id)
1877 }
1878
1879 resp, err := agent.getOnuImages(ctx, id)
1880 if err != nil {
1881 return nil, err
1882 }
1883
1884 logger.Debugw(ctx, "get-onu-images-result", log.Fields{"onu-image": resp.Items})
1885
1886 return resp, nil
1887}
1888
1889func (dMgr *Manager) ActivateImage(ctx context.Context, request *voltha.DeviceImageRequest) (*voltha.DeviceImageResponse, error) {
1890 if err := dMgr.validateImageRequest(request); err != nil {
1891 return nil, err
1892 }
1893
1894 ctx = utils.WithRPCMetadataContext(ctx, "ActivateImage")
1895 respCh := make(chan []*voltha.DeviceImageState, len(request.GetDeviceId()))
1896
ssiddiquif076cb82021-04-23 10:47:04 +05301897 for index, deviceID := range request.DeviceId {
ssiddiqui6bd4de02021-06-08 12:04:17 +05301898 // Create activate request per device
1899 activateImageReq := &voltha.DeviceImageRequest{
1900 Version: request.Version,
1901 CommitOnSuccess: request.CommitOnSuccess,
1902 }
1903
ssiddiquif076cb82021-04-23 10:47:04 +05301904 //slice-out only single deviceID from the request
1905 activateImageReq.DeviceId = request.DeviceId[index : index+1]
1906
1907 go func(deviceID string, req *voltha.DeviceImageRequest, ch chan []*voltha.DeviceImageState) {
1908 agent := dMgr.getDeviceAgent(ctx, deviceID)
1909 if agent == nil {
ssiddiquib2f526c2021-10-11 17:11:25 +05301910 logger.Errorw(ctx, "Device-agent-not-found", log.Fields{"device-id": deviceID})
1911 ch <- []*voltha.DeviceImageState{{
1912 DeviceId: deviceID,
1913 ImageState: &voltha.ImageState{
1914 Version: request.GetVersion(),
1915 DownloadState: voltha.ImageState_DOWNLOAD_UNKNOWN,
1916 Reason: voltha.ImageState_UNKNOWN_ERROR,
1917 ImageState: voltha.ImageState_IMAGE_ACTIVATION_ABORTED,
1918 },
1919 }}
ssiddiquif076cb82021-04-23 10:47:04 +05301920 return
1921 }
1922
1923 resp, err := agent.activateImageOnDevice(ctx, req)
1924 if err != nil {
1925 logger.Errorw(ctx, "activate-image-failed", log.Fields{"device-id": deviceID, "error": err})
ssiddiquib2f526c2021-10-11 17:11:25 +05301926 ch <- []*voltha.DeviceImageState{{
1927 DeviceId: deviceID,
1928 ImageState: &voltha.ImageState{
1929 Version: request.GetVersion(),
1930 DownloadState: voltha.ImageState_DOWNLOAD_UNKNOWN,
1931 Reason: voltha.ImageState_UNKNOWN_ERROR,
1932 ImageState: voltha.ImageState_IMAGE_ACTIVATION_ABORTED,
1933 },
1934 }}
ssiddiquif076cb82021-04-23 10:47:04 +05301935 return
1936 }
1937
1938 err = dMgr.validateDeviceImageResponse(resp)
1939 if err != nil {
1940 logger.Errorw(ctx, "activate-image-failed", log.Fields{"device-id": deviceID, "error": err})
ssiddiquib2f526c2021-10-11 17:11:25 +05301941 ch <- []*voltha.DeviceImageState{{
1942 DeviceId: deviceID,
1943 ImageState: &voltha.ImageState{
1944 Version: request.GetVersion(),
1945 DownloadState: voltha.ImageState_DOWNLOAD_UNKNOWN,
1946 Reason: voltha.ImageState_UNKNOWN_ERROR,
1947 ImageState: voltha.ImageState_IMAGE_UNKNOWN,
1948 },
1949 }}
ssiddiquif076cb82021-04-23 10:47:04 +05301950 return
1951 }
1952
1953 ch <- resp.GetDeviceImageStates()
1954 }(deviceID.GetId(), activateImageReq, respCh)
1955
1956 }
1957
1958 return dMgr.waitForAllResponses(ctx, "activate-image", respCh, len(request.GetDeviceId()))
1959}
1960
1961func (dMgr *Manager) CommitImage(ctx context.Context, request *voltha.DeviceImageRequest) (*voltha.DeviceImageResponse, error) {
1962 if err := dMgr.validateImageRequest(request); err != nil {
1963 return nil, err
1964 }
1965
1966 ctx = utils.WithRPCMetadataContext(ctx, "CommitImage")
1967 respCh := make(chan []*voltha.DeviceImageState, len(request.GetDeviceId()))
1968
ssiddiquif076cb82021-04-23 10:47:04 +05301969 for index, deviceID := range request.DeviceId {
ssiddiqui6bd4de02021-06-08 12:04:17 +05301970 // Create commit request per device
1971 commitImageReq := &voltha.DeviceImageRequest{
1972 Version: request.Version,
1973 CommitOnSuccess: request.CommitOnSuccess,
1974 }
ssiddiquif076cb82021-04-23 10:47:04 +05301975 //slice-out only single deviceID from the request
1976 commitImageReq.DeviceId = request.DeviceId[index : index+1]
1977
1978 go func(deviceID string, req *voltha.DeviceImageRequest, ch chan []*voltha.DeviceImageState) {
1979 agent := dMgr.getDeviceAgent(ctx, deviceID)
1980 if agent == nil {
ssiddiquib2f526c2021-10-11 17:11:25 +05301981 logger.Errorw(ctx, "Device-agent-not-found", log.Fields{"device-id": deviceID})
1982 ch <- []*voltha.DeviceImageState{{
1983 DeviceId: deviceID,
1984 ImageState: &voltha.ImageState{
1985 Version: request.GetVersion(),
1986 DownloadState: voltha.ImageState_DOWNLOAD_UNKNOWN,
1987 Reason: voltha.ImageState_UNKNOWN_ERROR,
1988 ImageState: voltha.ImageState_IMAGE_COMMIT_ABORTED,
1989 },
1990 }}
ssiddiquif076cb82021-04-23 10:47:04 +05301991 return
1992 }
1993
1994 resp, err := agent.commitImage(ctx, req)
1995 if err != nil {
1996 logger.Errorw(ctx, "commit-image-failed", log.Fields{"device-id": deviceID, "error": err})
ssiddiquib2f526c2021-10-11 17:11:25 +05301997 ch <- []*voltha.DeviceImageState{{
1998 DeviceId: deviceID,
1999 ImageState: &voltha.ImageState{
2000 Version: request.GetVersion(),
2001 DownloadState: voltha.ImageState_DOWNLOAD_UNKNOWN,
2002 Reason: voltha.ImageState_UNKNOWN_ERROR,
2003 ImageState: voltha.ImageState_IMAGE_COMMIT_ABORTED,
2004 },
2005 }}
ssiddiquif076cb82021-04-23 10:47:04 +05302006 return
2007 }
2008
2009 err = dMgr.validateDeviceImageResponse(resp)
2010 if err != nil {
2011 logger.Errorf(ctx, "commit-image-failed", log.Fields{"device-id": deviceID, "error": err})
ssiddiquib2f526c2021-10-11 17:11:25 +05302012 ch <- []*voltha.DeviceImageState{{
2013 DeviceId: deviceID,
2014 ImageState: &voltha.ImageState{
2015 Version: request.GetVersion(),
2016 DownloadState: voltha.ImageState_DOWNLOAD_UNKNOWN,
2017 Reason: voltha.ImageState_UNKNOWN_ERROR,
2018 ImageState: voltha.ImageState_IMAGE_UNKNOWN,
2019 },
2020 }}
ssiddiquif076cb82021-04-23 10:47:04 +05302021 return
2022 }
2023 ch <- resp.GetDeviceImageStates()
2024 }(deviceID.GetId(), commitImageReq, respCh)
2025
2026 }
2027
2028 return dMgr.waitForAllResponses(ctx, "commit-image", respCh, len(request.GetDeviceId()))
2029}
2030
2031func (dMgr *Manager) validateImageDownloadRequest(request *voltha.DeviceImageDownloadRequest) error {
2032 if request == nil || request.Image == nil || len(request.DeviceId) == 0 {
2033 return status.Errorf(codes.InvalidArgument, "invalid argument")
2034 }
2035
2036 for _, deviceID := range request.DeviceId {
2037 if deviceID == nil {
2038 return status.Errorf(codes.InvalidArgument, "id is nil")
2039 }
2040 }
2041 return nil
2042}
2043
2044func (dMgr *Manager) validateImageRequest(request *voltha.DeviceImageRequest) error {
2045 if request == nil || len(request.DeviceId) == 0 || request.DeviceId[0] == nil {
2046 return status.Errorf(codes.InvalidArgument, "invalid argument")
2047 }
2048
2049 for _, deviceID := range request.DeviceId {
2050 if deviceID == nil {
2051 return status.Errorf(codes.InvalidArgument, "id is nil")
2052 }
2053 }
2054
2055 return nil
2056}
2057
2058func (dMgr *Manager) validateDeviceImageResponse(response *voltha.DeviceImageResponse) error {
2059 if response == nil || len(response.GetDeviceImageStates()) == 0 || response.GetDeviceImageStates()[0] == nil {
2060 return status.Errorf(codes.Internal, "invalid-response-from-adapter")
2061 }
2062
2063 return nil
2064}
2065
2066func (dMgr *Manager) waitForAllResponses(ctx context.Context, opName string, respCh chan []*voltha.DeviceImageState, expectedResps int) (*voltha.DeviceImageResponse, error) {
2067 response := &voltha.DeviceImageResponse{}
2068 respCount := 0
2069 for {
2070 select {
2071 case resp, ok := <-respCh:
2072 if !ok {
2073 logger.Errorw(ctx, opName+"-failed", log.Fields{"error": "channel-closed"})
2074 return response, status.Errorf(codes.Aborted, "channel-closed")
2075 }
2076
2077 if resp != nil {
2078 logger.Debugw(ctx, opName+"-result", log.Fields{"image-state": resp[0].GetImageState(), "device-id": resp[0].GetDeviceId()})
2079 response.DeviceImageStates = append(response.DeviceImageStates, resp...)
2080 }
2081
2082 respCount++
2083
2084 //check whether all responses received, if so, sent back the collated response
2085 if respCount == expectedResps {
2086 return response, nil
2087 }
2088 continue
2089 case <-ctx.Done():
2090 return nil, status.Errorf(codes.Aborted, opName+"-failed-%s", ctx.Err())
2091 }
2092 }
2093}
Maninder0aabf0c2021-03-17 14:55:14 +05302094
2095func (dMgr *Manager) ReconcilingCleanup(ctx context.Context, device *voltha.Device) error {
2096 agent := dMgr.getDeviceAgent(ctx, device.Id)
2097 if agent == nil {
2098 logger.Errorf(ctx, "Not able to get device agent.")
2099 return status.Errorf(codes.NotFound, "Not able to get device agent for device : %s", device.Id)
2100 }
2101 err := agent.reconcilingCleanup(ctx)
2102 if err != nil {
2103 logger.Errorf(ctx, err.Error())
2104 return status.Errorf(codes.Internal, err.Error())
2105 }
2106 return nil
2107}
serkant.uluderyae25f6482020-12-17 21:08:38 +03002108
2109func (dMgr *Manager) DeleteAllLogicalMeters(ctx context.Context, cDevice *voltha.Device) error {
2110 logger.Debugw(ctx, "delete-all-logical-device-meters", log.Fields{"device-id": cDevice.Id})
2111 if err := dMgr.logicalDeviceMgr.deleteAllLogicalMeters(ctx, cDevice.Id); err != nil {
2112 // Just log the error. The logical device or port may already have been deleted before this callback is invoked.
2113 logger.Warnw(ctx, "delete-logical-ports-error", log.Fields{"device-id": cDevice.Id, "error": err})
2114 }
2115 return nil
2116
2117}