First version,
OLT is activated and enabled.
ONU are in discovery state, OMCI state machine is still missing.
Change-Id: I6dddd4fd3460ee73b44226a546318acb2545d64d
diff --git a/internal/bbsim/devices/olt.go b/internal/bbsim/devices/olt.go
new file mode 100644
index 0000000..8435af1
--- /dev/null
+++ b/internal/bbsim/devices/olt.go
@@ -0,0 +1,429 @@
+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
+}
\ No newline at end of file