blob: b3fa7b7335c445ad8d72adc200bfc2075bde96aa [file] [log] [blame]
khenaidoob9203542018-09-17 22:56:37 -04001/*
2 * Copyright 2018-present Open Networking Foundation
3
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7
8 * http://www.apache.org/licenses/LICENSE-2.0
9
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
npujar1d86a522019-11-14 17:11:16 +053016
Kent Hagerman2b216042020-04-03 18:28:56 -040017package device
khenaidoob9203542018-09-17 22:56:37 -040018
19import (
20 "context"
21 "errors"
Maninder0aabf0c2021-03-17 14:55:14 +053022 "github.com/opencord/voltha-go/rw_core/config"
David Bainbridged1afd662020-03-26 18:27:41 -070023 "sync"
24 "time"
25
Kent Hagerman45a13e42020-04-13 12:23:50 -040026 "github.com/golang/protobuf/ptypes/empty"
sbarbari17d7e222019-11-05 10:02:29 -050027 "github.com/opencord/voltha-go/db/model"
Kent Hagerman2b216042020-04-03 18:28:56 -040028 "github.com/opencord/voltha-go/rw_core/core/adapter"
Kent Hagermanf5a67352020-04-30 15:15:26 -040029 "github.com/opencord/voltha-go/rw_core/core/device/event"
Kent Hagerman2b216042020-04-03 18:28:56 -040030 "github.com/opencord/voltha-go/rw_core/core/device/remote"
Kent Hagerman6031aad2020-07-29 16:36:33 -040031 "github.com/opencord/voltha-go/rw_core/core/device/state"
khenaidoo3d3b8c22019-05-22 18:10:39 -040032 "github.com/opencord/voltha-go/rw_core/utils"
Himani Chawlab4c25912020-11-12 17:16:38 +053033 "github.com/opencord/voltha-lib-go/v4/pkg/events"
Maninderdfadc982020-10-28 14:04:33 +053034 "github.com/opencord/voltha-lib-go/v4/pkg/kafka"
35 "github.com/opencord/voltha-lib-go/v4/pkg/log"
36 "github.com/opencord/voltha-protos/v4/go/common"
37 ic "github.com/opencord/voltha-protos/v4/go/inter_container"
38 "github.com/opencord/voltha-protos/v4/go/openflow_13"
39 ofp "github.com/opencord/voltha-protos/v4/go/openflow_13"
40 "github.com/opencord/voltha-protos/v4/go/voltha"
khenaidoob9203542018-09-17 22:56:37 -040041 "google.golang.org/grpc/codes"
42 "google.golang.org/grpc/status"
khenaidoob9203542018-09-17 22:56:37 -040043)
44
Kent Hagerman2b216042020-04-03 18:28:56 -040045// Manager represent device manager attributes
46type Manager struct {
Himani Chawlab4c25912020-11-12 17:16:38 +053047 deviceAgents sync.Map
48 rootDevices map[string]bool
49 lockRootDeviceMap sync.RWMutex
50 adapterProxy *remote.AdapterProxy
Mahir Gunyelb0343bf2021-05-11 14:14:26 -070051 *event.Agent
Kent Hagerman2b216042020-04-03 18:28:56 -040052 adapterMgr *adapter.Manager
53 logicalDeviceMgr *LogicalManager
npujar467fe752020-01-16 20:17:45 +053054 kafkaICProxy kafka.InterContainerProxy
Kent Hagerman6031aad2020-07-29 16:36:33 -040055 stateTransitions *state.TransitionMap
Mahir Gunyel03de0d32020-06-03 01:36:59 -070056 dbPath *model.Path
Kent Hagermanf5a67352020-04-30 15:15:26 -040057 dProxy *model.Proxy
npujar1d86a522019-11-14 17:11:16 +053058 coreInstanceID string
khenaidoo442e7c72020-03-10 16:13:48 -040059 defaultTimeout time.Duration
khenaidoo4c9e5592019-09-09 16:20:41 -040060 devicesLoadingLock sync.RWMutex
61 deviceLoadingInProgress map[string][]chan int
Maninder0aabf0c2021-03-17 14:55:14 +053062 config *config.RWCoreFlags
khenaidoob9203542018-09-17 22:56:37 -040063}
64
Mahir Gunyel03de0d32020-06-03 01:36:59 -070065//NewManagers creates the Manager and the Logical Manager.
Maninder0aabf0c2021-03-17 14:55:14 +053066func NewManagers(dbPath *model.Path, adapterMgr *adapter.Manager, kmp kafka.InterContainerProxy, endpointMgr kafka.EndpointManager, cf *config.RWCoreFlags, coreInstanceID string, eventProxy *events.EventProxy) (*Manager, *LogicalManager) {
Kent Hagerman2b216042020-04-03 18:28:56 -040067 deviceMgr := &Manager{
Kent Hagerman2b216042020-04-03 18:28:56 -040068 rootDevices: make(map[string]bool),
69 kafkaICProxy: kmp,
Maninder0aabf0c2021-03-17 14:55:14 +053070 adapterProxy: remote.NewAdapterProxy(kmp, cf.CoreTopic, endpointMgr),
Kent Hagerman2b216042020-04-03 18:28:56 -040071 coreInstanceID: coreInstanceID,
Mahir Gunyel03de0d32020-06-03 01:36:59 -070072 dbPath: dbPath,
73 dProxy: dbPath.Proxy("devices"),
Kent Hagerman2b216042020-04-03 18:28:56 -040074 adapterMgr: adapterMgr,
Maninder0aabf0c2021-03-17 14:55:14 +053075 defaultTimeout: cf.DefaultCoreTimeout,
76 Agent: event.NewAgent(eventProxy, coreInstanceID, cf.VolthaStackID),
Kent Hagerman2b216042020-04-03 18:28:56 -040077 deviceLoadingInProgress: make(map[string][]chan int),
Maninder0aabf0c2021-03-17 14:55:14 +053078 config: cf,
Kent Hagerman2b216042020-04-03 18:28:56 -040079 }
Kent Hagerman6031aad2020-07-29 16:36:33 -040080 deviceMgr.stateTransitions = state.NewTransitionMap(deviceMgr)
Kent Hagerman2f0d0552020-04-23 17:28:52 -040081
Kent Hagerman2b216042020-04-03 18:28:56 -040082 logicalDeviceMgr := &LogicalManager{
Maninder0aabf0c2021-03-17 14:55:14 +053083 Manager: event.NewManager(eventProxy, coreInstanceID, cf.VolthaStackID),
Kent Hagerman2b216042020-04-03 18:28:56 -040084 deviceMgr: deviceMgr,
85 kafkaICProxy: kmp,
Mahir Gunyel03de0d32020-06-03 01:36:59 -070086 dbPath: dbPath,
87 ldProxy: dbPath.Proxy("logical_devices"),
Maninder0aabf0c2021-03-17 14:55:14 +053088 defaultTimeout: cf.DefaultCoreTimeout,
Kent Hagerman2b216042020-04-03 18:28:56 -040089 logicalDeviceLoadingInProgress: make(map[string][]chan int),
90 }
91 deviceMgr.logicalDeviceMgr = logicalDeviceMgr
Matteo Scandolod525ae32020-04-02 17:27:29 -070092
Kent Hagerman2b216042020-04-03 18:28:56 -040093 adapterMgr.SetAdapterRestartedCallback(deviceMgr.adapterRestarted)
Matteo Scandolod525ae32020-04-02 17:27:29 -070094
Kent Hagerman2b216042020-04-03 18:28:56 -040095 return deviceMgr, logicalDeviceMgr
khenaidoob9203542018-09-17 22:56:37 -040096}
97
Kent Hagerman2b216042020-04-03 18:28:56 -040098func (dMgr *Manager) addDeviceAgentToMap(agent *Agent) {
npujar1d86a522019-11-14 17:11:16 +053099 if _, exist := dMgr.deviceAgents.Load(agent.deviceID); !exist {
100 dMgr.deviceAgents.Store(agent.deviceID, agent)
khenaidoob9203542018-09-17 22:56:37 -0400101 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400102 dMgr.lockRootDeviceMap.Lock()
103 defer dMgr.lockRootDeviceMap.Unlock()
Kent Hagerman2a07b862020-06-19 15:23:07 -0400104 dMgr.rootDevices[agent.deviceID] = agent.isRootDevice
khenaidoo2c6a0992019-04-29 13:46:56 -0400105
khenaidoob9203542018-09-17 22:56:37 -0400106}
107
Kent Hagerman2b216042020-04-03 18:28:56 -0400108func (dMgr *Manager) deleteDeviceAgentFromMap(agent *Agent) {
npujar1d86a522019-11-14 17:11:16 +0530109 dMgr.deviceAgents.Delete(agent.deviceID)
khenaidoo2c6a0992019-04-29 13:46:56 -0400110 dMgr.lockRootDeviceMap.Lock()
111 defer dMgr.lockRootDeviceMap.Unlock()
npujar1d86a522019-11-14 17:11:16 +0530112 delete(dMgr.rootDevices, agent.deviceID)
khenaidoo4d4802d2018-10-04 21:59:49 -0400113}
114
khenaidoo297cd252019-02-07 22:10:23 -0500115// 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 -0400116func (dMgr *Manager) getDeviceAgent(ctx context.Context, deviceID string) *Agent {
npujar1d86a522019-11-14 17:11:16 +0530117 agent, ok := dMgr.deviceAgents.Load(deviceID)
118 if ok {
Kent Hagerman2b216042020-04-03 18:28:56 -0400119 return agent.(*Agent)
khenaidoob9203542018-09-17 22:56:37 -0400120 }
khenaidoo442e7c72020-03-10 16:13:48 -0400121 // Try to load into memory - loading will also create the device agent and set the device ownership
npujar467fe752020-01-16 20:17:45 +0530122 err := dMgr.load(ctx, deviceID)
npujar1d86a522019-11-14 17:11:16 +0530123 if err == nil {
124 agent, ok = dMgr.deviceAgents.Load(deviceID)
125 if !ok {
126 return nil
127 }
Kent Hagerman2b216042020-04-03 18:28:56 -0400128 return agent.(*Agent)
npujar1d86a522019-11-14 17:11:16 +0530129 }
130 //TODO: Change the return params to return an error as well
divyadesaicb8b59d2020-08-18 09:55:47 +0000131 logger.Errorw(ctx, "loading-device-failed", log.Fields{"device-id": deviceID, "error": err})
khenaidoob9203542018-09-17 22:56:37 -0400132 return nil
133}
134
khenaidoo297cd252019-02-07 22:10:23 -0500135// listDeviceIdsFromMap returns the list of device IDs that are in memory
Kent Hagerman2b216042020-04-03 18:28:56 -0400136func (dMgr *Manager) listDeviceIdsFromMap() *voltha.IDs {
khenaidoo7ccedd52018-12-14 16:48:54 -0500137 result := &voltha.IDs{Items: make([]*voltha.ID, 0)}
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400138
139 dMgr.deviceAgents.Range(func(key, value interface{}) bool {
140 result.Items = append(result.Items, &voltha.ID{Id: key.(string)})
141 return true
142 })
143
khenaidoo7ccedd52018-12-14 16:48:54 -0500144 return result
145}
146
Kent Hagerman45a13e42020-04-13 12:23:50 -0400147// CreateDevice creates a new parent device in the data model
148func (dMgr *Manager) CreateDevice(ctx context.Context, device *voltha.Device) (*voltha.Device, error) {
149 if device.MacAddress == "" && device.GetHostAndPort() == "" {
Himani Chawlab4c25912020-11-12 17:16:38 +0530150 logger.Errorf(ctx, "no-device-info-present")
Kent Hagerman45a13e42020-04-13 12:23:50 -0400151 return &voltha.Device{}, errors.New("no-device-info-present; MAC or HOSTIP&PORT")
152 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530153 ctx = utils.WithRPCMetadataContext(ctx, "CreateDevice")
Rohan Agrawal31f21802020-06-12 05:38:46 +0000154 logger.Debugw(ctx, "create-device", log.Fields{"device": *device})
Kent Hagerman45a13e42020-04-13 12:23:50 -0400155
npujar467fe752020-01-16 20:17:45 +0530156 deviceExist, err := dMgr.isParentDeviceExist(ctx, device)
Thomas Lee Se5a44012019-11-07 20:32:24 +0530157 if err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530158 logger.Errorf(ctx, "failed-to-fetch-parent-device-info")
Kent Hagerman45a13e42020-04-13 12:23:50 -0400159 return nil, err
Thomas Lee Se5a44012019-11-07 20:32:24 +0530160 }
161 if deviceExist {
Himani Chawlab4c25912020-11-12 17:16:38 +0530162 logger.Errorf(ctx, "device-is-pre-provisioned-already-with-same-ip-port-or-mac-address")
Kent Hagerman45a13e42020-04-13 12:23:50 -0400163 return nil, errors.New("device is already pre-provisioned")
Thomas Lee S51b5cb82019-10-14 14:49:34 +0530164 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530165 logger.Debugw(ctx, "create-device", log.Fields{"device": device, "aproxy": dMgr.adapterProxy})
khenaidoob9203542018-09-17 22:56:37 -0400166
khenaidoo5e677ae2019-02-28 17:26:29 -0500167 // Ensure this device is set as root
168 device.Root = true
khenaidoob9203542018-09-17 22:56:37 -0400169 // Create and start a device agent for that device
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700170 agent := newAgent(dMgr.adapterProxy, device, dMgr, dMgr.dbPath, dMgr.dProxy, dMgr.defaultTimeout)
Thomas Lee Se5a44012019-11-07 20:32:24 +0530171 device, err = agent.start(ctx, device)
Scott Baker80678602019-11-14 16:57:36 -0800172 if err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530173 logger.Errorw(ctx, "fail-to-start-device", log.Fields{"device-id": agent.deviceID, "error": err})
Kent Hagerman45a13e42020-04-13 12:23:50 -0400174 return nil, err
Scott Baker80678602019-11-14 16:57:36 -0800175 }
khenaidoo442e7c72020-03-10 16:13:48 -0400176 dMgr.addDeviceAgentToMap(agent)
Kent Hagerman45a13e42020-04-13 12:23:50 -0400177 return device, nil
khenaidoob9203542018-09-17 22:56:37 -0400178}
179
Kent Hagerman45a13e42020-04-13 12:23:50 -0400180// EnableDevice activates a device by invoking the adopt_device API on the appropriate adapter
181func (dMgr *Manager) EnableDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530182 ctx = utils.WithRPCMetadataContext(ctx, "EnableDevice")
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000183 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +0530184 logger.Debugw(ctx, "enable-device", log.Fields{"device-id": id.Id})
Kent Hagerman45a13e42020-04-13 12:23:50 -0400185 agent := dMgr.getDeviceAgent(ctx, id.Id)
186 if agent == nil {
187 return nil, status.Errorf(codes.NotFound, "%s", id.Id)
khenaidoob9203542018-09-17 22:56:37 -0400188 }
Kent Hagerman45a13e42020-04-13 12:23:50 -0400189 return &empty.Empty{}, agent.enableDevice(ctx)
khenaidoob9203542018-09-17 22:56:37 -0400190}
191
Kent Hagerman45a13e42020-04-13 12:23:50 -0400192// DisableDevice disables a device along with any child device it may have
193func (dMgr *Manager) DisableDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530194 ctx = utils.WithRPCMetadataContext(ctx, "DisableDevice")
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000195 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +0530196 logger.Debugw(ctx, "disable-device", log.Fields{"device-id": id.Id})
Kent Hagerman45a13e42020-04-13 12:23:50 -0400197 agent := dMgr.getDeviceAgent(ctx, id.Id)
198 if agent == nil {
199 return nil, status.Errorf(codes.NotFound, "%s", id.Id)
khenaidoob9203542018-09-17 22:56:37 -0400200 }
Kent Hagerman45a13e42020-04-13 12:23:50 -0400201 return &empty.Empty{}, agent.disableDevice(ctx)
khenaidoo92e62c52018-10-03 14:02:54 -0400202}
203
Kent Hagerman45a13e42020-04-13 12:23:50 -0400204//RebootDevice invoked the reboot API to the corresponding adapter
205func (dMgr *Manager) RebootDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530206 ctx = utils.WithRPCMetadataContext(ctx, "RebootDevice")
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000207 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +0530208 logger.Debugw(ctx, "reboot-device", log.Fields{"device-id": id.Id})
Kent Hagerman45a13e42020-04-13 12:23:50 -0400209 agent := dMgr.getDeviceAgent(ctx, id.Id)
210 if agent == nil {
211 return nil, status.Errorf(codes.NotFound, "%s", id.Id)
khenaidoo4d4802d2018-10-04 21:59:49 -0400212 }
Kent Hagerman45a13e42020-04-13 12:23:50 -0400213 return &empty.Empty{}, agent.rebootDevice(ctx)
khenaidoo4d4802d2018-10-04 21:59:49 -0400214}
215
Kent Hagerman45a13e42020-04-13 12:23:50 -0400216// DeleteDevice removes a device from the data model
217func (dMgr *Manager) DeleteDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530218 ctx = utils.WithRPCMetadataContext(ctx, "DeleteDevice")
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000219 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +0530220 logger.Debugw(ctx, "delete-device", log.Fields{"device-id": id.Id})
Kent Hagerman45a13e42020-04-13 12:23:50 -0400221 agent := dMgr.getDeviceAgent(ctx, id.Id)
222 if agent == nil {
223 return nil, status.Errorf(codes.NotFound, "%s", id.Id)
khenaidoo4d4802d2018-10-04 21:59:49 -0400224 }
Kent Hagerman45a13e42020-04-13 12:23:50 -0400225 return &empty.Empty{}, agent.deleteDevice(ctx)
226}
227
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530228// ForceDeleteDevice removes a device from the data model forcefully without successfully waiting for the adapters.
229func (dMgr *Manager) ForceDeleteDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530230 ctx = utils.WithRPCMetadataContext(ctx, "ForceDeleteDevice")
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530231 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +0530232 logger.Debugw(ctx, "force-delete-device", log.Fields{"device-id": id.Id})
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530233 agent := dMgr.getDeviceAgent(ctx, id.Id)
234 if agent == nil {
235 return nil, status.Errorf(codes.NotFound, "%s", id.Id)
236 }
237 return &empty.Empty{}, agent.deleteDeviceForce(ctx)
238}
239
Kent Hagerman2a07b862020-06-19 15:23:07 -0400240// GetDevicePort returns the port details for a specific device port entry
241func (dMgr *Manager) GetDevicePort(ctx context.Context, deviceID string, portID uint32) (*voltha.Port, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530242 logger.Debugw(ctx, "get-device-port", log.Fields{"device-id": deviceID})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400243 agent := dMgr.getDeviceAgent(ctx, deviceID)
244 if agent == nil {
245 return nil, status.Errorf(codes.NotFound, "device-%s", deviceID)
246 }
247 return agent.getDevicePort(portID)
248}
249
Kent Hagerman45a13e42020-04-13 12:23:50 -0400250// ListDevicePorts returns the ports details for a specific device entry
251func (dMgr *Manager) ListDevicePorts(ctx context.Context, id *voltha.ID) (*voltha.Ports, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530252 ctx = utils.WithRPCMetadataContext(ctx, "ListDevicePorts")
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000253 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +0530254 logger.Debugw(ctx, "list-device-ports", log.Fields{"device-id": id.Id})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400255 agent := dMgr.getDeviceAgent(ctx, id.Id)
256 if agent == nil {
257 return nil, status.Errorf(codes.NotFound, "device-%s", id.Id)
Kent Hagerman45a13e42020-04-13 12:23:50 -0400258 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400259
260 ports := agent.listDevicePorts()
261 ctr, ret := 0, make([]*voltha.Port, len(ports))
262 for _, port := range ports {
263 ret[ctr] = port
264 ctr++
265 }
266 return &voltha.Ports{Items: ret}, nil
Kent Hagerman45a13e42020-04-13 12:23:50 -0400267}
268
269// ListDeviceFlows returns the flow details for a specific device entry
270func (dMgr *Manager) ListDeviceFlows(ctx context.Context, id *voltha.ID) (*ofp.Flows, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530271 ctx = utils.WithRPCMetadataContext(ctx, "ListDeviceFlows")
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000272 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +0530273 logger.Debugw(ctx, "list-device-flows", log.Fields{"device-id": id.Id})
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700274 agent := dMgr.getDeviceAgent(ctx, id.Id)
275 if agent == nil {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400276 return nil, status.Errorf(codes.NotFound, "device-%s", id.Id)
Kent Hagerman45a13e42020-04-13 12:23:50 -0400277 }
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700278
279 flows := agent.listDeviceFlows()
280 ctr, ret := 0, make([]*ofp.OfpFlowStats, len(flows))
281 for _, flow := range flows {
282 ret[ctr] = flow
283 ctr++
284 }
285 return &openflow_13.Flows{Items: ret}, nil
Kent Hagerman45a13e42020-04-13 12:23:50 -0400286}
287
288// ListDeviceFlowGroups returns the flow group details for a specific device entry
289func (dMgr *Manager) ListDeviceFlowGroups(ctx context.Context, id *voltha.ID) (*voltha.FlowGroups, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530290 ctx = utils.WithRPCMetadataContext(ctx, "ListDeviceFlowGroups")
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000291 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +0530292 logger.Debugw(ctx, "list-device-flow-groups", log.Fields{"device-id": id.Id})
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700293 agent := dMgr.getDeviceAgent(ctx, id.Id)
294 if agent == nil {
Kent Hagerman45a13e42020-04-13 12:23:50 -0400295 return nil, status.Errorf(codes.NotFound, "device-%s", id.Id)
296 }
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700297 groups := agent.listDeviceGroups()
298 ctr, ret := 0, make([]*openflow_13.OfpGroupEntry, len(groups))
299 for _, group := range groups {
300 ret[ctr] = group
301 ctr++
302 }
303 return &voltha.FlowGroups{Items: ret}, nil
khenaidoo4d4802d2018-10-04 21:59:49 -0400304}
305
khenaidoo6d62c002019-05-15 21:57:03 -0400306// stopManagingDevice stops the management of the device as well as any of its reference device and logical device.
307// This function is called only in the Core that does not own this device. In the Core that owns this device then a
308// deletion deletion also includes removal of any reference of this device.
Kent Hagerman2b216042020-04-03 18:28:56 -0400309func (dMgr *Manager) stopManagingDevice(ctx context.Context, id string) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530310 logger.Infow(ctx, "stop-managing-device", log.Fields{"device-id": id})
khenaidoo6d62c002019-05-15 21:57:03 -0400311 if dMgr.IsDeviceInCache(id) { // Proceed only if an agent is present for this device
Kent Hagerman6031aad2020-07-29 16:36:33 -0400312 if device, err := dMgr.getDeviceReadOnly(ctx, id); err == nil && device.Root {
khenaidoo6d62c002019-05-15 21:57:03 -0400313 // stop managing the logical device
David Bainbridged1afd662020-03-26 18:27:41 -0700314 _ = dMgr.logicalDeviceMgr.stopManagingLogicalDeviceWithDeviceID(ctx, id)
khenaidoo6d62c002019-05-15 21:57:03 -0400315 }
npujar467fe752020-01-16 20:17:45 +0530316 if agent := dMgr.getDeviceAgent(ctx, id); agent != nil {
khenaidoo442e7c72020-03-10 16:13:48 -0400317 if err := agent.stop(ctx); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000318 logger.Warnw(ctx, "unable-to-stop-device-agent", log.Fields{"device-id": agent.deviceID, "error": err})
khenaidoo442e7c72020-03-10 16:13:48 -0400319 }
khenaidoo4c9e5592019-09-09 16:20:41 -0400320 dMgr.deleteDeviceAgentFromMap(agent)
khenaidoo6d62c002019-05-15 21:57:03 -0400321 }
322 }
323}
324
npujar1d86a522019-11-14 17:11:16 +0530325// RunPostDeviceDelete removes any reference of this device
Kent Hagerman2b216042020-04-03 18:28:56 -0400326func (dMgr *Manager) RunPostDeviceDelete(ctx context.Context, cDevice *voltha.Device) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530327 logger.Infow(ctx, "run-post-device-delete", log.Fields{"device-id": cDevice.Id})
npujar467fe752020-01-16 20:17:45 +0530328 dMgr.stopManagingDevice(ctx, cDevice.Id)
khenaidoo6d62c002019-05-15 21:57:03 -0400329 return nil
khenaidoo0a822f92019-05-08 15:15:57 -0400330}
331
Kent Hagermancba2f302020-07-28 13:37:36 -0400332// GetDevice exists primarily to implement the gRPC interface.
333// Internal functions should call getDeviceReadOnly instead.
Kent Hagerman45a13e42020-04-13 12:23:50 -0400334func (dMgr *Manager) GetDevice(ctx context.Context, id *voltha.ID) (*voltha.Device, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530335 ctx = utils.WithRPCMetadataContext(ctx, "GetDevice")
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000336 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
Kent Hagermancba2f302020-07-28 13:37:36 -0400337 return dMgr.getDeviceReadOnly(ctx, id.Id)
Kent Hagerman45a13e42020-04-13 12:23:50 -0400338}
339
Kent Hagermancba2f302020-07-28 13:37:36 -0400340// getDeviceReadOnly will returns a device, either from memory or from the dB, if present
341func (dMgr *Manager) getDeviceReadOnly(ctx context.Context, id string) (*voltha.Device, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530342 logger.Debugw(ctx, "get-device-read-only", log.Fields{"device-id": id})
npujar467fe752020-01-16 20:17:45 +0530343 if agent := dMgr.getDeviceAgent(ctx, id); agent != nil {
Kent Hagermancba2f302020-07-28 13:37:36 -0400344 return agent.getDeviceReadOnly(ctx)
khenaidoo92e62c52018-10-03 14:02:54 -0400345 }
346 return nil, status.Errorf(codes.NotFound, "%s", id)
khenaidoob9203542018-09-17 22:56:37 -0400347}
348
Kent Hagerman2a07b862020-06-19 15:23:07 -0400349func (dMgr *Manager) listDevicePorts(ctx context.Context, id string) (map[uint32]*voltha.Port, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530350 logger.Debugw(ctx, "list-device-ports", log.Fields{"device-id": id})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400351 agent := dMgr.getDeviceAgent(ctx, id)
352 if agent == nil {
353 return nil, status.Errorf(codes.NotFound, "%s", id)
354 }
355 return agent.listDevicePorts(), nil
356}
357
npujar1d86a522019-11-14 17:11:16 +0530358// GetChildDevice will return a device, either from memory or from the dB, if present
Kent Hagerman2b216042020-04-03 18:28:56 -0400359func (dMgr *Manager) GetChildDevice(ctx context.Context, parentDeviceID string, serialNumber string, onuID int64, parentPortNo int64) (*voltha.Device, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530360 logger.Debugw(ctx, "get-child-device", log.Fields{"parent-device-id": parentDeviceID, "serialNumber": serialNumber,
361 "parent-port-no": parentPortNo, "onu-id": onuID})
Matt Jeanneret4e241952019-02-28 11:16:04 -0500362
Kent Hagerman2a07b862020-06-19 15:23:07 -0400363 parentDevicePorts, err := dMgr.listDevicePorts(ctx, parentDeviceID)
364 if err != nil {
Matt Jeanneret4e241952019-02-28 11:16:04 -0500365 return nil, status.Errorf(codes.Aborted, "%s", err.Error())
366 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400367 childDeviceIds := dMgr.getAllChildDeviceIds(ctx, parentDevicePorts)
Matt Jeanneret4e241952019-02-28 11:16:04 -0500368 if len(childDeviceIds) == 0 {
Himani Chawlab4c25912020-11-12 17:16:38 +0530369 logger.Debugw(ctx, "no-child-devices", log.Fields{"parent-device-id": parentDeviceID, "serial-number": serialNumber, "onu-id": onuID})
npujar1d86a522019-11-14 17:11:16 +0530370 return nil, status.Errorf(codes.NotFound, "%s", parentDeviceID)
Matt Jeanneret4e241952019-02-28 11:16:04 -0500371 }
372
373 var foundChildDevice *voltha.Device
Kent Hagerman2a07b862020-06-19 15:23:07 -0400374 for childDeviceID := range childDeviceIds {
npujar1d86a522019-11-14 17:11:16 +0530375 var found bool
Kent Hagermancba2f302020-07-28 13:37:36 -0400376 if searchDevice, err := dMgr.getDeviceReadOnly(ctx, childDeviceID); err == nil {
Matt Jeanneret4e241952019-02-28 11:16:04 -0500377
npujar1d86a522019-11-14 17:11:16 +0530378 foundOnuID := false
379 if searchDevice.ProxyAddress.OnuId == uint32(onuID) {
Matt Jeanneret4e241952019-02-28 11:16:04 -0500380 if searchDevice.ParentPortNo == uint32(parentPortNo) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530381 logger.Debugw(ctx, "found-child-by-onuid", log.Fields{"parent-device-id": parentDeviceID, "onu-id": onuID})
npujar1d86a522019-11-14 17:11:16 +0530382 foundOnuID = true
Matt Jeanneret4e241952019-02-28 11:16:04 -0500383 }
384 }
385
386 foundSerialNumber := false
387 if searchDevice.SerialNumber == serialNumber {
Himani Chawlab4c25912020-11-12 17:16:38 +0530388 logger.Debugw(ctx, "found-child-by-serial-number", log.Fields{"parent-device-id": parentDeviceID, "serial-number": serialNumber})
Matt Jeanneret4e241952019-02-28 11:16:04 -0500389 foundSerialNumber = true
390 }
391
392 // if both onuId and serialNumber are provided both must be true for the device to be found
393 // otherwise whichever one found a match is good enough
npujar1d86a522019-11-14 17:11:16 +0530394 if onuID > 0 && serialNumber != "" {
395 found = foundOnuID && foundSerialNumber
Matt Jeanneret4e241952019-02-28 11:16:04 -0500396 } else {
npujar1d86a522019-11-14 17:11:16 +0530397 found = foundOnuID || foundSerialNumber
Matt Jeanneret4e241952019-02-28 11:16:04 -0500398 }
399
npujar1d86a522019-11-14 17:11:16 +0530400 if found {
Matt Jeanneret4e241952019-02-28 11:16:04 -0500401 foundChildDevice = searchDevice
402 break
403 }
404 }
405 }
406
407 if foundChildDevice != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530408 logger.Debugw(ctx, "child-device-found", log.Fields{"parent-device-id": parentDeviceID, "found-child-device": foundChildDevice})
Matt Jeanneret4e241952019-02-28 11:16:04 -0500409 return foundChildDevice, nil
410 }
411
divyadesaicb8b59d2020-08-18 09:55:47 +0000412 logger.Debugw(ctx, "child-device-not-found", log.Fields{"parent-device-id": parentDeviceID,
Himani Chawlab4c25912020-11-12 17:16:38 +0530413 "serial-number": serialNumber, "onu-id": onuID, "parent-port-no": parentPortNo})
npujar1d86a522019-11-14 17:11:16 +0530414 return nil, status.Errorf(codes.NotFound, "%s", parentDeviceID)
Matt Jeanneret4e241952019-02-28 11:16:04 -0500415}
416
npujar1d86a522019-11-14 17:11:16 +0530417// GetChildDeviceWithProxyAddress will return a device based on proxy address
Kent Hagerman2b216042020-04-03 18:28:56 -0400418func (dMgr *Manager) GetChildDeviceWithProxyAddress(ctx context.Context, proxyAddress *voltha.Device_ProxyAddress) (*voltha.Device, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530419 logger.Debugw(ctx, "get-child-device-with-proxy-address", log.Fields{"proxy-address": proxyAddress})
Matt Jeanneret2a20aaa2019-03-05 21:04:02 -0500420
Kent Hagerman2a07b862020-06-19 15:23:07 -0400421 parentDevicePorts, err := dMgr.listDevicePorts(ctx, proxyAddress.DeviceId)
422 if err != nil {
Matt Jeanneret2a20aaa2019-03-05 21:04:02 -0500423 return nil, status.Errorf(codes.Aborted, "%s", err.Error())
424 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400425 childDeviceIds := dMgr.getAllChildDeviceIds(ctx, parentDevicePorts)
Matt Jeanneret2a20aaa2019-03-05 21:04:02 -0500426 if len(childDeviceIds) == 0 {
divyadesaicb8b59d2020-08-18 09:55:47 +0000427 logger.Debugw(ctx, "no-child-devices", log.Fields{"parent-device-id": proxyAddress.DeviceId})
Matt Jeanneret2a20aaa2019-03-05 21:04:02 -0500428 return nil, status.Errorf(codes.NotFound, "%s", proxyAddress)
429 }
430
431 var foundChildDevice *voltha.Device
Kent Hagerman2a07b862020-06-19 15:23:07 -0400432 for childDeviceID := range childDeviceIds {
Kent Hagermancba2f302020-07-28 13:37:36 -0400433 if searchDevice, err := dMgr.getDeviceReadOnly(ctx, childDeviceID); err == nil {
Matt Jeanneret2a20aaa2019-03-05 21:04:02 -0500434 if searchDevice.ProxyAddress == proxyAddress {
435 foundChildDevice = searchDevice
436 break
437 }
438 }
439 }
440
441 if foundChildDevice != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530442 logger.Debugw(ctx, "child-device-found", log.Fields{"proxy-address": proxyAddress})
Matt Jeanneret2a20aaa2019-03-05 21:04:02 -0500443 return foundChildDevice, nil
444 }
445
Himani Chawlab4c25912020-11-12 17:16:38 +0530446 logger.Warnw(ctx, "child-device-not-found", log.Fields{"proxy-address": proxyAddress})
Matt Jeanneret2a20aaa2019-03-05 21:04:02 -0500447 return nil, status.Errorf(codes.NotFound, "%s", proxyAddress)
448}
449
npujar1d86a522019-11-14 17:11:16 +0530450// IsDeviceInCache returns true if device is found in the map
Kent Hagerman2b216042020-04-03 18:28:56 -0400451func (dMgr *Manager) IsDeviceInCache(id string) bool {
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400452 _, exist := dMgr.deviceAgents.Load(id)
khenaidoo297cd252019-02-07 22:10:23 -0500453 return exist
454}
455
Stephane Barbarieaa467942019-02-06 14:09:44 -0500456// ListDevices retrieves the latest devices from the data model
Kent Hagerman45a13e42020-04-13 12:23:50 -0400457func (dMgr *Manager) ListDevices(ctx context.Context, _ *empty.Empty) (*voltha.Devices, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530458 ctx = utils.WithRPCMetadataContext(ctx, "ListDevices")
459 logger.Debug(ctx, "list-devices")
khenaidoob9203542018-09-17 22:56:37 -0400460 result := &voltha.Devices{}
Kent Hagerman4f355f52020-03-30 16:01:33 -0400461
Esin Karamana4e4e002021-03-02 10:42:16 +0000462 dMgr.deviceAgents.Range(func(key, value interface{}) bool {
463 result.Items = append(result.Items, value.(*Agent).device)
464 return true
465 })
Kent Hagerman4f355f52020-03-30 16:01:33 -0400466
Himani Chawlab4c25912020-11-12 17:16:38 +0530467 logger.Debugw(ctx, "list-devices-end", log.Fields{"len": len(result.Items)})
khenaidoob9203542018-09-17 22:56:37 -0400468 return result, nil
469}
470
Thomas Lee S51b5cb82019-10-14 14:49:34 +0530471//isParentDeviceExist checks whether device is already preprovisioned.
Kent Hagerman2b216042020-04-03 18:28:56 -0400472func (dMgr *Manager) isParentDeviceExist(ctx context.Context, newDevice *voltha.Device) (bool, error) {
Thomas Lee S51b5cb82019-10-14 14:49:34 +0530473 hostPort := newDevice.GetHostAndPort()
Kent Hagerman4f355f52020-03-30 16:01:33 -0400474 var devices []*voltha.Device
Kent Hagermanf5a67352020-04-30 15:15:26 -0400475 if err := dMgr.dProxy.List(ctx, &devices); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530476 logger.Errorw(ctx, "failed-to-list-devices-from-cluster-data-proxy", log.Fields{"error": err})
Thomas Lee Se5a44012019-11-07 20:32:24 +0530477 return false, err
478 }
Kent Hagerman4f355f52020-03-30 16:01:33 -0400479 for _, device := range devices {
480 if !device.Root {
481 continue
482 }
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530483
484 if hostPort != "" && hostPort == device.GetHostAndPort() {
Kent Hagerman4f355f52020-03-30 16:01:33 -0400485 return true, nil
486 }
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530487 if newDevice.MacAddress != "" && newDevice.MacAddress == device.MacAddress {
Kent Hagerman4f355f52020-03-30 16:01:33 -0400488 return true, nil
Thomas Lee S51b5cb82019-10-14 14:49:34 +0530489 }
490 }
Thomas Lee Se5a44012019-11-07 20:32:24 +0530491 return false, nil
Thomas Lee S51b5cb82019-10-14 14:49:34 +0530492}
493
khenaidoo6d62c002019-05-15 21:57:03 -0400494//getDeviceFromModelretrieves the device data from the model.
Kent Hagerman2b216042020-04-03 18:28:56 -0400495func (dMgr *Manager) getDeviceFromModel(ctx context.Context, deviceID string) (*voltha.Device, error) {
Kent Hagerman4f355f52020-03-30 16:01:33 -0400496 device := &voltha.Device{}
Kent Hagermanf5a67352020-04-30 15:15:26 -0400497 if have, err := dMgr.dProxy.Get(ctx, deviceID, device); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000498 logger.Errorw(ctx, "failed-to-get-device-info-from-cluster-proxy", log.Fields{"error": err})
Thomas Lee Se5a44012019-11-07 20:32:24 +0530499 return nil, err
Kent Hagerman4f355f52020-03-30 16:01:33 -0400500 } else if !have {
501 return nil, status.Error(codes.NotFound, deviceID)
Thomas Lee Se5a44012019-11-07 20:32:24 +0530502 }
Kent Hagerman4f355f52020-03-30 16:01:33 -0400503
504 return device, nil
khenaidoo6d62c002019-05-15 21:57:03 -0400505}
506
npujar1d86a522019-11-14 17:11:16 +0530507// loadDevice loads the deviceID in memory, if not present
Kent Hagerman2b216042020-04-03 18:28:56 -0400508func (dMgr *Manager) loadDevice(ctx context.Context, deviceID string) (*Agent, error) {
npujar1d86a522019-11-14 17:11:16 +0530509 if deviceID == "" {
khenaidoo297cd252019-02-07 22:10:23 -0500510 return nil, status.Error(codes.InvalidArgument, "deviceId empty")
511 }
khenaidoo4c9e5592019-09-09 16:20:41 -0400512 var err error
513 var device *voltha.Device
514 dMgr.devicesLoadingLock.Lock()
npujar1d86a522019-11-14 17:11:16 +0530515 if _, exist := dMgr.deviceLoadingInProgress[deviceID]; !exist {
516 if !dMgr.IsDeviceInCache(deviceID) {
517 dMgr.deviceLoadingInProgress[deviceID] = []chan int{make(chan int, 1)}
khenaidoo4c9e5592019-09-09 16:20:41 -0400518 dMgr.devicesLoadingLock.Unlock()
519 // Proceed with the loading only if the device exist in the Model (could have been deleted)
npujar467fe752020-01-16 20:17:45 +0530520 if device, err = dMgr.getDeviceFromModel(ctx, deviceID); err == nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000521 logger.Debugw(ctx, "loading-device", log.Fields{"device-id": deviceID})
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700522 agent := newAgent(dMgr.adapterProxy, device, dMgr, dMgr.dbPath, dMgr.dProxy, dMgr.defaultTimeout)
npujar467fe752020-01-16 20:17:45 +0530523 if _, err = agent.start(ctx, nil); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530524 logger.Warnw(ctx, "failure-loading-device", log.Fields{"device-id": deviceID, "error": err})
khenaidoo4c9e5592019-09-09 16:20:41 -0400525 } else {
526 dMgr.addDeviceAgentToMap(agent)
527 }
528 } else {
Himani Chawlab4c25912020-11-12 17:16:38 +0530529 logger.Debugw(ctx, "device-is-not-in-model", log.Fields{"device-id": deviceID})
khenaidoo6d62c002019-05-15 21:57:03 -0400530 }
khenaidoo4c9e5592019-09-09 16:20:41 -0400531 // announce completion of task to any number of waiting channels
532 dMgr.devicesLoadingLock.Lock()
npujar1d86a522019-11-14 17:11:16 +0530533 if v, ok := dMgr.deviceLoadingInProgress[deviceID]; ok {
khenaidoo4c9e5592019-09-09 16:20:41 -0400534 for _, ch := range v {
535 close(ch)
536 }
npujar1d86a522019-11-14 17:11:16 +0530537 delete(dMgr.deviceLoadingInProgress, deviceID)
khenaidoo4c9e5592019-09-09 16:20:41 -0400538 }
539 dMgr.devicesLoadingLock.Unlock()
khenaidoo6d62c002019-05-15 21:57:03 -0400540 } else {
khenaidoo4c9e5592019-09-09 16:20:41 -0400541 dMgr.devicesLoadingLock.Unlock()
khenaidoo297cd252019-02-07 22:10:23 -0500542 }
khenaidoo4c9e5592019-09-09 16:20:41 -0400543 } else {
544 ch := make(chan int, 1)
npujar1d86a522019-11-14 17:11:16 +0530545 dMgr.deviceLoadingInProgress[deviceID] = append(dMgr.deviceLoadingInProgress[deviceID], ch)
khenaidoo4c9e5592019-09-09 16:20:41 -0400546 dMgr.devicesLoadingLock.Unlock()
547 // Wait for the channel to be closed, implying the process loading this device is done.
548 <-ch
khenaidoo297cd252019-02-07 22:10:23 -0500549 }
npujar1d86a522019-11-14 17:11:16 +0530550 if agent, ok := dMgr.deviceAgents.Load(deviceID); ok {
Kent Hagerman2b216042020-04-03 18:28:56 -0400551 return agent.(*Agent), nil
khenaidoo297cd252019-02-07 22:10:23 -0500552 }
npujar1d86a522019-11-14 17:11:16 +0530553 return nil, status.Errorf(codes.Aborted, "Error loading device %s", deviceID)
khenaidoo297cd252019-02-07 22:10:23 -0500554}
555
556// loadRootDeviceParentAndChildren loads the children and parents of a root device in memory
Kent Hagerman2a07b862020-06-19 15:23:07 -0400557func (dMgr *Manager) loadRootDeviceParentAndChildren(ctx context.Context, device *voltha.Device, devicePorts map[uint32]*voltha.Port) error {
divyadesaicb8b59d2020-08-18 09:55:47 +0000558 logger.Debugw(ctx, "loading-parent-and-children", log.Fields{"device-id": device.Id})
khenaidoo297cd252019-02-07 22:10:23 -0500559 if device.Root {
560 // Scenario A
561 if device.ParentId != "" {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400562 // Load logical device if needed.
npujar467fe752020-01-16 20:17:45 +0530563 if err := dMgr.logicalDeviceMgr.load(ctx, device.ParentId); err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000564 logger.Warnw(ctx, "failure-loading-logical-device", log.Fields{"logical-device-id": device.ParentId})
khenaidoo297cd252019-02-07 22:10:23 -0500565 }
566 } else {
divyadesaicb8b59d2020-08-18 09:55:47 +0000567 logger.Debugw(ctx, "no-parent-to-load", log.Fields{"device-id": device.Id})
khenaidoo297cd252019-02-07 22:10:23 -0500568 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400569 // Load all child devices, if needed
570 childDeviceIds := dMgr.getAllChildDeviceIds(ctx, devicePorts)
571 for childDeviceID := range childDeviceIds {
572 if _, err := dMgr.loadDevice(ctx, childDeviceID); err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000573 logger.Warnw(ctx, "failure-loading-device", log.Fields{"device-id": childDeviceID, "error": err})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400574 return err
khenaidoo297cd252019-02-07 22:10:23 -0500575 }
khenaidoo297cd252019-02-07 22:10:23 -0500576 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530577 logger.Debugw(ctx, "loaded-children", log.Fields{"device-id": device.Id, "num-children": len(childDeviceIds)})
khenaidoo297cd252019-02-07 22:10:23 -0500578 }
579 return nil
580}
581
582// load loads the deviceId in memory, if not present, and also loads its accompanying parents and children. Loading
583// in memory is for improved performance. It is not imperative that a device needs to be in memory when a request
584// acting on the device is received by the core. In such a scenario, the Core will load the device in memory first
585// and the proceed with the request.
Kent Hagerman2b216042020-04-03 18:28:56 -0400586func (dMgr *Manager) load(ctx context.Context, deviceID string) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000587 logger.Debug(ctx, "load...")
khenaidoo297cd252019-02-07 22:10:23 -0500588 // 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 -0400589 var dAgent *Agent
khenaidoo297cd252019-02-07 22:10:23 -0500590 var err error
npujar467fe752020-01-16 20:17:45 +0530591 if dAgent, err = dMgr.loadDevice(ctx, deviceID); err != nil {
khenaidoo297cd252019-02-07 22:10:23 -0500592 return err
593 }
594 // Get the loaded device details
Kent Hagermancba2f302020-07-28 13:37:36 -0400595 device, err := dAgent.getDeviceReadOnly(ctx)
khenaidoo442e7c72020-03-10 16:13:48 -0400596 if err != nil {
597 return err
598 }
khenaidoo297cd252019-02-07 22:10:23 -0500599
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530600 // If the device is in Pre-provisioning or getting deleted state stop here
601 if device.AdminState == voltha.AdminState_PREPROVISIONED || dAgent.isDeletionInProgress() {
khenaidoo297cd252019-02-07 22:10:23 -0500602 return nil
603 }
604
605 // Now we face two scenarios
606 if device.Root {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400607 devicePorts := dAgent.listDevicePorts()
608
khenaidoo297cd252019-02-07 22:10:23 -0500609 // Load all children as well as the parent of this device (logical_device)
Kent Hagerman2a07b862020-06-19 15:23:07 -0400610 if err := dMgr.loadRootDeviceParentAndChildren(ctx, device, devicePorts); err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000611 logger.Warnw(ctx, "failure-loading-device-parent-and-children", log.Fields{"device-id": deviceID})
khenaidoo297cd252019-02-07 22:10:23 -0500612 return err
613 }
divyadesaicb8b59d2020-08-18 09:55:47 +0000614 logger.Debugw(ctx, "successfully-loaded-parent-and-children", log.Fields{"device-id": deviceID})
Andrey Pozolotin34dd63f2021-05-31 21:26:40 +0300615 } else if device.ParentId != "" {
khenaidoo297cd252019-02-07 22:10:23 -0500616 // Scenario B - use the parentId of that device (root device) to trigger the loading
Andrey Pozolotin34dd63f2021-05-31 21:26:40 +0300617 return dMgr.load(ctx, device.ParentId)
khenaidoo297cd252019-02-07 22:10:23 -0500618 }
Andrey Pozolotin34dd63f2021-05-31 21:26:40 +0300619
khenaidoo297cd252019-02-07 22:10:23 -0500620 return nil
621}
622
khenaidoo7ccedd52018-12-14 16:48:54 -0500623// ListDeviceIds retrieves the latest device IDs information from the data model (memory data only)
Rohan Agrawal31f21802020-06-12 05:38:46 +0000624func (dMgr *Manager) ListDeviceIds(ctx context.Context, _ *empty.Empty) (*voltha.IDs, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530625 ctx = utils.WithRPCMetadataContext(ctx, "ListDeviceIds")
626 logger.Debug(ctx, "list-device-ids")
khenaidoo7ccedd52018-12-14 16:48:54 -0500627 // Report only device IDs that are in the device agent map
628 return dMgr.listDeviceIdsFromMap(), nil
629}
630
Kent Hagerman45a13e42020-04-13 12:23:50 -0400631// ReconcileDevices is a request to a voltha core to update its list of managed devices. This will
632// trigger loading the devices along with their children and parent in memory
633func (dMgr *Manager) ReconcileDevices(ctx context.Context, ids *voltha.IDs) (*empty.Empty, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530634 ctx = utils.WithRPCMetadataContext(ctx, "ReconcileDevices")
Andrey Pozolotin34dd63f2021-05-31 21:26:40 +0300635
636 numDevices := 0
637 if ids != nil {
638 numDevices = len(ids.Items)
639 }
640
641 logger.Debugw(ctx, "reconcile-devices", log.Fields{"num-devices": numDevices})
khenaidoo4c9e5592019-09-09 16:20:41 -0400642 if ids != nil && len(ids.Items) != 0 {
khenaidoo7ccedd52018-12-14 16:48:54 -0500643 toReconcile := len(ids.Items)
644 reconciled := 0
khenaidoo4c9e5592019-09-09 16:20:41 -0400645 var err error
khenaidoo7ccedd52018-12-14 16:48:54 -0500646 for _, id := range ids.Items {
npujar467fe752020-01-16 20:17:45 +0530647 if err = dMgr.load(ctx, id.Id); err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000648 logger.Warnw(ctx, "failure-reconciling-device", log.Fields{"device-id": id.Id, "error": err})
khenaidoo4c9e5592019-09-09 16:20:41 -0400649 } else {
npujar1d86a522019-11-14 17:11:16 +0530650 reconciled++
khenaidoo7ccedd52018-12-14 16:48:54 -0500651 }
652 }
653 if toReconcile != reconciled {
Kent Hagerman45a13e42020-04-13 12:23:50 -0400654 return nil, status.Errorf(codes.DataLoss, "less-device-reconciled-than-requested:%d/%d", reconciled, toReconcile)
khenaidoo7ccedd52018-12-14 16:48:54 -0500655 }
656 } else {
Kent Hagerman45a13e42020-04-13 12:23:50 -0400657 return nil, status.Errorf(codes.InvalidArgument, "empty-list-of-ids")
khenaidoo7ccedd52018-12-14 16:48:54 -0500658 }
Kent Hagerman45a13e42020-04-13 12:23:50 -0400659 return &empty.Empty{}, nil
khenaidoo7ccedd52018-12-14 16:48:54 -0500660}
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500661
khenaidooba6b6c42019-08-02 09:11:56 -0400662// adapterRestarted is invoked whenever an adapter is restarted
Kent Hagerman2b216042020-04-03 18:28:56 -0400663func (dMgr *Manager) adapterRestarted(ctx context.Context, adapter *voltha.Adapter) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530664 logger.Debugw(ctx, "adapter-restarted", log.Fields{"adapter-id": adapter.Id, "vendor": adapter.Vendor,
665 "current-replica": adapter.CurrentReplica, "total-replicas": adapter.TotalReplicas, "endpoint": adapter.Endpoint})
khenaidooba6b6c42019-08-02 09:11:56 -0400666
667 // Let's reconcile the device managed by this Core only
David Bainbridged1afd662020-03-26 18:27:41 -0700668 if len(dMgr.rootDevices) == 0 {
Himani Chawlab4c25912020-11-12 17:16:38 +0530669 logger.Debugw(ctx, "nothing-to-reconcile", log.Fields{"adapter-id": adapter.Id})
khenaidooba6b6c42019-08-02 09:11:56 -0400670 return nil
671 }
672
Maninder0aabf0c2021-03-17 14:55:14 +0530673 if len(dMgr.rootDevices) == 0 {
674 logger.Debugw(ctx, "no-managed-device-to-reconcile", log.Fields{"adapter-id": adapter.Id})
675 return nil
676 }
677
David Bainbridged1afd662020-03-26 18:27:41 -0700678 for rootDeviceID := range dMgr.rootDevices {
Mahir Gunyel12cf55f2020-12-16 17:55:03 -0800679 dAgent := dMgr.getDeviceAgent(ctx, rootDeviceID)
680 if dAgent == nil {
681 continue
682 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530683 logger.Debugw(ctx, "checking-adapter-type", log.Fields{"agentType": dAgent.deviceType, "adapter-type": adapter.Type})
Mahir Gunyel12cf55f2020-12-16 17:55:03 -0800684 if dAgent.deviceType == adapter.Type {
685 rootDevice, _ := dAgent.getDeviceReadOnly(ctx)
686 if rootDevice == nil {
687 continue
688 }
Rohan Agrawal31f21802020-06-12 05:38:46 +0000689 isDeviceOwnedByService, err := dMgr.adapterProxy.IsDeviceOwnedByService(ctx, rootDeviceID, adapter.Type, adapter.CurrentReplica)
serkant.uluderya7d545aa2020-04-09 13:38:45 -0700690 if err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530691 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 -0700692 continue
693 }
694 if isDeviceOwnedByService {
Maninder0aabf0c2021-03-17 14:55:14 +0530695 if rootDevice.AdminState != voltha.AdminState_PREPROVISIONED {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000696 logger.Debugw(ctx, "reconciling-root-device", log.Fields{"rootId": rootDevice.Id})
Maninder0aabf0c2021-03-17 14:55:14 +0530697 go dAgent.ReconcileDevice(ctx, rootDevice)
khenaidooba6b6c42019-08-02 09:11:56 -0400698 } else {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000699 logger.Debugw(ctx, "not-reconciling-root-device", log.Fields{"rootId": rootDevice.Id, "state": rootDevice.AdminState})
khenaidooba6b6c42019-08-02 09:11:56 -0400700 }
701 } else { // Should we be reconciling the root's children instead?
Kent Hagerman2a07b862020-06-19 15:23:07 -0400702 rootDevicePorts, _ := dMgr.listDevicePorts(ctx, rootDeviceID)
khenaidooba6b6c42019-08-02 09:11:56 -0400703 childManagedByAdapter:
Kent Hagerman2a07b862020-06-19 15:23:07 -0400704 for _, port := range rootDevicePorts {
khenaidooba6b6c42019-08-02 09:11:56 -0400705 for _, peer := range port.Peers {
npujar467fe752020-01-16 20:17:45 +0530706 if childDevice, _ := dMgr.getDeviceFromModel(ctx, peer.DeviceId); childDevice != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000707 isDeviceOwnedByService, err := dMgr.adapterProxy.IsDeviceOwnedByService(ctx, childDevice.Id, adapter.Type, adapter.CurrentReplica)
serkant.uluderya7d545aa2020-04-09 13:38:45 -0700708 if err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530709 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 -0700710 }
711 if isDeviceOwnedByService {
Maninder0aabf0c2021-03-17 14:55:14 +0530712 if childDevice.AdminState != voltha.AdminState_PREPROVISIONED {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000713 logger.Debugw(ctx, "reconciling-child-device", log.Fields{"child-device-id": childDevice.Id})
Maninder0aabf0c2021-03-17 14:55:14 +0530714 go dAgent.ReconcileDevice(ctx, childDevice)
khenaidooba6b6c42019-08-02 09:11:56 -0400715 } else {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000716 logger.Debugw(ctx, "not-reconciling-child-device", log.Fields{"child-device-id": childDevice.Id, "state": childDevice.AdminState})
khenaidooba6b6c42019-08-02 09:11:56 -0400717 }
718 } else {
719 // All child devices under a parent device are typically managed by the same adapter type.
720 // Therefore we only need to check whether the first device we retrieved is managed by that adapter
721 break childManagedByAdapter
722 }
723 }
724 }
725 }
726 }
727 }
728 }
Maninder0aabf0c2021-03-17 14:55:14 +0530729 logger.Debugw(ctx, "Reconciling for device on adapter restart is initiated", log.Fields{"adapter-id": adapter.Id})
730
khenaidooba6b6c42019-08-02 09:11:56 -0400731 return nil
732}
733
Kent Hagerman2b216042020-04-03 18:28:56 -0400734func (dMgr *Manager) ReconcileChildDevices(ctx context.Context, parentDeviceID string) error {
Maninder0aabf0c2021-03-17 14:55:14 +0530735 dAgent := dMgr.getDeviceAgent(ctx, parentDeviceID)
736 if dAgent == nil {
737 return status.Errorf(codes.NotFound, "error-unable to get agent from device")
738 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400739 if parentDevicePorts, err := dMgr.listDevicePorts(ctx, parentDeviceID); err == nil {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400740 for _, port := range parentDevicePorts {
khenaidooba6b6c42019-08-02 09:11:56 -0400741 for _, peer := range port.Peers {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400742 if childDevice, err := dMgr.getDeviceFromModel(ctx, peer.DeviceId); err == nil {
Maninder0aabf0c2021-03-17 14:55:14 +0530743 go dAgent.ReconcileDevice(ctx, childDevice)
khenaidooba6b6c42019-08-02 09:11:56 -0400744 }
745 }
746 }
Maninder0aabf0c2021-03-17 14:55:14 +0530747 logger.Debugw(ctx, "Reconcile initiated for child devices", log.Fields{"parent-device-id": parentDeviceID})
khenaidooba6b6c42019-08-02 09:11:56 -0400748 }
749 return nil
750}
751
Kent Hagerman2b216042020-04-03 18:28:56 -0400752func (dMgr *Manager) UpdateDeviceUsingAdapterData(ctx context.Context, device *voltha.Device) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530753 logger.Debugw(ctx, "update-device-using-adapter-data", log.Fields{"device-id": device.Id, "device": device})
npujar467fe752020-01-16 20:17:45 +0530754 if agent := dMgr.getDeviceAgent(ctx, device.Id); agent != nil {
755 return agent.updateDeviceUsingAdapterData(ctx, device)
khenaidoob9203542018-09-17 22:56:37 -0400756 }
757 return status.Errorf(codes.NotFound, "%s", device.Id)
758}
759
khenaidoo0db4c812020-05-27 15:27:30 -0400760func (dMgr *Manager) addPeerPort(ctx context.Context, deviceID string, port *voltha.Port) error {
761 meAsPeer := &voltha.Port_PeerPort{DeviceId: deviceID, PortNo: port.PortNo}
762 for _, peerPort := range port.Peers {
763 if agent := dMgr.getDeviceAgent(ctx, peerPort.DeviceId); agent != nil {
764 if err := agent.addPeerPort(ctx, meAsPeer); err != nil {
765 return err
766 }
767 }
768 }
769 // Notify the logical device manager to setup a logical port, if needed. If the added port is an NNI or UNI
770 // then a logical port will be added to the logical device and the device route generated. If the port is a
771 // PON port then only the device graph will be generated.
Kent Hagermancba2f302020-07-28 13:37:36 -0400772 device, err := dMgr.getDeviceReadOnly(ctx, deviceID)
khenaidoo0db4c812020-05-27 15:27:30 -0400773 if err != nil {
774 return err
775 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400776 ports, err := dMgr.listDevicePorts(ctx, deviceID)
777 if err != nil {
778 return err
779 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530780 subCtx := utils.WithSpanAndRPCMetadataFromContext(ctx)
781
782 if err = dMgr.logicalDeviceMgr.updateLogicalPort(subCtx, device, ports, port); err != nil {
khenaidoo0db4c812020-05-27 15:27:30 -0400783 return err
784 }
785 return nil
786}
787
Kent Hagerman2b216042020-04-03 18:28:56 -0400788func (dMgr *Manager) AddPort(ctx context.Context, deviceID string, port *voltha.Port) error {
npujar467fe752020-01-16 20:17:45 +0530789 agent := dMgr.getDeviceAgent(ctx, deviceID)
npujar1d86a522019-11-14 17:11:16 +0530790 if agent != nil {
npujar467fe752020-01-16 20:17:45 +0530791 if err := agent.addPort(ctx, port); err != nil {
khenaidoo92e62c52018-10-03 14:02:54 -0400792 return err
793 }
khenaidoo0db4c812020-05-27 15:27:30 -0400794 // Setup peer ports in its own routine
795 go func() {
Himani Chawlab4c25912020-11-12 17:16:38 +0530796 subCtx := utils.WithSpanAndRPCMetadataFromContext(ctx)
797 if err := dMgr.addPeerPort(subCtx, deviceID, port); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000798 logger.Errorw(ctx, "unable-to-add-peer-port", log.Fields{"error": err, "device-id": deviceID})
khenaidoo92e62c52018-10-03 14:02:54 -0400799 }
khenaidoo0db4c812020-05-27 15:27:30 -0400800 }()
khenaidoo92e62c52018-10-03 14:02:54 -0400801 return nil
khenaidoob9203542018-09-17 22:56:37 -0400802 }
npujar1d86a522019-11-14 17:11:16 +0530803 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoob9203542018-09-17 22:56:37 -0400804}
805
Kent Hagerman2b216042020-04-03 18:28:56 -0400806func (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 +0530807 logger.Debugw(ctx, "add-flows-and-groups", log.Fields{"device-id": deviceID, "groups:": groups, "flow-metadata": flowMetadata})
npujar467fe752020-01-16 20:17:45 +0530808 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
809 return agent.addFlowsAndGroups(ctx, flows, groups, flowMetadata)
khenaidoo0458db62019-06-20 08:50:36 -0400810 }
npujar1d86a522019-11-14 17:11:16 +0530811 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo0458db62019-06-20 08:50:36 -0400812}
813
khenaidoo787224a2020-04-16 18:08:47 -0400814// deleteParentFlows removes flows from the parent device based on specific attributes
815func (dMgr *Manager) deleteParentFlows(ctx context.Context, deviceID string, uniPort uint32, metadata *voltha.FlowMetadata) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530816 logger.Debugw(ctx, "delete-parent-flows", log.Fields{"device-id": deviceID, "uni-port": uniPort, "metadata": metadata})
khenaidoo787224a2020-04-16 18:08:47 -0400817 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400818 if !agent.isRootDevice {
khenaidoo787224a2020-04-16 18:08:47 -0400819 return status.Errorf(codes.FailedPrecondition, "not-a-parent-device-%s", deviceID)
820 }
821 return agent.filterOutFlows(ctx, uniPort, metadata)
822 }
823 return status.Errorf(codes.NotFound, "%s", deviceID)
824}
825
Kent Hagerman2b216042020-04-03 18:28:56 -0400826func (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 +0530827 logger.Debugw(ctx, "delete-flows-and-groups", log.Fields{"device-id": deviceID})
npujar467fe752020-01-16 20:17:45 +0530828 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
829 return agent.deleteFlowsAndGroups(ctx, flows, groups, flowMetadata)
khenaidoo0458db62019-06-20 08:50:36 -0400830 }
npujar1d86a522019-11-14 17:11:16 +0530831 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo0458db62019-06-20 08:50:36 -0400832}
833
Kent Hagerman2b216042020-04-03 18:28:56 -0400834func (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 +0530835 logger.Debugw(ctx, "update-flows-and-groups", log.Fields{"device-id": deviceID})
npujar467fe752020-01-16 20:17:45 +0530836 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
837 return agent.updateFlowsAndGroups(ctx, flows, groups, flowMetadata)
khenaidoo19d7b632018-10-30 10:49:50 -0400838 }
npujar1d86a522019-11-14 17:11:16 +0530839 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo19d7b632018-10-30 10:49:50 -0400840}
841
Kent Hagerman45a13e42020-04-13 12:23:50 -0400842// UpdateDevicePmConfigs updates the PM configs. This is executed when the northbound gRPC API is invoked, typically
khenaidoob3127472019-07-24 21:04:55 -0400843// following a user action
Kent Hagerman45a13e42020-04-13 12:23:50 -0400844func (dMgr *Manager) UpdateDevicePmConfigs(ctx context.Context, configs *voltha.PmConfigs) (*empty.Empty, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530845 ctx = utils.WithRPCMetadataContext(ctx, "UpdateDevicePmConfigs")
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000846 log.EnrichSpan(ctx, log.Fields{"device-id": configs.Id})
Kent Hagerman45a13e42020-04-13 12:23:50 -0400847 if configs.Id == "" {
848 return nil, status.Error(codes.FailedPrecondition, "invalid-device-Id")
khenaidoob3127472019-07-24 21:04:55 -0400849 }
Kent Hagerman45a13e42020-04-13 12:23:50 -0400850 agent := dMgr.getDeviceAgent(ctx, configs.Id)
851 if agent == nil {
852 return nil, status.Errorf(codes.NotFound, "%s", configs.Id)
853 }
854 return &empty.Empty{}, agent.updatePmConfigs(ctx, configs)
khenaidoob3127472019-07-24 21:04:55 -0400855}
856
Kent Hagerman2b216042020-04-03 18:28:56 -0400857// InitPmConfigs initialize the pm configs as defined by the adapter.
858func (dMgr *Manager) InitPmConfigs(ctx context.Context, deviceID string, pmConfigs *voltha.PmConfigs) error {
khenaidoob3127472019-07-24 21:04:55 -0400859 if pmConfigs.Id == "" {
860 return status.Errorf(codes.FailedPrecondition, "invalid-device-Id")
861 }
npujar467fe752020-01-16 20:17:45 +0530862 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
863 return agent.initPmConfigs(ctx, pmConfigs)
khenaidoob9203542018-09-17 22:56:37 -0400864 }
npujar1d86a522019-11-14 17:11:16 +0530865 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoob9203542018-09-17 22:56:37 -0400866}
867
Kent Hagerman45a13e42020-04-13 12:23:50 -0400868// ListDevicePmConfigs returns pm configs of device
869func (dMgr *Manager) ListDevicePmConfigs(ctx context.Context, id *voltha.ID) (*voltha.PmConfigs, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530870 ctx = utils.WithRPCMetadataContext(ctx, "ListDevicePmConfigs")
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000871 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
Kent Hagerman45a13e42020-04-13 12:23:50 -0400872 agent := dMgr.getDeviceAgent(ctx, id.Id)
873 if agent == nil {
874 return nil, status.Errorf(codes.NotFound, "%s", id.Id)
khenaidoob3127472019-07-24 21:04:55 -0400875 }
Kent Hagerman45a13e42020-04-13 12:23:50 -0400876 return agent.listPmConfigs(ctx)
khenaidoob3127472019-07-24 21:04:55 -0400877}
878
Kent Hagerman2b216042020-04-03 18:28:56 -0400879func (dMgr *Manager) getSwitchCapability(ctx context.Context, deviceID string) (*ic.SwitchCapability, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530880 logger.Debugw(ctx, "get-switch-capability", log.Fields{"device-id": deviceID})
npujar467fe752020-01-16 20:17:45 +0530881 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
khenaidoob9203542018-09-17 22:56:37 -0400882 return agent.getSwitchCapability(ctx)
883 }
npujar1d86a522019-11-14 17:11:16 +0530884 return nil, status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoob9203542018-09-17 22:56:37 -0400885}
886
Kent Hagerman2b216042020-04-03 18:28:56 -0400887func (dMgr *Manager) GetPorts(ctx context.Context, deviceID string, portType voltha.Port_PortType) (*voltha.Ports, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530888 logger.Debugw(ctx, "get-ports", log.Fields{"device-id": deviceID, "port-type": portType})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400889 agent := dMgr.getDeviceAgent(ctx, deviceID)
890 if agent == nil {
891 return nil, status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoob9203542018-09-17 22:56:37 -0400892 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400893 return agent.getPorts(ctx, portType), nil
khenaidoob9203542018-09-17 22:56:37 -0400894}
895
Kent Hagerman2b216042020-04-03 18:28:56 -0400896func (dMgr *Manager) UpdateDeviceStatus(ctx context.Context, deviceID string, operStatus voltha.OperStatus_Types, connStatus voltha.ConnectStatus_Types) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530897 logger.Debugw(ctx, "update-device-status", log.Fields{"device-id": deviceID, "oper-status": operStatus, "conn-status": connStatus})
npujar467fe752020-01-16 20:17:45 +0530898 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
899 return agent.updateDeviceStatus(ctx, operStatus, connStatus)
khenaidoo92e62c52018-10-03 14:02:54 -0400900 }
npujar1d86a522019-11-14 17:11:16 +0530901 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo92e62c52018-10-03 14:02:54 -0400902}
903
Kent Hagerman2b216042020-04-03 18:28:56 -0400904func (dMgr *Manager) UpdateChildrenStatus(ctx context.Context, deviceID string, operStatus voltha.OperStatus_Types, connStatus voltha.ConnectStatus_Types) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530905 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 -0400906 parentDevicePorts, err := dMgr.listDevicePorts(ctx, deviceID)
907 if err != nil {
khenaidoo4d4802d2018-10-04 21:59:49 -0400908 return status.Errorf(codes.Aborted, "%s", err.Error())
909 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400910 for childDeviceID := range dMgr.getAllChildDeviceIds(ctx, parentDevicePorts) {
npujar467fe752020-01-16 20:17:45 +0530911 if agent := dMgr.getDeviceAgent(ctx, childDeviceID); agent != nil {
912 if err = agent.updateDeviceStatus(ctx, operStatus, connStatus); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530913 return status.Errorf(codes.Aborted, "childDevice:%s, error:%s", childDeviceID, err.Error())
khenaidoo4d4802d2018-10-04 21:59:49 -0400914 }
915 }
916 }
917 return nil
918}
919
Kent Hagerman2b216042020-04-03 18:28:56 -0400920func (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 +0530921 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 +0530922 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
923 if err := agent.updatePortState(ctx, portType, portNo, operStatus); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530924 logger.Errorw(ctx, "updating-port-state-failed", log.Fields{"device-id": deviceID, "port-no": portNo, "error": err})
khenaidoo171b98e2019-10-31 11:48:15 -0400925 return err
926 }
927 // Notify the logical device manager to change the port state
Mahir Gunyel18fa0c92020-03-06 13:34:04 -0800928 // Do this for NNI and UNIs only. PON ports are not known by logical device
929 if portType == voltha.Port_ETHERNET_NNI || portType == voltha.Port_ETHERNET_UNI {
930 go func() {
Himani Chawlab4c25912020-11-12 17:16:38 +0530931 subCtx := utils.WithSpanAndRPCMetadataFromContext(ctx)
932 err := dMgr.logicalDeviceMgr.updatePortState(subCtx, deviceID, portNo, operStatus)
Mahir Gunyel18fa0c92020-03-06 13:34:04 -0800933 if err != nil {
934 // While we want to handle (catch) and log when
935 // an update to a port was not able to be
936 // propagated to the logical port, we can report
937 // it as a warning and not an error because it
938 // doesn't stop or modify processing.
939 // TODO: VOL-2707
Rohan Agrawal31f21802020-06-12 05:38:46 +0000940 logger.Warnw(ctx, "unable-to-update-logical-port-state", log.Fields{"error": err})
Mahir Gunyel18fa0c92020-03-06 13:34:04 -0800941 }
942 }()
943 }
khenaidoo442e7c72020-03-10 16:13:48 -0400944 return nil
khenaidoob9203542018-09-17 22:56:37 -0400945 }
npujar1d86a522019-11-14 17:11:16 +0530946 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoob9203542018-09-17 22:56:37 -0400947}
948
Kent Hagerman2b216042020-04-03 18:28:56 -0400949func (dMgr *Manager) DeleteAllPorts(ctx context.Context, deviceID string) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530950 logger.Debugw(ctx, "delete-all-ports", log.Fields{"device-id": deviceID})
npujar467fe752020-01-16 20:17:45 +0530951 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
952 if err := agent.deleteAllPorts(ctx); err != nil {
khenaidoo0a822f92019-05-08 15:15:57 -0400953 return err
954 }
955 // Notify the logical device manager to remove all logical ports, if needed.
Kent Hagerman2b216042020-04-03 18:28:56 -0400956 // At this stage the device itself may gave been deleted already at a DeleteAllPorts
khenaidoo0a822f92019-05-08 15:15:57 -0400957 // typically is part of a device deletion phase.
Kent Hagermancba2f302020-07-28 13:37:36 -0400958 if device, err := dMgr.getDeviceReadOnly(ctx, deviceID); err == nil {
npujar1d86a522019-11-14 17:11:16 +0530959 go func() {
Himani Chawlab4c25912020-11-12 17:16:38 +0530960 subCtx := utils.WithSpanAndRPCMetadataFromContext(ctx)
961 if err := dMgr.logicalDeviceMgr.deleteAllLogicalPorts(subCtx, device); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000962 logger.Errorw(ctx, "unable-to-delete-logical-ports", log.Fields{"error": err})
npujar1d86a522019-11-14 17:11:16 +0530963 }
964 }()
khenaidoo0a822f92019-05-08 15:15:57 -0400965 } else {
divyadesaicb8b59d2020-08-18 09:55:47 +0000966 logger.Warnw(ctx, "failed-to-retrieve-device", log.Fields{"device-id": deviceID})
khenaidoo0a822f92019-05-08 15:15:57 -0400967 return err
968 }
969 return nil
970 }
npujar1d86a522019-11-14 17:11:16 +0530971 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo0a822f92019-05-08 15:15:57 -0400972}
973
Kent Hagerman2b216042020-04-03 18:28:56 -0400974//UpdatePortsState updates all ports on the device
Kent Hagerman2a07b862020-06-19 15:23:07 -0400975func (dMgr *Manager) UpdatePortsState(ctx context.Context, deviceID string, portTypeFilter uint32, state voltha.OperStatus_Types) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530976 logger.Debugw(ctx, "update-ports-state", log.Fields{"device-id": deviceID})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400977 agent := dMgr.getDeviceAgent(ctx, deviceID)
978 if agent == nil {
979 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo3ab34882019-05-02 21:33:30 -0400980 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400981 if state != voltha.OperStatus_ACTIVE && state != voltha.OperStatus_UNKNOWN {
982 return status.Error(codes.Unimplemented, "state-change-not-implemented")
983 }
984 if err := agent.updatePortsOperState(ctx, portTypeFilter, state); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530985 logger.Warnw(ctx, "update-ports-state-failed", log.Fields{"device-id": deviceID, "error": err})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400986 return err
987 }
988 return nil
khenaidoo3ab34882019-05-02 21:33:30 -0400989}
990
Kent Hagerman2b216042020-04-03 18:28:56 -0400991func (dMgr *Manager) ChildDeviceDetected(ctx context.Context, parentDeviceID string, parentPortNo int64, deviceType string,
npujar1d86a522019-11-14 17:11:16 +0530992 channelID int64, vendorID string, serialNumber string, onuID int64) (*voltha.Device, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530993 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 -0700994
npujar1d86a522019-11-14 17:11:16 +0530995 if deviceType == "" && vendorID != "" {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000996 logger.Debug(ctx, "device-type-is-nil-fetching-device-type")
Kent Hagerman45a13e42020-04-13 12:23:50 -0400997 deviceTypes, err := dMgr.adapterMgr.ListDeviceTypes(ctx, nil)
998 if err != nil {
999 return nil, err
1000 }
Kent Hagerman4f355f52020-03-30 16:01:33 -04001001 OLoop:
Kent Hagerman45a13e42020-04-13 12:23:50 -04001002 for _, dType := range deviceTypes.Items {
Kent Hagerman4f355f52020-03-30 16:01:33 -04001003 for _, v := range dType.VendorIds {
1004 if v == vendorID {
1005 deviceType = dType.Adapter
1006 break OLoop
Chaitrashree G S4b3fada2019-07-28 23:55:25 -07001007 }
1008 }
1009 }
1010 }
1011 //if no match found for the vendorid,report adapter with the custom error message
1012 if deviceType == "" {
Himani Chawlab4c25912020-11-12 17:16:38 +05301013 logger.Errorw(ctx, "failed-to-fetch-adapter-name ", log.Fields{"vendor-id": vendorID})
npujar1d86a522019-11-14 17:11:16 +05301014 return nil, status.Errorf(codes.NotFound, "%s", vendorID)
Chaitrashree G S4b3fada2019-07-28 23:55:25 -07001015 }
khenaidoob9203542018-09-17 22:56:37 -04001016
1017 // Create the ONU device
1018 childDevice := &voltha.Device{}
khenaidoob9203542018-09-17 22:56:37 -04001019 childDevice.Type = deviceType
npujar1d86a522019-11-14 17:11:16 +05301020 childDevice.ParentId = parentDeviceID
khenaidoob9203542018-09-17 22:56:37 -04001021 childDevice.ParentPortNo = uint32(parentPortNo)
npujar1d86a522019-11-14 17:11:16 +05301022 childDevice.VendorId = vendorID
Matt Jeanneret4e241952019-02-28 11:16:04 -05001023 childDevice.SerialNumber = serialNumber
khenaidoob9203542018-09-17 22:56:37 -04001024 childDevice.Root = false
khenaidoo6fdf0ba2018-11-02 14:38:33 -04001025
khenaidoo442e7c72020-03-10 16:13:48 -04001026 // Get parent device type
1027 pAgent := dMgr.getDeviceAgent(ctx, parentDeviceID)
1028 if pAgent == nil {
npujar1d86a522019-11-14 17:11:16 +05301029 return nil, status.Errorf(codes.NotFound, "%s", parentDeviceID)
khenaidoo6fdf0ba2018-11-02 14:38:33 -04001030 }
khenaidoo442e7c72020-03-10 16:13:48 -04001031 if pAgent.deviceType == "" {
1032 return nil, status.Errorf(codes.FailedPrecondition, "device Type not set %s", parentDeviceID)
1033 }
khenaidoo6fdf0ba2018-11-02 14:38:33 -04001034
npujar467fe752020-01-16 20:17:45 +05301035 if device, err := dMgr.GetChildDevice(ctx, parentDeviceID, serialNumber, onuID, parentPortNo); err == nil {
Himani Chawlab4c25912020-11-12 17:16:38 +05301036 logger.Warnw(ctx, "child-device-exists", log.Fields{"parent-device-id": parentDeviceID, "serial-number": serialNumber})
Mahir Gunyel6deaa242019-06-27 04:53:33 -07001037 return device, status.Errorf(codes.AlreadyExists, "%s", serialNumber)
Matt Jeanneret4e241952019-02-28 11:16:04 -05001038 }
1039
khenaidoo442e7c72020-03-10 16:13:48 -04001040 childDevice.ProxyAddress = &voltha.Device_ProxyAddress{DeviceId: parentDeviceID, DeviceType: pAgent.deviceType, ChannelId: uint32(channelID), OnuId: uint32(onuID)}
khenaidoob9203542018-09-17 22:56:37 -04001041
1042 // Create and start a device agent for that device
Mahir Gunyel03de0d32020-06-03 01:36:59 -07001043 agent := newAgent(dMgr.adapterProxy, childDevice, dMgr, dMgr.dbPath, dMgr.dProxy, dMgr.defaultTimeout)
Mahir Gunyel23bd8c72020-09-21 23:20:43 -07001044 insertedChildDevice, err := agent.start(ctx, childDevice)
Scott Baker80678602019-11-14 16:57:36 -08001045 if err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001046 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 -08001047 return nil, err
1048 }
khenaidoo442e7c72020-03-10 16:13:48 -04001049 dMgr.addDeviceAgentToMap(agent)
khenaidoob9203542018-09-17 22:56:37 -04001050
1051 // Activate the child device
npujar467fe752020-01-16 20:17:45 +05301052 if agent = dMgr.getDeviceAgent(ctx, agent.deviceID); agent != nil {
npujar1d86a522019-11-14 17:11:16 +05301053 go func() {
Maninder9a1bc0d2020-10-26 11:34:02 +05301054 subCtx := utils.WithFromTopicMetadataFromContext(utils.WithSpanAndRPCMetadataFromContext(ctx), ctx)
Himani Chawlab4c25912020-11-12 17:16:38 +05301055 err := agent.enableDevice(subCtx)
npujar1d86a522019-11-14 17:11:16 +05301056 if err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001057 logger.Errorw(ctx, "unable-to-enable-device", log.Fields{"error": err})
npujar1d86a522019-11-14 17:11:16 +05301058 }
1059 }()
khenaidoob9203542018-09-17 22:56:37 -04001060 }
1061
Mahir Gunyel23bd8c72020-09-21 23:20:43 -07001062 return insertedChildDevice, nil
khenaidoob9203542018-09-17 22:56:37 -04001063}
1064
Kent Hagerman2b216042020-04-03 18:28:56 -04001065func (dMgr *Manager) packetOut(ctx context.Context, deviceID string, outPort uint32, packet *ofp.OfpPacketOut) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301066 logger.Debugw(ctx, "packet-out", log.Fields{"device-id": deviceID, "out-port": outPort})
npujar467fe752020-01-16 20:17:45 +05301067 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
1068 return agent.packetOut(ctx, outPort, packet)
khenaidoofdbad6e2018-11-06 22:26:38 -05001069 }
npujar1d86a522019-11-14 17:11:16 +05301070 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoofdbad6e2018-11-06 22:26:38 -05001071}
1072
npujar1d86a522019-11-14 17:11:16 +05301073// PacketIn receives packet from adapter
Kent Hagerman2b216042020-04-03 18:28:56 -04001074func (dMgr *Manager) PacketIn(ctx context.Context, deviceID string, port uint32, transactionID string, packet []byte) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301075 logger.Debugw(ctx, "packet-in", log.Fields{"device-id": deviceID, "port": port})
khenaidoofdbad6e2018-11-06 22:26:38 -05001076 // Get the logical device Id based on the deviceId
1077 var device *voltha.Device
1078 var err error
Kent Hagermancba2f302020-07-28 13:37:36 -04001079 if device, err = dMgr.getDeviceReadOnly(ctx, deviceID); err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +00001080 logger.Errorw(ctx, "device-not-found", log.Fields{"device-id": deviceID})
khenaidoofdbad6e2018-11-06 22:26:38 -05001081 return err
1082 }
khenaidoo43c82122018-11-22 18:38:28 -05001083 if !device.Root {
divyadesaicb8b59d2020-08-18 09:55:47 +00001084 logger.Errorw(ctx, "device-not-root", log.Fields{"device-id": deviceID})
npujar1d86a522019-11-14 17:11:16 +05301085 return status.Errorf(codes.FailedPrecondition, "%s", deviceID)
khenaidoofdbad6e2018-11-06 22:26:38 -05001086 }
1087
npujar467fe752020-01-16 20:17:45 +05301088 if err := dMgr.logicalDeviceMgr.packetIn(ctx, device.ParentId, port, transactionID, packet); err != nil {
khenaidoofdbad6e2018-11-06 22:26:38 -05001089 return err
1090 }
1091 return nil
1092}
1093
Kent Hagerman2b216042020-04-03 18:28:56 -04001094func (dMgr *Manager) setParentID(ctx context.Context, device *voltha.Device, parentID string) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301095 logger.Debugw(ctx, "set-parent-id", log.Fields{"device-id": device.Id, "parent-id": parentID})
npujar467fe752020-01-16 20:17:45 +05301096 if agent := dMgr.getDeviceAgent(ctx, device.Id); agent != nil {
1097 return agent.setParentID(ctx, device, parentID)
khenaidooad06fd72019-10-28 12:26:05 -04001098 }
1099 return status.Errorf(codes.NotFound, "%s", device.Id)
1100}
1101
Himani Chawlab4c25912020-11-12 17:16:38 +05301102//
1103//CreateLogicalDevice creates logical device in core
Kent Hagerman2b216042020-04-03 18:28:56 -04001104func (dMgr *Manager) CreateLogicalDevice(ctx context.Context, cDevice *voltha.Device) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301105 logger.Info(ctx, "create-logical-device")
khenaidoo59ef7be2019-06-21 12:40:28 -04001106 // Verify whether the logical device has already been created
1107 if cDevice.ParentId != "" {
Himani Chawlab4c25912020-11-12 17:16:38 +05301108 logger.Debugw(ctx, "parent-device-already-exist", log.Fields{"device-id": cDevice.Id, "logical-device-id": cDevice.Id})
khenaidoo59ef7be2019-06-21 12:40:28 -04001109 return nil
1110 }
khenaidoob9203542018-09-17 22:56:37 -04001111 var err error
npujar467fe752020-01-16 20:17:45 +05301112 if _, err = dMgr.logicalDeviceMgr.createLogicalDevice(ctx, cDevice); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +05301113 logger.Warnw(ctx, "create-logical-device-error", log.Fields{"device": cDevice})
khenaidoob9203542018-09-17 22:56:37 -04001114 return err
1115 }
khenaidoob9203542018-09-17 22:56:37 -04001116 return nil
1117}
1118
npujar1d86a522019-11-14 17:11:16 +05301119// DeleteLogicalDevice deletes logical device from core
Kent Hagerman2b216042020-04-03 18:28:56 -04001120func (dMgr *Manager) DeleteLogicalDevice(ctx context.Context, cDevice *voltha.Device) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301121 logger.Info(ctx, "delete-logical-device")
khenaidoo92e62c52018-10-03 14:02:54 -04001122 var err error
npujar467fe752020-01-16 20:17:45 +05301123 if err = dMgr.logicalDeviceMgr.deleteLogicalDevice(ctx, cDevice); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +05301124 logger.Warnw(ctx, "delete-logical-device-error", log.Fields{"device-id": cDevice.Id})
khenaidoo92e62c52018-10-03 14:02:54 -04001125 return err
1126 }
1127 // Remove the logical device Id from the parent device
npujar1d86a522019-11-14 17:11:16 +05301128 logicalID := ""
npujar467fe752020-01-16 20:17:45 +05301129 dMgr.UpdateDeviceAttribute(ctx, cDevice.Id, "ParentId", logicalID)
khenaidoo92e62c52018-10-03 14:02:54 -04001130 return nil
1131}
1132
npujar1d86a522019-11-14 17:11:16 +05301133// DeleteLogicalPorts removes the logical ports associated with that deviceId
Kent Hagerman2b216042020-04-03 18:28:56 -04001134func (dMgr *Manager) DeleteLogicalPorts(ctx context.Context, cDevice *voltha.Device) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001135 logger.Debugw(ctx, "delete-all-logical-ports", log.Fields{"device-id": cDevice.Id})
khenaidoo442e7c72020-03-10 16:13:48 -04001136 if err := dMgr.logicalDeviceMgr.deleteLogicalPorts(ctx, cDevice.Id); err != nil {
khenaidooe132f522020-03-20 15:23:15 -04001137 // 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 +05301138 logger.Warnw(ctx, "delete-logical-ports-error", log.Fields{"device-id": cDevice.Id, "error": err})
khenaidoo0a822f92019-05-08 15:15:57 -04001139 }
1140 return nil
1141}
1142
Kent Hagerman2b216042020-04-03 18:28:56 -04001143func (dMgr *Manager) getParentDevice(ctx context.Context, childDevice *voltha.Device) *voltha.Device {
khenaidoo92e62c52018-10-03 14:02:54 -04001144 // Sanity check
1145 if childDevice.Root {
1146 // childDevice is the parent device
1147 return childDevice
1148 }
Kent Hagermancba2f302020-07-28 13:37:36 -04001149 parentDevice, _ := dMgr.getDeviceReadOnly(ctx, childDevice.ParentId)
khenaidoo92e62c52018-10-03 14:02:54 -04001150 return parentDevice
1151}
1152
Kent Hagerman2b216042020-04-03 18:28:56 -04001153//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 -04001154//cannot manage the child devices. This will trigger the Core to disable all the child devices.
Kent Hagerman2b216042020-04-03 18:28:56 -04001155func (dMgr *Manager) ChildDevicesLost(ctx context.Context, parentDeviceID string) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301156 logger.Debug(ctx, "child-devices-lost")
Kent Hagermancba2f302020-07-28 13:37:36 -04001157 parentDevice, err := dMgr.getDeviceReadOnly(ctx, parentDeviceID)
Kent Hagerman2a07b862020-06-19 15:23:07 -04001158 if err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +00001159 logger.Warnw(ctx, "failed-getting-device", log.Fields{"parent-device-id": parentDeviceID, "error": err})
khenaidoo0a822f92019-05-08 15:15:57 -04001160 return err
1161 }
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001162 return dMgr.DisableAllChildDevices(ctx, parentDevice)
khenaidoo0a822f92019-05-08 15:15:57 -04001163}
1164
Kent Hagerman2b216042020-04-03 18:28:56 -04001165//ChildDevicesDetected is invoked by an adapter when child devices are found, typically after after a
khenaidoo0a822f92019-05-08 15:15:57 -04001166// disable/enable sequence. This will trigger the Core to Enable all the child devices of that parent.
Kent Hagerman2b216042020-04-03 18:28:56 -04001167func (dMgr *Manager) ChildDevicesDetected(ctx context.Context, parentDeviceID string) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301168 logger.Debug(ctx, "child-devices-detected")
Kent Hagerman2a07b862020-06-19 15:23:07 -04001169 parentDevicePorts, err := dMgr.listDevicePorts(ctx, parentDeviceID)
1170 if err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +00001171 logger.Warnw(ctx, "failed-getting-device", log.Fields{"device-id": parentDeviceID, "error": err})
khenaidoo0a822f92019-05-08 15:15:57 -04001172 return err
1173 }
Kent Hagerman2a07b862020-06-19 15:23:07 -04001174 childDeviceIds := dMgr.getAllChildDeviceIds(ctx, parentDevicePorts)
khenaidoo0a822f92019-05-08 15:15:57 -04001175 if len(childDeviceIds) == 0 {
divyadesaicb8b59d2020-08-18 09:55:47 +00001176 logger.Debugw(ctx, "no-child-device", log.Fields{"parent-device-id": parentDeviceID})
khenaidoo0a822f92019-05-08 15:15:57 -04001177 }
khenaidoo59ef7be2019-06-21 12:40:28 -04001178 allChildEnableRequestSent := true
Kent Hagerman2a07b862020-06-19 15:23:07 -04001179 for childDeviceID := range childDeviceIds {
npujar467fe752020-01-16 20:17:45 +05301180 if agent := dMgr.getDeviceAgent(ctx, childDeviceID); agent != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +05301181 subCtx := utils.WithSpanAndRPCMetadataFromContext(ctx)
khenaidoo59ef7be2019-06-21 12:40:28 -04001182 // Run the children re-registration in its own routine
Kent Hagerman2a07b862020-06-19 15:23:07 -04001183 go func(ctx context.Context) {
1184 err = agent.enableDevice(ctx)
npujar1d86a522019-11-14 17:11:16 +05301185 if err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001186 logger.Errorw(ctx, "unable-to-enable-device", log.Fields{"error": err})
npujar1d86a522019-11-14 17:11:16 +05301187 }
Himani Chawlab4c25912020-11-12 17:16:38 +05301188 }(subCtx)
khenaidoo59ef7be2019-06-21 12:40:28 -04001189 } else {
npujar1d86a522019-11-14 17:11:16 +05301190 err = status.Errorf(codes.Unavailable, "no agent for child device %s", childDeviceID)
Himani Chawlab4c25912020-11-12 17:16:38 +05301191 logger.Errorw(ctx, "no-child-device-agent", log.Fields{"parent-device-id": parentDeviceID, "child-id": childDeviceID})
khenaidoo59ef7be2019-06-21 12:40:28 -04001192 allChildEnableRequestSent = false
khenaidoo0a822f92019-05-08 15:15:57 -04001193 }
1194 }
khenaidoo59ef7be2019-06-21 12:40:28 -04001195 if !allChildEnableRequestSent {
khenaidoo0a822f92019-05-08 15:15:57 -04001196 return err
1197 }
1198 return nil
1199}
1200
khenaidoo4d4802d2018-10-04 21:59:49 -04001201/*
1202All the functions below are callback functions where they are invoked with the latest and previous data. We can
1203therefore use the data as is without trying to get the latest from the model.
1204*/
1205
khenaidoo0a822f92019-05-08 15:15:57 -04001206//DisableAllChildDevices is invoked as a callback when the parent device is disabled
Kent Hagerman2b216042020-04-03 18:28:56 -04001207func (dMgr *Manager) DisableAllChildDevices(ctx context.Context, parentCurrDevice *voltha.Device) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301208 logger.Debug(ctx, "disable-all-child-devices")
Kent Hagerman2a07b862020-06-19 15:23:07 -04001209 ports, _ := dMgr.listDevicePorts(ctx, parentCurrDevice.Id)
1210 for childDeviceID := range dMgr.getAllChildDeviceIds(ctx, ports) {
npujar467fe752020-01-16 20:17:45 +05301211 if agent := dMgr.getDeviceAgent(ctx, childDeviceID); agent != nil {
Kent Hagerman2a07b862020-06-19 15:23:07 -04001212 if err := agent.disableDevice(ctx); err != nil {
khenaidooe132f522020-03-20 15:23:15 -04001213 // Just log the error - this error happens only if the child device was already in deleted state.
divyadesaicb8b59d2020-08-18 09:55:47 +00001214 logger.Errorw(ctx, "failure-disable-device", log.Fields{"device-id": childDeviceID, "error": err.Error()})
khenaidoo92e62c52018-10-03 14:02:54 -04001215 }
1216 }
1217 }
1218 return nil
1219}
1220
khenaidoo0a822f92019-05-08 15:15:57 -04001221//DeleteAllChildDevices is invoked as a callback when the parent device is deleted
Kent Hagerman2b216042020-04-03 18:28:56 -04001222func (dMgr *Manager) DeleteAllChildDevices(ctx context.Context, parentCurrDevice *voltha.Device) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301223 logger.Debug(ctx, "delete-all-child-devices")
Himani Chawla2ba1c9c2020-10-07 13:19:03 +05301224 force := false
1225 // Get the parent device Transient state, if its FORCE_DELETED(go for force delete for child devices)
1226 // So in cases when this handler is getting called other than DELETE operation, no force option would be used.
1227 agent := dMgr.getDeviceAgent(ctx, parentCurrDevice.Id)
1228 if agent == nil {
1229 return status.Errorf(codes.NotFound, "%s", parentCurrDevice.Id)
1230 }
1231
1232 force = agent.getTransientState() == voltha.DeviceTransientState_FORCE_DELETING
1233
Kent Hagerman2a07b862020-06-19 15:23:07 -04001234 ports, _ := dMgr.listDevicePorts(ctx, parentCurrDevice.Id)
1235 for childDeviceID := range dMgr.getAllChildDeviceIds(ctx, ports) {
npujar467fe752020-01-16 20:17:45 +05301236 if agent := dMgr.getDeviceAgent(ctx, childDeviceID); agent != nil {
Himani Chawla2ba1c9c2020-10-07 13:19:03 +05301237 if force {
1238 if err := agent.deleteDeviceForce(ctx); err != nil {
1239 logger.Warnw(ctx, "failure-delete-device-force", log.Fields{"device-id": childDeviceID,
1240 "error": err.Error()})
1241 }
1242 } else {
1243 if err := agent.deleteDevice(ctx); err != nil {
1244 logger.Warnw(ctx, "failure-delete-device", log.Fields{"device-id": childDeviceID,
1245 "error": err.Error()})
1246 }
khenaidoo4d4802d2018-10-04 21:59:49 -04001247 }
khenaidoo49085352020-01-13 19:15:43 -05001248 // No further action is required here. The deleteDevice will change the device state where the resulting
1249 // callback will take care of cleaning the child device agent.
khenaidoo4d4802d2018-10-04 21:59:49 -04001250 }
1251 }
khenaidoo4d4802d2018-10-04 21:59:49 -04001252 return nil
1253}
1254
Girish Gowdra408cd962020-03-11 14:31:31 -07001255//DeleteAllLogicalPorts is invoked as a callback when the parent device's connection status moves to UNREACHABLE
Kent Hagerman2b216042020-04-03 18:28:56 -04001256func (dMgr *Manager) DeleteAllLogicalPorts(ctx context.Context, parentDevice *voltha.Device) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001257 logger.Debugw(ctx, "delete-all-logical-ports", log.Fields{"parent-device-id": parentDevice.Id})
Girish Gowdra408cd962020-03-11 14:31:31 -07001258 if err := dMgr.logicalDeviceMgr.deleteAllLogicalPorts(ctx, parentDevice); err != nil {
khenaidooe132f522020-03-20 15:23:15 -04001259 // Just log error as logical device may already have been deleted
Rohan Agrawal31f21802020-06-12 05:38:46 +00001260 logger.Warnw(ctx, "delete-all-logical-ports-fail", log.Fields{"parent-device-id": parentDevice.Id, "error": err})
Girish Gowdra408cd962020-03-11 14:31:31 -07001261 }
1262 return nil
1263}
1264
1265//DeleteAllDeviceFlows is invoked as a callback when the parent device's connection status moves to UNREACHABLE
Kent Hagerman2b216042020-04-03 18:28:56 -04001266func (dMgr *Manager) DeleteAllDeviceFlows(ctx context.Context, parentDevice *voltha.Device) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001267 logger.Debugw(ctx, "delete-all-device-flows", log.Fields{"parent-device-id": parentDevice.Id})
Girish Gowdra408cd962020-03-11 14:31:31 -07001268 if agent := dMgr.getDeviceAgent(ctx, parentDevice.Id); agent != nil {
1269 if err := agent.deleteAllFlows(ctx); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001270 logger.Errorw(ctx, "error-deleting-all-device-flows", log.Fields{"parent-device-id": parentDevice.Id})
Girish Gowdra408cd962020-03-11 14:31:31 -07001271 return err
1272 }
1273 return nil
1274 }
1275 return status.Errorf(codes.NotFound, "%s", parentDevice.Id)
1276}
1277
khenaidoo4d4802d2018-10-04 21:59:49 -04001278//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 -04001279func (dMgr *Manager) getAllChildDeviceIds(ctx context.Context, parentDevicePorts map[uint32]*voltha.Port) map[string]struct{} {
Himani Chawlab4c25912020-11-12 17:16:38 +05301280 logger.Debug(ctx, "get-all-child-device-ids")
Kent Hagerman2a07b862020-06-19 15:23:07 -04001281 childDeviceIds := make(map[string]struct{}, len(parentDevicePorts))
1282 for _, port := range parentDevicePorts {
1283 for _, peer := range port.Peers {
1284 childDeviceIds[peer.DeviceId] = struct{}{}
khenaidoo92e62c52018-10-03 14:02:54 -04001285 }
1286 }
Kent Hagerman2a07b862020-06-19 15:23:07 -04001287 logger.Debugw(ctx, "returning-getAllChildDeviceIds", log.Fields{"childDeviceIds": childDeviceIds})
1288 return childDeviceIds
khenaidoo92e62c52018-10-03 14:02:54 -04001289}
1290
Kent Hagerman2b216042020-04-03 18:28:56 -04001291//GetAllChildDevices is a helper method to get all the child device IDs from the device passed as parameter
1292func (dMgr *Manager) GetAllChildDevices(ctx context.Context, parentDeviceID string) (*voltha.Devices, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301293 logger.Debugw(ctx, "get-all-child-devices", log.Fields{"parent-device-id": parentDeviceID})
Kent Hagerman2a07b862020-06-19 15:23:07 -04001294 if parentDevicePorts, err := dMgr.listDevicePorts(ctx, parentDeviceID); err == nil {
khenaidoo297cd252019-02-07 22:10:23 -05001295 childDevices := make([]*voltha.Device, 0)
Kent Hagerman2a07b862020-06-19 15:23:07 -04001296 for deviceID := range dMgr.getAllChildDeviceIds(ctx, parentDevicePorts) {
Kent Hagermancba2f302020-07-28 13:37:36 -04001297 if d, e := dMgr.getDeviceReadOnly(ctx, deviceID); e == nil && d != nil {
Kent Hagerman2a07b862020-06-19 15:23:07 -04001298 childDevices = append(childDevices, d)
khenaidoo297cd252019-02-07 22:10:23 -05001299 }
1300 }
1301 return &voltha.Devices{Items: childDevices}, nil
1302 }
npujar1d86a522019-11-14 17:11:16 +05301303 return nil, status.Errorf(codes.NotFound, "%s", parentDeviceID)
khenaidoo297cd252019-02-07 22:10:23 -05001304}
1305
npujar1d86a522019-11-14 17:11:16 +05301306// SetupUNILogicalPorts creates UNI ports on the logical device that represents a child UNI interface
Kent Hagerman2b216042020-04-03 18:28:56 -04001307func (dMgr *Manager) SetupUNILogicalPorts(ctx context.Context, cDevice *voltha.Device) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301308 logger.Info(ctx, "setup-uni-logical-ports")
Kent Hagerman2a07b862020-06-19 15:23:07 -04001309 cDevicePorts, err := dMgr.listDevicePorts(ctx, cDevice.Id)
1310 if err != nil {
1311 return err
1312 }
1313 if err := dMgr.logicalDeviceMgr.setupUNILogicalPorts(ctx, cDevice, cDevicePorts); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +05301314 logger.Warnw(ctx, "setup-uni-logical-ports-error", log.Fields{"device": cDevice, "err": err})
khenaidoob9203542018-09-17 22:56:37 -04001315 return err
1316 }
1317 return nil
1318}
1319
Kent Hagerman45a13e42020-04-13 12:23:50 -04001320// convenience to avoid redefining
1321var operationFailureResp = &common.OperationResp{Code: voltha.OperationResp_OPERATION_FAILURE}
1322
1323// DownloadImage execute an image download request
1324func (dMgr *Manager) DownloadImage(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301325 ctx = utils.WithRPCMetadataContext(ctx, "DownloadImage")
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001326 log.EnrichSpan(ctx, log.Fields{"device-id": img.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +05301327 logger.Debugw(ctx, "download-image", log.Fields{"device-id": img.Id, "image-name": img.Name})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001328 agent := dMgr.getDeviceAgent(ctx, img.Id)
1329 if agent == nil {
1330 return operationFailureResp, status.Errorf(codes.NotFound, "%s", img.Id)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001331 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001332 resp, err := agent.downloadImage(ctx, img)
1333 if err != nil {
1334 return operationFailureResp, err
1335 }
1336 return resp, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001337}
1338
Kent Hagerman45a13e42020-04-13 12:23:50 -04001339// CancelImageDownload cancels image download request
1340func (dMgr *Manager) CancelImageDownload(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301341 ctx = utils.WithRPCMetadataContext(ctx, "CancelImageDownload")
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001342 log.EnrichSpan(ctx, log.Fields{"device-id": img.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +05301343 logger.Debugw(ctx, "cancel-image-download", log.Fields{"device-id": img.Id, "image-name": img.Name})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001344 agent := dMgr.getDeviceAgent(ctx, img.Id)
1345 if agent == nil {
1346 return operationFailureResp, status.Errorf(codes.NotFound, "%s", img.Id)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001347 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001348 resp, err := agent.cancelImageDownload(ctx, img)
1349 if err != nil {
1350 return operationFailureResp, err
1351 }
1352 return resp, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001353}
1354
Kent Hagerman45a13e42020-04-13 12:23:50 -04001355// ActivateImageUpdate activates image update request
1356func (dMgr *Manager) ActivateImageUpdate(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301357 ctx = utils.WithRPCMetadataContext(ctx, "ActivateImageUpdate")
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001358 log.EnrichSpan(ctx, log.Fields{"device-id": img.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +05301359 logger.Debugw(ctx, "activate-image-update", log.Fields{"device-id": img.Id, "image-name": img.Name})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001360 agent := dMgr.getDeviceAgent(ctx, img.Id)
1361 if agent == nil {
1362 return operationFailureResp, status.Errorf(codes.NotFound, "%s", img.Id)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001363 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001364 resp, err := agent.activateImage(ctx, img)
1365 if err != nil {
1366 return operationFailureResp, err
1367 }
1368 return resp, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001369}
1370
Kent Hagerman45a13e42020-04-13 12:23:50 -04001371// RevertImageUpdate reverts image update
1372func (dMgr *Manager) RevertImageUpdate(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301373 ctx = utils.WithRPCMetadataContext(ctx, "RevertImageUpdate")
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001374 log.EnrichSpan(ctx, log.Fields{"device-id": img.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +05301375 logger.Debugw(ctx, "rever-image-update", log.Fields{"device-id": img.Id, "image-name": img.Name})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001376 agent := dMgr.getDeviceAgent(ctx, img.Id)
1377 if agent == nil {
1378 return operationFailureResp, status.Errorf(codes.NotFound, "%s", img.Id)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001379 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001380 resp, err := agent.revertImage(ctx, img)
1381 if err != nil {
1382 return operationFailureResp, err
1383 }
1384 return resp, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001385}
1386
Kent Hagerman45a13e42020-04-13 12:23:50 -04001387// convenience to avoid redefining
1388var imageDownloadFailureResp = &voltha.ImageDownload{DownloadState: voltha.ImageDownload_DOWNLOAD_UNKNOWN}
1389
1390// GetImageDownloadStatus returns status of image download
1391func (dMgr *Manager) GetImageDownloadStatus(ctx context.Context, img *voltha.ImageDownload) (*voltha.ImageDownload, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301392 ctx = utils.WithRPCMetadataContext(ctx, "GetImageDownloadStatus")
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001393 log.EnrichSpan(ctx, log.Fields{"device-id": img.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +05301394 logger.Debugw(ctx, "get-image-download-status", log.Fields{"device-id": img.Id, "image-name": img.Name})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001395 agent := dMgr.getDeviceAgent(ctx, img.Id)
1396 if agent == nil {
1397 return imageDownloadFailureResp, status.Errorf(codes.NotFound, "%s", img.Id)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001398 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001399 resp, err := agent.getImageDownloadStatus(ctx, img)
1400 if err != nil {
1401 return imageDownloadFailureResp, err
1402 }
1403 return resp, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001404}
1405
Kent Hagerman2b216042020-04-03 18:28:56 -04001406func (dMgr *Manager) UpdateImageDownload(ctx context.Context, deviceID string, img *voltha.ImageDownload) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301407 ctx = utils.WithRPCMetadataContext(ctx, "UpdateImageDownload")
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001408 log.EnrichSpan(ctx, log.Fields{"device-id": img.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +05301409 logger.Debugw(ctx, "update-image-download", log.Fields{"device-id": img.Id, "image-name": img.Name})
npujar467fe752020-01-16 20:17:45 +05301410 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
1411 if err := agent.updateImageDownload(ctx, img); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +05301412 logger.Debugw(ctx, "update-image-download-failed", log.Fields{"err": err, "image-name": img.Name})
khenaidoof5a5bfa2019-01-23 22:20:29 -05001413 return err
1414 }
1415 } else {
1416 return status.Errorf(codes.NotFound, "%s", img.Id)
1417 }
1418 return nil
1419}
1420
Kent Hagerman45a13e42020-04-13 12:23:50 -04001421// GetImageDownload returns image download
Kent Hagerman2b216042020-04-03 18:28:56 -04001422func (dMgr *Manager) GetImageDownload(ctx context.Context, img *voltha.ImageDownload) (*voltha.ImageDownload, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301423 ctx = utils.WithRPCMetadataContext(ctx, "GetImageDownload")
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001424 log.EnrichSpan(ctx, log.Fields{"device-id": img.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +05301425 logger.Debugw(ctx, "get-image-download", log.Fields{"device-id": img.Id, "image-name": img.Name})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001426 agent := dMgr.getDeviceAgent(ctx, img.Id)
1427 if agent == nil {
1428 return imageDownloadFailureResp, status.Errorf(codes.NotFound, "%s", img.Id)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001429 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001430 resp, err := agent.getImageDownload(ctx, img)
1431 if err != nil {
1432 return imageDownloadFailureResp, err
1433 }
1434 return resp, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001435}
1436
Kent Hagerman45a13e42020-04-13 12:23:50 -04001437// ListImageDownloads returns image downloads
1438func (dMgr *Manager) ListImageDownloads(ctx context.Context, id *voltha.ID) (*voltha.ImageDownloads, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301439 ctx = utils.WithRPCMetadataContext(ctx, "ListImageDownloads")
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001440 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +05301441 logger.Debugw(ctx, "list-image-downloads", log.Fields{"device-id": id.Id})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001442 agent := dMgr.getDeviceAgent(ctx, id.Id)
1443 if agent == nil {
1444 return &voltha.ImageDownloads{Items: []*voltha.ImageDownload{imageDownloadFailureResp}}, status.Errorf(codes.NotFound, "%s", id.Id)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001445 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001446 resp, err := agent.listImageDownloads(ctx, id.Id)
1447 if err != nil {
1448 return &voltha.ImageDownloads{Items: []*voltha.ImageDownload{imageDownloadFailureResp}}, err
1449 }
1450 return resp, nil
1451}
1452
1453// GetImages returns all images for a specific device entry
1454func (dMgr *Manager) GetImages(ctx context.Context, id *voltha.ID) (*voltha.Images, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301455 ctx = utils.WithRPCMetadataContext(ctx, "GetImages")
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001456 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +05301457 logger.Debugw(ctx, "get-images", log.Fields{"device-id": id.Id})
Kent Hagermancba2f302020-07-28 13:37:36 -04001458 device, err := dMgr.getDeviceReadOnly(ctx, id.Id)
Kent Hagerman45a13e42020-04-13 12:23:50 -04001459 if err != nil {
1460 return nil, err
1461 }
Kent Hagermancba2f302020-07-28 13:37:36 -04001462 return device.Images, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001463}
1464
Rohan Agrawal31f21802020-06-12 05:38:46 +00001465func (dMgr *Manager) NotifyInvalidTransition(ctx context.Context, device *voltha.Device) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301466 logger.Errorw(ctx, "notify-invalid-transition", log.Fields{
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001467 "device": device.Id,
1468 "curr-admin-state": device.AdminState,
1469 "curr-oper-state": device.OperStatus,
1470 "curr-conn-state": device.ConnectStatus,
Stephane Barbarieef6650d2019-07-18 12:15:09 -04001471 })
khenaidoo0a822f92019-05-08 15:15:57 -04001472 //TODO: notify over kafka?
1473 return nil
1474}
1475
npujar1d86a522019-11-14 17:11:16 +05301476// UpdateDeviceAttribute updates value of particular device attribute
Kent Hagerman2b216042020-04-03 18:28:56 -04001477func (dMgr *Manager) UpdateDeviceAttribute(ctx context.Context, deviceID string, attribute string, value interface{}) {
npujar1d86a522019-11-14 17:11:16 +05301478 if agent, ok := dMgr.deviceAgents.Load(deviceID); ok {
Kent Hagerman2b216042020-04-03 18:28:56 -04001479 agent.(*Agent).updateDeviceAttribute(ctx, attribute, value)
khenaidoob9203542018-09-17 22:56:37 -04001480 }
1481}
1482
npujar1d86a522019-11-14 17:11:16 +05301483// GetParentDeviceID returns parent device id, either from memory or from the dB, if present
Kent Hagerman2b216042020-04-03 18:28:56 -04001484func (dMgr *Manager) GetParentDeviceID(ctx context.Context, deviceID string) string {
Kent Hagermancba2f302020-07-28 13:37:36 -04001485 if device, _ := dMgr.getDeviceReadOnly(ctx, deviceID); device != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +05301486 logger.Infow(ctx, "get-parent-device-id", log.Fields{"device-id": device.Id, "parent-id": device.ParentId})
khenaidoo4c9e5592019-09-09 16:20:41 -04001487 return device.ParentId
khenaidoob9203542018-09-17 22:56:37 -04001488 }
khenaidoo4c9e5592019-09-09 16:20:41 -04001489 return ""
khenaidoob9203542018-09-17 22:56:37 -04001490}
serkant.uluderya334479d2019-04-10 08:26:15 -07001491
Kent Hagerman45a13e42020-04-13 12:23:50 -04001492func (dMgr *Manager) SimulateAlarm(ctx context.Context, simulateReq *voltha.SimulateAlarmRequest) (*common.OperationResp, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301493 ctx = utils.WithRPCMetadataContext(ctx, "SimulateAlarm")
1494 logger.Debugw(ctx, "simulate-alarm", log.Fields{"id": simulateReq.Id, "indicator": simulateReq.Indicator, "intf-id": simulateReq.IntfId,
1495 "port-type-name": simulateReq.PortTypeName, "onu-device-id": simulateReq.OnuDeviceId, "inverse-bit-error-rate": simulateReq.InverseBitErrorRate,
1496 "drift": simulateReq.Drift, "new-eqd": simulateReq.NewEqd, "onu-serial-number": simulateReq.OnuSerialNumber, "operation": simulateReq.Operation})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001497 agent := dMgr.getDeviceAgent(ctx, simulateReq.Id)
1498 if agent == nil {
1499 return nil, status.Errorf(codes.NotFound, "%s", simulateReq.Id)
serkant.uluderya334479d2019-04-10 08:26:15 -07001500 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001501 if err := agent.simulateAlarm(ctx, simulateReq); err != nil {
1502 return nil, err
1503 }
1504 return &common.OperationResp{Code: common.OperationResp_OPERATION_SUCCESS}, nil
serkant.uluderya334479d2019-04-10 08:26:15 -07001505}
Mahir Gunyelfdee9212019-10-16 16:52:21 -07001506
Kent Hagerman2b216042020-04-03 18:28:56 -04001507func (dMgr *Manager) UpdateDeviceReason(ctx context.Context, deviceID string, reason string) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301508 logger.Debugw(ctx, "update-device-reason", log.Fields{"device-id": deviceID, "reason": reason})
npujar467fe752020-01-16 20:17:45 +05301509 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
1510 return agent.updateDeviceReason(ctx, reason)
Mahir Gunyelfdee9212019-10-16 16:52:21 -07001511 }
npujar1d86a522019-11-14 17:11:16 +05301512 return status.Errorf(codes.NotFound, "%s", deviceID)
Mahir Gunyelfdee9212019-10-16 16:52:21 -07001513}
kesavandbc2d1622020-01-21 00:42:01 -05001514
Kent Hagerman45a13e42020-04-13 12:23:50 -04001515func (dMgr *Manager) EnablePort(ctx context.Context, port *voltha.Port) (*empty.Empty, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301516 ctx = utils.WithRPCMetadataContext(ctx, "EnablePort")
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001517 log.EnrichSpan(ctx, log.Fields{"device-id": port.DeviceId})
Himani Chawlab4c25912020-11-12 17:16:38 +05301518 logger.Debugw(ctx, "enable-port", log.Fields{"device-id": port.DeviceId, "port-no": port.PortNo})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001519 agent := dMgr.getDeviceAgent(ctx, port.DeviceId)
1520 if agent == nil {
1521 return nil, status.Errorf(codes.NotFound, "%s", port.DeviceId)
kesavandbc2d1622020-01-21 00:42:01 -05001522 }
Kent Hagerman2a07b862020-06-19 15:23:07 -04001523 return &empty.Empty{}, agent.enablePort(ctx, port.PortNo)
kesavandbc2d1622020-01-21 00:42:01 -05001524}
1525
Kent Hagerman45a13e42020-04-13 12:23:50 -04001526func (dMgr *Manager) DisablePort(ctx context.Context, port *voltha.Port) (*empty.Empty, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301527 ctx = utils.WithRPCMetadataContext(ctx, "DisablePort")
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001528 log.EnrichSpan(ctx, log.Fields{"device-id": port.DeviceId})
Himani Chawlab4c25912020-11-12 17:16:38 +05301529 logger.Debugw(ctx, "disable-port", log.Fields{"device-id": port.DeviceId, "port-no": port.PortNo})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001530 agent := dMgr.getDeviceAgent(ctx, port.DeviceId)
1531 if agent == nil {
1532 return nil, status.Errorf(codes.NotFound, "%s", port.DeviceId)
kesavandbc2d1622020-01-21 00:42:01 -05001533 }
Kent Hagerman2a07b862020-06-19 15:23:07 -04001534 return &empty.Empty{}, agent.disablePort(ctx, port.PortNo)
kesavandbc2d1622020-01-21 00:42:01 -05001535}
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001536
Kent Hagerman2b216042020-04-03 18:28:56 -04001537// ChildDeviceLost calls parent adapter to delete child device and all its references
1538func (dMgr *Manager) ChildDeviceLost(ctx context.Context, curr *voltha.Device) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301539 logger.Debugw(ctx, "child-device-lost", log.Fields{"child-device-id": curr.Id, "parent-device-id": curr.ParentId})
khenaidoo442e7c72020-03-10 16:13:48 -04001540 if parentAgent := dMgr.getDeviceAgent(ctx, curr.ParentId); parentAgent != nil {
khenaidooe132f522020-03-20 15:23:15 -04001541 if err := parentAgent.ChildDeviceLost(ctx, curr); err != nil {
1542 // Just log the message and let the remaining pipeline proceed.
Rohan Agrawal31f21802020-06-12 05:38:46 +00001543 logger.Warnw(ctx, "childDeviceLost", log.Fields{"child-device-id": curr.Id, "parent-device-id": curr.ParentId, "error": err})
khenaidooe132f522020-03-20 15:23:15 -04001544 }
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001545 }
khenaidooe132f522020-03-20 15:23:15 -04001546 // Do not return an error as parent device may also have been deleted. Let the remaining pipeline proceed.
1547 return nil
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001548}
onkarkundargi87285252020-01-27 11:34:52 +05301549
Kent Hagerman45a13e42020-04-13 12:23:50 -04001550func (dMgr *Manager) StartOmciTestAction(ctx context.Context, request *voltha.OmciTestRequest) (*voltha.TestResponse, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301551 ctx = utils.WithRPCMetadataContext(ctx, "StartOmciTestAction")
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001552 log.EnrichSpan(ctx, log.Fields{"device-id": request.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +05301553 logger.Debugw(ctx, "start-omci-test-action", log.Fields{"device-id": request.Id, "uuid": request.Uuid})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001554 agent := dMgr.getDeviceAgent(ctx, request.Id)
1555 if agent == nil {
1556 return nil, status.Errorf(codes.NotFound, "%s", request.Id)
onkarkundargi87285252020-01-27 11:34:52 +05301557 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001558 return agent.startOmciTest(ctx, request)
onkarkundargi87285252020-01-27 11:34:52 +05301559}
Dinesh Belwalkarc1129f12020-02-27 10:41:33 -08001560
1561func (dMgr *Manager) GetExtValue(ctx context.Context, value *voltha.ValueSpecifier) (*voltha.ReturnValues, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301562 ctx = utils.WithRPCMetadataContext(ctx, "GetExtValue")
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001563 log.EnrichSpan(ctx, log.Fields{"device-id": value.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +05301564 logger.Debugw(ctx, "get-ext-value", log.Fields{"onu-id": value.Id})
Kent Hagermancba2f302020-07-28 13:37:36 -04001565 cDevice, err := dMgr.getDeviceReadOnly(ctx, value.Id)
Dinesh Belwalkarc1129f12020-02-27 10:41:33 -08001566 if err != nil {
1567 return nil, status.Errorf(codes.Aborted, "%s", err.Error())
1568 }
Kent Hagermancba2f302020-07-28 13:37:36 -04001569 pDevice, err := dMgr.getDeviceReadOnly(ctx, cDevice.ParentId)
Dinesh Belwalkarc1129f12020-02-27 10:41:33 -08001570 if err != nil {
1571 return nil, status.Errorf(codes.Aborted, "%s", err.Error())
1572 }
1573 if agent := dMgr.getDeviceAgent(ctx, cDevice.ParentId); agent != nil {
1574 resp, err := agent.getExtValue(ctx, pDevice, cDevice, value)
1575 if err != nil {
1576 return nil, err
1577 }
Himani Chawlab4c25912020-11-12 17:16:38 +05301578 logger.Debugw(ctx, "get-ext-value-result", log.Fields{"result": resp})
Dinesh Belwalkarc1129f12020-02-27 10:41:33 -08001579 return resp, nil
1580 }
1581 return nil, status.Errorf(codes.NotFound, "%s", value.Id)
1582
1583}
dpaul62686312020-06-23 14:17:36 +05301584
1585// SetExtValue set some given configs or value
1586func (dMgr *Manager) SetExtValue(ctx context.Context, value *voltha.ValueSet) (*empty.Empty, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301587 ctx = utils.WithRPCMetadataContext(ctx, "SetExtValue")
1588 logger.Debugw(ctx, "set-ext-value", log.Fields{"onu-id": value.Id})
dpaul62686312020-06-23 14:17:36 +05301589 device, err := dMgr.getDeviceReadOnly(ctx, value.Id)
1590 if err != nil {
1591 return nil, status.Errorf(codes.Aborted, "%s", err.Error())
1592 }
1593 if agent := dMgr.getDeviceAgent(ctx, device.Id); agent != nil {
1594 resp, err := agent.setExtValue(ctx, device, value)
1595 if err != nil {
1596 return nil, err
1597 }
Himani Chawlab4c25912020-11-12 17:16:38 +05301598 logger.Debugw(ctx, "set-ext-value-result", log.Fields{"result": resp})
dpaul62686312020-06-23 14:17:36 +05301599 return resp, nil
1600 }
1601 return nil, status.Errorf(codes.NotFound, "%s", value.Id)
1602
1603}
Himani Chawlab4c25912020-11-12 17:16:38 +05301604
1605func (dMgr *Manager) SendRPCEvent(ctx context.Context, id string, rpcEvent *voltha.RPCEvent,
1606 category voltha.EventCategory_Types, subCategory *voltha.EventSubCategory_Types, raisedTs int64) {
1607 //TODO Instead of directly sending to the kafka bus, queue the message and send it asynchronously
Mahir Gunyelb0343bf2021-05-11 14:14:26 -07001608 dMgr.Agent.SendRPCEvent(ctx, id, rpcEvent, category, subCategory, raisedTs)
Himani Chawlab4c25912020-11-12 17:16:38 +05301609}
Manindera496f852021-02-22 09:57:56 +05301610
1611func (dMgr *Manager) GetTransientState(ctx context.Context, id string) (voltha.DeviceTransientState_Types, error) {
1612 agent := dMgr.getDeviceAgent(ctx, id)
1613 if agent == nil {
1614 return voltha.DeviceTransientState_NONE, status.Errorf(codes.NotFound, "%s", id)
1615 }
1616 return agent.getTransientState(), nil
1617}
ssiddiquif076cb82021-04-23 10:47:04 +05301618
1619func (dMgr *Manager) DownloadImageToDevice(ctx context.Context, request *voltha.DeviceImageDownloadRequest) (*voltha.DeviceImageResponse, error) {
1620 if err := dMgr.validateImageDownloadRequest(request); err != nil {
1621 return nil, err
1622 }
1623
1624 ctx = utils.WithRPCMetadataContext(ctx, "DownloadImageToDevice")
1625 respCh := make(chan []*voltha.DeviceImageState, len(request.GetDeviceId()))
1626
ssiddiquif076cb82021-04-23 10:47:04 +05301627 for index, deviceID := range request.DeviceId {
ssiddiqui6bd4de02021-06-08 12:04:17 +05301628 // Create download request per device
1629 downloadReq := &voltha.DeviceImageDownloadRequest{
1630 Image: request.Image,
1631 ActivateOnSuccess: request.ActivateOnSuccess,
1632 CommitOnSuccess: request.CommitOnSuccess,
1633 }
1634
ssiddiquif076cb82021-04-23 10:47:04 +05301635 //slice-out only single deviceID from the request
1636 downloadReq.DeviceId = request.DeviceId[index : index+1]
1637
1638 go func(deviceID string, req *voltha.DeviceImageDownloadRequest, ch chan []*voltha.DeviceImageState) {
1639 agent := dMgr.getDeviceAgent(ctx, deviceID)
1640 if agent == nil {
1641 logger.Errorw(ctx, "Not-found", log.Fields{"device-id": deviceID})
1642 ch <- nil
1643 return
1644 }
1645
1646 resp, err := agent.downloadImageToDevice(ctx, req)
1647 if err != nil {
1648 logger.Errorw(ctx, "download-image-to-device-failed", log.Fields{"device-id": deviceID, "error": err})
1649 ch <- nil
1650 return
1651 }
1652
1653 err = dMgr.validateDeviceImageResponse(resp)
1654 if err != nil {
1655 logger.Errorw(ctx, "download-image-to-device-failed", log.Fields{"device-id": deviceID, "error": err})
1656 ch <- nil
1657 return
1658 }
1659 ch <- resp.GetDeviceImageStates()
1660 }(deviceID.GetId(), downloadReq, respCh)
1661
1662 }
1663
1664 return dMgr.waitForAllResponses(ctx, "download-image-to-device", respCh, len(request.GetDeviceId()))
1665}
1666
1667func (dMgr *Manager) GetImageStatus(ctx context.Context, request *voltha.DeviceImageRequest) (*voltha.DeviceImageResponse, error) {
1668 if err := dMgr.validateImageRequest(request); err != nil {
1669 return nil, err
1670 }
1671
1672 ctx = utils.WithRPCMetadataContext(ctx, "GetImageStatus")
1673
ssiddiquif076cb82021-04-23 10:47:04 +05301674 respCh := make(chan []*voltha.DeviceImageState, len(request.GetDeviceId()))
1675 for index, deviceID := range request.DeviceId {
ssiddiqui6bd4de02021-06-08 12:04:17 +05301676 // Create status request per device
1677 imageStatusReq := &voltha.DeviceImageRequest{
1678 Version: request.Version,
1679 CommitOnSuccess: request.CommitOnSuccess,
1680 }
1681
ssiddiquif076cb82021-04-23 10:47:04 +05301682 //slice-out only single deviceID from the request
1683 imageStatusReq.DeviceId = request.DeviceId[index : index+1]
1684
1685 go func(deviceID string, req *voltha.DeviceImageRequest, ch chan []*voltha.DeviceImageState) {
1686 agent := dMgr.getDeviceAgent(ctx, deviceID)
1687 if agent == nil {
1688 logger.Errorw(ctx, "Not-found", log.Fields{"device-id": deviceID})
1689 ch <- nil
1690 return
1691 }
1692
1693 resp, err := agent.getImageStatus(ctx, req)
1694 if err != nil {
1695 logger.Errorw(ctx, "get-image-status-failed", log.Fields{"device-id": deviceID, "error": err})
1696 ch <- nil
1697 return
1698 }
1699
1700 err = dMgr.validateDeviceImageResponse(resp)
1701 if err != nil {
1702 logger.Errorw(ctx, "get-image-status-failed", log.Fields{"device-id": deviceID, "error": err})
1703 ch <- nil
1704 return
1705 }
1706 ch <- resp.GetDeviceImageStates()
1707 }(deviceID.GetId(), imageStatusReq, respCh)
1708
1709 }
1710
1711 return dMgr.waitForAllResponses(ctx, "get-image-status", respCh, len(request.GetDeviceId()))
1712}
1713
1714func (dMgr *Manager) AbortImageUpgradeToDevice(ctx context.Context, request *voltha.DeviceImageRequest) (*voltha.DeviceImageResponse, error) {
1715 if err := dMgr.validateImageRequest(request); err != nil {
1716 return nil, err
1717 }
1718
1719 ctx = utils.WithRPCMetadataContext(ctx, "AbortImageUpgradeToDevice")
1720 respCh := make(chan []*voltha.DeviceImageState, len(request.GetDeviceId()))
1721
ssiddiquif076cb82021-04-23 10:47:04 +05301722 for index, deviceID := range request.DeviceId {
ssiddiqui6bd4de02021-06-08 12:04:17 +05301723 // Create abort request per device
1724 abortImageReq := &voltha.DeviceImageRequest{
1725 Version: request.Version,
1726 CommitOnSuccess: request.CommitOnSuccess,
1727 }
1728
ssiddiquif076cb82021-04-23 10:47:04 +05301729 //slice-out only single deviceID from the request
1730 abortImageReq.DeviceId = request.DeviceId[index : index+1]
1731
1732 go func(deviceID string, req *voltha.DeviceImageRequest, ch chan []*voltha.DeviceImageState) {
1733 agent := dMgr.getDeviceAgent(ctx, deviceID)
1734 if agent == nil {
1735 logger.Errorw(ctx, "Not-found", log.Fields{"device-id": deviceID})
1736 ch <- nil
1737 return
1738 }
1739
1740 resp, err := agent.abortImageUpgradeToDevice(ctx, req)
1741 if err != nil {
1742 logger.Errorw(ctx, "abort-image-upgrade-to-device-failed", log.Fields{"device-id": deviceID, "error": err})
1743 ch <- nil
1744 return
1745 }
1746
1747 err = dMgr.validateDeviceImageResponse(resp)
1748 if err != nil {
1749 logger.Errorw(ctx, "abort-image-upgrade-to-device-failed", log.Fields{"device-id": deviceID, "error": err})
1750 ch <- nil
1751 return
1752 }
1753 ch <- resp.GetDeviceImageStates()
1754 }(deviceID.GetId(), abortImageReq, respCh)
1755
1756 }
1757
1758 return dMgr.waitForAllResponses(ctx, "abort-image-upgrade-to-device", respCh, len(request.GetDeviceId()))
1759}
1760
1761func (dMgr *Manager) GetOnuImages(ctx context.Context, id *common.ID) (*voltha.OnuImages, error) {
1762 if id == nil || id.Id == "" {
1763 return nil, status.Errorf(codes.InvalidArgument, "empty device id")
1764 }
1765
1766 ctx = utils.WithRPCMetadataContext(ctx, "GetOnuImages")
1767 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
1768 agent := dMgr.getDeviceAgent(ctx, id.Id)
1769 if agent == nil {
1770 return nil, status.Errorf(codes.NotFound, "%s", id.Id)
1771 }
1772
1773 resp, err := agent.getOnuImages(ctx, id)
1774 if err != nil {
1775 return nil, err
1776 }
1777
1778 logger.Debugw(ctx, "get-onu-images-result", log.Fields{"onu-image": resp.Items})
1779
1780 return resp, nil
1781}
1782
1783func (dMgr *Manager) ActivateImage(ctx context.Context, request *voltha.DeviceImageRequest) (*voltha.DeviceImageResponse, error) {
1784 if err := dMgr.validateImageRequest(request); err != nil {
1785 return nil, err
1786 }
1787
1788 ctx = utils.WithRPCMetadataContext(ctx, "ActivateImage")
1789 respCh := make(chan []*voltha.DeviceImageState, len(request.GetDeviceId()))
1790
ssiddiquif076cb82021-04-23 10:47:04 +05301791 for index, deviceID := range request.DeviceId {
ssiddiqui6bd4de02021-06-08 12:04:17 +05301792 // Create activate request per device
1793 activateImageReq := &voltha.DeviceImageRequest{
1794 Version: request.Version,
1795 CommitOnSuccess: request.CommitOnSuccess,
1796 }
1797
ssiddiquif076cb82021-04-23 10:47:04 +05301798 //slice-out only single deviceID from the request
1799 activateImageReq.DeviceId = request.DeviceId[index : index+1]
1800
1801 go func(deviceID string, req *voltha.DeviceImageRequest, ch chan []*voltha.DeviceImageState) {
1802 agent := dMgr.getDeviceAgent(ctx, deviceID)
1803 if agent == nil {
1804 logger.Errorw(ctx, "Not-found", log.Fields{"device-id": deviceID})
1805 ch <- nil
1806 return
1807 }
1808
1809 resp, err := agent.activateImageOnDevice(ctx, req)
1810 if err != nil {
1811 logger.Errorw(ctx, "activate-image-failed", log.Fields{"device-id": deviceID, "error": err})
1812 ch <- nil
1813 return
1814 }
1815
1816 err = dMgr.validateDeviceImageResponse(resp)
1817 if err != nil {
1818 logger.Errorw(ctx, "activate-image-failed", log.Fields{"device-id": deviceID, "error": err})
1819 ch <- nil
1820 return
1821 }
1822
1823 ch <- resp.GetDeviceImageStates()
1824 }(deviceID.GetId(), activateImageReq, respCh)
1825
1826 }
1827
1828 return dMgr.waitForAllResponses(ctx, "activate-image", respCh, len(request.GetDeviceId()))
1829}
1830
1831func (dMgr *Manager) CommitImage(ctx context.Context, request *voltha.DeviceImageRequest) (*voltha.DeviceImageResponse, error) {
1832 if err := dMgr.validateImageRequest(request); err != nil {
1833 return nil, err
1834 }
1835
1836 ctx = utils.WithRPCMetadataContext(ctx, "CommitImage")
1837 respCh := make(chan []*voltha.DeviceImageState, len(request.GetDeviceId()))
1838
ssiddiquif076cb82021-04-23 10:47:04 +05301839 for index, deviceID := range request.DeviceId {
ssiddiqui6bd4de02021-06-08 12:04:17 +05301840 // Create commit request per device
1841 commitImageReq := &voltha.DeviceImageRequest{
1842 Version: request.Version,
1843 CommitOnSuccess: request.CommitOnSuccess,
1844 }
ssiddiquif076cb82021-04-23 10:47:04 +05301845 //slice-out only single deviceID from the request
1846 commitImageReq.DeviceId = request.DeviceId[index : index+1]
1847
1848 go func(deviceID string, req *voltha.DeviceImageRequest, ch chan []*voltha.DeviceImageState) {
1849 agent := dMgr.getDeviceAgent(ctx, deviceID)
1850 if agent == nil {
1851 logger.Errorw(ctx, "Not-found", log.Fields{"device-id": deviceID})
1852 ch <- nil
1853 return
1854 }
1855
1856 resp, err := agent.commitImage(ctx, req)
1857 if err != nil {
1858 logger.Errorw(ctx, "commit-image-failed", log.Fields{"device-id": deviceID, "error": err})
1859 ch <- nil
1860 return
1861 }
1862
1863 err = dMgr.validateDeviceImageResponse(resp)
1864 if err != nil {
1865 logger.Errorf(ctx, "commit-image-failed", log.Fields{"device-id": deviceID, "error": err})
1866 ch <- nil
1867 return
1868 }
1869 ch <- resp.GetDeviceImageStates()
1870 }(deviceID.GetId(), commitImageReq, respCh)
1871
1872 }
1873
1874 return dMgr.waitForAllResponses(ctx, "commit-image", respCh, len(request.GetDeviceId()))
1875}
1876
1877func (dMgr *Manager) validateImageDownloadRequest(request *voltha.DeviceImageDownloadRequest) error {
1878 if request == nil || request.Image == nil || len(request.DeviceId) == 0 {
1879 return status.Errorf(codes.InvalidArgument, "invalid argument")
1880 }
1881
1882 for _, deviceID := range request.DeviceId {
1883 if deviceID == nil {
1884 return status.Errorf(codes.InvalidArgument, "id is nil")
1885 }
1886 }
1887 return nil
1888}
1889
1890func (dMgr *Manager) validateImageRequest(request *voltha.DeviceImageRequest) error {
1891 if request == nil || len(request.DeviceId) == 0 || request.DeviceId[0] == nil {
1892 return status.Errorf(codes.InvalidArgument, "invalid argument")
1893 }
1894
1895 for _, deviceID := range request.DeviceId {
1896 if deviceID == nil {
1897 return status.Errorf(codes.InvalidArgument, "id is nil")
1898 }
1899 }
1900
1901 return nil
1902}
1903
1904func (dMgr *Manager) validateDeviceImageResponse(response *voltha.DeviceImageResponse) error {
1905 if response == nil || len(response.GetDeviceImageStates()) == 0 || response.GetDeviceImageStates()[0] == nil {
1906 return status.Errorf(codes.Internal, "invalid-response-from-adapter")
1907 }
1908
1909 return nil
1910}
1911
1912func (dMgr *Manager) waitForAllResponses(ctx context.Context, opName string, respCh chan []*voltha.DeviceImageState, expectedResps int) (*voltha.DeviceImageResponse, error) {
1913 response := &voltha.DeviceImageResponse{}
1914 respCount := 0
1915 for {
1916 select {
1917 case resp, ok := <-respCh:
1918 if !ok {
1919 logger.Errorw(ctx, opName+"-failed", log.Fields{"error": "channel-closed"})
1920 return response, status.Errorf(codes.Aborted, "channel-closed")
1921 }
1922
1923 if resp != nil {
1924 logger.Debugw(ctx, opName+"-result", log.Fields{"image-state": resp[0].GetImageState(), "device-id": resp[0].GetDeviceId()})
1925 response.DeviceImageStates = append(response.DeviceImageStates, resp...)
1926 }
1927
1928 respCount++
1929
1930 //check whether all responses received, if so, sent back the collated response
1931 if respCount == expectedResps {
1932 return response, nil
1933 }
1934 continue
1935 case <-ctx.Done():
1936 return nil, status.Errorf(codes.Aborted, opName+"-failed-%s", ctx.Err())
1937 }
1938 }
1939}
Maninder0aabf0c2021-03-17 14:55:14 +05301940
1941func (dMgr *Manager) ReconcilingCleanup(ctx context.Context, device *voltha.Device) error {
1942 agent := dMgr.getDeviceAgent(ctx, device.Id)
1943 if agent == nil {
1944 logger.Errorf(ctx, "Not able to get device agent.")
1945 return status.Errorf(codes.NotFound, "Not able to get device agent for device : %s", device.Id)
1946 }
1947 err := agent.reconcilingCleanup(ctx)
1948 if err != nil {
1949 logger.Errorf(ctx, err.Error())
1950 return status.Errorf(codes.Internal, err.Error())
1951 }
1952 return nil
1953}