blob: dd64ab90a8b00cc9249200271796df607bf3de33 [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
Kent Hagerman45a13e42020-04-13 12:23:50 -040025 "github.com/golang/protobuf/ptypes/empty"
sbarbari17d7e222019-11-05 10:02:29 -050026 "github.com/opencord/voltha-go/db/model"
Kent Hagerman2b216042020-04-03 18:28:56 -040027 "github.com/opencord/voltha-go/rw_core/core/adapter"
Kent Hagermanf5a67352020-04-30 15:15:26 -040028 "github.com/opencord/voltha-go/rw_core/core/device/event"
Kent Hagerman2b216042020-04-03 18:28:56 -040029 "github.com/opencord/voltha-go/rw_core/core/device/remote"
Kent Hagerman6031aad2020-07-29 16:36:33 -040030 "github.com/opencord/voltha-go/rw_core/core/device/state"
khenaidoo3d3b8c22019-05-22 18:10:39 -040031 "github.com/opencord/voltha-go/rw_core/utils"
Himani Chawlab4c25912020-11-12 17:16:38 +053032 "github.com/opencord/voltha-lib-go/v4/pkg/events"
Maninderdfadc982020-10-28 14:04:33 +053033 "github.com/opencord/voltha-lib-go/v4/pkg/kafka"
34 "github.com/opencord/voltha-lib-go/v4/pkg/log"
35 "github.com/opencord/voltha-protos/v4/go/common"
36 ic "github.com/opencord/voltha-protos/v4/go/inter_container"
37 "github.com/opencord/voltha-protos/v4/go/openflow_13"
38 ofp "github.com/opencord/voltha-protos/v4/go/openflow_13"
39 "github.com/opencord/voltha-protos/v4/go/voltha"
khenaidoob9203542018-09-17 22:56:37 -040040 "google.golang.org/grpc/codes"
41 "google.golang.org/grpc/status"
khenaidoob9203542018-09-17 22:56:37 -040042)
43
Kent Hagerman2b216042020-04-03 18:28:56 -040044// Manager represent device manager attributes
45type Manager struct {
Himani Chawlab4c25912020-11-12 17:16:38 +053046 deviceAgents sync.Map
47 rootDevices map[string]bool
48 lockRootDeviceMap sync.RWMutex
49 adapterProxy *remote.AdapterProxy
Mahir Gunyelb0343bf2021-05-11 14:14:26 -070050 *event.Agent
Kent Hagerman2b216042020-04-03 18:28:56 -040051 adapterMgr *adapter.Manager
52 logicalDeviceMgr *LogicalManager
npujar467fe752020-01-16 20:17:45 +053053 kafkaICProxy kafka.InterContainerProxy
Kent Hagerman6031aad2020-07-29 16:36:33 -040054 stateTransitions *state.TransitionMap
Mahir Gunyel03de0d32020-06-03 01:36:59 -070055 dbPath *model.Path
Kent Hagermanf5a67352020-04-30 15:15:26 -040056 dProxy *model.Proxy
npujar1d86a522019-11-14 17:11:16 +053057 coreInstanceID string
khenaidoo442e7c72020-03-10 16:13:48 -040058 defaultTimeout time.Duration
khenaidoo4c9e5592019-09-09 16:20:41 -040059 devicesLoadingLock sync.RWMutex
60 deviceLoadingInProgress map[string][]chan int
khenaidoob9203542018-09-17 22:56:37 -040061}
62
Mahir Gunyel03de0d32020-06-03 01:36:59 -070063//NewManagers creates the Manager and the Logical Manager.
Himani Chawla9cfc4992021-03-22 12:43:01 +053064func NewManagers(dbPath *model.Path, adapterMgr *adapter.Manager, kmp kafka.InterContainerProxy, endpointMgr kafka.EndpointManager, coreTopic, coreInstanceID string, defaultCoreTimeout time.Duration, eventProxy *events.EventProxy, stackID string) (*Manager, *LogicalManager) {
Kent Hagerman2b216042020-04-03 18:28:56 -040065 deviceMgr := &Manager{
Kent Hagerman2b216042020-04-03 18:28:56 -040066 rootDevices: make(map[string]bool),
67 kafkaICProxy: kmp,
serkant.uluderya8ff291d2020-05-20 00:58:00 -070068 adapterProxy: remote.NewAdapterProxy(kmp, coreTopic, endpointMgr),
Kent Hagerman2b216042020-04-03 18:28:56 -040069 coreInstanceID: coreInstanceID,
Mahir Gunyel03de0d32020-06-03 01:36:59 -070070 dbPath: dbPath,
71 dProxy: dbPath.Proxy("devices"),
Kent Hagerman2b216042020-04-03 18:28:56 -040072 adapterMgr: adapterMgr,
Kent Hagermanf4151de2020-06-19 15:58:47 -040073 defaultTimeout: defaultCoreTimeout,
Mahir Gunyelb0343bf2021-05-11 14:14:26 -070074 Agent: event.NewAgent(eventProxy, coreInstanceID, stackID),
Kent Hagerman2b216042020-04-03 18:28:56 -040075 deviceLoadingInProgress: make(map[string][]chan int),
76 }
Kent Hagerman6031aad2020-07-29 16:36:33 -040077 deviceMgr.stateTransitions = state.NewTransitionMap(deviceMgr)
Kent Hagerman2f0d0552020-04-23 17:28:52 -040078
Kent Hagerman2b216042020-04-03 18:28:56 -040079 logicalDeviceMgr := &LogicalManager{
Himani Chawla9cfc4992021-03-22 12:43:01 +053080 Manager: event.NewManager(eventProxy, coreInstanceID, stackID),
Kent Hagerman2b216042020-04-03 18:28:56 -040081 deviceMgr: deviceMgr,
82 kafkaICProxy: kmp,
Mahir Gunyel03de0d32020-06-03 01:36:59 -070083 dbPath: dbPath,
84 ldProxy: dbPath.Proxy("logical_devices"),
Kent Hagerman2b216042020-04-03 18:28:56 -040085 defaultTimeout: defaultCoreTimeout,
86 logicalDeviceLoadingInProgress: make(map[string][]chan int),
87 }
88 deviceMgr.logicalDeviceMgr = logicalDeviceMgr
Matteo Scandolod525ae32020-04-02 17:27:29 -070089
Kent Hagerman2b216042020-04-03 18:28:56 -040090 adapterMgr.SetAdapterRestartedCallback(deviceMgr.adapterRestarted)
Matteo Scandolod525ae32020-04-02 17:27:29 -070091
Kent Hagerman2b216042020-04-03 18:28:56 -040092 return deviceMgr, logicalDeviceMgr
khenaidoob9203542018-09-17 22:56:37 -040093}
94
Kent Hagerman2b216042020-04-03 18:28:56 -040095func (dMgr *Manager) addDeviceAgentToMap(agent *Agent) {
npujar1d86a522019-11-14 17:11:16 +053096 if _, exist := dMgr.deviceAgents.Load(agent.deviceID); !exist {
97 dMgr.deviceAgents.Store(agent.deviceID, agent)
khenaidoob9203542018-09-17 22:56:37 -040098 }
khenaidoo2c6a0992019-04-29 13:46:56 -040099 dMgr.lockRootDeviceMap.Lock()
100 defer dMgr.lockRootDeviceMap.Unlock()
Kent Hagerman2a07b862020-06-19 15:23:07 -0400101 dMgr.rootDevices[agent.deviceID] = agent.isRootDevice
khenaidoo2c6a0992019-04-29 13:46:56 -0400102
khenaidoob9203542018-09-17 22:56:37 -0400103}
104
Kent Hagerman2b216042020-04-03 18:28:56 -0400105func (dMgr *Manager) deleteDeviceAgentFromMap(agent *Agent) {
npujar1d86a522019-11-14 17:11:16 +0530106 dMgr.deviceAgents.Delete(agent.deviceID)
khenaidoo2c6a0992019-04-29 13:46:56 -0400107 dMgr.lockRootDeviceMap.Lock()
108 defer dMgr.lockRootDeviceMap.Unlock()
npujar1d86a522019-11-14 17:11:16 +0530109 delete(dMgr.rootDevices, agent.deviceID)
khenaidoo4d4802d2018-10-04 21:59:49 -0400110}
111
khenaidoo297cd252019-02-07 22:10:23 -0500112// 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 -0400113func (dMgr *Manager) getDeviceAgent(ctx context.Context, deviceID string) *Agent {
npujar1d86a522019-11-14 17:11:16 +0530114 agent, ok := dMgr.deviceAgents.Load(deviceID)
115 if ok {
Kent Hagerman2b216042020-04-03 18:28:56 -0400116 return agent.(*Agent)
khenaidoob9203542018-09-17 22:56:37 -0400117 }
khenaidoo442e7c72020-03-10 16:13:48 -0400118 // Try to load into memory - loading will also create the device agent and set the device ownership
npujar467fe752020-01-16 20:17:45 +0530119 err := dMgr.load(ctx, deviceID)
npujar1d86a522019-11-14 17:11:16 +0530120 if err == nil {
121 agent, ok = dMgr.deviceAgents.Load(deviceID)
122 if !ok {
123 return nil
124 }
Kent Hagerman2b216042020-04-03 18:28:56 -0400125 return agent.(*Agent)
npujar1d86a522019-11-14 17:11:16 +0530126 }
127 //TODO: Change the return params to return an error as well
divyadesaicb8b59d2020-08-18 09:55:47 +0000128 logger.Errorw(ctx, "loading-device-failed", log.Fields{"device-id": deviceID, "error": err})
khenaidoob9203542018-09-17 22:56:37 -0400129 return nil
130}
131
khenaidoo297cd252019-02-07 22:10:23 -0500132// listDeviceIdsFromMap returns the list of device IDs that are in memory
Kent Hagerman2b216042020-04-03 18:28:56 -0400133func (dMgr *Manager) listDeviceIdsFromMap() *voltha.IDs {
khenaidoo7ccedd52018-12-14 16:48:54 -0500134 result := &voltha.IDs{Items: make([]*voltha.ID, 0)}
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400135
136 dMgr.deviceAgents.Range(func(key, value interface{}) bool {
137 result.Items = append(result.Items, &voltha.ID{Id: key.(string)})
138 return true
139 })
140
khenaidoo7ccedd52018-12-14 16:48:54 -0500141 return result
142}
143
Kent Hagerman45a13e42020-04-13 12:23:50 -0400144// CreateDevice creates a new parent device in the data model
145func (dMgr *Manager) CreateDevice(ctx context.Context, device *voltha.Device) (*voltha.Device, error) {
146 if device.MacAddress == "" && device.GetHostAndPort() == "" {
Himani Chawlab4c25912020-11-12 17:16:38 +0530147 logger.Errorf(ctx, "no-device-info-present")
Kent Hagerman45a13e42020-04-13 12:23:50 -0400148 return &voltha.Device{}, errors.New("no-device-info-present; MAC or HOSTIP&PORT")
149 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530150 ctx = utils.WithRPCMetadataContext(ctx, "CreateDevice")
Rohan Agrawal31f21802020-06-12 05:38:46 +0000151 logger.Debugw(ctx, "create-device", log.Fields{"device": *device})
Kent Hagerman45a13e42020-04-13 12:23:50 -0400152
npujar467fe752020-01-16 20:17:45 +0530153 deviceExist, err := dMgr.isParentDeviceExist(ctx, device)
Thomas Lee Se5a44012019-11-07 20:32:24 +0530154 if err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530155 logger.Errorf(ctx, "failed-to-fetch-parent-device-info")
Kent Hagerman45a13e42020-04-13 12:23:50 -0400156 return nil, err
Thomas Lee Se5a44012019-11-07 20:32:24 +0530157 }
158 if deviceExist {
Himani Chawlab4c25912020-11-12 17:16:38 +0530159 logger.Errorf(ctx, "device-is-pre-provisioned-already-with-same-ip-port-or-mac-address")
Kent Hagerman45a13e42020-04-13 12:23:50 -0400160 return nil, errors.New("device is already pre-provisioned")
Thomas Lee S51b5cb82019-10-14 14:49:34 +0530161 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530162 logger.Debugw(ctx, "create-device", log.Fields{"device": device, "aproxy": dMgr.adapterProxy})
khenaidoob9203542018-09-17 22:56:37 -0400163
khenaidoo5e677ae2019-02-28 17:26:29 -0500164 // Ensure this device is set as root
165 device.Root = true
khenaidoob9203542018-09-17 22:56:37 -0400166 // Create and start a device agent for that device
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700167 agent := newAgent(dMgr.adapterProxy, device, dMgr, dMgr.dbPath, dMgr.dProxy, dMgr.defaultTimeout)
Thomas Lee Se5a44012019-11-07 20:32:24 +0530168 device, err = agent.start(ctx, device)
Scott Baker80678602019-11-14 16:57:36 -0800169 if err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530170 logger.Errorw(ctx, "fail-to-start-device", log.Fields{"device-id": agent.deviceID, "error": err})
Kent Hagerman45a13e42020-04-13 12:23:50 -0400171 return nil, err
Scott Baker80678602019-11-14 16:57:36 -0800172 }
khenaidoo442e7c72020-03-10 16:13:48 -0400173 dMgr.addDeviceAgentToMap(agent)
Kent Hagerman45a13e42020-04-13 12:23:50 -0400174 return device, nil
khenaidoob9203542018-09-17 22:56:37 -0400175}
176
Kent Hagerman45a13e42020-04-13 12:23:50 -0400177// EnableDevice activates a device by invoking the adopt_device API on the appropriate adapter
178func (dMgr *Manager) EnableDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530179 ctx = utils.WithRPCMetadataContext(ctx, "EnableDevice")
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000180 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +0530181 logger.Debugw(ctx, "enable-device", log.Fields{"device-id": id.Id})
Kent Hagerman45a13e42020-04-13 12:23:50 -0400182 agent := dMgr.getDeviceAgent(ctx, id.Id)
183 if agent == nil {
184 return nil, status.Errorf(codes.NotFound, "%s", id.Id)
khenaidoob9203542018-09-17 22:56:37 -0400185 }
Kent Hagerman45a13e42020-04-13 12:23:50 -0400186 return &empty.Empty{}, agent.enableDevice(ctx)
khenaidoob9203542018-09-17 22:56:37 -0400187}
188
Kent Hagerman45a13e42020-04-13 12:23:50 -0400189// DisableDevice disables a device along with any child device it may have
190func (dMgr *Manager) DisableDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530191 ctx = utils.WithRPCMetadataContext(ctx, "DisableDevice")
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000192 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +0530193 logger.Debugw(ctx, "disable-device", log.Fields{"device-id": id.Id})
Kent Hagerman45a13e42020-04-13 12:23:50 -0400194 agent := dMgr.getDeviceAgent(ctx, id.Id)
195 if agent == nil {
196 return nil, status.Errorf(codes.NotFound, "%s", id.Id)
khenaidoob9203542018-09-17 22:56:37 -0400197 }
Kent Hagerman45a13e42020-04-13 12:23:50 -0400198 return &empty.Empty{}, agent.disableDevice(ctx)
khenaidoo92e62c52018-10-03 14:02:54 -0400199}
200
Kent Hagerman45a13e42020-04-13 12:23:50 -0400201//RebootDevice invoked the reboot API to the corresponding adapter
202func (dMgr *Manager) RebootDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530203 ctx = utils.WithRPCMetadataContext(ctx, "RebootDevice")
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000204 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +0530205 logger.Debugw(ctx, "reboot-device", log.Fields{"device-id": id.Id})
Kent Hagerman45a13e42020-04-13 12:23:50 -0400206 agent := dMgr.getDeviceAgent(ctx, id.Id)
207 if agent == nil {
208 return nil, status.Errorf(codes.NotFound, "%s", id.Id)
khenaidoo4d4802d2018-10-04 21:59:49 -0400209 }
Kent Hagerman45a13e42020-04-13 12:23:50 -0400210 return &empty.Empty{}, agent.rebootDevice(ctx)
khenaidoo4d4802d2018-10-04 21:59:49 -0400211}
212
Kent Hagerman45a13e42020-04-13 12:23:50 -0400213// DeleteDevice removes a device from the data model
214func (dMgr *Manager) DeleteDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530215 ctx = utils.WithRPCMetadataContext(ctx, "DeleteDevice")
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000216 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +0530217 logger.Debugw(ctx, "delete-device", log.Fields{"device-id": id.Id})
Kent Hagerman45a13e42020-04-13 12:23:50 -0400218 agent := dMgr.getDeviceAgent(ctx, id.Id)
219 if agent == nil {
220 return nil, status.Errorf(codes.NotFound, "%s", id.Id)
khenaidoo4d4802d2018-10-04 21:59:49 -0400221 }
Kent Hagerman45a13e42020-04-13 12:23:50 -0400222 return &empty.Empty{}, agent.deleteDevice(ctx)
223}
224
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530225// ForceDeleteDevice removes a device from the data model forcefully without successfully waiting for the adapters.
226func (dMgr *Manager) ForceDeleteDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530227 ctx = utils.WithRPCMetadataContext(ctx, "ForceDeleteDevice")
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530228 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +0530229 logger.Debugw(ctx, "force-delete-device", log.Fields{"device-id": id.Id})
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530230 agent := dMgr.getDeviceAgent(ctx, id.Id)
231 if agent == nil {
232 return nil, status.Errorf(codes.NotFound, "%s", id.Id)
233 }
234 return &empty.Empty{}, agent.deleteDeviceForce(ctx)
235}
236
Kent Hagerman2a07b862020-06-19 15:23:07 -0400237// GetDevicePort returns the port details for a specific device port entry
238func (dMgr *Manager) GetDevicePort(ctx context.Context, deviceID string, portID uint32) (*voltha.Port, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530239 logger.Debugw(ctx, "get-device-port", log.Fields{"device-id": deviceID})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400240 agent := dMgr.getDeviceAgent(ctx, deviceID)
241 if agent == nil {
242 return nil, status.Errorf(codes.NotFound, "device-%s", deviceID)
243 }
244 return agent.getDevicePort(portID)
245}
246
Kent Hagerman45a13e42020-04-13 12:23:50 -0400247// ListDevicePorts returns the ports details for a specific device entry
248func (dMgr *Manager) ListDevicePorts(ctx context.Context, id *voltha.ID) (*voltha.Ports, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530249 ctx = utils.WithRPCMetadataContext(ctx, "ListDevicePorts")
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000250 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +0530251 logger.Debugw(ctx, "list-device-ports", log.Fields{"device-id": id.Id})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400252 agent := dMgr.getDeviceAgent(ctx, id.Id)
253 if agent == nil {
254 return nil, status.Errorf(codes.NotFound, "device-%s", id.Id)
Kent Hagerman45a13e42020-04-13 12:23:50 -0400255 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400256
257 ports := agent.listDevicePorts()
258 ctr, ret := 0, make([]*voltha.Port, len(ports))
259 for _, port := range ports {
260 ret[ctr] = port
261 ctr++
262 }
263 return &voltha.Ports{Items: ret}, nil
Kent Hagerman45a13e42020-04-13 12:23:50 -0400264}
265
266// ListDeviceFlows returns the flow details for a specific device entry
267func (dMgr *Manager) ListDeviceFlows(ctx context.Context, id *voltha.ID) (*ofp.Flows, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530268 ctx = utils.WithRPCMetadataContext(ctx, "ListDeviceFlows")
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000269 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +0530270 logger.Debugw(ctx, "list-device-flows", log.Fields{"device-id": id.Id})
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700271 agent := dMgr.getDeviceAgent(ctx, id.Id)
272 if agent == nil {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400273 return nil, status.Errorf(codes.NotFound, "device-%s", id.Id)
Kent Hagerman45a13e42020-04-13 12:23:50 -0400274 }
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700275
276 flows := agent.listDeviceFlows()
277 ctr, ret := 0, make([]*ofp.OfpFlowStats, len(flows))
278 for _, flow := range flows {
279 ret[ctr] = flow
280 ctr++
281 }
282 return &openflow_13.Flows{Items: ret}, nil
Kent Hagerman45a13e42020-04-13 12:23:50 -0400283}
284
285// ListDeviceFlowGroups returns the flow group details for a specific device entry
286func (dMgr *Manager) ListDeviceFlowGroups(ctx context.Context, id *voltha.ID) (*voltha.FlowGroups, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530287 ctx = utils.WithRPCMetadataContext(ctx, "ListDeviceFlowGroups")
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000288 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +0530289 logger.Debugw(ctx, "list-device-flow-groups", log.Fields{"device-id": id.Id})
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700290 agent := dMgr.getDeviceAgent(ctx, id.Id)
291 if agent == nil {
Kent Hagerman45a13e42020-04-13 12:23:50 -0400292 return nil, status.Errorf(codes.NotFound, "device-%s", id.Id)
293 }
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700294 groups := agent.listDeviceGroups()
295 ctr, ret := 0, make([]*openflow_13.OfpGroupEntry, len(groups))
296 for _, group := range groups {
297 ret[ctr] = group
298 ctr++
299 }
300 return &voltha.FlowGroups{Items: ret}, nil
khenaidoo4d4802d2018-10-04 21:59:49 -0400301}
302
khenaidoo6d62c002019-05-15 21:57:03 -0400303// stopManagingDevice stops the management of the device as well as any of its reference device and logical device.
304// This function is called only in the Core that does not own this device. In the Core that owns this device then a
305// deletion deletion also includes removal of any reference of this device.
Kent Hagerman2b216042020-04-03 18:28:56 -0400306func (dMgr *Manager) stopManagingDevice(ctx context.Context, id string) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530307 logger.Infow(ctx, "stop-managing-device", log.Fields{"device-id": id})
khenaidoo6d62c002019-05-15 21:57:03 -0400308 if dMgr.IsDeviceInCache(id) { // Proceed only if an agent is present for this device
Kent Hagerman6031aad2020-07-29 16:36:33 -0400309 if device, err := dMgr.getDeviceReadOnly(ctx, id); err == nil && device.Root {
khenaidoo6d62c002019-05-15 21:57:03 -0400310 // stop managing the logical device
David Bainbridged1afd662020-03-26 18:27:41 -0700311 _ = dMgr.logicalDeviceMgr.stopManagingLogicalDeviceWithDeviceID(ctx, id)
khenaidoo6d62c002019-05-15 21:57:03 -0400312 }
npujar467fe752020-01-16 20:17:45 +0530313 if agent := dMgr.getDeviceAgent(ctx, id); agent != nil {
khenaidoo442e7c72020-03-10 16:13:48 -0400314 if err := agent.stop(ctx); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000315 logger.Warnw(ctx, "unable-to-stop-device-agent", log.Fields{"device-id": agent.deviceID, "error": err})
khenaidoo442e7c72020-03-10 16:13:48 -0400316 }
khenaidoo4c9e5592019-09-09 16:20:41 -0400317 dMgr.deleteDeviceAgentFromMap(agent)
khenaidoo6d62c002019-05-15 21:57:03 -0400318 }
319 }
320}
321
npujar1d86a522019-11-14 17:11:16 +0530322// RunPostDeviceDelete removes any reference of this device
Kent Hagerman2b216042020-04-03 18:28:56 -0400323func (dMgr *Manager) RunPostDeviceDelete(ctx context.Context, cDevice *voltha.Device) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530324 logger.Infow(ctx, "run-post-device-delete", log.Fields{"device-id": cDevice.Id})
npujar467fe752020-01-16 20:17:45 +0530325 dMgr.stopManagingDevice(ctx, cDevice.Id)
khenaidoo6d62c002019-05-15 21:57:03 -0400326 return nil
khenaidoo0a822f92019-05-08 15:15:57 -0400327}
328
Kent Hagermancba2f302020-07-28 13:37:36 -0400329// GetDevice exists primarily to implement the gRPC interface.
330// Internal functions should call getDeviceReadOnly instead.
Kent Hagerman45a13e42020-04-13 12:23:50 -0400331func (dMgr *Manager) GetDevice(ctx context.Context, id *voltha.ID) (*voltha.Device, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530332 ctx = utils.WithRPCMetadataContext(ctx, "GetDevice")
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000333 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
Kent Hagermancba2f302020-07-28 13:37:36 -0400334 return dMgr.getDeviceReadOnly(ctx, id.Id)
Kent Hagerman45a13e42020-04-13 12:23:50 -0400335}
336
Kent Hagermancba2f302020-07-28 13:37:36 -0400337// getDeviceReadOnly will returns a device, either from memory or from the dB, if present
338func (dMgr *Manager) getDeviceReadOnly(ctx context.Context, id string) (*voltha.Device, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530339 logger.Debugw(ctx, "get-device-read-only", log.Fields{"device-id": id})
npujar467fe752020-01-16 20:17:45 +0530340 if agent := dMgr.getDeviceAgent(ctx, id); agent != nil {
Kent Hagermancba2f302020-07-28 13:37:36 -0400341 return agent.getDeviceReadOnly(ctx)
khenaidoo92e62c52018-10-03 14:02:54 -0400342 }
343 return nil, status.Errorf(codes.NotFound, "%s", id)
khenaidoob9203542018-09-17 22:56:37 -0400344}
345
Kent Hagerman2a07b862020-06-19 15:23:07 -0400346func (dMgr *Manager) listDevicePorts(ctx context.Context, id string) (map[uint32]*voltha.Port, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530347 logger.Debugw(ctx, "list-device-ports", log.Fields{"device-id": id})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400348 agent := dMgr.getDeviceAgent(ctx, id)
349 if agent == nil {
350 return nil, status.Errorf(codes.NotFound, "%s", id)
351 }
352 return agent.listDevicePorts(), nil
353}
354
npujar1d86a522019-11-14 17:11:16 +0530355// GetChildDevice will return a device, either from memory or from the dB, if present
Kent Hagerman2b216042020-04-03 18:28:56 -0400356func (dMgr *Manager) GetChildDevice(ctx context.Context, parentDeviceID string, serialNumber string, onuID int64, parentPortNo int64) (*voltha.Device, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530357 logger.Debugw(ctx, "get-child-device", log.Fields{"parent-device-id": parentDeviceID, "serialNumber": serialNumber,
358 "parent-port-no": parentPortNo, "onu-id": onuID})
Matt Jeanneret4e241952019-02-28 11:16:04 -0500359
Kent Hagerman2a07b862020-06-19 15:23:07 -0400360 parentDevicePorts, err := dMgr.listDevicePorts(ctx, parentDeviceID)
361 if err != nil {
Matt Jeanneret4e241952019-02-28 11:16:04 -0500362 return nil, status.Errorf(codes.Aborted, "%s", err.Error())
363 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400364 childDeviceIds := dMgr.getAllChildDeviceIds(ctx, parentDevicePorts)
Matt Jeanneret4e241952019-02-28 11:16:04 -0500365 if len(childDeviceIds) == 0 {
Himani Chawlab4c25912020-11-12 17:16:38 +0530366 logger.Debugw(ctx, "no-child-devices", log.Fields{"parent-device-id": parentDeviceID, "serial-number": serialNumber, "onu-id": onuID})
npujar1d86a522019-11-14 17:11:16 +0530367 return nil, status.Errorf(codes.NotFound, "%s", parentDeviceID)
Matt Jeanneret4e241952019-02-28 11:16:04 -0500368 }
369
370 var foundChildDevice *voltha.Device
Kent Hagerman2a07b862020-06-19 15:23:07 -0400371 for childDeviceID := range childDeviceIds {
npujar1d86a522019-11-14 17:11:16 +0530372 var found bool
Kent Hagermancba2f302020-07-28 13:37:36 -0400373 if searchDevice, err := dMgr.getDeviceReadOnly(ctx, childDeviceID); err == nil {
Matt Jeanneret4e241952019-02-28 11:16:04 -0500374
npujar1d86a522019-11-14 17:11:16 +0530375 foundOnuID := false
376 if searchDevice.ProxyAddress.OnuId == uint32(onuID) {
Matt Jeanneret4e241952019-02-28 11:16:04 -0500377 if searchDevice.ParentPortNo == uint32(parentPortNo) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530378 logger.Debugw(ctx, "found-child-by-onuid", log.Fields{"parent-device-id": parentDeviceID, "onu-id": onuID})
npujar1d86a522019-11-14 17:11:16 +0530379 foundOnuID = true
Matt Jeanneret4e241952019-02-28 11:16:04 -0500380 }
381 }
382
383 foundSerialNumber := false
384 if searchDevice.SerialNumber == serialNumber {
Himani Chawlab4c25912020-11-12 17:16:38 +0530385 logger.Debugw(ctx, "found-child-by-serial-number", log.Fields{"parent-device-id": parentDeviceID, "serial-number": serialNumber})
Matt Jeanneret4e241952019-02-28 11:16:04 -0500386 foundSerialNumber = true
387 }
388
389 // if both onuId and serialNumber are provided both must be true for the device to be found
390 // otherwise whichever one found a match is good enough
npujar1d86a522019-11-14 17:11:16 +0530391 if onuID > 0 && serialNumber != "" {
392 found = foundOnuID && foundSerialNumber
Matt Jeanneret4e241952019-02-28 11:16:04 -0500393 } else {
npujar1d86a522019-11-14 17:11:16 +0530394 found = foundOnuID || foundSerialNumber
Matt Jeanneret4e241952019-02-28 11:16:04 -0500395 }
396
npujar1d86a522019-11-14 17:11:16 +0530397 if found {
Matt Jeanneret4e241952019-02-28 11:16:04 -0500398 foundChildDevice = searchDevice
399 break
400 }
401 }
402 }
403
404 if foundChildDevice != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530405 logger.Debugw(ctx, "child-device-found", log.Fields{"parent-device-id": parentDeviceID, "found-child-device": foundChildDevice})
Matt Jeanneret4e241952019-02-28 11:16:04 -0500406 return foundChildDevice, nil
407 }
408
divyadesaicb8b59d2020-08-18 09:55:47 +0000409 logger.Debugw(ctx, "child-device-not-found", log.Fields{"parent-device-id": parentDeviceID,
Himani Chawlab4c25912020-11-12 17:16:38 +0530410 "serial-number": serialNumber, "onu-id": onuID, "parent-port-no": parentPortNo})
npujar1d86a522019-11-14 17:11:16 +0530411 return nil, status.Errorf(codes.NotFound, "%s", parentDeviceID)
Matt Jeanneret4e241952019-02-28 11:16:04 -0500412}
413
npujar1d86a522019-11-14 17:11:16 +0530414// GetChildDeviceWithProxyAddress will return a device based on proxy address
Kent Hagerman2b216042020-04-03 18:28:56 -0400415func (dMgr *Manager) GetChildDeviceWithProxyAddress(ctx context.Context, proxyAddress *voltha.Device_ProxyAddress) (*voltha.Device, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530416 logger.Debugw(ctx, "get-child-device-with-proxy-address", log.Fields{"proxy-address": proxyAddress})
Matt Jeanneret2a20aaa2019-03-05 21:04:02 -0500417
Kent Hagerman2a07b862020-06-19 15:23:07 -0400418 parentDevicePorts, err := dMgr.listDevicePorts(ctx, proxyAddress.DeviceId)
419 if err != nil {
Matt Jeanneret2a20aaa2019-03-05 21:04:02 -0500420 return nil, status.Errorf(codes.Aborted, "%s", err.Error())
421 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400422 childDeviceIds := dMgr.getAllChildDeviceIds(ctx, parentDevicePorts)
Matt Jeanneret2a20aaa2019-03-05 21:04:02 -0500423 if len(childDeviceIds) == 0 {
divyadesaicb8b59d2020-08-18 09:55:47 +0000424 logger.Debugw(ctx, "no-child-devices", log.Fields{"parent-device-id": proxyAddress.DeviceId})
Matt Jeanneret2a20aaa2019-03-05 21:04:02 -0500425 return nil, status.Errorf(codes.NotFound, "%s", proxyAddress)
426 }
427
428 var foundChildDevice *voltha.Device
Kent Hagerman2a07b862020-06-19 15:23:07 -0400429 for childDeviceID := range childDeviceIds {
Kent Hagermancba2f302020-07-28 13:37:36 -0400430 if searchDevice, err := dMgr.getDeviceReadOnly(ctx, childDeviceID); err == nil {
Matt Jeanneret2a20aaa2019-03-05 21:04:02 -0500431 if searchDevice.ProxyAddress == proxyAddress {
432 foundChildDevice = searchDevice
433 break
434 }
435 }
436 }
437
438 if foundChildDevice != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530439 logger.Debugw(ctx, "child-device-found", log.Fields{"proxy-address": proxyAddress})
Matt Jeanneret2a20aaa2019-03-05 21:04:02 -0500440 return foundChildDevice, nil
441 }
442
Himani Chawlab4c25912020-11-12 17:16:38 +0530443 logger.Warnw(ctx, "child-device-not-found", log.Fields{"proxy-address": proxyAddress})
Matt Jeanneret2a20aaa2019-03-05 21:04:02 -0500444 return nil, status.Errorf(codes.NotFound, "%s", proxyAddress)
445}
446
npujar1d86a522019-11-14 17:11:16 +0530447// IsDeviceInCache returns true if device is found in the map
Kent Hagerman2b216042020-04-03 18:28:56 -0400448func (dMgr *Manager) IsDeviceInCache(id string) bool {
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400449 _, exist := dMgr.deviceAgents.Load(id)
khenaidoo297cd252019-02-07 22:10:23 -0500450 return exist
451}
452
Stephane Barbarieaa467942019-02-06 14:09:44 -0500453// ListDevices retrieves the latest devices from the data model
Kent Hagerman45a13e42020-04-13 12:23:50 -0400454func (dMgr *Manager) ListDevices(ctx context.Context, _ *empty.Empty) (*voltha.Devices, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530455 ctx = utils.WithRPCMetadataContext(ctx, "ListDevices")
456 logger.Debug(ctx, "list-devices")
khenaidoob9203542018-09-17 22:56:37 -0400457 result := &voltha.Devices{}
Kent Hagerman4f355f52020-03-30 16:01:33 -0400458
Esin Karamana4e4e002021-03-02 10:42:16 +0000459 dMgr.deviceAgents.Range(func(key, value interface{}) bool {
460 result.Items = append(result.Items, value.(*Agent).device)
461 return true
462 })
Kent Hagerman4f355f52020-03-30 16:01:33 -0400463
Himani Chawlab4c25912020-11-12 17:16:38 +0530464 logger.Debugw(ctx, "list-devices-end", log.Fields{"len": len(result.Items)})
khenaidoob9203542018-09-17 22:56:37 -0400465 return result, nil
466}
467
Thomas Lee S51b5cb82019-10-14 14:49:34 +0530468//isParentDeviceExist checks whether device is already preprovisioned.
Kent Hagerman2b216042020-04-03 18:28:56 -0400469func (dMgr *Manager) isParentDeviceExist(ctx context.Context, newDevice *voltha.Device) (bool, error) {
Thomas Lee S51b5cb82019-10-14 14:49:34 +0530470 hostPort := newDevice.GetHostAndPort()
Kent Hagerman4f355f52020-03-30 16:01:33 -0400471 var devices []*voltha.Device
Kent Hagermanf5a67352020-04-30 15:15:26 -0400472 if err := dMgr.dProxy.List(ctx, &devices); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530473 logger.Errorw(ctx, "failed-to-list-devices-from-cluster-data-proxy", log.Fields{"error": err})
Thomas Lee Se5a44012019-11-07 20:32:24 +0530474 return false, err
475 }
Kent Hagerman4f355f52020-03-30 16:01:33 -0400476 for _, device := range devices {
477 if !device.Root {
478 continue
479 }
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530480
481 if hostPort != "" && hostPort == device.GetHostAndPort() {
Kent Hagerman4f355f52020-03-30 16:01:33 -0400482 return true, nil
483 }
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530484 if newDevice.MacAddress != "" && newDevice.MacAddress == device.MacAddress {
Kent Hagerman4f355f52020-03-30 16:01:33 -0400485 return true, nil
Thomas Lee S51b5cb82019-10-14 14:49:34 +0530486 }
487 }
Thomas Lee Se5a44012019-11-07 20:32:24 +0530488 return false, nil
Thomas Lee S51b5cb82019-10-14 14:49:34 +0530489}
490
khenaidoo6d62c002019-05-15 21:57:03 -0400491//getDeviceFromModelretrieves the device data from the model.
Kent Hagerman2b216042020-04-03 18:28:56 -0400492func (dMgr *Manager) getDeviceFromModel(ctx context.Context, deviceID string) (*voltha.Device, error) {
Kent Hagerman4f355f52020-03-30 16:01:33 -0400493 device := &voltha.Device{}
Kent Hagermanf5a67352020-04-30 15:15:26 -0400494 if have, err := dMgr.dProxy.Get(ctx, deviceID, device); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000495 logger.Errorw(ctx, "failed-to-get-device-info-from-cluster-proxy", log.Fields{"error": err})
Thomas Lee Se5a44012019-11-07 20:32:24 +0530496 return nil, err
Kent Hagerman4f355f52020-03-30 16:01:33 -0400497 } else if !have {
498 return nil, status.Error(codes.NotFound, deviceID)
Thomas Lee Se5a44012019-11-07 20:32:24 +0530499 }
Kent Hagerman4f355f52020-03-30 16:01:33 -0400500
501 return device, nil
khenaidoo6d62c002019-05-15 21:57:03 -0400502}
503
npujar1d86a522019-11-14 17:11:16 +0530504// loadDevice loads the deviceID in memory, if not present
Kent Hagerman2b216042020-04-03 18:28:56 -0400505func (dMgr *Manager) loadDevice(ctx context.Context, deviceID string) (*Agent, error) {
npujar1d86a522019-11-14 17:11:16 +0530506 if deviceID == "" {
khenaidoo297cd252019-02-07 22:10:23 -0500507 return nil, status.Error(codes.InvalidArgument, "deviceId empty")
508 }
khenaidoo4c9e5592019-09-09 16:20:41 -0400509 var err error
510 var device *voltha.Device
511 dMgr.devicesLoadingLock.Lock()
npujar1d86a522019-11-14 17:11:16 +0530512 if _, exist := dMgr.deviceLoadingInProgress[deviceID]; !exist {
513 if !dMgr.IsDeviceInCache(deviceID) {
514 dMgr.deviceLoadingInProgress[deviceID] = []chan int{make(chan int, 1)}
khenaidoo4c9e5592019-09-09 16:20:41 -0400515 dMgr.devicesLoadingLock.Unlock()
516 // Proceed with the loading only if the device exist in the Model (could have been deleted)
npujar467fe752020-01-16 20:17:45 +0530517 if device, err = dMgr.getDeviceFromModel(ctx, deviceID); err == nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000518 logger.Debugw(ctx, "loading-device", log.Fields{"device-id": deviceID})
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700519 agent := newAgent(dMgr.adapterProxy, device, dMgr, dMgr.dbPath, dMgr.dProxy, dMgr.defaultTimeout)
npujar467fe752020-01-16 20:17:45 +0530520 if _, err = agent.start(ctx, nil); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530521 logger.Warnw(ctx, "failure-loading-device", log.Fields{"device-id": deviceID, "error": err})
khenaidoo4c9e5592019-09-09 16:20:41 -0400522 } else {
523 dMgr.addDeviceAgentToMap(agent)
524 }
525 } else {
Himani Chawlab4c25912020-11-12 17:16:38 +0530526 logger.Debugw(ctx, "device-is-not-in-model", log.Fields{"device-id": deviceID})
khenaidoo6d62c002019-05-15 21:57:03 -0400527 }
khenaidoo4c9e5592019-09-09 16:20:41 -0400528 // announce completion of task to any number of waiting channels
529 dMgr.devicesLoadingLock.Lock()
npujar1d86a522019-11-14 17:11:16 +0530530 if v, ok := dMgr.deviceLoadingInProgress[deviceID]; ok {
khenaidoo4c9e5592019-09-09 16:20:41 -0400531 for _, ch := range v {
532 close(ch)
533 }
npujar1d86a522019-11-14 17:11:16 +0530534 delete(dMgr.deviceLoadingInProgress, deviceID)
khenaidoo4c9e5592019-09-09 16:20:41 -0400535 }
536 dMgr.devicesLoadingLock.Unlock()
khenaidoo6d62c002019-05-15 21:57:03 -0400537 } else {
khenaidoo4c9e5592019-09-09 16:20:41 -0400538 dMgr.devicesLoadingLock.Unlock()
khenaidoo297cd252019-02-07 22:10:23 -0500539 }
khenaidoo4c9e5592019-09-09 16:20:41 -0400540 } else {
541 ch := make(chan int, 1)
npujar1d86a522019-11-14 17:11:16 +0530542 dMgr.deviceLoadingInProgress[deviceID] = append(dMgr.deviceLoadingInProgress[deviceID], ch)
khenaidoo4c9e5592019-09-09 16:20:41 -0400543 dMgr.devicesLoadingLock.Unlock()
544 // Wait for the channel to be closed, implying the process loading this device is done.
545 <-ch
khenaidoo297cd252019-02-07 22:10:23 -0500546 }
npujar1d86a522019-11-14 17:11:16 +0530547 if agent, ok := dMgr.deviceAgents.Load(deviceID); ok {
Kent Hagerman2b216042020-04-03 18:28:56 -0400548 return agent.(*Agent), nil
khenaidoo297cd252019-02-07 22:10:23 -0500549 }
npujar1d86a522019-11-14 17:11:16 +0530550 return nil, status.Errorf(codes.Aborted, "Error loading device %s", deviceID)
khenaidoo297cd252019-02-07 22:10:23 -0500551}
552
553// loadRootDeviceParentAndChildren loads the children and parents of a root device in memory
Kent Hagerman2a07b862020-06-19 15:23:07 -0400554func (dMgr *Manager) loadRootDeviceParentAndChildren(ctx context.Context, device *voltha.Device, devicePorts map[uint32]*voltha.Port) error {
divyadesaicb8b59d2020-08-18 09:55:47 +0000555 logger.Debugw(ctx, "loading-parent-and-children", log.Fields{"device-id": device.Id})
khenaidoo297cd252019-02-07 22:10:23 -0500556 if device.Root {
557 // Scenario A
558 if device.ParentId != "" {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400559 // Load logical device if needed.
npujar467fe752020-01-16 20:17:45 +0530560 if err := dMgr.logicalDeviceMgr.load(ctx, device.ParentId); err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000561 logger.Warnw(ctx, "failure-loading-logical-device", log.Fields{"logical-device-id": device.ParentId})
khenaidoo297cd252019-02-07 22:10:23 -0500562 }
563 } else {
divyadesaicb8b59d2020-08-18 09:55:47 +0000564 logger.Debugw(ctx, "no-parent-to-load", log.Fields{"device-id": device.Id})
khenaidoo297cd252019-02-07 22:10:23 -0500565 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400566 // Load all child devices, if needed
567 childDeviceIds := dMgr.getAllChildDeviceIds(ctx, devicePorts)
568 for childDeviceID := range childDeviceIds {
569 if _, err := dMgr.loadDevice(ctx, childDeviceID); err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000570 logger.Warnw(ctx, "failure-loading-device", log.Fields{"device-id": childDeviceID, "error": err})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400571 return err
khenaidoo297cd252019-02-07 22:10:23 -0500572 }
khenaidoo297cd252019-02-07 22:10:23 -0500573 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530574 logger.Debugw(ctx, "loaded-children", log.Fields{"device-id": device.Id, "num-children": len(childDeviceIds)})
khenaidoo297cd252019-02-07 22:10:23 -0500575 }
576 return nil
577}
578
579// load loads the deviceId in memory, if not present, and also loads its accompanying parents and children. Loading
580// in memory is for improved performance. It is not imperative that a device needs to be in memory when a request
581// acting on the device is received by the core. In such a scenario, the Core will load the device in memory first
582// and the proceed with the request.
Kent Hagerman2b216042020-04-03 18:28:56 -0400583func (dMgr *Manager) load(ctx context.Context, deviceID string) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000584 logger.Debug(ctx, "load...")
khenaidoo297cd252019-02-07 22:10:23 -0500585 // 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 -0400586 var dAgent *Agent
khenaidoo297cd252019-02-07 22:10:23 -0500587 var err error
npujar467fe752020-01-16 20:17:45 +0530588 if dAgent, err = dMgr.loadDevice(ctx, deviceID); err != nil {
khenaidoo297cd252019-02-07 22:10:23 -0500589 return err
590 }
591 // Get the loaded device details
Kent Hagermancba2f302020-07-28 13:37:36 -0400592 device, err := dAgent.getDeviceReadOnly(ctx)
khenaidoo442e7c72020-03-10 16:13:48 -0400593 if err != nil {
594 return err
595 }
khenaidoo297cd252019-02-07 22:10:23 -0500596
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530597 // If the device is in Pre-provisioning or getting deleted state stop here
598 if device.AdminState == voltha.AdminState_PREPROVISIONED || dAgent.isDeletionInProgress() {
khenaidoo297cd252019-02-07 22:10:23 -0500599 return nil
600 }
601
602 // Now we face two scenarios
603 if device.Root {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400604 devicePorts := dAgent.listDevicePorts()
605
khenaidoo297cd252019-02-07 22:10:23 -0500606 // Load all children as well as the parent of this device (logical_device)
Kent Hagerman2a07b862020-06-19 15:23:07 -0400607 if err := dMgr.loadRootDeviceParentAndChildren(ctx, device, devicePorts); err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000608 logger.Warnw(ctx, "failure-loading-device-parent-and-children", log.Fields{"device-id": deviceID})
khenaidoo297cd252019-02-07 22:10:23 -0500609 return err
610 }
divyadesaicb8b59d2020-08-18 09:55:47 +0000611 logger.Debugw(ctx, "successfully-loaded-parent-and-children", log.Fields{"device-id": deviceID})
khenaidoo297cd252019-02-07 22:10:23 -0500612 } else {
613 // Scenario B - use the parentId of that device (root device) to trigger the loading
614 if device.ParentId != "" {
npujar467fe752020-01-16 20:17:45 +0530615 return dMgr.load(ctx, device.ParentId)
khenaidoo297cd252019-02-07 22:10:23 -0500616 }
617 }
618 return nil
619}
620
khenaidoo7ccedd52018-12-14 16:48:54 -0500621// ListDeviceIds retrieves the latest device IDs information from the data model (memory data only)
Rohan Agrawal31f21802020-06-12 05:38:46 +0000622func (dMgr *Manager) ListDeviceIds(ctx context.Context, _ *empty.Empty) (*voltha.IDs, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530623 ctx = utils.WithRPCMetadataContext(ctx, "ListDeviceIds")
624 logger.Debug(ctx, "list-device-ids")
khenaidoo7ccedd52018-12-14 16:48:54 -0500625 // Report only device IDs that are in the device agent map
626 return dMgr.listDeviceIdsFromMap(), nil
627}
628
Kent Hagerman45a13e42020-04-13 12:23:50 -0400629// ReconcileDevices is a request to a voltha core to update its list of managed devices. This will
630// trigger loading the devices along with their children and parent in memory
631func (dMgr *Manager) ReconcileDevices(ctx context.Context, ids *voltha.IDs) (*empty.Empty, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530632 ctx = utils.WithRPCMetadataContext(ctx, "ReconcileDevices")
633 logger.Debugw(ctx, "reconcile-devices", log.Fields{"num-devices": len(ids.Items)})
khenaidoo4c9e5592019-09-09 16:20:41 -0400634 if ids != nil && len(ids.Items) != 0 {
khenaidoo7ccedd52018-12-14 16:48:54 -0500635 toReconcile := len(ids.Items)
636 reconciled := 0
khenaidoo4c9e5592019-09-09 16:20:41 -0400637 var err error
khenaidoo7ccedd52018-12-14 16:48:54 -0500638 for _, id := range ids.Items {
npujar467fe752020-01-16 20:17:45 +0530639 if err = dMgr.load(ctx, id.Id); err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000640 logger.Warnw(ctx, "failure-reconciling-device", log.Fields{"device-id": id.Id, "error": err})
khenaidoo4c9e5592019-09-09 16:20:41 -0400641 } else {
npujar1d86a522019-11-14 17:11:16 +0530642 reconciled++
khenaidoo7ccedd52018-12-14 16:48:54 -0500643 }
644 }
645 if toReconcile != reconciled {
Kent Hagerman45a13e42020-04-13 12:23:50 -0400646 return nil, status.Errorf(codes.DataLoss, "less-device-reconciled-than-requested:%d/%d", reconciled, toReconcile)
khenaidoo7ccedd52018-12-14 16:48:54 -0500647 }
648 } else {
Kent Hagerman45a13e42020-04-13 12:23:50 -0400649 return nil, status.Errorf(codes.InvalidArgument, "empty-list-of-ids")
khenaidoo7ccedd52018-12-14 16:48:54 -0500650 }
Kent Hagerman45a13e42020-04-13 12:23:50 -0400651 return &empty.Empty{}, nil
khenaidoo7ccedd52018-12-14 16:48:54 -0500652}
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500653
khenaidooba6b6c42019-08-02 09:11:56 -0400654// isOkToReconcile validates whether a device is in the correct status to be reconciled
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530655func (dMgr *Manager) isOkToReconcile(ctx context.Context, device *voltha.Device) bool {
khenaidooba6b6c42019-08-02 09:11:56 -0400656 if device == nil {
657 return false
658 }
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530659 if agent := dMgr.getDeviceAgent(ctx, device.Id); agent != nil {
660 return device.AdminState != voltha.AdminState_PREPROVISIONED && (!agent.isDeletionInProgress())
661 }
662 return false
khenaidooba6b6c42019-08-02 09:11:56 -0400663}
664
665// adapterRestarted is invoked whenever an adapter is restarted
Kent Hagerman2b216042020-04-03 18:28:56 -0400666func (dMgr *Manager) adapterRestarted(ctx context.Context, adapter *voltha.Adapter) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530667 logger.Debugw(ctx, "adapter-restarted", log.Fields{"adapter-id": adapter.Id, "vendor": adapter.Vendor,
668 "current-replica": adapter.CurrentReplica, "total-replicas": adapter.TotalReplicas, "endpoint": adapter.Endpoint})
khenaidooba6b6c42019-08-02 09:11:56 -0400669
670 // Let's reconcile the device managed by this Core only
David Bainbridged1afd662020-03-26 18:27:41 -0700671 if len(dMgr.rootDevices) == 0 {
Himani Chawlab4c25912020-11-12 17:16:38 +0530672 logger.Debugw(ctx, "nothing-to-reconcile", log.Fields{"adapter-id": adapter.Id})
khenaidooba6b6c42019-08-02 09:11:56 -0400673 return nil
674 }
675
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500676 responses := make([]utils.Response, 0)
David Bainbridged1afd662020-03-26 18:27:41 -0700677 for rootDeviceID := range dMgr.rootDevices {
Mahir Gunyel12cf55f2020-12-16 17:55:03 -0800678 dAgent := dMgr.getDeviceAgent(ctx, rootDeviceID)
679 if dAgent == nil {
680 continue
681 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530682 logger.Debugw(ctx, "checking-adapter-type", log.Fields{"agentType": dAgent.deviceType, "adapter-type": adapter.Type})
Mahir Gunyel12cf55f2020-12-16 17:55:03 -0800683 if dAgent.deviceType == adapter.Type {
684 rootDevice, _ := dAgent.getDeviceReadOnly(ctx)
685 if rootDevice == nil {
686 continue
687 }
Rohan Agrawal31f21802020-06-12 05:38:46 +0000688 isDeviceOwnedByService, err := dMgr.adapterProxy.IsDeviceOwnedByService(ctx, rootDeviceID, adapter.Type, adapter.CurrentReplica)
serkant.uluderya7d545aa2020-04-09 13:38:45 -0700689 if err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530690 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 -0700691 continue
692 }
693 if isDeviceOwnedByService {
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530694 if dMgr.isOkToReconcile(ctx, rootDevice) {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000695 logger.Debugw(ctx, "reconciling-root-device", log.Fields{"rootId": rootDevice.Id})
npujar467fe752020-01-16 20:17:45 +0530696 responses = append(responses, dMgr.sendReconcileDeviceRequest(ctx, rootDevice))
khenaidooba6b6c42019-08-02 09:11:56 -0400697 } else {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000698 logger.Debugw(ctx, "not-reconciling-root-device", log.Fields{"rootId": rootDevice.Id, "state": rootDevice.AdminState})
khenaidooba6b6c42019-08-02 09:11:56 -0400699 }
700 } else { // Should we be reconciling the root's children instead?
Kent Hagerman2a07b862020-06-19 15:23:07 -0400701 rootDevicePorts, _ := dMgr.listDevicePorts(ctx, rootDeviceID)
khenaidooba6b6c42019-08-02 09:11:56 -0400702 childManagedByAdapter:
Kent Hagerman2a07b862020-06-19 15:23:07 -0400703 for _, port := range rootDevicePorts {
khenaidooba6b6c42019-08-02 09:11:56 -0400704 for _, peer := range port.Peers {
npujar467fe752020-01-16 20:17:45 +0530705 if childDevice, _ := dMgr.getDeviceFromModel(ctx, peer.DeviceId); childDevice != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000706 isDeviceOwnedByService, err := dMgr.adapterProxy.IsDeviceOwnedByService(ctx, childDevice.Id, adapter.Type, adapter.CurrentReplica)
serkant.uluderya7d545aa2020-04-09 13:38:45 -0700707 if err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530708 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 -0700709 }
710 if isDeviceOwnedByService {
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530711 if dMgr.isOkToReconcile(ctx, childDevice) {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000712 logger.Debugw(ctx, "reconciling-child-device", log.Fields{"child-device-id": childDevice.Id})
npujar467fe752020-01-16 20:17:45 +0530713 responses = append(responses, dMgr.sendReconcileDeviceRequest(ctx, childDevice))
khenaidooba6b6c42019-08-02 09:11:56 -0400714 } else {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000715 logger.Debugw(ctx, "not-reconciling-child-device", log.Fields{"child-device-id": childDevice.Id, "state": childDevice.AdminState})
khenaidooba6b6c42019-08-02 09:11:56 -0400716 }
717 } else {
718 // All child devices under a parent device are typically managed by the same adapter type.
719 // Therefore we only need to check whether the first device we retrieved is managed by that adapter
720 break childManagedByAdapter
721 }
722 }
723 }
724 }
725 }
726 }
727 }
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500728 if len(responses) > 0 {
khenaidooba6b6c42019-08-02 09:11:56 -0400729 // Wait for completion
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500730 if res := utils.WaitForNilOrErrorResponses(dMgr.defaultTimeout, responses...); res != nil {
khenaidooba6b6c42019-08-02 09:11:56 -0400731 return status.Errorf(codes.Aborted, "errors-%s", res)
732 }
733 } else {
Himani Chawlab4c25912020-11-12 17:16:38 +0530734 logger.Debugw(ctx, "no-managed-device-to-reconcile", log.Fields{"adapter-id": adapter.Id})
khenaidooba6b6c42019-08-02 09:11:56 -0400735 }
736 return nil
737}
738
Kent Hagerman2b216042020-04-03 18:28:56 -0400739func (dMgr *Manager) sendReconcileDeviceRequest(ctx context.Context, device *voltha.Device) utils.Response {
khenaidooba6b6c42019-08-02 09:11:56 -0400740 // Send a reconcile request to the adapter. Since this Core may not be managing this device then there is no
741 // point of creating a device agent (if the device is not being managed by this Core) before sending the request
npujar1d86a522019-11-14 17:11:16 +0530742 // to the adapter. We will therefore bypass the adapter adapter and send the request directly to the adapter via
Kent Hagerman2b216042020-04-03 18:28:56 -0400743 // the adapter proxy.
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500744 response := utils.NewResponse()
Kent Hagerman2b216042020-04-03 18:28:56 -0400745 ch, err := dMgr.adapterProxy.ReconcileDevice(ctx, device)
khenaidoo442e7c72020-03-10 16:13:48 -0400746 if err != nil {
747 response.Error(err)
748 }
749 // Wait for adapter response in its own routine
750 go func() {
751 resp, ok := <-ch
752 if !ok {
753 response.Error(status.Errorf(codes.Aborted, "channel-closed-device: %s", device.Id))
754 } else if resp.Err != nil {
755 response.Error(resp.Err)
khenaidooba6b6c42019-08-02 09:11:56 -0400756 }
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500757 response.Done()
khenaidoo442e7c72020-03-10 16:13:48 -0400758 }()
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500759 return response
khenaidooba6b6c42019-08-02 09:11:56 -0400760}
761
Kent Hagerman2b216042020-04-03 18:28:56 -0400762func (dMgr *Manager) ReconcileChildDevices(ctx context.Context, parentDeviceID string) error {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400763 if parentDevicePorts, err := dMgr.listDevicePorts(ctx, parentDeviceID); err == nil {
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500764 responses := make([]utils.Response, 0)
Kent Hagerman2a07b862020-06-19 15:23:07 -0400765 for _, port := range parentDevicePorts {
khenaidooba6b6c42019-08-02 09:11:56 -0400766 for _, peer := range port.Peers {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400767 if childDevice, err := dMgr.getDeviceFromModel(ctx, peer.DeviceId); err == nil {
npujar467fe752020-01-16 20:17:45 +0530768 responses = append(responses, dMgr.sendReconcileDeviceRequest(ctx, childDevice))
khenaidooba6b6c42019-08-02 09:11:56 -0400769 }
770 }
771 }
772 // Wait for completion
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500773 if res := utils.WaitForNilOrErrorResponses(dMgr.defaultTimeout, responses...); res != nil {
khenaidooba6b6c42019-08-02 09:11:56 -0400774 return status.Errorf(codes.Aborted, "errors-%s", res)
775 }
776 }
777 return nil
778}
779
Kent Hagerman2b216042020-04-03 18:28:56 -0400780func (dMgr *Manager) UpdateDeviceUsingAdapterData(ctx context.Context, device *voltha.Device) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530781 logger.Debugw(ctx, "update-device-using-adapter-data", log.Fields{"device-id": device.Id, "device": device})
npujar467fe752020-01-16 20:17:45 +0530782 if agent := dMgr.getDeviceAgent(ctx, device.Id); agent != nil {
783 return agent.updateDeviceUsingAdapterData(ctx, device)
khenaidoob9203542018-09-17 22:56:37 -0400784 }
785 return status.Errorf(codes.NotFound, "%s", device.Id)
786}
787
khenaidoo0db4c812020-05-27 15:27:30 -0400788func (dMgr *Manager) addPeerPort(ctx context.Context, deviceID string, port *voltha.Port) error {
789 meAsPeer := &voltha.Port_PeerPort{DeviceId: deviceID, PortNo: port.PortNo}
790 for _, peerPort := range port.Peers {
791 if agent := dMgr.getDeviceAgent(ctx, peerPort.DeviceId); agent != nil {
792 if err := agent.addPeerPort(ctx, meAsPeer); err != nil {
793 return err
794 }
795 }
796 }
797 // Notify the logical device manager to setup a logical port, if needed. If the added port is an NNI or UNI
798 // then a logical port will be added to the logical device and the device route generated. If the port is a
799 // PON port then only the device graph will be generated.
Kent Hagermancba2f302020-07-28 13:37:36 -0400800 device, err := dMgr.getDeviceReadOnly(ctx, deviceID)
khenaidoo0db4c812020-05-27 15:27:30 -0400801 if err != nil {
802 return err
803 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400804 ports, err := dMgr.listDevicePorts(ctx, deviceID)
805 if err != nil {
806 return err
807 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530808 subCtx := utils.WithSpanAndRPCMetadataFromContext(ctx)
809
810 if err = dMgr.logicalDeviceMgr.updateLogicalPort(subCtx, device, ports, port); err != nil {
khenaidoo0db4c812020-05-27 15:27:30 -0400811 return err
812 }
813 return nil
814}
815
Kent Hagerman2b216042020-04-03 18:28:56 -0400816func (dMgr *Manager) AddPort(ctx context.Context, deviceID string, port *voltha.Port) error {
npujar467fe752020-01-16 20:17:45 +0530817 agent := dMgr.getDeviceAgent(ctx, deviceID)
npujar1d86a522019-11-14 17:11:16 +0530818 if agent != nil {
npujar467fe752020-01-16 20:17:45 +0530819 if err := agent.addPort(ctx, port); err != nil {
khenaidoo92e62c52018-10-03 14:02:54 -0400820 return err
821 }
khenaidoo0db4c812020-05-27 15:27:30 -0400822 // Setup peer ports in its own routine
823 go func() {
Himani Chawlab4c25912020-11-12 17:16:38 +0530824 subCtx := utils.WithSpanAndRPCMetadataFromContext(ctx)
825 if err := dMgr.addPeerPort(subCtx, deviceID, port); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000826 logger.Errorw(ctx, "unable-to-add-peer-port", log.Fields{"error": err, "device-id": deviceID})
khenaidoo92e62c52018-10-03 14:02:54 -0400827 }
khenaidoo0db4c812020-05-27 15:27:30 -0400828 }()
khenaidoo92e62c52018-10-03 14:02:54 -0400829 return nil
khenaidoob9203542018-09-17 22:56:37 -0400830 }
npujar1d86a522019-11-14 17:11:16 +0530831 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoob9203542018-09-17 22:56:37 -0400832}
833
Kent Hagerman2b216042020-04-03 18:28:56 -0400834func (dMgr *Manager) addFlowsAndGroups(ctx context.Context, deviceID string, flows []*ofp.OfpFlowStats, groups []*ofp.OfpGroupEntry, flowMetadata *voltha.FlowMetadata) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530835 logger.Debugw(ctx, "add-flows-and-groups", log.Fields{"device-id": deviceID, "groups:": groups, "flow-metadata": flowMetadata})
npujar467fe752020-01-16 20:17:45 +0530836 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
837 return agent.addFlowsAndGroups(ctx, flows, groups, flowMetadata)
khenaidoo0458db62019-06-20 08:50:36 -0400838 }
npujar1d86a522019-11-14 17:11:16 +0530839 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo0458db62019-06-20 08:50:36 -0400840}
841
khenaidoo787224a2020-04-16 18:08:47 -0400842// deleteParentFlows removes flows from the parent device based on specific attributes
843func (dMgr *Manager) deleteParentFlows(ctx context.Context, deviceID string, uniPort uint32, metadata *voltha.FlowMetadata) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530844 logger.Debugw(ctx, "delete-parent-flows", log.Fields{"device-id": deviceID, "uni-port": uniPort, "metadata": metadata})
khenaidoo787224a2020-04-16 18:08:47 -0400845 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400846 if !agent.isRootDevice {
khenaidoo787224a2020-04-16 18:08:47 -0400847 return status.Errorf(codes.FailedPrecondition, "not-a-parent-device-%s", deviceID)
848 }
849 return agent.filterOutFlows(ctx, uniPort, metadata)
850 }
851 return status.Errorf(codes.NotFound, "%s", deviceID)
852}
853
Kent Hagerman2b216042020-04-03 18:28:56 -0400854func (dMgr *Manager) deleteFlowsAndGroups(ctx context.Context, deviceID string, flows []*ofp.OfpFlowStats, groups []*ofp.OfpGroupEntry, flowMetadata *voltha.FlowMetadata) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530855 logger.Debugw(ctx, "delete-flows-and-groups", log.Fields{"device-id": deviceID})
npujar467fe752020-01-16 20:17:45 +0530856 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
857 return agent.deleteFlowsAndGroups(ctx, flows, groups, flowMetadata)
khenaidoo0458db62019-06-20 08:50:36 -0400858 }
npujar1d86a522019-11-14 17:11:16 +0530859 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo0458db62019-06-20 08:50:36 -0400860}
861
Kent Hagerman2b216042020-04-03 18:28:56 -0400862func (dMgr *Manager) updateFlowsAndGroups(ctx context.Context, deviceID string, flows []*ofp.OfpFlowStats, groups []*ofp.OfpGroupEntry, flowMetadata *voltha.FlowMetadata) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530863 logger.Debugw(ctx, "update-flows-and-groups", log.Fields{"device-id": deviceID})
npujar467fe752020-01-16 20:17:45 +0530864 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
865 return agent.updateFlowsAndGroups(ctx, flows, groups, flowMetadata)
khenaidoo19d7b632018-10-30 10:49:50 -0400866 }
npujar1d86a522019-11-14 17:11:16 +0530867 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo19d7b632018-10-30 10:49:50 -0400868}
869
Kent Hagerman45a13e42020-04-13 12:23:50 -0400870// UpdateDevicePmConfigs updates the PM configs. This is executed when the northbound gRPC API is invoked, typically
khenaidoob3127472019-07-24 21:04:55 -0400871// following a user action
Kent Hagerman45a13e42020-04-13 12:23:50 -0400872func (dMgr *Manager) UpdateDevicePmConfigs(ctx context.Context, configs *voltha.PmConfigs) (*empty.Empty, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530873 ctx = utils.WithRPCMetadataContext(ctx, "UpdateDevicePmConfigs")
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000874 log.EnrichSpan(ctx, log.Fields{"device-id": configs.Id})
Kent Hagerman45a13e42020-04-13 12:23:50 -0400875 if configs.Id == "" {
876 return nil, status.Error(codes.FailedPrecondition, "invalid-device-Id")
khenaidoob3127472019-07-24 21:04:55 -0400877 }
Kent Hagerman45a13e42020-04-13 12:23:50 -0400878 agent := dMgr.getDeviceAgent(ctx, configs.Id)
879 if agent == nil {
880 return nil, status.Errorf(codes.NotFound, "%s", configs.Id)
881 }
882 return &empty.Empty{}, agent.updatePmConfigs(ctx, configs)
khenaidoob3127472019-07-24 21:04:55 -0400883}
884
Kent Hagerman2b216042020-04-03 18:28:56 -0400885// InitPmConfigs initialize the pm configs as defined by the adapter.
886func (dMgr *Manager) InitPmConfigs(ctx context.Context, deviceID string, pmConfigs *voltha.PmConfigs) error {
khenaidoob3127472019-07-24 21:04:55 -0400887 if pmConfigs.Id == "" {
888 return status.Errorf(codes.FailedPrecondition, "invalid-device-Id")
889 }
npujar467fe752020-01-16 20:17:45 +0530890 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
891 return agent.initPmConfigs(ctx, pmConfigs)
khenaidoob9203542018-09-17 22:56:37 -0400892 }
npujar1d86a522019-11-14 17:11:16 +0530893 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoob9203542018-09-17 22:56:37 -0400894}
895
Kent Hagerman45a13e42020-04-13 12:23:50 -0400896// ListDevicePmConfigs returns pm configs of device
897func (dMgr *Manager) ListDevicePmConfigs(ctx context.Context, id *voltha.ID) (*voltha.PmConfigs, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530898 ctx = utils.WithRPCMetadataContext(ctx, "ListDevicePmConfigs")
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000899 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
Kent Hagerman45a13e42020-04-13 12:23:50 -0400900 agent := dMgr.getDeviceAgent(ctx, id.Id)
901 if agent == nil {
902 return nil, status.Errorf(codes.NotFound, "%s", id.Id)
khenaidoob3127472019-07-24 21:04:55 -0400903 }
Kent Hagerman45a13e42020-04-13 12:23:50 -0400904 return agent.listPmConfigs(ctx)
khenaidoob3127472019-07-24 21:04:55 -0400905}
906
Kent Hagerman2b216042020-04-03 18:28:56 -0400907func (dMgr *Manager) getSwitchCapability(ctx context.Context, deviceID string) (*ic.SwitchCapability, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530908 logger.Debugw(ctx, "get-switch-capability", log.Fields{"device-id": deviceID})
npujar467fe752020-01-16 20:17:45 +0530909 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
khenaidoob9203542018-09-17 22:56:37 -0400910 return agent.getSwitchCapability(ctx)
911 }
npujar1d86a522019-11-14 17:11:16 +0530912 return nil, status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoob9203542018-09-17 22:56:37 -0400913}
914
Kent Hagerman2b216042020-04-03 18:28:56 -0400915func (dMgr *Manager) GetPorts(ctx context.Context, deviceID string, portType voltha.Port_PortType) (*voltha.Ports, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530916 logger.Debugw(ctx, "get-ports", log.Fields{"device-id": deviceID, "port-type": portType})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400917 agent := dMgr.getDeviceAgent(ctx, deviceID)
918 if agent == nil {
919 return nil, status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoob9203542018-09-17 22:56:37 -0400920 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400921 return agent.getPorts(ctx, portType), nil
khenaidoob9203542018-09-17 22:56:37 -0400922}
923
Kent Hagerman2b216042020-04-03 18:28:56 -0400924func (dMgr *Manager) UpdateDeviceStatus(ctx context.Context, deviceID string, operStatus voltha.OperStatus_Types, connStatus voltha.ConnectStatus_Types) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530925 logger.Debugw(ctx, "update-device-status", log.Fields{"device-id": deviceID, "oper-status": operStatus, "conn-status": connStatus})
npujar467fe752020-01-16 20:17:45 +0530926 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
927 return agent.updateDeviceStatus(ctx, operStatus, connStatus)
khenaidoo92e62c52018-10-03 14:02:54 -0400928 }
npujar1d86a522019-11-14 17:11:16 +0530929 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo92e62c52018-10-03 14:02:54 -0400930}
931
Kent Hagerman2b216042020-04-03 18:28:56 -0400932func (dMgr *Manager) UpdateChildrenStatus(ctx context.Context, deviceID string, operStatus voltha.OperStatus_Types, connStatus voltha.ConnectStatus_Types) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530933 logger.Debugw(ctx, "update-children-status", log.Fields{"parent-device-id": deviceID, "oper-status": operStatus, "conn-status": connStatus})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400934 parentDevicePorts, err := dMgr.listDevicePorts(ctx, deviceID)
935 if err != nil {
khenaidoo4d4802d2018-10-04 21:59:49 -0400936 return status.Errorf(codes.Aborted, "%s", err.Error())
937 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400938 for childDeviceID := range dMgr.getAllChildDeviceIds(ctx, parentDevicePorts) {
npujar467fe752020-01-16 20:17:45 +0530939 if agent := dMgr.getDeviceAgent(ctx, childDeviceID); agent != nil {
940 if err = agent.updateDeviceStatus(ctx, operStatus, connStatus); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530941 return status.Errorf(codes.Aborted, "childDevice:%s, error:%s", childDeviceID, err.Error())
khenaidoo4d4802d2018-10-04 21:59:49 -0400942 }
943 }
944 }
945 return nil
946}
947
Kent Hagerman2b216042020-04-03 18:28:56 -0400948func (dMgr *Manager) UpdatePortState(ctx context.Context, deviceID string, portType voltha.Port_PortType, portNo uint32, operStatus voltha.OperStatus_Types) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530949 logger.Debugw(ctx, "update-port-state", log.Fields{"device-id": deviceID, "port-type": portType, "port-no": portNo, "oper-status": operStatus})
npujar467fe752020-01-16 20:17:45 +0530950 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
951 if err := agent.updatePortState(ctx, portType, portNo, operStatus); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530952 logger.Errorw(ctx, "updating-port-state-failed", log.Fields{"device-id": deviceID, "port-no": portNo, "error": err})
khenaidoo171b98e2019-10-31 11:48:15 -0400953 return err
954 }
955 // Notify the logical device manager to change the port state
Mahir Gunyel18fa0c92020-03-06 13:34:04 -0800956 // Do this for NNI and UNIs only. PON ports are not known by logical device
957 if portType == voltha.Port_ETHERNET_NNI || portType == voltha.Port_ETHERNET_UNI {
958 go func() {
Himani Chawlab4c25912020-11-12 17:16:38 +0530959 subCtx := utils.WithSpanAndRPCMetadataFromContext(ctx)
960 err := dMgr.logicalDeviceMgr.updatePortState(subCtx, deviceID, portNo, operStatus)
Mahir Gunyel18fa0c92020-03-06 13:34:04 -0800961 if err != nil {
962 // While we want to handle (catch) and log when
963 // an update to a port was not able to be
964 // propagated to the logical port, we can report
965 // it as a warning and not an error because it
966 // doesn't stop or modify processing.
967 // TODO: VOL-2707
Rohan Agrawal31f21802020-06-12 05:38:46 +0000968 logger.Warnw(ctx, "unable-to-update-logical-port-state", log.Fields{"error": err})
Mahir Gunyel18fa0c92020-03-06 13:34:04 -0800969 }
970 }()
971 }
khenaidoo442e7c72020-03-10 16:13:48 -0400972 return nil
khenaidoob9203542018-09-17 22:56:37 -0400973 }
npujar1d86a522019-11-14 17:11:16 +0530974 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoob9203542018-09-17 22:56:37 -0400975}
976
Kent Hagerman2b216042020-04-03 18:28:56 -0400977func (dMgr *Manager) DeleteAllPorts(ctx context.Context, deviceID string) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530978 logger.Debugw(ctx, "delete-all-ports", log.Fields{"device-id": deviceID})
npujar467fe752020-01-16 20:17:45 +0530979 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
980 if err := agent.deleteAllPorts(ctx); err != nil {
khenaidoo0a822f92019-05-08 15:15:57 -0400981 return err
982 }
983 // Notify the logical device manager to remove all logical ports, if needed.
Kent Hagerman2b216042020-04-03 18:28:56 -0400984 // At this stage the device itself may gave been deleted already at a DeleteAllPorts
khenaidoo0a822f92019-05-08 15:15:57 -0400985 // typically is part of a device deletion phase.
Kent Hagermancba2f302020-07-28 13:37:36 -0400986 if device, err := dMgr.getDeviceReadOnly(ctx, deviceID); err == nil {
npujar1d86a522019-11-14 17:11:16 +0530987 go func() {
Himani Chawlab4c25912020-11-12 17:16:38 +0530988 subCtx := utils.WithSpanAndRPCMetadataFromContext(ctx)
989 if err := dMgr.logicalDeviceMgr.deleteAllLogicalPorts(subCtx, device); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000990 logger.Errorw(ctx, "unable-to-delete-logical-ports", log.Fields{"error": err})
npujar1d86a522019-11-14 17:11:16 +0530991 }
992 }()
khenaidoo0a822f92019-05-08 15:15:57 -0400993 } else {
divyadesaicb8b59d2020-08-18 09:55:47 +0000994 logger.Warnw(ctx, "failed-to-retrieve-device", log.Fields{"device-id": deviceID})
khenaidoo0a822f92019-05-08 15:15:57 -0400995 return err
996 }
997 return nil
998 }
npujar1d86a522019-11-14 17:11:16 +0530999 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo0a822f92019-05-08 15:15:57 -04001000}
1001
Kent Hagerman2b216042020-04-03 18:28:56 -04001002//UpdatePortsState updates all ports on the device
Kent Hagerman2a07b862020-06-19 15:23:07 -04001003func (dMgr *Manager) UpdatePortsState(ctx context.Context, deviceID string, portTypeFilter uint32, state voltha.OperStatus_Types) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301004 logger.Debugw(ctx, "update-ports-state", log.Fields{"device-id": deviceID})
Kent Hagerman2a07b862020-06-19 15:23:07 -04001005 agent := dMgr.getDeviceAgent(ctx, deviceID)
1006 if agent == nil {
1007 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo3ab34882019-05-02 21:33:30 -04001008 }
Kent Hagerman2a07b862020-06-19 15:23:07 -04001009 if state != voltha.OperStatus_ACTIVE && state != voltha.OperStatus_UNKNOWN {
1010 return status.Error(codes.Unimplemented, "state-change-not-implemented")
1011 }
1012 if err := agent.updatePortsOperState(ctx, portTypeFilter, state); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +05301013 logger.Warnw(ctx, "update-ports-state-failed", log.Fields{"device-id": deviceID, "error": err})
Kent Hagerman2a07b862020-06-19 15:23:07 -04001014 return err
1015 }
1016 return nil
khenaidoo3ab34882019-05-02 21:33:30 -04001017}
1018
Kent Hagerman2b216042020-04-03 18:28:56 -04001019func (dMgr *Manager) ChildDeviceDetected(ctx context.Context, parentDeviceID string, parentPortNo int64, deviceType string,
npujar1d86a522019-11-14 17:11:16 +05301020 channelID int64, vendorID string, serialNumber string, onuID int64) (*voltha.Device, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301021 logger.Debugw(ctx, "child-device-detected", log.Fields{"parent-device-id": parentDeviceID, "parent-port-no": parentPortNo, "device-type": deviceType, "channel-id": channelID, "vendor-id": vendorID, "serial-number": serialNumber, "onu-id": onuID})
Chaitrashree G S4b3fada2019-07-28 23:55:25 -07001022
npujar1d86a522019-11-14 17:11:16 +05301023 if deviceType == "" && vendorID != "" {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001024 logger.Debug(ctx, "device-type-is-nil-fetching-device-type")
Kent Hagerman45a13e42020-04-13 12:23:50 -04001025 deviceTypes, err := dMgr.adapterMgr.ListDeviceTypes(ctx, nil)
1026 if err != nil {
1027 return nil, err
1028 }
Kent Hagerman4f355f52020-03-30 16:01:33 -04001029 OLoop:
Kent Hagerman45a13e42020-04-13 12:23:50 -04001030 for _, dType := range deviceTypes.Items {
Kent Hagerman4f355f52020-03-30 16:01:33 -04001031 for _, v := range dType.VendorIds {
1032 if v == vendorID {
1033 deviceType = dType.Adapter
1034 break OLoop
Chaitrashree G S4b3fada2019-07-28 23:55:25 -07001035 }
1036 }
1037 }
1038 }
1039 //if no match found for the vendorid,report adapter with the custom error message
1040 if deviceType == "" {
Himani Chawlab4c25912020-11-12 17:16:38 +05301041 logger.Errorw(ctx, "failed-to-fetch-adapter-name ", log.Fields{"vendor-id": vendorID})
npujar1d86a522019-11-14 17:11:16 +05301042 return nil, status.Errorf(codes.NotFound, "%s", vendorID)
Chaitrashree G S4b3fada2019-07-28 23:55:25 -07001043 }
khenaidoob9203542018-09-17 22:56:37 -04001044
1045 // Create the ONU device
1046 childDevice := &voltha.Device{}
khenaidoob9203542018-09-17 22:56:37 -04001047 childDevice.Type = deviceType
npujar1d86a522019-11-14 17:11:16 +05301048 childDevice.ParentId = parentDeviceID
khenaidoob9203542018-09-17 22:56:37 -04001049 childDevice.ParentPortNo = uint32(parentPortNo)
npujar1d86a522019-11-14 17:11:16 +05301050 childDevice.VendorId = vendorID
Matt Jeanneret4e241952019-02-28 11:16:04 -05001051 childDevice.SerialNumber = serialNumber
khenaidoob9203542018-09-17 22:56:37 -04001052 childDevice.Root = false
khenaidoo6fdf0ba2018-11-02 14:38:33 -04001053
khenaidoo442e7c72020-03-10 16:13:48 -04001054 // Get parent device type
1055 pAgent := dMgr.getDeviceAgent(ctx, parentDeviceID)
1056 if pAgent == nil {
npujar1d86a522019-11-14 17:11:16 +05301057 return nil, status.Errorf(codes.NotFound, "%s", parentDeviceID)
khenaidoo6fdf0ba2018-11-02 14:38:33 -04001058 }
khenaidoo442e7c72020-03-10 16:13:48 -04001059 if pAgent.deviceType == "" {
1060 return nil, status.Errorf(codes.FailedPrecondition, "device Type not set %s", parentDeviceID)
1061 }
khenaidoo6fdf0ba2018-11-02 14:38:33 -04001062
npujar467fe752020-01-16 20:17:45 +05301063 if device, err := dMgr.GetChildDevice(ctx, parentDeviceID, serialNumber, onuID, parentPortNo); err == nil {
Himani Chawlab4c25912020-11-12 17:16:38 +05301064 logger.Warnw(ctx, "child-device-exists", log.Fields{"parent-device-id": parentDeviceID, "serial-number": serialNumber})
Mahir Gunyel6deaa242019-06-27 04:53:33 -07001065 return device, status.Errorf(codes.AlreadyExists, "%s", serialNumber)
Matt Jeanneret4e241952019-02-28 11:16:04 -05001066 }
1067
khenaidoo442e7c72020-03-10 16:13:48 -04001068 childDevice.ProxyAddress = &voltha.Device_ProxyAddress{DeviceId: parentDeviceID, DeviceType: pAgent.deviceType, ChannelId: uint32(channelID), OnuId: uint32(onuID)}
khenaidoob9203542018-09-17 22:56:37 -04001069
1070 // Create and start a device agent for that device
Mahir Gunyel03de0d32020-06-03 01:36:59 -07001071 agent := newAgent(dMgr.adapterProxy, childDevice, dMgr, dMgr.dbPath, dMgr.dProxy, dMgr.defaultTimeout)
Mahir Gunyel23bd8c72020-09-21 23:20:43 -07001072 insertedChildDevice, err := agent.start(ctx, childDevice)
Scott Baker80678602019-11-14 16:57:36 -08001073 if err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001074 logger.Errorw(ctx, "error-starting-child-device", log.Fields{"parent-device-id": childDevice.ParentId, "child-device-id": agent.deviceID, "error": err})
Scott Baker80678602019-11-14 16:57:36 -08001075 return nil, err
1076 }
khenaidoo442e7c72020-03-10 16:13:48 -04001077 dMgr.addDeviceAgentToMap(agent)
khenaidoob9203542018-09-17 22:56:37 -04001078
1079 // Activate the child device
npujar467fe752020-01-16 20:17:45 +05301080 if agent = dMgr.getDeviceAgent(ctx, agent.deviceID); agent != nil {
npujar1d86a522019-11-14 17:11:16 +05301081 go func() {
Maninder9a1bc0d2020-10-26 11:34:02 +05301082 subCtx := utils.WithFromTopicMetadataFromContext(utils.WithSpanAndRPCMetadataFromContext(ctx), ctx)
Himani Chawlab4c25912020-11-12 17:16:38 +05301083 err := agent.enableDevice(subCtx)
npujar1d86a522019-11-14 17:11:16 +05301084 if err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001085 logger.Errorw(ctx, "unable-to-enable-device", log.Fields{"error": err})
npujar1d86a522019-11-14 17:11:16 +05301086 }
1087 }()
khenaidoob9203542018-09-17 22:56:37 -04001088 }
1089
Mahir Gunyel23bd8c72020-09-21 23:20:43 -07001090 return insertedChildDevice, nil
khenaidoob9203542018-09-17 22:56:37 -04001091}
1092
Kent Hagerman2b216042020-04-03 18:28:56 -04001093func (dMgr *Manager) packetOut(ctx context.Context, deviceID string, outPort uint32, packet *ofp.OfpPacketOut) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301094 logger.Debugw(ctx, "packet-out", log.Fields{"device-id": deviceID, "out-port": outPort})
npujar467fe752020-01-16 20:17:45 +05301095 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
1096 return agent.packetOut(ctx, outPort, packet)
khenaidoofdbad6e2018-11-06 22:26:38 -05001097 }
npujar1d86a522019-11-14 17:11:16 +05301098 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoofdbad6e2018-11-06 22:26:38 -05001099}
1100
npujar1d86a522019-11-14 17:11:16 +05301101// PacketIn receives packet from adapter
Kent Hagerman2b216042020-04-03 18:28:56 -04001102func (dMgr *Manager) PacketIn(ctx context.Context, deviceID string, port uint32, transactionID string, packet []byte) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301103 logger.Debugw(ctx, "packet-in", log.Fields{"device-id": deviceID, "port": port})
khenaidoofdbad6e2018-11-06 22:26:38 -05001104 // Get the logical device Id based on the deviceId
1105 var device *voltha.Device
1106 var err error
Kent Hagermancba2f302020-07-28 13:37:36 -04001107 if device, err = dMgr.getDeviceReadOnly(ctx, deviceID); err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +00001108 logger.Errorw(ctx, "device-not-found", log.Fields{"device-id": deviceID})
khenaidoofdbad6e2018-11-06 22:26:38 -05001109 return err
1110 }
khenaidoo43c82122018-11-22 18:38:28 -05001111 if !device.Root {
divyadesaicb8b59d2020-08-18 09:55:47 +00001112 logger.Errorw(ctx, "device-not-root", log.Fields{"device-id": deviceID})
npujar1d86a522019-11-14 17:11:16 +05301113 return status.Errorf(codes.FailedPrecondition, "%s", deviceID)
khenaidoofdbad6e2018-11-06 22:26:38 -05001114 }
1115
npujar467fe752020-01-16 20:17:45 +05301116 if err := dMgr.logicalDeviceMgr.packetIn(ctx, device.ParentId, port, transactionID, packet); err != nil {
khenaidoofdbad6e2018-11-06 22:26:38 -05001117 return err
1118 }
1119 return nil
1120}
1121
Kent Hagerman2b216042020-04-03 18:28:56 -04001122func (dMgr *Manager) setParentID(ctx context.Context, device *voltha.Device, parentID string) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301123 logger.Debugw(ctx, "set-parent-id", log.Fields{"device-id": device.Id, "parent-id": parentID})
npujar467fe752020-01-16 20:17:45 +05301124 if agent := dMgr.getDeviceAgent(ctx, device.Id); agent != nil {
1125 return agent.setParentID(ctx, device, parentID)
khenaidooad06fd72019-10-28 12:26:05 -04001126 }
1127 return status.Errorf(codes.NotFound, "%s", device.Id)
1128}
1129
Himani Chawlab4c25912020-11-12 17:16:38 +05301130//
1131//CreateLogicalDevice creates logical device in core
Kent Hagerman2b216042020-04-03 18:28:56 -04001132func (dMgr *Manager) CreateLogicalDevice(ctx context.Context, cDevice *voltha.Device) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301133 logger.Info(ctx, "create-logical-device")
khenaidoo59ef7be2019-06-21 12:40:28 -04001134 // Verify whether the logical device has already been created
1135 if cDevice.ParentId != "" {
Himani Chawlab4c25912020-11-12 17:16:38 +05301136 logger.Debugw(ctx, "parent-device-already-exist", log.Fields{"device-id": cDevice.Id, "logical-device-id": cDevice.Id})
khenaidoo59ef7be2019-06-21 12:40:28 -04001137 return nil
1138 }
khenaidoob9203542018-09-17 22:56:37 -04001139 var err error
npujar467fe752020-01-16 20:17:45 +05301140 if _, err = dMgr.logicalDeviceMgr.createLogicalDevice(ctx, cDevice); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +05301141 logger.Warnw(ctx, "create-logical-device-error", log.Fields{"device": cDevice})
khenaidoob9203542018-09-17 22:56:37 -04001142 return err
1143 }
khenaidoob9203542018-09-17 22:56:37 -04001144 return nil
1145}
1146
npujar1d86a522019-11-14 17:11:16 +05301147// DeleteLogicalDevice deletes logical device from core
Kent Hagerman2b216042020-04-03 18:28:56 -04001148func (dMgr *Manager) DeleteLogicalDevice(ctx context.Context, cDevice *voltha.Device) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301149 logger.Info(ctx, "delete-logical-device")
khenaidoo92e62c52018-10-03 14:02:54 -04001150 var err error
npujar467fe752020-01-16 20:17:45 +05301151 if err = dMgr.logicalDeviceMgr.deleteLogicalDevice(ctx, cDevice); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +05301152 logger.Warnw(ctx, "delete-logical-device-error", log.Fields{"device-id": cDevice.Id})
khenaidoo92e62c52018-10-03 14:02:54 -04001153 return err
1154 }
1155 // Remove the logical device Id from the parent device
npujar1d86a522019-11-14 17:11:16 +05301156 logicalID := ""
npujar467fe752020-01-16 20:17:45 +05301157 dMgr.UpdateDeviceAttribute(ctx, cDevice.Id, "ParentId", logicalID)
khenaidoo92e62c52018-10-03 14:02:54 -04001158 return nil
1159}
1160
npujar1d86a522019-11-14 17:11:16 +05301161// DeleteLogicalPorts removes the logical ports associated with that deviceId
Kent Hagerman2b216042020-04-03 18:28:56 -04001162func (dMgr *Manager) DeleteLogicalPorts(ctx context.Context, cDevice *voltha.Device) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001163 logger.Debugw(ctx, "delete-all-logical-ports", log.Fields{"device-id": cDevice.Id})
khenaidoo442e7c72020-03-10 16:13:48 -04001164 if err := dMgr.logicalDeviceMgr.deleteLogicalPorts(ctx, cDevice.Id); err != nil {
khenaidooe132f522020-03-20 15:23:15 -04001165 // Just log the error. The logical device or port may already have been deleted before this callback is invoked.
Himani Chawlab4c25912020-11-12 17:16:38 +05301166 logger.Warnw(ctx, "delete-logical-ports-error", log.Fields{"device-id": cDevice.Id, "error": err})
khenaidoo0a822f92019-05-08 15:15:57 -04001167 }
1168 return nil
1169}
1170
Kent Hagerman2b216042020-04-03 18:28:56 -04001171func (dMgr *Manager) getParentDevice(ctx context.Context, childDevice *voltha.Device) *voltha.Device {
khenaidoo92e62c52018-10-03 14:02:54 -04001172 // Sanity check
1173 if childDevice.Root {
1174 // childDevice is the parent device
1175 return childDevice
1176 }
Kent Hagermancba2f302020-07-28 13:37:36 -04001177 parentDevice, _ := dMgr.getDeviceReadOnly(ctx, childDevice.ParentId)
khenaidoo92e62c52018-10-03 14:02:54 -04001178 return parentDevice
1179}
1180
Kent Hagerman2b216042020-04-03 18:28:56 -04001181//ChildDevicesLost is invoked by an adapter to indicate that a parent device is in a state (Disabled) where it
khenaidoo0a822f92019-05-08 15:15:57 -04001182//cannot manage the child devices. This will trigger the Core to disable all the child devices.
Kent Hagerman2b216042020-04-03 18:28:56 -04001183func (dMgr *Manager) ChildDevicesLost(ctx context.Context, parentDeviceID string) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301184 logger.Debug(ctx, "child-devices-lost")
Kent Hagermancba2f302020-07-28 13:37:36 -04001185 parentDevice, err := dMgr.getDeviceReadOnly(ctx, parentDeviceID)
Kent Hagerman2a07b862020-06-19 15:23:07 -04001186 if err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +00001187 logger.Warnw(ctx, "failed-getting-device", log.Fields{"parent-device-id": parentDeviceID, "error": err})
khenaidoo0a822f92019-05-08 15:15:57 -04001188 return err
1189 }
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001190 return dMgr.DisableAllChildDevices(ctx, parentDevice)
khenaidoo0a822f92019-05-08 15:15:57 -04001191}
1192
Kent Hagerman2b216042020-04-03 18:28:56 -04001193//ChildDevicesDetected is invoked by an adapter when child devices are found, typically after after a
khenaidoo0a822f92019-05-08 15:15:57 -04001194// disable/enable sequence. This will trigger the Core to Enable all the child devices of that parent.
Kent Hagerman2b216042020-04-03 18:28:56 -04001195func (dMgr *Manager) ChildDevicesDetected(ctx context.Context, parentDeviceID string) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301196 logger.Debug(ctx, "child-devices-detected")
Kent Hagerman2a07b862020-06-19 15:23:07 -04001197 parentDevicePorts, err := dMgr.listDevicePorts(ctx, parentDeviceID)
1198 if err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +00001199 logger.Warnw(ctx, "failed-getting-device", log.Fields{"device-id": parentDeviceID, "error": err})
khenaidoo0a822f92019-05-08 15:15:57 -04001200 return err
1201 }
Kent Hagerman2a07b862020-06-19 15:23:07 -04001202 childDeviceIds := dMgr.getAllChildDeviceIds(ctx, parentDevicePorts)
khenaidoo0a822f92019-05-08 15:15:57 -04001203 if len(childDeviceIds) == 0 {
divyadesaicb8b59d2020-08-18 09:55:47 +00001204 logger.Debugw(ctx, "no-child-device", log.Fields{"parent-device-id": parentDeviceID})
khenaidoo0a822f92019-05-08 15:15:57 -04001205 }
khenaidoo59ef7be2019-06-21 12:40:28 -04001206 allChildEnableRequestSent := true
Kent Hagerman2a07b862020-06-19 15:23:07 -04001207 for childDeviceID := range childDeviceIds {
npujar467fe752020-01-16 20:17:45 +05301208 if agent := dMgr.getDeviceAgent(ctx, childDeviceID); agent != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +05301209 subCtx := utils.WithSpanAndRPCMetadataFromContext(ctx)
khenaidoo59ef7be2019-06-21 12:40:28 -04001210 // Run the children re-registration in its own routine
Kent Hagerman2a07b862020-06-19 15:23:07 -04001211 go func(ctx context.Context) {
1212 err = agent.enableDevice(ctx)
npujar1d86a522019-11-14 17:11:16 +05301213 if err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001214 logger.Errorw(ctx, "unable-to-enable-device", log.Fields{"error": err})
npujar1d86a522019-11-14 17:11:16 +05301215 }
Himani Chawlab4c25912020-11-12 17:16:38 +05301216 }(subCtx)
khenaidoo59ef7be2019-06-21 12:40:28 -04001217 } else {
npujar1d86a522019-11-14 17:11:16 +05301218 err = status.Errorf(codes.Unavailable, "no agent for child device %s", childDeviceID)
Himani Chawlab4c25912020-11-12 17:16:38 +05301219 logger.Errorw(ctx, "no-child-device-agent", log.Fields{"parent-device-id": parentDeviceID, "child-id": childDeviceID})
khenaidoo59ef7be2019-06-21 12:40:28 -04001220 allChildEnableRequestSent = false
khenaidoo0a822f92019-05-08 15:15:57 -04001221 }
1222 }
khenaidoo59ef7be2019-06-21 12:40:28 -04001223 if !allChildEnableRequestSent {
khenaidoo0a822f92019-05-08 15:15:57 -04001224 return err
1225 }
1226 return nil
1227}
1228
khenaidoo4d4802d2018-10-04 21:59:49 -04001229/*
1230All the functions below are callback functions where they are invoked with the latest and previous data. We can
1231therefore use the data as is without trying to get the latest from the model.
1232*/
1233
khenaidoo0a822f92019-05-08 15:15:57 -04001234//DisableAllChildDevices is invoked as a callback when the parent device is disabled
Kent Hagerman2b216042020-04-03 18:28:56 -04001235func (dMgr *Manager) DisableAllChildDevices(ctx context.Context, parentCurrDevice *voltha.Device) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301236 logger.Debug(ctx, "disable-all-child-devices")
Kent Hagerman2a07b862020-06-19 15:23:07 -04001237 ports, _ := dMgr.listDevicePorts(ctx, parentCurrDevice.Id)
1238 for childDeviceID := range dMgr.getAllChildDeviceIds(ctx, ports) {
npujar467fe752020-01-16 20:17:45 +05301239 if agent := dMgr.getDeviceAgent(ctx, childDeviceID); agent != nil {
Kent Hagerman2a07b862020-06-19 15:23:07 -04001240 if err := agent.disableDevice(ctx); err != nil {
khenaidooe132f522020-03-20 15:23:15 -04001241 // Just log the error - this error happens only if the child device was already in deleted state.
divyadesaicb8b59d2020-08-18 09:55:47 +00001242 logger.Errorw(ctx, "failure-disable-device", log.Fields{"device-id": childDeviceID, "error": err.Error()})
khenaidoo92e62c52018-10-03 14:02:54 -04001243 }
1244 }
1245 }
1246 return nil
1247}
1248
khenaidoo0a822f92019-05-08 15:15:57 -04001249//DeleteAllChildDevices is invoked as a callback when the parent device is deleted
Kent Hagerman2b216042020-04-03 18:28:56 -04001250func (dMgr *Manager) DeleteAllChildDevices(ctx context.Context, parentCurrDevice *voltha.Device) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301251 logger.Debug(ctx, "delete-all-child-devices")
Himani Chawla2ba1c9c2020-10-07 13:19:03 +05301252 force := false
1253 // Get the parent device Transient state, if its FORCE_DELETED(go for force delete for child devices)
1254 // So in cases when this handler is getting called other than DELETE operation, no force option would be used.
1255 agent := dMgr.getDeviceAgent(ctx, parentCurrDevice.Id)
1256 if agent == nil {
1257 return status.Errorf(codes.NotFound, "%s", parentCurrDevice.Id)
1258 }
1259
1260 force = agent.getTransientState() == voltha.DeviceTransientState_FORCE_DELETING
1261
Kent Hagerman2a07b862020-06-19 15:23:07 -04001262 ports, _ := dMgr.listDevicePorts(ctx, parentCurrDevice.Id)
1263 for childDeviceID := range dMgr.getAllChildDeviceIds(ctx, ports) {
npujar467fe752020-01-16 20:17:45 +05301264 if agent := dMgr.getDeviceAgent(ctx, childDeviceID); agent != nil {
Himani Chawla2ba1c9c2020-10-07 13:19:03 +05301265 if force {
1266 if err := agent.deleteDeviceForce(ctx); err != nil {
1267 logger.Warnw(ctx, "failure-delete-device-force", log.Fields{"device-id": childDeviceID,
1268 "error": err.Error()})
1269 }
1270 } else {
1271 if err := agent.deleteDevice(ctx); err != nil {
1272 logger.Warnw(ctx, "failure-delete-device", log.Fields{"device-id": childDeviceID,
1273 "error": err.Error()})
1274 }
khenaidoo4d4802d2018-10-04 21:59:49 -04001275 }
khenaidoo49085352020-01-13 19:15:43 -05001276 // No further action is required here. The deleteDevice will change the device state where the resulting
1277 // callback will take care of cleaning the child device agent.
khenaidoo4d4802d2018-10-04 21:59:49 -04001278 }
1279 }
khenaidoo4d4802d2018-10-04 21:59:49 -04001280 return nil
1281}
1282
Girish Gowdra408cd962020-03-11 14:31:31 -07001283//DeleteAllLogicalPorts is invoked as a callback when the parent device's connection status moves to UNREACHABLE
Kent Hagerman2b216042020-04-03 18:28:56 -04001284func (dMgr *Manager) DeleteAllLogicalPorts(ctx context.Context, parentDevice *voltha.Device) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001285 logger.Debugw(ctx, "delete-all-logical-ports", log.Fields{"parent-device-id": parentDevice.Id})
Girish Gowdra408cd962020-03-11 14:31:31 -07001286 if err := dMgr.logicalDeviceMgr.deleteAllLogicalPorts(ctx, parentDevice); err != nil {
khenaidooe132f522020-03-20 15:23:15 -04001287 // Just log error as logical device may already have been deleted
Rohan Agrawal31f21802020-06-12 05:38:46 +00001288 logger.Warnw(ctx, "delete-all-logical-ports-fail", log.Fields{"parent-device-id": parentDevice.Id, "error": err})
Girish Gowdra408cd962020-03-11 14:31:31 -07001289 }
1290 return nil
1291}
1292
1293//DeleteAllDeviceFlows is invoked as a callback when the parent device's connection status moves to UNREACHABLE
Kent Hagerman2b216042020-04-03 18:28:56 -04001294func (dMgr *Manager) DeleteAllDeviceFlows(ctx context.Context, parentDevice *voltha.Device) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001295 logger.Debugw(ctx, "delete-all-device-flows", log.Fields{"parent-device-id": parentDevice.Id})
Girish Gowdra408cd962020-03-11 14:31:31 -07001296 if agent := dMgr.getDeviceAgent(ctx, parentDevice.Id); agent != nil {
1297 if err := agent.deleteAllFlows(ctx); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001298 logger.Errorw(ctx, "error-deleting-all-device-flows", log.Fields{"parent-device-id": parentDevice.Id})
Girish Gowdra408cd962020-03-11 14:31:31 -07001299 return err
1300 }
1301 return nil
1302 }
1303 return status.Errorf(codes.NotFound, "%s", parentDevice.Id)
1304}
1305
khenaidoo4d4802d2018-10-04 21:59:49 -04001306//getAllChildDeviceIds is a helper method to get all the child device IDs from the device passed as parameter
Kent Hagerman2a07b862020-06-19 15:23:07 -04001307func (dMgr *Manager) getAllChildDeviceIds(ctx context.Context, parentDevicePorts map[uint32]*voltha.Port) map[string]struct{} {
Himani Chawlab4c25912020-11-12 17:16:38 +05301308 logger.Debug(ctx, "get-all-child-device-ids")
Kent Hagerman2a07b862020-06-19 15:23:07 -04001309 childDeviceIds := make(map[string]struct{}, len(parentDevicePorts))
1310 for _, port := range parentDevicePorts {
1311 for _, peer := range port.Peers {
1312 childDeviceIds[peer.DeviceId] = struct{}{}
khenaidoo92e62c52018-10-03 14:02:54 -04001313 }
1314 }
Kent Hagerman2a07b862020-06-19 15:23:07 -04001315 logger.Debugw(ctx, "returning-getAllChildDeviceIds", log.Fields{"childDeviceIds": childDeviceIds})
1316 return childDeviceIds
khenaidoo92e62c52018-10-03 14:02:54 -04001317}
1318
Kent Hagerman2b216042020-04-03 18:28:56 -04001319//GetAllChildDevices is a helper method to get all the child device IDs from the device passed as parameter
1320func (dMgr *Manager) GetAllChildDevices(ctx context.Context, parentDeviceID string) (*voltha.Devices, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301321 logger.Debugw(ctx, "get-all-child-devices", log.Fields{"parent-device-id": parentDeviceID})
Kent Hagerman2a07b862020-06-19 15:23:07 -04001322 if parentDevicePorts, err := dMgr.listDevicePorts(ctx, parentDeviceID); err == nil {
khenaidoo297cd252019-02-07 22:10:23 -05001323 childDevices := make([]*voltha.Device, 0)
Kent Hagerman2a07b862020-06-19 15:23:07 -04001324 for deviceID := range dMgr.getAllChildDeviceIds(ctx, parentDevicePorts) {
Kent Hagermancba2f302020-07-28 13:37:36 -04001325 if d, e := dMgr.getDeviceReadOnly(ctx, deviceID); e == nil && d != nil {
Kent Hagerman2a07b862020-06-19 15:23:07 -04001326 childDevices = append(childDevices, d)
khenaidoo297cd252019-02-07 22:10:23 -05001327 }
1328 }
1329 return &voltha.Devices{Items: childDevices}, nil
1330 }
npujar1d86a522019-11-14 17:11:16 +05301331 return nil, status.Errorf(codes.NotFound, "%s", parentDeviceID)
khenaidoo297cd252019-02-07 22:10:23 -05001332}
1333
npujar1d86a522019-11-14 17:11:16 +05301334// SetupUNILogicalPorts creates UNI ports on the logical device that represents a child UNI interface
Kent Hagerman2b216042020-04-03 18:28:56 -04001335func (dMgr *Manager) SetupUNILogicalPorts(ctx context.Context, cDevice *voltha.Device) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301336 logger.Info(ctx, "setup-uni-logical-ports")
Kent Hagerman2a07b862020-06-19 15:23:07 -04001337 cDevicePorts, err := dMgr.listDevicePorts(ctx, cDevice.Id)
1338 if err != nil {
1339 return err
1340 }
1341 if err := dMgr.logicalDeviceMgr.setupUNILogicalPorts(ctx, cDevice, cDevicePorts); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +05301342 logger.Warnw(ctx, "setup-uni-logical-ports-error", log.Fields{"device": cDevice, "err": err})
khenaidoob9203542018-09-17 22:56:37 -04001343 return err
1344 }
1345 return nil
1346}
1347
Kent Hagerman45a13e42020-04-13 12:23:50 -04001348// convenience to avoid redefining
1349var operationFailureResp = &common.OperationResp{Code: voltha.OperationResp_OPERATION_FAILURE}
1350
1351// DownloadImage execute an image download request
1352func (dMgr *Manager) DownloadImage(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301353 ctx = utils.WithRPCMetadataContext(ctx, "DownloadImage")
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001354 log.EnrichSpan(ctx, log.Fields{"device-id": img.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +05301355 logger.Debugw(ctx, "download-image", log.Fields{"device-id": img.Id, "image-name": img.Name})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001356 agent := dMgr.getDeviceAgent(ctx, img.Id)
1357 if agent == nil {
1358 return operationFailureResp, status.Errorf(codes.NotFound, "%s", img.Id)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001359 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001360 resp, err := agent.downloadImage(ctx, img)
1361 if err != nil {
1362 return operationFailureResp, err
1363 }
1364 return resp, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001365}
1366
Kent Hagerman45a13e42020-04-13 12:23:50 -04001367// CancelImageDownload cancels image download request
1368func (dMgr *Manager) CancelImageDownload(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301369 ctx = utils.WithRPCMetadataContext(ctx, "CancelImageDownload")
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001370 log.EnrichSpan(ctx, log.Fields{"device-id": img.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +05301371 logger.Debugw(ctx, "cancel-image-download", log.Fields{"device-id": img.Id, "image-name": img.Name})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001372 agent := dMgr.getDeviceAgent(ctx, img.Id)
1373 if agent == nil {
1374 return operationFailureResp, status.Errorf(codes.NotFound, "%s", img.Id)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001375 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001376 resp, err := agent.cancelImageDownload(ctx, img)
1377 if err != nil {
1378 return operationFailureResp, err
1379 }
1380 return resp, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001381}
1382
Kent Hagerman45a13e42020-04-13 12:23:50 -04001383// ActivateImageUpdate activates image update request
1384func (dMgr *Manager) ActivateImageUpdate(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301385 ctx = utils.WithRPCMetadataContext(ctx, "ActivateImageUpdate")
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001386 log.EnrichSpan(ctx, log.Fields{"device-id": img.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +05301387 logger.Debugw(ctx, "activate-image-update", log.Fields{"device-id": img.Id, "image-name": img.Name})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001388 agent := dMgr.getDeviceAgent(ctx, img.Id)
1389 if agent == nil {
1390 return operationFailureResp, status.Errorf(codes.NotFound, "%s", img.Id)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001391 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001392 resp, err := agent.activateImage(ctx, img)
1393 if err != nil {
1394 return operationFailureResp, err
1395 }
1396 return resp, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001397}
1398
Kent Hagerman45a13e42020-04-13 12:23:50 -04001399// RevertImageUpdate reverts image update
1400func (dMgr *Manager) RevertImageUpdate(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301401 ctx = utils.WithRPCMetadataContext(ctx, "RevertImageUpdate")
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001402 log.EnrichSpan(ctx, log.Fields{"device-id": img.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +05301403 logger.Debugw(ctx, "rever-image-update", log.Fields{"device-id": img.Id, "image-name": img.Name})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001404 agent := dMgr.getDeviceAgent(ctx, img.Id)
1405 if agent == nil {
1406 return operationFailureResp, status.Errorf(codes.NotFound, "%s", img.Id)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001407 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001408 resp, err := agent.revertImage(ctx, img)
1409 if err != nil {
1410 return operationFailureResp, err
1411 }
1412 return resp, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001413}
1414
Kent Hagerman45a13e42020-04-13 12:23:50 -04001415// convenience to avoid redefining
1416var imageDownloadFailureResp = &voltha.ImageDownload{DownloadState: voltha.ImageDownload_DOWNLOAD_UNKNOWN}
1417
1418// GetImageDownloadStatus returns status of image download
1419func (dMgr *Manager) GetImageDownloadStatus(ctx context.Context, img *voltha.ImageDownload) (*voltha.ImageDownload, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301420 ctx = utils.WithRPCMetadataContext(ctx, "GetImageDownloadStatus")
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001421 log.EnrichSpan(ctx, log.Fields{"device-id": img.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +05301422 logger.Debugw(ctx, "get-image-download-status", log.Fields{"device-id": img.Id, "image-name": img.Name})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001423 agent := dMgr.getDeviceAgent(ctx, img.Id)
1424 if agent == nil {
1425 return imageDownloadFailureResp, status.Errorf(codes.NotFound, "%s", img.Id)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001426 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001427 resp, err := agent.getImageDownloadStatus(ctx, img)
1428 if err != nil {
1429 return imageDownloadFailureResp, err
1430 }
1431 return resp, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001432}
1433
Kent Hagerman2b216042020-04-03 18:28:56 -04001434func (dMgr *Manager) UpdateImageDownload(ctx context.Context, deviceID string, img *voltha.ImageDownload) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301435 ctx = utils.WithRPCMetadataContext(ctx, "UpdateImageDownload")
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001436 log.EnrichSpan(ctx, log.Fields{"device-id": img.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +05301437 logger.Debugw(ctx, "update-image-download", log.Fields{"device-id": img.Id, "image-name": img.Name})
npujar467fe752020-01-16 20:17:45 +05301438 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
1439 if err := agent.updateImageDownload(ctx, img); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +05301440 logger.Debugw(ctx, "update-image-download-failed", log.Fields{"err": err, "image-name": img.Name})
khenaidoof5a5bfa2019-01-23 22:20:29 -05001441 return err
1442 }
1443 } else {
1444 return status.Errorf(codes.NotFound, "%s", img.Id)
1445 }
1446 return nil
1447}
1448
Kent Hagerman45a13e42020-04-13 12:23:50 -04001449// GetImageDownload returns image download
Kent Hagerman2b216042020-04-03 18:28:56 -04001450func (dMgr *Manager) GetImageDownload(ctx context.Context, img *voltha.ImageDownload) (*voltha.ImageDownload, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301451 ctx = utils.WithRPCMetadataContext(ctx, "GetImageDownload")
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001452 log.EnrichSpan(ctx, log.Fields{"device-id": img.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +05301453 logger.Debugw(ctx, "get-image-download", log.Fields{"device-id": img.Id, "image-name": img.Name})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001454 agent := dMgr.getDeviceAgent(ctx, img.Id)
1455 if agent == nil {
1456 return imageDownloadFailureResp, status.Errorf(codes.NotFound, "%s", img.Id)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001457 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001458 resp, err := agent.getImageDownload(ctx, img)
1459 if err != nil {
1460 return imageDownloadFailureResp, err
1461 }
1462 return resp, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001463}
1464
Kent Hagerman45a13e42020-04-13 12:23:50 -04001465// ListImageDownloads returns image downloads
1466func (dMgr *Manager) ListImageDownloads(ctx context.Context, id *voltha.ID) (*voltha.ImageDownloads, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301467 ctx = utils.WithRPCMetadataContext(ctx, "ListImageDownloads")
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001468 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +05301469 logger.Debugw(ctx, "list-image-downloads", log.Fields{"device-id": id.Id})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001470 agent := dMgr.getDeviceAgent(ctx, id.Id)
1471 if agent == nil {
1472 return &voltha.ImageDownloads{Items: []*voltha.ImageDownload{imageDownloadFailureResp}}, status.Errorf(codes.NotFound, "%s", id.Id)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001473 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001474 resp, err := agent.listImageDownloads(ctx, id.Id)
1475 if err != nil {
1476 return &voltha.ImageDownloads{Items: []*voltha.ImageDownload{imageDownloadFailureResp}}, err
1477 }
1478 return resp, nil
1479}
1480
1481// GetImages returns all images for a specific device entry
1482func (dMgr *Manager) GetImages(ctx context.Context, id *voltha.ID) (*voltha.Images, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301483 ctx = utils.WithRPCMetadataContext(ctx, "GetImages")
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001484 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +05301485 logger.Debugw(ctx, "get-images", log.Fields{"device-id": id.Id})
Kent Hagermancba2f302020-07-28 13:37:36 -04001486 device, err := dMgr.getDeviceReadOnly(ctx, id.Id)
Kent Hagerman45a13e42020-04-13 12:23:50 -04001487 if err != nil {
1488 return nil, err
1489 }
Kent Hagermancba2f302020-07-28 13:37:36 -04001490 return device.Images, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001491}
1492
Rohan Agrawal31f21802020-06-12 05:38:46 +00001493func (dMgr *Manager) NotifyInvalidTransition(ctx context.Context, device *voltha.Device) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301494 logger.Errorw(ctx, "notify-invalid-transition", log.Fields{
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001495 "device": device.Id,
1496 "curr-admin-state": device.AdminState,
1497 "curr-oper-state": device.OperStatus,
1498 "curr-conn-state": device.ConnectStatus,
Stephane Barbarieef6650d2019-07-18 12:15:09 -04001499 })
khenaidoo0a822f92019-05-08 15:15:57 -04001500 //TODO: notify over kafka?
1501 return nil
1502}
1503
npujar1d86a522019-11-14 17:11:16 +05301504// UpdateDeviceAttribute updates value of particular device attribute
Kent Hagerman2b216042020-04-03 18:28:56 -04001505func (dMgr *Manager) UpdateDeviceAttribute(ctx context.Context, deviceID string, attribute string, value interface{}) {
npujar1d86a522019-11-14 17:11:16 +05301506 if agent, ok := dMgr.deviceAgents.Load(deviceID); ok {
Kent Hagerman2b216042020-04-03 18:28:56 -04001507 agent.(*Agent).updateDeviceAttribute(ctx, attribute, value)
khenaidoob9203542018-09-17 22:56:37 -04001508 }
1509}
1510
npujar1d86a522019-11-14 17:11:16 +05301511// GetParentDeviceID returns parent device id, either from memory or from the dB, if present
Kent Hagerman2b216042020-04-03 18:28:56 -04001512func (dMgr *Manager) GetParentDeviceID(ctx context.Context, deviceID string) string {
Kent Hagermancba2f302020-07-28 13:37:36 -04001513 if device, _ := dMgr.getDeviceReadOnly(ctx, deviceID); device != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +05301514 logger.Infow(ctx, "get-parent-device-id", log.Fields{"device-id": device.Id, "parent-id": device.ParentId})
khenaidoo4c9e5592019-09-09 16:20:41 -04001515 return device.ParentId
khenaidoob9203542018-09-17 22:56:37 -04001516 }
khenaidoo4c9e5592019-09-09 16:20:41 -04001517 return ""
khenaidoob9203542018-09-17 22:56:37 -04001518}
serkant.uluderya334479d2019-04-10 08:26:15 -07001519
Kent Hagerman45a13e42020-04-13 12:23:50 -04001520func (dMgr *Manager) SimulateAlarm(ctx context.Context, simulateReq *voltha.SimulateAlarmRequest) (*common.OperationResp, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301521 ctx = utils.WithRPCMetadataContext(ctx, "SimulateAlarm")
1522 logger.Debugw(ctx, "simulate-alarm", log.Fields{"id": simulateReq.Id, "indicator": simulateReq.Indicator, "intf-id": simulateReq.IntfId,
1523 "port-type-name": simulateReq.PortTypeName, "onu-device-id": simulateReq.OnuDeviceId, "inverse-bit-error-rate": simulateReq.InverseBitErrorRate,
1524 "drift": simulateReq.Drift, "new-eqd": simulateReq.NewEqd, "onu-serial-number": simulateReq.OnuSerialNumber, "operation": simulateReq.Operation})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001525 agent := dMgr.getDeviceAgent(ctx, simulateReq.Id)
1526 if agent == nil {
1527 return nil, status.Errorf(codes.NotFound, "%s", simulateReq.Id)
serkant.uluderya334479d2019-04-10 08:26:15 -07001528 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001529 if err := agent.simulateAlarm(ctx, simulateReq); err != nil {
1530 return nil, err
1531 }
1532 return &common.OperationResp{Code: common.OperationResp_OPERATION_SUCCESS}, nil
serkant.uluderya334479d2019-04-10 08:26:15 -07001533}
Mahir Gunyelfdee9212019-10-16 16:52:21 -07001534
Kent Hagerman2b216042020-04-03 18:28:56 -04001535func (dMgr *Manager) UpdateDeviceReason(ctx context.Context, deviceID string, reason string) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301536 logger.Debugw(ctx, "update-device-reason", log.Fields{"device-id": deviceID, "reason": reason})
npujar467fe752020-01-16 20:17:45 +05301537 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
1538 return agent.updateDeviceReason(ctx, reason)
Mahir Gunyelfdee9212019-10-16 16:52:21 -07001539 }
npujar1d86a522019-11-14 17:11:16 +05301540 return status.Errorf(codes.NotFound, "%s", deviceID)
Mahir Gunyelfdee9212019-10-16 16:52:21 -07001541}
kesavandbc2d1622020-01-21 00:42:01 -05001542
Kent Hagerman45a13e42020-04-13 12:23:50 -04001543func (dMgr *Manager) EnablePort(ctx context.Context, port *voltha.Port) (*empty.Empty, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301544 ctx = utils.WithRPCMetadataContext(ctx, "EnablePort")
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001545 log.EnrichSpan(ctx, log.Fields{"device-id": port.DeviceId})
Himani Chawlab4c25912020-11-12 17:16:38 +05301546 logger.Debugw(ctx, "enable-port", log.Fields{"device-id": port.DeviceId, "port-no": port.PortNo})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001547 agent := dMgr.getDeviceAgent(ctx, port.DeviceId)
1548 if agent == nil {
1549 return nil, status.Errorf(codes.NotFound, "%s", port.DeviceId)
kesavandbc2d1622020-01-21 00:42:01 -05001550 }
Kent Hagerman2a07b862020-06-19 15:23:07 -04001551 return &empty.Empty{}, agent.enablePort(ctx, port.PortNo)
kesavandbc2d1622020-01-21 00:42:01 -05001552}
1553
Kent Hagerman45a13e42020-04-13 12:23:50 -04001554func (dMgr *Manager) DisablePort(ctx context.Context, port *voltha.Port) (*empty.Empty, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301555 ctx = utils.WithRPCMetadataContext(ctx, "DisablePort")
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001556 log.EnrichSpan(ctx, log.Fields{"device-id": port.DeviceId})
Himani Chawlab4c25912020-11-12 17:16:38 +05301557 logger.Debugw(ctx, "disable-port", log.Fields{"device-id": port.DeviceId, "port-no": port.PortNo})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001558 agent := dMgr.getDeviceAgent(ctx, port.DeviceId)
1559 if agent == nil {
1560 return nil, status.Errorf(codes.NotFound, "%s", port.DeviceId)
kesavandbc2d1622020-01-21 00:42:01 -05001561 }
Kent Hagerman2a07b862020-06-19 15:23:07 -04001562 return &empty.Empty{}, agent.disablePort(ctx, port.PortNo)
kesavandbc2d1622020-01-21 00:42:01 -05001563}
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001564
Kent Hagerman2b216042020-04-03 18:28:56 -04001565// ChildDeviceLost calls parent adapter to delete child device and all its references
1566func (dMgr *Manager) ChildDeviceLost(ctx context.Context, curr *voltha.Device) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301567 logger.Debugw(ctx, "child-device-lost", log.Fields{"child-device-id": curr.Id, "parent-device-id": curr.ParentId})
khenaidoo442e7c72020-03-10 16:13:48 -04001568 if parentAgent := dMgr.getDeviceAgent(ctx, curr.ParentId); parentAgent != nil {
khenaidooe132f522020-03-20 15:23:15 -04001569 if err := parentAgent.ChildDeviceLost(ctx, curr); err != nil {
1570 // Just log the message and let the remaining pipeline proceed.
Rohan Agrawal31f21802020-06-12 05:38:46 +00001571 logger.Warnw(ctx, "childDeviceLost", log.Fields{"child-device-id": curr.Id, "parent-device-id": curr.ParentId, "error": err})
khenaidooe132f522020-03-20 15:23:15 -04001572 }
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001573 }
khenaidooe132f522020-03-20 15:23:15 -04001574 // Do not return an error as parent device may also have been deleted. Let the remaining pipeline proceed.
1575 return nil
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001576}
onkarkundargi87285252020-01-27 11:34:52 +05301577
Kent Hagerman45a13e42020-04-13 12:23:50 -04001578func (dMgr *Manager) StartOmciTestAction(ctx context.Context, request *voltha.OmciTestRequest) (*voltha.TestResponse, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301579 ctx = utils.WithRPCMetadataContext(ctx, "StartOmciTestAction")
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001580 log.EnrichSpan(ctx, log.Fields{"device-id": request.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +05301581 logger.Debugw(ctx, "start-omci-test-action", log.Fields{"device-id": request.Id, "uuid": request.Uuid})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001582 agent := dMgr.getDeviceAgent(ctx, request.Id)
1583 if agent == nil {
1584 return nil, status.Errorf(codes.NotFound, "%s", request.Id)
onkarkundargi87285252020-01-27 11:34:52 +05301585 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001586 return agent.startOmciTest(ctx, request)
onkarkundargi87285252020-01-27 11:34:52 +05301587}
Dinesh Belwalkarc1129f12020-02-27 10:41:33 -08001588
1589func (dMgr *Manager) GetExtValue(ctx context.Context, value *voltha.ValueSpecifier) (*voltha.ReturnValues, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301590 ctx = utils.WithRPCMetadataContext(ctx, "GetExtValue")
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001591 log.EnrichSpan(ctx, log.Fields{"device-id": value.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +05301592 logger.Debugw(ctx, "get-ext-value", log.Fields{"onu-id": value.Id})
Kent Hagermancba2f302020-07-28 13:37:36 -04001593 cDevice, err := dMgr.getDeviceReadOnly(ctx, value.Id)
Dinesh Belwalkarc1129f12020-02-27 10:41:33 -08001594 if err != nil {
1595 return nil, status.Errorf(codes.Aborted, "%s", err.Error())
1596 }
Kent Hagermancba2f302020-07-28 13:37:36 -04001597 pDevice, err := dMgr.getDeviceReadOnly(ctx, cDevice.ParentId)
Dinesh Belwalkarc1129f12020-02-27 10:41:33 -08001598 if err != nil {
1599 return nil, status.Errorf(codes.Aborted, "%s", err.Error())
1600 }
1601 if agent := dMgr.getDeviceAgent(ctx, cDevice.ParentId); agent != nil {
1602 resp, err := agent.getExtValue(ctx, pDevice, cDevice, value)
1603 if err != nil {
1604 return nil, err
1605 }
Himani Chawlab4c25912020-11-12 17:16:38 +05301606 logger.Debugw(ctx, "get-ext-value-result", log.Fields{"result": resp})
Dinesh Belwalkarc1129f12020-02-27 10:41:33 -08001607 return resp, nil
1608 }
1609 return nil, status.Errorf(codes.NotFound, "%s", value.Id)
1610
1611}
dpaul62686312020-06-23 14:17:36 +05301612
1613// SetExtValue set some given configs or value
1614func (dMgr *Manager) SetExtValue(ctx context.Context, value *voltha.ValueSet) (*empty.Empty, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301615 ctx = utils.WithRPCMetadataContext(ctx, "SetExtValue")
1616 logger.Debugw(ctx, "set-ext-value", log.Fields{"onu-id": value.Id})
dpaul62686312020-06-23 14:17:36 +05301617 device, err := dMgr.getDeviceReadOnly(ctx, value.Id)
1618 if err != nil {
1619 return nil, status.Errorf(codes.Aborted, "%s", err.Error())
1620 }
1621 if agent := dMgr.getDeviceAgent(ctx, device.Id); agent != nil {
1622 resp, err := agent.setExtValue(ctx, device, value)
1623 if err != nil {
1624 return nil, err
1625 }
Himani Chawlab4c25912020-11-12 17:16:38 +05301626 logger.Debugw(ctx, "set-ext-value-result", log.Fields{"result": resp})
dpaul62686312020-06-23 14:17:36 +05301627 return resp, nil
1628 }
1629 return nil, status.Errorf(codes.NotFound, "%s", value.Id)
1630
1631}
Himani Chawlab4c25912020-11-12 17:16:38 +05301632
1633func (dMgr *Manager) SendRPCEvent(ctx context.Context, id string, rpcEvent *voltha.RPCEvent,
1634 category voltha.EventCategory_Types, subCategory *voltha.EventSubCategory_Types, raisedTs int64) {
1635 //TODO Instead of directly sending to the kafka bus, queue the message and send it asynchronously
Mahir Gunyelb0343bf2021-05-11 14:14:26 -07001636 dMgr.Agent.SendRPCEvent(ctx, id, rpcEvent, category, subCategory, raisedTs)
Himani Chawlab4c25912020-11-12 17:16:38 +05301637}
Manindera496f852021-02-22 09:57:56 +05301638
1639func (dMgr *Manager) GetTransientState(ctx context.Context, id string) (voltha.DeviceTransientState_Types, error) {
1640 agent := dMgr.getDeviceAgent(ctx, id)
1641 if agent == nil {
1642 return voltha.DeviceTransientState_NONE, status.Errorf(codes.NotFound, "%s", id)
1643 }
1644 return agent.getTransientState(), nil
1645}
ssiddiquif076cb82021-04-23 10:47:04 +05301646
1647func (dMgr *Manager) DownloadImageToDevice(ctx context.Context, request *voltha.DeviceImageDownloadRequest) (*voltha.DeviceImageResponse, error) {
1648 if err := dMgr.validateImageDownloadRequest(request); err != nil {
1649 return nil, err
1650 }
1651
1652 ctx = utils.WithRPCMetadataContext(ctx, "DownloadImageToDevice")
1653 respCh := make(chan []*voltha.DeviceImageState, len(request.GetDeviceId()))
1654
1655 downloadReq := &voltha.DeviceImageDownloadRequest{
1656 Image: request.Image,
1657 ActivateOnSuccess: request.ActivateOnSuccess,
1658 CommitOnSuccess: request.CommitOnSuccess,
1659 }
1660
1661 for index, deviceID := range request.DeviceId {
1662 //slice-out only single deviceID from the request
1663 downloadReq.DeviceId = request.DeviceId[index : index+1]
1664
1665 go func(deviceID string, req *voltha.DeviceImageDownloadRequest, ch chan []*voltha.DeviceImageState) {
1666 agent := dMgr.getDeviceAgent(ctx, deviceID)
1667 if agent == nil {
1668 logger.Errorw(ctx, "Not-found", log.Fields{"device-id": deviceID})
1669 ch <- nil
1670 return
1671 }
1672
1673 resp, err := agent.downloadImageToDevice(ctx, req)
1674 if err != nil {
1675 logger.Errorw(ctx, "download-image-to-device-failed", log.Fields{"device-id": deviceID, "error": err})
1676 ch <- nil
1677 return
1678 }
1679
1680 err = dMgr.validateDeviceImageResponse(resp)
1681 if err != nil {
1682 logger.Errorw(ctx, "download-image-to-device-failed", log.Fields{"device-id": deviceID, "error": err})
1683 ch <- nil
1684 return
1685 }
1686 ch <- resp.GetDeviceImageStates()
1687 }(deviceID.GetId(), downloadReq, respCh)
1688
1689 }
1690
1691 return dMgr.waitForAllResponses(ctx, "download-image-to-device", respCh, len(request.GetDeviceId()))
1692}
1693
1694func (dMgr *Manager) GetImageStatus(ctx context.Context, request *voltha.DeviceImageRequest) (*voltha.DeviceImageResponse, error) {
1695 if err := dMgr.validateImageRequest(request); err != nil {
1696 return nil, err
1697 }
1698
1699 ctx = utils.WithRPCMetadataContext(ctx, "GetImageStatus")
1700
1701 imageStatusReq := &voltha.DeviceImageRequest{
1702 Version: request.Version,
1703 CommitOnSuccess: request.CommitOnSuccess,
1704 }
1705
1706 respCh := make(chan []*voltha.DeviceImageState, len(request.GetDeviceId()))
1707 for index, deviceID := range request.DeviceId {
1708 //slice-out only single deviceID from the request
1709 imageStatusReq.DeviceId = request.DeviceId[index : index+1]
1710
1711 go func(deviceID string, req *voltha.DeviceImageRequest, ch chan []*voltha.DeviceImageState) {
1712 agent := dMgr.getDeviceAgent(ctx, deviceID)
1713 if agent == nil {
1714 logger.Errorw(ctx, "Not-found", log.Fields{"device-id": deviceID})
1715 ch <- nil
1716 return
1717 }
1718
1719 resp, err := agent.getImageStatus(ctx, req)
1720 if err != nil {
1721 logger.Errorw(ctx, "get-image-status-failed", log.Fields{"device-id": deviceID, "error": err})
1722 ch <- nil
1723 return
1724 }
1725
1726 err = dMgr.validateDeviceImageResponse(resp)
1727 if err != nil {
1728 logger.Errorw(ctx, "get-image-status-failed", log.Fields{"device-id": deviceID, "error": err})
1729 ch <- nil
1730 return
1731 }
1732 ch <- resp.GetDeviceImageStates()
1733 }(deviceID.GetId(), imageStatusReq, respCh)
1734
1735 }
1736
1737 return dMgr.waitForAllResponses(ctx, "get-image-status", respCh, len(request.GetDeviceId()))
1738}
1739
1740func (dMgr *Manager) AbortImageUpgradeToDevice(ctx context.Context, request *voltha.DeviceImageRequest) (*voltha.DeviceImageResponse, error) {
1741 if err := dMgr.validateImageRequest(request); err != nil {
1742 return nil, err
1743 }
1744
1745 ctx = utils.WithRPCMetadataContext(ctx, "AbortImageUpgradeToDevice")
1746 respCh := make(chan []*voltha.DeviceImageState, len(request.GetDeviceId()))
1747
1748 abortImageReq := &voltha.DeviceImageRequest{
1749 Version: request.Version,
1750 CommitOnSuccess: request.CommitOnSuccess,
1751 }
1752
1753 for index, deviceID := range request.DeviceId {
1754 //slice-out only single deviceID from the request
1755 abortImageReq.DeviceId = request.DeviceId[index : index+1]
1756
1757 go func(deviceID string, req *voltha.DeviceImageRequest, ch chan []*voltha.DeviceImageState) {
1758 agent := dMgr.getDeviceAgent(ctx, deviceID)
1759 if agent == nil {
1760 logger.Errorw(ctx, "Not-found", log.Fields{"device-id": deviceID})
1761 ch <- nil
1762 return
1763 }
1764
1765 resp, err := agent.abortImageUpgradeToDevice(ctx, req)
1766 if err != nil {
1767 logger.Errorw(ctx, "abort-image-upgrade-to-device-failed", log.Fields{"device-id": deviceID, "error": err})
1768 ch <- nil
1769 return
1770 }
1771
1772 err = dMgr.validateDeviceImageResponse(resp)
1773 if err != nil {
1774 logger.Errorw(ctx, "abort-image-upgrade-to-device-failed", log.Fields{"device-id": deviceID, "error": err})
1775 ch <- nil
1776 return
1777 }
1778 ch <- resp.GetDeviceImageStates()
1779 }(deviceID.GetId(), abortImageReq, respCh)
1780
1781 }
1782
1783 return dMgr.waitForAllResponses(ctx, "abort-image-upgrade-to-device", respCh, len(request.GetDeviceId()))
1784}
1785
1786func (dMgr *Manager) GetOnuImages(ctx context.Context, id *common.ID) (*voltha.OnuImages, error) {
1787 if id == nil || id.Id == "" {
1788 return nil, status.Errorf(codes.InvalidArgument, "empty device id")
1789 }
1790
1791 ctx = utils.WithRPCMetadataContext(ctx, "GetOnuImages")
1792 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
1793 agent := dMgr.getDeviceAgent(ctx, id.Id)
1794 if agent == nil {
1795 return nil, status.Errorf(codes.NotFound, "%s", id.Id)
1796 }
1797
1798 resp, err := agent.getOnuImages(ctx, id)
1799 if err != nil {
1800 return nil, err
1801 }
1802
1803 logger.Debugw(ctx, "get-onu-images-result", log.Fields{"onu-image": resp.Items})
1804
1805 return resp, nil
1806}
1807
1808func (dMgr *Manager) ActivateImage(ctx context.Context, request *voltha.DeviceImageRequest) (*voltha.DeviceImageResponse, error) {
1809 if err := dMgr.validateImageRequest(request); err != nil {
1810 return nil, err
1811 }
1812
1813 ctx = utils.WithRPCMetadataContext(ctx, "ActivateImage")
1814 respCh := make(chan []*voltha.DeviceImageState, len(request.GetDeviceId()))
1815
1816 activateImageReq := &voltha.DeviceImageRequest{
1817 Version: request.Version,
1818 CommitOnSuccess: request.CommitOnSuccess,
1819 }
1820
1821 for index, deviceID := range request.DeviceId {
1822 //slice-out only single deviceID from the request
1823 activateImageReq.DeviceId = request.DeviceId[index : index+1]
1824
1825 go func(deviceID string, req *voltha.DeviceImageRequest, ch chan []*voltha.DeviceImageState) {
1826 agent := dMgr.getDeviceAgent(ctx, deviceID)
1827 if agent == nil {
1828 logger.Errorw(ctx, "Not-found", log.Fields{"device-id": deviceID})
1829 ch <- nil
1830 return
1831 }
1832
1833 resp, err := agent.activateImageOnDevice(ctx, req)
1834 if err != nil {
1835 logger.Errorw(ctx, "activate-image-failed", log.Fields{"device-id": deviceID, "error": err})
1836 ch <- nil
1837 return
1838 }
1839
1840 err = dMgr.validateDeviceImageResponse(resp)
1841 if err != nil {
1842 logger.Errorw(ctx, "activate-image-failed", log.Fields{"device-id": deviceID, "error": err})
1843 ch <- nil
1844 return
1845 }
1846
1847 ch <- resp.GetDeviceImageStates()
1848 }(deviceID.GetId(), activateImageReq, respCh)
1849
1850 }
1851
1852 return dMgr.waitForAllResponses(ctx, "activate-image", respCh, len(request.GetDeviceId()))
1853}
1854
1855func (dMgr *Manager) CommitImage(ctx context.Context, request *voltha.DeviceImageRequest) (*voltha.DeviceImageResponse, error) {
1856 if err := dMgr.validateImageRequest(request); err != nil {
1857 return nil, err
1858 }
1859
1860 ctx = utils.WithRPCMetadataContext(ctx, "CommitImage")
1861 respCh := make(chan []*voltha.DeviceImageState, len(request.GetDeviceId()))
1862
1863 commitImageReq := &voltha.DeviceImageRequest{
1864 Version: request.Version,
1865 CommitOnSuccess: request.CommitOnSuccess,
1866 }
1867
1868 for index, deviceID := range request.DeviceId {
1869 //slice-out only single deviceID from the request
1870 commitImageReq.DeviceId = request.DeviceId[index : index+1]
1871
1872 go func(deviceID string, req *voltha.DeviceImageRequest, ch chan []*voltha.DeviceImageState) {
1873 agent := dMgr.getDeviceAgent(ctx, deviceID)
1874 if agent == nil {
1875 logger.Errorw(ctx, "Not-found", log.Fields{"device-id": deviceID})
1876 ch <- nil
1877 return
1878 }
1879
1880 resp, err := agent.commitImage(ctx, req)
1881 if err != nil {
1882 logger.Errorw(ctx, "commit-image-failed", log.Fields{"device-id": deviceID, "error": err})
1883 ch <- nil
1884 return
1885 }
1886
1887 err = dMgr.validateDeviceImageResponse(resp)
1888 if err != nil {
1889 logger.Errorf(ctx, "commit-image-failed", log.Fields{"device-id": deviceID, "error": err})
1890 ch <- nil
1891 return
1892 }
1893 ch <- resp.GetDeviceImageStates()
1894 }(deviceID.GetId(), commitImageReq, respCh)
1895
1896 }
1897
1898 return dMgr.waitForAllResponses(ctx, "commit-image", respCh, len(request.GetDeviceId()))
1899}
1900
1901func (dMgr *Manager) validateImageDownloadRequest(request *voltha.DeviceImageDownloadRequest) error {
1902 if request == nil || request.Image == nil || len(request.DeviceId) == 0 {
1903 return status.Errorf(codes.InvalidArgument, "invalid argument")
1904 }
1905
1906 for _, deviceID := range request.DeviceId {
1907 if deviceID == nil {
1908 return status.Errorf(codes.InvalidArgument, "id is nil")
1909 }
1910 }
1911 return nil
1912}
1913
1914func (dMgr *Manager) validateImageRequest(request *voltha.DeviceImageRequest) error {
1915 if request == nil || len(request.DeviceId) == 0 || request.DeviceId[0] == nil {
1916 return status.Errorf(codes.InvalidArgument, "invalid argument")
1917 }
1918
1919 for _, deviceID := range request.DeviceId {
1920 if deviceID == nil {
1921 return status.Errorf(codes.InvalidArgument, "id is nil")
1922 }
1923 }
1924
1925 return nil
1926}
1927
1928func (dMgr *Manager) validateDeviceImageResponse(response *voltha.DeviceImageResponse) error {
1929 if response == nil || len(response.GetDeviceImageStates()) == 0 || response.GetDeviceImageStates()[0] == nil {
1930 return status.Errorf(codes.Internal, "invalid-response-from-adapter")
1931 }
1932
1933 return nil
1934}
1935
1936func (dMgr *Manager) waitForAllResponses(ctx context.Context, opName string, respCh chan []*voltha.DeviceImageState, expectedResps int) (*voltha.DeviceImageResponse, error) {
1937 response := &voltha.DeviceImageResponse{}
1938 respCount := 0
1939 for {
1940 select {
1941 case resp, ok := <-respCh:
1942 if !ok {
1943 logger.Errorw(ctx, opName+"-failed", log.Fields{"error": "channel-closed"})
1944 return response, status.Errorf(codes.Aborted, "channel-closed")
1945 }
1946
1947 if resp != nil {
1948 logger.Debugw(ctx, opName+"-result", log.Fields{"image-state": resp[0].GetImageState(), "device-id": resp[0].GetDeviceId()})
1949 response.DeviceImageStates = append(response.DeviceImageStates, resp...)
1950 }
1951
1952 respCount++
1953
1954 //check whether all responses received, if so, sent back the collated response
1955 if respCount == expectedResps {
1956 return response, nil
1957 }
1958 continue
1959 case <-ctx.Done():
1960 return nil, status.Errorf(codes.Aborted, opName+"-failed-%s", ctx.Err())
1961 }