1 /* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2013 Budiarto Herman
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation;
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  *
18  * Author: Budiarto Herman <budiarto.herman@magister.fi>
19  *
20  */
21 
22 #include "lte-test-cell-selection.h"
23 
24 #include <ns3/simulator.h>
25 #include <ns3/log.h>
26 #include <ns3/boolean.h>
27 #include <ns3/double.h>
28 #include <ns3/integer.h>
29 
30 #include <ns3/mobility-helper.h>
31 #include <ns3/lte-helper.h>
32 #include <ns3/point-to-point-epc-helper.h>
33 #include <ns3/internet-stack-helper.h>
34 #include <ns3/point-to-point-helper.h>
35 #include <ns3/ipv4-address-helper.h>
36 #include <ns3/ipv4-static-routing-helper.h>
37 
38 #include <ns3/node-container.h>
39 #include <ns3/net-device-container.h>
40 #include <ns3/ipv4-interface-container.h>
41 
42 #include <ns3/lte-ue-net-device.h>
43 #include <ns3/lte-ue-rrc.h>
44 #include <ns3/lte-enb-net-device.h>
45 
46 using namespace ns3;
47 
48 NS_LOG_COMPONENT_DEFINE ("LteCellSelectionTest");
49 
50 /*
51  * Test Suite
52  */
53 
54 
LteCellSelectionTestSuite()55 LteCellSelectionTestSuite::LteCellSelectionTestSuite ()
56   : TestSuite ("lte-cell-selection", SYSTEM)
57 {
58   std::vector<LteCellSelectionTestCase::UeSetup_t> w;
59 
60   // REAL RRC PROTOCOL
61 
62   w.clear ();
63   //                                                x     y    csgMember
64   //                                                checkPoint     cell1, cell2
65   w.push_back (LteCellSelectionTestCase::UeSetup_t (0.0, 0.55, false,
66                                                     MilliSeconds (283), 1, 0));
67   w.push_back (LteCellSelectionTestCase::UeSetup_t (0.0, 0.45, false,
68                                                     MilliSeconds (283), 1, 0));
69   w.push_back (LteCellSelectionTestCase::UeSetup_t (0.5, 0.45, false,
70                                                     MilliSeconds (363), 1, 3));
71   w.push_back (LteCellSelectionTestCase::UeSetup_t (0.5, 0.0,  true,
72                                                     MilliSeconds (283), 2, 4));
73   w.push_back (LteCellSelectionTestCase::UeSetup_t (1.0, 0.55, true,
74                                                     MilliSeconds (283), 3, 0));
75   w.push_back (LteCellSelectionTestCase::UeSetup_t (1.0, 0.45, true,
76                                                     MilliSeconds (283), 4, 0));
77 
78   AddTestCase (new LteCellSelectionTestCase ("EPC, real RRC, RngNum=1",
79                                              true, false, 60.0, w, 1),
80                //                                        isd       rngrun
81                TestCase::QUICK);
82 
83   // IDEAL RRC PROTOCOL
84 
85   w.clear ();
86   //                                                x     y    csgMember
87   //                                                checkPoint     cell1, cell2
88   w.push_back (LteCellSelectionTestCase::UeSetup_t (0.0, 0.55, false,
89                                                     MilliSeconds (266), 1, 0));
90   w.push_back (LteCellSelectionTestCase::UeSetup_t (0.0, 0.45, false,
91                                                     MilliSeconds (266), 1, 0));
92   w.push_back (LteCellSelectionTestCase::UeSetup_t (0.5, 0.45, false,
93                                                     MilliSeconds (346), 1, 3));
94   w.push_back (LteCellSelectionTestCase::UeSetup_t (0.5, 0.0,  true,
95                                                     MilliSeconds (266), 2, 4));
96   w.push_back (LteCellSelectionTestCase::UeSetup_t (1.0, 0.55, true,
97                                                     MilliSeconds (266), 3, 0));
98   w.push_back (LteCellSelectionTestCase::UeSetup_t (1.0, 0.45, true,
99                                                     MilliSeconds (266), 4, 0));
100 
101   AddTestCase (new LteCellSelectionTestCase ("EPC, ideal RRC, RngNum=1",
102                                              true, true, 60.0, w, 1),
103                //                                        isd      rngrun
104                TestCase::QUICK);
105 
106 } // end of LteCellSelectionTestSuite::LteCellSelectionTestSuite ()
107 
108 
109 static LteCellSelectionTestSuite g_lteCellSelectionTestSuite;
110 
111 
112 
113 /*
114  * Test Case
115  */
116 
117 
UeSetup_t(double relPosX,double relPosY,bool isCsgMember,Time checkPoint,uint16_t expectedCellId1,uint16_t expectedCellId2)118 LteCellSelectionTestCase::UeSetup_t::UeSetup_t (
119   double relPosX, double relPosY, bool isCsgMember, Time checkPoint,
120   uint16_t expectedCellId1, uint16_t expectedCellId2)
121   : position (Vector (relPosX, relPosY, 0.0)),
122     isCsgMember (isCsgMember),
123     checkPoint (checkPoint),
124     expectedCellId1 (expectedCellId1),
125     expectedCellId2 (expectedCellId2)
126 {
127 }
128 
129 
LteCellSelectionTestCase(std::string name,bool isEpcMode,bool isIdealRrc,double interSiteDistance,std::vector<UeSetup_t> ueSetupList,uint64_t rngRun)130 LteCellSelectionTestCase::LteCellSelectionTestCase (
131   std::string name, bool isEpcMode, bool isIdealRrc,
132   double interSiteDistance,
133   std::vector<UeSetup_t> ueSetupList, uint64_t rngRun)
134   : TestCase (name),
135     m_isEpcMode (isEpcMode),
136     m_isIdealRrc (isIdealRrc),
137     m_interSiteDistance (interSiteDistance),
138     m_ueSetupList (ueSetupList),
139     m_rngRun (rngRun)
140 {
141   NS_LOG_FUNCTION (this << GetName ());
142   m_lastState.resize (m_ueSetupList.size (), LteUeRrc::NUM_STATES);
143 }
144 
145 
~LteCellSelectionTestCase()146 LteCellSelectionTestCase::~LteCellSelectionTestCase ()
147 {
148   NS_LOG_FUNCTION (this << GetName ());
149 }
150 
151 
152 void
DoRun()153 LteCellSelectionTestCase::DoRun ()
154 {
155   NS_LOG_FUNCTION (this << GetName ());
156 
157   Config::SetGlobal ("RngRun", UintegerValue (m_rngRun));
158 
159   Ptr<LteHelper> lteHelper = CreateObject<LteHelper> ();
160   lteHelper->SetAttribute ("PathlossModel",
161                            StringValue ("ns3::FriisSpectrumPropagationLossModel"));
162   lteHelper->SetAttribute ("UseIdealRrc", BooleanValue (m_isIdealRrc));
163 
164   Ptr<PointToPointEpcHelper> epcHelper;
165 
166   if (m_isEpcMode)
167     {
168       epcHelper = CreateObject<PointToPointEpcHelper> ();
169       lteHelper->SetEpcHelper (epcHelper);
170     }
171 
172   /*
173    * The topology is the following (the number on the node indicate the cell ID)
174    *
175    *      [1]        [3]
176    *    non-CSG -- non-CSG
177    *       |          |
178    *       |          | 60 m
179    *       |          |
180    *      [2]        [4]
181    *      CSG ------ CSG
182    *           60 m
183    */
184 
185   // Create Nodes
186   NodeContainer enbNodes;
187   enbNodes.Create (4);
188   NodeContainer ueNodes;
189   uint16_t nUe = static_cast<uint16_t> (m_ueSetupList.size ());
190   ueNodes.Create (nUe);
191 
192   // Assign nodes to position
193   Ptr<ListPositionAllocator> positionAlloc = CreateObject<ListPositionAllocator> ();
194   // eNodeB
195   positionAlloc->Add (Vector (                0.0, m_interSiteDistance, 0.0));
196   positionAlloc->Add (Vector (                0.0,                 0.0, 0.0));
197   positionAlloc->Add (Vector (m_interSiteDistance, m_interSiteDistance, 0.0));
198   positionAlloc->Add (Vector (m_interSiteDistance,                 0.0, 0.0));
199   // UE
200   std::vector<UeSetup_t>::const_iterator itSetup;
201   for (itSetup = m_ueSetupList.begin ();
202        itSetup != m_ueSetupList.end (); itSetup++)
203     {
204       Vector uePos (m_interSiteDistance * itSetup->position.x,
205                     m_interSiteDistance * itSetup->position.y,
206                     m_interSiteDistance * itSetup->position.z);
207       NS_LOG_INFO ("UE position " << uePos);
208       positionAlloc->Add (uePos);
209     }
210 
211   MobilityHelper mobility;
212   mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel");
213   mobility.SetPositionAllocator (positionAlloc);
214   mobility.Install (enbNodes);
215   mobility.Install (ueNodes);
216 
217   // Create Devices and install them in the Nodes (eNB and UE)
218   int64_t stream = 1;
219   NetDeviceContainer enbDevs;
220 
221   // cell ID 1 is a non-CSG cell
222   lteHelper->SetEnbDeviceAttribute ("CsgId", UintegerValue (0));
223   lteHelper->SetEnbDeviceAttribute ("CsgIndication", BooleanValue (false));
224   enbDevs.Add (lteHelper->InstallEnbDevice (enbNodes.Get (0)));
225 
226   // cell ID 2 is a CSG cell
227   lteHelper->SetEnbDeviceAttribute ("CsgId", UintegerValue (1));
228   lteHelper->SetEnbDeviceAttribute ("CsgIndication", BooleanValue (true));
229   enbDevs.Add (lteHelper->InstallEnbDevice (enbNodes.Get (1)));
230 
231   // cell ID 3 is a non-CSG cell
232   lteHelper->SetEnbDeviceAttribute ("CsgId", UintegerValue (0));
233   lteHelper->SetEnbDeviceAttribute ("CsgIndication", BooleanValue (false));
234   enbDevs.Add (lteHelper->InstallEnbDevice (enbNodes.Get (2)));
235 
236   // cell ID 4 is a CSG cell
237   lteHelper->SetEnbDeviceAttribute ("CsgId", UintegerValue (1));
238   lteHelper->SetEnbDeviceAttribute ("CsgIndication", BooleanValue (true));
239   enbDevs.Add (lteHelper->InstallEnbDevice (enbNodes.Get (3)));
240 
241   NetDeviceContainer ueDevs;
242   Time lastCheckPoint = MilliSeconds (0);
243   NS_ASSERT (m_ueSetupList.size () == ueNodes.GetN ());
244   NodeContainer::Iterator itNode;
245   for (itSetup = m_ueSetupList.begin (), itNode = ueNodes.Begin ();
246        itSetup != m_ueSetupList.end () || itNode != ueNodes.End ();
247        itSetup++, itNode++)
248     {
249       if (itSetup->isCsgMember)
250         {
251           lteHelper->SetUeDeviceAttribute ("CsgId", UintegerValue (1));
252         }
253       else
254         {
255           lteHelper->SetUeDeviceAttribute ("CsgId", UintegerValue (0));
256         }
257 
258       NetDeviceContainer devs = lteHelper->InstallUeDevice (*itNode);
259       Ptr<LteUeNetDevice> ueDev = devs.Get (0)->GetObject<LteUeNetDevice> ();
260       NS_ASSERT (ueDev != 0);
261       ueDevs.Add (devs);
262       Simulator::Schedule (itSetup->checkPoint,
263                            &LteCellSelectionTestCase::CheckPoint,
264                            this, ueDev,
265                            itSetup->expectedCellId1, itSetup->expectedCellId2);
266 
267       if (lastCheckPoint < itSetup->checkPoint)
268         {
269           lastCheckPoint = itSetup->checkPoint;
270         }
271     }
272 
273   stream += lteHelper->AssignStreams (enbDevs, stream);
274   stream += lteHelper->AssignStreams (ueDevs, stream);
275 
276   // Tests
277   NS_ASSERT (m_ueSetupList.size () == ueDevs.GetN ());
278   NetDeviceContainer::Iterator itDev;
279   for (itSetup = m_ueSetupList.begin (), itDev = ueDevs.Begin ();
280        itSetup != m_ueSetupList.end () || itDev != ueDevs.End ();
281        itSetup++, itDev++)
282     {
283       Ptr<LteUeNetDevice> ueDev = (*itDev)->GetObject<LteUeNetDevice> ();
284     }
285 
286   if (m_isEpcMode)
287     {
288       // Create P-GW node
289       Ptr<Node> pgw = epcHelper->GetPgwNode ();
290 
291       // Create a single RemoteHost
292       NodeContainer remoteHostContainer;
293       remoteHostContainer.Create (1);
294       Ptr<Node> remoteHost = remoteHostContainer.Get (0);
295       InternetStackHelper internet;
296       internet.Install (remoteHostContainer);
297 
298       // Create the Internet
299       PointToPointHelper p2ph;
300       p2ph.SetDeviceAttribute ("DataRate", DataRateValue (DataRate ("100Gb/s")));
301       p2ph.SetDeviceAttribute ("Mtu", UintegerValue (1500));
302       p2ph.SetChannelAttribute ("Delay", TimeValue (Seconds (0.010)));
303       NetDeviceContainer internetDevices = p2ph.Install (pgw, remoteHost);
304       Ipv4AddressHelper ipv4h;
305       ipv4h.SetBase ("1.0.0.0", "255.0.0.0");
306       Ipv4InterfaceContainer internetIpIfaces = ipv4h.Assign (internetDevices);
307 
308       // Routing of the Internet Host (towards the LTE network)
309       Ipv4StaticRoutingHelper ipv4RoutingHelper;
310       Ptr<Ipv4StaticRouting> remoteHostStaticRouting = ipv4RoutingHelper.GetStaticRouting (remoteHost->GetObject<Ipv4> ());
311       remoteHostStaticRouting->AddNetworkRouteTo (Ipv4Address ("7.0.0.0"), Ipv4Mask ("255.0.0.0"), 1);
312 
313       // Install the IP stack on the UEs
314       internet.Install (ueNodes);
315       Ipv4InterfaceContainer ueIpIfaces;
316       ueIpIfaces = epcHelper->AssignUeIpv4Address (NetDeviceContainer (ueDevs));
317 
318       // Assign IP address to UEs
319       for (uint32_t u = 0; u < ueNodes.GetN (); ++u)
320         {
321           Ptr<Node> ueNode = ueNodes.Get (u);
322           // Set the default gateway for the UE
323           Ptr<Ipv4StaticRouting> ueStaticRouting = ipv4RoutingHelper.GetStaticRouting (ueNode->GetObject<Ipv4> ());
324           ueStaticRouting->SetDefaultRoute (epcHelper->GetUeDefaultGatewayAddress (), 1);
325         }
326 
327     } // end of if (m_isEpcMode)
328   else
329     {
330       NS_FATAL_ERROR ("No support yet for LTE-only simulations");
331     }
332 
333   // Connect to trace sources in UEs
334   Config::Connect ("/NodeList/*/DeviceList/*/LteUeRrc/StateTransition",
335                    MakeCallback (&LteCellSelectionTestCase::StateTransitionCallback,
336                                  this));
337   Config::Connect ("/NodeList/*/DeviceList/*/LteUeRrc/InitialCellSelectionEndOk",
338                    MakeCallback (&LteCellSelectionTestCase::InitialCellSelectionEndOkCallback,
339                                  this));
340   Config::Connect ("/NodeList/*/DeviceList/*/LteUeRrc/InitialCellSelectionEndError",
341                    MakeCallback (&LteCellSelectionTestCase::InitialCellSelectionEndErrorCallback,
342                                  this));
343   Config::Connect ("/NodeList/*/DeviceList/*/LteUeRrc/ConnectionEstablished",
344                    MakeCallback (&LteCellSelectionTestCase::ConnectionEstablishedCallback,
345                                  this));
346 
347   // Enable Idle mode cell selection
348   lteHelper->Attach (ueDevs);
349 
350   // Run simulation
351   Simulator::Stop (lastCheckPoint);
352   Simulator::Run ();
353 
354   NS_LOG_INFO ("Simulation ends");
355   Simulator::Destroy ();
356 
357 } // end of void LteCellSelectionTestCase::DoRun ()
358 
359 
360 void
CheckPoint(Ptr<LteUeNetDevice> ueDev,uint16_t expectedCellId1,uint16_t expectedCellId2)361 LteCellSelectionTestCase::CheckPoint (Ptr<LteUeNetDevice> ueDev,
362                                       uint16_t expectedCellId1,
363                                       uint16_t expectedCellId2)
364 {
365   uint16_t actualCellId = ueDev->GetRrc ()->GetCellId ();
366 
367   if (expectedCellId2 == 0)
368     {
369       NS_TEST_ASSERT_MSG_EQ (actualCellId, expectedCellId1,
370                              "IMSI " << ueDev->GetImsi ()
371                                      << " has attached to an unexpected cell");
372     }
373   else
374     {
375       bool pass = (actualCellId == expectedCellId1) ||
376         (actualCellId == expectedCellId2);
377       NS_TEST_ASSERT_MSG_EQ (pass, true,
378                              "IMSI " << ueDev->GetImsi ()
379                                      << " has attached to an unexpected cell"
380                                      << " (actual: " << actualCellId << ","
381                                      << " expected: " << expectedCellId1
382                                      << " or " << expectedCellId2 << ")");
383     }
384 
385   if (expectedCellId1 > 0)
386     {
387       NS_TEST_ASSERT_MSG_EQ (m_lastState.at (static_cast<unsigned int>(ueDev->GetImsi () - 1)),
388                              LteUeRrc::CONNECTED_NORMALLY,
389                              "UE " << ueDev->GetImsi ()
390                                    << " is not at CONNECTED_NORMALLY state");
391     }
392 }
393 
394 
395 void
StateTransitionCallback(std::string context,uint64_t imsi,uint16_t cellId,uint16_t rnti,LteUeRrc::State oldState,LteUeRrc::State newState)396 LteCellSelectionTestCase::StateTransitionCallback (
397   std::string context, uint64_t imsi, uint16_t cellId, uint16_t rnti,
398   LteUeRrc::State oldState, LteUeRrc::State newState)
399 {
400   NS_LOG_FUNCTION (this << imsi << cellId << rnti << oldState << newState);
401   m_lastState.at (static_cast<unsigned int>(imsi - 1)) = newState;
402 }
403 
404 
405 void
InitialCellSelectionEndOkCallback(std::string context,uint64_t imsi,uint16_t cellId)406 LteCellSelectionTestCase::InitialCellSelectionEndOkCallback (
407   std::string context, uint64_t imsi, uint16_t cellId)
408 {
409   NS_LOG_FUNCTION (this << imsi << cellId);
410 }
411 
412 
413 void
InitialCellSelectionEndErrorCallback(std::string context,uint64_t imsi,uint16_t cellId)414 LteCellSelectionTestCase::InitialCellSelectionEndErrorCallback (
415   std::string context, uint64_t imsi, uint16_t cellId)
416 {
417   NS_LOG_FUNCTION (this << imsi << cellId);
418 }
419 
420 
421 void
ConnectionEstablishedCallback(std::string context,uint64_t imsi,uint16_t cellId,uint16_t rnti)422 LteCellSelectionTestCase::ConnectionEstablishedCallback (
423   std::string context, uint64_t imsi, uint16_t cellId, uint16_t rnti)
424 {
425   NS_LOG_FUNCTION (this << imsi << cellId << rnti);
426 }
427