From 70940e926ce51fc616a0a1effaa110c7b597ce58 Mon Sep 17 00:00:00 2001 From: Valentin Date: Sat, 23 Mar 2024 21:45:42 +0000 Subject: [PATCH] Reduce the number of fatal assertions and add timeBeforeReconnecting Signed-off-by: Valentin --- cmd/packetrusher.go | 3 +- internal/common/tools/tools.go | 10 +++ .../gnb/ngap/dispatcher.go | 7 +- .../gnb/ngap/handler/handler.go | 68 +++++++++++++++++-- .../procedures/UeTesterMessage.go | 1 + internal/control_test_engine/ue/ue.go | 3 +- .../test-attach-ue-with-configuration.go | 2 +- internal/templates/test-multi-ues-in-queue.go | 3 +- 8 files changed, 84 insertions(+), 13 deletions(-) diff --git a/cmd/packetrusher.go b/cmd/packetrusher.go index 3cbecee3..df02fc60 100644 --- a/cmd/packetrusher.go +++ b/cmd/packetrusher.go @@ -92,6 +92,7 @@ func main() { &cli.IntFlag{Name: "timeBeforeNgapHandover", Value: 0, Aliases: []string{"ngh"}, Usage: "The time in ms, before triggering a UE handover using NGAP Handover. 0 to disable handover. This requires at least two gNodeB, eg: two N2/N3 IPs."}, &cli.IntFlag{Name: "timeBeforeXnHandover", Value: 0, Aliases: []string{"xnh"}, Usage: "The time in ms, before triggering a UE handover using Xn Handover. 0 to disable handover. This requires at least two gNodeB, eg: two N2/N3 IPs."}, &cli.IntFlag{Name: "timeBeforeIdle", Value: 0, Aliases: []string{"idl"}, Usage: "The time in ms, before switching UE to Idle. 0 to disable Idling."}, + &cli.IntFlag{Name: "timeBeforeReconnecting", Value: 1000, Aliases: []string{"tbr"}, Usage: "The time in ms, before reconnecting to gNodeB after switching to Idle state. Default is 1000 ms. Only work in conjunction with timeBeforeIdle."}, &cli.IntFlag{Name: "numPduSessions", Value: 1, Aliases: []string{"nPdu"}, Usage: "The number of PDU Sessions to create"}, &cli.BoolFlag{Name: "loop", Aliases: []string{"l"}, Usage: "Register UEs in a loop."}, &cli.BoolFlag{Name: "tunnel", Aliases: []string{"t"}, Usage: "Enable the creation of the GTP-U tunnel interface."}, @@ -131,7 +132,7 @@ func main() { tunnelMode = config.TunnelTun } } - templates.TestMultiUesInQueue(numUes, tunnelMode, c.Bool("dedicatedGnb"), c.Bool("loop"), c.Int("timeBetweenRegistration"), c.Int("timeBeforeDeregistration"), c.Int("timeBeforeNgapHandover"), c.Int("timeBeforeXnHandover"), c.Int("timeBeforeIdle"), c.Int("numPduSessions")) + templates.TestMultiUesInQueue(numUes, tunnelMode, c.Bool("dedicatedGnb"), c.Bool("loop"), c.Int("timeBetweenRegistration"), c.Int("timeBeforeDeregistration"), c.Int("timeBeforeNgapHandover"), c.Int("timeBeforeXnHandover"), c.Int("timeBeforeIdle"), c.Int("timeBeforeReconnecting"), c.Int("numPduSessions")) return nil }, diff --git a/internal/common/tools/tools.go b/internal/common/tools/tools.go index 66303783..7925650c 100644 --- a/internal/common/tools/tools.go +++ b/internal/common/tools/tools.go @@ -106,6 +106,7 @@ type UESimulationConfig struct { TimeBeforeNgapHandover int TimeBeforeXnHandover int TimeBeforeIdle int + TimeBeforeReconnecting int NumPduSessions int } @@ -148,6 +149,7 @@ func SimulateSingleUE(simConfig UESimulationConfig, wg *sync.WaitGroup) { } var idleChannel <-chan time.Time = nil + var reconnectChannel <-chan time.Time = nil if simConfig.TimeBeforeIdle != 0 { idleChannel = time.After(time.Duration(simConfig.TimeBeforeIdle) * time.Millisecond) } @@ -171,6 +173,14 @@ func SimulateSingleUE(simConfig UESimulationConfig, wg *sync.WaitGroup) { case <-idleChannel: if ueRx != nil { ueRx <- procedures.UeTesterMessage{Type: procedures.Idle} + // Channel creation to be transformed into a task ;-) + if simConfig.TimeBeforeReconnecting != 0 { + reconnectChannel = time.After(time.Duration(simConfig.TimeBeforeReconnecting) * time.Millisecond) + } + } + case <-reconnectChannel: + if ueRx != nil { + ueRx <- procedures.UeTesterMessage{Type: procedures.ServiceRequest} } case msg := <-scenarioChan: if ueRx != nil { diff --git a/internal/control_test_engine/gnb/ngap/dispatcher.go b/internal/control_test_engine/gnb/ngap/dispatcher.go index 6da420b6..51a521b9 100644 --- a/internal/control_test_engine/gnb/ngap/dispatcher.go +++ b/internal/control_test_engine/gnb/ngap/dispatcher.go @@ -67,10 +67,15 @@ func Dispatch(amf *context.GNBAmf, gnb *context.GNBContext, message []byte) { handler.HandlerAmfConfigurationUpdate(amf, gnb, ngapMsg) case ngapType.ProcedureCodeHandoverResourceAllocation: - // handler NGAP Handover REquest + // handler NGAP Handover Request log.Info("[GNB][NGAP] Receive Handover Request") handler.HandlerHandoverRequest(amf, gnb, ngapMsg) + case ngapType.ProcedureCodePaging: + // handler NGAP Paging + log.Info("[GNB][NGAP] Receive Paging") + handler.HandlerPaging(gnb, ngapMsg) + case ngapType.ProcedureCodeErrorIndication: // handler Error Indicator log.Error("[GNB][NGAP] Receive Error Indication") diff --git a/internal/control_test_engine/gnb/ngap/handler/handler.go b/internal/control_test_engine/gnb/ngap/handler/handler.go index f449b5fa..7731b5fe 100644 --- a/internal/control_test_engine/gnb/ngap/handler/handler.go +++ b/internal/control_test_engine/gnb/ngap/handler/handler.go @@ -57,6 +57,10 @@ func HandlerDownlinkNasTransport(gnb *context.GNBContext, message *ngapType.NGAP } ue := getUeFromContext(gnb, ranUeId, amfUeId) + if ue == nil { + log.Errorf("[GNB][NGAP] Cannot send DownlinkNASTransport message to UE with RANUEID %d as it does not know this UE", ranUeId) + return + } // send NAS message to UE. sender.SendToUe(ue, messageNas) @@ -177,7 +181,10 @@ func HandlerInitialContextSetupRequest(gnb *context.GNBContext, message *ngapTyp } ue := getUeFromContext(gnb, ranUeId, amfUeId) - + if ue == nil { + log.Errorf("[GNB][NGAP] Cannot setup context for unknown UE with RANUEID %d", ranUeId) + return + } // create UE context. ue.CreateUeContext(mobilityRestrict, maskedImeisv, sst, sd, ueSecurityCapabilities) @@ -284,6 +291,10 @@ func HandlerPduSessionResourceSetupRequest(gnb *context.GNBContext, message *nga } ue := getUeFromContext(gnb, ranUeId, amfUeId) + if ue == nil { + log.Errorf("[GNB][NGAP] Cannot setup PDU Session for unknown UE With RANUEID %d", ranUeId) + return + } var configuredPduSessions []*context.GnbPDUSession for _, item := range pDUSessionResourceSetupList.List { @@ -445,6 +456,10 @@ func HandlerPduSessionReleaseCommand(gnb *context.GNBContext, message *ngapType. } ue := getUeFromContext(gnb, ranUeId, amfUeId) + if ue == nil { + log.Errorf("[GNB][NGAP] Cannot release PDU Session for unknown UE With RANUEID %d", ranUeId) + return + } for _, pduSessionId := range pduSessionIds { pduSession, err := ue.GetPduSession(pduSessionId.Value) @@ -703,6 +718,10 @@ func HandlerPathSwitchRequestAcknowledge(gnb *context.GNBContext, message *ngapT } ue := getUeFromContext(gnb, ranUeId, amfUeId) + if ue == nil { + log.Errorf("[GNB][NGAP] Cannot Xn Handover unknown UE With RANUEID %d", ranUeId) + return + } if pduSessionResourceSwitchedList == nil || len(pduSessionResourceSwitchedList.List) == 0 { log.Warn("[GNB] No PDU Sessions to be switched") @@ -911,6 +930,10 @@ func HandlerHandoverCommand(amf *context.GNBAmf, gnb *context.GNBContext, messag } ue := getUeFromContext(gnb, ranUeId, amfUeId) + if ue == nil { + log.Errorf("[GNB][NGAP] Cannot NGAP Handover unknown UE With RANUEID %d", ranUeId) + return + } newGnb := ue.GetHandoverGnodeB() if newGnb == nil { log.Error("[GNB] AMF is sending a Handover Command for an UE we did not send a Handover Required message") @@ -927,6 +950,41 @@ func HandlerHandoverCommand(amf *context.GNBAmf, gnb *context.GNBContext, messag sender.SendMessageToUe(ue, msg) } +func HandlerPaging(gnb *context.GNBContext, message *ngapType.NGAPPDU) { + + valueMessage := message.InitiatingMessage.Value.Paging + + var uEPagingIdentity *ngapType.UEPagingIdentity + var tAIListForPaging *ngapType.TAIListForPaging + + for _, ies := range valueMessage.ProtocolIEs.List { + switch ies.Id.Value { + + case ngapType.ProtocolIEIDUEPagingIdentity: + + if ies.Value.UEPagingIdentity == nil { + log.Fatal("[GNB][NGAP] UE Paging Identity is missing") + } + uEPagingIdentity = ies.Value.UEPagingIdentity + + case ngapType.ProtocolIEIDTAIListForPaging: + + if ies.Value.TAIListForPaging == nil { + log.Fatal("[GNB][NGAP] TAI List For Paging is missing") + } + tAIListForPaging = ies.Value.TAIListForPaging + } + } + _ = uEPagingIdentity + _ = tAIListForPaging + // TODO: Implement Paging + // Upon reception of the Paging with its TMSI, the UE must send a Service Request + // as in UE-initiated Service Request + // But: we need to figure out how the gNodeB may contact the UE when it's not in its context + // While avoiding adding a new channel, deadlock / sending to closed channels, having to jungle too much between channels when doing handover + log.Warnf("[GNB][AMF] UE Paging is not implemented, please manually reconnect UE with --timeBeforeReconnecting") +} + func HandlerErrorIndication(gnb *context.GNBContext, message *ngapType.NGAPPDU) { valueMessage := message.InitiatingMessage.Value.ErrorIndication @@ -960,7 +1018,8 @@ func getUeFromContext(gnb *context.GNBContext, ranUeId int64, amfUeId int64) *co // check RanUeId and get UE. ue, err := gnb.GetGnbUe(ranUeId) if err != nil || ue == nil { - log.Fatal("[GNB][NGAP] RAN UE NGAP ID is incorrect, found: ", ranUeId) + log.Error("[GNB][NGAP] RAN UE NGAP ID is incorrect, found: ", ranUeId) + return nil // TODO SEND ERROR INDICATION } @@ -974,19 +1033,14 @@ func causeToString(cause *ngapType.Cause) string { switch cause.Present { case ngapType.CausePresentRadioNetwork: return "radioNetwork: " + causeRadioNetworkToString(cause.RadioNetwork) - break case ngapType.CausePresentTransport: return "transport: " + causeTransportToString(cause.Transport) - break case ngapType.CausePresentNas: return "nas: " + causeNasToString(cause.Nas) - break case ngapType.CausePresentProtocol: return "protocol: " + causeProtocolToString(cause.Protocol) - break case ngapType.CausePresentMisc: return "misc: " + causeMiscToString(cause.Misc) - break } } return "Cause not found" diff --git a/internal/control_test_engine/procedures/UeTesterMessage.go b/internal/control_test_engine/procedures/UeTesterMessage.go index 5ed7373c..b37d00a6 100644 --- a/internal/control_test_engine/procedures/UeTesterMessage.go +++ b/internal/control_test_engine/procedures/UeTesterMessage.go @@ -16,6 +16,7 @@ const ( Terminate UeTesterMessageType = 4 Kill UeTesterMessageType = 5 Idle UeTesterMessageType = 6 + ServiceRequest UeTesterMessageType = 7 ) type UeTesterMessage struct { diff --git a/internal/control_test_engine/ue/ue.go b/internal/control_test_engine/ue/ue.go index b0d6d4da..e136770b 100644 --- a/internal/control_test_engine/ue/ue.go +++ b/internal/control_test_engine/ue/ue.go @@ -119,8 +119,7 @@ func ueMgrHandler(msg procedures.UeTesterMessage, ue *context.UEContext) bool { // We switch UE to IDLE ue.SetStateMM_IDLE() trigger.SwitchToIdle(ue) - - time.Sleep(1 * time.Second) + case procedures.ServiceRequest: // Since gNodeB stopped communication after switching to Idle, we need to connect back to gNodeB service.InitConn(ue, ue.GetGnbInboundChannel()) if ue.Get5gGuti() != nil { diff --git a/internal/templates/test-attach-ue-with-configuration.go b/internal/templates/test-attach-ue-with-configuration.go index f1209820..ffa08664 100644 --- a/internal/templates/test-attach-ue-with-configuration.go +++ b/internal/templates/test-attach-ue-with-configuration.go @@ -11,5 +11,5 @@ func TestAttachUeWithConfiguration(tunnelEnabled bool) { if tunnelEnabled { tunnelMode = config.TunnelVrf } - TestMultiUesInQueue(1, tunnelMode, true, false, 500, 0, 0, 0, 0, 1) + TestMultiUesInQueue(1, tunnelMode, true, false, 500, 0, 0, 0, 0, 0, 1) } diff --git a/internal/templates/test-multi-ues-in-queue.go b/internal/templates/test-multi-ues-in-queue.go index 0a051f05..7e5d99c9 100644 --- a/internal/templates/test-multi-ues-in-queue.go +++ b/internal/templates/test-multi-ues-in-queue.go @@ -16,7 +16,7 @@ import ( log "github.com/sirupsen/logrus" ) -func TestMultiUesInQueue(numUes int, tunnelMode config.TunnelMode, dedicatedGnb bool, loop bool, timeBetweenRegistration int, timeBeforeDeregistration int, timeBeforeNgapHandover int, timeBeforeXnHandover int, timeBeforeIdle int, numPduSessions int) { +func TestMultiUesInQueue(numUes int, tunnelMode config.TunnelMode, dedicatedGnb bool, loop bool, timeBetweenRegistration int, timeBeforeDeregistration int, timeBeforeNgapHandover int, timeBeforeXnHandover int, timeBeforeIdle int, timeBeforeReconnecting int, numPduSessions int) { if tunnelMode != config.TunnelDisabled { if !dedicatedGnb { log.Fatal("You cannot use the --tunnel option, without using the --dedicatedGnb option") @@ -64,6 +64,7 @@ func TestMultiUesInQueue(numUes int, tunnelMode config.TunnelMode, dedicatedGnb TimeBeforeNgapHandover: timeBeforeNgapHandover, TimeBeforeXnHandover: timeBeforeXnHandover, TimeBeforeIdle: timeBeforeIdle, + TimeBeforeReconnecting: timeBeforeReconnecting, NumPduSessions: numPduSessions, }