lte: Handover failure test suite and related code

This commit is contained in:
Sachin Nayak
2021-11-10 06:47:30 -08:00
committed by Tom Henderson
parent af1739551c
commit 0dbe96f62d
8 changed files with 601 additions and 54 deletions

View File

@@ -335,6 +335,7 @@ set(test_sources
test/test-lte-antenna.cc
test/test-lte-epc-e2e-data.cc
test/test-lte-handover-delay.cc
test/test-lte-handover-failure.cc
test/test-lte-handover-target.cc
test/test-lte-rlc-header.cc
test/test-lte-rrc.cc

View File

@@ -480,6 +480,13 @@ public:
* \param params UE data parameters
*/
virtual void RecvUeData (UeDataParams params) = 0;
/**
* Receive handover cancel function
* \param params the receive handover cancel parameters
*
*/
virtual void RecvHandoverCancel (HandoverCancelParams params) = 0;
};
///////////////////////////////////////
@@ -701,6 +708,13 @@ public:
*/
virtual void RecvUeData (UeDataParams params);
/**
* Receive handover cancel function
* \param params the receive handover cancel parameters
*
*/
virtual void RecvHandoverCancel (HandoverCancelParams params);
private:
EpcX2SpecificEpcX2SapUser ();
C* m_rrc; ///< owner class
@@ -773,6 +787,13 @@ EpcX2SpecificEpcX2SapUser<C>::RecvUeData (UeDataParams params)
m_rrc->DoRecvUeData (params);
}
template <class C>
void
EpcX2SpecificEpcX2SapUser<C>::RecvHandoverCancel (HandoverCancelParams params)
{
m_rrc->DoRecvHandoverCancel (params);
}
} // namespace ns3
#endif // EPC_X2_SAP_H

View File

@@ -362,6 +362,33 @@ EpcX2::RecvFromX2cSocket (Ptr<Socket> socket)
m_x2SapUser->RecvResourceStatusUpdate (params);
}
}
else if (procedureCode == EpcX2Header::HandoverCancel)
{
if (messageType == EpcX2Header::SuccessfulOutcome)
{
NS_LOG_LOGIC("Recv X2 message: HANDOVER CANCEL");
EpcX2HandoverCancelHeader x2HoCancelHeader;
packet->RemoveHeader (x2HoCancelHeader);
NS_LOG_INFO("X2 HandoverCancel header: " << x2HoCancelHeader);
EpcX2SapUser::HandoverCancelParams params;
params.oldEnbUeX2apId = x2HoCancelHeader.GetOldEnbUeX2apId ();
params.newEnbUeX2apId = x2HoCancelHeader.GetNewEnbUeX2apId ();
params.sourceCellId = cellsInfo->m_localCellIds.at (0);
params.targetCellId = cellsInfo->m_remoteCellIds.at (0);
params.cause = x2HoCancelHeader.GetCause ();
NS_LOG_LOGIC("oldEnbUeX2apId = " << params.oldEnbUeX2apId);
NS_LOG_LOGIC("newEnbUeX2apId = " << params.newEnbUeX2apId);
NS_LOG_LOGIC("sourceCellId = " << params.sourceCellId);
NS_LOG_LOGIC("targetCellId = " << params.targetCellId);
NS_LOG_LOGIC("cause = " << params.cause);
m_x2SapUser->RecvHandoverCancel (params);
}
}
else
{
NS_ASSERT_MSG (false, "ProcedureCode NOT SUPPORTED!!!");

View File

@@ -571,11 +571,15 @@ void
LteEnbRrc::DoSendReleaseDataRadioBearer (uint64_t imsi, uint16_t rnti, uint8_t bearerId)
{
NS_LOG_FUNCTION (this << imsi << rnti << (uint16_t) bearerId);
Ptr<UeManager> ueManager = GetUeManager (rnti);
// Bearer de-activation towards UE
ueManager->ReleaseDataRadioBearer (bearerId);
// Bearer de-activation indication towards epc-enb application
m_s1SapProvider->DoSendReleaseIndication (imsi,rnti,bearerId);
// check if the RNTI to be removed is not stale
if (HasUeManager (rnti)) {
Ptr<UeManager> ueManager = GetUeManager (rnti);
// Bearer de-activation towards UE
ueManager->ReleaseDataRadioBearer (bearerId);
// Bearer de-activation indication towards epc-enb application
m_s1SapProvider->DoSendReleaseIndication (imsi,rnti,bearerId);
}
}
void
@@ -996,7 +1000,7 @@ UeManager::RecvHandoverPreparationFailure (uint16_t cellId)
NS_LOG_INFO ("target eNB sent HO preparation failure, aborting HO");
SwitchToState (CONNECTED_NORMALLY);
break;
case HANDOVER_LEAVING: //case added to tackle HO joining timer expiration
case HANDOVER_LEAVING: //case added to tackle HO leaving timer expiration
NS_ASSERT (cellId == m_targetCellId);
NS_LOG_INFO ("target eNB sent HO preparation failure, aborting HO");
m_handoverLeavingTimeout.Cancel ();
@@ -1036,6 +1040,14 @@ UeManager::RecvUeContextRelease (EpcX2SapUser::UeContextReleaseParams params)
m_handoverLeavingTimeout.Cancel ();
}
void
UeManager::RecvHandoverCancel (EpcX2SapUser::HandoverCancelParams params)
{
NS_LOG_FUNCTION (this);
NS_ASSERT_MSG (m_state == HANDOVER_JOINING, "method unexpected in state " << ToString (m_state));
m_handoverJoiningTimeout.Cancel ();
}
void
UeManager::SendRrcConnectionRelease ()
{
@@ -2541,17 +2553,20 @@ LteEnbRrc::HandoverJoiningTimeout (uint16_t rnti)
"HandoverJoiningTimeout in unexpected state " << ToString (GetUeManager (rnti)->GetState ()));
m_handoverFailureJoiningTrace (GetUeManager (rnti)->GetImsi (), rnti,
ComponentCarrierToCellId (GetUeManager (rnti)->GetComponentCarrierId ()));
/**
* When the handover joining timer expires at the target cell,
* then notify the source cell to release the RRC connection and
* delete the UE context at eNodeB and SGW/PGW. The
* HandoverPreparationFailure message is reused to notify the source cell
* through the X2 interface instead of creating a new message.
*/
Ptr<UeManager> ueManager = GetUeManager (rnti);
EpcX2Sap::HandoverPreparationFailureParams msg = ueManager->BuildHoPrepFailMsg ();
m_x2SapProvider->SendHandoverPreparationFailure (msg);
RemoveUe (rnti);
// check if the RNTI to be removed is not stale
if (HasUeManager (rnti)) {
/**
* When the handover joining timer expires at the target cell,
* then notify the source cell to release the RRC connection and
* delete the UE context at eNodeB and SGW/PGW. The
* HandoverPreparationFailure message is reused to notify the source cell
* through the X2 interface instead of creating a new message.
*/
Ptr<UeManager> ueManager = GetUeManager (rnti);
EpcX2Sap::HandoverPreparationFailureParams msg = ueManager->BuildHoPrepFailMsg ();
m_x2SapProvider->SendHandoverPreparationFailure (msg);
RemoveUe (rnti);
}
}
void
@@ -2562,15 +2577,18 @@ LteEnbRrc::HandoverLeavingTimeout (uint16_t rnti)
"HandoverLeavingTimeout in unexpected state " << ToString (GetUeManager (rnti)->GetState ()));
m_handoverFailureLeavingTrace (GetUeManager (rnti)->GetImsi (), rnti,
ComponentCarrierToCellId (GetUeManager (rnti)->GetComponentCarrierId ()));
/**
* Send HO cancel msg to the target eNB and release the RRC connection
* with the UE and also delete UE context at the source eNB and bearer
* info at SGW and PGW.
*/
Ptr<UeManager> ueManager = GetUeManager (rnti);
EpcX2Sap::HandoverCancelParams msg = ueManager->BuildHoCancelMsg ();
m_x2SapProvider->SendHandoverCancel (msg);
ueManager->SendRrcConnectionRelease ();
// check if the RNTI to be removed is not stale
if (HasUeManager (rnti)) {
/**
* Send HO cancel msg to the target eNB and release the RRC connection
* with the UE and also delete UE context at the source eNB and bearer
* info at SGW and PGW.
*/
Ptr<UeManager> ueManager = GetUeManager (rnti);
EpcX2Sap::HandoverCancelParams msg = ueManager->BuildHoCancelMsg ();
m_x2SapProvider->SendHandoverCancel (msg);
ueManager->SendRrcConnectionRelease ();
}
}
void
@@ -2646,25 +2664,31 @@ void
LteEnbRrc::DoRecvIdealUeContextRemoveRequest (uint16_t rnti)
{
NS_LOG_FUNCTION (this << rnti);
Ptr<UeManager> ueManager = GetUeManager (rnti);
if (ueManager->GetState () == UeManager::HANDOVER_JOINING)
// check if the RNTI to be removed is not stale
if (HasUeManager (rnti))
{
m_handoverFailureMaxRachTrace (GetUeManager (rnti)->GetImsi (), rnti,
ComponentCarrierToCellId (GetUeManager (rnti)->GetComponentCarrierId ()));
/**
* During the HO, when the RACH failure due to the maximum number of
* re-attempts is reached the UE request the target eNB to deletes its
* context. Upon which, the target eNB sends handover preparation
* failure to the source eNB.
*/
EpcX2Sap::HandoverPreparationFailureParams msg = ueManager->BuildHoPrepFailMsg ();
m_x2SapProvider->SendHandoverPreparationFailure (msg);
Ptr<UeManager> ueManager = GetUeManager (rnti);
if (ueManager->GetState () == UeManager::HANDOVER_JOINING)
{
m_handoverFailureMaxRachTrace (GetUeManager (rnti)->GetImsi (), rnti,
ComponentCarrierToCellId (GetUeManager (rnti)->GetComponentCarrierId ()));
/**
* During the HO, when the RACH failure due to the maximum number of
* re-attempts is reached the UE request the target eNB to deletes its
* context. Upon which, the target eNB sends handover preparation
* failure to the source eNB.
*/
EpcX2Sap::HandoverPreparationFailureParams msg = ueManager->BuildHoPrepFailMsg ();
m_x2SapProvider->SendHandoverPreparationFailure (msg);
}
GetUeManager (rnti)->RecvIdealUeContextRemoveRequest (rnti);
// delete the UE context at the eNB
RemoveUe (rnti);
}
GetUeManager (rnti)->RecvIdealUeContextRemoveRequest (rnti);
//delete the UE context at the eNB
RemoveUe (rnti);
}
void
@@ -2695,7 +2719,8 @@ LteEnbRrc::DoRecvHandoverRequest (EpcX2SapUser::HandoverRequestParams req)
NS_LOG_LOGIC ("targetCellId = " << req.targetCellId);
NS_LOG_LOGIC ("mmeUeS1apId = " << req.mmeUeS1apId);
if (m_admitHandoverRequest == false)
// if no SRS index is available, then do not accept the handover
if (m_admitHandoverRequest == false || IsMaxSrsReached())
{
NS_LOG_INFO ("rejecting handover request from cellId " << req.sourceCellId);
EpcX2Sap::HandoverPreparationFailureParams res;
@@ -2805,8 +2830,12 @@ LteEnbRrc::DoRecvHandoverPreparationFailure (EpcX2SapUser::HandoverPreparationFa
NS_LOG_LOGIC ("criticalityDiagnostics = " << params.criticalityDiagnostics);
uint16_t rnti = params.oldEnbUeX2apId;
Ptr<UeManager> ueManager = GetUeManager (rnti);
ueManager->RecvHandoverPreparationFailure (params.targetCellId);
// check if the RNTI is not stale
if (HasUeManager (rnti)) {
Ptr<UeManager> ueManager = GetUeManager (rnti);
ueManager->RecvHandoverPreparationFailure (params.targetCellId);
}
}
void
@@ -2821,8 +2850,13 @@ LteEnbRrc::DoRecvSnStatusTransfer (EpcX2SapUser::SnStatusTransferParams params)
NS_LOG_LOGIC ("erabsSubjectToStatusTransferList size = " << params.erabsSubjectToStatusTransferList.size ());
uint16_t rnti = params.newEnbUeX2apId;
Ptr<UeManager> ueManager = GetUeManager (rnti);
ueManager->RecvSnStatusTransfer (params);
// check if the RNTI to receive SN transfer for is not stale
if (HasUeManager (rnti))
{
Ptr<UeManager> ueManager = GetUeManager (rnti);
ueManager->RecvSnStatusTransfer (params);
}
}
void
@@ -2836,8 +2870,12 @@ LteEnbRrc::DoRecvUeContextRelease (EpcX2SapUser::UeContextReleaseParams params)
NS_LOG_LOGIC ("newEnbUeX2apId = " << params.newEnbUeX2apId);
uint16_t rnti = params.oldEnbUeX2apId;
GetUeManager (rnti)->RecvUeContextRelease (params);
RemoveUe (rnti);
// check if the RNTI to be removed is not stale
if (HasUeManager (rnti)) {
GetUeManager (rnti)->RecvUeContextRelease (params);
RemoveUe (rnti);
}
}
void
@@ -2889,11 +2927,37 @@ LteEnbRrc::DoRecvUeData (EpcX2SapUser::UeDataParams params)
}
}
void
LteEnbRrc::DoRecvHandoverCancel (EpcX2SapUser::HandoverCancelParams params)
{
NS_LOG_FUNCTION (this);
NS_LOG_LOGIC ("Recv X2 message: HANDOVER CANCEL");
NS_LOG_LOGIC ("oldEnbUeX2apId = " << params.oldEnbUeX2apId);
NS_LOG_LOGIC ("newEnbUeX2apId = " << params.newEnbUeX2apId);
NS_LOG_LOGIC ("sourceCellId = " << params.sourceCellId);
NS_LOG_LOGIC ("targetCellId = " << params.targetCellId);
NS_LOG_LOGIC ("cause = " << params.cause);
uint16_t rnti = params.newEnbUeX2apId;
if (HasUeManager (rnti))
{
Ptr<UeManager> ueManager = GetUeManager (rnti);
ueManager->RecvHandoverCancel (params);
GetUeManager (rnti)->RecvIdealUeContextRemoveRequest (rnti);
}
}
uint16_t
LteEnbRrc::DoAllocateTemporaryCellRnti (uint8_t componentCarrierId)
{
NS_LOG_FUNCTION (this << +componentCarrierId);
// if no SRS index is available, then do not create a new UE context.
if(IsMaxSrsReached())
{
return 0; // return 0 since new RNTI was not assigned for the received preamble
}
return AddUe (UeManager::INITIAL_RANDOM_ACCESS, componentCarrierId);
}
@@ -3245,7 +3309,23 @@ LteEnbRrc::RemoveSrsConfigurationIndex (uint16_t srcCi)
m_ueSrsConfigurationIndexSet.erase (it);
}
uint8_t
bool
LteEnbRrc::IsMaxSrsReached ()
{
NS_ASSERT(m_srsCurrentPeriodicityId > 0);
NS_ASSERT(m_srsCurrentPeriodicityId < SRS_ENTRIES);
NS_LOG_DEBUG(this << " SRS p " << g_srsPeriodicity[m_srsCurrentPeriodicityId] << " set " << m_ueSrsConfigurationIndexSet.size ());
if (m_ueSrsConfigurationIndexSet.size () >= g_srsPeriodicity[m_srsCurrentPeriodicityId])
{
return true;
}
else
{
return false;
}
}
uint8_t
LteEnbRrc::GetLogicalChannelGroup (EpsBearer bearer)
{
if (bearer.IsGbr ())

View File

@@ -266,6 +266,12 @@ public:
*/
void RecvUeContextRelease (EpcX2SapUser::UeContextReleaseParams params);
/**
* Take the necessary actions in response to the reception of an X2 UE CONTEXT RELEASE message
*
* \param params the SN STATUS
*/
void RecvHandoverCancel (EpcX2SapUser::HandoverCancelParams params);
// METHODS FORWARDED FROM ENB RRC SAP ///////////////////////////////////////
@@ -1276,6 +1282,13 @@ private:
* \param params EpcX2SapUser::UeDataParams
*/
void DoRecvUeData (EpcX2SapUser::UeDataParams params);
/**
* Receive Handover Cancel function.
*
* \param params EpcX2SapUser::HandoverCancelParams
*/
void DoRecvHandoverCancel (EpcX2SapUser::HandoverCancelParams params);
// CMAC SAP methods
@@ -1474,7 +1487,10 @@ private:
*/
void RemoveSrsConfigurationIndex (uint16_t srcCi);
/**
* \return true if all the SRS indices are assigned to UEs
*/
bool IsMaxSrsReached();
/**
*

View File

@@ -299,9 +299,11 @@ LteEnbRrcProtocolIdeal::SetUeRrcSapProvider (uint16_t rnti, LteUeRrcSapProvider*
{
std::map<uint16_t, LteUeRrcSapProvider*>::iterator it;
it = m_enbRrcSapProviderMap.find (rnti);
NS_ASSERT_MSG (it != m_enbRrcSapProviderMap.end (), "Cell id " << m_cellId
<< " could not find RNTI = " << rnti);
it->second = p;
// assign UE RRC only if the RNTI is found at eNB
if (it != m_enbRrcSapProviderMap.end ())
{
it->second = p;
}
}
void

View File

@@ -448,7 +448,6 @@ LteEnbRrcProtocolReal::SetUeRrcSapProvider (uint16_t rnti, LteUeRrcSapProvider*
{
std::map<uint16_t, LteUeRrcSapProvider*>::iterator it;
it = m_enbRrcSapProviderMap.find (rnti);
// TODO: remove after merge of ho_failure branch
// assign UE RRC only if the RNTI is found at eNB
if (it != m_enbRrcSapProviderMap.end ())
{

View File

@@ -0,0 +1,401 @@
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2013 Magister Solutions (original test-lte-handover-delay.cc)
* Copyright (c) 2021 University of Washington (handover failure cases)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Sachin Nayak <sachinnn@uw.edu>
*/
#include <ns3/test.h>
#include <ns3/log.h>
#include <ns3/nstime.h>
#include <ns3/callback.h>
#include <ns3/config.h>
#include <ns3/boolean.h>
#include <ns3/simulator.h>
#include <ns3/node-container.h>
#include <ns3/net-device-container.h>
#include <ns3/ipv4-interface-container.h>
#include <ns3/lte-helper.h>
#include <ns3/point-to-point-epc-helper.h>
#include <ns3/internet-stack-helper.h>
#include <ns3/point-to-point-helper.h>
#include <ns3/ipv4-address-helper.h>
#include <ns3/ipv4-static-routing-helper.h>
#include <ns3/mobility-helper.h>
#include <ns3/data-rate.h>
#include <ns3/ipv4-static-routing.h>
#include <ns3/position-allocator.h>
using namespace ns3;
NS_LOG_COMPONENT_DEFINE ("LteHandoverFailureTest");
/**
* \ingroup lte-test
* \ingroup tests
*
* \brief Verifying that a handover failure occurs due to various causes
*
* Handover failure cases dealt with in this test include the below.
*
* 1. Handover failure due to max random access channel (RACH) attempts from UE to target eNodeB
* 2. Handover failure due to non-allocation of non-contention preamble to UE at target eNodeB
* 3. Handover failure due to HANDOVER JOINING timeout (3 cases)
* 4. Handover failure due to HANDOVER LEAVING timeout (3 cases)
*
* \sa ns3::LteHandoverFailureTestCase
*/
class LteHandoverFailureTestCase : public TestCase
{
public:
/**
* Constructor
*
* \param name the name of the test case, to be displayed in the test result
* \param useIdealRrc if true, use the ideal RRC
* \param handoverTime the time of handover
* \param simulationDuration duration of the simulation
* \param numberOfRaPreambles number of random access preambles available for contention based RACH process
* number of non-contention preambles available for handover = (64 - numberRaPreambles)
* as numberOfRaPreambles out of the max 64 are reserved contention based RACH process
* \param preambleTransMax maximum number of random access preamble transmissions from UE to eNodeB
* \param raResponseWindowSize window length for reception of random access response (RAR)
* \param handoverJoiningTimeout time before which RRC RECONFIGURATION COMPLETE must be received
at target eNodeB after it receives a handover request
Else, the UE context is destroyed in the RRC.
Timeout can occur before different stages as below.
i. Reception of RRC CONNECTION RECONFIGURATION at source eNodeB
ii. Non-contention random access procedure from UE to target eNodeB
iii. Reception of RRC CONNECTION RECONFIGURATION COMPLETE at target eNodeB
* \param handoverLeavingTimeout time before which source eNodeB must receive a UE context release
from target eNodeB or RRC CONNECTION RESTABLISHMENT from UE
after issuing a handover request
Else, the UE context is destroyed in the RRC.
Timeout can occur before any of the cases in HANDOVER JOINING TIMEOUT
* \param targeteNodeBPosition position of the target eNodeB
*/
LteHandoverFailureTestCase (std::string name,
bool useIdealRrc,
Time handoverTime,
Time simulationDuration,
uint8_t numberOfRaPreambles,
uint8_t preambleTransMax,
uint8_t raResponseWindowSize,
Time handoverJoiningTimeout,
Time handoverLeavingTimeout,
uint16_t targeteNodeBPosition)
: TestCase (name),
m_useIdealRrc (useIdealRrc),
m_handoverTime (handoverTime),
m_simulationDuration (simulationDuration),
m_numberOfRaPreambles (numberOfRaPreambles),
m_preambleTransMax (preambleTransMax),
m_raResponseWindowSize (raResponseWindowSize),
m_handoverJoiningTimeout (handoverJoiningTimeout),
m_handoverLeavingTimeout (handoverLeavingTimeout),
m_targeteNodeBPosition (targeteNodeBPosition),
m_hasHandoverFailureOccured (false)
{}
private:
/**
* \brief Run a simulation of a two eNodeB network using the parameters
* provided to the constructor function.
*/
void DoRun () override;
/**
* \brief Called at the end of simulation and verifies that a handover
* and a handover failure has occured in the simulation.
*/
void DoTeardown () override;
/**
* UE handover start callback function to indicate start of handover
* \param context the context string
* \param imsi the IMSI
* \param sourceCellId the source cell ID
* \param rnti the RNTI
* \param targetCellId the target cell ID
*/
void UeHandoverStartCallback (std::string context, uint64_t imsi,
uint16_t sourceCellId, uint16_t rnti, uint16_t targetCellId);
/**
* Handover failure callback due to maximum RACH transmissions reached from UE to target eNodeB
* \param context the context string
* \param imsi the IMSI
* \param rnti the RNTI
* \param targetCellId the target cell ID
*/
void HandoverFailureMaxRach (std::string context, uint64_t imsi,
uint16_t rnti, uint16_t targetCellId);
/**
* Handover failure callback due to non-allocation of non-contention preamble at target eNodeB
* \param context the context string
* \param imsi the IMSI
* \param rnti the RNTI
* \param targetCellId the target cell ID
*/
void HandoverFailureNoPreamble (std::string context, uint64_t imsi,
uint16_t rnti, uint16_t targetCellId);
/**
* Handover failure callback due to handover joining timeout at target eNodeB
* \param context the context string
* \param imsi the IMSI
* \param rnti the RNTI
* \param targetCellId the target cell ID
*/
void HandoverFailureJoining (std::string context, uint64_t imsi,
uint16_t rnti, uint16_t targetCellId);
/**
* Handover failure callback due to handover leaving timeout at source eNodeB
* \param context the context string
* \param imsi the IMSI
* \param rnti the RNTI
* \param targetCellId the target cell ID
*/
void HandoverFailureLeaving (std::string context, uint64_t imsi,
uint16_t rnti, uint16_t targetCellId);
bool m_useIdealRrc; ///< use ideal RRC?
Time m_handoverTime; ///< handover time
Time m_simulationDuration; ///< the simulation duration
uint8_t m_numberOfRaPreambles; ///< number of random access preambles for contention based RACH process
uint8_t m_preambleTransMax; ///< max number of RACH preambles possible from UE to eNodeB
uint8_t m_raResponseWindowSize; ///< window length for reception of RAR
Time m_handoverJoiningTimeout; ///< handover joining timeout duration at target eNodeB
Time m_handoverLeavingTimeout; ///< handover leaving timeout duration at source eNodeB
uint16_t m_targeteNodeBPosition; ///< position of the target eNodeB
bool m_hasHandoverFailureOccured; ///< has handover failure occured in simulation
}; // end of class LteHandoverFailureTestCase
void
LteHandoverFailureTestCase::DoRun ()
{
NS_LOG_INFO (this << " " << GetName ());
/*
* Helpers.
*/
auto epcHelper = CreateObject<PointToPointEpcHelper> ();
auto lteHelper = CreateObject<LteHelper> ();
lteHelper->SetEpcHelper (epcHelper);
// Set parameters for helpers based on the test case parameters.
lteHelper->SetAttribute ("UseIdealRrc", BooleanValue (m_useIdealRrc));
Config::SetDefault ("ns3::LteEnbMac::NumberOfRaPreambles", UintegerValue (m_numberOfRaPreambles));
Config::SetDefault ("ns3::LteEnbMac::PreambleTransMax", UintegerValue (m_preambleTransMax));
Config::SetDefault ("ns3::LteEnbMac::RaResponseWindowSize", UintegerValue (m_raResponseWindowSize));
Config::SetDefault ("ns3::LteEnbRrc::HandoverJoiningTimeoutDuration", TimeValue (m_handoverJoiningTimeout));
Config::SetDefault ("ns3::LteEnbRrc::HandoverLeavingTimeoutDuration", TimeValue (m_handoverLeavingTimeout));
// Set PHY model to drastically decrease with distance.
lteHelper->SetPathlossModelType (TypeId::LookupByName ("ns3::LogDistancePropagationLossModel"));
lteHelper->SetPathlossModelAttribute ("Exponent", DoubleValue (3.5));
lteHelper->SetPathlossModelAttribute ("ReferenceLoss", DoubleValue (35));
/*
* Physical layer.
*
* eNodeB 0 UE eNodeB 1
*
* x ----------------------- x -------------------------- x
* 200 m m_targeteNodeBPosition
* source target
*/
// Create nodes.
NodeContainer enbNodes;
enbNodes.Create (2);
auto ueNode = CreateObject<Node> ();
// Setup mobility
auto posAlloc = CreateObject<ListPositionAllocator> ();
posAlloc->Add (Vector (0, 0, 0));
posAlloc->Add (Vector (m_targeteNodeBPosition, 0, 0));
posAlloc->Add (Vector (200, 0, 0));
MobilityHelper mobilityHelper;
mobilityHelper.SetMobilityModel ("ns3::ConstantPositionMobilityModel");
mobilityHelper.SetPositionAllocator (posAlloc);
mobilityHelper.Install (enbNodes);
mobilityHelper.Install (ueNode);
/*
* Link layer.
*/
auto enbDevs = lteHelper->InstallEnbDevice (enbNodes);
auto ueDev = lteHelper->InstallUeDevice (ueNode).Get (0);
/*
* Network layer.
*/
InternetStackHelper inetStackHelper;
inetStackHelper.Install (ueNode);
Ipv4InterfaceContainer ueIfs;
ueIfs = epcHelper->AssignUeIpv4Address (ueDev);
// Setup traces.
Config::Connect ("/NodeList/*/DeviceList/*/LteUeRrc/HandoverStart",
MakeCallback (&LteHandoverFailureTestCase::UeHandoverStartCallback, this));
Config::Connect ("/NodeList/*/DeviceList/*/LteEnbRrc/HandoverFailureMaxRach",
MakeCallback (&LteHandoverFailureTestCase::HandoverFailureMaxRach, this));
Config::Connect ("/NodeList/*/DeviceList/*/LteEnbRrc/HandoverFailureNoPreamble",
MakeCallback (&LteHandoverFailureTestCase::HandoverFailureNoPreamble, this));
Config::Connect ("/NodeList/*/DeviceList/*/LteEnbRrc/HandoverFailureJoining",
MakeCallback (&LteHandoverFailureTestCase::HandoverFailureJoining, this));
Config::Connect ("/NodeList/*/DeviceList/*/LteEnbRrc/HandoverFailureLeaving",
MakeCallback (&LteHandoverFailureTestCase::HandoverFailureLeaving, this));
// Prepare handover.
lteHelper->AddX2Interface (enbNodes);
lteHelper->Attach (ueDev, enbDevs.Get (0));
lteHelper->HandoverRequest (m_handoverTime, ueDev, enbDevs.Get (0), enbDevs.Get (1));
// Run simulation.
Simulator::Stop (m_simulationDuration);
Simulator::Run ();
Simulator::Destroy ();
} // end of void LteHandoverFailureTestCase::DoRun ()
void
LteHandoverFailureTestCase::UeHandoverStartCallback (std::string context, uint64_t imsi,
uint16_t sourceCellId, uint16_t rnti, uint16_t targetCellId)
{
NS_LOG_FUNCTION (this << " " << context << " IMSI-" << imsi << " sourceCellID-" << sourceCellId << " RNTI-"<< rnti << " targetCellID-" << targetCellId);
NS_LOG_INFO ("HANDOVER COMMAND received through at UE " << imsi << " to handover from " << sourceCellId << " to " << targetCellId);
}
void
LteHandoverFailureTestCase::HandoverFailureMaxRach (std::string context, uint64_t imsi,
uint16_t rnti, uint16_t targetCellId)
{
NS_LOG_FUNCTION (this << context << imsi << rnti << targetCellId);
m_hasHandoverFailureOccured = true;
}
void
LteHandoverFailureTestCase::HandoverFailureNoPreamble (std::string context, uint64_t imsi,
uint16_t rnti, uint16_t targetCellId)
{
NS_LOG_FUNCTION (this << context << imsi << rnti << targetCellId);
m_hasHandoverFailureOccured = true;
}
void
LteHandoverFailureTestCase::HandoverFailureJoining (std::string context, uint64_t imsi,
uint16_t rnti, uint16_t targetCellId)
{
NS_LOG_FUNCTION (this << context << imsi << rnti << targetCellId);
m_hasHandoverFailureOccured = true;
}
void
LteHandoverFailureTestCase::HandoverFailureLeaving (std::string context, uint64_t imsi,
uint16_t rnti, uint16_t targetCellId)
{
NS_LOG_FUNCTION (this << context << imsi << rnti << targetCellId);
m_hasHandoverFailureOccured = true;
}
void
LteHandoverFailureTestCase::DoTeardown ()
{
NS_LOG_FUNCTION (this);
NS_TEST_ASSERT_MSG_EQ (m_hasHandoverFailureOccured, true, "Handover failure did not occur");
}
/**
* \ingroup lte-test
* \ingroup tests
*
* \brief Lte Handover Failure Test Suite
*/
static class LteHandoverFailureTestSuite : public TestSuite
{
public:
LteHandoverFailureTestSuite ()
: TestSuite ("lte-handover-failure", TestSuite::SYSTEM)
{
LogLevel logLevel = (LogLevel) (LOG_PREFIX_TIME | LOG_LEVEL_INFO);
LogComponentEnable ("LteHandoverFailureTest", logLevel);
LogComponentEnable ("LteEnbRrc", logLevel);
LogComponentEnable ("LteEnbMac", logLevel);
LogComponentEnable ("LteUeRrc", logLevel);
LogComponentEnable ("EpcX2", logLevel);
// Argument sequence for all test cases: useIdealRrc, handoverTime, simulationDuration, numberOfRaPreambles, preambleTransMax, raResponseWindowSize,
// handoverJoiningTimeout, handoverLeavingTimeout
// Test cases for REAL RRC protocol
AddTestCase (new LteHandoverFailureTestCase ("REAL Handover failure due to maximum RACH transmissions reached from UE to target eNodeB",
false, Seconds (0.200), Seconds (0.300), 52, 3, 3, MilliSeconds(200), MilliSeconds(500), 2500), TestCase::QUICK);
AddTestCase (new LteHandoverFailureTestCase ("REAL Handover failure due to non-allocation of non-contention preamble at target eNodeB due to max number reached",
false, Seconds (0.100), Seconds (0.200), 64, 50, 3, MilliSeconds(200), MilliSeconds(500), 1500), TestCase::QUICK);
AddTestCase (new LteHandoverFailureTestCase ("REAL Handover failure due to HANDOVER JOINING timeout before reception of RRC CONNECTION RECONFIGURATION at source eNodeB",
false, Seconds (0.100), Seconds (0.200), 52, 50, 3, MilliSeconds(0), MilliSeconds(500), 1500), TestCase::QUICK);
AddTestCase (new LteHandoverFailureTestCase ("REAL Handover failure due to HANDOVER JOINING timeout before completion of non-contention RACH process to target eNodeB",
false, Seconds (0.100), Seconds (0.200), 52, 50, 3, MilliSeconds(15), MilliSeconds(500), 1500), TestCase::QUICK);
AddTestCase (new LteHandoverFailureTestCase ("REAL Handover failure due to HANDOVER JOINING timeout before reception of RRC CONNECTION RECONFIGURATION COMPLETE at target eNodeB",
false, Seconds (0.100), Seconds (0.200), 52, 50, 3, MilliSeconds(18), MilliSeconds(500), 500), TestCase::QUICK);
AddTestCase (new LteHandoverFailureTestCase ("REAL Handover failure due to HANDOVER LEAVING timeout before reception of RRC CONNECTION RECONFIGURATION at source eNodeB",
false, Seconds (0.100), Seconds (0.200), 52, 50, 3, MilliSeconds(200), MilliSeconds(0), 1500), TestCase::QUICK);
AddTestCase (new LteHandoverFailureTestCase ("REAL Handover failure due to HANDOVER LEAVING timeout before completion of non-contention RACH process to target eNodeB",
false, Seconds (0.100), Seconds (0.200), 52, 50, 3, MilliSeconds(200), MilliSeconds(15), 1500), TestCase::QUICK);
AddTestCase (new LteHandoverFailureTestCase ("REAL Handover failure due to HANDOVER LEAVING timeout before reception of RRC CONNECTION RECONFIGURATION COMPLETE at target eNodeB",
false, Seconds (0.100), Seconds (0.200), 52, 50, 3, MilliSeconds(200), MilliSeconds(18), 500), TestCase::QUICK);
// Test cases for IDEAL RRC protocol
AddTestCase (new LteHandoverFailureTestCase ("IDEAL Handover failure due to maximum RACH transmissions reached from UE to target eNodeB",
true, Seconds (0.100), Seconds (0.200), 52, 3, 3, MilliSeconds(200), MilliSeconds(500), 1500), TestCase::QUICK);
AddTestCase (new LteHandoverFailureTestCase ("IDEAL Handover failure due to non-allocation of non-contention preamble at target eNodeB due to max number reached",
true, Seconds (0.100), Seconds (0.200), 64, 50, 3, MilliSeconds(200), MilliSeconds(500), 1500), TestCase::QUICK);
AddTestCase (new LteHandoverFailureTestCase ("IDEAL Handover failure due to HANDOVER JOINING timeout before reception of RRC CONNECTION RECONFIGURATION at source eNodeB",
true, Seconds (0.100), Seconds (0.200), 52, 50, 3, MilliSeconds(0), MilliSeconds(500), 1500), TestCase::QUICK);
AddTestCase (new LteHandoverFailureTestCase ("IDEAL Handover failure due to HANDOVER JOINING timeout before completion of non-contention RACH process to target eNodeB",
true, Seconds (0.100), Seconds (0.200), 52, 50, 3, MilliSeconds(10), MilliSeconds(500), 1500), TestCase::QUICK);
AddTestCase (new LteHandoverFailureTestCase ("IDEAL Handover failure due to HANDOVER JOINING timeout before reception of RRC CONNECTION RECONFIGURATION COMPLETE at target eNodeB",
true, Seconds (0.100), Seconds (0.200), 52, 50, 3, MilliSeconds(4), MilliSeconds(500), 500), TestCase::QUICK);
AddTestCase (new LteHandoverFailureTestCase ("IDEAL Handover failure due to HANDOVER LEAVING timeout before reception of RRC CONNECTION RECONFIGURATION at source eNodeB",
true, Seconds (0.100), Seconds (0.200), 52, 50, 3, MilliSeconds(500), MilliSeconds(0), 1500), TestCase::QUICK);
AddTestCase (new LteHandoverFailureTestCase ("IDEAL Handover failure due to HANDOVER LEAVING timeout before completion of non-contention RACH process to target eNodeB",
true, Seconds (0.100), Seconds (0.200), 52, 50, 3, MilliSeconds(500), MilliSeconds(10), 1500), TestCase::QUICK);
AddTestCase (new LteHandoverFailureTestCase ("IDEAL Handover failure due to HANDOVER LEAVING timeout before reception of RRC CONNECTION RECONFIGURATION COMPLETE at target eNodeB",
true, Seconds (0.100), Seconds (0.200), 52, 50, 3, MilliSeconds(500), MilliSeconds(4), 500), TestCase::QUICK);
}
} g_lteHandoverFailureTestSuite; ///< end of LteHandoverFailureTestSuite ()