blob: cbc6bb938da5450ab32808f2b7be2e3c8a635363 [file] [log] [blame]
khenaidoob9203542018-09-17 22:56:37 -04001/*
2 * Copyright 2018-present Open Networking Foundation
3
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7
8 * http://www.apache.org/licenses/LICENSE-2.0
9
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
npujar1d86a522019-11-14 17:11:16 +053016
Kent Hagerman2b216042020-04-03 18:28:56 -040017package device
khenaidoob9203542018-09-17 22:56:37 -040018
19import (
20 "context"
21 "errors"
David Bainbridged1afd662020-03-26 18:27:41 -070022 "sync"
23 "time"
24
Kent Hagerman45a13e42020-04-13 12:23:50 -040025 "github.com/golang/protobuf/ptypes/empty"
sbarbari17d7e222019-11-05 10:02:29 -050026 "github.com/opencord/voltha-go/db/model"
Kent Hagerman2b216042020-04-03 18:28:56 -040027 "github.com/opencord/voltha-go/rw_core/core/adapter"
Kent Hagermanf5a67352020-04-30 15:15:26 -040028 "github.com/opencord/voltha-go/rw_core/core/device/event"
Kent Hagerman2b216042020-04-03 18:28:56 -040029 "github.com/opencord/voltha-go/rw_core/core/device/remote"
Kent Hagerman6031aad2020-07-29 16:36:33 -040030 "github.com/opencord/voltha-go/rw_core/core/device/state"
khenaidoo3d3b8c22019-05-22 18:10:39 -040031 "github.com/opencord/voltha-go/rw_core/utils"
Himani Chawlab4c25912020-11-12 17:16:38 +053032 "github.com/opencord/voltha-lib-go/v4/pkg/events"
Maninderdfadc982020-10-28 14:04:33 +053033 "github.com/opencord/voltha-lib-go/v4/pkg/kafka"
34 "github.com/opencord/voltha-lib-go/v4/pkg/log"
35 "github.com/opencord/voltha-protos/v4/go/common"
36 ic "github.com/opencord/voltha-protos/v4/go/inter_container"
37 "github.com/opencord/voltha-protos/v4/go/openflow_13"
38 ofp "github.com/opencord/voltha-protos/v4/go/openflow_13"
39 "github.com/opencord/voltha-protos/v4/go/voltha"
khenaidoob9203542018-09-17 22:56:37 -040040 "google.golang.org/grpc/codes"
41 "google.golang.org/grpc/status"
khenaidoob9203542018-09-17 22:56:37 -040042)
43
Kent Hagerman2b216042020-04-03 18:28:56 -040044// Manager represent device manager attributes
45type Manager struct {
Himani Chawlab4c25912020-11-12 17:16:38 +053046 deviceAgents sync.Map
47 rootDevices map[string]bool
48 lockRootDeviceMap sync.RWMutex
49 adapterProxy *remote.AdapterProxy
50 *event.RPCEventManager
Kent Hagerman2b216042020-04-03 18:28:56 -040051 adapterMgr *adapter.Manager
52 logicalDeviceMgr *LogicalManager
npujar467fe752020-01-16 20:17:45 +053053 kafkaICProxy kafka.InterContainerProxy
Kent Hagerman6031aad2020-07-29 16:36:33 -040054 stateTransitions *state.TransitionMap
Mahir Gunyel03de0d32020-06-03 01:36:59 -070055 dbPath *model.Path
Kent Hagermanf5a67352020-04-30 15:15:26 -040056 dProxy *model.Proxy
npujar1d86a522019-11-14 17:11:16 +053057 coreInstanceID string
khenaidoo442e7c72020-03-10 16:13:48 -040058 defaultTimeout time.Duration
khenaidoo4c9e5592019-09-09 16:20:41 -040059 devicesLoadingLock sync.RWMutex
60 deviceLoadingInProgress map[string][]chan int
khenaidoob9203542018-09-17 22:56:37 -040061}
62
Mahir Gunyel03de0d32020-06-03 01:36:59 -070063//NewManagers creates the Manager and the Logical Manager.
Himani Chawlab4c25912020-11-12 17:16:38 +053064func NewManagers(dbPath *model.Path, adapterMgr *adapter.Manager, kmp kafka.InterContainerProxy, endpointMgr kafka.EndpointManager, coreTopic, coreInstanceID string, defaultCoreTimeout time.Duration, eventProxy *events.EventProxy) (*Manager, *LogicalManager) {
Kent Hagerman2b216042020-04-03 18:28:56 -040065 deviceMgr := &Manager{
Kent Hagerman2b216042020-04-03 18:28:56 -040066 rootDevices: make(map[string]bool),
67 kafkaICProxy: kmp,
serkant.uluderya8ff291d2020-05-20 00:58:00 -070068 adapterProxy: remote.NewAdapterProxy(kmp, coreTopic, endpointMgr),
Kent Hagerman2b216042020-04-03 18:28:56 -040069 coreInstanceID: coreInstanceID,
Mahir Gunyel03de0d32020-06-03 01:36:59 -070070 dbPath: dbPath,
71 dProxy: dbPath.Proxy("devices"),
Kent Hagerman2b216042020-04-03 18:28:56 -040072 adapterMgr: adapterMgr,
Kent Hagermanf4151de2020-06-19 15:58:47 -040073 defaultTimeout: defaultCoreTimeout,
Himani Chawlab4c25912020-11-12 17:16:38 +053074 RPCEventManager: event.NewRPCEventManager(eventProxy, coreInstanceID),
Kent Hagerman2b216042020-04-03 18:28:56 -040075 deviceLoadingInProgress: make(map[string][]chan int),
76 }
Kent Hagerman6031aad2020-07-29 16:36:33 -040077 deviceMgr.stateTransitions = state.NewTransitionMap(deviceMgr)
Kent Hagerman2f0d0552020-04-23 17:28:52 -040078
Kent Hagerman2b216042020-04-03 18:28:56 -040079 logicalDeviceMgr := &LogicalManager{
Himani Chawlab4c25912020-11-12 17:16:38 +053080 Manager: event.NewManager(eventProxy, coreInstanceID),
Kent Hagerman2b216042020-04-03 18:28:56 -040081 deviceMgr: deviceMgr,
82 kafkaICProxy: kmp,
Mahir Gunyel03de0d32020-06-03 01:36:59 -070083 dbPath: dbPath,
84 ldProxy: dbPath.Proxy("logical_devices"),
Kent Hagerman2b216042020-04-03 18:28:56 -040085 defaultTimeout: defaultCoreTimeout,
86 logicalDeviceLoadingInProgress: make(map[string][]chan int),
87 }
88 deviceMgr.logicalDeviceMgr = logicalDeviceMgr
Matteo Scandolod525ae32020-04-02 17:27:29 -070089
Kent Hagerman2b216042020-04-03 18:28:56 -040090 adapterMgr.SetAdapterRestartedCallback(deviceMgr.adapterRestarted)
Matteo Scandolod525ae32020-04-02 17:27:29 -070091
Kent Hagerman2b216042020-04-03 18:28:56 -040092 return deviceMgr, logicalDeviceMgr
khenaidoob9203542018-09-17 22:56:37 -040093}
94
Kent Hagerman2b216042020-04-03 18:28:56 -040095func (dMgr *Manager) addDeviceAgentToMap(agent *Agent) {
npujar1d86a522019-11-14 17:11:16 +053096 if _, exist := dMgr.deviceAgents.Load(agent.deviceID); !exist {
97 dMgr.deviceAgents.Store(agent.deviceID, agent)
khenaidoob9203542018-09-17 22:56:37 -040098 }
khenaidoo2c6a0992019-04-29 13:46:56 -040099 dMgr.lockRootDeviceMap.Lock()
100 defer dMgr.lockRootDeviceMap.Unlock()
Kent Hagerman2a07b862020-06-19 15:23:07 -0400101 dMgr.rootDevices[agent.deviceID] = agent.isRootDevice
khenaidoo2c6a0992019-04-29 13:46:56 -0400102
khenaidoob9203542018-09-17 22:56:37 -0400103}
104
Kent Hagerman2b216042020-04-03 18:28:56 -0400105func (dMgr *Manager) deleteDeviceAgentFromMap(agent *Agent) {
npujar1d86a522019-11-14 17:11:16 +0530106 dMgr.deviceAgents.Delete(agent.deviceID)
khenaidoo2c6a0992019-04-29 13:46:56 -0400107 dMgr.lockRootDeviceMap.Lock()
108 defer dMgr.lockRootDeviceMap.Unlock()
npujar1d86a522019-11-14 17:11:16 +0530109 delete(dMgr.rootDevices, agent.deviceID)
khenaidoo4d4802d2018-10-04 21:59:49 -0400110}
111
khenaidoo297cd252019-02-07 22:10:23 -0500112// getDeviceAgent returns the agent managing the device. If the device is not in memory, it will loads it, if it exists
Kent Hagerman2b216042020-04-03 18:28:56 -0400113func (dMgr *Manager) getDeviceAgent(ctx context.Context, deviceID string) *Agent {
npujar1d86a522019-11-14 17:11:16 +0530114 agent, ok := dMgr.deviceAgents.Load(deviceID)
115 if ok {
Kent Hagerman2b216042020-04-03 18:28:56 -0400116 return agent.(*Agent)
khenaidoob9203542018-09-17 22:56:37 -0400117 }
khenaidoo442e7c72020-03-10 16:13:48 -0400118 // Try to load into memory - loading will also create the device agent and set the device ownership
npujar467fe752020-01-16 20:17:45 +0530119 err := dMgr.load(ctx, deviceID)
npujar1d86a522019-11-14 17:11:16 +0530120 if err == nil {
121 agent, ok = dMgr.deviceAgents.Load(deviceID)
122 if !ok {
123 return nil
124 }
Kent Hagerman2b216042020-04-03 18:28:56 -0400125 return agent.(*Agent)
npujar1d86a522019-11-14 17:11:16 +0530126 }
127 //TODO: Change the return params to return an error as well
divyadesaicb8b59d2020-08-18 09:55:47 +0000128 logger.Errorw(ctx, "loading-device-failed", log.Fields{"device-id": deviceID, "error": err})
khenaidoob9203542018-09-17 22:56:37 -0400129 return nil
130}
131
khenaidoo297cd252019-02-07 22:10:23 -0500132// listDeviceIdsFromMap returns the list of device IDs that are in memory
Kent Hagerman2b216042020-04-03 18:28:56 -0400133func (dMgr *Manager) listDeviceIdsFromMap() *voltha.IDs {
khenaidoo7ccedd52018-12-14 16:48:54 -0500134 result := &voltha.IDs{Items: make([]*voltha.ID, 0)}
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400135
136 dMgr.deviceAgents.Range(func(key, value interface{}) bool {
137 result.Items = append(result.Items, &voltha.ID{Id: key.(string)})
138 return true
139 })
140
khenaidoo7ccedd52018-12-14 16:48:54 -0500141 return result
142}
143
Kent Hagerman45a13e42020-04-13 12:23:50 -0400144// CreateDevice creates a new parent device in the data model
145func (dMgr *Manager) CreateDevice(ctx context.Context, device *voltha.Device) (*voltha.Device, error) {
146 if device.MacAddress == "" && device.GetHostAndPort() == "" {
Himani Chawlab4c25912020-11-12 17:16:38 +0530147 logger.Errorf(ctx, "no-device-info-present")
Kent Hagerman45a13e42020-04-13 12:23:50 -0400148 return &voltha.Device{}, errors.New("no-device-info-present; MAC or HOSTIP&PORT")
149 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530150 ctx = utils.WithRPCMetadataContext(ctx, "CreateDevice")
Rohan Agrawal31f21802020-06-12 05:38:46 +0000151 logger.Debugw(ctx, "create-device", log.Fields{"device": *device})
Kent Hagerman45a13e42020-04-13 12:23:50 -0400152
npujar467fe752020-01-16 20:17:45 +0530153 deviceExist, err := dMgr.isParentDeviceExist(ctx, device)
Thomas Lee Se5a44012019-11-07 20:32:24 +0530154 if err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530155 logger.Errorf(ctx, "failed-to-fetch-parent-device-info")
Kent Hagerman45a13e42020-04-13 12:23:50 -0400156 return nil, err
Thomas Lee Se5a44012019-11-07 20:32:24 +0530157 }
158 if deviceExist {
Himani Chawlab4c25912020-11-12 17:16:38 +0530159 logger.Errorf(ctx, "device-is-pre-provisioned-already-with-same-ip-port-or-mac-address")
Kent Hagerman45a13e42020-04-13 12:23:50 -0400160 return nil, errors.New("device is already pre-provisioned")
Thomas Lee S51b5cb82019-10-14 14:49:34 +0530161 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530162 logger.Debugw(ctx, "create-device", log.Fields{"device": device, "aproxy": dMgr.adapterProxy})
khenaidoob9203542018-09-17 22:56:37 -0400163
khenaidoo5e677ae2019-02-28 17:26:29 -0500164 // Ensure this device is set as root
165 device.Root = true
khenaidoob9203542018-09-17 22:56:37 -0400166 // Create and start a device agent for that device
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700167 agent := newAgent(dMgr.adapterProxy, device, dMgr, dMgr.dbPath, dMgr.dProxy, dMgr.defaultTimeout)
Thomas Lee Se5a44012019-11-07 20:32:24 +0530168 device, err = agent.start(ctx, device)
Scott Baker80678602019-11-14 16:57:36 -0800169 if err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530170 logger.Errorw(ctx, "fail-to-start-device", log.Fields{"device-id": agent.deviceID, "error": err})
Kent Hagerman45a13e42020-04-13 12:23:50 -0400171 return nil, err
Scott Baker80678602019-11-14 16:57:36 -0800172 }
khenaidoo442e7c72020-03-10 16:13:48 -0400173 dMgr.addDeviceAgentToMap(agent)
Kent Hagerman45a13e42020-04-13 12:23:50 -0400174 return device, nil
khenaidoob9203542018-09-17 22:56:37 -0400175}
176
Kent Hagerman45a13e42020-04-13 12:23:50 -0400177// EnableDevice activates a device by invoking the adopt_device API on the appropriate adapter
178func (dMgr *Manager) EnableDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530179 ctx = utils.WithRPCMetadataContext(ctx, "EnableDevice")
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000180 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +0530181 logger.Debugw(ctx, "enable-device", log.Fields{"device-id": id.Id})
Kent Hagerman45a13e42020-04-13 12:23:50 -0400182 agent := dMgr.getDeviceAgent(ctx, id.Id)
183 if agent == nil {
184 return nil, status.Errorf(codes.NotFound, "%s", id.Id)
khenaidoob9203542018-09-17 22:56:37 -0400185 }
Kent Hagerman45a13e42020-04-13 12:23:50 -0400186 return &empty.Empty{}, agent.enableDevice(ctx)
khenaidoob9203542018-09-17 22:56:37 -0400187}
188
Kent Hagerman45a13e42020-04-13 12:23:50 -0400189// DisableDevice disables a device along with any child device it may have
190func (dMgr *Manager) DisableDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530191 ctx = utils.WithRPCMetadataContext(ctx, "DisableDevice")
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000192 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +0530193 logger.Debugw(ctx, "disable-device", log.Fields{"device-id": id.Id})
Kent Hagerman45a13e42020-04-13 12:23:50 -0400194 agent := dMgr.getDeviceAgent(ctx, id.Id)
195 if agent == nil {
196 return nil, status.Errorf(codes.NotFound, "%s", id.Id)
khenaidoob9203542018-09-17 22:56:37 -0400197 }
Kent Hagerman45a13e42020-04-13 12:23:50 -0400198 return &empty.Empty{}, agent.disableDevice(ctx)
khenaidoo92e62c52018-10-03 14:02:54 -0400199}
200
Kent Hagerman45a13e42020-04-13 12:23:50 -0400201//RebootDevice invoked the reboot API to the corresponding adapter
202func (dMgr *Manager) RebootDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530203 ctx = utils.WithRPCMetadataContext(ctx, "RebootDevice")
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000204 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +0530205 logger.Debugw(ctx, "reboot-device", log.Fields{"device-id": id.Id})
Kent Hagerman45a13e42020-04-13 12:23:50 -0400206 agent := dMgr.getDeviceAgent(ctx, id.Id)
207 if agent == nil {
208 return nil, status.Errorf(codes.NotFound, "%s", id.Id)
khenaidoo4d4802d2018-10-04 21:59:49 -0400209 }
Kent Hagerman45a13e42020-04-13 12:23:50 -0400210 return &empty.Empty{}, agent.rebootDevice(ctx)
khenaidoo4d4802d2018-10-04 21:59:49 -0400211}
212
Kent Hagerman45a13e42020-04-13 12:23:50 -0400213// DeleteDevice removes a device from the data model
214func (dMgr *Manager) DeleteDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530215 ctx = utils.WithRPCMetadataContext(ctx, "DeleteDevice")
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000216 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +0530217 logger.Debugw(ctx, "delete-device", log.Fields{"device-id": id.Id})
Kent Hagerman45a13e42020-04-13 12:23:50 -0400218 agent := dMgr.getDeviceAgent(ctx, id.Id)
219 if agent == nil {
220 return nil, status.Errorf(codes.NotFound, "%s", id.Id)
khenaidoo4d4802d2018-10-04 21:59:49 -0400221 }
Kent Hagerman45a13e42020-04-13 12:23:50 -0400222 return &empty.Empty{}, agent.deleteDevice(ctx)
223}
224
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530225// ForceDeleteDevice removes a device from the data model forcefully without successfully waiting for the adapters.
226func (dMgr *Manager) ForceDeleteDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530227 ctx = utils.WithRPCMetadataContext(ctx, "ForceDeleteDevice")
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530228 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +0530229 logger.Debugw(ctx, "force-delete-device", log.Fields{"device-id": id.Id})
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530230 agent := dMgr.getDeviceAgent(ctx, id.Id)
231 if agent == nil {
232 return nil, status.Errorf(codes.NotFound, "%s", id.Id)
233 }
234 return &empty.Empty{}, agent.deleteDeviceForce(ctx)
235}
236
Kent Hagerman2a07b862020-06-19 15:23:07 -0400237// GetDevicePort returns the port details for a specific device port entry
238func (dMgr *Manager) GetDevicePort(ctx context.Context, deviceID string, portID uint32) (*voltha.Port, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530239 logger.Debugw(ctx, "get-device-port", log.Fields{"device-id": deviceID})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400240 agent := dMgr.getDeviceAgent(ctx, deviceID)
241 if agent == nil {
242 return nil, status.Errorf(codes.NotFound, "device-%s", deviceID)
243 }
244 return agent.getDevicePort(portID)
245}
246
Kent Hagerman45a13e42020-04-13 12:23:50 -0400247// ListDevicePorts returns the ports details for a specific device entry
248func (dMgr *Manager) ListDevicePorts(ctx context.Context, id *voltha.ID) (*voltha.Ports, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530249 ctx = utils.WithRPCMetadataContext(ctx, "ListDevicePorts")
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000250 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +0530251 logger.Debugw(ctx, "list-device-ports", log.Fields{"device-id": id.Id})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400252 agent := dMgr.getDeviceAgent(ctx, id.Id)
253 if agent == nil {
254 return nil, status.Errorf(codes.NotFound, "device-%s", id.Id)
Kent Hagerman45a13e42020-04-13 12:23:50 -0400255 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400256
257 ports := agent.listDevicePorts()
258 ctr, ret := 0, make([]*voltha.Port, len(ports))
259 for _, port := range ports {
260 ret[ctr] = port
261 ctr++
262 }
263 return &voltha.Ports{Items: ret}, nil
Kent Hagerman45a13e42020-04-13 12:23:50 -0400264}
265
266// ListDeviceFlows returns the flow details for a specific device entry
267func (dMgr *Manager) ListDeviceFlows(ctx context.Context, id *voltha.ID) (*ofp.Flows, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530268 ctx = utils.WithRPCMetadataContext(ctx, "ListDeviceFlows")
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000269 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +0530270 logger.Debugw(ctx, "list-device-flows", log.Fields{"device-id": id.Id})
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700271 agent := dMgr.getDeviceAgent(ctx, id.Id)
272 if agent == nil {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400273 return nil, status.Errorf(codes.NotFound, "device-%s", id.Id)
Kent Hagerman45a13e42020-04-13 12:23:50 -0400274 }
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700275
276 flows := agent.listDeviceFlows()
277 ctr, ret := 0, make([]*ofp.OfpFlowStats, len(flows))
278 for _, flow := range flows {
279 ret[ctr] = flow
280 ctr++
281 }
282 return &openflow_13.Flows{Items: ret}, nil
Kent Hagerman45a13e42020-04-13 12:23:50 -0400283}
284
285// ListDeviceFlowGroups returns the flow group details for a specific device entry
286func (dMgr *Manager) ListDeviceFlowGroups(ctx context.Context, id *voltha.ID) (*voltha.FlowGroups, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530287 ctx = utils.WithRPCMetadataContext(ctx, "ListDeviceFlowGroups")
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000288 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +0530289 logger.Debugw(ctx, "list-device-flow-groups", log.Fields{"device-id": id.Id})
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700290 agent := dMgr.getDeviceAgent(ctx, id.Id)
291 if agent == nil {
Kent Hagerman45a13e42020-04-13 12:23:50 -0400292 return nil, status.Errorf(codes.NotFound, "device-%s", id.Id)
293 }
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700294 groups := agent.listDeviceGroups()
295 ctr, ret := 0, make([]*openflow_13.OfpGroupEntry, len(groups))
296 for _, group := range groups {
297 ret[ctr] = group
298 ctr++
299 }
300 return &voltha.FlowGroups{Items: ret}, nil
khenaidoo4d4802d2018-10-04 21:59:49 -0400301}
302
khenaidoo6d62c002019-05-15 21:57:03 -0400303// stopManagingDevice stops the management of the device as well as any of its reference device and logical device.
304// This function is called only in the Core that does not own this device. In the Core that owns this device then a
305// deletion deletion also includes removal of any reference of this device.
Kent Hagerman2b216042020-04-03 18:28:56 -0400306func (dMgr *Manager) stopManagingDevice(ctx context.Context, id string) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530307 logger.Infow(ctx, "stop-managing-device", log.Fields{"device-id": id})
khenaidoo6d62c002019-05-15 21:57:03 -0400308 if dMgr.IsDeviceInCache(id) { // Proceed only if an agent is present for this device
Kent Hagerman6031aad2020-07-29 16:36:33 -0400309 if device, err := dMgr.getDeviceReadOnly(ctx, id); err == nil && device.Root {
khenaidoo6d62c002019-05-15 21:57:03 -0400310 // stop managing the logical device
David Bainbridged1afd662020-03-26 18:27:41 -0700311 _ = dMgr.logicalDeviceMgr.stopManagingLogicalDeviceWithDeviceID(ctx, id)
khenaidoo6d62c002019-05-15 21:57:03 -0400312 }
npujar467fe752020-01-16 20:17:45 +0530313 if agent := dMgr.getDeviceAgent(ctx, id); agent != nil {
khenaidoo442e7c72020-03-10 16:13:48 -0400314 if err := agent.stop(ctx); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000315 logger.Warnw(ctx, "unable-to-stop-device-agent", log.Fields{"device-id": agent.deviceID, "error": err})
khenaidoo442e7c72020-03-10 16:13:48 -0400316 }
khenaidoo4c9e5592019-09-09 16:20:41 -0400317 dMgr.deleteDeviceAgentFromMap(agent)
khenaidoo6d62c002019-05-15 21:57:03 -0400318 }
319 }
320}
321
npujar1d86a522019-11-14 17:11:16 +0530322// RunPostDeviceDelete removes any reference of this device
Kent Hagerman2b216042020-04-03 18:28:56 -0400323func (dMgr *Manager) RunPostDeviceDelete(ctx context.Context, cDevice *voltha.Device) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530324 logger.Infow(ctx, "run-post-device-delete", log.Fields{"device-id": cDevice.Id})
npujar467fe752020-01-16 20:17:45 +0530325 dMgr.stopManagingDevice(ctx, cDevice.Id)
khenaidoo6d62c002019-05-15 21:57:03 -0400326 return nil
khenaidoo0a822f92019-05-08 15:15:57 -0400327}
328
Kent Hagermancba2f302020-07-28 13:37:36 -0400329// GetDevice exists primarily to implement the gRPC interface.
330// Internal functions should call getDeviceReadOnly instead.
Kent Hagerman45a13e42020-04-13 12:23:50 -0400331func (dMgr *Manager) GetDevice(ctx context.Context, id *voltha.ID) (*voltha.Device, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530332 ctx = utils.WithRPCMetadataContext(ctx, "GetDevice")
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000333 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
Kent Hagermancba2f302020-07-28 13:37:36 -0400334 return dMgr.getDeviceReadOnly(ctx, id.Id)
Kent Hagerman45a13e42020-04-13 12:23:50 -0400335}
336
Kent Hagermancba2f302020-07-28 13:37:36 -0400337// getDeviceReadOnly will returns a device, either from memory or from the dB, if present
338func (dMgr *Manager) getDeviceReadOnly(ctx context.Context, id string) (*voltha.Device, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530339 logger.Debugw(ctx, "get-device-read-only", log.Fields{"device-id": id})
npujar467fe752020-01-16 20:17:45 +0530340 if agent := dMgr.getDeviceAgent(ctx, id); agent != nil {
Kent Hagermancba2f302020-07-28 13:37:36 -0400341 return agent.getDeviceReadOnly(ctx)
khenaidoo92e62c52018-10-03 14:02:54 -0400342 }
343 return nil, status.Errorf(codes.NotFound, "%s", id)
khenaidoob9203542018-09-17 22:56:37 -0400344}
345
Kent Hagerman2a07b862020-06-19 15:23:07 -0400346func (dMgr *Manager) listDevicePorts(ctx context.Context, id string) (map[uint32]*voltha.Port, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530347 logger.Debugw(ctx, "list-device-ports", log.Fields{"device-id": id})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400348 agent := dMgr.getDeviceAgent(ctx, id)
349 if agent == nil {
350 return nil, status.Errorf(codes.NotFound, "%s", id)
351 }
352 return agent.listDevicePorts(), nil
353}
354
npujar1d86a522019-11-14 17:11:16 +0530355// GetChildDevice will return a device, either from memory or from the dB, if present
Kent Hagerman2b216042020-04-03 18:28:56 -0400356func (dMgr *Manager) GetChildDevice(ctx context.Context, parentDeviceID string, serialNumber string, onuID int64, parentPortNo int64) (*voltha.Device, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530357 logger.Debugw(ctx, "get-child-device", log.Fields{"parent-device-id": parentDeviceID, "serialNumber": serialNumber,
358 "parent-port-no": parentPortNo, "onu-id": onuID})
Matt Jeanneret4e241952019-02-28 11:16:04 -0500359
Kent Hagerman2a07b862020-06-19 15:23:07 -0400360 parentDevicePorts, err := dMgr.listDevicePorts(ctx, parentDeviceID)
361 if err != nil {
Matt Jeanneret4e241952019-02-28 11:16:04 -0500362 return nil, status.Errorf(codes.Aborted, "%s", err.Error())
363 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400364 childDeviceIds := dMgr.getAllChildDeviceIds(ctx, parentDevicePorts)
Matt Jeanneret4e241952019-02-28 11:16:04 -0500365 if len(childDeviceIds) == 0 {
Himani Chawlab4c25912020-11-12 17:16:38 +0530366 logger.Debugw(ctx, "no-child-devices", log.Fields{"parent-device-id": parentDeviceID, "serial-number": serialNumber, "onu-id": onuID})
npujar1d86a522019-11-14 17:11:16 +0530367 return nil, status.Errorf(codes.NotFound, "%s", parentDeviceID)
Matt Jeanneret4e241952019-02-28 11:16:04 -0500368 }
369
370 var foundChildDevice *voltha.Device
Kent Hagerman2a07b862020-06-19 15:23:07 -0400371 for childDeviceID := range childDeviceIds {
npujar1d86a522019-11-14 17:11:16 +0530372 var found bool
Kent Hagermancba2f302020-07-28 13:37:36 -0400373 if searchDevice, err := dMgr.getDeviceReadOnly(ctx, childDeviceID); err == nil {
Matt Jeanneret4e241952019-02-28 11:16:04 -0500374
npujar1d86a522019-11-14 17:11:16 +0530375 foundOnuID := false
376 if searchDevice.ProxyAddress.OnuId == uint32(onuID) {
Matt Jeanneret4e241952019-02-28 11:16:04 -0500377 if searchDevice.ParentPortNo == uint32(parentPortNo) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530378 logger.Debugw(ctx, "found-child-by-onuid", log.Fields{"parent-device-id": parentDeviceID, "onu-id": onuID})
npujar1d86a522019-11-14 17:11:16 +0530379 foundOnuID = true
Matt Jeanneret4e241952019-02-28 11:16:04 -0500380 }
381 }
382
383 foundSerialNumber := false
384 if searchDevice.SerialNumber == serialNumber {
Himani Chawlab4c25912020-11-12 17:16:38 +0530385 logger.Debugw(ctx, "found-child-by-serial-number", log.Fields{"parent-device-id": parentDeviceID, "serial-number": serialNumber})
Matt Jeanneret4e241952019-02-28 11:16:04 -0500386 foundSerialNumber = true
387 }
388
389 // if both onuId and serialNumber are provided both must be true for the device to be found
390 // otherwise whichever one found a match is good enough
npujar1d86a522019-11-14 17:11:16 +0530391 if onuID > 0 && serialNumber != "" {
392 found = foundOnuID && foundSerialNumber
Matt Jeanneret4e241952019-02-28 11:16:04 -0500393 } else {
npujar1d86a522019-11-14 17:11:16 +0530394 found = foundOnuID || foundSerialNumber
Matt Jeanneret4e241952019-02-28 11:16:04 -0500395 }
396
npujar1d86a522019-11-14 17:11:16 +0530397 if found {
Matt Jeanneret4e241952019-02-28 11:16:04 -0500398 foundChildDevice = searchDevice
399 break
400 }
401 }
402 }
403
404 if foundChildDevice != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530405 logger.Debugw(ctx, "child-device-found", log.Fields{"parent-device-id": parentDeviceID, "found-child-device": foundChildDevice})
Matt Jeanneret4e241952019-02-28 11:16:04 -0500406 return foundChildDevice, nil
407 }
408
divyadesaicb8b59d2020-08-18 09:55:47 +0000409 logger.Debugw(ctx, "child-device-not-found", log.Fields{"parent-device-id": parentDeviceID,
Himani Chawlab4c25912020-11-12 17:16:38 +0530410 "serial-number": serialNumber, "onu-id": onuID, "parent-port-no": parentPortNo})
npujar1d86a522019-11-14 17:11:16 +0530411 return nil, status.Errorf(codes.NotFound, "%s", parentDeviceID)
Matt Jeanneret4e241952019-02-28 11:16:04 -0500412}
413
npujar1d86a522019-11-14 17:11:16 +0530414// GetChildDeviceWithProxyAddress will return a device based on proxy address
Kent Hagerman2b216042020-04-03 18:28:56 -0400415func (dMgr *Manager) GetChildDeviceWithProxyAddress(ctx context.Context, proxyAddress *voltha.Device_ProxyAddress) (*voltha.Device, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530416 logger.Debugw(ctx, "get-child-device-with-proxy-address", log.Fields{"proxy-address": proxyAddress})
Matt Jeanneret2a20aaa2019-03-05 21:04:02 -0500417
Kent Hagerman2a07b862020-06-19 15:23:07 -0400418 parentDevicePorts, err := dMgr.listDevicePorts(ctx, proxyAddress.DeviceId)
419 if err != nil {
Matt Jeanneret2a20aaa2019-03-05 21:04:02 -0500420 return nil, status.Errorf(codes.Aborted, "%s", err.Error())
421 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400422 childDeviceIds := dMgr.getAllChildDeviceIds(ctx, parentDevicePorts)
Matt Jeanneret2a20aaa2019-03-05 21:04:02 -0500423 if len(childDeviceIds) == 0 {
divyadesaicb8b59d2020-08-18 09:55:47 +0000424 logger.Debugw(ctx, "no-child-devices", log.Fields{"parent-device-id": proxyAddress.DeviceId})
Matt Jeanneret2a20aaa2019-03-05 21:04:02 -0500425 return nil, status.Errorf(codes.NotFound, "%s", proxyAddress)
426 }
427
428 var foundChildDevice *voltha.Device
Kent Hagerman2a07b862020-06-19 15:23:07 -0400429 for childDeviceID := range childDeviceIds {
Kent Hagermancba2f302020-07-28 13:37:36 -0400430 if searchDevice, err := dMgr.getDeviceReadOnly(ctx, childDeviceID); err == nil {
Matt Jeanneret2a20aaa2019-03-05 21:04:02 -0500431 if searchDevice.ProxyAddress == proxyAddress {
432 foundChildDevice = searchDevice
433 break
434 }
435 }
436 }
437
438 if foundChildDevice != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530439 logger.Debugw(ctx, "child-device-found", log.Fields{"proxy-address": proxyAddress})
Matt Jeanneret2a20aaa2019-03-05 21:04:02 -0500440 return foundChildDevice, nil
441 }
442
Himani Chawlab4c25912020-11-12 17:16:38 +0530443 logger.Warnw(ctx, "child-device-not-found", log.Fields{"proxy-address": proxyAddress})
Matt Jeanneret2a20aaa2019-03-05 21:04:02 -0500444 return nil, status.Errorf(codes.NotFound, "%s", proxyAddress)
445}
446
npujar1d86a522019-11-14 17:11:16 +0530447// IsDeviceInCache returns true if device is found in the map
Kent Hagerman2b216042020-04-03 18:28:56 -0400448func (dMgr *Manager) IsDeviceInCache(id string) bool {
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400449 _, exist := dMgr.deviceAgents.Load(id)
khenaidoo297cd252019-02-07 22:10:23 -0500450 return exist
451}
452
Stephane Barbarieaa467942019-02-06 14:09:44 -0500453// ListDevices retrieves the latest devices from the data model
Kent Hagerman45a13e42020-04-13 12:23:50 -0400454func (dMgr *Manager) ListDevices(ctx context.Context, _ *empty.Empty) (*voltha.Devices, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530455 ctx = utils.WithRPCMetadataContext(ctx, "ListDevices")
456 logger.Debug(ctx, "list-devices")
khenaidoob9203542018-09-17 22:56:37 -0400457 result := &voltha.Devices{}
Kent Hagerman4f355f52020-03-30 16:01:33 -0400458
459 var devices []*voltha.Device
Kent Hagermanf5a67352020-04-30 15:15:26 -0400460 if err := dMgr.dProxy.List(ctx, &devices); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000461 logger.Errorw(ctx, "failed-to-list-devices-from-cluster-proxy", log.Fields{"error": err})
Thomas Lee Se5a44012019-11-07 20:32:24 +0530462 return nil, err
463 }
Kent Hagerman4f355f52020-03-30 16:01:33 -0400464
465 for _, device := range devices {
466 // If device is not in memory then set it up
467 if !dMgr.IsDeviceInCache(device.Id) {
divyadesaicb8b59d2020-08-18 09:55:47 +0000468 logger.Debugw(ctx, "loading-device-from-Model", log.Fields{"device-id": device.Id})
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700469 agent := newAgent(dMgr.adapterProxy, device, dMgr, dMgr.dbPath, dMgr.dProxy, dMgr.defaultTimeout)
Kent Hagerman4f355f52020-03-30 16:01:33 -0400470 if _, err := agent.start(ctx, nil); err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000471 logger.Warnw(ctx, "failure-starting-agent", log.Fields{"device-id": device.Id})
Kent Hagerman4f355f52020-03-30 16:01:33 -0400472 } else {
473 dMgr.addDeviceAgentToMap(agent)
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500474 }
khenaidoob9203542018-09-17 22:56:37 -0400475 }
Kent Hagerman4f355f52020-03-30 16:01:33 -0400476 result.Items = append(result.Items, device)
khenaidoob9203542018-09-17 22:56:37 -0400477 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530478 logger.Debugw(ctx, "list-devices-end", log.Fields{"len": len(result.Items)})
khenaidoob9203542018-09-17 22:56:37 -0400479 return result, nil
480}
481
Thomas Lee S51b5cb82019-10-14 14:49:34 +0530482//isParentDeviceExist checks whether device is already preprovisioned.
Kent Hagerman2b216042020-04-03 18:28:56 -0400483func (dMgr *Manager) isParentDeviceExist(ctx context.Context, newDevice *voltha.Device) (bool, error) {
Thomas Lee S51b5cb82019-10-14 14:49:34 +0530484 hostPort := newDevice.GetHostAndPort()
Kent Hagerman4f355f52020-03-30 16:01:33 -0400485 var devices []*voltha.Device
Kent Hagermanf5a67352020-04-30 15:15:26 -0400486 if err := dMgr.dProxy.List(ctx, &devices); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530487 logger.Errorw(ctx, "failed-to-list-devices-from-cluster-data-proxy", log.Fields{"error": err})
Thomas Lee Se5a44012019-11-07 20:32:24 +0530488 return false, err
489 }
Kent Hagerman4f355f52020-03-30 16:01:33 -0400490 for _, device := range devices {
491 if !device.Root {
492 continue
493 }
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530494
495 if hostPort != "" && hostPort == device.GetHostAndPort() {
Kent Hagerman4f355f52020-03-30 16:01:33 -0400496 return true, nil
497 }
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530498 if newDevice.MacAddress != "" && newDevice.MacAddress == device.MacAddress {
Kent Hagerman4f355f52020-03-30 16:01:33 -0400499 return true, nil
Thomas Lee S51b5cb82019-10-14 14:49:34 +0530500 }
501 }
Thomas Lee Se5a44012019-11-07 20:32:24 +0530502 return false, nil
Thomas Lee S51b5cb82019-10-14 14:49:34 +0530503}
504
khenaidoo6d62c002019-05-15 21:57:03 -0400505//getDeviceFromModelretrieves the device data from the model.
Kent Hagerman2b216042020-04-03 18:28:56 -0400506func (dMgr *Manager) getDeviceFromModel(ctx context.Context, deviceID string) (*voltha.Device, error) {
Kent Hagerman4f355f52020-03-30 16:01:33 -0400507 device := &voltha.Device{}
Kent Hagermanf5a67352020-04-30 15:15:26 -0400508 if have, err := dMgr.dProxy.Get(ctx, deviceID, device); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000509 logger.Errorw(ctx, "failed-to-get-device-info-from-cluster-proxy", log.Fields{"error": err})
Thomas Lee Se5a44012019-11-07 20:32:24 +0530510 return nil, err
Kent Hagerman4f355f52020-03-30 16:01:33 -0400511 } else if !have {
512 return nil, status.Error(codes.NotFound, deviceID)
Thomas Lee Se5a44012019-11-07 20:32:24 +0530513 }
Kent Hagerman4f355f52020-03-30 16:01:33 -0400514
515 return device, nil
khenaidoo6d62c002019-05-15 21:57:03 -0400516}
517
npujar1d86a522019-11-14 17:11:16 +0530518// loadDevice loads the deviceID in memory, if not present
Kent Hagerman2b216042020-04-03 18:28:56 -0400519func (dMgr *Manager) loadDevice(ctx context.Context, deviceID string) (*Agent, error) {
npujar1d86a522019-11-14 17:11:16 +0530520 if deviceID == "" {
khenaidoo297cd252019-02-07 22:10:23 -0500521 return nil, status.Error(codes.InvalidArgument, "deviceId empty")
522 }
khenaidoo4c9e5592019-09-09 16:20:41 -0400523 var err error
524 var device *voltha.Device
525 dMgr.devicesLoadingLock.Lock()
npujar1d86a522019-11-14 17:11:16 +0530526 if _, exist := dMgr.deviceLoadingInProgress[deviceID]; !exist {
527 if !dMgr.IsDeviceInCache(deviceID) {
528 dMgr.deviceLoadingInProgress[deviceID] = []chan int{make(chan int, 1)}
khenaidoo4c9e5592019-09-09 16:20:41 -0400529 dMgr.devicesLoadingLock.Unlock()
530 // Proceed with the loading only if the device exist in the Model (could have been deleted)
npujar467fe752020-01-16 20:17:45 +0530531 if device, err = dMgr.getDeviceFromModel(ctx, deviceID); err == nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000532 logger.Debugw(ctx, "loading-device", log.Fields{"device-id": deviceID})
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700533 agent := newAgent(dMgr.adapterProxy, device, dMgr, dMgr.dbPath, dMgr.dProxy, dMgr.defaultTimeout)
npujar467fe752020-01-16 20:17:45 +0530534 if _, err = agent.start(ctx, nil); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530535 logger.Warnw(ctx, "failure-loading-device", log.Fields{"device-id": deviceID, "error": err})
khenaidoo4c9e5592019-09-09 16:20:41 -0400536 } else {
537 dMgr.addDeviceAgentToMap(agent)
538 }
539 } else {
Himani Chawlab4c25912020-11-12 17:16:38 +0530540 logger.Debugw(ctx, "device-is-not-in-model", log.Fields{"device-id": deviceID})
khenaidoo6d62c002019-05-15 21:57:03 -0400541 }
khenaidoo4c9e5592019-09-09 16:20:41 -0400542 // announce completion of task to any number of waiting channels
543 dMgr.devicesLoadingLock.Lock()
npujar1d86a522019-11-14 17:11:16 +0530544 if v, ok := dMgr.deviceLoadingInProgress[deviceID]; ok {
khenaidoo4c9e5592019-09-09 16:20:41 -0400545 for _, ch := range v {
546 close(ch)
547 }
npujar1d86a522019-11-14 17:11:16 +0530548 delete(dMgr.deviceLoadingInProgress, deviceID)
khenaidoo4c9e5592019-09-09 16:20:41 -0400549 }
550 dMgr.devicesLoadingLock.Unlock()
khenaidoo6d62c002019-05-15 21:57:03 -0400551 } else {
khenaidoo4c9e5592019-09-09 16:20:41 -0400552 dMgr.devicesLoadingLock.Unlock()
khenaidoo297cd252019-02-07 22:10:23 -0500553 }
khenaidoo4c9e5592019-09-09 16:20:41 -0400554 } else {
555 ch := make(chan int, 1)
npujar1d86a522019-11-14 17:11:16 +0530556 dMgr.deviceLoadingInProgress[deviceID] = append(dMgr.deviceLoadingInProgress[deviceID], ch)
khenaidoo4c9e5592019-09-09 16:20:41 -0400557 dMgr.devicesLoadingLock.Unlock()
558 // Wait for the channel to be closed, implying the process loading this device is done.
559 <-ch
khenaidoo297cd252019-02-07 22:10:23 -0500560 }
npujar1d86a522019-11-14 17:11:16 +0530561 if agent, ok := dMgr.deviceAgents.Load(deviceID); ok {
Kent Hagerman2b216042020-04-03 18:28:56 -0400562 return agent.(*Agent), nil
khenaidoo297cd252019-02-07 22:10:23 -0500563 }
npujar1d86a522019-11-14 17:11:16 +0530564 return nil, status.Errorf(codes.Aborted, "Error loading device %s", deviceID)
khenaidoo297cd252019-02-07 22:10:23 -0500565}
566
567// loadRootDeviceParentAndChildren loads the children and parents of a root device in memory
Kent Hagerman2a07b862020-06-19 15:23:07 -0400568func (dMgr *Manager) loadRootDeviceParentAndChildren(ctx context.Context, device *voltha.Device, devicePorts map[uint32]*voltha.Port) error {
divyadesaicb8b59d2020-08-18 09:55:47 +0000569 logger.Debugw(ctx, "loading-parent-and-children", log.Fields{"device-id": device.Id})
khenaidoo297cd252019-02-07 22:10:23 -0500570 if device.Root {
571 // Scenario A
572 if device.ParentId != "" {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400573 // Load logical device if needed.
npujar467fe752020-01-16 20:17:45 +0530574 if err := dMgr.logicalDeviceMgr.load(ctx, device.ParentId); err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000575 logger.Warnw(ctx, "failure-loading-logical-device", log.Fields{"logical-device-id": device.ParentId})
khenaidoo297cd252019-02-07 22:10:23 -0500576 }
577 } else {
divyadesaicb8b59d2020-08-18 09:55:47 +0000578 logger.Debugw(ctx, "no-parent-to-load", log.Fields{"device-id": device.Id})
khenaidoo297cd252019-02-07 22:10:23 -0500579 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400580 // Load all child devices, if needed
581 childDeviceIds := dMgr.getAllChildDeviceIds(ctx, devicePorts)
582 for childDeviceID := range childDeviceIds {
583 if _, err := dMgr.loadDevice(ctx, childDeviceID); err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000584 logger.Warnw(ctx, "failure-loading-device", log.Fields{"device-id": childDeviceID, "error": err})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400585 return err
khenaidoo297cd252019-02-07 22:10:23 -0500586 }
khenaidoo297cd252019-02-07 22:10:23 -0500587 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530588 logger.Debugw(ctx, "loaded-children", log.Fields{"device-id": device.Id, "num-children": len(childDeviceIds)})
khenaidoo297cd252019-02-07 22:10:23 -0500589 }
590 return nil
591}
592
593// load loads the deviceId in memory, if not present, and also loads its accompanying parents and children. Loading
594// in memory is for improved performance. It is not imperative that a device needs to be in memory when a request
595// acting on the device is received by the core. In such a scenario, the Core will load the device in memory first
596// and the proceed with the request.
Kent Hagerman2b216042020-04-03 18:28:56 -0400597func (dMgr *Manager) load(ctx context.Context, deviceID string) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000598 logger.Debug(ctx, "load...")
khenaidoo297cd252019-02-07 22:10:23 -0500599 // 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 -0400600 var dAgent *Agent
khenaidoo297cd252019-02-07 22:10:23 -0500601 var err error
npujar467fe752020-01-16 20:17:45 +0530602 if dAgent, err = dMgr.loadDevice(ctx, deviceID); err != nil {
khenaidoo297cd252019-02-07 22:10:23 -0500603 return err
604 }
605 // Get the loaded device details
Kent Hagermancba2f302020-07-28 13:37:36 -0400606 device, err := dAgent.getDeviceReadOnly(ctx)
khenaidoo442e7c72020-03-10 16:13:48 -0400607 if err != nil {
608 return err
609 }
khenaidoo297cd252019-02-07 22:10:23 -0500610
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530611 // If the device is in Pre-provisioning or getting deleted state stop here
612 if device.AdminState == voltha.AdminState_PREPROVISIONED || dAgent.isDeletionInProgress() {
khenaidoo297cd252019-02-07 22:10:23 -0500613 return nil
614 }
615
616 // Now we face two scenarios
617 if device.Root {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400618 devicePorts := dAgent.listDevicePorts()
619
khenaidoo297cd252019-02-07 22:10:23 -0500620 // Load all children as well as the parent of this device (logical_device)
Kent Hagerman2a07b862020-06-19 15:23:07 -0400621 if err := dMgr.loadRootDeviceParentAndChildren(ctx, device, devicePorts); err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000622 logger.Warnw(ctx, "failure-loading-device-parent-and-children", log.Fields{"device-id": deviceID})
khenaidoo297cd252019-02-07 22:10:23 -0500623 return err
624 }
divyadesaicb8b59d2020-08-18 09:55:47 +0000625 logger.Debugw(ctx, "successfully-loaded-parent-and-children", log.Fields{"device-id": deviceID})
khenaidoo297cd252019-02-07 22:10:23 -0500626 } else {
627 // Scenario B - use the parentId of that device (root device) to trigger the loading
628 if device.ParentId != "" {
npujar467fe752020-01-16 20:17:45 +0530629 return dMgr.load(ctx, device.ParentId)
khenaidoo297cd252019-02-07 22:10:23 -0500630 }
631 }
632 return nil
633}
634
khenaidoo7ccedd52018-12-14 16:48:54 -0500635// ListDeviceIds retrieves the latest device IDs information from the data model (memory data only)
Rohan Agrawal31f21802020-06-12 05:38:46 +0000636func (dMgr *Manager) ListDeviceIds(ctx context.Context, _ *empty.Empty) (*voltha.IDs, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530637 ctx = utils.WithRPCMetadataContext(ctx, "ListDeviceIds")
638 logger.Debug(ctx, "list-device-ids")
khenaidoo7ccedd52018-12-14 16:48:54 -0500639 // Report only device IDs that are in the device agent map
640 return dMgr.listDeviceIdsFromMap(), nil
641}
642
Kent Hagerman45a13e42020-04-13 12:23:50 -0400643// ReconcileDevices is a request to a voltha core to update its list of managed devices. This will
644// trigger loading the devices along with their children and parent in memory
645func (dMgr *Manager) ReconcileDevices(ctx context.Context, ids *voltha.IDs) (*empty.Empty, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530646 ctx = utils.WithRPCMetadataContext(ctx, "ReconcileDevices")
647 logger.Debugw(ctx, "reconcile-devices", log.Fields{"num-devices": len(ids.Items)})
khenaidoo4c9e5592019-09-09 16:20:41 -0400648 if ids != nil && len(ids.Items) != 0 {
khenaidoo7ccedd52018-12-14 16:48:54 -0500649 toReconcile := len(ids.Items)
650 reconciled := 0
khenaidoo4c9e5592019-09-09 16:20:41 -0400651 var err error
khenaidoo7ccedd52018-12-14 16:48:54 -0500652 for _, id := range ids.Items {
npujar467fe752020-01-16 20:17:45 +0530653 if err = dMgr.load(ctx, id.Id); err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000654 logger.Warnw(ctx, "failure-reconciling-device", log.Fields{"device-id": id.Id, "error": err})
khenaidoo4c9e5592019-09-09 16:20:41 -0400655 } else {
npujar1d86a522019-11-14 17:11:16 +0530656 reconciled++
khenaidoo7ccedd52018-12-14 16:48:54 -0500657 }
658 }
659 if toReconcile != reconciled {
Kent Hagerman45a13e42020-04-13 12:23:50 -0400660 return nil, status.Errorf(codes.DataLoss, "less-device-reconciled-than-requested:%d/%d", reconciled, toReconcile)
khenaidoo7ccedd52018-12-14 16:48:54 -0500661 }
662 } else {
Kent Hagerman45a13e42020-04-13 12:23:50 -0400663 return nil, status.Errorf(codes.InvalidArgument, "empty-list-of-ids")
khenaidoo7ccedd52018-12-14 16:48:54 -0500664 }
Kent Hagerman45a13e42020-04-13 12:23:50 -0400665 return &empty.Empty{}, nil
khenaidoo7ccedd52018-12-14 16:48:54 -0500666}
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500667
khenaidooba6b6c42019-08-02 09:11:56 -0400668// isOkToReconcile validates whether a device is in the correct status to be reconciled
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530669func (dMgr *Manager) isOkToReconcile(ctx context.Context, device *voltha.Device) bool {
khenaidooba6b6c42019-08-02 09:11:56 -0400670 if device == nil {
671 return false
672 }
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530673 if agent := dMgr.getDeviceAgent(ctx, device.Id); agent != nil {
674 return device.AdminState != voltha.AdminState_PREPROVISIONED && (!agent.isDeletionInProgress())
675 }
676 return false
khenaidooba6b6c42019-08-02 09:11:56 -0400677}
678
679// adapterRestarted is invoked whenever an adapter is restarted
Kent Hagerman2b216042020-04-03 18:28:56 -0400680func (dMgr *Manager) adapterRestarted(ctx context.Context, adapter *voltha.Adapter) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530681 logger.Debugw(ctx, "adapter-restarted", log.Fields{"adapter-id": adapter.Id, "vendor": adapter.Vendor,
682 "current-replica": adapter.CurrentReplica, "total-replicas": adapter.TotalReplicas, "endpoint": adapter.Endpoint})
khenaidooba6b6c42019-08-02 09:11:56 -0400683
684 // Let's reconcile the device managed by this Core only
David Bainbridged1afd662020-03-26 18:27:41 -0700685 if len(dMgr.rootDevices) == 0 {
Himani Chawlab4c25912020-11-12 17:16:38 +0530686 logger.Debugw(ctx, "nothing-to-reconcile", log.Fields{"adapter-id": adapter.Id})
khenaidooba6b6c42019-08-02 09:11:56 -0400687 return nil
688 }
689
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500690 responses := make([]utils.Response, 0)
David Bainbridged1afd662020-03-26 18:27:41 -0700691 for rootDeviceID := range dMgr.rootDevices {
Mahir Gunyel12cf55f2020-12-16 17:55:03 -0800692 dAgent := dMgr.getDeviceAgent(ctx, rootDeviceID)
693 if dAgent == nil {
694 continue
695 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530696 logger.Debugw(ctx, "checking-adapter-type", log.Fields{"agentType": dAgent.deviceType, "adapter-type": adapter.Type})
Mahir Gunyel12cf55f2020-12-16 17:55:03 -0800697 if dAgent.deviceType == adapter.Type {
698 rootDevice, _ := dAgent.getDeviceReadOnly(ctx)
699 if rootDevice == nil {
700 continue
701 }
Rohan Agrawal31f21802020-06-12 05:38:46 +0000702 isDeviceOwnedByService, err := dMgr.adapterProxy.IsDeviceOwnedByService(ctx, rootDeviceID, adapter.Type, adapter.CurrentReplica)
serkant.uluderya7d545aa2020-04-09 13:38:45 -0700703 if err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530704 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 -0700705 continue
706 }
707 if isDeviceOwnedByService {
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530708 if dMgr.isOkToReconcile(ctx, rootDevice) {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000709 logger.Debugw(ctx, "reconciling-root-device", log.Fields{"rootId": rootDevice.Id})
npujar467fe752020-01-16 20:17:45 +0530710 responses = append(responses, dMgr.sendReconcileDeviceRequest(ctx, rootDevice))
khenaidooba6b6c42019-08-02 09:11:56 -0400711 } else {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000712 logger.Debugw(ctx, "not-reconciling-root-device", log.Fields{"rootId": rootDevice.Id, "state": rootDevice.AdminState})
khenaidooba6b6c42019-08-02 09:11:56 -0400713 }
714 } else { // Should we be reconciling the root's children instead?
Kent Hagerman2a07b862020-06-19 15:23:07 -0400715 rootDevicePorts, _ := dMgr.listDevicePorts(ctx, rootDeviceID)
khenaidooba6b6c42019-08-02 09:11:56 -0400716 childManagedByAdapter:
Kent Hagerman2a07b862020-06-19 15:23:07 -0400717 for _, port := range rootDevicePorts {
khenaidooba6b6c42019-08-02 09:11:56 -0400718 for _, peer := range port.Peers {
npujar467fe752020-01-16 20:17:45 +0530719 if childDevice, _ := dMgr.getDeviceFromModel(ctx, peer.DeviceId); childDevice != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000720 isDeviceOwnedByService, err := dMgr.adapterProxy.IsDeviceOwnedByService(ctx, childDevice.Id, adapter.Type, adapter.CurrentReplica)
serkant.uluderya7d545aa2020-04-09 13:38:45 -0700721 if err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530722 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 -0700723 }
724 if isDeviceOwnedByService {
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530725 if dMgr.isOkToReconcile(ctx, childDevice) {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000726 logger.Debugw(ctx, "reconciling-child-device", log.Fields{"child-device-id": childDevice.Id})
npujar467fe752020-01-16 20:17:45 +0530727 responses = append(responses, dMgr.sendReconcileDeviceRequest(ctx, childDevice))
khenaidooba6b6c42019-08-02 09:11:56 -0400728 } else {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000729 logger.Debugw(ctx, "not-reconciling-child-device", log.Fields{"child-device-id": childDevice.Id, "state": childDevice.AdminState})
khenaidooba6b6c42019-08-02 09:11:56 -0400730 }
731 } else {
732 // All child devices under a parent device are typically managed by the same adapter type.
733 // Therefore we only need to check whether the first device we retrieved is managed by that adapter
734 break childManagedByAdapter
735 }
736 }
737 }
738 }
739 }
740 }
741 }
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500742 if len(responses) > 0 {
khenaidooba6b6c42019-08-02 09:11:56 -0400743 // Wait for completion
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500744 if res := utils.WaitForNilOrErrorResponses(dMgr.defaultTimeout, responses...); res != nil {
khenaidooba6b6c42019-08-02 09:11:56 -0400745 return status.Errorf(codes.Aborted, "errors-%s", res)
746 }
747 } else {
Himani Chawlab4c25912020-11-12 17:16:38 +0530748 logger.Debugw(ctx, "no-managed-device-to-reconcile", log.Fields{"adapter-id": adapter.Id})
khenaidooba6b6c42019-08-02 09:11:56 -0400749 }
750 return nil
751}
752
Kent Hagerman2b216042020-04-03 18:28:56 -0400753func (dMgr *Manager) sendReconcileDeviceRequest(ctx context.Context, device *voltha.Device) utils.Response {
khenaidooba6b6c42019-08-02 09:11:56 -0400754 // Send a reconcile request to the adapter. Since this Core may not be managing this device then there is no
755 // point of creating a device agent (if the device is not being managed by this Core) before sending the request
npujar1d86a522019-11-14 17:11:16 +0530756 // to the adapter. We will therefore bypass the adapter adapter and send the request directly to the adapter via
Kent Hagerman2b216042020-04-03 18:28:56 -0400757 // the adapter proxy.
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500758 response := utils.NewResponse()
Kent Hagerman2b216042020-04-03 18:28:56 -0400759 ch, err := dMgr.adapterProxy.ReconcileDevice(ctx, device)
khenaidoo442e7c72020-03-10 16:13:48 -0400760 if err != nil {
761 response.Error(err)
762 }
763 // Wait for adapter response in its own routine
764 go func() {
765 resp, ok := <-ch
766 if !ok {
767 response.Error(status.Errorf(codes.Aborted, "channel-closed-device: %s", device.Id))
768 } else if resp.Err != nil {
769 response.Error(resp.Err)
khenaidooba6b6c42019-08-02 09:11:56 -0400770 }
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500771 response.Done()
khenaidoo442e7c72020-03-10 16:13:48 -0400772 }()
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500773 return response
khenaidooba6b6c42019-08-02 09:11:56 -0400774}
775
Kent Hagerman2b216042020-04-03 18:28:56 -0400776func (dMgr *Manager) ReconcileChildDevices(ctx context.Context, parentDeviceID string) error {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400777 if parentDevicePorts, err := dMgr.listDevicePorts(ctx, parentDeviceID); err == nil {
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500778 responses := make([]utils.Response, 0)
Kent Hagerman2a07b862020-06-19 15:23:07 -0400779 for _, port := range parentDevicePorts {
khenaidooba6b6c42019-08-02 09:11:56 -0400780 for _, peer := range port.Peers {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400781 if childDevice, err := dMgr.getDeviceFromModel(ctx, peer.DeviceId); err == nil {
npujar467fe752020-01-16 20:17:45 +0530782 responses = append(responses, dMgr.sendReconcileDeviceRequest(ctx, childDevice))
khenaidooba6b6c42019-08-02 09:11:56 -0400783 }
784 }
785 }
786 // Wait for completion
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500787 if res := utils.WaitForNilOrErrorResponses(dMgr.defaultTimeout, responses...); res != nil {
khenaidooba6b6c42019-08-02 09:11:56 -0400788 return status.Errorf(codes.Aborted, "errors-%s", res)
789 }
790 }
791 return nil
792}
793
Kent Hagerman2b216042020-04-03 18:28:56 -0400794func (dMgr *Manager) UpdateDeviceUsingAdapterData(ctx context.Context, device *voltha.Device) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530795 logger.Debugw(ctx, "update-device-using-adapter-data", log.Fields{"device-id": device.Id, "device": device})
npujar467fe752020-01-16 20:17:45 +0530796 if agent := dMgr.getDeviceAgent(ctx, device.Id); agent != nil {
797 return agent.updateDeviceUsingAdapterData(ctx, device)
khenaidoob9203542018-09-17 22:56:37 -0400798 }
799 return status.Errorf(codes.NotFound, "%s", device.Id)
800}
801
khenaidoo0db4c812020-05-27 15:27:30 -0400802func (dMgr *Manager) addPeerPort(ctx context.Context, deviceID string, port *voltha.Port) error {
803 meAsPeer := &voltha.Port_PeerPort{DeviceId: deviceID, PortNo: port.PortNo}
804 for _, peerPort := range port.Peers {
805 if agent := dMgr.getDeviceAgent(ctx, peerPort.DeviceId); agent != nil {
806 if err := agent.addPeerPort(ctx, meAsPeer); err != nil {
807 return err
808 }
809 }
810 }
811 // Notify the logical device manager to setup a logical port, if needed. If the added port is an NNI or UNI
812 // then a logical port will be added to the logical device and the device route generated. If the port is a
813 // PON port then only the device graph will be generated.
Kent Hagermancba2f302020-07-28 13:37:36 -0400814 device, err := dMgr.getDeviceReadOnly(ctx, deviceID)
khenaidoo0db4c812020-05-27 15:27:30 -0400815 if err != nil {
816 return err
817 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400818 ports, err := dMgr.listDevicePorts(ctx, deviceID)
819 if err != nil {
820 return err
821 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530822 subCtx := utils.WithSpanAndRPCMetadataFromContext(ctx)
823
824 if err = dMgr.logicalDeviceMgr.updateLogicalPort(subCtx, device, ports, port); err != nil {
khenaidoo0db4c812020-05-27 15:27:30 -0400825 return err
826 }
827 return nil
828}
829
Kent Hagerman2b216042020-04-03 18:28:56 -0400830func (dMgr *Manager) AddPort(ctx context.Context, deviceID string, port *voltha.Port) error {
npujar467fe752020-01-16 20:17:45 +0530831 agent := dMgr.getDeviceAgent(ctx, deviceID)
npujar1d86a522019-11-14 17:11:16 +0530832 if agent != nil {
npujar467fe752020-01-16 20:17:45 +0530833 if err := agent.addPort(ctx, port); err != nil {
khenaidoo92e62c52018-10-03 14:02:54 -0400834 return err
835 }
khenaidoo0db4c812020-05-27 15:27:30 -0400836 // Setup peer ports in its own routine
837 go func() {
Himani Chawlab4c25912020-11-12 17:16:38 +0530838 subCtx := utils.WithSpanAndRPCMetadataFromContext(ctx)
839 if err := dMgr.addPeerPort(subCtx, deviceID, port); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000840 logger.Errorw(ctx, "unable-to-add-peer-port", log.Fields{"error": err, "device-id": deviceID})
khenaidoo92e62c52018-10-03 14:02:54 -0400841 }
khenaidoo0db4c812020-05-27 15:27:30 -0400842 }()
khenaidoo92e62c52018-10-03 14:02:54 -0400843 return nil
khenaidoob9203542018-09-17 22:56:37 -0400844 }
npujar1d86a522019-11-14 17:11:16 +0530845 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoob9203542018-09-17 22:56:37 -0400846}
847
Kent Hagerman2b216042020-04-03 18:28:56 -0400848func (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 +0530849 logger.Debugw(ctx, "add-flows-and-groups", log.Fields{"device-id": deviceID, "groups:": groups, "flow-metadata": flowMetadata})
npujar467fe752020-01-16 20:17:45 +0530850 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
851 return agent.addFlowsAndGroups(ctx, flows, groups, flowMetadata)
khenaidoo0458db62019-06-20 08:50:36 -0400852 }
npujar1d86a522019-11-14 17:11:16 +0530853 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo0458db62019-06-20 08:50:36 -0400854}
855
khenaidoo787224a2020-04-16 18:08:47 -0400856// deleteParentFlows removes flows from the parent device based on specific attributes
857func (dMgr *Manager) deleteParentFlows(ctx context.Context, deviceID string, uniPort uint32, metadata *voltha.FlowMetadata) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530858 logger.Debugw(ctx, "delete-parent-flows", log.Fields{"device-id": deviceID, "uni-port": uniPort, "metadata": metadata})
khenaidoo787224a2020-04-16 18:08:47 -0400859 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400860 if !agent.isRootDevice {
khenaidoo787224a2020-04-16 18:08:47 -0400861 return status.Errorf(codes.FailedPrecondition, "not-a-parent-device-%s", deviceID)
862 }
863 return agent.filterOutFlows(ctx, uniPort, metadata)
864 }
865 return status.Errorf(codes.NotFound, "%s", deviceID)
866}
867
Kent Hagerman2b216042020-04-03 18:28:56 -0400868func (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 +0530869 logger.Debugw(ctx, "delete-flows-and-groups", log.Fields{"device-id": deviceID})
npujar467fe752020-01-16 20:17:45 +0530870 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
871 return agent.deleteFlowsAndGroups(ctx, flows, groups, flowMetadata)
khenaidoo0458db62019-06-20 08:50:36 -0400872 }
npujar1d86a522019-11-14 17:11:16 +0530873 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo0458db62019-06-20 08:50:36 -0400874}
875
Kent Hagerman2b216042020-04-03 18:28:56 -0400876func (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 +0530877 logger.Debugw(ctx, "update-flows-and-groups", log.Fields{"device-id": deviceID})
npujar467fe752020-01-16 20:17:45 +0530878 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
879 return agent.updateFlowsAndGroups(ctx, flows, groups, flowMetadata)
khenaidoo19d7b632018-10-30 10:49:50 -0400880 }
npujar1d86a522019-11-14 17:11:16 +0530881 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo19d7b632018-10-30 10:49:50 -0400882}
883
Kent Hagerman45a13e42020-04-13 12:23:50 -0400884// UpdateDevicePmConfigs updates the PM configs. This is executed when the northbound gRPC API is invoked, typically
khenaidoob3127472019-07-24 21:04:55 -0400885// following a user action
Kent Hagerman45a13e42020-04-13 12:23:50 -0400886func (dMgr *Manager) UpdateDevicePmConfigs(ctx context.Context, configs *voltha.PmConfigs) (*empty.Empty, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530887 ctx = utils.WithRPCMetadataContext(ctx, "UpdateDevicePmConfigs")
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000888 log.EnrichSpan(ctx, log.Fields{"device-id": configs.Id})
Kent Hagerman45a13e42020-04-13 12:23:50 -0400889 if configs.Id == "" {
890 return nil, status.Error(codes.FailedPrecondition, "invalid-device-Id")
khenaidoob3127472019-07-24 21:04:55 -0400891 }
Kent Hagerman45a13e42020-04-13 12:23:50 -0400892 agent := dMgr.getDeviceAgent(ctx, configs.Id)
893 if agent == nil {
894 return nil, status.Errorf(codes.NotFound, "%s", configs.Id)
895 }
896 return &empty.Empty{}, agent.updatePmConfigs(ctx, configs)
khenaidoob3127472019-07-24 21:04:55 -0400897}
898
Kent Hagerman2b216042020-04-03 18:28:56 -0400899// InitPmConfigs initialize the pm configs as defined by the adapter.
900func (dMgr *Manager) InitPmConfigs(ctx context.Context, deviceID string, pmConfigs *voltha.PmConfigs) error {
khenaidoob3127472019-07-24 21:04:55 -0400901 if pmConfigs.Id == "" {
902 return status.Errorf(codes.FailedPrecondition, "invalid-device-Id")
903 }
npujar467fe752020-01-16 20:17:45 +0530904 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
905 return agent.initPmConfigs(ctx, pmConfigs)
khenaidoob9203542018-09-17 22:56:37 -0400906 }
npujar1d86a522019-11-14 17:11:16 +0530907 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoob9203542018-09-17 22:56:37 -0400908}
909
Kent Hagerman45a13e42020-04-13 12:23:50 -0400910// ListDevicePmConfigs returns pm configs of device
911func (dMgr *Manager) ListDevicePmConfigs(ctx context.Context, id *voltha.ID) (*voltha.PmConfigs, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530912 ctx = utils.WithRPCMetadataContext(ctx, "ListDevicePmConfigs")
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000913 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
Kent Hagerman45a13e42020-04-13 12:23:50 -0400914 agent := dMgr.getDeviceAgent(ctx, id.Id)
915 if agent == nil {
916 return nil, status.Errorf(codes.NotFound, "%s", id.Id)
khenaidoob3127472019-07-24 21:04:55 -0400917 }
Kent Hagerman45a13e42020-04-13 12:23:50 -0400918 return agent.listPmConfigs(ctx)
khenaidoob3127472019-07-24 21:04:55 -0400919}
920
Kent Hagerman2b216042020-04-03 18:28:56 -0400921func (dMgr *Manager) getSwitchCapability(ctx context.Context, deviceID string) (*ic.SwitchCapability, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530922 logger.Debugw(ctx, "get-switch-capability", log.Fields{"device-id": deviceID})
npujar467fe752020-01-16 20:17:45 +0530923 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
khenaidoob9203542018-09-17 22:56:37 -0400924 return agent.getSwitchCapability(ctx)
925 }
npujar1d86a522019-11-14 17:11:16 +0530926 return nil, status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoob9203542018-09-17 22:56:37 -0400927}
928
Kent Hagerman2b216042020-04-03 18:28:56 -0400929func (dMgr *Manager) GetPorts(ctx context.Context, deviceID string, portType voltha.Port_PortType) (*voltha.Ports, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530930 logger.Debugw(ctx, "get-ports", log.Fields{"device-id": deviceID, "port-type": portType})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400931 agent := dMgr.getDeviceAgent(ctx, deviceID)
932 if agent == nil {
933 return nil, status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoob9203542018-09-17 22:56:37 -0400934 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400935 return agent.getPorts(ctx, portType), nil
khenaidoob9203542018-09-17 22:56:37 -0400936}
937
Kent Hagerman2b216042020-04-03 18:28:56 -0400938func (dMgr *Manager) UpdateDeviceStatus(ctx context.Context, deviceID string, operStatus voltha.OperStatus_Types, connStatus voltha.ConnectStatus_Types) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530939 logger.Debugw(ctx, "update-device-status", log.Fields{"device-id": deviceID, "oper-status": operStatus, "conn-status": connStatus})
npujar467fe752020-01-16 20:17:45 +0530940 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
941 return agent.updateDeviceStatus(ctx, operStatus, connStatus)
khenaidoo92e62c52018-10-03 14:02:54 -0400942 }
npujar1d86a522019-11-14 17:11:16 +0530943 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo92e62c52018-10-03 14:02:54 -0400944}
945
Kent Hagerman2b216042020-04-03 18:28:56 -0400946func (dMgr *Manager) UpdateChildrenStatus(ctx context.Context, deviceID string, operStatus voltha.OperStatus_Types, connStatus voltha.ConnectStatus_Types) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530947 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 -0400948 parentDevicePorts, err := dMgr.listDevicePorts(ctx, deviceID)
949 if err != nil {
khenaidoo4d4802d2018-10-04 21:59:49 -0400950 return status.Errorf(codes.Aborted, "%s", err.Error())
951 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400952 for childDeviceID := range dMgr.getAllChildDeviceIds(ctx, parentDevicePorts) {
npujar467fe752020-01-16 20:17:45 +0530953 if agent := dMgr.getDeviceAgent(ctx, childDeviceID); agent != nil {
954 if err = agent.updateDeviceStatus(ctx, operStatus, connStatus); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530955 return status.Errorf(codes.Aborted, "childDevice:%s, error:%s", childDeviceID, err.Error())
khenaidoo4d4802d2018-10-04 21:59:49 -0400956 }
957 }
958 }
959 return nil
960}
961
Kent Hagerman2b216042020-04-03 18:28:56 -0400962func (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 +0530963 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 +0530964 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
965 if err := agent.updatePortState(ctx, portType, portNo, operStatus); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530966 logger.Errorw(ctx, "updating-port-state-failed", log.Fields{"device-id": deviceID, "port-no": portNo, "error": err})
khenaidoo171b98e2019-10-31 11:48:15 -0400967 return err
968 }
969 // Notify the logical device manager to change the port state
Mahir Gunyel18fa0c92020-03-06 13:34:04 -0800970 // Do this for NNI and UNIs only. PON ports are not known by logical device
971 if portType == voltha.Port_ETHERNET_NNI || portType == voltha.Port_ETHERNET_UNI {
972 go func() {
Himani Chawlab4c25912020-11-12 17:16:38 +0530973 subCtx := utils.WithSpanAndRPCMetadataFromContext(ctx)
974 err := dMgr.logicalDeviceMgr.updatePortState(subCtx, deviceID, portNo, operStatus)
Mahir Gunyel18fa0c92020-03-06 13:34:04 -0800975 if err != nil {
976 // While we want to handle (catch) and log when
977 // an update to a port was not able to be
978 // propagated to the logical port, we can report
979 // it as a warning and not an error because it
980 // doesn't stop or modify processing.
981 // TODO: VOL-2707
Rohan Agrawal31f21802020-06-12 05:38:46 +0000982 logger.Warnw(ctx, "unable-to-update-logical-port-state", log.Fields{"error": err})
Mahir Gunyel18fa0c92020-03-06 13:34:04 -0800983 }
984 }()
985 }
khenaidoo442e7c72020-03-10 16:13:48 -0400986 return nil
khenaidoob9203542018-09-17 22:56:37 -0400987 }
npujar1d86a522019-11-14 17:11:16 +0530988 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoob9203542018-09-17 22:56:37 -0400989}
990
Kent Hagerman2b216042020-04-03 18:28:56 -0400991func (dMgr *Manager) DeleteAllPorts(ctx context.Context, deviceID string) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530992 logger.Debugw(ctx, "delete-all-ports", log.Fields{"device-id": deviceID})
npujar467fe752020-01-16 20:17:45 +0530993 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
994 if err := agent.deleteAllPorts(ctx); err != nil {
khenaidoo0a822f92019-05-08 15:15:57 -0400995 return err
996 }
997 // Notify the logical device manager to remove all logical ports, if needed.
Kent Hagerman2b216042020-04-03 18:28:56 -0400998 // At this stage the device itself may gave been deleted already at a DeleteAllPorts
khenaidoo0a822f92019-05-08 15:15:57 -0400999 // typically is part of a device deletion phase.
Kent Hagermancba2f302020-07-28 13:37:36 -04001000 if device, err := dMgr.getDeviceReadOnly(ctx, deviceID); err == nil {
npujar1d86a522019-11-14 17:11:16 +05301001 go func() {
Himani Chawlab4c25912020-11-12 17:16:38 +05301002 subCtx := utils.WithSpanAndRPCMetadataFromContext(ctx)
1003 if err := dMgr.logicalDeviceMgr.deleteAllLogicalPorts(subCtx, device); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001004 logger.Errorw(ctx, "unable-to-delete-logical-ports", log.Fields{"error": err})
npujar1d86a522019-11-14 17:11:16 +05301005 }
1006 }()
khenaidoo0a822f92019-05-08 15:15:57 -04001007 } else {
divyadesaicb8b59d2020-08-18 09:55:47 +00001008 logger.Warnw(ctx, "failed-to-retrieve-device", log.Fields{"device-id": deviceID})
khenaidoo0a822f92019-05-08 15:15:57 -04001009 return err
1010 }
1011 return nil
1012 }
npujar1d86a522019-11-14 17:11:16 +05301013 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo0a822f92019-05-08 15:15:57 -04001014}
1015
Kent Hagerman2b216042020-04-03 18:28:56 -04001016//UpdatePortsState updates all ports on the device
Kent Hagerman2a07b862020-06-19 15:23:07 -04001017func (dMgr *Manager) UpdatePortsState(ctx context.Context, deviceID string, portTypeFilter uint32, state voltha.OperStatus_Types) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301018 logger.Debugw(ctx, "update-ports-state", log.Fields{"device-id": deviceID})
Kent Hagerman2a07b862020-06-19 15:23:07 -04001019 agent := dMgr.getDeviceAgent(ctx, deviceID)
1020 if agent == nil {
1021 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoo3ab34882019-05-02 21:33:30 -04001022 }
Kent Hagerman2a07b862020-06-19 15:23:07 -04001023 if state != voltha.OperStatus_ACTIVE && state != voltha.OperStatus_UNKNOWN {
1024 return status.Error(codes.Unimplemented, "state-change-not-implemented")
1025 }
1026 if err := agent.updatePortsOperState(ctx, portTypeFilter, state); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +05301027 logger.Warnw(ctx, "update-ports-state-failed", log.Fields{"device-id": deviceID, "error": err})
Kent Hagerman2a07b862020-06-19 15:23:07 -04001028 return err
1029 }
1030 return nil
khenaidoo3ab34882019-05-02 21:33:30 -04001031}
1032
Kent Hagerman2b216042020-04-03 18:28:56 -04001033func (dMgr *Manager) ChildDeviceDetected(ctx context.Context, parentDeviceID string, parentPortNo int64, deviceType string,
npujar1d86a522019-11-14 17:11:16 +05301034 channelID int64, vendorID string, serialNumber string, onuID int64) (*voltha.Device, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301035 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 -07001036
npujar1d86a522019-11-14 17:11:16 +05301037 if deviceType == "" && vendorID != "" {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001038 logger.Debug(ctx, "device-type-is-nil-fetching-device-type")
Kent Hagerman45a13e42020-04-13 12:23:50 -04001039 deviceTypes, err := dMgr.adapterMgr.ListDeviceTypes(ctx, nil)
1040 if err != nil {
1041 return nil, err
1042 }
Kent Hagerman4f355f52020-03-30 16:01:33 -04001043 OLoop:
Kent Hagerman45a13e42020-04-13 12:23:50 -04001044 for _, dType := range deviceTypes.Items {
Kent Hagerman4f355f52020-03-30 16:01:33 -04001045 for _, v := range dType.VendorIds {
1046 if v == vendorID {
1047 deviceType = dType.Adapter
1048 break OLoop
Chaitrashree G S4b3fada2019-07-28 23:55:25 -07001049 }
1050 }
1051 }
1052 }
1053 //if no match found for the vendorid,report adapter with the custom error message
1054 if deviceType == "" {
Himani Chawlab4c25912020-11-12 17:16:38 +05301055 logger.Errorw(ctx, "failed-to-fetch-adapter-name ", log.Fields{"vendor-id": vendorID})
npujar1d86a522019-11-14 17:11:16 +05301056 return nil, status.Errorf(codes.NotFound, "%s", vendorID)
Chaitrashree G S4b3fada2019-07-28 23:55:25 -07001057 }
khenaidoob9203542018-09-17 22:56:37 -04001058
1059 // Create the ONU device
1060 childDevice := &voltha.Device{}
khenaidoob9203542018-09-17 22:56:37 -04001061 childDevice.Type = deviceType
npujar1d86a522019-11-14 17:11:16 +05301062 childDevice.ParentId = parentDeviceID
khenaidoob9203542018-09-17 22:56:37 -04001063 childDevice.ParentPortNo = uint32(parentPortNo)
npujar1d86a522019-11-14 17:11:16 +05301064 childDevice.VendorId = vendorID
Matt Jeanneret4e241952019-02-28 11:16:04 -05001065 childDevice.SerialNumber = serialNumber
khenaidoob9203542018-09-17 22:56:37 -04001066 childDevice.Root = false
khenaidoo6fdf0ba2018-11-02 14:38:33 -04001067
khenaidoo442e7c72020-03-10 16:13:48 -04001068 // Get parent device type
1069 pAgent := dMgr.getDeviceAgent(ctx, parentDeviceID)
1070 if pAgent == nil {
npujar1d86a522019-11-14 17:11:16 +05301071 return nil, status.Errorf(codes.NotFound, "%s", parentDeviceID)
khenaidoo6fdf0ba2018-11-02 14:38:33 -04001072 }
khenaidoo442e7c72020-03-10 16:13:48 -04001073 if pAgent.deviceType == "" {
1074 return nil, status.Errorf(codes.FailedPrecondition, "device Type not set %s", parentDeviceID)
1075 }
khenaidoo6fdf0ba2018-11-02 14:38:33 -04001076
npujar467fe752020-01-16 20:17:45 +05301077 if device, err := dMgr.GetChildDevice(ctx, parentDeviceID, serialNumber, onuID, parentPortNo); err == nil {
Himani Chawlab4c25912020-11-12 17:16:38 +05301078 logger.Warnw(ctx, "child-device-exists", log.Fields{"parent-device-id": parentDeviceID, "serial-number": serialNumber})
Mahir Gunyel6deaa242019-06-27 04:53:33 -07001079 return device, status.Errorf(codes.AlreadyExists, "%s", serialNumber)
Matt Jeanneret4e241952019-02-28 11:16:04 -05001080 }
1081
khenaidoo442e7c72020-03-10 16:13:48 -04001082 childDevice.ProxyAddress = &voltha.Device_ProxyAddress{DeviceId: parentDeviceID, DeviceType: pAgent.deviceType, ChannelId: uint32(channelID), OnuId: uint32(onuID)}
khenaidoob9203542018-09-17 22:56:37 -04001083
1084 // Create and start a device agent for that device
Mahir Gunyel03de0d32020-06-03 01:36:59 -07001085 agent := newAgent(dMgr.adapterProxy, childDevice, dMgr, dMgr.dbPath, dMgr.dProxy, dMgr.defaultTimeout)
Mahir Gunyel23bd8c72020-09-21 23:20:43 -07001086 insertedChildDevice, err := agent.start(ctx, childDevice)
Scott Baker80678602019-11-14 16:57:36 -08001087 if err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001088 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 -08001089 return nil, err
1090 }
khenaidoo442e7c72020-03-10 16:13:48 -04001091 dMgr.addDeviceAgentToMap(agent)
khenaidoob9203542018-09-17 22:56:37 -04001092
1093 // Activate the child device
npujar467fe752020-01-16 20:17:45 +05301094 if agent = dMgr.getDeviceAgent(ctx, agent.deviceID); agent != nil {
npujar1d86a522019-11-14 17:11:16 +05301095 go func() {
Himani Chawlab4c25912020-11-12 17:16:38 +05301096 subCtx := utils.WithSpanAndRPCMetadataFromContext(ctx)
1097 err := agent.enableDevice(subCtx)
npujar1d86a522019-11-14 17:11:16 +05301098 if err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001099 logger.Errorw(ctx, "unable-to-enable-device", log.Fields{"error": err})
npujar1d86a522019-11-14 17:11:16 +05301100 }
1101 }()
khenaidoob9203542018-09-17 22:56:37 -04001102 }
1103
Mahir Gunyel23bd8c72020-09-21 23:20:43 -07001104 return insertedChildDevice, nil
khenaidoob9203542018-09-17 22:56:37 -04001105}
1106
Kent Hagerman2b216042020-04-03 18:28:56 -04001107func (dMgr *Manager) packetOut(ctx context.Context, deviceID string, outPort uint32, packet *ofp.OfpPacketOut) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301108 logger.Debugw(ctx, "packet-out", log.Fields{"device-id": deviceID, "out-port": outPort})
npujar467fe752020-01-16 20:17:45 +05301109 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
1110 return agent.packetOut(ctx, outPort, packet)
khenaidoofdbad6e2018-11-06 22:26:38 -05001111 }
npujar1d86a522019-11-14 17:11:16 +05301112 return status.Errorf(codes.NotFound, "%s", deviceID)
khenaidoofdbad6e2018-11-06 22:26:38 -05001113}
1114
npujar1d86a522019-11-14 17:11:16 +05301115// PacketIn receives packet from adapter
Kent Hagerman2b216042020-04-03 18:28:56 -04001116func (dMgr *Manager) PacketIn(ctx context.Context, deviceID string, port uint32, transactionID string, packet []byte) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301117 logger.Debugw(ctx, "packet-in", log.Fields{"device-id": deviceID, "port": port})
khenaidoofdbad6e2018-11-06 22:26:38 -05001118 // Get the logical device Id based on the deviceId
1119 var device *voltha.Device
1120 var err error
Kent Hagermancba2f302020-07-28 13:37:36 -04001121 if device, err = dMgr.getDeviceReadOnly(ctx, deviceID); err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +00001122 logger.Errorw(ctx, "device-not-found", log.Fields{"device-id": deviceID})
khenaidoofdbad6e2018-11-06 22:26:38 -05001123 return err
1124 }
khenaidoo43c82122018-11-22 18:38:28 -05001125 if !device.Root {
divyadesaicb8b59d2020-08-18 09:55:47 +00001126 logger.Errorw(ctx, "device-not-root", log.Fields{"device-id": deviceID})
npujar1d86a522019-11-14 17:11:16 +05301127 return status.Errorf(codes.FailedPrecondition, "%s", deviceID)
khenaidoofdbad6e2018-11-06 22:26:38 -05001128 }
1129
npujar467fe752020-01-16 20:17:45 +05301130 if err := dMgr.logicalDeviceMgr.packetIn(ctx, device.ParentId, port, transactionID, packet); err != nil {
khenaidoofdbad6e2018-11-06 22:26:38 -05001131 return err
1132 }
1133 return nil
1134}
1135
Kent Hagerman2b216042020-04-03 18:28:56 -04001136func (dMgr *Manager) setParentID(ctx context.Context, device *voltha.Device, parentID string) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301137 logger.Debugw(ctx, "set-parent-id", log.Fields{"device-id": device.Id, "parent-id": parentID})
npujar467fe752020-01-16 20:17:45 +05301138 if agent := dMgr.getDeviceAgent(ctx, device.Id); agent != nil {
1139 return agent.setParentID(ctx, device, parentID)
khenaidooad06fd72019-10-28 12:26:05 -04001140 }
1141 return status.Errorf(codes.NotFound, "%s", device.Id)
1142}
1143
Himani Chawlab4c25912020-11-12 17:16:38 +05301144//
1145//CreateLogicalDevice creates logical device in core
Kent Hagerman2b216042020-04-03 18:28:56 -04001146func (dMgr *Manager) CreateLogicalDevice(ctx context.Context, cDevice *voltha.Device) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301147 logger.Info(ctx, "create-logical-device")
khenaidoo59ef7be2019-06-21 12:40:28 -04001148 // Verify whether the logical device has already been created
1149 if cDevice.ParentId != "" {
Himani Chawlab4c25912020-11-12 17:16:38 +05301150 logger.Debugw(ctx, "parent-device-already-exist", log.Fields{"device-id": cDevice.Id, "logical-device-id": cDevice.Id})
khenaidoo59ef7be2019-06-21 12:40:28 -04001151 return nil
1152 }
khenaidoob9203542018-09-17 22:56:37 -04001153 var err error
npujar467fe752020-01-16 20:17:45 +05301154 if _, err = dMgr.logicalDeviceMgr.createLogicalDevice(ctx, cDevice); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +05301155 logger.Warnw(ctx, "create-logical-device-error", log.Fields{"device": cDevice})
khenaidoob9203542018-09-17 22:56:37 -04001156 return err
1157 }
khenaidoob9203542018-09-17 22:56:37 -04001158 return nil
1159}
1160
npujar1d86a522019-11-14 17:11:16 +05301161// DeleteLogicalDevice deletes logical device from core
Kent Hagerman2b216042020-04-03 18:28:56 -04001162func (dMgr *Manager) DeleteLogicalDevice(ctx context.Context, cDevice *voltha.Device) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301163 logger.Info(ctx, "delete-logical-device")
khenaidoo92e62c52018-10-03 14:02:54 -04001164 var err error
npujar467fe752020-01-16 20:17:45 +05301165 if err = dMgr.logicalDeviceMgr.deleteLogicalDevice(ctx, cDevice); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +05301166 logger.Warnw(ctx, "delete-logical-device-error", log.Fields{"device-id": cDevice.Id})
khenaidoo92e62c52018-10-03 14:02:54 -04001167 return err
1168 }
1169 // Remove the logical device Id from the parent device
npujar1d86a522019-11-14 17:11:16 +05301170 logicalID := ""
npujar467fe752020-01-16 20:17:45 +05301171 dMgr.UpdateDeviceAttribute(ctx, cDevice.Id, "ParentId", logicalID)
khenaidoo92e62c52018-10-03 14:02:54 -04001172 return nil
1173}
1174
npujar1d86a522019-11-14 17:11:16 +05301175// DeleteLogicalPorts removes the logical ports associated with that deviceId
Kent Hagerman2b216042020-04-03 18:28:56 -04001176func (dMgr *Manager) DeleteLogicalPorts(ctx context.Context, cDevice *voltha.Device) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001177 logger.Debugw(ctx, "delete-all-logical-ports", log.Fields{"device-id": cDevice.Id})
khenaidoo442e7c72020-03-10 16:13:48 -04001178 if err := dMgr.logicalDeviceMgr.deleteLogicalPorts(ctx, cDevice.Id); err != nil {
khenaidooe132f522020-03-20 15:23:15 -04001179 // 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 +05301180 logger.Warnw(ctx, "delete-logical-ports-error", log.Fields{"device-id": cDevice.Id, "error": err})
khenaidoo0a822f92019-05-08 15:15:57 -04001181 }
1182 return nil
1183}
1184
Kent Hagerman2b216042020-04-03 18:28:56 -04001185func (dMgr *Manager) getParentDevice(ctx context.Context, childDevice *voltha.Device) *voltha.Device {
khenaidoo92e62c52018-10-03 14:02:54 -04001186 // Sanity check
1187 if childDevice.Root {
1188 // childDevice is the parent device
1189 return childDevice
1190 }
Kent Hagermancba2f302020-07-28 13:37:36 -04001191 parentDevice, _ := dMgr.getDeviceReadOnly(ctx, childDevice.ParentId)
khenaidoo92e62c52018-10-03 14:02:54 -04001192 return parentDevice
1193}
1194
Kent Hagerman2b216042020-04-03 18:28:56 -04001195//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 -04001196//cannot manage the child devices. This will trigger the Core to disable all the child devices.
Kent Hagerman2b216042020-04-03 18:28:56 -04001197func (dMgr *Manager) ChildDevicesLost(ctx context.Context, parentDeviceID string) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301198 logger.Debug(ctx, "child-devices-lost")
Kent Hagermancba2f302020-07-28 13:37:36 -04001199 parentDevice, err := dMgr.getDeviceReadOnly(ctx, parentDeviceID)
Kent Hagerman2a07b862020-06-19 15:23:07 -04001200 if err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +00001201 logger.Warnw(ctx, "failed-getting-device", log.Fields{"parent-device-id": parentDeviceID, "error": err})
khenaidoo0a822f92019-05-08 15:15:57 -04001202 return err
1203 }
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001204 return dMgr.DisableAllChildDevices(ctx, parentDevice)
khenaidoo0a822f92019-05-08 15:15:57 -04001205}
1206
Kent Hagerman2b216042020-04-03 18:28:56 -04001207//ChildDevicesDetected is invoked by an adapter when child devices are found, typically after after a
khenaidoo0a822f92019-05-08 15:15:57 -04001208// disable/enable sequence. This will trigger the Core to Enable all the child devices of that parent.
Kent Hagerman2b216042020-04-03 18:28:56 -04001209func (dMgr *Manager) ChildDevicesDetected(ctx context.Context, parentDeviceID string) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301210 logger.Debug(ctx, "child-devices-detected")
Kent Hagerman2a07b862020-06-19 15:23:07 -04001211 parentDevicePorts, err := dMgr.listDevicePorts(ctx, parentDeviceID)
1212 if err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +00001213 logger.Warnw(ctx, "failed-getting-device", log.Fields{"device-id": parentDeviceID, "error": err})
khenaidoo0a822f92019-05-08 15:15:57 -04001214 return err
1215 }
Kent Hagerman2a07b862020-06-19 15:23:07 -04001216 childDeviceIds := dMgr.getAllChildDeviceIds(ctx, parentDevicePorts)
khenaidoo0a822f92019-05-08 15:15:57 -04001217 if len(childDeviceIds) == 0 {
divyadesaicb8b59d2020-08-18 09:55:47 +00001218 logger.Debugw(ctx, "no-child-device", log.Fields{"parent-device-id": parentDeviceID})
khenaidoo0a822f92019-05-08 15:15:57 -04001219 }
khenaidoo59ef7be2019-06-21 12:40:28 -04001220 allChildEnableRequestSent := true
Kent Hagerman2a07b862020-06-19 15:23:07 -04001221 for childDeviceID := range childDeviceIds {
npujar467fe752020-01-16 20:17:45 +05301222 if agent := dMgr.getDeviceAgent(ctx, childDeviceID); agent != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +05301223 subCtx := utils.WithSpanAndRPCMetadataFromContext(ctx)
khenaidoo59ef7be2019-06-21 12:40:28 -04001224 // Run the children re-registration in its own routine
Kent Hagerman2a07b862020-06-19 15:23:07 -04001225 go func(ctx context.Context) {
1226 err = agent.enableDevice(ctx)
npujar1d86a522019-11-14 17:11:16 +05301227 if err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001228 logger.Errorw(ctx, "unable-to-enable-device", log.Fields{"error": err})
npujar1d86a522019-11-14 17:11:16 +05301229 }
Himani Chawlab4c25912020-11-12 17:16:38 +05301230 }(subCtx)
khenaidoo59ef7be2019-06-21 12:40:28 -04001231 } else {
npujar1d86a522019-11-14 17:11:16 +05301232 err = status.Errorf(codes.Unavailable, "no agent for child device %s", childDeviceID)
Himani Chawlab4c25912020-11-12 17:16:38 +05301233 logger.Errorw(ctx, "no-child-device-agent", log.Fields{"parent-device-id": parentDeviceID, "child-id": childDeviceID})
khenaidoo59ef7be2019-06-21 12:40:28 -04001234 allChildEnableRequestSent = false
khenaidoo0a822f92019-05-08 15:15:57 -04001235 }
1236 }
khenaidoo59ef7be2019-06-21 12:40:28 -04001237 if !allChildEnableRequestSent {
khenaidoo0a822f92019-05-08 15:15:57 -04001238 return err
1239 }
1240 return nil
1241}
1242
khenaidoo4d4802d2018-10-04 21:59:49 -04001243/*
1244All the functions below are callback functions where they are invoked with the latest and previous data. We can
1245therefore use the data as is without trying to get the latest from the model.
1246*/
1247
khenaidoo0a822f92019-05-08 15:15:57 -04001248//DisableAllChildDevices is invoked as a callback when the parent device is disabled
Kent Hagerman2b216042020-04-03 18:28:56 -04001249func (dMgr *Manager) DisableAllChildDevices(ctx context.Context, parentCurrDevice *voltha.Device) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301250 logger.Debug(ctx, "disable-all-child-devices")
Kent Hagerman2a07b862020-06-19 15:23:07 -04001251 ports, _ := dMgr.listDevicePorts(ctx, parentCurrDevice.Id)
1252 for childDeviceID := range dMgr.getAllChildDeviceIds(ctx, ports) {
npujar467fe752020-01-16 20:17:45 +05301253 if agent := dMgr.getDeviceAgent(ctx, childDeviceID); agent != nil {
Kent Hagerman2a07b862020-06-19 15:23:07 -04001254 if err := agent.disableDevice(ctx); err != nil {
khenaidooe132f522020-03-20 15:23:15 -04001255 // Just log the error - this error happens only if the child device was already in deleted state.
divyadesaicb8b59d2020-08-18 09:55:47 +00001256 logger.Errorw(ctx, "failure-disable-device", log.Fields{"device-id": childDeviceID, "error": err.Error()})
khenaidoo92e62c52018-10-03 14:02:54 -04001257 }
1258 }
1259 }
1260 return nil
1261}
1262
khenaidoo0a822f92019-05-08 15:15:57 -04001263//DeleteAllChildDevices is invoked as a callback when the parent device is deleted
Kent Hagerman2b216042020-04-03 18:28:56 -04001264func (dMgr *Manager) DeleteAllChildDevices(ctx context.Context, parentCurrDevice *voltha.Device) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301265 logger.Debug(ctx, "delete-all-child-devices")
Himani Chawla2ba1c9c2020-10-07 13:19:03 +05301266 force := false
1267 // Get the parent device Transient state, if its FORCE_DELETED(go for force delete for child devices)
1268 // So in cases when this handler is getting called other than DELETE operation, no force option would be used.
1269 agent := dMgr.getDeviceAgent(ctx, parentCurrDevice.Id)
1270 if agent == nil {
1271 return status.Errorf(codes.NotFound, "%s", parentCurrDevice.Id)
1272 }
1273
1274 force = agent.getTransientState() == voltha.DeviceTransientState_FORCE_DELETING
1275
Kent Hagerman2a07b862020-06-19 15:23:07 -04001276 ports, _ := dMgr.listDevicePorts(ctx, parentCurrDevice.Id)
1277 for childDeviceID := range dMgr.getAllChildDeviceIds(ctx, ports) {
npujar467fe752020-01-16 20:17:45 +05301278 if agent := dMgr.getDeviceAgent(ctx, childDeviceID); agent != nil {
Himani Chawla2ba1c9c2020-10-07 13:19:03 +05301279 if force {
1280 if err := agent.deleteDeviceForce(ctx); err != nil {
1281 logger.Warnw(ctx, "failure-delete-device-force", log.Fields{"device-id": childDeviceID,
1282 "error": err.Error()})
1283 }
1284 } else {
1285 if err := agent.deleteDevice(ctx); err != nil {
1286 logger.Warnw(ctx, "failure-delete-device", log.Fields{"device-id": childDeviceID,
1287 "error": err.Error()})
1288 }
khenaidoo4d4802d2018-10-04 21:59:49 -04001289 }
khenaidoo49085352020-01-13 19:15:43 -05001290 // No further action is required here. The deleteDevice will change the device state where the resulting
1291 // callback will take care of cleaning the child device agent.
khenaidoo4d4802d2018-10-04 21:59:49 -04001292 }
1293 }
khenaidoo4d4802d2018-10-04 21:59:49 -04001294 return nil
1295}
1296
Girish Gowdra408cd962020-03-11 14:31:31 -07001297//DeleteAllLogicalPorts is invoked as a callback when the parent device's connection status moves to UNREACHABLE
Kent Hagerman2b216042020-04-03 18:28:56 -04001298func (dMgr *Manager) DeleteAllLogicalPorts(ctx context.Context, parentDevice *voltha.Device) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001299 logger.Debugw(ctx, "delete-all-logical-ports", log.Fields{"parent-device-id": parentDevice.Id})
Girish Gowdra408cd962020-03-11 14:31:31 -07001300 if err := dMgr.logicalDeviceMgr.deleteAllLogicalPorts(ctx, parentDevice); err != nil {
khenaidooe132f522020-03-20 15:23:15 -04001301 // Just log error as logical device may already have been deleted
Rohan Agrawal31f21802020-06-12 05:38:46 +00001302 logger.Warnw(ctx, "delete-all-logical-ports-fail", log.Fields{"parent-device-id": parentDevice.Id, "error": err})
Girish Gowdra408cd962020-03-11 14:31:31 -07001303 }
1304 return nil
1305}
1306
1307//DeleteAllDeviceFlows is invoked as a callback when the parent device's connection status moves to UNREACHABLE
Kent Hagerman2b216042020-04-03 18:28:56 -04001308func (dMgr *Manager) DeleteAllDeviceFlows(ctx context.Context, parentDevice *voltha.Device) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001309 logger.Debugw(ctx, "delete-all-device-flows", log.Fields{"parent-device-id": parentDevice.Id})
Girish Gowdra408cd962020-03-11 14:31:31 -07001310 if agent := dMgr.getDeviceAgent(ctx, parentDevice.Id); agent != nil {
1311 if err := agent.deleteAllFlows(ctx); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +00001312 logger.Errorw(ctx, "error-deleting-all-device-flows", log.Fields{"parent-device-id": parentDevice.Id})
Girish Gowdra408cd962020-03-11 14:31:31 -07001313 return err
1314 }
1315 return nil
1316 }
1317 return status.Errorf(codes.NotFound, "%s", parentDevice.Id)
1318}
1319
khenaidoo4d4802d2018-10-04 21:59:49 -04001320//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 -04001321func (dMgr *Manager) getAllChildDeviceIds(ctx context.Context, parentDevicePorts map[uint32]*voltha.Port) map[string]struct{} {
Himani Chawlab4c25912020-11-12 17:16:38 +05301322 logger.Debug(ctx, "get-all-child-device-ids")
Kent Hagerman2a07b862020-06-19 15:23:07 -04001323 childDeviceIds := make(map[string]struct{}, len(parentDevicePorts))
1324 for _, port := range parentDevicePorts {
1325 for _, peer := range port.Peers {
1326 childDeviceIds[peer.DeviceId] = struct{}{}
khenaidoo92e62c52018-10-03 14:02:54 -04001327 }
1328 }
Kent Hagerman2a07b862020-06-19 15:23:07 -04001329 logger.Debugw(ctx, "returning-getAllChildDeviceIds", log.Fields{"childDeviceIds": childDeviceIds})
1330 return childDeviceIds
khenaidoo92e62c52018-10-03 14:02:54 -04001331}
1332
Kent Hagerman2b216042020-04-03 18:28:56 -04001333//GetAllChildDevices is a helper method to get all the child device IDs from the device passed as parameter
1334func (dMgr *Manager) GetAllChildDevices(ctx context.Context, parentDeviceID string) (*voltha.Devices, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301335 logger.Debugw(ctx, "get-all-child-devices", log.Fields{"parent-device-id": parentDeviceID})
Kent Hagerman2a07b862020-06-19 15:23:07 -04001336 if parentDevicePorts, err := dMgr.listDevicePorts(ctx, parentDeviceID); err == nil {
khenaidoo297cd252019-02-07 22:10:23 -05001337 childDevices := make([]*voltha.Device, 0)
Kent Hagerman2a07b862020-06-19 15:23:07 -04001338 for deviceID := range dMgr.getAllChildDeviceIds(ctx, parentDevicePorts) {
Kent Hagermancba2f302020-07-28 13:37:36 -04001339 if d, e := dMgr.getDeviceReadOnly(ctx, deviceID); e == nil && d != nil {
Kent Hagerman2a07b862020-06-19 15:23:07 -04001340 childDevices = append(childDevices, d)
khenaidoo297cd252019-02-07 22:10:23 -05001341 }
1342 }
1343 return &voltha.Devices{Items: childDevices}, nil
1344 }
npujar1d86a522019-11-14 17:11:16 +05301345 return nil, status.Errorf(codes.NotFound, "%s", parentDeviceID)
khenaidoo297cd252019-02-07 22:10:23 -05001346}
1347
npujar1d86a522019-11-14 17:11:16 +05301348// SetupUNILogicalPorts creates UNI ports on the logical device that represents a child UNI interface
Kent Hagerman2b216042020-04-03 18:28:56 -04001349func (dMgr *Manager) SetupUNILogicalPorts(ctx context.Context, cDevice *voltha.Device) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301350 logger.Info(ctx, "setup-uni-logical-ports")
Kent Hagerman2a07b862020-06-19 15:23:07 -04001351 cDevicePorts, err := dMgr.listDevicePorts(ctx, cDevice.Id)
1352 if err != nil {
1353 return err
1354 }
1355 if err := dMgr.logicalDeviceMgr.setupUNILogicalPorts(ctx, cDevice, cDevicePorts); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +05301356 logger.Warnw(ctx, "setup-uni-logical-ports-error", log.Fields{"device": cDevice, "err": err})
khenaidoob9203542018-09-17 22:56:37 -04001357 return err
1358 }
1359 return nil
1360}
1361
Kent Hagerman45a13e42020-04-13 12:23:50 -04001362// convenience to avoid redefining
1363var operationFailureResp = &common.OperationResp{Code: voltha.OperationResp_OPERATION_FAILURE}
1364
1365// DownloadImage execute an image download request
1366func (dMgr *Manager) DownloadImage(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301367 ctx = utils.WithRPCMetadataContext(ctx, "DownloadImage")
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001368 log.EnrichSpan(ctx, log.Fields{"device-id": img.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +05301369 logger.Debugw(ctx, "download-image", log.Fields{"device-id": img.Id, "image-name": img.Name})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001370 agent := dMgr.getDeviceAgent(ctx, img.Id)
1371 if agent == nil {
1372 return operationFailureResp, status.Errorf(codes.NotFound, "%s", img.Id)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001373 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001374 resp, err := agent.downloadImage(ctx, img)
1375 if err != nil {
1376 return operationFailureResp, err
1377 }
1378 return resp, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001379}
1380
Kent Hagerman45a13e42020-04-13 12:23:50 -04001381// CancelImageDownload cancels image download request
1382func (dMgr *Manager) CancelImageDownload(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301383 ctx = utils.WithRPCMetadataContext(ctx, "CancelImageDownload")
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001384 log.EnrichSpan(ctx, log.Fields{"device-id": img.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +05301385 logger.Debugw(ctx, "cancel-image-download", log.Fields{"device-id": img.Id, "image-name": img.Name})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001386 agent := dMgr.getDeviceAgent(ctx, img.Id)
1387 if agent == nil {
1388 return operationFailureResp, status.Errorf(codes.NotFound, "%s", img.Id)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001389 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001390 resp, err := agent.cancelImageDownload(ctx, img)
1391 if err != nil {
1392 return operationFailureResp, err
1393 }
1394 return resp, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001395}
1396
Kent Hagerman45a13e42020-04-13 12:23:50 -04001397// ActivateImageUpdate activates image update request
1398func (dMgr *Manager) ActivateImageUpdate(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301399 ctx = utils.WithRPCMetadataContext(ctx, "ActivateImageUpdate")
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001400 log.EnrichSpan(ctx, log.Fields{"device-id": img.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +05301401 logger.Debugw(ctx, "activate-image-update", log.Fields{"device-id": img.Id, "image-name": img.Name})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001402 agent := dMgr.getDeviceAgent(ctx, img.Id)
1403 if agent == nil {
1404 return operationFailureResp, status.Errorf(codes.NotFound, "%s", img.Id)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001405 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001406 resp, err := agent.activateImage(ctx, img)
1407 if err != nil {
1408 return operationFailureResp, err
1409 }
1410 return resp, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001411}
1412
Kent Hagerman45a13e42020-04-13 12:23:50 -04001413// RevertImageUpdate reverts image update
1414func (dMgr *Manager) RevertImageUpdate(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301415 ctx = utils.WithRPCMetadataContext(ctx, "RevertImageUpdate")
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001416 log.EnrichSpan(ctx, log.Fields{"device-id": img.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +05301417 logger.Debugw(ctx, "rever-image-update", log.Fields{"device-id": img.Id, "image-name": img.Name})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001418 agent := dMgr.getDeviceAgent(ctx, img.Id)
1419 if agent == nil {
1420 return operationFailureResp, status.Errorf(codes.NotFound, "%s", img.Id)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001421 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001422 resp, err := agent.revertImage(ctx, img)
1423 if err != nil {
1424 return operationFailureResp, err
1425 }
1426 return resp, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001427}
1428
Kent Hagerman45a13e42020-04-13 12:23:50 -04001429// convenience to avoid redefining
1430var imageDownloadFailureResp = &voltha.ImageDownload{DownloadState: voltha.ImageDownload_DOWNLOAD_UNKNOWN}
1431
1432// GetImageDownloadStatus returns status of image download
1433func (dMgr *Manager) GetImageDownloadStatus(ctx context.Context, img *voltha.ImageDownload) (*voltha.ImageDownload, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301434 ctx = utils.WithRPCMetadataContext(ctx, "GetImageDownloadStatus")
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001435 log.EnrichSpan(ctx, log.Fields{"device-id": img.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +05301436 logger.Debugw(ctx, "get-image-download-status", log.Fields{"device-id": img.Id, "image-name": img.Name})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001437 agent := dMgr.getDeviceAgent(ctx, img.Id)
1438 if agent == nil {
1439 return imageDownloadFailureResp, status.Errorf(codes.NotFound, "%s", img.Id)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001440 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001441 resp, err := agent.getImageDownloadStatus(ctx, img)
1442 if err != nil {
1443 return imageDownloadFailureResp, err
1444 }
1445 return resp, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001446}
1447
Kent Hagerman2b216042020-04-03 18:28:56 -04001448func (dMgr *Manager) UpdateImageDownload(ctx context.Context, deviceID string, img *voltha.ImageDownload) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301449 ctx = utils.WithRPCMetadataContext(ctx, "UpdateImageDownload")
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001450 log.EnrichSpan(ctx, log.Fields{"device-id": img.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +05301451 logger.Debugw(ctx, "update-image-download", log.Fields{"device-id": img.Id, "image-name": img.Name})
npujar467fe752020-01-16 20:17:45 +05301452 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
1453 if err := agent.updateImageDownload(ctx, img); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +05301454 logger.Debugw(ctx, "update-image-download-failed", log.Fields{"err": err, "image-name": img.Name})
khenaidoof5a5bfa2019-01-23 22:20:29 -05001455 return err
1456 }
1457 } else {
1458 return status.Errorf(codes.NotFound, "%s", img.Id)
1459 }
1460 return nil
1461}
1462
Kent Hagerman45a13e42020-04-13 12:23:50 -04001463// GetImageDownload returns image download
Kent Hagerman2b216042020-04-03 18:28:56 -04001464func (dMgr *Manager) GetImageDownload(ctx context.Context, img *voltha.ImageDownload) (*voltha.ImageDownload, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301465 ctx = utils.WithRPCMetadataContext(ctx, "GetImageDownload")
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001466 log.EnrichSpan(ctx, log.Fields{"device-id": img.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +05301467 logger.Debugw(ctx, "get-image-download", log.Fields{"device-id": img.Id, "image-name": img.Name})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001468 agent := dMgr.getDeviceAgent(ctx, img.Id)
1469 if agent == nil {
1470 return imageDownloadFailureResp, status.Errorf(codes.NotFound, "%s", img.Id)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001471 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001472 resp, err := agent.getImageDownload(ctx, img)
1473 if err != nil {
1474 return imageDownloadFailureResp, err
1475 }
1476 return resp, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001477}
1478
Kent Hagerman45a13e42020-04-13 12:23:50 -04001479// ListImageDownloads returns image downloads
1480func (dMgr *Manager) ListImageDownloads(ctx context.Context, id *voltha.ID) (*voltha.ImageDownloads, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301481 ctx = utils.WithRPCMetadataContext(ctx, "ListImageDownloads")
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001482 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +05301483 logger.Debugw(ctx, "list-image-downloads", log.Fields{"device-id": id.Id})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001484 agent := dMgr.getDeviceAgent(ctx, id.Id)
1485 if agent == nil {
1486 return &voltha.ImageDownloads{Items: []*voltha.ImageDownload{imageDownloadFailureResp}}, status.Errorf(codes.NotFound, "%s", id.Id)
khenaidoof5a5bfa2019-01-23 22:20:29 -05001487 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001488 resp, err := agent.listImageDownloads(ctx, id.Id)
1489 if err != nil {
1490 return &voltha.ImageDownloads{Items: []*voltha.ImageDownload{imageDownloadFailureResp}}, err
1491 }
1492 return resp, nil
1493}
1494
1495// GetImages returns all images for a specific device entry
1496func (dMgr *Manager) GetImages(ctx context.Context, id *voltha.ID) (*voltha.Images, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301497 ctx = utils.WithRPCMetadataContext(ctx, "GetImages")
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001498 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +05301499 logger.Debugw(ctx, "get-images", log.Fields{"device-id": id.Id})
Kent Hagermancba2f302020-07-28 13:37:36 -04001500 device, err := dMgr.getDeviceReadOnly(ctx, id.Id)
Kent Hagerman45a13e42020-04-13 12:23:50 -04001501 if err != nil {
1502 return nil, err
1503 }
Kent Hagermancba2f302020-07-28 13:37:36 -04001504 return device.Images, nil
khenaidoof5a5bfa2019-01-23 22:20:29 -05001505}
1506
Rohan Agrawal31f21802020-06-12 05:38:46 +00001507func (dMgr *Manager) NotifyInvalidTransition(ctx context.Context, device *voltha.Device) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301508 logger.Errorw(ctx, "notify-invalid-transition", log.Fields{
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001509 "device": device.Id,
1510 "curr-admin-state": device.AdminState,
1511 "curr-oper-state": device.OperStatus,
1512 "curr-conn-state": device.ConnectStatus,
Stephane Barbarieef6650d2019-07-18 12:15:09 -04001513 })
khenaidoo0a822f92019-05-08 15:15:57 -04001514 //TODO: notify over kafka?
1515 return nil
1516}
1517
npujar1d86a522019-11-14 17:11:16 +05301518// UpdateDeviceAttribute updates value of particular device attribute
Kent Hagerman2b216042020-04-03 18:28:56 -04001519func (dMgr *Manager) UpdateDeviceAttribute(ctx context.Context, deviceID string, attribute string, value interface{}) {
npujar1d86a522019-11-14 17:11:16 +05301520 if agent, ok := dMgr.deviceAgents.Load(deviceID); ok {
Kent Hagerman2b216042020-04-03 18:28:56 -04001521 agent.(*Agent).updateDeviceAttribute(ctx, attribute, value)
khenaidoob9203542018-09-17 22:56:37 -04001522 }
1523}
1524
npujar1d86a522019-11-14 17:11:16 +05301525// GetParentDeviceID returns parent device id, either from memory or from the dB, if present
Kent Hagerman2b216042020-04-03 18:28:56 -04001526func (dMgr *Manager) GetParentDeviceID(ctx context.Context, deviceID string) string {
Kent Hagermancba2f302020-07-28 13:37:36 -04001527 if device, _ := dMgr.getDeviceReadOnly(ctx, deviceID); device != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +05301528 logger.Infow(ctx, "get-parent-device-id", log.Fields{"device-id": device.Id, "parent-id": device.ParentId})
khenaidoo4c9e5592019-09-09 16:20:41 -04001529 return device.ParentId
khenaidoob9203542018-09-17 22:56:37 -04001530 }
khenaidoo4c9e5592019-09-09 16:20:41 -04001531 return ""
khenaidoob9203542018-09-17 22:56:37 -04001532}
serkant.uluderya334479d2019-04-10 08:26:15 -07001533
Kent Hagerman45a13e42020-04-13 12:23:50 -04001534func (dMgr *Manager) SimulateAlarm(ctx context.Context, simulateReq *voltha.SimulateAlarmRequest) (*common.OperationResp, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301535 ctx = utils.WithRPCMetadataContext(ctx, "SimulateAlarm")
1536 logger.Debugw(ctx, "simulate-alarm", log.Fields{"id": simulateReq.Id, "indicator": simulateReq.Indicator, "intf-id": simulateReq.IntfId,
1537 "port-type-name": simulateReq.PortTypeName, "onu-device-id": simulateReq.OnuDeviceId, "inverse-bit-error-rate": simulateReq.InverseBitErrorRate,
1538 "drift": simulateReq.Drift, "new-eqd": simulateReq.NewEqd, "onu-serial-number": simulateReq.OnuSerialNumber, "operation": simulateReq.Operation})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001539 agent := dMgr.getDeviceAgent(ctx, simulateReq.Id)
1540 if agent == nil {
1541 return nil, status.Errorf(codes.NotFound, "%s", simulateReq.Id)
serkant.uluderya334479d2019-04-10 08:26:15 -07001542 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001543 if err := agent.simulateAlarm(ctx, simulateReq); err != nil {
1544 return nil, err
1545 }
1546 return &common.OperationResp{Code: common.OperationResp_OPERATION_SUCCESS}, nil
serkant.uluderya334479d2019-04-10 08:26:15 -07001547}
Mahir Gunyelfdee9212019-10-16 16:52:21 -07001548
Kent Hagerman2b216042020-04-03 18:28:56 -04001549func (dMgr *Manager) UpdateDeviceReason(ctx context.Context, deviceID string, reason string) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301550 logger.Debugw(ctx, "update-device-reason", log.Fields{"device-id": deviceID, "reason": reason})
npujar467fe752020-01-16 20:17:45 +05301551 if agent := dMgr.getDeviceAgent(ctx, deviceID); agent != nil {
1552 return agent.updateDeviceReason(ctx, reason)
Mahir Gunyelfdee9212019-10-16 16:52:21 -07001553 }
npujar1d86a522019-11-14 17:11:16 +05301554 return status.Errorf(codes.NotFound, "%s", deviceID)
Mahir Gunyelfdee9212019-10-16 16:52:21 -07001555}
kesavandbc2d1622020-01-21 00:42:01 -05001556
Kent Hagerman45a13e42020-04-13 12:23:50 -04001557func (dMgr *Manager) EnablePort(ctx context.Context, port *voltha.Port) (*empty.Empty, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301558 ctx = utils.WithRPCMetadataContext(ctx, "EnablePort")
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001559 log.EnrichSpan(ctx, log.Fields{"device-id": port.DeviceId})
Himani Chawlab4c25912020-11-12 17:16:38 +05301560 logger.Debugw(ctx, "enable-port", log.Fields{"device-id": port.DeviceId, "port-no": port.PortNo})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001561 agent := dMgr.getDeviceAgent(ctx, port.DeviceId)
1562 if agent == nil {
1563 return nil, status.Errorf(codes.NotFound, "%s", port.DeviceId)
kesavandbc2d1622020-01-21 00:42:01 -05001564 }
Kent Hagerman2a07b862020-06-19 15:23:07 -04001565 return &empty.Empty{}, agent.enablePort(ctx, port.PortNo)
kesavandbc2d1622020-01-21 00:42:01 -05001566}
1567
Kent Hagerman45a13e42020-04-13 12:23:50 -04001568func (dMgr *Manager) DisablePort(ctx context.Context, port *voltha.Port) (*empty.Empty, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301569 ctx = utils.WithRPCMetadataContext(ctx, "DisablePort")
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001570 log.EnrichSpan(ctx, log.Fields{"device-id": port.DeviceId})
Himani Chawlab4c25912020-11-12 17:16:38 +05301571 logger.Debugw(ctx, "disable-port", log.Fields{"device-id": port.DeviceId, "port-no": port.PortNo})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001572 agent := dMgr.getDeviceAgent(ctx, port.DeviceId)
1573 if agent == nil {
1574 return nil, status.Errorf(codes.NotFound, "%s", port.DeviceId)
kesavandbc2d1622020-01-21 00:42:01 -05001575 }
Kent Hagerman2a07b862020-06-19 15:23:07 -04001576 return &empty.Empty{}, agent.disablePort(ctx, port.PortNo)
kesavandbc2d1622020-01-21 00:42:01 -05001577}
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001578
Kent Hagerman2b216042020-04-03 18:28:56 -04001579// ChildDeviceLost calls parent adapter to delete child device and all its references
1580func (dMgr *Manager) ChildDeviceLost(ctx context.Context, curr *voltha.Device) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301581 logger.Debugw(ctx, "child-device-lost", log.Fields{"child-device-id": curr.Id, "parent-device-id": curr.ParentId})
khenaidoo442e7c72020-03-10 16:13:48 -04001582 if parentAgent := dMgr.getDeviceAgent(ctx, curr.ParentId); parentAgent != nil {
khenaidooe132f522020-03-20 15:23:15 -04001583 if err := parentAgent.ChildDeviceLost(ctx, curr); err != nil {
1584 // Just log the message and let the remaining pipeline proceed.
Rohan Agrawal31f21802020-06-12 05:38:46 +00001585 logger.Warnw(ctx, "childDeviceLost", log.Fields{"child-device-id": curr.Id, "parent-device-id": curr.ParentId, "error": err})
khenaidooe132f522020-03-20 15:23:15 -04001586 }
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001587 }
khenaidooe132f522020-03-20 15:23:15 -04001588 // Do not return an error as parent device may also have been deleted. Let the remaining pipeline proceed.
1589 return nil
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001590}
onkarkundargi87285252020-01-27 11:34:52 +05301591
Kent Hagerman45a13e42020-04-13 12:23:50 -04001592func (dMgr *Manager) StartOmciTestAction(ctx context.Context, request *voltha.OmciTestRequest) (*voltha.TestResponse, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301593 ctx = utils.WithRPCMetadataContext(ctx, "StartOmciTestAction")
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001594 log.EnrichSpan(ctx, log.Fields{"device-id": request.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +05301595 logger.Debugw(ctx, "start-omci-test-action", log.Fields{"device-id": request.Id, "uuid": request.Uuid})
Kent Hagerman45a13e42020-04-13 12:23:50 -04001596 agent := dMgr.getDeviceAgent(ctx, request.Id)
1597 if agent == nil {
1598 return nil, status.Errorf(codes.NotFound, "%s", request.Id)
onkarkundargi87285252020-01-27 11:34:52 +05301599 }
Kent Hagerman45a13e42020-04-13 12:23:50 -04001600 return agent.startOmciTest(ctx, request)
onkarkundargi87285252020-01-27 11:34:52 +05301601}
Dinesh Belwalkarc1129f12020-02-27 10:41:33 -08001602
1603func (dMgr *Manager) GetExtValue(ctx context.Context, value *voltha.ValueSpecifier) (*voltha.ReturnValues, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301604 ctx = utils.WithRPCMetadataContext(ctx, "GetExtValue")
Rohan Agrawalcf12f202020-08-03 04:42:01 +00001605 log.EnrichSpan(ctx, log.Fields{"device-id": value.Id})
Himani Chawlab4c25912020-11-12 17:16:38 +05301606 logger.Debugw(ctx, "get-ext-value", log.Fields{"onu-id": value.Id})
Kent Hagermancba2f302020-07-28 13:37:36 -04001607 cDevice, err := dMgr.getDeviceReadOnly(ctx, value.Id)
Dinesh Belwalkarc1129f12020-02-27 10:41:33 -08001608 if err != nil {
1609 return nil, status.Errorf(codes.Aborted, "%s", err.Error())
1610 }
Kent Hagermancba2f302020-07-28 13:37:36 -04001611 pDevice, err := dMgr.getDeviceReadOnly(ctx, cDevice.ParentId)
Dinesh Belwalkarc1129f12020-02-27 10:41:33 -08001612 if err != nil {
1613 return nil, status.Errorf(codes.Aborted, "%s", err.Error())
1614 }
1615 if agent := dMgr.getDeviceAgent(ctx, cDevice.ParentId); agent != nil {
1616 resp, err := agent.getExtValue(ctx, pDevice, cDevice, value)
1617 if err != nil {
1618 return nil, err
1619 }
Himani Chawlab4c25912020-11-12 17:16:38 +05301620 logger.Debugw(ctx, "get-ext-value-result", log.Fields{"result": resp})
Dinesh Belwalkarc1129f12020-02-27 10:41:33 -08001621 return resp, nil
1622 }
1623 return nil, status.Errorf(codes.NotFound, "%s", value.Id)
1624
1625}
dpaul62686312020-06-23 14:17:36 +05301626
1627// SetExtValue set some given configs or value
1628func (dMgr *Manager) SetExtValue(ctx context.Context, value *voltha.ValueSet) (*empty.Empty, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301629 ctx = utils.WithRPCMetadataContext(ctx, "SetExtValue")
1630 logger.Debugw(ctx, "set-ext-value", log.Fields{"onu-id": value.Id})
dpaul62686312020-06-23 14:17:36 +05301631 device, err := dMgr.getDeviceReadOnly(ctx, value.Id)
1632 if err != nil {
1633 return nil, status.Errorf(codes.Aborted, "%s", err.Error())
1634 }
1635 if agent := dMgr.getDeviceAgent(ctx, device.Id); agent != nil {
1636 resp, err := agent.setExtValue(ctx, device, value)
1637 if err != nil {
1638 return nil, err
1639 }
Himani Chawlab4c25912020-11-12 17:16:38 +05301640 logger.Debugw(ctx, "set-ext-value-result", log.Fields{"result": resp})
dpaul62686312020-06-23 14:17:36 +05301641 return resp, nil
1642 }
1643 return nil, status.Errorf(codes.NotFound, "%s", value.Id)
1644
1645}
Himani Chawlab4c25912020-11-12 17:16:38 +05301646
1647func (dMgr *Manager) SendRPCEvent(ctx context.Context, id string, rpcEvent *voltha.RPCEvent,
1648 category voltha.EventCategory_Types, subCategory *voltha.EventSubCategory_Types, raisedTs int64) {
1649 //TODO Instead of directly sending to the kafka bus, queue the message and send it asynchronously
1650 dMgr.RPCEventManager.SendRPCEvent(ctx, id, rpcEvent, category, subCategory, raisedTs)
1651}