A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
test-lte-x2-handover.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2012 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation;
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 *
17 * Author: Nicola Baldo <nbaldo@cttc.es>
18 */
19
20#include <ns3/core-module.h>
21#include <ns3/internet-module.h>
22#include <ns3/lte-module.h>
23#include <ns3/mobility-module.h>
24#include <ns3/network-module.h>
25#include <ns3/packet-sink-helper.h>
26#include <ns3/packet-sink.h>
27#include <ns3/point-to-point-module.h>
28#include <ns3/udp-client-server-helper.h>
29
30using namespace ns3;
31
32NS_LOG_COMPONENT_DEFINE("LteX2HandoverTest");
33
34/**
35 * \ingroup lte-test
36 *
37 * \brief HandoverEvent structure
38 */
40{
41 Time startTime; ///< start time
42 uint32_t ueDeviceIndex; ///< UE device index
43 uint32_t sourceEnbDeviceIndex; ///< source ENB device index
44 uint32_t targetEnbDeviceIndex; ///< target ENB device index
45};
46
47/**
48 * \ingroup lte-test
49 *
50 * \brief Test X2 Handover. In this test is used NoOpHandoverAlgorithm and
51 * the request for handover is generated manually, and it is not based on measurements.
52 */
54{
55 public:
56 /**
57 *
58 *
59 * \param nUes number of UEs in the test
60 * \param nDedicatedBearers number of bearers to be activated per UE
61 * \param handoverEventList
62 * \param handoverEventListName
63 * \param schedulerType the scheduler type
64 * \param admitHo
65 * \param useIdealRrc true if the ideal RRC should be used
66 */
68 uint32_t nDedicatedBearers,
69 std::list<HandoverEvent> handoverEventList,
70 std::string handoverEventListName,
71 std::string schedulerType,
72 bool admitHo,
73 bool useIdealRrc);
74
75 private:
76 /**
77 * Build name string
78 * \param nUes number of UEs in the test
79 * \param nDedicatedBearers number of bearers to be activated per UE
80 * \param handoverEventListName
81 * \param schedulerType the scheduler type
82 * \param admitHo
83 * \param useIdealRrc true if the ideal RRC should be used
84 * \returns the name string
85 */
86 static std::string BuildNameString(uint32_t nUes,
87 uint32_t nDedicatedBearers,
88 std::string handoverEventListName,
89 std::string schedulerType,
90 bool admitHo,
91 bool useIdealRrc);
92 void DoRun() override;
93 /**
94 * Check connected function
95 * \param ueDevice the UE device
96 * \param enbDevice the ENB device
97 */
98 void CheckConnected(Ptr<NetDevice> ueDevice, Ptr<NetDevice> enbDevice);
99
100 /**
101 * Teleport UE between both eNBs of the test
102 * \param ueNode the UE node
103 */
104 void TeleportUeToMiddle(Ptr<Node> ueNode);
105
106 /**
107 * Teleport UE near the target eNB of the handover
108 * \param ueNode the UE node
109 * \param enbNode the target eNB node
110 */
111 void TeleportUeNearTargetEnb(Ptr<Node> ueNode, Ptr<Node> enbNode);
112
113 uint32_t m_nUes; ///< number of UEs in the test
114 uint32_t m_nDedicatedBearers; ///< number of UEs in the test
115 std::list<HandoverEvent> m_handoverEventList; ///< handover event list
116 std::string m_handoverEventListName; ///< handover event list name
117 bool m_epc; ///< whether to use EPC
118 std::string m_schedulerType; ///< scheduler type
119 bool m_admitHo; ///< whether to admit the handover request
120 bool m_useIdealRrc; ///< whether to use the ideal RRC
123
124 /**
125 * \ingroup lte-test
126 *
127 * \brief BearerData structure
128 */
130 {
131 uint32_t bid; ///< BID
134 uint32_t dlOldTotalRx; ///< DL old total receive
135 uint32_t ulOldTotalRx; ///< UL old total receive
136 };
137
138 /**
139 * \ingroup lte-test
140 *
141 * \brief UeData structure
142 */
143 struct UeData
144 {
145 uint32_t id; ///< ID
146 std::list<BearerData> bearerDataList; ///< bearer ID list
147 };
148
149 /**
150 * \brief Save stats after handover function
151 * \param ueIndex the index of the UE
152 */
153 void SaveStatsAfterHandover(uint32_t ueIndex);
154 /**
155 * \brief Check stats a while after handover function
156 * \param ueIndex the index of the UE
157 */
159
160 std::vector<UeData> m_ueDataVector; ///< UE data vector
161
162 const Time m_maxHoDuration; ///< maximum HO duration
163 const Time m_statsDuration; ///< stats duration
164 const Time m_udpClientInterval; ///< UDP client interval
165 const uint32_t m_udpClientPktSize; ///< UDP client packet size
166};
167
168std::string
170 uint32_t nDedicatedBearers,
171 std::string handoverEventListName,
172 std::string schedulerType,
173 bool admitHo,
174 bool useIdealRrc)
175{
176 std::ostringstream oss;
177 oss << " nUes=" << nUes << " nDedicatedBearers=" << nDedicatedBearers << " " << schedulerType
178 << " admitHo=" << admitHo << " hoList: " << handoverEventListName;
179 if (useIdealRrc)
180 {
181 oss << ", ideal RRC";
182 }
183 else
184 {
185 oss << ", real RRC";
186 }
187 return oss.str();
188}
189
191 uint32_t nDedicatedBearers,
192 std::list<HandoverEvent> handoverEventList,
193 std::string handoverEventListName,
194 std::string schedulerType,
195 bool admitHo,
196 bool useIdealRrc)
197 : TestCase(BuildNameString(nUes,
198 nDedicatedBearers,
199 handoverEventListName,
200 schedulerType,
201 admitHo,
202 useIdealRrc)),
203 m_nUes(nUes),
204 m_nDedicatedBearers(nDedicatedBearers),
205 m_handoverEventList(handoverEventList),
206 m_handoverEventListName(handoverEventListName),
207 m_epc(true),
208 m_schedulerType(schedulerType),
209 m_admitHo(admitHo),
210 m_useIdealRrc(useIdealRrc),
211 m_maxHoDuration(Seconds(0.1)),
212 m_statsDuration(Seconds(0.1)),
213 m_udpClientInterval(Seconds(0.01)),
214 m_udpClientPktSize(100)
215
216{
217}
218
219void
221{
226 m_admitHo,
228
229 uint32_t previousSeed = RngSeedManager::GetSeed();
230 uint64_t previousRun = RngSeedManager::GetRun();
232 // This test is sensitive to random variable stream assignments
235 Config::SetDefault("ns3::UdpClient::Interval", TimeValue(m_udpClientInterval));
236 Config::SetDefault("ns3::UdpClient::MaxPackets", UintegerValue(1000000));
237 Config::SetDefault("ns3::UdpClient::PacketSize", UintegerValue(m_udpClientPktSize));
238
239 // Disable Uplink Power Control
240 Config::SetDefault("ns3::LteUePhy::EnableUplinkPowerControl", BooleanValue(false));
241
242 int64_t stream = 1;
243
244 m_lteHelper = CreateObject<LteHelper>();
245 m_lteHelper->SetAttribute("PathlossModel",
246 StringValue("ns3::FriisSpectrumPropagationLossModel"));
249 "ns3::NoOpHandoverAlgorithm"); // disable automatic handover
251
252 NodeContainer enbNodes;
253 enbNodes.Create(2);
254 NodeContainer ueNodes;
255 ueNodes.Create(m_nUes);
256
257 if (m_epc)
258 {
259 m_epcHelper = CreateObject<PointToPointEpcHelper>();
261 }
262
263 Ptr<ListPositionAllocator> positionAlloc = CreateObject<ListPositionAllocator>();
264 positionAlloc->Add(Vector(-3000, 0, 0)); // enb0
265 positionAlloc->Add(Vector(3000, 0, 0)); // enb1
266 for (uint32_t i = 0; i < m_nUes; i++)
267 {
268 positionAlloc->Add(Vector(-3000, 100, 0));
269 }
270 MobilityHelper mobility;
271 mobility.SetPositionAllocator(positionAlloc);
272 mobility.SetMobilityModel("ns3::ConstantPositionMobilityModel");
273 mobility.Install(enbNodes);
274 mobility.Install(ueNodes);
275
276 NetDeviceContainer enbDevices;
277 enbDevices = m_lteHelper->InstallEnbDevice(enbNodes);
278 stream += m_lteHelper->AssignStreams(enbDevices, stream);
279 for (auto it = enbDevices.Begin(); it != enbDevices.End(); ++it)
280 {
281 Ptr<LteEnbRrc> enbRrc = (*it)->GetObject<LteEnbNetDevice>()->GetRrc();
282 enbRrc->SetAttribute("AdmitHandoverRequest", BooleanValue(m_admitHo));
283 }
284
285 NetDeviceContainer ueDevices;
286 ueDevices = m_lteHelper->InstallUeDevice(ueNodes);
287 stream += m_lteHelper->AssignStreams(ueDevices, stream);
288
289 Ipv4Address remoteHostAddr;
290 Ipv4StaticRoutingHelper ipv4RoutingHelper;
291 Ipv4InterfaceContainer ueIpIfaces;
292 Ptr<Node> remoteHost;
293 if (m_epc)
294 {
295 // Create a single RemoteHost
296 NodeContainer remoteHostContainer;
297 remoteHostContainer.Create(1);
298 remoteHost = remoteHostContainer.Get(0);
299 InternetStackHelper internet;
300 internet.Install(remoteHostContainer);
301
302 // Create the Internet
304 p2ph.SetDeviceAttribute("DataRate", DataRateValue(DataRate("100Gb/s")));
305 p2ph.SetDeviceAttribute("Mtu", UintegerValue(1500));
306 p2ph.SetChannelAttribute("Delay", TimeValue(Seconds(0.010)));
308 NetDeviceContainer internetDevices = p2ph.Install(pgw, remoteHost);
309 Ipv4AddressHelper ipv4h;
310 ipv4h.SetBase("1.0.0.0", "255.0.0.0");
311 Ipv4InterfaceContainer internetIpIfaces = ipv4h.Assign(internetDevices);
312 // in this container, interface 0 is the pgw, 1 is the remoteHost
313 remoteHostAddr = internetIpIfaces.GetAddress(1);
314
315 Ipv4StaticRoutingHelper ipv4RoutingHelper;
316 Ptr<Ipv4StaticRouting> remoteHostStaticRouting =
317 ipv4RoutingHelper.GetStaticRouting(remoteHost->GetObject<Ipv4>());
318 remoteHostStaticRouting->AddNetworkRouteTo(Ipv4Address("7.0.0.0"),
319 Ipv4Mask("255.0.0.0"),
320 1);
321
322 // Install the IP stack on the UEs
323 internet.Install(ueNodes);
324 ueIpIfaces = m_epcHelper->AssignUeIpv4Address(NetDeviceContainer(ueDevices));
325 }
326
327 // attachment (needs to be done after IP stack configuration)
328 // all UEs attached to eNB 0 at the beginning
329 m_lteHelper->Attach(ueDevices, enbDevices.Get(0));
330
331 if (m_epc)
332 {
333 // always true: bool epcDl = true;
334 // always true: bool epcUl = true;
335 // the rest of this block is copied from lena-dual-stripe
336
337 // Install and start applications on UEs and remote host
338 uint16_t dlPort = 10000;
339 uint16_t ulPort = 20000;
340
341 // randomize a bit start times to avoid simulation artifacts
342 // (e.g., buffer overflows due to packet transmissions happening
343 // exactly at the same time)
344 Ptr<UniformRandomVariable> startTimeSeconds = CreateObject<UniformRandomVariable>();
345 startTimeSeconds->SetAttribute("Min", DoubleValue(0));
346 startTimeSeconds->SetAttribute("Max", DoubleValue(0.010));
347 startTimeSeconds->SetStream(stream++);
348
349 for (uint32_t u = 0; u < ueNodes.GetN(); ++u)
350 {
351 Ptr<Node> ue = ueNodes.Get(u);
352 // Set the default gateway for the UE
353 Ptr<Ipv4StaticRouting> ueStaticRouting =
354 ipv4RoutingHelper.GetStaticRouting(ue->GetObject<Ipv4>());
355 ueStaticRouting->SetDefaultRoute(m_epcHelper->GetUeDefaultGatewayAddress(), 1);
356
357 UeData ueData;
358
359 for (uint32_t b = 0; b < m_nDedicatedBearers; ++b)
360 {
361 ++dlPort;
362 ++ulPort;
363
364 ApplicationContainer clientApps;
365 ApplicationContainer serverApps;
366 BearerData bearerData = BearerData();
367
368 // always true: if (epcDl)
369 {
370 UdpClientHelper dlClientHelper(ueIpIfaces.GetAddress(u), dlPort);
371 clientApps.Add(dlClientHelper.Install(remoteHost));
372 PacketSinkHelper dlPacketSinkHelper(
373 "ns3::UdpSocketFactory",
375 ApplicationContainer sinkContainer = dlPacketSinkHelper.Install(ue);
376 bearerData.dlSink = sinkContainer.Get(0)->GetObject<PacketSink>();
377 serverApps.Add(sinkContainer);
378 }
379 // always true: if (epcUl)
380 {
381 UdpClientHelper ulClientHelper(remoteHostAddr, ulPort);
382 clientApps.Add(ulClientHelper.Install(ue));
383 PacketSinkHelper ulPacketSinkHelper(
384 "ns3::UdpSocketFactory",
386 ApplicationContainer sinkContainer = ulPacketSinkHelper.Install(remoteHost);
387 bearerData.ulSink = sinkContainer.Get(0)->GetObject<PacketSink>();
388 serverApps.Add(sinkContainer);
389 }
390
391 Ptr<EpcTft> tft = Create<EpcTft>();
392 // always true: if (epcDl)
393 {
395 dlpf.localPortStart = dlPort;
396 dlpf.localPortEnd = dlPort;
397 tft->Add(dlpf);
398 }
399 // always true: if (epcUl)
400 {
402 ulpf.remotePortStart = ulPort;
403 ulpf.remotePortEnd = ulPort;
404 tft->Add(ulpf);
405 }
406
407 // always true: if (epcDl || epcUl)
408 {
410 m_lteHelper->ActivateDedicatedEpsBearer(ueDevices.Get(u), bearer, tft);
411 }
412 double d = startTimeSeconds->GetValue();
413 Time startTime = Seconds(d);
414 serverApps.Start(startTime);
415 clientApps.Start(startTime);
416
417 ueData.bearerDataList.push_back(bearerData);
418
419 } // end for b
420
421 m_ueDataVector.push_back(ueData);
422 }
423 }
424 else // (epc == false)
425 {
426 // for radio bearer activation purposes, consider together home UEs and macro UEs
427 for (uint32_t u = 0; u < ueDevices.GetN(); ++u)
428 {
429 Ptr<NetDevice> ueDev = ueDevices.Get(u);
430 for (uint32_t b = 0; b < m_nDedicatedBearers; ++b)
431 {
433 EpsBearer bearer(q);
434 m_lteHelper->ActivateDataRadioBearer(ueDev, bearer);
435 }
436 }
437 }
438
439 m_lteHelper->AddX2Interface(enbNodes);
440
441 // check initial RRC connection
442 const Time maxRrcConnectionEstablishmentDuration = Seconds(0.080);
443 for (auto it = ueDevices.Begin(); it != ueDevices.End(); ++it)
444 {
445 Simulator::Schedule(maxRrcConnectionEstablishmentDuration,
447 this,
448 *it,
449 enbDevices.Get(0));
450 }
451
452 // schedule handover events and corresponding checks
453
454 Time stopTime = Seconds(0);
455 for (auto hoEventIt = m_handoverEventList.begin(); hoEventIt != m_handoverEventList.end();
456 ++hoEventIt)
457 {
458 // Teleport the UE between both eNBs just before the handover starts
459 Simulator::Schedule(hoEventIt->startTime - MilliSeconds(10),
461 this,
462 ueNodes.Get(hoEventIt->ueDeviceIndex));
463
464 Simulator::Schedule(hoEventIt->startTime,
466 this,
467 ueDevices.Get(hoEventIt->ueDeviceIndex),
468 enbDevices.Get(hoEventIt->sourceEnbDeviceIndex));
469
470 m_lteHelper->HandoverRequest(hoEventIt->startTime,
471 ueDevices.Get(hoEventIt->ueDeviceIndex),
472 enbDevices.Get(hoEventIt->sourceEnbDeviceIndex),
473 enbDevices.Get(hoEventIt->targetEnbDeviceIndex));
474
475 // Once the handover is finished, teleport the UE near the target eNB
476 Simulator::Schedule(hoEventIt->startTime + MilliSeconds(40),
478 this,
479 ueNodes.Get(hoEventIt->ueDeviceIndex),
480 enbNodes.Get(m_admitHo ? hoEventIt->targetEnbDeviceIndex
481 : hoEventIt->sourceEnbDeviceIndex));
482
483 Time hoEndTime = hoEventIt->startTime + m_maxHoDuration;
484 Simulator::Schedule(hoEndTime,
486 this,
487 ueDevices.Get(hoEventIt->ueDeviceIndex),
488 enbDevices.Get(m_admitHo ? hoEventIt->targetEnbDeviceIndex
489 : hoEventIt->sourceEnbDeviceIndex));
490 Simulator::Schedule(hoEndTime,
492 this,
493 hoEventIt->ueDeviceIndex);
494
495 Time checkStatsAfterHoTime = hoEndTime + m_statsDuration;
496 Simulator::Schedule(checkStatsAfterHoTime,
498 this,
499 hoEventIt->ueDeviceIndex);
500 if (stopTime <= checkStatsAfterHoTime)
501 {
502 stopTime = checkStatsAfterHoTime + MilliSeconds(1);
503 }
504 }
505
506 // m_lteHelper->EnableRlcTraces ();
507 // m_lteHelper->EnablePdcpTraces();
508
510
512
514
515 // Undo changes to default settings
517 // Restore the previous settings of RngSeed and RngRun
518 RngSeedManager::SetSeed(previousSeed);
519 RngSeedManager::SetRun(previousRun);
520}
521
522void
524{
525 Ptr<LteUeNetDevice> ueLteDevice = ueDevice->GetObject<LteUeNetDevice>();
526 Ptr<LteUeRrc> ueRrc = ueLteDevice->GetRrc();
527 NS_TEST_ASSERT_MSG_EQ(ueRrc->GetState(), LteUeRrc::CONNECTED_NORMALLY, "Wrong LteUeRrc state!");
528
529 Ptr<LteEnbNetDevice> enbLteDevice = enbDevice->GetObject<LteEnbNetDevice>();
530 Ptr<LteEnbRrc> enbRrc = enbLteDevice->GetRrc();
531 uint16_t rnti = ueRrc->GetRnti();
532 Ptr<UeManager> ueManager = enbRrc->GetUeManager(rnti);
533 NS_TEST_ASSERT_MSG_NE(ueManager, nullptr, "RNTI " << rnti << " not found in eNB");
534
535 UeManager::State ueManagerState = ueManager->GetState();
536 NS_TEST_ASSERT_MSG_EQ(ueManagerState, UeManager::CONNECTED_NORMALLY, "Wrong UeManager state!");
537 NS_ASSERT_MSG(ueManagerState == UeManager::CONNECTED_NORMALLY, "Wrong UeManager state!");
538
539 uint16_t ueCellId = ueRrc->GetCellId();
540 uint16_t enbCellId = enbLteDevice->GetCellId();
541 uint8_t ueDlBandwidth = ueRrc->GetDlBandwidth();
542 uint8_t enbDlBandwidth = enbLteDevice->GetDlBandwidth();
543 uint8_t ueUlBandwidth = ueRrc->GetUlBandwidth();
544 uint8_t enbUlBandwidth = enbLteDevice->GetUlBandwidth();
545 uint8_t ueDlEarfcn = ueRrc->GetDlEarfcn();
546 uint8_t enbDlEarfcn = enbLteDevice->GetDlEarfcn();
547 uint8_t ueUlEarfcn = ueRrc->GetUlEarfcn();
548 uint8_t enbUlEarfcn = enbLteDevice->GetUlEarfcn();
549 uint64_t ueImsi = ueLteDevice->GetImsi();
550 uint64_t enbImsi = ueManager->GetImsi();
551
552 NS_TEST_ASSERT_MSG_EQ(ueImsi, enbImsi, "inconsistent IMSI");
553 NS_TEST_ASSERT_MSG_EQ(ueCellId, enbCellId, "inconsistent CellId");
554 NS_TEST_ASSERT_MSG_EQ(ueDlBandwidth, enbDlBandwidth, "inconsistent DlBandwidth");
555 NS_TEST_ASSERT_MSG_EQ(ueUlBandwidth, enbUlBandwidth, "inconsistent UlBandwidth");
556 NS_TEST_ASSERT_MSG_EQ(ueDlEarfcn, enbDlEarfcn, "inconsistent DlEarfcn");
557 NS_TEST_ASSERT_MSG_EQ(ueUlEarfcn, enbUlEarfcn, "inconsistent UlEarfcn");
558
559 ObjectMapValue enbDataRadioBearerMapValue;
560 ueManager->GetAttribute("DataRadioBearerMap", enbDataRadioBearerMapValue);
561 NS_TEST_ASSERT_MSG_EQ(enbDataRadioBearerMapValue.GetN(),
563 "wrong num bearers at eNB");
564
565 ObjectMapValue ueDataRadioBearerMapValue;
566 ueRrc->GetAttribute("DataRadioBearerMap", ueDataRadioBearerMapValue);
567 NS_TEST_ASSERT_MSG_EQ(ueDataRadioBearerMapValue.GetN(),
569 "wrong num bearers at UE");
570
571 auto enbBearerIt = enbDataRadioBearerMapValue.Begin();
572 auto ueBearerIt = ueDataRadioBearerMapValue.Begin();
573 while (enbBearerIt != enbDataRadioBearerMapValue.End() &&
574 ueBearerIt != ueDataRadioBearerMapValue.End())
575 {
576 Ptr<LteDataRadioBearerInfo> enbDrbInfo =
577 enbBearerIt->second->GetObject<LteDataRadioBearerInfo>();
579 ueBearerIt->second->GetObject<LteDataRadioBearerInfo>();
580 // NS_TEST_ASSERT_MSG_EQ (enbDrbInfo->m_epsBearer, ueDrbInfo->m_epsBearer, "epsBearer
581 // differs");
582 NS_TEST_ASSERT_MSG_EQ((uint32_t)enbDrbInfo->m_epsBearerIdentity,
583 (uint32_t)ueDrbInfo->m_epsBearerIdentity,
584 "epsBearerIdentity differs");
585 NS_TEST_ASSERT_MSG_EQ((uint32_t)enbDrbInfo->m_drbIdentity,
586 (uint32_t)ueDrbInfo->m_drbIdentity,
587 "drbIdentity differs");
588 // NS_TEST_ASSERT_MSG_EQ (enbDrbInfo->m_rlcConfig, ueDrbInfo->m_rlcConfig, "rlcConfig
589 // differs");
590 NS_TEST_ASSERT_MSG_EQ((uint32_t)enbDrbInfo->m_logicalChannelIdentity,
591 (uint32_t)ueDrbInfo->m_logicalChannelIdentity,
592 "logicalChannelIdentity differs");
593 // NS_TEST_ASSERT_MSG_EQ (enbDrbInfo->m_logicalChannelConfig,
594 // ueDrbInfo->m_logicalChannelConfig, "logicalChannelConfig differs");
595
596 ++enbBearerIt;
597 ++ueBearerIt;
598 }
599 NS_ASSERT_MSG(enbBearerIt == enbDataRadioBearerMapValue.End(), "too many bearers at eNB");
600 NS_ASSERT_MSG(ueBearerIt == ueDataRadioBearerMapValue.End(), "too many bearers at UE");
601}
602
603void
605{
606 Ptr<MobilityModel> ueMobility = ueNode->GetObject<MobilityModel>();
607 ueMobility->SetPosition(Vector(0.0, 0.0, 0.0));
608}
609
610void
612{
613 Ptr<MobilityModel> enbMobility = enbNode->GetObject<MobilityModel>();
614 Vector pos = enbMobility->GetPosition();
615
616 Ptr<MobilityModel> ueMobility = ueNode->GetObject<MobilityModel>();
617 ueMobility->SetPosition(pos + Vector(0.0, 100.0, 0.0));
618}
619
620void
622{
623 for (auto it = m_ueDataVector.at(ueIndex).bearerDataList.begin();
624 it != m_ueDataVector.at(ueIndex).bearerDataList.end();
625 ++it)
626 {
627 it->dlOldTotalRx = it->dlSink->GetTotalRx();
628 it->ulOldTotalRx = it->ulSink->GetTotalRx();
629 }
630}
631
632void
634{
635 uint32_t b = 1;
636 for (auto it = m_ueDataVector.at(ueIndex).bearerDataList.begin();
637 it != m_ueDataVector.at(ueIndex).bearerDataList.end();
638 ++it)
639 {
640 uint32_t dlRx = it->dlSink->GetTotalRx() - it->dlOldTotalRx;
641 uint32_t ulRx = it->ulSink->GetTotalRx() - it->ulOldTotalRx;
642 uint32_t expectedBytes =
644
646 expectedBytes,
647 "too few RX bytes in DL, ue=" << ueIndex << ", b=" << b);
649 expectedBytes,
650 "too few RX bytes in UL, ue=" << ueIndex << ", b=" << b);
651 ++b;
652 }
653}
654
655/**
656 * \ingroup lte-test
657 *
658 * \brief LTE X2 Handover Test Suite.
659 *
660 * In this test suite, we use NoOpHandoverAlgorithm, i.e. "handover algorithm which does nothing"
661 * is used and handover is triggered manually. The automatic handover algorithms (A2A4, A3Rsrp)
662 * are not tested.
663 *
664 * The tests are designed to check that eNB-buffered data received while a handover is in progress
665 * is not lost but successfully forwarded. But the test suite doesn't test for possible loss of
666 * RLC-buffered data because "lossless" handover is not implemented, and there are other application
667 * send patterns (outside of the range tested here) that may incur losses.
668 */
670{
671 public:
673};
674
676 : TestSuite("lte-x2-handover", Type::SYSTEM)
677{
678 // in the following:
679 // fwd means handover from enb 0 to enb 1
680 // bwd means handover from enb 1 to enb 0
681
682 HandoverEvent ue1fwd;
683 ue1fwd.startTime = MilliSeconds(100);
684 ue1fwd.ueDeviceIndex = 0;
685 ue1fwd.sourceEnbDeviceIndex = 0;
686 ue1fwd.targetEnbDeviceIndex = 1;
687
688 HandoverEvent ue1bwd;
689 ue1bwd.startTime = MilliSeconds(400);
690 ue1bwd.ueDeviceIndex = 0;
691 ue1bwd.sourceEnbDeviceIndex = 1;
692 ue1bwd.targetEnbDeviceIndex = 0;
693
694 HandoverEvent ue1fwdagain;
695 ue1fwdagain.startTime = MilliSeconds(700);
696 ue1fwdagain.ueDeviceIndex = 0;
697 ue1fwdagain.sourceEnbDeviceIndex = 0;
698 ue1fwdagain.targetEnbDeviceIndex = 1;
699
700 HandoverEvent ue2fwd;
701 ue2fwd.startTime = MilliSeconds(110);
702 ue2fwd.ueDeviceIndex = 1;
703 ue2fwd.sourceEnbDeviceIndex = 0;
704 ue2fwd.targetEnbDeviceIndex = 1;
705
706 HandoverEvent ue2bwd;
707 ue2bwd.startTime = MilliSeconds(350);
708 ue2bwd.ueDeviceIndex = 1;
709 ue2bwd.sourceEnbDeviceIndex = 1;
710 ue2bwd.targetEnbDeviceIndex = 0;
711
712 std::string handoverEventList0name("none");
713 std::list<HandoverEvent> handoverEventList0;
714
715 std::string handoverEventList1name("1 fwd");
716 const std::list<HandoverEvent> handoverEventList1{
717 ue1fwd,
718 };
719
720 std::string handoverEventList2name("1 fwd & bwd");
721 const std::list<HandoverEvent> handoverEventList2{
722 ue1fwd,
723 ue1bwd,
724 };
725
726 std::string handoverEventList3name("1 fwd & bwd & fwd");
727 const std::list<HandoverEvent> handoverEventList3{
728 ue1fwd,
729 ue1bwd,
730 ue1fwdagain,
731 };
732
733 std::string handoverEventList4name("1+2 fwd");
734 const std::list<HandoverEvent> handoverEventList4{
735 ue1fwd,
736 ue2fwd,
737 };
738
739 std::string handoverEventList5name("1+2 fwd & bwd");
740 const std::list<HandoverEvent> handoverEventList5{
741 ue1fwd,
742 ue1bwd,
743 ue2fwd,
744 ue2bwd,
745 };
746
747 // std::string handoverEventList6name("2 fwd");
748 // const std::list<HandoverEvent> handoverEventList6{
749 // ue2fwd,
750 // };
751
752 // std::string handoverEventList7name("2 fwd & bwd");
753 // const std::list<HandoverEvent> handoverEventList7{
754 // ue2fwd,
755 // ue2bwd,
756 // };
757
758 std::vector<std::string> schedulers{
759 "ns3::RrFfMacScheduler",
760 "ns3::PfFfMacScheduler",
761 };
762
763 for (auto schedIt = schedulers.begin(); schedIt != schedulers.end(); ++schedIt)
764 {
765 for (auto useIdealRrc : {true, false})
766 {
767 // nUes, nDBearers, helist, name, sched, admitHo, idealRrc
769 0,
770 handoverEventList0,
771 handoverEventList0name,
772 *schedIt,
773 true,
774 useIdealRrc),
775 TestCase::Duration::EXTENSIVE);
777 0,
778 handoverEventList0,
779 handoverEventList0name,
780 *schedIt,
781 true,
782 useIdealRrc),
783 TestCase::Duration::EXTENSIVE);
785 5,
786 handoverEventList0,
787 handoverEventList0name,
788 *schedIt,
789 true,
790 useIdealRrc),
791 TestCase::Duration::EXTENSIVE);
793 5,
794 handoverEventList0,
795 handoverEventList0name,
796 *schedIt,
797 true,
798 useIdealRrc),
799 TestCase::Duration::EXTENSIVE);
801 0,
802 handoverEventList1,
803 handoverEventList1name,
804 *schedIt,
805 true,
806 useIdealRrc),
807 TestCase::Duration::EXTENSIVE);
809 1,
810 handoverEventList1,
811 handoverEventList1name,
812 *schedIt,
813 true,
814 useIdealRrc),
815 TestCase::Duration::EXTENSIVE);
817 2,
818 handoverEventList1,
819 handoverEventList1name,
820 *schedIt,
821 true,
822 useIdealRrc),
823 TestCase::Duration::EXTENSIVE);
825 0,
826 handoverEventList1,
827 handoverEventList1name,
828 *schedIt,
829 false,
830 useIdealRrc),
831 TestCase::Duration::EXTENSIVE);
833 1,
834 handoverEventList1,
835 handoverEventList1name,
836 *schedIt,
837 false,
838 useIdealRrc),
839 TestCase::Duration::EXTENSIVE);
841 2,
842 handoverEventList1,
843 handoverEventList1name,
844 *schedIt,
845 false,
846 useIdealRrc),
847 TestCase::Duration::EXTENSIVE);
849 0,
850 handoverEventList1,
851 handoverEventList1name,
852 *schedIt,
853 true,
854 useIdealRrc),
855 TestCase::Duration::EXTENSIVE);
857 1,
858 handoverEventList1,
859 handoverEventList1name,
860 *schedIt,
861 true,
862 useIdealRrc),
863 TestCase::Duration::EXTENSIVE);
865 2,
866 handoverEventList1,
867 handoverEventList1name,
868 *schedIt,
869 true,
870 useIdealRrc),
871 TestCase::Duration::EXTENSIVE);
873 0,
874 handoverEventList1,
875 handoverEventList1name,
876 *schedIt,
877 false,
878 useIdealRrc),
879 TestCase::Duration::EXTENSIVE);
881 1,
882 handoverEventList1,
883 handoverEventList1name,
884 *schedIt,
885 false,
886 useIdealRrc),
887 TestCase::Duration::EXTENSIVE);
889 2,
890 handoverEventList1,
891 handoverEventList1name,
892 *schedIt,
893 false,
894 useIdealRrc),
895 TestCase::Duration::EXTENSIVE);
897 0,
898 handoverEventList2,
899 handoverEventList2name,
900 *schedIt,
901 true,
902 useIdealRrc),
903 TestCase::Duration::EXTENSIVE);
905 1,
906 handoverEventList2,
907 handoverEventList2name,
908 *schedIt,
909 true,
910 useIdealRrc),
911 TestCase::Duration::EXTENSIVE);
913 2,
914 handoverEventList2,
915 handoverEventList2name,
916 *schedIt,
917 true,
918 useIdealRrc),
919 TestCase::Duration::EXTENSIVE);
921 0,
922 handoverEventList3,
923 handoverEventList3name,
924 *schedIt,
925 true,
926 useIdealRrc),
927 TestCase::Duration::EXTENSIVE);
929 1,
930 handoverEventList3,
931 handoverEventList3name,
932 *schedIt,
933 true,
934 useIdealRrc),
935 TestCase::Duration::EXTENSIVE);
937 2,
938 handoverEventList3,
939 handoverEventList3name,
940 *schedIt,
941 true,
942 useIdealRrc),
943 TestCase::Duration::EXTENSIVE);
945 0,
946 handoverEventList3,
947 handoverEventList3name,
948 *schedIt,
949 true,
950 useIdealRrc),
951 TestCase::Duration::EXTENSIVE);
953 1,
954 handoverEventList3,
955 handoverEventList3name,
956 *schedIt,
957 true,
958 useIdealRrc),
959 TestCase::Duration::EXTENSIVE);
961 2,
962 handoverEventList3,
963 handoverEventList3name,
964 *schedIt,
965 true,
966 useIdealRrc),
967 TestCase::Duration::QUICK);
969 0,
970 handoverEventList4,
971 handoverEventList4name,
972 *schedIt,
973 true,
974 useIdealRrc),
975 TestCase::Duration::EXTENSIVE);
977 1,
978 handoverEventList4,
979 handoverEventList4name,
980 *schedIt,
981 true,
982 useIdealRrc),
983 TestCase::Duration::EXTENSIVE);
985 2,
986 handoverEventList4,
987 handoverEventList4name,
988 *schedIt,
989 true,
990 useIdealRrc),
991 TestCase::Duration::EXTENSIVE);
993 0,
994 handoverEventList5,
995 handoverEventList5name,
996 *schedIt,
997 true,
998 useIdealRrc),
999 TestCase::Duration::EXTENSIVE);
1001 1,
1002 handoverEventList5,
1003 handoverEventList5name,
1004 *schedIt,
1005 true,
1006 useIdealRrc),
1007 TestCase::Duration::EXTENSIVE);
1009 2,
1010 handoverEventList5,
1011 handoverEventList5name,
1012 *schedIt,
1013 true,
1014 useIdealRrc),
1015 TestCase::Duration::EXTENSIVE);
1017 0,
1018 handoverEventList3,
1019 handoverEventList3name,
1020 *schedIt,
1021 true,
1022 useIdealRrc),
1023 TestCase::Duration::EXTENSIVE);
1025 1,
1026 handoverEventList3,
1027 handoverEventList3name,
1028 *schedIt,
1029 true,
1030 useIdealRrc),
1031 TestCase::Duration::EXTENSIVE);
1033 2,
1034 handoverEventList3,
1035 handoverEventList3name,
1036 *schedIt,
1037 true,
1038 useIdealRrc),
1039 TestCase::Duration::EXTENSIVE);
1041 0,
1042 handoverEventList4,
1043 handoverEventList4name,
1044 *schedIt,
1045 true,
1046 useIdealRrc),
1047 TestCase::Duration::EXTENSIVE);
1049 1,
1050 handoverEventList4,
1051 handoverEventList4name,
1052 *schedIt,
1053 true,
1054 useIdealRrc),
1055 TestCase::Duration::EXTENSIVE);
1057 2,
1058 handoverEventList4,
1059 handoverEventList4name,
1060 *schedIt,
1061 true,
1062 useIdealRrc),
1063 TestCase::Duration::EXTENSIVE);
1065 0,
1066 handoverEventList5,
1067 handoverEventList5name,
1068 *schedIt,
1069 true,
1070 useIdealRrc),
1071 TestCase::Duration::EXTENSIVE);
1073 1,
1074 handoverEventList5,
1075 handoverEventList5name,
1076 *schedIt,
1077 true,
1078 useIdealRrc),
1079 TestCase::Duration::EXTENSIVE);
1081 2,
1082 handoverEventList5,
1083 handoverEventList5name,
1084 *schedIt,
1085 true,
1086 useIdealRrc),
1087 TestCase::Duration::QUICK);
1088 }
1089 }
1090}
1091
1092/**
1093 * \ingroup lte-test
1094 * Static variable for test initialization
1095 */
static std::string BuildNameString(uint32_t nUes, uint32_t nDedicatedBearers, std::string handoverEventListName, std::string schedulerType, bool admitHo, bool useIdealRrc)
Build name string.
void DoRun() override
Implementation to actually run this TestCase.
Ptr< PointToPointEpcHelper > m_epcHelper
EPC helper.
uint32_t m_nUes
number of UEs in the test
std::string m_handoverEventListName
handover event list name
std::string m_schedulerType
scheduler type
const uint32_t m_udpClientPktSize
UDP client packet size.
bool m_useIdealRrc
whether to use the ideal RRC
const Time m_statsDuration
stats duration
std::vector< UeData > m_ueDataVector
UE data vector.
void CheckConnected(Ptr< NetDevice > ueDevice, Ptr< NetDevice > enbDevice)
Check connected function.
LteX2HandoverTestCase(uint32_t nUes, uint32_t nDedicatedBearers, std::list< HandoverEvent > handoverEventList, std::string handoverEventListName, std::string schedulerType, bool admitHo, bool useIdealRrc)
void TeleportUeNearTargetEnb(Ptr< Node > ueNode, Ptr< Node > enbNode)
Teleport UE near the target eNB of the handover.
bool m_admitHo
whether to admit the handover request
bool m_epc
whether to use EPC
void SaveStatsAfterHandover(uint32_t ueIndex)
Save stats after handover function.
const Time m_maxHoDuration
maximum HO duration
std::list< HandoverEvent > m_handoverEventList
handover event list
void CheckStatsAWhileAfterHandover(uint32_t ueIndex)
Check stats a while after handover function.
uint32_t m_nDedicatedBearers
number of UEs in the test
const Time m_udpClientInterval
UDP client interval.
void TeleportUeToMiddle(Ptr< Node > ueNode)
Teleport UE between both eNBs of the test.
Ptr< LteHelper > m_lteHelper
LTE helper.
LTE X2 Handover Test Suite.
holds a vector of ns3::Application pointers.
Ptr< Application > Get(uint32_t i) const
Get the Ptr<Application> stored in this container at a given index.
ApplicationContainer Install(NodeContainer c)
Install an application on each node of the input container configured with all the attributes set wit...
AttributeValue implementation for Boolean.
Definition: boolean.h:37
Class for representing data rates.
Definition: data-rate.h:89
AttributeValue implementation for DataRate.
Definition: data-rate.h:296
This class can be used to hold variables of floating point type such as 'double' or 'float'.
Definition: double.h:42
This class contains the specification of EPS Bearers.
Definition: eps-bearer.h:91
Qci
QoS Class Indicator.
Definition: eps-bearer.h:106
@ NGBR_VIDEO_TCP_DEFAULT
Non-GBR TCP-based Video (Buffered Streaming, e.g., www, e-mail...)
Definition: eps-bearer.h:126
an Inet address class
aggregate IP/TCP/UDP functionality to existing Nodes.
A helper class to make life easier while doing simple IPv4 address assignment in scripts.
void SetBase(Ipv4Address network, Ipv4Mask mask, Ipv4Address base="0.0.0.1")
Set the base network number, network mask and base address.
Ipv4InterfaceContainer Assign(const NetDeviceContainer &c)
Assign IP addresses to the net devices specified in the container based on the current network prefix...
Ipv4 addresses are stored in host order in this class.
Definition: ipv4-address.h:42
static Ipv4Address GetAny()
Access to the IPv4 forwarding table, interfaces, and configuration.
Definition: ipv4.h:80
holds a vector of std::pair of Ptr<Ipv4> and interface index.
Ipv4Address GetAddress(uint32_t i, uint32_t j=0) const
a class to represent an Ipv4 address mask
Definition: ipv4-address.h:257
Helper class that adds ns3::Ipv4StaticRouting objects.
Ptr< Ipv4StaticRouting > GetStaticRouting(Ptr< Ipv4 > ipv4) const
Try and find the static routing protocol as either the main routing protocol or in the list of routin...
store information on active data radio bearer instance
The eNodeB device implementation.
void SetEpcHelper(Ptr< EpcHelper > h)
Set the EpcHelper to be used to setup the EPC network in conjunction with the setup of the LTE radio ...
Definition: lte-helper.cc:285
void HandoverRequest(Time hoTime, Ptr< NetDevice > ueDev, Ptr< NetDevice > sourceEnbDev, Ptr< NetDevice > targetEnbDev)
Manually trigger an X2-based handover.
Definition: lte-helper.cc:1338
NetDeviceContainer InstallEnbDevice(NodeContainer c)
Create a set of eNodeB devices.
Definition: lte-helper.cc:485
void SetHandoverAlgorithmType(std::string type)
Set the type of handover algorithm to be used by eNodeB devices.
Definition: lte-helper.cc:340
void SetSchedulerType(std::string type)
Set the type of scheduler to be used by eNodeB devices.
Definition: lte-helper.cc:292
void Attach(NetDeviceContainer ueDevices)
Enables automatic attachment of a set of UE devices to a suitable cell using Idle mode initial cell s...
Definition: lte-helper.cc:1039
void ActivateDataRadioBearer(NetDeviceContainer ueDevices, EpsBearer bearer)
Activate a Data Radio Bearer on a given UE devices (for LTE-only simulation).
Definition: lte-helper.cc:1436
NetDeviceContainer InstallUeDevice(NodeContainer c)
Create a set of UE devices.
Definition: lte-helper.cc:500
void AddX2Interface(NodeContainer enbNodes)
Create an X2 interface between all the eNBs in a given set.
Definition: lte-helper.cc:1313
int64_t AssignStreams(NetDeviceContainer c, int64_t stream)
Assign a fixed random variable stream number to the random variables used.
Definition: lte-helper.cc:1567
uint8_t ActivateDedicatedEpsBearer(NetDeviceContainer ueDevices, EpsBearer bearer, Ptr< EpcTft > tft)
Activate a dedicated EPS bearer on a given set of UE devices.
Definition: lte-helper.cc:1154
The LteUeNetDevice class implements the UE net device.
Helper class used to assign positions and mobility models to nodes.
Keep track of the current position and velocity of an object.
holds a vector of ns3::NetDevice pointers
uint32_t GetN() const
Get the number of Ptr<NetDevice> stored in this container.
Iterator Begin() const
Get an iterator which refers to the first NetDevice in the container.
Iterator End() const
Get an iterator which indicates past-the-last NetDevice in the container.
Ptr< NetDevice > Get(uint32_t i) const
Get the Ptr<NetDevice> stored in this container at a given index.
Ptr< Node > GetPgwNode() const override
Get the PGW node.
Ipv4Address GetUeDefaultGatewayAddress() override
Ipv4InterfaceContainer AssignUeIpv4Address(NetDeviceContainer ueDevices) override
Assign IPv4 addresses to UE devices.
keep track of a set of node pointers.
uint32_t GetN() const
Get the number of Ptr<Node> stored in this container.
void Create(uint32_t n)
Create n nodes and append pointers to them to the end of this NodeContainer.
Ptr< Node > Get(uint32_t i) const
Get the Ptr<Node> stored in this container at a given index.
void SetAttribute(std::string name, const AttributeValue &value)
Set a single attribute, raising fatal errors if unsuccessful.
Definition: object-base.cc:211
Ptr< T > GetObject() const
Get a pointer to the requested aggregated Object.
Definition: object.h:522
Container for a set of ns3::Object pointers.
std::size_t GetN() const
Get the number of Objects.
Iterator End() const
Get an iterator to the past-the-end Object.
Iterator Begin() const
Get an iterator to the first Object.
A helper to make it easier to instantiate an ns3::PacketSinkApplication on a set of nodes.
Receive and consume traffic generated to an IP address and port.
Definition: packet-sink.h:75
Build a set of PointToPointNetDevice objects.
void SetDeviceAttribute(std::string name, const AttributeValue &value)
Set an attribute value to be propagated to each NetDevice created by the helper.
void SetChannelAttribute(std::string name, const AttributeValue &value)
Set an attribute value to be propagated to each Channel created by the helper.
NetDeviceContainer Install(NodeContainer c)
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:77
static void SetRun(uint64_t run)
Set the run number of simulation.
static void SetSeed(uint32_t seed)
Set the seed.
static uint64_t GetRun()
Get the current run number.
static uint32_t GetSeed()
Get the current seed value which will be used by all subsequently instantiated RandomVariableStream o...
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition: simulator.h:571
static void Destroy()
Execute the events scheduled with ScheduleDestroy().
Definition: simulator.cc:142
static void Run()
Run the simulation.
Definition: simulator.cc:178
static void Stop()
Tell the Simulator the calling event should be the last one executed.
Definition: simulator.cc:186
Hold variables of type string.
Definition: string.h:56
encapsulates test code
Definition: test.h:1061
void AddTestCase(TestCase *testCase, Duration duration=Duration::QUICK)
Add an individual child TestCase to this test suite.
Definition: test.cc:301
A suite of tests to run.
Definition: test.h:1268
Type
Type of test.
Definition: test.h:1275
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:105
AttributeValue implementation for Time.
Definition: nstime.h:1413
Create a client application which sends UDP packets carrying a 32bit sequence number and a 64 bit tim...
State
The state of the UeManager at the eNB RRC.
Definition: lte-enb-rrc.h:78
Hold an unsigned integer type.
Definition: uinteger.h:45
Time stopTime
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition: assert.h:86
void Reset()
Reset the initial value of every attribute as well as the value of every global to what they were bef...
Definition: config.cc:859
void SetDefault(std::string name, const AttributeValue &value)
Definition: config.cc:894
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
static LteX2HandoverTestSuite g_lteX2HandoverTestSuiteInstance
Static variable for test initialization.
#define NS_TEST_ASSERT_MSG_EQ(actual, limit, msg)
Test that an actual and expected (limit) value are equal and report and abort if not.
Definition: test.h:145
#define NS_TEST_ASSERT_MSG_NE(actual, limit, msg)
Test that an actual and expected (limit) value are not equal and report and abort if not.
Definition: test.h:565
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1326
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1338
Every class exported by the ns3 library is enclosed in the ns3 namespace.
HandoverEvent structure.
uint32_t ueDeviceIndex
UE device index.
Time startTime
start time
uint32_t targetEnbDeviceIndex
target ENB device index
uint32_t sourceEnbDeviceIndex
source ENB device index
uint32_t dlOldTotalRx
DL old total receive.
uint32_t ulOldTotalRx
UL old total receive.
std::list< BearerData > bearerDataList
bearer ID list
Implement the data structure representing a TrafficFlowTemplate Packet Filter.
Definition: epc-tft.h:71
uint16_t localPortEnd
end of the port number range of the UE
Definition: epc-tft.h:132
uint16_t remotePortEnd
end of the port number range of the remote host
Definition: epc-tft.h:130
uint16_t remotePortStart
start of the port number range of the remote host
Definition: epc-tft.h:129
uint16_t localPortStart
start of the port number range of the UE
Definition: epc-tft.h:131