khenaidoo | d948f77 | 2021-08-11 17:49:24 -0400 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2021-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 | */ |
| 16 | package device |
| 17 | |
| 18 | import ( |
| 19 | "context" |
khenaidoo | a46458b | 2021-12-15 16:50:44 -0500 | [diff] [blame] | 20 | "fmt" |
| 21 | "time" |
khenaidoo | d948f77 | 2021-08-11 17:49:24 -0400 | [diff] [blame] | 22 | |
| 23 | "github.com/golang/protobuf/ptypes/empty" |
| 24 | "github.com/opencord/voltha-go/rw_core/utils" |
| 25 | "github.com/opencord/voltha-lib-go/v7/pkg/log" |
| 26 | "github.com/opencord/voltha-protos/v5/go/common" |
khenaidoo | 9beaaf1 | 2021-10-19 17:32:01 -0400 | [diff] [blame] | 27 | ca "github.com/opencord/voltha-protos/v5/go/core_adapter" |
khenaidoo | a46458b | 2021-12-15 16:50:44 -0500 | [diff] [blame] | 28 | "github.com/opencord/voltha-protos/v5/go/core_service" |
khenaidoo | 25057da | 2021-12-08 14:40:45 -0500 | [diff] [blame] | 29 | "github.com/opencord/voltha-protos/v5/go/health" |
khenaidoo | d948f77 | 2021-08-11 17:49:24 -0400 | [diff] [blame] | 30 | "github.com/opencord/voltha-protos/v5/go/voltha" |
| 31 | "google.golang.org/grpc/codes" |
| 32 | "google.golang.org/grpc/status" |
| 33 | ) |
| 34 | |
| 35 | func (dMgr *Manager) PortCreated(ctx context.Context, port *voltha.Port) (*empty.Empty, error) { |
| 36 | ctx = utils.WithNewSpanAndRPCMetadataContext(ctx, "PortCreated") |
| 37 | |
| 38 | logger.Debugw(ctx, "port-created", log.Fields{"port": port}) |
| 39 | |
| 40 | agent := dMgr.getDeviceAgent(ctx, port.DeviceId) |
| 41 | if agent != nil { |
| 42 | if err := agent.addPort(ctx, port); err != nil { |
| 43 | return nil, err |
| 44 | } |
| 45 | // Setup peer ports in its own routine |
| 46 | go func() { |
| 47 | if err := dMgr.addPeerPort(log.WithSpanFromContext(context.Background(), ctx), port.DeviceId, port); err != nil { |
| 48 | logger.Errorw(ctx, "unable-to-add-peer-port", log.Fields{"error": err, "device-id": port.DeviceId}) |
| 49 | } |
| 50 | }() |
| 51 | return &empty.Empty{}, nil |
| 52 | } |
| 53 | return nil, status.Errorf(codes.NotFound, "%s", port.DeviceId) |
| 54 | } |
| 55 | |
| 56 | func (dMgr *Manager) DeviceUpdate(ctx context.Context, device *voltha.Device) (*empty.Empty, error) { |
| 57 | ctx = utils.WithNewSpanAndRPCMetadataContext(ctx, "DeviceUpdate") |
| 58 | logger.Debugw(ctx, "device-update", log.Fields{"device-id": device.Id, "device": device}) |
| 59 | |
| 60 | if agent := dMgr.getDeviceAgent(ctx, device.Id); agent != nil { |
| 61 | if err := agent.updateDeviceUsingAdapterData(ctx, device); err != nil { |
| 62 | return nil, err |
| 63 | } |
| 64 | return &empty.Empty{}, nil |
| 65 | } |
| 66 | return nil, status.Errorf(codes.NotFound, "%s", device.Id) |
| 67 | } |
| 68 | |
khenaidoo | 9beaaf1 | 2021-10-19 17:32:01 -0400 | [diff] [blame] | 69 | func (dMgr *Manager) DeviceStateUpdate(ctx context.Context, ds *ca.DeviceStateFilter) (*empty.Empty, error) { |
khenaidoo | d948f77 | 2021-08-11 17:49:24 -0400 | [diff] [blame] | 70 | ctx = utils.WithNewSpanAndRPCMetadataContext(ctx, "DeviceStateUpdate") |
| 71 | logger.Debugw(ctx, "device-state-update", log.Fields{"device-id": ds.DeviceId, "operStatus": ds.OperStatus, "connStatus": ds.ConnStatus}) |
| 72 | |
| 73 | if agent := dMgr.getDeviceAgent(ctx, ds.DeviceId); agent != nil { |
| 74 | if err := agent.updateDeviceStatus(ctx, ds.OperStatus, ds.ConnStatus); err != nil { |
| 75 | return nil, err |
| 76 | } |
| 77 | return &empty.Empty{}, nil |
| 78 | } |
| 79 | return nil, status.Errorf(codes.NotFound, "%s", ds.DeviceId) |
| 80 | } |
| 81 | |
khenaidoo | 9beaaf1 | 2021-10-19 17:32:01 -0400 | [diff] [blame] | 82 | func (dMgr *Manager) ChildDeviceDetected(ctx context.Context, dd *ca.DeviceDiscovery) (*voltha.Device, error) { |
khenaidoo | d948f77 | 2021-08-11 17:49:24 -0400 | [diff] [blame] | 83 | ctx = utils.WithNewSpanAndRPCMetadataContext(ctx, "ChildDeviceDetected") |
| 84 | logger.Debugw(ctx, "child-device-detected", |
| 85 | log.Fields{ |
| 86 | "parent-device-id": dd.ParentId, |
| 87 | "parentPortNo": dd.ParentPortNo, |
| 88 | "deviceType": dd.ChildDeviceType, |
| 89 | "channelId": dd.ChannelId, |
| 90 | "vendorId": dd.VendorId, |
| 91 | "serialNumber": dd.SerialNumber, |
| 92 | "onuId": dd.OnuId, |
| 93 | }) |
| 94 | |
| 95 | var err error |
| 96 | if dd.ChildDeviceType == "" && dd.VendorId != "" { |
| 97 | logger.Debug(ctx, "device-type-is-nil-fetching-device-type") |
| 98 | if dd.ChildDeviceType, err = dMgr.adapterMgr.GetAdapterTypeByVendorID(dd.VendorId); err != nil { |
| 99 | return nil, err |
| 100 | } |
| 101 | } |
| 102 | //if no match found for the vendorid,report adapter with the custom error message |
| 103 | if dd.ChildDeviceType == "" { |
| 104 | logger.Errorw(ctx, "failed-to-fetch-adapter-name ", log.Fields{"vendorId": dd.VendorId}) |
| 105 | return nil, status.Errorf(codes.NotFound, "%s", dd.VendorId) |
| 106 | } |
| 107 | |
| 108 | // Create the ONU device |
| 109 | childDevice := &voltha.Device{} |
| 110 | childDevice.Type = dd.ChildDeviceType |
| 111 | childDevice.ParentId = dd.ParentId |
| 112 | childDevice.ParentPortNo = uint32(dd.ParentPortNo) |
| 113 | childDevice.VendorId = dd.VendorId |
| 114 | childDevice.SerialNumber = dd.SerialNumber |
| 115 | childDevice.Root = false |
| 116 | |
| 117 | // Get parent device type |
| 118 | pAgent := dMgr.getDeviceAgent(ctx, dd.ParentId) |
| 119 | if pAgent == nil { |
| 120 | return nil, status.Errorf(codes.NotFound, "%s", dd.ParentId) |
| 121 | } |
| 122 | if pAgent.deviceType == "" { |
| 123 | pDevice, err := pAgent.getDeviceReadOnly(ctx) |
| 124 | logger.Errorw(ctx, "device-type-not-set", log.Fields{"parent-device": pDevice, "error": err}) |
| 125 | return nil, status.Errorf(codes.FailedPrecondition, "device Type not set %s", dd.ParentId) |
| 126 | } |
| 127 | |
khenaidoo | 9beaaf1 | 2021-10-19 17:32:01 -0400 | [diff] [blame] | 128 | if device, err := dMgr.GetChildDevice(ctx, &ca.ChildDeviceFilter{ |
khenaidoo | d948f77 | 2021-08-11 17:49:24 -0400 | [diff] [blame] | 129 | ParentId: dd.ParentId, |
| 130 | SerialNumber: dd.SerialNumber, |
| 131 | OnuId: dd.OnuId, |
| 132 | ParentPortNo: dd.ParentPortNo}); err == nil { |
| 133 | logger.Warnw(ctx, "child-device-exists", log.Fields{"parent-device-id": dd.ParentId, "serialNumber": dd.SerialNumber}) |
| 134 | return device, status.Errorf(codes.AlreadyExists, "%s", dd.SerialNumber) |
| 135 | } |
| 136 | |
| 137 | //Get parent endpoint |
| 138 | pEndPoint, err := dMgr.adapterMgr.GetAdapterEndpoint(ctx, pAgent.deviceID, pAgent.deviceType) |
| 139 | if err != nil { |
| 140 | logger.Errorw(ctx, "endpoint-error", log.Fields{"error": err, "parent-id": pAgent.deviceID, "parent-device-type": pAgent.deviceType}) |
| 141 | return nil, status.Errorf(codes.NotFound, "parent-endpoint-%s", dd.ParentId) |
| 142 | } |
| 143 | |
| 144 | childDevice.ProxyAddress = &voltha.Device_ProxyAddress{DeviceId: dd.ParentId, DeviceType: pAgent.deviceType, ChannelId: dd.ChannelId, OnuId: dd.OnuId, AdapterEndpoint: pEndPoint} |
| 145 | |
| 146 | // Set child device ID -- needed to get the device endpoint |
| 147 | childDevice.Id = utils.CreateDeviceID() |
| 148 | |
| 149 | // Set the child adapter endpoint |
| 150 | childDevice.AdapterEndpoint, err = dMgr.adapterMgr.GetAdapterEndpoint(ctx, childDevice.Id, childDevice.Type) |
| 151 | if err != nil { |
| 152 | return nil, status.Errorf(codes.NotFound, "child-endpoint-%s", childDevice.Id) |
| 153 | } |
| 154 | |
| 155 | // Create and start a device agent for that device |
Himani Chawla | 4b4bd25 | 2021-11-08 15:59:40 +0530 | [diff] [blame] | 156 | agent := newAgent(childDevice, dMgr, dMgr.dbPath, dMgr.dProxy, dMgr.internalTimeout, dMgr.rpcTimeout, dMgr.flowTimeout) |
khenaidoo | d948f77 | 2021-08-11 17:49:24 -0400 | [diff] [blame] | 157 | insertedChildDevice, err := agent.start(ctx, false, childDevice) |
| 158 | if err != nil { |
| 159 | logger.Errorw(ctx, "error-starting-child-device", log.Fields{"parent-device-id": childDevice.ParentId, "child-device-id": agent.deviceID, "error": err}) |
| 160 | return nil, err |
| 161 | } |
| 162 | dMgr.addDeviceAgentToMap(agent) |
| 163 | |
| 164 | // Activate the child device |
| 165 | if agent = dMgr.getDeviceAgent(ctx, agent.deviceID); agent != nil { |
| 166 | go func() { |
| 167 | err := agent.enableDevice(utils.WithSpanAndRPCMetadataFromContext(ctx)) |
| 168 | if err != nil { |
| 169 | logger.Errorw(ctx, "unable-to-enable-device", log.Fields{"error": err, "device-id": agent.deviceID}) |
| 170 | } |
| 171 | }() |
| 172 | } |
| 173 | |
| 174 | return insertedChildDevice, nil |
| 175 | } |
| 176 | |
khenaidoo | 9beaaf1 | 2021-10-19 17:32:01 -0400 | [diff] [blame] | 177 | func (dMgr *Manager) GetChildDevice(ctx context.Context, df *ca.ChildDeviceFilter) (*voltha.Device, error) { |
khenaidoo | d948f77 | 2021-08-11 17:49:24 -0400 | [diff] [blame] | 178 | ctx = utils.WithNewSpanAndRPCMetadataContext(ctx, "GetChildDevice") |
| 179 | logger.Debugw(ctx, "get-child-device", log.Fields{"filter": df}) |
| 180 | |
| 181 | parentDevicePorts, err := dMgr.listDevicePorts(ctx, df.ParentId) |
| 182 | if err != nil { |
| 183 | return nil, status.Errorf(codes.Aborted, "%s", err.Error()) |
| 184 | } |
| 185 | childDeviceIds := dMgr.getAllChildDeviceIds(ctx, parentDevicePorts) |
| 186 | if len(childDeviceIds) == 0 { |
| 187 | logger.Debugw(ctx, "no-child-devices", log.Fields{"parent-device-id": df.ParentId, "serial-number": df.SerialNumber, "onu-id": df.OnuId}) |
| 188 | return nil, status.Errorf(codes.NotFound, "%s", df.ParentId) |
| 189 | } |
| 190 | |
| 191 | var foundChildDevice *voltha.Device |
| 192 | for childDeviceID := range childDeviceIds { |
| 193 | var found bool |
| 194 | if searchDevice, err := dMgr.getDeviceReadOnly(ctx, childDeviceID); err == nil { |
| 195 | |
| 196 | foundOnuID := false |
| 197 | if searchDevice.ProxyAddress.OnuId == uint32(df.OnuId) { |
| 198 | if searchDevice.ParentPortNo == uint32(df.ParentPortNo) { |
| 199 | logger.Debugw(ctx, "found-child-by-onu-id", log.Fields{"parent-device-id": df.ParentId, "onuId": df.OnuId}) |
| 200 | foundOnuID = true |
| 201 | } |
| 202 | } |
| 203 | |
| 204 | foundSerialNumber := false |
| 205 | if searchDevice.SerialNumber == df.SerialNumber { |
| 206 | logger.Debugw(ctx, "found-child-by-serial-number", log.Fields{"parent-device-id": df.ParentId, "serialNumber": df.SerialNumber}) |
| 207 | foundSerialNumber = true |
| 208 | } |
| 209 | |
| 210 | // if both onuId and serialNumber are provided both must be true for the device to be found |
| 211 | // otherwise whichever one found a match is good enough |
| 212 | if df.OnuId > 0 && df.SerialNumber != "" { |
| 213 | found = foundOnuID && foundSerialNumber |
| 214 | } else { |
| 215 | found = foundOnuID || foundSerialNumber |
| 216 | } |
| 217 | |
| 218 | if found { |
| 219 | foundChildDevice = searchDevice |
| 220 | break |
| 221 | } |
| 222 | } |
| 223 | } |
| 224 | |
| 225 | if foundChildDevice != nil { |
| 226 | logger.Debugw(ctx, "child-device-found", log.Fields{"parent-device-id": df.ParentId, "foundChildDevice": foundChildDevice}) |
| 227 | return foundChildDevice, nil |
| 228 | } |
| 229 | |
| 230 | logger.Debugw(ctx, "child-device-not-found", log.Fields{"parent-device-id": df.ParentId, |
| 231 | "serialNumber": df.SerialNumber, "onuId": df.OnuId, "parentPortNo": df.ParentPortNo}) |
| 232 | return nil, status.Errorf(codes.NotFound, "%s", df.ParentId) |
| 233 | } |
| 234 | |
| 235 | // PortsStateUpdate updates the operational status of all ports on the device |
khenaidoo | 9beaaf1 | 2021-10-19 17:32:01 -0400 | [diff] [blame] | 236 | func (dMgr *Manager) PortsStateUpdate(ctx context.Context, ps *ca.PortStateFilter) (*empty.Empty, error) { |
khenaidoo | d948f77 | 2021-08-11 17:49:24 -0400 | [diff] [blame] | 237 | ctx = utils.WithNewSpanAndRPCMetadataContext(ctx, "PortsStateUpdate") |
| 238 | logger.Debugw(ctx, "ports-state-update", log.Fields{"device-id": ps.DeviceId}) |
| 239 | |
| 240 | agent := dMgr.getDeviceAgent(ctx, ps.DeviceId) |
| 241 | if agent == nil { |
| 242 | return nil, status.Errorf(codes.NotFound, "%s", ps.DeviceId) |
| 243 | } |
| 244 | if ps.OperStatus != voltha.OperStatus_ACTIVE && ps.OperStatus != voltha.OperStatus_UNKNOWN { |
| 245 | return nil, status.Error(codes.Unimplemented, "state-change-not-implemented") |
| 246 | } |
| 247 | if err := agent.updatePortsOperState(ctx, ps.PortTypeFilter, ps.OperStatus); err != nil { |
| 248 | logger.Warnw(ctx, "ports-state-update-failed", log.Fields{"device-id": ps.DeviceId, "error": err}) |
| 249 | return nil, err |
| 250 | } |
| 251 | return &empty.Empty{}, nil |
| 252 | } |
| 253 | |
| 254 | //ChildDevicesLost is invoked by an adapter to indicate that a parent device is in a state (Disabled) where it |
| 255 | //cannot manage the child devices. This will trigger the Core to disable all the child devices. |
| 256 | func (dMgr *Manager) ChildDevicesLost(ctx context.Context, parentID *common.ID) (*empty.Empty, error) { |
| 257 | ctx = utils.WithNewSpanAndRPCMetadataContext(ctx, "ChildDevicesLost") |
| 258 | logger.Debugw(ctx, "child-devices-lost", log.Fields{"parent-id": parentID.Id}) |
| 259 | |
| 260 | parentDevice, err := dMgr.getDeviceReadOnly(ctx, parentID.Id) |
| 261 | if err != nil { |
| 262 | logger.Warnw(ctx, "failed-getting-device", log.Fields{"parent-device-id": parentID.Id, "error": err}) |
| 263 | return nil, err |
| 264 | } |
| 265 | if err = dMgr.DisableAllChildDevices(ctx, parentDevice); err != nil { |
| 266 | return nil, err |
| 267 | } |
| 268 | return &empty.Empty{}, nil |
| 269 | } |
| 270 | |
| 271 | //ChildDevicesDetected is invoked by an adapter when child devices are found, typically after after a |
| 272 | // disable/enable sequence. This will trigger the Core to Enable all the child devices of that parent. |
| 273 | func (dMgr *Manager) ChildDevicesDetected(ctx context.Context, parentDeviceID *common.ID) (*empty.Empty, error) { |
| 274 | ctx = utils.WithNewSpanAndRPCMetadataContext(ctx, "ChildDevicesDetected") |
| 275 | logger.Debugw(ctx, "child-devices-detected", log.Fields{"parent-device-id": parentDeviceID}) |
| 276 | |
| 277 | parentDevicePorts, err := dMgr.listDevicePorts(ctx, parentDeviceID.Id) |
| 278 | if err != nil { |
| 279 | logger.Warnw(ctx, "failed-getting-device", log.Fields{"device-id": parentDeviceID.Id, "error": err}) |
| 280 | return nil, err |
| 281 | } |
| 282 | childDeviceIds := dMgr.getAllChildDeviceIds(ctx, parentDevicePorts) |
| 283 | if len(childDeviceIds) == 0 { |
| 284 | logger.Debugw(ctx, "no-child-device", log.Fields{"parent-device-id": parentDeviceID.Id}) |
| 285 | } |
| 286 | allChildEnableRequestSent := true |
| 287 | for childDeviceID := range childDeviceIds { |
| 288 | if agent := dMgr.getDeviceAgent(ctx, childDeviceID); agent != nil { |
| 289 | // Run the children re-registration in its own routine |
| 290 | go func(ctx context.Context) { |
| 291 | err = agent.enableDevice(ctx) |
| 292 | if err != nil { |
| 293 | logger.Errorw(ctx, "unable-to-enable-device", log.Fields{"error": err}) |
| 294 | } |
| 295 | }(log.WithSpanFromContext(context.Background(), ctx)) |
| 296 | } else { |
| 297 | err = status.Errorf(codes.Unavailable, "no agent for child device %s", childDeviceID) |
| 298 | logger.Errorw(ctx, "no-child-device-agent", log.Fields{"parent-device-id": parentDeviceID.Id, "childId": childDeviceID}) |
| 299 | allChildEnableRequestSent = false |
| 300 | } |
| 301 | } |
| 302 | if !allChildEnableRequestSent { |
| 303 | return nil, err |
| 304 | } |
| 305 | return &empty.Empty{}, nil |
| 306 | } |
| 307 | |
| 308 | // GetChildDeviceWithProxyAddress will return a device based on proxy address |
| 309 | func (dMgr *Manager) GetChildDeviceWithProxyAddress(ctx context.Context, proxyAddress *voltha.Device_ProxyAddress) (*voltha.Device, error) { |
| 310 | ctx = utils.WithNewSpanAndRPCMetadataContext(ctx, "GetChildDeviceWithProxyAddress") |
| 311 | |
| 312 | logger.Debugw(ctx, "get-child-device-with-proxy-address", log.Fields{"proxyAddress": proxyAddress}) |
| 313 | |
| 314 | parentDevicePorts, err := dMgr.listDevicePorts(ctx, proxyAddress.DeviceId) |
| 315 | if err != nil { |
| 316 | return nil, status.Errorf(codes.Aborted, "%s", err.Error()) |
| 317 | } |
| 318 | childDeviceIds := dMgr.getAllChildDeviceIds(ctx, parentDevicePorts) |
| 319 | if len(childDeviceIds) == 0 { |
| 320 | logger.Debugw(ctx, "no-child-devices", log.Fields{"parent-device-id": proxyAddress.DeviceId}) |
| 321 | return nil, status.Errorf(codes.NotFound, "%s", proxyAddress) |
| 322 | } |
| 323 | |
| 324 | var foundChildDevice *voltha.Device |
| 325 | for childDeviceID := range childDeviceIds { |
| 326 | if searchDevice, err := dMgr.getDeviceReadOnly(ctx, childDeviceID); err == nil { |
| 327 | if searchDevice.ProxyAddress == proxyAddress { |
| 328 | foundChildDevice = searchDevice |
| 329 | break |
| 330 | } |
| 331 | } |
| 332 | } |
| 333 | |
| 334 | if foundChildDevice != nil { |
| 335 | logger.Debugw(ctx, "child-device-found", log.Fields{"proxyAddress": proxyAddress}) |
| 336 | return foundChildDevice, nil |
| 337 | } |
| 338 | |
| 339 | logger.Warnw(ctx, "child-device-not-found", log.Fields{"proxyAddress": proxyAddress}) |
| 340 | return nil, status.Errorf(codes.NotFound, "%s", proxyAddress) |
| 341 | } |
| 342 | |
khenaidoo | 9beaaf1 | 2021-10-19 17:32:01 -0400 | [diff] [blame] | 343 | func (dMgr *Manager) GetPorts(ctx context.Context, pf *ca.PortFilter) (*voltha.Ports, error) { |
khenaidoo | d948f77 | 2021-08-11 17:49:24 -0400 | [diff] [blame] | 344 | ctx = utils.WithNewSpanAndRPCMetadataContext(ctx, "GetPorts") |
| 345 | logger.Debugw(ctx, "get-ports", log.Fields{"device-id": pf.DeviceId, "portType": pf.PortType}) |
| 346 | |
| 347 | agent := dMgr.getDeviceAgent(ctx, pf.DeviceId) |
| 348 | if agent == nil { |
| 349 | return nil, status.Errorf(codes.NotFound, "%s", pf.DeviceId) |
| 350 | } |
| 351 | return agent.getPorts(ctx, pf.PortType), nil |
| 352 | } |
| 353 | |
| 354 | func (dMgr *Manager) GetChildDevices(ctx context.Context, parentDeviceID *common.ID) (*voltha.Devices, error) { |
| 355 | ctx = utils.WithNewSpanAndRPCMetadataContext(ctx, "GetChildDevices") |
| 356 | |
| 357 | logger.Debugw(ctx, "get-child-devices", log.Fields{"parent-device-id": parentDeviceID.Id}) |
| 358 | return dMgr.getAllChildDevices(ctx, parentDeviceID.Id) |
| 359 | } |
| 360 | |
khenaidoo | 9beaaf1 | 2021-10-19 17:32:01 -0400 | [diff] [blame] | 361 | func (dMgr *Manager) ChildrenStateUpdate(ctx context.Context, ds *ca.DeviceStateFilter) (*empty.Empty, error) { |
khenaidoo | d948f77 | 2021-08-11 17:49:24 -0400 | [diff] [blame] | 362 | ctx = utils.WithNewSpanAndRPCMetadataContext(ctx, "ChildrenStateUpdate") |
| 363 | logger.Debugw(ctx, "children-state-update", log.Fields{"parent-device-id": ds.ParentDeviceId, "operStatus": ds.OperStatus, "connStatus": ds.ConnStatus}) |
| 364 | |
| 365 | parentDevicePorts, err := dMgr.listDevicePorts(ctx, ds.ParentDeviceId) |
| 366 | if err != nil { |
| 367 | return nil, status.Errorf(codes.Aborted, "%s", err.Error()) |
| 368 | } |
| 369 | for childDeviceID := range dMgr.getAllChildDeviceIds(ctx, parentDevicePorts) { |
| 370 | if agent := dMgr.getDeviceAgent(ctx, childDeviceID); agent != nil { |
| 371 | if err = agent.updateDeviceStatus(ctx, ds.OperStatus, ds.ConnStatus); err != nil { |
| 372 | return nil, status.Errorf(codes.Aborted, "childDevice:%s, error:%s", childDeviceID, err.Error()) |
| 373 | } |
| 374 | } |
| 375 | } |
| 376 | return &empty.Empty{}, nil |
| 377 | } |
| 378 | |
khenaidoo | 9beaaf1 | 2021-10-19 17:32:01 -0400 | [diff] [blame] | 379 | func (dMgr *Manager) PortStateUpdate(ctx context.Context, ps *ca.PortState) (*empty.Empty, error) { |
khenaidoo | d948f77 | 2021-08-11 17:49:24 -0400 | [diff] [blame] | 380 | ctx = utils.WithNewSpanAndRPCMetadataContext(ctx, "PortStateUpdate") |
| 381 | logger.Debugw(ctx, "port-state-update", log.Fields{"device-id": ps.DeviceId, "portType": ps.PortType, "portNo": ps.PortNo, "operStatus": ps.OperStatus}) |
| 382 | |
| 383 | if agent := dMgr.getDeviceAgent(ctx, ps.DeviceId); agent != nil { |
| 384 | if err := agent.updatePortState(ctx, ps.PortType, ps.PortNo, ps.OperStatus); err != nil { |
| 385 | logger.Errorw(ctx, "updating-port-state-failed", log.Fields{"device-id": ps.DeviceId, "portNo": ps.PortNo, "error": err}) |
| 386 | return nil, err |
| 387 | } |
| 388 | // Notify the logical device manager to change the port state |
| 389 | // Do this for NNI and UNIs only. PON ports are not known by logical device |
| 390 | if ps.PortType == voltha.Port_ETHERNET_NNI || ps.PortType == voltha.Port_ETHERNET_UNI { |
| 391 | go func() { |
| 392 | err := dMgr.logicalDeviceMgr.updatePortState(log.WithSpanFromContext(context.Background(), ctx), ps.DeviceId, ps.PortNo, ps.OperStatus) |
| 393 | if err != nil { |
| 394 | // While we want to handle (catch) and log when |
| 395 | // an update to a port was not able to be |
| 396 | // propagated to the logical port, we can report |
| 397 | // it as a warning and not an error because it |
| 398 | // doesn't stop or modify processing. |
| 399 | // TODO: VOL-2707 |
| 400 | logger.Warnw(ctx, "unable-to-update-logical-port-state", log.Fields{"error": err}) |
| 401 | } |
| 402 | }() |
| 403 | } |
| 404 | return &empty.Empty{}, nil |
| 405 | } |
| 406 | return nil, status.Errorf(codes.NotFound, "%s", ps.DeviceId) |
| 407 | } |
| 408 | |
| 409 | func (dMgr *Manager) DeleteAllPorts(ctx context.Context, deviceID *common.ID) (*empty.Empty, error) { |
| 410 | ctx = utils.WithNewSpanAndRPCMetadataContext(ctx, "DeleteAllPorts") |
| 411 | logger.Debugw(ctx, "delete-all-ports", log.Fields{"device-id": deviceID.Id}) |
| 412 | |
| 413 | if agent := dMgr.getDeviceAgent(ctx, deviceID.Id); agent != nil { |
| 414 | if err := agent.deleteAllPorts(ctx); err != nil { |
| 415 | return nil, err |
| 416 | } |
| 417 | // Notify the logical device manager to remove all logical ports, if needed. |
| 418 | // At this stage the device itself may gave been deleted already at a DeleteAllPorts |
| 419 | // typically is part of a device deletion phase. |
| 420 | if device, err := dMgr.getDeviceReadOnly(ctx, deviceID.Id); err == nil { |
| 421 | go func() { |
| 422 | subCtx := utils.WithSpanAndRPCMetadataFromContext(ctx) |
| 423 | if err := dMgr.logicalDeviceMgr.deleteAllLogicalPorts(subCtx, device); err != nil { |
| 424 | logger.Errorw(ctx, "unable-to-delete-logical-ports", log.Fields{"error": err}) |
| 425 | } |
| 426 | }() |
| 427 | } else { |
| 428 | logger.Warnw(ctx, "failed-to-retrieve-device", log.Fields{"device-id": deviceID.Id}) |
| 429 | return nil, err |
| 430 | } |
| 431 | return &empty.Empty{}, nil |
| 432 | } |
| 433 | return nil, status.Errorf(codes.NotFound, "%s", deviceID.Id) |
| 434 | } |
| 435 | |
| 436 | // GetDevicePort returns the port details for a specific device port entry |
khenaidoo | 9beaaf1 | 2021-10-19 17:32:01 -0400 | [diff] [blame] | 437 | func (dMgr *Manager) GetDevicePort(ctx context.Context, pf *ca.PortFilter) (*voltha.Port, error) { |
khenaidoo | d948f77 | 2021-08-11 17:49:24 -0400 | [diff] [blame] | 438 | ctx = utils.WithNewSpanAndRPCMetadataContext(ctx, "GetDevicePort") |
| 439 | logger.Debugw(ctx, "get-device-port", log.Fields{"device-id": pf.DeviceId}) |
| 440 | |
| 441 | agent := dMgr.getDeviceAgent(ctx, pf.DeviceId) |
| 442 | if agent == nil { |
| 443 | return nil, status.Errorf(codes.NotFound, "device-%s", pf.DeviceId) |
| 444 | } |
| 445 | return agent.getDevicePort(pf.Port) |
| 446 | } |
| 447 | |
| 448 | // DevicePMConfigUpdate updates the pm configs as defined by the adapter. |
| 449 | func (dMgr *Manager) DevicePMConfigUpdate(ctx context.Context, pc *voltha.PmConfigs) (*empty.Empty, error) { |
| 450 | ctx = utils.WithNewSpanAndRPCMetadataContext(ctx, "DevicePMConfigUpdate") |
| 451 | logger.Debugw(ctx, "device-pm-config-update", log.Fields{"device-id": pc.Id}) |
| 452 | |
| 453 | if pc.Id == "" { |
| 454 | return nil, status.Errorf(codes.FailedPrecondition, "invalid-device-Id") |
| 455 | } |
| 456 | if agent := dMgr.getDeviceAgent(ctx, pc.Id); agent != nil { |
| 457 | if err := agent.initPmConfigs(ctx, pc); err != nil { |
| 458 | return nil, err |
| 459 | } |
| 460 | return &empty.Empty{}, nil |
| 461 | } |
| 462 | return nil, status.Errorf(codes.NotFound, "%s", pc.Id) |
| 463 | } |
| 464 | |
| 465 | // SendPacketIn receives packetIn request from adapter |
khenaidoo | 9beaaf1 | 2021-10-19 17:32:01 -0400 | [diff] [blame] | 466 | func (dMgr *Manager) SendPacketIn(ctx context.Context, pi *ca.PacketIn) (*empty.Empty, error) { |
khenaidoo | d948f77 | 2021-08-11 17:49:24 -0400 | [diff] [blame] | 467 | ctx = utils.WithNewSpanAndRPCMetadataContext(ctx, "SendPacketIn") |
| 468 | logger.Debugw(ctx, "packet-in", log.Fields{"device-id": pi.DeviceId, "port": pi.Port}) |
| 469 | |
| 470 | // Get the logical device Id based on the deviceId |
| 471 | var device *voltha.Device |
| 472 | var err error |
| 473 | if device, err = dMgr.getDeviceReadOnly(ctx, pi.DeviceId); err != nil { |
| 474 | logger.Errorw(ctx, "device-not-found", log.Fields{"device-id": pi.DeviceId}) |
| 475 | return nil, err |
| 476 | } |
| 477 | if !device.Root { |
| 478 | logger.Errorw(ctx, "device-not-root", log.Fields{"device-id": pi.DeviceId}) |
| 479 | return nil, status.Errorf(codes.FailedPrecondition, "%s", pi.DeviceId) |
| 480 | } |
| 481 | |
| 482 | if err := dMgr.logicalDeviceMgr.packetIn(ctx, device.ParentId, pi.Port, pi.Packet); err != nil { |
| 483 | return nil, err |
| 484 | } |
| 485 | return &empty.Empty{}, nil |
| 486 | } |
| 487 | |
khenaidoo | 9beaaf1 | 2021-10-19 17:32:01 -0400 | [diff] [blame] | 488 | func (dMgr *Manager) DeviceReasonUpdate(ctx context.Context, dr *ca.DeviceReason) (*empty.Empty, error) { |
khenaidoo | d948f77 | 2021-08-11 17:49:24 -0400 | [diff] [blame] | 489 | ctx = utils.WithNewSpanAndRPCMetadataContext(ctx, "DeviceReasonUpdate") |
| 490 | logger.Debugw(ctx, "update-device-reason", log.Fields{"device-id": dr.DeviceId, "reason": dr.Reason}) |
| 491 | |
| 492 | if agent := dMgr.getDeviceAgent(ctx, dr.DeviceId); agent != nil { |
| 493 | if err := agent.updateDeviceReason(ctx, dr.Reason); err != nil { |
| 494 | return nil, err |
| 495 | } |
| 496 | return &empty.Empty{}, nil |
| 497 | } |
| 498 | return nil, status.Errorf(codes.NotFound, "%s", dr.DeviceId) |
| 499 | } |
| 500 | |
| 501 | func (dMgr *Manager) ReconcileChildDevices(ctx context.Context, parentDeviceID *common.ID) (*empty.Empty, error) { |
| 502 | ctx = utils.WithNewSpanAndRPCMetadataContext(ctx, "ReconcileChildDevices") |
| 503 | logger.Debugw(ctx, "reconcile-child-devices", log.Fields{"device-id": parentDeviceID.Id}) |
| 504 | |
| 505 | numberOfDevicesToReconcile := 0 |
| 506 | dMgr.deviceAgents.Range(func(key, value interface{}) bool { |
| 507 | deviceAgent, ok := value.(*Agent) |
| 508 | if ok && deviceAgent.parentID == parentDeviceID.Id { |
| 509 | go deviceAgent.ReconcileDevice(utils.WithNewSpanAndRPCMetadataContext(ctx, "ReconcileChildDevices")) |
| 510 | numberOfDevicesToReconcile++ |
| 511 | } |
| 512 | return true |
| 513 | }) |
| 514 | logger.Debugw(ctx, "reconciling-child-devices-initiated", log.Fields{"parent-device-id": parentDeviceID.Id, "number-of-child-devices-to-reconcile": numberOfDevicesToReconcile}) |
| 515 | return &empty.Empty{}, nil |
| 516 | } |
| 517 | |
| 518 | func (dMgr *Manager) UpdateImageDownload(ctx context.Context, img *voltha.ImageDownload) (*empty.Empty, error) { |
| 519 | ctx = utils.WithNewSpanAndRPCMetadataContext(ctx, "UpdateImageDownload") |
| 520 | log.EnrichSpan(ctx, log.Fields{"device-id": img.Id}) |
| 521 | |
| 522 | logger.Debugw(ctx, "update-image-download", log.Fields{"device-id": img.Id, "image-name": img.Name}) |
| 523 | |
| 524 | if agent := dMgr.getDeviceAgent(ctx, img.Id); agent != nil { |
| 525 | if err := agent.updateImageDownload(ctx, img); err != nil { |
| 526 | logger.Debugw(ctx, "update-image-download-failed", log.Fields{"err": err, "image-name": img.Name}) |
| 527 | return nil, err |
| 528 | } |
| 529 | } else { |
| 530 | return nil, status.Errorf(codes.NotFound, "%s", img.Id) |
| 531 | } |
| 532 | return &empty.Empty{}, nil |
| 533 | } |
khenaidoo | a46458b | 2021-12-15 16:50:44 -0500 | [diff] [blame] | 534 | |
| 535 | func (dMgr *Manager) GetHealthStatus(stream core_service.CoreService_GetHealthStatusServer) error { |
| 536 | ctx := utils.WithRPCMetadataContext(context.Background(), "keep-alive-connection") |
| 537 | logger.Debugw(ctx, "receive-stream-connection", log.Fields{"stream": stream}) |
| 538 | |
| 539 | if stream == nil { |
| 540 | return fmt.Errorf("conn-is-nil %v", stream) |
| 541 | } |
| 542 | initialRequestTime := time.Now() |
| 543 | var remoteClient *common.Connection |
| 544 | var tempClient *common.Connection |
| 545 | var err error |
| 546 | loop: |
| 547 | for { |
| 548 | tempClient, err = stream.Recv() |
| 549 | if err != nil { |
| 550 | logger.Warnw(ctx, "received-stream-error", log.Fields{"remote-client": remoteClient, "error": err}) |
Girish Gowdra | 11ddb23 | 2022-05-26 12:19:59 -0700 | [diff] [blame] | 551 | dMgr.adapterMgr.SignalOnRxStreamCloseCh(ctx, remoteClient.Endpoint) |
khenaidoo | a46458b | 2021-12-15 16:50:44 -0500 | [diff] [blame] | 552 | break loop |
| 553 | } |
| 554 | // Send a response back |
| 555 | err = stream.Send(&health.HealthStatus{State: health.HealthStatus_HEALTHY}) |
| 556 | if err != nil { |
| 557 | logger.Warnw(ctx, "sending-stream-error", log.Fields{"remote-client": remoteClient, "error": err}) |
Girish Gowdra | 11ddb23 | 2022-05-26 12:19:59 -0700 | [diff] [blame] | 558 | dMgr.adapterMgr.SignalOnRxStreamCloseCh(ctx, remoteClient.Endpoint) |
khenaidoo | a46458b | 2021-12-15 16:50:44 -0500 | [diff] [blame] | 559 | break loop |
| 560 | } |
| 561 | |
| 562 | remoteClient = tempClient |
| 563 | logger.Debugw(ctx, "received-keep-alive", log.Fields{"remote-client": remoteClient}) |
| 564 | |
| 565 | select { |
| 566 | case <-stream.Context().Done(): |
| 567 | logger.Infow(ctx, "stream-keep-alive-context-done", log.Fields{"remote-client": remoteClient, "error": stream.Context().Err()}) |
| 568 | break loop |
| 569 | case <-dMgr.doneCh: |
| 570 | logger.Warnw(ctx, "received-stop", log.Fields{"remote-client": remoteClient, "initial-conn-time": initialRequestTime}) |
| 571 | break loop |
| 572 | default: |
| 573 | } |
| 574 | } |
| 575 | logger.Errorw(ctx, "connection-down", log.Fields{"remote-client": remoteClient, "error": err, "initial-conn-time": initialRequestTime}) |
| 576 | return err |
| 577 | } |