blob: f06248464327a94fbe2c441fb58d18bb2ebf1825 [file] [log] [blame]
/*
* Copyright 2018-2024 Open Networking Foundation (ONF) and the ONF Contributors
* 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 dmiserver
import (
"context"
"fmt"
"github.com/opencord/bbsim/api/bbsim"
"github.com/opencord/bbsim/internal/bbsim/devices"
dmi "github.com/opencord/device-management-interface/go/dmi"
log "github.com/sirupsen/logrus"
"google.golang.org/grpc/codes"
"google.golang.org/protobuf/types/known/timestamppb"
)
const (
ponInterfaceType = "pon"
alarmStatusRaise = "on"
alarmStatusClear = "off"
)
type Transceiver struct {
ID uint32
Uuid string
Name string
Pons []*devices.PonPort
Technology dmi.TransceiverType
//Setting this bool will prevent the transceiver
//from being plugged out while already out, and
//plugged in while already in, but won't prevent
//the associated PONs from being enabled in other
//ways while the transceiver is plugged out
PluggedIn bool
}
func newTransceiver(id uint32, pons []*devices.PonPort) *Transceiver {
return &Transceiver{
ID: id,
Uuid: getTransceiverUUID(id).Uuid,
Name: getTransceiverName(id),
Pons: pons,
Technology: dmi.TransceiverType_TYPE_UNDEFINED,
PluggedIn: true,
}
}
func getTransceiverWithId(transId uint32, dms *DmiAPIServer) (*Transceiver, error) {
for _, t := range dms.Transceivers {
if t.ID == transId {
return t, nil
}
}
return nil, fmt.Errorf("Cannot find transceiver with ID %d", transId)
}
/////// Handler methods for grpc API
func (s DmiAPIServer) GetTransceivers(ctx context.Context, req *bbsim.DmiEmpty) (*bbsim.Transceivers, error) {
res := &bbsim.Transceivers{
Items: []*bbsim.Transceiver{},
}
for _, t := range s.Transceivers {
item := bbsim.Transceiver{
ID: t.ID,
UUID: t.Uuid,
Name: t.Name,
Technology: t.Technology.String(),
PluggedIn: t.PluggedIn,
PonIds: []uint32{},
}
for _, pon := range t.Pons {
item.PonIds = append(item.PonIds, pon.ID)
}
res.Items = append(res.Items, &item)
}
return res, nil
}
// PlugOutTransceiver plugs out the transceiver by its ID
func (s DmiAPIServer) PlugOutTransceiver(ctx context.Context, req *bbsim.TransceiverRequest) (*bbsim.DmiResponse, error) {
logger.WithFields(log.Fields{
"IntfId": req.TransceiverId,
}).Infof("Received request to plug out PON transceiver")
res := &bbsim.DmiResponse{}
olt := devices.GetOLT()
//Generate DMI event
dmiServ, err := getDmiAPIServer()
if err != nil {
res.StatusCode = int32(codes.Unavailable)
res.Message = fmt.Sprintf("Cannot get DMI server instance: %v", err)
return res, nil
}
trans, err := getTransceiverWithId(req.TransceiverId, dmiServ)
if err != nil {
res.StatusCode = int32(codes.NotFound)
res.Message = fmt.Sprintf("Cannot find transceiver with ID %d: %v", req.TransceiverId, err)
return res, nil
}
if !trans.PluggedIn {
res.StatusCode = int32(codes.Aborted)
res.Message = fmt.Sprintf("Cannot plug out transceiver with ID %d since it's not plugged in", req.TransceiverId)
return res, nil
}
err = PlugoutTransceiverComponent(req.TransceiverId, dmiServ)
if err != nil {
res.StatusCode = int32(codes.NotFound)
res.Message = fmt.Sprintf("Cannot remove transceiver with ID %d: %v", req.TransceiverId, err)
return res, nil
}
logger.Debug("Removed transceiver from DMI inventory")
if olt.InternalState.Is(devices.OltInternalStateEnabled) {
logger.Debug("Sending alarms for transceiver plug out")
for _, pon := range trans.Pons {
if pon.InternalState.Is("enabled") {
if err = olt.SetAlarm(pon.ID, ponInterfaceType, alarmStatusRaise); err != nil {
logger.WithFields(log.Fields{
"ponId": pon.ID,
"err": err,
}).Error("Cannot raise LOS alarm for PON")
}
if err = pon.InternalState.Event("disable"); err != nil {
logger.WithFields(log.Fields{
"ponId": pon.ID,
"err": err,
}).Error("Cannot disable PON")
continue
}
for _, onu := range pon.Onus {
if err := onu.SetAlarm(bbsim.AlarmType_ONU_ALARM_LOS.String(), alarmStatusRaise); err != nil {
logger.WithFields(log.Fields{
"ponId": pon.ID,
"onuId": onu.ID,
"err": err,
}).Error("Cannot raise LOS alarm for ONU")
}
}
}
}
} else {
logger.Debug("No operation on devices since the OLT is not enabled")
}
event := dmi.Event{
EventId: dmi.EventIds_EVENT_TRANSCEIVER_PLUG_OUT,
EventMetadata: &dmi.EventMetaData{
DeviceUuid: dmiServ.uuid,
ComponentUuid: &dmi.Uuid{
Uuid: trans.Uuid,
},
ComponentName: trans.Name,
},
RaisedTs: timestamppb.Now(),
}
sendOutEventOnKafka(event, dmiServ)
logger.Debug("Transceiver plug out event sent")
res.StatusCode = int32(codes.OK)
res.Message = fmt.Sprintf("Plugged out transceiver %d", req.TransceiverId)
return res, nil
}
// PlugInTransceiver plugs in the transceiver by its ID
func (s DmiAPIServer) PlugInTransceiver(ctx context.Context, req *bbsim.TransceiverRequest) (*bbsim.DmiResponse, error) {
logger.WithFields(log.Fields{
"IntfId": req.TransceiverId,
}).Infof("Received request to plug in PON transceiver")
res := &bbsim.DmiResponse{}
olt := devices.GetOLT()
//Generate DMI event
dmiServ, err := getDmiAPIServer()
if err != nil {
res.StatusCode = int32(codes.Unavailable)
res.Message = fmt.Sprintf("Cannot get DMI server instance: %v", err)
return res, nil
}
trans, err := getTransceiverWithId(req.TransceiverId, dmiServ)
if err != nil {
res.StatusCode = int32(codes.NotFound)
res.Message = fmt.Sprintf("Cannot find transceiver with ID %d: %v", req.TransceiverId, err)
return res, nil
}
if trans.PluggedIn {
res.StatusCode = int32(codes.Aborted)
res.Message = fmt.Sprintf("Cannot plug in transceiver with ID %d since it's already plugged in", req.TransceiverId)
return res, nil
}
err = PluginTransceiverComponent(req.TransceiverId, dmiServ)
if err != nil {
res.StatusCode = int32(codes.NotFound)
res.Message = fmt.Sprintf("Cannot add transceiver with ID %d: %v", req.TransceiverId, err)
return res, nil
}
logger.Debug("Added transceiver to DMI inventory")
if olt.InternalState.Is(devices.OltInternalStateEnabled) {
logger.Debug("Sending alarms for transceiver plug in")
for _, pon := range trans.Pons {
if err = olt.SetAlarm(pon.ID, ponInterfaceType, alarmStatusClear); err != nil {
logger.WithFields(log.Fields{
"ponId": pon.ID,
"err": err,
}).Error("Cannot clear LOS alarm for ONU")
}
if err = pon.InternalState.Event("enable"); err != nil {
logger.WithFields(log.Fields{
"ponId": pon.ID,
"err": err,
}).Error("Cannot enable PON")
continue
}
for _, onu := range pon.Onus {
if err := onu.SetAlarm(bbsim.AlarmType_ONU_ALARM_LOS.String(), alarmStatusClear); err != nil {
logger.WithFields(log.Fields{
"ponId": pon.ID,
"onuId": onu.ID,
"err": err,
}).Error("Cannot clear LOS alarm for ONU")
}
}
}
} else {
logger.Debug("No operation on devices since the OLT is not enabled")
}
event := dmi.Event{
EventId: dmi.EventIds_EVENT_TRANSCEIVER_PLUG_IN,
EventMetadata: &dmi.EventMetaData{
DeviceUuid: dmiServ.uuid,
ComponentUuid: &dmi.Uuid{
Uuid: trans.Uuid,
},
ComponentName: trans.Name,
},
RaisedTs: timestamppb.Now(),
}
sendOutEventOnKafka(event, dmiServ)
logger.Debug("Transceiver plug in event sent")
res.StatusCode = int32(codes.OK)
res.Message = fmt.Sprintf("Plugged in transceiver %d", req.TransceiverId)
return res, nil
}