blob: 8435af1d16cd4b987df79be27988dcd99486de50 [file] [log] [blame]
package devices
import (
"context"
"errors"
"fmt"
"gerrit.opencord.org/bbsim/api"
"github.com/looplab/fsm"
log "github.com/sirupsen/logrus"
"google.golang.org/grpc"
"net"
"sync"
)
func init() {
//log.SetReportCaller(true)
log.SetLevel(log.DebugLevel)
}
func CreateOLT(seq int, nni int, pon int, onuPerPon int) OltDevice {
log.WithFields(log.Fields{
"ID": seq,
"NumNni":nni,
"NumPon":pon,
"NumOnuPerPon":onuPerPon,
}).Debug("CreateOLT")
olt := OltDevice{
ID: seq,
NumNni:nni,
NumPon:pon,
NumOnuPerPon:onuPerPon,
Pons: []PonPort{},
Nnis: []NniPort{},
channel: make(chan interface{}, 32),
}
// OLT State machine
olt.InternalState = fsm.NewFSM(
"created",
fsm.Events{
{Name: "enable", Src: []string{"created"}, Dst: "enabled"},
{Name: "disable", Src: []string{"enabled"}, Dst: "disabled"},
},
fsm.Callbacks{
"enter_state": func(e *fsm.Event) {
olt.stateChange(e)
},
},
)
// create NNI Port
nniPort := NniPort{
ID: uint32(0),
OperState: DOWN,
Type: "nni",
}
olt.Nnis = append(olt.Nnis, nniPort)
// create PON ports
for i := 0; i < pon; i++ {
p := PonPort{
NumOnu: olt.NumOnuPerPon,
ID: uint32(i),
OperState: DOWN,
Type: "pon",
}
// create ONU devices
for j := 0; j < onuPerPon; j++ {
o := CreateONU(olt, p, uint32(j + 1))
p.Onus = append(p.Onus, o)
}
olt.Pons = append(olt.Pons, p)
}
wg := sync.WaitGroup{}
wg.Add(1)
go newOltServer(olt)
wg.Wait()
return olt
}
func newOltServer(o OltDevice) error {
// TODO make configurable
address := "0.0.0.0:50060"
log.Debugf("OLT Listening on: %v", address)
lis, err := net.Listen("tcp", address)
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
grpcServer := grpc.NewServer()
openolt.RegisterOpenoltServer(grpcServer, o)
go grpcServer.Serve(lis)
return nil
}
// Device Methods
func (o OltDevice) Enable (stream openolt.Openolt_EnableIndicationServer) error {
wg := sync.WaitGroup{}
wg.Add(1)
// create a channel for all the OLT events
go o.oltChannels(stream)
// enable the OLT
olt_msg := Message{
Type: OltIndication,
Data: OltIndicationMessage{
OperState: UP,
},
}
o.channel <- olt_msg
// send NNI Port Indications
for _, nni := range o.Nnis {
msg := Message{
Type: NniIndication,
Data: NniIndicationMessage{
OperState: UP,
NniPortID: nni.ID,
},
}
o.channel <- msg
}
// send PON Port indications
for _, pon := range o.Pons {
msg := Message{
Type: PonIndication,
Data: PonIndicationMessage{
OperState: UP,
PonPortID: pon.ID,
},
}
o.channel <- msg
for _, onu := range pon.Onus {
msg := Message{
Type: OnuDiscIndication,
Data: OnuDiscIndicationMessage{
Onu: onu,
OperState: UP,
},
}
o.channel <- msg
}
}
wg.Wait()
return nil
}
// Helpers method
func (o OltDevice) getPonById(id uint32) (*PonPort, error) {
for _, pon := range o.Pons {
if pon.ID == id {
return &pon, nil
}
}
return nil, errors.New(fmt.Sprintf("Cannot find PonPort with id %d in OLT %d", id, o.ID))
}
func (o OltDevice) getNniById(id uint32) (*NniPort, error) {
for _, nni := range o.Nnis {
if nni.ID == id {
return &nni, nil
}
}
return nil, errors.New(fmt.Sprintf("Cannot find NniPort with id %d in OLT %d", id, o.ID))
}
func (o OltDevice) stateChange(e *fsm.Event) {
log.WithFields(log.Fields{
"oltId": o.ID,
"dstState": e.Dst,
"srcState": e.Src,
}).Debugf("OLT state has changed")
}
func (o OltDevice) sendOltIndication(msg OltIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
data := &openolt.Indication_OltInd{OltInd: &openolt.OltIndication{OperState: msg.OperState.String()}}
if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
log.Error("Failed to send Indication_OltInd: %v", err)
}
log.WithFields(log.Fields{
"OperState": msg.OperState,
}).Debug("Sent Indication_OltInd")
}
func (o OltDevice) sendNniIndication(msg NniIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
nni, _ := o.getNniById(msg.NniPortID)
nni.OperState = UP
operData := &openolt.Indication_IntfOperInd{IntfOperInd: &openolt.IntfOperIndication{
Type: nni.Type,
IntfId: nni.ID,
OperState: nni.OperState.String(),
}}
if err := stream.Send(&openolt.Indication{Data: operData}); err != nil {
log.Error("Failed to send Indication_IntfOperInd for NNI: %v", err)
}
log.WithFields(log.Fields{
"Type": nni.Type,
"IntfId": nni.ID,
"OperState": nni.OperState.String(),
}).Debug("Sent Indication_IntfOperInd for NNI")
}
func (o OltDevice) sendPonIndication(msg PonIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
pon, _ := o.getPonById(msg.PonPortID)
pon.OperState = UP
discoverData := &openolt.Indication_IntfInd{IntfInd: &openolt.IntfIndication{
IntfId: pon.ID,
OperState: pon.OperState.String(),
}}
if err := stream.Send(&openolt.Indication{Data: discoverData}); err != nil {
log.Error("Failed to send Indication_IntfInd: %v", err)
}
log.WithFields(log.Fields{
"IntfId": pon.ID,
"OperState": pon.OperState.String(),
}).Debug("Sent Indication_IntfInd")
operData := &openolt.Indication_IntfOperInd{IntfOperInd: &openolt.IntfOperIndication{
Type: pon.Type,
IntfId: pon.ID,
OperState: pon.OperState.String(),
}}
if err := stream.Send(&openolt.Indication{Data: operData}); err != nil {
log.Error("Failed to send Indication_IntfOperInd for PON: %v", err)
}
log.WithFields(log.Fields{
"Type": pon.Type,
"IntfId": pon.ID,
"OperState": pon.OperState.String(),
}).Debug("Sent Indication_IntfOperInd for PON")
}
func (o OltDevice) oltChannels(stream openolt.Openolt_EnableIndicationServer) {
for message := range o.channel {
_msg, _ok := message.(Message)
if _ok {
log.WithFields(log.Fields{
"oltId": o.ID,
"messageType": _msg.Type,
}).Debug("Received message")
switch _msg.Data.(type) {
case OltIndicationMessage:
msg, _ := _msg.Data.(OltIndicationMessage)
o.InternalState.Event("enable")
o.sendOltIndication(msg, stream)
case NniIndicationMessage:
msg, _ := _msg.Data.(NniIndicationMessage)
o.sendNniIndication(msg, stream)
case PonIndicationMessage:
msg, _ := _msg.Data.(PonIndicationMessage)
o.sendPonIndication(msg, stream)
case OnuDiscIndicationMessage:
msg, _ := _msg.Data.(OnuDiscIndicationMessage)
msg.Onu.InternalState.Event("discover")
msg.Onu.sendOnuDiscIndication(msg, stream)
case OnuIndicationMessage:
msg, _ := _msg.Data.(OnuIndicationMessage)
pon, _ := o.getPonById(msg.PonPortID)
onu, _ := pon.getOnuBySn(msg.OnuSN)
onu.InternalState.Event("enable")
onu.sendOnuIndication(msg, stream)
default:
log.Warnf("Received unkown message data %v for type %v", _msg.Data, _msg.Type)
}
} else {
log.Warnf("Received unkown message %v", message)
}
}
}
// GRPC Endpoints
func (o OltDevice) ActivateOnu(context context.Context, onu *openolt.Onu) (*openolt.Empty, error) {
log.WithFields(log.Fields{
"onuSerialNumber": onu.SerialNumber,
}).Info("Received ActivateOnu call from VOLTHA")
msg := Message{
Type: OnuIndication,
Data: OnuIndicationMessage{
OnuSN: onu.SerialNumber,
PonPortID: onu.IntfId,
OperState: UP,
},
}
o.channel <- msg
return new(openolt.Empty) , nil
}
func (o OltDevice) DeactivateOnu(context.Context, *openolt.Onu) (*openolt.Empty, error) {
log.Error("DeactivateOnu not implemented")
return new(openolt.Empty) , nil
}
func (o OltDevice) DeleteOnu(context.Context, *openolt.Onu) (*openolt.Empty, error) {
log.Error("DeleteOnu not implemented")
return new(openolt.Empty) , nil
}
func (o OltDevice) DisableOlt(context.Context, *openolt.Empty) (*openolt.Empty, error) {
log.Error("DisableOlt not implemented")
return new(openolt.Empty) , nil
}
func (o OltDevice) DisablePonIf(context.Context, *openolt.Interface) (*openolt.Empty, error) {
log.Error("DisablePonIf not implemented")
return new(openolt.Empty) , nil
}
func (o OltDevice) EnableIndication(_ *openolt.Empty, stream openolt.Openolt_EnableIndicationServer) error {
log.WithField("oltId", o.ID).Info("OLT receives EnableIndication call from VOLTHA")
o.Enable(stream)
return nil
}
func (o OltDevice) EnablePonIf(context.Context, *openolt.Interface) (*openolt.Empty, error) {
log.Error("EnablePonIf not implemented")
return new(openolt.Empty) , nil
}
func (o OltDevice) FlowAdd(context.Context, *openolt.Flow) (*openolt.Empty, error) {
log.Error("FlowAdd not implemented")
return new(openolt.Empty) , nil
}
func (o OltDevice) FlowRemove(context.Context, *openolt.Flow) (*openolt.Empty, error) {
log.Error("FlowRemove not implemented")
return new(openolt.Empty) , nil
}
func (o OltDevice) HeartbeatCheck(context.Context, *openolt.Empty) (*openolt.Heartbeat, error) {
log.Error("HeartbeatCheck not implemented")
return new(openolt.Heartbeat) , nil
}
func (o OltDevice) GetDeviceInfo(context.Context, *openolt.Empty) (*openolt.DeviceInfo, error) {
log.WithField("oltId", o.ID).Info("OLT receives GetDeviceInfo call from VOLTHA")
devinfo := new(openolt.DeviceInfo)
devinfo.Vendor = "BBSim"
devinfo.Model = "asfvolt16"
devinfo.HardwareVersion = ""
devinfo.FirmwareVersion = ""
devinfo.Technology = "xgspon"
devinfo.PonPorts = 1
devinfo.OnuIdStart = 1
devinfo.OnuIdEnd = 255
devinfo.AllocIdStart = 1024
devinfo.AllocIdEnd = 16383
devinfo.GemportIdStart = 1024
devinfo.GemportIdEnd = 65535
devinfo.FlowIdStart = 1
devinfo.FlowIdEnd = 16383
return devinfo, nil
}
func (o OltDevice) OmciMsgOut(context.Context, *openolt.OmciMsg) (*openolt.Empty, error) {
log.Error("OmciMsgOut not implemented")
return new(openolt.Empty) , nil
}
func (o OltDevice) OnuPacketOut(context.Context, *openolt.OnuPacket) (*openolt.Empty, error) {
log.Error("OnuPacketOut not implemented")
return new(openolt.Empty) , nil
}
func (o OltDevice) Reboot(context.Context, *openolt.Empty) (*openolt.Empty, error) {
log.Error("Reboot not implemented")
return new(openolt.Empty) , nil
}
func (o OltDevice) ReenableOlt(context.Context, *openolt.Empty) (*openolt.Empty, error) {
log.Error("ReenableOlt not implemented")
return new(openolt.Empty) , nil
}
func (o OltDevice) UplinkPacketOut(context context.Context, packet *openolt.UplinkPacket) (*openolt.Empty, error) {
log.Error("UplinkPacketOut not implemented")
return new(openolt.Empty) , nil
}
func (o OltDevice) CollectStatistics(context.Context, *openolt.Empty) (*openolt.Empty, error) {
log.Error("CollectStatistics not implemented")
return new(openolt.Empty) , nil
}
func (o OltDevice) CreateTconts(context context.Context, packet *openolt.Tconts) (*openolt.Empty, error) {
log.Error("CreateTconts not implemented")
return new(openolt.Empty) , nil
}
func (o OltDevice) RemoveTconts(context context.Context, packet *openolt.Tconts) (*openolt.Empty, error) {
log.Error("RemoveTconts not implemented")
return new(openolt.Empty) , nil
}
func (o OltDevice) GetOnuInfo(context context.Context, packet *openolt.Onu) (*openolt.OnuIndication, error) {
log.Error("GetOnuInfo not implemented")
return new(openolt.OnuIndication) , nil
}
func (o OltDevice) GetPonIf(context context.Context, packet *openolt.Interface) (*openolt.IntfIndication, error) {
log.Error("GetPonIf not implemented")
return new(openolt.IntfIndication) , nil
}