[SEBA-434] Replacing omci-sim with omci-lib-go
Change-Id: I499afc9ec49bb483467ea93bd6ce3077dd0ccc6e
diff --git a/internal/bbr/devices/olt.go b/internal/bbr/devices/olt.go
index 2093520..b65a174 100644
--- a/internal/bbr/devices/olt.go
+++ b/internal/bbr/devices/olt.go
@@ -20,6 +20,7 @@
"context"
"encoding/hex"
"fmt"
+ "github.com/opencord/bbsim/internal/bbsim/types"
"io"
"reflect"
"time"
@@ -273,9 +274,9 @@
"Pkt": omciInd.Pkt,
}).Trace("Received Onu omci indication")
- msg := devices.Message{
- Type: devices.OmciIndication,
- Data: devices.OmciIndicationMessage{
+ msg := types.Message{
+ Type: types.OmciIndication,
+ Data: types.OmciIndicationMessage{
OnuSN: onu.SerialNumber,
OnuID: onu.ID,
OmciInd: omciInd,
@@ -329,9 +330,9 @@
service := s.(*devices.Service)
onu := service.Onu
- msg := devices.Message{
- Type: devices.OnuPacketIn,
- Data: devices.OnuPacketMessage{
+ msg := types.Message{
+ Type: types.OnuPacketIn,
+ Data: types.OnuPacketMessage{
IntfId: pktIndication.IntfId,
OnuId: onu.ID,
Packet: pkt,
@@ -362,9 +363,9 @@
}
// NOTE when we push the EAPOL flow we set the PortNo = OnuId for convenience sake
// BBsim responds setting the port number that was sent with the flow
- msg := devices.Message{
- Type: devices.OnuPacketIn,
- Data: devices.OnuPacketMessage{
+ msg := types.Message{
+ Type: types.OnuPacketIn,
+ Data: types.OnuPacketMessage{
IntfId: pktIndication.IntfId,
OnuId: pktIndication.PortNo,
Packet: pkt,
diff --git a/internal/bbsim/alarmsim/alarmsim.go b/internal/bbsim/alarmsim/alarmsim.go
index cbb51da..6c6a290 100644
--- a/internal/bbsim/alarmsim/alarmsim.go
+++ b/internal/bbsim/alarmsim/alarmsim.go
@@ -17,17 +17,14 @@
package alarmsim
import (
- "context"
"fmt"
+ "github.com/opencord/bbsim/internal/bbsim/types"
"strconv"
"github.com/opencord/bbsim/internal/common"
"github.com/opencord/bbsim/api/bbsim"
- "github.com/opencord/bbsim/internal/bbsim/devices"
"github.com/opencord/voltha-protos/v4/go/openolt"
- "google.golang.org/grpc/codes"
- "google.golang.org/grpc/status"
)
func AlarmNameToEnum(name string) (bbsim.AlarmType_Types, error) {
@@ -54,9 +51,8 @@
}
// BuildOnuAlarmIndication function forms openolt alarmIndication as per ONUAlarmRequest
-func BuildOnuAlarmIndication(req *bbsim.ONUAlarmRequest, o *devices.OltDevice) (*openolt.AlarmIndication, error) {
+func BuildOnuAlarmIndication(req *bbsim.ONUAlarmRequest, onuID uint32, ponPortID uint32) (*openolt.AlarmIndication, error) {
var alarm *openolt.AlarmIndication
- var onu *devices.Onu
var err error
alarmType, err := AlarmNameToEnum(req.AlarmType)
@@ -64,37 +60,29 @@
return nil, err
}
- if alarmType != bbsim.AlarmType_LOS {
- // No ONU Id for LOS
- onu, err = o.FindOnuBySn(req.SerialNumber)
- if err != nil {
- return nil, err
- }
- }
-
switch alarmType {
case bbsim.AlarmType_DYING_GASP:
alarm = &openolt.AlarmIndication{
Data: &openolt.AlarmIndication_DyingGaspInd{DyingGaspInd: &openolt.DyingGaspIndication{
Status: req.Status,
- OnuId: onu.ID,
- IntfId: onu.PonPortID,
+ OnuId: onuID,
+ IntfId: ponPortID,
}},
}
case bbsim.AlarmType_ONU_STARTUP_FAILURE:
alarm = &openolt.AlarmIndication{
Data: &openolt.AlarmIndication_OnuStartupFailInd{OnuStartupFailInd: &openolt.OnuStartupFailureIndication{
Status: req.Status,
- OnuId: onu.ID,
- IntfId: onu.PonPortID,
+ OnuId: onuID,
+ IntfId: ponPortID,
}},
}
case bbsim.AlarmType_ONU_SIGNAL_DEGRADE:
alarm = &openolt.AlarmIndication{
Data: &openolt.AlarmIndication_OnuSignalDegradeInd{OnuSignalDegradeInd: &openolt.OnuSignalDegradeIndication{
Status: req.Status,
- OnuId: onu.ID,
- IntfId: onu.PonPortID,
+ OnuId: onuID,
+ IntfId: ponPortID,
InverseBitErrorRate: uint32(extractInt(req.Parameters, "InverseBitErrorRate", 0)),
}},
}
@@ -102,8 +90,8 @@
alarm = &openolt.AlarmIndication{
Data: &openolt.AlarmIndication_OnuSignalsFailInd{OnuSignalsFailInd: &openolt.OnuSignalsFailureIndication{
Status: req.Status,
- OnuId: onu.ID,
- IntfId: onu.PonPortID,
+ OnuId: onuID,
+ IntfId: ponPortID,
InverseBitErrorRate: uint32(extractInt(req.Parameters, "InverseBitErrorRate", 0)),
}},
}
@@ -111,8 +99,8 @@
alarm = &openolt.AlarmIndication{
Data: &openolt.AlarmIndication_OnuDriftOfWindowInd{OnuDriftOfWindowInd: &openolt.OnuDriftOfWindowIndication{
Status: req.Status,
- OnuId: onu.ID,
- IntfId: onu.PonPortID,
+ OnuId: onuID,
+ IntfId: ponPortID,
Drift: uint32(extractInt(req.Parameters, "Drift", 0)),
NewEqd: uint32(extractInt(req.Parameters, "NewEqd", 0)),
}},
@@ -121,47 +109,47 @@
alarm = &openolt.AlarmIndication{
Data: &openolt.AlarmIndication_OnuLossOmciInd{OnuLossOmciInd: &openolt.OnuLossOfOmciChannelIndication{
Status: req.Status,
- OnuId: onu.ID,
- IntfId: onu.PonPortID,
+ OnuId: onuID,
+ IntfId: ponPortID,
}},
}
case bbsim.AlarmType_ONU_TRANSMISSION_INTERFERENCE_WARNING:
alarm = &openolt.AlarmIndication{
Data: &openolt.AlarmIndication_OnuTiwiInd{OnuTiwiInd: &openolt.OnuTransmissionInterferenceWarning{
Status: req.Status,
- OnuId: onu.ID,
- IntfId: onu.PonPortID,
+ OnuId: onuID,
+ IntfId: ponPortID,
Drift: uint32(extractInt(req.Parameters, "Drift", 0)),
}},
}
case bbsim.AlarmType_ONU_ACTIVATION_FAILURE:
alarm = &openolt.AlarmIndication{
Data: &openolt.AlarmIndication_OnuActivationFailInd{OnuActivationFailInd: &openolt.OnuActivationFailureIndication{
- OnuId: onu.ID,
- IntfId: onu.PonPortID,
+ OnuId: onuID,
+ IntfId: ponPortID,
FailReason: uint32(extractInt(req.Parameters, "FailReason", 0)),
}},
}
case bbsim.AlarmType_ONU_PROCESSING_ERROR:
alarm = &openolt.AlarmIndication{
Data: &openolt.AlarmIndication_OnuProcessingErrorInd{OnuProcessingErrorInd: &openolt.OnuProcessingErrorIndication{
- OnuId: onu.ID,
- IntfId: onu.PonPortID,
+ OnuId: onuID,
+ IntfId: ponPortID,
}},
}
case bbsim.AlarmType_ONU_LOSS_OF_KEY_SYNC_FAILURE:
alarm = &openolt.AlarmIndication{
Data: &openolt.AlarmIndication_OnuLossOfSyncFailInd{OnuLossOfSyncFailInd: &openolt.OnuLossOfKeySyncFailureIndication{
- OnuId: onu.ID,
- IntfId: onu.PonPortID,
+ OnuId: onuID,
+ IntfId: ponPortID,
Status: req.Status,
}},
}
case bbsim.AlarmType_ONU_ITU_PON_STATS:
alarm = &openolt.AlarmIndication{
Data: &openolt.AlarmIndication_OnuItuPonStatsInd{OnuItuPonStatsInd: &openolt.OnuItuPonStatsIndication{
- OnuId: onu.ID,
- IntfId: onu.PonPortID,
+ OnuId: onuID,
+ IntfId: ponPortID,
Stats: &openolt.OnuItuPonStatsIndication_RdiErrorInd{
RdiErrorInd: &openolt.RdiErrorIndication{
RdiErrorCount: uint64(extractInt(req.Parameters, "RdiErrors", 0)),
@@ -174,48 +162,48 @@
alarm = &openolt.AlarmIndication{
Data: &openolt.AlarmIndication_OnuAlarmInd{OnuAlarmInd: &openolt.OnuAlarmIndication{
LosStatus: req.Status,
- OnuId: onu.ID,
- IntfId: onu.PonPortID,
+ OnuId: onuID,
+ IntfId: ponPortID,
}},
}
case bbsim.AlarmType_ONU_ALARM_LOB:
alarm = &openolt.AlarmIndication{
Data: &openolt.AlarmIndication_OnuAlarmInd{OnuAlarmInd: &openolt.OnuAlarmIndication{
LobStatus: req.Status,
- OnuId: onu.ID,
- IntfId: onu.PonPortID,
+ OnuId: onuID,
+ IntfId: ponPortID,
}},
}
case bbsim.AlarmType_ONU_ALARM_LOPC_MISS:
alarm = &openolt.AlarmIndication{
Data: &openolt.AlarmIndication_OnuAlarmInd{OnuAlarmInd: &openolt.OnuAlarmIndication{
LopcMissStatus: req.Status,
- OnuId: onu.ID,
- IntfId: onu.PonPortID,
+ OnuId: onuID,
+ IntfId: ponPortID,
}},
}
case bbsim.AlarmType_ONU_ALARM_LOPC_MIC_ERROR:
alarm = &openolt.AlarmIndication{
Data: &openolt.AlarmIndication_OnuAlarmInd{OnuAlarmInd: &openolt.OnuAlarmIndication{
LopcMicErrorStatus: req.Status,
- OnuId: onu.ID,
- IntfId: onu.PonPortID,
+ OnuId: onuID,
+ IntfId: ponPortID,
}},
}
case bbsim.AlarmType_ONU_ALARM_LOFI:
alarm = &openolt.AlarmIndication{
Data: &openolt.AlarmIndication_OnuAlarmInd{OnuAlarmInd: &openolt.OnuAlarmIndication{
LofiStatus: req.Status,
- OnuId: onu.ID,
- IntfId: onu.PonPortID,
+ OnuId: onuID,
+ IntfId: ponPortID,
}},
}
case bbsim.AlarmType_ONU_ALARM_LOAMI:
alarm = &openolt.AlarmIndication{
Data: &openolt.AlarmIndication_OnuAlarmInd{OnuAlarmInd: &openolt.OnuAlarmIndication{
LoamiStatus: req.Status,
- OnuId: onu.ID,
- IntfId: onu.PonPortID,
+ OnuId: onuID,
+ IntfId: ponPortID,
}},
}
default:
@@ -226,70 +214,18 @@
}
// SimulateOnuAlarm accept request for Onu alarms and send proper alarmIndication to openolt stream
-func SimulateOnuAlarm(ctx context.Context, req *bbsim.ONUAlarmRequest, o *devices.OltDevice) error {
- alarmIndication, err := BuildOnuAlarmIndication(req, o)
+func SimulateOnuAlarm(req *bbsim.ONUAlarmRequest, onuID uint32, ponPortID uint32, channel chan types.Message) error {
+ alarmIndication, err := BuildOnuAlarmIndication(req, onuID, ponPortID)
if err != nil {
return err
}
- err = o.SendAlarmIndication(ctx, alarmIndication)
- if err != nil {
- return err
+ msg := types.Message{
+ Type: types.AlarmIndication,
+ Data: alarmIndication,
}
- return nil
-}
-
-// IsPonPortPresentInOlt verifies if given Pon port is present in olt
-func IsPonPortPresentInOlt(PonPort uint32) bool {
- o := devices.GetOLT()
- for _, intf := range o.Pons {
- if intf.ID == PonPort {
- return true
- }
- }
- return false
-}
-
-// IsNniPortPresentInOlt verifies if given nni port is present in olt
-func IsNniPortPresentInOlt(nniPort uint32) bool {
- o := devices.GetOLT()
- for _, intf := range o.Nnis {
- if intf.ID == nniPort {
- return true
- }
- }
- return false
-}
-
-// SimulateOltAlarm accept request for Olt alarms and send proper alarmIndication to openolt stream
-func SimulateOltAlarm(ctx context.Context, req *bbsim.OLTAlarmRequest, o *devices.OltDevice) error {
- var alarmIndication *openolt.AlarmIndication
- var err error
-
- //check if its a valid port id
- switch req.InterfaceType {
- case "nni":
- if !IsNniPortPresentInOlt(uint32(req.InterfaceID)) {
- return status.Errorf(codes.NotFound, strconv.Itoa(int(req.InterfaceID))+" NNI not present in olt")
- }
-
- case "pon":
- if !IsPonPortPresentInOlt(uint32(req.InterfaceID)) {
- return status.Errorf(codes.NotFound, strconv.Itoa(int(req.InterfaceID))+" PON not present in olt")
- }
- }
- alarmIndication = &openolt.AlarmIndication{
- Data: &openolt.AlarmIndication_LosInd{LosInd: &openolt.LosIndication{
- Status: req.Status,
- IntfId: devices.InterfaceIDToPortNo(req.InterfaceID, req.InterfaceType),
- }},
- }
-
- err = o.SendAlarmIndication(ctx, alarmIndication)
- if err != nil {
- return err
- }
+ channel <- msg
return nil
}
diff --git a/internal/bbsim/api/grpc_api_server.go b/internal/bbsim/api/grpc_api_server.go
index 84d3478..5fd6392 100644
--- a/internal/bbsim/api/grpc_api_server.go
+++ b/internal/bbsim/api/grpc_api_server.go
@@ -23,7 +23,6 @@
"time"
"github.com/opencord/bbsim/api/bbsim"
- "github.com/opencord/bbsim/internal/bbsim/alarmsim"
"github.com/opencord/bbsim/internal/bbsim/devices"
"github.com/opencord/bbsim/internal/common"
log "github.com/sirupsen/logrus"
@@ -193,12 +192,22 @@
func (s BBSimServer) SetOnuAlarmIndication(ctx context.Context, req *bbsim.ONUAlarmRequest) (*bbsim.Response, error) {
o := devices.GetOLT()
- err := alarmsim.SimulateOnuAlarm(ctx, req, o)
+
+ res := &bbsim.Response{}
+
+ onu, err := o.FindOnuBySn(req.SerialNumber)
if err != nil {
+ res.StatusCode = int32(codes.NotFound)
+ res.Message = err.Error()
return nil, err
}
- res := &bbsim.Response{}
+ if err := onu.SetAlarm(req.AlarmType, req.Status); err != nil {
+ res.StatusCode = int32(codes.Internal)
+ res.Message = err.Error()
+ return nil, err
+ }
+
res.StatusCode = int32(codes.OK)
res.Message = fmt.Sprintf("Onu Alarm Indication Sent.")
return res, nil
@@ -207,12 +216,14 @@
// SetOltAlarmIndication generates OLT Alarms for LOS
func (s BBSimServer) SetOltAlarmIndication(ctx context.Context, req *bbsim.OLTAlarmRequest) (*bbsim.Response, error) {
o := devices.GetOLT()
- err := alarmsim.SimulateOltAlarm(ctx, req, o)
- if err != nil {
+ res := &bbsim.Response{}
+
+ if err := o.SetAlarm(req.InterfaceID, req.InterfaceType, req.Status); err != nil {
+ res.StatusCode = int32(codes.Internal)
+ res.Message = err.Error()
return nil, err
}
- res := &bbsim.Response{}
res.StatusCode = int32(codes.OK)
res.Message = fmt.Sprintf("Olt Alarm Indication Sent.")
return res, nil
diff --git a/internal/bbsim/api/onus_handler.go b/internal/bbsim/api/onus_handler.go
index 43b624f..2533fa3 100644
--- a/internal/bbsim/api/onus_handler.go
+++ b/internal/bbsim/api/onus_handler.go
@@ -19,10 +19,10 @@
import (
"context"
"fmt"
+ "github.com/opencord/bbsim/internal/bbsim/types"
"github.com/opencord/voltha-protos/v4/go/openolt"
"github.com/opencord/bbsim/api/bbsim"
- "github.com/opencord/bbsim/internal/bbsim/alarmsim"
"github.com/opencord/bbsim/internal/bbsim/devices"
log "github.com/sirupsen/logrus"
"google.golang.org/grpc/codes"
@@ -270,7 +270,7 @@
"Service": service.Name,
}).Debugf("Sending %s event on Service %s", event, service.Name)
- if err := service.IGMPState.Event(event, devices.IgmpMessage{GroupAddress: req.GroupAddress}); err != nil {
+ if err := service.IGMPState.Event(event, types.IgmpMessage{GroupAddress: req.GroupAddress}); err != nil {
logger.WithFields(log.Fields{
"OnuId": onu.ID,
"IntfId": onu.PonPortID,
@@ -452,64 +452,13 @@
func handlePoweronONU(onu *devices.Onu) (*bbsim.Response, error) {
res := &bbsim.Response{}
- olt := devices.GetOLT()
- intitalState := onu.InternalState.Current()
- if onu.InternalState.Current() == "created" || onu.InternalState.Current() == "disabled" {
- if err := onu.InternalState.Event("initialize"); err != nil {
- logger.WithFields(log.Fields{
- "OnuId": onu.ID,
- "IntfId": onu.PonPortID,
- "OnuSn": onu.Sn(),
- }).Errorf("Cannot poweron ONU: %s", err.Error())
- res.StatusCode = int32(codes.FailedPrecondition)
- res.Message = err.Error()
- return res, err
- }
- }
- losReq := bbsim.ONUAlarmRequest{
- AlarmType: "ONU_ALARM_LOS",
- SerialNumber: onu.Sn(),
- Status: "off",
- }
-
- if err := alarmsim.SimulateOnuAlarm(context.TODO(), &losReq, olt); err != nil {
- logger.WithFields(log.Fields{
- "OnuId": onu.ID,
- "IntfId": onu.PonPortID,
- "OnuSn": onu.Sn(),
- }).Errorf("Cannot send LOS: %s", err.Error())
+ if err := onu.HandlePowerOnONU(); err != nil {
res.StatusCode = int32(codes.FailedPrecondition)
res.Message = err.Error()
return res, err
}
- if err := onu.InternalState.Event("discover"); err != nil {
- logger.WithFields(log.Fields{
- "OnuId": onu.ID,
- "IntfId": onu.PonPortID,
- "OnuSn": onu.Sn(),
- }).Errorf("Cannot poweron ONU: %s", err.Error())
- res.StatusCode = int32(codes.FailedPrecondition)
- res.Message = err.Error()
- return res, err
- }
- // move onu directly to enable state only when its a powercycle case
- // in case of first time onu poweron onu will be moved to enable on
- // receiving ActivateOnu request from openolt adapter
- if intitalState == "disabled" {
- if err := onu.InternalState.Event("enable"); err != nil {
- logger.WithFields(log.Fields{
- "OnuId": onu.ID,
- "IntfId": onu.PonPortID,
- "OnuSn": onu.Sn(),
- }).Errorf("Cannot enable ONU: %s", err.Error())
- res.StatusCode = int32(codes.FailedPrecondition)
- res.Message = err.Error()
- return res, err
- }
- }
-
res.StatusCode = int32(codes.OK)
res.Message = fmt.Sprintf("ONU %s successfully powered on.", onu.Sn())
@@ -518,50 +467,8 @@
func handleShutdownONU(onu *devices.Onu) (*bbsim.Response, error) {
res := &bbsim.Response{}
- olt := devices.GetOLT()
- dyingGasp := bbsim.ONUAlarmRequest{
- AlarmType: "DYING_GASP",
- SerialNumber: onu.Sn(),
- Status: "on",
- }
-
- if err := alarmsim.SimulateOnuAlarm(context.TODO(), &dyingGasp, olt); err != nil {
- logger.WithFields(log.Fields{
- "OnuId": onu.ID,
- "IntfId": onu.PonPortID,
- "OnuSn": onu.Sn(),
- }).Errorf("Cannot send Dying Gasp: %s", err.Error())
- res.StatusCode = int32(codes.FailedPrecondition)
- res.Message = err.Error()
- return res, err
- }
-
- losReq := bbsim.ONUAlarmRequest{
- AlarmType: "ONU_ALARM_LOS",
- SerialNumber: onu.Sn(),
- Status: "on",
- }
-
- if err := alarmsim.SimulateOnuAlarm(context.TODO(), &losReq, olt); err != nil {
- logger.WithFields(log.Fields{
- "OnuId": onu.ID,
- "IntfId": onu.PonPortID,
- "OnuSn": onu.Sn(),
- }).Errorf("Cannot send LOS: %s", err.Error())
- res.StatusCode = int32(codes.FailedPrecondition)
- res.Message = err.Error()
- return res, err
- }
-
- // TODO if it's the last ONU on the PON, then send a PON LOS
-
- if err := onu.InternalState.Event("disable"); err != nil {
- logger.WithFields(log.Fields{
- "OnuId": onu.ID,
- "IntfId": onu.PonPortID,
- "OnuSn": onu.Sn(),
- }).Errorf("Cannot shutdown ONU: %s", err.Error())
+ if err := onu.HandleShutdownONU(); err != nil {
res.StatusCode = int32(codes.FailedPrecondition)
res.Message = err.Error()
return res, err
diff --git a/internal/bbsim/devices/olt.go b/internal/bbsim/devices/olt.go
index 9e26ad2..6540a56 100644
--- a/internal/bbsim/devices/olt.go
+++ b/internal/bbsim/devices/olt.go
@@ -21,8 +21,10 @@
"encoding/hex"
"fmt"
"github.com/opencord/bbsim/internal/bbsim/responders/dhcp"
+ "github.com/opencord/bbsim/internal/bbsim/types"
"github.com/opencord/voltha-protos/v4/go/ext/config"
"net"
+ "strconv"
"sync"
"time"
@@ -31,7 +33,6 @@
"github.com/looplab/fsm"
"github.com/opencord/bbsim/internal/bbsim/packetHandlers"
"github.com/opencord/bbsim/internal/common"
- omcisim "github.com/opencord/omci-sim"
common_protos "github.com/opencord/voltha-protos/v4/go/common"
"github.com/opencord/voltha-protos/v4/go/openolt"
"github.com/opencord/voltha-protos/v4/go/tech_profile"
@@ -57,7 +58,7 @@
NumPon int
NumOnuPerPon int
InternalState *fsm.FSM
- channel chan Message
+ channel chan types.Message
dhcpServer dhcp.DHCPServerIf
Flows sync.Map
Delay int
@@ -230,7 +231,7 @@
}
// create new channel for processOltMessages Go routine
- o.channel = make(chan Message)
+ o.channel = make(chan types.Message)
// FIXME we are assuming we have only one NNI
if o.Nnis[0] != nil {
@@ -272,10 +273,10 @@
for _, pon := range o.Pons {
if pon.InternalState.Current() == "enabled" {
// disable PONs
- msg := Message{
- Type: PonIndication,
- Data: PonIndicationMessage{
- OperState: DOWN,
+ msg := types.Message{
+ Type: types.PonIndication,
+ Data: types.PonIndicationMessage{
+ OperState: types.DOWN,
PonPortID: pon.ID,
},
}
@@ -388,35 +389,33 @@
go o.processOltMessages(o.enableContext, stream, &wg)
// enable the OLT
- oltMsg := Message{
- Type: OltIndication,
- Data: OltIndicationMessage{
- OperState: UP,
+ oltMsg := types.Message{
+ Type: types.OltIndication,
+ Data: types.OltIndicationMessage{
+ OperState: types.UP,
},
}
o.channel <- oltMsg
// send NNI Port Indications
for _, nni := range o.Nnis {
- msg := Message{
- Type: NniIndication,
- Data: NniIndicationMessage{
- OperState: UP,
+ msg := types.Message{
+ Type: types.NniIndication,
+ Data: types.NniIndicationMessage{
+ OperState: types.UP,
NniPortID: nni.ID,
},
}
o.channel <- msg
}
- go o.processOmciMessages(o.enableContext, stream, &wg)
-
if rebootFlag {
for _, pon := range o.Pons {
if pon.InternalState.Current() == "disabled" {
- msg := Message{
- Type: PonIndication,
- Data: PonIndicationMessage{
- OperState: UP,
+ msg := types.Message{
+ Type: types.PonIndication,
+ Data: types.PonIndicationMessage{
+ OperState: types.UP,
PonPortID: pon.ID,
},
}
@@ -431,10 +430,10 @@
if o.ControlledActivation == Default || o.ControlledActivation == OnlyONU {
// send PON Port indications
for _, pon := range o.Pons {
- msg := Message{
- Type: PonIndication,
- Data: PonIndicationMessage{
- OperState: UP,
+ msg := types.Message{
+ Type: types.PonIndication,
+ Data: types.PonIndicationMessage{
+ OperState: types.UP,
PonPortID: pon.ID,
},
}
@@ -453,43 +452,6 @@
wg.Wait()
}
-func (o *OltDevice) processOmciMessages(ctx context.Context, stream openolt.Openolt_EnableIndicationServer, wg *sync.WaitGroup) {
- ch := omcisim.GetChannel()
-
- oltLogger.Debug("Starting OMCI Indication Channel")
-
-loop:
- for {
- select {
- case <-ctx.Done():
- oltLogger.Debug("OMCI processing canceled via context")
- break loop
- case message, ok := <-ch:
- if !ok || ctx.Err() != nil {
- oltLogger.Debug("OMCI processing canceled via channel close")
- break loop
- }
-
- oltLogger.WithFields(log.Fields{
- "messageType": message.Type,
- "OnuId": message.Data.OnuId,
- "IntfId": message.Data.IntfId,
- }).Debug("Received message on OMCI Sim channel")
-
- onuId := message.Data.OnuId
- intfId := message.Data.IntfId
- onu, err := o.FindOnuById(intfId, onuId)
- if err != nil {
- oltLogger.Errorf("Failed to find onu: %v", err)
- continue
- }
- go onu.processOmciMessage(message, stream)
- }
- }
-
- wg.Done()
-}
-
func (o *OltDevice) periodicPortStats(ctx context.Context) {
var portStats *openolt.PortStatistics
for {
@@ -525,6 +487,55 @@
// Helpers method
+func (o *OltDevice) SetAlarm(interfaceId uint32, interfaceType string, alarmStatus string) error {
+
+ switch interfaceType {
+ case "nni":
+ if !o.HasNni(interfaceId) {
+ return status.Errorf(codes.NotFound, strconv.Itoa(int(interfaceId))+" NNI not present in olt")
+ }
+
+ case "pon":
+ if !o.HasPon(interfaceId) {
+ return status.Errorf(codes.NotFound, strconv.Itoa(int(interfaceId))+" PON not present in olt")
+ }
+ }
+
+ alarmIndication := &openolt.AlarmIndication{
+ Data: &openolt.AlarmIndication_LosInd{LosInd: &openolt.LosIndication{
+ Status: alarmStatus,
+ IntfId: InterfaceIDToPortNo(interfaceId, interfaceType),
+ }},
+ }
+
+ msg := types.Message{
+ Type: types.AlarmIndication,
+ Data: alarmIndication,
+ }
+
+ o.channel <- msg
+
+ return nil
+}
+
+func (o *OltDevice) HasNni(id uint32) bool {
+ for _, intf := range o.Nnis {
+ if intf.ID == id {
+ return true
+ }
+ }
+ return false
+}
+
+func (o *OltDevice) HasPon(id uint32) bool {
+ for _, intf := range o.Pons {
+ if intf.ID == id {
+ return true
+ }
+ }
+ return false
+}
+
func (o *OltDevice) GetPonById(id uint32) (*PonPort, error) {
for _, pon := range o.Pons {
if pon.ID == id {
@@ -555,7 +566,7 @@
}).Debug("Sent Indication_AlarmInd")
}
-func (o *OltDevice) sendOltIndication(msg OltIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
+func (o *OltDevice) sendOltIndication(msg types.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 {
oltLogger.Errorf("Failed to send Indication_OltInd: %v", err)
@@ -567,9 +578,9 @@
}).Debug("Sent Indication_OltInd")
}
-func (o *OltDevice) sendNniIndication(msg NniIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
+func (o *OltDevice) sendNniIndication(msg types.NniIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
nni, _ := o.getNniById(msg.NniPortID)
- if msg.OperState == UP {
+ if msg.OperState == types.UP {
if err := nni.OperState.Event("enable"); err != nil {
log.WithFields(log.Fields{
"Type": nni.Type,
@@ -577,7 +588,7 @@
"OperState": nni.OperState.Current(),
}).Errorf("Can't move NNI Port to enabled state: %v", err)
}
- } else if msg.OperState == DOWN {
+ } else if msg.OperState == types.DOWN {
if err := nni.OperState.Event("disable"); err != nil {
log.WithFields(log.Fields{
"Type": nni.Type,
@@ -685,26 +696,26 @@
}).Trace("Received message")
switch message.Type {
- case OltIndication:
- msg, _ := message.Data.(OltIndicationMessage)
- if msg.OperState == UP {
+ case types.OltIndication:
+ msg, _ := message.Data.(types.OltIndicationMessage)
+ if msg.OperState == types.UP {
_ = o.InternalState.Event("enable")
_ = o.OperState.Event("enable")
- } else if msg.OperState == DOWN {
+ } else if msg.OperState == types.DOWN {
_ = o.InternalState.Event("disable")
_ = o.OperState.Event("disable")
}
o.sendOltIndication(msg, stream)
- case AlarmIndication:
+ case types.AlarmIndication:
alarmInd, _ := message.Data.(*openolt.AlarmIndication)
o.sendAlarmIndication(alarmInd, stream)
- case NniIndication:
- msg, _ := message.Data.(NniIndicationMessage)
+ case types.NniIndication:
+ msg, _ := message.Data.(types.NniIndicationMessage)
o.sendNniIndication(msg, stream)
- case PonIndication:
- msg, _ := message.Data.(PonIndicationMessage)
+ case types.PonIndication:
+ msg, _ := message.Data.(types.PonIndicationMessage)
pon, _ := o.GetPonById(msg.PonPortID)
- if msg.OperState == UP {
+ if msg.OperState == types.UP {
if err := pon.OperState.Event("enable"); err != nil {
oltLogger.WithFields(log.Fields{
"IntfId": msg.PonPortID,
@@ -717,7 +728,7 @@
"Err": err,
}).Error("Can't Enable Internal state for PON Port")
}
- } else if msg.OperState == DOWN {
+ } else if msg.OperState == types.DOWN {
if err := pon.OperState.Event("disable"); err != nil {
oltLogger.WithFields(log.Fields{
"IntfId": msg.PonPortID,
@@ -873,10 +884,10 @@
for _, pon := range o.Pons {
if pon.InternalState.Current() == "enabled" {
// disable PONs
- msg := Message{
- Type: PonIndication,
- Data: PonIndicationMessage{
- OperState: DOWN,
+ msg := types.Message{
+ Type: types.PonIndication,
+ Data: types.PonIndicationMessage{
+ OperState: types.DOWN,
PonPortID: pon.ID,
},
}
@@ -888,10 +899,10 @@
// The reason for that is in-band management
// disable OLT
- oltMsg := Message{
- Type: OltIndication,
- Data: OltIndicationMessage{
- OperState: DOWN,
+ oltMsg := types.Message{
+ Type: types.OltIndication,
+ Data: types.OltIndicationMessage{
+ OperState: types.DOWN,
},
}
o.channel <- oltMsg
@@ -903,10 +914,10 @@
ponID := intf.GetIntfId()
pon, _ := o.GetPonById(intf.IntfId)
- msg := Message{
- Type: PonIndication,
- Data: PonIndicationMessage{
- OperState: DOWN,
+ msg := types.Message{
+ Type: types.PonIndication,
+ Data: types.PonIndicationMessage{
+ OperState: types.DOWN,
PonPortID: ponID,
},
}
@@ -914,8 +925,8 @@
for _, onu := range pon.Onus {
- onuIndication := OnuIndicationMessage{
- OperState: DOWN,
+ onuIndication := types.OnuIndicationMessage{
+ OperState: types.DOWN,
PonPortID: ponID,
OnuID: onu.ID,
OnuSN: onu.SerialNumber,
@@ -939,10 +950,10 @@
ponID := intf.GetIntfId()
pon, _ := o.GetPonById(intf.IntfId)
- msg := Message{
- Type: PonIndication,
- Data: PonIndicationMessage{
- OperState: UP,
+ msg := types.Message{
+ Type: types.PonIndication,
+ Data: types.PonIndicationMessage{
+ OperState: types.UP,
PonPortID: ponID,
},
}
@@ -950,8 +961,8 @@
for _, onu := range pon.Onus {
- onuIndication := OnuIndicationMessage{
- OperState: UP,
+ onuIndication := types.OnuIndicationMessage{
+ OperState: types.UP,
PonPortID: ponID,
OnuID: onu.ID,
OnuSN: onu.SerialNumber,
@@ -1030,9 +1041,9 @@
}
}
- msg := Message{
- Type: FlowAdd,
- Data: OnuFlowUpdateMessage{
+ msg := types.Message{
+ Type: types.FlowAdd,
+ Data: types.OnuFlowUpdateMessage{
PonPortID: pon.ID,
OnuID: onu.ID,
Flow: flow,
@@ -1107,9 +1118,9 @@
return nil, err
}
- msg := Message{
- Type: FlowRemoved,
- Data: OnuFlowUpdateMessage{
+ msg := types.Message{
+ Type: types.FlowRemoved,
+ Data: types.OnuFlowUpdateMessage{
Flow: flow,
},
}
@@ -1193,12 +1204,12 @@
"OnuId": onu.ID,
"OnuSn": onu.Sn(),
}).Tracef("Received OmciMsgOut")
- msg := Message{
- Type: OMCI,
- Data: OmciMessage{
+ msg := types.Message{
+ Type: types.OMCI,
+ Data: types.OmciMessage{
OnuSN: onu.SerialNumber,
OnuID: onu.ID,
- omciMsg: omci_msg,
+ OmciMsg: omci_msg,
},
}
onu.Channel <- msg
@@ -1254,9 +1265,9 @@
return new(openolt.Empty), nil
}
- msg := Message{
- Type: OnuPacketOut,
- Data: OnuPacketMessage{
+ msg := types.Message{
+ Type: types.OnuPacketOut,
+ Data: types.OnuPacketMessage{
IntfId: onuPkt.IntfId,
OnuId: onuPkt.OnuId,
Packet: rawpkt,
@@ -1291,20 +1302,20 @@
publishEvent("OLT-reenable-received", -1, -1, "")
// enable OLT
- oltMsg := Message{
- Type: OltIndication,
- Data: OltIndicationMessage{
- OperState: UP,
+ oltMsg := types.Message{
+ Type: types.OltIndication,
+ Data: types.OltIndicationMessage{
+ OperState: types.UP,
},
}
o.channel <- oltMsg
for _, pon := range o.Pons {
if pon.InternalState.Current() == "disabled" {
- msg := Message{
- Type: PonIndication,
- Data: PonIndicationMessage{
- OperState: UP,
+ msg := types.Message{
+ Type: types.PonIndication,
+ Data: types.PonIndicationMessage{
+ OperState: types.UP,
PonPortID: pon.ID,
},
}
@@ -1397,17 +1408,6 @@
return new(openolt.Empty), nil
}
-// assumes caller has properly formulated an openolt.AlarmIndication
-func (o *OltDevice) SendAlarmIndication(context context.Context, ind *openolt.AlarmIndication) error {
- msg := Message{
- Type: AlarmIndication,
- Data: ind,
- }
-
- o.channel <- msg
- return nil
-}
-
func (o *OltDevice) PerformGroupOperation(ctx context.Context, group *openolt.Group) (*openolt.Empty, error) {
oltLogger.WithFields(log.Fields{
"GroupId": group.GroupId,
diff --git a/internal/bbsim/devices/olt_test.go b/internal/bbsim/devices/olt_test.go
index 0081ffa..154942b 100644
--- a/internal/bbsim/devices/olt_test.go
+++ b/internal/bbsim/devices/olt_test.go
@@ -17,6 +17,7 @@
package devices
import (
+ "github.com/opencord/bbsim/internal/bbsim/types"
"github.com/opencord/bbsim/internal/common"
"net"
"testing"
@@ -202,7 +203,7 @@
FlowId: 64,
Classifier: &openolt.Classifier{},
}
- msg1 := OnuFlowUpdateMessage{
+ msg1 := types.OnuFlowUpdateMessage{
OnuID: onu1.ID,
PonPortID: onu1.PonPortID,
Flow: &flow1,
@@ -214,7 +215,7 @@
FlowId: 72,
Classifier: &openolt.Classifier{},
}
- msg2 := OnuFlowUpdateMessage{
+ msg2 := types.OnuFlowUpdateMessage{
OnuID: onu2.ID,
PonPortID: onu2.PonPortID,
Flow: &flow2,
diff --git a/internal/bbsim/devices/onu.go b/internal/bbsim/devices/onu.go
index b85c804..822ec6b 100644
--- a/internal/bbsim/devices/onu.go
+++ b/internal/bbsim/devices/onu.go
@@ -20,20 +20,24 @@
"context"
"encoding/hex"
"fmt"
+ pb "github.com/opencord/bbsim/api/bbsim"
+ "github.com/opencord/bbsim/internal/bbsim/alarmsim"
+ bbsim "github.com/opencord/bbsim/internal/bbsim/types"
+ me "github.com/opencord/omci-lib-go/generated"
+ "strconv"
+
"github.com/opencord/bbsim/internal/bbsim/packetHandlers"
"github.com/opencord/bbsim/internal/bbsim/responders/dhcp"
"github.com/opencord/bbsim/internal/bbsim/responders/eapol"
"net"
-
"time"
- "github.com/cboling/omci"
"github.com/google/gopacket/layers"
"github.com/jpillora/backoff"
"github.com/looplab/fsm"
"github.com/opencord/bbsim/internal/common"
omcilib "github.com/opencord/bbsim/internal/common/omci"
- omcisim "github.com/opencord/omci-sim"
+ "github.com/opencord/omci-lib-go"
"github.com/opencord/voltha-protos/v4/go/openolt"
"github.com/opencord/voltha-protos/v4/go/tech_profile"
log "github.com/sirupsen/logrus"
@@ -72,7 +76,7 @@
OperState *fsm.FSM
SerialNumber *openolt.SerialNumber
- Channel chan Message // this Channel is to track state changes OMCI messages, EAPOL and DHCP packets
+ Channel chan bbsim.Message // this Channel is to track state changes OMCI messages, EAPOL and DHCP packets
// OMCI params
tid uint16
@@ -143,7 +147,7 @@
},
"enter_initialized": func(e *fsm.Event) {
// create new channel for ProcessOnuMessages Go routine
- o.Channel = make(chan Message, 2048)
+ o.Channel = make(chan bbsim.Message, 2048)
if err := o.OperState.Event("enable"); err != nil {
onuLogger.WithFields(log.Fields{
@@ -159,22 +163,21 @@
}
},
"enter_discovered": func(e *fsm.Event) {
- msg := Message{
- Type: OnuDiscIndication,
- Data: OnuDiscIndicationMessage{
- Onu: &o,
- OperState: UP,
+ msg := bbsim.Message{
+ Type: bbsim.OnuDiscIndication,
+ Data: bbsim.OnuDiscIndicationMessage{
+ OperState: bbsim.UP,
},
}
o.Channel <- msg
},
"enter_enabled": func(event *fsm.Event) {
- msg := Message{
- Type: OnuIndication,
- Data: OnuIndicationMessage{
+ msg := bbsim.Message{
+ Type: bbsim.OnuIndication,
+ Data: bbsim.OnuIndicationMessage{
OnuSN: o.SerialNumber,
PonPortID: o.PonPortID,
- OperState: UP,
+ OperState: bbsim.UP,
},
}
o.Channel <- msg
@@ -201,12 +204,12 @@
}
// send the OnuIndication DOWN event
- msg := Message{
- Type: OnuIndication,
- Data: OnuIndicationMessage{
+ msg := bbsim.Message{
+ Type: bbsim.OnuIndication,
+ Data: bbsim.OnuIndicationMessage{
OnuSN: o.SerialNumber,
PonPortID: o.PonPortID,
- OperState: DOWN,
+ OperState: bbsim.DOWN,
},
}
o.Channel <- msg
@@ -223,14 +226,14 @@
},
// BBR states
"enter_eapol_flow_sent": func(e *fsm.Event) {
- msg := Message{
- Type: SendEapolFlow,
+ msg := bbsim.Message{
+ Type: bbsim.SendEapolFlow,
}
o.Channel <- msg
},
"enter_dhcp_flow_sent": func(e *fsm.Event) {
- msg := Message{
- Type: SendDhcpFlow,
+ msg := bbsim.Message{
+ Type: bbsim.SendDhcpFlow,
}
o.Channel <- msg
},
@@ -280,26 +283,45 @@
}).Tracef("Received message on ONU Channel")
switch message.Type {
- case OnuDiscIndication:
- msg, _ := message.Data.(OnuDiscIndicationMessage)
+ case bbsim.OnuDiscIndication:
+ msg, _ := message.Data.(bbsim.OnuDiscIndicationMessage)
// NOTE we need to slow down and send ONU Discovery Indication in batches to better emulate a real scenario
time.Sleep(o.DiscoveryDelay)
o.sendOnuDiscIndication(msg, stream)
- case OnuIndication:
- msg, _ := message.Data.(OnuIndicationMessage)
+ case bbsim.OnuIndication:
+ msg, _ := message.Data.(bbsim.OnuIndicationMessage)
o.sendOnuIndication(msg, stream)
- case OMCI:
- msg, _ := message.Data.(OmciMessage)
- o.handleOmciMessage(msg, stream)
- case FlowAdd:
- msg, _ := message.Data.(OnuFlowUpdateMessage)
+ case bbsim.OMCI:
+ msg, _ := message.Data.(bbsim.OmciMessage)
+ o.handleOmciRequest(msg, stream)
+ case bbsim.UniStatusAlarm:
+ msg, _ := message.Data.(bbsim.UniStatusAlarmMessage)
+ pkt := omcilib.CreateUniStatusAlarm(msg.AdminState, msg.EntityID)
+ if err := o.sendOmciIndication(pkt, 0, stream); err != nil {
+ onuLogger.WithFields(log.Fields{
+ "IntfId": o.PonPortID,
+ "SerialNumber": o.Sn(),
+ "omciPacket": pkt,
+ "adminState": msg.AdminState,
+ "entityID": msg.EntityID,
+ }).Errorf("failed-to-send-UNI-Link-Alarm: %v", err)
+ }
+ onuLogger.WithFields(log.Fields{
+ "IntfId": o.PonPortID,
+ "SerialNumber": o.Sn(),
+ "omciPacket": pkt,
+ "adminState": msg.AdminState,
+ "entityID": msg.EntityID,
+ }).Trace("UNI-Link-alarm-sent")
+ case bbsim.FlowAdd:
+ msg, _ := message.Data.(bbsim.OnuFlowUpdateMessage)
o.handleFlowAdd(msg)
- case FlowRemoved:
- msg, _ := message.Data.(OnuFlowUpdateMessage)
+ case bbsim.FlowRemoved:
+ msg, _ := message.Data.(bbsim.OnuFlowUpdateMessage)
o.handleFlowRemove(msg)
- case OnuPacketOut:
+ case bbsim.OnuPacketOut:
- msg, _ := message.Data.(OnuPacketMessage)
+ msg, _ := message.Data.(bbsim.OnuPacketMessage)
onuLogger.WithFields(log.Fields{
"IntfId": msg.IntfId,
@@ -333,11 +355,11 @@
}
}
- case OnuPacketIn:
+ case bbsim.OnuPacketIn:
// NOTE we only receive BBR packets here.
// Eapol.HandleNextPacket can handle both BBSim and BBr cases so the call is the same
// in the DHCP case VOLTHA only act as a proxy, the behaviour is completely different thus we have a dhcp.HandleNextBbrPacket
- msg, _ := message.Data.(OnuPacketMessage)
+ msg, _ := message.Data.(bbsim.OnuPacketMessage)
log.WithFields(log.Fields{
"IntfId": msg.IntfId,
@@ -351,12 +373,12 @@
_ = dhcp.HandleNextBbrPacket(o.ID, o.PonPortID, o.Sn(), o.DoneChannel, msg.Packet, client)
}
// BBR specific messages
- case OmciIndication:
- msg, _ := message.Data.(OmciIndicationMessage)
- o.handleOmci(msg, client)
- case SendEapolFlow:
+ case bbsim.OmciIndication:
+ msg, _ := message.Data.(bbsim.OmciIndicationMessage)
+ o.handleOmciResponse(msg, client)
+ case bbsim.SendEapolFlow:
o.sendEapolFlow(client)
- case SendDhcpFlow:
+ case bbsim.SendDhcpFlow:
o.sendDhcpFlow(client)
default:
onuLogger.Warnf("Received unknown message data %v for type %v in OLT Channel", message.Data, message.Type)
@@ -369,42 +391,6 @@
}).Debug("Stopped handling ONU Indication Channel")
}
-func (o *Onu) processOmciMessage(message omcisim.OmciChMessage, stream openolt.Openolt_EnableIndicationServer) {
- switch message.Type {
- case omcisim.UniLinkUp, omcisim.UniLinkDown:
- onuLogger.WithFields(log.Fields{
- "OnuId": message.Data.OnuId,
- "IntfId": message.Data.IntfId,
- "Type": message.Type,
- }).Debug("UNI Link Alarm")
- // TODO send to OLT
-
- omciInd := openolt.OmciIndication{
- IntfId: message.Data.IntfId,
- OnuId: message.Data.OnuId,
- Pkt: message.Packet,
- }
-
- omci := &openolt.Indication_OmciInd{OmciInd: &omciInd}
- if err := stream.Send(&openolt.Indication{Data: omci}); err != nil {
- onuLogger.WithFields(log.Fields{
- "IntfId": o.PonPortID,
- "SerialNumber": o.Sn(),
- "Type": message.Type,
- "omciPacket": omciInd.Pkt,
- }).Errorf("Failed to send UNI Link Alarm: %v", err)
- return
- }
-
- onuLogger.WithFields(log.Fields{
- "IntfId": o.PonPortID,
- "SerialNumber": o.Sn(),
- "Type": message.Type,
- "omciPacket": omciInd.Pkt,
- }).Debug("UNI Link alarm sent")
- }
-}
-
func (o Onu) NewSN(oltid int, intfid uint32, onuid uint32) *openolt.SerialNumber {
sn := new(openolt.SerialNumber)
@@ -416,10 +402,10 @@
return sn
}
-func (o *Onu) sendOnuDiscIndication(msg OnuDiscIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
+func (o *Onu) sendOnuDiscIndication(msg bbsim.OnuDiscIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
discoverData := &openolt.Indication_OnuDiscInd{OnuDiscInd: &openolt.OnuDiscIndication{
- IntfId: msg.Onu.PonPortID,
- SerialNumber: msg.Onu.SerialNumber,
+ IntfId: o.PonPortID,
+ SerialNumber: o.SerialNumber,
}}
if err := stream.Send(&openolt.Indication{Data: discoverData}); err != nil {
@@ -428,11 +414,11 @@
}
onuLogger.WithFields(log.Fields{
- "IntfId": msg.Onu.PonPortID,
- "OnuSn": msg.Onu.Sn(),
+ "IntfId": o.PonPortID,
+ "OnuSn": o.Sn(),
"OnuId": o.ID,
}).Debug("Sent Indication_OnuDiscInd")
- publishEvent("ONU-discovery-indication-sent", int32(msg.Onu.PonPortID), int32(o.ID), msg.Onu.Sn())
+ publishEvent("ONU-discovery-indication-sent", int32(o.PonPortID), int32(o.ID), o.Sn())
// after DiscoveryRetryDelay check if the state is the same and in case send a new OnuDiscIndication
go func(delay time.Duration) {
@@ -443,7 +429,7 @@
}(o.DiscoveryRetryDelay)
}
-func (o *Onu) sendOnuIndication(msg OnuIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
+func (o *Onu) sendOnuIndication(msg bbsim.OnuIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
// NOTE voltha returns an ID, but if we use that ID then it complains:
// expected_onu_id: 1, received_onu_id: 1024, event: ONU-id-mismatch, can happen if both voltha and the olt rebooted
// so we're using the internal ID that is 1
@@ -471,17 +457,136 @@
}
-func (o *Onu) publishOmciEvent(msg OmciMessage) {
+func (o *Onu) HandleShutdownONU() error {
+
+ dyingGasp := pb.ONUAlarmRequest{
+ AlarmType: "DYING_GASP",
+ SerialNumber: o.Sn(),
+ Status: "on",
+ }
+
+ if err := alarmsim.SimulateOnuAlarm(&dyingGasp, o.ID, o.PonPortID, o.PonPort.Olt.channel); err != nil {
+ onuLogger.WithFields(log.Fields{
+ "OnuId": o.ID,
+ "IntfId": o.PonPortID,
+ "OnuSn": o.Sn(),
+ }).Errorf("Cannot send Dying Gasp: %s", err.Error())
+ return err
+ }
+
+ losReq := pb.ONUAlarmRequest{
+ AlarmType: "ONU_ALARM_LOS",
+ SerialNumber: o.Sn(),
+ Status: "on",
+ }
+
+ if err := alarmsim.SimulateOnuAlarm(&losReq, o.ID, o.PonPortID, o.PonPort.Olt.channel); err != nil {
+ onuLogger.WithFields(log.Fields{
+ "OnuId": o.ID,
+ "IntfId": o.PonPortID,
+ "OnuSn": o.Sn(),
+ }).Errorf("Cannot send LOS: %s", err.Error())
+
+ return err
+ }
+
+ // TODO if it's the last ONU on the PON, then send a PON LOS
+
+ if err := o.InternalState.Event("disable"); err != nil {
+ onuLogger.WithFields(log.Fields{
+ "OnuId": o.ID,
+ "IntfId": o.PonPortID,
+ "OnuSn": o.Sn(),
+ }).Errorf("Cannot shutdown ONU: %s", err.Error())
+ return err
+ }
+
+ return nil
+}
+
+func (o *Onu) HandlePowerOnONU() error {
+ intitalState := o.InternalState.Current()
+
+ // initialize the ONU
+ if intitalState == "created" || intitalState == "disabled" {
+ if err := o.InternalState.Event("initialize"); err != nil {
+ onuLogger.WithFields(log.Fields{
+ "OnuId": o.ID,
+ "IntfId": o.PonPortID,
+ "OnuSn": o.Sn(),
+ }).Errorf("Cannot poweron ONU: %s", err.Error())
+ return err
+ }
+ }
+
+ // turn off the LOS Alarm
+ losReq := pb.ONUAlarmRequest{
+ AlarmType: "ONU_ALARM_LOS",
+ SerialNumber: o.Sn(),
+ Status: "off",
+ }
+
+ if err := alarmsim.SimulateOnuAlarm(&losReq, o.ID, o.PonPortID, o.PonPort.Olt.channel); err != nil {
+ onuLogger.WithFields(log.Fields{
+ "OnuId": o.ID,
+ "IntfId": o.PonPortID,
+ "OnuSn": o.Sn(),
+ }).Errorf("Cannot send LOS: %s", err.Error())
+ return err
+ }
+
+ // Send a ONU Discovery indication
+ if err := o.InternalState.Event("discover"); err != nil {
+ onuLogger.WithFields(log.Fields{
+ "OnuId": o.ID,
+ "IntfId": o.PonPortID,
+ "OnuSn": o.Sn(),
+ }).Errorf("Cannot poweron ONU: %s", err.Error())
+ return err
+ }
+
+ // move o directly to enable state only when its a powercycle case
+ // in case of first time o poweron o will be moved to enable on
+ // receiving ActivateOnu request from openolt adapter
+ if intitalState == "disabled" {
+ if err := o.InternalState.Event("enable"); err != nil {
+ onuLogger.WithFields(log.Fields{
+ "OnuId": o.ID,
+ "IntfId": o.PonPortID,
+ "OnuSn": o.Sn(),
+ }).Errorf("Cannot enable ONU: %s", err.Error())
+ return err
+ }
+ }
+
+ return nil
+}
+
+func (o *Onu) SetAlarm(alarmType string, status string) error {
+ alarmReq := pb.ONUAlarmRequest{
+ AlarmType: alarmType,
+ SerialNumber: o.Sn(),
+ Status: status,
+ }
+
+ err := alarmsim.SimulateOnuAlarm(&alarmReq, o.ID, o.PonPortID, o.PonPort.Olt.channel)
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+func (o *Onu) publishOmciEvent(msg bbsim.OmciMessage) {
if olt.PublishEvents {
- _, _, msgType, _, _, _, err := omcisim.ParsePkt(HexDecode(msg.omciMsg.Pkt))
+ _, omciMsg, err := omcilib.ParseOpenOltOmciPacket(msg.OmciMsg.Pkt)
if err != nil {
log.Errorf("error in getting msgType %v", err)
return
}
- if msgType == omcisim.MibUpload {
+ if omciMsg.MessageType == omci.MibUploadRequestType {
o.seqNumber = 0
publishEvent("MIB-upload-received", int32(o.PonPortID), int32(o.ID), common.OnuSnToString(o.SerialNumber))
- } else if msgType == omcisim.MibUploadNext {
+ } else if omciMsg.MessageType == omci.MibUploadNextRequestType {
o.seqNumber++
if o.seqNumber > 290 {
publishEvent("MIB-upload-done", int32(o.PonPortID), int32(o.ID), common.OnuSnToString(o.SerialNumber))
@@ -491,8 +596,8 @@
}
// Create a TestResponse packet and send it
-func (o *Onu) sendTestResult(msg OmciMessage, stream openolt.Openolt_EnableIndicationServer) error {
- resp, err := omcilib.BuildTestResult(HexDecode(msg.omciMsg.Pkt))
+func (o *Onu) sendTestResult(msg bbsim.OmciMessage, stream openolt.Openolt_EnableIndicationServer) error {
+ resp, err := omcilib.BuildTestResult(msg.OmciMsg.Pkt)
if err != nil {
return err
}
@@ -504,12 +609,6 @@
omci := &openolt.Indication_OmciInd{OmciInd: &omciInd}
if err := stream.Send(&openolt.Indication{Data: omci}); err != nil {
- onuLogger.WithFields(log.Fields{
- "IntfId": o.PonPortID,
- "SerialNumber": o.Sn(),
- "omciPacket": omciInd.Pkt,
- "msg": msg,
- }).Errorf("send TestResult omcisim indication failed: %v", err)
return err
}
onuLogger.WithFields(log.Fields{
@@ -521,57 +620,151 @@
return nil
}
-func (o *Onu) handleOmciMessage(msg OmciMessage, stream openolt.Openolt_EnableIndicationServer) {
+// handleOmciRequest is responsible to parse the OMCI packets received from the openolt adapter
+// and generate the appropriate response to it
+func (o *Onu) handleOmciRequest(msg bbsim.OmciMessage, stream openolt.Openolt_EnableIndicationServer) {
+
+ omciPkt, omciMsg, err := omcilib.ParseOpenOltOmciPacket(msg.OmciMsg.Pkt)
+ if err != nil {
+ log.WithFields(log.Fields{
+ "IntfId": o.PonPortID,
+ "SerialNumber": o.Sn(),
+ "omciPacket": msg.OmciMsg.Pkt,
+ }).Error("cannot-parse-OMCI-packet")
+ }
onuLogger.WithFields(log.Fields{
+ "omciMsgType": omciMsg.MessageType,
+ "transCorrId": strconv.FormatInt(int64(omciMsg.TransactionID), 16),
+ "DeviceIdent": omciMsg.DeviceIdentifier,
"IntfId": o.PonPortID,
"SerialNumber": o.Sn(),
- "omciPacket": msg.omciMsg.Pkt,
- }).Tracef("Received OMCI message")
+ }).Trace("omci-message-decoded")
+
+ var responsePkt []byte
+ switch omciMsg.MessageType {
+ case omci.MibResetRequestType:
+ responsePkt, _ = omcilib.CreateMibResetResponse(omciMsg.TransactionID)
+ case omci.MibUploadRequestType:
+ responsePkt, _ = omcilib.CreateMibUploadResponse(omciMsg.TransactionID)
+ case omci.MibUploadNextRequestType:
+ responsePkt, _ = omcilib.CreateMibUploadNextResponse(omciPkt, omciMsg)
+ case omci.GetRequestType:
+ responsePkt, _ = omcilib.CreateGetResponse(omciPkt, omciMsg)
+ case omci.SetRequestType:
+ responsePkt, _ = omcilib.CreateSetResponse(omciPkt, omciMsg)
+
+ msgObj, _ := omcilib.ParseSetRequest(omciPkt)
+ switch msgObj.EntityClass {
+ case me.PhysicalPathTerminationPointEthernetUniClassID:
+ // if we're Setting a PPTP state
+ // we need to send the appropriate alarm
+
+ if msgObj.EntityInstance == 257 {
+ // for now we're only caring about the first UNI
+ // NOTE that the EntityID for the UNI port is for now hardcoded in
+ // omci/mibpackets.go where the PhysicalPathTerminationPointEthernetUni
+ // are reported during the MIB Upload sequence
+ adminState := msgObj.Attributes["AdministrativeState"].(uint8)
+ msg := bbsim.Message{
+ Type: bbsim.UniStatusAlarm,
+ Data: bbsim.UniStatusAlarmMessage{
+ OnuSN: o.SerialNumber,
+ OnuID: o.ID,
+ AdminState: adminState,
+ EntityID: msgObj.EntityInstance,
+ },
+ }
+ o.Channel <- msg
+ }
+ }
+ case omci.CreateRequestType:
+ responsePkt, _ = omcilib.CreateCreateResponse(omciPkt, omciMsg)
+ case omci.DeleteRequestType:
+ responsePkt, _ = omcilib.CreateDeleteResponse(omciPkt, omciMsg)
+ case omci.RebootRequestType:
+
+ responsePkt, _ = omcilib.CreateRebootResponse(omciPkt, omciMsg)
+
+ // powercycle the ONU
+ go func() {
+ // we run this in a separate goroutine so that
+ // the RebootRequestResponse is sent to VOLTHA
+ onuLogger.WithFields(log.Fields{
+ "IntfId": o.PonPortID,
+ "SerialNumber": o.Sn(),
+ }).Debug("shutting-down-onu-for-omci-reboot")
+ _ = o.HandleShutdownONU()
+ time.Sleep(10 * time.Second)
+ onuLogger.WithFields(log.Fields{
+ "IntfId": o.PonPortID,
+ "SerialNumber": o.Sn(),
+ }).Debug("power-on-onu-for-omci-reboot")
+ _ = o.HandlePowerOnONU()
+ }()
+ case omci.TestRequestType:
+
+ // Test message is special, it requires sending two packets:
+ // first packet: TestResponse, says whether test was started successully, handled by omci-sim
+ // second packet, TestResult, reports the result of running the self-test
+ // TestResult can come some time after a TestResponse
+ // TODO: Implement some delay between the TestResponse and the TestResult
+ isTest, err := omcilib.IsTestRequest(msg.OmciMsg.Pkt)
+ if (err == nil) && (isTest) {
+ if sendErr := o.sendTestResult(msg, stream); sendErr != nil {
+ onuLogger.WithFields(log.Fields{
+ "IntfId": o.PonPortID,
+ "SerialNumber": o.Sn(),
+ "omciPacket": msg.OmciMsg.Pkt,
+ "msg": msg,
+ "err": sendErr,
+ }).Error("send-TestResult-indication-failed")
+ }
+ }
+
+ default:
+ log.WithFields(log.Fields{
+ "omciMsgType": omciMsg.MessageType,
+ "transCorrId": omciMsg.TransactionID,
+ "IntfId": o.PonPortID,
+ "SerialNumber": o.Sn(),
+ }).Warnf("OMCI-message-not-supported")
+ }
+
+ if responsePkt != nil {
+ if err := o.sendOmciIndication(responsePkt, omciMsg.TransactionID, stream); err != nil {
+ onuLogger.WithFields(log.Fields{
+ "IntfId": o.PonPortID,
+ "SerialNumber": o.Sn(),
+ "omciPacket": responsePkt,
+ "omciMsgType": omciMsg.MessageType,
+ "transCorrId": omciMsg.TransactionID,
+ }).Errorf("failed-to-send-omci-message: %v", err)
+ }
+ }
o.publishOmciEvent(msg)
+}
- var omciInd openolt.OmciIndication
- respPkt, err := omcisim.OmciSim(o.PonPort.Olt.ID, o.PonPortID, o.ID, HexDecode(msg.omciMsg.Pkt))
- if err != nil {
- onuLogger.WithFields(log.Fields{
- "IntfId": o.PonPortID,
- "SerialNumber": o.Sn(),
- "omciPacket": omciInd.Pkt,
- "msg": msg,
- }).Errorf("Error handling OMCI message %v", msg)
- return
+// sendOmciIndication takes an OMCI packet and sends it up to VOLTHA
+func (o *Onu) sendOmciIndication(responsePkt []byte, txId uint16, stream bbsim.Stream) error {
+ indication := &openolt.Indication_OmciInd{
+ OmciInd: &openolt.OmciIndication{
+ IntfId: o.PonPortID,
+ OnuId: o.ID,
+ Pkt: responsePkt,
+ },
}
-
- omciInd.IntfId = o.PonPortID
- omciInd.OnuId = o.ID
- omciInd.Pkt = respPkt
-
- omci := &openolt.Indication_OmciInd{OmciInd: &omciInd}
- if err := stream.Send(&openolt.Indication{Data: omci}); err != nil {
- onuLogger.WithFields(log.Fields{
- "IntfId": o.PonPortID,
- "SerialNumber": o.Sn(),
- "omciPacket": omciInd.Pkt,
- "msg": msg,
- }).Errorf("send omcisim indication failed: %v", err)
- return
+ if err := stream.Send(&openolt.Indication{Data: indication}); err != nil {
+ return fmt.Errorf("failed-to-send-omci-message: %v", err)
}
onuLogger.WithFields(log.Fields{
"IntfId": o.PonPortID,
"SerialNumber": o.Sn(),
- "omciPacket": omciInd.Pkt,
- }).Tracef("Sent OMCI message")
-
- // Test message is special, it requires sending two packets:
- // first packet: TestResponse, says whether test was started successully, handled by omci-sim
- // second packet, TestResult, reports the result of running the self-test
- // TestResult can come some time after a TestResponse
- // TODO: Implement some delay between the TestResponse and the TestResult
- isTest, err := omcilib.IsTestRequest(HexDecode(msg.omciMsg.Pkt))
- if (err == nil) && (isTest) {
- _ = o.sendTestResult(msg, stream)
- }
+ "omciPacket": indication.OmciInd.Pkt,
+ "transCorrId": txId,
+ }).Trace("omci-message-sent")
+ return nil
}
func (o *Onu) storePortNumber(portNo uint32) {
@@ -602,7 +795,7 @@
o.ID = id
}
-func (o *Onu) handleFlowAdd(msg OnuFlowUpdateMessage) {
+func (o *Onu) handleFlowAdd(msg bbsim.OnuFlowUpdateMessage) {
onuLogger.WithFields(log.Fields{
"Cookie": msg.Flow.Cookie,
"DstPort": msg.Flow.Classifier.DstPort,
@@ -667,7 +860,7 @@
}
}
-func (o *Onu) handleFlowRemove(msg OnuFlowUpdateMessage) {
+func (o *Onu) handleFlowRemove(msg bbsim.OnuFlowUpdateMessage) {
onuLogger.WithFields(log.Fields{
"IntfId": o.PonPortID,
"OnuId": o.ID,
@@ -700,19 +893,6 @@
}
}
-// HexDecode converts the hex encoding to binary
-func HexDecode(pkt []byte) []byte {
- p := make([]byte, len(pkt)/2)
- for i, j := 0, 0; i < len(pkt); i, j = i+2, j+1 {
- // Go figure this ;)
- u := (pkt[i] & 15) + (pkt[i]>>6)*9
- l := (pkt[i+1] & 15) + (pkt[i+1]>>6)*9
- p[j] = u<<4 + l
- }
- onuLogger.Tracef("Omci decoded: %x.", p)
- return p
-}
-
// BBR methods
func sendOmciMsg(pktBytes []byte, intfId uint32, onuId uint32, sn *openolt.SerialNumber, msgType string, client openolt.OpenoltClient) {
@@ -762,24 +942,36 @@
sendOmciMsg(mibReset, o.PonPortID, o.ID, o.SerialNumber, "mibReset", client)
}
-func (o *Onu) handleOmci(msg OmciIndicationMessage, client openolt.OpenoltClient) {
- msgType, packet := omcilib.DecodeOmci(msg.OmciInd.Pkt)
+// handleOmciResponse is used in BBR to generate the OMCI packets the openolt-adapter would send to the device
+func (o *Onu) handleOmciResponse(msg bbsim.OmciIndicationMessage, client openolt.OpenoltClient) {
+
+ // we need to encode the packet in HEX
+ pkt := make([]byte, len(msg.OmciInd.Pkt)*2)
+ hex.Encode(pkt, msg.OmciInd.Pkt)
+ packet, omciMsg, err := omcilib.ParseOpenOltOmciPacket(pkt)
+ if err != nil {
+ log.WithFields(log.Fields{
+ "IntfId": o.PonPortID,
+ "SerialNumber": o.Sn(),
+ "omciPacket": msg.OmciInd.Pkt,
+ }).Error("BBR Cannot parse OMCI packet")
+ }
log.WithFields(log.Fields{
"IntfId": msg.OmciInd.IntfId,
"OnuId": msg.OmciInd.OnuId,
- "OnuSn": common.OnuSnToString(o.SerialNumber),
+ "OnuSn": o.Sn(),
"Pkt": msg.OmciInd.Pkt,
- "msgType": msgType,
+ "msgType": omciMsg.MessageType,
}).Trace("ONU Receives OMCI Msg")
- switch msgType {
+ switch omciMsg.MessageType {
default:
log.WithFields(log.Fields{
"IntfId": msg.OmciInd.IntfId,
"OnuId": msg.OmciInd.OnuId,
- "OnuSn": common.OnuSnToString(o.SerialNumber),
+ "OnuSn": o.Sn(),
"Pkt": msg.OmciInd.Pkt,
- "msgType": msgType,
+ "msgType": omciMsg.MessageType,
}).Fatalf("unexpected frame: %v", packet)
case omci.MibResetResponseType:
mibUpload, _ := omcilib.CreateMibUploadRequest(o.getNextTid(false))
diff --git a/internal/bbsim/devices/onu_flow_test.go b/internal/bbsim/devices/onu_flow_test.go
index 1464ae5..e0ad9fe 100644
--- a/internal/bbsim/devices/onu_flow_test.go
+++ b/internal/bbsim/devices/onu_flow_test.go
@@ -19,6 +19,7 @@
import (
"github.com/google/gopacket/layers"
"github.com/looplab/fsm"
+ "github.com/opencord/bbsim/internal/bbsim/types"
"github.com/opencord/voltha-protos/v4/go/openolt"
"gotest.tools/assert"
"testing"
@@ -54,7 +55,7 @@
FlowId: 64,
Classifier: &openolt.Classifier{},
}
- msg := OnuFlowUpdateMessage{
+ msg := types.OnuFlowUpdateMessage{
OnuID: onu.ID,
PonPortID: onu.PonPortID,
Flow: &flow,
@@ -74,7 +75,7 @@
FlowId: 64,
Classifier: &openolt.Classifier{},
}
- msg := OnuFlowUpdateMessage{
+ msg := types.OnuFlowUpdateMessage{
OnuID: onu.ID,
PonPortID: onu.PonPortID,
Flow: &flow,
@@ -107,7 +108,7 @@
FlowId: 64,
Classifier: &openolt.Classifier{},
}
- msg := OnuFlowUpdateMessage{
+ msg := types.OnuFlowUpdateMessage{
OnuID: onu.ID,
PonPortID: onu.PonPortID,
Flow: &flow,
@@ -147,7 +148,7 @@
PortNo: uint32(onu.ID), // NOTE we are using this to map an incoming packetIndication to an ONU
}
- msg := OnuFlowUpdateMessage{
+ msg := types.OnuFlowUpdateMessage{
PonPortID: 1,
OnuID: 1,
Flow: &flow,
@@ -194,7 +195,7 @@
PortNo: uint32(onu.ID), // NOTE we are using this to map an incoming packetIndication to an ONU
}
- msg := OnuFlowUpdateMessage{
+ msg := types.OnuFlowUpdateMessage{
PonPortID: 1,
OnuID: 1,
Flow: &flow,
@@ -235,7 +236,7 @@
PortNo: uint32(onu.ID), // NOTE we are using this to map an incoming packetIndication to an ONU
}
- msg := OnuFlowUpdateMessage{
+ msg := types.OnuFlowUpdateMessage{
PonPortID: 1,
OnuID: 1,
Flow: &flow,
@@ -279,7 +280,7 @@
PortNo: uint32(onu.ID), // NOTE we are using this to map an incoming packetIndication to an ONU
}
- msg := OnuFlowUpdateMessage{
+ msg := types.OnuFlowUpdateMessage{
PonPortID: 1,
OnuID: 1,
Flow: &flow,
@@ -323,7 +324,7 @@
PortNo: uint32(onu.ID), // NOTE we are using this to map an incoming packetIndication to an ONU
}
- msg := OnuFlowUpdateMessage{
+ msg := types.OnuFlowUpdateMessage{
PonPortID: 1,
OnuID: 1,
Flow: &flow,
@@ -367,7 +368,7 @@
PortNo: uint32(onu.ID), // NOTE we are using this to map an incoming packetIndication to an ONU
}
- msg := OnuFlowUpdateMessage{
+ msg := types.OnuFlowUpdateMessage{
PonPortID: 1,
OnuID: 1,
Flow: &flow,
@@ -409,7 +410,7 @@
PortNo: uint32(onu.ID), // NOTE we are using this to map an incoming packetIndication to an ONU
}
- msg := OnuFlowUpdateMessage{
+ msg := types.OnuFlowUpdateMessage{
PonPortID: 1,
OnuID: 1,
Flow: &flow,
@@ -457,7 +458,7 @@
PortNo: uint32(onu.ID), // NOTE we are using this to map an incoming packetIndication to an ONU
}
- msg := OnuFlowUpdateMessage{
+ msg := types.OnuFlowUpdateMessage{
PonPortID: 1,
OnuID: 1,
Flow: &flow,
diff --git a/internal/bbsim/devices/onu_test_helpers.go b/internal/bbsim/devices/onu_test_helpers.go
index 89eb195..ef6e4a2 100644
--- a/internal/bbsim/devices/onu_test_helpers.go
+++ b/internal/bbsim/devices/onu_test_helpers.go
@@ -19,6 +19,7 @@
import (
"context"
"errors"
+ "github.com/opencord/bbsim/internal/bbsim/types"
"github.com/opencord/voltha-protos/v4/go/common"
"github.com/opencord/voltha-protos/v4/go/ext/config"
"time"
@@ -137,7 +138,7 @@
},
}
o.SerialNumber = o.NewSN(0, ponPortId, o.ID)
- o.Channel = make(chan Message, 10)
+ o.Channel = make(chan types.Message, 10)
return &o
}
diff --git a/internal/bbsim/devices/services.go b/internal/bbsim/devices/services.go
index bd4d13c..4391414 100644
--- a/internal/bbsim/devices/services.go
+++ b/internal/bbsim/devices/services.go
@@ -71,9 +71,9 @@
EapolState *fsm.FSM
DHCPState *fsm.FSM
IGMPState *fsm.FSM
- Channel chan Message // drive Service lifecycle
- PacketCh chan OnuPacketMessage // handle packets
- Stream bbsimTypes.Stream // the gRPC stream to communicate with the adapter, created in the initialize transition
+ Channel chan bbsimTypes.Message // drive Service lifecycle
+ PacketCh chan bbsimTypes.OnuPacketMessage // handle packets
+ Stream bbsimTypes.Stream // the gRPC stream to communicate with the adapter, created in the initialize transition
}
func NewService(name string, hwAddress net.HardwareAddr, onu *Onu, cTag int, sTag int,
@@ -117,8 +117,8 @@
service.Stream = stream
- service.PacketCh = make(chan OnuPacketMessage)
- service.Channel = make(chan Message)
+ service.PacketCh = make(chan bbsimTypes.OnuPacketMessage)
+ service.Channel = make(chan bbsimTypes.Message)
go service.HandlePackets()
go service.HandleChannel()
@@ -153,8 +153,8 @@
service.logStateChange("EapolState", e.Src, e.Dst)
},
"before_start_auth": func(e *fsm.Event) {
- msg := Message{
- Type: StartEAPOL,
+ msg := bbsimTypes.Message{
+ Type: bbsimTypes.StartEAPOL,
}
service.Channel <- msg
},
@@ -207,8 +207,8 @@
service.logStateChange("DHCPState", e.Src, e.Dst)
},
"before_start_dhcp": func(e *fsm.Event) {
- msg := Message{
- Type: StartDHCP,
+ msg := bbsimTypes.Message{
+ Type: bbsimTypes.StartDHCP,
}
service.Channel <- msg
},
@@ -255,30 +255,30 @@
},
fsm.Callbacks{
"igmp_join_start": func(e *fsm.Event) {
- igmpInfo, _ := e.Args[0].(IgmpMessage)
- msg := Message{
- Type: IGMPMembershipReportV2,
- Data: IgmpMessage{
+ igmpInfo, _ := e.Args[0].(bbsimTypes.IgmpMessage)
+ msg := bbsimTypes.Message{
+ Type: bbsimTypes.IGMPMembershipReportV2,
+ Data: bbsimTypes.IgmpMessage{
GroupAddress: igmpInfo.GroupAddress,
},
}
service.Channel <- msg
},
"igmp_leave": func(e *fsm.Event) {
- igmpInfo, _ := e.Args[0].(IgmpMessage)
- msg := Message{
- Type: IGMPLeaveGroup,
- Data: IgmpMessage{
+ igmpInfo, _ := e.Args[0].(bbsimTypes.IgmpMessage)
+ msg := bbsimTypes.Message{
+ Type: bbsimTypes.IGMPLeaveGroup,
+ Data: bbsimTypes.IgmpMessage{
GroupAddress: igmpInfo.GroupAddress,
},
}
service.Channel <- msg
},
"igmp_join_startv3": func(e *fsm.Event) {
- igmpInfo, _ := e.Args[0].(IgmpMessage)
- msg := Message{
- Type: IGMPMembershipReportV3,
- Data: IgmpMessage{
+ igmpInfo, _ := e.Args[0].(bbsimTypes.IgmpMessage)
+ msg := bbsimTypes.Message{
+ Type: bbsimTypes.IGMPMembershipReportV3,
+ Data: bbsimTypes.IgmpMessage{
GroupAddress: igmpInfo.GroupAddress,
},
}
@@ -411,7 +411,7 @@
}()
for msg := range s.Channel {
switch msg.Type {
- case StartEAPOL:
+ case bbsimTypes.StartEAPOL:
if err := s.handleEapolStart(s.Stream); err != nil {
serviceLogger.WithFields(log.Fields{
"OnuId": s.Onu.ID,
@@ -422,7 +422,7 @@
}).Error("Error while sending EapolStart packet")
_ = s.EapolState.Event("auth_failed")
}
- case StartDHCP:
+ case bbsimTypes.StartDHCP:
if err := s.handleDHCPStart(s.Stream); err != nil {
serviceLogger.WithFields(log.Fields{
"OnuId": s.Onu.ID,
@@ -434,8 +434,8 @@
_ = s.DHCPState.Event("dhcp_failed")
}
- case IGMPMembershipReportV2:
- igmpInfo, _ := msg.Data.(IgmpMessage)
+ case bbsimTypes.IGMPMembershipReportV2:
+ igmpInfo, _ := msg.Data.(bbsimTypes.IgmpMessage)
serviceLogger.WithFields(log.Fields{
"OnuId": s.Onu.ID,
"IntfId": s.Onu.PonPortID,
@@ -443,8 +443,8 @@
"Name": s.Name,
}).Debug("Received IGMPMembershipReportV2 message on ONU channel")
_ = igmp.SendIGMPMembershipReportV2(s.Onu.PonPortID, s.Onu.ID, s.Onu.Sn(), s.Onu.PortNo, s.GemPort, s.HwAddress, s.CTag, s.UsPonCTagPriority, s.Stream, igmpInfo.GroupAddress)
- case IGMPLeaveGroup:
- igmpInfo, _ := msg.Data.(IgmpMessage)
+ case bbsimTypes.IGMPLeaveGroup:
+ igmpInfo, _ := msg.Data.(bbsimTypes.IgmpMessage)
serviceLogger.WithFields(log.Fields{
"OnuId": s.Onu.ID,
"IntfId": s.Onu.PonPortID,
@@ -452,8 +452,8 @@
"Name": s.Name,
}).Debug("Received IGMPLeaveGroupV2 message on ONU channel")
_ = igmp.SendIGMPLeaveGroupV2(s.Onu.PonPortID, s.Onu.ID, s.Onu.Sn(), s.Onu.PortNo, s.GemPort, s.HwAddress, s.CTag, s.UsPonCTagPriority, s.Stream, igmpInfo.GroupAddress)
- case IGMPMembershipReportV3:
- igmpInfo, _ := msg.Data.(IgmpMessage)
+ case bbsimTypes.IGMPMembershipReportV3:
+ igmpInfo, _ := msg.Data.(bbsimTypes.IgmpMessage)
serviceLogger.WithFields(log.Fields{
"OnuId": s.Onu.ID,
"IntfId": s.Onu.PonPortID,
diff --git a/internal/bbsim/responders/eapol/eapol.go b/internal/bbsim/responders/eapol/eapol.go
index 0860935..688728c 100644
--- a/internal/bbsim/responders/eapol/eapol.go
+++ b/internal/bbsim/responders/eapol/eapol.go
@@ -26,7 +26,6 @@
"github.com/google/gopacket/layers"
"github.com/looplab/fsm"
bbsim "github.com/opencord/bbsim/internal/bbsim/types"
- omci "github.com/opencord/omci-sim"
"github.com/opencord/voltha-protos/v4/go/openolt"
log "github.com/sirupsen/logrus"
)
@@ -36,7 +35,6 @@
})
var eapolVersion uint8 = 1
-var GetGemPortId = omci.GetGemPortId
func sendEapolPktIn(msg bbsim.ByteMsg, portNo uint32, gemid uint32, stream bbsim.Stream) error {
// FIXME unify sendDHCPPktIn and sendEapolPktIn methods
diff --git a/internal/bbsim/responders/eapol/eapol_test.go b/internal/bbsim/responders/eapol/eapol_test.go
index 248fd3d..69f941f 100644
--- a/internal/bbsim/responders/eapol/eapol_test.go
+++ b/internal/bbsim/responders/eapol/eapol_test.go
@@ -94,14 +94,6 @@
eapolStateMachine.SetState("auth_started")
- // Save current function and restore at the end:
- old := GetGemPortId
- defer func() { GetGemPortId = old }()
-
- GetGemPortId = func(oltId int, intfId uint32, onuId uint32) (uint16, error) {
- return 1, nil
- }
-
stream := &mockStream{
Calls: make(map[int]*openolt.PacketIndication),
fail: true,
diff --git a/internal/bbsim/devices/messageTypes.go b/internal/bbsim/types/messageTypes.go
similarity index 89%
rename from internal/bbsim/devices/messageTypes.go
rename to internal/bbsim/types/messageTypes.go
index 144e1b9..3afe7fb 100644
--- a/internal/bbsim/devices/messageTypes.go
+++ b/internal/bbsim/types/messageTypes.go
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package devices
+package types
import (
"github.com/google/gopacket"
@@ -50,6 +50,7 @@
AlarmIndication MessageType = 16 // message data is an openolt.AlarmIndication
IGMPMembershipReportV3 MessageType = 17 // Version 3 Membership Report
+ UniStatusAlarm MessageType = 19
)
func (m MessageType) String() string {
@@ -72,6 +73,7 @@
"IGMPLeaveGroup",
"IGMPMembershipReportV3",
"FlowRemoved",
+ "UniStatusAlarm",
}
return names[m]
}
@@ -97,7 +99,6 @@
type OnuDiscIndicationMessage struct {
OperState OperState
- Onu *Onu
}
type OnuIndicationMessage struct {
@@ -107,12 +108,23 @@
OnuSN *openolt.SerialNumber
}
+// these are OMCI messages going from VOLTHA to the OLT
+// used by BBSim
type OmciMessage struct {
OnuSN *openolt.SerialNumber
OnuID uint32
- omciMsg *openolt.OmciMsg
+ OmciMsg *openolt.OmciMsg
}
+type UniStatusAlarmMessage struct {
+ OnuSN *openolt.SerialNumber
+ OnuID uint32
+ AdminState uint8
+ EntityID uint16
+}
+
+// these are OMCI messages going from the OLT to VOLTHA
+// these messages are received by BBR
type OmciIndicationMessage struct {
OnuSN *openolt.SerialNumber
OnuID uint32
diff --git a/internal/common/omci/alarms.go b/internal/common/omci/alarms.go
new file mode 100644
index 0000000..aaa2fdd
--- /dev/null
+++ b/internal/common/omci/alarms.go
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2018-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 omci
+
+// CreateUniStatusAlarm will generate an Alarm packet to report that the Link is UP or DOWN
+// as a consequence of a SetRequest on PhysicalPathTerminationPointEthernetUniClassID
+func CreateUniStatusAlarm(adminState uint8, entityId uint16) []byte {
+
+ // TODO generate using omci-lib-go
+ linkMsgDown := []byte{
+ 0x00, 0x00, 0x10, 0x0a, 0x00, 0x0b, 0x01, 0x01,
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
+
+ linkMsgUp := []byte{
+ 0x00, 0x00, 0x10, 0x0a, 0x00, 0x0b, 0x01, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
+
+ if adminState == 0 {
+ return linkMsgUp
+ } else if adminState == 1 {
+ return linkMsgDown
+ }
+
+ return nil
+}
diff --git a/internal/common/omci/create.go b/internal/common/omci/create.go
new file mode 100644
index 0000000..8e4afb3
--- /dev/null
+++ b/internal/common/omci/create.go
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2018-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 omci
+
+import (
+ "encoding/hex"
+ "errors"
+ "github.com/google/gopacket"
+ "github.com/opencord/omci-lib-go"
+ me "github.com/opencord/omci-lib-go/generated"
+ log "github.com/sirupsen/logrus"
+ "strconv"
+)
+
+func ParseCreateRequest(omciPkt gopacket.Packet) (*omci.CreateRequest, error) {
+ msgLayer := omciPkt.Layer(omci.LayerTypeCreateRequest)
+ if msgLayer == nil {
+ err := "omci Msg layer could not be detected for LayerTypeCreateRequest"
+ omciLogger.Error(err)
+ return nil, errors.New(err)
+ }
+ msgObj, msgOk := msgLayer.(*omci.CreateRequest)
+ if !msgOk {
+ err := "omci Msg layer could not be assigned for LayerTypeCreateRequest"
+ omciLogger.Error(err)
+ return nil, errors.New(err)
+ }
+ return msgObj, nil
+}
+
+func CreateCreateResponse(omciPkt gopacket.Packet, omciMsg *omci.OMCI) ([]byte, error) {
+
+ msgObj, err := ParseCreateRequest(omciPkt)
+
+ if err != nil {
+ return nil, err
+ }
+
+ omciLogger.WithFields(log.Fields{
+ "EntityClass": msgObj.EntityClass,
+ "EntityInstance": msgObj.EntityInstance,
+ }).Trace("recevied-omci-create-request")
+
+ response := &omci.CreateResponse{
+ MeBasePacket: omci.MeBasePacket{
+ EntityClass: msgObj.EntityClass,
+ EntityInstance: msgObj.EntityInstance,
+ },
+ Result: me.Success,
+ }
+
+ pkt, err := serialize(omci.CreateResponseType, response, omciMsg.TransactionID)
+ if err != nil {
+ omciLogger.WithFields(log.Fields{
+ "Err": err,
+ }).Error("cannot-serialize-CreateResponse")
+ return nil, err
+ }
+
+ log.WithFields(log.Fields{
+ "TxID": strconv.FormatInt(int64(omciMsg.TransactionID), 16),
+ "pkt": hex.EncodeToString(pkt),
+ }).Trace("omci-create-response")
+
+ return pkt, nil
+}
+
+// methods used by BBR to drive the OMCI state machine
+
+func CreateGalEnetRequest(tid uint16) ([]byte, error) {
+ params := me.ParamData{
+ EntityID: galEthernetEID,
+ Attributes: me.AttributeValueMap{"MaximumGemPayloadSize": maxGemPayloadSize},
+ }
+ meDef, _ := me.NewGalEthernetProfile(params)
+ pkt, err := omci.GenFrame(meDef, omci.CreateRequestType, omci.TransactionID(tid))
+ if err != nil {
+ omciLogger.WithField("err", err).Fatalf("Can't generate GalEnetRequest")
+ }
+ return hexEncode(pkt)
+}
+
+func CreateEnableUniRequest(tid uint16, uniId uint16, enabled bool, isPtp bool) ([]byte, error) {
+
+ var _enabled uint8
+ if enabled {
+ _enabled = uint8(1)
+ } else {
+ _enabled = uint8(0)
+ }
+
+ data := me.ParamData{
+ EntityID: uniId,
+ Attributes: me.AttributeValueMap{
+ "AdministrativeState": _enabled,
+ },
+ }
+ var medef *me.ManagedEntity
+ var omciErr me.OmciErrors
+
+ if isPtp {
+ medef, omciErr = me.NewPhysicalPathTerminationPointEthernetUni(data)
+ } else {
+ medef, omciErr = me.NewVirtualEthernetInterfacePoint(data)
+ }
+ if omciErr != nil {
+ return nil, omciErr.GetError()
+ }
+ pkt, err := omci.GenFrame(medef, omci.SetRequestType, omci.TransactionID(tid))
+ if err != nil {
+ omciLogger.WithField("err", err).Fatalf("Can't generate EnableUniRequest")
+ }
+ return hexEncode(pkt)
+}
+
+func CreateGemPortRequest(tid uint16) ([]byte, error) {
+ params := me.ParamData{
+ EntityID: gemEID,
+ Attributes: me.AttributeValueMap{
+ "PortId": 1,
+ "TContPointer": 1,
+ "Direction": 0,
+ "TrafficManagementPointerForUpstream": 0,
+ "TrafficDescriptorProfilePointerForUpstream": 0,
+ "UniCounter": 0,
+ "PriorityQueuePointerForDownStream": 0,
+ "EncryptionState": 0,
+ "TrafficDescriptorProfilePointerForDownstream": 0,
+ "EncryptionKeyRing": 0,
+ },
+ }
+ meDef, _ := me.NewGemPortNetworkCtp(params)
+ pkt, err := omci.GenFrame(meDef, omci.CreateRequestType, omci.TransactionID(tid))
+ if err != nil {
+ omciLogger.WithField("err", err).Fatalf("Can't generate GemPortRequest")
+ }
+ return hexEncode(pkt)
+}
diff --git a/internal/common/omci/delete.go b/internal/common/omci/delete.go
new file mode 100644
index 0000000..c38d696
--- /dev/null
+++ b/internal/common/omci/delete.go
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2018-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 omci
+
+import (
+ "errors"
+ "github.com/google/gopacket"
+ "github.com/opencord/omci-lib-go"
+ me "github.com/opencord/omci-lib-go/generated"
+ log "github.com/sirupsen/logrus"
+)
+
+func ParseDeleteRequest(omciPkt gopacket.Packet) (*omci.DeleteRequest, error) {
+ msgLayer := omciPkt.Layer(omci.LayerTypeDeleteRequest)
+ if msgLayer == nil {
+ err := "omci Msg layer could not be detected for LayerTypeDeleteRequest"
+ omciLogger.Error(err)
+ return nil, errors.New(err)
+ }
+ msgObj, msgOk := msgLayer.(*omci.DeleteRequest)
+ if !msgOk {
+ err := "omci Msg layer could not be assigned for LayerTypeDeleteRequest"
+ omciLogger.Error(err)
+ return nil, errors.New(err)
+ }
+ return msgObj, nil
+}
+
+func CreateDeleteResponse(omciPkt gopacket.Packet, omciMsg *omci.OMCI) ([]byte, error) {
+ msgObj, err := ParseDeleteRequest(omciPkt)
+
+ if err != nil {
+ return nil, err
+ }
+
+ omciLogger.WithFields(log.Fields{
+ "EntityClass": msgObj.EntityClass,
+ "EntityInstance": msgObj.EntityInstance,
+ }).Trace("recevied-omci-delete-request")
+
+ response := &omci.DeleteResponse{
+ MeBasePacket: omci.MeBasePacket{
+ EntityClass: msgObj.EntityClass,
+ EntityInstance: msgObj.EntityInstance,
+ },
+ Result: me.Success,
+ }
+
+ pkt, err := serialize(omci.DeleteResponseType, response, omciMsg.TransactionID)
+ if err != nil {
+ omciLogger.WithFields(log.Fields{
+ "Err": err,
+ }).Error("cannot-serialize-DeleteResponse")
+ return nil, err
+ }
+
+ return pkt, nil
+}
diff --git a/internal/common/omci/get.go b/internal/common/omci/get.go
new file mode 100644
index 0000000..64a7968
--- /dev/null
+++ b/internal/common/omci/get.go
@@ -0,0 +1,344 @@
+/*
+ * Copyright 2018-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 omci
+
+import (
+ "encoding/hex"
+ "errors"
+ "fmt"
+ "github.com/google/gopacket"
+ "github.com/opencord/omci-lib-go"
+ me "github.com/opencord/omci-lib-go/generated"
+ log "github.com/sirupsen/logrus"
+ "strconv"
+)
+
+func ParseGetRequest(omciPkt gopacket.Packet) (*omci.GetRequest, error) {
+ msgLayer := omciPkt.Layer(omci.LayerTypeGetRequest)
+ if msgLayer == nil {
+ err := "omci Msg layer could not be detected for LayerTypeGetRequest"
+ omciLogger.Error(err)
+ return nil, errors.New(err)
+ }
+ msgObj, msgOk := msgLayer.(*omci.GetRequest)
+ if !msgOk {
+ err := "omci Msg layer could not be assigned for LayerTypeGetRequest"
+ omciLogger.Error(err)
+ return nil, errors.New(err)
+ }
+ return msgObj, nil
+}
+
+func CreateGetResponse(omciPkt gopacket.Packet, omciMsg *omci.OMCI) ([]byte, error) {
+
+ msgObj, err := ParseGetRequest(omciPkt)
+
+ if err != nil {
+ return nil, err
+ }
+
+ omciLogger.WithFields(log.Fields{
+ "EntityClass": msgObj.EntityClass,
+ "EntityInstance": msgObj.EntityInstance,
+ "AttributeMask": fmt.Sprintf("%x", msgObj.AttributeMask),
+ }).Trace("recevied-omci-get-request")
+
+ var response *omci.GetResponse
+ switch msgObj.EntityClass {
+ case me.Onu2GClassID:
+ response = createOnu2gResponse(msgObj.AttributeMask, msgObj.EntityInstance)
+ case me.OnuGClassID:
+ response = createOnugResponse(msgObj.AttributeMask, msgObj.EntityInstance)
+ case me.SoftwareImageClassID:
+ response = createSoftwareImageResponse(msgObj.AttributeMask, msgObj.EntityInstance)
+ case me.IpHostConfigDataClassID:
+ response = createIpHostResponse(msgObj.AttributeMask, msgObj.EntityInstance)
+ case me.UniGClassID:
+ response = createUnigResponse(msgObj.AttributeMask, msgObj.EntityInstance)
+ case me.PhysicalPathTerminationPointEthernetUniClassID:
+ response = createPptpResponse(msgObj.AttributeMask, msgObj.EntityInstance)
+ case me.AniGClassID:
+ response = createAnigResponse(msgObj.AttributeMask, msgObj.EntityInstance)
+ case me.OnuDataClassID:
+ response = createOnuDataResponse(msgObj.AttributeMask, msgObj.EntityInstance)
+ default:
+ omciLogger.WithFields(log.Fields{
+ "EntityClass": msgObj.EntityClass,
+ "EntityInstance": msgObj.EntityInstance,
+ "AttributeMask": fmt.Sprintf("%x", msgObj.AttributeMask),
+ }).Warnf("do-not-know-how-to-handle-get-request-for-me-class")
+ return nil, nil
+ }
+
+ pkt, err := serialize(omci.GetResponseType, response, omciMsg.TransactionID)
+ if err != nil {
+ omciLogger.WithFields(log.Fields{
+ "Err": err,
+ "TxID": strconv.FormatInt(int64(omciMsg.TransactionID), 16),
+ }).Error("cannot-serialize-Onu2gResponse")
+ return nil, err
+ }
+
+ log.WithFields(log.Fields{
+ "TxID": strconv.FormatInt(int64(omciMsg.TransactionID), 16),
+ "pkt": hex.EncodeToString(pkt),
+ }).Trace("omci-get-response")
+
+ return pkt, nil
+}
+
+func createOnu2gResponse(attributeMask uint16, entityID uint16) *omci.GetResponse {
+
+ managedEntity, meErr := me.NewOnu2G(me.ParamData{
+ EntityID: entityID,
+ Attributes: me.AttributeValueMap{
+ "ManagedEntityId": entityID,
+ "EquipmentId": toOctets("BBSM", 20),
+ "OpticalNetworkUnitManagementAndControlChannelOmccVersion": 180,
+ "VendorProductCode": 0,
+ "SecurityCapability": 1,
+ "SecurityMode": 1,
+ "TotalPriorityQueueNumber": 1,
+ "TotalTrafficSchedulerNumber": 1,
+ "Deprecated": 1,
+ "TotalGemPortIdNumber": 32,
+ "Sysuptime": 319389947, // NOTE need to be smarter?
+ "ConnectivityCapability": 127,
+ "CurrentConnectivityMode": 5,
+ "QualityOfServiceQosConfigurationFlexibility": 48,
+ "PriorityQueueScaleFactor": 1,
+ },
+ })
+
+ if meErr.GetError() != nil {
+ omciLogger.Errorf("NewOnu2G %v", meErr.Error())
+ return nil
+ }
+
+ return &omci.GetResponse{
+ MeBasePacket: omci.MeBasePacket{
+ EntityClass: me.Onu2GClassID,
+ },
+ Attributes: managedEntity.GetAttributeValueMap(),
+ AttributeMask: attributeMask,
+ Result: me.Success,
+ }
+}
+
+func createOnugResponse(attributeMask uint16, entityID uint16) *omci.GetResponse {
+ return &omci.GetResponse{
+ MeBasePacket: omci.MeBasePacket{
+ EntityClass: me.OnuGClassID,
+ EntityInstance: entityID,
+ },
+ Attributes: me.AttributeValueMap{
+ "ManagedEntityId": entityID,
+ "VendorId": toOctets("BBSM", 4),
+ "Version": toOctets("v0.0.1", 14),
+ "SerialNumber": toOctets("QkJTTQAKAAE=", 8),
+ "TrafficManagementOption": 0,
+ "Deprecated": 0,
+ "BatteryBackup": 0,
+ "AdministrativeState": 0,
+ "OperationalState": 0,
+ "OnuSurvivalTime": 10,
+ "LogicalOnuId": toOctets("BBSM", 24),
+ "LogicalPassword": toOctets("BBSM", 12),
+ "CredentialsStatus": 0,
+ "ExtendedTcLayerOptions": 0,
+ },
+ Result: me.Success,
+ AttributeMask: attributeMask,
+ }
+}
+
+func createSoftwareImageResponse(attributeMask uint16, entityInstance uint16) *omci.GetResponse {
+ // NOTE that we need send the response for the correct ME Instance or the adapter won't process it
+ return &omci.GetResponse{
+ MeBasePacket: omci.MeBasePacket{
+ EntityClass: me.SoftwareImageClassID,
+ EntityInstance: entityInstance,
+ },
+ Attributes: me.AttributeValueMap{
+ "ManagedEntityId": 0,
+ "Version": toOctets("v0.0.1", 14),
+ "IsCommitted": 1,
+ "IsActive": 1,
+ "IsValid": 1,
+ "ProductCode": toOctets("product-code", 25),
+ "ImageHash": toOctets("broadband-sim", 16),
+ },
+ Result: me.Success,
+ AttributeMask: attributeMask,
+ }
+}
+
+func createIpHostResponse(attributeMask uint16, entityInstance uint16) *omci.GetResponse {
+ return &omci.GetResponse{
+ MeBasePacket: omci.MeBasePacket{
+ EntityClass: me.IpHostConfigDataClassID,
+ EntityInstance: entityInstance,
+ },
+ Attributes: me.AttributeValueMap{
+ "ManagedEntityId": 0,
+ "MacAddress": toOctets("aabbcc", 6),
+ },
+ Result: me.Success,
+ AttributeMask: attributeMask,
+ }
+}
+
+func createUnigResponse(attributeMask uint16, entityID uint16) *omci.GetResponse {
+ managedEntity, meErr := me.NewUniG(me.ParamData{
+ EntityID: entityID,
+ Attributes: me.AttributeValueMap{
+ "ManagedEntityId": entityID,
+ "Deprecated": 0,
+ "AdministrativeState": 0,
+ "ManagementCapability": 0,
+ "NonOmciManagementIdentifier": 1,
+ "RelayAgentOptions": 1,
+ },
+ })
+
+ if meErr.GetError() != nil {
+ omciLogger.Errorf("NewUniG %v", meErr.Error())
+ return nil
+ }
+
+ return &omci.GetResponse{
+ MeBasePacket: omci.MeBasePacket{
+ EntityClass: me.UniGClassID,
+ },
+ Attributes: managedEntity.GetAttributeValueMap(),
+ AttributeMask: attributeMask,
+ Result: me.Success,
+ }
+}
+
+func createPptpResponse(attributeMask uint16, entityID uint16) *omci.GetResponse {
+ managedEntity, meErr := me.NewPhysicalPathTerminationPointEthernetUni(me.ParamData{
+ EntityID: entityID,
+ Attributes: me.AttributeValueMap{
+ "ManagedEntityId": entityID,
+ "ExpectedType": 0,
+ "SensedType": 0,
+ "AutoDetectionConfiguration": 0,
+ "EthernetLoopbackConfiguration": 0,
+ "AdministrativeState": 0,
+ "OperationalState": 0,
+ "ConfigurationInd": 0,
+ "MaxFrameSize": 0,
+ "DteOrDceInd": 0,
+ "PauseTime": 0,
+ "BridgedOrIpInd": 0,
+ "Arc": 0,
+ "ArcInterval": 0,
+ "PppoeFilter": 0,
+ "PowerControl": 0,
+ },
+ })
+
+ if meErr.GetError() != nil {
+ omciLogger.Errorf("NewPhysicalPathTerminationPointEthernetUni %v", meErr.Error())
+ return nil
+ }
+
+ return &omci.GetResponse{
+ MeBasePacket: omci.MeBasePacket{
+ EntityClass: me.PhysicalPathTerminationPointEthernetUniClassID,
+ },
+ Attributes: managedEntity.GetAttributeValueMap(),
+ AttributeMask: attributeMask,
+ Result: me.Success,
+ }
+}
+
+func createAnigResponse(attributeMask uint16, entityID uint16) *omci.GetResponse {
+ managedEntity, meErr := me.NewAniG(me.ParamData{
+ EntityID: entityID,
+ Attributes: me.AttributeValueMap{
+ "ManagedEntityId": entityID,
+ "SrIndication": 0,
+ "TotalTcontNumber": 0,
+ "GemBlockLength": 0,
+ "PiggybackDbaReporting": 0,
+ "Deprecated": 0,
+ "SignalFailThreshold": 0,
+ "SignalDegradeThreshold": 0,
+ "Arc": 0,
+ "ArcInterval": 0,
+ "OpticalSignalLevel": 0,
+ "LowerOpticalThreshold": 0,
+ "UpperOpticalThreshold": 0,
+ "OnuResponseTime": 0,
+ "TransmitOpticalLevel": 0,
+ "LowerTransmitPowerThreshold": 0,
+ "UpperTransmitPowerThreshold": 0,
+ },
+ })
+
+ if meErr.GetError() != nil {
+ omciLogger.Errorf("NewAniG %v", meErr.Error())
+ return nil
+ }
+
+ return &omci.GetResponse{
+ MeBasePacket: omci.MeBasePacket{
+ EntityClass: me.AniGClassID,
+ },
+ Attributes: managedEntity.GetAttributeValueMap(),
+ AttributeMask: attributeMask,
+ Result: me.Success,
+ }
+}
+
+func createOnuDataResponse(attributeMask uint16, entityID uint16) *omci.GetResponse {
+ managedEntity, meErr := me.NewOnuData(me.ParamData{
+ EntityID: entityID,
+ Attributes: me.AttributeValueMap{
+ "ManagedEntityId": entityID,
+ "MibDataSync": 0,
+ },
+ })
+
+ if meErr.GetError() != nil {
+ omciLogger.Errorf("NewOnuData %v", meErr.Error())
+ return nil
+ }
+
+ return &omci.GetResponse{
+ MeBasePacket: omci.MeBasePacket{
+ EntityClass: me.OnuDataClassID,
+ },
+ Attributes: managedEntity.GetAttributeValueMap(),
+ AttributeMask: attributeMask,
+ Result: me.Success,
+ }
+}
+
+func toOctets(str string, size int) []byte {
+ asciiBytes := []byte(str)
+
+ if len(asciiBytes) < size {
+ missing := size - len(asciiBytes)
+ for i := 0; i < missing; i++ {
+ asciiBytes = append(asciiBytes, []byte{0x00}[0])
+ }
+ }
+ return asciiBytes
+}
diff --git a/internal/common/omci/get_test.go b/internal/common/omci/get_test.go
new file mode 100644
index 0000000..0ab6d04
--- /dev/null
+++ b/internal/common/omci/get_test.go
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2018-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 omci
+
+import (
+ "github.com/google/gopacket"
+ "github.com/opencord/omci-lib-go"
+ me "github.com/opencord/omci-lib-go/generated"
+ "gotest.tools/assert"
+ "testing"
+)
+
+func omciBytesToMsg(t *testing.T, data []byte) (*omci.OMCI, *gopacket.Packet) {
+ packet := gopacket.NewPacket(data, omci.LayerTypeOMCI, gopacket.NoCopy)
+ if packet == nil {
+ t.Fatal("could not decode rxMsg as OMCI")
+ }
+ omciLayer := packet.Layer(omci.LayerTypeOMCI)
+ if omciLayer == nil {
+ t.Fatal("could not decode omci layer")
+ }
+ omciMsg, ok := omciLayer.(*omci.OMCI)
+ if !ok {
+ t.Fatal("could not assign omci layer")
+ }
+ return omciMsg, &packet
+}
+
+func omciToGetResponse(t *testing.T, omciPkt *gopacket.Packet) *omci.GetResponse {
+ msgLayer := (*omciPkt).Layer(omci.LayerTypeGetResponse)
+ if msgLayer == nil {
+ t.Fatal("omci Msg layer could not be detected for GetResponse - handling of MibSyncChan stopped")
+ }
+ msgObj, msgOk := msgLayer.(*omci.GetResponse)
+ if !msgOk {
+ t.Fatal("omci Msg layer could not be assigned for GetResponse - handling of MibSyncChan stopped")
+ }
+ return msgObj
+}
+
+func TestCreateOnu2gResponse(t *testing.T) {
+ response := createOnu2gResponse(40960, 1)
+ data, _ := serialize(omci.GetResponseType, response, 1)
+
+ // emulate the openonu-go behavior:
+ // omci_cc.receiveMessage process the message (creates a gopacket and extracts the OMCI layer) and invokes a callback
+ // in the GetResponse case omci_cc.receiveOmciResponse
+ // then the OmciMessage (gopacket + OMIC layer) is is published on a channel
+ omciMsg, omciPkt := omciBytesToMsg(t, data)
+
+ assert.Equal(t, omciMsg.MessageType, omci.GetResponseType)
+
+ // that is read by myb_sync.processMibSyncMessages
+ // the myb_sync.handleOmciMessage is called and then
+ // myb_sync.handleOmciGetResponseMessage where we extract the GetResponse layer
+ getResponseLayer := omciToGetResponse(t, omciPkt)
+
+ assert.Equal(t, getResponseLayer.Result, me.Success)
+}
+
+func TestCreateOnugResponse(t *testing.T) {
+ response := createOnugResponse(40960, 1)
+ data, _ := serialize(omci.GetResponseType, response, 1)
+
+ omciMsg, omciPkt := omciBytesToMsg(t, data)
+
+ assert.Equal(t, omciMsg.MessageType, omci.GetResponseType)
+
+ getResponseLayer := omciToGetResponse(t, omciPkt)
+
+ assert.Equal(t, getResponseLayer.Result, me.Success)
+}
diff --git a/internal/common/omci/mib_test.go b/internal/common/omci/mib_test.go
new file mode 100644
index 0000000..c73f616
--- /dev/null
+++ b/internal/common/omci/mib_test.go
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2018-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 omci
+
+import (
+ "fmt"
+ "github.com/google/gopacket"
+ "github.com/opencord/omci-lib-go"
+ me "github.com/opencord/omci-lib-go/generated"
+ "gotest.tools/assert"
+ "testing"
+)
+
+func TestCreateMibResetResponse(t *testing.T) {
+ data, _ := CreateMibResetResponse(1)
+
+ omciMsg, omciPkt := omciBytesToMsg(t, data)
+
+ assert.Equal(t, omciMsg.MessageType, omci.MibResetResponseType)
+
+ msgLayer := (*omciPkt).Layer(omci.LayerTypeMibResetResponse)
+ msgObj, msgOk := msgLayer.(*omci.MibResetResponse)
+ if !msgOk {
+ t.Fail()
+ }
+
+ assert.Equal(t, msgObj.Result, me.Success)
+}
+
+// types for TestCreateMibUploadNextResponse test
+type mibArgs struct {
+ omciPkt gopacket.Packet
+ omciMsg *omci.OMCI
+}
+
+type mibExpected struct {
+ messageType omci.MessageType
+ transactionId uint16
+ entityClass me.ClassID
+ attributes map[string]interface{}
+}
+
+func createTestMibUploadNextArgs(t *testing.T, tid uint16, seqNumber uint16) mibArgs {
+ mibUploadNext, _ := CreateMibUploadNextRequest(tid, seqNumber)
+ mibUploadNext = hexDecode(mibUploadNext)
+ mibUploadNextMsg, mibUploadNextPkt := omciBytesToMsg(t, mibUploadNext)
+
+ return mibArgs{
+ omciPkt: *mibUploadNextPkt,
+ omciMsg: mibUploadNextMsg,
+ }
+}
+
+func TestCreateMibUploadNextResponse(t *testing.T) {
+
+ tests := []struct {
+ name string
+ args mibArgs
+ want mibExpected
+ }{
+ {"mibUploadNext-0", createTestMibUploadNextArgs(t, 1, 0),
+ mibExpected{messageType: omci.MibUploadNextResponseType, transactionId: 1, entityClass: me.OnuDataClassID, attributes: map[string]interface{}{"MibDataSync": uint8(0)}}},
+ {"mibUploadNext-1", createTestMibUploadNextArgs(t, 2, 1),
+ mibExpected{messageType: omci.MibUploadNextResponseType, transactionId: 2, entityClass: me.CircuitPackClassID, attributes: map[string]interface{}{"Type": uint8(47), "NumberOfPorts": uint8(4)}}},
+ {"mibUploadNext-4", createTestMibUploadNextArgs(t, 3, 4),
+ mibExpected{messageType: omci.MibUploadNextResponseType, transactionId: 3, entityClass: me.CircuitPackClassID, attributes: map[string]interface{}{"PowerShedOverride": uint32(0)}}},
+ {"mibUploadNext-10", createTestMibUploadNextArgs(t, 4, 10),
+ mibExpected{messageType: omci.MibUploadNextResponseType, transactionId: 4, entityClass: me.CircuitPackClassID, attributes: map[string]interface{}{"SensedType": uint8(47)}}},
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+
+ // create the packet starting from the mibUploadNextRequest
+ data, _ := CreateMibUploadNextResponse(tt.args.omciPkt, tt.args.omciMsg)
+ omciMsg, omciPkt := omciBytesToMsg(t, data)
+
+ assert.Equal(t, omciMsg.MessageType, tt.want.messageType)
+
+ msgLayer := (*omciPkt).Layer(omci.LayerTypeMibUploadNextResponse)
+ msgObj, msgOk := msgLayer.(*omci.MibUploadNextResponse)
+ if !msgOk {
+ t.Fail()
+ }
+
+ assert.Equal(t, omciMsg.TransactionID, tt.want.transactionId) // tid
+ // GetAttribute("ManagedEntityId") returns nil,
+ // msgObj.EntityClass is always OnuDataClassID
+ // how do we check this?
+ //meId, _ := msgObj.ReportedME.GetAttribute("ManagedEntityId")
+ //assert.Equal(t, meId, tt.want.entityClass)
+ //assert.Equal(t, msgObj.EntityClass, tt.want.entityClass)
+
+ fmt.Println(msgObj.EntityInstance, msgObj.ReportedME.GetEntityID())
+
+ for k, v := range tt.want.attributes {
+ attr, _ := msgObj.ReportedME.GetAttribute(k)
+ assert.Equal(t, attr, v)
+ }
+ })
+ }
+
+}
diff --git a/internal/common/omci/mibpackets.go b/internal/common/omci/mibpackets.go
index b21da4d..fe02e5d 100755
--- a/internal/common/omci/mibpackets.go
+++ b/internal/common/omci/mibpackets.go
@@ -18,10 +18,10 @@
import (
"encoding/hex"
- "github.com/cboling/omci"
- me "github.com/cboling/omci/generated"
+ "errors"
"github.com/google/gopacket"
- omcisim "github.com/opencord/omci-sim"
+ "github.com/opencord/omci-lib-go"
+ me "github.com/opencord/omci-lib-go/generated"
log "github.com/sirupsen/logrus"
)
@@ -41,6 +41,8 @@
RxHandler rxFrameParser
}
+// NOTE this is basically the same as https://github.com/opencord/voltha-openonu-adapter-go/blob/master/internal/pkg/onuadaptercore/omci_cc.go#L545-L564
+// we should probably move it in "omci-lib-go"
func serialize(msgType omci.MessageType, request gopacket.SerializableLayer, tid uint16) ([]byte, error) {
omciLayer := &omci.OMCI{
TransactionID: tid,
@@ -63,57 +65,11 @@
return dst, nil
}
-func DecodeOmci(payload []byte) (omci.MessageType, gopacket.Packet) {
- // Perform base OMCI decode (common to all requests)
- packet := gopacket.NewPacket(payload, omci.LayerTypeOMCI, gopacket.NoCopy)
-
- if omciLayer := packet.Layer(omci.LayerTypeOMCI); omciLayer != nil {
-
- omciObj, omciOk := omciLayer.(*omci.OMCI)
- if !omciOk {
- panic("Not Expected") // TODO: Do something better or delete...
- }
- if byte(omciObj.MessageType) & ^me.AK == 0 {
- // Not a response, silently discard
- return 0, nil
- }
- return omciObj.MessageType, packet
- }
-
- // FIXME
- // if we can't properly decode the packet, try using shad helper method
- // most likely this won't be necessary once we move omci-sim to use cboling/omci
- // to generate packets
- _, _, msgType, _, _, _, err := omcisim.ParsePkt(payload)
- if err != nil {
- return 0, nil
- }
- if msgType == omcisim.MibReset {
- return omci.MibResetResponseType, nil
- }
- if msgType == omcisim.MibUpload {
- return omci.MibUploadResponseType, nil
- }
- if msgType == omcisim.MibUploadNext {
- return omci.MibUploadNextResponseType, nil
- }
- if msgType == omcisim.Create {
- return omci.CreateResponseType, nil
- }
- if msgType == omcisim.Set {
- return omci.SetResponseType, nil
- }
-
- omciLogger.Warnf("omci-sim returns msgType: %d", msgType)
-
- return 0, nil
-}
-
func CreateMibResetRequest(tid uint16) ([]byte, error) {
request := &omci.MibResetRequest{
MeBasePacket: omci.MeBasePacket{
- EntityClass: me.OnuDataClassId,
+ EntityClass: me.OnuDataClassID,
},
}
pkt, err := serialize(omci.MibResetRequestType, request, tid)
@@ -126,10 +82,29 @@
return hexEncode(pkt)
}
+func CreateMibResetResponse(tid uint16) ([]byte, error) {
+
+ // TODO reset MDX
+ request := &omci.MibResetResponse{
+ MeBasePacket: omci.MeBasePacket{
+ EntityClass: me.OnuDataClassID,
+ },
+ Result: me.Success,
+ }
+ pkt, err := serialize(omci.MibResetResponseType, request, tid)
+ if err != nil {
+ omciLogger.WithFields(log.Fields{
+ "Err": err,
+ }).Error("Cannot serialize MibResetResponse")
+ return nil, err
+ }
+ return pkt, nil
+}
+
func CreateMibUploadRequest(tid uint16) ([]byte, error) {
request := &omci.MibUploadRequest{
MeBasePacket: omci.MeBasePacket{
- EntityClass: me.OnuDataClassId,
+ EntityClass: me.OnuDataClassID,
// Default Instance ID is 0
},
}
@@ -143,11 +118,31 @@
return hexEncode(pkt)
}
+func CreateMibUploadResponse(tid uint16) ([]byte, error) {
+
+ numberOfCommands := uint16(291) //NOTE should this be configurable? (not until we have moved all the messages away from omci-sim)
+
+ request := &omci.MibUploadResponse{
+ MeBasePacket: omci.MeBasePacket{
+ EntityClass: me.OnuDataClassID,
+ },
+ NumberOfCommands: numberOfCommands,
+ }
+ pkt, err := serialize(omci.MibUploadResponseType, request, tid)
+ if err != nil {
+ omciLogger.WithFields(log.Fields{
+ "Err": err,
+ }).Error("Cannot serialize MibUploadResponse")
+ return nil, err
+ }
+ return pkt, nil
+}
+
func CreateMibUploadNextRequest(tid uint16, seqNumber uint16) ([]byte, error) {
request := &omci.MibUploadNextRequest{
MeBasePacket: omci.MeBasePacket{
- EntityClass: me.OnuDataClassId,
+ EntityClass: me.OnuDataClassID,
// Default Instance ID is 0
},
CommandSequenceNumber: seqNumber,
@@ -163,123 +158,299 @@
return hexEncode(pkt)
}
-// Return true if msg is an Omci Test Request
-func IsTestRequest(payload []byte) (bool, error) {
- _, _, msgType, _, _, _, err := omcisim.ParsePkt(payload)
- if err != nil {
- return false, err
+func ParseMibUploadNextRequest(omciPkt gopacket.Packet) (*omci.MibUploadNextRequest, error) {
+ msgLayer := omciPkt.Layer(omci.LayerTypeMibUploadNextRequest)
+ if msgLayer == nil {
+ err := "omci Msg layer could not be detected for LayerTypeMibUploadNextRequest"
+ omciLogger.Error(err)
+ return nil, errors.New(err)
}
-
- return ((msgType & 0x1F) == 18), nil
+ msgObj, msgOk := msgLayer.(*omci.MibUploadNextRequest)
+ if !msgOk {
+ err := "omci Msg layer could not be assigned for MibUploadNextRequest"
+ omciLogger.Error(err)
+ return nil, errors.New(err)
+ }
+ return msgObj, nil
}
-func BuildTestResult(payload []byte) ([]byte, error) {
- transactionId, deviceId, _, class, instance, _, err := omcisim.ParsePkt(payload)
+func CreateMibUploadNextResponse(omciPkt gopacket.Packet, omciMsg *omci.OMCI) ([]byte, error) {
+ msgObj, err := ParseMibUploadNextRequest(omciPkt)
if err != nil {
- return []byte{}, err
+ err := "omci Msg layer could not be assigned for LayerTypeGetRequest"
+ omciLogger.Error(err)
+ return nil, errors.New(err)
}
- resp := make([]byte, 48)
- resp[0] = byte(transactionId >> 8)
- resp[1] = byte(transactionId & 0xFF)
- resp[2] = 27 // Upper nibble 0x0 is fixed (0000), Lower nibbles defines msg type (TestResult=27)
- resp[3] = deviceId
- resp[4] = byte(class >> 8)
- resp[5] = byte(class & 0xFF)
- resp[6] = byte(instance >> 8)
- resp[7] = byte(instance & 0xFF)
- // Each of these is a 1-byte code
- // follow by a 2-byte (high, low) value
- resp[8] = 1 // power feed voltage
- resp[9] = 0
- resp[10] = 123 // 123 mV, 20 mv res --> 6mv
- resp[11] = 3 // received optical power
- resp[12] = 1
- resp[13] = 200 // 456 decibel-microwatts, 0.002 dB res --> 0.912 db-mw
- resp[14] = 5 // mean optical launch power
- resp[15] = 3
- resp[16] = 21 // 789 uA, 0.002 dB res --> 1.578 db-mw
- resp[17] = 9 // laser bias current
- resp[18] = 3
- resp[19] = 244 // 1012 uA, 2uA res --> 505 ua
- resp[20] = 12 // temperature
- resp[21] = 38
- resp[22] = 148 // 9876 deg C, 1/256 resolution --> 38.57 Deg C
+ omciLogger.WithFields(log.Fields{
+ "EntityClass": msgObj.EntityClass,
+ "EntityInstance": msgObj.EntityInstance,
+ "CommandSequenceNumber": msgObj.CommandSequenceNumber,
+ }).Trace("received-omci-mibUploadNext-request")
- return resp, nil
-}
+ // depending on the sequenceNumber we'll report a different
+ reportedMe := &me.ManagedEntity{}
+ var meErr me.OmciErrors
+ //var entityInstance uint16
+ switch msgObj.CommandSequenceNumber {
+ case 0:
+ reportedMe, meErr = me.NewOnuData(me.ParamData{Attributes: me.AttributeValueMap{
+ "ManagedEntityId": me.OnuDataClassID,
+ "MibDataSync": 0,
+ }})
+ if meErr.GetError() != nil {
+ omciLogger.Errorf("NewOnuData %v", meErr.Error())
+ }
-// TODO understand and refactor
-
-func CreateGalEnetRequest(tid uint16) ([]byte, error) {
- params := me.ParamData{
- EntityID: galEthernetEID,
- Attributes: me.AttributeValueMap{"MaximumGemPayloadSize": maxGemPayloadSize},
- }
- meDef, _ := me.NewGalEthernetProfile(params)
- pkt, err := omci.GenFrame(meDef, omci.CreateRequestType, omci.TransactionID(tid))
- if err != nil {
- omciLogger.WithField("err", err).Fatalf("Can't generate GalEnetRequest")
- }
- return hexEncode(pkt)
-}
-
-func CreateEnableUniRequest(tid uint16, uniId uint16, enabled bool, isPtp bool) ([]byte, error) {
-
- var _enabled uint8
- if enabled {
- _enabled = uint8(1)
- } else {
- _enabled = uint8(0)
+ case 1:
+ reportedMe, meErr = me.NewCircuitPack(me.ParamData{Attributes: me.AttributeValueMap{
+ "ManagedEntityId": me.CircuitPackClassID,
+ "Type": 47,
+ "NumberOfPorts": 4,
+ "SerialNumber": toOctets("BBSM-Circuit-Pack", 20),
+ "Version": toOctets("v0.0.1", 20),
+ }})
+ if meErr.GetError() != nil {
+ omciLogger.Errorf("NewCircuitPack %v", meErr.Error())
+ }
+ case 2:
+ reportedMe, meErr = me.NewCircuitPack(me.ParamData{Attributes: me.AttributeValueMap{
+ "ManagedEntityId": me.CircuitPackClassID,
+ "VendorId": "ONF",
+ "AdministrativeState": 0,
+ "OperationalState": 0,
+ "BridgedOrIpInd": 0,
+ }})
+ if meErr.GetError() != nil {
+ omciLogger.Errorf("NewCircuitPack %v", meErr.Error())
+ }
+ case 3:
+ reportedMe, meErr = me.NewCircuitPack(me.ParamData{Attributes: me.AttributeValueMap{
+ "ManagedEntityId": me.CircuitPackClassID,
+ "EquipmentId": toOctets("BBSM-Circuit-Pack", 20),
+ "CardConfiguration": 0,
+ "TotalTContBufferNumber": 0,
+ "TotalPriorityQueueNumber": 8,
+ "TotalTrafficSchedulerNumber": 0,
+ }})
+ if meErr.GetError() != nil {
+ omciLogger.Errorf("NewCircuitPack %v", meErr.Error())
+ }
+ case 4:
+ reportedMe, meErr = me.NewCircuitPack(me.ParamData{Attributes: me.AttributeValueMap{
+ "ManagedEntityId": me.CircuitPackClassID,
+ "PowerShedOverride": uint32(0),
+ }})
+ if meErr.GetError() != nil {
+ omciLogger.Errorf("NewCircuitPack %v", meErr.Error())
+ }
+ case 5:
+ reportedMe, meErr = me.NewCircuitPack(me.ParamData{Attributes: me.AttributeValueMap{
+ "ManagedEntityId": me.CircuitPackClassID,
+ "Type": 238,
+ "NumberOfPorts": 1,
+ "SerialNumber": toOctets("BBSM-Circuit-Pack-2", 20),
+ "Version": toOctets("v0.0.1", 20),
+ }})
+ if meErr.GetError() != nil {
+ omciLogger.Errorf("NewCircuitPack %v", meErr.Error())
+ }
+ case 6:
+ reportedMe, meErr = me.NewCircuitPack(me.ParamData{Attributes: me.AttributeValueMap{
+ "ManagedEntityId": me.CircuitPackClassID,
+ "VendorId": "ONF",
+ "AdministrativeState": 0,
+ "OperationalState": 0,
+ "BridgedOrIpInd": 0,
+ }})
+ if meErr.GetError() != nil {
+ omciLogger.Errorf("NewCircuitPack %v", meErr.Error())
+ }
+ case 7:
+ reportedMe, meErr = me.NewCircuitPack(me.ParamData{Attributes: me.AttributeValueMap{
+ "ManagedEntityId": me.CircuitPackClassID,
+ "EquipmentId": toOctets("BBSM-Circuit-Pack", 20),
+ "CardConfiguration": 0,
+ "TotalTContBufferNumber": 8,
+ "TotalPriorityQueueNumber": 40,
+ "TotalTrafficSchedulerNumber": 10,
+ }})
+ if meErr.GetError() != nil {
+ omciLogger.Errorf("NewCircuitPack %v", meErr.Error())
+ }
+ case 8:
+ reportedMe, meErr = me.NewCircuitPack(me.ParamData{Attributes: me.AttributeValueMap{
+ "ManagedEntityId": me.CircuitPackClassID,
+ "PowerShedOverride": uint32(0),
+ }})
+ if meErr.GetError() != nil {
+ omciLogger.Errorf("NewCircuitPack %v", meErr.Error())
+ }
+ case 9, 10, 11, 12:
+ // NOTE we're reporting for different UNIs, the IDs are 257, 258, 259, 260
+ meInstance := 248 + msgObj.CommandSequenceNumber
+ reportedMe, meErr = me.NewPhysicalPathTerminationPointEthernetUni(me.ParamData{
+ EntityID: meInstance,
+ Attributes: me.AttributeValueMap{
+ "ExpectedType": 0,
+ "SensedType": 47,
+ "AutoDetectionConfiguration": 0,
+ "EthernetLoopbackConfiguration": 0,
+ "AdministrativeState": 0,
+ "OperationalState": 0,
+ "ConfigurationInd": 3,
+ "MaxFrameSize": 1518,
+ "DteOrDceInd": 0,
+ "PauseTime": 0,
+ "BridgedOrIpInd": 2,
+ "Arc": 0,
+ "ArcInterval": 0,
+ "PppoeFilter": 0,
+ "PowerControl": 0,
+ }})
+ if meErr.GetError() != nil {
+ omciLogger.Errorf("NewPhysicalPathTerminationPointEthernetUni %v", meErr.Error())
+ }
+ case 13, 14, 15, 16, 17, 18, 19, 20:
+ // TODO report different MeID (see omci-sim pcap filter "frame[22:2] == 01:06")
+ reportedMe, meErr = me.NewTCont(me.ParamData{Attributes: me.AttributeValueMap{
+ "ManagedEntityId": me.TContClassID,
+ "AllocId": 0,
+ }})
+ if meErr.GetError() != nil {
+ omciLogger.Errorf("NewTCont %v", meErr.Error())
+ }
+ case 21:
+ reportedMe, meErr = me.NewAniG(me.ParamData{Attributes: me.AttributeValueMap{
+ "ManagedEntityId": me.AniGClassID,
+ "SrIndication": 1,
+ "TotalTcontNumber": 8,
+ "GemBlockLength": 30,
+ "PiggybackDbaReporting": 0,
+ "Deprecated": 0,
+ "SignalFailThreshold": 5,
+ "SignalDegradeThreshold": 9,
+ "Arc": 0,
+ "ArcInterval": 0,
+ "OpticalSignalLevel": 57428,
+ "LowerOpticalThreshold": 255,
+ "UpperOpticalThreshold": 255,
+ "OnuResponseTime": 0,
+ "TransmitOpticalLevel": 3171,
+ "LowerTransmitPowerThreshold": 129,
+ "UpperTransmitPowerThreshold": 129,
+ }})
+ if meErr.GetError() != nil {
+ omciLogger.Errorf("NewAniG %v", meErr.Error())
+ }
+ case 22, 23, 24, 25:
+ // TODO report different MeID (see omci-sim pcap filter "frame[22:2] == 01:08")
+ reportedMe, meErr = me.NewUniG(me.ParamData{Attributes: me.AttributeValueMap{
+ "ManagedEntityId": me.UniGClassID,
+ "Deprecated": 0,
+ "AdministrativeState": 0,
+ }})
+ if meErr.GetError() != nil {
+ omciLogger.Errorf("NewUniG %v", meErr.Error())
+ }
+ case 26, 30, 34, 38, 42, 46, 50, 54,
+ 58, 62, 66, 70, 74, 78, 82, 86,
+ 90, 94, 98, 102, 106, 110, 114, 118,
+ 122, 126, 130, 134, 138, 142, 146, 150,
+ 154, 158, 162, 166, 170, 174, 178, 182,
+ 186, 190, 194, 198, 202, 206, 210, 214,
+ 218, 222, 226, 230, 234, 238, 242, 246,
+ 250, 254, 258, 262, 266, 270, 274, 278:
+ case 27, 31, 35, 39, 43, 47, 51, 55,
+ 59, 63, 67, 71, 75, 79, 83, 87,
+ 91, 95, 99, 103, 107, 111, 115, 119,
+ 123, 127, 131, 135, 139, 143, 147, 151,
+ 155, 159, 163, 167, 171, 175, 179, 183,
+ 187, 191, 195, 199, 203, 207, 211, 215,
+ 219, 223, 227, 231, 235, 239, 243, 247,
+ 251, 255, 259, 263, 267, 271, 275, 279:
+ case 28, 32, 36, 40, 44, 48, 52, 56,
+ 60, 64, 68, 72, 76, 80, 84, 88,
+ 92, 96, 100, 104, 108, 112, 116, 120,
+ 124, 128, 132, 136, 140, 144, 148, 152,
+ 156, 160, 164, 168, 172, 176, 180, 184,
+ 188, 192, 196, 200, 204, 208, 212, 216,
+ 220, 224, 228, 232, 236, 240, 244, 248,
+ 252, 256, 260, 264, 268, 272, 276, 280:
+ case 29, 33, 37, 41, 45, 49, 53, 57,
+ 61, 65, 69, 73, 77, 81, 85, 89,
+ 93, 97, 101, 105, 109, 113, 117, 121,
+ 125, 129, 133, 137, 141, 145, 149, 153,
+ 157, 161, 165, 169, 173, 177, 181, 185,
+ 189, 193, 197, 201, 205, 209, 213, 217,
+ 221, 225, 229, 233, 237, 241, 245, 249,
+ 253, 257, 261, 265, 269, 273, 277, 281:
+ reportedMe, meErr = me.NewPriorityQueue(me.ParamData{Attributes: me.AttributeValueMap{
+ "ManagedEntityId": me.PriorityQueueClassID,
+ "QueueConfigurationOption": 0,
+ "MaximumQueueSize": 100,
+ "AllocatedQueueSize": 100,
+ "DiscardBlockCounterResetInterval": 0,
+ "ThresholdValueForDiscardedBlocksDueToBufferOverflow": 0,
+ "RelatedPort": 80010000, // does this need to change?
+ "TrafficSchedulerPointer": 8008, // does this need to change?
+ "Weight": 1,
+ "BackPressureOperation": 1,
+ "BackPressureTime": 0,
+ "BackPressureOccurQueueThreshold": 0,
+ "BackPressureClearQueueThreshold": 0,
+ }})
+ if meErr.GetError() != nil {
+ omciLogger.Errorf("NewPriorityQueue %v", meErr.Error())
+ }
+ case 282, 283, 284, 285, 286, 287, 288, 289:
+ reportedMe, meErr = me.NewTrafficScheduler(me.ParamData{Attributes: me.AttributeValueMap{
+ "ManagedEntityId": me.TrafficSchedulerClassID,
+ "TContPointer": 8008, // NOTE does this need to change?
+ "TrafficSchedulerPointer": 0,
+ "Policy": 02,
+ "PriorityWeight": 0,
+ }})
+ if meErr.GetError() != nil {
+ omciLogger.Errorf("NewTrafficScheduler %v", meErr.Error())
+ }
+ case 290:
+ reportedMe, meErr = me.NewOnu2G(me.ParamData{Attributes: me.AttributeValueMap{
+ "ManagedEntityId": me.Onu2GClassID,
+ "TotalPriorityQueueNumber": 40,
+ "SecurityMode": 1,
+ "TotalTrafficSchedulerNumber": 8,
+ "TotalGemPortIdNumber": 0,
+ "Sysuptime": 0,
+ }})
+ if meErr.GetError() != nil {
+ omciLogger.Errorf("NewOnu2G %v", meErr.Error())
+ }
+ default:
+ omciLogger.Warn("unsupported-CommandSequenceNumber-in-mib-upload-next", msgObj.CommandSequenceNumber)
+ return nil, nil
}
- data := me.ParamData{
- EntityID: uniId,
- Attributes: me.AttributeValueMap{
- "AdministrativeState": _enabled,
+ response := &omci.MibUploadNextResponse{
+ MeBasePacket: omci.MeBasePacket{
+ EntityClass: me.OnuDataClassID,
},
+ ReportedME: *reportedMe,
}
- var medef *me.ManagedEntity
- var omciErr me.OmciErrors
- if isPtp {
- medef, omciErr = me.NewPhysicalPathTerminationPointEthernetUni(data)
- } else {
- medef, omciErr = me.NewVirtualEthernetInterfacePoint(data)
- }
- if omciErr != nil {
- return nil, omciErr.GetError()
- }
- pkt, err := omci.GenFrame(medef, omci.SetRequestType, omci.TransactionID(tid))
+ omciLogger.WithFields(log.Fields{
+ "reportedMe": reportedMe,
+ }).Trace("created-omci-mibUploadNext-response")
+
+ pkt, err := serialize(omci.MibUploadNextResponseType, response, omciMsg.TransactionID)
+
if err != nil {
- omciLogger.WithField("err", err).Fatalf("Can't generate EnableUniRequest")
+ omciLogger.WithFields(log.Fields{
+ "Err": err,
+ }).Fatalf("Cannot serialize MibUploadNextRequest")
+ return nil, err
}
- return hexEncode(pkt)
-}
-func CreateGemPortRequest(tid uint16) ([]byte, error) {
- params := me.ParamData{
- EntityID: gemEID,
- Attributes: me.AttributeValueMap{
- "PortId": 1,
- "TContPointer": 1,
- "Direction": 0,
- "TrafficManagementPointerForUpstream": 0,
- "TrafficDescriptorProfilePointerForUpstream": 0,
- "UniCounter": 0,
- "PriorityQueuePointerForDownStream": 0,
- "EncryptionState": 0,
- "TrafficDescriptorProfilePointerForDownstream": 0,
- "EncryptionKeyRing": 0,
- },
- }
- meDef, _ := me.NewGemPortNetworkCtp(params)
- pkt, err := omci.GenFrame(meDef, omci.CreateRequestType, omci.TransactionID(tid))
- if err != nil {
- omciLogger.WithField("err", err).Fatalf("Can't generate GemPortRequest")
- }
- return hexEncode(pkt)
+ return pkt, nil
}
-
-// END TODO
diff --git a/internal/common/omci/omci_base.go b/internal/common/omci/omci_base.go
new file mode 100644
index 0000000..e74ec4a
--- /dev/null
+++ b/internal/common/omci/omci_base.go
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2018-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 omci
+
+import (
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "github.com/google/gopacket"
+ "github.com/opencord/omci-lib-go"
+ log "github.com/sirupsen/logrus"
+)
+
+// ParseOpenOltOmciPacket receive an OMCI packet in the openolt format and returns
+// an OMCI Layer as per omci-lib-go
+func ParseOpenOltOmciPacket(pkt []byte) (gopacket.Packet, *omci.OMCI, error) {
+ rxMsg := hexDecode(pkt)
+
+ // NOTE this is may not be needed, VOLTHA sends the correct message
+ if len(rxMsg) >= 44 {
+ trailerLenData := rxMsg[42:44]
+ trailerLen := binary.BigEndian.Uint16(trailerLenData)
+ if trailerLen != 40 { // invalid base Format entry -> autocorrect
+ binary.BigEndian.PutUint16(rxMsg[42:44], 40)
+ omciLogger.Trace("cc-corrected-omci-message: trailer len inserted")
+ }
+ } else {
+ omciLogger.WithFields(log.Fields{"Length": len(rxMsg)}).Error("received omci-message too small for OmciBaseFormat - abort")
+ return nil, nil, errors.New("received omci-message too small for OmciBaseFormat - abort")
+ }
+
+ packet := gopacket.NewPacket(rxMsg, omci.LayerTypeOMCI, gopacket.NoCopy)
+ if packet == nil {
+ omciLogger.Error("omci-message could not be decoded")
+ return nil, nil, errors.New("omci-message could not be decoded")
+ }
+ omciLayer := packet.Layer(omci.LayerTypeOMCI)
+ if omciLayer == nil {
+ omciLogger.Error("omci-message could not decode omci layer")
+ return nil, nil, fmt.Errorf("omci-message could not decode omci layer")
+ }
+ parsed, ok := omciLayer.(*omci.OMCI)
+ if !ok {
+ omciLogger.Error("omci-message could not assign omci layer")
+ return nil, nil, errors.New("omci-message could not assign omci layer")
+ }
+
+ return packet, parsed, nil
+}
+
+// hexDecode converts the hex encoding to binary
+func hexDecode(pkt []byte) []byte {
+ p := make([]byte, len(pkt)/2)
+ for i, j := 0, 0; i < len(pkt); i, j = i+2, j+1 {
+ // Go figure this ;)
+ u := (pkt[i] & 15) + (pkt[i]>>6)*9
+ l := (pkt[i+1] & 15) + (pkt[i+1]>>6)*9
+ p[j] = u<<4 + l
+ }
+ return p
+}
diff --git a/internal/common/omci/reboot.go b/internal/common/omci/reboot.go
new file mode 100644
index 0000000..e315044
--- /dev/null
+++ b/internal/common/omci/reboot.go
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2018-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 omci
+
+import (
+ "errors"
+ "github.com/google/gopacket"
+ "github.com/opencord/omci-lib-go"
+ me "github.com/opencord/omci-lib-go/generated"
+ log "github.com/sirupsen/logrus"
+)
+
+func ParseRebootRequest(omciPkt gopacket.Packet) (*omci.RebootRequest, error) {
+ msgLayer := omciPkt.Layer(omci.LayerTypeRebootRequest)
+ if msgLayer == nil {
+ err := "omci Msg layer could not be detected for LayerTypeRebootRequest"
+ omciLogger.Error(err)
+ return nil, errors.New(err)
+ }
+ msgObj, msgOk := msgLayer.(*omci.RebootRequest)
+ if !msgOk {
+ err := "omci Msg layer could not be assigned for LayerTypeRebootRequest"
+ omciLogger.Error(err)
+ return nil, errors.New(err)
+ }
+ return msgObj, nil
+}
+
+func CreateRebootResponse(omciPkt gopacket.Packet, omciMsg *omci.OMCI) ([]byte, error) {
+
+ msgObj, err := ParseRebootRequest(omciPkt)
+
+ if err != nil {
+ return nil, err
+ }
+
+ omciLogger.WithFields(log.Fields{
+ "EntityClass": msgObj.EntityClass,
+ "EntityInstance": msgObj.EntityInstance,
+ }).Trace("received-omci-set-request")
+
+ response := &omci.SetResponse{
+ MeBasePacket: omci.MeBasePacket{
+ EntityClass: msgObj.EntityClass,
+ EntityInstance: msgObj.EntityInstance,
+ },
+ Result: me.Success,
+ }
+
+ pkt, err := serialize(omci.RebootResponseType, response, omciMsg.TransactionID)
+ if err != nil {
+ omciLogger.WithFields(log.Fields{
+ "Err": err,
+ }).Error("cannot-serialize-RebootResponse")
+ return nil, err
+ }
+
+ return pkt, nil
+
+}
diff --git a/internal/common/omci/set.go b/internal/common/omci/set.go
new file mode 100644
index 0000000..eeb621e
--- /dev/null
+++ b/internal/common/omci/set.go
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2018-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 omci
+
+import (
+ "errors"
+ "github.com/google/gopacket"
+ "github.com/opencord/omci-lib-go"
+ me "github.com/opencord/omci-lib-go/generated"
+ log "github.com/sirupsen/logrus"
+)
+
+func ParseSetRequest(omciPkt gopacket.Packet) (*omci.SetRequest, error) {
+ msgLayer := omciPkt.Layer(omci.LayerTypeSetRequest)
+ if msgLayer == nil {
+ err := "omci Msg layer could not be detected for LayerTypeSetRequest"
+ omciLogger.Error(err)
+ return nil, errors.New(err)
+ }
+ msgObj, msgOk := msgLayer.(*omci.SetRequest)
+ if !msgOk {
+ err := "omci Msg layer could not be assigned for LayerTypeSetRequest"
+ omciLogger.Error(err)
+ return nil, errors.New(err)
+ }
+ return msgObj, nil
+}
+
+func CreateSetResponse(omciPkt gopacket.Packet, omciMsg *omci.OMCI) ([]byte, error) {
+
+ msgObj, err := ParseSetRequest(omciPkt)
+
+ if err != nil {
+ return nil, err
+ }
+
+ omciLogger.WithFields(log.Fields{
+ "EntityClass": msgObj.EntityClass,
+ "EntityInstance": msgObj.EntityInstance,
+ "AttributeMask": msgObj.AttributeMask,
+ }).Trace("received-omci-set-request")
+
+ response := &omci.SetResponse{
+ MeBasePacket: omci.MeBasePacket{
+ EntityClass: msgObj.EntityClass,
+ EntityInstance: msgObj.EntityInstance,
+ },
+ Result: me.Success,
+ }
+
+ pkt, err := serialize(omci.SetResponseType, response, omciMsg.TransactionID)
+ if err != nil {
+ omciLogger.WithFields(log.Fields{
+ "Err": err,
+ }).Error("cannot-serialize-SetResponse")
+ return nil, err
+ }
+
+ return pkt, nil
+
+}
diff --git a/internal/common/omci/test.go b/internal/common/omci/test.go
new file mode 100644
index 0000000..40398ba
--- /dev/null
+++ b/internal/common/omci/test.go
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2018-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 omci
+
+import (
+ "errors"
+ "github.com/google/gopacket"
+ "github.com/opencord/omci-lib-go"
+)
+
+func ParseTestRequest(omciPkt gopacket.Packet) (*omci.TestRequest, error) {
+ msgLayer := omciPkt.Layer(omci.LayerTypeGetRequest)
+ if msgLayer == nil {
+ err := "omci Msg layer could not be detected for LayerTypeTestRequest"
+ omciLogger.Error(err)
+ return nil, errors.New(err)
+ }
+ msgObj, msgOk := msgLayer.(*omci.TestRequest)
+ if !msgOk {
+ err := "omci Msg layer could not be assigned for LayerTypeTestRequest"
+ omciLogger.Error(err)
+ return nil, errors.New(err)
+ }
+ return msgObj, nil
+}
+
+// Return true if msg is an Omci Test Request
+func IsTestRequest(payload []byte) (bool, error) {
+ _, omciMsg, err := ParseOpenOltOmciPacket(payload)
+ if err != nil {
+ return false, err
+ }
+
+ return omciMsg.MessageType == omci.TestRequestType, nil
+}
+
+func BuildTestResult(payload []byte) ([]byte, error) {
+
+ omciPkt, omciMsg, err := ParseOpenOltOmciPacket(payload)
+
+ //transactionId, deviceId, _, class, instance, _, err := omcisim.ParsePkt(payload)
+
+ if err != nil {
+ return []byte{}, err
+ }
+
+ testRequest, err := ParseTestRequest(omciPkt)
+ if err != nil {
+ return []byte{}, err
+ }
+
+ // TODO create a TestResponse using omci-lib-go
+ resp := make([]byte, 48)
+ resp[0] = byte(omciMsg.TransactionID >> 8)
+ resp[1] = byte(omciMsg.TransactionID & 0xFF)
+ resp[2] = 27 // Upper nibble 0x0 is fixed (0000), Lower nibbles defines msg type (TestResult=27)
+ resp[3] = byte(omciMsg.DeviceIdentifier)
+ resp[4] = byte(omciMsg.MessageType)
+ resp[5] = byte(omciMsg.MessageType & 0xFF)
+ resp[6] = byte(testRequest.EntityInstance >> 8)
+ resp[7] = byte(testRequest.EntityInstance & 0xFF)
+ // Each of these is a 1-byte code
+ // follow by a 2-byte (high, low) value
+ resp[8] = 1 // power feed voltage
+ resp[9] = 0
+ resp[10] = 123 // 123 mV, 20 mv res --> 6mv
+ resp[11] = 3 // received optical power
+ resp[12] = 1
+ resp[13] = 200 // 456 decibel-microwatts, 0.002 dB res --> 0.912 db-mw
+ resp[14] = 5 // mean optical launch power
+ resp[15] = 3
+ resp[16] = 21 // 789 uA, 0.002 dB res --> 1.578 db-mw
+ resp[17] = 9 // laser bias current
+ resp[18] = 3
+ resp[19] = 244 // 1012 uA, 2uA res --> 505 ua
+ resp[20] = 12 // temperature
+ resp[21] = 38
+ resp[22] = 148 // 9876 deg C, 1/256 resolution --> 38.57 Deg C
+
+ return resp, nil
+}