blob: 5b8cc1b8895af638835b6b47673e814bd727abaf [file] [log] [blame]
/*
* Copyright 2019-present Open Networking Foundation
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package mocks
import (
"context"
"fmt"
"strconv"
"strings"
"sync"
"time"
"github.com/golang/protobuf/ptypes/empty"
vgrpc "github.com/opencord/voltha-lib-go/v7/pkg/grpc"
"github.com/opencord/voltha-lib-go/v7/pkg/log"
"github.com/opencord/voltha-lib-go/v7/pkg/probe"
"github.com/opencord/voltha-protos/v5/go/adapter_service"
"github.com/opencord/voltha-protos/v5/go/common"
"github.com/opencord/voltha-protos/v5/go/core_service"
"github.com/opencord/voltha-protos/v5/go/health"
"google.golang.org/grpc"
ca "github.com/opencord/voltha-protos/v5/go/core_adapter"
"github.com/opencord/voltha-protos/v5/go/extension"
"github.com/opencord/voltha-protos/v5/go/omci"
"github.com/opencord/voltha-protos/v5/go/openflow_13"
"github.com/opencord/voltha-protos/v5/go/voltha"
)
const (
numONUPerOLT = 4
startingUNIPortNo = 100
)
func macAddressToUint32Array(mac string) []uint32 {
slist := strings.Split(mac, ":")
result := make([]uint32, len(slist))
var err error
var tmp int64
for index, val := range slist {
if tmp, err = strconv.ParseInt(val, 16, 32); err != nil {
return []uint32{1, 2, 3, 4, 5, 6}
}
result[index] = uint32(tmp)
}
return result
}
// GetNumONUPerOLT returns number of ONUs per OLT
func GetNumONUPerOLT() int {
return numONUPerOLT
}
// Returns the starting UNI port number
func GetStartingUNIPortNo() int {
return startingUNIPortNo
}
// Adapter represents adapter attributes
type Adapter struct {
flows map[string]map[uint64]*openflow_13.OfpFlowStats
flowLock sync.RWMutex
devices map[string]*voltha.Device
deviceLock sync.RWMutex
failFlowAdd map[string]bool
failFlowAddLock sync.RWMutex
failFlowDelete map[string]bool
failFlowDeleteLock sync.RWMutex
failDeleteDevice map[string]bool
failDeleteDeviceLock sync.RWMutex
coreEnpoint string
coreClient *vgrpc.Client
serviceEndpoint string
DeviceType string
vendor string
Probe *probe.Probe
}
// NewAdapter creates adapter instance
func NewAdapter(serviceEndpoint, coreEndpoint, deviceType, vendor string) *Adapter {
return &Adapter{
flows: map[string]map[uint64]*openflow_13.OfpFlowStats{},
devices: map[string]*voltha.Device{},
failFlowAdd: map[string]bool{},
failFlowDelete: map[string]bool{},
failDeleteDevice: map[string]bool{},
coreEnpoint: coreEndpoint,
serviceEndpoint: serviceEndpoint,
DeviceType: deviceType,
vendor: vendor,
}
}
func (ta *Adapter) IsReady() bool {
return ta.Probe.IsReady()
}
func (ta *Adapter) storeDevice(d *voltha.Device) {
ta.deviceLock.Lock()
defer ta.deviceLock.Unlock()
if d != nil {
ta.devices[d.Id] = d
}
}
func (ta *Adapter) getDevice(id string) *voltha.Device {
ta.deviceLock.RLock()
defer ta.deviceLock.RUnlock()
return ta.devices[id]
}
func (ta *Adapter) updateDevice(d *voltha.Device) {
ta.storeDevice(d)
}
func (ta *Adapter) GetEndPoint() string {
return ta.serviceEndpoint
}
func (ta *Adapter) GetCoreClient() (core_service.CoreServiceClient, error) {
// Wait until the Core is up and running
for {
if ta.coreClient != nil {
client, err := ta.coreClient.GetClient()
if err != nil {
logger.Infow(context.Background(), "got-error-core-client", log.Fields{"error": err})
time.Sleep(1 * time.Second)
continue
}
c, ok := client.(core_service.CoreServiceClient)
if ok {
logger.Debug(context.Background(), "got-valid-client")
return c, nil
}
}
logger.Info(context.Background(), "waiting-for-grpc-core-client")
time.Sleep(1 * time.Second)
}
}
// Helper methods
// startGRPCService creates the grpc service handlers, registers it to the grpc server and starts the server
func (ta *Adapter) startGRPCService(ctx context.Context, server *vgrpc.GrpcServer, handler adapter_service.AdapterServiceServer, serviceName string) {
logger.Infow(ctx, "service-created", log.Fields{"service": serviceName})
server.AddService(func(gs *grpc.Server) { adapter_service.RegisterAdapterServiceServer(gs, handler) })
logger.Infow(ctx, "service-added", log.Fields{"service": serviceName})
ta.Probe.UpdateStatus(ctx, serviceName, probe.ServiceStatusRunning)
logger.Infow(ctx, "service-started", log.Fields{"service": serviceName})
// Note that there is a small window here in which the core could return its status as ready,
// when it really isn't. This is unlikely to cause issues, as the delay is incredibly short.
server.Start(ctx)
ta.Probe.UpdateStatus(ctx, serviceName, probe.ServiceStatusStopped)
}
func setAndTestCoreServiceHandler(ctx context.Context, conn *grpc.ClientConn) interface{} {
svc := core_service.NewCoreServiceClient(conn)
if h, err := svc.GetHealthStatus(ctx, &empty.Empty{}); err != nil || h.State != health.HealthStatus_HEALTHY {
return nil
}
return svc
}
// gRPC service
func (ta *Adapter) GetHealthStatus(ctx context.Context, empty *empty.Empty) (*health.HealthStatus, error) {
return &health.HealthStatus{State: health.HealthStatus_HEALTHY}, nil
}
// Device
func (ta *Adapter) AdoptDevice(ctx context.Context, device *voltha.Device) (*empty.Empty, error) {
return &empty.Empty{}, nil
}
func (ta *Adapter) ReconcileDevice(ctx context.Context, device *voltha.Device) (*empty.Empty, error) {
return &empty.Empty{}, nil
}
func (ta *Adapter) DeleteDevice(ctx context.Context, device *voltha.Device) (*empty.Empty, error) {
ta.failDeleteDeviceLock.RLock()
haveToFail, ok := ta.failDeleteDevice[device.Id]
if ok && haveToFail {
ta.failDeleteDeviceLock.RUnlock()
return nil, fmt.Errorf("delete-device-failure")
}
ta.failDeleteDeviceLock.RUnlock()
if ok {
ta.RemoveDevice(device.Id)
}
logger.Debugw(ctx, "device-deleted-in-adapter", log.Fields{"device-id": device.Id})
return &empty.Empty{}, nil
}
func (ta *Adapter) DisableDevice(ctx context.Context, device *voltha.Device) (*empty.Empty, error) {
return &empty.Empty{}, nil
}
func (ta *Adapter) ReEnableDevice(ctx context.Context, device *voltha.Device) (*empty.Empty, error) {
return &empty.Empty{}, nil
}
func (ta *Adapter) RebootDevice(ctx context.Context, device *voltha.Device) (*empty.Empty, error) {
return &empty.Empty{}, nil
}
func (ta *Adapter) SelfTestDevice(ctx context.Context, device *voltha.Device) (*empty.Empty, error) {
return &empty.Empty{}, nil
}
func (ta *Adapter) ChildDeviceLost(ctx context.Context, device *voltha.Device) (*empty.Empty, error) {
return &empty.Empty{}, nil
}
func (ta *Adapter) GetOfpDeviceInfo(ctx context.Context, device *voltha.Device) (*ca.SwitchCapability, error) {
return nil, nil
}
// Ports
func (ta *Adapter) EnablePort(ctx context.Context, port *voltha.Port) (*empty.Empty, error) {
return &empty.Empty{}, nil
}
func (ta *Adapter) DisablePort(ctx context.Context, port *voltha.Port) (*empty.Empty, error) {
return &empty.Empty{}, nil
}
// Flows
func (ta *Adapter) UpdateFlowsBulk(ctx context.Context, flows *ca.BulkFlows) (*empty.Empty, error) {
return &empty.Empty{}, nil
}
func (ta *Adapter) UpdateFlowsIncrementally(ctx context.Context, incrFlows *ca.IncrementalFlows) (*empty.Empty, error) {
ta.flowLock.Lock()
defer ta.flowLock.Unlock()
if _, ok := ta.flows[incrFlows.Device.Id]; !ok {
ta.flows[incrFlows.Device.Id] = map[uint64]*openflow_13.OfpFlowStats{}
}
if incrFlows.Flows.ToAdd != nil && len(incrFlows.Flows.ToAdd.Items) > 0 {
ta.failFlowAddLock.RLock()
if haveToFail, ok := ta.failFlowAdd[incrFlows.Device.Id]; ok && haveToFail {
ta.failFlowAddLock.RUnlock()
return nil, fmt.Errorf("flow-add-error")
}
ta.failFlowAddLock.RUnlock()
for _, f := range incrFlows.Flows.ToAdd.Items {
ta.flows[incrFlows.Device.Id][f.Id] = f
}
}
if incrFlows.Flows.ToRemove != nil && len(incrFlows.Flows.ToRemove.Items) > 0 {
ta.failFlowDeleteLock.RLock()
if haveToFail, ok := ta.failFlowDelete[incrFlows.Device.Id]; ok && haveToFail {
ta.failFlowDeleteLock.RUnlock()
return nil, fmt.Errorf("flow-delete-error")
}
ta.failFlowDeleteLock.RUnlock()
for _, f := range incrFlows.Flows.ToRemove.Items {
delete(ta.flows[incrFlows.Device.Id], f.Id)
}
}
return &empty.Empty{}, nil
}
//Packets
func (ta *Adapter) SendPacketOut(ctx context.Context, packet *ca.PacketOut) (*empty.Empty, error) {
return &empty.Empty{}, nil
}
// PM
func (ta *Adapter) UpdatePmConfig(ctx context.Context, configs *ca.PmConfigsInfo) (*empty.Empty, error) {
return &empty.Empty{}, nil
}
// Image
func (ta *Adapter) DownloadOnuImage(ctx context.Context, request *voltha.DeviceImageDownloadRequest) (*voltha.DeviceImageResponse, error) {
return &voltha.DeviceImageResponse{}, nil
}
func (ta *Adapter) GetOnuImageStatus(ctx context.Context, request *voltha.DeviceImageRequest) (*voltha.DeviceImageResponse, error) {
return &voltha.DeviceImageResponse{}, nil
}
func (ta *Adapter) AbortOnuImageUpgrade(ctx context.Context, request *voltha.DeviceImageRequest) (*voltha.DeviceImageResponse, error) {
return &voltha.DeviceImageResponse{}, nil
}
func (ta *Adapter) GetOnuImages(ctx context.Context, id *common.ID) (*voltha.OnuImages, error) {
return &voltha.OnuImages{}, nil
}
func (ta *Adapter) ActivateOnuImage(ctx context.Context, request *voltha.DeviceImageRequest) (*voltha.DeviceImageResponse, error) {
return &voltha.DeviceImageResponse{}, nil
}
func (ta *Adapter) CommitOnuImage(ctx context.Context, request *voltha.DeviceImageRequest) (*voltha.DeviceImageResponse, error) {
return &voltha.DeviceImageResponse{}, nil
}
// Deprecated image APIs
func (ta *Adapter) DownloadImage(ctx context.Context, in *ca.ImageDownloadMessage) (*voltha.ImageDownload, error) {
return &voltha.ImageDownload{}, nil
}
func (ta *Adapter) GetImageDownloadStatus(ctx context.Context, in *ca.ImageDownloadMessage) (*voltha.ImageDownload, error) {
return &voltha.ImageDownload{}, nil
}
func (ta *Adapter) CancelImageDownload(ctx context.Context, in *ca.ImageDownloadMessage) (*voltha.ImageDownload, error) {
return &voltha.ImageDownload{}, nil
}
func (ta *Adapter) ActivateImageUpdate(ctx context.Context, in *ca.ImageDownloadMessage) (*voltha.ImageDownload, error) {
return &voltha.ImageDownload{}, nil
}
func (ta *Adapter) RevertImageUpdate(ctx context.Context, in *ca.ImageDownloadMessage) (*voltha.ImageDownload, error) {
return &voltha.ImageDownload{}, nil
}
// OMCI test
func (ta *Adapter) StartOmciTest(ctx context.Context, test *ca.OMCITest) (*omci.TestResponse, error) {
return nil, nil
}
// Events
func (ta *Adapter) SuppressEvent(ctx context.Context, filter *voltha.EventFilter) (*empty.Empty, error) {
return &empty.Empty{}, nil
}
func (ta *Adapter) UnSuppressEvent(ctx context.Context, filter *voltha.EventFilter) (*empty.Empty, error) {
return &empty.Empty{}, nil
}
func (ta *Adapter) SimulateAlarm(context.Context, *ca.SimulateAlarmMessage) (*common.OperationResp, error) {
return &common.OperationResp{}, nil
}
func (ta *Adapter) GetExtValue(context.Context, *ca.GetExtValueMessage) (*extension.ReturnValues, error) {
return &extension.ReturnValues{}, nil
}
func (ta *Adapter) SetExtValue(context.Context, *ca.SetExtValueMessage) (*empty.Empty, error) {
return &empty.Empty{}, nil
}
func (ta *Adapter) GetSingleValue(context.Context, *extension.SingleGetValueRequest) (*extension.SingleGetValueResponse, error) {
return &extension.SingleGetValueResponse{}, nil
}
func (ta *Adapter) SetSingleValue(context.Context, *extension.SingleSetValueRequest) (*extension.SingleSetValueResponse, error) {
return &extension.SingleSetValueResponse{}, nil
}
// APIs for test ONLY
// GetFlowCount returns the total number of flows presently under this adapter
func (ta *Adapter) GetFlowCount(deviceID string) int {
ta.flowLock.RLock()
defer ta.flowLock.RUnlock()
if _, ok := ta.flows[deviceID]; ok {
return len(ta.flows[deviceID])
}
return 0
}
// RemoveDevice removes all flows in this adapter
func (ta *Adapter) RemoveDevice(deviceID string) {
ta.flowLock.Lock()
defer ta.flowLock.Unlock()
ta.failFlowAddLock.Lock()
defer ta.failFlowAddLock.Unlock()
ta.failFlowDeleteLock.Lock()
defer ta.failFlowDeleteLock.Unlock()
delete(ta.flows, deviceID)
delete(ta.failFlowAdd, deviceID)
delete(ta.failFlowDelete, deviceID)
}
// SetFlowAction sets the adapter action on addition and deletion of flows
func (ta *Adapter) SetFlowAction(deviceID string, failFlowAdd, failFlowDelete bool) {
ta.failFlowAddLock.Lock()
defer ta.failFlowAddLock.Unlock()
ta.failFlowDeleteLock.Lock()
defer ta.failFlowDeleteLock.Unlock()
ta.failFlowAdd[deviceID] = failFlowAdd
ta.failFlowDelete[deviceID] = failFlowDelete
}
// SetDeleteAction sets the adapter action on delete device
func (ta *Adapter) SetDeleteAction(deviceID string, failDeleteDevice bool) {
ta.failDeleteDeviceLock.Lock()
defer ta.failDeleteDeviceLock.Unlock()
ta.failDeleteDevice[deviceID] = failDeleteDevice
}